summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDaniel Hartmeier <dhartmei@cvs.openbsd.org>2001-08-18 22:26:09 +0000
committerDaniel Hartmeier <dhartmei@cvs.openbsd.org>2001-08-18 22:26:09 +0000
commit5ab8c6acb97f486a90ce89df16c6fe051855573c (patch)
treedcf1e7c82d1fd367d481e78356c859ba9d8c8e7f /sys
parentaf0d84f708cfd453ff222c45404ded1ee7f0290f (diff)
Add new ioctl for adding/removing individual rules to/from the active rule set.
Diffstat (limited to 'sys')
-rw-r--r--sys/net/pf.c108
-rw-r--r--sys/net/pfvar.h13
2 files changed, 119 insertions, 2 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index ef8ba7ad847..159ff0135d1 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.124 2001/08/18 21:09:13 deraadt Exp $ */
+/* $OpenBSD: pf.c,v 1.125 2001/08/18 22:26:08 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -117,6 +117,8 @@ struct pool pf_rdr_pl, pf_state_pl;
int pf_tree_key_compare(struct pf_tree_key *,
struct pf_tree_key *);
+int pf_compare_rules(struct pf_rule *,
+ struct pf_rule *);
void pf_tree_rotate_left(struct pf_tree_node **);
void pf_tree_rotate_right(struct pf_tree_node **);
struct pf_tree_node *pf_tree_first(struct pf_tree_node *);
@@ -224,6 +226,32 @@ pf_tree_key_compare(struct pf_tree_key *a, struct pf_tree_key *b)
return (0);
}
+int
+pf_compare_rules(struct pf_rule *a, struct pf_rule *b)
+{
+ if (a->return_icmp != b->return_icmp ||
+ a->action != b->action ||
+ a->direction != b->direction ||
+ a->log != b->log ||
+ a->quick != b->quick ||
+ a->keep_state != b->keep_state ||
+ a->proto != b->proto ||
+ a->type != b->type ||
+ a->code != b->code ||
+ a->flags != b->flags ||
+ a->flagset != b->flagset ||
+ a->rule_flag != b->rule_flag ||
+ a->min_ttl != b->min_ttl)
+ return (1);
+ if (memcmp(&a->src, &b->src, sizeof(struct pf_rule_addr)))
+ return (1);
+ if (memcmp(&a->dst, &b->dst, sizeof(struct pf_rule_addr)))
+ return (1);
+ if (strcmp(a->ifname, b->ifname))
+ return (1);
+ return (0);
+}
+
void
pf_tree_rotate_left(struct pf_tree_node **n)
{
@@ -869,6 +897,84 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
+ case DIOCCHANGERULE: {
+ struct pfioc_changerule *pcr = (struct pfioc_changerule *)addr;
+ struct pf_rule *oldrule = NULL, *newrule = NULL;
+ u_int32_t nr = 0;
+
+ if (pcr->action < PF_CHANGERULE_ADD_HEAD ||
+ pcr->action > PF_CHANGERULE_REMOVE) {
+ error = EINVAL;
+ break;
+ }
+
+ if (pcr->action != PF_CHANGERULE_REMOVE) {
+ newrule = pool_get(&pf_rule_pl, PR_NOWAIT);
+ if (newrule == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ bcopy(&pcr->newrule, newrule, sizeof(struct pf_rule));
+ newrule->ifp = NULL;
+ if (newrule->ifname[0]) {
+ newrule->ifp = ifunit(newrule->ifname);
+ if (newrule->ifp == NULL) {
+ pool_put(&pf_rule_pl, newrule);
+ error = EINVAL;
+ break;
+ }
+ }
+ }
+
+ s = splsoftnet();
+
+ if (pcr->action == PF_CHANGERULE_ADD_HEAD)
+ oldrule = TAILQ_FIRST(pf_rules_active);
+ else if (pcr->action == PF_CHANGERULE_ADD_TAIL)
+ oldrule = TAILQ_LAST(pf_rules_active, pf_rulequeue);
+ else {
+ oldrule = TAILQ_FIRST(pf_rules_active);
+ while ((oldrule != NULL) && pf_compare_rules(oldrule,
+ &pcr->oldrule))
+ oldrule = TAILQ_NEXT(oldrule, entries);
+ if (oldrule == NULL) {
+ error = EINVAL;
+ splx(s);
+ break;
+ }
+ }
+
+ if (pcr->action == PF_CHANGERULE_REMOVE) {
+ struct pf_tree_node *n;
+
+ for (n = pf_tree_first(tree_ext_gwy); n != NULL;
+ n = pf_tree_next(n))
+ if (n->state->rule == oldrule)
+ n->state->rule = NULL;
+ TAILQ_REMOVE(pf_rules_active, oldrule, entries);
+ pool_put(&pf_rule_pl, oldrule);
+ } else {
+ if (oldrule == NULL)
+ TAILQ_INSERT_TAIL(pf_rules_active, newrule,
+ entries);
+ else if (pcr->action == PF_CHANGERULE_ADD_HEAD ||
+ pcr->action == PF_CHANGERULE_ADD_BEFORE)
+ TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
+ else
+ TAILQ_INSERT_AFTER(pf_rules_active, oldrule,
+ newrule, entries);
+ }
+
+ TAILQ_FOREACH(oldrule, pf_rules_active, entries)
+ oldrule->nr = nr++;
+
+ pf_calc_skip_steps(pf_rules_active);
+
+ ticket_rules_active++;
+ splx(s);
+ break;
+ }
+
case DIOCBEGINNATS: {
u_int32_t *ticket = (u_int32_t *)addr;
struct pf_nat *nat;
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 65536ff80c1..761c9e83c1a 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.40 2001/08/18 21:09:13 deraadt Exp $ */
+/* $OpenBSD: pfvar.h,v 1.41 2001/08/18 22:26:08 dhartmei Exp $ */
/*
* Copyright (c) 2001, Daniel Hartmeier
@@ -41,6 +41,9 @@ enum { PF_PASS=0, PF_DROP=1, PF_SCRUB=2 };
enum { PF_OP_IRG=1, PF_OP_EQ=2, PF_OP_NE=3, PF_OP_LT=4,
PF_OP_LE=5, PF_OP_GT=6, PF_OP_GE=7, PF_OP_XRG=8 };
enum { PF_DEBUG_NONE=0, PF_DEBUG_URGENT=1, PF_DEBUG_MISC=2 };
+enum { PF_CHANGERULE_ADD_HEAD=1, PF_CHANGERULE_ADD_TAIL=2,
+ PF_CHANGERULE_ADD_BEFORE=3, PF_CHANGERULE_ADD_AFTER=4,
+ PF_CHANGERULE_REMOVE=5 };
struct pf_rule_addr {
u_int32_t addr;
@@ -247,6 +250,13 @@ struct pfioc_rule {
struct pf_rule rule;
};
+struct pfioc_changerule {
+ u_int32_t ticket;
+ u_int32_t action;
+ struct pf_rule oldrule;
+ struct pf_rule newrule;
+};
+
struct pfioc_nat {
u_int32_t ticket;
u_int32_t nr;
@@ -307,6 +317,7 @@ struct pfioc_if {
#define DIOCNATLOOK _IOWR('D', 23, struct pf_natlook)
#define DIOCSETDEBUG _IOWR('D', 24, u_int32_t)
#define DIOCGETSTATES _IOWR('D', 25, struct pfioc_states)
+#define DIOCCHANGERULE _IOWR('D', 26, struct pfioc_changerule)
#ifdef _KERNEL