summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCedric Berger <cedric@cvs.openbsd.org>2003-09-26 21:44:10 +0000
committerCedric Berger <cedric@cvs.openbsd.org>2003-09-26 21:44:10 +0000
commit21ee0f9ceb87b49a8d22ccccf781aaa0955725ef (patch)
tree985658c81572fcf0d3626c19a360b7ec20878add
parent759e80db3df46eb4e1e8d02d28f6df859e880ec9 (diff)
Rearchitecture of the userland/kernel IOCTL interface for transactions.
This brings us close to 100% atomicity for a "pfctl -f pf.conf" command. (some splxxx work remain in the kernel). Basically, improvements are: - Anchors/Rulesets cannot disappear unexpectedly anymore. - No more leftover in the kernel if "pfctl -f" fail. - Commit is now done in a single atomic IOCTL. WARNING: The kernel code is fully backward compatible, but the new pfctl/authpf userland utilities will only run on a new kernel. The following ioctls are deprecated (i.e. will be deleted sooner or later, depending on how many 3rd party utilities use them and how soon they can be upgraded): - DIOCBEGINRULES - DIOCCOMMITRULES - DIOCBEGINALTQS - DIOCCOMMITALTQS - DIOCRINABEGIN - DIOCRINADEFINE They are replaced by the following ioctls (yes, PF(4) will follow) which operate on a vector of rulesets: - DIOCXBEGIN - DIOCXCOMMIT - DIOCXROLLBACK Ok dhartmei@ mcbride@
-rw-r--r--sbin/pfctl/parse.y6
-rw-r--r--sbin/pfctl/pfctl.c231
-rw-r--r--sbin/pfctl/pfctl.h9
-rw-r--r--sbin/pfctl/pfctl_parser.c45
-rw-r--r--sbin/pfctl/pfctl_parser.h8
-rw-r--r--sbin/pfctl/pfctl_radix.c3
-rw-r--r--sys/net/pf.c3
-rw-r--r--sys/net/pf_ioctl.c501
-rw-r--r--sys/net/pf_table.c33
-rw-r--r--sys/net/pfvar.h22
-rw-r--r--usr.sbin/authpf/authpf.c72
11 files changed, 633 insertions, 300 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index e633fcbe63a..a8f1515109a 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.415 2003/09/01 15:07:40 henning Exp $ */
+/* $OpenBSD: parse.y,v 1.416 2003/09/26 21:44:09 cedric Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -4471,7 +4471,7 @@ parseicmpspec(char *w, sa_family_t af)
}
int
-pfctl_load_anchors(int dev, int opts)
+pfctl_load_anchors(int dev, int opts, struct pfr_buffer *trans)
{
struct loadanchors *la;
@@ -4480,7 +4480,7 @@ pfctl_load_anchors(int dev, int opts)
fprintf(stderr, "\nLoading anchor %s:%s from %s\n",
la->anchorname, la->rulesetname, la->filename);
if (pfctl_rules(dev, la->filename, opts, la->anchorname,
- la->rulesetname) == -1)
+ la->rulesetname, trans) == -1)
return (-1);
}
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 0e52476aadd..7559328f3a8 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl.c,v 1.188 2003/08/29 21:47:36 cedric Exp $ */
+/* $OpenBSD: pfctl.c,v 1.189 2003/09/26 21:44:09 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -239,7 +239,7 @@ pfctl_clear_stats(int dev, int opts)
int
pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname)
{
- struct pfioc_rule pr;
+ struct pfr_buffer t;
if (*anchorname && !*rulesetname) {
struct pfioc_ruleset pr;
@@ -269,19 +269,13 @@ pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname)
fprintf(stderr, "rules cleared\n");
return (0);
}
- memset(&pr, 0, sizeof(pr));
- memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
- memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
- pr.rule.action = PF_SCRUB;
- if (ioctl(dev, DIOCBEGINRULES, &pr))
- err(1, "DIOCBEGINRULES");
- else if (ioctl(dev, DIOCCOMMITRULES, &pr))
- err(1, "DIOCCOMMITRULES");
- pr.rule.action = PF_PASS;
- if (ioctl(dev, DIOCBEGINRULES, &pr))
- err(1, "DIOCBEGINRULES");
- else if (ioctl(dev, DIOCCOMMITRULES, &pr))
- err(1, "DIOCCOMMITRULES");
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname, rulesetname) ||
+ pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname, rulesetname) ||
+ pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
+ pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "pfctl_clear_rules");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "rules cleared\n");
return (0);
@@ -290,7 +284,7 @@ pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname)
int
pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname)
{
- struct pfioc_rule pr;
+ struct pfr_buffer t;
if (*anchorname && !*rulesetname) {
struct pfioc_ruleset pr;
@@ -320,24 +314,14 @@ pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname)
fprintf(stderr, "nat cleared\n");
return (0);
}
- memset(&pr, 0, sizeof(pr));
- memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
- memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
- pr.rule.action = PF_NAT;
- if (ioctl(dev, DIOCBEGINRULES, &pr))
- err(1, "DIOCBEGINRULES");
- else if (ioctl(dev, DIOCCOMMITRULES, &pr))
- err(1, "DIOCCOMMITRULES");
- pr.rule.action = PF_BINAT;
- if (ioctl(dev, DIOCBEGINRULES, &pr))
- err(1, "DIOCBEGINRULES");
- else if (ioctl(dev, DIOCCOMMITRULES, &pr))
- err(1, "DIOCCOMMITRULES");
- pr.rule.action = PF_RDR;
- if (ioctl(dev, DIOCBEGINRULES, &pr))
- err(1, "DIOCBEGINRULES");
- else if (ioctl(dev, DIOCCOMMITRULES, &pr))
- err(1, "DIOCCOMMITRULES");
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname, rulesetname) ||
+ pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname, rulesetname) ||
+ pfctl_add_trans(&t, PF_RULESET_RDR, anchorname, rulesetname) ||
+ pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
+ pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "pfctl_clear_nat");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "nat cleared\n");
return (0);
@@ -346,15 +330,16 @@ pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname)
int
pfctl_clear_altq(int dev, int opts)
{
- struct pfioc_altq pa;
+ struct pfr_buffer t;
if (!altqsupport)
return (-1);
- memset(&pa, 0, sizeof(pa));
- if (ioctl(dev, DIOCBEGINALTQS, &pa.ticket))
- err(1, "DIOCBEGINALTQS");
- else if (ioctl(dev, DIOCCOMMITALTQS, &pa.ticket))
- err(1, "DIOCCOMMITALTQS");
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "", "") ||
+ pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
+ pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "pfctl_clear_altq");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "altq cleared\n");
return (0);
@@ -836,7 +821,8 @@ pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
int
pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
{
- u_int8_t rs_num;
+ u_int8_t rs_num;
+ struct pfioc_rule pr;
switch (r->action) {
case PF_SCRUB:
@@ -874,12 +860,19 @@ pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
}
if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ bzero(&pr, sizeof(pr));
+ if (strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor)) >=
+ sizeof(pr.anchor) ||
+ strlcpy(pr.ruleset, pf->ruleset, sizeof(pr.ruleset)) >=
+ sizeof(pr.ruleset))
+ errx(1, "pfctl_add_rule: strlcpy");
if (pfctl_add_pool(pf, &r->rpool, r->af))
return (1);
- memcpy(&pf->prule[rs_num]->rule, r,
- sizeof(pf->prule[rs_num]->rule));
- pf->prule[rs_num]->pool_ticket = pf->paddr.ticket;
- if (ioctl(pf->dev, DIOCADDRULE, pf->prule[rs_num]))
+ pr.ticket = pfctl_get_ticket(pf->trans, rs_num, pf->anchor,
+ pf->ruleset);
+ pr.pool_ticket = pf->paddr.ticket;
+ memcpy(&pr.rule, r, sizeof(pr.rule));
+ if (ioctl(pf->dev, DIOCADDRULE, &pr))
err(1, "DIOCADDRULE");
}
if (pf->opts & PF_OPT_VERBOSE)
@@ -912,26 +905,31 @@ pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
int
pfctl_rules(int dev, char *filename, int opts, char *anchorname,
- char *rulesetname)
+ char *rulesetname, 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 pfioc_rule pr[PF_RULESET_MAX];
+ struct pfr_buffer *t, buf;
struct pfioc_altq pa;
struct pfctl pf;
struct pfr_table trs;
- int i;
+ int osize;
+ if (trans == NULL) {
+ bzero(&buf, sizeof(buf));
+ buf.pfrb_type = PFRB_TRANS;
+ t = &buf;
+ osize = 0;
+ } else {
+ t = trans;
+ osize = t->pfrb_size;
+ }
+
memset(&pa, 0, sizeof(pa));
memset(&pf, 0, sizeof(pf));
memset(&trs, 0, sizeof(trs));
- for (i = 0; i < PF_RULESET_MAX; i++) {
- memset(&pr[i], 0, sizeof(pr[i]));
- memcpy(pr[i].anchor, anchorname, sizeof(pr[i].anchor));
- memcpy(pr[i].ruleset, rulesetname, sizeof(pr[i].ruleset));
- }
if (strlcpy(trs.pfrt_anchor, anchorname,
sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor) ||
strlcpy(trs.pfrt_ruleset, rulesetname,
@@ -947,46 +945,53 @@ pfctl_rules(int dev, char *filename, int opts, char *anchorname,
}
infile = filename;
}
- if ((opts & PF_OPT_NOACTION) == 0) {
- if ((loadopt & PFCTL_FLAG_NAT) != 0) {
- pr[PF_RULESET_NAT].rule.action = PF_NAT;
- if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_NAT]))
- ERR("DIOCBEGINRULES");
- pr[PF_RULESET_RDR].rule.action = PF_RDR;
- if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_RDR]))
- ERR("DIOCBEGINRULES");
- pr[PF_RULESET_BINAT].rule.action = PF_BINAT;
- if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_BINAT]))
- ERR("DIOCBEGINRULES");
- }
- if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) &&
- ioctl(dev, DIOCBEGINALTQS, &pa.ticket)) {
- ERR("DIOCBEGINALTQS");
- }
- if ((loadopt & PFCTL_FLAG_FILTER) != 0) {
- pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB;
- if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_SCRUB]))
- ERR("DIOCBEGINRULES");
- pr[PF_RULESET_FILTER].rule.action = PF_PASS;
- if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_FILTER]))
- ERR("DIOCBEGINRULES");
- }
- if (loadopt & PFCTL_FLAG_TABLE) {
- if (pfr_ina_begin(&trs, &pf.tticket, NULL, 0) != 0)
- ERR("begin table");
- }
- }
- /* fill in callback data */
pf.dev = dev;
pf.opts = opts;
pf.loadopt = loadopt;
+ if (anchorname[0])
+ pf.loadopt &= ~PFCTL_FLAG_ALTQ;
pf.paltq = &pa;
- for (i = 0; i < PF_RULESET_MAX; i++) {
- pf.prule[i] = &pr[i];
- }
+ pf.trans = t;
pf.rule_nr = 0;
pf.anchor = anchorname;
pf.ruleset = rulesetname;
+
+ if ((opts & PF_OPT_NOACTION) == 0) {
+ if ((pf.loadopt & PFCTL_FLAG_NAT) != 0) {
+ if (pfctl_add_trans(t, PF_RULESET_NAT, anchorname,
+ rulesetname) ||
+ pfctl_add_trans(t, PF_RULESET_BINAT, anchorname,
+ rulesetname) ||
+ pfctl_add_trans(t, PF_RULESET_RDR, anchorname,
+ rulesetname))
+ ERR("pfctl_rules");
+ }
+ if (((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))) {
+ if (pfctl_add_trans(t, PF_RULESET_ALTQ, anchorname,
+ rulesetname))
+ ERR("pfctl_rules");
+ }
+ if ((pf.loadopt & PFCTL_FLAG_FILTER) != 0) {
+ if (pfctl_add_trans(t, PF_RULESET_SCRUB, anchorname,
+ rulesetname) ||
+ pfctl_add_trans(t, PF_RULESET_FILTER, anchorname,
+ rulesetname))
+ ERR("pfctl_rules");
+ }
+ if (pf.loadopt & PFCTL_FLAG_TABLE) {
+ if (pfctl_add_trans(t, PF_RULESET_TABLE, anchorname,
+ rulesetname))
+ ERR("pfctl_rules");
+ }
+ if (pfctl_trans(dev, t, DIOCXBEGIN, osize))
+ ERR("DIOCXBEGIN");
+ if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
+ pa.ticket = pfctl_get_ticket(t, PF_RULESET_ALTQ,
+ anchorname, rulesetname);
+ if (pf.loadopt & PFCTL_FLAG_TABLE)
+ pf.tticket = pfctl_get_ticket(t, PF_RULESET_TABLE,
+ anchorname, rulesetname);
+ }
if (parse_rules(fin, &pf) < 0) {
if ((opts & PF_OPT_NOACTION) == 0)
ERRX("Syntax error in config file: "
@@ -994,57 +999,30 @@ pfctl_rules(int dev, char *filename, int opts, char *anchorname,
else
goto _error;
}
- if ((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0))
+ if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
if (check_commit_altq(dev, opts) != 0)
ERRX("errors in altq config");
- if ((opts & PF_OPT_NOACTION) == 0) {
- if ((loadopt & PFCTL_FLAG_NAT) != 0) {
- pr[PF_RULESET_NAT].rule.action = PF_NAT;
- if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_NAT]) &&
- (errno != EINVAL || pf.rule_nr))
- ERR("DIOCCOMMITRULES NAT");
- pr[PF_RULESET_RDR].rule.action = PF_RDR;
- if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_RDR]) &&
- (errno != EINVAL || pf.rule_nr))
- ERR("DIOCCOMMITRULES RDR");
- pr[PF_RULESET_BINAT].rule.action = PF_BINAT;
- if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_BINAT]) &&
- (errno != EINVAL || pf.rule_nr))
- ERR("DIOCCOMMITRULES BINAT");
- }
- if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) &&
- ioctl(dev, DIOCCOMMITALTQS, &pa.ticket))
- ERR("DIOCCOMMITALTQS");
- if ((loadopt & PFCTL_FLAG_FILTER) != 0) {
- pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB;
- if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_SCRUB]) &&
- (errno != EINVAL || pf.rule_nr))
- ERR("DIOCCOMMITRULES SCRUB");
- pr[PF_RULESET_FILTER].rule.action = PF_PASS;
- if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_FILTER]) &&
- (errno != EINVAL || pf.rule_nr))
- ERR("DIOCCOMMITRULES FILTER");
- }
- if (loadopt & PFCTL_FLAG_TABLE) {
- if (pfr_ina_commit(&trs, pf.tticket, NULL, NULL, 0))
- ERR("commit table");
- pf.tdirty = 0;
- }
- }
if (fin != stdin)
fclose(fin);
/* process "load anchor" directives */
if (!anchorname[0] && !rulesetname[0])
- if (pfctl_load_anchors(dev, opts) == -1)
+ if (pfctl_load_anchors(dev, opts, t) == -1)
ERRX("load anchors");
+ if (trans == NULL && (opts & PF_OPT_NOACTION) == 0)
+ if (pfctl_trans(dev, t, DIOCXCOMMIT, 0))
+ ERR("DIOCXCOMMIT");
return (0);
_error:
- if (pf.tdirty) /* cleanup kernel leftover */
- pfr_ina_begin(&trs, NULL, NULL, 0);
- exit(1);
+ if (trans == NULL) { /* main ruleset */
+ if ((opts & PF_OPT_NOACTION) == 0)
+ if (pfctl_trans(dev, t, DIOCXROLLBACK, 0))
+ err(1, "DIOCXROLLBACK");
+ exit(1);
+ } else /* sub ruleset */
+ return (-1);
#undef ERR
#undef ERRX
@@ -1590,7 +1568,8 @@ main(int argc, char *argv[])
error = 1;
if (rulesopt != NULL) {
- if (pfctl_rules(dev, rulesopt, opts, anchorname, rulesetname))
+ if (pfctl_rules(dev, rulesopt, opts, anchorname, rulesetname,
+ NULL))
error = 1;
else if (!(opts & PF_OPT_NOACTION) &&
(loadopt & PFCTL_FLAG_TABLE))
diff --git a/sbin/pfctl/pfctl.h b/sbin/pfctl/pfctl.h
index 2149ac14f96..cc18acf7039 100644
--- a/sbin/pfctl/pfctl.h
+++ b/sbin/pfctl/pfctl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl.h,v 1.25 2003/08/29 21:47:36 cedric Exp $ */
+/* $OpenBSD: pfctl.h,v 1.26 2003/09/26 21:44:09 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -33,7 +33,8 @@
#ifndef _PFCTL_H_
#define _PFCTL_H_
-enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS, PFRB_MAX };
+enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS, PFRB_TRANS,
+ PFRB_MAX };
struct pfr_buffer {
int pfrb_type; /* type of content, see enum above */
int pfrb_size; /* number of objects in buffer */
@@ -111,5 +112,9 @@ void print_state(struct pf_state *, int);
int unmask(struct pf_addr *, sa_family_t);
int pfctl_cmdline_symset(char *);
+int pfctl_add_trans(struct pfr_buffer *, int, const char *, const char *);
+u_int32_t
+ pfctl_get_ticket(struct pfr_buffer *, int, const char *, const char *);
+int pfctl_trans(int, struct pfr_buffer *, int, int);
#endif /* _PFCTL_H_ */
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 7c051ac4bd4..24d5c3fc13c 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.c,v 1.175 2003/09/18 20:27:58 cedric Exp $ */
+/* $OpenBSD: pfctl_parser.c,v 1.176 2003/09/26 21:44:09 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -31,6 +31,7 @@
*/
#include <sys/types.h>
+#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -1284,3 +1285,45 @@ append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not)
return (0);
}
+
+int
+pfctl_add_trans(struct pfr_buffer *buf, int rs_num, const char *anchor,
+ const char *ruleset)
+{
+ struct pfioc_trans_e trans;
+
+ bzero(&trans, sizeof(trans));
+ trans.rs_num = rs_num;
+ if (strlcpy(trans.anchor, anchor,
+ sizeof(trans.anchor)) >= sizeof(trans.anchor) ||
+ strlcpy(trans.ruleset, ruleset,
+ sizeof(trans.ruleset)) >= sizeof(trans.ruleset))
+ errx(1, "pfctl_add_trans: strlcpy");
+
+ return pfr_buf_add(buf, &trans);
+}
+
+u_int32_t
+pfctl_get_ticket(struct pfr_buffer *buf, int rs_num, const char *anchor,
+ const char *ruleset)
+{
+ struct pfioc_trans_e *p;
+
+ PFRB_FOREACH(p, buf)
+ if (rs_num == p->rs_num && !strcmp(anchor, p->anchor) &&
+ !strcmp(ruleset, p->ruleset))
+ return (p->ticket);
+ errx(1, "pfr_get_ticket: assertion failed");
+}
+
+int
+pfctl_trans(int dev, struct pfr_buffer *buf, int cmd, int from)
+{
+ struct pfioc_trans trans;
+
+ bzero(&trans, sizeof(trans));
+ trans.size = buf->pfrb_size - from;
+ trans.esize = sizeof(struct pfioc_trans_e);
+ trans.array = ((struct pfioc_trans_e *)buf->pfrb_caddr) + from;
+ return ioctl(dev, cmd, &trans);
+}
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index 88047e59732..e8fa349c987 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.h,v 1.67 2003/08/21 19:12:09 frantzen Exp $ */
+/* $OpenBSD: pfctl_parser.h,v 1.68 2003/09/26 21:44:09 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -66,9 +66,9 @@ struct pfctl {
int tdirty; /* kernel dirty */
u_int32_t rule_nr;
struct pfioc_pooladdr paddr;
- struct pfioc_rule *prule[PF_RULESET_MAX];
struct pfioc_altq *paltq;
struct pfioc_queue *pqueue;
+ struct pfr_buffer *trans;
const char *anchor;
const char *ruleset;
};
@@ -143,7 +143,7 @@ struct node_tinit { /* table initializer */
struct pfr_buffer; /* forward definition */
-int pfctl_rules(int, char *, int, char *, char *);
+int pfctl_rules(int, char *, int, char *, char *, struct pfr_buffer *);
int pfctl_add_rule(struct pfctl *, struct pf_rule *);
int pfctl_add_altq(struct pfctl *, struct pf_altq *);
@@ -157,7 +157,7 @@ int pfctl_set_logif(struct pfctl *, char *);
int parse_rules(FILE *, struct pfctl *);
int parse_flags(char *);
-int pfctl_load_anchors(int, int);
+int pfctl_load_anchors(int, int, struct pfr_buffer *);
void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int);
void print_rule(struct pf_rule *, int);
diff --git a/sbin/pfctl/pfctl_radix.c b/sbin/pfctl/pfctl_radix.c
index 788522c530d..ba436bbef20 100644
--- a/sbin/pfctl/pfctl_radix.c
+++ b/sbin/pfctl/pfctl_radix.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_radix.c,v 1.21 2003/09/24 09:12:35 cedric Exp $ */
+/* $OpenBSD: pfctl_radix.c,v 1.22 2003/09/26 21:44:09 cedric Exp $ */
/*
* Copyright (c) 2002 Cedric Berger
@@ -459,6 +459,7 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
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 pfioc_trans_e)
};
/*
diff --git a/sys/net/pf.c b/sys/net/pf.c
index bde57816ebb..32ac4dabd1f 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.391 2003/09/26 14:48:19 mcbride Exp $ */
+/* $OpenBSD: pf.c,v 1.392 2003/09/26 21:44:08 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -103,6 +103,7 @@ struct ifnet *status_ifp;
u_int32_t ticket_altqs_active;
u_int32_t ticket_altqs_inactive;
+int altqs_inactive_open;
u_int32_t ticket_pabuf;
struct timeout pf_expire_to; /* expire timeout */
diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c
index 0607f96b7e6..09ce5daf881 100644
--- a/sys/net/pf_ioctl.c
+++ b/sys/net/pf_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_ioctl.c,v 1.81 2003/08/22 21:50:34 david Exp $ */
+/* $OpenBSD: pf_ioctl.c,v 1.82 2003/09/26 21:44:08 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -79,6 +79,12 @@ void pf_init_ruleset(struct pf_ruleset *);
void pf_mv_pool(struct pf_palist *, struct pf_palist *);
void pf_empty_pool(struct pf_palist *);
int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
+int pf_begin_altq(u_int32_t *);
+int pf_rollback_altq(u_int32_t);
+int pf_commit_altq(u_int32_t);
+int pf_begin_rules(u_int32_t *, int, char *, char *);
+int pf_rollback_rules(u_int32_t, int, char *, char *);
+int pf_commit_rules(u_int32_t, int, char *, char *);
extern struct timeout pf_expire_to;
@@ -353,7 +359,8 @@ pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
return;
for (i = 0; i < PF_RULESET_MAX; ++i)
if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
- !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr))
+ !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
+ ruleset->rules[i].inactive.open)
return;
anchor = ruleset->anchor;
@@ -499,6 +506,187 @@ pf_tag_unref(u_int16_t tag)
}
int
+pf_begin_altq(u_int32_t *ticket)
+{
+ struct pf_altq *altq;
+ int error = 0;
+
+ /* Purge the old altq list */
+ while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
+ TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
+ if (altq->qname[0] == 0) {
+ /* detach and destroy the discipline */
+ error = altq_remove(altq);
+ }
+ pool_put(&pf_altq_pl, altq);
+ }
+ if (error)
+ return (error);
+ *ticket = ++ticket_altqs_inactive;
+ altqs_inactive_open = 1;
+ return (0);
+}
+
+int
+pf_rollback_altq(u_int32_t ticket)
+{
+ struct pf_altq *altq;
+ int error = 0;
+
+ if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
+ return (0);
+ /* Purge the old altq list */
+ while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
+ TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
+ if (altq->qname[0] == 0) {
+ /* detach and destroy the discipline */
+ error = altq_remove(altq);
+ }
+ pool_put(&pf_altq_pl, altq);
+ }
+ altqs_inactive_open = 0;
+ return (error);
+}
+
+int
+pf_commit_altq(u_int32_t ticket)
+{
+ struct pf_altqqueue *old_altqs;
+ struct pf_altq *altq;
+ struct pf_anchor *anchor;
+ struct pf_ruleset *ruleset;
+ int s, err, error = 0;
+
+ if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
+ return (EBUSY);
+
+ /* swap altqs, keep the old. */
+ s = splsoftnet();
+ old_altqs = pf_altqs_active;
+ pf_altqs_active = pf_altqs_inactive;
+ pf_altqs_inactive = old_altqs;
+ ticket_altqs_active = ticket_altqs_inactive;
+
+ /* Attach new disciplines */
+ TAILQ_FOREACH(altq, pf_altqs_active, entries) {
+ if (altq->qname[0] == 0) {
+ /* attach the discipline */
+ error = altq_pfattach(altq);
+ if (error) {
+ splx(s);
+ return (error);
+ }
+ }
+ }
+
+ /* Purge the old altq list */
+ while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
+ TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
+ if (altq->qname[0] == 0) {
+ /* detach and destroy the discipline */
+ err = altq_pfdetach(altq);
+ if (err != 0 && error == 0)
+ error = err;
+ err = altq_remove(altq);
+ if (err != 0 && error == 0)
+ error = err;
+ }
+ pool_put(&pf_altq_pl, altq);
+ }
+ splx(s);
+
+ /* update queue IDs */
+ pf_rule_set_qid(
+ pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
+ TAILQ_FOREACH(anchor, &pf_anchors, entries) {
+ TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) {
+ pf_rule_set_qid(
+ ruleset->rules[PF_RULESET_FILTER].active.ptr
+ );
+ }
+ }
+ altqs_inactive_open = 0;
+ return (error);
+}
+
+int
+pf_begin_rules(u_int32_t *ticket, int rs_num, char *anchor, char *ruleset)
+{
+ struct pf_ruleset *rs;
+ struct pf_rule *rule;
+
+ if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
+ return (EINVAL);
+ rs = pf_find_or_create_ruleset(anchor, ruleset);
+ if (rs == NULL)
+ return (EINVAL);
+ while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL)
+ pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
+ *ticket = ++rs->rules[rs_num].inactive.ticket;
+ rs->rules[rs_num].inactive.open = 1;
+ return (0);
+}
+
+int
+pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset)
+{
+ struct pf_ruleset *rs;
+ struct pf_rule *rule;
+
+ if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
+ return (EINVAL);
+ rs = pf_find_ruleset(anchor, ruleset);
+ if (rs == NULL || !rs->rules[rs_num].inactive.open ||
+ rs->rules[rs_num].inactive.ticket != ticket)
+ return (0);
+ while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL)
+ pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
+ rs->rules[rs_num].inactive.open = 0;
+ return (0);
+}
+
+int
+pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor, char *ruleset)
+{
+ struct pf_ruleset *rs;
+ struct pf_rule *rule;
+ struct pf_rulequeue *old_rules;
+ int s;
+
+ if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
+ return (EINVAL);
+ rs = pf_find_ruleset(anchor, ruleset);
+ if (rs == NULL || !rs->rules[rs_num].inactive.open ||
+ ticket != rs->rules[rs_num].inactive.ticket)
+ return (EBUSY);
+
+#ifdef ALTQ
+ /* set queue IDs */
+ if (rs_num == PF_RULESET_FILTER)
+ pf_rule_set_qid(rs->rules[rs_num].inactive.ptr);
+#endif
+
+ /* Swap rules, keep the old. */
+ s = splsoftnet();
+ old_rules = rs->rules[rs_num].active.ptr;
+ rs->rules[rs_num].active.ptr =
+ rs->rules[rs_num].inactive.ptr;
+ rs->rules[rs_num].inactive.ptr = old_rules;
+ rs->rules[rs_num].active.ticket =
+ rs->rules[rs_num].inactive.ticket;
+ pf_calc_skip_steps(rs->rules[rs_num].active.ptr);
+
+ /* Purge the old rule list. */
+ while ((rule = TAILQ_FIRST(old_rules)) != NULL)
+ pf_rm_rule(old_rules, rule);
+ rs->rules[rs_num].inactive.open = 0;
+ pf_remove_if_empty_ruleset(rs);
+ pf_update_anchor_rules();
+ splx(s);
+ return (0);
+}
+
+int
pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
{
struct pf_pooladdr *pa = NULL;
@@ -605,24 +793,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCBEGINRULES: {
struct pfioc_rule *pr = (struct pfioc_rule *)addr;
- struct pf_ruleset *ruleset;
- struct pf_rule *rule;
- int rs_num;
- ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset);
- if (ruleset == NULL) {
- error = EINVAL;
- break;
- }
- rs_num = pf_get_ruleset_number(pr->rule.action);
- if (rs_num >= PF_RULESET_MAX) {
- error = EINVAL;
- break;
- }
- while ((rule =
- TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL)
- pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule);
- pr->ticket = ++ruleset->rules[rs_num].inactive.ticket;
+ error = pf_begin_rules(&pr->ticket, pf_get_ruleset_number(
+ pr->rule.action), pr->anchor, pr->ruleset);
break;
}
@@ -741,48 +914,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCCOMMITRULES: {
struct pfioc_rule *pr = (struct pfioc_rule *)addr;
- struct pf_ruleset *ruleset;
- struct pf_rulequeue *old_rules;
- struct pf_rule *rule;
- int rs_num;
- ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
- if (ruleset == NULL) {
- error = EINVAL;
- break;
- }
- rs_num = pf_get_ruleset_number(pr->rule.action);
- if (rs_num >= PF_RULESET_MAX) {
- error = EINVAL;
- break;
- }
- if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
- error = EBUSY;
- break;
- }
-
-#ifdef ALTQ
- /* set queue IDs */
- if (rs_num == PF_RULESET_FILTER)
- pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr);
-#endif
-
- /* Swap rules, keep the old. */
- s = splsoftnet();
- old_rules = ruleset->rules[rs_num].active.ptr;
- ruleset->rules[rs_num].active.ptr =
- ruleset->rules[rs_num].inactive.ptr;
- ruleset->rules[rs_num].inactive.ptr = old_rules;
- ruleset->rules[rs_num].active.ticket =
- ruleset->rules[rs_num].inactive.ticket;
- pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
-
- /* Purge the old rule list. */
- while ((rule = TAILQ_FIRST(old_rules)) != NULL)
- pf_rm_rule(old_rules, rule);
- pf_remove_if_empty_ruleset(ruleset);
- pf_update_anchor_rules();
- splx(s);
+ error = pf_commit_rules(pr->ticket, pf_get_ruleset_number(
+ pr->rule.action), pr->anchor, pr->ruleset);
break;
}
@@ -1438,18 +1572,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCBEGINALTQS: {
u_int32_t *ticket = (u_int32_t *)addr;
- struct pf_altq *altq;
- /* Purge the old altq list */
- while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
- TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
- if (altq->qname[0] == 0) {
- /* detach and destroy the discipline */
- error = altq_remove(altq);
- }
- pool_put(&pf_altq_pl, altq);
- }
- *ticket = ++ticket_altqs_inactive;
+ error = pf_begin_altq(ticket);
break;
}
@@ -1494,63 +1618,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
case DIOCCOMMITALTQS: {
- u_int32_t *ticket = (u_int32_t *)addr;
- struct pf_altqqueue *old_altqs;
- struct pf_altq *altq;
- struct pf_anchor *anchor;
- struct pf_ruleset *ruleset;
- int err;
-
- if (*ticket != ticket_altqs_inactive) {
- error = EBUSY;
- break;
- }
-
- /* Swap altqs, keep the old. */
- s = splsoftnet();
- old_altqs = pf_altqs_active;
- pf_altqs_active = pf_altqs_inactive;
- pf_altqs_inactive = old_altqs;
- ticket_altqs_active = ticket_altqs_inactive;
-
- /* Attach new disciplines */
- TAILQ_FOREACH(altq, pf_altqs_active, entries) {
- if (altq->qname[0] == 0) {
- /* attach the discipline */
- error = altq_pfattach(altq);
- if (error) {
- splx(s);
- goto fail;
- }
- }
- }
-
- /* Purge the old altq list */
- while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
- TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
- if (altq->qname[0] == 0) {
- /* detach and destroy the discipline */
- err = altq_pfdetach(altq);
- if (err != 0 && error == 0)
- error = err;
- err = altq_remove(altq);
- if (err != 0 && error == 0)
- error = err;
- }
- pool_put(&pf_altq_pl, altq);
- }
- splx(s);
+ u_int32_t ticket = *(u_int32_t *)addr;
- /* update queue IDs */
- pf_rule_set_qid(
- pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
- TAILQ_FOREACH(anchor, &pf_anchors, entries) {
- TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) {
- pf_rule_set_qid(
- ruleset->rules[PF_RULESET_FILTER].active.ptr
- );
- }
- }
+ error = pf_commit_altq(ticket);
break;
}
@@ -2148,6 +2218,183 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
+ case DIOCXBEGIN: {
+ struct pfioc_trans *io = (struct pfioc_trans *)addr;
+ struct pfioc_trans_e ioe;
+ struct pfr_table table;
+ int i;
+
+ if (io->esize != sizeof(ioe)) {
+ error = ENODEV;
+ goto fail;
+ }
+ for (i = 0; i < io->size; i++) {
+ if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+ error = EFAULT;
+ goto fail;
+ }
+ switch(ioe.rs_num) {
+ case PF_RULESET_ALTQ:
+ if (ioe.anchor[0] || ioe.ruleset[0]) {
+ error = EINVAL;
+ goto fail;
+ }
+ if ((error = pf_begin_altq(&ioe.ticket)))
+ goto fail;
+ break;
+ case PF_RULESET_TABLE:
+ bzero(&table, sizeof(table));
+ strlcpy(table.pfrt_anchor, ioe.anchor,
+ sizeof(table.pfrt_anchor));
+ strlcpy(table.pfrt_ruleset, ioe.ruleset,
+ sizeof(table.pfrt_ruleset));
+ if ((error = pfr_ina_begin(&table,
+ &ioe.ticket, NULL, 0)))
+ goto fail;
+ break;
+ default:
+ if ((error = pf_begin_rules(&ioe.ticket,
+ ioe.rs_num, ioe.anchor, ioe.ruleset)))
+ goto fail;
+ break;
+ }
+ if (copyout(&ioe, io->array+i, sizeof(io->array[i]))) {
+ error = EFAULT;
+ goto fail;
+ }
+ }
+ break;
+ }
+
+ case DIOCXROLLBACK: {
+ struct pfioc_trans *io = (struct pfioc_trans *)addr;
+ struct pfioc_trans_e ioe;
+ struct pfr_table table;
+ int i;
+
+ if (io->esize != sizeof(ioe)) {
+ error = ENODEV;
+ goto fail;
+ }
+ for (i = 0; i < io->size; i++) {
+ if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+ error = EFAULT;
+ goto fail;
+ }
+ switch(ioe.rs_num) {
+ case PF_RULESET_ALTQ:
+ if (ioe.anchor[0] || ioe.ruleset[0]) {
+ error = EINVAL;
+ goto fail;
+ }
+ if ((error = pf_rollback_altq(ioe.ticket)))
+ goto fail; /* really bad */
+ break;
+ case PF_RULESET_TABLE:
+ bzero(&table, sizeof(table));
+ strlcpy(table.pfrt_anchor, ioe.anchor,
+ sizeof(table.pfrt_anchor));
+ strlcpy(table.pfrt_ruleset, ioe.ruleset,
+ sizeof(table.pfrt_ruleset));
+ if ((error = pfr_ina_rollback(&table,
+ ioe.ticket, NULL, 0)))
+ goto fail; /* really bad */
+ break;
+ default:
+ if ((error = pf_rollback_rules(ioe.ticket,
+ ioe.rs_num, ioe.anchor, ioe.ruleset)))
+ goto fail; /* really bad */
+ break;
+ }
+ }
+ break;
+ }
+
+ case DIOCXCOMMIT: {
+ struct pfioc_trans *io = (struct pfioc_trans *)addr;
+ struct pfioc_trans_e ioe;
+ struct pfr_table table;
+ struct pf_ruleset *rs;
+ int i;
+
+ if (io->esize != sizeof(ioe)) {
+ error = ENODEV;
+ goto fail;
+ }
+ /* first makes sure everything will succeed */
+ for (i = 0; i < io->size; i++) {
+ if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+ error = EFAULT;
+ goto fail;
+ }
+ switch (ioe.rs_num) {
+ case PF_RULESET_ALTQ:
+ if (ioe.anchor[0] || ioe.ruleset[0]) {
+ error = EINVAL;
+ goto fail;
+ }
+ if (!altqs_inactive_open || ioe.ticket !=
+ ticket_altqs_inactive) {
+ error = EBUSY;
+ goto fail;
+ }
+ break;
+ case PF_RULESET_TABLE:
+ rs = pf_find_ruleset(ioe.anchor, ioe.ruleset);
+ if (rs == NULL || !rs->topen || ioe.ticket !=
+ rs->tticket) {
+ error = EBUSY;
+ goto fail;
+ }
+ break;
+ default:
+ if (ioe.rs_num < 0 || ioe.rs_num >=
+ PF_RULESET_MAX) {
+ error = EINVAL;
+ goto fail;
+ }
+ rs = pf_find_ruleset(ioe.anchor, ioe.ruleset);
+ if (rs == NULL ||
+ !rs->rules[ioe.rs_num].inactive.open ||
+ rs->rules[ioe.rs_num].inactive.ticket !=
+ ioe.ticket) {
+ error = EBUSY;
+ goto fail;
+ }
+ break;
+ }
+ }
+ /* now do the commit - no errors should happen here */
+ for (i = 0; i < io->size; i++) {
+ if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+ error = EFAULT;
+ goto fail;
+ }
+ switch (ioe.rs_num) {
+ case PF_RULESET_ALTQ:
+ if ((error = pf_commit_altq(ioe.ticket)))
+ goto fail; /* really bad */
+ break;
+ case PF_RULESET_TABLE:
+ bzero(&table, sizeof(table));
+ strlcpy(table.pfrt_anchor, ioe.anchor,
+ sizeof(table.pfrt_anchor));
+ strlcpy(table.pfrt_ruleset, ioe.ruleset,
+ sizeof(table.pfrt_ruleset));
+ if ((error = pfr_ina_commit(&table, ioe.ticket,
+ NULL, NULL, 0)))
+ goto fail; /* really bad */
+ break;
+ default:
+ if ((error = pf_commit_rules(ioe.ticket,
+ ioe.rs_num, ioe.anchor, ioe.ruleset)))
+ goto fail; /* really bad */
+ break;
+ }
+ }
+ break;
+ }
+
default:
error = ENODEV;
break;
diff --git a/sys/net/pf_table.c b/sys/net/pf_table.c
index e6ce25fa46e..490edb2393c 100644
--- a/sys/net/pf_table.c
+++ b/sys/net/pf_table.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_table.c,v 1.41 2003/08/22 15:19:23 henning Exp $ */
+/* $OpenBSD: pf_table.c,v 1.42 2003/09/26 21:44:09 cedric Exp $ */
/*
* Copyright (c) 2002 Cedric Berger
@@ -1459,6 +1459,37 @@ _bad:
}
int
+pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags)
+{
+ struct pfr_ktableworkq workq;
+ struct pfr_ktable *p;
+ struct pf_ruleset *rs;
+ int xdel = 0;
+
+ ACCEPT_FLAGS(PFR_FLAG_DUMMY);
+ rs = pf_find_ruleset(trs->pfrt_anchor, trs->pfrt_ruleset);
+ if (rs == NULL || !rs->topen || ticket != rs->tticket)
+ return (0);
+ SLIST_INIT(&workq);
+ RB_FOREACH(p, pfr_ktablehead, &pfr_ktables) {
+ if (!(p->pfrkt_flags & PFR_TFLAG_INACTIVE) ||
+ pfr_skip_table(trs, p, 0))
+ continue;
+ p->pfrkt_nflags = p->pfrkt_flags & ~PFR_TFLAG_INACTIVE;
+ SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
+ xdel++;
+ }
+ if (!(flags & PFR_FLAG_DUMMY)) {
+ pfr_setflags_ktables(&workq);
+ rs->topen = 0;
+ pf_remove_if_empty_ruleset(rs);
+ }
+ if (ndel != NULL)
+ *ndel = xdel;
+ return (0);
+}
+
+int
pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
int *nchange, int flags)
{
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 058e425c300..37f879cf80b 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.170 2003/08/22 21:50:34 david Exp $ */
+/* $OpenBSD: pfvar.h,v 1.171 2003/09/26 21:44:09 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -598,6 +598,7 @@ struct pf_ruleset {
struct {
struct pf_rulequeue *ptr;
u_int32_t ticket;
+ int open;
} active, inactive;
} rules[PF_RULESET_MAX];
struct pf_anchor *anchor;
@@ -1004,6 +1005,19 @@ struct pfioc_ruleset {
char name[PF_RULESET_NAME_SIZE];
};
+#define PF_RULESET_ALTQ (PF_RULESET_MAX)
+#define PF_RULESET_TABLE (PF_RULESET_MAX+1)
+struct pfioc_trans {
+ int size; /* number of elements */
+ int esize; /* size of each element in bytes */
+ struct pfioc_trans_e {
+ int rs_num;
+ char anchor[PF_ANCHOR_NAME_SIZE];
+ char ruleset[PF_RULESET_NAME_SIZE];
+ u_int32_t ticket;
+ } *array;
+};
+
#define PFR_FLAG_ATOMIC 0x00000001
#define PFR_FLAG_DUMMY 0x00000002
#define PFR_FLAG_FEEDBACK 0x00000004
@@ -1101,6 +1115,10 @@ struct pfioc_table {
#define DIOCOSFPFLUSH _IO('D', 78)
#define DIOCOSFPADD _IOWR('D', 79, struct pf_osfp_ioctl)
#define DIOCOSFPGET _IOWR('D', 80, struct pf_osfp_ioctl)
+#define DIOCXBEGIN _IOWR('D', 81, struct pfioc_trans)
+#define DIOCXCOMMIT _IOWR('D', 82, struct pfioc_trans)
+#define DIOCXROLLBACK _IOWR('D', 83, struct pfioc_trans)
+
#ifdef _KERNEL
RB_HEAD(pf_state_tree, pf_tree_node);
@@ -1118,6 +1136,7 @@ extern struct pf_palist pf_pabuf;
extern u_int32_t ticket_altqs_active;
extern u_int32_t ticket_altqs_inactive;
+extern int altqs_inactive_open;
extern u_int32_t ticket_pabuf;
extern struct pf_altqqueue *pf_altqs_active;
extern struct pf_altqqueue *pf_altqs_inactive;
@@ -1224,6 +1243,7 @@ int pfr_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *,
int pfr_tst_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
int);
int pfr_ina_begin(struct pfr_table *, u_int32_t *, int *, int);
+int pfr_ina_rollback(struct pfr_table *, u_int32_t, int *, int);
int pfr_ina_commit(struct pfr_table *, u_int32_t, int *, int *, int);
int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *,
int *, u_int32_t, int);
diff --git a/usr.sbin/authpf/authpf.c b/usr.sbin/authpf/authpf.c
index 8275309d265..0f26f830aef 100644
--- a/usr.sbin/authpf/authpf.c
+++ b/usr.sbin/authpf/authpf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: authpf.c,v 1.69 2003/09/26 07:24:10 henning Exp $ */
+/* $OpenBSD: authpf.c,v 1.70 2003/09/26 21:44:09 cedric Exp $ */
/*
* Copyright (C) 1998 - 2002 Bob Beck (beck@openbsd.org).
@@ -46,6 +46,7 @@
#include <unistd.h>
#include <pfctl_parser.h>
+#include <pfctl.h>
#include "pathnames.h"
@@ -253,7 +254,7 @@ main(int argc, char *argv[])
if (change_filter(1, luser, ipsrc) == -1) {
printf("Unable to modify filters\r\n");
- do_death(1);
+ do_death(0);
}
signal(SIGTERM, need_death);
@@ -576,10 +577,8 @@ change_filter(int add, const char *luser, const char *ipsrc)
{
char fn[MAXPATHLEN];
FILE *f = NULL;
- const int action[PF_RULESET_MAX] = { PF_SCRUB,
- PF_PASS, PF_NAT, PF_BINAT, PF_RDR };
struct pfctl pf;
- struct pfioc_rule pr[PF_RULESET_MAX];
+ struct pfr_buffer t;
int i;
if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) {
@@ -614,18 +613,18 @@ change_filter(int add, const char *luser, const char *ipsrc)
syslog(LOG_ERR, "unable to load kernel's OS fingerprints");
goto error;
}
-
+ bzero(&t, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
memset(&pf, 0, sizeof(pf));
for (i = 0; i < PF_RULESET_MAX; ++i) {
- memset(&pr[i], 0, sizeof(pr[i]));
- pr[i].rule.action = action[i];
- strlcpy(pr[i].anchor, anchorname, sizeof(pr[i].anchor));
- strlcpy(pr[i].ruleset, rulesetname, sizeof(pr[i].ruleset));
- if (ioctl(dev, DIOCBEGINRULES, &pr[i])) {
- syslog(LOG_ERR, "DIOCBEGINRULES %m");
+ if (pfctl_add_trans(&t, i, anchorname, rulesetname)) {
+ syslog(LOG_ERR, "pfctl_add_trans %m");
goto error;
}
- pf.prule[i] = &pr[i];
+ }
+ if (pfctl_trans(dev, &t, DIOCXBEGIN, 0)) {
+ syslog(LOG_ERR, "DIOCXBEGIN (%s) %m", add?"add":"remove");
+ goto error;
}
if (add) {
@@ -636,6 +635,10 @@ change_filter(int add, const char *luser, const char *ipsrc)
}
pf.dev = dev;
+ pf.trans = &t;
+ pf.anchor = anchorname;
+ pf.ruleset = rulesetname;
+
infile = fn;
if (parse_rules(f, &pf) < 0) {
syslog(LOG_ERR, "syntax error in rule file: "
@@ -648,16 +651,10 @@ change_filter(int add, const char *luser, const char *ipsrc)
f = NULL;
}
- for (i = 0; i < PF_RULESET_MAX; ++i)
- /*
- * ignore EINVAL on removal, it means the anchor was
- * already automatically removed by the kernel.
- */
- if (ioctl(dev, DIOCCOMMITRULES, &pr[i]) &&
- (add || errno != EINVAL)) {
- syslog(LOG_ERR, "DIOCCOMMITRULES %m");
- goto error;
- }
+ if (pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) {
+ syslog(LOG_ERR, "DIOCXCOMMIT (%s) %m", add?"add":"remove");
+ goto error;
+ }
if (add) {
gettimeofday(&Tstart, NULL);
@@ -672,6 +669,8 @@ change_filter(int add, const char *luser, const char *ipsrc)
error:
if (f != NULL)
fclose(f);
+ if (pfctl_trans(dev, &t, DIOCXROLLBACK, 0))
+ syslog(LOG_ERR, "DIOCXROLLBACK (%s) %m", add?"add":"remove");
infile = NULL;
return (-1);
@@ -747,37 +746,44 @@ do_death(int active)
int
pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
{
- struct pfioc_rule *pr;
+ u_int8_t rs_num;
+ struct pfioc_rule pr;
switch (r->action) {
case PF_PASS:
case PF_DROP:
- pr = pf->prule[PF_RULESET_FILTER];
+ rs_num = PF_RULESET_FILTER;
break;
case PF_SCRUB:
- pr = pf->prule[PF_RULESET_SCRUB];
+ rs_num = PF_RULESET_SCRUB;
break;
case PF_NAT:
case PF_NONAT:
- pr = pf->prule[PF_RULESET_NAT];
+ rs_num = PF_RULESET_NAT;
break;
case PF_RDR:
case PF_NORDR:
- pr = pf->prule[PF_RULESET_RDR];
+ rs_num = PF_RULESET_RDR;
break;
case PF_BINAT:
case PF_NOBINAT:
- pr = pf->prule[PF_RULESET_BINAT];
+ rs_num = PF_RULESET_BINAT;
break;
default:
syslog(LOG_ERR, "invalid rule action %d", r->action);
return (1);
}
+
+ bzero(&pr, sizeof(pr));
+ strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor));
+ strlcpy(pr.ruleset, pf->ruleset, sizeof(pr.ruleset));
if (pfctl_add_pool(pf, &r->rpool, r->af))
return (1);
- pr->pool_ticket = pf->paddr.ticket;
- memcpy(&pr->rule, r, sizeof(pr->rule));
- if (ioctl(pf->dev, DIOCADDRULE, pr)) {
+ pr.ticket = pfctl_get_ticket(pf->trans, rs_num, pf->anchor,
+ pf->ruleset);
+ pr.pool_ticket = pf->paddr.ticket;
+ memcpy(&pr.rule, r, sizeof(pr.rule));
+ if (ioctl(pf->dev, DIOCADDRULE, &pr)) {
syslog(LOG_ERR, "DIOCADDRULE %m");
return (1);
}
@@ -861,7 +867,7 @@ pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
int
pfctl_rules(int dev, char *filename, int opts, char *anchorname,
- char *rulesetname)
+ char *rulesetname, struct pfr_buffer *t)
{
/* never called, no anchors inside anchors, but we need the stub */
fprintf(stderr, "load anchor not supported from authpf\n");