summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2016-10-31 23:30:37 +0100
committerLubomir Rintel <lkundrak@v3.sk>2016-11-09 17:23:32 +0100
commit4ec37b0364d399d38a9d3634a01a6d0249b26330 (patch)
treea29e7ac2cf5aa1d1bb7a24a7889687c970b69f17
parent7d195856cc057f18964f69925739a36b9c29b1ec (diff)
downloadNetworkManager-4ec37b0364d399d38a9d3634a01a6d0249b26330.tar.gz
dhcp-manager: add ability to specify the number of IPv6 prefixes to request
Utilizes RFC 3633 prefix option in role of requesting router to ask the delegating router for prefixes. In future we'll be able to use the addresses from those prefixes on ipv6.method=shared connections.
-rw-r--r--src/devices/nm-device.c3
-rw-r--r--src/dhcp-manager/nm-dhcp-client.c43
-rw-r--r--src/dhcp-manager/nm-dhcp-client.h7
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient.c14
-rw-r--r--src/dhcp-manager/nm-dhcp-dhcpcd.c3
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.c12
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.h3
-rw-r--r--src/dhcp-manager/nm-dhcp-systemd.c10
-rw-r--r--src/dhcp-manager/nm-dhcp-utils.c48
-rw-r--r--src/dhcp-manager/nm-dhcp-utils.h2
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);