ipv6: Allow accepting RA from local IP addresses.
authorBen Greear <greearb@candelatech.com>
Wed, 25 Jun 2014 21:44:53 +0000 (14:44 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 1 Jul 2014 19:16:24 +0000 (12:16 -0700)
This can be used in virtual networking applications, and
may have other uses as well.  The option is disabled by
default.

A specific use case is setting up virtual routers, bridges, and
hosts on a single OS without the use of network namespaces or
virtual machines.  With proper use of ip rules, routing tables,
veth interface pairs and/or other virtual interfaces,
and applications that can bind to interfaces and/or IP addresses,
it is possibly to create one or more virtual routers with multiple
hosts attached.  The host interfaces can act as IPv6 systems,
with radvd running on the ports in the virtual routers.  With the
option provided in this patch enabled, those hosts can now properly
obtain IPv6 addresses from the radvd.

Signed-off-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/networking/ip-sysctl.txt
include/linux/ipv6.h
include/uapi/linux/ipv6.h
include/uapi/linux/sysctl.h
kernel/sysctl_binary.c
net/ipv6/addrconf.c
net/ipv6/ndisc.c

index ab42c95f9985c0172109308c052cfe426a5bed9a..10e216c6e05e4bc1b385f957a8c75140c24687ae 100644 (file)
@@ -1210,6 +1210,18 @@ accept_ra_defrtr - BOOLEAN
        Functional default: enabled if accept_ra is enabled.
                            disabled if accept_ra is disabled.
 
+accept_ra_from_local - BOOLEAN
+       Accept RA with source-address that is found on local machine
+        if the RA is otherwise proper and able to be accepted.
+        Default is to NOT accept these as it may be an un-intended
+        network loop.
+
+       Functional default:
+           enabled if accept_ra_from_local is enabled
+               on a specific interface.
+          disabled if accept_ra_from_local is disabled
+               on a specific interface.
+
 accept_ra_pinfo - BOOLEAN
        Learn Prefix Information in Router Advertisement.
 
index c811300b0b0c9fe2b7a585be3ea5a1ad64c1cba1..b0f2452f1d58de98adf552e30bcf0532ae83fee4 100644 (file)
@@ -39,6 +39,7 @@ struct ipv6_devconf {
 #endif
        __s32           proxy_ndp;
        __s32           accept_source_route;
+       __s32           accept_ra_from_local;
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
        __s32           optimistic_dad;
 #endif
index 593b0e32d956c931d667405c200767a122b43bd7..efa2666f4b8af10ca72c26206f82e527d7adc8e6 100644 (file)
@@ -163,6 +163,7 @@ enum {
        DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL,
        DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL,
        DEVCONF_SUPPRESS_FRAG_NDISC,
+       DEVCONF_ACCEPT_RA_FROM_LOCAL,
        DEVCONF_MAX
 };
 
index 6d6721341f498656e2dc8996326d3b561e3f9581..43aaba1cc0372c050f5d5caf0903609ed46f73e0 100644 (file)
@@ -568,6 +568,7 @@ enum {
        NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22,
        NET_IPV6_PROXY_NDP=23,
        NET_IPV6_ACCEPT_SOURCE_ROUTE=25,
+       NET_IPV6_ACCEPT_RA_FROM_LOCAL=26,
        __NET_IPV6_MAX
 };
 
index 653cbbd9e7ad4dcb1ee0647c6d11cc453b1e81a9..e4ba9a5a5ccb45be2a5291b0f0848f90f73c0851 100644 (file)
@@ -522,6 +522,7 @@ static const struct bin_table bin_net_ipv6_conf_var_table[] = {
        { CTL_INT,      NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN,    "accept_ra_rt_info_max_plen" },
        { CTL_INT,      NET_IPV6_PROXY_NDP,                     "proxy_ndp" },
        { CTL_INT,      NET_IPV6_ACCEPT_SOURCE_ROUTE,           "accept_source_route" },
+       { CTL_INT,      NET_IPV6_ACCEPT_RA_FROM_LOCAL,          "accept_ra_from_local" },
        {}
 };
 
index 5667b3003af9b51779ff322717e999282113c4b7..358edd2272ac6570ffdeca7c7fc8bd4c6abe8ab4 100644 (file)
@@ -186,6 +186,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
        .max_desync_factor      = MAX_DESYNC_FACTOR,
        .max_addresses          = IPV6_MAX_ADDRESSES,
        .accept_ra_defrtr       = 1,
+       .accept_ra_from_local   = 0,
        .accept_ra_pinfo        = 1,
 #ifdef CONFIG_IPV6_ROUTER_PREF
        .accept_ra_rtr_pref     = 1,
@@ -222,6 +223,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
        .max_desync_factor      = MAX_DESYNC_FACTOR,
        .max_addresses          = IPV6_MAX_ADDRESSES,
        .accept_ra_defrtr       = 1,
+       .accept_ra_from_local   = 0,
        .accept_ra_pinfo        = 1,
 #ifdef CONFIG_IPV6_ROUTER_PREF
        .accept_ra_rtr_pref     = 1,
@@ -4321,6 +4323,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
        array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao;
        array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify;
        array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc;
+       array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local;
 }
 
 static inline size_t inet6_ifla6_size(void)
@@ -5167,6 +5170,13 @@ static struct addrconf_sysctl_table
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec
                },
+               {
+                       .procname       = "accept_ra_from_local",
+                       .data           = &ipv6_devconf.accept_ra_from_local,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
+               },
                {
                        /* sentinel */
                }
index 736c11c6d266e1e8f9ae8a81826e1f04bd360ad2..a845e3d2057ef2470e73792148b99d29135418fc 100644 (file)
@@ -1148,11 +1148,15 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                goto skip_defrtr;
        }
 
-       if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
-                         NULL, 0)) {
+       /* Do not accept RA with source-addr found on local machine unless
+        * accept_ra_from_local is set to true.
+        */
+       if (!(in6_dev->cnf.accept_ra_from_local ||
+             ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
+                           NULL, 0))) {
                ND_PRINTK(2, info,
-                         "RA: %s, chk_addr failed for dev: %s\n",
-                         __func__, skb->dev->name);
+                         "RA from local address detected on dev: %s: default router ignored\n",
+                         skb->dev->name);
                goto skip_defrtr;
        }
 
@@ -1290,11 +1294,12 @@ skip_linkparms:
        }
 
 #ifdef CONFIG_IPV6_ROUTE_INFO
-       if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
-                         NULL, 0)) {
+       if (!(in6_dev->cnf.accept_ra_from_local ||
+             ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
+                           NULL, 0))) {
                ND_PRINTK(2, info,
-                         "RA: %s, chk-addr (route info) is false for dev: %s\n",
-                         __func__, skb->dev->name);
+                         "RA from local address detected on dev: %s: router info ignored.\n",
+                         skb->dev->name);
                goto skip_routeinfo;
        }