Perhaps another suffix along the lines of ':network' and ':broadcast' that omits non-routable addresses (':routable', ':network-routable')?
Attached is a patch that implements this. So now you can write:
pass in on gif0 from any to gif0:routable
and have it expand to only:
pass in on gif0 from any to 2001::x
assuming gif0 has 2001::x and a link-local address.
It allows calls to ifa_lookup() to specify a scope (PFCTL_IFLOOKUP_ANY, _LOCAL or _ROUTABLE), and host_if() simply translates the appropriate interface suffixes to a scope value.
ifa_lookup() does the scope check using the IN6_IS_ADDR_LINKLOCAL() macro from <netinet6/in6.h>. It would probably be a bit cleaner to check the scope id itself but since those scope values seem to be internal-use only and since the macro is also used in other parts of pfctl, I thought it best to use IN6_IS_ADDR_LINKLOCAL() for this.
I've also made a patch for the pf.conf manpage (see second attachment), in which the behaviour is documented as follows:
:local Translates to the interface's addresses that are not routable, eg. IPv6 link-local addresses. :network-local Same as above, but the addresses of the network(s) attached to the interface. :routable Translates to the interface's addresses that are routable. :network-routable Same as above, but the addresses of the network(s) attached to the interface.
Both patches are against OpenBSD 3.4.
Regards, Wouter Coene
Index: parse.y =================================================================== RCS file: /home/openbsd/cvs/src/sbin/pfctl/parse.y,v retrieving revision 1.415 diff -u -r1.415 parse.y --- parse.y 1 Sep 2003 15:07:40 -0000 1.415 +++ parse.y 9 Nov 2003 20:08:21 -0000 @@ -806,7 +806,9 @@ YYERROR; } j->not = 1; - h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET); + /* XXX only antispoof for routable addresses? */ + h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET, + PFCTL_IFLOOKUP_ANY); expand_rule(&r, j, NULL, NULL, NULL, h, NULL, NULL, NULL, NULL, NULL, NULL); @@ -821,8 +823,11 @@ r.af = $4; if (rule_label(&r, $5.label)) YYERROR; + /* XXX only antispoof for routable + addresses? */ h = ifa_lookup(i->ifname, - PFCTL_IFLOOKUP_HOST); + PFCTL_IFLOOKUP_HOST, + PFCTL_IFLOOKUP_ANY); expand_rule(&r, NULL, NULL, NULL, NULL, h, NULL, NULL, NULL, NULL, NULL, NULL); Index: pfctl_parser.c =================================================================== RCS file: /home/openbsd/cvs/src/sbin/pfctl/pfctl_parser.c,v retrieving revision 1.174 diff -u -r1.174 pfctl_parser.c --- pfctl_parser.c 22 Aug 2003 21:52:11 -0000 1.174 +++ pfctl_parser.c 9 Nov 2003 20:08:21 -0000 @@ -962,7 +962,8 @@ } struct node_host * -ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode) +ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode, + enum pfctl_iflookup_scope scope) { struct node_host *p = NULL, *h = NULL, *n = NULL; int return_all = 0; @@ -977,6 +978,16 @@ if (!((p->af == AF_INET || p->af == AF_INET6) && (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all))) continue; +#ifdef __KAME__ + if (scope != PFCTL_IFLOOKUP_ANY && p->af == AF_INET6) { + if (scope == PFCTL_IFLOOKUP_LOCAL && + !IN6_IS_ADDR_LINKLOCAL(&(p->addr.v.a.addr.v6))) + continue; + if (scope == PFCTL_IFLOOKUP_ROUTABLE && + IN6_IS_ADDR_LINKLOCAL(&(p->addr.v.a.addr.v6))) + continue; + } +#endif if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET) continue; if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0) @@ -1077,13 +1088,28 @@ struct node_host *n, *h = NULL; char *p, *ps; int mode = PFCTL_IFLOOKUP_HOST; + int scope = PFCTL_IFLOOKUP_ANY; if ((p = strrchr(s, ':')) != NULL && - (!strcmp(p+1, "network") || !strcmp(p+1, "broadcast"))) { + (!strcmp(p+1, "network") || !strcmp(p+1, "broadcast") || + !strcmp(p+1, "local") || !strcmp(p+1, "network-local") || + !strcmp(p+1, "routable") || !strcmp(p+1, "network-routable"))) { if (!strcmp(p+1, "network")) mode = PFCTL_IFLOOKUP_NET; if (!strcmp(p+1, "broadcast")) mode = PFCTL_IFLOOKUP_BCAST; + if (!strcmp(p+1, "local")) + scope = PFCTL_IFLOOKUP_LOCAL; + if (!strcmp(p+1, "network-local")) { + mode = PFCTL_IFLOOKUP_NET; + scope = PFCTL_IFLOOKUP_LOCAL; + } + if (!strcmp(p+1, "routable")) + scope = PFCTL_IFLOOKUP_ROUTABLE; + if (!strcmp(p+1, "network-routable")) { + mode = PFCTL_IFLOOKUP_NET; + scope = PFCTL_IFLOOKUP_ROUTABLE; + } if (mask > -1) { fprintf(stderr, "network or broadcast lookup, but " "extra netmask given\n"); @@ -1098,7 +1124,7 @@ if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) { /* interface with this name exists */ - h = ifa_lookup(ps, mode); + h = ifa_lookup(ps, mode, scope); for (n = h; n != NULL && mask > -1; n = n->next) set_ipmask(n, mask); } Index: pfctl_parser.h =================================================================== RCS file: /home/openbsd/cvs/src/sbin/pfctl/pfctl_parser.h,v retrieving revision 1.67 diff -u -r1.67 pfctl_parser.h --- pfctl_parser.h 21 Aug 2003 19:12:09 -0000 1.67 +++ pfctl_parser.h 9 Nov 2003 20:08:21 -0000 @@ -78,6 +78,11 @@ PFCTL_IFLOOKUP_NET, PFCTL_IFLOOKUP_BCAST }; +enum pfctl_iflookup_scope { + PFCTL_IFLOOKUP_ANY, + PFCTL_IFLOOKUP_LOCAL, + PFCTL_IFLOOKUP_ROUTABLE +}; struct node_if { char ifname[IFNAMSIZ]; @@ -218,7 +223,8 @@ int check_netmask(struct node_host *, sa_family_t); void ifa_load(void); struct node_host *ifa_exists(const char *); -struct node_host *ifa_lookup(const char *, enum pfctl_iflookup_mode); +struct node_host *ifa_lookup(const char *, enum pfctl_iflookup_mode, + enum pfctl_iflookup_scope scope); struct node_host *host(const char *); int append_addr(struct pfr_buffer *, char *, int);
Index: pf.conf.5 =================================================================== RCS file: /home/openbsd/cvs/src/share/man/man5/pf.conf.5,v retrieving revision 1.271 diff -u -r1.271 pf.conf.5 --- pf.conf.5 2 Sep 2003 18:37:08 -0000 1.271 +++ pf.conf.5 9 Nov 2003 20:06:09 -0000 @@ -1175,6 +1175,17 @@ Translates to the network(s) attached to the interface. .It Ar :broadcast Translates to the interface's broadcast address(es). +.It Ar :routable +Translates to the interface's addresses that are routable. +.It Ar :network-routable +Same as above, but the addresses of the network(s) attached to the +interface. +.It Ar :local +Translates to the interface's addresses that are not routable, eg. IPv6 +link-local addresses. +.It Ar :network-local +Same as above, but the addresses of the network(s) attached to the +interface. .El .Pp Host name resolution and interface to address translation are done at