diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2008-10-01 21:17:07 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2008-10-01 21:17:07 +0000 |
commit | 681fc59ab964ddcd2f94289c067b44b927a31576 (patch) | |
tree | 19e25328f647cafad8e8353672b667313c9826c3 | |
parent | 0339078b2931d1fd37be17f300448c8b32ec06e7 (diff) |
If a neighbor solictation isn't from the unspecified address, make sure
that the source address matches one of the interfaces address prefixes.
From NetBSD, tested by todd@ and naddy@
-rw-r--r-- | sys/netinet6/in6.c | 27 | ||||
-rw-r--r-- | sys/netinet6/in6_var.h | 4 | ||||
-rw-r--r-- | sys/netinet6/nd6_nbr.c | 22 |
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 " |