summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2015-10-03 19:44:27 +0200
committerLubomir Rintel <lkundrak@v3.sk>2015-11-02 20:27:36 +0100
commite603c86926ce48a7dd53b892fe85d506e6322378 (patch)
tree85e0e069ba9443b83ee850835021a525e71a6faf
parentf85728ecff824b1fece43aba51d8171db2766ea2 (diff)
core: add support for RFC7217 stable privacy addressing
RFC7217 introduces an alternative mechanism for creating addresses during stateless IPv6 address configuration. It's supposed to create addresses whose host part stays stable in a particular network but changes when the hosts enters another network to mitigate possibility of tracking the host movement. It can be used alongside RFC 4941 privacy extensions (temporary addresses) and replaces the use of RFC 4862 interface identifiers. The address creation mode is controlld by ip6.addr_gen_mode property (ADDR_GEN_MODE in ifcfg-rh), with values of "stable-privacy" and "eui-64", defaulting to "eui-64" if unspecified. The host part of an address is computed by hashing a system-specific secret salted with various stable values that identify the connection with a secure hash algorithm: RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) For NetworkManager we use these parameters: * F() SHA256 hash function. * Prefix This is a network part of the /64 address * Net_Iface We use the interface name (e.g. "eth0"). This ensures the address won't change with the change of interface hardware. * Network_ID We use the connection UUID here. This ensures the salt is different for wireless networks with a different SSID as suggested by RFC7217. * DAD_Counter A per-address counter that increases with each DAD failure. * secret_key We store the secret key in /var/lib/NetworkManager/secret_key. If it's shorter than 128 bits then it's rejected. If the file is not present we initialize it by fetching 256 pseudo-random bits from /dev/urandom on first use. Duplicate address detection uses IDGEN_RETRIES = 3 and does not utilize the IDGEN_DELAY delay (despite it SHOULD). This is for ease of implementation and may change in future. Neither parameter is currently configurable.
-rw-r--r--src/NetworkManagerUtils.c121
-rw-r--r--src/NetworkManagerUtils.h6
-rw-r--r--src/devices/nm-device.c83
-rw-r--r--src/nm-iface-helper.c5
-rw-r--r--src/rdisc/nm-lndp-rdisc.c4
-rw-r--r--src/rdisc/nm-lndp-rdisc.h2
-rw-r--r--src/rdisc/nm-rdisc.c29
-rw-r--r--src/rdisc/nm-rdisc.h3
-rw-r--r--src/rdisc/tests/test-rdisc-linux.c5
-rw-r--r--src/tests/Makefile.am22
-rw-r--r--src/tests/test-utils.c63
11 files changed, 314 insertions, 29 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index deab2a5869..cd8d717e96 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -29,6 +29,7 @@
#include <resolv.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/stat.h>
#include <linux/if.h>
#include <linux/if_infiniband.h>
@@ -3213,7 +3214,6 @@ nm_utils_get_ipv6_interface_identifier (NMLinkType link_type,
}
return FALSE;
}
-
void
nm_utils_ipv6_addr_set_interface_identfier (struct in6_addr *addr,
const NMUtilsIPv6IfaceId iid)
@@ -3228,6 +3228,125 @@ nm_utils_ipv6_interface_identfier_get_from_addr (NMUtilsIPv6IfaceId *iid,
memcpy (iid, addr->s6_addr + 8, 8);
}
+static gboolean
+_set_stable_privacy (struct in6_addr *addr,
+ const char *ifname,
+ const char *uuid,
+ guint dad_counter,
+ gchar *secret_key,
+ gsize key_len,
+ GError **error)
+{
+ GChecksum *sum;
+ guint8 digest[32];
+ guint32 tmp[2];
+ gsize len = sizeof (digest);
+
+ g_return_val_if_fail (key_len, FALSE);
+
+ /* Documentation suggests that this can fail.
+ * Maybe in case of a missing algorithm in crypto library? */
+ sum = g_checksum_new (G_CHECKSUM_SHA256);
+ if (!sum) {
+ g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+ "Can't create a SHA256 hash");
+ return FALSE;
+ }
+
+ key_len = CLAMP (key_len, 0, G_MAXUINT32);
+
+ g_checksum_update (sum, addr->s6_addr, 8);
+ g_checksum_update (sum, (const guchar *) ifname, strlen (ifname) + 1);
+ if (!uuid)
+ uuid = "";
+ g_checksum_update (sum, (const guchar *) uuid, strlen (uuid) + 1);
+ tmp[0] = htonl (dad_counter);
+ tmp[1] = htonl (key_len);
+ g_checksum_update (sum, (const guchar *) tmp, sizeof (tmp));
+ g_checksum_update (sum, (const guchar *) secret_key, key_len);
+
+ g_checksum_get_digest (sum, digest, &len);
+ g_checksum_free (sum);
+
+ g_return_val_if_fail (len == 32, FALSE);
+
+ memcpy (addr->s6_addr + 8, &digest[0], 8);
+
+ return TRUE;
+}
+
+#define RFC7217_IDGEN_RETRIES 3
+/**
+ * nm_utils_ipv6_addr_set_stable_privacy:
+ *
+ * Extend the address prefix with an interface identifier using the
+ * RFC 7217 Stable Privacy mechanism.
+ *
+ * Returns: %TRUE on success, %FALSE if the address could not be generated.
+ */
+gboolean
+nm_utils_ipv6_addr_set_stable_privacy (struct in6_addr *addr,
+ const char *ifname,
+ const char *uuid,
+ guint dad_counter,
+ GError **error)
+{
+ gchar *secret_key = NULL;
+ gsize key_len = 0;
+ gboolean success = FALSE;
+
+ if (dad_counter >= RFC7217_IDGEN_RETRIES) {
+ g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+ "Too many DAD collisions");
+ return FALSE;
+ }
+
+ /* Let's try to load a saved secret key first. */
+ if (g_file_get_contents (NMSTATEDIR "/secret_key", &secret_key, &key_len, NULL)) {
+ if (key_len < 16) {
+ g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+ "Key is too short to be usable");
+ key_len = 0;
+ }
+ } else {
+ int urandom = open ("/dev/urandom", O_RDONLY);
+ mode_t key_mask;
+
+ if (!urandom) {
+ g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+ "Can't open /dev/urandom: %s", strerror (errno));
+ return FALSE;
+ }
+
+ /* RFC7217 mandates the key SHOULD be at least 128 bits.
+ * Let's use twice as much. */
+ key_len = 32;
+ secret_key = g_malloc (key_len);
+
+ key_mask = umask (0077);
+ if (read (urandom, secret_key, key_len) == key_len) {
+ if (!g_file_set_contents (NMSTATEDIR "/secret_key", secret_key, key_len, error)) {
+ g_prefix_error (error, "Can't write " NMSTATEDIR "/secret_key");
+ key_len = 0;
+ }
+ } else {
+ g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+ "Could not obtain a secret");
+ key_len = 0;
+ }
+ umask (key_mask);
+ close (urandom);
+ }
+
+ if (key_len) {
+ success = _set_stable_privacy (addr, ifname, uuid, dad_counter,
+ secret_key, key_len, error);
+ }
+
+ g_free (secret_key);
+ return success;
+}
+
/**
* nm_utils_setpgid:
* @unused: unused
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index 3da2235559..2d29b5bb90 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -286,6 +286,12 @@ gboolean nm_utils_get_ipv6_interface_identifier (NMLinkType link_type,
void nm_utils_ipv6_addr_set_interface_identfier (struct in6_addr *addr,
const NMUtilsIPv6IfaceId iid);
+gboolean nm_utils_ipv6_addr_set_stable_privacy (struct in6_addr *addr,
+ const char *ifname,
+ const char *uuid,
+ guint dad_counter,
+ GError **error);
+
void nm_utils_ipv6_interface_identfier_get_from_addr (NMUtilsIPv6IfaceId *iid,
const struct in6_addr *addr);
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 4ce5eb4627..4b6d2d45fc 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -32,6 +32,7 @@
#include <arpa/inet.h>
#include <fcntl.h>
#include <netlink/route/addr.h>
+#include <linux/if_addr.h>
#include "nm-default.h"
#include "nm-device.h"
@@ -325,6 +326,7 @@ typedef struct {
NMIP6Config * ac_ip6_config;
guint linklocal6_timeout_id;
+ guint8 linklocal6_dad_counter;
GHashTable * ip6_saved_properties;
@@ -4832,9 +4834,11 @@ check_and_add_ipv6ll_addr (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ip_ifindex = nm_device_get_ip_ifindex (self);
- NMUtilsIPv6IfaceId iid;
struct in6_addr lladdr;
guint i, n;
+ NMConnection *connection;
+ NMSettingIP6Config *s_ip6 = NULL;
+ GError *error = NULL;
if (priv->nm_ipv6ll == FALSE)
return;
@@ -4853,21 +4857,43 @@ check_and_add_ipv6ll_addr (NMDevice *self)
}
}
- if (!nm_device_get_ip_iface_identifier (self, &iid)) {
- _LOGW (LOGD_IP6, "failed to get interface identifier; IPv6 may be broken");
- return;
- }
-
memset (&lladdr, 0, sizeof (lladdr));
lladdr.s6_addr16[0] = htons (0xfe80);
- nm_utils_ipv6_addr_set_interface_identfier (&lladdr, iid);
- if (priv->linklocal6_timeout_id) {
- /* We already started and attempt to add a LL address. For the EUI-64
- * mode we can't pick a new one, we'll just fail. */
- _LOGW (LOGD_IP6, "linklocal6: DAD failed for an EUI-64 address");
- linklocal6_failed (self);
- return;
+ connection = nm_device_get_applied_connection (self);
+ if (connection)
+ s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection));
+
+ if (s_ip6 && nm_setting_ip6_config_get_addr_gen_mode (s_ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ if (!nm_utils_ipv6_addr_set_stable_privacy (&lladdr,
+ nm_device_get_iface (self),
+ nm_connection_get_uuid (connection),
+ priv->linklocal6_dad_counter++,
+ &error)) {
+ _LOGW (LOGD_IP6, "linklocal6: failed to generate an address: %s", error->message);
+ g_clear_error (&error);
+ linklocal6_failed (self);
+ return;
+ }
+ _LOGD (LOGD_IP6, "linklocal6: using IPv6 stable-privacy addressing");
+ } else {
+ NMUtilsIPv6IfaceId iid;
+
+ if (priv->linklocal6_timeout_id) {
+ /* We already started and attempt to add a LL address. For the EUI-64
+ * mode we can't pick a new one, we'll just fail. */
+ _LOGW (LOGD_IP6, "linklocal6: DAD failed for an EUI-64 address");
+ linklocal6_failed (self);
+ return;
+ }
+
+ if (!nm_device_get_ip_iface_identifier (self, &iid)) {
+ _LOGW (LOGD_IP6, "linklocal6: failed to get interface identifier; IPv6 cannot continue");
+ return;
+ }
+ _LOGD (LOGD_IP6, "linklocal6: using EUI-64 identifier to generate IPv6LL address");
+
+ nm_utils_ipv6_addr_set_interface_identfier (&lladdr, iid);
}
_LOGD (LOGD_IP6, "linklocal6: adding IPv6LL address %s", nm_utils_inet6_ntop (&lladdr, NULL));
@@ -5143,10 +5169,15 @@ addrconf6_start_with_link_ready (NMDevice *self)
g_assert (priv->rdisc);
if (nm_platform_link_get_ipv6_token (NM_PLATFORM_GET, priv->ifindex, &iid)) {
- _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface);
- } else if (!nm_device_get_ip_iface_identifier (self, &iid)) {
- _LOGW (LOGD_IP6, "failed to get interface identifier; IPv6 cannot continue");
- return FALSE;
+ _LOGD (LOGD_IP6, "addrconf6: IPv6 tokenized identifier present");
+ nm_rdisc_set_iid (priv->rdisc, iid);
+ } else if (nm_device_get_ip_iface_identifier (self, &iid)) {
+ _LOGD (LOGD_IP6, "addrconf6: using the device EUI-64 identifier");
+ nm_rdisc_set_iid (priv->rdisc, iid);
+ } else {
+ /* Don't abort the addrconf at this point -- if rdisc needs the iid
+ * it will notice this itself. */
+ _LOGI (LOGD_IP6, "addrconf6: no interface identifier; IPv6 adddress creation may fail");
}
/* Apply any manual configuration before starting RA */
@@ -5167,7 +5198,6 @@ addrconf6_start_with_link_ready (NMDevice *self)
G_CALLBACK (rdisc_ra_timeout),
self);
- nm_rdisc_set_iid (priv->rdisc, iid);
nm_rdisc_start (priv->rdisc);
return TRUE;
}
@@ -5178,7 +5208,7 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
NMActStageReturn ret;
- const char *ip_iface = nm_device_get_ip_iface (self);
+ NMSettingIP6Config *s_ip6 = NULL;
connection = nm_device_get_applied_connection (self);
g_assert (connection);
@@ -5189,9 +5219,15 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
priv->ac_ip6_config = NULL;
}
- priv->rdisc = nm_lndp_rdisc_new (nm_device_get_ip_ifindex (self), ip_iface);
+ s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection));
+ g_assert (s_ip6);
+
+ priv->rdisc = nm_lndp_rdisc_new (nm_device_get_ip_ifindex (self),
+ nm_device_get_ip_iface (self),
+ nm_connection_get_uuid (connection),
+ nm_setting_ip6_config_get_addr_gen_mode (s_ip6));
if (!priv->rdisc) {
- _LOGE (LOGD_IP6, "failed to start router discovery (%s)", ip_iface);
+ _LOGE (LOGD_IP6, "addrconf6: failed to start router discovery");
return FALSE;
}
@@ -8627,6 +8663,8 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
priv->v4_commit_first_time = TRUE;
priv->v6_commit_first_time = TRUE;
+ priv->linklocal6_dad_counter = 0;
+
nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self);
nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self);
@@ -8875,6 +8913,9 @@ nm_device_spawn_iface_helper (NMDevice *self)
g_ptr_array_add (argv, hex_iid);
}
+ g_ptr_array_add (argv, g_strdup ("--addr-gen-mode"));
+ g_ptr_array_add (argv, g_strdup_printf ("%d", nm_setting_ip6_config_get_addr_gen_mode (NM_SETTING_IP6_CONFIG (s_ip6))));
+
configured = TRUE;
}
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index 93ea17e531..fdd714f918 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -44,6 +44,7 @@ extern unsigned int if_nametoindex (const char *__ifname);
#include "nm-rdisc.h"
#include "nm-lndp-rdisc.h"
#include "nm-utils.h"
+#include "nm-setting-ip6-config.h"
#if !defined(NM_DIST_VERSION)
# define NM_DIST_VERSION VERSION
@@ -69,6 +70,7 @@ static struct {
char *dhcp4_clientid;
char *dhcp4_hostname;
char *iid_str;
+ NMSettingIP6ConfigAddrGenMode addr_gen_mode;
char *logging_backend;
char *opt_log_level;
char *opt_log_domains;
@@ -292,6 +294,7 @@ do_early_setup (int *argc, char **argv[])
{ "priority4", '\0', 0, G_OPTION_ARG_INT64, &priority64_v4, N_("Route priority for IPv4"), N_("0") },
{ "priority6", '\0', 0, G_OPTION_ARG_INT64, &priority64_v6, N_("Route priority for IPv6"), N_("1024") },
{ "iid", 'e', 0, G_OPTION_ARG_STRING, &global_opt.iid_str, N_("Hex-encoded Interface Identifier"), "" },
+ { "addr-gen-mode", 'e', 0, G_OPTION_ARG_INT, &global_opt.addr_gen_mode, N_("IPv6 SLAAC address generation mode"), "eui64" },
{ "logging-backend", '\0', 0, G_OPTION_ARG_STRING, &global_opt.logging_backend, N_("The logging backend configuration value. See logging.backend in NetworkManager.conf"), NULL },
/* Logging/debugging */
@@ -470,7 +473,7 @@ main (int argc, char *argv[])
if (global_opt.slaac) {
nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, ifindex, TRUE);
- rdisc = nm_lndp_rdisc_new (ifindex, global_opt.ifname);
+ rdisc = nm_lndp_rdisc_new (ifindex, global_opt.ifname, global_opt.uuid, global_opt.addr_gen_mode);
g_assert (rdisc);
if (iid)
diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c
index fead72cba5..f0f56abb41 100644
--- a/src/rdisc/nm-lndp-rdisc.c
+++ b/src/rdisc/nm-lndp-rdisc.c
@@ -297,7 +297,7 @@ ipv6_sysctl_get (const char *ifname, const char *property, gint32 defval)
}
NMRDisc *
-nm_lndp_rdisc_new (int ifindex, const char *ifname)
+nm_lndp_rdisc_new (int ifindex, const char *ifname, const char *uuid, NMSettingIP6ConfigAddrGenMode addr_gen_mode)
{
NMRDisc *rdisc;
NMLNDPRDiscPrivate *priv;
@@ -307,6 +307,8 @@ nm_lndp_rdisc_new (int ifindex, const char *ifname)
rdisc->ifindex = ifindex;
rdisc->ifname = g_strdup (ifname);
+ rdisc->uuid = g_strdup (uuid);
+ rdisc->addr_gen_mode = addr_gen_mode;
rdisc->max_addresses = ipv6_sysctl_get (ifname, "max_addresses",
NM_RDISC_MAX_ADDRESSES_DEFAULT);
diff --git a/src/rdisc/nm-lndp-rdisc.h b/src/rdisc/nm-lndp-rdisc.h
index 407e1f9258..4172a3043a 100644
--- a/src/rdisc/nm-lndp-rdisc.h
+++ b/src/rdisc/nm-lndp-rdisc.h
@@ -44,6 +44,6 @@ typedef struct {
GType nm_lndp_rdisc_get_type (void);
-NMRDisc *nm_lndp_rdisc_new (int ifindex, const char *ifname);
+NMRDisc *nm_lndp_rdisc_new (int ifindex, const char *ifname, const char *uuid, NMSettingIP6ConfigAddrGenMode addr_gen_mode);
#endif /* __NETWORKMANAGER_LNDP_RDISC_H__ */
diff --git a/src/rdisc/nm-rdisc.c b/src/rdisc/nm-rdisc.c
index 66982f1163..37cc9ca8c2 100644
--- a/src/rdisc/nm-rdisc.c
+++ b/src/rdisc/nm-rdisc.c
@@ -30,6 +30,8 @@
#include "nm-default.h"
#include "nm-utils.h"
+#include <nm-setting-ip6-config.h>
+
#define _NMLOG_PREFIX_NAME "rdisc"
typedef struct {
@@ -104,6 +106,23 @@ nm_rdisc_add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new)
static gboolean
complete_address (NMRDisc *rdisc, NMRDiscAddress *addr)
{
+ GError *error = NULL;
+
+ if (rdisc->addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ if (!nm_utils_ipv6_addr_set_stable_privacy (&addr->address,
+ rdisc->ifname,
+ rdisc->uuid,
+ addr->dad_counter++,
+ &error)) {
+ _LOGW ("complete-address: failed to generate an stable-privacy address: %s",
+ error->message);
+ g_clear_error (&error);
+ return FALSE;
+ }
+ _LOGD ("complete-address: using an stable-privacy address");
+ return TRUE;
+ }
+
if (!rdisc->iid.id) {
_LOGW ("complete-address: can't generate an EUI-64 address: no interface identifier");
return FALSE;
@@ -268,7 +287,10 @@ nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new)
* the old identifier are removed. The caller should ensure the addresses
* will be reset by soliciting router advertisements.
*
- * Returns: %TRUE if the token was changed, %FALSE otherwise.
+ * In case the stable privacy addressing is used %FALSE is returned and
+ * addresses are left untouched.
+ *
+ * Returns: %TRUE if addresses need to be regenerated, %FALSE otherwise.
**/
gboolean
nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid)
@@ -277,6 +299,10 @@ nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid)
if (rdisc->iid.id != iid.id) {
rdisc->iid = iid;
+
+ if (rdisc->addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY)
+ return FALSE;
+
if (rdisc->addresses->len) {
_LOGD ("IPv6 interface identifier changed, flushing addresses");
g_array_remove_range (rdisc->addresses, 0, rdisc->addresses->len);
@@ -693,6 +719,7 @@ finalize (GObject *object)
NMRDisc *rdisc = NM_RDISC (object);
g_free (rdisc->ifname);
+ g_free (rdisc->uuid);
g_array_unref (rdisc->gateways);
g_array_unref (rdisc->addresses);
g_array_unref (rdisc->routes);
diff --git a/src/rdisc/nm-rdisc.h b/src/rdisc/nm-rdisc.h
index 4802e240fb..c150a72912 100644
--- a/src/rdisc/nm-rdisc.h
+++ b/src/rdisc/nm-rdisc.h
@@ -26,6 +26,7 @@
#include <netinet/in.h>
#include "nm-default.h"
+#include "nm-setting-ip6-config.h"
#include "NetworkManagerUtils.h"
#define NM_TYPE_RDISC (nm_rdisc_get_type ())
@@ -115,6 +116,8 @@ typedef struct {
int ifindex;
char *ifname;
+ char *uuid;
+ NMSettingIP6ConfigAddrGenMode addr_gen_mode;
NMUtilsIPv6IfaceId iid;
gint32 max_addresses;
gint32 rtr_solicitations;
diff --git a/src/rdisc/tests/test-rdisc-linux.c b/src/rdisc/tests/test-rdisc-linux.c
index 2d8cd080ac..a5b68494dd 100644
--- a/src/rdisc/tests/test-rdisc-linux.c
+++ b/src/rdisc/tests/test-rdisc-linux.c
@@ -61,7 +61,10 @@ main (int argc, char **argv)
return EXIT_FAILURE;
}
- rdisc = nm_lndp_rdisc_new (ifindex, ifname);
+ rdisc = nm_lndp_rdisc_new (ifindex,
+ ifname,
+ "8ce666e8-d34d-4fb1-b858-f15a7al28086",
+ NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64);
if (!rdisc) {
g_print ("Failed to create NMRDisc instance\n");
return EXIT_FAILURE;
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index c4dd716f38..219e0270ba 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -24,7 +24,8 @@ noinst_PROGRAMS = \
test-route-manager-fake \
test-dcb \
test-resolvconf-capture \
- test-wired-defname
+ test-wired-defname \
+ test-utils
####### ip4 config test #######
@@ -110,6 +111,22 @@ test_wired_defname_SOURCES = \
test_wired_defname_LDADD = \
$(top_builddir)/src/libNetworkManager.la
+####### utils test #######
+
+test_utils_SOURCES = \
+ test-utils.c
+
+test_utils_DEPENDENCIES = \
+ $(top_srcdir)/src/NetworkManagerUtils.c
+
+test_utils_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -DPREFIX=\"/nonexistent\" \
+ -DNMSTATEDIR=\"/nonsense\"
+
+test_utils_LDADD = \
+ $(top_builddir)/src/libNetworkManager.la
+
####### secret agent interface test #######
EXTRA_DIST = test-secret-agent.py
@@ -126,7 +143,8 @@ TESTS = \
test-resolvconf-capture \
test-general \
test-general-with-expect \
- test-wired-defname
+ test-wired-defname \
+ test-utils
if ENABLE_TESTS
diff --git a/src/tests/test-utils.c b/src/tests/test-utils.c
new file mode 100644
index 0000000000..79a7e68030
--- /dev/null
+++ b/src/tests/test-utils.c
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include "NetworkManagerUtils.c"
+
+#include "nm-test-utils.h"
+
+static void
+test_stable_privacy (void)
+{
+ struct in6_addr addr1;
+
+ inet_pton (AF_INET6, "1234::", &addr1);
+ _set_stable_privacy (&addr1, "eth666", "6b138152-9f3e-4b97-aaf7-e6e553f2a24e", 0, "key", 3, NULL);
+ nmtst_assert_ip6_address (&addr1, "1234::4ceb:14cd:3d54:793f");
+
+ /* We get an address without the UUID. */
+ inet_pton (AF_INET6, "1::", &addr1);
+ _set_stable_privacy (&addr1, "eth666", NULL, 384, "key", 3, NULL);
+ nmtst_assert_ip6_address (&addr1, "1::11aa:2530:9144:dafa");
+
+ /* We get a different address in a different network. */
+ inet_pton (AF_INET6, "2::", &addr1);
+ _set_stable_privacy (&addr1, "eth666", NULL, 384, "key", 3, NULL);
+ nmtst_assert_ip6_address (&addr1, "2::338e:8d:c11:8726");
+}
+
+/*******************************************/
+
+NMTST_DEFINE ();
+
+int
+main (int argc, char **argv)
+{
+ nmtst_init_with_logging (&argc, &argv, NULL, "ALL");
+
+ g_test_add_func ("/utils/stable_privacy", test_stable_privacy);
+
+ return g_test_run ();
+}