diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/if_bridge.c | 6 | ||||
-rw-r--r-- | sys/netinet/ip_carp.c | 82 | ||||
-rw-r--r-- | sys/netinet/ip_carp.h | 5 |
3 files changed, 62 insertions, 31 deletions
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 2b82b221dd4..21496b9e964 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bridge.c,v 1.169 2008/05/21 21:12:07 mk Exp $ */ +/* $OpenBSD: if_bridge.c,v 1.170 2008/06/14 21:46:22 reyk Exp $ */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) @@ -1470,7 +1470,7 @@ bridge_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m) if (bcmp(ac->ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN) == 0 #if NCARP > 0 || (ifl->ifp->if_carp && carp_ourether(ifl->ifp->if_carp, - eh, IFT_ETHER, 0) != NULL) + eh, 0) != NULL) #endif ) { if (srcifl->bif_flags & IFBIF_LEARNING) @@ -1493,7 +1493,7 @@ bridge_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m) if (bcmp(ac->ac_enaddr, eh->ether_shost, ETHER_ADDR_LEN) == 0 #if NCARP > 0 || (ifl->ifp->if_carp && carp_ourether(ifl->ifp->if_carp, - eh, IFT_ETHER, 1) != NULL) + eh, 1) != NULL) #endif ) { m_freem(m); diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index ca82bcf5c9f..67868b7d243 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_carp.c,v 1.166 2008/06/13 23:29:31 mpf Exp $ */ +/* $OpenBSD: ip_carp.c,v 1.167 2008/06/14 21:46:22 reyk Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff. All rights reserved. @@ -167,6 +167,8 @@ struct carp_softc { int sc_lscount; /* # load sharing interfaces (max 32) */ int sc_delayed_arp; /* delayed ARP request countdown */ + struct in_addr sc_peer; + LIST_HEAD(__carp_mchead, carp_mc_entry) carp_mc_listhead; struct carp_vhost_entry *cur_vhe; /* current active vhe */ }; @@ -201,7 +203,8 @@ void carp_hmac_generate(struct carp_vhost_entry *, u_int32_t *, int carp_hmac_verify(struct carp_vhost_entry *, u_int32_t *, unsigned char *); void carp_setroute(struct carp_softc *, int); -void carp_proto_input_c(struct mbuf *, struct carp_header *, sa_family_t); +void carp_proto_input_c(struct mbuf *, struct carp_header *, int, + sa_family_t); void carpattach(int); void carpdetach(struct carp_softc *); int carp_prepare_ad(struct mbuf *, struct carp_vhost_entry *, @@ -527,9 +530,10 @@ void carp_proto_input(struct mbuf *m, ...) { struct ip *ip = mtod(m, struct ip *); + struct ifnet *ifp = m->m_pkthdr.rcvif; struct carp_softc *sc = NULL; struct carp_header *ch; - int iplen, len, hlen; + int iplen, len, hlen, ismulti; va_list ap; va_start(ap, m); @@ -543,8 +547,11 @@ carp_proto_input(struct mbuf *m, ...) return; } + ismulti = IN_MULTICAST(ip->ip_dst.s_addr); + /* check if received on a valid carp interface */ - if (m->m_pkthdr.rcvif->if_type != IFT_CARP) { + if (!((ifp->if_type == IFT_CARP && ismulti) || + (ifp->if_type != IFT_CARP && !ismulti && ifp->if_carp != NULL))) { carpstats.carps_badif++; CARP_LOG(LOG_INFO, sc, ("packet received on non-carp interface: %s", m->m_pkthdr.rcvif->if_xname)); @@ -593,7 +600,7 @@ carp_proto_input(struct mbuf *m, ...) } m->m_data -= iplen; - carp_proto_input_c(m, ch, AF_INET); + carp_proto_input_c(m, ch, ismulti, AF_INET); } #ifdef INET6 @@ -652,20 +659,30 @@ carp6_proto_input(struct mbuf **mp, int *offp, int proto) } m->m_data -= *offp; - carp_proto_input_c(m, ch, AF_INET6); + carp_proto_input_c(m, ch, 1, AF_INET6); return (IPPROTO_DONE); } #endif /* INET6 */ void -carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af) +carp_proto_input_c(struct mbuf *m, struct carp_header *ch, int ismulti, + sa_family_t af) { + struct ifnet *ifp = m->m_pkthdr.rcvif; struct carp_softc *sc; struct carp_vhost_entry *vhe; struct timeval sc_tv, ch_tv; + struct carp_if *cif; + + if (ifp->if_type == IFT_CARP) + cif = (struct carp_if *)ifp->if_carpdev->if_carp; + else + cif = (struct carp_if *)ifp->if_carp; - TAILQ_FOREACH(sc, &((struct carp_if *) - m->m_pkthdr.rcvif->if_carpdev->if_carp)->vhif_vrs, sc_list) { + TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) { + if (af == AF_INET && + ismulti != IN_MULTICAST(sc->sc_peer.s_addr)) + continue; LIST_FOREACH(vhe, &sc->carp_vhosts, vhost_entries) { if (vhe->vhid == ch->carp_vhid) goto found; @@ -1119,7 +1136,6 @@ carp_send_ad(void *v) m->m_pkthdr.rcvif = NULL; m->m_len = len; MH_ALIGN(m, m->m_len); - m->m_flags |= M_MCAST; ip = mtod(m, struct ip *); ip->ip_v = IPVERSION; ip->ip_hl = sizeof(*ip) >> 2; @@ -1139,7 +1155,9 @@ carp_send_ad(void *v) else ip->ip_src.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr; - ip->ip_dst.s_addr = INADDR_CARP_GROUP; + ip->ip_dst.s_addr = sc->sc_peer.s_addr; + if (IN_MULTICAST(ip->ip_dst.s_addr)) + m->m_flags |= M_MCAST; ch_ptr = (void *)ip + sizeof(*ip); bcopy(&ch, ch_ptr, sizeof(ch)); @@ -1466,7 +1484,7 @@ carp_iamatch6(struct ifnet *ifp, u_char *src, struct sockaddr_dl **sdl) #endif /* INET6 */ struct ifnet * -carp_ourether(void *v, struct ether_header *eh, u_char iftype, int src) +carp_ourether(void *v, struct ether_header *eh, int src) { struct carp_if *cif = (struct carp_if *)v; struct carp_softc *vh; @@ -1537,7 +1555,7 @@ carp_input(struct mbuf *m, u_int8_t *shost, u_int8_t *dhost, u_int16_t etype) bcopy(dhost, &eh.ether_dhost, sizeof(eh.ether_dhost)); eh.ether_type = etype; - if ((ifp = carp_ourether(cif, &eh, m->m_pkthdr.rcvif->if_type, 0))) + if ((ifp = carp_ourether(cif, &eh, 0))) ; else if (m->m_flags & (M_BCAST|M_MCAST)) { struct carp_softc *vh; @@ -1925,18 +1943,22 @@ carp_addr_updated(void *v) sc->sc_naddrs6 = new_naddrs6; /* Re-establish multicast membership removed by in_control */ - mc_addr.s_addr = INADDR_CARP_GROUP; - IN_LOOKUP_MULTI(mc_addr, &sc->sc_if, inm); - if (inm == NULL) { - struct in_multi **imm = sc->sc_imo.imo_membership; - u_int16_t maxmem = sc->sc_imo.imo_max_memberships; - - bzero(&sc->sc_imo, sizeof(sc->sc_imo)); - sc->sc_imo.imo_membership = imm; - sc->sc_imo.imo_max_memberships = maxmem; - - if (sc->sc_carpdev != NULL && sc->sc_naddrs > 0) - carp_join_multicast(sc); + if (IN_MULTICAST(sc->sc_peer.s_addr)) { + mc_addr.s_addr = sc->sc_peer.s_addr; + IN_LOOKUP_MULTI(mc_addr, &sc->sc_if, inm); + if (inm == NULL) { + struct in_multi **imm = + sc->sc_imo.imo_membership; + u_int16_t maxmem = + sc->sc_imo.imo_max_memberships; + + bzero(&sc->sc_imo, sizeof(sc->sc_imo)); + sc->sc_imo.imo_membership = imm; + sc->sc_imo.imo_max_memberships = maxmem; + + if (sc->sc_carpdev != NULL && sc->sc_naddrs > 0) + carp_join_multicast(sc); + } } if (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0) { @@ -2024,7 +2046,10 @@ carp_join_multicast(struct carp_softc *sc) struct in_multi *imm; struct in_addr addr; - addr.s_addr = INADDR_CARP_GROUP; + if (!IN_MULTICAST(sc->sc_peer.s_addr)) + return (0); + + addr.s_addr = sc->sc_peer.s_addr; if ((imm = in_addmulti(&addr, &sc->sc_if)) == NULL) return (ENOBUFS); @@ -2222,6 +2247,10 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) if (carpr.carpr_carpdev[0] != '\0' && (cdev = ifunit(carpr.carpr_carpdev)) == NULL) return (EINVAL); + if (carpr.carpr_peer.s_addr == 0) + sc->sc_peer.s_addr = INADDR_CARP_GROUP; + else + sc->sc_peer.s_addr = carpr.carpr_peer.s_addr; if ((error = carp_set_ifp(sc, cdev))) return (error); if (vhe->state != INIT && carpr.carpr_state != vhe->state) { @@ -2294,6 +2323,7 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) if (suser(p, p->p_acflag) == 0) bcopy(sc->sc_key, carpr.carpr_key, sizeof(carpr.carpr_key)); + carpr.carpr_peer.s_addr = sc->sc_peer.s_addr; error = copyout(&carpr, ifr->ifr_data, sizeof(carpr)); break; diff --git a/sys/netinet/ip_carp.h b/sys/netinet/ip_carp.h index 857d8563c2b..145bc9d4023 100644 --- a/sys/netinet/ip_carp.h +++ b/sys/netinet/ip_carp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_carp.h,v 1.26 2008/02/05 22:57:31 mpf Exp $ */ +/* $OpenBSD: ip_carp.h,v 1.27 2008/06/14 21:46:22 reyk Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff. All rights reserved. @@ -142,6 +142,7 @@ struct carpreq { u_int8_t carpr_balancing; int carpr_advbase; unsigned char carpr_key[CARP_KEY_LEN]; + struct in_addr carpr_peer; }; /* @@ -170,7 +171,7 @@ int carp6_proto_input(struct mbuf **, int *, int); int carp_iamatch(struct in_ifaddr *, u_char *, u_int8_t **, u_int8_t **); int carp_iamatch6(struct ifnet *, u_char *, struct sockaddr_dl **); -struct ifnet *carp_ourether(void *, struct ether_header *, u_char, int); +struct ifnet *carp_ourether(void *, struct ether_header *, int); int carp_input(struct mbuf *, u_int8_t *, u_int8_t *, u_int16_t); int carp_output(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); |