diff --git a/lib/libnpf/npf.c b/lib/libnpf/npf.c index 4e32b211360d..71223e3ea352 100644 --- a/lib/libnpf/npf.c +++ b/lib/libnpf/npf.c @@ -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 -__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 #include @@ -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) { diff --git a/lib/libnpf/npf.h b/lib/libnpf/npf.h index 2db566e212be..6ad1e9e05cf8 100644 --- a/lib/libnpf/npf.h +++ b/lib/libnpf/npf.h @@ -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 *); diff --git a/sys/net/npf/npf.h b/sys/net/npf/npf.h index e8e5e1d69b8f..a369b5ab5c93 100644 --- a/sys/net/npf/npf.h +++ b/sys/net/npf/npf.h @@ -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 diff --git a/sys/net/npf/npf_ctl.c b/sys/net/npf/npf_ctl.c index 2534586d2023..e9a8c07f7f36 100644 --- a/sys/net/npf/npf_ctl.c +++ b/sys/net/npf/npf_ctl.c @@ -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 -__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 #include @@ -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); /* diff --git a/sys/net/npf/npf_impl.h b/sys/net/npf/npf_impl.h index e5963f25997e..a3a65e70db7d 100644 --- a/sys/net/npf/npf_impl.h +++ b/sys/net/npf/npf_impl.h @@ -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); diff --git a/sys/net/npf/npf_tableset.c b/sys/net/npf/npf_tableset.c index e391ec808fe4..d66a8a5fa5f6 100644 --- a/sys/net/npf/npf_tableset.c +++ b/sys/net/npf/npf_tableset.c @@ -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 -__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 #include #include #include +#include #include +#include #include #include #include @@ -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; } diff --git a/usr.sbin/npf/npfctl/npf.conf.5 b/usr.sbin/npf/npfctl/npf.conf.5 index e88a26fa7324..5b345c04a12b 100644 --- a/usr.sbin/npf/npfctl/npf.conf.5 +++ b/usr.sbin/npf/npfctl/npf.conf.5 @@ -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 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. diff --git a/usr.sbin/npf/npfctl/npf_build.c b/usr.sbin/npf/npfctl/npf_build.c index d93e83bc1920..0235ea9a8a43 100644 --- a/usr.sbin/npf/npfctl/npf_build.c +++ b/usr.sbin/npf/npfctl/npf_build.c @@ -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 -__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 -#include +#include +#include #include #include #include #include +#include #include #include #include +#include #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"); } } diff --git a/usr.sbin/npf/npfctl/npf_parse.y b/usr.sbin/npf/npfctl/npf_parse.y index ccc7eae07b7f..1371733aa461 100644 --- a/usr.sbin/npf/npfctl/npf_parse.y +++ b/usr.sbin/npf/npfctl/npf_parse.y @@ -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 diff --git a/usr.sbin/npf/npfctl/npf_scan.l b/usr.sbin/npf/npfctl/npf_scan.l index c36c3874b153..b6790457d9de 100644 --- a/usr.sbin/npf/npfctl/npf_scan.l +++ b/usr.sbin/npf/npfctl/npf_scan.l @@ -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; diff --git a/usr.sbin/npf/npftest/libnpftest/npf_table_test.c b/usr.sbin/npf/npftest/libnpftest/npf_table_test.c index e0b89ffc1de6..b262f88e1109 100644 --- a/usr.sbin/npf/npftest/libnpftest/npf_table_test.c +++ b/usr.sbin/npf/npftest/libnpftest/npf_table_test.c @@ -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 +#include #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; diff --git a/usr.sbin/npf/npftest/libnpftest/npf_test.h b/usr.sbin/npf/npftest/libnpftest/npf_test.h index e09ad620b1f0..dd5b188682d6 100644 --- a/usr.sbin/npf/npftest/libnpftest/npf_test.h +++ b/usr.sbin/npf/npftest/libnpftest/npf_test.h @@ -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); diff --git a/usr.sbin/npf/npftest/npftest.c b/usr.sbin/npf/npftest/npftest.c index dff42a03afb2..fab2727a12f8 100644 --- a/usr.sbin/npf/npftest/npftest.c +++ b/usr.sbin/npf/npftest/npftest.c @@ -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 #include +#include #include #include #include @@ -22,6 +23,8 @@ #include #include +#include + #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) { diff --git a/usr.sbin/npf/npftest/npftest.h b/usr.sbin/npf/npftest/npftest.h index 52ecc425ea96..1315b485ff67 100644 --- a/usr.sbin/npf/npftest/npftest.h +++ b/usr.sbin/npf/npftest/npftest.h @@ -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);