diff options
Diffstat (limited to 'src/dhcp-manager/nm-dhcp-client.c')
| -rw-r--r-- | src/dhcp-manager/nm-dhcp-client.c | 424 |
1 files changed, 235 insertions, 189 deletions
diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 980fcab8..03c11c74 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -28,6 +28,7 @@ #include <stdlib.h> #include <uuid/uuid.h> +#include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-logging.h" #include "nm-dbus-glib-types.h" @@ -38,6 +39,7 @@ typedef struct { GByteArray * hwaddr; gboolean ipv6; char * uuid; + guint priority; guint32 timeout; GByteArray * duid; @@ -57,9 +59,9 @@ typedef struct { G_DEFINE_TYPE_EXTENDED (NMDHCPClient, nm_dhcp_client, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT, {}) enum { - STATE_CHANGED, - TIMEOUT, - REMOVE, + SIGNAL_STATE_CHANGED, + SIGNAL_TIMEOUT, + SIGNAL_REMOVE, LAST_SIGNAL }; @@ -71,6 +73,7 @@ enum { PROP_HWADDR, PROP_IPV6, PROP_UUID, + PROP_PRIORITY, PROP_TIMEOUT, LAST_PROP }; @@ -80,7 +83,6 @@ enum { GPid nm_dhcp_client_get_pid (NMDHCPClient *self) { - g_return_val_if_fail (self != NULL, -1); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), -1); return NM_DHCP_CLIENT_GET_PRIVATE (self)->pid; @@ -89,7 +91,6 @@ nm_dhcp_client_get_pid (NMDHCPClient *self) const char * nm_dhcp_client_get_iface (NMDHCPClient *self) { - g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); return NM_DHCP_CLIENT_GET_PRIVATE (self)->iface; @@ -98,7 +99,6 @@ nm_dhcp_client_get_iface (NMDHCPClient *self) gboolean nm_dhcp_client_get_ipv6 (NMDHCPClient *self) { - g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); return NM_DHCP_CLIENT_GET_PRIVATE (self)->ipv6; @@ -107,7 +107,6 @@ nm_dhcp_client_get_ipv6 (NMDHCPClient *self) const char * nm_dhcp_client_get_uuid (NMDHCPClient *self) { - g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); return NM_DHCP_CLIENT_GET_PRIVATE (self)->uuid; @@ -138,9 +137,9 @@ watch_cleanup (NMDHCPClient *self) } void -nm_dhcp_client_stop_pid (GPid pid, const char *iface, guint timeout_secs) +nm_dhcp_client_stop_pid (GPid pid, const char *iface) { - int i = (timeout_secs ? timeout_secs : 3) * 5; /* default 3 seconds */ + int i = 5; /* roughly 0.5 seconds */ g_return_if_fail (pid > 0); @@ -167,7 +166,7 @@ nm_dhcp_client_stop_pid (GPid pid, const char *iface, guint timeout_secs) break; } } - g_usleep (G_USEC_PER_SEC / 5); + g_usleep (G_USEC_PER_SEC / 10); } if (i <= 0) { @@ -188,7 +187,6 @@ stop (NMDHCPClient *self, gboolean release, const GByteArray *duid) { NMDHCPClientPrivate *priv; - g_return_if_fail (self != NULL); g_return_if_fail (NM_IS_DHCP_CLIENT (self)); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); @@ -197,7 +195,7 @@ stop (NMDHCPClient *self, gboolean release, const GByteArray *duid) /* Clean up the watch handler since we're explicitly killing the daemon */ watch_cleanup (self); - nm_dhcp_client_stop_pid (priv->pid, priv->iface, 0); + nm_dhcp_client_stop_pid (priv->pid, priv->iface); priv->info_only = FALSE; } @@ -213,7 +211,7 @@ daemon_timeout (gpointer user_data) } else { nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 request timed out.", priv->iface); } - g_signal_emit (G_OBJECT (self), signals[TIMEOUT], 0); + g_signal_emit (G_OBJECT (self), signals[SIGNAL_TIMEOUT], 0); return FALSE; } @@ -223,7 +221,7 @@ signal_remove (gpointer user_data) NMDHCPClient *self = NM_DHCP_CLIENT (user_data); NM_DHCP_CLIENT_GET_PRIVATE (self)->remove_id = 0; - g_signal_emit (G_OBJECT (self), signals[REMOVE], 0); + g_signal_emit (G_OBJECT (self), signals[SIGNAL_REMOVE], 0); return FALSE; } @@ -238,12 +236,12 @@ dhcp_client_set_state (NMDHCPClient *self, priv->state = state; if (emit_state) - g_signal_emit (G_OBJECT (self), signals[STATE_CHANGED], 0, priv->state); + g_signal_emit (G_OBJECT (self), signals[SIGNAL_STATE_CHANGED], 0, priv->state); if (state == DHC_END || state == DHC_ABEND) { /* Start the remove signal timer */ if (remove_now) { - g_signal_emit (G_OBJECT (self), signals[REMOVE], 0); + g_signal_emit (G_OBJECT (self), signals[SIGNAL_REMOVE], 0); } else { if (!priv->remove_id) priv->remove_id = g_timeout_add_seconds (5, signal_remove, self); @@ -299,13 +297,12 @@ start_monitor (NMDHCPClient *self) gboolean nm_dhcp_client_start_ip4 (NMDHCPClient *self, - NMSettingIP4Config *s_ip4, - guint8 *dhcp_anycast_addr, + const char *dhcp_client_id, + GByteArray *dhcp_anycast_addr, const char *hostname) { NMDHCPClientPrivate *priv; - g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); @@ -316,7 +313,7 @@ nm_dhcp_client_start_ip4 (NMDHCPClient *self, nm_log_info (LOGD_DHCP, "Activation (%s) Beginning DHCPv4 transaction (timeout in %d seconds)", priv->iface, priv->timeout); - priv->pid = NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, s_ip4, dhcp_anycast_addr, hostname); + priv->pid = NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_client_id, dhcp_anycast_addr, hostname); if (priv->pid) start_monitor (self); @@ -334,7 +331,7 @@ machine_id_parse (const char *in, uuid_t uu) g_return_val_if_fail (in != NULL, FALSE); g_return_val_if_fail (strlen (in) == 32, FALSE); - for (i = 0; i < 32; i++, cp++) { + for (i = 0; i < 32; i++) { if (!g_ascii_isxdigit (in[i])) return FALSE; } @@ -437,7 +434,7 @@ get_duid (NMDHCPClient *self) duid = generate_duid_from_machine_id (); g_assert (duid); - if (nm_logging_level_enabled (LOGL_DEBUG)) { + if (nm_logging_enabled (LOGL_DEBUG, LOGD_DHCP6)) { escaped = escape_duid (duid); nm_log_dbg (LOGD_DHCP6, "Generated DUID %s", escaped); g_free (escaped); @@ -454,15 +451,13 @@ get_duid (NMDHCPClient *self) gboolean nm_dhcp_client_start_ip6 (NMDHCPClient *self, - NMSettingIP6Config *s_ip6, - guint8 *dhcp_anycast_addr, + GByteArray *dhcp_anycast_addr, const char *hostname, gboolean info_only) { NMDHCPClientPrivate *priv; char *escaped; - g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); @@ -476,7 +471,7 @@ nm_dhcp_client_start_ip6 (NMDHCPClient *self, if (!priv->duid) priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self); - if (nm_logging_level_enabled (LOGL_DEBUG)) { + if (nm_logging_enabled (LOGL_DEBUG, LOGD_DHCP)) { escaped = escape_duid (priv->duid); nm_log_dbg (LOGD_DHCP, "(%s): DHCPv6 DUID is '%s'", priv->iface, escaped); g_free (escaped); @@ -488,7 +483,6 @@ nm_dhcp_client_start_ip6 (NMDHCPClient *self, priv->iface, priv->timeout); priv->pid = NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self, - s_ip6, dhcp_anycast_addr, hostname, info_only, @@ -524,11 +518,13 @@ nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name) exe = proc_contents; if (!strcmp (exe, binary_name)) - nm_dhcp_client_stop_pid ((GPid) tmp, NULL, 0); + nm_dhcp_client_stop_pid ((GPid) tmp, NULL); } } - remove (pid_file); + if (remove (pid_file) == -1) + nm_log_dbg (LOGD_DHCP, "Could not remove dhcp pid file \"%s\": %d (%s)", pid_file, errno, g_strerror (errno)); + g_free (proc_path); g_free (pid_contents); g_free (proc_contents); @@ -539,7 +535,6 @@ nm_dhcp_client_stop (NMDHCPClient *self, gboolean release) { NMDHCPClientPrivate *priv; - g_return_if_fail (self != NULL); g_return_if_fail (NM_IS_DHCP_CLIENT (self)); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); @@ -582,63 +577,54 @@ state_is_bound (guint32 state) return FALSE; } -typedef struct { - NMDHCPState state; - const char *name; -} DhcState; - -#define STATE_TABLE_SIZE (sizeof (state_table) / sizeof (state_table[0])) - -static DhcState state_table[] = { - { DHC_NBI, "nbi" }, - { DHC_PREINIT, "preinit" }, - { DHC_PREINIT6,"preinit6" }, - { DHC_BOUND4, "bound" }, - { DHC_BOUND6, "bound6" }, - { DHC_IPV4LL, "ipv4ll" }, - { DHC_RENEW4, "renew" }, - { DHC_RENEW6, "renew6" }, - { DHC_REBOOT, "reboot" }, - { DHC_REBIND4, "rebind" }, - { DHC_REBIND6, "rebind6" }, - { DHC_STOP, "stop" }, - { DHC_STOP6, "stop6" }, - { DHC_MEDIUM, "medium" }, - { DHC_TIMEOUT, "timeout" }, - { DHC_FAIL, "fail" }, - { DHC_EXPIRE, "expire" }, - { DHC_EXPIRE6, "expire6" }, - { DHC_RELEASE, "release" }, - { DHC_RELEASE6,"release6" }, - { DHC_START, "start" }, - { DHC_ABEND, "abend" }, - { DHC_END, "end" }, - { DHC_DEPREF6, "depref6" }, +static const char *state_table[] = { + [DHC_NBI] = "nbi", + [DHC_PREINIT] = "preinit", + [DHC_PREINIT6] = "preinit6", + [DHC_BOUND4] = "bound", + [DHC_BOUND6] = "bound6", + [DHC_IPV4LL] = "ipv4ll", + [DHC_RENEW4] = "renew", + [DHC_RENEW6] = "renew6", + [DHC_REBOOT] = "reboot", + [DHC_REBIND4] = "rebind", + [DHC_REBIND6] = "rebind6", + [DHC_DEPREF6] = "depref6", + [DHC_STOP] = "stop", + [DHC_STOP6] = "stop6", + [DHC_MEDIUM] = "medium", + [DHC_TIMEOUT] = "timeout", + [DHC_FAIL] = "fail", + [DHC_EXPIRE] = "expire", + [DHC_EXPIRE6] = "expire6", + [DHC_RELEASE] = "release", + [DHC_RELEASE6] = "release6", + [DHC_START] = "start", + [DHC_ABEND] = "abend", + [DHC_END] = "end", }; -static inline const char * -state_to_string (guint32 state) +static const char * +state_to_string (NMDHCPState state) { - int i; - - for (i = 0; i < STATE_TABLE_SIZE; i++) { - if (state == state_table[i].state) - return state_table[i].name; - } - + if (state >= 0 && state < G_N_ELEMENTS (state_table)) + return state_table[state]; return NULL; } -static inline NMDHCPState +static NMDHCPState string_to_state (const char *name) { int i; - for (i = 0; i < STATE_TABLE_SIZE; i++) { - if (!strcasecmp (name, state_table[i].name)) - return state_table[i].state; - } + if (name) { + for (i = 0; i < G_N_ELEMENTS (state_table); i++) { + const char *n = state_table[i]; + if (n && !strcasecmp (name, n)) + return i; + } + } return 255; } @@ -705,7 +691,6 @@ nm_dhcp_client_new_options (NMDHCPClient *self, guint32 old_state; guint32 new_state; - g_return_if_fail (self != NULL); g_return_if_fail (NM_IS_DHCP_CLIENT (self)); g_return_if_fail (options != NULL); g_return_if_fail (reason != NULL); @@ -766,7 +751,6 @@ nm_dhcp_client_foreach_option (NMDHCPClient *self, GHashTableIter iter; gpointer iterkey, itervalue; - g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); g_return_val_if_fail (func != NULL, FALSE); @@ -813,10 +797,12 @@ nm_dhcp_client_foreach_option (NMDHCPClient *self, /********************************************/ static gboolean -ip4_process_dhcpcd_rfc3442_routes (const char *str, +ip4_process_dhcpcd_rfc3442_routes (NMDHCPClient *self, + const char *str, NMIP4Config *ip4_config, guint32 *gwaddr) { + NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); char **routes, **r; gboolean have_routes = FALSE; @@ -831,10 +817,9 @@ ip4_process_dhcpcd_rfc3442_routes (const char *str, for (r = routes; *r; r += 2) { char *slash; - NMIP4Route *route; + NMPlatformIP4Route route; int rt_cidr = 32; - struct in_addr rt_addr; - struct in_addr rt_route; + guint32 rt_addr, rt_route; slash = strchr(*r, '/'); if (slash) { @@ -856,17 +841,18 @@ ip4_process_dhcpcd_rfc3442_routes (const char *str, } have_routes = TRUE; - if (rt_cidr == 0 && rt_addr.s_addr == 0) { + if (rt_cidr == 0 && rt_addr == 0) { /* FIXME: how to handle multiple routers? */ - *gwaddr = rt_route.s_addr; + *gwaddr = rt_route; } else { - route = nm_ip4_route_new (); - nm_ip4_route_set_dest (route, (guint32) rt_addr.s_addr); - nm_ip4_route_set_prefix (route, rt_cidr); - nm_ip4_route_set_next_hop (route, (guint32) rt_route.s_addr); - - nm_ip4_config_take_route (ip4_config, route); nm_log_info (LOGD_DHCP4, " classless static route %s/%d gw %s", *r, rt_cidr, *(r + 1)); + memset (&route, 0, sizeof (route)); + route.network = rt_addr; + route.plen = rt_cidr; + route.gateway = rt_route; + route.source = NM_PLATFORM_SOURCE_DHCP; + route.metric = priv->priority; + nm_ip4_config_add_route (ip4_config, &route); } } @@ -876,14 +862,15 @@ out: } static const char ** -process_dhclient_rfc3442_route (const char **octets, NMIP4Route **out_route) +process_dhclient_rfc3442_route (const char **octets, NMPlatformIP4Route *route, gboolean *success) { const char **o = octets; int addr_len = 0, i = 0; long int tmp; - NMIP4Route *route; char *next_hop; - struct in_addr tmp_addr; + guint32 tmp_addr; + + *success = FALSE; if (!*o) return o; /* no prefix */ @@ -892,8 +879,8 @@ process_dhclient_rfc3442_route (const char **octets, NMIP4Route **out_route) if (tmp < 0 || tmp > 32) /* 32 == max IP4 prefix length */ return o; - route = nm_ip4_route_new (); - nm_ip4_route_set_prefix (route, (guint32) tmp); + memset (route, 0, sizeof (*route)); + route->plen = tmp; o++; if (tmp > 0) @@ -915,8 +902,8 @@ process_dhclient_rfc3442_route (const char **octets, NMIP4Route **out_route) g_free (str_addr); goto error; } - tmp_addr.s_addr &= nm_utils_ip4_prefix_to_netmask ((guint32) tmp); - nm_ip4_route_set_dest (route, tmp_addr.s_addr); + tmp_addr &= nm_utils_ip4_prefix_to_netmask ((guint32) tmp); + route->network = tmp_addr; } /* Handle next hop */ @@ -925,25 +912,27 @@ process_dhclient_rfc3442_route (const char **octets, NMIP4Route **out_route) g_free (next_hop); goto error; } - nm_ip4_route_set_next_hop (route, tmp_addr.s_addr); + route->gateway = tmp_addr; g_free (next_hop); - *out_route = route; + *success = TRUE; return o + 4; /* advance to past the next hop */ error: - nm_ip4_route_unref (route); return o; } static gboolean -ip4_process_dhclient_rfc3442_routes (const char *str, +ip4_process_dhclient_rfc3442_routes (NMDHCPClient *self, + const char *str, NMIP4Config *ip4_config, guint32 *gwaddr) { + NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); char **octets, **o; gboolean have_routes = FALSE; - NMIP4Route *route = NULL; + NMPlatformIP4Route route; + gboolean success; o = octets = g_strsplit_set (str, " .", 0); if (g_strv_length (octets) < 5) { @@ -952,32 +941,28 @@ ip4_process_dhclient_rfc3442_routes (const char *str, } while (*o) { - route = NULL; - o = (char **) process_dhclient_rfc3442_route ((const char **) o, &route); - if (!route) { + memset (&route, 0, sizeof (route)); + o = (char **) process_dhclient_rfc3442_route ((const char **) o, &route, &success); + if (!success) { nm_log_warn (LOGD_DHCP4, "ignoring invalid classless static routes"); break; } have_routes = TRUE; - if (nm_ip4_route_get_prefix (route) == 0) { + if (!route.plen) { /* gateway passed as classless static route */ - *gwaddr = nm_ip4_route_get_next_hop (route); - nm_ip4_route_unref (route); + *gwaddr = route.gateway; } else { - char addr[INET_ADDRSTRLEN + 1]; - char nh[INET_ADDRSTRLEN + 1]; - struct in_addr tmp; + char addr[INET_ADDRSTRLEN]; /* normal route */ - nm_ip4_config_take_route (ip4_config, route); + route.source = NM_PLATFORM_SOURCE_DHCP; + route.metric = priv->priority; + nm_ip4_config_add_route (ip4_config, &route); - tmp.s_addr = nm_ip4_route_get_dest (route); - inet_ntop (AF_INET, &tmp, addr, sizeof (addr)); - tmp.s_addr = nm_ip4_route_get_next_hop (route); - inet_ntop (AF_INET, &tmp, nh, sizeof (nh)); nm_log_info (LOGD_DHCP4, " classless static route %s/%d gw %s", - addr, nm_ip4_route_get_prefix (route), nh); + nm_utils_inet4_ntop (route.network, addr), route.plen, + nm_utils_inet4_ntop (route.gateway, NULL)); } } @@ -987,7 +972,8 @@ out: } static gboolean -ip4_process_classless_routes (GHashTable *options, +ip4_process_classless_routes (NMDHCPClient *self, + GHashTable *options, NMIP4Config *ip4_config, guint32 *gwaddr) { @@ -1043,15 +1029,16 @@ ip4_process_classless_routes (GHashTable *options, if (strchr (str, '/')) { /* dhcpcd format */ - return ip4_process_dhcpcd_rfc3442_routes (str, ip4_config, gwaddr); + return ip4_process_dhcpcd_rfc3442_routes (self, str, ip4_config, gwaddr); } - return ip4_process_dhclient_rfc3442_routes (str, ip4_config, gwaddr); + return ip4_process_dhclient_rfc3442_routes (self, str, ip4_config, gwaddr); } static void -process_classful_routes (GHashTable *options, NMIP4Config *ip4_config) +process_classful_routes (NMDHCPClient *self, GHashTable *options, NMIP4Config *ip4_config) { + NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); const char *str; char **searches, **s; @@ -1066,9 +1053,8 @@ process_classful_routes (GHashTable *options, NMIP4Config *ip4_config) } for (s = searches; *s; s += 2) { - NMIP4Route *route; - struct in_addr rt_addr; - struct in_addr rt_route; + NMPlatformIP4Route route; + guint32 rt_addr, rt_route; if (inet_pton (AF_INET, *s, &rt_addr) <= 0) { nm_log_warn (LOGD_DHCP, "DHCP provided invalid static route address: '%s'", *s); @@ -1079,15 +1065,26 @@ process_classful_routes (GHashTable *options, NMIP4Config *ip4_config) continue; } - // FIXME: ensure the IP addresse and route are sane - - route = nm_ip4_route_new (); - nm_ip4_route_set_dest (route, (guint32) rt_addr.s_addr); - nm_ip4_route_set_prefix (route, 32); /* 255.255.255.255 */ - nm_ip4_route_set_next_hop (route, (guint32) rt_route.s_addr); + // FIXME: ensure the IP address and route are sane + + memset (&route, 0, sizeof (route)); + route.network = rt_addr; + /* RFC 2132, updated by RFC 3442: + The Static Routes option (option 33) does not provide a subnet mask + for each route - it is assumed that the subnet mask is implicit in + whatever network number is specified in each route entry */ + route.plen = nm_utils_ip4_get_default_prefix (rt_addr); + if (rt_addr & ~nm_utils_ip4_prefix_to_netmask (route.plen)) { + /* RFC 943: target not "this network"; using host routing */ + route.plen = 32; + } + route.gateway = rt_route; + route.source = NM_PLATFORM_SOURCE_DHCP; + route.metric = priv->priority; - nm_ip4_config_take_route (ip4_config, route); - nm_log_info (LOGD_DHCP, " static route %s gw %s", *s, *(s + 1)); + nm_ip4_config_add_route (ip4_config, &route); + nm_log_info (LOGD_DHCP, " static route %s", + nm_platform_ip4_route_to_string (&route)); } out: @@ -1145,59 +1142,47 @@ ip4_options_to_config (NMDHCPClient *self) { NMDHCPClientPrivate *priv; NMIP4Config *ip4_config = NULL; - struct in_addr tmp_addr; - NMIP4Address *addr = NULL; + guint32 tmp_addr; + NMPlatformIP4Address address; char *str = NULL; - guint32 gwaddr = 0, prefix = 0; + guint32 gwaddr = 0, plen = 0; - g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); g_return_val_if_fail (priv->options != NULL, NULL); ip4_config = nm_ip4_config_new (); - if (!ip4_config) { - nm_log_warn (LOGD_DHCP4, "(%s): couldn't allocate memory for an IP4Config!", priv->iface); - return NULL; - } - - addr = nm_ip4_address_new (); - if (!addr) { - nm_log_warn (LOGD_DHCP4, "(%s): couldn't allocate memory for an IP4 Address!", priv->iface); - goto error; - } + memset (&address, 0, sizeof (address)); + address.timestamp = nm_utils_get_monotonic_timestamp_s (); str = g_hash_table_lookup (priv->options, "new_ip_address"); if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) { - nm_ip4_address_set_address (addr, tmp_addr.s_addr); + address.address = tmp_addr; nm_log_info (LOGD_DHCP4, " address %s", str); } else goto error; str = g_hash_table_lookup (priv->options, "new_subnet_mask"); if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) { - prefix = nm_utils_ip4_netmask_to_prefix (tmp_addr.s_addr); - nm_log_info (LOGD_DHCP4, " prefix %d (%s)", prefix, str); + plen = nm_utils_ip4_netmask_to_prefix (tmp_addr); + nm_log_info (LOGD_DHCP4, " plen %d (%s)", plen, str); } else { /* Get default netmask for the IP according to appropriate class. */ - prefix = nm_utils_ip4_get_default_prefix (nm_ip4_address_get_address (addr)); - nm_log_info (LOGD_DHCP4, " prefix %d (default)", prefix); + plen = nm_utils_ip4_get_default_prefix (address.address); + nm_log_info (LOGD_DHCP4, " plen %d (default)", plen); } - nm_ip4_address_set_prefix (addr, prefix); + address.plen = plen; /* Routes: if the server returns classless static routes, we MUST ignore * the 'static_routes' option. */ - if (!ip4_process_classless_routes (priv->options, ip4_config, &gwaddr)) - process_classful_routes (priv->options, ip4_config); + if (!ip4_process_classless_routes (self, priv->options, ip4_config, &gwaddr)) + process_classful_routes (self, priv->options, ip4_config); if (gwaddr) { - char buf[INET_ADDRSTRLEN + 1]; - - inet_ntop (AF_INET, &gwaddr, buf, sizeof (buf)); - nm_log_info (LOGD_DHCP4, " gateway %s", buf); - nm_ip4_address_set_gateway (addr, gwaddr); + nm_log_info (LOGD_DHCP4, " gateway %s", nm_utils_inet4_ntop (gwaddr, NULL)); + nm_ip4_config_set_gateway (ip4_config, gwaddr); } else { /* If the gateway wasn't provided as a classless static route with a * subnet length of 0, try to find it using the old-style 'routers' option. @@ -1209,8 +1194,8 @@ ip4_options_to_config (NMDHCPClient *self) for (s = routers; *s; s++) { /* FIXME: how to handle multiple routers? */ - if (inet_pton (AF_INET, *s, &tmp_addr) > 0) { - nm_ip4_address_set_gateway (addr, tmp_addr.s_addr); + if (inet_pton (AF_INET, *s, &gwaddr) > 0) { + nm_ip4_config_set_gateway (ip4_config, gwaddr); nm_log_info (LOGD_DHCP4, " gateway %s", *s); break; } else @@ -1220,8 +1205,51 @@ ip4_options_to_config (NMDHCPClient *self) } } - nm_ip4_config_take_address (ip4_config, addr); - addr = NULL; + /* + * RFC 2132, section 9.7 + * DHCP clients use the contents of the 'server identifier' field + * as the destination address for any DHCP messages unicast to + * the DHCP server. + * + * Some ISP's provide leases from central servers that are on + * different subnets that the address offered. If the host + * does not configure the interface as the default route, the + * dhcp server may not be reachable via unicast, and a host + * specific route is needed. + **/ + str = g_hash_table_lookup (priv->options, "new_dhcp_server_identifier"); + if (str) { + if (inet_pton (AF_INET, str, &tmp_addr) > 0) { + NMPlatformIP4Route route; + guint32 mask = nm_utils_ip4_prefix_to_netmask (address.plen); + + nm_log_info (LOGD_DHCP4, " server identifier %s", str); + if ((tmp_addr & mask) != (address.address & mask)) { + /* DHCP server not on assigned subnet, route needed */ + memset (&route, 0, sizeof (route)); + route.network = tmp_addr; + route.plen = 32; + /* this will be a device route if gwaddr is 0 */ + route.gateway = gwaddr; + route.source = NM_PLATFORM_SOURCE_DHCP; + route.metric = priv->priority; + nm_ip4_config_add_route (ip4_config, &route); + nm_log_dbg (LOGD_IP, "adding route for server identifier: %s", + nm_platform_ip4_route_to_string (&route)); + } + } + else + nm_log_warn (LOGD_DHCP4, "ignoring invalid server identifier '%s'", str); + } + + str = g_hash_table_lookup (priv->options, "new_dhcp_lease_time"); + if (str) { + address.lifetime = address.preferred = strtoul (str, NULL, 10); + nm_log_info (LOGD_DHCP4, " lease time %d", address.lifetime); + } + + address.source = NM_PLATFORM_SOURCE_DHCP; + nm_ip4_config_add_address (ip4_config, &address); str = g_hash_table_lookup (priv->options, "new_host_name"); if (str) @@ -1234,7 +1262,7 @@ ip4_options_to_config (NMDHCPClient *self) for (s = searches; *s; s++) { if (inet_pton (AF_INET, *s, &tmp_addr) > 0) { - nm_ip4_config_add_nameserver (ip4_config, tmp_addr.s_addr); + nm_ip4_config_add_nameserver (ip4_config, tmp_addr); nm_log_info (LOGD_DHCP4, " nameserver '%s'", *s); } else nm_log_warn (LOGD_DHCP4, "ignoring invalid nameserver '%s'", *s); @@ -1265,7 +1293,7 @@ ip4_options_to_config (NMDHCPClient *self) for (s = searches; *s; s++) { if (inet_pton (AF_INET, *s, &tmp_addr) > 0) { - nm_ip4_config_add_wins (ip4_config, tmp_addr.s_addr); + nm_ip4_config_add_wins (ip4_config, tmp_addr); nm_log_info (LOGD_DHCP4, " wins '%s'", *s); } else nm_log_warn (LOGD_DHCP4, "ignoring invalid WINS server '%s'", *s); @@ -1299,7 +1327,7 @@ ip4_options_to_config (NMDHCPClient *self) for (s = searches; *s; s++) { if (inet_pton (AF_INET, *s, &tmp_addr) > 0) { - nm_ip4_config_add_nis_server (ip4_config, tmp_addr.s_addr); + nm_ip4_config_add_nis_server (ip4_config, tmp_addr); nm_log_info (LOGD_DHCP4, " nis '%s'", *s); } else nm_log_warn (LOGD_DHCP4, "ignoring invalid NIS server '%s'", *s); @@ -1310,8 +1338,6 @@ ip4_options_to_config (NMDHCPClient *self) return ip4_config; error: - if (addr) - nm_ip4_address_unref (addr); g_object_unref (ip4_config); return NULL; } @@ -1321,7 +1347,6 @@ nm_dhcp_client_get_ip4_config (NMDHCPClient *self, gboolean test) { NMDHCPClientPrivate *priv; - g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); @@ -1354,14 +1379,17 @@ ip6_options_to_config (NMDHCPClient *self) NMDHCPClientPrivate *priv; NMIP6Config *ip6_config = NULL; struct in6_addr tmp_addr; - NMIP6Address *addr = NULL; + NMPlatformIP6Address address; char *str = NULL; GHashTableIter iter; gpointer key, value; - g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); + memset (&address, 0, sizeof (address)); + address.plen = 128; + address.timestamp = nm_utils_get_monotonic_timestamp_s (); + priv = NM_DHCP_CLIENT_GET_PRIVATE (self); g_return_val_if_fail (priv->options != NULL, NULL); @@ -1372,9 +1400,17 @@ ip6_options_to_config (NMDHCPClient *self) } ip6_config = nm_ip6_config_new (); - if (!ip6_config) { - nm_log_warn (LOGD_DHCP6, "(%s): couldn't allocate memory for an IP6Config!", priv->iface); - return NULL; + + str = g_hash_table_lookup (priv->options, "new_max_life"); + if (str) { + address.lifetime = strtoul (str, NULL, 10); + nm_log_info (LOGD_DHCP6, " valid_lft %d", address.lifetime); + } + + str = g_hash_table_lookup (priv->options, "new_preferred_life"); + if (str) { + address.preferred = strtoul (str, NULL, 10); + nm_log_info (LOGD_DHCP6, " preferred_lft %d", address.preferred); } str = g_hash_table_lookup (priv->options, "new_ip6_address"); @@ -1385,14 +1421,10 @@ ip6_options_to_config (NMDHCPClient *self) goto error; } - addr = nm_ip6_address_new (); - g_assert (addr); - nm_ip6_address_set_address (addr, &tmp_addr); - /* DHCPv6 IA_NA assignments are single address only */ - nm_ip6_address_set_prefix (addr, 128); - nm_log_info (LOGD_DHCP6, " address %s/128", str); - - nm_ip6_config_take_address (ip6_config, addr); + address.address = tmp_addr; + address.source = NM_PLATFORM_SOURCE_DHCP; + nm_ip6_config_add_address (ip6_config, &address); + nm_log_info (LOGD_DHCP6, " address %s", str); } else if (priv->info_only == FALSE) { /* No address in Managed mode is a hard error */ goto error; @@ -1433,7 +1465,6 @@ nm_dhcp_client_get_ip6_config (NMDHCPClient *self, gboolean test) { NMDHCPClientPrivate *priv; - g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); @@ -1481,6 +1512,9 @@ get_property (GObject *object, guint prop_id, case PROP_UUID: g_value_set_string (value, priv->uuid); break; + case PROP_PRIORITY: + g_value_set_uint (value, priv->priority); + break; case PROP_TIMEOUT: g_value_set_uint (value, priv->timeout); break; @@ -1513,6 +1547,10 @@ set_property (GObject *object, guint prop_id, /* construct-only */ priv->uuid = g_value_dup_string (value); break; + case PROP_PRIORITY: + /* construct-only */ + priv->priority = g_value_get_uint (value); + break; case PROP_TIMEOUT: priv->timeout = g_value_get_uint (value); break; @@ -1605,6 +1643,14 @@ nm_dhcp_client_class_init (NMDHCPClientClass *client_class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property + (object_class, PROP_PRIORITY, + g_param_spec_uint (NM_DHCP_CLIENT_PRIORITY, + "priority", + "Priority", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, PROP_TIMEOUT, g_param_spec_uint (NM_DHCP_CLIENT_TIMEOUT, "timeout", @@ -1613,8 +1659,8 @@ nm_dhcp_client_class_init (NMDHCPClientClass *client_class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); /* signals */ - signals[STATE_CHANGED] = - g_signal_new ("state-changed", + signals[SIGNAL_STATE_CHANGED] = + g_signal_new (NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMDHCPClientClass, state_changed), @@ -1622,8 +1668,8 @@ nm_dhcp_client_class_init (NMDHCPClientClass *client_class) g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); - signals[TIMEOUT] = - g_signal_new ("timeout", + signals[SIGNAL_TIMEOUT] = + g_signal_new (NM_DHCP_CLIENT_SIGNAL_TIMEOUT, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMDHCPClientClass, timeout), @@ -1631,8 +1677,8 @@ nm_dhcp_client_class_init (NMDHCPClientClass *client_class) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - signals[REMOVE] = - g_signal_new ("remove", + signals[SIGNAL_REMOVE] = + g_signal_new (NM_DHCP_CLIENT_SIGNAL_REMOVE, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMDHCPClientClass, remove), |