xref: /freebsd/sys/netpfil/ipfw/ip_fw_nat.c (revision ccba94b8fc30d4fbb7eaaa5b0bf90dbbd1dc7c64)
13b3a8eb9SGleb Smirnoff /*-
23b3a8eb9SGleb Smirnoff  * Copyright (c) 2008 Paolo Pisati
33b3a8eb9SGleb Smirnoff  * All rights reserved.
43b3a8eb9SGleb Smirnoff  *
53b3a8eb9SGleb Smirnoff  * Redistribution and use in source and binary forms, with or without
63b3a8eb9SGleb Smirnoff  * modification, are permitted provided that the following conditions
73b3a8eb9SGleb Smirnoff  * are met:
83b3a8eb9SGleb Smirnoff  * 1. Redistributions of source code must retain the above copyright
93b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer.
103b3a8eb9SGleb Smirnoff  * 2. Redistributions in binary form must reproduce the above copyright
113b3a8eb9SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer in the
123b3a8eb9SGleb Smirnoff  *    documentation and/or other materials provided with the distribution.
133b3a8eb9SGleb Smirnoff  *
143b3a8eb9SGleb Smirnoff  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153b3a8eb9SGleb Smirnoff  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163b3a8eb9SGleb Smirnoff  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173b3a8eb9SGleb Smirnoff  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183b3a8eb9SGleb Smirnoff  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193b3a8eb9SGleb Smirnoff  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203b3a8eb9SGleb Smirnoff  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213b3a8eb9SGleb Smirnoff  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223b3a8eb9SGleb Smirnoff  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233b3a8eb9SGleb Smirnoff  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243b3a8eb9SGleb Smirnoff  * SUCH DAMAGE.
253b3a8eb9SGleb Smirnoff  */
263b3a8eb9SGleb Smirnoff 
273b3a8eb9SGleb Smirnoff #include <sys/cdefs.h>
283b3a8eb9SGleb Smirnoff __FBSDID("$FreeBSD$");
293b3a8eb9SGleb Smirnoff 
303b3a8eb9SGleb Smirnoff #include <sys/param.h>
313b3a8eb9SGleb Smirnoff #include <sys/systm.h>
323b3a8eb9SGleb Smirnoff #include <sys/eventhandler.h>
333b3a8eb9SGleb Smirnoff #include <sys/malloc.h>
3476039bc8SGleb Smirnoff #include <sys/mbuf.h>
353b3a8eb9SGleb Smirnoff #include <sys/kernel.h>
363b3a8eb9SGleb Smirnoff #include <sys/lock.h>
373b3a8eb9SGleb Smirnoff #include <sys/module.h>
383b3a8eb9SGleb Smirnoff #include <sys/rwlock.h>
39*ccba94b8SAlexander V. Chernikov #include <sys/rmlock.h>
403b3a8eb9SGleb Smirnoff 
413b3a8eb9SGleb Smirnoff #include <netinet/libalias/alias.h>
423b3a8eb9SGleb Smirnoff #include <netinet/libalias/alias_local.h>
433b3a8eb9SGleb Smirnoff 
443b3a8eb9SGleb Smirnoff #include <net/if.h>
4576039bc8SGleb Smirnoff #include <net/if_var.h>
463b3a8eb9SGleb Smirnoff #include <netinet/in.h>
473b3a8eb9SGleb Smirnoff #include <netinet/ip.h>
483b3a8eb9SGleb Smirnoff #include <netinet/ip_var.h>
493b3a8eb9SGleb Smirnoff #include <netinet/ip_fw.h>
503b3a8eb9SGleb Smirnoff #include <netinet/tcp.h>
513b3a8eb9SGleb Smirnoff #include <netinet/udp.h>
523b3a8eb9SGleb Smirnoff 
533b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/ip_fw_private.h>
543b3a8eb9SGleb Smirnoff 
553b3a8eb9SGleb Smirnoff #include <machine/in_cksum.h>	/* XXX for in_cksum */
563b3a8eb9SGleb Smirnoff 
57d6164b77SAlexander V. Chernikov struct cfg_spool {
58d6164b77SAlexander V. Chernikov 	LIST_ENTRY(cfg_spool)   _next;          /* chain of spool instances */
59d6164b77SAlexander V. Chernikov 	struct in_addr          addr;
60d6164b77SAlexander V. Chernikov 	uint16_t		port;
61d6164b77SAlexander V. Chernikov };
62d6164b77SAlexander V. Chernikov 
63d6164b77SAlexander V. Chernikov /* Nat redirect configuration. */
64d6164b77SAlexander V. Chernikov struct cfg_redir {
65d6164b77SAlexander V. Chernikov 	LIST_ENTRY(cfg_redir)	_next;	/* chain of redir instances */
66d6164b77SAlexander V. Chernikov 	uint16_t		mode;	/* type of redirect mode */
67d6164b77SAlexander V. Chernikov 	uint16_t		proto;	/* protocol: tcp/udp */
68d6164b77SAlexander V. Chernikov 	struct in_addr		laddr;	/* local ip address */
69d6164b77SAlexander V. Chernikov 	struct in_addr		paddr;	/* public ip address */
70d6164b77SAlexander V. Chernikov 	struct in_addr		raddr;	/* remote ip address */
71d6164b77SAlexander V. Chernikov 	uint16_t		lport;	/* local port */
72d6164b77SAlexander V. Chernikov 	uint16_t		pport;	/* public port */
73d6164b77SAlexander V. Chernikov 	uint16_t		rport;	/* remote port	*/
74d6164b77SAlexander V. Chernikov 	uint16_t		pport_cnt;	/* number of public ports */
75d6164b77SAlexander V. Chernikov 	uint16_t		rport_cnt;	/* number of remote ports */
76d6164b77SAlexander V. Chernikov 	struct alias_link	**alink;
77d6164b77SAlexander V. Chernikov 	u_int16_t		spool_cnt; /* num of entry in spool chain */
78d6164b77SAlexander V. Chernikov 	/* chain of spool instances */
79d6164b77SAlexander V. Chernikov 	LIST_HEAD(spool_chain, cfg_spool) spool_chain;
80d6164b77SAlexander V. Chernikov };
81d6164b77SAlexander V. Chernikov 
82d6164b77SAlexander V. Chernikov /* Nat configuration data struct. */
83d6164b77SAlexander V. Chernikov struct cfg_nat {
84d6164b77SAlexander V. Chernikov 	/* chain of nat instances */
85d6164b77SAlexander V. Chernikov 	LIST_ENTRY(cfg_nat)	_next;
86d6164b77SAlexander V. Chernikov 	int			id;		/* nat id  */
87d6164b77SAlexander V. Chernikov 	struct in_addr		ip;		/* nat ip address */
88d6164b77SAlexander V. Chernikov 	struct libalias		*lib;		/* libalias instance */
89d6164b77SAlexander V. Chernikov 	int			mode;		/* aliasing mode */
90d6164b77SAlexander V. Chernikov 	int			redir_cnt; /* number of entry in spool chain */
91d6164b77SAlexander V. Chernikov 	/* chain of redir instances */
92d6164b77SAlexander V. Chernikov 	LIST_HEAD(redir_chain, cfg_redir) redir_chain;
93d6164b77SAlexander V. Chernikov 	char			if_name[IF_NAMESIZE];	/* interface name */
94d6164b77SAlexander V. Chernikov };
95d6164b77SAlexander V. Chernikov 
968856400bSMikolaj Golub static eventhandler_tag ifaddr_event_tag;
973b3a8eb9SGleb Smirnoff 
983b3a8eb9SGleb Smirnoff static void
993b3a8eb9SGleb Smirnoff ifaddr_change(void *arg __unused, struct ifnet *ifp)
1003b3a8eb9SGleb Smirnoff {
1013b3a8eb9SGleb Smirnoff 	struct cfg_nat *ptr;
1023b3a8eb9SGleb Smirnoff 	struct ifaddr *ifa;
1033b3a8eb9SGleb Smirnoff 	struct ip_fw_chain *chain;
1043b3a8eb9SGleb Smirnoff 
1058856400bSMikolaj Golub 	KASSERT(curvnet == ifp->if_vnet,
1068856400bSMikolaj Golub 	    ("curvnet(%p) differs from iface vnet(%p)", curvnet, ifp->if_vnet));
1073b3a8eb9SGleb Smirnoff 	chain = &V_layer3_chain;
108c254a209SAlexander V. Chernikov 	IPFW_WLOCK(chain);
1093b3a8eb9SGleb Smirnoff 	/* Check every nat entry... */
1103b3a8eb9SGleb Smirnoff 	LIST_FOREACH(ptr, &chain->nat, _next) {
1113b3a8eb9SGleb Smirnoff 		/* ...using nic 'ifp->if_xname' as dynamic alias address. */
112c254a209SAlexander V. Chernikov 		if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0)
1133b3a8eb9SGleb Smirnoff 			continue;
1143b3a8eb9SGleb Smirnoff 		if_addr_rlock(ifp);
1153b3a8eb9SGleb Smirnoff 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1163b3a8eb9SGleb Smirnoff 			if (ifa->ifa_addr == NULL)
1173b3a8eb9SGleb Smirnoff 				continue;
1183b3a8eb9SGleb Smirnoff 			if (ifa->ifa_addr->sa_family != AF_INET)
1193b3a8eb9SGleb Smirnoff 				continue;
1203b3a8eb9SGleb Smirnoff 			ptr->ip = ((struct sockaddr_in *)
1213b3a8eb9SGleb Smirnoff 			    (ifa->ifa_addr))->sin_addr;
1223b3a8eb9SGleb Smirnoff 			LibAliasSetAddress(ptr->lib, ptr->ip);
1233b3a8eb9SGleb Smirnoff 		}
1243b3a8eb9SGleb Smirnoff 		if_addr_runlock(ifp);
1253b3a8eb9SGleb Smirnoff 	}
126c254a209SAlexander V. Chernikov 	IPFW_WUNLOCK(chain);
1273b3a8eb9SGleb Smirnoff }
1283b3a8eb9SGleb Smirnoff 
1293b3a8eb9SGleb Smirnoff /*
1303b3a8eb9SGleb Smirnoff  * delete the pointers for nat entry ix, or all of them if ix < 0
1313b3a8eb9SGleb Smirnoff  */
1323b3a8eb9SGleb Smirnoff static void
1333b3a8eb9SGleb Smirnoff flush_nat_ptrs(struct ip_fw_chain *chain, const int ix)
1343b3a8eb9SGleb Smirnoff {
1353b3a8eb9SGleb Smirnoff 	int i;
1363b3a8eb9SGleb Smirnoff 	ipfw_insn_nat *cmd;
1373b3a8eb9SGleb Smirnoff 
1383b3a8eb9SGleb Smirnoff 	IPFW_WLOCK_ASSERT(chain);
1393b3a8eb9SGleb Smirnoff 	for (i = 0; i < chain->n_rules; i++) {
1403b3a8eb9SGleb Smirnoff 		cmd = (ipfw_insn_nat *)ACTION_PTR(chain->map[i]);
1413b3a8eb9SGleb Smirnoff 		/* XXX skip log and the like ? */
1423b3a8eb9SGleb Smirnoff 		if (cmd->o.opcode == O_NAT && cmd->nat != NULL &&
1433b3a8eb9SGleb Smirnoff 			    (ix < 0 || cmd->nat->id == ix))
1443b3a8eb9SGleb Smirnoff 			cmd->nat = NULL;
1453b3a8eb9SGleb Smirnoff 	}
1463b3a8eb9SGleb Smirnoff }
1473b3a8eb9SGleb Smirnoff 
1483b3a8eb9SGleb Smirnoff static void
1493b3a8eb9SGleb Smirnoff del_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head)
1503b3a8eb9SGleb Smirnoff {
1513b3a8eb9SGleb Smirnoff 	struct cfg_redir *r, *tmp_r;
1523b3a8eb9SGleb Smirnoff 	struct cfg_spool *s, *tmp_s;
1533b3a8eb9SGleb Smirnoff 	int i, num;
1543b3a8eb9SGleb Smirnoff 
1553b3a8eb9SGleb Smirnoff 	LIST_FOREACH_SAFE(r, head, _next, tmp_r) {
1563b3a8eb9SGleb Smirnoff 		num = 1; /* Number of alias_link to delete. */
1573b3a8eb9SGleb Smirnoff 		switch (r->mode) {
158d6164b77SAlexander V. Chernikov 		case NAT44_REDIR_PORT:
1593b3a8eb9SGleb Smirnoff 			num = r->pport_cnt;
1603b3a8eb9SGleb Smirnoff 			/* FALLTHROUGH */
161d6164b77SAlexander V. Chernikov 		case NAT44_REDIR_ADDR:
162d6164b77SAlexander V. Chernikov 		case NAT44_REDIR_PROTO:
1633b3a8eb9SGleb Smirnoff 			/* Delete all libalias redirect entry. */
1643b3a8eb9SGleb Smirnoff 			for (i = 0; i < num; i++)
1653b3a8eb9SGleb Smirnoff 				LibAliasRedirectDelete(n->lib, r->alink[i]);
1663b3a8eb9SGleb Smirnoff 			/* Del spool cfg if any. */
1673b3a8eb9SGleb Smirnoff 			LIST_FOREACH_SAFE(s, &r->spool_chain, _next, tmp_s) {
1683b3a8eb9SGleb Smirnoff 				LIST_REMOVE(s, _next);
1693b3a8eb9SGleb Smirnoff 				free(s, M_IPFW);
1703b3a8eb9SGleb Smirnoff 			}
1713b3a8eb9SGleb Smirnoff 			free(r->alink, M_IPFW);
1723b3a8eb9SGleb Smirnoff 			LIST_REMOVE(r, _next);
1733b3a8eb9SGleb Smirnoff 			free(r, M_IPFW);
1743b3a8eb9SGleb Smirnoff 			break;
1753b3a8eb9SGleb Smirnoff 		default:
1763b3a8eb9SGleb Smirnoff 			printf("unknown redirect mode: %u\n", r->mode);
1773b3a8eb9SGleb Smirnoff 			/* XXX - panic?!?!? */
1783b3a8eb9SGleb Smirnoff 			break;
1793b3a8eb9SGleb Smirnoff 		}
1803b3a8eb9SGleb Smirnoff 	}
1813b3a8eb9SGleb Smirnoff }
1823b3a8eb9SGleb Smirnoff 
183d6164b77SAlexander V. Chernikov static int
1843b3a8eb9SGleb Smirnoff add_redir_spool_cfg(char *buf, struct cfg_nat *ptr)
1853b3a8eb9SGleb Smirnoff {
186d6164b77SAlexander V. Chernikov 	struct cfg_redir *r;
187d6164b77SAlexander V. Chernikov 	struct cfg_spool *s;
188d6164b77SAlexander V. Chernikov 	struct nat44_cfg_redir *ser_r;
189d6164b77SAlexander V. Chernikov 	struct nat44_cfg_spool *ser_s;
190d6164b77SAlexander V. Chernikov 
1913b3a8eb9SGleb Smirnoff 	int cnt, off, i;
1923b3a8eb9SGleb Smirnoff 
1933b3a8eb9SGleb Smirnoff 	for (cnt = 0, off = 0; cnt < ptr->redir_cnt; cnt++) {
194d6164b77SAlexander V. Chernikov 		ser_r = (struct nat44_cfg_redir *)&buf[off];
195d6164b77SAlexander V. Chernikov 		r = malloc(sizeof(*r), M_IPFW, M_WAITOK | M_ZERO);
196d6164b77SAlexander V. Chernikov 		r->mode = ser_r->mode;
197d6164b77SAlexander V. Chernikov 		r->laddr = ser_r->laddr;
198d6164b77SAlexander V. Chernikov 		r->paddr = ser_r->paddr;
199d6164b77SAlexander V. Chernikov 		r->raddr = ser_r->raddr;
200d6164b77SAlexander V. Chernikov 		r->lport = ser_r->lport;
201d6164b77SAlexander V. Chernikov 		r->pport = ser_r->pport;
202d6164b77SAlexander V. Chernikov 		r->rport = ser_r->rport;
203d6164b77SAlexander V. Chernikov 		r->pport_cnt = ser_r->pport_cnt;
204d6164b77SAlexander V. Chernikov 		r->rport_cnt = ser_r->rport_cnt;
205d6164b77SAlexander V. Chernikov 		r->proto = ser_r->proto;
206d6164b77SAlexander V. Chernikov 		r->spool_cnt = ser_r->spool_cnt;
207d6164b77SAlexander V. Chernikov 		//memcpy(r, ser_r, SOF_REDIR);
2083b3a8eb9SGleb Smirnoff 		LIST_INIT(&r->spool_chain);
209d6164b77SAlexander V. Chernikov 		off += sizeof(struct nat44_cfg_redir);
2103b3a8eb9SGleb Smirnoff 		r->alink = malloc(sizeof(struct alias_link *) * r->pport_cnt,
2113b3a8eb9SGleb Smirnoff 		    M_IPFW, M_WAITOK | M_ZERO);
2123b3a8eb9SGleb Smirnoff 		switch (r->mode) {
213d6164b77SAlexander V. Chernikov 		case NAT44_REDIR_ADDR:
2143b3a8eb9SGleb Smirnoff 			r->alink[0] = LibAliasRedirectAddr(ptr->lib, r->laddr,
2153b3a8eb9SGleb Smirnoff 			    r->paddr);
2163b3a8eb9SGleb Smirnoff 			break;
217d6164b77SAlexander V. Chernikov 		case NAT44_REDIR_PORT:
2183b3a8eb9SGleb Smirnoff 			for (i = 0 ; i < r->pport_cnt; i++) {
2193b3a8eb9SGleb Smirnoff 				/* If remotePort is all ports, set it to 0. */
2203b3a8eb9SGleb Smirnoff 				u_short remotePortCopy = r->rport + i;
2213b3a8eb9SGleb Smirnoff 				if (r->rport_cnt == 1 && r->rport == 0)
2223b3a8eb9SGleb Smirnoff 					remotePortCopy = 0;
2233b3a8eb9SGleb Smirnoff 				r->alink[i] = LibAliasRedirectPort(ptr->lib,
2243b3a8eb9SGleb Smirnoff 				    r->laddr, htons(r->lport + i), r->raddr,
2253b3a8eb9SGleb Smirnoff 				    htons(remotePortCopy), r->paddr,
2263b3a8eb9SGleb Smirnoff 				    htons(r->pport + i), r->proto);
2273b3a8eb9SGleb Smirnoff 				if (r->alink[i] == NULL) {
2283b3a8eb9SGleb Smirnoff 					r->alink[0] = NULL;
2293b3a8eb9SGleb Smirnoff 					break;
2303b3a8eb9SGleb Smirnoff 				}
2313b3a8eb9SGleb Smirnoff 			}
2323b3a8eb9SGleb Smirnoff 			break;
233d6164b77SAlexander V. Chernikov 		case NAT44_REDIR_PROTO:
2343b3a8eb9SGleb Smirnoff 			r->alink[0] = LibAliasRedirectProto(ptr->lib ,r->laddr,
2353b3a8eb9SGleb Smirnoff 			    r->raddr, r->paddr, r->proto);
2363b3a8eb9SGleb Smirnoff 			break;
2373b3a8eb9SGleb Smirnoff 		default:
2383b3a8eb9SGleb Smirnoff 			printf("unknown redirect mode: %u\n", r->mode);
2393b3a8eb9SGleb Smirnoff 			break;
2403b3a8eb9SGleb Smirnoff 		}
241d6164b77SAlexander V. Chernikov 		if (r->alink[0] == NULL) {
242d6164b77SAlexander V. Chernikov 			printf("LibAliasRedirect* returned NULL\n");
243d6164b77SAlexander V. Chernikov 			return (EINVAL);
244d6164b77SAlexander V. Chernikov 		}
2453b3a8eb9SGleb Smirnoff 		/* LSNAT handling. */
2463b3a8eb9SGleb Smirnoff 		for (i = 0; i < r->spool_cnt; i++) {
247d6164b77SAlexander V. Chernikov 			ser_s = (struct nat44_cfg_spool *)&buf[off];
248d6164b77SAlexander V. Chernikov 			s = malloc(sizeof(*s), M_IPFW, M_WAITOK | M_ZERO);
249d6164b77SAlexander V. Chernikov 			s->addr = ser_s->addr;
250d6164b77SAlexander V. Chernikov 			s->port = ser_s->port;
2513b3a8eb9SGleb Smirnoff 			LibAliasAddServer(ptr->lib, r->alink[0],
2523b3a8eb9SGleb Smirnoff 			    s->addr, htons(s->port));
253d6164b77SAlexander V. Chernikov 			off += sizeof(struct nat44_cfg_spool);
2543b3a8eb9SGleb Smirnoff 			/* Hook spool entry. */
2553b3a8eb9SGleb Smirnoff 			LIST_INSERT_HEAD(&r->spool_chain, s, _next);
2563b3a8eb9SGleb Smirnoff 		}
2573b3a8eb9SGleb Smirnoff 		/* And finally hook this redir entry. */
2583b3a8eb9SGleb Smirnoff 		LIST_INSERT_HEAD(&ptr->redir_chain, r, _next);
2593b3a8eb9SGleb Smirnoff 	}
260d6164b77SAlexander V. Chernikov 
261d6164b77SAlexander V. Chernikov 	return (0);
2623b3a8eb9SGleb Smirnoff }
2633b3a8eb9SGleb Smirnoff 
26410ab2de0SAlexander V. Chernikov /*
26510ab2de0SAlexander V. Chernikov  * ipfw_nat - perform mbuf header translation.
26610ab2de0SAlexander V. Chernikov  *
26710ab2de0SAlexander V. Chernikov  * Note V_layer3_chain has to be locked while calling ipfw_nat() in
26810ab2de0SAlexander V. Chernikov  * 'global' operation mode (t == NULL).
26910ab2de0SAlexander V. Chernikov  *
27010ab2de0SAlexander V. Chernikov  */
2713b3a8eb9SGleb Smirnoff static int
2723b3a8eb9SGleb Smirnoff ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
2733b3a8eb9SGleb Smirnoff {
2743b3a8eb9SGleb Smirnoff 	struct mbuf *mcl;
2753b3a8eb9SGleb Smirnoff 	struct ip *ip;
2763b3a8eb9SGleb Smirnoff 	/* XXX - libalias duct tape */
2773b3a8eb9SGleb Smirnoff 	int ldt, retval, found;
2783b3a8eb9SGleb Smirnoff 	struct ip_fw_chain *chain;
2793b3a8eb9SGleb Smirnoff 	char *c;
2803b3a8eb9SGleb Smirnoff 
2813b3a8eb9SGleb Smirnoff 	ldt = 0;
2823b3a8eb9SGleb Smirnoff 	retval = 0;
2833b3a8eb9SGleb Smirnoff 	mcl = m_megapullup(m, m->m_pkthdr.len);
2843b3a8eb9SGleb Smirnoff 	if (mcl == NULL) {
2853b3a8eb9SGleb Smirnoff 		args->m = NULL;
2863b3a8eb9SGleb Smirnoff 		return (IP_FW_DENY);
2873b3a8eb9SGleb Smirnoff 	}
2883b3a8eb9SGleb Smirnoff 	ip = mtod(mcl, struct ip *);
2893b3a8eb9SGleb Smirnoff 
2903b3a8eb9SGleb Smirnoff 	/*
2913b3a8eb9SGleb Smirnoff 	 * XXX - Libalias checksum offload 'duct tape':
2923b3a8eb9SGleb Smirnoff 	 *
2933b3a8eb9SGleb Smirnoff 	 * locally generated packets have only pseudo-header checksum
2943b3a8eb9SGleb Smirnoff 	 * calculated and libalias will break it[1], so mark them for
2953b3a8eb9SGleb Smirnoff 	 * later fix.  Moreover there are cases when libalias modifies
2963b3a8eb9SGleb Smirnoff 	 * tcp packet data[2], mark them for later fix too.
2973b3a8eb9SGleb Smirnoff 	 *
2983b3a8eb9SGleb Smirnoff 	 * [1] libalias was never meant to run in kernel, so it does
2993b3a8eb9SGleb Smirnoff 	 * not have any knowledge about checksum offloading, and
3003b3a8eb9SGleb Smirnoff 	 * expects a packet with a full internet checksum.
3013b3a8eb9SGleb Smirnoff 	 * Unfortunately, packets generated locally will have just the
3023b3a8eb9SGleb Smirnoff 	 * pseudo header calculated, and when libalias tries to adjust
3033b3a8eb9SGleb Smirnoff 	 * the checksum it will actually compute a wrong value.
3043b3a8eb9SGleb Smirnoff 	 *
3053b3a8eb9SGleb Smirnoff 	 * [2] when libalias modifies tcp's data content, full TCP
3063b3a8eb9SGleb Smirnoff 	 * checksum has to be recomputed: the problem is that
3073b3a8eb9SGleb Smirnoff 	 * libalias does not have any idea about checksum offloading.
3083b3a8eb9SGleb Smirnoff 	 * To work around this, we do not do checksumming in LibAlias,
3093b3a8eb9SGleb Smirnoff 	 * but only mark the packets in th_x2 field. If we receive a
3103b3a8eb9SGleb Smirnoff 	 * marked packet, we calculate correct checksum for it
3113b3a8eb9SGleb Smirnoff 	 * aware of offloading.  Why such a terrible hack instead of
3123b3a8eb9SGleb Smirnoff 	 * recalculating checksum for each packet?
3133b3a8eb9SGleb Smirnoff 	 * Because the previous checksum was not checked!
3143b3a8eb9SGleb Smirnoff 	 * Recalculating checksums for EVERY packet will hide ALL
3153b3a8eb9SGleb Smirnoff 	 * transmission errors. Yes, marked packets still suffer from
3163b3a8eb9SGleb Smirnoff 	 * this problem. But, sigh, natd(8) has this problem, too.
3173b3a8eb9SGleb Smirnoff 	 *
3183b3a8eb9SGleb Smirnoff 	 * TODO: -make libalias mbuf aware (so
3193b3a8eb9SGleb Smirnoff 	 * it can handle delayed checksum and tso)
3203b3a8eb9SGleb Smirnoff 	 */
3213b3a8eb9SGleb Smirnoff 
3223b3a8eb9SGleb Smirnoff 	if (mcl->m_pkthdr.rcvif == NULL &&
3233b3a8eb9SGleb Smirnoff 	    mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA)
3243b3a8eb9SGleb Smirnoff 		ldt = 1;
3253b3a8eb9SGleb Smirnoff 
3263b3a8eb9SGleb Smirnoff 	c = mtod(mcl, char *);
3273b3a8eb9SGleb Smirnoff 
3283b3a8eb9SGleb Smirnoff 	/* Check if this is 'global' instance */
3293b3a8eb9SGleb Smirnoff 	if (t == NULL) {
3303b3a8eb9SGleb Smirnoff 		if (args->oif == NULL) {
3313b3a8eb9SGleb Smirnoff 			/* Wrong direction, skip processing */
3323b3a8eb9SGleb Smirnoff 			args->m = mcl;
3333b3a8eb9SGleb Smirnoff 			return (IP_FW_NAT);
3343b3a8eb9SGleb Smirnoff 		}
3353b3a8eb9SGleb Smirnoff 
3363b3a8eb9SGleb Smirnoff 		found = 0;
3373b3a8eb9SGleb Smirnoff 		chain = &V_layer3_chain;
3385d0cd926SAlexander V. Chernikov 		IPFW_RLOCK_ASSERT(chain);
3393b3a8eb9SGleb Smirnoff 		/* Check every nat entry... */
3403b3a8eb9SGleb Smirnoff 		LIST_FOREACH(t, &chain->nat, _next) {
3413b3a8eb9SGleb Smirnoff 			if ((t->mode & PKT_ALIAS_SKIP_GLOBAL) != 0)
3423b3a8eb9SGleb Smirnoff 				continue;
3433b3a8eb9SGleb Smirnoff 			retval = LibAliasOutTry(t->lib, c,
3443b3a8eb9SGleb Smirnoff 			    mcl->m_len + M_TRAILINGSPACE(mcl), 0);
3453b3a8eb9SGleb Smirnoff 			if (retval == PKT_ALIAS_OK) {
3463b3a8eb9SGleb Smirnoff 				/* Nat instance recognises state */
3473b3a8eb9SGleb Smirnoff 				found = 1;
3483b3a8eb9SGleb Smirnoff 				break;
3493b3a8eb9SGleb Smirnoff 			}
3503b3a8eb9SGleb Smirnoff 		}
3513b3a8eb9SGleb Smirnoff 		if (found != 1) {
3523b3a8eb9SGleb Smirnoff 			/* No instance found, return ignore */
3533b3a8eb9SGleb Smirnoff 			args->m = mcl;
3543b3a8eb9SGleb Smirnoff 			return (IP_FW_NAT);
3553b3a8eb9SGleb Smirnoff 		}
3563b3a8eb9SGleb Smirnoff 	} else {
3573b3a8eb9SGleb Smirnoff 		if (args->oif == NULL)
3583b3a8eb9SGleb Smirnoff 			retval = LibAliasIn(t->lib, c,
3593b3a8eb9SGleb Smirnoff 				mcl->m_len + M_TRAILINGSPACE(mcl));
3603b3a8eb9SGleb Smirnoff 		else
3613b3a8eb9SGleb Smirnoff 			retval = LibAliasOut(t->lib, c,
3623b3a8eb9SGleb Smirnoff 				mcl->m_len + M_TRAILINGSPACE(mcl));
3633b3a8eb9SGleb Smirnoff 	}
3643b3a8eb9SGleb Smirnoff 
3653b3a8eb9SGleb Smirnoff 	/*
3663b3a8eb9SGleb Smirnoff 	 * We drop packet when:
3673b3a8eb9SGleb Smirnoff 	 * 1. libalias returns PKT_ALIAS_ERROR;
3683b3a8eb9SGleb Smirnoff 	 * 2. For incoming packets:
3693b3a8eb9SGleb Smirnoff 	 *	a) for unresolved fragments;
3703b3a8eb9SGleb Smirnoff 	 *	b) libalias returns PKT_ALIAS_IGNORED and
3713b3a8eb9SGleb Smirnoff 	 *		PKT_ALIAS_DENY_INCOMING flag is set.
3723b3a8eb9SGleb Smirnoff 	 */
3733b3a8eb9SGleb Smirnoff 	if (retval == PKT_ALIAS_ERROR ||
3743b3a8eb9SGleb Smirnoff 	    (args->oif == NULL && (retval == PKT_ALIAS_UNRESOLVED_FRAGMENT ||
3753b3a8eb9SGleb Smirnoff 	    (retval == PKT_ALIAS_IGNORED &&
3763b3a8eb9SGleb Smirnoff 	    (t->mode & PKT_ALIAS_DENY_INCOMING) != 0)))) {
3773b3a8eb9SGleb Smirnoff 		/* XXX - should i add some logging? */
3783b3a8eb9SGleb Smirnoff 		m_free(mcl);
3793b3a8eb9SGleb Smirnoff 		args->m = NULL;
3803b3a8eb9SGleb Smirnoff 		return (IP_FW_DENY);
3813b3a8eb9SGleb Smirnoff 	}
3823b3a8eb9SGleb Smirnoff 
3833b3a8eb9SGleb Smirnoff 	if (retval == PKT_ALIAS_RESPOND)
3843b3a8eb9SGleb Smirnoff 		mcl->m_flags |= M_SKIP_FIREWALL;
3853b3a8eb9SGleb Smirnoff 	mcl->m_pkthdr.len = mcl->m_len = ntohs(ip->ip_len);
3863b3a8eb9SGleb Smirnoff 
3873b3a8eb9SGleb Smirnoff 	/*
3883b3a8eb9SGleb Smirnoff 	 * XXX - libalias checksum offload
3893b3a8eb9SGleb Smirnoff 	 * 'duct tape' (see above)
3903b3a8eb9SGleb Smirnoff 	 */
3913b3a8eb9SGleb Smirnoff 
3923b3a8eb9SGleb Smirnoff 	if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
3933b3a8eb9SGleb Smirnoff 	    ip->ip_p == IPPROTO_TCP) {
3943b3a8eb9SGleb Smirnoff 		struct tcphdr 	*th;
3953b3a8eb9SGleb Smirnoff 
3963b3a8eb9SGleb Smirnoff 		th = (struct tcphdr *)(ip + 1);
3973b3a8eb9SGleb Smirnoff 		if (th->th_x2)
3983b3a8eb9SGleb Smirnoff 			ldt = 1;
3993b3a8eb9SGleb Smirnoff 	}
4003b3a8eb9SGleb Smirnoff 
4013b3a8eb9SGleb Smirnoff 	if (ldt) {
4023b3a8eb9SGleb Smirnoff 		struct tcphdr 	*th;
4033b3a8eb9SGleb Smirnoff 		struct udphdr 	*uh;
40423e9c6dcSGleb Smirnoff 		uint16_t ip_len, cksum;
4053b3a8eb9SGleb Smirnoff 
40623e9c6dcSGleb Smirnoff 		ip_len = ntohs(ip->ip_len);
4073b3a8eb9SGleb Smirnoff 		cksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
40823e9c6dcSGleb Smirnoff 		    htons(ip->ip_p + ip_len - (ip->ip_hl << 2)));
4093b3a8eb9SGleb Smirnoff 
4103b3a8eb9SGleb Smirnoff 		switch (ip->ip_p) {
4113b3a8eb9SGleb Smirnoff 		case IPPROTO_TCP:
4123b3a8eb9SGleb Smirnoff 			th = (struct tcphdr *)(ip + 1);
4133b3a8eb9SGleb Smirnoff 			/*
4143b3a8eb9SGleb Smirnoff 			 * Maybe it was set in
4153b3a8eb9SGleb Smirnoff 			 * libalias...
4163b3a8eb9SGleb Smirnoff 			 */
4173b3a8eb9SGleb Smirnoff 			th->th_x2 = 0;
4183b3a8eb9SGleb Smirnoff 			th->th_sum = cksum;
4193b3a8eb9SGleb Smirnoff 			mcl->m_pkthdr.csum_data =
4203b3a8eb9SGleb Smirnoff 			    offsetof(struct tcphdr, th_sum);
4213b3a8eb9SGleb Smirnoff 			break;
4223b3a8eb9SGleb Smirnoff 		case IPPROTO_UDP:
4233b3a8eb9SGleb Smirnoff 			uh = (struct udphdr *)(ip + 1);
4243b3a8eb9SGleb Smirnoff 			uh->uh_sum = cksum;
4253b3a8eb9SGleb Smirnoff 			mcl->m_pkthdr.csum_data =
4263b3a8eb9SGleb Smirnoff 			    offsetof(struct udphdr, uh_sum);
4273b3a8eb9SGleb Smirnoff 			break;
4283b3a8eb9SGleb Smirnoff 		}
4293b3a8eb9SGleb Smirnoff 		/* No hw checksum offloading: do it ourselves */
4303b3a8eb9SGleb Smirnoff 		if ((mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA) == 0) {
4313b3a8eb9SGleb Smirnoff 			in_delayed_cksum(mcl);
4323b3a8eb9SGleb Smirnoff 			mcl->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
4333b3a8eb9SGleb Smirnoff 		}
4343b3a8eb9SGleb Smirnoff 	}
4353b3a8eb9SGleb Smirnoff 	args->m = mcl;
4363b3a8eb9SGleb Smirnoff 	return (IP_FW_NAT);
4373b3a8eb9SGleb Smirnoff }
4383b3a8eb9SGleb Smirnoff 
4393b3a8eb9SGleb Smirnoff static struct cfg_nat *
4403b3a8eb9SGleb Smirnoff lookup_nat(struct nat_list *l, int nat_id)
4413b3a8eb9SGleb Smirnoff {
4423b3a8eb9SGleb Smirnoff 	struct cfg_nat *res;
4433b3a8eb9SGleb Smirnoff 
4443b3a8eb9SGleb Smirnoff 	LIST_FOREACH(res, l, _next) {
4453b3a8eb9SGleb Smirnoff 		if (res->id == nat_id)
4463b3a8eb9SGleb Smirnoff 			break;
4473b3a8eb9SGleb Smirnoff 	}
4483b3a8eb9SGleb Smirnoff 	return res;
4493b3a8eb9SGleb Smirnoff }
4503b3a8eb9SGleb Smirnoff 
451d6164b77SAlexander V. Chernikov static struct cfg_nat *
452d6164b77SAlexander V. Chernikov lookup_nat_name(struct nat_list *l, char *name)
4533b3a8eb9SGleb Smirnoff {
454d6164b77SAlexander V. Chernikov 	struct cfg_nat *res;
455d6164b77SAlexander V. Chernikov 	int id;
456d6164b77SAlexander V. Chernikov 	char *errptr;
4573b3a8eb9SGleb Smirnoff 
458d6164b77SAlexander V. Chernikov 	id = strtol(name, &errptr, 10);
459d6164b77SAlexander V. Chernikov 	if (id == 0 || *errptr != '\0')
460d6164b77SAlexander V. Chernikov 		return (NULL);
4613b3a8eb9SGleb Smirnoff 
462d6164b77SAlexander V. Chernikov 	LIST_FOREACH(res, l, _next) {
463d6164b77SAlexander V. Chernikov 		if (res->id == id)
464d6164b77SAlexander V. Chernikov 			break;
4653b3a8eb9SGleb Smirnoff 	}
466d6164b77SAlexander V. Chernikov 	return (res);
467d6164b77SAlexander V. Chernikov }
468d6164b77SAlexander V. Chernikov 
469d6164b77SAlexander V. Chernikov /* IP_FW3 configuration routines */
470d6164b77SAlexander V. Chernikov 
471d6164b77SAlexander V. Chernikov static void
472d6164b77SAlexander V. Chernikov nat44_config(struct ip_fw_chain *chain, struct nat44_cfg_nat *ucfg)
473d6164b77SAlexander V. Chernikov {
474d6164b77SAlexander V. Chernikov 	struct cfg_nat *ptr, *tcfg;
475d6164b77SAlexander V. Chernikov 	int gencnt;
4763b3a8eb9SGleb Smirnoff 
4773b3a8eb9SGleb Smirnoff 	/*
4783b3a8eb9SGleb Smirnoff 	 * Find/create nat rule.
4793b3a8eb9SGleb Smirnoff 	 */
480d6164b77SAlexander V. Chernikov 	IPFW_UH_WLOCK(chain);
4813b3a8eb9SGleb Smirnoff 	gencnt = chain->gencnt;
482d6164b77SAlexander V. Chernikov 	ptr = lookup_nat_name(&chain->nat, ucfg->name);
4833b3a8eb9SGleb Smirnoff 	if (ptr == NULL) {
484d6164b77SAlexander V. Chernikov 		IPFW_UH_WUNLOCK(chain);
4853b3a8eb9SGleb Smirnoff 		/* New rule: allocate and init new instance. */
4863b3a8eb9SGleb Smirnoff 		ptr = malloc(sizeof(struct cfg_nat), M_IPFW, M_WAITOK | M_ZERO);
4873b3a8eb9SGleb Smirnoff 		ptr->lib = LibAliasInit(NULL);
4883b3a8eb9SGleb Smirnoff 		LIST_INIT(&ptr->redir_chain);
4893b3a8eb9SGleb Smirnoff 	} else {
4903b3a8eb9SGleb Smirnoff 		/* Entry already present: temporarily unhook it. */
491d6164b77SAlexander V. Chernikov 		IPFW_WLOCK(chain);
4923b3a8eb9SGleb Smirnoff 		LIST_REMOVE(ptr, _next);
493d6164b77SAlexander V. Chernikov 		flush_nat_ptrs(chain, ptr->id);
4943b3a8eb9SGleb Smirnoff 		IPFW_WUNLOCK(chain);
495d6164b77SAlexander V. Chernikov 		IPFW_UH_WUNLOCK(chain);
4963b3a8eb9SGleb Smirnoff 	}
4973b3a8eb9SGleb Smirnoff 
4983b3a8eb9SGleb Smirnoff 	/*
499d6164b77SAlexander V. Chernikov 	 * Basic nat (re)configuration.
5003b3a8eb9SGleb Smirnoff 	 */
501d6164b77SAlexander V. Chernikov 	ptr->id = strtol(ucfg->name, NULL, 10);
5023b3a8eb9SGleb Smirnoff 	/*
5033b3a8eb9SGleb Smirnoff 	 * XXX - what if this rule doesn't nat any ip and just
5043b3a8eb9SGleb Smirnoff 	 * redirect?
5053b3a8eb9SGleb Smirnoff 	 * do we set aliasaddress to 0.0.0.0?
5063b3a8eb9SGleb Smirnoff 	 */
507d6164b77SAlexander V. Chernikov 	ptr->ip = ucfg->ip;
508d6164b77SAlexander V. Chernikov 	ptr->redir_cnt = ucfg->redir_cnt;
509d6164b77SAlexander V. Chernikov 	ptr->mode = ucfg->mode;
510d6164b77SAlexander V. Chernikov 	strlcpy(ptr->if_name, ucfg->if_name, sizeof(ptr->if_name));
511d6164b77SAlexander V. Chernikov 	LibAliasSetMode(ptr->lib, ptr->mode, ~0);
5123b3a8eb9SGleb Smirnoff 	LibAliasSetAddress(ptr->lib, ptr->ip);
5133b3a8eb9SGleb Smirnoff 
5143b3a8eb9SGleb Smirnoff 	/*
5153b3a8eb9SGleb Smirnoff 	 * Redir and LSNAT configuration.
5163b3a8eb9SGleb Smirnoff 	 */
5173b3a8eb9SGleb Smirnoff 	/* Delete old cfgs. */
5183b3a8eb9SGleb Smirnoff 	del_redir_spool_cfg(ptr, &ptr->redir_chain);
5193b3a8eb9SGleb Smirnoff 	/* Add new entries. */
520d6164b77SAlexander V. Chernikov 	add_redir_spool_cfg((char *)(ucfg + 1), ptr);
521d6164b77SAlexander V. Chernikov 	IPFW_UH_WLOCK(chain);
5223b3a8eb9SGleb Smirnoff 
5233b3a8eb9SGleb Smirnoff 	/* Extra check to avoid race with another ipfw_nat_cfg() */
524d6164b77SAlexander V. Chernikov 	tcfg = NULL;
525d6164b77SAlexander V. Chernikov 	if (gencnt != chain->gencnt)
526d6164b77SAlexander V. Chernikov 	    tcfg = lookup_nat_name(&chain->nat, ucfg->name);
527d6164b77SAlexander V. Chernikov 	IPFW_WLOCK(chain);
528d6164b77SAlexander V. Chernikov 	if (tcfg != NULL)
529d6164b77SAlexander V. Chernikov 		LIST_REMOVE(tcfg, _next);
5303b3a8eb9SGleb Smirnoff 	LIST_INSERT_HEAD(&chain->nat, ptr, _next);
5313b3a8eb9SGleb Smirnoff 	IPFW_WUNLOCK(chain);
532d6164b77SAlexander V. Chernikov 	chain->gencnt++;
533d6164b77SAlexander V. Chernikov 
534d6164b77SAlexander V. Chernikov 	IPFW_UH_WUNLOCK(chain);
535d6164b77SAlexander V. Chernikov 
536d6164b77SAlexander V. Chernikov 	if (tcfg != NULL)
537d6164b77SAlexander V. Chernikov 		free(tcfg, M_IPFW);
538d6164b77SAlexander V. Chernikov }
539d6164b77SAlexander V. Chernikov 
540d6164b77SAlexander V. Chernikov /*
541d6164b77SAlexander V. Chernikov  * Creates/configure nat44 instance
542d6164b77SAlexander V. Chernikov  * Data layout (v0)(current):
543d6164b77SAlexander V. Chernikov  * Request: [ ipfw_obj_header nat44_cfg_nat .. ]
544d6164b77SAlexander V. Chernikov  *
545d6164b77SAlexander V. Chernikov  * Returns 0 on success
546d6164b77SAlexander V. Chernikov  */
547d6164b77SAlexander V. Chernikov static int
548d6164b77SAlexander V. Chernikov nat44_cfg(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
549d6164b77SAlexander V. Chernikov     struct sockopt_data *sd)
550d6164b77SAlexander V. Chernikov {
551d6164b77SAlexander V. Chernikov 	ipfw_obj_header *oh;
552d6164b77SAlexander V. Chernikov 	struct nat44_cfg_nat *ucfg;
553d6164b77SAlexander V. Chernikov 	int id;
554d6164b77SAlexander V. Chernikov 	size_t read;
555d6164b77SAlexander V. Chernikov 	char *errptr;
556d6164b77SAlexander V. Chernikov 
557d6164b77SAlexander V. Chernikov 	/* Check minimum header size */
558d6164b77SAlexander V. Chernikov 	if (sd->valsize < (sizeof(*oh) + sizeof(*ucfg)))
559d6164b77SAlexander V. Chernikov 		return (EINVAL);
560d6164b77SAlexander V. Chernikov 
561d6164b77SAlexander V. Chernikov 	oh = (ipfw_obj_header *)sd->kbuf;
562d6164b77SAlexander V. Chernikov 
563d6164b77SAlexander V. Chernikov 	/* Basic length checks for TLVs */
564d6164b77SAlexander V. Chernikov 	if (oh->ntlv.head.length != sizeof(oh->ntlv))
565d6164b77SAlexander V. Chernikov 		return (EINVAL);
566d6164b77SAlexander V. Chernikov 
567d6164b77SAlexander V. Chernikov 	ucfg = (struct nat44_cfg_nat *)(oh + 1);
568d6164b77SAlexander V. Chernikov 
569d6164b77SAlexander V. Chernikov 	/* Check if name is properly terminated and looks like number */
570d6164b77SAlexander V. Chernikov 	if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
571d6164b77SAlexander V. Chernikov 		return (EINVAL);
572d6164b77SAlexander V. Chernikov 	id = strtol(ucfg->name, &errptr, 10);
573d6164b77SAlexander V. Chernikov 	if (id == 0 || *errptr != '\0')
574d6164b77SAlexander V. Chernikov 		return (EINVAL);
575d6164b77SAlexander V. Chernikov 
576d6164b77SAlexander V. Chernikov 	read = sizeof(*oh) + sizeof(*ucfg);
577d6164b77SAlexander V. Chernikov 	/* Check number of redirs */
578d6164b77SAlexander V. Chernikov 	if (sd->valsize < read + ucfg->redir_cnt*sizeof(struct nat44_cfg_redir))
579d6164b77SAlexander V. Chernikov 		return (EINVAL);
580d6164b77SAlexander V. Chernikov 
581d6164b77SAlexander V. Chernikov 	nat44_config(chain, ucfg);
582d6164b77SAlexander V. Chernikov 	return (0);
583d6164b77SAlexander V. Chernikov }
584d6164b77SAlexander V. Chernikov 
585d6164b77SAlexander V. Chernikov /*
586d6164b77SAlexander V. Chernikov  * Destroys given nat instances.
587d6164b77SAlexander V. Chernikov  * Data layout (v0)(current):
588d6164b77SAlexander V. Chernikov  * Request: [ ipfw_obj_header ]
589d6164b77SAlexander V. Chernikov  *
590d6164b77SAlexander V. Chernikov  * Returns 0 on success
591d6164b77SAlexander V. Chernikov  */
592d6164b77SAlexander V. Chernikov static int
593d6164b77SAlexander V. Chernikov nat44_destroy(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
594d6164b77SAlexander V. Chernikov     struct sockopt_data *sd)
595d6164b77SAlexander V. Chernikov {
596d6164b77SAlexander V. Chernikov 	ipfw_obj_header *oh;
597d6164b77SAlexander V. Chernikov 	struct cfg_nat *ptr;
598d6164b77SAlexander V. Chernikov 	ipfw_obj_ntlv *ntlv;
599d6164b77SAlexander V. Chernikov 
600d6164b77SAlexander V. Chernikov 	/* Check minimum header size */
601d6164b77SAlexander V. Chernikov 	if (sd->valsize < sizeof(*oh))
602d6164b77SAlexander V. Chernikov 		return (EINVAL);
603d6164b77SAlexander V. Chernikov 
604d6164b77SAlexander V. Chernikov 	oh = (ipfw_obj_header *)sd->kbuf;
605d6164b77SAlexander V. Chernikov 
606d6164b77SAlexander V. Chernikov 	/* Basic length checks for TLVs */
607d6164b77SAlexander V. Chernikov 	if (oh->ntlv.head.length != sizeof(oh->ntlv))
608d6164b77SAlexander V. Chernikov 		return (EINVAL);
609d6164b77SAlexander V. Chernikov 
610d6164b77SAlexander V. Chernikov 	ntlv = &oh->ntlv;
611d6164b77SAlexander V. Chernikov 	/* Check if name is properly terminated */
612d6164b77SAlexander V. Chernikov 	if (strnlen(ntlv->name, sizeof(ntlv->name)) == sizeof(ntlv->name))
613d6164b77SAlexander V. Chernikov 		return (EINVAL);
614d6164b77SAlexander V. Chernikov 
615d6164b77SAlexander V. Chernikov 	IPFW_UH_WLOCK(chain);
616d6164b77SAlexander V. Chernikov 	ptr = lookup_nat_name(&chain->nat, ntlv->name);
617d6164b77SAlexander V. Chernikov 	if (ptr == NULL) {
618d6164b77SAlexander V. Chernikov 		IPFW_UH_WUNLOCK(chain);
619d6164b77SAlexander V. Chernikov 		return (ESRCH);
620d6164b77SAlexander V. Chernikov 	}
621d6164b77SAlexander V. Chernikov 	IPFW_WLOCK(chain);
622d6164b77SAlexander V. Chernikov 	LIST_REMOVE(ptr, _next);
623d6164b77SAlexander V. Chernikov 	flush_nat_ptrs(chain, ptr->id);
624d6164b77SAlexander V. Chernikov 	IPFW_WUNLOCK(chain);
625d6164b77SAlexander V. Chernikov 	IPFW_UH_WUNLOCK(chain);
626d6164b77SAlexander V. Chernikov 
627d6164b77SAlexander V. Chernikov 	del_redir_spool_cfg(ptr, &ptr->redir_chain);
628d6164b77SAlexander V. Chernikov 	LibAliasUninit(ptr->lib);
629d6164b77SAlexander V. Chernikov 	free(ptr, M_IPFW);
630d6164b77SAlexander V. Chernikov 
631d6164b77SAlexander V. Chernikov 	return (0);
632d6164b77SAlexander V. Chernikov }
633d6164b77SAlexander V. Chernikov 
634d6164b77SAlexander V. Chernikov static void
635d6164b77SAlexander V. Chernikov export_nat_cfg(struct cfg_nat *ptr, struct nat44_cfg_nat *ucfg)
636d6164b77SAlexander V. Chernikov {
637d6164b77SAlexander V. Chernikov 
638d6164b77SAlexander V. Chernikov 	snprintf(ucfg->name, sizeof(ucfg->name), "%d", ptr->id);
639d6164b77SAlexander V. Chernikov 	ucfg->ip = ptr->ip;
640d6164b77SAlexander V. Chernikov 	ucfg->redir_cnt = ptr->redir_cnt;
641d6164b77SAlexander V. Chernikov 	ucfg->mode = ptr->mode;
642d6164b77SAlexander V. Chernikov 	strlcpy(ucfg->if_name, ptr->if_name, sizeof(ucfg->if_name));
643d6164b77SAlexander V. Chernikov }
644d6164b77SAlexander V. Chernikov 
645d6164b77SAlexander V. Chernikov /*
646d6164b77SAlexander V. Chernikov  * Gets config for given nat instance
647d6164b77SAlexander V. Chernikov  * Data layout (v0)(current):
648d6164b77SAlexander V. Chernikov  * Request: [ ipfw_obj_header nat44_cfg_nat .. ]
649d6164b77SAlexander V. Chernikov  *
650d6164b77SAlexander V. Chernikov  * Returns 0 on success
651d6164b77SAlexander V. Chernikov  */
652d6164b77SAlexander V. Chernikov static int
653d6164b77SAlexander V. Chernikov nat44_get_cfg(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
654d6164b77SAlexander V. Chernikov     struct sockopt_data *sd)
655d6164b77SAlexander V. Chernikov {
656d6164b77SAlexander V. Chernikov 	ipfw_obj_header *oh;
657d6164b77SAlexander V. Chernikov 	struct nat44_cfg_nat *ucfg;
658d6164b77SAlexander V. Chernikov 	struct cfg_nat *ptr;
659d6164b77SAlexander V. Chernikov 	struct cfg_redir *r;
660d6164b77SAlexander V. Chernikov 	struct cfg_spool *s;
661d6164b77SAlexander V. Chernikov 	struct nat44_cfg_redir *ser_r;
662d6164b77SAlexander V. Chernikov 	struct nat44_cfg_spool *ser_s;
663d6164b77SAlexander V. Chernikov 	size_t sz;
664d6164b77SAlexander V. Chernikov 
665d6164b77SAlexander V. Chernikov 	sz = sizeof(*oh) + sizeof(*ucfg);
666d6164b77SAlexander V. Chernikov 	/* Check minimum header size */
667d6164b77SAlexander V. Chernikov 	if (sd->valsize < sz)
668d6164b77SAlexander V. Chernikov 		return (EINVAL);
669d6164b77SAlexander V. Chernikov 
670d6164b77SAlexander V. Chernikov 	oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
671d6164b77SAlexander V. Chernikov 
672d6164b77SAlexander V. Chernikov 	/* Basic length checks for TLVs */
673d6164b77SAlexander V. Chernikov 	if (oh->ntlv.head.length != sizeof(oh->ntlv))
674d6164b77SAlexander V. Chernikov 		return (EINVAL);
675d6164b77SAlexander V. Chernikov 
676d6164b77SAlexander V. Chernikov 	ucfg = (struct nat44_cfg_nat *)(oh + 1);
677d6164b77SAlexander V. Chernikov 
678d6164b77SAlexander V. Chernikov 	/* Check if name is properly terminated */
679d6164b77SAlexander V. Chernikov 	if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
680d6164b77SAlexander V. Chernikov 		return (EINVAL);
681d6164b77SAlexander V. Chernikov 
682d6164b77SAlexander V. Chernikov 	IPFW_UH_RLOCK(chain);
683d6164b77SAlexander V. Chernikov 	ptr = lookup_nat_name(&chain->nat, ucfg->name);
684d6164b77SAlexander V. Chernikov 	if (ptr == NULL) {
685d6164b77SAlexander V. Chernikov 		IPFW_UH_RUNLOCK(chain);
686d6164b77SAlexander V. Chernikov 		return (ESRCH);
687d6164b77SAlexander V. Chernikov 	}
688d6164b77SAlexander V. Chernikov 
689d6164b77SAlexander V. Chernikov 	export_nat_cfg(ptr, ucfg);
690d6164b77SAlexander V. Chernikov 
691d6164b77SAlexander V. Chernikov 	/* Estimate memory amount */
692d6164b77SAlexander V. Chernikov 	sz = sizeof(struct nat44_cfg_nat);
693d6164b77SAlexander V. Chernikov 	LIST_FOREACH(r, &ptr->redir_chain, _next) {
694d6164b77SAlexander V. Chernikov 		sz += sizeof(struct nat44_cfg_redir);
695d6164b77SAlexander V. Chernikov 		LIST_FOREACH(s, &r->spool_chain, _next)
696d6164b77SAlexander V. Chernikov 			sz += sizeof(struct nat44_cfg_spool);
697d6164b77SAlexander V. Chernikov 	}
698d6164b77SAlexander V. Chernikov 
699d6164b77SAlexander V. Chernikov 	ucfg->size = sz;
700d6164b77SAlexander V. Chernikov 	if (sd->valsize < sz + sizeof(*oh)) {
701d6164b77SAlexander V. Chernikov 
702d6164b77SAlexander V. Chernikov 		/*
703d6164b77SAlexander V. Chernikov 		 * Submitted buffer size is not enough.
704d6164b77SAlexander V. Chernikov 		 * WE've already filled in @ucfg structure with
705d6164b77SAlexander V. Chernikov 		 * relevant info including size, so we
706d6164b77SAlexander V. Chernikov 		 * can return. Buffer will be flushed automatically.
707d6164b77SAlexander V. Chernikov 		 */
708d6164b77SAlexander V. Chernikov 		IPFW_UH_RUNLOCK(chain);
709d6164b77SAlexander V. Chernikov 		return (ENOMEM);
710d6164b77SAlexander V. Chernikov 	}
711d6164b77SAlexander V. Chernikov 
712d6164b77SAlexander V. Chernikov 	/* Size OK, let's copy data */
713d6164b77SAlexander V. Chernikov 	LIST_FOREACH(r, &ptr->redir_chain, _next) {
714d6164b77SAlexander V. Chernikov 		ser_r = (struct nat44_cfg_redir *)ipfw_get_sopt_space(sd,
715d6164b77SAlexander V. Chernikov 		    sizeof(*ser_r));
716d6164b77SAlexander V. Chernikov 		ser_r->mode = r->mode;
717d6164b77SAlexander V. Chernikov 		ser_r->laddr = r->laddr;
718d6164b77SAlexander V. Chernikov 		ser_r->paddr = r->paddr;
719d6164b77SAlexander V. Chernikov 		ser_r->raddr = r->raddr;
720d6164b77SAlexander V. Chernikov 		ser_r->lport = r->lport;
721d6164b77SAlexander V. Chernikov 		ser_r->pport = r->pport;
722d6164b77SAlexander V. Chernikov 		ser_r->rport = r->rport;
723d6164b77SAlexander V. Chernikov 		ser_r->pport_cnt = r->pport_cnt;
724d6164b77SAlexander V. Chernikov 		ser_r->rport_cnt = r->rport_cnt;
725d6164b77SAlexander V. Chernikov 		ser_r->proto = r->proto;
726d6164b77SAlexander V. Chernikov 		ser_r->spool_cnt = r->spool_cnt;
727d6164b77SAlexander V. Chernikov 
728d6164b77SAlexander V. Chernikov 		LIST_FOREACH(s, &r->spool_chain, _next) {
729d6164b77SAlexander V. Chernikov 			ser_s = (struct nat44_cfg_spool *)ipfw_get_sopt_space(
730d6164b77SAlexander V. Chernikov 			    sd, sizeof(*ser_s));
731d6164b77SAlexander V. Chernikov 
732d6164b77SAlexander V. Chernikov 			ser_s->addr = s->addr;
733d6164b77SAlexander V. Chernikov 			ser_s->port = s->port;
734d6164b77SAlexander V. Chernikov 		}
735d6164b77SAlexander V. Chernikov 	}
736d6164b77SAlexander V. Chernikov 
737d6164b77SAlexander V. Chernikov 	IPFW_UH_RUNLOCK(chain);
738d6164b77SAlexander V. Chernikov 
739d6164b77SAlexander V. Chernikov 	return (0);
740d6164b77SAlexander V. Chernikov }
741d6164b77SAlexander V. Chernikov 
742d6164b77SAlexander V. Chernikov /*
743d6164b77SAlexander V. Chernikov  * Lists all nat44 instances currently available in kernel.
744d6164b77SAlexander V. Chernikov  * Data layout (v0)(current):
745d6164b77SAlexander V. Chernikov  * Request: [ ipfw_obj_lheader ]
746d6164b77SAlexander V. Chernikov  * Reply: [ ipfw_obj_lheader nat44_cfg_nat x N ]
747d6164b77SAlexander V. Chernikov  *
748d6164b77SAlexander V. Chernikov  * Returns 0 on success
749d6164b77SAlexander V. Chernikov  */
750d6164b77SAlexander V. Chernikov static int
751d6164b77SAlexander V. Chernikov nat44_list_nat(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
752d6164b77SAlexander V. Chernikov     struct sockopt_data *sd)
753d6164b77SAlexander V. Chernikov {
754d6164b77SAlexander V. Chernikov 	ipfw_obj_lheader *olh;
755d6164b77SAlexander V. Chernikov 	struct nat44_cfg_nat *ucfg;
756d6164b77SAlexander V. Chernikov 	struct cfg_nat *ptr;
757d6164b77SAlexander V. Chernikov 	int nat_count;
758d6164b77SAlexander V. Chernikov 
759d6164b77SAlexander V. Chernikov 	/* Check minimum header size */
760d6164b77SAlexander V. Chernikov 	if (sd->valsize < sizeof(ipfw_obj_lheader))
761d6164b77SAlexander V. Chernikov 		return (EINVAL);
762d6164b77SAlexander V. Chernikov 
763d6164b77SAlexander V. Chernikov 	olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh));
764d6164b77SAlexander V. Chernikov 	IPFW_UH_RLOCK(chain);
765d6164b77SAlexander V. Chernikov 	nat_count = 0;
766d6164b77SAlexander V. Chernikov 	LIST_FOREACH(ptr, &chain->nat, _next)
767d6164b77SAlexander V. Chernikov 		nat_count++;
768d6164b77SAlexander V. Chernikov 
769d6164b77SAlexander V. Chernikov 	olh->count = nat_count;
770d6164b77SAlexander V. Chernikov 	olh->objsize = sizeof(struct nat44_cfg_nat);
771d6164b77SAlexander V. Chernikov 	olh->size = sizeof(*olh) + olh->count * olh->objsize;
772d6164b77SAlexander V. Chernikov 
773d6164b77SAlexander V. Chernikov 	if (sd->valsize < olh->size) {
774d6164b77SAlexander V. Chernikov 		IPFW_UH_RUNLOCK(chain);
775d6164b77SAlexander V. Chernikov 		return (ENOMEM);
776d6164b77SAlexander V. Chernikov 	}
777d6164b77SAlexander V. Chernikov 
778d6164b77SAlexander V. Chernikov 	LIST_FOREACH(ptr, &chain->nat, _next) {
779d6164b77SAlexander V. Chernikov 		ucfg = (struct nat44_cfg_nat *)ipfw_get_sopt_space(sd,
780d6164b77SAlexander V. Chernikov 		    sizeof(*ucfg));
781d6164b77SAlexander V. Chernikov 		export_nat_cfg(ptr, ucfg);
782d6164b77SAlexander V. Chernikov 	}
783d6164b77SAlexander V. Chernikov 
784d6164b77SAlexander V. Chernikov 	IPFW_UH_RUNLOCK(chain);
785d6164b77SAlexander V. Chernikov 
786d6164b77SAlexander V. Chernikov 	return (0);
787d6164b77SAlexander V. Chernikov }
788d6164b77SAlexander V. Chernikov 
789d6164b77SAlexander V. Chernikov /*
790d6164b77SAlexander V. Chernikov  * Gets log for given nat instance
791d6164b77SAlexander V. Chernikov  * Data layout (v0)(current):
792d6164b77SAlexander V. Chernikov  * Request: [ ipfw_obj_header nat44_cfg_nat ]
793d6164b77SAlexander V. Chernikov  * Reply: [ ipfw_obj_header nat44_cfg_nat LOGBUFFER ]
794d6164b77SAlexander V. Chernikov  *
795d6164b77SAlexander V. Chernikov  * Returns 0 on success
796d6164b77SAlexander V. Chernikov  */
797d6164b77SAlexander V. Chernikov static int
798d6164b77SAlexander V. Chernikov nat44_get_log(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
799d6164b77SAlexander V. Chernikov     struct sockopt_data *sd)
800d6164b77SAlexander V. Chernikov {
801d6164b77SAlexander V. Chernikov 	ipfw_obj_header *oh;
802d6164b77SAlexander V. Chernikov 	struct nat44_cfg_nat *ucfg;
803d6164b77SAlexander V. Chernikov 	struct cfg_nat *ptr;
804d6164b77SAlexander V. Chernikov 	void *pbuf;
805d6164b77SAlexander V. Chernikov 	size_t sz;
806d6164b77SAlexander V. Chernikov 
807d6164b77SAlexander V. Chernikov 	sz = sizeof(*oh) + sizeof(*ucfg);
808d6164b77SAlexander V. Chernikov 	/* Check minimum header size */
809d6164b77SAlexander V. Chernikov 	if (sd->valsize < sz)
810d6164b77SAlexander V. Chernikov 		return (EINVAL);
811d6164b77SAlexander V. Chernikov 
812d6164b77SAlexander V. Chernikov 	oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
813d6164b77SAlexander V. Chernikov 
814d6164b77SAlexander V. Chernikov 	/* Basic length checks for TLVs */
815d6164b77SAlexander V. Chernikov 	if (oh->ntlv.head.length != sizeof(oh->ntlv))
816d6164b77SAlexander V. Chernikov 		return (EINVAL);
817d6164b77SAlexander V. Chernikov 
818d6164b77SAlexander V. Chernikov 	ucfg = (struct nat44_cfg_nat *)(oh + 1);
819d6164b77SAlexander V. Chernikov 
820d6164b77SAlexander V. Chernikov 	/* Check if name is properly terminated */
821d6164b77SAlexander V. Chernikov 	if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
822d6164b77SAlexander V. Chernikov 		return (EINVAL);
823d6164b77SAlexander V. Chernikov 
824d6164b77SAlexander V. Chernikov 	IPFW_UH_RLOCK(chain);
825d6164b77SAlexander V. Chernikov 	ptr = lookup_nat_name(&chain->nat, ucfg->name);
826d6164b77SAlexander V. Chernikov 	if (ptr == NULL) {
827d6164b77SAlexander V. Chernikov 		IPFW_UH_RUNLOCK(chain);
828d6164b77SAlexander V. Chernikov 		return (ESRCH);
829d6164b77SAlexander V. Chernikov 	}
830d6164b77SAlexander V. Chernikov 
831d6164b77SAlexander V. Chernikov 	if (ptr->lib->logDesc == NULL) {
832d6164b77SAlexander V. Chernikov 		IPFW_UH_RUNLOCK(chain);
833d6164b77SAlexander V. Chernikov 		return (ENOENT);
834d6164b77SAlexander V. Chernikov 	}
835d6164b77SAlexander V. Chernikov 
836d6164b77SAlexander V. Chernikov 	export_nat_cfg(ptr, ucfg);
837d6164b77SAlexander V. Chernikov 
838d6164b77SAlexander V. Chernikov 	/* Estimate memory amount */
839d6164b77SAlexander V. Chernikov 	ucfg->size = sizeof(struct nat44_cfg_nat) + LIBALIAS_BUF_SIZE;
840d6164b77SAlexander V. Chernikov 	if (sd->valsize < sz + sizeof(*oh)) {
841d6164b77SAlexander V. Chernikov 
842d6164b77SAlexander V. Chernikov 		/*
843d6164b77SAlexander V. Chernikov 		 * Submitted buffer size is not enough.
844d6164b77SAlexander V. Chernikov 		 * WE've already filled in @ucfg structure with
845d6164b77SAlexander V. Chernikov 		 * relevant info including size, so we
846d6164b77SAlexander V. Chernikov 		 * can return. Buffer will be flushed automatically.
847d6164b77SAlexander V. Chernikov 		 */
848d6164b77SAlexander V. Chernikov 		IPFW_UH_RUNLOCK(chain);
849d6164b77SAlexander V. Chernikov 		return (ENOMEM);
850d6164b77SAlexander V. Chernikov 	}
851d6164b77SAlexander V. Chernikov 
852d6164b77SAlexander V. Chernikov 	pbuf = (void *)ipfw_get_sopt_space(sd, LIBALIAS_BUF_SIZE);
853d6164b77SAlexander V. Chernikov 	memcpy(pbuf, ptr->lib->logDesc, LIBALIAS_BUF_SIZE);
854d6164b77SAlexander V. Chernikov 
855d6164b77SAlexander V. Chernikov 	IPFW_UH_RUNLOCK(chain);
856d6164b77SAlexander V. Chernikov 
857d6164b77SAlexander V. Chernikov 	return (0);
858d6164b77SAlexander V. Chernikov }
859d6164b77SAlexander V. Chernikov 
860d6164b77SAlexander V. Chernikov static struct ipfw_sopt_handler	scodes[] = {
861d6164b77SAlexander V. Chernikov 	{ IP_FW_NAT44_XCONFIG,	0,	HDIR_SET,	nat44_cfg },
862d6164b77SAlexander V. Chernikov 	{ IP_FW_NAT44_DESTROY,	0,	HDIR_SET,	nat44_destroy },
863d6164b77SAlexander V. Chernikov 	{ IP_FW_NAT44_XGETCONFIG,	0,	HDIR_GET,	nat44_get_cfg },
864d6164b77SAlexander V. Chernikov 	{ IP_FW_NAT44_LIST_NAT,	0,	HDIR_GET,	nat44_list_nat },
865d6164b77SAlexander V. Chernikov 	{ IP_FW_NAT44_XGETLOG,	0,	HDIR_GET,	nat44_get_log },
866d6164b77SAlexander V. Chernikov };
867d6164b77SAlexander V. Chernikov 
868d6164b77SAlexander V. Chernikov 
869d6164b77SAlexander V. Chernikov /*
870d6164b77SAlexander V. Chernikov  * Legacy configuration routines
871d6164b77SAlexander V. Chernikov  */
872d6164b77SAlexander V. Chernikov 
873d6164b77SAlexander V. Chernikov struct cfg_spool_legacy {
874d6164b77SAlexander V. Chernikov 	LIST_ENTRY(cfg_spool_legacy)	_next;
875d6164b77SAlexander V. Chernikov 	struct in_addr			addr;
876d6164b77SAlexander V. Chernikov 	u_short				port;
877d6164b77SAlexander V. Chernikov };
878d6164b77SAlexander V. Chernikov 
879d6164b77SAlexander V. Chernikov struct cfg_redir_legacy {
880d6164b77SAlexander V. Chernikov 	LIST_ENTRY(cfg_redir)   _next;
881d6164b77SAlexander V. Chernikov 	u_int16_t               mode;
882d6164b77SAlexander V. Chernikov 	struct in_addr	        laddr;
883d6164b77SAlexander V. Chernikov 	struct in_addr	        paddr;
884d6164b77SAlexander V. Chernikov 	struct in_addr	        raddr;
885d6164b77SAlexander V. Chernikov 	u_short                 lport;
886d6164b77SAlexander V. Chernikov 	u_short                 pport;
887d6164b77SAlexander V. Chernikov 	u_short                 rport;
888d6164b77SAlexander V. Chernikov 	u_short                 pport_cnt;
889d6164b77SAlexander V. Chernikov 	u_short                 rport_cnt;
890d6164b77SAlexander V. Chernikov 	int                     proto;
891d6164b77SAlexander V. Chernikov 	struct alias_link       **alink;
892d6164b77SAlexander V. Chernikov 	u_int16_t               spool_cnt;
893d6164b77SAlexander V. Chernikov 	LIST_HEAD(, cfg_spool_legacy) spool_chain;
894d6164b77SAlexander V. Chernikov };
895d6164b77SAlexander V. Chernikov 
896d6164b77SAlexander V. Chernikov struct cfg_nat_legacy {
897d6164b77SAlexander V. Chernikov 	LIST_ENTRY(cfg_nat_legacy)	_next;
898d6164b77SAlexander V. Chernikov 	int				id;
899d6164b77SAlexander V. Chernikov 	struct in_addr			ip;
900d6164b77SAlexander V. Chernikov 	char				if_name[IF_NAMESIZE];
901d6164b77SAlexander V. Chernikov 	int				mode;
902d6164b77SAlexander V. Chernikov 	struct libalias			*lib;
903d6164b77SAlexander V. Chernikov 	int				redir_cnt;
904d6164b77SAlexander V. Chernikov 	LIST_HEAD(, cfg_redir_legacy)	redir_chain;
905d6164b77SAlexander V. Chernikov };
906d6164b77SAlexander V. Chernikov 
907d6164b77SAlexander V. Chernikov static int
908d6164b77SAlexander V. Chernikov ipfw_nat_cfg(struct sockopt *sopt)
909d6164b77SAlexander V. Chernikov {
910d6164b77SAlexander V. Chernikov 	struct cfg_nat_legacy *cfg;
911d6164b77SAlexander V. Chernikov 	struct nat44_cfg_nat *ucfg;
912d6164b77SAlexander V. Chernikov 	struct cfg_redir_legacy *rdir;
913d6164b77SAlexander V. Chernikov 	struct nat44_cfg_redir *urdir;
914d6164b77SAlexander V. Chernikov 	char *buf;
915d6164b77SAlexander V. Chernikov 	size_t len, len2;
916d6164b77SAlexander V. Chernikov 	int error, i;
917d6164b77SAlexander V. Chernikov 
918d6164b77SAlexander V. Chernikov 	len = sopt->sopt_valsize;
919d6164b77SAlexander V. Chernikov 	len2 = len + 128;
920d6164b77SAlexander V. Chernikov 
921d6164b77SAlexander V. Chernikov 	/*
922d6164b77SAlexander V. Chernikov 	 * Allocate 2x buffer to store converted structures.
923d6164b77SAlexander V. Chernikov 	 * new redir_cfg has shrinked, so we're sure that
924d6164b77SAlexander V. Chernikov 	 * new buffer size is enough.
925d6164b77SAlexander V. Chernikov 	 */
926d6164b77SAlexander V. Chernikov 	buf = malloc(roundup2(len, 8) + len2, M_TEMP, M_WAITOK | M_ZERO);
927d6164b77SAlexander V. Chernikov 	error = sooptcopyin(sopt, buf, len, sizeof(struct cfg_nat_legacy));
928d6164b77SAlexander V. Chernikov 	if (error != 0)
929d6164b77SAlexander V. Chernikov 		goto out;
930d6164b77SAlexander V. Chernikov 
931d6164b77SAlexander V. Chernikov 	cfg = (struct cfg_nat_legacy *)buf;
932d6164b77SAlexander V. Chernikov 	if (cfg->id < 0) {
933d6164b77SAlexander V. Chernikov 		error = EINVAL;
934d6164b77SAlexander V. Chernikov 		goto out;
935d6164b77SAlexander V. Chernikov 	}
936d6164b77SAlexander V. Chernikov 
937d6164b77SAlexander V. Chernikov 	ucfg = (struct nat44_cfg_nat *)&buf[roundup2(len, 8)];
938d6164b77SAlexander V. Chernikov 	snprintf(ucfg->name, sizeof(ucfg->name), "%d", cfg->id);
939d6164b77SAlexander V. Chernikov 	strlcpy(ucfg->if_name, cfg->if_name, sizeof(ucfg->if_name));
940d6164b77SAlexander V. Chernikov 	ucfg->ip = cfg->ip;
941d6164b77SAlexander V. Chernikov 	ucfg->mode = cfg->mode;
942d6164b77SAlexander V. Chernikov 	ucfg->redir_cnt = cfg->redir_cnt;
943d6164b77SAlexander V. Chernikov 
944d6164b77SAlexander V. Chernikov 	if (len < sizeof(*cfg) + cfg->redir_cnt * sizeof(*rdir)) {
945d6164b77SAlexander V. Chernikov 		error = EINVAL;
946d6164b77SAlexander V. Chernikov 		goto out;
947d6164b77SAlexander V. Chernikov 	}
948d6164b77SAlexander V. Chernikov 
949d6164b77SAlexander V. Chernikov 	urdir = (struct nat44_cfg_redir *)(ucfg + 1);
950d6164b77SAlexander V. Chernikov 	rdir = (struct cfg_redir_legacy *)(cfg + 1);
951d6164b77SAlexander V. Chernikov 	for (i = 0; i < cfg->redir_cnt; i++) {
952d6164b77SAlexander V. Chernikov 		urdir->mode = rdir->mode;
953d6164b77SAlexander V. Chernikov 		urdir->laddr = rdir->laddr;
954d6164b77SAlexander V. Chernikov 		urdir->paddr = rdir->paddr;
955d6164b77SAlexander V. Chernikov 		urdir->raddr = rdir->raddr;
956d6164b77SAlexander V. Chernikov 		urdir->lport = rdir->lport;
957d6164b77SAlexander V. Chernikov 		urdir->pport = rdir->pport;
958d6164b77SAlexander V. Chernikov 		urdir->rport = rdir->rport;
959d6164b77SAlexander V. Chernikov 		urdir->pport_cnt = rdir->pport_cnt;
960d6164b77SAlexander V. Chernikov 		urdir->rport_cnt = rdir->rport_cnt;
961d6164b77SAlexander V. Chernikov 		urdir->proto = rdir->proto;
962d6164b77SAlexander V. Chernikov 		urdir->spool_cnt = rdir->spool_cnt;
963d6164b77SAlexander V. Chernikov 
964d6164b77SAlexander V. Chernikov 		urdir++;
965d6164b77SAlexander V. Chernikov 		rdir++;
966d6164b77SAlexander V. Chernikov 	}
967d6164b77SAlexander V. Chernikov 
968d6164b77SAlexander V. Chernikov 	nat44_config(&V_layer3_chain, ucfg);
9693b3a8eb9SGleb Smirnoff 
9703b3a8eb9SGleb Smirnoff out:
9713b3a8eb9SGleb Smirnoff 	free(buf, M_TEMP);
9723b3a8eb9SGleb Smirnoff 	return (error);
9733b3a8eb9SGleb Smirnoff }
9743b3a8eb9SGleb Smirnoff 
9753b3a8eb9SGleb Smirnoff static int
9763b3a8eb9SGleb Smirnoff ipfw_nat_del(struct sockopt *sopt)
9773b3a8eb9SGleb Smirnoff {
9783b3a8eb9SGleb Smirnoff 	struct cfg_nat *ptr;
9793b3a8eb9SGleb Smirnoff 	struct ip_fw_chain *chain = &V_layer3_chain;
9803b3a8eb9SGleb Smirnoff 	int i;
9813b3a8eb9SGleb Smirnoff 
9823b3a8eb9SGleb Smirnoff 	sooptcopyin(sopt, &i, sizeof i, sizeof i);
9833b3a8eb9SGleb Smirnoff 	/* XXX validate i */
984d6164b77SAlexander V. Chernikov 	IPFW_UH_WLOCK(chain);
9853b3a8eb9SGleb Smirnoff 	ptr = lookup_nat(&chain->nat, i);
9863b3a8eb9SGleb Smirnoff 	if (ptr == NULL) {
987d6164b77SAlexander V. Chernikov 		IPFW_UH_WUNLOCK(chain);
9883b3a8eb9SGleb Smirnoff 		return (EINVAL);
9893b3a8eb9SGleb Smirnoff 	}
990d6164b77SAlexander V. Chernikov 	IPFW_WLOCK(chain);
9913b3a8eb9SGleb Smirnoff 	LIST_REMOVE(ptr, _next);
9923b3a8eb9SGleb Smirnoff 	flush_nat_ptrs(chain, i);
9933b3a8eb9SGleb Smirnoff 	IPFW_WUNLOCK(chain);
994d6164b77SAlexander V. Chernikov 	IPFW_UH_WUNLOCK(chain);
9953b3a8eb9SGleb Smirnoff 	del_redir_spool_cfg(ptr, &ptr->redir_chain);
9963b3a8eb9SGleb Smirnoff 	LibAliasUninit(ptr->lib);
9973b3a8eb9SGleb Smirnoff 	free(ptr, M_IPFW);
9983b3a8eb9SGleb Smirnoff 	return (0);
9993b3a8eb9SGleb Smirnoff }
10003b3a8eb9SGleb Smirnoff 
10013b3a8eb9SGleb Smirnoff static int
10023b3a8eb9SGleb Smirnoff ipfw_nat_get_cfg(struct sockopt *sopt)
10033b3a8eb9SGleb Smirnoff {
10043b3a8eb9SGleb Smirnoff 	struct ip_fw_chain *chain = &V_layer3_chain;
10053b3a8eb9SGleb Smirnoff 	struct cfg_nat *n;
1006d6164b77SAlexander V. Chernikov 	struct cfg_nat_legacy *ucfg;
10073b3a8eb9SGleb Smirnoff 	struct cfg_redir *r;
10083b3a8eb9SGleb Smirnoff 	struct cfg_spool *s;
1009d6164b77SAlexander V. Chernikov 	struct cfg_redir_legacy *ser_r;
1010d6164b77SAlexander V. Chernikov 	struct cfg_spool_legacy *ser_s;
10113b3a8eb9SGleb Smirnoff 	char *data;
10123b3a8eb9SGleb Smirnoff 	int gencnt, nat_cnt, len, error;
10133b3a8eb9SGleb Smirnoff 
10143b3a8eb9SGleb Smirnoff 	nat_cnt = 0;
10153b3a8eb9SGleb Smirnoff 	len = sizeof(nat_cnt);
10163b3a8eb9SGleb Smirnoff 
1017d6164b77SAlexander V. Chernikov 	IPFW_UH_RLOCK(chain);
10183b3a8eb9SGleb Smirnoff retry:
10193b3a8eb9SGleb Smirnoff 	gencnt = chain->gencnt;
10203b3a8eb9SGleb Smirnoff 	/* Estimate memory amount */
10213b3a8eb9SGleb Smirnoff 	LIST_FOREACH(n, &chain->nat, _next) {
10223b3a8eb9SGleb Smirnoff 		nat_cnt++;
1023d6164b77SAlexander V. Chernikov 		len += sizeof(struct cfg_nat_legacy);
10243b3a8eb9SGleb Smirnoff 		LIST_FOREACH(r, &n->redir_chain, _next) {
1025d6164b77SAlexander V. Chernikov 			len += sizeof(struct cfg_redir_legacy);
10263b3a8eb9SGleb Smirnoff 			LIST_FOREACH(s, &r->spool_chain, _next)
1027d6164b77SAlexander V. Chernikov 				len += sizeof(struct cfg_spool_legacy);
10283b3a8eb9SGleb Smirnoff 		}
10293b3a8eb9SGleb Smirnoff 	}
1030d6164b77SAlexander V. Chernikov 	IPFW_UH_RUNLOCK(chain);
10313b3a8eb9SGleb Smirnoff 
10323b3a8eb9SGleb Smirnoff 	data = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
10333b3a8eb9SGleb Smirnoff 	bcopy(&nat_cnt, data, sizeof(nat_cnt));
10343b3a8eb9SGleb Smirnoff 
10353b3a8eb9SGleb Smirnoff 	nat_cnt = 0;
10363b3a8eb9SGleb Smirnoff 	len = sizeof(nat_cnt);
10373b3a8eb9SGleb Smirnoff 
1038d6164b77SAlexander V. Chernikov 	IPFW_UH_RLOCK(chain);
10393b3a8eb9SGleb Smirnoff 	if (gencnt != chain->gencnt) {
10403b3a8eb9SGleb Smirnoff 		free(data, M_TEMP);
10413b3a8eb9SGleb Smirnoff 		goto retry;
10423b3a8eb9SGleb Smirnoff 	}
10433b3a8eb9SGleb Smirnoff 	/* Serialize all the data. */
10443b3a8eb9SGleb Smirnoff 	LIST_FOREACH(n, &chain->nat, _next) {
1045d6164b77SAlexander V. Chernikov 		ucfg = (struct cfg_nat_legacy *)&data[len];
1046d6164b77SAlexander V. Chernikov 		ucfg->id = n->id;
1047d6164b77SAlexander V. Chernikov 		ucfg->ip = n->ip;
1048d6164b77SAlexander V. Chernikov 		ucfg->redir_cnt = n->redir_cnt;
1049d6164b77SAlexander V. Chernikov 		ucfg->mode = n->mode;
1050d6164b77SAlexander V. Chernikov 		strlcpy(ucfg->if_name, n->if_name, sizeof(ucfg->if_name));
1051d6164b77SAlexander V. Chernikov 		len += sizeof(struct cfg_nat_legacy);
10523b3a8eb9SGleb Smirnoff 		LIST_FOREACH(r, &n->redir_chain, _next) {
1053d6164b77SAlexander V. Chernikov 			ser_r = (struct cfg_redir_legacy *)&data[len];
1054d6164b77SAlexander V. Chernikov 			ser_r->mode = r->mode;
1055d6164b77SAlexander V. Chernikov 			ser_r->laddr = r->laddr;
1056d6164b77SAlexander V. Chernikov 			ser_r->paddr = r->paddr;
1057d6164b77SAlexander V. Chernikov 			ser_r->raddr = r->raddr;
1058d6164b77SAlexander V. Chernikov 			ser_r->lport = r->lport;
1059d6164b77SAlexander V. Chernikov 			ser_r->pport = r->pport;
1060d6164b77SAlexander V. Chernikov 			ser_r->rport = r->rport;
1061d6164b77SAlexander V. Chernikov 			ser_r->pport_cnt = r->pport_cnt;
1062d6164b77SAlexander V. Chernikov 			ser_r->rport_cnt = r->rport_cnt;
1063d6164b77SAlexander V. Chernikov 			ser_r->proto = r->proto;
1064d6164b77SAlexander V. Chernikov 			ser_r->spool_cnt = r->spool_cnt;
1065d6164b77SAlexander V. Chernikov 			len += sizeof(struct cfg_redir_legacy);
10663b3a8eb9SGleb Smirnoff 			LIST_FOREACH(s, &r->spool_chain, _next) {
1067d6164b77SAlexander V. Chernikov 				ser_s = (struct cfg_spool_legacy *)&data[len];
1068d6164b77SAlexander V. Chernikov 				ser_s->addr = s->addr;
1069d6164b77SAlexander V. Chernikov 				ser_s->port = s->port;
1070d6164b77SAlexander V. Chernikov 				len += sizeof(struct cfg_spool_legacy);
10713b3a8eb9SGleb Smirnoff 			}
10723b3a8eb9SGleb Smirnoff 		}
10733b3a8eb9SGleb Smirnoff 	}
1074d6164b77SAlexander V. Chernikov 	IPFW_UH_RUNLOCK(chain);
10753b3a8eb9SGleb Smirnoff 
10763b3a8eb9SGleb Smirnoff 	error = sooptcopyout(sopt, data, len);
10773b3a8eb9SGleb Smirnoff 	free(data, M_TEMP);
10783b3a8eb9SGleb Smirnoff 
10793b3a8eb9SGleb Smirnoff 	return (error);
10803b3a8eb9SGleb Smirnoff }
10813b3a8eb9SGleb Smirnoff 
10823b3a8eb9SGleb Smirnoff static int
10833b3a8eb9SGleb Smirnoff ipfw_nat_get_log(struct sockopt *sopt)
10843b3a8eb9SGleb Smirnoff {
10853b3a8eb9SGleb Smirnoff 	uint8_t *data;
10863b3a8eb9SGleb Smirnoff 	struct cfg_nat *ptr;
10873b3a8eb9SGleb Smirnoff 	int i, size;
10883b3a8eb9SGleb Smirnoff 	struct ip_fw_chain *chain;
1089*ccba94b8SAlexander V. Chernikov 	IPFW_RLOCK_TRACKER;
10903b3a8eb9SGleb Smirnoff 
10913b3a8eb9SGleb Smirnoff 	chain = &V_layer3_chain;
10923b3a8eb9SGleb Smirnoff 
10933b3a8eb9SGleb Smirnoff 	IPFW_RLOCK(chain);
10943b3a8eb9SGleb Smirnoff 	/* one pass to count, one to copy the data */
10953b3a8eb9SGleb Smirnoff 	i = 0;
10963b3a8eb9SGleb Smirnoff 	LIST_FOREACH(ptr, &chain->nat, _next) {
10973b3a8eb9SGleb Smirnoff 		if (ptr->lib->logDesc == NULL)
10983b3a8eb9SGleb Smirnoff 			continue;
10993b3a8eb9SGleb Smirnoff 		i++;
11003b3a8eb9SGleb Smirnoff 	}
11013b3a8eb9SGleb Smirnoff 	size = i * (LIBALIAS_BUF_SIZE + sizeof(int));
11023b3a8eb9SGleb Smirnoff 	data = malloc(size, M_IPFW, M_NOWAIT | M_ZERO);
11033b3a8eb9SGleb Smirnoff 	if (data == NULL) {
11043b3a8eb9SGleb Smirnoff 		IPFW_RUNLOCK(chain);
11053b3a8eb9SGleb Smirnoff 		return (ENOSPC);
11063b3a8eb9SGleb Smirnoff 	}
11073b3a8eb9SGleb Smirnoff 	i = 0;
11083b3a8eb9SGleb Smirnoff 	LIST_FOREACH(ptr, &chain->nat, _next) {
11093b3a8eb9SGleb Smirnoff 		if (ptr->lib->logDesc == NULL)
11103b3a8eb9SGleb Smirnoff 			continue;
11113b3a8eb9SGleb Smirnoff 		bcopy(&ptr->id, &data[i], sizeof(int));
11123b3a8eb9SGleb Smirnoff 		i += sizeof(int);
11133b3a8eb9SGleb Smirnoff 		bcopy(ptr->lib->logDesc, &data[i], LIBALIAS_BUF_SIZE);
11143b3a8eb9SGleb Smirnoff 		i += LIBALIAS_BUF_SIZE;
11153b3a8eb9SGleb Smirnoff 	}
11163b3a8eb9SGleb Smirnoff 	IPFW_RUNLOCK(chain);
11173b3a8eb9SGleb Smirnoff 	sooptcopyout(sopt, data, size);
11183b3a8eb9SGleb Smirnoff 	free(data, M_IPFW);
11193b3a8eb9SGleb Smirnoff 	return(0);
11203b3a8eb9SGleb Smirnoff }
11213b3a8eb9SGleb Smirnoff 
11228856400bSMikolaj Golub static int
11238856400bSMikolaj Golub vnet_ipfw_nat_init(const void *arg __unused)
11243b3a8eb9SGleb Smirnoff {
11253b3a8eb9SGleb Smirnoff 
11268856400bSMikolaj Golub 	V_ipfw_nat_ready = 1;
11278856400bSMikolaj Golub 	return (0);
11283b3a8eb9SGleb Smirnoff }
11293b3a8eb9SGleb Smirnoff 
11308856400bSMikolaj Golub static int
11318856400bSMikolaj Golub vnet_ipfw_nat_uninit(const void *arg __unused)
11323b3a8eb9SGleb Smirnoff {
11333b3a8eb9SGleb Smirnoff 	struct cfg_nat *ptr, *ptr_temp;
11343b3a8eb9SGleb Smirnoff 	struct ip_fw_chain *chain;
11353b3a8eb9SGleb Smirnoff 
11363b3a8eb9SGleb Smirnoff 	chain = &V_layer3_chain;
11373b3a8eb9SGleb Smirnoff 	IPFW_WLOCK(chain);
11383b3a8eb9SGleb Smirnoff 	LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) {
11393b3a8eb9SGleb Smirnoff 		LIST_REMOVE(ptr, _next);
11403b3a8eb9SGleb Smirnoff 		del_redir_spool_cfg(ptr, &ptr->redir_chain);
11413b3a8eb9SGleb Smirnoff 		LibAliasUninit(ptr->lib);
11423b3a8eb9SGleb Smirnoff 		free(ptr, M_IPFW);
11433b3a8eb9SGleb Smirnoff 	}
11443b3a8eb9SGleb Smirnoff 	flush_nat_ptrs(chain, -1 /* flush all */);
11458856400bSMikolaj Golub 	V_ipfw_nat_ready = 0;
11468856400bSMikolaj Golub 	IPFW_WUNLOCK(chain);
11478856400bSMikolaj Golub 	return (0);
11488856400bSMikolaj Golub }
11498856400bSMikolaj Golub 
11508856400bSMikolaj Golub static void
11518856400bSMikolaj Golub ipfw_nat_init(void)
11528856400bSMikolaj Golub {
11538856400bSMikolaj Golub 
11548856400bSMikolaj Golub 	/* init ipfw hooks */
11558856400bSMikolaj Golub 	ipfw_nat_ptr = ipfw_nat;
11568856400bSMikolaj Golub 	lookup_nat_ptr = lookup_nat;
11578856400bSMikolaj Golub 	ipfw_nat_cfg_ptr = ipfw_nat_cfg;
11588856400bSMikolaj Golub 	ipfw_nat_del_ptr = ipfw_nat_del;
11598856400bSMikolaj Golub 	ipfw_nat_get_cfg_ptr = ipfw_nat_get_cfg;
11608856400bSMikolaj Golub 	ipfw_nat_get_log_ptr = ipfw_nat_get_log;
1161d6164b77SAlexander V. Chernikov 	IPFW_ADD_SOPT_HANDLER(1, scodes);
11628856400bSMikolaj Golub 
11638856400bSMikolaj Golub 	ifaddr_event_tag = EVENTHANDLER_REGISTER(ifaddr_event, ifaddr_change,
11648856400bSMikolaj Golub 	    NULL, EVENTHANDLER_PRI_ANY);
11658856400bSMikolaj Golub }
11668856400bSMikolaj Golub 
11678856400bSMikolaj Golub static void
11688856400bSMikolaj Golub ipfw_nat_destroy(void)
11698856400bSMikolaj Golub {
11708856400bSMikolaj Golub 
11718856400bSMikolaj Golub 	EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_event_tag);
11723b3a8eb9SGleb Smirnoff 	/* deregister ipfw_nat */
1173d6164b77SAlexander V. Chernikov 	IPFW_DEL_SOPT_HANDLER(1, scodes);
11743b3a8eb9SGleb Smirnoff 	ipfw_nat_ptr = NULL;
11753b3a8eb9SGleb Smirnoff 	lookup_nat_ptr = NULL;
11763b3a8eb9SGleb Smirnoff 	ipfw_nat_cfg_ptr = NULL;
11773b3a8eb9SGleb Smirnoff 	ipfw_nat_del_ptr = NULL;
11783b3a8eb9SGleb Smirnoff 	ipfw_nat_get_cfg_ptr = NULL;
11793b3a8eb9SGleb Smirnoff 	ipfw_nat_get_log_ptr = NULL;
11803b3a8eb9SGleb Smirnoff }
11813b3a8eb9SGleb Smirnoff 
11823b3a8eb9SGleb Smirnoff static int
11833b3a8eb9SGleb Smirnoff ipfw_nat_modevent(module_t mod, int type, void *unused)
11843b3a8eb9SGleb Smirnoff {
11853b3a8eb9SGleb Smirnoff 	int err = 0;
11863b3a8eb9SGleb Smirnoff 
11873b3a8eb9SGleb Smirnoff 	switch (type) {
11883b3a8eb9SGleb Smirnoff 	case MOD_LOAD:
11893b3a8eb9SGleb Smirnoff 		break;
11903b3a8eb9SGleb Smirnoff 
11913b3a8eb9SGleb Smirnoff 	case MOD_UNLOAD:
11923b3a8eb9SGleb Smirnoff 		break;
11933b3a8eb9SGleb Smirnoff 
11943b3a8eb9SGleb Smirnoff 	default:
11953b3a8eb9SGleb Smirnoff 		return EOPNOTSUPP;
11963b3a8eb9SGleb Smirnoff 		break;
11973b3a8eb9SGleb Smirnoff 	}
11983b3a8eb9SGleb Smirnoff 	return err;
11993b3a8eb9SGleb Smirnoff }
12003b3a8eb9SGleb Smirnoff 
12013b3a8eb9SGleb Smirnoff static moduledata_t ipfw_nat_mod = {
12023b3a8eb9SGleb Smirnoff 	"ipfw_nat",
12033b3a8eb9SGleb Smirnoff 	ipfw_nat_modevent,
12049823d527SKevin Lo 	0
12053b3a8eb9SGleb Smirnoff };
12063b3a8eb9SGleb Smirnoff 
12078856400bSMikolaj Golub /* Define startup order. */
12088a477d48SMikolaj Golub #define	IPFW_NAT_SI_SUB_FIREWALL	SI_SUB_PROTO_IFATTACHDOMAIN
12098a477d48SMikolaj Golub #define	IPFW_NAT_MODEVENT_ORDER		(SI_ORDER_ANY - 128) /* after ipfw */
12108856400bSMikolaj Golub #define	IPFW_NAT_MODULE_ORDER		(IPFW_NAT_MODEVENT_ORDER + 1)
12118856400bSMikolaj Golub #define	IPFW_NAT_VNET_ORDER		(IPFW_NAT_MODEVENT_ORDER + 2)
12128856400bSMikolaj Golub 
12138856400bSMikolaj Golub DECLARE_MODULE(ipfw_nat, ipfw_nat_mod, IPFW_NAT_SI_SUB_FIREWALL, SI_ORDER_ANY);
12143b3a8eb9SGleb Smirnoff MODULE_DEPEND(ipfw_nat, libalias, 1, 1, 1);
12153b3a8eb9SGleb Smirnoff MODULE_DEPEND(ipfw_nat, ipfw, 2, 2, 2);
12163b3a8eb9SGleb Smirnoff MODULE_VERSION(ipfw_nat, 1);
12178856400bSMikolaj Golub 
12188856400bSMikolaj Golub SYSINIT(ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
12198856400bSMikolaj Golub     ipfw_nat_init, NULL);
12208856400bSMikolaj Golub VNET_SYSINIT(vnet_ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_VNET_ORDER,
12218856400bSMikolaj Golub     vnet_ipfw_nat_init, NULL);
12228856400bSMikolaj Golub 
12238856400bSMikolaj Golub SYSUNINIT(ipfw_nat_destroy, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
12248856400bSMikolaj Golub     ipfw_nat_destroy, NULL);
12258856400bSMikolaj Golub VNET_SYSUNINIT(vnet_ipfw_nat_uninit, IPFW_NAT_SI_SUB_FIREWALL,
12268856400bSMikolaj Golub     IPFW_NAT_VNET_ORDER, vnet_ipfw_nat_uninit, NULL);
12278856400bSMikolaj Golub 
12283b3a8eb9SGleb Smirnoff /* end of file */
1229