Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 19 Jan 2017 15:57:00 -0800
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        Josh Paetzel <jpaetzel@FreeBSD.org>
Cc:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   Re: svn commit: r312439 - stable/11/sys/netinet
Message-ID:  <20170119235700.GM2611@FreeBSD.org>
In-Reply-To: <201701192338.v0JNcVM5099732@repo.freebsd.org>
References:  <201701192338.v0JNcVM5099732@repo.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
  Josh,

  did you notice my reply to the original commit?!

On Thu, Jan 19, 2017 at 11:38:31PM +0000, Josh Paetzel wrote:
J> Author: jpaetzel
J> Date: Thu Jan 19 23:38:31 2017
J> New Revision: 312439
J> URL: https://svnweb.freebsd.org/changeset/base/312439
J> 
J> Log:
J>   MFC 310847 310864
J>   
J>   Harden CARP against network loops.
J>   
J>   If there is a loop in the network a CARP that is in MASTER state will see it's
J>   own broadcasts, which will then cause it to assume BACKUP state.  When it
J>   assumes BACKUP it will stop sending advertisements.  In that state it will no
J>   longer see advertisements and will assume MASTER...
J>   
J>   We can't catch all the cases where we are seeing our own CARP broadcast, but
J>   we can catch the obvious case.
J>   
J>   Unbreak ip_carp with WITHOUT_INET6 enabled by conditionalizing all IPv6
J>   structs under the INET6 #ifdef. Similarly (even though it doesn't seem
J>   to affect the build), conditionalize all IPv4 structs under the INET
J>   #ifdef
J>   
J>   This also unbreaks the LINT-NOINET6 tinderbox target on amd64; I have not
J>   verified other MACHINE/TARGET pairs (e.g. armv6/arm).
J>   
J>   Submitted by:	torek
J>   Obtained from:	FreeNAS
J>   Pointyhat fix:	ngie
J> 
J> Modified:
J>   stable/11/sys/netinet/ip_carp.c
J> Directory Properties:
J>   stable/11/   (props changed)
J> 
J> Modified: stable/11/sys/netinet/ip_carp.c
J> ==============================================================================
J> --- stable/11/sys/netinet/ip_carp.c	Thu Jan 19 22:07:21 2017	(r312438)
J> +++ stable/11/sys/netinet/ip_carp.c	Thu Jan 19 23:38:31 2017	(r312439)
J> @@ -581,27 +581,96 @@ carp6_input(struct mbuf **mp, int *offp,
J>  }
J>  #endif /* INET6 */
J>  
J> +/*
J> + * This routine should not be necessary at all, but some switches
J> + * (VMWare ESX vswitches) can echo our own packets back at us,
J> + * and we must ignore them or they will cause us to drop out of
J> + * MASTER mode.
J> + *
J> + * We cannot catch all cases of network loops.  Instead, what we
J> + * do here is catch any packet that arrives with a carp header
J> + * with a VHID of 0, that comes from an address that is our own.
J> + * These packets are by definition "from us" (even if they are from
J> + * a misconfigured host that is pretending to be us).
J> + *
J> + * The VHID test is outside this mini-function.
J> + */
J> +static int
J> +carp_source_is_self(struct mbuf *m, struct ifaddr *ifa, sa_family_t af)
J> +{
J> +#ifdef INET
J> +	struct ip *ip4;
J> +	struct in_addr in4;
J> +#endif
J> +#ifdef INET6
J> +	struct ip6_hdr *ip6;
J> +	struct in6_addr in6;
J> +#endif
J> +
J> +	switch (af) {
J> +#ifdef INET
J> +	case AF_INET:
J> +		ip4 = mtod(m, struct ip *);
J> +		in4 = ifatoia(ifa)->ia_addr.sin_addr;
J> +		return (in4.s_addr == ip4->ip_src.s_addr);
J> +#endif
J> +#ifdef INET6
J> +	case AF_INET6:
J> +		ip6 = mtod(m, struct ip6_hdr *);
J> +		in6 = ifatoia6(ifa)->ia_addr.sin6_addr;
J> +		return (memcmp(&in6, &ip6->ip6_src, sizeof(in6)) == 0);
J> +#endif
J> +	default:
J> +		break;
J> +	}
J> +	return (0);
J> +}
J> +
J>  static void
J>  carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
J>  {
J>  	struct ifnet *ifp = m->m_pkthdr.rcvif;
J> -	struct ifaddr *ifa;
J> +	struct ifaddr *ifa, *match;
J>  	struct carp_softc *sc;
J>  	uint64_t tmp_counter;
J>  	struct timeval sc_tv, ch_tv;
J> +	int error;
J>  
J> -	/* verify that the VHID is valid on the receiving interface */
J> +	/*
J> +	 * Verify that the VHID is valid on the receiving interface.
J> +	 *
J> +	 * There should be just one match.  If there are none
J> +	 * the VHID is not valid and we drop the packet.  If
J> +	 * there are multiple VHID matches, take just the first
J> +	 * one, for compatibility with previous code.  While we're
J> +	 * scanning, check for obvious loops in the network topology
J> +	 * (these should never happen, and as noted above, we may
J> +	 * miss real loops; this is just a double-check).
J> +	 */
J>  	IF_ADDR_RLOCK(ifp);
J> -	IFNET_FOREACH_IFA(ifp, ifa)
J> -		if (ifa->ifa_addr->sa_family == af &&
J> -		    ifa->ifa_carp->sc_vhid == ch->carp_vhid) {
J> -			ifa_ref(ifa);
J> -			break;
J> -		}
J> +	error = 0;
J> +	match = NULL;
J> +	IFNET_FOREACH_IFA(ifp, ifa) {
J> +		if (match == NULL && ifa->ifa_carp != NULL &&
J> +		    ifa->ifa_addr->sa_family == af &&
J> +		    ifa->ifa_carp->sc_vhid == ch->carp_vhid)
J> +			match = ifa;
J> +		if (ch->carp_vhid == 0 && carp_source_is_self(m, ifa, af))
J> +			error = ELOOP;
J> +	}
J> +	ifa = error ? NULL : match;
J> +	if (ifa != NULL)
J> +		ifa_ref(ifa);
J>  	IF_ADDR_RUNLOCK(ifp);
J>  
J>  	if (ifa == NULL) {
J> -		CARPSTATS_INC(carps_badvhid);
J> +		if (error == ELOOP) {
J> +			CARP_DEBUG("dropping looped packet on interface %s\n",
J> +			    ifp->if_xname);
J> +			CARPSTATS_INC(carps_badif);	/* ??? */
J> +		} else {
J> +			CARPSTATS_INC(carps_badvhid);
J> +		}
J>  		m_freem(m);
J>  		return;
J>  	}
J> @@ -787,12 +856,41 @@ carp_send_ad_error(struct carp_softc *sc
J>  	}
J>  }
J>  
J> +/*
J> + * Pick the best ifaddr on the given ifp for sending CARP
J> + * advertisements.
J> + *
J> + * "Best" here is defined by ifa_preferred().  This function is much
J> + * much like ifaof_ifpforaddr() except that we just use ifa_preferred().
J> + *
J> + * (This could be simplified to return the actual address, except that
J> + * it has a different format in AF_INET and AF_INET6.)
J> + */
J> +static struct ifaddr *
J> +carp_best_ifa(int af, struct ifnet *ifp)
J> +{
J> +	struct ifaddr *ifa, *best;
J> +
J> +	if (af >= AF_MAX)
J> +		return (NULL);
J> +	best = NULL;
J> +	IF_ADDR_RLOCK(ifp);
J> +	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
J> +		if (ifa->ifa_addr->sa_family == af &&
J> +		    (best == NULL || ifa_preferred(best, ifa)))
J> +			best = ifa;
J> +	}
J> +	IF_ADDR_RUNLOCK(ifp);
J> +	if (best != NULL)
J> +		ifa_ref(best);
J> +	return (best);
J> +}
J> +
J>  static void
J>  carp_send_ad_locked(struct carp_softc *sc)
J>  {
J>  	struct carp_header ch;
J>  	struct timeval tv;
J> -	struct sockaddr sa;
J>  	struct ifaddr *ifa;
J>  	struct carp_header *ch_ptr;
J>  	struct mbuf *m;
J> @@ -841,9 +939,7 @@ carp_send_ad_locked(struct carp_softc *s
J>  		ip->ip_sum = 0;
J>  		ip_fillid(ip);
J>  
J> -		bzero(&sa, sizeof(sa));
J> -		sa.sa_family = AF_INET;
J> -		ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
J> +		ifa = carp_best_ifa(AF_INET, sc->sc_carpdev);
J>  		if (ifa != NULL) {
J>  			ip->ip_src.s_addr =
J>  			    ifatoia(ifa)->ia_addr.sin_addr.s_addr;
J> @@ -887,11 +983,9 @@ carp_send_ad_locked(struct carp_softc *s
J>  		ip6->ip6_vfc |= IPV6_VERSION;
J>  		ip6->ip6_hlim = CARP_DFLTTL;
J>  		ip6->ip6_nxt = IPPROTO_CARP;
J> -		bzero(&sa, sizeof(sa));
J>  
J>  		/* set the source address */
J> -		sa.sa_family = AF_INET6;
J> -		ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
J> +		ifa = carp_best_ifa(AF_INET6, sc->sc_carpdev);
J>  		if (ifa != NULL) {
J>  			bcopy(IFA_IN6(ifa), &ip6->ip6_src,
J>  			    sizeof(struct in6_addr));
J> _______________________________________________
J> svn-src-all@freebsd.org mailing list
J> https://lists.freebsd.org/mailman/listinfo/svn-src-all
J> To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"

-- 
Totus tuus, Glebius.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20170119235700.GM2611>