Hello,
proposed diff follows stuff discussed here [1] (pf route-to issues). I think
we've reached a consensus to change route-to/reply-to such the only supported
option will be next-hop (and list and table of next-hop addresses).
I think bluhm@ and dlg@ have committed part of that change already.
the proposed diff updates pfctl(8) so parser will do 'a right thing',
namely:
specifying host using form as 1.2.3.4@em0 is not supporte
anymore
diff introduces a next_hop() function, which is a clone of
existing host(). unlike host(), the next_hop() does not accept
a name of local network interface.
the diff also breaks existing regression tests. We can update
them once, we will agree on proposed diff.
thanks and
regards
sashan
[1] https://marc.info/?l=openbsd-tech&m=160308583701259&w=2
--------8<---------------8<---------------8<------------------8<--------
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 2b3e62b1a7e..536aec3286b 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -3745,23 +3745,13 @@ pool_opt : BITMASK {
;
route_host : STRING {
- /* try to find @if0 address specs */
- if (strrchr($1, '@') != NULL) {
- if (($$ = host($1, pf->opts)) == NULL) {
- yyerror("invalid host for route spec");
- YYERROR;
- }
+ if (($$ = next_hop($1, pf->opts)) == NULL) {
+ /* error. "any" is handled elsewhere */
free($1);
- } else {
- $$ = calloc(1, sizeof(struct node_host));
- if ($$ == NULL)
- err(1, "route_host: calloc");
- $$->ifname = $1;
- $$->addr.type = PF_ADDR_NONE;
- set_ipmask($$, 128);
- $$->next = NULL;
- $$->tail = $$;
+ yyerror("could not parse host specification");
+ YYERROR;
}
+ free($1);
}
| STRING '/' STRING {
char *buf;
@@ -3769,7 +3759,7 @@ route_host : STRING {
if (asprintf(&buf, "%s/%s", $1, $3) == -1)
err(1, "host: asprintf");
free($1);
- if (($$ = host(buf, pf->opts)) == NULL) {
+ if (($$ = next_hop(buf, pf->opts)) == NULL) {
/* error. "any" is handled elsewhere */
free(buf);
yyerror("could not parse host specification");
@@ -3795,33 +3785,6 @@ route_host : STRING {
$$->next = NULL;
$$->tail = $$;
}
- | dynaddr '/' NUMBER {
- struct node_host *n;
-
- if ($3 < 0 || $3 > 128) {
- yyerror("bit number too big");
- YYERROR;
- }
- $$ = $1;
- for (n = $1; n != NULL; n = n->next)
- set_ipmask(n, $3);
- }
- | '(' STRING host ')' {
- struct node_host *n;
-
- $$ = $3;
- /* XXX check masks, only full mask should be allowed */
- for (n = $3; n != NULL; n = n->next) {
- if ($$->ifname) {
- yyerror("cannot specify interface twice
"
- "in route spec");
- YYERROR;
- }
- if (($$->ifname = strdup($2)) == NULL)
- errx(1, "host: strdup");
- }
- free($2);
- }
;
route_host_list : route_host optweight optnl {
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 03317844e91..534b53b1198 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1615,17 +1615,16 @@ host(const char *s, int opts)
{
struct node_host *h = NULL, *n;
int mask = -1;
- char *p, *ps, *if_name;
+ char *p, *ps;
const char *errstr;
+ if (strchr(s, '@') != NULL)
+ err(1, "%s: '@' not expected in host spec. (%s)\n",
+ __func__, s);
+
if ((ps = strdup(s)) == NULL)
err(1, "%s: strdup", __func__);
- if ((if_name = strrchr(ps, '@')) != NULL) {
- if_name[0] = '\0';
- if_name++;
- }
-
if ((p = strchr(ps, '/')) != NULL) {
mask = strtonum(p+1, 0, 128, &errstr);
if (errstr) {
@@ -1642,10 +1641,46 @@ host(const char *s, int opts)
goto error;
}
- if (if_name && if_name[0])
- for (n = h; n != NULL; n = n->next)
- if ((n->ifname = strdup(if_name)) == NULL)
- err(1, "%s: strdup", __func__);
+ for (n = h; n != NULL; n = n->next) {
+ n->addr.type = PF_ADDR_ADDRMASK;
+ n->weight = 0;
+ }
+
+error:
+ free(ps);
+ return (h);
+}
+
+struct node_host *
+next_hop(const char *s, int opts)
+{
+ struct node_host *h = NULL, *n;
+ int mask = -1;
+ char *p, *ps;
+ const char *errstr;
+
+ if (strchr(s, '@') != NULL)
+ err(1, "%s: '@' not expected in next-hop spec. (%s)\n",
+ __func__, s);
+
+ if ((ps = strdup(s)) == NULL)
+ err(1, "%s: strdup", __func__);
+
+ if ((p = strchr(ps, '/')) != NULL) {
+ mask = strtonum(p+1, 0, 128, &errstr);
+ if (errstr) {
+ fprintf(stderr, "netmask is %s: %s\n", errstr, p);
+ goto error;
+ }
+ p[0] = '\0';
+ }
+
+ if ((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);
+ goto error;
+ }
+
for (n = h; n != NULL; n = n->next) {
n->addr.type = PF_ADDR_ADDRMASK;
n->weight = 0;
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index a82854a0fea..c7ab3f967b6 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -292,6 +292,7 @@ char *ifa_indextoname(unsigned int,
char *);
struct node_host *ifa_exists(const char *);
struct node_host *ifa_lookup(const char *, int);
struct node_host *host(const char *, int);
+struct node_host *next_hop(const char *, int);
int append_addr(struct pfr_buffer *, char *, int, int);
int append_addr_host(struct pfr_buffer *,