Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 19 Sep 2024 20:21:17 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: 9ec74b675e04 - main - pf: factor out pf_setup_pdesc()
Message-ID:  <202409192021.48JKLHBQ046347@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=9ec74b675e04304df3e29eec80d8d259a1254c17

commit 9ec74b675e04304df3e29eec80d8d259a1254c17
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2024-09-02 14:24:38 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2024-09-19 20:20:13 +0000

    pf: factor out pf_setup_pdesc()
    
    factor our the code to set up pf_pdesc, a central structure in pf carrying
    information about the packet we're currently dealing with, into its own
    function. ok ryan dlg and additional testing sthen
    
    Obtained from:  OpenBSD, henning <henning@openbsd.org>, c4202972a3
    Obtained from:  OpenBSD, claudio <claudio@openbsd.org>, 78d25123ea
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D46586
---
 sys/net/pfvar.h          |   8 +
 sys/netpfil/pf/pf.c      | 624 +++++++++++++++++++++++++++--------------------
 sys/netpfil/pf/pf_norm.c |   9 +-
 3 files changed, 363 insertions(+), 278 deletions(-)

diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 4bb09d637def..9a0130dbf487 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1610,6 +1610,7 @@ struct pf_pdesc {
 	struct pf_rule_actions	act;
 
 	u_int32_t	 p_len;		/* total length of payload */
+	u_int32_t	 rh_cnt;	/* Route header count */
 
 	u_int16_t	*ip_sum;
 	u_int16_t	*proto_sum;
@@ -2350,8 +2351,15 @@ VNET_DECLARE(struct pf_krule,		 pf_default_rule);
 extern void			 pf_addrcpy(struct pf_addr *, struct pf_addr *,
 				    sa_family_t);
 void				pf_free_rule(struct pf_krule *);
+int				pf_setup_pdesc(sa_family_t, int,
+				    struct pf_pdesc *, struct mbuf *,
+				    u_short *, u_short *, struct pfi_kkif *,
+				    struct pf_krule **, struct pf_krule **,
+				    struct pf_kruleset **, int *, int *,
+				    struct pf_rule_actions *);
 
 int	pf_test_eth(int, int, struct ifnet *, struct mbuf **, struct inpcb *);
+int	pf_scan_sctp(struct mbuf *, int, struct pf_pdesc *, struct pfi_kkif *);
 #ifdef INET
 int	pf_test(int, int, struct ifnet *, struct mbuf **, struct inpcb *,
 	    struct pf_rule_actions *);
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 58bcd1f2ee71..59db6fd96953 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -324,7 +324,7 @@ static int		 pf_test_eth_rule(int, struct pfi_kkif *,
 static int		 pf_test_rule(struct pf_krule **, struct pf_kstate **,
 			    struct pfi_kkif *, struct mbuf *, int,
 			    struct pf_pdesc *, struct pf_krule **,
-			    struct pf_kruleset **, struct inpcb *);
+			    struct pf_kruleset **, struct inpcb *, int);
 static int		 pf_create_state(struct pf_krule *, struct pf_krule *,
 			    struct pf_krule *, struct pf_pdesc *,
 			    struct pf_ksrc_node *, struct pf_state_key *,
@@ -4865,7 +4865,7 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0)
 static int
 pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, struct pfi_kkif *kif,
     struct mbuf *m, int off, struct pf_pdesc *pd, struct pf_krule **am,
-    struct pf_kruleset **rsm, struct inpcb *inp)
+    struct pf_kruleset **rsm, struct inpcb *inp, int hdrlen)
 {
 	struct pf_krule		*nr = NULL;
 	struct pf_addr		* const saddr = pd->src;
@@ -4879,7 +4879,7 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, struct pfi_kkif *kif,
 	struct tcphdr		*th = &pd->hdr.tcp;
 	struct pf_state_key	*sk = NULL, *nk = NULL;
 	u_short			 reason, transerror;
-	int			 rewrite = 0, hdrlen = 0;
+	int			 rewrite = 0;
 	int			 tag = -1;
 	int			 asd = 0;
 	int			 match = 0;
@@ -4905,23 +4905,19 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, struct pfi_kkif *kif,
 	case IPPROTO_TCP:
 		sport = th->th_sport;
 		dport = th->th_dport;
-		hdrlen = sizeof(*th);
 		break;
 	case IPPROTO_UDP:
 		sport = pd->hdr.udp.uh_sport;
 		dport = pd->hdr.udp.uh_dport;
-		hdrlen = sizeof(pd->hdr.udp);
 		break;
 	case IPPROTO_SCTP:
 		sport = pd->hdr.sctp.src_port;
 		dport = pd->hdr.sctp.dest_port;
-		hdrlen = sizeof(pd->hdr.sctp);
 		break;
 #ifdef INET
 	case IPPROTO_ICMP:
 		if (pd->af != AF_INET)
 			break;
-		hdrlen = sizeof(pd->hdr.icmp);
 		icmptype = pd->hdr.icmp.icmp_type;
 		icmpcode = pd->hdr.icmp.icmp_code;
 		state_icmp = pf_icmp_mapping(pd, icmptype,
@@ -4939,7 +4935,6 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, struct pfi_kkif *kif,
 	case IPPROTO_ICMPV6:
 		if (af != AF_INET6)
 			break;
-		hdrlen = sizeof(pd->hdr.icmp6);
 		icmptype = pd->hdr.icmp6.icmp6_type;
 		icmpcode = pd->hdr.icmp6.icmp6_code;
 		state_icmp = pf_icmp_mapping(pd, icmptype,
@@ -4955,7 +4950,7 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, struct pfi_kkif *kif,
 		break;
 #endif /* INET6 */
 	default:
-		sport = dport = hdrlen = 0;
+		sport = dport = 0;
 		break;
 	}
 
@@ -6662,7 +6657,8 @@ again:
 			 * That's why we pass V_pfi_all rather than kif.
 			 */
 			ret = pf_test_rule(&r, &sm, V_pfi_all,
-			    j->m, off, &j->pd, &ra, &rs, NULL);
+			    j->m, off, &j->pd, &ra, &rs, NULL,
+			    sizeof(j->pd.hdr.sctp));
 			PF_RULES_RUNLOCK();
 			SDT_PROBE4(pf, sctp, multihome, test, kif, r, j->m, ret);
 			if (ret != PF_DROP && sm != NULL) {
@@ -8540,6 +8536,290 @@ pf_dummynet_route(struct pf_pdesc *pd, struct pf_kstate *s,
 	return (0);
 }
 
+int
+pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf *m,
+    u_short *action, u_short *reason, struct pfi_kkif *kif, struct pf_krule **a,
+    struct pf_krule **r, struct pf_kruleset **ruleset, int *off, int *hdrlen,
+    struct pf_rule_actions *default_actions)
+{
+
+	TAILQ_INIT(&pd->sctp_multihome_jobs);
+	if (default_actions != NULL)
+		memcpy(&pd->act, default_actions, sizeof(pd->act));
+	pd->pf_mtag = pf_find_mtag(m);
+
+	if (pd->pf_mtag && pd->pf_mtag->dnpipe) {
+		pd->act.dnpipe = pd->pf_mtag->dnpipe;
+		pd->act.flags = pd->pf_mtag->dnflags;
+	}
+
+	pd->af = af;
+
+	switch (af) {
+#ifdef INET
+	case AF_INET: {
+		struct ip *h;
+
+		h = mtod(m, struct ip *);
+		*off = h->ip_hl << 2;
+		if (*off < (int)sizeof(*h)) {
+			*action = PF_DROP;
+			REASON_SET(reason, PFRES_SHORT);
+			return (-1);
+		}
+		pd->src = (struct pf_addr *)&h->ip_src;
+		pd->dst = (struct pf_addr *)&h->ip_dst;
+		pd->sport = pd->dport = NULL;
+		pd->ip_sum = &h->ip_sum;
+		pd->proto_sum = NULL;
+		pd->proto = h->ip_p;
+		pd->dir = dir;
+		pd->sidx = (dir == PF_IN) ? 0 : 1;
+		pd->didx = (dir == PF_IN) ? 1 : 0;
+		pd->tos = h->ip_tos;
+		pd->tot_len = ntohs(h->ip_len);
+		pd->act.rtableid = -1;
+
+		/* fragments not reassembled handled later */
+		if (h->ip_off & htons(IP_MF | IP_OFFMASK))
+			return (0);
+
+		switch (h->ip_p) {
+		case IPPROTO_TCP: {
+			struct tcphdr *th = &pd->hdr.tcp;
+
+			if (!pf_pull_hdr(m, *off, th, sizeof(*th), action,
+				reason, AF_INET))
+				return (-1);
+			*hdrlen = sizeof(*th);
+			pd->p_len = pd->tot_len - *off - (th->th_off << 2);
+			pd->sport = &th->th_sport;
+			pd->dport = &th->th_dport;
+			break;
+		}
+		case IPPROTO_UDP: {
+			struct udphdr *uh = &pd->hdr.udp;
+
+			if (!pf_pull_hdr(m, *off, uh, sizeof(*uh), action,
+				reason, AF_INET))
+				return (-1);
+			*hdrlen = sizeof(*uh);
+			if (uh->uh_dport == 0 ||
+			    ntohs(uh->uh_ulen) > m->m_pkthdr.len - *off ||
+			    ntohs(uh->uh_ulen) < sizeof(struct udphdr)) {
+				*action = PF_DROP;
+				REASON_SET(reason, PFRES_SHORT);
+				return (-1);
+			}
+			pd->sport = &uh->uh_sport;
+			pd->dport = &uh->uh_dport;
+			break;
+		}
+		case IPPROTO_SCTP: {
+			if (!pf_pull_hdr(m, *off, &pd->hdr.sctp, sizeof(pd->hdr.sctp),
+			    action, reason, AF_INET)) {
+				return (-1);
+			}
+			*hdrlen = sizeof(pd->hdr.sctp);
+			pd->p_len = pd->tot_len - *off;
+
+			pd->sport = &pd->hdr.sctp.src_port;
+			pd->dport = &pd->hdr.sctp.dest_port;
+			if (pd->hdr.sctp.src_port == 0 || pd->hdr.sctp.dest_port == 0) {
+				*action = PF_DROP;
+				REASON_SET(reason, PFRES_SHORT);
+				return (-1);
+			}
+			if (pf_scan_sctp(m, *off, pd, kif) != PF_PASS) {
+				*action = PF_DROP;
+				REASON_SET(reason, PFRES_SHORT);
+				return (-1);
+			}
+			break;
+		}
+		case IPPROTO_ICMP: {
+			if (!pf_pull_hdr(m, *off, &pd->hdr.icmp, ICMP_MINLEN,
+				action, reason, AF_INET))
+				return (-1);
+			*hdrlen = ICMP_MINLEN;
+			break;
+		}
+		}
+		break;
+	}
+#endif
+#ifdef INET6
+	case AF_INET6: {
+		struct ip6_hdr *h;
+		int terminal = 0;
+
+		h = mtod(m, struct ip6_hdr *);
+		pd->src = (struct pf_addr *)&h->ip6_src;
+		pd->dst = (struct pf_addr *)&h->ip6_dst;
+		pd->sport = pd->dport = NULL;
+		pd->ip_sum = NULL;
+		pd->proto_sum = NULL;
+		pd->dir = dir;
+		pd->sidx = (dir == PF_IN) ? 0 : 1;
+		pd->didx = (dir == PF_IN) ? 1 : 0;
+		pd->tos = IPV6_DSCP(h);
+		pd->tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
+		*off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
+		pd->proto = h->ip6_nxt;
+		pd->act.rtableid = -1;
+
+		do {
+			switch (pd->proto) {
+			case IPPROTO_FRAGMENT:
+				if (kif == NULL || r == NULL) /* pflog */
+					*action = PF_DROP;
+				else
+					*action = pf_test_fragment(r, kif,
+					    m, h, pd, a, ruleset);
+				if (*action == PF_DROP)
+					REASON_SET(reason, PFRES_FRAG);
+				return (-1);
+			case IPPROTO_ROUTING: {
+				struct ip6_rthdr rthdr;
+
+				if (pd->rh_cnt++) {
+					DPFPRINTF(PF_DEBUG_MISC,
+					    ("pf: IPv6 more than one rthdr"));
+					*action = PF_DROP;
+					REASON_SET(reason, PFRES_IPOPTIONS);
+					return (-1);
+				}
+				if (!pf_pull_hdr(m, *off, &rthdr, sizeof(rthdr),
+					NULL, reason, pd->af)) {
+					DPFPRINTF(PF_DEBUG_MISC,
+					    ("pf: IPv6 short rthdr"));
+					*action = PF_DROP;
+					REASON_SET(reason, PFRES_SHORT);
+					return (-1);
+				}
+				if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) {
+					DPFPRINTF(PF_DEBUG_MISC,
+					    ("pf: IPv6 rthdr0"));
+					*action = PF_DROP;
+					REASON_SET(reason, PFRES_IPOPTIONS);
+					return (-1);
+				}
+				/* FALLTHROUGH */
+			}
+			case IPPROTO_AH:
+			case IPPROTO_HOPOPTS:
+			case IPPROTO_DSTOPTS: {
+				/* get next header and header length */
+				struct ip6_ext opt6;
+
+				if (!pf_pull_hdr(m, *off, &opt6, sizeof(opt6),
+					NULL, reason, pd->af)) {
+					DPFPRINTF(PF_DEBUG_MISC,
+					    ("pf: IPv6 short opt"));
+					*action = PF_DROP;
+					return (-1);
+				}
+				if (pd->proto == IPPROTO_AH)
+					*off += (opt6.ip6e_len + 2) * 4;
+				else
+					*off += (opt6.ip6e_len + 1) * 8;
+				pd->proto = opt6.ip6e_nxt;
+				/* goto the next header */
+				break;
+			}
+			default:
+				terminal++;
+				break;
+			}
+		} while (!terminal);
+
+		switch (pd->proto) {
+		case IPPROTO_TCP: {
+			struct tcphdr *th = &pd->hdr.tcp;
+
+			if (!pf_pull_hdr(m, *off, th, sizeof(*th), action,
+				reason, AF_INET6))
+				return (-1);
+			*hdrlen = sizeof(*th);
+			pd->p_len = pd->tot_len - *off - (th->th_off << 2);
+			pd->sport = &th->th_sport;
+			pd->dport = &th->th_dport;
+			break;
+		}
+		case IPPROTO_UDP: {
+			struct udphdr *uh = &pd->hdr.udp;
+
+			if (!pf_pull_hdr(m, *off, uh, sizeof(*uh), action,
+				reason, AF_INET6))
+				return (-1);
+			*hdrlen = sizeof(*uh);
+			if (uh->uh_dport == 0 ||
+			    ntohs(uh->uh_ulen) > m->m_pkthdr.len - *off ||
+			    ntohs(uh->uh_ulen) < sizeof(struct udphdr)) {
+				*action = PF_DROP;
+				REASON_SET(reason, PFRES_SHORT);
+				return (-1);
+			}
+			pd->sport = &uh->uh_sport;
+			pd->dport = &uh->uh_dport;
+			break;
+		}
+		case IPPROTO_SCTP: {
+			if (!pf_pull_hdr(m, *off, &pd->hdr.sctp, sizeof(pd->hdr.sctp),
+			    action, reason, AF_INET6)) {
+				return (-1);
+			}
+			*hdrlen = sizeof(pd->hdr.sctp);
+			pd->p_len = pd->tot_len - *off;
+
+			pd->sport = &pd->hdr.sctp.src_port;
+			pd->dport = &pd->hdr.sctp.dest_port;
+			if (pd->hdr.sctp.src_port == 0 || pd->hdr.sctp.dest_port == 0) {
+				*action = PF_DROP;
+				REASON_SET(reason, PFRES_SHORT);
+				return (-1);
+			}
+			if (pf_scan_sctp(m, *off, pd, kif) != PF_PASS) {
+				*action = PF_DROP;
+				REASON_SET(reason, PFRES_SHORT);
+				return (-1);
+			}
+			break;
+		}
+		case IPPROTO_ICMPV6: {
+			size_t icmp_hlen = sizeof(struct icmp6_hdr);
+
+			if (!pf_pull_hdr(m, *off, &pd->hdr.icmp6, icmp_hlen,
+				action, reason, AF_INET6))
+				return (-1);
+			/* ICMP headers we look further into to match state */
+			switch (pd->hdr.icmp6.icmp6_type) {
+			case MLD_LISTENER_QUERY:
+			case MLD_LISTENER_REPORT:
+				icmp_hlen = sizeof(struct mld_hdr);
+				break;
+			case ND_NEIGHBOR_SOLICIT:
+			case ND_NEIGHBOR_ADVERT:
+				icmp_hlen = sizeof(struct nd_neighbor_solicit);
+				break;
+			}
+			if (icmp_hlen > sizeof(struct icmp6_hdr) &&
+			    !pf_pull_hdr(m, *off, &pd->hdr.icmp6, icmp_hlen,
+				action, reason, AF_INET6))
+				return (-1);
+			*hdrlen = icmp_hlen;
+			break;
+		}
+		}
+		break;
+	}
+#endif
+	default:
+		panic("pf_setup_pdesc called with illegal af %u", af);
+	}
+	return (0);
+}
+
 #ifdef INET
 int
 pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
@@ -8554,7 +8834,7 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
 	struct pf_kstate	*s = NULL;
 	struct pf_kruleset	*ruleset = NULL;
 	struct pf_pdesc		 pd;
-	int			 off, dirndx, use_2nd_queue = 0;
+	int			 off, hdrlen, dirndx, use_2nd_queue = 0;
 	uint16_t		 tag;
 	uint8_t			 rt;
 
@@ -8591,11 +8871,31 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
 			return (PF_DROP);
 	}
 
+	if (__predict_false(m->m_len < sizeof(struct ip)) &&
+	    (m = *m0 = m_pullup(*m0, sizeof(struct ip))) == NULL) {
+		DPFPRINTF(PF_DEBUG_URGENT,
+		    ("pf_test: m_len < sizeof(struct ip), pullup failed\n"));
+		PF_RULES_RUNLOCK();
+		return (PF_DROP);
+	}
+
 	memset(&pd, 0, sizeof(pd));
-	TAILQ_INIT(&pd.sctp_multihome_jobs);
-	if (default_actions != NULL)
-		memcpy(&pd.act, default_actions, sizeof(pd.act));
-	pd.pf_mtag = pf_find_mtag(m);
+	pd.dir = dir;
+
+	if (pf_normalize_ip(m0, kif, &reason, &pd) != PF_PASS) {
+		/* We do IP header normalization and packet reassembly here */
+		action = PF_DROP;
+		goto done;
+	}
+	m = *m0;	/* pf_normalize messes with m0 */
+	h = mtod(m, struct ip *);
+
+	if (pf_setup_pdesc(AF_INET, dir, &pd, m, &action, &reason, kif, &a, &r,
+		&ruleset, &off, &hdrlen, default_actions) == -1) {
+		if (action != PF_PASS)
+			pd.act.log |= PF_LOG_FORCE;
+		goto done;
+	}
 
 	if (pd.pf_mtag != NULL && (pd.pf_mtag->flags & PF_MTAG_FLAG_ROUTE_TO)) {
 		pd.pf_mtag->flags &= ~PF_MTAG_FLAG_ROUTE_TO;
@@ -8614,11 +8914,6 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
 		return (PF_PASS);
 	}
 
-	if (pd.pf_mtag && pd.pf_mtag->dnpipe) {
-		pd.act.dnpipe = pd.pf_mtag->dnpipe;
-		pd.act.flags = pd.pf_mtag->dnflags;
-	}
-
 	if (ip_dn_io_ptr != NULL && pd.pf_mtag != NULL &&
 	    pd.pf_mtag->flags & PF_MTAG_FLAG_DUMMYNET) {
 		/* Dummynet re-injects packets after they've
@@ -8633,24 +8928,6 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
 		return (PF_PASS);
 	}
 
-	pd.sport = pd.dport = NULL;
-	pd.proto_sum = NULL;
-	pd.dir = dir;
-	pd.sidx = (dir == PF_IN) ? 0 : 1;
-	pd.didx = (dir == PF_IN) ? 1 : 0;
-	pd.af = AF_INET;
-	pd.act.rtableid = -1;
-
-	if (__predict_false(m->m_len < sizeof(struct ip)) &&
-	    (m = *m0 = m_pullup(*m0, sizeof(struct ip))) == NULL) {
-		DPFPRINTF(PF_DEBUG_URGENT,
-		    ("pf_test: m_len < sizeof(struct ip), pullup failed\n"));
-		PF_RULES_RUNLOCK();
-		return (PF_DROP);
-	}
-	h = mtod(m, struct ip *);
-	off = h->ip_hl << 2;
-
 	if (__predict_false(ip_divert_ptr != NULL) &&
 	    ((mtag = m_tag_locate(m, MTAG_PF_DIVERT, 0, NULL)) != NULL)) {
 		struct pf_divert_mtag *dt = (struct pf_divert_mtag *)(mtag+1);
@@ -8672,28 +8949,7 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
 		mtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL);
 		if (mtag != NULL)
 			m_tag_delete(m, mtag);
-	} else if (pf_normalize_ip(m0, kif, &reason, &pd) != PF_PASS) {
-		/* We do IP header normalization and packet reassembly here */
-		action = PF_DROP;
-		goto done;
 	}
-	m = *m0;	/* pf_normalize messes with m0 */
-	h = mtod(m, struct ip *);
-
-	off = h->ip_hl << 2;
-	if (off < (int)sizeof(struct ip)) {
-		action = PF_DROP;
-		REASON_SET(&reason, PFRES_SHORT);
-		pd.act.log = PF_LOG_FORCE;
-		goto done;
-	}
-
-	pd.src = (struct pf_addr *)&h->ip_src;
-	pd.dst = (struct pf_addr *)&h->ip_dst;
-	pd.ip_sum = &h->ip_sum;
-	pd.proto = h->ip_p;
-	pd.tos = h->ip_tos & ~IPTOS_ECN_MASK;
-	pd.tot_len = ntohs(h->ip_len);
 
 	/* handle fragments that didn't get reassembled by normalization */
 	if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
@@ -8703,16 +8959,6 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
 
 	switch (h->ip_p) {
 	case IPPROTO_TCP: {
-		if (!pf_pull_hdr(m, off, &pd.hdr.tcp, sizeof(pd.hdr.tcp),
-		    &action, &reason, AF_INET)) {
-			if (action != PF_PASS)
-				pd.act.log = PF_LOG_FORCE;
-			goto done;
-		}
-		pd.p_len = pd.tot_len - off - (pd.hdr.tcp.th_off << 2);
-
-		pd.sport = &pd.hdr.tcp.th_sport;
-		pd.dport = &pd.hdr.tcp.th_dport;
 
 		/* Respond to SYN with a syncookie. */
 		if ((pd.hdr.tcp.th_flags & (TH_SYN|TH_ACK|TH_RST)) == TH_SYN &&
@@ -8768,28 +9014,13 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
 				break;
 			} else {
 				action = pf_test_rule(&r, &s, kif, m, off, &pd,
-				    &a, &ruleset, inp);
+				    &a, &ruleset, inp, hdrlen);
 			}
 		}
 		break;
 	}
 
 	case IPPROTO_UDP: {
-		if (!pf_pull_hdr(m, off, &pd.hdr.udp, sizeof(pd.hdr.udp),
-		    &action, &reason, AF_INET)) {
-			if (action != PF_PASS)
-				pd.act.log = PF_LOG_FORCE;
-			goto done;
-		}
-		pd.sport = &pd.hdr.udp.uh_sport;
-		pd.dport = &pd.hdr.udp.uh_dport;
-		if (pd.hdr.udp.uh_dport == 0 ||
-		    ntohs(pd.hdr.udp.uh_ulen) > m->m_pkthdr.len - off ||
-		    ntohs(pd.hdr.udp.uh_ulen) < sizeof(struct udphdr)) {
-			action = PF_DROP;
-			REASON_SET(&reason, PFRES_SHORT);
-			goto done;
-		}
 		action = pf_test_state_udp(&s, kif, m, off, h, &pd);
 		if (action == PF_PASS) {
 			if (V_pfsync_update_state_ptr != NULL)
@@ -8798,26 +9029,11 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
 			a = s->anchor.ptr;
 		} else if (s == NULL)
 			action = pf_test_rule(&r, &s, kif, m, off, &pd,
-			    &a, &ruleset, inp);
+			    &a, &ruleset, inp, hdrlen);
 		break;
 	}
 
 	case IPPROTO_SCTP: {
-		if (!pf_pull_hdr(m, off, &pd.hdr.sctp, sizeof(pd.hdr.sctp),
-		    &action, &reason, AF_INET)) {
-			if (action != PF_PASS)
-				pd.act.log |= PF_LOG_FORCE;
-			goto done;
-		}
-		pd.p_len = pd.tot_len - off;
-
-		pd.sport = &pd.hdr.sctp.src_port;
-		pd.dport = &pd.hdr.sctp.dest_port;
-		if (pd.hdr.sctp.src_port == 0 || pd.hdr.sctp.dest_port == 0) {
-			action = PF_DROP;
-			REASON_SET(&reason, PFRES_SHORT);
-			goto done;
-		}
 		action = pf_normalize_sctp(dir, kif, m, 0, off, h, &pd);
 		if (action == PF_DROP)
 			goto done;
@@ -8830,18 +9046,12 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
 			a = s->anchor.ptr;
 		} else if (s == NULL) {
 			action = pf_test_rule(&r, &s, kif, m, off,
-			    &pd, &a, &ruleset, inp);
+			    &pd, &a, &ruleset, inp, hdrlen);
 		}
 		break;
 	}
 
 	case IPPROTO_ICMP: {
-		if (!pf_pull_hdr(m, off, &pd.hdr.icmp, ICMP_MINLEN,
-		    &action, &reason, AF_INET)) {
-			if (action != PF_PASS)
-				pd.act.log = PF_LOG_FORCE;
-			goto done;
-		}
 		action = pf_test_state_icmp(&s, kif, m, off, h, &pd, &reason);
 		if (action == PF_PASS) {
 			if (V_pfsync_update_state_ptr != NULL)
@@ -8850,7 +9060,7 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
 			a = s->anchor.ptr;
 		} else if (s == NULL)
 			action = pf_test_rule(&r, &s, kif, m, off, &pd,
-			    &a, &ruleset, inp);
+			    &a, &ruleset, inp, hdrlen);
 		break;
 	}
 
@@ -8870,7 +9080,7 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
 			a = s->anchor.ptr;
 		} else if (s == NULL)
 			action = pf_test_rule(&r, &s, kif, m, off, &pd,
-			    &a, &ruleset, inp);
+			    &a, &ruleset, inp, hdrlen);
 		break;
 	}
 
@@ -9141,7 +9351,7 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
 	struct pf_kstate	*s = NULL;
 	struct pf_kruleset	*ruleset = NULL;
 	struct pf_pdesc		 pd;
-	int			 off, terminal = 0, dirndx, rh_cnt = 0, use_2nd_queue = 0;
+	int			 off, hdrlen, dirndx, use_2nd_queue = 0;
 	uint16_t		 tag;
 	uint8_t			 rt;
 
@@ -9189,11 +9399,33 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
 			return (PF_DROP);
 	}
 
+	if (__predict_false(m->m_len < sizeof(struct ip6_hdr)) &&
+	    (m = *m0 = m_pullup(*m0, sizeof(struct ip6_hdr))) == NULL) {
+		DPFPRINTF(PF_DEBUG_URGENT,
+		    ("pf_test6: m_len < sizeof(struct ip6_hdr)"
+		     ", pullup failed\n"));
+		PF_RULES_RUNLOCK();
+		return (PF_DROP);
+	}
+
 	memset(&pd, 0, sizeof(pd));
-	TAILQ_INIT(&pd.sctp_multihome_jobs);
-	if (default_actions != NULL)
-		memcpy(&pd.act, default_actions, sizeof(pd.act));
-	pd.pf_mtag = pf_find_mtag(m);
+	pd.dir = dir;
+
+	/* We do IP header normalization and packet reassembly here */
+	if (pf_normalize_ip6(m0, kif, &reason, &pd) != PF_PASS) {
+		action = PF_DROP;
+		goto done;
+	}
+	m = *m0;	/* pf_normalize messes with m0 */
+	h = mtod(m, struct ip6_hdr *);
+	off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
+
+	if (pf_setup_pdesc(AF_INET6, dir, &pd, m, &action, &reason, kif, &a, &r,
+		&ruleset, &off, &hdrlen, default_actions) == -1) {
+		if (action != PF_PASS)
+			pd.act.log |= PF_LOG_FORCE;
+		goto done;
+	}
 
 	if (pd.pf_mtag != NULL && (pd.pf_mtag->flags & PF_MTAG_FLAG_ROUTE_TO)) {
 		pd.pf_mtag->flags &= ~PF_MTAG_FLAG_ROUTE_TO;
@@ -9213,11 +9445,6 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
 		return (PF_PASS);
 	}
 
-	if (pd.pf_mtag && pd.pf_mtag->dnpipe) {
-		pd.act.dnpipe = pd.pf_mtag->dnpipe;
-		pd.act.flags = pd.pf_mtag->dnflags;
-	}
-
 	if (ip_dn_io_ptr != NULL && pd.pf_mtag != NULL &&
 	    pd.pf_mtag->flags & PF_MTAG_FLAG_DUMMYNET) {
 		pf_dummynet_flag_remove(m, pd.pf_mtag);
@@ -9228,35 +9455,6 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
 		return (PF_PASS);
 	}
 
-	pd.sport = pd.dport = NULL;
-	pd.ip_sum = NULL;
-	pd.proto_sum = NULL;
-	pd.dir = dir;
-	pd.sidx = (dir == PF_IN) ? 0 : 1;
-	pd.didx = (dir == PF_IN) ? 1 : 0;
-	pd.af = AF_INET6;
-	pd.act.rtableid = -1;
-
-	if (__predict_false(m->m_len < sizeof(struct ip6_hdr)) &&
-	    (m = *m0 = m_pullup(*m0, sizeof(struct ip6_hdr))) == NULL) {
-		DPFPRINTF(PF_DEBUG_URGENT,
-		    ("pf_test6: m_len < sizeof(struct ip6_hdr)"
-		     ", pullup failed\n"));
-		PF_RULES_RUNLOCK();
-		return (PF_DROP);
-	}
-	h = mtod(m, struct ip6_hdr *);
-	off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
-
-	/* We do IP header normalization and packet reassembly here */
-	if (pf_normalize_ip6(m0, kif, &reason, &pd) != PF_PASS) {
-		action = PF_DROP;
-		goto done;
-	}
-	m = *m0;	/* pf_normalize messes with m0 */
-	h = mtod(m, struct ip6_hdr *);
-	off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
-
 	/*
 	 * we do not support jumbogram.  if we keep going, zero ip6_plen
 	 * will do something bad, so drop the packet for now.
@@ -9267,94 +9465,12 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
 		goto done;
 	}
 
-	pd.src = (struct pf_addr *)&h->ip6_src;
-	pd.dst = (struct pf_addr *)&h->ip6_dst;
-	pd.tos = IPV6_DSCP(h);
-	pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
-
-	pd.proto = h->ip6_nxt;
-	do {
-		switch (pd.proto) {
-		case IPPROTO_FRAGMENT:
-			action = pf_test_fragment(&r, kif, m, h, &pd, &a,
-			    &ruleset);
-			if (action == PF_DROP)
-				REASON_SET(&reason, PFRES_FRAG);
-			goto done;
-		case IPPROTO_ROUTING: {
-			struct ip6_rthdr rthdr;
-
-			if (rh_cnt++) {
-				DPFPRINTF(PF_DEBUG_MISC,
-				    ("pf: IPv6 more than one rthdr\n"));
-				action = PF_DROP;
-				REASON_SET(&reason, PFRES_IPOPTIONS);
-				pd.act.log = PF_LOG_FORCE;
-				goto done;
-			}
-			if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL,
-			    &reason, pd.af)) {
-				DPFPRINTF(PF_DEBUG_MISC,
-				    ("pf: IPv6 short rthdr\n"));
-				action = PF_DROP;
-				REASON_SET(&reason, PFRES_SHORT);
-				pd.act.log = PF_LOG_FORCE;
-				goto done;
-			}
-			if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) {
-				DPFPRINTF(PF_DEBUG_MISC,
-				    ("pf: IPv6 rthdr0\n"));
-				action = PF_DROP;
-				REASON_SET(&reason, PFRES_IPOPTIONS);
-				pd.act.log = PF_LOG_FORCE;
-				goto done;
-			}
-			/* FALLTHROUGH */
-		}
-		case IPPROTO_AH:
-		case IPPROTO_HOPOPTS:
-		case IPPROTO_DSTOPTS: {
-			/* get next header and header length */
-			struct ip6_ext	opt6;
-
-			if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6),
-			    NULL, &reason, pd.af)) {
-				DPFPRINTF(PF_DEBUG_MISC,
-				    ("pf: IPv6 short opt\n"));
-				action = PF_DROP;
-				pd.act.log = PF_LOG_FORCE;
-				goto done;
-			}
-			if (pd.proto == IPPROTO_AH)
-				off += (opt6.ip6e_len + 2) * 4;
-			else
-				off += (opt6.ip6e_len + 1) * 8;
-			pd.proto = opt6.ip6e_nxt;
-			/* goto the next header */
-			break;
-		}
-		default:
-			terminal++;
-			break;
-		}
-	} while (!terminal);
-
 	/* if there's no routing header, use unmodified mbuf for checksumming */
 	if (!n)
 		n = m;
 
 	switch (pd.proto) {
 	case IPPROTO_TCP: {
-		if (!pf_pull_hdr(m, off, &pd.hdr.tcp, sizeof(pd.hdr.tcp),
-		    &action, &reason, AF_INET6)) {
-			if (action != PF_PASS)
-				pd.act.log |= PF_LOG_FORCE;
-			goto done;
-		}
-		pd.p_len = pd.tot_len - off - (pd.hdr.tcp.th_off << 2);
-		pd.sport = &pd.hdr.tcp.th_sport;
-		pd.dport = &pd.hdr.tcp.th_dport;
-
 		/* Respond to SYN with a syncookie. */
 		if ((pd.hdr.tcp.th_flags & (TH_SYN|TH_ACK|TH_RST)) == TH_SYN &&
 		    pd.dir == PF_IN && pf_synflood_check(&pd)) {
@@ -9408,28 +9524,13 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
 				break;
 			} else {
 				action = pf_test_rule(&r, &s, kif, m, off, &pd,
-				    &a, &ruleset, inp);
+				    &a, &ruleset, inp, hdrlen);
 			}
 		}
 		break;
 	}
 
 	case IPPROTO_UDP: {
-		if (!pf_pull_hdr(m, off, &pd.hdr.udp, sizeof(pd.hdr.udp),
-		    &action, &reason, AF_INET6)) {
-			if (action != PF_PASS)
-				pd.act.log |= PF_LOG_FORCE;
-			goto done;
-		}
-		pd.sport = &pd.hdr.udp.uh_sport;
-		pd.dport = &pd.hdr.udp.uh_dport;
-		if (pd.hdr.udp.uh_dport == 0 ||
-		    ntohs(pd.hdr.udp.uh_ulen) > m->m_pkthdr.len - off ||
-		    ntohs(pd.hdr.udp.uh_ulen) < sizeof(struct udphdr)) {
-			action = PF_DROP;
-			REASON_SET(&reason, PFRES_SHORT);
-			goto done;
-		}
 		action = pf_test_state_udp(&s, kif, m, off, h, &pd);
 		if (action == PF_PASS) {
 			if (V_pfsync_update_state_ptr != NULL)
@@ -9438,24 +9539,11 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
 			a = s->anchor.ptr;
 		} else if (s == NULL)
 			action = pf_test_rule(&r, &s, kif, m, off, &pd,
-			    &a, &ruleset, inp);
+			    &a, &ruleset, inp, hdrlen);
 		break;
 	}
 
 	case IPPROTO_SCTP: {
-		if (!pf_pull_hdr(m, off, &pd.hdr.sctp, sizeof(pd.hdr.sctp),
-		    &action, &reason, AF_INET6)) {
-			if (action != PF_PASS)
-				pd.act.log |= PF_LOG_FORCE;
-			goto done;
-		}
-		pd.sport = &pd.hdr.sctp.src_port;
-		pd.dport = &pd.hdr.sctp.dest_port;
-		if (pd.hdr.sctp.src_port == 0 || pd.hdr.sctp.dest_port == 0) {
-			action = PF_DROP;
-			REASON_SET(&reason, PFRES_SHORT);
-			goto done;
-		}
 		action = pf_normalize_sctp(dir, kif, m, 0, off, h, &pd);
 		if (action == PF_DROP)
 			goto done;
@@ -9468,7 +9556,7 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
 			a = s->anchor.ptr;
 		} else if (s == NULL) {
 			action = pf_test_rule(&r, &s, kif, m, off,
-			    &pd, &a, &ruleset, inp);
+			    &pd, &a, &ruleset, inp, hdrlen);
 		}
 		break;
 	}
@@ -9481,12 +9569,6 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
 	}
 
 	case IPPROTO_ICMPV6: {
-		if (!pf_pull_hdr(m, off, &pd.hdr.icmp6, sizeof(pd.hdr.icmp6),
-		    &action, &reason, AF_INET6)) {
-			if (action != PF_PASS)
-				pd.act.log |= PF_LOG_FORCE;
-			goto done;
-		}
 		action = pf_test_state_icmp(&s, kif, m, off, h, &pd, &reason);
 		if (action == PF_PASS) {
 			if (V_pfsync_update_state_ptr != NULL)
@@ -9495,7 +9577,7 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
 			a = s->anchor.ptr;
 		} else if (s == NULL)
 			action = pf_test_rule(&r, &s, kif, m, off, &pd,
-			    &a, &ruleset, inp);
+			    &a, &ruleset, inp, hdrlen);
 		break;
 	}
 
@@ -9508,7 +9590,7 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
 			a = s->anchor.ptr;
 		} else if (s == NULL)
 			action = pf_test_rule(&r, &s, kif, m, off, &pd,
-			    &a, &ruleset, inp);
+			    &a, &ruleset, inp, hdrlen);
 		break;
 	}
 
@@ -9520,7 +9602,7 @@ done:
 	}
 
 	/* handle dangerous IPv6 extension headers. */
-	if (action == PF_PASS && rh_cnt &&
+	if (action == PF_PASS && pd.rh_cnt &&
 	    !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) {
 		action = PF_DROP;
 		REASON_SET(&reason, PFRES_IPOPTIONS);
diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
index 295377bef3e8..aaeb027ca8bd 100644
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -2066,8 +2066,8 @@ pf_normalize_mss(struct mbuf *m, int off, struct pf_pdesc *pd)
 	return (0);
 }
 
-static int
-pf_scan_sctp(struct mbuf *m, int ipoff, int off, struct pf_pdesc *pd,
+int
+pf_scan_sctp(struct mbuf *m, int off, struct pf_pdesc *pd,
     struct pfi_kkif *kif)
 {
 	struct sctp_chunkhdr ch = { };
@@ -2203,11 +2203,6 @@ pf_normalize_sctp(int dir, struct pfi_kkif *kif, struct mbuf *m, int ipoff,
 
 	PF_RULES_RASSERT();
 
-	/* Unconditionally scan the SCTP packet, because we need to look for
-	 * things like shutdown and asconf chunks. */
-	if (pf_scan_sctp(m, ipoff, off, pd, kif) != PF_PASS)
-		goto sctp_drop;
-
 	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
 	/* Check if there any scrub rules. Lack of scrub rules means enforced
 	 * packet normalization operation just like in OpenBSD. */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202409192021.48JKLHBQ046347>