git: 788f194f6064 - main - pf: 'sticky-address' requires 'keep state'

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Fri, 16 Aug 2024 09:45:39 UTC
The branch main has been updated by kp:

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

commit 788f194f60641dc3cdf7084c7286d6c9683fd238
Author:     Kajetan Staszkiewicz <vegeta@tuxpowered.net>
AuthorDate: 2024-08-16 08:08:16 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2024-08-16 09:43:00 +0000

    pf: 'sticky-address' requires 'keep state'
    
    When route_to() processes a packet without state, pf_map_addr() is called for
    each packet. Pf_map_addr() will search for a source node and will find none
    since those are created only in pf_create_state(). Thus sticky address,
    even though requested in rule definition, will never work.
    
    Raise an error when a stateless filter rule uses sticky address to avoid
    confusion and to keep ruleset limitations in sync with what the pf code
    really does.
    
    Reviewed by:    kp
    Differential Revision:  https://reviews.freebsd.org/D46310
---
 sbin/pfctl/parse.y        | 4 ++++
 sys/netpfil/pf/pf_ioctl.c | 5 +++++
 2 files changed, 9 insertions(+)

diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index d07a3fdc188e..724ffefcd7d9 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -5388,6 +5388,10 @@ filter_consistent(struct pfctl_rule *r, int anchor_call)
 			problems++;
 		}
 	}
+	if (r->rpool.opts & PF_POOL_STICKYADDR && !r->keep_state) {
+		yyerror("'sticky-address' requires 'keep state'");
+		problems++;
+	}
 	return (-problems);
 }
 
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 5467ebbed2eb..d22ffc2245cb 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -2207,6 +2207,11 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
 	    (TAILQ_FIRST(&rule->rpool.list) == NULL))
 		error = EINVAL;
 
+	if (rule->action == PF_PASS && rule->rpool.opts & PF_POOL_STICKYADDR &&
+	    !rule->keep_state) {
+		error = EINVAL;
+	}
+
 	if (error) {
 		pf_free_rule(rule);
 		rule = NULL;