about summary refs log tree commit diff
path: root/src/dhcp-manager/nm-dhcp-dhclient.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dhcp-manager/nm-dhcp-dhclient.c')
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient.c190
1 files changed, 107 insertions, 83 deletions
diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c
index 043cd63d..347d97c4 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient.c
@@ -32,7 +32,6 @@
 #include <stdio.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
-#include <ctype.h>
 
 #include <config.h>
 
@@ -46,16 +45,6 @@ G_DEFINE_TYPE (NMDHCPDhclient, nm_dhcp_dhclient, NM_TYPE_DHCP_CLIENT)
 
 #define NM_DHCP_DHCLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_DHCLIENT, NMDHCPDhclientPrivate))
 
-#if defined(TARGET_DEBIAN) || defined(TARGET_SUSE) || defined(TARGET_MANDRIVA)
-#if defined(DHCLIENT_V3)
-#define NM_DHCLIENT_LEASE_DIR			LOCALSTATEDIR "/lib/dhcp3"
-#else
-#define NM_DHCLIENT_LEASE_DIR           LOCALSTATEDIR "/lib/dhcp"
-#endif
-#else
-#define NM_DHCLIENT_LEASE_DIR           LOCALSTATEDIR "/lib/dhclient"
-#endif
-
 #define ACTION_SCRIPT_PATH	LIBEXECDIR "/nm-dhcp-client.action"
 
 typedef struct {
@@ -90,10 +79,9 @@ nm_dhcp_dhclient_get_path (const char *try_first)
 }
 
 static char *
-get_leasefile_for_iface (const char * iface, const char *uuid, gboolean ipv6)
+get_dhclient_leasefile (const char * iface, const char *uuid, gboolean ipv6)
 {
-	return g_strdup_printf ("%s/dhclient%s-%s-%s.lease",
-	                        NM_DHCLIENT_LEASE_DIR,
+	return g_strdup_printf (NMSTATEDIR "/dhclient%s-%s-%s.lease",
 	                        ipv6 ? "6" : "",
 	                        uuid,
 	                        iface);
@@ -140,7 +128,7 @@ add_lease_option (GHashTable *hash, char *line)
 }
 
 GSList *
-nm_dhcp_dhclient_get_lease_config (const char *iface, const char *uuid)
+nm_dhcp_dhclient_get_lease_config (const char *iface, const char *uuid, gboolean ipv6)
 {
 	GSList *parsed = NULL, *iter, *leases = NULL;
 	char *contents = NULL;
@@ -148,7 +136,11 @@ nm_dhcp_dhclient_get_lease_config (const char *iface, const char *uuid)
 	char **line, **split = NULL;
 	GHashTable *hash = NULL;
 
-	leasefile = get_leasefile_for_iface (iface, uuid, FALSE);
+	/* IPv6 not supported */
+	if (ipv6)
+		return NULL;
+
+	leasefile = get_dhclient_leasefile (iface, uuid, FALSE);
 	if (!leasefile)
 		return NULL;
 
@@ -308,7 +300,9 @@ out:
 static gboolean
 merge_dhclient_config (const char *iface,
                        const char *conf_file,
+                       gboolean is_ip6,
                        NMSettingIP4Config *s_ip4,
+                       NMSettingIP6Config *s_ip6,
                        guint8 *anycast_addr,
                        const char *hostname,
                        const char *orig_path,
@@ -324,13 +318,13 @@ merge_dhclient_config (const char *iface,
 		GError *read_error = NULL;
 
 		if (!g_file_get_contents (orig_path, &orig, NULL, &read_error)) {
-			nm_log_warn (LOGD_DHCP, "(%s): error reading dhclient configuration %s: %s",
-			             iface, orig_path, read_error->message);
+			nm_log_warn (LOGD_DHCP, "(%s): error reading dhclient%s configuration %s: %s",
+			             iface, is_ip6 ? "6" : "", orig_path, read_error->message);
 			g_error_free (read_error);
 		}
 	}
 
-	new = nm_dhcp_dhclient_create_config (iface, s_ip4, anycast_addr, hostname, orig_path, orig);
+	new = nm_dhcp_dhclient_create_config (iface, is_ip6, s_ip4, s_ip6, anycast_addr, hostname, orig_path, orig);
 	g_assert (new);
 	success = g_file_set_contents (conf_file, new, -1, error);
 	g_free (new);
@@ -339,6 +333,64 @@ merge_dhclient_config (const char *iface,
 	return success;
 }
 
+static char *
+get_dhclient_config (const char * iface, const char *uuid, gboolean ipv6)
+{
+	char *path;
+
+	/* NetworkManager-overridden configuration can be used to ship DHCP config
+	 * with NetworkManager itself. It can be uuid-specific, device-specific
+	 * or generic.
+	 */
+	if (uuid) {
+		path = g_strdup_printf (NMCONFDIR "/dhclient%s-%s.conf", ipv6 ? "6" : "", uuid);
+		if (g_file_test (path, G_FILE_TEST_EXISTS))
+			return path;
+		g_free (path);
+	}
+
+	path = g_strdup_printf (NMCONFDIR "/dhclient%s-%s.conf", ipv6 ? "6" : "", iface);
+	if (g_file_test (path, G_FILE_TEST_EXISTS))
+		return path;
+	g_free (path);
+
+	path = g_strdup_printf (NMCONFDIR "/dhclient%s.conf", ipv6 ? "6" : "");
+	if (g_file_test (path, G_FILE_TEST_EXISTS))
+		return path;
+	g_free (path);
+
+	/* Distribution's dhclient configuration is used so that we can use
+	 * configuration shipped with dhclient (if any).
+	 *
+	 * This replaces conditional compilation based on distribution name. Fedora
+	 * and Debian store the configs in /etc/dhcp while upstream defaults to /etc
+	 * which is then used by many other distributions. Some distributions
+	 * (including Fedora) don't even provide a default configuration file.
+	 */
+	path = g_strdup_printf (SYSCONFDIR "/dhcp/dhclient%s-%s.conf", ipv6 ? "6" : "", iface);
+	if (g_file_test (path, G_FILE_TEST_EXISTS))
+		return path;
+	g_free (path);
+
+	path = g_strdup_printf (SYSCONFDIR "/dhclient%s-%s.conf", ipv6 ? "6" : "", iface);
+	if (g_file_test (path, G_FILE_TEST_EXISTS))
+		return path;
+	g_free (path);
+
+	path = g_strdup_printf (SYSCONFDIR "/dhcp/dhclient%s.conf", ipv6 ? "6" : "");
+	if (g_file_test (path, G_FILE_TEST_EXISTS))
+		return path;
+	g_free (path);
+
+	path = g_strdup_printf (SYSCONFDIR "/dhclient%s.conf", ipv6 ? "6" : "");
+	if (g_file_test (path, G_FILE_TEST_EXISTS))
+		return path;
+	g_free (path);
+
+	return NULL;
+}
+
+
 /* NM provides interface-specific options; thus the same dhclient config
  * file cannot be used since DHCP transactions can happen in parallel.
  * Since some distros don't have default per-interface dhclient config files,
@@ -347,59 +399,32 @@ merge_dhclient_config (const char *iface,
  */
 static char *
 create_dhclient_config (const char *iface,
+                        gboolean is_ip6,
                         NMSettingIP4Config *s_ip4,
+                        NMSettingIP6Config *s_ip6,
                         guint8 *dhcp_anycast_addr,
                         const char *hostname)
 {
-	char *orig = NULL, *tmp, *conf_file = NULL;
+	char *orig = NULL, *new = NULL;
 	GError *error = NULL;
 	gboolean success = FALSE;
 
 	g_return_val_if_fail (iface != NULL, NULL);
 
-#if defined(TARGET_SUSE)
-	orig = g_strdup (SYSCONFDIR "/dhclient.conf");
-#elif defined(TARGET_DEBIAN) || defined(TARGET_GENTOO)
-#if defined(DHCLIENT_V3)
-	orig = g_strdup (SYSCONFDIR "/dhcp3/dhclient.conf");
-#else
-	orig = g_strdup (SYSCONFDIR "/dhcp/dhclient.conf");
-#endif
-#else
-	orig = g_strdup_printf (SYSCONFDIR "/dhclient-%s.conf", iface);
-#endif
-
-	if (!orig) {
-		nm_log_warn (LOGD_DHCP, "(%s): not enough memory for dhclient options.", iface);
-		return NULL;
-	}
-
-#if !defined(TARGET_SUSE) && !defined(TARGET_DEBIAN) && !defined(TARGET_GENTOO)
-	/* Try /etc/dhcp/ too (rh #607759) */
-	if (!g_file_test (orig, G_FILE_TEST_EXISTS)) {
-		g_free (orig);
-		orig = g_strdup_printf (SYSCONFDIR "/dhcp/dhclient-%s.conf", iface);
-		if (!orig) {
-			nm_log_warn (LOGD_DHCP, "(%s): not enough memory for dhclient options.", iface);
-			return NULL;
-		}
-	}
-#endif
-
-	tmp = g_strdup_printf ("nm-dhclient-%s.conf", iface);
-	conf_file = g_build_filename ("/var", "run", tmp, NULL);
-	g_free (tmp);
+	new = g_strdup_printf (NMSTATEDIR "/dhclient%s-%s.conf", is_ip6 ? "6" : "", iface);
 
+	/* TODO: also support UUID */
+	orig = get_dhclient_config (iface, NULL, is_ip6);
 	error = NULL;
-	success = merge_dhclient_config (iface, conf_file, s_ip4, dhcp_anycast_addr, hostname, orig, &error);
+	success = merge_dhclient_config (iface, new, is_ip6, s_ip4, s_ip6, dhcp_anycast_addr, hostname, orig, &error);
 	if (!success) {
-		nm_log_warn (LOGD_DHCP, "(%s): error creating dhclient configuration: %s",
-		             iface, error->message);
+		nm_log_warn (LOGD_DHCP, "(%s): error creating dhclient%s configuration: %s",
+		             iface, is_ip6 ? "6" : "", error->message);
 		g_error_free (error);
 	}
 
 	g_free (orig);
-	return conf_file;
+	return new;
 }
 
 
@@ -439,13 +464,6 @@ dhclient_start (NMDHCPClient *client,
 
 	log_domain = ipv6 ? LOGD_DHCP6 : LOGD_DHCP4;
 
-#if defined(DHCLIENT_V3)
-	if (ipv6) {
-		nm_log_warn (log_domain, "(%s): ISC dhcp3 does not support IPv6", iface);
-		return -1;
-	}
-#endif
-
 	if (!g_file_test (priv->path, G_FILE_TEST_EXISTS)) {
 		nm_log_warn (log_domain, "%s does not exist.", priv->path);
 		return -1;
@@ -471,7 +489,7 @@ dhclient_start (NMDHCPClient *client,
 	}
 
 	g_free (priv->lease_file);
-	priv->lease_file = get_leasefile_for_iface (iface, uuid, ipv6);
+	priv->lease_file = get_dhclient_leasefile (iface, uuid, ipv6);
 	if (!priv->lease_file) {
 		nm_log_warn (log_domain, "(%s): not enough memory for dhclient options.", iface);
 		return -1;
@@ -485,16 +503,11 @@ dhclient_start (NMDHCPClient *client,
 	if (release)
 		g_ptr_array_add (argv, (gpointer) "-r");
 
-#if !defined(DHCLIENT_V3)
 	if (ipv6) {
 		g_ptr_array_add (argv, (gpointer) "-6");
 		if (mode_opt)
 			g_ptr_array_add (argv, (gpointer) mode_opt);
-	} else {
-		g_ptr_array_add (argv, (gpointer) "-4");
 	}
-#endif
-
 	g_ptr_array_add (argv, (gpointer) "-sf");	/* Set script file */
 	g_ptr_array_add (argv, (gpointer) ACTION_SCRIPT_PATH );
 
@@ -546,17 +559,17 @@ dhclient_start (NMDHCPClient *client,
 }
 
 static GPid
-real_ip4_start (NMDHCPClient *client,
-                NMSettingIP4Config *s_ip4,
-                guint8 *dhcp_anycast_addr,
-                const char *hostname)
+ip4_start (NMDHCPClient *client,
+           NMSettingIP4Config *s_ip4,
+           guint8 *dhcp_anycast_addr,
+           const char *hostname)
 {
 	NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
 	const char *iface;
 
 	iface = nm_dhcp_client_get_iface (client);
 
-	priv->conf_file = create_dhclient_config (iface, s_ip4, dhcp_anycast_addr, hostname);
+	priv->conf_file = create_dhclient_config (iface, FALSE, s_ip4, NULL, dhcp_anycast_addr, hostname);
 	if (!priv->conf_file) {
 		nm_log_warn (LOGD_DHCP4, "(%s): error creating dhclient configuration file.", iface);
 		return -1;
@@ -566,17 +579,28 @@ real_ip4_start (NMDHCPClient *client,
 }
 
 static GPid
-real_ip6_start (NMDHCPClient *client,
-                NMSettingIP6Config *s_ip6,
-                guint8 *dhcp_anycast_addr,
-                const char *hostname,
-                gboolean info_only)
+ip6_start (NMDHCPClient *client,
+           NMSettingIP6Config *s_ip6,
+           guint8 *dhcp_anycast_addr,
+           const char *hostname,
+           gboolean info_only)
 {
+	NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
+	const char *iface;
+
+	iface = nm_dhcp_client_get_iface (client);
+
+	priv->conf_file = create_dhclient_config (iface, TRUE, NULL, s_ip6, dhcp_anycast_addr, hostname);
+	if (!priv->conf_file) {
+		nm_log_warn (LOGD_DHCP6, "(%s): error creating dhclient6 configuration file.", iface);
+		return -1;
+	}
+
 	return dhclient_start (client, info_only ? "-S" : "-N", FALSE);
 }
 
 static void
-real_stop (NMDHCPClient *client, gboolean release)
+stop (NMDHCPClient *client, gboolean release)
 {
 	NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client);
 
@@ -635,8 +659,8 @@ nm_dhcp_dhclient_class_init (NMDHCPDhclientClass *dhclient_class)
 	/* virtual methods */
 	object_class->dispose = dispose;
 
-	client_class->ip4_start = real_ip4_start;
-	client_class->ip6_start = real_ip6_start;
-	client_class->stop = real_stop;
+	client_class->ip4_start = ip4_start;
+	client_class->ip6_start = ip6_start;
+	client_class->stop = stop;
 }