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.
This commit is contained in:
Dan Williams
2010-05-03 03:42:43 -07:00
parent 10d6bc8d2e
commit 7926b3ca95
5 changed files with 107 additions and 58 deletions

View File

@@ -594,3 +594,32 @@ nm_utils_do_sysctl (const char *path, const char *value)
return TRUE; 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;
}

View 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_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 */ #endif /* NETWORK_MANAGER_UTILS_H */

View File

@@ -83,10 +83,6 @@ typedef struct {
char *iface; char *iface;
int ifindex; int ifindex;
char *accept_ra_path;
gboolean accept_ra_save_valid;
guint32 accept_ra_save;
char *disable_ip6_path; char *disable_ip6_path;
gboolean disable_ip6_save_valid; gboolean disable_ip6_save_valid;
guint32 disable_ip6_save; guint32 disable_ip6_save;
@@ -111,12 +107,6 @@ nm_ip6_device_destroy (NMIP6Device *device)
{ {
g_return_if_fail (device != NULL); 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 */ /* reset the saved IPv6 value */
if (device->disable_ip6_save_valid) { if (device->disable_ip6_save_valid) {
nm_utils_do_sysctl (device->disable_ip6_path, nm_utils_do_sysctl (device->disable_ip6_path,
@@ -135,37 +125,9 @@ nm_ip6_device_destroy (NMIP6Device *device)
if (device->ip6flags_poll_id) if (device->ip6flags_poll_id)
g_source_remove (device->ip6flags_poll_id); g_source_remove (device->ip6flags_poll_id);
g_free (device->accept_ra_path);
g_slice_free (NMIP6Device, device); 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 * static NMIP6Device *
nm_ip6_device_new (NMIP6Manager *manager, int ifindex) 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); 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 */ /* and the original value of IPv6 enable/disable */
device->disable_ip6_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6", device->disable_ip6_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6",
device->iface); device->iface);
g_assert (device->disable_ip6_path); g_assert (device->disable_ip6_path);
device->disable_ip6_save_valid = get_proc_sys_net_value (device->disable_ip6_path, device->disable_ip6_save_valid = nm_utils_get_proc_sys_net_value (device->disable_ip6_path,
device->iface, device->iface,
&device->disable_ip6_save); &device->disable_ip6_save);
return device; return device;
@@ -835,8 +787,9 @@ netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer us
void void
nm_ip6_manager_prepare_interface (NMIP6Manager *manager, nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
int ifindex, int ifindex,
NMSettingIP6Config *s_ip6) NMSettingIP6Config *s_ip6,
const char *accept_ra_path)
{ {
NMIP6ManagerPrivate *priv; NMIP6ManagerPrivate *priv;
NMIP6Device *device; NMIP6Device *device;
@@ -861,10 +814,10 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
/* Establish target state and turn router advertisement acceptance on or off */ /* Establish target state and turn router advertisement acceptance on or off */
if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) {
device->target_state = NM_IP6_DEVICE_GOT_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 { } else {
device->target_state = NM_IP6_DEVICE_GOT_ADDRESS; 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");
} }
} }

View File

@@ -73,7 +73,8 @@ GType nm_ip6_manager_get_type (void);
NMIP6Manager *nm_ip6_manager_get (void); NMIP6Manager *nm_ip6_manager_get (void);
void nm_ip6_manager_prepare_interface (NMIP6Manager *manager, void nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
int ifindex, int ifindex,
NMSettingIP6Config *s_ip6); NMSettingIP6Config *s_ip6,
const char *accept_ra_path);
void nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, void nm_ip6_manager_begin_addrconf (NMIP6Manager *manager,
int ifindex); int ifindex);
void nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager, void nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager,

View File

@@ -135,6 +135,9 @@ typedef struct {
gulong ip6_config_changed_sigid; gulong ip6_config_changed_sigid;
gboolean ip6_waiting_for_config; gboolean ip6_waiting_for_config;
char * ip6_accept_ra_path;
guint32 ip6_accept_ra_save;
NMDHCPClient * dhcp6_client; NMDHCPClient * dhcp6_client;
guint32 dhcp6_mode; guint32 dhcp6_mode;
gulong dhcp6_state_sigid; gulong dhcp6_state_sigid;
@@ -207,6 +210,41 @@ nm_device_init (NMDevice *self)
priv->rfkill_type = RFKILL_TYPE_UNKNOWN; 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* static GObject*
constructor (GType type, constructor (GType type,
guint n_construct_params, guint n_construct_params,
@@ -246,6 +284,8 @@ constructor (GType type,
priv->dhcp_manager = nm_dhcp_manager_get (); priv->dhcp_manager = nm_dhcp_manager_get ();
update_accept_ra_save (dev);
priv->initialized = TRUE; priv->initialized = TRUE;
return object; return object;
@@ -744,7 +784,8 @@ addrconf6_setup (NMDevice *self)
s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
nm_ip6_manager_prepare_interface (priv->ip6_manager, nm_ip6_manager_prepare_interface (priv->ip6_manager,
nm_device_get_ip_ifindex (self), nm_device_get_ip_ifindex (self),
s_ip6); s_ip6,
priv->ip6_accept_ra_path);
priv->ip6_waiting_for_config = TRUE; priv->ip6_waiting_for_config = TRUE;
return 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); ip_iface = nm_device_get_ip_iface (self);
update_accept_ra_save (self);
priv->dhcp6_mode = IP6_DHCP_OPT_NONE; priv->dhcp6_mode = IP6_DHCP_OPT_NONE;
if ( ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO) 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)); nm_ip6_manager_begin_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self));
ret = NM_ACT_STAGE_RETURN_POSTPONE; ret = NM_ACT_STAGE_RETURN_POSTPONE;
} else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { } 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; priv->dhcp6_mode = IP6_DHCP_OPT_MANAGED;
ret = dhcp6_start (self, connection, priv->dhcp6_mode, reason); ret = dhcp6_start (self, connection, priv->dhcp6_mode, reason);
} else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) {
priv->ip6_ready = TRUE; priv->ip6_ready = TRUE;
ret = NM_ACT_STAGE_RETURN_STOP; 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; ret = NM_ACT_STAGE_RETURN_SUCCESS;
}
/* Other methods (shared) aren't implemented yet */ /* Other methods (shared) aren't implemented yet */
@@ -2676,6 +2727,10 @@ nm_device_deactivate_quickly (NMDevice *self)
dnsmasq_cleanup (self); dnsmasq_cleanup (self);
aipd_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 */ /* Call device type-specific deactivation */
if (NM_DEVICE_GET_CLASS (self)->deactivate_quickly) if (NM_DEVICE_GET_CLASS (self)->deactivate_quickly)
NM_DEVICE_GET_CLASS (self)->deactivate_quickly (self); NM_DEVICE_GET_CLASS (self)->deactivate_quickly (self);
@@ -3247,6 +3302,13 @@ dispose (GObject *object)
addrconf6_cleanup (self); addrconf6_cleanup (self);
dnsmasq_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 */ /* Take the device itself down and clear its IPv4 configuration */
if (priv->managed && take_down) { if (priv->managed && take_down) {
NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE; NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE;