Skip to content

Commit

Permalink
Merge branch 'net-ipv4-ipv6-new-option-to-accept-garp-untracked-na-on…
Browse files Browse the repository at this point in the history
…ly-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/642672cb-8b11-c78f-8975-f287ece9e89e@gmail.com/t/
https://lore.kernel.org/netdev/20220530101414.65439-1-aajith@arista.com/T/

The third patch contains selftests for testing the different options
for accepting arp and neighbor advertisements.
====================

Link: https://lore.kernel.org/r/cover.1657755188.git.jhpark1013@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Jul 16, 2022
2 parents 459f326 + 0ea7b0a commit 2acd102
Show file tree
Hide file tree
Showing 7 changed files with 389 additions and 29 deletions.
52 changes: 32 additions & 20 deletions Documentation/networking/ip-sysctl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1633,12 +1633,15 @@ arp_notify - BOOLEAN
or hardware address changes.
== ==========================================================

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

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

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

By default this is turned off.

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

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

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

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

By default this is turned off.
This has lower precedence than drop_unsolicited_na.

This will optimize the return path for the initial off-link
communication that is initiated by a directly connected host, by
ensuring that the first-hop router which turns on this setting doesn't
have to buffer the initial return packets to do neighbor-solicitation.
The prerequisite is that the host is configured to send unsolicited
neighbor advertisements on interface bringup. This setting should be
used in conjunction with the ndisc_notify setting on the host to
satisfy this prerequisite.

- 2 - Extend option (1) to add a new neighbor cache entry only if the
source IP address is in the same subnet as an address configured on
the interface that received the neighbor advertisement.

enhanced_dad - BOOLEAN
Include a nonce option in the IPv6 neighbor solicitation messages used for
Expand Down
2 changes: 1 addition & 1 deletion include/linux/inetdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
IN_DEV_ORCONF((in_dev), IGNORE_ROUTES_WITH_LINKDOWN)

#define IN_DEV_ARPFILTER(in_dev) IN_DEV_ORCONF((in_dev), ARPFILTER)
#define IN_DEV_ARP_ACCEPT(in_dev) IN_DEV_ORCONF((in_dev), ARP_ACCEPT)
#define IN_DEV_ARP_ACCEPT(in_dev) IN_DEV_MAXCONF((in_dev), ARP_ACCEPT)
#define IN_DEV_ARP_ANNOUNCE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_ANNOUNCE)
#define IN_DEV_ARP_IGNORE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_IGNORE)
#define IN_DEV_ARP_NOTIFY(in_dev) IN_DEV_MAXCONF((in_dev), ARP_NOTIFY)
Expand Down
24 changes: 22 additions & 2 deletions net/ipv4/arp.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,26 @@ static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip)
return !inet_confirm_addr(net, in_dev, sip, tip, scope);
}

static int arp_accept(struct in_device *in_dev, __be32 sip)
{
struct net *net = dev_net(in_dev->dev);
int scope = RT_SCOPE_LINK;

switch (IN_DEV_ARP_ACCEPT(in_dev)) {
case 0: /* Don't create new entries from garp */
return 0;
case 1: /* Create new entries from garp */
return 1;
case 2: /* Create a neighbor in the arp table only if sip
* is in the same subnet as an address configured
* on the interface that received the garp message
*/
return !!inet_confirm_addr(net, in_dev, sip, 0, scope);
default:
return 0;
}
}

static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
{
struct rtable *rt;
Expand Down Expand Up @@ -868,12 +888,12 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
n = __neigh_lookup(&arp_tbl, &sip, dev, 0);

addr_type = -1;
if (n || IN_DEV_ARP_ACCEPT(in_dev)) {
if (n || arp_accept(in_dev, sip)) {
is_garp = arp_is_garp(net, dev, &addr_type, arp->ar_op,
sip, tip, sha, tha);
}

if (IN_DEV_ARP_ACCEPT(in_dev)) {
if (arp_accept(in_dev, sip)) {
/* Unsolicited ARP is not accepted by default.
It is possible, that this option should be enabled for some
devices (strip is candidate)
Expand Down
2 changes: 1 addition & 1 deletion net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -7042,7 +7042,7 @@ static const struct ctl_table addrconf_sysctl[] = {
.data = &ipv6_devconf.accept_untracked_na,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.proc_handler = proc_dointvec,
.extra1 = (void *)SYSCTL_ZERO,
.extra2 = (void *)SYSCTL_ONE,
},
Expand Down
29 changes: 24 additions & 5 deletions net/ipv6/ndisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,25 @@ static void ndisc_recv_ns(struct sk_buff *skb)
in6_dev_put(idev);
}

static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr)
{
struct inet6_dev *idev = __in6_dev_get(dev);

switch (idev->cnf.accept_untracked_na) {
case 0: /* Don't accept untracked na (absent in neighbor cache) */
return 0;
case 1: /* Create new entries from na if currently untracked */
return 1;
case 2: /* Create new entries from untracked na only if saddr is in the
* same subnet as an address configured on the interface that
* received the na
*/
return !!ipv6_chk_prefix(saddr, dev);
default:
return 0;
}
}

static void ndisc_recv_na(struct sk_buff *skb)
{
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
Expand Down Expand Up @@ -1061,11 +1080,11 @@ static void ndisc_recv_na(struct sk_buff *skb)
* Note that we don't do a (daddr == all-routers-mcast) check.
*/
new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE;
if (!neigh && lladdr &&
idev && idev->cnf.forwarding &&
idev->cnf.accept_untracked_na) {
neigh = neigh_create(&nd_tbl, &msg->target, dev);
new_state = NUD_STALE;
if (!neigh && lladdr && idev && idev->cnf.forwarding) {
if (accept_untracked_na(dev, saddr)) {
neigh = neigh_create(&nd_tbl, &msg->target, dev);
new_state = NUD_STALE;
}
}

if (neigh && !IS_ERR(neigh)) {
Expand Down
1 change: 1 addition & 0 deletions tools/testing/selftests/net/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ TEST_PROGS += srv6_end_dt6_l3vpn_test.sh
TEST_PROGS += vrf_strict_mode_test.sh
TEST_PROGS += arp_ndisc_evict_nocarrier.sh
TEST_PROGS += ndisc_unsolicited_na_test.sh
TEST_PROGS += arp_ndisc_untracked_subnets.sh
TEST_PROGS += stress_reuseport_listen.sh
TEST_PROGS_EXTENDED := in_netns.sh setup_loopback.sh setup_veth.sh
TEST_PROGS_EXTENDED += toeplitz_client.sh toeplitz.sh
Expand Down
Loading

0 comments on commit 2acd102

Please sign in to comment.