git: 646798b67831 - main - pf: Make nat-to and rdr-to work properly both on in and out rules
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 30 Oct 2025 17:44:39 UTC
The branch main has been updated by ks:
URL: https://cgit.FreeBSD.org/src/commit/?id=646798b6783184fb194a2d97667e05895e00c358
commit 646798b6783184fb194a2d97667e05895e00c358
Author: Kajetan Staszkiewicz <ks@FreeBSD.org>
AuthorDate: 2025-10-01 13:51:46 +0000
Commit: Kajetan Staszkiewicz <ks@FreeBSD.org>
CommitDate: 2025-10-30 17:32:21 +0000
pf: Make nat-to and rdr-to work properly both on in and out rules
New-style address translation is done by nat-to and rdr-to actions on
normal match and pass rules. Those rules, when used without address
translation, can be specified without direction. But that allows users
to specify pre-routing nat and post-routing rdr. This case is not
handled properly and causes pre-routing nat to modify destination
address, as if it was a rdr rule, and post-routing rdr to modify source
address, as if it was a nat rule.
Ensure that nat-to action modifies source address and rdr-to destination
address no matter in which direction the rule is applied. The man page
for pf.conf already specifies that nat-to and rdr-to rules should be
limited to respective directions.
PR: 288577
Reviewed by: kp
MFC after: 3 days
Sponsored by: InnoGames GmbH
Differential Revision: https://reviews.freebsd.org/D53216
---
sys/netpfil/pf/pf_lb.c | 16 +++++++++++++--
tests/sys/netpfil/pf/nat.sh | 47 +++++++++++++++++++++++++++++++++++++++------
2 files changed, 55 insertions(+), 8 deletions(-)
diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c
index 5d85e16f18e3..4b1d74e0e61f 100644
--- a/sys/netpfil/pf/pf_lb.c
+++ b/sys/netpfil/pf/pf_lb.c
@@ -974,6 +974,7 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
{
struct pf_pdesc *pd = ctx->pd;
struct pf_addr *naddr;
+ int idx;
uint16_t *nportp;
uint16_t low, high;
u_short reason;
@@ -988,8 +989,19 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
return (PFRES_MEMORY);
}
- naddr = &ctx->nk->addr[1];
- nportp = &ctx->nk->port[1];
+ switch (nat_action) {
+ case PF_NAT:
+ idx = pd->sidx;
+ break;
+ case PF_BINAT:
+ idx = 1;
+ break;
+ case PF_RDR:
+ idx = pd->didx;
+ break;
+ }
+ naddr = &ctx->nk->addr[idx];
+ nportp = &ctx->nk->port[idx];
switch (nat_action) {
case PF_NAT:
diff --git a/tests/sys/netpfil/pf/nat.sh b/tests/sys/netpfil/pf/nat.sh
index 1ef87cee3598..0824671fa0f1 100644
--- a/tests/sys/netpfil/pf/nat.sh
+++ b/tests/sys/netpfil/pf/nat.sh
@@ -477,15 +477,49 @@ no_addrs_random_cleanup()
pft_cleanup
}
-atf_test_case "nat_pass" "cleanup"
-nat_pass_head()
+atf_test_case "nat_pass_in" "cleanup"
+nat_pass_in_head()
{
- atf_set descr 'IPv4 NAT on pass rule'
+ atf_set descr 'IPv4 NAT on inbound pass rule'
atf_set require.user root
atf_set require.progs scapy
}
-nat_pass_body()
+nat_pass_in_body()
+{
+ setup_router_server_ipv4
+ # Delete the route back to make sure that the traffic has been NAT-ed
+ jexec server route del -net ${net_tester} ${net_server_host_router}
+ # Provide routing back to the NAT address
+ jexec server route add 203.0.113.0/24 ${net_server_host_router}
+ jexec router route add 203.0.113.0/24 -iface ${epair_tester}b
+
+ pft_set_rules router \
+ "block" \
+ "pass in on ${epair_tester}b inet proto tcp nat-to 203.0.113.0 keep state" \
+ "pass out on ${epair_server}a inet proto tcp keep state"
+
+ ping_server_check_reply exit:0 --ping-type=tcp3way --send-sport=4201
+
+ jexec router pfctl -qvvsr
+ jexec router pfctl -qvvss
+ jexec router ifconfig
+ jexec router netstat -rn
+}
+
+nat_pass_in_cleanup()
+{
+ pft_cleanup
+}
+
+nat_pass_out_head()
+{
+ atf_set descr 'IPv4 NAT on outbound pass rule'
+ atf_set require.user root
+ atf_set require.progs scapy
+}
+
+nat_pass_out_body()
{
setup_router_server_ipv4
# Delete the route back to make sure that the traffic has been NAT-ed
@@ -504,7 +538,7 @@ nat_pass_body()
jexec router netstat -rn
}
-nat_pass_cleanup()
+nat_pass_out_cleanup()
{
pft_cleanup
}
@@ -874,7 +908,8 @@ atf_init_test_cases()
atf_add_test_case "no_addrs_random"
atf_add_test_case "map_e_compat"
atf_add_test_case "map_e_pass"
- atf_add_test_case "nat_pass"
+ atf_add_test_case "nat_pass_in"
+ atf_add_test_case "nat_pass_out"
atf_add_test_case "nat_match"
atf_add_test_case "binat_compat"
atf_add_test_case "binat_match"