summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorCedric Berger <cedric@cvs.openbsd.org>2003-01-03 21:37:45 +0000
committerCedric Berger <cedric@cvs.openbsd.org>2003-01-03 21:37:45 +0000
commit53b24bf74006b8fe01c11b5912d6fdd335766f47 (patch)
tree808cc224a9a0a135b48997ef94f531d0af7be38d /sbin
parent18e3159b84731971d6a6fd04b186575959c2ea35 (diff)
Bring in userland code for accessing PF radix tables.
ok dhartmei@ mcbride@
Diffstat (limited to 'sbin')
-rw-r--r--sbin/pfctl/Makefile3
-rw-r--r--sbin/pfctl/parse.y22
-rw-r--r--sbin/pfctl/pf_print_state.c12
-rw-r--r--sbin/pfctl/pfctl.836
-rw-r--r--sbin/pfctl/pfctl.c44
-rw-r--r--sbin/pfctl/pfctl_radix.c378
-rw-r--r--sbin/pfctl/pfctl_radix.h58
-rw-r--r--sbin/pfctl/pfctl_table.c591
-rw-r--r--sbin/pfctl/pfctl_table.h42
9 files changed, 1177 insertions, 9 deletions
diff --git a/sbin/pfctl/Makefile b/sbin/pfctl/Makefile
index 4dfe8b38e6b..73c1a969f0a 100644
--- a/sbin/pfctl/Makefile
+++ b/sbin/pfctl/Makefile
@@ -1,7 +1,8 @@
-# $OpenBSD: Makefile,v 1.10 2002/12/06 16:16:15 henning Exp $
+# $OpenBSD: Makefile,v 1.11 2003/01/03 21:37:44 cedric Exp $
PROG= pfctl
SRCS= pfctl.c parse.y pfctl_parser.c pf_print_state.c pfctl_altq.c
+SRCS+= pfctl_radix.c pfctl_table.c
CFLAGS+= -Wall -Wmissing-prototypes -Wno-uninitialized
CFLAGS+= -Wstrict-prototypes
YFLAGS=
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index a5d44e0ab29..e492ca7b282 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.272 2003/01/02 11:34:59 mcbride Exp $ */
+/* $OpenBSD: parse.y,v 1.273 2003/01/03 21:37:44 cedric Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -56,6 +56,7 @@
#include "pf_print_state.h"
#include "pfctl_parser.h"
+#include "pfctl_radix.h"
#include "pfctl_altq.h"
static struct pfctl *pf = NULL;
@@ -1477,6 +1478,25 @@ xhost : '!' host {
host : address
| STRING '/' number { $$ = host($1, $3); }
+ | PORTUNARY STRING PORTUNARY {
+ struct pfr_table tbl;
+ int exists = 0;
+
+ if ($1 != PF_OP_LT || $3 != PF_OP_GT)
+ YYERROR;
+ $$ = calloc(1, sizeof(struct node_host));
+ if ($$ == NULL)
+ err(1, "host: calloc");
+ $$->af = 0;
+ bzero(&tbl, sizeof(tbl));
+ strlcpy(tbl.pfrt_name, $2, sizeof(tbl.pfrt_name));
+ if (pfr_wrap_table(&tbl, &$$->addr, &exists, 0))
+ err(1, "pfr_wrap_table");
+ if (!exists)
+ fprintf(stderr, "warning: %s "
+ "table is not currently defined\n",
+ tbl.pfrt_name);
+ }
;
number : STRING {
diff --git a/sbin/pfctl/pf_print_state.c b/sbin/pfctl/pf_print_state.c
index 6f43cc3cf74..f6d8fe02e32 100644
--- a/sbin/pfctl/pf_print_state.c
+++ b/sbin/pfctl/pf_print_state.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_print_state.c,v 1.14 2002/12/18 16:09:25 dhartmei Exp $ */
+/* $OpenBSD: pf_print_state.c,v 1.15 2003/01/03 21:37:44 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -53,6 +53,7 @@
#include <err.h>
#include "pfctl_parser.h"
+#include "pfctl_radix.h"
#include "pf_print_state.h"
void print_name(struct pf_addr *, struct pf_addr *, sa_family_t);
@@ -62,6 +63,15 @@ print_addr(struct pf_addr_wrap *addr, sa_family_t af)
{
char buf[48];
+ if (addr->mask.addr32[0] == PF_TABLE_MASK) {
+ struct pfr_table tbl = { "?" };
+
+ if (pfr_unwrap_table(&tbl, addr, 0))
+ printf("<0x%08X>", addr->addr.addr32[0]);
+ else
+ printf("<%s>", tbl.pfrt_name);
+ return;
+ }
if (addr->addr_dyn != NULL)
printf("(%s)", addr->addr.pfa.ifname);
else {
diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8
index 3da745ffc7b..e77dd31c123 100644
--- a/sbin/pfctl/pfctl.8
+++ b/sbin/pfctl/pfctl.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: pfctl.8,v 1.60 2002/12/15 16:52:35 margarida Exp $
+.\" $OpenBSD: pfctl.8,v 1.61 2003/01/03 21:37:44 cedric Exp $
.\"
.\" Copyright (c) 2001 Kjell Wooding. All rights reserved.
.\"
@@ -39,6 +39,8 @@
.Op Fl k Ar host
.Op Fl s Ar modifier
.Op Fl x Ar level
+.Op Fl t Ar table
+.Op Fl T Ar command
.Sh DESCRIPTION
The
.Nm
@@ -120,7 +122,7 @@ rules, in that order.
.It Fl F Ar modifier
Flush one of the following.
Modifier name may be abbreviated:
-.Bl -tag -width "F rules " -compact
+.Bl -tag -width "F tables " -compact
.It Fl F Ar nat
Flush the NAT rules.
.It Fl F Ar queue
@@ -131,6 +133,8 @@ Flush the filter rules.
Flush the state table (NAT and filter).
.It Fl F Ar info
Flush the filter information (statistics that are not bound to rules).
+.It Fl F Ar Tables
+Flush the radix tables.
.It Fl F Ar all
Flush all of the above.
.El
@@ -168,7 +172,7 @@ Other rules and options are ignored.
.It Fl s Ar modifier
Show filter parameters.
Modifier names may be abbreviated:
-.Bl -tag -width "s rules " -compact
+.Bl -tag -width "s timeouts " -compact
.It Fl s Ar nat
Show the currently loaded NAT rules.
.It Fl s Ar queue
@@ -199,9 +203,35 @@ useful for accounting.
Show the current global timeouts.
.It Fl s Ar memory
Show the current pool memory hard limits.
+.It Fl s Ar Tables
+Show the list of radix tables.
.It Fl s Ar all
Show all of the above.
.El
+.It Fl t Ar table
+Specify the name of the radix table.
+.It Fl T Ar command
+Specify the command to apply to the table. commands include:
+.Bl -tag -width "T Replace " -compact
+.It Fl T Ar create
+Create a new table.
+.It Fl T Ar kill
+Kill a table.
+.It Fl T Ar flush
+Flush all addresses of a table.
+.It Fl T Ar add
+Add one or more addresses in a table.
+.It Fl T Ar delete
+Delete one or more addresses from a table.
+.It Fl T Ar replace
+Replace the addresses of the table.
+.It Fl T Ar show
+Show the content (addresses) of a table.
+.It Fl T Ar test
+Test if the given addresses match a table.
+.It Fl T Ar zero
+Clear all the statistics of a table.
+.El
.It Fl v
Produce more verbose output. A second use of
.Fl v
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 5615aa50575..2f1115908d1 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl.c,v 1.117 2003/01/01 17:20:14 henning Exp $ */
+/* $OpenBSD: pfctl.c,v 1.118 2003/01/03 21:37:44 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -53,6 +53,8 @@
#include "pfctl_parser.h"
#include "pf_print_state.h"
#include "pfctl_altq.h"
+#include "pfctl_table.h"
+#include "pfctl_radix.h"
void usage(void);
int pfctl_enable(int, int);
@@ -85,6 +87,8 @@ char *rulesopt;
char *showopt;
char *debugopt;
char *anchoropt;
+char *tableopt;
+char *tblcmdopt;
int state_killers;
char *state_kill[2];
int loadopt = PFCTL_FLAG_ALL;
@@ -166,6 +170,8 @@ usage(void)
fprintf(stderr, "[-a anchor:ruleset] [-f file]\n");
fprintf(stderr, " ");
fprintf(stderr, "[-F modifier] [-k host] [-s modifier] [-x level]\n");
+ fprintf(stderr, " ");
+ fprintf(stderr, "[-t table [-T command [addresses]*]]\n");
exit(1);
}
@@ -1240,11 +1246,13 @@ main(int argc, char *argv[])
int ch;
int mode = O_RDONLY;
int opts = 0;
+ int dummy = 0;
if (argc < 2)
usage();
- while ((ch = getopt(argc, argv, "a:Adeqf:F:hk:nNOrRs:vx:z")) != -1) {
+ while ((ch = getopt(argc, argv, "a:Adeqf:F:hk:nNOrRs:t:T:vx:z")) !=
+ -1) {
switch (ch) {
case 'a':
anchoropt = optarg;
@@ -1302,6 +1310,12 @@ main(int argc, char *argv[])
case 's':
showopt = optarg;
break;
+ case 't':
+ tableopt = optarg;
+ break;
+ case 'T':
+ tblcmdopt = optarg;
+ break;
case 'v':
if (opts & PF_OPT_VERBOSE)
opts |= PF_OPT_VERBOSE2;
@@ -1323,7 +1337,16 @@ main(int argc, char *argv[])
}
}
- if (argc != optind) {
+ if (tableopt != NULL || tblcmdopt != NULL) {
+ argc -= optind;
+ argv += optind;
+ ch = (tblcmdopt != NULL) ? *tblcmdopt : 0;
+ mode = strchr("acdfkrz", ch) ? O_RDWR : O_RDONLY;
+ if (opts & PF_OPT_NOACTION) {
+ opts &= ~PF_OPT_NOACTION;
+ dummy = PF_OPT_NOACTION;
+ }
+ } else if (argc != optind) {
warnx("unknown command line argument: %s ...", argv[optind]);
usage();
/* NOTREACHED */
@@ -1367,6 +1390,7 @@ main(int argc, char *argv[])
if (dev == -1)
err(1, "open(\"/dev/pf\")");
altqsupport = pfctl_test_altqsupport(dev);
+ pfr_set_fd(dev);
} else {
/* turn off options */
opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
@@ -1401,6 +1425,10 @@ main(int argc, char *argv[])
pfctl_clear_altq(dev, opts);
pfctl_clear_states(dev, opts);
pfctl_clear_stats(dev, opts);
+ pfctl_clear_tables(opts);
+ break;
+ case 'T':
+ pfctl_clear_tables(opts);
break;
default:
warnx("Unknown flush modifier '%s'", clearopt);
@@ -1410,6 +1438,12 @@ main(int argc, char *argv[])
if (state_killers)
pfctl_kill_states(dev, opts);
+ if (tableopt != NULL || tblcmdopt != NULL) {
+ error = pfctl_command_tables(argc, argv, tableopt,
+ tblcmdopt, rulesopt, opts | dummy);
+ rulesopt = NULL;
+ }
+
if (rulesopt != NULL)
if (pfctl_rules(dev, rulesopt, opts))
error = 1;
@@ -1452,6 +1486,10 @@ main(int argc, char *argv[])
pfctl_show_rules(dev, opts, 1);
pfctl_show_timeouts(dev);
pfctl_show_limits(dev);
+ pfctl_show_tables(opts);
+ break;
+ case 'T':
+ pfctl_show_tables(opts);
break;
default:
warnx("Unknown show modifier '%s'", showopt);
diff --git a/sbin/pfctl/pfctl_radix.c b/sbin/pfctl/pfctl_radix.c
new file mode 100644
index 00000000000..d84cb433c7b
--- /dev/null
+++ b/sbin/pfctl/pfctl_radix.c
@@ -0,0 +1,378 @@
+/* $OpenBSD: pfctl_radix.c,v 1.1 2003/01/03 21:37:44 cedric Exp $ */
+
+/*
+ * Copyright (c) 2002 Cedric Berger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "pfctl_radix.h"
+
+#define RETURN_EINVAL \
+ do { \
+ errno = EINVAL; \
+ return (-1); \
+ } while (0)
+
+static int _pfr_dev = -1;
+
+static int
+_pfr_ioctl(unsigned long op, void *buf)
+{
+ if (_pfr_dev < 0)
+ return (_pfr_dev);
+ return (ioctl(_pfr_dev, op, buf));
+}
+
+void
+pfr_set_fd(int fd)
+{
+ _pfr_dev = fd;
+}
+
+int
+pfr_get_fd(void)
+{
+ return _pfr_dev;
+}
+
+int
+pfr_clr_tables(int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ if (_pfr_ioctl(DIOCRCLRTABLES, &io))
+ return (-1);
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ return (0);
+}
+
+int
+pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
+{
+ struct pfioc_table io;
+
+ if (size < 0 || (size && tbl == NULL))
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = tbl;
+ io.pfrio_size = size;
+ if (_pfr_ioctl(DIOCRADDTABLES, &io))
+ return (-1);
+ if (nadd != NULL)
+ *nadd = io.pfrio_nadd;
+ return (0);
+}
+
+int
+pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ if (size < 0 || (size && tbl == NULL))
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = tbl;
+ io.pfrio_size = size;
+ if (_pfr_ioctl(DIOCRDELTABLES, &io))
+ return (-1);
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ return (0);
+}
+
+int
+pfr_get_tables(struct pfr_table *tbl, int *size, int flags)
+{
+ struct pfioc_table io;
+
+ if (size == NULL || *size < 0 || (*size && tbl == NULL))
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = tbl;
+ io.pfrio_size = *size;
+ if (_pfr_ioctl(DIOCRGETTABLES, &io))
+ return (-1);
+ *size = io.pfrio_size;
+ return (0);
+}
+
+int
+pfr_get_tstats(struct pfr_tstats *tbl, int *size, int flags)
+{
+ struct pfioc_table io;
+
+ if (size == NULL || *size < 0 || (*size && tbl == NULL))
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = tbl;
+ io.pfrio_size = *size;
+ if (_pfr_ioctl(DIOCRGETTSTATS, &io))
+ return (-1);
+ *size = io.pfrio_size;
+ return (0);
+}
+
+int
+pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL)
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ if (_pfr_ioctl(DIOCRSETADDRS, &io))
+ return (-1);
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ return (0);
+}
+
+int
+pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *nadd, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL))
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_size = size;
+ if (_pfr_ioctl(DIOCRADDADDRS, &io))
+ return (-1);
+ if (nadd != NULL)
+ *nadd = io.pfrio_nadd;
+ return (0);
+}
+
+int
+pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL))
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_size = size;
+ if (_pfr_ioctl(DIOCRDELADDRS, &io))
+ return (-1);
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ return (0);
+}
+
+int
+pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *size2, int *nadd, int *ndel, int *nchange, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL))
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_size = size;
+ io.pfrio_size2 = (size2 != NULL) ? *size2 : 0;
+ if (_pfr_ioctl(DIOCRSETADDRS, &io))
+ return (-1);
+ if (nadd != NULL)
+ *nadd = io.pfrio_nadd;
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ if (nchange != NULL)
+ *nchange = io.pfrio_nchange;
+ if (size2 != NULL)
+ *size2 = io.pfrio_size2;
+ return (0);
+}
+
+int
+pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
+ int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size == NULL || *size < 0 || (*size && addr == NULL))
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_size = *size;
+ if (_pfr_ioctl(DIOCRGETADDRS, &io))
+ return (-1);
+ *size = io.pfrio_size;
+ return (0);
+}
+
+int
+pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
+ int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size == NULL || *size < 0 || (*size && addr == NULL))
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_size = *size;
+ if (_pfr_ioctl(DIOCRGETASTATS, &io))
+ return (-1);
+ *size = io.pfrio_size;
+ return (0);
+}
+
+int
+pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *nzero, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL))
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_size = size;
+ if (_pfr_ioctl(DIOCRCLRTSTATS, &io))
+ return (-1);
+ if (nzero != NULL)
+ *nzero = io.pfrio_nzero;
+ return (0);
+}
+
+int
+pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
+{
+ struct pfioc_table io;
+
+ if (size < 0 || (size && !tbl))
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = tbl;
+ io.pfrio_size = size;
+ if (_pfr_ioctl(DIOCRCLRTSTATS, &io))
+ return (-1);
+ if (nzero)
+ *nzero = io.pfrio_nzero;
+ return (0);
+}
+
+
+int
+pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *nmatch, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL))
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_size = size;
+ if (_pfr_ioctl(DIOCRTSTADDRS, &io))
+ return (-1);
+ if (nmatch)
+ *nmatch = io.pfrio_nmatch;
+ return (0);
+}
+
+int
+pfr_wrap_table(struct pfr_table *tbl, struct pf_addr_wrap *wrap,
+ int *exists, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL)
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = wrap;
+ io.pfrio_size = wrap ? 1 : 0;
+ io.pfrio_exists = exists ? 1 : 0;
+ if (_pfr_ioctl(DIOCRWRAPTABLE, &io))
+ return (-1);
+ if (exists)
+ *exists = io.pfrio_exists;
+ return (0);
+}
+
+int
+pfr_unwrap_table(struct pfr_table *tbl, struct pf_addr_wrap *wrap, int flags)
+{
+ struct pfioc_table io;
+
+ if (wrap == NULL)
+ RETURN_EINVAL;
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = wrap;
+ io.pfrio_size = 1;
+ if (_pfr_ioctl(DIOCRUNWRTABLE, &io))
+ return (-1);
+ if (tbl != NULL)
+ *tbl = io.pfrio_table;
+ return (0);
+}
diff --git a/sbin/pfctl/pfctl_radix.h b/sbin/pfctl/pfctl_radix.h
new file mode 100644
index 00000000000..084eb87b01d
--- /dev/null
+++ b/sbin/pfctl/pfctl_radix.h
@@ -0,0 +1,58 @@
+/* $OpenBSD: pfctl_radix.h,v 1.1 2003/01/03 21:37:44 cedric Exp $ */
+
+/*
+ * Copyright (c) 2002 Cedric Berger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _PFCTL_RADIX_H_
+#define _PFCTL_RADIX_H_
+
+#include <net/pfvar.h>
+
+void pfr_set_fd(int);
+int pfr_get_fd(void);
+int pfr_clr_tables(int *ndel, int);
+int pfr_add_tables(struct pfr_table *, int, int *, int);
+int pfr_del_tables(struct pfr_table *, int, int *, int);
+int pfr_get_tables(struct pfr_table *, int *, int);
+int pfr_get_tstats(struct pfr_tstats *, int *, int);
+int pfr_clr_tstats(struct pfr_table *, int, int *, int);
+int pfr_clr_addrs(struct pfr_table *, int *, int);
+int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
+int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
+int pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
+ int *, int *, int *, int);
+int pfr_get_addrs(struct pfr_table *, struct pfr_addr *, int *, int);
+int pfr_get_astats(struct pfr_table *, struct pfr_astats *, int *, int);
+int pfr_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *, int);
+int pfr_tst_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
+int pfr_wrap_table(struct pfr_table *, struct pf_addr_wrap *, int *, int);
+int pfr_unwrap_table(struct pfr_table *, struct pf_addr_wrap *, int);
+
+#endif /* _PFCTL_RADIX_H_ */
diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c
new file mode 100644
index 00000000000..00eb8f3a7dd
--- /dev/null
+++ b/sbin/pfctl/pfctl_table.c
@@ -0,0 +1,591 @@
+/* $OpenBSD: pfctl_table.c,v 1.1 2003/01/03 21:37:44 cedric Exp $ */
+
+/*
+ * Copyright (c) 2002 Cedric Berger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <errno.h>
+#include <time.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "pfctl_table.h"
+#include "pfctl_radix.h"
+#include "pfctl_parser.h"
+#include "pf_print_state.h"
+
+
+#define _BUF_SIZE 256
+
+extern void usage(void);
+static int _pfctl_table(int, char *[], char *, char *, char *, int);
+static void _grow_buffer(int, int);
+static void _print_table(struct pfr_table *);
+static void _print_tstats(struct pfr_tstats *);
+static void _load_addr(int, char *[], char *, int);
+static int _next_token(char [_BUF_SIZE], FILE *);
+static void _append_addr(char *, int);
+static void _print_addr(struct pfr_addr *, struct pfr_addr *, int);
+static void _print_astats(struct pfr_astats *, int);
+static void _perror(void);
+
+
+static union {
+ caddr_t caddr;
+ struct pfr_table *tables;
+ struct pfr_addr *addrs;
+ struct pfr_tstats *tstats;
+ struct pfr_astats *astats;
+} buffer, buffer2;
+
+static int size, msize;
+extern char *__progname;
+
+static char *commands[] = {
+ "-F", /* pfctl -F tables: flush all tables */
+ "-s", /* pfctl -s tables: show all tables */
+ "create", /* create a new table */
+ "kill", /* kill a table */
+ "flush", /* flush all addresses of a table */
+ "add", /* add one or more addresses in a table */
+ "delete", /* delete one or more addresses from a table */
+ "replace", /* replace the addresses of the table */
+ "show", /* show the content (addresses) of a table */
+ "test", /* test if the given addresses match a table */
+ "zero", /* clear all the statistics of a table */
+ NULL
+};
+
+static char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = {
+ { "In/Block:", "In/Pass:", "In/XPass:" },
+ { "Out/Block:", "Out/Pass:", "Out/XPass:" }
+};
+
+
+#define DUMMY ((flags & PFR_FLAG_DUMMY)?" (dummy)":"")
+#define RVTEST(fct) \
+ do { int rv = fct; if (rv) \
+ { _perror(); return (1); } \
+ } while (0)
+
+int
+pfctl_clear_tables(int opts)
+{
+ return _pfctl_table(0, NULL, NULL, "-F", NULL, opts);
+}
+
+int
+pfctl_show_tables(int opts)
+{
+ return _pfctl_table(0, NULL, NULL, "-s", NULL, opts);
+}
+
+int
+pfctl_command_tables(int argc, char *argv[], char *tname,
+ char *command, char *file, int opts)
+{
+ if (tname == NULL || command == NULL)
+ usage();
+ return _pfctl_table(argc, argv, tname, command, file, opts);
+}
+
+int
+_pfctl_table(int argc, char *argv[], char *tname, char *command,
+ char *file, int opts)
+{
+ struct pfr_table table;
+ char **p;
+ int nadd = 0, ndel = 0, nchange = 0, nzero = 0;
+ int i, flags = 0, nmatch = 0;
+
+ for (p = commands; *p != NULL; p++)
+ if (!strncmp(command, *p, strlen(command)))
+ break;
+ if (*p == NULL)
+ usage();
+ if (opts & PF_OPT_NOACTION)
+ flags |= PFR_FLAG_DUMMY;
+ bzero(&table, sizeof(table));
+ if (tname != NULL) {
+ if (strlen(tname) >= PF_TABLE_NAME_SIZE)
+ usage();
+ strlcpy(table.pfrt_name, tname, PF_TABLE_NAME_SIZE);
+ }
+ if (!strcmp(*p, "-F")) {
+ if (argc || file != NULL)
+ usage();
+ RVTEST(pfr_clr_tables(&ndel, flags));
+ if (!(opts & PF_OPT_QUIET))
+ fprintf(stderr, "%d tables deleted%s.\n", ndel,
+ DUMMY);
+ }
+ if (!strcmp(*p, "-s")) {
+ if (argc || file != NULL)
+ usage();
+ for (;;) {
+ if (opts & PF_OPT_VERBOSE) {
+ _grow_buffer(sizeof(struct pfr_tstats), size);
+ size = msize;
+ RVTEST(pfr_get_tstats(buffer.tstats, &size,
+ flags));
+ } else {
+ _grow_buffer(sizeof(struct pfr_table), size);
+ size = msize;
+ RVTEST(pfr_get_tables(buffer.tables, &size,
+ flags));
+ }
+ if (size <= msize)
+ break;
+ }
+ for (i = 0; i < size; i++)
+ if (opts & PF_OPT_VERBOSE)
+ _print_tstats(buffer.tstats+i);
+ else
+ _print_table(buffer.tables+i);
+ }
+ if (!strcmp(*p, "create")) {
+ if (argc || file != NULL)
+ usage();
+ RVTEST(pfr_add_tables(&table, 1, &nadd, flags));
+ if (!(opts & PF_OPT_QUIET))
+ fprintf(stderr, "%d table added%s.\n", nadd, DUMMY);
+ }
+ if (!strcmp(*p, "kill")) {
+ if (argc || file != NULL)
+ usage();
+ RVTEST(pfr_del_tables(&table, 1, &ndel, flags));
+ if (!(opts & PF_OPT_QUIET))
+ fprintf(stderr, "%d table deleted%s.\n", ndel, DUMMY);
+ }
+ if (!strcmp(*p, "flush")) {
+ if (argc || file != NULL)
+ usage();
+ RVTEST(pfr_clr_addrs(&table, &ndel, flags));
+ if (!(opts & PF_OPT_QUIET))
+ fprintf(stderr, "%d addresses deleted%s.\n", ndel,
+ DUMMY);
+ }
+ if (!strcmp(*p, "add")) {
+ _load_addr(argc, argv, file, 0);
+ if (opts & PF_OPT_VERBOSE)
+ flags |= PFR_FLAG_FEEDBACK;
+ RVTEST(pfr_add_addrs(&table, buffer.addrs, size, &nadd,
+ flags));
+ if (!(opts & PF_OPT_QUIET))
+ fprintf(stderr, "%d/%d addresses added%s.\n", nadd,
+ size, DUMMY);
+ if (opts & PF_OPT_VERBOSE)
+ for (i = 0; i < size; i++)
+ if ((opts & PF_OPT_VERBOSE2) ||
+ buffer.addrs[i].pfra_fback)
+ _print_addr(buffer.addrs+i, NULL,
+ opts & PF_OPT_USEDNS);
+ }
+ if (!strcmp(*p, "delete")) {
+ _load_addr(argc, argv, file, 0);
+ if (opts & PF_OPT_VERBOSE)
+ flags |= PFR_FLAG_FEEDBACK;
+ RVTEST(pfr_del_addrs(&table, buffer.addrs, size, &nadd,
+ flags));
+ if (!(opts & PF_OPT_QUIET))
+ fprintf(stderr, "%d/%d addresses deleted%s.\n", nadd,
+ size, DUMMY);
+ if (opts & PF_OPT_VERBOSE)
+ for (i = 0; i < size; i++)
+ if ((opts & PF_OPT_VERBOSE2) ||
+ buffer.addrs[i].pfra_fback)
+ _print_addr(buffer.addrs+i, NULL,
+ opts & PF_OPT_USEDNS);
+ }
+ if (!strcmp(*p, "replace")) {
+ _load_addr(argc, argv, file, 0);
+ if (opts & PF_OPT_VERBOSE)
+ flags |= PFR_FLAG_FEEDBACK;
+ for(;;) {
+ int size2 = msize;
+
+ RVTEST(pfr_set_addrs(&table, buffer.addrs, size,
+ &size2, &nadd, &ndel, &nchange, flags));
+ if (size2 <= msize) {
+ size = size2;
+ break;
+ } else
+ _grow_buffer(sizeof(struct pfr_addr), size2);
+ }
+ if (!(opts & PF_OPT_QUIET)) {
+ if (nadd)
+ fprintf(stderr, "%d addresses added%s.\n",
+ nadd, DUMMY);
+ if (ndel)
+ fprintf(stderr, "%d addresses deleted%s.\n",
+ ndel, DUMMY);
+ if (nchange)
+ fprintf(stderr, "%d addresses changed%s.\n",
+ nchange, DUMMY);
+ if (!nadd && !ndel && !nchange)
+ fprintf(stderr, "no changes%s.\n", DUMMY);
+ }
+ if (opts & PF_OPT_VERBOSE)
+ for (i = 0; i < size; i++)
+ if ((opts & PF_OPT_VERBOSE2) ||
+ buffer.addrs[i].pfra_fback)
+ _print_addr(buffer.addrs+i, NULL,
+ opts & PF_OPT_USEDNS);
+ }
+ if (!strcmp(*p, "show")) {
+ if (argc || file != NULL)
+ usage();
+ for (;;) {
+ if (opts & PF_OPT_VERBOSE) {
+ _grow_buffer(sizeof(struct pfr_astats), size);
+ size = msize;
+ RVTEST(pfr_get_astats(&table, buffer.astats,
+ &size, flags));
+ } else {
+ _grow_buffer(sizeof(struct pfr_addr), size);
+ size = msize;
+ RVTEST(pfr_get_addrs(&table, buffer.addrs,
+ &size, flags));
+ }
+ if (size <= msize)
+ break;
+ }
+ for (i = 0; i < size; i++)
+ if (opts & PF_OPT_VERBOSE) {
+ _print_astats(buffer.astats+i,
+ opts & PF_OPT_USEDNS);
+ } else {
+ _print_addr(buffer.addrs+i, NULL,
+ opts & PF_OPT_USEDNS);
+ }
+ }
+ if (!strcmp(*p, "test")) {
+ _load_addr(argc, argv, file, 1);
+ if (opts & PF_OPT_VERBOSE2) {
+ flags |= PFR_FLAG_REPLACE;
+ buffer2.caddr = calloc(sizeof(buffer.addrs[0]), size);
+ if (buffer2.caddr == NULL) {
+ _perror();
+ return 1;
+ }
+ memcpy(buffer2.addrs, buffer.addrs, size *
+ sizeof(buffer.addrs[0]));
+ }
+ RVTEST(pfr_tst_addrs(&table, buffer.addrs, size, &nmatch,
+ flags));
+ if (!(opts & PF_OPT_QUIET))
+ printf("%d/%d addresses match.\n", nmatch, size);
+ if (opts & PF_OPT_VERBOSE && !(opts & PF_OPT_VERBOSE2))
+ for (i = 0; i < size; i++)
+ if (buffer.addrs[i].pfra_fback == PFR_FB_MATCH)
+ _print_addr(buffer.addrs+i, NULL,
+ opts & PF_OPT_USEDNS);
+ if (opts & PF_OPT_VERBOSE2)
+ for (i = 0; i < size; i++)
+ _print_addr(buffer2.addrs+i, buffer.addrs+i,
+ opts & PF_OPT_USEDNS);
+ if (nmatch < size)
+ return (2);
+ }
+ if (!strcmp(*p, "zero")) {
+ if (argc || file != NULL)
+ usage();
+ flags |= PFR_FLAG_RECURSE;
+ RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags));
+ if (!(opts & PF_OPT_QUIET))
+ fprintf(stderr, "%d table/stats cleared%s.\n", nzero,
+ DUMMY);
+ }
+ return (0);
+}
+
+void
+_grow_buffer(int bs, int minsize)
+{
+ assert(minsize == 0 || minsize > msize);
+ if (!msize) {
+ msize = minsize;
+ if (msize < 64)
+ msize = 64;
+ buffer.caddr = calloc(bs, msize);
+ } else {
+ int omsize = msize;
+ if (minsize == 0)
+ msize *= 2;
+ else
+ msize = minsize;
+ buffer.caddr = realloc(buffer.caddr, msize * bs);
+ if (buffer.caddr)
+ bzero(buffer.caddr + omsize * bs, (msize-omsize) * bs);
+ }
+ if (!buffer.caddr) {
+ perror(__progname);
+ exit(1);
+ }
+}
+
+void
+_print_table(struct pfr_table *ta)
+{
+ printf("%s\n", ta->pfrt_name);
+}
+
+void
+_print_tstats(struct pfr_tstats *ts)
+{
+ time_t time = ts->pfrts_tzero;
+ int dir, op;
+
+ printf("%s\n", ts->pfrts_name);
+ printf("\tAddresses: %d\n", ts->pfrts_cnt);
+ printf("\tCleared: %s", ctime(&time));
+ printf("\tEvaluations: [ NoMatch: %-18llu Match: %-18llu ]\n",
+ ts->pfrts_nomatch, ts->pfrts_match);
+ for (dir = 0; dir < PFR_DIR_MAX; dir++)
+ for (op = 0; op < PFR_OP_TABLE_MAX; op++)
+ printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
+ stats_text[dir][op],
+ ts->pfrts_packets[dir][op],
+ ts->pfrts_bytes[dir][op]);
+}
+
+void
+_load_addr(int argc, char *argv[], char *file, int nonetwork)
+{
+ FILE *fp;
+ char buf[_BUF_SIZE];
+
+ while (argc--)
+ _append_addr(*argv++, nonetwork);
+ if (file == NULL)
+ return;
+ if (!strcmp(file, "-"))
+ fp = stdin;
+ else {
+ fp = fopen(file, "r");
+ if (fp == NULL) {
+ perror(__progname);
+ exit(1);
+ }
+ }
+ while (_next_token(buf, fp))
+ _append_addr(buf, nonetwork);
+ fclose(fp);
+}
+
+int
+_next_token(char buf[_BUF_SIZE], FILE *fp)
+{
+ static char _next_ch = ' ';
+ int i = 0;
+
+ for (;;) {
+ /* skip spaces */
+ while (isspace(_next_ch) && !feof(fp))
+ _next_ch = fgetc(fp);
+ /* remove from '#' until end of line */
+ if (_next_ch == '#')
+ while (!feof(fp)) {
+ _next_ch = fgetc(fp);
+ if (_next_ch == '\n')
+ break;
+ }
+ else
+ break;
+ }
+ if (feof(fp)) {
+ _next_ch = ' ';
+ return (0);
+ }
+ do {
+ if (i < _BUF_SIZE)
+ buf[i++] = _next_ch;
+ _next_ch = fgetc(fp);
+ } while (!feof(fp) && !isspace(_next_ch));
+ if (i >= _BUF_SIZE) {
+ fprintf(stderr, "%s: address too long (%d bytes)\n",
+ __progname, i);
+ exit(1);
+ }
+ buf[i] = '\0';
+ return (1);
+}
+
+void
+_append_addr(char *s, int test)
+{
+ char buf[_BUF_SIZE], *p, *q;
+ struct addrinfo *res, *ai, hints = { 0, 0, SOCK_DGRAM };
+ int not = (*s == '!'), net = -1, rv;
+
+ if (strlen(s) >= _BUF_SIZE) {
+ fprintf(stderr, "%s: address too long (%ld bytes)\n",
+ __progname, (long)strlen(s));
+ exit(1);
+ }
+ strlcpy(buf, s+not, sizeof(buf));
+ p = strrchr(buf, '/');
+ if (test && (not || p))
+ fprintf(stderr, "%s: illegal test address: \"%s\"\n",
+ __progname, s);
+ if (p) {
+ net = strtol(p+1, &q, 0);
+ if (!q || *q) {
+ fprintf(stderr, "%s: illegal network: \"%s\"\n",
+ __progname, p+1);
+ exit(1);
+ }
+ *p++ = '\0';
+ }
+ rv = getaddrinfo(buf, NULL, &hints, &res);
+ if (rv) {
+ fprintf(stderr, "%s: illegal address: \"%s\"\n", __progname,
+ buf);
+ exit(1);
+ }
+ for (ai = res; ai; ai = ai->ai_next) {
+ switch (ai->ai_family) {
+ case AF_INET:
+ if (net > 32) {
+ fprintf(stderr, "%s: network too big: %d\n",
+ __progname, net);
+ exit(1);
+ }
+ if (size >= msize)
+ _grow_buffer(sizeof(struct pfr_addr), 0);
+ buffer.addrs[size].pfra_ip4addr =
+ ((struct sockaddr_in *)ai->ai_addr)->sin_addr;
+ buffer.addrs[size].pfra_not = not;
+ buffer.addrs[size].pfra_net = (net >= 0) ? net : 32;
+ buffer.addrs[size].pfra_af = AF_INET;
+ size++;
+ break;
+ case AF_INET6:
+ if (net > 128) {
+ fprintf(stderr, "%s: network too big: %d\n",
+ __progname, net);
+ exit(1);
+ }
+ if (size >= msize)
+ _grow_buffer(sizeof(struct pfr_addr), 0);
+ buffer.addrs[size].pfra_ip6addr =
+ ((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
+ buffer.addrs[size].pfra_not = not;
+ buffer.addrs[size].pfra_net = (net >= 0) ? net : 128;
+ buffer.addrs[size].pfra_af = AF_INET6;
+ size++;
+ break;
+ }
+ }
+ freeaddrinfo(res);
+}
+
+void
+_print_addr(struct pfr_addr *ad, struct pfr_addr *rad, int dns)
+{
+ char buf[_BUF_SIZE] = "{error}";
+ const char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ' };
+ int fback, hostnet;
+
+ fback = (rad != NULL) ? rad->pfra_fback : ad->pfra_fback;
+ hostnet = (ad->pfra_af == AF_INET6) ? 128 : 32;
+ inet_ntop(ad->pfra_af, &ad->pfra_u, buf, sizeof(buf));
+ printf("%c %c%s", fb[fback], (ad->pfra_not?'!':' '), buf);
+ if (ad->pfra_net < hostnet)
+ printf("/%d", ad->pfra_net);
+ if (rad != NULL && fback != PFR_FB_NONE) {
+ strcpy(buf, "{error}");
+ inet_ntop(rad->pfra_af, &rad->pfra_u, buf, sizeof(buf));
+ printf("\t%c%s", (rad->pfra_not?'!':' '), buf);
+ if (rad->pfra_net < hostnet)
+ printf("/%d", rad->pfra_net);
+ }
+ if (rad != NULL && fback == PFR_FB_NONE)
+ printf("\t nomatch");
+ if (dns && ad->pfra_net == hostnet) {
+ char host[NI_MAXHOST] = "?";
+ union sockaddr_union sa;
+ int rv;
+
+ sa.sa.sa_len = (ad->pfra_af == AF_INET) ?
+ sizeof(sa.sin) : sizeof(sa.sin6);
+ sa.sa.sa_family = ad->pfra_af;
+ if (ad->pfra_af == AF_INET)
+ sa.sin.sin_addr = ad->pfra_ip4addr;
+ else
+ sa.sin6.sin6_addr = ad->pfra_ip6addr;
+ rv = getnameinfo(&sa.sa, sa.sa.sa_len, host, sizeof(host),
+ NULL, 0, NI_NAMEREQD);
+ if (!rv)
+ printf("\t(%s)", host);
+ }
+ printf("\n");
+}
+
+void
+_print_astats(struct pfr_astats *as, int dns)
+{
+ time_t time = as->pfras_tzero;
+ int dir, op;
+
+ _print_addr(&as->pfras_a, NULL, dns);
+ printf("\tCleared: %s", ctime(&time));
+ for (dir = 0; dir < PFR_DIR_MAX; dir++)
+ for (op = 0; op < PFR_OP_ADDR_MAX; op++)
+ printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
+ stats_text[dir][op],
+ as->pfras_packets[dir][op],
+ as->pfras_bytes[dir][op]);
+}
+
+void
+_perror(void)
+{
+ if (errno == ESRCH)
+ fprintf(stderr, "%s: Table does not exist.\n", __progname);
+ else
+ perror(__progname);
+}
diff --git a/sbin/pfctl/pfctl_table.h b/sbin/pfctl/pfctl_table.h
new file mode 100644
index 00000000000..650438271cc
--- /dev/null
+++ b/sbin/pfctl/pfctl_table.h
@@ -0,0 +1,42 @@
+/* $OpenBSD: pfctl_table.h,v 1.1 2003/01/03 21:37:44 cedric Exp $ */
+
+/*
+ * Copyright (c) 2002 Cedric Berger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _PFCTL_TABLE_H_
+#define _PFCTL_TABLE_H_
+
+#include <net/pfvar.h>
+
+int pfctl_clear_tables(int);
+int pfctl_show_tables(int);
+int pfctl_command_tables(int, char *[], char *, char *, char *, int);
+
+#endif /* _PFCTL_TABLE_H_ */