diff options
Diffstat (limited to 'src/dhcp')
| -rw-r--r-- | src/dhcp/nm-dhcp-client.c | 76 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-client.h | 7 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-dhclient-utils.c | 41 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-dhclient.c | 7 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-manager.c | 11 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-manager.h | 2 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-utils.h | 6 | ||||
| -rw-r--r-- | src/dhcp/tests/test-dhcp-dhclient.c | 47 |
8 files changed, 103 insertions, 94 deletions
diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index ba517606..390b7054 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -513,69 +513,15 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self, } static GBytes * -generate_duid_from_machine_id (void) +get_duid (NMDhcpClient *self, gboolean global) { - 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 nm_dhcp_client_start_ip6 (NMDhcpClient *self, + GBytes *client_id, + NMDhcpDuidEnforce enforce_duid, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, const char *hostname, @@ -592,11 +538,17 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, g_return_val_if_fail (priv->addr_family == AF_INET6, FALSE); g_return_val_if_fail (priv->uuid != NULL, FALSE); - /* If we don't have one yet, read the default DUID for this DHCPv6 client - * from the client-specific persistent configuration. - */ + nm_assert (!priv->duid); + nm_assert (client_id); + + if (enforce_duid == NM_DHCP_DUID_ENFORCE_NEVER) + priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self, TRUE); + else if (enforce_duid == NM_DHCP_DUID_ENFORCE_LEASE_FALLBACK) + priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self, FALSE); + + /* NM_DHCP_DUID_ENFORCE_ALWAYS and fallback */ if (!priv->duid) - priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self); + priv->duid = g_bytes_ref (client_id); _LOGD ("DUID is '%s'", (str = nm_dhcp_utils_duid_to_string (priv->duid))); diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h index 111b063b..98c3ed26 100644 --- a/src/dhcp/nm-dhcp-client.h +++ b/src/dhcp/nm-dhcp-client.h @@ -23,6 +23,7 @@ #include "nm-setting-ip6-config.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" +#include "nm-dhcp-utils.h" #define NM_DHCP_TIMEOUT_DEFAULT ((guint32) 45) /* default DHCP timeout, in seconds */ #define NM_DHCP_TIMEOUT_INFINITY G_MAXINT32 @@ -95,13 +96,15 @@ typedef struct { /** * get_duid: * @self: the #NMDhcpClient + * @global: if set to #true, the duid should be searched also in the + * DHCP client's system-wide persistent configuration. * * Attempts to find an existing DHCPv6 DUID for this client in the DHCP * client's persistent configuration. Returned DUID should be the binary * representation of the DUID. If no DUID is found, %NULL should be * returned. */ - GBytes *(*get_duid) (NMDhcpClient *self); + GBytes *(*get_duid) (NMDhcpClient *self, gboolean global); /* Signals */ void (*state_changed) (NMDhcpClient *self, @@ -149,6 +152,8 @@ gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self, const char *last_ip4_address); gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self, + GBytes *client_id, + NMDhcpDuidEnforce enforce_duid, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, const char *hostname, diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index 16a76d23..3290dd65 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -594,7 +594,8 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, const char *escaped_duid, GError **error) { - char **lines = NULL, **iter, *l; + gs_strfreev char **lines = NULL; + char **iter, *l; GString *s; gboolean success; gsize len = 0; @@ -610,19 +611,9 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, return FALSE; } - /* If the file already contains an uncommented DUID, leave it */ g_assert (contents); lines = g_strsplit_set (contents, "\n\r", -1); g_free (contents); - for (iter = lines; iter && *iter; iter++) { - l = *iter; - while (g_ascii_isspace (*l)) - l++; - if (g_str_has_prefix (l, DUID_PREFIX)) { - g_strfreev (lines); - return TRUE; - } - } } s = g_string_sized_new (len + 50); @@ -630,9 +621,31 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, /* Preserve existing leasefile contents */ if (lines) { - for (iter = lines; iter && *iter; iter++) - g_string_append (s, *iter[0] ? *iter : "\n"); - g_strfreev (lines); + for (iter = lines; iter && *iter; iter++) { + l = *iter; + while (g_ascii_isspace (*l)) + l++; + /* If we find an uncommented DUID in the file, check if + * equal to the one we are going to write: if so, no need + * to update the lease file, otherwise skip the old DUID. + */ + if (g_str_has_prefix (l, DUID_PREFIX)) { + gs_strfreev char **split = NULL; + + split = g_strsplit (l, "\"", -1); + if (nm_streq0 (split[1], escaped_duid)) { + g_string_free (s, TRUE); + return TRUE; + } + continue; + } + + if (*iter[0]) + g_string_append (s, *iter); + /* avoid to add an extra '\n' at the end of file */ + if ((iter[1]) != NULL) + g_string_append_c (s, '\n'); + } } success = g_file_set_contents (leasefile, s->str, -1, error); diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c index 93306ddd..43746dd3 100644 --- a/src/dhcp/nm-dhcp-dhclient.c +++ b/src/dhcp/nm-dhcp-dhclient.c @@ -582,7 +582,7 @@ state_changed (NMDhcpClient *client, } static GBytes * -get_duid (NMDhcpClient *client) +get_duid (NMDhcpClient *client, gboolean global) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); @@ -607,7 +607,7 @@ get_duid (NMDhcpClient *client) g_free (leasefile); } - if (!duid) { + if (!duid && global) { /* Otherwise read the default machine-wide DUID */ _LOGD ("looking for default DUID in '%s'", priv->def_leasefile); duid = nm_dhcp_dhclient_read_duid (priv->def_leasefile, &error); @@ -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; } /*****************************************************************************/ diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c index aa40e803..2d85c73a 100644 --- a/src/dhcp/nm-dhcp-manager.c +++ b/src/dhcp/nm-dhcp-manager.c @@ -164,6 +164,7 @@ client_start (NMDhcpManager *self, guint32 route_metric, const struct in6_addr *ipv6_ll_addr, GBytes *dhcp_client_id, + NMDhcpDuidEnforce enforce_duid, guint32 timeout, const char *dhcp_anycast_addr, const char *hostname, @@ -218,7 +219,7 @@ client_start (NMDhcpManager *self, if (addr_family == AF_INET) success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, last_ip4_address); else - success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, privacy, needed_prefixes); + success = nm_dhcp_client_start_ip6 (client, dhcp_client_id, enforce_duid, dhcp_anycast_addr, ipv6_ll_addr, hostname, privacy, needed_prefixes); if (!success) { remove_client_unref (self, client); @@ -280,7 +281,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self, return client_start (self, AF_INET, multi_idx, iface, ifindex, hwaddr, uuid, route_table, route_metric, NULL, - dhcp_client_id, timeout, dhcp_anycast_addr, hostname, + dhcp_client_id, 0, timeout, dhcp_anycast_addr, hostname, use_fqdn, FALSE, 0, last_ip_address, 0); } @@ -297,6 +298,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, + GBytes *duid, + NMDhcpDuidEnforce enforce_duid, guint32 timeout, const char *dhcp_anycast_addr, gboolean info_only, @@ -314,8 +317,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, hostname = dhcp_hostname ?: priv->default_hostname; } return client_start (self, AF_INET6, multi_idx, iface, ifindex, hwaddr, uuid, - route_table, route_metric, ll_addr, - NULL, timeout, dhcp_anycast_addr, hostname, TRUE, info_only, + route_table, route_metric, ll_addr, duid, enforce_duid, + timeout, dhcp_anycast_addr, hostname, TRUE, info_only, privacy, NULL, needed_prefixes); } diff --git a/src/dhcp/nm-dhcp-manager.h b/src/dhcp/nm-dhcp-manager.h index f8a7e31d..ed8ee742 100644 --- a/src/dhcp/nm-dhcp-manager.h +++ b/src/dhcp/nm-dhcp-manager.h @@ -72,6 +72,8 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, + GBytes *duid, + NMDhcpDuidEnforce enforce_duid, guint32 timeout, const char *dhcp_anycast_addr, gboolean info_only, diff --git a/src/dhcp/nm-dhcp-utils.h b/src/dhcp/nm-dhcp-utils.h index 5c127bd1..afb87c1a 100644 --- a/src/dhcp/nm-dhcp-utils.h +++ b/src/dhcp/nm-dhcp-utils.h @@ -24,6 +24,12 @@ #include "nm-ip4-config.h" #include "nm-ip6-config.h" +typedef enum { + NM_DHCP_DUID_ENFORCE_NEVER = 0, + NM_DHCP_DUID_ENFORCE_LEASE_FALLBACK, + NM_DHCP_DUID_ENFORCE_ALWAYS, +} NMDhcpDuidEnforce; + NMIP4Config *nm_dhcp_utils_ip4_config_from_options (struct _NMDedupMultiIndex *multi_idx, int ifindex, const char *iface, diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c index a8284b23..2f369aac 100644 --- a/src/dhcp/tests/test-dhcp-dhclient.c +++ b/src/dhcp/tests/test-dhcp-dhclient.c @@ -785,17 +785,18 @@ static void test_write_existing_duid (void) { const char *duid = "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302"; - const char *expected_contents = "default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n"; + const char *original_contents = "default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n"; + const char *expected_contents = "default-duid \"\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302\";\n"; GError *error = NULL; char *contents = NULL; gboolean success; const char *path = "test-dhclient-write-existing-duid.leases"; - success = g_file_set_contents (path, expected_contents, -1, &error); + success = g_file_set_contents (path, original_contents, -1, &error); g_assert_no_error (error); g_assert (success); - /* Save other DUID; should be a no-op */ + /* Save other DUID; should be overwritten */ success = nm_dhcp_dhclient_save_duid (path, duid, &error); g_assert_no_error (error); g_assert (success); @@ -811,14 +812,14 @@ test_write_existing_duid (void) g_free (contents); } +#define DUID "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302" static void test_write_existing_commented_duid (void) { - #define DUID "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302" - #define ORIG_CONTENTS "#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n" - const char *expected_contents = \ - "default-duid \"" DUID "\";\n" - ORIG_CONTENTS; +#define ORIG_CONTENTS "#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n" + const char *expected_contents = + "default-duid \"" DUID "\";\n" + ORIG_CONTENTS; GError *error = NULL; char *contents = NULL; gboolean success; @@ -828,7 +829,7 @@ test_write_existing_commented_duid (void) g_assert_no_error (error); g_assert (success); - /* Save other DUID; should be a no-op */ + /* Save other DUID; should be saved on top */ success = nm_dhcp_dhclient_save_duid (path, DUID, &error); g_assert_no_error (error); g_assert (success); @@ -842,6 +843,33 @@ test_write_existing_commented_duid (void) g_assert_cmpstr (expected_contents, ==, contents); g_free (contents); +#undef ORIG_CONTENTS +} + +static void +test_write_existing_multiline_duid (void) +{ +#define ORIG_CONTENTS "### Commented old DUID ###\n" \ + "#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n" + const char *expected_contents = \ + "default-duid \"" DUID "\";\n" + ORIG_CONTENTS; + GError *error = NULL; + gs_free char *contents = NULL; + gboolean success; + nmtst_auto_unlinkfile char *path = g_strdup ("test-dhclient-write-existing-multiline-duid.leases"); + + success = g_file_set_contents (path, ORIG_CONTENTS, -1, &error); + nmtst_assert_success (success, error); + + success = nm_dhcp_dhclient_save_duid (path, DUID, &error); + nmtst_assert_success (success, error); + + success = g_file_get_contents (path, &contents, NULL, &error); + nmtst_assert_success (success, error); + + g_assert_cmpstr (expected_contents, ==, contents); +#undef ORIG_CONTENTS } /*****************************************************************************/ @@ -1025,6 +1053,7 @@ main (int argc, char **argv) g_test_add_func ("/dhcp/dhclient/write_duid", test_write_duid); g_test_add_func ("/dhcp/dhclient/write_existing_duid", test_write_existing_duid); g_test_add_func ("/dhcp/dhclient/write_existing_commented_duid", test_write_existing_commented_duid); + g_test_add_func ("/dhcp/dhclient/write_existing_multiline_duid", test_write_existing_multiline_duid); return g_test_run (); } |