summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Thomas McBride <mcbride@cvs.openbsd.org>2006-10-28 14:29:06 +0000
committerRyan Thomas McBride <mcbride@cvs.openbsd.org>2006-10-28 14:29:06 +0000
commitfd5ded3ce298939bef9ffea34ce27adc59585ba5 (patch)
treefecb2c540c3e90a3ec063da750758e0387e4ce87
parentd10f28caa885276f258377fdc0868d6ae514360a (diff)
Load all rules into memory before loading into the kernel, and add support
for anchors loaded inline in pf.conf, enclosed in a brace-delimited block ("{" "}"). anchor on fxp0 { pass in proto tcp port 22 } The anchor name is optional on inline loaded anchors. testing ckuethe@ ok henning@ dhartmei@
-rw-r--r--sbin/pfctl/Makefile7
-rw-r--r--sbin/pfctl/parse.y138
-rw-r--r--sbin/pfctl/pfctl.c346
-rw-r--r--sbin/pfctl/pfctl_optimize.c88
-rw-r--r--sbin/pfctl/pfctl_parser.c18
-rw-r--r--sbin/pfctl/pfctl_parser.h19
6 files changed, 429 insertions, 187 deletions
diff --git a/sbin/pfctl/Makefile b/sbin/pfctl/Makefile
index 52763fde678..ef097355a1d 100644
--- a/sbin/pfctl/Makefile
+++ b/sbin/pfctl/Makefile
@@ -1,14 +1,17 @@
-# $OpenBSD: Makefile,v 1.17 2004/07/16 23:44:24 frantzen Exp $
+# $OpenBSD: Makefile,v 1.18 2006/10/28 14:29:05 mcbride Exp $
PROG= pfctl
SRCS= pfctl.c parse.y pfctl_parser.c pf_print_state.c pfctl_altq.c
SRCS+= pfctl_osfp.c pfctl_radix.c pfctl_table.c pfctl_qstats.c
-SRCS+= pfctl_optimize.c
+SRCS+= pfctl_optimize.c pf_ruleset.c
CFLAGS+= -Wall -Wmissing-prototypes -Wno-uninitialized
CFLAGS+= -Wstrict-prototypes -I${.CURDIR}
YFLAGS=
MAN= pfctl.8
+# Ruleset and Anchor handling
+.PATH: ${.CURDIR}/../../sys/net
+
LDADD+= -lm
DPADD+= ${LIBM}
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index e7116136a7b..128e87a6fa9 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.512 2006/10/25 14:50:30 henning Exp $ */
+/* $OpenBSD: parse.y,v 1.513 2006/10/28 14:29:05 mcbride Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -310,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);
@@ -443,7 +444,7 @@ 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 quick log logopts logopt
@@ -479,9 +480,22 @@ 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'
+ ;
+
option : SET OPTIMIZATION STRING {
if (check_rulestate(PFCTL_STATE_OPTION)) {
free($3);
@@ -547,7 +561,7 @@ option : SET OPTIMIZATION STRING {
free($3);
YYERROR;
}
- if (!pf->anchor[0]) {
+ if (!pf->anchor->name[0]) {
if (pfctl_file_fingerprints(pf->dev,
pf->opts, $3)) {
yyerror("error loading "
@@ -609,15 +623,84 @@ varset : STRING '=' string {
}
;
-anchorrule : ANCHOR string dir quick 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 tmp_anchorname[PF_ANCHOR_NAME_SIZE];
+ struct pf_ruleset *rs;
+
+ pf->asd++;
+ pf->bn++;
+ pf->brace = 1;
+ snprintf(tmp_anchorname, PF_ANCHOR_NAME_SIZE,
+ "_%d", pf->bn);
+ rs = pf_find_or_create_ruleset(tmp_anchorname);
+ 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)) {
- free($2);
+ if ($2)
+ free($2);
YYERROR;
}
memset(&r, 0, sizeof(r));
+ if (pf->astack[pf->asd + 1]) {
+ if ($2) {
+ struct pf_ruleset *src =
+ &pf->alast->ruleset;
+ struct pf_ruleset *dst =
+ pf_find_or_create_ruleset($2);
+
+ if (!dst)
+ err(1, "anchorrule: unable to "
+ "create ruleset");
+ if (dst->anchor->refcnt) {
+ yyerror("inline anchor "
+ "already exists\n");
+ YYERROR;
+ }
+
+ mv_rules(src, dst);
+ pf_remove_if_empty_ruleset(src);
+ pf->alast = dst->anchor;
+ }
+ r.anchor = pf->alast;
+ } else {
+ if (!$2) {
+ yyerror("anchors without explicit "
+ "rules must specify a name\n");
+ YYERROR;
+ }
+ }
r.direction = $3;
r.quick = $4.quick;
r.af = $6;
@@ -638,8 +721,10 @@ anchorrule : ANCHOR string dir quick interface af proto fromto filter_opts {
expand_rule(&r, $5, NULL, $7, $8.src_os,
$8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
- 0, 0, 0, $2);
+ 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 rtable {
struct pf_rule r;
@@ -744,7 +829,8 @@ anchorrule : ANCHOR string dir quick interface af proto fromto filter_opts {
loadrule : LOAD ANCHOR string FROM string {
struct loadanchors *loadanchor;
- if (strlen(pf->anchor) + 1 + 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);
@@ -756,9 +842,9 @@ loadrule : LOAD ANCHOR string FROM string {
if ((loadanchor->anchorname = malloc(MAXPATHLEN)) ==
NULL)
err(1, "loadrule: malloc");
- if (pf->anchor[0])
+ if (pf->anchor->name[0])
snprintf(loadanchor->anchorname, MAXPATHLEN,
- "%s/%s", pf->anchor, $3);
+ "%s/%s", pf->anchor->name, $3);
else
strlcpy(loadanchor->anchorname, $3, MAXPATHLEN);
if ((loadanchor->filename = strdup($5)) == NULL)
@@ -1630,7 +1716,7 @@ pfrule : action dir logquick interface route af proto fromto
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;
@@ -2962,7 +3048,7 @@ statelock : IFBOUND {
keep : NO STATE {
$$.action = 0;
- $$.options = NULL;
+ $$.options = NULL;
}
| KEEP STATE state_opt_spec {
$$.action = PF_STATE_NORMAL;
@@ -4029,7 +4115,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;
@@ -4221,7 +4307,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->refcnt);
expand_label_str(label, len, name, n);
}
}
@@ -4651,7 +4737,7 @@ expand_rule(struct pf_rule *r,
if (rule_consistent(r, anchor_call[0]) < 0 || error)
yyerror("skipping rule due to errors");
else {
- r->nr = pf->rule_nr++;
+ r->nr = pf->anchor->refcnt++;
pfctl_add_rule(pf, r, anchor_call);
added++;
}
@@ -5181,6 +5267,29 @@ symget(const char *nam)
}
void
+mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst)
+{
+ 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);
+ }
+ 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);
+ }
+ }
+ dst->anchor->refcnt = src->anchor->refcnt;
+ src->anchor->refcnt = 0;
+}
+
+void
decide_address_family(struct node_host *n, sa_family_t *af)
{
sa_family_t target_af = 0;
@@ -5356,4 +5465,3 @@ pfctl_load_anchors(int dev, int opts, struct pfr_buffer *trans)
return (0);
}
-
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 002e6ce4e3d..20b768965f8 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl.c,v 1.247 2006/06/30 16:52:27 deraadt Exp $ */
+/* $OpenBSD: pfctl.c,v 1.248 2006/10/28 14:29:05 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -77,7 +77,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, int, char *, int);
int pfctl_show_nat(int, int, char *);
int pfctl_show_src_nodes(int, int);
int pfctl_show_states(int, const char *, int);
@@ -88,8 +88,15 @@ 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;
@@ -110,6 +117,15 @@ 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;
@@ -557,6 +573,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;
@@ -614,26 +641,33 @@ 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, int 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);
+
+ 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))
@@ -646,12 +680,12 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname)
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:
@@ -680,19 +714,19 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname)
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:
@@ -713,12 +747,24 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname)
default:
if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
labels = 1;
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
print_rule(&pr.rule, pr.anchor_call, rule_numbers);
pfctl_print_rule_counters(&pr.rule, opts);
+ if (pr.anchor_call[0] == '_') {
+ pfctl_show_rules(dev, path, opts, format,
+ pr.anchor_call, depth + 1);
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+ printf("}\n");
+ }
}
pfctl_clear_pool(&pr.rule.rpool);
}
+ path[len] = '\0';
return (0);
+
+ error:
+ path[len] = '\0';
+ return (-1);
}
int
@@ -941,93 +987,134 @@ 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;
- 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.
- */
- struct pf_opt_rule *pfr;
- struct pf_pooladdr *pa;
- 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);
- }
- } else {
- memset(&pfr->por_rule.rpool, 0,
- sizeof(pfr->por_rule.rpool));
+ if (anchor_call[0] && r->anchor == NULL)
+ r->anchor = pf_find_or_create_ruleset(anchor_call)->anchor;
+
+ 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);
+
+ 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 (rs != &pf->astack[0]->ruleset &&
+ ((pf->opts & PF_OPT_NOACTION) == 0)) {
+ if ((error = pfctl_ruleset_trans(pf, path, rs->anchor))) {
+ printf("pfctl_load_rulesets: "
+ "pfctl_ruleset_trans %d\n", error);
+ goto error;
}
- return (0);
}
+ if ((pf->opts & PF_OPT_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 && r->anchor->name[0] == '_') {
+ if ((error = pfctl_load_ruleset(pf, path,
+ &r->anchor->ruleset, rs_num, depth + 1)))
+ goto error;
+ INDENT(depth, (pf->opts & PF_OPT_VERBOSE));
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("}\n");
+ }
+ free(r);
+ }
+ 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);
+ struct pfioc_rule pr;
+
if ((pf->opts & PF_OPT_NOACTION) == 0) {
bzero(&pr, sizeof(pr));
- if (strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor)) >=
+ if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >=
sizeof(pr.anchor))
- errx(1, "pfctl_add_rule: strlcpy");
+ errx(1, "pfctl_load_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.ticket = pfctl_get_ticket(pf->trans, rs_num, path);
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, r->anchor->name,
+ sizeof(pr.anchor_call)));
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);
+ }
pfctl_clear_pool(&r->rpool);
return (0);
}
@@ -1064,22 +1151,30 @@ pfctl_rules(int dev, char *filename, FILE *fin, int opts, char *anchorname,
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");
@@ -1087,44 +1182,32 @@ pfctl_rules(int dev, char *filename, FILE *fin, int opts, char *anchorname,
pf.dev = dev;
pf.opts = opts;
pf.loadopt = loadopt;
+ pf.anchor = pf_find_or_create_ruleset(anchorname)->anchor;
+ rs = &pf.anchor->ruleset;
+ 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: "
@@ -1132,9 +1215,19 @@ pfctl_rules(int dev, char *filename, FILE *fin, 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))
@@ -1155,7 +1248,7 @@ pfctl_rules(int dev, char *filename, FILE *fin, int opts, char *anchorname,
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);
@@ -1163,7 +1256,7 @@ pfctl_rules(int dev, char *filename, FILE *fin, 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 */
@@ -1824,17 +1917,22 @@ main(int argc, char *argv[])
error = 1;
if (showopt != NULL) {
+ char *path;
+
+ if ((path = calloc(1, MAXPATHLEN)) == NULL)
+ errx(1, "pfctl: calloc");
+
switch (*showopt) {
case 'A':
pfctl_show_anchors(dev, opts, anchorname);
break;
case 'r':
pfctl_load_fingerprints(dev, opts);
- pfctl_show_rules(dev, opts, 0, anchorname);
+ pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
break;
case 'l':
pfctl_load_fingerprints(dev, opts);
- pfctl_show_rules(dev, opts, 1, anchorname);
+ pfctl_show_rules(dev, path, opts, 1, anchorname, 0);
break;
case 'n':
pfctl_load_fingerprints(dev, opts);
@@ -1864,12 +1962,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);
diff --git a/sbin/pfctl/pfctl_optimize.c b/sbin/pfctl/pfctl_optimize.c
index a63494d553f..e041073569d 100644
--- a/sbin/pfctl/pfctl_optimize.c
+++ b/sbin/pfctl/pfctl_optimize.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_optimize.c,v 1.11 2006/10/25 14:50:21 henning Exp $ */
+/* $OpenBSD: pfctl_optimize.c,v 1.12 2006/10/28 14:29:05 mcbride Exp $ */
/*
* Copyright (c) 2004 Mike Frantzen <frantzen@openbsd.org>
@@ -112,6 +112,7 @@ struct pf_rule_field {
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.
@@ -181,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),
@@ -255,22 +255,49 @@ 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) {
@@ -283,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);
@@ -309,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);
@@ -379,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 */
@@ -868,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);
@@ -878,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));
@@ -1286,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);
}
@@ -1386,9 +1412,8 @@ 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);
/*
@@ -1414,8 +1439,7 @@ superblock_inclusive(struct superblock *block, struct pf_opt_rule *por)
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
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 20e67130427..4503048e069 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.c,v 1.232 2006/10/25 11:28:36 henning Exp $ */
+/* $OpenBSD: pfctl_parser.c,v 1.233 2006/10/28 14:29:05 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -668,15 +668,21 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
"anchor", "nat-anchor", "nat-anchor", "binat-anchor",
"binat-anchor", "rdr-anchor", "rdr-anchor" };
int i, opts;
+ int brace = 0;
if (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] == '_') {
+ brace++;
+ 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");
@@ -984,6 +990,8 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
print_pool(&r->rpool, r->rpool.proxy_port[0],
r->rpool.proxy_port[1], r->af, r->action);
}
+ if (brace)
+ printf(" {");
printf("\n");
}
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index c22a76e8389..a43ad9e3629 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.h,v 1.83 2005/11/17 20:52:39 dhartmei Exp $ */
+/* $OpenBSD: pfctl_parser.h,v 1.84 2006/10/28 14:29:05 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -63,24 +63,24 @@
}
struct pfr_buffer; /* forward definition */
-struct pf_opt_rule;
-TAILQ_HEAD(pf_opt_queue, pf_opt_rule);
struct pfctl {
int dev;
int opts;
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];
@@ -176,19 +176,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 *, FILE *, int, char *, struct pfr_buffer *);
-int pfctl_optimize_rules(struct pfctl *);
+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);