git: e2177bca94f2 - main - pf: allow pf_get_sport() to work on in rules

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Wed, 16 Apr 2025 18:02:56 UTC
The branch main has been updated by kp:

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

commit e2177bca94f28613ab4a47ef6d3469f80e8d5923
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2025-04-16 08:47:58 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2025-04-16 14:23:48 +0000

    pf: allow pf_get_sport() to work on in rules
    
    The function pf_get_sport() did work for out rules only.  Make it
    aware of the direction of the packet.  Now nat-to can be used by
    in rules and together with divert-to.  Collisions with existing
    states are found and produce a "NAT proxy port allocation failed"
    message.
    OK henning@ mikeb@
    
    Obtained from:  OpenBSD, bluhm <bluhm@openbsd.org>, 4af3c109db
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
---
 sys/netpfil/pf/pf_lb.c | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c
index 9785611271a0..d40f4828eb62 100644
--- a/sys/netpfil/pf/pf_lb.c
+++ b/sys/netpfil/pf/pf_lb.c
@@ -226,6 +226,9 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
 {
 	struct pf_state_key_cmp	key;
 	struct pf_addr		init_addr;
+	int			dir = (pd->dir == PF_IN) ? PF_OUT : PF_IN;
+	int			sidx = pd->sidx;
+	int			didx = pd->didx;
 
 	bzero(&init_addr, sizeof(init_addr));
 
@@ -291,11 +294,12 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
 	bzero(&key, sizeof(key));
 	key.af = pd->naf;
 	key.proto = pd->proto;
-	key.port[0] = pd->ndport;
-	PF_ACPY(&key.addr[0], &pd->ndaddr, key.af);
 
 	do {
-		PF_ACPY(&key.addr[1], naddr, key.af);
+		PF_ACPY(&key.addr[didx], &pd->ndaddr, key.af);
+		PF_ACPY(&key.addr[sidx], naddr, key.af);
+		key.port[didx] = pd->ndport;
+
 		if (udp_mapping && *udp_mapping)
 			PF_ACPY(&(*udp_mapping)->endpoints[1].addr, naddr, pd->af);
 
@@ -304,8 +308,8 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
 		 * similar 2 portloop in in_pcbbind
 		 */
 		if (pd->proto == IPPROTO_SCTP) {
-			key.port[1] = pd->nsport;
-			if (!pf_find_state_all_exists(&key, PF_IN)) {
+			key.port[sidx] = pd->nsport;
+			if (!pf_find_state_all_exists(&key, dir)) {
 				*nport = pd->nsport;
 				return (0);
 			} else {
@@ -317,14 +321,14 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
 			 * XXX bug: icmp states don't use the id on both sides.
 			 * (traceroute -I through nat)
 			 */
-			key.port[1] = pd->nsport;
-			if (!pf_find_state_all_exists(&key, PF_IN)) {
+			key.port[sidx] = pd->nsport;
+			if (!pf_find_state_all_exists(&key, dir)) {
 				*nport = pd->nsport;
 				return (0);
 			}
 		} else if (low == high) {
-			key.port[1] = htons(low);
-			if (!pf_find_state_all_exists(&key, PF_IN)) {
+			key.port[sidx] = htons(low);
+			if (!pf_find_state_all_exists(&key, dir)) {
 				if (udp_mapping && *udp_mapping != NULL) {
 					(*udp_mapping)->endpoints[1].port = htons(low);
 					if (pf_udp_mapping_insert(*udp_mapping) == 0) {
@@ -350,14 +354,14 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
 			/* low <= cut <= high */
 			for (tmp = cut; tmp <= high && tmp <= 0xffff; ++tmp) {
 				if (udp_mapping && *udp_mapping != NULL) {
-					(*udp_mapping)->endpoints[1].port = htons(tmp);
+					(*udp_mapping)->endpoints[sidx].port = htons(tmp);
 					if (pf_udp_mapping_insert(*udp_mapping) == 0) {
 						*nport = htons(tmp);
 						return (0);
 					}
 				} else {
-					key.port[1] = htons(tmp);
-					if (!pf_find_state_all_exists(&key, PF_IN)) {
+					key.port[sidx] = htons(tmp);
+					if (!pf_find_state_all_exists(&key, dir)) {
 						*nport = htons(tmp);
 						return (0);
 					}
@@ -374,8 +378,8 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_krule *r,
 						return (0);
 					}
 				} else {
-					key.port[1] = htons(tmp);
-					if (!pf_find_state_all_exists(&key, PF_IN)) {
+					key.port[sidx] = htons(tmp);
+					if (!pf_find_state_all_exists(&key, dir)) {
 						*nport = htons(tmp);
 						return (0);
 					}