Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/netinet6 inet6: match NS nonce to any interface



details:   https://anonhg.NetBSD.org/src/rev/f1f247851e01
branches:  trunk
changeset: 446477:f1f247851e01
user:      roy <roy%NetBSD.org@localhost>
date:      Fri Dec 07 14:47:24 2018 +0000

description:
inet6: match NS nonce to any interface

This allows the same address to exist on many interfaces on the same
prefix, matching the inet behaviour.

diffstat:

 sys/netinet6/nd6_nbr.c |  53 +++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 46 insertions(+), 7 deletions(-)

diffs (109 lines):

diff -r 1258f0cf4c94 -r f1f247851e01 sys/netinet6/nd6_nbr.c
--- a/sys/netinet6/nd6_nbr.c    Fri Dec 07 09:36:26 2018 +0000
+++ b/sys/netinet6/nd6_nbr.c    Fri Dec 07 14:47:24 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: nd6_nbr.c,v 1.161 2018/12/04 21:16:54 roy Exp $        */
+/*     $NetBSD: nd6_nbr.c,v 1.162 2018/12/07 14:47:24 roy Exp $        */
 /*     $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $        */
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.161 2018/12/04 21:16:54 roy Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.162 2018/12/07 14:47:24 roy Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -77,6 +77,7 @@
 
 struct dadq;
 static struct dadq *nd6_dad_find(struct ifaddr *, struct nd_opt_nonce *, bool *);
+static bool nd6_dad_ownnonce(struct ifaddr *, struct nd_opt_nonce *nonce);
 static void nd6_dad_starttimer(struct dadq *, int);
 static void nd6_dad_destroytimer(struct dadq *);
 static void nd6_dad_timer(struct dadq *);
@@ -309,6 +310,16 @@
                goto freeit;
        }
 
+       /*
+        * It looks that sender is performing DAD.
+        * Check that the nonce is not being used by the same address
+        * on another interface.
+        */
+       if (IN6_IS_ADDR_UNSPECIFIED(&saddr6) && ndopts.nd_opts_nonce != NULL) {
+               if (nd6_dad_ownnonce(ifa, ndopts.nd_opts_nonce))
+                       goto freeit;
+       }
+
        ifa_release(ifa, &psref_ia);
        ifa = NULL;
 
@@ -1088,17 +1099,33 @@
 static struct dadq *
 nd6_dad_find(struct ifaddr *ifa, struct nd_opt_nonce *nonce, bool *found_nonce)
 {
+       struct in6_addr *myaddr6, *dadaddr6;
+       bool match_ifa;
        struct dadq *dp;
        int i, nonce_max;
 
        KASSERT(mutex_owned(&nd6_dad_lock));
+       KASSERT(ifa != NULL);
+
+       myaddr6 = IFA_IN6(ifa);
+       if (nonce != NULL &&
+           nonce->nd_opt_nonce_len != (ND_OPT_NONCE_LEN + 2) / 8)
+               nonce = NULL;
+       match_ifa = nonce == NULL || found_nonce == NULL || *found_nonce == false;
+       if (found_nonce != NULL)
+               *found_nonce = false;
 
        TAILQ_FOREACH(dp, &dadq, dad_list) {
-               if (dp->dad_ifa != ifa)
-                       continue;
+               if (match_ifa) {
+                       if (dp->dad_ifa != ifa)
+                               continue;
+               } else {
+                       dadaddr6 = IFA_IN6(dp->dad_ifa);
+                       if (!IN6_ARE_ADDR_EQUAL(myaddr6, dadaddr6))
+                               continue;
+               }
 
-               if (nonce == NULL ||
-                   nonce->nd_opt_nonce_len != (ND_OPT_NONCE_LEN + 2) / 8)
+               if (nonce == NULL)
                        break;
 
                nonce_max = MIN(dp->dad_ns_ocount, ND_OPT_NONCE_STORE);
@@ -1115,7 +1142,7 @@
                        log(LOG_DEBUG,
                            "%s: detected a looped back NS message for %s\n",
                            ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???",
-                           IN6_PRINT(ip6buf, IFA_IN6(ifa)));
+                           IN6_PRINT(ip6buf, myaddr6));
                        dp->dad_ns_lcount++;
                        continue;
                }
@@ -1125,6 +1152,18 @@
        return dp;
 }
 
+static bool
+nd6_dad_ownnonce(struct ifaddr *ifa, struct nd_opt_nonce *nonce)
+{
+       bool found_nonce = true;
+
+       mutex_enter(&nd6_dad_lock);
+       nd6_dad_find(ifa, nonce, &found_nonce);
+       mutex_exit(&nd6_dad_lock);
+
+       return found_nonce;
+}
+
 static void
 nd6_dad_starttimer(struct dadq *dp, int ticks)
 {



Home | Main Index | Thread Index | Old Index