improvements to PF macros
- Reply: Adrian Chadd : "Re: improvements to PF macros"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 08 Oct 2026 21:00:33 UTC
I've been working with PF under freebsd for a few months, and have noticed a recurring theme in the forums,
that the macros in PF could be improved.
I notice that it is often difficult to define one macro in terms of another, and just addressing that item alone would help
write cleaner simpler rules.
here are two possible changes to parse.y of pfctl.
change 1:
@@ -872,6 +872,16 @@
numberstring : NUMBER {
char *s;
if (asprintf(&s, "%lld", (long long)$1) == -1) {
yyerror("string: asprintf");
YYERROR;
}
$$ = s;
}
+ | '@' STRING {
+ char s = symget($2);
+ if (s == NULL) {
+ yyerror("macro '%s' not defined", $2);
+ YYERROR;
+ }
+ if (($$ = strdup(s)) == NULL) {
+ err(1, "numberstring: strdup");
+ }
+ }
| STRING
;
this change allows a macro to be defined in terms of an existing macro, using the '@' to refer to that existing macro by name,
rather than expanding the macro out and causing the eventual 'syntax error' response that often results.
this allows using one macro within another
set_ext_tag = "tag \"from_outside\""
is_int_tag = "tagged \"from_inside\""
combined_tags = @set_ext_tag @is_int_tag
this results in $combined_tags expanding to:
tag "from_outside" tagged "from_inside"
change 2:
@@ -861,6 +861,12 @@
varstring : numberstring varstring {
if (asprintf(&$$, "%s %s", $1, $2) == -1)
err(1, "string: asprintf");
free($1);
free($2);
}
+ | numberstring '+' varstring {
+ if (asprintf(&$$, "%s%s", $1, $3) == -1)
+ err(1, "string: asprintf");
+ free($1);
+ free($3);
+ }
| numberstring
;
the existing grammar for varstring inserts a space, which is not always helpful, so the second change.
this change adds the '+' operator to explicitly concat two strings together (either or both could be a macro),
which allows the following
subnet = "192.168.0."
client = @subnet + "206"
this results in $client expanding to:
192.168.0.206
I've been working with one external interface and four mostly isolated LANs, two of which have common
rules, and rather than copy-paste everything, I've been fighting with the limitations of PF's macros.
These two changes make it ever so much easier to maintain readable, maintainable rules, so I figured
I would toss them into the ring.
Robert
ps: I've already submitted my corrections to PFIL (the shared layer beneath PF, IPFW, IPTABLES) that block
by default traffic that goes through the firewall before whatever the chosen firewall layer (PF, IPFW, IPTABLES)
comes alive and loads its ruleset, but I haven't seen them applied. Communication wrt them has gone cold.
But if anyone is interested in blocking unwanted traffic that gets thru during a delayed filesystem check etc.,
I can send them again.