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-01 08:09:11 +0100
commit4b9dfb8ae063b2a2d136ec780b85d1541877330c (patch)
treea8e7ee0a3e11e8689470823eb2fa6df1e684c3f1
parent1877e2e5fc38204af8b82f3d266decffb4022397 (diff)
downloadNetworkManager-4b9dfb8ae063b2a2d136ec780b85d1541877330c.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/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
9 files changed, 115 insertions, 27 deletions
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);