The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=9d9bc7f462bd152d87ab8f1767cad19bab09bf8b
commit 9d9bc7f462bd152d87ab8f1767cad19bab09bf8b Author: Kristof Provost <k...@freebsd.org> AuthorDate: 2025-08-25 13:43:10 +0000 Commit: Kristof Provost <k...@freebsd.org> CommitDate: 2025-09-17 14:15:15 +0000 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 <sas...@openbsd.org>, 85baac7751 Sponsored by: Rubicon Communications, LLC ("Netgate") --- sbin/pfctl/pfctl.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file 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; @@ -1780,6 +1784,31 @@ pfctl_show_limits(int dev, int opts) return (0); } +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) { @@ -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 *