From 95015692958ba836f46bad24f9e0e593f1a50520 Mon Sep 17 00:00:00 2001 From: mlaier Date: Tue, 3 Jul 2007 12:22:02 +0000 Subject: Import pf userland from OpenBSD 4.1 and (for ftp-proxy) libevent 1.3b as a local lib. --- contrib/pf/pfctl/parse.y | 642 +++++++++++++++++++-------- contrib/pf/pfctl/pf_print_state.c | 12 +- contrib/pf/pfctl/pfctl.8 | 147 +++++-- contrib/pf/pfctl/pfctl.c | 888 +++++++++++++++++++++++++++++--------- contrib/pf/pfctl/pfctl.h | 7 +- contrib/pf/pfctl/pfctl_altq.c | 32 +- contrib/pf/pfctl/pfctl_optimize.c | 156 +++++-- contrib/pf/pfctl/pfctl_osfp.c | 13 +- contrib/pf/pfctl/pfctl_parser.c | 154 +++++-- contrib/pf/pfctl/pfctl_parser.h | 35 +- contrib/pf/pfctl/pfctl_radix.c | 7 +- contrib/pf/pfctl/pfctl_table.c | 89 ++-- 12 files changed, 1610 insertions(+), 572 deletions(-) (limited to 'contrib/pf/pfctl') diff --git a/contrib/pf/pfctl/parse.y b/contrib/pf/pfctl/parse.y index 179898f..ef5d77b 100644 --- a/contrib/pf/pfctl/parse.y +++ b/contrib/pf/pfctl/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.482 2005/03/07 13:20:03 henning Exp $ */ +/* $OpenBSD: parse.y,v 1.517 2007/02/03 23:26:40 dhartmei Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -199,10 +199,12 @@ struct filter_opts { char *tag; char *match_tag; u_int8_t match_tag_not; + int rtableid; } filter_opts; struct antispoof_opts { char *label; + int rtableid; } antispoof_opts; struct scrub_opts { @@ -216,6 +218,7 @@ struct scrub_opts { int fragcache; int randomid; int reassemble_tcp; + int rtableid; } scrub_opts; struct queue_opts { @@ -254,9 +257,10 @@ struct node_hfsc_opts hfsc_opts; int yyerror(const char *, ...); int disallow_table(struct node_host *, const char *); +int disallow_urpf_failed(struct node_host *, const char *); int disallow_alias(struct node_host *, const char *); -int rule_consistent(struct pf_rule *); -int filter_consistent(struct pf_rule *); +int rule_consistent(struct pf_rule *, int); +int filter_consistent(struct pf_rule *, int); int nat_consistent(struct pf_rule *); int rdr_consistent(struct pf_rule *); int process_tabledef(char *, struct table_opts *); @@ -306,6 +310,7 @@ struct sym { int symset(const char *, const char *, int); char *symget(const char *); +void mv_rules(struct pf_ruleset *, struct pf_ruleset *); void decide_address_family(struct node_host *, sa_family_t *); void remove_invalid_hosts(struct node_host **, sa_family_t *); int invalid_redirect(struct node_host *, sa_family_t); @@ -325,6 +330,7 @@ typedef struct { u_int32_t number; int i; char *string; + int rtableid; struct { u_int8_t b1; u_int8_t b2; @@ -367,6 +373,7 @@ typedef struct { } keep_state; struct { u_int8_t log; + u_int8_t logif; u_int8_t quick; } logquick; struct { @@ -395,30 +402,30 @@ typedef struct { %} -%token PASS BLOCK SCRUB RETURN IN OS OUT LOG LOGALL QUICK ON FROM TO FLAGS +%token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS %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 FILENAME ROUTETO DUPTO REPLYTO NO LABEL -%token NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE +%token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE %token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR %token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID %token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID %token ANTISPOOF FOR %token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY %token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT -%token QUEUE PRIORITY QLIMIT -%token LOAD +%token QUEUE PRIORITY QLIMIT RTABLE +%token LOAD RULESET_OPTIMIZATION %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH -%token TAGGED TAG IFBOUND GRBOUND FLOATING STATEPOLICY ROUTE +%token TAGGED TAG IFBOUND FLOATING STATEPOLICY ROUTE %token STRING %token PORTBINARY %type interface if_list if_item_not if_item %type number icmptype icmp6type uid gid -%type tos not yesno natpass -%type no dir log af fragcache sourcetrack flush -%type unaryop statelock -%type action nataction scrubaction +%type tos not yesno +%type no dir af fragcache optimizer +%type sourcetrack flush unaryop statelock +%type action nataction natpass scrubaction %type flags flag blockspec %type port rport %type hashkey @@ -437,10 +444,10 @@ typedef struct { %type gids gid_list gid_item %type route %type redirection redirpool -%type label string tag +%type label string tag anchorname %type keep %type state_opt_spec state_opt_list state_opt_item -%type logquick +%type logquick quick log logopts logopt %type antispoof_ifspc antispoof_iflst antispoof_if %type qname %type qassign qassign_list qassign_item @@ -456,6 +463,7 @@ typedef struct { %type table_opts table_opt table_opts_l %type pool_opts pool_opt pool_opts_l %type tagged +%type rtable %% ruleset : /* empty */ @@ -472,9 +480,36 @@ ruleset : /* empty */ | ruleset varset '\n' | ruleset antispoof '\n' | ruleset tabledef '\n' + | '{' fakeanchor '}' '\n'; | ruleset error '\n' { errors++; } ; +/* + * apply to previouslys specified rule: must be careful to note + * what that is: pf or nat or binat or rdr + */ +fakeanchor : fakeanchor '\n' + | fakeanchor anchorrule '\n' + | fakeanchor binatrule '\n' + | fakeanchor natrule '\n' + | fakeanchor pfrule '\n' + | fakeanchor error '\n' + ; + +optimizer : string { + if (!strcmp($1, "none")) + $$ = 0; + else if (!strcmp($1, "basic")) + $$ = PF_OPTIMIZE_BASIC; + else if (!strcmp($1, "profile")) + $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE; + else { + yyerror("unknown ruleset-optimization %s", $$); + YYERROR; + } + } + ; + option : SET OPTIMIZATION STRING { if (check_rulestate(PFCTL_STATE_OPTION)) { free($3); @@ -485,7 +520,13 @@ option : SET OPTIMIZATION STRING { free($3); YYERROR; } - free ($3); + free($3); + } + | SET RULESET_OPTIMIZATION optimizer { + if (!(pf->opts & PF_OPT_OPTIMIZE)) { + pf->opts |= PF_OPT_OPTIMIZE; + pf->optimize = $3; + } } | SET TIMEOUT timeout_spec | SET TIMEOUT '{' timeout_list '}' @@ -535,12 +576,12 @@ option : SET OPTIMIZATION STRING { } | SET FINGERPRINTS STRING { if (pf->opts & PF_OPT_VERBOSE) - printf("set fingerprints %s\n", $3); + printf("set fingerprints \"%s\"\n", $3); if (check_rulestate(PFCTL_STATE_OPTION)) { free($3); YYERROR; } - if (!pf->anchor[0]) { + if (!pf->anchor->name[0]) { if (pfctl_file_fingerprints(pf->dev, pf->opts, $3)) { yyerror("error loading " @@ -560,10 +601,6 @@ option : SET OPTIMIZATION STRING { case PFRULE_IFBOUND: printf("set state-policy if-bound\n"); break; - case PFRULE_GRBOUND: - printf("set state-policy " - "group-bound\n"); - break; } default_statelock = $3; } @@ -606,37 +643,120 @@ varset : STRING '=' string { } ; -anchorrule : ANCHOR string dir interface af proto fromto filter_opts { +anchorname : STRING { $$ = $1; } + | /* empty */ { $$ = NULL; } + ; + +optnl : optnl '\n' + | + ; + +pfa_anchorlist : pfrule optnl + | anchorrule optnl + | pfa_anchorlist pfrule optnl + | pfa_anchorlist anchorrule optnl + ; + +pfa_anchor : '{' + { + char ta[PF_ANCHOR_NAME_SIZE]; + struct pf_ruleset *rs; + + /* steping into a brace anchor */ + pf->asd++; + pf->bn++; + pf->brace = 1; + + /* create a holding ruleset in the root */ + snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn); + rs = pf_find_or_create_ruleset(ta); + if (rs == NULL) + err(1, "pfa_anchor: pf_find_or_create_ruleset"); + pf->astack[pf->asd] = rs->anchor; + pf->anchor = rs->anchor; + } '\n' pfa_anchorlist '}' + { + pf->alast = pf->anchor; + pf->asd--; + pf->anchor = pf->astack[pf->asd]; + } + | /* empty */ + ; + +anchorrule : ANCHOR anchorname dir quick interface af proto fromto + filter_opts pfa_anchor + { struct pf_rule r; if (check_rulestate(PFCTL_STATE_FILTER)) { + if ($2) + free($2); + YYERROR; + } + + if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) { free($2); + yyerror("anchor names beginning with '_' " + "are reserved for internal use"); YYERROR; } memset(&r, 0, sizeof(r)); + if (pf->astack[pf->asd + 1]) { + /* move inline rules into relative location */ + pf_anchor_setup(&r, + &pf->astack[pf->asd]->ruleset, + $2 ? $2 : pf->alast->name); + + if (r.anchor == NULL) + err(1, "anchorrule: unable to " + "create ruleset"); + + if (pf->alast != r.anchor) { + if (r.anchor->match) { + yyerror("inline anchor '%s' " + "already exists", + r.anchor->name); + YYERROR; + } + mv_rules(&pf->alast->ruleset, + &r.anchor->ruleset); + } + pf_remove_if_empty_ruleset(&pf->alast->ruleset); + pf->alast = r.anchor; + } else { + if (!$2) { + yyerror("anchors without explicit " + "rules must specify a name"); + YYERROR; + } + } r.direction = $3; - r.af = $5; - r.prob = $8.prob; + r.quick = $4.quick; + r.af = $6; + r.prob = $9.prob; + r.rtableid = $9.rtableid; - if ($8.match_tag) - if (strlcpy(r.match_tagname, $8.match_tag, + if ($9.match_tag) + if (strlcpy(r.match_tagname, $9.match_tag, PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { yyerror("tag too long, max %u chars", PF_TAG_NAME_SIZE - 1); YYERROR; } - r.match_tag_not = $8.match_tag_not; + r.match_tag_not = $9.match_tag_not; - decide_address_family($7.src.host, &r.af); - decide_address_family($7.dst.host, &r.af); + decide_address_family($8.src.host, &r.af); + decide_address_family($8.dst.host, &r.af); - expand_rule(&r, $4, NULL, $6, $7.src_os, - $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, - 0, 0, 0, $2); + expand_rule(&r, $5, NULL, $7, $8.src_os, + $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, + 0, 0, 0, pf->astack[pf->asd + 1] ? + pf->alast->name : $2); free($2); + pf->astack[pf->asd + 1] = NULL; } - | NATANCHOR string interface af proto fromto { + | NATANCHOR string interface af proto fromto rtable { struct pf_rule r; if (check_rulestate(PFCTL_STATE_NAT)) { @@ -647,6 +767,7 @@ anchorrule : ANCHOR string dir interface af proto fromto filter_opts { memset(&r, 0, sizeof(r)); r.action = PF_NAT; r.af = $4; + r.rtableid = $7; decide_address_family($6.src.host, &r.af); decide_address_family($6.dst.host, &r.af); @@ -656,7 +777,7 @@ anchorrule : ANCHOR string dir interface af proto fromto filter_opts { 0, 0, 0, $2); free($2); } - | RDRANCHOR string interface af proto fromto { + | RDRANCHOR string interface af proto fromto rtable { struct pf_rule r; if (check_rulestate(PFCTL_STATE_NAT)) { @@ -667,6 +788,7 @@ anchorrule : ANCHOR string dir interface af proto fromto filter_opts { memset(&r, 0, sizeof(r)); r.action = PF_RDR; r.af = $4; + r.rtableid = $7; decide_address_family($6.src.host, &r.af); decide_address_family($6.dst.host, &r.af); @@ -697,7 +819,7 @@ anchorrule : ANCHOR string dir interface af proto fromto filter_opts { 0, 0, 0, $2); free($2); } - | BINATANCHOR string interface af proto fromto { + | BINATANCHOR string interface af proto fromto rtable { struct pf_rule r; if (check_rulestate(PFCTL_STATE_NAT)) { @@ -708,6 +830,7 @@ anchorrule : ANCHOR string dir interface af proto fromto filter_opts { memset(&r, 0, sizeof(r)); r.action = PF_BINAT; r.af = $4; + r.rtableid = $7; if ($5 != NULL) { if ($5->next != NULL) { yyerror("proto list expansion" @@ -736,7 +859,8 @@ anchorrule : ANCHOR string dir interface af proto fromto filter_opts { loadrule : LOAD ANCHOR string FROM string { struct loadanchors *loadanchor; - if (strlen($3) >= MAXPATHLEN) { + if (strlen(pf->anchor->name) + 1 + + strlen($3) >= MAXPATHLEN) { yyerror("anchorname %s too long, max %u\n", $3, MAXPATHLEN - 1); free($3); @@ -745,8 +869,14 @@ loadrule : LOAD ANCHOR string FROM string { loadanchor = calloc(1, sizeof(struct loadanchors)); if (loadanchor == NULL) err(1, "loadrule: calloc"); - if ((loadanchor->anchorname = strdup($3)) == NULL) - err(1, "loadrule: strdup"); + if ((loadanchor->anchorname = malloc(MAXPATHLEN)) == + NULL) + err(1, "loadrule: malloc"); + if (pf->anchor->name[0]) + snprintf(loadanchor->anchorname, MAXPATHLEN, + "%s/%s", pf->anchor->name, $3); + else + strlcpy(loadanchor->anchorname, $3, MAXPATHLEN); if ((loadanchor->filename = strdup($5)) == NULL) err(1, "loadrule: strdup"); @@ -779,6 +909,7 @@ scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts r.direction = $2; r.log = $3.log; + r.logif = $3.logif; if ($3.quick) { yyerror("scrub rules do not support 'quick'"); YYERROR; @@ -803,6 +934,7 @@ scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts r.max_mss = $8.maxmss; if ($8.fragcache) r.rule_flag |= $8.fragcache; + r.rtableid = $8.rtableid; expand_rule(&r, $4, NULL, $6, $7.src_os, $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, @@ -811,12 +943,14 @@ scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts ; scrub_opts : { - bzero(&scrub_opts, sizeof scrub_opts); - } + bzero(&scrub_opts, sizeof scrub_opts); + scrub_opts.rtableid = -1; + } scrub_opts_l { $$ = scrub_opts; } | /* empty */ { bzero(&scrub_opts, sizeof scrub_opts); + scrub_opts.rtableid = -1; $$ = scrub_opts; } ; @@ -885,6 +1019,13 @@ scrub_opt : NODF { } scrub_opts.randomid = 1; } + | RTABLE number { + if ($2 > RT_TABLEID_MAX || $2 < 0) { + yyerror("invalid rtable id"); + YYERROR; + } + scrub_opts.rtableid = $2; + } ; fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } @@ -906,10 +1047,12 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { r.action = PF_DROP; r.direction = PF_IN; r.log = $2.log; + r.logif = $2.logif; r.quick = $2.quick; r.af = $4; if (rule_label(&r, $5.label)) YYERROR; + r.rtableid = $5.rtableid; j = calloc(1, sizeof(struct node_if)); if (j == NULL) err(1, "antispoof: calloc"); @@ -960,6 +1103,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { r.af = $4; if (rule_label(&r, $5.label)) YYERROR; + r.rtableid = $5.rtableid; if (hh != NULL) h = hh; else @@ -994,11 +1138,15 @@ antispoof_if : if_item { $$ = $1; } } ; -antispoof_opts : { bzero(&antispoof_opts, sizeof antispoof_opts); } +antispoof_opts : { + bzero(&antispoof_opts, sizeof antispoof_opts); + antispoof_opts.rtableid = -1; + } antispoof_opts_l { $$ = antispoof_opts; } | /* empty */ { bzero(&antispoof_opts, sizeof antispoof_opts); + antispoof_opts.rtableid = -1; $$ = antispoof_opts; } ; @@ -1014,6 +1162,13 @@ antispoof_opt : label { } antispoof_opts.label = $1; } + | RTABLE number { + if ($2 > RT_TABLEID_MAX || $2 < 0) { + yyerror("invalid rtable id"); + YYERROR; + } + antispoof_opts.rtableid = $2; + } ; not : '!' { $$ = 1; } @@ -1100,6 +1255,10 @@ table_opt : STRING { yyerror("\"no-route\" is not permitted " "inside tables"); break; + case PF_ADDR_URPFFAILED: + yyerror("\"urpf-failed\" is not " + "permitted inside tables"); + break; default: yyerror("unknown address type %d", n->addr.type); @@ -1499,6 +1658,7 @@ pfrule : action dir logquick interface route af proto fromto struct node_proto *proto; int srctrack = 0; int statelock = 0; + int adaptive = 0; if (check_rulestate(PFCTL_STATE_FILTER)) YYERROR; @@ -1524,8 +1684,10 @@ pfrule : action dir logquick interface route af proto fromto } r.direction = $2; r.log = $3.log; + r.logif = $3.logif; r.quick = $3.quick; r.prob = $9.prob; + r.rtableid = $9.rtableid; r.af = $6; if ($9.tag) @@ -1543,11 +1705,15 @@ pfrule : action dir logquick interface route af proto fromto YYERROR; } r.match_tag_not = $9.match_tag_not; - r.flags = $9.flags.b1; - r.flagset = $9.flags.b2; if (rule_label(&r, $9.label)) YYERROR; free($9.label); + r.flags = $9.flags.b1; + r.flagset = $9.flags.b2; + if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { + yyerror("flags always false"); + YYERROR; + } if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { for (proto = $7; proto != NULL && proto->proto != IPPROTO_TCP; @@ -1575,6 +1741,12 @@ pfrule : action dir logquick interface route af proto fromto r.tos = $9.tos; r.keep_state = $9.keep.action; + + /* 'keep state' by default on pass rules. */ + if (!r.keep_state && !r.action && + !($9.marker & FOM_KEEP)) + r.keep_state = PF_STATE_NORMAL; + o = $9.keep.options; while (o) { struct node_state_opt *p = o; @@ -1671,8 +1843,8 @@ pfrule : action dir logquick interface route af proto fromto if (o->data.max_src_conn_rate.limit > PF_THRESHOLD_MAX) { yyerror("'max-src-conn-rate' " - "maximum rate must be < %u", - PF_THRESHOLD_MAX); + "maximum rate must be < %u", + PF_THRESHOLD_MAX); YYERROR; } r.max_src_conn_rate.limit = @@ -1709,6 +1881,11 @@ pfrule : action dir logquick interface route af proto fromto r.rule_flag |= o->data.statelock; break; case PF_STATE_OPT_TIMEOUT: + if (o->data.timeout.number == + PFTM_ADAPTIVE_START || + o->data.timeout.number == + PFTM_ADAPTIVE_END) + adaptive = 1; if (r.timeout[o->data.timeout.number]) { yyerror("state timeout %s " "multiple definitions", @@ -1722,6 +1899,20 @@ pfrule : action dir logquick interface route af proto fromto o = o->next; free(p); } + + /* 'flags S/SA' by default on stateful rules */ + if (!r.action && !r.flags && !r.flagset && + !$9.fragment && !($9.marker & FOM_FLAGS) && + r.keep_state) { + r.flags = parse_flags("S"); + r.flagset = parse_flags("SA"); + } + if (!adaptive && r.max_states) { + r.timeout[PFTM_ADAPTIVE_START] = + (r.max_states / 10) * 6; + r.timeout[PFTM_ADAPTIVE_END] = + (r.max_states / 10) * 12; + } if (r.rule_flag & PFRULE_SRCTRACK) { if (srctrack == PF_SRCTRACK_GLOBAL && r.max_src_nodes) { @@ -1832,11 +2023,15 @@ pfrule : action dir logquick interface route af proto fromto } ; -filter_opts : { bzero(&filter_opts, sizeof filter_opts); } +filter_opts : { + bzero(&filter_opts, sizeof filter_opts); + filter_opts.rtableid = -1; + } filter_opts_l { $$ = filter_opts; } | /* empty */ { bzero(&filter_opts, sizeof filter_opts); + filter_opts.rtableid = -1; $$ = filter_opts; } ; @@ -1940,6 +2135,13 @@ filter_opt : USER uids { filter_opts.prob = (u_int32_t)p; free($2); } + | RTABLE number { + if ($2 > RT_TABLEID_MAX || $2 < 0) { + yyerror("invalid rtable id"); + YYERROR; + } + filter_opts.rtableid = $2; + } ; action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } @@ -2021,15 +2223,55 @@ dir : /* empty */ { $$ = 0; } | OUT { $$ = PF_OUT; } ; -logquick : /* empty */ { $$.log = 0; $$.quick = 0; } - | log { $$.log = $1; $$.quick = 0; } - | QUICK { $$.log = 0; $$.quick = 1; } - | log QUICK { $$.log = $1; $$.quick = 1; } - | QUICK log { $$.log = $2; $$.quick = 1; } +quick : /* empty */ { $$.quick = 0; } + | QUICK { $$.quick = 1; } + ; + +logquick : /* empty */ { $$.log = 0; $$.quick = 0; $$.logif = 0; } + | log { $$ = $1; $$.quick = 0; } + | QUICK { $$.quick = 1; $$.log = 0; $$.logif = 0; } + | log QUICK { $$ = $1; $$.quick = 1; } + | QUICK log { $$ = $2; $$.quick = 1; } + ; + +log : LOG { $$.log = PF_LOG; $$.logif = 0; } + | LOG '(' logopts ')' { + $$.log = PF_LOG | $3.log; + $$.logif = $3.logif; + } ; -log : LOG { $$ = 1; } - | LOGALL { $$ = 2; } +logopts : logopt { $$ = $1; } + | logopts comma logopt { + $$.log = $1.log | $3.log; + $$.logif = $3.logif; + if ($$.logif == 0) + $$.logif = $1.logif; + } + ; + +logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; } + | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } + | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } + | TO string { + const char *errstr; + u_int i; + + $$.log = 0; + if (strncmp($2, "pflog", 5)) { + yyerror("%s: should be a pflog interface", $2); + free($2); + YYERROR; + } + i = strtonum($2 + 5, 0, 255, &errstr); + if (errstr) { + yyerror("%s: %s", $2, errstr); + free($2); + YYERROR; + } + free($2); + $$.logif = i; + } ; interface : /* empty */ { $$ = NULL; } @@ -2062,7 +2304,7 @@ if_item : STRING { YYERROR; } - if ((n = ifa_exists($1, 1)) != NULL) + if ((n = ifa_exists($1)) != NULL) $$->ifa_flags = n->ifa_flags; free($1); @@ -2176,6 +2418,9 @@ to : /* empty */ { $$.port = NULL; } | TO ipportspec { + if (disallow_urpf_failed($2.host, "\"urpf-failed\" is " + "not permitted in a destination address")) + YYERROR; $$ = $2; } ; @@ -2199,8 +2444,8 @@ ipspec : ANY { $$ = NULL; } | '{' host_list '}' { $$ = $2; } ; -host_list : xhost { $$ = $1; } - | host_list comma xhost { +host_list : ipspec { $$ = $1; } + | host_list comma ipspec { if ($3 == NULL) $$ = $1; else if ($1 == NULL) @@ -2220,12 +2465,22 @@ xhost : not host { n->not = $1; $$ = $2; } - | NOROUTE { + | not NOROUTE { $$ = calloc(1, sizeof(struct node_host)); if ($$ == NULL) err(1, "xhost: calloc"); $$->addr.type = PF_ADDR_NOROUTE; $$->next = NULL; + $$->not = $1; + $$->tail = $$; + } + | not URPFFAILED { + $$ = calloc(1, sizeof(struct node_host)); + if ($$ == NULL) + err(1, "xhost: calloc"); + $$->addr.type = PF_ADDR_URPFFAILED; + $$->next = NULL; + $$->not = $1; $$->tail = $$; } ; @@ -2428,31 +2683,13 @@ port_item : port { port : STRING { char *p = strchr($1, ':'); - struct servent *s = NULL; - u_long ulval; if (p == NULL) { - if (atoul($1, &ulval) == 0) { - if (ulval > 65535) { - free($1); - yyerror("illegal port value %lu", - ulval); - YYERROR; - } - $$.a = htons(ulval); - } else { - s = getservbyname($1, "tcp"); - if (s == NULL) - s = getservbyname($1, "udp"); - if (s == NULL) { - yyerror("unknown port %s", $1); - free($1); - YYERROR; - } - $$.a = s->s_port; + if (($$.a = getservice($1)) == -1) { + free($1); + YYERROR; } - $$.b = 0; - $$.t = 0; + $$.b = $$.t = 0; } else { int port[2]; @@ -2649,6 +2886,7 @@ flag : STRING { flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } | FLAGS '/' flag { $$.b1 = 0; $$.b2 = $3.b1; } + | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; } ; icmpspec : ICMPTYPE icmp_item { $$ = $2; } @@ -2786,7 +3024,8 @@ icmp6type : STRING { if (atoul($1, &ulval) == 0) { if (ulval > 255) { - yyerror("illegal icmp6-type %lu", ulval); + yyerror("illegal icmp6-type %lu", + ulval); free($1); YYERROR; } @@ -2832,15 +3071,16 @@ sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; } statelock : IFBOUND { $$ = PFRULE_IFBOUND; } - | GRBOUND { - $$ = PFRULE_GRBOUND; - } | FLOATING { $$ = 0; } ; -keep : KEEP STATE state_opt_spec { +keep : NO STATE { + $$.action = 0; + $$.options = NULL; + } + | KEEP STATE state_opt_spec { $$.action = PF_STATE_NORMAL; $$.options = $3; } @@ -3199,29 +3439,41 @@ redirection : /* empty */ { $$ = NULL; } } ; -natpass : /* empty */ { $$ = 0; } - | PASS { $$ = 1; } +natpass : /* empty */ { $$.b1 = $$.b2 = 0; } + | PASS { $$.b1 = 1; $$.b2 = 0; } + | PASS log { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; } ; nataction : no NAT natpass { - $$.b2 = $$.w = 0; + if ($1 && $3.b1) { + yyerror("\"pass\" not valid with \"no\""); + YYERROR; + } if ($1) $$.b1 = PF_NONAT; else $$.b1 = PF_NAT; - $$.b2 = $3; + $$.b2 = $3.b1; + $$.w = $3.b2; + $$.w2 = $3.w2; } | no RDR natpass { - $$.b2 = $$.w = 0; + if ($1 && $3.b1) { + yyerror("\"pass\" not valid with \"no\""); + YYERROR; + } if ($1) $$.b1 = PF_NORDR; else $$.b1 = PF_RDR; - $$.b2 = $3; + $$.b2 = $3.b1; + $$.w = $3.b2; + $$.w2 = $3.w2; } ; -natrule : nataction interface af proto fromto tag tagged redirpool pool_opts +natrule : nataction interface af proto fromto tag tagged rtable + redirpool pool_opts { struct pf_rule r; @@ -3232,6 +3484,8 @@ natrule : nataction interface af proto fromto tag tagged redirpool pool_opts r.action = $1.b1; r.natpass = $1.b2; + r.log = $1.w; + r.logif = $1.w2; r.af = $3; if (!r.af) { @@ -3259,47 +3513,48 @@ natrule : nataction interface af proto fromto tag tagged redirpool pool_opts YYERROR; } r.match_tag_not = $7.neg; + r.rtableid = $8; if (r.action == PF_NONAT || r.action == PF_NORDR) { - if ($8 != NULL) { + if ($9 != NULL) { yyerror("translation rule with 'no' " "does not need '->'"); YYERROR; } } else { - if ($8 == NULL || $8->host == NULL) { + if ($9 == NULL || $9->host == NULL) { yyerror("translation rule requires '-> " "address'"); YYERROR; } - if (!r.af && ! $8->host->ifindex) - r.af = $8->host->af; + if (!r.af && ! $9->host->ifindex) + r.af = $9->host->af; - remove_invalid_hosts(&$8->host, &r.af); - if (invalid_redirect($8->host, r.af)) + remove_invalid_hosts(&$9->host, &r.af); + if (invalid_redirect($9->host, r.af)) YYERROR; - if (check_netmask($8->host, r.af)) + if (check_netmask($9->host, r.af)) YYERROR; - r.rpool.proxy_port[0] = ntohs($8->rport.a); + r.rpool.proxy_port[0] = ntohs($9->rport.a); switch (r.action) { case PF_RDR: - if (!$8->rport.b && $8->rport.t && + if (!$9->rport.b && $9->rport.t && $5.dst.port != NULL) { r.rpool.proxy_port[1] = - ntohs($8->rport.a) + + ntohs($9->rport.a) + (ntohs( $5.dst.port->port[1]) - ntohs( $5.dst.port->port[0])); } else r.rpool.proxy_port[1] = - ntohs($8->rport.b); + ntohs($9->rport.b); break; case PF_NAT: r.rpool.proxy_port[1] = - ntohs($8->rport.b); + ntohs($9->rport.b); if (!r.rpool.proxy_port[0] && !r.rpool.proxy_port[1]) { r.rpool.proxy_port[0] = @@ -3314,25 +3569,25 @@ natrule : nataction interface af proto fromto tag tagged redirpool pool_opts break; } - r.rpool.opts = $9.type; + r.rpool.opts = $10.type; if ((r.rpool.opts & PF_POOL_TYPEMASK) == - PF_POOL_NONE && ($8->host->next != NULL || - $8->host->addr.type == PF_ADDR_TABLE || - DYNIF_MULTIADDR($8->host->addr))) + PF_POOL_NONE && ($9->host->next != NULL || + $9->host->addr.type == PF_ADDR_TABLE || + DYNIF_MULTIADDR($9->host->addr))) r.rpool.opts = PF_POOL_ROUNDROBIN; if ((r.rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN && - disallow_table($8->host, "tables are only " + disallow_table($9->host, "tables are only " "supported in round-robin redirection " "pools")) YYERROR; if ((r.rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN && - disallow_alias($8->host, "interface (%s) " + disallow_alias($9->host, "interface (%s) " "is only supported in round-robin " "redirection pools")) YYERROR; - if ($8->host->next != NULL) { + if ($9->host->next != NULL) { if ((r.rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) { yyerror("only round-robin " @@ -3343,14 +3598,14 @@ natrule : nataction interface af proto fromto tag tagged redirpool pool_opts } } - if ($9.key != NULL) - memcpy(&r.rpool.key, $9.key, + if ($10.key != NULL) + memcpy(&r.rpool.key, $10.key, sizeof(struct pf_poolhashkey)); - if ($9.opts) - r.rpool.opts |= $9.opts; + if ($10.opts) + r.rpool.opts |= $10.opts; - if ($9.staticport) { + if ($10.staticport) { if (r.action != PF_NAT) { yyerror("the 'static-port' option is " "only valid with nat rules"); @@ -3369,37 +3624,46 @@ natrule : nataction interface af proto fromto tag tagged redirpool pool_opts r.rpool.proxy_port[1] = 0; } - expand_rule(&r, $2, $8 == NULL ? NULL : $8->host, $4, + expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4, $5.src_os, $5.src.host, $5.src.port, $5.dst.host, $5.dst.port, 0, 0, 0, ""); - free($8); + free($9); } ; -binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag tagged - redirection +binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag + tagged rtable redirection { struct pf_rule binat; struct pf_pooladdr *pa; if (check_rulestate(PFCTL_STATE_NAT)) YYERROR; + if (disallow_urpf_failed($10, "\"urpf-failed\" is not " + "permitted as a binat destination")) + YYERROR; memset(&binat, 0, sizeof(binat)); + if ($1 && $3.b1) { + yyerror("\"pass\" not valid with \"no\""); + YYERROR; + } if ($1) binat.action = PF_NOBINAT; else binat.action = PF_BINAT; - binat.natpass = $3; + binat.natpass = $3.b1; + binat.log = $3.b2; + binat.logif = $3.w2; binat.af = $5; if (!binat.af && $8 != NULL && $8->af) binat.af = $8->af; if (!binat.af && $10 != NULL && $10->af) binat.af = $10->af; - if (!binat.af && $13 != NULL && $13->host) - binat.af = $13->host->af; + if (!binat.af && $14 != NULL && $14->host) + binat.af = $14->host->af; if (!binat.af) { yyerror("address family (inet/inet6) " "undefined"); @@ -3428,6 +3692,7 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag tagged YYERROR; } binat.match_tag_not = $12.neg; + binat.rtableid = $13; if ($6 != NULL) { binat.proto = $6->proto; @@ -3441,12 +3706,12 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag tagged "interface (%s) as the source address of a binat " "rule")) YYERROR; - if ($13 != NULL && $13->host != NULL && disallow_table( - $13->host, "invalid use of table <%s> as the " + if ($14 != NULL && $14->host != NULL && disallow_table( + $14->host, "invalid use of table <%s> as the " "redirect address of a binat rule")) YYERROR; - if ($13 != NULL && $13->host != NULL && disallow_alias( - $13->host, "invalid use of interface (%s) as the " + if ($14 != NULL && $14->host != NULL && disallow_alias( + $14->host, "invalid use of interface (%s) as the " "redirect address of a binat rule")) YYERROR; @@ -3485,33 +3750,33 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag tagged } if (binat.action == PF_NOBINAT) { - if ($13 != NULL) { + if ($14 != NULL) { yyerror("'no binat' rule does not need" " '->'"); YYERROR; } } else { - if ($13 == NULL || $13->host == NULL) { + if ($14 == NULL || $14->host == NULL) { yyerror("'binat' rule requires" " '-> address'"); YYERROR; } - remove_invalid_hosts(&$13->host, &binat.af); - if (invalid_redirect($13->host, binat.af)) + remove_invalid_hosts(&$14->host, &binat.af); + if (invalid_redirect($14->host, binat.af)) YYERROR; - if ($13->host->next != NULL) { + if ($14->host->next != NULL) { yyerror("binat rule must redirect to " "a single address"); YYERROR; } - if (check_netmask($13->host, binat.af)) + if (check_netmask($14->host, binat.af)) YYERROR; if (!PF_AZERO(&binat.src.addr.v.a.mask, binat.af) && !PF_AEQ(&binat.src.addr.v.a.mask, - &$13->host->addr.v.a.mask, binat.af)) { + &$14->host->addr.v.a.mask, binat.af)) { yyerror("'binat' source mask and " "redirect mask must be the same"); YYERROR; @@ -3521,12 +3786,12 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag tagged pa = calloc(1, sizeof(struct pf_pooladdr)); if (pa == NULL) err(1, "binat: calloc"); - pa->addr = $13->host->addr; + pa->addr = $14->host->addr; pa->ifname[0] = 0; TAILQ_INSERT_TAIL(&binat.rpool.list, pa, entries); - free($13); + free($14); } pfctl_add_rule(pf, &binat, ""); @@ -3541,6 +3806,16 @@ tagged : /* empty */ { $$.neg = 0; $$.name = NULL; } | not TAGGED string { $$.neg = $1; $$.name = $3; } ; +rtable : /* empty */ { $$ = -1; } + | RTABLE number { + if ($2 > RT_TABLEID_MAX || $2 < 0) { + yyerror("invalid rtable id"); + YYERROR; + } + $$ = $2; + } + ; + route_host : STRING { $$ = calloc(1, sizeof(struct node_host)); if ($$ == NULL) @@ -3701,6 +3976,17 @@ disallow_table(struct node_host *h, const char *fmt) } int +disallow_urpf_failed(struct node_host *h, const char *fmt) +{ + for (; h != NULL; h = h->next) + if (h->addr.type == PF_ADDR_URPFFAILED) { + yyerror(fmt); + return (1); + } + return (0); +} + +int disallow_alias(struct node_host *h, const char *fmt) { for (; h != NULL; h = h->next) @@ -3712,7 +3998,7 @@ disallow_alias(struct node_host *h, const char *fmt) } int -rule_consistent(struct pf_rule *r) +rule_consistent(struct pf_rule *r, int anchor_call) { int problems = 0; @@ -3721,7 +4007,7 @@ rule_consistent(struct pf_rule *r) case PF_DROP: case PF_SCRUB: case PF_NOSCRUB: - problems = filter_consistent(r); + problems = filter_consistent(r, anchor_call); break; case PF_NAT: case PF_NONAT: @@ -3740,7 +4026,7 @@ rule_consistent(struct pf_rule *r) } int -filter_consistent(struct pf_rule *r) +filter_consistent(struct pf_rule *r, int anchor_call) { int problems = 0; @@ -3792,11 +4078,6 @@ filter_consistent(struct pf_rule *r) yyerror("keep state on block rules doesn't make sense"); problems++; } - if ((r->tagname[0] || r->match_tagname[0]) && !r->keep_state && - r->action == PF_PASS) { - yyerror("tags cannot be used without keep state"); - problems++; - } return (-problems); } @@ -3864,7 +4145,7 @@ process_tabledef(char *name, struct table_opts *opts) &opts->init_nodes); if (!(pf->opts & PF_OPT_NOACTION) && pfctl_define_table(name, opts->flags, opts->init_addr, - pf->anchor, &ab, pf->tticket)) { + pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) { yyerror("cannot define table %s: %s", name, pfr_strerror(errno)); goto _error; @@ -3963,6 +4244,9 @@ expand_label_addr(const char *name, char *label, size_t len, sa_family_t af, case PF_ADDR_NOROUTE: snprintf(tmp, sizeof(tmp), "no-route"); break; + case PF_ADDR_URPFFAILED: + snprintf(tmp, sizeof(tmp), "urpf-failed"); + break; case PF_ADDR_ADDRMASK: if (!af || (PF_AZERO(&h->addr.v.a.addr, af) && PF_AZERO(&h->addr.v.a.mask, af))) @@ -4053,7 +4337,7 @@ expand_label_nr(const char *name, char *label, size_t len) char n[11]; if (strstr(label, name) != NULL) { - snprintf(n, sizeof(n), "%u", pf->rule_nr); + snprintf(n, sizeof(n), "%u", pf->anchor->match); expand_label_str(label, len, name, n); } } @@ -4480,10 +4764,10 @@ expand_rule(struct pf_rule *r, TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries); } - if (rule_consistent(r) < 0 || error) + if (rule_consistent(r, anchor_call[0]) < 0 || error) yyerror("skipping rule due to errors"); else { - r->nr = pf->rule_nr++; + r->nr = pf->astack[pf->asd]->match++; pfctl_add_rule(pf, r, anchor_call); added++; } @@ -4598,7 +4882,6 @@ lookup(char *s) { "from", FROM}, { "global", GLOBAL}, { "group", GROUP}, - { "group-bound", GRBOUND}, { "hfsc", HFSC}, { "hostid", HOSTID}, { "icmp-type", ICMPTYPE}, @@ -4613,7 +4896,6 @@ lookup(char *s) { "linkshare", LINKSHARE}, { "load", LOAD}, { "log", LOG}, - { "log-all", LOGALL}, { "loginterface", LOGINTERFACE}, { "max", MAXIMUM}, { "max-mss", MAXMSS}, @@ -4658,7 +4940,9 @@ lookup(char *s) { "round-robin", ROUNDROBIN}, { "route", ROUTE}, { "route-to", ROUTETO}, + { "rtable", RTABLE}, { "rule", RULE}, + { "ruleset-optimization", RULESET_OPTIMIZATION}, { "scrub", SCRUB}, { "set", SET}, { "skip", SKIP}, @@ -4678,6 +4962,7 @@ lookup(char *s) { "tos", TOS}, { "ttl", TTL}, { "upperlimit", UPPERLIMIT}, + { "urpf-failed", URPFFAILED}, { "user", USER}, }; const struct keywords *p; @@ -4725,9 +5010,7 @@ lgetc(FILE *f) while ((c = getc(f)) == '\\') { next = getc(f); if (next != '\n') { - if (isspace(next)) - yyerror("whitespace after \\"); - ungetc(next, f); + c = next; break; } yylval.lineno = lineno; @@ -5015,21 +5298,40 @@ symget(const char *nam) } void -decide_address_family(struct node_host *n, sa_family_t *af) +mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst) { - sa_family_t target_af = 0; + int i; + struct pf_rule *r; + + for (i = 0; i < PF_RULESET_MAX; ++i) { + while ((r = TAILQ_FIRST(src->rules[i].active.ptr)) + != NULL) { + TAILQ_REMOVE(src->rules[i].active.ptr, r, entries); + TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries); + dst->anchor->match++; + } + src->anchor->match = 0; + while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr)) + != NULL) { + TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries); + TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr, + r, entries); + } + } +} - while (!*af && n != NULL) { - if (n->af) { - if (target_af == 0) - target_af = n->af; - if (target_af != n->af) - return; +void +decide_address_family(struct node_host *n, sa_family_t *af) +{ + if (*af != 0 || n == NULL) + return; + *af = n->af; + while ((n = n->next) != NULL) { + if (n->af != *af) { + *af = 0; + return; } - n = n->next; } - if (!*af && target_af) - *af = target_af; } void @@ -5170,19 +5472,23 @@ parseicmpspec(char *w, sa_family_t af) } int -pfctl_load_anchors(int dev, int opts, struct pfr_buffer *trans) +pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) { struct loadanchors *la; + FILE *fin; TAILQ_FOREACH(la, &loadanchorshead, entries) { - if (opts & PF_OPT_VERBOSE) + if (pf->opts & PF_OPT_VERBOSE) fprintf(stderr, "\nLoading anchor %s from %s\n", la->anchorname, la->filename); - if (pfctl_rules(dev, la->filename, opts, la->anchorname, - trans) == -1) + if ((fin = pfctl_fopen(la->filename, "r")) == NULL) { + warn("%s", la->filename); + continue; + } + if (pfctl_rules(dev, la->filename, fin, pf->opts, pf->optimize, + la->anchorname, trans) == -1) return (-1); } return (0); } - diff --git a/contrib/pf/pfctl/pf_print_state.c b/contrib/pf/pfctl/pf_print_state.c index a41e9e5..e36b1fd 100644 --- a/contrib/pf/pfctl/pf_print_state.c +++ b/contrib/pf/pfctl/pf_print_state.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_print_state.c,v 1.40 2004/12/10 22:13:26 henning Exp $ */ +/* $OpenBSD: pf_print_state.c,v 1.44 2007/03/01 17:20:53 deraadt Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -96,6 +96,9 @@ print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose) case PF_ADDR_NOROUTE: printf("no-route"); return; + case PF_ADDR_URPFFAILED: + printf("urpf-failed"); + return; case PF_ADDR_RTLABEL: printf("route \"%s\"", addr->v.rtlabelname); return; @@ -274,7 +277,7 @@ print_state(struct pf_state *s, int opts) min = s->expire % 60; s->expire /= 60; printf(", expires in %.2u:%.2u:%.2u", s->expire, min, sec); - printf(", %u:%u pkts, %u:%u bytes", + printf(", %llu:%llu pkts, %llu:%llu bytes", s->packets[0], s->packets[1], s->bytes[0], s->bytes[1]); if (s->anchor.nr != -1) printf(", anchor %u", s->anchor.nr); @@ -287,8 +290,9 @@ print_state(struct pf_state *s, int opts) printf("\n"); } if (opts & PF_OPT_VERBOSE2) { - printf(" id: %016llx creatorid: %08x\n", - betoh64(s->id), ntohl(s->creatorid)); + printf(" id: %016llx creatorid: %08x%s\n", + betoh64(s->id), ntohl(s->creatorid), + ((s->sync_flags & PFSTATE_NOSYNC) ? " (no-sync)" : "")); } } diff --git a/contrib/pf/pfctl/pfctl.8 b/contrib/pf/pfctl/pfctl.8 index 9fdb00e..b5be8a1 100644 --- a/contrib/pf/pfctl/pfctl.8 +++ b/contrib/pf/pfctl/pfctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pfctl.8,v 1.118 2005/01/05 23:41:45 jmc Exp $ +.\" $OpenBSD: pfctl.8,v 1.128 2007/01/30 21:01:56 jmc Exp $ .\" .\" Copyright (c) 2001 Kjell Wooding. All rights reserved. .\" @@ -33,23 +33,23 @@ .Sh SYNOPSIS .Nm pfctl .Bk -words -.Op Fl AdeghmNnOoqRrvz +.Op Fl AdeghmNnOqRrvz .Op Fl a Ar anchor -.Xo -.Oo Fl D -.Ar macro Ns = Ns Ar value Oc -.Xc +.Oo Fl D Ar macro Ns = +.Ar value Oc .Op Fl F Ar modifier .Op Fl f Ar file .Op Fl i Ar interface -.Op Fl k Ar host +.Op Fl K Ar host | network +.Op Fl k Ar host | network +.Op Fl o Op Ar level .Op Fl p Ar device .Op Fl s Ar modifier -.Oo Xo +.Oo .Fl t Ar table .Fl T Ar command -.Op Ar address ... Oc -.Xc +.Op Ar address ... +.Oc .Op Fl x Ar level .Ek .Sh DESCRIPTION @@ -138,8 +138,10 @@ rules from the main ruleset is described in For example, the following will show all filter rules (see the .Fl s flag below) inside the anchor -.Li authpf/smith(1234) , -which would have been created for user smith by +.Dq authpf/smith(1234) , +which would have been created for user +.Dq smith +by .Xr authpf 8 , PID 1234: .Bd -literal -offset indent @@ -161,6 +163,27 @@ This is similar to C rules for variable scope. It is possible to create distinct tables with the same name in the global ruleset and in an anchor, but this is often bad design and a warning will be issued in that case. +.Pp +By default, recursive inline printing of anchors applies only to unnamed +anchors specified inline in the ruleset. +If the anchor name is terminated with a +.Sq * +character, the +.Fl s +flag will recursively print all anchors in a brace delimited block. +For example the following will print the +.Dq authpf +ruleset recursively: +.Bd -literal -offset indent +# pfctl -a 'authpf/*' -sr +.Ed +.Pp +To print the main ruleset recursively, specify only +.Sq * +as the anchor name: +.Bd -literal -offset indent +# pfctl -a '*' -sr +.Ed .It Fl D Ar macro Ns = Ns Ar value Define .Ar macro @@ -215,29 +238,49 @@ Help. .It Fl i Ar interface Restrict the operation to the given .Ar interface . -.It Fl k Ar host +.It Fl K Ar host | network +Kill all of the source tracking entries originating from the specified +.Ar host +or +.Ar network . +A second +.Fl K Ar host +or +.Fl K Ar network +option may be specified, which will kill all the source tracking +entries from the first host/network to the second. +.It Fl k Ar host | network Kill all of the state entries originating from the specified -.Ar host . +.Ar host +or +.Ar network . A second .Fl k Ar host +or +.Fl k Ar network option may be specified, which will kill all the state entries -from the first -.Ar host -to the second -.Ar host . +from the first host/network to the second. For example, to kill all of the state entries originating from -.Li host : -.Bd -literal -offset indent -# pfctl -k host -.Ed +.Dq host : +.Pp +.Dl # pfctl -k host .Pp To kill all of the state entries from -.Li host1 +.Dq host1 to -.Li host2 : -.Bd -literal -offset indent -# pfctl -k host1 -k host2 -.Ed +.Dq host2 : +.Pp +.Dl # pfctl -k host1 -k host2 +.Pp +To kill all states originating from 192.168.1.0/24 to 172.16.0.0/16: +.Pp +.Dl # pfctl -k 192.168.1.0/24 -k 172.16.0.0/16 +.Pp +A network prefix length of 0 can be used as a wildcard. +To kill all states with the target +.Dq host2 : +.Pp +.Dl # pfctl -k 0.0.0.0/0 -k host2 .It Fl m Merge in explicitly given options without resetting those which are omitted. @@ -253,11 +296,22 @@ Do not actually load rules, just parse them. .It Fl O Load only the options present in the rule file. Other rules and options are ignored. -.It Fl o -Enable the ruleset optimizer. +.It Fl o Op Ar level +Control the ruleset optimizer. The ruleset optimizer attempts to improve rulesets by removing rule duplication and making better use of rule ordering. -Specifically, it does four things: +.Pp +.Bl -tag -width xxxxxxxxxxxx -compact +.It Fl o Cm none +Disable the ruleset optimizer. +.It Fl o Cm basic +Enable basic ruleset optimizations. +.It Fl o Cm profile +Enable basic ruleset optimizations with profiling. +.El +.Pp +.Cm basic +optimization does does four things: .Pp .Bl -enum -compact .It @@ -270,10 +324,10 @@ combine multiple rules into a table when advantageous re-order the rules to improve evaluation performance .El .Pp -A second -.Fl o -may be specified to use the currently loaded ruleset as a feedback profile -to tailor the optimization of the +If +.Cm profile +is specified, the currently loaded ruleset will be examined as a feedback +profile to tailor the optimization of the .Ar quick rules to the actual network behavior. .Pp @@ -286,6 +340,14 @@ the ruleset optimizer should not be used or a .Ar label field should be added to all of the accounting rules to act as optimization barriers. +.Pp +To retain compatibility with previous behaviour, a single +.Fl o +without any options will enable +.Cm basic +optimizations, and a second +.Fl o +will enable profiling. .It Fl p Ar device Use the device file .Ar device @@ -350,7 +412,8 @@ When used together with .Fl v , source tracking statistics are also shown. .It Fl s Cm labels -Show per-rule statistics (label, evaluations, packets, bytes) of +Show per-rule statistics (label, evaluations, packets total, bytes total, +packets in, bytes in, packets out, bytes out) of filter rules with labels, useful for accounting. .It Fl s Cm timeouts Show the current global timeouts. @@ -362,8 +425,11 @@ Show the list of tables. Show the list of operating system fingerprints. .It Fl s Cm Interfaces Show the list of interfaces and interface drivers available to PF. -When used together with a double +When used together with .Fl v , +it additionally lists which interfaces have skip rules activated. +When used together with +.Fl vv , interface statistics are also shown. .Fl i can be used to select an interface or a group of interfaces. @@ -387,6 +453,13 @@ Add one or more addresses in a table. Automatically create a nonexisting table. .It Fl T Cm delete Delete one or more addresses from a table. +.It Fl T Cm expire Ar number +Delete addresses which had their statistics cleared more than +.Ar number +seconds ago. +For entries which have never had their statistics cleared, +.Ar number +refers to the time they were added to the table. .It Fl T Cm replace Replace the addresses of the table. Automatically create a nonexisting table. @@ -463,7 +536,7 @@ The following commands configure the firewall and send 10 pings to the FTP server: .Bd -literal -offset indent # printf "table { ftp.openbsd.org }\en \e - pass out to keep state\en" | pfctl -f- + pass out to \en" | pfctl -f- # ping -qc10 ftp.openbsd.org .Ed .Pp diff --git a/contrib/pf/pfctl/pfctl.c b/contrib/pf/pfctl/pfctl.c index 2e628e5..cf338c7 100644 --- a/contrib/pf/pfctl/pfctl.c +++ b/contrib/pf/pfctl/pfctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl.c,v 1.234 2005/03/07 13:52:50 henning Exp $ */ +/* $OpenBSD: pfctl.c,v 1.262 2007/03/01 17:20:53 deraadt Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -65,6 +66,8 @@ int pfctl_clear_nat(int, int, char *); int pfctl_clear_altq(int, int); int pfctl_clear_src_nodes(int, int); int pfctl_clear_states(int, const char *, int); +void pfctl_addrprefix(char *, struct pf_addr *); +int pfctl_kill_src_nodes(int, const char *, int); int pfctl_kill_states(int, const char *, int); void pfctl_init_options(struct pfctl *); int pfctl_load_options(struct pfctl *); @@ -76,7 +79,7 @@ int pfctl_load_hostid(struct pfctl *, unsigned int); int pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int, char *); void pfctl_print_rule_counters(struct pf_rule *, int); -int pfctl_show_rules(int, int, int, char *); +int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int); int pfctl_show_nat(int, int, char *); int pfctl_show_src_nodes(int, int); int pfctl_show_states(int, const char *, int); @@ -84,20 +87,29 @@ int pfctl_show_status(int, int); int pfctl_show_timeouts(int, int); int pfctl_show_limits(int, int); void pfctl_debug(int, u_int32_t, int); -int pfctl_clear_rule_counters(int, int); int pfctl_test_altqsupport(int, int); int pfctl_show_anchors(int, int, char *); +int pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *); +int pfctl_load_ruleset(struct pfctl *, char *, + struct pf_ruleset *, int, int); +int pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int); const char *pfctl_lookup_option(char *, const char **); +struct pf_anchor_global pf_anchors; +struct pf_anchor pf_main_anchor; + const char *clearopt; char *rulesopt; const char *showopt; const char *debugopt; char *anchoropt; +const char *optiopt = NULL; char *pf_device = "/dev/pf"; char *ifaceopt; char *tableopt; const char *tblcmdopt; +int src_node_killers; +char *src_node_kill[2]; int state_killers; char *state_kill[2]; int loadopt; @@ -109,14 +121,25 @@ int labels = 0; const char *infile; +#define INDENT(d, o) do { \ + if (o) { \ + int i; \ + for (i=0; i < d; i++) \ + printf(" "); \ + } \ + } while (0); \ + + static const struct { const char *name; int index; } pf_limits[] = { - { "states", PF_LIMIT_STATES }, - { "src-nodes", PF_LIMIT_SRC_NODES }, - { "frags", PF_LIMIT_FRAGS }, - { NULL, 0 } + { "states", PF_LIMIT_STATES }, + { "src-nodes", PF_LIMIT_SRC_NODES }, + { "frags", PF_LIMIT_FRAGS }, + { "tables", PF_LIMIT_TABLES }, + { "table-entries", PF_LIMIT_TABLE_ENTRIES }, + { NULL, 0 } }; struct pf_hint { @@ -189,27 +212,28 @@ static const char *showopt_list[] = { static const char *tblcmdopt_list[] = { "kill", "flush", "add", "delete", "load", "replace", "show", - "test", "zero", NULL + "test", "zero", "expire", NULL }; static const char *debugopt_list[] = { "none", "urgent", "misc", "loud", NULL }; +static const char *optiopt_list[] = { + "o", "none", "basic", "profile", NULL +}; void usage(void) { extern char *__progname; - fprintf(stderr, "usage: %s [-AdeghmNnOoqRrvz] ", __progname); + fprintf(stderr, "usage: %s [-AdeghmNnOqRrvz] ", __progname); fprintf(stderr, "[-a anchor] [-D macro=value] [-F modifier]\n"); - fprintf(stderr, " "); - fprintf(stderr, "[-f file] [-i interface] [-k host] "); - fprintf(stderr, "[-p device] [-s modifier]\n"); - fprintf(stderr, " "); - fprintf(stderr, "[-t table -T command [address ...]] "); - fprintf(stderr, "[-x level]\n"); + fprintf(stderr, "\t[-f file] [-i interface] [-K host | network] "); + fprintf(stderr, "[-k host | network ]\n"); + fprintf(stderr, "\t[-o [level]] [-p device] [-s modifier ]\n"); + fprintf(stderr, "\t[-t table -T command [address ...]] [-x level]\n"); exit(1); } @@ -268,7 +292,7 @@ pfctl_clear_interface_flags(int dev, int opts) if ((opts & PF_OPT_NOACTION) == 0) { bzero(&pi, sizeof(pi)); - pi.pfiio_flags = PFI_IFLAG_SETABLE_MASK; + pi.pfiio_flags = PFI_IFLAG_SKIP; if (ioctl(dev, DIOCCLRIFFLAG, &pi)) err(1, "DIOCCLRIFFLAG"); @@ -358,6 +382,163 @@ pfctl_clear_states(int dev, const char *iface, int opts) return (0); } +void +pfctl_addrprefix(char *addr, struct pf_addr *mask) +{ + char *p; + const char *errstr; + int prefix, ret_ga, q, r; + struct addrinfo hints, *res; + + if ((p = strchr(addr, '/')) == NULL) + return; + + *p++ = '\0'; + prefix = strtonum(p, 0, 128, &errstr); + if (errstr) + errx(1, "prefix is %s: %s", errstr, p); + + bzero(&hints, sizeof(hints)); + /* prefix only with numeric addresses */ + hints.ai_flags |= AI_NUMERICHOST; + + if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) { + errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); + /* NOTREACHED */ + } + + if (res->ai_family == AF_INET && prefix > 32) + errx(1, "prefix too long for AF_INET"); + else if (res->ai_family == AF_INET6 && prefix > 128) + errx(1, "prefix too long for AF_INET6"); + + q = prefix >> 3; + r = prefix & 7; + switch (res->ai_family) { + case AF_INET: + bzero(&mask->v4, sizeof(mask->v4)); + mask->v4.s_addr = htonl((u_int32_t) + (0xffffffffffULL << (32 - prefix))); + break; + case AF_INET6: + bzero(&mask->v6, sizeof(mask->v6)); + if (q > 0) + memset((void *)&mask->v6, 0xff, q); + if (r > 0) + *((u_char *)&mask->v6 + q) = + (0xff00 >> r) & 0xff; + break; + } + freeaddrinfo(res); +} + +int +pfctl_kill_src_nodes(int dev, const char *iface, int opts) +{ + struct pfioc_src_node_kill psnk; + struct addrinfo *res[2], *resp[2]; + struct sockaddr last_src, last_dst; + int killed, sources, dests; + int ret_ga; + + killed = sources = dests = 0; + + memset(&psnk, 0, sizeof(psnk)); + memset(&psnk.psnk_src.addr.v.a.mask, 0xff, + sizeof(psnk.psnk_src.addr.v.a.mask)); + memset(&last_src, 0xff, sizeof(last_src)); + memset(&last_dst, 0xff, sizeof(last_dst)); + + pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask); + + if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) { + errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); + /* NOTREACHED */ + } + for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { + if (resp[0]->ai_addr == NULL) + continue; + /* We get lots of duplicates. Catch the easy ones */ + if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) + continue; + last_src = *(struct sockaddr *)resp[0]->ai_addr; + + psnk.psnk_af = resp[0]->ai_family; + sources++; + + if (psnk.psnk_af == AF_INET) + psnk.psnk_src.addr.v.a.addr.v4 = + ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; + else if (psnk.psnk_af == AF_INET6) + psnk.psnk_src.addr.v.a.addr.v6 = + ((struct sockaddr_in6 *)resp[0]->ai_addr)-> + sin6_addr; + else + errx(1, "Unknown address family %d", psnk.psnk_af); + + if (src_node_killers > 1) { + dests = 0; + memset(&psnk.psnk_dst.addr.v.a.mask, 0xff, + sizeof(psnk.psnk_dst.addr.v.a.mask)); + memset(&last_dst, 0xff, sizeof(last_dst)); + pfctl_addrprefix(src_node_kill[1], + &psnk.psnk_dst.addr.v.a.mask); + if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL, + &res[1]))) { + errx(1, "getaddrinfo: %s", + gai_strerror(ret_ga)); + /* NOTREACHED */ + } + for (resp[1] = res[1]; resp[1]; + resp[1] = resp[1]->ai_next) { + if (resp[1]->ai_addr == NULL) + continue; + if (psnk.psnk_af != resp[1]->ai_family) + continue; + + if (memcmp(&last_dst, resp[1]->ai_addr, + sizeof(last_dst)) == 0) + continue; + last_dst = *(struct sockaddr *)resp[1]->ai_addr; + + dests++; + + if (psnk.psnk_af == AF_INET) + psnk.psnk_dst.addr.v.a.addr.v4 = + ((struct sockaddr_in *)resp[1]-> + ai_addr)->sin_addr; + else if (psnk.psnk_af == AF_INET6) + psnk.psnk_dst.addr.v.a.addr.v6 = + ((struct sockaddr_in6 *)resp[1]-> + ai_addr)->sin6_addr; + else + errx(1, "Unknown address family %d", + psnk.psnk_af); + + if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) + err(1, "DIOCKILLSRCNODES"); + killed += psnk.psnk_af; + /* fixup psnk.psnk_af */ + psnk.psnk_af = resp[1]->ai_family; + } + freeaddrinfo(res[1]); + } else { + if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) + err(1, "DIOCKILLSRCNODES"); + killed += psnk.psnk_af; + /* fixup psnk.psnk_af */ + psnk.psnk_af = res[0]->ai_family; + } + } + + freeaddrinfo(res[0]); + + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "killed %d src nodes from %d sources and %d " + "destinations\n", killed, sources, dests); + return (0); +} + int pfctl_kill_states(int dev, const char *iface, int opts) { @@ -378,6 +559,8 @@ pfctl_kill_states(int dev, const char *iface, int opts) sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) errx(1, "invalid interface: %s", iface); + pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask); + if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) { errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); /* NOTREACHED */ @@ -408,6 +591,8 @@ pfctl_kill_states(int dev, const char *iface, int opts) memset(&psk.psk_dst.addr.v.a.mask, 0xff, sizeof(psk.psk_dst.addr.v.a.mask)); memset(&last_dst, 0xff, sizeof(last_dst)); + pfctl_addrprefix(state_kill[1], + &psk.psk_dst.addr.v.a.mask); if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, &res[1]))) { errx(1, "getaddrinfo: %s", @@ -500,6 +685,17 @@ pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr, } void +pfctl_move_pool(struct pf_pool *src, struct pf_pool *dst) +{ + struct pf_pooladdr *pa; + + while ((pa = TAILQ_FIRST(&src->list)) != NULL) { + TAILQ_REMOVE(&src->list, pa, entries); + TAILQ_INSERT_TAIL(&dst->list, pa, entries); + } +} + +void pfctl_clear_pool(struct pf_pool *pool) { struct pf_pooladdr *pa; @@ -533,12 +729,18 @@ pfctl_print_rule_counters(struct pf_rule *rule, int opts) printf(" [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n", rule->qname, rule->qid, rule->pqname, rule->pqid); } - if (opts & PF_OPT_VERBOSE) + if (opts & PF_OPT_VERBOSE) { printf(" [ Evaluations: %-8llu Packets: %-8llu " "Bytes: %-10llu States: %-6u]\n", (unsigned long long)rule->evaluations, - (unsigned long long)rule->packets, - (unsigned long long)rule->bytes, rule->states); + (unsigned long long)(rule->packets[0] + + rule->packets[1]), + (unsigned long long)(rule->bytes[0] + + rule->bytes[1]), rule->states); + if (!(opts & PF_OPT_DEBUG)) + printf(" [ Inserted: uid %u pid %u ]\n", + (unsigned)rule->cuid, (unsigned)rule->cpid); + } } void @@ -551,99 +753,160 @@ pfctl_print_title(char *title) } int -pfctl_show_rules(int dev, int opts, int format, char *anchorname) +pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, + char *anchorname, int depth) { struct pfioc_rule pr; u_int32_t nr, mnr, header = 0; int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); + int len = strlen(path); + int brace; + char *p; + + if (path[0]) + snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname); + else + snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname); memset(&pr, 0, sizeof(pr)); - memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); + memcpy(pr.anchor, path, sizeof(pr.anchor)); if (opts & PF_OPT_SHOWALL) { pr.rule.action = PF_PASS; if (ioctl(dev, DIOCGETRULES, &pr)) { warn("DIOCGETRULES"); - return (-1); + goto error; } header++; } pr.rule.action = PF_SCRUB; if (ioctl(dev, DIOCGETRULES, &pr)) { warn("DIOCGETRULES"); - return (-1); + goto error; } if (opts & PF_OPT_SHOWALL) { - if (format == 0 && (pr.nr > 0 || header)) + if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header)) pfctl_print_title("FILTER RULES:"); - else if (format == 1 && labels) + else if (format == PFCTL_SHOW_LABELS && labels) pfctl_print_title("LABEL COUNTERS:"); } mnr = pr.nr; + if (opts & PF_OPT_CLRRULECTRS) + pr.action = PF_GET_CLR_CNTR; + for (nr = 0; nr < mnr; ++nr) { pr.nr = nr; if (ioctl(dev, DIOCGETRULE, &pr)) { warn("DIOCGETRULE"); - return (-1); + goto error; } if (pfctl_get_pool(dev, &pr.rule.rpool, - nr, pr.ticket, PF_SCRUB, anchorname) != 0) - return (-1); + nr, pr.ticket, PF_SCRUB, path) != 0) + goto error; switch (format) { - case 1: + case PFCTL_SHOW_LABELS: if (pr.rule.label[0]) { printf("%s ", pr.rule.label); - printf("%llu %llu %llu\n", + printf("%llu %llu %llu %llu %llu %llu %llu\n", (unsigned long long)pr.rule.evaluations, - (unsigned long long)pr.rule.packets, - (unsigned long long)pr.rule.bytes); + (unsigned long long)(pr.rule.packets[0] + + pr.rule.packets[1]), + (unsigned long long)(pr.rule.bytes[0] + + pr.rule.bytes[1]), + (unsigned long long)pr.rule.packets[0], + (unsigned long long)pr.rule.bytes[0], + (unsigned long long)pr.rule.packets[1], + (unsigned long long)pr.rule.bytes[1]); } break; - default: + case PFCTL_SHOW_RULES: if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) labels = 1; print_rule(&pr.rule, pr.anchor_call, rule_numbers); + printf("\n"); pfctl_print_rule_counters(&pr.rule, opts); + break; + case PFCTL_SHOW_NOTHING: + break; } pfctl_clear_pool(&pr.rule.rpool); } pr.rule.action = PF_PASS; if (ioctl(dev, DIOCGETRULES, &pr)) { warn("DIOCGETRULES"); - return (-1); + goto error; } mnr = pr.nr; for (nr = 0; nr < mnr; ++nr) { pr.nr = nr; if (ioctl(dev, DIOCGETRULE, &pr)) { warn("DIOCGETRULE"); - return (-1); + goto error; } if (pfctl_get_pool(dev, &pr.rule.rpool, - nr, pr.ticket, PF_PASS, anchorname) != 0) - return (-1); + nr, pr.ticket, PF_PASS, path) != 0) + goto error; switch (format) { - case 1: + case PFCTL_SHOW_LABELS: if (pr.rule.label[0]) { printf("%s ", pr.rule.label); - printf("%llu %llu %llu\n", + printf("%llu %llu %llu %llu %llu %llu %llu\n", (unsigned long long)pr.rule.evaluations, - (unsigned long long)pr.rule.packets, - (unsigned long long)pr.rule.bytes); + (unsigned long long)(pr.rule.packets[0] + + pr.rule.packets[1]), + (unsigned long long)(pr.rule.bytes[0] + + pr.rule.bytes[1]), + (unsigned long long)pr.rule.packets[0], + (unsigned long long)pr.rule.bytes[0], + (unsigned long long)pr.rule.packets[1], + (unsigned long long)pr.rule.bytes[1]); } break; - default: + case PFCTL_SHOW_RULES: + brace = 0; if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) labels = 1; - print_rule(&pr.rule, pr.anchor_call, rule_numbers); + INDENT(depth, !(opts & PF_OPT_VERBOSE)); + if (pr.anchor_call[0] && + ((((p = strrchr(pr.anchor_call, '_')) != NULL) && + ((void *)p == (void *)pr.anchor_call || + *(--p) == '/')) || (opts & PF_OPT_RECURSE))) { + brace++; + if ((p = strrchr(pr.anchor_call, '/')) != + NULL) + p++; + else + p = &pr.anchor_call[0]; + } else + p = &pr.anchor_call[0]; + + print_rule(&pr.rule, p, rule_numbers); + if (brace) + printf(" {\n"); + else + printf("\n"); pfctl_print_rule_counters(&pr.rule, opts); + if (brace) { + pfctl_show_rules(dev, path, opts, format, + p, depth + 1); + INDENT(depth, !(opts & PF_OPT_VERBOSE)); + printf("}\n"); + } + break; + case PFCTL_SHOW_NOTHING: + break; } pfctl_clear_pool(&pr.rule.rpool); } + path[len] = '\0'; return (0); + + error: + path[len] = '\0'; + return (-1); } int @@ -678,6 +941,7 @@ pfctl_show_nat(int dev, int opts, char *anchorname) } print_rule(&pr.rule, pr.anchor_call, opts & PF_OPT_VERBOSE2); + printf("\n"); pfctl_print_rule_counters(&pr.rule, opts); pfctl_clear_pool(&pr.rule.rpool); } @@ -705,16 +969,17 @@ pfctl_show_src_nodes(int dev, int opts) } if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) { warn("DIOCGETSRCNODES"); + free(inbuf); return (-1); } if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len) break; if (len == 0 && psn.psn_len == 0) - return (0); + goto done; if (len == 0 && psn.psn_len != 0) len = psn.psn_len; if (psn.psn_len == 0) - return (0); /* no src_nodes */ + goto done; /* no src_nodes */ len *= 2; } p = psn.psn_src_nodes; @@ -724,6 +989,8 @@ pfctl_show_src_nodes(int dev, int opts) print_src_node(p, opts); p++; } +done: + free(inbuf); return (0); } @@ -747,16 +1014,17 @@ pfctl_show_states(int dev, const char *iface, int opts) } if (ioctl(dev, DIOCGETSTATES, &ps) < 0) { warn("DIOCGETSTATES"); + free(inbuf); return (-1); } if (ps.ps_len + sizeof(struct pfioc_states) < len) break; if (len == 0 && ps.ps_len == 0) - return (0); + goto done; if (len == 0 && ps.ps_len != 0) len = ps.ps_len; if (ps.ps_len == 0) - return (0); /* no states */ + goto done; /* no states */ len *= 2; } p = ps.ps_states; @@ -769,6 +1037,8 @@ pfctl_show_states(int dev, const char *iface, int opts) } print_state(p, opts); } +done: + free(inbuf); return (0); } @@ -825,11 +1095,11 @@ pfctl_show_limits(int dev, int opts) pl.index = pf_limits[i].index; if (ioctl(dev, DIOCGETLIMIT, &pl)) err(1, "DIOCGETLIMIT"); - printf("%-10s ", pf_limits[i].name); + printf("%-13s ", pf_limits[i].name); if (pl.limit == UINT_MAX) printf("unlimited\n"); else - printf("hard limit %6u\n", pl.limit); + printf("hard limit %8u\n", pl.limit); } return (0); } @@ -860,93 +1130,186 @@ int pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call) { u_int8_t rs_num; - struct pfioc_rule pr; + struct pf_rule *rule; + struct pf_ruleset *rs; + char *p; - switch (r->action) { - case PF_SCRUB: - case PF_NOSCRUB: - if ((loadopt & PFCTL_FLAG_FILTER) == 0) - return (0); - rs_num = PF_RULESET_SCRUB; - break; - case PF_DROP: - case PF_PASS: - if ((loadopt & PFCTL_FLAG_FILTER) == 0) - return (0); - rs_num = PF_RULESET_FILTER; - break; - case PF_NAT: - case PF_NONAT: - if ((loadopt & PFCTL_FLAG_NAT) == 0) - return (0); - rs_num = PF_RULESET_NAT; - break; - case PF_RDR: - case PF_NORDR: - if ((loadopt & PFCTL_FLAG_NAT) == 0) - return (0); - rs_num = PF_RULESET_RDR; - break; - case PF_BINAT: - case PF_NOBINAT: - if ((loadopt & PFCTL_FLAG_NAT) == 0) - return (0); - rs_num = PF_RULESET_BINAT; - break; - default: + rs_num = pf_get_ruleset_number(r->action); + if (rs_num == PF_RULESET_MAX) errx(1, "Invalid rule type %d", r->action); - break; - } + rs = &pf->anchor->ruleset; - if ((pf->opts & PF_OPT_OPTIMIZE) && rs_num == PF_RULESET_FILTER) { - /* - * We'll do an optimization post-pass before finally adding the - * rules. Then we'll disable the optimization flag and feed - * the rules right back into this function. + if (anchor_call[0] && r->anchor == NULL) { + /* + * Don't make non-brace anchors part of the main anchor pool. */ - struct pf_opt_rule *pfr; - struct pf_pooladdr *pa; + if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL) + err(1, "pfctl_add_rule: calloc"); + + pf_init_ruleset(&r->anchor->ruleset); + r->anchor->ruleset.anchor = r->anchor; + if (strlcpy(r->anchor->path, anchor_call, + sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path)) + errx(1, "pfctl_add_rule: strlcpy"); + if ((p = strrchr(anchor_call, '/')) != NULL) { + if (!strlen(p)) + err(1, "pfctl_add_rule: bad anchor name %s", + anchor_call); + } else + p = (char *)anchor_call; + if (strlcpy(r->anchor->name, p, + sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name)) + errx(1, "pfctl_add_rule: strlcpy"); + } - if ((pfr = calloc(1, sizeof(*pfr))) == NULL) - err(1, "calloc"); - memcpy(&pfr->por_rule, r, sizeof(*r)); - if (strlcpy(pfr->por_anchor, anchor_call, - sizeof(pfr->por_anchor)) >= sizeof(pfr->por_anchor)) - errx(1, "pfctl_add_rule: strlcpy"); - TAILQ_INSERT_TAIL(&pf->opt_queue, pfr, por_entry); - - if (TAILQ_FIRST(&r->rpool.list) != NULL) { - TAILQ_INIT(&pfr->por_rule.rpool.list); - while ((pa = TAILQ_FIRST(&r->rpool.list)) != NULL) { - TAILQ_REMOVE(&r->rpool.list, pa, entries); - TAILQ_INSERT_TAIL(&pfr->por_rule.rpool.list, pa, - entries); + if ((rule = calloc(1, sizeof(*rule))) == NULL) + err(1, "calloc"); + bcopy(r, rule, sizeof(*rule)); + TAILQ_INIT(&rule->rpool.list); + pfctl_move_pool(&r->rpool, &rule->rpool); + + TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries); + return (0); +} + +int +pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a) +{ + int osize = pf->trans->pfrb_size; + + if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) { + if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) || + pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) || + pfctl_add_trans(pf->trans, PF_RULESET_RDR, path)) + return (1); + } + if (a == pf->astack[0] && ((altqsupport && + (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) { + if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path)) + return (2); + } + if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) { + if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) || + pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path)) + return (3); + } + if (pf->loadopt & PFCTL_FLAG_TABLE) + if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path)) + return (4); + if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize)) + return (5); + + return (0); +} + +int +pfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs, + int rs_num, int depth) +{ + struct pf_rule *r; + int error, len = strlen(path); + int brace = 0; + + pf->anchor = rs->anchor; + + if (path[0]) + snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name); + else + snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name); + + if (depth) { + if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) { + brace++; + if (pf->opts & PF_OPT_VERBOSE) + printf(" {\n"); + if ((pf->opts & PF_OPT_NOACTION) == 0 && + (error = pfctl_ruleset_trans(pf, + path, rs->anchor))) { + printf("pfctl_load_rulesets: " + "pfctl_ruleset_trans %d\n", error); + goto error; } - } else { - memset(&pfr->por_rule.rpool, 0, - sizeof(pfr->por_rule.rpool)); + } else if (pf->opts & PF_OPT_VERBOSE) + printf("\n"); - } - return (0); } + if (pf->optimize && rs_num == PF_RULESET_FILTER) + pfctl_optimize_ruleset(pf, rs); + + while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) { + TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries); + if ((error = pfctl_load_rule(pf, path, r, depth))) + goto error; + if (r->anchor) { + if ((error = pfctl_load_ruleset(pf, path, + &r->anchor->ruleset, rs_num, depth + 1))) + goto error; + } else if (pf->opts & PF_OPT_VERBOSE) + printf("\n"); + free(r); + } + if (brace && pf->opts & PF_OPT_VERBOSE) { + INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE)); + printf("}\n"); + } + path[len] = '\0'; + return (0); + + error: + path[len] = '\0'; + return (error); + +} + +int +pfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth) +{ + u_int8_t rs_num = pf_get_ruleset_number(r->action); + char *name; + struct pfioc_rule pr; + int len = strlen(path); + + bzero(&pr, sizeof(pr)); + /* set up anchor before adding to path for anchor_call */ + if ((pf->opts & PF_OPT_NOACTION) == 0) + pr.ticket = pfctl_get_ticket(pf->trans, rs_num, path); + if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor)) + errx(1, "pfctl_load_rule: strlcpy"); + + if (r->anchor) { + if (r->anchor->match) { + if (path[0]) + snprintf(&path[len], MAXPATHLEN - len, + "/%s", r->anchor->name); + else + snprintf(&path[len], MAXPATHLEN - len, + "%s", r->anchor->name); + name = path; + } else + name = r->anchor->path; + } else + name = ""; + if ((pf->opts & PF_OPT_NOACTION) == 0) { - bzero(&pr, sizeof(pr)); - if (strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor)) >= - sizeof(pr.anchor)) - errx(1, "pfctl_add_rule: strlcpy"); if (pfctl_add_pool(pf, &r->rpool, r->af)) return (1); - pr.ticket = pfctl_get_ticket(pf->trans, rs_num, pf->anchor); pr.pool_ticket = pf->paddr.ticket; memcpy(&pr.rule, r, sizeof(pr.rule)); - strlcpy(pr.anchor_call, anchor_call, sizeof(pr.anchor_call)); + if (r->anchor && strlcpy(pr.anchor_call, name, + sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call)) + errx(1, "pfctl_load_rule: strlcpy"); if (ioctl(pf->dev, DIOCADDRULE, &pr)) err(1, "DIOCADDRULE"); } - if (pf->opts & PF_OPT_VERBOSE) - print_rule(r, anchor_call, pf->opts & PF_OPT_VERBOSE2); + + if (pf->opts & PF_OPT_VERBOSE) { + INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2)); + print_rule(r, r->anchor ? r->anchor->name : "", + pf->opts & PF_OPT_VERBOSE2); + } + path[len] = '\0'; pfctl_clear_pool(&r->rpool); return (0); } @@ -974,86 +1337,86 @@ pfctl_add_altq(struct pfctl *pf, struct pf_altq *a) } int -pfctl_rules(int dev, char *filename, int opts, char *anchorname, - struct pfr_buffer *trans) +pfctl_rules(int dev, char *filename, FILE *fin, int opts, int optimize, + char *anchorname, struct pfr_buffer *trans) { #define ERR(x) do { warn(x); goto _error; } while(0) #define ERRX(x) do { warnx(x); goto _error; } while(0) - FILE *fin; struct pfr_buffer *t, buf; struct pfioc_altq pa; struct pfctl pf; + struct pf_ruleset *rs; struct pfr_table trs; + char *path; int osize; + RB_INIT(&pf_anchors); + memset(&pf_main_anchor, 0, sizeof(pf_main_anchor)); + pf_init_ruleset(&pf_main_anchor.ruleset); + pf_main_anchor.ruleset.anchor = &pf_main_anchor; if (trans == NULL) { - bzero(&buf, sizeof(buf)); - buf.pfrb_type = PFRB_TRANS; - t = &buf; - osize = 0; + bzero(&buf, sizeof(buf)); + buf.pfrb_type = PFRB_TRANS; + t = &buf; + osize = 0; } else { - t = trans; - osize = t->pfrb_size; + t = trans; + osize = t->pfrb_size; } memset(&pa, 0, sizeof(pa)); memset(&pf, 0, sizeof(pf)); memset(&trs, 0, sizeof(trs)); + if ((path = calloc(1, MAXPATHLEN)) == NULL) + ERRX("pfctl_rules: calloc"); if (strlcpy(trs.pfrt_anchor, anchorname, sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor)) ERRX("pfctl_rules: strlcpy"); - if (strcmp(filename, "-") == 0) { - fin = stdin; - infile = "stdin"; - } else { - if ((fin = pfctl_fopen(filename, "r")) == NULL) { - warn("%s", filename); - return (1); - } - infile = filename; - } + infile = filename; pf.dev = dev; pf.opts = opts; + pf.optimize = optimize; pf.loadopt = loadopt; + + /* non-brace anchor, create without resolving the path */ + if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL) + ERRX("pfctl_rules: calloc"); + rs = &pf.anchor->ruleset; + pf_init_ruleset(rs); + rs->anchor = pf.anchor; + if (strlcpy(pf.anchor->path, anchorname, + sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path)) + errx(1, "pfctl_add_rule: strlcpy"); + if (strlcpy(pf.anchor->name, anchorname, + sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name)) + errx(1, "pfctl_add_rule: strlcpy"); + + + pf.astack[0] = pf.anchor; + pf.asd = 0; if (anchorname[0]) pf.loadopt &= ~PFCTL_FLAG_ALTQ; pf.paltq = &pa; pf.trans = t; - pf.rule_nr = 0; - pf.anchor = anchorname; - TAILQ_INIT(&pf.opt_queue); pfctl_init_options(&pf); if ((opts & PF_OPT_NOACTION) == 0) { - if ((pf.loadopt & PFCTL_FLAG_NAT) != 0) { - if (pfctl_add_trans(t, PF_RULESET_NAT, anchorname) || - pfctl_add_trans(t, PF_RULESET_BINAT, anchorname) || - pfctl_add_trans(t, PF_RULESET_RDR, anchorname)) - ERR("pfctl_rules"); - } - if (((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))) { - if (pfctl_add_trans(t, PF_RULESET_ALTQ, anchorname)) - ERR("pfctl_rules"); - } - if ((pf.loadopt & PFCTL_FLAG_FILTER) != 0) { - if (pfctl_add_trans(t, PF_RULESET_SCRUB, anchorname) || - pfctl_add_trans(t, PF_RULESET_FILTER, anchorname)) - ERR("pfctl_rules"); - } - if (pf.loadopt & PFCTL_FLAG_TABLE) { - if (pfctl_add_trans(t, PF_RULESET_TABLE, anchorname)) - ERR("pfctl_rules"); - } - if (pfctl_trans(dev, t, DIOCXBEGIN, osize)) - ERR("DIOCXBEGIN"); + /* + * XXX For the time being we need to open transactions for + * the main ruleset before parsing, because tables are still + * loaded at parse time. + */ + if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor)) + ERRX("pfctl_rules"); if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ)) - pa.ticket = pfctl_get_ticket(t, PF_RULESET_ALTQ, - anchorname); + pa.ticket = + pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname); if (pf.loadopt & PFCTL_FLAG_TABLE) - pf.tticket = pfctl_get_ticket(t, PF_RULESET_TABLE, - anchorname); + pf.astack[0]->ruleset.tticket = + pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname); } + if (parse_rules(fin, &pf) < 0) { if ((opts & PF_OPT_NOACTION) == 0) ERRX("Syntax error in config file: " @@ -1061,9 +1424,19 @@ pfctl_rules(int dev, char *filename, int opts, char *anchorname, else goto _error; } - if (pf.opts & PF_OPT_OPTIMIZE) { - if (pfctl_optimize_rules(&pf)) - ERRX("Failed to optimize ruleset: pf rules not loaded"); + + if ((pf.loadopt & PFCTL_FLAG_FILTER && + (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) || + (pf.loadopt & PFCTL_FLAG_NAT && + (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) || + pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) || + pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) || + (pf.loadopt & PFCTL_FLAG_FILTER && + pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) { + if ((opts & PF_OPT_NOACTION) == 0) + ERRX("Unable to load rules into kernel"); + else + goto _error; } if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0)) @@ -1077,14 +1450,14 @@ pfctl_rules(int dev, char *filename, int opts, char *anchorname, /* process "load anchor" directives */ if (!anchorname[0]) - if (pfctl_load_anchors(dev, opts, t) == -1) + if (pfctl_load_anchors(dev, &pf, t) == -1) ERRX("load anchors"); if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) { if (!anchorname[0]) if (pfctl_load_options(&pf)) goto _error; - if (pfctl_trans(dev, t, DIOCXCOMMIT, 0)) + if (pfctl_trans(dev, t, DIOCXCOMMIT, osize)) ERR("DIOCXCOMMIT"); } return (0); @@ -1092,7 +1465,7 @@ pfctl_rules(int dev, char *filename, int opts, char *anchorname, _error: if (trans == NULL) { /* main ruleset */ if ((opts & PF_OPT_NOACTION) == 0) - if (pfctl_trans(dev, t, DIOCXROLLBACK, 0)) + if (pfctl_trans(dev, t, DIOCXROLLBACK, osize)) err(1, "DIOCXROLLBACK"); exit(1); } else { /* sub ruleset */ @@ -1129,6 +1502,9 @@ pfctl_fopen(const char *name, const char *mode) void pfctl_init_options(struct pfctl *pf) { + int mib[2], mem; + size_t size; + pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; @@ -1147,10 +1523,21 @@ pfctl_init_options(struct pfctl *pf) pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; - - pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT; - pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT; - pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT; + pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; + pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; + + pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT; + pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT; + pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT; + pf->limit[PF_LIMIT_TABLES] = PFR_KTABLE_HIWAT; + pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT; + + mib[0] = CTL_HW; + mib[1] = HW_PHYSMEM; + size = sizeof(mem); + (void) sysctl(mib, 2, &mem, &size, NULL, 0); + if (mem <= 100*1024*1024) + pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT_SMALL; pf->debug = PF_DEBUG_URGENT; } @@ -1171,6 +1558,21 @@ pfctl_load_options(struct pfctl *pf) error = 1; } + /* + * If we've set the limit, but havn't explicitly set adaptive + * timeouts, do it now with a start of 60% and end of 120%. + */ + if (pf->limit_set[PF_LIMIT_STATES] && + !pf->timeout_set[PFTM_ADAPTIVE_START] && + !pf->timeout_set[PFTM_ADAPTIVE_END]) { + pf->timeout[PFTM_ADAPTIVE_START] = + (pf->limit[PF_LIMIT_STATES] / 10) * 6; + pf->timeout_set[PFTM_ADAPTIVE_START] = 1; + pf->timeout[PFTM_ADAPTIVE_END] = + (pf->limit[PF_LIMIT_STATES] / 10) * 12; + pf->timeout_set[PFTM_ADAPTIVE_END] = 1; + } + /* load timeouts */ for (i = 0; i < PFTM_MAX; i++) { if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i]) @@ -1297,7 +1699,7 @@ pfctl_set_optimization(struct pfctl *pf, const char *opt) hint = pf_hints[i].hint; if (hint == NULL) { - warnx("Bad hint name."); + warnx("invalid state timeouts optimization"); return (1); } @@ -1343,7 +1745,7 @@ pfctl_load_logif(struct pfctl *pf, char *ifname) memset(&pi, 0, sizeof(pi)); if (ifname && strlcpy(pi.ifname, ifname, sizeof(pi.ifname)) >= sizeof(pi.ifname)) { - warnx("pfctl_set_logif: strlcpy"); + warnx("pfctl_load_logif: strlcpy"); return (1); } if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) { @@ -1480,16 +1882,6 @@ pfctl_debug(int dev, u_int32_t level, int opts) } int -pfctl_clear_rule_counters(int dev, int opts) -{ - if (ioctl(dev, DIOCCLRRULECTRS)) - err(1, "DIOCCLRRULECTRS"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "pf: rule counters cleared\n"); - return (0); -} - -int pfctl_test_altqsupport(int dev, int opts) { struct pfioc_altq pa; @@ -1537,8 +1929,9 @@ pfctl_show_anchors(int dev, int opts, char *anchorname) strlcat(sub, "/", sizeof(sub)); } strlcat(sub, pr.name, sizeof(sub)); - printf(" %s\n", sub); - if (opts & PF_OPT_VERBOSE && pfctl_show_anchors(dev, opts, sub)) + if (sub[0] != '_' || (opts & PF_OPT_VERBOSE)) + printf(" %s\n", sub); + if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub)) return (-1); } return (0); @@ -1557,17 +1950,20 @@ pfctl_lookup_option(char *cmd, const char **list) int main(int argc, char *argv[]) { - int error = 0; - int ch; - int mode = O_RDONLY; - int opts = 0; - char anchorname[MAXPATHLEN]; + int error = 0; + int ch; + int mode = O_RDONLY; + int opts = 0; + int optimize = 0; + char anchorname[MAXPATHLEN]; + char *path; + FILE *fin = NULL; if (argc < 2) usage(); while ((ch = getopt(argc, argv, - "a:AdD:eqf:F:ghi:k:mnNOop:rRs:t:T:vx:z")) != -1) { + "a:AdD:eqf:F:ghi:k:K:mnNOo::p:rRs:t:T:vx:z")) != -1) { switch (ch) { case 'a': anchoropt = optarg; @@ -1608,6 +2004,15 @@ main(int argc, char *argv[]) state_kill[state_killers++] = optarg; mode = O_RDWR; break; + case 'K': + if (src_node_killers >= 2) { + warnx("can only specify -K twice"); + usage(); + /* NOTREACHED */ + } + src_node_kill[src_node_killers++] = optarg; + mode = O_RDWR; + break; case 'm': opts |= PF_OPT_MERGE; break; @@ -1634,10 +2039,25 @@ main(int argc, char *argv[]) loadopt |= PFCTL_FLAG_FILTER; break; case 'o': - if (opts & PF_OPT_OPTIMIZE) - opts |= PF_OPT_OPTIMIZE_PROFILE; - else - opts |= PF_OPT_OPTIMIZE; + if (optarg) { + optiopt = pfctl_lookup_option(optarg, + optiopt_list); + if (optiopt == NULL) { + warnx("Unknown optimization '%s'", + optarg); + usage(); + } + } + if (opts & PF_OPT_OPTIMIZE) { + if (optiopt != NULL) { + warnx("Cannot specify -o multiple times" + "with optimizer level"); + usage(); + } + optimize |= PF_OPTIMIZE_PROFILE; + } + optimize |= PF_OPTIMIZE_BASIC; + opts |= PF_OPT_OPTIMIZE; break; case 'O': loadopt |= PFCTL_FLAG_OPTION; @@ -1695,7 +2115,7 @@ main(int argc, char *argv[]) loadopt |= PFCTL_FLAG_TABLE; tblcmdopt = NULL; } else - mode = strchr("acdfkrz", ch) ? O_RDWR : O_RDONLY; + mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY; } else if (argc != optind) { warnx("unknown command line argument: %s ...", argv[optind]); usage(); @@ -1704,8 +2124,19 @@ main(int argc, char *argv[]) if (loadopt == 0) loadopt = ~0; + if ((path = calloc(1, MAXPATHLEN)) == NULL) + errx(1, "pfctl: calloc"); memset(anchorname, 0, sizeof(anchorname)); if (anchoropt != NULL) { + int len = strlen(anchoropt); + + if (anchoropt[len - 1] == '*') { + if (len >= 2 && anchoropt[len - 2] == '/') + anchoropt[len - 2] = '\0'; + else + anchoropt[len - 1] = '\0'; + opts |= PF_OPT_RECURSE; + } if (strlcpy(anchorname, anchoropt, sizeof(anchorname)) >= sizeof(anchorname)) errx(1, "anchor name '%s' too long", @@ -1739,11 +2170,13 @@ main(int argc, char *argv[]) break; case 'r': pfctl_load_fingerprints(dev, opts); - pfctl_show_rules(dev, opts, 0, anchorname); + pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES, + anchorname, 0); break; case 'l': pfctl_load_fingerprints(dev, opts); - pfctl_show_rules(dev, opts, 1, anchorname); + pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS, + anchorname, 0); break; case 'n': pfctl_load_fingerprints(dev, opts); @@ -1773,12 +2206,12 @@ main(int argc, char *argv[]) pfctl_load_fingerprints(dev, opts); pfctl_show_nat(dev, opts, anchorname); - pfctl_show_rules(dev, opts, 0, anchorname); + pfctl_show_rules(dev, path, opts, 0, anchorname, 0); pfctl_show_altq(dev, ifaceopt, opts, 0); pfctl_show_states(dev, ifaceopt, opts); pfctl_show_src_nodes(dev, opts); pfctl_show_status(dev, opts); - pfctl_show_rules(dev, opts, 1, anchorname); + pfctl_show_rules(dev, path, opts, 1, anchorname, 0); pfctl_show_timeouts(dev, opts); pfctl_show_limits(dev, opts); pfctl_show_tables(anchorname, opts); @@ -1797,7 +2230,15 @@ main(int argc, char *argv[]) } } + if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL) + pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING, + anchorname, 0); + if (clearopt != NULL) { + if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) + errx(1, "anchor names beginning with '_' cannot " + "be modified from the command line"); + switch (*clearopt) { case 'r': pfctl_clear_rules(dev, opts, anchorname); @@ -1841,13 +2282,40 @@ main(int argc, char *argv[]) if (state_killers) pfctl_kill_states(dev, ifaceopt, opts); + if (src_node_killers) + pfctl_kill_src_nodes(dev, ifaceopt, opts); + if (tblcmdopt != NULL) { error = pfctl_command_tables(argc, argv, tableopt, tblcmdopt, rulesopt, anchorname, opts); rulesopt = NULL; } + if (optiopt != NULL) { + switch (*optiopt) { + case 'n': + optimize = 0; + break; + case 'b': + optimize |= PF_OPTIMIZE_BASIC; + break; + case 'o': + case 'p': + optimize |= PF_OPTIMIZE_PROFILE; + break; + } + } - if ((rulesopt != NULL) && (!*anchorname)) + if (rulesopt != NULL) { + if (strcmp(rulesopt, "-") == 0) { + fin = stdin; + rulesopt = "stdin"; + } else { + if ((fin = pfctl_fopen(rulesopt, "r")) == NULL) + err(1, "%s", rulesopt); + } + } + if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) && + !anchorname[0]) if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET)) error = 1; @@ -1857,7 +2325,11 @@ main(int argc, char *argv[]) error = 1; if (rulesopt != NULL) { - if (pfctl_rules(dev, rulesopt, opts, anchorname, NULL)) + if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) + errx(1, "anchor names beginning with '_' cannot " + "be modified from the command line"); + if (pfctl_rules(dev, rulesopt, fin, opts, optimize, + anchorname, NULL)) error = 1; else if (!(opts & PF_OPT_NOACTION) && (loadopt & PFCTL_FLAG_TABLE)) @@ -1885,9 +2357,5 @@ main(int argc, char *argv[]) } } - if (opts & PF_OPT_CLRRULECTRS) { - if (pfctl_clear_rule_counters(dev, opts)) - error = 1; - } exit(error); } diff --git a/contrib/pf/pfctl/pfctl.h b/contrib/pf/pfctl/pfctl.h index 3b943dc..9450a55 100644 --- a/contrib/pf/pfctl/pfctl.h +++ b/contrib/pf/pfctl/pfctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl.h,v 1.37 2005/01/05 18:23:10 mcbride Exp $ */ +/* $OpenBSD: pfctl.h,v 1.40 2007/02/09 11:25:27 henning Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -33,6 +33,8 @@ #ifndef _PFCTL_H_ #define _PFCTL_H_ +enum pfctl_show { PFCTL_SHOW_RULES, PFCTL_SHOW_LABELS, PFCTL_SHOW_NOTHING }; + enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS, PFRB_IFACES, PFRB_TRANS, PFRB_MAX }; struct pfr_buffer { @@ -73,7 +75,7 @@ int pfr_buf_grow(struct pfr_buffer *, int); int pfr_buf_load(struct pfr_buffer *, char *, int, int (*)(struct pfr_buffer *, char *, int)); char *pfr_strerror(int); -int pfi_get_ifaces(const char *, struct pfi_if *, int *, int); +int pfi_get_ifaces(const char *, struct pfi_kif *, int *); int pfi_clr_istats(const char *, int *, int); void pfctl_print_title(char *); @@ -106,7 +108,6 @@ extern int loadopt; int check_commit_altq(int, int); void pfaltq_store(struct pf_altq *); -void pfaltq_free(struct pf_altq *); struct pf_altq *pfaltq_lookup(const char *); char *rate2str(double); diff --git a/contrib/pf/pfctl/pfctl_altq.c b/contrib/pf/pfctl/pfctl_altq.c index 3f5b087..b4faaa0 100644 --- a/contrib/pf/pfctl/pfctl_altq.c +++ b/contrib/pf/pfctl/pfctl_altq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_altq.c,v 1.86 2005/02/28 14:04:51 henning Exp $ */ +/* $OpenBSD: pfctl_altq.c,v 1.91 2006/11/28 00:08:50 henning Exp $ */ /* * Copyright (c) 2002 @@ -93,21 +93,6 @@ pfaltq_store(struct pf_altq *a) TAILQ_INSERT_TAIL(&altqs, altq, entries); } -void -pfaltq_free(struct pf_altq *a) -{ - struct pf_altq *altq; - - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(a->ifname, altq->ifname, IFNAMSIZ) == 0 && - strncmp(a->qname, altq->qname, PF_QNAME_SIZE) == 0) { - TAILQ_REMOVE(&altqs, altq, entries); - free(altq); - return; - } - } -} - struct pf_altq * pfaltq_lookup(const char *ifname) { @@ -157,7 +142,7 @@ print_altq(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw, struct node_queue_opt *qopts) { if (a->qname[0] != 0) { - print_queue(a, level, bw, 0, qopts); + print_queue(a, level, bw, 1, qopts); return; } @@ -238,8 +223,8 @@ eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw, pa->ifbandwidth = bw->bw_absolute; else if ((rate = getifspeed(pa->ifname)) == 0) { - fprintf(stderr, "cannot determine interface bandwidth " - "for %s, specify an absolute bandwidth\n", + fprintf(stderr, "interface %s does not know its bandwidth, " + "please specify an absolute bandwidth\n", pa->ifname); errors++; } else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0) @@ -490,10 +475,7 @@ cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa) maxidle = ptime * maxidle; else maxidle = ptime * maxidle_s; - if (minburst) - offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom); - else - offtime = cptime; + offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom); minidle = -((double)opts->maxpktsize * (double)nsPerByte); /* scale parameters */ @@ -698,8 +680,8 @@ eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa) } if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) || - (opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) || - (opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0)) { + (opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) || + (opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) { warnx("m1 must be zero for convex curve: %s", pa->qname); return (-1); } diff --git a/contrib/pf/pfctl/pfctl_optimize.c b/contrib/pf/pfctl/pfctl_optimize.c index 6c6803e..37d9320 100644 --- a/contrib/pf/pfctl/pfctl_optimize.c +++ b/contrib/pf/pfctl/pfctl_optimize.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_optimize.c,v 1.5 2005/01/03 15:18:10 frantzen Exp $ */ +/* $OpenBSD: pfctl_optimize.c,v 1.13 2006/10/31 14:17:45 mcbride Exp $ */ /* * Copyright (c) 2004 Mike Frantzen @@ -109,6 +109,10 @@ struct pf_rule_field { PF_RULE_FIELD(prob, BARRIER), PF_RULE_FIELD(max_states, BARRIER), PF_RULE_FIELD(max_src_nodes, BARRIER), + PF_RULE_FIELD(max_src_states, BARRIER), + PF_RULE_FIELD(max_src_conn, BARRIER), + PF_RULE_FIELD(max_src_conn_rate, BARRIER), + PF_RULE_FIELD(anchor, BARRIER), /* for now */ /* * These fields must be the same between all rules in the same superblock. @@ -120,10 +124,18 @@ struct pf_rule_field { PF_RULE_FIELD(tagname, BREAK), PF_RULE_FIELD(keep_state, BREAK), PF_RULE_FIELD(qname, BREAK), + PF_RULE_FIELD(pqname, BREAK), PF_RULE_FIELD(rt, BREAK), PF_RULE_FIELD(allow_opts, BREAK), PF_RULE_FIELD(rule_flag, BREAK), PF_RULE_FIELD(action, BREAK), + PF_RULE_FIELD(log, BREAK), + PF_RULE_FIELD(quick, BREAK), + PF_RULE_FIELD(return_ttl, BREAK), + PF_RULE_FIELD(overload_tblname, BREAK), + PF_RULE_FIELD(flush, BREAK), + PF_RULE_FIELD(rpool, BREAK), + PF_RULE_FIELD(logif, BREAK), /* * Any fields not listed in this structure act as BREAK fields @@ -137,7 +149,7 @@ struct pf_rule_field { */ PF_RULE_FIELD(af, NOMERGE), PF_RULE_FIELD(ifnot, NOMERGE), - PF_RULE_FIELD(ifname, NOMERGE), + PF_RULE_FIELD(ifname, NOMERGE), /* hack for IF groups */ PF_RULE_FIELD(match_tag_not, NOMERGE), PF_RULE_FIELD(match_tagname, NOMERGE), PF_RULE_FIELD(os_fingerprint, NOMERGE), @@ -170,7 +182,6 @@ struct pf_rule_field { PF_RULE_FIELD(packets, DC), PF_RULE_FIELD(bytes, DC), PF_RULE_FIELD(kif, DC), - PF_RULE_FIELD(anchor, DC), PF_RULE_FIELD(states, DC), PF_RULE_FIELD(src_nodes, DC), PF_RULE_FIELD(nr, DC), @@ -179,6 +190,9 @@ struct pf_rule_field { PF_RULE_FIELD(pqid, DC), PF_RULE_FIELD(anchor_relative, DC), PF_RULE_FIELD(anchor_wildcard, DC), + PF_RULE_FIELD(tag, DC), + PF_RULE_FIELD(match_tag, DC), + PF_RULE_FIELD(overload_tbl, DC), /* These fields should never be set in a PASS/BLOCK rule */ PF_RULE_FIELD(natpass, NEVER), @@ -198,6 +212,7 @@ void comparable_rule(struct pf_rule *, const struct pf_rule *, int); int construct_superblocks(struct pfctl *, struct pf_opt_queue *, struct superblocks *); void exclude_supersets(struct pf_rule *, struct pf_rule *); +int interface_group(const char *); int load_feedback_profile(struct pfctl *, struct superblocks *); int optimize_superblock(struct pfctl *, struct superblock *); int pf_opt_create_table(struct pfctl *, struct pf_opt_tbl *); @@ -240,25 +255,52 @@ int table_identifier; int -pfctl_optimize_rules(struct pfctl *pf) +pfctl_optimize_ruleset(struct pfctl *pf, struct pf_ruleset *rs) { struct superblocks superblocks; + struct pf_opt_queue opt_queue; struct superblock *block; struct pf_opt_rule *por; - int nr; + struct pf_rule *r; + struct pf_rulequeue *old_rules; DEBUG("optimizing ruleset"); memset(&table_buffer, 0, sizeof(table_buffer)); skip_init(); + TAILQ_INIT(&opt_queue); - if (TAILQ_FIRST(&pf->opt_queue)) - nr = TAILQ_FIRST(&pf->opt_queue)->por_rule.nr; + old_rules = rs->rules[PF_RULESET_FILTER].active.ptr; + rs->rules[PF_RULESET_FILTER].active.ptr = + rs->rules[PF_RULESET_FILTER].inactive.ptr; + rs->rules[PF_RULESET_FILTER].inactive.ptr = old_rules; + + /* + * XXX expanding the pf_opt_rule format throughout pfctl might allow + * us to avoid all this copying. + */ + while ((r = TAILQ_FIRST(rs->rules[PF_RULESET_FILTER].inactive.ptr)) + != NULL) { + TAILQ_REMOVE(rs->rules[PF_RULESET_FILTER].inactive.ptr, r, + entries); + if ((por = calloc(1, sizeof(*por))) == NULL) + err(1, "calloc"); + memcpy(&por->por_rule, r, sizeof(*r)); + if (TAILQ_FIRST(&r->rpool.list) != NULL) { + TAILQ_INIT(&por->por_rule.rpool.list); + pfctl_move_pool(&r->rpool, &por->por_rule.rpool); + } else + bzero(&por->por_rule.rpool, + sizeof(por->por_rule.rpool)); + + + TAILQ_INSERT_TAIL(&opt_queue, por, por_entry); + } TAILQ_INIT(&superblocks); - if (construct_superblocks(pf, &pf->opt_queue, &superblocks)) + if (construct_superblocks(pf, &opt_queue, &superblocks)) goto error; - if (pf->opts & PF_OPT_OPTIMIZE_PROFILE) { + if (pf->optimize & PF_OPTIMIZE_PROFILE) { if (load_feedback_profile(pf, &superblocks)) goto error; } @@ -268,24 +310,21 @@ pfctl_optimize_rules(struct pfctl *pf) goto error; } - - /* - * Optimizations are done so we turn off the optimization flag and - * put the rules right back into the regular codepath. - */ - pf->opts &= ~PF_OPT_OPTIMIZE; - + rs->anchor->refcnt = 0; while ((block = TAILQ_FIRST(&superblocks))) { TAILQ_REMOVE(&superblocks, block, sb_entry); while ((por = TAILQ_FIRST(&block->sb_rules))) { TAILQ_REMOVE(&block->sb_rules, por, por_entry); - por->por_rule.nr = nr++; - if (pfctl_add_rule(pf, &por->por_rule, - por->por_anchor)) { - free(por); - goto error; - } + por->por_rule.nr = rs->anchor->refcnt++; + if ((r = calloc(1, sizeof(*r))) == NULL) + err(1, "calloc"); + memcpy(r, &por->por_rule, sizeof(*r)); + TAILQ_INIT(&r->rpool.list); + pfctl_move_pool(&por->por_rule.rpool, &r->rpool); + TAILQ_INSERT_TAIL( + rs->rules[PF_RULESET_FILTER].active.ptr, + r, entries); free(por); } free(block); @@ -294,8 +333,8 @@ pfctl_optimize_rules(struct pfctl *pf) return (0); error: - while ((por = TAILQ_FIRST(&pf->opt_queue))) { - TAILQ_REMOVE(&pf->opt_queue, por, por_entry); + while ((por = TAILQ_FIRST(&opt_queue))) { + TAILQ_REMOVE(&opt_queue, por, por_entry); if (por->por_src_tbl) { pfr_buf_clear(por->por_src_tbl->pt_buf); free(por->por_src_tbl->pt_buf); @@ -364,7 +403,8 @@ optimize_superblock(struct pfctl *pf, struct superblock *block) printf("--- Superblock ---\n"); TAILQ_FOREACH(por, &block->sb_rules, por_entry) { printf(" "); - print_rule(&por->por_rule, por->por_anchor, 1); + print_rule(&por->por_rule, por->por_rule.anchor ? + por->por_rule.anchor->name : "", 1); } #endif /* OPT_DEBUG */ @@ -373,7 +413,7 @@ optimize_superblock(struct pfctl *pf, struct superblock *block) return (1); if (combine_rules(pf, block)) return (1); - if ((pf->opts & PF_OPT_OPTIMIZE_PROFILE) && + if ((pf->optimize & PF_OPTIMIZE_PROFILE) && TAILQ_FIRST(&block->sb_rules)->por_rule.quick && block->sb_profiled_block) { if (block_feedback(pf, block)) @@ -780,14 +820,16 @@ block_feedback(struct pfctl *pf, struct superblock *block) */ TAILQ_FOREACH(por1, &block->sb_profiled_block->sb_rules, por_entry) { comparable_rule(&a, &por1->por_rule, DC); - total_count += por1->por_rule.packets; + total_count += por1->por_rule.packets[0] + + por1->por_rule.packets[1]; TAILQ_FOREACH(por2, &block->sb_rules, por_entry) { if (por2->por_profile_count) continue; comparable_rule(&b, &por2->por_rule, DC); if (memcmp(&a, &b, sizeof(a)) == 0) { por2->por_profile_count = - por1->por_rule.packets; + por1->por_rule.packets[0] + + por1->por_rule.packets[1]; break; } } @@ -851,6 +893,7 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks) DEBUG("Loading %d active rules for a feedback profile", mnr); for (nr = 0; nr < mnr; ++nr) { + struct pf_ruleset *rs; if ((por = calloc(1, sizeof(*por))) == NULL) { warn("calloc"); return (1); @@ -861,8 +904,8 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks) return (1); } memcpy(&por->por_rule, &pr.rule, sizeof(por->por_rule)); - strlcpy(por->por_anchor, pr.anchor_call, - sizeof(por->por_anchor)); + rs = pf_find_or_create_ruleset(pr.anchor_call); + por->por_rule.anchor = rs->anchor; if (TAILQ_EMPTY(&por->por_rule.rpool.list)) memset(&por->por_rule.rpool, 0, sizeof(por->por_rule.rpool)); @@ -1045,6 +1088,7 @@ skip_cmp_dst_addr(struct pf_rule *a, struct pf_rule *b) return (1); return (0); case PF_ADDR_NOROUTE: + case PF_ADDR_URPFFAILED: return (0); case PF_ADDR_TABLE: return (strcmp(a->dst.addr.v.tblname, b->dst.addr.v.tblname)); @@ -1116,6 +1160,7 @@ skip_cmp_src_addr(struct pf_rule *a, struct pf_rule *b) return (1); return (0); case PF_ADDR_NOROUTE: + case PF_ADDR_URPFFAILED: return (0); case PF_ADDR_TABLE: return (strcmp(a->src.addr.v.tblname, b->src.addr.v.tblname)); @@ -1267,8 +1312,8 @@ again: tablenum++; - if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1, pf->anchor, - tbl->pt_buf, pf->tticket)) { + if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1, + pf->anchor->name, tbl->pt_buf, pf->anchor->ruleset.tticket)) { warn("failed to create table %s", tbl->pt_name); return (1); } @@ -1367,15 +1412,34 @@ superblock_inclusive(struct superblock *block, struct pf_opt_rule *por) } } - /* 'anchor' heads and per-rule src-track are also hard breaks */ - if (por->por_anchor[0] != '\0' || - (por->por_rule.rule_flag & PFRULE_RULESRCTRACK)) + /* per-rule src-track is also a hard break */ + if (por->por_rule.rule_flag & PFRULE_RULESRCTRACK) return (0); + /* + * Have to handle interface groups seperately. Consider the following + * rules: + * block on EXTIFS to any port 22 + * pass on em0 to any port 22 + * (where EXTIFS is an arbitrary interface group) + * The optimizer may decide to re-order the pass rule in front of the + * block rule. But what if EXTIFS includes em0??? Such a reordering + * would change the meaning of the ruleset. + * We can't just lookup the EXTIFS group and check if em0 is a member + * because the user is allowed to add interfaces to a group during + * runtime. + * Ergo interface groups become a defacto superblock break :-( + */ + if (interface_group(por->por_rule.ifname) || + interface_group(TAILQ_FIRST(&block->sb_rules)->por_rule.ifname)) { + if (strcasecmp(por->por_rule.ifname, + TAILQ_FIRST(&block->sb_rules)->por_rule.ifname) != 0) + return (0); + } + comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, NOMERGE); comparable_rule(&b, &por->por_rule, NOMERGE); - if (strcmp(TAILQ_FIRST(&block->sb_rules)->por_anchor, - por->por_anchor) == 0 && memcmp(&a, &b, sizeof(a)) == 0) + if (memcmp(&a, &b, sizeof(a)) == 0) return (1); #ifdef OPT_DEBUG @@ -1419,6 +1483,24 @@ superblock_inclusive(struct superblock *block, struct pf_opt_rule *por) /* + * Figure out if an interface name is an actual interface or actually a + * group of interfaces. + */ +int +interface_group(const char *ifname) +{ + if (ifname == NULL || !ifname[0]) + return (0); + + /* Real interfaces must end in a number, interface groups do not */ + if (isdigit(ifname[strlen(ifname) - 1])) + return (0); + else + return (1); +} + + +/* * Make a rule that can directly compared by memcmp() */ void diff --git a/contrib/pf/pfctl/pfctl_osfp.c b/contrib/pf/pfctl/pfctl_osfp.c index 23e3ccc..7018d6c 100644 --- a/contrib/pf/pfctl/pfctl_osfp.c +++ b/contrib/pf/pfctl/pfctl_osfp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_osfp.c,v 1.12 2005/02/17 13:18:00 aaron Exp $ */ +/* $OpenBSD: pfctl_osfp.c,v 1.15 2006/12/13 05:10:15 itojun Exp $ */ /* * Copyright (c) 2003 Mike Frantzen @@ -23,6 +23,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -240,6 +244,10 @@ pfctl_file_fingerprints(int dev, int opts, const char *fp_filename) sizeof(fp.fp_os.fp_subtype_nm)); add_fingerprint(dev, opts, &fp); + + fp.fp_flags |= (PF_OSFP_DF | PF_OSFP_INET6); + fp.fp_psize += sizeof(struct ip6_hdr) - sizeof(struct ip); + add_fingerprint(dev, opts, &fp); } if (class) @@ -250,6 +258,8 @@ pfctl_file_fingerprints(int dev, int opts, const char *fp_filename) free(subtype); if (desc) free(desc); + if (tcpopts) + free(tcpopts); fclose(in); @@ -762,7 +772,6 @@ sort_name_list(int opts, struct name_list *nml) LIST_INSERT_AFTER(nmlast, nm, nm_entry); nmlast = nm; } - return; } /* parse the next integer in a formatted config file line */ diff --git a/contrib/pf/pfctl/pfctl_parser.c b/contrib/pf/pfctl/pfctl_parser.c index 4d5ca0d..e7b3b85 100644 --- a/contrib/pf/pfctl/pfctl_parser.c +++ b/contrib/pf/pfctl/pfctl_parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.c,v 1.211 2004/12/07 10:33:41 dhartmei Exp $ */ +/* $OpenBSD: pfctl_parser.c,v 1.234 2006/10/31 23:46:24 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -54,6 +54,7 @@ #include #include #include +#include #include "pfctl_parser.h" #include "pfctl.h" @@ -66,6 +67,7 @@ void print_fromto(struct pf_rule_addr *, pf_osfp_t, struct pf_rule_addr *, u_int8_t, u_int8_t, int); int ifa_skip_if(const char *filter, struct node_host *p); +struct node_host *ifa_grouplookup(const char *, int); struct node_host *host_if(const char *, int); struct node_host *host_v4(const char *, int); struct node_host *host_v6(const char *, int); @@ -479,9 +481,11 @@ const char *pf_scounters[FCNT_MAX+1] = FCNT_NAMES; void print_status(struct pf_status *s, int opts) { - char statline[80], *running; - time_t runtime; - int i; + char statline[80], *running; + time_t runtime; + int i; + char buf[PF_MD5_DIGEST_LENGTH * 2 + 1]; + static const char hex[] = "0123456789abcdef"; runtime = time(NULL) - s->since; running = s->running ? "Enabled" : "Disabled"; @@ -515,7 +519,18 @@ print_status(struct pf_status *s, int opts) printf("%15s\n\n", "Debug: Loud"); break; } - printf("Hostid: 0x%08x\n\n", ntohl(s->hostid)); + + if (opts & PF_OPT_VERBOSE) { + printf("Hostid: 0x%08x\n", ntohl(s->hostid)); + + for (i = 0; i < PF_MD5_DIGEST_LENGTH; i++) { + buf[i + i] = hex[s->pf_chksum[i] >> 4]; + buf[i + i + 1] = hex[s->pf_chksum[i] & 0x0f]; + } + buf[i + i] = '\0'; + printf("Checksum: 0x%s\n\n", buf); + } + if (s->ifname[0] != 0) { printf("Interface Stats for %-16s %5s %16s\n", s->ifname, "IPv4", "IPv6"); @@ -623,7 +638,9 @@ print_src_node(struct pf_src_node *sn, int opts) printf(", expires in %.2u:%.2u:%.2u", sn->expire, min, sec); } - printf(", %u pkts, %u bytes", sn->packets, sn->bytes); + printf(", %llu pkts, %llu bytes", + sn->packets[0] + sn->packets[1], + sn->bytes[0] + sn->bytes[1]); switch (sn->ruletype) { case PF_NAT: if (sn->rule.nr != -1) @@ -656,10 +673,13 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) printf("@%d ", r->nr); if (r->action > PF_NORDR) printf("action(%d)", r->action); - else if (anchor_call[0]) - printf("%s \"%s\"", anchortypes[r->action], - anchor_call); - else { + else if (anchor_call[0]) { + if (anchor_call[0] == '_') { + printf("%s", anchortypes[r->action]); + } else + printf("%s \"%s\"", anchortypes[r->action], + anchor_call); + } else { printf("%s", actiontypes[r->action]); if (r->natpass) printf(" pass"); @@ -714,10 +734,22 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) printf(" in"); else if (r->direction == PF_OUT) printf(" out"); - if (r->log == 1) + if (r->log) { printf(" log"); - else if (r->log == 2) - printf(" log-all"); + if (r->log & ~PF_LOG || r->logif) { + int count = 0; + + printf(" ("); + if (r->log & PF_LOG_ALL) + printf("%sall", count++ ? ", " : ""); + if (r->log & PF_LOG_SOCKET_LOOKUP) + printf("%suser", count++ ? ", " : ""); + if (r->logif) + printf("%sto pflog%u", count++ ? ", " : "", + r->logif); + printf(")"); + } + } if (r->quick) printf(" quick"); if (r->ifname[0]) { @@ -767,7 +799,11 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) print_flags(r->flags); printf("/"); print_flags(r->flagset); - } + } else if (r->action == PF_PASS && + (!r->proto || r->proto == IPPROTO_TCP) && + !(r->rule_flag & PFRULE_FRAGMENT) && + !anchor_call[0] && r->keep_state) + printf(" flags any"); if (r->type) { const struct icmptypeent *it; @@ -792,7 +828,9 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) } if (r->tos) printf(" tos 0x%2.2x", r->tos); - if (r->keep_state == PF_STATE_NORMAL) + if (!r->keep_state && r->action == PF_PASS && !anchor_call[0]) + printf(" no state"); + else if (r->keep_state == PF_STATE_NORMAL) printf(" keep state"); else if (r->keep_state == PF_STATE_MODULATE) printf(" modulate state"); @@ -820,7 +858,7 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) opts = 1; if (r->rule_flag & PFRULE_SRCTRACK) opts = 1; - if (r->rule_flag & (PFRULE_IFBOUND | PFRULE_GRBOUND)) + if (r->rule_flag & PFRULE_IFBOUND) opts = 1; for (i = 0; !opts && i < PFTM_MAX; ++i) if (r->timeout[i]) @@ -888,12 +926,6 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) printf("if-bound"); opts = 0; } - if (r->rule_flag & PFRULE_GRBOUND) { - if (!opts) - printf(", "); - printf("group-bound"); - opts = 0; - } for (i = 0; i < PFTM_MAX; ++i) if (r->timeout[i]) { int j; @@ -901,12 +933,13 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) if (!opts) printf(", "); opts = 0; - for (j = 0; j < sizeof(pf_timeouts) / - sizeof(pf_timeouts[0]); ++j) + for (j = 0; pf_timeouts[j].name != NULL; + ++j) if (pf_timeouts[j].timeout == i) break; - printf("%s %u", j == PFTM_MAX ? "inv.timeout" : - pf_timeouts[j].name, r->timeout[i]); + printf("%s %u", pf_timeouts[j].name == NULL ? + "inv.timeout" : pf_timeouts[j].name, + r->timeout[i]); } printf(")"); } @@ -946,13 +979,14 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) printf(" !"); printf(" tagged %s", r->match_tagname); } + if (r->rtableid != -1) + printf(" rtable %u", r->rtableid); if (!anchor_call[0] && (r->action == PF_NAT || r->action == PF_BINAT || r->action == PF_RDR)) { printf(" -> "); print_pool(&r->rpool, r->rpool.proxy_port[0], r->rpool.proxy_port[1], r->af, r->action); } - printf("\n"); } void @@ -1145,13 +1179,31 @@ ifa_load(void) } struct node_host * -ifa_exists(const char *ifa_name, int group_ok) +ifa_exists(const char *ifa_name) { struct node_host *n; + struct ifgroupreq ifgr; + int s; if (iftab == NULL) ifa_load(); + /* check wether this is a group */ + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + err(1, "socket"); + bzero(&ifgr, sizeof(ifgr)); + strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name)); + if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == 0) { + /* fake a node_host */ + if ((n = calloc(1, sizeof(*n))) == NULL) + err(1, "calloc"); + if ((n->ifname = strdup(ifa_name)) == NULL) + err(1, "strdup"); + close(s); + return (n); + } + close(s); + for (n = iftab; n; n = n->next) { if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) return (n); @@ -1161,12 +1213,56 @@ ifa_exists(const char *ifa_name, int group_ok) } struct node_host * +ifa_grouplookup(const char *ifa_name, int flags) +{ + struct ifg_req *ifg; + struct ifgroupreq ifgr; + int s, len; + struct node_host *n, *h = NULL; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + err(1, "socket"); + bzero(&ifgr, sizeof(ifgr)); + strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name)); + if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) { + close(s); + return (NULL); + } + + len = ifgr.ifgr_len; + if ((ifgr.ifgr_groups = calloc(1, len)) == NULL) + err(1, "calloc"); + if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) + err(1, "SIOCGIFGMEMB"); + + for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req); + ifg++) { + len -= sizeof(struct ifg_req); + if ((n = ifa_lookup(ifg->ifgrq_member, flags)) == NULL) + continue; + if (h == NULL) + h = n; + else { + h->tail->next = n; + h->tail = n->tail; + } + } + free(ifgr.ifgr_groups); + close(s); + + return (h); +} + +struct node_host * ifa_lookup(const char *ifa_name, int flags) { struct node_host *p = NULL, *h = NULL, *n = NULL; int got4 = 0, got6 = 0; const char *last_if = NULL; + if ((h = ifa_grouplookup(ifa_name, flags)) != NULL) + return (h); + if (!strncmp(ifa_name, "self", IFNAMSIZ)) ifa_name = NULL; @@ -1344,7 +1440,7 @@ host_if(const char *s, int mask) free(ps); return (NULL); } - if (ifa_exists(ps, 1) || !strncmp(ps, "self", IFNAMSIZ)) { + if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) { /* interface with this name exists */ h = ifa_lookup(ps, flags); for (n = h; n != NULL && mask > -1; n = n->next) diff --git a/contrib/pf/pfctl/pfctl_parser.h b/contrib/pf/pfctl/pfctl_parser.h index 5f32942..b901fb9 100644 --- a/contrib/pf/pfctl/pfctl_parser.h +++ b/contrib/pf/pfctl/pfctl_parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.h,v 1.80 2005/02/07 18:18:14 david Exp $ */ +/* $OpenBSD: pfctl_parser.h,v 1.86 2006/10/31 23:46:25 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -47,14 +47,17 @@ #define PF_OPT_DEBUG 0x0200 #define PF_OPT_SHOWALL 0x0400 #define PF_OPT_OPTIMIZE 0x0800 -#define PF_OPT_OPTIMIZE_PROFILE 0x1000 #define PF_OPT_MERGE 0x2000 +#define PF_OPT_RECURSE 0x4000 #define PF_TH_ALL 0xFF #define PF_NAT_PROXY_PORT_LOW 50001 #define PF_NAT_PROXY_PORT_HIGH 65535 +#define PF_OPTIMIZE_BASIC 0x0001 +#define PF_OPTIMIZE_PROFILE 0x0002 + #define FCNT_NAMES { \ "searches", \ "inserts", \ @@ -63,24 +66,25 @@ } struct pfr_buffer; /* forward definition */ -struct pf_opt_rule; -TAILQ_HEAD(pf_opt_queue, pf_opt_rule); struct pfctl { int dev; int opts; + int optimize; int loadopt; - u_int32_t tticket; /* table ticket */ + int asd; /* anchor stack depth */ + int bn; /* brace number */ + int brace; int tdirty; /* kernel dirty */ - u_int32_t rule_nr; +#define PFCTL_ANCHOR_STACK_DEPTH 64 + struct pf_anchor *astack[PFCTL_ANCHOR_STACK_DEPTH]; struct pfioc_pooladdr paddr; struct pfioc_altq *paltq; struct pfioc_queue *pqueue; struct pfr_buffer *trans; - const char *anchor; + struct pf_anchor *anchor, *alast; const char *ruleset; - struct pf_opt_queue opt_queue; /* 'set foo' options */ u_int32_t timeout[PFTM_MAX]; @@ -117,10 +121,6 @@ struct node_host { struct node_host *next; struct node_host *tail; }; -/* special flags used by ifa_exists */ -#define PF_IFA_FLAG_GROUP 0x10000 -#define PF_IFA_FLAG_DYNAMIC 0x20000 -#define PF_IFA_FLAG_CLONABLE 0x40000 struct node_os { char *os; @@ -180,19 +180,20 @@ struct pf_opt_rule { struct pf_rule por_rule; struct pf_opt_tbl *por_src_tbl; struct pf_opt_tbl *por_dst_tbl; - char por_anchor[MAXPATHLEN]; u_int64_t por_profile_count; TAILQ_ENTRY(pf_opt_rule) por_entry; TAILQ_ENTRY(pf_opt_rule) por_skip_entry[PF_SKIP_COUNT]; }; +TAILQ_HEAD(pf_opt_queue, pf_opt_rule); -int pfctl_rules(int, char *, int, char *, struct pfr_buffer *); -int pfctl_optimize_rules(struct pfctl *); +int pfctl_rules(int, char *, FILE *, int, int, char *, struct pfr_buffer *); +int pfctl_optimize_ruleset(struct pfctl *, struct pf_ruleset *); int pfctl_add_rule(struct pfctl *, struct pf_rule *, const char *); int pfctl_add_altq(struct pfctl *, struct pf_altq *); int pfctl_add_pool(struct pfctl *, struct pf_pool *, sa_family_t); +void pfctl_move_pool(struct pf_pool *, struct pf_pool *); void pfctl_clear_pool(struct pf_pool *); int pfctl_set_timeout(struct pfctl *, const char *, int, int); @@ -205,7 +206,7 @@ int pfctl_set_interface_flags(struct pfctl *, char *, int, int); int parse_rules(FILE *, struct pfctl *); int parse_flags(char *); -int pfctl_load_anchors(int, int, struct pfr_buffer *); +int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *); void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int); void print_src_node(struct pf_src_node *, int); @@ -267,7 +268,7 @@ void set_ipmask(struct node_host *, u_int8_t); int check_netmask(struct node_host *, sa_family_t); int unmask(struct pf_addr *, sa_family_t); void ifa_load(void); -struct node_host *ifa_exists(const char *, int); +struct node_host *ifa_exists(const char *); struct node_host *ifa_lookup(const char *, int); struct node_host *host(const char *); diff --git a/contrib/pf/pfctl/pfctl_radix.c b/contrib/pf/pfctl/pfctl_radix.c index ba004b8..01ad475 100644 --- a/contrib/pf/pfctl/pfctl_radix.c +++ b/contrib/pf/pfctl/pfctl_radix.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_radix.c,v 1.26 2004/06/14 20:44:22 cedric Exp $ */ +/* $OpenBSD: pfctl_radix.c,v 1.27 2005/05/21 21:03:58 henning Exp $ */ /* * Copyright (c) 2002 Cedric Berger @@ -421,7 +421,7 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, /* interface management code */ int -pfi_get_ifaces(const char *filter, struct pfi_if *buf, int *size, int flags) +pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size) { struct pfioc_iface io; @@ -430,7 +430,6 @@ pfi_get_ifaces(const char *filter, struct pfi_if *buf, int *size, int flags) return (-1); } bzero(&io, sizeof io); - io.pfiio_flags = flags; if (filter != NULL) if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >= sizeof(io.pfiio_name)) { @@ -451,7 +450,7 @@ pfi_get_ifaces(const char *filter, struct pfi_if *buf, int *size, int flags) size_t buf_esize[PFRB_MAX] = { 0, sizeof(struct pfr_table), sizeof(struct pfr_tstats), sizeof(struct pfr_addr), sizeof(struct pfr_astats), - sizeof(struct pfi_if), sizeof(struct pfioc_trans_e) + sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e) }; /* diff --git a/contrib/pf/pfctl/pfctl_table.c b/contrib/pf/pfctl/pfctl_table.c index 9c7ba5b..bee5786 100644 --- a/contrib/pf/pfctl/pfctl_table.c +++ b/contrib/pf/pfctl/pfctl_table.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_table.c,v 1.62 2004/12/22 17:17:55 dhartmei Exp $ */ +/* $OpenBSD: pfctl_table.c,v 1.66 2007/03/01 17:20:54 deraadt Exp $ */ /* * Copyright (c) 2002 Cedric Berger @@ -61,8 +61,7 @@ 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 xprintf(int, const char *, ...); -static void print_iface(struct pfi_if *, int); -static void oprintf(int, int, const char *, int *, int); +static void print_iface(struct pfi_kif *, int); static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = { { "In/Block:", "In/Pass:", "In/XPass:" }, @@ -175,7 +174,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command, break; } - if (opts & PF_OPT_SHOWALL && b.pfrb_size > 0) + if ((opts & PF_OPT_SHOWALL) && b.pfrb_size > 0) pfctl_print_title("TABLES:"); PFRB_FOREACH(p, &b) @@ -254,6 +253,42 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command, if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) print_addrx(a, NULL, opts & PF_OPT_USEDNS); + } else if (!strcmp(command, "expire")) { + const char *errstr; + u_int lifetime; + + b.pfrb_type = PFRB_ASTATS; + b2.pfrb_type = PFRB_ADDRS; + if (argc != 1 || file != NULL) + usage(); + lifetime = strtonum(*argv, 0, UINT_MAX, &errstr); + if (errstr) + errx(1, "expiry time: %s", errstr); + for (;;) { + pfr_buf_grow(&b, b.pfrb_size); + b.pfrb_size = b.pfrb_msize; + RVTEST(pfr_get_astats(&table, b.pfrb_caddr, + &b.pfrb_size, flags)); + if (b.pfrb_size <= b.pfrb_msize) + break; + } + PFRB_FOREACH(p, &b) + if (time(NULL) - ((struct pfr_astats *)p)->pfras_tzero > + lifetime) + if (pfr_buf_add(&b2, + &((struct pfr_astats *)p)->pfras_a)) + err(1, "duplicate buffer"); + + if (opts & PF_OPT_VERBOSE) + flags |= PFR_FLAG_FEEDBACK; + RVTEST(pfr_del_addrs(&table, b2.pfrb_caddr, b2.pfrb_size, + &ndel, flags)); + xprintf(opts, "%d/%d addresses expired", ndel, b2.pfrb_size); + if (opts & PF_OPT_VERBOSE) + PFRB_FOREACH(a, &b2) + if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) + print_addrx(a, NULL, + opts & PF_OPT_USEDNS); } else if (!strcmp(command, "show")) { b.pfrb_type = (opts & PF_OPT_VERBOSE) ? PFRB_ASTATS : PFRB_ADDRS; @@ -291,7 +326,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command, RVTEST(pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size, &nmatch, flags)); xprintf(opts, "%d/%d addresses match", nmatch, b.pfrb_size); - if (opts & PF_OPT_VERBOSE && !(opts & PF_OPT_VERBOSE2)) + if ((opts & PF_OPT_VERBOSE) && !(opts & PF_OPT_VERBOSE2)) PFRB_FOREACH(a, &b) if (a->pfra_fback == PFR_FB_MATCH) print_addrx(a, NULL, @@ -539,17 +574,15 @@ int pfctl_show_ifaces(const char *filter, int opts) { struct pfr_buffer b; - struct pfi_if *p; - int i = 0, f = PFI_FLAG_GROUP|PFI_FLAG_INSTANCE; + struct pfi_kif *p; + int i = 0; - if (filter != NULL && *filter && !isdigit(filter[strlen(filter)-1])) - f &= ~PFI_FLAG_INSTANCE; bzero(&b, sizeof(b)); b.pfrb_type = PFRB_IFACES; for (;;) { pfr_buf_grow(&b, b.pfrb_size); b.pfrb_size = b.pfrb_msize; - if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size, f)) { + if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) { radix_perror(); return (1); } @@ -565,46 +598,30 @@ pfctl_show_ifaces(const char *filter, int opts) } void -print_iface(struct pfi_if *p, int opts) +print_iface(struct pfi_kif *p, int opts) { - time_t tzero = p->pfif_tzero; - int flags = (opts & PF_OPT_VERBOSE) ? p->pfif_flags : 0; - int first = 1; + time_t tzero = p->pfik_tzero; int i, af, dir, act; - printf("%s", p->pfif_name); - oprintf(flags, PFI_IFLAG_INSTANCE, "instance", &first, 0); - oprintf(flags, PFI_IFLAG_GROUP, "group", &first, 0); - oprintf(flags, PFI_IFLAG_CLONABLE, "clonable", &first, 0); - oprintf(flags, PFI_IFLAG_DYNAMIC, "dynamic", &first, 0); - oprintf(flags, PFI_IFLAG_ATTACHED, "attached", &first, 0); - oprintf(flags, PFI_IFLAG_SKIP, "skipped", &first, 1); + printf("%s", p->pfik_name); + if (opts & PF_OPT_VERBOSE) { + if (p->pfik_flags & PFI_IFLAG_SKIP) + printf(" (skip)"); + } printf("\n"); if (!(opts & PF_OPT_VERBOSE2)) return; printf("\tCleared: %s", ctime(&tzero)); printf("\tReferences: [ States: %-18d Rules: %-18d ]\n", - p->pfif_states, p->pfif_rules); + p->pfik_states, p->pfik_rules); for (i = 0; i < 8; i++) { af = (i>>2) & 1; dir = (i>>1) &1; act = i & 1; printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", istats_text[af][dir][act], - (unsigned long long)p->pfif_packets[af][dir][act], - (unsigned long long)p->pfif_bytes[af][dir][act]); + (unsigned long long)p->pfik_packets[af][dir][act], + (unsigned long long)p->pfik_bytes[af][dir][act]); } } - -void -oprintf(int flags, int flag, const char *s, int *first, int last) -{ - if (flags & flag) { - printf(*first ? "\t(%s" : ", %s", s); - *first = 0; - } - if (last && !*first) - printf(")"); -} - -- cgit v1.1