diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -337,7 +337,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 --- a/tests/sys/netpfil/pf/nat64.sh +++ b/tests/sys/netpfil/pf/nat64.sh @@ -799,6 +799,67 @@ 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_add_test_case "gateway6" atf_add_test_case "route_to" atf_add_test_case "reply_to" + atf_add_test_case "v6_gateway" }