summaryrefslogtreecommitdiff
path: root/sbin/pfctl/pfctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/pfctl/pfctl.c')
-rw-r--r--sbin/pfctl/pfctl.c346
1 files changed, 222 insertions, 124 deletions
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);