git: b0e3fb7e65c3 - main - pf: fix nat64 round-robin addresses from a table

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

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

commit b0e3fb7e65c3a745177e52ec2f20a773b4d59c1e
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2024-12-09 17:37:36 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2024-12-17 10:07:17 +0000

    pf: fix nat64 round-robin addresses from a table
    
    We do multiple lookups during the nat64 process, some of which will fail due
    to address family mismatches. Do not reset the lookup offset so we actually use
    different addresses from the table.
    
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
---
 sys/netpfil/pf/pf_lb.c        |  1 -
 tests/sys/netpfil/pf/nat64.sh | 67 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c
index 0f08226c1c0d..35896bdcf5b1 100644
--- a/sys/netpfil/pf/pf_lb.c
+++ b/sys/netpfil/pf/pf_lb.c
@@ -598,7 +598,6 @@ pf_map_addr(sa_family_t af, struct pf_krule *r, struct pf_addr *saddr,
 		else
 			rpool->cur = TAILQ_NEXT(rpool->cur, entries);
 		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
-			rpool->tblidx = -1;
 			if (pfr_pool_get(rpool->cur->addr.p.tbl,
 			    &rpool->tblidx, &rpool->counter, af, NULL)) {
 				/* table contains no address of type 'af' */
diff --git a/tests/sys/netpfil/pf/nat64.sh b/tests/sys/netpfil/pf/nat64.sh
index b6b2b97a2f63..827891373903 100644
--- a/tests/sys/netpfil/pf/nat64.sh
+++ b/tests/sys/netpfil/pf/nat64.sh
@@ -341,6 +341,72 @@ pool_cleanup()
 	pft_cleanup
 }
 
+atf_test_case "table_round_robin" "cleanup"
+table_round_robin_head()
+{
+	atf_set descr 'Use a table of IPv4 addresses in round-robin mode'
+	atf_set require.user root
+}
+
+table_round_robin_body()
+{
+	pft_init
+
+	epair_link=$(vnet_mkepair)
+	epair=$(vnet_mkepair)
+
+	ifconfig ${epair}a inet6 2001:db8::2/64 up no_dad
+	route -6 add default 2001:db8::1
+
+	vnet_mkjail rtr ${epair}b ${epair_link}a
+	jexec rtr ifconfig ${epair}b inet6 2001:db8::1/64 up no_dad
+	jexec rtr ifconfig ${epair_link}a 192.0.2.1/24 up
+	jexec rtr ifconfig ${epair_link}a inet alias 192.0.2.3/24 up
+	jexec rtr ifconfig ${epair_link}a inet alias 192.0.2.4/24 up
+
+	vnet_mkjail dst ${epair_link}b
+	jexec dst ifconfig ${epair_link}b 192.0.2.2/24 up
+	jexec dst route add default 192.0.2.1
+
+	# Sanity checks
+	atf_check -s exit:0 -o ignore \
+	    ping6 -c 1 2001:db8::1
+	atf_check -s exit:0 -o ignore \
+	    jexec dst ping -c 1 192.0.2.1
+
+	jexec rtr pfctl -e
+	pft_set_rules rtr \
+	    "set reassemble yes" \
+	    "set state-policy if-bound" \
+	    "table <wanaddrs> { 192.0.2.1, 192.0.2.3, 192.0.2.4 }" \
+	    "pass in on ${epair}b inet6 from any to 64:ff9b::/96 af-to inet from <wanaddrs> round-robin"
+
+	# Use pf to count sources
+	jexec dst pfctl -e
+	pft_set_rules dst \
+	    "pass"
+
+	atf_check -s exit:0 -o ignore \
+	    ping6 -c 1 64:ff9b::192.0.2.2
+	atf_check -s exit:0 -o ignore \
+	    ping6 -c 1 64:ff9b::192.0.2.2
+	atf_check -s exit:0 -o ignore \
+	    ping6 -c 1 64:ff9b::192.0.2.2
+
+	# Verify on dst that we saw different source addresses
+	atf_check -s exit:0 -o match:".*192.0.2.1.*" \
+	    jexec dst pfctl -ss
+	atf_check -s exit:0 -o match:".*192.0.2.3.*" \
+	    jexec dst pfctl -ss
+	atf_check -s exit:0 -o match:".*192.0.2.4.*" \
+	    jexec dst pfctl -ss
+}
+
+table_round_robin_cleanup()
+{
+	pft_cleanup
+}
+
 atf_init_test_cases()
 {
 	atf_add_test_case "icmp_echo"
@@ -351,4 +417,5 @@ atf_init_test_cases()
 	atf_add_test_case "tos"
 	atf_add_test_case "no_v4"
 	atf_add_test_case "pool"
+	atf_add_test_case "table_round_robin"
 }