NPF: rework of the connection saving and restoring:
- Add support for saving a snapshot of the current connections together with a full configuration. Support a reverse load operation. Eliminate the old 'sess-save' and 'sess-load' in favour of the new mechanism. - Share code between load and reload operations: the latter performs load from npf.conf without affecting the connections. - Simplify and fix races with connection loading. - Bump NPF_VERSION.
This commit is contained in:
parent
4af1928aa9
commit
a02b7176fb
105
lib/libnpf/npf.c
105
lib/libnpf/npf.c
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf.c,v 1.29 2014/05/19 18:47:19 jakllsch Exp $ */
|
||||
/* $NetBSD: npf.c,v 1.30 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2010-2014 The NetBSD Foundation, Inc.
|
||||
@ -30,7 +30,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.29 2014/05/19 18:47:19 jakllsch Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.30 2014/07/23 01:25:34 rmind Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in_systm.h>
|
||||
@ -167,7 +167,7 @@ npf_config_submit(nl_config_t *ncf, int fd)
|
||||
}
|
||||
if (fd) {
|
||||
error = prop_dictionary_sendrecv_ioctl(npf_dict, fd,
|
||||
IOC_NPF_RELOAD, &ncf->ncf_err);
|
||||
IOC_NPF_LOAD, &ncf->ncf_err);
|
||||
if (error) {
|
||||
prop_object_release(npf_dict);
|
||||
assert(ncf->ncf_err == NULL);
|
||||
@ -179,20 +179,13 @@ npf_config_submit(nl_config_t *ncf, int fd)
|
||||
return error;
|
||||
}
|
||||
|
||||
nl_config_t *
|
||||
npf_config_retrieve(int fd, bool *active, bool *loaded)
|
||||
static nl_config_t *
|
||||
_npf_config_consdict(prop_dictionary_t npf_dict)
|
||||
{
|
||||
prop_dictionary_t npf_dict;
|
||||
nl_config_t *ncf;
|
||||
int error;
|
||||
|
||||
error = prop_dictionary_recv_ioctl(fd, IOC_NPF_GETCONF, &npf_dict);
|
||||
if (error) {
|
||||
return NULL;
|
||||
}
|
||||
ncf = calloc(1, sizeof(*ncf));
|
||||
if (ncf == NULL) {
|
||||
prop_object_release(npf_dict);
|
||||
return NULL;
|
||||
}
|
||||
ncf->ncf_dict = npf_dict;
|
||||
@ -201,12 +194,60 @@ npf_config_retrieve(int fd, bool *active, bool *loaded)
|
||||
ncf->ncf_rproc_list = prop_dictionary_get(npf_dict, "rprocs");
|
||||
ncf->ncf_table_list = prop_dictionary_get(npf_dict, "tables");
|
||||
ncf->ncf_nat_list = prop_dictionary_get(npf_dict, "translation");
|
||||
return ncf;
|
||||
}
|
||||
|
||||
nl_config_t *
|
||||
npf_config_retrieve(int fd, bool *active, bool *loaded)
|
||||
{
|
||||
prop_dictionary_t npf_dict;
|
||||
nl_config_t *ncf;
|
||||
int error;
|
||||
|
||||
error = prop_dictionary_recv_ioctl(fd, IOC_NPF_SAVE, &npf_dict);
|
||||
if (error) {
|
||||
return NULL;
|
||||
}
|
||||
ncf = _npf_config_consdict(npf_dict);
|
||||
if (ncf == NULL) {
|
||||
prop_object_release(npf_dict);
|
||||
return NULL;
|
||||
}
|
||||
prop_dictionary_get_bool(npf_dict, "active", active);
|
||||
*loaded = (ncf->ncf_rules_list != NULL);
|
||||
return ncf;
|
||||
}
|
||||
|
||||
int
|
||||
npf_config_export(const nl_config_t *ncf, const char *path)
|
||||
{
|
||||
prop_dictionary_t npf_dict = ncf->ncf_dict;
|
||||
int error = 0;
|
||||
|
||||
if (!prop_dictionary_externalize_to_file(npf_dict, path)) {
|
||||
error = errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
nl_config_t *
|
||||
npf_config_import(const char *path)
|
||||
{
|
||||
prop_dictionary_t npf_dict;
|
||||
nl_config_t *ncf;
|
||||
|
||||
npf_dict = prop_dictionary_internalize_from_file(path);
|
||||
if (npf_dict) {
|
||||
return NULL;
|
||||
}
|
||||
ncf = _npf_config_consdict(npf_dict);
|
||||
if (ncf == NULL) {
|
||||
prop_object_release(npf_dict);
|
||||
return NULL;
|
||||
}
|
||||
return ncf;
|
||||
}
|
||||
|
||||
int
|
||||
npf_config_flush(int fd)
|
||||
{
|
||||
@ -1136,46 +1177,6 @@ _npf_alg_unload(nl_config_t *ncf, const char *name)
|
||||
* MISC.
|
||||
*/
|
||||
|
||||
int
|
||||
npf_sessions_recv(int fd, const char *fpath)
|
||||
{
|
||||
prop_dictionary_t sdict;
|
||||
int error;
|
||||
|
||||
error = prop_dictionary_recv_ioctl(fd, IOC_NPF_SESSIONS_SAVE, &sdict);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (!prop_dictionary_externalize_to_file(sdict, fpath)) {
|
||||
error = errno;
|
||||
}
|
||||
prop_object_release(sdict);
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
npf_sessions_send(int fd, const char *fpath)
|
||||
{
|
||||
prop_dictionary_t sdict;
|
||||
int error;
|
||||
|
||||
if (fpath) {
|
||||
sdict = prop_dictionary_internalize_from_file(fpath);
|
||||
if (sdict == NULL) {
|
||||
return errno;
|
||||
}
|
||||
} else {
|
||||
/* Empty: will flush the sessions. */
|
||||
prop_array_t selist = prop_array_create();
|
||||
sdict = prop_dictionary_create();
|
||||
prop_dictionary_set(sdict, "session-list", selist);
|
||||
prop_object_release(selist);
|
||||
}
|
||||
error = prop_dictionary_send_ioctl(sdict, fd, IOC_NPF_SESSIONS_LOAD);
|
||||
prop_object_release(sdict);
|
||||
return error;
|
||||
}
|
||||
|
||||
static prop_dictionary_t
|
||||
_npf_debug_initonce(nl_config_t *ncf)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf.h,v 1.26 2014/05/19 18:47:19 jakllsch Exp $ */
|
||||
/* $NetBSD: npf.h,v 1.27 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2011-2014 The NetBSD Foundation, Inc.
|
||||
@ -74,9 +74,12 @@ typedef void (*nl_table_callback_t)(unsigned, int);
|
||||
#define NPF_MAX_TABLE_ID (16)
|
||||
|
||||
nl_config_t * npf_config_create(void);
|
||||
int npf_config_submit(nl_config_t *, int);
|
||||
void npf_config_destroy(nl_config_t *);
|
||||
|
||||
int npf_config_submit(nl_config_t *, int);
|
||||
nl_config_t * npf_config_retrieve(int, bool *, bool *);
|
||||
nl_config_t * npf_config_import(const char *);
|
||||
int npf_config_export(const nl_config_t *, const char *);
|
||||
int npf_config_flush(int);
|
||||
|
||||
int npf_ruleset_add(int, const char *, nl_rule_t *, uint64_t *);
|
||||
@ -120,9 +123,6 @@ void npf_table_destroy(nl_table_t *);
|
||||
|
||||
#include <ifaddrs.h>
|
||||
|
||||
int npf_sessions_send(int, const char *);
|
||||
int npf_sessions_recv(int, const char *);
|
||||
|
||||
nl_rule_t * npf_rule_iterate(nl_config_t *, unsigned *);
|
||||
const char * npf_rule_getname(nl_rule_t *);
|
||||
uint32_t npf_rule_getattr(nl_rule_t *);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf.c,v 1.20 2014/07/19 18:24:16 rmind Exp $ */
|
||||
/* $NetBSD: npf.c,v 1.21 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
|
||||
@ -34,7 +34,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.20 2014/07/19 18:24:16 rmind Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.21 2014/07/23 01:25:34 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
@ -129,9 +129,6 @@ npf_fini(void)
|
||||
devsw_detach(NULL, &npf_cdevsw);
|
||||
#endif
|
||||
npf_pfil_unregister(true);
|
||||
|
||||
/* Flush all connections, destroy configuration (ruleset, etc). */
|
||||
npf_conn_tracking(false);
|
||||
npf_config_fini();
|
||||
|
||||
/* Finally, safe to destroy the subsystems. */
|
||||
@ -220,23 +217,17 @@ npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
|
||||
case IOC_NPF_RULE:
|
||||
error = npfctl_rule(cmd, data);
|
||||
break;
|
||||
case IOC_NPF_GETCONF:
|
||||
error = npfctl_getconf(cmd, data);
|
||||
break;
|
||||
case IOC_NPF_STATS:
|
||||
error = npfctl_stats(data);
|
||||
break;
|
||||
case IOC_NPF_SESSIONS_SAVE:
|
||||
error = npfctl_conn_save(cmd, data);
|
||||
break;
|
||||
case IOC_NPF_SESSIONS_LOAD:
|
||||
error = npfctl_conn_load(cmd, data);
|
||||
case IOC_NPF_SAVE:
|
||||
error = npfctl_save(cmd, data);
|
||||
break;
|
||||
case IOC_NPF_SWITCH:
|
||||
error = npfctl_switch(data);
|
||||
break;
|
||||
case IOC_NPF_RELOAD:
|
||||
error = npfctl_reload(cmd, data);
|
||||
case IOC_NPF_LOAD:
|
||||
error = npfctl_load(cmd, data);
|
||||
break;
|
||||
case IOC_NPF_VERSION:
|
||||
*(int *)data = NPF_VERSION;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf.h,v 1.44 2014/07/20 00:37:41 rmind Exp $ */
|
||||
/* $NetBSD: npf.h,v 1.45 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
|
||||
@ -45,7 +45,7 @@
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define NPF_VERSION 15
|
||||
#define NPF_VERSION 16
|
||||
|
||||
/*
|
||||
* Public declarations and definitions.
|
||||
@ -308,13 +308,11 @@ typedef struct npf_ioctl_table {
|
||||
|
||||
#define IOC_NPF_VERSION _IOR('N', 100, int)
|
||||
#define IOC_NPF_SWITCH _IOW('N', 101, int)
|
||||
#define IOC_NPF_RELOAD _IOWR('N', 102, struct plistref)
|
||||
#define IOC_NPF_LOAD _IOWR('N', 102, struct plistref)
|
||||
#define IOC_NPF_TABLE _IOW('N', 103, struct npf_ioctl_table)
|
||||
#define IOC_NPF_STATS _IOW('N', 104, void *)
|
||||
#define IOC_NPF_SESSIONS_SAVE _IOR('N', 105, struct plistref)
|
||||
#define IOC_NPF_SESSIONS_LOAD _IOW('N', 106, struct plistref)
|
||||
#define IOC_NPF_SAVE _IOR('N', 105, struct plistref)
|
||||
#define IOC_NPF_RULE _IOWR('N', 107, struct plistref)
|
||||
#define IOC_NPF_GETCONF _IOR('N', 108, struct plistref)
|
||||
|
||||
/*
|
||||
* Statistics counters.
|
||||
@ -324,13 +322,13 @@ typedef enum {
|
||||
/* Packets passed. */
|
||||
NPF_STAT_PASS_DEFAULT,
|
||||
NPF_STAT_PASS_RULESET,
|
||||
NPF_STAT_PASS_SESSION,
|
||||
NPF_STAT_PASS_CONN,
|
||||
/* Packets blocked. */
|
||||
NPF_STAT_BLOCK_DEFAULT,
|
||||
NPF_STAT_BLOCK_RULESET,
|
||||
/* Connection and NAT entries. */
|
||||
NPF_STAT_SESSION_CREATE,
|
||||
NPF_STAT_SESSION_DESTROY,
|
||||
NPF_STAT_CONN_CREATE,
|
||||
NPF_STAT_CONN_DESTROY,
|
||||
NPF_STAT_NAT_CREATE,
|
||||
NPF_STAT_NAT_DESTROY,
|
||||
/* Invalid state cases. */
|
||||
@ -339,7 +337,7 @@ typedef enum {
|
||||
NPF_STAT_INVALID_STATE_TCP2,
|
||||
NPF_STAT_INVALID_STATE_TCP3,
|
||||
/* Raced packets. */
|
||||
NPF_STAT_RACE_SESSION,
|
||||
NPF_STAT_RACE_CONN,
|
||||
NPF_STAT_RACE_NAT,
|
||||
/* Fragments. */
|
||||
NPF_STAT_FRAGMENTS,
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_conf.c,v 1.6 2014/05/30 23:26:06 rmind Exp $ */
|
||||
/* $NetBSD: npf_conf.c,v 1.7 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2013 The NetBSD Foundation, Inc.
|
||||
@ -48,7 +48,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_conf.c,v 1.6 2014/05/30 23:26:06 rmind Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_conf.c,v 1.7 2014/07/23 01:25:34 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
@ -59,6 +59,7 @@ __KERNEL_RCSID(0, "$NetBSD: npf_conf.c,v 1.6 2014/05/30 23:26:06 rmind Exp $");
|
||||
#include <sys/mutex.h>
|
||||
|
||||
#include "npf_impl.h"
|
||||
#include "npf_conn.h"
|
||||
|
||||
typedef struct {
|
||||
npf_ruleset_t * n_rules;
|
||||
@ -90,7 +91,7 @@ npf_config_init(void)
|
||||
rpset = npf_rprocset_create();
|
||||
rlset = npf_ruleset_create(0);
|
||||
nset = npf_ruleset_create(0);
|
||||
npf_config_reload(dict, rlset, tset, nset, rpset, true);
|
||||
npf_config_load(dict, rlset, tset, nset, rpset, NULL, true);
|
||||
KASSERT(npf_config != NULL);
|
||||
}
|
||||
|
||||
@ -108,8 +109,11 @@ npf_config_destroy(npf_config_t *nc)
|
||||
void
|
||||
npf_config_fini(void)
|
||||
{
|
||||
/* Flush the connections. */
|
||||
mutex_enter(&npf_config_lock);
|
||||
npf_conn_tracking(false);
|
||||
pserialize_perform(npf_config_psz);
|
||||
npf_conn_load(NULL, false);
|
||||
npf_ifmap_flush();
|
||||
mutex_exit(&npf_config_lock);
|
||||
|
||||
@ -119,13 +123,13 @@ npf_config_fini(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_config_reload: the main routine performing configuration reload.
|
||||
* npf_config_load: the main routine performing configuration load.
|
||||
* Performs the necessary synchronisation and destroys the old config.
|
||||
*/
|
||||
void
|
||||
npf_config_reload(prop_dictionary_t dict, npf_ruleset_t *rset,
|
||||
npf_config_load(prop_dictionary_t dict, npf_ruleset_t *rset,
|
||||
npf_tableset_t *tset, npf_ruleset_t *nset, npf_rprocset_t *rpset,
|
||||
bool flush)
|
||||
npf_conndb_t *conns, bool flush)
|
||||
{
|
||||
npf_config_t *nc, *onc;
|
||||
|
||||
@ -157,16 +161,31 @@ npf_config_reload(prop_dictionary_t dict, npf_ruleset_t *rset,
|
||||
if (onc == NULL) {
|
||||
/* Initial load, done. */
|
||||
npf_ifmap_flush();
|
||||
npf_conn_load(conns, !flush);
|
||||
mutex_exit(&npf_config_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are going to flush the connections or load the new ones,
|
||||
* then disable the connection tracking for the grace period.
|
||||
*/
|
||||
if (flush || conns) {
|
||||
npf_conn_tracking(false);
|
||||
}
|
||||
|
||||
/* Synchronise: drain all references. */
|
||||
pserialize_perform(npf_config_psz);
|
||||
if (flush) {
|
||||
npf_ifmap_flush();
|
||||
}
|
||||
|
||||
/*
|
||||
* G/C the existing connections and, if passed, load the new ones.
|
||||
* If not flushing - enable the connection tracking.
|
||||
*/
|
||||
npf_conn_load(conns, !flush);
|
||||
|
||||
/* Sync the config proplib data. */
|
||||
npf_tableset_syncdict(tset, dict);
|
||||
mutex_exit(&npf_config_lock);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_conn.c,v 1.5 2014/07/20 14:16:00 joerg Exp $ */
|
||||
/* $NetBSD: npf_conn.c,v 1.6 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2014 Mindaugas Rasiukevicius <rmind at netbsd org>
|
||||
@ -93,14 +93,13 @@
|
||||
*
|
||||
* Lock order
|
||||
*
|
||||
* conn_lock ->
|
||||
* [ npf_config_lock -> ]
|
||||
* npf_hashbucket_t::cd_lock ->
|
||||
* npf_conn_t::c_lock
|
||||
* npf_config_lock ->
|
||||
* conn_lock ->
|
||||
* npf_conn_t::c_lock
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_conn.c,v 1.5 2014/07/20 14:16:00 joerg Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_conn.c,v 1.6 2014/07/23 01:25:34 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
@ -132,25 +131,22 @@ CTASSERT(PFIL_ALL == (0x001 | 0x002));
|
||||
#define CONN_REMOVED 0x020 /* "forw/back" entries removed */
|
||||
|
||||
/*
|
||||
* Connection tracking state: disabled (off), enabled (on) or flush request.
|
||||
* Connection tracking state: disabled (off) or enabled (on).
|
||||
*/
|
||||
enum { CONN_TRACKING_OFF, CONN_TRACKING_ON, CONN_TRACKING_FLUSH };
|
||||
enum { CONN_TRACKING_OFF, CONN_TRACKING_ON };
|
||||
static volatile int conn_tracking __cacheline_aligned;
|
||||
|
||||
/* Connection tracking database, connection cache and the lock. */
|
||||
static npf_conndb_t * conn_db __read_mostly;
|
||||
static pool_cache_t conn_cache __read_mostly;
|
||||
static kmutex_t conn_lock __cacheline_aligned;
|
||||
static kcondvar_t conn_cv __cacheline_aligned;
|
||||
|
||||
static void npf_conn_gc(npf_conndb_t *, bool, bool);
|
||||
static void npf_conn_worker(void);
|
||||
static void npf_conn_destroy(npf_conn_t *);
|
||||
|
||||
/*
|
||||
* npf_conn_sys{init,fini}: initialise/destroy connection tracking.
|
||||
*
|
||||
* Connection database is initialised when connection tracking gets
|
||||
* enabled via npf_conn_tracking() interface.
|
||||
*/
|
||||
|
||||
void
|
||||
@ -159,9 +155,8 @@ npf_conn_sysinit(void)
|
||||
conn_cache = pool_cache_init(sizeof(npf_conn_t), coherency_unit,
|
||||
0, 0, "npfconpl", NULL, IPL_NET, NULL, NULL, NULL);
|
||||
mutex_init(&conn_lock, MUTEX_DEFAULT, IPL_NONE);
|
||||
cv_init(&conn_cv, "npfconcv");
|
||||
conn_tracking = CONN_TRACKING_OFF;
|
||||
conn_db = NULL;
|
||||
conn_db = npf_conndb_create();
|
||||
|
||||
npf_worker_register(npf_conn_worker);
|
||||
}
|
||||
@ -169,58 +164,54 @@ npf_conn_sysinit(void)
|
||||
void
|
||||
npf_conn_sysfini(void)
|
||||
{
|
||||
/* Disable tracking, flush all connections. */
|
||||
npf_conn_tracking(false);
|
||||
/* Note: the caller should have flushed the connections. */
|
||||
KASSERT(conn_tracking == CONN_TRACKING_OFF);
|
||||
npf_worker_unregister(npf_conn_worker);
|
||||
|
||||
KASSERT(conn_tracking == CONN_TRACKING_OFF);
|
||||
KASSERT(conn_db == NULL);
|
||||
npf_conndb_destroy(conn_db);
|
||||
pool_cache_destroy(conn_cache);
|
||||
mutex_destroy(&conn_lock);
|
||||
cv_destroy(&conn_cv);
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_conn_reload: perform the reload by flushing the current connection
|
||||
* database and replacing with the new one or just destroying.
|
||||
* npf_conn_load: perform the load by flushing the current connection
|
||||
* database and replacing it with the new one or just destroying.
|
||||
*
|
||||
* Key routine synchronising with all other readers and writers.
|
||||
* => The caller must disable the connection tracking and ensure that
|
||||
* there are no connection database lookups or references in-flight.
|
||||
*/
|
||||
static void
|
||||
npf_conn_reload(npf_conndb_t *ndb, int tracking)
|
||||
void
|
||||
npf_conn_load(npf_conndb_t *ndb, bool track)
|
||||
{
|
||||
npf_conndb_t *odb;
|
||||
npf_conndb_t *odb = NULL;
|
||||
|
||||
/* Must synchronise with G/C thread and connection saving/restoring. */
|
||||
mutex_enter(&conn_lock);
|
||||
while (conn_tracking == CONN_TRACKING_FLUSH) {
|
||||
cv_wait(&conn_cv, &conn_lock);
|
||||
}
|
||||
KASSERT(npf_config_locked_p());
|
||||
|
||||
/*
|
||||
* Set the flush status. It disables connection inspection as well
|
||||
* as creation. There may be some operations in-flight, drain them.
|
||||
* The connection database is in the quiescent state.
|
||||
* Prevent G/C thread from running and install a new database.
|
||||
*/
|
||||
npf_config_enter();
|
||||
conn_tracking = CONN_TRACKING_FLUSH;
|
||||
npf_config_sync();
|
||||
npf_config_exit();
|
||||
|
||||
/* Notify the worker to G/C all connections. */
|
||||
npf_worker_signal();
|
||||
while (conn_tracking == CONN_TRACKING_FLUSH) {
|
||||
cv_wait(&conn_cv, &conn_lock);
|
||||
mutex_enter(&conn_lock);
|
||||
if (ndb) {
|
||||
KASSERT(conn_tracking == CONN_TRACKING_OFF);
|
||||
odb = conn_db;
|
||||
conn_db = ndb;
|
||||
membar_sync();
|
||||
}
|
||||
if (track) {
|
||||
/* After this point lookups start flying in. */
|
||||
conn_tracking = CONN_TRACKING_ON;
|
||||
}
|
||||
|
||||
/* Install the new database, make it visible. */
|
||||
odb = atomic_swap_ptr(&conn_db, ndb);
|
||||
membar_sync();
|
||||
conn_tracking = tracking;
|
||||
|
||||
/* Done. Destroy the old database, if any. */
|
||||
mutex_exit(&conn_lock);
|
||||
|
||||
if (odb) {
|
||||
/*
|
||||
* Flush all, no sync since the caller did it for us.
|
||||
* Also, release the pool cache memory.
|
||||
*/
|
||||
npf_conn_gc(odb, true, false);
|
||||
npf_conndb_destroy(odb);
|
||||
pool_cache_invalidate(conn_cache);
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,21 +221,11 @@ npf_conn_reload(npf_conndb_t *ndb, int tracking)
|
||||
void
|
||||
npf_conn_tracking(bool track)
|
||||
{
|
||||
if (conn_tracking == CONN_TRACKING_OFF && track) {
|
||||
/* Disabled -> Enable. */
|
||||
npf_conndb_t *cd = npf_conndb_create();
|
||||
npf_conn_reload(cd, CONN_TRACKING_ON);
|
||||
return;
|
||||
}
|
||||
if (conn_tracking == CONN_TRACKING_ON && !track) {
|
||||
/* Enabled -> Disable. */
|
||||
npf_conn_reload(NULL, CONN_TRACKING_OFF);
|
||||
pool_cache_invalidate(conn_cache);
|
||||
return;
|
||||
}
|
||||
KASSERT(npf_config_locked_p());
|
||||
conn_tracking = track ? CONN_TRACKING_ON : CONN_TRACKING_OFF;
|
||||
}
|
||||
|
||||
static bool
|
||||
static inline bool
|
||||
npf_conn_trackable_p(const npf_cache_t *npc)
|
||||
{
|
||||
/*
|
||||
@ -476,7 +457,7 @@ npf_conn_establish(npf_cache_t *npc, int di, bool per_if)
|
||||
return NULL;
|
||||
}
|
||||
NPF_PRINTF(("NPF: create conn %p\n", con));
|
||||
npf_stats_inc(NPF_STAT_SESSION_CREATE);
|
||||
npf_stats_inc(NPF_STAT_CONN_CREATE);
|
||||
|
||||
/* Reference count and flags (indicate direction). */
|
||||
mutex_init(&con->c_lock, MUTEX_DEFAULT, IPL_SOFTNET);
|
||||
@ -521,7 +502,7 @@ npf_conn_establish(npf_cache_t *npc, int di, bool per_if)
|
||||
if (!npf_conndb_insert(conn_db, bk, con)) {
|
||||
/* We have hit the duplicate. */
|
||||
npf_conndb_remove(conn_db, fw);
|
||||
npf_stats_inc(NPF_STAT_RACE_SESSION);
|
||||
npf_stats_inc(NPF_STAT_RACE_CONN);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -552,7 +533,7 @@ npf_conn_destroy(npf_conn_t *con)
|
||||
|
||||
/* Free the structure, increase the counter. */
|
||||
pool_cache_put(conn_cache, con);
|
||||
npf_stats_inc(NPF_STAT_SESSION_DESTROY);
|
||||
npf_stats_inc(NPF_STAT_CONN_DESTROY);
|
||||
NPF_PRINTF(("NPF: conn %p destroyed\n", con));
|
||||
}
|
||||
|
||||
@ -719,21 +700,18 @@ npf_conn_expired(const npf_conn_t *con, const struct timespec *tsnow)
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_conn_worker: G/C to run from a worker thread.
|
||||
* npf_conn_gc: garbage collect the expired connections.
|
||||
*
|
||||
* => Must run in a single-threaded manner.
|
||||
* => If it is a flush request, then destroy all connections.
|
||||
* => If 'sync' is true, then perform passive serialisation.
|
||||
*/
|
||||
static void
|
||||
npf_conn_worker(void)
|
||||
npf_conn_gc(npf_conndb_t *cd, bool flush, bool sync)
|
||||
{
|
||||
npf_conn_t *con, *prev, *gclist = NULL;
|
||||
npf_conndb_t *cd;
|
||||
struct timespec tsnow;
|
||||
bool flushall;
|
||||
|
||||
mutex_enter(&conn_lock);
|
||||
if ((cd = conn_db) == NULL) {
|
||||
goto done;
|
||||
}
|
||||
flushall = (conn_tracking != CONN_TRACKING_ON);
|
||||
getnanouptime(&tsnow);
|
||||
|
||||
/*
|
||||
@ -745,7 +723,7 @@ npf_conn_worker(void)
|
||||
npf_conn_t *next = con->c_next;
|
||||
|
||||
/* Expired? Flushing all? */
|
||||
if (!npf_conn_expired(con, &tsnow) && !flushall) {
|
||||
if (!npf_conn_expired(con, &tsnow) && !flush) {
|
||||
prev = con;
|
||||
con = next;
|
||||
continue;
|
||||
@ -775,12 +753,18 @@ npf_conn_worker(void)
|
||||
con = next;
|
||||
}
|
||||
npf_conndb_settail(cd, prev);
|
||||
done:
|
||||
/* Ensure we it is safe to destroy the connections. */
|
||||
if (gclist) {
|
||||
npf_config_enter();
|
||||
npf_config_sync();
|
||||
npf_config_exit();
|
||||
|
||||
/*
|
||||
* Ensure it is safe to destroy the connections.
|
||||
* Note: drop the conn_lock (see the lock order).
|
||||
*/
|
||||
if (sync) {
|
||||
mutex_exit(&conn_lock);
|
||||
if (gclist) {
|
||||
npf_config_enter();
|
||||
npf_config_sync();
|
||||
npf_config_exit();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -802,28 +786,25 @@ done:
|
||||
npf_conn_destroy(con);
|
||||
con = next;
|
||||
}
|
||||
|
||||
if (conn_tracking == CONN_TRACKING_FLUSH) {
|
||||
/* Flush was requested - indicate we are done. */
|
||||
conn_tracking = CONN_TRACKING_OFF;
|
||||
cv_broadcast(&conn_cv);
|
||||
}
|
||||
mutex_exit(&conn_lock);
|
||||
}
|
||||
|
||||
void
|
||||
npf_conn_load(npf_conndb_t *cd)
|
||||
{
|
||||
KASSERT(cd != NULL);
|
||||
npf_conn_reload(cd, CONN_TRACKING_ON);
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_conn_save: construct a list of connections prepared for saving.
|
||||
* npf_conn_worker: G/C to run from a worker thread.
|
||||
*/
|
||||
static void
|
||||
npf_conn_worker(void)
|
||||
{
|
||||
mutex_enter(&conn_lock);
|
||||
/* Note: the conn_lock will be released (sync == true). */
|
||||
npf_conn_gc(conn_db, false, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_conn_export: construct a list of connections prepared for saving.
|
||||
* Note: this is expected to be an expensive operation.
|
||||
*/
|
||||
int
|
||||
npf_conn_save(prop_array_t conlist, prop_array_t nplist)
|
||||
npf_conn_export(prop_array_t conlist)
|
||||
{
|
||||
npf_conn_t *con, *prev;
|
||||
|
||||
@ -832,7 +813,7 @@ npf_conn_save(prop_array_t conlist, prop_array_t nplist)
|
||||
* destruction and G/C thread.
|
||||
*/
|
||||
mutex_enter(&conn_lock);
|
||||
if (!conn_db || conn_tracking != CONN_TRACKING_ON) {
|
||||
if (conn_tracking != CONN_TRACKING_ON) {
|
||||
mutex_exit(&conn_lock);
|
||||
return 0;
|
||||
}
|
||||
@ -861,11 +842,8 @@ npf_conn_save(prop_array_t conlist, prop_array_t nplist)
|
||||
d = prop_data_create_data(bkey, NPF_CONN_MAXKEYLEN);
|
||||
prop_dictionary_set_and_rel(cdict, "back-key", d);
|
||||
|
||||
CTASSERT(sizeof(uintptr_t) <= sizeof(uint64_t));
|
||||
prop_dictionary_set_uint64(cdict, "id-ptr", (uintptr_t)con);
|
||||
|
||||
if (con->c_nat) {
|
||||
npf_nat_save(cdict, nplist, con->c_nat);
|
||||
npf_nat_export(cdict, con->c_nat);
|
||||
}
|
||||
prop_array_add(conlist, cdict);
|
||||
prop_object_release(cdict);
|
||||
@ -875,16 +853,16 @@ skip:
|
||||
}
|
||||
npf_conndb_settail(conn_db, prev);
|
||||
mutex_exit(&conn_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_conn_restore: fully reconstruct a single connection from a directory
|
||||
* and insert into the given database.
|
||||
* npf_conn_import: fully reconstruct a single connection from a
|
||||
* directory and insert into the given database.
|
||||
*/
|
||||
int
|
||||
npf_conn_restore(npf_conndb_t *cd, prop_dictionary_t cdict)
|
||||
npf_conn_import(npf_conndb_t *cd, prop_dictionary_t cdict,
|
||||
npf_ruleset_t *natlist)
|
||||
{
|
||||
npf_conn_t *con;
|
||||
npf_connkey_t *fw, *bk;
|
||||
@ -909,7 +887,7 @@ npf_conn_restore(npf_conndb_t *cd, prop_dictionary_t cdict)
|
||||
memcpy(&con->c_state, d, sizeof(npf_state_t));
|
||||
|
||||
/* Reconstruct NAT association, if any, or return NULL. */
|
||||
con->c_nat = npf_nat_restore(cdict, con);
|
||||
con->c_nat = npf_nat_import(cdict, natlist, con);
|
||||
|
||||
/*
|
||||
* Fetch and copy the keys for each direction.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_conn.h,v 1.2 2014/07/20 00:37:41 rmind Exp $ */
|
||||
/* $NetBSD: npf_conn.h,v 1.3 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
|
||||
@ -46,6 +46,9 @@ typedef struct npf_connkey npf_connkey_t;
|
||||
|
||||
#include <sys/rbtree.h>
|
||||
|
||||
/*
|
||||
* See npf_conn_key() function for the description key layout.
|
||||
*/
|
||||
#define NPF_CONN_NKEYWORDS (2 + ((sizeof(npf_addr_t) * 2) >> 2))
|
||||
#define NPF_CONN_MAXKEYLEN (NPF_CONN_NKEYWORDS * sizeof(uint32_t))
|
||||
#define NPF_CONN_GETALEN(key) ((key)->ck_key[0] & 0xffff)
|
||||
@ -98,6 +101,7 @@ struct npf_conn {
|
||||
void npf_conn_sysinit(void);
|
||||
void npf_conn_sysfini(void);
|
||||
void npf_conn_tracking(bool);
|
||||
void npf_conn_load(npf_conndb_t *, bool);
|
||||
|
||||
bool npf_conn_conkey(const npf_cache_t *, npf_connkey_t *, bool);
|
||||
npf_conn_t * npf_conn_lookup(const npf_cache_t *, const int, bool *);
|
||||
@ -110,11 +114,9 @@ void npf_conn_setpass(npf_conn_t *, npf_rproc_t *);
|
||||
int npf_conn_setnat(const npf_cache_t *, npf_conn_t *,
|
||||
npf_nat_t *, u_int);
|
||||
npf_nat_t * npf_conn_retnat(npf_conn_t *, const int, bool *);
|
||||
|
||||
void npf_conn_load(npf_conndb_t *);
|
||||
int npf_conn_save(prop_array_t, prop_array_t);
|
||||
int npf_conn_restore(npf_conndb_t *, prop_dictionary_t);
|
||||
|
||||
int npf_conn_export(prop_array_t);
|
||||
int npf_conn_import(npf_conndb_t *, prop_dictionary_t,
|
||||
npf_ruleset_t *);
|
||||
void npf_conn_print(const npf_conn_t *);
|
||||
|
||||
/*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_conndb.c,v 1.1 2014/07/19 18:24:16 rmind Exp $ */
|
||||
/* $NetBSD: npf_conndb.c,v 1.2 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2010-2014 The NetBSD Foundation, Inc.
|
||||
@ -34,7 +34,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_conndb.c,v 1.1 2014/07/19 18:24:16 rmind Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_conndb.c,v 1.2 2014/07/23 01:25:34 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
@ -127,6 +127,10 @@ npf_conndb_destroy(npf_conndb_t *cd)
|
||||
{
|
||||
size_t len = offsetof(npf_conndb_t, cd_hashtbl[CONNDB_HASH_BUCKETS]);
|
||||
|
||||
KASSERT(cd->cd_recent == NULL);
|
||||
KASSERT(cd->cd_list == NULL);
|
||||
KASSERT(cd->cd_tail == NULL);
|
||||
|
||||
for (u_int i = 0; i < CONNDB_HASH_BUCKETS; i++) {
|
||||
npf_hashbucket_t *hb = &cd->cd_hashtbl[i];
|
||||
|
||||
@ -252,6 +256,7 @@ npf_conndb_getlist(npf_conndb_t *cd)
|
||||
KASSERT(cd->cd_list == NULL);
|
||||
cd->cd_list = con;
|
||||
} else {
|
||||
KASSERT(prev->c_next == NULL);
|
||||
prev->c_next = con;
|
||||
}
|
||||
return cd->cd_list;
|
||||
@ -264,5 +269,6 @@ void
|
||||
npf_conndb_settail(npf_conndb_t *cd, npf_conn_t *con)
|
||||
{
|
||||
KASSERT(con || cd->cd_list == NULL);
|
||||
KASSERT(!con || con->c_next == NULL);
|
||||
cd->cd_tail = con;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_ctl.c,v 1.34 2014/07/19 18:24:16 rmind Exp $ */
|
||||
/* $NetBSD: npf_ctl.c,v 1.35 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
|
||||
@ -37,7 +37,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.34 2014/07/19 18:24:16 rmind Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.35 2014/07/23 01:25:34 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/conf.h>
|
||||
@ -181,6 +181,7 @@ npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables,
|
||||
NPF_ERR_DEBUG(errdict);
|
||||
break;
|
||||
}
|
||||
prop_dictionary_remove(tbldict, "entries");
|
||||
}
|
||||
prop_object_iterator_release(it);
|
||||
/*
|
||||
@ -453,19 +454,67 @@ npf_mk_natlist(npf_ruleset_t *nset, prop_array_t natlist,
|
||||
}
|
||||
|
||||
/*
|
||||
* npfctl_reload: store passed data i.e. update settings, create passed
|
||||
* npf_mk_connlist: import a list of connections and load them.
|
||||
*/
|
||||
static int __noinline
|
||||
npf_mk_connlist(prop_array_t conlist, npf_ruleset_t *natlist,
|
||||
npf_conndb_t **conndb, prop_dictionary_t errdict)
|
||||
{
|
||||
prop_dictionary_t condict;
|
||||
prop_object_iterator_t it;
|
||||
npf_conndb_t *cd;
|
||||
int error;
|
||||
|
||||
/* Connection list - array */
|
||||
if (prop_object_type(conlist) != PROP_TYPE_ARRAY) {
|
||||
NPF_ERR_DEBUG(errdict);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Create a connection database. */
|
||||
cd = npf_conndb_create();
|
||||
|
||||
error = 0;
|
||||
it = prop_array_iterator(conlist);
|
||||
while ((condict = prop_object_iterator_next(it)) != NULL) {
|
||||
/* Connection - dictionary. */
|
||||
if (prop_object_type(condict) != PROP_TYPE_DICTIONARY) {
|
||||
NPF_ERR_DEBUG(errdict);
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
/* Construct and insert real connection structure. */
|
||||
error = npf_conn_import(cd, condict, natlist);
|
||||
if (error) {
|
||||
NPF_ERR_DEBUG(errdict);
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop_object_iterator_release(it);
|
||||
if (error) {
|
||||
/* FIXME: npf_conn_gc(cd, true, false); */
|
||||
npf_conndb_destroy(cd);
|
||||
} else {
|
||||
*conndb = cd;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* npfctl_load: store passed data i.e. update settings, create passed
|
||||
* tables, rules and atomically activate all them.
|
||||
*/
|
||||
int
|
||||
npfctl_reload(u_long cmd, void *data)
|
||||
npfctl_load(u_long cmd, void *data)
|
||||
{
|
||||
struct plistref *pref = data;
|
||||
prop_dictionary_t npf_dict, errdict;
|
||||
prop_array_t alglist, natlist, tables, rprocs, rules;
|
||||
prop_array_t alglist, natlist, tables, rprocs, rules, conlist;
|
||||
npf_tableset_t *tblset = NULL;
|
||||
npf_rprocset_t *rpset = NULL;
|
||||
npf_ruleset_t *rlset = NULL;
|
||||
npf_ruleset_t *nset = NULL;
|
||||
npf_conndb_t *conndb = NULL;
|
||||
uint32_t ver = 0;
|
||||
size_t nitems;
|
||||
bool flush;
|
||||
@ -541,16 +590,22 @@ npfctl_reload(u_long cmd, void *data)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Connections (if loading any). */
|
||||
if ((conlist = prop_dictionary_get(npf_dict, "conn-list")) != NULL) {
|
||||
error = npf_mk_connlist(conlist, nset, &conndb, errdict);
|
||||
if (error) {
|
||||
goto fail;
|
||||
}
|
||||
prop_dictionary_remove(npf_dict, "conn-list");
|
||||
}
|
||||
|
||||
flush = false;
|
||||
prop_dictionary_get_bool(npf_dict, "flush", &flush);
|
||||
|
||||
/*
|
||||
* Finally - perform the reload.
|
||||
* Finally - perform the load.
|
||||
*/
|
||||
npf_config_reload(npf_dict, rlset, tblset, nset, rpset, flush);
|
||||
|
||||
/* Turn on/off connection tracking accordingly. */
|
||||
npf_conn_tracking(!flush);
|
||||
npf_config_load(npf_dict, rlset, tblset, nset, rpset, conndb, flush);
|
||||
|
||||
/* Done. Since data is consumed now, we shall not destroy it. */
|
||||
tblset = NULL;
|
||||
@ -588,6 +643,39 @@ fail:
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* npfctl_save: export the config dictionary as it was submitted,
|
||||
* including the current snapshot of the connections. Additionally,
|
||||
* indicate whether the ruleset is currently active.
|
||||
*/
|
||||
int
|
||||
npfctl_save(u_long cmd, void *data)
|
||||
{
|
||||
struct plistref *pref = data;
|
||||
prop_dictionary_t npf_dict;
|
||||
prop_array_t conlist;
|
||||
int error;
|
||||
|
||||
npf_config_enter();
|
||||
conlist = prop_array_create();
|
||||
|
||||
/* Serialise the connections. */
|
||||
error = npf_conn_export(conlist);
|
||||
if (error) {
|
||||
prop_object_release(conlist);
|
||||
goto out;
|
||||
}
|
||||
|
||||
npf_dict = npf_config_dict();
|
||||
prop_dictionary_set_bool(npf_dict, "active", npf_pfil_registered_p());
|
||||
prop_dictionary_set_and_rel(npf_dict, "conn-list", conlist);
|
||||
|
||||
error = prop_dictionary_copyout_ioctl(pref, cmd, npf_dict);
|
||||
out:
|
||||
npf_config_exit();
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* npfctl_rule: add or remove dynamic rules in the specified ruleset.
|
||||
*/
|
||||
@ -688,123 +776,6 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* npfctl_getconf: return the config dictionary as it was submitted.
|
||||
* Additionally, indicate whether the ruleset is currently active.
|
||||
*/
|
||||
int
|
||||
npfctl_getconf(u_long cmd, void *data)
|
||||
{
|
||||
struct plistref *pref = data;
|
||||
prop_dictionary_t npf_dict;
|
||||
int error;
|
||||
|
||||
npf_config_enter();
|
||||
npf_dict = npf_config_dict();
|
||||
prop_dictionary_set_bool(npf_dict, "active", npf_pfil_registered_p());
|
||||
error = prop_dictionary_copyout_ioctl(pref, cmd, npf_dict);
|
||||
npf_config_exit();
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* npfctl_conn_save: construct a list of connections and export.
|
||||
*/
|
||||
int
|
||||
npfctl_conn_save(u_long cmd, void *data)
|
||||
{
|
||||
struct plistref *pref = data;
|
||||
prop_array_t conlist, nplist;
|
||||
prop_dictionary_t dict;
|
||||
int error;
|
||||
|
||||
/* Create a dictionary and two lists. */
|
||||
dict = prop_dictionary_create();
|
||||
conlist = prop_array_create();
|
||||
nplist = prop_array_create();
|
||||
|
||||
/* Save the connections. */
|
||||
error = npf_conn_save(conlist, nplist);
|
||||
if (error) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Set the connection list, NAT policy list and export. */
|
||||
prop_dictionary_set(dict, "session-list", conlist);
|
||||
prop_dictionary_set(dict, "nat-policy-list", nplist);
|
||||
error = prop_dictionary_copyout_ioctl(pref, cmd, dict);
|
||||
fail:
|
||||
prop_object_release(dict);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* npfctl_conn_load: import a list of connections and load them.
|
||||
*/
|
||||
int
|
||||
npfctl_conn_load(u_long cmd, void *data)
|
||||
{
|
||||
const struct plistref *pref = data;
|
||||
npf_conndb_t *conndb = NULL;
|
||||
prop_dictionary_t dict, condict;
|
||||
prop_object_iterator_t it;
|
||||
prop_array_t conlist;
|
||||
int error;
|
||||
|
||||
/* Get the dictionary containing connections and NAT policies. */
|
||||
error = prop_dictionary_copyin_ioctl(pref, cmd, &dict);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* Note: connection objects contain the references to the NAT
|
||||
* policy entries. Therefore, no need to directly access it.
|
||||
*/
|
||||
conlist = prop_dictionary_get(dict, "session-list");
|
||||
if (prop_object_type(conlist) != PROP_TYPE_ARRAY) {
|
||||
prop_object_release(conlist);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Create a connection database. */
|
||||
conndb = npf_conndb_create();
|
||||
|
||||
/*
|
||||
* Iterate through and construct each connection. Note: acquire
|
||||
* the config lock as we access NAT policies during the restore.
|
||||
*/
|
||||
error = 0;
|
||||
it = prop_array_iterator(conlist);
|
||||
|
||||
npf_config_enter();
|
||||
while ((condict = prop_object_iterator_next(it)) != NULL) {
|
||||
/* Connection - dictionary. */
|
||||
if (prop_object_type(condict) != PROP_TYPE_DICTIONARY) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
/* Construct and insert real connection structure. */
|
||||
error = npf_conn_restore(conndb, condict);
|
||||
if (error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
npf_config_exit();
|
||||
|
||||
prop_object_iterator_release(it);
|
||||
prop_object_release(conlist);
|
||||
|
||||
if (!error) {
|
||||
/* Finally, load the new table. */
|
||||
npf_conn_load(conndb);
|
||||
} else {
|
||||
/* Destroy the connection database. */
|
||||
npf_conndb_destroy(conndb);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* npfctl_table: add, remove or query entries in the specified table.
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_handler.c,v 1.32 2014/07/20 00:37:41 rmind Exp $ */
|
||||
/* $NetBSD: npf_handler.c,v 1.33 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
|
||||
@ -36,7 +36,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.32 2014/07/20 00:37:41 rmind Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.33 2014/07/23 01:25:34 rmind Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
@ -184,7 +184,7 @@ npf_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di)
|
||||
|
||||
/* If "passing" connection found - skip the ruleset inspection. */
|
||||
if (con && npf_conn_pass(con, &rp)) {
|
||||
npf_stats_inc(NPF_STAT_PASS_SESSION);
|
||||
npf_stats_inc(NPF_STAT_PASS_CONN);
|
||||
KASSERT(error == 0);
|
||||
goto pass;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_impl.h,v 1.55 2014/07/20 00:37:41 rmind Exp $ */
|
||||
/* $NetBSD: npf_impl.h,v 1.56 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
|
||||
@ -149,8 +149,9 @@ bool npf_config_locked_p(void);
|
||||
int npf_config_read_enter(void);
|
||||
void npf_config_read_exit(int);
|
||||
|
||||
void npf_config_reload(prop_dictionary_t, npf_ruleset_t *,
|
||||
npf_tableset_t *, npf_ruleset_t *, npf_rprocset_t *, bool);
|
||||
void npf_config_load(prop_dictionary_t, npf_ruleset_t *,
|
||||
npf_tableset_t *, npf_ruleset_t *, npf_rprocset_t *,
|
||||
npf_conndb_t *, bool);
|
||||
npf_ruleset_t * npf_config_ruleset(void);
|
||||
npf_ruleset_t * npf_config_natset(void);
|
||||
npf_tableset_t *npf_config_tableset(void);
|
||||
@ -167,9 +168,8 @@ void npflogattach(int);
|
||||
void npflogdetach(void);
|
||||
int npfctl_switch(void *);
|
||||
int npfctl_reload(u_long, void *);
|
||||
int npfctl_getconf(u_long, void *);
|
||||
int npfctl_conn_save(u_long, void *);
|
||||
int npfctl_conn_load(u_long, void *);
|
||||
int npfctl_save(u_long, void *);
|
||||
int npfctl_load(u_long, void *);
|
||||
int npfctl_rule(u_long, void *);
|
||||
int npfctl_table(void *);
|
||||
|
||||
@ -255,8 +255,8 @@ npf_ruleset_t * npf_ruleset_create(size_t);
|
||||
void npf_ruleset_destroy(npf_ruleset_t *);
|
||||
void npf_ruleset_insert(npf_ruleset_t *, npf_rule_t *);
|
||||
void npf_ruleset_reload(npf_ruleset_t *, npf_ruleset_t *);
|
||||
npf_rule_t * npf_ruleset_matchnat(npf_ruleset_t *, npf_natpolicy_t *);
|
||||
npf_rule_t * npf_ruleset_sharepm(npf_ruleset_t *, npf_natpolicy_t *);
|
||||
npf_natpolicy_t *npf_ruleset_findnat(npf_ruleset_t *, uint64_t);
|
||||
void npf_ruleset_freealg(npf_ruleset_t *, npf_alg_t *);
|
||||
|
||||
int npf_ruleset_add(npf_ruleset_t *, const char *, npf_rule_t *);
|
||||
@ -310,8 +310,10 @@ void npf_nat_sysinit(void);
|
||||
void npf_nat_sysfini(void);
|
||||
npf_natpolicy_t *npf_nat_newpolicy(prop_dictionary_t, npf_ruleset_t *);
|
||||
void npf_nat_freepolicy(npf_natpolicy_t *);
|
||||
bool npf_nat_matchpolicy(npf_natpolicy_t *, npf_natpolicy_t *);
|
||||
bool npf_nat_cmppolicy(npf_natpolicy_t *, npf_natpolicy_t *);
|
||||
bool npf_nat_sharepm(npf_natpolicy_t *, npf_natpolicy_t *);
|
||||
void npf_nat_setid(npf_natpolicy_t *, uint64_t);
|
||||
uint64_t npf_nat_getid(const npf_natpolicy_t *);
|
||||
void npf_nat_freealg(npf_natpolicy_t *, npf_alg_t *);
|
||||
|
||||
int npf_do_nat(npf_cache_t *, npf_conn_t *, const int);
|
||||
@ -320,8 +322,9 @@ void npf_nat_getorig(npf_nat_t *, npf_addr_t **, in_port_t *);
|
||||
void npf_nat_gettrans(npf_nat_t *, npf_addr_t **, in_port_t *);
|
||||
void npf_nat_setalg(npf_nat_t *, npf_alg_t *, uintptr_t);
|
||||
|
||||
int npf_nat_save(prop_dictionary_t, prop_array_t, npf_nat_t *);
|
||||
npf_nat_t * npf_nat_restore(prop_dictionary_t, npf_conn_t *);
|
||||
void npf_nat_export(prop_dictionary_t, npf_nat_t *);
|
||||
npf_nat_t * npf_nat_import(prop_dictionary_t, npf_ruleset_t *,
|
||||
npf_conn_t *);
|
||||
|
||||
/* ALG interface. */
|
||||
void npf_alg_sysinit(void);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_nat.c,v 1.30 2014/07/20 00:37:41 rmind Exp $ */
|
||||
/* $NetBSD: npf_nat.c,v 1.31 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2014 Mindaugas Rasiukevicius <rmind at netbsd org>
|
||||
@ -71,7 +71,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.30 2014/07/20 00:37:41 rmind Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.31 2014/07/23 01:25:34 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
@ -113,14 +113,22 @@ typedef struct {
|
||||
* NAT policy structure.
|
||||
*/
|
||||
struct npf_natpolicy {
|
||||
kmutex_t n_lock;
|
||||
LIST_HEAD(, npf_nat) n_nat_list;
|
||||
volatile u_int n_refcnt;
|
||||
kmutex_t n_lock;
|
||||
npf_portmap_t * n_portmap;
|
||||
/* NPF_NP_CMP_START */
|
||||
uint64_t n_id;
|
||||
|
||||
/*
|
||||
* Translation type, flags and address. Optionally, prefix
|
||||
* for the NPTv6 and translation port. Translation algorithm
|
||||
* and related data (for NPTv6, the adjustment value).
|
||||
*
|
||||
* NPF_NP_CMP_START mark starts here.
|
||||
*/
|
||||
int n_type;
|
||||
u_int n_flags;
|
||||
size_t n_addr_sz;
|
||||
u_int n_alen;
|
||||
npf_addr_t n_taddr;
|
||||
npf_netmask_t n_tmask;
|
||||
in_port_t n_tport;
|
||||
@ -183,7 +191,7 @@ npf_nat_sysfini(void)
|
||||
* => Shares portmap if policy is on existing translation address.
|
||||
*/
|
||||
npf_natpolicy_t *
|
||||
npf_nat_newpolicy(prop_dictionary_t natdict, npf_ruleset_t *nrlset)
|
||||
npf_nat_newpolicy(prop_dictionary_t natdict, npf_ruleset_t *rset)
|
||||
{
|
||||
npf_natpolicy_t *np;
|
||||
prop_object_t obj;
|
||||
@ -204,11 +212,11 @@ npf_nat_newpolicy(prop_dictionary_t natdict, npf_ruleset_t *nrlset)
|
||||
|
||||
/* Translation IP, mask and port (if applicable). */
|
||||
obj = prop_dictionary_get(natdict, "translation-ip");
|
||||
np->n_addr_sz = prop_data_size(obj);
|
||||
if (np->n_addr_sz == 0 || np->n_addr_sz > sizeof(npf_addr_t)) {
|
||||
np->n_alen = prop_data_size(obj);
|
||||
if (np->n_alen == 0 || np->n_alen > sizeof(npf_addr_t)) {
|
||||
goto err;
|
||||
}
|
||||
memcpy(&np->n_taddr, prop_data_data_nocopy(obj), np->n_addr_sz);
|
||||
memcpy(&np->n_taddr, prop_data_data_nocopy(obj), np->n_alen);
|
||||
prop_dictionary_get_uint8(natdict, "translation-mask", &np->n_tmask);
|
||||
prop_dictionary_get_uint16(natdict, "translation-port", &np->n_tport);
|
||||
|
||||
@ -235,7 +243,7 @@ npf_nat_newpolicy(prop_dictionary_t natdict, npf_ruleset_t *nrlset)
|
||||
* Inspect NAT policies in the ruleset for port map sharing.
|
||||
* Note that npf_ruleset_sharepm() will increase the reference count.
|
||||
*/
|
||||
if (!npf_ruleset_sharepm(nrlset, np)) {
|
||||
if (!npf_ruleset_sharepm(rset, np)) {
|
||||
/* Allocate a new port map for the NAT policy. */
|
||||
pm = kmem_zalloc(PORTMAP_MEM_SIZE, KM_SLEEP);
|
||||
pm->p_refcnt = 1;
|
||||
@ -297,31 +305,30 @@ npf_nat_freealg(npf_natpolicy_t *np, npf_alg_t *alg)
|
||||
|
||||
mutex_enter(&np->n_lock);
|
||||
LIST_FOREACH(nt, &np->n_nat_list, nt_entry) {
|
||||
if (nt->nt_alg != alg) {
|
||||
continue;
|
||||
}
|
||||
nt->nt_alg = NULL;
|
||||
if (nt->nt_alg == alg)
|
||||
nt->nt_alg = NULL;
|
||||
}
|
||||
mutex_exit(&np->n_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_nat_matchpolicy: compare two NAT policies.
|
||||
* npf_nat_cmppolicy: compare two NAT policies.
|
||||
*
|
||||
* => Return 0 on match, and non-zero otherwise.
|
||||
*/
|
||||
bool
|
||||
npf_nat_matchpolicy(npf_natpolicy_t *np, npf_natpolicy_t *mnp)
|
||||
npf_nat_cmppolicy(npf_natpolicy_t *np, npf_natpolicy_t *mnp)
|
||||
{
|
||||
void *np_raw, *mnp_raw;
|
||||
const void *np_raw, *mnp_raw;
|
||||
|
||||
/*
|
||||
* Compare the relevant NAT policy information (in raw form),
|
||||
* which is enough for matching criterion.
|
||||
*/
|
||||
KASSERT(np && mnp && np != mnp);
|
||||
np_raw = (uint8_t *)np + NPF_NP_CMP_START;
|
||||
mnp_raw = (uint8_t *)mnp + NPF_NP_CMP_START;
|
||||
return (memcmp(np_raw, mnp_raw, NPF_NP_CMP_SIZE) == 0);
|
||||
np_raw = (const uint8_t *)np + NPF_NP_CMP_START;
|
||||
mnp_raw = (const uint8_t *)mnp + NPF_NP_CMP_START;
|
||||
return memcmp(np_raw, mnp_raw, NPF_NP_CMP_SIZE) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -335,10 +342,10 @@ npf_nat_sharepm(npf_natpolicy_t *np, npf_natpolicy_t *mnp)
|
||||
if ((np->n_flags & mnp->n_flags & NPF_NAT_PORTMAP) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (np->n_addr_sz != mnp->n_addr_sz) {
|
||||
if (np->n_alen != mnp->n_alen) {
|
||||
return false;
|
||||
}
|
||||
if (memcmp(&np->n_taddr, &mnp->n_taddr, np->n_addr_sz) != 0) {
|
||||
if (memcmp(&np->n_taddr, &mnp->n_taddr, np->n_alen) != 0) {
|
||||
return false;
|
||||
}
|
||||
/* If NAT policy has an old port map - drop the reference. */
|
||||
@ -355,6 +362,18 @@ npf_nat_sharepm(npf_natpolicy_t *np, npf_natpolicy_t *mnp)
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
npf_nat_setid(npf_natpolicy_t *np, uint64_t id)
|
||||
{
|
||||
np->n_id = id;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
npf_nat_getid(const npf_natpolicy_t *np)
|
||||
{
|
||||
return np->n_id;
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_nat_getport: allocate and return a port in the NAT policy portmap.
|
||||
*
|
||||
@ -605,7 +624,7 @@ npf_nat_algo(npf_cache_t *npc, const npf_natpolicy_t *np, bool forw)
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_do_nat:
|
||||
@ -776,103 +795,62 @@ npf_nat_destroy(npf_nat_t *nt)
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_nat_save: construct NAT entry and reference to the NAT policy.
|
||||
* npf_nat_export: serialise the NAT entry with a NAT policy ID.
|
||||
*/
|
||||
int
|
||||
npf_nat_save(prop_dictionary_t condict, prop_array_t natlist, npf_nat_t *nt)
|
||||
void
|
||||
npf_nat_export(prop_dictionary_t condict, npf_nat_t *nt)
|
||||
{
|
||||
npf_natpolicy_t *np = nt->nt_natpolicy;
|
||||
prop_object_iterator_t it;
|
||||
prop_dictionary_t npdict;
|
||||
prop_data_t nd, npd;
|
||||
uint64_t itnp;
|
||||
prop_dictionary_t natdict;
|
||||
prop_data_t d;
|
||||
|
||||
/* Set NAT entry data. */
|
||||
nd = prop_data_create_data(nt, sizeof(npf_nat_t));
|
||||
prop_dictionary_set(condict, "nat-data", nd);
|
||||
prop_object_release(nd);
|
||||
|
||||
/* Find or create a NAT policy. */
|
||||
it = prop_array_iterator(natlist);
|
||||
while ((npdict = prop_object_iterator_next(it)) != NULL) {
|
||||
CTASSERT(sizeof(uintptr_t) <= sizeof(uint64_t));
|
||||
prop_dictionary_get_uint64(npdict, "id-ptr", &itnp);
|
||||
if ((uintptr_t)itnp == (uintptr_t)np) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (npdict == NULL) {
|
||||
/* Create NAT policy dictionary and copy the data. */
|
||||
npdict = prop_dictionary_create();
|
||||
npd = prop_data_create_data(np, sizeof(npf_natpolicy_t));
|
||||
prop_dictionary_set(npdict, "nat-policy-data", npd);
|
||||
prop_object_release(npd);
|
||||
|
||||
CTASSERT(sizeof(uintptr_t) <= sizeof(uint64_t));
|
||||
prop_dictionary_set_uint64(npdict, "id-ptr", (uintptr_t)np);
|
||||
prop_array_add(natlist, npdict);
|
||||
prop_object_release(npdict);
|
||||
}
|
||||
prop_dictionary_set(condict, "nat-policy", npdict);
|
||||
prop_object_release(npdict);
|
||||
return 0;
|
||||
natdict = prop_dictionary_create();
|
||||
d = prop_data_create_data(&nt->nt_oaddr, sizeof(npf_addr_t));
|
||||
prop_dictionary_set_and_rel(natdict, "oaddr", d);
|
||||
prop_dictionary_set_uint16(natdict, "oport", nt->nt_oport);
|
||||
prop_dictionary_set_uint16(natdict, "tport", nt->nt_tport);
|
||||
prop_dictionary_set_uint64(natdict, "nat-policy", np->n_id);
|
||||
prop_dictionary_set_and_rel(condict, "nat", natdict);
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_nat_restore: find a matching NAT policy and restore NAT entry.
|
||||
*
|
||||
* => Caller should lock the active NAT ruleset.
|
||||
* npf_nat_import: find the NAT policy and unserialise the NAT entry.
|
||||
*/
|
||||
npf_nat_t *
|
||||
npf_nat_restore(prop_dictionary_t condict, npf_conn_t *con)
|
||||
npf_nat_import(prop_dictionary_t natdict, npf_ruleset_t *natlist,
|
||||
npf_conn_t *con)
|
||||
{
|
||||
const npf_natpolicy_t *onp;
|
||||
const npf_nat_t *ntraw;
|
||||
prop_object_t obj;
|
||||
npf_natpolicy_t *np;
|
||||
npf_rule_t *rl;
|
||||
npf_nat_t *nt;
|
||||
uint64_t np_id;
|
||||
const void *d;
|
||||
|
||||
/* Get raw NAT entry. */
|
||||
obj = prop_dictionary_get(condict, "nat-data");
|
||||
ntraw = prop_data_data_nocopy(obj);
|
||||
if (ntraw == NULL || prop_data_size(obj) != sizeof(npf_nat_t)) {
|
||||
prop_dictionary_get_uint64(natdict, "nat-policy", &np_id);
|
||||
if ((np = npf_ruleset_findnat(natlist, np_id)) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
nt = pool_cache_get(nat_cache, PR_WAITOK);
|
||||
memset(nt, 0, sizeof(npf_nat_t));
|
||||
|
||||
/* Find a stored NAT policy information. */
|
||||
obj = prop_dictionary_get(
|
||||
prop_dictionary_get(condict, "nat-policy"), "nat-policy-data");
|
||||
onp = prop_data_data_nocopy(obj);
|
||||
if (onp == NULL || prop_data_size(obj) != sizeof(npf_natpolicy_t)) {
|
||||
prop_object_t obj = prop_dictionary_get(natdict, "oaddr");
|
||||
if ((d = prop_data_data_nocopy(obj)) == NULL ||
|
||||
prop_data_size(obj) != sizeof(npf_addr_t)) {
|
||||
pool_cache_put(nat_cache, nt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Match if there is an existing NAT policy. Will acquire the
|
||||
* reference on it if further operations are successful.
|
||||
*/
|
||||
KASSERT(npf_config_locked_p());
|
||||
rl = npf_ruleset_matchnat(npf_config_natset(), __UNCONST(onp));
|
||||
if (rl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
np = npf_rule_getnat(rl);
|
||||
KASSERT(np != NULL);
|
||||
memcpy(&nt->nt_oaddr, d, sizeof(npf_addr_t));
|
||||
prop_dictionary_get_uint16(natdict, "oport", &nt->nt_oport);
|
||||
prop_dictionary_get_uint16(natdict, "tport", &nt->nt_tport);
|
||||
|
||||
/* Take a specific port from port-map. */
|
||||
if (!npf_nat_takeport(np, ntraw->nt_tport)) {
|
||||
if (!npf_nat_takeport(np, nt->nt_tport)) {
|
||||
pool_cache_put(nat_cache, nt);
|
||||
return NULL;
|
||||
}
|
||||
atomic_inc_uint(&np->n_refcnt);
|
||||
|
||||
/* Create and return NAT entry for association. */
|
||||
nt = pool_cache_get(nat_cache, PR_WAITOK);
|
||||
memcpy(nt, ntraw, sizeof(npf_nat_t));
|
||||
LIST_INSERT_HEAD(&np->n_nat_list, nt, nt_entry);
|
||||
nt->nt_natpolicy = np;
|
||||
nt->nt_conn = con;
|
||||
nt->nt_alg = NULL;
|
||||
return nt;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_ruleset.c,v 1.34 2014/07/20 00:37:41 rmind Exp $ */
|
||||
/* $NetBSD: npf_ruleset.c,v 1.35 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
|
||||
@ -34,7 +34,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.34 2014/07/20 00:37:41 rmind Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.35 2014/07/23 01:25:34 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
@ -378,6 +378,22 @@ npf_ruleset_gc(npf_ruleset_t *rlset)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_ruleset_cmpnat: find a matching NAT policy in the ruleset.
|
||||
*/
|
||||
static inline npf_rule_t *
|
||||
npf_ruleset_cmpnat(npf_ruleset_t *rlset, npf_natpolicy_t *mnp)
|
||||
{
|
||||
npf_rule_t *rl;
|
||||
|
||||
/* Find a matching NAT policy in the old ruleset. */
|
||||
LIST_FOREACH(rl, &rlset->rs_all, r_aentry) {
|
||||
if (rl->r_natp && npf_nat_cmppolicy(rl->r_natp, mnp))
|
||||
break;
|
||||
}
|
||||
return rl;
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_ruleset_reload: prepare the new ruleset by scanning the active
|
||||
* ruleset and 1) sharing the dynamic rules 2) sharing NAT policies.
|
||||
@ -388,6 +404,7 @@ void
|
||||
npf_ruleset_reload(npf_ruleset_t *newset, npf_ruleset_t *oldset)
|
||||
{
|
||||
npf_rule_t *rg, *rl;
|
||||
uint64_t nid = 0;
|
||||
|
||||
KASSERT(npf_config_locked_p());
|
||||
|
||||
@ -422,6 +439,7 @@ npf_ruleset_reload(npf_ruleset_t *newset, npf_ruleset_t *oldset)
|
||||
|
||||
/*
|
||||
* Scan all rules in the new ruleset and share NAT policies.
|
||||
* Also, assign a unique ID for each policy here.
|
||||
*/
|
||||
LIST_FOREACH(rl, &newset->rs_all, r_aentry) {
|
||||
npf_natpolicy_t *np;
|
||||
@ -431,8 +449,10 @@ npf_ruleset_reload(npf_ruleset_t *newset, npf_ruleset_t *oldset)
|
||||
if ((np = rl->r_natp) == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Does it match with any policy in the active ruleset? */
|
||||
if ((actrl = npf_ruleset_matchnat(oldset, np)) == NULL) {
|
||||
if ((actrl = npf_ruleset_cmpnat(oldset, np)) == NULL) {
|
||||
npf_nat_setid(np, ++nid);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -442,6 +462,7 @@ npf_ruleset_reload(npf_ruleset_t *newset, npf_ruleset_t *oldset)
|
||||
*/
|
||||
rl->r_natp = actrl->r_natp;
|
||||
npf_ruleset_sharepm(newset, rl->r_natp);
|
||||
npf_nat_setid(rl->r_natp, ++nid);
|
||||
|
||||
/*
|
||||
* Finally, mark the active rule to not destroy its NAT
|
||||
@ -456,22 +477,6 @@ npf_ruleset_reload(npf_ruleset_t *newset, npf_ruleset_t *oldset)
|
||||
newset->rs_idcnt = oldset->rs_idcnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_ruleset_matchnat: find a matching NAT policy in the ruleset.
|
||||
*/
|
||||
npf_rule_t *
|
||||
npf_ruleset_matchnat(npf_ruleset_t *rlset, npf_natpolicy_t *mnp)
|
||||
{
|
||||
npf_rule_t *rl;
|
||||
|
||||
/* Find a matching NAT policy in the old ruleset. */
|
||||
LIST_FOREACH(rl, &rlset->rs_all, r_aentry) {
|
||||
if (rl->r_natp && npf_nat_matchpolicy(rl->r_natp, mnp))
|
||||
break;
|
||||
}
|
||||
return rl;
|
||||
}
|
||||
|
||||
npf_rule_t *
|
||||
npf_ruleset_sharepm(npf_ruleset_t *rlset, npf_natpolicy_t *mnp)
|
||||
{
|
||||
@ -494,6 +499,20 @@ npf_ruleset_sharepm(npf_ruleset_t *rlset, npf_natpolicy_t *mnp)
|
||||
return rl;
|
||||
}
|
||||
|
||||
npf_natpolicy_t *
|
||||
npf_ruleset_findnat(npf_ruleset_t *rlset, uint64_t id)
|
||||
{
|
||||
npf_rule_t *rl;
|
||||
|
||||
LIST_FOREACH(rl, &rlset->rs_all, r_aentry) {
|
||||
npf_natpolicy_t *np = rl->r_natp;
|
||||
if (np && npf_nat_getid(np) == id) {
|
||||
return np;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_ruleset_freealg: inspect the ruleset and disassociate specified
|
||||
* ALG from all NAT entries using it.
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" $NetBSD: npfctl.8,v 1.15 2013/09/20 21:30:49 wiz Exp $
|
||||
.\" $NetBSD: npfctl.8,v 1.16 2014/07/23 01:25:34 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 September 19, 2013
|
||||
.Dd July 23, 2014
|
||||
.Dt NPFCTL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -53,26 +53,26 @@ Valid commands are:
|
||||
.It Ic start
|
||||
Enable packet inspection using the currently loaded configuration, if any.
|
||||
Note that this command does not load or reload the configuration,
|
||||
or affect existing sessions.
|
||||
or affect existing connections.
|
||||
.It Ic stop
|
||||
Disable packet inspection.
|
||||
This command does not change the currently loaded configuration,
|
||||
or affect existing sessions.
|
||||
or affect existing connections.
|
||||
.It Ic reload Op Ar path
|
||||
Load or reload configuration from file.
|
||||
The configuration file at
|
||||
.Pa /etc/npf.conf
|
||||
will be used unless a file is specified by
|
||||
.Ar path .
|
||||
All sessions will be preserved during the reload, except those which
|
||||
All connections will be preserved during the reload, except those which
|
||||
will lose NAT policy due to removal.
|
||||
NAT policy is determined by the translation type and address.
|
||||
Note that change of filter criteria will not expire associated sessions.
|
||||
Note that change of filter criteria will not expire associated connections.
|
||||
The reload operation (i.e., replacing the ruleset, NAT policies and tables)
|
||||
is atomic.
|
||||
.It Ic flush
|
||||
Flush configuration.
|
||||
That is, remove all rules, tables and expire all sessions.
|
||||
That is, remove all rules, tables and expire all connections.
|
||||
This command does not disable packet inspection.
|
||||
.It Ic show
|
||||
Show the current state and configuration.
|
||||
@ -137,20 +137,16 @@ List all entries in the currently loaded table specified by
|
||||
.Ar tid .
|
||||
This operation is expensive and should be used with caution.
|
||||
.\" ---
|
||||
.It Ic sess-save
|
||||
Save all active sessions.
|
||||
.It Ic save
|
||||
Save the active configuration and a spanshot of the current connections.
|
||||
The data will be stored in the
|
||||
.Pa /var/db/npf_sessions.db
|
||||
.Pa /var/db/npf.db
|
||||
file.
|
||||
Administrator may want to stop the packet inspection before the
|
||||
session saving.
|
||||
.It Ic sess-load
|
||||
Load saved sessions from the file.
|
||||
Note that original configuration should be loaded before the session loading.
|
||||
In a case of NAT policy changes, sessions which lose an associated policy
|
||||
will not be loaded.
|
||||
Any existing sessions during the load operation will be expired.
|
||||
Administrator may want to start packet inspection after the session loading.
|
||||
Administrator may want to stop the packet inspection before saving.
|
||||
.It Ic load
|
||||
Load the saved configuration file and the connections from the file.
|
||||
Note that any existing connections will be destroyed.
|
||||
Administrator may want to start packet inspection after the load.
|
||||
.It Ic stats
|
||||
Print various statistics.
|
||||
.It Ic debug
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* $NetBSD: npfctl.c,v 1.40 2013/11/12 00:46:34 rmind Exp $ */
|
||||
/* $NetBSD: npfctl.c,v 1.41 2014/07/23 01:25:34 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
|
||||
@ -30,7 +30,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: npfctl.c,v 1.40 2013/11/12 00:46:34 rmind Exp $");
|
||||
__RCSID("$NetBSD: npfctl.c,v 1.41 2014/07/23 01:25:34 rmind Exp $");
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
@ -60,8 +60,8 @@ enum {
|
||||
NPFCTL_TABLE,
|
||||
NPFCTL_RULE,
|
||||
NPFCTL_STATS,
|
||||
NPFCTL_SESSIONS_SAVE,
|
||||
NPFCTL_SESSIONS_LOAD,
|
||||
NPFCTL_SAVE,
|
||||
NPFCTL_LOAD,
|
||||
};
|
||||
|
||||
static const struct operations_s {
|
||||
@ -69,23 +69,23 @@ static const struct operations_s {
|
||||
int action;
|
||||
} operations[] = {
|
||||
/* Start, stop, reload */
|
||||
{ "start", NPFCTL_START },
|
||||
{ "stop", NPFCTL_STOP },
|
||||
{ "reload", NPFCTL_RELOAD },
|
||||
{ "show", NPFCTL_SHOWCONF, },
|
||||
{ "flush", NPFCTL_FLUSH },
|
||||
{ "valid", NPFCTL_VALIDATE },
|
||||
{ "start", NPFCTL_START },
|
||||
{ "stop", NPFCTL_STOP },
|
||||
{ "reload", NPFCTL_RELOAD },
|
||||
{ "show", NPFCTL_SHOWCONF, },
|
||||
{ "flush", NPFCTL_FLUSH },
|
||||
{ "valid", NPFCTL_VALIDATE },
|
||||
/* Table */
|
||||
{ "table", NPFCTL_TABLE },
|
||||
{ "table", NPFCTL_TABLE },
|
||||
/* Rule */
|
||||
{ "rule", NPFCTL_RULE },
|
||||
{ "rule", NPFCTL_RULE },
|
||||
/* Stats */
|
||||
{ "stats", NPFCTL_STATS },
|
||||
/* Sessions */
|
||||
{ "sess-save", NPFCTL_SESSIONS_SAVE },
|
||||
{ "sess-load", NPFCTL_SESSIONS_LOAD },
|
||||
{ "stats", NPFCTL_STATS },
|
||||
/* Full state save/load */
|
||||
{ "save", NPFCTL_SAVE },
|
||||
{ "load", NPFCTL_LOAD },
|
||||
/* --- */
|
||||
{ NULL, 0 }
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
bool
|
||||
@ -137,7 +137,7 @@ usage(void)
|
||||
"\t%s table <tid> { list | flush }\n",
|
||||
progname);
|
||||
fprintf(stderr,
|
||||
"\t%s sess-load | sess-save\n",
|
||||
"\t%s save | load\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -153,15 +153,15 @@ npfctl_print_stats(int fd)
|
||||
{ -1, "Packets passed" },
|
||||
{ NPF_STAT_PASS_DEFAULT, "default pass" },
|
||||
{ NPF_STAT_PASS_RULESET, "ruleset pass" },
|
||||
{ NPF_STAT_PASS_SESSION, "session pass" },
|
||||
{ NPF_STAT_PASS_CONN, "state pass" },
|
||||
|
||||
{ -1, "Packets blocked" },
|
||||
{ NPF_STAT_BLOCK_DEFAULT, "default block" },
|
||||
{ NPF_STAT_BLOCK_RULESET, "ruleset block" },
|
||||
|
||||
{ -1, "Session and NAT entries" },
|
||||
{ NPF_STAT_SESSION_CREATE, "session allocations" },
|
||||
{ NPF_STAT_SESSION_DESTROY, "session destructions" },
|
||||
{ -1, "State and NAT entries" },
|
||||
{ NPF_STAT_CONN_CREATE, "state allocations"},
|
||||
{ NPF_STAT_CONN_DESTROY, "state destructions"},
|
||||
{ NPF_STAT_NAT_CREATE, "NAT entry allocations" },
|
||||
{ NPF_STAT_NAT_DESTROY, "NAT entry destructions"},
|
||||
|
||||
@ -177,7 +177,7 @@ npfctl_print_stats(int fd)
|
||||
|
||||
{ -1, "Packet race cases" },
|
||||
{ NPF_STAT_RACE_NAT, "NAT association race" },
|
||||
{ NPF_STAT_RACE_SESSION, "duplicate session race"},
|
||||
{ NPF_STAT_RACE_CONN, "duplicate state race" },
|
||||
|
||||
{ -1, "Fragmentation" },
|
||||
{ NPF_STAT_FRAGMENTS, "fragments" },
|
||||
@ -480,6 +480,37 @@ npfctl_rule(int fd, int argc, char **argv)
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static int
|
||||
npfctl_save(int fd)
|
||||
{
|
||||
nl_config_t *ncf;
|
||||
bool active, loaded;
|
||||
int error;
|
||||
|
||||
ncf = npf_config_retrieve(fd, &active, &loaded);
|
||||
if (ncf == NULL) {
|
||||
return errno;
|
||||
}
|
||||
error = npf_config_export(ncf, NPF_DB_PATH);
|
||||
npf_config_destroy(ncf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
npfctl_load(int fd)
|
||||
{
|
||||
nl_config_t *ncf;
|
||||
int error;
|
||||
|
||||
ncf = npf_config_import(NPF_DB_PATH);
|
||||
if (ncf == NULL) {
|
||||
return errno;
|
||||
}
|
||||
error = npf_config_submit(ncf, fd);
|
||||
npf_config_destroy(ncf);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void
|
||||
npfctl(int action, int argc, char **argv)
|
||||
{
|
||||
@ -544,22 +575,18 @@ npfctl(int action, int argc, char **argv)
|
||||
argv += 2;
|
||||
npfctl_rule(fd, argc, argv);
|
||||
break;
|
||||
case NPFCTL_LOAD:
|
||||
ret = npfctl_load(fd);
|
||||
fun = "npfctl_config_load";
|
||||
break;
|
||||
case NPFCTL_SAVE:
|
||||
fd = npfctl_save(fd);
|
||||
fun = "npfctl_config_save";
|
||||
break;
|
||||
case NPFCTL_STATS:
|
||||
ret = npfctl_print_stats(fd);
|
||||
fun = "npfctl_print_stats";
|
||||
break;
|
||||
case NPFCTL_SESSIONS_SAVE:
|
||||
if (npf_sessions_recv(fd, NPF_SESSDB_PATH) != 0) {
|
||||
errx(EXIT_FAILURE, "could not save sessions to '%s'",
|
||||
NPF_SESSDB_PATH);
|
||||
}
|
||||
break;
|
||||
case NPFCTL_SESSIONS_LOAD:
|
||||
if (npf_sessions_send(fd, NPF_SESSDB_PATH) != 0) {
|
||||
errx(EXIT_FAILURE, "no sessions loaded from '%s'",
|
||||
NPF_SESSDB_PATH);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ret) {
|
||||
err(EXIT_FAILURE, "%s", fun);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npfctl.h,v 1.37 2014/05/15 02:34:29 rmind Exp $ */
|
||||
/* $NetBSD: npfctl.h,v 1.38 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
|
||||
@ -48,7 +48,7 @@
|
||||
|
||||
#define NPF_DEV_PATH "/dev/npf"
|
||||
#define NPF_CONF_PATH "/etc/npf.conf"
|
||||
#define NPF_SESSDB_PATH "/var/db/npf_sessions.db"
|
||||
#define NPF_DB_PATH "/var/db/npf.db"
|
||||
|
||||
typedef struct fam_addr_mask {
|
||||
sa_family_t fam_family;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_test_subr.c,v 1.9 2014/02/13 03:34:40 rmind Exp $ */
|
||||
/* $NetBSD: npf_test_subr.c,v 1.10 2014/07/23 01:25:34 rmind Exp $ */
|
||||
|
||||
/*
|
||||
* NPF initialisation and handler routines.
|
||||
@ -40,7 +40,7 @@ int
|
||||
npf_test_load(const void *xml)
|
||||
{
|
||||
prop_dictionary_t npf_dict = prop_dictionary_internalize(xml);
|
||||
return npfctl_reload(0, npf_dict);
|
||||
return npfctl_load(0, npf_dict);
|
||||
}
|
||||
|
||||
ifnet_t *
|
||||
|
Loading…
x
Reference in New Issue
Block a user