aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2025-08-25 13:43:10 +0000
committerKristof Provost <kp@FreeBSD.org>2025-09-17 14:15:15 +0000
commit9d9bc7f462bd152d87ab8f1767cad19bab09bf8b (patch)
treee37f89823e9c36e21782f753f7b74200dee8efdf
parent1066515eb5219904c76f6f142e65ccf57eee6c53 (diff)
pf: set limits before rules
The current way to adjust pf(4) limits in pf.conf(5) is inconvenient. For example when ruleset uses more than 512 anchors (the current default limit) one would typically add 'set limit anchor 1024' to adjust the limit so the 'pf.conf(5)' gets processed. Unfortunately it does not work because limit gets changed with DIOCXCOMMIT which is too late. The pf.conf(5) fails to load the anchors to transaction, because the old lower limit is still in place. To fix it we must set the limit as soon as we parse 'set limit ...' option. The issue has been reported and fix tested by rafal _dot_ ramocki _von_ eo.pl OK @bluhm Obtained from: OpenBSD, sashan <sashan@openbsd.org>, 85baac7751 Sponsored by: Rubicon Communications, LLC ("Netgate")
-rw-r--r--sbin/pfctl/pfctl.c60
1 files changed, 57 insertions, 3 deletions
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 601b7651e40b..b29d992b1cda 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -110,6 +110,8 @@ int pfctl_show_status(int, int);
int pfctl_show_running(int);
int pfctl_show_timeouts(int, int);
int pfctl_show_limits(int, int);
+void pfctl_read_limits(struct pfctl_handle *);
+void pfctl_restore_limits(void);
void pfctl_debug(int, u_int32_t, int);
int pfctl_test_altqsupport(int, int);
int pfctl_show_anchors(int, int, char *);
@@ -189,6 +191,8 @@ static const struct {
{ NULL, 0 }
};
+static unsigned int limit_curr[PF_LIMIT_MAX];
+
struct pf_hint {
const char *name;
int timeout;
@@ -1781,6 +1785,31 @@ pfctl_show_limits(int dev, int opts)
}
void
+pfctl_read_limits(struct pfctl_handle *h)
+{
+ int i;
+
+ for (i = 0; pf_limits[i].name; i++) {
+ if (pfctl_get_limit(h, i, &limit_curr[i]))
+ err(1, "DIOCGETLIMIT");
+ }
+}
+
+void
+pfctl_restore_limits(void)
+{
+ int i;
+
+ if (pfh == NULL)
+ return;
+
+ for (i = 0; pf_limits[i].name; i++) {
+ if (pfctl_set_limit(pfh, i, limit_curr[i]))
+ warn("DIOCSETLIMIT (%s)", pf_limits[i].name);
+ }
+}
+
+void
pfctl_show_creators(int opts)
{
int ret;
@@ -2487,8 +2516,14 @@ pfctl_init_options(struct pfctl *pf)
pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT;
pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT;
- pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT;
- pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
+
+ pf->limit[PF_LIMIT_SRC_NODES] = (limit_curr[PF_LIMIT_SRC_NODES] == 0) ?
+ PFSNODE_HIWAT : limit_curr[PF_LIMIT_SRC_NODES];
+ pf->limit[PF_LIMIT_TABLE_ENTRIES] =
+ (limit_curr[PF_LIMIT_TABLE_ENTRIES] == 0) ?
+ PFR_KENTRY_HIWAT : limit_curr[PF_LIMIT_TABLE_ENTRIES];
+ pf->limit[PF_LIMIT_ANCHORS] = (limit_curr[PF_LIMIT_ANCHORS] == 0) ?
+ PF_ANCHOR_HIWAT : limit_curr[PF_LIMIT_ANCHORS];
pf->debug = PF_DEBUG_URGENT;
pf->reassemble = 0;
@@ -2589,6 +2624,9 @@ pfctl_apply_limit(struct pfctl *pf, const char *opt, unsigned int limit)
if (pf->opts & PF_OPT_VERBOSE)
printf("set limit %s %d\n", opt, limit);
+ if ((pf->opts & PF_OPT_NOACTION) == 0)
+ pfctl_load_options(pf);
+
return (0);
}
@@ -3452,6 +3490,11 @@ main(int argc, char *argv[])
if (pfh == NULL)
err(1, "Failed to open netlink");
+ if ((opts & PF_OPT_NOACTION) == 0) {
+ pfctl_read_limits(pfh);
+ atexit(pfctl_restore_limits);
+ }
+
if (opts & PF_OPT_DISABLE)
if (pfctl_disable(dev, opts))
exit_val = 1;
@@ -3695,7 +3738,18 @@ main(int argc, char *argv[])
}
}
- exit(exit_val);
+ /*
+ * prevent pfctl_restore_limits() exit handler from restoring
+ * pf(4) options settings on successful exit.
+ */
+ if (exit_val == 0) {
+ close(dev);
+ dev = -1;
+ pfctl_close(pfh);
+ pfh = NULL;
+ }
+
+ return (exit_val);
}
char *