From owner-svn-src-all@freebsd.org Thu Jan 19 23:57:03 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 404B4CB887E; Thu, 19 Jan 2017 23:57:03 +0000 (UTC) (envelope-from glebius@FreeBSD.org) Received: from cell.glebi.us (glebi.us [96.95.210.25]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "cell.glebi.us", Issuer "cell.glebi.us" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 2B41316A6; Thu, 19 Jan 2017 23:57:02 +0000 (UTC) (envelope-from glebius@FreeBSD.org) Received: from cell.glebi.us (localhost [127.0.0.1]) by cell.glebi.us (8.15.2/8.15.2) with ESMTPS id v0JNv1Dr070739 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Thu, 19 Jan 2017 15:57:01 -0800 (PST) (envelope-from glebius@FreeBSD.org) Received: (from glebius@localhost) by cell.glebi.us (8.15.2/8.15.2/Submit) id v0JNv1BI070738; Thu, 19 Jan 2017 15:57:01 -0800 (PST) (envelope-from glebius@FreeBSD.org) X-Authentication-Warning: cell.glebi.us: glebius set sender to glebius@FreeBSD.org using -f Date: Thu, 19 Jan 2017 15:57:00 -0800 From: Gleb Smirnoff To: Josh Paetzel 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> References: <201701192338.v0JNcVM5099732@repo.freebsd.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <201701192338.v0JNcVM5099732@repo.freebsd.org> User-Agent: Mutt/1.7.2 (2016-11-26) X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 19 Jan 2017 23:57:03 -0000 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.