ipv6: sysctl to restrict candidate source addresses
Erik Kline [Wed, 22 Jul 2015 07:38:25 +0000 (16:38 +0900)]
Per RFC 6724, section 4, "Candidate Source Addresses":

    It is RECOMMENDED that the candidate source addresses be the set
    of unicast addresses assigned to the interface that will be used
    to send to the destination (the "outgoing" interface).

Add a sysctl to enable this behaviour.

[Simplified back-port of net-next 3985e8a3611a93bb36789f65db862e5700aab65e]

Bug: 19470192
Bug: 21832279
Bug: 22464419
Change-Id: I404a53694f0df948389d33b0669be6203a1d2da5
Signed-off-by: Erik Kline <ek@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Reviewed-on: http://git-master/r/1123593
GVS: Gerrit_Virtual_Submit
Reviewed-by: Om Prakash Singh <omp@nvidia.com>
Reviewed-by: Bhadram Varka <vbhadram@nvidia.com>
Tested-by: Bhadram Varka <vbhadram@nvidia.com>
Reviewed-by: Srinivas Ramachandran <srinivasra@nvidia.com>
Reviewed-by: Ashutosh Jha <ajha@nvidia.com>
(cherry picked from commit 97e252a84c7d1c791196115ea4cf836a838cebd2)
Reviewed-on: http://git-master/r/1127379
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>

Documentation/networking/ip-sysctl.txt
include/linux/ipv6.h
include/uapi/linux/ipv6.h
net/ipv6/addrconf.c

index fbfc9e0..b4ec119 100644 (file)
@@ -1258,6 +1258,13 @@ router_solicitations - INTEGER
        routers are present.
        Default: 3
 
+use_oif_addrs_only - BOOLEAN
+       When enabled, the candidate source addresses for destinations
+       routed via this interface are restricted to the set of addresses
+       configured on this interface (vis. RFC 6724, section 4).
+
+       Default: false
+
 use_tempaddr - INTEGER
        Preference for Privacy Extensions (RFC3041).
          <= 0 : disable Privacy Extensions
index ebc6306..c4a36ab 100644 (file)
@@ -50,6 +50,7 @@ struct ipv6_devconf {
        __s32           accept_dad;
        __s32           force_tllao;
        __s32           ndisc_notify;
+       __s32           use_oif_addrs_only;
        void            *sysctl;
 };
 
index e9d0f7e..15ac588 100644 (file)
@@ -162,6 +162,7 @@ enum {
        DEVCONF_NDISC_NOTIFY,
        DEVCONF_ACCEPT_RA_RT_TABLE,
        DEVCONF_USE_OPTIMISTIC,
+       DEVCONF_USE_OIF_ADDRS_ONLY,
        DEVCONF_MAX
 };
 
index 69e8b50..3eb4363 100644 (file)
@@ -203,6 +203,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
        .accept_source_route    = 0,    /* we do not accept RH0 by default. */
        .disable_ipv6           = 0,
        .accept_dad             = 1,
+       .use_oif_addrs_only     = 0,
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -238,6 +239,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
        .accept_source_route    = 0,    /* we do not accept RH0 by default. */
        .disable_ipv6           = 0,
        .accept_dad             = 1,
+       .use_oif_addrs_only     = 0,
 };
 
 /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -1386,9 +1388,15 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
                 *    include addresses assigned to interfaces
                 *    belonging to the same site as the outgoing
                 *    interface.)
+                *  - "It is RECOMMENDED that the candidate source addresses
+                *    be the set of unicast addresses assigned to the
+                *    interface that will be used to send to the destination
+                *    (the 'outgoing' interface)." (RFC 6724)
                 */
+               idev = dst_dev ? __in6_dev_get(dst_dev) : NULL;
                if (((dst_type & IPV6_ADDR_MULTICAST) ||
-                    dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL) &&
+                    dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL ||
+                    (idev && idev->cnf.use_oif_addrs_only)) &&
                    dst.ifindex && dev->ifindex != dst.ifindex)
                        continue;
 
@@ -4284,6 +4292,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
        array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
        array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao;
        array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify;
+       array[DEVCONF_USE_OIF_ADDRS_ONLY] = cnf->use_oif_addrs_only;
 }
 
 static inline size_t inet6_ifla6_size(void)
@@ -5057,6 +5066,14 @@ static struct addrconf_sysctl_table
                        .proc_handler   = proc_dointvec
                },
                {
+                       .procname       = "use_oif_addrs_only",
+                       .data           = &ipv6_devconf.use_oif_addrs_only,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
+
+               },
+               {
                        /* sentinel */
                }
        },