Add support for CDB based NPF tables.

This commit is contained in:
rmind 2014-02-06 02:51:28 +00:00
parent 17a304eec5
commit ffcdc4af8d
14 changed files with 370 additions and 118 deletions

View File

@ -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)
{

View File

@ -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 *);

View File

@ -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

View File

@ -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);
/*

View File

@ -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);

View File

@ -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;
}

View File

@ -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.

View File

@ -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");
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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);