- Rework NPF NAT syntax to be more structured and support future additions trunk
authorrmind <rmind@NetBSD.org>
Fri, 15 Jun 2012 23:24:08 +0000
branchtrunk
changeset 211576 18ae6eb11c8f
parent 211575 81bbc94f5bfe
child 211577 d49d4187b5c6
- Rework NPF NAT syntax to be more structured and support future additions of different types and configurations of NAT. - npfctl: improve disassemble and show-config command functionality. - Fix custom ICMP code and type filtering.
sys/net/npf/npf_ncode.h
usr.sbin/npf/npfctl/npf.conf.5
usr.sbin/npf/npfctl/npf_build.c
usr.sbin/npf/npfctl/npf_data.c
usr.sbin/npf/npfctl/npf_disassemble.c
usr.sbin/npf/npfctl/npf_ncgen.c
usr.sbin/npf/npfctl/npf_parse.y
usr.sbin/npf/npfctl/npf_scan.l
usr.sbin/npf/npfctl/npfctl.c
usr.sbin/npf/npfctl/npfctl.h
--- a/sys/net/npf/npf_ncode.h	Fri Jun 15 23:01:16 2012 +0000
+++ b/sys/net/npf/npf_ncode.h	Fri Jun 15 23:24:08 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ncode.h,v 1.7 2012/04/14 19:01:21 rmind Exp $	*/
+/*	$NetBSD: npf_ncode.h,v 1.8 2012/06/15 23:24:08 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@@ -143,9 +143,9 @@
 # define	NPF_OPERAND_PORT_RANGE		14
 
 static const struct npf_instruction {
-	const char *name;
-	uint8_t op[4];
-} npf_instructions[256] = {
+	const char *	name;
+	uint8_t		op[4];
+} npf_instructions[] = {
 	[NPF_OPCODE_RET] = {
 		.name = "ret",
 		.op = {
@@ -247,7 +247,8 @@
 			[1] = NPF_OPERAND_REGISTER,
 		},
 	},
-	[NPF_OPCODE_DIV] = { .name = "div",
+	[NPF_OPCODE_DIV] = {
+		.name = "div",
 		.op = {
 			[0] = NPF_OPERAND_VALUE,
 			[1] = NPF_OPERAND_REGISTER,
--- a/usr.sbin/npf/npfctl/npf.conf.5	Fri Jun 15 23:01:16 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf.conf.5	Fri Jun 15 23:24:08 2012 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: npf.conf.5,v 1.11 2012/05/30 22:00:44 wiz Exp $
+.\"    $NetBSD: npf.conf.5,v 1.12 2012/06/15 23:24:08 rmind Exp $
 .\"
 .\" Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -27,7 +27,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd May 27, 2012
+.Dd June 14, 2012
 .Dt NPF.CONF 5
 .Os
 .Sh NAME
@@ -132,7 +132,7 @@
 .\" -----
 .Sh GRAMMAR
 .Bd -literal
-line		= ( def | table | nat | group | rproc )
+line		= ( def | table | map | group | rproc )
 
 def		= ( \*[Lt]name\*[Gt] "=" "{ a, b, ... }" | "\*[Lt]text\*[Gt]" | "$\*[Lt]interface\*[Gt]" )
 iface		= ( \*[Lt]interface\*[Gt] | def )
@@ -140,9 +140,9 @@
 table		= "table" \*[Lt]tid\*[Gt] "type" ( "hash" | "tree" )
 		  ( "dynamic" | "file" \*[Lt]path\*[Gt] )
 
-nat		= "nat" iface filt-opts "->" \*[Lt]addr\*[Gt]
-binat		= "binat" iface filt-opts "->" \*[Lt]addr\*[Gt]
-rdr		= "rdr" iface filt-opts "->" \*[Lt]addr\*[Gt] port-opts
+map-di		= ( "->" | "<-" | "<->" )
+map-type	= ( "static" | "dynamic" )
+map		= "map" iface maptype \*[Lt]seg1\*[Gt] mapdi \*[Lt]seg2\*[Gt] [ "pass" filt-opts ]
 
 rproc		= "procedure" \*[Lt]name\*[Gt] procs
 procs		= "{" op1 \*[Lt]newline\*[Gt], op2 \*[Lt]newline\*[Gt], ... "}"
@@ -179,13 +179,15 @@
 $ext_if = "wm0"
 $int_if = "wm1"
 
-$services_tcp = { http, https, smtp, domain, 6000 }
-$services_udp = { domain, ntp, 6000 }
-
 table <1> type hash file "/etc/npf_blacklist"
 table <2> type tree dynamic
 
-nat $ext_if from 192.168.0.0/24 to any -> $ext_if
+$services_tcp = { http, https, smtp, domain, 6000, 9022 }
+$services_udp = { domain, ntp, 6000 }
+$localnet = { 10.1.1.0/24 }
+
+map $ext_if dynamic 10.1.1.0/24 -> $ext_if
+map $ext_if dynamic 10.1.1.2 port 22 <- $ext_if 9022
 
 procedure "log" {
 	log: npflog0
@@ -196,9 +198,9 @@
 }
 
 group (name "external", interface $ext_if) {
-	block in final from \*[Lt]1\*[Gt]
 	pass stateful out final from $ext_if apply "rid"
 
+	block in final from \*[Lt]1\*[Gt]
 	pass in final family inet proto tcp to $ext_if port ssh apply "log"
 	pass in final proto tcp to $ext_if port $services_tcp
 	pass in final proto udp to $ext_if port $services_udp
--- a/usr.sbin/npf/npfctl/npf_build.c	Fri Jun 15 23:01:16 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_build.c	Fri Jun 15 23:24:08 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_build.c,v 1.6 2012/02/26 21:50:05 christos Exp $	*/
+/*	$NetBSD: npf_build.c,v 1.7 2012/06/15 23:24:08 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_build.c,v 1.6 2012/02/26 21:50:05 christos Exp $");
+__RCSID("$NetBSD: npf_build.c,v 1.7 2012/06/15 23:24:08 rmind Exp $");
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
@@ -90,10 +90,11 @@
 	return npf_table_exists_p(npf_conf, atoi(id));
 }
 
-static in_port_t *
+static in_port_t
 npfctl_get_singleport(const npfvar_t *vp)
 {
 	port_range_t *pr;
+	in_port_t *port;
 
 	if (npfvar_get_count(vp) > 1) {
 		yyerror("multiple ports are not valid");
@@ -102,7 +103,8 @@
 	if (pr->pr_start != pr->pr_end) {
 		yyerror("port range is not valid");
 	}
-	return &pr->pr_start;
+	port = &pr->pr_start;
+	return *port;
 }
 
 static fam_addr_mask_t *
@@ -247,13 +249,15 @@
 npfctl_build_ncode(nl_rule_t *rl, sa_family_t family, const opt_proto_t *op,
     const filt_opts_t *fopts, bool invert)
 {
+	const addr_port_t *apfrom = &fopts->fo_from;
+	const addr_port_t *apto = &fopts->fo_to;
 	nc_ctx_t *nc;
 	void *code;
 	size_t len;
 
 	if (family == AF_UNSPEC && op->op_proto == -1 &&
-	    op->op_opts == NULL && !fopts->fo_from && !fopts->fo_to &&
-	    !fopts->fo_from_port_range && !fopts->fo_to_port_range)
+	    op->op_opts == NULL && !apfrom->ap_netaddr && !apto->ap_netaddr &&
+	    !apfrom->ap_portrange && !apto->ap_portrange)
 		return false;
 
 	int srcflag = NC_MATCH_SRC;
@@ -267,19 +271,19 @@
 	nc = npfctl_ncgen_create();
 
 	/* Build IP address blocks. */
-	npfctl_build_vars(nc, family, fopts->fo_from, srcflag);
-	npfctl_build_vars(nc, family, fopts->fo_to, dstflag);
+	npfctl_build_vars(nc, family, apfrom->ap_netaddr, srcflag);
+	npfctl_build_vars(nc, family, apto->ap_netaddr, dstflag);
 
 	/* Build layer 4 protocol blocks. */
 	int pflag = npfctl_build_proto(nc, op);
 
 	/* Build port-range blocks. */
-	if (fopts->fo_from_port_range) {
-		npfctl_build_vars(nc, family, fopts->fo_from_port_range,
+	if (apfrom->ap_portrange) {
+		npfctl_build_vars(nc, family, apfrom->ap_portrange,
 		    srcflag | pflag);
 	}
-	if (fopts->fo_to_port_range) {
-		npfctl_build_vars(nc, family, fopts->fo_to_port_range,
+	if (apto->ap_portrange) {
+		npfctl_build_vars(nc, family, apto->ap_portrange,
 		    dstflag | pflag);
 	}
 
@@ -289,7 +293,7 @@
 	code = npfctl_ncgen_complete(nc, &len);
 	if (npf_debug) {
 		extern int yylineno;
-		printf("RULE AT LINE %d\n", yylineno - 1);
+		printf("RULE AT LINE %d\n", yylineno);
 		npfctl_ncgen_print(code, len);
 	}
 	if (npf_rule_setcode(rl, NPF_CODE_NCODE, code, len) == -1) {
@@ -430,64 +434,100 @@
  * given filter options.
  */
 void
-npfctl_build_nat(int type, u_int if_idx, const filt_opts_t *fopts,
-    npfvar_t *var1, npfvar_t *var2)
+npfctl_build_nat(int sd, int type, u_int if_idx, const addr_port_t *ap1,
+    const addr_port_t *ap2, const filt_opts_t *fopts)
 {
-	opt_proto_t op = { .op_proto = -1, .op_opts = NULL };
+	const opt_proto_t op = { .op_proto = -1, .op_opts = NULL };
+	fam_addr_mask_t *am1, *am2;
+	filt_opts_t imfopts;
+	sa_family_t family;
 	nl_nat_t *nat;
-	fam_addr_mask_t *ai;
+
+	if (sd == NPFCTL_NAT_STATIC) {
+		yyerror("static NAT is not yet supported");
+	}
+	assert(sd == NPFCTL_NAT_DYNAMIC);
+	assert(if_idx != 0);
+
+	family = AF_INET;
 
-	assert(type != 0 && if_idx != 0);
-	assert(fopts != NULL && var1 != NULL);
+	if (type & NPF_NATIN) {
+		if (!ap1->ap_netaddr) {
+			yyerror("inbound network segment is not specified");
+		}
+		am1 = npfctl_get_singlefam(ap1->ap_netaddr);
+		if (am1->fam_family != AF_INET) {
+			yyerror("IPv6 NAT is not supported");
+		}
+		assert(am1 != NULL);
+	}
 
-	ai = npfctl_get_singlefam(var1);
-	assert(ai != NULL);
-	if (ai->fam_family != AF_INET) {
-		yyerror("IPv6 NAT is not supported");
+	if (type & NPF_NATOUT) {
+		if (!ap2->ap_netaddr) {
+			yyerror("outbound network segment is not specified");
+		}
+		am2 = npfctl_get_singlefam(ap2->ap_netaddr);
+		if (am2->fam_family != family) {
+			yyerror("IPv6 NAT is not supported");
+		}
+		assert(am2 != NULL);
+	}
+
+	/*
+	 * If filter criteria is not specified explicitly, apply implicit
+	 * filtering according to the given network segements.
+	 */
+	if (!fopts) {
+		memset(&imfopts, 0, sizeof(filt_opts_t));
+		if (type & NPF_NATOUT) {
+			memcpy(&imfopts.fo_from, ap1, sizeof(addr_port_t));
+		}
+		if (type & NPF_NATIN) {
+			memcpy(&imfopts.fo_to, ap2, sizeof(addr_port_t));
+		}
+		fopts = &imfopts;
 	}
 
 	switch (type) {
-	case NPFCTL_RDR: {
+	case NPF_NATIN: {
 		/*
 		 * Redirection: an inbound NAT with a specific port.
 		 */
-		in_port_t *port = npfctl_get_singleport(var2);
+		if (!ap1->ap_portrange) {
+			yyerror("inbound port is not specified");
+		}
+		in_port_t port = npfctl_get_singleport(ap1->ap_portrange);
 		nat = npf_nat_create(NPF_NATIN, NPF_NAT_PORTS,
-		    if_idx, &ai->fam_addr, ai->fam_family, *port);
+		    if_idx, &am1->fam_addr, am1->fam_family, port);
 		break;
 	}
-	case NPFCTL_BINAT: {
+	case (NPF_NATIN | NPF_NATOUT): {
 		/*
 		 * Bi-directional NAT: a combination of inbound NAT and
 		 * outbound NAT policies.  Note that the translation address
 		 * is local IP and filter criteria is inverted accordingly.
 		 */
-		fam_addr_mask_t *tai = npfctl_get_singlefam(var2);
-		assert(tai != NULL);
-		if (ai->fam_family != AF_INET) {
-			yyerror("IPv6 NAT is not supported");
-		}
 		nat = npf_nat_create(NPF_NATIN, 0, if_idx,
-		    &tai->fam_addr, tai->fam_family, 0);
-		npfctl_build_ncode(nat, AF_INET, &op, fopts, true);
+		    &am1->fam_addr, am1->fam_family, 0);
+		npfctl_build_ncode(nat, family, &op, fopts, true);
 		npf_nat_insert(npf_conf, nat, NPF_PRI_NEXT);
 		/* FALLTHROUGH */
 	}
-	case NPFCTL_NAT: {
+	case NPF_NATOUT: {
 		/*
 		 * Traditional NAPT: an outbound NAT policy with port.
-		 * If this is another hald for bi-directional NAT, then
+		 * If this is another half for bi-directional NAT, then
 		 * no port translation with mapping.
 		 */
-		nat = npf_nat_create(NPF_NATOUT, type == NPFCTL_NAT ?
+		nat = npf_nat_create(NPF_NATOUT, type == NPF_NATOUT ?
 		    (NPF_NAT_PORTS | NPF_NAT_PORTMAP) : 0,
-		    if_idx, &ai->fam_addr, ai->fam_family, 0);
+		    if_idx, &am2->fam_addr, am2->fam_family, 0);
 		break;
 	}
 	default:
 		assert(false);
 	}
-	npfctl_build_ncode(nat, AF_INET, &op, fopts, false);
+	npfctl_build_ncode(nat, family, &op, fopts, false);
 	npf_nat_insert(npf_conf, nat, NPF_PRI_NEXT);
 }
 
--- a/usr.sbin/npf/npfctl/npf_data.c	Fri Jun 15 23:01:16 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_data.c	Fri Jun 15 23:24:08 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_data.c,v 1.12 2012/05/30 21:30:07 rmind Exp $	*/
+/*	$NetBSD: npf_data.c,v 1.13 2012/06/15 23:24:08 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_data.c,v 1.12 2012/05/30 21:30:07 rmind Exp $");
+__RCSID("$NetBSD: npf_data.c,v 1.13 2012/06/15 23:24:08 rmind Exp $");
 
 #include <sys/types.h>
 #include <sys/null.h>
@@ -474,7 +474,7 @@
 }
 
 npfvar_t *
-npfctl_parse_icmp(uint8_t type, uint8_t code)
+npfctl_parse_icmp(int type, int code)
 {
 	npfvar_t *vp = npfvar_create(".icmp");
 
--- a/usr.sbin/npf/npfctl/npf_disassemble.c	Fri Jun 15 23:01:16 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_disassemble.c	Fri Jun 15 23:24:08 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_disassemble.c,v 1.4 2012/05/30 21:30:07 rmind Exp $	*/
+/*	$NetBSD: npf_disassemble.c,v 1.5 2012/06/15 23:24:08 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -30,13 +30,14 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_disassemble.c,v 1.4 2012/05/30 21:30:07 rmind Exp $");
+__RCSID("$NetBSD: npf_disassemble.c,v 1.5 2012/06/15 23:24:08 rmind Exp $");
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
+#include <assert.h>
 #include <err.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -60,55 +61,63 @@
 };
 
 struct nc_inf {
-	npfvar_t *	nci_vlist[NPF_SHOW_COUNT];
-	bool		nci_srcdst;
+	FILE *			ni_fp;
+	const uint32_t *	ni_buf;
+	size_t			ni_left;
+	const uint32_t *	ni_ipc;
+	const uint32_t *	ni_pc;
+
+	/* Jump target array, its size and current index. */
+	const uint32_t **	ni_targs;
+	size_t			ni_targsize;
+	size_t			ni_targidx;
+
+	/* Other meta-data. */
+	npfvar_t *		ni_vlist[NPF_SHOW_COUNT];
+	int			ni_proto;
+	bool			ni_srcdst;
 };
 
-#define ADVANCE(n, rv) \
-	do { \
-		if (len < sizeof(*pc) * (n)) { \
-			warnx("ran out of bytes"); \
-			return rv; \
-		} \
-		pc += (n); \
-		len -= sizeof(*pc) * (n); \
-	} while (/*CONSTCOND*/0)
-
 static size_t
-npfctl_ncode_get_target(const uint32_t *pc, const uint32_t **t, size_t l)
+npfctl_ncode_get_target(const nc_inf_t *ni, const uint32_t *pc)
 {
-	for (size_t i = 0; i < l; i++)
-		if (t[i] == pc)
+	for (size_t i = 0; i < ni->ni_targidx; i++) {
+		if (ni->ni_targs[i] == pc)
 			return i;
-	return ~0;
+	}
+	return (size_t)-1;
 }
 
 static size_t
-npfctl_ncode_add_target(const uint32_t *pc, const uint32_t ***t, size_t *l,
-    size_t *m)
+npfctl_ncode_add_target(nc_inf_t *ni, const uint32_t *pc)
 {
-	size_t q = npfctl_ncode_get_target(pc, *t, *l);
+	size_t i = npfctl_ncode_get_target(ni, pc);
 
-	if (q != (size_t)~0)
-		return q;
+	/* If found, just return the index. */
+	if (i != (size_t)-1) {
+		return i;
+	}
 
-	if (*l <= *m) {
-		*m += 10;
-		*t = xrealloc(*t, *m * sizeof(**t));
+	/* Grow array, if needed, and add a new target. */
+	if (ni->ni_targidx == ni->ni_targsize) {
+		ni->ni_targsize += 16;
+		ni->ni_targs = xrealloc(ni->ni_targs,
+		    ni->ni_targsize * sizeof(uint32_t));
 	}
-	q = *l;
-	(*t)[(*l)++] = pc;
-	return q;
+	assert(ni->ni_targidx < ni->ni_targsize);
+	i = ni->ni_targidx++;
+	ni->ni_targs[i] = pc;
+	return i;
 }
 
 static void
-npfctl_ncode_add_vp(char *buf, nc_inf_t *nci, unsigned idx)
+npfctl_ncode_add_vp(nc_inf_t *ni, char *buf, unsigned idx)
 {
-	npfvar_t *vl = nci->nci_vlist[idx];
+	npfvar_t *vl = ni->ni_vlist[idx];
 
 	if (vl == NULL) {
 		vl = npfvar_create(".list");
-		nci->nci_vlist[idx] = vl;
+		ni->ni_vlist[idx] = vl;
 	}
 	npfvar_t *vp = npfvar_create(".string");
 	npfvar_add_element(vp, NPFVAR_STRING, buf, strlen(buf) + 1);
@@ -116,56 +125,52 @@
 }
 
 static const char *
-npfctl_ncode_operand(char *buf, size_t bufsiz, uint8_t op, const uint32_t *st,
-    const uint32_t *ipc, const uint32_t **pcv, size_t *lenv,
-    const uint32_t ***t, size_t *l, size_t *m, nc_inf_t *nci)
+npfctl_ncode_operand(nc_inf_t *ni, char *buf, size_t bufsiz, uint8_t operand)
 {
-	const uint32_t *pc = *pcv;
-	size_t len = *lenv;
+	const uint32_t op = *ni->ni_pc;
 	struct sockaddr_storage ss;
+	unsigned advance;
 
-	switch (op) {
+	/* Advance by one is a default for most cases. */
+	advance = 1;
+
+	switch (operand) {
 	case NPF_OPERAND_NONE:
 		abort();
 
 	case NPF_OPERAND_REGISTER:
-		if (*pc & ~0x3) {
+		if (op & ~0x3) {
 			warnx("invalid register operand 0x%x at offset %td",
-			    *pc, pc - st);
+			    op, ni->ni_pc - ni->ni_buf);
 			return NULL;
 		}
-		snprintf(buf, bufsiz, "R%d", *pc);
-		ADVANCE(1, NULL);
+		snprintf(buf, bufsiz, "R%d", op);
 		break;
 
 	case NPF_OPERAND_KEY:
-		snprintf(buf, bufsiz, "key=<0x%x>", *pc);
-		ADVANCE(1, NULL);
+		snprintf(buf, bufsiz, "key=<0x%x>", op);
 		break;
 
 	case NPF_OPERAND_VALUE:
-		snprintf(buf, bufsiz, "value=<0x%x>", *pc);
-		ADVANCE(1, NULL);
+		snprintf(buf, bufsiz, "value=<0x%x>", op);
 		break;
 
 	case NPF_OPERAND_SD:
-		if (*pc & ~0x1) {
+		if (op & ~0x1) {
 			warnx("invalid src/dst operand 0x%x at offset %td",
-			    *pc, pc - st);
+			    op, ni->ni_pc - ni->ni_buf);
 			return NULL;
 		}
-		bool srcdst = (*pc == NPF_OPERAND_SD_SRC);
-		if (nci) {
-			nci->nci_srcdst = srcdst;
+		bool srcdst = (op == NPF_OPERAND_SD_SRC);
+		if (ni) {
+			ni->ni_srcdst = srcdst;
 		}
 		snprintf(buf, bufsiz, "%s", srcdst ? "SRC" : "DST");
-		ADVANCE(1, NULL);
 		break;
 
 	case NPF_OPERAND_REL_ADDRESS:
-		snprintf(buf, bufsiz, "+%zu",
-		    npfctl_ncode_add_target(ipc + *pc, t, l, m));
-		ADVANCE(1, NULL);
+		snprintf(buf, bufsiz, "L%zu",
+		    npfctl_ncode_add_target(ni, ni->ni_ipc + op));
 		break;
 
 	case NPF_OPERAND_NET_ADDRESS4: {
@@ -173,13 +178,13 @@
 		sin->sin_len = sizeof(*sin);
 		sin->sin_family = AF_INET;
 		sin->sin_port = 0;
-		memcpy(&sin->sin_addr, pc, sizeof(sin->sin_addr));
+		memcpy(&sin->sin_addr, ni->ni_pc, sizeof(sin->sin_addr));
 		sockaddr_snprintf(buf, bufsiz, "%a", (struct sockaddr *)sin);
-		if (nci) {
-			npfctl_ncode_add_vp(buf, nci, nci->nci_srcdst ?
+		if (ni) {
+			npfctl_ncode_add_vp(ni, buf, ni->ni_srcdst ?
 			    NPF_SHOW_SRCADDR : NPF_SHOW_DSTADDR);
 		}
-		ADVANCE(sizeof(sin->sin_addr) / sizeof(*pc), NULL);
+		advance = sizeof(sin->sin_addr) / sizeof(op);
 		break;
 	}
 	case NPF_OPERAND_NET_ADDRESS6: {
@@ -187,139 +192,172 @@
 		sin6->sin6_len = sizeof(*sin6);
 		sin6->sin6_family = AF_INET6;
 		sin6->sin6_port = 0;
-		memcpy(&sin6->sin6_addr, pc, sizeof(sin6->sin6_addr));
+		memcpy(&sin6->sin6_addr, ni->ni_pc, sizeof(sin6->sin6_addr));
 		sockaddr_snprintf(buf, bufsiz, "%a", (struct sockaddr *)sin6);
-		if (nci) {
-			npfctl_ncode_add_vp(buf, nci, nci->nci_srcdst ?
+		if (ni) {
+			npfctl_ncode_add_vp(ni, buf, ni->ni_srcdst ?
 			    NPF_SHOW_SRCADDR : NPF_SHOW_DSTADDR);
 		}
-		ADVANCE(sizeof(sin6->sin6_addr) / sizeof(*pc), NULL);
+		advance = sizeof(sin6->sin6_addr) / sizeof(op);
 		break;
 	}
 	case NPF_OPERAND_ETHER_TYPE:
-		snprintf(buf, bufsiz, "ether=0x%x", *pc);
-		ADVANCE(1, NULL);
+		snprintf(buf, bufsiz, "ether=0x%x", op);
 		break;
 
 	case NPF_OPERAND_SUBNET: {
-		snprintf(buf, bufsiz, "/%d", *pc);
-		if (nci) {
-			npfctl_ncode_add_vp(buf, nci, nci->nci_srcdst ?
+		snprintf(buf, bufsiz, "/%d", op);
+		if (ni) {
+			npfctl_ncode_add_vp(ni, buf, ni->ni_srcdst ?
 			    NPF_SHOW_SRCADDR : NPF_SHOW_DSTADDR);
 		}
-		ADVANCE(1, NULL);
 		break;
 	}
 	case NPF_OPERAND_LENGTH:
-		snprintf(buf, bufsiz, "length=%d", *pc);
-		ADVANCE(1, NULL);
+		snprintf(buf, bufsiz, "length=%d", op);
 		break;
 
 	case NPF_OPERAND_TABLE_ID:
-		if (nci) {
-			snprintf(buf, bufsiz, "<%d>", *pc);
-			npfctl_ncode_add_vp(buf, nci, nci->nci_srcdst ?
+		if (ni) {
+			snprintf(buf, bufsiz, "<%d>", op);
+			npfctl_ncode_add_vp(ni, buf, ni->ni_srcdst ?
 			    NPF_SHOW_SRCADDR : NPF_SHOW_DSTADDR);
 		}
-		snprintf(buf, bufsiz, "id=%d", *pc);
-		ADVANCE(1, NULL);
+		snprintf(buf, bufsiz, "id=%d", op);
 		break;
 
-	case NPF_OPERAND_ICMP4_TYPE_CODE:
-		if (*pc & ~0xffff) {
+	case NPF_OPERAND_ICMP4_TYPE_CODE: {
+		uint8_t type = (op & 31) ? op >> 8 : 0;
+		uint8_t code = (op & 30) ? op & 0xff : 0;
+
+		if (op & ~0xc000ffff) {
 			warnx("invalid icmp/type operand 0x%x at offset %td",
-			    *pc, pc - st);
+			    op, ni->ni_pc - ni->ni_buf);
 			return NULL;
 		}
-		snprintf(buf, bufsiz, "type=%d, code=%d", *pc >> 8, *pc & 0xff);
-		if (nci) {
-			npfctl_ncode_add_vp(buf, nci, NPF_SHOW_ICMP);
+		snprintf(buf, bufsiz, "type=%d, code=%d", type, code);
+		if (ni) {
+			ni->ni_proto |= NC_MATCH_ICMP;
+			if (type || code) {
+				snprintf(buf, bufsiz,
+				    "icmp-type %d code %d", type, code);
+				npfctl_ncode_add_vp(ni, buf, NPF_SHOW_ICMP);
+			}
 		}
-		ADVANCE(1, NULL);
 		break;
-
-	case NPF_OPERAND_TCP_FLAGS_MASK:
-		if (*pc & ~0xffff) {
+	}
+	case NPF_OPERAND_TCP_FLAGS_MASK: {
+		uint8_t tf = op >> 8, tf_mask = op & 0xff;
+		if (op & ~0xffff) {
 			warnx("invalid flags/mask operand 0x%x at offset %td",
-			    *pc, pc - st);
+			    op, ni->ni_pc - ni->ni_buf);
 			return NULL;
 		}
-		snprintf(buf, bufsiz, "type=%d, code=%d", *pc >> 8, *pc & 0xff);
-		if (nci) {
-			npfctl_ncode_add_vp(buf, nci, NPF_SHOW_TCPF);
+		snprintf(buf, bufsiz, "flags=0x%x, mask=%0xx", tf, tf_mask);
+		if (ni) {
+			ni->ni_proto |= NC_MATCH_TCP;
+			npfctl_ncode_add_vp(ni, buf, NPF_SHOW_TCPF);
 		}
-		ADVANCE(1, NULL);
 		break;
-
+	}
 	case NPF_OPERAND_PORT_RANGE: {
-		in_port_t p1 = ntohs(*pc >> 16), p2 = ntohs(*pc & 0xffff);
+		in_port_t p1 = ntohs(op >> 16), p2 = ntohs(op & 0xffff);
 
 		if (p1 == p2) {
 			snprintf(buf, bufsiz, "%d", p1);
 		} else {
 			snprintf(buf, bufsiz, "%d-%d", p1, p2);
 		}
-		if (nci) {
-			npfctl_ncode_add_vp(buf, nci, nci->nci_srcdst ?
+		if (ni) {
+			npfctl_ncode_add_vp(ni, buf, ni->ni_srcdst ?
 			    NPF_SHOW_SRCPORT : NPF_SHOW_DSTPORT);
 		}
-		ADVANCE(1, NULL);
 		break;
 	}
 	default:
-		warnx("invalid operand %d at offset %td", op, pc - st);
+		warnx("invalid operand %d at offset %td",
+		    operand, ni->ni_pc - ni->ni_buf);
 		return NULL;
 	}
 
-	*pcv = pc;
-	*lenv = len;
+	if (ni->ni_left < sizeof(op) * advance) {
+		warnx("ran out of bytes");
+		return NULL;
+	}
+	ni->ni_pc += advance;
+	ni->ni_left -= sizeof(op) * advance;
 	return buf;
 }
 
+nc_inf_t *
+npfctl_ncode_disinf(FILE *fp)
+{
+	nc_inf_t *ni = zalloc(sizeof(nc_inf_t));
+
+	memset(ni, 0, sizeof(nc_inf_t));
+	ni->ni_fp = fp;
+	return ni;
+}
+
 int
-npfctl_ncode_disassemble(FILE *fp, const void *v, size_t len, nc_inf_t *nci)
+npfctl_ncode_disassemble(nc_inf_t *ni, const void *v, size_t len)
 {
-	const uint32_t *ipc, *pc = v;
-	const uint32_t *st = v;
-	const struct npf_instruction *ni;
-	char buf[256];
-	const uint32_t **targ;
-	size_t tlen, mlen, target;
+	FILE *fp = ni->ni_fp;
 	int error = -1;
 
-	targ = NULL;
-	mlen = tlen = 0;
-	while (len) {
-		/* Get the opcode */
-		if (*pc & ~0xff) {
-			warnx("invalid opcode 0x%x at offset (%td)", *pc,
-			    pc - st);
+	ni->ni_buf = v;
+	ni->ni_left = len;
+	ni->ni_pc = v;
+
+	while (ni->ni_left) {
+		const struct npf_instruction *insn;
+		const uint32_t opcode = *ni->ni_pc;
+		size_t target;
+
+		/* Get the opcode. */
+		if (opcode & ~0xff) {
+			warnx("invalid opcode 0x%x at offset (%td)",
+			    opcode, ni->ni_pc - ni->ni_buf);
 			goto out;
 		}
-		ni = &npf_instructions[*pc];
-		if (ni->name == NULL) {
-			warnx("invalid opcode 0x%x at offset (%td)", *pc,
-			    pc - st);
+		insn = &npf_instructions[opcode];
+		if (insn->name == NULL) {
+			warnx("invalid opcode 0x%x at offset (%td)",
+			    opcode, ni->ni_pc - ni->ni_buf);
 			goto out;
 		}
 
-		ipc = pc;
-		target = npfctl_ncode_get_target(pc, targ, tlen);
+		/*
+		 * Lookup target array and prefix with the label,
+		 * if this opcode is a jump target.
+		 */
+		ni->ni_ipc = ni->ni_pc;
+		target = npfctl_ncode_get_target(ni, ni->ni_pc);
 		if (fp) {
-			if (target != (size_t)~0)
-				fprintf(fp, "%zu:", target);
-			fprintf(fp, "\t%s", ni->name);
+			if (target != (size_t)-1) {
+				fprintf(fp, "L%zu:", target);
+			}
+			fprintf(fp, "\t%s", insn->name);
 		}
-		ADVANCE(1, -1);
+		if (ni->ni_left < sizeof(opcode)) {
+			warnx("ran out of bytes");
+			return -1;
+		}
+		ni->ni_left -= sizeof(opcode);
+		ni->ni_pc++;
 
-		for (size_t i = 0; i < __arraycount(ni->op); i++) {
+		for (size_t i = 0; i < __arraycount(insn->op); i++) {
+			const uint8_t o = insn->op[i];
 			const char *op;
-			if (ni->op[i] == NPF_OPERAND_NONE)
+			char buf[256];
+
+			if (o == NPF_OPERAND_NONE) {
 				break;
-			op = npfctl_ncode_operand(buf, sizeof(buf), ni->op[i],
-			    st, ipc, &pc, &len, &targ, &tlen, &mlen, nci);
-			if (op == NULL)
+			}
+			op = npfctl_ncode_operand(ni, buf, sizeof(buf), o);
+			if (op == NULL) {
 				goto out;
+			}
 			if (fp) {
 				fprintf(fp, "%s%s", i == 0 ? " " : ", ", op);
 			}
@@ -330,7 +368,7 @@
 	}
 	error = 0;
 out:
-	free(targ);
+	free(ni->ni_targs);
 	return error;
 }
 
@@ -342,7 +380,7 @@
 
 	if (count == 0) {
 		if (showany) {
-			printf("%s all ", name);
+			printf("%s any ", name);
 		}
 		return;
 	}
@@ -355,21 +393,47 @@
 	npfvar_destroy(vl);
 }
 
-static void
+static bool
 npfctl_show_ncode(const void *nc, size_t len)
 {
-	nc_inf_t nci;
+	nc_inf_t *ni = npfctl_ncode_disinf(NULL);
+	npfvar_t *vl;
+	bool any;
 
-	memset(&nci, 0, sizeof(nc_inf_t));
+	if (npfctl_ncode_disassemble(ni, nc, len) != 0) {
+		printf("<< ncode >> ");
+		return true;
+	}
 
-	if (npfctl_ncode_disassemble(NULL, nc, len, (void *)&nci) == 0) {
-		npfctl_show_fromto("from", nci.nci_vlist[NPF_SHOW_SRCADDR], true);
-		npfctl_show_fromto("port", nci.nci_vlist[NPF_SHOW_SRCPORT], false);
-		npfctl_show_fromto("to", nci.nci_vlist[NPF_SHOW_DSTADDR], true);
-		npfctl_show_fromto("port", nci.nci_vlist[NPF_SHOW_DSTPORT], false);
-	} else {
-		printf("<< ncode >> ");
+	switch (ni->ni_proto) {
+	case NC_MATCH_TCP:
+		printf("proto tcp ");
+		break;
+	case NC_MATCH_ICMP:
+		printf("proto icmp ");
+		if ((vl = ni->ni_vlist[NPF_SHOW_ICMP]) != NULL) {
+			printf("%s ", npfvar_expand_string(vl));
+			npfvar_destroy(vl);
+		}
+		break;
+	default:
+		break;
 	}
+
+	any = false;
+	if (ni->ni_vlist[NPF_SHOW_SRCADDR] || ni->ni_vlist[NPF_SHOW_SRCPORT]) {
+		npfctl_show_fromto("from", ni->ni_vlist[NPF_SHOW_SRCADDR], true);
+		npfctl_show_fromto("port", ni->ni_vlist[NPF_SHOW_SRCPORT], false);
+		any = true;
+	}
+	if (ni->ni_vlist[NPF_SHOW_DSTADDR] || ni->ni_vlist[NPF_SHOW_DSTPORT]) {
+		npfctl_show_fromto("to", ni->ni_vlist[NPF_SHOW_DSTADDR], true);
+		npfctl_show_fromto("port", ni->ni_vlist[NPF_SHOW_DSTPORT], false);
+		any = true;
+	}
+
+	free(ni);
+	return any;
 }
 
 #define	NPF_RSTICMP		(NPF_RULE_RETRST | NPF_RULE_RETICMP)
@@ -414,7 +478,7 @@
 		const char *rname = rg.rg_name;
 
 		if (ingroup) {
-			puts("}");
+			printf("}\n\n");
 		}
 		ingroup = true;
 		if (rg.rg_attr & NPF_RULE_DEFAULT) {
@@ -450,12 +514,9 @@
 	}
 
 	nc = _npf_rule_ncode(nrl, &nclen);
-	if (nc) {
-		npfctl_show_ncode(nc, nclen);
-	} else {
+	if (!nc || npfctl_show_ncode(nc, nclen)) {
 		printf("all ");
 	}
-	/* apply <rproc> */
 
 	if ((rproc = _npf_rule_rproc(nrl)) != NULL) {
 		printf("apply \"%s\"", rproc);
--- a/usr.sbin/npf/npfctl/npf_ncgen.c	Fri Jun 15 23:01:16 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_ncgen.c	Fri Jun 15 23:24:08 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_ncgen.c,v 1.9 2012/05/30 21:30:07 rmind Exp $	*/
+/*	$NetBSD: npf_ncgen.c,v 1.10 2012/06/15 23:24:08 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_ncgen.c,v 1.9 2012/05/30 21:30:07 rmind Exp $");
+__RCSID("$NetBSD: npf_ncgen.c,v 1.10 2012/06/15 23:24:08 rmind Exp $");
 
 #include <stdlib.h>
 #include <stddef.h>
@@ -333,8 +333,8 @@
 
 	/* OP, code, type (2 words) */
 	*nc++ = NPF_OPCODE_ICMP4;
-	*nc++ = (type == -1 ? 0 : (1 << 31) & (type & 0xff << 8)) |
-		(code == -1 ? 0 : (1 << 31) & (code & 0xff));
+	*nc++ = (type == -1 ? 0 : (1 << 31) | ((type & 0xff) << 8)) |
+		(code == -1 ? 0 : (1 << 30) | (code & 0xff));
 
 	/* Comparison block (2 words). */
 	npfctl_ncgen_addjmp(ctx, &nc);
@@ -388,5 +388,16 @@
 void
 npfctl_ncgen_print(const void *code, size_t len)
 {
-	npfctl_ncode_disassemble(stdout, code, len, NULL);
+#if 0
+	const uint32_t *op = code;
+
+	while (len) {
+		printf("\t> |0x%02x|\n", (u_int)*op++);
+		len -= sizeof(*op);
+	}
+#else
+	nc_inf_t *ni = npfctl_ncode_disinf(stdout);
+	npfctl_ncode_disassemble(ni, code, len);
+	free(ni);
+#endif
 }
--- a/usr.sbin/npf/npfctl/npf_parse.y	Fri Jun 15 23:01:16 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_parse.y	Fri Jun 15 23:24:08 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_parse.y,v 1.7 2012/05/30 21:30:07 rmind Exp $	*/
+/*	$NetBSD: npf_parse.y,v 1.8 2012/06/15 23:24:08 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -73,8 +73,9 @@
 %token			ALL
 %token			ANY
 %token			APPLY
-%token			ARROW
-%token			BINAT
+%token			ARROWBOTH
+%token			ARROWLEFT
+%token			ARROWRIGHT
 %token			BLOCK
 %token			CURLY_CLOSE
 %token			CURLY_OPEN
@@ -83,6 +84,7 @@
 %token			COMMA
 %token			DEFAULT
 %token			TDYNAMIC
+%token			TSTATIC
 %token			EQ
 %token			TFILE
 %token			FLAGS
@@ -95,8 +97,8 @@
 %token			INET
 %token			INET6
 %token			INTERFACE
+%token			MAP
 %token			MINUS
-%token			NAT
 %token			NAME
 %token			ON
 %token			OUT
@@ -108,7 +110,6 @@
 %token			PROTO
 %token			FAMILY
 %token			FINAL
-%token			RDR
 %token			RETURN
 %token			RETURNICMP
 %token			RETURNRST
@@ -136,10 +137,11 @@
 %type	<str>		opt_apply
 %type	<num>		ifindex, port, opt_final, on_iface
 %type	<num>		block_or_pass, rule_dir, block_opts, family, opt_family
-%type	<num>		opt_stateful, icmp_type, table_type
+%type	<num>		opt_stateful, icmp_type, table_type, map_sd, map_type
 %type	<var>		addr_or_iface, port_range, icmp_type_and_code
 %type	<var>		filt_addr, addr_and_mask, tcp_flags, tcp_flags_and_mask
 %type	<var>		modulearg_opts, procs, proc_op, modulearg, moduleargs
+%type	<addrport>	mapseg
 %type	<filtopts>	filt_opts, all_or_filt_opts
 %type	<optproto>	opt_proto
 %type	<rulegroup>	group_attr, group_opt
@@ -147,6 +149,7 @@
 %union {
 	char *		str;
 	unsigned long	num;
+	addr_port_t	addrport;
 	filt_opts_t	filtopts;
 	npfvar_t *	var;
 	opt_proto_t	optproto;
@@ -167,7 +170,7 @@
 line
 	: def
 	| table
-	| nat
+	| map
 	| group
 	| rproc
 	|
@@ -252,30 +255,34 @@
 	| TFILE STRING	{ $$ = $2; }
 	;
 
-nat
-	: natdef
-	| binatdef
-	| rdrdef
+map_sd
+	: TSTATIC	{ $$ = NPFCTL_NAT_STATIC; }
+	| TDYNAMIC	{ $$ = NPFCTL_NAT_DYNAMIC; }
+	|		{ $$ = NPFCTL_NAT_DYNAMIC; }
 	;
 
-natdef
-	: NAT ifindex filt_opts ARROW addr_or_iface
+map_type
+	: ARROWBOTH	{ $$ = NPF_NATIN | NPF_NATOUT; }
+	| ARROWLEFT	{ $$ = NPF_NATIN; }
+	| ARROWRIGHT	{ $$ = NPF_NATOUT; }
+	;
+
+mapseg
+	: addr_or_iface port_range
 	{
-		npfctl_build_nat(NPFCTL_NAT, $2, &$3, $5, NULL);
+		$$.ap_netaddr = $1;
+		$$.ap_portrange = $2;
 	}
 	;
 
-binatdef
-	: BINAT ifindex filt_opts ARROW addr_or_iface
+map
+	: MAP ifindex map_sd mapseg map_type mapseg PASS filt_opts
 	{
-		npfctl_build_nat(NPFCTL_BINAT, $2, &$3, $5, $3.fo_from);
+		npfctl_build_nat($3, $5, $2, &$4, &$6, &$8);
 	}
-	;
-
-rdrdef
-	: RDR ifindex filt_opts ARROW addr_or_iface port_range
+	| MAP ifindex map_sd mapseg map_type mapseg
 	{
-		npfctl_build_nat(NPFCTL_RDR, $2, &$3, $5, $6);
+		npfctl_build_nat($3, $5, $2, &$4, &$6, NULL);
 	}
 	;
 
@@ -490,10 +497,10 @@
 all_or_filt_opts
 	: ALL
 	{
-		$$.fo_from = NULL;
-		$$.fo_from_port_range = NULL;
-		$$.fo_to = NULL;
-		$$.fo_to_port_range = NULL;
+		$$.fo_from.ap_netaddr = NULL;
+		$$.fo_from.ap_portrange = NULL;
+		$$.fo_to.ap_netaddr = NULL;
+		$$.fo_to.ap_portrange = NULL;
 	}
 	| filt_opts	{ $$ = $1; }
 	;
@@ -518,24 +525,24 @@
 filt_opts
 	: FROM filt_addr port_range TO filt_addr port_range
 	{
-		$$.fo_from = $2;
-		$$.fo_from_port_range = $3;
-		$$.fo_to = $5;
-		$$.fo_to_port_range = $6;
+		$$.fo_from.ap_netaddr = $2;
+		$$.fo_from.ap_portrange = $3;
+		$$.fo_to.ap_netaddr = $5;
+		$$.fo_to.ap_portrange = $6;
 	}
 	| FROM filt_addr port_range
 	{
-		$$.fo_from = $2;
-		$$.fo_from_port_range = $3;
-		$$.fo_to = NULL;
-		$$.fo_to_port_range = NULL;
+		$$.fo_from.ap_netaddr = $2;
+		$$.fo_from.ap_portrange = $3;
+		$$.fo_to.ap_netaddr = NULL;
+		$$.fo_to.ap_portrange = NULL;
 	}
 	| TO filt_addr port_range
 	{
-		$$.fo_from = NULL;
-		$$.fo_from_port_range = NULL;
-		$$.fo_to = $2;
-		$$.fo_to_port_range = $3;
+		$$.fo_from.ap_netaddr = NULL;
+		$$.fo_from.ap_portrange = NULL;
+		$$.fo_to.ap_netaddr = $2;
+		$$.fo_to.ap_portrange = $3;
 	}
 	;
 
@@ -606,11 +613,12 @@
 	{
 		$$ = npfctl_parse_port_range($2, $2);
 	}
-	| PORT port MINUS port	/* port from:to */
+	| PORT port MINUS port	/* port from-to */
 	{
 		$$ = npfctl_parse_port_range($2, $4);
 	}
-	| PORT VAR_ID {
+	| PORT VAR_ID
+	{
 		$$ = npfctl_parse_port_range_variable($2);
 	}
 	|
--- a/usr.sbin/npf/npfctl/npf_scan.l	Fri Jun 15 23:01:16 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_scan.l	Fri Jun 15 23:24:08 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_scan.l,v 1.2 2012/05/30 21:30:07 rmind Exp $	*/
+/*	$NetBSD: npf_scan.l,v 1.3 2012/06/15 23:24:08 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -53,14 +53,16 @@
 type			return TYPE;
 hash			return HASH;
 tree			return TREE;
+static			return TSTATIC;
 dynamic			return TDYNAMIC;
 file			return TFILE;
-nat			return NAT;
-binat			return BINAT;
-"->"			return ARROW;
+map			return MAP;
+"<->"			return ARROWBOTH;
+"<-"			return ARROWLEFT;
+"->"			return ARROWRIGHT;
 "-"			return MINUS;
-rdr			return RDR;
 procedure		return PROCEDURE;
+\\\n			yylineno++; yycolumn = 0;
 \n			yylineno++; yycolumn = 0; return SEPLINE;
 ;			return SEPLINE;
 name			return NAME;
--- a/usr.sbin/npf/npfctl/npfctl.c	Fri Jun 15 23:01:16 2012 +0000
+++ b/usr.sbin/npf/npfctl/npfctl.c	Fri Jun 15 23:24:08 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npfctl.c,v 1.11 2012/05/30 21:30:07 rmind Exp $	*/
+/*	$NetBSD: npfctl.c,v 1.12 2012/06/15 23:24:08 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npfctl.c,v 1.11 2012/05/30 21:30:07 rmind Exp $");
+__RCSID("$NetBSD: npfctl.c,v 1.12 2012/06/15 23:24:08 rmind Exp $");
 
 #include <sys/ioctl.h>
 #include <sys/stat.h>
@@ -338,14 +338,14 @@
 	cmd = argv[1];
 
 	if (strcmp(cmd, "debug") == 0) {
-		const char *cfg = argc > 2 ? argv[2] : "npf.conf";
+		const char *cfg = argc > 2 ? argv[2] : "/tmp/npf.conf";
 		npfctl_config_init(true);
 		npfctl_parsecfg(cfg);
 		npfctl_config_send(0);
 		return EXIT_SUCCESS;
 	}
 
-	/* Find and call the subroutine */
+	/* Find and call the subroutine. */
 	for (int n = 0; operations[n].cmd != NULL; n++) {
 		if (strcmp(cmd, operations[n].cmd) != 0)
 			continue;
--- a/usr.sbin/npf/npfctl/npfctl.h	Fri Jun 15 23:01:16 2012 +0000
+++ b/usr.sbin/npf/npfctl/npfctl.h	Fri Jun 15 23:24:08 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npfctl.h,v 1.14 2012/05/30 21:30:07 rmind Exp $	*/
+/*	$NetBSD: npfctl.h,v 1.15 2012/06/15 23:24:08 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -57,11 +57,14 @@
 	in_port_t	pr_end;
 } port_range_t;
 
+typedef struct addr_port {
+	npfvar_t *	ap_netaddr;
+	npfvar_t *	ap_portrange;
+} addr_port_t;
+
 typedef struct filt_opts {
-	npfvar_t *	fo_from;
-	npfvar_t *	fo_from_port_range;
-	npfvar_t *	fo_to;
-	npfvar_t *	fo_to_port_range;
+	addr_port_t	fo_from;
+	addr_port_t	fo_to;
 } filt_opts_t;
 
 typedef struct opt_proto {
@@ -100,7 +103,7 @@
 npfvar_t *	npfctl_parse_tcpflag(const char *);
 npfvar_t *	npfctl_parse_table_id(const char *);
 npfvar_t * 	npfctl_parse_icmpcode(const char *);
-npfvar_t * 	npfctl_parse_icmp(uint8_t, uint8_t);
+npfvar_t * 	npfctl_parse_icmp(int, int);
 npfvar_t *	npfctl_parse_iface(const char *);
 npfvar_t *	npfctl_parse_port_range(in_port_t, in_port_t);
 npfvar_t *	npfctl_parse_port_range_variable(const char *);
@@ -119,6 +122,7 @@
 
 #define	NC_MATCH_TCP		0x04
 #define	NC_MATCH_UDP		0x08
+#define	NC_MATCH_ICMP		0x10
 
 nc_ctx_t *	npfctl_ncgen_create(void);
 void *		npfctl_ncgen_complete(nc_ctx_t *, size_t *);
@@ -137,12 +141,20 @@
 void		npfctl_gennc_tcpfl(nc_ctx_t *, uint8_t, uint8_t);
 
 /*
+ * N-code disassembler.
+ */
+
+typedef struct nc_inf nc_inf_t;
+
+nc_inf_t *	npfctl_ncode_disinf(FILE *);
+int		npfctl_ncode_disassemble(nc_inf_t *, const void *, size_t);
+
+/*
  * Configuration building interface.
  */
 
-#define	NPFCTL_RDR		1
-#define	NPFCTL_BINAT		2
-#define	NPFCTL_NAT		3
+#define	NPFCTL_NAT_DYNAMIC	1
+#define	NPFCTL_NAT_STATIC	2
 
 void		npfctl_config_init(bool);
 int		npfctl_config_send(int);
@@ -152,16 +164,8 @@
 void		npfctl_build_group(const char *, int, u_int);
 void		npfctl_build_rule(int, u_int, sa_family_t,
 		    const opt_proto_t *, const filt_opts_t *, const char *);
-void		npfctl_build_nat(int, u_int, const filt_opts_t *,
-		    npfvar_t *, npfvar_t *);
+void		npfctl_build_nat(int, int, u_int, const addr_port_t *,
+		    const addr_port_t *, const filt_opts_t *);
 void		npfctl_build_table(const char *, u_int, const char *);
 
-/*
- * N-code disassembler.
- */
-typedef struct nc_inf nc_inf_t;
-
-int		npfctl_ncode_disassemble(FILE *, const void *, size_t,
-		    nc_inf_t *);
-
 #endif