Date: Tue, 25 Feb 2025 10:04:19 GMT From: Kristof Provost <kp@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 41265f65a549 - main - pf: cope with IPv6 gateways for an IPv4 route in nat64 Message-ID: <202502251004.51PA4Jb3064267@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=41265f65a549d919363e322a39cbf3ce034c5de9 commit 41265f65a549d919363e322a39cbf3ce034c5de9 Author: Kristof Provost <kp@FreeBSD.org> AuthorDate: 2025-02-21 15:49:45 +0000 Commit: Kristof Provost <kp@FreeBSD.org> 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" }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202502251004.51PA4Jb3064267>