git: 5e9272401d80 - main - pf: fold pf_test_state_{tcp,udp,other} into one pf_test_state
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 12 Feb 2025 19:39:06 UTC
The branch main has been updated by kp:
URL: https://cgit.FreeBSD.org/src/commit/?id=5e9272401d80381d95be84ab3b7755a207245268
commit 5e9272401d80381d95be84ab3b7755a207245268
Author: Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2025-02-06 14:36:11 +0000
Commit: Kristof Provost <kp@FreeBSD.org>
CommitDate: 2025-02-12 19:38:38 +0000
pf: fold pf_test_state_{tcp,udp,other} into one pf_test_state
The _icmp variant stays because it is completely different.
pf_setup_pdesc sets us up with access to ports, cksum etc in a protocol
independent matter, so we don't need many protocol switches here.
tcp and udp were almost identical, the _other case changes significantly -
not too unlikely this fixes a subtle bug or two in that case.
ok ryan benno bluhm mikeb
Obtained from: OpenBSD, henning <henning@openbsd.org>, f6cfeb8e09
Sponsored by: Rubicon Communications, LLC ("Netgate")
---
sys/netpfil/pf/pf.c | 325 ++++++++++++++--------------------------------------
1 file changed, 87 insertions(+), 238 deletions(-)
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 3957d39edc13..c92faf43d967 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -353,10 +353,8 @@ static int pf_tcp_track_full(struct pf_kstate **,
struct pf_pdesc *, u_short *, int *);
static int pf_tcp_track_sloppy(struct pf_kstate **,
struct pf_pdesc *, u_short *);
-static int pf_test_state_tcp(struct pf_kstate **,
- struct pf_pdesc *, u_short *);
-static int pf_test_state_udp(struct pf_kstate **,
- struct pf_pdesc *);
+static int pf_test_state(struct pf_kstate **, struct pf_pdesc *,
+ u_short *);
int pf_icmp_state_lookup(struct pf_state_key_cmp *,
struct pf_pdesc *, struct pf_kstate **,
int, u_int16_t, u_int16_t,
@@ -368,8 +366,6 @@ static void pf_sctp_multihome_delayed(struct pf_pdesc *,
struct pfi_kkif *, struct pf_kstate *, int);
static int pf_test_state_sctp(struct pf_kstate **,
struct pf_pdesc *, u_short *);
-static int pf_test_state_other(struct pf_kstate **,
- struct pf_pdesc *);
static u_int16_t pf_calc_mss(struct pf_addr *, sa_family_t,
int, u_int16_t);
static int pf_check_proto_cksum(struct mbuf *, int, int,
@@ -6901,153 +6897,102 @@ pf_synproxy(struct pf_pdesc *pd, struct pf_kstate **state, u_short *reason)
}
static int
-pf_test_state_tcp(struct pf_kstate **state, struct pf_pdesc *pd,
- u_short *reason)
+pf_test_state(struct pf_kstate **state, struct pf_pdesc *pd, u_short *reason)
{
struct pf_state_key_cmp key;
- struct tcphdr *th = &pd->hdr.tcp;
int copyback = 0;
- int action = PF_PASS;
struct pf_state_peer *src, *dst;
+ uint8_t psrc, pdst;
+ int action = PF_PASS;
bzero(&key, sizeof(key));
key.af = pd->af;
- key.proto = IPPROTO_TCP;
+ key.proto = pd->virtual_proto;
PF_ACPY(&key.addr[pd->sidx], pd->src, key.af);
PF_ACPY(&key.addr[pd->didx], pd->dst, key.af);
- key.port[pd->sidx] = th->th_sport;
- key.port[pd->didx] = th->th_dport;
+ key.port[pd->sidx] = pd->osport;
+ key.port[pd->didx] = pd->odport;
STATE_LOOKUP(&key, *state, pd);
if (pd->dir == (*state)->direction) {
src = &(*state)->src;
dst = &(*state)->dst;
+ psrc = PF_PEER_SRC;
+ pdst = PF_PEER_DST;
} else {
src = &(*state)->dst;
dst = &(*state)->src;
+ psrc = PF_PEER_DST;
+ pdst = PF_PEER_SRC;
}
- if ((action = pf_synproxy(pd, state, reason)) != PF_PASS)
- return (action);
-
- if (dst->state >= TCPS_FIN_WAIT_2 &&
- src->state >= TCPS_FIN_WAIT_2 &&
- (((tcp_get_flags(th) & (TH_SYN|TH_ACK)) == TH_SYN) ||
- ((tcp_get_flags(th) & (TH_SYN|TH_ACK|TH_RST)) == TH_ACK &&
- pf_syncookie_check(pd) && pd->dir == PF_IN))) {
- if (V_pf_status.debug >= PF_DEBUG_MISC) {
- printf("pf: state reuse ");
- pf_print_state(*state);
- pf_print_flags(tcp_get_flags(th));
- printf("\n");
- }
- /* XXX make sure it's the same direction ?? */
- pf_set_protostate(*state, PF_PEER_BOTH, TCPS_CLOSED);
- pf_unlink_state(*state);
- *state = NULL;
- return (PF_DROP);
- }
-
- if ((*state)->state_flags & PFSTATE_SLOPPY) {
- if (pf_tcp_track_sloppy(state, pd, reason) == PF_DROP)
- return (PF_DROP);
- } else {
- int ret;
+ switch (pd->virtual_proto) {
+ case IPPROTO_TCP: {
+ struct tcphdr *th = &pd->hdr.tcp;
- ret = pf_tcp_track_full(state, pd, reason,
- ©back);
- if (ret == PF_DROP)
+ if ((action = pf_synproxy(pd, state, reason)) != PF_PASS)
+ return (action);
+ if ((*state)->src.state >= TCPS_FIN_WAIT_2 &&
+ (*state)->dst.state >= TCPS_FIN_WAIT_2 &&
+ (((tcp_get_flags(th) & (TH_SYN|TH_ACK)) == TH_SYN) ||
+ ((tcp_get_flags(th) & (TH_SYN|TH_ACK|TH_RST)) == TH_ACK &&
+ pf_syncookie_check(pd) && pd->dir == PF_IN))) {
+ if (V_pf_status.debug >= PF_DEBUG_MISC) {
+ printf("pf: state reuse ");
+ pf_print_state(*state);
+ pf_print_flags(tcp_get_flags(th));
+ printf("\n");
+ }
+ /* XXX make sure it's the same direction ?? */
+ pf_set_protostate(*state, PF_PEER_BOTH, TCPS_CLOSED);
+ pf_unlink_state(*state);
+ *state = NULL;
return (PF_DROP);
- }
-
- /* translate source/destination address, if necessary */
- if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) {
- struct pf_state_key *nk;
- int afto, sidx, didx;
-
- if (PF_REVERSED_KEY((*state)->key, pd->af))
- nk = (*state)->key[pd->sidx];
- else
- nk = (*state)->key[pd->didx];
-
- afto = pd->af != nk->af;
- sidx = afto ? pd->didx : pd->sidx;
- didx = afto ? pd->sidx : pd->didx;
-
- if (afto || PF_ANEQ(pd->src, &nk->addr[sidx], pd->af) ||
- nk->port[sidx] != th->th_sport)
- pf_change_ap(pd->m, pd->src, &th->th_sport,
- pd->ip_sum, &th->th_sum, &nk->addr[sidx],
- nk->port[sidx], 0, pd->af, nk->af);
-
- if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) ||
- nk->port[didx] != th->th_dport)
- pf_change_ap(pd->m, pd->dst, &th->th_dport,
- pd->ip_sum, &th->th_sum, &nk->addr[didx],
- nk->port[didx], 0, pd->af, nk->af);
-
- if (afto) {
- PF_ACPY(&pd->nsaddr, &nk->addr[sidx], nk->af);
- PF_ACPY(&pd->ndaddr, &nk->addr[didx], nk->af);
- pd->naf = nk->af;
- action = PF_AFRT;
}
+ if ((*state)->state_flags & PFSTATE_SLOPPY) {
+ if (pf_tcp_track_sloppy(state, pd, reason) == PF_DROP)
+ return (PF_DROP);
+ } else {
+ int ret;
- copyback = 1;
+ ret = pf_tcp_track_full(state, pd, reason,
+ ©back);
+ if (ret == PF_DROP)
+ return (PF_DROP);
+ }
+ break;
}
+ case IPPROTO_UDP:
+ /* update states */
+ if (src->state < PFUDPS_SINGLE)
+ pf_set_protostate(*state, psrc, PFUDPS_SINGLE);
+ if (dst->state == PFUDPS_SINGLE)
+ pf_set_protostate(*state, pdst, PFUDPS_MULTIPLE);
- /* Copyback sequence modulation or stateful scrub changes if needed */
- if (copyback)
- m_copyback(pd->m, pd->off, sizeof(*th), (caddr_t)th);
-
- return (action);
-}
-
-static int
-pf_test_state_udp(struct pf_kstate **state, struct pf_pdesc *pd)
-{
- struct pf_state_peer *src, *dst;
- struct pf_state_key_cmp key;
- struct udphdr *uh = &pd->hdr.udp;
- uint8_t psrc, pdst;
- int action = PF_PASS;
-
- bzero(&key, sizeof(key));
- key.af = pd->af;
- key.proto = IPPROTO_UDP;
- PF_ACPY(&key.addr[pd->sidx], pd->src, key.af);
- PF_ACPY(&key.addr[pd->didx], pd->dst, key.af);
- key.port[pd->sidx] = uh->uh_sport;
- key.port[pd->didx] = uh->uh_dport;
-
- STATE_LOOKUP(&key, *state, pd);
+ /* update expire time */
+ (*state)->expire = pf_get_uptime();
+ if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
+ (*state)->timeout = PFTM_UDP_MULTIPLE;
+ else
+ (*state)->timeout = PFTM_UDP_SINGLE;
+ break;
+ default:
+ /* update states */
+ if (src->state < PFOTHERS_SINGLE)
+ pf_set_protostate(*state, psrc, PFOTHERS_SINGLE);
+ if (dst->state == PFOTHERS_SINGLE)
+ pf_set_protostate(*state, pdst, PFOTHERS_MULTIPLE);
- if (pd->dir == (*state)->direction) {
- src = &(*state)->src;
- dst = &(*state)->dst;
- psrc = PF_PEER_SRC;
- pdst = PF_PEER_DST;
- } else {
- src = &(*state)->dst;
- dst = &(*state)->src;
- psrc = PF_PEER_DST;
- pdst = PF_PEER_SRC;
+ /* update expire time */
+ (*state)->expire = pf_get_uptime();
+ if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
+ (*state)->timeout = PFTM_OTHER_MULTIPLE;
+ else
+ (*state)->timeout = PFTM_OTHER_SINGLE;
+ break;
}
- /* update states */
- if (src->state < PFUDPS_SINGLE)
- pf_set_protostate(*state, psrc, PFUDPS_SINGLE);
- if (dst->state == PFUDPS_SINGLE)
- pf_set_protostate(*state, pdst, PFUDPS_MULTIPLE);
-
- /* update expire time */
- (*state)->expire = pf_get_uptime();
- if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
- (*state)->timeout = PFTM_UDP_MULTIPLE;
- else
- (*state)->timeout = PFTM_UDP_SINGLE;
-
/* translate source/destination address, if necessary */
if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) {
struct pf_state_key *nk;
@@ -7063,16 +7008,18 @@ pf_test_state_udp(struct pf_kstate **state, struct pf_pdesc *pd)
didx = afto ? pd->sidx : pd->didx;
if (afto || PF_ANEQ(pd->src, &nk->addr[sidx], pd->af) ||
- nk->port[sidx] != uh->uh_sport)
- pf_change_ap(pd->m, pd->src, &uh->uh_sport, pd->ip_sum,
- &uh->uh_sum, &nk->addr[pd->sidx],
- nk->port[sidx], 1, pd->af, nk->af);
+ nk->port[sidx] != pd->osport)
+ pf_change_ap(pd->m, pd->src, pd->sport, pd->ip_sum,
+ pd->pcksum, &nk->addr[pd->sidx],
+ nk->port[sidx], pd->virtual_proto == IPPROTO_UDP,
+ pd->af, nk->af);
if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) ||
- nk->port[didx] != uh->uh_dport)
- pf_change_ap(pd->m, pd->dst, &uh->uh_dport, pd->ip_sum,
- &uh->uh_sum, &nk->addr[pd->didx],
- nk->port[didx], 1, pd->af, nk->af);
+ nk->port[didx] != pd->odport)
+ pf_change_ap(pd->m, pd->dst, pd->dport, pd->ip_sum,
+ pd->pcksum, &nk->addr[pd->didx],
+ nk->port[didx], pd->virtual_proto == IPPROTO_UDP,
+ pd->af, nk->af);
if (afto) {
PF_ACPY(&pd->nsaddr, &nk->addr[sidx], nk->af);
@@ -7081,9 +7028,12 @@ pf_test_state_udp(struct pf_kstate **state, struct pf_pdesc *pd)
action = PF_AFRT;
}
- m_copyback(pd->m, pd->off, sizeof(*uh), (caddr_t)uh);
+ copyback = 1;
}
+ if (copyback && pd->hdrlen > 0)
+ m_copyback(pd->m, pd->off, pd->hdrlen, pd->hdr.any);
+
return (action);
}
@@ -8672,107 +8622,6 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
}
}
-static int
-pf_test_state_other(struct pf_kstate **state, struct pf_pdesc *pd)
-{
- struct pf_state_peer *src, *dst;
- struct pf_state_key_cmp key;
- uint8_t psrc, pdst;
- int action = PF_PASS;
-
- bzero(&key, sizeof(key));
- key.af = pd->af;
- key.proto = pd->proto;
- PF_ACPY(&key.addr[pd->sidx], pd->src, key.af);
- PF_ACPY(&key.addr[pd->didx], pd->dst, key.af);
- key.port[0] = key.port[1] = 0;
-
- STATE_LOOKUP(&key, *state, pd);
-
- if (pd->dir == (*state)->direction) {
- src = &(*state)->src;
- dst = &(*state)->dst;
- psrc = PF_PEER_SRC;
- pdst = PF_PEER_DST;
- } else {
- src = &(*state)->dst;
- dst = &(*state)->src;
- psrc = PF_PEER_DST;
- pdst = PF_PEER_SRC;
- }
-
- /* update states */
- if (src->state < PFOTHERS_SINGLE)
- pf_set_protostate(*state, psrc, PFOTHERS_SINGLE);
- if (dst->state == PFOTHERS_SINGLE)
- pf_set_protostate(*state, pdst, PFOTHERS_MULTIPLE);
-
- /* update expire time */
- (*state)->expire = pf_get_uptime();
- if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
- (*state)->timeout = PFTM_OTHER_MULTIPLE;
- else
- (*state)->timeout = PFTM_OTHER_SINGLE;
-
- /* translate source/destination address, if necessary */
- if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) {
- struct pf_state_key *nk;
- int afto;
-
- if (PF_REVERSED_KEY((*state)->key, pd->af))
- nk = (*state)->key[pd->sidx];
- else
- nk = (*state)->key[pd->didx];
-
- KASSERT(nk, ("%s: nk is null", __func__));
- KASSERT(pd, ("%s: pd is null", __func__));
- KASSERT(pd->src, ("%s: pd->src is null", __func__));
- KASSERT(pd->dst, ("%s: pd->dst is null", __func__));
-
- afto = pd->af != nk->af;
-
- switch (pd->af) {
-#ifdef INET
- case AF_INET:
- if (!afto &&
- PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET))
- pf_change_a(&pd->src->v4.s_addr,
- pd->ip_sum,
- nk->addr[pd->sidx].v4.s_addr,
- 0);
-
- if (!afto &&
- PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET))
- pf_change_a(&pd->dst->v4.s_addr,
- pd->ip_sum,
- nk->addr[pd->didx].v4.s_addr,
- 0);
-
- break;
-#endif /* INET */
-#ifdef INET6
- case AF_INET6:
- if (!afto &&
- PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET6))
- PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af);
-
- if (!afto &&
- PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET6))
- PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af);
-#endif /* INET6 */
- }
- if (afto) {
- PF_ACPY(&pd->nsaddr,
- &nk->addr[afto ? pd->didx : pd->sidx], nk->af);
- PF_ACPY(&pd->ndaddr,
- &nk->addr[afto ? pd->sidx : pd->didx], nk->af);
- pd->naf = nk->af;
- action = PF_AFRT;
- }
- }
- return (action);
-}
-
/*
* ipoff and off are measured from the start of the mbuf chain.
* h must be at "ipoff" on the mbuf chain.
@@ -10439,7 +10288,7 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
action = pf_normalize_tcp(&pd);
if (action == PF_DROP)
goto done;
- action = pf_test_state_tcp(&s, &pd, &reason);
+ action = pf_test_state(&s, &pd, &reason);
if (action == PF_PASS || action == PF_AFRT) {
if (V_pfsync_update_state_ptr != NULL)
V_pfsync_update_state_ptr(s);
@@ -10465,7 +10314,7 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
if (action != PF_PASS)
break;
- action = pf_test_state_tcp(&s, &pd, &reason);
+ action = pf_test_state(&s, &pd, &reason);
if (action != PF_PASS || s == NULL) {
action = PF_DROP;
break;
@@ -10485,7 +10334,7 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
}
case IPPROTO_UDP: {
- action = pf_test_state_udp(&s, &pd);
+ action = pf_test_state(&s, &pd, &reason);
if (action == PF_PASS || action == PF_AFRT) {
if (V_pfsync_update_state_ptr != NULL)
V_pfsync_update_state_ptr(s);
@@ -10543,7 +10392,7 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
}
default:
- action = pf_test_state_other(&s, &pd);
+ action = pf_test_state(&s, &pd, &reason);
if (action == PF_PASS || action == PF_AFRT) {
if (V_pfsync_update_state_ptr != NULL)
V_pfsync_update_state_ptr(s);