diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml index 9fa925e85c..f25083cc69 100644 --- a/man/networkd.conf.xml +++ b/man/networkd.conf.xml @@ -127,7 +127,7 @@ RFC 3315 for a description of all the options. - The following values are understood: + This takes an integer in the range 0…65535, or one of the following string values: @@ -138,13 +138,6 @@ - - - If DUIDType=custom, then the DUIDRawData= value will - used be as custom identifier. If DUIDType=custom is specified then the - DUIDRawData= key is mandatory. Note it applies only on DHCPv6 clients. - - If DUIDType=uuid, and DUIDRawData= is not set, diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 83fb6ce340..c905704ab5 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -15,52 +15,15 @@ #define USEC_2000 ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */ static const char * const duid_type_table[_DUID_TYPE_MAX] = { - [DUID_TYPE_LLT] = "DUID-LLT", - [DUID_TYPE_EN] = "DUID-EN/Vendor", - [DUID_TYPE_LL] = "DUID-LL", - [DUID_TYPE_UUID] = "UUID", - [DUID_TYPE_CUSTOM] = "Custom", + [DUID_TYPE_LLT] = "DUID-LLT", + [DUID_TYPE_EN] = "DUID-EN/Vendor", + [DUID_TYPE_LL] = "DUID-LL", + [DUID_TYPE_UUID] = "UUID", }; DEFINE_STRING_TABLE_LOOKUP_TO_STRING(duid_type, DUIDType); -int dhcp_validate_duid_len(DUIDType duid_type, size_t duid_len, bool strict) { - struct duid d; - - assert_cc(sizeof(d.raw) >= MAX_DUID_LEN); - if (duid_len > MAX_DUID_LEN) - return -EINVAL; - - if (!strict) - /* Strict validation is not requested. We only ensure that the - * DUID is not too long. */ - return 0; - - switch (duid_type) { - case DUID_TYPE_LLT: - if (duid_len <= sizeof(d.llt)) - return -EINVAL; - break; - case DUID_TYPE_EN: - if (duid_len != sizeof(d.en)) - return -EINVAL; - break; - case DUID_TYPE_LL: - if (duid_len <= sizeof(d.ll)) - return -EINVAL; - break; - case DUID_TYPE_UUID: - if (duid_len != sizeof(d.uuid)) - return -EINVAL; - break; - default: - /* accept unknown type in order to be forward compatible */ - break; - } - return 0; -} - -static int dhcp_identifier_set_duid_llt( +int dhcp_identifier_set_duid_llt( const struct hw_addr_data *hw_addr, uint16_t arp_type, usec_t t, @@ -98,7 +61,7 @@ static int dhcp_identifier_set_duid_llt( return 0; } -static int dhcp_identifier_set_duid_ll( +int dhcp_identifier_set_duid_ll( const struct hw_addr_data *hw_addr, uint16_t arp_type, struct duid *ret_duid, @@ -151,9 +114,9 @@ int dhcp_identifier_set_duid_en(bool test_mode, struct duid *ret_duid, size_t *r /* a bit of snake-oil perhaps, but no need to expose the machine-id * directly; duid->en.id might not be aligned, so we need to copy */ hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes)); - memcpy(ret_duid->en.id, &hash, sizeof(ret_duid->en.id)); + memcpy(ret_duid->en.id, &hash, sizeof(hash)); - *ret_len = offsetof(struct duid, en.id) + sizeof(ret_duid->en.id); + *ret_len = offsetof(struct duid, en.id) + sizeof(hash); if (test_mode) assert_se(memcmp(ret_duid, (const uint8_t[]) { 0x00, 0x02, 0x00, 0x00, 0xab, 0x11, 0x61, 0x77, 0x40, 0xde, 0x13, 0x42, 0xc3, 0xa2 }, *ret_len) == 0); @@ -161,7 +124,7 @@ int dhcp_identifier_set_duid_en(bool test_mode, struct duid *ret_duid, size_t *r return 0; } -static int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len) { +int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len) { sd_id128_t machine_id; int r; @@ -180,27 +143,28 @@ static int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len) return 0; } -int dhcp_identifier_set_duid( +int dhcp_identifier_set_duid_raw( DUIDType duid_type, - const struct hw_addr_data *hw_addr, - uint16_t arp_type, - usec_t llt_time, - bool test_mode, + const uint8_t *buf, + size_t buf_len, struct duid *ret_duid, size_t *ret_len) { - switch (duid_type) { - case DUID_TYPE_LLT: - return dhcp_identifier_set_duid_llt(hw_addr, arp_type, llt_time, ret_duid, ret_len); - case DUID_TYPE_EN: - return dhcp_identifier_set_duid_en(test_mode, ret_duid, ret_len); - case DUID_TYPE_LL: - return dhcp_identifier_set_duid_ll(hw_addr, arp_type, ret_duid, ret_len); - case DUID_TYPE_UUID: - return dhcp_identifier_set_duid_uuid(ret_duid, ret_len); - default: + assert(buf || buf_len == 0); + assert(ret_duid); + assert(ret_len); + + if (duid_type < 0 || duid_type > UINT16_MAX) return -EINVAL; - } + + if (buf_len > MAX_DUID_DATA_LEN) + return -EINVAL; + + unaligned_write_be16(&ret_duid->type, duid_type); + memcpy_safe(ret_duid->raw.data, buf, buf_len); + + *ret_len = offsetof(struct duid, raw.data) + buf_len; + return 0; } int dhcp_identifier_set_iaid( diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index 1ac3476157..7b36f92e7f 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -17,15 +17,16 @@ typedef enum DUIDType { DUID_TYPE_EN = 2, DUID_TYPE_LL = 3, DUID_TYPE_UUID = 4, - DUID_TYPE_CUSTOM = 5, _DUID_TYPE_MAX, _DUID_TYPE_INVALID = -EINVAL, + _DUID_TYPE_FORCE_U16 = UINT16_MAX, } DUIDType; /* RFC 3315 section 9.1: * A DUID can be no more than 128 octets long (not including the type code). */ #define MAX_DUID_LEN 128 +#define MAX_DUID_DATA_LEN (MAX_DUID_LEN - sizeof(be16_t)) /* https://tools.ietf.org/html/rfc3315#section-9.1 */ struct duid { @@ -35,36 +36,46 @@ struct duid { /* DUID_TYPE_LLT */ be16_t htype; be32_t time; - uint8_t haddr[0]; + uint8_t haddr[]; } _packed_ llt; struct { /* DUID_TYPE_EN */ be32_t pen; - uint8_t id[8]; + uint8_t id[]; } _packed_ en; struct { /* DUID_TYPE_LL */ be16_t htype; - uint8_t haddr[0]; + uint8_t haddr[]; } _packed_ ll; struct { /* DUID_TYPE_UUID */ sd_id128_t uuid; } _packed_ uuid; struct { - uint8_t data[MAX_DUID_LEN]; + uint8_t data[MAX_DUID_DATA_LEN]; } _packed_ raw; }; } _packed_; int dhcp_validate_duid_len(DUIDType duid_type, size_t duid_len, bool strict); -int dhcp_identifier_set_duid_en(bool test_mode, struct duid *ret_duid, size_t *ret_len); -int dhcp_identifier_set_duid( - DUIDType duid_type, +int dhcp_identifier_set_duid_llt( const struct hw_addr_data *hw_addr, uint16_t arp_type, - usec_t llt_time, - bool test_mode, + usec_t t, + struct duid *ret_duid, + size_t *ret_len); +int dhcp_identifier_set_duid_ll( + const struct hw_addr_data *hw_addr, + uint16_t arp_type, + struct duid *ret_duid, + size_t *ret_len); +int dhcp_identifier_set_duid_en(bool test_mode, struct duid *ret_duid, size_t *ret_len); +int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len); +int dhcp_identifier_set_duid_raw( + DUIDType duid_type, + const uint8_t *buf, + size_t buf_len, struct duid *ret_duid, size_t *ret_len); int dhcp_identifier_set_iaid( diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 272201abfd..8f330c8f14 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -402,27 +402,15 @@ int sd_dhcp_client_set_client_id( * without further modification. Otherwise, if duid_type is supported, DUID * is set based on that type. Otherwise, an error is returned. */ -static int dhcp_client_set_iaid_duid_internal( +static int dhcp_client_set_iaid( sd_dhcp_client *client, bool iaid_set, - uint32_t iaid, - DUIDType duid_type, - const void *duid, - size_t duid_len, - usec_t llt_time) { + uint32_t iaid) { - size_t len; int r; assert_return(client, -EINVAL); assert_return(!sd_dhcp_client_is_running(client), -EBUSY); - assert_return(duid_len == 0 || duid, -EINVAL); - - if (duid) { - r = dhcp_validate_duid_len(duid_type, duid_len, true); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to validate length of DUID: %m"); - } zero(client->client_id); client->client_id.type = 255; @@ -437,46 +425,132 @@ static int dhcp_client_set_iaid_duid_internal( return log_dhcp_client_errno(client, r, "Failed to set IAID: %m"); } - if (duid) { - client->client_id.ns.duid.type = htobe16(duid_type); - memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); - len = sizeof(client->client_id.ns.duid.type) + duid_len; - - } else { - r = dhcp_identifier_set_duid(duid_type, &client->hw_addr, - client->arp_type, llt_time, client->test_mode, - &client->client_id.ns.duid, &len); - if (r == -EOPNOTSUPP) - return log_dhcp_client_errno(client, r, - "Failed to set %s. MAC address is not set or " - "interface type is not supported.", - duid_type_to_string(duid_type)); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to set %s: %m", - duid_type_to_string(duid_type)); - } - - client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len; - return 0; } -int sd_dhcp_client_set_iaid_duid( - sd_dhcp_client *client, - bool iaid_set, - uint32_t iaid, - uint16_t duid_type, - const void *duid, - size_t duid_len) { - return dhcp_client_set_iaid_duid_internal(client, iaid_set, iaid, duid_type, duid, duid_len, 0); -} - int sd_dhcp_client_set_iaid_duid_llt( sd_dhcp_client *client, bool iaid_set, uint32_t iaid, usec_t llt_time) { - return dhcp_client_set_iaid_duid_internal(client, iaid_set, iaid, DUID_TYPE_LLT, NULL, 0, llt_time); + + size_t len; + int r; + + assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); + + r = dhcp_client_set_iaid(client, iaid_set, iaid); + if (r < 0) + return r; + + r = dhcp_identifier_set_duid_llt(&client->hw_addr, client->arp_type, llt_time, &client->client_id.ns.duid, &len); + if (r < 0) + return log_dhcp_client_errno(client, r, "Failed to set DUID-LLT: %m"); + + client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len; + + return 0; +} + +int sd_dhcp_client_set_iaid_duid_ll( + sd_dhcp_client *client, + bool iaid_set, + uint32_t iaid) { + + size_t len; + int r; + + assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); + + r = dhcp_client_set_iaid(client, iaid_set, iaid); + if (r < 0) + return r; + + r = dhcp_identifier_set_duid_ll(&client->hw_addr, client->arp_type, &client->client_id.ns.duid, &len); + if (r < 0) + return log_dhcp_client_errno(client, r, "Failed to set DUID-LL: %m"); + + client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len; + + return 0; +} + +int sd_dhcp_client_set_iaid_duid_en( + sd_dhcp_client *client, + bool iaid_set, + uint32_t iaid) { + + size_t len; + int r; + + assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); + + r = dhcp_client_set_iaid(client, iaid_set, iaid); + if (r < 0) + return r; + + r = dhcp_identifier_set_duid_en(client->test_mode, &client->client_id.ns.duid, &len); + if (r < 0) + return log_dhcp_client_errno(client, r, "Failed to set DUID-EN: %m"); + + client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len; + + return 0; +} + +int sd_dhcp_client_set_iaid_duid_uuid( + sd_dhcp_client *client, + bool iaid_set, + uint32_t iaid) { + + size_t len; + int r; + + assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); + + r = dhcp_client_set_iaid(client, iaid_set, iaid); + if (r < 0) + return r; + + r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len); + if (r < 0) + return log_dhcp_client_errno(client, r, "Failed to set DUID-UUID: %m"); + + client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len; + + return 0; +} + +int sd_dhcp_client_set_iaid_duid_raw( + sd_dhcp_client *client, + bool iaid_set, + uint32_t iaid, + uint16_t duid_type, + const uint8_t *duid, + size_t duid_len) { + + size_t len; + int r; + + assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); + assert_return(duid || duid_len == 0, -EINVAL); + + r = dhcp_client_set_iaid(client, iaid_set, iaid); + if (r < 0) + return r; + + r = dhcp_identifier_set_duid_raw(duid_type, duid, duid_len, &client->client_id.ns.duid, &len); + if (r < 0) + return log_dhcp_client_errno(client, r, "Failed to set DUID: %m"); + + client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + len; + + return 0; } void dhcp_client_set_test_mode(sd_dhcp_client *client, bool test_mode) { @@ -798,21 +872,9 @@ static int client_message_init( /* If no client identifier exists, construct an RFC 4361-compliant one */ if (client->client_id_len == 0) { - size_t duid_len; - - client->client_id.type = 255; - - r = dhcp_identifier_set_iaid(client->dev, &client->hw_addr, - /* legacy_unstable_byteorder = */ true, - &client->client_id.ns.iaid); + r = sd_dhcp_client_set_iaid_duid_en(client, /* iaid_set = */ false, /* iaid = */ 0); if (r < 0) return r; - - r = dhcp_identifier_set_duid_en(client->test_mode, &client->client_id.ns.duid, &duid_len); - if (r < 0) - return r; - - client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len; } /* Some DHCP servers will refuse to issue an DHCP lease if the Client diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index e8d99718b3..8957e1cf4b 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -190,64 +190,70 @@ static int client_ensure_duid(sd_dhcp6_client *client) { * without further modification. Otherwise, if duid_type is supported, DUID * is set based on that type. Otherwise, an error is returned. */ -static int dhcp6_client_set_duid_internal( - sd_dhcp6_client *client, - DUIDType duid_type, - const void *duid, - size_t duid_len, - usec_t llt_time) { +int sd_dhcp6_client_set_duid_llt(sd_dhcp6_client *client, uint64_t llt_time) { int r; assert_return(client, -EINVAL); assert_return(!sd_dhcp6_client_is_running(client), -EBUSY); - assert_return(duid_len == 0 || duid, -EINVAL); - if (duid) { - r = dhcp_validate_duid_len(duid_type, duid_len, true); - if (r < 0) { - r = dhcp_validate_duid_len(duid_type, duid_len, false); - if (r < 0) - return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m"); - - log_dhcp6_client(client, "Using DUID of type %i of incorrect length, proceeding.", duid_type); - } - - if (duid_type == DUID_TYPE_CUSTOM) { - memcpy(&client->duid, duid, duid_len); - client->duid_len = duid_len; - } else { - client->duid.type = htobe16(duid_type); - memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = sizeof(client->duid.type) + duid_len; - } - } else { - r = dhcp_identifier_set_duid(duid_type, &client->hw_addr, client->arp_type, llt_time, - client->test_mode, &client->duid, &client->duid_len); - if (r == -EOPNOTSUPP) - return log_dhcp6_client_errno(client, r, - "Failed to set %s. MAC address is not set or " - "interface type is not supported.", - duid_type_to_string(duid_type)); - if (r < 0) - return log_dhcp6_client_errno(client, r, "Failed to set %s: %m", - duid_type_to_string(duid_type)); - } + r = dhcp_identifier_set_duid_llt(&client->hw_addr, client->arp_type, llt_time, &client->duid, &client->duid_len); + if (r < 0) + return log_dhcp6_client_errno(client, r, "Failed to set DUID-LLT: %m"); return 0; } -int sd_dhcp6_client_set_duid( - sd_dhcp6_client *client, - uint16_t duid_type, - const void *duid, - size_t duid_len) { - return dhcp6_client_set_duid_internal(client, duid_type, duid, duid_len, 0); +int sd_dhcp6_client_set_duid_ll(sd_dhcp6_client *client) { + int r; + + assert_return(client, -EINVAL); + assert_return(!sd_dhcp6_client_is_running(client), -EBUSY); + + r = dhcp_identifier_set_duid_ll(&client->hw_addr, client->arp_type, &client->duid, &client->duid_len); + if (r < 0) + return log_dhcp6_client_errno(client, r, "Failed to set DUID-LL: %m"); + + return 0; } -int sd_dhcp6_client_set_duid_llt( - sd_dhcp6_client *client, - usec_t llt_time) { - return dhcp6_client_set_duid_internal(client, DUID_TYPE_LLT, NULL, 0, llt_time); +int sd_dhcp6_client_set_duid_en(sd_dhcp6_client *client) { + int r; + + assert_return(client, -EINVAL); + assert_return(!sd_dhcp6_client_is_running(client), -EBUSY); + + r = dhcp_identifier_set_duid_en(client->test_mode, &client->duid, &client->duid_len); + if (r < 0) + return log_dhcp6_client_errno(client, r, "Failed to set DUID-EN: %m"); + + return 0; +} + +int sd_dhcp6_client_set_duid_uuid(sd_dhcp6_client *client) { + int r; + + assert_return(client, -EINVAL); + assert_return(!sd_dhcp6_client_is_running(client), -EBUSY); + + r = dhcp_identifier_set_duid_uuid(&client->duid, &client->duid_len); + if (r < 0) + return log_dhcp6_client_errno(client, r, "Failed to set DUID-UUID: %m"); + + return 0; +} + +int sd_dhcp6_client_set_duid_raw(sd_dhcp6_client *client, uint16_t duid_type, const uint8_t *duid, size_t duid_len) { + int r; + + assert_return(client, -EINVAL); + assert_return(!sd_dhcp6_client_is_running(client), -EBUSY); + assert_return(duid || duid_len == 0, -EINVAL); + + r = dhcp_identifier_set_duid_raw(duid_type, duid, duid_len, &client->duid, &client->duid_len); + if (r < 0) + return log_dhcp6_client_errno(client, r, "Failed to set DUID: %m"); + + return 0; } int sd_dhcp6_client_duid_as_string( diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index 6b1842f1f8..ccf9208d43 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -428,7 +428,7 @@ TEST(client_parse_message_issue_22099) { assert_se(sd_dhcp6_client_new(&client) >= 0); assert_se(sd_dhcp6_client_set_iaid(client, 0xcc59117b) >= 0); - assert_se(sd_dhcp6_client_set_duid(client, 2, duid, sizeof(duid)) >= 0); + assert_se(sd_dhcp6_client_set_duid_raw(client, 2, duid, sizeof(duid)) >= 0); assert_se(dhcp6_lease_new_from_message(client, (const DHCP6Message*) msg, sizeof(msg), NULL, NULL, &lease) >= 0); } @@ -472,7 +472,7 @@ TEST(client_parse_message_issue_24002) { assert_se(sd_dhcp6_client_new(&client) >= 0); assert_se(sd_dhcp6_client_set_iaid(client, 0xaabbccdd) >= 0); - assert_se(sd_dhcp6_client_set_duid(client, 2, duid, sizeof(duid)) >= 0); + assert_se(sd_dhcp6_client_set_duid_raw(client, 2, duid, sizeof(duid)) >= 0); assert_se(dhcp6_lease_new_from_message(client, (const DHCP6Message*) msg, sizeof(msg), NULL, NULL, &lease) >= 0); } diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index baf80cb644..5b5b251e61 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -1106,11 +1106,10 @@ static const char * const dhcp_option_data_type_table[_DHCP_OPTION_DATA_MAX] = { DEFINE_STRING_TABLE_LOOKUP(dhcp_option_data_type, DHCPOptionDataType); static const char* const duid_type_table[_DUID_TYPE_MAX] = { - [DUID_TYPE_LLT] = "link-layer-time", - [DUID_TYPE_EN] = "vendor", - [DUID_TYPE_LL] = "link-layer", - [DUID_TYPE_UUID] = "uuid", - [DUID_TYPE_CUSTOM] = "custom", + [DUID_TYPE_LLT] = "link-layer-time", + [DUID_TYPE_EN] = "vendor", + [DUID_TYPE_LL] = "link-layer", + [DUID_TYPE_UUID] = "uuid", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType); @@ -1155,9 +1154,17 @@ int config_parse_duid_type( type = duid_type_from_string(type_string); if (type < 0) { - log_syntax(unit, LOG_WARNING, filename, line, type, - "Failed to parse DUID type '%s', ignoring.", type_string); - return 0; + uint16_t t; + + r = safe_atou16(type_string, &t); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse DUID type '%s', ignoring.", type_string); + return 0; + } + + type = t; + assert(type == t); /* Check if type can store uint16_t. */ } if (!isempty(p)) { @@ -1244,7 +1251,7 @@ int config_parse_duid_rawdata( void *data, void *userdata) { - uint8_t raw_data[MAX_DUID_LEN]; + uint8_t raw_data[MAX_DUID_DATA_LEN]; unsigned count = 0; bool force = ltype; DUID *duid = ASSERT_PTR(data); @@ -1272,7 +1279,7 @@ int config_parse_duid_rawdata( if (r == 0) break; - if (count >= MAX_DUID_LEN) { + if (count >= MAX_DUID_DATA_LEN) { log_syntax(unit, LOG_WARNING, filename, line, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue); return 0; } diff --git a/src/network/networkd-dhcp-common.h b/src/network/networkd-dhcp-common.h index 07367d4d24..ea942af721 100644 --- a/src/network/networkd-dhcp-common.h +++ b/src/network/networkd-dhcp-common.h @@ -48,7 +48,7 @@ typedef struct DUID { DUIDType type; uint8_t raw_data_len; - uint8_t raw_data[MAX_DUID_LEN]; + uint8_t raw_data[MAX_DUID_DATA_LEN]; usec_t llt_time; bool set; } DUID; diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index eeb3585f29..9dcd37e11c 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -1326,20 +1326,42 @@ static int dhcp4_set_client_identifier(Link *link) { /* If configured, apply user specified DUID and IAID */ const DUID *duid = link_get_dhcp4_duid(link); - if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0) - r = sd_dhcp_client_set_iaid_duid_llt(link->dhcp_client, + if (duid->raw_data_len == 0) + switch (duid->type) { + case DUID_TYPE_LLT: + r = sd_dhcp_client_set_iaid_duid_llt(link->dhcp_client, + link->network->dhcp_iaid_set, + link->network->dhcp_iaid, + duid->llt_time); + break; + case DUID_TYPE_LL: + r = sd_dhcp_client_set_iaid_duid_ll(link->dhcp_client, + link->network->dhcp_iaid_set, + link->network->dhcp_iaid); + break; + case DUID_TYPE_EN: + r = sd_dhcp_client_set_iaid_duid_en(link->dhcp_client, + link->network->dhcp_iaid_set, + link->network->dhcp_iaid); + break; + case DUID_TYPE_UUID: + r = sd_dhcp_client_set_iaid_duid_uuid(link->dhcp_client, + link->network->dhcp_iaid_set, + link->network->dhcp_iaid); + break; + default: + r = sd_dhcp_client_set_iaid_duid_raw(link->dhcp_client, + link->network->dhcp_iaid_set, + link->network->dhcp_iaid, + duid->type, NULL, 0); + } + else + r = sd_dhcp_client_set_iaid_duid_raw(link->dhcp_client, link->network->dhcp_iaid_set, link->network->dhcp_iaid, - duid->llt_time); - else - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->dhcp_iaid_set, - link->network->dhcp_iaid, - duid->type, - duid->raw_data_len > 0 ? duid->raw_data : NULL, - duid->raw_data_len); + duid->type, duid->raw_data, duid->raw_data_len); if (r < 0) - return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IAID+DUID: %m"); + return r; break; } case DHCP_CLIENT_ID_MAC: { diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index e0f0850898..95b13ca93c 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -556,17 +556,25 @@ static int dhcp6_set_identifier(Link *link, sd_dhcp6_client *client) { duid = link_get_dhcp6_duid(link); - if (duid->type == DUID_TYPE_CUSTOM && duid->raw_data_len == 0) - return log_link_debug_errno(link, SYNTHETIC_ERRNO(EINVAL), - "DHCPv6 CLIENT: Missing DUID Raw Data as duid type set to 'custom': %m"); - - if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0) - r = sd_dhcp6_client_set_duid_llt(client, duid->llt_time); + if (duid->raw_data_len == 0) + switch (duid->type) { + case DUID_TYPE_LLT: + r = sd_dhcp6_client_set_duid_llt(client, duid->llt_time); + break; + case DUID_TYPE_LL: + r = sd_dhcp6_client_set_duid_ll(client); + break; + case DUID_TYPE_EN: + r = sd_dhcp6_client_set_duid_en(client); + break; + case DUID_TYPE_UUID: + r = sd_dhcp6_client_set_duid_uuid(client); + break; + default: + r = sd_dhcp6_client_set_duid_raw(client, duid->type, NULL, 0); + } else - r = sd_dhcp6_client_set_duid(client, - duid->type, - duid->raw_data_len > 0 ? duid->raw_data : NULL, - duid->raw_data_len); + r = sd_dhcp6_client_set_duid_raw(client, duid->type, duid->raw_data, duid->raw_data_len); if (r < 0) return r; diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c index f6f068706a..22dd991fb0 100644 --- a/src/network/test-networkd-conf.c +++ b/src/network/test-networkd-conf.c @@ -83,9 +83,26 @@ static void test_config_parse_ether_addrs_one(const char *rvalue, const struct e assert_se(set_size(s) == 0); } -#define BYTES_0_128 "0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f:20:21:22:23:24:25:26:27:28:29:2a:2b:2c:2d:2e:2f:30:31:32:33:34:35:36:37:38:39:3a:3b:3c:3d:3e:3f:40:41:42:43:44:45:46:47:48:49:4a:4b:4c:4d:4e:4f:50:51:52:53:54:55:56:57:58:59:5a:5b:5c:5d:5e:5f:60:61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:70:71:72:73:74:75:76:77:78:79:7a:7b:7c:7d:7e:7f:80" +#define BYTES_0_126 \ + "00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:" \ + "10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f:" \ + "20:21:22:23:24:25:26:27:28:29:2a:2b:2c:2d:2e:2f:" \ + "30:31:32:33:34:35:36:37:38:39:3a:3b:3c:3d:3e:3f:" \ + "40:41:42:43:44:45:46:47:48:49:4a:4b:4c:4d:4e:4f:" \ + "50:51:52:53:54:55:56:57:58:59:5a:5b:5c:5d:5e:5f:" \ + "60:61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:" \ + "70:71:72:73:74:75:76:77:78:79:7a:7b:7c:7d:7e" -#define BYTES_1_128 {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80} +#define BYTES_1_126 { \ + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, \ + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, \ + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, \ + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, \ + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, \ + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, \ + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, \ + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e \ +} TEST(config_parse_duid_rawdata) { test_config_parse_duid_rawdata_one("", 0, &(DUID){}); @@ -99,8 +116,8 @@ TEST(config_parse_duid_rawdata) { &(DUID){0, 8, {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}}); test_config_parse_duid_rawdata_one("11::", 0, &(DUID){0, 1, {0x11}}); /* FIXME: should this be an error? */ test_config_parse_duid_rawdata_one("abcdef", 0, &(DUID){}); - test_config_parse_duid_rawdata_one(BYTES_0_128, 0, &(DUID){}); - test_config_parse_duid_rawdata_one(&BYTES_0_128[2], 0, &(DUID){0, 128, BYTES_1_128}); + test_config_parse_duid_rawdata_one(BYTES_0_126, 0, &(DUID){}); + test_config_parse_duid_rawdata_one(&BYTES_0_126[3], 0, &(DUID){0, 126, BYTES_1_126}); } TEST(config_parse_ether_addr) { diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 7339bb6872..ddd445c9f0 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -257,18 +257,30 @@ int sd_dhcp_client_set_client_id( uint8_t type, const uint8_t *data, size_t data_len); -__extension__ int sd_dhcp_client_set_iaid_duid( - sd_dhcp_client *client, - bool iaid_set, - uint32_t iaid, - uint16_t duid_type, - const void *duid, - size_t duid_len); __extension__ int sd_dhcp_client_set_iaid_duid_llt( sd_dhcp_client *client, bool iaid_set, uint32_t iaid, uint64_t llt_time); +__extension__ int sd_dhcp_client_set_iaid_duid_ll( + sd_dhcp_client *client, + bool iaid_set, + uint32_t iaid); +__extension__ int sd_dhcp_client_set_iaid_duid_en( + sd_dhcp_client *client, + bool iaid_set, + uint32_t iaid); +__extension__ int sd_dhcp_client_set_iaid_duid_uuid( + sd_dhcp_client *client, + bool iaid_set, + uint32_t iaid); +__extension__ int sd_dhcp_client_set_iaid_duid_raw( + sd_dhcp_client *client, + bool iaid_set, + uint32_t iaid, + uint16_t duid_type, + const uint8_t *duid, + size_t duid_len); int sd_dhcp_client_get_client_id( sd_dhcp_client *client, uint8_t *ret_type, diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index a9fa78569d..c85c5652c4 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -211,14 +211,11 @@ int sd_dhcp6_client_set_mac( const uint8_t *addr, size_t addr_len, uint16_t arp_type); -int sd_dhcp6_client_set_duid( - sd_dhcp6_client *client, - uint16_t duid_type, - const void *duid, - size_t duid_len); -int sd_dhcp6_client_set_duid_llt( - sd_dhcp6_client *client, - uint64_t llt_time); +int sd_dhcp6_client_set_duid_llt(sd_dhcp6_client *client, uint64_t llt_time); +int sd_dhcp6_client_set_duid_ll(sd_dhcp6_client *client); +int sd_dhcp6_client_set_duid_en(sd_dhcp6_client *client); +int sd_dhcp6_client_set_duid_uuid(sd_dhcp6_client *client); +int sd_dhcp6_client_set_duid_raw(sd_dhcp6_client *client, uint16_t duid_type, const uint8_t *duid, size_t duid_len); int sd_dhcp6_client_set_iaid( sd_dhcp6_client *client, uint32_t iaid); diff --git a/test/test-network/conf/25-dhcp-client-ipv6-only-custom-client-identifier.network b/test/test-network/conf/25-dhcp-client-ipv6-only-custom-client-identifier.network index edd5b7f501..1b1a56cd70 100644 --- a/test/test-network/conf/25-dhcp-client-ipv6-only-custom-client-identifier.network +++ b/test/test-network/conf/25-dhcp-client-ipv6-only-custom-client-identifier.network @@ -11,5 +11,5 @@ Gateway=_ipv6ra Destination=2001:1234:5:9fff:ff:ff:ff:ff/128 [DHCPv6] -DUIDType=custom +DUIDType=0x42 DUIDRawData=00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 5910d0d8da..171152040b 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -5034,20 +5034,10 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): self.assertRegex(output, r'inet6 2600::[0-9a-f:]*/128 scope global dynamic noprefixroute') self.assertNotIn('192.168.5', output) - # checking semi-static route - output = check_output('ip -6 route list dev veth99 2001:1234:5:9fff:ff:ff:ff:ff') - print(output) - self.assertRegex(output, 'via fe80::1034:56ff:fe78:9abd') - - # Confirm that ipv6 token is not set in the kernel - output = check_output('ip token show dev veth99') - print(output) - self.assertRegex(output, 'token :: dev veth99') - print('## dnsmasq log') output = read_dnsmasq_log_file() print(output) - self.assertIn('DHCPSOLICIT(veth-peer) 00:00:ab:11:f9:2a:c2:77:29:f9:5c:00', output) + self.assertIn('DHCPSOLICIT(veth-peer) 00:42:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00', output) self.assertNotIn('DHCPADVERTISE(veth-peer)', output) self.assertNotIn('DHCPREQUEST(veth-peer)', output) self.assertIn('DHCPREPLY(veth-peer)', output)