NPF checkpoint:
- Add support for session saving/restoring. - Add packet logging support (can tcpdump a pseudo-interface). - Support reload without flushing of sessions; rework some locking. - Revisit session mangement, replace linking with npf_sentry_t entries. - Add some counters for statistics, using percpu(9). - Add IP_DF flag cleansing. - Fix various bugs; misc clean-up.
This commit is contained in:
parent
3c8b71849f
commit
628e094cdc
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: Makefile,v 1.3 2010/11/11 06:30:39 rmind Exp $
|
# $NetBSD: Makefile,v 1.4 2010/12/18 01:07:26 rmind Exp $
|
||||||
|
|
||||||
.include "../Makefile.inc"
|
.include "../Makefile.inc"
|
||||||
|
|
||||||
|
@ -9,5 +9,6 @@ KMOD= npf
|
||||||
SRCS= npf.c npf_ctl.c npf_handler.c npf_instr.c npf_mbuf.c
|
SRCS= npf.c npf_ctl.c npf_handler.c npf_instr.c npf_mbuf.c
|
||||||
SRCS+= npf_processor.c npf_ruleset.c npf_tableset.c npf_inet.c
|
SRCS+= npf_processor.c npf_ruleset.c npf_tableset.c npf_inet.c
|
||||||
SRCS+= npf_session.c npf_state.c npf_nat.c npf_alg.c npf_sendpkt.c
|
SRCS+= npf_session.c npf_state.c npf_nat.c npf_alg.c npf_sendpkt.c
|
||||||
|
SRCS+= npf_log.c
|
||||||
|
|
||||||
.include <bsd.kmodule.mk>
|
.include <bsd.kmodule.mk>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: files.npf,v 1.3 2010/11/11 06:30:39 rmind Exp $
|
# $NetBSD: files.npf,v 1.4 2010/12/18 01:07:25 rmind Exp $
|
||||||
#
|
#
|
||||||
# Public Domain.
|
# Public Domain.
|
||||||
#
|
#
|
||||||
|
@ -24,6 +24,7 @@ file net/npf/npf_state.c npf
|
||||||
file net/npf/npf_nat.c npf
|
file net/npf/npf_nat.c npf
|
||||||
file net/npf/npf_alg.c npf
|
file net/npf/npf_alg.c npf
|
||||||
file net/npf/npf_sendpkt.c npf
|
file net/npf/npf_sendpkt.c npf
|
||||||
|
file net/npf/npf_log.c npf
|
||||||
|
|
||||||
# ALGs
|
# ALGs
|
||||||
file net/npf/npf_alg_icmp.c npf
|
file net/npf/npf_alg_icmp.c npf
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf.c,v 1.1 2010/08/22 18:56:22 rmind Exp $ */
|
/* $NetBSD: npf.c,v 1.2 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -34,15 +34,19 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.1 2010/08/22 18:56:22 rmind Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.2 2010/12/18 01:07:25 rmind Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <sys/atomic.h>
|
||||||
#include <sys/conf.h>
|
#include <sys/conf.h>
|
||||||
#include <sys/kauth.h>
|
#include <sys/kauth.h>
|
||||||
|
#include <sys/kmem.h>
|
||||||
#include <sys/lwp.h>
|
#include <sys/lwp.h>
|
||||||
#include <sys/module.h>
|
#include <sys/module.h>
|
||||||
|
#include <sys/percpu.h>
|
||||||
|
#include <sys/rwlock.h>
|
||||||
#include <sys/socketvar.h>
|
#include <sys/socketvar.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
@ -61,6 +65,19 @@ static int npf_dev_ioctl(dev_t, u_long, void *, int, lwp_t *);
|
||||||
static int npf_dev_poll(dev_t, int, lwp_t *);
|
static int npf_dev_poll(dev_t, int, lwp_t *);
|
||||||
static int npf_dev_read(dev_t, struct uio *, int);
|
static int npf_dev_read(dev_t, struct uio *, int);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
npf_ruleset_t * n_rules;
|
||||||
|
npf_tableset_t * n_tables;
|
||||||
|
npf_ruleset_t * n_nat_rules;
|
||||||
|
} npf_core_t;
|
||||||
|
|
||||||
|
static void npf_core_destroy(npf_core_t *);
|
||||||
|
static int npfctl_stats(void *);
|
||||||
|
|
||||||
|
static krwlock_t npf_lock __cacheline_aligned;
|
||||||
|
static npf_core_t * npf_core __cacheline_aligned;
|
||||||
|
static percpu_t * npf_stats_percpu __read_mostly;
|
||||||
|
|
||||||
const struct cdevsw npf_cdevsw = {
|
const struct cdevsw npf_cdevsw = {
|
||||||
npf_dev_open, npf_dev_close, npf_dev_read, nowrite, npf_dev_ioctl,
|
npf_dev_open, npf_dev_close, npf_dev_read, nowrite, npf_dev_ioctl,
|
||||||
nostop, notty, npf_dev_poll, nommap, nokqfilter, D_OTHER | D_MPSAFE
|
nostop, notty, npf_dev_poll, nommap, nokqfilter, D_OTHER | D_MPSAFE
|
||||||
|
@ -72,39 +89,31 @@ npf_init(void)
|
||||||
#ifdef _MODULE
|
#ifdef _MODULE
|
||||||
devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR;
|
devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR;
|
||||||
#endif
|
#endif
|
||||||
int error;
|
npf_ruleset_t *rset, *nset;
|
||||||
|
npf_tableset_t *tset;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
/*
|
rw_init(&npf_lock);
|
||||||
* Initialise ruleset, tables and session structures.
|
npf_stats_percpu = percpu_alloc(NPF_STATS_SIZE);
|
||||||
*/
|
npf_tableset_sysinit();
|
||||||
|
npf_session_sysinit();
|
||||||
error = npf_ruleset_sysinit();
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
error = npf_tableset_sysinit();
|
|
||||||
if (error) {
|
|
||||||
npf_ruleset_sysfini();
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = npf_session_sysinit();
|
|
||||||
if (error) {
|
|
||||||
npf_tableset_sysfini();
|
|
||||||
npf_ruleset_sysfini();
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
npf_nat_sysinit();
|
npf_nat_sysinit();
|
||||||
npf_alg_sysinit();
|
npf_alg_sysinit();
|
||||||
|
npflogattach(1);
|
||||||
|
|
||||||
|
/* Load empty configuration. */
|
||||||
|
rset = npf_ruleset_create();
|
||||||
|
tset = npf_tableset_create();
|
||||||
|
nset = npf_ruleset_create();
|
||||||
|
npf_reload(rset, tset, nset);
|
||||||
|
KASSERT(npf_core != NULL);
|
||||||
|
|
||||||
#ifdef _MODULE
|
#ifdef _MODULE
|
||||||
/* Attach /dev/npf device. */
|
/* Attach /dev/npf device. */
|
||||||
error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor);
|
error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor);
|
||||||
if (error) {
|
if (error) {
|
||||||
npf_nat_sysfini();
|
/* It will call devsw_detach(), which is safe. */
|
||||||
npf_session_sysfini();
|
(void)npf_fini();
|
||||||
npf_tableset_sysfini();
|
|
||||||
npf_ruleset_sysfini();
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return error;
|
return error;
|
||||||
|
@ -114,15 +123,24 @@ static int
|
||||||
npf_fini(void)
|
npf_fini(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At first, detach device, remove pfil hooks and unload existing
|
||||||
|
* configuration, destroy structures.
|
||||||
|
*/
|
||||||
#ifdef _MODULE
|
#ifdef _MODULE
|
||||||
/* At first, detach device and remove pfil hooks. */
|
|
||||||
devsw_detach(NULL, &npf_cdevsw);
|
devsw_detach(NULL, &npf_cdevsw);
|
||||||
#endif
|
#endif
|
||||||
|
npf_unregister_pfil();
|
||||||
|
npf_core_destroy(npf_core);
|
||||||
|
npflogdetach();
|
||||||
|
|
||||||
|
/* Note: order is particular. */
|
||||||
npf_nat_sysfini();
|
npf_nat_sysfini();
|
||||||
npf_alg_sysfini();
|
npf_alg_sysfini();
|
||||||
npf_session_sysfini();
|
npf_session_sysfini();
|
||||||
npf_tableset_sysfini();
|
npf_tableset_sysfini();
|
||||||
npf_ruleset_sysfini();
|
percpu_free(npf_stats_percpu, NPF_STATS_SIZE);
|
||||||
|
rw_destroy(&npf_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -194,6 +212,15 @@ npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
|
||||||
case IOC_NPF_TABLE:
|
case IOC_NPF_TABLE:
|
||||||
error = npfctl_table(data);
|
error = npfctl_table(data);
|
||||||
break;
|
break;
|
||||||
|
case IOC_NPF_STATS:
|
||||||
|
error = npfctl_stats(data);
|
||||||
|
break;
|
||||||
|
case IOC_NPF_SESSIONS_SAVE:
|
||||||
|
error = npfctl_sessions_save(cmd, data);
|
||||||
|
break;
|
||||||
|
case IOC_NPF_SESSIONS_LOAD:
|
||||||
|
error = npfctl_sessions_load(cmd, data);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error = ENOTTY;
|
error = ENOTTY;
|
||||||
break;
|
break;
|
||||||
|
@ -214,3 +241,137 @@ npf_dev_read(dev_t dev, struct uio *uio, int flag)
|
||||||
|
|
||||||
return ENOTSUP;
|
return ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NPF core loading/reloading/unloading mechanism.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
npf_core_destroy(npf_core_t *nc)
|
||||||
|
{
|
||||||
|
|
||||||
|
npf_tableset_destroy(nc->n_tables);
|
||||||
|
npf_ruleset_destroy(nc->n_rules);
|
||||||
|
npf_ruleset_destroy(nc->n_nat_rules);
|
||||||
|
kmem_free(nc, sizeof(npf_core_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* npf_reload: atomically load new ruleset, tableset and NAT policies.
|
||||||
|
* Then destroy old (unloaded) structures.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
npf_reload(npf_ruleset_t *rset, npf_tableset_t *tset, npf_ruleset_t *nset)
|
||||||
|
{
|
||||||
|
npf_core_t *nc, *onc;
|
||||||
|
|
||||||
|
/* Setup a new core structure. */
|
||||||
|
nc = kmem_alloc(sizeof(npf_core_t), KM_SLEEP);
|
||||||
|
nc->n_rules = rset;
|
||||||
|
nc->n_tables = tset;
|
||||||
|
nc->n_nat_rules = nset;
|
||||||
|
|
||||||
|
/* Lock and load the core structure. */
|
||||||
|
rw_enter(&npf_lock, RW_WRITER);
|
||||||
|
onc = atomic_swap_ptr(&npf_core, nc);
|
||||||
|
if (onc) {
|
||||||
|
/* Reload only necessary NAT policies. */
|
||||||
|
npf_ruleset_natreload(nset, onc->n_nat_rules);
|
||||||
|
}
|
||||||
|
/* Unlock. Everything goes "live" now. */
|
||||||
|
rw_exit(&npf_lock);
|
||||||
|
|
||||||
|
/* Turn on/off session tracking accordingly. */
|
||||||
|
npf_session_tracking(true);
|
||||||
|
|
||||||
|
if (onc) {
|
||||||
|
/* Destroy unloaded structures. */
|
||||||
|
npf_core_destroy(onc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
npf_core_enter(void)
|
||||||
|
{
|
||||||
|
rw_enter(&npf_lock, RW_READER);
|
||||||
|
}
|
||||||
|
|
||||||
|
npf_ruleset_t *
|
||||||
|
npf_core_ruleset(void)
|
||||||
|
{
|
||||||
|
KASSERT(rw_lock_held(&npf_lock));
|
||||||
|
return npf_core->n_rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
npf_ruleset_t *
|
||||||
|
npf_core_natset(void)
|
||||||
|
{
|
||||||
|
KASSERT(rw_lock_held(&npf_lock));
|
||||||
|
return npf_core->n_nat_rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
npf_tableset_t *
|
||||||
|
npf_core_tableset(void)
|
||||||
|
{
|
||||||
|
KASSERT(rw_lock_held(&npf_lock));
|
||||||
|
return npf_core->n_tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
npf_core_exit(void)
|
||||||
|
{
|
||||||
|
rw_exit(&npf_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
npf_core_locked(void)
|
||||||
|
{
|
||||||
|
return rw_lock_held(&npf_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NPF statistics interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
npf_stats_inc(npf_stats_t st)
|
||||||
|
{
|
||||||
|
uint64_t *stats = percpu_getref(npf_stats_percpu);
|
||||||
|
stats[st]++;
|
||||||
|
percpu_putref(npf_stats_percpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
npf_stats_dec(npf_stats_t st)
|
||||||
|
{
|
||||||
|
uint64_t *stats = percpu_getref(npf_stats_percpu);
|
||||||
|
stats[st]--;
|
||||||
|
percpu_putref(npf_stats_percpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
npf_stats_collect(void *mem, void *arg, struct cpu_info *ci)
|
||||||
|
{
|
||||||
|
uint64_t *percpu_stats = mem, *full_stats = arg;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NPF_STATS_COUNT; i++) {
|
||||||
|
full_stats[i] += percpu_stats[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* npfctl_stats: export collected statistics.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
npfctl_stats(void *data)
|
||||||
|
{
|
||||||
|
uint64_t *fullst, *uptr = *(uint64_t **)data;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
fullst = kmem_zalloc(NPF_STATS_SIZE, KM_SLEEP);
|
||||||
|
percpu_foreach(npf_stats_percpu, npf_stats_collect, fullst);
|
||||||
|
error = copyout(fullst, uptr, NPF_STATS_SIZE);
|
||||||
|
kmem_free(fullst, NPF_STATS_SIZE);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf.h,v 1.4 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf.h,v 1.5 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -98,9 +98,8 @@ typedef struct in6_addr npf_addr_t;
|
||||||
#define NPC_IP46 (NPC_IP4|NPC_IP6)
|
#define NPC_IP46 (NPC_IP4|NPC_IP6)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* Information flags and packet direction. */
|
/* Information flags. */
|
||||||
uint32_t npc_info;
|
uint32_t npc_info;
|
||||||
int npc_di;
|
|
||||||
/* Pointers to the IP v4/v6 addresses. */
|
/* Pointers to the IP v4/v6 addresses. */
|
||||||
npf_addr_t * npc_srcip;
|
npf_addr_t * npc_srcip;
|
||||||
npf_addr_t * npc_dstip;
|
npf_addr_t * npc_dstip;
|
||||||
|
@ -147,7 +146,7 @@ int nbuf_add_tag(nbuf_t *, uint32_t, uint32_t);
|
||||||
int nbuf_find_tag(nbuf_t *, uint32_t, void **);
|
int nbuf_find_tag(nbuf_t *, uint32_t, void **);
|
||||||
|
|
||||||
/* Ruleset interface. */
|
/* Ruleset interface. */
|
||||||
npf_rule_t * npf_rule_alloc(int, pri_t, int, void *, size_t, bool, int, int);
|
npf_rule_t * npf_rule_alloc(prop_dictionary_t, void *, size_t);
|
||||||
void npf_rule_free(npf_rule_t *);
|
void npf_rule_free(npf_rule_t *);
|
||||||
void npf_activate_rule(npf_rule_t *);
|
void npf_activate_rule(npf_rule_t *);
|
||||||
void npf_deactivate_rule(npf_rule_t *);
|
void npf_deactivate_rule(npf_rule_t *);
|
||||||
|
@ -206,6 +205,33 @@ typedef struct npf_ioctl_table {
|
||||||
int _reserved;
|
int _reserved;
|
||||||
} npf_ioctl_table_t;
|
} npf_ioctl_table_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* Packets passed. */
|
||||||
|
NPF_STAT_PASS_DEFAULT,
|
||||||
|
NPF_STAT_PASS_RULESET,
|
||||||
|
NPF_STAT_PASS_SESSION,
|
||||||
|
/* Packets blocked. */
|
||||||
|
NPF_STAT_BLOCK_DEFAULT,
|
||||||
|
NPF_STAT_BLOCK_RULESET,
|
||||||
|
/* Session and NAT entries. */
|
||||||
|
NPF_STAT_SESSION_CREATE,
|
||||||
|
NPF_STAT_SESSION_DESTROY,
|
||||||
|
NPF_STAT_NAT_CREATE,
|
||||||
|
NPF_STAT_NAT_DESTROY,
|
||||||
|
/* Invalid state cases. */
|
||||||
|
NPF_STAT_INVALID_STATE,
|
||||||
|
NPF_STAT_INVALID_STATE_TCP1,
|
||||||
|
NPF_STAT_INVALID_STATE_TCP2,
|
||||||
|
NPF_STAT_INVALID_STATE_TCP3,
|
||||||
|
/* Raced packets. */
|
||||||
|
NPF_STAT_RACE_SESSION,
|
||||||
|
NPF_STAT_RACE_NAT,
|
||||||
|
/* Count (last). */
|
||||||
|
NPF_STATS_COUNT
|
||||||
|
} npf_stats_t;
|
||||||
|
|
||||||
|
#define NPF_STATS_SIZE (sizeof(uint64_t) * NPF_STATS_COUNT)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IOCTL operations.
|
* IOCTL operations.
|
||||||
*/
|
*/
|
||||||
|
@ -214,5 +240,8 @@ typedef struct npf_ioctl_table {
|
||||||
#define IOC_NPF_SWITCH _IOW('N', 101, int)
|
#define IOC_NPF_SWITCH _IOW('N', 101, int)
|
||||||
#define IOC_NPF_RELOAD _IOW('N', 102, struct plistref)
|
#define IOC_NPF_RELOAD _IOW('N', 102, struct plistref)
|
||||||
#define IOC_NPF_TABLE _IOW('N', 103, struct npf_ioctl_table)
|
#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)
|
||||||
|
|
||||||
#endif /* _NPF_H_ */
|
#endif /* _NPF_H_ */
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_alg_icmp.c,v 1.4 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_alg_icmp.c,v 1.5 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.4 2010/11/11 06:30:39 rmind Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.5 2010/12/18 01:07:25 rmind Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
|
@ -151,7 +151,7 @@ npfa_icmp_match(npf_cache_t *npc, nbuf_t *nbuf, void *ntptr)
|
||||||
* npf_icmp_uniqid: retrieve unique identifiers - either ICMP query ID
|
* npf_icmp_uniqid: retrieve unique identifiers - either ICMP query ID
|
||||||
* or TCP/UDP ports of the original packet, which is embedded.
|
* or TCP/UDP ports of the original packet, which is embedded.
|
||||||
*/
|
*/
|
||||||
static inline bool
|
static bool
|
||||||
npf_icmp_uniqid(const int type, npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
|
npf_icmp_uniqid(const int type, npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
|
||||||
{
|
{
|
||||||
struct icmp *ic;
|
struct icmp *ic;
|
||||||
|
@ -252,7 +252,7 @@ npfa_icmp_session(npf_cache_t *npc, nbuf_t *nbuf, void *keyptr)
|
||||||
*/
|
*/
|
||||||
KASSERT(npf_iscached(key, NPC_IP46));
|
KASSERT(npf_iscached(key, NPC_IP46));
|
||||||
KASSERT(npf_iscached(key, NPC_LAYER4));
|
KASSERT(npf_iscached(key, NPC_LAYER4));
|
||||||
key->npc_di = (npc->npc_di == PFIL_IN) ? PFIL_OUT : PFIL_IN;
|
key->npc_ipsz = npc->npc_ipsz;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_ctl.c,v 1.3 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_ctl.c,v 1.4 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -34,13 +34,10 @@
|
||||||
*
|
*
|
||||||
* Implementation of (re)loading, construction of tables and rules.
|
* Implementation of (re)loading, construction of tables and rules.
|
||||||
* NPF proplib(9) dictionary consumer.
|
* NPF proplib(9) dictionary consumer.
|
||||||
*
|
|
||||||
* TODO:
|
|
||||||
* - Consider implementing 'sync' functionality.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.3 2010/11/11 06:30:39 rmind Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.4 2010/12/18 01:07:25 rmind Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/conf.h>
|
#include <sys/conf.h>
|
||||||
|
@ -84,9 +81,6 @@ npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
it = prop_array_iterator(tables);
|
it = prop_array_iterator(tables);
|
||||||
if (it == NULL)
|
|
||||||
return ENOMEM;
|
|
||||||
|
|
||||||
while ((tbldict = prop_object_iterator_next(it)) != NULL) {
|
while ((tbldict = prop_object_iterator_next(it)) != NULL) {
|
||||||
prop_dictionary_t ent;
|
prop_dictionary_t ent;
|
||||||
prop_object_iterator_t eit;
|
prop_object_iterator_t eit;
|
||||||
|
@ -127,10 +121,6 @@ npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
eit = prop_array_iterator(entries);
|
eit = prop_array_iterator(entries);
|
||||||
if (eit == NULL) {
|
|
||||||
error = ENOMEM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while ((ent = prop_object_iterator_next(eit)) != NULL) {
|
while ((ent = prop_object_iterator_next(eit)) != NULL) {
|
||||||
in_addr_t addr, mask; /* XXX: IPv6 */
|
in_addr_t addr, mask; /* XXX: IPv6 */
|
||||||
|
|
||||||
|
@ -151,46 +141,17 @@ npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables)
|
||||||
}
|
}
|
||||||
prop_object_iterator_release(it);
|
prop_object_iterator_release(it);
|
||||||
/*
|
/*
|
||||||
* Note: in a case of error, caller will free entire tableset.
|
* Note: in a case of error, caller will free the tableset.
|
||||||
*/
|
*/
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
|
||||||
npf_mk_ncode(const void *ncptr, size_t nc_size)
|
|
||||||
{
|
|
||||||
int npf_err, errat;
|
|
||||||
void *nc;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate and copy n-code.
|
|
||||||
*
|
|
||||||
* XXX: Inefficient; consider extending proplib(9) to provide
|
|
||||||
* interface for custom allocator and avoid copy.
|
|
||||||
*/
|
|
||||||
nc = npf_ncode_alloc(nc_size);
|
|
||||||
if (nc == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memcpy(nc, ncptr, nc_size);
|
|
||||||
npf_err = npf_ncode_validate(nc, nc_size, &errat);
|
|
||||||
if (npf_err) {
|
|
||||||
npf_ncode_free(nc, nc_size);
|
|
||||||
/* TODO: return error details via proplib */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return nc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
npf_mk_singlerule(prop_dictionary_t rldict,
|
npf_mk_singlerule(prop_dictionary_t rldict,
|
||||||
npf_ruleset_t *rlset, npf_rule_t **parent)
|
npf_ruleset_t *rlset, npf_rule_t **parent)
|
||||||
{
|
{
|
||||||
npf_rule_t *rl;
|
npf_rule_t *rl;
|
||||||
prop_object_t obj;
|
prop_object_t obj;
|
||||||
int attr, ifidx, minttl, maxmss;
|
|
||||||
pri_t pri;
|
|
||||||
bool rnd_ipid;
|
|
||||||
size_t nc_size;
|
size_t nc_size;
|
||||||
void *nc;
|
void *nc;
|
||||||
|
|
||||||
|
@ -198,45 +159,31 @@ npf_mk_singlerule(prop_dictionary_t rldict,
|
||||||
if (prop_object_type(rldict) != PROP_TYPE_DICTIONARY)
|
if (prop_object_type(rldict) != PROP_TYPE_DICTIONARY)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
/* Attributes (integer). */
|
|
||||||
obj = prop_dictionary_get(rldict, "attributes");
|
|
||||||
attr = prop_number_integer_value(obj);
|
|
||||||
|
|
||||||
/* Priority (integer). */
|
|
||||||
obj = prop_dictionary_get(rldict, "priority");
|
|
||||||
pri = prop_number_integer_value(obj);
|
|
||||||
|
|
||||||
/* Interface ID (integer). */
|
|
||||||
obj = prop_dictionary_get(rldict, "interface");
|
|
||||||
ifidx = prop_number_integer_value(obj);
|
|
||||||
|
|
||||||
/* Randomize IP ID (bool). */
|
|
||||||
obj = prop_dictionary_get(rldict, "randomize-id");
|
|
||||||
rnd_ipid = prop_bool_true(obj);
|
|
||||||
|
|
||||||
/* Minimum IP TTL (integer). */
|
|
||||||
obj = prop_dictionary_get(rldict, "min-ttl");
|
|
||||||
minttl = prop_number_integer_value(obj);
|
|
||||||
|
|
||||||
/* Maximum TCP MSS (integer). */
|
|
||||||
obj = prop_dictionary_get(rldict, "max-mss");
|
|
||||||
maxmss = prop_number_integer_value(obj);
|
|
||||||
|
|
||||||
/* N-code (binary data). */
|
/* N-code (binary data). */
|
||||||
obj = prop_dictionary_get(rldict, "ncode");
|
obj = prop_dictionary_get(rldict, "ncode");
|
||||||
if (obj) {
|
if (obj) {
|
||||||
const void *ncptr;
|
const void *ncptr;
|
||||||
|
int npf_err, errat;
|
||||||
|
|
||||||
/* Perform n-code validation. */
|
/*
|
||||||
nc_size = prop_data_size(obj);
|
* Allocate, copy and validate n-code. XXX: Inefficient.
|
||||||
|
*/
|
||||||
ncptr = prop_data_data_nocopy(obj);
|
ncptr = prop_data_data_nocopy(obj);
|
||||||
|
nc_size = prop_data_size(obj);
|
||||||
if (ncptr == NULL || nc_size > NPF_NCODE_LIMIT) {
|
if (ncptr == NULL || nc_size > NPF_NCODE_LIMIT) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
nc = npf_mk_ncode(ncptr, nc_size);
|
nc = npf_ncode_alloc(nc_size);
|
||||||
if (nc == NULL) {
|
if (nc == NULL) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
memcpy(nc, ncptr, nc_size);
|
||||||
|
npf_err = npf_ncode_validate(nc, nc_size, &errat);
|
||||||
|
if (npf_err) {
|
||||||
|
npf_ncode_free(nc, nc_size);
|
||||||
|
/* TODO: return error details via proplib */
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* No n-code. */
|
/* No n-code. */
|
||||||
nc = NULL;
|
nc = NULL;
|
||||||
|
@ -244,8 +191,7 @@ npf_mk_singlerule(prop_dictionary_t rldict,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate and setup NPF rule. */
|
/* Allocate and setup NPF rule. */
|
||||||
rl = npf_rule_alloc(attr, pri, ifidx, nc, nc_size,
|
rl = npf_rule_alloc(rldict, nc, nc_size);
|
||||||
rnd_ipid, minttl, maxmss);
|
|
||||||
if (rl == NULL) {
|
if (rl == NULL) {
|
||||||
if (nc) {
|
if (nc) {
|
||||||
npf_ncode_free(nc, nc_size); /* XXX */
|
npf_ncode_free(nc, nc_size); /* XXX */
|
||||||
|
@ -270,11 +216,8 @@ npf_mk_rules(npf_ruleset_t *rlset, prop_array_t rules)
|
||||||
if (prop_object_type(rules) != PROP_TYPE_ARRAY)
|
if (prop_object_type(rules) != PROP_TYPE_ARRAY)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
it = prop_array_iterator(rules);
|
|
||||||
if (it == NULL)
|
|
||||||
return ENOMEM;
|
|
||||||
|
|
||||||
error = 0;
|
error = 0;
|
||||||
|
it = prop_array_iterator(rules);
|
||||||
while ((rldict = prop_object_iterator_next(it)) != NULL) {
|
while ((rldict = prop_object_iterator_next(it)) != NULL) {
|
||||||
prop_object_iterator_t sit;
|
prop_object_iterator_t sit;
|
||||||
prop_array_t subrules;
|
prop_array_t subrules;
|
||||||
|
@ -298,10 +241,6 @@ npf_mk_rules(npf_ruleset_t *rlset, prop_array_t rules)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sit = prop_array_iterator(subrules);
|
sit = prop_array_iterator(subrules);
|
||||||
if (sit == NULL) {
|
|
||||||
error = ENOMEM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while ((srldict = prop_object_iterator_next(sit)) != NULL) {
|
while ((srldict = prop_object_iterator_next(sit)) != NULL) {
|
||||||
/* For subrule, pass ruleset pointer of parent. */
|
/* For subrule, pass ruleset pointer of parent. */
|
||||||
error = npf_mk_singlerule(srldict,
|
error = npf_mk_singlerule(srldict,
|
||||||
|
@ -315,7 +254,7 @@ npf_mk_rules(npf_ruleset_t *rlset, prop_array_t rules)
|
||||||
}
|
}
|
||||||
prop_object_iterator_release(it);
|
prop_object_iterator_release(it);
|
||||||
/*
|
/*
|
||||||
* Note: in a case of error, caller will free entire ruleset.
|
* Note: in a case of error, caller will free the ruleset.
|
||||||
*/
|
*/
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -331,19 +270,11 @@ npf_mk_natlist(npf_ruleset_t *nset, prop_array_t natlist)
|
||||||
if (prop_object_type(natlist) != PROP_TYPE_ARRAY)
|
if (prop_object_type(natlist) != PROP_TYPE_ARRAY)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
it = prop_array_iterator(natlist);
|
|
||||||
if (it == NULL)
|
|
||||||
return ENOMEM;
|
|
||||||
|
|
||||||
error = 0;
|
error = 0;
|
||||||
|
it = prop_array_iterator(natlist);
|
||||||
while ((natdict = prop_object_iterator_next(it)) != NULL) {
|
while ((natdict = prop_object_iterator_next(it)) != NULL) {
|
||||||
prop_object_t obj;
|
|
||||||
npf_natpolicy_t *np;
|
npf_natpolicy_t *np;
|
||||||
npf_rule_t *rl;
|
npf_rule_t *rl;
|
||||||
const npf_addr_t *taddr;
|
|
||||||
size_t taddr_sz;
|
|
||||||
in_port_t tport;
|
|
||||||
int type, flags;
|
|
||||||
|
|
||||||
/* NAT policy - dictionary. */
|
/* NAT policy - dictionary. */
|
||||||
if (prop_object_type(natdict) != PROP_TYPE_DICTIONARY) {
|
if (prop_object_type(natdict) != PROP_TYPE_DICTIONARY) {
|
||||||
|
@ -351,23 +282,6 @@ npf_mk_natlist(npf_ruleset_t *nset, prop_array_t natlist)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Translation type. */
|
|
||||||
obj = prop_dictionary_get(natdict, "type");
|
|
||||||
type = prop_number_integer_value(obj);
|
|
||||||
|
|
||||||
/* Translation type. */
|
|
||||||
obj = prop_dictionary_get(natdict, "flags");
|
|
||||||
flags = prop_number_integer_value(obj);
|
|
||||||
|
|
||||||
/* Translation IP. */
|
|
||||||
obj = prop_dictionary_get(natdict, "translation-ip");
|
|
||||||
taddr_sz = prop_data_size(obj);
|
|
||||||
taddr = (const npf_addr_t *)prop_data_data_nocopy(obj);
|
|
||||||
|
|
||||||
/* Translation port (for redirect case). */
|
|
||||||
obj = prop_dictionary_get(natdict, "translation-port");
|
|
||||||
tport = (in_port_t)prop_number_integer_value(obj);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NAT policies are standard rules, plus additional
|
* NAT policies are standard rules, plus additional
|
||||||
* information for translation. Make a rule.
|
* information for translation. Make a rule.
|
||||||
|
@ -377,8 +291,9 @@ npf_mk_natlist(npf_ruleset_t *nset, prop_array_t natlist)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Allocate a new NAT policy and assign to the rule. */
|
/* Allocate a new NAT policy and assign to the rule. */
|
||||||
np = npf_nat_newpolicy(type, flags, taddr, taddr_sz, tport);
|
np = npf_nat_newpolicy(natdict);
|
||||||
if (np == NULL) {
|
if (np == NULL) {
|
||||||
|
npf_rule_free(rl);
|
||||||
error = ENOMEM;
|
error = ENOMEM;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -405,7 +320,6 @@ npfctl_reload(u_long cmd, void *data)
|
||||||
npf_ruleset_t *nset = NULL;
|
npf_ruleset_t *nset = NULL;
|
||||||
prop_dictionary_t dict;
|
prop_dictionary_t dict;
|
||||||
prop_array_t natlist, tables, rules;
|
prop_array_t natlist, tables, rules;
|
||||||
prop_object_t ver;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
/* Retrieve the dictionary. */
|
/* Retrieve the dictionary. */
|
||||||
|
@ -418,16 +332,6 @@ npfctl_reload(u_long cmd, void *data)
|
||||||
if (dict == NULL)
|
if (dict == NULL)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
#endif
|
#endif
|
||||||
/* Version. */
|
|
||||||
ver = prop_dictionary_get(dict, "version");
|
|
||||||
if (ver == NULL || prop_number_integer_value(ver) != NPF_VERSION) {
|
|
||||||
error = EINVAL;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX: Hard way for now. */
|
|
||||||
(void)npf_session_tracking(false);
|
|
||||||
|
|
||||||
/* NAT policies. */
|
/* NAT policies. */
|
||||||
nset = npf_ruleset_create();
|
nset = npf_ruleset_create();
|
||||||
natlist = prop_dictionary_get(dict, "translation");
|
natlist = prop_dictionary_get(dict, "translation");
|
||||||
|
@ -449,16 +353,11 @@ npfctl_reload(u_long cmd, void *data)
|
||||||
if (error)
|
if (error)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* Flush and reload NAT policies. */
|
|
||||||
npf_nat_reload(nset);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finally, reload the ruleset. It will also reload the tableset.
|
* Finally - reload ruleset, tableset and NAT policies.
|
||||||
* Operation will be performed as a single transaction.
|
* Operation will be performed as a single transaction.
|
||||||
*/
|
*/
|
||||||
npf_ruleset_reload(rlset, tblset);
|
npf_reload(rlset, tblset, nset);
|
||||||
|
|
||||||
(void)npf_session_tracking(true);
|
|
||||||
|
|
||||||
/* Done. Since data is consumed now, we shall not destroy it. */
|
/* Done. Since data is consumed now, we shall not destroy it. */
|
||||||
tblset = NULL;
|
tblset = NULL;
|
||||||
|
@ -482,6 +381,110 @@ fail:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* npfctl_sessions_save: construct a list of sessions and export for saving.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
npfctl_sessions_save(u_long cmd, void *data)
|
||||||
|
{
|
||||||
|
struct plistref *pref = data;
|
||||||
|
prop_dictionary_t sesdict;
|
||||||
|
prop_array_t selist, nplist;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Create a dictionary and two lists. */
|
||||||
|
sesdict = prop_dictionary_create();
|
||||||
|
selist = prop_array_create();
|
||||||
|
nplist = prop_array_create();
|
||||||
|
|
||||||
|
/* Save the sessions. */
|
||||||
|
error = npf_session_save(selist, nplist);
|
||||||
|
if (error) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the session list, NAT policy list and export the dictionary. */
|
||||||
|
prop_dictionary_set(sesdict, "session-list", selist);
|
||||||
|
prop_dictionary_set(sesdict, "nat-policy-list", nplist);
|
||||||
|
#ifdef _KERNEL
|
||||||
|
error = prop_dictionary_copyout_ioctl(pref, cmd, sesdict);
|
||||||
|
#else
|
||||||
|
error = prop_dictionary_externalize_to_file(sesdict, data) ? 0 : errno;
|
||||||
|
#endif
|
||||||
|
fail:
|
||||||
|
prop_object_release(sesdict);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* npfctl_sessions_load: import a list of sessions, reconstruct them and load.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
npfctl_sessions_load(u_long cmd, void *data)
|
||||||
|
{
|
||||||
|
const struct plistref *pref = data;
|
||||||
|
npf_sehash_t *sehasht = NULL;
|
||||||
|
prop_dictionary_t sesdict, sedict;
|
||||||
|
prop_object_iterator_t it;
|
||||||
|
prop_array_t selist;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Retrieve the dictionary containing session and NAT policy lists. */
|
||||||
|
#ifdef _KERNEL
|
||||||
|
error = prop_dictionary_copyin_ioctl(pref, cmd, &sesdict);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
#else
|
||||||
|
sesdict = prop_dictionary_internalize_from_file(data);
|
||||||
|
if (sesdict == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Note: session objects contain the references to the NAT policy
|
||||||
|
* entries. Therefore, no need to directly access it.
|
||||||
|
*/
|
||||||
|
selist = prop_dictionary_get(sesdict, "session-list");
|
||||||
|
if (prop_object_type(selist) != PROP_TYPE_ARRAY) {
|
||||||
|
error = EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a session hash table. */
|
||||||
|
sehasht = sess_htable_create();
|
||||||
|
if (sehasht == NULL) {
|
||||||
|
error = ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iterate through and construct each session.
|
||||||
|
*/
|
||||||
|
error = 0;
|
||||||
|
it = prop_array_iterator(selist);
|
||||||
|
npf_core_enter();
|
||||||
|
while ((sedict = prop_object_iterator_next(it)) != NULL) {
|
||||||
|
/* Session - dictionary. */
|
||||||
|
if (prop_object_type(sedict) != PROP_TYPE_DICTIONARY) {
|
||||||
|
error = EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
/* Construct and insert real session structure. */
|
||||||
|
error = npf_session_restore(sehasht, sedict);
|
||||||
|
if (error) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
npf_core_exit();
|
||||||
|
sess_htable_reload(sehasht);
|
||||||
|
fail:
|
||||||
|
prop_object_release(selist);
|
||||||
|
if (error && sehasht) {
|
||||||
|
/* Destroy session table. */
|
||||||
|
sess_htable_destroy(sehasht);
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* npfctl_table: add, remove or query entries in the specified table.
|
* npfctl_table: add, remove or query entries in the specified table.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_handler.c,v 1.4 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_handler.c,v 1.5 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.4 2010/11/11 06:30:39 rmind Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.5 2010/12/18 01:07:25 rmind Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
|
@ -84,7 +84,7 @@ npf_packet_handler(void *arg, struct mbuf **mp, struct ifnet *ifp, int di)
|
||||||
npf_cache_t npc;
|
npf_cache_t npc;
|
||||||
npf_session_t *se;
|
npf_session_t *se;
|
||||||
npf_rule_t *rl;
|
npf_rule_t *rl;
|
||||||
bool keepstate;
|
npf_rproc_t *rp;
|
||||||
int retfl, error;
|
int retfl, error;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -94,6 +94,7 @@ npf_packet_handler(void *arg, struct mbuf **mp, struct ifnet *ifp, int di)
|
||||||
npc.npc_info = 0;
|
npc.npc_info = 0;
|
||||||
error = 0;
|
error = 0;
|
||||||
retfl = 0;
|
retfl = 0;
|
||||||
|
rp = NULL;
|
||||||
|
|
||||||
/* Cache everything. Determine whether it is an IPv4 fragment. */
|
/* Cache everything. Determine whether it is an IPv4 fragment. */
|
||||||
if (npf_cache_all(&npc, nbuf) && npf_iscached(&npc, NPC_IPFRAG)) {
|
if (npf_cache_all(&npc, nbuf) && npf_iscached(&npc, NPC_IPFRAG)) {
|
||||||
|
@ -119,7 +120,8 @@ npf_packet_handler(void *arg, struct mbuf **mp, struct ifnet *ifp, int di)
|
||||||
se = npf_session_inspect(&npc, nbuf, di);
|
se = npf_session_inspect(&npc, nbuf, di);
|
||||||
|
|
||||||
/* If "passing" session found - skip the ruleset inspection. */
|
/* If "passing" session found - skip the ruleset inspection. */
|
||||||
if (se && npf_session_pass(se)) {
|
if (se && npf_session_pass(se, &rp)) {
|
||||||
|
npf_stats_inc(NPF_STAT_PASS_SESSION);
|
||||||
goto pass;
|
goto pass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,29 +129,44 @@ npf_packet_handler(void *arg, struct mbuf **mp, struct ifnet *ifp, int di)
|
||||||
rl = npf_ruleset_inspect(&npc, nbuf, ifp, di, NPF_LAYER_3);
|
rl = npf_ruleset_inspect(&npc, nbuf, ifp, di, NPF_LAYER_3);
|
||||||
if (rl == NULL) {
|
if (rl == NULL) {
|
||||||
if (default_pass) {
|
if (default_pass) {
|
||||||
|
npf_stats_inc(NPF_STAT_PASS_DEFAULT);
|
||||||
goto pass;
|
goto pass;
|
||||||
}
|
}
|
||||||
|
npf_stats_inc(NPF_STAT_BLOCK_DEFAULT);
|
||||||
error = ENETUNREACH;
|
error = ENETUNREACH;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply the rule. */
|
/* Apply the rule. */
|
||||||
error = npf_rule_apply(&npc, nbuf, rl, &keepstate, &retfl);
|
error = npf_rule_apply(&npc, nbuf, rl, &retfl);
|
||||||
if (error) {
|
if (error) {
|
||||||
|
npf_stats_inc(NPF_STAT_BLOCK_RULESET);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
npf_stats_inc(NPF_STAT_PASS_RULESET);
|
||||||
|
|
||||||
/* Establish a "pass" session, if required. */
|
/* Establish a "pass" session, if required. */
|
||||||
if (keepstate && !se) {
|
if ((retfl & NPF_RULE_KEEPSTATE) != 0 && !se) {
|
||||||
se = npf_session_establish(&npc, nbuf, NULL, di);
|
se = npf_session_establish(&npc, nbuf, di);
|
||||||
if (se == NULL) {
|
if (se == NULL) {
|
||||||
error = ENOMEM;
|
error = ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
npf_session_setpass(se);
|
/* Associate rule processing data (XXX locking). */
|
||||||
|
rp = npf_rproc_return(rl);
|
||||||
|
npf_session_setpass(se, rp);
|
||||||
|
} else {
|
||||||
|
/* XXX: Return rule processing, needs locking. */
|
||||||
}
|
}
|
||||||
pass:
|
pass:
|
||||||
KASSERT(error == 0);
|
KASSERT(error == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform rule processing, if required.
|
||||||
|
*/
|
||||||
|
if (rp) {
|
||||||
|
npf_rproc_run(&npc, nbuf, rp);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Perform NAT.
|
* Perform NAT.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_impl.h,v 1.4 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_impl.h,v 1.5 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -57,16 +57,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct npf_nat;
|
struct npf_nat;
|
||||||
|
struct npf_rproc;
|
||||||
struct npf_session;
|
struct npf_session;
|
||||||
|
|
||||||
typedef struct npf_nat npf_nat_t;
|
typedef struct npf_nat npf_nat_t;
|
||||||
|
typedef struct npf_rproc npf_rproc_t;
|
||||||
typedef struct npf_alg npf_alg_t;
|
typedef struct npf_alg npf_alg_t;
|
||||||
typedef struct npf_natpolicy npf_natpolicy_t;
|
typedef struct npf_natpolicy npf_natpolicy_t;
|
||||||
typedef struct npf_session npf_session_t;
|
typedef struct npf_session npf_session_t;
|
||||||
|
|
||||||
|
struct npf_sehash;
|
||||||
struct npf_tblent;
|
struct npf_tblent;
|
||||||
struct npf_table;
|
struct npf_table;
|
||||||
|
|
||||||
|
typedef struct npf_sehash npf_sehash_t;
|
||||||
typedef struct npf_tblent npf_tblent_t;
|
typedef struct npf_tblent npf_tblent_t;
|
||||||
typedef struct npf_table npf_table_t;
|
typedef struct npf_table npf_table_t;
|
||||||
|
|
||||||
|
@ -76,11 +80,12 @@ typedef npf_table_t * npf_tableset_t;
|
||||||
* DEFINITIONS.
|
* DEFINITIONS.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef bool (*npf_algfunc_t)(npf_cache_t *, nbuf_t *, void *);
|
typedef bool (*npf_algfunc_t)(npf_cache_t *, nbuf_t *, void *);
|
||||||
|
|
||||||
#define NPF_NCODE_LIMIT 1024
|
#define NPF_NCODE_LIMIT 1024
|
||||||
#define NPF_TABLE_SLOTS 32
|
#define NPF_TABLE_SLOTS 32
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SESSION STATE STRUCTURES
|
* SESSION STATE STRUCTURES
|
||||||
*/
|
*/
|
||||||
|
@ -88,7 +93,7 @@ typedef bool (*npf_algfunc_t)(npf_cache_t *, nbuf_t *, void *);
|
||||||
#define ST_OPENING 1 /* SYN has been sent. */
|
#define ST_OPENING 1 /* SYN has been sent. */
|
||||||
#define ST_ACKNOWLEDGE 2 /* SYN-ACK received, wait for ACK. */
|
#define ST_ACKNOWLEDGE 2 /* SYN-ACK received, wait for ACK. */
|
||||||
#define ST_ESTABLISHED 3 /* ACK seen, connection established. */
|
#define ST_ESTABLISHED 3 /* ACK seen, connection established. */
|
||||||
#define ST_CLOSING 4
|
#define ST_CLOSING 4 /* FIN or RST seen. */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t nst_seqend; /* SEQ number + length. */
|
uint32_t nst_seqend; /* SEQ number + length. */
|
||||||
|
@ -107,14 +112,30 @@ typedef struct {
|
||||||
* INTERFACES.
|
* INTERFACES.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* NPF control. */
|
/* NPF control, statistics, etc. */
|
||||||
|
void npf_core_enter(void);
|
||||||
|
npf_ruleset_t * npf_core_ruleset(void);
|
||||||
|
npf_ruleset_t * npf_core_natset(void);
|
||||||
|
npf_tableset_t *npf_core_tableset(void);
|
||||||
|
void npf_core_exit(void);
|
||||||
|
bool npf_core_locked(void);
|
||||||
|
void npf_reload(npf_ruleset_t *, npf_tableset_t *, npf_ruleset_t *);
|
||||||
|
|
||||||
|
void npflogattach(int);
|
||||||
|
void npflogdetach(void);
|
||||||
int npfctl_switch(void *);
|
int npfctl_switch(void *);
|
||||||
int npfctl_reload(u_long, void *);
|
int npfctl_reload(u_long, void *);
|
||||||
|
int npfctl_sessions_save(u_long, void *);
|
||||||
|
int npfctl_sessions_load(u_long, void *);
|
||||||
int npfctl_table(void *);
|
int npfctl_table(void *);
|
||||||
|
|
||||||
|
void npf_stats_inc(npf_stats_t);
|
||||||
|
void npf_stats_dec(npf_stats_t);
|
||||||
|
|
||||||
/* Packet filter hooks. */
|
/* Packet filter hooks. */
|
||||||
int npf_register_pfil(void);
|
int npf_register_pfil(void);
|
||||||
void npf_unregister_pfil(void);
|
void npf_unregister_pfil(void);
|
||||||
|
void npf_log_packet(npf_cache_t *, nbuf_t *, int);
|
||||||
|
|
||||||
/* Protocol helpers. */
|
/* Protocol helpers. */
|
||||||
bool npf_fetch_ip(npf_cache_t *, nbuf_t *, void *);
|
bool npf_fetch_ip(npf_cache_t *, nbuf_t *, void *);
|
||||||
|
@ -137,7 +158,7 @@ uint32_t npf_addr_sum(const int, const npf_addr_t *, const npf_addr_t *);
|
||||||
int npf_tcpsaw(npf_cache_t *, tcp_seq *, tcp_seq *, uint32_t *);
|
int npf_tcpsaw(npf_cache_t *, tcp_seq *, tcp_seq *, uint32_t *);
|
||||||
bool npf_fetch_tcpopts(const npf_cache_t *, nbuf_t *,
|
bool npf_fetch_tcpopts(const npf_cache_t *, nbuf_t *,
|
||||||
uint16_t *, int *);
|
uint16_t *, int *);
|
||||||
bool npf_normalize(npf_cache_t *, nbuf_t *, bool, u_int, u_int);
|
bool npf_normalize(npf_cache_t *, nbuf_t *, bool, bool, u_int, u_int);
|
||||||
void npf_return_block(npf_cache_t *, nbuf_t *, const int);
|
void npf_return_block(npf_cache_t *, nbuf_t *, const int);
|
||||||
|
|
||||||
/* Complex instructions. */
|
/* Complex instructions. */
|
||||||
|
@ -154,7 +175,7 @@ int npf_match_icmp4(npf_cache_t *, nbuf_t *, void *, uint32_t);
|
||||||
int npf_match_tcpfl(npf_cache_t *, nbuf_t *, void *, uint32_t);
|
int npf_match_tcpfl(npf_cache_t *, nbuf_t *, void *, uint32_t);
|
||||||
|
|
||||||
/* Tableset interface. */
|
/* Tableset interface. */
|
||||||
int npf_tableset_sysinit(void);
|
void npf_tableset_sysinit(void);
|
||||||
void npf_tableset_sysfini(void);
|
void npf_tableset_sysfini(void);
|
||||||
|
|
||||||
npf_tableset_t *npf_tableset_create(void);
|
npf_tableset_t *npf_tableset_create(void);
|
||||||
|
@ -177,39 +198,48 @@ int npf_table_rem_v4cidr(npf_tableset_t *, u_int,
|
||||||
int npf_table_match_v4addr(u_int, in_addr_t);
|
int npf_table_match_v4addr(u_int, in_addr_t);
|
||||||
|
|
||||||
/* Ruleset interface. */
|
/* Ruleset interface. */
|
||||||
int npf_ruleset_sysinit(void);
|
|
||||||
void npf_ruleset_sysfini(void);
|
|
||||||
|
|
||||||
npf_ruleset_t * npf_ruleset_create(void);
|
npf_ruleset_t * npf_ruleset_create(void);
|
||||||
void npf_ruleset_destroy(npf_ruleset_t *);
|
void npf_ruleset_destroy(npf_ruleset_t *);
|
||||||
void npf_ruleset_insert(npf_ruleset_t *, npf_rule_t *);
|
void npf_ruleset_insert(npf_ruleset_t *, npf_rule_t *);
|
||||||
void npf_ruleset_reload(npf_ruleset_t *, npf_tableset_t *);
|
void npf_ruleset_natreload(npf_ruleset_t *, npf_ruleset_t *);
|
||||||
|
npf_rule_t * npf_ruleset_matchnat(npf_ruleset_t *, npf_natpolicy_t *);
|
||||||
|
|
||||||
npf_rule_t * npf_ruleset_match(npf_ruleset_t *, npf_cache_t *, nbuf_t *,
|
npf_rule_t * npf_ruleset_match(npf_ruleset_t *, npf_cache_t *, nbuf_t *,
|
||||||
struct ifnet *, const int, const int);
|
struct ifnet *, const int, const int);
|
||||||
npf_rule_t * npf_ruleset_inspect(npf_cache_t *, nbuf_t *,
|
npf_rule_t * npf_ruleset_inspect(npf_cache_t *, nbuf_t *,
|
||||||
struct ifnet *, const int, const int);
|
struct ifnet *, const int, const int);
|
||||||
int npf_rule_apply(npf_cache_t *, nbuf_t *, npf_rule_t *,
|
int npf_rule_apply(npf_cache_t *, nbuf_t *, npf_rule_t *, int *);
|
||||||
bool *, int *);
|
|
||||||
npf_ruleset_t * npf_rule_subset(npf_rule_t *);
|
|
||||||
|
|
||||||
|
npf_ruleset_t * npf_rule_subset(npf_rule_t *);
|
||||||
npf_natpolicy_t *npf_rule_getnat(const npf_rule_t *);
|
npf_natpolicy_t *npf_rule_getnat(const npf_rule_t *);
|
||||||
void npf_rule_setnat(npf_rule_t *, npf_natpolicy_t *);
|
void npf_rule_setnat(npf_rule_t *, npf_natpolicy_t *);
|
||||||
|
|
||||||
|
npf_rproc_t * npf_rproc_create(prop_dictionary_t);
|
||||||
|
npf_rproc_t * npf_rproc_return(npf_rule_t *);
|
||||||
|
void npf_rproc_release(npf_rproc_t *);
|
||||||
|
void npf_rproc_run(npf_cache_t *, nbuf_t *, npf_rproc_t *);
|
||||||
|
|
||||||
/* Session handling interface. */
|
/* Session handling interface. */
|
||||||
int npf_session_sysinit(void);
|
void npf_session_sysinit(void);
|
||||||
void npf_session_sysfini(void);
|
void npf_session_sysfini(void);
|
||||||
int npf_session_tracking(bool);
|
int npf_session_tracking(bool);
|
||||||
|
|
||||||
|
npf_sehash_t * sess_htable_create(void);
|
||||||
|
void sess_htable_destroy(npf_sehash_t *);
|
||||||
|
void sess_htable_reload(npf_sehash_t *);
|
||||||
|
|
||||||
npf_session_t * npf_session_inspect(npf_cache_t *, nbuf_t *, const int);
|
npf_session_t * npf_session_inspect(npf_cache_t *, nbuf_t *, const int);
|
||||||
npf_session_t * npf_session_establish(const npf_cache_t *, nbuf_t *,
|
npf_session_t * npf_session_establish(const npf_cache_t *, nbuf_t *, const int);
|
||||||
npf_nat_t *, const int);
|
|
||||||
void npf_session_release(npf_session_t *);
|
void npf_session_release(npf_session_t *);
|
||||||
bool npf_session_pass(const npf_session_t *);
|
void npf_session_expire(npf_session_t *);
|
||||||
void npf_session_setpass(npf_session_t *);
|
bool npf_session_pass(const npf_session_t *, npf_rproc_t **);
|
||||||
void npf_session_link(npf_session_t *, npf_session_t *);
|
void npf_session_setpass(npf_session_t *, npf_rproc_t *);
|
||||||
|
int npf_session_setnat(npf_session_t *, npf_nat_t *, const int);
|
||||||
npf_nat_t * npf_session_retnat(npf_session_t *, const int, bool *);
|
npf_nat_t * npf_session_retnat(npf_session_t *, const int, bool *);
|
||||||
|
|
||||||
|
int npf_session_save(prop_array_t, prop_array_t);
|
||||||
|
int npf_session_restore(npf_sehash_t *, prop_dictionary_t);
|
||||||
|
|
||||||
/* State handling. */
|
/* State handling. */
|
||||||
bool npf_state_init(const npf_cache_t *, nbuf_t *, npf_state_t *);
|
bool npf_state_init(const npf_cache_t *, nbuf_t *, npf_state_t *);
|
||||||
bool npf_state_inspect(const npf_cache_t *, nbuf_t *, npf_state_t *,
|
bool npf_state_inspect(const npf_cache_t *, nbuf_t *, npf_state_t *,
|
||||||
|
@ -220,18 +250,20 @@ void npf_state_destroy(npf_state_t *);
|
||||||
/* NAT. */
|
/* NAT. */
|
||||||
void npf_nat_sysinit(void);
|
void npf_nat_sysinit(void);
|
||||||
void npf_nat_sysfini(void);
|
void npf_nat_sysfini(void);
|
||||||
npf_natpolicy_t *npf_nat_newpolicy(int, int, const npf_addr_t *, size_t,
|
npf_natpolicy_t *npf_nat_newpolicy(prop_dictionary_t);
|
||||||
in_port_t);
|
|
||||||
void npf_nat_freepolicy(npf_natpolicy_t *);
|
void npf_nat_freepolicy(npf_natpolicy_t *);
|
||||||
void npf_nat_flush(void);
|
bool npf_nat_matchpolicy(npf_natpolicy_t *, npf_natpolicy_t *);
|
||||||
void npf_nat_reload(npf_ruleset_t *);
|
|
||||||
|
|
||||||
int npf_do_nat(npf_cache_t *, npf_session_t *, nbuf_t *,
|
int npf_do_nat(npf_cache_t *, npf_session_t *, nbuf_t *,
|
||||||
struct ifnet *, const int);
|
struct ifnet *, const int);
|
||||||
void npf_nat_expire(npf_nat_t *);
|
void npf_nat_expire(npf_nat_t *);
|
||||||
void npf_nat_getorig(npf_nat_t *, npf_addr_t **, in_port_t *);
|
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);
|
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_session_t *);
|
||||||
|
|
||||||
/* ALG interface. */
|
/* ALG interface. */
|
||||||
void npf_alg_sysinit(void);
|
void npf_alg_sysinit(void);
|
||||||
void npf_alg_sysfini(void);
|
void npf_alg_sysfini(void);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_inet.c,v 1.4 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_inet.c,v 1.5 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.4 2010/11/11 06:30:39 rmind Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.5 2010/12/18 01:07:25 rmind Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
|
@ -112,6 +112,8 @@ npf_addr_sum(const int sz, const npf_addr_t *a1, const npf_addr_t *a2)
|
||||||
uint32_t mix = 0;
|
uint32_t mix = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
KASSERT(sz > 0 && a1 != NULL && a2 != NULL);
|
||||||
|
|
||||||
for (i = 0; i < (sz >> 2); i++) {
|
for (i = 0; i < (sz >> 2); i++) {
|
||||||
mix += a1->s6_addr32[i];
|
mix += a1->s6_addr32[i];
|
||||||
mix += a2->s6_addr32[i];
|
mix += a2->s6_addr32[i];
|
||||||
|
@ -524,15 +526,17 @@ npf_rwrcksum(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const int di,
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
npf_normalize_ip4(npf_cache_t *npc, nbuf_t *nbuf, bool rnd, int minttl)
|
npf_normalize_ip4(npf_cache_t *npc, nbuf_t *nbuf,
|
||||||
|
bool rnd, bool no_df, int minttl)
|
||||||
{
|
{
|
||||||
void *n_ptr = nbuf_dataptr(nbuf);
|
void *n_ptr = nbuf_dataptr(nbuf);
|
||||||
struct ip *ip = &npc->npc_ip.v4;
|
struct ip *ip = &npc->npc_ip.v4;
|
||||||
uint16_t cksum = ip->ip_sum;
|
uint16_t cksum = ip->ip_sum;
|
||||||
|
uint16_t ip_off = ip->ip_off;
|
||||||
uint8_t ttl = ip->ip_ttl;
|
uint8_t ttl = ip->ip_ttl;
|
||||||
u_int offby = 0;
|
u_int offby = 0;
|
||||||
|
|
||||||
KASSERT(rnd || minttl);
|
KASSERT(rnd || minttl || no_df);
|
||||||
|
|
||||||
/* Randomize IPv4 ID. */
|
/* Randomize IPv4 ID. */
|
||||||
if (rnd) {
|
if (rnd) {
|
||||||
|
@ -547,6 +551,20 @@ npf_normalize_ip4(npf_cache_t *npc, nbuf_t *nbuf, bool rnd, int minttl)
|
||||||
ip->ip_id = nid;
|
ip->ip_id = nid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* IP_DF flag cleansing. */
|
||||||
|
if (no_df && (ip_off & htons(IP_DF)) != 0) {
|
||||||
|
uint16_t nip_off = ip_off & ~htons(IP_DF);
|
||||||
|
|
||||||
|
if (nbuf_advstore(&nbuf, &n_ptr,
|
||||||
|
offsetof(struct ip, ip_off) - offby,
|
||||||
|
sizeof(uint8_t), &nip_off)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cksum = npf_fixup16_cksum(cksum, ip_off, nip_off);
|
||||||
|
ip->ip_off = nip_off;
|
||||||
|
offby = offsetof(struct ip, ip_off);
|
||||||
|
}
|
||||||
|
|
||||||
/* Enforce minimum TTL. */
|
/* Enforce minimum TTL. */
|
||||||
if (minttl && ttl < minttl) {
|
if (minttl && ttl < minttl) {
|
||||||
if (nbuf_advstore(&nbuf, &n_ptr,
|
if (nbuf_advstore(&nbuf, &n_ptr,
|
||||||
|
@ -570,7 +588,7 @@ npf_normalize_ip4(npf_cache_t *npc, nbuf_t *nbuf, bool rnd, int minttl)
|
||||||
|
|
||||||
bool
|
bool
|
||||||
npf_normalize(npf_cache_t *npc, nbuf_t *nbuf,
|
npf_normalize(npf_cache_t *npc, nbuf_t *nbuf,
|
||||||
bool rnd, u_int minttl, u_int maxmss)
|
bool no_df, bool rnd, u_int minttl, u_int maxmss)
|
||||||
{
|
{
|
||||||
void *n_ptr = nbuf_dataptr(nbuf);
|
void *n_ptr = nbuf_dataptr(nbuf);
|
||||||
struct ip *ip = &npc->npc_ip.v4;
|
struct ip *ip = &npc->npc_ip.v4;
|
||||||
|
@ -580,7 +598,7 @@ npf_normalize(npf_cache_t *npc, nbuf_t *nbuf,
|
||||||
|
|
||||||
/* Normalize IPv4. */
|
/* Normalize IPv4. */
|
||||||
if (npf_iscached(npc, NPC_IP4) && (rnd || minttl)) {
|
if (npf_iscached(npc, NPC_IP4) && (rnd || minttl)) {
|
||||||
if (!npf_normalize_ip4(npc, nbuf, rnd, minttl)) {
|
if (!npf_normalize_ip4(npc, nbuf, rnd, no_df, minttl)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
/* $NetBSD: npf_log.c,v 1.1 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This material is based upon work partially supported by The
|
||||||
|
* NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NPF logging interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__KERNEL_RCSID(0, "$NetBSD: npf_log.c,v 1.1 2010/12/18 01:07:25 rmind Exp $");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/kmem.h>
|
||||||
|
#include <sys/mbuf.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_types.h>
|
||||||
|
#include <net/bpf.h>
|
||||||
|
|
||||||
|
#include "npf_impl.h"
|
||||||
|
|
||||||
|
typedef struct npflog_softc {
|
||||||
|
LIST_ENTRY(npflog_softc) sc_entry;
|
||||||
|
kmutex_t sc_lock;
|
||||||
|
struct ifnet sc_if;
|
||||||
|
int sc_unit;
|
||||||
|
} npflog_softc_t;
|
||||||
|
|
||||||
|
static int npflog_clone_create(struct if_clone *, int );
|
||||||
|
static int npflog_clone_destroy(struct ifnet *);
|
||||||
|
|
||||||
|
static LIST_HEAD(, npflog_softc) npflog_if_list __cacheline_aligned;
|
||||||
|
static struct if_clone npflog_cloner =
|
||||||
|
IF_CLONE_INITIALIZER("npflog", npflog_clone_create, npflog_clone_destroy);
|
||||||
|
|
||||||
|
void
|
||||||
|
npflogattach(int nunits)
|
||||||
|
{
|
||||||
|
|
||||||
|
LIST_INIT(&npflog_if_list);
|
||||||
|
if_clone_attach(&npflog_cloner);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
npflogdetach(void)
|
||||||
|
{
|
||||||
|
npflog_softc_t *sc;
|
||||||
|
|
||||||
|
while ((sc = LIST_FIRST(&npflog_if_list)) != NULL) {
|
||||||
|
npflog_clone_destroy(&sc->sc_if);
|
||||||
|
}
|
||||||
|
if_clone_detach(&npflog_cloner);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
npflog_ioctl(struct ifnet *ifp, u_long cmd, void *data)
|
||||||
|
{
|
||||||
|
npflog_softc_t *sc = ifp->if_softc;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
mutex_enter(&sc->sc_lock);
|
||||||
|
switch (cmd) {
|
||||||
|
case SIOCINITIFADDR:
|
||||||
|
ifp->if_flags |= (IFF_UP | IFF_RUNNING);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error = ifioctl_common(ifp, cmd, data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mutex_exit(&sc->sc_lock);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
npflog_clone_create(struct if_clone *ifc, int unit)
|
||||||
|
{
|
||||||
|
npflog_softc_t *sc;
|
||||||
|
struct ifnet *ifp;
|
||||||
|
|
||||||
|
sc = kmem_zalloc(sizeof(npflog_softc_t), KM_SLEEP);
|
||||||
|
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTNET);
|
||||||
|
|
||||||
|
ifp = &sc->sc_if;
|
||||||
|
ifp->if_softc = sc;
|
||||||
|
|
||||||
|
if_initname(ifp, "npflog", unit);
|
||||||
|
ifp->if_type = IFT_OTHER;
|
||||||
|
ifp->if_dlt = DLT_NULL;
|
||||||
|
ifp->if_ioctl = npflog_ioctl;
|
||||||
|
|
||||||
|
if_attach(ifp);
|
||||||
|
if_alloc_sadl(ifp);
|
||||||
|
bpf_attach(ifp, DLT_NULL, 0);
|
||||||
|
|
||||||
|
LIST_INSERT_HEAD(&npflog_if_list, sc, sc_entry);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
npflog_clone_destroy(struct ifnet *ifp)
|
||||||
|
{
|
||||||
|
npflog_softc_t *sc = ifp->if_softc;
|
||||||
|
|
||||||
|
LIST_REMOVE(sc, sc_entry);
|
||||||
|
bpf_detach(ifp);
|
||||||
|
if_detach(ifp);
|
||||||
|
mutex_destroy(&sc->sc_lock);
|
||||||
|
kmem_free(sc, sizeof(npflog_softc_t));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
npf_log_packet(npf_cache_t *npc, nbuf_t *nbuf, int ifidx)
|
||||||
|
{
|
||||||
|
struct mbuf *m = nbuf;
|
||||||
|
npflog_softc_t *sc;
|
||||||
|
struct ifnet *ifp;
|
||||||
|
int family;
|
||||||
|
|
||||||
|
KASSERT(m != NULL);
|
||||||
|
|
||||||
|
/* Lookup for a pseudo-interface to log. */
|
||||||
|
LIST_FOREACH(sc, &npflog_if_list, sc_entry) {
|
||||||
|
ifp = &sc->sc_if;
|
||||||
|
if (ifp->if_index != ifidx) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Set the address family. */
|
||||||
|
if (npf_iscached(npc, NPC_IP4)) {
|
||||||
|
family = AF_INET;
|
||||||
|
} else if (npf_iscached(npc, NPC_IP6)) {
|
||||||
|
family = AF_INET6;
|
||||||
|
} else {
|
||||||
|
family = AF_UNSPEC;
|
||||||
|
}
|
||||||
|
/* Pass through BPF. */
|
||||||
|
KERNEL_LOCK(1, NULL);
|
||||||
|
ifp->if_opackets++;
|
||||||
|
ifp->if_obytes += m->m_pkthdr.len;
|
||||||
|
bpf_mtap_af(ifp, family, m);
|
||||||
|
KERNEL_UNLOCK_ONE(NULL);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_nat.c,v 1.3 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_nat.c,v 1.4 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -64,26 +64,28 @@
|
||||||
* the IP addresses, therefore multiple NAT policies with the same IP
|
* the IP addresses, therefore multiple NAT policies with the same IP
|
||||||
* will share the same port map.
|
* will share the same port map.
|
||||||
*
|
*
|
||||||
* NAT sessions and translation entries
|
* Sessions, translation entries and their life-cycle
|
||||||
*
|
*
|
||||||
* NAT module relies on session management module. Each "NAT" session
|
* NAT module relies on session management module. Each translated
|
||||||
* has an associated translation entry (npf_nat_t). It contains saved
|
* session has an associated translation entry (npf_nat_t), which
|
||||||
* i.e. original IP address with port and translation port, allocated
|
* contains information used for backwards stream translation, i.e.
|
||||||
* from the port map. Each NAT translation entry is associated with
|
* original IP address with port and translation port, allocated from
|
||||||
* the policy, which contains translation IP address. Allocated port
|
* the port map. Each NAT entry is associated with the policy, which
|
||||||
* is returned to the port map and translation entry destroyed when
|
* contains translation IP address. Allocated port is returned to the
|
||||||
* "NAT" session expires.
|
* port map and NAT entry is destroyed when session expires.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.3 2010/11/11 06:30:39 rmind Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.4 2010/12/18 01:07:25 rmind Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
|
|
||||||
#include <sys/atomic.h>
|
#include <sys/atomic.h>
|
||||||
#include <sys/bitops.h>
|
#include <sys/bitops.h>
|
||||||
|
#include <sys/condvar.h>
|
||||||
#include <sys/kmem.h>
|
#include <sys/kmem.h>
|
||||||
|
#include <sys/mutex.h>
|
||||||
#include <sys/pool.h>
|
#include <sys/pool.h>
|
||||||
#include <net/pfil.h>
|
#include <net/pfil.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
@ -94,44 +96,53 @@ __KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.3 2010/11/11 06:30:39 rmind Exp $");
|
||||||
* NPF portmap structure.
|
* NPF portmap structure.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u_int p_refcnt;
|
u_int p_refcnt;
|
||||||
uint32_t p_bitmap[0];
|
uint32_t p_bitmap[0];
|
||||||
} npf_portmap_t;
|
} npf_portmap_t;
|
||||||
|
|
||||||
/* Portmap range: [ 1024 .. 65535 ] */
|
/* Portmap range: [ 1024 .. 65535 ] */
|
||||||
#define PORTMAP_FIRST (1024)
|
#define PORTMAP_FIRST (1024)
|
||||||
#define PORTMAP_SIZE ((65536 - PORTMAP_FIRST) / 32)
|
#define PORTMAP_SIZE ((65536 - PORTMAP_FIRST) / 32)
|
||||||
#define PORTMAP_FILLED ((uint32_t)~0)
|
#define PORTMAP_FILLED ((uint32_t)~0)
|
||||||
#define PORTMAP_MASK (31)
|
#define PORTMAP_MASK (31)
|
||||||
#define PORTMAP_SHIFT (5)
|
#define PORTMAP_SHIFT (5)
|
||||||
|
|
||||||
|
#define PORTMAP_MEM_SIZE \
|
||||||
|
(sizeof(npf_portmap_t) + (PORTMAP_SIZE * sizeof(uint32_t)))
|
||||||
|
|
||||||
/* NAT policy structure. */
|
/* NAT policy structure. */
|
||||||
struct npf_natpolicy {
|
struct npf_natpolicy {
|
||||||
LIST_ENTRY(npf_natpolicy) n_entry;
|
LIST_HEAD(, npf_nat) n_nat_list;
|
||||||
int n_type;
|
kmutex_t n_lock;
|
||||||
int n_flags;
|
kcondvar_t n_cv;
|
||||||
npf_portmap_t * n_portmap;
|
npf_portmap_t * n_portmap;
|
||||||
size_t n_addr_sz;
|
int n_type;
|
||||||
npf_addr_t n_taddr;
|
int n_flags;
|
||||||
in_port_t n_tport;
|
size_t n_addr_sz;
|
||||||
|
npf_addr_t n_taddr;
|
||||||
|
in_port_t n_tport;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define NPF_NP_CMP_START offsetof(npf_natpolicy_t, n_type)
|
||||||
|
#define NPF_NP_CMP_SIZE (sizeof(npf_natpolicy_t) - NPF_NP_CMP_START)
|
||||||
|
|
||||||
/* NAT translation entry for a session. */
|
/* NAT translation entry for a session. */
|
||||||
struct npf_nat {
|
struct npf_nat {
|
||||||
npf_natpolicy_t * nt_natpolicy;
|
/* Association (list entry and a link pointer) with NAT policy. */
|
||||||
|
LIST_ENTRY(npf_nat) nt_entry;
|
||||||
|
npf_natpolicy_t * nt_natpolicy;
|
||||||
|
npf_session_t * nt_session;
|
||||||
/* Original address and port (for backwards translation). */
|
/* Original address and port (for backwards translation). */
|
||||||
npf_addr_t nt_oaddr;
|
npf_addr_t nt_oaddr;
|
||||||
in_port_t nt_oport;
|
in_port_t nt_oport;
|
||||||
/* Translation port (for redirects). */
|
/* Translation port (for redirects). */
|
||||||
in_port_t nt_tport;
|
in_port_t nt_tport;
|
||||||
/* ALG (if any) associated with this NAT entry. */
|
/* ALG (if any) associated with this NAT entry. */
|
||||||
npf_alg_t * nt_alg;
|
npf_alg_t * nt_alg;
|
||||||
uintptr_t nt_alg_arg;
|
uintptr_t nt_alg_arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
static npf_ruleset_t * nat_ruleset __read_mostly;
|
static pool_cache_t nat_cache __read_mostly;
|
||||||
static LIST_HEAD(, npf_natpolicy) nat_policy_list __read_mostly;
|
|
||||||
static pool_cache_t nat_cache __read_mostly;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* npf_nat_sys{init,fini}: initialise/destroy NAT subsystem structures.
|
* npf_nat_sys{init,fini}: initialise/destroy NAT subsystem structures.
|
||||||
|
@ -144,17 +155,13 @@ npf_nat_sysinit(void)
|
||||||
nat_cache = pool_cache_init(sizeof(npf_nat_t), coherency_unit,
|
nat_cache = pool_cache_init(sizeof(npf_nat_t), coherency_unit,
|
||||||
0, 0, "npfnatpl", NULL, IPL_NET, NULL, NULL, NULL);
|
0, 0, "npfnatpl", NULL, IPL_NET, NULL, NULL, NULL);
|
||||||
KASSERT(nat_cache != NULL);
|
KASSERT(nat_cache != NULL);
|
||||||
nat_ruleset = npf_ruleset_create();
|
|
||||||
LIST_INIT(&nat_policy_list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
npf_nat_sysfini(void)
|
npf_nat_sysfini(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Flush NAT policies. */
|
/* NAT policies should already be destroyed. */
|
||||||
npf_nat_reload(NULL);
|
|
||||||
KASSERT(LIST_EMPTY(&nat_policy_list));
|
|
||||||
pool_cache_destroy(nat_cache);
|
pool_cache_destroy(nat_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,29 +172,46 @@ npf_nat_sysfini(void)
|
||||||
* => XXX: serialise at upper layer.
|
* => XXX: serialise at upper layer.
|
||||||
*/
|
*/
|
||||||
npf_natpolicy_t *
|
npf_natpolicy_t *
|
||||||
npf_nat_newpolicy(int type, int flags, const npf_addr_t *taddr,
|
npf_nat_newpolicy(prop_dictionary_t natdict)
|
||||||
size_t addr_sz, in_port_t tport)
|
|
||||||
{
|
{
|
||||||
npf_natpolicy_t *np, *it;
|
npf_natpolicy_t *np/*, *it */;
|
||||||
|
const npf_addr_t *taddr;
|
||||||
|
prop_object_t obj;
|
||||||
npf_portmap_t *pm;
|
npf_portmap_t *pm;
|
||||||
|
|
||||||
np = kmem_zalloc(sizeof(npf_natpolicy_t), KM_SLEEP);
|
np = kmem_zalloc(sizeof(npf_natpolicy_t), KM_SLEEP);
|
||||||
if (np == NULL) {
|
mutex_init(&np->n_lock, MUTEX_DEFAULT, IPL_SOFTNET);
|
||||||
return NULL;
|
cv_init(&np->n_cv, "npfnatcv");
|
||||||
}
|
LIST_INIT(&np->n_nat_list);
|
||||||
KASSERT(type == NPF_NATIN || type == NPF_NATOUT);
|
|
||||||
np->n_type = type;
|
/* Translation type. */
|
||||||
np->n_flags = flags;
|
obj = prop_dictionary_get(natdict, "type");
|
||||||
np->n_addr_sz = addr_sz;
|
np->n_type = prop_number_integer_value(obj);
|
||||||
memcpy(&np->n_taddr, taddr, sizeof(npf_addr_t));
|
|
||||||
np->n_tport = tport;
|
/* Translation type. */
|
||||||
|
obj = prop_dictionary_get(natdict, "flags");
|
||||||
|
np->n_flags = prop_number_integer_value(obj);
|
||||||
|
|
||||||
|
/* Translation IP. */
|
||||||
|
obj = prop_dictionary_get(natdict, "translation-ip");
|
||||||
|
np->n_addr_sz = prop_data_size(obj);
|
||||||
|
KASSERT(np->n_addr_sz > 0 && np->n_addr_sz <= sizeof(npf_addr_t));
|
||||||
|
taddr = (const npf_addr_t *)prop_data_data_nocopy(obj);
|
||||||
|
memcpy(&np->n_taddr, taddr, np->n_addr_sz);
|
||||||
|
|
||||||
|
/* Translation port (for redirect case). */
|
||||||
|
obj = prop_dictionary_get(natdict, "translation-port");
|
||||||
|
np->n_tport = (in_port_t)prop_number_integer_value(obj);
|
||||||
|
|
||||||
|
KASSERT(np->n_type == NPF_NATIN || np->n_type == NPF_NATOUT);
|
||||||
|
|
||||||
pm = NULL;
|
pm = NULL;
|
||||||
if ((flags & NPF_NAT_PORTMAP) == 0) {
|
if ((np->n_flags & NPF_NAT_PORTMAP) == 0) {
|
||||||
goto nopm;
|
goto nopm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search for a NAT policy using the same translation address. */
|
/* Search for a NAT policy using the same translation address. */
|
||||||
|
#if 0
|
||||||
LIST_FOREACH(it, &nat_policy_list, n_entry) {
|
LIST_FOREACH(it, &nat_policy_list, n_entry) {
|
||||||
if (memcmp(&it->n_taddr, &np->n_taddr, sizeof(npf_addr_t))) {
|
if (memcmp(&it->n_taddr, &np->n_taddr, sizeof(npf_addr_t))) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -195,10 +219,12 @@ npf_nat_newpolicy(int type, int flags, const npf_addr_t *taddr,
|
||||||
pm = it->n_portmap;
|
pm = it->n_portmap;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
pm = NULL;
|
||||||
|
#endif
|
||||||
if (pm == NULL) {
|
if (pm == NULL) {
|
||||||
/* Allocate a new port map for the NAT policy. */
|
/* Allocate a new port map for the NAT policy. */
|
||||||
pm = kmem_zalloc(sizeof(npf_portmap_t) +
|
pm = kmem_zalloc(PORTMAP_MEM_SIZE, KM_SLEEP);
|
||||||
(PORTMAP_SIZE * sizeof(uint32_t)), KM_SLEEP);
|
|
||||||
if (pm == NULL) {
|
if (pm == NULL) {
|
||||||
kmem_free(np, sizeof(npf_natpolicy_t));
|
kmem_free(np, sizeof(npf_natpolicy_t));
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -211,46 +237,53 @@ npf_nat_newpolicy(int type, int flags, const npf_addr_t *taddr,
|
||||||
}
|
}
|
||||||
nopm:
|
nopm:
|
||||||
np->n_portmap = pm;
|
np->n_portmap = pm;
|
||||||
/*
|
|
||||||
* Note: old policies with new might co-exist in the list,
|
|
||||||
* while reload is in progress, but that is not an issue.
|
|
||||||
*/
|
|
||||||
LIST_INSERT_HEAD(&nat_policy_list, np, n_entry);
|
|
||||||
return np;
|
return np;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* npf_nat_freepolicy: free NAT policy and, on last reference, free portmap.
|
* npf_nat_freepolicy: free NAT policy and, on last reference, free portmap.
|
||||||
*
|
*
|
||||||
* => Called from npf_rule_free() during the reload via npf_nat_reload().
|
* => Called from npf_rule_free() during the reload via npf_ruleset_destroy().
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
npf_nat_freepolicy(npf_natpolicy_t *np)
|
npf_nat_freepolicy(npf_natpolicy_t *np)
|
||||||
{
|
{
|
||||||
npf_portmap_t *pm = np->n_portmap;
|
npf_portmap_t *pm = np->n_portmap;
|
||||||
|
npf_nat_t *nt;
|
||||||
|
|
||||||
LIST_REMOVE(np, n_entry);
|
/* De-associate all entries from the policy. */
|
||||||
|
mutex_enter(&np->n_lock);
|
||||||
|
LIST_FOREACH(nt, &np->n_nat_list, nt_entry) {
|
||||||
|
if (nt->nt_session == NULL) { /* XXXSMP */
|
||||||
|
npf_session_expire(nt->nt_session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!LIST_EMPTY(&np->n_nat_list)) {
|
||||||
|
cv_wait(&np->n_cv, &np->n_lock);
|
||||||
|
}
|
||||||
|
mutex_exit(&np->n_lock);
|
||||||
|
|
||||||
|
/* Destroy the port map, on last reference. */
|
||||||
if (pm && --pm->p_refcnt == 0) {
|
if (pm && --pm->p_refcnt == 0) {
|
||||||
KASSERT((np->n_flags & NPF_NAT_PORTMAP) != 0);
|
KASSERT((np->n_flags & NPF_NAT_PORTMAP) != 0);
|
||||||
kmem_free(pm, sizeof(npf_portmap_t) +
|
kmem_free(pm, PORTMAP_MEM_SIZE);
|
||||||
(PORTMAP_SIZE * sizeof(uint32_t)));
|
|
||||||
}
|
}
|
||||||
|
cv_destroy(&np->n_cv);
|
||||||
|
mutex_destroy(&np->n_lock);
|
||||||
kmem_free(np, sizeof(npf_natpolicy_t));
|
kmem_free(np, sizeof(npf_natpolicy_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
bool
|
||||||
* npf_nat_reload: activate new ruleset of NAT policies and destroy old.
|
npf_nat_matchpolicy(npf_natpolicy_t *np, npf_natpolicy_t *mnp)
|
||||||
*
|
|
||||||
* => Destruction of ruleset will perform npf_nat_freepolicy() for each policy.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
npf_nat_reload(npf_ruleset_t *nset)
|
|
||||||
{
|
{
|
||||||
npf_ruleset_t *oldnset;
|
void *np_raw, *mnp_raw;
|
||||||
|
/*
|
||||||
oldnset = atomic_swap_ptr(&nat_ruleset, nset);
|
* Compare the relevant NAT policy information (in raw form),
|
||||||
KASSERT(oldnset != NULL);
|
* which is enough for matching criterion.
|
||||||
npf_ruleset_destroy(oldnset);
|
*/
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -289,6 +322,28 @@ npf_nat_getport(npf_natpolicy_t *np)
|
||||||
return htons(PORTMAP_FIRST + (idx << PORTMAP_SHIFT) + bit);
|
return htons(PORTMAP_FIRST + (idx << PORTMAP_SHIFT) + bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* npf_nat_takeport: allocate specific port in the NAT policy portmap.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
npf_nat_takeport(npf_natpolicy_t *np, in_port_t port)
|
||||||
|
{
|
||||||
|
npf_portmap_t *pm = np->n_portmap;
|
||||||
|
uint32_t map, nmap;
|
||||||
|
u_int idx, bit;
|
||||||
|
|
||||||
|
port = ntohs(port) - PORTMAP_FIRST;
|
||||||
|
idx = port >> PORTMAP_SHIFT;
|
||||||
|
bit = port & PORTMAP_MASK;
|
||||||
|
map = pm->p_bitmap[idx];
|
||||||
|
nmap = map | (1 << bit);
|
||||||
|
if (map == nmap) {
|
||||||
|
/* Already taken. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return atomic_cas_32(&pm->p_bitmap[idx], map, nmap) == map;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* npf_nat_putport: return port as available in the NAT policy portmap.
|
* npf_nat_putport: return port as available in the NAT policy portmap.
|
||||||
*
|
*
|
||||||
|
@ -317,10 +372,11 @@ npf_nat_putport(npf_natpolicy_t *np, in_port_t port)
|
||||||
static npf_natpolicy_t *
|
static npf_natpolicy_t *
|
||||||
npf_nat_inspect(npf_cache_t *npc, nbuf_t *nbuf, struct ifnet *ifp, const int di)
|
npf_nat_inspect(npf_cache_t *npc, nbuf_t *nbuf, struct ifnet *ifp, const int di)
|
||||||
{
|
{
|
||||||
|
npf_ruleset_t *rlset;
|
||||||
npf_rule_t *rl;
|
npf_rule_t *rl;
|
||||||
|
|
||||||
rl = npf_ruleset_match(nat_ruleset, npc, nbuf, ifp, di, NPF_LAYER_3);
|
rlset = npf_core_natset();
|
||||||
|
rl = npf_ruleset_match(rlset, npc, nbuf, ifp, di, NPF_LAYER_3);
|
||||||
return rl ? npf_rule_getnat(rl) : NULL;
|
return rl ? npf_rule_getnat(rl) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +396,12 @@ npf_nat_create(npf_cache_t *npc, npf_natpolicy_t *np)
|
||||||
if (nt == NULL){
|
if (nt == NULL){
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
npf_stats_inc(NPF_STAT_NAT_CREATE);
|
||||||
|
mutex_enter(&np->n_lock);
|
||||||
|
LIST_INSERT_HEAD(&np->n_nat_list, nt, nt_entry);
|
||||||
nt->nt_natpolicy = np;
|
nt->nt_natpolicy = np;
|
||||||
|
nt->nt_session = NULL;
|
||||||
|
mutex_exit(&np->n_lock);
|
||||||
nt->nt_alg = NULL;
|
nt->nt_alg = NULL;
|
||||||
|
|
||||||
/* Save the original address which may be rewritten. */
|
/* Save the original address which may be rewritten. */
|
||||||
|
@ -457,11 +518,11 @@ npf_nat_translate(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt,
|
||||||
/*
|
/*
|
||||||
* npf_do_nat:
|
* npf_do_nat:
|
||||||
* - Inspect packet for a NAT policy, unless a session with a NAT
|
* - Inspect packet for a NAT policy, unless a session with a NAT
|
||||||
* association already exists. In such case, determine whether is
|
* association already exists. In such case, determine whether it
|
||||||
* is a "forwards" or "backwards" stream.
|
* is a "forwards" or "backwards" stream.
|
||||||
* - Perform translation: rewrite source address if "forwards" stream
|
* - Perform translation: rewrite source or destination fields,
|
||||||
* and destination address if "backwards".
|
* depending on translation type and direction.
|
||||||
* - Establish sessions or, if already exists, associate a NAT policy.
|
* - Associate a NAT policy with a session (may establish a new).
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
npf_do_nat(npf_cache_t *npc, npf_session_t *se, nbuf_t *nbuf,
|
npf_do_nat(npf_cache_t *npc, npf_session_t *se, nbuf_t *nbuf,
|
||||||
|
@ -481,6 +542,7 @@ npf_do_nat(npf_cache_t *npc, npf_session_t *se, nbuf_t *nbuf,
|
||||||
/*
|
/*
|
||||||
* Return the NAT entry associated with the session, if any.
|
* Return the NAT entry associated with the session, if any.
|
||||||
* Determines whether the stream is "forwards" or "backwards".
|
* Determines whether the stream is "forwards" or "backwards".
|
||||||
|
* Note: no need to lock, since reference on session is held.
|
||||||
*/
|
*/
|
||||||
if (se && (nt = npf_session_retnat(se, di, &forw)) != NULL) {
|
if (se && (nt = npf_session_retnat(se, di, &forw)) != NULL) {
|
||||||
np = nt->nt_natpolicy;
|
np = nt->nt_natpolicy;
|
||||||
|
@ -489,18 +551,27 @@ npf_do_nat(npf_cache_t *npc, npf_session_t *se, nbuf_t *nbuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inspect the packet for a NAT policy, if there is no session. */
|
/* Inspect the packet for a NAT policy, if there is no session. */
|
||||||
|
npf_core_enter();
|
||||||
np = npf_nat_inspect(npc, nbuf, ifp, di);
|
np = npf_nat_inspect(npc, nbuf, ifp, di);
|
||||||
if (np == NULL) {
|
if (np == NULL) {
|
||||||
/* If packet does not match - done. */
|
/* If packet does not match - done. */
|
||||||
|
npf_core_exit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
forw = true;
|
forw = true;
|
||||||
|
|
||||||
/* Create a new NAT translation entry. */
|
/*
|
||||||
|
* Create a new NAT entry. Note: it is safe to unlock, since the
|
||||||
|
* NAT policy wont be desotroyed while there are list entries, which
|
||||||
|
* are removed only on session expiration. Currently, NAT entry is
|
||||||
|
* not yet associated with any session.
|
||||||
|
*/
|
||||||
nt = npf_nat_create(npc, np);
|
nt = npf_nat_create(npc, np);
|
||||||
if (nt == NULL) {
|
if (nt == NULL) {
|
||||||
|
npf_core_exit();
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
npf_core_exit();
|
||||||
new = true;
|
new = true;
|
||||||
|
|
||||||
/* Determine whether any ALG matches. */
|
/* Determine whether any ALG matches. */
|
||||||
|
@ -515,7 +586,7 @@ npf_do_nat(npf_cache_t *npc, npf_session_t *se, nbuf_t *nbuf,
|
||||||
* stream depends on other, stateless filtering rules.
|
* stream depends on other, stateless filtering rules.
|
||||||
*/
|
*/
|
||||||
if (se == NULL) {
|
if (se == NULL) {
|
||||||
nse = npf_session_establish(npc, nbuf, NULL, di);
|
nse = npf_session_establish(npc, nbuf, di);
|
||||||
if (nse == NULL) {
|
if (nse == NULL) {
|
||||||
error = ENOMEM;
|
error = ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -530,27 +601,17 @@ translate:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (__predict_false(new)) {
|
if (__predict_false(new)) {
|
||||||
npf_session_t *natse;
|
|
||||||
/*
|
/*
|
||||||
* Establish a new NAT session using translated address and
|
* Associate NAT translation entry with the session.
|
||||||
* associate NAT translation data with this session.
|
|
||||||
*
|
|
||||||
* Note: packet now has a translated address in the cache.
|
* Note: packet now has a translated address in the cache.
|
||||||
*/
|
*/
|
||||||
natse = npf_session_establish(npc, nbuf, nt, di);
|
nt->nt_session = se;
|
||||||
if (natse == NULL) {
|
error = npf_session_setnat(se, nt, di);
|
||||||
error = ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Link local session with NAT session, if no link already.
|
|
||||||
*/
|
|
||||||
npf_session_link(se, natse);
|
|
||||||
npf_session_release(natse);
|
|
||||||
out:
|
out:
|
||||||
if (error) {
|
if (error) {
|
||||||
if (nse != NULL) {
|
/* If session was for NAT only - expire it. */
|
||||||
/* XXX: Expire it?? */
|
if (nse) {
|
||||||
|
npf_session_expire(nse);
|
||||||
}
|
}
|
||||||
/* Will free the structure and return the port. */
|
/* Will free the structure and return the port. */
|
||||||
npf_nat_expire(nt);
|
npf_nat_expire(nt);
|
||||||
|
@ -562,6 +623,18 @@ out:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* npf_nat_gettrans: return translation IP address and port.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
npf_nat_gettrans(npf_nat_t *nt, npf_addr_t **addr, in_port_t *port)
|
||||||
|
{
|
||||||
|
npf_natpolicy_t *np = nt->nt_natpolicy;
|
||||||
|
|
||||||
|
*addr = &np->n_taddr;
|
||||||
|
*port = nt->nt_tport;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* npf_nat_getorig: return original IP address and port from translation entry.
|
* npf_nat_getorig: return original IP address and port from translation entry.
|
||||||
*/
|
*/
|
||||||
|
@ -592,11 +665,116 @@ npf_nat_expire(npf_nat_t *nt)
|
||||||
{
|
{
|
||||||
npf_natpolicy_t *np = nt->nt_natpolicy;
|
npf_natpolicy_t *np = nt->nt_natpolicy;
|
||||||
|
|
||||||
if ((np->n_flags & NPF_NAT_PORTMAP) != 0) {
|
/* Return any taken port to the portmap. */
|
||||||
KASSERT(nt->nt_tport != 0);
|
if ((np->n_flags & NPF_NAT_PORTMAP) != 0 && nt->nt_tport) {
|
||||||
npf_nat_putport(np, nt->nt_tport);
|
npf_nat_putport(np, nt->nt_tport);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove NAT entry from the list, notify any waiters if last entry. */
|
||||||
|
mutex_enter(&np->n_lock);
|
||||||
|
LIST_REMOVE(nt, nt_entry);
|
||||||
|
if (LIST_EMPTY(&np->n_nat_list)) {
|
||||||
|
cv_broadcast(&np->n_cv);
|
||||||
|
}
|
||||||
|
mutex_exit(&np->n_lock);
|
||||||
|
|
||||||
|
/* Free structure, increase the counter. */
|
||||||
pool_cache_put(nat_cache, nt);
|
pool_cache_put(nat_cache, nt);
|
||||||
|
npf_stats_inc(NPF_STAT_NAT_DESTROY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* npf_nat_save: construct NAT entry and reference to the NAT policy.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
npf_nat_save(prop_dictionary_t sedict, prop_array_t natlist, 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;
|
||||||
|
uintptr_t itnp;
|
||||||
|
|
||||||
|
/* Set NAT entry data. */
|
||||||
|
nd = prop_data_create_data(nt, sizeof(npf_nat_t));
|
||||||
|
prop_dictionary_set(sedict, "nat-data", nd);
|
||||||
|
|
||||||
|
/* Find or create a NAT policy. */
|
||||||
|
it = prop_array_iterator(natlist);
|
||||||
|
while ((npdict = prop_object_iterator_next(it)) != NULL) {
|
||||||
|
itnp = (uintptr_t)prop_number_unsigned_integer_value(
|
||||||
|
prop_dictionary_get(npdict, "id-ptr"));
|
||||||
|
if (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));
|
||||||
|
|
||||||
|
/* Set the data, insert into the array. */
|
||||||
|
prop_dictionary_set(npdict, "id-ptr",
|
||||||
|
prop_number_create_unsigned_integer((uintptr_t)np));
|
||||||
|
prop_dictionary_set(npdict, "nat-policy-data", npd);
|
||||||
|
prop_array_add(natlist, npdict);
|
||||||
|
}
|
||||||
|
prop_dictionary_set(sedict, "nat-policy",
|
||||||
|
prop_dictionary_copy(npdict));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* npf_nat_restore: find a matching NAT policy and restore NAT entry.
|
||||||
|
*
|
||||||
|
* => Caller should lock the active NAT ruleset.
|
||||||
|
*/
|
||||||
|
npf_nat_t *
|
||||||
|
npf_nat_restore(prop_dictionary_t sedict, npf_session_t *se)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Get raw NAT entry. */
|
||||||
|
obj = prop_dictionary_get(sedict, "nat-data");
|
||||||
|
ntraw = prop_data_data_nocopy(obj);
|
||||||
|
if (ntraw == NULL || prop_data_size(obj) != sizeof(npf_nat_t)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find a stored NAT policy information. */
|
||||||
|
obj = prop_dictionary_get(
|
||||||
|
prop_dictionary_get(sedict, "nat-policy"), "nat-policy-data");
|
||||||
|
onp = prop_data_data_nocopy(obj);
|
||||||
|
if (onp == NULL || prop_data_size(obj) != sizeof(npf_natpolicy_t)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Match if there is an existing NAT policy. */
|
||||||
|
rl = npf_ruleset_matchnat(npf_core_natset(), __UNCONST(onp));
|
||||||
|
if (rl == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
np = npf_rule_getnat(rl);
|
||||||
|
KASSERT(np != NULL);
|
||||||
|
|
||||||
|
/* Take a specific port from port-map. */
|
||||||
|
if (!npf_nat_takeport(np, ntraw->nt_tport)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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_session = se;
|
||||||
|
nt->nt_alg = NULL;
|
||||||
|
return nt;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DDB) || defined(_NPF_TESTING)
|
#if defined(DDB) || defined(_NPF_TESTING)
|
||||||
|
@ -607,26 +785,16 @@ npf_nat_dump(npf_nat_t *nt)
|
||||||
npf_natpolicy_t *np;
|
npf_natpolicy_t *np;
|
||||||
struct in_addr ip;
|
struct in_addr ip;
|
||||||
|
|
||||||
if (nt) {
|
np = nt->nt_natpolicy;
|
||||||
np = nt->nt_natpolicy;
|
memcpy(&ip, &np->n_taddr, sizeof(ip));
|
||||||
goto skip;
|
printf("\tNATP(%p): type %d flags 0x%x taddr %s tport %d\n",
|
||||||
}
|
np, np->n_type, np->n_flags, inet_ntoa(ip), np->n_tport);
|
||||||
LIST_FOREACH(np, &nat_policy_list, n_entry) {
|
memcpy(&ip, &nt->nt_oaddr, sizeof(ip));
|
||||||
skip:
|
printf("\tNAT: original address %s oport %d tport %d\n",
|
||||||
memcpy(&ip, &np->n_taddr, sizeof(ip));
|
inet_ntoa(ip), ntohs(nt->nt_oport), ntohs(nt->nt_tport));
|
||||||
printf("\tNAT policy: type %d, flags 0x%x, taddr %s, tport = %d\n",
|
if (nt->nt_alg) {
|
||||||
np->n_type, np->n_flags, inet_ntoa(ip), np->n_tport);
|
printf("\tNAT ALG = %p, ARG = %p\n",
|
||||||
if (nt == NULL) {
|
nt->nt_alg, (void *)nt->nt_alg_arg);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
memcpy(&ip, &nt->nt_oaddr, sizeof(ip));
|
|
||||||
printf("\tNAT: original address %s, oport %d, tport = %d\n",
|
|
||||||
inet_ntoa(ip), ntohs(nt->nt_oport), ntohs(nt->nt_tport));
|
|
||||||
if (nt->nt_alg) {
|
|
||||||
printf("\tNAT ALG = %p, ARG = %p\n",
|
|
||||||
nt->nt_alg, (void *)nt->nt_alg_arg);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_ncode.h,v 1.3 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_ncode.h,v 1.4 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -82,8 +82,8 @@ int npf_ncode_validate(const void *, size_t, int *);
|
||||||
#define NPF_OPCODE_TAG 0x04
|
#define NPF_OPCODE_TAG 0x04
|
||||||
|
|
||||||
/* Set and load instructions. */
|
/* Set and load instructions. */
|
||||||
#define NPF_OPCODE_MOV 0x10
|
#define NPF_OPCODE_MOVE 0x10
|
||||||
#define NPF_OPCODE_LOAD 0x11
|
#define NPF_OPCODE_LW 0x11
|
||||||
|
|
||||||
/* Compare and jump instructions. */
|
/* Compare and jump instructions. */
|
||||||
#define NPF_OPCODE_CMP 0x21
|
#define NPF_OPCODE_CMP 0x21
|
||||||
|
@ -93,8 +93,19 @@ int npf_ncode_validate(const void *, size_t, int *);
|
||||||
#define NPF_OPCODE_BGT 0x25
|
#define NPF_OPCODE_BGT 0x25
|
||||||
#define NPF_OPCODE_BLT 0x26
|
#define NPF_OPCODE_BLT 0x26
|
||||||
|
|
||||||
|
/* Arithmetic instructions. */
|
||||||
|
#define NPF_OPCODE_ADD 0x30
|
||||||
|
#define NPF_OPCODE_SUB 0x31
|
||||||
|
#define NPF_OPCODE_MULT 0x32
|
||||||
|
#define NPF_OPCODE_DIV 0x33
|
||||||
|
|
||||||
/* Bitwise instructions. */
|
/* Bitwise instructions. */
|
||||||
#define NPF_OPCODE_AND 0x30
|
#define NPF_OPCODE_NOT 0x40
|
||||||
|
#define NPF_OPCODE_AND 0x41
|
||||||
|
#define NPF_OPCODE_OR 0x42
|
||||||
|
#define NPF_OPCODE_XOR 0x43
|
||||||
|
#define NPF_OPCODE_SLL 0x44
|
||||||
|
#define NPF_OPCODE_SRL 0x45
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CISC-like n-code instructions.
|
* CISC-like n-code instructions.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_processor.c,v 1.3 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_processor.c,v 1.4 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: npf_processor.c,v 1.3 2010/11/11 06:30:39 rmind Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: npf_processor.c,v 1.4 2010/12/18 01:07:25 rmind Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
|
@ -173,9 +173,9 @@ process_next:
|
||||||
/*
|
/*
|
||||||
* RISC-like instructions.
|
* RISC-like instructions.
|
||||||
*
|
*
|
||||||
* - ADVR, LOAD, CMP, CMPR
|
* - ADVR, LW, CMP, CMPR
|
||||||
* - BEQ, BNE, BGT, BLT
|
* - BEQ, BNE, BGT, BLT
|
||||||
* - RET, TAG, MOV
|
* - RET, TAG, MOVE
|
||||||
* - AND, J, INVL
|
* - AND, J, INVL
|
||||||
*/
|
*/
|
||||||
switch (d) {
|
switch (d) {
|
||||||
|
@ -187,7 +187,7 @@ process_next:
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NPF_OPCODE_LOAD:
|
case NPF_OPCODE_LW:
|
||||||
i_ptr = nc_fetch_double(i_ptr, &n, &i); /* Size, register */
|
i_ptr = nc_fetch_double(i_ptr, &n, &i); /* Size, register */
|
||||||
KASSERT(i < NPF_NREGS);
|
KASSERT(i < NPF_NREGS);
|
||||||
KASSERT(n >= sizeof(uint8_t) && n <= sizeof(uint32_t));
|
KASSERT(n >= sizeof(uint8_t) && n <= sizeof(uint32_t));
|
||||||
|
@ -242,7 +242,7 @@ process_next:
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NPF_OPCODE_MOV:
|
case NPF_OPCODE_MOVE:
|
||||||
i_ptr = nc_fetch_double(i_ptr, &n, &i); /* Value, register */
|
i_ptr = nc_fetch_double(i_ptr, &n, &i); /* Value, register */
|
||||||
KASSERT(i < NPF_NREGS);
|
KASSERT(i < NPF_NREGS);
|
||||||
regs[i] = n;
|
regs[i] = n;
|
||||||
|
@ -379,7 +379,7 @@ nc_insn_check(const uintptr_t optr, const void *nc, size_t sz,
|
||||||
case NPF_OPCODE_ADVR:
|
case NPF_OPCODE_ADVR:
|
||||||
error = nc_ptr_check(&iptr, nc, sz, 1, ®idx, 1);
|
error = nc_ptr_check(&iptr, nc, sz, 1, ®idx, 1);
|
||||||
break;
|
break;
|
||||||
case NPF_OPCODE_LOAD:
|
case NPF_OPCODE_LW:
|
||||||
error = nc_ptr_check(&iptr, nc, sz, 1, &val, 1);
|
error = nc_ptr_check(&iptr, nc, sz, 1, &val, 1);
|
||||||
if (error || val < sizeof(uint8_t) || val > sizeof(uint32_t)) {
|
if (error || val < sizeof(uint8_t) || val > sizeof(uint32_t)) {
|
||||||
return error ? error : NPF_ERR_INVAL;
|
return error ? error : NPF_ERR_INVAL;
|
||||||
|
@ -404,7 +404,7 @@ nc_insn_check(const uintptr_t optr, const void *nc, size_t sz,
|
||||||
case NPF_OPCODE_TAG:
|
case NPF_OPCODE_TAG:
|
||||||
error = nc_ptr_check(&iptr, nc, sz, 2, NULL, 0);
|
error = nc_ptr_check(&iptr, nc, sz, 2, NULL, 0);
|
||||||
break;
|
break;
|
||||||
case NPF_OPCODE_MOV:
|
case NPF_OPCODE_MOVE:
|
||||||
error = nc_ptr_check(&iptr, nc, sz, 2, ®idx, 2);
|
error = nc_ptr_check(&iptr, nc, sz, 2, ®idx, 2);
|
||||||
break;
|
break;
|
||||||
case NPF_OPCODE_CMPR:
|
case NPF_OPCODE_CMPR:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_ruleset.c,v 1.3 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_ruleset.c,v 1.4 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -31,15 +31,11 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NPF ruleset module.
|
* NPF ruleset module.
|
||||||
*
|
|
||||||
* Lock order:
|
|
||||||
*
|
|
||||||
* ruleset_lock -> table_lock -> npf_table_t::t_lock
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.3 2010/11/11 06:30:39 rmind Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.4 2010/12/18 01:07:25 rmind Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
|
@ -48,7 +44,6 @@ __KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.3 2010/11/11 06:30:39 rmind Exp $"
|
||||||
#include <sys/kmem.h>
|
#include <sys/kmem.h>
|
||||||
#include <sys/pool.h>
|
#include <sys/pool.h>
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
#include <sys/rwlock.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <net/pfil.h>
|
#include <net/pfil.h>
|
||||||
|
@ -58,75 +53,56 @@ __KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.3 2010/11/11 06:30:39 rmind Exp $"
|
||||||
#include "npf_ncode.h"
|
#include "npf_ncode.h"
|
||||||
#include "npf_impl.h"
|
#include "npf_impl.h"
|
||||||
|
|
||||||
|
/* Ruleset structre (queue and default rule). */
|
||||||
|
struct npf_ruleset {
|
||||||
|
TAILQ_HEAD(, npf_rule) rs_queue;
|
||||||
|
npf_rule_t * rs_default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Rule hook entry. */
|
||||||
struct npf_hook {
|
struct npf_hook {
|
||||||
void (*hk_fn)(npf_cache_t *, nbuf_t *, void *);
|
void (*hk_fn)(npf_cache_t *, nbuf_t *, void *);
|
||||||
void * hk_arg;
|
void * hk_arg;
|
||||||
LIST_ENTRY(npf_hook) hk_entry;
|
LIST_ENTRY(npf_hook) hk_entry;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct npf_ruleset {
|
/* Rule processing structure. */
|
||||||
TAILQ_HEAD(, npf_rule) rs_queue;
|
struct npf_rproc {
|
||||||
npf_rule_t * rs_default;
|
/* Reference count. */
|
||||||
int _reserved;
|
u_int rp_refcnt;
|
||||||
|
/* Normalization options. */
|
||||||
|
bool rp_rnd_ipid;
|
||||||
|
bool rp_no_df;
|
||||||
|
u_int rp_minttl;
|
||||||
|
u_int rp_maxmss;
|
||||||
|
/* Logging interface. */
|
||||||
|
u_int rp_log_ifid;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Rule structure. */
|
/* Rule structure. */
|
||||||
struct npf_rule {
|
struct npf_rule {
|
||||||
/* List entry in the ruleset. */
|
TAILQ_ENTRY(npf_rule) r_entry;
|
||||||
TAILQ_ENTRY(npf_rule) r_entry;
|
|
||||||
/* Optional: sub-ruleset, NAT policy. */
|
/* Optional: sub-ruleset, NAT policy. */
|
||||||
npf_ruleset_t r_subset;
|
npf_ruleset_t r_subset;
|
||||||
npf_natpolicy_t * r_nat;
|
npf_natpolicy_t * r_natp;
|
||||||
/* Rule priority: (highest) 0, 1, 2 ... n (lowest). */
|
/* Rule priority: (highest) 0, 1, 2 ... n (lowest). */
|
||||||
u_int r_priority;
|
u_int r_priority;
|
||||||
/* N-code to process. */
|
/* N-code to process. */
|
||||||
void * r_ncode;
|
void * r_ncode;
|
||||||
size_t r_nc_size;
|
size_t r_nc_size;
|
||||||
/* Attributes of this rule. */
|
/* Attributes of this rule. */
|
||||||
uint32_t r_attr;
|
uint32_t r_attr;
|
||||||
/* Interface. */
|
/* Interface. */
|
||||||
u_int r_ifid;
|
u_int r_ifid;
|
||||||
/* Hit counter. */
|
/* Hit counter. */
|
||||||
u_long r_hitcount;
|
u_long r_hitcount;
|
||||||
/* Normalization options (XXX - abstract). */
|
/* Rule processing data. */
|
||||||
bool rl_rnd_ipid;
|
npf_rproc_t * r_rproc;
|
||||||
u_int rl_minttl;
|
|
||||||
u_int rl_maxmss;
|
|
||||||
/* List of hooks to process on match. */
|
/* List of hooks to process on match. */
|
||||||
LIST_HEAD(, npf_hook) r_hooks;
|
kmutex_t r_hooks_lock;
|
||||||
|
LIST_HEAD(, npf_hook) r_hooks;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Global ruleset, its lock, cache and NAT ruleset. */
|
|
||||||
static npf_ruleset_t * ruleset;
|
|
||||||
static krwlock_t ruleset_lock;
|
|
||||||
static pool_cache_t rule_cache;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* npf_ruleset_sysinit: initialise ruleset structures.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
npf_ruleset_sysinit(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
rule_cache = pool_cache_init(sizeof(npf_rule_t), coherency_unit,
|
|
||||||
0, 0, "npfrlpl", NULL, IPL_NONE, NULL, NULL, NULL);
|
|
||||||
if (rule_cache == NULL) {
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
rw_init(&ruleset_lock);
|
|
||||||
ruleset = npf_ruleset_create();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
npf_ruleset_sysfini(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
npf_ruleset_destroy(ruleset);
|
|
||||||
rw_destroy(&ruleset_lock);
|
|
||||||
pool_cache_destroy(rule_cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
npf_ruleset_t *
|
npf_ruleset_t *
|
||||||
npf_ruleset_create(void)
|
npf_ruleset_create(void)
|
||||||
{
|
{
|
||||||
|
@ -176,120 +152,194 @@ npf_ruleset_insert(npf_ruleset_t *rlset, npf_rule_t *rl)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* npf_ruleset_reload: atomically load new ruleset and tableset,
|
* npf_ruleset_matchnat: find a matching NAT policy in the ruleset.
|
||||||
* and destroy old structures.
|
*/
|
||||||
|
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. */
|
||||||
|
TAILQ_FOREACH(rl, &rlset->rs_queue, r_entry) {
|
||||||
|
if (npf_nat_matchpolicy(rl->r_natp, mnp))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return rl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* npf_ruleset_natreload: minimum reload of NAT policies by maching
|
||||||
|
* two (active and new) NAT rulesets.
|
||||||
|
*
|
||||||
|
* => Active ruleset should be exclusively locked.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
npf_ruleset_reload(npf_ruleset_t *nrlset, npf_tableset_t *ntblset)
|
npf_ruleset_natreload(npf_ruleset_t *nrlset, npf_ruleset_t *arlset)
|
||||||
{
|
{
|
||||||
npf_ruleset_t *oldrlset;
|
npf_natpolicy_t *np, *anp;
|
||||||
npf_tableset_t *oldtblset;
|
npf_rule_t *rl, *arl;
|
||||||
|
|
||||||
/*
|
KASSERT(npf_core_locked());
|
||||||
* Swap old ruleset with the new.
|
|
||||||
* XXX: Rework to be fully lock-less; later.
|
|
||||||
*/
|
|
||||||
rw_enter(&ruleset_lock, RW_WRITER);
|
|
||||||
oldrlset = atomic_swap_ptr(&ruleset, nrlset);
|
|
||||||
KASSERT(oldrlset != NULL);
|
|
||||||
|
|
||||||
/*
|
/* Scan a new NAT ruleset against NAT policies in old ruleset. */
|
||||||
* Setup a new tableset. It will lock the global tableset lock,
|
TAILQ_FOREACH(rl, &nrlset->rs_queue, r_entry) {
|
||||||
* therefore ensures atomicity. We shall free the old table-set.
|
np = rl->r_natp;
|
||||||
*/
|
arl = npf_ruleset_matchnat(arlset, np);
|
||||||
oldtblset = npf_tableset_reload(ntblset);
|
if (arl == NULL) {
|
||||||
KASSERT(oldtblset != NULL);
|
continue;
|
||||||
/* Unlock. Everything goes "live" now. */
|
}
|
||||||
rw_exit(&ruleset_lock);
|
/* On match - we exchange NAT policies. */
|
||||||
|
anp = arl->r_natp;
|
||||||
|
rl->r_natp = anp;
|
||||||
|
arl->r_natp = np;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
npf_rproc_t *
|
||||||
|
npf_rproc_create(prop_dictionary_t rpdict)
|
||||||
|
{
|
||||||
|
npf_rproc_t *rp;
|
||||||
|
prop_object_t obj;
|
||||||
|
|
||||||
|
rp = kmem_alloc(sizeof(npf_rproc_t), KM_SLEEP);
|
||||||
|
rp->rp_refcnt = 1;
|
||||||
|
|
||||||
|
/* Logging interface ID (integer). */
|
||||||
|
obj = prop_dictionary_get(rpdict, "log-interface");
|
||||||
|
rp->rp_log_ifid = prop_number_integer_value(obj);
|
||||||
|
|
||||||
|
/* Randomize IP ID (bool). */
|
||||||
|
obj = prop_dictionary_get(rpdict, "randomize-id");
|
||||||
|
rp->rp_rnd_ipid = prop_bool_true(obj);
|
||||||
|
|
||||||
|
/* IP_DF flag cleansing (bool). */
|
||||||
|
obj = prop_dictionary_get(rpdict, "no-df");
|
||||||
|
rp->rp_no_df = prop_bool_true(obj);
|
||||||
|
|
||||||
|
/* Minimum IP TTL (integer). */
|
||||||
|
obj = prop_dictionary_get(rpdict, "min-ttl");
|
||||||
|
rp->rp_minttl = prop_number_integer_value(obj);
|
||||||
|
|
||||||
|
/* Maximum TCP MSS (integer). */
|
||||||
|
obj = prop_dictionary_get(rpdict, "max-mss");
|
||||||
|
rp->rp_maxmss = prop_number_integer_value(obj);
|
||||||
|
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
npf_rproc_t *
|
||||||
|
npf_rproc_return(npf_rule_t *rl)
|
||||||
|
{
|
||||||
|
npf_rproc_t *rp = rl->r_rproc;
|
||||||
|
|
||||||
|
if (rp) {
|
||||||
|
atomic_inc_uint(&rp->rp_refcnt);
|
||||||
|
}
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
npf_rproc_release(npf_rproc_t *rp)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Destroy on last reference. */
|
||||||
|
if (atomic_dec_uint_nv(&rp->rp_refcnt) != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
kmem_free(rp, sizeof(npf_rproc_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
npf_rproc_run(npf_cache_t *npc, nbuf_t *nbuf, npf_rproc_t *rp)
|
||||||
|
{
|
||||||
|
|
||||||
|
KASSERT(rp->rp_refcnt > 0);
|
||||||
|
|
||||||
|
/* Normalize the packet, if required. */
|
||||||
|
(void)npf_normalize(npc, nbuf,
|
||||||
|
rp->rp_rnd_ipid, rp->rp_no_df, rp->rp_minttl, rp->rp_maxmss);
|
||||||
|
|
||||||
|
/* Log packet, if required. */
|
||||||
|
if (rp->rp_log_ifid) {
|
||||||
|
npf_log_packet(npc, nbuf, rp->rp_log_ifid);
|
||||||
|
}
|
||||||
|
|
||||||
npf_tableset_destroy(oldtblset);
|
|
||||||
npf_ruleset_destroy(oldrlset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* npf_rule_alloc: allocate a rule and copy ncode from user-space.
|
* npf_rule_alloc: allocate a rule and copy ncode from user-space.
|
||||||
|
*
|
||||||
|
* => N-code should be validated by the caller.
|
||||||
*/
|
*/
|
||||||
npf_rule_t *
|
npf_rule_t *
|
||||||
npf_rule_alloc(int attr, pri_t pri, int ifidx, void *nc, size_t sz,
|
npf_rule_alloc(prop_dictionary_t rldict, void *nc, size_t nc_size)
|
||||||
bool rnd_ipid, int minttl, int maxmss)
|
|
||||||
{
|
{
|
||||||
npf_rule_t *rl;
|
npf_rule_t *rl;
|
||||||
|
prop_object_t obj;
|
||||||
int errat;
|
int errat;
|
||||||
|
|
||||||
/* Perform validation & building of n-code. */
|
|
||||||
if (nc && npf_ncode_validate(nc, sz, &errat)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* Allocate a rule structure. */
|
/* Allocate a rule structure. */
|
||||||
rl = pool_cache_get(rule_cache, PR_WAITOK);
|
rl = kmem_alloc(sizeof(npf_rule_t), KM_SLEEP);
|
||||||
if (rl == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
TAILQ_INIT(&rl->r_subset.rs_queue);
|
TAILQ_INIT(&rl->r_subset.rs_queue);
|
||||||
|
mutex_init(&rl->r_hooks_lock, MUTEX_DEFAULT, IPL_SOFTNET);
|
||||||
LIST_INIT(&rl->r_hooks);
|
LIST_INIT(&rl->r_hooks);
|
||||||
rl->r_priority = pri;
|
|
||||||
rl->r_attr = attr;
|
|
||||||
rl->r_ifid = ifidx;
|
|
||||||
rl->r_ncode = nc;
|
|
||||||
rl->r_nc_size = sz;
|
|
||||||
rl->r_hitcount = 0;
|
rl->r_hitcount = 0;
|
||||||
rl->r_nat = NULL;
|
rl->r_natp = NULL;
|
||||||
|
|
||||||
rl->rl_rnd_ipid = rnd_ipid;
|
/* N-code. */
|
||||||
rl->rl_minttl = minttl;
|
KASSERT(nc == NULL || npf_ncode_validate(nc, nc_size, &errat) == 0);
|
||||||
rl->rl_maxmss = maxmss;
|
rl->r_ncode = nc;
|
||||||
|
rl->r_nc_size = nc_size;
|
||||||
|
|
||||||
|
/* Attributes (integer). */
|
||||||
|
obj = prop_dictionary_get(rldict, "attributes");
|
||||||
|
rl->r_attr = prop_number_integer_value(obj);
|
||||||
|
|
||||||
|
/* Priority (integer). */
|
||||||
|
obj = prop_dictionary_get(rldict, "priority");
|
||||||
|
rl->r_priority = prop_number_integer_value(obj);
|
||||||
|
|
||||||
|
/* Interface ID (integer). */
|
||||||
|
obj = prop_dictionary_get(rldict, "interface");
|
||||||
|
rl->r_ifid = prop_number_integer_value(obj);
|
||||||
|
|
||||||
|
/* Create rule processing structure, if any. */
|
||||||
|
if (rl->r_attr & (NPF_RULE_LOG | NPF_RULE_NORMALIZE)) {
|
||||||
|
rl->r_rproc = npf_rproc_create(rldict);
|
||||||
|
} else {
|
||||||
|
rl->r_rproc = NULL;
|
||||||
|
}
|
||||||
return rl;
|
return rl;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/*
|
|
||||||
* npf_activate_rule: activate rule by inserting it into the global ruleset.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
npf_activate_rule(npf_rule_t *rl)
|
|
||||||
{
|
|
||||||
|
|
||||||
rw_enter(&ruleset_lock, RW_WRITER);
|
|
||||||
npf_ruleset_insert(ruleset, rl);
|
|
||||||
rw_exit(&ruleset_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* npf_deactivate_rule: deactivate rule by removing it from the ruleset.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
npf_deactivate_rule(npf_rule_t *)
|
|
||||||
{
|
|
||||||
|
|
||||||
rw_enter(&ruleset_lock, RW_WRITER);
|
|
||||||
TAILQ_REMOVE(&ruleset->rs_queue, rl, r_entry);
|
|
||||||
rw_exit(&ruleset_lock);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* npf_rule_free: free the specified rule.
|
* npf_rule_free: free the specified rule.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
npf_rule_free(npf_rule_t *rl)
|
npf_rule_free(npf_rule_t *rl)
|
||||||
{
|
{
|
||||||
|
npf_natpolicy_t *np = rl->r_natp;
|
||||||
|
npf_rproc_t *rp = rl->r_rproc;
|
||||||
|
|
||||||
|
if (np) {
|
||||||
|
/* Free NAT policy. */
|
||||||
|
npf_nat_freepolicy(np);
|
||||||
|
}
|
||||||
|
if (rp) {
|
||||||
|
/* Release/free rule processing structure. */
|
||||||
|
npf_rproc_release(rp);
|
||||||
|
}
|
||||||
if (rl->r_ncode) {
|
if (rl->r_ncode) {
|
||||||
/* Free n-code (if any). */
|
/* Free n-code. */
|
||||||
npf_ncode_free(rl->r_ncode, rl->r_nc_size);
|
npf_ncode_free(rl->r_ncode, rl->r_nc_size);
|
||||||
}
|
}
|
||||||
if (rl->r_nat) {
|
mutex_destroy(&rl->r_hooks_lock);
|
||||||
/* Free NAT policy (if associated). */
|
kmem_free(rl, sizeof(npf_rule_t));
|
||||||
npf_nat_freepolicy(rl->r_nat);
|
|
||||||
}
|
|
||||||
pool_cache_put(rule_cache, rl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* npf_rule_subset: return sub-ruleset, if any.
|
* npf_rule_subset: return sub-ruleset, if any.
|
||||||
* npf_rule_getnat: get NAT policy assigned to the rule.
|
* npf_rule_getnat: get NAT policy assigned to the rule.
|
||||||
* npf_rule_setnat: assign NAT policy to the rule.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
npf_ruleset_t *
|
npf_ruleset_t *
|
||||||
|
@ -301,15 +351,19 @@ npf_rule_subset(npf_rule_t *rl)
|
||||||
npf_natpolicy_t *
|
npf_natpolicy_t *
|
||||||
npf_rule_getnat(const npf_rule_t *rl)
|
npf_rule_getnat(const npf_rule_t *rl)
|
||||||
{
|
{
|
||||||
return rl->r_nat;
|
return rl->r_natp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* npf_rule_setnat: assign NAT policy to the rule and insert into the
|
||||||
|
* NAT policy list in the ruleset.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
npf_rule_setnat(npf_rule_t *rl, npf_natpolicy_t *np)
|
npf_rule_setnat(npf_rule_t *rl, npf_natpolicy_t *np)
|
||||||
{
|
{
|
||||||
|
|
||||||
KASSERT(rl->r_nat == NULL);
|
KASSERT(rl->r_natp == NULL);
|
||||||
rl->r_nat = np;
|
rl->r_natp = np;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -325,9 +379,9 @@ npf_hook_register(npf_rule_t *rl,
|
||||||
if (hk != NULL) {
|
if (hk != NULL) {
|
||||||
hk->hk_fn = fn;
|
hk->hk_fn = fn;
|
||||||
hk->hk_arg = arg;
|
hk->hk_arg = arg;
|
||||||
rw_enter(&ruleset_lock, RW_WRITER);
|
mutex_enter(&rl->r_hooks_lock);
|
||||||
LIST_INSERT_HEAD(&rl->r_hooks, hk, hk_entry);
|
LIST_INSERT_HEAD(&rl->r_hooks, hk, hk_entry);
|
||||||
rw_exit(&ruleset_lock);
|
mutex_exit(&rl->r_hooks_lock);
|
||||||
}
|
}
|
||||||
return hk;
|
return hk;
|
||||||
}
|
}
|
||||||
|
@ -341,9 +395,9 @@ void
|
||||||
npf_hook_unregister(npf_rule_t *rl, npf_hook_t *hk)
|
npf_hook_unregister(npf_rule_t *rl, npf_hook_t *hk)
|
||||||
{
|
{
|
||||||
|
|
||||||
rw_enter(&ruleset_lock, RW_WRITER);
|
mutex_enter(&rl->r_hooks_lock);
|
||||||
LIST_REMOVE(hk, hk_entry);
|
LIST_REMOVE(hk, hk_entry);
|
||||||
rw_exit(&ruleset_lock);
|
mutex_exit(&rl->r_hooks_lock);
|
||||||
kmem_free(hk, sizeof(npf_hook_t));
|
kmem_free(hk, sizeof(npf_hook_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,18 +455,20 @@ npf_rule_t *
|
||||||
npf_ruleset_inspect(npf_cache_t *npc, nbuf_t *nbuf,
|
npf_ruleset_inspect(npf_cache_t *npc, nbuf_t *nbuf,
|
||||||
struct ifnet *ifp, const int di, const int layer)
|
struct ifnet *ifp, const int di, const int layer)
|
||||||
{
|
{
|
||||||
npf_ruleset_t *rlset = ruleset;
|
npf_ruleset_t *rlset;
|
||||||
npf_rule_t *rl;
|
npf_rule_t *rl;
|
||||||
bool defed;
|
bool defed;
|
||||||
|
|
||||||
defed = false;
|
defed = false;
|
||||||
rw_enter(&ruleset_lock, RW_READER);
|
npf_core_enter();
|
||||||
|
rlset = npf_core_ruleset();
|
||||||
reinspect:
|
reinspect:
|
||||||
rl = npf_ruleset_match(rlset, npc, nbuf, ifp, di, layer);
|
rl = npf_ruleset_match(rlset, npc, nbuf, ifp, di, layer);
|
||||||
|
|
||||||
/* If no final rule, then - default. */
|
/* If no final rule, then - default. */
|
||||||
if (rl == NULL && !defed) {
|
if (rl == NULL && !defed) {
|
||||||
rl = ruleset->rs_default;
|
npf_ruleset_t *mainrlset = npf_core_ruleset();
|
||||||
|
rl = mainrlset->rs_default;
|
||||||
defed = true;
|
defed = true;
|
||||||
}
|
}
|
||||||
/* Inspect the sub-ruleset, if any. */
|
/* Inspect the sub-ruleset, if any. */
|
||||||
|
@ -421,7 +477,7 @@ reinspect:
|
||||||
goto reinspect;
|
goto reinspect;
|
||||||
}
|
}
|
||||||
if (rl == NULL) {
|
if (rl == NULL) {
|
||||||
rw_exit(&ruleset_lock);
|
npf_core_exit();
|
||||||
}
|
}
|
||||||
return rl;
|
return rl;
|
||||||
}
|
}
|
||||||
|
@ -433,12 +489,12 @@ reinspect:
|
||||||
* => Releases the ruleset lock.
|
* => Releases the ruleset lock.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
npf_rule_apply(npf_cache_t *npc, nbuf_t *nbuf, npf_rule_t *rl,
|
npf_rule_apply(npf_cache_t *npc, nbuf_t *nbuf, npf_rule_t *rl, int *retfl)
|
||||||
bool *keepstate, int *retfl)
|
|
||||||
{
|
{
|
||||||
npf_hook_t *hk;
|
npf_hook_t *hk;
|
||||||
|
int error;
|
||||||
|
|
||||||
KASSERT(rw_lock_held(&ruleset_lock));
|
KASSERT(npf_core_locked());
|
||||||
|
|
||||||
/* Update the "hit" counter. */
|
/* Update the "hit" counter. */
|
||||||
if (rl->r_attr & NPF_RULE_COUNT) {
|
if (rl->r_attr & NPF_RULE_COUNT) {
|
||||||
|
@ -447,27 +503,20 @@ npf_rule_apply(npf_cache_t *npc, nbuf_t *nbuf, npf_rule_t *rl,
|
||||||
|
|
||||||
/* If not passing - drop the packet. */
|
/* If not passing - drop the packet. */
|
||||||
if ((rl->r_attr & NPF_RULE_PASS) == 0) {
|
if ((rl->r_attr & NPF_RULE_PASS) == 0) {
|
||||||
/* Determine whether any return message is needed. */
|
error = ENETUNREACH;
|
||||||
*retfl = rl->r_attr & (NPF_RULE_RETRST | NPF_RULE_RETICMP);
|
goto done;
|
||||||
rw_exit(&ruleset_lock);
|
|
||||||
return ENETUNREACH;
|
|
||||||
}
|
}
|
||||||
|
error = 0;
|
||||||
|
|
||||||
/* Passing. Run the hooks. */
|
/* Passing. Run the hooks. */
|
||||||
LIST_FOREACH(hk, &rl->r_hooks, hk_entry) {
|
LIST_FOREACH(hk, &rl->r_hooks, hk_entry) {
|
||||||
KASSERT(hk->hk_fn != NULL);
|
KASSERT(hk->hk_fn != NULL);
|
||||||
(*hk->hk_fn)(npc, nbuf, hk->hk_arg);
|
(*hk->hk_fn)(npc, nbuf, hk->hk_arg);
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
/* Normalize the packet, if required. */
|
*retfl = rl->r_attr;
|
||||||
if (rl->r_attr & NPF_RULE_NORMALIZE) {
|
npf_core_exit();
|
||||||
(void)npf_normalize(npc, nbuf,
|
return error;
|
||||||
rl->rl_rnd_ipid, rl->rl_minttl, rl->rl_maxmss);
|
|
||||||
}
|
|
||||||
|
|
||||||
*keepstate = (rl->r_attr & NPF_RULE_KEEPSTATE) != 0;
|
|
||||||
rw_exit(&ruleset_lock);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DDB) || defined(_NPF_TESTING)
|
#if defined(DDB) || defined(_NPF_TESTING)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_state.c,v 1.1 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_state.c,v 1.2 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.1 2010/11/11 06:30:39 rmind Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.2 2010/12/18 01:07:25 rmind Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
|
@ -146,10 +146,12 @@ npf_tcp_inwindow(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst,
|
||||||
* that is, upper boundary for valid data (I).
|
* that is, upper boundary for valid data (I).
|
||||||
*/
|
*/
|
||||||
if (!SEQ_GEQ(fstate->nst_ackend, end)) {
|
if (!SEQ_GEQ(fstate->nst_ackend, end)) {
|
||||||
|
npf_stats_inc(NPF_STAT_INVALID_STATE_TCP1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* Lower boundary (II), which is no more than one window back. */
|
/* Lower boundary (II), which is no more than one window back. */
|
||||||
if (!SEQ_GEQ(seq, fstate->nst_seqend - tstate->nst_maxwin)) {
|
if (!SEQ_GEQ(seq, fstate->nst_seqend - tstate->nst_maxwin)) {
|
||||||
|
npf_stats_inc(NPF_STAT_INVALID_STATE_TCP2);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -158,10 +160,13 @@ npf_tcp_inwindow(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst,
|
||||||
*/
|
*/
|
||||||
ackskew = tstate->nst_seqend - ack;
|
ackskew = tstate->nst_seqend - ack;
|
||||||
if (ackskew < -MAXACKWINDOW || ackskew > MAXACKWINDOW) {
|
if (ackskew < -MAXACKWINDOW || ackskew > MAXACKWINDOW) {
|
||||||
|
npf_stats_inc(NPF_STAT_INVALID_STATE_TCP3);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* Packet is passed now.
|
||||||
|
*
|
||||||
* Negative ackskew might be due to fragmented packets. Since the
|
* Negative ackskew might be due to fragmented packets. Since the
|
||||||
* total length of the packet is unknown - bump the boundary.
|
* total length of the packet is unknown - bump the boundary.
|
||||||
*/
|
*/
|
||||||
|
@ -188,6 +193,7 @@ npf_state_tcp(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst,
|
||||||
{
|
{
|
||||||
const struct tcphdr *th = &npc->npc_l4.tcp;
|
const struct tcphdr *th = &npc->npc_l4.tcp;
|
||||||
const int tcpfl = th->th_flags;
|
const int tcpfl = th->th_flags;
|
||||||
|
int nstate = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle 3-way handshake (SYN -> SYN,ACK -> ACK).
|
* Handle 3-way handshake (SYN -> SYN,ACK -> ACK).
|
||||||
|
@ -195,19 +201,16 @@ npf_state_tcp(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst,
|
||||||
switch (nst->nst_state) {
|
switch (nst->nst_state) {
|
||||||
case ST_ESTABLISHED:
|
case ST_ESTABLISHED:
|
||||||
/* Common case - connection established. */
|
/* Common case - connection established. */
|
||||||
if (tcpfl & TH_ACK) {
|
if (__predict_false(tcpfl & (TH_FIN | TH_RST))) {
|
||||||
/*
|
/* Handle connection closure (FIN or RST). */
|
||||||
* Data transmission.
|
nstate = ST_CLOSING;
|
||||||
*/
|
|
||||||
} else if (tcpfl & TH_FIN) {
|
|
||||||
/* XXX TODO */
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ST_OPENING:
|
case ST_OPENING:
|
||||||
/* SYN has been sent, expecting SYN-ACK. */
|
/* SYN has been sent, expecting SYN-ACK. */
|
||||||
if (tcpfl == (TH_SYN | TH_ACK) && !forw) {
|
if (tcpfl == (TH_SYN | TH_ACK) && !forw) {
|
||||||
/* Received backwards SYN-ACK. */
|
/* Received backwards SYN-ACK. */
|
||||||
nst->nst_state = ST_ACKNOWLEDGE;
|
nstate = ST_ACKNOWLEDGE;
|
||||||
} else if (tcpfl == TH_SYN && forw) {
|
} else if (tcpfl == TH_SYN && forw) {
|
||||||
/* Re-transmission of SYN. */
|
/* Re-transmission of SYN. */
|
||||||
} else {
|
} else {
|
||||||
|
@ -217,7 +220,7 @@ npf_state_tcp(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst,
|
||||||
case ST_ACKNOWLEDGE:
|
case ST_ACKNOWLEDGE:
|
||||||
/* SYN-ACK was seen, expecting ACK. */
|
/* SYN-ACK was seen, expecting ACK. */
|
||||||
if (tcpfl == TH_ACK && forw) {
|
if (tcpfl == TH_ACK && forw) {
|
||||||
nst->nst_state = ST_ESTABLISHED;
|
nstate = ST_ESTABLISHED;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -229,7 +232,15 @@ npf_state_tcp(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst,
|
||||||
npf_state_dump(nst);
|
npf_state_dump(nst);
|
||||||
KASSERT(false);
|
KASSERT(false);
|
||||||
}
|
}
|
||||||
return npf_tcp_inwindow(npc, nbuf, nst, forw);
|
#if 0
|
||||||
|
if (!npf_tcp_inwindow(npc, nbuf, nst, forw)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (__predict_false(nstate)) {
|
||||||
|
nst->nst_state = nstate;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -238,20 +249,24 @@ npf_state_init(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst)
|
||||||
const int proto = npf_cache_ipproto(npc);
|
const int proto = npf_cache_ipproto(npc);
|
||||||
|
|
||||||
KASSERT(npf_iscached(npc, NPC_IP46 | NPC_LAYER4));
|
KASSERT(npf_iscached(npc, NPC_IP46 | NPC_LAYER4));
|
||||||
|
|
||||||
|
mutex_init(&nst->nst_lock, MUTEX_DEFAULT, IPL_SOFTNET);
|
||||||
|
nst->nst_state = ST_OPENING;
|
||||||
|
|
||||||
if (proto == IPPROTO_TCP) {
|
if (proto == IPPROTO_TCP) {
|
||||||
const struct tcphdr *th = &npc->npc_l4.tcp;
|
const struct tcphdr *th = &npc->npc_l4.tcp;
|
||||||
/* TCP case: must be SYN. */
|
/* TCP case: must be SYN. */
|
||||||
KASSERT(npf_iscached(npc, NPC_TCP));
|
KASSERT(npf_iscached(npc, NPC_TCP));
|
||||||
if (th->th_flags != TH_SYN) {
|
if (th->th_flags != TH_SYN) {
|
||||||
|
npf_stats_inc(NPF_STAT_INVALID_STATE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* Initial values for TCP window and sequence tracking. */
|
/* Initial values for TCP window and sequence tracking. */
|
||||||
if (!npf_tcp_inwindow(npc, nbuf, nst, true)) {
|
if (!npf_tcp_inwindow(npc, nbuf, nst, true)) {
|
||||||
|
npf_stats_inc(NPF_STAT_INVALID_STATE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_init(&nst->nst_lock, MUTEX_DEFAULT, IPL_SOFTNET);
|
|
||||||
nst->nst_state = ST_OPENING;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +299,9 @@ npf_state_inspect(const npf_cache_t *npc, nbuf_t *nbuf,
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
mutex_exit(&nst->nst_lock);
|
mutex_exit(&nst->nst_lock);
|
||||||
|
if (__predict_false(!ret)) {
|
||||||
|
npf_stats_inc(NPF_STAT_INVALID_STATE);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_tableset.c,v 1.3 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_tableset.c,v 1.4 2010/12/18 01:07:25 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -30,10 +30,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NPF table module.
|
* NPF tableset module.
|
||||||
*
|
|
||||||
* table_lock ->
|
|
||||||
* npf_table_t::t_lock
|
|
||||||
*
|
*
|
||||||
* TODO:
|
* TODO:
|
||||||
* - Currently, code is modeled to handle IPv4 CIDR blocks.
|
* - Currently, code is modeled to handle IPv4 CIDR blocks.
|
||||||
|
@ -42,7 +39,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.3 2010/11/11 06:30:39 rmind Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.4 2010/12/18 01:07:25 rmind Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
|
@ -63,7 +60,7 @@ struct npf_tblent {
|
||||||
/* Hash/tree entry. */
|
/* Hash/tree entry. */
|
||||||
union {
|
union {
|
||||||
LIST_ENTRY(npf_tblent) hashq;
|
LIST_ENTRY(npf_tblent) hashq;
|
||||||
struct rb_node rbnode;
|
rb_node_t rbnode;
|
||||||
} te_entry;
|
} te_entry;
|
||||||
/* IPv4 CIDR block. */
|
/* IPv4 CIDR block. */
|
||||||
in_addr_t te_addr;
|
in_addr_t te_addr;
|
||||||
|
@ -87,39 +84,24 @@ struct npf_table {
|
||||||
rb_tree_t t_rbtree;
|
rb_tree_t t_rbtree;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Global table array and its lock. */
|
static pool_cache_t tblent_cache __read_mostly;
|
||||||
static npf_tableset_t * table_array;
|
|
||||||
static krwlock_t table_lock;
|
|
||||||
static pool_cache_t tblent_cache;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* npf_table_sysinit: initialise tableset structures.
|
* npf_table_sysinit: initialise tableset structures.
|
||||||
*/
|
*/
|
||||||
int
|
void
|
||||||
npf_tableset_sysinit(void)
|
npf_tableset_sysinit(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
tblent_cache = pool_cache_init(sizeof(npf_tblent_t), coherency_unit,
|
tblent_cache = pool_cache_init(sizeof(npf_tblent_t), coherency_unit,
|
||||||
0, 0, "npftenpl", NULL, IPL_NONE, NULL, NULL, NULL);
|
0, 0, "npftenpl", NULL, IPL_NONE, NULL, NULL, NULL);
|
||||||
if (tblent_cache == NULL) {
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
table_array = npf_tableset_create();
|
|
||||||
if (table_array == NULL) {
|
|
||||||
pool_cache_destroy(tblent_cache);
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
rw_init(&table_lock);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
npf_tableset_sysfini(void)
|
npf_tableset_sysfini(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
npf_tableset_destroy(table_array);
|
|
||||||
pool_cache_destroy(tblent_cache);
|
pool_cache_destroy(tblent_cache);
|
||||||
rw_destroy(&table_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
npf_tableset_t *
|
npf_tableset_t *
|
||||||
|
@ -172,25 +154,6 @@ npf_tableset_insert(npf_tableset_t *tblset, npf_table_t *t)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* npf_tableset_reload: replace old tableset array with a new one.
|
|
||||||
*
|
|
||||||
* => Called from npf_ruleset_reload() with a global ruleset lock held.
|
|
||||||
* => Returns pointer to the old tableset, caller will destroy it.
|
|
||||||
*/
|
|
||||||
npf_tableset_t *
|
|
||||||
npf_tableset_reload(npf_tableset_t *tblset)
|
|
||||||
{
|
|
||||||
npf_tableset_t *oldtblset;
|
|
||||||
|
|
||||||
rw_enter(&table_lock, RW_WRITER);
|
|
||||||
oldtblset = table_array;
|
|
||||||
table_array = tblset;
|
|
||||||
rw_exit(&table_lock);
|
|
||||||
|
|
||||||
return oldtblset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Red-black tree storage.
|
* Red-black tree storage.
|
||||||
*/
|
*/
|
||||||
|
@ -341,24 +304,25 @@ npf_table_unref(npf_table_t *t)
|
||||||
npf_table_t *
|
npf_table_t *
|
||||||
npf_table_get(npf_tableset_t *tset, u_int tid)
|
npf_table_get(npf_tableset_t *tset, u_int tid)
|
||||||
{
|
{
|
||||||
|
npf_tableset_t *rtset;
|
||||||
npf_table_t *t;
|
npf_table_t *t;
|
||||||
|
|
||||||
if ((u_int)tid >= NPF_TABLE_SLOTS) {
|
if ((u_int)tid >= NPF_TABLE_SLOTS) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (tset) {
|
if (tset == NULL) {
|
||||||
t = tset[tid];
|
npf_core_enter();
|
||||||
if (t != NULL) {
|
rtset = npf_core_tableset();
|
||||||
rw_enter(&t->t_lock, RW_READER);
|
} else {
|
||||||
}
|
rtset = tset;
|
||||||
return t;
|
|
||||||
}
|
}
|
||||||
rw_enter(&table_lock, RW_READER);
|
t = rtset[tid];
|
||||||
t = table_array[tid];
|
|
||||||
if (t != NULL) {
|
if (t != NULL) {
|
||||||
rw_enter(&t->t_lock, RW_READER);
|
rw_enter(&t->t_lock, RW_READER);
|
||||||
}
|
}
|
||||||
rw_exit(&table_lock);
|
if (tset == NULL) {
|
||||||
|
npf_core_exit();
|
||||||
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,9 +370,6 @@ npf_table_add_v4cidr(npf_tableset_t *tset, u_int tid,
|
||||||
|
|
||||||
/* Allocate and setup entry. */
|
/* Allocate and setup entry. */
|
||||||
e = pool_cache_get(tblent_cache, PR_WAITOK);
|
e = pool_cache_get(tblent_cache, PR_WAITOK);
|
||||||
if (e == NULL) {
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
e->te_addr = addr;
|
e->te_addr = addr;
|
||||||
e->te_mask = mask;
|
e->te_mask = mask;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_data.c,v 1.4 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_data.c,v 1.5 2010/12/18 01:07:26 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__RCSID("$NetBSD: npf_data.c,v 1.4 2010/11/11 06:30:39 rmind Exp $");
|
__RCSID("$NetBSD: npf_data.c,v 1.5 2010/12/18 01:07:26 rmind Exp $");
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
@ -67,16 +67,12 @@ static pri_t nat_prio_counter = 1;
|
||||||
void
|
void
|
||||||
npfctl_init_data(void)
|
npfctl_init_data(void)
|
||||||
{
|
{
|
||||||
prop_number_t ver;
|
|
||||||
|
|
||||||
if (getifaddrs(&ifs_list) == -1)
|
if (getifaddrs(&ifs_list) == -1)
|
||||||
err(EXIT_FAILURE, "getifaddrs");
|
err(EXIT_FAILURE, "getifaddrs");
|
||||||
|
|
||||||
npf_dict = prop_dictionary_create();
|
npf_dict = prop_dictionary_create();
|
||||||
|
|
||||||
ver = prop_number_create_integer(NPF_VERSION);
|
|
||||||
prop_dictionary_set(npf_dict, "version", ver);
|
|
||||||
|
|
||||||
nat_arr = prop_array_create();
|
nat_arr = prop_array_create();
|
||||||
prop_dictionary_set(npf_dict, "translation", nat_arr);
|
prop_dictionary_set(npf_dict, "translation", nat_arr);
|
||||||
|
|
||||||
|
@ -108,6 +104,42 @@ npfctl_ioctl_send(int fd)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
npfctl_ioctl_sendse(int fd)
|
||||||
|
{
|
||||||
|
prop_dictionary_t sesdict;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
sesdict = prop_dictionary_internalize_from_file(NPF_SESSDB_PATH);
|
||||||
|
if (sesdict == NULL) {
|
||||||
|
errx(EXIT_FAILURE, "npfctl: no sessions saved "
|
||||||
|
"('%s' does not exist)", NPF_SESSDB_PATH);
|
||||||
|
}
|
||||||
|
error = prop_dictionary_send_ioctl(sesdict, fd, IOC_NPF_SESSIONS_LOAD);
|
||||||
|
prop_object_release(sesdict);
|
||||||
|
if (error) {
|
||||||
|
err(EXIT_FAILURE, "npfctl_ioctl_sendse");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
npfctl_ioctl_recvse(int fd)
|
||||||
|
{
|
||||||
|
prop_dictionary_t sesdict;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = prop_dictionary_recv_ioctl(fd, IOC_NPF_SESSIONS_SAVE, &sesdict);
|
||||||
|
if (error) {
|
||||||
|
err(EXIT_FAILURE, "prop_array_recv_ioctl");
|
||||||
|
}
|
||||||
|
if (!prop_dictionary_externalize_to_file(sesdict, NPF_SESSDB_PATH)) {
|
||||||
|
errx(EXIT_FAILURE, "could not save to '%s'", NPF_SESSDB_PATH);
|
||||||
|
}
|
||||||
|
prop_object_release(sesdict);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper routines:
|
* Helper routines:
|
||||||
*
|
*
|
||||||
|
@ -393,22 +425,27 @@ npfctl_add_rule(prop_dictionary_t rl, prop_dictionary_t parent)
|
||||||
|
|
||||||
void
|
void
|
||||||
npfctl_rule_setattr(prop_dictionary_t rl, int attr, char *iface,
|
npfctl_rule_setattr(prop_dictionary_t rl, int attr, char *iface,
|
||||||
bool ipid_rnd, int minttl, int maxmss)
|
char *logiface, bool ipid_rnd, int minttl, int maxmss, bool no_df)
|
||||||
{
|
{
|
||||||
prop_number_t attrnum;
|
prop_number_t attrnum, ifnum;
|
||||||
|
unsigned int if_idx;
|
||||||
|
|
||||||
attrnum = prop_number_create_integer(attr);
|
attrnum = prop_number_create_integer(attr);
|
||||||
prop_dictionary_set(rl, "attributes", attrnum);
|
prop_dictionary_set(rl, "attributes", attrnum);
|
||||||
if (iface) {
|
if (iface) {
|
||||||
prop_number_t ifnum;
|
|
||||||
unsigned int if_idx;
|
|
||||||
|
|
||||||
if (npfctl_getif(iface, &if_idx) == NULL) {
|
if (npfctl_getif(iface, &if_idx) == NULL) {
|
||||||
errx(EXIT_FAILURE, "invalid interface '%s'", iface);
|
errx(EXIT_FAILURE, "invalid interface '%s'", iface);
|
||||||
}
|
}
|
||||||
ifnum = prop_number_create_integer(if_idx);
|
ifnum = prop_number_create_integer(if_idx);
|
||||||
prop_dictionary_set(rl, "interface", ifnum);
|
prop_dictionary_set(rl, "interface", ifnum);
|
||||||
}
|
}
|
||||||
|
if (logiface) {
|
||||||
|
if (npfctl_getif(logiface, &if_idx) == NULL) {
|
||||||
|
errx(EXIT_FAILURE, "invalid interface '%s'", logiface);
|
||||||
|
}
|
||||||
|
ifnum = prop_number_create_integer(if_idx);
|
||||||
|
prop_dictionary_set(rl, "log-interface", ifnum);
|
||||||
|
}
|
||||||
if (attr & NPF_RULE_NORMALIZE) {
|
if (attr & NPF_RULE_NORMALIZE) {
|
||||||
prop_dictionary_set(rl, "randomize-id",
|
prop_dictionary_set(rl, "randomize-id",
|
||||||
prop_bool_create(ipid_rnd));
|
prop_bool_create(ipid_rnd));
|
||||||
|
@ -416,6 +453,8 @@ npfctl_rule_setattr(prop_dictionary_t rl, int attr, char *iface,
|
||||||
prop_number_create_integer(minttl));
|
prop_number_create_integer(minttl));
|
||||||
prop_dictionary_set(rl, "max-mss",
|
prop_dictionary_set(rl, "max-mss",
|
||||||
prop_number_create_integer(maxmss));
|
prop_number_create_integer(maxmss));
|
||||||
|
prop_dictionary_set(rl, "no-df",
|
||||||
|
prop_bool_create(no_df));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +491,8 @@ npfctl_rulenc_v4cidr(void **nc, int nblocks[], var_t *dat, bool sd)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
npfctl_rulenc_ports(void **nc, int nblocks[], var_t *dat, bool tcpudp, bool sd)
|
npfctl_rulenc_ports(void **nc, int nblocks[], var_t *dat, bool tcpudp,
|
||||||
|
bool both, bool sd)
|
||||||
{
|
{
|
||||||
element_t *el = dat->v_elements;
|
element_t *el = dat->v_elements;
|
||||||
int foff;
|
int foff;
|
||||||
|
@ -468,7 +508,7 @@ npfctl_rulenc_ports(void **nc, int nblocks[], var_t *dat, bool tcpudp, bool sd)
|
||||||
errx(EXIT_FAILURE, "invalid service '%s'", el->e_data);
|
errx(EXIT_FAILURE, "invalid service '%s'", el->e_data);
|
||||||
}
|
}
|
||||||
nblocks[0]--;
|
nblocks[0]--;
|
||||||
foff = npfctl_failure_offset(nblocks);
|
foff = both ? 0 : npfctl_failure_offset(nblocks);
|
||||||
npfctl_gennc_ports(nc, foff, fport, tport, tcpudp, sd);
|
npfctl_gennc_ports(nc, foff, fport, tport, tcpudp, sd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -482,11 +522,11 @@ npfctl_rulenc_block(void **nc, int nblocks[], var_t *cidr, var_t *ports,
|
||||||
if (ports == NULL) {
|
if (ports == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
npfctl_rulenc_ports(nc, nblocks, ports, tcpudp, sd);
|
npfctl_rulenc_ports(nc, nblocks, ports, tcpudp, both, sd);
|
||||||
if (!both) {
|
if (!both) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
npfctl_rulenc_ports(nc, nblocks, ports, !tcpudp, sd);
|
npfctl_rulenc_ports(nc, nblocks, ports, !tcpudp, false, sd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -505,10 +545,11 @@ npfctl_rule_protodata(prop_dictionary_t rl, char *proto, char *tcp_flags,
|
||||||
*/
|
*/
|
||||||
icmp = false;
|
icmp = false;
|
||||||
tcpudp = true;
|
tcpudp = true;
|
||||||
both = false;
|
|
||||||
if (proto == NULL) {
|
if (proto == NULL) {
|
||||||
|
both = true;
|
||||||
goto skip_proto;
|
goto skip_proto;
|
||||||
}
|
}
|
||||||
|
both = false;
|
||||||
|
|
||||||
if (strcmp(proto, "icmp") == 0) {
|
if (strcmp(proto, "icmp") == 0) {
|
||||||
/* ICMP case. */
|
/* ICMP case. */
|
||||||
|
@ -661,7 +702,7 @@ npfctl_nat_setup(prop_dictionary_t rl, int type, int flags,
|
||||||
{
|
{
|
||||||
int attr = NPF_RULE_PASS | NPF_RULE_FINAL;
|
int attr = NPF_RULE_PASS | NPF_RULE_FINAL;
|
||||||
in_addr_t addr, mask;
|
in_addr_t addr, mask;
|
||||||
void *addrptr;
|
prop_data_t addrdat;
|
||||||
|
|
||||||
/* Translation type and flags. */
|
/* Translation type and flags. */
|
||||||
prop_dictionary_set(rl, "type",
|
prop_dictionary_set(rl, "type",
|
||||||
|
@ -671,15 +712,15 @@ npfctl_nat_setup(prop_dictionary_t rl, int type, int flags,
|
||||||
|
|
||||||
/* Interface and attributes. */
|
/* Interface and attributes. */
|
||||||
attr |= (type == NPF_NATOUT) ? NPF_RULE_OUT : NPF_RULE_IN;
|
attr |= (type == NPF_NATOUT) ? NPF_RULE_OUT : NPF_RULE_IN;
|
||||||
npfctl_rule_setattr(rl, attr, iface, false, 0, 0);
|
npfctl_rule_setattr(rl, attr, iface, NULL, false, 0, 0, false);
|
||||||
|
|
||||||
/* Translation IP, XXX should be no mask. */
|
/* Translation IP, XXX should be no mask. */
|
||||||
npfctl_parse_cidr(taddr, &addr, &mask);
|
npfctl_parse_cidr(taddr, &addr, &mask);
|
||||||
addrptr = prop_data_create_data(&addr, sizeof(in_addr_t));
|
addrdat = prop_data_create_data(&addr, sizeof(in_addr_t));
|
||||||
if (addrptr == NULL) {
|
if (addrdat == NULL) {
|
||||||
err(EXIT_FAILURE, "prop_data_create_data");
|
err(EXIT_FAILURE, "prop_data_create_data");
|
||||||
}
|
}
|
||||||
prop_dictionary_set(rl, "translation-ip", addrptr);
|
prop_dictionary_set(rl, "translation-ip", addrdat);
|
||||||
|
|
||||||
/* Translation port (for redirect case). */
|
/* Translation port (for redirect case). */
|
||||||
if (rport) {
|
if (rport) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_ncgen.c,v 1.3 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_ncgen.c,v 1.4 2010/12/18 01:07:26 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__RCSID("$NetBSD: npf_ncgen.c,v 1.3 2010/11/11 06:30:39 rmind Exp $");
|
__RCSID("$NetBSD: npf_ncgen.c,v 1.4 2010/12/18 01:07:26 rmind Exp $");
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
@ -152,9 +152,18 @@ npfctl_gennc_ports(void **ncptr, int foff,
|
||||||
*nc++ = (sd ? 0x01 : 0x00);
|
*nc++ = (sd ? 0x01 : 0x00);
|
||||||
*nc++ = ((uint32_t)pfrom << 16) | pto;
|
*nc++ = ((uint32_t)pfrom << 16) | pto;
|
||||||
|
|
||||||
/* If not equal, jump to failure block, continue otherwise (2 words). */
|
/*
|
||||||
*nc++ = NPF_OPCODE_BNE;
|
* If not equal, jump to failure block, continue otherwise (2 words).
|
||||||
*nc++ = foff;
|
* Specific case (foff == 0): when matching both TCP and UDP ports,
|
||||||
|
* skip next port-matching fragment on success (5 + 2 words).
|
||||||
|
*/
|
||||||
|
if (foff) {
|
||||||
|
*nc++ = NPF_OPCODE_BNE;
|
||||||
|
*nc++ = foff;
|
||||||
|
} else {
|
||||||
|
*nc++ = NPF_OPCODE_BEQ;
|
||||||
|
*nc++ = 5 + 2;
|
||||||
|
}
|
||||||
|
|
||||||
/* + 5 words. */
|
/* + 5 words. */
|
||||||
*ncptr = (void *)nc;
|
*ncptr = (void *)nc;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npf_parser.c,v 1.3 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npf_parser.c,v 1.4 2010/12/18 01:07:26 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__RCSID("$NetBSD: npf_parser.c,v 1.3 2010/11/11 06:30:39 rmind Exp $");
|
__RCSID("$NetBSD: npf_parser.c,v 1.4 2010/12/18 01:07:26 rmind Exp $");
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -144,7 +144,7 @@ npfctl_parsevalue(char *buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
npfctl_parsenorm(char *buf, bool *rnd, int *minttl, int *maxmss)
|
npfctl_parsenorm(char *buf, bool *rnd, int *minttl, int *maxmss, bool *no_df)
|
||||||
{
|
{
|
||||||
char *p = buf, *sptr;
|
char *p = buf, *sptr;
|
||||||
|
|
||||||
|
@ -163,6 +163,8 @@ npfctl_parsenorm(char *buf, bool *rnd, int *minttl, int *maxmss)
|
||||||
} else if (strcmp(p, "max-mss") == 0) {
|
} else if (strcmp(p, "max-mss") == 0) {
|
||||||
p = strtok_r(NULL, ", \t", &sptr);
|
p = strtok_r(NULL, ", \t", &sptr);
|
||||||
*maxmss = atoi(p);
|
*maxmss = atoi(p);
|
||||||
|
} else if (strcmp(p, "no-df") == 0) {
|
||||||
|
*no_df = true;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -185,9 +187,9 @@ npfctl_parserule(char *buf, prop_dictionary_t rl)
|
||||||
{
|
{
|
||||||
var_t *from_cidr = NULL, *fports = NULL;
|
var_t *from_cidr = NULL, *fports = NULL;
|
||||||
var_t *to_cidr = NULL, *tports = NULL;
|
var_t *to_cidr = NULL, *tports = NULL;
|
||||||
char *p, *sptr, *iface, *proto = NULL, *tcp_flags = NULL;
|
char *p, *sptr, *iface, *logiface, *proto = NULL, *tcp_flags = NULL;
|
||||||
int icmp_type = -1, icmp_code = -1, minttl = 0, maxmss = 0;
|
int icmp_type = -1, icmp_code = -1, minttl = 0, maxmss = 0;
|
||||||
bool icmp = false, tcp = false, rnd = false;
|
bool icmp = false, tcp = false, rnd = false, no_df = false;
|
||||||
int ret, attr = 0;
|
int ret, attr = 0;
|
||||||
|
|
||||||
DPRINTF(("rule\t|%s|\n", buf));
|
DPRINTF(("rule\t|%s|\n", buf));
|
||||||
|
@ -228,10 +230,24 @@ npfctl_parserule(char *buf, prop_dictionary_t rl)
|
||||||
attr |= (NPF_RULE_IN | NPF_RULE_OUT);
|
attr |= (NPF_RULE_IN | NPF_RULE_OUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* log (XXX: NOP) */
|
/* log <interface> */
|
||||||
if (strcmp(p, "log") == 0) {
|
if (strcmp(p, "log") == 0) {
|
||||||
|
var_t *ifvar;
|
||||||
|
element_t *el;
|
||||||
|
|
||||||
|
PARSE_NEXT_TOKEN();
|
||||||
|
if ((ifvar = npfctl_parsevalue(p)) == NULL)
|
||||||
|
return PARSE_ERR();
|
||||||
|
if (ifvar->v_type != VAR_SINGLE) {
|
||||||
|
errx(EXIT_FAILURE, "invalid interface value '%s'", p);
|
||||||
|
}
|
||||||
|
el = ifvar->v_elements;
|
||||||
|
logiface = el->e_data;
|
||||||
|
|
||||||
attr |= NPF_RULE_LOG;
|
attr |= NPF_RULE_LOG;
|
||||||
PARSE_NEXT_TOKEN();
|
PARSE_NEXT_TOKEN();
|
||||||
|
} else {
|
||||||
|
logiface = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* count */
|
/* count */
|
||||||
|
@ -379,7 +395,7 @@ last:
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
return PARSE_ERR();
|
return PARSE_ERR();
|
||||||
}
|
}
|
||||||
if (npfctl_parsenorm(p, &rnd, &minttl, &maxmss)) {
|
if (npfctl_parsenorm(p, &rnd, &minttl, &maxmss, &no_df)) {
|
||||||
return PARSE_ERR();
|
return PARSE_ERR();
|
||||||
}
|
}
|
||||||
attr |= NPF_RULE_NORMALIZE;
|
attr |= NPF_RULE_NORMALIZE;
|
||||||
|
@ -392,7 +408,8 @@ last:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the rule attributes and interface, if any. */
|
/* Set the rule attributes and interface, if any. */
|
||||||
npfctl_rule_setattr(rl, attr, iface, rnd, minttl, maxmss);
|
npfctl_rule_setattr(rl, attr, iface, logiface,
|
||||||
|
rnd, minttl, maxmss, no_df);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate all protocol data.
|
* Generate all protocol data.
|
||||||
|
@ -439,7 +456,7 @@ npfctl_parsegroup(char *buf, prop_dictionary_t rl)
|
||||||
attr_dir = NPF_RULE_IN | NPF_RULE_OUT;
|
attr_dir = NPF_RULE_IN | NPF_RULE_OUT;
|
||||||
npfctl_rule_setattr(rl,
|
npfctl_rule_setattr(rl,
|
||||||
GROUP_ATTRS | NPF_RULE_DEFAULT | attr_dir, NULL,
|
GROUP_ATTRS | NPF_RULE_DEFAULT | attr_dir, NULL,
|
||||||
false, 0, 0);
|
NULL, false, 0, 0, false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,7 +503,8 @@ npfctl_parsegroup(char *buf, prop_dictionary_t rl)
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
npfctl_rule_setattr(rl, GROUP_ATTRS | attr_dir, iface, false, 0, 0);
|
npfctl_rule_setattr(rl, GROUP_ATTRS | attr_dir, iface, NULL,
|
||||||
|
false, 0, 0, false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npfctl.c,v 1.2 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npfctl.c,v 1.3 2010/12/18 01:07:26 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__RCSID("$NetBSD: npfctl.c,v 1.2 2010/11/11 06:30:39 rmind Exp $");
|
__RCSID("$NetBSD: npfctl.c,v 1.3 2010/12/18 01:07:26 rmind Exp $");
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -50,20 +50,28 @@ __RCSID("$NetBSD: npfctl.c,v 1.2 2010/11/11 06:30:39 rmind Exp $");
|
||||||
#define NPFCTL_RELOAD 3
|
#define NPFCTL_RELOAD 3
|
||||||
#define NPFCTL_FLUSH 4
|
#define NPFCTL_FLUSH 4
|
||||||
#define NPFCTL_TABLE 5
|
#define NPFCTL_TABLE 5
|
||||||
|
#define NPFCTL_STATS 6
|
||||||
|
#define NPFCTL_SESSIONS_SAVE 7
|
||||||
|
#define NPFCTL_SESSIONS_LOAD 8
|
||||||
|
|
||||||
static struct operations_s {
|
static struct operations_s {
|
||||||
const char * cmd;
|
const char * cmd;
|
||||||
int action;
|
int action;
|
||||||
} operations[] = {
|
} operations[] = {
|
||||||
/* Start, stop, reload */
|
/* Start, stop, reload */
|
||||||
{ "start", NPFCTL_START },
|
{ "start", NPFCTL_START },
|
||||||
{ "stop", NPFCTL_STOP },
|
{ "stop", NPFCTL_STOP },
|
||||||
{ "reload", NPFCTL_RELOAD },
|
{ "reload", NPFCTL_RELOAD },
|
||||||
{ "flush", NPFCTL_FLUSH },
|
{ "flush", NPFCTL_FLUSH },
|
||||||
/* Table */
|
/* Table */
|
||||||
{ "table", NPFCTL_TABLE },
|
{ "table", NPFCTL_TABLE },
|
||||||
|
/* Stats */
|
||||||
|
{ "stats", NPFCTL_STATS },
|
||||||
|
/* Sessions */
|
||||||
|
{ "sess-save", NPFCTL_SESSIONS_SAVE },
|
||||||
|
{ "sess-load", NPFCTL_SESSIONS_LOAD },
|
||||||
/* --- */
|
/* --- */
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
void *
|
void *
|
||||||
|
@ -99,7 +107,10 @@ usage(void)
|
||||||
const char *progname = getprogname();
|
const char *progname = getprogname();
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"usage:\t%s [ start | stop | reload ]\n",
|
"usage:\t%s [ start | stop | reload | flush | stats ]\n",
|
||||||
|
progname);
|
||||||
|
fprintf(stderr,
|
||||||
|
"usage:\t%s [ sess-save | sess-load ]\n",
|
||||||
progname);
|
progname);
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"\t%s table <tid> [ flush ]\n",
|
"\t%s table <tid> [ flush ]\n",
|
||||||
|
@ -141,6 +152,44 @@ npfctl_parsecfg(const char *cfg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
npfctl_print_stats(int fd)
|
||||||
|
{
|
||||||
|
uint64_t *st = malloc(NPF_STATS_SIZE);
|
||||||
|
|
||||||
|
if (ioctl(fd, IOC_NPF_STATS, &st) != 0) {
|
||||||
|
err(EXIT_FAILURE, "ioctl(IOC_NPF_STATS)");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Packets passed:\n\t%"PRIu64" default pass\n\t"
|
||||||
|
"%"PRIu64 " ruleset pass\n\t%"PRIu64" session pass\n\n",
|
||||||
|
st[NPF_STAT_PASS_DEFAULT], st[NPF_STAT_PASS_RULESET],
|
||||||
|
st[NPF_STAT_PASS_SESSION]);
|
||||||
|
|
||||||
|
printf("Packets blocked:\n\t%"PRIu64" default block\n\t"
|
||||||
|
"%"PRIu64 " ruleset block\n\n", st[NPF_STAT_BLOCK_DEFAULT],
|
||||||
|
st[NPF_STAT_BLOCK_RULESET]);
|
||||||
|
|
||||||
|
printf("Session and NAT entries:\n\t%"PRIu64" session allocations\n\t"
|
||||||
|
"%"PRIu64" session destructions\n\t%"PRIu64" NAT entry allocations\n\t"
|
||||||
|
"%"PRIu64" NAT entry destructions\n\n", st[NPF_STAT_SESSION_CREATE],
|
||||||
|
st[NPF_STAT_SESSION_DESTROY], st[NPF_STAT_NAT_CREATE],
|
||||||
|
st[NPF_STAT_NAT_DESTROY]);
|
||||||
|
|
||||||
|
printf("Invalid packet state cases:\n\t%"PRIu64" cases in total\n\t"
|
||||||
|
"%"PRIu64" TCP case I\n\t%"PRIu64" TCP case II\n\t%"PRIu64
|
||||||
|
" TCP case III\n\n", st[NPF_STAT_INVALID_STATE],
|
||||||
|
st[NPF_STAT_INVALID_STATE_TCP1], st[NPF_STAT_INVALID_STATE_TCP2],
|
||||||
|
st[NPF_STAT_INVALID_STATE_TCP3]);
|
||||||
|
|
||||||
|
printf("Packet race cases:\n\t%"PRIu64" NAT association race\n\t"
|
||||||
|
"%"PRIu64" duplicate session race\n", st[NPF_STAT_RACE_NAT],
|
||||||
|
st[NPF_STAT_RACE_SESSION]);
|
||||||
|
|
||||||
|
free(st);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
npfctl(int action, int argc, char **argv)
|
npfctl(int action, int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -148,6 +197,7 @@ npfctl(int action, int argc, char **argv)
|
||||||
npf_ioctl_table_t tbl;
|
npf_ioctl_table_t tbl;
|
||||||
char *arg;
|
char *arg;
|
||||||
|
|
||||||
|
#ifndef DEBUG
|
||||||
fd = open(NPF_DEV_PATH, O_RDONLY);
|
fd = open(NPF_DEV_PATH, O_RDONLY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
err(EXIT_FAILURE, "cannot open " NPF_DEV_PATH);
|
err(EXIT_FAILURE, "cannot open " NPF_DEV_PATH);
|
||||||
|
@ -157,6 +207,7 @@ npfctl(int action, int argc, char **argv)
|
||||||
errx(EXIT_FAILURE, "incompatible npf interface version "
|
errx(EXIT_FAILURE, "incompatible npf interface version "
|
||||||
"(%d, kernel %d)", NPF_VERSION, ver);
|
"(%d, kernel %d)", NPF_VERSION, ver);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case NPFCTL_START:
|
case NPFCTL_START:
|
||||||
boolval = true;
|
boolval = true;
|
||||||
|
@ -168,6 +219,10 @@ npfctl(int action, int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
case NPFCTL_RELOAD:
|
case NPFCTL_RELOAD:
|
||||||
npfctl_init_data();
|
npfctl_init_data();
|
||||||
|
#ifdef DEBUG
|
||||||
|
npfctl_parsecfg("npf.conf");
|
||||||
|
return npfctl_ioctl_send(0);
|
||||||
|
#endif
|
||||||
npfctl_parsecfg(argc < 3 ? NPF_CONF_PATH : argv[2]);
|
npfctl_parsecfg(argc < 3 ? NPF_CONF_PATH : argv[2]);
|
||||||
ret = npfctl_ioctl_send(fd);
|
ret = npfctl_ioctl_send(fd);
|
||||||
break;
|
break;
|
||||||
|
@ -197,6 +252,15 @@ npfctl(int action, int argc, char **argv)
|
||||||
}
|
}
|
||||||
ret = ioctl(fd, IOC_NPF_TABLE, &tbl);
|
ret = ioctl(fd, IOC_NPF_TABLE, &tbl);
|
||||||
break;
|
break;
|
||||||
|
case NPFCTL_STATS:
|
||||||
|
ret = npfctl_print_stats(fd);
|
||||||
|
break;
|
||||||
|
case NPFCTL_SESSIONS_SAVE:
|
||||||
|
ret = npfctl_ioctl_recvse(fd);
|
||||||
|
break;
|
||||||
|
case NPFCTL_SESSIONS_LOAD:
|
||||||
|
ret = npfctl_ioctl_sendse(fd);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
err(EXIT_FAILURE, "ioctl");
|
err(EXIT_FAILURE, "ioctl");
|
||||||
|
@ -215,18 +279,13 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
cmd = argv[1];
|
cmd = argv[1];
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
npfctl_init_data();
|
|
||||||
npfctl_parsecfg("npf.conf");
|
|
||||||
return npfctl_ioctl_send(0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Find and call the subroutine */
|
/* Find and call the subroutine */
|
||||||
for (n = 0; operations[n].cmd != NULL; n++) {
|
for (n = 0; operations[n].cmd != NULL; n++) {
|
||||||
if (strcmp(cmd, operations[n].cmd) != 0)
|
if (strcmp(cmd, operations[n].cmd) != 0)
|
||||||
continue;
|
continue;
|
||||||
npfctl(operations[n].action, argc, argv);
|
npfctl(operations[n].action, argc, argv);
|
||||||
break;
|
return 0;
|
||||||
}
|
}
|
||||||
|
usage();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: npfctl.h,v 1.3 2010/11/11 06:30:39 rmind Exp $ */
|
/* $NetBSD: npfctl.h,v 1.4 2010/12/18 01:07:26 rmind Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
|
||||||
|
@ -49,6 +49,7 @@
|
||||||
|
|
||||||
#define NPF_DEV_PATH "/dev/npf"
|
#define NPF_DEV_PATH "/dev/npf"
|
||||||
#define NPF_CONF_PATH "/etc/npf.conf"
|
#define NPF_CONF_PATH "/etc/npf.conf"
|
||||||
|
#define NPF_SESSDB_PATH "/var/db/npf_sessions.db"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char * e_data;
|
char * e_data;
|
||||||
|
@ -72,13 +73,15 @@ char * xstrdup(const char *);
|
||||||
|
|
||||||
void npfctl_init_data(void);
|
void npfctl_init_data(void);
|
||||||
int npfctl_ioctl_send(int);
|
int npfctl_ioctl_send(int);
|
||||||
|
int npfctl_ioctl_recvse(int);
|
||||||
|
int npfctl_ioctl_sendse(int);
|
||||||
|
|
||||||
bool npfctl_parse_v4mask(char *, in_addr_t *, in_addr_t *);
|
bool npfctl_parse_v4mask(char *, in_addr_t *, in_addr_t *);
|
||||||
|
|
||||||
prop_dictionary_t npfctl_mk_rule(bool);
|
prop_dictionary_t npfctl_mk_rule(bool);
|
||||||
void npfctl_add_rule(prop_dictionary_t, prop_dictionary_t);
|
void npfctl_add_rule(prop_dictionary_t, prop_dictionary_t);
|
||||||
void npfctl_rule_setattr(prop_dictionary_t, int, char *,
|
void npfctl_rule_setattr(prop_dictionary_t, int, char *,
|
||||||
bool, int, int);
|
char *, bool, int, int, bool);
|
||||||
void npfctl_rule_protodata(prop_dictionary_t, char *, char *,
|
void npfctl_rule_protodata(prop_dictionary_t, char *, char *,
|
||||||
int, int, var_t *, var_t *, var_t *, var_t *);
|
int, int, var_t *, var_t *, var_t *, var_t *);
|
||||||
void npfctl_rule_icmpdata(prop_dictionary_t, var_t *, var_t *);
|
void npfctl_rule_icmpdata(prop_dictionary_t, var_t *, var_t *);
|
||||||
|
|
Loading…
Reference in New Issue