Module Name: src
Committed By: rmind
Date: Fri Feb 7 23:45:22 UTC 2014
Modified Files:
src/lib/libnpf: npf.c npf.h
src/sys/net/npf: npf.h npf_nat.c
src/usr.sbin/npf/npfctl: npf_build.c npf_show.c
src/usr.sbin/npf/npftest: npftest.conf
src/usr.sbin/npf/npftest/libnpftest: npf_nat_test.c npf_test.h
Log Message:
NPF: add support for static (stateless) NAT.
To generate a diff of this commit:
cvs rdiff -u -r1.26 -r1.27 src/lib/libnpf/npf.c
cvs rdiff -u -r1.23 -r1.24 src/lib/libnpf/npf.h
cvs rdiff -u -r1.35 -r1.36 src/sys/net/npf/npf.h
cvs rdiff -u -r1.23 -r1.24 src/sys/net/npf/npf_nat.c
cvs rdiff -u -r1.34 -r1.35 src/usr.sbin/npf/npfctl/npf_build.c
cvs rdiff -u -r1.8 -r1.9 src/usr.sbin/npf/npfctl/npf_show.c
cvs rdiff -u -r1.3 -r1.4 src/usr.sbin/npf/npftest/npftest.conf
cvs rdiff -u -r1.6 -r1.7 src/usr.sbin/npf/npftest/libnpftest/npf_nat_test.c
cvs rdiff -u -r1.13 -r1.14 src/usr.sbin/npf/npftest/libnpftest/npf_test.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/lib/libnpf/npf.c
diff -u src/lib/libnpf/npf.c:1.26 src/lib/libnpf/npf.c:1.27
--- src/lib/libnpf/npf.c:1.26 Thu Feb 6 02:51:28 2014
+++ src/lib/libnpf/npf.c Fri Feb 7 23:45:22 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: npf.c,v 1.26 2014/02/06 02:51:28 rmind Exp $ */
+/* $NetBSD: npf.c,v 1.27 2014/02/07 23:45:22 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.26 2014/02/06 02:51:28 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.27 2014/02/07 23:45:22 rmind Exp $");
#include <sys/types.h>
#include <netinet/in_systm.h>
@@ -874,6 +874,16 @@ npf_nat_gettype(nl_nat_t *nt)
return type;
}
+u_int
+npf_nat_getflags(nl_nat_t *nt)
+{
+ prop_dictionary_t rldict = nt->nrl_dict;
+ unsigned flags = 0;
+
+ prop_dictionary_get_uint32(rldict, "flags", &flags);
+ return flags;
+}
+
void
npf_nat_getmap(nl_nat_t *nt, npf_addr_t *addr, size_t *alen, in_port_t *port)
{
Index: src/lib/libnpf/npf.h
diff -u src/lib/libnpf/npf.h:1.23 src/lib/libnpf/npf.h:1.24
--- src/lib/libnpf/npf.h:1.23 Thu Feb 6 02:51:28 2014
+++ src/lib/libnpf/npf.h Fri Feb 7 23:45:22 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: npf.h,v 1.23 2014/02/06 02:51:28 rmind Exp $ */
+/* $NetBSD: npf.h,v 1.24 2014/02/07 23:45:22 rmind Exp $ */
/*-
* Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
@@ -136,6 +136,7 @@ int npf_table_gettype(nl_table_t *);
nl_nat_t * npf_nat_iterate(nl_config_t *);
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 *);
nl_rproc_t * npf_rproc_iterate(nl_config_t *);
Index: src/sys/net/npf/npf.h
diff -u src/sys/net/npf/npf.h:1.35 src/sys/net/npf/npf.h:1.36
--- src/sys/net/npf/npf.h:1.35 Thu Feb 6 02:51:28 2014
+++ src/sys/net/npf/npf.h Fri Feb 7 23:45:22 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: npf.h,v 1.35 2014/02/06 02:51:28 rmind Exp $ */
+/* $NetBSD: npf.h,v 1.36 2014/02/07 23:45:22 rmind Exp $ */
/*-
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -87,7 +87,7 @@ typedef uint8_t npf_netmask_t;
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
-#define NPC_IP4 0x01 /* Indicates fetched IPv4 header. */
+#define NPC_IP4 0x01 /* Indicates IPv4 header. */
#define NPC_IP6 0x02 /* Indicates IPv6 header. */
#define NPC_IPFRAG 0x04 /* IPv4/IPv6 fragment. */
#define NPC_LAYER4 0x08 /* Layer 4 has been fetched. */
@@ -235,6 +235,7 @@ bool npf_autounload_p(void);
#define NPF_NAT_PORTS 0x01
#define NPF_NAT_PORTMAP 0x02
+#define NPF_NAT_STATIC 0x04
/* Table types. */
#define NPF_TABLE_HASH 1
Index: src/sys/net/npf/npf_nat.c
diff -u src/sys/net/npf/npf_nat.c:1.23 src/sys/net/npf/npf_nat.c:1.24
--- src/sys/net/npf/npf_nat.c:1.23 Fri Dec 6 01:33:37 2013
+++ src/sys/net/npf/npf_nat.c Fri Feb 7 23:45:22 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_nat.c,v 1.23 2013/12/06 01:33:37 rmind Exp $ */
+/* $NetBSD: npf_nat.c,v 1.24 2014/02/07 23:45:22 rmind Exp $ */
/*-
* Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.23 2013/12/06 01:33:37 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.24 2014/02/07 23:45:22 rmind Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -423,8 +423,8 @@ npf_nat_which(const int type, bool forw)
{
/*
* Outbound NAT rewrites:
- * - Source on "forwards" stream.
- * - Destination on "backwards" stream.
+ * - Source (NPF_SRC) on "forwards" stream.
+ * - Destination (NPF_DST) on "backwards" stream.
* Inbound NAT is other way round.
*/
if (type == NPF_NATOUT) {
@@ -433,7 +433,7 @@ npf_nat_which(const int type, bool forw)
KASSERT(type == NPF_NATIN);
}
CTASSERT(NPF_SRC == 0 && NPF_DST == 1);
- KASSERT(forw == 0 || forw == 1);
+ KASSERT(forw == NPF_SRC || forw == NPF_DST);
return (u_int)forw;
}
@@ -528,37 +528,14 @@ out:
}
/*
- * npf_nat_translate: perform address and/or port translation.
+ * npf_nat_rwr: perform address and/or port translation.
*/
-int
-npf_nat_translate(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw)
+static int
+npf_nat_rwr(npf_cache_t *npc, const npf_natpolicy_t *np,
+ const npf_addr_t *addr, const in_addr_t port, bool forw)
{
- const int proto = npc->npc_proto;
- const npf_natpolicy_t *np = nt->nt_natpolicy;
+ const unsigned proto = npc->npc_proto;
const u_int which = npf_nat_which(np->n_type, forw);
- const npf_addr_t *addr;
- in_port_t port;
-
- KASSERT(npf_iscached(npc, NPC_IP46));
- KASSERT(npf_iscached(npc, NPC_LAYER4));
- KASSERT(!nbuf_flag_p(nbuf, NBUF_DATAREF_RESET));
-
- if (forw) {
- /* "Forwards" stream: use translation address/port. */
- addr = &np->n_taddr;
- port = nt->nt_tport;
- } else {
- /* "Backwards" stream: use original address/port. */
- addr = &nt->nt_oaddr;
- port = nt->nt_oport;
- }
- KASSERT((np->n_flags & NPF_NAT_PORTS) != 0 || port == 0);
-
- /* Execute ALG hook first. */
- if ((npc->npc_info & NPC_ALG_EXEC) == 0) {
- npc->npc_info |= NPC_ALG_EXEC;
- npf_alg_exec(npc, nbuf, nt, forw);
- }
/*
* Rewrite IP and/or TCP/UDP checksums first, since we need the
@@ -571,7 +548,6 @@ npf_nat_translate(npf_cache_t *npc, nbuf
if (!npf_rwrip(npc, which, addr)) {
return EINVAL;
}
-
if ((np->n_flags & NPF_NAT_PORTS) == 0) {
/* Done. */
return 0;
@@ -596,6 +572,41 @@ npf_nat_translate(npf_cache_t *npc, nbuf
}
/*
+ * npf_nat_translate: perform translation given the state data.
+ */
+int
+npf_nat_translate(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, bool forw)
+{
+ const npf_natpolicy_t *np = nt->nt_natpolicy;
+ const npf_addr_t *addr;
+ in_port_t port;
+
+ KASSERT(npf_iscached(npc, NPC_IP46));
+ KASSERT(npf_iscached(npc, NPC_LAYER4));
+ KASSERT(!nbuf_flag_p(nbuf, NBUF_DATAREF_RESET));
+
+ if (forw) {
+ /* "Forwards" stream: use translation address/port. */
+ addr = &np->n_taddr;
+ port = nt->nt_tport;
+ } else {
+ /* "Backwards" stream: use original address/port. */
+ addr = &nt->nt_oaddr;
+ port = nt->nt_oport;
+ }
+ KASSERT((np->n_flags & NPF_NAT_PORTS) != 0 || port == 0);
+
+ /* Execute ALG hook first. */
+ if ((npc->npc_info & NPC_ALG_EXEC) == 0) {
+ npc->npc_info |= NPC_ALG_EXEC;
+ npf_alg_exec(npc, nbuf, nt, forw);
+ }
+
+ /* Finally, perform the translation. */
+ return npf_nat_rwr(npc, np, addr, port, forw);
+}
+
+/*
* npf_do_nat:
* - Inspect packet for a NAT policy, unless a session with a NAT
* association already exists. In such case, determine whether it
@@ -640,6 +651,16 @@ npf_do_nat(npf_cache_t *npc, npf_session
}
forw = true;
+ /* Static NAT - just perform the translation. */
+ if (np->n_flags & NPF_NAT_STATIC) {
+ if (nbuf_cksum_barrier(nbuf, di)) {
+ npf_recache(npc, nbuf);
+ }
+ error = npf_nat_rwr(npc, np, &np->n_taddr, np->n_tport, forw);
+ atomic_dec_uint(&np->n_refcnt);
+ return error;
+ }
+
/*
* If there is no local session (no "stateful" rule - unusual, but
* possible configuration), establish one before translation. Note
@@ -688,11 +709,11 @@ translate:
/* Perform the translation. */
error = npf_nat_translate(npc, nbuf, nt, forw);
out:
- if (error && nse) {
- /* It created for NAT - just expire. */
- npf_session_expire(nse);
- }
- if (nse) {
+ if (__predict_false(nse)) {
+ if (error) {
+ /* It created for NAT - just expire. */
+ npf_session_expire(nse);
+ }
npf_session_release(nse);
}
return error;
Index: src/usr.sbin/npf/npfctl/npf_build.c
diff -u src/usr.sbin/npf/npfctl/npf_build.c:1.34 src/usr.sbin/npf/npfctl/npf_build.c:1.35
--- src/usr.sbin/npf/npfctl/npf_build.c:1.34 Thu Feb 6 18:48:09 2014
+++ src/usr.sbin/npf/npfctl/npf_build.c Fri Feb 7 23:45:22 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_build.c,v 1.34 2014/02/06 18:48:09 christos Exp $ */
+/* $NetBSD: npf_build.c,v 1.35 2014/02/07 23:45:22 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.34 2014/02/06 18:48:09 christos Exp $");
+__RCSID("$NetBSD: npf_build.c,v 1.35 2014/02/07 23:45:22 rmind Exp $");
#include <sys/types.h>
#include <sys/mman.h>
@@ -535,7 +535,7 @@ npfctl_build_rule(uint32_t attr, const c
*/
static void
npfctl_build_nat(int type, const char *ifname, sa_family_t family,
- const addr_port_t *ap, const filt_opts_t *fopts, bool binat)
+ 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;
@@ -551,36 +551,16 @@ npfctl_build_nat(int type, const char *i
yyerror("IPv6 NAT is not supported");
}
- switch (type) {
- case NPF_NATOUT:
- /*
- * Outbound NAT (or source NAT) policy, usually used for the
- * traditional NAPT. If it is a half for bi-directional NAT,
- * then no port translation with mapping.
- */
- nat = npf_nat_create(NPF_NATOUT, !binat ?
- (NPF_NAT_PORTS | NPF_NAT_PORTMAP) : 0,
- ifname, &am->fam_addr, am->fam_family, 0);
- break;
- case NPF_NATIN:
- /*
- * Inbound NAT (or destination NAT). Unless bi-NAT, a port
- * must be specified, since it has to be redirection.
- */
+ if (ap->ap_portrange) {
+ port = npfctl_get_singleport(ap->ap_portrange);
+ flags &= ~NPF_NAT_PORTMAP;
+ flags |= NPF_NAT_PORTS;
+ } else {
port = 0;
- if (!binat) {
- if (!ap->ap_portrange) {
- yyerror("inbound port is not specified");
- }
- port = npfctl_get_singleport(ap->ap_portrange);
- }
- nat = npf_nat_create(NPF_NATIN, !binat ? NPF_NAT_PORTS : 0,
- ifname, &am->fam_addr, am->fam_family, port);
- break;
- default:
- assert(false);
}
+ nat = npf_nat_create(type, flags, ifname,
+ &am->fam_addr, am->fam_family, port);
npfctl_build_code(nat, family, &op, fopts);
npf_nat_insert(npf_conf, nat, NPF_PRI_LAST);
}
@@ -595,21 +575,33 @@ npfctl_build_natseg(int sd, int type, co
{
sa_family_t af = AF_INET;
filt_opts_t imfopts;
+ u_int flags;
bool binat;
- if (sd == NPFCTL_NAT_STATIC) {
- yyerror("static NAT is not yet supported");
- }
- assert(sd == NPFCTL_NAT_DYNAMIC);
assert(ifname != NULL);
/*
* Bi-directional NAT is a combination of inbound NAT and outbound
- * NAT policies. Note that the translation address is local IP and
- * the filter criteria is inverted accordingly.
+ * NAT policies with the translation segments inverted respectively.
*/
binat = (NPF_NATIN | NPF_NATOUT) == type;
+ switch (sd) {
+ case NPFCTL_NAT_DYNAMIC:
+ /*
+ * Dynamic NAT: traditional NAPT is expected. Unless it
+ * is bi-directional NAT, perform port mapping.
+ */
+ flags = !binat ? (NPF_NAT_PORTS | NPF_NAT_PORTMAP) : 0;
+ break;
+ case NPFCTL_NAT_STATIC:
+ /* Static NAT: mechanic translation. */
+ flags = NPF_NAT_STATIC;
+ break;
+ default:
+ abort();
+ }
+
/*
* If the filter criteria is not specified explicitly, apply implicit
* filtering according to the given network segments.
@@ -623,12 +615,12 @@ npfctl_build_natseg(int sd, int type, co
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, binat);
+ npfctl_build_nat(NPF_NATIN, ifname, af, 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, binat);
+ npfctl_build_nat(NPF_NATOUT, ifname, af, ap2, fopts, flags);
}
}
Index: src/usr.sbin/npf/npfctl/npf_show.c
diff -u src/usr.sbin/npf/npfctl/npf_show.c:1.8 src/usr.sbin/npf/npfctl/npf_show.c:1.9
--- src/usr.sbin/npf/npfctl/npf_show.c:1.8 Fri Nov 22 18:42:02 2013
+++ src/usr.sbin/npf/npfctl/npf_show.c Fri Feb 7 23:45:22 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_show.c,v 1.8 2013/11/22 18:42:02 rmind Exp $ */
+/* $NetBSD: npf_show.c,v 1.9 2014/02/07 23:45:22 rmind Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_show.c,v 1.8 2013/11/22 18:42:02 rmind Exp $");
+__RCSID("$NetBSD: npf_show.c,v 1.9 2014/02/07 23:45:22 rmind Exp $");
#include <sys/socket.h>
#include <netinet/in.h>
@@ -378,6 +378,7 @@ npfctl_print_nat(npf_conf_info_t *ctx, n
npf_addr_t addr;
in_port_t port;
size_t alen;
+ u_int flags;
char *seg;
/* Get the interface. */
@@ -405,12 +406,14 @@ npfctl_print_nat(npf_conf_info_t *ctx, n
seg2 = seg;
break;
default:
- assert(false);
+ abort();
}
+ flags = npf_nat_getflags(nt);
/* Print out the NAT policy with the filter criteria. */
- fprintf(ctx->fp, "map %s dynamic %s %s %s pass ",
- ifname, seg1, arrow, seg2);
+ fprintf(ctx->fp, "map %s %s %s %s %s pass ",
+ ifname, (flags & NPF_NAT_STATIC) ? "static" : "dynamic",
+ seg1, arrow, seg2);
npfctl_print_filter(ctx, rl);
fputs("\n", ctx->fp);
free(seg);
Index: src/usr.sbin/npf/npftest/npftest.conf
diff -u src/usr.sbin/npf/npftest/npftest.conf:1.3 src/usr.sbin/npf/npftest/npftest.conf:1.4
--- src/usr.sbin/npf/npftest/npftest.conf:1.3 Mon Sep 23 15:30:32 2013
+++ src/usr.sbin/npf/npftest/npftest.conf Fri Feb 7 23:45:22 2014
@@ -1,4 +1,4 @@
-# $NetBSD: npftest.conf,v 1.3 2013/09/23 15:30:32 rmind Exp $
+# $NetBSD: npftest.conf,v 1.4 2014/02/07 23:45:22 rmind Exp $
$ext_if = "npftest0"
$int_if = "npftest1"
@@ -9,6 +9,7 @@ $int_if = "npftest1"
$pub_ip1 = 192.0.2.1
$pub_ip2 = 192.0.2.2
+$pub_ip3 = 192.0.2.3
$local_ip1 = 10.1.1.1
$local_ip2 = 10.1.1.2
@@ -18,11 +19,15 @@ $local_ip4 = 10.1.1.4
$local_net = { 10.1.1.0/24 }
$ports = { 8000, 9000 }
+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
group "ext" on $ext_if {
+ pass out final from $local_ip3
+ pass in final to $pub_ip3
+
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
Index: src/usr.sbin/npf/npftest/libnpftest/npf_nat_test.c
diff -u src/usr.sbin/npf/npftest/libnpftest/npf_nat_test.c:1.6 src/usr.sbin/npf/npftest/libnpftest/npf_nat_test.c:1.7
--- src/usr.sbin/npf/npftest/libnpftest/npf_nat_test.c:1.6 Wed Feb 5 03:49:48 2014
+++ src/usr.sbin/npf/npftest/libnpftest/npf_nat_test.c Fri Feb 7 23:45:22 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_nat_test.c,v 1.6 2014/02/05 03:49:48 rmind Exp $ */
+/* $NetBSD: npf_nat_test.c,v 1.7 2014/02/07 23:45:22 rmind Exp $ */
/*
* NPF NAT test.
@@ -68,7 +68,7 @@ static const struct test_case {
/*
* NAT redirect (inbound NAT):
- * map $ext_if dynamic $local_ip1 port 8000 <- $pub_ip1 port 8000
+ * map $ext_if dynamic $local_ip1 port 6000 <- $pub_ip1 port 8000
*/
{
REMOTE_IP2, 16000, PUB_IP1, 8000,
@@ -106,6 +106,21 @@ static const struct test_case {
RESULT_PASS, LOCAL_IP2, 18000
},
+ /*
+ * Static NAT: plain translation both ways.
+ * map $ext_if static $local_ip3 <-> $pub_ip3
+ */
+ {
+ LOCAL_IP3, 19000, REMOTE_IP3, 10000,
+ NPF_BINAT, IFNAME_EXT, PFIL_OUT,
+ RESULT_PASS, PUB_IP3, 19000
+ },
+ {
+ REMOTE_IP3, 10000, PUB_IP3, 19000,
+ NPF_BINAT, IFNAME_EXT, PFIL_IN,
+ RESULT_PASS, LOCAL_IP3, 19000
+ },
+
};
static bool
Index: src/usr.sbin/npf/npftest/libnpftest/npf_test.h
diff -u src/usr.sbin/npf/npftest/libnpftest/npf_test.h:1.13 src/usr.sbin/npf/npftest/libnpftest/npf_test.h:1.14
--- src/usr.sbin/npf/npftest/libnpftest/npf_test.h:1.13 Thu Feb 6 02:51:28 2014
+++ src/usr.sbin/npf/npftest/libnpftest/npf_test.h Fri Feb 7 23:45:22 2014
@@ -36,8 +36,11 @@
/* Note: RFC 5737 compliant addresses. */
#define PUB_IP1 "192.0.2.1"
#define PUB_IP2 "192.0.2.2"
-#define REMOTE_IP1 "192.0.2.3"
-#define REMOTE_IP2 "192.0.2.4"
+#define PUB_IP3 "192.0.2.3"
+
+#define REMOTE_IP1 "192.0.2.101"
+#define REMOTE_IP2 "192.0.2.102"
+#define REMOTE_IP3 "192.0.2.103"
void npf_test_init(long (*)(void));
int npf_test_load(const void *);