From ee9c73a923909e23a649407be77e25235d769e25 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Fri, 11 May 2018 22:08:45 +0200 Subject: New upstream version 1.10.8 --- src/dhcp/meson.build | 22 --- src/dhcp/nm-dhcp-client.c | 119 ++++++------ src/dhcp/nm-dhcp-client.h | 49 ++--- src/dhcp/nm-dhcp-dhclient-utils.c | 330 ++++++++++++++++++++++++++------ src/dhcp/nm-dhcp-dhclient-utils.h | 15 +- src/dhcp/nm-dhcp-dhclient.c | 59 ++++-- src/dhcp/nm-dhcp-dhcpcanon.c | 14 +- src/dhcp/nm-dhcp-dhcpcd.c | 17 +- src/dhcp/nm-dhcp-helper.c | 2 + src/dhcp/nm-dhcp-listener.c | 84 ++++---- src/dhcp/nm-dhcp-manager.c | 118 ++++++++---- src/dhcp/nm-dhcp-manager.h | 15 +- src/dhcp/nm-dhcp-systemd.c | 115 ++++++----- src/dhcp/nm-dhcp-utils.c | 8 +- src/dhcp/nm-dhcp-utils.h | 2 +- src/dhcp/tests/leases/basic.leases | 31 +++ src/dhcp/tests/leases/malformed1.leases | 15 ++ src/dhcp/tests/leases/malformed2.leases | 15 ++ src/dhcp/tests/leases/malformed3.leases | 15 ++ src/dhcp/tests/meson.build | 19 -- src/dhcp/tests/test-dhcp-dhclient.c | 318 +++++++++++++++++------------- src/dhcp/tests/test-dhcp-utils.c | 21 +- 22 files changed, 917 insertions(+), 486 deletions(-) delete mode 100644 src/dhcp/meson.build create mode 100644 src/dhcp/tests/leases/basic.leases create mode 100644 src/dhcp/tests/leases/malformed1.leases create mode 100644 src/dhcp/tests/leases/malformed2.leases create mode 100644 src/dhcp/tests/leases/malformed3.leases delete mode 100644 src/dhcp/tests/meson.build (limited to 'src/dhcp') diff --git a/src/dhcp/meson.build b/src/dhcp/meson.build deleted file mode 100644 index 289a16ca..00000000 --- a/src/dhcp/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -name = 'nm-dhcp-helper' - -cflags = [ - '-DG_LOG_DOMAIN="@0@"'.format(name), - '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_GLIB', - '-DNMRUNDIR="@0@"'.format(nm_pkgrundir), -] - -executable( - name, - name + '.c', - dependencies: nm_core_dep, - c_args: cflags, - link_args: ldflags_linker_script_binary, - link_depends: linker_script_binary, - install: true, - install_dir: nm_libexecdir -) - -if enable_tests - subdir('tests') -endif diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index 96c02653..ea3938d6 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -52,24 +52,23 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; NM_GOBJECT_PROPERTIES_DEFINE_BASE ( + PROP_MULTI_IDX, PROP_ADDR_FAMILY, - PROP_FLAGS, - PROP_HWADDR, PROP_IFACE, PROP_IFINDEX, - PROP_MULTI_IDX, - PROP_ROUTE_METRIC, + PROP_HWADDR, + PROP_UUID, PROP_ROUTE_TABLE, + PROP_ROUTE_METRIC, PROP_TIMEOUT, - PROP_UUID, ); typedef struct _NMDhcpClientPrivate { NMDedupMultiIndex *multi_idx; char * iface; - GBytes * hwaddr; + GByteArray * hwaddr; char * uuid; - GBytes * duid; + GByteArray * duid; GBytes * client_id; char * hostname; pid_t pid; @@ -139,7 +138,7 @@ nm_dhcp_client_get_uuid (NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE (self)->uuid; } -GBytes * +const GByteArray * nm_dhcp_client_get_duid (NMDhcpClient *self) { g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); @@ -147,7 +146,7 @@ nm_dhcp_client_get_duid (NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE (self)->duid; } -GBytes * +const GByteArray * nm_dhcp_client_get_hw_addr (NMDhcpClient *self) { g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); @@ -239,20 +238,26 @@ nm_dhcp_client_set_client_id_bin (NMDhcpClient *self, _set_client_id (self, b, TRUE); } -const char * -nm_dhcp_client_get_hostname (NMDhcpClient *self) +void +nm_dhcp_client_set_client_id_str (NMDhcpClient *self, + const char *dhcp_client_id) { - g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); + g_return_if_fail (NM_IS_DHCP_CLIENT (self)); + g_return_if_fail (!dhcp_client_id || dhcp_client_id[0]); - return NM_DHCP_CLIENT_GET_PRIVATE (self)->hostname; + _set_client_id (self, + dhcp_client_id + ? nm_dhcp_utils_client_id_string_to_bytes (dhcp_client_id) + : NULL, + TRUE); } -gboolean -nm_dhcp_client_get_info_only (NMDhcpClient *self) +const char * +nm_dhcp_client_get_hostname (NMDhcpClient *self) { - g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); + g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); - return NM_DHCP_CLIENT_GET_PRIVATE (self)->info_only; + return NM_DHCP_CLIENT_GET_PRIVATE (self)->hostname; } gboolean @@ -340,7 +345,7 @@ nm_dhcp_client_stop_pid (pid_t pid, const char *iface) } static void -stop (NMDhcpClient *self, gboolean release, GBytes *duid) +stop (NMDhcpClient *self, gboolean release, const GByteArray *duid) { NMDhcpClientPrivate *priv; @@ -354,6 +359,7 @@ stop (NMDhcpClient *self, gboolean release, GBytes *duid) nm_dhcp_client_stop_pid (priv->pid, priv->iface); } priv->pid = -1; + priv->info_only = FALSE; } void @@ -486,9 +492,10 @@ nm_dhcp_client_watch_child (NMDhcpClient *self, pid_t pid) gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self, - GBytes *client_id, + const char *dhcp_client_id, const char *dhcp_anycast_addr, const char *hostname, + gboolean use_fqdn, const char *last_ip4_address) { NMDhcpClientPrivate *priv; @@ -505,19 +512,19 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self, else _LOGI ("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout); - nm_dhcp_client_set_client_id (self, client_id); + nm_dhcp_client_set_client_id_str (self, dhcp_client_id); g_clear_pointer (&priv->hostname, g_free); priv->hostname = g_strdup (hostname); + priv->use_fqdn = use_fqdn; return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_anycast_addr, last_ip4_address); } -static GBytes * +static GByteArray * generate_duid_from_machine_id (void) { - const int DUID_SIZE = 18; - guint8 *duid_buffer; + GByteArray *duid; GChecksum *sum; guint8 buffer[32]; /* SHA256 digest size */ gsize sumlen = sizeof (buffer); @@ -525,7 +532,6 @@ generate_duid_from_machine_id (void) uuid_t uuid; gs_free char *machine_id_s = NULL; gs_free char *str = NULL; - GBytes *duid; machine_id_s = nm_utils_machine_id_read (); if (nm_utils_machine_id_parse (machine_id_s, uuid)) { @@ -548,31 +554,36 @@ generate_duid_from_machine_id (void) * u16: type (DUID-UUID = 4) * u8[16]: UUID bytes */ - duid_buffer = g_malloc (DUID_SIZE); - - G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2); - memcpy (&duid_buffer[0], &duid_type, 2); + duid = g_byte_array_sized_new (18); + g_byte_array_append (duid, (guint8 *) &duid_type, sizeof (duid_type)); /* Since SHA256 is 256 bits, but UUID is 128 bits, we just take the first * 128 bits of the SHA256 as the DUID-UUID. */ - memcpy (&duid_buffer[2], buffer, 16); + g_byte_array_append (duid, buffer, 16); - duid = g_bytes_new_take (duid_buffer, DUID_SIZE); nm_log_dbg (LOGD_DHCP, "dhcp: generated DUID %s", (str = nm_dhcp_utils_duid_to_string (duid))); return duid; } -static GBytes * +static GByteArray * get_duid (NMDhcpClient *self) { - static GBytes *duid = NULL; + static GByteArray *duid = NULL; + GByteArray *copy = NULL; - if (G_UNLIKELY (!duid)) + if (G_UNLIKELY (duid == NULL)) { duid = generate_duid_from_machine_id (); + g_assert (duid); + } + + if (G_LIKELY (duid)) { + copy = g_byte_array_sized_new (duid->len); + g_byte_array_append (copy, duid->data, duid->len); + } - return g_bytes_ref (duid); + return copy; } gboolean @@ -580,6 +591,7 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, const char *hostname, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes) { @@ -604,6 +616,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, g_clear_pointer (&priv->hostname, g_free); priv->hostname = g_strdup (hostname); + priv->info_only = info_only; + if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) _LOGI ("activation: beginning transaction (no timeout)"); else @@ -612,6 +626,7 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, return NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self, dhcp_anycast_addr, ll_addr, + info_only, privacy, priv->duid, needed_prefixes); @@ -796,8 +811,8 @@ nm_dhcp_client_handle_event (gpointer unused, old_state = priv->state; new_state = reason_to_state (self, priv->iface, reason); - _LOGD ("DHCP state '%s' -> '%s' (reason: '%s')", - state_to_string (old_state), state_to_string (new_state), reason); + _LOGD ("DHCP reason '%s' -> state '%s'", + reason, state_to_string (new_state)); if (new_state == NM_DHCP_STATE_BOUND) { GVariantIter iter; @@ -908,16 +923,8 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE ((NMDhcpClient *) object); - guint flags; switch (prop_id) { - case PROP_FLAGS: - /* construct-only */ - flags = g_value_get_uint (value); - nm_assert ((flags & ~((guint) (NM_DHCP_CLIENT_FLAGS_INFO_ONLY | NM_DHCP_CLIENT_FLAGS_USE_FQDN))) == 0); - priv->info_only = NM_FLAGS_HAS (flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY); - priv->use_fqdn = NM_FLAGS_HAS (flags, NM_DHCP_CLIENT_FLAGS_USE_FQDN); - break; case PROP_MULTI_IDX: /* construct-only */ priv->multi_idx = g_value_get_pointer (value); @@ -976,8 +983,6 @@ nm_dhcp_client_init (NMDhcpClient *self) priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_DHCP_CLIENT, NMDhcpClientPrivate); self->_priv = priv; - c_list_init (&self->dhcp_client_lst); - priv->pid = -1; } @@ -992,8 +997,6 @@ dispose (GObject *object) * the DHCP client. */ - nm_assert (c_list_is_empty (&self->dhcp_client_lst)); - watch_cleanup (self); timeout_cleanup (self); @@ -1001,8 +1004,16 @@ dispose (GObject *object) g_clear_pointer (&priv->hostname, g_free); g_clear_pointer (&priv->uuid, g_free); g_clear_pointer (&priv->client_id, g_bytes_unref); - g_clear_pointer (&priv->hwaddr, g_bytes_unref); - g_clear_pointer (&priv->duid, g_bytes_unref); + + if (priv->hwaddr) { + g_byte_array_free (priv->hwaddr, TRUE); + priv->hwaddr = NULL; + } + + if (priv->duid) { + g_byte_array_free (priv->duid, TRUE); + priv->duid = NULL; + } G_OBJECT_CLASS (nm_dhcp_client_parent_class)->dispose (object); @@ -1043,7 +1054,7 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class) obj_properties[PROP_HWADDR] = g_param_spec_boxed (NM_DHCP_CLIENT_HWADDR, "", "", - G_TYPE_BYTES, + G_TYPE_BYTE_ARRAY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); @@ -1077,12 +1088,6 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_FLAGS] = - g_param_spec_uint (NM_DHCP_CLIENT_FLAGS, "", "", - 0, G_MAXUINT32, 0, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[SIGNAL_STATE_CHANGED] = diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h index 0d92d743..2c634168 100644 --- a/src/dhcp/nm-dhcp-client.h +++ b/src/dhcp/nm-dhcp-client.h @@ -34,16 +34,15 @@ #define NM_IS_DHCP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP_CLIENT)) #define NM_DHCP_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClientClass)) -#define NM_DHCP_CLIENT_ADDR_FAMILY "addr-family" -#define NM_DHCP_CLIENT_FLAGS "flags" -#define NM_DHCP_CLIENT_HWADDR "hwaddr" -#define NM_DHCP_CLIENT_IFINDEX "ifindex" -#define NM_DHCP_CLIENT_INTERFACE "iface" -#define NM_DHCP_CLIENT_MULTI_IDX "multi-idx" -#define NM_DHCP_CLIENT_ROUTE_METRIC "route-metric" +#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_UUID "uuid" #define NM_DHCP_CLIENT_ROUTE_TABLE "route-table" -#define NM_DHCP_CLIENT_TIMEOUT "timeout" -#define NM_DHCP_CLIENT_UUID "uuid" +#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" @@ -65,14 +64,8 @@ struct _NMDhcpClientPrivate; typedef struct { GObject parent; struct _NMDhcpClientPrivate *_priv; - CList dhcp_client_lst; } NMDhcpClient; -typedef enum { - NM_DHCP_CLIENT_FLAGS_INFO_ONLY = (1LL << 0), - NM_DHCP_CLIENT_FLAGS_USE_FQDN = (1LL << 1), -} NMDhcpClientFlags; - typedef struct { GObjectClass parent; @@ -85,13 +78,14 @@ typedef struct { gboolean (*ip6_start) (NMDhcpClient *self, const char *anycast_addr, const struct in6_addr *ll_addr, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - GBytes *duid, + const GByteArray *duid, guint needed_prefixes); void (*stop) (NMDhcpClient *self, gboolean release, - GBytes *duid); + const GByteArray *duid); /** * get_duid: @@ -102,7 +96,7 @@ typedef struct { * representation of the DUID. If no DUID is found, %NULL should be * returned. */ - GBytes *(*get_duid) (NMDhcpClient *self); + GByteArray * (*get_duid) (NMDhcpClient *self); /* Signals */ void (*state_changed) (NMDhcpClient *self, @@ -125,9 +119,9 @@ int nm_dhcp_client_get_ifindex (NMDhcpClient *self); const char *nm_dhcp_client_get_uuid (NMDhcpClient *self); -GBytes *nm_dhcp_client_get_duid (NMDhcpClient *self); +const GByteArray *nm_dhcp_client_get_duid (NMDhcpClient *self); -GBytes *nm_dhcp_client_get_hw_addr (NMDhcpClient *self); +const GByteArray *nm_dhcp_client_get_hw_addr (NMDhcpClient *self); guint32 nm_dhcp_client_get_route_table (NMDhcpClient *self); @@ -139,20 +133,20 @@ GBytes *nm_dhcp_client_get_client_id (NMDhcpClient *self); const char *nm_dhcp_client_get_hostname (NMDhcpClient *self); -gboolean nm_dhcp_client_get_info_only (NMDhcpClient *self); - gboolean nm_dhcp_client_get_use_fqdn (NMDhcpClient *self); gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self, - GBytes *client_id, + const char *dhcp_client_id, const char *dhcp_anycast_addr, const char *hostname, + gboolean use_fqdn, const char *last_ip4_address); gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, const char *hostname, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes); @@ -185,6 +179,8 @@ void nm_dhcp_client_set_client_id_bin (NMDhcpClient *self, guint8 type, const guint8 *client_id, gsize len); +void nm_dhcp_client_set_client_id_str (NMDhcpClient *self, + const char *dhcp_client_id); /***************************************************************************** * Client data @@ -194,6 +190,13 @@ typedef struct { GType (*get_type)(void); const char *name; const char *(*get_path) (void); + GSList *(*get_lease_ip_configs) (struct _NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, + int ifindex, + const char *uuid, + guint32 route_table, + guint32 route_metric); } NMDhcpClientFactory; extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcanon; diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index 52923310..4df90d76 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -125,7 +125,7 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname, gboolean * as long as all the characters are printable. */ for (i = 1; (p[0] == 0) && i < l; i++) { - if (!g_ascii_isprint (p[i]) || p[i] == '\\' || p[i] == '"') + if (!g_ascii_isprint (p[i])) break; } @@ -138,9 +138,8 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname, gboolean g_string_append_printf (str, "%02x", (guint8) p[i]); } } else { - /* Printable; just add to the line with type 0 */ + /* Printable; just add to the line minus the 'type' */ g_string_append_c (str, '"'); - g_string_append (str, "\\x00"); g_string_append_len (str, p + 1, l - 1); g_string_append_c (str, '"'); } @@ -178,60 +177,31 @@ read_client_id (const char *str) { gs_free char *s = NULL; char *p; - int i = 0, j = 0; nm_assert (!strncmp (str, CLIENTID_TAG, NM_STRLEN (CLIENTID_TAG))); - str += NM_STRLEN (CLIENTID_TAG); - if (!g_ascii_isspace (*str)) - return NULL; + str += NM_STRLEN (CLIENTID_TAG); while (g_ascii_isspace (*str)) str++; if (*str == '"') { - /* Parse string literal with escape sequences */ s = g_strdup (str + 1); p = strrchr (s, '"'); if (p) *p = '\0'; else return NULL; + } else + s = g_strdup (str); - if (!s[0]) - return NULL; - - while (s[i]) { - if ( s[i] == '\\' - && s[i + 1] == 'x' - && g_ascii_isxdigit (s[i + 2]) - && g_ascii_isxdigit (s[i + 3])) { - s[j++] = (g_ascii_xdigit_value (s[i + 2]) << 4) - + g_ascii_xdigit_value (s[i + 3]); - i += 4; - continue; - } - if ( s[i] == '\\' - && s[i + 1] >= '0' && s[i + 1] <= '7' - && s[1 + 2] >= '0' && s[i + 2] <= '7' - && s[1 + 3] >= '0' && s[i + 3] <= '7') { - s[j++] = ((s[i + 1] - '0') << 6) - + ((s[i + 2] - '0') << 3) - + ( s[i + 3] - '0'); - i += 4; - continue; - } - s[j++] = s[i++]; - } - return g_bytes_new_take (g_steal_pointer (&s), j); - } - - /* Otherwise, try to read a hexadecimal sequence */ - s = g_strdup (str); g_strchomp (s); if (s[strlen (s) - 1] == ';') s[strlen (s) - 1] = '\0'; - return nm_utils_hexstr2bin (s); + if (!s[0]) + return NULL; + + return nm_dhcp_utils_client_id_string_to_bytes (s); } GBytes * @@ -309,7 +279,6 @@ nm_dhcp_dhclient_create_config (const char *interface, 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); - nm_assert (!out_new_client_id || !*out_new_client_id); new_contents = g_string_new (_("# Created by NetworkManager\n")); fqdn_opts = g_ptr_array_sized_new (5); @@ -363,8 +332,6 @@ nm_dhcp_dhclient_create_config (const char *interface, continue; /* Otherwise capture and return the existing client id */ - if (out_new_client_id) - g_clear_pointer (out_new_client_id, g_bytes_unref); NM_SET_OUT (out_new_client_id, read_client_id (p)); } @@ -477,20 +444,14 @@ nm_dhcp_dhclient_create_config (const char *interface, /* Roughly follow what dhclient's quotify_buf() and pretty_escape() functions do */ char * -nm_dhcp_dhclient_escape_duid (GBytes *duid) +nm_dhcp_dhclient_escape_duid (const GByteArray *duid) { char *escaped; - const guint8 *s, *s0; - gsize len; + const guint8 *s = duid->data; char *d; - g_return_val_if_fail (duid, NULL); - - s0 = g_bytes_get_data (duid, &len); - s = s0; - - d = escaped = g_malloc ((len * 4) + 1); - while (s < (s0 + len)) { + d = escaped = g_malloc0 ((duid->len * 4) + 1); + while (s < (duid->data + duid->len)) { if (!g_ascii_isprint (*s)) { *d++ = '\\'; *d++ = '0' + ((*s >> 6) & 0x7); @@ -504,7 +465,6 @@ nm_dhcp_dhclient_escape_duid (GBytes *duid) } else *d++ = *s++; } - *d++ = '\0'; return escaped; } @@ -516,7 +476,7 @@ isoctal (const guint8 *p) && p[2] >= '0' && p[2] <= '7'); } -GBytes * +GByteArray * nm_dhcp_dhclient_unescape_duid (const char *duid) { GByteArray *unescaped; @@ -547,7 +507,7 @@ nm_dhcp_dhclient_unescape_duid (const char *duid) g_byte_array_append (unescaped, &p[i], 1); } - return g_byte_array_free_to_bytes (unescaped); + return unescaped; error: g_byte_array_free (unescaped, TRUE); @@ -556,10 +516,10 @@ error: #define DUID_PREFIX "default-duid \"" -GBytes * +GByteArray * nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error) { - GBytes *duid = NULL; + GByteArray *duid = NULL; char *contents; char **line, **split, *p, *e; @@ -643,3 +603,259 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, g_string_free (s, TRUE); return success; } + +static void +add_lease_option (GHashTable *hash, char *line) +{ + char *spc; + size_t len; + + /* Find the space after "option" */ + spc = strchr (line, ' '); + if (!spc) + return; + + /* Find the option tag's data, which is after the second space */ + if (g_str_has_prefix (line, "option ")) { + while (g_ascii_isspace (*spc)) + spc++; + spc = strchr (spc + 1, ' '); + if (!spc) + return; + } + + /* Split the line at the space */ + *spc = '\0'; + spc++; + + /* Kill the ';' at the end of the line, if any */ + len = strlen (spc); + if (*(spc + len - 1) == ';') + *(spc + len - 1) = '\0'; + + /* Strip leading quote */ + while (g_ascii_isspace (*spc)) + spc++; + if (*spc == '"') + spc++; + + /* Strip trailing quote */ + len = strlen (spc); + if (len > 0 && spc[len - 1] == '"') + spc[len - 1] = '\0'; + + if (spc[0]) + g_hash_table_insert (hash, g_strdup (line), g_strdup (spc)); +} + +#define LEASE_INVALID G_MININT64 +static GTimeSpan +lease_validity_span (const char *str_expire, GDateTime *now) +{ + GDateTime *expire = NULL; + struct tm expire_tm; + GTimeSpan span; + + g_return_val_if_fail (now != NULL, LEASE_INVALID); + g_return_val_if_fail (str_expire != NULL, LEASE_INVALID); + + /* Skip initial number (day of week?) */ + if (!isdigit (*str_expire++)) + return LEASE_INVALID; + if (!isspace (*str_expire++)) + return LEASE_INVALID; + /* Read lease expiration (in UTC) */ + if (!strptime (str_expire, "%t%Y/%m/%d %H:%M:%S", &expire_tm)) + return LEASE_INVALID; + + expire = g_date_time_new_utc (expire_tm.tm_year + 1900, + expire_tm.tm_mon + 1, + expire_tm.tm_mday, + expire_tm.tm_hour, + expire_tm.tm_min, + expire_tm.tm_sec); + if (!expire) + return LEASE_INVALID; + + span = g_date_time_difference (expire, now); + g_date_time_unref (expire); + + /* GDateTime only supports a range of less then 10000 years, so span can + * not overflow or be equal to LEASE_INVALID */ + return span; +} + +/** + * 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 + * @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 @addr_family. + * + * 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 (NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, + int ifindex, + guint32 route_table, + guint32 route_metric, + const char *contents, + GDateTime *now) +{ + GSList *parsed = NULL, *iter, *leases = NULL; + char **line, **split = NULL; + GHashTable *hash = NULL; + 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) + return NULL; + + for (line = split; line && *line; line++) { + *line = g_strstrip (*line); + + if (*line[0] == '#') { + /* Comment */ + } else if (!strcmp (*line, "}")) { + /* Lease ends */ + parsed = g_slist_append (parsed, hash); + hash = NULL; + } else if (!strcmp (*line, "lease {")) { + /* Beginning of a new lease */ + if (hash) { + /* Ignore malformed lease that doesn't end before new one starts */ + g_hash_table_destroy (hash); + } + + 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); + } + g_strfreev (split); + + /* Check if the last lease in the file was properly ended */ + if (hash) { + /* Ignore malformed lease that doesn't end before new one starts */ + g_hash_table_destroy (hash); + hash = NULL; + } + + if (now) + g_date_time_ref (now); + else + now = g_date_time_new_now_utc (); + now_monotonic_ts = nm_utils_get_monotonic_timestamp_s (); + + for (iter = parsed; iter; iter = g_slist_next (iter)) { + NMIP4Config *ip4; + NMPlatformIP4Address address; + const char *value; + GTimeSpan expiry; + guint32 tmp, gw = 0; + + hash = iter->data; + + /* Make sure this lease is for the interface we want */ + value = g_hash_table_lookup (hash, "interface"); + if (!value || strcmp (value, iface)) + continue; + + value = g_hash_table_lookup (hash, "expire"); + if (!value) + continue; + expiry = lease_validity_span (value, now); + if (expiry == LEASE_INVALID) + continue; + + /* scale expiry to seconds (and CLAMP into the range of guint32) */ + expiry = CLAMP (expiry / G_TIME_SPAN_SECOND, 0, NM_PLATFORM_LIFETIME_PERMANENT-1); + if (expiry <= 0) { + /* the address is already expired. Don't even add it. */ + continue; + } + + memset (&address, 0, sizeof (address)); + + /* IP4 address */ + value = g_hash_table_lookup (hash, "fixed-address"); + if (!value) + continue; + if (!inet_pton (AF_INET, value, &address.address)) + continue; + address.peer_address = address.address; + + /* Gateway */ + value = g_hash_table_lookup (hash, "option routers"); + if (!value) + continue; + if (!inet_pton (AF_INET, value, &gw)) + continue; + + /* Netmask */ + value = g_hash_table_lookup (hash, "option subnet-mask"); + if (value && inet_pton (AF_INET, value, &tmp)) + address.plen = nm_utils_ip4_netmask_to_prefix (tmp); + + /* Get default netmask for the IP according to appropriate class. */ + if (!address.plen) + 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 (multi_idx, ifindex); + nm_ip4_config_add_address (ip4, &address); + + { + 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) { + char **dns, **dns_iter; + + dns = g_strsplit_set (value, ",", -1); + for (dns_iter = dns; dns_iter && *dns_iter; dns_iter++) { + if (inet_pton (AF_INET, *dns_iter, &tmp)) + nm_ip4_config_add_nameserver (ip4, tmp); + } + if (dns) + g_strfreev (dns); + } + + value = g_hash_table_lookup (hash, "option domain-name"); + if (value && value[0]) + nm_ip4_config_add_domain (ip4, value); + + /* FIXME: static routes */ + + leases = g_slist_append (leases, ip4); + } + + g_date_time_unref (now); + g_slist_free_full (parsed, (GDestroyNotify) g_hash_table_destroy); + return leases; +} + diff --git a/src/dhcp/nm-dhcp-dhclient-utils.h b/src/dhcp/nm-dhcp-dhclient-utils.h index fab9196a..94de1963 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.h +++ b/src/dhcp/nm-dhcp-dhclient-utils.h @@ -33,16 +33,25 @@ char *nm_dhcp_dhclient_create_config (const char *interface, const char *orig_contents, GBytes **out_new_client_id); -char *nm_dhcp_dhclient_escape_duid (GBytes *duid); +char *nm_dhcp_dhclient_escape_duid (const GByteArray *duid); -GBytes *nm_dhcp_dhclient_unescape_duid (const char *duid); +GByteArray *nm_dhcp_dhclient_unescape_duid (const char *duid); -GBytes *nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error); +GByteArray *nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error); gboolean nm_dhcp_dhclient_save_duid (const char *leasefile, const char *escaped_duid, GError **error); +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, + GDateTime *now); + GBytes *nm_dhcp_dhclient_get_client_id_from_config_file (const char *path); #endif /* __NETWORKMANAGER_DHCP_DHCLIENT_UTILS_H__ */ diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c index 738e9f91..74d920a8 100644 --- a/src/dhcp/nm-dhcp-dhclient.c +++ b/src/dhcp/nm-dhcp-dhclient.c @@ -158,6 +158,32 @@ get_dhclient_leasefile (int addr_family, return NULL; } +static GSList * +nm_dhcp_dhclient_get_lease_ip_configs (NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, + int ifindex, + const char *uuid, + guint32 route_table, + guint32 route_metric) +{ + gs_free char *contents = NULL; + gs_free char *leasefile = 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]) { + 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, @@ -312,7 +338,7 @@ create_dhclient_config (NMDhcpDhclient *self, static gboolean dhclient_start (NMDhcpClient *client, const char *mode_opt, - GBytes *duid, + const GByteArray *duid, gboolean release, pid_t *out_pid, int prefixes) @@ -413,19 +439,19 @@ dhclient_start (NMDhcpClient *client, while (prefixes--) g_ptr_array_add (argv, (gpointer) "-P"); } - g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */ + 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) "-pf"); /* Set pid file */ g_ptr_array_add (argv, (gpointer) pid_file); } - g_ptr_array_add (argv, (gpointer) "-lf"); /* Set lease file */ + g_ptr_array_add (argv, (gpointer) "-lf"); /* Set lease file */ g_ptr_array_add (argv, (gpointer) priv->lease_file); if (priv->conf_file) { - g_ptr_array_add (argv, (gpointer) "-cf"); /* Set interface config file */ + g_ptr_array_add (argv, (gpointer) "-cf"); /* Set interface config file */ g_ptr_array_add (argv, (gpointer) priv->conf_file); } @@ -492,10 +518,8 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last 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) { - nm_assert (!client_id); + if (new_client_id) nm_dhcp_client_set_client_id (client, new_client_id); - } success = dhclient_start (client, NULL, NULL, FALSE, NULL, 0); } else _LOGW ("error creating dhclient configuration file"); @@ -507,8 +531,9 @@ static gboolean ip6_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - GBytes *duid, + const GByteArray *duid, guint needed_prefixes) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); @@ -528,19 +553,16 @@ ip6_start (NMDhcpClient *client, return FALSE; } - return dhclient_start (client, - nm_dhcp_client_get_info_only (NM_DHCP_CLIENT (self)) - ? "-S" - : "-N", - duid, FALSE, NULL, needed_prefixes); + return dhclient_start (client, info_only ? "-S" : "-N", duid, FALSE, NULL, needed_prefixes); } static void -stop (NMDhcpClient *client, gboolean release, GBytes *duid) +stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); + /* Chain up to parent */ NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->stop (client, release, duid); if (priv->conf_file) @@ -581,12 +603,12 @@ state_changed (NMDhcpClient *client, nm_dhcp_client_set_client_id (client, client_id); } -static GBytes * +static GByteArray * get_duid (NMDhcpClient *client) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); - GBytes *duid = NULL; + GByteArray *duid = NULL; char *leasefile; GError *error = NULL; @@ -620,7 +642,7 @@ get_duid (NMDhcpClient *client) } /* return our DUID, otherwise let the parent class make a default DUID */ - return duid ?: NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->get_duid (client); + return duid ? duid : NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->get_duid (client); } /*****************************************************************************/ @@ -695,6 +717,7 @@ const NMDhcpClientFactory _nm_dhcp_client_factory_dhclient = { .name = "dhclient", .get_type = nm_dhcp_dhclient_get_type, .get_path = nm_dhcp_dhclient_get_path, + .get_lease_ip_configs = nm_dhcp_dhclient_get_lease_ip_configs, }; #endif /* WITH_DHCLIENT */ diff --git a/src/dhcp/nm-dhcp-dhcpcanon.c b/src/dhcp/nm-dhcp-dhcpcanon.c index 82b3db4f..d7ddd194 100644 --- a/src/dhcp/nm-dhcp-dhcpcanon.c +++ b/src/dhcp/nm-dhcp-dhcpcanon.c @@ -80,7 +80,7 @@ nm_dhcp_dhcpcanon_get_path (void) static gboolean dhcpcanon_start (NMDhcpClient *client, const char *mode_opt, - GBytes *duid, + const GByteArray *duid, gboolean release, pid_t *out_pid, int prefixes) @@ -118,16 +118,16 @@ dhcpcanon_start (NMDhcpClient *client, 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) "-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) "-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) "-cf"); /* Set interface config file */ g_ptr_array_add (argv, (gpointer) priv->conf_file); } @@ -179,8 +179,9 @@ static gboolean ip6_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - GBytes *duid, + const GByteArray *duid, guint needed_prefixes) { NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client); @@ -189,7 +190,7 @@ ip6_start (NMDhcpClient *client, return FALSE; } static void -stop (NMDhcpClient *client, gboolean release, GBytes *duid) +stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) { NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client); NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE (self); @@ -265,6 +266,7 @@ 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-dhcpcd.c b/src/dhcp/nm-dhcp-dhcpcd.c index c4bcb084..66a31acf 100644 --- a/src/dhcp/nm-dhcp-dhcpcd.c +++ b/src/dhcp/nm-dhcp-dhcpcd.c @@ -114,18 +114,18 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last argv = g_ptr_array_new (); g_ptr_array_add (argv, (gpointer) dhcpcd_path); - g_ptr_array_add (argv, (gpointer) "-B"); /* Don't background on lease (disable fork()) */ + g_ptr_array_add (argv, (gpointer) "-B"); /* Don't background on lease (disable fork()) */ - g_ptr_array_add (argv, (gpointer) "-K"); /* Disable built-in carrier detection */ + g_ptr_array_add (argv, (gpointer) "-K"); /* Disable built-in carrier detection */ - g_ptr_array_add (argv, (gpointer) "-L"); /* Disable built-in IPv4LL */ + g_ptr_array_add (argv, (gpointer) "-L"); /* Disable built-in IPv4LL */ /* --noarp. Don't request or claim the address by ARP; this also disables IPv4LL. */ g_ptr_array_add (argv, (gpointer) "-A"); - g_ptr_array_add (argv, (gpointer) "-G"); /* Let NM handle routing */ + g_ptr_array_add (argv, (gpointer) "-G"); /* Let NM handle routing */ - g_ptr_array_add (argv, (gpointer) "-c"); /* Set script file */ + g_ptr_array_add (argv, (gpointer) "-c"); /* Set script file */ g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path); #ifdef DHCPCD_SUPPORTS_IPV6 @@ -177,8 +177,9 @@ static gboolean ip6_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - GBytes *duid, + const GByteArray *duid, guint needed_prefixes) { NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client); @@ -188,11 +189,12 @@ ip6_start (NMDhcpClient *client, } static void -stop (NMDhcpClient *client, gboolean release, GBytes *duid) +stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) { NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client); NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (self); + /* Chain up to parent */ NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcd_parent_class)->stop (client, release, duid); if (priv->pid_file) { @@ -251,6 +253,7 @@ const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcd = { .name = "dhcpcd", .get_type = nm_dhcp_dhcpcd_get_type, .get_path = nm_dhcp_dhcpcd_get_path, + .get_lease_ip_configs = NULL, }; #endif /* WITH_DHCPCD */ diff --git a/src/dhcp/nm-dhcp-helper.c b/src/dhcp/nm-dhcp-helper.c index 8ea55061..f50c5cec 100644 --- a/src/dhcp/nm-dhcp-helper.c +++ b/src/dhcp/nm-dhcp-helper.c @@ -134,6 +134,8 @@ main (int argc, char *argv[]) guint try_count = 0; gint64 time_end; + nm_g_type_init (); + /* FIXME: g_dbus_connection_new_for_address_sync() tries to connect to the socket in * non-blocking mode, which can easily fail with EAGAIN, causing the creation of the * socket to fail with "Could not connect: Resource temporarily unavailable". diff --git a/src/dhcp/nm-dhcp-listener.c b/src/dhcp/nm-dhcp-listener.c index d7d38e54..1cce5a1c 100644 --- a/src/dhcp/nm-dhcp-listener.c +++ b/src/dhcp/nm-dhcp-listener.c @@ -33,7 +33,7 @@ #include "nm-dhcp-client.h" #include "nm-dhcp-manager.h" #include "nm-core-internal.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" #include "NetworkManagerUtils.h" #define PRIV_SOCK_PATH NMRUNDIR "/private-dhcp" @@ -60,7 +60,7 @@ const NMDhcpClientFactory *const _nm_dhcp_manager_factories[4] = { /*****************************************************************************/ typedef struct { - NMDBusManager * dbus_mgr; + NMBusManager * dbus_mgr; gulong new_conn_id; gulong dis_conn_id; GHashTable * connections; @@ -192,52 +192,70 @@ _method_call (GDBusConnection *connection, { NMDhcpListener *self = NM_DHCP_LISTENER (user_data); - if ( !nm_streq (interface_name, NM_DHCP_HELPER_SERVER_INTERFACE_NAME) - || !nm_streq (method_name, NM_DHCP_HELPER_SERVER_METHOD_NOTIFY)) { - g_dbus_method_invocation_return_error (invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_UNKNOWN_METHOD, - "Unknown method %s", - method_name); - return; - } + 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); + g_dbus_method_invocation_return_value (invocation, NULL); } -static GDBusInterfaceInfo *const interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO ( - NM_DHCP_HELPER_SERVER_INTERFACE_NAME, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_GDBUS_METHOD_INFO ( - NM_DHCP_HELPER_SERVER_METHOD_NOTIFY, - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("data", "a{sv}"), - ), - ), - ), -); - static guint _dbus_connection_register_object (NMDhcpListener *self, GDBusConnection *connection, GError **error) { - static const GDBusInterfaceVTable interface_vtable = { + static GDBusArgInfo arg_info_notify_in = { + .ref_count = -1, + .name = "data", + .signature = "a{sv}", + .annotations = NULL, + }; + static GDBusArgInfo *arg_infos_notify[] = { + &arg_info_notify_in, + NULL, + }; + static GDBusMethodInfo method_info_notify = { + .ref_count = -1, + .name = NM_DHCP_HELPER_SERVER_METHOD_NOTIFY, + .in_args = arg_infos_notify, + .out_args = NULL, + .annotations = NULL, + }; + static GDBusMethodInfo *method_infos[] = { + &method_info_notify, + NULL, + }; + static GDBusInterfaceInfo interface_info = { + .ref_count = -1, + .name = NM_DHCP_HELPER_SERVER_INTERFACE_NAME, + .methods = method_infos, + .signals = NULL, + .properties = NULL, + .annotations = NULL, + }; + + static GDBusInterfaceVTable interface_vtable = { .method_call = _method_call, + .get_property = NULL, + .set_property = NULL, }; return g_dbus_connection_register_object (connection, NM_DHCP_HELPER_SERVER_OBJECT_PATH, - interface_info, - NM_UNCONST_PTR (GDBusInterfaceVTable, &interface_vtable), + &interface_info, + &interface_vtable, self, NULL, error); } static void -new_connection_cb (NMDBusManager *mgr, +new_connection_cb (NMBusManager *mgr, GDBusConnection *connection, GDBusObjectManager *manager, NMDhcpListener *self) @@ -260,7 +278,7 @@ new_connection_cb (NMDBusManager *mgr, } static void -dis_connection_cb (NMDBusManager *mgr, +dis_connection_cb (NMBusManager *mgr, GDBusConnection *connection, NMDhcpListener *self) { @@ -282,18 +300,18 @@ nm_dhcp_listener_init (NMDhcpListener *self) NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (self); /* Maps GDBusConnection :: signal-id */ - priv->connections = g_hash_table_new (nm_direct_hash, NULL); + priv->connections = g_hash_table_new (NULL, NULL); - priv->dbus_mgr = nm_dbus_manager_get (); + priv->dbus_mgr = nm_bus_manager_get (); /* Register the socket our DHCP clients will return lease info on */ - nm_dbus_manager_private_server_register (priv->dbus_mgr, PRIV_SOCK_PATH, PRIV_SOCK_TAG); + nm_bus_manager_private_server_register (priv->dbus_mgr, PRIV_SOCK_PATH, PRIV_SOCK_TAG); priv->new_conn_id = g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG, + NM_BUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG, G_CALLBACK (new_connection_cb), self); priv->dis_conn_id = g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG, + NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG, G_CALLBACK (dis_connection_cb), self); } diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c index bf22872d..f5c7c84b 100644 --- a/src/dhcp/nm-dhcp-manager.c +++ b/src/dhcp/nm-dhcp-manager.c @@ -43,8 +43,8 @@ typedef struct { const NMDhcpClientFactory *client_factory; - char *default_hostname; - CList dhcp_client_lst_head; + GHashTable * clients; + char * default_hostname; } NMDhcpManagerPrivate; struct _NMDhcpManager { @@ -98,17 +98,21 @@ static NMDhcpClient * get_client_for_ifindex (NMDhcpManager *manager, int addr_family, int ifindex) { NMDhcpManagerPrivate *priv; - NMDhcpClient *client; + GHashTableIter iter; + gpointer value; g_return_val_if_fail (NM_IS_DHCP_MANAGER (manager), NULL); g_return_val_if_fail (ifindex > 0, NULL); priv = NM_DHCP_MANAGER_GET_PRIVATE (manager); - c_list_for_each_entry (client, &priv->dhcp_client_lst_head, dhcp_client_lst) { - if ( nm_dhcp_client_get_ifindex (client) == ifindex - && nm_dhcp_client_get_addr_family (client) == addr_family) - return client; + g_hash_table_iter_init (&iter, priv->clients); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + NMDhcpClient *candidate = NM_DHCP_CLIENT (value); + + if ( nm_dhcp_client_get_ifindex (candidate) == ifindex + && nm_dhcp_client_get_addr_family (candidate) == addr_family) + return candidate; } return NULL; @@ -125,19 +129,13 @@ static void remove_client (NMDhcpManager *self, NMDhcpClient *client) { g_signal_handlers_disconnect_by_func (client, client_state_changed, self); - c_list_unlink (&client->dhcp_client_lst); /* Stopping the client is left up to the controlling device * explicitly since we may want to quit NetworkManager but not terminate * the DHCP client. */ -} -static void -remove_client_unref (NMDhcpManager *self, NMDhcpClient *client) -{ - remove_client (self, client); - g_object_unref (client); + g_hash_table_remove (NM_DHCP_MANAGER_GET_PRIVATE (self)->clients, client); } static void @@ -149,7 +147,7 @@ client_state_changed (NMDhcpClient *client, NMDhcpManager *self) { if (state >= NM_DHCP_STATE_TIMEOUT) - remove_client_unref (self, client); + remove_client (self, client); } static NMDhcpClient * @@ -158,12 +156,12 @@ client_start (NMDhcpManager *self, NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - GBytes *hwaddr, + const GByteArray *hwaddr, const char *uuid, guint32 route_table, guint32 route_metric, const struct in6_addr *ipv6_ll_addr, - GBytes *dhcp_client_id, + const char *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, const char *hostname, @@ -181,21 +179,23 @@ client_start (NMDhcpManager *self, g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL); g_return_val_if_fail (ifindex > 0, NULL); g_return_val_if_fail (uuid != NULL, NULL); - g_return_val_if_fail (!dhcp_client_id || g_bytes_get_size (dhcp_client_id) >= 2, NULL); priv = NM_DHCP_MANAGER_GET_PRIVATE (self); + /* Ensure we have a usable DHCP client */ if (!priv->client_factory) return NULL; /* Kill any old client instance */ client = get_client_for_ifindex (self, addr_family, ifindex); if (client) { + g_object_ref (client); remove_client (self, client); nm_dhcp_client_stop (client, FALSE); g_object_unref (client); } + /* 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, @@ -206,26 +206,21 @@ client_start (NMDhcpManager *self, NM_DHCP_CLIENT_ROUTE_TABLE, (guint) route_table, NM_DHCP_CLIENT_ROUTE_METRIC, (guint) route_metric, NM_DHCP_CLIENT_TIMEOUT, (guint) timeout, - NM_DHCP_CLIENT_FLAGS, (guint) (0 - | (hostname_use_fqdn ? NM_DHCP_CLIENT_FLAGS_USE_FQDN : 0) - | (info_only ? NM_DHCP_CLIENT_FLAGS_INFO_ONLY : 0) - ), NULL); - nm_assert (client && c_list_is_empty (&client->dhcp_client_lst)); - c_list_link_tail (&priv->dhcp_client_lst_head, &client->dhcp_client_lst); + 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 (addr_family == AF_INET) - success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, last_ip4_address); + 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, privacy, needed_prefixes); + success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy, needed_prefixes); if (!success) { - remove_client_unref (self, client); - return NULL; + remove_client (self, client); + client = NULL; } - return g_object_ref (client); + return client; } /* Caller owns a reference to the NMDhcpClient on return */ @@ -234,14 +229,14 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self, NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - GBytes *hwaddr, + const GByteArray *hwaddr, const char *uuid, guint32 route_table, guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, const char *dhcp_fqdn, - GBytes *dhcp_client_id, + const char *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, const char *last_ip_address) @@ -290,7 +285,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - GBytes *hwaddr, + const GByteArray *hwaddr, const struct in6_addr *ll_addr, const char *uuid, guint32 route_table, @@ -333,6 +328,31 @@ nm_dhcp_manager_set_default_hostname (NMDhcpManager *manager, const char *hostna priv->default_hostname = g_strdup (hostname); } +GSList * +nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self, + NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, + int ifindex, + const char *uuid, + guint32 route_table, + guint32 route_metric) +{ + NMDhcpManagerPrivate *priv; + + g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL); + 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 (multi_idx, addr_family, iface, ifindex, uuid, route_table, route_metric); + return NULL; +} + const char * nm_dhcp_manager_get_config (NMDhcpManager *self) { @@ -358,8 +378,6 @@ nm_dhcp_manager_init (NMDhcpManager *self) int i; const NMDhcpClientFactory *client_factory = NULL; - c_list_init (&priv->dhcp_client_lst_head); - for (i = 0; i < G_N_ELEMENTS (_nm_dhcp_manager_factories); i++) { const NMDhcpClientFactory *f = _nm_dhcp_manager_factories[i]; @@ -411,21 +429,38 @@ nm_dhcp_manager_init (NMDhcpManager *self) nm_log_info (LOGD_DHCP, "dhcp-init: Using DHCP client '%s'", client_factory->name); priv->client_factory = client_factory; + priv->clients = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify) g_object_unref); } static void dispose (GObject *object) { - NMDhcpManager *self = NM_DHCP_MANAGER (object); - NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self); - NMDhcpClient *client, *client_safe; - - c_list_for_each_entry_safe (client, client_safe, &priv->dhcp_client_lst_head, dhcp_client_lst) - remove_client_unref (self, client); + NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE ((NMDhcpManager *) object); + GList *values, *iter; + + if (priv->clients) { + values = g_hash_table_get_values (priv->clients); + for (iter = values; iter; iter = g_list_next (iter)) + remove_client (NM_DHCP_MANAGER (object), NM_DHCP_CLIENT (iter->data)); + g_list_free (values); + } G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE ((NMDhcpManager *) object); + + g_free (priv->default_hostname); + + if (priv->clients) + g_hash_table_destroy (priv->clients); - nm_clear_g_free (&priv->default_hostname); + G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->finalize (object); } static void @@ -433,5 +468,6 @@ nm_dhcp_manager_class_init (NMDhcpManagerClass *manager_class) { GObjectClass *object_class = G_OBJECT_CLASS (manager_class); + object_class->finalize = finalize; object_class->dispose = dispose; } diff --git a/src/dhcp/nm-dhcp-manager.h b/src/dhcp/nm-dhcp-manager.h index f8a7e31d..078117ff 100644 --- a/src/dhcp/nm-dhcp-manager.h +++ b/src/dhcp/nm-dhcp-manager.h @@ -49,14 +49,14 @@ NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *manager, struct _NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - GBytes *hwaddr, + const GByteArray *hwaddr, const char *uuid, guint32 route_table, guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, const char *dhcp_fqdn, - GBytes *dhcp_client_id, + const char *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, const char *last_ip_address); @@ -65,7 +65,7 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, struct _NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - GBytes *hwaddr, + const GByteArray *hwaddr, const struct in6_addr *ll_addr, const char *uuid, guint32 route_table, @@ -78,6 +78,15 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, NMSettingIP6ConfigPrivacy privacy, 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, + guint32 route_table, + guint32 route_metric); + /* For testing only */ extern const char* nm_dhcp_helper_path; diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c index 4f37f069..f79b7cb1 100644 --- a/src/dhcp/nm-dhcp-systemd.c +++ b/src/dhcp/nm-dhcp-systemd.c @@ -29,7 +29,6 @@ #include #include "nm-utils/nm-dedup-multi.h" -#include "nm-utils/unaligned.h" #include "nm-utils.h" #include "nm-dhcp-utils.h" @@ -61,7 +60,8 @@ typedef struct { guint request_count; - bool privacy:1; + gboolean privacy; + gboolean info_only; } NMDhcpSystemdPrivate; struct _NMDhcpSystemd { @@ -451,6 +451,36 @@ get_leasefile_path (int addr_family, const char *iface, const char *uuid) iface); } +static GSList * +nm_dhcp_systemd_get_lease_ip_configs (NMDedupMultiIndex *multi_idx, + int addr_family, + const char *iface, + int ifindex, + const char *uuid, + guint32 route_table, + guint32 route_metric) +{ + GSList *leases = NULL; + gs_free char *path = NULL; + sd_dhcp_lease *lease = NULL; + NMIP4Config *ip4_config; + int r; + + if (addr_family != AF_INET) + return NULL; + + path = get_leasefile_path (addr_family, iface, uuid); + r = dhcp_lease_load (&lease, path); + if (r == 0 && lease) { + 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); + } + + return leases; +} + /*****************************************************************************/ static void @@ -554,16 +584,14 @@ dhcp_event_cb (sd_dhcp_client *client, int event, gpointer user_data) } static guint16 -get_arp_type (GBytes *hwaddr) +get_arp_type (const GByteArray *hwaddr) { - switch (g_bytes_get_size (hwaddr)) { - case ETH_ALEN: + if (hwaddr->len == ETH_ALEN) return ARPHRD_ETHER; - case INFINIBAND_ALEN: + else if (hwaddr->len == INFINIBAND_ALEN) return ARPHRD_INFINIBAND; - default: + else return ARPHRD_NONE; - } } static gboolean @@ -572,7 +600,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); const char *iface = nm_dhcp_client_get_iface (client); - GBytes *hwaddr; + const GByteArray *hwaddr; sd_dhcp_lease *lease = NULL; GBytes *override_client_id; const uint8_t *client_id = NULL; @@ -581,6 +609,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last const char *hostname; int r, i; gboolean success = FALSE; + guint16 arp_type; g_assert (priv->client4 == NULL); g_assert (priv->client6 == NULL); @@ -604,14 +633,16 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last hwaddr = nm_dhcp_client_get_hw_addr (client); if (hwaddr) { - const uint8_t *data; - gsize len; + arp_type= get_arp_type (hwaddr); + if (arp_type == ARPHRD_NONE) { + _LOGW ("failed to determine ARP type"); + goto error; + } - data = g_bytes_get_data (hwaddr, &len); r = sd_dhcp_client_set_mac (priv->client4, - data, - len, - get_arp_type (hwaddr)); + hwaddr->data, + hwaddr->len, + arp_type); if (r < 0) { _LOGW ("failed to set MAC address (%d)", r); goto error; @@ -630,6 +661,12 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last goto error; } + r = sd_dhcp_client_set_request_broadcast (priv->client4, true); + if (r < 0) { + _LOGW ("failed to enable broadcast mode (%d)", r); + goto error; + } + dhcp_lease_load (&lease, priv->lease_file); if (last_ip4_address) @@ -817,7 +854,7 @@ bound6_handle (NMDhcpSystemd *self) lease, options, TRUE, - nm_dhcp_client_get_info_only (NM_DHCP_CLIENT (self)), + priv->info_only, &error); if (ip6_config) { @@ -863,29 +900,24 @@ static gboolean ip6_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, + gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - GBytes *duid, + const GByteArray *duid, guint needed_prefixes) { NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); const char *iface = nm_dhcp_client_get_iface (client); - GBytes *hwaddr; - const char *hostname; + const GByteArray *hwaddr; int r, i; - const guint8 *duid_arr; - gsize duid_len; g_assert (priv->client4 == NULL); g_assert (priv->client6 == NULL); g_return_val_if_fail (duid != NULL, FALSE); - duid_arr = g_bytes_get_data (duid, &duid_len); - if (!duid_arr || duid_len < 2) - g_return_val_if_reached (FALSE); - g_free (priv->lease_file); 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); if (r < 0) { @@ -900,13 +932,16 @@ ip6_start (NMDhcpClient *client, _LOGT ("dhcp-client6: set %p", priv->client6); - if (nm_dhcp_client_get_info_only (client)) - sd_dhcp6_client_set_information_request (priv->client6, 1); + if (info_only) + sd_dhcp6_client_set_information_request (priv->client6, 1); + /* NM stores the entire DUID which includes the uint16 "type", while systemd + * wants the type passed separately from the following data. + */ r = sd_dhcp6_client_set_duid (priv->client6, - unaligned_read_be16 (&duid_arr[0]), - &duid_arr[2], - duid_len - 2); + ntohs (((const guint16 *) duid->data)[0]), + duid->data + 2, + duid->len - 2); if (r < 0) { _LOGW ("failed to set DUID (%d)", r); return FALSE; @@ -920,13 +955,9 @@ ip6_start (NMDhcpClient *client, hwaddr = nm_dhcp_client_get_hw_addr (client); if (hwaddr) { - const uint8_t *data; - gsize len; - - data = g_bytes_get_data (hwaddr, &len); r = sd_dhcp6_client_set_mac (priv->client6, - data, - len, + hwaddr->data, + hwaddr->len, get_arp_type (hwaddr)); if (r < 0) { _LOGW ("failed to set MAC address (%d)", r); @@ -958,13 +989,6 @@ ip6_start (NMDhcpClient *client, goto error; } - hostname = nm_dhcp_client_get_hostname (client); - r = sd_dhcp6_client_set_fqdn (priv->client6, hostname); - if (r < 0) { - _LOGW ("failed to set DHCP hostname to '%s' (%d)", hostname, r); - goto error; - } - r = sd_dhcp6_client_start (priv->client6); if (r < 0) { _LOGW ("failed to start client (%d)", r); @@ -982,14 +1006,12 @@ error: } static void -stop (NMDhcpClient *client, gboolean release, GBytes *duid) +stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) { NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); int r = 0; - NM_DHCP_CLIENT_CLASS (nm_dhcp_systemd_parent_class)->stop (client, release, duid); - _LOGT ("dhcp-client%d: stop %p", priv->client4 ? '4' : '6', priv->client4 ? (gpointer) priv->client4 : (gpointer) priv->client6); @@ -1052,4 +1074,5 @@ const NMDhcpClientFactory _nm_dhcp_client_factory_internal = { .name = "internal", .get_type = nm_dhcp_systemd_get_type, .get_path = NULL, + .get_lease_ip_configs = nm_dhcp_systemd_get_lease_ip_configs, }; diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c index 9185a135..50ca2abe 100644 --- a/src/dhcp/nm-dhcp-utils.c +++ b/src/dhcp/nm-dhcp-utils.c @@ -721,15 +721,11 @@ error: } char * -nm_dhcp_utils_duid_to_string (GBytes *duid) +nm_dhcp_utils_duid_to_string (const GByteArray *duid) { - gconstpointer data; - gsize len; - g_return_val_if_fail (duid != NULL, NULL); - data = g_bytes_get_data (duid, &len); - return _nm_utils_bin2str (data, len, FALSE); + return _nm_utils_bin2str (duid->data, duid->len, FALSE); } /** diff --git a/src/dhcp/nm-dhcp-utils.h b/src/dhcp/nm-dhcp-utils.h index 5c127bd1..32140f48 100644 --- a/src/dhcp/nm-dhcp-utils.h +++ b/src/dhcp/nm-dhcp-utils.h @@ -39,7 +39,7 @@ NMIP6Config *nm_dhcp_utils_ip6_config_from_options (struct _NMDedupMultiIndex *m NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options); -char *nm_dhcp_utils_duid_to_string (GBytes *duid); +char * nm_dhcp_utils_duid_to_string (const GByteArray *duid); GBytes * nm_dhcp_utils_client_id_string_to_bytes (const char *client_id); diff --git a/src/dhcp/tests/leases/basic.leases b/src/dhcp/tests/leases/basic.leases new file mode 100644 index 00000000..703d9247 --- /dev/null +++ b/src/dhcp/tests/leases/basic.leases @@ -0,0 +1,31 @@ +lease { + interface "wlan0"; + fixed-address 192.168.1.180; + option subnet-mask 255.255.255.0; + option routers 192.168.1.1; + option dhcp-lease-time 600; + option dhcp-message-type 5; + option domain-name-servers 192.168.1.1; + option dhcp-server-identifier 192.168.1.1; + option broadcast-address 192.168.1.255; + renew 5 2013/11/01 19:56:15; + rebind 5 2013/11/01 20:00:44; + expire 5 2013/11/01 20:01:59; +} +lease { + interface "wlan0"; + fixed-address 10.77.52.141; + option subnet-mask 255.0.0.0; + option dhcp-lease-time 1200; + option routers 10.77.52.254; + option dhcp-message-type 5; + option dhcp-server-identifier 10.77.52.254; + option domain-name-servers 8.8.8.8,8.8.4.4; + option dhcp-renewal-time 600; + option dhcp-rebinding-time 1050; + option domain-name "morriesguest.local"; + renew 5 2013/11/01 20:01:08; + rebind 5 2013/11/01 20:05:00; + expire 5 2013/11/01 20:06:15; +} + diff --git a/src/dhcp/tests/leases/malformed1.leases b/src/dhcp/tests/leases/malformed1.leases new file mode 100644 index 00000000..401d982a --- /dev/null +++ b/src/dhcp/tests/leases/malformed1.leases @@ -0,0 +1,15 @@ +# missing fixed-address option +lease { + interface "wlan0"; + option subnet-mask 255.255.255.0; + option routers 192.168.1.1; + option dhcp-lease-time 600; + option dhcp-message-type 5; + option domain-name-servers 192.168.1.1; + option dhcp-server-identifier 192.168.1.1; + option broadcast-address 192.168.1.255; + renew 5 2013/11/01 19:56:15; + rebind 5 2013/11/01 20:00:44; + expire 5 2013/11/01 20:01:59; +} + diff --git a/src/dhcp/tests/leases/malformed2.leases b/src/dhcp/tests/leases/malformed2.leases new file mode 100644 index 00000000..adf5f6de --- /dev/null +++ b/src/dhcp/tests/leases/malformed2.leases @@ -0,0 +1,15 @@ +# missing routers option +lease { + interface "wlan0"; + fixed-address 192.168.1.180; + option subnet-mask 255.255.255.0; + option dhcp-lease-time 600; + option dhcp-message-type 5; + option domain-name-servers 192.168.1.1; + option dhcp-server-identifier 192.168.1.1; + option broadcast-address 192.168.1.255; + renew 5 2013/11/01 19:56:15; + rebind 5 2013/11/01 20:00:44; + expire 5 2013/11/01 20:01:59; +} + diff --git a/src/dhcp/tests/leases/malformed3.leases b/src/dhcp/tests/leases/malformed3.leases new file mode 100644 index 00000000..a2afc8b6 --- /dev/null +++ b/src/dhcp/tests/leases/malformed3.leases @@ -0,0 +1,15 @@ +# missing expire time +lease { + interface "wlan0"; + fixed-address 192.168.1.180; + option subnet-mask 255.255.255.0; + option routers 192.168.1.1; + option dhcp-lease-time 600; + option dhcp-message-type 5; + option domain-name-servers 192.168.1.1; + option dhcp-server-identifier 192.168.1.1; + option broadcast-address 192.168.1.255; + renew 5 2013/11/01 19:56:15; + rebind 5 2013/11/01 20:00:44; +} + diff --git a/src/dhcp/tests/meson.build b/src/dhcp/tests/meson.build deleted file mode 100644 index 32badae8..00000000 --- a/src/dhcp/tests/meson.build +++ /dev/null @@ -1,19 +0,0 @@ -test_units = [ - 'test-dhcp-dhclient', - 'test-dhcp-utils' -] - -foreach test_unit: test_units - exe = executable( - test_unit, - test_unit + '.c', - dependencies: test_nm_dep, - c_args: '-DTESTDIR="@0@"'.format(meson.current_source_dir()) - ) - - test( - 'dhcp/' + test_unit, - test_script, - args: test_args + [exe.full_path()] - ) -endforeach diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c index 25af51a1..f2e1f321 100644 --- a/src/dhcp/tests/test-dhcp-dhclient.c +++ b/src/dhcp/tests/test-dhcp-dhclient.c @@ -36,6 +36,12 @@ #include "nm-test-utils-core.h" +#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, @@ -148,7 +154,7 @@ test_override_client_id (void) static const char *quote_client_id_expected = \ "# Created by NetworkManager\n" "\n" - "send dhcp-client-identifier \"\\x00abcd\"; # added by NetworkManager\n" + "send dhcp-client-identifier \"1234\"; # added by NetworkManager\n" "\n" "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" @@ -166,65 +172,7 @@ test_quote_client_id (void) { test_config (NULL, quote_client_id_expected, AF_INET, NULL, 0, FALSE, - "abcd", - NULL, - "eth0", - NULL); -} - -/*****************************************************************************/ - -static const char *quote_client_id_expected_2 = \ - "# Created by NetworkManager\n" - "\n" - "send dhcp-client-identifier 00:61:5c:62:63; # added by NetworkManager\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "\n"; - -static void -test_quote_client_id_2 (void) -{ - test_config (NULL, quote_client_id_expected_2, - AF_INET, NULL, 0, FALSE, - "a\\bc", - NULL, - "eth0", - NULL); -} - -/*****************************************************************************/ - -static const char *hex_zero_client_id_expected = \ - "# Created by NetworkManager\n" - "\n" - "send dhcp-client-identifier 00:11:22:33; # added by NetworkManager\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "\n"; - -static void -test_hex_zero_client_id (void) -{ - test_config (NULL, hex_zero_client_id_expected, - AF_INET, NULL, 0, FALSE, - "00:11:22:33", + "1234", NULL, "eth0", NULL); @@ -235,7 +183,7 @@ test_hex_zero_client_id (void) static const char *ascii_client_id_expected = \ "# Created by NetworkManager\n" "\n" - "send dhcp-client-identifier \"\\x00qb:cd:ef:12:34:56\"; # added by NetworkManager\n" + "send dhcp-client-identifier \"qb:cd:ef:12:34:56\"; # added by NetworkManager\n" "\n" "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" @@ -291,13 +239,13 @@ test_hex_single_client_id (void) /*****************************************************************************/ static const char *existing_hex_client_id_orig = \ - "send dhcp-client-identifier 10:30:04:20:7A:08;\n"; + "send dhcp-client-identifier 00:30:04:20:7A:08;\n"; static const char *existing_hex_client_id_expected = \ "# Created by NetworkManager\n" "# Merged from /path/to/dhclient.conf\n" "\n" - "send dhcp-client-identifier 10:30:04:20:7A:08;\n" + "send dhcp-client-identifier 00:30:04:20:7A:08;\n" "\n" "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" @@ -314,7 +262,7 @@ static void test_existing_hex_client_id (void) { gs_unref_bytes GBytes *new_client_id = NULL; - const guint8 bytes[] = { 0x10, 0x30, 0x04, 0x20, 0x7A, 0x08 }; + const guint8 bytes[] = { 0x00, 0x30, 0x04,0x20, 0x7A, 0x08 }; new_client_id = g_bytes_new (bytes, sizeof (bytes)); test_config (existing_hex_client_id_orig, existing_hex_client_id_expected, @@ -327,52 +275,16 @@ test_existing_hex_client_id (void) /*****************************************************************************/ -static const char *existing_escaped_client_id_orig = \ - "send dhcp-client-identifier \"\\044test\\xfe\";\n"; - -static const char *existing_escaped_client_id_expected = \ - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n" - "send dhcp-client-identifier \"\\044test\\xfe\";\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "\n"; - -static void -test_existing_escaped_client_id (void) -{ - gs_unref_bytes GBytes *new_client_id = NULL; - - new_client_id = g_bytes_new ("$test\xfe", 6); - test_config (existing_escaped_client_id_orig, existing_escaped_client_id_expected, - AF_INET, NULL, 0, FALSE, - NULL, - new_client_id, - "eth0", - NULL); -} - -/*****************************************************************************/ - #define EACID "qb:cd:ef:12:34:56" static const char *existing_ascii_client_id_orig = \ - "send dhcp-client-identifier \"\\x00" EACID "\";\n"; + "send dhcp-client-identifier \"" EACID "\";\n"; static const char *existing_ascii_client_id_expected = \ "# Created by NetworkManager\n" "# Merged from /path/to/dhclient.conf\n" "\n" - "send dhcp-client-identifier \"\\x00" EACID "\";\n" + "send dhcp-client-identifier \"" EACID "\";\n" "\n" "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" @@ -673,26 +585,23 @@ test_existing_multiline_alsoreq (void) static void test_one_duid (const char *escaped, const guint8 *unescaped, guint len) { - GBytes *t; + GByteArray *t; char *w; - gsize t_len; - gconstpointer t_arr; t = nm_dhcp_dhclient_unescape_duid (escaped); g_assert (t); - t_arr = g_bytes_get_data (t, &t_len); - g_assert (t_arr); - g_assert_cmpint (t_len, ==, len); - g_assert_cmpint (memcmp (t_arr, unescaped, len), ==, 0); - g_bytes_unref (t); + g_assert_cmpint (t->len, ==, len); + g_assert_cmpint (memcmp (t->data, unescaped, len), ==, 0); + g_byte_array_free (t, TRUE); - t = g_bytes_new_static (unescaped, len); + t = g_byte_array_sized_new (len); + g_byte_array_append (t, unescaped, len); w = nm_dhcp_dhclient_escape_duid (t); g_assert (w); g_assert_cmpint (strlen (escaped), ==, strlen (w)); g_assert_cmpstr (escaped, ==, w); - g_bytes_unref (t); + g_byte_array_free (t, TRUE); g_free (w); } @@ -731,23 +640,22 @@ test_read_duid_from_leasefile (void) { const guint8 expected[] = { 0x00, 0x01, 0x00, 0x01, 0x18, 0x79, 0xa6, 0x13, 0x60, 0x67, 0x20, 0xec, 0x4c, 0x70 }; - gs_unref_bytes GBytes *duid = NULL; + GByteArray *duid; GError *error = NULL; - gconstpointer duid_arr; - gsize duid_len; duid = nm_dhcp_dhclient_read_duid (TESTDIR "/test-dhclient-duid.leases", &error); g_assert_no_error (error); g_assert (duid); - duid_arr = g_bytes_get_data (duid, &duid_len); - g_assert_cmpint (duid_len, ==, sizeof (expected)); - g_assert_cmpint (memcmp (duid_arr, expected, duid_len), ==, 0); + g_assert_cmpint (duid->len, ==, sizeof (expected)); + g_assert_cmpint (memcmp (duid->data, expected, duid->len), ==, 0); + + g_byte_array_free (duid, TRUE); } static void test_read_commented_duid_from_leasefile (void) { - GBytes *duid; + GByteArray *duid; GError *error = NULL; duid = nm_dhcp_dhclient_read_duid (TESTDIR "/test-dhclient-commented-duid.leases", &error); @@ -846,12 +754,12 @@ test_write_existing_commented_duid (void) static const char *interface1_orig = \ "interface \"eth0\" {\n" - "\talso request my-option;\n" - "\tinitial-delay 5;\n" + " also request my-option;\n" + " initial-delay 5;\n" "}\n" "interface \"eth1\" {\n" - "\talso request another-option;\n" - "\tinitial-delay 0;\n" + " also request another-option;\n" + " initial-delay 0;\n" "}\n" "\n" "also request yet-another-option;\n"; @@ -890,12 +798,12 @@ test_interface1 (void) static const char *interface2_orig = \ "interface eth0 {\n" - "\talso request my-option;\n" - "\tinitial-delay 5;\n" + " also request my-option;\n" + " initial-delay 5;\n" " }\n" "interface eth1 {\n" - "\tinitial-delay 0;\n" - "\trequest another-option;\n" + " initial-delay 0;\n" + " request another-option;\n" " } \n" "\n" "also request yet-another-option;\n"; @@ -936,12 +844,12 @@ test_config_req_intf (void) { static const char *const orig = \ "request subnet-mask, broadcast-address, routers,\n" - "\trfc3442-classless-static-routes,\n" - "\tinterface-mtu, host-name, domain-name, domain-search,\n" - "\tdomain-name-servers, nis-domain, nis-servers,\n" - "\tnds-context, nds-servers, nds-tree-name,\n" - "\tnetbios-name-servers, netbios-dd-server,\n" - "\tnetbios-node-type, netbios-scope, ntp-servers;\n" + " rfc3442-classless-static-routes,\n" + " interface-mtu, host-name, domain-name, domain-search,\n" + " domain-name-servers, nis-domain, nis-servers,\n" + " nds-context, nds-servers, nds-tree-name,\n" + " netbios-name-servers, netbios-dd-server,\n" + " netbios-node-type, netbios-scope, ntp-servers;\n" ""; static const char *const expected = \ "# Created by NetworkManager\n" @@ -987,6 +895,133 @@ 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; + const char *path = TESTDIR "/leases/basic.leases"; + GSList *leases; + GDateTime *now; + NMIP4Config *config; + const NMPlatformIP4Address *addr; + guint32 expected_addr; + + success = g_file_get_contents (path, &contents, NULL, &error); + g_assert_no_error (error); + g_assert (success); + + /* 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 (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now); + g_assert_cmpint (g_slist_length (leases), ==, 2); + + /* IP4Config #1 */ + config = g_slist_nth_data (leases, 0); + g_assert (NM_IS_IP4_CONFIG (config)); + + /* Address */ + g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1); + 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 */ + 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); + 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); + + /* IP4Config #2 */ + config = g_slist_nth_data (leases, 1); + g_assert (NM_IS_IP4_CONFIG (config)); + + /* Address */ + g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1); + 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 */ + 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); + expected_addr = nmtst_inet4_from_string ("8.8.8.8"); + g_assert_cmpint (nm_ip4_config_get_nameserver (config, 0), ==, 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 */ + g_assert_cmpint (nm_ip4_config_get_num_domains (config), ==, 1); + g_assert_cmpstr (nm_ip4_config_get_domain (config, 0), ==, "morriesguest.local"); + + g_slist_free_full (leases, g_object_unref); + g_date_time_unref (now); + g_free (contents); +} + +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; + const char *path = TESTDIR "/leases/basic.leases"; + GSList *leases; + GDateTime *now; + + success = g_file_get_contents (path, &contents, NULL, &error); + g_assert_no_error (error); + g_assert (success); + + /* 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 (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now); + g_assert (leases == NULL); + + g_date_time_unref (now); + g_free (contents); +} + +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; + GSList *leases; + GDateTime *now; + + success = g_file_get_contents ((const char *) user_data, &contents, NULL, &error); + g_assert_no_error (error); + g_assert (success); + + /* 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 (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now); + g_assert (leases == NULL); + + g_date_time_unref (now); + g_free (contents); +} + +/*****************************************************************************/ + NMTST_DEFINE (); int @@ -996,13 +1031,10 @@ main (int argc, char **argv) g_test_add_func ("/dhcp/dhclient/orig_missing", test_orig_missing); g_test_add_func ("/dhcp/dhclient/override_client_id", test_override_client_id); - g_test_add_func ("/dhcp/dhclient/quote_client_id/1", test_quote_client_id); - g_test_add_func ("/dhcp/dhclient/quote_client_id/2", test_quote_client_id_2); - g_test_add_func ("/dhcp/dhclient/hex_zero_client_id", test_hex_zero_client_id); + g_test_add_func ("/dhcp/dhclient/quote_client_id", test_quote_client_id); g_test_add_func ("/dhcp/dhclient/ascii_client_id", test_ascii_client_id); g_test_add_func ("/dhcp/dhclient/hex_single_client_id", test_hex_single_client_id); g_test_add_func ("/dhcp/dhclient/existing-hex-client-id", test_existing_hex_client_id); - g_test_add_func ("/dhcp/dhclient/existing-client-id", test_existing_escaped_client_id); g_test_add_func ("/dhcp/dhclient/existing-ascii-client-id", test_existing_ascii_client_id); g_test_add_func ("/dhcp/dhclient/fqdn", test_fqdn); g_test_add_func ("/dhcp/dhclient/fqdn_options_override", test_fqdn_options_override); @@ -1024,6 +1056,18 @@ main (int argc, char **argv) g_test_add_func ("/dhcp/dhclient/write_existing_duid", test_write_existing_duid); g_test_add_func ("/dhcp/dhclient/write_existing_commented_duid", test_write_existing_commented_duid); + g_test_add_func ("/dhcp/dhclient/leases/ip4-config/basic", test_read_lease_ip4_config_basic); + g_test_add_func ("/dhcp/dhclient/leases/ip4-config/expired", test_read_lease_ip4_config_expired); + g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-address", + TESTDIR "/leases/malformed1.leases", + test_read_lease_ip4_config_expect_failure); + g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-gateway", + TESTDIR "/leases/malformed2.leases", + test_read_lease_ip4_config_expect_failure); + g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-expire", + TESTDIR "/leases/malformed3.leases", + test_read_lease_ip4_config_expect_failure); + return g_test_run (); } diff --git a/src/dhcp/tests/test-dhcp-utils.c b/src/dhcp/tests/test-dhcp-utils.c index 617a3c6c..72f31191 100644 --- a/src/dhcp/tests/test-dhcp-utils.c +++ b/src/dhcp/tests/test-dhcp-utils.c @@ -349,7 +349,8 @@ test_dhclient_invalid_classless_routes_1 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -379,7 +380,8 @@ test_dhcpcd_invalid_classless_routes_1 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -411,7 +413,8 @@ test_dhclient_invalid_classless_routes_2 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -443,7 +446,8 @@ test_dhcpcd_invalid_classless_routes_2 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -475,7 +479,8 @@ test_dhclient_invalid_classless_routes_3 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -502,7 +507,8 @@ test_dhcpcd_invalid_classless_routes_3 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*DHCP provided invalid classless static route*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*DHCP provided invalid classless static route*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -609,7 +615,8 @@ test_invalid_escaped_domain_searches (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - NMTST_EXPECT_NM_WARN ("*invalid domain search*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*invalid domain search*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); -- cgit 1.3.0-6-gf8a5 From 04bc9e1cd3544445d883ad29ea108c1645c8e7b7 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Mon, 4 Jun 2018 00:07:45 +0200 Subject: New upstream version 1.11.4 --- src/dhcp/meson.build | 22 +++ src/dhcp/nm-dhcp-client.c | 202 +++++++++---------- src/dhcp/nm-dhcp-client.h | 52 +++-- src/dhcp/nm-dhcp-dhclient-utils.c | 331 ++++++-------------------------- src/dhcp/nm-dhcp-dhclient-utils.h | 15 +- src/dhcp/nm-dhcp-dhclient.c | 191 ++++++++---------- src/dhcp/nm-dhcp-dhcpcanon.c | 16 +- src/dhcp/nm-dhcp-dhcpcd.c | 17 +- src/dhcp/nm-dhcp-helper.c | 2 - src/dhcp/nm-dhcp-listener.c | 86 ++++----- src/dhcp/nm-dhcp-manager.c | 120 ++++-------- src/dhcp/nm-dhcp-manager.h | 15 +- src/dhcp/nm-dhcp-systemd.c | 120 +++++------- src/dhcp/nm-dhcp-utils.c | 8 +- src/dhcp/nm-dhcp-utils.h | 2 +- src/dhcp/tests/leases/basic.leases | 31 --- src/dhcp/tests/leases/malformed1.leases | 15 -- src/dhcp/tests/leases/malformed2.leases | 15 -- src/dhcp/tests/leases/malformed3.leases | 15 -- src/dhcp/tests/meson.build | 19 ++ src/dhcp/tests/test-dhcp-dhclient.c | 322 ++++++++++++++----------------- src/dhcp/tests/test-dhcp-utils.c | 21 +- 22 files changed, 594 insertions(+), 1043 deletions(-) create mode 100644 src/dhcp/meson.build delete mode 100644 src/dhcp/tests/leases/basic.leases delete mode 100644 src/dhcp/tests/leases/malformed1.leases delete mode 100644 src/dhcp/tests/leases/malformed2.leases delete mode 100644 src/dhcp/tests/leases/malformed3.leases create mode 100644 src/dhcp/tests/meson.build (limited to 'src/dhcp') diff --git a/src/dhcp/meson.build b/src/dhcp/meson.build new file mode 100644 index 00000000..289a16ca --- /dev/null +++ b/src/dhcp/meson.build @@ -0,0 +1,22 @@ +name = 'nm-dhcp-helper' + +cflags = [ + '-DG_LOG_DOMAIN="@0@"'.format(name), + '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_GLIB', + '-DNMRUNDIR="@0@"'.format(nm_pkgrundir), +] + +executable( + name, + name + '.c', + dependencies: nm_core_dep, + c_args: cflags, + link_args: ldflags_linker_script_binary, + link_depends: linker_script_binary, + install: true, + install_dir: nm_libexecdir +) + +if enable_tests + subdir('tests') +endif diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index ea3938d6..ba517606 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -52,23 +52,24 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; NM_GOBJECT_PROPERTIES_DEFINE_BASE ( - PROP_MULTI_IDX, PROP_ADDR_FAMILY, + PROP_FLAGS, + PROP_HWADDR, PROP_IFACE, PROP_IFINDEX, - PROP_HWADDR, - PROP_UUID, - PROP_ROUTE_TABLE, + PROP_MULTI_IDX, PROP_ROUTE_METRIC, + PROP_ROUTE_TABLE, PROP_TIMEOUT, + PROP_UUID, ); typedef struct _NMDhcpClientPrivate { NMDedupMultiIndex *multi_idx; char * iface; - GByteArray * hwaddr; + GBytes * hwaddr; char * uuid; - GByteArray * duid; + GBytes * duid; GBytes * client_id; char * hostname; pid_t pid; @@ -138,7 +139,7 @@ nm_dhcp_client_get_uuid (NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE (self)->uuid; } -const GByteArray * +GBytes * nm_dhcp_client_get_duid (NMDhcpClient *self) { g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); @@ -146,7 +147,7 @@ nm_dhcp_client_get_duid (NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE (self)->duid; } -const GByteArray * +GBytes * nm_dhcp_client_get_hw_addr (NMDhcpClient *self) { g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); @@ -238,20 +239,6 @@ nm_dhcp_client_set_client_id_bin (NMDhcpClient *self, _set_client_id (self, b, TRUE); } -void -nm_dhcp_client_set_client_id_str (NMDhcpClient *self, - const char *dhcp_client_id) -{ - g_return_if_fail (NM_IS_DHCP_CLIENT (self)); - g_return_if_fail (!dhcp_client_id || dhcp_client_id[0]); - - _set_client_id (self, - dhcp_client_id - ? nm_dhcp_utils_client_id_string_to_bytes (dhcp_client_id) - : NULL, - TRUE); -} - const char * nm_dhcp_client_get_hostname (NMDhcpClient *self) { @@ -260,6 +247,14 @@ nm_dhcp_client_get_hostname (NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE (self)->hostname; } +gboolean +nm_dhcp_client_get_info_only (NMDhcpClient *self) +{ + g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); + + return NM_DHCP_CLIENT_GET_PRIVATE (self)->info_only; +} + gboolean nm_dhcp_client_get_use_fqdn (NMDhcpClient *self) { @@ -339,13 +334,13 @@ nm_dhcp_client_stop_pid (pid_t pid, const char *iface) g_return_if_fail (pid > 1); - nm_utils_kill_child_sync (pid, SIGTERM, LOGD_DHCP, name ? name : "dhcp-client", NULL, + nm_utils_kill_child_sync (pid, SIGTERM, LOGD_DHCP, name ?: "dhcp-client", NULL, 1000 / 2, 1000 / 20); g_free (name); } static void -stop (NMDhcpClient *self, gboolean release, const GByteArray *duid) +stop (NMDhcpClient *self, gboolean release, GBytes *duid) { NMDhcpClientPrivate *priv; @@ -359,32 +354,30 @@ stop (NMDhcpClient *self, gboolean release, const GByteArray *duid) nm_dhcp_client_stop_pid (priv->pid, priv->iface); } priv->pid = -1; - priv->info_only = FALSE; } void nm_dhcp_client_set_state (NMDhcpClient *self, NMDhcpState new_state, - GObject *ip_config, + NMIPConfig *ip_config, GHashTable *options) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); gs_free char *event_id = NULL; + if (new_state == NM_DHCP_STATE_BOUND) { + g_return_if_fail (NM_IS_IP_CONFIG (ip_config, priv->addr_family)); + g_return_if_fail (options); + } else { + g_return_if_fail (!ip_config); + g_return_if_fail (!options); + } + if (new_state >= NM_DHCP_STATE_BOUND) timeout_cleanup (self); if (new_state >= NM_DHCP_STATE_TIMEOUT) watch_cleanup (self); - if (new_state == NM_DHCP_STATE_BOUND) { - 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); - g_assert (options == NULL); - } - /* The client may send same-state transitions for RENEW/REBIND events and * the lease may have changed, so handle same-state transitions for the * BOUND state. Ignore same-state transitions for other events since @@ -492,10 +485,9 @@ nm_dhcp_client_watch_child (NMDhcpClient *self, pid_t pid) gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self, - const char *dhcp_client_id, + GBytes *client_id, const char *dhcp_anycast_addr, const char *hostname, - gboolean use_fqdn, const char *last_ip4_address) { NMDhcpClientPrivate *priv; @@ -512,19 +504,19 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self, else _LOGI ("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout); - nm_dhcp_client_set_client_id_str (self, dhcp_client_id); + nm_dhcp_client_set_client_id (self, client_id); g_clear_pointer (&priv->hostname, g_free); priv->hostname = g_strdup (hostname); - priv->use_fqdn = use_fqdn; return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_anycast_addr, last_ip4_address); } -static GByteArray * +static GBytes * generate_duid_from_machine_id (void) { - GByteArray *duid; + const int DUID_SIZE = 18; + guint8 *duid_buffer; GChecksum *sum; guint8 buffer[32]; /* SHA256 digest size */ gsize sumlen = sizeof (buffer); @@ -532,6 +524,7 @@ generate_duid_from_machine_id (void) uuid_t uuid; gs_free char *machine_id_s = NULL; gs_free char *str = NULL; + GBytes *duid; machine_id_s = nm_utils_machine_id_read (); if (nm_utils_machine_id_parse (machine_id_s, uuid)) { @@ -554,36 +547,31 @@ generate_duid_from_machine_id (void) * u16: type (DUID-UUID = 4) * u8[16]: UUID bytes */ - duid = g_byte_array_sized_new (18); - g_byte_array_append (duid, (guint8 *) &duid_type, sizeof (duid_type)); + duid_buffer = g_malloc (DUID_SIZE); + + G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2); + memcpy (&duid_buffer[0], &duid_type, 2); /* Since SHA256 is 256 bits, but UUID is 128 bits, we just take the first * 128 bits of the SHA256 as the DUID-UUID. */ - g_byte_array_append (duid, buffer, 16); + memcpy (&duid_buffer[2], buffer, 16); + duid = g_bytes_new_take (duid_buffer, DUID_SIZE); nm_log_dbg (LOGD_DHCP, "dhcp: generated DUID %s", (str = nm_dhcp_utils_duid_to_string (duid))); return duid; } -static GByteArray * +static GBytes * get_duid (NMDhcpClient *self) { - static GByteArray *duid = NULL; - GByteArray *copy = NULL; + static GBytes *duid = NULL; - if (G_UNLIKELY (duid == NULL)) { + if (G_UNLIKELY (!duid)) duid = generate_duid_from_machine_id (); - g_assert (duid); - } - if (G_LIKELY (duid)) { - copy = g_byte_array_sized_new (duid->len); - g_byte_array_append (copy, duid->data, duid->len); - } - - return copy; + return g_bytes_ref (duid); } gboolean @@ -591,7 +579,6 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, const char *hostname, - gboolean info_only, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes) { @@ -616,8 +603,6 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, g_clear_pointer (&priv->hostname, g_free); priv->hostname = g_strdup (hostname); - priv->info_only = info_only; - if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) _LOGI ("activation: beginning transaction (no timeout)"); else @@ -626,7 +611,6 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, return NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self, dhcp_anycast_addr, ll_addr, - info_only, privacy, priv->duid, needed_prefixes); @@ -675,8 +659,10 @@ nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name) out: if (remove (pid_file) == -1) { - nm_log_dbg (LOGD_DHCP, "dhcp: could not remove pid file \"%s\": %d (%s)", - pid_file, errno, g_strerror (errno)); + int errsv = errno; + + nm_log_dbg (LOGD_DHCP, "dhcp: could not remove pid file \"%s\": %s (%d)", + pid_file, g_strerror (errsv), errsv); } } @@ -751,14 +737,6 @@ maybe_add_option (NMDhcpClient *self, GVariant *value) { char *str_value = NULL; - const char **p; - static const char *ignored_keys[] = { - "interface", - "pid", - "reason", - "dhcp_message_type", - NULL - }; g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_BYTESTRING)); @@ -766,10 +744,11 @@ maybe_add_option (NMDhcpClient *self, return; /* Filter out stuff that's not actually new DHCP options */ - for (p = ignored_keys; *p; p++) { - if (!strcmp (*p, key)) - return; - } + if (NM_IN_STRSET (key, "interface", + "pid", + "reason", + "dhcp_message_type")) + return; if (g_str_has_prefix (key, NEW_TAG)) key += NM_STRLEN (NEW_TAG); @@ -792,8 +771,8 @@ nm_dhcp_client_handle_event (gpointer unused, NMDhcpClientPrivate *priv; guint32 old_state; guint32 new_state; - GHashTable *str_options = NULL; - GObject *ip_config = NULL; + gs_unref_hashtable GHashTable *str_options = NULL; + gs_unref_object NMIPConfig *ip_config = NULL; NMPlatformIP6Address prefix = { 0, }; g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); @@ -811,8 +790,8 @@ nm_dhcp_client_handle_event (gpointer unused, old_state = priv->state; new_state = reason_to_state (self, priv->iface, reason); - _LOGD ("DHCP reason '%s' -> state '%s'", - reason, state_to_string (new_state)); + _LOGD ("DHCP state '%s' -> '%s' (reason: '%s')", + state_to_string (old_state), state_to_string (new_state), reason); if (new_state == NM_DHCP_STATE_BOUND) { GVariantIter iter; @@ -837,24 +816,24 @@ 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 (g_hash_table_size (str_options) > 0) { 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->route_table, - priv->route_metric); + ip_config = NM_IP_CONFIG_CAST (nm_dhcp_utils_ip4_config_from_options (nm_dhcp_client_get_multi_idx (self), + priv->ifindex, + priv->iface, + str_options, + priv->route_table, + priv->route_metric)); } else { 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->info_only); + ip_config = NM_IP_CONFIG_CAST (nm_dhcp_utils_ip6_config_from_options (nm_dhcp_client_get_multi_idx (self), + priv->ifindex, + priv->iface, + str_options, + priv->info_only)); } - } + } else + g_warn_if_reached (); } if (!IN6_IS_ADDR_UNSPECIFIED (&prefix.address)) { @@ -866,7 +845,8 @@ nm_dhcp_client_handle_event (gpointer unused, &prefix); } else { /* Fail if no valid IP config was received */ - if (new_state == NM_DHCP_STATE_BOUND && ip_config == NULL) { + if ( new_state == NM_DHCP_STATE_BOUND + && !ip_config) { _LOGW ("client bound but IP config not received"); new_state = NM_DHCP_STATE_FAIL; g_clear_pointer (&str_options, g_hash_table_unref); @@ -875,10 +855,6 @@ nm_dhcp_client_handle_event (gpointer unused, nm_dhcp_client_set_state (self, new_state, ip_config, str_options); } - if (str_options) - g_hash_table_destroy (str_options); - g_clear_object (&ip_config); - return TRUE; } @@ -923,8 +899,16 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE ((NMDhcpClient *) object); + guint flags; switch (prop_id) { + case PROP_FLAGS: + /* construct-only */ + flags = g_value_get_uint (value); + nm_assert ((flags & ~((guint) (NM_DHCP_CLIENT_FLAGS_INFO_ONLY | NM_DHCP_CLIENT_FLAGS_USE_FQDN))) == 0); + priv->info_only = NM_FLAGS_HAS (flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY); + priv->use_fqdn = NM_FLAGS_HAS (flags, NM_DHCP_CLIENT_FLAGS_USE_FQDN); + break; case PROP_MULTI_IDX: /* construct-only */ priv->multi_idx = g_value_get_pointer (value); @@ -983,6 +967,8 @@ nm_dhcp_client_init (NMDhcpClient *self) priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_DHCP_CLIENT, NMDhcpClientPrivate); self->_priv = priv; + c_list_init (&self->dhcp_client_lst); + priv->pid = -1; } @@ -997,6 +983,8 @@ dispose (GObject *object) * the DHCP client. */ + nm_assert (c_list_is_empty (&self->dhcp_client_lst)); + watch_cleanup (self); timeout_cleanup (self); @@ -1004,16 +992,8 @@ dispose (GObject *object) g_clear_pointer (&priv->hostname, g_free); g_clear_pointer (&priv->uuid, g_free); g_clear_pointer (&priv->client_id, g_bytes_unref); - - if (priv->hwaddr) { - g_byte_array_free (priv->hwaddr, TRUE); - priv->hwaddr = NULL; - } - - if (priv->duid) { - g_byte_array_free (priv->duid, TRUE); - priv->duid = NULL; - } + g_clear_pointer (&priv->hwaddr, g_bytes_unref); + g_clear_pointer (&priv->duid, g_bytes_unref); G_OBJECT_CLASS (nm_dhcp_client_parent_class)->dispose (object); @@ -1054,7 +1034,7 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class) obj_properties[PROP_HWADDR] = g_param_spec_boxed (NM_DHCP_CLIENT_HWADDR, "", "", - G_TYPE_BYTE_ARRAY, + G_TYPE_BYTES, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); @@ -1088,6 +1068,12 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_FLAGS] = + g_param_spec_uint (NM_DHCP_CLIENT_FLAGS, "", "", + 0, G_MAXUINT32, 0, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[SIGNAL_STATE_CHANGED] = diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h index 2c634168..111b063b 100644 --- a/src/dhcp/nm-dhcp-client.h +++ b/src/dhcp/nm-dhcp-client.h @@ -34,20 +34,20 @@ #define NM_IS_DHCP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP_CLIENT)) #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_UUID "uuid" -#define NM_DHCP_CLIENT_ROUTE_TABLE "route-table" +#define NM_DHCP_CLIENT_ADDR_FAMILY "addr-family" +#define NM_DHCP_CLIENT_FLAGS "flags" +#define NM_DHCP_CLIENT_HWADDR "hwaddr" +#define NM_DHCP_CLIENT_IFINDEX "ifindex" +#define NM_DHCP_CLIENT_INTERFACE "iface" +#define NM_DHCP_CLIENT_MULTI_IDX "multi-idx" #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_ROUTE_TABLE "route-table" +#define NM_DHCP_CLIENT_TIMEOUT "timeout" +#define NM_DHCP_CLIENT_UUID "uuid" #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 */ @@ -64,8 +64,14 @@ struct _NMDhcpClientPrivate; typedef struct { GObject parent; struct _NMDhcpClientPrivate *_priv; + CList dhcp_client_lst; } NMDhcpClient; +typedef enum { + NM_DHCP_CLIENT_FLAGS_INFO_ONLY = (1LL << 0), + NM_DHCP_CLIENT_FLAGS_USE_FQDN = (1LL << 1), +} NMDhcpClientFlags; + typedef struct { GObjectClass parent; @@ -78,14 +84,13 @@ typedef struct { gboolean (*ip6_start) (NMDhcpClient *self, const char *anycast_addr, const struct in6_addr *ll_addr, - gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - const GByteArray *duid, + GBytes *duid, guint needed_prefixes); void (*stop) (NMDhcpClient *self, gboolean release, - const GByteArray *duid); + GBytes *duid); /** * get_duid: @@ -96,7 +101,7 @@ typedef struct { * representation of the DUID. If no DUID is found, %NULL should be * returned. */ - GByteArray * (*get_duid) (NMDhcpClient *self); + GBytes *(*get_duid) (NMDhcpClient *self); /* Signals */ void (*state_changed) (NMDhcpClient *self, @@ -119,9 +124,9 @@ int nm_dhcp_client_get_ifindex (NMDhcpClient *self); const char *nm_dhcp_client_get_uuid (NMDhcpClient *self); -const GByteArray *nm_dhcp_client_get_duid (NMDhcpClient *self); +GBytes *nm_dhcp_client_get_duid (NMDhcpClient *self); -const GByteArray *nm_dhcp_client_get_hw_addr (NMDhcpClient *self); +GBytes *nm_dhcp_client_get_hw_addr (NMDhcpClient *self); guint32 nm_dhcp_client_get_route_table (NMDhcpClient *self); @@ -133,20 +138,20 @@ GBytes *nm_dhcp_client_get_client_id (NMDhcpClient *self); const char *nm_dhcp_client_get_hostname (NMDhcpClient *self); +gboolean nm_dhcp_client_get_info_only (NMDhcpClient *self); + gboolean nm_dhcp_client_get_use_fqdn (NMDhcpClient *self); gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self, - const char *dhcp_client_id, + GBytes *client_id, const char *dhcp_anycast_addr, const char *hostname, - gboolean use_fqdn, const char *last_ip4_address); gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, const char *hostname, - gboolean info_only, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes); @@ -163,7 +168,7 @@ void nm_dhcp_client_watch_child (NMDhcpClient *self, pid_t pid); void nm_dhcp_client_set_state (NMDhcpClient *self, NMDhcpState new_state, - GObject *ip_config, /* NMIP4Config or NMIP6Config */ + NMIPConfig *ip_config, GHashTable *options); /* str:str hash */ gboolean nm_dhcp_client_handle_event (gpointer unused, @@ -179,8 +184,6 @@ void nm_dhcp_client_set_client_id_bin (NMDhcpClient *self, guint8 type, const guint8 *client_id, gsize len); -void nm_dhcp_client_set_client_id_str (NMDhcpClient *self, - const char *dhcp_client_id); /***************************************************************************** * Client data @@ -190,13 +193,6 @@ typedef struct { GType (*get_type)(void); const char *name; const char *(*get_path) (void); - GSList *(*get_lease_ip_configs) (struct _NMDedupMultiIndex *multi_idx, - int addr_family, - const char *iface, - int ifindex, - const char *uuid, - guint32 route_table, - guint32 route_metric); } NMDhcpClientFactory; extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcanon; diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index 4df90d76..16a76d23 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -95,7 +95,6 @@ grab_request_options (GPtrArray *store, const char* line) return end; } - static void add_hostname4 (GString *str, const char *hostname, gboolean use_fqdn) { @@ -125,7 +124,7 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname, gboolean * as long as all the characters are printable. */ for (i = 1; (p[0] == 0) && i < l; i++) { - if (!g_ascii_isprint (p[i])) + if (!g_ascii_isprint (p[i]) || p[i] == '\\' || p[i] == '"') break; } @@ -138,8 +137,9 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname, gboolean g_string_append_printf (str, "%02x", (guint8) p[i]); } } else { - /* Printable; just add to the line minus the 'type' */ + /* Printable; just add to the line with type 0 */ g_string_append_c (str, '"'); + g_string_append (str, "\\x00"); g_string_append_len (str, p + 1, l - 1); g_string_append_c (str, '"'); } @@ -177,31 +177,60 @@ read_client_id (const char *str) { gs_free char *s = NULL; char *p; + int i = 0, j = 0; nm_assert (!strncmp (str, CLIENTID_TAG, NM_STRLEN (CLIENTID_TAG))); - str += NM_STRLEN (CLIENTID_TAG); + + if (!g_ascii_isspace (*str)) + return NULL; while (g_ascii_isspace (*str)) str++; if (*str == '"') { + /* Parse string literal with escape sequences */ s = g_strdup (str + 1); p = strrchr (s, '"'); if (p) *p = '\0'; else return NULL; - } else - s = g_strdup (str); + if (!s[0]) + return NULL; + + while (s[i]) { + if ( s[i] == '\\' + && s[i + 1] == 'x' + && g_ascii_isxdigit (s[i + 2]) + && g_ascii_isxdigit (s[i + 3])) { + s[j++] = (g_ascii_xdigit_value (s[i + 2]) << 4) + + g_ascii_xdigit_value (s[i + 3]); + i += 4; + continue; + } + if ( s[i] == '\\' + && s[i + 1] >= '0' && s[i + 1] <= '7' + && s[1 + 2] >= '0' && s[i + 2] <= '7' + && s[1 + 3] >= '0' && s[i + 3] <= '7') { + s[j++] = ((s[i + 1] - '0') << 6) + + ((s[i + 2] - '0') << 3) + + ( s[i + 3] - '0'); + i += 4; + continue; + } + s[j++] = s[i++]; + } + return g_bytes_new_take (g_steal_pointer (&s), j); + } + + /* Otherwise, try to read a hexadecimal sequence */ + s = g_strdup (str); g_strchomp (s); if (s[strlen (s) - 1] == ';') s[strlen (s) - 1] = '\0'; - if (!s[0]) - return NULL; - - return nm_dhcp_utils_client_id_string_to_bytes (s); + return nm_utils_hexstr2bin (s); } GBytes * @@ -279,6 +308,7 @@ nm_dhcp_dhclient_create_config (const char *interface, 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); + nm_assert (!out_new_client_id || !*out_new_client_id); new_contents = g_string_new (_("# Created by NetworkManager\n")); fqdn_opts = g_ptr_array_sized_new (5); @@ -332,6 +362,8 @@ nm_dhcp_dhclient_create_config (const char *interface, continue; /* Otherwise capture and return the existing client id */ + if (out_new_client_id) + g_clear_pointer (out_new_client_id, g_bytes_unref); NM_SET_OUT (out_new_client_id, read_client_id (p)); } @@ -444,14 +476,20 @@ nm_dhcp_dhclient_create_config (const char *interface, /* Roughly follow what dhclient's quotify_buf() and pretty_escape() functions do */ char * -nm_dhcp_dhclient_escape_duid (const GByteArray *duid) +nm_dhcp_dhclient_escape_duid (GBytes *duid) { char *escaped; - const guint8 *s = duid->data; + const guint8 *s, *s0; + gsize len; char *d; - d = escaped = g_malloc0 ((duid->len * 4) + 1); - while (s < (duid->data + duid->len)) { + g_return_val_if_fail (duid, NULL); + + s0 = g_bytes_get_data (duid, &len); + s = s0; + + d = escaped = g_malloc ((len * 4) + 1); + while (s < (s0 + len)) { if (!g_ascii_isprint (*s)) { *d++ = '\\'; *d++ = '0' + ((*s >> 6) & 0x7); @@ -465,6 +503,7 @@ nm_dhcp_dhclient_escape_duid (const GByteArray *duid) } else *d++ = *s++; } + *d++ = '\0'; return escaped; } @@ -476,7 +515,7 @@ isoctal (const guint8 *p) && p[2] >= '0' && p[2] <= '7'); } -GByteArray * +GBytes * nm_dhcp_dhclient_unescape_duid (const char *duid) { GByteArray *unescaped; @@ -507,7 +546,7 @@ nm_dhcp_dhclient_unescape_duid (const char *duid) g_byte_array_append (unescaped, &p[i], 1); } - return unescaped; + return g_byte_array_free_to_bytes (unescaped); error: g_byte_array_free (unescaped, TRUE); @@ -516,10 +555,10 @@ error: #define DUID_PREFIX "default-duid \"" -GByteArray * +GBytes * nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error) { - GByteArray *duid = NULL; + GBytes *duid = NULL; char *contents; char **line, **split, *p, *e; @@ -603,259 +642,3 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, g_string_free (s, TRUE); return success; } - -static void -add_lease_option (GHashTable *hash, char *line) -{ - char *spc; - size_t len; - - /* Find the space after "option" */ - spc = strchr (line, ' '); - if (!spc) - return; - - /* Find the option tag's data, which is after the second space */ - if (g_str_has_prefix (line, "option ")) { - while (g_ascii_isspace (*spc)) - spc++; - spc = strchr (spc + 1, ' '); - if (!spc) - return; - } - - /* Split the line at the space */ - *spc = '\0'; - spc++; - - /* Kill the ';' at the end of the line, if any */ - len = strlen (spc); - if (*(spc + len - 1) == ';') - *(spc + len - 1) = '\0'; - - /* Strip leading quote */ - while (g_ascii_isspace (*spc)) - spc++; - if (*spc == '"') - spc++; - - /* Strip trailing quote */ - len = strlen (spc); - if (len > 0 && spc[len - 1] == '"') - spc[len - 1] = '\0'; - - if (spc[0]) - g_hash_table_insert (hash, g_strdup (line), g_strdup (spc)); -} - -#define LEASE_INVALID G_MININT64 -static GTimeSpan -lease_validity_span (const char *str_expire, GDateTime *now) -{ - GDateTime *expire = NULL; - struct tm expire_tm; - GTimeSpan span; - - g_return_val_if_fail (now != NULL, LEASE_INVALID); - g_return_val_if_fail (str_expire != NULL, LEASE_INVALID); - - /* Skip initial number (day of week?) */ - if (!isdigit (*str_expire++)) - return LEASE_INVALID; - if (!isspace (*str_expire++)) - return LEASE_INVALID; - /* Read lease expiration (in UTC) */ - if (!strptime (str_expire, "%t%Y/%m/%d %H:%M:%S", &expire_tm)) - return LEASE_INVALID; - - expire = g_date_time_new_utc (expire_tm.tm_year + 1900, - expire_tm.tm_mon + 1, - expire_tm.tm_mday, - expire_tm.tm_hour, - expire_tm.tm_min, - expire_tm.tm_sec); - if (!expire) - return LEASE_INVALID; - - span = g_date_time_difference (expire, now); - g_date_time_unref (expire); - - /* GDateTime only supports a range of less then 10000 years, so span can - * not overflow or be equal to LEASE_INVALID */ - return span; -} - -/** - * 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 - * @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 @addr_family. - * - * 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 (NMDedupMultiIndex *multi_idx, - int addr_family, - const char *iface, - int ifindex, - guint32 route_table, - guint32 route_metric, - const char *contents, - GDateTime *now) -{ - GSList *parsed = NULL, *iter, *leases = NULL; - char **line, **split = NULL; - GHashTable *hash = NULL; - 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) - return NULL; - - for (line = split; line && *line; line++) { - *line = g_strstrip (*line); - - if (*line[0] == '#') { - /* Comment */ - } else if (!strcmp (*line, "}")) { - /* Lease ends */ - parsed = g_slist_append (parsed, hash); - hash = NULL; - } else if (!strcmp (*line, "lease {")) { - /* Beginning of a new lease */ - if (hash) { - /* Ignore malformed lease that doesn't end before new one starts */ - g_hash_table_destroy (hash); - } - - 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); - } - g_strfreev (split); - - /* Check if the last lease in the file was properly ended */ - if (hash) { - /* Ignore malformed lease that doesn't end before new one starts */ - g_hash_table_destroy (hash); - hash = NULL; - } - - if (now) - g_date_time_ref (now); - else - now = g_date_time_new_now_utc (); - now_monotonic_ts = nm_utils_get_monotonic_timestamp_s (); - - for (iter = parsed; iter; iter = g_slist_next (iter)) { - NMIP4Config *ip4; - NMPlatformIP4Address address; - const char *value; - GTimeSpan expiry; - guint32 tmp, gw = 0; - - hash = iter->data; - - /* Make sure this lease is for the interface we want */ - value = g_hash_table_lookup (hash, "interface"); - if (!value || strcmp (value, iface)) - continue; - - value = g_hash_table_lookup (hash, "expire"); - if (!value) - continue; - expiry = lease_validity_span (value, now); - if (expiry == LEASE_INVALID) - continue; - - /* scale expiry to seconds (and CLAMP into the range of guint32) */ - expiry = CLAMP (expiry / G_TIME_SPAN_SECOND, 0, NM_PLATFORM_LIFETIME_PERMANENT-1); - if (expiry <= 0) { - /* the address is already expired. Don't even add it. */ - continue; - } - - memset (&address, 0, sizeof (address)); - - /* IP4 address */ - value = g_hash_table_lookup (hash, "fixed-address"); - if (!value) - continue; - if (!inet_pton (AF_INET, value, &address.address)) - continue; - address.peer_address = address.address; - - /* Gateway */ - value = g_hash_table_lookup (hash, "option routers"); - if (!value) - continue; - if (!inet_pton (AF_INET, value, &gw)) - continue; - - /* Netmask */ - value = g_hash_table_lookup (hash, "option subnet-mask"); - if (value && inet_pton (AF_INET, value, &tmp)) - address.plen = nm_utils_ip4_netmask_to_prefix (tmp); - - /* Get default netmask for the IP according to appropriate class. */ - if (!address.plen) - 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 (multi_idx, ifindex); - nm_ip4_config_add_address (ip4, &address); - - { - 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) { - char **dns, **dns_iter; - - dns = g_strsplit_set (value, ",", -1); - for (dns_iter = dns; dns_iter && *dns_iter; dns_iter++) { - if (inet_pton (AF_INET, *dns_iter, &tmp)) - nm_ip4_config_add_nameserver (ip4, tmp); - } - if (dns) - g_strfreev (dns); - } - - value = g_hash_table_lookup (hash, "option domain-name"); - if (value && value[0]) - nm_ip4_config_add_domain (ip4, value); - - /* FIXME: static routes */ - - leases = g_slist_append (leases, ip4); - } - - g_date_time_unref (now); - g_slist_free_full (parsed, (GDestroyNotify) g_hash_table_destroy); - return leases; -} - diff --git a/src/dhcp/nm-dhcp-dhclient-utils.h b/src/dhcp/nm-dhcp-dhclient-utils.h index 94de1963..fab9196a 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.h +++ b/src/dhcp/nm-dhcp-dhclient-utils.h @@ -33,25 +33,16 @@ char *nm_dhcp_dhclient_create_config (const char *interface, const char *orig_contents, GBytes **out_new_client_id); -char *nm_dhcp_dhclient_escape_duid (const GByteArray *duid); +char *nm_dhcp_dhclient_escape_duid (GBytes *duid); -GByteArray *nm_dhcp_dhclient_unescape_duid (const char *duid); +GBytes *nm_dhcp_dhclient_unescape_duid (const char *duid); -GByteArray *nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error); +GBytes *nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error); gboolean nm_dhcp_dhclient_save_duid (const char *leasefile, const char *escaped_duid, GError **error); -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, - GDateTime *now); - GBytes *nm_dhcp_dhclient_get_client_id_from_config_file (const char *path); #endif /* __NETWORKMANAGER_DHCP_DHCLIENT_UTILS_H__ */ diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c index 74d920a8..93306ddd 100644 --- a/src/dhcp/nm-dhcp-dhclient.c +++ b/src/dhcp/nm-dhcp-dhclient.c @@ -127,11 +127,13 @@ get_dhclient_leasefile (int addr_family, _addr_family_to_path_part (addr_family), uuid, iface); - if (out_preferred_path) - *out_preferred_path = g_strdup (path); - if (g_file_test (path, G_FILE_TEST_EXISTS)) + if (g_file_test (path, G_FILE_TEST_EXISTS)) { + NM_SET_OUT (out_preferred_path, g_strdup (path)); return path; + } + + NM_SET_OUT (out_preferred_path, g_steal_pointer (&path)); /* If the leasefile we're looking for doesn't exist yet in the new location * (eg, /var/lib/NetworkManager) then look in old locations to maintain @@ -158,32 +160,6 @@ get_dhclient_leasefile (int addr_family, return NULL; } -static GSList * -nm_dhcp_dhclient_get_lease_ip_configs (NMDedupMultiIndex *multi_idx, - int addr_family, - const char *iface, - int ifindex, - const char *uuid, - guint32 route_table, - guint32 route_metric) -{ - gs_free char *contents = NULL; - gs_free char *leasefile = 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]) { - 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, @@ -288,7 +264,6 @@ find_existing_config (NMDhcpDhclient *self, int addr_family, const char *iface, return NULL; } - /* NM provides interface-specific options; thus the same dhclient config * file cannot be used since DHCP transactions can happen in parallel. * Since some distros don't have default per-interface dhclient config files, @@ -334,31 +309,33 @@ create_dhclient_config (NMDhcpDhclient *self, return new; } - static gboolean dhclient_start (NMDhcpClient *client, const char *mode_opt, - const GByteArray *duid, + GBytes *duid, gboolean release, pid_t *out_pid, int prefixes) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); - GPtrArray *argv = NULL; + gs_unref_ptrarray GPtrArray *argv = NULL; pid_t pid; 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; - int addr_family; - gboolean success; - char *escaped, *preferred_leasefile_path = NULL; + const char *iface; + const char *uuid; + const char *system_bus_address; + const char *dhclient_path; + char *binary_name; + gs_free char *cmd_str = NULL; + gs_free char *pid_file = NULL; + gs_free char *system_bus_address_env = NULL; + gs_free char *preferred_leasefile_path = NULL; + const int addr_family = nm_dhcp_client_get_addr_family (client); - g_return_val_if_fail (priv->pid_file == NULL, FALSE); + g_return_val_if_fail (!priv->pid_file, FALSE); - iface = nm_dhcp_client_get_iface (client); - uuid = nm_dhcp_client_get_uuid (client); - addr_family = nm_dhcp_client_get_addr_family (client); + NM_SET_OUT (out_pid, 0); dhclient_path = nm_dhcp_dhclient_get_path (); if (!dhclient_path) { @@ -366,6 +343,9 @@ dhclient_start (NMDhcpClient *client, return FALSE; } + iface = nm_dhcp_client_get_iface (client); + uuid = nm_dhcp_client_get_uuid (client); + pid_file = g_strdup_printf (RUNSTATEDIR "/dhclient%s-%s.pid", _addr_family_to_path_part (addr_family), iface); @@ -377,18 +357,18 @@ dhclient_start (NMDhcpClient *client, if (release) { /* release doesn't use the pidfile after killing an old client */ - g_free (pid_file); - pid_file = NULL; + nm_clear_g_free (&pid_file); } g_free (priv->lease_file); priv->lease_file = get_dhclient_leasefile (addr_family, iface, uuid, &preferred_leasefile_path); + nm_assert (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); - } else if (g_strcmp0 (priv->lease_file, preferred_leasefile_path) != 0) { - GFile *src = g_file_new_for_path (priv->lease_file); - GFile *dst = g_file_new_for_path (preferred_leasefile_path); + priv->lease_file = g_steal_pointer (&preferred_leasefile_path); + } else if (!nm_streq0 (priv->lease_file, preferred_leasefile_path)) { + gs_unref_object GFile *src = g_file_new_for_path (priv->lease_file); + gs_unref_object GFile *dst = g_file_new_for_path (preferred_leasefile_path); /* Try to copy the existing leasefile to the preferred location */ if (g_file_copy (src, dst, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &error)) { @@ -402,19 +382,16 @@ dhclient_start (NMDhcpClient *client, error->message); g_clear_error (&error); } - g_object_unref (src); - g_object_unref (dst); } - g_free (preferred_leasefile_path); /* Save the DUID to the leasefile dhclient will actually use */ if (addr_family == AF_INET6) { + gs_free char *escaped = NULL; + escaped = nm_dhcp_dhclient_escape_duid (duid); - success = nm_dhcp_dhclient_save_duid (priv->lease_file, escaped, &error); - g_free (escaped); - if (!success) { + if (!nm_dhcp_dhclient_save_duid (priv->lease_file, escaped, &error)) { _LOGW ("failed to save DUID to %s: %s", priv->lease_file, error->message); - g_free (pid_file); + g_clear_error (&error); return FALSE; } } @@ -439,19 +416,19 @@ dhclient_start (NMDhcpClient *client, while (prefixes--) g_ptr_array_add (argv, (gpointer) "-P"); } - g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */ + 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) "-pf"); /* Set pid file */ g_ptr_array_add (argv, (gpointer) pid_file); } - g_ptr_array_add (argv, (gpointer) "-lf"); /* Set lease file */ + g_ptr_array_add (argv, (gpointer) "-lf"); /* Set lease file */ g_ptr_array_add (argv, (gpointer) priv->lease_file); if (priv->conf_file) { - g_ptr_array_add (argv, (gpointer) "-cf"); /* Set interface config file */ + g_ptr_array_add (argv, (gpointer) "-cf"); /* Set interface config file */ g_ptr_array_add (argv, (gpointer) priv->conf_file); } @@ -466,34 +443,29 @@ dhclient_start (NMDhcpClient *client, 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); - _LOGD ("running: %s", cmd_str); - 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 ("dhclient started with pid %d", pid); - if (release == FALSE) - nm_dhcp_client_watch_child (client, pid); - priv->pid_file = pid_file; - } else { + _LOGD ("running: %s", + (cmd_str = g_strjoinv (" ", (gchar **) argv->pdata))); + + 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)) { _LOGW ("dhclient failed to start: '%s'", error->message); g_error_free (error); - g_free (pid_file); + return FALSE; } - if (out_pid) - *out_pid = pid; + _LOGI ("dhclient started with pid %lld", (long long int) pid); + + if (!release) + nm_dhcp_client_watch_child (client, pid); - g_ptr_array_free (argv, TRUE); - g_free (system_bus_address_env); - return pid > 0 ? TRUE : FALSE; + priv->pid_file = g_steal_pointer (&pid_file); + + NM_SET_OUT (out_pid, pid); + return TRUE; } static gboolean @@ -518,8 +490,10 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last 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) + if (new_client_id) { + nm_assert (!client_id); nm_dhcp_client_set_client_id (client, new_client_id); + } success = dhclient_start (client, NULL, NULL, FALSE, NULL, 0); } else _LOGW ("error creating dhclient configuration file"); @@ -531,9 +505,8 @@ 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, + GBytes *duid, guint needed_prefixes) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); @@ -553,26 +526,31 @@ ip6_start (NMDhcpClient *client, return FALSE; } - return dhclient_start (client, info_only ? "-S" : "-N", duid, FALSE, NULL, needed_prefixes); + return dhclient_start (client, + nm_dhcp_client_get_info_only (NM_DHCP_CLIENT (self)) + ? "-S" + : "-N", + duid, FALSE, NULL, needed_prefixes); } static void -stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) +stop (NMDhcpClient *client, gboolean release, GBytes *duid) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); - /* Chain up to parent */ NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->stop (client, release, duid); if (priv->conf_file) if (remove (priv->conf_file) == -1) _LOGD ("could not remove dhcp config file \"%s\": %d (%s)", priv->conf_file, errno, g_strerror (errno)); 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; + if (remove (priv->pid_file) == -1) { + int errsv = errno; + + _LOGD ("could not remove dhcp pid file \"%s\": %s (%d)", priv->pid_file, g_strerror (errsv), errsv); + } + nm_clear_g_free (&priv->pid_file); } if (release) { @@ -603,12 +581,12 @@ state_changed (NMDhcpClient *client, nm_dhcp_client_set_client_id (client, client_id); } -static GByteArray * +static GBytes * get_duid (NMDhcpClient *client) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); - GByteArray *duid = NULL; + GBytes *duid = NULL; char *leasefile; GError *error = NULL; @@ -629,7 +607,7 @@ get_duid (NMDhcpClient *client) g_free (leasefile); } - if (!duid && priv->def_leasefile) { + if (!duid) { /* Otherwise read the default machine-wide DUID */ _LOGD ("looking for default DUID in '%s'", priv->def_leasefile); duid = nm_dhcp_dhclient_read_duid (priv->def_leasefile, &error); @@ -642,36 +620,30 @@ get_duid (NMDhcpClient *client) } /* return our DUID, otherwise let the parent class make a default DUID */ - return duid ? duid : NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->get_duid (client); + return duid ?: NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->get_duid (client); } /*****************************************************************************/ -static const char *def_leasefiles[] = { - SYSCONFDIR "/dhclient6.leases", - LOCALSTATEDIR "/lib/dhcp/dhclient6.leases", - LOCALSTATEDIR "/lib/dhclient/dhclient6.leases", - NULL -}; - static void nm_dhcp_dhclient_init (NMDhcpDhclient *self) { + static const char *const FILES[] = { + SYSCONFDIR "/dhclient6.leases", /* default */ + LOCALSTATEDIR "/lib/dhcp/dhclient6.leases", + LOCALSTATEDIR "/lib/dhclient/dhclient6.leases", + }; NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); - const char **iter = &def_leasefiles[0]; + int i; - while (iter && *iter) { - if (g_file_test (*iter, G_FILE_TEST_EXISTS)) { - priv->def_leasefile = *iter; + priv->def_leasefile = FILES[0]; + for (i = 0; i < G_N_ELEMENTS (FILES); i++) { + if (g_file_test (FILES[i], G_FILE_TEST_EXISTS)) { + priv->def_leasefile = FILES[i]; break; } - iter++; } - /* Fallback option */ - if (!priv->def_leasefile) - priv->def_leasefile = SYSCONFDIR "/dhclient6.leases"; - priv->dhcp_listener = g_object_ref (nm_dhcp_listener_get ()); g_signal_connect (priv->dhcp_listener, NM_DHCP_LISTENER_EVENT, @@ -717,7 +689,6 @@ const NMDhcpClientFactory _nm_dhcp_client_factory_dhclient = { .name = "dhclient", .get_type = nm_dhcp_dhclient_get_type, .get_path = nm_dhcp_dhclient_get_path, - .get_lease_ip_configs = nm_dhcp_dhclient_get_lease_ip_configs, }; #endif /* WITH_DHCLIENT */ diff --git a/src/dhcp/nm-dhcp-dhcpcanon.c b/src/dhcp/nm-dhcp-dhcpcanon.c index d7ddd194..12aa57aa 100644 --- a/src/dhcp/nm-dhcp-dhcpcanon.c +++ b/src/dhcp/nm-dhcp-dhcpcanon.c @@ -76,11 +76,10 @@ 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, + GBytes *duid, gboolean release, pid_t *out_pid, int prefixes) @@ -118,16 +117,16 @@ dhcpcanon_start (NMDhcpClient *client, 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) "-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) "-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) "-cf"); /* Set interface config file */ g_ptr_array_add (argv, (gpointer) priv->conf_file); } @@ -142,7 +141,6 @@ dhcpcanon_start (NMDhcpClient *client, g_ptr_array_add (argv, (gpointer) system_bus_address_env); } - g_ptr_array_add (argv, (gpointer) iface); g_ptr_array_add (argv, NULL); @@ -179,9 +177,8 @@ 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, + GBytes *duid, guint needed_prefixes) { NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client); @@ -190,7 +187,7 @@ ip6_start (NMDhcpClient *client, return FALSE; } static void -stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) +stop (NMDhcpClient *client, gboolean release, GBytes *duid) { NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client); NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE (self); @@ -266,7 +263,6 @@ 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-dhcpcd.c b/src/dhcp/nm-dhcp-dhcpcd.c index 66a31acf..c4bcb084 100644 --- a/src/dhcp/nm-dhcp-dhcpcd.c +++ b/src/dhcp/nm-dhcp-dhcpcd.c @@ -114,18 +114,18 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last argv = g_ptr_array_new (); g_ptr_array_add (argv, (gpointer) dhcpcd_path); - g_ptr_array_add (argv, (gpointer) "-B"); /* Don't background on lease (disable fork()) */ + g_ptr_array_add (argv, (gpointer) "-B"); /* Don't background on lease (disable fork()) */ - g_ptr_array_add (argv, (gpointer) "-K"); /* Disable built-in carrier detection */ + g_ptr_array_add (argv, (gpointer) "-K"); /* Disable built-in carrier detection */ - g_ptr_array_add (argv, (gpointer) "-L"); /* Disable built-in IPv4LL */ + g_ptr_array_add (argv, (gpointer) "-L"); /* Disable built-in IPv4LL */ /* --noarp. Don't request or claim the address by ARP; this also disables IPv4LL. */ g_ptr_array_add (argv, (gpointer) "-A"); - g_ptr_array_add (argv, (gpointer) "-G"); /* Let NM handle routing */ + g_ptr_array_add (argv, (gpointer) "-G"); /* Let NM handle routing */ - g_ptr_array_add (argv, (gpointer) "-c"); /* Set script file */ + g_ptr_array_add (argv, (gpointer) "-c"); /* Set script file */ g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path); #ifdef DHCPCD_SUPPORTS_IPV6 @@ -177,9 +177,8 @@ 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, + GBytes *duid, guint needed_prefixes) { NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client); @@ -189,12 +188,11 @@ ip6_start (NMDhcpClient *client, } static void -stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) +stop (NMDhcpClient *client, gboolean release, GBytes *duid) { NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client); NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (self); - /* Chain up to parent */ NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcd_parent_class)->stop (client, release, duid); if (priv->pid_file) { @@ -253,7 +251,6 @@ const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcd = { .name = "dhcpcd", .get_type = nm_dhcp_dhcpcd_get_type, .get_path = nm_dhcp_dhcpcd_get_path, - .get_lease_ip_configs = NULL, }; #endif /* WITH_DHCPCD */ diff --git a/src/dhcp/nm-dhcp-helper.c b/src/dhcp/nm-dhcp-helper.c index f50c5cec..8ea55061 100644 --- a/src/dhcp/nm-dhcp-helper.c +++ b/src/dhcp/nm-dhcp-helper.c @@ -134,8 +134,6 @@ main (int argc, char *argv[]) guint try_count = 0; gint64 time_end; - nm_g_type_init (); - /* FIXME: g_dbus_connection_new_for_address_sync() tries to connect to the socket in * non-blocking mode, which can easily fail with EAGAIN, causing the creation of the * socket to fail with "Could not connect: Resource temporarily unavailable". diff --git a/src/dhcp/nm-dhcp-listener.c b/src/dhcp/nm-dhcp-listener.c index 1cce5a1c..1770ead3 100644 --- a/src/dhcp/nm-dhcp-listener.c +++ b/src/dhcp/nm-dhcp-listener.c @@ -33,7 +33,7 @@ #include "nm-dhcp-client.h" #include "nm-dhcp-manager.h" #include "nm-core-internal.h" -#include "nm-bus-manager.h" +#include "nm-dbus-manager.h" #include "NetworkManagerUtils.h" #define PRIV_SOCK_PATH NMRUNDIR "/private-dhcp" @@ -60,7 +60,7 @@ const NMDhcpClientFactory *const _nm_dhcp_manager_factories[4] = { /*****************************************************************************/ typedef struct { - NMBusManager * dbus_mgr; + NMDBusManager * dbus_mgr; gulong new_conn_id; gulong dis_conn_id; GHashTable * connections; @@ -160,7 +160,7 @@ _method_call_handle (NMDhcpListener *self, 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)"); + _LOGW ("dhcp-event: couldn't convert PID '%s' to an integer", pid_str ?: "(null)"); return; } @@ -192,70 +192,52 @@ _method_call (GDBusConnection *connection, { 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 (); + if ( !nm_streq (interface_name, NM_DHCP_HELPER_SERVER_INTERFACE_NAME) + || !nm_streq (method_name, NM_DHCP_HELPER_SERVER_METHOD_NOTIFY)) { + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_UNKNOWN_METHOD, + "Unknown method %s", + method_name); + return; + } _method_call_handle (self, parameters); - g_dbus_method_invocation_return_value (invocation, NULL); } +static GDBusInterfaceInfo *const interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO ( + NM_DHCP_HELPER_SERVER_INTERFACE_NAME, + .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( + NM_DEFINE_GDBUS_METHOD_INFO ( + NM_DHCP_HELPER_SERVER_METHOD_NOTIFY, + .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( + NM_DEFINE_GDBUS_ARG_INFO ("data", "a{sv}"), + ), + ), + ), +); + static guint _dbus_connection_register_object (NMDhcpListener *self, GDBusConnection *connection, GError **error) { - static GDBusArgInfo arg_info_notify_in = { - .ref_count = -1, - .name = "data", - .signature = "a{sv}", - .annotations = NULL, - }; - static GDBusArgInfo *arg_infos_notify[] = { - &arg_info_notify_in, - NULL, - }; - static GDBusMethodInfo method_info_notify = { - .ref_count = -1, - .name = NM_DHCP_HELPER_SERVER_METHOD_NOTIFY, - .in_args = arg_infos_notify, - .out_args = NULL, - .annotations = NULL, - }; - static GDBusMethodInfo *method_infos[] = { - &method_info_notify, - NULL, - }; - static GDBusInterfaceInfo interface_info = { - .ref_count = -1, - .name = NM_DHCP_HELPER_SERVER_INTERFACE_NAME, - .methods = method_infos, - .signals = NULL, - .properties = NULL, - .annotations = NULL, - }; - - static GDBusInterfaceVTable interface_vtable = { + static const GDBusInterfaceVTable interface_vtable = { .method_call = _method_call, - .get_property = NULL, - .set_property = NULL, }; return g_dbus_connection_register_object (connection, NM_DHCP_HELPER_SERVER_OBJECT_PATH, - &interface_info, - &interface_vtable, + interface_info, + NM_UNCONST_PTR (GDBusInterfaceVTable, &interface_vtable), self, NULL, error); } static void -new_connection_cb (NMBusManager *mgr, +new_connection_cb (NMDBusManager *mgr, GDBusConnection *connection, GDBusObjectManager *manager, NMDhcpListener *self) @@ -278,7 +260,7 @@ new_connection_cb (NMBusManager *mgr, } static void -dis_connection_cb (NMBusManager *mgr, +dis_connection_cb (NMDBusManager *mgr, GDBusConnection *connection, NMDhcpListener *self) { @@ -300,18 +282,18 @@ nm_dhcp_listener_init (NMDhcpListener *self) NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (self); /* Maps GDBusConnection :: signal-id */ - priv->connections = g_hash_table_new (NULL, NULL); + priv->connections = g_hash_table_new (nm_direct_hash, NULL); - priv->dbus_mgr = nm_bus_manager_get (); + priv->dbus_mgr = nm_dbus_manager_get (); /* Register the socket our DHCP clients will return lease info on */ - nm_bus_manager_private_server_register (priv->dbus_mgr, PRIV_SOCK_PATH, PRIV_SOCK_TAG); + nm_dbus_manager_private_server_register (priv->dbus_mgr, PRIV_SOCK_PATH, PRIV_SOCK_TAG); priv->new_conn_id = g_signal_connect (priv->dbus_mgr, - NM_BUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG, + NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG, G_CALLBACK (new_connection_cb), self); priv->dis_conn_id = g_signal_connect (priv->dbus_mgr, - NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG, + NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG, G_CALLBACK (dis_connection_cb), self); } diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c index f5c7c84b..aa40e803 100644 --- a/src/dhcp/nm-dhcp-manager.c +++ b/src/dhcp/nm-dhcp-manager.c @@ -43,8 +43,8 @@ typedef struct { const NMDhcpClientFactory *client_factory; - GHashTable * clients; - char * default_hostname; + char *default_hostname; + CList dhcp_client_lst_head; } NMDhcpManagerPrivate; struct _NMDhcpManager { @@ -98,21 +98,17 @@ static NMDhcpClient * get_client_for_ifindex (NMDhcpManager *manager, int addr_family, int ifindex) { NMDhcpManagerPrivate *priv; - GHashTableIter iter; - gpointer value; + NMDhcpClient *client; g_return_val_if_fail (NM_IS_DHCP_MANAGER (manager), NULL); g_return_val_if_fail (ifindex > 0, NULL); priv = NM_DHCP_MANAGER_GET_PRIVATE (manager); - g_hash_table_iter_init (&iter, priv->clients); - while (g_hash_table_iter_next (&iter, NULL, &value)) { - NMDhcpClient *candidate = NM_DHCP_CLIENT (value); - - if ( nm_dhcp_client_get_ifindex (candidate) == ifindex - && nm_dhcp_client_get_addr_family (candidate) == addr_family) - return candidate; + c_list_for_each_entry (client, &priv->dhcp_client_lst_head, dhcp_client_lst) { + if ( nm_dhcp_client_get_ifindex (client) == ifindex + && nm_dhcp_client_get_addr_family (client) == addr_family) + return client; } return NULL; @@ -129,13 +125,19 @@ static void remove_client (NMDhcpManager *self, NMDhcpClient *client) { g_signal_handlers_disconnect_by_func (client, client_state_changed, self); + c_list_unlink (&client->dhcp_client_lst); /* Stopping the client is left up to the controlling device * explicitly since we may want to quit NetworkManager but not terminate * the DHCP client. */ +} - g_hash_table_remove (NM_DHCP_MANAGER_GET_PRIVATE (self)->clients, client); +static void +remove_client_unref (NMDhcpManager *self, NMDhcpClient *client) +{ + remove_client (self, client); + g_object_unref (client); } static void @@ -147,7 +149,7 @@ client_state_changed (NMDhcpClient *client, NMDhcpManager *self) { if (state >= NM_DHCP_STATE_TIMEOUT) - remove_client (self, client); + remove_client_unref (self, client); } static NMDhcpClient * @@ -156,12 +158,12 @@ client_start (NMDhcpManager *self, NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - const GByteArray *hwaddr, + GBytes *hwaddr, const char *uuid, guint32 route_table, guint32 route_metric, const struct in6_addr *ipv6_ll_addr, - const char *dhcp_client_id, + GBytes *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, const char *hostname, @@ -179,23 +181,21 @@ client_start (NMDhcpManager *self, g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL); g_return_val_if_fail (ifindex > 0, NULL); g_return_val_if_fail (uuid != NULL, NULL); + g_return_val_if_fail (!dhcp_client_id || g_bytes_get_size (dhcp_client_id) >= 2, NULL); priv = NM_DHCP_MANAGER_GET_PRIVATE (self); - /* Ensure we have a usable DHCP client */ if (!priv->client_factory) return NULL; /* Kill any old client instance */ client = get_client_for_ifindex (self, addr_family, ifindex); if (client) { - g_object_ref (client); remove_client (self, client); nm_dhcp_client_stop (client, FALSE); g_object_unref (client); } - /* 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, @@ -206,21 +206,26 @@ client_start (NMDhcpManager *self, NM_DHCP_CLIENT_ROUTE_TABLE, (guint) route_table, NM_DHCP_CLIENT_ROUTE_METRIC, (guint) route_metric, NM_DHCP_CLIENT_TIMEOUT, (guint) timeout, + NM_DHCP_CLIENT_FLAGS, (guint) (0 + | (hostname_use_fqdn ? NM_DHCP_CLIENT_FLAGS_USE_FQDN : 0) + | (info_only ? NM_DHCP_CLIENT_FLAGS_INFO_ONLY : 0) + ), NULL); - g_hash_table_insert (NM_DHCP_MANAGER_GET_PRIVATE (self)->clients, client, g_object_ref (client)); + nm_assert (client && c_list_is_empty (&client->dhcp_client_lst)); + c_list_link_tail (&priv->dhcp_client_lst_head, &client->dhcp_client_lst); g_signal_connect (client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (client_state_changed), self); 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); + success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, last_ip4_address); else - success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy, needed_prefixes); + success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, privacy, needed_prefixes); if (!success) { - remove_client (self, client); - client = NULL; + remove_client_unref (self, client); + return NULL; } - return client; + return g_object_ref (client); } /* Caller owns a reference to the NMDhcpClient on return */ @@ -229,14 +234,14 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self, NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - const GByteArray *hwaddr, + GBytes *hwaddr, const char *uuid, guint32 route_table, guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, const char *dhcp_fqdn, - const char *dhcp_client_id, + GBytes *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, const char *last_ip_address) @@ -285,7 +290,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - const GByteArray *hwaddr, + GBytes *hwaddr, const struct in6_addr *ll_addr, const char *uuid, guint32 route_table, @@ -306,7 +311,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, if (send_hostname) { /* Always prefer the explicit dhcp-hostname if given */ - hostname = dhcp_hostname ? dhcp_hostname : priv->default_hostname; + hostname = dhcp_hostname ?: priv->default_hostname; } return client_start (self, AF_INET6, multi_idx, iface, ifindex, hwaddr, uuid, route_table, route_metric, ll_addr, @@ -328,31 +333,6 @@ nm_dhcp_manager_set_default_hostname (NMDhcpManager *manager, const char *hostna priv->default_hostname = g_strdup (hostname); } -GSList * -nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self, - NMDedupMultiIndex *multi_idx, - int addr_family, - const char *iface, - int ifindex, - const char *uuid, - guint32 route_table, - guint32 route_metric) -{ - NMDhcpManagerPrivate *priv; - - g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL); - 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 (multi_idx, addr_family, iface, ifindex, uuid, route_table, route_metric); - return NULL; -} - const char * nm_dhcp_manager_get_config (NMDhcpManager *self) { @@ -378,6 +358,8 @@ nm_dhcp_manager_init (NMDhcpManager *self) int i; const NMDhcpClientFactory *client_factory = NULL; + c_list_init (&priv->dhcp_client_lst_head); + for (i = 0; i < G_N_ELEMENTS (_nm_dhcp_manager_factories); i++) { const NMDhcpClientFactory *f = _nm_dhcp_manager_factories[i]; @@ -429,38 +411,21 @@ nm_dhcp_manager_init (NMDhcpManager *self) nm_log_info (LOGD_DHCP, "dhcp-init: Using DHCP client '%s'", client_factory->name); priv->client_factory = client_factory; - priv->clients = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, - (GDestroyNotify) g_object_unref); } static void dispose (GObject *object) { - NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE ((NMDhcpManager *) object); - GList *values, *iter; - - if (priv->clients) { - values = g_hash_table_get_values (priv->clients); - for (iter = values; iter; iter = g_list_next (iter)) - remove_client (NM_DHCP_MANAGER (object), NM_DHCP_CLIENT (iter->data)); - g_list_free (values); - } - - G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->dispose (object); -} - -static void -finalize (GObject *object) -{ - NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE ((NMDhcpManager *) object); + NMDhcpManager *self = NM_DHCP_MANAGER (object); + NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self); + NMDhcpClient *client, *client_safe; - g_free (priv->default_hostname); + c_list_for_each_entry_safe (client, client_safe, &priv->dhcp_client_lst_head, dhcp_client_lst) + remove_client_unref (self, client); - if (priv->clients) - g_hash_table_destroy (priv->clients); + G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->dispose (object); - G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->finalize (object); + nm_clear_g_free (&priv->default_hostname); } static void @@ -468,6 +433,5 @@ nm_dhcp_manager_class_init (NMDhcpManagerClass *manager_class) { GObjectClass *object_class = G_OBJECT_CLASS (manager_class); - object_class->finalize = finalize; object_class->dispose = dispose; } diff --git a/src/dhcp/nm-dhcp-manager.h b/src/dhcp/nm-dhcp-manager.h index 078117ff..f8a7e31d 100644 --- a/src/dhcp/nm-dhcp-manager.h +++ b/src/dhcp/nm-dhcp-manager.h @@ -49,14 +49,14 @@ NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *manager, struct _NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - const GByteArray *hwaddr, + GBytes *hwaddr, const char *uuid, guint32 route_table, guint32 route_metric, gboolean send_hostname, const char *dhcp_hostname, const char *dhcp_fqdn, - const char *dhcp_client_id, + GBytes *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, const char *last_ip_address); @@ -65,7 +65,7 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, struct _NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, - const GByteArray *hwaddr, + GBytes *hwaddr, const struct in6_addr *ll_addr, const char *uuid, guint32 route_table, @@ -78,15 +78,6 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, NMSettingIP6ConfigPrivacy privacy, 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, - guint32 route_table, - guint32 route_metric); - /* For testing only */ extern const char* nm_dhcp_helper_path; diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c index f79b7cb1..2d0202bb 100644 --- a/src/dhcp/nm-dhcp-systemd.c +++ b/src/dhcp/nm-dhcp-systemd.c @@ -29,6 +29,7 @@ #include #include "nm-utils/nm-dedup-multi.h" +#include "nm-utils/unaligned.h" #include "nm-utils.h" #include "nm-dhcp-utils.h" @@ -60,8 +61,7 @@ typedef struct { guint request_count; - gboolean privacy; - gboolean info_only; + bool privacy:1; } NMDhcpSystemdPrivate; struct _NMDhcpSystemd { @@ -451,36 +451,6 @@ get_leasefile_path (int addr_family, const char *iface, const char *uuid) iface); } -static GSList * -nm_dhcp_systemd_get_lease_ip_configs (NMDedupMultiIndex *multi_idx, - int addr_family, - const char *iface, - int ifindex, - const char *uuid, - guint32 route_table, - guint32 route_metric) -{ - GSList *leases = NULL; - gs_free char *path = NULL; - sd_dhcp_lease *lease = NULL; - NMIP4Config *ip4_config; - int r; - - if (addr_family != AF_INET) - return NULL; - - path = get_leasefile_path (addr_family, iface, uuid); - r = dhcp_lease_load (&lease, path); - if (r == 0 && lease) { - 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); - } - - return leases; -} - /*****************************************************************************/ static void @@ -543,7 +513,7 @@ bound4_handle (NMDhcpSystemd *self) nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_BOUND, - G_OBJECT (ip4_config), + NM_IP_CONFIG_CAST (ip4_config), options); } else { _LOGW ("%s", error->message); @@ -584,14 +554,16 @@ dhcp_event_cb (sd_dhcp_client *client, int event, gpointer user_data) } static guint16 -get_arp_type (const GByteArray *hwaddr) +get_arp_type (GBytes *hwaddr) { - if (hwaddr->len == ETH_ALEN) + switch (g_bytes_get_size (hwaddr)) { + case ETH_ALEN: return ARPHRD_ETHER; - else if (hwaddr->len == INFINIBAND_ALEN) + case INFINIBAND_ALEN: return ARPHRD_INFINIBAND; - else + default: return ARPHRD_NONE; + } } static gboolean @@ -600,7 +572,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); const char *iface = nm_dhcp_client_get_iface (client); - const GByteArray *hwaddr; + GBytes *hwaddr; sd_dhcp_lease *lease = NULL; GBytes *override_client_id; const uint8_t *client_id = NULL; @@ -609,7 +581,6 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last const char *hostname; int r, i; gboolean success = FALSE; - guint16 arp_type; g_assert (priv->client4 == NULL); g_assert (priv->client6 == NULL); @@ -633,16 +604,14 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last hwaddr = nm_dhcp_client_get_hw_addr (client); if (hwaddr) { - arp_type= get_arp_type (hwaddr); - if (arp_type == ARPHRD_NONE) { - _LOGW ("failed to determine ARP type"); - goto error; - } + const uint8_t *data; + gsize len; + data = g_bytes_get_data (hwaddr, &len); r = sd_dhcp_client_set_mac (priv->client4, - hwaddr->data, - hwaddr->len, - arp_type); + data, + len, + get_arp_type (hwaddr)); if (r < 0) { _LOGW ("failed to set MAC address (%d)", r); goto error; @@ -661,12 +630,6 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last goto error; } - r = sd_dhcp_client_set_request_broadcast (priv->client4, true); - if (r < 0) { - _LOGW ("failed to enable broadcast mode (%d)", r); - goto error; - } - dhcp_lease_load (&lease, priv->lease_file); if (last_ip4_address) @@ -704,7 +667,6 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last } } - /* Add requested options */ for (i = 0; dhcp4_requests[i].name; i++) { if (dhcp4_requests[i].include) @@ -854,13 +816,13 @@ bound6_handle (NMDhcpSystemd *self) lease, options, TRUE, - priv->info_only, + nm_dhcp_client_get_info_only (NM_DHCP_CLIENT (self)), &error); if (ip6_config) { nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_BOUND, - G_OBJECT (ip6_config), + NM_IP_CONFIG_CAST (ip6_config), options); } else { _LOGW ("%s", error->message); @@ -900,24 +862,29 @@ 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, + GBytes *duid, guint needed_prefixes) { NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); const char *iface = nm_dhcp_client_get_iface (client); - const GByteArray *hwaddr; + GBytes *hwaddr; + const char *hostname; int r, i; + const guint8 *duid_arr; + gsize duid_len; g_assert (priv->client4 == NULL); g_assert (priv->client6 == NULL); g_return_val_if_fail (duid != NULL, FALSE); + duid_arr = g_bytes_get_data (duid, &duid_len); + if (!duid_arr || duid_len < 2) + g_return_val_if_reached (FALSE); + g_free (priv->lease_file); 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); if (r < 0) { @@ -932,16 +899,13 @@ ip6_start (NMDhcpClient *client, _LOGT ("dhcp-client6: set %p", priv->client6); - if (info_only) - sd_dhcp6_client_set_information_request (priv->client6, 1); + if (nm_dhcp_client_get_info_only (client)) + sd_dhcp6_client_set_information_request (priv->client6, 1); - /* NM stores the entire DUID which includes the uint16 "type", while systemd - * wants the type passed separately from the following data. - */ r = sd_dhcp6_client_set_duid (priv->client6, - ntohs (((const guint16 *) duid->data)[0]), - duid->data + 2, - duid->len - 2); + unaligned_read_be16 (&duid_arr[0]), + &duid_arr[2], + duid_len - 2); if (r < 0) { _LOGW ("failed to set DUID (%d)", r); return FALSE; @@ -955,9 +919,13 @@ ip6_start (NMDhcpClient *client, hwaddr = nm_dhcp_client_get_hw_addr (client); if (hwaddr) { + const uint8_t *data; + gsize len; + + data = g_bytes_get_data (hwaddr, &len); r = sd_dhcp6_client_set_mac (priv->client6, - hwaddr->data, - hwaddr->len, + data, + len, get_arp_type (hwaddr)); if (r < 0) { _LOGW ("failed to set MAC address (%d)", r); @@ -989,6 +957,13 @@ ip6_start (NMDhcpClient *client, goto error; } + hostname = nm_dhcp_client_get_hostname (client); + r = sd_dhcp6_client_set_fqdn (priv->client6, hostname); + if (r < 0) { + _LOGW ("failed to set DHCP hostname to '%s' (%d)", hostname, r); + goto error; + } + r = sd_dhcp6_client_start (priv->client6); if (r < 0) { _LOGW ("failed to start client (%d)", r); @@ -1006,12 +981,14 @@ error: } static void -stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) +stop (NMDhcpClient *client, gboolean release, GBytes *duid) { NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); int r = 0; + NM_DHCP_CLIENT_CLASS (nm_dhcp_systemd_parent_class)->stop (client, release, duid); + _LOGT ("dhcp-client%d: stop %p", priv->client4 ? '4' : '6', priv->client4 ? (gpointer) priv->client4 : (gpointer) priv->client6); @@ -1074,5 +1051,4 @@ const NMDhcpClientFactory _nm_dhcp_client_factory_internal = { .name = "internal", .get_type = nm_dhcp_systemd_get_type, .get_path = NULL, - .get_lease_ip_configs = nm_dhcp_systemd_get_lease_ip_configs, }; diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c index 50ca2abe..9185a135 100644 --- a/src/dhcp/nm-dhcp-utils.c +++ b/src/dhcp/nm-dhcp-utils.c @@ -721,11 +721,15 @@ error: } char * -nm_dhcp_utils_duid_to_string (const GByteArray *duid) +nm_dhcp_utils_duid_to_string (GBytes *duid) { + gconstpointer data; + gsize len; + g_return_val_if_fail (duid != NULL, NULL); - return _nm_utils_bin2str (duid->data, duid->len, FALSE); + data = g_bytes_get_data (duid, &len); + return _nm_utils_bin2str (data, len, FALSE); } /** diff --git a/src/dhcp/nm-dhcp-utils.h b/src/dhcp/nm-dhcp-utils.h index 32140f48..5c127bd1 100644 --- a/src/dhcp/nm-dhcp-utils.h +++ b/src/dhcp/nm-dhcp-utils.h @@ -39,7 +39,7 @@ NMIP6Config *nm_dhcp_utils_ip6_config_from_options (struct _NMDedupMultiIndex *m NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options); -char * nm_dhcp_utils_duid_to_string (const GByteArray *duid); +char *nm_dhcp_utils_duid_to_string (GBytes *duid); GBytes * nm_dhcp_utils_client_id_string_to_bytes (const char *client_id); diff --git a/src/dhcp/tests/leases/basic.leases b/src/dhcp/tests/leases/basic.leases deleted file mode 100644 index 703d9247..00000000 --- a/src/dhcp/tests/leases/basic.leases +++ /dev/null @@ -1,31 +0,0 @@ -lease { - interface "wlan0"; - fixed-address 192.168.1.180; - option subnet-mask 255.255.255.0; - option routers 192.168.1.1; - option dhcp-lease-time 600; - option dhcp-message-type 5; - option domain-name-servers 192.168.1.1; - option dhcp-server-identifier 192.168.1.1; - option broadcast-address 192.168.1.255; - renew 5 2013/11/01 19:56:15; - rebind 5 2013/11/01 20:00:44; - expire 5 2013/11/01 20:01:59; -} -lease { - interface "wlan0"; - fixed-address 10.77.52.141; - option subnet-mask 255.0.0.0; - option dhcp-lease-time 1200; - option routers 10.77.52.254; - option dhcp-message-type 5; - option dhcp-server-identifier 10.77.52.254; - option domain-name-servers 8.8.8.8,8.8.4.4; - option dhcp-renewal-time 600; - option dhcp-rebinding-time 1050; - option domain-name "morriesguest.local"; - renew 5 2013/11/01 20:01:08; - rebind 5 2013/11/01 20:05:00; - expire 5 2013/11/01 20:06:15; -} - diff --git a/src/dhcp/tests/leases/malformed1.leases b/src/dhcp/tests/leases/malformed1.leases deleted file mode 100644 index 401d982a..00000000 --- a/src/dhcp/tests/leases/malformed1.leases +++ /dev/null @@ -1,15 +0,0 @@ -# missing fixed-address option -lease { - interface "wlan0"; - option subnet-mask 255.255.255.0; - option routers 192.168.1.1; - option dhcp-lease-time 600; - option dhcp-message-type 5; - option domain-name-servers 192.168.1.1; - option dhcp-server-identifier 192.168.1.1; - option broadcast-address 192.168.1.255; - renew 5 2013/11/01 19:56:15; - rebind 5 2013/11/01 20:00:44; - expire 5 2013/11/01 20:01:59; -} - diff --git a/src/dhcp/tests/leases/malformed2.leases b/src/dhcp/tests/leases/malformed2.leases deleted file mode 100644 index adf5f6de..00000000 --- a/src/dhcp/tests/leases/malformed2.leases +++ /dev/null @@ -1,15 +0,0 @@ -# missing routers option -lease { - interface "wlan0"; - fixed-address 192.168.1.180; - option subnet-mask 255.255.255.0; - option dhcp-lease-time 600; - option dhcp-message-type 5; - option domain-name-servers 192.168.1.1; - option dhcp-server-identifier 192.168.1.1; - option broadcast-address 192.168.1.255; - renew 5 2013/11/01 19:56:15; - rebind 5 2013/11/01 20:00:44; - expire 5 2013/11/01 20:01:59; -} - diff --git a/src/dhcp/tests/leases/malformed3.leases b/src/dhcp/tests/leases/malformed3.leases deleted file mode 100644 index a2afc8b6..00000000 --- a/src/dhcp/tests/leases/malformed3.leases +++ /dev/null @@ -1,15 +0,0 @@ -# missing expire time -lease { - interface "wlan0"; - fixed-address 192.168.1.180; - option subnet-mask 255.255.255.0; - option routers 192.168.1.1; - option dhcp-lease-time 600; - option dhcp-message-type 5; - option domain-name-servers 192.168.1.1; - option dhcp-server-identifier 192.168.1.1; - option broadcast-address 192.168.1.255; - renew 5 2013/11/01 19:56:15; - rebind 5 2013/11/01 20:00:44; -} - diff --git a/src/dhcp/tests/meson.build b/src/dhcp/tests/meson.build new file mode 100644 index 00000000..9d8be427 --- /dev/null +++ b/src/dhcp/tests/meson.build @@ -0,0 +1,19 @@ +test_units = [ + 'test-dhcp-dhclient', + 'test-dhcp-utils' +] + +foreach test_unit: test_units + exe = executable( + test_unit, + test_unit + '.c', + dependencies: test_nm_dep, + c_args: nm_build_cflags, + ) + + test( + 'dhcp/' + test_unit, + test_script, + args: test_args + [exe.full_path()] + ) +endforeach diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c index f2e1f321..a8284b23 100644 --- a/src/dhcp/tests/test-dhcp-dhclient.c +++ b/src/dhcp/tests/test-dhcp-dhclient.c @@ -36,11 +36,7 @@ #include "nm-test-utils-core.h" -#define DEBUG 1 - -static const int IFINDEX = 5; -static const guint32 ROUTE_TABLE = RT_TABLE_MAIN; -static const guint32 ROUTE_METRIC = 100; +#define TEST_DIR NM_BUILD_SRCDIR"/src/dhcp/tests" static void test_config (const char *orig, @@ -154,7 +150,7 @@ test_override_client_id (void) static const char *quote_client_id_expected = \ "# Created by NetworkManager\n" "\n" - "send dhcp-client-identifier \"1234\"; # added by NetworkManager\n" + "send dhcp-client-identifier \"\\x00abcd\"; # added by NetworkManager\n" "\n" "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" @@ -172,7 +168,65 @@ test_quote_client_id (void) { test_config (NULL, quote_client_id_expected, AF_INET, NULL, 0, FALSE, - "1234", + "abcd", + NULL, + "eth0", + NULL); +} + +/*****************************************************************************/ + +static const char *quote_client_id_expected_2 = \ + "# Created by NetworkManager\n" + "\n" + "send dhcp-client-identifier 00:61:5c:62:63; # added by NetworkManager\n" + "\n" + "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" + "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" + "option wpad code 252 = string;\n" + "\n" + "also request rfc3442-classless-static-routes;\n" + "also request ms-classless-static-routes;\n" + "also request static-routes;\n" + "also request wpad;\n" + "also request ntp-servers;\n" + "\n"; + +static void +test_quote_client_id_2 (void) +{ + test_config (NULL, quote_client_id_expected_2, + AF_INET, NULL, 0, FALSE, + "a\\bc", + NULL, + "eth0", + NULL); +} + +/*****************************************************************************/ + +static const char *hex_zero_client_id_expected = \ + "# Created by NetworkManager\n" + "\n" + "send dhcp-client-identifier 00:11:22:33; # added by NetworkManager\n" + "\n" + "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" + "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" + "option wpad code 252 = string;\n" + "\n" + "also request rfc3442-classless-static-routes;\n" + "also request ms-classless-static-routes;\n" + "also request static-routes;\n" + "also request wpad;\n" + "also request ntp-servers;\n" + "\n"; + +static void +test_hex_zero_client_id (void) +{ + test_config (NULL, hex_zero_client_id_expected, + AF_INET, NULL, 0, FALSE, + "00:11:22:33", NULL, "eth0", NULL); @@ -183,7 +237,7 @@ test_quote_client_id (void) static const char *ascii_client_id_expected = \ "# Created by NetworkManager\n" "\n" - "send dhcp-client-identifier \"qb:cd:ef:12:34:56\"; # added by NetworkManager\n" + "send dhcp-client-identifier \"\\x00qb:cd:ef:12:34:56\"; # added by NetworkManager\n" "\n" "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" @@ -239,13 +293,13 @@ test_hex_single_client_id (void) /*****************************************************************************/ static const char *existing_hex_client_id_orig = \ - "send dhcp-client-identifier 00:30:04:20:7A:08;\n"; + "send dhcp-client-identifier 10:30:04:20:7A:08;\n"; static const char *existing_hex_client_id_expected = \ "# Created by NetworkManager\n" "# Merged from /path/to/dhclient.conf\n" "\n" - "send dhcp-client-identifier 00:30:04:20:7A:08;\n" + "send dhcp-client-identifier 10:30:04:20:7A:08;\n" "\n" "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" @@ -262,7 +316,7 @@ static void test_existing_hex_client_id (void) { gs_unref_bytes GBytes *new_client_id = NULL; - const guint8 bytes[] = { 0x00, 0x30, 0x04,0x20, 0x7A, 0x08 }; + const guint8 bytes[] = { 0x10, 0x30, 0x04, 0x20, 0x7A, 0x08 }; new_client_id = g_bytes_new (bytes, sizeof (bytes)); test_config (existing_hex_client_id_orig, existing_hex_client_id_expected, @@ -275,16 +329,52 @@ test_existing_hex_client_id (void) /*****************************************************************************/ +static const char *existing_escaped_client_id_orig = \ + "send dhcp-client-identifier \"\\044test\\xfe\";\n"; + +static const char *existing_escaped_client_id_expected = \ + "# Created by NetworkManager\n" + "# Merged from /path/to/dhclient.conf\n" + "\n" + "send dhcp-client-identifier \"\\044test\\xfe\";\n" + "\n" + "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" + "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" + "option wpad code 252 = string;\n" + "\n" + "also request rfc3442-classless-static-routes;\n" + "also request ms-classless-static-routes;\n" + "also request static-routes;\n" + "also request wpad;\n" + "also request ntp-servers;\n" + "\n"; + +static void +test_existing_escaped_client_id (void) +{ + gs_unref_bytes GBytes *new_client_id = NULL; + + new_client_id = g_bytes_new ("$test\xfe", 6); + test_config (existing_escaped_client_id_orig, existing_escaped_client_id_expected, + AF_INET, NULL, 0, FALSE, + NULL, + new_client_id, + "eth0", + NULL); +} + +/*****************************************************************************/ + #define EACID "qb:cd:ef:12:34:56" static const char *existing_ascii_client_id_orig = \ - "send dhcp-client-identifier \"" EACID "\";\n"; + "send dhcp-client-identifier \"\\x00" EACID "\";\n"; static const char *existing_ascii_client_id_expected = \ "# Created by NetworkManager\n" "# Merged from /path/to/dhclient.conf\n" "\n" - "send dhcp-client-identifier \"" EACID "\";\n" + "send dhcp-client-identifier \"\\x00" EACID "\";\n" "\n" "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" @@ -585,23 +675,26 @@ test_existing_multiline_alsoreq (void) static void test_one_duid (const char *escaped, const guint8 *unescaped, guint len) { - GByteArray *t; + GBytes *t; char *w; + gsize t_len; + gconstpointer t_arr; t = nm_dhcp_dhclient_unescape_duid (escaped); g_assert (t); - g_assert_cmpint (t->len, ==, len); - g_assert_cmpint (memcmp (t->data, unescaped, len), ==, 0); - g_byte_array_free (t, TRUE); + t_arr = g_bytes_get_data (t, &t_len); + g_assert (t_arr); + g_assert_cmpint (t_len, ==, len); + g_assert_cmpint (memcmp (t_arr, unescaped, len), ==, 0); + g_bytes_unref (t); - t = g_byte_array_sized_new (len); - g_byte_array_append (t, unescaped, len); + t = g_bytes_new_static (unescaped, len); w = nm_dhcp_dhclient_escape_duid (t); g_assert (w); g_assert_cmpint (strlen (escaped), ==, strlen (w)); g_assert_cmpstr (escaped, ==, w); - g_byte_array_free (t, TRUE); + g_bytes_unref (t); g_free (w); } @@ -640,25 +733,26 @@ test_read_duid_from_leasefile (void) { const guint8 expected[] = { 0x00, 0x01, 0x00, 0x01, 0x18, 0x79, 0xa6, 0x13, 0x60, 0x67, 0x20, 0xec, 0x4c, 0x70 }; - GByteArray *duid; + gs_unref_bytes GBytes *duid = NULL; GError *error = NULL; + gconstpointer duid_arr; + gsize duid_len; - duid = nm_dhcp_dhclient_read_duid (TESTDIR "/test-dhclient-duid.leases", &error); + duid = nm_dhcp_dhclient_read_duid (TEST_DIR"/test-dhclient-duid.leases", &error); g_assert_no_error (error); g_assert (duid); - g_assert_cmpint (duid->len, ==, sizeof (expected)); - g_assert_cmpint (memcmp (duid->data, expected, duid->len), ==, 0); - - g_byte_array_free (duid, TRUE); + duid_arr = g_bytes_get_data (duid, &duid_len); + g_assert_cmpint (duid_len, ==, sizeof (expected)); + g_assert_cmpint (memcmp (duid_arr, expected, duid_len), ==, 0); } static void test_read_commented_duid_from_leasefile (void) { - GByteArray *duid; + GBytes *duid; GError *error = NULL; - duid = nm_dhcp_dhclient_read_duid (TESTDIR "/test-dhclient-commented-duid.leases", &error); + duid = nm_dhcp_dhclient_read_duid (TEST_DIR"/test-dhclient-commented-duid.leases", &error); g_assert_no_error (error); g_assert (duid == NULL); } @@ -754,12 +848,12 @@ test_write_existing_commented_duid (void) static const char *interface1_orig = \ "interface \"eth0\" {\n" - " also request my-option;\n" - " initial-delay 5;\n" + "\talso request my-option;\n" + "\tinitial-delay 5;\n" "}\n" "interface \"eth1\" {\n" - " also request another-option;\n" - " initial-delay 0;\n" + "\talso request another-option;\n" + "\tinitial-delay 0;\n" "}\n" "\n" "also request yet-another-option;\n"; @@ -798,12 +892,12 @@ test_interface1 (void) static const char *interface2_orig = \ "interface eth0 {\n" - " also request my-option;\n" - " initial-delay 5;\n" + "\talso request my-option;\n" + "\tinitial-delay 5;\n" " }\n" "interface eth1 {\n" - " initial-delay 0;\n" - " request another-option;\n" + "\tinitial-delay 0;\n" + "\trequest another-option;\n" " } \n" "\n" "also request yet-another-option;\n"; @@ -844,12 +938,12 @@ test_config_req_intf (void) { static const char *const orig = \ "request subnet-mask, broadcast-address, routers,\n" - " rfc3442-classless-static-routes,\n" - " interface-mtu, host-name, domain-name, domain-search,\n" - " domain-name-servers, nis-domain, nis-servers,\n" - " nds-context, nds-servers, nds-tree-name,\n" - " netbios-name-servers, netbios-dd-server,\n" - " netbios-node-type, netbios-scope, ntp-servers;\n" + "\trfc3442-classless-static-routes,\n" + "\tinterface-mtu, host-name, domain-name, domain-search,\n" + "\tdomain-name-servers, nis-domain, nis-servers,\n" + "\tnds-context, nds-servers, nds-tree-name,\n" + "\tnetbios-name-servers, netbios-dd-server,\n" + "\tnetbios-node-type, netbios-scope, ntp-servers;\n" ""; static const char *const expected = \ "# Created by NetworkManager\n" @@ -895,133 +989,6 @@ 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; - const char *path = TESTDIR "/leases/basic.leases"; - GSList *leases; - GDateTime *now; - NMIP4Config *config; - const NMPlatformIP4Address *addr; - guint32 expected_addr; - - success = g_file_get_contents (path, &contents, NULL, &error); - g_assert_no_error (error); - g_assert (success); - - /* 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 (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now); - g_assert_cmpint (g_slist_length (leases), ==, 2); - - /* IP4Config #1 */ - config = g_slist_nth_data (leases, 0); - g_assert (NM_IS_IP4_CONFIG (config)); - - /* Address */ - g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1); - 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 */ - 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); - 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); - - /* IP4Config #2 */ - config = g_slist_nth_data (leases, 1); - g_assert (NM_IS_IP4_CONFIG (config)); - - /* Address */ - g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1); - 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 */ - 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); - expected_addr = nmtst_inet4_from_string ("8.8.8.8"); - g_assert_cmpint (nm_ip4_config_get_nameserver (config, 0), ==, 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 */ - g_assert_cmpint (nm_ip4_config_get_num_domains (config), ==, 1); - g_assert_cmpstr (nm_ip4_config_get_domain (config, 0), ==, "morriesguest.local"); - - g_slist_free_full (leases, g_object_unref); - g_date_time_unref (now); - g_free (contents); -} - -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; - const char *path = TESTDIR "/leases/basic.leases"; - GSList *leases; - GDateTime *now; - - success = g_file_get_contents (path, &contents, NULL, &error); - g_assert_no_error (error); - g_assert (success); - - /* 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 (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now); - g_assert (leases == NULL); - - g_date_time_unref (now); - g_free (contents); -} - -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; - GSList *leases; - GDateTime *now; - - success = g_file_get_contents ((const char *) user_data, &contents, NULL, &error); - g_assert_no_error (error); - g_assert (success); - - /* 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 (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now); - g_assert (leases == NULL); - - g_date_time_unref (now); - g_free (contents); -} - -/*****************************************************************************/ - NMTST_DEFINE (); int @@ -1031,10 +998,13 @@ main (int argc, char **argv) g_test_add_func ("/dhcp/dhclient/orig_missing", test_orig_missing); g_test_add_func ("/dhcp/dhclient/override_client_id", test_override_client_id); - g_test_add_func ("/dhcp/dhclient/quote_client_id", test_quote_client_id); + g_test_add_func ("/dhcp/dhclient/quote_client_id/1", test_quote_client_id); + g_test_add_func ("/dhcp/dhclient/quote_client_id/2", test_quote_client_id_2); + g_test_add_func ("/dhcp/dhclient/hex_zero_client_id", test_hex_zero_client_id); g_test_add_func ("/dhcp/dhclient/ascii_client_id", test_ascii_client_id); g_test_add_func ("/dhcp/dhclient/hex_single_client_id", test_hex_single_client_id); g_test_add_func ("/dhcp/dhclient/existing-hex-client-id", test_existing_hex_client_id); + g_test_add_func ("/dhcp/dhclient/existing-client-id", test_existing_escaped_client_id); g_test_add_func ("/dhcp/dhclient/existing-ascii-client-id", test_existing_ascii_client_id); g_test_add_func ("/dhcp/dhclient/fqdn", test_fqdn); g_test_add_func ("/dhcp/dhclient/fqdn_options_override", test_fqdn_options_override); @@ -1056,18 +1026,6 @@ main (int argc, char **argv) g_test_add_func ("/dhcp/dhclient/write_existing_duid", test_write_existing_duid); g_test_add_func ("/dhcp/dhclient/write_existing_commented_duid", test_write_existing_commented_duid); - g_test_add_func ("/dhcp/dhclient/leases/ip4-config/basic", test_read_lease_ip4_config_basic); - g_test_add_func ("/dhcp/dhclient/leases/ip4-config/expired", test_read_lease_ip4_config_expired); - g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-address", - TESTDIR "/leases/malformed1.leases", - test_read_lease_ip4_config_expect_failure); - g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-gateway", - TESTDIR "/leases/malformed2.leases", - test_read_lease_ip4_config_expect_failure); - g_test_add_data_func ("/dhcp/dhclient/leases/ip4-config/missing-expire", - TESTDIR "/leases/malformed3.leases", - test_read_lease_ip4_config_expect_failure); - return g_test_run (); } diff --git a/src/dhcp/tests/test-dhcp-utils.c b/src/dhcp/tests/test-dhcp-utils.c index 72f31191..617a3c6c 100644 --- a/src/dhcp/tests/test-dhcp-utils.c +++ b/src/dhcp/tests/test-dhcp-utils.c @@ -349,8 +349,7 @@ test_dhclient_invalid_classless_routes_1 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, - "*ignoring invalid classless static routes*"); + NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -380,8 +379,7 @@ test_dhcpcd_invalid_classless_routes_1 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, - "*ignoring invalid classless static routes*"); + NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -413,8 +411,7 @@ test_dhclient_invalid_classless_routes_2 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, - "*ignoring invalid classless static routes*"); + NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -446,8 +443,7 @@ test_dhcpcd_invalid_classless_routes_2 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, - "*ignoring invalid classless static routes*"); + NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -479,8 +475,7 @@ test_dhclient_invalid_classless_routes_3 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, - "*ignoring invalid classless static routes*"); + NMTST_EXPECT_NM_WARN ("*ignoring invalid classless static routes*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -507,8 +502,7 @@ test_dhcpcd_invalid_classless_routes_3 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, - "*DHCP provided invalid classless static route*"); + NMTST_EXPECT_NM_WARN ("*DHCP provided invalid classless static route*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); @@ -615,8 +609,7 @@ test_invalid_escaped_domain_searches (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, - "*invalid domain search*"); + NMTST_EXPECT_NM_WARN ("*invalid domain search*"); ip4_config = _ip4_config_from_options (1, "eth0", options, 0); g_test_assert_expected_messages (); -- cgit 1.3.0-6-gf8a5