Add support for CDB based NPF tables.
This commit is contained in:
parent
17a304eec5
commit
ffcdc4af8d
|
@ -1,7 +1,7 @@
|
|||
/* $NetBSD: npf.c,v 1.25 2014/02/03 02:21:52 rmind Exp $ */
|
||||
/* $NetBSD: npf.c,v 1.26 2014/02/06 02:51:28 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
|
||||
* Copyright (c) 2010-2014 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This material is based upon work partially supported by The
|
||||
|
@ -30,7 +30,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.25 2014/02/03 02:21:52 rmind Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.26 2014/02/06 02:51:28 rmind Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in_systm.h>
|
||||
|
@ -961,6 +961,20 @@ npf_table_add_entry(nl_table_t *tl, int af, const npf_addr_t *addr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
npf_table_setdata(nl_table_t *tl, const void *blob, size_t len)
|
||||
{
|
||||
prop_dictionary_t tldict = tl->ntl_dict;
|
||||
prop_data_t bobj;
|
||||
|
||||
if ((bobj = prop_data_create_data(blob, len)) == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
prop_dictionary_set(tldict, "data", bobj);
|
||||
prop_object_release(bobj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
_npf_table_exists_p(nl_config_t *ncf, const char *name)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: npf.h,v 1.22 2014/02/03 02:21:52 rmind Exp $ */
|
||||
/* $NetBSD: npf.h,v 1.23 2014/02/06 02:51:28 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
|
||||
|
@ -111,6 +111,7 @@ int npf_nat_insert(nl_config_t *, nl_nat_t *, pri_t);
|
|||
nl_table_t * npf_table_create(const char *, u_int, int);
|
||||
int npf_table_add_entry(nl_table_t *, int,
|
||||
const npf_addr_t *, const npf_netmask_t);
|
||||
int npf_table_setdata(nl_table_t *, const void *, size_t);
|
||||
int npf_table_insert(nl_config_t *, nl_table_t *);
|
||||
void npf_table_destroy(nl_table_t *);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: npf.h,v 1.34 2013/12/06 01:33:37 rmind Exp $ */
|
||||
/* $NetBSD: npf.h,v 1.35 2014/02/06 02:51:28 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
|
||||
|
@ -239,6 +239,7 @@ bool npf_autounload_p(void);
|
|||
/* Table types. */
|
||||
#define NPF_TABLE_HASH 1
|
||||
#define NPF_TABLE_TREE 2
|
||||
#define NPF_TABLE_CDB 3
|
||||
|
||||
#define NPF_TABLE_MAXNAMELEN 32
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $NetBSD: npf_ctl.c,v 1.32 2013/11/12 00:46:34 rmind Exp $ */
|
||||
/* $NetBSD: npf_ctl.c,v 1.33 2014/02/06 02:51:28 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
|
||||
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This material is based upon work partially supported by The
|
||||
|
@ -37,7 +37,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.32 2013/11/12 00:46:34 rmind Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.33 2014/02/06 02:51:28 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/conf.h>
|
||||
|
@ -76,6 +76,34 @@ npfctl_switch(void *data)
|
|||
return error;
|
||||
}
|
||||
|
||||
static int __noinline
|
||||
npf_mk_table_entries(npf_table_t *t, prop_array_t entries)
|
||||
{
|
||||
prop_object_iterator_t eit;
|
||||
prop_dictionary_t ent;
|
||||
int error = 0;
|
||||
|
||||
/* Fill all the entries. */
|
||||
eit = prop_array_iterator(entries);
|
||||
while ((ent = prop_object_iterator_next(eit)) != NULL) {
|
||||
const npf_addr_t *addr;
|
||||
npf_netmask_t mask;
|
||||
int alen;
|
||||
|
||||
/* Get address and mask. Add a table entry. */
|
||||
prop_object_t obj = prop_dictionary_get(ent, "addr");
|
||||
addr = (const npf_addr_t *)prop_data_data_nocopy(obj);
|
||||
prop_dictionary_get_uint8(ent, "mask", &mask);
|
||||
alen = prop_data_size(obj);
|
||||
|
||||
error = npf_table_insert(t, alen, addr, mask);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
prop_object_iterator_release(eit);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __noinline
|
||||
npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables,
|
||||
prop_dictionary_t errdict)
|
||||
|
@ -92,9 +120,6 @@ npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables,
|
|||
|
||||
it = prop_array_iterator(tables);
|
||||
while ((tbldict = prop_object_iterator_next(it)) != NULL) {
|
||||
prop_dictionary_t ent;
|
||||
prop_object_iterator_t eit;
|
||||
prop_array_t entries;
|
||||
const char *name;
|
||||
npf_table_t *t;
|
||||
u_int tid;
|
||||
|
@ -121,8 +146,25 @@ npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables,
|
|||
break;
|
||||
}
|
||||
|
||||
/* Get the entries or binary data. */
|
||||
prop_array_t entries = prop_dictionary_get(tbldict, "entries");
|
||||
if (prop_object_type(entries) != PROP_TYPE_ARRAY) {
|
||||
NPF_ERR_DEBUG(errdict);
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
prop_object_t obj = prop_dictionary_get(tbldict, "data");
|
||||
void *blob = prop_data_data(obj);
|
||||
size_t size = prop_data_size(obj);
|
||||
|
||||
if (type == NPF_TABLE_CDB && (blob == NULL || size == 0)) {
|
||||
NPF_ERR_DEBUG(errdict);
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Create and insert the table. */
|
||||
t = npf_table_create(name, tid, type, 1024); /* XXX */
|
||||
t = npf_table_create(name, tid, type, blob, size);
|
||||
if (t == NULL) {
|
||||
NPF_ERR_DEBUG(errdict);
|
||||
error = ENOMEM;
|
||||
|
@ -131,32 +173,10 @@ npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables,
|
|||
error = npf_tableset_insert(tblset, t);
|
||||
KASSERT(error == 0);
|
||||
|
||||
/* Entries. */
|
||||
entries = prop_dictionary_get(tbldict, "entries");
|
||||
if (prop_object_type(entries) != PROP_TYPE_ARRAY) {
|
||||
if ((error = npf_mk_table_entries(t, entries)) != 0) {
|
||||
NPF_ERR_DEBUG(errdict);
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
eit = prop_array_iterator(entries);
|
||||
while ((ent = prop_object_iterator_next(eit)) != NULL) {
|
||||
const npf_addr_t *addr;
|
||||
npf_netmask_t mask;
|
||||
int alen;
|
||||
|
||||
/* Get address and mask. Add a table entry. */
|
||||
prop_object_t obj = prop_dictionary_get(ent, "addr");
|
||||
addr = (const npf_addr_t *)prop_data_data_nocopy(obj);
|
||||
prop_dictionary_get_uint8(ent, "mask", &mask);
|
||||
alen = prop_data_size(obj);
|
||||
|
||||
error = npf_table_insert(t, alen, addr, mask);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
prop_object_iterator_release(eit);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
prop_object_iterator_release(it);
|
||||
/*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: npf_impl.h,v 1.45 2013/12/06 01:33:37 rmind Exp $ */
|
||||
/* $NetBSD: npf_impl.h,v 1.46 2014/02/06 02:51:28 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
|
||||
|
@ -229,7 +229,7 @@ npf_table_t * npf_tableset_getbyid(npf_tableset_t *, u_int);
|
|||
void npf_tableset_reload(npf_tableset_t *, npf_tableset_t *);
|
||||
void npf_tableset_syncdict(const npf_tableset_t *, prop_dictionary_t);
|
||||
|
||||
npf_table_t * npf_table_create(const char *, u_int, int, size_t);
|
||||
npf_table_t * npf_table_create(const char *, u_int, int, void *, size_t);
|
||||
void npf_table_destroy(npf_table_t *);
|
||||
|
||||
int npf_table_check(npf_tableset_t *, const char *, u_int, int);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $NetBSD: npf_tableset.c,v 1.20 2013/11/22 00:25:51 rmind Exp $ */
|
||||
/* $NetBSD: npf_tableset.c,v 1.21 2014/02/06 02:51:28 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
|
||||
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This material is based upon work partially supported by The
|
||||
|
@ -41,14 +41,16 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.20 2013/11/22 00:25:51 rmind Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.21 2014/02/06 02:51:28 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <sys/atomic.h>
|
||||
#include <sys/hash.h>
|
||||
#include <sys/cdbr.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/pool.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/rwlock.h>
|
||||
|
@ -59,9 +61,9 @@ __KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.20 2013/11/22 00:25:51 rmind Exp
|
|||
|
||||
typedef struct npf_tblent {
|
||||
union {
|
||||
LIST_ENTRY(npf_tblent) hashq;
|
||||
pt_node_t node;
|
||||
} te_entry;
|
||||
LIST_ENTRY(npf_tblent) te_hashent;
|
||||
pt_node_t te_node;
|
||||
} /* C11 */;
|
||||
int te_alen;
|
||||
npf_addr_t te_addr;
|
||||
} npf_tblent_t;
|
||||
|
@ -70,12 +72,23 @@ LIST_HEAD(npf_hashl, npf_tblent);
|
|||
|
||||
struct npf_table {
|
||||
/*
|
||||
* The storage type can be: a) hash b) tree.
|
||||
* The storage type can be: a) hash b) tree c) cdb.
|
||||
* There are separate trees for IPv4 and IPv6.
|
||||
*/
|
||||
struct npf_hashl * t_hashl;
|
||||
u_long t_hashmask;
|
||||
pt_tree_t t_tree[2];
|
||||
union {
|
||||
struct {
|
||||
struct npf_hashl *t_hashl;
|
||||
u_long t_hashmask;
|
||||
};
|
||||
struct {
|
||||
pt_tree_t t_tree[2];
|
||||
};
|
||||
struct {
|
||||
void * t_blob;
|
||||
size_t t_bsize;
|
||||
struct cdbr * t_cdb;
|
||||
};
|
||||
} /* C11 */;
|
||||
|
||||
/*
|
||||
* Table ID, type and lock. The ID may change during the
|
||||
|
@ -237,7 +250,7 @@ npf_tableset_reload(npf_tableset_t *nts, npf_tableset_t *ots)
|
|||
KASSERT(npf_config_locked_p());
|
||||
ot->t_id = tid;
|
||||
|
||||
/* Destroy the new table (we hold only reference). */
|
||||
/* Destroy the new table (we hold the only reference). */
|
||||
t->t_refcnt--;
|
||||
npf_table_destroy(t);
|
||||
}
|
||||
|
@ -284,7 +297,7 @@ table_hash_lookup(const npf_table_t *t, const npf_addr_t *addr,
|
|||
* Lookup the hash table and check for duplicates.
|
||||
* Note: mask is ignored for the hash storage.
|
||||
*/
|
||||
LIST_FOREACH(ent, htbl, te_entry.hashq) {
|
||||
LIST_FOREACH(ent, htbl, te_hashent) {
|
||||
if (ent->te_alen != alen) {
|
||||
continue;
|
||||
}
|
||||
|
@ -303,7 +316,7 @@ table_hash_destroy(npf_table_t *t)
|
|||
npf_tblent_t *ent;
|
||||
|
||||
while ((ent = LIST_FIRST(&t->t_hashl[n])) != NULL) {
|
||||
LIST_REMOVE(ent, te_entry.hashq);
|
||||
LIST_REMOVE(ent, te_hashent);
|
||||
pool_cache_put(tblent_cache, ent);
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +337,8 @@ table_tree_destroy(pt_tree_t *tree)
|
|||
* npf_table_create: create table with a specified ID.
|
||||
*/
|
||||
npf_table_t *
|
||||
npf_table_create(const char *name, u_int tid, int type, size_t hsize)
|
||||
npf_table_create(const char *name, u_int tid, int type,
|
||||
void *blob, size_t size)
|
||||
{
|
||||
npf_table_t *t;
|
||||
|
||||
|
@ -335,20 +349,31 @@ npf_table_create(const char *name, u_int tid, int type, size_t hsize)
|
|||
case NPF_TABLE_TREE:
|
||||
ptree_init(&t->t_tree[0], &npf_table_ptree_ops,
|
||||
(void *)(sizeof(struct in_addr) / sizeof(uint32_t)),
|
||||
offsetof(npf_tblent_t, te_entry.node),
|
||||
offsetof(npf_tblent_t, te_node),
|
||||
offsetof(npf_tblent_t, te_addr));
|
||||
ptree_init(&t->t_tree[1], &npf_table_ptree_ops,
|
||||
(void *)(sizeof(struct in6_addr) / sizeof(uint32_t)),
|
||||
offsetof(npf_tblent_t, te_entry.node),
|
||||
offsetof(npf_tblent_t, te_node),
|
||||
offsetof(npf_tblent_t, te_addr));
|
||||
break;
|
||||
case NPF_TABLE_HASH:
|
||||
t->t_hashl = hashinit(hsize, HASH_LIST, true, &t->t_hashmask);
|
||||
t->t_hashl = hashinit(1024, HASH_LIST, true, &t->t_hashmask);
|
||||
if (t->t_hashl == NULL) {
|
||||
kmem_free(t, sizeof(npf_table_t));
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case NPF_TABLE_CDB:
|
||||
t->t_blob = blob;
|
||||
t->t_bsize = size;
|
||||
t->t_cdb = cdbr_open_mem(blob, size, CDBR_DEFAULT, NULL, NULL);
|
||||
if (t->t_cdb == NULL) {
|
||||
kmem_free(t, sizeof(npf_table_t));
|
||||
free(blob, M_TEMP);
|
||||
return NULL;
|
||||
}
|
||||
t->t_nitems = cdbr_entries(t->t_cdb);
|
||||
break;
|
||||
default:
|
||||
KASSERT(false);
|
||||
}
|
||||
|
@ -376,6 +401,10 @@ npf_table_destroy(npf_table_t *t)
|
|||
table_tree_destroy(&t->t_tree[0]);
|
||||
table_tree_destroy(&t->t_tree[1]);
|
||||
break;
|
||||
case NPF_TABLE_CDB:
|
||||
cdbr_close(t->t_cdb);
|
||||
free(t->t_blob, M_TEMP);
|
||||
break;
|
||||
default:
|
||||
KASSERT(false);
|
||||
}
|
||||
|
@ -395,7 +424,12 @@ npf_table_check(npf_tableset_t *ts, const char *name, u_int tid, int type)
|
|||
if (ts->ts_map[tid] != NULL) {
|
||||
return EEXIST;
|
||||
}
|
||||
if (type != NPF_TABLE_TREE && type != NPF_TABLE_HASH) {
|
||||
switch (type) {
|
||||
case NPF_TABLE_TREE:
|
||||
case NPF_TABLE_HASH:
|
||||
case NPF_TABLE_CDB:
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
if (strlen(name) >= NPF_TABLE_MAXNAMELEN) {
|
||||
|
@ -463,7 +497,7 @@ npf_table_insert(npf_table_t *t, const int alen,
|
|||
break;
|
||||
}
|
||||
if (!table_hash_lookup(t, addr, alen, &htbl)) {
|
||||
LIST_INSERT_HEAD(htbl, ent, te_entry.hashq);
|
||||
LIST_INSERT_HEAD(htbl, ent, te_hashent);
|
||||
t->t_nitems++;
|
||||
} else {
|
||||
error = EEXIST;
|
||||
|
@ -488,6 +522,9 @@ npf_table_insert(npf_table_t *t, const int alen,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case NPF_TABLE_CDB:
|
||||
error = EINVAL;
|
||||
break;
|
||||
default:
|
||||
KASSERT(false);
|
||||
}
|
||||
|
@ -507,8 +544,8 @@ npf_table_remove(npf_table_t *t, const int alen,
|
|||
const npf_addr_t *addr, const npf_netmask_t mask)
|
||||
{
|
||||
const u_int aidx = NPF_ADDRLEN2TREE(alen);
|
||||
npf_tblent_t *ent;
|
||||
int error;
|
||||
npf_tblent_t *ent = NULL;
|
||||
int error = ENOENT;
|
||||
|
||||
error = table_cidr_check(aidx, addr, mask);
|
||||
if (error) {
|
||||
|
@ -522,7 +559,7 @@ npf_table_remove(npf_table_t *t, const int alen,
|
|||
|
||||
ent = table_hash_lookup(t, addr, alen, &htbl);
|
||||
if (__predict_true(ent != NULL)) {
|
||||
LIST_REMOVE(ent, te_entry.hashq);
|
||||
LIST_REMOVE(ent, te_hashent);
|
||||
t->t_nitems--;
|
||||
}
|
||||
break;
|
||||
|
@ -537,17 +574,19 @@ npf_table_remove(npf_table_t *t, const int alen,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case NPF_TABLE_CDB:
|
||||
error = EINVAL;
|
||||
break;
|
||||
default:
|
||||
KASSERT(false);
|
||||
ent = NULL;
|
||||
}
|
||||
rw_exit(&t->t_lock);
|
||||
|
||||
if (ent == NULL) {
|
||||
return ENOENT;
|
||||
if (ent) {
|
||||
pool_cache_put(tblent_cache, ent);
|
||||
}
|
||||
pool_cache_put(tblent_cache, ent);
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -558,34 +597,43 @@ int
|
|||
npf_table_lookup(npf_table_t *t, const int alen, const npf_addr_t *addr)
|
||||
{
|
||||
const u_int aidx = NPF_ADDRLEN2TREE(alen);
|
||||
npf_tblent_t *ent;
|
||||
struct npf_hashl *htbl;
|
||||
const void *data;
|
||||
size_t dlen;
|
||||
bool found;
|
||||
|
||||
if (__predict_false(aidx > 1)) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
rw_enter(&t->t_lock, RW_READER);
|
||||
switch (t->t_type) {
|
||||
case NPF_TABLE_HASH: {
|
||||
struct npf_hashl *htbl;
|
||||
ent = table_hash_lookup(t, addr, alen, &htbl);
|
||||
case NPF_TABLE_HASH:
|
||||
rw_enter(&t->t_lock, RW_READER);
|
||||
found = table_hash_lookup(t, addr, alen, &htbl) != NULL;
|
||||
rw_exit(&t->t_lock);
|
||||
break;
|
||||
}
|
||||
case NPF_TABLE_TREE: {
|
||||
ent = ptree_find_node(&t->t_tree[aidx], addr);
|
||||
case NPF_TABLE_TREE:
|
||||
rw_enter(&t->t_lock, RW_READER);
|
||||
found = ptree_find_node(&t->t_tree[aidx], addr) != NULL;
|
||||
rw_exit(&t->t_lock);
|
||||
break;
|
||||
case NPF_TABLE_CDB:
|
||||
if (cdbr_find(t->t_cdb, addr, alen, &data, &dlen) == 0) {
|
||||
found = dlen == alen && memcmp(addr, data, dlen) == 0;
|
||||
} else {
|
||||
found = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
KASSERT(false);
|
||||
ent = NULL;
|
||||
found = false;
|
||||
}
|
||||
rw_exit(&t->t_lock);
|
||||
|
||||
return ent ? 0 : ENOENT;
|
||||
return found ? 0 : ENOENT;
|
||||
}
|
||||
|
||||
static int
|
||||
table_ent_copyout(npf_tblent_t *ent, npf_netmask_t mask,
|
||||
table_ent_copyout(const npf_addr_t *addr, const int alen, npf_netmask_t mask,
|
||||
void *ubuf, size_t len, size_t *off)
|
||||
{
|
||||
void *ubufp = (uint8_t *)ubuf + *off;
|
||||
|
@ -594,13 +642,32 @@ table_ent_copyout(npf_tblent_t *ent, npf_netmask_t mask,
|
|||
if ((*off += sizeof(npf_ioctl_ent_t)) > len) {
|
||||
return ENOMEM;
|
||||
}
|
||||
uent.alen = ent->te_alen;
|
||||
memcpy(&uent.addr, &ent->te_addr, sizeof(npf_addr_t));
|
||||
uent.alen = alen;
|
||||
memcpy(&uent.addr, addr, sizeof(npf_addr_t));
|
||||
uent.mask = mask;
|
||||
|
||||
return copyout(&uent, ubufp, sizeof(npf_ioctl_ent_t));
|
||||
}
|
||||
|
||||
static int
|
||||
table_hash_list(const npf_table_t *t, void *ubuf, size_t len)
|
||||
{
|
||||
size_t off = 0;
|
||||
int error = 0;
|
||||
|
||||
for (unsigned n = 0; n <= t->t_hashmask; n++) {
|
||||
npf_tblent_t *ent;
|
||||
|
||||
LIST_FOREACH(ent, &t->t_hashl[n], te_hashent) {
|
||||
error = table_ent_copyout(&ent->te_addr,
|
||||
ent->te_alen, 0, ubuf, len, &off);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
table_tree_list(pt_tree_t *tree, npf_netmask_t maxmask, void *ubuf,
|
||||
size_t len, size_t *off)
|
||||
|
@ -614,7 +681,26 @@ table_tree_list(pt_tree_t *tree, npf_netmask_t maxmask, void *ubuf,
|
|||
if (!ptree_mask_node_p(tree, ent, &blen)) {
|
||||
blen = maxmask;
|
||||
}
|
||||
error = table_ent_copyout(ent, blen, ubuf, len, off);
|
||||
error = table_ent_copyout(&ent->te_addr, ent->te_alen,
|
||||
blen, ubuf, len, off);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
table_cdb_list(npf_table_t *t, void *ubuf, size_t len)
|
||||
{
|
||||
size_t off = 0, dlen;
|
||||
const void *data;
|
||||
int error = 0;
|
||||
|
||||
for (size_t i = 0; i < t->t_nitems; i++) {
|
||||
if (cdbr_get(t->t_cdb, i, &data, &dlen) != 0) {
|
||||
return EINVAL;
|
||||
}
|
||||
error = table_ent_copyout(data, dlen, 0, ubuf, len, &off);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
|
@ -633,14 +719,7 @@ npf_table_list(npf_table_t *t, void *ubuf, size_t len)
|
|||
rw_enter(&t->t_lock, RW_READER);
|
||||
switch (t->t_type) {
|
||||
case NPF_TABLE_HASH:
|
||||
for (unsigned n = 0; n <= t->t_hashmask; n++) {
|
||||
npf_tblent_t *ent;
|
||||
|
||||
LIST_FOREACH(ent, &t->t_hashl[n], te_entry.hashq)
|
||||
if ((error = table_ent_copyout(ent, 0, ubuf,
|
||||
len, &off)) != 0)
|
||||
break;
|
||||
}
|
||||
error = table_hash_list(t, ubuf, len);
|
||||
break;
|
||||
case NPF_TABLE_TREE:
|
||||
error = table_tree_list(&t->t_tree[0], 32, ubuf, len, &off);
|
||||
|
@ -648,6 +727,9 @@ npf_table_list(npf_table_t *t, void *ubuf, size_t len)
|
|||
break;
|
||||
error = table_tree_list(&t->t_tree[1], 128, ubuf, len, &off);
|
||||
break;
|
||||
case NPF_TABLE_CDB:
|
||||
error = table_cdb_list(t, ubuf, len);
|
||||
break;
|
||||
default:
|
||||
KASSERT(false);
|
||||
}
|
||||
|
@ -662,6 +744,8 @@ npf_table_list(npf_table_t *t, void *ubuf, size_t len)
|
|||
int
|
||||
npf_table_flush(npf_table_t *t)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
rw_enter(&t->t_lock, RW_WRITER);
|
||||
switch (t->t_type) {
|
||||
case NPF_TABLE_HASH:
|
||||
|
@ -673,9 +757,12 @@ npf_table_flush(npf_table_t *t)
|
|||
table_tree_destroy(&t->t_tree[1]);
|
||||
t->t_nitems = 0;
|
||||
break;
|
||||
case NPF_TABLE_CDB:
|
||||
error = EINVAL;
|
||||
break;
|
||||
default:
|
||||
KASSERT(false);
|
||||
}
|
||||
rw_exit(&t->t_lock);
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" $NetBSD: npf.conf.5,v 1.35 2013/11/19 00:28:41 rmind Exp $
|
||||
.\" $NetBSD: npf.conf.5,v 1.36 2014/02/06 02:51:28 rmind Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
|
||||
.\" Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" This material is based upon work partially supported by The
|
||||
|
@ -27,7 +27,7 @@
|
|||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd November 18, 2013
|
||||
.Dd February 6, 2014
|
||||
.Dt NPF.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -85,7 +85,7 @@ The following is an example of table definition:
|
|||
table <black> type hash dynamic
|
||||
.Pp
|
||||
.Ed
|
||||
Currently, tables support two storage types: "hash" or "tree".
|
||||
Currently, tables support two storage types: "hash", "tree" or "cdb".
|
||||
They can also be "dynamic" or static i.e. loaded from the specified file.
|
||||
.Pp
|
||||
The file should contain a list of IP addresses and/or networks in the form of:
|
||||
|
@ -94,7 +94,8 @@ The file should contain a list of IP addresses and/or networks in the form of:
|
|||
10.1.1.1
|
||||
.Ed
|
||||
.Pp
|
||||
Tables of type "hash" can only contain IP addresses.
|
||||
Tables of type "hash" and "cdb" can only contain IP addresses.
|
||||
Also, the latter can only be static.
|
||||
.Ss Interfaces
|
||||
Interfaces can be specified as the values of the variables:
|
||||
.Pp
|
||||
|
@ -223,7 +224,7 @@ var-def = var "=" ( var-value | "{" value *[ "," value ] "}" )
|
|||
; Table definition. Table ID shall be numeric. Path is in the double quotes.
|
||||
|
||||
table-id = \*[Lt]table-name\*[Gt]
|
||||
table-def = "table" table-id "type" ( "hash" | "tree" )
|
||||
table-def = "table" table-id "type" ( "hash" | "tree" | "cdb" )
|
||||
( "dynamic" | "file" path )
|
||||
|
||||
; Mapping for address translation.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $NetBSD: npf_build.c,v 1.32 2014/02/03 02:21:52 rmind Exp $ */
|
||||
/* $NetBSD: npf_build.c,v 1.33 2014/02/06 02:51:28 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
|
||||
* Copyright (c) 2011-2014 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This material is based upon work partially supported by The
|
||||
|
@ -34,19 +34,22 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: npf_build.c,v 1.32 2014/02/03 02:21:52 rmind Exp $");
|
||||
__RCSID("$NetBSD: npf_build.c,v 1.33 2014/02/06 02:51:28 rmind Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
|
||||
#include <pcap/pcap.h>
|
||||
#include <cdbw.h>
|
||||
|
||||
#include "npfctl.h"
|
||||
|
||||
|
@ -635,11 +638,15 @@ npfctl_build_natseg(int sd, int type, const char *ifname,
|
|||
static void
|
||||
npfctl_fill_table(nl_table_t *tl, u_int type, const char *fname)
|
||||
{
|
||||
struct cdbw *cdbw;
|
||||
char *buf = NULL;
|
||||
int l = 0;
|
||||
FILE *fp;
|
||||
size_t n;
|
||||
|
||||
if (type == NPF_TABLE_CDB && (cdbw = cdbw_open()) == NULL) {
|
||||
err(EXIT_FAILURE, "cdbw_open");
|
||||
}
|
||||
fp = fopen(fname, "r");
|
||||
if (fp == NULL) {
|
||||
err(EXIT_FAILURE, "open '%s'", fname);
|
||||
|
@ -656,18 +663,56 @@ npfctl_fill_table(nl_table_t *tl, u_int type, const char *fname)
|
|||
errx(EXIT_FAILURE,
|
||||
"%s:%d: invalid table entry", fname, l);
|
||||
}
|
||||
if (type == NPF_TABLE_HASH && fam.fam_mask != NPF_NO_NETMASK) {
|
||||
errx(EXIT_FAILURE,
|
||||
"%s:%d: mask used with the hash table", fname, l);
|
||||
if (type != NPF_TABLE_TREE && fam.fam_mask != NPF_NO_NETMASK) {
|
||||
errx(EXIT_FAILURE, "%s:%d: mask used with the "
|
||||
"non-tree table", fname, l);
|
||||
}
|
||||
|
||||
/* Create and add a table entry. */
|
||||
npf_table_add_entry(tl, fam.fam_family,
|
||||
&fam.fam_addr, fam.fam_mask);
|
||||
/*
|
||||
* Create and add a table entry.
|
||||
*/
|
||||
if (type == NPF_TABLE_CDB) {
|
||||
const npf_addr_t *addr = &fam.fam_addr;
|
||||
if (cdbw_put(cdbw, addr, alen, addr, alen) == -1) {
|
||||
err(EXIT_FAILURE, "cdbw_put");
|
||||
}
|
||||
} else {
|
||||
npf_table_add_entry(tl, fam.fam_family,
|
||||
&fam.fam_addr, fam.fam_mask);
|
||||
}
|
||||
}
|
||||
if (buf != NULL) {
|
||||
free(buf);
|
||||
}
|
||||
|
||||
if (type == NPF_TABLE_CDB) {
|
||||
struct stat sb;
|
||||
char sfn[32];
|
||||
void *cdb;
|
||||
int fd;
|
||||
|
||||
strlcpy(sfn, "/tmp/npfcdb.XXXXXX", sizeof(sfn));
|
||||
if ((fd = mkstemp(sfn)) == -1) {
|
||||
err(EXIT_FAILURE, "mkstemp");
|
||||
}
|
||||
unlink(sfn);
|
||||
|
||||
if (cdbw_output(cdbw, fd, "npf-table-cdb", NULL) == -1) {
|
||||
err(EXIT_FAILURE, "cdbw_output");
|
||||
}
|
||||
cdbw_close(cdbw);
|
||||
|
||||
if (fstat(fd, &sb) == -1) {
|
||||
err(EXIT_FAILURE, "fstat");
|
||||
}
|
||||
if ((cdb = mmap(NULL, sb.st_size, PROT_READ,
|
||||
MAP_FILE | MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
|
||||
err(EXIT_FAILURE, "mmap");
|
||||
}
|
||||
npf_table_setdata(tl, cdb, sb.st_size);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -689,6 +734,8 @@ npfctl_build_table(const char *tname, u_int type, const char *fname)
|
|||
|
||||
if (fname) {
|
||||
npfctl_fill_table(tl, type, fname);
|
||||
} else if (type == NPF_TABLE_CDB) {
|
||||
errx(EXIT_FAILURE, "tables of cdb type must be static");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: npf_parse.y,v 1.29 2013/11/19 00:28:41 rmind Exp $ */
|
||||
/* $NetBSD: npf_parse.y,v 1.30 2014/02/06 02:51:28 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
|
||||
|
@ -91,6 +91,7 @@ yyerror(const char *fmt, ...)
|
|||
%token ARROWLEFT
|
||||
%token ARROWRIGHT
|
||||
%token BLOCK
|
||||
%token CDB
|
||||
%token CURLY_CLOSE
|
||||
%token CURLY_OPEN
|
||||
%token CODE
|
||||
|
@ -278,6 +279,7 @@ table
|
|||
table_type
|
||||
: HASH { $$ = NPF_TABLE_HASH; }
|
||||
| TREE { $$ = NPF_TABLE_TREE; }
|
||||
| CDB { $$ = NPF_TABLE_CDB; }
|
||||
;
|
||||
|
||||
table_store
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: npf_scan.l,v 1.16 2013/11/19 00:28:41 rmind Exp $ */
|
||||
/* $NetBSD: npf_scan.l,v 1.17 2014/02/06 02:51:28 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
|
||||
|
@ -91,6 +91,7 @@ table return TABLE;
|
|||
type return TYPE;
|
||||
hash return HASH;
|
||||
tree return TREE;
|
||||
cdb return CDB;
|
||||
static return TSTATIC;
|
||||
dynamic return TDYNAMIC;
|
||||
file return TFILE;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: npf_table_test.c,v 1.7 2013/11/12 00:46:34 rmind Exp $ */
|
||||
/* $NetBSD: npf_table_test.c,v 1.8 2014/02/06 02:51:28 rmind Exp $ */
|
||||
|
||||
/*
|
||||
* NPF tableset test.
|
||||
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include "npf_impl.h"
|
||||
#include "npf_test.h"
|
||||
|
@ -43,6 +44,7 @@ static const uint16_t ip6_list[][8] = {
|
|||
|
||||
#define HASH_TID "hash-table"
|
||||
#define TREE_TID "tree-table"
|
||||
#define CDB_TID "cdb-table"
|
||||
|
||||
static bool
|
||||
npf_table_test_fill4(npf_tableset_t *tblset, npf_addr_t *addr)
|
||||
|
@ -74,21 +76,22 @@ npf_table_test_fill4(npf_tableset_t *tblset, npf_addr_t *addr)
|
|||
}
|
||||
|
||||
bool
|
||||
npf_table_test(bool verbose)
|
||||
npf_table_test(bool verbose, void *blob, size_t size)
|
||||
{
|
||||
npf_addr_t addr_storage, *addr = &addr_storage;
|
||||
const int nm = NPF_NO_NETMASK;
|
||||
npf_table_t *t, *t1, *t2, *t3;
|
||||
npf_tableset_t *tblset;
|
||||
npf_table_t *t, *t1, *t2;
|
||||
int error, alen;
|
||||
bool fail = false;
|
||||
void *cdb;
|
||||
u_int i;
|
||||
|
||||
tblset = npf_tableset_create(2);
|
||||
tblset = npf_tableset_create(3);
|
||||
fail |= !(tblset != NULL);
|
||||
|
||||
/* Table ID 1, using hash table with 256 lists. */
|
||||
t1 = npf_table_create(HASH_TID, 0, NPF_TABLE_HASH, 256);
|
||||
t1 = npf_table_create(HASH_TID, 0, NPF_TABLE_HASH, NULL, 256);
|
||||
fail |= !(t1 != NULL);
|
||||
error = npf_tableset_insert(tblset, t1);
|
||||
fail |= !(error == 0);
|
||||
|
@ -98,11 +101,20 @@ npf_table_test(bool verbose)
|
|||
fail |= !(error != 0);
|
||||
|
||||
/* Table ID 2, using a prefix tree. */
|
||||
t2 = npf_table_create(TREE_TID, 1, NPF_TABLE_TREE, 0);
|
||||
t2 = npf_table_create(TREE_TID, 1, NPF_TABLE_TREE, NULL, 0);
|
||||
fail |= !(t2 != NULL);
|
||||
error = npf_tableset_insert(tblset, t2);
|
||||
fail |= !(error == 0);
|
||||
|
||||
/* Table ID 3, using a CDB. */
|
||||
cdb = malloc(size, M_TEMP, M_WAITOK);
|
||||
memcpy(cdb, blob, size);
|
||||
|
||||
t3 = npf_table_create(CDB_TID, 2, NPF_TABLE_CDB, cdb, size);
|
||||
fail |= !(t3 != NULL);
|
||||
error = npf_tableset_insert(tblset, t3);
|
||||
fail |= !(error == 0);
|
||||
|
||||
/* Attempt to match non-existing entries - should fail. */
|
||||
addr->s6_addr32[0] = inet_addr(ip_list[0]);
|
||||
alen = sizeof(struct in_addr);
|
||||
|
@ -221,6 +233,19 @@ npf_table_test(bool verbose)
|
|||
fail |= !(error == 0);
|
||||
}
|
||||
|
||||
/* Test CDB. */
|
||||
addr->s6_addr32[0] = inet_addr(ip_list[0]);
|
||||
alen = sizeof(struct in_addr);
|
||||
error = npf_table_lookup(t3, alen, addr);
|
||||
fail |= !(error == 0);
|
||||
|
||||
for (i = 1; i < __arraycount(ip_list) - 1; i++) {
|
||||
addr->s6_addr32[0] = inet_addr(ip_list[i]);
|
||||
alen = sizeof(struct in_addr);
|
||||
error = npf_table_lookup(t3, alen, addr);
|
||||
fail |= !(error != 0);
|
||||
}
|
||||
|
||||
npf_tableset_destroy(tblset);
|
||||
|
||||
return !fail;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: npf_test.h,v 1.12 2014/02/05 03:49:48 rmind Exp $ */
|
||||
/* $NetBSD: npf_test.h,v 1.13 2014/02/06 02:51:28 rmind Exp $ */
|
||||
|
||||
/*
|
||||
* Public Domain.
|
||||
|
@ -57,7 +57,7 @@ void mbuf_icmp_append(struct mbuf *, struct mbuf *);
|
|||
|
||||
bool npf_nbuf_test(bool);
|
||||
bool npf_bpf_test(bool);
|
||||
bool npf_table_test(bool);
|
||||
bool npf_table_test(bool, void *, size_t);
|
||||
bool npf_state_test(bool);
|
||||
|
||||
bool npf_rule_test(bool);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: npftest.c,v 1.15 2014/02/05 03:49:48 rmind Exp $ */
|
||||
/* $NetBSD: npftest.c,v 1.16 2014/02/06 02:51:28 rmind Exp $ */
|
||||
|
||||
/*
|
||||
* NPF testing framework.
|
||||
|
@ -15,6 +15,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
|
@ -22,6 +23,8 @@
|
|||
#include <rump/rump.h>
|
||||
#include <rump/rump_syscalls.h>
|
||||
|
||||
#include <cdbw.h>
|
||||
|
||||
#include "npftest.h"
|
||||
|
||||
static bool verbose, quiet;
|
||||
|
@ -121,6 +124,51 @@ load_npf_config(const char *config)
|
|||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
generate_test_cdb(size_t *size)
|
||||
{
|
||||
in_addr_t addr;
|
||||
struct cdbw *cdbw;
|
||||
struct stat sb;
|
||||
char sfn[32];
|
||||
int alen, fd;
|
||||
void *cdb;
|
||||
|
||||
if ((cdbw = cdbw_open()) == NULL) {
|
||||
err(EXIT_FAILURE, "cdbw_open");
|
||||
}
|
||||
strlcpy(sfn, "/tmp/npftest_cdb.XXXXXX", sizeof(sfn));
|
||||
if ((fd = mkstemp(sfn)) == -1) {
|
||||
err(EXIT_FAILURE, "mkstemp");
|
||||
}
|
||||
unlink(sfn);
|
||||
|
||||
addr = inet_addr("192.168.1.1"), alen = sizeof(struct in_addr);
|
||||
if (cdbw_put(cdbw, &addr, alen, &addr, alen) == -1)
|
||||
err(EXIT_FAILURE, "cdbw_put");
|
||||
|
||||
addr = inet_addr("10.0.0.2"), alen = sizeof(struct in_addr);
|
||||
if (cdbw_put(cdbw, &addr, alen, &addr, alen) == -1)
|
||||
err(EXIT_FAILURE, "cdbw_put");
|
||||
|
||||
if (cdbw_output(cdbw, fd, "npf-table-cdb", NULL) == -1) {
|
||||
err(EXIT_FAILURE, "cdbw_output");
|
||||
}
|
||||
cdbw_close(cdbw);
|
||||
|
||||
if (fstat(fd, &sb) == -1) {
|
||||
err(EXIT_FAILURE, "fstat");
|
||||
}
|
||||
if ((cdb = mmap(NULL, sb.st_size, PROT_READ,
|
||||
MAP_FILE | MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
|
||||
err(EXIT_FAILURE, "mmap");
|
||||
}
|
||||
close(fd);
|
||||
|
||||
*size = sb.st_size;
|
||||
return cdb;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
@ -233,9 +281,14 @@ main(int argc, char **argv)
|
|||
}
|
||||
|
||||
if (!testname || strcmp("table", testname) == 0) {
|
||||
ok = rumpns_npf_table_test(verbose);
|
||||
void *cdb;
|
||||
size_t len;
|
||||
|
||||
cdb = generate_test_cdb(&len);
|
||||
ok = rumpns_npf_table_test(verbose, cdb, len);
|
||||
fail |= result("table", ok);
|
||||
tname_matched = true;
|
||||
munmap(cdb, len);
|
||||
}
|
||||
|
||||
if (!testname || strcmp("state", testname) == 0) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: npftest.h,v 1.11 2014/02/05 03:49:48 rmind Exp $ */
|
||||
/* $NetBSD: npftest.h,v 1.12 2014/02/06 02:51:28 rmind Exp $ */
|
||||
|
||||
/*
|
||||
* Public Domain.
|
||||
|
@ -23,7 +23,7 @@ void rumpns_npf_test_conc(bool, unsigned);
|
|||
|
||||
bool rumpns_npf_nbuf_test(bool);
|
||||
bool rumpns_npf_bpf_test(bool);
|
||||
bool rumpns_npf_table_test(bool);
|
||||
bool rumpns_npf_table_test(bool, void *, size_t);
|
||||
bool rumpns_npf_state_test(bool);
|
||||
|
||||
bool rumpns_npf_rule_test(bool);
|
||||
|
|
Loading…
Reference in New Issue