From nobody Sat Dec 04 19:15:35 2021 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id E2FDB18D6BB5; Sat, 4 Dec 2021 19:15:35 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4J5ztH49tWz3CqX; Sat, 4 Dec 2021 19:15:35 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 706421B37; Sat, 4 Dec 2021 19:15:35 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 1B4JFZpj052282; Sat, 4 Dec 2021 19:15:35 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 1B4JFZPN052281; Sat, 4 Dec 2021 19:15:35 GMT (envelope-from git) Date: Sat, 4 Dec 2021 19:15:35 GMT Message-Id: <202112041915.1B4JFZPN052281@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: "Alexander V. Chernikov" Subject: git: b9772822a6b3 - stable/13 - routing: fix source address selection rules for IPv4 over IPv6. List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: melifaro X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: b9772822a6b363d2dad42ae8915730405986edb9 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1638645335; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=vcxDzZhqCjc5S583LWg0omN/26ApX4YQFKdD+H2TUHI=; b=l12Xf7e1YuKniAU1iKhYqC/EfNoFyRJfcYu8ByBJ5yb8FoHRLPMjrjFe7VACqD612O5wf6 Y5gecXfXC/ObzHZKa53J+rpIicEaG3ldqgCFI5IwaDviGsLQHwa7kKcEtcCnkF++hHgs84 m5QdkQg5vwzTFw3v+aymVU5n+bvP4XXahxHn/r+mayyYhvAHt1jgqk40uBIw7x2W7DVgOO b1S1VSpcsD4ndy5RM/qPXjh4WzVZXQtVZjbDiyIem+cd8hsntqAD0/1gI8WFEv26oMEsm5 /mzByy5kYxDdUjwY7t8WspxLNdQwxn5WxQ6+mtJQ2dlwk9H10vV+cS6DBo/BBQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1638645335; a=rsa-sha256; cv=none; b=gcScTBrtnNKovnWeYbAhZjiWpFbKDn/l4+6cqg0TIbLtSyXUOUa9b0vrntGGEKSlbJU9fS HqYzqYnaQ3Q7TMiHkUC+jdE4f4TO7gj4eHZnYm6m9Bt9hrbVdDt8s6d6xiHcN7Hb5GaQBu N9C9X1QHmC7xTq2SuwTOrOrxAx6NQzJwrOOtZwKAze4uIQgqDiAricc576DJouxj1neDtY rGYL4iYl/t/rgYJGgJYW66UX8mz0V4eA8znaU7c4hNkvFmWWuW+KmztkXRgbvyfqLSajJF EJIn5RlVVCQXvrkXxNBhWQjSLa8oXOSTY4rZbk0aiD0kqXI9qddd8DJMlfaPYA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=b9772822a6b363d2dad42ae8915730405986edb9 commit b9772822a6b363d2dad42ae8915730405986edb9 Author: Alexander V. Chernikov AuthorDate: 2021-09-06 22:08:15 +0000 Commit: Alexander V. Chernikov CommitDate: 2021-12-04 19:02:52 +0000 routing: fix source address selection rules for IPv4 over IPv6. Current logic always selects an IFA of the same family from the outgoing interfaces. In IPv4 over IPv6 setup there can be just single non-127.0.0.1 ifa, attached to the loopback interface. Create a separate rt_getifa_family() to handle entire ifa selection for the IPv4 over IPv6. Differential Revision: https://reviews.freebsd.org/D31868 MFC after: 1 week (cherry picked from commit 4b631fc832acf1bab24aa88aa06229d368d8e131) --- sys/net/route.c | 38 ++++++++++++++++++++++++++++++++++++++ sys/netinet/in.c | 34 ++++++++++++++++++++++++++++++++++ sys/netinet/in.h | 1 + 3 files changed, 73 insertions(+) diff --git a/sys/net/route.c b/sys/net/route.c index a24438563f50..b2c9051d98c0 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -532,6 +532,41 @@ info_get_ifp(struct rt_addrinfo *info) return (NULL); } +/* + * Calculates proper ifa/ifp for the cases when gateway AF is different + * from dst AF. + * + * Returns 0 on success. + */ +__noinline static int +rt_getifa_family(struct rt_addrinfo *info, uint32_t fibnum) +{ + if (info->rti_ifp == NULL) { + struct ifaddr *ifa = NULL; + /* + * No transmit interface specified. Guess it by checking gw sa. + */ + const struct sockaddr *gw = info->rti_info[RTAX_GATEWAY]; + ifa = ifa_ifwithroute(RTF_GATEWAY, gw, gw, fibnum); + if (ifa == NULL) + return (ENETUNREACH); + info->rti_ifp = ifa->ifa_ifp; + } + + /* Prefer address from outgoing interface */ + info->rti_ifa = ifaof_ifpforaddr(info->rti_info[RTAX_DST], info->rti_ifp); +#ifdef INET + if (info->rti_ifa == NULL) { + /* Use first found IPv4 address */ + bool loopback_ok = info->rti_ifp->if_flags & IFF_LOOPBACK; + info->rti_ifa = (struct ifaddr *)in_findlocal(fibnum, loopback_ok); + } +#endif + if (info->rti_ifa == NULL) + return (ENETUNREACH); + return (0); +} + /* * Look up rt_addrinfo for a specific fib. * @@ -564,6 +599,9 @@ rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) */ if (info->rti_ifa == NULL && ifaaddr != NULL) info->rti_ifa = ifa_ifwithaddr(ifaaddr); + if ((info->rti_ifa == NULL) && ((info->rti_flags & RTF_GATEWAY) != 0) && + (gateway->sa_family != dst->sa_family)) + return (rt_getifa_family(info, fibnum)); if (info->rti_ifa == NULL) { const struct sockaddr *sa; diff --git a/sys/netinet/in.c b/sys/netinet/in.c index a0ea17e47154..b51f1111b88a 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -194,6 +194,40 @@ in_localip_more(struct in_ifaddr *original_ia) return (NULL); } +/* + * Tries to find first IPv4 address in the provided fib. + * Prefers non-loopback addresses and return loopback IFF + * @loopback_ok is set. + * + * Returns ifa or NULL. + */ +struct in_ifaddr * +in_findlocal(uint32_t fibnum, bool loopback_ok) +{ + struct rm_priotracker in_ifa_tracker; + struct in_ifaddr *ia = NULL, *ia_lo = NULL; + + NET_EPOCH_ASSERT(); + + IN_IFADDR_RLOCK(&in_ifa_tracker); + CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { + uint32_t ia_fib = ia->ia_ifa.ifa_ifp->if_fib; + if (!V_rt_add_addr_allfibs && (fibnum != ia_fib)) + continue; + + if (!IN_LOOPBACK(ntohl(IA_SIN(ia)->sin_addr.s_addr))) + break; + if (loopback_ok) + ia_lo = ia; + } + IN_IFADDR_RUNLOCK(&in_ifa_tracker); + + if (ia == NULL) + ia = ia_lo; + + return (ia); +} + /* * Determine whether an IP address is in a reserved set of addresses * that may not be forwarded, or whether datagrams to that destination diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 28d6721edc53..0206fd16d2fe 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -651,6 +651,7 @@ int in_canforward(struct in_addr); int in_localaddr(struct in_addr); int in_localip(struct in_addr); int in_ifhasaddr(struct ifnet *, struct in_addr); +struct in_ifaddr *in_findlocal(uint32_t, bool); int inet_aton(const char *, struct in_addr *); /* in libkern */ char *inet_ntoa_r(struct in_addr ina, char *buf); /* in libkern */ char *inet_ntop(int, const void *, char *, socklen_t); /* in libkern */