summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/netinet6/in6.c27
-rw-r--r--sys/netinet6/in6_var.h4
-rw-r--r--sys/netinet6/nd6_nbr.c22
3 files changed, 48 insertions, 5 deletions
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index e4f200b54a3..f729b1ec5fb 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6.c,v 1.78 2008/07/13 20:41:39 claudio Exp $ */
+/* $OpenBSD: in6.c,v 1.79 2008/10/01 21:17:06 claudio Exp $ */
/* $KAME: in6.c,v 1.372 2004/06/14 08:14:21 itojun Exp $ */
/*
@@ -1944,6 +1944,31 @@ in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr)
}
/*
+ * 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;
+
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
+ 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;
+}
+
+/*
* Convert IP6 address to printable (loggable) representation.
*/
static char digits[] = "0123456789abcdef";
diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h
index 58bc6da3f28..b55993a1d35 100644
--- a/sys/netinet6/in6_var.h
+++ b/sys/netinet6/in6_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6_var.h,v 1.29 2008/06/11 06:30:36 mcbride Exp $ */
+/* $OpenBSD: in6_var.h,v 1.30 2008/10/01 21:17:06 claudio Exp $ */
/* $KAME: in6_var.h,v 1.55 2001/02/16 12:49:45 itojun Exp $ */
/*
@@ -588,6 +588,8 @@ void in6_createmkludge(struct ifnet *);
void in6_purgemkludge(struct ifnet *);
struct in6_ifaddr *in6ifa_ifpforlinklocal(struct ifnet *, int);
struct in6_ifaddr *in6ifa_ifpwithaddr(struct ifnet *, struct in6_addr *);
+struct in6_ifaddr *in6ifa_ifplocaladdr(const struct ifnet *,
+ const struct in6_addr *);
char *ip6_sprintf(struct in6_addr *);
int in6_addr2scopeid(struct ifnet *, struct in6_addr *);
int in6_matchlen(struct in6_addr *, struct in6_addr *);
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index d89e818f254..5b604f3825e 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nd6_nbr.c,v 1.52 2008/09/17 05:43:15 chl Exp $ */
+/* $OpenBSD: nd6_nbr.c,v 1.53 2008/10/01 21:17:06 claudio Exp $ */
/* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */
/*
@@ -132,8 +132,18 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
"(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 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
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;
@@ -629,6 +637,14 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
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_na_input: "
+ "ND packet from non-neighbor\n"));
+ goto bad;
+ }
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
nd6log((LOG_INFO, "nd6_na_input: lladdrlen mismatch for %s "