Index | Thread | Search

From:
Alexandr Nedvedicky <sashan@fastmail.net>
Subject:
tell pfctl(8) route-to no longer expects network interface
To:
tech@openbsd.org
Cc:
mvs@openbsd.org
Date:
Sat, 2 May 2026 16:03:54 +0200

Download raw body.

Thread
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?

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