diff options
author | Marco Pfatschbacher <mpf@cvs.openbsd.org> | 2006-05-18 12:39:24 +0000 |
---|---|---|
committer | Marco Pfatschbacher <mpf@cvs.openbsd.org> | 2006-05-18 12:39:24 +0000 |
commit | b42654278ee738318428def0dbf347b27f8aa4ad (patch) | |
tree | 89852f8c5a19632bded709448edc6002b169f6b3 /sys | |
parent | 55e32a8a54de962901566d36ba896e695d844b97 (diff) |
Add a duplicate check for our own advertisements. This is necessary
for dumb non simplex interfaces, that receive packets they've just
sent. Fixes bug 5121.
OK deraadt@, mcbride@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/ip_carp.c | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index ae5c4f3e6cc..f81a8596044 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_carp.c,v 1.123 2006/03/26 14:54:01 camield Exp $ */ +/* $OpenBSD: ip_carp.c,v 1.124 2006/05/18 12:39:23 mpf Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff. All rights reserved. @@ -588,6 +588,48 @@ carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) return; } + /* + * Check if our own advertisement was duplicated + * from a non simplex interface. + * XXX If there is no address on our physical interface + * there is no way to distinguish our ads from the ones + * another carp host might have sent us. + */ + if ((sc->sc_carpdev->if_flags & IFF_SIMPLEX) == 0) { + struct sockaddr sa; + struct ifaddr *ifa; + + bzero(&sa, sizeof(sa)); + sa.sa_family = af; + ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev); + + if (ifa && af == AF_INET) { + struct ip *ip = mtod(m, struct ip *); + if (ip->ip_src.s_addr == + ifatoia(ifa)->ia_addr.sin_addr.s_addr) { + m_freem(m); + return; + } + } +#ifdef INET6 + if (ifa && af == AF_INET6) { + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + struct in6_addr in6_src, in6_found; + + in6_src = ip6->ip6_src; + in6_found = ifatoia6(ifa)->ia_addr.sin6_addr; + if (IN6_IS_ADDR_LINKLOCAL(&in6_src)) + in6_src.s6_addr16[1] = 0; + if (IN6_IS_ADDR_LINKLOCAL(&in6_found)) + in6_found.s6_addr16[1] = 0; + if (IN6_ARE_ADDR_EQUAL(&in6_src, &in6_found)) { + m_freem(m); + return; + } + } +#endif /* INET6 */ + } + getmicrotime(&sc->sc_if.if_lastchange); sc->sc_if.if_ipackets++; sc->sc_if.if_ibytes += m->m_pkthdr.len; |