diff options
-rw-r--r-- | src/devices/nm-device.c | 3 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-client.c | 43 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-client.h | 7 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-dhclient.c | 14 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-dhcpcd.c | 3 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-manager.c | 12 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-manager.h | 3 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-systemd.c | 10 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-utils.c | 48 | ||||
-rw-r--r-- | src/dhcp-manager/nm-dhcp-utils.h | 2 |
10 files changed, 117 insertions, 28 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 2c4d4421b5..4269bc8ada 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -5992,7 +5992,8 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) priv->dhcp_timeout, priv->dhcp_anycast_address, (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, - nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6))); + nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)), + 0); if (tmp) g_byte_array_free (tmp, TRUE); diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 15eb7a9f09..ec981e0ead 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -41,6 +41,7 @@ enum { SIGNAL_STATE_CHANGED, + SIGNAL_PREFIX_DELEGATED, LAST_SIGNAL }; @@ -511,7 +512,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, const struct in6_addr *ll_addr, const char *hostname, gboolean info_only, - NMSettingIP6ConfigPrivacy privacy) + NMSettingIP6ConfigPrivacy privacy, + guint needed_prefixes) { NMDhcpClientPrivate *priv; gs_free char *str = NULL; @@ -544,7 +546,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, ll_addr, info_only, privacy, - priv->duid); + priv->duid, + needed_prefixes); } void @@ -709,6 +712,7 @@ nm_dhcp_client_handle_event (gpointer unused, guint32 new_state; GHashTable *str_options = NULL; GObject *ip_config = NULL; + NMPlatformIP6Address prefix = { 0, }; g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); g_return_val_if_fail (iface != NULL, FALSE); @@ -754,6 +758,7 @@ nm_dhcp_client_handle_event (gpointer unused, g_warn_if_fail (g_hash_table_size (str_options)); if (g_hash_table_size (str_options)) { if (priv->ipv6) { + prefix = nm_dhcp_utils_ip6_prefix_from_options (str_options); ip_config = (GObject *) nm_dhcp_utils_ip6_config_from_options (priv->ifindex, priv->iface, str_options, @@ -765,17 +770,26 @@ nm_dhcp_client_handle_event (gpointer unused, str_options, priv->priority); } - - /* Fail if no valid IP config was received */ - if (ip_config == NULL) { - _LOGW ("client bound but IP config not received"); - new_state = NM_DHCP_STATE_FAIL; - g_clear_pointer (&str_options, g_hash_table_unref); - } } } - nm_dhcp_client_set_state (self, new_state, ip_config, str_options); + if (!IN6_IS_ADDR_UNSPECIFIED (&prefix.address)) { + /* If we got an IPv6 prefix to delegate, we don't change the state + * of the DHCP client instance. Instead, we just signal the prefix + * to the device. */ + g_signal_emit (G_OBJECT (self), + signals[SIGNAL_PREFIX_DELEGATED], 0, + &prefix); + } else { + /* Fail if no valid IP config was received */ + if (new_state == NM_DHCP_STATE_BOUND && ip_config == NULL) { + _LOGW ("client bound but IP config not received"); + new_state = NM_DHCP_STATE_FAIL; + g_clear_pointer (&str_options, g_hash_table_unref); + } + + nm_dhcp_client_set_state (self, new_state, ip_config, str_options); + } if (str_options) g_hash_table_destroy (str_options); @@ -972,5 +986,12 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class) G_STRUCT_OFFSET (NMDhcpClientClass, state_changed), NULL, NULL, NULL, G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_OBJECT, G_TYPE_HASH_TABLE, G_TYPE_STRING); -} + signals[SIGNAL_PREFIX_DELEGATED] = + g_signal_new (NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDhcpClientClass, state_changed), + NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_POINTER); +} diff --git a/src/dhcp-manager/nm-dhcp-client.h b/src/dhcp-manager/nm-dhcp-client.h index 9a2d21f713..7a083ae7a3 100644 --- a/src/dhcp-manager/nm-dhcp-client.h +++ b/src/dhcp-manager/nm-dhcp-client.h @@ -40,6 +40,7 @@ #define NM_DHCP_CLIENT_TIMEOUT "timeout" #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, @@ -73,7 +74,8 @@ typedef struct { const struct in6_addr *ll_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - const GByteArray *duid); + const GByteArray *duid, + guint needed_prefixes); void (*stop) (NMDhcpClient *self, gboolean release, @@ -133,7 +135,8 @@ gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self, const struct in6_addr *ll_addr, const char *hostname, gboolean info_only, - NMSettingIP6ConfigPrivacy privacy); + NMSettingIP6ConfigPrivacy privacy, + guint needed_prefixes); void nm_dhcp_client_stop (NMDhcpClient *self, gboolean release); diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c index a055e54179..64d93744f2 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient.c +++ b/src/dhcp-manager/nm-dhcp-dhclient.c @@ -330,7 +330,8 @@ dhclient_start (NMDhcpClient *client, const char *mode_opt, const GByteArray *duid, gboolean release, - pid_t *out_pid) + pid_t *out_pid, + int prefixes) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); @@ -424,6 +425,8 @@ dhclient_start (NMDhcpClient *client, g_ptr_array_add (argv, (gpointer) "-6"); if (mode_opt) g_ptr_array_add (argv, (gpointer) mode_opt); + 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) nm_dhcp_helper_path); @@ -503,7 +506,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last if (priv->conf_file) { if (new_client_id) nm_dhcp_client_set_client_id (client, new_client_id); - success = dhclient_start (client, NULL, NULL, FALSE, NULL); + success = dhclient_start (client, NULL, NULL, FALSE, NULL, 0); } else _LOGW ("error creating dhclient configuration file"); @@ -516,7 +519,8 @@ ip6_start (NMDhcpClient *client, const struct in6_addr *ll_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - const GByteArray *duid) + const GByteArray *duid, + guint needed_prefixes) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); @@ -532,7 +536,7 @@ ip6_start (NMDhcpClient *client, return FALSE; } - return dhclient_start (client, info_only ? "-S" : "-N", duid, FALSE, NULL); + return dhclient_start (client, info_only ? "-S" : "-N", duid, FALSE, NULL, needed_prefixes); } static void @@ -557,7 +561,7 @@ stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) if (release) { pid_t rpid = -1; - if (dhclient_start (client, NULL, duid, TRUE, &rpid)) { + if (dhclient_start (client, NULL, duid, TRUE, &rpid, 0)) { /* Wait a few seconds for the release to happen */ nm_dhcp_client_stop_pid (rpid, nm_dhcp_client_get_iface (client)); } diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c index 6b7fe38bbf..c8643881fc 100644 --- a/src/dhcp-manager/nm-dhcp-dhcpcd.c +++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c @@ -185,7 +185,8 @@ ip6_start (NMDhcpClient *client, const struct in6_addr *ll_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - const GByteArray *duid) + const GByteArray *duid, + guint needed_prefixes) { NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client); diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index dee4039a5c..6cb5c105b9 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -166,7 +166,8 @@ client_start (NMDhcpManager *self, const char *fqdn, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - const char *last_ip4_address) + const char *last_ip4_address, + guint needed_prefixes) { NMDhcpManagerPrivate *priv; NMDhcpClient *client; @@ -206,7 +207,7 @@ client_start (NMDhcpManager *self, g_signal_connect (client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (client_state_changed), self); if (ipv6) - success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy); + success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy, needed_prefixes); else success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, fqdn, last_ip4_address); @@ -254,7 +255,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self, } return client_start (self, iface, ifindex, hwaddr, uuid, priority, FALSE, NULL, dhcp_client_id, timeout, dhcp_anycast_addr, hostname, - fqdn, FALSE, 0, last_ip_address); + fqdn, FALSE, 0, last_ip_address, 0); } /* Caller owns a reference to the NMDhcpClient on return */ @@ -271,7 +272,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, guint32 timeout, const char *dhcp_anycast_addr, gboolean info_only, - NMSettingIP6ConfigPrivacy privacy) + NMSettingIP6ConfigPrivacy privacy, + guint needed_prefixes) { const char *hostname = NULL; @@ -281,7 +283,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, hostname = get_send_hostname (self, dhcp_hostname); return client_start (self, iface, ifindex, hwaddr, uuid, priority, TRUE, ll_addr, NULL, timeout, dhcp_anycast_addr, hostname, NULL, info_only, - privacy, NULL); + privacy, NULL, needed_prefixes); } void diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h index e525180d43..a948b60970 100644 --- a/src/dhcp-manager/nm-dhcp-manager.h +++ b/src/dhcp-manager/nm-dhcp-manager.h @@ -69,7 +69,8 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, guint32 timeout, const char *dhcp_anycast_addr, gboolean info_only, - NMSettingIP6ConfigPrivacy privacy); + NMSettingIP6ConfigPrivacy privacy, + guint needed_prefixes); GSList * nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self, const char *iface, diff --git a/src/dhcp-manager/nm-dhcp-systemd.c b/src/dhcp-manager/nm-dhcp-systemd.c index 4e3f85deb9..b6c9e27c17 100644 --- a/src/dhcp-manager/nm-dhcp-systemd.c +++ b/src/dhcp-manager/nm-dhcp-systemd.c @@ -894,7 +894,8 @@ ip6_start (NMDhcpClient *client, const struct in6_addr *ll_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - const GByteArray *duid) + const GByteArray *duid, + guint needed_prefixes) { NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); @@ -916,7 +917,12 @@ ip6_start (NMDhcpClient *client, return FALSE; } - _LOGT ("dhcp-client6: set %p", priv->client4); + if (needed_prefixes > 0) { + _LOGW ("dhcp-client6: prefix delegation not yet supported, won't supply %d prefixes\n", + needed_prefixes); + } + + _LOGT ("dhcp-client6: set %p", priv->client6); if (info_only) sd_dhcp6_client_set_information_request (priv->client6, 1); diff --git a/src/dhcp-manager/nm-dhcp-utils.c b/src/dhcp-manager/nm-dhcp-utils.c index 0fdc31a46d..4205d021b7 100644 --- a/src/dhcp-manager/nm-dhcp-utils.c +++ b/src/dhcp-manager/nm-dhcp-utils.c @@ -604,6 +604,54 @@ ip6_add_domain_search (gpointer data, gpointer user_data) nm_ip6_config_add_search (NM_IP6_CONFIG (user_data), (const char *) data); } +NMPlatformIP6Address +nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options) +{ + gs_strfreev gchar **split_addr = NULL; + NMPlatformIP6Address address = { 0, }; + struct in6_addr tmp_addr; + char *str = NULL; + int prefix; + + g_return_val_if_fail (options != NULL, address); + + str = g_hash_table_lookup (options, "ip6_prefix"); + if (!str) + return address; + + split_addr = g_strsplit (str, "/", 2); + if (split_addr[0] == NULL && split_addr[1] == NULL) { + nm_log_warn (LOGD_DHCP6, "DHCP returned prefix without length '%s'", str); + return address; + } + + if (!inet_pton (AF_INET6, split_addr[0], &tmp_addr)) { + nm_log_warn (LOGD_DHCP6, "DHCP returned invalid prefix '%s'", str); + return address; + } + + prefix = _nm_utils_ascii_str_to_int64 (split_addr[1], 10, 0, 128, -1); + if (prefix < 0) { + nm_log_warn (LOGD_DHCP6, "DHCP returned prefix with invalid length '%s'", str); + return address; + } + + address.address = tmp_addr; + address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; + address.plen = prefix; + address.timestamp = nm_utils_get_monotonic_timestamp_s (); + + str = g_hash_table_lookup (options, "max_life"); + if (str) + address.lifetime = strtoul (str, NULL, 10); + + str = g_hash_table_lookup (options, "preferred_life"); + if (str) + address.preferred = strtoul (str, NULL, 10); + + return address; +} + NMIP6Config * nm_dhcp_utils_ip6_config_from_options (int ifindex, const char *iface, diff --git a/src/dhcp-manager/nm-dhcp-utils.h b/src/dhcp-manager/nm-dhcp-utils.h index 6540b1ff80..b45c5e89a2 100644 --- a/src/dhcp-manager/nm-dhcp-utils.h +++ b/src/dhcp-manager/nm-dhcp-utils.h @@ -35,6 +35,8 @@ NMIP6Config *nm_dhcp_utils_ip6_config_from_options (int ifindex, guint priority, gboolean info_only); +NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options); + char * nm_dhcp_utils_duid_to_string (const GByteArray *duid); GBytes * nm_dhcp_utils_client_id_string_to_bytes (const char *client_id); |