summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-01-03 17:03:35 +0100
committerThomas Haller <thaller@redhat.com>2014-01-30 17:04:36 +0100
commit1dea2714697b8cfe386c6665d7e556d537bebaf0 (patch)
tree4afa77dd1ae1b8b3f338504c36a9e08435fb0a21
parent39cbe772a67aece69dc30f8f394bba2eea9ca762 (diff)
downloadNetworkManager-1dea2714697b8cfe386c6665d7e556d537bebaf0.tar.gz
core/rdisc: add support for IPv6 privacy
Add support for ipv6-private addresses. This feature needs support from the kernel and libnl. If there is no system support, temporary addresses are not supported. Log a warning in this case. Depending on whether ipv6-privacy (use_tempaddr) is enabled, we add the address flag IFA_F_MANAGETEMPADDR and the kernel will add temporary addresses for us. https://bugzilla.gnome.org/show_bug.cgi?id=705170 https://bugzilla.redhat.com/show_bug.cgi?id=1003859 https://bugzilla.redhat.com/show_bug.cgi?id=1047139 Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r--src/devices/nm-device.c124
1 files changed, 96 insertions, 28 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index c6581b4b61..50440d09dd 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -75,7 +75,10 @@
#include "nm-device-bond.h"
#include "nm-device-team.h"
-/* workaround for older libnl version, that does not define this flag. */
+/* workaround for older libnl version, that does not define these flags. */
+#ifndef IFA_F_MANAGETEMPADDR
+#define IFA_F_MANAGETEMPADDR 0x100
+#endif
#ifndef IFA_F_NOPREFIXROUTE
#define IFA_F_NOPREFIXROUTE 0x200
#endif
@@ -282,6 +285,7 @@ typedef struct {
NMRDisc * rdisc;
gulong rdisc_config_changed_sigid;
+ NMSettingIP6ConfigPrivacy rdisc_use_tempaddr;
/* IP6 config from autoconf */
NMIP6Config * ac_ip6_config;
@@ -3313,6 +3317,53 @@ linklocal6_start (NMDevice *self)
static void dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release);
static void
+print_support_extended_ifa_flags (NMSettingIP6ConfigPrivacy use_tempaddr)
+{
+ static gint8 warn = 0;
+ static gint8 s_libnl = -1, s_kernel;
+
+ if (warn >= 2)
+ return;
+
+ if (s_libnl == -1) {
+ s_libnl = !!nm_platform_check_support_libnl_extended_ifa_flags ();
+ s_kernel = !!nm_platform_check_support_kernel_extended_ifa_flags ();
+
+ if (s_libnl && s_kernel) {
+ nm_log_dbg (LOGD_IP6, "kernel and libnl support extended IFA_FLAGS (needed by NM for IPv6 private addresses)");
+ warn = 2;
+ return;
+ }
+ }
+
+ if ( use_tempaddr != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
+ && use_tempaddr != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) {
+ if (warn == 0) {
+ nm_log_dbg (LOGD_IP6, "%s%s%s %s not support extended IFA_FLAGS (needed by NM for IPv6 private addresses)",
+ !s_kernel ? "kernel" : "",
+ !s_kernel && !s_libnl ? " and " : "",
+ !s_libnl ? "libnl" : "",
+ !s_kernel && !s_libnl ? "do" : "does");
+ warn = 1;
+ }
+ return;
+ }
+
+ if (!s_libnl && !s_kernel) {
+ nm_log_warn (LOGD_IP6, "libnl and the kernel do not support extended IFA_FLAGS needed by NM for "
+ "IPv6 private addresses. This feature is not available");
+ } else if (!s_libnl) {
+ nm_log_warn (LOGD_IP6, "libnl does not support extended IFA_FLAGS needed by NM for "
+ "IPv6 private addresses. This feature is not available");
+ } else if (!s_kernel) {
+ nm_log_warn (LOGD_IP6, "The kernel does not support extended IFA_FLAGS needed by NM for "
+ "IPv6 private addresses. This feature is not available");
+ }
+
+ warn = 2;
+}
+
+static void
rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
@@ -3326,18 +3377,21 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device
/*
* Check, if both libnl and the kernel are recent enough,
* to help user space handling RA. If it's not supported,
- * we must add autoconf addresses as /128.
- * The reason for /128 is to prevent the kernel from adding
- * a prefix route for this address.
+ * we have no ipv6-privacy and must add autoconf addresses
+ * as /128. The reason for the /128 is to prevent the kernel
+ * from adding a prefix route for this address.
**/
system_support = nm_platform_check_support_libnl_extended_ifa_flags () &&
nm_platform_check_support_kernel_extended_ifa_flags ();
}
- /* without system_support, this flag will be ignored.
- * Still, we set it (why not?).
+ /* without system_support, these flags will be ignored.
+ * Still, we set them (why not?).
**/
ifa_flags = IFA_F_NOPREFIXROUTE;
+ if (priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
+ || priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
+ ifa_flags |= IFA_F_MANAGETEMPADDR;
g_return_if_fail (priv->act_request);
connection = nm_device_get_connection (device);
@@ -3458,7 +3512,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device
}
static gboolean
-addrconf6_start (NMDevice *self)
+addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
@@ -3481,6 +3535,9 @@ addrconf6_start (NMDevice *self)
return FALSE;
}
+ priv->rdisc_use_tempaddr = use_tempaddr;
+ print_support_extended_ifa_flags (use_tempaddr);
+
/* ensure link local is ready... */
ret = linklocal6_start (self);
if (ret == NM_ACT_STAGE_RETURN_SUCCESS)
@@ -3527,10 +3584,23 @@ addrconf6_cleanup (NMDevice *self)
/******************************************/
+static NMSettingIP6ConfigPrivacy
+use_tempaddr_clamp (NMSettingIP6ConfigPrivacy use_tempaddr)
+{
+ switch (use_tempaddr) {
+ case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED:
+ case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR:
+ case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR:
+ return use_tempaddr;
+ default:
+ return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
+ }
+}
+
/* Get net.ipv6.conf.default.use_tempaddr value from /etc/sysctl.conf or
* /lib/sysctl.d/sysctl.conf
*/
-static int
+static NMSettingIP6ConfigPrivacy
ip6_use_tempaddr (void)
{
char *contents = NULL;
@@ -3538,12 +3608,13 @@ ip6_use_tempaddr (void)
char *sysctl_data = NULL;
GKeyFile *keyfile;
GError *error = NULL;
- int tmp, ret = -1;
+ gint tmp;
+ NMSettingIP6ConfigPrivacy ret = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
/* Read file contents to a string. */
if (!g_file_get_contents ("/etc/sysctl.conf", &contents, NULL, NULL))
if (!g_file_get_contents ("/lib/sysctl.d/sysctl.conf", &contents, NULL, NULL))
- return -1;
+ return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
/* Prepend a group so that we can use GKeyFile parser. */
sysctl_data = g_strdup_printf ("%s%s", group_name, contents);
@@ -3554,7 +3625,7 @@ ip6_use_tempaddr (void)
tmp = g_key_file_get_integer (keyfile, "forged_group", "net.ipv6.conf.default.use_tempaddr", &error);
if (error == NULL)
- ret = tmp;
+ ret = use_tempaddr_clamp (tmp);
done:
g_free (contents);
@@ -3591,7 +3662,6 @@ act_stage3_ip6_config_start (NMDevice *self,
NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
NMConnection *connection;
const char *method;
- int conf_use_tempaddr;
NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
const char *ip6_privacy_str = "0\n";
GSList *slaves;
@@ -3643,8 +3713,21 @@ act_stage3_ip6_config_start (NMDevice *self,
/* Re-enable IPv6 on the interface */
nm_platform_sysctl_set (priv->ip6_disable_ipv6_path, "0");
+ /* Enable/disable IPv6 Privacy Extensions.
+ * If a global value is configured by sysadmin (e.g. /etc/sysctl.conf),
+ * use that value instead of per-connection value.
+ */
+ ip6_privacy = ip6_use_tempaddr ();
+ if (ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) {
+ NMSettingIP6Config *s_ip6 = nm_connection_get_setting_ip6_config (connection);
+
+ if (s_ip6)
+ ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (s_ip6);
+ }
+ ip6_privacy = use_tempaddr_clamp (ip6_privacy);
+
if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) {
- if (!addrconf6_start (self)) {
+ if (!addrconf6_start (self, ip6_privacy)) {
/* IPv6 might be disabled; allow IPv4 to proceed */
ret = NM_ACT_STAGE_RETURN_STOP;
} else
@@ -3672,21 +3755,6 @@ act_stage3_ip6_config_start (NMDevice *self,
/* Other methods (shared) aren't implemented yet */
- /* Enable/disable IPv6 Privacy Extensions.
- * If a global value is configured by sysadmin (e.g. /etc/sysctl.conf),
- * use that value instead of per-connection value.
- */
- conf_use_tempaddr = ip6_use_tempaddr ();
- if (conf_use_tempaddr >= 0)
- ip6_privacy = conf_use_tempaddr;
- else {
- NMSettingIP6Config *s_ip6 = nm_connection_get_setting_ip6_config (connection);
-
- if (s_ip6)
- ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (s_ip6);
- }
- ip6_privacy = CLAMP (ip6_privacy, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR);
-
switch (ip6_privacy) {
case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN:
case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: