NPF: add support for IPv6-to-IPv6 Network Prefix Translation (NPTv6),

as per RFC 6296.  Add a unit test.  Also, bump NPF_VERSION.

Thanks to S.P.Zeidler for the help with NPTv6 work!
This commit is contained in:
rmind 2014-02-13 03:34:40 +00:00
parent 82f6ff32b1
commit 068cee2998
18 changed files with 423 additions and 103 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf.c,v 1.27 2014/02/07 23:45:22 rmind Exp $ */
/* $NetBSD: npf.c,v 1.28 2014/02/13 03:34:41 rmind Exp $ */
/*-
* Copyright (c) 2010-2014 The NetBSD Foundation, Inc.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.27 2014/02/07 23:45:22 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.28 2014/02/13 03:34:41 rmind Exp $");
#include <sys/types.h>
#include <netinet/in_systm.h>
@ -802,7 +802,7 @@ npf_rproc_getname(nl_rproc_t *rp)
nl_nat_t *
npf_nat_create(int type, u_int flags, const char *ifname,
npf_addr_t *addr, int af, in_port_t port)
int af, npf_addr_t *addr, npf_netmask_t mask, in_port_t port)
{
nl_rule_t *rl;
prop_dictionary_t rldict;
@ -832,13 +832,14 @@ npf_nat_create(int type, u_int flags, const char *ifname,
prop_dictionary_set_int32(rldict, "type", type);
prop_dictionary_set_uint32(rldict, "flags", flags);
/* Translation IP. */
/* Translation IP and mask. */
addrdat = prop_data_create_data(addr, sz);
if (addrdat == NULL) {
npf_rule_destroy(rl);
return NULL;
}
prop_dictionary_set(rldict, "translation-ip", addrdat);
prop_dictionary_set_uint32(rldict, "translation-mask", mask);
prop_object_release(addrdat);
/* Translation port (for redirect case). */
@ -864,6 +865,27 @@ npf_nat_iterate(nl_config_t *ncf)
return _npf_rule_iterate1(ncf, ncf->ncf_nat_list, &level);
}
int
npf_nat_setalgo(nl_nat_t *nt, u_int algo)
{
prop_dictionary_t rldict = nt->nrl_dict;
prop_dictionary_set_uint32(rldict, "translation-algo", algo);
return 0;
}
int
npf_nat_setnpt66(nl_nat_t *nt, uint16_t adj)
{
prop_dictionary_t rldict = nt->nrl_dict;
int error;
if ((error = npf_nat_setalgo(nt, NPF_ALGO_NPT66)) != 0) {
return error;
}
prop_dictionary_set_uint16(rldict, "npt66-adjustment", adj);
return 0;
}
int
npf_nat_gettype(nl_nat_t *nt)
{

View File

@ -1,7 +1,7 @@
/* $NetBSD: npf.h,v 1.24 2014/02/07 23:45:22 rmind Exp $ */
/* $NetBSD: npf.h,v 1.25 2014/02/13 03:34:41 rmind Exp $ */
/*-
* Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
* Copyright (c) 2011-2014 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This material is based upon work partially supported by The
@ -105,7 +105,7 @@ bool npf_rproc_exists_p(nl_config_t *, const char *);
int npf_rproc_insert(nl_config_t *, nl_rproc_t *);
nl_nat_t * npf_nat_create(int, u_int, const char *,
npf_addr_t *, int, in_port_t);
int, npf_addr_t *, npf_netmask_t, in_port_t);
int npf_nat_insert(nl_config_t *, nl_nat_t *, pri_t);
nl_table_t * npf_table_create(const char *, u_int, int);
@ -139,6 +139,9 @@ int npf_nat_gettype(nl_nat_t *);
unsigned npf_nat_getflags(nl_nat_t *);
void npf_nat_getmap(nl_nat_t *, npf_addr_t *, size_t *, in_port_t *);
int npf_nat_setalgo(nl_nat_t *, u_int);
int npf_nat_setnpt66(nl_nat_t *, uint16_t);
nl_rproc_t * npf_rproc_iterate(nl_config_t *);
const char * npf_rproc_getname(nl_rproc_t *);

View File

@ -1,7 +1,7 @@
/* $NetBSD: npf.h,v 1.36 2014/02/07 23:45:22 rmind Exp $ */
/* $NetBSD: npf.h,v 1.37 2014/02/13 03:34:40 rmind Exp $ */
/*-
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This material is based upon work partially supported by The
@ -45,7 +45,7 @@
#include <netinet/in_systm.h>
#include <netinet/in.h>
#define NPF_VERSION 12
#define NPF_VERSION 13
/*
* Public declarations and definitions.
@ -237,6 +237,8 @@ bool npf_autounload_p(void);
#define NPF_NAT_PORTMAP 0x02
#define NPF_NAT_STATIC 0x04
#define NPF_ALGO_NPT66 1
/* Table types. */
#define NPF_TABLE_HASH 1
#define NPF_TABLE_TREE 2

View File

@ -1,7 +1,7 @@
/* $NetBSD: npf_impl.h,v 1.46 2014/02/06 02:51:28 rmind Exp $ */
/* $NetBSD: npf_impl.h,v 1.47 2014/02/13 03:34:40 rmind Exp $ */
/*-
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This material is based upon work partially supported by The
@ -192,6 +192,8 @@ bool npf_rwrip(const npf_cache_t *, u_int, const npf_addr_t *);
bool npf_rwrport(const npf_cache_t *, u_int, const in_port_t);
bool npf_rwrcksum(const npf_cache_t *, u_int,
const npf_addr_t *, const in_port_t);
int npf_npt66_rwr(const npf_cache_t *, u_int, const npf_addr_t *,
npf_netmask_t, uint16_t);
uint16_t npf_fixup16_cksum(uint16_t, uint16_t, uint16_t);
uint16_t npf_fixup32_cksum(uint16_t, uint32_t, uint32_t);

View File

@ -1,7 +1,7 @@
/* $NetBSD: npf_inet.c,v 1.28 2013/12/06 01:33:37 rmind Exp $ */
/* $NetBSD: npf_inet.c,v 1.29 2014/02/13 03:34:40 rmind Exp $ */
/*-
* Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This material is based upon work partially supported by The
@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.28 2013/12/06 01:33:37 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.29 2014/02/13 03:34:40 rmind Exp $");
#include <sys/param.h>
#include <sys/types.h>
@ -616,6 +616,79 @@ npf_rwrcksum(const npf_cache_t *npc, u_int which,
return true;
}
/*
* IPv6-to-IPv6 Network Prefix Translation (NPTv6), as per RFC 6296.
*/
int
npf_npt66_rwr(const npf_cache_t *npc, u_int which, const npf_addr_t *pref,
npf_netmask_t len, uint16_t adj)
{
npf_addr_t *addr = npc->npc_ips[which];
unsigned remnant, word, preflen = len >> 4;
uint32_t sum;
KASSERT(which == NPF_SRC || which == NPF_DST);
if (!npf_iscached(npc, NPC_IP6)) {
return EINVAL;
}
if (len <= 48) {
/*
* The word to adjust. Cannot translate the 0xffff
* subnet if /48 or shorter.
*/
word = 3;
if (addr->s6_addr16[word] == 0xffff) {
return EINVAL;
}
} else {
/*
* Also, all 0s or 1s in the host part are disallowed for
* longer than /48 prefixes.
*/
if ((addr->s6_addr32[2] == 0 && addr->s6_addr32[3] == 0) ||
(addr->s6_addr32[2] == ~0U && addr->s6_addr32[3] == ~0U))
return EINVAL;
/* Determine the 16-bit word to adjust. */
for (word = 4; word < 8; word++)
if (addr->s6_addr16[word] != 0xffff)
break;
}
/* Rewrite the prefix. */
for (unsigned i = 0; i < preflen; i++) {
addr->s6_addr16[i] = pref->s6_addr16[i];
}
/*
* If prefix length is within a 16-bit word (not dividable by 16),
* then prepare a mask, determine the word and adjust it.
*/
if ((remnant = len - (preflen << 4)) != 0) {
const uint16_t wordmask = (1U << remnant) - 1;
const unsigned i = preflen;
addr->s6_addr16[i] = (pref->s6_addr16[i] & wordmask) |
(addr->s6_addr16[i] & ~wordmask);
}
/*
* Performing 1's complement sum/difference.
*/
sum = addr->s6_addr16[word] + adj;
while (sum >> 16) {
sum = (sum >> 16) + (sum & 0xffff);
}
if (sum == 0xffff) {
/* RFC 1071. */
sum = 0x0000;
}
addr->s6_addr16[word] = sum;
return 0;
}
#if defined(DDB) || defined(_NPF_TESTING)
void

View File

@ -1,6 +1,7 @@
/* $NetBSD: npf_nat.c,v 1.24 2014/02/07 23:45:22 rmind Exp $ */
/* $NetBSD: npf_nat.c,v 1.25 2014/02/13 03:34:40 rmind Exp $ */
/*-
* Copyright (c) 2014 Mindaugas Rasiukevicius <rmind at netbsd org>
* Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
* All rights reserved.
*
@ -70,7 +71,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.24 2014/02/07 23:45:22 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.25 2014/02/13 03:34:40 rmind Exp $");
#include <sys/param.h>
#include <sys/types.h>
@ -100,7 +101,7 @@ typedef struct {
/* Portmap range: [ 1024 .. 65535 ] */
#define PORTMAP_FIRST (1024)
#define PORTMAP_SIZE ((65536 - PORTMAP_FIRST) / 32)
#define PORTMAP_FILLED ((uint32_t)~0)
#define PORTMAP_FILLED ((uint32_t)~0U)
#define PORTMAP_MASK (31)
#define PORTMAP_SHIFT (5)
@ -121,7 +122,12 @@ struct npf_natpolicy {
u_int n_flags;
size_t n_addr_sz;
npf_addr_t n_taddr;
npf_netmask_t n_tmask;
in_port_t n_tport;
u_int n_algo;
union {
uint16_t n_npt66_adj;
};
};
#define NPF_NP_CMP_START offsetof(npf_natpolicy_t, n_type)
@ -186,22 +192,34 @@ npf_nat_newpolicy(prop_dictionary_t natdict, npf_ruleset_t *nrlset)
/* Should be exclusively either inbound or outbound NAT. */
if (((np->n_type == NPF_NATIN) ^ (np->n_type == NPF_NATOUT)) == 0) {
kmem_free(np, sizeof(npf_natpolicy_t));
return NULL;
goto err;
}
mutex_init(&np->n_lock, MUTEX_DEFAULT, IPL_SOFTNET);
cv_init(&np->n_cv, "npfnatcv");
LIST_INIT(&np->n_nat_list);
/* Translation IP. */
/* Translation IP, mask and port (if applicable). */
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));
if (np->n_addr_sz == 0 || np->n_addr_sz > sizeof(npf_addr_t)) {
goto err;
}
memcpy(&np->n_taddr, prop_data_data_nocopy(obj), np->n_addr_sz);
/* Translation port (for redirect case). */
prop_dictionary_get_uint8(natdict, "translation-mask", &np->n_tmask);
prop_dictionary_get_uint16(natdict, "translation-port", &np->n_tport);
prop_dictionary_get_uint32(natdict, "translation-algo", &np->n_algo);
switch (np->n_algo) {
case NPF_ALGO_NPT66:
prop_dictionary_get_uint16(natdict, "npt66-adjustment",
&np->n_npt66_adj);
break;
default:
if (np->n_tmask != NPF_NO_NETMASK)
goto err;
break;
}
/* Determine if port map is needed. */
np->n_portmap = NULL;
if ((np->n_flags & NPF_NAT_PORTMAP) == 0) {
@ -223,6 +241,9 @@ npf_nat_newpolicy(prop_dictionary_t natdict, npf_ruleset_t *nrlset)
KASSERT(np->n_portmap != NULL);
}
return np;
err:
kmem_free(np, sizeof(npf_natpolicy_t));
return NULL;
}
/*
@ -606,6 +627,29 @@ npf_nat_translate(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw)
return npf_nat_rwr(npc, np, addr, port, forw);
}
/*
* npf_nat_algo: perform the translation given the algorithm.
*/
static inline int
npf_nat_algo(npf_cache_t *npc, const npf_natpolicy_t *np, bool forw)
{
u_int which;
int error;
switch (np->n_algo) {
case NPF_ALGO_NPT66:
which = npf_nat_which(np->n_type, forw);
error = npf_npt66_rwr(npc, which, &np->n_taddr,
np->n_tmask, np->n_npt66_adj);
break;
default:
error = npf_nat_rwr(npc, np, &np->n_taddr, np->n_tport, forw);
break;
}
return error;
}
/*
* npf_do_nat:
* - Inspect packet for a NAT policy, unless a session with a NAT
@ -656,7 +700,7 @@ npf_do_nat(npf_cache_t *npc, npf_session_t *se, nbuf_t *nbuf, const int di)
if (nbuf_cksum_barrier(nbuf, di)) {
npf_recache(npc, nbuf);
}
error = npf_nat_rwr(npc, np, &np->n_taddr, np->n_tport, forw);
error = npf_nat_algo(npc, np, forw);
atomic_dec_uint(&np->n_refcnt);
return error;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_build.c,v 1.35 2014/02/07 23:45:22 rmind Exp $ */
/* $NetBSD: npf_build.c,v 1.36 2014/02/13 03:34:40 rmind Exp $ */
/*-
* Copyright (c) 2011-2014 The NetBSD Foundation, Inc.
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: npf_build.c,v 1.35 2014/02/07 23:45:22 rmind Exp $");
__RCSID("$NetBSD: npf_build.c,v 1.36 2014/02/13 03:34:40 rmind Exp $");
#include <sys/types.h>
#include <sys/mman.h>
@ -533,24 +533,15 @@ npfctl_build_rule(uint32_t attr, const char *ifname, sa_family_t family,
* npfctl_build_nat: create a single NAT policy of a specified
* type with a given filter options.
*/
static void
npfctl_build_nat(int type, const char *ifname, sa_family_t family,
const addr_port_t *ap, const filt_opts_t *fopts, u_int flags)
static nl_nat_t *
npfctl_build_nat(int type, const char *ifname, const addr_port_t *ap,
const filt_opts_t *fopts, u_int flags)
{
const opt_proto_t op = { .op_proto = -1, .op_opts = NULL };
fam_addr_mask_t *am;
fam_addr_mask_t *am = npfctl_get_singlefam(ap->ap_netaddr);
in_port_t port;
nl_nat_t *nat;
if (!ap->ap_netaddr) {
yyerror("%s network segment is not specified",
type == NPF_NATIN ? "inbound" : "outbound");
}
am = npfctl_get_singlefam(ap->ap_netaddr);
if (am->fam_family != family) {
yyerror("IPv6 NAT is not supported");
}
if (ap->ap_portrange) {
port = npfctl_get_singleport(ap->ap_portrange);
flags &= ~NPF_NAT_PORTMAP;
@ -559,10 +550,11 @@ npfctl_build_nat(int type, const char *ifname, sa_family_t family,
port = 0;
}
nat = npf_nat_create(type, flags, ifname,
&am->fam_addr, am->fam_family, port);
npfctl_build_code(nat, family, &op, fopts);
nat = npf_nat_create(type, flags, ifname, am->fam_family,
&am->fam_addr, am->fam_mask, port);
npfctl_build_code(nat, am->fam_family, &op, fopts);
npf_nat_insert(npf_conf, nat, NPF_PRI_LAST);
return nat;
}
/*
@ -571,10 +563,12 @@ npfctl_build_nat(int type, const char *ifname, sa_family_t family,
void
npfctl_build_natseg(int sd, int type, const char *ifname,
const addr_port_t *ap1, const addr_port_t *ap2,
const filt_opts_t *fopts)
const filt_opts_t *fopts, u_int algo)
{
sa_family_t af = AF_INET;
fam_addr_mask_t *am1 = NULL, *am2 = NULL;
nl_nat_t *nt1 = NULL, *nt2 = NULL;
filt_opts_t imfopts;
uint16_t adj = 0;
u_int flags;
bool binat;
@ -602,6 +596,38 @@ npfctl_build_natseg(int sd, int type, const char *ifname,
abort();
}
/*
* Validate the mappings and their configuration.
*/
if ((type & NPF_NATIN) != 0) {
if (!ap1->ap_netaddr)
yyerror("inbound network segment is not specified");
am1 = npfctl_get_singlefam(ap1->ap_netaddr);
}
if ((type & NPF_NATOUT) != 0) {
if (!ap2->ap_netaddr)
yyerror("outbound network segment is not specified");
am2 = npfctl_get_singlefam(ap2->ap_netaddr);
}
switch (algo) {
case NPF_ALGO_NPT66:
if (am1 == NULL || am2 == NULL)
yyerror("1:1 mapping of two segments must be "
"used for NPTv6");
if (am1->fam_mask != am2->fam_mask)
yyerror("asymmetric translation is not supported");
adj = npfctl_npt66_calcadj(am1->fam_mask,
&am1->fam_addr, &am2->fam_addr);
break;
default:
if ((am1 && am1->fam_mask != NPF_NO_NETMASK) ||
(am2 && am2->fam_mask != NPF_NO_NETMASK))
yyerror("net-to-net translation is not supported");
break;
}
/*
* If the filter criteria is not specified explicitly, apply implicit
* filtering according to the given network segments.
@ -615,12 +641,17 @@ npfctl_build_natseg(int sd, int type, const char *ifname,
if (type & NPF_NATIN) {
memset(&imfopts, 0, sizeof(filt_opts_t));
memcpy(&imfopts.fo_to, ap2, sizeof(addr_port_t));
npfctl_build_nat(NPF_NATIN, ifname, af, ap1, fopts, flags);
nt1 = npfctl_build_nat(NPF_NATIN, ifname, ap1, fopts, flags);
}
if (type & NPF_NATOUT) {
memset(&imfopts, 0, sizeof(filt_opts_t));
memcpy(&imfopts.fo_from, ap1, sizeof(addr_port_t));
npfctl_build_nat(NPF_NATOUT, ifname, af, ap2, fopts, flags);
nt2 = npfctl_build_nat(NPF_NATOUT, ifname, ap2, fopts, flags);
}
if (algo == NPF_ALGO_NPT66) {
npf_nat_setnpt66(nt1, ~adj);
npf_nat_setnpt66(nt2, adj);
}
}

View File

@ -1,7 +1,7 @@
/* $NetBSD: npf_data.c,v 1.24 2014/02/03 02:21:52 rmind Exp $ */
/* $NetBSD: npf_data.c,v 1.25 2014/02/13 03:34:40 rmind Exp $ */
/*-
* Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: npf_data.c,v 1.24 2014/02/03 02:21:52 rmind Exp $");
__RCSID("$NetBSD: npf_data.c,v 1.25 2014/02/13 03:34:40 rmind Exp $");
#include <sys/types.h>
#include <sys/null.h>
@ -585,3 +585,49 @@ out:
npfvar_destroy(vp);
return NULL;
}
/*
* npfctl_npt66_calcadj: calculate the adjustment for NPTv6 as per RFC 6296.
*/
uint16_t
npfctl_npt66_calcadj(npf_netmask_t len, const npf_addr_t *pref_in,
const npf_addr_t *pref_out)
{
const uint16_t *addr6_in = (const uint16_t *)pref_in;
const uint16_t *addr6_out = (const uint16_t *)pref_out;
unsigned i, remnant, wordmask, preflen = len >> 4;
uint32_t adj, isum = 0, osum = 0;
/*
* Extract the bits within a 16-bit word (when prefix length is
* not dividable by 16) and include them into the sum.
*/
remnant = len - (preflen << 4);
wordmask = (1U << remnant) - 1;
assert(wordmask == 0 || (len % 16) != 0);
/* Inner prefix - sum and fold. */
for (i = 0; i < preflen; i++) {
isum += addr6_in[i];
}
isum += addr6_in[i] & wordmask;
while (isum >> 16) {
isum = (isum >> 16) + (isum & 0xffff);
}
/* Outer prefix - sum and fold. */
for (i = 0; i < preflen; i++) {
osum += addr6_out[i];
}
osum += addr6_out[i] & wordmask;
while (osum >> 16) {
osum = (osum >> 16) + (osum & 0xffff);
}
/* Calculate 1's complement difference. */
adj = isum + ~osum;
while (adj >> 16) {
adj = (adj >> 16) + (adj & 0xffff);
}
return (uint16_t)adj;
}

View File

@ -1,7 +1,7 @@
/* $NetBSD: npf_parse.y,v 1.31 2014/02/08 01:20:09 rmind Exp $ */
/* $NetBSD: npf_parse.y,v 1.32 2014/02/13 03:34:40 rmind Exp $ */
/*-
* Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
* Copyright (c) 2011-2014 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -84,6 +84,7 @@ yyerror(const char *fmt, ...)
%}
%token ALG
%token ALGO
%token ALL
%token ANY
%token APPLY
@ -115,6 +116,7 @@ yyerror(const char *fmt, ...)
%token MAP
%token MINUS
%token NAME
%token NPT66
%token ON
%token OUT
%token PAR_CLOSE
@ -156,7 +158,8 @@ yyerror(const char *fmt, ...)
%type <str> proc_param_val, opt_apply, ifname, on_ifname, ifref
%type <num> port, opt_final, number, afamily, opt_family
%type <num> block_or_pass, rule_dir, group_dir, block_opts
%type <num> opt_stateful, icmp_type, table_type, map_sd, map_type
%type <num> opt_stateful, icmp_type, table_type
%type <num> map_sd, map_algo, map_type
%type <var> ifaddrs, addr_or_ifaddr, port_range, icmp_type_and_code
%type <var> filt_addr, addr_and_mask, tcp_flags, tcp_flags_and_mask
%type <var> procs, proc_call, proc_param_list, proc_param
@ -296,6 +299,11 @@ map_sd
| { $$ = NPFCTL_NAT_DYNAMIC; }
;
map_algo
: ALGO NPT66 { $$ = NPF_ALGO_NPT66; }
| { $$ = 0; }
;
map_type
: ARROWBOTH { $$ = NPF_NATIN | NPF_NATOUT; }
| ARROWLEFT { $$ = NPF_NATIN; }
@ -311,13 +319,13 @@ mapseg
;
map
: MAP ifref map_sd mapseg map_type mapseg PASS filt_opts
: MAP ifref map_sd map_algo mapseg map_type mapseg PASS filt_opts
{
npfctl_build_natseg($3, $5, $2, &$4, &$6, &$8);
npfctl_build_natseg($3, $6, $2, &$5, &$7, &$9, $4);
}
| MAP ifref map_sd mapseg map_type mapseg
| MAP ifref map_sd map_algo mapseg map_type mapseg
{
npfctl_build_natseg($3, $5, $2, &$4, &$6, NULL);
npfctl_build_natseg($3, $6, $2, &$5, &$7, NULL, $4);
}
| MAP RULESET group_opts
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_scan.l,v 1.18 2014/02/08 01:20:09 rmind Exp $ */
/* $NetBSD: npf_scan.l,v 1.19 2014/02/13 03:34:40 rmind Exp $ */
/*-
* Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@ -99,6 +99,8 @@ map return MAP;
"<->" return ARROWBOTH;
"<-" return ARROWLEFT;
"->" return ARROWRIGHT;
algo return ALGO;
npt66 return NPT66;
"-" return MINUS;
procedure return PROCEDURE;
\\\n yylineno++; yycolumn = 0;

View File

@ -1,4 +1,4 @@
/* $NetBSD: npfctl.h,v 1.35 2014/02/03 02:21:52 rmind Exp $ */
/* $NetBSD: npfctl.h,v 1.36 2014/02/13 03:34:40 rmind Exp $ */
/*-
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@ -126,6 +126,8 @@ npfvar_t * npfctl_parse_port_range_variable(const char *);
npfvar_t * npfctl_parse_fam_addr_mask(const char *, const char *,
unsigned long *);
bool npfctl_parse_cidr(char *, fam_addr_mask_t *, int *);
uint16_t npfctl_npt66_calcadj(npf_netmask_t, const npf_addr_t *,
const npf_addr_t *);
/*
* NPF extension loading.
@ -193,7 +195,7 @@ void npfctl_build_rule(uint32_t, const char *, sa_family_t,
const char *, const char *);
void npfctl_build_natseg(int, int, const char *,
const addr_port_t *, const addr_port_t *,
const filt_opts_t *);
const filt_opts_t *, unsigned);
void npfctl_build_maprset(const char *, int, const char *);
void npfctl_build_table(const char *, u_int, const char *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_mbuf_subr.c,v 1.4 2012/12/24 19:05:47 rmind Exp $ */
/* $NetBSD: npf_mbuf_subr.c,v 1.5 2014/02/13 03:34:40 rmind Exp $ */
/*
* NPF testing - helper routines.
@ -136,6 +136,15 @@ mbuf_return_hdrs(struct mbuf *m, bool ether, struct ip **ip)
return (void *)(iphdr + 1);
}
void *
mbuf_return_hdrs6(struct mbuf *m, struct ip6_hdr **ip6)
{
struct ip6_hdr *ip6hdr = mtod(m, struct ip6_hdr *);
*ip6 = ip6hdr;
return (void *)(ip6hdr + 1);
}
void
mbuf_icmp_append(struct mbuf *m, struct mbuf *m_orig)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_nat_test.c,v 1.7 2014/02/07 23:45:22 rmind Exp $ */
/* $NetBSD: npf_nat_test.c,v 1.8 2014/02/13 03:34:40 rmind Exp $ */
/*
* NPF NAT test.
@ -27,6 +27,7 @@ static const struct test_case {
const char * ifname;
int di;
int ret;
int af;
const char * taddr;
in_port_t tport;
} test_cases[] = {
@ -38,32 +39,32 @@ static const struct test_case {
{
LOCAL_IP1, 15000, REMOTE_IP1, 7000,
NPF_NATOUT, IFNAME_EXT, PFIL_OUT,
RESULT_PASS, PUB_IP1, RANDOM_PORT
RESULT_PASS, AF_INET, PUB_IP1, RANDOM_PORT
},
{
LOCAL_IP1, 15000, REMOTE_IP1, 7000,
NPF_NATOUT, IFNAME_EXT, PFIL_OUT,
RESULT_PASS, PUB_IP1, RANDOM_PORT
RESULT_PASS, AF_INET, PUB_IP1, RANDOM_PORT
},
{
LOCAL_IP1, 15000, REMOTE_IP1, 7000,
NPF_NATOUT, IFNAME_EXT, PFIL_IN,
RESULT_BLOCK, NULL, 0
RESULT_BLOCK, AF_INET, NULL, 0
},
{
REMOTE_IP1, 7000, LOCAL_IP1, 15000,
NPF_NATOUT, IFNAME_EXT, PFIL_IN,
RESULT_BLOCK, NULL, 0
RESULT_BLOCK, AF_INET, NULL, 0
},
{
REMOTE_IP1, 7000, PUB_IP1, RANDOM_PORT,
NPF_NATOUT, IFNAME_INT, PFIL_IN,
RESULT_BLOCK, NULL, 0
RESULT_BLOCK, AF_INET, NULL, 0
},
{
REMOTE_IP1, 7000, PUB_IP1, RANDOM_PORT,
NPF_NATOUT, IFNAME_EXT, PFIL_IN,
RESULT_PASS, LOCAL_IP1, 15000
RESULT_PASS, AF_INET, LOCAL_IP1, 15000
},
/*
@ -73,12 +74,12 @@ static const struct test_case {
{
REMOTE_IP2, 16000, PUB_IP1, 8000,
NPF_NATIN, IFNAME_EXT, PFIL_IN,
RESULT_PASS, LOCAL_IP1, 6000
RESULT_PASS, AF_INET, LOCAL_IP1, 6000
},
{
LOCAL_IP1, 6000, REMOTE_IP2, 16000,
NPF_NATIN, IFNAME_EXT, PFIL_OUT,
RESULT_PASS, PUB_IP1, 8000
RESULT_PASS, AF_INET, PUB_IP1, 8000
},
/*
@ -88,22 +89,22 @@ static const struct test_case {
{
REMOTE_IP2, 17000, PUB_IP2, 9000,
NPF_BINAT, IFNAME_EXT, PFIL_IN,
RESULT_PASS, LOCAL_IP2, 9000
RESULT_PASS, AF_INET, LOCAL_IP2, 9000
},
{
LOCAL_IP2, 9000, REMOTE_IP2, 17000,
NPF_BINAT, IFNAME_EXT, PFIL_OUT,
RESULT_PASS, PUB_IP2, 9000
RESULT_PASS, AF_INET, PUB_IP2, 9000
},
{
LOCAL_IP2, 18000, REMOTE_IP2, 9000,
NPF_BINAT, IFNAME_EXT, PFIL_OUT,
RESULT_PASS, PUB_IP2, 18000
RESULT_PASS, AF_INET, PUB_IP2, 18000
},
{
REMOTE_IP2, 9000, PUB_IP2, 18000,
NPF_BINAT, IFNAME_EXT, PFIL_IN,
RESULT_PASS, LOCAL_IP2, 18000
RESULT_PASS, AF_INET, LOCAL_IP2, 18000
},
/*
@ -113,21 +114,40 @@ static const struct test_case {
{
LOCAL_IP3, 19000, REMOTE_IP3, 10000,
NPF_BINAT, IFNAME_EXT, PFIL_OUT,
RESULT_PASS, PUB_IP3, 19000
RESULT_PASS, AF_INET, PUB_IP3, 19000
},
{
REMOTE_IP3, 10000, PUB_IP3, 19000,
NPF_BINAT, IFNAME_EXT, PFIL_IN,
RESULT_PASS, LOCAL_IP3, 19000
RESULT_PASS, AF_INET, LOCAL_IP3, 19000
},
/*
* NPTv6 case:
* map $ext_if static algo npt66 $net6_inner <-> $net6_outer
*/
{
LOCAL_IP6, 1000, REMOTE_IP6, 1001,
NPF_BINAT, IFNAME_EXT, PFIL_OUT,
RESULT_PASS, AF_INET6, EXPECTED_IP6, 1000
},
{
REMOTE_IP6, 1001, EXPECTED_IP6, 1000,
NPF_BINAT, IFNAME_EXT, PFIL_IN,
RESULT_PASS, AF_INET6, LOCAL_IP6, 1000
},
};
static bool
nmatch_addr(const char *saddr, const struct in_addr *addr2)
nmatch_addr(int af, const char *saddr, const npf_addr_t *addr2)
{
const in_addr_t addr1 = inet_addr(saddr);
return memcmp(&addr1, &addr2->s_addr, sizeof(in_addr_t)) != 0;
npf_addr_t addr1;
size_t len;
npf_inet_pton(af, saddr, &addr1);
len = af == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr);
return memcmp(&addr1, addr2, len) != 0;
}
static bool
@ -135,6 +155,7 @@ checkresult(bool verbose, unsigned i, struct mbuf *m, ifnet_t *ifp, int error)
{
const struct test_case *t = &test_cases[i];
npf_cache_t npc = { .npc_info = 0 };
const int af = t->af;
nbuf_t nbuf;
if (verbose) {
@ -150,14 +171,17 @@ checkresult(bool verbose, unsigned i, struct mbuf *m, ifnet_t *ifp, int error)
return false;
}
const struct ip *ip = npc.npc_ip.v4;
const struct udphdr *uh = npc.npc_l4.udp;
if (verbose) {
printf("\tpost-translation: src %s (%d)",
inet_ntoa(ip->ip_src), ntohs(uh->uh_sport));
printf(" dst %s (%d)\n",
inet_ntoa(ip->ip_dst), ntohs(uh->uh_dport));
char sbuf[64], dbuf[64];
npf_inet_ntop(af, npc.npc_ips[NPF_SRC], sbuf, sizeof(sbuf));
npf_inet_ntop(af, npc.npc_ips[NPF_DST], dbuf, sizeof(dbuf));
printf("\tpost-translation:");
printf("src %s (%d) ", sbuf, ntohs(uh->uh_sport));
printf("dst %s (%d)\n", dbuf, ntohs(uh->uh_dport));
}
if (error != t->ret) {
return false;
@ -170,10 +194,11 @@ checkresult(bool verbose, unsigned i, struct mbuf *m, ifnet_t *ifp, int error)
in_addr_t dport = forw ? t->dport : t->tport;
bool defect = false;
defect |= nmatch_addr(saddr, &ip->ip_src);
defect |= nmatch_addr(af, saddr, npc.npc_ips[NPF_SRC]);
defect |= sport != ntohs(uh->uh_sport);
defect |= nmatch_addr(daddr, &ip->ip_dst);
defect |= nmatch_addr(af, daddr, npc.npc_ips[NPF_DST]);
defect |= dport != ntohs(uh->uh_dport);
return !defect;
}
@ -181,13 +206,25 @@ static struct mbuf *
fill_packet(const struct test_case *t)
{
struct mbuf *m;
struct ip *ip;
void *ipsrc, *ipdst;
struct udphdr *uh;
m = mbuf_construct(IPPROTO_UDP);
uh = mbuf_return_hdrs(m, false, &ip);
ip->ip_src.s_addr = inet_addr(t->src);
ip->ip_dst.s_addr = inet_addr(t->dst);
if (t->af == AF_INET6) {
struct ip6_hdr *ip6;
m = mbuf_construct6(IPPROTO_UDP);
uh = mbuf_return_hdrs6(m, &ip6);
ipsrc = &ip6->ip6_src, ipdst = &ip6->ip6_dst;
} else {
struct ip *ip;
m = mbuf_construct(IPPROTO_UDP);
uh = mbuf_return_hdrs(m, false, &ip);
ipsrc = &ip->ip_src.s_addr, ipdst = &ip->ip_dst.s_addr;
}
npf_inet_pton(t->af, t->src, ipsrc);
npf_inet_pton(t->af, t->dst, ipdst);
uh->uh_sport = htons(t->sport);
uh->uh_dport = htons(t->dport);
return m;

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_test.h,v 1.14 2014/02/07 23:45:22 rmind Exp $ */
/* $NetBSD: npf_test.h,v 1.15 2014/02/13 03:34:40 rmind Exp $ */
/*
* Public Domain.
@ -42,7 +42,13 @@
#define REMOTE_IP2 "192.0.2.102"
#define REMOTE_IP3 "192.0.2.103"
void npf_test_init(long (*)(void));
#define LOCAL_IP6 "fd01:203:405:1::1234"
#define REMOTE_IP6 "2001:db8:fefe::1010"
#define EXPECTED_IP6 "2001:db8:1:d550::1234"
void npf_test_init(int (*)(int, const char *, void *),
const char *(*)(int, const void *, char *, socklen_t),
long (*)(void));
int npf_test_load(const void *);
ifnet_t * npf_test_addif(const char *, bool, bool);
ifnet_t * npf_test_getif(const char *);
@ -56,6 +62,7 @@ struct mbuf * mbuf_construct_ether(int);
struct mbuf * mbuf_construct(int);
struct mbuf * mbuf_construct6(int);
void * mbuf_return_hdrs(struct mbuf *, bool, struct ip **);
void * mbuf_return_hdrs6(struct mbuf *, struct ip6_hdr **);
void mbuf_icmp_append(struct mbuf *, struct mbuf *);
bool npf_nbuf_test(bool);
@ -66,4 +73,7 @@ bool npf_state_test(bool);
bool npf_rule_test(bool);
bool npf_nat_test(bool);
int npf_inet_pton(int, const char *, void *);
const char * npf_inet_ntop(int, const void *, char *, socklen_t);
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_test_subr.c,v 1.8 2014/02/05 03:49:48 rmind Exp $ */
/* $NetBSD: npf_test_subr.c,v 1.9 2014/02/13 03:34:40 rmind Exp $ */
/*
* NPF initialisation and handler routines.
@ -19,14 +19,21 @@ static npf_state_t cstream_state;
static void * cstream_ptr;
static bool cstream_retval;
static long (*_random_func)(void);
static int (*_pton_func)(int, const char *, void *);
static const char * (*_ntop_func)(int, const void *, char *, socklen_t);
static void npf_state_sample(npf_state_t *, bool);
static long (*npf_random_func)(void) = NULL;
void
npf_test_init(long (*rndfunc)(void))
npf_test_init(int (*pton_func)(int, const char *, void *),
const char *(*ntop_func)(int, const void *, char *, socklen_t),
long (*rndfunc)(void))
{
npf_state_setsampler(npf_state_sample);
npf_random_func = rndfunc;
_pton_func = pton_func;
_ntop_func = ntop_func;
_random_func = rndfunc;
}
int
@ -118,11 +125,23 @@ npf_test_statetrack(const void *data, size_t len, ifnet_t *ifp,
return 0;
}
int
npf_inet_pton(int af, const char *src, void *dst)
{
return _pton_func(af, src, dst);
}
const char *
npf_inet_ntop(int af, const void *src, char *dst, socklen_t size)
{
return _ntop_func(af, src, dst, size);
}
/*
* Need to override for cprng_fast32() -- we need deterministic PRNG.
*/
uint32_t
_arc4random(void)
{
return (uint32_t)(npf_random_func ? npf_random_func() : random());
return (uint32_t)(_random_func ? _random_func() : random());
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: npftest.c,v 1.16 2014/02/06 02:51:28 rmind Exp $ */
/* $NetBSD: npftest.c,v 1.17 2014/02/13 03:34:40 rmind Exp $ */
/*
* NPF testing framework.
@ -255,7 +255,7 @@ main(int argc, char **argv)
rump_init();
rump_schedule();
rumpns_npf_test_init(random);
rumpns_npf_test_init(inet_pton, inet_ntop, random);
if (config) {
load_npf_config(config);

View File

@ -1,4 +1,4 @@
# $NetBSD: npftest.conf,v 1.4 2014/02/07 23:45:22 rmind Exp $
# $NetBSD: npftest.conf,v 1.5 2014/02/13 03:34:40 rmind Exp $
$ext_if = "npftest0"
$int_if = "npftest1"
@ -19,15 +19,23 @@ $local_ip4 = 10.1.1.4
$local_net = { 10.1.1.0/24 }
$ports = { 8000, 9000 }
$net6_inner = fd01:203:405::/48
$net6_outer = 2001:db8:1::/48
map $ext_if static $local_ip3 <-> $pub_ip3
map $ext_if dynamic $local_ip2 <-> $pub_ip2
map $ext_if dynamic $local_net -> $pub_ip1
map $ext_if dynamic $local_ip1 port 6000 <- $pub_ip1 port 8000
map $ext_if static algo npt66 $net6_inner <-> $net6_outer
group "ext" on $ext_if {
pass out final from $local_ip3
pass in final to $pub_ip3
pass out final from $net6_inner
pass in final to $net6_outer
pass stateful out final proto tcp flags S/SA all
pass stateful out final from $local_net
pass stateful in final to any port $ports

View File

@ -1,4 +1,4 @@
/* $NetBSD: npftest.h,v 1.12 2014/02/06 02:51:28 rmind Exp $ */
/* $NetBSD: npftest.h,v 1.13 2014/02/13 03:34:40 rmind Exp $ */
/*
* Public Domain.
@ -12,7 +12,9 @@
#include <net/if.h>
void rumpns_npf_test_init(long (*)(void));
void rumpns_npf_test_init(int (*)(int, const char *, void *),
const char *(*)(int, const void *, char *, socklen_t),
long (*)(void));
int rumpns_npf_test_load(const void *);
ifnet_t * rumpns_npf_test_addif(const char *, bool, bool);
ifnet_t * rumpns_npf_test_getif(const char *);