diff options
-rw-r--r-- | sbin/ifconfig/ifconfig.8 | 25 | ||||
-rw-r--r-- | sbin/ifconfig/ifconfig.c | 73 | ||||
-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 |
5 files changed, 153 insertions, 38 deletions
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index 23c84a820b8..7dc23e5bce0 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ifconfig.8,v 1.160 2008/05/07 11:57:19 claudio Exp $ +.\" $OpenBSD: ifconfig.8,v 1.161 2008/06/14 21:46:22 reyk Exp $ .\" $NetBSD: ifconfig.8,v 1.11 1996/01/04 21:27:29 pk Exp $ .\" $FreeBSD: ifconfig.8,v 1.16 1998/02/01 07:03:29 steve Exp $ .\" @@ -31,7 +31,7 @@ .\" .\" @(#)ifconfig.8 8.4 (Berkeley) 6/1/94 .\" -.Dd $Mdocdate: May 7 2008 $ +.Dd $Mdocdate: June 14 2008 $ .Dt IFCONFIG 8 .Os .Sh NAME @@ -454,6 +454,7 @@ and .Op Cm pass Ar passphrase .Op Cm state Ar state .Op Cm vhid Ar host-id +.Op Oo Fl Oc Cm carppeer Ar peer_address .Ek .Pp The options are as follows: @@ -517,6 +518,26 @@ If the driver is a pseudo-device, set the virtual host ID to .Ar n . Acceptable values are 1 to 255. +.It Cm carppeer Ar peer_address +If the driver is a +.Xr carp 4 +pseudo-device, send the carp advertisements to a specified +point-to-point peer or multicast group instead of sending the messages +to the default carp multicast group. +The +.Ar peer_address +is the IP address of the other host taking part in the carp cluster. +With this option, +.Xr carp 4 +traffic can be protected using +.Xr ipsec 4 +and it may be desired in networks that do not allow or have problems +with IPv4 multicast traffic. +.It Fl carppeer +If the driver is a +.Xr carp 4 +pseudo-device, send the advertisements to the default carp multicast +group. .El .Pp Taken together, the diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index a3b8995236b..35ff1961498 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ifconfig.c,v 1.198 2008/06/13 06:58:20 reyk Exp $ */ +/* $OpenBSD: ifconfig.c,v 1.199 2008/06/14 21:46:22 reyk Exp $ */ /* $NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $ */ /* @@ -202,6 +202,8 @@ void getifgroups(void); void carp_status(void); void setcarp_advbase(const char *,int); void setcarp_advskew(const char *, int); +void setcarppeer(const char *, int); +void unsetcarppeer(const char *, int); void setcarp_passwd(const char *, int); void setcarp_vhid(const char *, int); void setcarp_state(const char *, int); @@ -333,6 +335,8 @@ const struct cmd { { "-vlandev", 1, 0, unsetvlandev }, { "advbase", NEXTARG, 0, setcarp_advbase }, { "advskew", NEXTARG, 0, setcarp_advskew }, + { "carppeer", NEXTARG, 0, setcarppeer }, + { "-carppeer", 1, 0, unsetcarppeer }, { "pass", NEXTARG, 0, setcarp_passwd }, { "vhid", NEXTARG, 0, setcarp_vhid }, { "state", NEXTARG, 0, setcarp_state }, @@ -3196,6 +3200,7 @@ carp_status(void) { const char *state, *balmode; struct carpreq carpr; + char peer[32]; int i; memset((char *)&carpr, 0, sizeof(struct carpreq)); @@ -3212,6 +3217,12 @@ carp_status(void) else balmode = carp_bal_modes[carpr.carpr_balancing]; + if (carpr.carpr_peer.s_addr != htonl(INADDR_CARP_GROUP)) + snprintf(peer, sizeof(peer), + " carppeer %s", inet_ntoa(carpr.carpr_peer)); + else + peer[0] = '\0'; + for (i = 0; carpr.carpr_vhids[i]; i++) { if (carpr.carpr_states[i] > CARP_MAXSTATE) state = "<UNKNOWN>"; @@ -3219,17 +3230,18 @@ carp_status(void) state = carp_states[carpr.carpr_states[i]]; if (carpr.carpr_vhids[1] == 0) { printf("\tcarp: %s carpdev %s vhid %u advbase %d " - "advskew %u\n", state, + "advskew %u%s\n", state, carpr.carpr_carpdev[0] != '\0' ? carpr.carpr_carpdev : "none", carpr.carpr_vhids[0], - carpr.carpr_advbase, carpr.carpr_advskews[0]); + carpr.carpr_advbase, carpr.carpr_advskews[0], + peer); } else { if (i == 0) { printf("\tcarp: carpdev %s advbase %d" - " balancing %s\n", + " balancing %s%s\n", carpr.carpr_carpdev[0] != '\0' ? carpr.carpr_carpdev : "none", - carpr.carpr_advbase, balmode); + carpr.carpr_advbase, balmode, peer); } printf("\t\tstate %s vhid %u advskew %u\n", state, carpr.carpr_vhids[i], carpr.carpr_advskews[i]); @@ -3331,6 +3343,57 @@ setcarp_advbase(const char *val, int d) /* ARGSUSED */ void +setcarppeer(const char *val, int d) +{ + struct carpreq carpr; + struct addrinfo hints, *peerres; + int ecode; + + memset((char *)&carpr, 0, sizeof(struct carpreq)); + ifr.ifr_data = (caddr_t)&carpr; + + if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1) + err(1, "SIOCGVH"); + + bzero(&hints, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + + if ((ecode = getaddrinfo(val, NULL, &hints, &peerres)) != 0) + errx(1, "error in parsing address string: %s", + gai_strerror(ecode)); + + if (peerres->ai_addr->sa_family != AF_INET) + errx(1, "only IPv4 addresses supported for the carppeer"); + + carpr.carpr_peer.s_addr = ((struct sockaddr_in *) + peerres->ai_addr)->sin_addr.s_addr; + + if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1) + err(1, "SIOCSVH"); + + freeaddrinfo(peerres); +} + +void +unsetcarppeer(const char *val, int d) +{ + struct carpreq carpr; + + bzero((char *)&carpr, sizeof(struct carpreq)); + ifr.ifr_data = (caddr_t)&carpr; + + if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1) + err(1, "SIOCGVH"); + + bzero((char *)&carpr.carpr_peer, sizeof(carpr.carpr_peer)); + + if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1) + err(1, "SIOCSVH"); +} + +/* ARGSUSED */ +void setcarp_state(const char *val, int d) { struct carpreq carpr; 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 *); |