Download raw body.
tell pfctl(8) route-to no longer expects network interface
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
tell pfctl(8) route-to no longer expects network interface