diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2014-03-21 13:48:29 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2014-03-21 13:48:29 +0000 |
commit | e7213f074b0646c7c2ebf8c4b2d15b58ea190ff9 (patch) | |
tree | 93e4a267079730476af643f74f140cf5c3b8d2b1 /sys | |
parent | 00332ac547689c66a1e96b5e9e1228b187a115a8 (diff) |
Global lists of addresses are species near extinction, even carp do
not like them!
Since carp(4) interfaces do some magic tricks to find a compatible
interface if you do not specify a `carpdev' argument, make them
iterate over &ifnet instead of &in{,6}_ifaddr.
ok benno@, mikeb@, florian@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/ip_carp.c | 94 |
1 files changed, 53 insertions, 41 deletions
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 0635b559256..58635844535 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_carp.c,v 1.223 2014/03/18 10:47:34 mpi Exp $ */ +/* $OpenBSD: ip_carp.c,v 1.224 2014/03/21 13:48:28 mpi Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff. All rights reserved. @@ -2003,12 +2003,14 @@ carp_addr_updated(void *v) int carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin) { - struct ifnet *ifp = sc->sc_carpdev; + struct ifnet *ifp = NULL; + struct in_addr *in = &sin->sin_addr; + struct ifaddr *ifa; struct in_ifaddr *ia; int error = 0; /* XXX is this necessary? */ - if (sin->sin_addr.s_addr == 0) { + if (in->s_addr == INADDR_ANY) { if (!(sc->sc_if.if_flags & IFF_UP)) carp_set_state_all(sc, INIT); if (sc->sc_naddrs) @@ -2018,25 +2020,30 @@ carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin) } /* we have to do this by hand to ensure we don't match on ourselves */ - TAILQ_FOREACH(ia, &in_ifaddr, ia_list) { + TAILQ_FOREACH(ifp, &ifnet, if_list) { /* and, yeah, we need a multicast-capable iface too */ - if (ia->ia_ifp != &sc->sc_if && - ia->ia_ifp->if_type != IFT_CARP && - (ia->ia_ifp->if_flags & IFF_MULTICAST) && - ia->ia_ifp->if_rdomain == sc->sc_if.if_rdomain && - (sin->sin_addr.s_addr & ia->ia_netmask) == ia->ia_net) - break; - } + if ((ifp->if_type == IFT_CARP) || + (ifp->if_flags & IFF_MULTICAST) == 0 || + (ifp->if_rdomain != sc->sc_if.if_rdomain)) + continue; - if (ia) { - if (ifp) { - if (ifp != ia->ia_ifp) - return (EADDRNOTAVAIL); - } else { - ifp = ia->ia_ifp; + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { + if (ifa->ifa_addr->sa_family != AF_INET) + continue; + + ia = ifatoia(ifa); + if ((in->s_addr & ia->ia_netmask) == ia->ia_net) + goto found; } } +found: + if (ifp == NULL) + ifp = sc->sc_carpdev; + + if (sc->sc_carpdev != NULL && ifp != sc->sc_carpdev) + return (EADDRNOTAVAIL); + if ((error = carp_set_ifp(sc, ifp))) return (error); @@ -2082,8 +2089,9 @@ int carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6) { struct ifnet *ifp = sc->sc_carpdev; + struct ifaddr *ifa; struct in6_ifaddr *ia6; - int error = 0; + int i, error = 0; if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { if (!(sc->sc_if.if_flags & IFF_UP)) @@ -2095,34 +2103,38 @@ carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6) } /* we have to do this by hand to ensure we don't match on ourselves */ - TAILQ_FOREACH(ia6, &in6_ifaddr, ia_list) { - int i; - - for (i = 0; i < 4; i++) { - if ((sin6->sin6_addr.s6_addr32[i] & - ia6->ia_prefixmask.sin6_addr.s6_addr32[i]) != - (ia6->ia_addr.sin6_addr.s6_addr32[i] & - ia6->ia_prefixmask.sin6_addr.s6_addr32[i])) - break; - } + TAILQ_FOREACH(ifp, &ifnet, if_list) { /* and, yeah, we need a multicast-capable iface too */ - if (ia6->ia_ifp != &sc->sc_if && - ia6->ia_ifp->if_type != IFT_CARP && - (ia6->ia_ifp->if_flags & IFF_MULTICAST) && - ia6->ia_ifp->if_rdomain == sc->sc_if.if_rdomain && - (i == 4)) - break; - } + if ((ifp->if_type == IFT_CARP) || + (ifp->if_flags & IFF_MULTICAST) == 0 || + (ifp->if_rdomain != sc->sc_if.if_rdomain)) + continue; - if (ia6) { - if (sc->sc_carpdev) { - if (sc->sc_carpdev != ia6->ia_ifp) - return (EADDRNOTAVAIL); - } else { - ifp = ia6->ia_ifp; + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + + ia6 = ifatoia6(ifa); + for (i = 0; i < 4; i++) { + if ((sin6->sin6_addr.s6_addr32[i] & + ia6->ia_prefixmask.sin6_addr.s6_addr32[i]) != + (ia6->ia_addr.sin6_addr.s6_addr32[i] & + ia6->ia_prefixmask.sin6_addr.s6_addr32[i])) + break; + } + + if (i == 4) + goto found; } } +found: + if (ifp == NULL) + ifp = sc->sc_carpdev; + + if (sc->sc_carpdev != NULL && ifp != sc->sc_carpdev) + return (EADDRNOTAVAIL); + if ((error = carp_set_ifp(sc, ifp))) return (error); |