Skip to content

Commit d933319

Browse files
greearbdavem330
authored andcommitted
ipv6: Allow accepting RA from local IP addresses.
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f2a762d commit d933319

File tree

7 files changed

+39
-8
lines changed

7 files changed

+39
-8
lines changed

Documentation/networking/ip-sysctl.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,18 @@ accept_ra_defrtr - BOOLEAN
12101210
Functional default: enabled if accept_ra is enabled.
12111211
disabled if accept_ra is disabled.
12121212

1213+
accept_ra_from_local - BOOLEAN
1214+
Accept RA with source-address that is found on local machine
1215+
if the RA is otherwise proper and able to be accepted.
1216+
Default is to NOT accept these as it may be an un-intended
1217+
network loop.
1218+
1219+
Functional default:
1220+
enabled if accept_ra_from_local is enabled
1221+
on a specific interface.
1222+
disabled if accept_ra_from_local is disabled
1223+
on a specific interface.
1224+
12131225
accept_ra_pinfo - BOOLEAN
12141226
Learn Prefix Information in Router Advertisement.
12151227

include/linux/ipv6.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct ipv6_devconf {
3939
#endif
4040
__s32 proxy_ndp;
4141
__s32 accept_source_route;
42+
__s32 accept_ra_from_local;
4243
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
4344
__s32 optimistic_dad;
4445
#endif

include/uapi/linux/ipv6.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ enum {
163163
DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL,
164164
DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL,
165165
DEVCONF_SUPPRESS_FRAG_NDISC,
166+
DEVCONF_ACCEPT_RA_FROM_LOCAL,
166167
DEVCONF_MAX
167168
};
168169

include/uapi/linux/sysctl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@ enum {
568568
NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22,
569569
NET_IPV6_PROXY_NDP=23,
570570
NET_IPV6_ACCEPT_SOURCE_ROUTE=25,
571+
NET_IPV6_ACCEPT_RA_FROM_LOCAL=26,
571572
__NET_IPV6_MAX
572573
};
573574

kernel/sysctl_binary.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ static const struct bin_table bin_net_ipv6_conf_var_table[] = {
522522
{ CTL_INT, NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN, "accept_ra_rt_info_max_plen" },
523523
{ CTL_INT, NET_IPV6_PROXY_NDP, "proxy_ndp" },
524524
{ CTL_INT, NET_IPV6_ACCEPT_SOURCE_ROUTE, "accept_source_route" },
525+
{ CTL_INT, NET_IPV6_ACCEPT_RA_FROM_LOCAL, "accept_ra_from_local" },
525526
{}
526527
};
527528

net/ipv6/addrconf.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
186186
.max_desync_factor = MAX_DESYNC_FACTOR,
187187
.max_addresses = IPV6_MAX_ADDRESSES,
188188
.accept_ra_defrtr = 1,
189+
.accept_ra_from_local = 0,
189190
.accept_ra_pinfo = 1,
190191
#ifdef CONFIG_IPV6_ROUTER_PREF
191192
.accept_ra_rtr_pref = 1,
@@ -222,6 +223,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
222223
.max_desync_factor = MAX_DESYNC_FACTOR,
223224
.max_addresses = IPV6_MAX_ADDRESSES,
224225
.accept_ra_defrtr = 1,
226+
.accept_ra_from_local = 0,
225227
.accept_ra_pinfo = 1,
226228
#ifdef CONFIG_IPV6_ROUTER_PREF
227229
.accept_ra_rtr_pref = 1,
@@ -4321,6 +4323,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
43214323
array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao;
43224324
array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify;
43234325
array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc;
4326+
array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local;
43244327
}
43254328

43264329
static inline size_t inet6_ifla6_size(void)
@@ -5167,6 +5170,13 @@ static struct addrconf_sysctl_table
51675170
.mode = 0644,
51685171
.proc_handler = proc_dointvec
51695172
},
5173+
{
5174+
.procname = "accept_ra_from_local",
5175+
.data = &ipv6_devconf.accept_ra_from_local,
5176+
.maxlen = sizeof(int),
5177+
.mode = 0644,
5178+
.proc_handler = proc_dointvec,
5179+
},
51705180
{
51715181
/* sentinel */
51725182
}

net/ipv6/ndisc.c

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,11 +1148,15 @@ static void ndisc_router_discovery(struct sk_buff *skb)
11481148
goto skip_defrtr;
11491149
}
11501150

1151-
if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1152-
NULL, 0)) {
1151+
/* Do not accept RA with source-addr found on local machine unless
1152+
* accept_ra_from_local is set to true.
1153+
*/
1154+
if (!(in6_dev->cnf.accept_ra_from_local ||
1155+
ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1156+
NULL, 0))) {
11531157
ND_PRINTK(2, info,
1154-
"RA: %s, chk_addr failed for dev: %s\n",
1155-
__func__, skb->dev->name);
1158+
"RA from local address detected on dev: %s: default router ignored\n",
1159+
skb->dev->name);
11561160
goto skip_defrtr;
11571161
}
11581162

@@ -1290,11 +1294,12 @@ static void ndisc_router_discovery(struct sk_buff *skb)
12901294
}
12911295

12921296
#ifdef CONFIG_IPV6_ROUTE_INFO
1293-
if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1294-
NULL, 0)) {
1297+
if (!(in6_dev->cnf.accept_ra_from_local ||
1298+
ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
1299+
NULL, 0))) {
12951300
ND_PRINTK(2, info,
1296-
"RA: %s, chk-addr (route info) is false for dev: %s\n",
1297-
__func__, skb->dev->name);
1301+
"RA from local address detected on dev: %s: router info ignored.\n",
1302+
skb->dev->name);
12981303
goto skip_routeinfo;
12991304
}
13001305

0 commit comments

Comments
 (0)