Page MenuHomeFreeBSD

D23475.id67677.diff
No OneTemporary

D23475.id67677.diff

Index: /usr/src/sys/netinet/ip_carp.h
===================================================================
--- /usr/src/sys/netinet/ip_carp.h
+++ /usr/src/sys/netinet/ip_carp.h
@@ -92,6 +92,8 @@
#define CARP_KEY_LEN 20 /* a sha1 hash of a passphrase */
+#define CARP_AUTHLEN 7
+
/* carp_advbase */
#define CARP_DFLTINTV 1
@@ -110,6 +112,7 @@
uint64_t carps_badauth; /* bad authentication */
uint64_t carps_badvhid; /* bad VHID */
uint64_t carps_badaddrs; /* bad address list */
+ uint64_t carps_dups; /* duplicate packets */
uint64_t carps_opackets; /* total output packets, IPv4 */
uint64_t carps_opackets6; /* total output packets, IPv6 */
Index: /usr/src/sys/netinet/ip_carp.c
===================================================================
--- /usr/src/sys/netinet/ip_carp.c
+++ /usr/src/sys/netinet/ip_carp.c
@@ -115,7 +115,6 @@
int sc_sendad_success;
#define CARP_SENDAD_MIN_SUCCESS 3
- int sc_init_counter;
uint64_t sc_counter;
/* authentication */
@@ -416,7 +415,7 @@
/* fetch first half of inner hash */
bcopy(&sc->sc_sha1, &sha1ctx, sizeof(sha1ctx));
- SHA1Update(&sha1ctx, (void *)counter, sizeof(sc->sc_counter));
+ SHA1Update(&sha1ctx, (void *)counter, (sizeof(uint32_t) * 2));
SHA1Final(md, &sha1ctx);
/* outer hash */
@@ -594,110 +593,48 @@
}
#endif /* INET6 */
-/*
- * This routine should not be necessary at all, but some switches
- * (VMWare ESX vswitches) can echo our own packets back at us,
- * and we must ignore them or they will cause us to drop out of
- * MASTER mode.
- *
- * We cannot catch all cases of network loops. Instead, what we
- * do here is catch any packet that arrives with a carp header
- * with a VHID of 0, that comes from an address that is our own.
- * These packets are by definition "from us" (even if they are from
- * a misconfigured host that is pretending to be us).
- *
- * The VHID test is outside this mini-function.
- */
-static int
-carp_source_is_self(struct mbuf *m, struct ifaddr *ifa, sa_family_t af)
-{
-#ifdef INET
- struct ip *ip4;
- struct in_addr in4;
-#endif
-#ifdef INET6
- struct ip6_hdr *ip6;
- struct in6_addr in6;
-#endif
-
- switch (af) {
-#ifdef INET
- case AF_INET:
- ip4 = mtod(m, struct ip *);
- in4 = ifatoia(ifa)->ia_addr.sin_addr;
- return (in4.s_addr == ip4->ip_src.s_addr);
-#endif
-#ifdef INET6
- case AF_INET6:
- ip6 = mtod(m, struct ip6_hdr *);
- in6 = ifatoia6(ifa)->ia_addr.sin6_addr;
- return (memcmp(&in6, &ip6->ip6_src, sizeof(in6)) == 0);
-#endif
- default:
- break;
- }
- return (0);
-}
-
static void
carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
{
struct ifnet *ifp = m->m_pkthdr.rcvif;
- struct ifaddr *ifa, *match;
+ struct ifaddr *ifa;
struct carp_softc *sc;
uint64_t tmp_counter;
struct timeval sc_tv, ch_tv;
- int error;
- /*
- * Verify that the VHID is valid on the receiving interface.
- *
- * There should be just one match. If there are none
- * the VHID is not valid and we drop the packet. If
- * there are multiple VHID matches, take just the first
- * one, for compatibility with previous code. While we're
- * scanning, check for obvious loops in the network topology
- * (these should never happen, and as noted above, we may
- * miss real loops; this is just a double-check).
- */
- IF_ADDR_RLOCK(ifp);
- error = 0;
- match = NULL;
- IFNET_FOREACH_IFA(ifp, ifa) {
- if (match == NULL && ifa->ifa_carp != NULL &&
- ifa->ifa_addr->sa_family == af &&
- ifa->ifa_carp->sc_vhid == ch->carp_vhid)
- match = ifa;
- if (ch->carp_vhid == 0 && carp_source_is_self(m, ifa, af))
- error = ELOOP;
- }
- ifa = error ? NULL : match;
- if (ifa != NULL)
- ifa_ref(ifa);
- IF_ADDR_RUNLOCK(ifp);
-
- if (ifa == NULL) {
- if (error == ELOOP) {
- CARP_DEBUG("dropping looped packet on interface %s\n",
- ifp->if_xname);
- CARPSTATS_INC(carps_badif); /* ??? */
- } else {
- CARPSTATS_INC(carps_badvhid);
- }
+ /* Is VHID valid? */
+ if (ch->carp_vhid == 0) {
+ CARP_DEBUG("%s: invalid VHID: 0@%s\n", __func__,
+ ifp->if_xname);
+err_badvhid:
+ CARPSTATS_INC(carps_badvhid);
m_freem(m);
return;
}
-
- /* verify the CARP version. */
- if (ch->carp_version != CARP_VERSION) {
+ /* Verify the CARP version. */
+ if (ch->carp_version != CARP_VERSION ||
+ ch->carp_authlen != CARP_AUTHLEN) {
CARPSTATS_INC(carps_badver);
- CARP_DEBUG("%s: invalid version %d\n", ifp->if_xname,
- ch->carp_version);
- ifa_free(ifa);
m_freem(m);
+ CARP_DEBUG("%s: invalid version %d at %s\n", __func__,
+ ch->carp_version, ifp->if_xname);
return;
}
+ /* Verify that the VHID is valid on the receiving interface. */
+ IF_ADDR_RLOCK(ifp);
+ IFNET_FOREACH_IFA(ifp, ifa) {
+ if (ifa->ifa_addr->sa_family == af &&
+ ifa->ifa_carp != NULL &&
+ ifa->ifa_carp->sc_vhid == ch->carp_vhid) {
+ ifa_ref(ifa);
+ break;
+ }
+ }
+ IF_ADDR_RUNLOCK(ifp);
+ if (ifa == NULL)
+ goto err_badvhid;
+
sc = ifa->ifa_carp;
CARP_LOCK(sc);
ifa_free(ifa);
@@ -714,8 +651,12 @@
tmp_counter += ntohl(ch->carp_counter[1]);
/* XXX Replay protection goes here */
-
- sc->sc_init_counter = 0;
+ if (sc->sc_counter == tmp_counter) {
+ CARPSTATS_INC(carps_dups);
+ CARP_DEBUG("%s: dropping duplicated packet for VHID %u@%s\n",
+ __func__, sc->sc_vhid, ifp->if_xname);
+ goto out;
+ }
sc->sc_counter = tmp_counter;
sc_tv.tv_sec = sc->sc_advbase;
@@ -780,14 +721,7 @@
{
struct m_tag *mtag;
- if (sc->sc_init_counter) {
- /* this could also be seconds since unix epoch */
- sc->sc_counter = arc4random();
- sc->sc_counter = sc->sc_counter << 32;
- sc->sc_counter += arc4random();
- } else
- sc->sc_counter++;
-
+ sc->sc_counter++;
ch->carp_counter[0] = htonl((sc->sc_counter>>32)&0xffffffff);
ch->carp_counter[1] = htonl(sc->sc_counter&0xffffffff);
@@ -920,7 +854,7 @@
ch.carp_vhid = sc->sc_vhid;
ch.carp_advbase = sc->sc_advbase;
ch.carp_advskew = advskew;
- ch.carp_authlen = 7; /* XXX DEFINE */
+ ch.carp_authlen = CARP_AUTHLEN;
ch.carp_pad1 = 0; /* must be zero */
ch.carp_cksum = 0;
@@ -1569,8 +1503,11 @@
sc->sc_advbase = CARP_DFLTINTV;
sc->sc_vhid = -1; /* required setting */
- sc->sc_init_counter = 1;
sc->sc_state = INIT;
+ /* this could also be seconds since unix epoch */
+ sc->sc_counter = arc4random();
+ sc->sc_counter = sc->sc_counter << 32;
+ sc->sc_counter += arc4random();
sc->sc_ifasiz = sizeof(struct ifaddr *);
sc->sc_ifas = malloc(sc->sc_ifasiz, M_CARP, M_WAITOK|M_ZERO);
@@ -2028,7 +1965,7 @@
const char *carp_states[] = { CARP_STATES };
char subsys[IFNAMSIZ+5];
- snprintf(subsys, IFNAMSIZ+5, "%u@%s", sc->sc_vhid,
+ snprintf(subsys, sizeof(subsys), "%u@%s", sc->sc_vhid,
sc->sc_carpdev->if_xname);
CARP_LOG("%s: %s -> %s (%s)\n", subsys,
Index: /usr/src/usr.bin/netstat/inet.c
===================================================================
--- /usr/src/usr.bin/netstat/inet.c
+++ /usr/src/usr.bin/netstat/inet.c
@@ -907,6 +907,8 @@
"{N:/packet%s received (IPv4)}\n");
p(carps_ipackets6, "\t{:received-inet6-packets/%ju} "
"{N:/packet%s received (IPv6)}\n");
+ p(carps_badif, "\t\t{:dropped-bad-if/%ju} "
+ "{N:/packet%s discarded for wrong interface}\n");
p(carps_badttl, "\t\t{:dropped-wrong-ttl/%ju} "
"{N:/packet%s discarded for wrong TTL}\n");
p(carps_hdrops, "\t\t{:dropped-short-header/%ju} "
@@ -923,6 +925,8 @@
"{N:/discarded for bad vhid}\n");
p2(carps_badaddrs, "\t\t{:dropped-bad-address-list/%ju} "
"{N:/discarded because of a bad address list}\n");
+ p2(carps_dups, "\t\t{:dropped-duplicates/%ju} "
+ "{N:/discarded because packet is duplicate}\n");
p(carps_opackets, "\t{:sent-inet-packets/%ju} "
"{N:/packet%s sent (IPv4)}\n");
p(carps_opackets6, "\t{:sent-inet6-packets/%ju} "

File Metadata

Mime Type
text/plain
Expires
Wed, Jul 22, 3:57 PM (3 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35329056
Default Alt Text
D23475.id67677.diff (7 KB)

Event Timeline