core: add support for IPv6 Privacy Extensions for SLAAC (RFC4941) (bgo #633233)

This commit is contained in:
Jiří Klimeš 2012-02-21 15:44:19 +01:00
parent 96378dfa82
commit d376270bfe

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2005 - 2011 Red Hat, Inc.
* Copyright (C) 2005 - 2012 Red Hat, Inc.
* Copyright (C) 2006 - 2008 Novell, Inc.
*/
@ -38,6 +38,7 @@
#include "nm-glib-compat.h"
#include "nm-device.h"
#include "nm-device-private.h"
#include "backends/nm-backend.h"
#include "NetworkManagerUtils.h"
#include "nm-system.h"
#include "nm-dhcp-manager.h"
@ -206,6 +207,10 @@ typedef struct {
char * ip6_accept_ra_path;
gint32 ip6_accept_ra_save;
/* IPv6 privacy extensions (RFC4941) */
char * ip6_privacy_tempaddr_path;
gint32 ip6_privacy_tempaddr_save;
NMDHCPClient * dhcp6_client;
guint32 dhcp6_mode;
gulong dhcp6_state_sigid;
@ -290,6 +295,41 @@ update_accept_ra_save (NMDevice *self)
}
}
static void
update_ip6_privacy_save (NMDevice *self)
{
NMDevicePrivate *priv;
const char *ip_iface;
char *new_path;
g_return_if_fail (self != NULL);
g_return_if_fail (NM_IS_DEVICE (self));
priv = NM_DEVICE_GET_PRIVATE (self);
ip_iface = nm_device_get_ip_iface (self);
new_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/use_tempaddr", ip_iface);
g_assert (new_path);
if (priv->ip6_privacy_tempaddr_path) {
/* If the IP iface is different from before, use the new value */
if (!strcmp (new_path, priv->ip6_privacy_tempaddr_path)) {
g_free (new_path);
return;
}
g_free (priv->ip6_privacy_tempaddr_path);
}
/* Grab the original value of "use_tempaddr" so we can restore it when NM exits */
priv->ip6_privacy_tempaddr_path = new_path;
if (!nm_utils_get_proc_sys_net_value (priv->ip6_privacy_tempaddr_path,
ip_iface,
&priv->ip6_privacy_tempaddr_save)) {
g_free (priv->ip6_privacy_tempaddr_path);
priv->ip6_privacy_tempaddr_path = NULL;
}
}
static GObject*
constructor (GType type,
guint n_construct_params,
@ -329,6 +369,7 @@ constructor (GType type,
priv->fw_manager = nm_firewall_manager_get ();
update_accept_ra_save (dev);
update_ip6_privacy_save (dev);
priv->initialized = TRUE;
return object;
@ -723,6 +764,14 @@ nm_device_complete_connection (NMDevice *self,
if (success)
success = nm_connection_verify (connection, error);
/* If ip6-privacy is unknown, enable it with temporary address preferred */
if (success) {
NMSettingIP6Config *s_ip6 = nm_connection_get_setting_ip6_config (connection);
if (s_ip6 && nm_setting_ip6_config_get_ip6_privacy (s_ip6) == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN)
g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_IP6_PRIVACY,
NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, NULL);
}
return success;
}
@ -2126,6 +2175,10 @@ real_act_stage3_ip6_config_start (NMDevice *self,
const char *ip_iface;
NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
NMConnection *connection;
NMSettingIP6Config *s_ip6;
int conf_use_tempaddr;
NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
const char *ip6_privacy_str = "0\n";
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
@ -2135,6 +2188,7 @@ real_act_stage3_ip6_config_start (NMDevice *self,
ip_iface = nm_device_get_ip_iface (self);
update_accept_ra_save (self);
update_ip6_privacy_save (self);
priv->dhcp6_mode = IP6_DHCP_OPT_NONE;
@ -2175,6 +2229,36 @@ real_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 = nm_backend_ipv6_use_tempaddr ();
if (conf_use_tempaddr >= 0)
ip6_privacy = conf_use_tempaddr;
else {
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 = ip6_privacy < -1 ? NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN : ip6_privacy;
ip6_privacy = ip6_privacy > 2 ? NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR : ip6_privacy;
switch (ip6_privacy) {
case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN:
case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED:
ip6_privacy_str = "0\n";
break;
case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR:
ip6_privacy_str = "1\n";
break;
case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR:
ip6_privacy_str = "2\n";
break;
}
if (priv->ip6_privacy_tempaddr_path)
nm_utils_do_sysctl (priv->ip6_privacy_tempaddr_path, ip6_privacy_str);
return ret;
}
@ -3039,6 +3123,10 @@ nm_device_deactivate (NMDevice *self, NMDeviceStateReason reason)
if (priv->ip6_accept_ra_path)
nm_utils_do_sysctl (priv->ip6_accept_ra_path, "0\n");
/* Turn off IPv6 privacy extensions */
if (priv->ip6_privacy_tempaddr_path)
nm_utils_do_sysctl (priv->ip6_privacy_tempaddr_path, "0\n");
/* Call device type-specific deactivation */
if (NM_DEVICE_GET_CLASS (self)->deactivate)
NM_DEVICE_GET_CLASS (self)->deactivate (self);
@ -3523,6 +3611,15 @@ dispose (GObject *object)
}
g_free (priv->ip6_accept_ra_path);
/* reset the saved use_tempaddr value */
if (priv->ip6_privacy_tempaddr_path) {
char tmp[16];
snprintf (tmp, sizeof (tmp), "%d\n", priv->ip6_privacy_tempaddr_save);
nm_utils_do_sysctl (priv->ip6_privacy_tempaddr_path, tmp);
}
g_free (priv->ip6_privacy_tempaddr_path);
activation_source_clear (self, TRUE, AF_INET);
activation_source_clear (self, TRUE, AF_INET6);