Download raw body.
tell pfctl(8) route-to no longer expects network interface
On 02/05/2026 16:03, Alexandr Nedvedicky wrote:
> Hello,
>
> Consider rule as follows:
>
> pass in on vio0 from vio0:network to ! (vio0) route-to wg1
>
> When pfctl(8) in current resolves 'wg1' option at route-to action
> it attempts to interpret it also as interface name. This is wrong.
> When wg1 interface happens to be plumbed to system the parser
> accepts the rule with no error and uses wg1 IP address as next-hop
> for route-to action. Such configuration is invalid/unexpected because
> matching packets will be looped back to local IP stack.
>
> since 6.9 route-to action expects next-hop/destination IP address where
> matching packets should be sent to.
>
> diff below prevents parser to prevent route-to parameter as interface name.
>
> The issue has been noticed and reported off-list by Vitaliy Makkoveev mvs@
>
> OK to commit?
>
It seems this breaks correct simple rules
amd64# echo 'match out on em0 inet nat-to (em0)' > /tmp/test.conf
amd64# /home/r/pfctl-patched -nvf /tmp/test.conf
/tmp/test.conf:1: syntax error
> thanks and
> regards
> sashan
>
> --------8<---------------8<---------------8<------------------8<--------
> diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
> index 92764edcf3b..74b0ebaa43b 100644
> --- a/sbin/pfctl/parse.y
> +++ b/sbin/pfctl/parse.y
> @@ -567,7 +567,7 @@ int parseport(char *, struct range *r, int);
> %type <v.number> reticmpspec reticmp6spec
> %type <v.fromto> fromto
> %type <v.peer> ipportspec from to
> -%type <v.host> ipspec xhost host dynaddr host_list
> +%type <v.host> ipspec xhost host dynaddr host_list redirhost
> %type <v.host> table_host_list tablespec
> %type <v.host> redir_host_list redirspec
> %type <v.os> os xos os_list
> @@ -4032,7 +4032,7 @@ portstar : numberstring {
> }
> ;
>
> -redirspec : host optweight {
> +redirspec : redirhost optweight {
> if ($2 > 0) {
> struct node_host *n;
> for (n = $1; n != NULL; n = n->next)
> @@ -4043,7 +4043,7 @@ redirspec : host optweight {
> | '{' optnl redir_host_list '}' { $$ = $3; }
> ;
>
> -redir_host_list : host optweight optnl {
> +redir_host_list : redirhost optweight optnl {
> if ($1->addr.type != PF_ADDR_ADDRMASK) {
> free($1);
> yyerror("only addresses can be listed for "
> @@ -4057,7 +4057,7 @@ redir_host_list : host optweight optnl {
> }
> $$ = $1;
> }
> - | redir_host_list comma host optweight optnl {
> + | redir_host_list comma redirhost optweight optnl {
> $1->tail->next = $3;
> $1->tail = $3->tail;
> if ($4 > 0) {
> @@ -4085,6 +4085,17 @@ redirpool : redirspec {
> }
> ;
>
> +redirhost : STRING {
> + $$ = host($1, pf->opts | PF_OPT_NOIFNAME);
> + if ($$ == NULL) {
> + free($1);
> + yyerror("could not parse host specification");
> + YYERROR;
> + }
> + free($1);
> + }
> + ;
> +
> hashkey : /* empty */
> {
> $$ = calloc(1, sizeof(struct pf_poolhashkey));
> diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
> index f47ee3e8568..0905d5bf15c 100644
> --- a/sbin/pfctl/pfctl_parser.c
> +++ b/sbin/pfctl/pfctl_parser.c
> @@ -77,7 +77,7 @@ void print_scspec(const char *, struct pf_queue_scspec *);
> int ifa_skip_if(const char *filter, struct node_host *p);
>
> struct node_host *ifa_grouplookup(const char *, int);
> -struct node_host *host_if(const char *, int);
> +struct node_host *host_if(const char *, int, int);
> struct node_host *host_ip(const char *, int);
> struct node_host *host_dns(const char *, int, int);
>
> @@ -1713,7 +1713,7 @@ host(const char *s, int opts)
> p[0] = '\0';
> }
>
> - if ((h = host_if(ps, mask)) == NULL &&
> + if ((h = host_if(ps, mask, (opts & PF_OPT_NOIFNAME))) == NULL &&
> (h = host_ip(ps, mask)) == NULL &&
> (h = host_dns(ps, mask, (opts & PF_OPT_NODNS))) == NULL) {
> fprintf(stderr, "no IP address found for %s\n", s);
> @@ -1731,12 +1731,15 @@ error:
> }
>
> struct node_host *
> -host_if(const char *s, int mask)
> +host_if(const char *s, int mask, int reject_iface)
> {
> struct node_host *n, *h = NULL;
> char *p, *ps;
> int flags = 0;
>
> + if (reject_iface)
> + return (NULL);
> +
> if ((ps = strdup(s)) == NULL)
> err(1, "host_if: strdup");
> while ((p = strrchr(ps, ':')) != NULL) {
> diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
> index c65a805ad90..dc52f195a9f 100644
> --- a/sbin/pfctl/pfctl_parser.h
> +++ b/sbin/pfctl/pfctl_parser.h
> @@ -53,6 +53,7 @@
> #define PF_OPT_PORTNAMES 0x08000
> #define PF_OPT_IGNFAIL 0x10000
> #define PF_OPT_CALLSHOW 0x20000
> +#define PF_OPT_NOIFNAME 0x40000
>
> #define PF_TH_ALL 0xFF
>
>
tell pfctl(8) route-to no longer expects network interface