diff options
author | Thomas Haller <thaller@redhat.com> | 2014-01-03 17:03:35 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2014-01-30 17:04:36 +0100 |
commit | 1dea2714697b8cfe386c6665d7e556d537bebaf0 (patch) | |
tree | 4afa77dd1ae1b8b3f338504c36a9e08435fb0a21 | |
parent | 39cbe772a67aece69dc30f8f394bba2eea9ca762 (diff) | |
download | NetworkManager-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.c | 124 |
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: |