summaryrefslogtreecommitdiff
path: root/sys/net/pf_table.c
diff options
context:
space:
mode:
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);
+ }
+ }
+}