Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F168582823
D38940.id118445.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
D38940.id118445.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D38940: carp: support unicast
Attached
Detach File
Event Timeline
Log In to Comment