summary refs log tree commit diff
path: root/src/dhcp
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2018-06-17 14:54:10 +0200
committerMichael Biebl <biebl@debian.org>2018-06-17 14:54:10 +0200
commit069cb5c3a525ebcc19cc2927964258acaca87b13 (patch)
tree66ac6b21a44d630c0fc281c0df327239d491226a /src/dhcp
parent04bc9e1cd3544445d883ad29ea108c1645c8e7b7 (diff)
New upstream version 1.11.90 upstream/1.11.90
Diffstat (limited to 'src/dhcp')
-rw-r--r--src/dhcp/nm-dhcp-client.c76
-rw-r--r--src/dhcp/nm-dhcp-client.h7
-rw-r--r--src/dhcp/nm-dhcp-dhclient-utils.c41
-rw-r--r--src/dhcp/nm-dhcp-dhclient.c7
-rw-r--r--src/dhcp/nm-dhcp-manager.c11
-rw-r--r--src/dhcp/nm-dhcp-manager.h2
-rw-r--r--src/dhcp/nm-dhcp-utils.h6
-rw-r--r--src/dhcp/tests/test-dhcp-dhclient.c47
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 ();
 }