git: ceff35a3aeef - main - pfctl: fix anchor handling for nat/rdr/binat anchors
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 25 Sep 2025 12:41:44 UTC
The branch main has been updated by kp:
URL: https://cgit.FreeBSD.org/src/commit/?id=ceff35a3aeef822976bd159c8bc403b68d5571ff
commit ceff35a3aeef822976bd159c8bc403b68d5571ff
Author: Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2025-08-28 14:26:59 +0000
Commit: Kristof Provost <kp@FreeBSD.org>
CommitDate: 2025-09-25 12:41:10 +0000
pfctl: fix anchor handling for nat/rdr/binat anchors
After the refactoring in 'pfctl: fix once rules' we broke nat/rdr/binat rules.
These no longer exist on OpenBSD, so were not considered in that patch. Factor
out the common code and call it from all anchor types.
Sponsored by: Rubicon Communications, LLC ("Netgate")
---
sbin/pfctl/parse.y | 141 ++++++++++++++++++++++++++++++-----------------------
1 file changed, 79 insertions(+), 62 deletions(-)
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index babe6b99013e..0f7702fc4630 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -432,6 +432,7 @@ int filteropts_to_rule(struct pfctl_rule *, struct filter_opts *);
struct node_mac* node_mac_from_string(const char *);
struct node_mac* node_mac_from_string_masklen(const char *, int);
struct node_mac* node_mac_from_string_mask(const char *, const char *);
+static bool pfctl_setup_anchor(struct pfctl_rule *, struct pfctl *, char *);
static TAILQ_HEAD(loadanchorshead, loadanchors)
loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);
@@ -994,7 +995,6 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
{
struct pfctl_rule r;
struct node_proto *proto;
- char *p;
if (check_rulestate(PFCTL_STATE_FILTER)) {
if ($2)
@@ -1003,68 +1003,9 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
}
pfctl_init_rule(&r);
+ if (! pfctl_setup_anchor(&r, pf, $2))
+ YYERROR;
- if (pf->astack[pf->asd + 1]) {
- if ($2 && strchr($2, '/') != NULL) {
- free($2);
- yyerror("anchor paths containing '/' "
- "cannot be used for inline anchors.");
- YYERROR;
- }
-
- /* Move inline rules into relative location. */
- pfctl_anchor_setup(&r,
- &pf->astack[pf->asd]->ruleset,
- $2 ? $2 : pf->alast->name);
-
- if (r.anchor == NULL)
- err(1, "anchorrule: unable to "
- "create ruleset");
-
- if (pf->alast != r.anchor) {
- if (r.anchor->match) {
- yyerror("inline anchor '%s' "
- "already exists",
- r.anchor->name);
- YYERROR;
- }
- mv_rules(&pf->alast->ruleset,
- &r.anchor->ruleset);
- mv_tables(pf, &pfr_ktables, r.anchor, pf->alast);
- }
- pf_remove_if_empty_ruleset(&pf->alast->ruleset);
- pf->alast = r.anchor;
- } else {
- if (!$2) {
- yyerror("anchors without explicit "
- "rules must specify a name");
- YYERROR;
- }
- /*
- * Don't make non-brace anchors part of the main anchor pool.
- */
- if ((r.anchor = calloc(1, sizeof(*r.anchor))) == NULL) {
- err(1, "anchorrule: calloc");
- }
- pf_init_ruleset(&r.anchor->ruleset);
- r.anchor->ruleset.anchor = r.anchor;
- if (strlcpy(r.anchor->path, $2,
- sizeof(r.anchor->path)) >= sizeof(r.anchor->path)) {
- errx(1, "anchorrule: strlcpy");
- }
- if ((p = strrchr($2, '/')) != NULL) {
- if (strlen(p) == 1) {
- yyerror("anchorrule: bad anchor name %s",
- $2);
- YYERROR;
- }
- } else
- p = $2;
- if (strlcpy(r.anchor->name, p,
- sizeof(r.anchor->name)) >= sizeof(r.anchor->name)) {
- errx(1, "anchorrule: strlcpy");
- }
- }
r.direction = $3;
r.quick = $4.quick;
r.af = $6;
@@ -1113,6 +1054,8 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
}
pfctl_init_rule(&r);
+ if (! pfctl_setup_anchor(&r, pf, $2))
+ YYERROR;
r.action = PF_NAT;
r.af = $4;
@@ -1135,6 +1078,8 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
}
pfctl_init_rule(&r);
+ if (! pfctl_setup_anchor(&r, pf, $2))
+ YYERROR;
r.action = PF_RDR;
r.af = $4;
@@ -1178,6 +1123,8 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto
}
pfctl_init_rule(&r);
+ if (! pfctl_setup_anchor(&r, pf, $2))
+ YYERROR;
r.action = PF_BINAT;
r.af = $4;
@@ -7860,3 +7807,73 @@ filteropts_to_rule(struct pfctl_rule *r, struct filter_opts *opts)
return (0);
}
+
+static bool
+pfctl_setup_anchor(struct pfctl_rule *r, struct pfctl *pf, char *anchorname)
+{
+ char *p;
+
+ if (pf->astack[pf->asd + 1]) {
+ if (anchorname && strchr(anchorname, '/') != NULL) {
+ free(anchorname);
+ yyerror("anchor paths containing '/' "
+ "cannot be used for inline anchors.");
+ return (false);
+ }
+
+ /* Move inline rules into relative location. */
+ pfctl_anchor_setup(r,
+ &pf->astack[pf->asd]->ruleset,
+ anchorname ? anchorname : pf->alast->name);
+
+ if (r->anchor == NULL)
+ err(1, "anchorrule: unable to "
+ "create ruleset");
+
+ if (pf->alast != r->anchor) {
+ if (r->anchor->match) {
+ yyerror("inline anchor '%s' "
+ "already exists",
+ r->anchor->name);
+ return (false);
+ }
+ mv_rules(&pf->alast->ruleset,
+ &r->anchor->ruleset);
+ mv_tables(pf, &pfr_ktables, r->anchor, pf->alast);
+ }
+ pf_remove_if_empty_ruleset(&pf->alast->ruleset);
+ pf->alast = r->anchor;
+ } else {
+ if (! anchorname) {
+ yyerror("anchors without explicit "
+ "rules must specify a name");
+ return (false);
+ }
+ /*
+ * Don't make non-brace anchors part of the main anchor pool.
+ */
+ if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL) {
+ err(1, "anchorrule: calloc");
+ }
+ pf_init_ruleset(&r->anchor->ruleset);
+ r->anchor->ruleset.anchor = r->anchor;
+ if (strlcpy(r->anchor->path, anchorname,
+ sizeof(r->anchor->path)) >= sizeof(r->anchor->path)) {
+ errx(1, "anchorrule: strlcpy");
+ }
+ if ((p = strrchr(anchorname, '/')) != NULL) {
+ if (strlen(p) == 1) {
+ yyerror("anchorrule: bad anchor name %s",
+ anchorname);
+ return (false);
+ }
+ } else
+ p = anchorname;
+ if (strlcpy(r->anchor->name, p,
+ sizeof(r->anchor->name)) >= sizeof(r->anchor->name)) {
+ errx(1, "anchorrule: strlcpy");
+ }
+ }
+
+ return (true);
+}