Page MenuHomeFreeBSD

D38940.id118445.diff
No OneTemporary

D38940.id118445.diff

diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h
--- a/lib/libifconfig/libifconfig.h
+++ b/lib/libifconfig/libifconfig.h
@@ -52,6 +52,7 @@
typedef struct ifconfig_handle ifconfig_handle_t;
struct carpreq;
+struct carpreq_peer;
struct ifaddrs;
struct ifbropreq;
struct ifbreq;
@@ -281,6 +282,8 @@
int ifconfig_carp_get_info(ifconfig_handle_t *h, const char *name,
struct carpreq *carpr, int ncarpr);
+int ifconfig_carp_get_peer_info(ifconfig_handle_t *h, const char *name,
+ struct carpreq_peer *carprp, int ncarprp);
/** Retrieve additional information about an inet address
* @param h An open ifconfig state object
diff --git a/lib/libifconfig/libifconfig_carp.c b/lib/libifconfig/libifconfig_carp.c
--- a/lib/libifconfig/libifconfig_carp.c
+++ b/lib/libifconfig/libifconfig_carp.c
@@ -32,6 +32,7 @@
#include <sys/ioctl.h>
#include <net/if.h>
+#include <netinet/in.h>
#include <netinet/ip_carp.h>
#include <string.h>
@@ -58,3 +59,20 @@
return (0);
}
+
+int ifconfig_carp_get_peer_info(ifconfig_handle_t *h, const char *name,
+ struct carpreq_peer *carprp, int ncarprp)
+{
+ struct ifreq ifr;
+
+ bzero(carprp, sizeof(struct carpreq_peer) * ncarprp);
+ carprp[0].carprp_count = ncarprp;
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (caddr_t)carprp;
+
+ if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGPEER, &ifr) != 0) {
+ return (-1);
+ }
+
+ return (0);
+}
diff --git a/sbin/ifconfig/carp.c b/sbin/ifconfig/carp.c
--- a/sbin/ifconfig/carp.c
+++ b/sbin/ifconfig/carp.c
@@ -42,13 +42,17 @@
#include <netinet/in_var.h>
#include <netinet/ip_carp.h>
+#include <arpa/inet.h>
+
#include <ctype.h>
+#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <err.h>
#include <errno.h>
+#include <netdb.h>
#include <libifconfig.h>
@@ -67,17 +71,32 @@
static int carpr_advskew = -1;
static int carpr_advbase = -1;
static int carpr_state = -1;
+static in_addr_t carp_peer;
+static struct in6_addr carp_peer6;
static unsigned char const *carpr_key;
static void
carp_status(int s)
{
struct carpreq carpr[CARP_MAXVHID];
+ struct carpreq_peer carprp[CARP_MAXVHID];
+ char addr_buf[NI_MAXHOST];
if (ifconfig_carp_get_info(lifh, name, carpr, CARP_MAXVHID) == -1)
return;
+ if (ifconfig_carp_get_peer_info(lifh, name, carprp, CARP_MAXVHID) ==
+ -1)
+ return;
+
+ /* XXX: We assume that get_info and get_peer_info returned the same
+ * number of entries, in the same order. That's sensitive to race
+ * conditions (i.e. a vhid is added or removed between the two calls).
+ * We don't cope with that, because it's expected to be very rare. */
+
for (size_t i = 0; i < carpr[0].carpr_count; i++) {
+ struct in_addr peer;
+
printf("\tcarp: %s vhid %d advbase %d advskew %d",
carp_states[carpr[i].carpr_state], carpr[i].carpr_vhid,
carpr[i].carpr_advbase, carpr[i].carpr_advskew);
@@ -85,6 +104,13 @@
printf(" key \"%s\"\n", carpr[i].carpr_key);
else
printf("\n");
+
+ peer.s_addr = carprp[i].carprp_addr;
+ inet_ntop(AF_INET6, &carprp[i].carprp_addr6, addr_buf,
+ sizeof(addr_buf));
+
+ printf("\t peer %s peer6 %s\n", inet_ntoa(peer),
+ addr_buf);
}
}
@@ -130,6 +156,7 @@
setcarp_callback(int s, void *arg __unused)
{
struct carpreq carpr;
+ struct carpreq_peer carpr_peer;
bzero(&carpr, sizeof(struct carpreq));
carpr.carpr_vhid = carpr_vhid;
@@ -139,6 +166,13 @@
if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1 && errno != ENOENT)
err(1, "SIOCGVH");
+ bzero(&carpr_peer, sizeof(struct carpreq_peer));
+ carpr_peer.carprp_vhid = carpr_vhid;
+ carpr_peer.carprp_count = 1;
+ ifr.ifr_data = (caddr_t)&carpr_peer;
+ if (ioctl(s, SIOCGPEER, (caddr_t)&ifr) == -1 && errno != ENOENT)
+ err(1, "SIOCGPEER");
+
if (carpr_key != NULL)
/* XXX Should hash the password into the key here? */
strlcpy(carpr.carpr_key, carpr_key, CARP_KEY_LEN);
@@ -149,8 +183,19 @@
if (carpr_state > -1)
carpr.carpr_state = carpr_state;
+ ifr.ifr_data = (caddr_t)&carpr;
if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1)
err(1, "SIOCSVH");
+
+ if (carp_peer != INADDR_ANY)
+ carpr_peer.carprp_addr = carp_peer;
+ if (! IN6_IS_ADDR_UNSPECIFIED(&carp_peer6))
+ memcpy(&carpr_peer.carprp_addr6, &carp_peer6,
+ sizeof(carp_peer6));
+
+ ifr.ifr_data = (caddr_t)&carpr_peer;
+ if (ioctl(s, SIOCSPEER, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSPEER");
}
static void
@@ -200,12 +245,53 @@
errx(1, "unknown state");
}
+static void
+setcarp_peer(const char *val, int d, int s, const struct afswtch *afp)
+{
+ carp_peer = inet_addr(val);
+}
+
+static void
+setcarp_mcast(const char *val, int d, int s, const struct afswtch *afp)
+{
+ carp_peer = htonl(INADDR_CARP_GROUP);
+}
+
+static void
+setcarp_peer6(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct addrinfo hints, *res;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_flags = AI_NUMERICHOST;
+
+ if (getaddrinfo(val, NULL, &hints, &res) == 1)
+ errx(1, "Invalid IPv6 address %s", val);
+
+ memcpy(&carp_peer6, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
+ sizeof(carp_peer6));
+}
+
+static void
+setcarp_mcast6(const char *val, int d, int s, const struct afswtch *afp)
+{
+ bzero(&carp_peer6, sizeof(carp_peer6));
+ carp_peer6.s6_addr[0] = 0xff;
+ carp_peer6.s6_addr[1] = 0x02;
+ carp_peer6.s6_addr[15] = 0x12;
+}
+
static struct cmd carp_cmds[] = {
DEF_CMD_ARG("advbase", setcarp_advbase),
DEF_CMD_ARG("advskew", setcarp_advskew),
DEF_CMD_ARG("pass", setcarp_passwd),
DEF_CMD_ARG("vhid", setcarp_vhid),
DEF_CMD_ARG("state", setcarp_state),
+ DEF_CMD_ARG("peer", setcarp_peer),
+ DEF_CMD_ARG("mcast", setcarp_mcast),
+ DEF_CMD_ARG("peer6", setcarp_peer6),
+ DEF_CMD_ARG("mcast6", setcarp_mcast6),
};
static struct afswtch af_carp = {
.af_name = "af_carp",
@@ -218,6 +304,10 @@
{
int i;
+ /* Default to multicast. */
+ setcarp_mcast(NULL, 0, 0, NULL);
+ setcarp_mcast6(NULL, 0, 0, NULL);
+
for (i = 0; i < nitems(carp_cmds); i++)
cmd_register(&carp_cmds[i]);
af_register(&af_carp);
diff --git a/sys/net/if.c b/sys/net/if.c
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -3122,6 +3122,8 @@
#if defined(INET) || defined(INET6)
case SIOCSVH:
case SIOCGVH:
+ case SIOCSPEER:
+ case SIOCGPEER:
if (carp_ioctl_p == NULL)
error = EPROTONOSUPPORT;
else
diff --git a/sys/netinet/ip_carp.h b/sys/netinet/ip_carp.h
--- a/sys/netinet/ip_carp.h
+++ b/sys/netinet/ip_carp.h
@@ -137,6 +137,16 @@
#define SIOCSVH _IOWR('i', 245, struct ifreq)
#define SIOCGVH _IOWR('i', 246, struct ifreq)
+struct carpreq_peer {
+ int carprp_count;
+ int carprp_vhid;
+ in_addr_t carprp_addr; /* Peer address */
+ struct in6_addr carprp_addr6; /* Peer address for IPv6 */
+
+};
+#define SIOCSPEER _IOWR('i', 251, struct ifreq)
+#define SIOCGPEER _IOWR('i', 252, struct ifreq)
+
#ifdef _KERNEL
int carp_ioctl(struct ifreq *, u_long, struct thread *);
int carp_attach(struct ifaddr *, int);
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -104,6 +104,8 @@
int sc_vhid;
int sc_advskew;
int sc_advbase;
+ in_addr_t sc_carpaddr;
+ struct in6_addr sc_carpaddr6;
int sc_naddrs;
int sc_naddrs6;
@@ -304,7 +306,7 @@
(((sc)->sc_advskew + V_carp_demotion < 0) ? \
0 : ((sc)->sc_advskew + V_carp_demotion)))
-static void carp_input_c(struct mbuf *, struct carp_header *, sa_family_t);
+static void carp_input_c(struct mbuf *, struct carp_header *, sa_family_t, int);
static struct carp_softc
*carp_alloc(struct ifnet *);
static void carp_destroy(struct carp_softc *);
@@ -464,16 +466,6 @@
return (IPPROTO_DONE);
}
- /* verify that the IP TTL is 255. */
- if (ip->ip_ttl != CARP_DFLTTL) {
- CARPSTATS_INC(carps_badttl);
- CARP_DEBUG("%s: received ttl %d != 255 on %s\n", __func__,
- ip->ip_ttl,
- m->m_pkthdr.rcvif->if_xname);
- m_freem(m);
- return (IPPROTO_DONE);
- }
-
iplen = ip->ip_hl << 2;
if (m->m_pkthdr.len < iplen + sizeof(*ch)) {
@@ -527,7 +519,7 @@
}
m->m_data -= iplen;
- carp_input_c(m, ch, AF_INET);
+ carp_input_c(m, ch, AF_INET, ip->ip_ttl);
return (IPPROTO_DONE);
}
#endif
@@ -557,15 +549,6 @@
return (IPPROTO_DONE);
}
- /* verify that the IP TTL is 255 */
- if (ip6->ip6_hlim != CARP_DFLTTL) {
- CARPSTATS_INC(carps_badttl);
- CARP_DEBUG("%s: received ttl %d != 255 on %s\n", __func__,
- ip6->ip6_hlim, m->m_pkthdr.rcvif->if_xname);
- m_freem(m);
- return (IPPROTO_DONE);
- }
-
/* verify that we have a complete carp packet */
if (m->m_len < *offp + sizeof(*ch)) {
len = m->m_len;
@@ -575,6 +558,7 @@
CARP_DEBUG("%s: packet size %u too small\n", __func__, len);
return (IPPROTO_DONE);
}
+ ip6 = mtod(m, struct ip6_hdr *);
}
ch = (struct carp_header *)(mtod(m, char *) + *offp);
@@ -589,7 +573,7 @@
}
m->m_data -= *offp;
- carp_input_c(m, ch, AF_INET6);
+ carp_input_c(m, ch, AF_INET6, ip6->ip6_hlim);
return (IPPROTO_DONE);
}
#endif /* INET6 */
@@ -640,7 +624,7 @@
}
static void
-carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
+carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af, int ttl)
{
struct ifnet *ifp = m->m_pkthdr.rcvif;
struct ifaddr *ifa, *match;
@@ -648,6 +632,7 @@
uint64_t tmp_counter;
struct timeval sc_tv, ch_tv;
int error;
+ bool multicast = false;
NET_EPOCH_ASSERT();
@@ -700,8 +685,22 @@
sc = ifa->ifa_carp;
CARP_LOCK(sc);
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ multicast = IN_MULTICAST(sc->sc_carpaddr);
+ } else {
+ multicast = IN6_IS_ADDR_MULTICAST(&sc->sc_carpaddr6);
+ }
ifa_free(ifa);
+ /* verify that the IP TTL is 255, but only if we're not in unicast mode. */
+ if (multicast && ttl != CARP_DFLTTL) {
+ CARPSTATS_INC(carps_badttl);
+ CARP_DEBUG("%s: received ttl %d != 255 on %s\n", __func__,
+ ttl,
+ m->m_pkthdr.rcvif->if_xname);
+ goto out;
+ }
+
if (carp_hmac_verify(sc, ch->carp_counter, ch->carp_md)) {
CARPSTATS_INC(carps_badauth);
CARP_DEBUG("%s: incorrect hash for VHID %u@%s\n", __func__,
@@ -954,7 +953,9 @@
m->m_pkthdr.rcvif = NULL;
m->m_len = len;
M_ALIGN(m, m->m_len);
- m->m_flags |= M_MCAST;
+
+ if (IN_MULTICAST(sc->sc_carpaddr))
+ m->m_flags |= M_MCAST;
ip = mtod(m, struct ip *);
ip->ip_v = IPVERSION;
ip->ip_hl = sizeof(*ip) >> 2;
@@ -973,7 +974,7 @@
ifa_free(ifa);
} else
ip->ip_src.s_addr = 0;
- ip->ip_dst.s_addr = htonl(INADDR_CARP_GROUP);
+ ip->ip_dst.s_addr = htonl(sc->sc_carpaddr);
ch_ptr = (struct carp_header *)(&ip[1]);
bcopy(&ch, ch_ptr, sizeof(ch));
@@ -1004,7 +1005,6 @@
m->m_pkthdr.rcvif = NULL;
m->m_len = len;
M_ALIGN(m, m->m_len);
- m->m_flags |= M_MCAST;
ip6 = mtod(m, struct ip6_hdr *);
bzero(ip6, sizeof(*ip6));
ip6->ip6_vfc |= IPV6_VERSION;
@@ -1026,12 +1026,14 @@
bzero(&ip6->ip6_src, sizeof(struct in6_addr));
/* Set the multicast destination. */
- ip6->ip6_dst.s6_addr16[0] = htons(0xff02);
- ip6->ip6_dst.s6_addr8[15] = 0x12;
- if (in6_setscope(&ip6->ip6_dst, sc->sc_carpdev, NULL) != 0) {
- m_freem(m);
- CARP_DEBUG("%s: in6_setscope failed\n", __func__);
- goto resched;
+ memcpy(&ip6->ip6_dst, &sc->sc_carpaddr6, sizeof(ip6->ip6_dst));
+ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
+ if (in6_setscope(&ip6->ip6_dst, sc->sc_carpdev, NULL) != 0) {
+ m_freem(m);
+ CARP_DEBUG("%s: in6_setscope failed\n", __func__);
+ goto resched;
+ }
+ m->m_flags |= M_MCAST;
}
ch_ptr = (struct carp_header *)(&ip6[1]);
@@ -1594,6 +1596,10 @@
sc->sc_ifas = malloc(sc->sc_ifasiz, M_CARP, M_WAITOK|M_ZERO);
sc->sc_carpdev = ifp;
+ sc->sc_carpaddr = INADDR_CARP_GROUP;
+ sc->sc_carpaddr6.s6_addr16[0] = htons(0xff02);
+ sc->sc_carpaddr6.s6_addr8[15] = 0x12;
+
CARP_LOCK_INIT(sc);
#ifdef INET
callout_init_mtx(&sc->sc_md_tmo, &sc->sc_mtx, CALLOUT_RETURNUNLOCKED);
@@ -1725,16 +1731,40 @@
CARP_UNLOCK(sc);
}
+static void
+carp_carpr_peercp(struct carpreq_peer *carprp, struct carp_softc *sc)
+{
+ CARP_LOCK(sc);
+ carprp->carprp_addr = htonl(sc->sc_carpaddr);
+ memcpy(&carprp->carprp_addr6, &sc->sc_carpaddr6,
+ sizeof(carprp->carprp_addr6));
+ CARP_UNLOCK(sc);
+}
+
int
carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
{
struct carpreq carpr;
+ struct carpreq_peer carpr_peer;
struct ifnet *ifp;
struct carp_softc *sc = NULL;
int error = 0, locked = 0;
- if ((error = copyin(ifr_data_get_ptr(ifr), &carpr, sizeof carpr)))
- return (error);
+ switch (cmd) {
+ case SIOCSVH:
+ case SIOCGVH:
+ if ((error = copyin(ifr_data_get_ptr(ifr), &carpr, sizeof carpr)))
+ return (error);
+ break;
+ case SIOCSPEER:
+ case SIOCGPEER:
+ if ((error = copyin(ifr_data_get_ptr(ifr), &carpr_peer,
+ sizeof carpr_peer)))
+ return (error);
+ break;
+ default:
+ panic("Unknown ioctl %#lx", cmd);
+ }
ifp = ifunit_ref(ifr->ifr_name);
if (ifp == NULL)
@@ -1878,7 +1908,87 @@
}
}
break;
- }
+ }
+ case SIOCSPEER:
+ if ((error = priv_check(td, PRIV_NETINET_CARP)))
+ break;
+ if (carpr_peer.carprp_vhid <= 0 ||
+ carpr_peer.carprp_vhid > CARP_MAXVHID) {
+ error = EINVAL;
+ break;
+ }
+ if (ifp->if_carp == NULL) {
+ error = ENOENT;
+ break;
+ }
+
+ IFNET_FOREACH_CARP(ifp, sc)
+ if (sc->sc_vhid == carpr_peer.carprp_vhid)
+ break;
+ if (sc == NULL) {
+ error = ENOENT;
+ break;
+ }
+
+ CARP_LOCK(sc);
+ sc->sc_carpaddr = ntohl(carpr_peer.carprp_addr);
+ memcpy(&sc->sc_carpaddr6, &carpr_peer.carprp_addr6,
+ sizeof(sc->sc_carpaddr6));
+ CARP_UNLOCK(sc);
+ break;
+ case SIOCGPEER:
+ if (carpr_peer.carprp_vhid < 0 ||
+ carpr_peer.carprp_vhid > CARP_MAXVHID) {
+ error = EINVAL;
+ break;
+ }
+ if (carpr_peer.carprp_count < 1) {
+ error = EMSGSIZE;
+ break;
+ }
+ if (ifp->if_carp == NULL) {
+ error = ENOENT;
+ break;
+ }
+ if (carpr_peer.carprp_vhid != 0) {
+ IFNET_FOREACH_CARP(ifp, sc)
+ if (sc->sc_vhid == carpr_peer.carprp_vhid)
+ break;
+ if (sc == NULL) {
+ error = ENOENT;
+ break;
+ }
+ carp_carpr_peercp(&carpr_peer, sc);
+ error = copyout(&carpr_peer, ifr_data_get_ptr(ifr),
+ sizeof(carpr_peer));
+ } else {
+ int i, count;
+
+ count = 0;
+ IFNET_FOREACH_CARP(ifp, sc)
+ count++;
+
+ if (count > carpr_peer.carprp_count) {
+ CIF_UNLOCK(ifp->if_carp);
+ error = EMSGSIZE;
+ break;
+ }
+
+ i = 0;
+ IFNET_FOREACH_CARP(ifp, sc) {
+ carp_carpr_peercp(&carpr_peer, sc);
+ carpr_peer.carprp_count = count;
+ error = copyout(&carpr_peer,
+ (char *)ifr_data_get_ptr(ifr) +
+ (i * sizeof(carpr_peer)), sizeof(carpr_peer));
+ if (error) {
+ CIF_UNLOCK(ifp->if_carp);
+ break;
+ }
+ i++;
+ }
+ }
+ break;
default:
error = EINVAL;
}

File Metadata

Mime Type
text/plain
Expires
Sun, Aug 30, 3:16 AM (31 m, 59 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37563709
Default Alt Text
D38940.id118445.diff (14 KB)

Event Timeline