net: ipv6: new accept_untracked_na option to accept na only if in-network
authorJaehee Park <jhpark1013@gmail.com>
Wed, 13 Jul 2022 23:40:48 +0000 (16:40 -0700)
committerJakub Kicinski <kuba@kernel.org>
Sat, 16 Jul 2022 01:55:50 +0000 (18:55 -0700)
This patch adds a third knob, '2', which extends the
accept_untracked_na option to learn a neighbor only if the src ip is
in the same subnet as an address configured on the interface that
received the neighbor advertisement. This is similar to the arp_accept
configuration for ipv4.

Signed-off-by: Jaehee Park <jhpark1013@gmail.com>
Suggested-by: Roopa Prabhu <roopa@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Documentation/networking/ip-sysctl.rst
net/ipv6/addrconf.c
net/ipv6/ndisc.c

index b316014..1c3897a 100644 (file)
@@ -2483,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.
-
-       This is as per router-side behaviour documented in RFC9131.
-
-       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 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.
-
-       By default this is turned off.
+accept_untracked_na - INTEGER
+       Define behavior for accepting neighbor advertisements from devices that
+       are absent in the neighbor cache:
+
+       - 0 - (default) Do not accept unsolicited and untracked neighbor
+         advertisements.
+
+       - 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 is as per router-side behavior documented in RFC9131.
+
+         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
index 88becb0..6ed807b 100644 (file)
@@ -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,
        },
index cd84cbd..9845369 100644 (file)
@@ -967,6 +967,25 @@ out:
                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);
@@ -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)) {