Skip to content

Commit 2acd102

Browse files
committed
Merge branch 'net-ipv4-ipv6-new-option-to-accept-garp-untracked-na-only-if-in-network'
Jaehee Park says: ==================== net: ipv4/ipv6: new option to accept garp/untracked na only if in-network The first patch adds an option to learn a neighbor from garp only if the source ip is in the same subnet as an address configured on the interface that received the garp message. The option has been added to arp_accept in ipv4. The same feature has been added to ndisc (patch 2). For ipv6, the subnet filtering knob is an extension of the accept_untracked_na option introduced in these patches: https://lore.kernel.org/all/[email protected]/t/ https://lore.kernel.org/netdev/[email protected]/T/ The third patch contains selftests for testing the different options for accepting arp and neighbor advertisements. ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 459f326 + 0ea7b0a commit 2acd102

File tree

7 files changed

+389
-29
lines changed

7 files changed

+389
-29
lines changed

Documentation/networking/ip-sysctl.rst

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,12 +1633,15 @@ arp_notify - BOOLEAN
16331633
or hardware address changes.
16341634
== ==========================================================
16351635

1636-
arp_accept - BOOLEAN
1637-
Define behavior for gratuitous ARP frames who's IP is not
1638-
already present in the ARP table:
1636+
arp_accept - INTEGER
1637+
Define behavior for accepting gratuitous ARP (garp) frames from devices
1638+
that are not already present in the ARP table:
16391639

16401640
- 0 - don't create new entries in the ARP table
16411641
- 1 - create new entries in the ARP table
1642+
- 2 - create new entries only if the source IP address is in the same
1643+
subnet as an address configured on the interface that received the
1644+
garp message.
16421645

16431646
Both replies and requests type gratuitous arp will trigger the
16441647
ARP table to be updated, if this setting is on.
@@ -2480,27 +2483,36 @@ drop_unsolicited_na - BOOLEAN
24802483

24812484
By default this is turned off.
24822485

2483-
accept_untracked_na - BOOLEAN
2484-
Add a new neighbour cache entry in STALE state for routers on receiving a
2485-
neighbour advertisement (either solicited or unsolicited) with target
2486-
link-layer address option specified if no neighbour entry is already
2487-
present for the advertised IPv6 address. Without this knob, NAs received
2488-
for untracked addresses (absent in neighbour cache) are silently ignored.
2486+
accept_untracked_na - INTEGER
2487+
Define behavior for accepting neighbor advertisements from devices that
2488+
are absent in the neighbor cache:
24892489

2490-
This is as per router-side behaviour documented in RFC9131.
2490+
- 0 - (default) Do not accept unsolicited and untracked neighbor
2491+
advertisements.
24912492

2492-
This has lower precedence than drop_unsolicited_na.
2493+
- 1 - Add a new neighbor cache entry in STALE state for routers on
2494+
receiving a neighbor advertisement (either solicited or unsolicited)
2495+
with target link-layer address option specified if no neighbor entry
2496+
is already present for the advertised IPv6 address. Without this knob,
2497+
NAs received for untracked addresses (absent in neighbor cache) are
2498+
silently ignored.
24932499

2494-
This will optimize the return path for the initial off-link communication
2495-
that is initiated by a directly connected host, by ensuring that
2496-
the first-hop router which turns on this setting doesn't have to
2497-
buffer the initial return packets to do neighbour-solicitation.
2498-
The prerequisite is that the host is configured to send
2499-
unsolicited neighbour advertisements on interface bringup.
2500-
This setting should be used in conjunction with the ndisc_notify setting
2501-
on the host to satisfy this prerequisite.
2500+
This is as per router-side behavior documented in RFC9131.
25022501

2503-
By default this is turned off.
2502+
This has lower precedence than drop_unsolicited_na.
2503+
2504+
This will optimize the return path for the initial off-link
2505+
communication that is initiated by a directly connected host, by
2506+
ensuring that the first-hop router which turns on this setting doesn't
2507+
have to buffer the initial return packets to do neighbor-solicitation.
2508+
The prerequisite is that the host is configured to send unsolicited
2509+
neighbor advertisements on interface bringup. This setting should be
2510+
used in conjunction with the ndisc_notify setting on the host to
2511+
satisfy this prerequisite.
2512+
2513+
- 2 - Extend option (1) to add a new neighbor cache entry only if the
2514+
source IP address is in the same subnet as an address configured on
2515+
the interface that received the neighbor advertisement.
25042516

25052517
enhanced_dad - BOOLEAN
25062518
Include a nonce option in the IPv6 neighbor solicitation messages used for

include/linux/inetdevice.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
131131
IN_DEV_ORCONF((in_dev), IGNORE_ROUTES_WITH_LINKDOWN)
132132

133133
#define IN_DEV_ARPFILTER(in_dev) IN_DEV_ORCONF((in_dev), ARPFILTER)
134-
#define IN_DEV_ARP_ACCEPT(in_dev) IN_DEV_ORCONF((in_dev), ARP_ACCEPT)
134+
#define IN_DEV_ARP_ACCEPT(in_dev) IN_DEV_MAXCONF((in_dev), ARP_ACCEPT)
135135
#define IN_DEV_ARP_ANNOUNCE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_ANNOUNCE)
136136
#define IN_DEV_ARP_IGNORE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_IGNORE)
137137
#define IN_DEV_ARP_NOTIFY(in_dev) IN_DEV_MAXCONF((in_dev), ARP_NOTIFY)

net/ipv4/arp.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,26 @@ static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip)
429429
return !inet_confirm_addr(net, in_dev, sip, tip, scope);
430430
}
431431

432+
static int arp_accept(struct in_device *in_dev, __be32 sip)
433+
{
434+
struct net *net = dev_net(in_dev->dev);
435+
int scope = RT_SCOPE_LINK;
436+
437+
switch (IN_DEV_ARP_ACCEPT(in_dev)) {
438+
case 0: /* Don't create new entries from garp */
439+
return 0;
440+
case 1: /* Create new entries from garp */
441+
return 1;
442+
case 2: /* Create a neighbor in the arp table only if sip
443+
* is in the same subnet as an address configured
444+
* on the interface that received the garp message
445+
*/
446+
return !!inet_confirm_addr(net, in_dev, sip, 0, scope);
447+
default:
448+
return 0;
449+
}
450+
}
451+
432452
static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
433453
{
434454
struct rtable *rt;
@@ -868,12 +888,12 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
868888
n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
869889

870890
addr_type = -1;
871-
if (n || IN_DEV_ARP_ACCEPT(in_dev)) {
891+
if (n || arp_accept(in_dev, sip)) {
872892
is_garp = arp_is_garp(net, dev, &addr_type, arp->ar_op,
873893
sip, tip, sha, tha);
874894
}
875895

876-
if (IN_DEV_ARP_ACCEPT(in_dev)) {
896+
if (arp_accept(in_dev, sip)) {
877897
/* Unsolicited ARP is not accepted by default.
878898
It is possible, that this option should be enabled for some
879899
devices (strip is candidate)

net/ipv6/addrconf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7042,7 +7042,7 @@ static const struct ctl_table addrconf_sysctl[] = {
70427042
.data = &ipv6_devconf.accept_untracked_na,
70437043
.maxlen = sizeof(int),
70447044
.mode = 0644,
7045-
.proc_handler = proc_dointvec_minmax,
7045+
.proc_handler = proc_dointvec,
70467046
.extra1 = (void *)SYSCTL_ZERO,
70477047
.extra2 = (void *)SYSCTL_ONE,
70487048
},

net/ipv6/ndisc.c

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,25 @@ static void ndisc_recv_ns(struct sk_buff *skb)
967967
in6_dev_put(idev);
968968
}
969969

970+
static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr)
971+
{
972+
struct inet6_dev *idev = __in6_dev_get(dev);
973+
974+
switch (idev->cnf.accept_untracked_na) {
975+
case 0: /* Don't accept untracked na (absent in neighbor cache) */
976+
return 0;
977+
case 1: /* Create new entries from na if currently untracked */
978+
return 1;
979+
case 2: /* Create new entries from untracked na only if saddr is in the
980+
* same subnet as an address configured on the interface that
981+
* received the na
982+
*/
983+
return !!ipv6_chk_prefix(saddr, dev);
984+
default:
985+
return 0;
986+
}
987+
}
988+
970989
static void ndisc_recv_na(struct sk_buff *skb)
971990
{
972991
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
@@ -1061,11 +1080,11 @@ static void ndisc_recv_na(struct sk_buff *skb)
10611080
* Note that we don't do a (daddr == all-routers-mcast) check.
10621081
*/
10631082
new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE;
1064-
if (!neigh && lladdr &&
1065-
idev && idev->cnf.forwarding &&
1066-
idev->cnf.accept_untracked_na) {
1067-
neigh = neigh_create(&nd_tbl, &msg->target, dev);
1068-
new_state = NUD_STALE;
1083+
if (!neigh && lladdr && idev && idev->cnf.forwarding) {
1084+
if (accept_untracked_na(dev, saddr)) {
1085+
neigh = neigh_create(&nd_tbl, &msg->target, dev);
1086+
new_state = NUD_STALE;
1087+
}
10691088
}
10701089

10711090
if (neigh && !IS_ERR(neigh)) {

tools/testing/selftests/net/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ TEST_PROGS += srv6_end_dt6_l3vpn_test.sh
3838
TEST_PROGS += vrf_strict_mode_test.sh
3939
TEST_PROGS += arp_ndisc_evict_nocarrier.sh
4040
TEST_PROGS += ndisc_unsolicited_na_test.sh
41+
TEST_PROGS += arp_ndisc_untracked_subnets.sh
4142
TEST_PROGS += stress_reuseport_listen.sh
4243
TEST_PROGS_EXTENDED := in_netns.sh setup_loopback.sh setup_veth.sh
4344
TEST_PROGS_EXTENDED += toeplitz_client.sh toeplitz.sh

0 commit comments

Comments
 (0)