git: af922319e813 - main - pf: support one shot rules
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 25 Sep 2025 12:41:33 UTC
The branch main has been updated by kp:
URL: https://cgit.FreeBSD.org/src/commit/?id=af922319e8136a818bc6c38440d98a574c5df7a9
commit af922319e8136a818bc6c38440d98a574c5df7a9
Author: Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2025-08-27 10:02:51 +0000
Commit: Kristof Provost <kp@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 <mikeb@openbsd.org>, c981122504
Obtained from: OpenBSD, sashan <sashan@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 */