summaryrefslogtreecommitdiff
path: root/sys/net/pf_table.c
diff options
context:
space:
mode:
authorDaniel Hartmeier <dhartmei@cvs.openbsd.org>2003-01-07 00:21:09 +0000
committerDaniel Hartmeier <dhartmei@cvs.openbsd.org>2003-01-07 00:21:09 +0000
commit0987a4276d8fcff0c0a3f9b07ac039c1f85c744c (patch)
tree7fc8e171b718da2a12e8315418ac80af328baa56 /sys/net/pf_table.c
parentf56df94d448441650adcbba06f82aea81b0d246d (diff)
Remove table name hashing (pass the name in each ioctl instead), and
introduce reference counting for tables, they are now automatically created and deleted through referencing rules. Diff partly from cedric@. ok mcbride@, henning@, cedric@
Diffstat (limited to 'sys/net/pf_table.c')
-rw-r--r--sys/net/pf_table.c223
1 files changed, 78 insertions, 145 deletions
diff --git a/sys/net/pf_table.c b/sys/net/pf_table.c
index 0775961c572..b363bebeaca 100644
--- a/sys/net/pf_table.c
+++ b/sys/net/pf_table.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_table.c,v 1.14 2003/01/06 14:19:40 cedric Exp $ */
+/* $OpenBSD: pf_table.c,v 1.15 2003/01/07 00:21:07 dhartmei Exp $ */
/*
* Copyright (c) 2002 Cedric Berger
@@ -42,8 +42,6 @@
#include <netinet/ip_ipsp.h>
#include <net/pfvar.h>
-#include <crypto/sha1.h>
-
#define ACCEPT_FLAGS(oklist) \
do { \
if ((flags & ~(oklist)) & \
@@ -89,9 +87,6 @@ struct pfr_walktree {
#define pfrw_workq pfrw_1.pfrw1_workq
#define pfrw_cnt pfrw_free
-#define PFR_HASH_BUCKETS 1024
-#define PFR_HASH_BUCKET(hash) ((hash).pfrh_int32[1] & (PFR_HASH_BUCKETS-1))
-
#define senderr(e) do { rv = (e); goto _bad; } while (0)
struct pool pfr_ktable_pl;
@@ -130,18 +125,11 @@ void pfr_destroy_ktable(struct pfr_ktable *);
void pfr_destroy_ktables(struct pfr_ktableworkq *);
int pfr_ktable_compare(struct pfr_ktable *,
struct pfr_ktable *);
-struct pfr_ktable *pfr_lookup_hash(union pfr_hash *);
struct pfr_ktable *pfr_lookup_table(struct pfr_table *);
-int pfr_match_addr(struct pf_addr *, struct pf_addr *,
- struct pf_addr *, sa_family_t);
-void pfr_update_stats(struct pf_addr *, struct pf_addr *,
- struct pf_addr *, sa_family_t, u_int64_t, int, int,
- int);
RB_PROTOTYPE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
RB_GENERATE(pfr_ktablehead, pfr_ktable, pfrkt_tree, pfr_ktable_compare);
-struct pfr_ktablehashq pfr_ktablehash[PFR_HASH_BUCKETS];
struct pfr_ktablehead pfr_ktables;
struct pfr_table pfr_nulltable;
int pfr_ktable_cnt;
@@ -169,7 +157,7 @@ pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
kt = pfr_lookup_table(tbl);
- if (kt == NULL)
+ if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
return (ESRCH);
rv = pfr_enqueue_addrs(kt, &workq, ndel);
if (rv)
@@ -202,7 +190,7 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
kt = pfr_lookup_table(tbl);
- if (kt == NULL)
+ if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
return (ESRCH);
tmpkt = pfr_create_ktable(&pfr_nulltable, 0);
if (tmpkt == NULL)
@@ -265,7 +253,7 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
kt = pfr_lookup_table(tbl);
- if (kt == NULL)
+ if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
return (ESRCH);
bzero(&w, sizeof(w));
@@ -328,7 +316,7 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
kt = pfr_lookup_table(tbl);
- if (kt == NULL)
+ if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
return (ESRCH);
tmpkt = pfr_create_ktable(&pfr_nulltable, 0);
if (tmpkt == NULL)
@@ -444,7 +432,7 @@ pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
ACCEPT_FLAGS(PFR_FLAG_REPLACE);
kt = pfr_lookup_table(tbl);
- if (kt == NULL)
+ if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
return (ESRCH);
for (i = 0; i < size; i++) {
@@ -479,7 +467,7 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
ACCEPT_FLAGS(0);
kt = pfr_lookup_table(tbl);
- if (kt == NULL)
+ if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
return (ESRCH);
if (kt->pfrkt_cnt > *size) {
*size = kt->pfrkt_cnt;
@@ -516,7 +504,7 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
ACCEPT_FLAGS(PFR_FLAG_ATOMIC); /* XXX PFR_FLAG_CLSTATS disabled */
kt = pfr_lookup_table(tbl);
- if (kt == NULL)
+ if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
return (ESRCH);
if (kt->pfrkt_cnt > *size) {
*size = kt->pfrkt_cnt;
@@ -563,7 +551,7 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
kt = pfr_lookup_table(tbl);
- if (kt == NULL)
+ if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE))
return (ESRCH);
SLIST_INIT(&workq);
for (i = 0; i < size; i++) {
@@ -949,18 +937,20 @@ pfr_clr_tables(int *ndel, int flags)
int
pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
{
- struct pfr_ktableworkq workq;
+ struct pfr_ktableworkq workq, changeq;
struct pfr_ktable *p, *q, key;
int i, rv, s, xadd = 0;
long tzero = time.tv_sec;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
SLIST_INIT(&workq);
+ SLIST_INIT(&changeq);
for (i = 0; i < size; i++) {
if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
senderr(EFAULT);
if (key.pfrkt_name[PF_TABLE_NAME_SIZE-1])
senderr(EINVAL);
+ key.pfrkt_flags = PFR_TFLAG_ACTIVE+PFR_TFLAG_PERSIST;
p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
if (p == NULL) {
p = pfr_create_ktable(&key.pfrkt_t, tzero);
@@ -969,19 +959,11 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
SLIST_FOREACH(q, &workq, pfrkt_workq) {
if (!strcmp(p->pfrkt_name, q->pfrkt_name))
goto _skip;
- if (!memcmp(&p->pfrkt_hash, &q->pfrkt_hash,
- sizeof(p->pfrkt_hash))) {
- printf("pfr_add_tables: "
- "sha collision\n");
- senderr(EEXIST);
- }
}
SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
- if (pfr_lookup_hash(&p->pfrkt_hash)) {
- printf("pfr_add_tables: sha collision\n");
- senderr(EEXIST);
- }
xadd++;
+ } else if (!(p->pfrkt_flags & PFR_TFLAG_PERSIST)) {
+ SLIST_INSERT_HEAD(&changeq, p, pfrkt_workq);
}
_skip:
}
@@ -989,6 +971,8 @@ _skip:
if (flags & PFR_FLAG_ATOMIC)
s = splsoftnet();
pfr_insert_ktables(&workq);
+ SLIST_FOREACH(p, &changeq, pfrkt_workq)
+ p->pfrkt_flags |= PFR_TFLAG_PERSIST;
if (flags & PFR_FLAG_ATOMIC)
splx(s);
} else
@@ -1004,22 +988,27 @@ _bad:
int
pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
{
- struct pfr_ktableworkq workq;
+ struct pfr_ktableworkq workq, changeq;
struct pfr_ktable *p, *q, key;
int i, s, xdel = 0;
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
SLIST_INIT(&workq);
+ SLIST_INIT(&changeq);
for (i = 0; i < size; i++) {
if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
return (EFAULT);
p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
if (p != NULL) {
- SLIST_FOREACH(q, &workq, pfrkt_workq)
+ struct pfr_ktableworkq *queue;
+
+ queue = (p->pfrkt_refcnt > 0) ? &changeq : &workq;
+ SLIST_FOREACH(q, queue, pfrkt_workq)
if (!strcmp(p->pfrkt_name, q->pfrkt_name))
goto _skip;
- SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
- xdel++;
+ SLIST_INSERT_HEAD(queue, p, pfrkt_workq);
+ if (queue == &workq)
+ xdel++;
}
_skip:
}
@@ -1028,6 +1017,8 @@ _skip:
if (flags & PFR_FLAG_ATOMIC)
s = splsoftnet();
pfr_remove_ktables(&workq);
+ SLIST_FOREACH(p, &changeq, pfrkt_workq)
+ p->pfrkt_flags &= ~PFR_TFLAG_PERSIST;
if (flags & PFR_FLAG_ATOMIC)
splx(s);
}
@@ -1135,62 +1126,11 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
return (0);
}
-int
-pfr_wrap_table(struct pfr_table *tbl, struct pf_addr_wrap *wrap,
- int *exists, int flags)
-{
- union pfr_hash hash;
- struct pf_addr_wrap w;
- SHA1_CTX sha1;
-
- ACCEPT_FLAGS(0);
- if (!*tbl->pfrt_name || tbl->pfrt_name[PF_TABLE_NAME_SIZE-1])
- return (EINVAL);
- SHA1Init(&sha1);
- SHA1Update(&sha1, tbl->pfrt_name, strlen(tbl->pfrt_name));
- SHA1Final(hash.pfrh_sha1, &sha1);
-
- bzero(&w, sizeof(w));
- bcopy(&hash, &w.v.a.addr, sizeof(w.v.a.addr));
- w.v.a.mask.addr32[0] = PF_TABLE_MASK;
- w.v.a.mask.addr32[1] = hash.pfrh_int32[4];
- if (copyout(&w, wrap, sizeof(*wrap)))
- return (EFAULT);
-
- if (exists != NULL)
- *exists = pfr_lookup_table(tbl) != NULL;
- return (0);
-}
-
-int
-pfr_unwrap_table(struct pfr_table *tbl, struct pf_addr_wrap *wrap, int flags)
-{
- union pfr_hash hash;
- struct pf_addr_wrap w;
- struct pfr_ktable *kt;
-
- ACCEPT_FLAGS(0);
- if (copyin(wrap, &w, sizeof(w)))
- return (EFAULT);
-
- if (w.v.a.mask.addr32[0] != PF_TABLE_MASK || w.v.a.mask.addr32[2] ||
- w.v.a.mask.addr32[3])
- return (EINVAL);
-
- bcopy(&w.v.a.addr, &hash, 16);
- hash.pfrh_int32[4] = w.v.a.mask.addr32[1];
- kt = pfr_lookup_hash(&hash);
- if (kt == NULL)
- return (ENOENT);
- *tbl = kt->pfrkt_t;
- return (0);
-}
-
void
pfr_insert_ktables(struct pfr_ktableworkq *workq)
{
struct pfr_ktable *p;
- int s, n = 0;
+ int n = 0;
/* insert into tree */
SLIST_FOREACH(p, workq, pfrkt_workq) {
@@ -1198,14 +1138,6 @@ pfr_insert_ktables(struct pfr_ktableworkq *workq)
n++;
}
pfr_ktable_cnt += n;
-
- SLIST_FOREACH(p, workq, pfrkt_workq) {
- s = splsoftnet();
- SLIST_INSERT_HEAD(pfr_ktablehash +
- PFR_HASH_BUCKET(p->pfrkt_hash),
- p, pfrkt_hashq);
- splx(s);
- }
}
void
@@ -1213,14 +1145,7 @@ pfr_remove_ktables(struct pfr_ktableworkq *workq)
{
struct pfr_kentryworkq addrq;
struct pfr_ktable *p;
- int s, n = 0;
-
- SLIST_FOREACH(p, workq, pfrkt_workq) {
- s = splsoftnet();
- SLIST_REMOVE(pfr_ktablehash + PFR_HASH_BUCKET(p->pfrkt_hash),
- p, pfr_ktable, pfrkt_hashq);
- splx(s);
- }
+ int n = 0;
SLIST_FOREACH(p, workq, pfrkt_workq) {
RB_REMOVE(pfr_ktablehead, &pfr_ktables, p);
@@ -1259,7 +1184,6 @@ struct pfr_ktable *
pfr_create_ktable(struct pfr_table *tbl, long tzero)
{
struct pfr_ktable *kt;
- SHA1_CTX sha1;
kt = pool_get(&pfr_ktable_pl, PR_NOWAIT);
if (kt == NULL)
@@ -1267,11 +1191,6 @@ pfr_create_ktable(struct pfr_table *tbl, long tzero)
bzero(kt, sizeof(*kt));
kt->pfrkt_t = *tbl;
- /* compute secure hash */
- SHA1Init(&sha1);
- SHA1Update(&sha1, kt->pfrkt_name, strlen(kt->pfrkt_name));
- SHA1Final(kt->pfrkt_hash.pfrh_sha1, &sha1);
-
if (!rn_inithead((void **)&kt->pfrkt_ip4,
offsetof(struct sockaddr_in, sin_addr) * 8) ||
!rn_inithead((void **)&kt->pfrkt_ip6,
@@ -1314,17 +1233,6 @@ pfr_ktable_compare(struct pfr_ktable *p, struct pfr_ktable *q)
}
struct pfr_ktable *
-pfr_lookup_hash(union pfr_hash *hash)
-{
- struct pfr_ktable *p;
-
- SLIST_FOREACH(p, pfr_ktablehash+PFR_HASH_BUCKET(*hash), pfrkt_hashq)
- if (!memcmp(p->pfrkt_hash.pfrh_sha1, hash->pfrh_sha1, 20))
- return (p);
- return (NULL);
-}
-
-struct pfr_ktable *
pfr_lookup_table(struct pfr_table *tbl)
{
/* struct pfr_ktable start like a struct pfr_table */
@@ -1338,26 +1246,18 @@ pfr_lookup_table(struct pfr_table *tbl)
* are different.
*/
int
-pfr_match_addr(struct pf_addr *a, struct pf_addr *m,
- struct pf_addr *b, sa_family_t af)
+pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af)
{
- union pfr_hash hash;
- struct pfr_ktable *kt;
struct pfr_kentry *ke = NULL;
int match;
- bcopy(a, &hash, 16);
- hash.pfrh_int32[4] = m->addr32[1];
- kt = pfr_lookup_hash(&hash);
- if (kt == NULL)
- return (0);
switch (af) {
case AF_INET:
- pfr_sin.sin_addr.s_addr = b->addr32[0];
+ pfr_sin.sin_addr.s_addr = a->addr32[0];
ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
break;
case AF_INET6:
- bcopy(&b, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
+ bcopy(&a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
break;
}
@@ -1370,27 +1270,18 @@ pfr_match_addr(struct pf_addr *a, struct pf_addr *m,
}
void
-pfr_update_stats(struct pf_addr *a, struct pf_addr *m,
- struct pf_addr *b, sa_family_t af, u_int64_t len,
- int dir_out, int op_pass, int notrule)
+pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
+ u_int64_t len, int dir_out, int op_pass, int notrule)
{
- union pfr_hash hash;
- struct pfr_ktable *kt;
struct pfr_kentry *ke = NULL;
- bcopy(a, &hash, 16);
- hash.pfrh_int32[4] = m->addr32[1];
- kt = pfr_lookup_hash(&hash);
- if (kt == NULL)
- return;
-
switch (af) {
case AF_INET:
- pfr_sin.sin_addr.s_addr = b->addr32[0];
+ pfr_sin.sin_addr.s_addr = a->addr32[0];
ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4);
break;
case AF_INET6:
- bcopy(&b, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
+ bcopy(&a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr));
ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6);
break;
}
@@ -1406,3 +1297,45 @@ pfr_update_stats(struct pf_addr *a, struct pf_addr *m,
ke->pfrke_bytes[dir_out][op_pass] += len;
}
}
+
+struct pfr_ktable *
+pfr_attach_table(char *name)
+{
+ struct pfr_ktable *p, key;
+ struct pfr_ktableworkq workq;
+
+ bzero(&key, sizeof(key));
+ strlcpy(key.pfrkt_name, name, sizeof(key.pfrkt_name));
+ key.pfrkt_flags = PFR_TFLAG_ACTIVE;
+ p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
+ if (p == NULL) {
+ p = pfr_create_ktable(&key.pfrkt_t, time.tv_sec);
+ if (p == NULL)
+ return NULL;
+ SLIST_INIT(&workq);
+ SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
+ pfr_insert_ktables(&workq);
+ }
+ p->pfrkt_refcnt++;
+ return p;
+}
+
+void
+pfr_detach_table(struct pfr_ktable *kt)
+{
+ struct pfr_ktableworkq workq;
+
+ if (kt->pfrkt_refcnt <= 0)
+ printf("pfr_detach_table, refcount = %d\n",
+ kt->pfrkt_refcnt);
+ else {
+ kt->pfrkt_refcnt--;
+ if (kt->pfrkt_refcnt == 0 &&
+ !(kt->pfrkt_flags & PFR_TFLAG_PERSIST)) {
+ kt->pfrkt_flags &= ~PFR_TFLAG_ACTIVE;
+ SLIST_INIT(&workq);
+ SLIST_INSERT_HEAD(&workq, kt, pfrkt_workq);
+ pfr_remove_ktables(&workq);
+ }
+ }
+}