diff options
author | Daniel Hartmeier <dhartmei@cvs.openbsd.org> | 2001-10-07 11:56:59 +0000 |
---|---|---|
committer | Daniel Hartmeier <dhartmei@cvs.openbsd.org> | 2001-10-07 11:56:59 +0000 |
commit | 3c478011ad2d4c9495aa88a3e52e27d8fd464fe9 (patch) | |
tree | 3b045021bf793b3ad3ec9d96b758094985090249 | |
parent | 235f01ce50c57f39706729c8673c685f0a3b001b (diff) |
Add interface name to address translation to pfctl, document it and add
a regress test. Translation is done on rule set load-time only, so the
rule sets must be reloaded when an interface address changes.
parse.y patch from Cedric Berger. Similar patch from Jonathon Fletcher.
Thanks to both.
-rw-r--r-- | regress/sbin/pfctl/Makefile | 4 | ||||
-rw-r--r-- | regress/sbin/pfctl/pf12.in | 5 | ||||
-rw-r--r-- | regress/sbin/pfctl/pf12.ok | 5 | ||||
-rw-r--r-- | sbin/pfctl/parse.y | 140 | ||||
-rw-r--r-- | share/man/man5/nat.conf.5 | 16 | ||||
-rw-r--r-- | share/man/man5/pf.conf.5 | 19 |
6 files changed, 179 insertions, 10 deletions
diff --git a/regress/sbin/pfctl/Makefile b/regress/sbin/pfctl/Makefile index 0c7e7430051..e3a0a4769c2 100644 --- a/regress/sbin/pfctl/Makefile +++ b/regress/sbin/pfctl/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.9 2001/09/15 23:25:23 wilfried Exp $ +# $OpenBSD: Makefile,v 1.10 2001/10/07 11:56:58 dhartmei Exp $ NOMAN= NOPROG= -PFTESTS=1 2 3 4 5 6 7 8 9 10 11 +PFTESTS=1 2 3 4 5 6 7 8 9 10 11 12 PFFAIL=1 2 3 4 5 6 7 .for n in ${PFFAIL} diff --git a/regress/sbin/pfctl/pf12.in b/regress/sbin/pfctl/pf12.in new file mode 100644 index 00000000000..50078bb3c6b --- /dev/null +++ b/regress/sbin/pfctl/pf12.in @@ -0,0 +1,5 @@ +pass in from 127.0.0.1 to 127.0.0.1/8 +pass in from 127.0.0.1/16 to 127.0.0.1/24 +pass in from 127.0.0.1/25 to ! 127.0.0.1/26 +pass in from ! localhost to localhost/16 +pass in from ! lo0 to ! lo0/8 diff --git a/regress/sbin/pfctl/pf12.ok b/regress/sbin/pfctl/pf12.ok new file mode 100644 index 00000000000..7577152029c --- /dev/null +++ b/regress/sbin/pfctl/pf12.ok @@ -0,0 +1,5 @@ +@0 pass in inet from 127.0.0.1/32 to 127.0.0.1/8 +@0 pass in inet from 127.0.0.1/16 to 127.0.0.1/24 +@0 pass in inet from 127.0.0.1/25 to ! 127.0.0.1/26 +@0 pass in inet from ! 127.0.0.1/32 to 127.0.0.1/16 +@0 pass in inet from ! 127.0.0.1/32 to ! 127.0.0.1/8 diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index b9a3e449737..a0a83c37930 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.38 2001/10/01 17:58:16 markus Exp $ */ +/* $OpenBSD: parse.y,v 1.39 2001/10/07 11:56:57 dhartmei Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -38,6 +38,8 @@ #include <arpa/inet.h> #include <stdio.h> +#include <stdlib.h> +#include <ifaddrs.h> #include <netdb.h> #include <stdarg.h> #include <errno.h> @@ -121,6 +123,10 @@ struct sym *symhead = NULL; int symset(char *name, char *val); char * symget(char *name); +struct ifaddrs *ifa0_lookup(char *ifa_name); +struct ifaddrs *ifa4_lookup(char *ifa_name); +struct ifaddrs *ifa6_lookup(char *ifa_name); + typedef struct { union { u_int32_t number; @@ -409,8 +415,41 @@ host : address { address : STRING { struct hostent *hp; + struct ifaddrs *ifa; + + if (ifa0_lookup($1)) { + /* an interface with this name exists */ + if ((ifa = ifa4_lookup($1))) { + struct sockaddr_in *sin = + (struct sockaddr_in *) + ifa->ifa_addr; - if ((hp = gethostbyname2($1, AF_INET)) == NULL) { + $$ = calloc(1, + sizeof(struct node_host)); + if ($$ == NULL) + err(1, "address: calloc"); + $$->af = AF_INET; + memcpy(&$$->addr, &sin->sin_addr, + sizeof(u_int32_t)); + } else if ((ifa = ifa6_lookup($1))) { + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *) + ifa->ifa_addr; + + $$ = calloc(1, + sizeof(struct node_host)); + if ($$ == NULL) + err(1, "address: calloc"); + $$->af = AF_INET6; + memcpy(&$$->addr, &sin6->sin6_addr, + sizeof(struct pf_addr)); + } else { + yyerror("interface %s has no IP " + "addresses", $1); + YYERROR; + } + } + else if ((hp = gethostbyname2($1, AF_INET)) == NULL) { if ((hp = gethostbyname2($1, AF_INET6)) == NULL) { yyerror("cannot resolve %s", $1); @@ -1555,3 +1594,100 @@ symget(char *nam) return (sym->val); return (NULL); } + +struct ifaddrs **ifa0tab, **ifa4tab, **ifa6tab; +int ifa0len, ifa4len, ifa6len; + +int +ifa_comp(const void *p1, const void *p2) +{ + struct ifaddrs *ifa1 = *(struct ifaddrs **)p1; + struct ifaddrs *ifa2 = *(struct ifaddrs **)p2; + + return strcmp(ifa1->ifa_name, ifa2->ifa_name); +} + +void +ifa_load(void) +{ + struct ifaddrs *ifap, *ifa; + int ifalen = 0; + + if (getifaddrs(&ifap) < 0) + err(1, "getifaddrs"); + for (ifa = ifap; ifa; ifa = ifa->ifa_next) + ifalen++; + /* (over-)allocate tables */ + ifa0tab = malloc(ifalen * sizeof(void *)); + ifa4tab = malloc(ifalen * sizeof(void *)); + ifa6tab = malloc(ifalen * sizeof(void *)); + if (!ifa0tab || !ifa4tab || !ifa6tab) + err(1, "malloc"); + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family == AF_LINK) { + if (bsearch(&ifa, ifa0tab, ifa0len, sizeof(void *), + ifa_comp)) + continue; /* take only the first LINK address */ + ifa0tab[ifa0len++] = ifa; + qsort(ifa0tab, ifa0len, sizeof(void *), ifa_comp); + } + if (ifa->ifa_addr->sa_family == AF_INET) { + if (bsearch(&ifa, ifa4tab, ifa4len, sizeof(void *), + ifa_comp)) + continue; /* take only the first IPv4 address */ + ifa4tab[ifa4len++] = ifa; + qsort(ifa4tab, ifa4len, sizeof(void *), ifa_comp); + } + if (ifa->ifa_addr->sa_family == AF_INET6) { + /* XXX - better address selection required! */ + if (bsearch(&ifa, ifa6tab, ifa6len, sizeof(void *), + ifa_comp)) + continue; /* take only the first IPv6 address */ + ifa6tab[ifa6len++] = ifa; + qsort(ifa6tab, ifa6len, sizeof(void *), ifa_comp); + } + } + /* shrink tables */ + ifa0tab = realloc(ifa0tab, ifa0len * sizeof(void *)); + ifa4tab = realloc(ifa4tab, ifa4len * sizeof(void *)); + ifa6tab = realloc(ifa6tab, ifa6len * sizeof(void *)); + if (!ifa0tab || !ifa4tab || !ifa6tab) + err(1, "realloc"); +} + +struct ifaddrs * +ifa0_lookup(char *ifa_name) +{ + struct ifaddrs ifa, *ifp = &ifa, **ifpp; + + if (!ifa0tab) + ifa_load(); + ifa.ifa_name = ifa_name; + ifpp = bsearch(&ifp, ifa0tab, ifa0len, sizeof(void *), ifa_comp); + return ifpp ? *ifpp : NULL; +} + +struct ifaddrs * +ifa4_lookup(char *ifa_name) +{ + struct ifaddrs ifa, *ifp = &ifa, **ifpp; + + if (!ifa4tab) + ifa_load(); + ifa.ifa_name = ifa_name; + ifpp = bsearch(&ifp, ifa4tab, ifa4len, sizeof(void *), ifa_comp); + return ifpp ? *ifpp : NULL; +} + +struct ifaddrs * +ifa6_lookup(char *ifa_name) +{ + struct ifaddrs ifa, *ifp = &ifa, **ifpp; + + if (!ifa6tab) + ifa_load(); + ifa.ifa_name = ifa_name; + ifpp = bsearch(&ifp, ifa6tab, ifa6len, sizeof(void *), ifa_comp); + return ifpp ? *ifpp : NULL; +} + diff --git a/share/man/man5/nat.conf.5 b/share/man/man5/nat.conf.5 index e9c7fbb7ba6..bee513c1519 100644 --- a/share/man/man5/nat.conf.5 +++ b/share/man/man5/nat.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: nat.conf.5,v 1.15 2001/10/05 14:45:54 mpech Exp $ +.\" $OpenBSD: nat.conf.5,v 1.16 2001/10/07 11:56:57 dhartmei Exp $ .\" .\" Copyright (c) 2001 Ian Darwin. All rights reserved. .\" @@ -88,9 +88,19 @@ Comments begin with the character `#'; empty lines are ignored. An .Em ifname is a network interface such as fxp4, ne0, or ep1. -An .Em address -is an IP address. +can be specified in CIDR notation (matching netblocks), as +symbolic host names or interface names. +Host name resolution and interface to address translation are done at rule +set load-time. +When the address of an interface (or host name) changes (by DHCP or PPP, +for instance), the rule set must be reloaded for the change to be reflected +in the kernel. +See +.Xr dhclient-script 8 +or +.Xr ppp 8 +for information on how to automate this task. If specified, .Em mask-bits refers to the number of bits in the netmask. diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5 index 497e49179fa..3c93aadc269 100644 --- a/share/man/man5/pf.conf.5 +++ b/share/man/man5/pf.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pf.conf.5,v 1.20 2001/10/05 14:45:54 mpech Exp $ +.\" $OpenBSD: pf.conf.5,v 1.21 2001/10/07 11:56:57 dhartmei Exp $ .\" .\" Copyright (c) 2001, Daniel Hartmeier .\" All rights reserved. @@ -186,8 +186,21 @@ Common protocols used here are tcp, udp, icmp and ipv6-icmp. .Ss from <source> port <source> to <dest> port <dest> The rule applies only to packets with the specified source and destination addresses/ports. -Addresses can be specified in CIDR notation (matching netblocks) and ports -can be specified using these operators +.Pp +Addresses can be specified in CIDR notation (matching netblocks), as +symbolic host names or interface names. +Host name resolution and interface to address translation are done at +rule set load-time. +When the address of an interface (or host name) changes (by DHCP or PPP, +for instance), the rule set must be reloaded for the change to be reflected +in the kernel. +See +.Xr dhclient-script 8 +or +.Xr ppp 8 +for information on how to automate this task. +.Pp +Ports can be specified using these operators .Bd -literal = (equal), != (unequal), < (lesser), <= (lesser or equal), > (greater), >= (greater or equal), >< (range) and <> (except range). |