summaryrefslogtreecommitdiffstats
path: root/sys/contrib/pf/net/pf_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/pf/net/pf_ioctl.c')
-rw-r--r--sys/contrib/pf/net/pf_ioctl.c1002
1 files changed, 535 insertions, 467 deletions
diff --git a/sys/contrib/pf/net/pf_ioctl.c b/sys/contrib/pf/net/pf_ioctl.c
index d4cb3c7..5694717 100644
--- a/sys/contrib/pf/net/pf_ioctl.c
+++ b/sys/contrib/pf/net/pf_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_ioctl.c,v 1.139 2005/03/03 07:13:39 dhartmei Exp $ */
+/* $OpenBSD: pf_ioctl.c,v 1.175 2007/02/26 22:47:43 deraadt Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -48,7 +48,11 @@
#include <sys/time.h>
#include <sys/timeout.h>
#include <sys/pool.h>
+#include <sys/proc.h>
#include <sys/malloc.h>
+#include <sys/kthread.h>
+#include <sys/rwlock.h>
+#include <uvm/uvm_extern.h>
#include <net/if.h>
#include <net/if_types.h>
@@ -62,12 +66,17 @@
#include <netinet/ip_icmp.h>
#include <dev/rndvar.h>
+#include <crypto/md5.h>
#include <net/pfvar.h>
#if NPFSYNC > 0
#include <net/if_pfsync.h>
#endif /* NPFSYNC > 0 */
+#if NPFLOG > 0
+#include <net/if_pflog.h>
+#endif /* NPFLOG > 0 */
+
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet/in_pcb.h>
@@ -78,17 +87,11 @@
#endif
void pfattach(int);
+void pf_thread_create(void *);
int pfopen(dev_t, int, int, struct proc *);
int pfclose(dev_t, int, int, struct proc *);
struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t,
u_int8_t, u_int8_t, u_int8_t);
-int pf_get_ruleset_number(u_int8_t);
-void pf_init_ruleset(struct pf_ruleset *);
-int pf_anchor_setup(struct pf_rule *,
- const struct pf_ruleset *, const char *);
-int pf_anchor_copyout(const struct pf_ruleset *,
- const struct pf_rule *, struct pfioc_rule *);
-void pf_anchor_remove(struct pf_rule *);
void pf_mv_pool(struct pf_palist *, struct pf_palist *);
void pf_empty_pool(struct pf_palist *);
@@ -102,11 +105,13 @@ int pf_disable_altq(struct pf_altq *);
#endif /* ALTQ */
int pf_begin_rules(u_int32_t *, int, const char *);
int pf_rollback_rules(u_int32_t, int, char *);
+int pf_setup_pfsync_matching(struct pf_ruleset *);
+void pf_hash_rule(MD5_CTX *, struct pf_rule *);
+void pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *);
int pf_commit_rules(u_int32_t, int, char *);
-extern struct timeout pf_expire_to;
-
struct pf_rule pf_default_rule;
+struct rwlock pf_consistency_lock = RWLOCK_INITIALIZER;
#ifdef ALTQ
static int pf_altq_running;
#endif
@@ -118,9 +123,9 @@ TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags),
#if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE)
#error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE
#endif
-static u_int16_t tagname2tag(struct pf_tags *, char *);
-static void tag2tagname(struct pf_tags *, u_int16_t, char *);
-static void tag_unref(struct pf_tags *, u_int16_t);
+u_int16_t tagname2tag(struct pf_tags *, char *);
+void tag2tagname(struct pf_tags *, u_int16_t, char *);
+void tag_unref(struct pf_tags *, u_int16_t);
int pf_rtlabel_add(struct pf_addr_wrap *);
void pf_rtlabel_remove(struct pf_addr_wrap *);
void pf_rtlabel_copyout(struct pf_addr_wrap *);
@@ -149,6 +154,10 @@ pfattach(int num)
pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp,
pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0);
+ if (ctob(physmem) <= 100*1024*1024)
+ pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit =
+ PFR_KENTRY_HIWAT_SMALL;
+
RB_INIT(&tree_src_tracking);
RB_INIT(&pf_anchors);
pf_init_ruleset(&pf_main_ruleset);
@@ -157,12 +166,13 @@ pfattach(int num)
TAILQ_INIT(&pf_pabuf);
pf_altqs_active = &pf_altqs[0];
pf_altqs_inactive = &pf_altqs[1];
- TAILQ_INIT(&state_updates);
+ TAILQ_INIT(&state_list);
/* default rule should never be garbage collected */
pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
pf_default_rule.action = PF_PASS;
pf_default_rule.nr = -1;
+ pf_default_rule.rtableid = -1;
/* initialize default timeouts */
timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
@@ -183,9 +193,8 @@ pfattach(int num)
timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
-
- timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to);
- timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz);
+ timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
+ timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
pf_normalize_init();
bzero(&pf_status, sizeof(pf_status));
@@ -193,6 +202,16 @@ pfattach(int num)
/* XXX do our best to avoid a conflict */
pf_status.hostid = arc4random();
+
+ /* require process context to purge states, so perform in a thread */
+ kthread_create_deferred(pf_thread_create, NULL);
+}
+
+void
+pf_thread_create(void *v)
+{
+ if (kthread_create(pf_purge_thread, NULL, NULL, "pfpurge"))
+ panic("pfpurge thread");
}
int
@@ -255,292 +274,6 @@ pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action,
return (&rule->rpool);
}
-int
-pf_get_ruleset_number(u_int8_t action)
-{
- switch (action) {
- case PF_SCRUB:
- case PF_NOSCRUB:
- return (PF_RULESET_SCRUB);
- break;
- case PF_PASS:
- case PF_DROP:
- return (PF_RULESET_FILTER);
- break;
- case PF_NAT:
- case PF_NONAT:
- return (PF_RULESET_NAT);
- break;
- case PF_BINAT:
- case PF_NOBINAT:
- return (PF_RULESET_BINAT);
- break;
- case PF_RDR:
- case PF_NORDR:
- return (PF_RULESET_RDR);
- break;
- default:
- return (PF_RULESET_MAX);
- break;
- }
-}
-
-void
-pf_init_ruleset(struct pf_ruleset *ruleset)
-{
- int i;
-
- memset(ruleset, 0, sizeof(struct pf_ruleset));
- for (i = 0; i < PF_RULESET_MAX; i++) {
- TAILQ_INIT(&ruleset->rules[i].queues[0]);
- TAILQ_INIT(&ruleset->rules[i].queues[1]);
- ruleset->rules[i].active.ptr = &ruleset->rules[i].queues[0];
- ruleset->rules[i].inactive.ptr = &ruleset->rules[i].queues[1];
- }
-}
-
-struct pf_anchor *
-pf_find_anchor(const char *path)
-{
- static struct pf_anchor key;
-
- memset(&key, 0, sizeof(key));
- strlcpy(key.path, path, sizeof(key.path));
- return (RB_FIND(pf_anchor_global, &pf_anchors, &key));
-}
-
-struct pf_ruleset *
-pf_find_ruleset(const char *path)
-{
- struct pf_anchor *anchor;
-
- while (*path == '/')
- path++;
- if (!*path)
- return (&pf_main_ruleset);
- anchor = pf_find_anchor(path);
- if (anchor == NULL)
- return (NULL);
- else
- return (&anchor->ruleset);
-}
-
-struct pf_ruleset *
-pf_find_or_create_ruleset(const char *path)
-{
- static char p[MAXPATHLEN];
- char *q, *r;
- struct pf_ruleset *ruleset;
- struct pf_anchor *anchor, *dup, *parent = NULL;
-
- while (*path == '/')
- path++;
- ruleset = pf_find_ruleset(path);
- if (ruleset != NULL)
- return (ruleset);
- strlcpy(p, path, sizeof(p));
- while (parent == NULL && (q = strrchr(p, '/')) != NULL) {
- *q = 0;
- if ((ruleset = pf_find_ruleset(p)) != NULL) {
- parent = ruleset->anchor;
- break;
- }
- }
- if (q == NULL)
- q = p;
- else
- q++;
- strlcpy(p, path, sizeof(p));
- if (!*q)
- return (NULL);
- while ((r = strchr(q, '/')) != NULL || *q) {
- if (r != NULL)
- *r = 0;
- if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
- (parent != NULL && strlen(parent->path) >=
- MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1))
- return (NULL);
- anchor = (struct pf_anchor *)malloc(sizeof(*anchor), M_TEMP,
- M_NOWAIT);
- if (anchor == NULL)
- return (NULL);
- memset(anchor, 0, sizeof(*anchor));
- RB_INIT(&anchor->children);
- strlcpy(anchor->name, q, sizeof(anchor->name));
- if (parent != NULL) {
- strlcpy(anchor->path, parent->path,
- sizeof(anchor->path));
- strlcat(anchor->path, "/", sizeof(anchor->path));
- }
- strlcat(anchor->path, anchor->name, sizeof(anchor->path));
- if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) !=
- NULL) {
- printf("pf_find_or_create_ruleset: RB_INSERT1 "
- "'%s' '%s' collides with '%s' '%s'\n",
- anchor->path, anchor->name, dup->path, dup->name);
- free(anchor, M_TEMP);
- return (NULL);
- }
- if (parent != NULL) {
- anchor->parent = parent;
- if ((dup = RB_INSERT(pf_anchor_node, &parent->children,
- anchor)) != NULL) {
- printf("pf_find_or_create_ruleset: "
- "RB_INSERT2 '%s' '%s' collides with "
- "'%s' '%s'\n", anchor->path, anchor->name,
- dup->path, dup->name);
- RB_REMOVE(pf_anchor_global, &pf_anchors,
- anchor);
- free(anchor, M_TEMP);
- return (NULL);
- }
- }
- pf_init_ruleset(&anchor->ruleset);
- anchor->ruleset.anchor = anchor;
- parent = anchor;
- if (r != NULL)
- q = r + 1;
- else
- *q = 0;
- }
- return (&anchor->ruleset);
-}
-
-void
-pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
-{
- struct pf_anchor *parent;
- int i;
-
- while (ruleset != NULL) {
- if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
- !RB_EMPTY(&ruleset->anchor->children) ||
- ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
- ruleset->topen)
- return;
- for (i = 0; i < PF_RULESET_MAX; ++i)
- if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
- !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
- ruleset->rules[i].inactive.open)
- return;
- RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor);
- if ((parent = ruleset->anchor->parent) != NULL)
- RB_REMOVE(pf_anchor_node, &parent->children,
- ruleset->anchor);
- free(ruleset->anchor, M_TEMP);
- if (parent == NULL)
- return;
- ruleset = &parent->ruleset;
- }
-}
-
-int
-pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s,
- const char *name)
-{
- static char *p, path[MAXPATHLEN];
- struct pf_ruleset *ruleset;
-
- r->anchor = NULL;
- r->anchor_relative = 0;
- r->anchor_wildcard = 0;
- if (!name[0])
- return (0);
- if (name[0] == '/')
- strlcpy(path, name + 1, sizeof(path));
- else {
- /* relative path */
- r->anchor_relative = 1;
- if (s->anchor == NULL || !s->anchor->path[0])
- path[0] = 0;
- else
- strlcpy(path, s->anchor->path, sizeof(path));
- while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
- if (!path[0]) {
- printf("pf_anchor_setup: .. beyond root\n");
- return (1);
- }
- if ((p = strrchr(path, '/')) != NULL)
- *p = 0;
- else
- path[0] = 0;
- r->anchor_relative++;
- name += 3;
- }
- if (path[0])
- strlcat(path, "/", sizeof(path));
- strlcat(path, name, sizeof(path));
- }
- if ((p = strrchr(path, '/')) != NULL && !strcmp(p, "/*")) {
- r->anchor_wildcard = 1;
- *p = 0;
- }
- ruleset = pf_find_or_create_ruleset(path);
- if (ruleset == NULL || ruleset->anchor == NULL) {
- printf("pf_anchor_setup: ruleset\n");
- return (1);
- }
- r->anchor = ruleset->anchor;
- r->anchor->refcnt++;
- return (0);
-}
-
-int
-pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r,
- struct pfioc_rule *pr)
-{
- pr->anchor_call[0] = 0;
- if (r->anchor == NULL)
- return (0);
- if (!r->anchor_relative) {
- strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
- strlcat(pr->anchor_call, r->anchor->path,
- sizeof(pr->anchor_call));
- } else {
- char a[MAXPATHLEN], b[MAXPATHLEN], *p;
- int i;
-
- if (rs->anchor == NULL)
- a[0] = 0;
- else
- strlcpy(a, rs->anchor->path, sizeof(a));
- strlcpy(b, r->anchor->path, sizeof(b));
- for (i = 1; i < r->anchor_relative; ++i) {
- if ((p = strrchr(a, '/')) == NULL)
- p = a;
- *p = 0;
- strlcat(pr->anchor_call, "../",
- sizeof(pr->anchor_call));
- }
- if (strncmp(a, b, strlen(a))) {
- printf("pf_anchor_copyout: '%s' '%s'\n", a, b);
- return (1);
- }
- if (strlen(b) > strlen(a))
- strlcat(pr->anchor_call, b + (a[0] ? strlen(a) + 1 : 0),
- sizeof(pr->anchor_call));
- }
- if (r->anchor_wildcard)
- strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
- sizeof(pr->anchor_call));
- return (0);
-}
-
-void
-pf_anchor_remove(struct pf_rule *r)
-{
- if (r->anchor == NULL)
- return;
- if (r->anchor->refcnt <= 0) {
- printf("pf_anchor_remove: broken refcount");
- r->anchor = NULL;
- return;
- }
- if (!--r->anchor->refcnt)
- pf_remove_if_empty_ruleset(&r->anchor->ruleset);
- r->anchor = NULL;
-}
-
void
pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
{
@@ -560,7 +293,7 @@ pf_empty_pool(struct pf_palist *poola)
while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
pfi_dynaddr_remove(&empty_pool_pa->addr);
pf_tbladdr_remove(&empty_pool_pa->addr);
- pfi_detach_rule(empty_pool_pa->kif);
+ pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE);
TAILQ_REMOVE(poola, empty_pool_pa, entries);
pool_put(&pf_pooladdr_pl, empty_pool_pa);
}
@@ -606,13 +339,13 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
if (rule->overload_tbl)
pfr_detach_table(rule->overload_tbl);
}
- pfi_detach_rule(rule->kif);
+ pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE);
pf_anchor_remove(rule);
pf_empty_pool(&rule->rpool.list);
pool_put(&pf_rule_pl, rule);
}
-static u_int16_t
+u_int16_t
tagname2tag(struct pf_tags *head, char *tagname)
{
struct pf_tagname *tag, *p = NULL;
@@ -657,7 +390,7 @@ tagname2tag(struct pf_tags *head, char *tagname)
return (tag->tag);
}
-static void
+void
tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p)
{
struct pf_tagname *tag;
@@ -669,7 +402,7 @@ tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p)
}
}
-static void
+void
tag_unref(struct pf_tags *head, u_int16_t tag)
{
struct pf_tagname *p, *next;
@@ -698,7 +431,7 @@ pf_tagname2tag(char *tagname)
void
pf_tag2tagname(u_int16_t tagid, char *p)
{
- return (tag2tagname(&pf_tags, tagid, p));
+ tag2tagname(&pf_tags, tagid, p);
}
void
@@ -716,7 +449,7 @@ pf_tag_ref(u_int16_t tag)
void
pf_tag_unref(u_int16_t tag)
{
- return (tag_unref(&pf_tags, tag));
+ tag_unref(&pf_tags, tag);
}
int
@@ -760,13 +493,13 @@ pf_qname2qid(char *qname)
void
pf_qid2qname(u_int32_t qid, char *p)
{
- return (tag2tagname(&pf_qids, (u_int16_t)qid, p));
+ tag2tagname(&pf_qids, (u_int16_t)qid, p);
}
void
pf_qid_unref(u_int32_t qid)
{
- return (tag_unref(&pf_qids, (u_int16_t)qid));
+ tag_unref(&pf_qids, (u_int16_t)qid);
}
int
@@ -885,7 +618,7 @@ pf_enable_altq(struct pf_altq *altq)
if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
tb.rate = altq->ifbandwidth;
tb.depth = altq->tbrsize;
- s = splimp();
+ s = splnet();
error = tbr_set(&ifp->if_snd, &tb);
splx(s);
}
@@ -915,7 +648,7 @@ pf_disable_altq(struct pf_altq *altq)
if (error == 0) {
/* clear tokenbucket regulator */
tb.rate = 0;
- s = splimp();
+ s = splnet();
error = tbr_set(&ifp->if_snd, &tb);
splx(s);
}
@@ -935,8 +668,10 @@ pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor)
rs = pf_find_or_create_ruleset(anchor);
if (rs == NULL)
return (EINVAL);
- while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL)
+ 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.rcount--;
+ }
*ticket = ++rs->rules[rs_num].inactive.ticket;
rs->rules[rs_num].inactive.open = 1;
return (0);
@@ -954,19 +689,105 @@ pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor)
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)
+ 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.rcount--;
+ }
rs->rules[rs_num].inactive.open = 0;
return (0);
}
+#define PF_MD5_UPD(st, elm) \
+ MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm))
+
+#define PF_MD5_UPD_STR(st, elm) \
+ MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm))
+
+#define PF_MD5_UPD_HTONL(st, elm, stor) do { \
+ (stor) = htonl((st)->elm); \
+ MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\
+} while (0)
+
+#define PF_MD5_UPD_HTONS(st, elm, stor) do { \
+ (stor) = htons((st)->elm); \
+ MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\
+} while (0)
+
+void
+pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr)
+{
+ PF_MD5_UPD(pfr, addr.type);
+ switch (pfr->addr.type) {
+ case PF_ADDR_DYNIFTL:
+ PF_MD5_UPD(pfr, addr.v.ifname);
+ PF_MD5_UPD(pfr, addr.iflags);
+ break;
+ case PF_ADDR_TABLE:
+ PF_MD5_UPD(pfr, addr.v.tblname);
+ break;
+ case PF_ADDR_ADDRMASK:
+ /* XXX ignore af? */
+ PF_MD5_UPD(pfr, addr.v.a.addr.addr32);
+ PF_MD5_UPD(pfr, addr.v.a.mask.addr32);
+ break;
+ case PF_ADDR_RTLABEL:
+ PF_MD5_UPD(pfr, addr.v.rtlabelname);
+ break;
+ }
+
+ PF_MD5_UPD(pfr, port[0]);
+ PF_MD5_UPD(pfr, port[1]);
+ PF_MD5_UPD(pfr, neg);
+ PF_MD5_UPD(pfr, port_op);
+}
+
+void
+pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule)
+{
+ u_int16_t x;
+ u_int32_t y;
+
+ pf_hash_rule_addr(ctx, &rule->src);
+ pf_hash_rule_addr(ctx, &rule->dst);
+ PF_MD5_UPD_STR(rule, label);
+ PF_MD5_UPD_STR(rule, ifname);
+ PF_MD5_UPD_STR(rule, match_tagname);
+ PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */
+ PF_MD5_UPD_HTONL(rule, os_fingerprint, y);
+ PF_MD5_UPD_HTONL(rule, prob, y);
+ PF_MD5_UPD_HTONL(rule, uid.uid[0], y);
+ PF_MD5_UPD_HTONL(rule, uid.uid[1], y);
+ PF_MD5_UPD(rule, uid.op);
+ PF_MD5_UPD_HTONL(rule, gid.gid[0], y);
+ PF_MD5_UPD_HTONL(rule, gid.gid[1], y);
+ PF_MD5_UPD(rule, gid.op);
+ PF_MD5_UPD_HTONL(rule, rule_flag, y);
+ PF_MD5_UPD(rule, action);
+ PF_MD5_UPD(rule, direction);
+ PF_MD5_UPD(rule, af);
+ PF_MD5_UPD(rule, quick);
+ PF_MD5_UPD(rule, ifnot);
+ PF_MD5_UPD(rule, match_tag_not);
+ PF_MD5_UPD(rule, natpass);
+ PF_MD5_UPD(rule, keep_state);
+ PF_MD5_UPD(rule, proto);
+ PF_MD5_UPD(rule, type);
+ PF_MD5_UPD(rule, code);
+ PF_MD5_UPD(rule, flags);
+ PF_MD5_UPD(rule, flagset);
+ PF_MD5_UPD(rule, allow_opts);
+ PF_MD5_UPD(rule, rt);
+ PF_MD5_UPD(rule, tos);
+}
+
int
pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
{
struct pf_ruleset *rs;
- struct pf_rule *rule;
+ struct pf_rule *rule, **old_array;
struct pf_rulequeue *old_rules;
- int s;
+ int s, error;
+ u_int32_t old_rcount;
if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
return (EINVAL);
@@ -975,19 +796,41 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
ticket != rs->rules[rs_num].inactive.ticket)
return (EBUSY);
+ /* Calculate checksum for the main ruleset */
+ if (rs == &pf_main_ruleset) {
+ error = pf_setup_pfsync_matching(rs);
+ if (error != 0)
+ return (error);
+ }
+
/* Swap rules, keep the old. */
s = splsoftnet();
old_rules = rs->rules[rs_num].active.ptr;
+ old_rcount = rs->rules[rs_num].active.rcount;
+ old_array = rs->rules[rs_num].active.ptr_array;
+
rs->rules[rs_num].active.ptr =
rs->rules[rs_num].inactive.ptr;
+ rs->rules[rs_num].active.ptr_array =
+ rs->rules[rs_num].inactive.ptr_array;
+ rs->rules[rs_num].active.rcount =
+ rs->rules[rs_num].inactive.rcount;
rs->rules[rs_num].inactive.ptr = old_rules;
+ rs->rules[rs_num].inactive.ptr_array = old_array;
+ rs->rules[rs_num].inactive.rcount = old_rcount;
+
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);
+ if (rs->rules[rs_num].inactive.ptr_array)
+ free(rs->rules[rs_num].inactive.ptr_array, M_TEMP);
+ rs->rules[rs_num].inactive.ptr_array = NULL;
+ rs->rules[rs_num].inactive.rcount = 0;
rs->rules[rs_num].inactive.open = 0;
pf_remove_if_empty_ruleset(rs);
splx(s);
@@ -995,6 +838,46 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
}
int
+pf_setup_pfsync_matching(struct pf_ruleset *rs)
+{
+ MD5_CTX ctx;
+ struct pf_rule *rule;
+ int rs_cnt;
+ u_int8_t digest[PF_MD5_DIGEST_LENGTH];
+
+ MD5Init(&ctx);
+ for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) {
+ /* XXX PF_RULESET_SCRUB as well? */
+ if (rs_cnt == PF_RULESET_SCRUB)
+ continue;
+
+ if (rs->rules[rs_cnt].inactive.ptr_array)
+ free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP);
+ rs->rules[rs_cnt].inactive.ptr_array = NULL;
+
+ if (rs->rules[rs_cnt].inactive.rcount) {
+ rs->rules[rs_cnt].inactive.ptr_array =
+ malloc(sizeof(caddr_t) *
+ rs->rules[rs_cnt].inactive.rcount,
+ M_TEMP, M_NOWAIT);
+
+ if (!rs->rules[rs_cnt].inactive.ptr_array)
+ return (ENOMEM);
+ }
+
+ TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
+ entries) {
+ pf_hash_rule(&ctx, rule);
+ (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
+ }
+ }
+
+ MD5Final(digest, &ctx);
+ memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum));
+ return (0);
+}
+
+int
pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
{
struct pf_pooladdr *pa = NULL;
@@ -1039,7 +922,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCGETSRCNODES:
case DIOCCLRSRCNODES:
case DIOCIGETIFACES:
- case DIOCICLRISTATS:
case DIOCSETIFFLAG:
case DIOCCLRIFFLAG:
break;
@@ -1058,7 +940,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
if (!(flags & FWRITE))
switch (cmd) {
case DIOCGETRULES:
- case DIOCGETRULE:
case DIOCGETADDRS:
case DIOCGETADDR:
case DIOCGETSTATE:
@@ -1071,6 +952,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCGETQSTATS:
case DIOCGETRULESETS:
case DIOCGETRULESET:
+ case DIOCNATLOOK:
case DIOCRGETTABLES:
case DIOCRGETTSTATS:
case DIOCRGETADDRS:
@@ -1090,13 +972,24 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCRSETADDRS:
case DIOCRSETTFLAGS:
if (((struct pfioc_table *)addr)->pfrio_flags &
- PFR_FLAG_DUMMY)
+ PFR_FLAG_DUMMY) {
+ flags |= FWRITE; /* need write lock for dummy */
break; /* dummy operation ok */
+ }
return (EACCES);
+ case DIOCGETRULE:
+ if (((struct pfioc_rule *)addr)->action == PF_GET_CLR_CNTR)
+ return (EACCES);
+ break;
default:
return (EACCES);
}
+ if (flags & FWRITE)
+ rw_enter_write(&pf_consistency_lock);
+ else
+ rw_enter_read(&pf_consistency_lock);
+
s = splsoftnet();
switch (cmd) {
@@ -1160,6 +1053,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
bcopy(&pr->rule, rule, sizeof(struct pf_rule));
+ rule->cuid = p->p_cred->p_ruid;
+ rule->cpid = p->p_pid;
rule->anchor = NULL;
rule->kif = NULL;
TAILQ_INIT(&rule->rpool.list);
@@ -1188,14 +1083,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
else
rule->nr = 0;
if (rule->ifname[0]) {
- rule->kif = pfi_attach_rule(rule->ifname);
+ rule->kif = pfi_kif_get(rule->ifname);
if (rule->kif == NULL) {
pool_put(&pf_rule_pl, rule);
error = EINVAL;
break;
}
+ pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE);
}
+ if (rule->rtableid > 0 && !rtable_exists(rule->rtableid))
+ error = EBUSY;
+
#ifdef ALTQ
/* set queue IDs */
if (rule->qname[0] != 0) {
@@ -1218,6 +1117,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EBUSY;
if (rule->rt && !rule->direction)
error = EINVAL;
+#if NPFLOG > 0
+ if (rule->logif >= PFLOGIFS_MAX)
+ error = EINVAL;
+#endif
if (pf_rtlabel_add(&rule->src.addr) ||
pf_rtlabel_add(&rule->dst.addr))
error = EBUSY;
@@ -1256,9 +1159,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
- rule->evaluations = rule->packets = rule->bytes = 0;
+ rule->evaluations = rule->packets[0] = rule->packets[1] =
+ rule->bytes[0] = rule->bytes[1] = 0;
TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
rule, entries);
+ ruleset->rules[rs_num].inactive.rcount++;
break;
}
@@ -1334,6 +1239,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
else
pr->rule.skip[i].nr =
rule->skip[i].ptr->nr;
+
+ if (pr->action == PF_GET_CLR_CNTR) {
+ rule->evaluations = 0;
+ rule->packets[0] = rule->packets[1] = 0;
+ rule->bytes[0] = rule->bytes[1] = 0;
+ }
break;
}
@@ -1389,6 +1300,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
+ newrule->cuid = p->p_cred->p_ruid;
+ newrule->cpid = p->p_pid;
TAILQ_INIT(&newrule->rpool.list);
/* initialize refcounting */
newrule->states = 0;
@@ -1408,15 +1321,20 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
#endif /* INET6 */
if (newrule->ifname[0]) {
- newrule->kif = pfi_attach_rule(newrule->ifname);
+ newrule->kif = pfi_kif_get(newrule->ifname);
if (newrule->kif == NULL) {
pool_put(&pf_rule_pl, newrule);
error = EINVAL;
break;
}
+ pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE);
} else
newrule->kif = NULL;
+ if (newrule->rtableid > 0 &&
+ !rtable_exists(newrule->rtableid))
+ error = EBUSY;
+
#ifdef ALTQ
/* set queue IDs */
if (newrule->qname[0] != 0) {
@@ -1473,7 +1391,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
(newrule->action == PF_RDR) ||
(newrule->action == PF_BINAT) ||
(newrule->rt > PF_FASTROUTE)) &&
- !pcr->anchor[0])) &&
+ !newrule->anchor)) &&
(TAILQ_FIRST(&newrule->rpool.list) == NULL))
error = EINVAL;
@@ -1482,8 +1400,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
- newrule->evaluations = newrule->packets = 0;
- newrule->bytes = 0;
+ newrule->evaluations = 0;
+ newrule->packets[0] = newrule->packets[1] = 0;
+ newrule->bytes[0] = newrule->bytes[1] = 0;
}
pf_empty_pool(&pf_pabuf);
@@ -1506,9 +1425,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
}
- if (pcr->action == PF_CHANGE_REMOVE)
+ if (pcr->action == PF_CHANGE_REMOVE) {
pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
- else {
+ ruleset->rules[rs_num].active.rcount--;
+ } else {
if (oldrule == NULL)
TAILQ_INSERT_TAIL(
ruleset->rules[rs_num].active.ptr,
@@ -1520,6 +1440,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
TAILQ_INSERT_AFTER(
ruleset->rules[rs_num].active.ptr,
oldrule, newrule, entries);
+ ruleset->rules[rs_num].active.rcount++;
}
nr = 0;
@@ -1536,23 +1457,24 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
case DIOCCLRSTATES: {
- struct pf_state *state;
+ struct pf_state *state, *nexts;
struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
int killed = 0;
- RB_FOREACH(state, pf_state_tree_id, &tree_id) {
+ for (state = RB_MIN(pf_state_tree_id, &tree_id); state;
+ state = nexts) {
+ nexts = RB_NEXT(pf_state_tree_id, &tree_id, state);
+
if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
state->u.s.kif->pfik_name)) {
- state->timeout = PFTM_PURGE;
#if NPFSYNC
/* don't send out individual delete messages */
state->sync_flags = PFSTATE_NOSYNC;
#endif
+ pf_unlink_state(state);
killed++;
}
}
- pf_purge_expired_states();
- pf_status.states = 0;
psk->psk_af = killed;
#if NPFSYNC
pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
@@ -1561,37 +1483,52 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
case DIOCKILLSTATES: {
- struct pf_state *state;
+ struct pf_state *state, *nexts;
+ struct pf_state_host *src, *dst;
struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
int killed = 0;
- RB_FOREACH(state, pf_state_tree_id, &tree_id) {
+ for (state = RB_MIN(pf_state_tree_id, &tree_id); state;
+ state = nexts) {
+ nexts = RB_NEXT(pf_state_tree_id, &tree_id, state);
+
+ if (state->direction == PF_OUT) {
+ src = &state->lan;
+ dst = &state->ext;
+ } else {
+ src = &state->ext;
+ dst = &state->lan;
+ }
if ((!psk->psk_af || state->af == psk->psk_af)
&& (!psk->psk_proto || psk->psk_proto ==
state->proto) &&
PF_MATCHA(psk->psk_src.neg,
&psk->psk_src.addr.v.a.addr,
&psk->psk_src.addr.v.a.mask,
- &state->lan.addr, state->af) &&
+ &src->addr, state->af) &&
PF_MATCHA(psk->psk_dst.neg,
&psk->psk_dst.addr.v.a.addr,
&psk->psk_dst.addr.v.a.mask,
- &state->ext.addr, state->af) &&
+ &dst->addr, state->af) &&
(psk->psk_src.port_op == 0 ||
pf_match_port(psk->psk_src.port_op,
psk->psk_src.port[0], psk->psk_src.port[1],
- state->lan.port)) &&
+ src->port)) &&
(psk->psk_dst.port_op == 0 ||
pf_match_port(psk->psk_dst.port_op,
psk->psk_dst.port[0], psk->psk_dst.port[1],
- state->ext.port)) &&
+ dst->port)) &&
(!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
state->u.s.kif->pfik_name))) {
- state->timeout = PFTM_PURGE;
+#if NPFSYNC > 0
+ /* send immediate delete of state */
+ pfsync_delete_state(state);
+ state->sync_flags |= PFSTATE_NOSYNC;
+#endif
+ pf_unlink_state(state);
killed++;
}
}
- pf_purge_expired_states();
psk->psk_af = killed;
break;
}
@@ -1611,7 +1548,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = ENOMEM;
break;
}
- kif = pfi_lookup_create(ps->state.u.ifname);
+ kif = pfi_kif_get(ps->state.u.ifname);
if (kif == NULL) {
pool_put(&pf_state_pl, state);
error = ENOENT;
@@ -1629,7 +1566,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
state->bytes[0] = state->bytes[1] = 0;
if (pf_insert_state(kif, state)) {
- pfi_maybe_destroy(kif);
+ pfi_kif_unref(kif, PFI_KIF_REF_NONE);
pool_put(&pf_state_pl, state);
error = ENOMEM;
}
@@ -1640,6 +1577,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
struct pfioc_state *ps = (struct pfioc_state *)addr;
struct pf_state *state;
u_int32_t nr;
+ int secs;
nr = 0;
RB_FOREACH(state, pf_state_tree_id, &tree_id) {
@@ -1651,15 +1589,19 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EBUSY;
break;
}
- bcopy(state, &ps->state, sizeof(struct pf_state));
+ secs = time_second;
+ bcopy(state, &ps->state, sizeof(ps->state));
+ strlcpy(ps->state.u.ifname, state->u.s.kif->pfik_name,
+ sizeof(ps->state.u.ifname));
ps->state.rule.nr = state->rule.ptr->nr;
ps->state.nat_rule.nr = (state->nat_rule.ptr == NULL) ?
-1 : state->nat_rule.ptr->nr;
ps->state.anchor.nr = (state->anchor.ptr == NULL) ?
-1 : state->anchor.ptr->nr;
+ ps->state.creation = secs - ps->state.creation;
ps->state.expire = pf_state_expires(state);
- if (ps->state.expire > time_second)
- ps->state.expire -= time_second;
+ if (ps->state.expire > secs)
+ ps->state.expire -= secs;
else
ps->state.expire = 0;
break;
@@ -1668,48 +1610,57 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCGETSTATES: {
struct pfioc_states *ps = (struct pfioc_states *)addr;
struct pf_state *state;
- struct pf_state *p, pstore;
- struct pfi_kif *kif;
+ struct pf_state *p, *pstore;
u_int32_t nr = 0;
int space = ps->ps_len;
if (space == 0) {
- TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states)
- nr += kif->pfik_states;
+ nr = pf_status.states;
ps->ps_len = sizeof(struct pf_state) * nr;
break;
}
+ pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK);
+
p = ps->ps_states;
- TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states)
- RB_FOREACH(state, pf_state_tree_ext_gwy,
- &kif->pfik_ext_gwy) {
+
+ state = TAILQ_FIRST(&state_list);
+ while (state) {
+ if (state->timeout != PFTM_UNLINKED) {
int secs = time_second;
if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len)
break;
- bcopy(state, &pstore, sizeof(pstore));
- strlcpy(pstore.u.ifname, kif->pfik_name,
- sizeof(pstore.u.ifname));
- pstore.rule.nr = state->rule.ptr->nr;
- pstore.nat_rule.nr = (state->nat_rule.ptr ==
+ bcopy(state, pstore, sizeof(*pstore));
+ strlcpy(pstore->u.ifname,
+ state->u.s.kif->pfik_name,
+ sizeof(pstore->u.ifname));
+ pstore->rule.nr = state->rule.ptr->nr;
+ pstore->nat_rule.nr = (state->nat_rule.ptr ==
NULL) ? -1 : state->nat_rule.ptr->nr;
- pstore.anchor.nr = (state->anchor.ptr ==
+ pstore->anchor.nr = (state->anchor.ptr ==
NULL) ? -1 : state->anchor.ptr->nr;
- pstore.creation = secs - pstore.creation;
- pstore.expire = pf_state_expires(state);
- if (pstore.expire > secs)
- pstore.expire -= secs;
+ pstore->creation = secs - pstore->creation;
+ pstore->expire = pf_state_expires(state);
+ if (pstore->expire > secs)
+ pstore->expire -= secs;
else
- pstore.expire = 0;
- error = copyout(&pstore, p, sizeof(*p));
- if (error)
+ pstore->expire = 0;
+ error = copyout(pstore, p, sizeof(*p));
+ if (error) {
+ free(pstore, M_TEMP);
goto fail;
+ }
p++;
nr++;
}
+ state = TAILQ_NEXT(state, u.s.entry_list);
+ }
+
ps->ps_len = sizeof(struct pf_state) * nr;
+
+ free(pstore, M_TEMP);
break;
}
@@ -1739,16 +1690,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
bzero(pf_status.counters, sizeof(pf_status.counters));
bzero(pf_status.fcounters, sizeof(pf_status.fcounters));
bzero(pf_status.scounters, sizeof(pf_status.scounters));
+ pf_status.since = time_second;
if (*pf_status.ifname)
- pfi_clr_istats(pf_status.ifname, NULL,
- PFI_FLAG_INSTANCE);
+ pfi_clr_istats(pf_status.ifname);
break;
}
case DIOCNATLOOK: {
struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr;
struct pf_state *state;
- struct pf_state key;
+ struct pf_state_cmp key;
int m = 0, direction = pnl->direction;
key.af = pnl->af;
@@ -1757,7 +1708,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
if (!pnl->proto ||
PF_AZERO(&pnl->saddr, pnl->af) ||
PF_AZERO(&pnl->daddr, pnl->af) ||
- !pnl->dport || !pnl->sport)
+ ((pnl->proto == IPPROTO_TCP ||
+ pnl->proto == IPPROTO_UDP) &&
+ (!pnl->dport || !pnl->sport)))
error = EINVAL;
else {
/*
@@ -1813,7 +1766,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
goto fail;
}
old = pf_default_rule.timeout[pt->timeout];
+ if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0)
+ pt->seconds = 1;
pf_default_rule.timeout[pt->timeout] = pt->seconds;
+ if (pt->timeout == PFTM_INTERVAL && pt->seconds < old)
+ wakeup(pf_purge_thread);
pt->seconds = old;
break;
}
@@ -1868,13 +1825,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
case DIOCCLRRULECTRS: {
+ /* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */
struct pf_ruleset *ruleset = &pf_main_ruleset;
struct pf_rule *rule;
TAILQ_FOREACH(rule,
- ruleset->rules[PF_RULESET_FILTER].active.ptr, entries)
- rule->evaluations = rule->packets =
- rule->bytes = 0;
+ ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) {
+ rule->evaluations = 0;
+ rule->packets[0] = rule->packets[1] = 0;
+ rule->bytes[0] = rule->bytes[1] = 0;
+ }
break;
}
@@ -2067,16 +2027,17 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
if (pa->ifname[0]) {
- pa->kif = pfi_attach_rule(pa->ifname);
+ pa->kif = pfi_kif_get(pa->ifname);
if (pa->kif == NULL) {
pool_put(&pf_pooladdr_pl, pa);
error = EINVAL;
break;
}
+ pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE);
}
if (pfi_dynaddr_setup(&pa->addr, pp->af)) {
pfi_dynaddr_remove(&pa->addr);
- pfi_detach_rule(pa->kif);
+ pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE);
pool_put(&pf_pooladdr_pl, pa);
error = EINVAL;
break;
@@ -2176,18 +2137,19 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
#endif /* INET6 */
if (newpa->ifname[0]) {
- newpa->kif = pfi_attach_rule(newpa->ifname);
+ newpa->kif = pfi_kif_get(newpa->ifname);
if (newpa->kif == NULL) {
pool_put(&pf_pooladdr_pl, newpa);
error = EINVAL;
break;
}
+ pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE);
} else
newpa->kif = NULL;
if (pfi_dynaddr_setup(&newpa->addr, pca->af) ||
pf_tbladdr_setup(ruleset, &newpa->addr)) {
pfi_dynaddr_remove(&newpa->addr);
- pfi_detach_rule(newpa->kif);
+ pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE);
pool_put(&pf_pooladdr_pl, newpa);
error = EINVAL;
break;
@@ -2216,7 +2178,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
TAILQ_REMOVE(&pool->list, oldpa, entries);
pfi_dynaddr_remove(&oldpa->addr);
pf_tbladdr_remove(&oldpa->addr);
- pfi_detach_rule(oldpa->kif);
+ pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE);
pool_put(&pf_pooladdr_pl, oldpa);
} else {
if (oldpa == NULL)
@@ -2426,7 +2388,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
&io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags |
- PFR_FLAG_USERIOCTL);
+ PFR_FLAG_USERIOCTL, 0);
break;
}
@@ -2506,150 +2468,203 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
case DIOCXBEGIN: {
- struct pfioc_trans *io = (struct pfioc_trans *)
- addr;
- static struct pfioc_trans_e ioe;
- static struct pfr_table table;
- int i;
+ struct pfioc_trans *io = (struct pfioc_trans *)addr;
+ struct pfioc_trans_e *ioe;
+ struct pfr_table *table;
+ int i;
- if (io->esize != sizeof(ioe)) {
+ if (io->esize != sizeof(*ioe)) {
error = ENODEV;
goto fail;
}
+ ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe),
+ M_TEMP, M_WAITOK);
+ table = (struct pfr_table *)malloc(sizeof(*table),
+ M_TEMP, M_WAITOK);
for (i = 0; i < io->size; i++) {
- if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+ if (copyin(io->array+i, ioe, sizeof(*ioe))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
error = EFAULT;
goto fail;
}
- switch (ioe.rs_num) {
+ switch (ioe->rs_num) {
#ifdef ALTQ
case PF_RULESET_ALTQ:
- if (ioe.anchor[0]) {
+ if (ioe->anchor[0]) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
error = EINVAL;
goto fail;
}
- if ((error = pf_begin_altq(&ioe.ticket)))
+ if ((error = pf_begin_altq(&ioe->ticket))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
goto fail;
+ }
break;
#endif /* ALTQ */
case PF_RULESET_TABLE:
- bzero(&table, sizeof(table));
- strlcpy(table.pfrt_anchor, ioe.anchor,
- sizeof(table.pfrt_anchor));
- if ((error = pfr_ina_begin(&table,
- &ioe.ticket, NULL, 0)))
+ bzero(table, sizeof(*table));
+ strlcpy(table->pfrt_anchor, ioe->anchor,
+ sizeof(table->pfrt_anchor));
+ if ((error = pfr_ina_begin(table,
+ &ioe->ticket, NULL, 0))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
goto fail;
+ }
break;
default:
- if ((error = pf_begin_rules(&ioe.ticket,
- ioe.rs_num, ioe.anchor)))
+ if ((error = pf_begin_rules(&ioe->ticket,
+ ioe->rs_num, ioe->anchor))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
goto fail;
+ }
break;
}
- if (copyout(&ioe, io->array+i, sizeof(io->array[i]))) {
+ if (copyout(ioe, io->array+i, sizeof(io->array[i]))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
error = EFAULT;
goto fail;
}
}
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
break;
}
case DIOCXROLLBACK: {
- struct pfioc_trans *io = (struct pfioc_trans *)
- addr;
- static struct pfioc_trans_e ioe;
- static struct pfr_table table;
- int i;
+ struct pfioc_trans *io = (struct pfioc_trans *)addr;
+ struct pfioc_trans_e *ioe;
+ struct pfr_table *table;
+ int i;
- if (io->esize != sizeof(ioe)) {
+ if (io->esize != sizeof(*ioe)) {
error = ENODEV;
goto fail;
}
+ ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe),
+ M_TEMP, M_WAITOK);
+ table = (struct pfr_table *)malloc(sizeof(*table),
+ M_TEMP, M_WAITOK);
for (i = 0; i < io->size; i++) {
- if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+ if (copyin(io->array+i, ioe, sizeof(*ioe))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
error = EFAULT;
goto fail;
}
- switch (ioe.rs_num) {
+ switch (ioe->rs_num) {
#ifdef ALTQ
case PF_RULESET_ALTQ:
- if (ioe.anchor[0]) {
+ if (ioe->anchor[0]) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
error = EINVAL;
goto fail;
}
- if ((error = pf_rollback_altq(ioe.ticket)))
+ if ((error = pf_rollback_altq(ioe->ticket))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
goto fail; /* really bad */
+ }
break;
#endif /* ALTQ */
case PF_RULESET_TABLE:
- bzero(&table, sizeof(table));
- strlcpy(table.pfrt_anchor, ioe.anchor,
- sizeof(table.pfrt_anchor));
- if ((error = pfr_ina_rollback(&table,
- ioe.ticket, NULL, 0)))
+ bzero(table, sizeof(*table));
+ strlcpy(table->pfrt_anchor, ioe->anchor,
+ sizeof(table->pfrt_anchor));
+ if ((error = pfr_ina_rollback(table,
+ ioe->ticket, NULL, 0))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
goto fail; /* really bad */
+ }
break;
default:
- if ((error = pf_rollback_rules(ioe.ticket,
- ioe.rs_num, ioe.anchor)))
+ if ((error = pf_rollback_rules(ioe->ticket,
+ ioe->rs_num, ioe->anchor))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
goto fail; /* really bad */
+ }
break;
}
}
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
break;
}
case DIOCXCOMMIT: {
- struct pfioc_trans *io = (struct pfioc_trans *)
- addr;
- static struct pfioc_trans_e ioe;
- static struct pfr_table table;
- struct pf_ruleset *rs;
- int i;
-
- if (io->esize != sizeof(ioe)) {
+ 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;
}
+ ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe),
+ M_TEMP, M_WAITOK);
+ table = (struct pfr_table *)malloc(sizeof(*table),
+ M_TEMP, M_WAITOK);
/* first makes sure everything will succeed */
for (i = 0; i < io->size; i++) {
- if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+ if (copyin(io->array+i, ioe, sizeof(*ioe))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
error = EFAULT;
goto fail;
}
- switch (ioe.rs_num) {
+ switch (ioe->rs_num) {
#ifdef ALTQ
case PF_RULESET_ALTQ:
- if (ioe.anchor[0]) {
+ if (ioe->anchor[0]) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
error = EINVAL;
goto fail;
}
- if (!altqs_inactive_open || ioe.ticket !=
+ if (!altqs_inactive_open || ioe->ticket !=
ticket_altqs_inactive) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
error = EBUSY;
goto fail;
}
break;
#endif /* ALTQ */
case PF_RULESET_TABLE:
- rs = pf_find_ruleset(ioe.anchor);
- if (rs == NULL || !rs->topen || ioe.ticket !=
+ rs = pf_find_ruleset(ioe->anchor);
+ if (rs == NULL || !rs->topen || ioe->ticket !=
rs->tticket) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
error = EBUSY;
goto fail;
}
break;
default:
- if (ioe.rs_num < 0 || ioe.rs_num >=
+ if (ioe->rs_num < 0 || ioe->rs_num >=
PF_RULESET_MAX) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
error = EINVAL;
goto fail;
}
- rs = pf_find_ruleset(ioe.anchor);
+ rs = pf_find_ruleset(ioe->anchor);
if (rs == NULL ||
- !rs->rules[ioe.rs_num].inactive.open ||
- rs->rules[ioe.rs_num].inactive.ticket !=
- ioe.ticket) {
+ !rs->rules[ioe->rs_num].inactive.open ||
+ rs->rules[ioe->rs_num].inactive.ticket !=
+ ioe->ticket) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
error = EBUSY;
goto fail;
}
@@ -2658,39 +2673,51 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
/* now do the commit - no errors should happen here */
for (i = 0; i < io->size; i++) {
- if (copyin(io->array+i, &ioe, sizeof(ioe))) {
+ if (copyin(io->array+i, ioe, sizeof(*ioe))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
error = EFAULT;
goto fail;
}
- switch (ioe.rs_num) {
+ switch (ioe->rs_num) {
#ifdef ALTQ
case PF_RULESET_ALTQ:
- if ((error = pf_commit_altq(ioe.ticket)))
+ if ((error = pf_commit_altq(ioe->ticket))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
goto fail; /* really bad */
+ }
break;
#endif /* ALTQ */
case PF_RULESET_TABLE:
- bzero(&table, sizeof(table));
- strlcpy(table.pfrt_anchor, ioe.anchor,
- sizeof(table.pfrt_anchor));
- if ((error = pfr_ina_commit(&table, ioe.ticket,
- NULL, NULL, 0)))
+ bzero(table, sizeof(*table));
+ strlcpy(table->pfrt_anchor, ioe->anchor,
+ sizeof(table->pfrt_anchor));
+ if ((error = pfr_ina_commit(table, ioe->ticket,
+ NULL, NULL, 0))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
goto fail; /* really bad */
+ }
break;
default:
- if ((error = pf_commit_rules(ioe.ticket,
- ioe.rs_num, ioe.anchor)))
+ if ((error = pf_commit_rules(ioe->ticket,
+ ioe->rs_num, ioe->anchor))) {
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
goto fail; /* really bad */
+ }
break;
}
}
+ free(table, M_TEMP);
+ free(ioe, M_TEMP);
break;
}
case DIOCGETSRCNODES: {
struct pfioc_src_nodes *psn = (struct pfioc_src_nodes *)addr;
- struct pf_src_node *n;
- struct pf_src_node *p, pstore;
+ struct pf_src_node *n, *p, *pstore;
u_int32_t nr = 0;
int space = psn->psn_len;
@@ -2701,6 +2728,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
+ pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK);
+
p = psn->psn_src_nodes;
RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
int secs = time_second, diff;
@@ -2708,31 +2737,35 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len)
break;
- bcopy(n, &pstore, sizeof(pstore));
+ bcopy(n, pstore, sizeof(*pstore));
if (n->rule.ptr != NULL)
- pstore.rule.nr = n->rule.ptr->nr;
- pstore.creation = secs - pstore.creation;
- if (pstore.expire > secs)
- pstore.expire -= secs;
+ pstore->rule.nr = n->rule.ptr->nr;
+ pstore->creation = secs - pstore->creation;
+ if (pstore->expire > secs)
+ pstore->expire -= secs;
else
- pstore.expire = 0;
+ pstore->expire = 0;
/* adjust the connection rate estimate */
diff = secs - n->conn_rate.last;
if (diff >= n->conn_rate.seconds)
- pstore.conn_rate.count = 0;
+ pstore->conn_rate.count = 0;
else
- pstore.conn_rate.count -=
+ pstore->conn_rate.count -=
n->conn_rate.count * diff /
n->conn_rate.seconds;
- error = copyout(&pstore, p, sizeof(*p));
- if (error)
+ error = copyout(pstore, p, sizeof(*p));
+ if (error) {
+ free(pstore, M_TEMP);
goto fail;
+ }
p++;
nr++;
}
psn->psn_len = sizeof(struct pf_src_node) * nr;
+
+ free(pstore, M_TEMP);
break;
}
@@ -2748,11 +2781,50 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
n->expire = 1;
n->states = 0;
}
- pf_purge_expired_src_nodes();
+ pf_purge_expired_src_nodes(1);
pf_status.src_nodes = 0;
break;
}
+ case DIOCKILLSRCNODES: {
+ struct pf_src_node *sn;
+ struct pf_state *s;
+ struct pfioc_src_node_kill *psnk = \
+ (struct pfioc_src_node_kill *) addr;
+ int killed = 0;
+
+ RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) {
+ if (PF_MATCHA(psnk->psnk_src.neg, \
+ &psnk->psnk_src.addr.v.a.addr, \
+ &psnk->psnk_src.addr.v.a.mask, \
+ &sn->addr, sn->af) &&
+ PF_MATCHA(psnk->psnk_dst.neg, \
+ &psnk->psnk_dst.addr.v.a.addr, \
+ &psnk->psnk_dst.addr.v.a.mask, \
+ &sn->raddr, sn->af)) {
+ /* Handle state to src_node linkage */
+ if (sn->states != 0) {
+ RB_FOREACH(s, pf_state_tree_id,
+ &tree_id) {
+ if (s->src_node == sn)
+ s->src_node = NULL;
+ if (s->nat_src_node == sn)
+ s->nat_src_node = NULL;
+ }
+ sn->states = 0;
+ }
+ sn->expire = 1;
+ killed++;
+ }
+ }
+
+ if (killed > 0)
+ pf_purge_expired_src_nodes(1);
+
+ psnk->psnk_af = killed;
+ break;
+ }
+
case DIOCSETHOSTID: {
u_int32_t *hostid = (u_int32_t *)addr;
@@ -2770,20 +2842,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCIGETIFACES: {
struct pfioc_iface *io = (struct pfioc_iface *)addr;
- if (io->pfiio_esize != sizeof(struct pfi_if)) {
+ if (io->pfiio_esize != sizeof(struct pfi_kif)) {
error = ENODEV;
break;
}
error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer,
- &io->pfiio_size, io->pfiio_flags);
- break;
- }
-
- case DIOCICLRISTATS: {
- struct pfioc_iface *io = (struct pfioc_iface *)addr;
-
- error = pfi_clr_istats(io->pfiio_name, &io->pfiio_nzero,
- io->pfiio_flags);
+ &io->pfiio_size);
break;
}
@@ -2807,5 +2871,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
fail:
splx(s);
+ if (flags & FWRITE)
+ rw_exit_write(&pf_consistency_lock);
+ else
+ rw_exit_read(&pf_consistency_lock);
return (error);
}
OpenPOWER on IntegriCloud