summaryrefslogtreecommitdiffstats
path: root/contrib/pf/pfctl
diff options
context:
space:
mode:
authormlaier <mlaier@FreeBSD.org>2007-07-03 12:22:02 +0000
committermlaier <mlaier@FreeBSD.org>2007-07-03 12:22:02 +0000
commit95015692958ba836f46bad24f9e0e593f1a50520 (patch)
tree02a49070663d642b663044908c899617f0fd7bf0 /contrib/pf/pfctl
parent511d1c13c361b4534ed4c6f973fd891d95055cab (diff)
downloadFreeBSD-src-95015692958ba836f46bad24f9e0e593f1a50520.zip
FreeBSD-src-95015692958ba836f46bad24f9e0e593f1a50520.tar.gz
Import pf userland from OpenBSD 4.1 and (for ftp-proxy) libevent 1.3b as
a local lib.
Diffstat (limited to 'contrib/pf/pfctl')
-rw-r--r--contrib/pf/pfctl/parse.y642
-rw-r--r--contrib/pf/pfctl/pf_print_state.c12
-rw-r--r--contrib/pf/pfctl/pfctl.8147
-rw-r--r--contrib/pf/pfctl/pfctl.c888
-rw-r--r--contrib/pf/pfctl/pfctl.h7
-rw-r--r--contrib/pf/pfctl/pfctl_altq.c32
-rw-r--r--contrib/pf/pfctl/pfctl_optimize.c156
-rw-r--r--contrib/pf/pfctl/pfctl_osfp.c13
-rw-r--r--contrib/pf/pfctl/pfctl_parser.c154
-rw-r--r--contrib/pf/pfctl/pfctl_parser.h35
-rw-r--r--contrib/pf/pfctl/pfctl_radix.c7
-rw-r--r--contrib/pf/pfctl/pfctl_table.c89
12 files changed, 1610 insertions, 572 deletions
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 <v.string> STRING
%token <v.i> PORTBINARY
%type <v.interface> interface if_list if_item_not if_item
%type <v.number> number icmptype icmp6type uid gid
-%type <v.number> tos not yesno natpass
-%type <v.i> no dir log af fragcache sourcetrack flush
-%type <v.i> unaryop statelock
-%type <v.b> action nataction scrubaction
+%type <v.number> tos not yesno
+%type <v.i> no dir af fragcache optimizer
+%type <v.i> sourcetrack flush unaryop statelock
+%type <v.b> action nataction natpass scrubaction
%type <v.b> flags flag blockspec
%type <v.range> port rport
%type <v.hashkey> hashkey
@@ -437,10 +444,10 @@ typedef struct {
%type <v.gid> gids gid_list gid_item
%type <v.route> route
%type <v.redirection> redirection redirpool
-%type <v.string> label string tag
+%type <v.string> label string tag anchorname
%type <v.keep_state> keep
%type <v.state_opt> state_opt_spec state_opt_list state_opt_item
-%type <v.logquick> logquick
+%type <v.logquick> logquick quick log logopts logopt
%type <v.interface> antispoof_ifspc antispoof_iflst antispoof_if
%type <v.qassign> qname
%type <v.queue> qassign qassign_list qassign_item
@@ -456,6 +463,7 @@ typedef struct {
%type <v.table_opts> table_opts table_opt table_opts_l
%type <v.pool_opts> pool_opts pool_opt pool_opts_l
%type <v.tagged> tagged
+%type <v.rtableid> 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 <test> { ftp.openbsd.org }\en \e
- pass out to <test> keep state\en" | pfctl -f-
+ pass out to <test>\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 <net/pfvar.h>
#include <arpa/inet.h>
#include <altq/altq.h>
+#include <sys/sysctl.h>
#include <err.h>
#include <errno.h>
@@ -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 <frantzen@openbsd.org>
@@ -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 <frantzen@openbsd.org>
@@ -23,6 +23,10 @@
#include <net/if.h>
#include <net/pfvar.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
#include <ctype.h>
#include <err.h>
#include <errno.h>
@@ -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 <errno.h>
#include <err.h>
#include <ifaddrs.h>
+#include <unistd.h>
#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(")");
-}
-
OpenPOWER on IntegriCloud