diff --git a/src/dhcp-manager/Makefile.am b/src/dhcp-manager/Makefile.am index 04ae148948..40a0583411 100644 --- a/src/dhcp-manager/Makefile.am +++ b/src/dhcp-manager/Makefile.am @@ -52,6 +52,7 @@ libdhcp_manager_la_SOURCES = \ libdhcp_manager_la_CPPFLAGS = \ $(DBUS_CFLAGS) \ $(GLIB_CFLAGS) \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ -DLIBEXECDIR=\"$(libexecdir)\" \ -DLOCALSTATEDIR=\"$(localstatedir)\" \ -DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \ diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 8cfe579697..2cdd304de2 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -25,10 +25,8 @@ #include #include #include -#include -#include #include -#include +#include #include "nm-utils.h" #include "nm-logging.h" @@ -325,38 +323,58 @@ nm_dhcp_client_start_ip4 (NMDHCPClient *self, return priv->pid ? TRUE : FALSE; } -struct duid_header { - uint16_t duid_type; - uint16_t hw_type; - uint32_t time; - /* link-layer address follows */ -} __attribute__((__packed__)); - -#define DUID_TIME_EPOCH 946684800 - -/* Generate a DHCP Unique Identifier for DHCPv6 using the - * DUID-LLT method (see RFC 3315 s9.2), following Debian's - * netcfg DUID-LL generation method. - */ static GByteArray * -generate_duid (const GByteArray *hwaddr) +generate_duid_from_machine_id (void) { GByteArray *duid; - struct duid_header p; - int arptype; + char *contents = NULL; + GError *error = NULL; + GChecksum *sum; + guint8 buffer[32]; /* SHA256 digest size */ + gsize sumlen = sizeof (buffer); + const guint16 duid_type = g_htons (4); + uuid_t uuid; + int ret; - g_return_val_if_fail (hwaddr != NULL, NULL); + /* Get the machine ID from /etc/machine-id; it's always in /etc no matter + * where our configured SYSCONFDIR is. + */ + if (!g_file_get_contents ("/etc/machine-id", &contents, NULL, &error)) { + nm_log_warn (LOGD_DHCP6, "Failed to read " SYSCONFDIR "/machine-id to generate DHCPv6 DUID: (%d) %s", + error ? error->code : -1, + error ? error->message : "(unknown)"); + g_clear_error (&error); + return NULL; + } - memset (&p, 0, sizeof (p)); - p.duid_type = g_htons(1); - arptype = nm_utils_hwaddr_type (hwaddr->len); - g_assert (arptype == ARPHRD_ETHER || arptype == ARPHRD_INFINIBAND); - p.hw_type = g_htons (arptype); - p.time = g_htonl (time (NULL) - DUID_TIME_EPOCH); + contents = g_strstrip (contents); + ret = uuid_parse (contents, uuid); + g_free (contents); - duid = g_byte_array_sized_new (sizeof (p) + hwaddr->len); - g_byte_array_append (duid, (const guint8 *) &p, sizeof (p)); - g_byte_array_append (duid, hwaddr->data, hwaddr->len); + if (ret != 0) { + nm_log_warn (LOGD_DHCP6, "Failed to parse " SYSCONFDIR "/machine-id to generate DHCPv6 DUID."); + return NULL; + } + + /* Hash the machine ID so it's not leaked to the network */ + sum = g_checksum_new (G_CHECKSUM_SHA256); + g_checksum_update (sum, (const guchar *) &uuid, sizeof (uuid)); + g_checksum_get_digest (sum, buffer, &sumlen); + g_checksum_free (sum); + + /* Generate a DHCP Unique Identifier for DHCPv6 using the + * DUID-UUID method (see RFC 6355 section 4). Format is: + * + * u16: type (DUID-UUID = 4) + * u8[16]: UUID bytes + */ + duid = g_byte_array_sized_new (18); + g_byte_array_append (duid, (guint8 *) &duid_type, sizeof (duid_type)); + + /* Since SHA256 is 256 bits, but UUID is 128 bits, we just take the first + * 128 bits of the SHA256 as the DUID-UUID. + */ + g_byte_array_append (duid, buffer, 16); return duid; } @@ -364,8 +382,18 @@ generate_duid (const GByteArray *hwaddr) static GByteArray * get_duid (NMDHCPClient *self) { - /* generate a default DUID */ - return generate_duid (NM_DHCP_CLIENT_GET_PRIVATE (self)->hwaddr); + static GByteArray *duid = NULL; + GByteArray *copy = NULL; + + if (G_UNLIKELY (duid == NULL)) + duid = generate_duid_from_machine_id (); + + if (G_LIKELY (duid)) { + copy = g_byte_array_sized_new (duid->len); + g_byte_array_append (copy, duid->data, duid->len); + } + + return copy; } static char * diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c index be1ec29918..d9f51352c7 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient.c +++ b/src/dhcp-manager/nm-dhcp-dhclient.c @@ -53,8 +53,6 @@ typedef struct { const char *def_leasefile; char *lease_file; char *pid_file; - gboolean lease_duid_found; - gboolean default_duid_found; } NMDHCPDhclientPrivate; const char * @@ -499,36 +497,6 @@ dhclient_start (NMDHCPClient *client, return -1; } - if (ipv6 && duid) { - char *escaped = NULL; - - escaped = nm_dhcp_dhclient_escape_duid (duid); - - /* Save the generated DUID into the default leasefile for persistent storage */ - if (!priv->default_duid_found) { - nm_log_dbg (LOGD_DHCP6, "Saving DHCPv6 DUID '%s' to leasefile %s", - escaped, priv->def_leasefile); - if (!nm_dhcp_dhclient_save_duid (priv->def_leasefile, escaped, &error)) { - g_assert (error); - nm_log_warn (LOGD_DHCP6, "Could not save DUID: %s", error->message); - g_clear_error (&error); - } - } - - /* Save the DUID to the network-specific leasefile so it'll actually get used */ - if (!priv->lease_duid_found) { - nm_log_dbg (LOGD_DHCP6, "Saving DHCPv6 DUID '%s' to leasefile %s", - escaped, priv->lease_file); - if (!nm_dhcp_dhclient_save_duid (priv->lease_file, escaped, &error)) { - g_assert (error); - nm_log_warn (LOGD_DHCP6, "Could not save DUID: %s", error->message); - g_clear_error (&error); - } - } - - g_free (escaped); - } - argv = g_ptr_array_new (); g_ptr_array_add (argv, (gpointer) priv->path); @@ -675,7 +643,6 @@ get_duid (NMDHCPClient *client) TRUE); nm_log_dbg (LOGD_DHCP, "Looking for DHCPv6 DUID in '%s'.", leasefile); duid = nm_dhcp_dhclient_read_duid (leasefile, &error); - priv->lease_duid_found = !!duid; g_free (leasefile); if (error) { @@ -690,7 +657,6 @@ get_duid (NMDHCPClient *client) /* Otherwise read the default machine-wide DUID */ nm_log_dbg (LOGD_DHCP, "Looking for default DHCPv6 DUID in '%s'.", priv->def_leasefile); duid = nm_dhcp_dhclient_read_duid (priv->def_leasefile, &error); - priv->default_duid_found = !!duid; if (error) { nm_log_warn (LOGD_DHCP, "Failed to read leasefile '%s': (%d) %s", priv->def_leasefile,