ip6: turn RA acceptance off when RAs shouldn't be used (rh #588163)
authorDan Williams <dcbw@redhat.com>
Mon, 3 May 2010 10:42:43 +0000 (03:42 -0700)
committerDan Williams <dcbw@redhat.com>
Mon, 3 May 2010 10:42:43 +0000 (03:42 -0700)
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
src/NetworkManagerUtils.h
src/ip6-manager/nm-ip6-manager.c
src/ip6-manager/nm-ip6-manager.h
src/nm-device.c

index 4bd57d9..fe64e1f 100644 (file)
@@ -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;
+}
+
index fa8b598..e3d1793 100644 (file)
@@ -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 */
index 5101faf..333638a 100644 (file)
@@ -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");
        }
 }
 
index 7cd0ef7..77c1106 100644 (file)
@@ -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,
index d8f7b64..88c57ba 100644 (file)
@@ -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;