Fri Oct 3 10:43:48 2008 UTC ()
Pull up revisions:
  src/sys/netinet6/in6.c	1.141 via patch
  src/sys/netinet6/in6_var.h	1.59 via patch
  src/sys/netinet6/nd6_nbr.c	1.89-1.90 via patch
(requested by adrianp in ticket #1967).

If a neighbor solictation isn't from the unspecified address, make sure
that the source address matches one of the interfaces address prefixes.

Generalize previous fix so that both NS and NA packets are checked.


(jdc)
diff -r1.91 -r1.91.4.1 src/sys/netinet6/in6.c
diff -r1.38 -r1.38.4.1 src/sys/netinet6/in6_var.h
diff -r1.56 -r1.56.2.1 src/sys/netinet6/nd6_nbr.c

cvs diff -r1.91 -r1.91.4.1 src/sys/netinet6/in6.c (expand / switch to context diff)
--- src/sys/netinet6/in6.c 2005/02/01 15:29:23 1.91
+++ src/sys/netinet6/in6.c 2008/10/03 10:43:48 1.91.4.1
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6.c,v 1.91 2005/02/01 15:29:23 drochner Exp $	*/
+/*	$NetBSD: in6.c,v 1.91.4.1 2008/10/03 10:43:48 jdc Exp $	*/
 /*	$KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.91 2005/02/01 15:29:23 drochner Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.91.4.1 2008/10/03 10:43:48 jdc Exp $");
 
 #include "opt_inet.h"
 #include "opt_pfil_hooks.h"
@@ -2022,6 +2022,31 @@
 	}
 
 	return ((struct in6_ifaddr *)ifa);
+}
+
+/*
+ * find the internet address on a given interface corresponding to a neighbor's
+ * address.
+ */
+struct in6_ifaddr *
+in6ifa_ifplocaladdr(const struct ifnet *ifp, const struct in6_addr *addr)
+{
+	struct ifaddr *ifa;
+	struct in6_ifaddr *ia;
+
+	IFADDR_FOREACH(ifa, ifp) {
+		if (ifa->ifa_addr == NULL)
+			continue;	/* just for safety */
+		if (ifa->ifa_addr->sa_family != AF_INET6)
+			continue;
+		ia = (struct in6_ifaddr *)ifa;
+		if (IN6_ARE_MASKED_ADDR_EQUAL(addr,
+				&ia->ia_addr.sin6_addr,
+				&ia->ia_prefixmask.sin6_addr))
+			return ia;
+	}
+
+	return NULL;
 }
 
 /*

cvs diff -r1.38 -r1.38.4.1 src/sys/netinet6/in6_var.h (expand / switch to context diff)
--- src/sys/netinet6/in6_var.h 2005/02/01 15:29:23 1.38
+++ src/sys/netinet6/in6_var.h 2008/10/03 10:43:48 1.38.4.1
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_var.h,v 1.38 2005/02/01 15:29:23 drochner Exp $	*/
+/*	$NetBSD: in6_var.h,v 1.38.4.1 2008/10/03 10:43:48 jdc Exp $	*/
 /*	$KAME: in6_var.h,v 1.81 2002/06/08 11:16:51 itojun Exp $	*/
 
 /*
@@ -592,6 +592,8 @@
 void	in6_createmkludge __P((struct ifnet *));
 void	in6_purgemkludge __P((struct ifnet *));
 struct in6_ifaddr *in6ifa_ifpforlinklocal __P((struct ifnet *, int));
+struct in6_ifaddr *in6ifa_ifplocaladdr __P((const struct ifnet *, 
+        const struct in6_addr *));
 struct in6_ifaddr *in6ifa_ifpwithaddr __P((struct ifnet *, struct in6_addr *));
 char	*ip6_sprintf __P((const struct in6_addr *));
 int	in6_addr2scopeid __P((struct ifnet *, struct in6_addr *));

cvs diff -r1.56 -r1.56.2.1 src/sys/netinet6/nd6_nbr.c (expand / switch to context diff)
--- src/sys/netinet6/nd6_nbr.c 2005/02/26 22:45:13 1.56
+++ src/sys/netinet6/nd6_nbr.c 2008/10/03 10:43:48 1.56.2.1
@@ -1,4 +1,4 @@
-/*	$NetBSD: nd6_nbr.c,v 1.56 2005/02/26 22:45:13 perry Exp $	*/
+/*	$NetBSD: nd6_nbr.c,v 1.56.2.1 2008/10/03 10:43:48 jdc 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.56 2005/02/26 22:45:13 perry Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.56.2.1 2008/10/03 10:43:48 jdc Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -139,8 +139,18 @@
 			    "(wrong ip6 dst)\n"));
 			goto bad;
 		}
+	} else {
+		/*
+		 * Make sure the source address is from a neighbor's address.
+		 */
+		if (in6ifa_ifplocaladdr(ifp, &saddr6) == NULL) {
+			nd6log((LOG_INFO, "nd6_ns_input: "
+			    "NS packet from non-neighbor\n"));
+			goto bad;
+		}
 	}
 
+
 	if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
 		nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"));
 		goto bad;
@@ -540,9 +550,7 @@
 	struct ifnet *ifp = m->m_pkthdr.rcvif;
 	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
 	struct nd_neighbor_advert *nd_na;
-#if 0
 	struct in6_addr saddr6 = ip6->ip6_src;
-#endif
 	struct in6_addr daddr6 = ip6->ip6_dst;
 	struct in6_addr taddr6;
 	int flags;
@@ -628,6 +636,14 @@
 		    "nd6_na_input: duplicate IP6 address %s\n",
 		    ip6_sprintf(&taddr6));
 		goto freeit;
+	}
+	/*
+	 * Make sure the source address is from a neighbor's address.
+	 */
+	if (in6ifa_ifplocaladdr(ifp, &saddr6) == NULL) {
+		nd6log((LOG_INFO, "nd6_ns_input: "
+		    "ND packet from non-neighbor\n"));
+		goto bad;
 	}
 
 	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {