Module Name: src
Committed By: rmind
Date: Mon Oct 29 02:27:12 UTC 2012
Modified Files:
src/sys/net/npf: npf.c npf.h npf_ctl.c npf_impl.h npf_tableset.c
src/usr.sbin/npf/npfctl: npf_disassemble.c npfctl.c npfctl.h
src/usr.sbin/npf/npftest/libnpftest: npf_table_test.c
Log Message:
Implement NPF table listing and preservation of entries on reload.
Bump the version.
To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sys/net/npf/npf.c
cvs rdiff -u -r1.21 -r1.22 src/sys/net/npf/npf.h
cvs rdiff -u -r1.18 -r1.19 src/sys/net/npf/npf_ctl.c
cvs rdiff -u -r1.23 -r1.24 src/sys/net/npf/npf_impl.h
cvs rdiff -u -r1.14 -r1.15 src/sys/net/npf/npf_tableset.c
cvs rdiff -u -r1.9 -r1.10 src/usr.sbin/npf/npfctl/npf_disassemble.c
cvs rdiff -u -r1.20 -r1.21 src/usr.sbin/npf/npfctl/npfctl.c \
src/usr.sbin/npf/npfctl/npfctl.h
cvs rdiff -u -r1.5 -r1.6 src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/net/npf/npf.c
diff -u src/sys/net/npf/npf.c:1.13 src/sys/net/npf/npf.c:1.14
--- src/sys/net/npf/npf.c:1.13 Sun Sep 16 13:47:41 2012
+++ src/sys/net/npf/npf.c Mon Oct 29 02:27:11 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: npf.c,v 1.13 2012/09/16 13:47:41 rmind Exp $ */
+/* $NetBSD: npf.c,v 1.14 2012/10/29 02:27:11 rmind Exp $ */
/*-
* Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.13 2012/09/16 13:47:41 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.14 2012/10/29 02:27:11 rmind Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -305,7 +305,9 @@ npf_reload(prop_dictionary_t dict, npf_r
rw_enter(&npf_lock, RW_WRITER);
onc = atomic_swap_ptr(&npf_core, nc);
if (onc) {
- /* Reload only necessary NAT policies. */
+ /* Reload only the static tables. */
+ npf_tableset_reload(tset, onc->n_tables);
+ /* Reload only the necessary NAT policies. */
npf_ruleset_natreload(nset, onc->n_nat_rules);
}
/* Unlock. Everything goes "live" now. */
Index: src/sys/net/npf/npf.h
diff -u src/sys/net/npf/npf.h:1.21 src/sys/net/npf/npf.h:1.22
--- src/sys/net/npf/npf.h:1.21 Sun Sep 16 13:47:41 2012
+++ src/sys/net/npf/npf.h Mon Oct 29 02:27:11 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: npf.h,v 1.21 2012/09/16 13:47:41 rmind Exp $ */
+/* $NetBSD: npf.h,v 1.22 2012/10/29 02:27:11 rmind Exp $ */
/*-
* Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -45,7 +45,7 @@
#include <netinet/in_systm.h>
#include <netinet/in.h>
-#define NPF_VERSION 6
+#define NPF_VERSION 7
/*
* Public declarations and definitions.
@@ -211,15 +211,29 @@ bool npf_autounload_p(void);
* IOCTL structures.
*/
+#define NPF_IOCTL_TBLENT_LOOKUP 0
#define NPF_IOCTL_TBLENT_ADD 1
#define NPF_IOCTL_TBLENT_REM 2
+#define NPF_IOCTL_TBLENT_LIST 3
+
+typedef struct npf_ioctl_ent {
+ int alen;
+ npf_addr_t addr;
+ npf_netmask_t mask;
+} npf_ioctl_ent_t;
+
+typedef struct npf_ioctl_buf {
+ void * buf;
+ size_t len;
+} npf_ioctl_buf_t;
typedef struct npf_ioctl_table {
int nct_action;
u_int nct_tid;
- int nct_alen;
- npf_addr_t nct_addr;
- npf_netmask_t nct_mask;
+ union {
+ npf_ioctl_ent_t ent;
+ npf_ioctl_buf_t buf;
+ } nct_data;
} npf_ioctl_table_t;
typedef enum {
Index: src/sys/net/npf/npf_ctl.c
diff -u src/sys/net/npf/npf_ctl.c:1.18 src/sys/net/npf/npf_ctl.c:1.19
--- src/sys/net/npf/npf_ctl.c:1.18 Sun Sep 16 13:47:41 2012
+++ src/sys/net/npf/npf_ctl.c Mon Oct 29 02:27:12 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_ctl.c,v 1.18 2012/09/16 13:47:41 rmind Exp $ */
+/* $NetBSD: npf_ctl.c,v 1.19 2012/10/29 02:27:12 rmind Exp $ */
/*-
* Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.18 2012/09/16 13:47:41 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.19 2012/10/29 02:27:12 rmind Exp $");
#include <sys/param.h>
#include <sys/conf.h>
@@ -710,24 +710,33 @@ fail:
int
npfctl_table(void *data)
{
- npf_ioctl_table_t *nct = data;
+ const npf_ioctl_table_t *nct = data;
npf_tableset_t *tblset;
int error;
npf_core_enter(); /* XXXSMP */
tblset = npf_core_tableset();
switch (nct->nct_action) {
+ case NPF_IOCTL_TBLENT_LOOKUP:
+ error = npf_table_lookup(tblset, nct->nct_tid,
+ nct->nct_data.ent.alen, &nct->nct_data.ent.addr);
case NPF_IOCTL_TBLENT_ADD:
error = npf_table_insert(tblset, nct->nct_tid,
- nct->nct_alen, &nct->nct_addr, nct->nct_mask);
+ nct->nct_data.ent.alen, &nct->nct_data.ent.addr,
+ nct->nct_data.ent.mask);
break;
case NPF_IOCTL_TBLENT_REM:
error = npf_table_remove(tblset, nct->nct_tid,
- nct->nct_alen, &nct->nct_addr, nct->nct_mask);
+ nct->nct_data.ent.alen, &nct->nct_data.ent.addr,
+ nct->nct_data.ent.mask);
+ break;
+ case NPF_IOCTL_TBLENT_LIST:
+ error = npf_table_list(tblset, nct->nct_tid,
+ nct->nct_data.buf.buf, nct->nct_data.buf.len);
break;
default:
- error = npf_table_lookup(tblset, nct->nct_tid,
- nct->nct_alen, &nct->nct_addr);
+ error = EINVAL;
+ break;
}
npf_core_exit(); /* XXXSMP */
return error;
Index: src/sys/net/npf/npf_impl.h
diff -u src/sys/net/npf/npf_impl.h:1.23 src/sys/net/npf/npf_impl.h:1.24
--- src/sys/net/npf/npf_impl.h:1.23 Sun Sep 16 13:47:41 2012
+++ src/sys/net/npf/npf_impl.h Mon Oct 29 02:27:12 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_impl.h,v 1.23 2012/09/16 13:47:41 rmind Exp $ */
+/* $NetBSD: npf_impl.h,v 1.24 2012/10/29 02:27:12 rmind Exp $ */
/*-
* Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -81,11 +81,9 @@ typedef struct npf_natpolicy npf_natpoli
typedef struct npf_session npf_session_t;
struct npf_sehash;
-struct npf_tblent;
struct npf_table;
typedef struct npf_sehash npf_sehash_t;
-typedef struct npf_tblent npf_tblent_t;
typedef struct npf_table npf_table_t;
typedef npf_table_t * npf_tableset_t;
@@ -208,15 +206,11 @@ extern const pt_tree_ops_t npf_table_ptr
npf_tableset_t *npf_tableset_create(void);
void npf_tableset_destroy(npf_tableset_t *);
int npf_tableset_insert(npf_tableset_t *, npf_table_t *);
-npf_tableset_t *npf_tableset_reload(npf_tableset_t *);
+void npf_tableset_reload(npf_tableset_t *, npf_tableset_t *);
npf_table_t * npf_table_create(u_int, int, size_t);
void npf_table_destroy(npf_table_t *);
-void npf_table_ref(npf_table_t *);
-void npf_table_unref(npf_table_t *);
-npf_table_t * npf_table_get(npf_tableset_t *, u_int);
-void npf_table_put(npf_table_t *);
int npf_table_check(const npf_tableset_t *, u_int, int);
int npf_table_insert(npf_tableset_t *, u_int,
const int, const npf_addr_t *, const npf_netmask_t);
@@ -224,6 +218,7 @@ int npf_table_remove(npf_tableset_t *,
const int, const npf_addr_t *, const npf_netmask_t);
int npf_table_lookup(npf_tableset_t *, u_int,
const int, const npf_addr_t *);
+int npf_table_list(npf_tableset_t *, u_int, void *, size_t);
/* Ruleset interface. */
npf_ruleset_t * npf_ruleset_create(void);
Index: src/sys/net/npf/npf_tableset.c
diff -u src/sys/net/npf/npf_tableset.c:1.14 src/sys/net/npf/npf_tableset.c:1.15
--- src/sys/net/npf/npf_tableset.c:1.14 Sun Aug 12 03:35:14 2012
+++ src/sys/net/npf/npf_tableset.c Mon Oct 29 02:27:12 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_tableset.c,v 1.14 2012/08/12 03:35:14 rmind Exp $ */
+/* $NetBSD: npf_tableset.c,v 1.15 2012/10/29 02:27:12 rmind Exp $ */
/*-
* Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -32,13 +32,16 @@
/*
* NPF tableset module.
*
- * TODO:
- * - Dynamic hash growing/shrinking (i.e. re-hash functionality), maybe?
- * - Dynamic array resize.
+ * Notes
+ *
+ * The tableset is an array of tables. After the creation, the array
+ * is immutable. The caller is responsible to synchronise the access
+ * to the tableset. The table can either be a hash or a tree. Its
+ * entries are protected by a read-write lock.
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.14 2012/08/12 03:35:14 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.15 2012/10/29 02:27:12 rmind Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -58,14 +61,14 @@ __KERNEL_RCSID(0, "$NetBSD: npf_tableset
* Table structures.
*/
-struct npf_tblent {
+typedef struct npf_tblent {
union {
LIST_ENTRY(npf_tblent) hashq;
pt_node_t node;
} te_entry;
int te_alen;
npf_addr_t te_addr;
-};
+} npf_tblent_t;
LIST_HEAD(npf_hashl, npf_tblent);
@@ -74,12 +77,15 @@ struct npf_table {
/* Lock and reference count. */
krwlock_t t_lock;
u_int t_refcnt;
+ /* Total number of items. */
+ u_int t_nitems;
/* Table ID. */
u_int t_id;
/* The storage type can be: a) hash b) tree. */
int t_type;
struct npf_hashl * t_hashl;
u_long t_hashmask;
+ /* Separate trees for IPv4 and IPv6. */
pt_tree_t t_tree[2];
};
@@ -126,7 +132,7 @@ npf_tableset_destroy(npf_tableset_t *tbl
*/
for (tid = 0; tid < NPF_TABLE_SLOTS; tid++) {
t = tblset[tid];
- if (t != NULL) {
+ if (t && --t->t_refcnt == 0) {
npf_table_destroy(t);
}
}
@@ -148,6 +154,7 @@ npf_tableset_insert(npf_tableset_t *tbls
if (tblset[tid] == NULL) {
tblset[tid] = t;
+ t->t_refcnt++;
error = 0;
} else {
error = EEXIST;
@@ -156,6 +163,30 @@ npf_tableset_insert(npf_tableset_t *tbls
}
/*
+ * npf_tableset_reload: iterate all tables and if the new table is of the
+ * same type and has no items, then we preserve the old one and its entries.
+ *
+ * => The caller is responsible for providing synchronisation.
+ */
+void
+npf_tableset_reload(npf_tableset_t *ntset, npf_tableset_t *otset)
+{
+ for (int i = 0; i < NPF_TABLE_SLOTS; i++) {
+ npf_table_t *t = ntset[i], *ot = otset[i];
+
+ if (t == NULL || ot == NULL) {
+ continue;
+ }
+ if (t->t_nitems || t->t_type != ot->t_type) {
+ continue;
+ }
+ ntset[i] = ot;
+ ot->t_refcnt++;
+ npf_table_destroy(t);
+ }
+}
+
+/*
* Few helper routines.
*/
@@ -228,8 +259,8 @@ npf_table_create(u_int tid, int type, si
}
rw_init(&t->t_lock);
t->t_type = type;
- t->t_refcnt = 1;
t->t_id = tid;
+
return t;
}
@@ -241,7 +272,7 @@ npf_table_destroy(npf_table_t *t)
{
switch (t->t_type) {
- case NPF_TABLE_HASH: {
+ case NPF_TABLE_HASH:
for (unsigned n = 0; n <= t->t_hashmask; n++) {
npf_tblent_t *ent;
@@ -252,12 +283,10 @@ npf_table_destroy(npf_table_t *t)
}
hashdone(t->t_hashl, HASH_LIST, t->t_hashmask);
break;
- }
- case NPF_TABLE_TREE: {
+ case NPF_TABLE_TREE:
table_tree_destroy(&t->t_tree[0]);
table_tree_destroy(&t->t_tree[1]);
break;
- }
default:
KASSERT(false);
}
@@ -266,63 +295,6 @@ npf_table_destroy(npf_table_t *t)
}
/*
- * npf_table_ref: holds the reference on table.
- *
- * => Table must be locked.
- */
-void
-npf_table_ref(npf_table_t *t)
-{
-
- KASSERT(rw_lock_held(&t->t_lock));
- atomic_inc_uint(&t->t_refcnt);
-}
-
-/*
- * npf_table_unref: drop reference from the table and destroy the table if
- * it is the last reference.
- */
-void
-npf_table_unref(npf_table_t *t)
-{
-
- if (atomic_dec_uint_nv(&t->t_refcnt) != 0) {
- return;
- }
- npf_table_destroy(t);
-}
-
-/*
- * npf_table_get: find the table according to ID and "get it" by locking it.
- */
-npf_table_t *
-npf_table_get(npf_tableset_t *tset, u_int tid)
-{
- npf_table_t *t;
-
- KASSERT(tset != NULL);
-
- if ((u_int)tid >= NPF_TABLE_SLOTS) {
- return NULL;
- }
- t = tset[tid];
- if (t != NULL) {
- rw_enter(&t->t_lock, RW_READER);
- }
- return t;
-}
-
-/*
- * npf_table_put: "put table back" by unlocking it.
- */
-void
-npf_table_put(npf_table_t *t)
-{
-
- rw_exit(&t->t_lock);
-}
-
-/*
* npf_table_check: validate ID and type.
*/
int
@@ -342,7 +314,7 @@ npf_table_check(const npf_tableset_t *ts
}
static int
-npf_table_validate_cidr(const u_int aidx, const npf_addr_t *addr,
+table_cidr_check(const u_int aidx, const npf_addr_t *addr,
const npf_netmask_t mask)
{
@@ -375,7 +347,11 @@ npf_table_insert(npf_tableset_t *tset, u
npf_table_t *t;
int error;
- error = npf_table_validate_cidr(aidx, addr, mask);
+ if ((u_int)tid >= NPF_TABLE_SLOTS || (t = tset[tid]) == NULL) {
+ return EINVAL;
+ }
+
+ error = table_cidr_check(aidx, addr, mask);
if (error) {
return error;
}
@@ -383,16 +359,10 @@ npf_table_insert(npf_tableset_t *tset, u
memcpy(&ent->te_addr, addr, alen);
ent->te_alen = alen;
- /* Get the table (acquire the lock). */
- t = npf_table_get(tset, tid);
- if (t == NULL) {
- pool_cache_put(tblent_cache, ent);
- return EINVAL;
- }
-
/*
* Insert the entry. Return an error on duplicate.
*/
+ rw_enter(&t->t_lock, RW_WRITER);
switch (t->t_type) {
case NPF_TABLE_HASH: {
struct npf_hashl *htbl;
@@ -406,6 +376,7 @@ npf_table_insert(npf_tableset_t *tset, u
}
if (!table_hash_lookup(t, addr, alen, &htbl)) {
LIST_INSERT_HEAD(htbl, ent, te_entry.hashq);
+ t->t_nitems++;
} else {
error = EEXIST;
}
@@ -418,18 +389,21 @@ npf_table_insert(npf_tableset_t *tset, u
/*
* If no mask specified, use maximum mask.
*/
- if (mask != NPF_NO_NETMASK) {
- ok = ptree_insert_mask_node(tree, ent, mask);
+ ok = (mask != NPF_NO_NETMASK) ?
+ ptree_insert_mask_node(tree, ent, mask) :
+ ptree_insert_node(tree, ent);
+ if (ok) {
+ t->t_nitems++;
+ error = 0;
} else {
- ok = ptree_insert_node(tree, ent);
+ error = EEXIST;
}
- error = ok ? 0 : EEXIST;
break;
}
default:
KASSERT(false);
}
- npf_table_put(t);
+ rw_exit(&t->t_lock);
if (error) {
pool_cache_put(tblent_cache, ent);
@@ -449,15 +423,16 @@ npf_table_remove(npf_tableset_t *tset, u
npf_table_t *t;
int error;
- error = npf_table_validate_cidr(aidx, addr, mask);
+ error = table_cidr_check(aidx, addr, mask);
if (error) {
return error;
}
- t = npf_table_get(tset, tid);
- if (t == NULL) {
+
+ if ((u_int)tid >= NPF_TABLE_SLOTS || (t = tset[tid]) == NULL) {
return EINVAL;
}
+ rw_enter(&t->t_lock, RW_WRITER);
switch (t->t_type) {
case NPF_TABLE_HASH: {
struct npf_hashl *htbl;
@@ -465,6 +440,7 @@ npf_table_remove(npf_tableset_t *tset, u
ent = table_hash_lookup(t, addr, alen, &htbl);
if (__predict_true(ent != NULL)) {
LIST_REMOVE(ent, te_entry.hashq);
+ t->t_nitems--;
}
break;
}
@@ -474,6 +450,7 @@ npf_table_remove(npf_tableset_t *tset, u
ent = ptree_find_node(tree, addr);
if (__predict_true(ent != NULL)) {
ptree_remove_node(tree, ent);
+ t->t_nitems--;
}
break;
}
@@ -481,7 +458,7 @@ npf_table_remove(npf_tableset_t *tset, u
KASSERT(false);
ent = NULL;
}
- npf_table_put(t);
+ rw_exit(&t->t_lock);
if (ent == NULL) {
return ENOENT;
@@ -506,10 +483,11 @@ npf_table_lookup(npf_tableset_t *tset, u
return EINVAL;
}
- t = npf_table_get(tset, tid);
- if (__predict_false(t == NULL)) {
+ if ((u_int)tid >= NPF_TABLE_SLOTS || (t = tset[tid]) == NULL) {
return EINVAL;
}
+
+ rw_enter(&t->t_lock, RW_READER);
switch (t->t_type) {
case NPF_TABLE_HASH: {
struct npf_hashl *htbl;
@@ -524,7 +502,85 @@ npf_table_lookup(npf_tableset_t *tset, u
KASSERT(false);
ent = NULL;
}
- npf_table_put(t);
+ rw_exit(&t->t_lock);
return ent ? 0 : ENOENT;
}
+
+static int
+table_ent_copyout(npf_tblent_t *ent, npf_netmask_t mask,
+ void *ubuf, size_t len, size_t *off)
+{
+ void *ubufp = (uint8_t *)ubuf + *off;
+ npf_ioctl_ent_t uent;
+
+ 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.mask = mask;
+
+ return copyout(&uent, ubufp, sizeof(npf_ioctl_ent_t));
+}
+
+static int
+table_tree_list(pt_tree_t *tree, npf_netmask_t maxmask, void *ubuf,
+ size_t len, size_t *off)
+{
+ npf_tblent_t *ent = NULL;
+ int error = 0;
+
+ while ((ent = ptree_iterate(tree, ent, PT_ASCENDING)) != NULL) {
+ pt_bitlen_t blen;
+
+ if (!ptree_mask_node_p(tree, ent, &blen)) {
+ blen = maxmask;
+ }
+ error = table_ent_copyout(ent, blen, ubuf, len, off);
+ if (error)
+ break;
+ }
+ return error;
+}
+
+/*
+ * npf_table_list: copy a list of all table entries into a userspace buffer.
+ */
+int
+npf_table_list(npf_tableset_t *tset, u_int tid, void *ubuf, size_t len)
+{
+ npf_table_t *t;
+ size_t off = 0;
+ int error = 0;
+
+ if ((u_int)tid >= NPF_TABLE_SLOTS || (t = tset[tid]) == NULL) {
+ return EINVAL;
+ }
+
+ 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;
+ }
+ break;
+ case NPF_TABLE_TREE:
+ error = table_tree_list(&t->t_tree[0], 32, ubuf, len, &off);
+ if (error)
+ break;
+ error = table_tree_list(&t->t_tree[1], 128, ubuf, len, &off);
+ if (error)
+ break;
+ default:
+ KASSERT(false);
+ }
+ rw_exit(&t->t_lock);
+
+ return error;
+}
Index: src/usr.sbin/npf/npfctl/npf_disassemble.c
diff -u src/usr.sbin/npf/npfctl/npf_disassemble.c:1.9 src/usr.sbin/npf/npfctl/npf_disassemble.c:1.10
--- src/usr.sbin/npf/npfctl/npf_disassemble.c:1.9 Mon Aug 13 01:18:32 2012
+++ src/usr.sbin/npf/npfctl/npf_disassemble.c Mon Oct 29 02:27:12 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_disassemble.c,v 1.9 2012/08/13 01:18:32 rmind Exp $ */
+/* $NetBSD: npf_disassemble.c,v 1.10 2012/10/29 02:27:12 rmind Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
* FIXME: config generation should be redesigned..
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_disassemble.c,v 1.9 2012/08/13 01:18:32 rmind Exp $");
+__RCSID("$NetBSD: npf_disassemble.c,v 1.10 2012/10/29 02:27:12 rmind Exp $");
#include <stdio.h>
#include <stdlib.h>
@@ -664,31 +664,11 @@ npfctl_show_nat(nl_rule_t *nrl, unsigned
}
_npf_nat_getinfo(nt, &type, &flags, &taddr, &alen, &port);
- struct sockaddr_storage ss;
- char taddrbuf[64], tportbuf[16];
-
- if (alen == 4) {
- struct sockaddr_in *sin = (void *)&ss;
- sin->sin_len = sizeof(*sin);
- sin->sin_family = AF_INET;
- sin->sin_port = 0;
- memcpy(&sin->sin_addr, &taddr, sizeof(sin->sin_addr));
- sockaddr_snprintf(taddrbuf, sizeof(taddrbuf),
- "%a", (struct sockaddr *)sin);
- } else {
- assert(alen == 16);
- struct sockaddr_in6 *sin6 = (void *)&ss;
- sin6->sin6_len = sizeof(*sin6);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- memcpy(&sin6->sin6_addr, &taddr, sizeof(sin6->sin6_addr));
- sockaddr_snprintf(taddrbuf, sizeof(taddrbuf),
- "%a", (struct sockaddr *)sin6);
- }
+ char *taddrbuf, tportbuf[16];
+ taddrbuf = npfctl_print_addrmask(alen, &taddr, 0);
if (port) {
- snprintf(tportbuf, sizeof(tportbuf),
- " port %d", ntohs(port));
+ snprintf(tportbuf, sizeof(tportbuf), " port %d", ntohs(port));
}
const char *seg1 = "any", *seg2 = "any", *sp1 = "", *sp2 = "", *mt;
@@ -708,6 +688,7 @@ npfctl_show_nat(nl_rule_t *nrl, unsigned
}
printf("map %s dynamic %s%s %s %s%s pass ", ifname,
seg1, sp1, mt, seg2, sp2);
+ free(taddrbuf);
const void *nc;
size_t nclen;
Index: src/usr.sbin/npf/npfctl/npfctl.c
diff -u src/usr.sbin/npf/npfctl/npfctl.c:1.20 src/usr.sbin/npf/npfctl/npfctl.c:1.21
--- src/usr.sbin/npf/npfctl/npfctl.c:1.20 Sun Sep 16 13:47:41 2012
+++ src/usr.sbin/npf/npfctl/npfctl.c Mon Oct 29 02:27:12 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: npfctl.c,v 1.20 2012/09/16 13:47:41 rmind Exp $ */
+/* $NetBSD: npfctl.c,v 1.21 2012/10/29 02:27:12 rmind Exp $ */
/*-
* Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: npfctl.c,v 1.20 2012/09/16 13:47:41 rmind Exp $");
+__RCSID("$NetBSD: npfctl.c,v 1.21 2012/10/29 02:27:12 rmind Exp $");
#include <sys/ioctl.h>
#include <sys/stat.h>
@@ -44,6 +44,8 @@ __RCSID("$NetBSD: npfctl.c,v 1.20 2012/0
#include <unistd.h>
#include <errno.h>
+#include <util.h>
+
#include "npfctl.h"
extern int yylineno, yycolumn;
@@ -142,10 +144,10 @@ usage(void)
"\t%s ( sess-save | sess-load )\n",
progname);
fprintf(stderr,
- "\t%s table <tid> [ flush ]\n",
+ "\t%s table <tid> { add | rem | test } <address/mask>\n",
progname);
fprintf(stderr,
- "\t%s table <tid> { add | rem | test } <address/mask>\n",
+ "\t%s table <tid> { list | flush }\n",
progname);
exit(EXIT_FAILURE);
@@ -255,62 +257,136 @@ npfctl_print_error(const nl_error_t *ne)
}
}
+char *
+npfctl_print_addrmask(int alen, npf_addr_t *addr, npf_netmask_t mask)
+{
+ struct sockaddr_storage ss;
+ char *buf = zalloc(64);
+ int len;
+
+ switch (alen) {
+ case 4: {
+ struct sockaddr_in *sin = (void *)&ss;
+ sin->sin_len = sizeof(*sin);
+ sin->sin_family = AF_INET;
+ sin->sin_port = 0;
+ memcpy(&sin->sin_addr, addr, sizeof(sin->sin_addr));
+ break;
+ }
+ case 16: {
+ struct sockaddr_in6 *sin6 = (void *)&ss;
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = 0;
+ memcpy(&sin6->sin6_addr, addr, sizeof(sin6->sin6_addr));
+ break;
+ }
+ default:
+ assert(false);
+ }
+ len = sockaddr_snprintf(buf, 64, "%a", (struct sockaddr *)&ss);
+ if (mask) {
+ snprintf(&buf[len], 64 - len, "/%u", mask);
+ }
+ return buf;
+}
+
__dead static void
-npfctl_table(int fd, char **argv)
+npfctl_table(int fd, int argc, char **argv)
{
static const struct tblops_s {
const char * cmd;
int action;
} tblops[] = {
- { "add", NPF_IOCTL_TBLENT_ADD },
- { "rem", NPF_IOCTL_TBLENT_REM },
- { "test", 0 },
- { NULL, 0 }
+ { "add", NPF_IOCTL_TBLENT_ADD },
+ { "rem", NPF_IOCTL_TBLENT_REM },
+ { "test", NPF_IOCTL_TBLENT_LOOKUP },
+ { "list", NPF_IOCTL_TBLENT_LIST },
+ { NULL, 0 }
};
npf_ioctl_table_t nct;
fam_addr_mask_t fam;
- char *cmd = argv[3];
- char *arg = argv[3];
+ size_t buflen = 512;
+ char *cmd, *arg;
int n, alen;
+ /* Default action is list. */
memset(&nct, 0, sizeof(npf_ioctl_table_t));
- nct.nct_tid = atoi(argv[2]);
+ nct.nct_tid = atoi(argv[0]);
+ cmd = argv[1];
for (n = 0; tblops[n].cmd != NULL; n++) {
- if (strcmp(cmd, tblops[n].cmd) == 0) {
- nct.nct_action = tblops[n].action;
- arg = argv[4];
- break;
+ if (strcmp(cmd, tblops[n].cmd) != 0) {
+ continue;
+ }
+ nct.nct_action = tblops[n].action;
+ break;
+ }
+ if (tblops[n].cmd == NULL) {
+ errx(EXIT_FAILURE, "invalid command '%s'", cmd);
+ }
+ if (nct.nct_action != NPF_IOCTL_TBLENT_LIST) {
+ if (argc < 3) {
+ usage();
}
+ arg = argv[2];
}
- if (!npfctl_parse_cidr(arg, &fam, &alen)) {
- errx(EXIT_FAILURE, "invalid CIDR '%s'", arg);
+again:
+ if (nct.nct_action == NPF_IOCTL_TBLENT_LIST) {
+ nct.nct_data.buf.buf = zalloc(buflen);
+ nct.nct_data.buf.len = buflen;
+ } else {
+ if (!npfctl_parse_cidr(arg, &fam, &alen)) {
+ errx(EXIT_FAILURE, "invalid CIDR '%s'", arg);
+ }
+ nct.nct_data.ent.alen = alen;
+ memcpy(&nct.nct_data.ent.addr, &fam.fam_addr, sizeof(npf_addr_t));
+ nct.nct_data.ent.mask = fam.fam_mask;
}
- memcpy(&nct.nct_addr, &fam.fam_addr, sizeof(npf_addr_t));
- nct.nct_mask = fam.fam_mask;
- nct.nct_alen = alen;
if (ioctl(fd, IOC_NPF_TABLE, &nct) != -1) {
errno = 0;
}
switch (errno) {
- case EEXIST:
- warnx("entry already exists or is conflicting");
+ case 0:
break;
+ case EEXIST:
+ errx(EXIT_FAILURE, "entry already exists or is conflicting");
case ENOENT:
- warnx("no matching entry was not found");
- break;
+ errx(EXIT_FAILURE, "no matching entry was not found");
case EINVAL:
- warnx("invalid address, mask or table ID");
- break;
- case 0:
- printf("%s: %s\n", getprogname(), nct.nct_action == 0 ?
- "matching entry found" : "success");
- break;
+ errx(EXIT_FAILURE, "invalid address, mask or table ID");
+ case ENOMEM:
+ if (nct.nct_action == NPF_IOCTL_TBLENT_LIST) {
+ /* XXX */
+ free(nct.nct_data.buf.buf);
+ buflen <<= 1;
+ goto again;
+ }
+ /* FALLTHROUGH */
default:
- warn("error");
+ err(EXIT_FAILURE, "ioctl");
+ }
+
+ if (nct.nct_action == NPF_IOCTL_TBLENT_LIST) {
+ npf_ioctl_ent_t *ent = nct.nct_data.buf.buf;
+ char *buf;
+
+ while (nct.nct_data.buf.len--) {
+ if (!ent->alen)
+ break;
+ buf = npfctl_print_addrmask(ent->alen,
+ &ent->addr, ent->mask);
+ puts(buf);
+ ent++;
+ }
+ free(nct.nct_data.buf.buf);
+ } else {
+ printf("%s: %s\n", getprogname(),
+ nct.nct_action == NPF_IOCTL_TBLENT_LOOKUP ?
+ "matching entry found" : "success");
}
- exit(errno ? EXIT_FAILURE : EXIT_SUCCESS);
+ exit(EXIT_SUCCESS);
}
static void
@@ -355,10 +431,11 @@ npfctl(int action, int argc, char **argv
ret = npf_config_flush(fd);
break;
case NPFCTL_TABLE:
- if (argc < 5) {
+ if ((argc -= 2) < 2) {
usage();
}
- npfctl_table(fd, argv);
+ argv += 2;
+ npfctl_table(fd, argc, argv);
break;
case NPFCTL_STATS:
ret = npfctl_print_stats(fd);
Index: src/usr.sbin/npf/npfctl/npfctl.h
diff -u src/usr.sbin/npf/npfctl/npfctl.h:1.20 src/usr.sbin/npf/npfctl/npfctl.h:1.21
--- src/usr.sbin/npf/npfctl/npfctl.h:1.20 Sun Sep 16 13:47:41 2012
+++ src/usr.sbin/npf/npfctl/npfctl.h Mon Oct 29 02:27:12 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: npfctl.h,v 1.20 2012/09/16 13:47:41 rmind Exp $ */
+/* $NetBSD: npfctl.h,v 1.21 2012/10/29 02:27:12 rmind Exp $ */
/*-
* Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -96,6 +96,7 @@ char * xstrdup(const char *);
char * xstrndup(const char *, size_t);
void npfctl_print_error(const nl_error_t *);
+char * npfctl_print_addrmask(int, npf_addr_t *, npf_netmask_t);
bool npfctl_table_exists_p(const char *);
int npfctl_protono(const char *);
in_port_t npfctl_portno(const char *);
Index: src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c
diff -u src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c:1.5 src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c:1.6
--- src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c:1.5 Tue Aug 21 20:52:11 2012
+++ src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c Mon Oct 29 02:27:11 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_table_test.c,v 1.5 2012/08/21 20:52:11 rmind Exp $ */
+/* $NetBSD: npf_table_test.c,v 1.6 2012/10/29 02:27:11 rmind Exp $ */
/*
* NPF tableset test.
@@ -44,6 +44,32 @@ static const uint16_t ip6_list[][8] = {
#define HASH_TID 1
#define TREE_TID 2
+static bool
+npf_table_test_fill4(npf_tableset_t *tblset, npf_addr_t *addr)
+{
+ const int alen = sizeof(struct in_addr);
+ const int nm = NPF_NO_NETMASK;
+ bool fail = false;
+
+ /* Fill both tables with IP addresses. */
+ for (unsigned i = 0; i < __arraycount(ip_list); i++) {
+ int error;
+
+ addr->s6_addr32[0] = inet_addr(ip_list[i]);
+
+ error = npf_table_insert(tblset, HASH_TID, alen, addr, nm);
+ fail |= !(error == 0);
+ error = npf_table_insert(tblset, HASH_TID, alen, addr, nm);
+ fail |= !(error != 0);
+
+ error = npf_table_insert(tblset, TREE_TID, alen, addr, nm);
+ fail |= !(error == 0);
+ error = npf_table_insert(tblset, TREE_TID, alen, addr, nm);
+ fail |= !(error != 0);
+ }
+ return fail;
+}
+
bool
npf_table_test(bool verbose)
{
@@ -55,8 +81,6 @@ npf_table_test(bool verbose)
bool fail = false;
u_int i;
- npf_tableset_sysinit();
-
tblset = npf_tableset_create();
fail |= !(tblset != NULL);
@@ -87,19 +111,7 @@ npf_table_test(bool verbose)
fail |= !(error != 0);
/* Fill both tables with IP addresses. */
- for (i = 0; i < __arraycount(ip_list); i++) {
- addr->s6_addr32[0] = inet_addr(ip_list[i]);
-
- error = npf_table_insert(tblset, HASH_TID, alen, addr, nm);
- fail |= !(error == 0);
- error = npf_table_insert(tblset, HASH_TID, alen, addr, nm);
- fail |= !(error != 0);
-
- error = npf_table_insert(tblset, TREE_TID, alen, addr, nm);
- fail |= !(error == 0);
- error = npf_table_insert(tblset, TREE_TID, alen, addr, nm);
- fail |= !(error != 0);
- }
+ fail |= npf_table_test_fill4(tblset, addr);
/* Attempt to add duplicates - should fail. */
addr->s6_addr32[0] = inet_addr(ip_list[0]);
@@ -111,15 +123,6 @@ npf_table_test(bool verbose)
error = npf_table_insert(tblset, TREE_TID, alen, addr, nm);
fail |= !(error != 0);
- /* Reference checks. */
- t1 = npf_table_get(tblset, HASH_TID);
- fail |= !(t1 != NULL);
- npf_table_put(t1);
-
- t2 = npf_table_get(tblset, TREE_TID);
- fail |= !(t2 != NULL);
- npf_table_put(t2);
-
/* Match (validate) each IP entry. */
for (i = 0; i < __arraycount(ip_list); i++) {
addr->s6_addr32[0] = inet_addr(ip_list[i]);
@@ -206,7 +209,6 @@ npf_table_test(bool verbose)
}
npf_tableset_destroy(tblset);
- npf_tableset_sysfini();
return !fail;
}