dhcp4: introduce new option 'duid-only' for ClientIdentifier= (#8350)

This makes users can configure DHCPv4 client with ClientIdentifier=duid-only.
If set so, then DHCP client sends only DUID as the client identifier.
This may not be RFC compliant, but some setups require this.

Closes #7828.
This commit is contained in:
Yu Watanabe 2018-03-13 01:18:07 +09:00 committed by Zbigniew Jędrzejewski-Szmek
parent 6910dceef2
commit dace710c4a
7 changed files with 71 additions and 14 deletions

View File

@ -1236,8 +1236,11 @@
<varlistentry>
<term><varname>ClientIdentifier=</varname></term>
<listitem>
<para>The DHCPv4 client identifier to use. Either <literal>mac</literal> to use the MAC address of the link
or <literal>duid</literal> (the default, see below) to use an RFC4361-compliant Client ID.</para>
<para>The DHCPv4 client identifier to use. Takes one of <literal>mac</literal>, <literal>duid</literal> or <literal>duid-only</literal>.
If set to <literal>mac</literal>, the MAC address of the link is used.
If set to <literal>duid</literal>, an RFC4361-compliant Client ID, which is the combination of IAID and DUID (see below), is used.
If set to <literal>duid-only</literal>, only DUID is used, this may not be RFC compliant, but some setups may require to use this.
Defaults to <literal>duid</literal>.</para>
</listitem>
</varlistentry>

View File

@ -354,9 +354,10 @@ 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.
*/
int sd_dhcp_client_set_iaid_duid(
static int dhcp_client_set_iaid_duid(
sd_dhcp_client *client,
uint32_t iaid,
bool append_iaid,
uint16_t duid_type,
const void *duid,
size_t duid_len) {
@ -377,15 +378,17 @@ int sd_dhcp_client_set_iaid_duid(
zero(client->client_id);
client->client_id.type = 255;
/* If IAID is not configured, generate it. */
if (iaid == 0) {
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
client->mac_addr_len,
&client->client_id.ns.iaid);
if (r < 0)
return r;
} else
client->client_id.ns.iaid = htobe32(iaid);
if (append_iaid) {
/* If IAID is not configured, generate it. */
if (iaid == 0) {
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
client->mac_addr_len,
&client->client_id.ns.iaid);
if (r < 0)
return r;
} else
client->client_id.ns.iaid = htobe32(iaid);
}
if (duid != NULL) {
client->client_id.ns.duid.type = htobe16(duid_type);
@ -399,7 +402,7 @@ int sd_dhcp_client_set_iaid_duid(
return -EOPNOTSUPP;
client->client_id_len = sizeof(client->client_id.type) + len +
sizeof(client->client_id.ns.iaid);
(append_iaid ? sizeof(client->client_id.ns.iaid) : 0);
if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
log_dhcp_client(client, "Configured IAID+DUID, restarting.");
@ -410,6 +413,23 @@ int sd_dhcp_client_set_iaid_duid(
return 0;
}
int sd_dhcp_client_set_iaid_duid(
sd_dhcp_client *client,
uint32_t iaid,
uint16_t duid_type,
const void *duid,
size_t duid_len) {
return dhcp_client_set_iaid_duid(client, iaid, true, duid_type, duid, duid_len);
}
int sd_dhcp_client_set_duid(
sd_dhcp_client *client,
uint16_t duid_type,
const void *duid,
size_t duid_len) {
return dhcp_client_set_iaid_duid(client, 0, false, duid_type, duid, duid_len);
}
int sd_dhcp_client_set_hostname(
sd_dhcp_client *client,
const char *hostname) {

View File

@ -776,6 +776,18 @@ int dhcp4_configure(Link *link) {
return r;
break;
}
case DHCP_CLIENT_ID_DUID_ONLY: {
/* If configured, apply user specified DUID */
const DUID *duid = link_duid(link);
r = sd_dhcp_client_set_duid(link->dhcp_client,
duid->type,
duid->raw_data_len > 0 ? duid->raw_data : NULL,
duid->raw_data_len);
if (r < 0)
return r;
break;
}
case DHCP_CLIENT_ID_MAC:
r = sd_dhcp_client_set_client_id(link->dhcp_client,
ARPHRD_ETHER,

View File

@ -3282,6 +3282,17 @@ int link_update(Link *link, sd_netlink_message *m) {
return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m");
break;
}
case DHCP_CLIENT_ID_DUID_ONLY: {
const DUID *duid = link_duid(link);
r = sd_dhcp_client_set_duid(link->dhcp_client,
duid->type,
duid->raw_data_len > 0 ? duid->raw_data : NULL,
duid->raw_data_len);
if (r < 0)
return log_link_warning_errno(link, r, "Could not update DUID in DHCP client: %m");
break;
}
case DHCP_CLIENT_ID_MAC:
r = sd_dhcp_client_set_client_id(link->dhcp_client,
ARPHRD_ETHER,

View File

@ -859,7 +859,8 @@ int config_parse_dhcp(
static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
[DHCP_CLIENT_ID_MAC] = "mac",
[DHCP_CLIENT_ID_DUID] = "duid"
[DHCP_CLIENT_ID_DUID] = "duid",
[DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);

View File

@ -49,6 +49,11 @@
typedef enum DHCPClientIdentifier {
DHCP_CLIENT_ID_MAC,
DHCP_CLIENT_ID_DUID,
/* The following option may not be good for RFC regarding DHCP (3315 and 4361).
* But some setups require this. E.g., Sky Broadband, the second largest provider in the UK
* requires the client id to be set to a custom string, reported at
* https://github.com/systemd/systemd/issues/7828 */
DHCP_CLIENT_ID_DUID_ONLY,
_DHCP_CLIENT_ID_MAX,
_DHCP_CLIENT_ID_INVALID = -1,
} DHCPClientIdentifier;

View File

@ -132,6 +132,11 @@ int sd_dhcp_client_set_iaid_duid(
uint16_t duid_type,
const void *duid,
size_t duid_len);
int sd_dhcp_client_set_duid(
sd_dhcp_client *client,
uint16_t duid_type,
const void *duid,
size_t duid_len);
int sd_dhcp_client_get_client_id(
sd_dhcp_client *client,
uint8_t *type,