summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/pfctl/parse.y48
-rw-r--r--sbin/pfctl/pfctl.85
-rw-r--r--sbin/pfctl/pfctl.c18
-rw-r--r--sbin/pfctl/pfctl.h7
-rw-r--r--sbin/pfctl/pfctl_parser.h9
-rw-r--r--sbin/pfctl/pfctl_radix.c84
-rw-r--r--sbin/pfctl/pfctl_table.c114
-rw-r--r--share/man/man4/pf.460
-rw-r--r--share/man/man5/pf.conf.581
-rw-r--r--sys/net/pf.c11
-rw-r--r--sys/net/pf_ioctl.c38
-rw-r--r--sys/net/pf_table.c649
-rw-r--r--sys/net/pfvar.h38
-rw-r--r--usr.sbin/authpf/authpf.c12
14 files changed, 922 insertions, 252 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 36bd1521efa..085d2d88498 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.282 2003/01/08 19:47:37 deraadt Exp $ */
+/* $OpenBSD: parse.y,v 1.283 2003/01/09 10:40:44 cedric Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -377,7 +377,7 @@ typedef struct {
%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
%token MINTTL ERROR ALLOWOPTS FASTROUTE ROUTETO DUPTO REPLYTO NO LABEL
-%token NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP
+%token NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
%token FRAGNORM FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY
%token REQUIREORDER YES
@@ -390,7 +390,7 @@ typedef struct {
%token <v.i> PORTUNARY PORTBINARY
%type <v.interface> interface if_list if_item_not if_item
%type <v.number> number port icmptype icmp6type uid gid
-%type <v.number> tos
+%type <v.number> tos tableopts tableinit
%type <v.i> no dir log af fragcache
%type <v.i> staticport
%type <v.b> action flags flag blockspec
@@ -440,6 +440,7 @@ ruleset : /* empty */
| ruleset queuespec '\n'
| ruleset varset '\n'
| ruleset antispoof '\n'
+ | ruleset tabledef '\n'
| ruleset error '\n' { errors++; }
;
@@ -776,6 +777,46 @@ antispoof_iflst : if_item { $$ = $1; }
}
;
+tabledef : TABLE PORTUNARY STRING PORTUNARY tableopts tableinit {
+ if ($2 != PF_OP_LT || $4 != PF_OP_GT)
+ YYERROR;
+ if (strlen($3) >= PF_TABLE_NAME_SIZE)
+ YYERROR;
+ pfctl_define_table($3, $5, $6);
+ }
+ ;
+
+tableopts : /* empty */ { $$ = 0; }
+ | tableopts STRING {
+ $$ = $1;
+ if (!strcmp($2, "const"))
+ $$ |= PFR_TFLAG_CONST;
+ else if (!strcmp($2, "persist"))
+ $$ |= PFR_TFLAG_PERSIST;
+ else
+ YYERROR;
+ }
+
+tableinit : /* empty */ { $$ = 0; }
+ | '{' tableaddrs '}' { $$ = 1; }
+
+tableaddrs : /* empty */
+ | tableaddrs tableaddr comma
+
+tableaddr : STRING {
+ pfctl_append_addr($1, -1, 0);
+ }
+ | STRING '/' number {
+ pfctl_append_addr($1, $3, 0);
+ }
+ | '!' STRING {
+ pfctl_append_addr($2, -1, 1);
+ }
+ | '!' STRING '/' number {
+ pfctl_append_addr($2, $4, 1);
+ }
+ ;
+
altqif : ALTQ interface queue_opts QUEUE qassign {
struct pf_altq a;
@@ -3529,6 +3570,7 @@ lookup(char *s)
{ "set", SET},
{ "source-hash", SOURCEHASH},
{ "state", STATE},
+ { "table", TABLE},
{ "tbrsize", TBRSIZE},
{ "timeout", TIMEOUT},
{ "to", TO},
diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8
index e77dd31c123..cf1865803ff 100644
--- a/sbin/pfctl/pfctl.8
+++ b/sbin/pfctl/pfctl.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: pfctl.8,v 1.61 2003/01/03 21:37:44 cedric Exp $
+.\" $OpenBSD: pfctl.8,v 1.62 2003/01/09 10:40:44 cedric Exp $
.\"
.\" Copyright (c) 2001 Kjell Wooding. All rights reserved.
.\"
@@ -231,6 +231,9 @@ Show the content (addresses) of a table.
Test if the given addresses match a table.
.It Fl T Ar zero
Clear all the statistics of a table.
+.It Fl T Ar load
+Load only the table definitions from pf.conf.
+Used in "pfctl -Tl -f pf.conf".
.El
.It Fl v
Produce more verbose output. A second use of
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index f7a9c2a138e..3e673c6a8cb 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl.c,v 1.125 2003/01/07 01:04:33 henning Exp $ */
+/* $OpenBSD: pfctl.c,v 1.126 2003/01/09 10:40:44 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -974,7 +974,7 @@ pfctl_rules(int dev, char *filename, int opts)
if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_FILTER]))
err(1, "DIOCBEGINRULES");
}
-
+ pfctl_begin_table();
}
/* fill in callback data */
pf.dev = dev;
@@ -1013,6 +1013,7 @@ pfctl_rules(int dev, char *filename, int opts)
if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_FILTER]))
err(1, "DIOCCOMMITRULES");
}
+ pfctl_commit_table();
#if 0
if ((opts & PF_OPT_QUIET) == 0) {
fprintf(stderr, "%u nat entries loaded\n", n);
@@ -1340,10 +1341,15 @@ main(int argc, char *argv[])
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;
+ if (ch == 'l') {
+ loadopt = PFCTL_FLAG_TABLE;
+ tblcmdopt = NULL;
+ } else {
+ 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]);
diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h
index 8111f407405..0d6f1f3161b 100644
--- a/sbin/pfctl/pfctl.h
+++ b/sbin/pfctl/pfctl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl.h,v 1.3 2003/01/07 00:21:08 dhartmei Exp $ */
+/* $OpenBSD: pfctl.h,v 1.4 2003/01/09 10:40:44 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -50,6 +50,11 @@ 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_set_tflags(struct pfr_table *, int, int, int, int *, int *, int);
+int pfr_ina_begin(int *, int *, int);
+int pfr_ina_commit(int, int *, int *, int);
+int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *,
+ int *, int, int);
int pfctl_clear_tables(int);
int pfctl_show_tables(int);
int pfctl_command_tables(int, char *[], char *, char *, char *, int);
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index 8be11417b38..07fd09c1c24 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.h,v 1.38 2003/01/04 00:01:34 deraadt Exp $ */
+/* $OpenBSD: pfctl_parser.h,v 1.39 2003/01/09 10:40:44 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -88,6 +88,11 @@ void print_status(struct pf_status *);
int eval_pfaltq(struct pfctl *, struct pf_altq *, u_int32_t, u_int16_t);
int eval_pfqueue(struct pfctl *, struct pf_altq *, u_int32_t, u_int16_t);
+void pfctl_begin_table(void);
+void pfctl_append_addr(char *, int, int);
+void pfctl_define_table(char *, int, int);
+void pfctl_commit_table(void);
+
struct icmptypeent {
char *name;
u_int8_t type;
@@ -114,7 +119,9 @@ struct pf_timeout {
#define PFCTL_FLAG_NAT 0x04
#define PFCTL_FLAG_OPTION 0x08
#define PFCTL_FLAG_ALTQ 0x10
+#define PFCTL_FLAG_TABLE 0x20
extern const struct pf_timeout pf_timeouts[];
+extern int loadopt;
#endif /* _PFCTL_PARSER_H_ */
diff --git a/sbin/pfctl/pfctl_radix.c b/sbin/pfctl/pfctl_radix.c
index d5fdb825dac..c8ed2c7a8e3 100644
--- a/sbin/pfctl/pfctl_radix.c
+++ b/sbin/pfctl/pfctl_radix.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_radix.c,v 1.7 2003/01/07 00:21:08 dhartmei Exp $ */
+/* $OpenBSD: pfctl_radix.c,v 1.8 2003/01/09 10:40:44 cedric Exp $ */
/*
* Copyright (c) 2002 Cedric Berger
@@ -315,6 +315,30 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
return (0);
}
+int
+pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
+ int *nchange, int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ if (size < 0 || (size && !tbl)) {
+ errno = EINVAL;
+ return -1;
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = tbl;
+ io.pfrio_size = size;
+ io.pfrio_setflag = setflag;
+ io.pfrio_clrflag = clrflag;
+ if (ioctl(dev, DIOCRCLRTSTATS, &io))
+ return (-1);
+ if (nchange)
+ *nchange = io.pfrio_nchange;
+ if (ndel)
+ *ndel = io.pfrio_ndel;
+ return (0);
+}
int
pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
@@ -337,3 +361,61 @@ pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
*nmatch = io.pfrio_nmatch;
return (0);
}
+
+int
+pfr_ina_begin(int *ticket, int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ if (ioctl(dev, DIOCRINABEGIN, &io))
+ return (-1);
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ if (ticket != NULL)
+ *ticket = io.pfrio_ticket;
+ return (0);
+}
+
+int
+pfr_ina_commit(int ticket, int *nadd, int *nchange, int flags)
+{
+ struct pfioc_table io;
+
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_ticket = ticket;
+ if (ioctl(dev, DIOCRINACOMMIT, &io))
+ return (-1);
+ if (nadd != NULL)
+ *nadd = io.pfrio_nadd;
+ if (nchange != NULL)
+ *nchange = io.pfrio_nchange;
+ return (0);
+}
+
+int
+pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *nadd, int *naddr, int ticket, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL)) {
+ errno = EINVAL;
+ return -1;
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_size = size;
+ io.pfrio_ticket = ticket;
+ if (ioctl(dev, DIOCRINADEFINE, &io))
+ return (-1);
+ if (nadd != NULL)
+ *nadd = io.pfrio_nadd;
+ if (naddr != NULL)
+ *naddr = io.pfrio_naddr;
+ return (0);
+}
diff --git a/sbin/pfctl/pfctl_table.c b/sbin/pfctl/pfctl_table.c
index 9957718b181..9100aab7c6b 100644
--- a/sbin/pfctl/pfctl_table.c
+++ b/sbin/pfctl/pfctl_table.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_table.c,v 1.12 2003/01/07 00:21:08 dhartmei Exp $ */
+/* $OpenBSD: pfctl_table.c,v 1.13 2003/01/09 10:40:44 cedric Exp $ */
/*
* Copyright (c) 2002 Cedric Berger
@@ -68,7 +68,7 @@ static void append_addr(char *, int);
static void print_addrx(struct pfr_addr *, struct pfr_addr *, int);
static void print_astats(struct pfr_astats *, int);
static void radix_perror(void);
-
+static void inactive_cleanup(void);
static union {
caddr_t caddr;
@@ -78,7 +78,7 @@ static union {
struct pfr_astats *astats;
} buffer, buffer2;
-static int size, msize;
+static int size, msize, ticket, inactive;
extern char *__progname;
static char *commands[] = {
@@ -165,7 +165,7 @@ pfctl_table(int argc, char *argv[], char *tname, char *command,
if (argc || file != NULL)
usage();
for (;;) {
- if (opts & PF_OPT_VERBOSE) {
+ if (opts & PF_OPT_VERBOSE2) {
grow_buffer(sizeof(struct pfr_tstats), size);
size = msize;
RVTEST(pfr_get_tstats(buffer.tstats, &size,
@@ -180,15 +180,16 @@ pfctl_table(int argc, char *argv[], char *tname, char *command,
break;
}
for (i = 0; i < size; i++)
- if (opts & PF_OPT_VERBOSE)
+ if (opts & PF_OPT_VERBOSE2)
print_tstats(buffer.tstats+i,
- opts & PF_OPT_VERBOSE2);
+ opts & PF_OPT_VERBOSE);
else
print_table(buffer.tables+i,
- opts & PF_OPT_VERBOSE2);
+ opts & PF_OPT_VERBOSE);
} else if (!strcmp(*p, "create")) {
if (argc || file != NULL)
usage();
+ table.pfrt_flags = PFR_TFLAG_PERSIST;
RVTEST(pfr_add_tables(&table, 1, &nadd, flags));
if (!(opts & PF_OPT_QUIET))
fprintf(stderr, "%d table added%s.\n", nadd, DUMMY);
@@ -239,7 +240,7 @@ pfctl_table(int argc, char *argv[], char *tname, char *command,
load_addr(argc, argv, file, 0);
if (opts & PF_OPT_VERBOSE)
flags |= PFR_FLAG_FEEDBACK;
- for(;;) {
+ for (;;) {
int size2 = msize;
RVTEST(pfr_set_addrs(&table, buffer.addrs, size,
@@ -325,7 +326,7 @@ pfctl_table(int argc, char *argv[], char *tname, char *command,
} else if (!strcmp(*p, "zero")) {
if (argc || file != NULL)
usage();
- flags |= PFR_FLAG_RECURSE;
+ flags |= PFR_FLAG_ADDRSTOO;
RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags));
if (!(opts & PF_OPT_QUIET))
fprintf(stderr, "%d table/stats cleared%s.\n", nzero,
@@ -364,8 +365,16 @@ print_table(struct pfr_table *ta, int all)
{
if (!all && !(ta->pfrt_flags & PFR_TFLAG_ACTIVE))
return;
- printf(" %c%s\n", (ta->pfrt_flags & PFR_TFLAG_PERSIST)?'+':' ',
- ta->pfrt_name);
+ if (all) {
+ printf("%c%c%c%c%c\t%s\n",
+ (ta->pfrt_flags & PFR_TFLAG_CONST) ? 'c' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_PERSIST) ? 'p' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_ACTIVE) ? 'a' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_INACTIVE) ? 'i' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_REFERENCED) ? 'r' : '-',
+ ta->pfrt_name);
+ } else
+ puts(ta->pfrt_name);
}
void
@@ -590,3 +599,86 @@ radix_perror(void)
else
perror(__progname);
}
+
+void pfctl_begin_table(void)
+{
+ static int hookreg;
+ int rv;
+
+ if ((loadopt & (PFCTL_FLAG_TABLE | PFCTL_FLAG_ALL)) == 0)
+ return;
+ rv = pfr_ina_begin(&ticket, NULL, 0);
+ if (rv) {
+ radix_perror();
+ exit(1);
+ }
+ if (!hookreg) {
+ atexit(inactive_cleanup);
+ hookreg = 1;
+ }
+}
+
+void pfctl_append_addr(char *addr, int net, int neg)
+{
+ char *p = NULL;
+
+ if (net < 0 && !neg) {
+ append_addr(addr, 0);
+ return;
+ }
+ if (net >= 0 && !neg)
+ asprintf(&p, "%s/%d", addr, net);
+ else if (net < 0)
+ asprintf(&p, "!%s", addr);
+ else
+ asprintf(&p, "!%s/%d", addr, net);
+ if (p == NULL) {
+ radix_perror();
+ exit(1);
+ }
+ append_addr(p, 0);
+ free(p);
+}
+
+void pfctl_define_table(char *name, int flags, int addrs)
+{
+ struct pfr_table tbl;
+ int rv;
+
+ if ((loadopt & (PFCTL_FLAG_TABLE | PFCTL_FLAG_ALL)) == 0) {
+ size = 0;
+ return;
+ }
+ bzero(&tbl, sizeof(tbl));
+ strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name));
+ tbl.pfrt_flags = flags;
+
+ inactive = 1;
+ rv = pfr_ina_define(&tbl, buffer.addrs, size, NULL, NULL, ticket,
+ addrs ? PFR_FLAG_ADDRSTOO : 0);
+ if (rv) {
+ radix_perror();
+ exit(1);
+ }
+ size = 0;
+}
+
+void pfctl_commit_table(void)
+{
+ int rv;
+
+ if ((loadopt & (PFCTL_FLAG_TABLE | PFCTL_FLAG_ALL)) == 0)
+ return;
+ rv = pfr_ina_commit(ticket, NULL, NULL, 0);
+ if (rv) {
+ radix_perror();
+ exit(1);
+ }
+ inactive = 0;
+}
+
+void inactive_cleanup(void)
+{
+ if (inactive)
+ pfr_ina_begin(NULL, NULL, 0);
+}
diff --git a/share/man/man4/pf.4 b/share/man/man4/pf.4
index e62ddc10572..69c8bf460c7 100644
--- a/share/man/man4/pf.4
+++ b/share/man/man4/pf.4
@@ -1,4 +1,4 @@
-.\" $OpenBSD: pf.4,v 1.25 2002/12/29 20:07:34 cedric Exp $
+.\" $OpenBSD: pf.4,v 1.26 2003/01/09 10:40:44 cedric Exp $
.\"
.\" Copyright (C) 2001, Kjell Wooding. All rights reserved.
.\"
@@ -377,9 +377,14 @@ struct pfioc_table {
int pfrio_ndel;
int pfrio_nchange;
int pfrio_flags;
+ int pfrio_ticket;
};
#define pfrio_exists pfrio_nadd
#define pfrio_nzero pfrio_nadd
+#define pfrio_nmatch pfrio_nadd
+#define pfrio_naddr pfrio_size2
+#define pfrio_setflag pfrio_size2
+#define pfrio_clrflag pfrio_nadd
.Ed
.It Dv DIOCRADDTABLES Fa "struct pfioc_table"
Creates one or more tables.
@@ -412,12 +417,12 @@ Add one or more addresses to a table.
On entry, pfrio_table contain the table id and pfrio_buffer[pfrio_size]
contains the list of pfr_addr structures to add.
On exit, pfrio_nadd contains the number of addresses effectively added.
-.It Dv DIOCRDELTABLES Fa "struct pfioc_table"
+.It Dv DIOCRDELADDRS Fa "struct pfioc_table"
Delete one or more addresses from a table.
On entry, pfrio_table contain the table id and pfrio_buffer[pfrio_size]
contains the list of pfr_addr structures to delete.
On exit, pfrio_ndel contains the number of addresses effectively deleted.
-.It Dv DIOCRSETTABLES Fa "struct pfioc_table"
+.It Dv DIOCRSETADDRS Fa "struct pfioc_table"
Replace the content of a table by a new address list.
This is the most complicated command, which uses all the structure members.
On entry, pfrio_table contain the table id and pfrio_buffer[pfrio_size]
@@ -450,22 +455,39 @@ On entry, pfrio_table contain the table id and pfrio_buffer[pfrio_size]
contains a table of pfr_addr structures to test.
On exit, the kernel update the pfr_addr table by setting the pfra_fback
member appropriately.
-.It Dv DIOCRWRAPTABLE Fa "struct pfioc_table"
-Compute the SHA1 hash of a table and pack it into a pf_addr_wrap structure,
-along with a magic mask in the first word of the mask.
-On entry, pfrio_table contain the table id, and pfrio_buffer[pfrio_size]
-should contain a buffer large enough to contain one pf_addr_wrap structure.
-If the kernel should check if the table exists, then pfrio_exists must be
-set to a nonzero value.
-On exit, the kernel fill the pf_addr_wrap structure and set pfrio_exists
-if that flag was requested.
-.It Dv DIOCRUNWRTABLE Fa "struct pfioc_table"
-Do the opposite of
-.Dv DIOCRWRAPTABLE, and lookup a table from its hash value.
-On entry, pfrio_buffer[pfrio_size] should point to a pf_addr_wrap structure
-(a one-entry table).
-On exit, the kernel fills pfrio_table or returns ENOENT if it cannot find
-the matching table.
+.It Dv DIOCRSETTFLAGS Fa "struct pfioc_table"
+Change the
+.Va const
+or
+.Va persist
+flag of a table.
+On entry, pfrio_buffer[pfrio_size] contains a table of pfr_table structures,
+and pfrio_setflag contain the flags to add, while pfrio_clrflag the flags to
+remove.
+On exit, pfrio_nchange and pfrio_ndel contains the number of tables altered
+or deleted by the kernel. Yes, tables can be deleted if one remove the
+.Va persist
+flag of an unreferenced table.
+.It Dv DIOCRINABEGIN Fa "struct pfioc_table"
+Starts a transaction with the inactive set of tables. Cleans up any leftover
+from a previous aborted transaction, and returns a new ticket.
+On exit, pfrio_ndel contains the number of leftover table deleted, and
+pfrio_ticket contain a valid ticket to use for the following two IOCTLs.
+.It Dv DIOCRINACOMMIT Fa "struct pfioc_table"
+Commit the inactive set of tables into the active set. While copying the
+addresses, do a best effort to keep statistics for addresses present before
+and after the commit.
+On entry, io->pfrio_ticket takes a valid ticket.
+On exit, io->pfrio_nadd and io->pfrio_nchange contains the number of tables
+added and altered by the commit operation.
+.It Dv DIOCRINADEFINE Fa "struct pfioc_table"
+Defines a table in the inactive set.
+On entry, pfrio_table contain the table id and pfrio_buffer[pfrio_size]
+contains the list of pfr_addr structures to put in the table. A valid ticket
+must also be supplied to pfrio_ticket.
+On exit, pfrio_nadd contains 0 if the table was already defined in the
+inactive list, or 1 if a new table has been created. pfrio_naddr contains
+the number of addresses effectively put in the table.
.El
.Sh EXAMPLES
The following example demonstrates how to use the DIOCNATLOOK command
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
index 761b6a80997..ebd120a5ce0 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.162 2002/12/30 23:58:46 mcbride Exp $
+.\" $OpenBSD: pf.conf.5,v 1.163 2003/01/09 10:40:44 cedric Exp $
.\"
.\" Copyright (c) 2002, Daniel Hartmeier
.\" All rights reserved.
@@ -40,7 +40,7 @@ packet filter modifies, drops or passes packets according to rules or
definitions specified in
.Nm pf.conf .
.Pp
-There are six types of statement in
+There are seven types of statement in
.Nm pf.conf :
.Bl -tag -width xxxx
.It Macros
@@ -59,6 +59,10 @@ other addresses.
.It Packet Filtering
Stateful and stateless packet filtering provides rule-based blocking or
passing of packets.
+.It Table Definition
+Radix tables provide an effective way to match the source or destination
+address of packets against big and changing collections of addresses and
+CIDR networks.
.El
.Pp
The types of statement should be grouped and appear in
@@ -724,11 +728,13 @@ addresses and ports.
Addresses can be specified in CIDR notation (matching netblocks), as
symbolic host names or interface names, or as any of the following keywords:
.Pp
-.Bl -tag -width no-route -compact
+.Bl -tag -width "<table>" -compact
.It Pa any
Means any address.
.It Pa no-route
Means any address which is not currently routable.
+.It Pa <table>
+Means any address that matches the given table.
.El
.Pp
Host name resolution and interface to address translation are done at
@@ -1013,6 +1019,69 @@ option prevents
.Xr pf 4
from modifying the source port on tcp and udp packets.
.El
+.Sh TABLES
+Tables are named structures which can hold a collections of addresses and
+networks.
+Internally, they are implemented as PATRICIA trees, like the kernel routing
+table.
+Tables can be used as the source or destination of filter rules,
+.Pa scrub
+rules
+or
+.Pa nat
+rules where it makes sense.
+They cannot, however, be used for things like the redirect address of a
+.Pa rdr
+rule,
+.Pa dup-to
+construct or similar, as one would guess.
+.Pp
+Tables may be defined with the following two attributes:
+.Bl -tag -width persist
+.It Pa persist
+The
+.Pa persist
+flag inform the kernel that we want to keep the table even when no rule
+refer to that table.
+If that flag is not set, the kernel will automagically remove the table
+when the last rule refering to it is flushed.
+.It Pa const
+The
+.Pa const
+flag prevent the user to alter the content of the table once it has been
+created.
+Without that flag,
+.Xr pfctl 8
+can be used to add or remove addresses from the table at any time, even
+when running with
+.Xr securelevel 7
+= 2.
+.El
+.Pp
+Tables can be defined with any of the following
+.Xr pfctl 8
+mechanism:
+.Bl -tag -width "manually"
+.It Pa manually
+Persistant tables can be manually created with the
+.Pa create
+option of pfctl, before or after the ruleset has been loaded.
+.It Pa pf.conf
+Table definitions can be placed directly in this file, and loaded at the
+same time as other rules are loaded, atomically.
+Table definitions inside
+.Pa pf.conf
+use the
+.Pa table
+statement, and are especially useful to define non-persistant tables.
+The content of preexisting tables defined without initializer ('{' and '}')
+is not altered when (re-)loaded from
+.Pa pf.conf.
+.El
+.Pp
+When the resolver is called to add a hostname to a table,
+.Pa all
+resulting IP addresses are placed into the table, IPv4 as well as IPv6.
.Sh STATEFUL INSPECTION
.Xr pf 4
is a stateful packet filter, which means it can track the state of
@@ -1590,6 +1659,9 @@ rdr-rule = [ "no" ] "rdr" "on" ifspec [ af ] [ protospec ]
antispoof-rule = "antispoof" [ "log" ] [ "quick" ]
"for" ( interface-name | "{" interface-list "}" ) [ af ]
+table-rule = "table "<" tablename ">" [ "persist" ] [ "const" ]
+ [ "{" [ table-address [ "," ] ]* "}" ]
+
altq-rule = "altq" "on" interface-name queueopts-list
"queue" queue-list
queue-rule = "queue" string queueopts-list queue-list
@@ -1627,11 +1699,12 @@ hosts = "all" |
"{" host-list "}" ) [ port ]
ipspec = "any" | host | "{" host-list "}"
-host = [ "!" ] address [ "/" mask-bits ]
+host = [ "!" ] ( address [ "/" mask-bits ] | "<" table ">" )
redirhost = address [ "/" mask-bits ]
routehost = ( interface-name [ address [ "/" mask-bits ] ] )
address = ( interface-name | "(" interface-name ")" | host-name |
ipv4-dotted-quad | ipv6-coloned-hex )
+table-address = hostname | ipv4-dotted-quad | ipv6-coloned-hex
host-list = host [ [ "," ] host-list ]
redirhost-list = redirhost [ [","] redirhost-list ]
routehost-list = routehost [ [","] routehost-list ]
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 7bdc9617f99..cdb47e555eb 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.300 2003/01/07 00:21:07 dhartmei Exp $ */
+/* $OpenBSD: pf.c,v 1.301 2003/01/09 10:40:44 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -528,6 +528,15 @@ pf_tbladdr_remove(struct pf_addr_wrap *aw)
aw->p.tbl = NULL;
}
+void
+pf_tbladdr_copyout(struct pf_addr_wrap *aw)
+{
+ if (aw->type != PF_ADDR_TABLE || aw->p.tbl == NULL)
+ return;
+ aw->p.tblcnt = (aw->p.tbl->pfrkt_flags & PFR_TFLAG_ACTIVE) ?
+ aw->p.tbl->pfrkt_cnt : -1;
+}
+
int
pf_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
{
diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c
index 6f75f10f72c..d1c2e0fb39e 100644
--- a/sys/net/pf_ioctl.c
+++ b/sys/net/pf_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_ioctl.c,v 1.45 2003/01/07 00:21:07 dhartmei Exp $ */
+/* $OpenBSD: pf_ioctl.c,v 1.46 2003/01/09 10:40:44 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -706,6 +706,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
bcopy(rule, &pr->rule, sizeof(struct pf_rule));
pf_dynaddr_copyout(&pr->rule.src.addr);
pf_dynaddr_copyout(&pr->rule.dst.addr);
+ pf_tbladdr_copyout(&pr->rule.src.addr);
+ pf_tbladdr_copyout(&pr->rule.dst.addr);
for (i = 0; i < PF_SKIP_COUNT; ++i)
if (rule->skip[i].ptr == NULL)
pr->rule.skip[i].nr = -1;
@@ -1755,6 +1757,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
+ case DIOCRSETTFLAGS: {
+ struct pfioc_table *io = (struct pfioc_table *)addr;
+
+ error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size,
+ io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
+ &io->pfrio_nadd, io->pfrio_flags);
+ break;
+ }
+
case DIOCRCLRADDRS: {
struct pfioc_table *io = (struct pfioc_table *)addr;
@@ -1820,6 +1831,31 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
+ case DIOCRINABEGIN: {
+ struct pfioc_table *io = (struct pfioc_table *)addr;
+
+ error = pfr_ina_begin(&io->pfrio_ticket, &io->pfrio_ndel,
+ io->pfrio_flags);
+ break;
+ }
+
+ case DIOCRINACOMMIT: {
+ struct pfioc_table *io = (struct pfioc_table *)addr;
+
+ error = pfr_ina_commit(io->pfrio_ticket, &io->pfrio_nadd,
+ &io->pfrio_nchange, io->pfrio_flags);
+ break;
+ }
+
+ case DIOCRINADEFINE: {
+ struct pfioc_table *io = (struct pfioc_table *)addr;
+
+ error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer,
+ io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
+ io->pfrio_ticket, io->pfrio_flags);
+ break;
+ }
+
default:
error = ENODEV;
break;
diff --git a/sys/net/pf_table.c b/sys/net/pf_table.c
index b363bebeaca..ea5b037867a 100644
--- a/sys/net/pf_table.c
+++ b/sys/net/pf_table.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_table.c,v 1.15 2003/01/07 00:21:07 dhartmei Exp $ */
+/* $OpenBSD: pf_table.c,v 1.16 2003/01/09 10:40:44 cedric Exp $ */
/*
* Copyright (c) 2002 Cedric Berger
@@ -63,9 +63,17 @@
(sin6).sin6_addr = (addr); \
} while (0)
+#define SWAP(type, a1, a2) \
+ do { \
+ type tmp = a1; \
+ a1 = a2; \
+ a2 = tmp; \
+ } while (0)
+
#define AF_BITS(af) (((af)==AF_INET)?32:128)
#define ADDR_NETWORK(ad) ((ad)->pfra_net < AF_BITS((ad)->pfra_af))
#define KENTRY_NETWORK(ke) ((ke)->pfrke_net < AF_BITS((ke)->pfrke_af))
+#define NO_ADDRESSES (-1)
struct pfr_walktree {
enum pfrw_op {
@@ -94,35 +102,41 @@ struct pool pfr_kentry_pl;
struct sockaddr_in pfr_sin;
struct sockaddr_in6 pfr_sin6;
+void pfr_copyout_addr(struct pfr_addr *,
+ struct pfr_kentry *ke);
int pfr_validate_addr(struct pfr_addr *);
-int pfr_enqueue_addrs(struct pfr_ktable *,
- struct pfr_kentryworkq *, int *);
+void pfr_enqueue_addrs(struct pfr_ktable *,
+ struct pfr_kentryworkq *, int *, int);
+void pfr_mark_addrs(struct pfr_ktable *);
struct pfr_kentry *pfr_lookup_addr(struct pfr_ktable *,
struct pfr_addr *, int);
-struct pfr_kentry *pfr_create_kentry(struct pfr_addr *, long);
-void pfr_destroy_kentry(struct pfr_kentry *);
+struct pfr_kentry *pfr_create_kentry(struct pfr_addr *);
void pfr_destroy_kentries(struct pfr_kentryworkq *);
void pfr_insert_kentries(struct pfr_ktable *,
- struct pfr_kentryworkq *);
+ struct pfr_kentryworkq *, long);
void pfr_remove_kentries(struct pfr_ktable *,
struct pfr_kentryworkq *);
-void pfr_clstats_kentries(struct pfr_kentryworkq *, long);
+void pfr_clstats_kentries(struct pfr_kentryworkq *, long,
+ int);
void pfr_reset_feedback(struct pfr_addr *, int);
void pfr_prepare_network(union sockaddr_union *, int, int);
int pfr_route_kentry(struct pfr_ktable *,
struct pfr_kentry *);
int pfr_unroute_kentry(struct pfr_ktable *,
struct pfr_kentry *);
-void pfr_copyout_addr(struct pfr_addr *,
- struct pfr_kentry *);
int pfr_walktree(struct radix_node *, void *);
+void pfr_commit_ktable(struct pfr_ktable *, long);
void pfr_insert_ktables(struct pfr_ktableworkq *);
-void pfr_remove_ktables(struct pfr_ktableworkq *);
+void pfr_insert_ktable(struct pfr_ktable *);
+void pfr_setflags_ktables(struct pfr_ktableworkq *, int,
+ int);
+void pfr_setflags_ktable(struct pfr_ktable *, int, int);
void pfr_clstats_ktables(struct pfr_ktableworkq *, long,
int);
+void pfr_clstats_ktable(struct pfr_ktable *, long, int);
struct pfr_ktable *pfr_create_ktable(struct pfr_table *, long);
-void pfr_destroy_ktable(struct pfr_ktable *);
-void pfr_destroy_ktables(struct pfr_ktableworkq *);
+void pfr_destroy_ktables(struct pfr_ktableworkq *, int);
+void pfr_destroy_ktable(struct pfr_ktable *, int);
int pfr_ktable_compare(struct pfr_ktable *,
struct pfr_ktable *);
struct pfr_ktable *pfr_lookup_table(struct pfr_table *);
@@ -133,6 +147,7 @@ RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
struct pfr_ktablehead pfr_ktables;
struct pfr_table pfr_nulltable;
int pfr_ktable_cnt;
+int pfr_ticket;
void
pfr_initialize(void)
@@ -146,6 +161,8 @@ pfr_initialize(void)
pfr_sin.sin_family = AF_INET;
pfr_sin6.sin6_len = sizeof(pfr_sin6);
pfr_sin6.sin6_family = AF_INET6;
+
+ pfr_ticket = 100;
}
int
@@ -153,15 +170,15 @@ pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
{
struct pfr_ktable *kt;
struct pfr_kentryworkq workq;
- int s, rv;
+ int s;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
kt = pfr_lookup_table(tbl);
if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
return (ESRCH);
- rv = pfr_enqueue_addrs(kt, &workq, ndel);
- if (rv)
- return rv;
+ if (kt->pfrkt_flags & PFR_TFLAG_CONST)
+ return (EPERM);
+ pfr_enqueue_addrs(kt, &workq, ndel, 0);
if (!(flags & PFR_FLAG_DUMMY)) {
if (flags & PFR_FLAG_ATOMIC)
@@ -170,7 +187,8 @@ pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
if (flags & PFR_FLAG_ATOMIC)
splx(s);
if (kt->pfrkt_cnt) {
- printf("pfr_clr_addrs: corruption detected.");
+ printf("pfr_clr_addrs: corruption detected (%d).",
+ kt->pfrkt_cnt);
kt->pfrkt_cnt = 0;
}
}
@@ -192,6 +210,8 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
kt = pfr_lookup_table(tbl);
if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
return (ESRCH);
+ if (kt->pfrkt_flags & PFR_TFLAG_CONST)
+ return (EPERM);
tmpkt = pfr_create_ktable(&pfr_nulltable, 0);
if (tmpkt == NULL)
return (ENOMEM);
@@ -212,7 +232,7 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
if (q != NULL)
continue;
if (p == NULL) {
- p = pfr_create_kentry(&ad, tzero);
+ p = pfr_create_kentry(&ad);
if (p == NULL)
senderr(ENOMEM);
SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
@@ -224,19 +244,21 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
if (!(flags & PFR_FLAG_DUMMY)) {
if (flags & PFR_FLAG_ATOMIC)
s = splsoftnet();
- pfr_insert_kentries(kt, &workq);
+ pfr_insert_kentries(kt, &workq, tzero);
if (flags & PFR_FLAG_ATOMIC)
splx(s);
}
if (nadd != NULL)
*nadd = xadd;
+ if (tmpkt != NULL)
+ pfr_destroy_ktable(tmpkt, 0);
return (0);
_bad:
pfr_destroy_kentries(&workq);
if (flags & PFR_FLAG_FEEDBACK)
pfr_reset_feedback(addr, size);
if (tmpkt != NULL)
- pfr_destroy_ktable(tmpkt);
+ pfr_destroy_ktable(tmpkt, 0);
return (rv);
}
@@ -246,7 +268,6 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
{
struct pfr_ktable *kt;
struct pfr_kentryworkq workq;
- struct pfr_walktree w;
struct pfr_kentry *p;
struct pfr_addr ad;
int i, rv, s, xdel = 0;
@@ -255,15 +276,9 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
kt = pfr_lookup_table(tbl);
if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
return (ESRCH);
-
- bzero(&w, sizeof(w));
- w.pfrw_op = PFRW_MARK;
- rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
- if (!rv)
- rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
- if (rv)
- return (rv);
-
+ if (kt->pfrkt_flags & PFR_TFLAG_CONST)
+ return (EPERM);
+ pfr_mark_addrs(kt);
SLIST_INIT(&workq);
for (i = 0; i < size; i++) {
if (copyin(addr+i, &ad, sizeof(ad)))
@@ -308,7 +323,6 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
{
struct pfr_ktable *kt, *tmpkt;
struct pfr_kentryworkq addq, delq, changeq;
- struct pfr_walktree w;
struct pfr_kentry *p, *q;
struct pfr_addr ad;
int i, rv, s, xadd = 0, xdel = 0, xchange = 0;
@@ -318,18 +332,12 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
kt = pfr_lookup_table(tbl);
if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
return (ESRCH);
+ if (kt->pfrkt_flags & PFR_TFLAG_CONST)
+ return (EPERM);
tmpkt = pfr_create_ktable(&pfr_nulltable, 0);
if (tmpkt == NULL)
return (ENOMEM);
-
- bzero(&w, sizeof(w));
- w.pfrw_op = PFRW_MARK;
- rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
- if (!rv)
- rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
- if (rv)
- return (rv);
-
+ pfr_mark_addrs(kt);
SLIST_INIT(&addq);
SLIST_INIT(&delq);
SLIST_INIT(&changeq);
@@ -357,7 +365,7 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
ad.pfra_fback = PFR_FB_DUPLICATE;
goto _skip;
}
- p = pfr_create_kentry(&ad, tzero);
+ p = pfr_create_kentry(&ad);
if (p == NULL)
senderr(ENOMEM);
SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
@@ -370,14 +378,7 @@ _skip:
if (copyout(&ad, addr+i, sizeof(ad)))
senderr(EFAULT);
}
- w.pfrw_op = PFRW_SWEEP;
- w.pfrw_workq = &delq;
- rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
- if (!rv)
- rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
- if (rv)
- senderr(rv);
- xdel = w.pfrw_cnt;
+ pfr_enqueue_addrs(kt, &delq, &xdel, 1);
if ((flags & PFR_FLAG_FEEDBACK) && *size2) {
if (*size2 < size+xdel) {
*size2 = size+xdel;
@@ -395,11 +396,9 @@ _skip:
if (!(flags & PFR_FLAG_DUMMY)) {
if (flags & PFR_FLAG_ATOMIC)
s = splsoftnet();
- pfr_insert_kentries(kt, &addq);
+ pfr_insert_kentries(kt, &addq, tzero);
pfr_remove_kentries(kt, &delq);
- SLIST_FOREACH(p, &changeq, pfrke_workq)
- p->pfrke_not ^= 1;
- pfr_clstats_kentries(&changeq, time.tv_sec);
+ pfr_clstats_kentries(&changeq, tzero, 1);
if (flags & PFR_FLAG_ATOMIC)
splx(s);
}
@@ -411,13 +410,15 @@ _skip:
*nchange = xchange;
if ((flags & PFR_FLAG_FEEDBACK) && *size2)
*size2 = size+xdel;
+ if (tmpkt != NULL)
+ pfr_destroy_ktable(tmpkt, 0);
return (0);
_bad:
pfr_destroy_kentries(&addq);
if (flags & PFR_FLAG_FEEDBACK)
pfr_reset_feedback(addr, size);
if (tmpkt != NULL)
- pfr_destroy_ktable(tmpkt);
+ pfr_destroy_ktable(tmpkt, 0);
return (rv);
}
@@ -485,7 +486,8 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
return (rv);
if (w.pfrw_free) {
- printf("pfr_get_addrs: corruption detected.");
+ printf("pfr_get_addrs: corruption detected (%d).",
+ w.pfrw_free);
return (ENOTTY);
}
*size = kt->pfrkt_cnt;
@@ -521,10 +523,8 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
if (!rv)
rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
if (!rv && (flags & PFR_FLAG_CLSTATS)) {
- rv = pfr_enqueue_addrs(kt, &workq, NULL);
- if (rv)
- return rv;
- pfr_clstats_kentries(&workq, tzero);
+ pfr_enqueue_addrs(kt, &workq, NULL, 0);
+ pfr_clstats_kentries(&workq, tzero, 0);
}
if (flags & PFR_FLAG_ATOMIC)
splx(s);
@@ -532,7 +532,8 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
return (rv);
if (w.pfrw_free) {
- printf("pfr_get_astats: corruption detected.");
+ printf("pfr_get_astats: corruption detected (%d).",
+ w.pfrw_free);
return (ENOTTY);
}
*size = kt->pfrkt_cnt;
@@ -575,7 +576,7 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
if (!(flags & PFR_FLAG_DUMMY)) {
if (flags & PFR_FLAG_ATOMIC)
s = splsoftnet();
- pfr_clstats_kentries(&workq, 0);
+ pfr_clstats_kentries(&workq, 0, 0);
if (flags & PFR_FLAG_ATOMIC)
splx(s);
}
@@ -588,7 +589,6 @@ _bad:
return (rv);
}
-
int
pfr_validate_addr(struct pfr_addr *ad)
{
@@ -606,28 +606,40 @@ pfr_validate_addr(struct pfr_addr *ad)
}
}
-int
+void
pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq,
- int *naddr)
+ int *naddr, int sweep)
{
struct pfr_walktree w;
- int rv;
SLIST_INIT(workq);
bzero(&w, sizeof(w));
- w.pfrw_op = PFRW_ENQUEUE;
+ w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE;
w.pfrw_workq = workq;
- rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
- if (rv)
- return (rv);
- rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
- if (rv)
- return (rv);
+ if (kt->pfrkt_ip4 != NULL)
+ if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
+ printf("pfr_enqueue_addrs: IPv4 walktree failed.");
+ if (kt->pfrkt_ip6 != NULL)
+ if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
+ printf("pfr_enqueue_addrs: IPv6 walktree failed.");
if (naddr != NULL)
*naddr = w.pfrw_cnt;
- return (0);
}
+void
+pfr_mark_addrs(struct pfr_ktable *kt)
+{
+ struct pfr_walktree w;
+
+ bzero(&w, sizeof(w));
+ w.pfrw_op = PFRW_MARK;
+ if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
+ printf("pfr_mark_addrs: IPv4 walktree failed.");
+ if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
+ printf("pfr_mark_addrs: IPv6 walktree failed.");
+}
+
+
struct pfr_kentry *
pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact)
{
@@ -655,7 +667,7 @@ pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact)
}
struct pfr_kentry *
-pfr_create_kentry(struct pfr_addr *ad, long tzero)
+pfr_create_kentry(struct pfr_addr *ad)
{
struct pfr_kentry *ke;
@@ -671,31 +683,23 @@ pfr_create_kentry(struct pfr_addr *ad, long tzero)
ke->pfrke_af = ad->pfra_af;
ke->pfrke_net = ad->pfra_net;
ke->pfrke_not = ad->pfra_not;
- ke->pfrke_tzero = tzero;
return (ke);
}
void
-pfr_destroy_kentry(struct pfr_kentry *ke)
-{
- if (ke != NULL)
- pool_put(&pfr_kentry_pl, ke);
-}
-
-void
pfr_destroy_kentries(struct pfr_kentryworkq *workq)
{
struct pfr_kentry *p, *q;
for (p = SLIST_FIRST(workq); p != NULL; p = q) {
q = SLIST_NEXT(p, pfrke_workq);
- pfr_destroy_kentry(p);
+ pool_put(&pfr_kentry_pl, p);
}
}
void
pfr_insert_kentries(struct pfr_ktable *kt,
- struct pfr_kentryworkq *workq)
+ struct pfr_kentryworkq *workq, long tzero)
{
struct pfr_kentry *p;
int rv, n = 0;
@@ -707,6 +711,7 @@ pfr_insert_kentries(struct pfr_ktable *kt,
"(code=%d).\n", rv);
break;
}
+ p->pfrke_tzero = tzero;
n++;
}
kt->pfrkt_cnt += n;
@@ -728,13 +733,15 @@ pfr_remove_kentries(struct pfr_ktable *kt,
}
void
-pfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero)
+pfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero, int negchange)
{
struct pfr_kentry *p;
int s, n = 0;
SLIST_FOREACH(p, workq, pfrke_workq) {
s = splsoftnet();
+ if (negchange)
+ p->pfrke_not = !p->pfrke_not;
bzero(p->pfrke_packets, sizeof(p->pfrke_packets));
bzero(p->pfrke_bytes, sizeof(p->pfrke_bytes));
splx(s);
@@ -907,7 +914,6 @@ pfr_walktree(struct radix_node *rn, void *arg)
return (0);
}
-
int
pfr_clr_tables(int *ndel, int flags)
{
@@ -918,14 +924,15 @@ pfr_clr_tables(int *ndel, int flags)
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
SLIST_INIT(&workq);
RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
+ if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE))
+ continue;
SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
xdel++;
}
-
if (!(flags & PFR_FLAG_DUMMY)) {
if (flags & PFR_FLAG_ATOMIC)
s = splsoftnet();
- pfr_remove_ktables(&workq);
+ pfr_setflags_ktables(&workq, 0, PFR_TFLAG_ACTIVE);
if (flags & PFR_FLAG_ATOMIC)
splx(s);
}
@@ -937,78 +944,78 @@ pfr_clr_tables(int *ndel, int flags)
int
pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
{
- struct pfr_ktableworkq workq, changeq;
+ struct pfr_ktableworkq addq, changeq;
struct pfr_ktable *p, *q, key;
int i, rv, s, xadd = 0;
long tzero = time.tv_sec;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
- SLIST_INIT(&workq);
+ SLIST_INIT(&addq);
SLIST_INIT(&changeq);
for (i = 0; i < size; i++) {
if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
senderr(EFAULT);
if (key.pfrkt_name[PF_TABLE_NAME_SIZE-1])
senderr(EINVAL);
- key.pfrkt_flags = PFR_TFLAG_ACTIVE+PFR_TFLAG_PERSIST;
+ key.pfrkt_flags |= PFR_TFLAG_ACTIVE;
+ if (key.pfrkt_flags & ~(PFR_TFLAG_USRMASK+PFR_TFLAG_ACTIVE))
+ senderr(EINVAL);
p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
if (p == NULL) {
p = pfr_create_ktable(&key.pfrkt_t, tzero);
if (p == NULL)
senderr(ENOMEM);
- SLIST_FOREACH(q, &workq, pfrkt_workq) {
+ SLIST_FOREACH(q, &addq, pfrkt_workq) {
if (!strcmp(p->pfrkt_name, q->pfrkt_name))
goto _skip;
}
- SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
+ SLIST_INSERT_HEAD(&addq, p, pfrkt_workq);
xadd++;
- } else if (!(p->pfrkt_flags & PFR_TFLAG_PERSIST)) {
+ } else if (!(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
+ SLIST_FOREACH(q, &changeq, pfrkt_workq)
+ if (!strcmp(key.pfrkt_name, q->pfrkt_name))
+ goto _skip;
SLIST_INSERT_HEAD(&changeq, p, pfrkt_workq);
+ xadd++;
}
_skip:
}
if (!(flags & PFR_FLAG_DUMMY)) {
if (flags & PFR_FLAG_ATOMIC)
s = splsoftnet();
- pfr_insert_ktables(&workq);
- SLIST_FOREACH(p, &changeq, pfrkt_workq)
- p->pfrkt_flags |= PFR_TFLAG_PERSIST;
+ pfr_insert_ktables(&addq);
+ pfr_setflags_ktables(&changeq, PFR_TFLAG_ACTIVE, 0);
if (flags & PFR_FLAG_ATOMIC)
splx(s);
} else
- pfr_destroy_ktables(&workq);
+ pfr_destroy_ktables(&addq, 0);
if (nadd != NULL)
*nadd = xadd;
return (0);
_bad:
- pfr_destroy_ktables(&workq);
+ pfr_destroy_ktables(&addq, 0);
return (rv);
}
int
pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
{
- struct pfr_ktableworkq workq, changeq;
+ struct pfr_ktableworkq workq;
struct pfr_ktable *p, *q, key;
int i, s, xdel = 0;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
SLIST_INIT(&workq);
- SLIST_INIT(&changeq);
for (i = 0; i < size; i++) {
if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
return (EFAULT);
p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
- if (p != NULL) {
- struct pfr_ktableworkq *queue;
-
- queue = (p->pfrkt_refcnt > 0) ? &changeq : &workq;
- SLIST_FOREACH(q, queue, pfrkt_workq)
+ if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
+ SLIST_FOREACH(q, &workq, pfrkt_workq)
if (!strcmp(p->pfrkt_name, q->pfrkt_name))
goto _skip;
- SLIST_INSERT_HEAD(queue, p, pfrkt_workq);
- if (queue == &workq)
- xdel++;
+ SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
+ xdel++;
}
_skip:
}
@@ -1016,9 +1023,7 @@ _skip:
if (!(flags & PFR_FLAG_DUMMY)) {
if (flags & PFR_FLAG_ATOMIC)
s = splsoftnet();
- pfr_remove_ktables(&workq);
- SLIST_FOREACH(p, &changeq, pfrkt_workq)
- p->pfrkt_flags &= ~PFR_TFLAG_PERSIST;
+ pfr_setflags_ktables(&workq, 0, PFR_TFLAG_ACTIVE);
if (flags & PFR_FLAG_ATOMIC)
splx(s);
}
@@ -1045,7 +1050,7 @@ pfr_get_tables(struct pfr_table *tbl, int *size, int flags)
return (EFAULT);
}
if (n) {
- printf("pfr_get_tables: corruption detected.");
+ printf("pfr_get_tables: corruption detected (%d).", n);
return (ENOTTY);
}
*size = pfr_ktable_cnt;
@@ -1083,11 +1088,11 @@ pfr_get_tstats(struct pfr_tstats *tbl, int *size, int flags)
}
if (flags & PFR_FLAG_CLSTATS)
pfr_clstats_ktables(&workq, tzero,
- flags & PFR_FLAG_RECURSE);
+ flags & PFR_FLAG_ADDRSTOO);
if (flags & PFR_FLAG_ATOMIC)
splx(s);
if (n) {
- printf("pfr_get_tstats: corruption detected.");
+ printf("pfr_get_tstats: corruption detected (%d).", n);
return (ENOTTY);
}
*size = pfr_ktable_cnt;
@@ -1102,7 +1107,7 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
int i, s, xzero = 0;
long tzero = time.tv_sec;
- ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_CLSTATS+PFR_FLAG_RECURSE);
+ ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_CLSTATS+PFR_FLAG_ADDRSTOO);
SLIST_INIT(&workq);
for (i = 0; i < size; i++) {
if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
@@ -1113,11 +1118,10 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
xzero++;
}
}
-
if (!(flags & PFR_FLAG_DUMMY)) {
if (flags & PFR_FLAG_ATOMIC)
s = splsoftnet();
- pfr_clstats_ktables(&workq, tzero, flags & PFR_FLAG_RECURSE);
+ pfr_clstats_ktables(&workq, tzero, flags & PFR_FLAG_ADDRSTOO);
if (flags & PFR_FLAG_ATOMIC)
splx(s);
}
@@ -1126,58 +1130,328 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
return (0);
}
+int
+pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
+ int *nchange, int *ndel, int flags)
+{
+ struct pfr_ktableworkq workq;
+ struct pfr_ktable *p, *q, key;
+ int i, s, xchange = 0, xdel = 0;
+
+ ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
+ if ((setflag & ~PFR_TFLAG_USRMASK) ||
+ (clrflag & ~PFR_TFLAG_USRMASK) ||
+ (setflag & clrflag))
+ return (EINVAL);
+ SLIST_INIT(&workq);
+ for (i = 0; i < size; i++) {
+ if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
+ return (EFAULT);
+ p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
+ if (p != NULL && (p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
+ if (((p->pfrkt_flags & setflag) == setflag) &&
+ !(p->pfrkt_flags & clrflag))
+ goto _skip;
+ SLIST_FOREACH(q, &workq, pfrkt_workq)
+ if (!strcmp(p->pfrkt_name, q->pfrkt_name))
+ goto _skip;
+ SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
+ if ((p->pfrkt_flags & PFR_TFLAG_PERSIST) &&
+ (clrflag & PFR_TFLAG_PERSIST) &&
+ !(p->pfrkt_flags & PFR_TFLAG_REFERENCED))
+ xdel++;
+ else
+ xchange++;
+ }
+_skip:
+ }
+ if (!(flags & PFR_FLAG_DUMMY)) {
+ if (flags & PFR_FLAG_ATOMIC)
+ s = splsoftnet();
+ pfr_setflags_ktables(&workq, setflag, clrflag);
+ if (flags & PFR_FLAG_ATOMIC)
+ splx(s);
+ }
+ if (nchange != NULL)
+ *nchange = xchange;
+ if (ndel != NULL)
+ *ndel = xdel;
+ return (0);
+}
+
+int
+pfr_ina_begin(int *ticket, int *ndel, int flags)
+{
+ struct pfr_ktableworkq workq;
+ struct pfr_ktable *p;
+ int xdel = 0;
+
+ ACCEPT_FLAGS(PFR_FLAG_DUMMY);
+ SLIST_INIT(&workq);
+ RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
+ if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE))
+ continue;
+ SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
+ xdel++;
+ }
+ if (!(flags & PFR_FLAG_DUMMY))
+ pfr_setflags_ktables(&workq, 0, PFR_TFLAG_INACTIVE);
+ if (ndel != NULL)
+ *ndel = xdel;
+ if (ticket != NULL && !(flags & PFR_FLAG_DUMMY))
+ *ticket = ++pfr_ticket;
+ return (0);
+}
+
+int
+pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *nadd, int *naddr, int ticket, int flags)
+{
+ struct pfr_ktableworkq tableq;
+ struct pfr_kentryworkq addrq;
+ struct pfr_ktable *kt, *shadow;
+ struct pfr_kentry *p;
+ struct pfr_addr ad;
+ int i, rv, xadd = 0, xaddr = 0;
+
+ ACCEPT_FLAGS(PFR_FLAG_DUMMY|PFR_FLAG_ADDRSTOO);
+ if (ticket != pfr_ticket)
+ return (EBUSY);
+ if (size && !(flags & PFR_FLAG_ADDRSTOO))
+ return (EINVAL);
+ tbl->pfrt_flags |= PFR_TFLAG_INACTIVE;
+ if (tbl->pfrt_flags & ~(PFR_TFLAG_USRMASK+PFR_TFLAG_INACTIVE))
+ return (EINVAL);
+ SLIST_INIT(&tableq);
+ kt = RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl);
+ if (kt == NULL) {
+ kt = pfr_create_ktable(tbl, 0);
+ if (kt == NULL)
+ return (ENOMEM);
+ SLIST_INSERT_HEAD(&tableq, kt, pfrkt_workq);
+ xadd++;
+ } else if (!(kt->pfrkt_flags & PFR_TFLAG_INACTIVE))
+ xadd++;
+ shadow = pfr_create_ktable(tbl, 0);
+ if (shadow == NULL)
+ return (ENOMEM);
+ SLIST_INIT(&addrq);
+ for (i = 0; i < size; i++) {
+ if (copyin(addr+i, &ad, sizeof(ad)))
+ senderr(EFAULT);
+ if (pfr_validate_addr(&ad))
+ senderr(EFAULT);
+ if (pfr_lookup_addr(shadow, &ad, 1) != NULL)
+ continue;
+ p = pfr_create_kentry(&ad);
+ if (p == NULL)
+ senderr(ENOMEM);
+ SLIST_INSERT_HEAD(&addrq, p, pfrke_workq);
+ xaddr++;
+ }
+ if (!(flags & PFR_FLAG_ADDRSTOO))
+ shadow->pfrkt_cnt = NO_ADDRESSES;
+ if (!(flags & PFR_FLAG_DUMMY)) {
+ pfr_destroy_ktable(kt->pfrkt_shadow, 1);
+ kt->pfrkt_flags |= PFR_TFLAG_INACTIVE;
+ pfr_insert_ktables(&tableq);
+ kt->pfrkt_shadow = shadow;
+ pfr_insert_kentries(shadow, &addrq, 0);
+ } else {
+ pfr_destroy_ktable(shadow, 0);
+ pfr_destroy_ktables(&tableq, 0);
+ pfr_destroy_kentries(&addrq);
+ }
+ if (nadd != NULL)
+ *nadd = xadd;
+ if (naddr != NULL)
+ *naddr = xaddr;
+ return (0);
+_bad:
+ pfr_destroy_ktable(shadow, 0);
+ pfr_destroy_ktables(&tableq, 0);
+ pfr_destroy_kentries(&addrq);
+ return (rv);
+}
+
+int
+pfr_ina_commit(int ticket, int *nadd, int *nchange, int flags)
+{
+ struct pfr_ktable *p;
+ struct pfr_ktableworkq workq;
+ int s, xadd = 0, xchange = 0;
+ long tzero = time.tv_sec;
+
+ ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
+ if (ticket != pfr_ticket)
+ return (EBUSY);
+ pfr_ticket++;
+
+ SLIST_INIT(&workq);
+ RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
+ if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE))
+ continue;
+ SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
+ if (p->pfrkt_flags & PFR_TFLAG_ACTIVE)
+ xchange++;
+ else
+ xadd++;
+ }
+
+ if (!(flags & PFR_FLAG_DUMMY)) {
+ if (flags & PFR_FLAG_ATOMIC)
+ s = splsoftnet();
+ SLIST_FOREACH(p, &workq, pfrkt_workq)
+ pfr_commit_ktable(p, tzero);
+ if (flags & PFR_FLAG_ATOMIC)
+ splx(s);
+ }
+ if (nadd != NULL)
+ *nadd = xadd;
+ if (nchange != NULL)
+ *nchange = xchange;
+
+ return (0);
+}
+
+void
+pfr_commit_ktable(struct pfr_ktable *kt, long tzero)
+{
+ struct pfr_ktable *shadow = kt->pfrkt_shadow;
+ int setflag, clrflag;
+
+ if (shadow->pfrkt_cnt == NO_ADDRESSES) {
+ if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
+ pfr_clstats_ktable(kt, tzero, 1);
+ } else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) {
+ /* kt might contain addresses */
+ struct pfr_kentryworkq addrq, addq, changeq, delq, garbageq;
+ struct pfr_kentry *p, *q, *next;
+ struct pfr_addr ad;
+
+ pfr_enqueue_addrs(shadow, &addrq, NULL, 0);
+ pfr_mark_addrs(kt);
+ SLIST_INIT(&addq);
+ SLIST_INIT(&changeq);
+ SLIST_INIT(&delq);
+ SLIST_INIT(&garbageq);
+ for (p = SLIST_FIRST(&addrq); p != NULL; p = next) {
+ next = SLIST_NEXT(p, pfrke_workq); /* XXX */
+ pfr_copyout_addr(&ad, p);
+ q = pfr_lookup_addr(kt, &ad, 1);
+ if (q != NULL) {
+ if (q->pfrke_not != p->pfrke_not)
+ SLIST_INSERT_HEAD(&changeq, q,
+ pfrke_workq);
+ q->pfrke_mark = 1;
+ SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq);
+ } else {
+ p->pfrke_tzero = tzero;
+ SLIST_INSERT_HEAD(&addq, p, pfrke_workq);
+ }
+ }
+ pfr_enqueue_addrs(kt, &delq, NULL, 1);
+ pfr_insert_kentries(kt, &addq, tzero);
+ pfr_remove_kentries(kt, &delq);
+ pfr_clstats_kentries(&changeq, tzero, 1);
+ pfr_destroy_kentries(&garbageq);
+ } else {
+ /* kt cannot contain addresses */
+ SWAP(struct radix_node_head *, kt->pfrkt_ip4,
+ shadow->pfrkt_ip4);
+ SWAP(struct radix_node_head *, kt->pfrkt_ip6,
+ shadow->pfrkt_ip6);
+ SWAP(int, kt->pfrkt_cnt, shadow->pfrkt_cnt);
+ pfr_clstats_ktable(kt, tzero, 1);
+ }
+ setflag = shadow->pfrkt_flags & PFR_TFLAG_USRMASK;
+ clrflag = (kt->pfrkt_flags & ~setflag) & PFR_TFLAG_USRMASK;
+ setflag |= PFR_TFLAG_ACTIVE;
+ clrflag |= PFR_TFLAG_INACTIVE;
+ pfr_destroy_ktable(kt->pfrkt_shadow, 0);
+ kt->pfrkt_shadow = NULL;
+ pfr_setflags_ktable(kt, setflag, clrflag);
+}
+
void
pfr_insert_ktables(struct pfr_ktableworkq *workq)
{
struct pfr_ktable *p;
- int n = 0;
- /* insert into tree */
- SLIST_FOREACH(p, workq, pfrkt_workq) {
- RB_INSERT(pfr_ktablehead, &pfr_ktables, p);
- n++;
- }
- pfr_ktable_cnt += n;
+ SLIST_FOREACH(p, workq, pfrkt_workq)
+ pfr_insert_ktable(p);
}
void
-pfr_remove_ktables(struct pfr_ktableworkq *workq)
+pfr_insert_ktable(struct pfr_ktable *kt)
+{
+ RB_INSERT(pfr_ktablehead, &pfr_ktables, kt);
+ pfr_ktable_cnt++;
+}
+
+void
+pfr_setflags_ktables(struct pfr_ktableworkq *workq, int setflag, int clrflag)
{
- struct pfr_kentryworkq addrq;
struct pfr_ktable *p;
- int n = 0;
- SLIST_FOREACH(p, workq, pfrkt_workq) {
- RB_REMOVE(pfr_ktablehead, &pfr_ktables, p);
- if (pfr_enqueue_addrs(p, &addrq, NULL))
- printf("pfr_remove_ktables: enqueue failed");
- pfr_destroy_kentries(&addrq);
- n++;
+ SLIST_FOREACH(p, workq, pfrkt_workq)
+ pfr_setflags_ktable(p, setflag, clrflag);
+}
+
+void
+pfr_setflags_ktable(struct pfr_ktable *kt, int setflag, int clrflag)
+{
+ struct pfr_kentryworkq addrq;
+ int oldf = kt->pfrkt_flags;
+ int newf = (oldf | setflag) & ~clrflag;
+
+ if (!(newf & PFR_TFLAG_REFERENCED) &&
+ !(newf & PFR_TFLAG_PERSIST))
+ newf &= ~PFR_TFLAG_ACTIVE;
+ if (!(newf & PFR_TFLAG_ACTIVE))
+ newf &= ~PFR_TFLAG_USRMASK;
+ if (!(newf & PFR_TFLAG_SETMASK)) {
+ RB_REMOVE(pfr_ktablehead, &pfr_ktables, kt);
+ pfr_destroy_ktable(kt, 1);
+ pfr_ktable_cnt--;
+ return;
}
- pfr_ktable_cnt -= n;
- pfr_destroy_ktables(workq);
+ if (!(newf & PFR_TFLAG_ACTIVE) && kt->pfrkt_cnt) {
+ pfr_enqueue_addrs(kt, &addrq, NULL, 0);
+ pfr_remove_kentries(kt, &addrq);
+ }
+ if (!(newf & PFR_TFLAG_INACTIVE) && kt->pfrkt_shadow != NULL) {
+ pfr_destroy_ktable(kt->pfrkt_shadow, 1);
+ kt->pfrkt_shadow = NULL;
+ }
+ kt->pfrkt_flags = newf;
}
void
pfr_clstats_ktables(struct pfr_ktableworkq *workq, long tzero, int recurse)
{
- struct pfr_kentryworkq addrq;
struct pfr_ktable *p;
+
+ SLIST_FOREACH(p, workq, pfrkt_workq)
+ pfr_clstats_ktable(p, tzero, recurse);
+}
+
+void
+pfr_clstats_ktable(struct pfr_ktable *kt, long tzero, int recurse)
+{
+ struct pfr_kentryworkq addrq;
int s;
- SLIST_FOREACH(p, workq, pfrkt_workq) {
- if (recurse) {
- if (pfr_enqueue_addrs(p, &addrq, NULL))
- printf("pfr_clr_tstats: enqueue failed");
- pfr_clstats_kentries(&addrq, tzero);
- }
- s = splsoftnet();
- bzero(p->pfrkt_packets, sizeof(p->pfrkt_packets));
- bzero(p->pfrkt_bytes, sizeof(p->pfrkt_bytes));
- p->pfrkt_match = p->pfrkt_nomatch = 0;
- splx(s);
- p->pfrkt_tzero = tzero;
+ if (recurse) {
+ pfr_enqueue_addrs(kt, &addrq, NULL, 0);
+ pfr_clstats_kentries(&addrq, tzero, 0);
}
+ s = splsoftnet();
+ bzero(kt->pfrkt_packets, sizeof(kt->pfrkt_packets));
+ bzero(kt->pfrkt_bytes, sizeof(kt->pfrkt_bytes));
+ kt->pfrkt_match = kt->pfrkt_nomatch = 0;
+ splx(s);
+ kt->pfrkt_tzero = tzero;
}
struct pfr_ktable *
@@ -1195,7 +1469,7 @@ pfr_create_ktable(struct pfr_table *tbl, long tzero)
offsetof(struct sockaddr_in, sin_addr) * 8) ||
!rn_inithead((void **)&kt->pfrkt_ip6,
offsetof(struct sockaddr_in6, sin6_addr) * 8)) {
- pfr_destroy_ktable(kt);
+ pfr_destroy_ktable(kt, 0);
return (NULL);
}
kt->pfrkt_tzero = tzero;
@@ -1204,28 +1478,35 @@ pfr_create_ktable(struct pfr_table *tbl, long tzero)
}
void
-pfr_destroy_ktable(struct pfr_ktable *kt)
+pfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr)
+{
+ struct pfr_ktable *p, *q;
+
+ for (p = SLIST_FIRST(workq); p; p = q) {
+ q = SLIST_NEXT(p, pfrkt_workq);
+ pfr_destroy_ktable(p, flushaddr);
+ }
+}
+
+void
+pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr)
{
+ struct pfr_kentryworkq addrq;
+
if (kt == NULL)
return;
+ if (flushaddr) {
+ pfr_enqueue_addrs(kt, &addrq, NULL, 0);
+ pfr_destroy_kentries(&addrq);
+ }
if (kt->pfrkt_ip4 != NULL)
free((caddr_t)kt->pfrkt_ip4, M_RTABLE);
if (kt->pfrkt_ip6 != NULL)
free((caddr_t)kt->pfrkt_ip6, M_RTABLE);
+ pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr);
pool_put(&pfr_ktable_pl, kt);
}
-void
-pfr_destroy_ktables(struct pfr_ktableworkq *workq)
-{
- struct pfr_ktable *p, *q;
-
- for (p = SLIST_FIRST(workq); p; p = q) {
- q = SLIST_NEXT(p, pfrkt_workq);
- pfr_destroy_ktable(p);
- }
-}
-
int
pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q)
{
@@ -1301,41 +1582,29 @@ pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
struct pfr_ktable *
pfr_attach_table(char *name)
{
- struct pfr_ktable *p, key;
- struct pfr_ktableworkq workq;
-
- bzero(&key, sizeof(key));
- strlcpy(key.pfrkt_name, name, sizeof(key.pfrkt_name));
- key.pfrkt_flags = PFR_TFLAG_ACTIVE;
- p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
- if (p == NULL) {
- p = pfr_create_ktable(&key.pfrkt_t, time.tv_sec);
- if (p == NULL)
+ struct pfr_ktable *kt;
+ struct pfr_table tbl;
+
+ bzero(&tbl, sizeof(tbl));
+ strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name));
+ kt = pfr_lookup_table(&tbl);
+ if (kt == NULL) {
+ kt = pfr_create_ktable(&tbl, time.tv_sec);
+ if (kt == NULL)
return NULL;
- SLIST_INIT(&workq);
- SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
- pfr_insert_ktables(&workq);
+ pfr_insert_ktable(kt);
}
- p->pfrkt_refcnt++;
- return p;
+ if (!kt->pfrkt_refcnt++)
+ pfr_setflags_ktable(kt, PFR_TFLAG_REFERENCED, 0);
+ return kt;
}
void
pfr_detach_table(struct pfr_ktable *kt)
{
- struct pfr_ktableworkq workq;
-
if (kt->pfrkt_refcnt <= 0)
- printf("pfr_detach_table, refcount = %d\n",
+ printf("pfr_detach_table: refcount = %d\n",
kt->pfrkt_refcnt);
- else {
- kt->pfrkt_refcnt--;
- if (kt->pfrkt_refcnt == 0 &&
- !(kt->pfrkt_flags & PFR_TFLAG_PERSIST)) {
- kt->pfrkt_flags &= ~PFR_TFLAG_ACTIVE;
- SLIST_INIT(&workq);
- SLIST_INSERT_HEAD(&workq, kt, pfrkt_workq);
- pfr_remove_ktables(&workq);
- }
- }
+ else if (!--kt->pfrkt_refcnt)
+ pfr_setflags_ktable(kt, 0, PFR_TFLAG_REFERENCED);
}
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 2ce24b2abba..99bb797910e 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.129 2003/01/07 00:21:07 dhartmei Exp $ */
+/* $OpenBSD: pfvar.h,v 1.130 2003/01/09 10:40:45 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -96,6 +96,7 @@ struct pf_addr_wrap {
union {
struct pf_addr_dyn *dyn;
struct pfr_ktable *tbl;
+ int tblcnt;
} p;
u_int8_t type; /* PF_ADDR_* */
};
@@ -470,11 +471,14 @@ struct pf_anchor {
TAILQ_HEAD(pf_anchorqueue, pf_anchor);
-#define PFR_TFLAG_PERSIST 0x00000001
-#define PFR_TFLAG_CONST 0x00000002
-#define PFR_TFLAG_ACTIVE 0x00000004
-#define PFR_TFLAG_INACTIVE 0x00000008
-#define PFR_TFLAG_ALLMASK 0x0000000F
+#define PFR_TFLAG_PERSIST 0x00000001
+#define PFR_TFLAG_CONST 0x00000002
+#define PFR_TFLAG_ACTIVE 0x00000004
+#define PFR_TFLAG_INACTIVE 0x00000008
+#define PFR_TFLAG_REFERENCED 0x00000010
+#define PFR_TFLAG_USRMASK 0x00000003
+#define PFR_TFLAG_SETMASK 0x0000001C
+#define PFR_TFLAG_ALLMASK 0x0000001F
struct pfr_table {
char pfrt_name[PF_TABLE_NAME_SIZE];
@@ -544,6 +548,7 @@ struct pfr_ktable {
SLIST_ENTRY(pfr_ktable) pfrkt_workq;
struct radix_node_head *pfrkt_ip4;
struct radix_node_head *pfrkt_ip6;
+ struct pfr_ktable *pfrkt_shadow;
};
#define pfrkt_t pfrkt_ts.pfrts_t
#define pfrkt_name pfrkt_t.pfrt_name
@@ -834,7 +839,7 @@ struct pfioc_ruleset {
#define PFR_FLAG_DUMMY 0x00000002
#define PFR_FLAG_FEEDBACK 0x00000004
#define PFR_FLAG_CLSTATS 0x00000008
-#define PFR_FLAG_RECURSE 0x00000010
+#define PFR_FLAG_ADDRSTOO 0x00000010
#define PFR_FLAG_REPLACE 0x00000020
#define PFR_FLAG_ALLMASK 0x0000003F
@@ -847,11 +852,14 @@ struct pfioc_table {
int pfrio_ndel;
int pfrio_nchange;
int pfrio_flags;
+ int pfrio_ticket;
};
#define pfrio_exists pfrio_nadd
#define pfrio_nzero pfrio_nadd
#define pfrio_nmatch pfrio_nadd
-#define pfrio_name pfrio_table.pfrt_name
+#define pfrio_naddr pfrio_size2
+#define pfrio_setflag pfrio_size2
+#define pfrio_clrflag pfrio_nadd
/*
@@ -915,7 +923,10 @@ struct pfioc_table {
#define DIOCRGETASTATS _IOWR('D', 71, struct pfioc_table)
#define DIOCRCLRASTATS _IOWR('D', 72, struct pfioc_table)
#define DIOCRTSTADDRS _IOWR('D', 73, struct pfioc_table)
-
+#define DIOCRSETTFLAGS _IOWR('D', 74, struct pfioc_table)
+#define DIOCRINABEGIN _IOWR('D', 75, struct pfioc_table)
+#define DIOCRINACOMMIT _IOWR('D', 76, struct pfioc_table)
+#define DIOCRINADEFINE _IOWR('D', 77, struct pfioc_table)
#ifdef _KERNEL
RB_HEAD(pf_state_tree, pf_tree_node);
@@ -940,6 +951,7 @@ extern struct pf_poolqueue *pf_pools_active;
extern struct pf_poolqueue *pf_pools_inactive;
extern int pf_tbladdr_setup(struct pf_addr_wrap *);
extern void pf_tbladdr_remove(struct pf_addr_wrap *);
+extern void pf_tbladdr_copyout(struct pf_addr_wrap *);
extern int pf_dynaddr_setup(struct pf_addr_wrap *,
sa_family_t);
extern void pf_dynaddr_copyout(struct pf_addr_wrap *);
@@ -994,6 +1006,7 @@ 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_set_tflags(struct pfr_table *, int, int, int, 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);
@@ -1007,9 +1020,10 @@ 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);
+int pfr_ina_begin(int *, int *, int);
+int pfr_ina_commit(int, int *, int *, int);
+int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *,
+ int *, int, int);
extern struct pf_status pf_status;
extern struct pool pf_frent_pl, pf_frag_pl;
diff --git a/usr.sbin/authpf/authpf.c b/usr.sbin/authpf/authpf.c
index 9c6f68f243c..36ce004d53a 100644
--- a/usr.sbin/authpf/authpf.c
+++ b/usr.sbin/authpf/authpf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: authpf.c,v 1.44 2003/01/07 03:32:15 dhartmei Exp $ */
+/* $OpenBSD: authpf.c,v 1.45 2003/01/09 10:40:44 cedric Exp $ */
/*
* Copyright (C) 1998 - 2002 Bob Beck (beck@openbsd.org).
@@ -855,3 +855,13 @@ pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
fprintf(stderr, "set limit not supported in authpf\n");
return (1);
}
+
+void pfctl_append_addr(char *addr, int net, int neg)
+{
+ /* appropriate message will be printed by following function */
+}
+
+void pfctl_define_table(char *name, int flags, int addrs)
+{
+ fprintf(stderr, "table definitions not yet supported in authpf\n");
+}