1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-08 08:58:27 +03:00

Merge pull request #28918 from yuwata/network-dhcp-custom-duid

network/dhcp: allow to specify custom duid type
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2023-08-24 15:45:07 +02:00 committed by GitHub
commit 12455d6e87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 340 additions and 251 deletions

View File

@ -127,7 +127,7 @@
<ulink url="https://tools.ietf.org/html/rfc3315#section-9">RFC 3315</ulink>
for a description of all the options.</para>
<para>The following values are understood:
<para>This takes an integer in the range 0…65535, or one of the following string values:
<variablelist>
<varlistentry>
<term><option>vendor</option></term>
@ -138,13 +138,6 @@
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>custom</option></term>
<listitem><para>If <literal>DUIDType=custom</literal>, then the <literal>DUIDRawData=</literal> value will
used be as custom identifier. If <literal>DUIDType=custom</literal> is specified then the
<literal>DUIDRawData=</literal> key is mandatory. Note it applies only on DHCPv6 clients.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>uuid</option></term>
<listitem><para>If <literal>DUIDType=uuid</literal>, and <varname>DUIDRawData=</varname> is not set,

View File

@ -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(

View File

@ -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(

View File

@ -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

View File

@ -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(

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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: {

View File

@ -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;

View File

@ -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) {

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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)