git: 9a1cab6d79b7 - main - pfsync: support deferring IPv6 packets

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Thu, 16 Feb 2023 08:26:24 UTC
The branch main has been updated by kp:

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

commit 9a1cab6d79b7286e5f650f57ed95625e6ddb8e4b
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2023-02-14 06:11:38 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2023-02-16 06:43:04 +0000

    pfsync: support deferring IPv6 packets
    
    When we send out a deferred packet we must make sure to call
    ip6_output() for IPv6 packets. If not we might end up attempting to
    ip_fragment() an IPv6 packet, which could lead to us reading outside of
    the mbuf.
    
    PR:             268246
    Reviewed by:    melifaro, zlei
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D38586
---
 sys/netpfil/pf/if_pfsync.c | 91 +++++++++++++++++++++++++++++-----------------
 1 file changed, 58 insertions(+), 33 deletions(-)

diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index 2301dc475e27..1c8d8d325346 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -103,9 +103,13 @@ __FBSDID("$FreeBSD$");
 #include <netinet/tcp_fsm.h>
 #include <netinet/tcp_seq.h>
 
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+
 #include <netpfil/pf/pfsync_nv.h>
 
 struct pfsync_bucket;
+struct pfsync_softc;
 
 union inet_template {
 	struct ip      ipv4;
@@ -171,6 +175,7 @@ static void	pfsync_q_ins(struct pf_kstate *, int, bool);
 static void	pfsync_q_del(struct pf_kstate *, bool, struct pfsync_bucket *);
 
 static void	pfsync_update_state(struct pf_kstate *);
+static void	pfsync_tx(struct pfsync_softc *, struct mbuf *);
 
 struct pfsync_upd_req_item {
 	TAILQ_ENTRY(pfsync_upd_req_item)	ur_entry;
@@ -187,8 +192,6 @@ struct pfsync_deferral {
 	struct mbuf			*pd_m;
 };
 
-struct pfsync_sofct;
-
 struct pfsync_bucket
 {
 	int			b_id;
@@ -1837,13 +1840,7 @@ pfsync_defer_tmo(void *arg)
 		free(pd, M_PFSYNC);
 	PFSYNC_BUCKET_UNLOCK(b);
 
-	switch (sc->sc_sync_peer.ss_family) {
-#ifdef INET
-	case AF_INET:
-		ip_output(m, NULL, NULL, 0, NULL, NULL);
-		break;
-#endif
-	}
+	pfsync_tx(sc, m);
 
 	pf_release_state(st);
 
@@ -2326,6 +2323,56 @@ pfsync_push_all(struct pfsync_softc *sc)
 	}
 }
 
+static void
+pfsync_tx(struct pfsync_softc *sc, struct mbuf *m)
+{
+	struct ip *ip;
+	int error, af;
+
+	ip = mtod(m, struct ip *);
+	MPASS(ip->ip_v == IPVERSION || ip->ip_v == (IPV6_VERSION >> 4));
+
+	af = ip->ip_v == IPVERSION ? AF_INET : AF_INET6;
+
+	/*
+	 * We distinguish between a deferral packet and our
+	 * own pfsync packet based on M_SKIP_FIREWALL
+	 * flag. This is XXX.
+	 */
+	switch (af) {
+#ifdef INET
+	case AF_INET:
+		if (m->m_flags & M_SKIP_FIREWALL) {
+			error = ip_output(m, NULL, NULL, 0,
+			    NULL, NULL);
+		} else {
+			error = ip_output(m, NULL, NULL,
+			    IP_RAWOUTPUT, &sc->sc_imo, NULL);
+		}
+		break;
+#endif
+#ifdef INET6
+	case AF_INET6:
+		if (m->m_flags & M_SKIP_FIREWALL) {
+			error = ip6_output(m, NULL, NULL, 0,
+			    NULL, NULL, NULL);
+		} else {
+			MPASS(false);
+			/* We don't support pfsync over IPv6. */
+			/*error = ip6_output(m, NULL, NULL,
+			    IP_RAWOUTPUT, &sc->sc_imo6, NULL);*/
+		}
+		break;
+#endif
+	}
+
+	if (error == 0)
+		V_pfsyncstats.pfsyncs_opackets++;
+	else
+		V_pfsyncstats.pfsyncs_oerrors++;
+
+}
+
 static void
 pfsyncintr(void *arg)
 {
@@ -2333,7 +2380,7 @@ pfsyncintr(void *arg)
 	struct pfsync_softc *sc = arg;
 	struct pfsync_bucket *b;
 	struct mbuf *m, *n;
-	int c, error;
+	int c;
 
 	NET_EPOCH_ENTER(et);
 	CURVNET_SET(sc->sc_ifp->if_vnet);
@@ -2353,29 +2400,7 @@ pfsyncintr(void *arg)
 			n = m->m_nextpkt;
 			m->m_nextpkt = NULL;
 
-			/*
-			 * We distinguish between a deferral packet and our
-			 * own pfsync packet based on M_SKIP_FIREWALL
-			 * flag. This is XXX.
-			 */
-			switch (sc->sc_sync_peer.ss_family) {
-#ifdef INET
-			case AF_INET:
-				if (m->m_flags & M_SKIP_FIREWALL) {
-					error = ip_output(m, NULL, NULL, 0,
-					    NULL, NULL);
-				} else {
-					error = ip_output(m, NULL, NULL,
-					    IP_RAWOUTPUT, &sc->sc_imo, NULL);
-				}
-				break;
-#endif
-			}
-
-			if (error == 0)
-				V_pfsyncstats.pfsyncs_opackets++;
-			else
-				V_pfsyncstats.pfsyncs_oerrors++;
+			pfsync_tx(sc, m);
 		}
 	}
 	CURVNET_RESTORE();