summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/ifconfig/ifconfig.825
-rw-r--r--sbin/ifconfig/ifconfig.c73
-rw-r--r--sys/net/if_bridge.c6
-rw-r--r--sys/netinet/ip_carp.c82
-rw-r--r--sys/netinet/ip_carp.h5
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 *);