From 7926b3ca95f2c0c611e271f805437cca9dc004ea Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 May 2010 03:42:43 -0700 Subject: [PATCH] ip6: turn RA acceptance off when RAs shouldn't be used (rh #588163) Make sure we don't inadvertenly let the kernel assign an RA address when connections that don't allow RA are used. --- src/NetworkManagerUtils.c | 29 ++++++++++++++ src/NetworkManagerUtils.h | 4 ++ src/ip6-manager/nm-ip6-manager.c | 63 ++++-------------------------- src/ip6-manager/nm-ip6-manager.h | 3 +- src/nm-device.c | 66 +++++++++++++++++++++++++++++++- 5 files changed, 107 insertions(+), 58 deletions(-) diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 4bd57d9944..fe64e1fea7 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -594,3 +594,32 @@ nm_utils_do_sysctl (const char *path, const char *value) return TRUE; } +gboolean +nm_utils_get_proc_sys_net_value (const char *path, + const char *iface, + guint32 *out_value) +{ + GError *error = NULL; + char *contents = NULL; + gboolean success = FALSE; + long int tmp; + + if (!g_file_get_contents (path, &contents, NULL, &error)) { + nm_log_warn (LOGD_DEVICE, "(%s): error reading %s: (%d) %s", + iface, path, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } else { + errno = 0; + tmp = strtol (contents, NULL, 10); + if ((errno == 0) && (tmp == 0 || tmp == 1)) { + *out_value = (guint32) tmp; + success = TRUE; + } + g_free (contents); + } + + return success; +} + diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index fa8b598db2..e3d1793b4d 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -73,4 +73,8 @@ void value_hash_add_bool (GHashTable *hash, gboolean nm_utils_do_sysctl (const char *path, const char *value); +gboolean nm_utils_get_proc_sys_net_value (const char *path, + const char *iface, + guint32 *out_value); + #endif /* NETWORK_MANAGER_UTILS_H */ diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 5101faf2a8..333638adb3 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -83,10 +83,6 @@ typedef struct { char *iface; int ifindex; - char *accept_ra_path; - gboolean accept_ra_save_valid; - guint32 accept_ra_save; - char *disable_ip6_path; gboolean disable_ip6_save_valid; guint32 disable_ip6_save; @@ -111,12 +107,6 @@ nm_ip6_device_destroy (NMIP6Device *device) { g_return_if_fail (device != NULL); - /* reset the saved RA value */ - if (device->accept_ra_save_valid) { - nm_utils_do_sysctl (device->accept_ra_path, - device->accept_ra_save ? "1\n" : "0\n"); - } - /* reset the saved IPv6 value */ if (device->disable_ip6_save_valid) { nm_utils_do_sysctl (device->disable_ip6_path, @@ -135,37 +125,9 @@ nm_ip6_device_destroy (NMIP6Device *device) if (device->ip6flags_poll_id) g_source_remove (device->ip6flags_poll_id); - g_free (device->accept_ra_path); g_slice_free (NMIP6Device, device); } -static gboolean -get_proc_sys_net_value (const char *path, const char *iface, guint32 *out_value) -{ - GError *error = NULL; - char *contents = NULL; - gboolean success = FALSE; - long int tmp; - - if (!g_file_get_contents (path, &contents, NULL, &error)) { - nm_log_warn (LOGD_IP6, "(%s): error reading %s: (%d) %s", - iface, path, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } else { - errno = 0; - tmp = strtol (contents, NULL, 10); - if ((errno == 0) && (tmp == 0 || tmp == 1)) { - *out_value = (guint32) tmp; - success = TRUE; - } - g_free (contents); - } - - return success; -} - static NMIP6Device * nm_ip6_device_new (NMIP6Manager *manager, int ifindex) { @@ -195,23 +157,13 @@ nm_ip6_device_new (NMIP6Manager *manager, int ifindex) g_hash_table_replace (priv->devices, GINT_TO_POINTER (device->ifindex), device); - /* Grab the original value of "accept_ra" so we can restore it when the - * device is taken down. - */ - device->accept_ra_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra", - device->iface); - g_assert (device->accept_ra_path); - device->accept_ra_save_valid = get_proc_sys_net_value (device->accept_ra_path, - device->iface, - &device->accept_ra_save); - /* and the original value of IPv6 enable/disable */ device->disable_ip6_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6", device->iface); g_assert (device->disable_ip6_path); - device->disable_ip6_save_valid = get_proc_sys_net_value (device->disable_ip6_path, - device->iface, - &device->disable_ip6_save); + device->disable_ip6_save_valid = nm_utils_get_proc_sys_net_value (device->disable_ip6_path, + device->iface, + &device->disable_ip6_save); return device; @@ -835,8 +787,9 @@ netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer us void nm_ip6_manager_prepare_interface (NMIP6Manager *manager, - int ifindex, - NMSettingIP6Config *s_ip6) + int ifindex, + NMSettingIP6Config *s_ip6, + const char *accept_ra_path) { NMIP6ManagerPrivate *priv; NMIP6Device *device; @@ -861,10 +814,10 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager, /* Establish target state and turn router advertisement acceptance on or off */ if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { device->target_state = NM_IP6_DEVICE_GOT_LINK_LOCAL; - nm_utils_do_sysctl (device->accept_ra_path, "0\n"); + nm_utils_do_sysctl (accept_ra_path, "0\n"); } else { device->target_state = NM_IP6_DEVICE_GOT_ADDRESS; - nm_utils_do_sysctl (device->accept_ra_path, "1\n"); + nm_utils_do_sysctl (accept_ra_path, "1\n"); } } diff --git a/src/ip6-manager/nm-ip6-manager.h b/src/ip6-manager/nm-ip6-manager.h index 7cd0ef70e6..77c1106841 100644 --- a/src/ip6-manager/nm-ip6-manager.h +++ b/src/ip6-manager/nm-ip6-manager.h @@ -73,7 +73,8 @@ GType nm_ip6_manager_get_type (void); NMIP6Manager *nm_ip6_manager_get (void); void nm_ip6_manager_prepare_interface (NMIP6Manager *manager, int ifindex, - NMSettingIP6Config *s_ip6); + NMSettingIP6Config *s_ip6, + const char *accept_ra_path); void nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, int ifindex); void nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager, diff --git a/src/nm-device.c b/src/nm-device.c index d8f7b64f02..88c57ba75b 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -135,6 +135,9 @@ typedef struct { gulong ip6_config_changed_sigid; gboolean ip6_waiting_for_config; + char * ip6_accept_ra_path; + guint32 ip6_accept_ra_save; + NMDHCPClient * dhcp6_client; guint32 dhcp6_mode; gulong dhcp6_state_sigid; @@ -207,6 +210,41 @@ nm_device_init (NMDevice *self) priv->rfkill_type = RFKILL_TYPE_UNKNOWN; } +static void +update_accept_ra_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/accept_ra", ip_iface); + g_assert (new_path); + + if (priv->ip6_accept_ra_path) { + /* If the IP iface is different from before, use the new value */ + if (!strcmp (new_path, priv->ip6_accept_ra_path)) { + g_free (new_path); + return; + } + g_free (priv->ip6_accept_ra_path); + } + + /* Grab the original value of "accept_ra" so we can restore it when NM exits */ + priv->ip6_accept_ra_path = new_path; + if (!nm_utils_get_proc_sys_net_value (priv->ip6_accept_ra_path, + ip_iface, + &priv->ip6_accept_ra_save)) { + g_free (priv->ip6_accept_ra_path); + priv->ip6_accept_ra_path = NULL; + } +} + static GObject* constructor (GType type, guint n_construct_params, @@ -246,6 +284,8 @@ constructor (GType type, priv->dhcp_manager = nm_dhcp_manager_get (); + update_accept_ra_save (dev); + priv->initialized = TRUE; return object; @@ -744,7 +784,8 @@ addrconf6_setup (NMDevice *self) s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); nm_ip6_manager_prepare_interface (priv->ip6_manager, nm_device_get_ip_ifindex (self), - s_ip6); + s_ip6, + priv->ip6_accept_ra_path); priv->ip6_waiting_for_config = TRUE; return TRUE; @@ -1589,6 +1630,8 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) ip_iface = nm_device_get_ip_iface (self); + update_accept_ra_save (self); + priv->dhcp6_mode = IP6_DHCP_OPT_NONE; if ( ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO) @@ -1600,13 +1643,21 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) nm_ip6_manager_begin_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self)); ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { + /* Router advertisements shouldn't be used in pure DHCP mode */ + if (priv->ip6_accept_ra_path) + nm_utils_do_sysctl (priv->ip6_accept_ra_path, "0\n"); + priv->dhcp6_mode = IP6_DHCP_OPT_MANAGED; ret = dhcp6_start (self, connection, priv->dhcp6_mode, reason); } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { priv->ip6_ready = TRUE; ret = NM_ACT_STAGE_RETURN_STOP; - } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { + /* Router advertisements shouldn't be used in manual mode */ + if (priv->ip6_accept_ra_path) + nm_utils_do_sysctl (priv->ip6_accept_ra_path, "0\n"); ret = NM_ACT_STAGE_RETURN_SUCCESS; + } /* Other methods (shared) aren't implemented yet */ @@ -2676,6 +2727,10 @@ nm_device_deactivate_quickly (NMDevice *self) dnsmasq_cleanup (self); aipd_cleanup (self); + /* Turn off router advertisements until they are needed */ + if (priv->ip6_accept_ra_path) + nm_utils_do_sysctl (priv->ip6_accept_ra_path, "0\n"); + /* Call device type-specific deactivation */ if (NM_DEVICE_GET_CLASS (self)->deactivate_quickly) NM_DEVICE_GET_CLASS (self)->deactivate_quickly (self); @@ -3247,6 +3302,13 @@ dispose (GObject *object) addrconf6_cleanup (self); dnsmasq_cleanup (self); + /* reset the saved RA value */ + if (priv->ip6_accept_ra_path) { + nm_utils_do_sysctl (priv->ip6_accept_ra_path, + priv->ip6_accept_ra_save ? "1\n" : "0\n"); + } + g_free (priv->ip6_accept_ra_path); + /* Take the device itself down and clear its IPv4 configuration */ if (priv->managed && take_down) { NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE;