From: renaud@openbsd.org Subject: Re: tell pfctl(8) route-to no longer expects network interface To: Alexandr Nedvedicky , tech@openbsd.org Cc: mvs@openbsd.org Date: Sat, 2 May 2026 17:41:35 +0200 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 reticmpspec reticmp6spec > %type fromto > %type ipportspec from to > -%type ipspec xhost host dynaddr host_list > +%type ipspec xhost host dynaddr host_list redirhost > %type table_host_list tablespec > %type redir_host_list redirspec > %type 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 > >