From 800e226334cb165c18301b8d62833f83789208f8 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 4 Jan 2021 17:32:47 +0100 Subject: [PATCH] device: add "ipv4.dhcp-client-id=ipv6-duid" property for RFC4361 RFC4361 intends to set the same IAID/DUID for both DHCPv4 and DHCPv6. Previously, we didn't have a mode for that. Of course, you could always set "ipv4.dhcp-client-id" and "ipv6.dhcp-duid" to (the same) hex string, but there was no automatic mode. Instead we had: - "ipv4.dhcp-client-id=duid" which sets the client ID to a stable, generated DUID. However, there was no option so that the same DUID/IAID would be automatically used for DHCPv6. - there are various special values for "ipv6.dhcp-duid" which generate a stable DUIDs. However, those values did not work for "ipv4.dhcp-client-id". Solve that by adding "ipv4.dhcp-client-id=ipv6-duid" which indicates to use the DUID from DHCPv6's "ipv6.dhcp-duid" setting. As IAID it will prefer "ipv4.dhcp-iaid" (if set), but fallback to "ipv6.dhcp-iaid". https://tools.ietf.org/html/rfc4361 https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/618 https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/718 --- .../generate-docs-nm-settings-nmcli.xml.in | 2 +- clients/common/settings-docs.h.in | 2 +- libnm-core/nm-setting-ip4-config.c | 6 +- src/devices/nm-device.c | 67 ++++++++++++++----- src/nm-core-utils.c | 24 +++++++ src/nm-core-utils.h | 2 + 6 files changed, 83 insertions(+), 20 deletions(-) diff --git a/clients/cli/generate-docs-nm-settings-nmcli.xml.in b/clients/cli/generate-docs-nm-settings-nmcli.xml.in index a4e6715cc8..f269af0646 100644 --- a/clients/cli/generate-docs-nm-settings-nmcli.xml.in +++ b/clients/cli/generate-docs-nm-settings-nmcli.xml.in @@ -652,7 +652,7 @@ + description="A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values "mac" and "perm-mac" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value "ipv6-duid" uses the DUID from "ipv6.dhcp-duid" property as an RFC4361-compliant client identifier. As IAID it uses "ipv4.dhcp-iaid" and falls back to "ipv6.dhcp-iaid" if unset. The special value "duid" generates a RFC4361-compliant client identifier based on "ipv4.dhcp-iaid" and uses a DUID generated by hashing /etc/machine-id. The special value "stable" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If you set the stable-id, you may want to include the "${DEVICE}" or "${MAC}" specifier to get a per-device key. If unset, a globally configured default is used. If still unset, the default depends on the DHCP plugin." /> = 2u + 1u); + nm_assert(duid_len <= 2u + 128u); + + result = nm_utils_dhcp_client_id_duid(iaid, duid_arr, duid_len); + goto out_good; + } + if (nm_streq(client_id, "stable")) { nm_auto_free_checksum GChecksum *sum = NULL; guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1]; @@ -9802,7 +9835,7 @@ dhcp6_start_with_link_ready(NMDevice *self, NMConnection *connection) if (pllink) hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address); - iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET6, connection, &iaid_explicit); + iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET6, connection, TRUE, &iaid_explicit); duid = _prop_get_ipv6_dhcp_duid(self, connection, hwaddr, &enforce_duid); priv->dhcp_data_6.client = nm_dhcp_manager_start_ip6( diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 9df960ac3c..7b62968fb5 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -4035,6 +4035,30 @@ nm_utils_create_dhcp_iaid(gboolean legacy_unstable_byteorder, } } +GBytes * +nm_utils_dhcp_client_id_duid(guint32 iaid, const guint8 *duid, gsize duid_len) +{ + struct _nm_packed { + guint8 type; + guint32 iaid; + guint8 duid[]; + } * client_id; + gsize total_size; + + /* the @duid must include the 16 bit duid-type and the data (of max 128 bytes). */ + g_return_val_if_fail(duid_len > 2 && duid_len < 128 + 2, NULL); + g_return_val_if_fail(duid, NULL); + + total_size = sizeof(*client_id) + duid_len; + + client_id = g_malloc(total_size); + + client_id->type = 255; + unaligned_write_be32(&client_id->iaid, iaid); + memcpy(client_id->duid, duid, duid_len); + return g_bytes_new_take(client_id, total_size); +} + /** * nm_utils_dhcp_client_id_systemd_node_specific_full: * @iaid: the IAID (identity association identifier) in native byte order diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index a5244f5d8c..c90daaa683 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -449,6 +449,8 @@ guint32 nm_utils_create_dhcp_iaid(gboolean legacy_unstable_byteorder, const guint8 *interface_id, gsize interface_id_len); +GBytes *nm_utils_dhcp_client_id_duid(guint32 iaid, const guint8 *duid, gsize duid_len); + GBytes *nm_utils_dhcp_client_id_systemd_node_specific_full(guint32 iaid, const guint8 *machine_id, gsize machine_id_len);