Commit 0d841e74 authored by Francesco Giudici's avatar Francesco Giudici

dhcp: remove fallback DUID-UUID generation from dhcp code

This commit centralizes the DUID generation in nm-device.c.
As a consequence, a DUID is always provided when starting a
DHCPv6 client. The DHCP client can override the passed DUID
with the value contained in the client-specific lease file.
parent 7a0b6b17
......@@ -7750,6 +7750,37 @@ generate_duid_uuid (guint8 *data, gsize data_len)
return g_bytes_new_take (duid_buffer, DUID_SIZE);
}
static GBytes *
generate_duid_from_machine_id (void)
{
gs_free const char *machine_id_s = NULL;
uuid_t uuid;
GChecksum *sum;
guint8 sha256_digest[32];
gsize len = sizeof (sha256_digest);
static GBytes *global_duid = NULL;
if (global_duid)
return g_bytes_ref (global_duid);
machine_id_s = nm_utils_machine_id_read ();
if (nm_utils_machine_id_parse (machine_id_s, uuid)) {
/* 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, sha256_digest, &len);
g_checksum_free (sum);
} else {
nm_log_warn (LOGD_IP6, "global duid: failed to read " SYSCONFDIR "/machine-id "
"or " LOCALSTATEDIR "/lib/dbus/machine-id to generate "
"DHCPv6 DUID; creating non-persistent random DUID.");
nm_utils_random_bytes (sha256_digest, len);
}
global_duid = generate_duid_uuid (sha256_digest, len);
return g_bytes_ref (global_duid);
}
static GBytes *
dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcpDuidEnforce *out_enforce)
{
......@@ -7760,8 +7791,8 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcp
GBytes *duid_out = NULL;
guint8 sha256_digest[32];
gsize len = sizeof (sha256_digest);
NMDhcpDuidEnforce duid_enforce = NM_DHCP_DUID_ENFORCE_NEVER;
NM_SET_OUT (out_enforce, NM_DHCP_DUID_ENFORCE_NEVER);
s_ip6 = nm_connection_get_setting_ip6_config (connection);
duid = nm_setting_ip6_config_get_dhcp_duid (NM_SETTING_IP6_CONFIG (s_ip6));
......@@ -7772,14 +7803,18 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcp
duid = duid_default;
}
if (!duid || nm_streq (duid, "lease"))
return NULL;
if (!duid || nm_streq (duid, "lease")) {
duid_out = generate_duid_from_machine_id ();
goto end;
}
if (!_nm_utils_dhcp_duid_valid (duid, &duid_out))
return NULL;
if (!_nm_utils_dhcp_duid_valid (duid, &duid_out)) {
duid_error = "invalid duid";
goto end;
}
if (duid_out)
return duid_out;
goto end;
if (NM_IN_STRSET (duid, "ll", "llt")) {
if (!hwaddr) {
......@@ -7819,7 +7854,7 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcp
g_checksum_free (sum);
}
NM_SET_OUT (out_enforce, NM_DHCP_DUID_ENFORCE_ALWAYS);
duid_enforce = NM_DHCP_DUID_ENFORCE_ALWAYS;
#define EPOCH_DATETIME_THREE_YEARS (356 * 24 * 3600 * 3)
if (nm_streq0 (duid, "ll")) {
......@@ -7861,12 +7896,24 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcp
duid_out = generate_duid_uuid (sha256_digest, len);
}
duid_error = "generation failed";
end:
if (!duid_out) {
if (!duid_error)
duid_error = "generation failed";
_LOGD (LOGD_IP6, "duid-gen (%s): %s. Fallback to 'lease'.", duid, duid_error);
guint8 uuid[16];
if (duid_error)
_LOGW (LOGD_IP6, "duid-gen (%s): %s. Fallback to random DUID-UUID.", duid, duid_error);
nm_utils_random_bytes (uuid, sizeof (uuid));
duid_out = generate_duid_uuid (uuid, sizeof (uuid));
}
_LOGD (LOGD_IP6, "DUID gen: '%s' (%s)",
nm_dhcp_utils_duid_to_string (duid_out),
(duid_enforce == NM_DHCP_DUID_ENFORCE_ALWAYS) ? "enforcing" : "fallback");
NM_SET_OUT (out_enforce, duid_enforce);
return duid_out;
}
......
......@@ -512,66 +512,10 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self,
return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_anycast_addr, last_ip4_address);
}
static GBytes *
generate_duid_from_machine_id (void)
{
const int DUID_SIZE = 18;
guint8 *duid_buffer;
GChecksum *sum;
guint8 buffer[32]; /* SHA256 digest size */
gsize sumlen = sizeof (buffer);
const guint16 duid_type = g_htons (4);
uuid_t uuid;
gs_free char *machine_id_s = NULL;
gs_free char *str = NULL;
GBytes *duid;
machine_id_s = nm_utils_machine_id_read ();
if (nm_utils_machine_id_parse (machine_id_s, uuid)) {
/* 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);
} else {
nm_log_warn (LOGD_DHCP, "dhcp: failed to read " SYSCONFDIR "/machine-id "
"or " LOCALSTATEDIR "/lib/dbus/machine-id to generate "
"DHCPv6 DUID; creating non-persistent random DUID.");
nm_utils_random_bytes (buffer, sizeof (buffer));
}
/* 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_buffer = g_malloc (DUID_SIZE);
G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2);
memcpy (&duid_buffer[0], &duid_type, 2);
/* Since SHA256 is 256 bits, but UUID is 128 bits, we just take the first
* 128 bits of the SHA256 as the DUID-UUID.
*/
memcpy (&duid_buffer[2], buffer, 16);
duid = g_bytes_new_take (duid_buffer, DUID_SIZE);
nm_log_dbg (LOGD_DHCP, "dhcp: generated DUID %s",
(str = nm_dhcp_utils_duid_to_string (duid)));
return duid;
}
static GBytes *
get_duid (NMDhcpClient *self)
{
static GBytes *duid = NULL;
if (G_UNLIKELY (!duid))
duid = generate_duid_from_machine_id ();
return g_bytes_ref (duid);
return NULL;
}
gboolean
......@@ -595,6 +539,7 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
g_return_val_if_fail (priv->uuid != NULL, FALSE);
nm_assert (!priv->duid);
nm_assert (client_id);
switch (enforce_duid) {
case NM_DHCP_DUID_ENFORCE_NEVER:
......@@ -604,11 +549,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
break;
/* fall through */
case NM_DHCP_DUID_ENFORCE_ALWAYS:
if (client_id) {
priv->duid = g_bytes_ref (client_id);
break;
}
/* fall through */
priv->duid = g_bytes_ref (client_id);
break;
default:
nm_assert_not_reached ();
}
......
......@@ -619,8 +619,7 @@ get_duid (NMDhcpClient *client)
}
}
/* return our DUID, otherwise let the parent class make a default DUID */
return duid ?: NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->get_duid (client);
return duid;
}
/*****************************************************************************/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment