diff options
-rw-r--r-- | sbin/pfctl/parse.y | 48 | ||||
-rw-r--r-- | sbin/pfctl/pfctl.8 | 5 | ||||
-rw-r--r-- | sbin/pfctl/pfctl.c | 18 | ||||
-rw-r--r-- | sbin/pfctl/pfctl.h | 7 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.h | 9 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_radix.c | 84 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_table.c | 114 | ||||
-rw-r--r-- | share/man/man4/pf.4 | 60 | ||||
-rw-r--r-- | share/man/man5/pf.conf.5 | 81 | ||||
-rw-r--r-- | sys/net/pf.c | 11 | ||||
-rw-r--r-- | sys/net/pf_ioctl.c | 38 | ||||
-rw-r--r-- | sys/net/pf_table.c | 649 | ||||
-rw-r--r-- | sys/net/pfvar.h | 38 | ||||
-rw-r--r-- | usr.sbin/authpf/authpf.c | 12 |
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"); +} |