git: ea9113be3f19 - main - pf: extra route lookup in pf_route(6)()

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Tue, 17 Dec 2024 10:07:45 UTC
The branch main has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=ea9113be3f19db02d7108ebb207c2d5ca87e6a76

commit ea9113be3f19db02d7108ebb207c2d5ca87e6a76
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2024-10-28 13:18:30 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2024-12-17 10:07:13 +0000

    pf: extra route lookup in pf_route(6)()
    
    In the NAT64 case we use pf_route(6)() to emit the translated packet. This
    requires a new route lookup, so perform this, but only in the NAT64/NAT46 case.
    Update the destination sockaddr to send packets to the gateway if appropriate.
    
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D47788
---
 sys/netpfil/pf/pf.c | 69 ++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 52 insertions(+), 17 deletions(-)

diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 860f9a8fce64..36bb0e1975fa 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -8648,14 +8648,13 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
 	struct mbuf		*m0, *m1, *md;
 	struct sockaddr_in	dst;
 	struct ip		*ip;
-	struct ifnet		*ifp;
+	struct ifnet		*ifp = NULL;
 	int			 error = 0;
 	uint16_t		 ip_len, ip_off;
 	uint16_t		 tmp;
 	int			 r_dir;
 
-	KASSERT(m && *m && r && oifp && pd->act.rt_kif,
-	    ("%s: invalid parameters", __func__));
+	KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__));
 
 	SDT_PROBE4(pf, ip, route_to, entry, *m, pd, s, oifp);
 
@@ -8678,12 +8677,8 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
 		goto bad_locked;
 	}
 
-	if ((ifp = pd->act.rt_kif->pfik_ifp) == NULL) {
-		m0 = *m;
-		*m = NULL;
-		SDT_PROBE1(pf, ip, route_to, drop, __LINE__);
-		goto bad_locked;
-	}
+	if (pd->act.rt_kif != NULL)
+		ifp = pd->act.rt_kif->pfik_ifp;
 
 	if (pd->act.rt == PF_DUPTO) {
 		if ((pd->pf_mtag->flags & PF_MTAG_FLAG_DUPLICATED)) {
@@ -8733,9 +8728,31 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
 			s->orig_kif = oifp->if_pf_kif;
 		}
 
+		if (ifp == NULL && (pd->af != pd->naf)) {
+			/* We're in the AFTO case. Do a route lookup. */
+			struct nhop_object *nh;
+			nh = fib4_lookup(M_GETFIB(*m), ip->ip_dst, 0, NHR_NONE, 0);
+			if (nh) {
+				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;
+			}
+		}
+
 		PF_STATE_UNLOCK(s);
 	}
 
+	if (ifp == NULL) {
+		m0 = *m;
+		*m = NULL;
+		SDT_PROBE1(pf, ip, route_to, drop, __LINE__);
+		goto bad;
+	}
+
 	if (pd->dir == PF_IN) {
 		if (pf_test(AF_INET, PF_OUT, PFIL_FWD, ifp, &m0, inp,
 		    &pd->act) != PF_PASS) {
@@ -8887,8 +8904,7 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
 	struct ifnet		*ifp = NULL;
 	int			 r_dir;
 
-	KASSERT(m && *m && r && oifp && pd->act.rt_kif,
-	    ("%s: invalid parameters", __func__));
+	KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__));
 
 	SDT_PROBE4(pf, ip6, route_to, entry, *m, pd, s, oifp);
 
@@ -8911,12 +8927,8 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
 		goto bad_locked;
 	}
 
-	if ((ifp = pd->act.rt_kif->pfik_ifp) == NULL) {
-		m0 = *m;
-		*m = NULL;
-		SDT_PROBE1(pf, ip6, route_to, drop, __LINE__);
-		goto bad_locked;
-	}
+	if (pd->act.rt_kif != NULL)
+		ifp = pd->act.rt_kif->pfik_ifp;
 
 	if (pd->act.rt == PF_DUPTO) {
 		if ((pd->pf_mtag->flags & PF_MTAG_FLAG_DUPLICATED)) {
@@ -8965,9 +8977,32 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp,
 			s->kif = pd->act.rt_kif;
 			s->orig_kif = oifp->if_pf_kif;
 		}
+
+		if (ifp == NULL && (pd->af != pd->naf)) {
+			struct nhop_object *nh;
+			nh = fib6_lookup(M_GETFIB(*m), &ip6->ip6_dst, 0, NHR_NONE, 0);
+			if (nh) {
+				ifp = nh->nh_ifp;
+
+				/* Use the gateway if needed. */
+				if (nh->nh_flags & NHF_GATEWAY)
+					bcopy(&dst.sin6_addr, &nh->gw6_sa.sin6_addr,
+					    sizeof(dst.sin6_addr));
+				else
+					dst.sin6_addr = ip6->ip6_dst;
+			}
+		}
+
 		PF_STATE_UNLOCK(s);
 	}
 
+	if (ifp == NULL) {
+		m0 = *m;
+		*m = NULL;
+		SDT_PROBE1(pf, ip6, route_to, drop, __LINE__);
+		goto bad;
+	}
+
 	if (pd->dir == PF_IN) {
 		if (pf_test(AF_INET6, PF_OUT, PFIL_FWD | PF_PFIL_NOREFRAGMENT,
 		    ifp, &m0, inp, &pd->act) != PF_PASS) {