ip_nat.c revision 89336
1/*
2 * Copyright (C) 1995-2001 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 *
6 * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com)
7 */
8
9#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL)
10#define _KERNEL
11#endif
12
13#include <sys/errno.h>
14#include <sys/types.h>
15#include <sys/param.h>
16#include <sys/time.h>
17#include <sys/file.h>
18#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
19    defined(_KERNEL)
20# include "opt_ipfilter_log.h"
21#endif
22#if !defined(_KERNEL) && !defined(KERNEL)
23# include <stdio.h>
24# include <string.h>
25# include <stdlib.h>
26#endif
27#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000)
28# include <sys/filio.h>
29# include <sys/fcntl.h>
30#else
31# include <sys/ioctl.h>
32#endif
33#include <sys/fcntl.h>
34#include <sys/uio.h>
35#ifndef linux
36# include <sys/protosw.h>
37#endif
38#include <sys/socket.h>
39#if defined(_KERNEL) && !defined(linux)
40# include <sys/systm.h>
41#endif
42#if !defined(__SVR4) && !defined(__svr4__)
43# ifndef linux
44#  include <sys/mbuf.h>
45# endif
46#else
47# include <sys/filio.h>
48# include <sys/byteorder.h>
49# ifdef _KERNEL
50#  include <sys/dditypes.h>
51# endif
52# include <sys/stream.h>
53# include <sys/kmem.h>
54#endif
55#if __FreeBSD_version >= 300000
56# include <sys/queue.h>
57#endif
58#include <net/if.h>
59#if __FreeBSD_version >= 300000
60# include <net/if_var.h>
61# if defined(_KERNEL) && !defined(IPFILTER_LKM)
62#  include "opt_ipfilter.h"
63# endif
64#endif
65#ifdef sun
66# include <net/af.h>
67#endif
68#include <net/route.h>
69#include <netinet/in.h>
70#include <netinet/in_systm.h>
71#include <netinet/ip.h>
72
73#ifdef __sgi
74# ifdef IFF_DRVRLOCK /* IRIX6 */
75#include <sys/hashing.h>
76#include <netinet/in_var.h>
77# endif
78#endif
79
80#ifdef RFC1825
81# include <vpn/md5.h>
82# include <vpn/ipsec.h>
83extern struct ifnet vpnif;
84#endif
85
86#ifndef linux
87# include <netinet/ip_var.h>
88# include <netinet/tcp_fsm.h>
89#endif
90#include <netinet/tcp.h>
91#include <netinet/udp.h>
92#include <netinet/ip_icmp.h>
93#include "netinet/ip_compat.h"
94#include <netinet/tcpip.h>
95#include "netinet/ip_fil.h"
96#include "netinet/ip_proxy.h"
97#include "netinet/ip_nat.h"
98#include "netinet/ip_frag.h"
99#include "netinet/ip_state.h"
100#if (__FreeBSD_version >= 300000)
101# include <sys/malloc.h>
102#endif
103#ifndef	MIN
104# define	MIN(a,b)	(((a)<(b))?(a):(b))
105#endif
106#undef	SOCKADDR_IN
107#define	SOCKADDR_IN	struct sockaddr_in
108
109#if !defined(lint)
110static const char sccsid[] = "@(#)ip_nat.c	1.11 6/5/96 (C) 1995 Darren Reed";
111/* static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.44 2001/07/21 07:17:22 darrenr Exp $"; */
112static const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_nat.c 89336 2002-01-14 09:07:15Z alfred $";
113#endif
114
115nat_t	**nat_table[2] = { NULL, NULL },
116	*nat_instances = NULL;
117ipnat_t	*nat_list = NULL;
118u_int	ipf_nattable_sz = NAT_TABLE_SZ;
119u_int	ipf_natrules_sz = NAT_SIZE;
120u_int	ipf_rdrrules_sz = RDR_SIZE;
121u_int	ipf_hostmap_sz = HOSTMAP_SIZE;
122u_32_t	nat_masks = 0;
123u_32_t	rdr_masks = 0;
124ipnat_t	**nat_rules = NULL;
125ipnat_t	**rdr_rules = NULL;
126hostmap_t	**maptable  = NULL;
127
128u_long	fr_defnatage = DEF_NAT_AGE,
129	fr_defnaticmpage = 6;		/* 3 seconds */
130natstat_t nat_stats;
131int	fr_nat_lock = 0;
132#if	(SOLARIS || defined(__sgi)) && defined(_KERNEL)
133extern	kmutex_t	ipf_rw;
134extern	KRWLOCK_T	ipf_nat;
135#endif
136
137static	int	nat_flushtable __P((void));
138static	int	nat_clearlist __P((void));
139static	void	nat_addnat __P((struct ipnat *));
140static	void	nat_addrdr __P((struct ipnat *));
141static	void	nat_delete __P((struct nat *));
142static	void	nat_delrdr __P((struct ipnat *));
143static	void	nat_delnat __P((struct ipnat *));
144static	int	fr_natgetent __P((caddr_t));
145static	int	fr_natgetsz __P((caddr_t));
146static	int	fr_natputent __P((caddr_t));
147static	void	nat_tabmove __P((nat_t *, u_32_t));
148static	int	nat_match __P((fr_info_t *, ipnat_t *, ip_t *));
149static	hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr,
150				    struct in_addr));
151static	void	nat_hostmapdel __P((struct hostmap *));
152
153
154int nat_init()
155{
156	KMALLOCS(nat_table[0], nat_t **, sizeof(nat_t *) * ipf_nattable_sz);
157	if (nat_table[0] != NULL)
158		bzero((char *)nat_table[0], ipf_nattable_sz * sizeof(nat_t *));
159	else
160		return -1;
161
162	KMALLOCS(nat_table[1], nat_t **, sizeof(nat_t *) * ipf_nattable_sz);
163	if (nat_table[1] != NULL)
164		bzero((char *)nat_table[1], ipf_nattable_sz * sizeof(nat_t *));
165	else
166		return -1;
167
168	KMALLOCS(nat_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_natrules_sz);
169	if (nat_rules != NULL)
170		bzero((char *)nat_rules, ipf_natrules_sz * sizeof(ipnat_t *));
171	else
172		return -1;
173
174	KMALLOCS(rdr_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_rdrrules_sz);
175	if (rdr_rules != NULL)
176		bzero((char *)rdr_rules, ipf_rdrrules_sz * sizeof(ipnat_t *));
177	else
178		return -1;
179
180	KMALLOCS(maptable, hostmap_t **, sizeof(hostmap_t *) * ipf_hostmap_sz);
181	if (maptable != NULL)
182		bzero((char *)maptable, sizeof(hostmap_t *) * ipf_hostmap_sz);
183	else
184		return -1;
185	return 0;
186}
187
188
189static void nat_addrdr(n)
190ipnat_t *n;
191{
192	ipnat_t **np;
193	u_32_t j;
194	u_int hv;
195	int k;
196
197	k = countbits(n->in_outmsk);
198	if ((k >= 0) && (k != 32))
199		rdr_masks |= 1 << k;
200	j = (n->in_outip & n->in_outmsk);
201	hv = NAT_HASH_FN(j, 0, ipf_rdrrules_sz);
202	np = rdr_rules + hv;
203	while (*np != NULL)
204		np = &(*np)->in_rnext;
205	n->in_rnext = NULL;
206	n->in_prnext = np;
207	*np = n;
208}
209
210
211static void nat_addnat(n)
212ipnat_t *n;
213{
214	ipnat_t **np;
215	u_32_t j;
216	u_int hv;
217	int k;
218
219	k = countbits(n->in_inmsk);
220	if ((k >= 0) && (k != 32))
221		nat_masks |= 1 << k;
222	j = (n->in_inip & n->in_inmsk);
223	hv = NAT_HASH_FN(j, 0, ipf_natrules_sz);
224	np = nat_rules + hv;
225	while (*np != NULL)
226		np = &(*np)->in_mnext;
227	n->in_mnext = NULL;
228	n->in_pmnext = np;
229	*np = n;
230}
231
232
233static void nat_delrdr(n)
234ipnat_t *n;
235{
236	if (n->in_rnext)
237		n->in_rnext->in_prnext = n->in_prnext;
238	*n->in_prnext = n->in_rnext;
239}
240
241
242static void nat_delnat(n)
243ipnat_t *n;
244{
245	if (n->in_mnext)
246		n->in_mnext->in_pmnext = n->in_pmnext;
247	*n->in_pmnext = n->in_mnext;
248}
249
250
251/*
252 * check if an ip address has already been allocated for a given mapping that
253 * is not doing port based translation.
254 *
255 * Must be called with ipf_nat held as a write lock.
256 */
257static struct hostmap *nat_hostmap(np, real, map)
258ipnat_t *np;
259struct in_addr real;
260struct in_addr map;
261{
262	hostmap_t *hm;
263	u_int hv;
264
265	hv = real.s_addr % HOSTMAP_SIZE;
266	for (hm = maptable[hv]; hm; hm = hm->hm_next)
267		if ((hm->hm_realip.s_addr == real.s_addr) &&
268		    (np == hm->hm_ipnat)) {
269			hm->hm_ref++;
270			return hm;
271		}
272
273	KMALLOC(hm, hostmap_t *);
274	if (hm) {
275		hm->hm_next = maptable[hv];
276		hm->hm_pnext = maptable + hv;
277		if (maptable[hv])
278			maptable[hv]->hm_pnext = &hm->hm_next;
279		maptable[hv] = hm;
280		hm->hm_ipnat = np;
281		hm->hm_realip = real;
282		hm->hm_mapip = map;
283		hm->hm_ref = 1;
284	}
285	return hm;
286}
287
288
289/*
290 * Must be called with ipf_nat held as a write lock.
291 */
292static void nat_hostmapdel(hm)
293struct hostmap *hm;
294{
295	ATOMIC_DEC32(hm->hm_ref);
296	if (hm->hm_ref == 0) {
297		if (hm->hm_next)
298			hm->hm_next->hm_pnext = hm->hm_pnext;
299		*hm->hm_pnext = hm->hm_next;
300		KFREE(hm);
301	}
302}
303
304
305void fix_outcksum(fin, sp, n)
306fr_info_t *fin;
307u_short *sp;
308u_32_t n;
309{
310	register u_short sumshort;
311	register u_32_t sum1;
312
313	if (!n)
314		return;
315	else if (n & NAT_HW_CKSUM) {
316		n &= 0xffff;
317		n += fin->fin_dlen;
318		n = (n & 0xffff) + (n >> 16);
319		*sp = n & 0xffff;
320		return;
321	}
322	sum1 = (~ntohs(*sp)) & 0xffff;
323	sum1 += (n);
324	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
325	/* Again */
326	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
327	sumshort = ~(u_short)sum1;
328	*(sp) = htons(sumshort);
329}
330
331
332void fix_incksum(fin, sp, n)
333fr_info_t *fin;
334u_short *sp;
335u_32_t n;
336{
337	register u_short sumshort;
338	register u_32_t sum1;
339
340	if (!n)
341		return;
342	else if (n & NAT_HW_CKSUM) {
343		n &= 0xffff;
344		n += fin->fin_dlen;
345		n = (n & 0xffff) + (n >> 16);
346		*sp = n & 0xffff;
347		return;
348	}
349#ifdef sparc
350	sum1 = (~(*sp)) & 0xffff;
351#else
352	sum1 = (~ntohs(*sp)) & 0xffff;
353#endif
354	sum1 += ~(n) & 0xffff;
355	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
356	/* Again */
357	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
358	sumshort = ~(u_short)sum1;
359	*(sp) = htons(sumshort);
360}
361
362
363/*
364 * fix_datacksum is used *only* for the adjustments of checksums in the data
365 * section of an IP packet.
366 *
367 * The only situation in which you need to do this is when NAT'ing an
368 * ICMP error message. Such a message, contains in its body the IP header
369 * of the original IP packet, that causes the error.
370 *
371 * You can't use fix_incksum or fix_outcksum in that case, because for the
372 * kernel the data section of the ICMP error is just data, and no special
373 * processing like hardware cksum or ntohs processing have been done by the
374 * kernel on the data section.
375 */
376void fix_datacksum(sp, n)
377u_short *sp;
378u_32_t n;
379{
380	register u_short sumshort;
381	register u_32_t sum1;
382
383	if (!n)
384		return;
385
386	sum1 = (~ntohs(*sp)) & 0xffff;
387	sum1 += (n);
388	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
389	/* Again */
390	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
391	sumshort = ~(u_short)sum1;
392	*(sp) = htons(sumshort);
393}
394
395/*
396 * How the NAT is organised and works.
397 *
398 * Inside (interface y) NAT       Outside (interface x)
399 * -------------------- -+- -------------------------------------
400 * Packet going          |   out, processsed by ip_natout() for x
401 * ------------>         |   ------------>
402 * src=10.1.1.1          |   src=192.1.1.1
403 *                       |
404 *                       |   in, processed by ip_natin() for x
405 * <------------         |   <------------
406 * dst=10.1.1.1          |   dst=192.1.1.1
407 * -------------------- -+- -------------------------------------
408 * ip_natout() - changes ip_src and if required, sport
409 *             - creates a new mapping, if required.
410 * ip_natin()  - changes ip_dst and if required, dport
411 *
412 * In the NAT table, internal source is recorded as "in" and externally
413 * seen as "out".
414 */
415
416/*
417 * Handle ioctls which manipulate the NAT.
418 */
419int nat_ioctl(data, cmd, mode)
420#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
421u_long cmd;
422#else
423int cmd;
424#endif
425caddr_t data;
426int mode;
427{
428	register ipnat_t *nat, *nt, *n = NULL, **np = NULL;
429	int error = 0, ret, arg;
430	ipnat_t natd;
431	u_32_t i, j;
432
433#if (BSD >= 199306) && defined(_KERNEL)
434	if ((securelevel >= 3) && (mode & FWRITE))
435		return EPERM;
436#endif
437
438	nat = NULL;     /* XXX gcc -Wuninitialized */
439	KMALLOC(nt, ipnat_t *);
440	if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT))
441		error = IRCOPYPTR(data, (char *)&natd, sizeof(natd));
442	else if (cmd == SIOCIPFFL) {	/* SIOCFLNAT & SIOCCNATL */
443		error = IRCOPY(data, (char *)&arg, sizeof(arg));
444		if (error)
445			error = EFAULT;
446	}
447
448	if (error)
449		goto done;
450
451	/*
452	 * For add/delete, look to see if the NAT entry is already present
453	 */
454	WRITE_ENTER(&ipf_nat);
455	if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) {
456		nat = &natd;
457		nat->in_flags &= IPN_USERFLAGS;
458		if ((nat->in_redir & NAT_MAPBLK) == 0) {
459			if ((nat->in_flags & IPN_SPLIT) == 0)
460				nat->in_inip &= nat->in_inmsk;
461			if ((nat->in_flags & IPN_IPRANGE) == 0)
462				nat->in_outip &= nat->in_outmsk;
463		}
464		for (np = &nat_list; (n = *np); np = &n->in_next)
465			if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags,
466					IPN_CMPSIZ))
467				break;
468	}
469
470	switch (cmd)
471	{
472#ifdef  IPFILTER_LOG
473	case SIOCIPFFB :
474	{
475		int tmp;
476
477		if (!(mode & FWRITE))
478			error = EPERM;
479		else {
480			tmp = ipflog_clear(IPL_LOGNAT);
481			IWCOPY((char *)&tmp, (char *)data, sizeof(tmp));
482		}
483		break;
484	}
485#endif
486	case SIOCADNAT :
487		if (!(mode & FWRITE)) {
488			error = EPERM;
489			break;
490		}
491		if (n) {
492			error = EEXIST;
493			break;
494		}
495		if (nt == NULL) {
496			error = ENOMEM;
497			break;
498		}
499		n = nt;
500		nt = NULL;
501		bcopy((char *)nat, (char *)n, sizeof(*n));
502		n->in_ifp = (void *)GETUNIT(n->in_ifname, 4);
503		if (!n->in_ifp)
504			n->in_ifp = (void *)-1;
505		if (n->in_plabel[0] != '\0') {
506			n->in_apr = appr_match(n->in_p, n->in_plabel);
507			if (!n->in_apr) {
508				error = ENOENT;
509				break;
510			}
511		}
512		n->in_next = NULL;
513		*np = n;
514
515		if (n->in_redir & NAT_REDIRECT) {
516			n->in_flags &= ~IPN_NOTDST;
517			nat_addrdr(n);
518		}
519		if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
520			n->in_flags &= ~IPN_NOTSRC;
521			nat_addnat(n);
522		}
523
524		n->in_use = 0;
525		if (n->in_redir & NAT_MAPBLK)
526			n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk);
527		else if (n->in_flags & IPN_AUTOPORTMAP)
528			n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk);
529		else if (n->in_flags & IPN_IPRANGE)
530			n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip);
531		else if (n->in_flags & IPN_SPLIT)
532			n->in_space = 2;
533		else
534			n->in_space = ~ntohl(n->in_outmsk);
535		/*
536		 * Calculate the number of valid IP addresses in the output
537		 * mapping range.  In all cases, the range is inclusive of
538		 * the start and ending IP addresses.
539		 * If to a CIDR address, lose 2: broadcast + network address
540		 *			         (so subtract 1)
541		 * If to a range, add one.
542		 * If to a single IP address, set to 1.
543		 */
544		if (n->in_space) {
545			if ((n->in_flags & IPN_IPRANGE) != 0)
546				n->in_space += 1;
547			else
548				n->in_space -= 1;
549		} else
550			n->in_space = 1;
551		if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) &&
552		    ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0))
553			n->in_nip = ntohl(n->in_outip) + 1;
554		else if ((n->in_flags & IPN_SPLIT) &&
555			 (n->in_redir & NAT_REDIRECT))
556			n->in_nip = ntohl(n->in_inip);
557		else
558			n->in_nip = ntohl(n->in_outip);
559		if (n->in_redir & NAT_MAP) {
560			n->in_pnext = ntohs(n->in_pmin);
561			/*
562			 * Multiply by the number of ports made available.
563			 */
564			if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) {
565				n->in_space *= (ntohs(n->in_pmax) -
566						ntohs(n->in_pmin) + 1);
567				/*
568				 * Because two different sources can map to
569				 * different destinations but use the same
570				 * local IP#/port #.
571				 * If the result is smaller than in_space, then
572				 * we may have wrapped around 32bits.
573				 */
574				i = n->in_inmsk;
575				if ((i != 0) && (i != 0xffffffff)) {
576					j = n->in_space * (~ntohl(i) + 1);
577					if (j >= n->in_space)
578						n->in_space = j;
579					else
580						n->in_space = 0xffffffff;
581				}
582			}
583			/*
584			 * If no protocol is specified, multiple by 256.
585			 */
586			if ((n->in_flags & IPN_TCPUDP) == 0) {
587					j = n->in_space * 256;
588					if (j >= n->in_space)
589						n->in_space = j;
590					else
591						n->in_space = 0xffffffff;
592			}
593		}
594		/* Otherwise, these fields are preset */
595		n = NULL;
596		nat_stats.ns_rules++;
597		break;
598	case SIOCRMNAT :
599		if (!(mode & FWRITE)) {
600			error = EPERM;
601			n = NULL;
602			break;
603		}
604		if (!n) {
605			error = ESRCH;
606			break;
607		}
608		if (n->in_redir & NAT_REDIRECT)
609			nat_delrdr(n);
610		if (n->in_redir & (NAT_MAPBLK|NAT_MAP))
611			nat_delnat(n);
612		if (nat_list == NULL) {
613			nat_masks = 0;
614			rdr_masks = 0;
615		}
616		*np = n->in_next;
617		if (!n->in_use) {
618			if (n->in_apr)
619				appr_free(n->in_apr);
620			KFREE(n);
621			nat_stats.ns_rules--;
622		} else {
623			n->in_flags |= IPN_DELETE;
624			n->in_next = NULL;
625		}
626		n = NULL;
627		break;
628	case SIOCGNATS :
629		MUTEX_DOWNGRADE(&ipf_nat);
630		nat_stats.ns_table[0] = nat_table[0];
631		nat_stats.ns_table[1] = nat_table[1];
632		nat_stats.ns_list = nat_list;
633		nat_stats.ns_maptable = maptable;
634		nat_stats.ns_nattab_sz = ipf_nattable_sz;
635		nat_stats.ns_rultab_sz = ipf_natrules_sz;
636		nat_stats.ns_rdrtab_sz = ipf_rdrrules_sz;
637		nat_stats.ns_hostmap_sz = ipf_hostmap_sz;
638		nat_stats.ns_instances = nat_instances;
639		nat_stats.ns_apslist = ap_sess_list;
640		error = IWCOPYPTR((char *)&nat_stats, (char *)data,
641				  sizeof(nat_stats));
642		break;
643	case SIOCGNATL :
644	    {
645		natlookup_t nl;
646
647		MUTEX_DOWNGRADE(&ipf_nat);
648		error = IRCOPYPTR((char *)data, (char *)&nl, sizeof(nl));
649		if (error)
650			break;
651
652		if (nat_lookupredir(&nl)) {
653			error = IWCOPYPTR((char *)&nl, (char *)data,
654					  sizeof(nl));
655		} else
656			error = ESRCH;
657		break;
658	    }
659	case SIOCIPFFL :	/* old SIOCFLNAT & SIOCCNATL */
660		if (!(mode & FWRITE)) {
661			error = EPERM;
662			break;
663		}
664		error = 0;
665		if (arg == 0)
666			ret = nat_flushtable();
667		else if (arg == 1)
668			ret = nat_clearlist();
669		else
670			error = EINVAL;
671		MUTEX_DOWNGRADE(&ipf_nat);
672		if (!error) {
673			error = IWCOPY((caddr_t)&ret, data, sizeof(ret));
674			if (error)
675				error = EFAULT;
676		}
677		break;
678	case SIOCSTLCK :
679		error = IRCOPY(data, (caddr_t)&arg, sizeof(arg));
680		if (!error) {
681			error = IWCOPY((caddr_t)&fr_nat_lock, data,
682					sizeof(fr_nat_lock));
683			if (!error)
684				fr_nat_lock = arg;
685		} else
686			error = EFAULT;
687		break;
688	case SIOCSTPUT :
689		if (fr_nat_lock)
690			error = fr_natputent(data);
691		else
692			error = EACCES;
693		break;
694	case SIOCSTGSZ :
695		if (fr_nat_lock)
696			error = fr_natgetsz(data);
697		else
698			error = EACCES;
699		break;
700	case SIOCSTGET :
701		if (fr_nat_lock)
702			error = fr_natgetent(data);
703		else
704			error = EACCES;
705		break;
706	case FIONREAD :
707#ifdef	IPFILTER_LOG
708		arg = (int)iplused[IPL_LOGNAT];
709		MUTEX_DOWNGRADE(&ipf_nat);
710		error = IWCOPY((caddr_t)&arg, (caddr_t)data, sizeof(arg));
711		if (error)
712			error = EFAULT;
713#endif
714		break;
715	default :
716		error = EINVAL;
717		break;
718	}
719	RWLOCK_EXIT(&ipf_nat);			/* READ/WRITE */
720done:
721	if (nt)
722		KFREE(nt);
723	return error;
724}
725
726
727static int fr_natgetsz(data)
728caddr_t data;
729{
730	ap_session_t *aps;
731	nat_t *nat, *n;
732	int error = 0;
733	natget_t ng;
734
735	error = IRCOPY(data, (caddr_t)&ng, sizeof(ng));
736	if (error)
737		return EFAULT;
738
739	nat = ng.ng_ptr;
740	if (!nat) {
741		nat = nat_instances;
742		ng.ng_sz = 0;
743		if (nat == NULL) {
744			error = IWCOPY((caddr_t)&ng, data, sizeof(ng));
745			if (error)
746				error = EFAULT;
747			return error;
748		}
749	} else {
750		/*
751		 * Make sure the pointer we're copying from exists in the
752		 * current list of entries.  Security precaution to prevent
753		 * copying of random kernel data.
754		 */
755		for (n = nat_instances; n; n = n->nat_next)
756			if (n == nat)
757				break;
758		if (!n)
759			return ESRCH;
760	}
761
762	ng.ng_sz = sizeof(nat_save_t);
763	aps = nat->nat_aps;
764	if ((aps != NULL) && (aps->aps_data != 0)) {
765		ng.ng_sz += sizeof(ap_session_t);
766		ng.ng_sz += aps->aps_psiz;
767	}
768
769	error = IWCOPY((caddr_t)&ng, data, sizeof(ng));
770	if (error)
771		error = EFAULT;
772	return error;
773}
774
775
776static int fr_natgetent(data)
777caddr_t data;
778{
779	nat_save_t ipn, *ipnp, *ipnn = NULL;
780	register nat_t *n, *nat;
781	ap_session_t *aps;
782	int error;
783
784	error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp));
785	if (error)
786		return EFAULT;
787	error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn));
788	if (error)
789		return EFAULT;
790
791	nat = ipn.ipn_next;
792	if (!nat) {
793		nat = nat_instances;
794		if (nat == NULL) {
795			if (nat_instances == NULL)
796				return ENOENT;
797			return 0;
798		}
799	} else {
800		/*
801		 * Make sure the pointer we're copying from exists in the
802		 * current list of entries.  Security precaution to prevent
803		 * copying of random kernel data.
804		 */
805		for (n = nat_instances; n; n = n->nat_next)
806			if (n == nat)
807				break;
808		if (!n)
809			return ESRCH;
810	}
811
812	ipn.ipn_next = nat->nat_next;
813	ipn.ipn_dsize = 0;
814	bcopy((char *)nat, (char *)&ipn.ipn_nat, sizeof(ipn.ipn_nat));
815	ipn.ipn_nat.nat_data = NULL;
816
817	if (nat->nat_ptr) {
818		bcopy((char *)nat->nat_ptr, (char *)&ipn.ipn_ipnat,
819		      sizeof(ipn.ipn_ipnat));
820	}
821
822	if (nat->nat_fr)
823		bcopy((char *)nat->nat_fr, (char *)&ipn.ipn_rule,
824		      sizeof(ipn.ipn_rule));
825
826	if ((aps = nat->nat_aps)) {
827		ipn.ipn_dsize = sizeof(*aps);
828		if (aps->aps_data)
829			ipn.ipn_dsize += aps->aps_psiz;
830		KMALLOCS(ipnn, nat_save_t *, sizeof(*ipnn) + ipn.ipn_dsize);
831		if (ipnn == NULL)
832			return ENOMEM;
833		bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn));
834
835		bcopy((char *)aps, ipnn->ipn_data, sizeof(*aps));
836		if (aps->aps_data) {
837			bcopy(aps->aps_data, ipnn->ipn_data + sizeof(*aps),
838			      aps->aps_psiz);
839			ipnn->ipn_dsize += aps->aps_psiz;
840		}
841		error = IWCOPY((caddr_t)ipnn, ipnp,
842			       sizeof(ipn) + ipn.ipn_dsize);
843		if (error)
844			error = EFAULT;
845		KFREES(ipnn, sizeof(*ipnn) + ipn.ipn_dsize);
846	} else {
847		error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn));
848		if (error)
849			error = EFAULT;
850	}
851	return error;
852}
853
854
855static int fr_natputent(data)
856caddr_t data;
857{
858	nat_save_t ipn, *ipnp, *ipnn = NULL;
859	register nat_t *n, *nat;
860	ap_session_t *aps;
861	frentry_t *fr;
862	ipnat_t *in;
863
864	int error;
865
866	error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp));
867	if (error)
868		return EFAULT;
869	error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn));
870	if (error)
871		return EFAULT;
872	nat = NULL;
873	if (ipn.ipn_dsize) {
874		KMALLOCS(ipnn, nat_save_t *, sizeof(ipn) + ipn.ipn_dsize);
875		if (ipnn == NULL)
876			return ENOMEM;
877		bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn));
878		error = IRCOPY((caddr_t)ipnp, (caddr_t)ipn.ipn_data,
879			       ipn.ipn_dsize);
880		if (error) {
881			error = EFAULT;
882			goto junkput;
883		}
884	} else
885		ipnn = NULL;
886
887	KMALLOC(nat, nat_t *);
888	if (nat == NULL) {
889		error = EFAULT;
890		goto junkput;
891	}
892
893	bcopy((char *)&ipn.ipn_nat, (char *)nat, sizeof(*nat));
894	/*
895	 * Initialize all these so that nat_delete() doesn't cause a crash.
896	 */
897	nat->nat_phnext[0] = NULL;
898	nat->nat_phnext[1] = NULL;
899	fr = nat->nat_fr;
900	nat->nat_fr = NULL;
901	aps = nat->nat_aps;
902	nat->nat_aps = NULL;
903	in = nat->nat_ptr;
904	nat->nat_ptr = NULL;
905	nat->nat_hm = NULL;
906	nat->nat_data = NULL;
907
908	/*
909	 * Restore the rule associated with this nat session
910	 */
911	if (in) {
912		KMALLOC(in, ipnat_t *);
913		if (in == NULL) {
914			error = ENOMEM;
915			goto junkput;
916		}
917		nat->nat_ptr = in;
918		bcopy((char *)&ipn.ipn_ipnat, (char *)in, sizeof(*in));
919		in->in_use = 1;
920		in->in_flags |= IPN_DELETE;
921		in->in_next = NULL;
922		in->in_rnext = NULL;
923		in->in_prnext = NULL;
924		in->in_mnext = NULL;
925		in->in_pmnext = NULL;
926		in->in_ifp = GETUNIT(in->in_ifname, 4);
927		if (in->in_plabel[0] != '\0') {
928			in->in_apr = appr_match(in->in_p, in->in_plabel);
929		}
930	}
931
932	/*
933	 * Restore ap_session_t structure.  Include the private data allocated
934	 * if it was there.
935	 */
936	if (aps) {
937		KMALLOC(aps, ap_session_t *);
938		if (aps == NULL) {
939			error = ENOMEM;
940			goto junkput;
941		}
942		nat->nat_aps = aps;
943		aps->aps_next = ap_sess_list;
944		ap_sess_list = aps;
945		bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps));
946		if (in)
947			aps->aps_apr = in->in_apr;
948		if (aps->aps_psiz) {
949			KMALLOCS(aps->aps_data, void *, aps->aps_psiz);
950			if (aps->aps_data == NULL) {
951				error = ENOMEM;
952				goto junkput;
953			}
954			bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data,
955			      aps->aps_psiz);
956		} else {
957			aps->aps_psiz = 0;
958			aps->aps_data = NULL;
959		}
960	}
961
962	/*
963	 * If there was a filtering rule associated with this entry then
964	 * build up a new one.
965	 */
966	if (fr != NULL) {
967		if (nat->nat_flags & FI_NEWFR) {
968			KMALLOC(fr, frentry_t *);
969			nat->nat_fr = fr;
970			if (fr == NULL) {
971				error = ENOMEM;
972				goto junkput;
973			}
974			bcopy((char *)&ipn.ipn_fr, (char *)fr, sizeof(*fr));
975			ipn.ipn_nat.nat_fr = fr;
976			error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn));
977			if (error) {
978				error = EFAULT;
979				goto junkput;
980			}
981		} else {
982			for (n = nat_instances; n; n = n->nat_next)
983				if (n->nat_fr == fr)
984					break;
985			if (!n) {
986				error = ESRCH;
987				goto junkput;
988			}
989		}
990	}
991
992	if (ipnn)
993		KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize);
994	nat_insert(nat);
995	return 0;
996junkput:
997	if (ipnn)
998		KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize);
999	if (nat)
1000		nat_delete(nat);
1001	return error;
1002}
1003
1004
1005/*
1006 * Delete a nat entry from the various lists and table.
1007 */
1008static void nat_delete(natd)
1009struct nat *natd;
1010{
1011	struct ipnat *ipn;
1012
1013	if (natd->nat_flags & FI_WILDP)
1014		nat_stats.ns_wilds--;
1015	if (natd->nat_hnext[0])
1016		natd->nat_hnext[0]->nat_phnext[0] = natd->nat_phnext[0];
1017	*natd->nat_phnext[0] = natd->nat_hnext[0];
1018	if (natd->nat_hnext[1])
1019		natd->nat_hnext[1]->nat_phnext[1] = natd->nat_phnext[1];
1020	*natd->nat_phnext[1] = natd->nat_hnext[1];
1021
1022	if (natd->nat_fr != NULL) {
1023		ATOMIC_DEC32(natd->nat_fr->fr_ref);
1024	}
1025
1026	if (natd->nat_hm != NULL)
1027		nat_hostmapdel(natd->nat_hm);
1028
1029	/*
1030	 * If there is an active reference from the nat entry to its parent
1031	 * rule, decrement the rule's reference count and free it too if no
1032	 * longer being used.
1033	 */
1034	ipn = natd->nat_ptr;
1035	if (ipn != NULL) {
1036		ipn->in_space++;
1037		ipn->in_use--;
1038		if (!ipn->in_use && (ipn->in_flags & IPN_DELETE)) {
1039			if (ipn->in_apr)
1040				appr_free(ipn->in_apr);
1041			KFREE(ipn);
1042			nat_stats.ns_rules--;
1043		}
1044	}
1045
1046	MUTEX_DESTROY(&natd->nat_lock);
1047	/*
1048	 * If there's a fragment table entry too for this nat entry, then
1049	 * dereference that as well.
1050	 */
1051	ipfr_forget((void *)natd);
1052	aps_free(natd->nat_aps);
1053	nat_stats.ns_inuse--;
1054	KFREE(natd);
1055}
1056
1057
1058/*
1059 * nat_flushtable - clear the NAT table of all mapping entries.
1060 */
1061static int nat_flushtable()
1062{
1063	register nat_t *nat, **natp;
1064	register int j = 0;
1065
1066	/*
1067	 * ALL NAT mappings deleted, so lets just make the deletions
1068	 * quicker.
1069	 */
1070	if (nat_table[0] != NULL)
1071		bzero((char *)nat_table[0],
1072		      sizeof(nat_table[0]) * ipf_nattable_sz);
1073	if (nat_table[1] != NULL)
1074		bzero((char *)nat_table[1],
1075		      sizeof(nat_table[1]) * ipf_nattable_sz);
1076
1077	for (natp = &nat_instances; (nat = *natp); ) {
1078		*natp = nat->nat_next;
1079#ifdef	IPFILTER_LOG
1080		nat_log(nat, NL_FLUSH);
1081#endif
1082		nat_delete(nat);
1083		j++;
1084	}
1085	nat_stats.ns_inuse = 0;
1086	return j;
1087}
1088
1089
1090/*
1091 * nat_clearlist - delete all rules in the active NAT mapping list.
1092 */
1093static int nat_clearlist()
1094{
1095	register ipnat_t *n, **np = &nat_list;
1096	int i = 0;
1097
1098	if (nat_rules != NULL)
1099		bzero((char *)nat_rules, sizeof(*nat_rules) * ipf_natrules_sz);
1100	if (rdr_rules != NULL)
1101		bzero((char *)rdr_rules, sizeof(*rdr_rules) * ipf_rdrrules_sz);
1102
1103	while ((n = *np)) {
1104		*np = n->in_next;
1105		if (!n->in_use) {
1106			if (n->in_apr)
1107				appr_free(n->in_apr);
1108			KFREE(n);
1109			nat_stats.ns_rules--;
1110		} else {
1111			n->in_flags |= IPN_DELETE;
1112			n->in_next = NULL;
1113		}
1114		i++;
1115	}
1116	nat_masks = 0;
1117	rdr_masks = 0;
1118	return i;
1119}
1120
1121
1122/*
1123 * Create a new NAT table entry.
1124 * NOTE: assumes write lock on ipf_nat has been obtained already.
1125 */
1126nat_t *nat_new(np, ip, fin, flags, direction)
1127ipnat_t *np;
1128ip_t *ip;
1129fr_info_t *fin;
1130u_int flags;
1131int direction;
1132{
1133	register u_32_t sum1, sum2, sumd, l;
1134	u_short port = 0, sport = 0, dport = 0, nport = 0;
1135	struct in_addr in, inb;
1136	tcphdr_t *tcp = NULL;
1137	hostmap_t *hm = NULL;
1138	nat_t *nat, *natl;
1139	u_short nflags;
1140#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
1141	qif_t *qf = fin->fin_qif;
1142#endif
1143
1144	nflags = flags & np->in_flags;
1145	if (flags & IPN_TCPUDP) {
1146		tcp = (tcphdr_t *)fin->fin_dp;
1147		sport = tcp->th_sport;
1148		dport = tcp->th_dport;
1149	}
1150
1151	/* Give me a new nat */
1152	KMALLOC(nat, nat_t *);
1153	if (nat == NULL) {
1154		nat_stats.ns_memfail++;
1155		return NULL;
1156	}
1157
1158	bzero((char *)nat, sizeof(*nat));
1159	nat->nat_flags = flags;
1160	if (flags & FI_WILDP)
1161		nat_stats.ns_wilds++;
1162	/*
1163	 * Search the current table for a match.
1164	 */
1165	if (direction == NAT_OUTBOUND) {
1166		/*
1167		 * Values at which the search for a free resouce starts.
1168		 */
1169		u_32_t st_ip;
1170		u_short st_port;
1171
1172		/*
1173		 * If it's an outbound packet which doesn't match any existing
1174		 * record, then create a new port
1175		 */
1176		l = 0;
1177		st_ip = np->in_nip;
1178		st_port = np->in_pnext;
1179
1180		do {
1181			port = 0;
1182			in.s_addr = htonl(np->in_nip);
1183			if (l == 0) {
1184				/*
1185				 * Check to see if there is an existing NAT
1186				 * setup for this IP address pair.
1187				 */
1188				hm = nat_hostmap(np, ip->ip_src, in);
1189				if (hm != NULL)
1190					in.s_addr = hm->hm_mapip.s_addr;
1191			} else if ((l == 1) && (hm != NULL)) {
1192				nat_hostmapdel(hm);
1193				hm = NULL;
1194			}
1195			in.s_addr = ntohl(in.s_addr);
1196
1197			nat->nat_hm = hm;
1198
1199			if ((np->in_outmsk == 0xffffffff) &&
1200			    (np->in_pnext == 0)) {
1201				if (l > 0)
1202					goto badnat;
1203			}
1204
1205			if (np->in_redir & NAT_MAPBLK) {
1206				if ((l >= np->in_ppip) || ((l > 0) &&
1207				     !(flags & IPN_TCPUDP)))
1208					goto badnat;
1209				/*
1210				 * map-block - Calculate destination address.
1211				 */
1212				in.s_addr = ntohl(ip->ip_src.s_addr);
1213				in.s_addr &= ntohl(~np->in_inmsk);
1214				inb.s_addr = in.s_addr;
1215				in.s_addr /= np->in_ippip;
1216				in.s_addr &= ntohl(~np->in_outmsk);
1217				in.s_addr += ntohl(np->in_outip);
1218				/*
1219				 * Calculate destination port.
1220				 */
1221				if ((flags & IPN_TCPUDP) &&
1222				    (np->in_ppip != 0)) {
1223					port = ntohs(sport) + l;
1224					port %= np->in_ppip;
1225					port += np->in_ppip *
1226						(inb.s_addr % np->in_ippip);
1227					port += MAPBLK_MINPORT;
1228					port = htons(port);
1229				}
1230			} else if (!np->in_outip &&
1231				   (np->in_outmsk == 0xffffffff)) {
1232				/*
1233				 * 0/32 - use the interface's IP address.
1234				 */
1235				if ((l > 0) ||
1236				    fr_ifpaddr(4, fin->fin_ifp, &in) == -1)
1237					goto badnat;
1238				in.s_addr = ntohl(in.s_addr);
1239			} else if (!np->in_outip && !np->in_outmsk) {
1240				/*
1241				 * 0/0 - use the original source address/port.
1242				 */
1243				if (l > 0)
1244					goto badnat;
1245				in.s_addr = ntohl(ip->ip_src.s_addr);
1246			} else if ((np->in_outmsk != 0xffffffff) &&
1247				   (np->in_pnext == 0) &&
1248				   ((l > 0) || (hm == NULL)))
1249				np->in_nip++;
1250			natl = NULL;
1251
1252			if ((nflags & IPN_TCPUDP) &&
1253			    ((np->in_redir & NAT_MAPBLK) == 0) &&
1254			    (np->in_flags & IPN_AUTOPORTMAP)) {
1255				if ((l > 0) && (l % np->in_ppip == 0)) {
1256					if (l > np->in_space) {
1257						goto badnat;
1258					} else if ((l > np->in_ppip) &&
1259						   np->in_outmsk != 0xffffffff)
1260						np->in_nip++;
1261				}
1262				if (np->in_ppip != 0) {
1263					port = ntohs(sport);
1264					port += (l % np->in_ppip);
1265					port %= np->in_ppip;
1266					port += np->in_ppip *
1267						(ntohl(ip->ip_src.s_addr) %
1268						 np->in_ippip);
1269					port += MAPBLK_MINPORT;
1270					port = htons(port);
1271				}
1272			} else if (((np->in_redir & NAT_MAPBLK) == 0) &&
1273				   (nflags & IPN_TCPUDP) &&
1274				   (np->in_pnext != 0)) {
1275				port = htons(np->in_pnext++);
1276				if (np->in_pnext > ntohs(np->in_pmax)) {
1277					np->in_pnext = ntohs(np->in_pmin);
1278					if (np->in_outmsk != 0xffffffff)
1279						np->in_nip++;
1280				}
1281			}
1282
1283			if (np->in_flags & IPN_IPRANGE) {
1284				if (np->in_nip > ntohl(np->in_outmsk))
1285					np->in_nip = ntohl(np->in_outip);
1286			} else {
1287				if ((np->in_outmsk != 0xffffffff) &&
1288				    ((np->in_nip + 1) & ntohl(np->in_outmsk)) >
1289				    ntohl(np->in_outip))
1290					np->in_nip = ntohl(np->in_outip) + 1;
1291			}
1292
1293			if (!port && (flags & IPN_TCPUDP))
1294				port = sport;
1295
1296			/*
1297			 * Here we do a lookup of the connection as seen from
1298			 * the outside.  If an IP# pair already exists, try
1299			 * again.  So if you have A->B becomes C->B, you can
1300			 * also have D->E become C->E but not D->B causing
1301			 * another C->B.  Also take protocol and ports into
1302			 * account when determining whether a pre-existing
1303			 * NAT setup will cause an external conflict where
1304			 * this is appropriate.
1305			 */
1306			inb.s_addr = htonl(in.s_addr);
1307			natl = nat_inlookup(fin->fin_ifp, flags & ~FI_WILDP,
1308					    (u_int)ip->ip_p, ip->ip_dst, inb,
1309					    (port << 16) | dport, 1);
1310
1311			/*
1312			 * Has the search wrapped around and come back to the
1313			 * start ?
1314			 */
1315			if ((natl != NULL) &&
1316			    (np->in_pnext != 0) && (st_port == np->in_pnext) &&
1317			    (np->in_nip != 0) && (st_ip == np->in_nip))
1318				goto badnat;
1319			l++;
1320		} while (natl != NULL);
1321
1322		if (np->in_space > 0)
1323			np->in_space--;
1324
1325		/* Setup the NAT table */
1326		nat->nat_inip = ip->ip_src;
1327		nat->nat_outip.s_addr = htonl(in.s_addr);
1328		nat->nat_oip = ip->ip_dst;
1329		if (nat->nat_hm == NULL)
1330			nat->nat_hm = nat_hostmap(np, ip->ip_src,
1331						  nat->nat_outip);
1332
1333		sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)) + ntohs(sport);
1334		sum2 = LONG_SUM(in.s_addr) + ntohs(port);
1335
1336		if (flags & IPN_TCPUDP) {
1337			nat->nat_inport = sport;
1338			nat->nat_outport = port;	/* sport */
1339			nat->nat_oport = dport;
1340		}
1341	} else {
1342		/*
1343		 * Otherwise, it's an inbound packet. Most likely, we don't
1344		 * want to rewrite source ports and source addresses. Instead,
1345		 * we want to rewrite to a fixed internal address and fixed
1346		 * internal port.
1347		 */
1348		if (np->in_flags & IPN_SPLIT) {
1349			in.s_addr = np->in_nip;
1350			if (np->in_inip == htonl(in.s_addr))
1351				np->in_nip = ntohl(np->in_inmsk);
1352			else {
1353				np->in_nip = ntohl(np->in_inip);
1354				if (np->in_flags & IPN_ROUNDR) {
1355					nat_delrdr(np);
1356					nat_addrdr(np);
1357				}
1358			}
1359		} else {
1360			in.s_addr = ntohl(np->in_inip);
1361			if (np->in_flags & IPN_ROUNDR) {
1362				nat_delrdr(np);
1363				nat_addrdr(np);
1364			}
1365		}
1366		if (!np->in_pnext)
1367			nport = dport;
1368		else {
1369			/*
1370			 * Whilst not optimized for the case where
1371			 * pmin == pmax, the gain is not significant.
1372			 */
1373			nport = ntohs(dport) - ntohs(np->in_pmin) +
1374				ntohs(np->in_pnext);
1375			nport = htons(nport);
1376		}
1377
1378		/*
1379		 * When the redirect-to address is set to 0.0.0.0, just
1380		 * assume a blank `forwarding' of the packet.  We don't
1381		 * setup any translation for this either.
1382		 */
1383		if (in.s_addr == 0) {
1384			if (nport == dport)
1385				goto badnat;
1386			in.s_addr = ntohl(ip->ip_dst.s_addr);
1387		}
1388
1389		nat->nat_inip.s_addr = htonl(in.s_addr);
1390		nat->nat_outip = ip->ip_dst;
1391		nat->nat_oip = ip->ip_src;
1392
1393		sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr)) + ntohs(dport);
1394		sum2 = LONG_SUM(in.s_addr) + ntohs(nport);
1395
1396		if (flags & IPN_TCPUDP) {
1397			nat->nat_inport = nport;
1398			nat->nat_outport = dport;
1399			nat->nat_oport = sport;
1400		}
1401	}
1402
1403	CALC_SUMD(sum1, sum2, sumd);
1404	nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
1405#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
1406	if ((flags & IPN_TCPUDP) && dohwcksum &&
1407	    (qf->qf_ill->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) {
1408		if (direction == NAT_OUTBOUND)
1409			sum1 = LONG_SUM(ntohl(in.s_addr));
1410		else
1411			sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr));
1412		sum1 += LONG_SUM(ntohl(ip->ip_dst.s_addr));
1413		sum1 += IPPROTO_TCP;
1414		sum1 = (sum1 & 0xffff) + (sum1 >> 16);
1415		nat->nat_sumd[1] = NAT_HW_CKSUM|(sum1 & 0xffff);
1416	} else
1417#endif
1418		nat->nat_sumd[1] = nat->nat_sumd[0];
1419
1420	if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) {
1421		if (direction == NAT_OUTBOUND)
1422			sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr));
1423		else
1424			sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr));
1425
1426		sum2 = LONG_SUM(in.s_addr);
1427
1428		CALC_SUMD(sum1, sum2, sumd);
1429		nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
1430	} else
1431		nat->nat_ipsumd = nat->nat_sumd[0];
1432
1433	in.s_addr = htonl(in.s_addr);
1434
1435#ifdef  _KERNEL
1436	strncpy(nat->nat_ifname, IFNAME(fin->fin_ifp), IFNAMSIZ);
1437#endif
1438	nat_insert(nat);
1439
1440	nat->nat_dir = direction;
1441	nat->nat_ifp = fin->fin_ifp;
1442	nat->nat_ptr = np;
1443	nat->nat_p = ip->ip_p;
1444	nat->nat_bytes = 0;
1445	nat->nat_pkts = 0;
1446	nat->nat_fr = fin->fin_fr;
1447	if (nat->nat_fr != NULL) {
1448		ATOMIC_INC32(nat->nat_fr->fr_ref);
1449	}
1450	if (direction == NAT_OUTBOUND) {
1451		if (flags & IPN_TCPUDP)
1452			tcp->th_sport = port;
1453	} else {
1454		if (flags & IPN_TCPUDP)
1455			tcp->th_dport = nport;
1456	}
1457	np->in_use++;
1458#ifdef	IPFILTER_LOG
1459	nat_log(nat, (u_int)np->in_redir);
1460#endif
1461	return nat;
1462badnat:
1463	nat_stats.ns_badnat++;
1464	if ((hm = nat->nat_hm) != NULL)
1465		nat_hostmapdel(hm);
1466	KFREE(nat);
1467	return NULL;
1468}
1469
1470
1471void	nat_insert(nat)
1472nat_t	*nat;
1473{
1474	u_int hv1, hv2;
1475	nat_t **natp;
1476
1477	MUTEX_INIT(&nat->nat_lock, "nat entry lock", NULL);
1478
1479	nat->nat_age = fr_defnatage;
1480	nat->nat_ifname[sizeof(nat->nat_ifname) - 1] = '\0';
1481	if (nat->nat_ifname[0] !='\0') {
1482		nat->nat_ifp = GETUNIT(nat->nat_ifname, 4);
1483	}
1484
1485	nat->nat_next = nat_instances;
1486	nat_instances = nat;
1487
1488	if (!(nat->nat_flags & (FI_W_SPORT|FI_W_DPORT))) {
1489		hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport,
1490				  0xffffffff);
1491		hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport,
1492				  ipf_nattable_sz);
1493		hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport,
1494				  0xffffffff);
1495		hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport,
1496				 ipf_nattable_sz);
1497	} else {
1498		hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff);
1499		hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1, ipf_nattable_sz);
1500		hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff);
1501		hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2, ipf_nattable_sz);
1502	}
1503
1504	natp = &nat_table[0][hv1];
1505	if (*natp)
1506		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
1507	nat->nat_phnext[0] = natp;
1508	nat->nat_hnext[0] = *natp;
1509	*natp = nat;
1510
1511	natp = &nat_table[1][hv2];
1512	if (*natp)
1513		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
1514	nat->nat_phnext[1] = natp;
1515	nat->nat_hnext[1] = *natp;
1516	*natp = nat;
1517
1518	nat_stats.ns_added++;
1519	nat_stats.ns_inuse++;
1520}
1521
1522
1523nat_t *nat_icmplookup(ip, fin, dir)
1524ip_t *ip;
1525fr_info_t *fin;
1526int dir;
1527{
1528	icmphdr_t *icmp;
1529	tcphdr_t *tcp = NULL;
1530	ip_t *oip;
1531	int flags = 0, type, minlen;
1532
1533	icmp = (icmphdr_t *)fin->fin_dp;
1534	/*
1535	 * Does it at least have the return (basic) IP header ?
1536	 * Only a basic IP header (no options) should be with an ICMP error
1537	 * header.
1538	 */
1539	if ((ip->ip_hl != 5) || (ip->ip_len < ICMPERR_MINPKTLEN))
1540		return NULL;
1541	type = icmp->icmp_type;
1542	/*
1543	 * If it's not an error type, then return.
1544	 */
1545	if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) &&
1546	    (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) &&
1547	    (type != ICMP_PARAMPROB))
1548		return NULL;
1549
1550	oip = (ip_t *)((char *)fin->fin_dp + 8);
1551	minlen = (oip->ip_hl << 2);
1552	if (minlen < sizeof(ip_t))
1553		return NULL;
1554	if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen)
1555		return NULL;
1556	/*
1557	 * Is the buffer big enough for all of it ?  It's the size of the IP
1558	 * header claimed in the encapsulated part which is of concern.  It
1559	 * may be too big to be in this buffer but not so big that it's
1560	 * outside the ICMP packet, leading to TCP deref's causing problems.
1561	 * This is possible because we don't know how big oip_hl is when we
1562	 * do the pullup early in fr_check() and thus can't gaurantee it is
1563	 * all here now.
1564	 */
1565#ifdef  _KERNEL
1566	{
1567	mb_t *m;
1568
1569# if SOLARIS
1570	m = fin->fin_qfm;
1571	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr)
1572		return NULL;
1573# else
1574	m = *(mb_t **)fin->fin_mp;
1575	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
1576	    (char *)ip + m->m_len)
1577		return NULL;
1578# endif
1579	}
1580#endif
1581
1582	if (oip->ip_p == IPPROTO_TCP)
1583		flags = IPN_TCP;
1584	else if (oip->ip_p == IPPROTO_UDP)
1585		flags = IPN_UDP;
1586	if (flags & IPN_TCPUDP) {
1587		minlen += 8;		/* + 64bits of data to get ports */
1588		if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen)
1589			return NULL;
1590		tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2));
1591		if (dir == NAT_INBOUND)
1592			return nat_inlookup(fin->fin_ifp, flags,
1593				(u_int)oip->ip_p, oip->ip_dst, oip->ip_src,
1594				(tcp->th_sport << 16) | tcp->th_dport, 0);
1595		else
1596			return nat_outlookup(fin->fin_ifp, flags,
1597				(u_int)oip->ip_p, oip->ip_dst, oip->ip_src,
1598				(tcp->th_sport << 16) | tcp->th_dport, 0);
1599	}
1600	if (dir == NAT_INBOUND)
1601		return nat_inlookup(fin->fin_ifp, 0, (u_int)oip->ip_p,
1602			oip->ip_dst, oip->ip_src, 0, 0);
1603	else
1604		return nat_outlookup(fin->fin_ifp, 0, (u_int)oip->ip_p,
1605			oip->ip_dst, oip->ip_src, 0, 0);
1606}
1607
1608
1609/*
1610 * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP
1611 * packet gets correctly recognised.
1612 */
1613nat_t *nat_icmp(ip, fin, nflags, dir)
1614ip_t *ip;
1615fr_info_t *fin;
1616u_int *nflags;
1617int dir;
1618{
1619	u_32_t sum1, sum2, sumd, sumd2 = 0;
1620	struct in_addr in;
1621	icmphdr_t *icmp;
1622	udphdr_t *udp;
1623	nat_t *nat;
1624	ip_t *oip;
1625	int flags = 0;
1626
1627	if ((fin->fin_fl & FI_SHORT) || (fin->fin_off != 0))
1628		return NULL;
1629	/*
1630	 * nat_icmplookup() will return NULL for `defective' packets.
1631	 */
1632	if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir)))
1633		return NULL;
1634	*nflags = IPN_ICMPERR;
1635	icmp = (icmphdr_t *)fin->fin_dp;
1636	oip = (ip_t *)&icmp->icmp_ip;
1637	if (oip->ip_p == IPPROTO_TCP)
1638		flags = IPN_TCP;
1639	else if (oip->ip_p == IPPROTO_UDP)
1640		flags = IPN_UDP;
1641	udp = (udphdr_t *)((((char *)oip) + (oip->ip_hl << 2)));
1642	/*
1643	 * Need to adjust ICMP header to include the real IP#'s and
1644	 * port #'s.  Only apply a checksum change relative to the
1645	 * IP address change as it will be modified again in ip_natout
1646	 * for both address and port.  Two checksum changes are
1647	 * necessary for the two header address changes.  Be careful
1648	 * to only modify the checksum once for the port # and twice
1649	 * for the IP#.
1650	 */
1651
1652	/*
1653	 * Step 1
1654	 * Fix the IP addresses in the offending IP packet. You also need
1655	 * to adjust the IP header checksum of that offending IP packet
1656	 * and the ICMP checksum of the ICMP error message itself.
1657	 *
1658	 * Unfortunately, for UDP and TCP, the IP addresses are also contained
1659	 * in the pseudo header that is used to compute the UDP resp. TCP
1660	 * checksum. So, we must compensate that as well. Even worse, the
1661	 * change in the UDP and TCP checksums require yet another
1662	 * adjustment of the ICMP checksum of the ICMP error message.
1663	 *
1664	 * For the moment we forget about TCP, because that checksum is not
1665	 * in the first 8 bytes, so it will not be available in most cases.
1666	 */
1667
1668	if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) {
1669		sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr));
1670		in = nat->nat_inip;
1671		oip->ip_src = in;
1672	} else {
1673		sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr));
1674		in = nat->nat_outip;
1675		oip->ip_dst = in;
1676	}
1677
1678	sum2 = LONG_SUM(ntohl(in.s_addr));
1679
1680	CALC_SUMD(sum1, sum2, sumd);
1681
1682	if (nat->nat_dir == NAT_OUTBOUND) {
1683		/*
1684		 * Fix IP checksum of the offending IP packet to adjust for
1685		 * the change in the IP address.
1686		 *
1687		 * Normally, you would expect that the ICMP checksum of the
1688		 * ICMP error message needs to be adjusted as well for the
1689		 * IP address change in oip.
1690		 * However, this is a NOP, because the ICMP checksum is
1691		 * calculated over the complete ICMP packet, which includes the
1692		 * changed oip IP addresses and oip->ip_sum. However, these
1693		 * two changes cancel each other out (if the delta for
1694		 * the IP address is x, then the delta for ip_sum is minus x),
1695		 * so no change in the icmp_cksum is necessary.
1696		 *
1697		 * Be careful that nat_dir refers to the direction of the
1698		 * offending IP packet (oip), not to its ICMP response (icmp)
1699		 */
1700		fix_datacksum(&oip->ip_sum, sumd);
1701
1702		/*
1703		 * Fix UDP pseudo header checksum to compensate for the
1704		 * IP address change.
1705		 */
1706		if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
1707			/*
1708			 * The UDP checksum is optional, only adjust it
1709			 * if it has been set.
1710			 */
1711			sum1 = ntohs(udp->uh_sum);
1712			fix_datacksum(&udp->uh_sum, sumd);
1713			sum2 = ntohs(udp->uh_sum);
1714
1715			/*
1716			 * Fix ICMP checksum to compensate the UDP
1717			 * checksum adjustment.
1718			 */
1719			CALC_SUMD(sum1, sum2, sumd);
1720			sumd2 = sumd;
1721		}
1722
1723#if 0
1724		/*
1725		 * Fix TCP pseudo header checksum to compensate for the
1726		 * IP address change. Before we can do the change, we
1727		 * must make sure that oip is sufficient large to hold
1728		 * the TCP checksum (normally it does not!).
1729		 */
1730		if (oip->ip_p == IPPROTO_TCP) {
1731
1732		}
1733#endif
1734	} else {
1735
1736		/*
1737		 * Fix IP checksum of the offending IP packet to adjust for
1738		 * the change in the IP address.
1739		 *
1740		 * Normally, you would expect that the ICMP checksum of the
1741		 * ICMP error message needs to be adjusted as well for the
1742		 * IP address change in oip.
1743		 * However, this is a NOP, because the ICMP checksum is
1744		 * calculated over the complete ICMP packet, which includes the
1745		 * changed oip IP addresses and oip->ip_sum. However, these
1746		 * two changes cancel each other out (if the delta for
1747		 * the IP address is x, then the delta for ip_sum is minus x),
1748		 * so no change in the icmp_cksum is necessary.
1749		 *
1750		 * Be careful that nat_dir refers to the direction of the
1751		 * offending IP packet (oip), not to its ICMP response (icmp)
1752		 */
1753		fix_datacksum(&oip->ip_sum, sumd);
1754
1755/* XXX FV : without having looked at Solaris source code, it seems unlikely
1756 * that SOLARIS would compensate this in the kernel (a body of an IP packet
1757 * in the data section of an ICMP packet). I have the feeling that this should
1758 * be unconditional, but I'm not in a position to check.
1759 */
1760#if !SOLARIS && !defined(__sgi)
1761		/*
1762		 * Fix UDP pseudo header checksum to compensate for the
1763		 * IP address change.
1764		 */
1765		if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
1766			/*
1767			 * The UDP checksum is optional, only adjust it
1768			 * if it has been set
1769			 */
1770			sum1 = ntohs(udp->uh_sum);
1771			fix_datacksum(&udp->uh_sum, sumd);
1772			sum2 = ntohs(udp->uh_sum);
1773
1774			/*
1775			 * Fix ICMP checksum to compensate the UDP
1776			 * checksum adjustment.
1777			 */
1778			CALC_SUMD(sum1, sum2, sumd);
1779			sumd2 = sumd;
1780		}
1781
1782#if 0
1783		/*
1784		 * Fix TCP pseudo header checksum to compensate for the
1785		 * IP address change. Before we can do the change, we
1786		 * must make sure that oip is sufficient large to hold
1787		 * the TCP checksum (normally it does not!).
1788		 */
1789		if (oip->ip_p == IPPROTO_TCP) {
1790
1791		};
1792#endif
1793
1794#endif
1795	}
1796
1797	if ((flags & IPN_TCPUDP) != 0) {
1798		tcphdr_t *tcp;
1799
1800		/*
1801		 * XXX - what if this is bogus hl and we go off the end ?
1802		 * In this case, nat_icmpinlookup() will have returned NULL.
1803		 */
1804		tcp = (tcphdr_t *)udp;
1805
1806		/*
1807		 * Step 2 :
1808		 * For offending TCP/UDP IP packets, translate the ports as
1809		 * well, based on the NAT specification. Of course such
1810		 * a change must be reflected in the ICMP checksum as well.
1811		 *
1812		 * Advance notice : Now it becomes complicated :-)
1813		 *
1814		 * Since the port fields are part of the TCP/UDP checksum
1815		 * of the offending IP packet, you need to adjust that checksum
1816		 * as well... but, if you change, you must change the icmp
1817		 * checksum *again*, to reflect that change.
1818		 *
1819		 * To further complicate: the TCP checksum is not in the first
1820		 * 8 bytes of the offending ip packet, so it most likely is not
1821		 * available (we might have to fix that if the encounter a
1822		 * device that returns more than 8 data bytes on icmp error)
1823		 */
1824
1825		if (nat->nat_oport == tcp->th_dport) {
1826			if (tcp->th_sport != nat->nat_inport) {
1827				/*
1828				 * Fix ICMP checksum to compensate port
1829				 * adjustment.
1830				 */
1831				sum1 = ntohs(tcp->th_sport);
1832				sum2 = ntohs(nat->nat_inport);
1833				CALC_SUMD(sum1, sum2, sumd);
1834				sumd2 += sumd;
1835				tcp->th_sport = nat->nat_inport;
1836
1837				/*
1838				 * Fix udp checksum to compensate port
1839				 * adjustment.  NOTE : the offending IP packet
1840				 * flows the other direction compared to the
1841				 * ICMP message.
1842				 *
1843				 * The UDP checksum is optional, only adjust
1844				 * it if it has been set.
1845				 */
1846				if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
1847
1848					sum1 = ntohs(udp->uh_sum);
1849					fix_datacksum(&udp->uh_sum, sumd);
1850					sum2 = ntohs(udp->uh_sum);
1851
1852					/*
1853					 * Fix ICMP checksum to
1854					 * compensate UDP checksum
1855					 * adjustment.
1856					 */
1857					CALC_SUMD(sum1, sum2, sumd);
1858					sumd2 += sumd;
1859				}
1860			}
1861		} else {
1862			if (tcp->th_dport != nat->nat_outport) {
1863				/*
1864				 * Fix ICMP checksum to compensate port
1865				 * adjustment.
1866				 */
1867				sum1 = ntohs(tcp->th_dport);
1868				sum2 = ntohs(nat->nat_outport);
1869				CALC_SUMD(sum1, sum2, sumd);
1870				sumd2 += sumd;
1871				tcp->th_dport = nat->nat_outport;
1872
1873				/*
1874				 * Fix udp checksum to compensate port
1875				 * adjustment.   NOTE : the offending IP
1876				 * packet flows the other direction compared
1877				 * to the ICMP message.
1878				 *
1879				 * The UDP checksum is optional, only adjust
1880				 * it if it has been set.
1881				 */
1882				if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) {
1883
1884					sum1 = ntohs(udp->uh_sum);
1885					fix_datacksum(&udp->uh_sum, sumd);
1886					sum2 = ntohs(udp->uh_sum);
1887
1888					/*
1889					 * Fix ICMP checksum to compensate
1890					 * UDP checksum adjustment.
1891					 */
1892					CALC_SUMD(sum1, sum2, sumd);
1893					sumd2 += sumd;
1894				}
1895			}
1896		}
1897		if (sumd2) {
1898			sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
1899			sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
1900			if (nat->nat_dir == NAT_OUTBOUND) {
1901				fix_outcksum(fin, &icmp->icmp_cksum, sumd2);
1902			} else {
1903				fix_incksum(fin, &icmp->icmp_cksum, sumd2);
1904			}
1905		}
1906	}
1907	if (oip->ip_p == IPPROTO_ICMP)
1908		nat->nat_age = fr_defnaticmpage;
1909	return nat;
1910}
1911
1912
1913/*
1914 * NB: these lookups don't lock access to the list, it assume it has already
1915 * been done!
1916 */
1917/*
1918 * Lookup a nat entry based on the mapped destination ip address/port and
1919 * real source address/port.  We use this lookup when receiving a packet,
1920 * we're looking for a table entry, based on the destination address.
1921 * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
1922 */
1923nat_t *nat_inlookup(ifp, flags, p, src, mapdst, ports, rw)
1924void *ifp;
1925register u_int flags, p;
1926struct in_addr src , mapdst;
1927u_32_t ports;
1928int rw;
1929{
1930	register u_short sport, dport;
1931	register nat_t *nat;
1932	register int nflags;
1933	register u_32_t dst;
1934	u_int hv;
1935
1936	dst = mapdst.s_addr;
1937	dport = ports >> 16;
1938	sport = ports & 0xffff;
1939	flags &= IPN_TCPUDP;
1940
1941	hv = NAT_HASH_FN(dst, dport, 0xffffffff);
1942	hv = NAT_HASH_FN(src.s_addr, hv + sport, ipf_nattable_sz);
1943	nat = nat_table[1][hv];
1944	for (; nat; nat = nat->nat_hnext[1]) {
1945		nflags = nat->nat_flags;
1946		if ((!ifp || ifp == nat->nat_ifp) &&
1947		    nat->nat_oip.s_addr == src.s_addr &&
1948		    nat->nat_outip.s_addr == dst &&
1949		    (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP)))
1950		     || (p == nat->nat_p)) && (!flags ||
1951		     (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) &&
1952		      ((nat->nat_outport == dport) || (nflags & FI_W_SPORT)))))
1953			return nat;
1954	}
1955	if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP))
1956		return NULL;
1957	if (!rw) {
1958		RWLOCK_EXIT(&ipf_nat);
1959	}
1960	hv = NAT_HASH_FN(dst, 0, 0xffffffff);
1961	hv = NAT_HASH_FN(src.s_addr, hv, ipf_nattable_sz);
1962	if (!rw) {
1963		WRITE_ENTER(&ipf_nat);
1964	}
1965	nat = nat_table[1][hv];
1966	for (; nat; nat = nat->nat_hnext[1]) {
1967		nflags = nat->nat_flags;
1968		if (ifp && ifp != nat->nat_ifp)
1969			continue;
1970		if (!(nflags & IPN_TCPUDP))
1971			continue;
1972		if (!(nflags & FI_WILDP))
1973			continue;
1974		if (nat->nat_oip.s_addr != src.s_addr ||
1975		    nat->nat_outip.s_addr != dst)
1976			continue;
1977		if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) &&
1978		    ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) {
1979			nat_tabmove(nat, ports);
1980			break;
1981		}
1982	}
1983	if (!rw) {
1984		MUTEX_DOWNGRADE(&ipf_nat);
1985	}
1986	return nat;
1987}
1988
1989
1990/*
1991 * This function is only called for TCP/UDP NAT table entries where the
1992 * original was placed in the table without hashing on the ports and we now
1993 * want to include hashing on port numbers.
1994 */
1995static void nat_tabmove(nat, ports)
1996nat_t *nat;
1997u_32_t ports;
1998{
1999	register u_short sport, dport;
2000	nat_t **natp;
2001	u_int hv;
2002
2003	dport = ports >> 16;
2004	sport = ports & 0xffff;
2005
2006	if (nat->nat_oport == dport) {
2007		nat->nat_inport = sport;
2008		nat->nat_outport = sport;
2009	}
2010
2011	/*
2012	 * Remove the NAT entry from the old location
2013	 */
2014	if (nat->nat_hnext[0])
2015		nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
2016	*nat->nat_phnext[0] = nat->nat_hnext[0];
2017
2018	if (nat->nat_hnext[1])
2019		nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
2020	*nat->nat_phnext[1] = nat->nat_hnext[1];
2021
2022	/*
2023	 * Add into the NAT table in the new position
2024	 */
2025	hv = NAT_HASH_FN(nat->nat_inip.s_addr, sport, 0xffffffff);
2026	hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + dport, ipf_nattable_sz);
2027	natp = &nat_table[0][hv];
2028	if (*natp)
2029		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
2030	nat->nat_phnext[0] = natp;
2031	nat->nat_hnext[0] = *natp;
2032	*natp = nat;
2033
2034	hv = NAT_HASH_FN(nat->nat_outip.s_addr, sport, 0xffffffff);
2035	hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + dport, ipf_nattable_sz);
2036	natp = &nat_table[1][hv];
2037	if (*natp)
2038		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
2039	nat->nat_phnext[1] = natp;
2040	nat->nat_hnext[1] = *natp;
2041	*natp = nat;
2042}
2043
2044
2045/*
2046 * Lookup a nat entry based on the source 'real' ip address/port and
2047 * destination address/port.  We use this lookup when sending a packet out,
2048 * we're looking for a table entry, based on the source address.
2049 * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
2050 */
2051nat_t *nat_outlookup(ifp, flags, p, src, dst, ports, rw)
2052void *ifp;
2053register u_int flags, p;
2054struct in_addr src , dst;
2055u_32_t ports;
2056int rw;
2057{
2058	register u_short sport, dport;
2059	register nat_t *nat;
2060	register int nflags;
2061	u_32_t srcip;
2062	u_int hv;
2063
2064	sport = ports & 0xffff;
2065	dport = ports >> 16;
2066	flags &= IPN_TCPUDP;
2067	srcip = src.s_addr;
2068
2069	hv = NAT_HASH_FN(srcip, sport, 0xffffffff);
2070	hv = NAT_HASH_FN(dst.s_addr, hv + dport, ipf_nattable_sz);
2071	nat = nat_table[0][hv];
2072	for (; nat; nat = nat->nat_hnext[0]) {
2073		nflags = nat->nat_flags;
2074
2075		if ((!ifp || ifp == nat->nat_ifp) &&
2076		    nat->nat_inip.s_addr == srcip &&
2077		    nat->nat_oip.s_addr == dst.s_addr &&
2078		    (((p == 0) && (flags == (nflags & IPN_TCPUDP)))
2079		     || (p == nat->nat_p)) && (!flags ||
2080		     ((nat->nat_inport == sport || nflags & FI_W_SPORT) &&
2081		      (nat->nat_oport == dport || nflags & FI_W_DPORT))))
2082			return nat;
2083	}
2084	if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP))
2085		return NULL;
2086	if (!rw) {
2087		RWLOCK_EXIT(&ipf_nat);
2088	}
2089	hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz);
2090	hv = NAT_HASH_FN(dst.s_addr, hv, ipf_nattable_sz);
2091	if (!rw) {
2092		WRITE_ENTER(&ipf_nat);
2093	}
2094	nat = nat_table[0][hv];
2095	for (; nat; nat = nat->nat_hnext[0]) {
2096		nflags = nat->nat_flags;
2097		if (ifp && ifp != nat->nat_ifp)
2098			continue;
2099		if (!(nflags & IPN_TCPUDP))
2100			continue;
2101		if (!(nflags & FI_WILDP))
2102			continue;
2103		if ((nat->nat_inip.s_addr != srcip) ||
2104		    (nat->nat_oip.s_addr != dst.s_addr))
2105			continue;
2106		if (((nat->nat_inport == sport) || (nflags & FI_W_SPORT)) &&
2107		    ((nat->nat_oport == dport) || (nflags & FI_W_DPORT))) {
2108			nat_tabmove(nat, ports);
2109			break;
2110		}
2111	}
2112	if (!rw) {
2113		MUTEX_DOWNGRADE(&ipf_nat);
2114	}
2115	return nat;
2116}
2117
2118
2119/*
2120 * Lookup the NAT tables to search for a matching redirect
2121 */
2122nat_t *nat_lookupredir(np)
2123register natlookup_t *np;
2124{
2125	u_32_t ports;
2126	nat_t *nat;
2127
2128	ports = (np->nl_outport << 16) | np->nl_inport;
2129	/*
2130	 * If nl_inip is non null, this is a lookup based on the real
2131	 * ip address. Else, we use the fake.
2132	 */
2133	if ((nat = nat_outlookup(NULL, np->nl_flags, 0, np->nl_inip,
2134				 np->nl_outip, ports, 0))) {
2135		np->nl_realip = nat->nat_outip;
2136		np->nl_realport = nat->nat_outport;
2137	}
2138	return nat;
2139}
2140
2141
2142static int nat_match(fin, np, ip)
2143fr_info_t *fin;
2144ipnat_t *np;
2145ip_t *ip;
2146{
2147	frtuc_t *ft;
2148
2149	if (ip->ip_v != 4)
2150		return 0;
2151
2152	if (np->in_p && ip->ip_p != np->in_p)
2153		return 0;
2154	if (fin->fin_out) {
2155		if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK)))
2156			return 0;
2157		if (((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip)
2158		    ^ ((np->in_flags & IPN_NOTSRC) != 0))
2159			return 0;
2160		if (((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip)
2161		    ^ ((np->in_flags & IPN_NOTDST) != 0))
2162			return 0;
2163	} else {
2164		if (!(np->in_redir & NAT_REDIRECT))
2165			return 0;
2166		if (((fin->fin_fi.fi_saddr & np->in_srcmsk) != np->in_srcip)
2167		    ^ ((np->in_flags & IPN_NOTSRC) != 0))
2168			return 0;
2169		if (((fin->fin_fi.fi_daddr & np->in_outmsk) != np->in_outip)
2170		    ^ ((np->in_flags & IPN_NOTDST) != 0))
2171			return 0;
2172	}
2173
2174	ft = &np->in_tuc;
2175	if (!(fin->fin_fl & FI_TCPUDP) ||
2176	    (fin->fin_fl & FI_SHORT) || (fin->fin_off != 0)) {
2177		if (ft->ftu_scmp || ft->ftu_dcmp)
2178			return 0;
2179		return 1;
2180	}
2181
2182	return fr_tcpudpchk(ft, fin);
2183}
2184
2185
2186/*
2187 * Packets going out on the external interface go through this.
2188 * Here, the source address requires alteration, if anything.
2189 */
2190int ip_natout(ip, fin)
2191ip_t *ip;
2192fr_info_t *fin;
2193{
2194	register ipnat_t *np = NULL;
2195	register u_32_t ipa;
2196	tcphdr_t *tcp = NULL;
2197	u_short sport = 0, dport = 0, *csump = NULL;
2198	int natadd = 1, i, icmpset = 1;
2199	u_int nflags = 0, hv, msk;
2200	struct ifnet *ifp;
2201	frentry_t *fr;
2202	u_32_t iph;
2203	nat_t *nat;
2204
2205	if (nat_list == NULL || (fr_nat_lock))
2206		return 0;
2207
2208	if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) &&
2209	    fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1)
2210		ifp = fr->fr_tif.fd_ifp;
2211	else
2212		ifp = fin->fin_ifp;
2213
2214	if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) {
2215		if (ip->ip_p == IPPROTO_TCP)
2216			nflags = IPN_TCP;
2217		else if (ip->ip_p == IPPROTO_UDP)
2218			nflags = IPN_UDP;
2219		if ((nflags & IPN_TCPUDP)) {
2220			tcp = (tcphdr_t *)fin->fin_dp;
2221			sport = tcp->th_sport;
2222			dport = tcp->th_dport;
2223		}
2224	}
2225
2226	ipa = ip->ip_src.s_addr;
2227
2228	READ_ENTER(&ipf_nat);
2229
2230	if ((ip->ip_p == IPPROTO_ICMP) &&
2231	    (nat = nat_icmp(ip, fin, &nflags, NAT_OUTBOUND)))
2232		icmpset = 1;
2233	else if ((fin->fin_fl & FI_FRAG) &&
2234	    (nat = ipfr_nat_knownfrag(ip, fin)))
2235		natadd = 0;
2236	else if ((nat = nat_outlookup(ifp, nflags, (u_int)ip->ip_p,
2237				      ip->ip_src, ip->ip_dst,
2238				      (dport << 16) | sport, 0))) {
2239		nflags = nat->nat_flags;
2240		if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) {
2241			if ((nflags & FI_W_SPORT) &&
2242			    (nat->nat_inport != sport))
2243				nat->nat_inport = sport;
2244			else if ((nflags & FI_W_DPORT) &&
2245				 (nat->nat_oport != dport))
2246				nat->nat_oport = dport;
2247			if (nat->nat_outport == 0)
2248				nat->nat_outport = sport;
2249			nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT);
2250			nflags = nat->nat_flags;
2251			nat_stats.ns_wilds--;
2252		}
2253	} else {
2254		RWLOCK_EXIT(&ipf_nat);
2255		WRITE_ENTER(&ipf_nat);
2256		/*
2257		 * If there is no current entry in the nat table for this IP#,
2258		 * create one for it (if there is a matching rule).
2259		 */
2260		msk = 0xffffffff;
2261		i = 32;
2262maskloop:
2263		iph = ipa & htonl(msk);
2264		hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz);
2265		for (np = nat_rules[hv]; np; np = np->in_mnext)
2266		{
2267			if (np->in_ifp && (np->in_ifp != ifp))
2268				continue;
2269			if ((np->in_flags & IPN_RF) &&
2270			    !(np->in_flags & nflags))
2271				continue;
2272			if (np->in_flags & IPN_FILTER) {
2273				if (!nat_match(fin, np, ip))
2274					continue;
2275			} else if ((ipa & np->in_inmsk) != np->in_inip)
2276				continue;
2277			if (np->in_redir & (NAT_MAP|NAT_MAPBLK)) {
2278				if (*np->in_plabel && !appr_ok(ip, tcp, np))
2279					continue;
2280				/*
2281				 * If it's a redirection, then we don't want to
2282				 * create new outgoing port stuff.
2283				 * Redirections are only for incoming
2284				 * connections.
2285				 */
2286				if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK)))
2287					continue;
2288				if ((nat = nat_new(np, ip, fin, (u_int)nflags,
2289						    NAT_OUTBOUND))) {
2290					np->in_hits++;
2291					break;
2292				}
2293			}
2294		}
2295		if ((np == NULL) && (i > 0)) {
2296			do {
2297				i--;
2298				msk <<= 1;
2299			} while ((i >= 0) && ((nat_masks & (1 << i)) == 0));
2300			if (i >= 0)
2301				goto maskloop;
2302		}
2303		MUTEX_DOWNGRADE(&ipf_nat);
2304	}
2305
2306	/*
2307	 * NOTE: ipf_nat must now only be held as a read lock
2308	 */
2309	if (nat) {
2310		np = nat->nat_ptr;
2311		if (natadd && (fin->fin_fl & FI_FRAG) && np)
2312			ipfr_nat_newfrag(ip, fin, 0, nat);
2313		MUTEX_ENTER(&nat->nat_lock);
2314		nat->nat_age = fr_defnatage;
2315		nat->nat_bytes += ip->ip_len;
2316		nat->nat_pkts++;
2317		MUTEX_EXIT(&nat->nat_lock);
2318
2319		/*
2320		 * Fix up checksums, not by recalculating them, but
2321		 * simply computing adjustments.
2322		 */
2323		if (nflags == IPN_ICMPERR) {
2324			u_32_t s1, s2, sumd;
2325
2326			s1 = LONG_SUM(ntohl(ip->ip_src.s_addr));
2327			s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr));
2328			CALC_SUMD(s1, s2, sumd);
2329
2330			if (nat->nat_dir == NAT_OUTBOUND)
2331				fix_incksum(fin, &ip->ip_sum, sumd);
2332			else
2333				fix_outcksum(fin, &ip->ip_sum, sumd);
2334		}
2335#if SOLARIS || defined(__sgi)
2336		else {
2337			if (nat->nat_dir == NAT_OUTBOUND)
2338				fix_outcksum(fin, &ip->ip_sum, nat->nat_ipsumd);
2339			else
2340				fix_incksum(fin, &ip->ip_sum, nat->nat_ipsumd);
2341		}
2342#endif
2343		ip->ip_src = nat->nat_outip;
2344
2345		if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) {
2346
2347			if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) {
2348				tcp->th_sport = nat->nat_outport;
2349				fin->fin_data[0] = ntohs(tcp->th_sport);
2350			}
2351
2352			if (ip->ip_p == IPPROTO_TCP) {
2353				csump = &tcp->th_sum;
2354				MUTEX_ENTER(&nat->nat_lock);
2355				fr_tcp_age(&nat->nat_age,
2356					   nat->nat_tcpstate, fin, 1);
2357				if (nat->nat_age < fr_defnaticmpage)
2358					nat->nat_age = fr_defnaticmpage;
2359#ifdef LARGE_NAT
2360				else if (nat->nat_age > fr_defnatage)
2361					nat->nat_age = fr_defnatage;
2362#endif
2363				/*
2364				 * Increase this because we may have
2365				 * "keep state" following this too and
2366				 * packet storms can occur if this is
2367				 * removed too quickly.
2368				 */
2369				if (nat->nat_age == fr_tcpclosed)
2370					nat->nat_age = fr_tcplastack;
2371				MUTEX_EXIT(&nat->nat_lock);
2372			} else if (ip->ip_p == IPPROTO_UDP) {
2373				udphdr_t *udp = (udphdr_t *)tcp;
2374
2375				if (udp->uh_sum)
2376					csump = &udp->uh_sum;
2377			} else if (ip->ip_p == IPPROTO_ICMP) {
2378				if (!icmpset)
2379					nat->nat_age = fr_defnaticmpage;
2380			}
2381
2382			if (csump) {
2383				if (nat->nat_dir == NAT_OUTBOUND)
2384					fix_outcksum(fin, csump, nat->nat_sumd[1]);
2385				else
2386					fix_incksum(fin, csump, nat->nat_sumd[1]);
2387			}
2388		}
2389
2390		if ((np->in_apr != NULL) && (np->in_dport == 0 ||
2391		     (tcp != NULL && dport == np->in_dport))) {
2392			i = appr_check(ip, fin, nat);
2393			if (i == 0)
2394				i = 1;
2395		} else
2396			i = 1;
2397		ATOMIC_INCL(nat_stats.ns_mapped[1]);
2398		RWLOCK_EXIT(&ipf_nat);	/* READ */
2399		return i;
2400	}
2401	RWLOCK_EXIT(&ipf_nat);			/* READ/WRITE */
2402	return 0;
2403}
2404
2405
2406/*
2407 * Packets coming in from the external interface go through this.
2408 * Here, the destination address requires alteration, if anything.
2409 */
2410int ip_natin(ip, fin)
2411ip_t *ip;
2412fr_info_t *fin;
2413{
2414	register struct in_addr src;
2415	register struct in_addr in;
2416	register ipnat_t *np;
2417	u_short sport = 0, dport = 0, *csump = NULL;
2418	u_int nflags = 0, natadd = 1, hv, msk;
2419	struct ifnet *ifp = fin->fin_ifp;
2420	tcphdr_t *tcp = NULL;
2421	int i, icmpset = 0;
2422	nat_t *nat;
2423	u_32_t iph;
2424
2425	if ((nat_list == NULL) || (ip->ip_v != 4) || (fr_nat_lock))
2426		return 0;
2427
2428	if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) {
2429		if (ip->ip_p == IPPROTO_TCP)
2430			nflags = IPN_TCP;
2431		else if (ip->ip_p == IPPROTO_UDP)
2432			nflags = IPN_UDP;
2433		if ((nflags & IPN_TCPUDP)) {
2434			tcp = (tcphdr_t *)fin->fin_dp;
2435			dport = tcp->th_dport;
2436			sport = tcp->th_sport;
2437		}
2438	}
2439
2440	in = ip->ip_dst;
2441	/* make sure the source address is to be redirected */
2442	src = ip->ip_src;
2443
2444	READ_ENTER(&ipf_nat);
2445
2446	if ((ip->ip_p == IPPROTO_ICMP) &&
2447	    (nat = nat_icmp(ip, fin, &nflags, NAT_INBOUND)))
2448		icmpset = 1;
2449	else if ((fin->fin_fl & FI_FRAG) &&
2450		 (nat = ipfr_nat_knownfrag(ip, fin)))
2451		natadd = 0;
2452	else if ((nat = nat_inlookup(fin->fin_ifp, nflags, (u_int)ip->ip_p,
2453				     ip->ip_src, in, (dport << 16) | sport,
2454				     0))) {
2455		nflags = nat->nat_flags;
2456		if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) {
2457			if ((nat->nat_oport != sport) && (nflags & FI_W_DPORT))
2458				nat->nat_oport = sport;
2459			else if ((nat->nat_outport != dport) &&
2460				 (nflags & FI_W_SPORT))
2461				nat->nat_outport = dport;
2462			nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT);
2463			nflags = nat->nat_flags;
2464			nat_stats.ns_wilds--;
2465		}
2466	} else {
2467		RWLOCK_EXIT(&ipf_nat);
2468		WRITE_ENTER(&ipf_nat);
2469		/*
2470		 * If there is no current entry in the nat table for this IP#,
2471		 * create one for it (if there is a matching rule).
2472		 */
2473		msk = 0xffffffff;
2474		i = 32;
2475maskloop:
2476		iph = in.s_addr & htonl(msk);
2477		hv = NAT_HASH_FN(iph, 0, ipf_rdrrules_sz);
2478		for (np = rdr_rules[hv]; np; np = np->in_rnext) {
2479			if ((np->in_ifp && (np->in_ifp != ifp)) ||
2480			    (np->in_p && (np->in_p != ip->ip_p)) ||
2481			    (np->in_flags && !(nflags & np->in_flags)))
2482				continue;
2483			if (np->in_flags & IPN_FILTER) {
2484				if (!nat_match(fin, np, ip))
2485					continue;
2486			} else if ((in.s_addr & np->in_outmsk) != np->in_outip)
2487				continue;
2488			if ((np->in_redir & NAT_REDIRECT) &&
2489			    (!np->in_pmin || (np->in_flags & IPN_FILTER) ||
2490			     ((ntohs(np->in_pmax) >= ntohs(dport)) &&
2491			      (ntohs(dport) >= ntohs(np->in_pmin)))))
2492				if ((nat = nat_new(np, ip, fin, nflags,
2493						    NAT_INBOUND))) {
2494					np->in_hits++;
2495					break;
2496				}
2497		}
2498
2499		if ((np == NULL) && (i > 0)) {
2500			do {
2501				i--;
2502				msk <<= 1;
2503			} while ((i >= 0) && ((rdr_masks & (1 << i)) == 0));
2504			if (i >= 0)
2505				goto maskloop;
2506		}
2507		MUTEX_DOWNGRADE(&ipf_nat);
2508	}
2509
2510	/*
2511	 * NOTE: ipf_nat must now only be held as a read lock
2512	 */
2513	if (nat) {
2514		np = nat->nat_ptr;
2515		fin->fin_fr = nat->nat_fr;
2516		if (natadd && (fin->fin_fl & FI_FRAG) && np)
2517			ipfr_nat_newfrag(ip, fin, 0, nat);
2518		if ((np->in_apr != NULL) && (np->in_dport == 0 ||
2519		    (tcp != NULL && sport == np->in_dport))) {
2520			i = appr_check(ip, fin, nat);
2521			if (i == -1) {
2522				RWLOCK_EXIT(&ipf_nat);
2523				return i;
2524			}
2525		}
2526
2527		MUTEX_ENTER(&nat->nat_lock);
2528		if (nflags != IPN_ICMPERR)
2529			nat->nat_age = fr_defnatage;
2530
2531		nat->nat_bytes += ip->ip_len;
2532		nat->nat_pkts++;
2533		MUTEX_EXIT(&nat->nat_lock);
2534		ip->ip_dst = nat->nat_inip;
2535		fin->fin_fi.fi_daddr = nat->nat_inip.s_addr;
2536
2537		/*
2538		 * Fix up checksums, not by recalculating them, but
2539		 * simply computing adjustments.
2540		 */
2541#if SOLARIS || defined(__sgi)
2542		if (nat->nat_dir == NAT_OUTBOUND)
2543			fix_incksum(fin, &ip->ip_sum, nat->nat_ipsumd);
2544		else
2545			fix_outcksum(fin, &ip->ip_sum, nat->nat_ipsumd);
2546#endif
2547		if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) {
2548
2549			if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) {
2550				tcp->th_dport = nat->nat_inport;
2551				fin->fin_data[1] = ntohs(tcp->th_dport);
2552			}
2553
2554			if (ip->ip_p == IPPROTO_TCP) {
2555				csump = &tcp->th_sum;
2556				MUTEX_ENTER(&nat->nat_lock);
2557				fr_tcp_age(&nat->nat_age,
2558					   nat->nat_tcpstate, fin, 0);
2559				if (nat->nat_age < fr_defnaticmpage)
2560					nat->nat_age = fr_defnaticmpage;
2561#ifdef LARGE_NAT
2562				else if (nat->nat_age > fr_defnatage)
2563					nat->nat_age = fr_defnatage;
2564#endif
2565				/*
2566				 * Increase this because we may have
2567				 * "keep state" following this too and
2568				 * packet storms can occur if this is
2569				 * removed too quickly.
2570				 */
2571				if (nat->nat_age == fr_tcpclosed)
2572					nat->nat_age = fr_tcplastack;
2573				MUTEX_EXIT(&nat->nat_lock);
2574			} else if (ip->ip_p == IPPROTO_UDP) {
2575				udphdr_t *udp = (udphdr_t *)tcp;
2576
2577				if (udp->uh_sum)
2578					csump = &udp->uh_sum;
2579			} else if (ip->ip_p == IPPROTO_ICMP) {
2580				if (!icmpset)
2581					nat->nat_age = fr_defnaticmpage;
2582			}
2583
2584			if (csump) {
2585				if (nat->nat_dir == NAT_OUTBOUND)
2586					fix_incksum(fin, csump, nat->nat_sumd[0]);
2587				else
2588					fix_outcksum(fin, csump, nat->nat_sumd[0]);
2589			}
2590		}
2591		ATOMIC_INCL(nat_stats.ns_mapped[0]);
2592		RWLOCK_EXIT(&ipf_nat);			/* READ */
2593		return 1;
2594	}
2595	RWLOCK_EXIT(&ipf_nat);			/* READ/WRITE */
2596	return 0;
2597}
2598
2599
2600/*
2601 * Free all memory used by NAT structures allocated at runtime.
2602 */
2603void ip_natunload()
2604{
2605	WRITE_ENTER(&ipf_nat);
2606	(void) nat_clearlist();
2607	(void) nat_flushtable();
2608	RWLOCK_EXIT(&ipf_nat);
2609
2610	if (nat_table[0] != NULL) {
2611		KFREES(nat_table[0], sizeof(nat_t *) * ipf_nattable_sz);
2612		nat_table[0] = NULL;
2613	}
2614	if (nat_table[1] != NULL) {
2615		KFREES(nat_table[1], sizeof(nat_t *) * ipf_nattable_sz);
2616		nat_table[1] = NULL;
2617	}
2618	if (nat_rules != NULL) {
2619		KFREES(nat_rules, sizeof(ipnat_t *) * ipf_natrules_sz);
2620		nat_rules = NULL;
2621	}
2622	if (rdr_rules != NULL) {
2623		KFREES(rdr_rules, sizeof(ipnat_t *) * ipf_rdrrules_sz);
2624		rdr_rules = NULL;
2625	}
2626	if (maptable != NULL) {
2627		KFREES(maptable, sizeof(hostmap_t *) * ipf_hostmap_sz);
2628		maptable = NULL;
2629	}
2630}
2631
2632
2633/*
2634 * Slowly expire held state for NAT entries.  Timeouts are set in
2635 * expectation of this being called twice per second.
2636 */
2637void ip_natexpire()
2638{
2639	register struct nat *nat, **natp;
2640#if defined(_KERNEL) && !SOLARIS
2641	int s;
2642#endif
2643
2644	SPL_NET(s);
2645	WRITE_ENTER(&ipf_nat);
2646	for (natp = &nat_instances; (nat = *natp); ) {
2647		nat->nat_age--;
2648		if (nat->nat_age) {
2649			natp = &nat->nat_next;
2650			continue;
2651		}
2652		*natp = nat->nat_next;
2653#ifdef	IPFILTER_LOG
2654		nat_log(nat, NL_EXPIRE);
2655#endif
2656		nat_delete(nat);
2657		nat_stats.ns_expire++;
2658	}
2659	RWLOCK_EXIT(&ipf_nat);
2660	SPL_X(s);
2661}
2662
2663
2664/*
2665 */
2666void ip_natsync(ifp)
2667void *ifp;
2668{
2669	register ipnat_t *n;
2670	register nat_t *nat;
2671	register u_32_t sum1, sum2, sumd;
2672	struct in_addr in;
2673	ipnat_t *np;
2674	void *ifp2;
2675#if defined(_KERNEL) && !SOLARIS
2676	int s;
2677#endif
2678
2679	/*
2680	 * Change IP addresses for NAT sessions for any protocol except TCP
2681	 * since it will break the TCP connection anyway.
2682	 */
2683	SPL_NET(s);
2684	WRITE_ENTER(&ipf_nat);
2685	for (nat = nat_instances; nat; nat = nat->nat_next)
2686		if (((ifp == NULL) || (ifp == nat->nat_ifp)) &&
2687		    !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr) &&
2688		    (np->in_outmsk == 0xffffffff) && !np->in_nip) {
2689			ifp2 = nat->nat_ifp;
2690			/*
2691			 * Change the map-to address to be the same as the
2692			 * new one.
2693			 */
2694			sum1 = nat->nat_outip.s_addr;
2695			if (fr_ifpaddr(4, ifp2, &in) != -1)
2696				nat->nat_outip = in;
2697			sum2 = nat->nat_outip.s_addr;
2698
2699			if (sum1 == sum2)
2700				continue;
2701			/*
2702			 * Readjust the checksum adjustment to take into
2703			 * account the new IP#.
2704			 */
2705			CALC_SUMD(sum1, sum2, sumd);
2706			/* XXX - dont change for TCP when solaris does
2707			 * hardware checksumming.
2708			 */
2709			sumd += nat->nat_sumd[0];
2710			nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
2711			nat->nat_sumd[1] = nat->nat_sumd[0];
2712		}
2713
2714	for (n = nat_list; (n != NULL); n = n->in_next)
2715		if (n->in_ifp == ifp) {
2716			n->in_ifp = (void *)GETUNIT(n->in_ifname, 4);
2717			if (!n->in_ifp)
2718				n->in_ifp = (void *)-1;
2719		}
2720	RWLOCK_EXIT(&ipf_nat);
2721	SPL_X(s);
2722}
2723
2724
2725#ifdef	IPFILTER_LOG
2726void nat_log(nat, type)
2727struct nat *nat;
2728u_int type;
2729{
2730	struct ipnat *np;
2731	struct natlog natl;
2732	void *items[1];
2733	size_t sizes[1];
2734	int rulen, types[1];
2735
2736	natl.nl_inip = nat->nat_inip;
2737	natl.nl_outip = nat->nat_outip;
2738	natl.nl_origip = nat->nat_oip;
2739	natl.nl_bytes = nat->nat_bytes;
2740	natl.nl_pkts = nat->nat_pkts;
2741	natl.nl_origport = nat->nat_oport;
2742	natl.nl_inport = nat->nat_inport;
2743	natl.nl_outport = nat->nat_outport;
2744	natl.nl_p = nat->nat_p;
2745	natl.nl_type = type;
2746	natl.nl_rule = -1;
2747#ifndef LARGE_NAT
2748	if (nat->nat_ptr != NULL) {
2749		for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++)
2750			if (np == nat->nat_ptr) {
2751				natl.nl_rule = rulen;
2752				break;
2753			}
2754	}
2755#endif
2756	items[0] = &natl;
2757	sizes[0] = sizeof(natl);
2758	types[0] = 0;
2759
2760	(void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1);
2761}
2762#endif
2763