summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2014-03-21 13:48:29 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2014-03-21 13:48:29 +0000
commite7213f074b0646c7c2ebf8c4b2d15b58ea190ff9 (patch)
tree93e4a267079730476af643f74f140cf5c3b8d2b1 /sys
parent00332ac547689c66a1e96b5e9e1228b187a115a8 (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.c94
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);