The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=af922319e8136a818bc6c38440d98a574c5df7a9
commit af922319e8136a818bc6c38440d98a574c5df7a9 Author: Kristof Provost <k...@freebsd.org> AuthorDate: 2025-08-27 10:02:51 +0000 Commit: Kristof Provost <k...@freebsd.org> CommitDate: 2025-09-25 12:41:07 +0000 pf: support one shot rules Add support for one shot rules that remove themselves from an active ruleset after match. This is an extremely handy technique for firewall proxies. ok henning, mcbride Note that the FreeBSD implementation differs significantly from the OpenBSD version due to locking differences. We do not remove the rule, but mark it as having fired previously so we can skip it. Obtained from: OpenBSD, mikeb <mi...@openbsd.org>, c981122504 Obtained from: OpenBSD, sashan <sas...@openbsd.org>, a21b78cad0 (partial) Sponsored by: Rubicon Communications, LLC ("Netgate") --- sys/netpfil/pf/pf.c | 19 +++++++++++++++++++ sys/netpfil/pf/pf.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index be00aff1f5cb..450e465e926a 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -5633,6 +5633,9 @@ pf_match_rule(struct pf_test_ctx *ctx, struct pf_kruleset *ruleset) *ctx->rm = ctx->pd->related_rule; break; } + PF_TEST_ATTRIB(r->rule_flag & PFRULE_EXPIRED, + TAILQ_NEXT(r, entries)); + /* Don't count expired rule evaluations. */ pf_counter_u64_add(&r->evaluations, 1); PF_TEST_ATTRIB(pfi_kkif_match(r->kif, pd->kif) == r->ifnot, r->skip[PF_SKIP_IFP]); @@ -5736,6 +5739,21 @@ pf_match_rule(struct pf_test_ctx *ctx, struct pf_kruleset *ruleset) if (r->tag) ctx->tag = r->tag; if (r->anchor == NULL) { + + if (r->rule_flag & PFRULE_ONCE) { + uint32_t rule_flag; + + rule_flag = r->rule_flag; + if ((rule_flag & PFRULE_EXPIRED) == 0 && + atomic_cmpset_int(&r->rule_flag, rule_flag, + rule_flag | PFRULE_EXPIRED)) { + //r->exptime = gettime(); + } else { + r = TAILQ_NEXT(r, entries); + continue; + } + } + if (r->action == PF_MATCH) { /* * Apply translations before increasing counters, @@ -5813,6 +5831,7 @@ pf_match_rule(struct pf_test_ctx *ctx, struct pf_kruleset *ruleset) r = TAILQ_NEXT(r, entries); } + return (ctx->test_status); } diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h index 54ffdbed3de5..bcd66fd17d5d 100644 --- a/sys/netpfil/pf/pf.h +++ b/sys/netpfil/pf/pf.h @@ -637,6 +637,8 @@ struct pf_rule { #define PFRULE_PFLOW 0x00040000 #define PFRULE_ALLOW_RELATED 0x00080000 #define PFRULE_AFTO 0x00200000 /* af-to rule */ +#define PFRULE_ONCE 0x00400000 /* one shot rule */ +#define PFRULE_EXPIRED 0x00800000 /* one shot rule hit by pkt */ #ifdef _KERNEL #define PFRULE_REFS 0x0080 /* rule has references */