diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 80d2802610..e4e7bad855 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1236,8 +1236,11 @@ ClientIdentifier= - The DHCPv4 client identifier to use. Either mac to use the MAC address of the link - or duid (the default, see below) to use an RFC4361-compliant Client ID. + The DHCPv4 client identifier to use. Takes one of mac, duid or duid-only. + If set to mac, the MAC address of the link is used. + If set to duid, an RFC4361-compliant Client ID, which is the combination of IAID and DUID (see below), is used. + If set to duid-only, only DUID is used, this may not be RFC compliant, but some setups may require to use this. + Defaults to duid. diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 33f3469f07..9cf49747e0 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -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) { diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index ecb96cdb57..91762362f1 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -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, diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 64c45080df..ad2d90b37b 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -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, diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 709ae2a0cc..fc9fbed6f1 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -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); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 7b40ba51e6..8163d9eb77 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -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; diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 6eb9eb61a8..789cc50174 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -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,