diff options
Diffstat (limited to 'src/dhcp')
| -rw-r--r-- | src/dhcp/nm-dhcp-client-logging.h | 21 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-client.c | 166 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-client.h | 29 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-dhclient-utils.c | 60 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-dhclient-utils.h | 9 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-dhclient.c | 104 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-dhcpcanon.c | 272 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-listener.c | 67 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-manager.c | 55 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-manager.h | 16 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-systemd.c | 271 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-utils.c | 88 | ||||
| -rw-r--r-- | src/dhcp/nm-dhcp-utils.h | 10 | ||||
| -rw-r--r-- | src/dhcp/tests/test-dhcp-dhclient.c | 84 | ||||
| -rw-r--r-- | src/dhcp/tests/test-dhcp-utils.c | 140 |
15 files changed, 941 insertions, 451 deletions
diff --git a/src/dhcp/nm-dhcp-client-logging.h b/src/dhcp/nm-dhcp-client-logging.h index 1047a7d7..1ed47170 100644 --- a/src/dhcp/nm-dhcp-client-logging.h +++ b/src/dhcp/nm-dhcp-client-logging.h @@ -23,6 +23,23 @@ #include "nm-dhcp-client.h" +static inline NMLogDomain +_nm_dhcp_client_get_domain (NMDhcpClient *self) +{ + if (self) { + switch (nm_dhcp_client_get_addr_family (self)) { + case AF_INET: + return LOGD_DHCP4; + case AF_INET6: + return LOGD_DHCP6; + default: + nm_assert_not_reached (); + break; + } + } + return LOGD_DHCP; +} + #define _NMLOG_PREFIX_NAME "dhcp" #define _NMLOG_DOMAIN LOGD_DHCP #define _NMLOG(level, ...) \ @@ -38,9 +55,7 @@ if (nm_logging_enabled (_level, _NMLOG_DOMAIN)) { \ NMDhcpClient *_self = (NMDhcpClient *) (self); \ const char *__ifname = _self ? nm_dhcp_client_get_iface (_self) : NULL; \ - const NMLogDomain _domain = !_self \ - ? LOGD_DHCP \ - : (nm_dhcp_client_get_ipv6 (_self) ? LOGD_DHCP6 : LOGD_DHCP4); \ + const NMLogDomain _domain = _nm_dhcp_client_get_domain (_self); \ \ nm_log (_level, _domain, __ifname, NULL, \ "%s%s%s%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index 0906f5be..20ea092f 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -29,6 +29,10 @@ #include <stdio.h> #include <stdlib.h> #include <uuid/uuid.h> +#include <linux/rtnetlink.h> + +#include "nm-utils/nm-dedup-multi.h" +#include "nm-utils/nm-random-utils.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" @@ -48,33 +52,36 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; NM_GOBJECT_PROPERTIES_DEFINE_BASE ( + PROP_MULTI_IDX, + PROP_ADDR_FAMILY, PROP_IFACE, PROP_IFINDEX, PROP_HWADDR, - PROP_IPV6, PROP_UUID, - PROP_PRIORITY, + PROP_ROUTE_TABLE, + PROP_ROUTE_METRIC, PROP_TIMEOUT, ); typedef struct _NMDhcpClientPrivate { + NMDedupMultiIndex *multi_idx; char * iface; - int ifindex; GByteArray * hwaddr; - gboolean ipv6; char * uuid; - guint32 priority; - guint32 timeout; GByteArray * duid; GBytes * client_id; char * hostname; - gboolean use_fqdn; - - NMDhcpState state; pid_t pid; guint timeout_id; guint watch_id; - gboolean info_only; + int addr_family; + int ifindex; + guint32 route_table; + guint32 route_metric; + guint32 timeout; + NMDhcpState state; + bool info_only:1; + bool use_fqdn:1; } NMDhcpClientPrivate; G_DEFINE_TYPE_EXTENDED (NMDhcpClient, nm_dhcp_client, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT, {}) @@ -91,6 +98,14 @@ nm_dhcp_client_get_pid (NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE (self)->pid; } +NMDedupMultiIndex * +nm_dhcp_client_get_multi_idx (NMDhcpClient *self) +{ + g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); + + return NM_DHCP_CLIENT_GET_PRIVATE (self)->multi_idx; +} + const char * nm_dhcp_client_get_iface (NMDhcpClient *self) { @@ -107,12 +122,12 @@ nm_dhcp_client_get_ifindex (NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE (self)->ifindex; } -gboolean -nm_dhcp_client_get_ipv6 (NMDhcpClient *self) +int +nm_dhcp_client_get_addr_family (NMDhcpClient *self) { - g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); + g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), AF_UNSPEC); - return NM_DHCP_CLIENT_GET_PRIVATE (self)->ipv6; + return NM_DHCP_CLIENT_GET_PRIVATE (self)->addr_family; } const char * @@ -140,11 +155,19 @@ nm_dhcp_client_get_hw_addr (NMDhcpClient *self) } guint32 -nm_dhcp_client_get_priority (NMDhcpClient *self) +nm_dhcp_client_get_route_table (NMDhcpClient *self) +{ + g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), RT_TABLE_MAIN); + + return NM_DHCP_CLIENT_GET_PRIVATE (self)->route_table; +} + +guint32 +nm_dhcp_client_get_route_metric (NMDhcpClient *self) { g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), G_MAXUINT32); - return NM_DHCP_CLIENT_GET_PRIVATE (self)->priority; + return NM_DHCP_CLIENT_GET_PRIVATE (self)->route_metric; } guint32 @@ -303,8 +326,8 @@ nm_dhcp_client_set_state (NMDhcpClient *self, watch_cleanup (self); if (new_state == NM_DHCP_STATE_BOUND) { - g_assert ( (priv->ipv6 && NM_IS_IP6_CONFIG (ip_config)) - || (!priv->ipv6 && NM_IS_IP4_CONFIG (ip_config))); + g_assert ( (priv->addr_family == AF_INET && NM_IS_IP4_CONFIG (ip_config)) + || (priv->addr_family == AF_INET6 && NM_IS_IP6_CONFIG (ip_config))); g_assert (options); } else { g_assert (ip_config == NULL); @@ -319,7 +342,8 @@ nm_dhcp_client_set_state (NMDhcpClient *self, if ((priv->state == new_state) && (new_state != NM_DHCP_STATE_BOUND)) return; - if (priv->ipv6 && new_state == NM_DHCP_STATE_BOUND) { + if ( priv->addr_family == AF_INET6 + && new_state == NM_DHCP_STATE_BOUND) { char *start, *iaid; iaid = g_hash_table_lookup (options, "iaid"); @@ -392,6 +416,10 @@ nm_dhcp_client_start_timeout (NMDhcpClient *self) /* Set up a timeout on the transaction to kill it after the timeout */ g_assert (priv->timeout_id == 0); + + if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) + return; + priv->timeout_id = g_timeout_add_seconds (priv->timeout, transaction_timeout, self); @@ -426,10 +454,13 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self, priv = NM_DHCP_CLIENT_GET_PRIVATE (self); g_return_val_if_fail (priv->pid == -1, FALSE); - g_return_val_if_fail (priv->ipv6 == FALSE, FALSE); + g_return_val_if_fail (priv->addr_family == AF_INET, FALSE); g_return_val_if_fail (priv->uuid != NULL, FALSE); - _LOGI ("activation: beginning transaction (timeout in %d seconds)", priv->timeout); + if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) + _LOGI ("activation: beginning transaction (no timeout)"); + else + _LOGI ("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout); if (dhcp_client_id) tmp = nm_dhcp_utils_client_id_string_to_bytes (dhcp_client_id); @@ -451,8 +482,6 @@ generate_duid_from_machine_id (void) gsize sumlen = sizeof (buffer); const guint16 duid_type = g_htons (4); uuid_t uuid; - GRand *generator; - guint i; gs_free char *machine_id_s = NULL; gs_free char *str = NULL; @@ -468,10 +497,7 @@ generate_duid_from_machine_id (void) "or " LOCALSTATEDIR "/lib/dbus/machine-id to generate " "DHCPv6 DUID; creating non-persistent random DUID."); - generator = g_rand_new (); - for (i = 0; i < sizeof (buffer) / sizeof (guint32); i++) - ((guint32 *) buffer)[i] = g_rand_int (generator); - g_rand_free (generator); + nm_utils_random_bytes (buffer, sizeof (buffer)); } /* Generate a DHCP Unique Identifier for DHCPv6 using the @@ -528,7 +554,7 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, priv = NM_DHCP_CLIENT_GET_PRIVATE (self); g_return_val_if_fail (priv->pid == -1, FALSE); - g_return_val_if_fail (priv->ipv6 == TRUE, FALSE); + 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 @@ -544,8 +570,10 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, priv->info_only = info_only; - _LOGI ("activation: beginning transaction (timeout in %d seconds)", - priv->timeout); + if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) + _LOGI ("activation: beginning transaction (no timeout)"); + else + _LOGI ("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout); return NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self, dhcp_anycast_addr, @@ -744,7 +772,7 @@ nm_dhcp_client_handle_event (gpointer unused, GVariant *value; /* Copy options */ - str_options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + str_options = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); g_variant_iter_init (&iter, options); while (g_variant_iter_next (&iter, "{&sv}", &name, &value)) { maybe_add_option (self, str_options, name, value); @@ -763,18 +791,20 @@ nm_dhcp_client_handle_event (gpointer unused, /* Create the IP config */ g_warn_if_fail (g_hash_table_size (str_options)); if (g_hash_table_size (str_options)) { - if (priv->ipv6) { - prefix = nm_dhcp_utils_ip6_prefix_from_options (str_options); - ip_config = (GObject *) nm_dhcp_utils_ip6_config_from_options (priv->ifindex, + if (priv->addr_family == AF_INET) { + ip_config = (GObject *) nm_dhcp_utils_ip4_config_from_options (nm_dhcp_client_get_multi_idx (self), + priv->ifindex, priv->iface, str_options, - priv->priority, - priv->info_only); + priv->route_table, + priv->route_metric); } else { - ip_config = (GObject *) nm_dhcp_utils_ip4_config_from_options (priv->ifindex, + prefix = nm_dhcp_utils_ip6_prefix_from_options (str_options); + ip_config = (GObject *) nm_dhcp_utils_ip6_config_from_options (nm_dhcp_client_get_multi_idx (self), + priv->ifindex, priv->iface, str_options, - priv->priority); + priv->info_only); } } } @@ -822,14 +852,14 @@ get_property (GObject *object, guint prop_id, case PROP_HWADDR: g_value_set_boxed (value, priv->hwaddr); break; - case PROP_IPV6: - g_value_set_boolean (value, priv->ipv6); + case PROP_ADDR_FAMILY: + g_value_set_int (value, priv->addr_family); break; case PROP_UUID: g_value_set_string (value, priv->uuid); break; - case PROP_PRIORITY: - g_value_set_uint (value, priv->priority); + case PROP_ROUTE_METRIC: + g_value_set_uint (value, priv->route_metric); break; case PROP_TIMEOUT: g_value_set_uint (value, priv->timeout); @@ -847,6 +877,13 @@ set_property (GObject *object, guint prop_id, NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE ((NMDhcpClient *) object); switch (prop_id) { + case PROP_MULTI_IDX: + /* construct-only */ + priv->multi_idx = g_value_get_pointer (value); + if (!priv->multi_idx) + g_return_if_reached (); + nm_dedup_multi_index_ref (priv->multi_idx); + break; case PROP_IFACE: /* construct-only */ priv->iface = g_value_dup_string (value); @@ -860,19 +897,26 @@ set_property (GObject *object, guint prop_id, /* construct-only */ priv->hwaddr = g_value_dup_boxed (value); break; - case PROP_IPV6: + case PROP_ADDR_FAMILY: /* construct-only */ - priv->ipv6 = g_value_get_boolean (value); + priv->addr_family = g_value_get_int (value); + if (!NM_IN_SET (priv->addr_family, AF_INET, AF_INET6)) + g_return_if_reached (); break; case PROP_UUID: /* construct-only */ priv->uuid = g_value_dup_string (value); break; - case PROP_PRIORITY: + case PROP_ROUTE_TABLE: + /* construct-only */ + priv->route_table = g_value_get_uint (value); + break; + case PROP_ROUTE_METRIC: /* construct-only */ - priv->priority = g_value_get_uint (value); + priv->route_metric = g_value_get_uint (value); break; case PROP_TIMEOUT: + /* construct-only */ priv->timeout = g_value_get_uint (value); break; default: @@ -924,6 +968,8 @@ dispose (GObject *object) } G_OBJECT_CLASS (nm_dhcp_client_parent_class)->dispose (object); + + priv->multi_idx = nm_dedup_multi_index_unref (priv->multi_idx); } static void @@ -940,6 +986,12 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class) client_class->stop = stop; client_class->get_duid = get_duid; + obj_properties[PROP_MULTI_IDX] = + g_param_spec_pointer (NM_DHCP_CLIENT_MULTI_IDX, "", "", + G_PARAM_WRITABLE + | G_PARAM_CONSTRUCT_ONLY + | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_IFACE] = g_param_spec_string (NM_DHCP_CLIENT_INTERFACE, "", "", NULL, @@ -958,11 +1010,11 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IPV6] = - g_param_spec_boolean (NM_DHCP_CLIENT_IPV6, "", "", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); + obj_properties[PROP_ADDR_FAMILY] = + g_param_spec_int (NM_DHCP_CLIENT_ADDR_FAMILY, "", "", + 0, G_MAXINT, AF_UNSPEC, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_UUID] = g_param_spec_string (NM_DHCP_CLIENT_UUID, "", "", @@ -970,15 +1022,21 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_PRIORITY] = - g_param_spec_uint (NM_DHCP_CLIENT_PRIORITY, "", "", + obj_properties[PROP_ROUTE_TABLE] = + g_param_spec_uint (NM_DHCP_CLIENT_ROUTE_TABLE, "", "", + 0, G_MAXUINT32, RT_TABLE_MAIN, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_ROUTE_METRIC] = + g_param_spec_uint (NM_DHCP_CLIENT_ROUTE_METRIC, "", "", 0, G_MAXUINT32, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_properties[PROP_TIMEOUT] = g_param_spec_uint (NM_DHCP_CLIENT_TIMEOUT, "", "", - 0, G_MAXUINT, 45, + 1, G_MAXINT32, NM_DHCP_TIMEOUT_DEFAULT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h index e41a59a2..02804002 100644 --- a/src/dhcp/nm-dhcp-client.h +++ b/src/dhcp/nm-dhcp-client.h @@ -24,6 +24,9 @@ #include "nm-ip4-config.h" #include "nm-ip6-config.h" +#define NM_DHCP_TIMEOUT_DEFAULT ((guint32) 45) /* default DHCP timeout, in seconds */ +#define NM_DHCP_TIMEOUT_INFINITY G_MAXINT32 + #define NM_TYPE_DHCP_CLIENT (nm_dhcp_client_get_type ()) #define NM_DHCP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClient)) #define NM_DHCP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP_CLIENT, NMDhcpClientClass)) @@ -32,16 +35,19 @@ #define NM_DHCP_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClientClass)) #define NM_DHCP_CLIENT_INTERFACE "iface" +#define NM_DHCP_CLIENT_ADDR_FAMILY "addr-family" #define NM_DHCP_CLIENT_IFINDEX "ifindex" #define NM_DHCP_CLIENT_HWADDR "hwaddr" -#define NM_DHCP_CLIENT_IPV6 "ipv6" #define NM_DHCP_CLIENT_UUID "uuid" -#define NM_DHCP_CLIENT_PRIORITY "priority" +#define NM_DHCP_CLIENT_ROUTE_TABLE "route-table" +#define NM_DHCP_CLIENT_ROUTE_METRIC "route-metric" #define NM_DHCP_CLIENT_TIMEOUT "timeout" +#define NM_DHCP_CLIENT_MULTI_IDX "multi-idx" #define NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED "state-changed" #define NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED "prefix-delegated" + typedef enum { NM_DHCP_STATE_UNKNOWN = 0, NM_DHCP_STATE_BOUND, /* new lease or lease changed */ @@ -101,21 +107,25 @@ typedef struct { GType nm_dhcp_client_get_type (void); +struct _NMDedupMultiIndex *nm_dhcp_client_get_multi_idx (NMDhcpClient *self); + pid_t nm_dhcp_client_get_pid (NMDhcpClient *self); +int nm_dhcp_client_get_addr_family (NMDhcpClient *self); + const char *nm_dhcp_client_get_iface (NMDhcpClient *self); int nm_dhcp_client_get_ifindex (NMDhcpClient *self); -gboolean nm_dhcp_client_get_ipv6 (NMDhcpClient *self); - const char *nm_dhcp_client_get_uuid (NMDhcpClient *self); const GByteArray *nm_dhcp_client_get_duid (NMDhcpClient *self); const GByteArray *nm_dhcp_client_get_hw_addr (NMDhcpClient *self); -guint32 nm_dhcp_client_get_priority (NMDhcpClient *self); +guint32 nm_dhcp_client_get_route_table (NMDhcpClient *self); + +guint32 nm_dhcp_client_get_route_metric (NMDhcpClient *self); guint32 nm_dhcp_client_get_timeout (NMDhcpClient *self); @@ -173,13 +183,16 @@ typedef struct { GType (*get_type)(void); const char *name; const char *(*get_path) (void); - GSList *(*get_lease_ip_configs) (const char *iface, + GSList *(*get_lease_ip_configs) (struct _NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, int ifindex, const char *uuid, - gboolean ipv6, - guint32 default_route_metric); + guint32 route_table, + guint32 route_metric); } NMDhcpClientFactory; +extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcanon; extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhclient; extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcd; extern const NMDhcpClientFactory _nm_dhcp_client_factory_internal; diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index 6a1b6865..e63e6a86 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -25,6 +25,8 @@ #include <ctype.h> #include <arpa/inet.h> +#include "nm-utils/nm-dedup-multi.h" + #include "nm-dhcp-utils.h" #include "nm-ip4-config.h" #include "nm-utils.h" @@ -162,13 +164,9 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname, gboolean static void add_hostname6 (GString *str, const char *hostname) { - /* dhclient only supports the fqdn.fqdn for DHCPv6 and requires a fully- - * qualified name for this option, so we must require one here too. - */ - if (hostname && strchr (hostname, '.')) { + if (hostname) { g_string_append_printf (str, FQDN_FORMAT "\n", hostname); g_string_append (str, - "send fqdn.encoded on;\n" "send fqdn.server-update on;\n"); g_string_append_c (str, '\n'); } @@ -261,7 +259,7 @@ read_interface (const char *line, char *interface, guint size) char * nm_dhcp_dhclient_create_config (const char *interface, - gboolean is_ip6, + int addr_family, GBytes *client_id, const char *anycast_addr, const char *hostname, @@ -277,6 +275,7 @@ nm_dhcp_dhclient_create_config (const char *interface, int i; g_return_val_if_fail (!anycast_addr || nm_utils_hwaddr_valid (anycast_addr, ETH_ALEN), NULL); + g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), NULL); new_contents = g_string_new (_("# Created by NetworkManager\n")); fqdn_opts = g_ptr_array_sized_new (5); @@ -397,18 +396,18 @@ nm_dhcp_dhclient_create_config (const char *interface, g_string_append_printf (new_contents, "timeout %u;\n", timeout); } - if (is_ip6) { - add_hostname6 (new_contents, hostname); - add_request (reqs, "dhcp6.name-servers"); - add_request (reqs, "dhcp6.domain-search"); - add_request (reqs, "dhcp6.client-id"); - } else { + if (addr_family == AF_INET) { add_ip4_config (new_contents, client_id, hostname, use_fqdn); add_request (reqs, "rfc3442-classless-static-routes"); add_request (reqs, "ms-classless-static-routes"); add_request (reqs, "static-routes"); add_request (reqs, "wpad"); add_request (reqs, "ntp-servers"); + } else { + add_hostname6 (new_contents, hostname); + add_request (reqs, "dhcp6.name-servers"); + add_request (reqs, "dhcp6.domain-search"); + add_request (reqs, "dhcp6.client-id"); } if (reset_reqlist) @@ -686,24 +685,30 @@ lease_validity_span (const char *str_expire, GDateTime *now) /** * nm_dhcp_dhclient_read_lease_ip_configs: + * @multi_idx: the multi index instance for the ip config object + * @addr_family: whether to read IPv4 or IPv6 leases * @iface: the interface name to match leases with * @ifindex: interface index of @iface + * @route_table: the route table for the default route. + * @route_metric: the route metric for the default route. * @contents: the contents of a dhclient leasefile - * @ipv6: whether to read IPv4 or IPv6 leases * @now: the current UTC date/time; pass %NULL to automatically use current * UTC time. Testcases may need a different value for 'now' * * Reads dhclient leases from @contents and parses them into either - * #NMIP4Config or #NMIP6Config objects depending on the value of @ipv6. + * #NMIP4Config or #NMIP6Config objects depending on the value of @addr_family. * - * Returns: a #GSList of #NMIP4Config objects (if @ipv6 is %FALSE) or a list of - * #NMIP6Config objects (if @ipv6 is %TRUE) containing the lease data. + * Returns: a #GSList of #NMIP4Config objects (if @addr_family is %AF_INET) or a list of + * #NMIP6Config objects (if @addr_family is %AF_INET6) containing the lease data. */ GSList * -nm_dhcp_dhclient_read_lease_ip_configs (const char *iface, +nm_dhcp_dhclient_read_lease_ip_configs (NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, int ifindex, + guint32 route_table, + guint32 route_metric, const char *contents, - gboolean ipv6, GDateTime *now) { GSList *parsed = NULL, *iter, *leases = NULL; @@ -712,6 +717,7 @@ nm_dhcp_dhclient_read_lease_ip_configs (const char *iface, gint32 now_monotonic_ts; g_return_val_if_fail (contents != NULL, NULL); + nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); split = g_strsplit_set (contents, "\n\r", -1); if (!split) @@ -733,7 +739,7 @@ nm_dhcp_dhclient_read_lease_ip_configs (const char *iface, g_hash_table_destroy (hash); } - hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + hash = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); } else if (hash && strlen (*line)) add_lease_option (hash, *line); } @@ -804,15 +810,25 @@ nm_dhcp_dhclient_read_lease_ip_configs (const char *iface, /* Get default netmask for the IP according to appropriate class. */ if (!address.plen) - address.plen = nm_utils_ip4_get_default_prefix (address.address); + address.plen = _nm_utils_ip4_get_default_prefix (address.address); address.timestamp = now_monotonic_ts; address.lifetime = address.preferred = expiry; address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; - ip4 = nm_ip4_config_new (ifindex); + ip4 = nm_ip4_config_new (multi_idx, ifindex); nm_ip4_config_add_address (ip4, &address); - nm_ip4_config_set_gateway (ip4, gw); + + { + const NMPlatformIP4Route r = { + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .gateway = gw, + .table_coerced = nm_platform_route_table_coerce (route_table), + .metric = route_metric, + }; + + nm_ip4_config_add_route (ip4, &r, NULL); + } value = g_hash_table_lookup (hash, "option domain-name-servers"); if (value) { diff --git a/src/dhcp/nm-dhcp-dhclient-utils.h b/src/dhcp/nm-dhcp-dhclient-utils.h index 2268890b..94de1963 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.h +++ b/src/dhcp/nm-dhcp-dhclient-utils.h @@ -23,7 +23,7 @@ #include "nm-setting-ip6-config.h" char *nm_dhcp_dhclient_create_config (const char *interface, - gboolean is_ip6, + int addr_family, GBytes *client_id, const char *anycast_addr, const char *hostname, @@ -43,10 +43,13 @@ gboolean nm_dhcp_dhclient_save_duid (const char *leasefile, const char *escaped_duid, GError **error); -GSList *nm_dhcp_dhclient_read_lease_ip_configs (const char *iface, +GSList *nm_dhcp_dhclient_read_lease_ip_configs (struct _NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, int ifindex, + guint32 route_table, + guint32 route_metric, const char *contents, - gboolean ipv6, GDateTime *now); GBytes *nm_dhcp_dhclient_get_client_id_from_config_file (const char *path); diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c index f20158c6..74d920a8 100644 --- a/src/dhcp/nm-dhcp-dhclient.c +++ b/src/dhcp/nm-dhcp-dhclient.c @@ -38,6 +38,8 @@ #include <arpa/inet.h> #include <ctype.h> +#include "nm-utils/nm-dedup-multi.h" + #include "nm-utils.h" #include "nm-dhcp-dhclient-utils.h" #include "nm-dhcp-manager.h" @@ -47,6 +49,15 @@ /*****************************************************************************/ +static const char * +_addr_family_to_path_part (int addr_family) +{ + nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + return (addr_family == AF_INET6) ? "6" : ""; +} + +/*****************************************************************************/ + #define NM_TYPE_DHCP_DHCLIENT (nm_dhcp_dhclient_get_type ()) #define NM_DHCP_DHCLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_DHCLIENT, NMDhcpDhclient)) #define NM_DHCP_DHCLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP_DHCLIENT, NMDhcpDhclientClass)) @@ -92,9 +103,9 @@ nm_dhcp_dhclient_get_path (void) /** * get_dhclient_leasefile(): + * @addr_family: AF_INET or AF_INET6 * @iface: the interface name of the device on which DHCP will be done * @uuid: the connection UUID to which the returned lease should belong - * @ipv6: %TRUE for IPv6, %FALSE for IPv4 * @out_preferred_path: on return, the "most preferred" leasefile path * * Returns the path of an existing leasefile (if any) for this interface and @@ -104,16 +115,16 @@ nm_dhcp_dhclient_get_path (void) * Returns: an existing leasefile, or %NULL if no matching leasefile could be found */ static char * -get_dhclient_leasefile (const char *iface, +get_dhclient_leasefile (int addr_family, + const char *iface, const char *uuid, - gboolean ipv6, char **out_preferred_path) { char *path; /* /var/lib/NetworkManager is the preferred leasefile path */ path = g_strdup_printf (NMSTATEDIR "/dhclient%s-%s-%s.lease", - ipv6 ? "6" : "", + _addr_family_to_path_part (addr_family), uuid, iface); if (out_preferred_path) @@ -131,14 +142,14 @@ get_dhclient_leasefile (const char *iface, /* Old Debian, SUSE, and Mandriva location */ g_free (path); path = g_strdup_printf (LOCALSTATEDIR "/lib/dhcp/dhclient%s-%s-%s.lease", - ipv6 ? "6" : "", uuid, iface); + _addr_family_to_path_part (addr_family), uuid, iface); if (g_file_test (path, G_FILE_TEST_EXISTS)) return path; /* Old Red Hat and Fedora location */ g_free (path); path = g_strdup_printf (LOCALSTATEDIR "/lib/dhclient/dhclient%s-%s-%s.lease", - ipv6 ? "6" : "", uuid, iface); + _addr_family_to_path_part (addr_family), uuid, iface); if (g_file_test (path, G_FILE_TEST_EXISTS)) return path; @@ -148,37 +159,36 @@ get_dhclient_leasefile (const char *iface, } static GSList * -nm_dhcp_dhclient_get_lease_ip_configs (const char *iface, +nm_dhcp_dhclient_get_lease_ip_configs (NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, int ifindex, const char *uuid, - gboolean ipv6, - guint32 default_route_metric) + guint32 route_table, + guint32 route_metric) { - char *contents = NULL; - char *leasefile; - GSList *leases = NULL; + gs_free char *contents = NULL; + gs_free char *leasefile = NULL; - leasefile = get_dhclient_leasefile (iface, uuid, FALSE, NULL); + leasefile = get_dhclient_leasefile (addr_family, iface, uuid, NULL); if (!leasefile) return NULL; if ( g_file_test (leasefile, G_FILE_TEST_EXISTS) && g_file_get_contents (leasefile, &contents, NULL, NULL) && contents - && contents[0]) - leases = nm_dhcp_dhclient_read_lease_ip_configs (iface, ifindex, contents, ipv6, NULL); - - g_free (leasefile); - g_free (contents); - - return leases; + && contents[0]) { + return nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, addr_family, iface, ifindex, + route_table, route_metric, contents, NULL); + } + return NULL; } static gboolean merge_dhclient_config (NMDhcpDhclient *self, + int addr_family, const char *iface, const char *conf_file, - gboolean is_ip6, GBytes *client_id, const char *anycast_addr, const char *hostname, @@ -204,10 +214,7 @@ merge_dhclient_config (NMDhcpDhclient *self, } } - if (is_ip6 && hostname && !strchr (hostname, '.')) - _LOGW ("hostname is not a FQDN, it will be ignored"); - - new = nm_dhcp_dhclient_create_config (iface, is_ip6, client_id, anycast_addr, hostname, timeout, + new = nm_dhcp_dhclient_create_config (iface, addr_family, client_id, anycast_addr, hostname, timeout, use_fqdn, orig_path, orig, out_new_client_id); g_assert (new); success = g_file_set_contents (conf_file, new, -1, error); @@ -218,7 +225,7 @@ merge_dhclient_config (NMDhcpDhclient *self, } static char * -find_existing_config (NMDhcpDhclient *self, const char *iface, const char *uuid, gboolean ipv6) +find_existing_config (NMDhcpDhclient *self, int addr_family, const char *iface, const char *uuid) { char *path; @@ -227,20 +234,20 @@ find_existing_config (NMDhcpDhclient *self, const char *iface, const char *uuid, * or generic. */ if (uuid) { - path = g_strdup_printf (NMCONFDIR "/dhclient%s-%s.conf", ipv6 ? "6" : "", uuid); + path = g_strdup_printf (NMCONFDIR "/dhclient%s-%s.conf", _addr_family_to_path_part (addr_family), uuid); _LOGD ("looking for existing config %s", path); 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); + path = g_strdup_printf (NMCONFDIR "/dhclient%s-%s.conf", _addr_family_to_path_part (addr_family), iface); _LOGD ("looking for existing config %s", path); if (g_file_test (path, G_FILE_TEST_EXISTS)) return path; g_free (path); - path = g_strdup_printf (NMCONFDIR "/dhclient%s.conf", ipv6 ? "6" : ""); + path = g_strdup_printf (NMCONFDIR "/dhclient%s.conf", _addr_family_to_path_part (addr_family)); _LOGD ("looking for existing config %s", path); if (g_file_test (path, G_FILE_TEST_EXISTS)) return path; @@ -254,25 +261,25 @@ find_existing_config (NMDhcpDhclient *self, const char *iface, const char *uuid, * 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); + path = g_strdup_printf (SYSCONFDIR "/dhcp/dhclient%s-%s.conf", _addr_family_to_path_part (addr_family), iface); _LOGD ("looking for existing config %s", path); 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); + path = g_strdup_printf (SYSCONFDIR "/dhclient%s-%s.conf", _addr_family_to_path_part (addr_family), iface); _LOGD ("looking for existing config %s", path); 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" : ""); + path = g_strdup_printf (SYSCONFDIR "/dhcp/dhclient%s.conf", _addr_family_to_path_part (addr_family)); _LOGD ("looking for existing config %s", path); if (g_file_test (path, G_FILE_TEST_EXISTS)) return path; g_free (path); - path = g_strdup_printf (SYSCONFDIR "/dhclient%s.conf", ipv6 ? "6" : ""); + path = g_strdup_printf (SYSCONFDIR "/dhclient%s.conf", _addr_family_to_path_part (addr_family)); _LOGD ("looking for existing config %s", path); if (g_file_test (path, G_FILE_TEST_EXISTS)) return path; @@ -290,8 +297,8 @@ find_existing_config (NMDhcpDhclient *self, const char *iface, const char *uuid, */ static char * create_dhclient_config (NMDhcpDhclient *self, + int addr_family, const char *iface, - gboolean is_ip6, const char *uuid, GBytes *client_id, const char *dhcp_anycast_addr, @@ -306,17 +313,17 @@ create_dhclient_config (NMDhcpDhclient *self, g_return_val_if_fail (iface != NULL, NULL); - new = g_strdup_printf (NMSTATEDIR "/dhclient%s-%s.conf", is_ip6 ? "6" : "", iface); + new = g_strdup_printf (NMSTATEDIR "/dhclient%s-%s.conf", _addr_family_to_path_part (addr_family), iface); _LOGD ("creating composite dhclient config %s", new); - orig = find_existing_config (self, iface, uuid, is_ip6); + orig = find_existing_config (self, addr_family, iface, uuid); if (orig) _LOGD ("merging existing dhclient config %s", orig); else _LOGD ("no existing dhclient configuration to merge"); error = NULL; - success = merge_dhclient_config (self, iface, new, is_ip6, client_id, dhcp_anycast_addr, + success = merge_dhclient_config (self, addr_family, iface, new, client_id, dhcp_anycast_addr, hostname, timeout, use_fqdn, orig, out_new_client_id, &error); if (!success) { _LOGW ("error creating dhclient configuration: %s", error->message); @@ -343,14 +350,15 @@ dhclient_start (NMDhcpClient *client, GError *error = NULL; const char *iface, *uuid, *system_bus_address, *dhclient_path = NULL; char *binary_name, *cmd_str, *pid_file = NULL, *system_bus_address_env = NULL; - gboolean ipv6, success; + int addr_family; + gboolean success; char *escaped, *preferred_leasefile_path = NULL; g_return_val_if_fail (priv->pid_file == NULL, FALSE); iface = nm_dhcp_client_get_iface (client); uuid = nm_dhcp_client_get_uuid (client); - ipv6 = nm_dhcp_client_get_ipv6 (client); + addr_family = nm_dhcp_client_get_addr_family (client); dhclient_path = nm_dhcp_dhclient_get_path (); if (!dhclient_path) { @@ -359,8 +367,8 @@ dhclient_start (NMDhcpClient *client, } pid_file = g_strdup_printf (RUNSTATEDIR "/dhclient%s-%s.pid", - ipv6 ? "6" : "", - iface); + _addr_family_to_path_part (addr_family), + iface); /* Kill any existing dhclient from the pidfile */ binary_name = g_path_get_basename (dhclient_path); @@ -374,7 +382,7 @@ dhclient_start (NMDhcpClient *client, } g_free (priv->lease_file); - priv->lease_file = get_dhclient_leasefile (iface, uuid, ipv6, &preferred_leasefile_path); + priv->lease_file = get_dhclient_leasefile (addr_family, iface, uuid, &preferred_leasefile_path); if (!priv->lease_file) { /* No existing leasefile, dhclient will create one at the preferred path */ priv->lease_file = g_strdup (preferred_leasefile_path); @@ -400,7 +408,7 @@ dhclient_start (NMDhcpClient *client, g_free (preferred_leasefile_path); /* Save the DUID to the leasefile dhclient will actually use */ - if (ipv6) { + if (addr_family == AF_INET6) { escaped = nm_dhcp_dhclient_escape_duid (duid); success = nm_dhcp_dhclient_save_duid (priv->lease_file, escaped, &error); g_free (escaped); @@ -424,7 +432,7 @@ dhclient_start (NMDhcpClient *client, if (release) g_ptr_array_add (argv, (gpointer) "-r"); - if (ipv6) { + if (addr_family == AF_INET6) { g_ptr_array_add (argv, (gpointer) "-6"); if (mode_opt) g_ptr_array_add (argv, (gpointer) mode_opt); @@ -507,7 +515,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last timeout = nm_dhcp_client_get_timeout (client); use_fqdn = nm_dhcp_client_get_use_fqdn (client); - priv->conf_file = create_dhclient_config (self, iface, FALSE, uuid, client_id, dhcp_anycast_addr, + priv->conf_file = create_dhclient_config (self, AF_INET, iface, uuid, client_id, dhcp_anycast_addr, hostname, timeout, use_fqdn, &new_client_id); if (priv->conf_file) { if (new_client_id) @@ -538,7 +546,7 @@ ip6_start (NMDhcpClient *client, hostname = nm_dhcp_client_get_hostname (client); timeout = nm_dhcp_client_get_timeout (client); - priv->conf_file = create_dhclient_config (self, iface, TRUE, uuid, NULL, dhcp_anycast_addr, + priv->conf_file = create_dhclient_config (self, AF_INET6, iface, uuid, NULL, dhcp_anycast_addr, hostname, timeout, TRUE, NULL); if (!priv->conf_file) { _LOGW ("error creating dhclient configuration file"); @@ -605,9 +613,9 @@ get_duid (NMDhcpClient *client) GError *error = NULL; /* Look in interface-specific leasefile first for backwards compat */ - leasefile = get_dhclient_leasefile (nm_dhcp_client_get_iface (client), + leasefile = get_dhclient_leasefile (AF_INET6, + nm_dhcp_client_get_iface (client), nm_dhcp_client_get_uuid (client), - TRUE, NULL); if (leasefile) { _LOGD ("looking for DUID in '%s'", leasefile); diff --git a/src/dhcp/nm-dhcp-dhcpcanon.c b/src/dhcp/nm-dhcp-dhcpcanon.c new file mode 100644 index 00000000..d7ddd194 --- /dev/null +++ b/src/dhcp/nm-dhcp-dhcpcanon.c @@ -0,0 +1,272 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* nm-dhcp-dhcpcanon.c - dhcpcanon specific hooks for NetworkManager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2017 juga <juga at riseup dot net> + */ + +#include "nm-default.h" + +#if WITH_DHCPCANON + +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> + +#include "nm-utils.h" +#include "nm-dhcp-manager.h" +#include "NetworkManagerUtils.h" +#include "nm-dhcp-listener.h" +#include "nm-dhcp-client-logging.h" + +#define NM_TYPE_DHCP_DHCPCANON (nm_dhcp_dhcpcanon_get_type ()) +#define NM_DHCP_DHCPCANON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_DHCPCANON, NMDhcpDhcpcanon)) +#define NM_DHCP_DHCPCANON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP_DHCPCANON, NMDhcpDhcpcanonClass)) +#define NM_IS_DHCP_DHCPCANON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DHCP_DHCPCANON)) +#define NM_IS_DHCP_DHCPCANON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP_DHCPCANON)) +#define NM_DHCP_DHCPCANON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_DHCPCANON, NMDhcpDhcpcanonClass)) + +typedef struct _NMDhcpDhcpcanon NMDhcpDhcpcanon; +typedef struct _NMDhcpDhcpcanonClass NMDhcpDhcpcanonClass; + +static GType nm_dhcp_dhcpcanon_get_type (void); + +/*****************************************************************************/ + +typedef struct { + char *conf_file; + const char *def_leasefile; + char *lease_file; + char *pid_file; + NMDhcpListener *dhcp_listener; +} NMDhcpDhcpcanonPrivate; + +struct _NMDhcpDhcpcanon { + NMDhcpClient parent; + NMDhcpDhcpcanonPrivate _priv; +}; + +struct _NMDhcpDhcpcanonClass { + NMDhcpClientClass parent; +}; + +G_DEFINE_TYPE (NMDhcpDhcpcanon, nm_dhcp_dhcpcanon, NM_TYPE_DHCP_CLIENT) + +#define NM_DHCP_DHCPCANON_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDhcpDhcpcanon, NM_IS_DHCP_DHCPCANON) + +/*****************************************************************************/ + +static const char * +nm_dhcp_dhcpcanon_get_path (void) +{ + return nm_utils_find_helper ("dhcpcanon", DHCPCANON_PATH, NULL); +} + + +static gboolean +dhcpcanon_start (NMDhcpClient *client, + const char *mode_opt, + const GByteArray *duid, + gboolean release, + pid_t *out_pid, + int prefixes) +{ + NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client); + NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE (self); + GPtrArray *argv = NULL; + pid_t pid; + GError *error = NULL; + const char *iface, *system_bus_address, *dhcpcanon_path = NULL; + char *binary_name, *cmd_str, *pid_file = NULL, *system_bus_address_env = NULL; + int addr_family; + + g_return_val_if_fail (priv->pid_file == NULL, FALSE); + + iface = nm_dhcp_client_get_iface (client); + addr_family = nm_dhcp_client_get_addr_family (client); + dhcpcanon_path = nm_dhcp_dhcpcanon_get_path (); + _LOGD ("dhcpcanon_path: %s", dhcpcanon_path); + if (!dhcpcanon_path) { + _LOGW ("dhcpcanon could not be found"); + return FALSE; + } + + pid_file = g_strdup_printf (RUNSTATEDIR "/dhcpcanon%c-%s.pid", + nm_utils_addr_family_to_char (addr_family), + iface); + _LOGD ("pid_file: %s", pid_file); + + /* Kill any existing dhcpcanon from the pidfile */ + binary_name = g_path_get_basename (dhcpcanon_path); + nm_dhcp_client_stop_existing (pid_file, binary_name); + g_free (binary_name); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (gpointer) dhcpcanon_path); + + g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */ + g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path); + + if (pid_file) { + g_ptr_array_add (argv, (gpointer) "-pf"); /* Set pid file */ + g_ptr_array_add (argv, (gpointer) pid_file); + } + + if (priv->conf_file) { + g_ptr_array_add (argv, (gpointer) "-cf"); /* Set interface config file */ + g_ptr_array_add (argv, (gpointer) priv->conf_file); + } + + /* Usually the system bus address is well-known; but if it's supposed + * to be something else, we need to push it to dhcpcanon, since dhcpcanon + * sanitizes the environment it gives the action scripts. + */ + system_bus_address = getenv ("DBUS_SYSTEM_BUS_ADDRESS"); + if (system_bus_address) { + system_bus_address_env = g_strdup_printf ("DBUS_SYSTEM_BUS_ADDRESS=%s", system_bus_address); + g_ptr_array_add (argv, (gpointer) "-e"); + g_ptr_array_add (argv, (gpointer) system_bus_address_env); + } + + + g_ptr_array_add (argv, (gpointer) iface); + g_ptr_array_add (argv, NULL); + + cmd_str = g_strjoinv (" ", (gchar **) argv->pdata); + g_free (cmd_str); + + if (g_spawn_async (NULL, (char **) argv->pdata, NULL, + G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, + nm_utils_setpgid, NULL, &pid, &error)) { + g_assert (pid > 0); + _LOGI ("dhcpcanon started with pid %d", pid); + nm_dhcp_client_watch_child (client, pid); + priv->pid_file = pid_file; + } else { + _LOGW ("dhcpcanon failed to start: '%s'", error->message); + g_error_free (error); + g_free (pid_file); + } + + g_ptr_array_free (argv, TRUE); + g_free (system_bus_address_env); + return pid > 0 ? TRUE : FALSE; +} + +static gboolean +ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address) +{ + gboolean success = FALSE; + success = dhcpcanon_start (client, NULL, NULL, FALSE, NULL, 0); + return success; +} + +static gboolean +ip6_start (NMDhcpClient *client, + const char *dhcp_anycast_addr, + const struct in6_addr *ll_addr, + gboolean info_only, + NMSettingIP6ConfigPrivacy privacy, + const GByteArray *duid, + guint needed_prefixes) +{ + NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client); + + _LOGW ("the dhcpcd backend does not support IPv6"); + return FALSE; +} +static void +stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) +{ + NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client); + NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE (self); + + NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcanon_parent_class)->stop (client, release, duid); + + if (priv->pid_file) { + if (remove (priv->pid_file) == -1) + _LOGD ("could not remove dhcp pid file \"%s\": %d (%s)", priv->pid_file, errno, g_strerror (errno)); + g_free (priv->pid_file); + priv->pid_file = NULL; + } +} + +static void +state_changed (NMDhcpClient *client, + NMDhcpState state, + GObject *ip_config, + GHashTable *options) +{ + if (nm_dhcp_client_get_client_id (client)) + return; + if (state != NM_DHCP_STATE_BOUND) + return; +} + +/*****************************************************************************/ + +static void +nm_dhcp_dhcpcanon_init (NMDhcpDhcpcanon *self) +{ + NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE (self); + + priv->dhcp_listener = g_object_ref (nm_dhcp_listener_get ()); + g_signal_connect (priv->dhcp_listener, + NM_DHCP_LISTENER_EVENT, + G_CALLBACK (nm_dhcp_client_handle_event), + self); +} + +static void +dispose (GObject *object) +{ + NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE ((NMDhcpDhcpcanon *) object); + + if (priv->dhcp_listener) { + g_signal_handlers_disconnect_by_func (priv->dhcp_listener, + G_CALLBACK (nm_dhcp_client_handle_event), + NM_DHCP_DHCPCANON (object)); + g_clear_object (&priv->dhcp_listener); + } + + nm_clear_g_free (&priv->pid_file); + + G_OBJECT_CLASS (nm_dhcp_dhcpcanon_parent_class)->dispose (object); +} + +static void +nm_dhcp_dhcpcanon_class_init (NMDhcpDhcpcanonClass *dhcpcanon_class) +{ + NMDhcpClientClass *client_class = NM_DHCP_CLIENT_CLASS (dhcpcanon_class); + GObjectClass *object_class = G_OBJECT_CLASS (dhcpcanon_class); + + object_class->dispose = dispose; + + client_class->ip4_start = ip4_start; + client_class->ip6_start = ip6_start; + client_class->stop = stop; + client_class->state_changed = state_changed; +} + +const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcanon = { + .name = "dhcpcanon", + .get_type = nm_dhcp_dhcpcanon_get_type, + .get_path = nm_dhcp_dhcpcanon_get_path, + .get_lease_ip_configs = NULL, +}; + +#endif /* WITH_DHCPCANON */ diff --git a/src/dhcp/nm-dhcp-listener.c b/src/dhcp/nm-dhcp-listener.c index ca697ab3..a0449816 100644 --- a/src/dhcp/nm-dhcp-listener.c +++ b/src/dhcp/nm-dhcp-listener.c @@ -31,6 +31,7 @@ #include "nm-dhcp-helper-api.h" #include "nm-dhcp-client.h" +#include "nm-dhcp-manager.h" #include "nm-core-internal.h" #include "nm-bus-manager.h" #include "NetworkManagerUtils.h" @@ -40,10 +41,13 @@ /*****************************************************************************/ -const NMDhcpClientFactory *const _nm_dhcp_manager_factories[3] = { +const NMDhcpClientFactory *const _nm_dhcp_manager_factories[4] = { /* the order here matters, as we will try the plugins in this order to find * the first available plugin. */ +#if WITH_DHCPCANON + &_nm_dhcp_client_factory_dhcpcanon, +#endif #if WITH_DHCLIENT &_nm_dhcp_client_factory_dhclient, #endif @@ -135,49 +139,35 @@ get_option (GVariant *options, const char *key) } static void -_method_call (GDBusConnection *connection, - const char *sender, - const char *object_path, - const char *interface_name, - const char *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) +_method_call_handle (NMDhcpListener *self, + GVariant *parameters) { - NMDhcpListener *self = NM_DHCP_LISTENER (user_data); - char *iface = NULL; - char *pid_str = NULL; - char *reason = NULL; - gint pid; + gs_free char *iface = NULL; + gs_free char *pid_str = NULL; + gs_free char *reason = NULL; + gs_unref_variant GVariant *options; + int pid; gboolean handled = FALSE; - GVariant *options; - - if (!nm_streq0 (interface_name, NM_DHCP_HELPER_SERVER_INTERFACE_NAME)) - g_return_if_reached (); - if (!nm_streq0 (method_name, NM_DHCP_HELPER_SERVER_METHOD_NOTIFY)) - g_return_if_reached (); - if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})"))) - g_return_if_reached (); g_variant_get (parameters, "(@a{sv})", &options); iface = get_option (options, "interface"); if (iface == NULL) { _LOGW ("dhcp-event: didn't have associated interface."); - goto out; + return; } pid_str = get_option (options, "pid"); pid = _nm_utils_ascii_str_to_int64 (pid_str, 10, 0, G_MAXINT32, -1); if (pid == -1) { _LOGW ("dhcp-event: couldn't convert PID '%s' to an integer", pid_str ? pid_str : "(null)"); - goto out; + return; } reason = get_option (options, "reason"); if (reason == NULL) { _LOGW ("dhcp-event: (pid %d) DHCP event didn't have a reason", pid); - goto out; + return; } g_signal_emit (self, signals[EVENT], 0, iface, pid, options, reason, &handled); @@ -188,12 +178,29 @@ _method_call (GDBusConnection *connection, } else _LOGW ("dhcp-event: (pid %d) unhandled DHCP event for interface %s", pid, iface); } +} + +static void +_method_call (GDBusConnection *connection, + const char *sender, + const char *object_path, + const char *interface_name, + const char *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + NMDhcpListener *self = NM_DHCP_LISTENER (user_data); + + if (!nm_streq0 (interface_name, NM_DHCP_HELPER_SERVER_INTERFACE_NAME)) + g_return_if_reached (); + if (!nm_streq0 (method_name, NM_DHCP_HELPER_SERVER_METHOD_NOTIFY)) + g_return_if_reached (); + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})"))) + g_return_if_reached (); + + _method_call_handle (self, parameters); -out: - g_free (iface); - g_free (pid_str); - g_free (reason); - g_variant_unref (options); g_dbus_method_invocation_return_value (invocation, NULL); } diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c index fff9f9ec..f5c7c84b 100644 --- a/src/dhcp/nm-dhcp-manager.c +++ b/src/dhcp/nm-dhcp-manager.c @@ -34,11 +34,11 @@ #include <fcntl.h> #include <stdio.h> +#include "nm-utils/nm-dedup-multi.h" + #include "nm-config.h" #include "NetworkManagerUtils.h" -#define DHCP_TIMEOUT 45 /* default DHCP timeout, in seconds */ - /*****************************************************************************/ typedef struct { @@ -95,7 +95,7 @@ _client_factory_available (const NMDhcpClientFactory *client_factory) /*****************************************************************************/ static NMDhcpClient * -get_client_for_ifindex (NMDhcpManager *manager, int ifindex, gboolean ip6) +get_client_for_ifindex (NMDhcpManager *manager, int addr_family, int ifindex) { NMDhcpManagerPrivate *priv; GHashTableIter iter; @@ -111,7 +111,7 @@ get_client_for_ifindex (NMDhcpManager *manager, int ifindex, gboolean ip6) NMDhcpClient *candidate = NM_DHCP_CLIENT (value); if ( nm_dhcp_client_get_ifindex (candidate) == ifindex - && nm_dhcp_client_get_ipv6 (candidate) == ip6) + && nm_dhcp_client_get_addr_family (candidate) == addr_family) return candidate; } @@ -152,12 +152,14 @@ client_state_changed (NMDhcpClient *client, static NMDhcpClient * client_start (NMDhcpManager *self, + int addr_family, + NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, const GByteArray *hwaddr, const char *uuid, - guint32 priority, - gboolean ipv6, + guint32 route_table, + guint32 route_metric, const struct in6_addr *ipv6_ll_addr, const char *dhcp_client_id, guint32 timeout, @@ -185,7 +187,7 @@ client_start (NMDhcpManager *self, return NULL; /* Kill any old client instance */ - client = get_client_for_ifindex (self, ifindex, ipv6); + client = get_client_for_ifindex (self, addr_family, ifindex); if (client) { g_object_ref (client); remove_client (self, client); @@ -195,21 +197,23 @@ client_start (NMDhcpManager *self, /* And make a new one */ client = g_object_new (priv->client_factory->get_type (), + NM_DHCP_CLIENT_MULTI_IDX, multi_idx, + NM_DHCP_CLIENT_ADDR_FAMILY, addr_family, NM_DHCP_CLIENT_INTERFACE, iface, NM_DHCP_CLIENT_IFINDEX, ifindex, NM_DHCP_CLIENT_HWADDR, hwaddr, - NM_DHCP_CLIENT_IPV6, ipv6, NM_DHCP_CLIENT_UUID, uuid, - NM_DHCP_CLIENT_PRIORITY, priority, - NM_DHCP_CLIENT_TIMEOUT, timeout ? timeout : DHCP_TIMEOUT, + NM_DHCP_CLIENT_ROUTE_TABLE, (guint) route_table, + NM_DHCP_CLIENT_ROUTE_METRIC, (guint) route_metric, + NM_DHCP_CLIENT_TIMEOUT, (guint) timeout, NULL); g_hash_table_insert (NM_DHCP_MANAGER_GET_PRIVATE (self)->clients, client, g_object_ref (client)); g_signal_connect (client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (client_state_changed), self); - if (ipv6) - success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy, needed_prefixes); - else + if (addr_family == AF_INET) success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, hostname_use_fqdn, last_ip4_address); + else + success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy, needed_prefixes); if (!success) { remove_client (self, client); @@ -222,11 +226,13 @@ client_start (NMDhcpManager *self, /* Caller owns a reference to the NMDhcpClient on return */ NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *self, + NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, const GByteArray *hwaddr, const char *uuid, - guint32 priority, + guint32 route_table, + guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, const char *dhcp_fqdn, @@ -267,7 +273,8 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self, } } - return client_start (self, iface, ifindex, hwaddr, uuid, priority, FALSE, NULL, + 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, use_fqdn, FALSE, 0, last_ip_address, 0); } @@ -275,12 +282,14 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self, /* Caller owns a reference to the NMDhcpClient on return */ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *self, + NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, const GByteArray *hwaddr, const struct in6_addr *ll_addr, const char *uuid, - guint32 priority, + guint32 route_table, + guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, guint32 timeout, @@ -299,8 +308,9 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, /* Always prefer the explicit dhcp-hostname if given */ hostname = dhcp_hostname ? dhcp_hostname : priv->default_hostname; } - return client_start (self, iface, ifindex, hwaddr, uuid, priority, TRUE, - ll_addr, NULL, timeout, dhcp_anycast_addr, hostname, TRUE, info_only, + 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, privacy, NULL, needed_prefixes); } @@ -320,11 +330,13 @@ nm_dhcp_manager_set_default_hostname (NMDhcpManager *manager, const char *hostna GSList * nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self, + NMDedupMultiIndex *multi_idx, + int addr_family, const char *iface, int ifindex, const char *uuid, - gboolean ipv6, - guint32 default_route_metric) + guint32 route_table, + guint32 route_metric) { NMDhcpManagerPrivate *priv; @@ -332,11 +344,12 @@ nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self, g_return_val_if_fail (iface != NULL, NULL); g_return_val_if_fail (ifindex >= -1, NULL); g_return_val_if_fail (uuid != NULL, NULL); + g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), NULL); priv = NM_DHCP_MANAGER_GET_PRIVATE (self); if ( priv->client_factory && priv->client_factory->get_lease_ip_configs) - return priv->client_factory->get_lease_ip_configs (iface, ifindex, uuid, ipv6, default_route_metric); + return priv->client_factory->get_lease_ip_configs (multi_idx, addr_family, iface, ifindex, uuid, route_table, route_metric); return NULL; } diff --git a/src/dhcp/nm-dhcp-manager.h b/src/dhcp/nm-dhcp-manager.h index 66fdd145..078117ff 100644 --- a/src/dhcp/nm-dhcp-manager.h +++ b/src/dhcp/nm-dhcp-manager.h @@ -46,11 +46,13 @@ void nm_dhcp_manager_set_default_hostname (NMDhcpManager *manager, const char *hostname); NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *manager, + struct _NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, const GByteArray *hwaddr, const char *uuid, - guint32 priority, + guint32 route_table, + guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, const char *dhcp_fqdn, @@ -60,12 +62,14 @@ NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *manager, const char *last_ip_address); NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, + struct _NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, const GByteArray *hwaddr, const struct in6_addr *ll_addr, const char *uuid, - guint32 priority, + guint32 route_table, + guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, guint32 timeout, @@ -75,15 +79,17 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, guint needed_prefixes); GSList * nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self, + struct _NMDedupMultiIndex *multi_idx, + int addr_family, const char *iface, int ifindex, const char *uuid, - gboolean ipv6, - guint32 default_route_metric); + guint32 route_table, + guint32 route_metric); /* For testing only */ extern const char* nm_dhcp_helper_path; -extern const NMDhcpClientFactory *const _nm_dhcp_manager_factories[3]; +extern const NMDhcpClientFactory *const _nm_dhcp_manager_factories[4]; #endif /* __NETWORKMANAGER_DHCP_MANAGER_H__ */ diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c index aa902701..9b1a4433 100644 --- a/src/dhcp/nm-dhcp-systemd.c +++ b/src/dhcp/nm-dhcp-systemd.c @@ -28,6 +28,8 @@ #include <ctype.h> #include <net/if_arp.h> +#include "nm-utils/nm-dedup-multi.h" + #include "nm-utils.h" #include "nm-dhcp-utils.h" #include "NetworkManagerUtils.h" @@ -79,9 +81,6 @@ G_DEFINE_TYPE (NMDhcpSystemd, nm_dhcp_systemd, NM_TYPE_DHCP_CLIENT) #define DHCP_OPTION_NIS_DOMAIN 40 #define DHCP_OPTION_NIS_SERVERS 41 -#define DHCP_OPTION_DOMAIN_SEARCH 119 -#define DHCP_OPTION_MS_ROUTES 249 -#define DHCP_OPTION_WPAD 252 /* Internal values */ #define DHCP_OPTION_IP_ADDRESS 1024 @@ -105,53 +104,53 @@ typedef struct { #define REQPREFIX "requested_" static const ReqOption dhcp4_requests[] = { - { SD_DHCP_OPTION_SUBNET_MASK, REQPREFIX "subnet_mask", TRUE }, - { SD_DHCP_OPTION_TIME_OFFSET, REQPREFIX "time_offset", TRUE }, - { SD_DHCP_OPTION_ROUTER, REQPREFIX "routers", TRUE }, - { SD_DHCP_OPTION_DOMAIN_NAME_SERVER, REQPREFIX "domain_name_servers", TRUE }, - { SD_DHCP_OPTION_HOST_NAME, REQPREFIX "host_name", TRUE }, - { SD_DHCP_OPTION_DOMAIN_NAME, REQPREFIX "domain_name", TRUE }, - { SD_DHCP_OPTION_INTERFACE_MTU, REQPREFIX "interface_mtu", TRUE }, - { SD_DHCP_OPTION_BROADCAST, REQPREFIX "broadcast_address", TRUE }, - { SD_DHCP_OPTION_STATIC_ROUTE, REQPREFIX "static_routes", TRUE }, - { DHCP_OPTION_NIS_DOMAIN, REQPREFIX "nis_domain", TRUE }, - { DHCP_OPTION_NIS_SERVERS, REQPREFIX "nis_servers", TRUE }, - { SD_DHCP_OPTION_NTP_SERVER, REQPREFIX "ntp_servers", TRUE }, - { SD_DHCP_OPTION_SERVER_IDENTIFIER, REQPREFIX "dhcp_server_identifier", TRUE }, - { DHCP_OPTION_DOMAIN_SEARCH, REQPREFIX "domain_search", TRUE }, - { SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, REQPREFIX "rfc3442_classless_static_routes", TRUE }, - { DHCP_OPTION_MS_ROUTES, REQPREFIX "ms_classless_static_routes", TRUE }, - { DHCP_OPTION_WPAD, REQPREFIX "wpad", TRUE }, + { SD_DHCP_OPTION_SUBNET_MASK, REQPREFIX "subnet_mask", TRUE }, + { SD_DHCP_OPTION_TIME_OFFSET, REQPREFIX "time_offset", TRUE }, + { SD_DHCP_OPTION_ROUTER, REQPREFIX "routers", TRUE }, + { SD_DHCP_OPTION_DOMAIN_NAME_SERVER, REQPREFIX "domain_name_servers", TRUE }, + { SD_DHCP_OPTION_HOST_NAME, REQPREFIX "host_name", TRUE }, + { SD_DHCP_OPTION_DOMAIN_NAME, REQPREFIX "domain_name", TRUE }, + { SD_DHCP_OPTION_INTERFACE_MTU, REQPREFIX "interface_mtu", TRUE }, + { SD_DHCP_OPTION_BROADCAST, REQPREFIX "broadcast_address", TRUE }, + { SD_DHCP_OPTION_STATIC_ROUTE, REQPREFIX "static_routes", TRUE }, + { DHCP_OPTION_NIS_DOMAIN, REQPREFIX "nis_domain", TRUE }, + { DHCP_OPTION_NIS_SERVERS, REQPREFIX "nis_servers", TRUE }, + { SD_DHCP_OPTION_NTP_SERVER, REQPREFIX "ntp_servers", TRUE }, + { SD_DHCP_OPTION_SERVER_IDENTIFIER, REQPREFIX "dhcp_server_identifier", TRUE }, + { SD_DHCP_OPTION_DOMAIN_SEARCH_LIST, REQPREFIX "domain_search", TRUE }, + { SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, REQPREFIX "rfc3442_classless_static_routes", TRUE }, + { SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, REQPREFIX "ms_classless_static_routes", TRUE }, + { SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, REQPREFIX "wpad", TRUE }, /* Internal values */ - { SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, REQPREFIX "expiry", FALSE }, - { SD_DHCP_OPTION_CLIENT_IDENTIFIER, REQPREFIX "dhcp_client_identifier", FALSE }, - { DHCP_OPTION_IP_ADDRESS, REQPREFIX "ip_address", FALSE }, + { SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, REQPREFIX "expiry", FALSE }, + { SD_DHCP_OPTION_CLIENT_IDENTIFIER, REQPREFIX "dhcp_client_identifier", FALSE }, + { DHCP_OPTION_IP_ADDRESS, REQPREFIX "ip_address", FALSE }, { 0, NULL, FALSE } }; static const ReqOption dhcp6_requests[] = { - { SD_DHCP6_OPTION_CLIENTID, REQPREFIX "dhcp6_client_id", TRUE }, + { SD_DHCP6_OPTION_CLIENTID, REQPREFIX "dhcp6_client_id", TRUE }, /* Don't request server ID by default; some servers don't reply to * Information Requests that request the Server ID. */ - { SD_DHCP6_OPTION_SERVERID, REQPREFIX "dhcp6_server_id", FALSE }, + { SD_DHCP6_OPTION_SERVERID, REQPREFIX "dhcp6_server_id", FALSE }, - { SD_DHCP6_OPTION_DNS_SERVERS, REQPREFIX "dhcp6_name_servers", TRUE }, - { SD_DHCP6_OPTION_DOMAIN_LIST, REQPREFIX "dhcp6_domain_search", TRUE }, - { SD_DHCP6_OPTION_SNTP_SERVERS, REQPREFIX "dhcp6_sntp_servers", TRUE }, + { SD_DHCP6_OPTION_DNS_SERVERS, REQPREFIX "dhcp6_name_servers", TRUE }, + { SD_DHCP6_OPTION_DOMAIN_LIST, REQPREFIX "dhcp6_domain_search", TRUE }, + { SD_DHCP6_OPTION_SNTP_SERVERS, REQPREFIX "dhcp6_sntp_servers", TRUE }, /* Internal values */ - { DHCP6_OPTION_IP_ADDRESS, REQPREFIX "ip6_address", FALSE }, - { DHCP6_OPTION_PREFIXLEN, REQPREFIX "ip6_prefixlen", FALSE }, - { DHCP6_OPTION_PREFERRED_LIFE, REQPREFIX "preferred_life", FALSE }, - { DHCP6_OPTION_MAX_LIFE, REQPREFIX "max_life", FALSE }, - { DHCP6_OPTION_STARTS, REQPREFIX "starts", FALSE }, - { DHCP6_OPTION_LIFE_STARTS, REQPREFIX "life_starts", FALSE }, - { DHCP6_OPTION_RENEW, REQPREFIX "renew", FALSE }, - { DHCP6_OPTION_REBIND, REQPREFIX "rebind", FALSE }, - { DHCP6_OPTION_IAID, REQPREFIX "iaid", FALSE }, + { DHCP6_OPTION_IP_ADDRESS, REQPREFIX "ip6_address", FALSE }, + { DHCP6_OPTION_PREFIXLEN, REQPREFIX "ip6_prefixlen", FALSE }, + { DHCP6_OPTION_PREFERRED_LIFE, REQPREFIX "preferred_life", FALSE }, + { DHCP6_OPTION_MAX_LIFE, REQPREFIX "max_life", FALSE }, + { DHCP6_OPTION_STARTS, REQPREFIX "starts", FALSE }, + { DHCP6_OPTION_LIFE_STARTS, REQPREFIX "life_starts", FALSE }, + { DHCP6_OPTION_RENEW, REQPREFIX "renew", FALSE }, + { DHCP6_OPTION_REBIND, REQPREFIX "rebind", FALSE }, + { DHCP6_OPTION_IAID, REQPREFIX "iaid", FALSE }, { 0, NULL, FALSE } }; @@ -212,16 +211,18 @@ add_requests_to_options (GHashTable *options, const ReqOption *requests) #define LOG_LEASE(domain, ...) \ G_STMT_START { \ if (log_lease) { \ - _LOG2I ((domain), (iface), __VA_ARGS__); \ + _LOG2I ((domain), (iface), " "__VA_ARGS__); \ } \ } G_STMT_END static NMIP4Config * -lease_to_ip4_config (const char *iface, +lease_to_ip4_config (NMDedupMultiIndex *multi_idx, + const char *iface, int ifindex, sd_dhcp_lease *lease, GHashTable *options, - guint32 default_priority, + guint32 route_table, + guint32 route_metric, gboolean log_lease, GError **error) { @@ -229,11 +230,12 @@ lease_to_ip4_config (const char *iface, struct in_addr tmp_addr; const struct in_addr *addr_list; char buf[INET_ADDRSTRLEN]; - const char *str; + const char *s; guint32 lifetime = 0, i; NMPlatformIP4Address address; - GString *l; + nm_auto_free_gstring GString *str = NULL; gs_free sd_dhcp_route **routes = NULL; + const char *const*search_domains = NULL; guint16 mtu; int r, num; guint64 end_time; @@ -241,24 +243,26 @@ lease_to_ip4_config (const char *iface, gsize data_len; gboolean metered = FALSE; gboolean static_default_gateway = FALSE; + gboolean gateway_has = FALSE; + in_addr_t gateway = 0; g_return_val_if_fail (lease != NULL, NULL); - ip4_config = nm_ip4_config_new (ifindex); + ip4_config = nm_ip4_config_new (multi_idx, ifindex); /* Address */ sd_dhcp_lease_get_address (lease, &tmp_addr); memset (&address, 0, sizeof (address)); address.address = tmp_addr.s_addr; address.peer_address = tmp_addr.s_addr; - str = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL); - LOG_LEASE (LOGD_DHCP4, " address %s", str); - add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, str); + s = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL); + LOG_LEASE (LOGD_DHCP4, "address %s", s); + add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, s); /* Prefix/netmask */ sd_dhcp_lease_get_netmask (lease, &tmp_addr); address.plen = nm_utils_ip4_netmask_to_prefix (tmp_addr.s_addr); - LOG_LEASE (LOGD_DHCP4, " plen %d", address.plen); + LOG_LEASE (LOGD_DHCP4, "plen %d", address.plen); add_option (options, dhcp4_requests, SD_DHCP_OPTION_SUBNET_MASK, @@ -269,7 +273,7 @@ lease_to_ip4_config (const char *iface, address.timestamp = nm_utils_get_monotonic_timestamp_s (); address.lifetime = address.preferred = lifetime; end_time = (guint64) time (NULL) + lifetime; - LOG_LEASE (LOGD_DHCP4, " expires in %" G_GUINT32_FORMAT " seconds", lifetime); + LOG_LEASE (LOGD_DHCP4, "expires in %" G_GUINT32_FORMAT " seconds", lifetime); add_option_u64 (options, dhcp4_requests, SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, @@ -281,47 +285,58 @@ lease_to_ip4_config (const char *iface, /* DNS Servers */ num = sd_dhcp_lease_get_dns (lease, &addr_list); if (num > 0) { - l = g_string_sized_new (30); + nm_gstring_prepare (&str); for (i = 0; i < num; i++) { if (addr_list[i].s_addr) { nm_ip4_config_add_nameserver (ip4_config, addr_list[i].s_addr); - str = nm_utils_inet4_ntop (addr_list[i].s_addr, NULL); - LOG_LEASE (LOGD_DHCP4, " nameserver '%s'", str); - g_string_append_printf (l, "%s%s", l->len ? " " : "", str); + s = nm_utils_inet4_ntop (addr_list[i].s_addr, NULL); + LOG_LEASE (LOGD_DHCP4, "nameserver '%s'", s); + g_string_append_printf (str, "%s%s", str->len ? " " : "", s); } } - if (l->len) - add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME_SERVER, l->str); - g_string_free (l, TRUE); + if (str->len) + add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME_SERVER, str->str); + } + + /* Search domains */ + num = sd_dhcp_lease_get_search_domains (lease, (char ***) &search_domains); + if (num > 0) { + nm_gstring_prepare (&str); + for (i = 0; i < num; i++) { + nm_ip4_config_add_search (ip4_config, search_domains[i]); + g_string_append_printf (str, "%s%s", str->len ? " " : "", search_domains[i]); + LOG_LEASE (LOGD_DHCP4, "domain search '%s'", search_domains[i]); + } + add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST, str->str); } /* Domain Name */ - r = sd_dhcp_lease_get_domainname (lease, &str); + r = sd_dhcp_lease_get_domainname (lease, &s); if (r == 0) { /* Multiple domains sometimes stuffed into option 15 "Domain Name". * As systemd escapes such characters, split them at \\032. */ - char **domains = g_strsplit (str, "\\032", 0); - char **s; + char **domains = g_strsplit (s, "\\032", 0); + char **d; - for (s = domains; *s; s++) { - LOG_LEASE (LOGD_DHCP4, " domain name '%s'", *s); - nm_ip4_config_add_domain (ip4_config, *s); + for (d = domains; *d; d++) { + LOG_LEASE (LOGD_DHCP4, "domain name '%s'", *d); + nm_ip4_config_add_domain (ip4_config, *d); } g_strfreev (domains); - add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME, str); + add_option (options, dhcp4_requests, SD_DHCP_OPTION_DOMAIN_NAME, s); } /* Hostname */ - r = sd_dhcp_lease_get_hostname (lease, &str); + r = sd_dhcp_lease_get_hostname (lease, &s); if (r == 0) { - LOG_LEASE (LOGD_DHCP4, " hostname '%s'", str); - add_option (options, dhcp4_requests, SD_DHCP_OPTION_HOST_NAME, str); + LOG_LEASE (LOGD_DHCP4, "hostname '%s'", s); + add_option (options, dhcp4_requests, SD_DHCP_OPTION_HOST_NAME, s); } /* Routes */ num = sd_dhcp_lease_get_routes (lease, &routes); if (num > 0) { - l = g_string_sized_new (30); + nm_gstring_prepare (&str); for (i = 0; i < num; i++) { NMPlatformIP4Route route = { 0 }; const char *gw_str; @@ -330,12 +345,13 @@ lease_to_ip4_config (const char *iface, if (sd_dhcp_route_get_destination (routes[i], &a) < 0) continue; - route.network = a.s_addr; if ( sd_dhcp_route_get_destination_prefix_length (routes[i], &plen) < 0 || plen > 32) continue; + route.plen = plen; + route.network = nm_utils_ip4_address_clear_host_address (a.s_addr, plen); if (sd_dhcp_route_get_gateway (routes[i], &a) < 0) continue; @@ -343,28 +359,29 @@ lease_to_ip4_config (const char *iface, if (route.plen) { route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; - route.metric = default_priority; - nm_ip4_config_add_route (ip4_config, &route); + route.metric = route_metric; + route.table_coerced = nm_platform_route_table_coerce (route_table); + nm_ip4_config_add_route (ip4_config, &route, NULL); - str = nm_utils_inet4_ntop (route.network, buf); + s = nm_utils_inet4_ntop (route.network, buf); gw_str = nm_utils_inet4_ntop (route.gateway, NULL); - LOG_LEASE (LOGD_DHCP4, " static route %s/%d gw %s", str, route.plen, gw_str); + LOG_LEASE (LOGD_DHCP4, "static route %s/%d gw %s", s, route.plen, gw_str); - g_string_append_printf (l, "%s%s/%d %s", l->len ? " " : "", str, route.plen, gw_str); + g_string_append_printf (str, "%s%s/%d %s", str->len ? " " : "", s, route.plen, gw_str); } else { if (!static_default_gateway) { static_default_gateway = TRUE; - nm_ip4_config_set_gateway (ip4_config, route.gateway); + gateway_has = TRUE; + gateway = route.gateway; - str = nm_utils_inet4_ntop (route.gateway, NULL); - LOG_LEASE (LOGD_DHCP4, " gateway %s", str); - add_option (options, dhcp4_requests, SD_DHCP_OPTION_ROUTER, str); + s = nm_utils_inet4_ntop (route.gateway, NULL); + LOG_LEASE (LOGD_DHCP4, "gateway %s", s); + add_option (options, dhcp4_requests, SD_DHCP_OPTION_ROUTER, s); } } } - if (l->len) - add_option (options, dhcp4_requests, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, l->str); - g_string_free (l, TRUE); + if (str->len) + add_option (options, dhcp4_requests, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, str->str); } /* If the DHCP server returns both a Classless Static Routes option and a @@ -376,32 +393,43 @@ lease_to_ip4_config (const char *iface, if (!static_default_gateway) { r = sd_dhcp_lease_get_router (lease, &tmp_addr); if (r == 0) { - nm_ip4_config_set_gateway (ip4_config, tmp_addr.s_addr); - str = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL); - LOG_LEASE (LOGD_DHCP4, " gateway %s", str); - add_option (options, dhcp4_requests, SD_DHCP_OPTION_ROUTER, str); + gateway_has = TRUE; + gateway = tmp_addr.s_addr; + s = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL); + LOG_LEASE (LOGD_DHCP4, "gateway %s", s); + add_option (options, dhcp4_requests, SD_DHCP_OPTION_ROUTER, s); } } + if (gateway_has) { + const NMPlatformIP4Route rt = { + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .gateway = gateway, + .table_coerced = nm_platform_route_table_coerce (route_table), + .metric = route_metric, + }; + + nm_ip4_config_add_route (ip4_config, &rt, NULL); + } + /* MTU */ r = sd_dhcp_lease_get_mtu (lease, &mtu); if (r == 0 && mtu) { nm_ip4_config_set_mtu (ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP); add_option_u32 (options, dhcp4_requests, SD_DHCP_OPTION_INTERFACE_MTU, mtu); - LOG_LEASE (LOGD_DHCP4, " mtu %u", mtu); + LOG_LEASE (LOGD_DHCP4, "mtu %u", mtu); } /* NTP servers */ num = sd_dhcp_lease_get_ntp (lease, &addr_list); if (num > 0) { - l = g_string_sized_new (30); + nm_gstring_prepare (&str); for (i = 0; i < num; i++) { - str = nm_utils_inet4_ntop (addr_list[i].s_addr, buf); - LOG_LEASE (LOGD_DHCP4, " ntp server '%s'", str); - g_string_append_printf (l, "%s%s", l->len ? " " : "", str); + s = nm_utils_inet4_ntop (addr_list[i].s_addr, buf); + LOG_LEASE (LOGD_DHCP4, "ntp server '%s'", s); + g_string_append_printf (str, "%s%s", str->len ? " " : "", s); } - add_option (options, dhcp4_requests, SD_DHCP_OPTION_NTP_SERVER, l->str); - g_string_free (l, TRUE); + add_option (options, dhcp4_requests, SD_DHCP_OPTION_NTP_SERVER, str->str); } r = sd_dhcp_lease_get_vendor_specific (lease, &data, &data_len); @@ -415,20 +443,22 @@ lease_to_ip4_config (const char *iface, /*****************************************************************************/ static char * -get_leasefile_path (const char *iface, const char *uuid, gboolean ipv6) +get_leasefile_path (int addr_family, const char *iface, const char *uuid) { return g_strdup_printf (NMSTATEDIR "/internal%s-%s-%s.lease", - ipv6 ? "6" : "", + addr_family == AF_INET6 ? "6" : "", uuid, iface); } static GSList * -nm_dhcp_systemd_get_lease_ip_configs (const char *iface, +nm_dhcp_systemd_get_lease_ip_configs (NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, int ifindex, const char *uuid, - gboolean ipv6, - guint32 default_route_metric) + guint32 route_table, + guint32 route_metric) { GSList *leases = NULL; gs_free char *path = NULL; @@ -436,13 +466,13 @@ nm_dhcp_systemd_get_lease_ip_configs (const char *iface, NMIP4Config *ip4_config; int r; - if (ipv6) + if (addr_family != AF_INET) return NULL; - path = get_leasefile_path (iface, uuid, FALSE); + path = get_leasefile_path (addr_family, iface, uuid); r = dhcp_lease_load (&lease, path); if (r == 0 && lease) { - ip4_config = lease_to_ip4_config (iface, ifindex, lease, NULL, default_route_metric, FALSE, NULL); + ip4_config = lease_to_ip4_config (multi_idx, iface, ifindex, lease, NULL, route_table, route_metric, FALSE, NULL); if (ip4_config) leases = g_slist_append (leases, ip4_config); sd_dhcp_lease_unref (lease); @@ -495,12 +525,14 @@ bound4_handle (NMDhcpSystemd *self) _LOGD ("lease available"); - options = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); - ip4_config = lease_to_ip4_config (iface, + options = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_free); + ip4_config = lease_to_ip4_config (nm_dhcp_client_get_multi_idx (NM_DHCP_CLIENT (self)), + iface, nm_dhcp_client_get_ifindex (NM_DHCP_CLIENT (self)), lease, options, - nm_dhcp_client_get_priority (NM_DHCP_CLIENT (self)), + nm_dhcp_client_get_route_table (NM_DHCP_CLIENT (self)), + nm_dhcp_client_get_route_metric (NM_DHCP_CLIENT (self)), TRUE, &error); if (ip4_config) { @@ -589,9 +621,9 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last g_assert (priv->client6 == NULL); g_free (priv->lease_file); - priv->lease_file = get_leasefile_path (iface, nm_dhcp_client_get_uuid (client), FALSE); + priv->lease_file = get_leasefile_path (AF_INET, iface, nm_dhcp_client_get_uuid (client)); - r = sd_dhcp_client_new (&priv->client4); + r = sd_dhcp_client_new (&priv->client4, FALSE); if (r < 0) { _LOGW ("failed to create client (%d)", r); return FALSE; @@ -716,7 +748,8 @@ error: } static NMIP6Config * -lease_to_ip6_config (const char *iface, +lease_to_ip6_config (NMDedupMultiIndex *multi_idx, + const char *iface, int ifindex, sd_dhcp6_lease *lease, GHashTable *options, @@ -729,17 +762,17 @@ lease_to_ip6_config (const char *iface, NMIP6Config *ip6_config; const char *addr_str; char **domains; - GString *str; + nm_auto_free_gstring GString *str = NULL; int num, i; gint32 ts; g_return_val_if_fail (lease, NULL); - ip6_config = nm_ip6_config_new (ifindex); + ip6_config = nm_ip6_config_new (multi_idx, ifindex); ts = nm_utils_get_monotonic_timestamp_s (); - str = g_string_sized_new (30); /* Addresses */ sd_dhcp6_lease_reset_address_iter (lease); + nm_gstring_prepare (&str); while (sd_dhcp6_lease_get_address (lease, &tmp_addr, &lft_pref, &lft_valid) >= 0) { NMPlatformIP6Address address = { .plen = 128, @@ -756,17 +789,14 @@ lease_to_ip6_config (const char *iface, g_string_append_printf (str, "%s%s", str->len ? " " : "", addr_str); LOG_LEASE (LOGD_DHCP6, - " address %s", + "address %s", nm_platform_ip6_address_to_string (&address, NULL, 0)); }; - if (str->len) { + if (str->len) add_option (options, dhcp6_requests, DHCP6_OPTION_IP_ADDRESS, str->str); - g_string_set_size (str , 0); - } if (!info_only && nm_ip6_config_get_num_addresses (ip6_config) == 0) { - g_string_free (str, TRUE); g_object_unref (ip6_config); g_set_error_literal (error, NM_MANAGER_ERROR, @@ -778,30 +808,28 @@ lease_to_ip6_config (const char *iface, /* DNS servers */ num = sd_dhcp6_lease_get_dns (lease, &dns); if (num > 0) { + nm_gstring_prepare (&str); for (i = 0; i < num; i++) { nm_ip6_config_add_nameserver (ip6_config, &dns[i]); addr_str = nm_utils_inet6_ntop (&dns[i], NULL); g_string_append_printf (str, "%s%s", str->len ? " " : "", addr_str); - LOG_LEASE (LOGD_DHCP6, " nameserver %s", addr_str); + LOG_LEASE (LOGD_DHCP6, "nameserver %s", addr_str); } add_option (options, dhcp6_requests, SD_DHCP6_OPTION_DNS_SERVERS, str->str); - g_string_set_size (str, 0); } /* Search domains */ num = sd_dhcp6_lease_get_domains (lease, &domains); if (num > 0) { + nm_gstring_prepare (&str); for (i = 0; i < num; i++) { nm_ip6_config_add_search (ip6_config, domains[i]); g_string_append_printf (str, "%s%s", str->len ? " " : "", domains[i]); - LOG_LEASE (LOGD_DHCP6, " domain name '%s'", domains[i]); + LOG_LEASE (LOGD_DHCP6, "domain name '%s'", domains[i]); } add_option (options, dhcp6_requests, SD_DHCP6_OPTION_DOMAIN_LIST, str->str); - g_string_set_size (str, 0); } - g_string_free (str, TRUE); - return ip6_config; } @@ -825,8 +853,9 @@ bound6_handle (NMDhcpSystemd *self) _LOGD ("lease available"); - options = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); - ip6_config = lease_to_ip6_config (iface, + options = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_free); + ip6_config = lease_to_ip6_config (nm_dhcp_client_get_multi_idx (NM_DHCP_CLIENT (self)), + iface, nm_dhcp_client_get_ifindex (NM_DHCP_CLIENT (self)), lease, options, @@ -893,7 +922,7 @@ ip6_start (NMDhcpClient *client, g_return_val_if_fail (duid != NULL, FALSE); g_free (priv->lease_file); - priv->lease_file = get_leasefile_path (iface, nm_dhcp_client_get_uuid (client), TRUE); + priv->lease_file = get_leasefile_path (AF_INET6, iface, nm_dhcp_client_get_uuid (client)); priv->info_only = info_only; r = sd_dhcp6_client_new (&priv->client6); diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c index e55a21b4..4b2d57b9 100644 --- a/src/dhcp/nm-dhcp-utils.c +++ b/src/dhcp/nm-dhcp-utils.c @@ -24,6 +24,8 @@ #include <unistd.h> #include <arpa/inet.h> +#include "nm-utils/nm-dedup-multi.h" + #include "nm-dhcp-utils.h" #include "nm-utils.h" #include "NetworkManagerUtils.h" @@ -36,7 +38,8 @@ static gboolean ip4_process_dhcpcd_rfc3442_routes (const char *iface, const char *str, - guint32 priority, + guint32 route_table, + guint32 route_metric, NMIP4Config *ip4_config, guint32 *gwaddr) { @@ -84,12 +87,13 @@ ip4_process_dhcpcd_rfc3442_routes (const char *iface, } else { _LOG2I (LOGD_DHCP4, iface, " classless static route %s/%d gw %s", *r, rt_cidr, *(r + 1)); memset (&route, 0, sizeof (route)); - route.network = rt_addr; + route.network = nm_utils_ip4_address_clear_host_address (rt_addr, rt_cidr); route.plen = rt_cidr; route.gateway = rt_route; route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; - route.metric = priority; - nm_ip4_config_add_route (ip4_config, &route); + route.metric = route_metric; + route.table_coerced = nm_platform_route_table_coerce (route_table); + nm_ip4_config_add_route (ip4_config, &route, NULL); } } @@ -142,8 +146,7 @@ process_dhclient_rfc3442_route (const char **octets, goto error; } g_free (str_addr); - tmp_addr &= nm_utils_ip4_prefix_to_netmask ((guint32) tmp); - route->network = tmp_addr; + route->network = nm_utils_ip4_address_clear_host_address (tmp_addr, tmp); } /* Handle next hop */ @@ -165,7 +168,8 @@ error: static gboolean ip4_process_dhclient_rfc3442_routes (const char *iface, const char *str, - guint32 priority, + guint32 route_table, + guint32 route_metric, NMIP4Config *ip4_config, guint32 *gwaddr) { @@ -197,8 +201,9 @@ ip4_process_dhclient_rfc3442_routes (const char *iface, /* normal route */ route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; - route.metric = priority; - nm_ip4_config_add_route (ip4_config, &route); + route.metric = route_metric; + route.table_coerced = nm_platform_route_table_coerce (route_table); + nm_ip4_config_add_route (ip4_config, &route, NULL); _LOG2I (LOGD_DHCP4, iface, " classless static route %s/%d gw %s", nm_utils_inet4_ntop (route.network, addr), route.plen, @@ -214,7 +219,8 @@ out: static gboolean ip4_process_classless_routes (const char *iface, GHashTable *options, - guint32 priority, + guint32 route_table, + guint32 route_metric, NMIP4Config *ip4_config, guint32 *gwaddr) { @@ -270,16 +276,17 @@ ip4_process_classless_routes (const char *iface, if (strchr (str, '/')) { /* dhcpcd format */ - return ip4_process_dhcpcd_rfc3442_routes (iface, str, priority, ip4_config, gwaddr); + return ip4_process_dhcpcd_rfc3442_routes (iface, str, route_table, route_metric, ip4_config, gwaddr); } - return ip4_process_dhclient_rfc3442_routes (iface, str, priority, ip4_config, gwaddr); + return ip4_process_dhclient_rfc3442_routes (iface, str, route_table, route_metric, ip4_config, gwaddr); } static void process_classful_routes (const char *iface, GHashTable *options, - guint32 priority, + guint32 route_table, + guint32 route_metric, NMIP4Config *ip4_config) { const char *str; @@ -316,16 +323,19 @@ process_classful_routes (const char *iface, 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)) { + 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.rt_source = NM_IP_CONFIG_SOURCE_DHCP; - route.metric = priority; + route.metric = route_metric; + route.table_coerced = nm_platform_route_table_coerce (route_table); + + route.network = nm_utils_ip4_address_clear_host_address (route.network, route.plen); - nm_ip4_config_add_route (ip4_config, &route); + nm_ip4_config_add_route (ip4_config, &route, NULL); _LOG2I (LOGD_DHCP, iface, " static route %s", nm_platform_ip4_route_to_string (&route, NULL, 0)); } @@ -383,22 +393,25 @@ ip4_add_domain_search (gpointer data, gpointer user_data) } NMIP4Config * -nm_dhcp_utils_ip4_config_from_options (int ifindex, +nm_dhcp_utils_ip4_config_from_options (NMDedupMultiIndex *multi_idx, + int ifindex, const char *iface, GHashTable *options, - guint32 priority) + guint32 route_table, + guint32 route_metric) { NMIP4Config *ip4_config = NULL; guint32 tmp_addr; in_addr_t addr; NMPlatformIP4Address address; char *str = NULL; - guint32 gwaddr = 0; + gboolean gateway_has = FALSE; + guint32 gateway = 0; guint8 plen = 0; g_return_val_if_fail (options != NULL, NULL); - ip4_config = nm_ip4_config_new (ifindex); + ip4_config = nm_ip4_config_new (multi_idx, ifindex); memset (&address, 0, sizeof (address)); address.timestamp = nm_utils_get_monotonic_timestamp_s (); @@ -414,7 +427,7 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex, _LOG2I (LOGD_DHCP4, iface, " plen %d (%s)", plen, str); } else { /* Get default netmask for the IP according to appropriate class. */ - plen = nm_utils_ip4_get_default_prefix (addr); + plen = _nm_utils_ip4_get_default_prefix (addr); _LOG2I (LOGD_DHCP4, iface, " plen %d (default)", plen); } nm_platform_ip4_address_set_addr (&address, addr, plen); @@ -422,12 +435,12 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex, /* Routes: if the server returns classless static routes, we MUST ignore * the 'static_routes' option. */ - if (!ip4_process_classless_routes (iface, options, priority, ip4_config, &gwaddr)) - process_classful_routes (iface, options, priority, ip4_config); + if (!ip4_process_classless_routes (iface, options, route_table, route_metric, ip4_config, &gateway)) + process_classful_routes (iface, options, route_table, route_metric, ip4_config); - if (gwaddr) { - _LOG2I (LOGD_DHCP4, iface, " gateway %s", nm_utils_inet4_ntop (gwaddr, NULL)); - nm_ip4_config_set_gateway (ip4_config, gwaddr); + if (gateway) { + _LOG2I (LOGD_DHCP4, iface, " gateway %s", nm_utils_inet4_ntop (gateway, NULL)); + gateway_has = TRUE; } 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. @@ -439,9 +452,9 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex, for (s = routers; *s; s++) { /* FIXME: how to handle multiple routers? */ - if (inet_pton (AF_INET, *s, &gwaddr) > 0) { - nm_ip4_config_set_gateway (ip4_config, gwaddr); + if (inet_pton (AF_INET, *s, &gateway) > 0) { _LOG2I (LOGD_DHCP4, iface, " gateway %s", *s); + gateway_has = TRUE; break; } else _LOG2W (LOGD_DHCP4, iface, "ignoring invalid gateway '%s'", *s); @@ -450,6 +463,17 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex, } } + if (gateway_has) { + const NMPlatformIP4Route r = { + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .gateway = gateway, + .table_coerced = nm_platform_route_table_coerce (route_table), + .metric = route_metric, + }; + + nm_ip4_config_add_route (ip4_config, &r, NULL); + } + str = g_hash_table_lookup (options, "dhcp_lease_time"); if (str) { address.lifetime = address.preferred = strtoul (str, NULL, 10); @@ -616,10 +640,10 @@ nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options) } NMIP6Config * -nm_dhcp_utils_ip6_config_from_options (int ifindex, +nm_dhcp_utils_ip6_config_from_options (NMDedupMultiIndex *multi_idx, + int ifindex, const char *iface, GHashTable *options, - guint32 priority, gboolean info_only) { NMIP6Config *ip6_config = NULL; @@ -633,7 +657,7 @@ nm_dhcp_utils_ip6_config_from_options (int ifindex, address.plen = 128; address.timestamp = nm_utils_get_monotonic_timestamp_s (); - ip6_config = nm_ip6_config_new (ifindex); + ip6_config = nm_ip6_config_new (multi_idx, ifindex); str = g_hash_table_lookup (options, "max_life"); if (str) { diff --git a/src/dhcp/nm-dhcp-utils.h b/src/dhcp/nm-dhcp-utils.h index 05982b16..32140f48 100644 --- a/src/dhcp/nm-dhcp-utils.h +++ b/src/dhcp/nm-dhcp-utils.h @@ -24,15 +24,17 @@ #include "nm-ip4-config.h" #include "nm-ip6-config.h" -NMIP4Config *nm_dhcp_utils_ip4_config_from_options (int ifindex, +NMIP4Config *nm_dhcp_utils_ip4_config_from_options (struct _NMDedupMultiIndex *multi_idx, + int ifindex, const char *iface, GHashTable *options, - guint priority); + guint32 route_table, + guint32 route_metric); -NMIP6Config *nm_dhcp_utils_ip6_config_from_options (int ifindex, +NMIP6Config *nm_dhcp_utils_ip6_config_from_options (struct _NMDedupMultiIndex *multi_idx, + int ifindex, const char *iface, GHashTable *options, - guint priority, gboolean info_only); NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options); diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c index 5816932b..f2e1f321 100644 --- a/src/dhcp/tests/test-dhcp-dhclient.c +++ b/src/dhcp/tests/test-dhcp-dhclient.c @@ -23,6 +23,9 @@ #include <string.h> #include <unistd.h> #include <arpa/inet.h> +#include <linux/rtnetlink.h> + +#include "nm-utils/nm-dedup-multi.h" #include "NetworkManagerUtils.h" #include "dhcp/nm-dhcp-dhclient-utils.h" @@ -35,10 +38,14 @@ #define DEBUG 1 +static const int IFINDEX = 5; +static const guint32 ROUTE_TABLE = RT_TABLE_MAIN; +static const guint32 ROUTE_METRIC = 100; + static void test_config (const char *orig, const char *expected, - gboolean ipv6, + int addr_family, const char *hostname, guint32 timeout, gboolean use_fqdn, @@ -57,7 +64,7 @@ test_config (const char *orig, } new = nm_dhcp_dhclient_create_config (iface, - ipv6, + addr_family, client_id, anycast_addr, hostname, @@ -106,7 +113,7 @@ static const char *orig_missing_expected = \ static void test_orig_missing (void) { - test_config (NULL, orig_missing_expected, FALSE, NULL, 0, FALSE, NULL, NULL, "eth0", NULL); + test_config (NULL, orig_missing_expected, AF_INET, NULL, 0, FALSE, NULL, NULL, "eth0", NULL); } /*****************************************************************************/ @@ -135,7 +142,7 @@ static void test_override_client_id (void) { test_config (override_client_id_orig, override_client_id_expected, - FALSE, NULL, 0, FALSE, + AF_INET, NULL, 0, FALSE, "11:22:33:44:55:66", NULL, "eth0", @@ -164,7 +171,7 @@ static void test_quote_client_id (void) { test_config (NULL, quote_client_id_expected, - FALSE, NULL, 0, FALSE, + AF_INET, NULL, 0, FALSE, "1234", NULL, "eth0", @@ -193,7 +200,7 @@ static void test_ascii_client_id (void) { test_config (NULL, ascii_client_id_expected, - FALSE, NULL, 0, FALSE, + AF_INET, NULL, 0, FALSE, "qb:cd:ef:12:34:56", NULL, "eth0", @@ -222,7 +229,7 @@ static void test_hex_single_client_id (void) { test_config (NULL, hex_single_client_id_expected, - FALSE, NULL, 0, FALSE, + AF_INET, NULL, 0, FALSE, "ab:cd:e:12:34:56", NULL, "eth0", @@ -259,7 +266,7 @@ test_existing_hex_client_id (void) new_client_id = g_bytes_new (bytes, sizeof (bytes)); test_config (existing_hex_client_id_orig, existing_hex_client_id_expected, - FALSE, NULL, 0, FALSE, + AF_INET, NULL, 0, FALSE, NULL, new_client_id, "eth0", @@ -299,7 +306,7 @@ test_existing_ascii_client_id (void) memcpy (buf + 1, EACID, NM_STRLEN (EACID)); new_client_id = g_bytes_new (buf, sizeof (buf)); test_config (existing_ascii_client_id_orig, existing_ascii_client_id_expected, - FALSE, NULL, 0, FALSE, + AF_INET, NULL, 0, FALSE, NULL, new_client_id, "eth0", @@ -328,7 +335,7 @@ static void test_fqdn (void) { test_config (NULL, fqdn_expected, - FALSE, "foo.bar.com", 0, + AF_INET, "foo.bar.com", 0, TRUE, NULL, NULL, "eth0", @@ -368,7 +375,7 @@ test_fqdn_options_override (void) { test_config (fqdn_options_override_orig, fqdn_options_override_expected, - FALSE, "example2.com", 0, + AF_INET, "example2.com", 0, TRUE, NULL, NULL, "eth0", @@ -401,7 +408,7 @@ static void test_override_hostname (void) { test_config (override_hostname_orig, override_hostname_expected, - FALSE, "blahblah", 0, FALSE, + AF_INET, "blahblah", 0, FALSE, NULL, NULL, "eth0", @@ -418,7 +425,6 @@ static const char *override_hostname6_expected = \ "# Merged from /path/to/dhclient.conf\n" "\n" "send fqdn.fqdn \"blahblah.local\"; # added by NetworkManager\n" - "send fqdn.encoded on;\n" "send fqdn.server-update on;\n" "\n" "also request dhcp6.name-servers;\n" @@ -430,7 +436,7 @@ static void test_override_hostname6 (void) { test_config (override_hostname6_orig, override_hostname6_expected, - TRUE, "blahblah.local", 0, TRUE, + AF_INET6, "blahblah.local", 0, TRUE, NULL, NULL, "eth0", @@ -442,6 +448,9 @@ test_override_hostname6 (void) static const char *nonfqdn_hostname6_expected = \ "# Created by NetworkManager\n" "\n" + "send fqdn.fqdn \"blahblah\"; # added by NetworkManager\n" + "send fqdn.server-update on;\n" + "\n" "also request dhcp6.name-servers;\n" "also request dhcp6.domain-search;\n" "also request dhcp6.client-id;\n" @@ -450,9 +459,9 @@ static const char *nonfqdn_hostname6_expected = \ static void test_nonfqdn_hostname6 (void) { - /* Non-FQDN hostname can't be used with dhclient */ + /* Non-FQDN hostname can now be used with dhclient */ test_config (NULL, nonfqdn_hostname6_expected, - TRUE, "blahblah", 0, TRUE, + AF_INET6, "blahblah", 0, TRUE, NULL, NULL, "eth0", @@ -487,7 +496,7 @@ static void test_existing_alsoreq (void) { test_config (existing_alsoreq_orig, existing_alsoreq_expected, - FALSE, NULL, 0, FALSE, + AF_INET, NULL, 0, FALSE, NULL, NULL, "eth0", @@ -525,7 +534,7 @@ static void test_existing_req (void) { test_config (existing_req_orig, existing_req_expected, - FALSE, NULL, 0, FALSE, + AF_INET, NULL, 0, FALSE, NULL, NULL, "eth0", @@ -564,7 +573,7 @@ static void test_existing_multiline_alsoreq (void) { test_config (existing_multiline_alsoreq_orig, existing_multiline_alsoreq_expected, - FALSE, NULL, 0, FALSE, + AF_INET, NULL, 0, FALSE, NULL, NULL, "eth0", @@ -778,7 +787,7 @@ static void test_interface1 (void) { test_config (interface1_orig, interface1_expected, - FALSE, NULL, 0, FALSE, + AF_INET, NULL, 0, FALSE, NULL, NULL, "eth0", @@ -823,7 +832,7 @@ static void test_interface2 (void) { test_config (interface2_orig, interface2_expected, - FALSE, NULL, 0, FALSE, + AF_INET, NULL, 0, FALSE, NULL, NULL, "eth1", @@ -877,7 +886,7 @@ test_config_req_intf (void) "\n"; test_config (orig, expected, - FALSE, NULL, 0, FALSE, + AF_INET, NULL, 0, FALSE, NULL, NULL, "eth0", @@ -889,6 +898,7 @@ test_config_req_intf (void) static void test_read_lease_ip4_config_basic (void) { + nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new (); GError *error = NULL; char *contents = NULL; gboolean success; @@ -905,7 +915,7 @@ test_read_lease_ip4_config_basic (void) /* Date from before the least expiration */ now = g_date_time_new_utc (2013, 11, 1, 19, 55, 32); - leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", -1, contents, FALSE, now); + leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now); g_assert_cmpint (g_slist_length (leases), ==, 2); /* IP4Config #1 */ @@ -914,19 +924,19 @@ test_read_lease_ip4_config_basic (void) /* Address */ g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1); - g_assert (inet_aton ("192.168.1.180", (struct in_addr *) &expected_addr)); - addr = nm_ip4_config_get_address (config, 0); + expected_addr = nmtst_inet4_from_string ("192.168.1.180"); + addr = _nmtst_ip4_config_get_address (config, 0); g_assert_cmpint (addr->address, ==, expected_addr); g_assert_cmpint (addr->peer_address, ==, expected_addr); g_assert_cmpint (addr->plen, ==, 24); /* Gateway */ - g_assert (inet_aton ("192.168.1.1", (struct in_addr *) &expected_addr)); - g_assert_cmpint (nm_ip4_config_get_gateway (config), ==, expected_addr); + expected_addr = nmtst_inet4_from_string ("192.168.1.1"); + g_assert_cmpint (nmtst_ip4_config_get_gateway (config), ==, expected_addr); /* DNS */ g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 1); - g_assert (inet_aton ("192.168.1.1", (struct in_addr *) &expected_addr)); + expected_addr = nmtst_inet4_from_string ("192.168.1.1"); g_assert_cmpint (nm_ip4_config_get_nameserver (config, 0), ==, expected_addr); g_assert_cmpint (nm_ip4_config_get_num_domains (config), ==, 0); @@ -937,21 +947,21 @@ test_read_lease_ip4_config_basic (void) /* Address */ g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1); - g_assert (inet_aton ("10.77.52.141", (struct in_addr *) &expected_addr)); - addr = nm_ip4_config_get_address (config, 0); + expected_addr = nmtst_inet4_from_string ("10.77.52.141"); + addr = _nmtst_ip4_config_get_address (config, 0); g_assert_cmpint (addr->address, ==, expected_addr); g_assert_cmpint (addr->peer_address, ==, expected_addr); g_assert_cmpint (addr->plen, ==, 8); /* Gateway */ - g_assert (inet_aton ("10.77.52.254", (struct in_addr *) &expected_addr)); - g_assert_cmpint (nm_ip4_config_get_gateway (config), ==, expected_addr); + expected_addr = nmtst_inet4_from_string ("10.77.52.254"); + g_assert_cmpint (nmtst_ip4_config_get_gateway (config), ==, expected_addr); /* DNS */ g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 2); - g_assert (inet_aton ("8.8.8.8", (struct in_addr *) &expected_addr)); + expected_addr = nmtst_inet4_from_string ("8.8.8.8"); g_assert_cmpint (nm_ip4_config_get_nameserver (config, 0), ==, expected_addr); - g_assert (inet_aton ("8.8.4.4", (struct in_addr *) &expected_addr)); + expected_addr = nmtst_inet4_from_string ("8.8.4.4"); g_assert_cmpint (nm_ip4_config_get_nameserver (config, 1), ==, expected_addr); /* Domains */ @@ -966,6 +976,7 @@ test_read_lease_ip4_config_basic (void) static void test_read_lease_ip4_config_expired (void) { + nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new (); GError *error = NULL; char *contents = NULL; gboolean success; @@ -979,7 +990,7 @@ test_read_lease_ip4_config_expired (void) /* Date from *after* the lease expiration */ now = g_date_time_new_utc (2013, 12, 1, 19, 55, 32); - leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", -1, contents, FALSE, now); + leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now); g_assert (leases == NULL); g_date_time_unref (now); @@ -989,6 +1000,7 @@ test_read_lease_ip4_config_expired (void) static void test_read_lease_ip4_config_expect_failure (gconstpointer user_data) { + nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new (); GError *error = NULL; char *contents = NULL; gboolean success; @@ -1001,7 +1013,7 @@ test_read_lease_ip4_config_expect_failure (gconstpointer user_data) /* Date from before the least expiration */ now = g_date_time_new_utc (2013, 11, 1, 1, 1, 1); - leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", -1, contents, FALSE, now); + leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now); g_assert (leases == NULL); g_date_time_unref (now); diff --git a/src/dhcp/tests/test-dhcp-utils.c b/src/dhcp/tests/test-dhcp-utils.c index ffd63493..72f31191 100644 --- a/src/dhcp/tests/test-dhcp-utils.c +++ b/src/dhcp/tests/test-dhcp-utils.c @@ -22,7 +22,9 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> +#include <linux/rtnetlink.h> +#include "nm-utils/nm-dedup-multi.h" #include "nm-utils.h" #include "dhcp/nm-dhcp-utils.h" @@ -30,6 +32,20 @@ #include "nm-test-utils-core.h" +static NMIP4Config * +_ip4_config_from_options (int ifindex, + const char *iface, + GHashTable *options, + guint32 route_metric) +{ + nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new (); + NMIP4Config *config; + + config = nm_dhcp_utils_ip4_config_from_options (multi_idx, ifindex, iface, options, RT_TABLE_MAIN, route_metric); + g_assert (config); + return config; +} + typedef struct { const char *name; const char *value; @@ -41,7 +57,7 @@ fill_table (const Option *test_options, GHashTable *table) const Option *opt; if (!table) - table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); + table = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, NULL); for (opt = test_options; opt->name; opt++) g_hash_table_insert (table, (gpointer) opt->name, (gpointer) opt->value); return table; @@ -86,12 +102,11 @@ test_generic_options (void) const char *expected_route2_gw = "10.1.1.1"; options = fill_table (generic_options, NULL); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); /* IP4 address */ g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1); - address = nm_ip4_config_get_address (ip4_config, 0); + address = _nmtst_ip4_config_get_address (ip4_config, 0); g_assert (inet_pton (AF_INET, expected_addr, &tmp) > 0); g_assert (address->address == tmp); g_assert (address->peer_address == tmp); @@ -99,7 +114,7 @@ test_generic_options (void) /* Gateway */ g_assert (inet_pton (AF_INET, expected_gw, &tmp) > 0); - g_assert (nm_ip4_config_get_gateway (ip4_config) == tmp); + g_assert (nmtst_ip4_config_get_gateway (ip4_config) == tmp); g_assert_cmpint (nm_ip4_config_get_num_wins (ip4_config), ==, 0); @@ -118,10 +133,10 @@ test_generic_options (void) g_assert (nm_ip4_config_get_nameserver (ip4_config, 1) == tmp); /* Routes */ - g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); + g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3); /* Route #1 */ - route = nm_ip4_config_get_route (ip4_config, 0); + route = _nmtst_ip4_config_get_route (ip4_config, 0); g_assert (inet_pton (AF_INET, expected_route1_dest, &tmp) > 0); g_assert (route->network == tmp); g_assert (inet_pton (AF_INET, expected_route1_gw, &tmp) > 0); @@ -130,14 +145,18 @@ test_generic_options (void) g_assert_cmpint (route->metric, ==, 0); /* Route #2 */ - route = nm_ip4_config_get_route (ip4_config, 1); - g_assert (inet_pton (AF_INET, expected_route2_dest, &tmp) > 0); - g_assert (route->network == tmp); - g_assert (inet_pton (AF_INET, expected_route2_gw, &tmp) > 0); - g_assert (route->gateway == tmp); + route = _nmtst_ip4_config_get_route (ip4_config, 1); + g_assert (route->network == nmtst_inet4_from_string (expected_route2_dest)); + g_assert (route->gateway == nmtst_inet4_from_string (expected_route2_gw)); g_assert_cmpint (route->plen, ==, 32); g_assert_cmpint (route->metric, ==, 0); + route = _nmtst_ip4_config_get_route (ip4_config, 2); + g_assert (route->network == nmtst_inet4_from_string ("0.0.0.0")); + g_assert (route->gateway == nmtst_inet4_from_string ("192.168.1.1")); + g_assert_cmpint (route->plen, ==, 0); + g_assert_cmpint (route->metric, ==, 0); + g_hash_table_destroy (options); } @@ -157,12 +176,11 @@ test_wins_options (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); /* IP4 address */ g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1); - address = nm_ip4_config_get_address (ip4_config, 0); + address = _nmtst_ip4_config_get_address (ip4_config, 0); g_assert (address); g_assert_cmpint (nm_ip4_config_get_num_wins (ip4_config), ==, 2); g_assert (inet_pton (AF_INET, expected_wins1, &tmp) > 0); @@ -184,16 +202,14 @@ test_vendor_option_metered (void) }; options = fill_table (generic_options, NULL); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_assert (nm_ip4_config_get_metered (ip4_config) == FALSE); g_hash_table_destroy (options); g_clear_object (&ip4_config); options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_assert (nm_ip4_config_get_metered (ip4_config) == TRUE); g_hash_table_destroy (options); } @@ -210,7 +226,7 @@ ip4_test_route (NMIP4Config *ip4_config, g_assert (expected_prefix <= 32); - route = nm_ip4_config_get_route (ip4_config, route_num); + route = _nmtst_ip4_config_get_route (ip4_config, route_num); g_assert (inet_pton (AF_INET, expected_dest, &tmp) > 0); g_assert (route->network == tmp); g_assert (inet_pton (AF_INET, expected_gw, &tmp) > 0); @@ -226,7 +242,7 @@ ip4_test_gateway (NMIP4Config *ip4_config, const char *expected_gw) g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1); g_assert (inet_pton (AF_INET, expected_gw, &tmp) > 0); - g_assert (nm_ip4_config_get_gateway (ip4_config) == tmp); + g_assert (nmtst_ip4_config_get_gateway (ip4_config) == tmp); } static void @@ -246,13 +262,13 @@ test_classless_static_routes_1 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); /* IP4 routes */ - g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); + g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 8); + ip4_test_route (ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); g_hash_table_destroy (options); } @@ -274,13 +290,13 @@ test_classless_static_routes_2 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); /* IP4 routes */ - g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); + g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 8); + ip4_test_route (ip4_config, 2, "0.0.0.0", expected_route1_gw, 0); g_hash_table_destroy (options); } @@ -303,13 +319,13 @@ test_fedora_dhclient_classless_static_routes (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); /* IP4 routes */ - g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); + g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 25); ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 7); + ip4_test_route (ip4_config, 2, "0.0.0.0", expected_route1_gw, 0); /* Gateway */ ip4_test_gateway (ip4_config, expected_gateway); @@ -335,13 +351,13 @@ test_dhclient_invalid_classless_routes_1 (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*ignoring invalid classless static routes*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); /* IP4 routes */ - g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1); + g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route (ip4_config, 1, "0.0.0.0", expected_route1_gw, 0); g_hash_table_destroy (options); } @@ -366,16 +382,16 @@ test_dhcpcd_invalid_classless_routes_1 (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*ignoring invalid classless static routes*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); /* Test falling back to old-style static routes if the classless static * routes are invalid. */ - g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); + g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); + ip4_test_route (ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); g_hash_table_destroy (options); } @@ -399,16 +415,16 @@ test_dhclient_invalid_classless_routes_2 (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*ignoring invalid classless static routes*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); /* Test falling back to old-style static routes if the classless static * routes are invalid. */ - g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); + g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); + ip4_test_route (ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); g_hash_table_destroy (options); } @@ -432,8 +448,7 @@ test_dhcpcd_invalid_classless_routes_2 (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*ignoring invalid classless static routes*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); /* Test falling back to old-style static routes if the classless static @@ -441,9 +456,10 @@ test_dhcpcd_invalid_classless_routes_2 (void) */ /* Routes */ - g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); + g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); + ip4_test_route (ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); g_hash_table_destroy (options); } @@ -465,13 +481,13 @@ test_dhclient_invalid_classless_routes_3 (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*ignoring invalid classless static routes*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); /* IP4 routes */ - g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1); + g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route (ip4_config, 1, "0.0.0.0", expected_route1_gw, 0); g_hash_table_destroy (options); } @@ -493,13 +509,13 @@ test_dhcpcd_invalid_classless_routes_3 (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*DHCP provided invalid classless static route*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); /* IP4 routes */ - g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1); + g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route (ip4_config, 1, "0.0.0.0", expected_route1_gw, 0); g_hash_table_destroy (options); } @@ -519,12 +535,12 @@ test_dhclient_gw_in_classless_routes (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); /* IP4 routes */ - g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1); + g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route (ip4_config, 1, "0.0.0.0", "192.2.3.4", 0); /* Gateway */ ip4_test_gateway (ip4_config, expected_gateway); @@ -547,12 +563,12 @@ test_dhcpcd_gw_in_classless_routes (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); /* IP4 routes */ - g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1); + g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route (ip4_config, 1, "0.0.0.0", "192.2.3.4", 0); /* Gateway */ ip4_test_gateway (ip4_config, expected_gateway); @@ -575,8 +591,7 @@ test_escaped_domain_searches (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); /* domain searches */ g_assert_cmpint (nm_ip4_config_get_num_searches (ip4_config), ==, 3); @@ -602,8 +617,7 @@ test_invalid_escaped_domain_searches (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*invalid domain search*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); /* domain searches */ @@ -623,11 +637,10 @@ test_ip4_missing_prefix (const char *ip, guint32 expected_prefix) g_hash_table_insert (options, "ip_address", (gpointer) ip); g_hash_table_remove (options, "subnet_mask"); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1); - address = nm_ip4_config_get_address (ip4_config, 0); + address = _nmtst_ip4_config_get_address (ip4_config, 0); g_assert (address); g_assert_cmpint (address->plen, ==, expected_prefix); @@ -668,11 +681,10 @@ test_ip4_prefix_classless (void) g_hash_table_insert (options, "ip_address", "172.16.54.22"); g_hash_table_insert (options, "subnet_mask", "255.255.252.0"); - ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); - g_assert (ip4_config); + ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1); - address = nm_ip4_config_get_address (ip4_config, 0); + address = _nmtst_ip4_config_get_address (ip4_config, 0); g_assert (address); g_assert_cmpint (address->plen, ==, 22); |