diff --git a/lib/libipfw3/basic/ipfw3_basic.c b/lib/libipfw3/basic/ipfw3_basic.c
index d686295..0282642 100644
--- a/lib/libipfw3/basic/ipfw3_basic.c
+++ b/lib/libipfw3/basic/ipfw3_basic.c
@@ -56,7 +56,7 @@
 #include <net/pfil.h>
 
 #include "../../../sys/net/ipfw3/ip_fw3.h"
-#include "../../../sbin/ipfw3/ipfw.h"
+#include "../../../sbin/ipfw3/ipfw3.h"
 #include "ipfw3_basic.h"
 
 
@@ -96,21 +96,7 @@ static struct char_int_map ether_types[] = {
 	{ NULL, 	0 }
 };
 
-/**
- * match_token takes a table and a string, returns the value associated
- * with the string (0 meaning an error in most cases)
- */
-static int
-match_token(struct char_int_map *table, char *string)
-{
-	while (table->key) {
-		if (strcmp(table->key, string) == 0)
-			return table->val;
 
-		table++;
-	}
-	return 0;
-};
 
 static char *
 match_token2(struct char_int_map *table, int val)
diff --git a/sbin/ipfw3/Makefile b/sbin/ipfw3/Makefile
index 07e6fa2..8ac691e 100644
--- a/sbin/ipfw3/Makefile
+++ b/sbin/ipfw3/Makefile
@@ -1,9 +1,10 @@
 # $FreeBSD: src/sbin/ipfw/Makefile,v 1.6.6.3 2002/07/24 03:21:23 luigi Exp $
 
-PROG=	ipfw3
-MAN=	ipfw3.8
-SRCS=	ipfw3.c
+PROG =	ipfw3
+MAN =	ipfw3.8
+SRCS =	ipfw3.c
 SRCS += ipfw3sync.c ipfw3sync.h
+SRCS += ipfw3nat.c ipfw3nat.h
 WARNS?=	2
 
 .include <bsd.prog.mk>
diff --git a/sbin/ipfw3/ipfw.h b/sbin/ipfw3/ipfw.h
deleted file mode 100644
index 94130e2..0000000
--- a/sbin/ipfw3/ipfw.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
- *
- * This code is derived from software contributed to The DragonFly Project
- * by Bill Yuan <bycn82@gmail.com>
- *
- * 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.
- * 3. Neither the name of The DragonFly Project nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific, prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
- * COPYRIGHT HOLDERS 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.
- */
-
-
-#ifndef _IPFW_H
-#define _IPFW_H
-
-
-struct char_int_map {
-	char *key;
-	int val;
-};
-
-
-typedef void (*parser_func)(ipfw_insn **cmd,int *ac, char **av[]);
-typedef void (*shower_func)(ipfw_insn *cmd, int show_or);
-typedef void (*register_func)(int module, int opcode,parser_func parser,shower_func shower);
-typedef void (*register_keyword)(int module,int opcode,char *word,int type);
-void register_ipfw_keyword(int module, int opcode,char *word,int type);
-void register_ipfw_func(int module, int opcode,parser_func parser,shower_func shower);
-typedef void (*init_module)(register_func func,register_keyword keyword);
-int do_get_x(int optname, void *rule, int *optlen);
-int do_set_x(int optname, void *rule, int optlen);
-
-#endif
diff --git a/sbin/ipfw3/ipfw3.c b/sbin/ipfw3/ipfw3.c
index d303255..c61a7df 100644
--- a/sbin/ipfw3/ipfw3.c
+++ b/sbin/ipfw3/ipfw3.c
@@ -64,8 +64,10 @@
 #include "../../sys/net/libalias/alias.h"
 #include "../../sys/net/ipfw3_basic/ip_fw3_basic.h"
 #include "../../sys/net/ipfw3_nat/ip_fw3_nat.h"
-#include "ipfw.h"
+
+#include "ipfw3.h"
 #include "ipfw3sync.h"
+#include "ipfw3nat.h"
 
 
 #define KEYWORD_SIZE	256
@@ -76,7 +78,6 @@
 #define WHITESP		" \t\f\v\n\r"
 #define IPFW_LIB_PATH	"/usr/lib/libipfw3%s.so"
 #define	IP_MASK_ALL	0xffffffff
-#define NAT_BUF_LEN	1024
 /*
  * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
  * This is only used in this code.
@@ -84,18 +85,6 @@
 #define IPPROTO_ETHERTYPE	0x1000
 
 /*
- * This macro returns the size of a struct sockaddr when passed
- * through a routing socket. Basically we round up sa_len to
- * a multiple of sizeof(long), with a minimum of sizeof(long).
- * The check for a NULL pointer is just a convenience, probably never used.
- * The case sa_len == 0 should only apply to empty structures.
- */
-#define SA_SIZE(sa)						\
-	( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?	\
-	sizeof(long)		:				\
-	1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
-
-/*
  * show_rules() prints the body of an ipfw rule.
  * Because the standard rule has at least proto src_ip dst_ip, we use
  * a helper function to produce these entries if not provided explicitly.
@@ -116,32 +105,6 @@
 
 #define	HAVE_IP		(HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
 
-/*
- * Definition of a port range, and macros to deal with values.
- * FORMAT: HI 16-bits == first port in range, 0 == all ports.
- *		 LO 16-bits == number of ports in range
- * NOTES: - Port values are not stored in network byte order.
- */
-
-#define port_range u_long
-
-#define GETLOPORT(x)	((x) >> 0x10)
-#define GETNUMPORTS(x)	((x) & 0x0000ffff)
-#define GETHIPORT(x)	(GETLOPORT((x)) + GETNUMPORTS((x)))
-
-/* Set y to be the low-port value in port_range variable x. */
-#define SETLOPORT(x, y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
-
-/* Set y to be the number of ports in port_range variable x. */
-#define SETNUMPORTS(x, y) ((x) = ((x) & 0xffff0000) | (y))
-
-#define INC_ARGCV() do {			\
-	(*_av)++;				\
-	(*_ac)--;				\
-	av = *_av;				\
-	ac = *_ac;				\
-} while (0)
-
 
 int		ipfw_socket = -1;	/* main RAW socket */
 int		do_resolv, 		/* Would try to resolve all */
@@ -158,42 +121,6 @@ int		do_resolv, 		/* Would try to resolve all */
 		show_sets, 		/* display rule sets */
 		verbose;
 
-enum tokens {
-	TOK_NULL=0,
-
-	TOK_IP,
-	TOK_IF,
-	TOK_ALOG,
-	TOK_DENY_INC,
-	TOK_SAME_PORTS,
-	TOK_UNREG_ONLY,
-	TOK_RESET_ADDR,
-	TOK_ALIAS_REV,
-	TOK_PROXY_ONLY,
-	TOK_REDIR_ADDR,
-	TOK_REDIR_PORT,
-	TOK_REDIR_PROTO,
-
-	TOK_PIPE,
-	TOK_QUEUE,
-	TOK_PLR,
-	TOK_NOERROR,
-	TOK_BUCKETS,
-	TOK_DSTIP,
-	TOK_SRCIP,
-	TOK_DSTPORT,
-	TOK_SRCPORT,
-	TOK_ALL,
-	TOK_MASK,
-	TOK_BW,
-	TOK_DELAY,
-	TOK_RED,
-	TOK_GRED,
-	TOK_DROPTAIL,
-	TOK_PROTO,
-	TOK_WEIGHT,
-};
-
 struct char_int_map dummynet_params[] = {
 	{ "plr", 		TOK_PLR },
 	{ "noerror", 		TOK_NOERROR },
@@ -218,22 +145,6 @@ struct char_int_map dummynet_params[] = {
 	{ NULL, 0 }
 };
 
-struct char_int_map nat_params[] = {
-	{ "ip", 		TOK_IP },
-	{ "if", 		TOK_IF },
-	{ "log", 		TOK_ALOG },
-	{ "deny_in", 		TOK_DENY_INC },
-	{ "same_ports", 	TOK_SAME_PORTS },
-	{ "unreg_only", 	TOK_UNREG_ONLY },
-	{ "reset", 		TOK_RESET_ADDR },
-	{ "reverse", 		TOK_ALIAS_REV },
-	{ "proxy_only", 	TOK_PROXY_ONLY },
-	{ "redirect_addr", 	TOK_REDIR_ADDR },
-	{ "redirect_port", 	TOK_REDIR_PORT },
-	{ "redirect_proto", 	TOK_REDIR_PROTO },
-	{ NULL, 0 },
-};
-
 struct ipfw_keyword {
 	int type;
 	char word[MAX_KEYWORD_LEN];
@@ -252,7 +163,7 @@ struct ipfw_mapping {
 struct ipfw_keyword keywords[KEYWORD_SIZE];
 struct ipfw_mapping mappings[MAPPING_SIZE];
 
-static int
+int
 match_token(struct char_int_map *table, char *string)
 {
 	while (table->key) {
@@ -1650,17 +1561,6 @@ help(void)
 	exit(EX_USAGE);
 }
 
-static void
-delete_nat_config(int ac, char *av[])
-{
-	NEXT_ARG;
-	int i = 0;
-	if (ac > 0) {
-		i = atoi(*av);
-	}
-	if (do_set_x(IP_FW_NAT_DEL, &i, sizeof(i)) == -1)
-		errx(EX_USAGE, "NAT %d in use or not exists", i);
-}
 
 static void
 delete_rules(int ac, char *av[])
@@ -1693,7 +1593,8 @@ delete_rules(int ac, char *av[])
 			if (i) {
 				exitval = 1;
 				warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
-					do_pipe == 1 ? pipe.pipe_nr : pipe.fs.fs_nr);
+					do_pipe == 1 ? pipe.pipe_nr :
+					pipe.fs.fs_nr);
 			}
 		} else {
 			rulenum = (i & 0xffff) | (do_set << 24);
@@ -1887,7 +1788,8 @@ config_dummynet(int ac, char **av)
 					if (a > 255)
 						errx(EX_DATAERR,
 						"mask: must be 8 bit");
-					pipe.fs.flow_mask.u.ip.proto = (uint8_t)a;
+					pipe.fs.flow_mask.u.ip.proto =
+						(uint8_t)a;
 				}
 				if (a != 0)
 					pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
@@ -1938,7 +1840,8 @@ end_mask:
 		case TOK_BW:
 			NEED1("bw needs bandwidth\n");
 			if (do_pipe != 1)
-				errx(EX_DATAERR, "bandwidth only valid for pipes");
+				errx(EX_DATAERR,
+					"bandwidth only valid for pipes");
 			/*
 			 * set bandwidth value
 			 */
@@ -1958,7 +1861,8 @@ end_mask:
 
 		case TOK_WEIGHT:
 			if (do_pipe == 1)
-				errx(EX_DATAERR, "weight only valid for queues");
+				errx(EX_DATAERR,
+					"weight only valid for queues");
 			NEED1("weight needs argument 0..100\n");
 			pipe.fs.weight = strtoul(av[0], &end, 0);
 			NEXT_ARG;
@@ -2182,7 +2086,8 @@ add(int ac, char *av[])
 	for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
 		if (ac > 0 && key->type == ACTION &&
 			strcmp(key->word, *av) == 0) {
-			for (j = 0, map = mappings; j<MAPPING_SIZE; j++, map++) {
+			for (j = 0, map = mappings;
+					j < MAPPING_SIZE; j++, map++) {
 				if (map->type == IN_USE &&
 					map->module == key->module &&
 					map->opcode == key->opcode) {
@@ -2208,7 +2113,8 @@ add(int ac, char *av[])
 	for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
 		if (key->type == PROTO &&
 			strcmp(key->word, "proto") == 0) {
-			for (j = 0, map = mappings; j<MAPPING_SIZE; j++, map++) {
+			for (j = 0, map = mappings;
+					j < MAPPING_SIZE; j++, map++) {
 				if (map->type == IN_USE &&
 					map->module == key->module &&
 					map->opcode == key->opcode ) {
@@ -2294,7 +2200,8 @@ done:
 	for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
 		/* pick comment out */
 		i = F_LEN(src);
-		if (src->module == MODULE_BASIC_ID && src->opcode == O_BASIC_COMMENT) {
+		if (src->module == MODULE_BASIC_ID &&
+				src->opcode == O_BASIC_COMMENT) {
 			the_comment=src;
 		} else {
 			bcopy(src, dst, i * sizeof(u_int32_t));
@@ -2385,7 +2292,8 @@ resetlog(int ac, char *av[])
 
 	if (!ac) {
 		/* clear all entries */
-		if (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_RESETLOG, NULL, 0) < 0)
+		if (setsockopt(ipfw_socket, IPPROTO_IP,
+					IP_FW_RESETLOG, NULL, 0) < 0)
 			err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)");
 		if (!do_quiet)
 			printf("Logging counts reset.\n");
@@ -2400,10 +2308,12 @@ resetlog(int ac, char *av[])
 			NEXT_ARG;
 			if (setsockopt(ipfw_socket, IPPROTO_IP,
 				IP_FW_RESETLOG, &rulenum, sizeof rulenum)) {
-				warn("rule %u: setsockopt(IP_FW_RESETLOG)", rulenum);
+				warn("rule %u: setsockopt(IP_FW_RESETLOG)",
+						rulenum);
 				failed = EX_UNAVAILABLE;
 			} else if (!do_quiet)
-				printf("Entry %d logging count reset\n", rulenum);
+				printf("Entry %d logging count reset\n",
+						rulenum);
 		} else {
 			errx(EX_DATAERR, "invalid rule number ``%s''", *av);
 		}
@@ -2418,8 +2328,6 @@ flush(void)
 	int cmd = IP_FW_FLUSH;
 	if (do_pipe) {
 		cmd = IP_DUMMYNET_FLUSH;
-	} else if (do_nat) {
-		cmd = IP_FW_NAT_FLUSH;
 	}
 	if (!do_force) {
 		int c;
@@ -2438,740 +2346,11 @@ flush(void)
 	if (do_set_x(cmd, NULL, 0) < 0 ) {
 		if (do_pipe)
 			errx(EX_USAGE, "pipe/queue in use");
-		else if (do_nat)
-			errx(EX_USAGE, "NAT configuration in use");
 		else
-			errx(EX_USAGE, "do_set_x(IP_FWFLUSH) failed");
+			errx(EX_USAGE, "do_set_x(IP_FW_FLUSH) failed");
 	}
 	if (!do_quiet) {
-		printf("Flushed all %s.\n", do_pipe ? "pipes":
-				(do_nat?"nat configurations":"rules"));
-	}
-}
-
-static void
-str2addr(const char* str, struct in_addr* addr)
-{
-	struct hostent* hp;
-
-	if (inet_aton (str, addr))
-		return;
-
-	hp = gethostbyname (str);
-	if (!hp)
-		errx (1, "unknown host %s", str);
-
-	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
-}
-
-static int
-str2portrange(const char* str, const char* proto, port_range *portRange)
-{
-	struct servent*	sp;
-	char*	sep;
-	char*	end;
-	u_short	loPort, hiPort;
-
-	/* First see if this is a service, return corresponding port if so. */
-	sp = getservbyname (str, proto);
-	if (sp) {
-		SETLOPORT(*portRange, ntohs(sp->s_port));
-		SETNUMPORTS(*portRange, 1);
-		return 0;
-	}
-
-	/* Not a service, see if it's a single port or port range. */
-	sep = strchr (str, '-');
-	if (sep == NULL) {
-		SETLOPORT(*portRange, strtol(str, &end, 10));
-		if (end != str) {
-			/* Single port. */
-			SETNUMPORTS(*portRange, 1);
-			return 0;
-		}
-
-		/* Error in port range field. */
-		errx (EX_DATAERR, "%s/%s: unknown service", str, proto);
-	}
-
-	/* Port range, get the values and sanity check. */
-	sscanf (str, "%hu-%hu", &loPort, &hiPort);
-	SETLOPORT(*portRange, loPort);
-	SETNUMPORTS(*portRange, 0); 	/* Error by default */
-	if (loPort <= hiPort)
-		SETNUMPORTS(*portRange, hiPort - loPort + 1);
-
-	if (GETNUMPORTS(*portRange) == 0)
-		errx (EX_DATAERR, "invalid port range %s", str);
-
-	return 0;
-}
-
-static int
-str2proto(const char* str)
-{
-	if (!strcmp (str, "tcp"))
-		return IPPROTO_TCP;
-	if (!strcmp (str, "udp"))
-		return IPPROTO_UDP;
-	errx (EX_DATAERR, "unknown protocol %s. Expected tcp or udp", str);
-}
-
-static int
-str2addr_portrange (const char* str, struct in_addr* addr,
-	char* proto, port_range *portRange)
-{
-	char*	ptr;
-
-	ptr = strchr (str, ':');
-	if (!ptr)
-		errx (EX_DATAERR, "%s is missing port number", str);
-
-	*ptr = '\0';
-	++ptr;
-
-	str2addr (str, addr);
-	return str2portrange (ptr, proto, portRange);
-}
-
-/*
- * Search for interface with name "ifn", and fill n accordingly:
- *
- * n->ip		ip address of interface "ifn"
- * n->if_name copy of interface name "ifn"
- */
-static void
-set_addr_dynamic(const char *ifn, struct cfg_nat *n)
-{
-	struct if_msghdr *ifm;
-	struct ifa_msghdr *ifam;
-	struct sockaddr_dl *sdl;
-	struct sockaddr_in *sin;
-	char *buf, *lim, *next;
-	size_t needed;
-	int mib[6];
-	int ifIndex, ifMTU;
-
-	mib[0] = CTL_NET;
-	mib[1] = PF_ROUTE;
-	mib[2] = 0;
-	mib[3] = AF_INET;
-	mib[4] = NET_RT_IFLIST;
-	mib[5] = 0;
-
-	/*
-	 * Get interface data.
-	 */
-	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
-		err(1, "iflist-sysctl-estimate");
-	if ((buf = malloc(needed)) == NULL)
-		errx(1, "malloc failed");
-	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
-		err(1, "iflist-sysctl-get");
-	lim = buf + needed;
-	/*
-	 * Loop through interfaces until one with
-	 * given name is found. This is done to
-	 * find correct interface index for routing
-	 * message processing.
-	 */
-	ifIndex	= 0;
-	next = buf;
-	while (next < lim) {
-		ifm = (struct if_msghdr *)next;
-		next += ifm->ifm_msglen;
-		if (ifm->ifm_version != RTM_VERSION) {
-			if (verbose)
-				warnx("routing message version %d "
-					"not understood", ifm->ifm_version);
-			continue;
-		}
-		if (ifm->ifm_type == RTM_IFINFO) {
-			sdl = (struct sockaddr_dl *)(ifm + 1);
-			if (strlen(ifn) == sdl->sdl_nlen &&
-				strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
-				ifIndex = ifm->ifm_index;
-				ifMTU = ifm->ifm_data.ifi_mtu;
-				break;
-			}
-		}
-	}
-	if (!ifIndex)
-		errx(1, "unknown interface name %s", ifn);
-	/*
-	 * Get interface address.
-	 */
-	sin = NULL;
-	while (next < lim) {
-		ifam = (struct ifa_msghdr *)next;
-		next += ifam->ifam_msglen;
-		if (ifam->ifam_version != RTM_VERSION) {
-			if (verbose)
-				warnx("routing message version %d "
-					"not understood", ifam->ifam_version);
-			continue;
-		}
-		if (ifam->ifam_type != RTM_NEWADDR)
-			break;
-		if (ifam->ifam_addrs & RTA_IFA) {
-			int i;
-			char *cp = (char *)(ifam + 1);
-
-			for (i = 1; i < RTA_IFA; i <<= 1) {
-				if (ifam->ifam_addrs & i)
-					cp += SA_SIZE((struct sockaddr *)cp);
-			}
-			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
-				sin = (struct sockaddr_in *)cp;
-				break;
-			}
-		}
-	}
-	if (sin == NULL)
-		errx(1, "%s: cannot get interface address", ifn);
-
-	n->ip = sin->sin_addr;
-	strncpy(n->if_name, ifn, IF_NAMESIZE);
-
-	free(buf);
-}
-
-static int
-setup_redir_addr(char *spool_buf, int len, int *_ac, char ***_av)
-{
-	struct cfg_redir *r;
-	struct cfg_spool *tmp;
-	char **av, *sep;
-	char tmp_spool_buf[NAT_BUF_LEN];
-	int ac, i, space, lsnat;
-
-	i=0;
-	av = *_av;
-	ac = *_ac;
-	space = 0;
-	lsnat = 0;
-	if (len >= SOF_REDIR) {
-		r = (struct cfg_redir *)spool_buf;
-		/* Skip cfg_redir at beginning of buf. */
-		spool_buf = &spool_buf[SOF_REDIR];
-		space = SOF_REDIR;
-		len -= SOF_REDIR;
-	} else {
-		goto nospace;
-	}
-
-	r->mode = REDIR_ADDR;
-	/* Extract local address. */
-	if (ac == 0)
-		errx(EX_DATAERR, "redirect_addr: missing local address");
-
-	sep = strchr(*av, ',');
-	if (sep) {		/* LSNAT redirection syntax. */
-		r->laddr.s_addr = INADDR_NONE;
-		/* Preserve av, copy spool servers to tmp_spool_buf. */
-		strncpy(tmp_spool_buf, *av, strlen(*av)+1);
-		lsnat = 1;
-	} else {
-		str2addr(*av, &r->laddr);
-	}
-	INC_ARGCV();
-
-	/* Extract public address. */
-	if (ac == 0)
-		errx(EX_DATAERR, "redirect_addr: missing public address");
-
-	str2addr(*av, &r->paddr);
-	INC_ARGCV();
-
-	/* Setup LSNAT server pool. */
-	if (sep) {
-		sep = strtok(tmp_spool_buf, ", ");
-		while (sep != NULL) {
-			tmp = (struct cfg_spool *)spool_buf;
-			if (len < SOF_SPOOL)
-				goto nospace;
-
-			len -= SOF_SPOOL;
-			space += SOF_SPOOL;
-			str2addr(sep, &tmp->addr);
-			tmp->port = ~0;
-			r->spool_cnt++;
-			/* Point to the next possible cfg_spool. */
-			spool_buf = &spool_buf[SOF_SPOOL];
-			sep = strtok(NULL, ", ");
-		}
-	}
-	return(space);
-
-nospace:
-	errx(EX_DATAERR, "redirect_addr: buf is too small\n");
-}
-
-static int
-setup_redir_port(char *spool_buf, int len, int *_ac, char ***_av)
-{
-	char **av, *sep, *protoName;
-	char tmp_spool_buf[NAT_BUF_LEN];
-	int ac, space, lsnat;
-	struct cfg_redir *r;
-	struct cfg_spool *tmp;
-	u_short numLocalPorts;
-	port_range portRange;
-
-	av = *_av;
-	ac = *_ac;
-	space = 0;
-	lsnat = 0;
-	numLocalPorts = 0;
-
-	if (len >= SOF_REDIR) {
-		r = (struct cfg_redir *)spool_buf;
-		/* Skip cfg_redir at beginning of buf. */
-		spool_buf = &spool_buf[SOF_REDIR];
-		space = SOF_REDIR;
-		len -= SOF_REDIR;
-	} else {
-		goto nospace;
-	}
-
-	r->mode = REDIR_PORT;
-	/*
-	 * Extract protocol.
-	 */
-	if (ac == 0)
-		errx (EX_DATAERR, "redirect_port: missing protocol");
-
-	r->proto = str2proto(*av);
-	protoName = *av;
-	INC_ARGCV();
-
-	/*
-	 * Extract local address.
-	 */
-	if (ac == 0)
-		errx (EX_DATAERR, "redirect_port: missing local address");
-
-	sep = strchr(*av, ',');
-	/* LSNAT redirection syntax. */
-	if (sep) {
-		r->laddr.s_addr = INADDR_NONE;
-		r->lport = ~0;
-		numLocalPorts = 1;
-		/* Preserve av, copy spool servers to tmp_spool_buf. */
-		strncpy(tmp_spool_buf, *av, strlen(*av)+1);
-		lsnat = 1;
-	} else {
-		if (str2addr_portrange (*av, &r->laddr, protoName, &portRange) != 0)
-			errx(EX_DATAERR, "redirect_port:"
-				"invalid local port range");
-
-		r->lport = GETLOPORT(portRange);
-		numLocalPorts = GETNUMPORTS(portRange);
-	}
-	INC_ARGCV();
-
-	/*
-	 * Extract public port and optionally address.
-	 */
-	if (ac == 0)
-		errx (EX_DATAERR, "redirect_port: missing public port");
-
-	sep = strchr (*av, ':');
-	if (sep) {
-		if (str2addr_portrange (*av, &r->paddr, protoName, &portRange) != 0)
-			errx(EX_DATAERR, "redirect_port:"
-				"invalid public port range");
-	} else {
-		r->paddr.s_addr = INADDR_ANY;
-		if (str2portrange(*av, protoName, &portRange) != 0)
-			errx(EX_DATAERR, "redirect_port:"
-				"invalid public port range");
-	}
-
-	r->pport = GETLOPORT(portRange);
-	r->pport_cnt = GETNUMPORTS(portRange);
-	INC_ARGCV();
-
-	/*
-	 * Extract remote address and optionally port.
-	 */
-	/*
-	 * NB: isalpha(**av) => we've to check that next parameter is really an
-	 * option for this redirect entry, else stop here processing arg[cv].
-	 */
-	if (ac != 0 && !isalpha(**av)) {
-		sep = strchr (*av, ':');
-		if (sep) {
-			if (str2addr_portrange (*av, &r->raddr,
-				protoName, &portRange) != 0)
-				errx(EX_DATAERR, "redirect_port:"
-					"invalid remote port range");
-		} else {
-			SETLOPORT(portRange, 0);
-			SETNUMPORTS(portRange, 1);
-			str2addr (*av, &r->raddr);
-		}
-		INC_ARGCV();
-	} else {
-		SETLOPORT(portRange, 0);
-		SETNUMPORTS(portRange, 1);
-		r->raddr.s_addr = INADDR_ANY;
-	}
-	r->rport = GETLOPORT(portRange);
-	r->rport_cnt = GETNUMPORTS(portRange);
-
-	/*
-	 * Make sure port ranges match up, then add the redirect ports.
-	 */
-	if (numLocalPorts != r->pport_cnt)
-		errx(EX_DATAERR, "redirect_port:"
-			"port ranges must be equal in size");
-
-	/* Remote port range is allowed to be '0' which means all ports. */
-	if (r->rport_cnt != numLocalPorts &&
-		(r->rport_cnt != 1 || r->rport != 0))
-			errx(EX_DATAERR, "redirect_port: remote port must"
-				"be 0 or equal to local port range in size");
-
-	/*
-	 * Setup LSNAT server pool.
-	 */
-	if (lsnat) {
-		sep = strtok(tmp_spool_buf, ", ");
-		while (sep != NULL) {
-			tmp = (struct cfg_spool *)spool_buf;
-			if (len < SOF_SPOOL)
-				goto nospace;
-
-			len -= SOF_SPOOL;
-			space += SOF_SPOOL;
-			if (str2addr_portrange(sep,
-				&tmp->addr, protoName, &portRange) != 0)
-				errx(EX_DATAERR, "redirect_port:"
-					"invalid local port range");
-			if (GETNUMPORTS(portRange) != 1)
-				errx(EX_DATAERR, "redirect_port: local port"
-					"must be single in this context");
-			tmp->port = GETLOPORT(portRange);
-			r->spool_cnt++;
-			/* Point to the next possible cfg_spool. */
-			spool_buf = &spool_buf[SOF_SPOOL];
-			sep = strtok(NULL, ", ");
-		}
-	}
-	return (space);
-
-nospace:
-	errx(EX_DATAERR, "redirect_port: buf is too small\n");
-}
-
-static int
-setup_redir_proto(char *spool_buf, int len, int *_ac, char ***_av)
-{
-	struct protoent *protoent;
-	struct cfg_redir *r;
-	int ac, i, space;
-	char **av;
-
-	i=0;
-	av = *_av;
-	ac = *_ac;
-	if (len >= SOF_REDIR) {
-		r = (struct cfg_redir *)spool_buf;
-		/* Skip cfg_redir at beginning of buf. */
-		spool_buf = &spool_buf[SOF_REDIR];
-		space = SOF_REDIR;
-		len -= SOF_REDIR;
-	} else {
-		goto nospace;
-	}
-	r->mode = REDIR_PROTO;
-	/*
-	 * Extract protocol.
-	 */
-	if (ac == 0)
-		errx(EX_DATAERR, "redirect_proto: missing protocol");
-
-	protoent = getprotobyname(*av);
-	if (protoent == NULL)
-		errx(EX_DATAERR, "redirect_proto: unknown protocol %s", *av);
-	else
-		r->proto = protoent->p_proto;
-
-	INC_ARGCV();
-
-	/*
-	 * Extract local address.
-	 */
-	if (ac == 0)
-		errx(EX_DATAERR, "redirect_proto: missing local address");
-	else
-		str2addr(*av, &r->laddr);
-	INC_ARGCV();
-
-	/*
-	 * Extract optional public address.
-	 */
-	if (ac == 0) {
-		r->paddr.s_addr = INADDR_ANY;
-		r->raddr.s_addr = INADDR_ANY;
-	} else {
-		/* see above in setup_redir_port() */
-		if (!isalpha(**av)) {
-			str2addr(*av, &r->paddr);
-			INC_ARGCV();
-
-			/*
-			 * Extract optional remote address.
-			 */
-			/* see above in setup_redir_port() */
-			if (ac != 0 && !isalpha(**av)) {
-				str2addr(*av, &r->raddr);
-				INC_ARGCV();
-			}
-		}
-	}
-	return (space);
-
-nospace:
-	errx(EX_DATAERR, "redirect_proto: buf is too small\n");
-}
-
-static void
-show_nat_config(char *buf) {
-	struct cfg_nat *n;
-	struct cfg_redir *t;
-	struct cfg_spool *s;
-	struct protoent *p;
-	int i, cnt, flag, off;
-
-	n = (struct cfg_nat *)buf;
-	flag = 1;
-	off = sizeof(*n);
-	printf("ipfw nat %u config", n->id);
-	if (strlen(n->if_name) != 0)
-		printf(" if %s", n->if_name);
-	else if (n->ip.s_addr != 0)
-		printf(" ip %s", inet_ntoa(n->ip));
-	while (n->mode != 0) {
-		if (n->mode & PKT_ALIAS_LOG) {
-			printf(" log");
-			n->mode &= ~PKT_ALIAS_LOG;
-		} else if (n->mode & PKT_ALIAS_DENY_INCOMING) {
-			printf(" deny_in");
-			n->mode &= ~PKT_ALIAS_DENY_INCOMING;
-		} else if (n->mode & PKT_ALIAS_SAME_PORTS) {
-			printf(" same_ports");
-			n->mode &= ~PKT_ALIAS_SAME_PORTS;
-		} else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) {
-			printf(" unreg_only");
-			n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY;
-		} else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) {
-			printf(" reset");
-			n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE;
-		} else if (n->mode & PKT_ALIAS_REVERSE) {
-			printf(" reverse");
-			n->mode &= ~PKT_ALIAS_REVERSE;
-		} else if (n->mode & PKT_ALIAS_PROXY_ONLY) {
-			printf(" proxy_only");
-			n->mode &= ~PKT_ALIAS_PROXY_ONLY;
-		}
-	}
-	/* Print all the redirect's data configuration. */
-	for (cnt = 0; cnt < n->redir_cnt; cnt++) {
-		t = (struct cfg_redir *)&buf[off];
-		off += SOF_REDIR;
-		switch (t->mode) {
-		case REDIR_ADDR:
-			printf(" redirect_addr");
-			if (t->spool_cnt == 0)
-				printf(" %s", inet_ntoa(t->laddr));
-			else
-				for (i = 0; i < t->spool_cnt; i++) {
-					s = (struct cfg_spool *)&buf[off];
-					if (i)
-						printf(", ");
-					else
-						printf(" ");
-					printf("%s", inet_ntoa(s->addr));
-					off += SOF_SPOOL;
-				}
-			printf(" %s", inet_ntoa(t->paddr));
-			break;
-		case REDIR_PORT:
-			p = getprotobynumber(t->proto);
-			printf(" redirect_port %s ", p->p_name);
-			if (!t->spool_cnt) {
-				printf("%s:%u", inet_ntoa(t->laddr), t->lport);
-				if (t->pport_cnt > 1)
-					printf("-%u", t->lport + t->pport_cnt - 1);
-			} else
-				for (i=0; i < t->spool_cnt; i++) {
-					s = (struct cfg_spool *)&buf[off];
-					if (i)
-						printf(", ");
-					printf("%s:%u", inet_ntoa(s->addr), s->port);
-					off += SOF_SPOOL;
-				}
-
-			printf(" ");
-			if (t->paddr.s_addr)
-				printf("%s:", inet_ntoa(t->paddr));
-			printf("%u", t->pport);
-			if (!t->spool_cnt && t->pport_cnt > 1)
-				printf("-%u", t->pport + t->pport_cnt - 1);
-
-			if (t->raddr.s_addr) {
-				printf(" %s", inet_ntoa(t->raddr));
-				if (t->rport) {
-					printf(":%u", t->rport);
-					if (!t->spool_cnt && t->rport_cnt > 1)
-						printf("-%u", t->rport +
-							t->rport_cnt - 1);
-				}
-			}
-			break;
-		case REDIR_PROTO:
-			p = getprotobynumber(t->proto);
-			printf(" redirect_proto %s %s", p->p_name,
-				inet_ntoa(t->laddr));
-			if (t->paddr.s_addr != 0) {
-				printf(" %s", inet_ntoa(t->paddr));
-				if (t->raddr.s_addr)
-					printf(" %s", inet_ntoa(t->raddr));
-			}
-			break;
-		default:
-			errx(EX_DATAERR, "unknown redir mode");
-			break;
-		}
-	}
-	printf("\n");
-}
-
-
-static void
-show_nat(int ac, char **av) {
-	struct cfg_nat *n;
-	struct cfg_redir *e;
-	int i, nbytes, nalloc, size;
-	int nat_cnt, redir_cnt, nat_id;
-	uint8_t *data;
-
-	nalloc = 1024;
-	size = 0;
-	data = NULL;
-
-	NEXT_ARG;
-
-	if (ac == 0)
-		nat_id = 0;
-	else
-		nat_id = strtoul(*av, NULL, 10);
-
-	nbytes = nalloc;
-	while (nbytes >= nalloc) {
-		nalloc = nalloc * 2;
-		nbytes = nalloc;
-		if ((data = realloc(data, nbytes)) == NULL) {
-			err(EX_OSERR, "realloc");
-		}
-		if (do_get_x(IP_FW_NAT_GET, data, &nbytes) < 0) {
-			err(EX_OSERR, "do_get_x(IP_FW_NAT_GET)");
-		}
-	}
-
-	if (nbytes == 0) {
-		exit(EX_OK);
-	}
-
-	nat_cnt = *((int *)data);
-	for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) {
-		n = (struct cfg_nat *)&data[i];
-		if (n->id >= 0 && n->id <= IPFW_DEFAULT_RULE) {
-			if (nat_id == 0 || n->id == nat_id)
-				show_nat_config(&data[i]);
-		}
-		i += sizeof(struct cfg_nat);
-		for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) {
-			e = (struct cfg_redir *)&data[i];
-			i += sizeof(struct cfg_redir) +
-				e->spool_cnt * sizeof(struct cfg_spool);
-		}
-	}
-}
-
-int
-get_kern_boottime(void)
-{
-	struct timeval boottime;
-	size_t size;
-	int mib[2];
-	mib[0] = CTL_KERN;
-	mib[1] = KERN_BOOTTIME;
-	size = sizeof(boottime);
-	if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
-			boottime.tv_sec != 0) {
-		return boottime.tv_sec;
-	}
-	return -1;
-}
-
-void
-show_nat_state(int ac, char **av)
-{
-	int nbytes, nalloc;
-	int nat_id;
-	uint8_t *data;
-
-	nalloc = 1024;
-	data = NULL;
-
-	NEXT_ARG;
-	if (ac == 0)
-		nat_id = 0;
-	else
-		nat_id = strtoul(*av, NULL, 10);
-
-	nbytes = nalloc;
-	while (nbytes >= nalloc) {
-		nalloc = nalloc * 2;
-		nbytes = nalloc;
-		if ((data = realloc(data, nbytes)) == NULL) {
-			err(EX_OSERR, "realloc");
-		}
-		memcpy(data, &nat_id, sizeof(int));
-		if (do_get_x(IP_FW_NAT_LOG, data, &nbytes) < 0) {
-			err(EX_OSERR, "do_get_x(IP_FW_NAT_GET_STATE)");
-		}
-	}
-	if (nbytes == 0)
-		exit(EX_OK);
-	struct ipfw_ioc_nat_state *nat_state;
-	nat_state =(struct ipfw_ioc_nat_state *)data;
-	int count = nbytes / sizeof( struct ipfw_ioc_nat_state);
-	int i, uptime_sec;
-	uptime_sec = get_kern_boottime();
-	for (i = 0; i < count; i ++) {
-		struct protoent *pe = getprotobynumber(nat_state->link_type);
-		printf("%s ", pe->p_name);
-		printf("%s:%hu => ",inet_ntoa(nat_state->src_addr),
-				htons(nat_state->src_port));
-		printf("%s:%hu",inet_ntoa(nat_state->alias_addr),
-				htons(nat_state->alias_port));
-		printf(" -> %s:%hu ",inet_ntoa(nat_state->dst_addr),
-				htons(nat_state->dst_port));
-		if (do_time == 1) {
-			char timestr[30];
-			time_t t = _long_to_time(uptime_sec + nat_state->timestamp);
-			strcpy(timestr, ctime(&t));
-			*strchr(timestr, '\n') = '\0';
-			printf("%s ", timestr);
-		} else if (do_time == 2) {
-			printf( "%10u ", uptime_sec + nat_state->timestamp);
-		}
-		printf("\n");
-		nat_state++;
+		printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules");
 	}
 }
 
@@ -3226,107 +2405,6 @@ do_get_x(int optname, void *rule, int *optlen)
 	return retval;
 }
 
-static void
-config_nat(int ac, char **av)
-{
-	struct cfg_nat *n; 			 /* Nat instance configuration. */
-	int i, len, off, tok;
-	char *id, buf[NAT_BUF_LEN]; 	/* Buffer for serialized data. */
-
-	len = NAT_BUF_LEN;
-	/* Offset in buf: save space for n at the beginning. */
-	off = sizeof(struct cfg_nat);
-	memset(buf, 0, sizeof(buf));
-	n = (struct cfg_nat *)buf;
-
-	NEXT_ARG;
-	/* Nat id. */
-	if (ac && isdigit(**av)) {
-		id = *av;
-		i = atoi(*av);
-		NEXT_ARG;
-		n->id = i;
-	} else
-		errx(EX_DATAERR, "missing nat id");
-	if (ac == 0)
-		errx(EX_DATAERR, "missing option");
-
-	while (ac > 0) {
-		tok = match_token(nat_params, *av);
-		NEXT_ARG;
-		switch (tok) {
-		case TOK_IP:
-			if (ac == 0)
-				errx(EX_DATAERR, "missing option");
-			if (!inet_aton(av[0], &(n->ip)))
-				errx(EX_DATAERR, "bad ip address ``%s''",
-					av[0]);
-			NEXT_ARG;
-			break;
-		case TOK_IF:
-			if (ac == 0)
-				errx(EX_DATAERR, "missing option");
-			set_addr_dynamic(av[0], n);
-			NEXT_ARG;
-			break;
-		case TOK_ALOG:
-			n->mode |= PKT_ALIAS_LOG;
-			break;
-		case TOK_DENY_INC:
-			n->mode |= PKT_ALIAS_DENY_INCOMING;
-			break;
-		case TOK_SAME_PORTS:
-			n->mode |= PKT_ALIAS_SAME_PORTS;
-			break;
-		case TOK_UNREG_ONLY:
-			n->mode |= PKT_ALIAS_UNREGISTERED_ONLY;
-			break;
-		case TOK_RESET_ADDR:
-			n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
-			break;
-		case TOK_ALIAS_REV:
-			n->mode |= PKT_ALIAS_REVERSE;
-			break;
-		case TOK_PROXY_ONLY:
-			n->mode |= PKT_ALIAS_PROXY_ONLY;
-			break;
-			/*
-			 * All the setup_redir_* functions work directly in the final
-			 * buffer, see above for details.
-			 */
-		case TOK_REDIR_ADDR:
-		case TOK_REDIR_PORT:
-		case TOK_REDIR_PROTO:
-			switch (tok) {
-			case TOK_REDIR_ADDR:
-				i = setup_redir_addr(&buf[off], len, &ac, &av);
-				break;
-			case TOK_REDIR_PORT:
-				i = setup_redir_port(&buf[off], len, &ac, &av);
-				break;
-			case TOK_REDIR_PROTO:
-				i = setup_redir_proto(&buf[off], len, &ac, &av);
-				break;
-			}
-			n->redir_cnt++;
-			off += i;
-			len -= i;
-			break;
-		default:
-			errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
-		}
-	}
-	i = do_set_x(IP_FW_NAT_CFG, buf, off);
-	if (i)
-		err(1, "do_set_x(%s)", "IP_FW_NAT_CFG");
-
-	/* After every modification, we show the resultant rule. */
-	int _ac = 2;
-	char *_av[] = {"config", id};
-	show_nat(_ac, _av);
-}
-
-
 static int
 ipfw_main(int ac, char **av)
 {
@@ -3456,31 +2534,7 @@ ipfw_main(int ac, char **av)
 		}
 	} else if (!strncmp(*av, "nat", strlen(*av))) {
 		NEXT_ARG;
-		if (!strncmp(*av, "config", strlen(*av))) {
-			config_nat(ac, av);
-		} else if (!strncmp(*av, "flush", strlen(*av))) {
-			flush();
-		} else if (!strncmp(*av, "show", strlen(*av)) ||
-				!strncmp(*av, "list", strlen(*av))) {
-			if (ac > 2 && isdigit(*(av[1]))) {
-				char *p = av[1];
-				av[1] = av[2];
-				av[2] = p;
-			}
-			NEXT_ARG;
-			if (!strncmp(*av, "config", strlen(*av))) {
-				show_nat(ac, av);
-			} else if (!strncmp(*av, "state", strlen(*av))) {
-				show_nat_state(ac,av);
-			} else {
-				 errx(EX_USAGE,
-					"bad nat show command `%s'", *av);
-			}
-		} else if (!strncmp(*av, "delete", strlen(*av))) {
-			delete_nat_config(ac, av);
-		} else {
-			errx(EX_USAGE, "bad ipfw nat command `%s'", *av);
-		}
+		nat_main(ac, av);
 	} else if (!strncmp(*av, "pipe", strlen(*av)) ||
 		!strncmp(*av, "queue", strlen(*av))) {
 		NEXT_ARG;
diff --git a/sbin/ipfw3/ipfw3sync.c b/sbin/ipfw3/ipfw3sync.c
index 41fcae0..914a23d 100644
--- a/sbin/ipfw3/ipfw3sync.c
+++ b/sbin/ipfw3/ipfw3sync.c
@@ -76,7 +76,7 @@
 #include "../../sys/net/ipfw3_basic/ip_fw3_basic.h"
 #include "../../sys/net/ipfw3_nat/ip_fw3_nat.h"
 
-#include "ipfw.h"
+#include "ipfw3.h"
 #include "ipfw3sync.h"
 
 void
diff --git a/sys/net/ipfw3/ip_fw3.c b/sys/net/ipfw3/ip_fw3.c
index e77aafa..28c9c2c 100644
--- a/sys/net/ipfw3/ip_fw3.c
+++ b/sys/net/ipfw3/ip_fw3.c
@@ -135,18 +135,12 @@ struct netmsg_zent {
 	uint16_t	log_only;
 };
 
-ipfw_nat_cfg_t *ipfw_nat_cfg_ptr;
-ipfw_nat_cfg_t *ipfw_nat_del_ptr;
-ipfw_nat_cfg_t *ipfw_nat_flush_ptr;
-ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;
-ipfw_nat_cfg_t *ipfw_nat_get_log_ptr;
+ip_fw_ctl_t *ipfw_ctl_nat_ptr = NULL;
 
 /* handlers which implemented in ipfw_basic module */
 ipfw_basic_delete_state_t *ipfw_basic_flush_state_prt = NULL;
 ipfw_basic_append_state_t *ipfw_basic_append_state_prt = NULL;
 
-static struct ipfw_nat_context *ipfw_nat_ctx;
-
 extern int ip_fw_loaded;
 static uint32_t static_count;	/* # of static rules */
 static uint32_t static_ioc_len;	/* bytes of static rules */
@@ -206,7 +200,7 @@ register_ipfw_module(int module_id,char *module_name)
 		}
 		tmp++;
 	}
-	kprintf("ipfw3 module %s loaded ", module_name);
+	kprintf("ipfw3 module %s loaded\n", module_name);
 }
 
 int
@@ -242,7 +236,8 @@ decide:
 		for (i = 0; i < MAX_MODULE; i++) {
 			if (tmp->type == 1 && tmp->id == module_id) {
 				tmp->type = 0;
-				kprintf("ipfw3 module %s unloaded ", tmp->name);
+				kprintf("ipfw3 module %s unloaded\n",
+						tmp->name);
 				break;
 			}
 			tmp++;
@@ -1677,20 +1672,14 @@ ipfw_ctl(struct sockopt *sopt)
 			error = ipfw_ctl_zero_entry(rulenum,
 					sopt->sopt_name == IP_FW_RESETLOG);
 			break;
-		case IP_FW_NAT_CFG:
-			error = ipfw_nat_cfg_ptr(sopt);
-			break;
+		case IP_FW_NAT_ADD:
 		case IP_FW_NAT_DEL:
-			error = ipfw_nat_del_ptr(sopt);
-			break;
 		case IP_FW_NAT_FLUSH:
-			error = ipfw_nat_flush_ptr(sopt);
-			break;
 		case IP_FW_NAT_GET:
-			error = ipfw_nat_get_cfg_ptr(sopt);
-			break;
-		case IP_FW_NAT_LOG:
-			error = ipfw_nat_get_log_ptr(sopt);
+		case IP_FW_NAT_GET_RECORD:
+			if (ipfw_ctl_nat_ptr != NULL) {
+				error = ipfw_ctl_nat_ptr(sopt);
+			}
 			break;
 		case IP_DUMMYNET_GET:
 		case IP_DUMMYNET_CONFIGURE:
@@ -1973,11 +1962,6 @@ ipfw_ctx_init_dispatch(netmsg_t nmsg)
 	struct ipfw_context *ctx;
 	struct ip_fw *def_rule;
 
-	if (mycpuid == 0 ) {
-		ipfw_nat_ctx = kmalloc(sizeof(struct ipfw_nat_context),
-				M_IPFW3, M_WAITOK | M_ZERO);
-	}
-
 	ctx = kmalloc(sizeof(struct ipfw_context), M_IPFW3, M_WAITOK | M_ZERO);
 	ipfw_ctx[mycpuid] = ctx;
 
@@ -2025,7 +2009,7 @@ ipfw_init_dispatch(netmsg_t nmsg)
 	struct netmsg_ipfw fwmsg;
 	int error = 0;
 	if (IPFW3_LOADED) {
-		kprintf("IP firewall already loaded\n");
+		kprintf("ipfw3 already loaded\n");
 		error = EEXIST;
 		goto reply;
 	}
@@ -2039,17 +2023,9 @@ ipfw_init_dispatch(netmsg_t nmsg)
 	ip_fw_ctl_x_ptr = ipfw_ctl_x;
 	ip_fw_dn_io_ptr = ipfw_dummynet_io;
 
-	kprintf("ipfw3 initialized, default to %s, logging ",
-		(int)(ipfw_ctx[mycpuid]->ipfw_default_rule->cmd[0].opcode) ==
-		O_BASIC_ACCEPT ? "accept" : "deny");
+	kprintf("ipfw3 initialized, default to %s\n",
+			filters_default_to_accept ? "accept" : "deny");
 
-#ifdef IPFIREWALL_VERBOSE
-	fw_verbose = 1;
-#endif
-	if (fw_verbose == 0) {
-		kprintf("disabled ");
-	}
-	kprintf("\n");
 	ip_fw3_loaded = 1;
 	if (fw3_enable)
 		ipfw_hook();
@@ -2099,9 +2075,7 @@ ipfw_fini_dispatch(netmsg_t nmsg)
 			ipfw_ctx[cpu] = NULL;
 		}
 	}
-	kfree(ipfw_nat_ctx,M_IPFW3);
-	ipfw_nat_ctx = NULL;
-	kprintf("IP firewall unloaded\n");
+	kprintf("ipfw3 unloaded\n");
 
 	lwkt_replymsg(&nmsg->lmsg, error);
 }
diff --git a/sys/net/ipfw3/ip_fw3.h b/sys/net/ipfw3/ip_fw3.h
index 9fb12d5..2d40fe6 100644
--- a/sys/net/ipfw3/ip_fw3.h
+++ b/sys/net/ipfw3/ip_fw3.h
@@ -344,7 +344,6 @@ struct dn_flow_set;
 
 typedef int	ip_fw_chk_t(struct ip_fw_args *);
 typedef int	ip_fw_ctl_t(struct sockopt *);
-typedef int	ipfw_nat_cfg_t(struct sockopt *);
 typedef void ip_fw_dn_io_t(struct mbuf *, int, int, struct ip_fw_args *);
 
 
@@ -380,10 +379,6 @@ struct ipfw_state_context {
 	int	count;
 };
 
-/* place to hold the nat conf */
-struct ipfw_nat_context {
-	LIST_HEAD(, cfg_nat) nat;		/* list of nat entries */
-};
 
 typedef void (*filter_func)(int *cmd_ctl,int *cmd_val,struct ip_fw_args **args,
 struct ip_fw **f,ipfw_insn *cmd,uint16_t ip_len);
@@ -542,11 +537,11 @@ typedef void ipfw_sync_send_state_t(struct ip_fw_state *, int cpu, int hash);
 
 #define IP_FW_MODULE		67  /* get modules names */
 
-#define IP_FW_NAT_CFG		68   /* add/config a nat rule */
+#define IP_FW_NAT_ADD		68   /* add/config a nat rule */
 #define IP_FW_NAT_DEL		69   /* delete a nat rule */
 #define IP_FW_NAT_FLUSH		70   /* get configuration of a nat rule */
 #define IP_FW_NAT_GET		71   /* get config of a nat rule */
-#define IP_FW_NAT_LOG		72   /* get nat record of a nat rule */
+#define IP_FW_NAT_GET_RECORD	72   /* get nat record of a nat rule */
 
 #define IP_FW_STATE_ADD		56   /* add one state */
 #define IP_FW_STATE_DEL		57   /* delete states of one rulenum */
diff --git a/sys/net/ipfw3_nat/ip_fw3_nat.c b/sys/net/ipfw3_nat/ip_fw3_nat.c
index 9f2a2f0..a5eba5d 100644
--- a/sys/net/ipfw3_nat/ip_fw3_nat.c
+++ b/sys/net/ipfw3_nat/ip_fw3_nat.c
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2016 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
- * by Bill Yuan <bycn82@gmail.com>
+ * by Bill Yuan <bycn82@dragonflybsd.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -78,24 +78,25 @@
 #include "ip_fw3_nat.h"
 
 
-static struct lock nat_lock;
+struct ipfw_nat_context	*ipfw_nat_ctx[MAXCPU];
+extern struct ipfw_context *ipfw_ctx[MAXCPU];
+extern ip_fw_ctl_t *ipfw_ctl_nat_ptr;
 
-extern struct ipfw_nat_context	*ipfw_nat_ctx;
-extern struct ipfw_context	*ipfw_ctx[MAXCPU];
-extern ipfw_nat_cfg_t *ipfw_nat_cfg_ptr;
-extern ipfw_nat_cfg_t *ipfw_nat_del_ptr;
-extern ipfw_nat_cfg_t *ipfw_nat_flush_ptr;
-extern ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;
-extern ipfw_nat_cfg_t *ipfw_nat_get_log_ptr;
-
-typedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *);
-
-int ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m);
-int ipfw_nat_cfg(struct sockopt *sopt);
-int ipfw_nat_del(struct sockopt *sopt);
-int ipfw_nat_flush(struct sockopt *sopt);
 void check_nat(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
 		struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
+void add_alias_link_dispatch(netmsg_t nat_del_msg);
+int ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m);
+void nat_add_dispatch(netmsg_t msg);
+int ipfw_ctl_nat_add(struct sockopt *sopt);
+void nat_del_dispatch(netmsg_t msg);
+int ipfw_ctl_nat_del(struct sockopt *sopt);
+int ipfw_ctl_nat_flush(struct sockopt *sopt);
+int ipfw_ctl_nat_sockopt(struct sockopt *sopt);
+void nat_init_ctx_dispatch(netmsg_t msg);
+int ipfw_ctl_nat_get_cfg(struct sockopt *sopt);
+void del_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head);
+int add_redir_spool_cfg(char *buf, struct cfg_nat *ptr);
+int ipfw_ctl_nat_get_record(struct sockopt *sopt);
 
 
 void
@@ -107,16 +108,18 @@ check_nat(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
 		*cmd_val = IP_FW_NOT_MATCH;
 		return;
 	}
+
+	struct ipfw_nat_context *nat_ctx;
 	struct cfg_nat *t;
 	int nat_id;
+
+	nat_ctx = ipfw_nat_ctx[mycpuid];
 	(*args)->rule = *f;
-	lockmgr(&nat_lock, LK_SHARED);
 	t = ((ipfw_insn_nat *)cmd)->nat;
 	if (t == NULL) {
 		nat_id = cmd->arg1;
-		LOOKUP_NAT((*ipfw_nat_ctx), nat_id, t);
+		LOOKUP_NAT((*nat_ctx), nat_id, t);
 		if (t == NULL) {
-			lockmgr(&nat_lock, LK_RELEASE);
 			*cmd_val = IP_FW_DENY;
 			*cmd_ctl = IP_FW_CTL_DONE;
 			return;
@@ -124,11 +127,210 @@ check_nat(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
 		((ipfw_insn_nat *)cmd)->nat = t;
 	}
 	*cmd_val = ipfw_nat(*args, t, (*args)->m);
-	lockmgr(&nat_lock, LK_RELEASE);
 	*cmd_ctl = IP_FW_CTL_NAT;
 }
 
-static void
+/* Local prototypes */
+u_int StartPointIn(struct in_addr, u_short, int);
+
+u_int StartPointOut(struct in_addr, struct in_addr,
+		u_short, u_short, int);
+
+u_int
+StartPointIn(struct in_addr alias_addr,
+	u_short alias_port,
+	int link_type)
+{
+	u_int n;
+
+	n = alias_addr.s_addr;
+	if (link_type != LINK_PPTP)
+		n += alias_port;
+	n += link_type;
+	return (n % LINK_TABLE_IN_SIZE);
+}
+
+
+u_int
+StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
+	u_short src_port, u_short dst_port, int link_type)
+{
+	u_int n;
+
+	n = src_addr.s_addr;
+	n += dst_addr.s_addr;
+	if (link_type != LINK_PPTP) {
+		n += src_port;
+		n += dst_port;
+	}
+	n += link_type;
+
+	return (n % LINK_TABLE_OUT_SIZE);
+}
+
+
+void
+add_alias_link_dispatch(netmsg_t alias_link_add)
+{
+	struct ipfw_nat_context *nat_ctx;
+	struct netmsg_alias_link_add *msg;
+	struct libalias *la;
+	struct alias_link *lnk;
+	struct cfg_nat *t;
+	struct tcp_dat *aux_tcp;
+	u_int start_point;
+
+	msg = (struct netmsg_alias_link_add *)alias_link_add;
+	nat_ctx = ipfw_nat_ctx[mycpuid];
+	LOOKUP_NAT((*nat_ctx), msg->id, t);
+	la = t->lib;
+	lnk = kmalloc(sizeof(struct alias_link), M_ALIAS, M_WAITOK | M_ZERO);
+	memcpy(lnk, msg->lnk, sizeof(struct alias_link));
+	lnk->la = la;
+	if (msg->is_tcp) {
+		aux_tcp = kmalloc(sizeof(struct tcp_dat),
+				M_ALIAS, M_WAITOK | M_ZERO);
+		memcpy(aux_tcp, msg->lnk->data.tcp, sizeof(struct tcp_dat));
+		lnk->data.tcp = aux_tcp;
+	}
+
+	/* Set up pointers for output lookup table */
+	start_point = StartPointOut(lnk->src_addr, lnk->dst_addr,
+			lnk->src_port, lnk->dst_port, lnk->link_type);
+	LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
+
+	/* Set up pointers for input lookup table */
+	start_point = StartPointIn(lnk->alias_addr,
+			lnk->alias_port, lnk->link_type);
+	LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
+	kfree(alias_link_add, M_IPFW_NAT);
+}
+
+int
+ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
+{
+	struct alias_link *new = NULL;
+	struct mbuf *mcl;
+	struct ip *ip;
+	int ldt, retval, nextcpu;
+	char *c;
+
+	ldt = 0;
+	retval = 0;
+	if ((mcl = m_megapullup(m, m->m_pkthdr.len)) ==NULL)
+		goto badnat;
+
+	ip = mtod(mcl, struct ip *);
+	if (args->eh == NULL) {
+		ip->ip_len = htons(ip->ip_len);
+		ip->ip_off = htons(ip->ip_off);
+	}
+
+	if (mcl->m_pkthdr.rcvif == NULL &&
+			mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+		ldt = 1;
+	}
+
+	c = mtod(mcl, char *);
+	if (args->oif == NULL) {
+		retval = LibAliasIn(t->lib, c,
+				mcl->m_len + M_TRAILINGSPACE(mcl), &new);
+	} else {
+		retval = LibAliasOut(t->lib, c,
+				mcl->m_len + M_TRAILINGSPACE(mcl), &new);
+	}
+	if (retval != PKT_ALIAS_OK &&
+			retval != PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
+		/* XXX - should i add some logging? */
+		m_free(mcl);
+badnat:
+		args->m = NULL;
+		return IP_FW_DENY;
+	}
+	mcl->m_pkthdr.len = mcl->m_len = ntohs(ip->ip_len);
+
+	if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
+			ip->ip_p == IPPROTO_TCP) {
+		struct tcphdr 	*th;
+
+		th = (struct tcphdr *)(ip + 1);
+		if (th->th_x2){
+			ldt = 1;
+		}
+	}
+	if (new != NULL &&
+			(ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)) {
+		ip_hashfn(&mcl, 0);
+		nextcpu = netisr_hashcpu(m->m_pkthdr.hash);
+		if (nextcpu != mycpuid) {
+			struct netmsg_alias_link_add *msg;
+			msg = kmalloc(sizeof(struct netmsg_alias_link_add),
+					M_IPFW_NAT, M_NOWAIT | M_ZERO);
+
+			netmsg_init(&msg->base, NULL,
+					&curthread->td_msgport, 0,
+					add_alias_link_dispatch);
+			msg->lnk = new;
+			msg->id = t->id;
+			if (ip->ip_p == IPPROTO_TCP) {
+				msg->is_tcp = 1;
+			}
+			if (args->oif == NULL) {
+				msg->is_outgoing = 0;
+			} else {
+				msg->is_outgoing = 1;
+			}
+			ifnet_sendmsg(&msg->base.lmsg, nextcpu);
+		}
+	}
+	if (ldt) {
+		struct tcphdr 	*th;
+		struct udphdr 	*uh;
+		u_short cksum;
+
+		ip->ip_len = ntohs(ip->ip_len);
+		cksum = in_pseudo(
+				ip->ip_src.s_addr,
+				ip->ip_dst.s_addr,
+				htons(ip->ip_p + ip->ip_len - (ip->ip_hl << 2))
+				);
+
+		switch (ip->ip_p) {
+			case IPPROTO_TCP:
+				th = (struct tcphdr *)(ip + 1);
+				th->th_x2 = 0;
+				th->th_sum = cksum;
+				mcl->m_pkthdr.csum_data =
+					offsetof(struct tcphdr, th_sum);
+				break;
+			case IPPROTO_UDP:
+				uh = (struct udphdr *)(ip + 1);
+				uh->uh_sum = cksum;
+				mcl->m_pkthdr.csum_data =
+					offsetof(struct udphdr, uh_sum);
+				break;
+		}
+		/*
+		 * No hw checksum offloading: do it
+		 * by ourself.
+		 */
+		if ((mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA) == 0) {
+			in_delayed_cksum(mcl);
+			mcl->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
+		}
+		ip->ip_len = htons(ip->ip_len);
+	}
+
+	if (args->eh == NULL) {
+		ip->ip_len = ntohs(ip->ip_len);
+		ip->ip_off = ntohs(ip->ip_off);
+	}
+
+	args->m = mcl;
+	return IP_FW_NAT;
+}
+
+void
 del_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head)
 {
 	struct cfg_redir *r, *tmp_r;
@@ -166,7 +368,7 @@ del_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head)
 	}
 }
 
-static int
+int
 add_redir_spool_cfg(char *buf, struct cfg_nat *ptr)
 {
 	struct cfg_redir *r, *ser_r;
@@ -242,30 +444,31 @@ bad:
 	panic("%s\n", panic_err);
 }
 
-static int
-ipfw_nat_get_cfg(struct sockopt *sopt)
+int
+ipfw_ctl_nat_get_cfg(struct sockopt *sopt)
 {
-	uint8_t *data;
+	struct ipfw_nat_context *nat_ctx;
 	struct cfg_nat *n;
 	struct cfg_redir *r;
 	struct cfg_spool *s;
 	int nat_cnt, off, nat_cfg_size;
 	size_t size;
+	uint8_t *data;
 
 	nat_cnt = 0;
 	nat_cfg_size = 0;
 	off = sizeof(nat_cnt);
 
+	nat_ctx = ipfw_nat_ctx[mycpuid];
 	size = sopt->sopt_valsize;
 
 	data = sopt->sopt_val;
-	lockmgr(&nat_lock, LK_SHARED);
 	/* count the size of nat cfg */
-	LIST_FOREACH(n, &((*ipfw_nat_ctx).nat), _next) {
+	LIST_FOREACH(n, &((*nat_ctx).nat), _next) {
 		nat_cfg_size += SOF_NAT;
 	}
 
-	LIST_FOREACH(n, &((*ipfw_nat_ctx).nat), _next) {
+	LIST_FOREACH(n, &((*nat_ctx).nat), _next) {
 		nat_cnt++;
 		if (off + SOF_NAT < size) {
 			bcopy(n, &data[off], SOF_NAT);
@@ -291,191 +494,102 @@ ipfw_nat_get_cfg(struct sockopt *sopt)
 	}
 	bcopy(&nat_cnt, data, sizeof(nat_cnt));
 	sopt->sopt_valsize = nat_cfg_size;
-	lockmgr(&nat_lock, LK_RELEASE);
 	return 0;
 nospace:
-	lockmgr(&nat_lock, LK_RELEASE);
 	bzero(sopt->sopt_val, sopt->sopt_valsize);
 	sopt->sopt_valsize = nat_cfg_size;
 	return 0;
 }
 
-static int
-ipfw_nat_get_log(struct sockopt *sopt)
+int
+ipfw_ctl_nat_get_record(struct sockopt *sopt)
 {
+	struct ipfw_nat_context *nat_ctx;
 	struct cfg_nat *t;
 	struct alias_link *lnk;
 	struct libalias *la;
 	size_t sopt_size, all_lnk_size = 0;
-	int i, *nat_id;
+	int i, *nat_id, id, n;
 	struct ipfw_ioc_nat_state *nat_state;
 
+	int cpu;
+
 	nat_id = (int *)(sopt->sopt_val);
+	n = *nat_id;
 	sopt_size = sopt->sopt_valsize;
-
-	lockmgr(&nat_lock, LK_SHARED);
-	LOOKUP_NAT((*ipfw_nat_ctx), *nat_id, t);
-	if (t != NULL) {
-		nat_state = (struct ipfw_ioc_nat_state *)sopt->sopt_val;
-		la = t->lib;
-		LIBALIAS_LOCK_ASSERT(la);
-		for (i = 0; i < LINK_TABLE_OUT_SIZE; i ++) {
-			LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
-				all_lnk_size += sizeof(*nat_state);
-				if (all_lnk_size > sopt_size)
-					goto nospace;
-				nat_state->src_addr = lnk->src_addr;
-				nat_state->dst_addr = lnk->dst_addr;
-				nat_state->alias_addr = lnk->alias_addr;
-				nat_state->src_port = lnk->src_port;
-				nat_state->dst_port = lnk->dst_port;
-				nat_state->alias_port = lnk->alias_port;
-				nat_state->link_type = lnk->link_type;
-				nat_state->timestamp = lnk->timestamp;
-				nat_state++;
+	nat_state = (struct ipfw_ioc_nat_state *)sopt->sopt_val;
+	for (cpu = 0; cpu < ncpus; cpu++) {
+		nat_ctx = ipfw_nat_ctx[cpu];
+		id = n;
+		LOOKUP_NAT((*nat_ctx), id, t);
+		if (t != NULL) {
+			la = t->lib;
+			LIBALIAS_LOCK_ASSERT(la);
+			for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
+				LIST_FOREACH(lnk, &la->linkTableOut[i],
+						list_out) {
+					all_lnk_size += sizeof(*nat_state);
+					if (all_lnk_size > sopt_size)
+						goto nospace;
+					nat_state->src_addr = lnk->src_addr;
+					nat_state->dst_addr = lnk->dst_addr;
+					nat_state->alias_addr = lnk->alias_addr;
+					nat_state->src_port = lnk->src_port;
+					nat_state->dst_port = lnk->dst_port;
+					nat_state->alias_port = lnk->alias_port;
+					nat_state->link_type = lnk->link_type;
+					nat_state->timestamp = lnk->timestamp;
+					nat_state->cpuid = cpu;
+					nat_state->is_outgoing = 1;
+					nat_state++;
+				}
+				LIST_FOREACH(lnk, &la->linkTableIn[i],
+						list_out) {
+					all_lnk_size += sizeof(*nat_state);
+					if (all_lnk_size > sopt_size)
+						goto nospace;
+					nat_state->src_addr = lnk->src_addr;
+					nat_state->dst_addr = lnk->dst_addr;
+					nat_state->alias_addr = lnk->alias_addr;
+					nat_state->src_port = lnk->src_port;
+					nat_state->dst_port = lnk->dst_port;
+					nat_state->alias_port = lnk->alias_port;
+					nat_state->link_type = lnk->link_type;
+					nat_state->timestamp = lnk->timestamp;
+					nat_state->cpuid = cpu;
+					nat_state->is_outgoing = 0;
+					nat_state++;
+				}
 			}
 		}
 	}
 	sopt->sopt_valsize = all_lnk_size;
-	lockmgr(&nat_lock, LK_RELEASE);
 	return 0;
 nospace:
-	lockmgr(&nat_lock, LK_RELEASE);
 	return 0;
 }
 
-int
-ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
-{
-	struct mbuf *mcl;
-	struct ip *ip;
-	int ldt, retval;
-	char *c;
-	ldt = 0;
-	retval = 0;
-	if ((mcl = m_megapullup(m, m->m_pkthdr.len)) ==NULL)
-		goto badnat;
-	ip = mtod(mcl, struct ip *);
-	if (args->eh == NULL) {
-		ip->ip_len = htons(ip->ip_len);
-		ip->ip_off = htons(ip->ip_off);
-	}
-
-	if (mcl->m_pkthdr.rcvif == NULL &&
-			mcl->m_pkthdr.csum_flags &
-			CSUM_DELAY_DATA)
-		ldt = 1;
-
-	c = mtod(mcl, char *);
-	if (args->oif == NULL)
-		retval = LibAliasIn(t->lib, c,
-				mcl->m_len + M_TRAILINGSPACE(mcl));
-	else
-		retval = LibAliasOut(t->lib, c,
-				mcl->m_len + M_TRAILINGSPACE(mcl));
-	if (retval != PKT_ALIAS_OK &&
-			retval != PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
-		/* XXX - should i add some logging? */
-		m_free(mcl);
-badnat:
-		args->m = NULL;
-		return IP_FW_DENY;
-	}
-	mcl->m_pkthdr.len = mcl->m_len = ntohs(ip->ip_len);
-
-	if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
-			ip->ip_p == IPPROTO_TCP) {
-		struct tcphdr 	*th;
-
-		th = (struct tcphdr *)(ip + 1);
-		if (th->th_x2){
-			ldt = 1;
-		}
-	}
-
-	if (ldt) {
-		struct tcphdr 	*th;
-		struct udphdr 	*uh;
-		u_short cksum;
-
-		ip->ip_len = ntohs(ip->ip_len);
-		cksum = in_pseudo(
-				ip->ip_src.s_addr,
-				ip->ip_dst.s_addr,
-				htons(ip->ip_p + ip->ip_len - (ip->ip_hl << 2))
-				);
-
-		switch (ip->ip_p) {
-			case IPPROTO_TCP:
-				th = (struct tcphdr *)(ip + 1);
-				th->th_x2 = 0;
-				th->th_sum = cksum;
-				mcl->m_pkthdr.csum_data =
-					offsetof(struct tcphdr, th_sum);
-				break;
-			case IPPROTO_UDP:
-				uh = (struct udphdr *)(ip + 1);
-				uh->uh_sum = cksum;
-				mcl->m_pkthdr.csum_data =
-					offsetof(struct udphdr, uh_sum);
-				break;
-		}
-		/*
-		 * No hw checksum offloading: do it
-		 * by ourself.
-		 */
-		if ((mcl->m_pkthdr.csum_flags &
-					CSUM_DELAY_DATA) == 0) {
-			in_delayed_cksum(mcl);
-			mcl->m_pkthdr.csum_flags &=
-				~CSUM_DELAY_DATA;
-		}
-		ip->ip_len = htons(ip->ip_len);
-	}
-
-	if (args->eh == NULL) {
-		ip->ip_len = ntohs(ip->ip_len);
-		ip->ip_off = ntohs(ip->ip_off);
-	}
-
-	args->m = mcl;
-	return IP_FW_NAT;
-}
-
-int ipfw_nat_cfg(struct sockopt *sopt)
+void
+nat_add_dispatch(netmsg_t nat_add_msg)
 {
+	struct ipfw_nat_context *nat_ctx;
 	struct cfg_nat *ptr, *ser_n;
-	char *buf;
+	struct netmsg_nat_add *msg;
 
-	buf = kmalloc(sopt->sopt_valsize, M_IPFW_NAT, M_WAITOK | M_ZERO);
-	sooptcopyin(sopt, buf, sopt->sopt_valsize, sizeof(struct cfg_nat));
-	ser_n = (struct cfg_nat *)(sopt->sopt_val);
+	msg = (struct netmsg_nat_add *)nat_add_msg;
 
-	/*
-	 * Find/create nat rule.
-	 */
-	lockmgr(&nat_lock, LK_EXCLUSIVE);
-	LOOKUP_NAT((*ipfw_nat_ctx), ser_n->id, ptr);
+	ser_n = (struct cfg_nat *)(msg->buf);
 
-	if (ptr == NULL) {
-		/* New rule: allocate and init new instance. */
-		ptr = kmalloc(sizeof(struct cfg_nat), M_IPFW_NAT,
-				M_WAITOK | M_ZERO);
-
-		ptr->lib = LibAliasInit(NULL);
-		if (ptr->lib == NULL) {
-			kfree(ptr, M_IPFW_NAT);
-			kfree(buf, M_IPFW_NAT);
-			lockmgr(&nat_lock, LK_RELEASE);
-			return EINVAL;
-		}
+	/* New rule: allocate and init new instance. */
+	ptr = kmalloc(sizeof(struct cfg_nat), M_IPFW_NAT, M_WAITOK | M_ZERO);
 
-		LIST_INIT(&ptr->redir_chain);
-	} else {
-		/* XXX TODO Entry already exists */
-		goto done;
+	ptr->lib = LibAliasInit(NULL);
+	if (ptr->lib == NULL) {
+		kfree(ptr, M_IPFW_NAT);
+		kfree(msg->buf, M_IPFW_NAT);
 	}
 
+	LIST_INIT(&ptr->redir_chain);
 	/*
 	 * Basic nat configuration.
 	 */
@@ -494,45 +608,79 @@ int ipfw_nat_cfg(struct sockopt *sopt)
 	memcpy(ptr->if_name, ser_n->if_name, IF_NAMESIZE);
 
 	/* Add new entries. */
-	add_redir_spool_cfg(&buf[(sizeof(struct cfg_nat))], ptr);
-	HOOK_NAT(&(ipfw_nat_ctx->nat), ptr);
+	add_redir_spool_cfg(&msg->buf[(sizeof(struct cfg_nat))], ptr);
+
+	nat_ctx = ipfw_nat_ctx[mycpuid];
+	HOOK_NAT(&(nat_ctx->nat), ptr);
+	ifnet_forwardmsg(&msg->base.lmsg, mycpuid + 1);
+}
+
+int
+ipfw_ctl_nat_add(struct sockopt *sopt)
+{
+	struct ipfw_nat_context *nat_ctx;
+	struct cfg_nat *ptr, *ser_n;
+	ser_n = (struct cfg_nat *)(sopt->sopt_val);
+
+	nat_ctx = ipfw_nat_ctx[mycpuid];
+	/*
+	 * Find/create nat rule.
+	 */
+	LOOKUP_NAT((*nat_ctx), ser_n->id, ptr);
+
+	if (ptr == NULL) {
+		struct netmsg_nat_add nat_add_msg;
+		struct netmsg_nat_add *msg;
+
+		msg = &nat_add_msg;
+		msg->buf = kmalloc(sopt->sopt_valsize,
+				M_IPFW_NAT, M_WAITOK | M_ZERO);
+
+		sooptcopyin(sopt, msg->buf, sopt->sopt_valsize,
+				sizeof(struct cfg_nat));
+
+		netmsg_init(&msg->base, NULL, &curthread->td_msgport,
+				0, nat_add_dispatch);
+
+
+		ifnet_domsg(&msg->base.lmsg, 0);
+		kfree(msg->buf, M_IPFW_NAT);
+	} else {
+		goto done;
+	}
 done:
-	lockmgr(&nat_lock, LK_RELEASE);
-	kfree(buf, M_IPFW_NAT);
 	return 0;
 }
 
-int
-ipfw_nat_del(struct sockopt *sopt)
+void
+nat_del_dispatch(netmsg_t nat_del_msg)
 {
+	struct ipfw_nat_context *nat_ctx;
 	struct ipfw_context *ctx;
 	struct cfg_nat *n, *tmp;
+	struct netmsg_nat_del *msg;
 	struct ip_fw *f;
 	ipfw_insn *cmd;
-	int *i, cpu;
+	int id;
 
-	i = sopt->sopt_val;
-	lockmgr(&nat_lock, LK_EXCLUSIVE);
-	LOOKUP_NAT((*ipfw_nat_ctx), *i, n);
+	msg = (struct netmsg_nat_del *)nat_del_msg;
+	id = msg->id;
+
+	nat_ctx = ipfw_nat_ctx[mycpuid];
+	LOOKUP_NAT((*nat_ctx), id, n);
 	if (n == NULL) {
-		lockmgr(&nat_lock, LK_RELEASE);
-		return EINVAL;
 	}
 
 	/*
 	 * stop deleting when this cfg_nat was in use in ipfw_ctx
 	 */
-	for (cpu = 0; cpu < ncpus; cpu++) {
-		ctx = ipfw_ctx[cpu];
-		for (f = ctx->ipfw_rule_chain; f; f = f->next) {
-			cmd = ACTION_PTR(f);
-			if ((int)cmd->module == MODULE_NAT_ID &&
-					(int)cmd->opcode == O_NAT_NAT) {
-				tmp = ((ipfw_insn_nat *)cmd)->nat;
-				if (tmp != NULL && tmp->id == n->id) {
-					lockmgr(&nat_lock, LK_RELEASE);
-					return EINVAL;
-				}
+	ctx = ipfw_ctx[mycpuid];
+	for (f = ctx->ipfw_rule_chain; f; f = f->next) {
+		cmd = ACTION_PTR(f);
+		if ((int)cmd->module == MODULE_NAT_ID &&
+				(int)cmd->opcode == O_NAT_NAT) {
+			tmp = ((ipfw_insn_nat *)cmd)->nat;
+			if (tmp != NULL && tmp->id == n->id) {
 			}
 		}
 	}
@@ -541,13 +689,30 @@ ipfw_nat_del(struct sockopt *sopt)
 	del_redir_spool_cfg(n, &n->redir_chain);
 	LibAliasUninit(n->lib);
 	kfree(n, M_IPFW_NAT);
-	lockmgr(&nat_lock, LK_RELEASE);
+}
+
+int
+ipfw_ctl_nat_del(struct sockopt *sopt)
+{
+	struct netmsg_nat_del nat_del_msg;
+	struct netmsg_nat_del *msg;
+	int *id;
+
+	msg = &nat_del_msg;
+	id = sopt->sopt_val;
+	msg->id = *id;
+
+	netmsg_init(&msg->base, NULL, &curthread->td_msgport,
+			0, nat_del_dispatch);
+
+	ifnet_domsg(&msg->base.lmsg, 0);
 	return 0;
 }
 
 int
-ipfw_nat_flush(struct sockopt *sopt)
+ipfw_ctl_nat_flush(struct sockopt *sopt)
 {
+	struct ipfw_nat_context *nat_ctx;
 	struct ipfw_context *ctx;
 	struct cfg_nat *ptr, *tmp;
 	struct ip_fw *f;
@@ -568,67 +733,108 @@ ipfw_nat_flush(struct sockopt *sopt)
 		}
 	}
 
-	lockmgr(&nat_lock, LK_EXCLUSIVE);
-	LIST_FOREACH_MUTABLE(ptr, &(ipfw_nat_ctx->nat), _next, tmp) {
+	nat_ctx = ipfw_nat_ctx[mycpuid];
+
+	LIST_FOREACH_MUTABLE(ptr, &(nat_ctx->nat), _next, tmp) {
 		LIST_REMOVE(ptr, _next);
 		del_redir_spool_cfg(ptr, &ptr->redir_chain);
 		LibAliasUninit(ptr->lib);
 		kfree(ptr, M_IPFW_NAT);
 	}
-	lockmgr(&nat_lock, LK_RELEASE);
 	return 0;
 }
 
+int
+ipfw_ctl_nat_sockopt(struct sockopt *sopt)
+{
+	int error = 0;
+	switch (sopt->sopt_name) {
+		case IP_FW_NAT_ADD:
+			error = ipfw_ctl_nat_add(sopt);
+			break;
+		case IP_FW_NAT_DEL:
+			error = ipfw_ctl_nat_del(sopt);
+			break;
+		case IP_FW_NAT_FLUSH:
+			error = ipfw_ctl_nat_flush(sopt);
+			break;
+		case IP_FW_NAT_GET:
+			error = ipfw_ctl_nat_get_cfg(sopt);
+			break;
+		case IP_FW_NAT_GET_RECORD:
+			error = ipfw_ctl_nat_get_record(sopt);
+			break;
+		default:
+			kprintf("ipfw3 nat invalid socket option %d\n",
+					sopt->sopt_name);
+	}
+	return error;
+}
+
+void
+nat_init_ctx_dispatch(netmsg_t msg)
+{
+	struct ipfw_nat_context *tmp;
+	tmp = kmalloc(sizeof(struct ipfw_nat_context),
+				M_IPFW_NAT, M_WAITOK | M_ZERO);
+	ipfw_nat_ctx[mycpuid] = tmp;
+	ifnet_forwardmsg(&msg->lmsg, mycpuid + 1);
+}
+
 static
 int ipfw_nat_init(void)
 {
-	lockinit(&nat_lock, "ipfw3 nat lock", 0, 0);
+	struct netmsg_base msg;
 	register_ipfw_module(MODULE_NAT_ID, MODULE_NAT_NAME);
 	register_ipfw_filter_funcs(MODULE_NAT_ID, O_NAT_NAT,
 			(filter_func)check_nat);
-	ipfw_nat_cfg_ptr = ipfw_nat_cfg;
-	ipfw_nat_del_ptr = ipfw_nat_del;
-	ipfw_nat_flush_ptr = ipfw_nat_flush;
-	ipfw_nat_get_cfg_ptr = ipfw_nat_get_cfg;
-	ipfw_nat_get_log_ptr = ipfw_nat_get_log;
+	ipfw_ctl_nat_ptr = ipfw_ctl_nat_sockopt;
+	netmsg_init(&msg, NULL, &curthread->td_msgport,
+			0, nat_init_ctx_dispatch);
+	ifnet_domsg(&msg.lmsg, 0);
 	return 0;
 }
 
 static int
-ipfw_nat_stop(void)
+ipfw_nat_fini(void)
 {
-	struct cfg_nat *ptr, *ptr_temp;
-	lockuninit(&nat_lock);
-	LIST_FOREACH_MUTABLE(ptr, &(ipfw_nat_ctx->nat), _next, ptr_temp) {
-		LIST_REMOVE(ptr, _next);
-		del_redir_spool_cfg(ptr, &ptr->redir_chain);
-		LibAliasUninit(ptr->lib);
-		kfree(ptr, M_IPFW_NAT);
-	}
+	struct cfg_nat *ptr, *tmp;
+	struct ipfw_nat_context *ctx;
 
-	ipfw_nat_cfg_ptr = NULL;
-	ipfw_nat_del_ptr = NULL;
-	ipfw_nat_flush_ptr = NULL;
-	ipfw_nat_get_cfg_ptr = NULL;
-	ipfw_nat_get_log_ptr = NULL;
+	for (cpu = 0; cpu < ncpus; cpu++) {
+		ctx = ipfw_nat_ctx[cpu];
+		if(ctx != NULL) {
+			LIST_FOREACH_MUTABLE(ptr, &(ctx->nat), _next, tmp) {
+				LIST_REMOVE(ptr, _next);
+				del_redir_spool_cfg(ptr, &ptr->redir_chain);
+				LibAliasUninit(ptr->lib);
+				kfree(ptr, M_IPFW_NAT);
+			}
+
+			kfree(ctx, M_IPFW_NAT);
+			ipfw_nat_ctx[cpu] = NULL;
+		}
+	}
+	ipfw_ctl_nat_ptr = NULL;
 
 	return unregister_ipfw_module(MODULE_NAT_ID);
 }
 
-static int ipfw_nat_modevent(module_t mod, int type, void *data)
+static int
+ipfw_nat_modevent(module_t mod, int type, void *data)
 {
 	switch (type) {
 		case MOD_LOAD:
 			return ipfw_nat_init();
 		case MOD_UNLOAD:
-			return ipfw_nat_stop();
+			return ipfw_nat_fini();
 		default:
 			break;
 	}
 	return 0;
 }
 
-static moduledata_t ipfw_nat_mod = {
+moduledata_t ipfw_nat_mod = {
 	"ipfw3_nat",
 	ipfw_nat_modevent,
 	NULL
diff --git a/sys/net/ipfw3_nat/ip_fw3_nat.h b/sys/net/ipfw3_nat/ip_fw3_nat.h
index b51b31a..4f86689 100644
--- a/sys/net/ipfw3_nat/ip_fw3_nat.h
+++ b/sys/net/ipfw3_nat/ip_fw3_nat.h
@@ -39,7 +39,32 @@
 #define MODULE_NAT_NAME		"nat"
 
 #ifdef _KERNEL
+
 MALLOC_DEFINE(M_IPFW_NAT, "IPFW3/NAT", "IPFW3/NAT 's");
+
+/* place to hold the nat conf */
+struct ipfw_nat_context {
+	LIST_HEAD(, cfg_nat) nat;	/* list of nat entries*/
+};
+
+struct netmsg_nat_del {
+	struct netmsg_base base;
+	int id;
+};
+
+struct netmsg_nat_add {
+	struct netmsg_base base;
+	char *buf;
+};
+
+struct netmsg_alias_link_add {
+	struct netmsg_base base;
+	struct alias_link *lnk;
+	int id;
+	int is_outgoing;
+	int is_tcp;
+};
+
 #endif
 
 enum ipfw_nat_opcodes {
@@ -54,6 +79,8 @@ struct ipfw_ioc_nat_state {
 	int		timestamp;
 	int		expire_time;
 	int		nat_id;
+	int		cpuid;
+	int		is_outgoing;
 	u_short		src_port;
 	u_short		dst_port;
 	u_short		alias_port;
diff --git a/sys/net/libalias/alias.c b/sys/net/libalias/alias.c
index 4749c67..4da85d2 100644
--- a/sys/net/libalias/alias.c
+++ b/sys/net/libalias/alias.c
@@ -245,26 +245,35 @@ the gateway machine or other machines on a local area network.
 
 
 /* Local prototypes */
-static int	IcmpAliasIn1(struct libalias *, struct ip *);
-static int	IcmpAliasIn2(struct libalias *, struct ip *);
-static int	IcmpAliasIn(struct libalias *, struct ip *);
-
-static int	IcmpAliasOut1(struct libalias *, struct ip *, int create);
-static int	IcmpAliasOut2(struct libalias *, struct ip *);
-static int	IcmpAliasOut(struct libalias *, struct ip *, int create);
+static int	IcmpAliasIn1(struct libalias *, struct ip *,
+		struct alias_link **);
+static int	IcmpAliasIn2(struct libalias *, struct ip *,
+		struct alias_link **);
+static int	IcmpAliasIn(struct libalias *, struct ip *,
+		struct alias_link **);
+
+static int	IcmpAliasOut1(struct libalias *, struct ip *, int create,
+		struct alias_link **);
+static int	IcmpAliasOut2(struct libalias *, struct ip *,
+		struct alias_link **);
+static int	IcmpAliasOut(struct libalias *, struct ip *, int create,
+		struct alias_link **);
 
 static int	ProtoAliasIn(struct libalias *, struct ip *);
 static int	ProtoAliasOut(struct libalias *, struct ip *, int create);
 
-static int	UdpAliasIn(struct libalias *, struct ip *);
-static int	UdpAliasOut(struct libalias *, struct ip *, int create);
+static int	UdpAliasIn(struct libalias *, struct ip *,struct alias_link **);
+static int	UdpAliasOut(struct libalias *, struct ip *, int create,
+		struct alias_link **);
 
-static int	TcpAliasIn(struct libalias *, struct ip *);
-static int	TcpAliasOut(struct libalias *, struct ip *, int, int create);
+static int	TcpAliasIn(struct libalias *, struct ip *,
+		struct alias_link **);
+static int	TcpAliasOut(struct libalias *, struct ip *, int, int create,
+		struct alias_link **);
 
 
 static int
-IcmpAliasIn1(struct libalias *la, struct ip *pip)
+IcmpAliasIn1(struct libalias *la, struct ip *pip, struct alias_link **new)
 {
 
 	LIBALIAS_LOCK_ASSERT(la);
@@ -280,6 +289,7 @@ IcmpAliasIn1(struct libalias *la, struct ip *pip)
 /* Get source address from ICMP data field and restore original data */
 	lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
 	if (lnk != NULL) {
+		*new = lnk;
 		u_short original_id;
 		int accumulate;
 
@@ -309,7 +319,7 @@ IcmpAliasIn1(struct libalias *la, struct ip *pip)
 }
 
 static int
-IcmpAliasIn2(struct libalias *la, struct ip *pip)
+IcmpAliasIn2(struct libalias *la, struct ip *pip, struct alias_link **new)
 {
 
 	LIBALIAS_LOCK_ASSERT(la);
@@ -411,7 +421,7 @@ fragment contained in ICMP data section */
 
 
 static int
-IcmpAliasIn(struct libalias *la, struct ip *pip)
+IcmpAliasIn(struct libalias *la, struct ip *pip, struct alias_link **new)
 {
 	int iresult;
 	struct icmp *ic;
@@ -428,18 +438,18 @@ IcmpAliasIn(struct libalias *la, struct ip *pip)
 	case ICMP_ECHOREPLY:
 	case ICMP_TSTAMPREPLY:
 		if (ic->icmp_code == 0) {
-			iresult = IcmpAliasIn1(la, pip);
+			iresult = IcmpAliasIn1(la, pip, new);
 		}
 		break;
 	case ICMP_UNREACH:
 	case ICMP_SOURCEQUENCH:
 	case ICMP_TIMXCEED:
 	case ICMP_PARAMPROB:
-		iresult = IcmpAliasIn2(la, pip);
+		iresult = IcmpAliasIn2(la, pip, new);
 		break;
 	case ICMP_ECHO:
 	case ICMP_TSTAMP:
-		iresult = IcmpAliasIn1(la, pip);
+		iresult = IcmpAliasIn1(la, pip, new);
 		break;
 	}
 	return (iresult);
@@ -447,7 +457,8 @@ IcmpAliasIn(struct libalias *la, struct ip *pip)
 
 
 static int
-IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
+IcmpAliasOut1(struct libalias *la, struct ip *pip, int create,
+		struct alias_link **new)
 {
 /*
 	Alias outgoing echo and timestamp requests.
@@ -462,6 +473,9 @@ IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
 /* Save overwritten data for when echo packet returns */
 	lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
 	if (lnk != NULL) {
+		if (create) {
+			*new = lnk;
+		}
 		u_short alias_id;
 		int accumulate;
 
@@ -492,7 +506,7 @@ IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
 
 
 static int
-IcmpAliasOut2(struct libalias *la, struct ip *pip)
+IcmpAliasOut2(struct libalias *la, struct ip *pip, struct alias_link **new)
 {
 /*
 	Alias outgoing ICMP error messages containing
@@ -593,7 +607,8 @@ fragment contained in ICMP data section */
 
 
 static int
-IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
+IcmpAliasOut(struct libalias *la, struct ip *pip, int create,
+		struct alias_link **new)
 {
 	int iresult;
 	struct icmp *ic;
@@ -612,18 +627,18 @@ IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
 	case ICMP_ECHO:
 	case ICMP_TSTAMP:
 		if (ic->icmp_code == 0) {
-			iresult = IcmpAliasOut1(la, pip, create);
+			iresult = IcmpAliasOut1(la, pip, create, new);
 		}
 		break;
 	case ICMP_UNREACH:
 	case ICMP_SOURCEQUENCH:
 	case ICMP_TIMXCEED:
 	case ICMP_PARAMPROB:
-		iresult = IcmpAliasOut2(la, pip);
+		iresult = IcmpAliasOut2(la, pip, new);
 		break;
 	case ICMP_ECHOREPLY:
 	case ICMP_TSTAMPREPLY:
-		iresult = IcmpAliasOut1(la, pip, create);
+		iresult = IcmpAliasOut1(la, pip, create, new);
 	}
 	return (iresult);
 }
@@ -698,7 +713,7 @@ ProtoAliasOut(struct libalias *la, struct ip *pip, int create)
 
 
 static int
-UdpAliasIn(struct libalias *la, struct ip *pip)
+UdpAliasIn(struct libalias *la, struct ip *pip, struct alias_link **new)
 {
 	struct udphdr *ud;
 	struct alias_link *lnk;
@@ -714,6 +729,7 @@ UdpAliasIn(struct libalias *la, struct ip *pip)
 		ud->uh_sport, ud->uh_dport,
 		IPPROTO_UDP, 1);
 	if (lnk != NULL) {
+		*new = lnk;
 		struct in_addr alias_address;
 		struct in_addr original_address;
 		u_short alias_port;
@@ -763,7 +779,8 @@ UdpAliasIn(struct libalias *la, struct ip *pip)
 }
 
 static int
-UdpAliasOut(struct libalias *la, struct ip *pip, int create)
+UdpAliasOut(struct libalias *la, struct ip *pip, int create,
+		struct alias_link **new)
 {
 	struct udphdr *ud;
 	struct alias_link *lnk;
@@ -780,6 +797,9 @@ UdpAliasOut(struct libalias *la, struct ip *pip, int create)
 		ud->uh_sport, ud->uh_dport,
 		IPPROTO_UDP, create);
 	if (lnk != NULL) {
+		if (create) {
+			*new = lnk;
+		}
 		u_short alias_port;
 		struct in_addr alias_address;
 		struct alias_data ad = {
@@ -825,7 +845,7 @@ UdpAliasOut(struct libalias *la, struct ip *pip, int create)
 
 
 static int
-TcpAliasIn(struct libalias *la, struct ip *pip)
+TcpAliasIn(struct libalias *la, struct ip *pip, struct alias_link **new)
 {
 	struct tcphdr *tc;
 	struct alias_link *lnk;
@@ -838,6 +858,9 @@ TcpAliasIn(struct libalias *la, struct ip *pip)
 		IPPROTO_TCP,
 		!(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
 	if (lnk != NULL) {
+		if (!(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)) {
+			*new = lnk;
+		}
 		struct in_addr alias_address;
 		struct in_addr original_address;
 		struct in_addr proxy_address;
@@ -945,7 +968,8 @@ TcpAliasIn(struct libalias *la, struct ip *pip)
 }
 
 static int
-TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
+TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create,
+		struct alias_link **new)
 {
 	int proxy_type, error;
 	u_short dest_port;
@@ -992,6 +1016,9 @@ TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
 	if (lnk == NULL)
 		return (PKT_ALIAS_IGNORED);
 	if (lnk != NULL) {
+		if (create) {
+			*new = lnk;
+		}
 		u_short alias_port;
 		struct in_addr alias_address;
 		int accumulate;
@@ -1197,24 +1224,26 @@ LibAliasFragmentIn(struct libalias *la, char *ptr,	/* Points to correctly
 /* Local prototypes */
 static int
 LibAliasOutLocked(struct libalias *la, char *ptr,
-		  int maxpacketsize, int create);
+		  int maxpacketsize, int create, struct alias_link **);
 static int
 LibAliasInLocked(struct libalias *la, char *ptr,
-		  int maxpacketsize);
+		  int maxpacketsize, struct alias_link **);
 
 int
-LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
+LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize,
+		struct alias_link **new)
 {
 	int res;
 
 	LIBALIAS_LOCK(la);
-	res = LibAliasInLocked(la, ptr, maxpacketsize);
+	res = LibAliasInLocked(la, ptr, maxpacketsize, new);
 	LIBALIAS_UNLOCK(la);
 	return (res);
 }
 
 static int
-LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize)
+LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize,
+		struct alias_link **new)
 {
 	struct in_addr alias_addr;
 	struct ip *pip;
@@ -1222,7 +1251,7 @@ LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize)
 
 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
-		iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
+		iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1, new);
 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
 		goto getout;
 	}
@@ -1242,13 +1271,13 @@ LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize)
 	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
 		switch (pip->ip_p) {
 		case IPPROTO_ICMP:
-			iresult = IcmpAliasIn(la, pip);
+			iresult = IcmpAliasIn(la, pip, new);
 			break;
 		case IPPROTO_UDP:
-			iresult = UdpAliasIn(la, pip);
+			iresult = UdpAliasIn(la, pip, new);
 			break;
 		case IPPROTO_TCP:
-			iresult = TcpAliasIn(la, pip);
+			iresult = TcpAliasIn(la, pip, new);
 			break;
 		case IPPROTO_GRE: {
 			int error;
@@ -1311,23 +1340,25 @@ getout:
 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
 
 int
-LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize)
+LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize,
+		struct alias_link **new)
 {
 	int res;
 
 	LIBALIAS_LOCK(la);
-	res = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
+	res = LibAliasOutLocked(la, ptr, maxpacketsize, 1, new);
 	LIBALIAS_UNLOCK(la);
 	return (res);
 }
 
 int
-LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create)
+LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create,
+		struct alias_link **new)
 {
 	int res;
 
 	LIBALIAS_LOCK(la);
-	res = LibAliasOutLocked(la, ptr, maxpacketsize, create);
+	res = LibAliasOutLocked(la, ptr, maxpacketsize, create, new);
 	LIBALIAS_UNLOCK(la);
 	return (res);
 }
@@ -1337,6 +1368,7 @@ LibAliasOutLocked(struct libalias *la, char *ptr,	/* valid IP packet */
 	int maxpacketsize,		/* How much the packet data may grow (FTP
 				 * and IRC inline changes) */
 	int create				  /* Create new entries ? */
+	, struct alias_link **new
 )
 {
 	int iresult;
@@ -1345,7 +1377,7 @@ LibAliasOutLocked(struct libalias *la, char *ptr,	/* valid IP packet */
 
 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
-		iresult = LibAliasInLocked(la, ptr, maxpacketsize);
+		iresult = LibAliasInLocked(la, ptr, maxpacketsize, new);
 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
 		goto getout;
 	}
@@ -1384,13 +1416,14 @@ LibAliasOutLocked(struct libalias *la, char *ptr,	/* valid IP packet */
 	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
 		switch (pip->ip_p) {
 		case IPPROTO_ICMP:
-			iresult = IcmpAliasOut(la, pip, create);
+			iresult = IcmpAliasOut(la, pip, create, new);
 			break;
 		case IPPROTO_UDP:
-			iresult = UdpAliasOut(la, pip, create);
+			iresult = UdpAliasOut(la, pip, create, new);
 			break;
 			case IPPROTO_TCP:
-			iresult = TcpAliasOut(la, pip, maxpacketsize, create);
+			iresult = TcpAliasOut(la, pip, maxpacketsize, create,
+					new);
 			break;
 		case IPPROTO_GRE: {
 			int error;
diff --git a/sys/net/libalias/alias.h b/sys/net/libalias/alias.h
index 259064b..1ad70e4 100644
--- a/sys/net/libalias/alias.h
+++ b/sys/net/libalias/alias.h
@@ -249,9 +249,12 @@ unsigned int
 void		LibAliasUninit(struct libalias *);
 
 /* Packet Handling functions. */
-int		LibAliasIn (struct libalias *, char *_ptr, int _maxpacketsize);
-int		LibAliasOut(struct libalias *, char *_ptr, int _maxpacketsize);
-int		LibAliasOutTry(struct libalias *, char *_ptr, int _maxpacketsize, int _create);
+int		LibAliasIn (struct libalias *, char *_ptr, int _maxpacketsize,
+		struct alias_link **);
+int		LibAliasOut(struct libalias *, char *_ptr, int _maxpacketsize,
+		struct alias_link **);
+int		LibAliasOutTry(struct libalias *, char *_ptr, int
+		_maxpacketsize, int _create, struct alias_link **);
 int		LibAliasUnaliasOut(struct libalias *, char *_ptr, int _maxpacketsize);
 
 /* Port and address redirection functions. */
