about summary refs log tree commit diff
path: root/src/dhcp-manager/nm-dhcp-dhclient-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dhcp-manager/nm-dhcp-dhclient-utils.c')
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient-utils.c152
1 files changed, 106 insertions, 46 deletions
diff --git a/src/dhcp-manager/nm-dhcp-dhclient-utils.c b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
index 8527e6c0..46e8e0b8 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient-utils.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
@@ -17,21 +17,24 @@
  * Copyright (C) 2011 Red Hat, Inc.
  */
 
-#include <config.h>
+#include "config.h"
 
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <string.h>
 #include <ctype.h>
+#include <arpa/inet.h>
 
 #include "nm-dhcp-dhclient-utils.h"
+#include "nm-dhcp-utils.h"
 #include "nm-ip4-config.h"
 #include "nm-utils.h"
+#include "nm-platform.h"
 #include "NetworkManagerUtils.h"
+#include "gsystem-local-alloc.h"
+#include "nm-utils-internal.h"
 
 #define CLIENTID_TAG            "send dhcp-client-identifier"
-#define CLIENTID_FORMAT         CLIENTID_TAG " \"%s\"; # added by NetworkManager"
-#define CLIENTID_FORMAT_OCTETS  CLIENTID_TAG " %s; # added by NetworkManager"
 
 #define HOSTNAME4_TAG    "send host-name"
 #define HOSTNAME4_FORMAT HOSTNAME4_TAG " \"%s\"; # added by NetworkManager"
@@ -71,32 +74,39 @@ add_hostname (GString *str, const char *format, const char *hostname)
 }
 
 static void
-add_ip4_config (GString *str, const char *dhcp_client_id, const char *hostname)
+add_ip4_config (GString *str, GBytes *client_id, const char *hostname)
 {
-	if (dhcp_client_id) {
-		gboolean is_octets = TRUE;
-		int i = 0;
+	if (client_id) {
+		const char *p;
+		gsize l;
+		guint i;
 
-		while (dhcp_client_id[i]) {
-			if ((i % 3) != 2 && !g_ascii_isxdigit (dhcp_client_id[i])) {
-				is_octets = FALSE;
-				break;
-			}
-			if ((i % 3) == 2 && dhcp_client_id[i] != ':') {
-				is_octets = FALSE;
+		p = g_bytes_get_data (client_id, &l);
+		g_assert (p);
+
+		/* Allow type 0 (non-hardware address) to be represented as a string
+		 * as long as all the characters are printable.
+		 */
+		for (i = 1; (p[0] == 0) && i < l; i++) {
+			if (!g_ascii_isprint (p[i]))
 				break;
-			}
-			i++;
 		}
 
-		/* If the client ID is just hex digits and : then don't use quotes,
-		 * because dhclient expects either a quoted ASCII string, or a byte
-		 * array formated as hex octets separated by :
-		 */
-		if (is_octets)
-			g_string_append_printf (str, CLIENTID_FORMAT_OCTETS "\n", dhcp_client_id);
-		else
-			g_string_append_printf (str, CLIENTID_FORMAT "\n", dhcp_client_id);
+		g_string_append (str, CLIENTID_TAG " ");
+		if (i < l) {
+			/* Unprintable; convert to a hex string */
+			for (i = 0; i < l; i++) {
+				if (i > 0)
+					g_string_append_c (str, ':');
+				g_string_append_printf (str, "%02x", (guint8) p[i]);
+			}
+		} else {
+			/* Printable; just add to the line minus the 'type' */
+			g_string_append_c (str, '"');
+			g_string_append_len (str, p + 1, l - 1);
+			g_string_append_c (str, '"');
+		}
+		g_string_append (str, "; # added by NetworkManager\n");
 	}
 
 	add_hostname (str, HOSTNAME4_FORMAT "\n", hostname);
@@ -124,19 +134,74 @@ add_ip6_config (GString *str, const char *hostname)
 	                 "send fqdn.server-update on;\n");
 }
 
+static GBytes *
+read_client_id (const char *str)
+{
+	gs_free char *s = NULL;
+	char *p;
+
+	g_assert (!strncmp (str, CLIENTID_TAG, STRLEN (CLIENTID_TAG)));
+
+	str += STRLEN (CLIENTID_TAG);
+	while (g_ascii_isspace (*str))
+		str++;
+
+	if (*str == '"') {
+		s = g_strdup (str + 1);
+		p = strrchr (s, '"');
+		if (p)
+			*p = '\0';
+		else
+			return NULL;
+	} else
+		s = g_strdup (str);
+
+	g_strchomp (s);
+	if (s[strlen (s) - 1] == ';')
+		s[strlen (s) - 1] = '\0';
+
+	return nm_dhcp_utils_client_id_string_to_bytes (s);
+}
+
+GBytes *
+nm_dhcp_dhclient_get_client_id_from_config_file (const char *path)
+{
+	gs_free char *contents = NULL;
+	gs_strfreev char **lines = NULL;
+	char **line;
+
+	g_return_val_if_fail (path != NULL, NULL);
+
+	if (!g_file_test (path, G_FILE_TEST_EXISTS))
+		return NULL;
+
+	if (!g_file_get_contents (path, &contents, NULL, NULL))
+		return NULL;
+
+	lines = g_strsplit_set (contents, "\n\r", 0);
+	for (line = lines; lines && *line; line++) {
+		if (!strncmp (*line, CLIENTID_TAG, STRLEN (CLIENTID_TAG)))
+			return read_client_id (*line);
+	}
+	return NULL;
+}
+
 char *
 nm_dhcp_dhclient_create_config (const char *interface,
                                 gboolean is_ip6,
-                                const char *dhcp_client_id,
-                                GByteArray *anycast_addr,
+                                GBytes *client_id,
+                                const char *anycast_addr,
                                 const char *hostname,
                                 const char *orig_path,
-                                const char *orig_contents)
+                                const char *orig_contents,
+                                GBytes **out_new_client_id)
 {
 	GString *new_contents;
 	GPtrArray *alsoreq;
 	int i;
 
+	g_return_val_if_fail (!anycast_addr || nm_utils_hwaddr_valid (anycast_addr, ETH_ALEN), NULL);
+
 	new_contents = g_string_new (_("# Created by NetworkManager\n"));
 	alsoreq = g_ptr_array_sized_new (5);
 
@@ -153,11 +218,15 @@ nm_dhcp_dhclient_create_config (const char *interface,
 			if (!strlen (g_strstrip (p)))
 				continue;
 
-			/* Override config file "dhcp-client-id" and use one from the
-			 * connection.
-			 */
-			if (dhcp_client_id && !strncmp (p, CLIENTID_TAG, strlen (CLIENTID_TAG)))
-				continue;
+			if (!strncmp (p, CLIENTID_TAG, strlen (CLIENTID_TAG))) {
+				/* Override config file "dhcp-client-id" and use one from the connection */
+				if (client_id)
+					continue;
+
+				/* Otherwise capture and return the existing client id */
+				if (out_new_client_id)
+					*out_new_client_id = read_client_id (p);
+			}
 
 			/* Override config file hostname and use one from the connection */
 			if (hostname) {
@@ -225,9 +294,8 @@ nm_dhcp_dhclient_create_config (const char *interface,
 		add_also_request (alsoreq, "dhcp6.name-servers");
 		add_also_request (alsoreq, "dhcp6.domain-search");
 		add_also_request (alsoreq, "dhcp6.client-id");
-		add_also_request (alsoreq, "dhcp6.server-id");
 	} else {
-		add_ip4_config (new_contents, dhcp_client_id, hostname);
+		add_ip4_config (new_contents, client_id, hostname);
 		add_also_request (alsoreq, "rfc3442-classless-static-routes");
 		add_also_request (alsoreq, "ms-classless-static-routes");
 		add_also_request (alsoreq, "static-routes");
@@ -246,22 +314,14 @@ nm_dhcp_dhclient_create_config (const char *interface,
 
 	g_string_append_c (new_contents, '\n');
 
-	if (anycast_addr && anycast_addr->len == 6) {
-		const guint8 *p_anycast_addr = anycast_addr->data;
-
+	if (anycast_addr) {
 		g_string_append_printf (new_contents, "interface \"%s\" {\n"
 		                        " initial-interval 1; \n"
-		                        " anycast-mac ethernet %02x:%02x:%02x:%02x:%02x:%02x;\n"
+		                        " anycast-mac ethernet %s;\n"
 		                        "}\n",
-		                        interface,
-		                        p_anycast_addr[0], p_anycast_addr[1],
-		                        p_anycast_addr[2], p_anycast_addr[3],
-		                        p_anycast_addr[4], p_anycast_addr[5]);
+		                        interface, anycast_addr);
 	}
 
-	/* Finally, assert that anycast_addr was unset or a 48 bit mac address. */
-	g_return_val_if_fail (!anycast_addr || anycast_addr->len == 6, g_string_free (new_contents, FALSE));
-
 	return g_string_free (new_contents, FALSE);
 }
 
@@ -629,7 +689,7 @@ nm_dhcp_dhclient_read_lease_ip_configs (const char *iface,
 
 		address.timestamp = now_monotonic_ts;
 		address.lifetime = address.preferred = expiry;
-		address.source = NM_PLATFORM_SOURCE_DHCP;
+		address.source = NM_IP_CONFIG_SOURCE_DHCP;
 
 		ip4 = nm_ip4_config_new ();
 		nm_ip4_config_add_address (ip4, &address);