summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Hartmeier <dhartmei@cvs.openbsd.org>2001-10-07 11:56:59 +0000
committerDaniel Hartmeier <dhartmei@cvs.openbsd.org>2001-10-07 11:56:59 +0000
commit3c478011ad2d4c9495aa88a3e52e27d8fd464fe9 (patch)
tree3b045021bf793b3ad3ec9d96b758094985090249
parent235f01ce50c57f39706729c8673c685f0a3b001b (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/Makefile4
-rw-r--r--regress/sbin/pfctl/pf12.in5
-rw-r--r--regress/sbin/pfctl/pf12.ok5
-rw-r--r--sbin/pfctl/parse.y140
-rw-r--r--share/man/man5/nat.conf.516
-rw-r--r--share/man/man5/pf.conf.519
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).