From nobody Tue Feb 25 10:04:19 2025 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 4Z2Cr41jgLz5pY4l; Tue, 25 Feb 2025 10:04:20 +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 "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Z2Cr40XYqz3pnj; Tue, 25 Feb 2025 10:04:20 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1740477860; 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=0f3XPLXM9DOiYC7VuFf0GfDOIZPPiM9xdstSfbeJ89U=; b=Cy4iMJZ+mdBWB1Jua6BbircowZXclNCa48HupgSVBDOQPHfDpgRlzs1dwcRladcuohlEgh JqI4nj0EbpgKDT/fHuNlTTdhLMPa5Rq3IhwvttlT9Z90J3URhamOMpeUOpshmdz+TdG32z +aKXT0t62+CUqUiQq+jfV87cTRzM3Cd4rasJfUNt0bPPoWPnTZYh+DPKZ6zvmypiz3CzYl oKEGWJzdc8SAT1cJgLtKRLEzLkfzz3ekq7Jy1cG76CHOyCdwUA4XFKxHQb/C2jDijcYj+r gizCad17/mKHETze1KVg4RUBL2v3Jsipo1vvBajFawA/SVv0ym5PjFpfZmNYjw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1740477860; a=rsa-sha256; cv=none; b=dWIFljhMKP+r5VVi4twd1v7hDOd9cTh5eTEC6dyi+F8fDyEe1kUrT5lxod5fbYXQAlpiSG oJNETW0rtfLQZfKZ7ql8MbEh/+8+THJ377e7B7Vgeq+4G2KKH16OvTc3idyBV5RKROCLlI ngNACFzKpbz+SKTK/Lt041m5nCTrvYVUEfWaDWAX3bRPSxRPSVarnQgjGQhEemX3Gilwyz Mjgm2DTaGFcVsVETSzTK1nMl9cwSyDILzMhdnhvmscGfdVlWJJ42qakd0UItRonga2D8zL BpoabDFUdy7Wr7XA5FOxm67IjazSSRD5ts7WOXnfCdQZoMlBh1SROS4VpsSNPQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1740477860; 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=0f3XPLXM9DOiYC7VuFf0GfDOIZPPiM9xdstSfbeJ89U=; b=CVSIvH3xZWtINP556/V8EY69CmmIaUw6zaTQBQ01dwVC45jdecRKbh8BTMpe5692NxvvJm oI4yR2IqkLJdRjB/2vJJbOeKATUqvxupZQlmCOYlJQ368ooJtxP+JIRZ/NtunJ/3Yf3EVA o77vzFPoqDFsNSzsnsK44VQpqtxhLAyed0YKJ0dGF0uEREqchcgygPdN0h/JbDudH7rfor ubyTCyh7+0EncwZnfZepKcrrrub18qyzR6T4WpAzTpGqVI8KbO1p77y/3Q6fJIz7Oa9W5m +vaohHP+Uxgz3Wb7nmHtkteybrf3H2ypxl6/rtj6qXPbTuswDwwEldJO6+3HuQ== 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 4Z2Cr403Nqz6jK; Tue, 25 Feb 2025 10:04:20 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 51PA4Jj5064270; Tue, 25 Feb 2025 10:04:19 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 51PA4Jb3064267; Tue, 25 Feb 2025 10:04:19 GMT (envelope-from git) Date: Tue, 25 Feb 2025 10:04:19 GMT Message-Id: <202502251004.51PA4Jb3064267@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kristof Provost Subject: git: 41265f65a549 - main - pf: cope with IPv6 gateways for an IPv4 route in nat64 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: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 41265f65a549d919363e322a39cbf3ce034c5de9 Auto-Submitted: auto-generated The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=41265f65a549d919363e322a39cbf3ce034c5de9 commit 41265f65a549d919363e322a39cbf3ce034c5de9 Author: Kristof Provost AuthorDate: 2025-02-21 15:49:45 +0000 Commit: Kristof Provost CommitDate: 2025-02-25 08:32:34 +0000 pf: cope with IPv6 gateways for an IPv4 route in nat64 It's possible for an IPv4 next hop to be specified as an IPv6 address. This broke pf's route lookup in pf_route(), which is required for nat64. Handle this case just like ip_tryforward(): use the struct sockaddr from the struct nhop_object, and mark a struct route to indicate if_output() has to use the gateway. Add a test case for this. PR: 284946 Reviewed by: zlei Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D49095 --- sys/netpfil/pf/pf.c | 40 +++++++++++++++------------- tests/sys/netpfil/pf/nat64.sh | 62 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 19 deletions(-) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 15d9697c0040..f3c9ea7a2fb1 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -337,7 +337,7 @@ static int pf_dummynet(struct pf_pdesc *, struct pf_kstate *, struct pf_krule *, struct mbuf **); static int pf_dummynet_route(struct pf_pdesc *, struct pf_kstate *, struct pf_krule *, - struct ifnet *, struct sockaddr *, struct mbuf **); + struct ifnet *, const struct sockaddr *, struct mbuf **); static int pf_test_eth_rule(int, struct pfi_kkif *, struct mbuf **); static int pf_test_rule(struct pf_krule **, struct pf_kstate **, @@ -8665,7 +8665,9 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp, struct pf_kstate *s, struct pf_pdesc *pd, struct inpcb *inp) { struct mbuf *m0, *m1, *md; - struct sockaddr_in dst; + struct route ro; + const struct sockaddr *gw = &ro.ro_dst; + struct sockaddr_in *dst; struct ip *ip; struct ifnet *ifp = NULL; int error = 0; @@ -8754,11 +8756,11 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp, ip = mtod(m0, struct ip *); - bzero(&dst, sizeof(dst)); - dst.sin_family = AF_INET; - dst.sin_len = sizeof(dst); - dst.sin_addr = ip->ip_dst; - dst.sin_addr.s_addr = pd->act.rt_addr.v4.s_addr; + bzero(&ro, sizeof(ro)); + dst = (struct sockaddr_in *)&ro.ro_dst; + dst->sin_family = AF_INET; + dst->sin_len = sizeof(struct sockaddr_in); + dst->sin_addr.s_addr = pd->act.rt_addr.v4.s_addr; if (s != NULL){ if (ifp == NULL && (pd->af != pd->naf)) { @@ -8769,10 +8771,12 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp, ifp = nh->nh_ifp; /* Use the gateway if needed. */ - if (nh->nh_flags & NHF_GATEWAY) - dst.sin_addr = nh->gw4_sa.sin_addr; - else - dst.sin_addr = ip->ip_dst; + if (nh->nh_flags & NHF_GATEWAY) { + gw = &nh->gw_sa; + ro.ro_flags |= RT_HAS_GW; + } else { + dst->sin_addr = ip->ip_dst; + } /* * Bind to the correct interface if we're @@ -8873,9 +8877,9 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp, m_clrprotoflags(m0); /* Avoid confusing lower layers. */ md = m0; - error = pf_dummynet_route(pd, s, r, ifp, sintosa(&dst), &md); + error = pf_dummynet_route(pd, s, r, ifp, gw, &md); if (md != NULL) { - error = (*ifp->if_output)(ifp, md, sintosa(&dst), NULL); + error = (*ifp->if_output)(ifp, md, gw, &ro); SDT_PROBE2(pf, ip, route_to, output, ifp, error); } goto done; @@ -8915,10 +8919,9 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp, md = m0; pd->pf_mtag = pf_find_mtag(md); error = pf_dummynet_route(pd, s, r, ifp, - sintosa(&dst), &md); + gw, &md); if (md != NULL) { - error = (*ifp->if_output)(ifp, md, - sintosa(&dst), NULL); + error = (*ifp->if_output)(ifp, md, gw, &ro); SDT_PROBE2(pf, ip, route_to, output, ifp, error); } } else @@ -9038,7 +9041,6 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp, bzero(&dst, sizeof(dst)); dst.sin6_family = AF_INET6; dst.sin6_len = sizeof(dst); - dst.sin6_addr = ip6->ip6_dst; PF_ACPY((struct pf_addr *)&dst.sin6_addr, &pd->act.rt_addr, AF_INET6); if (s != NULL) { @@ -9442,7 +9444,7 @@ pf_dummynet(struct pf_pdesc *pd, struct pf_kstate *s, static int pf_dummynet_route(struct pf_pdesc *pd, struct pf_kstate *s, - struct pf_krule *r, struct ifnet *ifp, struct sockaddr *sa, + struct pf_krule *r, struct ifnet *ifp, const struct sockaddr *sa, struct mbuf **m0) { struct ip_fw_args dnflow; @@ -9473,7 +9475,7 @@ pf_dummynet_route(struct pf_pdesc *pd, struct pf_kstate *s, MPASS(sa != NULL); - switch (pd->naf) { + switch (sa->sa_family) { case AF_INET: memcpy(&pd->pf_mtag->dst, sa, sizeof(struct sockaddr_in)); diff --git a/tests/sys/netpfil/pf/nat64.sh b/tests/sys/netpfil/pf/nat64.sh index 6227da01fccf..94c6c5fd8c8f 100644 --- a/tests/sys/netpfil/pf/nat64.sh +++ b/tests/sys/netpfil/pf/nat64.sh @@ -799,6 +799,67 @@ reply_to_cleanup() pft_cleanup } +atf_test_case "v6_gateway" "cleanup" +v6_gateway_head() +{ + atf_set descr 'nat64 when the IPv4 gateway is given by an IPv6 address' + atf_set require.user root +} + +v6_gateway_body() +{ + pft_init + + epair_wan_two=$(vnet_mkepair) + epair_wan_one=$(vnet_mkepair) + epair_lan=$(vnet_mkepair) + + ifconfig ${epair_lan}a inet6 2001:db8::2/64 up no_dad + route -6 add default 2001:db8::1 + + vnet_mkjail rtr ${epair_lan}b ${epair_wan_one}a + jexec rtr ifconfig ${epair_lan}b inet6 2001:db8::1/64 up no_dad + jexec rtr ifconfig ${epair_wan_one}a 192.0.2.1/24 up + jexec rtr ifconfig ${epair_wan_one}a inet6 -ifdisabled + jexec rtr route add default -inet6 fe80::1%${epair_wan_one}a + #jexec rtr route add default 192.0.2.2 + + vnet_mkjail wan_one ${epair_wan_one}b ${epair_wan_two}a + jexec wan_one ifconfig ${epair_wan_one}b 192.0.2.2/24 up + jexec wan_one ifconfig ${epair_wan_one}b inet6 fe80::1/64 + jexec wan_one ifconfig ${epair_wan_two}a 198.51.100.2/24 up + jexec wan_one route add default 192.0.2.1 + jexec wan_one sysctl net.inet.ip.forwarding=1 + + vnet_mkjail wan_two ${epair_wan_two}b + jexec wan_two ifconfig ${epair_wan_two}b 198.51.100.1/24 up + jexec wan_two route add default 198.51.100.2 + + # Sanity checks + atf_check -s exit:0 -o ignore \ + ping6 -c 1 2001:db8::1 + atf_check -s exit:0 -o ignore \ + jexec rtr ping -c 1 192.0.2.2 + atf_check -s exit:0 -o ignore \ + jexec rtr ping -c 1 198.51.100.1 + + jexec rtr pfctl -e + pft_set_rules rtr \ + "set reassemble yes" \ + "set state-policy if-bound" \ + "pass in on ${epair_lan}b inet6 from any to 64:ff9b::/96 af-to inet from (${epair_wan_one}a)" + + atf_check -s exit:0 -o ignore \ + ping6 -c 3 64:ff9b::192.0.2.2 + atf_check -s exit:0 -o ignore \ + ping6 -c 3 64:ff9b::198.51.100.1 +} + +v6_gateway_cleanup() +{ + pft_cleanup +} + atf_init_test_cases() { atf_add_test_case "icmp_echo" @@ -818,4 +879,5 @@ atf_init_test_cases() atf_add_test_case "gateway6" atf_add_test_case "route_to" atf_add_test_case "reply_to" + atf_add_test_case "v6_gateway" }