xref: /titanic_50/usr/src/uts/common/inet/ipf/ip_nat.c (revision 694c35faa87b858ecdadfe4fc592615f4eefbb07)
1 /*
2  * Copyright (C) 1995-2004 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  *
6  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
7  * Use is subject to license terms.
8  */
9 
10 #if defined(KERNEL) || defined(_KERNEL)
11 # undef KERNEL
12 # undef _KERNEL
13 # define        KERNEL	1
14 # define        _KERNEL	1
15 #endif
16 #include <sys/errno.h>
17 #include <sys/types.h>
18 #include <sys/param.h>
19 #include <sys/time.h>
20 #include <sys/file.h>
21 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
22     defined(_KERNEL)
23 # include "opt_ipfilter_log.h"
24 #endif
25 #if !defined(_KERNEL)
26 # include <stdio.h>
27 # include <string.h>
28 # include <stdlib.h>
29 # define _KERNEL
30 # ifdef __OpenBSD__
31 struct file;
32 # endif
33 # include <sys/uio.h>
34 # undef _KERNEL
35 #endif
36 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
37 # include <sys/filio.h>
38 # include <sys/fcntl.h>
39 #else
40 # include <sys/ioctl.h>
41 #endif
42 #if !defined(AIX)
43 # include <sys/fcntl.h>
44 #endif
45 #if !defined(linux)
46 # include <sys/protosw.h>
47 #endif
48 #include <sys/socket.h>
49 #if defined(_KERNEL)
50 # include <sys/systm.h>
51 # if !defined(__SVR4) && !defined(__svr4__)
52 #  include <sys/mbuf.h>
53 # endif
54 #endif
55 #if defined(__SVR4) || defined(__svr4__)
56 # include <sys/filio.h>
57 # include <sys/byteorder.h>
58 # ifdef _KERNEL
59 #  include <sys/dditypes.h>
60 # endif
61 # include <sys/stream.h>
62 # include <sys/kmem.h>
63 #endif
64 #if __FreeBSD_version >= 300000
65 # include <sys/queue.h>
66 #endif
67 #include <net/if.h>
68 #if __FreeBSD_version >= 300000
69 # include <net/if_var.h>
70 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
71 #  include "opt_ipfilter.h"
72 # endif
73 #endif
74 #ifdef sun
75 # include <net/af.h>
76 #endif
77 #include <net/route.h>
78 #include <netinet/in.h>
79 #include <netinet/in_systm.h>
80 #include <netinet/ip.h>
81 
82 #ifdef RFC1825
83 # include <vpn/md5.h>
84 # include <vpn/ipsec.h>
85 extern struct ifnet vpnif;
86 #endif
87 
88 #if !defined(linux)
89 # include <netinet/ip_var.h>
90 #endif
91 #include <netinet/tcp.h>
92 #include <netinet/udp.h>
93 #include <netinet/ip_icmp.h>
94 #include "netinet/ip_compat.h"
95 #include <netinet/tcpip.h>
96 #include "netinet/ip_fil.h"
97 #include "netinet/ip_nat.h"
98 #include "netinet/ip_frag.h"
99 #include "netinet/ip_state.h"
100 #include "netinet/ip_proxy.h"
101 #include "netinet/ipf_stack.h"
102 #ifdef	IPFILTER_SYNC
103 #include "netinet/ip_sync.h"
104 #endif
105 #if (__FreeBSD_version >= 300000)
106 # include <sys/malloc.h>
107 #endif
108 /* END OF INCLUDES */
109 
110 #undef	SOCKADDR_IN
111 #define	SOCKADDR_IN	struct sockaddr_in
112 
113 #if !defined(lint)
114 static const char sccsid[] = "@(#)ip_nat.c	1.11 6/5/96 (C) 1995 Darren Reed";
115 static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.42 2005/08/11 19:51:36 darrenr Exp $";
116 #endif
117 
118 
119 /* ======================================================================== */
120 /* How the NAT is organised and works.                                      */
121 /*                                                                          */
122 /* Inside (interface y) NAT       Outside (interface x)                     */
123 /* -------------------- -+- -------------------------------------           */
124 /* Packet going          |   out, processsed by fr_checknatout() for x      */
125 /* ------------>         |   ------------>                                  */
126 /* src=10.1.1.1          |   src=192.1.1.1                                  */
127 /*                       |                                                  */
128 /*                       |   in, processed by fr_checknatin() for x         */
129 /* <------------         |   <------------                                  */
130 /* dst=10.1.1.1          |   dst=192.1.1.1                                  */
131 /* -------------------- -+- -------------------------------------           */
132 /* fr_checknatout() - changes ip_src and if required, sport                 */
133 /*             - creates a new mapping, if required.                        */
134 /* fr_checknatin()  - changes ip_dst and if required, dport                 */
135 /*                                                                          */
136 /* In the NAT table, internal source is recorded as "in" and externally     */
137 /* seen as "out".                                                           */
138 /* ======================================================================== */
139 
140 
141 static	int	nat_clearlist __P((ipf_stack_t *));
142 static	void	nat_addnat __P((struct ipnat *, ipf_stack_t *));
143 static	void	nat_addrdr __P((struct ipnat *, ipf_stack_t *));
144 static	int	fr_natgetent __P((caddr_t, ipf_stack_t *));
145 static	int	fr_natgetsz __P((caddr_t, ipf_stack_t *));
146 static	int	fr_natputent __P((caddr_t, int, ipf_stack_t *));
147 static	void	nat_tabmove __P((nat_t *, ipf_stack_t *));
148 static	int	nat_match __P((fr_info_t *, ipnat_t *));
149 static	INLINE	int nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
150 static	INLINE	int nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *));
151 static	hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr,
152 				    struct in_addr, struct in_addr, u_32_t,
153 				    ipf_stack_t *));
154 static	INLINE	int nat_icmpquerytype4 __P((int));
155 static	int	nat_ruleaddrinit __P((ipnat_t *));
156 static	int	nat_siocaddnat __P((ipnat_t *, ipnat_t **, int, ipf_stack_t *));
157 static	void	nat_siocdelnat __P((ipnat_t *, ipnat_t **, int, ipf_stack_t *));
158 static	INLINE	int nat_icmperrortype4 __P((int));
159 static	INLINE	int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *,
160 				      tcphdr_t *, nat_t **, int));
161 static	INLINE	int nat_resolverule __P((ipnat_t *, ipf_stack_t *));
162 static	void	nat_mssclamp __P((tcphdr_t *, u_32_t, u_short *));
163 static	int	nat_getnext __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *));
164 static	int	nat_iterator __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *));
165 static	int	nat_flushtable __P((int, ipf_stack_t *));
166 
167 #define NAT_HAS_L4_CHANGED(n)	\
168  	(((n)->nat_flags & (IPN_TCPUDPICMP)) && \
169  	(n)->nat_inport != (n)->nat_outport)
170 
171 
172 /* ------------------------------------------------------------------------ */
173 /* Function:    fr_natinit                                                  */
174 /* Returns:     int - 0 == success, -1 == failure                           */
175 /* Parameters:  Nil                                                         */
176 /*                                                                          */
177 /* Initialise all of the NAT locks, tables and other structures.            */
178 /* ------------------------------------------------------------------------ */
179 int fr_natinit(ifs)
180 ipf_stack_t *ifs;
181 {
182 	int i;
183 
184 	KMALLOCS(ifs->ifs_nat_table[0], nat_t **,
185 		 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz);
186 	if (ifs->ifs_nat_table[0] != NULL)
187 		bzero((char *)ifs->ifs_nat_table[0],
188 		      ifs->ifs_ipf_nattable_sz * sizeof(nat_t *));
189 	else
190 		return -1;
191 
192 	KMALLOCS(ifs->ifs_nat_table[1], nat_t **,
193 		 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz);
194 	if (ifs->ifs_nat_table[1] != NULL)
195 		bzero((char *)ifs->ifs_nat_table[1],
196 		      ifs->ifs_ipf_nattable_sz * sizeof(nat_t *));
197 	else
198 		return -2;
199 
200 	KMALLOCS(ifs->ifs_nat_rules, ipnat_t **,
201 		 sizeof(ipnat_t *) * ifs->ifs_ipf_natrules_sz);
202 	if (ifs->ifs_nat_rules != NULL)
203 		bzero((char *)ifs->ifs_nat_rules,
204 		      ifs->ifs_ipf_natrules_sz * sizeof(ipnat_t *));
205 	else
206 		return -3;
207 
208 	KMALLOCS(ifs->ifs_rdr_rules, ipnat_t **,
209 		 sizeof(ipnat_t *) * ifs->ifs_ipf_rdrrules_sz);
210 	if (ifs->ifs_rdr_rules != NULL)
211 		bzero((char *)ifs->ifs_rdr_rules,
212 		      ifs->ifs_ipf_rdrrules_sz * sizeof(ipnat_t *));
213 	else
214 		return -4;
215 
216 	KMALLOCS(ifs->ifs_maptable, hostmap_t **,
217 		 sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz);
218 	if (ifs->ifs_maptable != NULL)
219 		bzero((char *)ifs->ifs_maptable,
220 		      sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz);
221 	else
222 		return -5;
223 
224 	ifs->ifs_ipf_hm_maplist = NULL;
225 
226 	KMALLOCS(ifs->ifs_nat_stats.ns_bucketlen[0], u_long *,
227 		 ifs->ifs_ipf_nattable_sz * sizeof(u_long));
228 	if (ifs->ifs_nat_stats.ns_bucketlen[0] == NULL)
229 		return -1;
230 	bzero((char *)ifs->ifs_nat_stats.ns_bucketlen[0],
231 	      ifs->ifs_ipf_nattable_sz * sizeof(u_long));
232 
233 	KMALLOCS(ifs->ifs_nat_stats.ns_bucketlen[1], u_long *,
234 		 ifs->ifs_ipf_nattable_sz * sizeof(u_long));
235 	if (ifs->ifs_nat_stats.ns_bucketlen[1] == NULL)
236 		return -1;
237 	bzero((char *)ifs->ifs_nat_stats.ns_bucketlen[1],
238 	      ifs->ifs_ipf_nattable_sz * sizeof(u_long));
239 
240 	if (ifs->ifs_fr_nat_maxbucket == 0) {
241 		for (i = ifs->ifs_ipf_nattable_sz; i > 0; i >>= 1)
242 			ifs->ifs_fr_nat_maxbucket++;
243 		ifs->ifs_fr_nat_maxbucket *= 2;
244 	}
245 
246 	fr_sttab_init(ifs->ifs_nat_tqb, ifs);
247 	/*
248 	 * Increase this because we may have "keep state" following this too
249 	 * and packet storms can occur if this is removed too quickly.
250 	 */
251 	ifs->ifs_nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = ifs->ifs_fr_tcplastack;
252 	ifs->ifs_nat_tqb[IPF_TCP_NSTATES - 1].ifq_next = &ifs->ifs_nat_udptq;
253 	ifs->ifs_nat_udptq.ifq_ttl = ifs->ifs_fr_defnatage;
254 	ifs->ifs_nat_udptq.ifq_ref = 1;
255 	ifs->ifs_nat_udptq.ifq_head = NULL;
256 	ifs->ifs_nat_udptq.ifq_tail = &ifs->ifs_nat_udptq.ifq_head;
257 	MUTEX_INIT(&ifs->ifs_nat_udptq.ifq_lock, "nat ipftq udp tab");
258 	ifs->ifs_nat_udptq.ifq_next = &ifs->ifs_nat_icmptq;
259 	ifs->ifs_nat_icmptq.ifq_ttl = ifs->ifs_fr_defnaticmpage;
260 	ifs->ifs_nat_icmptq.ifq_ref = 1;
261 	ifs->ifs_nat_icmptq.ifq_head = NULL;
262 	ifs->ifs_nat_icmptq.ifq_tail = &ifs->ifs_nat_icmptq.ifq_head;
263 	MUTEX_INIT(&ifs->ifs_nat_icmptq.ifq_lock, "nat icmp ipftq tab");
264 	ifs->ifs_nat_icmptq.ifq_next = &ifs->ifs_nat_iptq;
265 	ifs->ifs_nat_iptq.ifq_ttl = ifs->ifs_fr_defnatipage;
266 	ifs->ifs_nat_iptq.ifq_ref = 1;
267 	ifs->ifs_nat_iptq.ifq_head = NULL;
268 	ifs->ifs_nat_iptq.ifq_tail = &ifs->ifs_nat_iptq.ifq_head;
269 	MUTEX_INIT(&ifs->ifs_nat_iptq.ifq_lock, "nat ip ipftq tab");
270 	ifs->ifs_nat_iptq.ifq_next = NULL;
271 
272 	for (i = 0; i < IPF_TCP_NSTATES; i++) {
273 		if (ifs->ifs_nat_tqb[i].ifq_ttl < ifs->ifs_fr_defnaticmpage)
274 			ifs->ifs_nat_tqb[i].ifq_ttl = ifs->ifs_fr_defnaticmpage;
275 #ifdef LARGE_NAT
276 		else if (ifs->ifs_nat_tqb[i].ifq_ttl > ifs->ifs_fr_defnatage)
277 			ifs->ifs_nat_tqb[i].ifq_ttl = ifs->ifs_fr_defnatage;
278 #endif
279 	}
280 
281 	/*
282 	 * Increase this because we may have "keep state" following
283 	 * this too and packet storms can occur if this is removed
284 	 * too quickly.
285 	 */
286 	ifs->ifs_nat_tqb[IPF_TCPS_CLOSED].ifq_ttl =
287 	    ifs->ifs_nat_tqb[IPF_TCPS_LAST_ACK].ifq_ttl;
288 
289 	RWLOCK_INIT(&ifs->ifs_ipf_nat, "ipf IP NAT rwlock");
290 	RWLOCK_INIT(&ifs->ifs_ipf_natfrag, "ipf IP NAT-Frag rwlock");
291 	MUTEX_INIT(&ifs->ifs_ipf_nat_new, "ipf nat new mutex");
292 	MUTEX_INIT(&ifs->ifs_ipf_natio, "ipf nat io mutex");
293 
294 	ifs->ifs_fr_nat_init = 1;
295 	ifs->ifs_nat_last_force_flush = ifs->ifs_fr_ticks;
296 	return 0;
297 }
298 
299 
300 /* ------------------------------------------------------------------------ */
301 /* Function:    nat_addrdr                                                  */
302 /* Returns:     Nil                                                         */
303 /* Parameters:  n(I) - pointer to NAT rule to add                           */
304 /*                                                                          */
305 /* Adds a redirect rule to the hash table of redirect rules and the list of */
306 /* loaded NAT rules.  Updates the bitmask indicating which netmasks are in  */
307 /* use by redirect rules.                                                   */
308 /* ------------------------------------------------------------------------ */
309 static void nat_addrdr(n, ifs)
310 ipnat_t *n;
311 ipf_stack_t *ifs;
312 {
313 	ipnat_t **np;
314 	u_32_t j;
315 	u_int hv;
316 	int k;
317 
318 	k = count4bits(n->in_outmsk);
319 	if ((k >= 0) && (k != 32))
320 		ifs->ifs_rdr_masks |= 1 << k;
321 	j = (n->in_outip & n->in_outmsk);
322 	hv = NAT_HASH_FN(j, 0, ifs->ifs_ipf_rdrrules_sz);
323 	np = ifs->ifs_rdr_rules + hv;
324 	while (*np != NULL)
325 		np = &(*np)->in_rnext;
326 	n->in_rnext = NULL;
327 	n->in_prnext = np;
328 	n->in_hv = hv;
329 	*np = n;
330 }
331 
332 
333 /* ------------------------------------------------------------------------ */
334 /* Function:    nat_addnat                                                  */
335 /* Returns:     Nil                                                         */
336 /* Parameters:  n(I) - pointer to NAT rule to add                           */
337 /*                                                                          */
338 /* Adds a NAT map rule to the hash table of rules and the list of  loaded   */
339 /* NAT rules.  Updates the bitmask indicating which netmasks are in use by  */
340 /* redirect rules.                                                          */
341 /* ------------------------------------------------------------------------ */
342 static void nat_addnat(n, ifs)
343 ipnat_t *n;
344 ipf_stack_t *ifs;
345 {
346 	ipnat_t **np;
347 	u_32_t j;
348 	u_int hv;
349 	int k;
350 
351 	k = count4bits(n->in_inmsk);
352 	if ((k >= 0) && (k != 32))
353 		ifs->ifs_nat_masks |= 1 << k;
354 	j = (n->in_inip & n->in_inmsk);
355 	hv = NAT_HASH_FN(j, 0, ifs->ifs_ipf_natrules_sz);
356 	np = ifs->ifs_nat_rules + hv;
357 	while (*np != NULL)
358 		np = &(*np)->in_mnext;
359 	n->in_mnext = NULL;
360 	n->in_pmnext = np;
361 	n->in_hv = hv;
362 	*np = n;
363 }
364 
365 
366 /* ------------------------------------------------------------------------ */
367 /* Function:    nat_delrdr                                                  */
368 /* Returns:     Nil                                                         */
369 /* Parameters:  n(I) - pointer to NAT rule to delete                        */
370 /*                                                                          */
371 /* Removes a redirect rule from the hash table of redirect rules.           */
372 /* ------------------------------------------------------------------------ */
373 void nat_delrdr(n)
374 ipnat_t *n;
375 {
376 	if (n->in_rnext)
377 		n->in_rnext->in_prnext = n->in_prnext;
378 	*n->in_prnext = n->in_rnext;
379 }
380 
381 
382 /* ------------------------------------------------------------------------ */
383 /* Function:    nat_delnat                                                  */
384 /* Returns:     Nil                                                         */
385 /* Parameters:  n(I) - pointer to NAT rule to delete                        */
386 /*                                                                          */
387 /* Removes a NAT map rule from the hash table of NAT map rules.             */
388 /* ------------------------------------------------------------------------ */
389 void nat_delnat(n)
390 ipnat_t *n;
391 {
392 	if (n->in_mnext != NULL)
393 		n->in_mnext->in_pmnext = n->in_pmnext;
394 	*n->in_pmnext = n->in_mnext;
395 }
396 
397 
398 /* ------------------------------------------------------------------------ */
399 /* Function:    nat_hostmap                                                 */
400 /* Returns:     struct hostmap* - NULL if no hostmap could be created,      */
401 /*                                else a pointer to the hostmapping to use  */
402 /* Parameters:  np(I)   - pointer to NAT rule                               */
403 /*              real(I) - real IP address                                   */
404 /*              map(I)  - mapped IP address                                 */
405 /*              port(I) - destination port number                           */
406 /* Write Locks: ipf_nat                                                     */
407 /*                                                                          */
408 /* Check if an ip address has already been allocated for a given mapping    */
409 /* that is not doing port based translation.  If is not yet allocated, then */
410 /* create a new entry if a non-NULL NAT rule pointer has been supplied.     */
411 /* ------------------------------------------------------------------------ */
412 static struct hostmap *nat_hostmap(np, src, dst, map, port, ifs)
413 ipnat_t *np;
414 struct in_addr src;
415 struct in_addr dst;
416 struct in_addr map;
417 u_32_t port;
418 ipf_stack_t *ifs;
419 {
420 	hostmap_t *hm;
421 	u_int hv;
422 
423 	hv = (src.s_addr ^ dst.s_addr);
424 	hv += src.s_addr;
425 	hv += dst.s_addr;
426 	hv %= HOSTMAP_SIZE;
427 	for (hm = ifs->ifs_maptable[hv]; hm; hm = hm->hm_next)
428 		if ((hm->hm_srcip.s_addr == src.s_addr) &&
429 		    (hm->hm_dstip.s_addr == dst.s_addr) &&
430 		    ((np == NULL) || (np == hm->hm_ipnat)) &&
431 		    ((port == 0) || (port == hm->hm_port))) {
432 			hm->hm_ref++;
433 			return hm;
434 		}
435 
436 	if (np == NULL)
437 		return NULL;
438 
439 	KMALLOC(hm, hostmap_t *);
440 	if (hm) {
441 		hm->hm_hnext = ifs->ifs_ipf_hm_maplist;
442 		hm->hm_phnext = &ifs->ifs_ipf_hm_maplist;
443 		if (ifs->ifs_ipf_hm_maplist != NULL)
444 			ifs->ifs_ipf_hm_maplist->hm_phnext = &hm->hm_hnext;
445 		ifs->ifs_ipf_hm_maplist = hm;
446 
447 		hm->hm_next = ifs->ifs_maptable[hv];
448 		hm->hm_pnext = ifs->ifs_maptable + hv;
449 		if (ifs->ifs_maptable[hv] != NULL)
450 			ifs->ifs_maptable[hv]->hm_pnext = &hm->hm_next;
451 		ifs->ifs_maptable[hv] = hm;
452 		hm->hm_ipnat = np;
453 		hm->hm_srcip = src;
454 		hm->hm_dstip = dst;
455 		hm->hm_mapip = map;
456 		hm->hm_ref = 1;
457 		hm->hm_port = port;
458 		hm->hm_v = 4;
459 	}
460 	return hm;
461 }
462 
463 
464 /* ------------------------------------------------------------------------ */
465 /* Function:    fr_hostmapdel                                              */
466 /* Returns:     Nil                                                         */
467 /* Parameters:  hmp(I) - pointer to pointer to hostmap structure            */
468 /* Write Locks: ipf_nat                                                     */
469 /*                                                                          */
470 /* Decrement the references to this hostmap structure by one.  If this      */
471 /* reaches zero then remove it and free it.                                 */
472 /* ------------------------------------------------------------------------ */
473 void fr_hostmapdel(hmp)
474 struct hostmap **hmp;
475 {
476 	struct hostmap *hm;
477 
478 	hm = *hmp;
479 	*hmp = NULL;
480 
481 	hm->hm_ref--;
482 	if (hm->hm_ref == 0) {
483 		if (hm->hm_next)
484 			hm->hm_next->hm_pnext = hm->hm_pnext;
485 		*hm->hm_pnext = hm->hm_next;
486 		if (hm->hm_hnext)
487 			hm->hm_hnext->hm_phnext = hm->hm_phnext;
488 		*hm->hm_phnext = hm->hm_hnext;
489 		KFREE(hm);
490 	}
491 }
492 
493 
494 /* ------------------------------------------------------------------------ */
495 /* Function:    fix_outcksum                                                */
496 /* Returns:     Nil                                                         */
497 /* Parameters:  sp(I)  - location of 16bit checksum to update               */
498 /*              n((I)  - amount to adjust checksum by                       */
499 /*                                                                          */
500 /* Adjusts the 16bit checksum by "n" for packets going out.                 */
501 /* ------------------------------------------------------------------------ */
502 void fix_outcksum(sp, n)
503 u_short *sp;
504 u_32_t n;
505 {
506 	u_short sumshort;
507 	u_32_t sum1;
508 
509 	if (n == 0)
510 		return;
511 
512 	sum1 = (~ntohs(*sp)) & 0xffff;
513 	sum1 += (n);
514 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
515 	/* Again */
516 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
517 	sumshort = ~(u_short)sum1;
518 	*(sp) = htons(sumshort);
519 }
520 
521 
522 /* ------------------------------------------------------------------------ */
523 /* Function:    fix_incksum                                                 */
524 /* Returns:     Nil                                                         */
525 /* Parameters:  sp(I)  - location of 16bit checksum to update               */
526 /*              n((I)  - amount to adjust checksum by                       */
527 /*                                                                          */
528 /* Adjusts the 16bit checksum by "n" for packets going in.                  */
529 /* ------------------------------------------------------------------------ */
530 void fix_incksum(sp, n)
531 u_short *sp;
532 u_32_t n;
533 {
534 	u_short sumshort;
535 	u_32_t sum1;
536 
537 	if (n == 0)
538 		return;
539 
540 	sum1 = (~ntohs(*sp)) & 0xffff;
541 	sum1 += ~(n) & 0xffff;
542 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
543 	/* Again */
544 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
545 	sumshort = ~(u_short)sum1;
546 	*(sp) = htons(sumshort);
547 }
548 
549 
550 /* ------------------------------------------------------------------------ */
551 /* Function:    fix_datacksum                                               */
552 /* Returns:     Nil                                                         */
553 /* Parameters:  sp(I)  - location of 16bit checksum to update               */
554 /*              n((I)  - amount to adjust checksum by                       */
555 /*                                                                          */
556 /* Fix_datacksum is used *only* for the adjustments of checksums in the     */
557 /* data section of an IP packet.                                            */
558 /*                                                                          */
559 /* The only situation in which you need to do this is when NAT'ing an       */
560 /* ICMP error message. Such a message, contains in its body the IP header   */
561 /* of the original IP packet, that causes the error.                        */
562 /*                                                                          */
563 /* You can't use fix_incksum or fix_outcksum in that case, because for the  */
564 /* kernel the data section of the ICMP error is just data, and no special   */
565 /* processing like hardware cksum or ntohs processing have been done by the */
566 /* kernel on the data section.                                              */
567 /* ------------------------------------------------------------------------ */
568 void fix_datacksum(sp, n)
569 u_short *sp;
570 u_32_t n;
571 {
572 	u_short sumshort;
573 	u_32_t sum1;
574 
575 	if (n == 0)
576 		return;
577 
578 	sum1 = (~ntohs(*sp)) & 0xffff;
579 	sum1 += (n);
580 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
581 	/* Again */
582 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
583 	sumshort = ~(u_short)sum1;
584 	*(sp) = htons(sumshort);
585 }
586 
587 
588 /* ------------------------------------------------------------------------ */
589 /* Function:    fr_nat_ioctl                                                */
590 /* Returns:     int - 0 == success, != 0 == failure                         */
591 /* Parameters:  data(I) - pointer to ioctl data                             */
592 /*              cmd(I)  - ioctl command integer                             */
593 /*              mode(I) - file mode bits used with open                     */
594 /*              uid(I)  - uid of caller                                     */
595 /*              ctx(I)  - pointer to give the uid context                   */
596 /*              ifs     - ipf stack instance                                */
597 /*                                                                          */
598 /* Processes an ioctl call made to operate on the IP Filter NAT device.     */
599 /* ------------------------------------------------------------------------ */
600 int fr_nat_ioctl(data, cmd, mode, uid, ctx, ifs)
601 ioctlcmd_t cmd;
602 caddr_t data;
603 int mode, uid;
604 void *ctx;
605 ipf_stack_t *ifs;
606 {
607 	ipnat_t *nat, *nt, *n = NULL, **np = NULL;
608 	int error = 0, ret, arg, getlock;
609 	ipnat_t natd;
610 
611 #if (BSD >= 199306) && defined(_KERNEL)
612 	if ((securelevel >= 2) && (mode & FWRITE))
613 		return EPERM;
614 #endif
615 
616 #if defined(__osf__) && defined(_KERNEL)
617 	getlock = 0;
618 #else
619 	getlock = (mode & NAT_LOCKHELD) ? 0 : 1;
620 #endif
621 
622 	nat = NULL;     /* XXX gcc -Wuninitialized */
623 	if (cmd == (ioctlcmd_t)SIOCADNAT) {
624 		KMALLOC(nt, ipnat_t *);
625 	} else {
626 		nt = NULL;
627 	}
628 
629 	if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) {
630 		if (mode & NAT_SYSSPACE) {
631 			bcopy(data, (char *)&natd, sizeof(natd));
632 			error = 0;
633 		} else {
634 			error = fr_inobj(data, &natd, IPFOBJ_IPNAT);
635 		}
636 
637 	}
638 
639 	if (error != 0)
640 		goto done;
641 
642 	/*
643 	 * For add/delete, look to see if the NAT entry is already present
644 	 */
645 	if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) {
646 		nat = &natd;
647 		if (nat->in_v == 0)	/* For backward compat. */
648 			nat->in_v = 4;
649 		nat->in_flags &= IPN_USERFLAGS;
650 		if ((nat->in_redir & NAT_MAPBLK) == 0) {
651 			if ((nat->in_flags & IPN_SPLIT) == 0)
652 				nat->in_inip &= nat->in_inmsk;
653 			if ((nat->in_flags & IPN_IPRANGE) == 0)
654 				nat->in_outip &= nat->in_outmsk;
655 		}
656 		MUTEX_ENTER(&ifs->ifs_ipf_natio);
657 		for (np = &ifs->ifs_nat_list; ((n = *np) != NULL);
658 		     np = &n->in_next)
659 			if (bcmp((char *)&nat->in_flags, (char *)&n->in_flags,
660 			    IPN_CMPSIZ) == 0) {
661 				if (nat->in_redir == NAT_REDIRECT &&
662 				    nat->in_pnext != n->in_pnext)
663 					continue;
664 				break;
665 			}
666 	}
667 
668 	switch (cmd)
669 	{
670 	case SIOCGENITER :
671 	    {
672 		ipfgeniter_t iter;
673 		ipftoken_t *token;
674 
675 		error = fr_inobj(data, &iter, IPFOBJ_GENITER);
676 		if (error != 0)
677 			break;
678 
679 		token = ipf_findtoken(iter.igi_type, uid, ctx, ifs);
680 		if (token != NULL)
681 			error  = nat_iterator(token, &iter, ifs);
682 		else
683 			error = ESRCH;
684 		RWLOCK_EXIT(&ifs->ifs_ipf_tokens);
685 		break;
686 	    }
687 #ifdef  IPFILTER_LOG
688 	case SIOCIPFFB :
689 	{
690 		int tmp;
691 
692 		if (!(mode & FWRITE))
693 			error = EPERM;
694 		else {
695 			tmp = ipflog_clear(IPL_LOGNAT, ifs);
696 			error = BCOPYOUT((char *)&tmp, (char *)data,
697 					sizeof(tmp));
698 			if (error != 0)
699 				error = EFAULT;
700 		}
701 		break;
702 	}
703 	case SIOCSETLG :
704 		if (!(mode & FWRITE)) {
705 			error = EPERM;
706 		} else {
707 			error = BCOPYIN((char *)data,
708 					(char *)&ifs->ifs_nat_logging,
709 					sizeof(ifs->ifs_nat_logging));
710 			if (error != 0)
711 				error = EFAULT;
712 		}
713 		break;
714 	case SIOCGETLG :
715 		error = BCOPYOUT((char *)&ifs->ifs_nat_logging, (char *)data,
716 				sizeof(ifs->ifs_nat_logging));
717 		if (error != 0)
718 			error = EFAULT;
719 		break;
720 	case FIONREAD :
721 		arg = ifs->ifs_iplused[IPL_LOGNAT];
722 		error = BCOPYOUT(&arg, data, sizeof(arg));
723 		if (error != 0)
724 			error = EFAULT;
725 		break;
726 #endif
727 	case SIOCADNAT :
728 		if (!(mode & FWRITE)) {
729 			error = EPERM;
730 		} else if (n != NULL) {
731 			error = EEXIST;
732 		} else if (nt == NULL) {
733 			error = ENOMEM;
734 		}
735 		if (error != 0) {
736 			MUTEX_EXIT(&ifs->ifs_ipf_natio);
737 			break;
738 		}
739 		bcopy((char *)nat, (char *)nt, sizeof(*n));
740 		error = nat_siocaddnat(nt, np, getlock, ifs);
741 		MUTEX_EXIT(&ifs->ifs_ipf_natio);
742 		if (error == 0)
743 			nt = NULL;
744 		break;
745 	case SIOCRMNAT :
746 		if (!(mode & FWRITE)) {
747 			error = EPERM;
748 			n = NULL;
749 		} else if (n == NULL) {
750 			error = ESRCH;
751 		}
752 
753 		if (error != 0) {
754 			MUTEX_EXIT(&ifs->ifs_ipf_natio);
755 			break;
756 		}
757 		nat_siocdelnat(n, np, getlock, ifs);
758 
759 		MUTEX_EXIT(&ifs->ifs_ipf_natio);
760 		n = NULL;
761 		break;
762 	case SIOCGNATS :
763 		ifs->ifs_nat_stats.ns_table[0] = ifs->ifs_nat_table[0];
764 		ifs->ifs_nat_stats.ns_table[1] = ifs->ifs_nat_table[1];
765 		ifs->ifs_nat_stats.ns_list = ifs->ifs_nat_list;
766 		ifs->ifs_nat_stats.ns_maptable = ifs->ifs_maptable;
767 		ifs->ifs_nat_stats.ns_maplist = ifs->ifs_ipf_hm_maplist;
768 		ifs->ifs_nat_stats.ns_nattab_max = ifs->ifs_ipf_nattable_max;
769 		ifs->ifs_nat_stats.ns_nattab_sz = ifs->ifs_ipf_nattable_sz;
770 		ifs->ifs_nat_stats.ns_rultab_sz = ifs->ifs_ipf_natrules_sz;
771 		ifs->ifs_nat_stats.ns_rdrtab_sz = ifs->ifs_ipf_rdrrules_sz;
772 		ifs->ifs_nat_stats.ns_hostmap_sz = ifs->ifs_ipf_hostmap_sz;
773 		ifs->ifs_nat_stats.ns_instances = ifs->ifs_nat_instances;
774 		ifs->ifs_nat_stats.ns_apslist = ifs->ifs_ap_sess_list;
775 		error = fr_outobj(data, &ifs->ifs_nat_stats, IPFOBJ_NATSTAT);
776 		break;
777 	case SIOCGNATL :
778 	    {
779 		natlookup_t nl;
780 
781 		if (getlock) {
782 			READ_ENTER(&ifs->ifs_ipf_nat);
783 		}
784 		error = fr_inobj(data, &nl, IPFOBJ_NATLOOKUP);
785 		if (nl.nl_v != 6)
786 			nl.nl_v = 4;
787 		if (error == 0) {
788 			void *ptr;
789 
790 			switch (nl.nl_v)
791 			{
792 			case 4:
793 				ptr = nat_lookupredir(&nl, ifs);
794 				break;
795 #ifdef	USE_INET6
796 			case 6:
797 				ptr = nat6_lookupredir(&nl, ifs);
798 				break;
799 #endif
800 			default:
801 				ptr = NULL;
802 				break;
803 			}
804 
805 			if (ptr != NULL) {
806 				error = fr_outobj(data, &nl, IPFOBJ_NATLOOKUP);
807 			} else {
808 				error = ESRCH;
809 			}
810 		}
811 		if (getlock) {
812 			RWLOCK_EXIT(&ifs->ifs_ipf_nat);
813 		}
814 		break;
815 	    }
816 	case SIOCIPFFL :	/* old SIOCFLNAT & SIOCCNATL */
817 		if (!(mode & FWRITE)) {
818 			error = EPERM;
819 			break;
820 		}
821 		if (getlock) {
822 			WRITE_ENTER(&ifs->ifs_ipf_nat);
823 		}
824 		error = BCOPYIN(data, &arg, sizeof(arg));
825 		if (error != 0) {
826 			error = EFAULT;
827 		} else {
828 			if (arg == FLUSH_LIST)
829 				ret = nat_clearlist(ifs);
830 			else if (VALID_TABLE_FLUSH_OPT(arg))
831 				ret = nat_flushtable(arg, ifs);
832 			else
833 				error = EINVAL;
834 		}
835 		if (getlock) {
836 			RWLOCK_EXIT(&ifs->ifs_ipf_nat);
837 		}
838 		if (error == 0) {
839 			error = BCOPYOUT(&ret, data, sizeof(ret));
840 			if (error != 0)
841 				error = EFAULT;
842 		}
843 		break;
844 	case SIOCPROXY :
845 		error = appr_ioctl(data, cmd, mode, ifs);
846 		break;
847 	case SIOCSTLCK :
848 		if (!(mode & FWRITE)) {
849 			error = EPERM;
850 		} else {
851 			error = fr_lock(data, &ifs->ifs_fr_nat_lock);
852 		}
853 		break;
854 	case SIOCSTPUT :
855 		if ((mode & FWRITE) != 0) {
856 			error = fr_natputent(data, getlock, ifs);
857 		} else {
858 			error = EACCES;
859 		}
860 		break;
861 	case SIOCSTGSZ :
862 		if (ifs->ifs_fr_nat_lock) {
863 			if (getlock) {
864 				READ_ENTER(&ifs->ifs_ipf_nat);
865 			}
866 			error = fr_natgetsz(data, ifs);
867 			if (getlock) {
868 				RWLOCK_EXIT(&ifs->ifs_ipf_nat);
869 			}
870 		} else
871 			error = EACCES;
872 		break;
873 	case SIOCSTGET :
874 		if (ifs->ifs_fr_nat_lock) {
875 			if (getlock) {
876 				READ_ENTER(&ifs->ifs_ipf_nat);
877 			}
878 			error = fr_natgetent(data, ifs);
879 			if (getlock) {
880 				RWLOCK_EXIT(&ifs->ifs_ipf_nat);
881 			}
882 		} else
883 			error = EACCES;
884 		break;
885 	case SIOCIPFDELTOK :
886 		error = BCOPYIN((caddr_t)data, (caddr_t)&arg, sizeof(arg));
887 		if (error != 0) {
888 			error = EFAULT;
889 		} else {
890 			error = ipf_deltoken(arg, uid, ctx, ifs);
891 		}
892 		break;
893 	default :
894 		error = EINVAL;
895 		break;
896 	}
897 done:
898 	if (nt)
899 		KFREE(nt);
900 	return error;
901 }
902 
903 
904 /* ------------------------------------------------------------------------ */
905 /* Function:    nat_siocaddnat                                              */
906 /* Returns:     int - 0 == success, != 0 == failure                         */
907 /* Parameters:  n(I)       - pointer to new NAT rule                        */
908 /*              np(I)      - pointer to where to insert new NAT rule        */
909 /*              getlock(I) - flag indicating if lock on ipf_nat is held     */
910 /* Mutex Locks: ipf_natio                                                   */
911 /*                                                                          */
912 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
913 /* from information passed to the kernel, then add it  to the appropriate   */
914 /* NAT rule table(s).                                                       */
915 /* ------------------------------------------------------------------------ */
916 static int nat_siocaddnat(n, np, getlock, ifs)
917 ipnat_t *n, **np;
918 int getlock;
919 ipf_stack_t *ifs;
920 {
921 	int error = 0, i, j;
922 
923 	if (nat_resolverule(n, ifs) != 0)
924 		return ENOENT;
925 
926 	if ((n->in_age[0] == 0) && (n->in_age[1] != 0))
927 		return EINVAL;
928 
929 	n->in_use = 0;
930 	if (n->in_redir & NAT_MAPBLK)
931 		n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk);
932 	else if (n->in_flags & IPN_AUTOPORTMAP)
933 		n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk);
934 	else if (n->in_flags & IPN_IPRANGE)
935 		n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip);
936 	else if (n->in_flags & IPN_SPLIT)
937 		n->in_space = 2;
938 	else if (n->in_outmsk != 0)
939 		n->in_space = ~ntohl(n->in_outmsk);
940 	else
941 		n->in_space = 1;
942 	if ((n->in_flags & NAT_TCPUDPICMPQ) && (n->in_redir != NAT_REDIRECT)) {
943 		if (ntohs(n->in_pmax) < ntohs(n->in_pmin))
944 			return EINVAL;
945 	}
946 
947 	/*
948 	 * Calculate the number of valid IP addresses in the output
949 	 * mapping range.  In all cases, the range is inclusive of
950 	 * the start and ending IP addresses.
951 	 * If to a CIDR address, lose 2: broadcast + network address
952 	 *                               (so subtract 1)
953 	 * If to a range, add one.
954 	 * If to a single IP address, set to 1.
955 	 */
956 	if (n->in_space) {
957 		if ((n->in_flags & IPN_IPRANGE) != 0)
958 			n->in_space += 1;
959 		else
960 			n->in_space -= 1;
961 	} else
962 		n->in_space = 1;
963 
964 #ifdef	USE_INET6
965 	if (n->in_v == 6 && (n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0 &&
966 	    !IP6_ISONES(&n->in_out[1]) && !IP6_ISZERO(&n->in_out[1]))
967 		IP6_ADD(&n->in_out[0], 1, &n->in_next6)
968 	else if (n->in_v == 6 &&
969 	    (n->in_flags & IPN_SPLIT) && (n->in_redir & NAT_REDIRECT))
970 		n->in_next6 = n->in_in[0];
971 	else if (n->in_v == 6)
972 		n->in_next6 = n->in_out[0];
973 	else
974 #endif
975 	if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) &&
976 	    ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0))
977 		n->in_nip = ntohl(n->in_outip) + 1;
978 	else if ((n->in_flags & IPN_SPLIT) &&
979 		 (n->in_redir & NAT_REDIRECT))
980 		n->in_nip = ntohl(n->in_inip);
981 	else
982 		n->in_nip = ntohl(n->in_outip);
983 
984 	if (n->in_redir & NAT_MAP) {
985 		n->in_pnext = ntohs(n->in_pmin);
986 		/*
987 		 * Multiply by the number of ports made available.
988 		 */
989 		if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) {
990 			n->in_space *= (ntohs(n->in_pmax) -
991 					ntohs(n->in_pmin) + 1);
992 			/*
993 			 * Because two different sources can map to
994 			 * different destinations but use the same
995 			 * local IP#/port #.
996 			 * If the result is smaller than in_space, then
997 			 * we may have wrapped around 32bits.
998 			 */
999 			i = n->in_inmsk;
1000 			if ((i != 0) && (i != 0xffffffff)) {
1001 				j = n->in_space * (~ntohl(i) + 1);
1002 				if (j >= n->in_space)
1003 					n->in_space = j;
1004 				else
1005 					n->in_space = 0xffffffff;
1006 			}
1007 		}
1008 		/*
1009 		 * If no protocol is specified, multiple by 256 to allow for
1010 		 * at least one IP:IP mapping per protocol.
1011 		 */
1012 		if ((n->in_flags & IPN_TCPUDPICMP) == 0) {
1013 				j = n->in_space * 256;
1014 				if (j >= n->in_space)
1015 					n->in_space = j;
1016 				else
1017 					n->in_space = 0xffffffff;
1018 		}
1019 	}
1020 
1021 	/* Otherwise, these fields are preset */
1022 
1023 	if (getlock) {
1024 		WRITE_ENTER(&ifs->ifs_ipf_nat);
1025 	}
1026 	n->in_next = NULL;
1027 	*np = n;
1028 
1029 	if (n->in_age[0] != 0)
1030 	    n->in_tqehead[0] = fr_addtimeoutqueue(&ifs->ifs_nat_utqe,
1031 						  n->in_age[0], ifs);
1032 
1033 	if (n->in_age[1] != 0)
1034 	    n->in_tqehead[1] = fr_addtimeoutqueue(&ifs->ifs_nat_utqe,
1035 						  n->in_age[1], ifs);
1036 
1037 	if (n->in_redir & NAT_REDIRECT) {
1038 		n->in_flags &= ~IPN_NOTDST;
1039 		switch (n->in_v)
1040 		{
1041 		case 4 :
1042 			nat_addrdr(n, ifs);
1043 			break;
1044 #ifdef	USE_INET6
1045 		case 6 :
1046 			nat6_addrdr(n, ifs);
1047 			break;
1048 #endif
1049 		default :
1050 			break;
1051 		}
1052 	}
1053 	if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
1054 		n->in_flags &= ~IPN_NOTSRC;
1055 		switch (n->in_v)
1056 		{
1057 		case 4 :
1058 			nat_addnat(n, ifs);
1059 			break;
1060 #ifdef	USE_INET6
1061 		case 6 :
1062 			nat6_addnat(n, ifs);
1063 			break;
1064 #endif
1065 		default :
1066 			break;
1067 		}
1068 	}
1069 	n = NULL;
1070 	ifs->ifs_nat_stats.ns_rules++;
1071 	if (getlock) {
1072 		RWLOCK_EXIT(&ifs->ifs_ipf_nat);			/* WRITE */
1073 	}
1074 
1075 	return error;
1076 }
1077 
1078 
1079 /* ------------------------------------------------------------------------ */
1080 /* Function:    nat_resolvrule                                              */
1081 /* Returns:     int - 0 == success, -1 == failure                           */
1082 /* Parameters:  n(I)  - pointer to NAT rule                                 */
1083 /*                                                                          */
1084 /* Resolve some of the details inside the NAT rule.  Includes resolving	    */
1085 /* any specified interfaces and proxy labels, and determines whether or not */
1086 /* all proxy labels are correctly specified.				    */
1087 /*									    */
1088 /* Called by nat_siocaddnat() (SIOCADNAT) and fr_natputent (SIOCSTPUT).     */
1089 /* ------------------------------------------------------------------------ */
1090 static int nat_resolverule(n, ifs)
1091 ipnat_t *n;
1092 ipf_stack_t *ifs;
1093 {
1094 	n->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
1095 	n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], n->in_v, ifs);
1096 
1097 	n->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
1098 	if (n->in_ifnames[1][0] == '\0') {
1099 		(void) strncpy(n->in_ifnames[1], n->in_ifnames[0], LIFNAMSIZ);
1100 		n->in_ifps[1] = n->in_ifps[0];
1101 	} else {
1102 		n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], n->in_v, ifs);
1103 	}
1104 
1105 	if (n->in_plabel[0] != '\0') {
1106 		n->in_apr = appr_lookup(n->in_p, n->in_plabel, ifs);
1107 		if (n->in_apr == NULL)
1108 			return -1;
1109 	}
1110 	return 0;
1111 }
1112 
1113 
1114 /* ------------------------------------------------------------------------ */
1115 /* Function:    nat_siocdelnat                                              */
1116 /* Returns:     int - 0 == success, != 0 == failure                         */
1117 /* Parameters:  n(I)       - pointer to new NAT rule                        */
1118 /*              np(I)      - pointer to where to insert new NAT rule        */
1119 /*              getlock(I) - flag indicating if lock on ipf_nat is held     */
1120 /* Mutex Locks: ipf_natio                                                   */
1121 /*                                                                          */
1122 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
1123 /* from information passed to the kernel, then add it  to the appropriate   */
1124 /* NAT rule table(s).                                                       */
1125 /* ------------------------------------------------------------------------ */
1126 static void nat_siocdelnat(n, np, getlock, ifs)
1127 ipnat_t *n, **np;
1128 int getlock;
1129 ipf_stack_t *ifs;
1130 {
1131 	int i;
1132 
1133 	if (getlock) {
1134 		WRITE_ENTER(&ifs->ifs_ipf_nat);
1135 	}
1136 	if (n->in_redir & NAT_REDIRECT)
1137 		nat_delrdr(n);
1138 	if (n->in_redir & (NAT_MAPBLK|NAT_MAP))
1139 		nat_delnat(n);
1140 	if (ifs->ifs_nat_list == NULL) {
1141 		ifs->ifs_nat_masks = 0;
1142 		ifs->ifs_rdr_masks = 0;
1143 		for (i = 0; i < 4; i++) {
1144 			ifs->ifs_nat6_masks[i] = 0;
1145 			ifs->ifs_rdr6_masks[i] = 0;
1146 		}
1147 	}
1148 
1149 	if (n->in_tqehead[0] != NULL) {
1150 		if (fr_deletetimeoutqueue(n->in_tqehead[0]) == 0) {
1151 			fr_freetimeoutqueue(n->in_tqehead[0], ifs);
1152 		}
1153 	}
1154 
1155 	if (n->in_tqehead[1] != NULL) {
1156 		if (fr_deletetimeoutqueue(n->in_tqehead[1]) == 0) {
1157 			fr_freetimeoutqueue(n->in_tqehead[1], ifs);
1158 		}
1159 	}
1160 
1161 	*np = n->in_next;
1162 
1163 	if (n->in_use == 0) {
1164 		if (n->in_apr)
1165 			appr_free(n->in_apr);
1166 		KFREE(n);
1167 		ifs->ifs_nat_stats.ns_rules--;
1168 	} else {
1169 		n->in_flags |= IPN_DELETE;
1170 		n->in_next = NULL;
1171 	}
1172 	if (getlock) {
1173 		RWLOCK_EXIT(&ifs->ifs_ipf_nat);			/* READ/WRITE */
1174 	}
1175 }
1176 
1177 
1178 /* ------------------------------------------------------------------------ */
1179 /* Function:    fr_natgetsz                                                 */
1180 /* Returns:     int - 0 == success, != 0 is the error value.                */
1181 /* Parameters:  data(I) - pointer to natget structure with kernel pointer   */
1182 /*                        get the size of.                                  */
1183 /*                                                                          */
1184 /* Handle SIOCSTGSZ.                                                        */
1185 /* Return the size of the nat list entry to be copied back to user space.   */
1186 /* The size of the entry is stored in the ng_sz field and the enture natget */
1187 /* structure is copied back to the user.                                    */
1188 /* ------------------------------------------------------------------------ */
1189 static int fr_natgetsz(data, ifs)
1190 caddr_t data;
1191 ipf_stack_t *ifs;
1192 {
1193 	ap_session_t *aps;
1194 	nat_t *nat, *n;
1195 	natget_t ng;
1196 	int err;
1197 
1198 	err = BCOPYIN(data, &ng, sizeof(ng));
1199 	if (err != 0)
1200 		return EFAULT;
1201 
1202 	nat = ng.ng_ptr;
1203 	if (!nat) {
1204 		nat = ifs->ifs_nat_instances;
1205 		ng.ng_sz = 0;
1206 		/*
1207 		 * Empty list so the size returned is 0.  Simple.
1208 		 */
1209 		if (nat == NULL) {
1210 			err = BCOPYOUT(&ng, data, sizeof(ng));
1211 			if (err != 0) {
1212 				return EFAULT;
1213 			} else {
1214 				return 0;
1215 			}
1216 		}
1217 	} else {
1218 		/*
1219 		 * Make sure the pointer we're copying from exists in the
1220 		 * current list of entries.  Security precaution to prevent
1221 		 * copying of random kernel data.
1222 		 */
1223 		for (n = ifs->ifs_nat_instances; n; n = n->nat_next)
1224 			if (n == nat)
1225 				break;
1226 		if (!n)
1227 			return ESRCH;
1228 	}
1229 
1230 	/*
1231 	 * Incluse any space required for proxy data structures.
1232 	 */
1233 	ng.ng_sz = sizeof(nat_save_t);
1234 	aps = nat->nat_aps;
1235 	if (aps != NULL) {
1236 		ng.ng_sz += sizeof(ap_session_t) - 4;
1237 		if (aps->aps_data != 0)
1238 			ng.ng_sz += aps->aps_psiz;
1239 	}
1240 
1241 	err = BCOPYOUT(&ng, data, sizeof(ng));
1242 	if (err != 0)
1243 		return EFAULT;
1244 	return 0;
1245 }
1246 
1247 
1248 /* ------------------------------------------------------------------------ */
1249 /* Function:    fr_natgetent                                                */
1250 /* Returns:     int - 0 == success, != 0 is the error value.                */
1251 /* Parameters:  data(I) - pointer to natget structure with kernel pointer   */
1252 /*                        to NAT structure to copy out.                     */
1253 /*                                                                          */
1254 /* Handle SIOCSTGET.                                                        */
1255 /* Copies out NAT entry to user space.  Any additional data held for a      */
1256 /* proxy is also copied, as to is the NAT rule which was responsible for it */
1257 /* ------------------------------------------------------------------------ */
1258 static int fr_natgetent(data, ifs)
1259 caddr_t data;
1260 ipf_stack_t *ifs;
1261 {
1262 	int error, outsize;
1263 	ap_session_t *aps;
1264 	nat_save_t *ipn, ipns;
1265 	nat_t *n, *nat;
1266 
1267 	error = fr_inobj(data, &ipns, IPFOBJ_NATSAVE);
1268 	if (error != 0)
1269 		return error;
1270 
1271 	if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920))
1272 		return EINVAL;
1273 
1274 	KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize);
1275 	if (ipn == NULL)
1276 		return ENOMEM;
1277 
1278 	ipn->ipn_dsize = ipns.ipn_dsize;
1279 	nat = ipns.ipn_next;
1280 	if (nat == NULL) {
1281 		nat = ifs->ifs_nat_instances;
1282 		if (nat == NULL) {
1283 			if (ifs->ifs_nat_instances == NULL)
1284 				error = ENOENT;
1285 			goto finished;
1286 		}
1287 	} else {
1288 		/*
1289 		 * Make sure the pointer we're copying from exists in the
1290 		 * current list of entries.  Security precaution to prevent
1291 		 * copying of random kernel data.
1292 		 */
1293 		for (n = ifs->ifs_nat_instances; n; n = n->nat_next)
1294 			if (n == nat)
1295 				break;
1296 		if (n == NULL) {
1297 			error = ESRCH;
1298 			goto finished;
1299 		}
1300 	}
1301 	ipn->ipn_next = nat->nat_next;
1302 
1303 	/*
1304 	 * Copy the NAT structure.
1305 	 */
1306 	bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat));
1307 
1308 	/*
1309 	 * If we have a pointer to the NAT rule it belongs to, save that too.
1310 	 */
1311 	if (nat->nat_ptr != NULL)
1312 		bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat,
1313 		      sizeof(ipn->ipn_ipnat));
1314 
1315 	/*
1316 	 * If we also know the NAT entry has an associated filter rule,
1317 	 * save that too.
1318 	 */
1319 	if (nat->nat_fr != NULL)
1320 		bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr,
1321 		      sizeof(ipn->ipn_fr));
1322 
1323 	/*
1324 	 * Last but not least, if there is an application proxy session set
1325 	 * up for this NAT entry, then copy that out too, including any
1326 	 * private data saved along side it by the proxy.
1327 	 */
1328 	aps = nat->nat_aps;
1329 	outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data);
1330 	if (aps != NULL) {
1331 		char *s;
1332 
1333 		if (outsize < sizeof(*aps)) {
1334 			error = ENOBUFS;
1335 			goto finished;
1336 		}
1337 
1338 		s = ipn->ipn_data;
1339 		bcopy((char *)aps, s, sizeof(*aps));
1340 		s += sizeof(*aps);
1341 		outsize -= sizeof(*aps);
1342 		if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz))
1343 			bcopy(aps->aps_data, s, aps->aps_psiz);
1344 		else
1345 			error = ENOBUFS;
1346 	}
1347 	if (error == 0) {
1348 		error = fr_outobjsz(data, ipn, IPFOBJ_NATSAVE, ipns.ipn_dsize);
1349 	}
1350 
1351 finished:
1352 	if (ipn != NULL) {
1353 		KFREES(ipn, ipns.ipn_dsize);
1354 	}
1355 	return error;
1356 }
1357 
1358 /* ------------------------------------------------------------------------ */
1359 /* Function:    nat_calc_chksum_diffs					    */
1360 /* Returns:     void							    */
1361 /* Parameters:  nat	-	pointer to NAT table entry		    */
1362 /*                                                                          */
1363 /* Function calculates chksum deltas for IP header (nat_ipsumd) and TCP/UDP */
1364 /* headers (nat_sumd). The things for L4 (UDP/TCP) get complicated when     */
1365 /* we are dealing with partial chksum offload. For these cases we need to   */
1366 /* compute a 'partial chksum delta'. The 'partial chksum delta'is stored    */
1367 /* into nat_sumd[1], while ordinary chksum delta for TCP/UDP is in 	    */
1368 /* nat_sumd[0]. 							    */
1369 /*									    */
1370 /* The function accepts initialized NAT table entry and computes the deltas */
1371 /* from nat_inip/nat_outip members. The function is called right before	    */
1372 /* the new entry is inserted into the table.				    */
1373 /*									    */
1374 /* The ipsumd (IP hedaer chksum delta adjustment) is computed as a chksum   */
1375 /* of delta between original and new IP addresses.			    */
1376 /*									    */
1377 /* the nat_sumd[0] (TCP/UDP header chksum delta adjustment) is computed as  */
1378 /* a chkusm of delta between original an new IP addrress:port tupples.	    */
1379 /*									    */
1380 /* Some facts about chksum, we should remember:				    */
1381 /*	IP header chksum covers IP header only				    */
1382 /*									    */
1383 /*	TCP/UDP chksum covers data payload and so called pseudo header	    */
1384 /*		SRC, DST IP address					    */
1385 /*		SRC, DST Port						    */
1386 /*		length of payload					    */
1387 /*									    */
1388 /* The partial chksum delta (nat_sumd[1] is used to adjust db_ckusm16	    */
1389 /* member of dblk_t structure. The db_ckusm16 member is not part of 	    */
1390 /* IP/UDP/TCP header it is 16 bit value computed by NIC driver with partial */
1391 /* chksum offload capacbility for every inbound packet. The db_cksum16 is   */
1392 /* stored along with other IP packet data in dblk_t structure and used in   */
1393 /* for IP/UDP/TCP chksum validation later in ip.c. 			    */
1394 /*									    */
1395 /* The partial chksum delta (adjustment, nat_sumd[1]) is computed as chksum */
1396 /* of delta between new and orig address. NOTE: the order of operands for   */
1397 /* partial delta operation is swapped compared to computing the IP/TCP/UDP  */
1398 /* header adjustment. It is by design see (IP_CKSUM_RECV() macro in ip.c).  */
1399 /*									    */
1400 /* ------------------------------------------------------------------------ */
1401 void nat_calc_chksum_diffs(nat)
1402 nat_t *nat;
1403 {
1404 	u_32_t	sum_orig = 0;
1405 	u_32_t	sum_changed = 0;
1406 	u_32_t	sumd;
1407 	u_32_t	ipsum_orig = 0;
1408 	u_32_t	ipsum_changed = 0;
1409 
1410 	if (nat->nat_v != 4 && nat->nat_v != 6)
1411 		return;
1412 
1413 	/*
1414 	 * the switch calculates operands for CALC_SUMD(),
1415 	 * which will compute the partial chksum delta.
1416 	 */
1417 	switch (nat->nat_dir)
1418 	{
1419 	case NAT_INBOUND:
1420 		/*
1421 		 * we are dealing with RDR rule (DST address gets
1422 		 * modified on packet from client)
1423 		 */
1424 		if (nat->nat_v == 4) {
1425 			sum_changed = LONG_SUM(ntohl(nat->nat_inip.s_addr));
1426 			sum_orig = LONG_SUM(ntohl(nat->nat_outip.s_addr));
1427 		} else {
1428 			sum_changed = LONG_SUM6(&nat->nat_inip6);
1429 			sum_orig = LONG_SUM6(&nat->nat_outip6);
1430 		}
1431 		break;
1432 	case NAT_OUTBOUND:
1433 		/*
1434 		 * we are dealing with MAP rule (SRC address gets
1435 		 * modified on packet from client)
1436 		 */
1437 		if (nat->nat_v == 4) {
1438 			sum_changed = LONG_SUM(ntohl(nat->nat_outip.s_addr));
1439 			sum_orig = LONG_SUM(ntohl(nat->nat_inip.s_addr));
1440 		} else {
1441 			sum_changed = LONG_SUM6(&nat->nat_outip6);
1442 			sum_orig = LONG_SUM6(&nat->nat_inip6);
1443 		}
1444 		break;
1445 	default: ;
1446 		break;
1447 	}
1448 
1449 	/*
1450 	 * we also preserve CALC_SUMD() operands here, for IP chksum delta
1451 	 * calculation, which happens at the end of function.
1452 	 */
1453 	ipsum_changed = sum_changed;
1454 	ipsum_orig = sum_orig;
1455 	/*
1456 	 * NOTE: the order of operands for partial chksum adjustment
1457 	 * computation has to be swapped!
1458 	 */
1459 	CALC_SUMD(sum_changed, sum_orig, sumd);
1460 	nat->nat_sumd[1] = (sumd & 0xffff) + (sumd >> 16);
1461 
1462 	if (nat->nat_flags & (IPN_TCPUDP | IPN_ICMPQUERY)) {
1463 
1464 		/*
1465 		 * switch calculates operands for CALC_SUMD(), which will
1466 		 * compute the full chksum delta.
1467 		 */
1468 		switch (nat->nat_dir)
1469 		{
1470 		case NAT_INBOUND:
1471 			if (nat->nat_v == 4) {
1472 				sum_changed = LONG_SUM(
1473 				    ntohl(nat->nat_inip.s_addr) +
1474 				    ntohs(nat->nat_inport));
1475 				sum_orig = LONG_SUM(
1476 				    ntohl(nat->nat_outip.s_addr) +
1477 				    ntohs(nat->nat_outport));
1478 			} else {
1479 				sum_changed = LONG_SUM6(&nat->nat_inip6) +
1480 				    ntohs(nat->nat_inport);
1481 				sum_orig = LONG_SUM6(&nat->nat_outip6) +
1482 				    ntohs(nat->nat_outport);
1483 			}
1484 			break;
1485 		case NAT_OUTBOUND:
1486 			if (nat->nat_v == 4) {
1487 				sum_changed = LONG_SUM(
1488 				    ntohl(nat->nat_outip.s_addr) +
1489 				    ntohs(nat->nat_outport));
1490 				sum_orig = LONG_SUM(
1491 				    ntohl(nat->nat_inip.s_addr) +
1492 				    ntohs(nat->nat_inport));
1493 			} else {
1494 				sum_changed = LONG_SUM6(&nat->nat_outip6) +
1495 				    ntohs(nat->nat_outport);
1496 				sum_orig = LONG_SUM6(&nat->nat_inip6) +
1497 				    ntohs(nat->nat_inport);
1498 			}
1499 			break;
1500 		default: ;
1501 			break;
1502 		}
1503 
1504 		CALC_SUMD(sum_orig, sum_changed, sumd);
1505 		nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
1506 
1507 		if (!(nat->nat_flags & IPN_TCPUDP)) {
1508 			/*
1509 			 * partial HW chksum offload works for TCP/UDP headers only,
1510 			 * so we need to enforce full chksum adjustment for ICMP
1511 			 */
1512 			nat->nat_sumd[1] = nat->nat_sumd[0];
1513 		}
1514 	}
1515 	else
1516 		nat->nat_sumd[0] = nat->nat_sumd[1];
1517 
1518 	/*
1519 	 * we may reuse the already computed nat_sumd[0] for IP header chksum
1520 	 * adjustment in case the L4 (TCP/UDP header) is not changed by NAT.
1521 	 */
1522 	if (nat->nat_v == 4) {
1523 		if (NAT_HAS_L4_CHANGED(nat)) {
1524 			/*
1525 			 * bad luck, NAT changes also the L4 header, use IP
1526 			 * addresses to compute chksum adjustment for IP header.
1527 			 */
1528 			CALC_SUMD(ipsum_orig, ipsum_changed, sumd);
1529 			nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
1530 		} else {
1531 			/*
1532 			 * the NAT does not change L4 hdr -> reuse chksum
1533 			 * adjustment for IP hdr.
1534 			 */
1535 			nat->nat_ipsumd = nat->nat_sumd[0];
1536 
1537 			/*
1538 			 * if L4 header does not use chksum - zero out deltas
1539 			 */
1540 			if (!(nat->nat_flags & IPN_TCPUDP)) {
1541 				nat->nat_sumd[0] = 0;
1542 				nat->nat_sumd[1] = 0;
1543 			}
1544 		}
1545 	}
1546 
1547 	return;
1548 }
1549 
1550 /* ------------------------------------------------------------------------ */
1551 /* Function:    fr_natputent                                                */
1552 /* Returns:     int - 0 == success, != 0 is the error value.                */
1553 /* Parameters:  data(I)    - pointer to natget structure with NAT           */
1554 /*                           structure information to load into the kernel  */
1555 /*              getlock(I) - flag indicating whether or not a write lock    */
1556 /*                           on ipf_nat is already held.                    */
1557 /*              ifs        - ipf stack instance                             */
1558 /*                                                                          */
1559 /* Handle SIOCSTPUT.                                                        */
1560 /* Loads a NAT table entry from user space, including a NAT rule, proxy and */
1561 /* firewall rule data structures, if pointers to them indicate so.          */
1562 /* ------------------------------------------------------------------------ */
1563 static int fr_natputent(data, getlock, ifs)
1564 caddr_t data;
1565 int getlock;
1566 ipf_stack_t *ifs;
1567 {
1568 	nat_save_t ipn, *ipnn;
1569 	ap_session_t *aps;
1570 	nat_t *n, *nat;
1571 	frentry_t *fr;
1572 	fr_info_t fin;
1573 	ipnat_t *in;
1574 	int error;
1575 
1576 	error = fr_inobj(data, &ipn, IPFOBJ_NATSAVE);
1577 	if (error != 0)
1578 		return error;
1579 
1580 	/*
1581 	 * Trigger automatic call to nat_flushtable() if the
1582 	 * table has reached capcity specified by hi watermark.
1583 	 */
1584 	if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_level_hi)
1585 		ifs->ifs_nat_doflush = 1;
1586 
1587 	/*
1588 	 * If automatic flushing did not do its job, and the table
1589 	 * has filled up, don't try to create a new entry.
1590 	 */
1591 	if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) {
1592 		ifs->ifs_nat_stats.ns_memfail++;
1593 		return ENOMEM;
1594 	}
1595 
1596 	/*
1597 	 * Initialise early because of code at junkput label.
1598 	 */
1599 	in = NULL;
1600 	aps = NULL;
1601 	nat = NULL;
1602 	ipnn = NULL;
1603 
1604 	/*
1605 	 * New entry, copy in the rest of the NAT entry if it's size is more
1606 	 * than just the nat_t structure.
1607 	 */
1608 	fr = NULL;
1609 	if (ipn.ipn_dsize > sizeof(ipn)) {
1610 		if (ipn.ipn_dsize > 81920) {
1611 			error = ENOMEM;
1612 			goto junkput;
1613 		}
1614 
1615 		KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize);
1616 		if (ipnn == NULL)
1617 			return ENOMEM;
1618 
1619 		error = fr_inobjsz(data, ipnn, IPFOBJ_NATSAVE, ipn.ipn_dsize);
1620 		if (error != 0) {
1621 			error = EFAULT;
1622 			goto junkput;
1623 		}
1624 	} else
1625 		ipnn = &ipn;
1626 
1627 	KMALLOC(nat, nat_t *);
1628 	if (nat == NULL) {
1629 		error = ENOMEM;
1630 		goto junkput;
1631 	}
1632 
1633 	bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat));
1634 	/*
1635 	 * Initialize all these so that nat_delete() doesn't cause a crash.
1636 	 */
1637 	bzero((char *)nat, offsetof(struct nat, nat_tqe));
1638 	nat->nat_tqe.tqe_pnext = NULL;
1639 	nat->nat_tqe.tqe_next = NULL;
1640 	nat->nat_tqe.tqe_ifq = NULL;
1641 	nat->nat_tqe.tqe_parent = nat;
1642 
1643 	/*
1644 	 * Restore the rule associated with this nat session
1645 	 */
1646 	in = ipnn->ipn_nat.nat_ptr;
1647 	if (in != NULL) {
1648 		KMALLOC(in, ipnat_t *);
1649 		nat->nat_ptr = in;
1650 		if (in == NULL) {
1651 			error = ENOMEM;
1652 			goto junkput;
1653 		}
1654 		bzero((char *)in, offsetof(struct ipnat, in_next6));
1655 		bcopy((char *)&ipnn->ipn_ipnat, (char *)in, sizeof(*in));
1656 		in->in_use = 1;
1657 		in->in_flags |= IPN_DELETE;
1658 
1659 		ATOMIC_INC(ifs->ifs_nat_stats.ns_rules);
1660 
1661 		if (nat_resolverule(in, ifs) != 0) {
1662 			error = ESRCH;
1663 			goto junkput;
1664 		}
1665 	}
1666 
1667 	/*
1668 	 * Check that the NAT entry doesn't already exist in the kernel.
1669 	 */
1670 	if (nat->nat_v != 6)
1671 		nat->nat_v = 4;
1672 	bzero((char *)&fin, sizeof(fin));
1673 	fin.fin_p = nat->nat_p;
1674 	fin.fin_ifs = ifs;
1675 	if (nat->nat_dir == NAT_OUTBOUND) {
1676 		fin.fin_data[0] = ntohs(nat->nat_oport);
1677 		fin.fin_data[1] = ntohs(nat->nat_outport);
1678 		fin.fin_ifp = nat->nat_ifps[0];
1679 		if (getlock) {
1680 			READ_ENTER(&ifs->ifs_ipf_nat);
1681 		}
1682 
1683 		switch (nat->nat_v)
1684 		{
1685 		case 4:
1686 			fin.fin_v = nat->nat_v;
1687 			n = nat_inlookup(&fin, nat->nat_flags, fin.fin_p,
1688 			    nat->nat_oip, nat->nat_outip);
1689 			break;
1690 #ifdef USE_INET6
1691 		case 6:
1692 			n = nat6_inlookup(&fin, nat->nat_flags, fin.fin_p,
1693 			    &nat->nat_oip6.in6, &nat->nat_outip6.in6);
1694 			break;
1695 #endif
1696 		default:
1697 			n = NULL;
1698 			break;
1699 		}
1700 
1701 		if (getlock) {
1702 			RWLOCK_EXIT(&ifs->ifs_ipf_nat);
1703 		}
1704 		if (n != NULL) {
1705 			error = EEXIST;
1706 			goto junkput;
1707 		}
1708 	} else if (nat->nat_dir == NAT_INBOUND) {
1709 		fin.fin_data[0] = ntohs(nat->nat_inport);
1710 		fin.fin_data[1] = ntohs(nat->nat_oport);
1711 		fin.fin_ifp = nat->nat_ifps[1];
1712 		if (getlock) {
1713 			READ_ENTER(&ifs->ifs_ipf_nat);
1714 		}
1715 
1716 		switch (nat->nat_v)
1717 		{
1718 		case 4:
1719 			n = nat_outlookup(&fin, nat->nat_flags, fin.fin_p,
1720 			    nat->nat_inip, nat->nat_oip);
1721 			break;
1722 #ifdef USE_INET6
1723 		case 6:
1724 			n = nat6_outlookup(&fin, nat->nat_flags, fin.fin_p,
1725 			    &nat->nat_inip6.in6, &nat->nat_oip6.in6);
1726 			break;
1727 #endif
1728 		default:
1729 			n = NULL;
1730 			break;
1731 		}
1732 
1733 		if (getlock) {
1734 			RWLOCK_EXIT(&ifs->ifs_ipf_nat);
1735 		}
1736 		if (n != NULL) {
1737 			error = EEXIST;
1738 			goto junkput;
1739 		}
1740 	} else {
1741 		error = EINVAL;
1742 		goto junkput;
1743 	}
1744 
1745 	/*
1746 	 * Restore ap_session_t structure.  Include the private data allocated
1747 	 * if it was there.
1748 	 */
1749 	aps = nat->nat_aps;
1750 	if (aps != NULL) {
1751 		KMALLOC(aps, ap_session_t *);
1752 		nat->nat_aps = aps;
1753 		if (aps == NULL) {
1754 			error = ENOMEM;
1755 			goto junkput;
1756 		}
1757 		bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps));
1758 		if (in != NULL)
1759 			aps->aps_apr = in->in_apr;
1760 		else
1761 			aps->aps_apr = NULL;
1762 		if (aps->aps_psiz != 0) {
1763 			if (aps->aps_psiz > 81920) {
1764 				error = ENOMEM;
1765 				goto junkput;
1766 			}
1767 			KMALLOCS(aps->aps_data, void *, aps->aps_psiz);
1768 			if (aps->aps_data == NULL) {
1769 				error = ENOMEM;
1770 				goto junkput;
1771 			}
1772 			bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data,
1773 			      aps->aps_psiz);
1774 		} else {
1775 			aps->aps_psiz = 0;
1776 			aps->aps_data = NULL;
1777 		}
1778 	}
1779 
1780 	/*
1781 	 * If there was a filtering rule associated with this entry then
1782 	 * build up a new one.
1783 	 */
1784 	fr = nat->nat_fr;
1785 	if (fr != NULL) {
1786 		if ((nat->nat_flags & SI_NEWFR) != 0) {
1787 			KMALLOC(fr, frentry_t *);
1788 			nat->nat_fr = fr;
1789 			if (fr == NULL) {
1790 				error = ENOMEM;
1791 				goto junkput;
1792 			}
1793 			ipnn->ipn_nat.nat_fr = fr;
1794 			(void) fr_outobj(data, ipnn, IPFOBJ_NATSAVE);
1795 			bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr));
1796 
1797 			fr->fr_ref = 1;
1798 			fr->fr_dsize = 0;
1799 			fr->fr_data = NULL;
1800 			fr->fr_type = FR_T_NONE;
1801 
1802 			MUTEX_NUKE(&fr->fr_lock);
1803 			MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock");
1804 		} else {
1805 			if (getlock) {
1806 				READ_ENTER(&ifs->ifs_ipf_nat);
1807 			}
1808 			for (n = ifs->ifs_nat_instances; n; n = n->nat_next)
1809 				if (n->nat_fr == fr)
1810 					break;
1811 
1812 			if (n != NULL) {
1813 				MUTEX_ENTER(&fr->fr_lock);
1814 				fr->fr_ref++;
1815 				MUTEX_EXIT(&fr->fr_lock);
1816 			}
1817 			if (getlock) {
1818 				RWLOCK_EXIT(&ifs->ifs_ipf_nat);
1819 			}
1820 			if (!n) {
1821 				error = ESRCH;
1822 				goto junkput;
1823 			}
1824 		}
1825 	}
1826 
1827 	if (ipnn != &ipn) {
1828 		KFREES(ipnn, ipn.ipn_dsize);
1829 		ipnn = NULL;
1830 	}
1831 
1832 	nat_calc_chksum_diffs(nat);
1833 
1834 	if (getlock) {
1835 		WRITE_ENTER(&ifs->ifs_ipf_nat);
1836 	}
1837 
1838 	nat_calc_chksum_diffs(nat);
1839 
1840 	switch (nat->nat_v)
1841 	{
1842 	case 4 :
1843 		error = nat_insert(nat, nat->nat_rev, ifs);
1844 		break;
1845 #ifdef USE_INET6
1846 	case 6 :
1847 		error = nat6_insert(nat, nat->nat_rev, ifs);
1848 		break;
1849 #endif
1850 	default :
1851 		break;
1852 	}
1853 
1854 	if ((error == 0) && (aps != NULL)) {
1855 		aps->aps_next = ifs->ifs_ap_sess_list;
1856 		ifs->ifs_ap_sess_list = aps;
1857 	}
1858 	if (getlock) {
1859 		RWLOCK_EXIT(&ifs->ifs_ipf_nat);
1860 	}
1861 
1862 	if (error == 0)
1863 		return 0;
1864 
1865 	error = ENOMEM;
1866 
1867 junkput:
1868 	if (fr != NULL)
1869 		(void) fr_derefrule(&fr, ifs);
1870 
1871 	if ((ipnn != NULL) && (ipnn != &ipn)) {
1872 		KFREES(ipnn, ipn.ipn_dsize);
1873 	}
1874 	if (nat != NULL) {
1875 		if (aps != NULL) {
1876 			if (aps->aps_data != NULL) {
1877 				KFREES(aps->aps_data, aps->aps_psiz);
1878 			}
1879 			KFREE(aps);
1880 		}
1881 		if (in != NULL) {
1882 			if (in->in_apr)
1883 				appr_free(in->in_apr);
1884 			KFREE(in);
1885 		}
1886 		KFREE(nat);
1887 	}
1888 	return error;
1889 }
1890 
1891 
1892 /* ------------------------------------------------------------------------ */
1893 /* Function:    nat_delete                                                  */
1894 /* Returns:     int	- 0 if entry deleted. Otherwise, ref count on entry */
1895 /* Parameters:  nat	- pointer to the NAT entry to delete		    */
1896 /*		logtype	- type of LOG record to create before deleting	    */
1897 /*		ifs	- ipf stack instance				    */
1898 /* Write Lock:  ipf_nat                                                     */
1899 /*                                                                          */
1900 /* Delete a nat entry from the various lists and table.  If NAT logging is  */
1901 /* enabled then generate a NAT log record for this event.                   */
1902 /* ------------------------------------------------------------------------ */
1903 int nat_delete(nat, logtype, ifs)
1904 struct nat *nat;
1905 int logtype;
1906 ipf_stack_t *ifs;
1907 {
1908 	struct ipnat *ipn;
1909 	int removed = 0;
1910 
1911 	if (logtype != 0 && ifs->ifs_nat_logging != 0)
1912 		nat_log(nat, logtype, ifs);
1913 
1914 	/*
1915 	 * Start by removing the entry from the hash table of nat entries
1916 	 * so it will not be "used" again.
1917 	 *
1918 	 * It will remain in the "list" of nat entries until all references
1919 	 * have been accounted for.
1920 	 */
1921 	if ((nat->nat_phnext[0] != NULL) && (nat->nat_phnext[1] != NULL)) {
1922 		removed = 1;
1923 
1924 		ifs->ifs_nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--;
1925 		ifs->ifs_nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--;
1926 
1927 		*nat->nat_phnext[0] = nat->nat_hnext[0];
1928 		if (nat->nat_hnext[0] != NULL) {
1929 			nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
1930 			nat->nat_hnext[0] = NULL;
1931 		}
1932 		nat->nat_phnext[0] = NULL;
1933 
1934 		*nat->nat_phnext[1] = nat->nat_hnext[1];
1935 		if (nat->nat_hnext[1] != NULL) {
1936 			nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
1937 			nat->nat_hnext[1] = NULL;
1938 		}
1939 		nat->nat_phnext[1] = NULL;
1940 
1941 		if ((nat->nat_flags & SI_WILDP) != 0)
1942 			ifs->ifs_nat_stats.ns_wilds--;
1943 	}
1944 
1945 	/*
1946 	 * Next, remove it from the timeout queue it is in.
1947 	 */
1948 	fr_deletequeueentry(&nat->nat_tqe);
1949 
1950 	if (nat->nat_me != NULL) {
1951 		*nat->nat_me = NULL;
1952 		nat->nat_me = NULL;
1953 	}
1954 
1955 	MUTEX_ENTER(&nat->nat_lock);
1956  	if (nat->nat_ref > 1) {
1957 		nat->nat_ref--;
1958 		MUTEX_EXIT(&nat->nat_lock);
1959  		if (removed)
1960  			ifs->ifs_nat_stats.ns_orphans++;
1961 		return (nat->nat_ref);
1962 	}
1963 	MUTEX_EXIT(&nat->nat_lock);
1964 
1965 	nat->nat_ref = 0;
1966 
1967 	/*
1968 	 * If entry had already been removed,
1969 	 * it means we're cleaning up an orphan.
1970 	 */
1971  	if (!removed)
1972  		ifs->ifs_nat_stats.ns_orphans--;
1973 
1974 #ifdef	IPFILTER_SYNC
1975 	if (nat->nat_sync)
1976 		ipfsync_del(nat->nat_sync);
1977 #endif
1978 
1979 	/*
1980 	 * Now remove it from master list of nat table entries
1981 	 */
1982 	if (nat->nat_pnext != NULL) {
1983 		*nat->nat_pnext = nat->nat_next;
1984 		if (nat->nat_next != NULL) {
1985 			nat->nat_next->nat_pnext = nat->nat_pnext;
1986 			nat->nat_next = NULL;
1987 		}
1988 		nat->nat_pnext = NULL;
1989 	}
1990 
1991 	if (nat->nat_fr != NULL)
1992 		(void)fr_derefrule(&nat->nat_fr, ifs);
1993 
1994 	if (nat->nat_hm != NULL)
1995 		fr_hostmapdel(&nat->nat_hm);
1996 
1997 	/*
1998 	 * If there is an active reference from the nat entry to its parent
1999 	 * rule, decrement the rule's reference count and free it too if no
2000 	 * longer being used.
2001 	 */
2002 	ipn = nat->nat_ptr;
2003 	if (ipn != NULL) {
2004 		ipn->in_space++;
2005 		ipn->in_use--;
2006 		if (ipn->in_use == 0 && (ipn->in_flags & IPN_DELETE)) {
2007 			if (ipn->in_apr)
2008 				appr_free(ipn->in_apr);
2009 			KFREE(ipn);
2010 			ifs->ifs_nat_stats.ns_rules--;
2011 		}
2012 	}
2013 
2014 	MUTEX_DESTROY(&nat->nat_lock);
2015 
2016 	aps_free(nat->nat_aps, ifs);
2017 	ifs->ifs_nat_stats.ns_inuse--;
2018 
2019 	/*
2020 	 * If there's a fragment table entry too for this nat entry, then
2021 	 * dereference that as well.  This is after nat_lock is released
2022 	 * because of Tru64.
2023 	 */
2024 	fr_forgetnat((void *)nat, ifs);
2025 
2026 	KFREE(nat);
2027 
2028 	return (0);
2029 }
2030 
2031 
2032 /* ------------------------------------------------------------------------ */
2033 /* Function:    nat_clearlist                                               */
2034 /* Returns:     int - number of NAT/RDR rules deleted                       */
2035 /* Parameters:  Nil                                                         */
2036 /*                                                                          */
2037 /* Delete all rules in the current list of rules.  There is nothing elegant */
2038 /* about this cleanup: simply free all entries on the list of rules and     */
2039 /* clear out the tables used for hashed NAT rule lookups.                   */
2040 /* ------------------------------------------------------------------------ */
2041 static int nat_clearlist(ifs)
2042 ipf_stack_t *ifs;
2043 {
2044 	ipnat_t *n, **np = &ifs->ifs_nat_list;
2045 	int i = 0;
2046 
2047 	if (ifs->ifs_nat_rules != NULL)
2048 		bzero((char *)ifs->ifs_nat_rules,
2049 		      sizeof(*ifs->ifs_nat_rules) * ifs->ifs_ipf_natrules_sz);
2050 	if (ifs->ifs_rdr_rules != NULL)
2051 		bzero((char *)ifs->ifs_rdr_rules,
2052 		      sizeof(*ifs->ifs_rdr_rules) * ifs->ifs_ipf_rdrrules_sz);
2053 
2054 	while ((n = *np) != NULL) {
2055 		*np = n->in_next;
2056 		if (n->in_use == 0) {
2057 			if (n->in_apr != NULL)
2058 				appr_free(n->in_apr);
2059 			KFREE(n);
2060 			ifs->ifs_nat_stats.ns_rules--;
2061 		} else {
2062 			n->in_flags |= IPN_DELETE;
2063 			n->in_next = NULL;
2064 		}
2065 		i++;
2066 	}
2067 	ifs->ifs_nat_masks = 0;
2068 	ifs->ifs_rdr_masks = 0;
2069 	for (i = 0; i < 4; i++) {
2070 		ifs->ifs_nat6_masks[i] = 0;
2071 		ifs->ifs_rdr6_masks[i] = 0;
2072 	}
2073 	return i;
2074 }
2075 
2076 
2077 /* ------------------------------------------------------------------------ */
2078 /* Function:    nat_newmap                                                  */
2079 /* Returns:     int - -1 == error, 0 == success                             */
2080 /* Parameters:  fin(I) - pointer to packet information                      */
2081 /*              nat(I) - pointer to NAT entry                               */
2082 /*              ni(I)  - pointer to structure with misc. information needed */
2083 /*                       to create new NAT entry.                           */
2084 /*                                                                          */
2085 /* Given an empty NAT structure, populate it with new information about a   */
2086 /* new NAT session, as defined by the matching NAT rule.                    */
2087 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
2088 /* to the new IP address for the translation.                               */
2089 /* ------------------------------------------------------------------------ */
2090 static INLINE int nat_newmap(fin, nat, ni)
2091 fr_info_t *fin;
2092 nat_t *nat;
2093 natinfo_t *ni;
2094 {
2095 	u_short st_port, dport, sport, port, sp, dp;
2096 	struct in_addr in, inb;
2097 	hostmap_t *hm;
2098 	u_32_t flags;
2099 	u_32_t st_ip;
2100 	ipnat_t *np;
2101 	nat_t *natl;
2102 	int l;
2103 	ipf_stack_t *ifs = fin->fin_ifs;
2104 
2105 	/*
2106 	 * If it's an outbound packet which doesn't match any existing
2107 	 * record, then create a new port
2108 	 */
2109 	l = 0;
2110 	hm = NULL;
2111 	np = ni->nai_np;
2112 	st_ip = np->in_nip;
2113 	st_port = np->in_pnext;
2114 	flags = ni->nai_flags;
2115 	sport = ni->nai_sport;
2116 	dport = ni->nai_dport;
2117 
2118 	/*
2119 	 * Do a loop until we either run out of entries to try or we find
2120 	 * a NAT mapping that isn't currently being used.  This is done
2121 	 * because the change to the source is not (usually) being fixed.
2122 	 */
2123 	do {
2124 		port = 0;
2125 		in.s_addr = htonl(np->in_nip);
2126 		if (l == 0) {
2127 			/*
2128 			 * Check to see if there is an existing NAT
2129 			 * setup for this IP address pair.
2130 			 */
2131 			hm = nat_hostmap(np, fin->fin_src, fin->fin_dst,
2132 					 in, 0, ifs);
2133 			if (hm != NULL)
2134 				in.s_addr = hm->hm_mapip.s_addr;
2135 		} else if ((l == 1) && (hm != NULL)) {
2136 			fr_hostmapdel(&hm);
2137 		}
2138 		in.s_addr = ntohl(in.s_addr);
2139 
2140 		nat->nat_hm = hm;
2141 
2142 		if ((np->in_outmsk == 0xffffffff) && (np->in_pnext == 0)) {
2143 			if (l > 0)
2144 				return -1;
2145 		}
2146 
2147 		if (np->in_redir == NAT_BIMAP &&
2148 		    np->in_inmsk == np->in_outmsk) {
2149 			/*
2150 			 * map the address block in a 1:1 fashion
2151 			 */
2152 			in.s_addr = np->in_outip;
2153 			in.s_addr |= fin->fin_saddr & ~np->in_inmsk;
2154 			in.s_addr = ntohl(in.s_addr);
2155 
2156 		} else if (np->in_redir & NAT_MAPBLK) {
2157 			if ((l >= np->in_ppip) || ((l > 0) &&
2158 			     !(flags & IPN_TCPUDP)))
2159 				return -1;
2160 			/*
2161 			 * map-block - Calculate destination address.
2162 			 */
2163 			in.s_addr = ntohl(fin->fin_saddr);
2164 			in.s_addr &= ntohl(~np->in_inmsk);
2165 			inb.s_addr = in.s_addr;
2166 			in.s_addr /= np->in_ippip;
2167 			in.s_addr &= ntohl(~np->in_outmsk);
2168 			in.s_addr += ntohl(np->in_outip);
2169 			/*
2170 			 * Calculate destination port.
2171 			 */
2172 			if ((flags & IPN_TCPUDP) &&
2173 			    (np->in_ppip != 0)) {
2174 				port = ntohs(sport) + l;
2175 				port %= np->in_ppip;
2176 				port += np->in_ppip *
2177 					(inb.s_addr % np->in_ippip);
2178 				port += MAPBLK_MINPORT;
2179 				port = htons(port);
2180 			}
2181 
2182 		} else if ((np->in_outip == 0) &&
2183 			   (np->in_outmsk == 0xffffffff)) {
2184 			/*
2185 			 * 0/32 - use the interface's IP address.
2186 			 */
2187 			if ((l > 0) ||
2188 			    fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp,
2189 				       &in, NULL, fin->fin_ifs) == -1)
2190 				return -1;
2191 			in.s_addr = ntohl(in.s_addr);
2192 
2193 		} else if ((np->in_outip == 0) && (np->in_outmsk == 0)) {
2194 			/*
2195 			 * 0/0 - use the original source address/port.
2196 			 */
2197 			if (l > 0)
2198 				return -1;
2199 			in.s_addr = ntohl(fin->fin_saddr);
2200 
2201 		} else if ((np->in_outmsk != 0xffffffff) &&
2202 			   (np->in_pnext == 0) && ((l > 0) || (hm == NULL)))
2203 			np->in_nip++;
2204 
2205 		natl = NULL;
2206 
2207 		if ((flags & IPN_TCPUDP) &&
2208 		    ((np->in_redir & NAT_MAPBLK) == 0) &&
2209 		    (np->in_flags & IPN_AUTOPORTMAP)) {
2210 			/*
2211 			 * "ports auto" (without map-block)
2212 			 */
2213 			if ((l > 0) && (l % np->in_ppip == 0)) {
2214 				if (l > np->in_space) {
2215 					return -1;
2216 				} else if ((l > np->in_ppip) &&
2217 					   np->in_outmsk != 0xffffffff)
2218 					np->in_nip++;
2219 			}
2220 			if (np->in_ppip != 0) {
2221 				port = ntohs(sport);
2222 				port += (l % np->in_ppip);
2223 				port %= np->in_ppip;
2224 				port += np->in_ppip *
2225 					(ntohl(fin->fin_saddr) %
2226 					 np->in_ippip);
2227 				port += MAPBLK_MINPORT;
2228 				port = htons(port);
2229 			}
2230 
2231 		} else if (((np->in_redir & NAT_MAPBLK) == 0) &&
2232 			   (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) {
2233 			/*
2234 			 * Standard port translation.  Select next port.
2235 			 */
2236 			if (np->in_flags & IPN_SEQUENTIAL) {
2237 				port = np->in_pnext;
2238 			} else {
2239 				port = ipf_random() % (ntohs(np->in_pmax) -
2240 						       ntohs(np->in_pmin) + 1);
2241 				port += ntohs(np->in_pmin);
2242 			}
2243 			port = htons(port);
2244 			np->in_pnext++;
2245 
2246 			if (np->in_pnext > ntohs(np->in_pmax)) {
2247 				np->in_pnext = ntohs(np->in_pmin);
2248 				if (np->in_outmsk != 0xffffffff)
2249 					np->in_nip++;
2250 			}
2251 		}
2252 
2253 		if (np->in_flags & IPN_IPRANGE) {
2254 			if (np->in_nip > ntohl(np->in_outmsk))
2255 				np->in_nip = ntohl(np->in_outip);
2256 		} else {
2257 			if ((np->in_outmsk != 0xffffffff) &&
2258 			    ((np->in_nip + 1) & ntohl(np->in_outmsk)) >
2259 			    ntohl(np->in_outip))
2260 				np->in_nip = ntohl(np->in_outip) + 1;
2261 		}
2262 
2263 		if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
2264 			port = sport;
2265 
2266 		/*
2267 		 * Here we do a lookup of the connection as seen from
2268 		 * the outside.  If an IP# pair already exists, try
2269 		 * again.  So if you have A->B becomes C->B, you can
2270 		 * also have D->E become C->E but not D->B causing
2271 		 * another C->B.  Also take protocol and ports into
2272 		 * account when determining whether a pre-existing
2273 		 * NAT setup will cause an external conflict where
2274 		 * this is appropriate.
2275 		 */
2276 		inb.s_addr = htonl(in.s_addr);
2277 		sp = fin->fin_data[0];
2278 		dp = fin->fin_data[1];
2279 		fin->fin_data[0] = fin->fin_data[1];
2280 		fin->fin_data[1] = htons(port);
2281 		natl = nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
2282 				    (u_int)fin->fin_p, fin->fin_dst, inb);
2283 		fin->fin_data[0] = sp;
2284 		fin->fin_data[1] = dp;
2285 
2286 		/*
2287 		 * Has the search wrapped around and come back to the
2288 		 * start ?
2289 		 */
2290 		if ((natl != NULL) &&
2291 		    (np->in_pnext != 0) && (st_port == np->in_pnext) &&
2292 		    (np->in_nip != 0) && (st_ip == np->in_nip))
2293 			return -1;
2294 		l++;
2295 	} while (natl != NULL);
2296 
2297 	if (np->in_space > 0)
2298 		np->in_space--;
2299 
2300 	/* Setup the NAT table */
2301 	nat->nat_inip = fin->fin_src;
2302 	nat->nat_outip.s_addr = htonl(in.s_addr);
2303 	nat->nat_oip = fin->fin_dst;
2304 	if (nat->nat_hm == NULL)
2305 		nat->nat_hm = nat_hostmap(np, fin->fin_src, fin->fin_dst,
2306 					  nat->nat_outip, 0, ifs);
2307 
2308 	if (flags & IPN_TCPUDP) {
2309 		nat->nat_inport = sport;
2310 		nat->nat_outport = port;	/* sport */
2311 		nat->nat_oport = dport;
2312 		((tcphdr_t *)fin->fin_dp)->th_sport = port;
2313 	} else if (flags & IPN_ICMPQUERY) {
2314 		((icmphdr_t *)fin->fin_dp)->icmp_id = port;
2315 		nat->nat_inport = port;
2316 		nat->nat_outport = port;
2317 	}
2318 
2319 	ni->nai_ip.s_addr = in.s_addr;
2320 	ni->nai_port = port;
2321 	ni->nai_nport = dport;
2322 	return 0;
2323 }
2324 
2325 
2326 /* ------------------------------------------------------------------------ */
2327 /* Function:    nat_newrdr                                                  */
2328 /* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
2329 /*                    allow rule to be moved if IPN_ROUNDR is set.          */
2330 /* Parameters:  fin(I) - pointer to packet information                      */
2331 /*              nat(I) - pointer to NAT entry                               */
2332 /*              ni(I)  - pointer to structure with misc. information needed */
2333 /*                       to create new NAT entry.                           */
2334 /*                                                                          */
2335 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
2336 /* to the new IP address for the translation.                               */
2337 /* ------------------------------------------------------------------------ */
2338 static INLINE int nat_newrdr(fin, nat, ni)
2339 fr_info_t *fin;
2340 nat_t *nat;
2341 natinfo_t *ni;
2342 {
2343 	u_short nport, dport, sport;
2344 	struct in_addr in, inb;
2345 	u_short sp, dp;
2346 	hostmap_t *hm;
2347 	u_32_t flags;
2348 	ipnat_t *np;
2349 	nat_t *natl;
2350 	int move;
2351 	ipf_stack_t *ifs = fin->fin_ifs;
2352 
2353 	move = 1;
2354 	hm = NULL;
2355 	in.s_addr = 0;
2356 	np = ni->nai_np;
2357 	flags = ni->nai_flags;
2358 	sport = ni->nai_sport;
2359 	dport = ni->nai_dport;
2360 
2361 	/*
2362 	 * If the matching rule has IPN_STICKY set, then we want to have the
2363 	 * same rule kick in as before.  Why would this happen?  If you have
2364 	 * a collection of rdr rules with "round-robin sticky", the current
2365 	 * packet might match a different one to the previous connection but
2366 	 * we want the same destination to be used.
2367 	 */
2368 	if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) ==
2369 	    (IPN_ROUNDR|IPN_STICKY)) {
2370 		hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst, in,
2371 				 (u_32_t)dport, ifs);
2372 		if (hm != NULL) {
2373 			in.s_addr = ntohl(hm->hm_mapip.s_addr);
2374 			np = hm->hm_ipnat;
2375 			ni->nai_np = np;
2376 			move = 0;
2377 		}
2378 	}
2379 
2380 	/*
2381 	 * Otherwise, it's an inbound packet. Most likely, we don't
2382 	 * want to rewrite source ports and source addresses. Instead,
2383 	 * we want to rewrite to a fixed internal address and fixed
2384 	 * internal port.
2385 	 */
2386 	if (np->in_flags & IPN_SPLIT) {
2387 		in.s_addr = np->in_nip;
2388 
2389 		if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
2390 			hm = nat_hostmap(np, fin->fin_src, fin->fin_dst,
2391 					 in, (u_32_t)dport, ifs);
2392 			if (hm != NULL) {
2393 				in.s_addr = hm->hm_mapip.s_addr;
2394 				move = 0;
2395 			}
2396 		}
2397 
2398 		if (hm == NULL || hm->hm_ref == 1) {
2399 			if (np->in_inip == htonl(in.s_addr)) {
2400 				np->in_nip = ntohl(np->in_inmsk);
2401 				move = 0;
2402 			} else {
2403 				np->in_nip = ntohl(np->in_inip);
2404 			}
2405 		}
2406 
2407 	} else if ((np->in_inip == 0) && (np->in_inmsk == 0xffffffff)) {
2408 		/*
2409 		 * 0/32 - use the interface's IP address.
2410 		 */
2411 		if (fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, &in, NULL,
2412 			   fin->fin_ifs) == -1)
2413 			return -1;
2414 		in.s_addr = ntohl(in.s_addr);
2415 
2416 	} else if ((np->in_inip == 0) && (np->in_inmsk== 0)) {
2417 		/*
2418 		 * 0/0 - use the original destination address/port.
2419 		 */
2420 		in.s_addr = ntohl(fin->fin_daddr);
2421 
2422 	} else if (np->in_redir == NAT_BIMAP &&
2423 		   np->in_inmsk == np->in_outmsk) {
2424 		/*
2425 		 * map the address block in a 1:1 fashion
2426 		 */
2427 		in.s_addr = np->in_inip;
2428 		in.s_addr |= fin->fin_daddr & ~np->in_inmsk;
2429 		in.s_addr = ntohl(in.s_addr);
2430 	} else {
2431 		in.s_addr = ntohl(np->in_inip);
2432 	}
2433 
2434 	if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
2435 		nport = dport;
2436 	else {
2437 		/*
2438 		 * Whilst not optimized for the case where
2439 		 * pmin == pmax, the gain is not significant.
2440 		 */
2441 		if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
2442 		    (np->in_pmin != np->in_pmax)) {
2443 			nport = ntohs(dport) - ntohs(np->in_pmin) +
2444 				ntohs(np->in_pnext);
2445 			nport = htons(nport);
2446 		} else
2447 			nport = np->in_pnext;
2448 	}
2449 
2450 	/*
2451 	 * When the redirect-to address is set to 0.0.0.0, just
2452 	 * assume a blank `forwarding' of the packet.  We don't
2453 	 * setup any translation for this either.
2454 	 */
2455 	if (in.s_addr == 0) {
2456 		if (nport == dport)
2457 			return -1;
2458 		in.s_addr = ntohl(fin->fin_daddr);
2459 	}
2460 
2461 	/*
2462 	 * Check to see if this redirect mapping already exists and if
2463 	 * it does, return "failure" (allowing it to be created will just
2464 	 * cause one or both of these "connections" to stop working.)
2465 	 */
2466 	inb.s_addr = htonl(in.s_addr);
2467 	sp = fin->fin_data[0];
2468 	dp = fin->fin_data[1];
2469 	fin->fin_data[1] = fin->fin_data[0];
2470 	fin->fin_data[0] = ntohs(nport);
2471 	natl = nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
2472 		    (u_int)fin->fin_p, inb, fin->fin_src);
2473 	fin->fin_data[0] = sp;
2474 	fin->fin_data[1] = dp;
2475 	if (natl != NULL)
2476 		return (-1);
2477 
2478 	nat->nat_inip.s_addr = htonl(in.s_addr);
2479 	nat->nat_outip = fin->fin_dst;
2480 	nat->nat_oip = fin->fin_src;
2481 
2482 	ni->nai_ip.s_addr = in.s_addr;
2483 	ni->nai_nport = nport;
2484 	ni->nai_port = sport;
2485 
2486 	if (flags & IPN_TCPUDP) {
2487 		nat->nat_inport = nport;
2488 		nat->nat_outport = dport;
2489 		nat->nat_oport = sport;
2490 		((tcphdr_t *)fin->fin_dp)->th_dport = nport;
2491 	} else if (flags & IPN_ICMPQUERY) {
2492 		((icmphdr_t *)fin->fin_dp)->icmp_id = nport;
2493 		nat->nat_inport = nport;
2494 		nat->nat_outport = nport;
2495 	}
2496 
2497 	return move;
2498 }
2499 
2500 /* ------------------------------------------------------------------------ */
2501 /* Function:    nat_new                                                     */
2502 /* Returns:     nat_t* - NULL == failure to create new NAT structure,       */
2503 /*                       else pointer to new NAT structure                  */
2504 /* Parameters:  fin(I)       - pointer to packet information                */
2505 /*              np(I)        - pointer to NAT rule                          */
2506 /*              natsave(I)   - pointer to where to store NAT struct pointer */
2507 /*              flags(I)     - flags describing the current packet          */
2508 /*              direction(I) - direction of packet (in/out)                 */
2509 /* Write Lock:  ipf_nat                                                     */
2510 /*                                                                          */
2511 /* Attempts to create a new NAT entry.  Does not actually change the packet */
2512 /* in any way.                                                              */
2513 /*                                                                          */
2514 /* This fucntion is in three main parts: (1) deal with creating a new NAT   */
2515 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with     */
2516 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
2517 /* and (3) building that structure and putting it into the NAT table(s).    */
2518 /* ------------------------------------------------------------------------ */
2519 nat_t *nat_new(fin, np, natsave, flags, direction)
2520 fr_info_t *fin;
2521 ipnat_t *np;
2522 nat_t **natsave;
2523 u_int flags;
2524 int direction;
2525 {
2526 	tcphdr_t *tcp = NULL;
2527 	hostmap_t *hm = NULL;
2528 	nat_t *nat, *natl;
2529 	u_int nflags;
2530 	natinfo_t ni;
2531 	int move;
2532 	ipf_stack_t *ifs = fin->fin_ifs;
2533 
2534 	/*
2535 	 * Trigger automatic call to nat_flushtable() if the
2536 	 * table has reached capcity specified by hi watermark.
2537 	 */
2538 	if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_level_hi)
2539 		ifs->ifs_nat_doflush = 1;
2540 
2541 	/*
2542 	 * If automatic flushing did not do its job, and the table
2543 	 * has filled up, don't try to create a new entry.
2544 	 */
2545 	if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) {
2546 		ifs->ifs_nat_stats.ns_memfail++;
2547 		return NULL;
2548 	}
2549 
2550 	move = 1;
2551 	nflags = np->in_flags & flags;
2552 	nflags &= NAT_FROMRULE;
2553 
2554 	ni.nai_np = np;
2555 	ni.nai_nflags = nflags;
2556 	ni.nai_flags = flags;
2557 
2558 	/* Give me a new nat */
2559 	KMALLOC(nat, nat_t *);
2560 	if (nat == NULL) {
2561 		ifs->ifs_nat_stats.ns_memfail++;
2562 		/*
2563 		 * Try to automatically tune the max # of entries in the
2564 		 * table allowed to be less than what will cause kmem_alloc()
2565 		 * to fail and try to eliminate panics due to out of memory
2566 		 * conditions arising.
2567 		 */
2568 		if (ifs->ifs_ipf_nattable_max > ifs->ifs_ipf_nattable_sz) {
2569 			ifs->ifs_ipf_nattable_max = ifs->ifs_nat_stats.ns_inuse - 100;
2570 			printf("ipf_nattable_max reduced to %d\n",
2571 				ifs->ifs_ipf_nattable_max);
2572 		}
2573 		return NULL;
2574 	}
2575 
2576 	if (flags & IPN_TCPUDP) {
2577 		tcp = fin->fin_dp;
2578 		ni.nai_sport = htons(fin->fin_sport);
2579 		ni.nai_dport = htons(fin->fin_dport);
2580 	} else if (flags & IPN_ICMPQUERY) {
2581 		/*
2582 		 * In the ICMP query NAT code, we translate the ICMP id fields
2583 		 * to make them unique. This is indepedent of the ICMP type
2584 		 * (e.g. in the unlikely event that a host sends an echo and
2585 		 * an tstamp request with the same id, both packets will have
2586 		 * their ip address/id field changed in the same way).
2587 		 */
2588 		/* The icmp_id field is used by the sender to identify the
2589 		 * process making the icmp request. (the receiver justs
2590 		 * copies it back in its response). So, it closely matches
2591 		 * the concept of source port. We overlay sport, so we can
2592 		 * maximally reuse the existing code.
2593 		 */
2594 		ni.nai_sport = ((icmphdr_t *)fin->fin_dp)->icmp_id;
2595 		ni.nai_dport = ni.nai_sport;
2596 	}
2597 
2598 	bzero((char *)nat, sizeof(*nat));
2599 	nat->nat_flags = flags;
2600 	nat->nat_redir = np->in_redir;
2601 
2602 	if ((flags & NAT_SLAVE) == 0) {
2603 		MUTEX_ENTER(&ifs->ifs_ipf_nat_new);
2604 	}
2605 
2606 	/*
2607 	 * Search the current table for a match.
2608 	 */
2609 	if (direction == NAT_OUTBOUND) {
2610 		/*
2611 		 * We can now arrange to call this for the same connection
2612 		 * because ipf_nat_new doesn't protect the code path into
2613 		 * this function.
2614 		 */
2615 		natl = nat_outlookup(fin, nflags, (u_int)fin->fin_p,
2616 				     fin->fin_src, fin->fin_dst);
2617 		if (natl != NULL) {
2618 			KFREE(nat);
2619 			nat = natl;
2620 			goto done;
2621 		}
2622 
2623 		move = nat_newmap(fin, nat, &ni);
2624 		if (move == -1)
2625 			goto badnat;
2626 
2627 		np = ni.nai_np;
2628 	} else {
2629 		/*
2630 		 * NAT_INBOUND is used only for redirects rules
2631 		 */
2632 		natl = nat_inlookup(fin, nflags, (u_int)fin->fin_p,
2633 				    fin->fin_src, fin->fin_dst);
2634 		if (natl != NULL) {
2635 			KFREE(nat);
2636 			nat = natl;
2637 			goto done;
2638 		}
2639 
2640 		move = nat_newrdr(fin, nat, &ni);
2641 		if (move == -1)
2642 			goto badnat;
2643 
2644 		np = ni.nai_np;
2645 	}
2646 
2647 	if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
2648 		if (np->in_redir == NAT_REDIRECT) {
2649 			nat_delrdr(np);
2650 			nat_addrdr(np, ifs);
2651 		} else if (np->in_redir == NAT_MAP) {
2652 			nat_delnat(np);
2653 			nat_addnat(np, ifs);
2654 		}
2655 	}
2656 
2657 	if (nat_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) {
2658 		goto badnat;
2659 	}
2660 
2661 	nat_calc_chksum_diffs(nat);
2662 
2663 	if (flags & SI_WILDP)
2664 		ifs->ifs_nat_stats.ns_wilds++;
2665 	fin->fin_flx |= FI_NEWNAT;
2666 	goto done;
2667 badnat:
2668 	ifs->ifs_nat_stats.ns_badnat++;
2669 	if ((hm = nat->nat_hm) != NULL)
2670 		fr_hostmapdel(&hm);
2671 	KFREE(nat);
2672 	nat = NULL;
2673 done:
2674 	if ((flags & NAT_SLAVE) == 0) {
2675 		MUTEX_EXIT(&ifs->ifs_ipf_nat_new);
2676 	}
2677 	return nat;
2678 }
2679 
2680 
2681 /* ------------------------------------------------------------------------ */
2682 /* Function:    nat_finalise                                                */
2683 /* Returns:     int - 0 == sucess, -1 == failure                            */
2684 /* Parameters:  fin(I) - pointer to packet information                      */
2685 /*              nat(I) - pointer to NAT entry                               */
2686 /*              ni(I)  - pointer to structure with misc. information needed */
2687 /*                       to create new NAT entry.                           */
2688 /* Write Lock:  ipf_nat                                                     */
2689 /*                                                                          */
2690 /* This is the tail end of constructing a new NAT entry and is the same     */
2691 /* for both IPv4 and IPv6.                                                  */
2692 /* ------------------------------------------------------------------------ */
2693 /*ARGSUSED*/
2694 static INLINE int nat_finalise(fin, nat, ni, tcp, natsave, direction)
2695 fr_info_t *fin;
2696 nat_t *nat;
2697 natinfo_t *ni;
2698 tcphdr_t *tcp;
2699 nat_t **natsave;
2700 int direction;
2701 {
2702 	frentry_t *fr;
2703 	ipnat_t *np;
2704 	ipf_stack_t *ifs = fin->fin_ifs;
2705 
2706 	np = ni->nai_np;
2707 
2708 	COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0], fin->fin_v);
2709 
2710 #ifdef	IPFILTER_SYNC
2711 	if ((nat->nat_flags & SI_CLONE) == 0)
2712 		nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat);
2713 #endif
2714 
2715 	nat->nat_me = natsave;
2716 	nat->nat_dir = direction;
2717 	nat->nat_ifps[0] = np->in_ifps[0];
2718 	nat->nat_ifps[1] = np->in_ifps[1];
2719 	nat->nat_ptr = np;
2720 	nat->nat_p = fin->fin_p;
2721 	nat->nat_v = fin->fin_v;
2722 	nat->nat_mssclamp = np->in_mssclamp;
2723 	fr = fin->fin_fr;
2724 	nat->nat_fr = fr;
2725 
2726 	if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0))
2727 		if (appr_new(fin, nat) == -1)
2728 			return -1;
2729 
2730 	if (nat_insert(nat, fin->fin_rev, ifs) == 0) {
2731 		if (ifs->ifs_nat_logging)
2732 			nat_log(nat, (u_int)np->in_redir, ifs);
2733 		np->in_use++;
2734 		if (fr != NULL) {
2735 			MUTEX_ENTER(&fr->fr_lock);
2736 			fr->fr_ref++;
2737 			MUTEX_EXIT(&fr->fr_lock);
2738 		}
2739 		return 0;
2740 	}
2741 
2742 	/*
2743 	 * nat_insert failed, so cleanup time...
2744 	 */
2745 	return -1;
2746 }
2747 
2748 
2749 /* ------------------------------------------------------------------------ */
2750 /* Function:   nat_insert                                                   */
2751 /* Returns:    int - 0 == sucess, -1 == failure                             */
2752 /* Parameters: nat(I) - pointer to NAT structure                            */
2753 /*             rev(I) - flag indicating forward/reverse direction of packet */
2754 /* Write Lock: ipf_nat                                                      */
2755 /*                                                                          */
2756 /* Insert a NAT entry into the hash tables for searching and add it to the  */
2757 /* list of active NAT entries.  Adjust global counters when complete.       */
2758 /* ------------------------------------------------------------------------ */
2759 int	nat_insert(nat, rev, ifs)
2760 nat_t	*nat;
2761 int	rev;
2762 ipf_stack_t *ifs;
2763 {
2764 	u_int hv1, hv2;
2765 	nat_t **natp;
2766 
2767 	/*
2768 	 * Try and return an error as early as possible, so calculate the hash
2769 	 * entry numbers first and then proceed.
2770 	 */
2771 	if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
2772 		hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport,
2773 				  0xffffffff);
2774 		hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport,
2775 				  ifs->ifs_ipf_nattable_sz);
2776 		hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport,
2777 				  0xffffffff);
2778 		hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport,
2779 				  ifs->ifs_ipf_nattable_sz);
2780 	} else {
2781 		hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff);
2782 		hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1,
2783 				  ifs->ifs_ipf_nattable_sz);
2784 		hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff);
2785 		hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2,
2786 				  ifs->ifs_ipf_nattable_sz);
2787 	}
2788 
2789 	if (ifs->ifs_nat_stats.ns_bucketlen[0][hv1] >= ifs->ifs_fr_nat_maxbucket ||
2790 	    ifs->ifs_nat_stats.ns_bucketlen[1][hv2] >= ifs->ifs_fr_nat_maxbucket) {
2791 		return -1;
2792 	}
2793 
2794 	nat->nat_hv[0] = hv1;
2795 	nat->nat_hv[1] = hv2;
2796 
2797 	MUTEX_INIT(&nat->nat_lock, "nat entry lock");
2798 
2799 	nat->nat_rev = rev;
2800 	nat->nat_ref = 1;
2801 	nat->nat_bytes[0] = 0;
2802 	nat->nat_pkts[0] = 0;
2803 	nat->nat_bytes[1] = 0;
2804 	nat->nat_pkts[1] = 0;
2805 
2806 	nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
2807 	nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 4, ifs);
2808 
2809 	if (nat->nat_ifnames[1][0] !='\0') {
2810 		nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
2811 		nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 4, ifs);
2812 	} else {
2813 		(void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0],
2814 			       LIFNAMSIZ);
2815 		nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
2816 		nat->nat_ifps[1] = nat->nat_ifps[0];
2817 	}
2818 
2819 	nat->nat_next = ifs->ifs_nat_instances;
2820 	nat->nat_pnext = &ifs->ifs_nat_instances;
2821 	if (ifs->ifs_nat_instances)
2822 		ifs->ifs_nat_instances->nat_pnext = &nat->nat_next;
2823 	ifs->ifs_nat_instances = nat;
2824 
2825 	natp = &ifs->ifs_nat_table[0][hv1];
2826 	if (*natp)
2827 		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
2828 	nat->nat_phnext[0] = natp;
2829 	nat->nat_hnext[0] = *natp;
2830 	*natp = nat;
2831 	ifs->ifs_nat_stats.ns_bucketlen[0][hv1]++;
2832 
2833 	natp = &ifs->ifs_nat_table[1][hv2];
2834 	if (*natp)
2835 		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
2836 	nat->nat_phnext[1] = natp;
2837 	nat->nat_hnext[1] = *natp;
2838 	*natp = nat;
2839 	ifs->ifs_nat_stats.ns_bucketlen[1][hv2]++;
2840 
2841 	fr_setnatqueue(nat, rev, ifs);
2842 
2843 	ifs->ifs_nat_stats.ns_added++;
2844 	ifs->ifs_nat_stats.ns_inuse++;
2845 	return 0;
2846 }
2847 
2848 
2849 /* ------------------------------------------------------------------------ */
2850 /* Function:    nat_icmperrorlookup                                         */
2851 /* Returns:     nat_t* - point to matching NAT structure                    */
2852 /* Parameters:  fin(I) - pointer to packet information                      */
2853 /*              dir(I) - direction of packet (in/out)                       */
2854 /*                                                                          */
2855 /* Check if the ICMP error message is related to an existing TCP, UDP or    */
2856 /* ICMP query nat entry.  It is assumed that the packet is already of the   */
2857 /* the required length.                                                     */
2858 /* ------------------------------------------------------------------------ */
2859 nat_t *nat_icmperrorlookup(fin, dir)
2860 fr_info_t *fin;
2861 int dir;
2862 {
2863 	int flags = 0, minlen;
2864 	icmphdr_t *orgicmp;
2865 	tcphdr_t *tcp = NULL;
2866 	u_short data[2];
2867 	nat_t *nat;
2868 	ip_t *oip;
2869 	u_int p;
2870 
2871 	/*
2872 	 * Does it at least have the return (basic) IP header ?
2873 	 * Only a basic IP header (no options) should be with an ICMP error
2874 	 * header.  Also, if it's not an error type, then return.
2875 	 */
2876 	if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR))
2877 		return NULL;
2878 
2879 	/*
2880 	 * Check packet size
2881 	 */
2882 	oip = (ip_t *)((char *)fin->fin_dp + 8);
2883 	minlen = IP_HL(oip) << 2;
2884 	if ((minlen < sizeof(ip_t)) ||
2885 	    (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen))
2886 		return NULL;
2887 	/*
2888 	 * Is the buffer big enough for all of it ?  It's the size of the IP
2889 	 * header claimed in the encapsulated part which is of concern.  It
2890 	 * may be too big to be in this buffer but not so big that it's
2891 	 * outside the ICMP packet, leading to TCP deref's causing problems.
2892 	 * This is possible because we don't know how big oip_hl is when we
2893 	 * do the pullup early in fr_check() and thus can't gaurantee it is
2894 	 * all here now.
2895 	 */
2896 #ifdef  _KERNEL
2897 	{
2898 	mb_t *m;
2899 
2900 	m = fin->fin_m;
2901 # if defined(MENTAT)
2902 	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr)
2903 		return NULL;
2904 # else
2905 	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
2906 	    (char *)fin->fin_ip + M_LEN(m))
2907 		return NULL;
2908 # endif
2909 	}
2910 #endif
2911 
2912 	if (fin->fin_daddr != oip->ip_src.s_addr)
2913 		return NULL;
2914 
2915 	p = oip->ip_p;
2916 	if (p == IPPROTO_TCP)
2917 		flags = IPN_TCP;
2918 	else if (p == IPPROTO_UDP)
2919 		flags = IPN_UDP;
2920 	else if (p == IPPROTO_ICMP) {
2921 		orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2));
2922 
2923 		/* see if this is related to an ICMP query */
2924 		if (nat_icmpquerytype4(orgicmp->icmp_type)) {
2925 			data[0] = fin->fin_data[0];
2926 			data[1] = fin->fin_data[1];
2927 			fin->fin_data[0] = 0;
2928 			fin->fin_data[1] = orgicmp->icmp_id;
2929 
2930 			flags = IPN_ICMPERR|IPN_ICMPQUERY;
2931 			/*
2932 			 * NOTE : dir refers to the direction of the original
2933 			 *        ip packet. By definition the icmp error
2934 			 *        message flows in the opposite direction.
2935 			 */
2936 			if (dir == NAT_INBOUND)
2937 				nat = nat_inlookup(fin, flags, p, oip->ip_dst,
2938 						   oip->ip_src);
2939 			else
2940 				nat = nat_outlookup(fin, flags, p, oip->ip_dst,
2941 						    oip->ip_src);
2942 			fin->fin_data[0] = data[0];
2943 			fin->fin_data[1] = data[1];
2944 			return nat;
2945 		}
2946 	}
2947 
2948 	if (flags & IPN_TCPUDP) {
2949 		minlen += 8;		/* + 64bits of data to get ports */
2950 		if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)
2951 			return NULL;
2952 
2953 		data[0] = fin->fin_data[0];
2954 		data[1] = fin->fin_data[1];
2955 		tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2));
2956 		fin->fin_data[0] = ntohs(tcp->th_dport);
2957 		fin->fin_data[1] = ntohs(tcp->th_sport);
2958 
2959 		if (dir == NAT_INBOUND) {
2960 			nat = nat_inlookup(fin, flags, p, oip->ip_dst,
2961 					   oip->ip_src);
2962 		} else {
2963 			nat = nat_outlookup(fin, flags, p, oip->ip_dst,
2964 					    oip->ip_src);
2965 		}
2966 		fin->fin_data[0] = data[0];
2967 		fin->fin_data[1] = data[1];
2968 		return nat;
2969 	}
2970 	if (dir == NAT_INBOUND)
2971 		return nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
2972 	else
2973 		return nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
2974 }
2975 
2976 
2977 /* ------------------------------------------------------------------------ */
2978 /* Function:    nat_icmperror                                               */
2979 /* Returns:     nat_t* - point to matching NAT structure                    */
2980 /* Parameters:  fin(I)    - pointer to packet information                   */
2981 /*              nflags(I) - NAT flags for this packet                       */
2982 /*              dir(I)    - direction of packet (in/out)                    */
2983 /*                                                                          */
2984 /* Fix up an ICMP packet which is an error message for an existing NAT      */
2985 /* session.  This will correct both packet header data and checksums.       */
2986 /*                                                                          */
2987 /* This should *ONLY* be used for incoming ICMP error packets to make sure  */
2988 /* a NAT'd ICMP packet gets correctly recognised.                           */
2989 /* ------------------------------------------------------------------------ */
2990 nat_t *nat_icmperror(fin, nflags, dir)
2991 fr_info_t *fin;
2992 u_int *nflags;
2993 int dir;
2994 {
2995 	u_32_t sum1, sum2, sumd, psum1, psum2, psumd, sumd2;
2996 	struct in_addr in;
2997 	icmphdr_t *icmp, *orgicmp;
2998 	int dlen;
2999 	udphdr_t *udp;
3000 	tcphdr_t *tcp;
3001 	nat_t *nat;
3002 	ip_t *oip;
3003 	if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY)))
3004 		return NULL;
3005 
3006 	/*
3007 	 * nat_icmperrorlookup() looks up nat entry associated with the
3008 	 * offending IP packet and returns pointer to the entry, or NULL
3009 	 * if packet wasn't natted or for `defective' packets.
3010 	 */
3011 
3012 	if ((fin->fin_v != 4) || !(nat = nat_icmperrorlookup(fin, dir)))
3013 		return NULL;
3014 
3015 	sumd2 = 0;
3016 	*nflags = IPN_ICMPERR;
3017 	icmp = fin->fin_dp;
3018 	oip = (ip_t *)&icmp->icmp_ip;
3019 	udp = (udphdr_t *)((((char *)oip) + (IP_HL(oip) << 2)));
3020 	tcp = (tcphdr_t *)udp;
3021 	dlen = fin->fin_plen - ((char *)udp - (char *)fin->fin_ip);
3022 
3023 	/*
3024 	 * Need to adjust ICMP header to include the real IP#'s and
3025 	 * port #'s.  There are three steps required.
3026 	 *
3027 	 * Step 1
3028 	 * Fix the IP addresses in the offending IP packet and update
3029 	 * ip header checksum to compensate for the change.
3030 	 *
3031 	 * No update needed here for icmp_cksum because the ICMP checksum
3032 	 * is calculated over the complete ICMP packet, which includes the
3033 	 * changed oip IP addresses and oip->ip_sum.  These two changes
3034 	 * cancel each other out (if the delta for the IP address is x,
3035 	 * then the delta for ip_sum is minus x).
3036 	 */
3037 
3038 	if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) {
3039 		sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr));
3040 		in = nat->nat_inip;
3041 		oip->ip_src = in;
3042 	} else {
3043 		sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr));
3044 		in = nat->nat_outip;
3045 		oip->ip_dst = in;
3046 	}
3047 
3048 	sum2 = LONG_SUM(ntohl(in.s_addr));
3049 	CALC_SUMD(sum1, sum2, sumd);
3050 	fix_datacksum(&oip->ip_sum, sumd);
3051 
3052 	/*
3053 	 * Step 2
3054 	 * Perform other adjustments based on protocol of offending packet.
3055 	 */
3056 
3057 	switch (oip->ip_p) {
3058 		case IPPROTO_TCP :
3059 		case IPPROTO_UDP :
3060 
3061 			/*
3062 			* For offending TCP/UDP IP packets, translate the ports
3063 			* based on the NAT specification.
3064 			*
3065 			* Advance notice : Now it becomes complicated :-)
3066 			*
3067 			* Since the port and IP addresse fields are both part
3068 			* of the TCP/UDP checksum of the offending IP packet,
3069 			* we need to adjust that checksum as well.
3070 			*
3071 			* To further complicate things, the TCP/UDP checksum
3072 			* may not be present.  We must check to see if the
3073 			* length of the data portion is big enough to hold
3074 			* the checksum.  In the UDP case, a test to determine
3075 			* if the checksum is even set is also required.
3076 			*
3077 			* Any changes to an IP address, port or checksum within
3078 			* the ICMP packet requires a change to icmp_cksum.
3079 			*
3080 			* Be extremely careful here ... The change is dependent
3081 			* upon whether or not the TCP/UPD checksum is present.
3082 			*
3083 			* If TCP/UPD checksum is present, the icmp_cksum must
3084 			* compensate for checksum modification resulting from
3085 			* IP address change only.  Port change and resulting
3086 			* data checksum adjustments cancel each other out.
3087 			*
3088 			* If TCP/UDP checksum is not present, icmp_cksum must
3089 			* compensate for port change only.  The IP address
3090 			* change does not modify anything else in this case.
3091 			*/
3092 
3093 			psum1 = 0;
3094 			psum2 = 0;
3095 			psumd = 0;
3096 
3097 			if ((tcp->th_dport == nat->nat_oport) &&
3098 			    (tcp->th_sport != nat->nat_inport)) {
3099 
3100 				/*
3101 				 * Translate the source port.
3102 				 */
3103 
3104 				psum1 = ntohs(tcp->th_sport);
3105 				psum2 = ntohs(nat->nat_inport);
3106 				tcp->th_sport = nat->nat_inport;
3107 
3108 			} else if ((tcp->th_sport == nat->nat_oport) &&
3109 				    (tcp->th_dport != nat->nat_outport)) {
3110 
3111 				/*
3112 				 * Translate the destination port.
3113 				 */
3114 
3115 				psum1 = ntohs(tcp->th_dport);
3116 				psum2 = ntohs(nat->nat_outport);
3117 				tcp->th_dport = nat->nat_outport;
3118 			}
3119 
3120 			if ((oip->ip_p == IPPROTO_TCP) && (dlen >= 18)) {
3121 
3122 				/*
3123 				 * TCP checksum present.
3124 				 *
3125 				 * Adjust data checksum and icmp checksum to
3126 				 * compensate for any IP address change.
3127 				 */
3128 
3129 				sum1 = ntohs(tcp->th_sum);
3130 				fix_datacksum(&tcp->th_sum, sumd);
3131 				sum2 = ntohs(tcp->th_sum);
3132 				sumd2 = sumd << 1;
3133 				CALC_SUMD(sum1, sum2, sumd);
3134 				sumd2 += sumd;
3135 
3136 				/*
3137 				 * Also make data checksum adjustment to
3138 				 * compensate for any port change.
3139 				 */
3140 
3141 				if (psum1 != psum2) {
3142 					CALC_SUMD(psum1, psum2, psumd);
3143 					fix_datacksum(&tcp->th_sum, psumd);
3144 				}
3145 
3146 			} else if ((oip->ip_p == IPPROTO_UDP) &&
3147 				   (dlen >= 8) && (udp->uh_sum != 0)) {
3148 
3149 				/*
3150 				 * The UDP checksum is present and set.
3151 				 *
3152 				 * Adjust data checksum and icmp checksum to
3153 				 * compensate for any IP address change.
3154 				 */
3155 
3156 				sum1 = ntohs(udp->uh_sum);
3157 				fix_datacksum(&udp->uh_sum, sumd);
3158 				sum2 = ntohs(udp->uh_sum);
3159 				sumd2 = sumd << 1;
3160 				CALC_SUMD(sum1, sum2, sumd);
3161 				sumd2 += sumd;
3162 
3163 				/*
3164 				 * Also make data checksum adjustment to
3165 				 * compensate for any port change.
3166 				 */
3167 
3168 				if (psum1 != psum2) {
3169 					CALC_SUMD(psum1, psum2, psumd);
3170 					fix_datacksum(&udp->uh_sum, psumd);
3171 				}
3172 
3173 			} else {
3174 
3175 				/*
3176 				 * Data checksum was not present.
3177 				 *
3178 				 * Compensate for any port change.
3179 				 */
3180 
3181 				CALC_SUMD(psum2, psum1, psumd);
3182 				sumd2 += psumd;
3183 			}
3184 			break;
3185 
3186 		case IPPROTO_ICMP :
3187 
3188 			orgicmp = (icmphdr_t *)udp;
3189 
3190 			if ((nat->nat_dir == NAT_OUTBOUND) &&
3191 			    (orgicmp->icmp_id != nat->nat_inport) &&
3192 			    (dlen >= 8)) {
3193 
3194 				/*
3195 				 * Fix ICMP checksum (of the offening ICMP
3196 				 * query packet) to compensate the change
3197 				 * in the ICMP id of the offending ICMP
3198 				 * packet.
3199 				 *
3200 				 * Since you modify orgicmp->icmp_id with
3201 				 * a delta (say x) and you compensate that
3202 				 * in origicmp->icmp_cksum with a delta
3203 				 * minus x, you don't have to adjust the
3204 				 * overall icmp->icmp_cksum
3205 				 */
3206 
3207 				sum1 = ntohs(orgicmp->icmp_id);
3208 				sum2 = ntohs(nat->nat_inport);
3209 				CALC_SUMD(sum1, sum2, sumd);
3210 				orgicmp->icmp_id = nat->nat_inport;
3211 				fix_datacksum(&orgicmp->icmp_cksum, sumd);
3212 
3213 			} /* nat_dir can't be NAT_INBOUND for icmp queries */
3214 
3215 			break;
3216 
3217 		default :
3218 
3219 			break;
3220 
3221 	} /* switch (oip->ip_p) */
3222 
3223 	/*
3224 	 * Step 3
3225 	 * Make the adjustments to icmp checksum.
3226 	 */
3227 
3228 	if (sumd2 != 0) {
3229 		sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
3230 		sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
3231 		fix_incksum(&icmp->icmp_cksum, sumd2);
3232 	}
3233 	return nat;
3234 }
3235 
3236 
3237 /*
3238  * NB: these lookups don't lock access to the list, it assumed that it has
3239  * already been done!
3240  */
3241 
3242 /* ------------------------------------------------------------------------ */
3243 /* Function:    nat_inlookup                                                */
3244 /* Returns:     nat_t* - NULL == no match,                                  */
3245 /*                       else pointer to matching NAT entry                 */
3246 /* Parameters:  fin(I)    - pointer to packet information                   */
3247 /*              flags(I)  - NAT flags for this packet                       */
3248 /*              p(I)      - protocol for this packet                        */
3249 /*              src(I)    - source IP address                               */
3250 /*              mapdst(I) - destination IP address                          */
3251 /*                                                                          */
3252 /* Lookup a nat entry based on the mapped destination ip address/port and   */
3253 /* real source address/port.  We use this lookup when receiving a packet,   */
3254 /* we're looking for a table entry, based on the destination address.       */
3255 /*                                                                          */
3256 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
3257 /*                                                                          */
3258 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN      */
3259 /*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
3260 /*                                                                          */
3261 /* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
3262 /*            the packet is of said protocol                                */
3263 /* ------------------------------------------------------------------------ */
3264 nat_t *nat_inlookup(fin, flags, p, src, mapdst)
3265 fr_info_t *fin;
3266 u_int flags, p;
3267 struct in_addr src , mapdst;
3268 {
3269 	u_short sport, dport;
3270 	ipnat_t *ipn;
3271 	u_int sflags;
3272 	nat_t *nat;
3273 	int nflags;
3274 	u_32_t dst;
3275 	void *ifp;
3276 	u_int hv;
3277 	ipf_stack_t *ifs = fin->fin_ifs;
3278 
3279 	if (fin != NULL)
3280 		ifp = fin->fin_ifp;
3281 	else
3282 		ifp = NULL;
3283 	sport = 0;
3284 	dport = 0;
3285 	dst = mapdst.s_addr;
3286 	sflags = flags & NAT_TCPUDPICMP;
3287 
3288 	switch (p)
3289 	{
3290 	case IPPROTO_TCP :
3291 	case IPPROTO_UDP :
3292 		sport = htons(fin->fin_data[0]);
3293 		dport = htons(fin->fin_data[1]);
3294 		break;
3295 	case IPPROTO_ICMP :
3296 		if (flags & IPN_ICMPERR)
3297 			sport = fin->fin_data[1];
3298 		else
3299 			dport = fin->fin_data[1];
3300 		break;
3301 	default :
3302 		break;
3303 	}
3304 
3305 
3306 	if ((flags & SI_WILDP) != 0)
3307 		goto find_in_wild_ports;
3308 
3309 	hv = NAT_HASH_FN(dst, dport, 0xffffffff);
3310 	hv = NAT_HASH_FN(src.s_addr, hv + sport, ifs->ifs_ipf_nattable_sz);
3311 	nat = ifs->ifs_nat_table[1][hv];
3312 	for (; nat; nat = nat->nat_hnext[1]) {
3313 		if (nat->nat_v != 4)
3314 			continue;
3315 
3316 		if (nat->nat_ifps[0] != NULL) {
3317 			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
3318 				continue;
3319 		} else if (ifp != NULL)
3320 			nat->nat_ifps[0] = ifp;
3321 
3322 		nflags = nat->nat_flags;
3323 
3324 		if (nat->nat_oip.s_addr == src.s_addr &&
3325 		    nat->nat_outip.s_addr == dst &&
3326 		    (((p == 0) &&
3327 		      (sflags == (nat->nat_flags & IPN_TCPUDPICMP)))
3328 		     || (p == nat->nat_p))) {
3329 			switch (p)
3330 			{
3331 #if 0
3332 			case IPPROTO_GRE :
3333 				if (nat->nat_call[1] != fin->fin_data[0])
3334 					continue;
3335 				break;
3336 #endif
3337 			case IPPROTO_ICMP :
3338 				if ((flags & IPN_ICMPERR) != 0) {
3339 					if (nat->nat_outport != sport)
3340 						continue;
3341 				} else {
3342 					if (nat->nat_outport != dport)
3343 						continue;
3344 				}
3345 				break;
3346 			case IPPROTO_TCP :
3347 			case IPPROTO_UDP :
3348 				if (nat->nat_oport != sport)
3349 					continue;
3350 				if (nat->nat_outport != dport)
3351 					continue;
3352 				break;
3353 			default :
3354 				break;
3355 			}
3356 
3357 			ipn = nat->nat_ptr;
3358 			if ((ipn != NULL) && (nat->nat_aps != NULL))
3359 				if (appr_match(fin, nat) != 0)
3360 					continue;
3361 			return nat;
3362 		}
3363 	}
3364 
3365 	/*
3366 	 * So if we didn't find it but there are wildcard members in the hash
3367 	 * table, go back and look for them.  We do this search and update here
3368 	 * because it is modifying the NAT table and we want to do this only
3369 	 * for the first packet that matches.  The exception, of course, is
3370 	 * for "dummy" (FI_IGNORE) lookups.
3371 	 */
3372 find_in_wild_ports:
3373 	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH))
3374 		return NULL;
3375 	if (ifs->ifs_nat_stats.ns_wilds == 0)
3376 		return NULL;
3377 
3378 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
3379 
3380 	hv = NAT_HASH_FN(dst, 0, 0xffffffff);
3381 	hv = NAT_HASH_FN(src.s_addr, hv, ifs->ifs_ipf_nattable_sz);
3382 
3383 	WRITE_ENTER(&ifs->ifs_ipf_nat);
3384 
3385 	nat = ifs->ifs_nat_table[1][hv];
3386 	for (; nat; nat = nat->nat_hnext[1]) {
3387 		if (nat->nat_v != 4)
3388 			continue;
3389 
3390 		if (nat->nat_ifps[0] != NULL) {
3391 			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
3392 				continue;
3393 		} else if (ifp != NULL)
3394 			nat->nat_ifps[0] = ifp;
3395 
3396 		if (nat->nat_p != fin->fin_p)
3397 			continue;
3398 		if (nat->nat_oip.s_addr != src.s_addr ||
3399 		    nat->nat_outip.s_addr != dst)
3400 			continue;
3401 
3402 		nflags = nat->nat_flags;
3403 		if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
3404 			continue;
3405 
3406 		if (nat_wildok(nat, (int)sport, (int)dport, nflags,
3407 			       NAT_INBOUND) == 1) {
3408 			if ((fin->fin_flx & FI_IGNORE) != 0)
3409 				break;
3410 			if ((nflags & SI_CLONE) != 0) {
3411 				nat = fr_natclone(fin, nat);
3412 				if (nat == NULL)
3413 					break;
3414 			} else {
3415 				MUTEX_ENTER(&ifs->ifs_ipf_nat_new);
3416 				ifs->ifs_nat_stats.ns_wilds--;
3417 				MUTEX_EXIT(&ifs->ifs_ipf_nat_new);
3418 			}
3419 			nat->nat_oport = sport;
3420 			nat->nat_outport = dport;
3421 			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
3422 			nat_tabmove(nat, ifs);
3423 			break;
3424 		}
3425 	}
3426 
3427 	MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
3428 
3429 	return nat;
3430 }
3431 
3432 
3433 /* ------------------------------------------------------------------------ */
3434 /* Function:    nat_tabmove                                                 */
3435 /* Returns:     Nil                                                         */
3436 /* Parameters:  nat(I) - pointer to NAT structure                           */
3437 /* Write Lock:  ipf_nat                                                     */
3438 /*                                                                          */
3439 /* This function is only called for TCP/UDP NAT table entries where the     */
3440 /* original was placed in the table without hashing on the ports and we now */
3441 /* want to include hashing on port numbers.                                 */
3442 /* ------------------------------------------------------------------------ */
3443 static void nat_tabmove(nat, ifs)
3444 nat_t *nat;
3445 ipf_stack_t *ifs;
3446 {
3447 	nat_t **natp;
3448 	u_int hv;
3449 
3450 	if (nat->nat_flags & SI_CLONE)
3451 		return;
3452 
3453 	/*
3454 	 * Remove the NAT entry from the old location
3455 	 */
3456 	if (nat->nat_hnext[0])
3457 		nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
3458 	*nat->nat_phnext[0] = nat->nat_hnext[0];
3459 	ifs->ifs_nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--;
3460 
3461 	if (nat->nat_hnext[1])
3462 		nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
3463 	*nat->nat_phnext[1] = nat->nat_hnext[1];
3464 	ifs->ifs_nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--;
3465 
3466 	/*
3467 	 * Add into the NAT table in the new position
3468 	 */
3469 	hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 0xffffffff);
3470 	hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport,
3471 			 ifs->ifs_ipf_nattable_sz);
3472 	nat->nat_hv[0] = hv;
3473 	natp = &ifs->ifs_nat_table[0][hv];
3474 	if (*natp)
3475 		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
3476 	nat->nat_phnext[0] = natp;
3477 	nat->nat_hnext[0] = *natp;
3478 	*natp = nat;
3479 	ifs->ifs_nat_stats.ns_bucketlen[0][hv]++;
3480 
3481 	hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 0xffffffff);
3482 	hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport,
3483 			 ifs->ifs_ipf_nattable_sz);
3484 	nat->nat_hv[1] = hv;
3485 	natp = &ifs->ifs_nat_table[1][hv];
3486 	if (*natp)
3487 		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
3488 	nat->nat_phnext[1] = natp;
3489 	nat->nat_hnext[1] = *natp;
3490 	*natp = nat;
3491 	ifs->ifs_nat_stats.ns_bucketlen[1][hv]++;
3492 }
3493 
3494 
3495 /* ------------------------------------------------------------------------ */
3496 /* Function:    nat_outlookup                                               */
3497 /* Returns:     nat_t* - NULL == no match,                                  */
3498 /*                       else pointer to matching NAT entry                 */
3499 /* Parameters:  fin(I)   - pointer to packet information                    */
3500 /*              flags(I) - NAT flags for this packet                        */
3501 /*              p(I)     - protocol for this packet                         */
3502 /*              src(I)   - source IP address                                */
3503 /*              dst(I)   - destination IP address                           */
3504 /*              rw(I)    - 1 == write lock on ipf_nat held, 0 == read lock. */
3505 /*                                                                          */
3506 /* Lookup a nat entry based on the source 'real' ip address/port and        */
3507 /* destination address/port.  We use this lookup when sending a packet out, */
3508 /* we're looking for a table entry, based on the source address.            */
3509 /*                                                                          */
3510 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
3511 /*                                                                          */
3512 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN      */
3513 /*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
3514 /*                                                                          */
3515 /* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
3516 /*            the packet is of said protocol                                */
3517 /* ------------------------------------------------------------------------ */
3518 nat_t *nat_outlookup(fin, flags, p, src, dst)
3519 fr_info_t *fin;
3520 u_int flags, p;
3521 struct in_addr src , dst;
3522 {
3523 	u_short sport, dport;
3524 	u_int sflags;
3525 	ipnat_t *ipn;
3526 	u_32_t srcip;
3527 	nat_t *nat;
3528 	int nflags;
3529 	void *ifp;
3530 	u_int hv;
3531 	ipf_stack_t *ifs = fin->fin_ifs;
3532 
3533 	ifp = fin->fin_ifp;
3534 
3535 	srcip = src.s_addr;
3536 	sflags = flags & IPN_TCPUDPICMP;
3537 	sport = 0;
3538 	dport = 0;
3539 
3540 	switch (p)
3541 	{
3542 	case IPPROTO_TCP :
3543 	case IPPROTO_UDP :
3544 		sport = htons(fin->fin_data[0]);
3545 		dport = htons(fin->fin_data[1]);
3546 		break;
3547 	case IPPROTO_ICMP :
3548 		if (flags & IPN_ICMPERR)
3549 			sport = fin->fin_data[1];
3550 		else
3551 			dport = fin->fin_data[1];
3552 		break;
3553 	default :
3554 		break;
3555 	}
3556 
3557 	if ((flags & SI_WILDP) != 0)
3558 		goto find_out_wild_ports;
3559 
3560 	hv = NAT_HASH_FN(srcip, sport, 0xffffffff);
3561 	hv = NAT_HASH_FN(dst.s_addr, hv + dport, ifs->ifs_ipf_nattable_sz);
3562 	nat = ifs->ifs_nat_table[0][hv];
3563 	for (; nat; nat = nat->nat_hnext[0]) {
3564 		if (nat->nat_v != 4)
3565 			continue;
3566 
3567 		if (nat->nat_ifps[1] != NULL) {
3568 			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
3569 				continue;
3570 		} else if (ifp != NULL)
3571 			nat->nat_ifps[1] = ifp;
3572 
3573 		nflags = nat->nat_flags;
3574 
3575 		if (nat->nat_inip.s_addr == srcip &&
3576 		    nat->nat_oip.s_addr == dst.s_addr &&
3577 		    (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP)))
3578 		     || (p == nat->nat_p))) {
3579 			switch (p)
3580 			{
3581 #if 0
3582 			case IPPROTO_GRE :
3583 				if (nat->nat_call[1] != fin->fin_data[0])
3584 					continue;
3585 				break;
3586 #endif
3587 			case IPPROTO_TCP :
3588 			case IPPROTO_UDP :
3589 				if (nat->nat_oport != dport)
3590 					continue;
3591 				if (nat->nat_inport != sport)
3592 					continue;
3593 				break;
3594 			default :
3595 				break;
3596 			}
3597 
3598 			ipn = nat->nat_ptr;
3599 			if ((ipn != NULL) && (nat->nat_aps != NULL))
3600 				if (appr_match(fin, nat) != 0)
3601 					continue;
3602 			return nat;
3603 		}
3604 	}
3605 
3606 	/*
3607 	 * So if we didn't find it but there are wildcard members in the hash
3608 	 * table, go back and look for them.  We do this search and update here
3609 	 * because it is modifying the NAT table and we want to do this only
3610 	 * for the first packet that matches.  The exception, of course, is
3611 	 * for "dummy" (FI_IGNORE) lookups.
3612 	 */
3613 find_out_wild_ports:
3614 	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH))
3615 		return NULL;
3616 	if (ifs->ifs_nat_stats.ns_wilds == 0)
3617 		return NULL;
3618 
3619 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
3620 
3621 	hv = NAT_HASH_FN(srcip, 0, 0xffffffff);
3622 	hv = NAT_HASH_FN(dst.s_addr, hv, ifs->ifs_ipf_nattable_sz);
3623 
3624 	WRITE_ENTER(&ifs->ifs_ipf_nat);
3625 
3626 	nat = ifs->ifs_nat_table[0][hv];
3627 	for (; nat; nat = nat->nat_hnext[0]) {
3628 		if (nat->nat_v != 4)
3629 			continue;
3630 
3631 		if (nat->nat_ifps[1] != NULL) {
3632 			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
3633 				continue;
3634 		} else if (ifp != NULL)
3635 			nat->nat_ifps[1] = ifp;
3636 
3637 		if (nat->nat_p != fin->fin_p)
3638 			continue;
3639 		if ((nat->nat_inip.s_addr != srcip) ||
3640 		    (nat->nat_oip.s_addr != dst.s_addr))
3641 			continue;
3642 
3643 		nflags = nat->nat_flags;
3644 		if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
3645 			continue;
3646 
3647 		if (nat_wildok(nat, (int)sport, (int)dport, nflags,
3648 			       NAT_OUTBOUND) == 1) {
3649 			if ((fin->fin_flx & FI_IGNORE) != 0)
3650 				break;
3651 			if ((nflags & SI_CLONE) != 0) {
3652 				nat = fr_natclone(fin, nat);
3653 				if (nat == NULL)
3654 					break;
3655 			} else {
3656 				MUTEX_ENTER(&ifs->ifs_ipf_nat_new);
3657 				ifs->ifs_nat_stats.ns_wilds--;
3658 				MUTEX_EXIT(&ifs->ifs_ipf_nat_new);
3659 			}
3660 			nat->nat_inport = sport;
3661 			nat->nat_oport = dport;
3662 			if (nat->nat_outport == 0)
3663 				nat->nat_outport = sport;
3664 			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
3665 			nat_tabmove(nat, ifs);
3666 			break;
3667 		}
3668 	}
3669 
3670 	MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
3671 
3672 	return nat;
3673 }
3674 
3675 
3676 /* ------------------------------------------------------------------------ */
3677 /* Function:    nat_lookupredir                                             */
3678 /* Returns:     nat_t* - NULL == no match,                                  */
3679 /*                       else pointer to matching NAT entry                 */
3680 /* Parameters:  np(I) - pointer to description of packet to find NAT table  */
3681 /*                      entry for.                                          */
3682 /*                                                                          */
3683 /* Lookup the NAT tables to search for a matching redirect                  */
3684 /* ------------------------------------------------------------------------ */
3685 nat_t *nat_lookupredir(np, ifs)
3686 natlookup_t *np;
3687 ipf_stack_t *ifs;
3688 {
3689 	fr_info_t fi;
3690 	nat_t *nat;
3691 
3692 	bzero((char *)&fi, sizeof(fi));
3693 	if (np->nl_flags & IPN_IN) {
3694 		fi.fin_data[0] = ntohs(np->nl_realport);
3695 		fi.fin_data[1] = ntohs(np->nl_outport);
3696 	} else {
3697 		fi.fin_data[0] = ntohs(np->nl_inport);
3698 		fi.fin_data[1] = ntohs(np->nl_outport);
3699 	}
3700 	if (np->nl_flags & IPN_TCP)
3701 		fi.fin_p = IPPROTO_TCP;
3702 	else if (np->nl_flags & IPN_UDP)
3703 		fi.fin_p = IPPROTO_UDP;
3704 	else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY))
3705 		fi.fin_p = IPPROTO_ICMP;
3706 
3707 	fi.fin_ifs = ifs;
3708 	/*
3709 	 * We can do two sorts of lookups:
3710 	 * - IPN_IN: we have the `real' and `out' address, look for `in'.
3711 	 * - default: we have the `in' and `out' address, look for `real'.
3712 	 */
3713 	if (np->nl_flags & IPN_IN) {
3714 		if ((nat = nat_inlookup(&fi, np->nl_flags, fi.fin_p,
3715 					np->nl_realip, np->nl_outip))) {
3716 			np->nl_inip = nat->nat_inip;
3717 			np->nl_inport = nat->nat_inport;
3718 		}
3719 	} else {
3720 		/*
3721 		 * If nl_inip is non null, this is a lookup based on the real
3722 		 * ip address. Else, we use the fake.
3723 		 */
3724 		if ((nat = nat_outlookup(&fi, np->nl_flags, fi.fin_p,
3725 					 np->nl_inip, np->nl_outip))) {
3726 
3727 			if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
3728 				fr_info_t fin;
3729 				bzero((char *)&fin, sizeof(fin));
3730 				fin.fin_p = nat->nat_p;
3731 				fin.fin_data[0] = ntohs(nat->nat_outport);
3732 				fin.fin_data[1] = ntohs(nat->nat_oport);
3733 				fin.fin_ifs = ifs;
3734 				if (nat_inlookup(&fin, np->nl_flags, fin.fin_p,
3735 						 nat->nat_outip,
3736 						 nat->nat_oip) != NULL) {
3737 					np->nl_flags &= ~IPN_FINDFORWARD;
3738 				}
3739 			}
3740 
3741 			np->nl_realip = nat->nat_outip;
3742 			np->nl_realport = nat->nat_outport;
3743 		}
3744  	}
3745 
3746 	return nat;
3747 }
3748 
3749 
3750 /* ------------------------------------------------------------------------ */
3751 /* Function:    nat_match                                                   */
3752 /* Returns:     int - 0 == no match, 1 == match                             */
3753 /* Parameters:  fin(I)   - pointer to packet information                    */
3754 /*              np(I)    - pointer to NAT rule                              */
3755 /*                                                                          */
3756 /* Pull the matching of a packet against a NAT rule out of that complex     */
3757 /* loop inside fr_checknatin() and lay it out properly in its own function. */
3758 /* ------------------------------------------------------------------------ */
3759 static int nat_match(fin, np)
3760 fr_info_t *fin;
3761 ipnat_t *np;
3762 {
3763 	frtuc_t *ft;
3764 
3765 	if (fin->fin_v != 4)
3766 		return 0;
3767 
3768 	if (np->in_p && fin->fin_p != np->in_p)
3769 		return 0;
3770 
3771 	if (fin->fin_out) {
3772 		if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK)))
3773 			return 0;
3774 		if (((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip)
3775 		    ^ ((np->in_flags & IPN_NOTSRC) != 0))
3776 			return 0;
3777 		if (((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip)
3778 		    ^ ((np->in_flags & IPN_NOTDST) != 0))
3779 			return 0;
3780 	} else {
3781 		if (!(np->in_redir & NAT_REDIRECT))
3782 			return 0;
3783 		if (((fin->fin_fi.fi_saddr & np->in_srcmsk) != np->in_srcip)
3784 		    ^ ((np->in_flags & IPN_NOTSRC) != 0))
3785 			return 0;
3786 		if (((fin->fin_fi.fi_daddr & np->in_outmsk) != np->in_outip)
3787 		    ^ ((np->in_flags & IPN_NOTDST) != 0))
3788 			return 0;
3789 	}
3790 
3791 	ft = &np->in_tuc;
3792 	if (!(fin->fin_flx & FI_TCPUDP) ||
3793 	    (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
3794 		if (ft->ftu_scmp || ft->ftu_dcmp)
3795 			return 0;
3796 		return 1;
3797 	}
3798 
3799 	return fr_tcpudpchk(fin, ft);
3800 }
3801 
3802 
3803 /* ------------------------------------------------------------------------ */
3804 /* Function:    nat_update                                                  */
3805 /* Returns:     Nil                                                         */
3806 /* Parameters:	fin(I) - pointer to packet information			    */
3807 /*		nat(I) - pointer to NAT structure			    */
3808 /*              np(I)     - pointer to NAT rule                             */
3809 /* Locks:	nat_lock						    */
3810 /*                                                                          */
3811 /* Updates the lifetime of a NAT table entry for non-TCP packets.  Must be  */
3812 /* called with fin_rev updated - i.e. after calling nat_proto().            */
3813 /* ------------------------------------------------------------------------ */
3814 void nat_update(fin, nat, np)
3815 fr_info_t *fin;
3816 nat_t *nat;
3817 ipnat_t *np;
3818 {
3819 	ipftq_t *ifq, *ifq2;
3820 	ipftqent_t *tqe;
3821 	ipf_stack_t *ifs = fin->fin_ifs;
3822 
3823 	tqe = &nat->nat_tqe;
3824 	ifq = tqe->tqe_ifq;
3825 
3826 	/*
3827 	 * We allow over-riding of NAT timeouts from NAT rules, even for
3828 	 * TCP, however, if it is TCP and there is no rule timeout set,
3829 	 * then do not update the timeout here.
3830 	 */
3831 	if (np != NULL)
3832 		ifq2 = np->in_tqehead[fin->fin_rev];
3833 	else
3834 		ifq2 = NULL;
3835 
3836 	if (nat->nat_p == IPPROTO_TCP && ifq2 == NULL) {
3837 		(void) fr_tcp_age(&nat->nat_tqe, fin, ifs->ifs_nat_tqb, 0);
3838 	} else {
3839 		if (ifq2 == NULL) {
3840 			if (nat->nat_p == IPPROTO_UDP)
3841 				ifq2 = &ifs->ifs_nat_udptq;
3842 			else if (nat->nat_p == IPPROTO_ICMP)
3843 				ifq2 = &ifs->ifs_nat_icmptq;
3844 			else
3845 				ifq2 = &ifs->ifs_nat_iptq;
3846 		}
3847 
3848 		fr_movequeue(tqe, ifq, ifq2, ifs);
3849 	}
3850 }
3851 
3852 
3853 /* ------------------------------------------------------------------------ */
3854 /* Function:    fr_checknatout                                              */
3855 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
3856 /*                     0 == no packet translation occurred,                 */
3857 /*                     1 == packet was successfully translated.             */
3858 /* Parameters:  fin(I)   - pointer to packet information                    */
3859 /*              passp(I) - pointer to filtering result flags                */
3860 /*                                                                          */
3861 /* Check to see if an outcoming packet should be changed.  ICMP packets are */
3862 /* first checked to see if they match an existing entry (if an error),      */
3863 /* otherwise a search of the current NAT table is made.  If neither results */
3864 /* in a match then a search for a matching NAT rule is made.  Create a new  */
3865 /* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
3866 /* packet header(s) as required.                                            */
3867 /* ------------------------------------------------------------------------ */
3868 int fr_checknatout(fin, passp)
3869 fr_info_t *fin;
3870 u_32_t *passp;
3871 {
3872 	ipnat_t *np = NULL, *npnext;
3873 	struct ifnet *ifp, *sifp;
3874 	icmphdr_t *icmp = NULL;
3875 	tcphdr_t *tcp = NULL;
3876 	int rval, natfailed;
3877 	u_int nflags = 0;
3878 	u_32_t ipa, iph;
3879 	int natadd = 1;
3880 	frentry_t *fr;
3881 	nat_t *nat;
3882 	ipf_stack_t *ifs = fin->fin_ifs;
3883 
3884 	if (ifs->ifs_fr_nat_lock != 0)
3885 		return 0;
3886 	if (ifs->ifs_nat_stats.ns_rules == 0 && ifs->ifs_nat_instances == NULL)
3887 		return 0;
3888 
3889 	natfailed = 0;
3890 	fr = fin->fin_fr;
3891 	sifp = fin->fin_ifp;
3892 	if ((fr != NULL) && !(fr->fr_flags & FR_DUP) &&
3893 	    fr->fr_tifs[fin->fin_rev].fd_ifp &&
3894 	    fr->fr_tifs[fin->fin_rev].fd_ifp != (void *)-1)
3895 		fin->fin_ifp = fr->fr_tifs[fin->fin_rev].fd_ifp;
3896 	ifp = fin->fin_ifp;
3897 
3898 	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
3899 		switch (fin->fin_p)
3900 		{
3901 		case IPPROTO_TCP :
3902 			nflags = IPN_TCP;
3903 			break;
3904 		case IPPROTO_UDP :
3905 			nflags = IPN_UDP;
3906 			break;
3907 		case IPPROTO_ICMP :
3908 			icmp = fin->fin_dp;
3909 
3910 			/*
3911 			 * This is an incoming packet, so the destination is
3912 			 * the icmp_id and the source port equals 0
3913 			 */
3914 			if (nat_icmpquerytype4(icmp->icmp_type))
3915 				nflags = IPN_ICMPQUERY;
3916 			break;
3917 		default :
3918 			break;
3919 		}
3920 
3921 		if ((nflags & IPN_TCPUDP))
3922 			tcp = fin->fin_dp;
3923 	}
3924 
3925 	ipa = fin->fin_saddr;
3926 
3927 	READ_ENTER(&ifs->ifs_ipf_nat);
3928 
3929 	if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
3930 	    (nat = nat_icmperror(fin, &nflags, NAT_OUTBOUND)))
3931 		/*EMPTY*/;
3932 	else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin)))
3933 		natadd = 0;
3934 	else if ((nat = nat_outlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p,
3935 				      fin->fin_src, fin->fin_dst))) {
3936 		nflags = nat->nat_flags;
3937 	} else {
3938 		u_32_t hv, msk, nmsk;
3939 
3940 		/*
3941 		 * There is no current entry in the nat table for this packet.
3942 		 *
3943 		 * If the packet is a fragment, but not the first fragment,
3944 		 * then don't do anything.  Otherwise, if there is a matching
3945 		 * nat rule, try to create a new nat entry.
3946 		 */
3947 		if ((fin->fin_off != 0) && (fin->fin_flx & FI_TCPUDP))
3948 			goto nonatfrag;
3949 
3950 		msk = 0xffffffff;
3951 		nmsk = ifs->ifs_nat_masks;
3952 maskloop:
3953 		iph = ipa & htonl(msk);
3954 		hv = NAT_HASH_FN(iph, 0, ifs->ifs_ipf_natrules_sz);
3955 		for (np = ifs->ifs_nat_rules[hv]; np; np = npnext) {
3956 			npnext = np->in_mnext;
3957 			if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
3958 				continue;
3959 			if (np->in_v != fin->fin_v)
3960 				continue;
3961 			if (np->in_p && (np->in_p != fin->fin_p))
3962 				continue;
3963 			if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
3964 				continue;
3965 			if (np->in_flags & IPN_FILTER) {
3966 				if (!nat_match(fin, np))
3967 					continue;
3968 			} else if ((ipa & np->in_inmsk) != np->in_inip)
3969 				continue;
3970 
3971 			if ((fr != NULL) &&
3972 			    !fr_matchtag(&np->in_tag, &fr->fr_nattag))
3973 				continue;
3974 
3975 			if (*np->in_plabel != '\0') {
3976 				if (((np->in_flags & IPN_FILTER) == 0) &&
3977 				    (np->in_dport != tcp->th_dport))
3978 					continue;
3979 				if (appr_ok(fin, tcp, np) == 0)
3980 					continue;
3981 			}
3982 
3983 			ATOMIC_INC32(np->in_use);
3984 			RWLOCK_EXIT(&ifs->ifs_ipf_nat);
3985 			WRITE_ENTER(&ifs->ifs_ipf_nat);
3986 			nat = nat_new(fin, np, NULL, nflags, NAT_OUTBOUND);
3987 			if (nat != NULL) {
3988 				np->in_use--;
3989 				np->in_hits++;
3990 				MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
3991 				break;
3992 			}
3993 			natfailed = -1;
3994 			npnext = np->in_mnext;
3995 			fr_ipnatderef(&np, ifs);
3996 			MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
3997 		}
3998 		if ((np == NULL) && (nmsk != 0)) {
3999 			while (nmsk) {
4000 				msk <<= 1;
4001 				if (nmsk & 0x80000000)
4002 					break;
4003 				nmsk <<= 1;
4004 			}
4005 			if (nmsk != 0) {
4006 				nmsk <<= 1;
4007 				goto maskloop;
4008 			}
4009 		}
4010 	}
4011 
4012 nonatfrag:
4013 	if (nat != NULL) {
4014 		rval = fr_natout(fin, nat, natadd, nflags);
4015 		if (rval == 1) {
4016 			MUTEX_ENTER(&nat->nat_lock);
4017 			nat_update(fin, nat, nat->nat_ptr);
4018 			nat->nat_bytes[1] += fin->fin_plen;
4019 			nat->nat_pkts[1]++;
4020 			fin->fin_pktnum = nat->nat_pkts[1];
4021 			MUTEX_EXIT(&nat->nat_lock);
4022 		}
4023 	} else
4024 		rval = natfailed;
4025 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
4026 
4027 	if (rval == -1) {
4028 		if (passp != NULL)
4029 			*passp = FR_BLOCK;
4030 		fin->fin_flx |= FI_BADNAT;
4031 	}
4032 	fin->fin_ifp = sifp;
4033 	return rval;
4034 }
4035 
4036 /* ------------------------------------------------------------------------ */
4037 /* Function:    fr_natout                                                   */
4038 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
4039 /*                     1 == packet was successfully translated.             */
4040 /* Parameters:  fin(I)    - pointer to packet information                   */
4041 /*              nat(I)    - pointer to NAT structure                        */
4042 /*              natadd(I) - flag indicating if it is safe to add frag cache */
4043 /*              nflags(I) - NAT flags set for this packet                   */
4044 /*                                                                          */
4045 /* Translate a packet coming "out" on an interface.                         */
4046 /* ------------------------------------------------------------------------ */
4047 int fr_natout(fin, nat, natadd, nflags)
4048 fr_info_t *fin;
4049 nat_t *nat;
4050 int natadd;
4051 u_32_t nflags;
4052 {
4053 	icmphdr_t *icmp;
4054 	u_short *csump;
4055 	u_32_t sumd;
4056 	tcphdr_t *tcp;
4057 	ipnat_t *np;
4058 	int i;
4059 	ipf_stack_t *ifs = fin->fin_ifs;
4060 
4061 	if (fin->fin_v == 6) {
4062 #ifdef	USE_INET6
4063 		return fr_nat6out(fin, nat, natadd, nflags);
4064 #else
4065 		return NULL;
4066 #endif
4067 	}
4068 
4069 #if SOLARIS && defined(_KERNEL)
4070 	net_handle_t net_data_p = ifs->ifs_ipf_ipv4;
4071 #endif
4072 
4073 	tcp = NULL;
4074 	icmp = NULL;
4075 	csump = NULL;
4076 	np = nat->nat_ptr;
4077 
4078 	if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
4079 		(void) fr_nat_newfrag(fin, 0, nat);
4080 
4081 	/*
4082 	 * Fix up checksums, not by recalculating them, but
4083 	 * simply computing adjustments.
4084 	 * This is only done for STREAMS based IP implementations where the
4085 	 * checksum has already been calculated by IP.  In all other cases,
4086 	 * IPFilter is called before the checksum needs calculating so there
4087 	 * is no call to modify whatever is in the header now.
4088 	 */
4089 	ASSERT(fin->fin_m != NULL);
4090 	if (fin->fin_v == 4 && !NET_IS_HCK_L3_FULL(net_data_p, fin->fin_m)) {
4091 		if (nflags == IPN_ICMPERR) {
4092 			u_32_t s1, s2;
4093 
4094 			s1 = LONG_SUM(ntohl(fin->fin_saddr));
4095 			s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr));
4096 			CALC_SUMD(s1, s2, sumd);
4097 
4098 			fix_outcksum(&fin->fin_ip->ip_sum, sumd);
4099 		}
4100 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
4101     defined(linux) || defined(BRIDGE_IPF)
4102 		else {
4103 			/*
4104 			 * Strictly speaking, this isn't necessary on BSD
4105 			 * kernels because they do checksum calculation after
4106 			 * this code has run BUT if ipfilter is being used
4107 			 * to do NAT as a bridge, that code doesn't exist.
4108 			 */
4109 			if (nat->nat_dir == NAT_OUTBOUND)
4110 				fix_outcksum(&fin->fin_ip->ip_sum,
4111 					    nat->nat_ipsumd);
4112 			else
4113 				fix_incksum(&fin->fin_ip->ip_sum,
4114 				 	   nat->nat_ipsumd);
4115 		}
4116 #endif
4117 	}
4118 
4119 	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
4120 		if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) {
4121 			tcp = fin->fin_dp;
4122 
4123 			tcp->th_sport = nat->nat_outport;
4124 			fin->fin_data[0] = ntohs(nat->nat_outport);
4125 		}
4126 
4127 		if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) {
4128 			icmp = fin->fin_dp;
4129 			icmp->icmp_id = nat->nat_outport;
4130 		}
4131 
4132 		csump = nat_proto(fin, nat, nflags);
4133 	}
4134 
4135 	fin->fin_ip->ip_src = nat->nat_outip;
4136 
4137 	/*
4138 	 * The above comments do not hold for layer 4 (or higher) checksums...
4139 	 */
4140 	if (csump != NULL && !NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m)) {
4141 		if (nflags & IPN_TCPUDP &&
4142 	   	    NET_IS_HCK_L4_PART(net_data_p, fin->fin_m))
4143 			sumd = nat->nat_sumd[1];
4144 		else
4145 			sumd = nat->nat_sumd[0];
4146 
4147 		if (nat->nat_dir == NAT_OUTBOUND)
4148 			fix_outcksum(csump, sumd);
4149 		else
4150 			fix_incksum(csump, sumd);
4151 	}
4152 #ifdef	IPFILTER_SYNC
4153 	ipfsync_update(SMC_NAT, fin, nat->nat_sync);
4154 #endif
4155 	/* ------------------------------------------------------------- */
4156 	/* A few quick notes:						 */
4157 	/*	Following are test conditions prior to calling the 	 */
4158 	/*	appr_check routine.					 */
4159 	/*								 */
4160 	/* 	A NULL tcp indicates a non TCP/UDP packet.  When dealing */
4161 	/*	with a redirect rule, we attempt to match the packet's	 */
4162 	/*	source port against in_dport, otherwise	we'd compare the */
4163 	/*	packet's destination.			 		 */
4164 	/* ------------------------------------------------------------- */
4165 	if ((np != NULL) && (np->in_apr != NULL)) {
4166 		i = appr_check(fin, nat);
4167 		if (i == 0)
4168 			i = 1;
4169 	} else
4170 		i = 1;
4171 	ifs->ifs_nat_stats.ns_mapped[1]++;
4172 	fin->fin_flx |= FI_NATED;
4173 	return i;
4174 }
4175 
4176 
4177 /* ------------------------------------------------------------------------ */
4178 /* Function:    fr_checknatin                                               */
4179 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
4180 /*                     0 == no packet translation occurred,                 */
4181 /*                     1 == packet was successfully translated.             */
4182 /* Parameters:  fin(I)   - pointer to packet information                    */
4183 /*              passp(I) - pointer to filtering result flags                */
4184 /*                                                                          */
4185 /* Check to see if an incoming packet should be changed.  ICMP packets are  */
4186 /* first checked to see if they match an existing entry (if an error),      */
4187 /* otherwise a search of the current NAT table is made.  If neither results */
4188 /* in a match then a search for a matching NAT rule is made.  Create a new  */
4189 /* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
4190 /* packet header(s) as required.                                            */
4191 /* ------------------------------------------------------------------------ */
4192 int fr_checknatin(fin, passp)
4193 fr_info_t *fin;
4194 u_32_t *passp;
4195 {
4196 	u_int nflags, natadd;
4197 	ipnat_t *np, *npnext;
4198 	int rval, natfailed;
4199 	struct ifnet *ifp;
4200 	struct in_addr in;
4201 	icmphdr_t *icmp;
4202 	tcphdr_t *tcp;
4203 	u_short dport;
4204 	nat_t *nat;
4205 	u_32_t iph;
4206 	ipf_stack_t *ifs = fin->fin_ifs;
4207 
4208 	if (ifs->ifs_fr_nat_lock != 0)
4209 		return 0;
4210 	if (ifs->ifs_nat_stats.ns_rules == 0 && ifs->ifs_nat_instances == NULL)
4211 		return 0;
4212 
4213 	tcp = NULL;
4214 	icmp = NULL;
4215 	dport = 0;
4216 	natadd = 1;
4217 	nflags = 0;
4218 	natfailed = 0;
4219 	ifp = fin->fin_ifp;
4220 
4221 	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
4222 		switch (fin->fin_p)
4223 		{
4224 		case IPPROTO_TCP :
4225 			nflags = IPN_TCP;
4226 			break;
4227 		case IPPROTO_UDP :
4228 			nflags = IPN_UDP;
4229 			break;
4230 		case IPPROTO_ICMP :
4231 			icmp = fin->fin_dp;
4232 
4233 			/*
4234 			 * This is an incoming packet, so the destination is
4235 			 * the icmp_id and the source port equals 0
4236 			 */
4237 			if (nat_icmpquerytype4(icmp->icmp_type)) {
4238 				nflags = IPN_ICMPQUERY;
4239 				dport = icmp->icmp_id;
4240 			} break;
4241 		default :
4242 			break;
4243 		}
4244 
4245 		if ((nflags & IPN_TCPUDP)) {
4246 			tcp = fin->fin_dp;
4247 			dport = tcp->th_dport;
4248 		}
4249 	}
4250 
4251 	in = fin->fin_dst;
4252 
4253 	READ_ENTER(&ifs->ifs_ipf_nat);
4254 
4255 	if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
4256 	    (nat = nat_icmperror(fin, &nflags, NAT_INBOUND)))
4257 		/*EMPTY*/;
4258 	else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin)))
4259 		natadd = 0;
4260 	else if ((nat = nat_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p,
4261 				     fin->fin_src, in))) {
4262 		nflags = nat->nat_flags;
4263 	} else {
4264 		u_32_t hv, msk, rmsk;
4265 
4266 		/*
4267 		 * There is no current entry in the nat table for this packet.
4268 		 *
4269 		 * If the packet is a fragment, but not the first fragment,
4270 		 * then don't do anything.  Otherwise, if there is a matching
4271 		 * nat rule, try to create a new nat entry.
4272 		 */
4273 		if ((fin->fin_off != 0) && (fin->fin_flx & FI_TCPUDP))
4274 			goto nonatfrag;
4275 
4276 		rmsk = ifs->ifs_rdr_masks;
4277 		msk = 0xffffffff;
4278 maskloop:
4279 		iph = in.s_addr & htonl(msk);
4280 		hv = NAT_HASH_FN(iph, 0, ifs->ifs_ipf_rdrrules_sz);
4281 		for (np = ifs->ifs_rdr_rules[hv]; np; np = npnext) {
4282 			npnext = np->in_rnext;
4283 			if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
4284 				continue;
4285 			if (np->in_v != fin->fin_v)
4286 				continue;
4287 			if (np->in_p && (np->in_p != fin->fin_p))
4288 				continue;
4289 			if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
4290 				continue;
4291 			if (np->in_flags & IPN_FILTER) {
4292 				if (!nat_match(fin, np))
4293 					continue;
4294 			} else {
4295 				if ((in.s_addr & np->in_outmsk) != np->in_outip)
4296 					continue;
4297 				if (np->in_pmin &&
4298 				    ((ntohs(np->in_pmax) < ntohs(dport)) ||
4299 				     (ntohs(dport) < ntohs(np->in_pmin))))
4300 					continue;
4301 			}
4302 
4303 			if (*np->in_plabel != '\0') {
4304 				if (!appr_ok(fin, tcp, np)) {
4305 					continue;
4306 				}
4307 			}
4308 
4309 			ATOMIC_INC32(np->in_use);
4310 			RWLOCK_EXIT(&ifs->ifs_ipf_nat);
4311 			WRITE_ENTER(&ifs->ifs_ipf_nat);
4312 			nat = nat_new(fin, np, NULL, nflags, NAT_INBOUND);
4313 			if (nat != NULL) {
4314 				np->in_use--;
4315 				np->in_hits++;
4316 				MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
4317 				break;
4318 			}
4319 			natfailed = -1;
4320 			npnext = np->in_rnext;
4321 			fr_ipnatderef(&np, ifs);
4322 			MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
4323 		}
4324 
4325 		if ((np == NULL) && (rmsk != 0)) {
4326 			while (rmsk) {
4327 				msk <<= 1;
4328 				if (rmsk & 0x80000000)
4329 					break;
4330 				rmsk <<= 1;
4331 			}
4332 			if (rmsk != 0) {
4333 				rmsk <<= 1;
4334 				goto maskloop;
4335 			}
4336 		}
4337 	}
4338 
4339 nonatfrag:
4340 	if (nat != NULL) {
4341 		rval = fr_natin(fin, nat, natadd, nflags);
4342 		if (rval == 1) {
4343 			MUTEX_ENTER(&nat->nat_lock);
4344 			nat_update(fin, nat, nat->nat_ptr);
4345 			nat->nat_bytes[0] += fin->fin_plen;
4346 			nat->nat_pkts[0]++;
4347 			fin->fin_pktnum = nat->nat_pkts[0];
4348 			MUTEX_EXIT(&nat->nat_lock);
4349 		}
4350 	} else
4351 		rval = natfailed;
4352 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
4353 
4354 	if (rval == -1) {
4355 		if (passp != NULL)
4356 			*passp = FR_BLOCK;
4357 		fin->fin_flx |= FI_BADNAT;
4358 	}
4359 	return rval;
4360 }
4361 
4362 
4363 /* ------------------------------------------------------------------------ */
4364 /* Function:    fr_natin                                                    */
4365 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
4366 /*                     1 == packet was successfully translated.             */
4367 /* Parameters:  fin(I)    - pointer to packet information                   */
4368 /*              nat(I)    - pointer to NAT structure                        */
4369 /*              natadd(I) - flag indicating if it is safe to add frag cache */
4370 /*              nflags(I) - NAT flags set for this packet                   */
4371 /* Locks Held:  ipf_nat (READ)                                              */
4372 /*                                                                          */
4373 /* Translate a packet coming "in" on an interface.                          */
4374 /* ------------------------------------------------------------------------ */
4375 int fr_natin(fin, nat, natadd, nflags)
4376 fr_info_t *fin;
4377 nat_t *nat;
4378 int natadd;
4379 u_32_t nflags;
4380 {
4381 	icmphdr_t *icmp;
4382 	u_short *csump;
4383 	tcphdr_t *tcp;
4384 	ipnat_t *np;
4385 	int i;
4386 	ipf_stack_t *ifs = fin->fin_ifs;
4387 
4388 	if (fin->fin_v == 6) {
4389 #ifdef	USE_INET6
4390 		return fr_nat6in(fin, nat, natadd, nflags);
4391 #else
4392 		return NULL;
4393 #endif
4394 	}
4395 
4396 #if SOLARIS && defined(_KERNEL)
4397 	net_handle_t net_data_p = ifs->ifs_ipf_ipv4;
4398 #endif
4399 
4400 	tcp = NULL;
4401 	csump = NULL;
4402 	np = nat->nat_ptr;
4403 	fin->fin_fr = nat->nat_fr;
4404 
4405 	if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
4406 		(void) fr_nat_newfrag(fin, 0, nat);
4407 
4408 	if (np != NULL) {
4409 
4410 	/* ------------------------------------------------------------- */
4411 	/* A few quick notes:						 */
4412 	/*	Following are test conditions prior to calling the 	 */
4413 	/*	appr_check routine.					 */
4414 	/*								 */
4415 	/* 	A NULL tcp indicates a non TCP/UDP packet.  When dealing */
4416 	/*	with a map rule, we attempt to match the packet's	 */
4417 	/*	source port against in_dport, otherwise	we'd compare the */
4418 	/*	packet's destination.			 		 */
4419 	/* ------------------------------------------------------------- */
4420 		if (np->in_apr != NULL) {
4421 			i = appr_check(fin, nat);
4422 			if (i == -1) {
4423 				return -1;
4424 			}
4425 		}
4426 	}
4427 
4428 #ifdef	IPFILTER_SYNC
4429 	ipfsync_update(SMC_NAT, fin, nat->nat_sync);
4430 #endif
4431 
4432 	fin->fin_ip->ip_dst = nat->nat_inip;
4433 	fin->fin_fi.fi_daddr = nat->nat_inip.s_addr;
4434 	if (nflags & IPN_TCPUDP)
4435 		tcp = fin->fin_dp;
4436 
4437 	/*
4438 	 * Fix up checksums, not by recalculating them, but
4439 	 * simply computing adjustments.
4440 	 * Why only do this for some platforms on inbound packets ?
4441 	 * Because for those that it is done, IP processing is yet to happen
4442 	 * and so the IPv4 header checksum has not yet been evaluated.
4443 	 * Perhaps it should always be done for the benefit of things like
4444 	 * fast forwarding (so that it doesn't need to be recomputed) but with
4445 	 * header checksum offloading, perhaps it is a moot point.
4446 	 */
4447 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
4448      defined(__osf__) || defined(linux)
4449 	if (nat->nat_dir == NAT_OUTBOUND)
4450 		fix_incksum(&fin->fin_ip->ip_sum, nat->nat_ipsumd);
4451 	else
4452 		fix_outcksum(&fin->fin_ip->ip_sum, nat->nat_ipsumd);
4453 #endif
4454 
4455 	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
4456 		if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) {
4457 			tcp->th_dport = nat->nat_inport;
4458 			fin->fin_data[1] = ntohs(nat->nat_inport);
4459 		}
4460 
4461 
4462 		if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) {
4463 			icmp = fin->fin_dp;
4464 
4465 			icmp->icmp_id = nat->nat_inport;
4466 		}
4467 
4468 		csump = nat_proto(fin, nat, nflags);
4469 	}
4470 
4471 	/*
4472 	 * In case they are being forwarded, inbound packets always need to have
4473 	 * their checksum adjusted even if hardware checksum validation said OK.
4474 	 */
4475 	if (csump != NULL) {
4476 		if (nat->nat_dir == NAT_OUTBOUND)
4477 			fix_incksum(csump, nat->nat_sumd[0]);
4478 		else
4479 			fix_outcksum(csump, nat->nat_sumd[0]);
4480 	}
4481 
4482 #if SOLARIS && defined(_KERNEL)
4483 	if (nflags & IPN_TCPUDP &&
4484 	    NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) {
4485 		/*
4486 		 * Need to adjust the partial checksum result stored in
4487 		 * db_cksum16, which will be used for validation in IP.
4488 		 * See IP_CKSUM_RECV().
4489 		 * Adjustment data should be the inverse of the IP address
4490 		 * changes, because db_cksum16 is supposed to be the complement
4491 		 * of the pesudo header.
4492 		 */
4493 		csump = &fin->fin_m->b_datap->db_cksum16;
4494 		if (nat->nat_dir == NAT_OUTBOUND)
4495 			fix_outcksum(csump, nat->nat_sumd[1]);
4496 		else
4497 			fix_incksum(csump, nat->nat_sumd[1]);
4498 	}
4499 #endif
4500 
4501 	ifs->ifs_nat_stats.ns_mapped[0]++;
4502 	fin->fin_flx |= FI_NATED;
4503 	if (np != NULL && np->in_tag.ipt_num[0] != 0)
4504 		fin->fin_nattag = &np->in_tag;
4505 	return 1;
4506 }
4507 
4508 
4509 /* ------------------------------------------------------------------------ */
4510 /* Function:    nat_proto                                                   */
4511 /* Returns:     u_short* - pointer to transport header checksum to update,  */
4512 /*                         NULL if the transport protocol is not recognised */
4513 /*                         as needing a checksum update.                    */
4514 /* Parameters:  fin(I)    - pointer to packet information                   */
4515 /*              nat(I)    - pointer to NAT structure                        */
4516 /*              nflags(I) - NAT flags set for this packet                   */
4517 /*                                                                          */
4518 /* Return the pointer to the checksum field for each protocol so understood.*/
4519 /* If support for making other changes to a protocol header is required,    */
4520 /* that is not strictly 'address' translation, such as clamping the MSS in  */
4521 /* TCP down to a specific value, then do it from here.                      */
4522 /* ------------------------------------------------------------------------ */
4523 u_short *nat_proto(fin, nat, nflags)
4524 fr_info_t *fin;
4525 nat_t *nat;
4526 u_int nflags;
4527 {
4528 	icmphdr_t *icmp;
4529 	struct icmp6_hdr *icmp6;
4530 	u_short *csump;
4531 	tcphdr_t *tcp;
4532 	udphdr_t *udp;
4533 
4534 	csump = NULL;
4535 	if (fin->fin_out == 0) {
4536 		fin->fin_rev = (nat->nat_dir == NAT_OUTBOUND);
4537 	} else {
4538 		fin->fin_rev = (nat->nat_dir == NAT_INBOUND);
4539 	}
4540 
4541 	switch (fin->fin_p)
4542 	{
4543 	case IPPROTO_TCP :
4544 		tcp = fin->fin_dp;
4545 
4546 		csump = &tcp->th_sum;
4547 
4548 		/*
4549 		 * Do a MSS CLAMPING on a SYN packet,
4550 		 * only deal IPv4 for now.
4551 		 */
4552 		if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0)
4553 			nat_mssclamp(tcp, nat->nat_mssclamp, csump);
4554 
4555 		break;
4556 
4557 	case IPPROTO_UDP :
4558 		udp = fin->fin_dp;
4559 
4560 		if (udp->uh_sum)
4561 			csump = &udp->uh_sum;
4562 		break;
4563 
4564 	case IPPROTO_ICMP :
4565 		icmp = fin->fin_dp;
4566 
4567 		if ((nflags & IPN_ICMPQUERY) != 0) {
4568 			if (icmp->icmp_cksum != 0)
4569 				csump = &icmp->icmp_cksum;
4570 		}
4571 		break;
4572 
4573 	case IPPROTO_ICMPV6 :
4574 		icmp6 = fin->fin_dp;
4575 
4576 		if ((nflags & IPN_ICMPQUERY) != 0) {
4577 			if (icmp6->icmp6_cksum != 0)
4578 				csump = &icmp6->icmp6_cksum;
4579 		}
4580 		break;
4581 	}
4582 	return csump;
4583 }
4584 
4585 
4586 /* ------------------------------------------------------------------------ */
4587 /* Function:    fr_natunload                                                */
4588 /* Returns:     Nil                                                         */
4589 /* Parameters:  ifs - ipf stack instance                                  */
4590 /*                                                                          */
4591 /* Free all memory used by NAT structures allocated at runtime.             */
4592 /* ------------------------------------------------------------------------ */
4593 void fr_natunload(ifs)
4594 ipf_stack_t *ifs;
4595 {
4596 	ipftq_t *ifq, *ifqnext;
4597 
4598 	(void) nat_clearlist(ifs);
4599 	(void) nat_flushtable(FLUSH_TABLE_ALL, ifs);
4600 
4601 	/*
4602 	 * Proxy timeout queues are not cleaned here because although they
4603 	 * exist on the NAT list, appr_unload is called after fr_natunload
4604 	 * and the proxies actually are responsible for them being created.
4605 	 * Should the proxy timeouts have their own list?  There's no real
4606 	 * justification as this is the only complication.
4607 	 */
4608 	for (ifq = ifs->ifs_nat_utqe; ifq != NULL; ifq = ifqnext) {
4609 		ifqnext = ifq->ifq_next;
4610 		if (((ifq->ifq_flags & IFQF_PROXY) == 0) &&
4611 		    (fr_deletetimeoutqueue(ifq) == 0))
4612 			fr_freetimeoutqueue(ifq, ifs);
4613 	}
4614 
4615 	if (ifs->ifs_nat_table[0] != NULL) {
4616 		KFREES(ifs->ifs_nat_table[0],
4617 		       sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz);
4618 		ifs->ifs_nat_table[0] = NULL;
4619 	}
4620 	if (ifs->ifs_nat_table[1] != NULL) {
4621 		KFREES(ifs->ifs_nat_table[1],
4622 		       sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz);
4623 		ifs->ifs_nat_table[1] = NULL;
4624 	}
4625 	if (ifs->ifs_nat_rules != NULL) {
4626 		KFREES(ifs->ifs_nat_rules,
4627 		       sizeof(ipnat_t *) * ifs->ifs_ipf_natrules_sz);
4628 		ifs->ifs_nat_rules = NULL;
4629 	}
4630 	if (ifs->ifs_rdr_rules != NULL) {
4631 		KFREES(ifs->ifs_rdr_rules,
4632 		       sizeof(ipnat_t *) * ifs->ifs_ipf_rdrrules_sz);
4633 		ifs->ifs_rdr_rules = NULL;
4634 	}
4635 	if (ifs->ifs_maptable != NULL) {
4636 		KFREES(ifs->ifs_maptable,
4637 		       sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz);
4638 		ifs->ifs_maptable = NULL;
4639 	}
4640 	if (ifs->ifs_nat_stats.ns_bucketlen[0] != NULL) {
4641 		KFREES(ifs->ifs_nat_stats.ns_bucketlen[0],
4642 		       sizeof(u_long *) * ifs->ifs_ipf_nattable_sz);
4643 		ifs->ifs_nat_stats.ns_bucketlen[0] = NULL;
4644 	}
4645 	if (ifs->ifs_nat_stats.ns_bucketlen[1] != NULL) {
4646 		KFREES(ifs->ifs_nat_stats.ns_bucketlen[1],
4647 		       sizeof(u_long *) * ifs->ifs_ipf_nattable_sz);
4648 		ifs->ifs_nat_stats.ns_bucketlen[1] = NULL;
4649 	}
4650 
4651 	if (ifs->ifs_fr_nat_maxbucket_reset == 1)
4652 		ifs->ifs_fr_nat_maxbucket = 0;
4653 
4654 	if (ifs->ifs_fr_nat_init == 1) {
4655 		ifs->ifs_fr_nat_init = 0;
4656 		fr_sttab_destroy(ifs->ifs_nat_tqb);
4657 
4658 		RW_DESTROY(&ifs->ifs_ipf_natfrag);
4659 		RW_DESTROY(&ifs->ifs_ipf_nat);
4660 
4661 		MUTEX_DESTROY(&ifs->ifs_ipf_nat_new);
4662 		MUTEX_DESTROY(&ifs->ifs_ipf_natio);
4663 
4664 		MUTEX_DESTROY(&ifs->ifs_nat_udptq.ifq_lock);
4665 		MUTEX_DESTROY(&ifs->ifs_nat_icmptq.ifq_lock);
4666 		MUTEX_DESTROY(&ifs->ifs_nat_iptq.ifq_lock);
4667 	}
4668 }
4669 
4670 
4671 /* ------------------------------------------------------------------------ */
4672 /* Function:    fr_natexpire                                                */
4673 /* Returns:     Nil                                                         */
4674 /* Parameters:  ifs - ipf stack instance                                    */
4675 /*                                                                          */
4676 /* Check all of the timeout queues for entries at the top which need to be  */
4677 /* expired.                                                                 */
4678 /* ------------------------------------------------------------------------ */
4679 void fr_natexpire(ifs)
4680 ipf_stack_t *ifs;
4681 {
4682 	ipftq_t *ifq, *ifqnext;
4683 	ipftqent_t *tqe, *tqn;
4684 	int i;
4685 	SPL_INT(s);
4686 
4687 	SPL_NET(s);
4688 	WRITE_ENTER(&ifs->ifs_ipf_nat);
4689 	for (ifq = ifs->ifs_nat_tqb, i = 0; ifq != NULL; ifq = ifq->ifq_next) {
4690 		for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
4691 			if (tqe->tqe_die > ifs->ifs_fr_ticks)
4692 				break;
4693 			tqn = tqe->tqe_next;
4694 			(void) nat_delete(tqe->tqe_parent, NL_EXPIRE, ifs);
4695 		}
4696 	}
4697 
4698 	for (ifq = ifs->ifs_nat_utqe; ifq != NULL; ifq = ifqnext) {
4699 		ifqnext = ifq->ifq_next;
4700 
4701 		for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
4702 			if (tqe->tqe_die > ifs->ifs_fr_ticks)
4703 				break;
4704 			tqn = tqe->tqe_next;
4705 			(void) nat_delete(tqe->tqe_parent, NL_EXPIRE, ifs);
4706 		}
4707 	}
4708 
4709 	for (ifq = ifs->ifs_nat_utqe; ifq != NULL; ifq = ifqnext) {
4710 		ifqnext = ifq->ifq_next;
4711 
4712 		if (((ifq->ifq_flags & IFQF_DELETE) != 0) &&
4713 		    (ifq->ifq_ref == 0)) {
4714 			fr_freetimeoutqueue(ifq, ifs);
4715 		}
4716 	}
4717 
4718 	if (ifs->ifs_nat_doflush != 0) {
4719 		(void) nat_flushtable(FLUSH_TABLE_EXTRA, ifs);
4720 		ifs->ifs_nat_doflush = 0;
4721 	}
4722 
4723 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
4724 	SPL_X(s);
4725 }
4726 
4727 
4728 /* ------------------------------------------------------------------------ */
4729 /* Function:    fr_nataddrsync                                              */
4730 /* Returns:     Nil                                                         */
4731 /* Parameters:  ifp(I) -  pointer to network interface                      */
4732 /*              addr(I) - pointer to new network address                    */
4733 /*                                                                          */
4734 /* Walk through all of the currently active NAT sessions, looking for those */
4735 /* which need to have their translated address updated (where the interface */
4736 /* matches the one passed in) and change it, recalculating the checksum sum */
4737 /* difference too.                                                          */
4738 /* ------------------------------------------------------------------------ */
4739 void fr_nataddrsync(v, ifp, addr, ifs)
4740 int v;
4741 void *ifp;
4742 void *addr;
4743 ipf_stack_t *ifs;
4744 {
4745 	u_32_t sum1, sum2, sumd;
4746 	nat_t *nat;
4747 	ipnat_t *np;
4748 	SPL_INT(s);
4749 
4750 	if (ifs->ifs_fr_running <= 0)
4751 		return;
4752 
4753 	SPL_NET(s);
4754 	WRITE_ENTER(&ifs->ifs_ipf_nat);
4755 
4756 	if (ifs->ifs_fr_running <= 0) {
4757 		RWLOCK_EXIT(&ifs->ifs_ipf_nat);
4758 		return;
4759 	}
4760 
4761 	/*
4762 	 * Change IP addresses for NAT sessions for any protocol except TCP
4763 	 * since it will break the TCP connection anyway.  The only rules
4764 	 * which will get changed are those which are "map ... -> 0/32",
4765 	 * where the rule specifies the address is taken from the interface.
4766 	 */
4767 	for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) {
4768 		if (addr != NULL) {
4769 			if (((ifp != NULL) && ifp != (nat->nat_ifps[0])) ||
4770 			    ((nat->nat_flags & IPN_TCP) != 0))
4771 				continue;
4772 			if ((np = nat->nat_ptr) == NULL)
4773 				continue;
4774 			if (v == 4 && np->in_v == 4) {
4775 				if (np->in_nip || np->in_outmsk != 0xffffffff)
4776 					continue;
4777 				/*
4778 				 * Change the map-to address to be the same as
4779 				 * the new one.
4780 				 */
4781 				sum1 = nat->nat_outip.s_addr;
4782 				nat->nat_outip = *(struct in_addr *)addr;
4783 				sum2 = nat->nat_outip.s_addr;
4784 			} else if (v == 6 && np->in_v == 6) {
4785 				if (!IP6_ISZERO(&np->in_next6.in6) ||
4786 				    !IP6_ISONES(&np->in_out[1].in6))
4787 					continue;
4788 				/*
4789 				 * Change the map-to address to be the same as
4790 				 * the new one.
4791 				 */
4792 				nat->nat_outip6.in6 = *(struct in6_addr *)addr;
4793 			} else
4794 				continue;
4795 
4796 		} else if (((ifp == NULL) || (ifp == nat->nat_ifps[0])) &&
4797 		    !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr)) {
4798 			if (np->in_v == 4 && (v == 4 || v == 0)) {
4799 				struct in_addr in;
4800 				if (np->in_outmsk != 0xffffffff || np->in_nip)
4801 					continue;
4802 				/*
4803 				 * Change the map-to address to be the same as
4804 				 * the new one.
4805 				 */
4806 				sum1 = nat->nat_outip.s_addr;
4807 				if (fr_ifpaddr(4, FRI_NORMAL, nat->nat_ifps[0],
4808 					       &in, NULL, ifs) != -1)
4809 					nat->nat_outip = in;
4810 				sum2 = nat->nat_outip.s_addr;
4811 			} else if (np->in_v == 6 && (v == 6 || v == 0)) {
4812 				struct in6_addr in6;
4813 				if (!IP6_ISZERO(&np->in_next6.in6) ||
4814 				    !IP6_ISONES(&np->in_out[1].in6))
4815 					continue;
4816 				/*
4817 				 * Change the map-to address to be the same as
4818 				 * the new one.
4819 				 */
4820 				if (fr_ifpaddr(6, FRI_NORMAL, nat->nat_ifps[0],
4821 					       (void *)&in6, NULL, ifs) != -1)
4822 					nat->nat_outip6.in6 = in6;
4823 			} else
4824 				continue;
4825 		} else {
4826 			continue;
4827 		}
4828 
4829 		if (sum1 == sum2)
4830 			continue;
4831 		/*
4832 		 * Readjust the checksum adjustment to take into
4833 		 * account the new IP#.
4834 		 */
4835 		CALC_SUMD(sum1, sum2, sumd);
4836 		/* XXX - dont change for TCP when solaris does
4837 		 * hardware checksumming.
4838 		 */
4839 		sumd += nat->nat_sumd[0];
4840 		nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
4841 		nat->nat_sumd[1] = nat->nat_sumd[0];
4842 	}
4843 
4844 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
4845 	SPL_X(s);
4846 }
4847 
4848 
4849 /* ------------------------------------------------------------------------ */
4850 /* Function:    fr_natifpsync                                               */
4851 /* Returns:     Nil                                                         */
4852 /* Parameters:  action(I) - how we are syncing                              */
4853 /*              ifp(I)    - pointer to network interface                    */
4854 /*              name(I)   - name of interface to sync to                    */
4855 /*                                                                          */
4856 /* This function is used to resync the mapping of interface names and their */
4857 /* respective 'pointers'.  For "action == IPFSYNC_RESYNC", resync all       */
4858 /* interfaces by doing a new lookup of name to 'pointer'.  For "action ==   */
4859 /* IPFSYNC_NEWIFP", treat ifp as the new pointer value associated with      */
4860 /* "name" and for "action == IPFSYNC_OLDIFP", ifp is a pointer for which    */
4861 /* there is no longer any interface associated with it.                     */
4862 /* ------------------------------------------------------------------------ */
4863 void fr_natifpsync(action, v, ifp, name, ifs)
4864 int action, v;
4865 void *ifp;
4866 char *name;
4867 ipf_stack_t *ifs;
4868 {
4869 #if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL)
4870 	int s;
4871 #endif
4872 	nat_t *nat;
4873 	ipnat_t *n;
4874 	int nv;
4875 
4876 	if (ifs->ifs_fr_running <= 0)
4877 		return;
4878 
4879 	SPL_NET(s);
4880 	WRITE_ENTER(&ifs->ifs_ipf_nat);
4881 
4882 	if (ifs->ifs_fr_running <= 0) {
4883 		RWLOCK_EXIT(&ifs->ifs_ipf_nat);
4884 		return;
4885 	}
4886 
4887 	switch (action)
4888 	{
4889 	case IPFSYNC_RESYNC :
4890 		for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) {
4891 			nv = (v == 0) ? nat->nat_v : v;
4892 			if (nat->nat_v != nv)
4893 				continue;
4894 			if ((ifp == nat->nat_ifps[0]) ||
4895 			    (nat->nat_ifps[0] == (void *)-1)) {
4896 				nat->nat_ifps[0] =
4897 				    fr_resolvenic(nat->nat_ifnames[0], nv, ifs);
4898 			}
4899 
4900 			if ((ifp == nat->nat_ifps[1]) ||
4901 			    (nat->nat_ifps[1] == (void *)-1)) {
4902 				nat->nat_ifps[1] =
4903 				    fr_resolvenic(nat->nat_ifnames[1], nv, ifs);
4904 			}
4905 		}
4906 
4907 		for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) {
4908 			nv = (v == 0) ? (int)n->in_v : v;
4909 			if ((int)n->in_v != nv)
4910 				continue;
4911 			if (n->in_ifps[0] == ifp ||
4912 			    n->in_ifps[0] == (void *)-1) {
4913 				n->in_ifps[0] =
4914 				    fr_resolvenic(n->in_ifnames[0], nv, ifs);
4915 			}
4916 			if (n->in_ifps[1] == ifp ||
4917 			    n->in_ifps[1] == (void *)-1) {
4918 				n->in_ifps[1] =
4919 				    fr_resolvenic(n->in_ifnames[1], nv, ifs);
4920 			}
4921 		}
4922 		break;
4923 	case IPFSYNC_NEWIFP :
4924 		for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) {
4925 			if (nat->nat_v != v)
4926 				continue;
4927 			if (!strncmp(name, nat->nat_ifnames[0],
4928 				     sizeof(nat->nat_ifnames[0])))
4929 				nat->nat_ifps[0] = ifp;
4930 			if (!strncmp(name, nat->nat_ifnames[1],
4931 				     sizeof(nat->nat_ifnames[1])))
4932 				nat->nat_ifps[1] = ifp;
4933 		}
4934 		for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) {
4935 			if ((int)n->in_v != v)
4936 				continue;
4937 			if (!strncmp(name, n->in_ifnames[0],
4938 				     sizeof(n->in_ifnames[0])))
4939 				n->in_ifps[0] = ifp;
4940 			if (!strncmp(name, n->in_ifnames[1],
4941 				     sizeof(n->in_ifnames[1])))
4942 				n->in_ifps[1] = ifp;
4943 		}
4944 		break;
4945 	case IPFSYNC_OLDIFP :
4946 		for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) {
4947 			if (nat->nat_v != v)
4948 				continue;
4949 			if (ifp == nat->nat_ifps[0])
4950 				nat->nat_ifps[0] = (void *)-1;
4951 			if (ifp == nat->nat_ifps[1])
4952 				nat->nat_ifps[1] = (void *)-1;
4953 		}
4954 		for (n = ifs->ifs_nat_list; (n != NULL); n = n->in_next) {
4955 			if ((int)n->in_v != v)
4956 				continue;
4957 			if (n->in_ifps[0] == ifp)
4958 				n->in_ifps[0] = (void *)-1;
4959 			if (n->in_ifps[1] == ifp)
4960 				n->in_ifps[1] = (void *)-1;
4961 		}
4962 		break;
4963 	}
4964 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
4965 	SPL_X(s);
4966 }
4967 
4968 #if SOLARIS2 >= 10
4969 /* ------------------------------------------------------------------------ */
4970 /* Function:	fr_natifindexsync					    */
4971 /* Returns:	void							    */
4972 /* Parameters:	ifp	  - interface, which is being sync'd		    */
4973 /*		newifp	  - new ifindex value for interface		    */
4974 /*              ifs	  - IPF's stack					    */
4975 /*                                                                          */
4976 /* Write Locks: assumes ipf_mutex is locked				    */
4977 /*                                                                          */
4978 /* Updates all interface index references in NAT rules and NAT entries.	    */
4979 /* the index, which is about to be updated must match ifp value.	    */
4980 /* ------------------------------------------------------------------------ */
4981 void fr_natifindexsync(ifp, newifp, ifs)
4982 void *ifp;
4983 void *newifp;
4984 ipf_stack_t *ifs;
4985 {
4986 	nat_t *nat;
4987 	ipnat_t *n;
4988 
4989 	WRITE_ENTER(&ifs->ifs_ipf_nat);
4990 
4991 	for (nat = ifs->ifs_nat_instances; nat != NULL; nat = nat->nat_next) {
4992 		if (ifp == nat->nat_ifps[0])
4993 			nat->nat_ifps[0] = newifp;
4994 
4995 		if (ifp == nat->nat_ifps[1])
4996 			nat->nat_ifps[1] = newifp;
4997 	}
4998 
4999 	for (n = ifs->ifs_nat_list; n != NULL; n = n->in_next) {
5000 		if (ifp == n->in_ifps[0])
5001 			n->in_ifps[0] = newifp;
5002 
5003 		if (ifp == n->in_ifps[1])
5004 			n->in_ifps[1] = newifp;
5005 	}
5006 
5007 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
5008 }
5009 #endif
5010 
5011 /* ------------------------------------------------------------------------ */
5012 /* Function:    nat_icmpquerytype4                                          */
5013 /* Returns:     int - 1 == success, 0 == failure                            */
5014 /* Parameters:  icmptype(I) - ICMP type number                              */
5015 /*                                                                          */
5016 /* Tests to see if the ICMP type number passed is a query/response type or  */
5017 /* not.                                                                     */
5018 /* ------------------------------------------------------------------------ */
5019 static INLINE int nat_icmpquerytype4(icmptype)
5020 int icmptype;
5021 {
5022 
5023 	/*
5024 	 * For the ICMP query NAT code, it is essential that both the query
5025 	 * and the reply match on the NAT rule. Because the NAT structure
5026 	 * does not keep track of the icmptype, and a single NAT structure
5027 	 * is used for all icmp types with the same src, dest and id, we
5028 	 * simply define the replies as queries as well. The funny thing is,
5029 	 * altough it seems silly to call a reply a query, this is exactly
5030 	 * as it is defined in the IPv4 specification
5031 	 */
5032 
5033 	switch (icmptype)
5034 	{
5035 
5036 	case ICMP_ECHOREPLY:
5037 	case ICMP_ECHO:
5038 	/* route aedvertisement/solliciation is currently unsupported: */
5039 	/* it would require rewriting the ICMP data section            */
5040 	case ICMP_TSTAMP:
5041 	case ICMP_TSTAMPREPLY:
5042 	case ICMP_IREQ:
5043 	case ICMP_IREQREPLY:
5044 	case ICMP_MASKREQ:
5045 	case ICMP_MASKREPLY:
5046 		return 1;
5047 	default:
5048 		return 0;
5049 	}
5050 }
5051 
5052 
5053 /* ------------------------------------------------------------------------ */
5054 /* Function:    nat_log                                                     */
5055 /* Returns:     Nil                                                         */
5056 /* Parameters:  nat(I)  - pointer to NAT structure                          */
5057 /*              type(I) - type of log entry to create                       */
5058 /*                                                                          */
5059 /* Creates a NAT log entry.                                                 */
5060 /* ------------------------------------------------------------------------ */
5061 void nat_log(nat, type, ifs)
5062 struct nat *nat;
5063 u_int type;
5064 ipf_stack_t *ifs;
5065 {
5066 #ifdef	IPFILTER_LOG
5067 # ifndef LARGE_NAT
5068 	struct ipnat *np;
5069 	int rulen;
5070 # endif
5071 	struct natlog natl;
5072 	void *items[1];
5073 	size_t sizes[1];
5074 	int types[1];
5075 
5076 	natl.nlg_inip = nat->nat_inip6;
5077 	natl.nlg_outip = nat->nat_outip6;
5078 	natl.nlg_origip = nat->nat_oip6;
5079 	natl.nlg_bytes[0] = nat->nat_bytes[0];
5080 	natl.nlg_bytes[1] = nat->nat_bytes[1];
5081 	natl.nlg_pkts[0] = nat->nat_pkts[0];
5082 	natl.nlg_pkts[1] = nat->nat_pkts[1];
5083 	natl.nlg_origport = nat->nat_oport;
5084 	natl.nlg_inport = nat->nat_inport;
5085 	natl.nlg_outport = nat->nat_outport;
5086 	natl.nlg_p = nat->nat_p;
5087 	natl.nlg_type = type;
5088 	natl.nlg_rule = -1;
5089 	natl.nlg_v = nat->nat_v;
5090 # ifndef LARGE_NAT
5091 	if (nat->nat_ptr != NULL) {
5092 		for (rulen = 0, np = ifs->ifs_nat_list; np;
5093 		     np = np->in_next, rulen++)
5094 			if (np == nat->nat_ptr) {
5095 				natl.nlg_rule = rulen;
5096 				break;
5097 			}
5098 	}
5099 # endif
5100 	items[0] = &natl;
5101 	sizes[0] = sizeof(natl);
5102 	types[0] = 0;
5103 
5104 	(void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1, ifs);
5105 #endif
5106 }
5107 
5108 
5109 #if defined(__OpenBSD__)
5110 /* ------------------------------------------------------------------------ */
5111 /* Function:    nat_ifdetach                                                */
5112 /* Returns:     Nil                                                         */
5113 /* Parameters:  ifp(I) - pointer to network interface                       */
5114 /*                                                                          */
5115 /* Compatibility interface for OpenBSD to trigger the correct updating of   */
5116 /* interface references within IPFilter.                                    */
5117 /* ------------------------------------------------------------------------ */
5118 void nat_ifdetach(ifp, ifs)
5119 void *ifp;
5120 ipf_stack_t *ifs;
5121 {
5122 	frsync(ifp, ifs);
5123 	return;
5124 }
5125 #endif
5126 
5127 
5128 /* ------------------------------------------------------------------------ */
5129 /* Function:    fr_ipnatderef                                               */
5130 /* Returns:     Nil                                                         */
5131 /* Parameters:  inp(I) - pointer to pointer to NAT rule                     */
5132 /* Write Locks: ipf_nat                                                     */
5133 /*                                                                          */
5134 /* ------------------------------------------------------------------------ */
5135 void fr_ipnatderef(inp, ifs)
5136 ipnat_t **inp;
5137 ipf_stack_t *ifs;
5138 {
5139 	ipnat_t *in;
5140 
5141 	in = *inp;
5142 	*inp = NULL;
5143 	in->in_use--;
5144 	if (in->in_use == 0 && (in->in_flags & IPN_DELETE)) {
5145 		if (in->in_apr)
5146 			appr_free(in->in_apr);
5147 		KFREE(in);
5148 		ifs->ifs_nat_stats.ns_rules--;
5149 #ifdef notdef
5150 #if SOLARIS
5151 		if (ifs->ifs_nat_stats.ns_rules == 0)
5152 			ifs->ifs_pfil_delayed_copy = 1;
5153 #endif
5154 #endif
5155 	}
5156 }
5157 
5158 
5159 /* ------------------------------------------------------------------------ */
5160 /* Function:    fr_natderef                                                 */
5161 /* Returns:     Nil                                                         */
5162 /* Parameters:  natp - pointer to pointer to NAT table entry                */
5163 /*              ifs  - ipf stack instance                                   */
5164 /*                                                                          */
5165 /* Decrement the reference counter for this NAT table entry and free it if  */
5166 /* there are no more things using it.                                       */
5167 /*                                                                          */
5168 /* IF nat_ref == 1 when this function is called, then we have an orphan nat */
5169 /* structure *because* it only gets called on paths _after_ nat_ref has been*/
5170 /* incremented.  If nat_ref == 1 then we shouldn't decrement it here        */
5171 /* because nat_delete() will do that and send nat_ref to -1.                */
5172 /*                                                                          */
5173 /* Holding the lock on nat_lock is required to serialise nat_delete() being */
5174 /* called from a NAT flush ioctl with a deref happening because of a packet.*/
5175 /* ------------------------------------------------------------------------ */
5176 void fr_natderef(natp, ifs)
5177 nat_t **natp;
5178 ipf_stack_t *ifs;
5179 {
5180 	nat_t *nat;
5181 
5182 	nat = *natp;
5183 	*natp = NULL;
5184 
5185 	MUTEX_ENTER(&nat->nat_lock);
5186 	if (nat->nat_ref > 1) {
5187 		nat->nat_ref--;
5188 		MUTEX_EXIT(&nat->nat_lock);
5189 		return;
5190 	}
5191 	MUTEX_EXIT(&nat->nat_lock);
5192 
5193 	WRITE_ENTER(&ifs->ifs_ipf_nat);
5194 	(void) nat_delete(nat, NL_EXPIRE, ifs);
5195 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
5196 }
5197 
5198 
5199 /* ------------------------------------------------------------------------ */
5200 /* Function:    fr_natclone                                                 */
5201 /* Returns:     ipstate_t* - NULL == cloning failed,                        */
5202 /*                           else pointer to new NAT structure              */
5203 /* Parameters:  fin(I)   - pointer to packet information                    */
5204 /*              nat(I)   - pointer to master NAT structure                  */
5205 /* Write Lock:  ipf_nat                                                     */
5206 /*                                                                          */
5207 /* Create a "duplicate" NAT table entry from the master.                    */
5208 /* ------------------------------------------------------------------------ */
5209 nat_t *fr_natclone(fin, nat)
5210 fr_info_t *fin;
5211 nat_t *nat;
5212 {
5213 	frentry_t *fr;
5214 	nat_t *clone;
5215 	ipnat_t *np;
5216 	ipf_stack_t *ifs = fin->fin_ifs;
5217 
5218 	/*
5219 	 * Trigger automatic call to nat_flushtable() if the
5220 	 * table has reached capcity specified by hi watermark.
5221 	 */
5222 	if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_level_hi)
5223 		ifs->ifs_nat_doflush = 1;
5224 
5225 	/*
5226 	 * If automatic flushing did not do its job, and the table
5227 	 * has filled up, don't try to create a new entry.
5228 	 */
5229 	if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) {
5230 		ifs->ifs_nat_stats.ns_memfail++;
5231 		return NULL;
5232 	}
5233 
5234 	KMALLOC(clone, nat_t *);
5235 	if (clone == NULL)
5236 		return NULL;
5237 	bcopy((char *)nat, (char *)clone, sizeof(*clone));
5238 
5239 	MUTEX_NUKE(&clone->nat_lock);
5240 
5241 	clone->nat_aps = NULL;
5242 	/*
5243 	 * Initialize all these so that nat_delete() doesn't cause a crash.
5244 	 */
5245 	clone->nat_tqe.tqe_pnext = NULL;
5246 	clone->nat_tqe.tqe_next = NULL;
5247 	clone->nat_tqe.tqe_ifq = NULL;
5248 	clone->nat_tqe.tqe_parent = clone;
5249 
5250 	clone->nat_flags &= ~SI_CLONE;
5251 	clone->nat_flags |= SI_CLONED;
5252 
5253 	if (clone->nat_hm)
5254 		clone->nat_hm->hm_ref++;
5255 
5256 	if (nat_insert(clone, fin->fin_rev, ifs) == -1) {
5257 		KFREE(clone);
5258 		return NULL;
5259 	}
5260 	np = clone->nat_ptr;
5261 	if (np != NULL) {
5262 		if (ifs->ifs_nat_logging)
5263 			nat_log(clone, (u_int)np->in_redir, ifs);
5264 		np->in_use++;
5265 	}
5266 	fr = clone->nat_fr;
5267 	if (fr != NULL) {
5268 		MUTEX_ENTER(&fr->fr_lock);
5269 		fr->fr_ref++;
5270 		MUTEX_EXIT(&fr->fr_lock);
5271 	}
5272 
5273 	/*
5274 	 * Because the clone is created outside the normal loop of things and
5275 	 * TCP has special needs in terms of state, initialise the timeout
5276 	 * state of the new NAT from here.
5277 	 */
5278 	if (clone->nat_p == IPPROTO_TCP) {
5279 		(void) fr_tcp_age(&clone->nat_tqe, fin, ifs->ifs_nat_tqb,
5280 				  clone->nat_flags);
5281 	}
5282 #ifdef	IPFILTER_SYNC
5283 	clone->nat_sync = ipfsync_new(SMC_NAT, fin, clone);
5284 #endif
5285 	if (ifs->ifs_nat_logging)
5286 		nat_log(clone, NL_CLONE, ifs);
5287 	return clone;
5288 }
5289 
5290 
5291 /* ------------------------------------------------------------------------ */
5292 /* Function:   nat_wildok                                                   */
5293 /* Returns:    int - 1 == packet's ports match wildcards                    */
5294 /*                   0 == packet's ports don't match wildcards              */
5295 /* Parameters: nat(I)   - NAT entry                                         */
5296 /*             sport(I) - source port                                       */
5297 /*             dport(I) - destination port                                  */
5298 /*             flags(I) - wildcard flags                                    */
5299 /*             dir(I)   - packet direction                                  */
5300 /*                                                                          */
5301 /* Use NAT entry and packet direction to determine which combination of     */
5302 /* wildcard flags should be used.                                           */
5303 /* ------------------------------------------------------------------------ */
5304 int nat_wildok(nat, sport, dport, flags, dir)
5305 nat_t *nat;
5306 int sport;
5307 int dport;
5308 int flags;
5309 int dir;
5310 {
5311 	/*
5312 	 * When called by       dir is set to
5313 	 * nat_inlookup         NAT_INBOUND (0)
5314 	 * nat_outlookup        NAT_OUTBOUND (1)
5315 	 *
5316 	 * We simply combine the packet's direction in dir with the original
5317 	 * "intended" direction of that NAT entry in nat->nat_dir to decide
5318 	 * which combination of wildcard flags to allow.
5319 	 */
5320 
5321 	switch ((dir << 1) | nat->nat_dir)
5322 	{
5323 	case 3: /* outbound packet / outbound entry */
5324 		if (((nat->nat_inport == sport) ||
5325 		    (flags & SI_W_SPORT)) &&
5326 		    ((nat->nat_oport == dport) ||
5327 		    (flags & SI_W_DPORT)))
5328 			return 1;
5329 		break;
5330 	case 2: /* outbound packet / inbound entry */
5331 		if (((nat->nat_outport == sport) ||
5332 		    (flags & SI_W_DPORT)) &&
5333 		    ((nat->nat_oport == dport) ||
5334 		    (flags & SI_W_SPORT)))
5335 			return 1;
5336 		break;
5337 	case 1: /* inbound packet / outbound entry */
5338 		if (((nat->nat_oport == sport) ||
5339 		    (flags & SI_W_DPORT)) &&
5340 		    ((nat->nat_outport == dport) ||
5341 		    (flags & SI_W_SPORT)))
5342 			return 1;
5343 		break;
5344 	case 0: /* inbound packet / inbound entry */
5345 		if (((nat->nat_oport == sport) ||
5346 		    (flags & SI_W_SPORT)) &&
5347 		    ((nat->nat_outport == dport) ||
5348 		    (flags & SI_W_DPORT)))
5349 			return 1;
5350 		break;
5351 	default:
5352 		break;
5353 	}
5354 
5355 	return(0);
5356 }
5357 
5358 
5359 /* ------------------------------------------------------------------------ */
5360 /* Function:    nat_mssclamp                                                */
5361 /* Returns:     Nil                                                         */
5362 /* Parameters:  tcp(I)    - pointer to TCP header                           */
5363 /*              maxmss(I) - value to clamp the TCP MSS to                   */
5364 /*              csump(I)  - pointer to TCP checksum                         */
5365 /*                                                                          */
5366 /* Check for MSS option and clamp it if necessary.  If found and changed,   */
5367 /* then the TCP header checksum will be updated to reflect the change in    */
5368 /* the MSS.                                                                 */
5369 /* ------------------------------------------------------------------------ */
5370 static void nat_mssclamp(tcp, maxmss, csump)
5371 tcphdr_t *tcp;
5372 u_32_t maxmss;
5373 u_short *csump;
5374 {
5375 	u_char *cp, *ep, opt;
5376 	int hlen, advance;
5377 	u_32_t mss, sumd;
5378 
5379 	hlen = TCP_OFF(tcp) << 2;
5380 	if (hlen > sizeof(*tcp)) {
5381 		cp = (u_char *)tcp + sizeof(*tcp);
5382 		ep = (u_char *)tcp + hlen;
5383 
5384 		while (cp < ep) {
5385 			opt = cp[0];
5386 			if (opt == TCPOPT_EOL)
5387 				break;
5388 			else if (opt == TCPOPT_NOP) {
5389 				cp++;
5390 				continue;
5391 			}
5392 
5393 			if (cp + 1 >= ep)
5394 				break;
5395 			advance = cp[1];
5396 			if ((cp + advance > ep) || (advance <= 0))
5397 				break;
5398 			switch (opt)
5399 			{
5400 			case TCPOPT_MAXSEG:
5401 				if (advance != 4)
5402 					break;
5403 				mss = cp[2] * 256 + cp[3];
5404 				if (mss > maxmss) {
5405 					cp[2] = maxmss / 256;
5406 					cp[3] = maxmss & 0xff;
5407 					CALC_SUMD(mss, maxmss, sumd);
5408 					fix_outcksum(csump, sumd);
5409 				}
5410 				break;
5411 			default:
5412 				/* ignore unknown options */
5413 				break;
5414 			}
5415 
5416 			cp += advance;
5417 		}
5418 	}
5419 }
5420 
5421 
5422 /* ------------------------------------------------------------------------ */
5423 /* Function:    fr_setnatqueue                                              */
5424 /* Returns:     Nil                                                         */
5425 /* Parameters:  nat(I)- pointer to NAT structure                            */
5426 /*              rev(I) - forward(0) or reverse(1) direction                 */
5427 /* Locks:       ipf_nat (read or write)                                     */
5428 /*                                                                          */
5429 /* Put the NAT entry on its default queue entry, using rev as a helped in   */
5430 /* determining which queue it should be placed on.                          */
5431 /* ------------------------------------------------------------------------ */
5432 void fr_setnatqueue(nat, rev, ifs)
5433 nat_t *nat;
5434 int rev;
5435 ipf_stack_t *ifs;
5436 {
5437 	ipftq_t *oifq, *nifq;
5438 
5439 	if (nat->nat_ptr != NULL)
5440 		nifq = nat->nat_ptr->in_tqehead[rev];
5441 	else
5442 		nifq = NULL;
5443 
5444 	if (nifq == NULL) {
5445 		switch (nat->nat_p)
5446 		{
5447 		case IPPROTO_UDP :
5448 			nifq = &ifs->ifs_nat_udptq;
5449 			break;
5450 		case IPPROTO_ICMP :
5451 			nifq = &ifs->ifs_nat_icmptq;
5452 			break;
5453 		case IPPROTO_TCP :
5454 			nifq = ifs->ifs_nat_tqb + nat->nat_tqe.tqe_state[rev];
5455 			break;
5456 		default :
5457 			nifq = &ifs->ifs_nat_iptq;
5458 			break;
5459 		}
5460 	}
5461 
5462 	oifq = nat->nat_tqe.tqe_ifq;
5463 	/*
5464 	 * If it's currently on a timeout queue, move it from one queue to
5465 	 * another, else put it on the end of the newly determined queue.
5466 	 */
5467 	if (oifq != NULL)
5468 		fr_movequeue(&nat->nat_tqe, oifq, nifq, ifs);
5469 	else
5470 		fr_queueappend(&nat->nat_tqe, nifq, nat, ifs);
5471 	return;
5472 }
5473 
5474 /* ------------------------------------------------------------------------ */
5475 /* Function:    nat_getnext                                                 */
5476 /* Returns:     int - 0 == ok, else error                                   */
5477 /* Parameters:  t(I)   - pointer to ipftoken structure                      */
5478 /*              itp(I) - pointer to ipfgeniter_t structure                  */
5479 /*              ifs - ipf stack instance                                    */
5480 /*                                                                          */
5481 /* Fetch the next nat/ipnat/hostmap structure pointer from the linked list  */
5482 /* and copy it out to the storage space pointed to by itp.  The next item   */
5483 /* in the list to look at is put back in the ipftoken struture.             */
5484 /* ------------------------------------------------------------------------ */
5485 static int nat_getnext(t, itp, ifs)
5486 ipftoken_t *t;
5487 ipfgeniter_t *itp;
5488 ipf_stack_t *ifs;
5489 {
5490 	hostmap_t *hm, *nexthm = NULL, zerohm;
5491 	ipnat_t *ipn, *nextipnat = NULL, zeroipn;
5492 	nat_t *nat, *nextnat = NULL, zeronat;
5493 	int error = 0, count;
5494 	char *dst;
5495 
5496 	if (itp->igi_nitems == 0)
5497 		return EINVAL;
5498 
5499 	READ_ENTER(&ifs->ifs_ipf_nat);
5500 
5501 	/*
5502 	 * Get "previous" entry from the token and find the next entry.
5503 	 */
5504 	switch (itp->igi_type)
5505 	{
5506 	case IPFGENITER_HOSTMAP :
5507 		hm = t->ipt_data;
5508 		if (hm == NULL) {
5509 			nexthm = ifs->ifs_ipf_hm_maplist;
5510 		} else {
5511 			nexthm = hm->hm_next;
5512 		}
5513 		break;
5514 
5515 	case IPFGENITER_IPNAT :
5516 		ipn = t->ipt_data;
5517 		if (ipn == NULL) {
5518 			nextipnat = ifs->ifs_nat_list;
5519 		} else {
5520 			nextipnat = ipn->in_next;
5521 		}
5522 		break;
5523 
5524 	case IPFGENITER_NAT :
5525 		nat = t->ipt_data;
5526 		if (nat == NULL) {
5527 			nextnat = ifs->ifs_nat_instances;
5528 		} else {
5529 			nextnat = nat->nat_next;
5530 		}
5531 		break;
5532 	default :
5533 		RWLOCK_EXIT(&ifs->ifs_ipf_nat);
5534 		return EINVAL;
5535 	}
5536 
5537 	dst = itp->igi_data;
5538 	for (count = itp->igi_nitems; count > 0; count--) {
5539 		/*
5540 		 * If we found an entry, add a reference to it and update the token.
5541 		 * Otherwise, zero out data to be returned and NULL out token.
5542 		 */
5543 		switch (itp->igi_type)
5544 		{
5545 		case IPFGENITER_HOSTMAP :
5546 			if (nexthm != NULL) {
5547 				ATOMIC_INC32(nexthm->hm_ref);
5548 				t->ipt_data = nexthm;
5549 			} else {
5550 				bzero(&zerohm, sizeof(zerohm));
5551 				nexthm = &zerohm;
5552 				t->ipt_data = NULL;
5553 			}
5554 			break;
5555 		case IPFGENITER_IPNAT :
5556 			if (nextipnat != NULL) {
5557 				ATOMIC_INC32(nextipnat->in_use);
5558 				t->ipt_data = nextipnat;
5559 			} else {
5560 				bzero(&zeroipn, sizeof(zeroipn));
5561 				nextipnat = &zeroipn;
5562 				t->ipt_data = NULL;
5563 			}
5564 			break;
5565 		case IPFGENITER_NAT :
5566 			if (nextnat != NULL) {
5567 				MUTEX_ENTER(&nextnat->nat_lock);
5568 				nextnat->nat_ref++;
5569 				MUTEX_EXIT(&nextnat->nat_lock);
5570 				t->ipt_data = nextnat;
5571 			} else {
5572 				bzero(&zeronat, sizeof(zeronat));
5573 				nextnat = &zeronat;
5574 				t->ipt_data = NULL;
5575 			}
5576 			break;
5577 		default :
5578 			break;
5579 		}
5580 
5581 		/*
5582 		 * Now that we have ref, it's save to give up lock.
5583 		 */
5584 		RWLOCK_EXIT(&ifs->ifs_ipf_nat);
5585 
5586 		/*
5587 		 * Copy out data and clean up references and token as needed.
5588 		 */
5589 		switch (itp->igi_type)
5590 		{
5591 		case IPFGENITER_HOSTMAP :
5592 			error = COPYOUT(nexthm, dst, sizeof(*nexthm));
5593 			if (error != 0)
5594 				error = EFAULT;
5595 			if (t->ipt_data == NULL) {
5596 				ipf_freetoken(t, ifs);
5597 				break;
5598 			} else {
5599 				if (hm != NULL) {
5600 					WRITE_ENTER(&ifs->ifs_ipf_nat);
5601 					fr_hostmapdel(&hm);
5602 					RWLOCK_EXIT(&ifs->ifs_ipf_nat);
5603 				}
5604 				if (nexthm->hm_next == NULL) {
5605 					ipf_freetoken(t, ifs);
5606 					break;
5607 				}
5608 				dst += sizeof(*nexthm);
5609 				hm = nexthm;
5610 				nexthm = nexthm->hm_next;
5611 			}
5612 			break;
5613 
5614 		case IPFGENITER_IPNAT :
5615 			error = COPYOUT(nextipnat, dst, sizeof(*nextipnat));
5616 			if (error != 0)
5617 				error = EFAULT;
5618 			if (t->ipt_data == NULL) {
5619 				ipf_freetoken(t, ifs);
5620 				break;
5621 			} else {
5622 				if (ipn != NULL) {
5623 					WRITE_ENTER(&ifs->ifs_ipf_nat);
5624 					fr_ipnatderef(&ipn, ifs);
5625 					RWLOCK_EXIT(&ifs->ifs_ipf_nat);
5626 				}
5627 				if (nextipnat->in_next == NULL) {
5628 					ipf_freetoken(t, ifs);
5629 					break;
5630 				}
5631 				dst += sizeof(*nextipnat);
5632 				ipn = nextipnat;
5633 				nextipnat = nextipnat->in_next;
5634 			}
5635 			break;
5636 
5637 		case IPFGENITER_NAT :
5638 			error = COPYOUT(nextnat, dst, sizeof(*nextnat));
5639 			if (error != 0)
5640 				error = EFAULT;
5641 			if (t->ipt_data == NULL) {
5642 				ipf_freetoken(t, ifs);
5643 				break;
5644 			} else {
5645 				if (nat != NULL)
5646 					fr_natderef(&nat, ifs);
5647 				if (nextnat->nat_next == NULL) {
5648 					ipf_freetoken(t, ifs);
5649 					break;
5650 				}
5651 				dst += sizeof(*nextnat);
5652 				nat = nextnat;
5653 				nextnat = nextnat->nat_next;
5654 			}
5655 			break;
5656 		default :
5657 			break;
5658 		}
5659 
5660 		if ((count == 1) || (error != 0))
5661 			break;
5662 
5663 		READ_ENTER(&ifs->ifs_ipf_nat);
5664 	}
5665 
5666 	return error;
5667 }
5668 
5669 
5670 /* ------------------------------------------------------------------------ */
5671 /* Function:    nat_iterator                                                */
5672 /* Returns:     int - 0 == ok, else error                                   */
5673 /* Parameters:  token(I) - pointer to ipftoken structure                    */
5674 /*              itp(I) - pointer to ipfgeniter_t structure                  */
5675 /*                                                                          */
5676 /* This function acts as a handler for the SIOCGENITER ioctls that use a    */
5677 /* generic structure to iterate through a list.  There are three different  */
5678 /* linked lists of NAT related information to go through: NAT rules, active */
5679 /* NAT mappings and the NAT fragment cache.                                 */
5680 /* ------------------------------------------------------------------------ */
5681 static int nat_iterator(token, itp, ifs)
5682 ipftoken_t *token;
5683 ipfgeniter_t *itp;
5684 ipf_stack_t *ifs;
5685 {
5686 	int error;
5687 
5688 	if (itp->igi_data == NULL)
5689 		return EFAULT;
5690 
5691 	token->ipt_subtype = itp->igi_type;
5692 
5693 	switch (itp->igi_type)
5694 	{
5695 	case IPFGENITER_HOSTMAP :
5696 	case IPFGENITER_IPNAT :
5697 	case IPFGENITER_NAT :
5698 		error = nat_getnext(token, itp, ifs);
5699 		break;
5700 	case IPFGENITER_NATFRAG :
5701 		error = fr_nextfrag(token, itp, &ifs->ifs_ipfr_natlist,
5702 				    &ifs->ifs_ipfr_nattail,
5703 				    &ifs->ifs_ipf_natfrag, ifs);
5704 		break;
5705 	default :
5706 		error = EINVAL;
5707 		break;
5708 	}
5709 
5710 	return error;
5711 }
5712 
5713 
5714 /* ---------------------------------------------------------------------- */
5715 /* Function:    nat_flushtable						  */
5716 /* Returns:     int - 0 == success, -1 == failure			  */
5717 /* Parameters:  flush_option - how to flush the active NAT table	  */
5718 /*              ifs - ipf stack instance				  */
5719 /* Write Locks: ipf_nat							  */
5720 /*									  */
5721 /* Flush NAT tables.  Three actions currently defined:                    */
5722 /*									  */
5723 /* FLUSH_TABLE_ALL	: Flush all NAT table entries			  */
5724 /*									  */
5725 /* FLUSH_TABLE_CLOSING	: Flush entries with TCP connections which	  */
5726 /*			  have started to close on both ends using	  */
5727 /*			  ipf_flushclosing().				  */
5728 /*									  */
5729 /* FLUSH_TABLE_EXTRA	: First, flush entries which are "almost" closed. */
5730 /*			  Then, if needed, flush entries with TCP	  */
5731 /*			  connections which have been idle for a long	  */
5732 /*			  time with ipf_extraflush().			  */
5733 /* ---------------------------------------------------------------------- */
5734 static int nat_flushtable(flush_option, ifs)
5735 int flush_option;
5736 ipf_stack_t *ifs;
5737 {
5738         nat_t *nat, *natn;
5739         int removed;
5740         SPL_INT(s);
5741 
5742         removed = 0;
5743 
5744         SPL_NET(s);
5745         switch (flush_option)
5746         {
5747         case FLUSH_TABLE_ALL:
5748 		natn = ifs->ifs_nat_instances;
5749 		while ((nat = natn) != NULL) {
5750 			natn = nat->nat_next;
5751 			if (nat_delete(nat, NL_FLUSH, ifs) == 0)
5752 				removed++;
5753 		}
5754                 break;
5755 
5756         case FLUSH_TABLE_CLOSING:
5757                 removed = ipf_flushclosing(NAT_FLUSH,
5758 					   IPF_TCPS_CLOSE_WAIT,
5759 					   ifs->ifs_nat_tqb,
5760 					   ifs->ifs_nat_utqe,
5761 					   ifs);
5762                 break;
5763 
5764         case FLUSH_TABLE_EXTRA:
5765                 removed = ipf_flushclosing(NAT_FLUSH,
5766 					   IPF_TCPS_FIN_WAIT_2,
5767 					   ifs->ifs_nat_tqb,
5768 					   ifs->ifs_nat_utqe,
5769 					   ifs);
5770 
5771                 /*
5772                  * Be sure we haven't done this in the last 10 seconds.
5773                  */
5774                 if (ifs->ifs_fr_ticks - ifs->ifs_nat_last_force_flush <
5775                     IPF_TTLVAL(10))
5776                         break;
5777                 ifs->ifs_nat_last_force_flush = ifs->ifs_fr_ticks;
5778                 removed += ipf_extraflush(NAT_FLUSH,
5779 					  &ifs->ifs_nat_tqb[IPF_TCPS_ESTABLISHED],
5780 					  ifs->ifs_nat_utqe,
5781 					  ifs);
5782                 break;
5783 
5784         default: /* Flush Nothing */
5785                 break;
5786         }
5787 
5788         SPL_X(s);
5789         return (removed);
5790 }
5791 
5792 
5793 /* ------------------------------------------------------------------------ */
5794 /* Function:    nat_uncreate                                                */
5795 /* Returns:     Nil                                                         */
5796 /* Parameters:  fin(I) - pointer to packet information                      */
5797 /*                                                                          */
5798 /* This function is used to remove a NAT entry from the NAT table when we   */
5799 /* decide that the create was actually in error. It is thus assumed that    */
5800 /* fin_flx will have both FI_NATED and FI_NATNEW set. Because we're dealing */
5801 /* with the translated packet (not the original), we have to reverse the    */
5802 /* lookup. Although doing the lookup is expensive (relatively speaking), it */
5803 /* is not anticipated that this will be a frequent occurance for normal     */
5804 /* traffic patterns.                                                        */
5805 /* ------------------------------------------------------------------------ */
5806 void nat_uncreate(fin)
5807 fr_info_t *fin;
5808 {
5809 	ipf_stack_t *ifs = fin->fin_ifs;
5810 	int nflags;
5811 	nat_t *nat;
5812 
5813 	switch (fin->fin_p)
5814 	{
5815 	case IPPROTO_TCP :
5816 		nflags = IPN_TCP;
5817 		break;
5818 	case IPPROTO_UDP :
5819 		nflags = IPN_UDP;
5820 		break;
5821 	default :
5822 		nflags = 0;
5823 		break;
5824 	}
5825 
5826 	WRITE_ENTER(&ifs->ifs_ipf_nat);
5827 
5828 	if (fin->fin_out == 0) {
5829 		nat = nat_outlookup(fin, nflags, (u_int)fin->fin_p,
5830 				    fin->fin_dst, fin->fin_src);
5831 	} else {
5832 		nat = nat_inlookup(fin, nflags, (u_int)fin->fin_p,
5833 				   fin->fin_src, fin->fin_dst);
5834 	}
5835 
5836 	if (nat != NULL) {
5837 		ifs->ifs_nat_stats.ns_uncreate[fin->fin_out][0]++;
5838 		(void) nat_delete(nat, NL_DESTROY, ifs);
5839 	} else {
5840 		ifs->ifs_nat_stats.ns_uncreate[fin->fin_out][1]++;
5841 	}
5842 
5843 	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
5844 }
5845