diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 77f5f55ffcdf6633a006ef610e9b091f251dd716..bf38b80b06daefd451e27b96a1927f68a616659f 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1199,6 +1199,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 diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 9ea0dbb40352a14e26ad383ea01c4d609a875310..e9c4e51ed115bc71da103692ca6944eeacb7bf3d 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -174,6 +174,7 @@ struct ipv6_devconf { __s32 disable_ipv6; __s32 accept_dad; __s32 force_tllao; + __s32 use_oif_addrs_only; void *sysctl; }; @@ -217,6 +218,7 @@ enum { DEVCONF_FORCE_TLLAO, DEVCONF_ACCEPT_RA_RT_TABLE, DEVCONF_USE_OPTIMISTIC, + DEVCONF_USE_OIF_ADDRS_ONLY, DEVCONF_MAX }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d0789497ad9180ca60147c88a3072c2520a80e23..15bf5e7fa36043e66fa9302fd8739bf9c67fda78 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -198,6 +198,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 = { @@ -233,6 +234,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 */ @@ -1166,9 +1168,15 @@ int ipv6_dev_get_saddr(struct net *net, 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; @@ -3992,6 +4000,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6; array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad; array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; + array[DEVCONF_USE_OIF_ADDRS_ONLY] = cnf->use_oif_addrs_only; } static inline size_t inet6_ifla6_size(void) @@ -4677,6 +4686,14 @@ static struct addrconf_sysctl_table .mode = 0644, .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 */ }