diff options
-rw-r--r-- | ChangeLog | 28 | ||||
-rw-r--r-- | libnm-util/nm-setting-ip4-config.c | 45 | ||||
-rw-r--r-- | libnm-util/nm-setting-ip4-config.h | 4 | ||||
-rw-r--r-- | po/POTFILES.in | 1 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-manager.c | 176 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-manager.h | 4 | ||||
-rw-r--r-- | src/nm-device.c | 7 |
7 files changed, 236 insertions, 29 deletions
@@ -1,3 +1,31 @@ +2008-07-03 Dan Williams <dcbw@redhat.com> + + * libnm-util/nm-setting-ip4-config.c + libnm-util/nm-setting-ip4-config.h + - Add properties for DHCP Client Identifier and DHCP Hostname + + * src/dhcp-manager/nm-dhcp-manager.c + src/dhcp-manager/nm-dhcp-manager.h + - (nm_dhcp_manager_begin_transaction): take the connection's ip4-config + setting as an argument to pass on to the dhclient config file + creation function + - (nm_dhcp_manager_cancel_transaction_real): remove dhclient config when + DHCP is torn down + - (dhclient_run): punt config file handling to create_dhclient_config() + - (create_dhclient_config): create an interface-specific dhclient + config file since there may need to be interface-specific options + passed to dhclient + - (merge_dhclient_config): merge normal distro dhclient config file and + add options from the connection + - (nm_dhcp_device_new): generate the interface specific dhclient + config file path once + - (nm_dhcp_device_destroy): handle partially initialized objects; free + dhclient config file path + + * src/nm-device.c + - (real_act_stage3_ip_config_start): pass ip4-config, if any, to the + DHCP manager when starting DHCP + 2008-07-02 Dan Williams <dcbw@redhat.com> * libnm-util/nm-setting-8021x.c diff --git a/libnm-util/nm-setting-ip4-config.c b/libnm-util/nm-setting-ip4-config.c index b8bfae94fc..a04b70320d 100644 --- a/libnm-util/nm-setting-ip4-config.c +++ b/libnm-util/nm-setting-ip4-config.c @@ -1,4 +1,4 @@ -/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ #include <string.h> @@ -54,6 +54,8 @@ enum { PROP_ADDRESSES, PROP_ROUTES, PROP_IGNORE_DHCP_DNS, + PROP_DHCP_CLIENT_ID, + PROP_DHCP_HOSTNAME, LAST_PROP }; @@ -120,6 +122,16 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) return FALSE; } + if (self->dhcp_client_id && !strlen (self->dhcp_client_id)) { + g_warning ("invalid DHCP client ID"); + return FALSE; + } + + if (self->dhcp_hostname && !strlen (self->dhcp_hostname)) { + g_warning ("invalid DHCP client ID"); + return FALSE; + } + return TRUE; } @@ -176,6 +188,14 @@ set_property (GObject *object, guint prop_id, case PROP_IGNORE_DHCP_DNS: setting->ignore_dhcp_dns = g_value_get_boolean (value); break; + case PROP_DHCP_CLIENT_ID: + g_free (setting->dhcp_client_id); + setting->dhcp_client_id = g_value_dup_string (value); + break; + case PROP_DHCP_HOSTNAME: + g_free (setting->dhcp_hostname); + setting->dhcp_hostname = g_value_dup_string (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -207,6 +227,12 @@ get_property (GObject *object, guint prop_id, case PROP_IGNORE_DHCP_DNS: g_value_set_boolean (value, setting->ignore_dhcp_dns); break; + case PROP_DHCP_CLIENT_ID: + g_value_set_string (value, setting->dhcp_client_id); + break; + case PROP_DHCP_HOSTNAME: + g_value_set_string (value, setting->dhcp_hostname); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -273,4 +299,21 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) "Ignore DHCP DNS", FALSE, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + g_object_class_install_property + (object_class, PROP_DHCP_CLIENT_ID, + g_param_spec_string (NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, + "DHCP Client ID", + "DHCP Client ID", + NULL, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + g_object_class_install_property + (object_class, PROP_DHCP_HOSTNAME, + g_param_spec_string (NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME, + "DHCP Hostname", + "DHCP Hostname", + NULL, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); } + diff --git a/libnm-util/nm-setting-ip4-config.h b/libnm-util/nm-setting-ip4-config.h index 14cd1e7d7a..ec73d869d3 100644 --- a/libnm-util/nm-setting-ip4-config.h +++ b/libnm-util/nm-setting-ip4-config.h @@ -36,6 +36,8 @@ GQuark nm_setting_ip4_config_error_quark (void); #define NM_SETTING_IP4_CONFIG_ADDRESSES "addresses" #define NM_SETTING_IP4_CONFIG_ROUTES "routes" #define NM_SETTING_IP4_CONFIG_IGNORE_DHCP_DNS "ignore-dhcp-dns" +#define NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID "dhcp-client-id" +#define NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME "dhcp-hostname" #define NM_SETTING_IP4_CONFIG_METHOD_DHCP "dhcp" #define NM_SETTING_IP4_CONFIG_METHOD_AUTOIP "autoip" @@ -57,6 +59,8 @@ typedef struct { GSList *addresses; /* array of NMSettingIP4Address */ GSList *routes; /* array of NMSettingIP4Address */ gboolean ignore_dhcp_dns; + char *dhcp_client_id; + char *dhcp_hostname; } NMSettingIP4Config; typedef struct { diff --git a/po/POTFILES.in b/po/POTFILES.in index 249b8bd172..3425d7b9a5 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -3,6 +3,7 @@ # Please keep this file sorted alphabetically. src/nm-netlink-monitor.c src/NetworkManager.c +src/dhcp-manager/nm-dhcp-manager.c src/named-manager/nm-named-manager.c system-settings/plugins/ifcfg-fedora/plugin.c system-settings/src/main.c diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index cc5844cdfc..b69b0dced2 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -22,6 +22,7 @@ #include <glib.h> +#include <glib/gi18n.h> #include <dbus/dbus.h> #include <sys/socket.h> #include <netinet/in.h> @@ -32,6 +33,7 @@ #include <stdlib.h> #include <errno.h> #include <unistd.h> +#include <fcntl.h> #include "nm-dhcp-manager.h" #include "nm-marshal.h" @@ -55,14 +57,6 @@ #define NM_DHCP_TIMEOUT 45 /* DHCP timeout, in seconds */ -#if defined(TARGET_SUSE) -#define DHCLIENT_CONF_PATH SYSCONFDIR "/dhclient.conf" -#elif defined(TARGET_DEBIAN) -#define DHCLIENT_CONF_PATH SYSCONFDIR "/dhcp3/dhclient.conf" -#else -#define DHCLIENT_CONF_PATH_FORMAT SYSCONFDIR "/dhclient-%s.conf" -#endif - static const char *dhclient_binary_paths[] = { @@ -76,6 +70,7 @@ typedef struct { char * iface; guchar state; GPid dhclient_pid; + char * dhclient_conf; guint timeout_id; guint watch_id; NMDHCPManager * manager; @@ -224,9 +219,19 @@ nm_dhcp_device_watch_cleanup (NMDHCPDevice * device) static void nm_dhcp_device_destroy (NMDHCPDevice *device) { + int ret; + nm_dhcp_device_timeout_cleanup (device); nm_dhcp_device_watch_cleanup (device); - g_hash_table_destroy (device->options); + + if (device->options) + g_hash_table_destroy (device->options); + + if (device->dhclient_conf) { + ret = unlink (device->dhclient_conf); + g_free (device->dhclient_conf); + } + g_free (device->iface); g_slice_free (NMDHCPDevice, device); } @@ -529,6 +534,7 @@ nm_dhcp_device_new (NMDHCPManager *manager, const char *iface) { NMDHCPDevice *device; GHashTable * hash = NM_DHCP_MANAGER_GET_PRIVATE (manager)->devices; + char *tmp; device = g_slice_new0 (NMDHCPDevice); if (!device) { @@ -546,6 +552,10 @@ nm_dhcp_device_new (NMDHCPManager *manager, const char *iface) device->manager = manager; + tmp = g_strdup_printf ("nm-dhclient-%s.conf", iface); + device->dhclient_conf = g_build_filename ("/var", "run", tmp, NULL); + g_free (tmp); + nm_dhcp_manager_cancel_transaction_real (device, FALSE); /* Do this after the transaction cancel since that clears options out */ @@ -564,9 +574,7 @@ nm_dhcp_device_new (NMDHCPManager *manager, const char *iface) return device; error: - g_hash_table_destroy (device->options); - g_free (device->iface); - g_slice_free (NMDHCPDevice, device); + nm_dhcp_device_destroy (device); return NULL; } @@ -607,8 +615,131 @@ dhclient_child_setup (gpointer user_data G_GNUC_UNUSED) setpgid (pid, pid); } + +#define DHCP_CLIENT_ID_TAG "send dhcp-client-identifier" +#define DHCP_CLIENT_ID_FORMAT DHCP_CLIENT_ID_TAG " \"%s\"; # added by NetworkManager" + +#define DHCP_HOSTNAME_TAG "send host-name" +#define DHCP_HOSTNAME_FORMAT DHCP_HOSTNAME_TAG " \"%s\"; # added by NetworkManager" + static gboolean -dhclient_run (NMDHCPDevice *device) +merge_dhclient_config (NMDHCPDevice *device, + NMSettingIP4Config *s_ip4, + const char *contents, + const char *orig, + GError **error) +{ + GString *new_contents; + gboolean success = FALSE; + + g_return_val_if_fail (device != NULL, FALSE); + g_return_val_if_fail (device->iface != NULL, FALSE); + + new_contents = g_string_new (_("# Created by NetworkManager\n")); + + /* Add existing options, if any, but ignore stuff NM will replace. */ + if (contents) { + char **lines = NULL, **line; + + g_string_append_printf (new_contents, _("# Merged from %s\n\n"), orig); + + lines = g_strsplit_set (contents, "\n\r", 0); + for (line = lines; lines && *line; line++) { + gboolean ignore = FALSE; + + if (!strlen (g_strstrip (*line))) + continue; + + if ( s_ip4 + && s_ip4->dhcp_client_id + && !strncmp (*line, DHCP_CLIENT_ID_TAG, strlen (DHCP_CLIENT_ID_TAG))) + ignore = TRUE; + + if ( s_ip4 + && s_ip4->dhcp_client_id + && !strncmp (*line, DHCP_HOSTNAME_TAG, strlen (DHCP_HOSTNAME_TAG))) + ignore = TRUE; + + if (!ignore) { + g_string_append (new_contents, *line); + g_string_append_c (new_contents, '\n'); + } + } + + if (lines) + g_strfreev (lines); + } else + g_string_append_c (new_contents, '\n'); + + /* Add NM options from connection */ + if (s_ip4 && s_ip4->dhcp_client_id) + g_string_append_printf (new_contents, DHCP_CLIENT_ID_FORMAT "\n", s_ip4->dhcp_client_id); + + if (s_ip4 && s_ip4->dhcp_hostname) + g_string_append_printf (new_contents, DHCP_HOSTNAME_FORMAT "\n", s_ip4->dhcp_hostname); + + if (g_file_set_contents (device->dhclient_conf, new_contents->str, -1, error)) + success = TRUE; + + g_string_free (new_contents, TRUE); + return success; +} + +/* 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, + * read their single config file and merge that into a custom per-interface + * config file along with the NM options. + */ +static gboolean +create_dhclient_config (NMDHCPDevice *device, NMSettingIP4Config *s_ip4) +{ + char *orig = NULL, *contents = NULL; + GError *error = NULL; + gboolean success = FALSE; + + g_return_val_if_fail (device != NULL, FALSE); + +#if defined(TARGET_SUSE) + orig = g_strdup (SYSCONFDIR "/dhclient.conf"); +#elif defined(TARGET_DEBIAN) + orig = g_strdup (SYSCONFDIR "/dhcp3/dhclient.conf"); +#else + orig = g_strdup_printf (SYSCONFDIR "/dhclient-%s.conf", device->iface); +#endif + + if (!orig) { + nm_warning ("%s: not enough memory for dhclient options.", device->iface); + return FALSE; + } + + if (!g_file_test (orig, G_FILE_TEST_EXISTS)) + goto out; + + if (!g_file_get_contents (orig, &contents, NULL, &error)) { + nm_warning ("%s: error reading dhclient configuration %s: %s", + device->iface, orig, error->message); + g_error_free (error); + goto out; + } + +out: + error = NULL; + if (merge_dhclient_config (device, s_ip4, contents, orig, &error)) + success = TRUE; + else { + nm_warning ("%s: error creating dhclient configuration: %s", + device->iface, error->message); + g_error_free (error); + } + + g_free (contents); + g_free (orig); + return success; +} + +static gboolean +dhclient_run (NMDHCPDevice *device, NMSettingIP4Config *s_ip4) { const char ** dhclient_binary = NULL; GPtrArray * dhclient_argv = NULL; @@ -616,7 +747,6 @@ dhclient_run (NMDHCPDevice *device) GError * error = NULL; char * pidfile = NULL; char * leasefile = NULL; - char * conffile = NULL; gboolean success = FALSE; char * pid_contents = NULL; @@ -645,15 +775,8 @@ dhclient_run (NMDHCPDevice *device) goto out; } -#ifdef DHCLIENT_CONF_PATH_FORMAT - conffile = g_strdup_printf (DHCLIENT_CONF_PATH_FORMAT, device->iface); -#else - conffile = g_strdup (DHCLIENT_CONF_PATH); -#endif - if (!conffile) { - nm_warning ("%s: not enough memory for dhclient options.", device->iface); + if (!create_dhclient_config (device, s_ip4)) goto out; - } /* Kill any existing dhclient bound to this interface */ if (g_file_get_contents (pidfile, &pid_contents, NULL, NULL)) { @@ -679,7 +802,7 @@ dhclient_run (NMDHCPDevice *device) g_ptr_array_add (dhclient_argv, (gpointer) leasefile); g_ptr_array_add (dhclient_argv, (gpointer) "-cf"); /* Set interface config file */ - g_ptr_array_add (dhclient_argv, (gpointer) conffile); + g_ptr_array_add (dhclient_argv, (gpointer) device->dhclient_conf); g_ptr_array_add (dhclient_argv, (gpointer) device->iface); g_ptr_array_add (dhclient_argv, NULL); @@ -701,7 +824,6 @@ dhclient_run (NMDHCPDevice *device) out: g_free (pid_contents); - g_free (conffile); g_free (leasefile); g_free (pidfile); g_ptr_array_free (dhclient_argv, TRUE); @@ -711,6 +833,7 @@ out: gboolean nm_dhcp_manager_begin_transaction (NMDHCPManager *manager, const char *iface, + NMSettingIP4Config *s_ip4, guint32 timeout) { NMDHCPManagerPrivate *priv; @@ -740,7 +863,7 @@ nm_dhcp_manager_begin_transaction (NMDHCPManager *manager, nm_dhcp_manager_handle_timeout, device); - dhclient_run (device); + dhclient_run (device, s_ip4); return TRUE; } @@ -810,6 +933,9 @@ nm_dhcp_manager_cancel_transaction_real (NMDHCPDevice *device, gboolean blocking g_free (leasefile); } + /* Clean up config file if it got left around */ + remove (device->dhclient_conf); + nm_dhcp_device_watch_cleanup (device); nm_dhcp_device_timeout_cleanup (device); g_hash_table_remove_all (device->options); diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h index 2aaf0ba098..21a1a8ba05 100644 --- a/src/dhcp-manager/nm-dhcp-manager.h +++ b/src/dhcp-manager/nm-dhcp-manager.h @@ -23,6 +23,9 @@ #include <glib/gtypes.h> #include <glib-object.h> + +#include <nm-setting-ip4-config.h> + #include "nm-ip4-config.h" #define NM_TYPE_DHCP_MANAGER (nm_dhcp_manager_get_type ()) @@ -68,6 +71,7 @@ GType nm_dhcp_manager_get_type (void); NMDHCPManager *nm_dhcp_manager_get (void); gboolean nm_dhcp_manager_begin_transaction (NMDHCPManager *manager, const char *iface, + NMSettingIP4Config *s_ip4, guint32 timeout); void nm_dhcp_manager_cancel_transaction (NMDHCPManager *manager, const char *iface); diff --git a/src/nm-device.c b/src/nm-device.c index 453b4e0fab..733897133e 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -525,16 +525,16 @@ nm_device_activate_schedule_stage2_device_config (NMDevice *self) static NMActStageReturn real_act_stage3_ip_config_start (NMDevice *self) { - NMSettingIP4Config *setting; + NMSettingIP4Config *s_ip4; NMActRequest *req; NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; req = nm_device_get_act_request (self); - setting = (NMSettingIP4Config *) nm_connection_get_setting (nm_act_request_get_connection (req), + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (nm_act_request_get_connection (req), NM_TYPE_SETTING_IP4_CONFIG); /* If we did not receive IP4 configuration information, default to DHCP */ - if (!setting || !strcmp (setting->method, NM_SETTING_IP4_CONFIG_METHOD_DHCP)) { + if (!s_ip4 || !strcmp (s_ip4->method, NM_SETTING_IP4_CONFIG_METHOD_DHCP)) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); gboolean success; @@ -547,6 +547,7 @@ real_act_stage3_ip_config_start (NMDevice *self) success = nm_dhcp_manager_begin_transaction (priv->dhcp_manager, nm_device_get_iface (self), + s_ip4, 45); g_signal_handler_unblock (priv->dhcp_manager, priv->dhcp_state_sigid); |