1 /*	$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_nat.c 344113 2019-02-14 00:52:03Z cy $	*/
2 
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #if defined(KERNEL) || defined(_KERNEL)
9 # undef KERNEL
10 # undef _KERNEL
11 # define        KERNEL	1
12 # define        _KERNEL	1
13 #endif
14 #include <sys/errno.h>
15 #include <sys/types.h>
16 #include <sys/param.h>
17 #include <sys/time.h>
18 #include <sys/file.h>
19 #if defined(_KERNEL) && \
20     (defined(__NetBSD_Version) && (__NetBSD_Version >= 399002000))
21 # include <sys/kauth.h>
22 #endif
23 #if !defined(_KERNEL)
24 # include <stdio.h>
25 # include <string.h>
26 # include <stdlib.h>
27 # define KERNEL
28 # ifdef _OpenBSD__
29 struct file;
30 # endif
31 # include <sys/uio.h>
32 # undef KERNEL
33 #endif
34 #if defined(_KERNEL) && \
35     defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
36 # include <sys/filio.h>
37 # include <sys/fcntl.h>
38 #else
39 # include <sys/ioctl.h>
40 #endif
41 #if !defined(AIX)
42 # include <sys/fcntl.h>
43 #endif
44 #if !defined(linux)
45 # include <sys/protosw.h>
46 #endif
47 #include <sys/socket.h>
48 #if defined(_KERNEL)
49 # include <sys/systm.h>
50 # if !defined(__SVR4) && !defined(__svr4__)
51 #  include <sys/mbuf.h>
52 # endif
53 #endif
54 #if defined(__SVR4) || defined(__svr4__)
55 # include <sys/filio.h>
56 # include <sys/byteorder.h>
57 # ifdef KERNEL
58 #  include <sys/dditypes.h>
59 # endif
60 # include <sys/stream.h>
61 # include <sys/kmem.h>
62 #endif
63 #if __FreeBSD_version >= 300000
64 # include <sys/queue.h>
65 #endif
66 #include <net/if.h>
67 #if __FreeBSD_version >= 300000
68 # include <net/if_var.h>
69 #endif
70 #ifdef sun
71 # include <net/af.h>
72 #endif
73 #include <netinet/in.h>
74 #include <netinet/in_systm.h>
75 #include <netinet/ip.h>
76 
77 #ifdef RFC1825
78 # include <vpn/md5.h>
79 # include <vpn/ipsec.h>
80 extern struct ifnet vpnif;
81 #endif
82 
83 #if !defined(linux)
84 # include <netinet/ip_var.h>
85 #endif
86 #include <netinet/tcp.h>
87 #include <netinet/udp.h>
88 #include <netinet/ip_icmp.h>
89 #include "netinet/ip_compat.h"
90 #include <netinet/tcpip.h>
91 #include "netinet/ipl.h"
92 #include "netinet/ip_fil.h"
93 #include "netinet/ip_nat.h"
94 #include "netinet/ip_frag.h"
95 #include "netinet/ip_state.h"
96 #include "netinet/ip_proxy.h"
97 #include "netinet/ip_lookup.h"
98 #include "netinet/ip_dstlist.h"
99 #include "netinet/ip_sync.h"
100 #if FREEBSD_GE_REV(300000)
101 # include <sys/malloc.h>
102 #endif
103 #ifdef HAS_SYS_MD5_H
104 # include <sys/md5.h>
105 #else
106 # include "md5.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[] = "@(#)$FreeBSD: stable/10/sys/contrib/ipfilter/netinet/ip_nat.c 344113 2019-02-14 00:52:03Z cy $";
116 /* static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.102 2007/10/16 10:08:10 darrenr Exp $"; */
117 #endif
118 
119 
120 #define	NATFSUM(n,v,f)	((v) == 4 ? (n)->f.in4.s_addr : (n)->f.i6[0] + \
121 			 (n)->f.i6[1] + (n)->f.i6[2] + (n)->f.i6[3])
122 #define	NBUMP(x)	softn->(x)++
123 #define	NBUMPD(x, y)	do { \
124 				softn->x.y++; \
125 				DT(y); \
126 			} while (0)
127 #define	NBUMPSIDE(y,x)	softn->ipf_nat_stats.ns_side[y].x++
128 #define	NBUMPSIDED(y,x)	do { softn->ipf_nat_stats.ns_side[y].x++; \
129 			     DT(x); } while (0)
130 #define	NBUMPSIDEX(y,x,z) \
131 			do { softn->ipf_nat_stats.ns_side[y].x++; \
132 			     DT(z); } while (0)
133 #define	NBUMPSIDEDF(y,x)do { softn->ipf_nat_stats.ns_side[y].x++; \
134 			     DT1(x, fr_info_t *, fin); } while (0)
135 
136 frentry_t	ipfnatblock;
137 
138 static ipftuneable_t ipf_nat_tuneables[] = {
139 	/* nat */
140 	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_lock) },
141 		"nat_lock",	0,	1,
142 		stsizeof(ipf_nat_softc_t, ipf_nat_lock),
143 		IPFT_RDONLY,		NULL,	NULL },
144 	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_sz) },
145 		"nat_table_size", 1,	0x7fffffff,
146 		stsizeof(ipf_nat_softc_t, ipf_nat_table_sz),
147 		0,			NULL,	ipf_nat_rehash },
148 	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_max) },
149 		"nat_table_max", 1,	0x7fffffff,
150 		stsizeof(ipf_nat_softc_t, ipf_nat_table_max),
151 		0,			NULL,	NULL },
152 	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maprules_sz) },
153 		"nat_rules_size", 1,	0x7fffffff,
154 		stsizeof(ipf_nat_softc_t, ipf_nat_maprules_sz),
155 		0,			NULL,	ipf_nat_rehash_rules },
156 	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_rdrrules_sz) },
157 		"rdr_rules_size", 1,	0x7fffffff,
158 		stsizeof(ipf_nat_softc_t, ipf_nat_rdrrules_sz),
159 		0,			NULL,	ipf_nat_rehash_rules },
160 	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_hostmap_sz) },
161 		"hostmap_size",	1,	0x7fffffff,
162 		stsizeof(ipf_nat_softc_t, ipf_nat_hostmap_sz),
163 		0,			NULL,	ipf_nat_hostmap_rehash },
164 	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maxbucket) },
165 		"nat_maxbucket",1,	0x7fffffff,
166 		stsizeof(ipf_nat_softc_t, ipf_nat_maxbucket),
167 		0,			NULL,	NULL },
168 	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_logging) },
169 		"nat_logging",	0,	1,
170 		stsizeof(ipf_nat_softc_t, ipf_nat_logging),
171 		0,			NULL,	NULL },
172 	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_doflush) },
173 		"nat_doflush",	0,	1,
174 		stsizeof(ipf_nat_softc_t, ipf_nat_doflush),
175 		0,			NULL,	NULL },
176 	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_low) },
177 		"nat_table_wm_low",	1,	99,
178 		stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_low),
179 		0,			NULL,	NULL },
180 	{ { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_high) },
181 		"nat_table_wm_high",	2,	100,
182 		stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_high),
183 		0,			NULL,	NULL },
184 	{ { 0 },
185 		NULL,			0,	0,
186 		0,
187 		0,			NULL,	NULL }
188 };
189 
190 /* ======================================================================== */
191 /* How the NAT is organised and works.                                      */
192 /*                                                                          */
193 /* Inside (interface y) NAT       Outside (interface x)                     */
194 /* -------------------- -+- -------------------------------------           */
195 /* Packet going          |   out, processsed by ipf_nat_checkout() for x    */
196 /* ------------>         |   ------------>                                  */
197 /* src=10.1.1.1          |   src=192.1.1.1                                  */
198 /*                       |                                                  */
199 /*                       |   in, processed by ipf_nat_checkin() for x       */
200 /* <------------         |   <------------                                  */
201 /* dst=10.1.1.1          |   dst=192.1.1.1                                  */
202 /* -------------------- -+- -------------------------------------           */
203 /* ipf_nat_checkout() - changes ip_src and if required, sport               */
204 /*             - creates a new mapping, if required.                        */
205 /* ipf_nat_checkin()  - changes ip_dst and if required, dport               */
206 /*                                                                          */
207 /* In the NAT table, internal source is recorded as "in" and externally     */
208 /* seen as "out".                                                           */
209 /* ======================================================================== */
210 
211 
212 #if SOLARIS && !defined(INSTANCES)
213 extern	int		pfil_delayed_copy;
214 #endif
215 
216 static	int	ipf_nat_flush_entry __P((ipf_main_softc_t *, void *));
217 static	int	ipf_nat_getent __P((ipf_main_softc_t *, caddr_t, int));
218 static	int	ipf_nat_getsz __P((ipf_main_softc_t *, caddr_t, int));
219 static	int	ipf_nat_putent __P((ipf_main_softc_t *, caddr_t, int));
220 static	void	ipf_nat_addmap __P((ipf_nat_softc_t *, ipnat_t *));
221 static	void	ipf_nat_addrdr __P((ipf_nat_softc_t *, ipnat_t *));
222 static	int	ipf_nat_builddivertmp __P((ipf_nat_softc_t *, ipnat_t *));
223 static	int	ipf_nat_clearlist __P((ipf_main_softc_t *, ipf_nat_softc_t *));
224 static	int	ipf_nat_cmp_rules __P((ipnat_t *, ipnat_t *));
225 static	int	ipf_nat_decap __P((fr_info_t *, nat_t *));
226 static	void	ipf_nat_delrule __P((ipf_main_softc_t *, ipf_nat_softc_t *,
227 				     ipnat_t *, int));
228 static	int	ipf_nat_extraflush __P((ipf_main_softc_t *, ipf_nat_softc_t *, int));
229 static	int	ipf_nat_finalise __P((fr_info_t *, nat_t *));
230 static	int	ipf_nat_flushtable __P((ipf_main_softc_t *, ipf_nat_softc_t *));
231 static	int	ipf_nat_getnext __P((ipf_main_softc_t *, ipftoken_t *,
232 				     ipfgeniter_t *, ipfobj_t *));
233 static	int	ipf_nat_gettable __P((ipf_main_softc_t *, ipf_nat_softc_t *,
234 				      char *));
235 static	hostmap_t *ipf_nat_hostmap __P((ipf_nat_softc_t *, ipnat_t *,
236 					struct in_addr, struct in_addr,
237 					struct in_addr, u_32_t));
238 static	int	ipf_nat_icmpquerytype __P((int));
239 static	int	ipf_nat_iterator __P((ipf_main_softc_t *, ipftoken_t *,
240 				      ipfgeniter_t *, ipfobj_t *));
241 static	int	ipf_nat_match __P((fr_info_t *, ipnat_t *));
242 static	int	ipf_nat_matcharray __P((nat_t *, int *, u_long));
243 static	int	ipf_nat_matchflush __P((ipf_main_softc_t *, ipf_nat_softc_t *,
244 					caddr_t));
245 static	void	ipf_nat_mssclamp __P((tcphdr_t *, u_32_t, fr_info_t *,
246 				      u_short *));
247 static	int	ipf_nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
248 static	int	ipf_nat_newdivert __P((fr_info_t *, nat_t *, natinfo_t *));
249 static	int	ipf_nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *));
250 static	int	ipf_nat_newrewrite __P((fr_info_t *, nat_t *, natinfo_t *));
251 static	int	ipf_nat_nextaddr __P((fr_info_t *, nat_addr_t *, u_32_t *,
252 				      u_32_t *));
253 static	int	ipf_nat_nextaddrinit __P((ipf_main_softc_t *, char *,
254 					  nat_addr_t *, int, void *));
255 static	int	ipf_nat_resolverule __P((ipf_main_softc_t *, ipnat_t *));
256 static	int	ipf_nat_ruleaddrinit __P((ipf_main_softc_t *,
257 					  ipf_nat_softc_t *, ipnat_t *));
258 static	void	ipf_nat_rule_fini __P((ipf_main_softc_t *, ipnat_t *));
259 static	int	ipf_nat_rule_init __P((ipf_main_softc_t *, ipf_nat_softc_t *,
260 				       ipnat_t *));
261 static	int	ipf_nat_siocaddnat __P((ipf_main_softc_t *, ipf_nat_softc_t *,
262 					ipnat_t *, int));
263 static	void	ipf_nat_siocdelnat __P((ipf_main_softc_t *, ipf_nat_softc_t *,
264 					ipnat_t *, int));
265 static	void	ipf_nat_tabmove __P((ipf_nat_softc_t *, nat_t *));
266 
267 /* ------------------------------------------------------------------------ */
268 /* Function:    ipf_nat_main_load                                           */
269 /* Returns:     int - 0 == success, -1 == failure                           */
270 /* Parameters:  Nil                                                         */
271 /*                                                                          */
272 /* The only global NAT structure that needs to be initialised is the filter */
273 /* rule that is used with blocking packets.                                 */
274 /* ------------------------------------------------------------------------ */
275 int
ipf_nat_main_load()276 ipf_nat_main_load()
277 {
278 	bzero((char *)&ipfnatblock, sizeof(ipfnatblock));
279 	ipfnatblock.fr_flags = FR_BLOCK|FR_QUICK;
280 	ipfnatblock.fr_ref = 1;
281 
282 	return 0;
283 }
284 
285 
286 /* ------------------------------------------------------------------------ */
287 /* Function:    ipf_nat_main_unload                                         */
288 /* Returns:     int - 0 == success, -1 == failure                           */
289 /* Parameters:  Nil                                                         */
290 /*                                                                          */
291 /* A null-op function that exists as a placeholder so that the flow in      */
292 /* other functions is obvious.                                              */
293 /* ------------------------------------------------------------------------ */
294 int
ipf_nat_main_unload()295 ipf_nat_main_unload()
296 {
297 	return 0;
298 }
299 
300 
301 /* ------------------------------------------------------------------------ */
302 /* Function:    ipf_nat_soft_create                                         */
303 /* Returns:     void * - NULL = failure, else pointer to NAT context        */
304 /* Parameters:  softc(I) - pointer to soft context main structure           */
305 /*                                                                          */
306 /* Allocate the initial soft context structure for NAT and populate it with */
307 /* some default values. Creating the tables is left until we call _init so  */
308 /* that sizes can be changed before we get under way.                       */
309 /* ------------------------------------------------------------------------ */
310 void *
ipf_nat_soft_create(softc)311 ipf_nat_soft_create(softc)
312 	ipf_main_softc_t *softc;
313 {
314 	ipf_nat_softc_t *softn;
315 
316 	KMALLOC(softn, ipf_nat_softc_t *);
317 	if (softn == NULL)
318 		return NULL;
319 
320 	bzero((char *)softn, sizeof(*softn));
321 
322 	softn->ipf_nat_tune = ipf_tune_array_copy(softn,
323 						  sizeof(ipf_nat_tuneables),
324 						  ipf_nat_tuneables);
325 	if (softn->ipf_nat_tune == NULL) {
326 		ipf_nat_soft_destroy(softc, softn);
327 		return NULL;
328 	}
329 	if (ipf_tune_array_link(softc, softn->ipf_nat_tune) == -1) {
330 		ipf_nat_soft_destroy(softc, softn);
331 		return NULL;
332 	}
333 
334 	softn->ipf_nat_list_tail = &softn->ipf_nat_list;
335 
336 	softn->ipf_nat_table_max = NAT_TABLE_MAX;
337 	softn->ipf_nat_table_sz = NAT_TABLE_SZ;
338 	softn->ipf_nat_maprules_sz = NAT_SIZE;
339 	softn->ipf_nat_rdrrules_sz = RDR_SIZE;
340 	softn->ipf_nat_hostmap_sz = HOSTMAP_SIZE;
341 	softn->ipf_nat_doflush = 0;
342 #ifdef  IPFILTER_LOG
343 	softn->ipf_nat_logging = 1;
344 #else
345 	softn->ipf_nat_logging = 0;
346 #endif
347 
348 	softn->ipf_nat_defage = DEF_NAT_AGE;
349 	softn->ipf_nat_defipage = IPF_TTLVAL(60);
350 	softn->ipf_nat_deficmpage = IPF_TTLVAL(3);
351 	softn->ipf_nat_table_wm_high = 99;
352 	softn->ipf_nat_table_wm_low = 90;
353 
354 	return softn;
355 }
356 
357 /* ------------------------------------------------------------------------ */
358 /* Function:    ipf_nat_soft_destroy                                        */
359 /* Returns:     Nil                                                         */
360 /* Parameters:  softc(I) - pointer to soft context main structure           */
361 /*                                                                          */
362 /* ------------------------------------------------------------------------ */
363 void
ipf_nat_soft_destroy(softc,arg)364 ipf_nat_soft_destroy(softc, arg)
365 	ipf_main_softc_t *softc;
366 	void *arg;
367 {
368 	ipf_nat_softc_t *softn = arg;
369 
370 	if (softn->ipf_nat_tune != NULL) {
371 		ipf_tune_array_unlink(softc, softn->ipf_nat_tune);
372 		KFREES(softn->ipf_nat_tune, sizeof(ipf_nat_tuneables));
373 		softn->ipf_nat_tune = NULL;
374 	}
375 
376 	KFREE(softn);
377 }
378 
379 
380 /* ------------------------------------------------------------------------ */
381 /* Function:    ipf_nat_init                                                */
382 /* Returns:     int - 0 == success, -1 == failure                           */
383 /* Parameters:  softc(I) - pointer to soft context main structure           */
384 /*                                                                          */
385 /* Initialise all of the NAT locks, tables and other structures.            */
386 /* ------------------------------------------------------------------------ */
387 int
ipf_nat_soft_init(softc,arg)388 ipf_nat_soft_init(softc, arg)
389 	ipf_main_softc_t *softc;
390 	void *arg;
391 {
392 	ipf_nat_softc_t *softn = arg;
393 	ipftq_t *tq;
394 	int i;
395 
396 	KMALLOCS(softn->ipf_nat_table[0], nat_t **, \
397 		 sizeof(nat_t *) * softn->ipf_nat_table_sz);
398 
399 	if (softn->ipf_nat_table[0] != NULL) {
400 		bzero((char *)softn->ipf_nat_table[0],
401 		      softn->ipf_nat_table_sz * sizeof(nat_t *));
402 	} else {
403 		return -1;
404 	}
405 
406 	KMALLOCS(softn->ipf_nat_table[1], nat_t **, \
407 		 sizeof(nat_t *) * softn->ipf_nat_table_sz);
408 
409 	if (softn->ipf_nat_table[1] != NULL) {
410 		bzero((char *)softn->ipf_nat_table[1],
411 		      softn->ipf_nat_table_sz * sizeof(nat_t *));
412 	} else {
413 		return -2;
414 	}
415 
416 	KMALLOCS(softn->ipf_nat_map_rules, ipnat_t **, \
417 		 sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz);
418 
419 	if (softn->ipf_nat_map_rules != NULL) {
420 		bzero((char *)softn->ipf_nat_map_rules,
421 		      softn->ipf_nat_maprules_sz * sizeof(ipnat_t *));
422 	} else {
423 		return -3;
424 	}
425 
426 	KMALLOCS(softn->ipf_nat_rdr_rules, ipnat_t **, \
427 		 sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz);
428 
429 	if (softn->ipf_nat_rdr_rules != NULL) {
430 		bzero((char *)softn->ipf_nat_rdr_rules,
431 		      softn->ipf_nat_rdrrules_sz * sizeof(ipnat_t *));
432 	} else {
433 		return -4;
434 	}
435 
436 	KMALLOCS(softn->ipf_hm_maptable, hostmap_t **, \
437 		 sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
438 
439 	if (softn->ipf_hm_maptable != NULL) {
440 		bzero((char *)softn->ipf_hm_maptable,
441 		      sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
442 	} else {
443 		return -5;
444 	}
445 	softn->ipf_hm_maplist = NULL;
446 
447 	KMALLOCS(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, u_int *,
448 		 softn->ipf_nat_table_sz * sizeof(u_int));
449 
450 	if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen == NULL) {
451 		return -6;
452 	}
453 	bzero((char *)softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
454 	      softn->ipf_nat_table_sz * sizeof(u_int));
455 
456 	KMALLOCS(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, u_int *,
457 		 softn->ipf_nat_table_sz * sizeof(u_int));
458 
459 	if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen == NULL) {
460 		return -7;
461 	}
462 
463 	bzero((char *)softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
464 	      softn->ipf_nat_table_sz * sizeof(u_int));
465 
466 	if (softn->ipf_nat_maxbucket == 0) {
467 		for (i = softn->ipf_nat_table_sz; i > 0; i >>= 1)
468 			softn->ipf_nat_maxbucket++;
469 		softn->ipf_nat_maxbucket *= 2;
470 	}
471 
472 	ipf_sttab_init(softc, softn->ipf_nat_tcptq);
473 	/*
474 	 * Increase this because we may have "keep state" following this too
475 	 * and packet storms can occur if this is removed too quickly.
476 	 */
477 	softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack;
478 	softn->ipf_nat_tcptq[IPF_TCP_NSTATES - 1].ifq_next =
479 							&softn->ipf_nat_udptq;
480 
481 	IPFTQ_INIT(&softn->ipf_nat_udptq, softn->ipf_nat_defage,
482 		   "nat ipftq udp tab");
483 	softn->ipf_nat_udptq.ifq_next = &softn->ipf_nat_udpacktq;
484 
485 	IPFTQ_INIT(&softn->ipf_nat_udpacktq, softn->ipf_nat_defage,
486 		   "nat ipftq udpack tab");
487 	softn->ipf_nat_udpacktq.ifq_next = &softn->ipf_nat_icmptq;
488 
489 	IPFTQ_INIT(&softn->ipf_nat_icmptq, softn->ipf_nat_deficmpage,
490 		   "nat icmp ipftq tab");
491 	softn->ipf_nat_icmptq.ifq_next = &softn->ipf_nat_icmpacktq;
492 
493 	IPFTQ_INIT(&softn->ipf_nat_icmpacktq, softn->ipf_nat_defage,
494 		   "nat icmpack ipftq tab");
495 	softn->ipf_nat_icmpacktq.ifq_next = &softn->ipf_nat_iptq;
496 
497 	IPFTQ_INIT(&softn->ipf_nat_iptq, softn->ipf_nat_defipage,
498 		   "nat ip ipftq tab");
499 	softn->ipf_nat_iptq.ifq_next = &softn->ipf_nat_pending;
500 
501 	IPFTQ_INIT(&softn->ipf_nat_pending, 1, "nat pending ipftq tab");
502 	softn->ipf_nat_pending.ifq_next = NULL;
503 
504 	for (i = 0, tq = softn->ipf_nat_tcptq; i < IPF_TCP_NSTATES; i++, tq++) {
505 		if (tq->ifq_ttl < softn->ipf_nat_deficmpage)
506 			tq->ifq_ttl = softn->ipf_nat_deficmpage;
507 #ifdef LARGE_NAT
508 		else if (tq->ifq_ttl > softn->ipf_nat_defage)
509 			tq->ifq_ttl = softn->ipf_nat_defage;
510 #endif
511 	}
512 
513 	/*
514 	 * Increase this because we may have "keep state" following
515 	 * this too and packet storms can occur if this is removed
516 	 * too quickly.
517 	 */
518 	softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack;
519 
520 	MUTEX_INIT(&softn->ipf_nat_new, "ipf nat new mutex");
521 	MUTEX_INIT(&softn->ipf_nat_io, "ipf nat io mutex");
522 
523 	softn->ipf_nat_inited = 1;
524 
525 	return 0;
526 }
527 
528 
529 /* ------------------------------------------------------------------------ */
530 /* Function:    ipf_nat_soft_fini                                           */
531 /* Returns:     Nil                                                         */
532 /* Parameters:  softc(I) - pointer to soft context main structure           */
533 /*                                                                          */
534 /* Free all memory used by NAT structures allocated at runtime.             */
535 /* ------------------------------------------------------------------------ */
536 int
ipf_nat_soft_fini(softc,arg)537 ipf_nat_soft_fini(softc, arg)
538 	ipf_main_softc_t *softc;
539 	void *arg;
540 {
541 	ipf_nat_softc_t *softn = arg;
542 	ipftq_t *ifq, *ifqnext;
543 
544 	(void) ipf_nat_clearlist(softc, softn);
545 	(void) ipf_nat_flushtable(softc, softn);
546 
547 	/*
548 	 * Proxy timeout queues are not cleaned here because although they
549 	 * exist on the NAT list, ipf_proxy_unload is called after unload
550 	 * and the proxies actually are responsible for them being created.
551 	 * Should the proxy timeouts have their own list?  There's no real
552 	 * justification as this is the only complication.
553 	 */
554 	for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) {
555 		ifqnext = ifq->ifq_next;
556 		if (ipf_deletetimeoutqueue(ifq) == 0)
557 			ipf_freetimeoutqueue(softc, ifq);
558 	}
559 
560 	if (softn->ipf_nat_table[0] != NULL) {
561 		KFREES(softn->ipf_nat_table[0],
562 		       sizeof(nat_t *) * softn->ipf_nat_table_sz);
563 		softn->ipf_nat_table[0] = NULL;
564 	}
565 	if (softn->ipf_nat_table[1] != NULL) {
566 		KFREES(softn->ipf_nat_table[1],
567 		       sizeof(nat_t *) * softn->ipf_nat_table_sz);
568 		softn->ipf_nat_table[1] = NULL;
569 	}
570 	if (softn->ipf_nat_map_rules != NULL) {
571 		KFREES(softn->ipf_nat_map_rules,
572 		       sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz);
573 		softn->ipf_nat_map_rules = NULL;
574 	}
575 	if (softn->ipf_nat_rdr_rules != NULL) {
576 		KFREES(softn->ipf_nat_rdr_rules,
577 		       sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz);
578 		softn->ipf_nat_rdr_rules = NULL;
579 	}
580 	if (softn->ipf_hm_maptable != NULL) {
581 		KFREES(softn->ipf_hm_maptable,
582 		       sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
583 		softn->ipf_hm_maptable = NULL;
584 	}
585 	if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) {
586 		KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
587 		       sizeof(u_int) * softn->ipf_nat_table_sz);
588 		softn->ipf_nat_stats.ns_side[0].ns_bucketlen = NULL;
589 	}
590 	if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) {
591 		KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
592 		       sizeof(u_int) * softn->ipf_nat_table_sz);
593 		softn->ipf_nat_stats.ns_side[1].ns_bucketlen = NULL;
594 	}
595 
596 	if (softn->ipf_nat_inited == 1) {
597 		softn->ipf_nat_inited = 0;
598 		ipf_sttab_destroy(softn->ipf_nat_tcptq);
599 
600 		MUTEX_DESTROY(&softn->ipf_nat_new);
601 		MUTEX_DESTROY(&softn->ipf_nat_io);
602 
603 		MUTEX_DESTROY(&softn->ipf_nat_udptq.ifq_lock);
604 		MUTEX_DESTROY(&softn->ipf_nat_udpacktq.ifq_lock);
605 		MUTEX_DESTROY(&softn->ipf_nat_icmptq.ifq_lock);
606 		MUTEX_DESTROY(&softn->ipf_nat_icmpacktq.ifq_lock);
607 		MUTEX_DESTROY(&softn->ipf_nat_iptq.ifq_lock);
608 		MUTEX_DESTROY(&softn->ipf_nat_pending.ifq_lock);
609 	}
610 
611 	return 0;
612 }
613 
614 
615 /* ------------------------------------------------------------------------ */
616 /* Function:    ipf_nat_setlock                                             */
617 /* Returns:     Nil                                                         */
618 /* Parameters:  arg(I) - pointer to soft state information                  */
619 /*              tmp(I) - new lock value                                     */
620 /*                                                                          */
621 /* Set the "lock status" of NAT to the value in tmp.                        */
622 /* ------------------------------------------------------------------------ */
623 void
ipf_nat_setlock(arg,tmp)624 ipf_nat_setlock(arg, tmp)
625 	void *arg;
626 	int tmp;
627 {
628 	ipf_nat_softc_t *softn = arg;
629 
630 	softn->ipf_nat_lock = tmp;
631 }
632 
633 
634 /* ------------------------------------------------------------------------ */
635 /* Function:    ipf_nat_addrdr                                              */
636 /* Returns:     Nil                                                         */
637 /* Parameters:  n(I) - pointer to NAT rule to add                           */
638 /*                                                                          */
639 /* Adds a redirect rule to the hash table of redirect rules and the list of */
640 /* loaded NAT rules.  Updates the bitmask indicating which netmasks are in  */
641 /* use by redirect rules.                                                   */
642 /* ------------------------------------------------------------------------ */
643 static void
ipf_nat_addrdr(softn,n)644 ipf_nat_addrdr(softn, n)
645 	ipf_nat_softc_t *softn;
646 	ipnat_t *n;
647 {
648 	ipnat_t **np;
649 	u_32_t j;
650 	u_int hv;
651 	u_int rhv;
652 	int k;
653 
654 	if (n->in_odstatype == FRI_NORMAL) {
655 		k = count4bits(n->in_odstmsk);
656 		ipf_inet_mask_add(k, &softn->ipf_nat_rdr_mask);
657 		j = (n->in_odstaddr & n->in_odstmsk);
658 		rhv = NAT_HASH_FN(j, 0, 0xffffffff);
659 	} else {
660 		ipf_inet_mask_add(0, &softn->ipf_nat_rdr_mask);
661 		j = 0;
662 		rhv = 0;
663 	}
664 	hv = rhv % softn->ipf_nat_rdrrules_sz;
665 	np = softn->ipf_nat_rdr_rules + hv;
666 	while (*np != NULL)
667 		np = &(*np)->in_rnext;
668 	n->in_rnext = NULL;
669 	n->in_prnext = np;
670 	n->in_hv[0] = hv;
671 	n->in_use++;
672 	*np = n;
673 }
674 
675 
676 /* ------------------------------------------------------------------------ */
677 /* Function:    ipf_nat_addmap                                              */
678 /* Returns:     Nil                                                         */
679 /* Parameters:  n(I) - pointer to NAT rule to add                           */
680 /*                                                                          */
681 /* Adds a NAT map rule to the hash table of rules and the list of  loaded   */
682 /* NAT rules.  Updates the bitmask indicating which netmasks are in use by  */
683 /* redirect rules.                                                          */
684 /* ------------------------------------------------------------------------ */
685 static void
ipf_nat_addmap(softn,n)686 ipf_nat_addmap(softn, n)
687 	ipf_nat_softc_t *softn;
688 	ipnat_t *n;
689 {
690 	ipnat_t **np;
691 	u_32_t j;
692 	u_int hv;
693 	u_int rhv;
694 	int k;
695 
696 	if (n->in_osrcatype == FRI_NORMAL) {
697 		k = count4bits(n->in_osrcmsk);
698 		ipf_inet_mask_add(k, &softn->ipf_nat_map_mask);
699 		j = (n->in_osrcaddr & n->in_osrcmsk);
700 		rhv = NAT_HASH_FN(j, 0, 0xffffffff);
701 	} else {
702 		ipf_inet_mask_add(0, &softn->ipf_nat_map_mask);
703 		j = 0;
704 		rhv = 0;
705 	}
706 	hv = rhv % softn->ipf_nat_maprules_sz;
707 	np = softn->ipf_nat_map_rules + hv;
708 	while (*np != NULL)
709 		np = &(*np)->in_mnext;
710 	n->in_mnext = NULL;
711 	n->in_pmnext = np;
712 	n->in_hv[1] = rhv;
713 	n->in_use++;
714 	*np = n;
715 }
716 
717 
718 /* ------------------------------------------------------------------------ */
719 /* Function:    ipf_nat_delrdr                                              */
720 /* Returns:     Nil                                                         */
721 /* Parameters:  n(I) - pointer to NAT rule to delete                        */
722 /*                                                                          */
723 /* Removes a redirect rule from the hash table of redirect rules.           */
724 /* ------------------------------------------------------------------------ */
725 void
ipf_nat_delrdr(softn,n)726 ipf_nat_delrdr(softn, n)
727 	ipf_nat_softc_t *softn;
728 	ipnat_t *n;
729 {
730 	if (n->in_odstatype == FRI_NORMAL) {
731 		int k = count4bits(n->in_odstmsk);
732 		ipf_inet_mask_del(k, &softn->ipf_nat_rdr_mask);
733 	} else {
734 		ipf_inet_mask_del(0, &softn->ipf_nat_rdr_mask);
735 	}
736 	if (n->in_rnext)
737 		n->in_rnext->in_prnext = n->in_prnext;
738 	*n->in_prnext = n->in_rnext;
739 	n->in_use--;
740 }
741 
742 
743 /* ------------------------------------------------------------------------ */
744 /* Function:    ipf_nat_delmap                                              */
745 /* Returns:     Nil                                                         */
746 /* Parameters:  n(I) - pointer to NAT rule to delete                        */
747 /*                                                                          */
748 /* Removes a NAT map rule from the hash table of NAT map rules.             */
749 /* ------------------------------------------------------------------------ */
750 void
ipf_nat_delmap(softn,n)751 ipf_nat_delmap(softn, n)
752 	ipf_nat_softc_t *softn;
753 	ipnat_t *n;
754 {
755 	if (n->in_osrcatype == FRI_NORMAL) {
756 		int k = count4bits(n->in_osrcmsk);
757 		ipf_inet_mask_del(k, &softn->ipf_nat_map_mask);
758 	} else {
759 		ipf_inet_mask_del(0, &softn->ipf_nat_map_mask);
760 	}
761 	if (n->in_mnext != NULL)
762 		n->in_mnext->in_pmnext = n->in_pmnext;
763 	*n->in_pmnext = n->in_mnext;
764 	n->in_use--;
765 }
766 
767 
768 /* ------------------------------------------------------------------------ */
769 /* Function:    ipf_nat_hostmap                                             */
770 /* Returns:     struct hostmap* - NULL if no hostmap could be created,      */
771 /*                                else a pointer to the hostmapping to use  */
772 /* Parameters:  np(I)   - pointer to NAT rule                               */
773 /*              real(I) - real IP address                                   */
774 /*              map(I)  - mapped IP address                                 */
775 /*              port(I) - destination port number                           */
776 /* Write Locks: ipf_nat                                                     */
777 /*                                                                          */
778 /* Check if an ip address has already been allocated for a given mapping    */
779 /* that is not doing port based translation.  If is not yet allocated, then */
780 /* create a new entry if a non-NULL NAT rule pointer has been supplied.     */
781 /* ------------------------------------------------------------------------ */
782 static struct hostmap *
ipf_nat_hostmap(softn,np,src,dst,map,port)783 ipf_nat_hostmap(softn, np, src, dst, map, port)
784 	ipf_nat_softc_t *softn;
785 	ipnat_t *np;
786 	struct in_addr src;
787 	struct in_addr dst;
788 	struct in_addr map;
789 	u_32_t port;
790 {
791 	hostmap_t *hm;
792 	u_int hv, rhv;
793 
794 	hv = (src.s_addr ^ dst.s_addr);
795 	hv += src.s_addr;
796 	hv += dst.s_addr;
797 	rhv = hv;
798 	hv %= softn->ipf_nat_hostmap_sz;
799 	for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_hnext)
800 		if ((hm->hm_osrcip.s_addr == src.s_addr) &&
801 		    (hm->hm_odstip.s_addr == dst.s_addr) &&
802 		    ((np == NULL) || (np == hm->hm_ipnat)) &&
803 		    ((port == 0) || (port == hm->hm_port))) {
804 			softn->ipf_nat_stats.ns_hm_addref++;
805 			hm->hm_ref++;
806 			return hm;
807 		}
808 
809 	if (np == NULL) {
810 		softn->ipf_nat_stats.ns_hm_nullnp++;
811 		return NULL;
812 	}
813 
814 	KMALLOC(hm, hostmap_t *);
815 	if (hm) {
816 		hm->hm_next = softn->ipf_hm_maplist;
817 		hm->hm_pnext = &softn->ipf_hm_maplist;
818 		if (softn->ipf_hm_maplist != NULL)
819 			softn->ipf_hm_maplist->hm_pnext = &hm->hm_next;
820 		softn->ipf_hm_maplist = hm;
821 		hm->hm_hnext = softn->ipf_hm_maptable[hv];
822 		hm->hm_phnext = softn->ipf_hm_maptable + hv;
823 		if (softn->ipf_hm_maptable[hv] != NULL)
824 			softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
825 		softn->ipf_hm_maptable[hv] = hm;
826 		hm->hm_ipnat = np;
827 		np->in_use++;
828 		hm->hm_osrcip = src;
829 		hm->hm_odstip = dst;
830 		hm->hm_nsrcip = map;
831 		hm->hm_ndstip.s_addr = 0;
832 		hm->hm_ref = 1;
833 		hm->hm_port = port;
834 		hm->hm_hv = rhv;
835 		hm->hm_v = 4;
836 		softn->ipf_nat_stats.ns_hm_new++;
837 	} else {
838 		softn->ipf_nat_stats.ns_hm_newfail++;
839 	}
840 	return hm;
841 }
842 
843 
844 /* ------------------------------------------------------------------------ */
845 /* Function:    ipf_nat_hostmapdel                                          */
846 /* Returns:     Nil                                                         */
847 /* Parameters:  hmp(I) - pointer to hostmap structure pointer               */
848 /* Write Locks: ipf_nat                                                     */
849 /*                                                                          */
850 /* Decrement the references to this hostmap structure by one.  If this      */
851 /* reaches zero then remove it and free it.                                 */
852 /* ------------------------------------------------------------------------ */
853 void
ipf_nat_hostmapdel(softc,hmp)854 ipf_nat_hostmapdel(softc, hmp)
855 	ipf_main_softc_t *softc;
856 	struct hostmap **hmp;
857 {
858 	struct hostmap *hm;
859 
860 	hm = *hmp;
861 	*hmp = NULL;
862 
863 	hm->hm_ref--;
864 	if (hm->hm_ref == 0) {
865 		ipf_nat_rule_deref(softc, &hm->hm_ipnat);
866 		if (hm->hm_hnext)
867 			hm->hm_hnext->hm_phnext = hm->hm_phnext;
868 		*hm->hm_phnext = hm->hm_hnext;
869 		if (hm->hm_next)
870 			hm->hm_next->hm_pnext = hm->hm_pnext;
871 		*hm->hm_pnext = hm->hm_next;
872 		KFREE(hm);
873 	}
874 }
875 
876 
877 /* ------------------------------------------------------------------------ */
878 /* Function:    ipf_fix_outcksum                                            */
879 /* Returns:     Nil                                                         */
880 /* Parameters:  fin(I) - pointer to packet information                      */
881 /*              sp(I)  - location of 16bit checksum to update               */
882 /*              n((I)  - amount to adjust checksum by                       */
883 /*                                                                          */
884 /* Adjusts the 16bit checksum by "n" for packets going out.                 */
885 /* ------------------------------------------------------------------------ */
886 void
ipf_fix_outcksum(cksum,sp,n,partial)887 ipf_fix_outcksum(cksum, sp, n, partial)
888 	int cksum;
889 	u_short *sp;
890 	u_32_t n, partial;
891 {
892 	u_short sumshort;
893 	u_32_t sum1;
894 
895 	if (n == 0)
896 		return;
897 
898 	if (cksum == 4) {
899 		*sp = 0;
900 		return;
901 	}
902 	if (cksum == 2) {
903 		sum1 = partial;
904 		sum1 = (sum1 & 0xffff) + (sum1 >> 16);
905 		*sp = htons(sum1);
906 		return;
907 	}
908 	sum1 = (~ntohs(*sp)) & 0xffff;
909 	sum1 += (n);
910 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
911 	/* Again */
912 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
913 	sumshort = ~(u_short)sum1;
914 	*(sp) = htons(sumshort);
915 }
916 
917 
918 /* ------------------------------------------------------------------------ */
919 /* Function:    ipf_fix_incksum                                             */
920 /* Returns:     Nil                                                         */
921 /* Parameters:  fin(I) - pointer to packet information                      */
922 /*              sp(I)  - location of 16bit checksum to update               */
923 /*              n((I)  - amount to adjust checksum by                       */
924 /*                                                                          */
925 /* Adjusts the 16bit checksum by "n" for packets going in.                  */
926 /* ------------------------------------------------------------------------ */
927 void
ipf_fix_incksum(cksum,sp,n,partial)928 ipf_fix_incksum(cksum, sp, n, partial)
929 	int cksum;
930 	u_short *sp;
931 	u_32_t n, partial;
932 {
933 	u_short sumshort;
934 	u_32_t sum1;
935 
936 	if (n == 0)
937 		return;
938 
939 	if (cksum == 4) {
940 		*sp = 0;
941 		return;
942 	}
943 	if (cksum == 2) {
944 		sum1 = partial;
945 		sum1 = (sum1 & 0xffff) + (sum1 >> 16);
946 		*sp = htons(sum1);
947 		return;
948 	}
949 
950 	sum1 = (~ntohs(*sp)) & 0xffff;
951 	sum1 += ~(n) & 0xffff;
952 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
953 	/* Again */
954 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
955 	sumshort = ~(u_short)sum1;
956 	*(sp) = htons(sumshort);
957 }
958 
959 
960 /* ------------------------------------------------------------------------ */
961 /* Function:    ipf_fix_datacksum                                           */
962 /* Returns:     Nil                                                         */
963 /* Parameters:  sp(I)  - location of 16bit checksum to update               */
964 /*              n((I)  - amount to adjust checksum by                       */
965 /*                                                                          */
966 /* Fix_datacksum is used *only* for the adjustments of checksums in the     */
967 /* data section of an IP packet.                                            */
968 /*                                                                          */
969 /* The only situation in which you need to do this is when NAT'ing an       */
970 /* ICMP error message. Such a message, contains in its body the IP header   */
971 /* of the original IP packet, that causes the error.                        */
972 /*                                                                          */
973 /* You can't use fix_incksum or fix_outcksum in that case, because for the  */
974 /* kernel the data section of the ICMP error is just data, and no special   */
975 /* processing like hardware cksum or ntohs processing have been done by the */
976 /* kernel on the data section.                                              */
977 /* ------------------------------------------------------------------------ */
978 void
ipf_fix_datacksum(sp,n)979 ipf_fix_datacksum(sp, n)
980 	u_short *sp;
981 	u_32_t n;
982 {
983 	u_short sumshort;
984 	u_32_t sum1;
985 
986 	if (n == 0)
987 		return;
988 
989 	sum1 = (~ntohs(*sp)) & 0xffff;
990 	sum1 += (n);
991 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
992 	/* Again */
993 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
994 	sumshort = ~(u_short)sum1;
995 	*(sp) = htons(sumshort);
996 }
997 
998 
999 /* ------------------------------------------------------------------------ */
1000 /* Function:    ipf_nat_ioctl                                               */
1001 /* Returns:     int - 0 == success, != 0 == failure                         */
1002 /* Parameters:  softc(I) - pointer to soft context main structure           */
1003 /*              data(I)  - pointer to ioctl data                            */
1004 /*              cmd(I)   - ioctl command integer                            */
1005 /*              mode(I)  - file mode bits used with open                    */
1006 /*              uid(I)   - uid of calling process                           */
1007 /*              ctx(I)   - pointer used as key for finding context          */
1008 /*                                                                          */
1009 /* Processes an ioctl call made to operate on the IP Filter NAT device.     */
1010 /* ------------------------------------------------------------------------ */
1011 int
ipf_nat_ioctl(softc,data,cmd,mode,uid,ctx)1012 ipf_nat_ioctl(softc, data, cmd, mode, uid, ctx)
1013 	ipf_main_softc_t *softc;
1014 	ioctlcmd_t cmd;
1015 	caddr_t data;
1016 	int mode, uid;
1017 	void *ctx;
1018 {
1019 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1020 	int error = 0, ret, arg, getlock;
1021 	ipnat_t *nat, *nt, *n;
1022 	ipnat_t natd;
1023 	SPL_INT(s);
1024 
1025 #if BSD_GE_YEAR(199306) && defined(_KERNEL)
1026 # if NETBSD_GE_REV(399002000)
1027 	if ((mode & FWRITE) &&
1028 	     kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_FIREWALL,
1029 				     KAUTH_REQ_NETWORK_FIREWALL_FW,
1030 				     NULL, NULL, NULL))
1031 # else
1032 #  if defined(__FreeBSD_version) && (__FreeBSD_version >= 500034)
1033 	if (securelevel_ge(curthread->td_ucred, 3) && (mode & FWRITE))
1034 #  else
1035 	if ((securelevel >= 3) && (mode & FWRITE))
1036 #  endif
1037 # endif
1038 	{
1039 		IPFERROR(60001);
1040 		return EPERM;
1041 	}
1042 #endif
1043 
1044 #if defined(__osf__) && defined(_KERNEL)
1045 	getlock = 0;
1046 #else
1047 	getlock = (mode & NAT_LOCKHELD) ? 0 : 1;
1048 #endif
1049 
1050 	n = NULL;
1051 	nt = NULL;
1052 	nat = NULL;
1053 
1054 	if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT) ||
1055 	    (cmd == (ioctlcmd_t)SIOCPURGENAT)) {
1056 		if (mode & NAT_SYSSPACE) {
1057 			bcopy(data, (char *)&natd, sizeof(natd));
1058 			nat = &natd;
1059 			error = 0;
1060 		} else {
1061 			bzero(&natd, sizeof(natd));
1062 			error = ipf_inobj(softc, data, NULL, &natd,
1063 					  IPFOBJ_IPNAT);
1064 			if (error != 0)
1065 				goto done;
1066 
1067 			if (natd.in_size < sizeof(ipnat_t)) {
1068 				error = EINVAL;
1069 				goto done;
1070 			}
1071 			KMALLOCS(nt, ipnat_t *, natd.in_size);
1072 			if (nt == NULL) {
1073 				IPFERROR(60070);
1074 				error = ENOMEM;
1075 				goto done;
1076 			}
1077 			bzero(nt, natd.in_size);
1078 			error = ipf_inobjsz(softc, data, nt, IPFOBJ_IPNAT,
1079 					    natd.in_size);
1080 			if (error)
1081 				goto done;
1082 			nat = nt;
1083 		}
1084 
1085 		/*
1086 		 * For add/delete, look to see if the NAT entry is
1087 		 * already present
1088 		 */
1089 		nat->in_flags &= IPN_USERFLAGS;
1090 		if ((nat->in_redir & NAT_MAPBLK) == 0) {
1091 			if (nat->in_osrcatype == FRI_NORMAL ||
1092 			    nat->in_osrcatype == FRI_NONE)
1093 				nat->in_osrcaddr &= nat->in_osrcmsk;
1094 			if (nat->in_odstatype == FRI_NORMAL ||
1095 			    nat->in_odstatype == FRI_NONE)
1096 				nat->in_odstaddr &= nat->in_odstmsk;
1097 			if ((nat->in_flags & (IPN_SPLIT|IPN_SIPRANGE)) == 0) {
1098 				if (nat->in_nsrcatype == FRI_NORMAL)
1099 					nat->in_nsrcaddr &= nat->in_nsrcmsk;
1100 				if (nat->in_ndstatype == FRI_NORMAL)
1101 					nat->in_ndstaddr &= nat->in_ndstmsk;
1102 			}
1103 		}
1104 
1105 		error = ipf_nat_rule_init(softc, softn, nat);
1106 		if (error != 0)
1107 			goto done;
1108 
1109 		MUTEX_ENTER(&softn->ipf_nat_io);
1110 		for (n = softn->ipf_nat_list; n != NULL; n = n->in_next)
1111 			if (ipf_nat_cmp_rules(nat, n) == 0)
1112 				break;
1113 	}
1114 
1115 	switch (cmd)
1116 	{
1117 #ifdef  IPFILTER_LOG
1118 	case SIOCIPFFB :
1119 	{
1120 		int tmp;
1121 
1122 		if (!(mode & FWRITE)) {
1123 			IPFERROR(60002);
1124 			error = EPERM;
1125 		} else {
1126 			tmp = ipf_log_clear(softc, IPL_LOGNAT);
1127 			error = BCOPYOUT(&tmp, data, sizeof(tmp));
1128 			if (error != 0) {
1129 				IPFERROR(60057);
1130 				error = EFAULT;
1131 			}
1132 		}
1133 		break;
1134 	}
1135 
1136 	case SIOCSETLG :
1137 		if (!(mode & FWRITE)) {
1138 			IPFERROR(60003);
1139 			error = EPERM;
1140 		} else {
1141 			error = BCOPYIN(data, &softn->ipf_nat_logging,
1142 					sizeof(softn->ipf_nat_logging));
1143 			if (error != 0)
1144 				error = EFAULT;
1145 		}
1146 		break;
1147 
1148 	case SIOCGETLG :
1149 		error = BCOPYOUT(&softn->ipf_nat_logging, data,
1150 				 sizeof(softn->ipf_nat_logging));
1151 		if (error != 0) {
1152 			IPFERROR(60004);
1153 			error = EFAULT;
1154 		}
1155 		break;
1156 
1157 	case FIONREAD :
1158 		arg = ipf_log_bytesused(softc, IPL_LOGNAT);
1159 		error = BCOPYOUT(&arg, data, sizeof(arg));
1160 		if (error != 0) {
1161 			IPFERROR(60005);
1162 			error = EFAULT;
1163 		}
1164 		break;
1165 #endif
1166 	case SIOCADNAT :
1167 		if (!(mode & FWRITE)) {
1168 			IPFERROR(60006);
1169 			error = EPERM;
1170 		} else if (n != NULL) {
1171 			natd.in_flineno = n->in_flineno;
1172 			(void) ipf_outobj(softc, data, &natd, IPFOBJ_IPNAT);
1173 			IPFERROR(60007);
1174 			error = EEXIST;
1175 		} else if (nt == NULL) {
1176 			IPFERROR(60008);
1177 			error = ENOMEM;
1178 		}
1179 		if (error != 0) {
1180 			MUTEX_EXIT(&softn->ipf_nat_io);
1181 			break;
1182 		}
1183 		if (nat != nt)
1184 			bcopy((char *)nat, (char *)nt, sizeof(*n));
1185 		error = ipf_nat_siocaddnat(softc, softn, nt, getlock);
1186 		MUTEX_EXIT(&softn->ipf_nat_io);
1187 		if (error == 0) {
1188 			nat = NULL;
1189 			nt = NULL;
1190 		}
1191 		break;
1192 
1193 	case SIOCRMNAT :
1194 	case SIOCPURGENAT :
1195 		if (!(mode & FWRITE)) {
1196 			IPFERROR(60009);
1197 			error = EPERM;
1198 			n = NULL;
1199 		} else if (n == NULL) {
1200 			IPFERROR(60010);
1201 			error = ESRCH;
1202 		}
1203 
1204 		if (error != 0) {
1205 			MUTEX_EXIT(&softn->ipf_nat_io);
1206 			break;
1207 		}
1208 		if (cmd == (ioctlcmd_t)SIOCPURGENAT) {
1209 			error = ipf_outobjsz(softc, data, n, IPFOBJ_IPNAT,
1210 					     n->in_size);
1211 			if (error) {
1212 				MUTEX_EXIT(&softn->ipf_nat_io);
1213 				goto done;
1214 			}
1215 			n->in_flags |= IPN_PURGE;
1216 		}
1217 		ipf_nat_siocdelnat(softc, softn, n, getlock);
1218 
1219 		MUTEX_EXIT(&softn->ipf_nat_io);
1220 		n = NULL;
1221 		break;
1222 
1223 	case SIOCGNATS :
1224 	    {
1225 		natstat_t *nsp = &softn->ipf_nat_stats;
1226 
1227 		nsp->ns_side[0].ns_table = softn->ipf_nat_table[0];
1228 		nsp->ns_side[1].ns_table = softn->ipf_nat_table[1];
1229 		nsp->ns_list = softn->ipf_nat_list;
1230 		nsp->ns_maptable = softn->ipf_hm_maptable;
1231 		nsp->ns_maplist = softn->ipf_hm_maplist;
1232 		nsp->ns_nattab_sz = softn->ipf_nat_table_sz;
1233 		nsp->ns_nattab_max = softn->ipf_nat_table_max;
1234 		nsp->ns_rultab_sz = softn->ipf_nat_maprules_sz;
1235 		nsp->ns_rdrtab_sz = softn->ipf_nat_rdrrules_sz;
1236 		nsp->ns_hostmap_sz = softn->ipf_nat_hostmap_sz;
1237 		nsp->ns_instances = softn->ipf_nat_instances;
1238 		nsp->ns_ticks = softc->ipf_ticks;
1239 #ifdef IPFILTER_LOGGING
1240 		nsp->ns_log_ok = ipf_log_logok(softc, IPF_LOGNAT);
1241 		nsp->ns_log_fail = ipf_log_failures(softc, IPF_LOGNAT);
1242 #else
1243 		nsp->ns_log_ok = 0;
1244 		nsp->ns_log_fail = 0;
1245 #endif
1246 		error = ipf_outobj(softc, data, nsp, IPFOBJ_NATSTAT);
1247 		break;
1248 	    }
1249 
1250 	case SIOCGNATL :
1251 	    {
1252 		natlookup_t nl;
1253 
1254 		error = ipf_inobj(softc, data, NULL, &nl, IPFOBJ_NATLOOKUP);
1255 		if (error == 0) {
1256 			void *ptr;
1257 
1258 			if (getlock) {
1259 				READ_ENTER(&softc->ipf_nat);
1260 			}
1261 
1262 			switch (nl.nl_v)
1263 			{
1264 			case 4 :
1265 				ptr = ipf_nat_lookupredir(&nl);
1266 				break;
1267 #ifdef USE_INET6
1268 			case 6 :
1269 				ptr = ipf_nat6_lookupredir(&nl);
1270 				break;
1271 #endif
1272 			default:
1273 				ptr = NULL;
1274 				break;
1275 			}
1276 
1277 			if (getlock) {
1278 				RWLOCK_EXIT(&softc->ipf_nat);
1279 			}
1280 			if (ptr != NULL) {
1281 				error = ipf_outobj(softc, data, &nl,
1282 						   IPFOBJ_NATLOOKUP);
1283 			} else {
1284 				IPFERROR(60011);
1285 				error = ESRCH;
1286 			}
1287 		}
1288 		break;
1289 	    }
1290 
1291 	case SIOCIPFFL :	/* old SIOCFLNAT & SIOCCNATL */
1292 		if (!(mode & FWRITE)) {
1293 			IPFERROR(60012);
1294 			error = EPERM;
1295 			break;
1296 		}
1297 		if (getlock) {
1298 			WRITE_ENTER(&softc->ipf_nat);
1299 		}
1300 
1301 		error = BCOPYIN(data, &arg, sizeof(arg));
1302 		if (error != 0) {
1303 			IPFERROR(60013);
1304 			error = EFAULT;
1305 		} else {
1306 			if (arg == 0)
1307 				ret = ipf_nat_flushtable(softc, softn);
1308 			else if (arg == 1)
1309 				ret = ipf_nat_clearlist(softc, softn);
1310 			else
1311 				ret = ipf_nat_extraflush(softc, softn, arg);
1312 			ipf_proxy_flush(softc->ipf_proxy_soft, arg);
1313 		}
1314 
1315 		if (getlock) {
1316 			RWLOCK_EXIT(&softc->ipf_nat);
1317 		}
1318 		if (error == 0) {
1319 			error = BCOPYOUT(&ret, data, sizeof(ret));
1320 		}
1321 		break;
1322 
1323 	case SIOCMATCHFLUSH :
1324 		if (!(mode & FWRITE)) {
1325 			IPFERROR(60014);
1326 			error = EPERM;
1327 			break;
1328 		}
1329 		if (getlock) {
1330 			WRITE_ENTER(&softc->ipf_nat);
1331 		}
1332 
1333 		error = ipf_nat_matchflush(softc, softn, data);
1334 
1335 		if (getlock) {
1336 			RWLOCK_EXIT(&softc->ipf_nat);
1337 		}
1338 		break;
1339 
1340 	case SIOCPROXY :
1341 		error = ipf_proxy_ioctl(softc, data, cmd, mode, ctx);
1342 		break;
1343 
1344 	case SIOCSTLCK :
1345 		if (!(mode & FWRITE)) {
1346 			IPFERROR(60015);
1347 			error = EPERM;
1348 		} else {
1349 			error = ipf_lock(data, &softn->ipf_nat_lock);
1350 		}
1351 		break;
1352 
1353 	case SIOCSTPUT :
1354 		if ((mode & FWRITE) != 0) {
1355 			error = ipf_nat_putent(softc, data, getlock);
1356 		} else {
1357 			IPFERROR(60016);
1358 			error = EACCES;
1359 		}
1360 		break;
1361 
1362 	case SIOCSTGSZ :
1363 		if (softn->ipf_nat_lock) {
1364 			error = ipf_nat_getsz(softc, data, getlock);
1365 		} else {
1366 			IPFERROR(60017);
1367 			error = EACCES;
1368 		}
1369 		break;
1370 
1371 	case SIOCSTGET :
1372 		if (softn->ipf_nat_lock) {
1373 			error = ipf_nat_getent(softc, data, getlock);
1374 		} else {
1375 			IPFERROR(60018);
1376 			error = EACCES;
1377 		}
1378 		break;
1379 
1380 	case SIOCGENITER :
1381 	    {
1382 		ipfgeniter_t iter;
1383 		ipftoken_t *token;
1384 		ipfobj_t obj;
1385 
1386 		error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER);
1387 		if (error != 0)
1388 			break;
1389 
1390 		SPL_SCHED(s);
1391 		token = ipf_token_find(softc, iter.igi_type, uid, ctx);
1392 		if (token != NULL) {
1393 			error  = ipf_nat_iterator(softc, token, &iter, &obj);
1394 			WRITE_ENTER(&softc->ipf_tokens);
1395 			ipf_token_deref(softc, token);
1396 			RWLOCK_EXIT(&softc->ipf_tokens);
1397 		}
1398 		SPL_X(s);
1399 		break;
1400 	    }
1401 
1402 	case SIOCIPFDELTOK :
1403 		error = BCOPYIN(data, &arg, sizeof(arg));
1404 		if (error == 0) {
1405 			SPL_SCHED(s);
1406 			error = ipf_token_del(softc, arg, uid, ctx);
1407 			SPL_X(s);
1408 		} else {
1409 			IPFERROR(60019);
1410 			error = EFAULT;
1411 		}
1412 		break;
1413 
1414 	case SIOCGTQTAB :
1415 		error = ipf_outobj(softc, data, softn->ipf_nat_tcptq,
1416 				   IPFOBJ_STATETQTAB);
1417 		break;
1418 
1419 	case SIOCGTABL :
1420 		error = ipf_nat_gettable(softc, softn, data);
1421 		break;
1422 
1423 	default :
1424 		IPFERROR(60020);
1425 		error = EINVAL;
1426 		break;
1427 	}
1428 done:
1429 	if (nat != NULL)
1430 		ipf_nat_rule_fini(softc, nat);
1431 	if (nt != NULL)
1432 		KFREES(nt, nt->in_size);
1433 	return error;
1434 }
1435 
1436 
1437 /* ------------------------------------------------------------------------ */
1438 /* Function:    ipf_nat_siocaddnat                                          */
1439 /* Returns:     int - 0 == success, != 0 == failure                         */
1440 /* Parameters:  softc(I) - pointer to soft context main structure           */
1441 /*              softn(I) - pointer to NAT context structure                 */
1442 /*              n(I)       - pointer to new NAT rule                        */
1443 /*              np(I)      - pointer to where to insert new NAT rule        */
1444 /*              getlock(I) - flag indicating if lock on  is held            */
1445 /* Mutex Locks: ipf_nat_io                                                   */
1446 /*                                                                          */
1447 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
1448 /* from information passed to the kernel, then add it  to the appropriate   */
1449 /* NAT rule table(s).                                                       */
1450 /* ------------------------------------------------------------------------ */
1451 static int
ipf_nat_siocaddnat(softc,softn,n,getlock)1452 ipf_nat_siocaddnat(softc, softn, n, getlock)
1453 	ipf_main_softc_t *softc;
1454 	ipf_nat_softc_t *softn;
1455 	ipnat_t *n;
1456 	int getlock;
1457 {
1458 	int error = 0;
1459 
1460 	if (ipf_nat_resolverule(softc, n) != 0) {
1461 		IPFERROR(60022);
1462 		return ENOENT;
1463 	}
1464 
1465 	if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) {
1466 		IPFERROR(60023);
1467 		return EINVAL;
1468 	}
1469 
1470 	if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) {
1471 		/*
1472 		 * Prerecord whether or not the destination of the divert
1473 		 * is local or not to the interface the packet is going
1474 		 * to be sent out.
1475 		 */
1476 		n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1],
1477 						n->in_ifps[1], &n->in_ndstip6);
1478 	}
1479 
1480 	if (getlock) {
1481 		WRITE_ENTER(&softc->ipf_nat);
1482 	}
1483 	n->in_next = NULL;
1484 	n->in_pnext = softn->ipf_nat_list_tail;
1485 	*n->in_pnext = n;
1486 	softn->ipf_nat_list_tail = &n->in_next;
1487 	n->in_use++;
1488 
1489 	if (n->in_redir & NAT_REDIRECT) {
1490 		n->in_flags &= ~IPN_NOTDST;
1491 		switch (n->in_v[0])
1492 		{
1493 		case 4 :
1494 			ipf_nat_addrdr(softn, n);
1495 			break;
1496 #ifdef USE_INET6
1497 		case 6 :
1498 			ipf_nat6_addrdr(softn, n);
1499 			break;
1500 #endif
1501 		default :
1502 			break;
1503 		}
1504 		ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_rdr);
1505 	}
1506 
1507 	if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
1508 		n->in_flags &= ~IPN_NOTSRC;
1509 		switch (n->in_v[0])
1510 		{
1511 		case 4 :
1512 			ipf_nat_addmap(softn, n);
1513 			break;
1514 #ifdef USE_INET6
1515 		case 6 :
1516 			ipf_nat6_addmap(softn, n);
1517 			break;
1518 #endif
1519 		default :
1520 			break;
1521 		}
1522 		ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_map);
1523 	}
1524 
1525 	if (n->in_age[0] != 0)
1526 		n->in_tqehead[0] = ipf_addtimeoutqueue(softc,
1527 						       &softn->ipf_nat_utqe,
1528 						       n->in_age[0]);
1529 
1530 	if (n->in_age[1] != 0)
1531 		n->in_tqehead[1] = ipf_addtimeoutqueue(softc,
1532 						       &softn->ipf_nat_utqe,
1533 						       n->in_age[1]);
1534 
1535 	MUTEX_INIT(&n->in_lock, "ipnat rule lock");
1536 
1537 	n = NULL;
1538 	ATOMIC_INC32(softn->ipf_nat_stats.ns_rules);
1539 #if SOLARIS && !defined(INSTANCES)
1540 	pfil_delayed_copy = 0;
1541 #endif
1542 	if (getlock) {
1543 		RWLOCK_EXIT(&softc->ipf_nat);			/* WRITE */
1544 	}
1545 
1546 	return error;
1547 }
1548 
1549 
1550 /* ------------------------------------------------------------------------ */
1551 /* Function:    ipf_nat_ruleaddrinit                                        */
1552 /* Parameters:  softc(I) - pointer to soft context main structure           */
1553 /*              softn(I) - pointer to NAT context structure                 */
1554 /*              n(I)     - pointer to NAT rule                              */
1555 /*                                                                          */
1556 /* Initialise all of the NAT address structures in a NAT rule.              */
1557 /* ------------------------------------------------------------------------ */
1558 static int
ipf_nat_ruleaddrinit(softc,softn,n)1559 ipf_nat_ruleaddrinit(softc, softn, n)
1560 	ipf_main_softc_t *softc;
1561 	ipf_nat_softc_t *softn;
1562 	ipnat_t *n;
1563 {
1564 	int idx, error;
1565 
1566 	if ((n->in_ndst.na_atype == FRI_LOOKUP) &&
1567 	    (n->in_ndst.na_type != IPLT_DSTLIST)) {
1568 		IPFERROR(60071);
1569 		return EINVAL;
1570 	}
1571 	if ((n->in_nsrc.na_atype == FRI_LOOKUP) &&
1572 	    (n->in_nsrc.na_type != IPLT_DSTLIST)) {
1573 		IPFERROR(60069);
1574 		return EINVAL;
1575 	}
1576 
1577 	if (n->in_redir == NAT_BIMAP) {
1578 		n->in_ndstaddr = n->in_osrcaddr;
1579 		n->in_ndstmsk = n->in_osrcmsk;
1580 		n->in_odstaddr = n->in_nsrcaddr;
1581 		n->in_odstmsk = n->in_nsrcmsk;
1582 
1583 	}
1584 
1585 	if (n->in_redir & NAT_REDIRECT)
1586 		idx = 1;
1587 	else
1588 		idx = 0;
1589 	/*
1590 	 * Initialise all of the address fields.
1591 	 */
1592 	error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc, 1,
1593 				     n->in_ifps[idx]);
1594 	if (error != 0)
1595 		return error;
1596 
1597 	error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst, 1,
1598 				     n->in_ifps[idx]);
1599 	if (error != 0)
1600 		return error;
1601 
1602 	error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc, 1,
1603 				     n->in_ifps[idx]);
1604 	if (error != 0)
1605 		return error;
1606 
1607 	error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst, 1,
1608 				     n->in_ifps[idx]);
1609 	if (error != 0)
1610 		return error;
1611 
1612 	if (n->in_redir & NAT_DIVERTUDP)
1613 		ipf_nat_builddivertmp(softn, n);
1614 
1615 	return 0;
1616 }
1617 
1618 
1619 /* ------------------------------------------------------------------------ */
1620 /* Function:    ipf_nat_resolvrule                                          */
1621 /* Returns:     Nil                                                         */
1622 /* Parameters:  softc(I) - pointer to soft context main structure           */
1623 /*              n(I)     - pointer to NAT rule                              */
1624 /*                                                                          */
1625 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
1626 /* from information passed to the kernel, then add it  to the appropriate   */
1627 /* NAT rule table(s).                                                       */
1628 /* ------------------------------------------------------------------------ */
1629 static int
ipf_nat_resolverule(softc,n)1630 ipf_nat_resolverule(softc, n)
1631 	ipf_main_softc_t *softc;
1632 	ipnat_t *n;
1633 {
1634 	char *base;
1635 
1636 	base = n->in_names;
1637 
1638 	n->in_ifps[0] = ipf_resolvenic(softc, base + n->in_ifnames[0],
1639 				       n->in_v[0]);
1640 
1641 	if (n->in_ifnames[1] == -1) {
1642 		n->in_ifnames[1] = n->in_ifnames[0];
1643 		n->in_ifps[1] = n->in_ifps[0];
1644 	} else {
1645 		n->in_ifps[1] = ipf_resolvenic(softc, base + n->in_ifnames[1],
1646 					       n->in_v[1]);
1647 	}
1648 
1649 	if (n->in_plabel != -1) {
1650 		if (n->in_redir & NAT_REDIRECT)
1651 			n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft,
1652 						     n->in_pr[0],
1653 						     base + n->in_plabel);
1654 		else
1655 			n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft,
1656 						     n->in_pr[1],
1657 						     base + n->in_plabel);
1658 		if (n->in_apr == NULL)
1659 			return -1;
1660 	}
1661 	return 0;
1662 }
1663 
1664 
1665 /* ------------------------------------------------------------------------ */
1666 /* Function:    ipf_nat_siocdelnat                                          */
1667 /* Returns:     int - 0 == success, != 0 == failure                         */
1668 /* Parameters:  softc(I)   - pointer to soft context main structure         */
1669 /*              softn(I)   - pointer to NAT context structure               */
1670 /*              n(I)       - pointer to new NAT rule                        */
1671 /*              getlock(I) - flag indicating if lock on  is held            */
1672 /* Mutex Locks: ipf_nat_io                                                  */
1673 /*                                                                          */
1674 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
1675 /* from information passed to the kernel, then add it  to the appropriate   */
1676 /* NAT rule table(s).                                                       */
1677 /* ------------------------------------------------------------------------ */
1678 static void
ipf_nat_siocdelnat(softc,softn,n,getlock)1679 ipf_nat_siocdelnat(softc, softn, n, getlock)
1680 	ipf_main_softc_t *softc;
1681 	ipf_nat_softc_t *softn;
1682 	ipnat_t *n;
1683 	int getlock;
1684 {
1685 	if (getlock) {
1686 		WRITE_ENTER(&softc->ipf_nat);
1687 	}
1688 
1689 	ipf_nat_delrule(softc, softn, n, 1);
1690 
1691 	if (getlock) {
1692 		RWLOCK_EXIT(&softc->ipf_nat);			/* READ/WRITE */
1693 	}
1694 }
1695 
1696 
1697 /* ------------------------------------------------------------------------ */
1698 /* Function:    ipf_nat_getsz                                               */
1699 /* Returns:     int - 0 == success, != 0 is the error value.                */
1700 /* Parameters:  softc(I)   - pointer to soft context main structure         */
1701 /*              data(I)    - pointer to natget structure with kernel        */
1702 /*                           pointer get the size of.                       */
1703 /*              getlock(I) - flag indicating whether or not the caller      */
1704 /*                           holds a lock on ipf_nat                        */
1705 /*                                                                          */
1706 /* Handle SIOCSTGSZ.                                                        */
1707 /* Return the size of the nat list entry to be copied back to user space.   */
1708 /* The size of the entry is stored in the ng_sz field and the enture natget */
1709 /* structure is copied back to the user.                                    */
1710 /* ------------------------------------------------------------------------ */
1711 static int
ipf_nat_getsz(softc,data,getlock)1712 ipf_nat_getsz(softc, data, getlock)
1713 	ipf_main_softc_t *softc;
1714 	caddr_t data;
1715 	int getlock;
1716 {
1717 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1718 	ap_session_t *aps;
1719 	nat_t *nat, *n;
1720 	natget_t ng;
1721 	int error;
1722 
1723 	error = BCOPYIN(data, &ng, sizeof(ng));
1724 	if (error != 0) {
1725 		IPFERROR(60024);
1726 		return EFAULT;
1727 	}
1728 
1729 	if (getlock) {
1730 		READ_ENTER(&softc->ipf_nat);
1731 	}
1732 
1733 	nat = ng.ng_ptr;
1734 	if (!nat) {
1735 		nat = softn->ipf_nat_instances;
1736 		ng.ng_sz = 0;
1737 		/*
1738 		 * Empty list so the size returned is 0.  Simple.
1739 		 */
1740 		if (nat == NULL) {
1741 			if (getlock) {
1742 				RWLOCK_EXIT(&softc->ipf_nat);
1743 			}
1744 			error = BCOPYOUT(&ng, data, sizeof(ng));
1745 			if (error != 0) {
1746 				IPFERROR(60025);
1747 				return EFAULT;
1748 			}
1749 			return 0;
1750 		}
1751 	} else {
1752 		/*
1753 		 * Make sure the pointer we're copying from exists in the
1754 		 * current list of entries.  Security precaution to prevent
1755 		 * copying of random kernel data.
1756 		 */
1757 		for (n = softn->ipf_nat_instances; n; n = n->nat_next)
1758 			if (n == nat)
1759 				break;
1760 		if (n == NULL) {
1761 			if (getlock) {
1762 				RWLOCK_EXIT(&softc->ipf_nat);
1763 			}
1764 			IPFERROR(60026);
1765 			return ESRCH;
1766 		}
1767 	}
1768 
1769 	/*
1770 	 * Incluse any space required for proxy data structures.
1771 	 */
1772 	ng.ng_sz = sizeof(nat_save_t);
1773 	aps = nat->nat_aps;
1774 	if (aps != NULL) {
1775 		ng.ng_sz += sizeof(ap_session_t) - 4;
1776 		if (aps->aps_data != 0)
1777 			ng.ng_sz += aps->aps_psiz;
1778 	}
1779 	if (getlock) {
1780 		RWLOCK_EXIT(&softc->ipf_nat);
1781 	}
1782 
1783 	error = BCOPYOUT(&ng, data, sizeof(ng));
1784 	if (error != 0) {
1785 		IPFERROR(60027);
1786 		return EFAULT;
1787 	}
1788 	return 0;
1789 }
1790 
1791 
1792 /* ------------------------------------------------------------------------ */
1793 /* Function:    ipf_nat_getent                                              */
1794 /* Returns:     int - 0 == success, != 0 is the error value.                */
1795 /* Parameters:  softc(I)   - pointer to soft context main structure         */
1796 /*              data(I)    - pointer to natget structure with kernel pointer*/
1797 /*                           to NAT structure to copy out.                  */
1798 /*              getlock(I) - flag indicating whether or not the caller      */
1799 /*                           holds a lock on ipf_nat                        */
1800 /*                                                                          */
1801 /* Handle SIOCSTGET.                                                        */
1802 /* Copies out NAT entry to user space.  Any additional data held for a      */
1803 /* proxy is also copied, as to is the NAT rule which was responsible for it */
1804 /* ------------------------------------------------------------------------ */
1805 static int
ipf_nat_getent(softc,data,getlock)1806 ipf_nat_getent(softc, data, getlock)
1807 	ipf_main_softc_t *softc;
1808 	caddr_t data;
1809 	int getlock;
1810 {
1811 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1812 	int error, outsize;
1813 	ap_session_t *aps;
1814 	nat_save_t *ipn, ipns;
1815 	nat_t *n, *nat;
1816 
1817 	error = ipf_inobj(softc, data, NULL, &ipns, IPFOBJ_NATSAVE);
1818 	if (error != 0)
1819 		return error;
1820 
1821 	if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) {
1822 		IPFERROR(60028);
1823 		return EINVAL;
1824 	}
1825 
1826 	KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize);
1827 	if (ipn == NULL) {
1828 		IPFERROR(60029);
1829 		return ENOMEM;
1830 	}
1831 
1832 	if (getlock) {
1833 		READ_ENTER(&softc->ipf_nat);
1834 	}
1835 
1836 	ipn->ipn_dsize = ipns.ipn_dsize;
1837 	nat = ipns.ipn_next;
1838 	if (nat == NULL) {
1839 		nat = softn->ipf_nat_instances;
1840 		if (nat == NULL) {
1841 			if (softn->ipf_nat_instances == NULL) {
1842 				IPFERROR(60030);
1843 				error = ENOENT;
1844 			}
1845 			goto finished;
1846 		}
1847 	} else {
1848 		/*
1849 		 * Make sure the pointer we're copying from exists in the
1850 		 * current list of entries.  Security precaution to prevent
1851 		 * copying of random kernel data.
1852 		 */
1853 		for (n = softn->ipf_nat_instances; n; n = n->nat_next)
1854 			if (n == nat)
1855 				break;
1856 		if (n == NULL) {
1857 			IPFERROR(60031);
1858 			error = ESRCH;
1859 			goto finished;
1860 		}
1861 	}
1862 	ipn->ipn_next = nat->nat_next;
1863 
1864 	/*
1865 	 * Copy the NAT structure.
1866 	 */
1867 	bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat));
1868 
1869 	/*
1870 	 * If we have a pointer to the NAT rule it belongs to, save that too.
1871 	 */
1872 	if (nat->nat_ptr != NULL)
1873 		bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat,
1874 		      ipn->ipn_ipnat.in_size);
1875 
1876 	/*
1877 	 * If we also know the NAT entry has an associated filter rule,
1878 	 * save that too.
1879 	 */
1880 	if (nat->nat_fr != NULL)
1881 		bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr,
1882 		      sizeof(ipn->ipn_fr));
1883 
1884 	/*
1885 	 * Last but not least, if there is an application proxy session set
1886 	 * up for this NAT entry, then copy that out too, including any
1887 	 * private data saved along side it by the proxy.
1888 	 */
1889 	aps = nat->nat_aps;
1890 	outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data);
1891 	if (aps != NULL) {
1892 		char *s;
1893 
1894 		if (outsize < sizeof(*aps)) {
1895 			IPFERROR(60032);
1896 			error = ENOBUFS;
1897 			goto finished;
1898 		}
1899 
1900 		s = ipn->ipn_data;
1901 		bcopy((char *)aps, s, sizeof(*aps));
1902 		s += sizeof(*aps);
1903 		outsize -= sizeof(*aps);
1904 		if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz))
1905 			bcopy(aps->aps_data, s, aps->aps_psiz);
1906 		else {
1907 			IPFERROR(60033);
1908 			error = ENOBUFS;
1909 		}
1910 	}
1911 	if (error == 0) {
1912 		error = ipf_outobjsz(softc, data, ipn, IPFOBJ_NATSAVE,
1913 				     ipns.ipn_dsize);
1914 	}
1915 
1916 finished:
1917 	if (ipn != NULL) {
1918 		KFREES(ipn, ipns.ipn_dsize);
1919 	}
1920 	if (getlock) {
1921 		RWLOCK_EXIT(&softc->ipf_nat);
1922 	}
1923 	return error;
1924 }
1925 
1926 
1927 /* ------------------------------------------------------------------------ */
1928 /* Function:    ipf_nat_putent                                              */
1929 /* Returns:     int - 0 == success, != 0 is the error value.                */
1930 /* Parameters:  softc(I)   - pointer to soft context main structure         */
1931 /*              data(I)    - pointer to natget structure with NAT           */
1932 /*                           structure information to load into the kernel  */
1933 /*              getlock(I) - flag indicating whether or not a write lock    */
1934 /*                           on is already held.                            */
1935 /*                                                                          */
1936 /* Handle SIOCSTPUT.                                                        */
1937 /* Loads a NAT table entry from user space, including a NAT rule, proxy and */
1938 /* firewall rule data structures, if pointers to them indicate so.          */
1939 /* ------------------------------------------------------------------------ */
1940 static int
ipf_nat_putent(softc,data,getlock)1941 ipf_nat_putent(softc, data, getlock)
1942 	ipf_main_softc_t *softc;
1943 	caddr_t data;
1944 	int getlock;
1945 {
1946 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1947 	nat_save_t ipn, *ipnn;
1948 	ap_session_t *aps;
1949 	nat_t *n, *nat;
1950 	frentry_t *fr;
1951 	fr_info_t fin;
1952 	ipnat_t *in;
1953 	int error;
1954 
1955 	error = ipf_inobj(softc, data, NULL, &ipn, IPFOBJ_NATSAVE);
1956 	if (error != 0)
1957 		return error;
1958 
1959 	/*
1960 	 * Initialise early because of code at junkput label.
1961 	 */
1962 	n = NULL;
1963 	in = NULL;
1964 	aps = NULL;
1965 	nat = NULL;
1966 	ipnn = NULL;
1967 	fr = NULL;
1968 
1969 	/*
1970 	 * New entry, copy in the rest of the NAT entry if it's size is more
1971 	 * than just the nat_t structure.
1972 	 */
1973 	if (ipn.ipn_dsize > sizeof(ipn)) {
1974 		if (ipn.ipn_dsize > 81920) {
1975 			IPFERROR(60034);
1976 			error = ENOMEM;
1977 			goto junkput;
1978 		}
1979 
1980 		KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize);
1981 		if (ipnn == NULL) {
1982 			IPFERROR(60035);
1983 			return ENOMEM;
1984 		}
1985 
1986 		bzero(ipnn, ipn.ipn_dsize);
1987 		error = ipf_inobjsz(softc, data, ipnn, IPFOBJ_NATSAVE,
1988 				    ipn.ipn_dsize);
1989 		if (error != 0) {
1990 			goto junkput;
1991 		}
1992 	} else
1993 		ipnn = &ipn;
1994 
1995 	KMALLOC(nat, nat_t *);
1996 	if (nat == NULL) {
1997 		IPFERROR(60037);
1998 		error = ENOMEM;
1999 		goto junkput;
2000 	}
2001 
2002 	bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat));
2003 
2004 	switch (nat->nat_v[0])
2005 	{
2006 	case 4:
2007 #ifdef USE_INET6
2008 	case 6 :
2009 #endif
2010 		break;
2011 	default :
2012 		IPFERROR(60061);
2013 		error = EPROTONOSUPPORT;
2014 		goto junkput;
2015 		/*NOTREACHED*/
2016 	}
2017 
2018 	/*
2019 	 * Initialize all these so that ipf_nat_delete() doesn't cause a crash.
2020 	 */
2021 	bzero((char *)nat, offsetof(struct nat, nat_tqe));
2022 	nat->nat_tqe.tqe_pnext = NULL;
2023 	nat->nat_tqe.tqe_next = NULL;
2024 	nat->nat_tqe.tqe_ifq = NULL;
2025 	nat->nat_tqe.tqe_parent = nat;
2026 
2027 	/*
2028 	 * Restore the rule associated with this nat session
2029 	 */
2030 	in = ipnn->ipn_nat.nat_ptr;
2031 	if (in != NULL) {
2032 		KMALLOCS(in, ipnat_t *, ipnn->ipn_ipnat.in_size);
2033 		nat->nat_ptr = in;
2034 		if (in == NULL) {
2035 			IPFERROR(60038);
2036 			error = ENOMEM;
2037 			goto junkput;
2038 		}
2039 		bcopy((char *)&ipnn->ipn_ipnat, (char *)in,
2040 		      ipnn->ipn_ipnat.in_size);
2041 		in->in_use = 1;
2042 		in->in_flags |= IPN_DELETE;
2043 
2044 		ATOMIC_INC32(softn->ipf_nat_stats.ns_rules);
2045 
2046 		if (ipf_nat_resolverule(softc, in) != 0) {
2047 			IPFERROR(60039);
2048 			error = ESRCH;
2049 			goto junkput;
2050 		}
2051 	}
2052 
2053 	/*
2054 	 * Check that the NAT entry doesn't already exist in the kernel.
2055 	 *
2056 	 * For NAT_OUTBOUND, we're lookup for a duplicate MAP entry.  To do
2057 	 * this, we check to see if the inbound combination of addresses and
2058 	 * ports is already known.  Similar logic is applied for NAT_INBOUND.
2059 	 *
2060 	 */
2061 	bzero((char *)&fin, sizeof(fin));
2062 	fin.fin_v = nat->nat_v[0];
2063 	fin.fin_p = nat->nat_pr[0];
2064 	fin.fin_rev = nat->nat_rev;
2065 	fin.fin_ifp = nat->nat_ifps[0];
2066 	fin.fin_data[0] = ntohs(nat->nat_ndport);
2067 	fin.fin_data[1] = ntohs(nat->nat_nsport);
2068 
2069 	switch (nat->nat_dir)
2070 	{
2071 	case NAT_OUTBOUND :
2072 	case NAT_DIVERTOUT :
2073 		if (getlock) {
2074 			READ_ENTER(&softc->ipf_nat);
2075 		}
2076 
2077 		fin.fin_v = nat->nat_v[1];
2078 		if (nat->nat_v[1] == 4) {
2079 			n = ipf_nat_inlookup(&fin, nat->nat_flags, fin.fin_p,
2080 					     nat->nat_ndstip, nat->nat_nsrcip);
2081 #ifdef USE_INET6
2082 		} else if (nat->nat_v[1] == 6) {
2083 			n = ipf_nat6_inlookup(&fin, nat->nat_flags, fin.fin_p,
2084 					      &nat->nat_ndst6.in6,
2085 					      &nat->nat_nsrc6.in6);
2086 #endif
2087 		}
2088 
2089 		if (getlock) {
2090 			RWLOCK_EXIT(&softc->ipf_nat);
2091 		}
2092 		if (n != NULL) {
2093 			IPFERROR(60040);
2094 			error = EEXIST;
2095 			goto junkput;
2096 		}
2097 		break;
2098 
2099 	case NAT_INBOUND :
2100 	case NAT_DIVERTIN :
2101 		if (getlock) {
2102 			READ_ENTER(&softc->ipf_nat);
2103 		}
2104 
2105 		if (fin.fin_v == 4) {
2106 			n = ipf_nat_outlookup(&fin, nat->nat_flags, fin.fin_p,
2107 					      nat->nat_ndstip,
2108 					      nat->nat_nsrcip);
2109 #ifdef USE_INET6
2110 		} else if (fin.fin_v == 6) {
2111 			n = ipf_nat6_outlookup(&fin, nat->nat_flags, fin.fin_p,
2112 					       &nat->nat_ndst6.in6,
2113 					       &nat->nat_nsrc6.in6);
2114 #endif
2115 		}
2116 
2117 		if (getlock) {
2118 			RWLOCK_EXIT(&softc->ipf_nat);
2119 		}
2120 		if (n != NULL) {
2121 			IPFERROR(60041);
2122 			error = EEXIST;
2123 			goto junkput;
2124 		}
2125 		break;
2126 
2127 	default :
2128 		IPFERROR(60042);
2129 		error = EINVAL;
2130 		goto junkput;
2131 	}
2132 
2133 	/*
2134 	 * Restore ap_session_t structure.  Include the private data allocated
2135 	 * if it was there.
2136 	 */
2137 	aps = nat->nat_aps;
2138 	if (aps != NULL) {
2139 		KMALLOC(aps, ap_session_t *);
2140 		nat->nat_aps = aps;
2141 		if (aps == NULL) {
2142 			IPFERROR(60043);
2143 			error = ENOMEM;
2144 			goto junkput;
2145 		}
2146 		bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps));
2147 		if (in != NULL)
2148 			aps->aps_apr = in->in_apr;
2149 		else
2150 			aps->aps_apr = NULL;
2151 		if (aps->aps_psiz != 0) {
2152 			if (aps->aps_psiz > 81920) {
2153 				IPFERROR(60044);
2154 				error = ENOMEM;
2155 				goto junkput;
2156 			}
2157 			KMALLOCS(aps->aps_data, void *, aps->aps_psiz);
2158 			if (aps->aps_data == NULL) {
2159 				IPFERROR(60045);
2160 				error = ENOMEM;
2161 				goto junkput;
2162 			}
2163 			bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data,
2164 			      aps->aps_psiz);
2165 		} else {
2166 			aps->aps_psiz = 0;
2167 			aps->aps_data = NULL;
2168 		}
2169 	}
2170 
2171 	/*
2172 	 * If there was a filtering rule associated with this entry then
2173 	 * build up a new one.
2174 	 */
2175 	fr = nat->nat_fr;
2176 	if (fr != NULL) {
2177 		if ((nat->nat_flags & SI_NEWFR) != 0) {
2178 			KMALLOC(fr, frentry_t *);
2179 			nat->nat_fr = fr;
2180 			if (fr == NULL) {
2181 				IPFERROR(60046);
2182 				error = ENOMEM;
2183 				goto junkput;
2184 			}
2185 			ipnn->ipn_nat.nat_fr = fr;
2186 			fr->fr_ref = 1;
2187 			(void) ipf_outobj(softc, data, ipnn, IPFOBJ_NATSAVE);
2188 			bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr));
2189 
2190 			fr->fr_ref = 1;
2191 			fr->fr_dsize = 0;
2192 			fr->fr_data = NULL;
2193 			fr->fr_type = FR_T_NONE;
2194 
2195 			MUTEX_NUKE(&fr->fr_lock);
2196 			MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock");
2197 		} else {
2198 			if (getlock) {
2199 				READ_ENTER(&softc->ipf_nat);
2200 			}
2201 			for (n = softn->ipf_nat_instances; n; n = n->nat_next)
2202 				if (n->nat_fr == fr)
2203 					break;
2204 
2205 			if (n != NULL) {
2206 				MUTEX_ENTER(&fr->fr_lock);
2207 				fr->fr_ref++;
2208 				MUTEX_EXIT(&fr->fr_lock);
2209 			}
2210 			if (getlock) {
2211 				RWLOCK_EXIT(&softc->ipf_nat);
2212 			}
2213 
2214 			if (n == NULL) {
2215 				IPFERROR(60047);
2216 				error = ESRCH;
2217 				goto junkput;
2218 			}
2219 		}
2220 	}
2221 
2222 	if (ipnn != &ipn) {
2223 		KFREES(ipnn, ipn.ipn_dsize);
2224 		ipnn = NULL;
2225 	}
2226 
2227 	if (getlock) {
2228 		WRITE_ENTER(&softc->ipf_nat);
2229 	}
2230 
2231 	if (fin.fin_v == 4)
2232 		error = ipf_nat_finalise(&fin, nat);
2233 #ifdef USE_INET6
2234 	else
2235 		error = ipf_nat6_finalise(&fin, nat);
2236 #endif
2237 
2238 	if (getlock) {
2239 		RWLOCK_EXIT(&softc->ipf_nat);
2240 	}
2241 
2242 	if (error == 0)
2243 		return 0;
2244 
2245 	IPFERROR(60048);
2246 	error = ENOMEM;
2247 
2248 junkput:
2249 	if (fr != NULL) {
2250 		(void) ipf_derefrule(softc, &fr);
2251 	}
2252 
2253 	if ((ipnn != NULL) && (ipnn != &ipn)) {
2254 		KFREES(ipnn, ipn.ipn_dsize);
2255 	}
2256 	if (nat != NULL) {
2257 		if (aps != NULL) {
2258 			if (aps->aps_data != NULL) {
2259 				KFREES(aps->aps_data, aps->aps_psiz);
2260 			}
2261 			KFREE(aps);
2262 		}
2263 		if (in != NULL) {
2264 			if (in->in_apr)
2265 				ipf_proxy_deref(in->in_apr);
2266 			KFREES(in, in->in_size);
2267 		}
2268 		KFREE(nat);
2269 	}
2270 	return error;
2271 }
2272 
2273 
2274 /* ------------------------------------------------------------------------ */
2275 /* Function:    ipf_nat_delete                                              */
2276 /* Returns:     Nil                                                         */
2277 /* Parameters:  softc(I)   - pointer to soft context main structure         */
2278 /*              nat(I)     - pointer to NAT structure to delete             */
2279 /*              logtype(I) - type of LOG record to create before deleting   */
2280 /* Write Lock:  ipf_nat                                                     */
2281 /*                                                                          */
2282 /* Delete a nat entry from the various lists and table.  If NAT logging is  */
2283 /* enabled then generate a NAT log record for this event.                   */
2284 /* ------------------------------------------------------------------------ */
2285 void
ipf_nat_delete(softc,nat,logtype)2286 ipf_nat_delete(softc, nat, logtype)
2287 	ipf_main_softc_t *softc;
2288 	struct nat *nat;
2289 	int logtype;
2290 {
2291 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2292 	int madeorphan = 0, bkt, removed = 0;
2293 	nat_stat_side_t *nss;
2294 	struct ipnat *ipn;
2295 
2296 	if (logtype != 0 && softn->ipf_nat_logging != 0)
2297 		ipf_nat_log(softc, softn, nat, logtype);
2298 
2299 	/*
2300 	 * Take it as a general indication that all the pointers are set if
2301 	 * nat_pnext is set.
2302 	 */
2303 	if (nat->nat_pnext != NULL) {
2304 		removed = 1;
2305 
2306 		bkt = nat->nat_hv[0] % softn->ipf_nat_table_sz;
2307 		nss = &softn->ipf_nat_stats.ns_side[0];
2308 		if (nss->ns_bucketlen[bkt] > 0)
2309 			nss->ns_bucketlen[bkt]--;
2310 		if (nss->ns_bucketlen[bkt] == 0) {
2311 			nss->ns_inuse--;
2312 		}
2313 
2314 		bkt = nat->nat_hv[1] % softn->ipf_nat_table_sz;
2315 		nss = &softn->ipf_nat_stats.ns_side[1];
2316 		if (nss->ns_bucketlen[bkt] > 0)
2317 			nss->ns_bucketlen[bkt]--;
2318 		if (nss->ns_bucketlen[bkt] == 0) {
2319 			nss->ns_inuse--;
2320 		}
2321 
2322 		*nat->nat_pnext = nat->nat_next;
2323 		if (nat->nat_next != NULL) {
2324 			nat->nat_next->nat_pnext = nat->nat_pnext;
2325 			nat->nat_next = NULL;
2326 		}
2327 		nat->nat_pnext = NULL;
2328 
2329 		*nat->nat_phnext[0] = nat->nat_hnext[0];
2330 		if (nat->nat_hnext[0] != NULL) {
2331 			nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
2332 			nat->nat_hnext[0] = NULL;
2333 		}
2334 		nat->nat_phnext[0] = NULL;
2335 
2336 		*nat->nat_phnext[1] = nat->nat_hnext[1];
2337 		if (nat->nat_hnext[1] != NULL) {
2338 			nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
2339 			nat->nat_hnext[1] = NULL;
2340 		}
2341 		nat->nat_phnext[1] = NULL;
2342 
2343 		if ((nat->nat_flags & SI_WILDP) != 0) {
2344 			ATOMIC_DEC32(softn->ipf_nat_stats.ns_wilds);
2345 		}
2346 		madeorphan = 1;
2347 	}
2348 
2349 	if (nat->nat_me != NULL) {
2350 		*nat->nat_me = NULL;
2351 		nat->nat_me = NULL;
2352 		nat->nat_ref--;
2353 		ASSERT(nat->nat_ref >= 0);
2354 	}
2355 
2356 	if (nat->nat_tqe.tqe_ifq != NULL) {
2357 		/*
2358 		 * No call to ipf_freetimeoutqueue() is made here, they are
2359 		 * garbage collected in ipf_nat_expire().
2360 		 */
2361 		(void) ipf_deletequeueentry(&nat->nat_tqe);
2362 	}
2363 
2364 	if (nat->nat_sync) {
2365 		ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
2366 		nat->nat_sync = NULL;
2367 	}
2368 
2369 	if (logtype == NL_EXPIRE)
2370 		softn->ipf_nat_stats.ns_expire++;
2371 
2372 	MUTEX_ENTER(&nat->nat_lock);
2373 	/*
2374 	 * NL_DESTROY should only be passed in when we've got nat_ref >= 2.
2375 	 * This happens when a nat'd packet is blocked and we want to throw
2376 	 * away the NAT session.
2377 	 */
2378 	if (logtype == NL_DESTROY) {
2379 		if (nat->nat_ref > 2) {
2380 			nat->nat_ref -= 2;
2381 			MUTEX_EXIT(&nat->nat_lock);
2382 			if (removed)
2383 				softn->ipf_nat_stats.ns_orphans++;
2384 			return;
2385 		}
2386 	} else if (nat->nat_ref > 1) {
2387 		nat->nat_ref--;
2388 		MUTEX_EXIT(&nat->nat_lock);
2389 		if (madeorphan == 1)
2390 			softn->ipf_nat_stats.ns_orphans++;
2391 		return;
2392 	}
2393 	ASSERT(nat->nat_ref >= 0);
2394 	MUTEX_EXIT(&nat->nat_lock);
2395 
2396 	nat->nat_ref = 0;
2397 
2398 	if (madeorphan == 0)
2399 		softn->ipf_nat_stats.ns_orphans--;
2400 
2401 	/*
2402 	 * At this point, nat_ref can be either 0 or -1
2403 	 */
2404 	softn->ipf_nat_stats.ns_proto[nat->nat_pr[0]]--;
2405 
2406 	if (nat->nat_fr != NULL) {
2407 		(void) ipf_derefrule(softc, &nat->nat_fr);
2408 	}
2409 
2410 	if (nat->nat_hm != NULL) {
2411 		ipf_nat_hostmapdel(softc, &nat->nat_hm);
2412 	}
2413 
2414 	/*
2415 	 * If there is an active reference from the nat entry to its parent
2416 	 * rule, decrement the rule's reference count and free it too if no
2417 	 * longer being used.
2418 	 */
2419 	ipn = nat->nat_ptr;
2420 	nat->nat_ptr = NULL;
2421 
2422 	if (ipn != NULL) {
2423 		ipn->in_space++;
2424 		ipf_nat_rule_deref(softc, &ipn);
2425 	}
2426 
2427 	if (nat->nat_aps != NULL) {
2428 		ipf_proxy_free(softc, nat->nat_aps);
2429 		nat->nat_aps = NULL;
2430 	}
2431 
2432 	MUTEX_DESTROY(&nat->nat_lock);
2433 
2434 	softn->ipf_nat_stats.ns_active--;
2435 
2436 	/*
2437 	 * If there's a fragment table entry too for this nat entry, then
2438 	 * dereference that as well.  This is after nat_lock is released
2439 	 * because of Tru64.
2440 	 */
2441 	ipf_frag_natforget(softc, (void *)nat);
2442 
2443 	KFREE(nat);
2444 }
2445 
2446 
2447 /* ------------------------------------------------------------------------ */
2448 /* Function:    ipf_nat_flushtable                                          */
2449 /* Returns:     int - number of NAT rules deleted                           */
2450 /* Parameters:  softc(I) - pointer to soft context main structure           */
2451 /*              softn(I) - pointer to NAT context structure                 */
2452 /* Write Lock:  ipf_nat                                                     */
2453 /*                                                                          */
2454 /* Deletes all currently active NAT sessions.  In deleting each NAT entry a */
2455 /* log record should be emitted in ipf_nat_delete() if NAT logging is       */
2456 /* enabled.                                                                 */
2457 /* ------------------------------------------------------------------------ */
2458 /*
2459  * nat_flushtable - clear the NAT table of all mapping entries.
2460  */
2461 static int
ipf_nat_flushtable(softc,softn)2462 ipf_nat_flushtable(softc, softn)
2463 	ipf_main_softc_t *softc;
2464 	ipf_nat_softc_t *softn;
2465 {
2466 	nat_t *nat;
2467 	int j = 0;
2468 
2469 	/*
2470 	 * ALL NAT mappings deleted, so lets just make the deletions
2471 	 * quicker.
2472 	 */
2473 	if (softn->ipf_nat_table[0] != NULL)
2474 		bzero((char *)softn->ipf_nat_table[0],
2475 		      sizeof(softn->ipf_nat_table[0]) *
2476 		      softn->ipf_nat_table_sz);
2477 	if (softn->ipf_nat_table[1] != NULL)
2478 		bzero((char *)softn->ipf_nat_table[1],
2479 		      sizeof(softn->ipf_nat_table[1]) *
2480 		      softn->ipf_nat_table_sz);
2481 
2482 	while ((nat = softn->ipf_nat_instances) != NULL) {
2483 		ipf_nat_delete(softc, nat, NL_FLUSH);
2484 		j++;
2485 	}
2486 
2487 	return j;
2488 }
2489 
2490 
2491 /* ------------------------------------------------------------------------ */
2492 /* Function:    ipf_nat_clearlist                                           */
2493 /* Returns:     int - number of NAT/RDR rules deleted                       */
2494 /* Parameters:  softc(I) - pointer to soft context main structure           */
2495 /*              softn(I) - pointer to NAT context structure                 */
2496 /*                                                                          */
2497 /* Delete all rules in the current list of rules.  There is nothing elegant */
2498 /* about this cleanup: simply free all entries on the list of rules and     */
2499 /* clear out the tables used for hashed NAT rule lookups.                   */
2500 /* ------------------------------------------------------------------------ */
2501 static int
ipf_nat_clearlist(softc,softn)2502 ipf_nat_clearlist(softc, softn)
2503 	ipf_main_softc_t *softc;
2504 	ipf_nat_softc_t *softn;
2505 {
2506 	ipnat_t *n;
2507 	int i = 0;
2508 
2509 	if (softn->ipf_nat_map_rules != NULL) {
2510 		bzero((char *)softn->ipf_nat_map_rules,
2511 		      sizeof(*softn->ipf_nat_map_rules) *
2512 		      softn->ipf_nat_maprules_sz);
2513 	}
2514 	if (softn->ipf_nat_rdr_rules != NULL) {
2515 		bzero((char *)softn->ipf_nat_rdr_rules,
2516 		      sizeof(*softn->ipf_nat_rdr_rules) *
2517 		      softn->ipf_nat_rdrrules_sz);
2518 	}
2519 
2520 	while ((n = softn->ipf_nat_list) != NULL) {
2521 		ipf_nat_delrule(softc, softn, n, 0);
2522 		i++;
2523 	}
2524 #if SOLARIS && !defined(INSTANCES)
2525 	pfil_delayed_copy = 1;
2526 #endif
2527 	return i;
2528 }
2529 
2530 
2531 /* ------------------------------------------------------------------------ */
2532 /* Function:    ipf_nat_delrule                                             */
2533 /* Returns:     Nil                                                         */
2534 /* Parameters:  softc(I) - pointer to soft context main structure           */
2535 /*              softn(I) - pointer to NAT context structure                 */
2536 /*              np(I)    - pointer to NAT rule to delete                    */
2537 /*              purge(I) - 1 == allow purge, 0 == prevent purge             */
2538 /* Locks:       WRITE(ipf_nat)                                              */
2539 /*                                                                          */
2540 /* Preventing "purge" from occuring is allowed because when all of the NAT  */
2541 /* rules are being removed, allowing the "purge" to walk through the list   */
2542 /* of NAT sessions, possibly multiple times, would be a large performance   */
2543 /* hit, on the order of O(N^2).                                             */
2544 /* ------------------------------------------------------------------------ */
2545 static void
ipf_nat_delrule(softc,softn,np,purge)2546 ipf_nat_delrule(softc, softn, np, purge)
2547 	ipf_main_softc_t *softc;
2548 	ipf_nat_softc_t *softn;
2549 	ipnat_t *np;
2550 	int purge;
2551 {
2552 
2553 	if (np->in_pnext != NULL) {
2554 		*np->in_pnext = np->in_next;
2555 		if (np->in_next != NULL)
2556 			np->in_next->in_pnext = np->in_pnext;
2557 		if (softn->ipf_nat_list_tail == &np->in_next)
2558 			softn->ipf_nat_list_tail = np->in_pnext;
2559 	}
2560 
2561 	if ((purge == 1) && ((np->in_flags & IPN_PURGE) != 0)) {
2562 		nat_t *next;
2563 		nat_t *nat;
2564 
2565 		for (next = softn->ipf_nat_instances; (nat = next) != NULL;) {
2566 			next = nat->nat_next;
2567 			if (nat->nat_ptr == np)
2568 				ipf_nat_delete(softc, nat, NL_PURGE);
2569 		}
2570 	}
2571 
2572 	if ((np->in_flags & IPN_DELETE) == 0) {
2573 		if (np->in_redir & NAT_REDIRECT) {
2574 			switch (np->in_v[0])
2575 			{
2576 			case 4 :
2577 				ipf_nat_delrdr(softn, np);
2578 				break;
2579 #ifdef USE_INET6
2580 			case 6 :
2581 				ipf_nat6_delrdr(softn, np);
2582 				break;
2583 #endif
2584 			}
2585 		}
2586 		if (np->in_redir & (NAT_MAPBLK|NAT_MAP)) {
2587 			switch (np->in_v[0])
2588 			{
2589 			case 4 :
2590 				ipf_nat_delmap(softn, np);
2591 				break;
2592 #ifdef USE_INET6
2593 			case 6 :
2594 				ipf_nat6_delmap(softn, np);
2595 				break;
2596 #endif
2597 			}
2598 		}
2599 	}
2600 
2601 	np->in_flags |= IPN_DELETE;
2602 	ipf_nat_rule_deref(softc, &np);
2603 }
2604 
2605 
2606 /* ------------------------------------------------------------------------ */
2607 /* Function:    ipf_nat_newmap                                              */
2608 /* Returns:     int - -1 == error, 0 == success                             */
2609 /* Parameters:  fin(I) - pointer to packet information                      */
2610 /*              nat(I) - pointer to NAT entry                               */
2611 /*              ni(I)  - pointer to structure with misc. information needed */
2612 /*                       to create new NAT entry.                           */
2613 /*                                                                          */
2614 /* Given an empty NAT structure, populate it with new information about a   */
2615 /* new NAT session, as defined by the matching NAT rule.                    */
2616 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
2617 /* to the new IP address for the translation.                               */
2618 /* ------------------------------------------------------------------------ */
2619 static int
ipf_nat_newmap(fin,nat,ni)2620 ipf_nat_newmap(fin, nat, ni)
2621 	fr_info_t *fin;
2622 	nat_t *nat;
2623 	natinfo_t *ni;
2624 {
2625 	ipf_main_softc_t *softc = fin->fin_main_soft;
2626 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2627 	u_short st_port, dport, sport, port, sp, dp;
2628 	struct in_addr in, inb;
2629 	hostmap_t *hm;
2630 	u_32_t flags;
2631 	u_32_t st_ip;
2632 	ipnat_t *np;
2633 	nat_t *natl;
2634 	int l;
2635 
2636 	/*
2637 	 * If it's an outbound packet which doesn't match any existing
2638 	 * record, then create a new port
2639 	 */
2640 	l = 0;
2641 	hm = NULL;
2642 	np = ni->nai_np;
2643 	st_ip = np->in_snip;
2644 	st_port = np->in_spnext;
2645 	flags = nat->nat_flags;
2646 
2647 	if (flags & IPN_ICMPQUERY) {
2648 		sport = fin->fin_data[1];
2649 		dport = 0;
2650 	} else {
2651 		sport = htons(fin->fin_data[0]);
2652 		dport = htons(fin->fin_data[1]);
2653 	}
2654 
2655 	/*
2656 	 * Do a loop until we either run out of entries to try or we find
2657 	 * a NAT mapping that isn't currently being used.  This is done
2658 	 * because the change to the source is not (usually) being fixed.
2659 	 */
2660 	do {
2661 		port = 0;
2662 		in.s_addr = htonl(np->in_snip);
2663 		if (l == 0) {
2664 			/*
2665 			 * Check to see if there is an existing NAT
2666 			 * setup for this IP address pair.
2667 			 */
2668 			hm = ipf_nat_hostmap(softn, np, fin->fin_src,
2669 					     fin->fin_dst, in, 0);
2670 			if (hm != NULL)
2671 				in.s_addr = hm->hm_nsrcip.s_addr;
2672 		} else if ((l == 1) && (hm != NULL)) {
2673 			ipf_nat_hostmapdel(softc, &hm);
2674 		}
2675 		in.s_addr = ntohl(in.s_addr);
2676 
2677 		nat->nat_hm = hm;
2678 
2679 		if ((np->in_nsrcmsk == 0xffffffff) && (np->in_spnext == 0)) {
2680 			if (l > 0) {
2681 				NBUMPSIDEX(1, ns_exhausted, ns_exhausted_1);
2682 				DT4(ns_exhausted_1, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np);
2683 				return -1;
2684 			}
2685 		}
2686 
2687 		if (np->in_redir == NAT_BIMAP &&
2688 		    np->in_osrcmsk == np->in_nsrcmsk) {
2689 			/*
2690 			 * map the address block in a 1:1 fashion
2691 			 */
2692 			in.s_addr = np->in_nsrcaddr;
2693 			in.s_addr |= fin->fin_saddr & ~np->in_osrcmsk;
2694 			in.s_addr = ntohl(in.s_addr);
2695 
2696 		} else if (np->in_redir & NAT_MAPBLK) {
2697 			if ((l >= np->in_ppip) || ((l > 0) &&
2698 			     !(flags & IPN_TCPUDP))) {
2699 				NBUMPSIDEX(1, ns_exhausted, ns_exhausted_2);
2700 				DT4(ns_exhausted_2, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np);
2701 				return -1;
2702 			}
2703 			/*
2704 			 * map-block - Calculate destination address.
2705 			 */
2706 			in.s_addr = ntohl(fin->fin_saddr);
2707 			in.s_addr &= ntohl(~np->in_osrcmsk);
2708 			inb.s_addr = in.s_addr;
2709 			in.s_addr /= np->in_ippip;
2710 			in.s_addr &= ntohl(~np->in_nsrcmsk);
2711 			in.s_addr += ntohl(np->in_nsrcaddr);
2712 			/*
2713 			 * Calculate destination port.
2714 			 */
2715 			if ((flags & IPN_TCPUDP) &&
2716 			    (np->in_ppip != 0)) {
2717 				port = ntohs(sport) + l;
2718 				port %= np->in_ppip;
2719 				port += np->in_ppip *
2720 					(inb.s_addr % np->in_ippip);
2721 				port += MAPBLK_MINPORT;
2722 				port = htons(port);
2723 			}
2724 
2725 		} else if ((np->in_nsrcaddr == 0) &&
2726 			   (np->in_nsrcmsk == 0xffffffff)) {
2727 			i6addr_t in6;
2728 
2729 			/*
2730 			 * 0/32 - use the interface's IP address.
2731 			 */
2732 			if ((l > 0) ||
2733 			    ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp,
2734 				       &in6, NULL) == -1) {
2735 				NBUMPSIDEX(1, ns_new_ifpaddr, ns_new_ifpaddr_1);
2736 				DT4(ns_new_ifpaddr_1, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np);
2737 				return -1;
2738 			}
2739 			in.s_addr = ntohl(in6.in4.s_addr);
2740 
2741 		} else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) {
2742 			/*
2743 			 * 0/0 - use the original source address/port.
2744 			 */
2745 			if (l > 0) {
2746 				NBUMPSIDEX(1, ns_exhausted, ns_exhausted_3);
2747 				DT4(ns_exhausted_3, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np);
2748 				return -1;
2749 			}
2750 			in.s_addr = ntohl(fin->fin_saddr);
2751 
2752 		} else if ((np->in_nsrcmsk != 0xffffffff) &&
2753 			   (np->in_spnext == 0) && ((l > 0) || (hm == NULL)))
2754 			np->in_snip++;
2755 
2756 		natl = NULL;
2757 
2758 		if ((flags & IPN_TCPUDP) &&
2759 		    ((np->in_redir & NAT_MAPBLK) == 0) &&
2760 		    (np->in_flags & IPN_AUTOPORTMAP)) {
2761 			/*
2762 			 * "ports auto" (without map-block)
2763 			 */
2764 			if ((l > 0) && (l % np->in_ppip == 0)) {
2765 				if ((l > np->in_ppip) &&
2766 				    np->in_nsrcmsk != 0xffffffff)
2767 					np->in_snip++;
2768 			}
2769 			if (np->in_ppip != 0) {
2770 				port = ntohs(sport);
2771 				port += (l % np->in_ppip);
2772 				port %= np->in_ppip;
2773 				port += np->in_ppip *
2774 					(ntohl(fin->fin_saddr) %
2775 					 np->in_ippip);
2776 				port += MAPBLK_MINPORT;
2777 				port = htons(port);
2778 			}
2779 
2780 		} else if (((np->in_redir & NAT_MAPBLK) == 0) &&
2781 			   (flags & IPN_TCPUDPICMP) && (np->in_spnext != 0)) {
2782 			/*
2783 			 * Standard port translation.  Select next port.
2784 			 */
2785 			if (np->in_flags & IPN_SEQUENTIAL) {
2786 				port = np->in_spnext;
2787 			} else {
2788 				port = ipf_random() % (np->in_spmax -
2789 						       np->in_spmin + 1);
2790 				port += np->in_spmin;
2791 			}
2792 			port = htons(port);
2793 			np->in_spnext++;
2794 
2795 			if (np->in_spnext > np->in_spmax) {
2796 				np->in_spnext = np->in_spmin;
2797 				if (np->in_nsrcmsk != 0xffffffff)
2798 					np->in_snip++;
2799 			}
2800 		}
2801 
2802 		if (np->in_flags & IPN_SIPRANGE) {
2803 			if (np->in_snip > ntohl(np->in_nsrcmsk))
2804 				np->in_snip = ntohl(np->in_nsrcaddr);
2805 		} else {
2806 			if ((np->in_nsrcmsk != 0xffffffff) &&
2807 			    ((np->in_snip + 1) & ntohl(np->in_nsrcmsk)) >
2808 			    ntohl(np->in_nsrcaddr))
2809 				np->in_snip = ntohl(np->in_nsrcaddr) + 1;
2810 		}
2811 
2812 		if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
2813 			port = sport;
2814 
2815 		/*
2816 		 * Here we do a lookup of the connection as seen from
2817 		 * the outside.  If an IP# pair already exists, try
2818 		 * again.  So if you have A->B becomes C->B, you can
2819 		 * also have D->E become C->E but not D->B causing
2820 		 * another C->B.  Also take protocol and ports into
2821 		 * account when determining whether a pre-existing
2822 		 * NAT setup will cause an external conflict where
2823 		 * this is appropriate.
2824 		 */
2825 		inb.s_addr = htonl(in.s_addr);
2826 		sp = fin->fin_data[0];
2827 		dp = fin->fin_data[1];
2828 		fin->fin_data[0] = fin->fin_data[1];
2829 		fin->fin_data[1] = ntohs(port);
2830 		natl = ipf_nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
2831 					(u_int)fin->fin_p, fin->fin_dst, inb);
2832 		fin->fin_data[0] = sp;
2833 		fin->fin_data[1] = dp;
2834 
2835 		/*
2836 		 * Has the search wrapped around and come back to the
2837 		 * start ?
2838 		 */
2839 		if ((natl != NULL) &&
2840 		    (np->in_spnext != 0) && (st_port == np->in_spnext) &&
2841 		    (np->in_snip != 0) && (st_ip == np->in_snip)) {
2842 			NBUMPSIDED(1, ns_wrap);
2843 			DT4(ns_wrap, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np);
2844 			return -1;
2845 		}
2846 		l++;
2847 	} while (natl != NULL);
2848 
2849 	/* Setup the NAT table */
2850 	nat->nat_osrcip = fin->fin_src;
2851 	nat->nat_nsrcaddr = htonl(in.s_addr);
2852 	nat->nat_odstip = fin->fin_dst;
2853 	nat->nat_ndstip = fin->fin_dst;
2854 	if (nat->nat_hm == NULL)
2855 		nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src,
2856 					      fin->fin_dst, nat->nat_nsrcip,
2857 					      0);
2858 
2859 	if (flags & IPN_TCPUDP) {
2860 		nat->nat_osport = sport;
2861 		nat->nat_nsport = port;	/* sport */
2862 		nat->nat_odport = dport;
2863 		nat->nat_ndport = dport;
2864 		((tcphdr_t *)fin->fin_dp)->th_sport = port;
2865 	} else if (flags & IPN_ICMPQUERY) {
2866 		nat->nat_oicmpid = fin->fin_data[1];
2867 		((icmphdr_t *)fin->fin_dp)->icmp_id = port;
2868 		nat->nat_nicmpid = port;
2869 	}
2870 	return 0;
2871 }
2872 
2873 
2874 /* ------------------------------------------------------------------------ */
2875 /* Function:    ipf_nat_newrdr                                              */
2876 /* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
2877 /*                    allow rule to be moved if IPN_ROUNDR is set.          */
2878 /* Parameters:  fin(I) - pointer to packet information                      */
2879 /*              nat(I) - pointer to NAT entry                               */
2880 /*              ni(I)  - pointer to structure with misc. information needed */
2881 /*                       to create new NAT entry.                           */
2882 /*                                                                          */
2883 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
2884 /* to the new IP address for the translation.                               */
2885 /* ------------------------------------------------------------------------ */
2886 static int
ipf_nat_newrdr(fin,nat,ni)2887 ipf_nat_newrdr(fin, nat, ni)
2888 	fr_info_t *fin;
2889 	nat_t *nat;
2890 	natinfo_t *ni;
2891 {
2892 	ipf_main_softc_t *softc = fin->fin_main_soft;
2893 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2894 	u_short nport, dport, sport;
2895 	struct in_addr in, inb;
2896 	u_short sp, dp;
2897 	hostmap_t *hm;
2898 	u_32_t flags;
2899 	ipnat_t *np;
2900 	nat_t *natl;
2901 	int move;
2902 
2903 	move = 1;
2904 	hm = NULL;
2905 	in.s_addr = 0;
2906 	np = ni->nai_np;
2907 	flags = nat->nat_flags;
2908 
2909 	if (flags & IPN_ICMPQUERY) {
2910 		dport = fin->fin_data[1];
2911 		sport = 0;
2912 	} else {
2913 		sport = htons(fin->fin_data[0]);
2914 		dport = htons(fin->fin_data[1]);
2915 	}
2916 
2917 	/* TRACE sport, dport */
2918 
2919 
2920 	/*
2921 	 * If the matching rule has IPN_STICKY set, then we want to have the
2922 	 * same rule kick in as before.  Why would this happen?  If you have
2923 	 * a collection of rdr rules with "round-robin sticky", the current
2924 	 * packet might match a different one to the previous connection but
2925 	 * we want the same destination to be used.
2926 	 */
2927 	if (((np->in_flags & (IPN_ROUNDR|IPN_SPLIT)) != 0) &&
2928 	    ((np->in_flags & IPN_STICKY) != 0)) {
2929 		hm = ipf_nat_hostmap(softn, NULL, fin->fin_src, fin->fin_dst,
2930 				     in, (u_32_t)dport);
2931 		if (hm != NULL) {
2932 			in.s_addr = ntohl(hm->hm_ndstip.s_addr);
2933 			np = hm->hm_ipnat;
2934 			ni->nai_np = np;
2935 			move = 0;
2936 			ipf_nat_hostmapdel(softc, &hm);
2937 		}
2938 	}
2939 
2940 	/*
2941 	 * Otherwise, it's an inbound packet. Most likely, we don't
2942 	 * want to rewrite source ports and source addresses. Instead,
2943 	 * we want to rewrite to a fixed internal address and fixed
2944 	 * internal port.
2945 	 */
2946 	if (np->in_flags & IPN_SPLIT) {
2947 		in.s_addr = np->in_dnip;
2948 		inb.s_addr = htonl(in.s_addr);
2949 
2950 		if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
2951 			hm = ipf_nat_hostmap(softn, NULL, fin->fin_src,
2952 					     fin->fin_dst, inb, (u_32_t)dport);
2953 			if (hm != NULL) {
2954 				in.s_addr = hm->hm_ndstip.s_addr;
2955 				move = 0;
2956 			}
2957 		}
2958 
2959 		if (hm == NULL || hm->hm_ref == 1) {
2960 			if (np->in_ndstaddr == htonl(in.s_addr)) {
2961 				np->in_dnip = ntohl(np->in_ndstmsk);
2962 				move = 0;
2963 			} else {
2964 				np->in_dnip = ntohl(np->in_ndstaddr);
2965 			}
2966 		}
2967 		if (hm != NULL)
2968 			ipf_nat_hostmapdel(softc, &hm);
2969 
2970 	} else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) {
2971 		i6addr_t in6;
2972 
2973 		/*
2974 		 * 0/32 - use the interface's IP address.
2975 		 */
2976 		if (ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp,
2977 			       &in6, NULL) == -1) {
2978 			NBUMPSIDEX(0, ns_new_ifpaddr, ns_new_ifpaddr_2);
2979 			DT3(ns_new_ifpaddr_2, fr_info_t *, fin, nat_t *, nat, natinfo_t, ni);
2980 			return -1;
2981 		}
2982 		in.s_addr = ntohl(in6.in4.s_addr);
2983 
2984 	} else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk== 0)) {
2985 		/*
2986 		 * 0/0 - use the original destination address/port.
2987 		 */
2988 		in.s_addr = ntohl(fin->fin_daddr);
2989 
2990 	} else if (np->in_redir == NAT_BIMAP &&
2991 		   np->in_ndstmsk == np->in_odstmsk) {
2992 		/*
2993 		 * map the address block in a 1:1 fashion
2994 		 */
2995 		in.s_addr = np->in_ndstaddr;
2996 		in.s_addr |= fin->fin_daddr & ~np->in_ndstmsk;
2997 		in.s_addr = ntohl(in.s_addr);
2998 	} else {
2999 		in.s_addr = ntohl(np->in_ndstaddr);
3000 	}
3001 
3002 	if ((np->in_dpnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
3003 		nport = dport;
3004 	else {
3005 		/*
3006 		 * Whilst not optimized for the case where
3007 		 * pmin == pmax, the gain is not significant.
3008 		 */
3009 		if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
3010 		    (np->in_odport != np->in_dtop)) {
3011 			nport = ntohs(dport) - np->in_odport + np->in_dpmax;
3012 			nport = htons(nport);
3013 		} else {
3014 			nport = htons(np->in_dpnext);
3015 			np->in_dpnext++;
3016 			if (np->in_dpnext > np->in_dpmax)
3017 				np->in_dpnext = np->in_dpmin;
3018 		}
3019 	}
3020 
3021 	/*
3022 	 * When the redirect-to address is set to 0.0.0.0, just
3023 	 * assume a blank `forwarding' of the packet.  We don't
3024 	 * setup any translation for this either.
3025 	 */
3026 	if (in.s_addr == 0) {
3027 		if (nport == dport) {
3028 			NBUMPSIDED(0, ns_xlate_null);
3029 			return -1;
3030 		}
3031 		in.s_addr = ntohl(fin->fin_daddr);
3032 	}
3033 
3034 	/*
3035 	 * Check to see if this redirect mapping already exists and if
3036 	 * it does, return "failure" (allowing it to be created will just
3037 	 * cause one or both of these "connections" to stop working.)
3038 	 */
3039 	inb.s_addr = htonl(in.s_addr);
3040 	sp = fin->fin_data[0];
3041 	dp = fin->fin_data[1];
3042 	fin->fin_data[1] = fin->fin_data[0];
3043 	fin->fin_data[0] = ntohs(nport);
3044 	natl = ipf_nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
3045 			     (u_int)fin->fin_p, inb, fin->fin_src);
3046 	fin->fin_data[0] = sp;
3047 	fin->fin_data[1] = dp;
3048 	if (natl != NULL) {
3049 		DT2(ns_new_xlate_exists, fr_info_t *, fin, nat_t *, natl);
3050 		NBUMPSIDE(0, ns_xlate_exists);
3051 		return -1;
3052 	}
3053 
3054 	inb.s_addr = htonl(in.s_addr);
3055 	nat->nat_ndstaddr = htonl(in.s_addr);
3056 	nat->nat_odstip = fin->fin_dst;
3057 	nat->nat_nsrcip = fin->fin_src;
3058 	nat->nat_osrcip = fin->fin_src;
3059 	if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0))
3060 		nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src,
3061 					      fin->fin_dst, inb, (u_32_t)dport);
3062 
3063 	if (flags & IPN_TCPUDP) {
3064 		nat->nat_odport = dport;
3065 		nat->nat_ndport = nport;
3066 		nat->nat_osport = sport;
3067 		nat->nat_nsport = sport;
3068 		((tcphdr_t *)fin->fin_dp)->th_dport = nport;
3069 	} else if (flags & IPN_ICMPQUERY) {
3070 		nat->nat_oicmpid = fin->fin_data[1];
3071 		((icmphdr_t *)fin->fin_dp)->icmp_id = nport;
3072 		nat->nat_nicmpid = nport;
3073 	}
3074 
3075 	return move;
3076 }
3077 
3078 /* ------------------------------------------------------------------------ */
3079 /* Function:    ipf_nat_add                                                 */
3080 /* Returns:     nat_t* - NULL == failure to create new NAT structure,       */
3081 /*                       else pointer to new NAT structure                  */
3082 /* Parameters:  fin(I)       - pointer to packet information                */
3083 /*              np(I)        - pointer to NAT rule                          */
3084 /*              natsave(I)   - pointer to where to store NAT struct pointer */
3085 /*              flags(I)     - flags describing the current packet          */
3086 /*              direction(I) - direction of packet (in/out)                 */
3087 /* Write Lock:  ipf_nat                                                     */
3088 /*                                                                          */
3089 /* Attempts to create a new NAT entry.  Does not actually change the packet */
3090 /* in any way.                                                              */
3091 /*                                                                          */
3092 /* This fucntion is in three main parts: (1) deal with creating a new NAT   */
3093 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with     */
3094 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
3095 /* and (3) building that structure and putting it into the NAT table(s).    */
3096 /*                                                                          */
3097 /* NOTE: natsave should NOT be used top point back to an ipstate_t struct   */
3098 /*       as it can result in memory being corrupted.                        */
3099 /* ------------------------------------------------------------------------ */
3100 nat_t *
ipf_nat_add(fin,np,natsave,flags,direction)3101 ipf_nat_add(fin, np, natsave, flags, direction)
3102 	fr_info_t *fin;
3103 	ipnat_t *np;
3104 	nat_t **natsave;
3105 	u_int flags;
3106 	int direction;
3107 {
3108 	ipf_main_softc_t *softc = fin->fin_main_soft;
3109 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3110 	hostmap_t *hm = NULL;
3111 	nat_t *nat, *natl;
3112 	natstat_t *nsp;
3113 	u_int nflags;
3114 	natinfo_t ni;
3115 	int move;
3116 
3117 	nsp = &softn->ipf_nat_stats;
3118 
3119 	if ((nsp->ns_active * 100 / softn->ipf_nat_table_max) >
3120 	    softn->ipf_nat_table_wm_high) {
3121 		softn->ipf_nat_doflush = 1;
3122 	}
3123 
3124 	if (nsp->ns_active >= softn->ipf_nat_table_max) {
3125 		NBUMPSIDED(fin->fin_out, ns_table_max);
3126 		DT2(ns_table_max, nat_stat_t *, nsp, ipf_nat_softc_t *, softn);
3127 		return NULL;
3128 	}
3129 
3130 	move = 1;
3131 	nflags = np->in_flags & flags;
3132 	nflags &= NAT_FROMRULE;
3133 
3134 	ni.nai_np = np;
3135 	ni.nai_dport = 0;
3136 	ni.nai_sport = 0;
3137 
3138 	/* Give me a new nat */
3139 	KMALLOC(nat, nat_t *);
3140 	if (nat == NULL) {
3141 		DT(ns_memfail);
3142 		NBUMPSIDED(fin->fin_out, ns_memfail);
3143 		/*
3144 		 * Try to automatically tune the max # of entries in the
3145 		 * table allowed to be less than what will cause kmem_alloc()
3146 		 * to fail and try to eliminate panics due to out of memory
3147 		 * conditions arising.
3148 		 */
3149 		if ((softn->ipf_nat_table_max > softn->ipf_nat_table_sz) &&
3150 		    (nsp->ns_active > 100)) {
3151 			softn->ipf_nat_table_max = nsp->ns_active - 100;
3152 			printf("table_max reduced to %d\n",
3153 				softn->ipf_nat_table_max);
3154 		}
3155 		return NULL;
3156 	}
3157 
3158 	if (flags & IPN_ICMPQUERY) {
3159 		/*
3160 		 * In the ICMP query NAT code, we translate the ICMP id fields
3161 		 * to make them unique. This is indepedent of the ICMP type
3162 		 * (e.g. in the unlikely event that a host sends an echo and
3163 		 * an tstamp request with the same id, both packets will have
3164 		 * their ip address/id field changed in the same way).
3165 		 */
3166 		/* The icmp_id field is used by the sender to identify the
3167 		 * process making the icmp request. (the receiver justs
3168 		 * copies it back in its response). So, it closely matches
3169 		 * the concept of source port. We overlay sport, so we can
3170 		 * maximally reuse the existing code.
3171 		 */
3172 		ni.nai_sport = fin->fin_data[1];
3173 		ni.nai_dport = 0;
3174 	}
3175 
3176 	bzero((char *)nat, sizeof(*nat));
3177 	nat->nat_flags = flags;
3178 	nat->nat_redir = np->in_redir;
3179 	nat->nat_dir = direction;
3180 	nat->nat_pr[0] = fin->fin_p;
3181 	nat->nat_pr[1] = fin->fin_p;
3182 
3183 	/*
3184 	 * Search the current table for a match and create a new mapping
3185 	 * if there is none found.
3186 	 */
3187 	if (np->in_redir & NAT_DIVERTUDP) {
3188 		move = ipf_nat_newdivert(fin, nat, &ni);
3189 
3190 	} else if (np->in_redir & NAT_REWRITE) {
3191 		move = ipf_nat_newrewrite(fin, nat, &ni);
3192 
3193 	} else if (direction == NAT_OUTBOUND) {
3194 		/*
3195 		 * We can now arrange to call this for the same connection
3196 		 * because ipf_nat_new doesn't protect the code path into
3197 		 * this function.
3198 		 */
3199 		natl = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p,
3200 				     fin->fin_src, fin->fin_dst);
3201 		if (natl != NULL) {
3202 			KFREE(nat);
3203 			nat = natl;
3204 			goto done;
3205 		}
3206 
3207 		move = ipf_nat_newmap(fin, nat, &ni);
3208 	} else {
3209 		/*
3210 		 * NAT_INBOUND is used for redirects rules
3211 		 */
3212 		natl = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p,
3213 					fin->fin_src, fin->fin_dst);
3214 		if (natl != NULL) {
3215 			KFREE(nat);
3216 			nat = natl;
3217 			goto done;
3218 		}
3219 
3220 		move = ipf_nat_newrdr(fin, nat, &ni);
3221 	}
3222 	if (move == -1)
3223 		goto badnat;
3224 
3225 	np = ni.nai_np;
3226 
3227 	nat->nat_mssclamp = np->in_mssclamp;
3228 	nat->nat_me = natsave;
3229 	nat->nat_fr = fin->fin_fr;
3230 	nat->nat_rev = fin->fin_rev;
3231 	nat->nat_ptr = np;
3232 	nat->nat_dlocal = np->in_dlocal;
3233 
3234 	if ((np->in_apr != NULL) && ((nat->nat_flags & NAT_SLAVE) == 0)) {
3235 		if (ipf_proxy_new(fin, nat) == -1) {
3236 			NBUMPSIDED(fin->fin_out, ns_appr_fail);
3237 			DT3(ns_appr_fail, fr_info_t *, fin, nat_t *, nat, ipnat_t *, np);
3238 			goto badnat;
3239 		}
3240 	}
3241 
3242 	nat->nat_ifps[0] = np->in_ifps[0];
3243 	if (np->in_ifps[0] != NULL) {
3244 		COPYIFNAME(np->in_v[0], np->in_ifps[0], nat->nat_ifnames[0]);
3245 	}
3246 
3247 	nat->nat_ifps[1] = np->in_ifps[1];
3248 	if (np->in_ifps[1] != NULL) {
3249 		COPYIFNAME(np->in_v[1], np->in_ifps[1], nat->nat_ifnames[1]);
3250 	}
3251 
3252 	if (ipf_nat_finalise(fin, nat) == -1) {
3253 		goto badnat;
3254 	}
3255 
3256 	np->in_use++;
3257 
3258 	if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
3259 		if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_REDIRECT) {
3260 			ipf_nat_delrdr(softn, np);
3261 			ipf_nat_addrdr(softn, np);
3262 		} else if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_MAP) {
3263 			ipf_nat_delmap(softn, np);
3264 			ipf_nat_addmap(softn, np);
3265 		}
3266 	}
3267 
3268 	if (flags & SI_WILDP)
3269 		nsp->ns_wilds++;
3270 	nsp->ns_proto[nat->nat_pr[0]]++;
3271 
3272 	goto done;
3273 badnat:
3274 	DT3(ns_badnatnew, fr_info_t *, fin, nat_t *, nat, ipnat_t *, np);
3275 	NBUMPSIDE(fin->fin_out, ns_badnatnew);
3276 	if ((hm = nat->nat_hm) != NULL)
3277 		ipf_nat_hostmapdel(softc, &hm);
3278 	KFREE(nat);
3279 	nat = NULL;
3280 done:
3281 	if (nat != NULL && np != NULL)
3282 		np->in_hits++;
3283 	if (natsave != NULL)
3284 		*natsave = nat;
3285 	return nat;
3286 }
3287 
3288 
3289 /* ------------------------------------------------------------------------ */
3290 /* Function:    ipf_nat_finalise                                            */
3291 /* Returns:     int - 0 == sucess, -1 == failure                            */
3292 /* Parameters:  fin(I) - pointer to packet information                      */
3293 /*              nat(I) - pointer to NAT entry                               */
3294 /* Write Lock:  ipf_nat                                                     */
3295 /*                                                                          */
3296 /* This is the tail end of constructing a new NAT entry and is the same     */
3297 /* for both IPv4 and IPv6.                                                  */
3298 /* ------------------------------------------------------------------------ */
3299 /*ARGSUSED*/
3300 static int
ipf_nat_finalise(fin,nat)3301 ipf_nat_finalise(fin, nat)
3302 	fr_info_t *fin;
3303 	nat_t *nat;
3304 {
3305 	ipf_main_softc_t *softc = fin->fin_main_soft;
3306 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3307 	u_32_t sum1, sum2, sumd;
3308 	frentry_t *fr;
3309 	u_32_t flags;
3310 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC)
3311 	qpktinfo_t *qpi = fin->fin_qpi;
3312 #endif
3313 
3314 	flags = nat->nat_flags;
3315 
3316 	switch (nat->nat_pr[0])
3317 	{
3318 	case IPPROTO_ICMP :
3319 		sum1 = LONG_SUM(ntohs(nat->nat_oicmpid));
3320 		sum2 = LONG_SUM(ntohs(nat->nat_nicmpid));
3321 		CALC_SUMD(sum1, sum2, sumd);
3322 		nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
3323 
3324 		break;
3325 
3326 	default :
3327 		sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr) + \
3328 				ntohs(nat->nat_osport));
3329 		sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr) + \
3330 				ntohs(nat->nat_nsport));
3331 		CALC_SUMD(sum1, sum2, sumd);
3332 		nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
3333 
3334 		sum1 = LONG_SUM(ntohl(nat->nat_odstaddr) + \
3335 				ntohs(nat->nat_odport));
3336 		sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr) + \
3337 				ntohs(nat->nat_ndport));
3338 		CALC_SUMD(sum1, sum2, sumd);
3339 		nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
3340 		break;
3341 	}
3342 
3343 	/*
3344 	 * Compute the partial checksum, just in case.
3345 	 * This is only ever placed into outbound packets so care needs
3346 	 * to be taken over which pair of addresses are used.
3347 	 */
3348 	if (nat->nat_dir == NAT_OUTBOUND) {
3349 		sum1 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
3350 		sum1 += LONG_SUM(ntohl(nat->nat_ndstaddr));
3351 	} else {
3352 		sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr));
3353 		sum1 += LONG_SUM(ntohl(nat->nat_odstaddr));
3354 	}
3355 	sum1 += nat->nat_pr[1];
3356 	nat->nat_sumd[1] = (sum1 & 0xffff) + (sum1 >> 16);
3357 
3358 	sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr));
3359 	sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
3360 	CALC_SUMD(sum1, sum2, sumd);
3361 	nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
3362 
3363 	sum1 = LONG_SUM(ntohl(nat->nat_odstaddr));
3364 	sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr));
3365 	CALC_SUMD(sum1, sum2, sumd);
3366 	nat->nat_ipsumd += (sumd & 0xffff) + (sumd >> 16);
3367 
3368 	nat->nat_v[0] = 4;
3369 	nat->nat_v[1] = 4;
3370 
3371 	if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
3372 		nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
3373 	}
3374 
3375 	if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
3376 		nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
3377 	}
3378 
3379 	if ((nat->nat_flags & SI_CLONE) == 0)
3380 		nat->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, nat);
3381 
3382 	if (ipf_nat_insert(softc, softn, nat) == 0) {
3383 		if (softn->ipf_nat_logging)
3384 			ipf_nat_log(softc, softn, nat, NL_NEW);
3385 		fr = nat->nat_fr;
3386 		if (fr != NULL) {
3387 			MUTEX_ENTER(&fr->fr_lock);
3388 			fr->fr_ref++;
3389 			MUTEX_EXIT(&fr->fr_lock);
3390 		}
3391 		return 0;
3392 	}
3393 
3394 	NBUMPSIDED(fin->fin_out, ns_unfinalised);
3395 	DT2(ns_unfinalised, fr_info_t *, fin, nat_t *, nat);
3396 	/*
3397 	 * nat_insert failed, so cleanup time...
3398 	 */
3399 	if (nat->nat_sync != NULL)
3400 		ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
3401 	return -1;
3402 }
3403 
3404 
3405 /* ------------------------------------------------------------------------ */
3406 /* Function:    ipf_nat_insert                                              */
3407 /* Returns:     int - 0 == sucess, -1 == failure                            */
3408 /* Parameters:  softc(I) - pointer to soft context main structure           */
3409 /*              softn(I) - pointer to NAT context structure                 */
3410 /*              nat(I) - pointer to NAT structure                           */
3411 /* Write Lock:  ipf_nat                                                     */
3412 /*                                                                          */
3413 /* Insert a NAT entry into the hash tables for searching and add it to the  */
3414 /* list of active NAT entries.  Adjust global counters when complete.       */
3415 /* ------------------------------------------------------------------------ */
3416 int
ipf_nat_insert(softc,softn,nat)3417 ipf_nat_insert(softc, softn, nat)
3418 	ipf_main_softc_t *softc;
3419 	ipf_nat_softc_t *softn;
3420 	nat_t *nat;
3421 {
3422 	u_int hv0, hv1;
3423 	u_int sp, dp;
3424 	ipnat_t *in;
3425 
3426 	/*
3427 	 * Try and return an error as early as possible, so calculate the hash
3428 	 * entry numbers first and then proceed.
3429 	 */
3430 	if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
3431 		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
3432 			sp = nat->nat_osport;
3433 			dp = nat->nat_odport;
3434 		} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
3435 			sp = 0;
3436 			dp = nat->nat_oicmpid;
3437 		} else {
3438 			sp = 0;
3439 			dp = 0;
3440 		}
3441 		hv0 = NAT_HASH_FN(nat->nat_osrcaddr, sp, 0xffffffff);
3442 		hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0 + dp, 0xffffffff);
3443 		/*
3444 		 * TRACE nat_osrcaddr, nat_osport, nat_odstaddr,
3445 		 * nat_odport, hv0
3446 		 */
3447 
3448 		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
3449 			sp = nat->nat_nsport;
3450 			dp = nat->nat_ndport;
3451 		} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
3452 			sp = 0;
3453 			dp = nat->nat_nicmpid;
3454 		} else {
3455 			sp = 0;
3456 			dp = 0;
3457 		}
3458 		hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, sp, 0xffffffff);
3459 		hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1 + dp, 0xffffffff);
3460 		/*
3461 		 * TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr,
3462 		 * nat_ndport, hv1
3463 		 */
3464 	} else {
3465 		hv0 = NAT_HASH_FN(nat->nat_osrcaddr, 0, 0xffffffff);
3466 		hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0, 0xffffffff);
3467 		/* TRACE nat_osrcaddr, nat_odstaddr, hv0 */
3468 
3469 		hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, 0, 0xffffffff);
3470 		hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1, 0xffffffff);
3471 		/* TRACE nat_nsrcaddr, nat_ndstaddr, hv1 */
3472 	}
3473 
3474 	nat->nat_hv[0] = hv0;
3475 	nat->nat_hv[1] = hv1;
3476 
3477 	MUTEX_INIT(&nat->nat_lock, "nat entry lock");
3478 
3479 	in = nat->nat_ptr;
3480 	nat->nat_ref = nat->nat_me ? 2 : 1;
3481 
3482 	nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
3483 	nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0], 4);
3484 
3485 	if (nat->nat_ifnames[1][0] != '\0') {
3486 		nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
3487 		nat->nat_ifps[1] = ipf_resolvenic(softc,
3488 						  nat->nat_ifnames[1], 4);
3489 	} else if (in->in_ifnames[1] != -1) {
3490 		char *name;
3491 
3492 		name = in->in_names + in->in_ifnames[1];
3493 		if (name[1] != '\0' && name[0] != '-' && name[0] != '*') {
3494 			(void) strncpy(nat->nat_ifnames[1],
3495 				       nat->nat_ifnames[0], LIFNAMSIZ);
3496 			nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
3497 			nat->nat_ifps[1] = nat->nat_ifps[0];
3498 		}
3499 	}
3500 	if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
3501 		nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
3502 	}
3503 	if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
3504 		nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
3505 	}
3506 
3507 	return ipf_nat_hashtab_add(softc, softn, nat);
3508 }
3509 
3510 
3511 /* ------------------------------------------------------------------------ */
3512 /* Function:    ipf_nat_hashtab_add                                         */
3513 /* Parameters:  softc(I) - pointer to soft context main structure           */
3514 /*              softn(I) - pointer to NAT context structure                 */
3515 /*              nat(I) - pointer to NAT structure                           */
3516 /*                                                                          */
3517 /* Handle the insertion of a NAT entry into the table/list.                 */
3518 /* ------------------------------------------------------------------------ */
3519 int
ipf_nat_hashtab_add(softc,softn,nat)3520 ipf_nat_hashtab_add(softc, softn, nat)
3521 	ipf_main_softc_t *softc;
3522 	ipf_nat_softc_t *softn;
3523 	nat_t *nat;
3524 {
3525 	nat_t **natp;
3526 	u_int hv0;
3527 	u_int hv1;
3528 
3529 	hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz;
3530 	hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz;
3531 
3532 	if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
3533 		u_int swap;
3534 
3535 		swap = hv0;
3536 		hv0 = hv1;
3537 		hv1 = swap;
3538 	}
3539 
3540 	if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0] >=
3541 	    softn->ipf_nat_maxbucket) {
3542 		DT1(ns_bucket_max_0, int,
3543 		    softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]);
3544 		NBUMPSIDE(0, ns_bucket_max);
3545 		return -1;
3546 	}
3547 
3548 	if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1] >=
3549 	    softn->ipf_nat_maxbucket) {
3550 		DT1(ns_bucket_max_1, int,
3551 		    softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]);
3552 		NBUMPSIDE(1, ns_bucket_max);
3553 		return -1;
3554 	}
3555 
3556 	/*
3557 	 * The ordering of operations in the list and hash table insertion
3558 	 * is very important.  The last operation for each task should be
3559 	 * to update the top of the list, after all the "nexts" have been
3560 	 * done so that walking the list while it is being done does not
3561 	 * find strange pointers.
3562 	 *
3563 	 * Global list of NAT instances
3564 	 */
3565 	nat->nat_next = softn->ipf_nat_instances;
3566 	nat->nat_pnext = &softn->ipf_nat_instances;
3567 	if (softn->ipf_nat_instances)
3568 		softn->ipf_nat_instances->nat_pnext = &nat->nat_next;
3569 	softn->ipf_nat_instances = nat;
3570 
3571 	/*
3572 	 * Inbound hash table.
3573 	 */
3574 	natp = &softn->ipf_nat_table[0][hv0];
3575 	nat->nat_phnext[0] = natp;
3576 	nat->nat_hnext[0] = *natp;
3577 	if (*natp) {
3578 		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
3579 	} else {
3580 		NBUMPSIDE(0, ns_inuse);
3581 	}
3582 	*natp = nat;
3583 	NBUMPSIDE(0, ns_bucketlen[hv0]);
3584 
3585 	/*
3586 	 * Outbound hash table.
3587 	 */
3588 	natp = &softn->ipf_nat_table[1][hv1];
3589 	nat->nat_phnext[1] = natp;
3590 	nat->nat_hnext[1] = *natp;
3591 	if (*natp)
3592 		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
3593 	else {
3594 		NBUMPSIDE(1, ns_inuse);
3595 	}
3596 	*natp = nat;
3597 	NBUMPSIDE(1, ns_bucketlen[hv1]);
3598 
3599 	ipf_nat_setqueue(softc, softn, nat);
3600 
3601 	if (nat->nat_dir & NAT_OUTBOUND) {
3602 		NBUMPSIDE(1, ns_added);
3603 	} else {
3604 		NBUMPSIDE(0, ns_added);
3605 	}
3606 	softn->ipf_nat_stats.ns_active++;
3607 	return 0;
3608 }
3609 
3610 
3611 /* ------------------------------------------------------------------------ */
3612 /* Function:    ipf_nat_icmperrorlookup                                     */
3613 /* Returns:     nat_t* - point to matching NAT structure                    */
3614 /* Parameters:  fin(I) - pointer to packet information                      */
3615 /*              dir(I) - direction of packet (in/out)                       */
3616 /*                                                                          */
3617 /* Check if the ICMP error message is related to an existing TCP, UDP or    */
3618 /* ICMP query nat entry.  It is assumed that the packet is already of the   */
3619 /* the required length.                                                     */
3620 /* ------------------------------------------------------------------------ */
3621 nat_t *
ipf_nat_icmperrorlookup(fin,dir)3622 ipf_nat_icmperrorlookup(fin, dir)
3623 	fr_info_t *fin;
3624 	int dir;
3625 {
3626 	ipf_main_softc_t *softc = fin->fin_main_soft;
3627 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3628 	int flags = 0, type, minlen;
3629 	icmphdr_t *icmp, *orgicmp;
3630 	nat_stat_side_t *nside;
3631 	tcphdr_t *tcp = NULL;
3632 	u_short data[2];
3633 	nat_t *nat;
3634 	ip_t *oip;
3635 	u_int p;
3636 
3637 	icmp = fin->fin_dp;
3638 	type = icmp->icmp_type;
3639 	nside = &softn->ipf_nat_stats.ns_side[fin->fin_out];
3640 	/*
3641 	 * Does it at least have the return (basic) IP header ?
3642 	 * Only a basic IP header (no options) should be with an ICMP error
3643 	 * header.  Also, if it's not an error type, then return.
3644 	 */
3645 	if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) {
3646 		ATOMIC_INCL(nside->ns_icmp_basic);
3647 		return NULL;
3648 	}
3649 
3650 	/*
3651 	 * Check packet size
3652 	 */
3653 	oip = (ip_t *)((char *)fin->fin_dp + 8);
3654 	minlen = IP_HL(oip) << 2;
3655 	if ((minlen < sizeof(ip_t)) ||
3656 	    (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) {
3657 		ATOMIC_INCL(nside->ns_icmp_size);
3658 		return NULL;
3659 	}
3660 
3661 	/*
3662 	 * Is the buffer big enough for all of it ?  It's the size of the IP
3663 	 * header claimed in the encapsulated part which is of concern.  It
3664 	 * may be too big to be in this buffer but not so big that it's
3665 	 * outside the ICMP packet, leading to TCP deref's causing problems.
3666 	 * This is possible because we don't know how big oip_hl is when we
3667 	 * do the pullup early in ipf_check() and thus can't gaurantee it is
3668 	 * all here now.
3669 	 */
3670 #ifdef  ipf_nat_KERNEL
3671 	{
3672 	mb_t *m;
3673 
3674 	m = fin->fin_m;
3675 # if defined(MENTAT)
3676 	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
3677 	    (char *)m->b_wptr) {
3678 		ATOMIC_INCL(nside->ns_icmp_mbuf);
3679 		return NULL;
3680 	}
3681 # else
3682 	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
3683 	    (char *)fin->fin_ip + M_LEN(m)) {
3684 		ATOMIC_INCL(nside->ns_icmp_mbuf);
3685 		return NULL;
3686 	}
3687 # endif
3688 	}
3689 #endif
3690 
3691 	if (fin->fin_daddr != oip->ip_src.s_addr) {
3692 		ATOMIC_INCL(nside->ns_icmp_address);
3693 		return NULL;
3694 	}
3695 
3696 	p = oip->ip_p;
3697 	if (p == IPPROTO_TCP)
3698 		flags = IPN_TCP;
3699 	else if (p == IPPROTO_UDP)
3700 		flags = IPN_UDP;
3701 	else if (p == IPPROTO_ICMP) {
3702 		orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2));
3703 
3704 		/* see if this is related to an ICMP query */
3705 		if (ipf_nat_icmpquerytype(orgicmp->icmp_type)) {
3706 			data[0] = fin->fin_data[0];
3707 			data[1] = fin->fin_data[1];
3708 			fin->fin_data[0] = 0;
3709 			fin->fin_data[1] = orgicmp->icmp_id;
3710 
3711 			flags = IPN_ICMPERR|IPN_ICMPQUERY;
3712 			/*
3713 			 * NOTE : dir refers to the direction of the original
3714 			 *        ip packet. By definition the icmp error
3715 			 *        message flows in the opposite direction.
3716 			 */
3717 			if (dir == NAT_INBOUND)
3718 				nat = ipf_nat_inlookup(fin, flags, p,
3719 						       oip->ip_dst,
3720 						       oip->ip_src);
3721 			else
3722 				nat = ipf_nat_outlookup(fin, flags, p,
3723 							oip->ip_dst,
3724 							oip->ip_src);
3725 			fin->fin_data[0] = data[0];
3726 			fin->fin_data[1] = data[1];
3727 			return nat;
3728 		}
3729 	}
3730 
3731 	if (flags & IPN_TCPUDP) {
3732 		minlen += 8;		/* + 64bits of data to get ports */
3733 		/* TRACE (fin,minlen) */
3734 		if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) {
3735 			ATOMIC_INCL(nside->ns_icmp_short);
3736 			return NULL;
3737 		}
3738 
3739 		data[0] = fin->fin_data[0];
3740 		data[1] = fin->fin_data[1];
3741 		tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2));
3742 		fin->fin_data[0] = ntohs(tcp->th_dport);
3743 		fin->fin_data[1] = ntohs(tcp->th_sport);
3744 
3745 		if (dir == NAT_INBOUND) {
3746 			nat = ipf_nat_inlookup(fin, flags, p, oip->ip_dst,
3747 					       oip->ip_src);
3748 		} else {
3749 			nat = ipf_nat_outlookup(fin, flags, p, oip->ip_dst,
3750 					    oip->ip_src);
3751 		}
3752 		fin->fin_data[0] = data[0];
3753 		fin->fin_data[1] = data[1];
3754 		return nat;
3755 	}
3756 	if (dir == NAT_INBOUND)
3757 		nat = ipf_nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
3758 	else
3759 		nat = ipf_nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
3760 
3761 	return nat;
3762 }
3763 
3764 
3765 /* ------------------------------------------------------------------------ */
3766 /* Function:    ipf_nat_icmperror                                           */
3767 /* Returns:     nat_t* - point to matching NAT structure                    */
3768 /* Parameters:  fin(I)    - pointer to packet information                   */
3769 /*              nflags(I) - NAT flags for this packet                       */
3770 /*              dir(I)    - direction of packet (in/out)                    */
3771 /*                                                                          */
3772 /* Fix up an ICMP packet which is an error message for an existing NAT      */
3773 /* session.  This will correct both packet header data and checksums.       */
3774 /*                                                                          */
3775 /* This should *ONLY* be used for incoming ICMP error packets to make sure  */
3776 /* a NAT'd ICMP packet gets correctly recognised.                           */
3777 /* ------------------------------------------------------------------------ */
3778 nat_t *
ipf_nat_icmperror(fin,nflags,dir)3779 ipf_nat_icmperror(fin, nflags, dir)
3780 	fr_info_t *fin;
3781 	u_int *nflags;
3782 	int dir;
3783 {
3784 	ipf_main_softc_t *softc = fin->fin_main_soft;
3785 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3786 	u_32_t sum1, sum2, sumd, sumd2;
3787 	struct in_addr a1, a2, a3, a4;
3788 	int flags, dlen, odst;
3789 	icmphdr_t *icmp;
3790 	u_short *csump;
3791 	tcphdr_t *tcp;
3792 	nat_t *nat;
3793 	ip_t *oip;
3794 	void *dp;
3795 
3796 	if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
3797 		NBUMPSIDED(fin->fin_out, ns_icmp_short);
3798 		return NULL;
3799 	}
3800 
3801 	/*
3802 	 * ipf_nat_icmperrorlookup() will return NULL for `defective' packets.
3803 	 */
3804 	if ((fin->fin_v != 4) || !(nat = ipf_nat_icmperrorlookup(fin, dir))) {
3805 		NBUMPSIDED(fin->fin_out, ns_icmp_notfound);
3806 		return NULL;
3807 	}
3808 
3809 	tcp = NULL;
3810 	csump = NULL;
3811 	flags = 0;
3812 	sumd2 = 0;
3813 	*nflags = IPN_ICMPERR;
3814 	icmp = fin->fin_dp;
3815 	oip = (ip_t *)&icmp->icmp_ip;
3816 	dp = (((char *)oip) + (IP_HL(oip) << 2));
3817 	if (oip->ip_p == IPPROTO_TCP) {
3818 		tcp = (tcphdr_t *)dp;
3819 		csump = (u_short *)&tcp->th_sum;
3820 		flags = IPN_TCP;
3821 	} else if (oip->ip_p == IPPROTO_UDP) {
3822 		udphdr_t *udp;
3823 
3824 		udp = (udphdr_t *)dp;
3825 		tcp = (tcphdr_t *)dp;
3826 		csump = (u_short *)&udp->uh_sum;
3827 		flags = IPN_UDP;
3828 	} else if (oip->ip_p == IPPROTO_ICMP)
3829 		flags = IPN_ICMPQUERY;
3830 	dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip);
3831 
3832 	/*
3833 	 * Need to adjust ICMP header to include the real IP#'s and
3834 	 * port #'s.  Only apply a checksum change relative to the
3835 	 * IP address change as it will be modified again in ipf_nat_checkout
3836 	 * for both address and port.  Two checksum changes are
3837 	 * necessary for the two header address changes.  Be careful
3838 	 * to only modify the checksum once for the port # and twice
3839 	 * for the IP#.
3840 	 */
3841 
3842 	/*
3843 	 * Step 1
3844 	 * Fix the IP addresses in the offending IP packet. You also need
3845 	 * to adjust the IP header checksum of that offending IP packet.
3846 	 *
3847 	 * Normally, you would expect that the ICMP checksum of the
3848 	 * ICMP error message needs to be adjusted as well for the
3849 	 * IP address change in oip.
3850 	 * However, this is a NOP, because the ICMP checksum is
3851 	 * calculated over the complete ICMP packet, which includes the
3852 	 * changed oip IP addresses and oip->ip_sum. However, these
3853 	 * two changes cancel each other out (if the delta for
3854 	 * the IP address is x, then the delta for ip_sum is minus x),
3855 	 * so no change in the icmp_cksum is necessary.
3856 	 *
3857 	 * Inbound ICMP
3858 	 * ------------
3859 	 * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
3860 	 * - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b)
3861 	 * - OIP_SRC(c)=nat_newsrcip,          OIP_DST(b)=nat_newdstip
3862 	 *=> OIP_SRC(c)=nat_oldsrcip,          OIP_DST(b)=nat_olddstip
3863 	 *
3864 	 * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
3865 	 * - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a)
3866 	 * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
3867 	 *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3868 	 *
3869 	 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
3870 	 * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d)
3871 	 * - OIP_SRC(c)=nat_newsrcip,          OIP_DST(d)=nat_newdstip
3872 	 *=> OIP_SRC(c)=nat_oldsrcip,          OIP_DST(d)=nat_olddstip
3873 	 *
3874 	 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
3875 	 * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
3876 	 * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
3877 	 *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3878 	 *
3879 	 * Outbound ICMP
3880 	 * -------------
3881 	 * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
3882 	 * - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
3883 	 * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
3884 	 *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3885 	 *
3886 	 * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
3887 	 * - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c)
3888 	 * - OIP_SRC(a)=nat_newsrcip,          OIP_DST(c)=nat_newdstip
3889 	 *=> OIP_SRC(a)=nat_oldsrcip,          OIP_DST(c)=nat_olddstip
3890 	 *
3891 	 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
3892 	 * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d)
3893 	 * - OIP_SRC(c)=nat_olddstip,          OIP_DST(d)=nat_oldsrcip
3894 	 *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3895 	 *
3896 	 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
3897 	 * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a)
3898 	 * - OIP_SRC(b)=nat_newsrcip,          OIP_DST(a)=nat_newdstip
3899 	 *=> OIP_SRC(a)=nat_oldsrcip,          OIP_DST(c)=nat_olddstip
3900 	 */
3901 
3902 	if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) ||
3903 	    ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) {
3904 		a1.s_addr = ntohl(nat->nat_osrcaddr);
3905 		a4.s_addr = ntohl(oip->ip_src.s_addr);
3906 		a3.s_addr = ntohl(nat->nat_odstaddr);
3907 		a2.s_addr = ntohl(oip->ip_dst.s_addr);
3908 		oip->ip_src.s_addr = htonl(a1.s_addr);
3909 		oip->ip_dst.s_addr = htonl(a3.s_addr);
3910 		odst = 1;
3911 	} else {
3912 		a1.s_addr = ntohl(nat->nat_ndstaddr);
3913 		a2.s_addr = ntohl(oip->ip_dst.s_addr);
3914 		a3.s_addr = ntohl(nat->nat_nsrcaddr);
3915 		a4.s_addr = ntohl(oip->ip_src.s_addr);
3916 		oip->ip_dst.s_addr = htonl(a3.s_addr);
3917 		oip->ip_src.s_addr = htonl(a1.s_addr);
3918 		odst = 0;
3919 	}
3920 	sum1 = 0;
3921 	sum2 = 0;
3922 	sumd = 0;
3923 	CALC_SUMD(a2.s_addr, a3.s_addr, sum1);
3924 	CALC_SUMD(a4.s_addr, a1.s_addr, sum2);
3925 	sumd = sum2 + sum1;
3926 	if (sumd != 0)
3927 		ipf_fix_datacksum(&oip->ip_sum, sumd);
3928 
3929 	sumd2 = sumd;
3930 	sum1 = 0;
3931 	sum2 = 0;
3932 
3933 	/*
3934 	 * Fix UDP pseudo header checksum to compensate for the
3935 	 * IP address change.
3936 	 */
3937 	if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) {
3938 		u_32_t sum3, sum4, sumt;
3939 
3940 		/*
3941 		 * Step 2 :
3942 		 * For offending TCP/UDP IP packets, translate the ports as
3943 		 * well, based on the NAT specification. Of course such
3944 		 * a change may be reflected in the ICMP checksum as well.
3945 		 *
3946 		 * Since the port fields are part of the TCP/UDP checksum
3947 		 * of the offending IP packet, you need to adjust that checksum
3948 		 * as well... except that the change in the port numbers should
3949 		 * be offset by the checksum change.  However, the TCP/UDP
3950 		 * checksum will also need to change if there has been an
3951 		 * IP address change.
3952 		 */
3953 		if (odst == 1) {
3954 			sum1 = ntohs(nat->nat_osport);
3955 			sum4 = ntohs(tcp->th_sport);
3956 			sum3 = ntohs(nat->nat_odport);
3957 			sum2 = ntohs(tcp->th_dport);
3958 
3959 			tcp->th_sport = htons(sum1);
3960 			tcp->th_dport = htons(sum3);
3961 		} else {
3962 			sum1 = ntohs(nat->nat_ndport);
3963 			sum2 = ntohs(tcp->th_dport);
3964 			sum3 = ntohs(nat->nat_nsport);
3965 			sum4 = ntohs(tcp->th_sport);
3966 
3967 			tcp->th_dport = htons(sum3);
3968 			tcp->th_sport = htons(sum1);
3969 		}
3970 		CALC_SUMD(sum4, sum1, sumt);
3971 		sumd += sumt;
3972 		CALC_SUMD(sum2, sum3, sumt);
3973 		sumd += sumt;
3974 
3975 		if (sumd != 0 || sumd2 != 0) {
3976 			/*
3977 			 * At this point, sumd is the delta to apply to the
3978 			 * TCP/UDP header, given the changes in both the IP
3979 			 * address and the ports and sumd2 is the delta to
3980 			 * apply to the ICMP header, given the IP address
3981 			 * change delta that may need to be applied to the
3982 			 * TCP/UDP checksum instead.
3983 			 *
3984 			 * If we will both the IP and TCP/UDP checksums
3985 			 * then the ICMP checksum changes by the address
3986 			 * delta applied to the TCP/UDP checksum.  If we
3987 			 * do not change the TCP/UDP checksum them we
3988 			 * apply the delta in ports to the ICMP checksum.
3989 			 */
3990 			if (oip->ip_p == IPPROTO_UDP) {
3991 				if ((dlen >= 8) && (*csump != 0)) {
3992 					ipf_fix_datacksum(csump, sumd);
3993 				} else {
3994 					CALC_SUMD(sum1, sum4, sumd2);
3995 					CALC_SUMD(sum3, sum2, sumt);
3996 					sumd2 += sumt;
3997 				}
3998 			} else if (oip->ip_p == IPPROTO_TCP) {
3999 				if (dlen >= 18) {
4000 					ipf_fix_datacksum(csump, sumd);
4001 				} else {
4002 					CALC_SUMD(sum1, sum4, sumd2);
4003 					CALC_SUMD(sum3, sum2, sumt);
4004 					sumd2 += sumt;
4005 				}
4006 			}
4007 			if (sumd2 != 0) {
4008 				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
4009 				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
4010 				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
4011 				ipf_fix_incksum(0, &icmp->icmp_cksum, sumd2, 0);
4012 			}
4013 		}
4014 	} else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) {
4015 		icmphdr_t *orgicmp;
4016 
4017 		/*
4018 		 * XXX - what if this is bogus hl and we go off the end ?
4019 		 * In this case, ipf_nat_icmperrorlookup() will have
4020 		 * returned NULL.
4021 		 */
4022 		orgicmp = (icmphdr_t *)dp;
4023 
4024 		if (odst == 1) {
4025 			if (orgicmp->icmp_id != nat->nat_osport) {
4026 
4027 				/*
4028 				 * Fix ICMP checksum (of the offening ICMP
4029 				 * query packet) to compensate the change
4030 				 * in the ICMP id of the offending ICMP
4031 				 * packet.
4032 				 *
4033 				 * Since you modify orgicmp->icmp_id with
4034 				 * a delta (say x) and you compensate that
4035 				 * in origicmp->icmp_cksum with a delta
4036 				 * minus x, you don't have to adjust the
4037 				 * overall icmp->icmp_cksum
4038 				 */
4039 				sum1 = ntohs(orgicmp->icmp_id);
4040 				sum2 = ntohs(nat->nat_oicmpid);
4041 				CALC_SUMD(sum1, sum2, sumd);
4042 				orgicmp->icmp_id = nat->nat_oicmpid;
4043 				ipf_fix_datacksum(&orgicmp->icmp_cksum, sumd);
4044 			}
4045 		} /* nat_dir == NAT_INBOUND is impossible for icmp queries */
4046 	}
4047 	return nat;
4048 }
4049 
4050 
4051 /*
4052  *       MAP-IN    MAP-OUT   RDR-IN   RDR-OUT
4053  * osrc    X       == src    == src      X
4054  * odst    X       == dst    == dst      X
4055  * nsrc  == dst      X         X      == dst
4056  * ndst  == src      X         X      == src
4057  * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND
4058  */
4059 /*
4060  * NB: these lookups don't lock access to the list, it assumed that it has
4061  * already been done!
4062  */
4063 /* ------------------------------------------------------------------------ */
4064 /* Function:    ipf_nat_inlookup                                            */
4065 /* Returns:     nat_t* - NULL == no match,                                  */
4066 /*                       else pointer to matching NAT entry                 */
4067 /* Parameters:  fin(I)    - pointer to packet information                   */
4068 /*              flags(I)  - NAT flags for this packet                       */
4069 /*              p(I)      - protocol for this packet                        */
4070 /*              src(I)    - source IP address                               */
4071 /*              mapdst(I) - destination IP address                          */
4072 /*                                                                          */
4073 /* Lookup a nat entry based on the mapped destination ip address/port and   */
4074 /* real source address/port.  We use this lookup when receiving a packet,   */
4075 /* we're looking for a table entry, based on the destination address.       */
4076 /*                                                                          */
4077 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
4078 /*                                                                          */
4079 /* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
4080 /*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
4081 /*                                                                          */
4082 /* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
4083 /*            the packet is of said protocol                                */
4084 /* ------------------------------------------------------------------------ */
4085 nat_t *
ipf_nat_inlookup(fin,flags,p,src,mapdst)4086 ipf_nat_inlookup(fin, flags, p, src, mapdst)
4087 	fr_info_t *fin;
4088 	u_int flags, p;
4089 	struct in_addr src , mapdst;
4090 {
4091 	ipf_main_softc_t *softc = fin->fin_main_soft;
4092 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4093 	u_short sport, dport;
4094 	grehdr_t *gre;
4095 	ipnat_t *ipn;
4096 	u_int sflags;
4097 	nat_t *nat;
4098 	int nflags;
4099 	u_32_t dst;
4100 	void *ifp;
4101 	u_int hv, rhv;
4102 
4103 	ifp = fin->fin_ifp;
4104 	gre = NULL;
4105 	dst = mapdst.s_addr;
4106 	sflags = flags & NAT_TCPUDPICMP;
4107 
4108 	switch (p)
4109 	{
4110 	case IPPROTO_TCP :
4111 	case IPPROTO_UDP :
4112 		sport = htons(fin->fin_data[0]);
4113 		dport = htons(fin->fin_data[1]);
4114 		break;
4115 	case IPPROTO_ICMP :
4116 		sport = 0;
4117 		dport = fin->fin_data[1];
4118 		break;
4119 	default :
4120 		sport = 0;
4121 		dport = 0;
4122 		break;
4123 	}
4124 
4125 
4126 	if ((flags & SI_WILDP) != 0)
4127 		goto find_in_wild_ports;
4128 
4129 	rhv = NAT_HASH_FN(dst, dport, 0xffffffff);
4130 	rhv = NAT_HASH_FN(src.s_addr, rhv + sport, 0xffffffff);
4131 	hv = rhv % softn->ipf_nat_table_sz;
4132 	nat = softn->ipf_nat_table[1][hv];
4133 	/* TRACE dst, dport, src, sport, hv, nat */
4134 
4135 	for (; nat; nat = nat->nat_hnext[1]) {
4136 		if (nat->nat_ifps[0] != NULL) {
4137 			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
4138 				continue;
4139 		}
4140 
4141 		if (nat->nat_pr[0] != p)
4142 			continue;
4143 
4144 		switch (nat->nat_dir)
4145 		{
4146 		case NAT_INBOUND :
4147 		case NAT_DIVERTIN :
4148 			if (nat->nat_v[0] != 4)
4149 				continue;
4150 			if (nat->nat_osrcaddr != src.s_addr ||
4151 			    nat->nat_odstaddr != dst)
4152 				continue;
4153 			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4154 				if (nat->nat_osport != sport)
4155 					continue;
4156 				if (nat->nat_odport != dport)
4157 					continue;
4158 
4159 			} else if (p == IPPROTO_ICMP) {
4160 				if (nat->nat_osport != dport) {
4161 					continue;
4162 				}
4163 			}
4164 			break;
4165 		case NAT_DIVERTOUT :
4166 			if (nat->nat_dlocal)
4167 				continue;
4168 		case NAT_OUTBOUND :
4169 			if (nat->nat_v[1] != 4)
4170 				continue;
4171 			if (nat->nat_dlocal)
4172 				continue;
4173 			if (nat->nat_dlocal)
4174 				continue;
4175 			if (nat->nat_ndstaddr != src.s_addr ||
4176 			    nat->nat_nsrcaddr != dst)
4177 				continue;
4178 			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4179 				if (nat->nat_ndport != sport)
4180 					continue;
4181 				if (nat->nat_nsport != dport)
4182 					continue;
4183 
4184 			} else if (p == IPPROTO_ICMP) {
4185 				if (nat->nat_osport != dport) {
4186 					continue;
4187 				}
4188 			}
4189 			break;
4190 		}
4191 
4192 
4193 		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4194 			ipn = nat->nat_ptr;
4195 			if ((ipn != NULL) && (nat->nat_aps != NULL))
4196 				if (ipf_proxy_match(fin, nat) != 0)
4197 					continue;
4198 		}
4199 		if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
4200 			nat->nat_ifps[0] = ifp;
4201 			nat->nat_mtu[0] = GETIFMTU_4(ifp);
4202 		}
4203 		return nat;
4204 	}
4205 
4206 	/*
4207 	 * So if we didn't find it but there are wildcard members in the hash
4208 	 * table, go back and look for them.  We do this search and update here
4209 	 * because it is modifying the NAT table and we want to do this only
4210 	 * for the first packet that matches.  The exception, of course, is
4211 	 * for "dummy" (FI_IGNORE) lookups.
4212 	 */
4213 find_in_wild_ports:
4214 	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
4215 		NBUMPSIDEX(0, ns_lookup_miss, ns_lookup_miss_0);
4216 		return NULL;
4217 	}
4218 	if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
4219 		NBUMPSIDEX(0, ns_lookup_nowild, ns_lookup_nowild_0);
4220 		return NULL;
4221 	}
4222 
4223 	RWLOCK_EXIT(&softc->ipf_nat);
4224 
4225 	hv = NAT_HASH_FN(dst, 0, 0xffffffff);
4226 	hv = NAT_HASH_FN(src.s_addr, hv, softn->ipf_nat_table_sz);
4227 	WRITE_ENTER(&softc->ipf_nat);
4228 
4229 	nat = softn->ipf_nat_table[1][hv];
4230 	/* TRACE dst, src, hv, nat */
4231 	for (; nat; nat = nat->nat_hnext[1]) {
4232 		if (nat->nat_ifps[0] != NULL) {
4233 			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
4234 				continue;
4235 		}
4236 
4237 		if (nat->nat_pr[0] != fin->fin_p)
4238 			continue;
4239 
4240 		switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
4241 		{
4242 		case NAT_INBOUND :
4243 			if (nat->nat_v[0] != 4)
4244 				continue;
4245 			if (nat->nat_osrcaddr != src.s_addr ||
4246 			    nat->nat_odstaddr != dst)
4247 				continue;
4248 			break;
4249 		case NAT_OUTBOUND :
4250 			if (nat->nat_v[1] != 4)
4251 				continue;
4252 			if (nat->nat_ndstaddr != src.s_addr ||
4253 			    nat->nat_nsrcaddr != dst)
4254 				continue;
4255 			break;
4256 		}
4257 
4258 		nflags = nat->nat_flags;
4259 		if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
4260 			continue;
4261 
4262 		if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags,
4263 				   NAT_INBOUND) == 1) {
4264 			if ((fin->fin_flx & FI_IGNORE) != 0)
4265 				break;
4266 			if ((nflags & SI_CLONE) != 0) {
4267 				nat = ipf_nat_clone(fin, nat);
4268 				if (nat == NULL)
4269 					break;
4270 			} else {
4271 				MUTEX_ENTER(&softn->ipf_nat_new);
4272 				softn->ipf_nat_stats.ns_wilds--;
4273 				MUTEX_EXIT(&softn->ipf_nat_new);
4274 			}
4275 
4276 			if (nat->nat_dir == NAT_INBOUND) {
4277 				if (nat->nat_osport == 0) {
4278 					nat->nat_osport = sport;
4279 					nat->nat_nsport = sport;
4280 				}
4281 				if (nat->nat_odport == 0) {
4282 					nat->nat_odport = dport;
4283 					nat->nat_ndport = dport;
4284 				}
4285 			} else if (nat->nat_dir == NAT_OUTBOUND) {
4286 				if (nat->nat_osport == 0) {
4287 					nat->nat_osport = dport;
4288 					nat->nat_nsport = dport;
4289 				}
4290 				if (nat->nat_odport == 0) {
4291 					nat->nat_odport = sport;
4292 					nat->nat_ndport = sport;
4293 				}
4294 			}
4295 			if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
4296 				nat->nat_ifps[0] = ifp;
4297 				nat->nat_mtu[0] = GETIFMTU_4(ifp);
4298 			}
4299 			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
4300 			ipf_nat_tabmove(softn, nat);
4301 			break;
4302 		}
4303 	}
4304 
4305 	MUTEX_DOWNGRADE(&softc->ipf_nat);
4306 
4307 	if (nat == NULL) {
4308 		NBUMPSIDE(0, ns_lookup_miss);
4309 	}
4310 	return nat;
4311 }
4312 
4313 
4314 /* ------------------------------------------------------------------------ */
4315 /* Function:    ipf_nat_tabmove                                             */
4316 /* Returns:     Nil                                                         */
4317 /* Parameters:  softn(I) - pointer to NAT context structure                 */
4318 /*              nat(I)   - pointer to NAT structure                         */
4319 /* Write Lock:  ipf_nat                                                     */
4320 /*                                                                          */
4321 /* This function is only called for TCP/UDP NAT table entries where the     */
4322 /* original was placed in the table without hashing on the ports and we now */
4323 /* want to include hashing on port numbers.                                 */
4324 /* ------------------------------------------------------------------------ */
4325 static void
ipf_nat_tabmove(softn,nat)4326 ipf_nat_tabmove(softn, nat)
4327 	ipf_nat_softc_t *softn;
4328 	nat_t *nat;
4329 {
4330 	u_int hv0, hv1, rhv0, rhv1;
4331 	natstat_t *nsp;
4332 	nat_t **natp;
4333 
4334 	if (nat->nat_flags & SI_CLONE)
4335 		return;
4336 
4337 	nsp = &softn->ipf_nat_stats;
4338 	/*
4339 	 * Remove the NAT entry from the old location
4340 	 */
4341 	if (nat->nat_hnext[0])
4342 		nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
4343 	*nat->nat_phnext[0] = nat->nat_hnext[0];
4344 	nsp->ns_side[0].ns_bucketlen[nat->nat_hv[0] %
4345 				     softn->ipf_nat_table_sz]--;
4346 
4347 	if (nat->nat_hnext[1])
4348 		nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
4349 	*nat->nat_phnext[1] = nat->nat_hnext[1];
4350 	nsp->ns_side[1].ns_bucketlen[nat->nat_hv[1] %
4351 				     softn->ipf_nat_table_sz]--;
4352 
4353 	/*
4354 	 * Add into the NAT table in the new position
4355 	 */
4356 	rhv0 = NAT_HASH_FN(nat->nat_osrcaddr, nat->nat_osport, 0xffffffff);
4357 	rhv0 = NAT_HASH_FN(nat->nat_odstaddr, rhv0 + nat->nat_odport,
4358 			   0xffffffff);
4359 	rhv1 = NAT_HASH_FN(nat->nat_nsrcaddr, nat->nat_nsport, 0xffffffff);
4360 	rhv1 = NAT_HASH_FN(nat->nat_ndstaddr, rhv1 + nat->nat_ndport,
4361 			   0xffffffff);
4362 
4363 	hv0 = rhv0 % softn->ipf_nat_table_sz;
4364 	hv1 = rhv1 % softn->ipf_nat_table_sz;
4365 
4366 	if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
4367 		u_int swap;
4368 
4369 		swap = hv0;
4370 		hv0 = hv1;
4371 		hv1 = swap;
4372 	}
4373 
4374 	/* TRACE nat_osrcaddr, nat_osport, nat_odstaddr, nat_odport, hv0 */
4375 	/* TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr, nat_ndport, hv1 */
4376 
4377 	nat->nat_hv[0] = rhv0;
4378 	natp = &softn->ipf_nat_table[0][hv0];
4379 	if (*natp)
4380 		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
4381 	nat->nat_phnext[0] = natp;
4382 	nat->nat_hnext[0] = *natp;
4383 	*natp = nat;
4384 	nsp->ns_side[0].ns_bucketlen[hv0]++;
4385 
4386 	nat->nat_hv[1] = rhv1;
4387 	natp = &softn->ipf_nat_table[1][hv1];
4388 	if (*natp)
4389 		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
4390 	nat->nat_phnext[1] = natp;
4391 	nat->nat_hnext[1] = *natp;
4392 	*natp = nat;
4393 	nsp->ns_side[1].ns_bucketlen[hv1]++;
4394 }
4395 
4396 
4397 /* ------------------------------------------------------------------------ */
4398 /* Function:    ipf_nat_outlookup                                           */
4399 /* Returns:     nat_t* - NULL == no match,                                  */
4400 /*                       else pointer to matching NAT entry                 */
4401 /* Parameters:  fin(I)   - pointer to packet information                    */
4402 /*              flags(I) - NAT flags for this packet                        */
4403 /*              p(I)     - protocol for this packet                         */
4404 /*              src(I)   - source IP address                                */
4405 /*              dst(I)   - destination IP address                           */
4406 /*              rw(I)    - 1 == write lock on  held, 0 == read lock.        */
4407 /*                                                                          */
4408 /* Lookup a nat entry based on the source 'real' ip address/port and        */
4409 /* destination address/port.  We use this lookup when sending a packet out, */
4410 /* we're looking for a table entry, based on the source address.            */
4411 /*                                                                          */
4412 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
4413 /*                                                                          */
4414 /* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
4415 /*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
4416 /*                                                                          */
4417 /* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
4418 /*            the packet is of said protocol                                */
4419 /* ------------------------------------------------------------------------ */
4420 nat_t *
ipf_nat_outlookup(fin,flags,p,src,dst)4421 ipf_nat_outlookup(fin, flags, p, src, dst)
4422 	fr_info_t *fin;
4423 	u_int flags, p;
4424 	struct in_addr src , dst;
4425 {
4426 	ipf_main_softc_t *softc = fin->fin_main_soft;
4427 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4428 	u_short sport, dport;
4429 	u_int sflags;
4430 	ipnat_t *ipn;
4431 	nat_t *nat;
4432 	void *ifp;
4433 	u_int hv;
4434 
4435 	ifp = fin->fin_ifp;
4436 	sflags = flags & IPN_TCPUDPICMP;
4437 
4438 	switch (p)
4439 	{
4440 	case IPPROTO_TCP :
4441 	case IPPROTO_UDP :
4442 		sport = htons(fin->fin_data[0]);
4443 		dport = htons(fin->fin_data[1]);
4444 		break;
4445 	case IPPROTO_ICMP :
4446 		sport = 0;
4447 		dport = fin->fin_data[1];
4448 		break;
4449 	default :
4450 		sport = 0;
4451 		dport = 0;
4452 		break;
4453 	}
4454 
4455 	if ((flags & SI_WILDP) != 0)
4456 		goto find_out_wild_ports;
4457 
4458 	hv = NAT_HASH_FN(src.s_addr, sport, 0xffffffff);
4459 	hv = NAT_HASH_FN(dst.s_addr, hv + dport, softn->ipf_nat_table_sz);
4460 	nat = softn->ipf_nat_table[0][hv];
4461 
4462 	/* TRACE src, sport, dst, dport, hv, nat */
4463 
4464 	for (; nat; nat = nat->nat_hnext[0]) {
4465 		if (nat->nat_ifps[1] != NULL) {
4466 			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
4467 				continue;
4468 		}
4469 
4470 		if (nat->nat_pr[1] != p)
4471 			continue;
4472 
4473 		switch (nat->nat_dir)
4474 		{
4475 		case NAT_INBOUND :
4476 		case NAT_DIVERTIN :
4477 			if (nat->nat_v[1] != 4)
4478 				continue;
4479 			if (nat->nat_ndstaddr != src.s_addr ||
4480 			    nat->nat_nsrcaddr != dst.s_addr)
4481 				continue;
4482 
4483 			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4484 				if (nat->nat_ndport != sport)
4485 					continue;
4486 				if (nat->nat_nsport != dport)
4487 					continue;
4488 
4489 			} else if (p == IPPROTO_ICMP) {
4490 				if (nat->nat_osport != dport) {
4491 					continue;
4492 				}
4493 			}
4494 			break;
4495 		case NAT_OUTBOUND :
4496 		case NAT_DIVERTOUT :
4497 			if (nat->nat_v[0] != 4)
4498 				continue;
4499 			if (nat->nat_osrcaddr != src.s_addr ||
4500 			    nat->nat_odstaddr != dst.s_addr)
4501 				continue;
4502 
4503 			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4504 				if (nat->nat_odport != dport)
4505 					continue;
4506 				if (nat->nat_osport != sport)
4507 					continue;
4508 
4509 			} else if (p == IPPROTO_ICMP) {
4510 				if (nat->nat_osport != dport) {
4511 					continue;
4512 				}
4513 			}
4514 			break;
4515 		}
4516 
4517 		ipn = nat->nat_ptr;
4518 		if ((ipn != NULL) && (nat->nat_aps != NULL))
4519 			if (ipf_proxy_match(fin, nat) != 0)
4520 				continue;
4521 
4522 		if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
4523 			nat->nat_ifps[1] = ifp;
4524 			nat->nat_mtu[1] = GETIFMTU_4(ifp);
4525 		}
4526 		return nat;
4527 	}
4528 
4529 	/*
4530 	 * So if we didn't find it but there are wildcard members in the hash
4531 	 * table, go back and look for them.  We do this search and update here
4532 	 * because it is modifying the NAT table and we want to do this only
4533 	 * for the first packet that matches.  The exception, of course, is
4534 	 * for "dummy" (FI_IGNORE) lookups.
4535 	 */
4536 find_out_wild_ports:
4537 	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
4538 		NBUMPSIDEX(1, ns_lookup_miss, ns_lookup_miss_1);
4539 		return NULL;
4540 	}
4541 	if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
4542 		NBUMPSIDEX(1, ns_lookup_nowild, ns_lookup_nowild_1);
4543 		return NULL;
4544 	}
4545 
4546 	RWLOCK_EXIT(&softc->ipf_nat);
4547 
4548 	hv = NAT_HASH_FN(src.s_addr, 0, 0xffffffff);
4549 	hv = NAT_HASH_FN(dst.s_addr, hv, softn->ipf_nat_table_sz);
4550 
4551 	WRITE_ENTER(&softc->ipf_nat);
4552 
4553 	nat = softn->ipf_nat_table[0][hv];
4554 	for (; nat; nat = nat->nat_hnext[0]) {
4555 		if (nat->nat_ifps[1] != NULL) {
4556 			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
4557 				continue;
4558 		}
4559 
4560 		if (nat->nat_pr[1] != fin->fin_p)
4561 			continue;
4562 
4563 		switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
4564 		{
4565 		case NAT_INBOUND :
4566 			if (nat->nat_v[1] != 4)
4567 				continue;
4568 			if (nat->nat_ndstaddr != src.s_addr ||
4569 			    nat->nat_nsrcaddr != dst.s_addr)
4570 				continue;
4571 			break;
4572 		case NAT_OUTBOUND :
4573 			if (nat->nat_v[0] != 4)
4574 				continue;
4575 			if (nat->nat_osrcaddr != src.s_addr ||
4576 			    nat->nat_odstaddr != dst.s_addr)
4577 				continue;
4578 			break;
4579 		}
4580 
4581 		if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP)))
4582 			continue;
4583 
4584 		if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags,
4585 				   NAT_OUTBOUND) == 1) {
4586 			if ((fin->fin_flx & FI_IGNORE) != 0)
4587 				break;
4588 			if ((nat->nat_flags & SI_CLONE) != 0) {
4589 				nat = ipf_nat_clone(fin, nat);
4590 				if (nat == NULL)
4591 					break;
4592 			} else {
4593 				MUTEX_ENTER(&softn->ipf_nat_new);
4594 				softn->ipf_nat_stats.ns_wilds--;
4595 				MUTEX_EXIT(&softn->ipf_nat_new);
4596 			}
4597 
4598 			if (nat->nat_dir == NAT_OUTBOUND) {
4599 				if (nat->nat_osport == 0) {
4600 					nat->nat_osport = sport;
4601 					nat->nat_nsport = sport;
4602 				}
4603 				if (nat->nat_odport == 0) {
4604 					nat->nat_odport = dport;
4605 					nat->nat_ndport = dport;
4606 				}
4607 			} else if (nat->nat_dir == NAT_INBOUND) {
4608 				if (nat->nat_osport == 0) {
4609 					nat->nat_osport = dport;
4610 					nat->nat_nsport = dport;
4611 				}
4612 				if (nat->nat_odport == 0) {
4613 					nat->nat_odport = sport;
4614 					nat->nat_ndport = sport;
4615 				}
4616 			}
4617 			if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
4618 				nat->nat_ifps[1] = ifp;
4619 				nat->nat_mtu[1] = GETIFMTU_4(ifp);
4620 			}
4621 			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
4622 			ipf_nat_tabmove(softn, nat);
4623 			break;
4624 		}
4625 	}
4626 
4627 	MUTEX_DOWNGRADE(&softc->ipf_nat);
4628 
4629 	if (nat == NULL) {
4630 		NBUMPSIDE(1, ns_lookup_miss);
4631 	}
4632 	return nat;
4633 }
4634 
4635 
4636 /* ------------------------------------------------------------------------ */
4637 /* Function:    ipf_nat_lookupredir                                         */
4638 /* Returns:     nat_t* - NULL == no match,                                  */
4639 /*                       else pointer to matching NAT entry                 */
4640 /* Parameters:  np(I) - pointer to description of packet to find NAT table  */
4641 /*                      entry for.                                          */
4642 /*                                                                          */
4643 /* Lookup the NAT tables to search for a matching redirect                  */
4644 /* The contents of natlookup_t should imitate those found in a packet that  */
4645 /* would be translated - ie a packet coming in for RDR or going out for MAP.*/
4646 /* We can do the lookup in one of two ways, imitating an inbound or         */
4647 /* outbound  packet.  By default we assume outbound, unless IPN_IN is set.  */
4648 /* For IN, the fields are set as follows:                                   */
4649 /*     nl_real* = source information                                        */
4650 /*     nl_out* = destination information (translated)                       */
4651 /* For an out packet, the fields are set like this:                         */
4652 /*     nl_in* = source information (untranslated)                           */
4653 /*     nl_out* = destination information (translated)                       */
4654 /* ------------------------------------------------------------------------ */
4655 nat_t *
ipf_nat_lookupredir(np)4656 ipf_nat_lookupredir(np)
4657 	natlookup_t *np;
4658 {
4659 	fr_info_t fi;
4660 	nat_t *nat;
4661 
4662 	bzero((char *)&fi, sizeof(fi));
4663 	if (np->nl_flags & IPN_IN) {
4664 		fi.fin_data[0] = ntohs(np->nl_realport);
4665 		fi.fin_data[1] = ntohs(np->nl_outport);
4666 	} else {
4667 		fi.fin_data[0] = ntohs(np->nl_inport);
4668 		fi.fin_data[1] = ntohs(np->nl_outport);
4669 	}
4670 	if (np->nl_flags & IPN_TCP)
4671 		fi.fin_p = IPPROTO_TCP;
4672 	else if (np->nl_flags & IPN_UDP)
4673 		fi.fin_p = IPPROTO_UDP;
4674 	else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY))
4675 		fi.fin_p = IPPROTO_ICMP;
4676 
4677 	/*
4678 	 * We can do two sorts of lookups:
4679 	 * - IPN_IN: we have the `real' and `out' address, look for `in'.
4680 	 * - default: we have the `in' and `out' address, look for `real'.
4681 	 */
4682 	if (np->nl_flags & IPN_IN) {
4683 		if ((nat = ipf_nat_inlookup(&fi, np->nl_flags, fi.fin_p,
4684 					    np->nl_realip, np->nl_outip))) {
4685 			np->nl_inip = nat->nat_odstip;
4686 			np->nl_inport = nat->nat_odport;
4687 		}
4688 	} else {
4689 		/*
4690 		 * If nl_inip is non null, this is a lookup based on the real
4691 		 * ip address. Else, we use the fake.
4692 		 */
4693 		if ((nat = ipf_nat_outlookup(&fi, np->nl_flags, fi.fin_p,
4694 					 np->nl_inip, np->nl_outip))) {
4695 
4696 			if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
4697 				fr_info_t fin;
4698 				bzero((char *)&fin, sizeof(fin));
4699 				fin.fin_p = nat->nat_pr[0];
4700 				fin.fin_data[0] = ntohs(nat->nat_ndport);
4701 				fin.fin_data[1] = ntohs(nat->nat_nsport);
4702 				if (ipf_nat_inlookup(&fin, np->nl_flags,
4703 						     fin.fin_p, nat->nat_ndstip,
4704 						     nat->nat_nsrcip) != NULL) {
4705 					np->nl_flags &= ~IPN_FINDFORWARD;
4706 				}
4707 			}
4708 
4709 			np->nl_realip = nat->nat_odstip;
4710 			np->nl_realport = nat->nat_odport;
4711 		}
4712  	}
4713 
4714 	return nat;
4715 }
4716 
4717 
4718 /* ------------------------------------------------------------------------ */
4719 /* Function:    ipf_nat_match                                               */
4720 /* Returns:     int - 0 == no match, 1 == match                             */
4721 /* Parameters:  fin(I)   - pointer to packet information                    */
4722 /*              np(I)    - pointer to NAT rule                              */
4723 /*                                                                          */
4724 /* Pull the matching of a packet against a NAT rule out of that complex     */
4725 /* loop inside ipf_nat_checkin() and lay it out properly in its own function. */
4726 /* ------------------------------------------------------------------------ */
4727 static int
ipf_nat_match(fin,np)4728 ipf_nat_match(fin, np)
4729 	fr_info_t *fin;
4730 	ipnat_t *np;
4731 {
4732 	ipf_main_softc_t *softc = fin->fin_main_soft;
4733 	frtuc_t *ft;
4734 	int match;
4735 
4736 	match = 0;
4737 	switch (np->in_osrcatype)
4738 	{
4739 	case FRI_NORMAL :
4740 		match = ((fin->fin_saddr & np->in_osrcmsk) != np->in_osrcaddr);
4741 		break;
4742 	case FRI_LOOKUP :
4743 		match = (*np->in_osrcfunc)(softc, np->in_osrcptr,
4744 					   4, &fin->fin_saddr, fin->fin_plen);
4745 		break;
4746 	}
4747 	match ^= ((np->in_flags & IPN_NOTSRC) != 0);
4748 	if (match)
4749 		return 0;
4750 
4751 	match = 0;
4752 	switch (np->in_odstatype)
4753 	{
4754 	case FRI_NORMAL :
4755 		match = ((fin->fin_daddr & np->in_odstmsk) != np->in_odstaddr);
4756 		break;
4757 	case FRI_LOOKUP :
4758 		match = (*np->in_odstfunc)(softc, np->in_odstptr,
4759 					   4, &fin->fin_daddr, fin->fin_plen);
4760 		break;
4761 	}
4762 
4763 	match ^= ((np->in_flags & IPN_NOTDST) != 0);
4764 	if (match)
4765 		return 0;
4766 
4767 	ft = &np->in_tuc;
4768 	if (!(fin->fin_flx & FI_TCPUDP) ||
4769 	    (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
4770 		if (ft->ftu_scmp || ft->ftu_dcmp)
4771 			return 0;
4772 		return 1;
4773 	}
4774 
4775 	return ipf_tcpudpchk(&fin->fin_fi, ft);
4776 }
4777 
4778 
4779 /* ------------------------------------------------------------------------ */
4780 /* Function:    ipf_nat_update                                              */
4781 /* Returns:     Nil                                                         */
4782 /* Parameters:  fin(I) - pointer to packet information                      */
4783 /*              nat(I) - pointer to NAT structure                           */
4784 /*                                                                          */
4785 /* Updates the lifetime of a NAT table entry for non-TCP packets.  Must be  */
4786 /* called with fin_rev updated - i.e. after calling ipf_nat_proto().        */
4787 /*                                                                          */
4788 /* This *MUST* be called after ipf_nat_proto() as it expects fin_rev to     */
4789 /* already be set.                                                          */
4790 /* ------------------------------------------------------------------------ */
4791 void
ipf_nat_update(fin,nat)4792 ipf_nat_update(fin, nat)
4793 	fr_info_t *fin;
4794 	nat_t *nat;
4795 {
4796 	ipf_main_softc_t *softc = fin->fin_main_soft;
4797 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4798 	ipftq_t *ifq, *ifq2;
4799 	ipftqent_t *tqe;
4800 	ipnat_t *np = nat->nat_ptr;
4801 
4802 	tqe = &nat->nat_tqe;
4803 	ifq = tqe->tqe_ifq;
4804 
4805 	/*
4806 	 * We allow over-riding of NAT timeouts from NAT rules, even for
4807 	 * TCP, however, if it is TCP and there is no rule timeout set,
4808 	 * then do not update the timeout here.
4809 	 */
4810 	if (np != NULL) {
4811 		np->in_bytes[fin->fin_rev] += fin->fin_plen;
4812 		ifq2 = np->in_tqehead[fin->fin_rev];
4813 	} else {
4814 		ifq2 = NULL;
4815 	}
4816 
4817 	if (nat->nat_pr[0] == IPPROTO_TCP && ifq2 == NULL) {
4818 		(void) ipf_tcp_age(&nat->nat_tqe, fin, softn->ipf_nat_tcptq,
4819 				   0, 2);
4820 	} else {
4821 		if (ifq2 == NULL) {
4822 			if (nat->nat_pr[0] == IPPROTO_UDP)
4823 				ifq2 = fin->fin_rev ? &softn->ipf_nat_udpacktq :
4824 						      &softn->ipf_nat_udptq;
4825 			else if (nat->nat_pr[0] == IPPROTO_ICMP ||
4826 				 nat->nat_pr[0] == IPPROTO_ICMPV6)
4827 				ifq2 = fin->fin_rev ? &softn->ipf_nat_icmpacktq:
4828 						      &softn->ipf_nat_icmptq;
4829 			else
4830 				ifq2 = &softn->ipf_nat_iptq;
4831 		}
4832 
4833 		ipf_movequeue(softc->ipf_ticks, tqe, ifq, ifq2);
4834 	}
4835 }
4836 
4837 
4838 /* ------------------------------------------------------------------------ */
4839 /* Function:    ipf_nat_checkout                                            */
4840 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
4841 /*                     0 == no packet translation occurred,                 */
4842 /*                     1 == packet was successfully translated.             */
4843 /* Parameters:  fin(I)   - pointer to packet information                    */
4844 /*              passp(I) - pointer to filtering result flags                */
4845 /*                                                                          */
4846 /* Check to see if an outcoming packet should be changed.  ICMP packets are */
4847 /* first checked to see if they match an existing entry (if an error),      */
4848 /* otherwise a search of the current NAT table is made.  If neither results */
4849 /* in a match then a search for a matching NAT rule is made.  Create a new  */
4850 /* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
4851 /* packet header(s) as required.                                            */
4852 /* ------------------------------------------------------------------------ */
4853 int
ipf_nat_checkout(fin,passp)4854 ipf_nat_checkout(fin, passp)
4855 	fr_info_t *fin;
4856 	u_32_t *passp;
4857 {
4858 	ipnat_t *np = NULL, *npnext;
4859 	struct ifnet *ifp, *sifp;
4860 	ipf_main_softc_t *softc;
4861 	ipf_nat_softc_t *softn;
4862 	icmphdr_t *icmp = NULL;
4863 	tcphdr_t *tcp = NULL;
4864 	int rval, natfailed;
4865 	u_int nflags = 0;
4866 	u_32_t ipa, iph;
4867 	int natadd = 1;
4868 	frentry_t *fr;
4869 	nat_t *nat;
4870 
4871 	if (fin->fin_v == 6) {
4872 #ifdef USE_INET6
4873 		return ipf_nat6_checkout(fin, passp);
4874 #else
4875 		return 0;
4876 #endif
4877 	}
4878 
4879 	softc = fin->fin_main_soft;
4880 	softn = softc->ipf_nat_soft;
4881 
4882 	if (softn->ipf_nat_lock != 0)
4883 		return 0;
4884 	if (softn->ipf_nat_stats.ns_rules == 0 &&
4885 	    softn->ipf_nat_instances == NULL)
4886 		return 0;
4887 
4888 	natfailed = 0;
4889 	fr = fin->fin_fr;
4890 	sifp = fin->fin_ifp;
4891 	if (fr != NULL) {
4892 		ifp = fr->fr_tifs[fin->fin_rev].fd_ptr;
4893 		if ((ifp != NULL) && (ifp != (void *)-1))
4894 			fin->fin_ifp = ifp;
4895 	}
4896 	ifp = fin->fin_ifp;
4897 
4898 	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
4899 		switch (fin->fin_p)
4900 		{
4901 		case IPPROTO_TCP :
4902 			nflags = IPN_TCP;
4903 			break;
4904 		case IPPROTO_UDP :
4905 			nflags = IPN_UDP;
4906 			break;
4907 		case IPPROTO_ICMP :
4908 			icmp = fin->fin_dp;
4909 
4910 			/*
4911 			 * This is an incoming packet, so the destination is
4912 			 * the icmp_id and the source port equals 0
4913 			 */
4914 			if ((fin->fin_flx & FI_ICMPQUERY) != 0)
4915 				nflags = IPN_ICMPQUERY;
4916 			break;
4917 		default :
4918 			break;
4919 		}
4920 
4921 		if ((nflags & IPN_TCPUDP))
4922 			tcp = fin->fin_dp;
4923 	}
4924 
4925 	ipa = fin->fin_saddr;
4926 
4927 	READ_ENTER(&softc->ipf_nat);
4928 
4929 	if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
4930 	    (nat = ipf_nat_icmperror(fin, &nflags, NAT_OUTBOUND)))
4931 		/*EMPTY*/;
4932 	else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
4933 		natadd = 0;
4934 	else if ((nat = ipf_nat_outlookup(fin, nflags|NAT_SEARCH,
4935 				      (u_int)fin->fin_p, fin->fin_src,
4936 				      fin->fin_dst))) {
4937 		nflags = nat->nat_flags;
4938 	} else if (fin->fin_off == 0) {
4939 		u_32_t hv, msk, nmsk = 0;
4940 
4941 		/*
4942 		 * If there is no current entry in the nat table for this IP#,
4943 		 * create one for it (if there is a matching rule).
4944 		 */
4945 maskloop:
4946 		msk = softn->ipf_nat_map_active_masks[nmsk];
4947 		iph = ipa & msk;
4948 		hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_maprules_sz);
4949 retry_roundrobin:
4950 		for (np = softn->ipf_nat_map_rules[hv]; np; np = npnext) {
4951 			npnext = np->in_mnext;
4952 			if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
4953 				continue;
4954 			if (np->in_v[0] != 4)
4955 				continue;
4956 			if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p))
4957 				continue;
4958 			if ((np->in_flags & IPN_RF) &&
4959 			    !(np->in_flags & nflags))
4960 				continue;
4961 			if (np->in_flags & IPN_FILTER) {
4962 				switch (ipf_nat_match(fin, np))
4963 				{
4964 				case 0 :
4965 					continue;
4966 				case -1 :
4967 					rval = -3;
4968 					goto outmatchfail;
4969 				case 1 :
4970 				default :
4971 					break;
4972 				}
4973 			} else if ((ipa & np->in_osrcmsk) != np->in_osrcaddr)
4974 				continue;
4975 
4976 			if ((fr != NULL) &&
4977 			    !ipf_matchtag(&np->in_tag, &fr->fr_nattag))
4978 				continue;
4979 
4980 			if (np->in_plabel != -1) {
4981 				if (((np->in_flags & IPN_FILTER) == 0) &&
4982 				    (np->in_odport != fin->fin_data[1]))
4983 					continue;
4984 				if (ipf_proxy_ok(fin, tcp, np) == 0)
4985 					continue;
4986 			}
4987 
4988 			if (np->in_flags & IPN_NO) {
4989 				np->in_hits++;
4990 				break;
4991 			}
4992 			MUTEX_ENTER(&softn->ipf_nat_new);
4993 			/*
4994 			 * If we've matched a round-robin rule but it has
4995 			 * moved in the list since we got it, start over as
4996 			 * this is now no longer correct.
4997 			 */
4998 			if (npnext != np->in_mnext) {
4999 				if ((np->in_flags & IPN_ROUNDR) != 0) {
5000 					MUTEX_EXIT(&softn->ipf_nat_new);
5001 					goto retry_roundrobin;
5002 				}
5003 				npnext = np->in_mnext;
5004 			}
5005 
5006 			nat = ipf_nat_add(fin, np, NULL, nflags, NAT_OUTBOUND);
5007 			MUTEX_EXIT(&softn->ipf_nat_new);
5008 			if (nat != NULL) {
5009 				natfailed = 0;
5010 				break;
5011 			}
5012 			natfailed = -2;
5013 		}
5014 		if ((np == NULL) && (nmsk < softn->ipf_nat_map_max)) {
5015 			nmsk++;
5016 			goto maskloop;
5017 		}
5018 	}
5019 
5020 	if (nat != NULL) {
5021 		rval = ipf_nat_out(fin, nat, natadd, nflags);
5022 		if (rval == 1) {
5023 			MUTEX_ENTER(&nat->nat_lock);
5024 			ipf_nat_update(fin, nat);
5025 			nat->nat_bytes[1] += fin->fin_plen;
5026 			nat->nat_pkts[1]++;
5027 			fin->fin_pktnum = nat->nat_pkts[1];
5028 			MUTEX_EXIT(&nat->nat_lock);
5029 		}
5030 	} else
5031 		rval = natfailed;
5032 outmatchfail:
5033 	RWLOCK_EXIT(&softc->ipf_nat);
5034 
5035 	switch (rval)
5036 	{
5037 	case -3 :
5038 		/* ipf_nat_match() failure */
5039 		/* FALLTHROUGH */
5040 	case -2 :
5041 		/* retry_roundrobin loop failure */
5042 		/* FALLTHROUGH */
5043 	case -1 :
5044 		/* proxy failure detected by ipf_nat_out() */
5045 		if (passp != NULL) {
5046 			DT2(frb_natv4out, fr_info_t *, fin, int, rval);
5047 			NBUMPSIDED(1, ns_drop);
5048 			*passp = FR_BLOCK;
5049 			fin->fin_reason = FRB_NATV4;
5050 		}
5051 		fin->fin_flx |= FI_BADNAT;
5052 		NBUMPSIDED(1, ns_badnat);
5053 		rval = -1;	/* We only return -1 on error. */
5054 		break;
5055 	case 0 :
5056 		NBUMPSIDE(1, ns_ignored);
5057 		break;
5058 	case 1 :
5059 		NBUMPSIDE(1, ns_translated);
5060 		break;
5061 	}
5062 	fin->fin_ifp = sifp;
5063 	return rval;
5064 }
5065 
5066 /* ------------------------------------------------------------------------ */
5067 /* Function:    ipf_nat_out                                                 */
5068 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
5069 /*                     1 == packet was successfully translated.             */
5070 /* Parameters:  fin(I)    - pointer to packet information                   */
5071 /*              nat(I)    - pointer to NAT structure                        */
5072 /*              natadd(I) - flag indicating if it is safe to add frag cache */
5073 /*              nflags(I) - NAT flags set for this packet                   */
5074 /*                                                                          */
5075 /* Translate a packet coming "out" on an interface.                         */
5076 /* ------------------------------------------------------------------------ */
5077 int
ipf_nat_out(fin,nat,natadd,nflags)5078 ipf_nat_out(fin, nat, natadd, nflags)
5079 	fr_info_t *fin;
5080 	nat_t *nat;
5081 	int natadd;
5082 	u_32_t nflags;
5083 {
5084 	ipf_main_softc_t *softc = fin->fin_main_soft;
5085 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5086 	icmphdr_t *icmp;
5087 	tcphdr_t *tcp;
5088 	ipnat_t *np;
5089 	int skip;
5090 	int i;
5091 
5092 	tcp = NULL;
5093 	icmp = NULL;
5094 	np = nat->nat_ptr;
5095 
5096 	if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL))
5097 		(void) ipf_frag_natnew(softc, fin, 0, nat);
5098 
5099 	/*
5100 	 * Fix up checksums, not by recalculating them, but
5101 	 * simply computing adjustments.
5102 	 * This is only done for STREAMS based IP implementations where the
5103 	 * checksum has already been calculated by IP.  In all other cases,
5104 	 * IPFilter is called before the checksum needs calculating so there
5105 	 * is no call to modify whatever is in the header now.
5106 	 */
5107 	if (nflags == IPN_ICMPERR) {
5108 		u_32_t s1, s2, sumd, msumd;
5109 
5110 		s1 = LONG_SUM(ntohl(fin->fin_saddr));
5111 		if (nat->nat_dir == NAT_OUTBOUND) {
5112 			s2 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
5113 		} else {
5114 			s2 = LONG_SUM(ntohl(nat->nat_odstaddr));
5115 		}
5116 		CALC_SUMD(s1, s2, sumd);
5117 		msumd = sumd;
5118 
5119 		s1 = LONG_SUM(ntohl(fin->fin_daddr));
5120 		if (nat->nat_dir == NAT_OUTBOUND) {
5121 			s2 = LONG_SUM(ntohl(nat->nat_ndstaddr));
5122 		} else {
5123 			s2 = LONG_SUM(ntohl(nat->nat_osrcaddr));
5124 		}
5125 		CALC_SUMD(s1, s2, sumd);
5126 		msumd += sumd;
5127 
5128 		ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, msumd, 0);
5129 	}
5130 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5131     defined(linux) || defined(BRIDGE_IPF) || defined(__FreeBSD__)
5132 	else {
5133 		/*
5134 		 * Strictly speaking, this isn't necessary on BSD
5135 		 * kernels because they do checksum calculation after
5136 		 * this code has run BUT if ipfilter is being used
5137 		 * to do NAT as a bridge, that code doesn't exist.
5138 		 */
5139 		switch (nat->nat_dir)
5140 		{
5141 		case NAT_OUTBOUND :
5142 			ipf_fix_outcksum(fin->fin_cksum & FI_CK_L4PART,
5143 					 &fin->fin_ip->ip_sum,
5144 					 nat->nat_ipsumd, 0);
5145 			break;
5146 
5147 		case NAT_INBOUND :
5148 			ipf_fix_incksum(fin->fin_cksum & FI_CK_L4PART,
5149 					&fin->fin_ip->ip_sum,
5150 					nat->nat_ipsumd, 0);
5151 			break;
5152 
5153 		default :
5154 			break;
5155 		}
5156 	}
5157 #endif
5158 
5159 	/*
5160 	 * Address assignment is after the checksum modification because
5161 	 * we are using the address in the packet for determining the
5162 	 * correct checksum offset (the ICMP error could be coming from
5163 	 * anyone...)
5164 	 */
5165 	switch (nat->nat_dir)
5166 	{
5167 	case NAT_OUTBOUND :
5168 		fin->fin_ip->ip_src = nat->nat_nsrcip;
5169 		fin->fin_saddr = nat->nat_nsrcaddr;
5170 		fin->fin_ip->ip_dst = nat->nat_ndstip;
5171 		fin->fin_daddr = nat->nat_ndstaddr;
5172 		break;
5173 
5174 	case NAT_INBOUND :
5175 		fin->fin_ip->ip_src = nat->nat_odstip;
5176 		fin->fin_saddr = nat->nat_ndstaddr;
5177 		fin->fin_ip->ip_dst = nat->nat_osrcip;
5178 		fin->fin_daddr = nat->nat_nsrcaddr;
5179 		break;
5180 
5181 	case NAT_DIVERTIN :
5182 	    {
5183 		mb_t *m;
5184 
5185 		skip = ipf_nat_decap(fin, nat);
5186 		if (skip <= 0) {
5187 			NBUMPSIDED(1, ns_decap_fail);
5188 			return -1;
5189 		}
5190 
5191 		m = fin->fin_m;
5192 
5193 #if defined(MENTAT) && defined(_KERNEL)
5194 		m->b_rptr += skip;
5195 #else
5196 		m->m_data += skip;
5197 		m->m_len -= skip;
5198 
5199 # ifdef M_PKTHDR
5200 		if (m->m_flags & M_PKTHDR)
5201 			m->m_pkthdr.len -= skip;
5202 # endif
5203 #endif
5204 
5205 		MUTEX_ENTER(&nat->nat_lock);
5206 		ipf_nat_update(fin, nat);
5207 		MUTEX_EXIT(&nat->nat_lock);
5208 		fin->fin_flx |= FI_NATED;
5209 		if (np != NULL && np->in_tag.ipt_num[0] != 0)
5210 			fin->fin_nattag = &np->in_tag;
5211 		return 1;
5212 		/* NOTREACHED */
5213 	    }
5214 
5215 	case NAT_DIVERTOUT :
5216 	    {
5217 		u_32_t s1, s2, sumd;
5218 		udphdr_t *uh;
5219 		ip_t *ip;
5220 		mb_t *m;
5221 
5222 		m = M_DUP(np->in_divmp);
5223 		if (m == NULL) {
5224 			NBUMPSIDED(1, ns_divert_dup);
5225 			return -1;
5226 		}
5227 
5228 		ip = MTOD(m, ip_t *);
5229 		ip->ip_id = htons(ipf_nextipid(fin));
5230 		s2 = ntohs(ip->ip_id);
5231 
5232 		s1 = ip->ip_len;
5233 		ip->ip_len = ntohs(ip->ip_len);
5234 		ip->ip_len += fin->fin_plen;
5235 		ip->ip_len = htons(ip->ip_len);
5236 		s2 += ntohs(ip->ip_len);
5237 		CALC_SUMD(s1, s2, sumd);
5238 
5239 		uh = (udphdr_t *)(ip + 1);
5240 		uh->uh_ulen += fin->fin_plen;
5241 		uh->uh_ulen = htons(uh->uh_ulen);
5242 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5243     defined(linux) || defined(BRIDGE_IPF) || defined(__FreeBSD__)
5244 		ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
5245 #endif
5246 
5247 		PREP_MB_T(fin, m);
5248 
5249 		fin->fin_src = ip->ip_src;
5250 		fin->fin_dst = ip->ip_dst;
5251 		fin->fin_ip = ip;
5252 		fin->fin_plen += sizeof(ip_t) + 8;	/* UDP + IPv4 hdr */
5253 		fin->fin_dlen += sizeof(ip_t) + 8;	/* UDP + IPv4 hdr */
5254 
5255 		nflags &= ~IPN_TCPUDPICMP;
5256 
5257 		break;
5258 	    }
5259 
5260 	default :
5261 		break;
5262 	}
5263 
5264 	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
5265 		u_short *csump;
5266 
5267 		if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) {
5268 			tcp = fin->fin_dp;
5269 
5270 			switch (nat->nat_dir)
5271 			{
5272 			case NAT_OUTBOUND :
5273 				tcp->th_sport = nat->nat_nsport;
5274 				fin->fin_data[0] = ntohs(nat->nat_nsport);
5275 				tcp->th_dport = nat->nat_ndport;
5276 				fin->fin_data[1] = ntohs(nat->nat_ndport);
5277 				break;
5278 
5279 			case NAT_INBOUND :
5280 				tcp->th_sport = nat->nat_odport;
5281 				fin->fin_data[0] = ntohs(nat->nat_odport);
5282 				tcp->th_dport = nat->nat_osport;
5283 				fin->fin_data[1] = ntohs(nat->nat_osport);
5284 				break;
5285 			}
5286 		}
5287 
5288 		if ((nat->nat_nsport != 0) && (nflags & IPN_ICMPQUERY)) {
5289 			icmp = fin->fin_dp;
5290 			icmp->icmp_id = nat->nat_nicmpid;
5291 		}
5292 
5293 		csump = ipf_nat_proto(fin, nat, nflags);
5294 
5295 		/*
5296 		 * The above comments do not hold for layer 4 (or higher)
5297 		 * checksums...
5298 		 */
5299 		if (csump != NULL) {
5300 			if (nat->nat_dir == NAT_OUTBOUND)
5301 				ipf_fix_outcksum(fin->fin_cksum, csump,
5302 						 nat->nat_sumd[0],
5303 						 nat->nat_sumd[1] +
5304 						 fin->fin_dlen);
5305 			else
5306 				ipf_fix_incksum(fin->fin_cksum, csump,
5307 						nat->nat_sumd[0],
5308 						nat->nat_sumd[1] +
5309 						fin->fin_dlen);
5310 		}
5311 	}
5312 
5313 	ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
5314 	/* ------------------------------------------------------------- */
5315 	/* A few quick notes:                                            */
5316 	/*      Following are test conditions prior to calling the       */
5317 	/*      ipf_proxy_check routine.                                 */
5318 	/*                                                               */
5319 	/*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
5320 	/*      with a redirect rule, we attempt to match the packet's   */
5321 	/*      source port against in_dport, otherwise we'd compare the */
5322 	/*      packet's destination.                                    */
5323 	/* ------------------------------------------------------------- */
5324 	if ((np != NULL) && (np->in_apr != NULL)) {
5325 		i = ipf_proxy_check(fin, nat);
5326 		if (i == 0) {
5327 			i = 1;
5328 		} else if (i == -1) {
5329 			NBUMPSIDED(1, ns_ipf_proxy_fail);
5330 		}
5331 	} else {
5332 		i = 1;
5333 	}
5334 	fin->fin_flx |= FI_NATED;
5335 	return i;
5336 }
5337 
5338 
5339 /* ------------------------------------------------------------------------ */
5340 /* Function:    ipf_nat_checkin                                             */
5341 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
5342 /*                     0 == no packet translation occurred,                 */
5343 /*                     1 == packet was successfully translated.             */
5344 /* Parameters:  fin(I)   - pointer to packet information                    */
5345 /*              passp(I) - pointer to filtering result flags                */
5346 /*                                                                          */
5347 /* Check to see if an incoming packet should be changed.  ICMP packets are  */
5348 /* first checked to see if they match an existing entry (if an error),      */
5349 /* otherwise a search of the current NAT table is made.  If neither results */
5350 /* in a match then a search for a matching NAT rule is made.  Create a new  */
5351 /* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
5352 /* packet header(s) as required.                                            */
5353 /* ------------------------------------------------------------------------ */
5354 int
ipf_nat_checkin(fin,passp)5355 ipf_nat_checkin(fin, passp)
5356 	fr_info_t *fin;
5357 	u_32_t *passp;
5358 {
5359 	ipf_main_softc_t *softc;
5360 	ipf_nat_softc_t *softn;
5361 	u_int nflags, natadd;
5362 	ipnat_t *np, *npnext;
5363 	int rval, natfailed;
5364 	struct ifnet *ifp;
5365 	struct in_addr in;
5366 	icmphdr_t *icmp;
5367 	tcphdr_t *tcp;
5368 	u_short dport;
5369 	nat_t *nat;
5370 	u_32_t iph;
5371 
5372 	softc = fin->fin_main_soft;
5373 	softn = softc->ipf_nat_soft;
5374 
5375 	if (softn->ipf_nat_lock != 0)
5376 		return 0;
5377 	if (softn->ipf_nat_stats.ns_rules == 0 &&
5378 	    softn->ipf_nat_instances == NULL)
5379 		return 0;
5380 
5381 	tcp = NULL;
5382 	icmp = NULL;
5383 	dport = 0;
5384 	natadd = 1;
5385 	nflags = 0;
5386 	natfailed = 0;
5387 	ifp = fin->fin_ifp;
5388 
5389 	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
5390 		switch (fin->fin_p)
5391 		{
5392 		case IPPROTO_TCP :
5393 			nflags = IPN_TCP;
5394 			break;
5395 		case IPPROTO_UDP :
5396 			nflags = IPN_UDP;
5397 			break;
5398 		case IPPROTO_ICMP :
5399 			icmp = fin->fin_dp;
5400 
5401 			/*
5402 			 * This is an incoming packet, so the destination is
5403 			 * the icmp_id and the source port equals 0
5404 			 */
5405 			if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
5406 				nflags = IPN_ICMPQUERY;
5407 				dport = icmp->icmp_id;
5408 			} break;
5409 		default :
5410 			break;
5411 		}
5412 
5413 		if ((nflags & IPN_TCPUDP)) {
5414 			tcp = fin->fin_dp;
5415 			dport = fin->fin_data[1];
5416 		}
5417 	}
5418 
5419 	in = fin->fin_dst;
5420 
5421 	READ_ENTER(&softc->ipf_nat);
5422 
5423 	if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
5424 	    (nat = ipf_nat_icmperror(fin, &nflags, NAT_INBOUND)))
5425 		/*EMPTY*/;
5426 	else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
5427 		natadd = 0;
5428 	else if ((nat = ipf_nat_inlookup(fin, nflags|NAT_SEARCH,
5429 					 (u_int)fin->fin_p,
5430 					 fin->fin_src, in))) {
5431 		nflags = nat->nat_flags;
5432 	} else if (fin->fin_off == 0) {
5433 		u_32_t hv, msk, rmsk = 0;
5434 
5435 		/*
5436 		 * If there is no current entry in the nat table for this IP#,
5437 		 * create one for it (if there is a matching rule).
5438 		 */
5439 maskloop:
5440 		msk = softn->ipf_nat_rdr_active_masks[rmsk];
5441 		iph = in.s_addr & msk;
5442 		hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_rdrrules_sz);
5443 retry_roundrobin:
5444 		/* TRACE (iph,msk,rmsk,hv,softn->ipf_nat_rdrrules_sz) */
5445 		for (np = softn->ipf_nat_rdr_rules[hv]; np; np = npnext) {
5446 			npnext = np->in_rnext;
5447 			if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
5448 				continue;
5449 			if (np->in_v[0] != 4)
5450 				continue;
5451 			if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p))
5452 				continue;
5453 			if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
5454 				continue;
5455 			if (np->in_flags & IPN_FILTER) {
5456 				switch (ipf_nat_match(fin, np))
5457 				{
5458 				case 0 :
5459 					continue;
5460 				case -1 :
5461 					rval = -3;
5462 					goto inmatchfail;
5463 				case 1 :
5464 				default :
5465 					break;
5466 				}
5467 			} else {
5468 				if ((in.s_addr & np->in_odstmsk) !=
5469 				    np->in_odstaddr)
5470 					continue;
5471 				if (np->in_odport &&
5472 				    ((np->in_dtop < dport) ||
5473 				     (dport < np->in_odport)))
5474 					continue;
5475 			}
5476 
5477 			if (np->in_plabel != -1) {
5478 				if (!ipf_proxy_ok(fin, tcp, np)) {
5479 					continue;
5480 				}
5481 			}
5482 
5483 			if (np->in_flags & IPN_NO) {
5484 				np->in_hits++;
5485 				break;
5486 			}
5487 
5488 			MUTEX_ENTER(&softn->ipf_nat_new);
5489 			/*
5490 			 * If we've matched a round-robin rule but it has
5491 			 * moved in the list since we got it, start over as
5492 			 * this is now no longer correct.
5493 			 */
5494 			if (npnext != np->in_rnext) {
5495 				if ((np->in_flags & IPN_ROUNDR) != 0) {
5496 					MUTEX_EXIT(&softn->ipf_nat_new);
5497 					goto retry_roundrobin;
5498 				}
5499 				npnext = np->in_rnext;
5500 			}
5501 
5502 			nat = ipf_nat_add(fin, np, NULL, nflags, NAT_INBOUND);
5503 			MUTEX_EXIT(&softn->ipf_nat_new);
5504 			if (nat != NULL) {
5505 				natfailed = 0;
5506 				break;
5507 			}
5508 			natfailed = -2;
5509 		}
5510 		if ((np == NULL) && (rmsk < softn->ipf_nat_rdr_max)) {
5511 			rmsk++;
5512 			goto maskloop;
5513 		}
5514 	}
5515 
5516 	if (nat != NULL) {
5517 		rval = ipf_nat_in(fin, nat, natadd, nflags);
5518 		if (rval == 1) {
5519 			MUTEX_ENTER(&nat->nat_lock);
5520 			ipf_nat_update(fin, nat);
5521 			nat->nat_bytes[0] += fin->fin_plen;
5522 			nat->nat_pkts[0]++;
5523 			fin->fin_pktnum = nat->nat_pkts[0];
5524 			MUTEX_EXIT(&nat->nat_lock);
5525 		}
5526 	} else
5527 		rval = natfailed;
5528 inmatchfail:
5529 	RWLOCK_EXIT(&softc->ipf_nat);
5530 
5531 	switch (rval)
5532 	{
5533 	case -3 :
5534 		/* ipf_nat_match() failure */
5535 		/* FALLTHROUGH */
5536 	case -2 :
5537 		/* retry_roundrobin loop failure */
5538 		/* FALLTHROUGH */
5539 	case -1 :
5540 		/* proxy failure detected by ipf_nat_in() */
5541 		if (passp != NULL) {
5542 			DT2(frb_natv4in, fr_info_t *, fin, int, rval);
5543 			NBUMPSIDED(0, ns_drop);
5544 			*passp = FR_BLOCK;
5545 			fin->fin_reason = FRB_NATV4;
5546 		}
5547 		fin->fin_flx |= FI_BADNAT;
5548 		NBUMPSIDED(0, ns_badnat);
5549 		rval = -1;	/* We only return -1 on error. */
5550 		break;
5551 	case 0 :
5552 		NBUMPSIDE(0, ns_ignored);
5553 		break;
5554 	case 1 :
5555 		NBUMPSIDE(0, ns_translated);
5556 		break;
5557 	}
5558 	return rval;
5559 }
5560 
5561 
5562 /* ------------------------------------------------------------------------ */
5563 /* Function:    ipf_nat_in                                                  */
5564 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
5565 /*                     1 == packet was successfully translated.             */
5566 /* Parameters:  fin(I)    - pointer to packet information                   */
5567 /*              nat(I)    - pointer to NAT structure                        */
5568 /*              natadd(I) - flag indicating if it is safe to add frag cache */
5569 /*              nflags(I) - NAT flags set for this packet                   */
5570 /* Locks Held:  ipf_nat(READ)                                               */
5571 /*                                                                          */
5572 /* Translate a packet coming "in" on an interface.                          */
5573 /* ------------------------------------------------------------------------ */
5574 int
ipf_nat_in(fin,nat,natadd,nflags)5575 ipf_nat_in(fin, nat, natadd, nflags)
5576 	fr_info_t *fin;
5577 	nat_t *nat;
5578 	int natadd;
5579 	u_32_t nflags;
5580 {
5581 	ipf_main_softc_t *softc = fin->fin_main_soft;
5582 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5583 	u_32_t sumd, ipsumd, sum1, sum2;
5584 	icmphdr_t *icmp;
5585 	tcphdr_t *tcp;
5586 	ipnat_t *np;
5587 	int skip;
5588 	int i;
5589 
5590 	tcp = NULL;
5591 	np = nat->nat_ptr;
5592 	fin->fin_fr = nat->nat_fr;
5593 
5594 	if (np != NULL) {
5595 		if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
5596 			(void) ipf_frag_natnew(softc, fin, 0, nat);
5597 
5598 	/* ------------------------------------------------------------- */
5599 	/* A few quick notes:                                            */
5600 	/*      Following are test conditions prior to calling the       */
5601 	/*      ipf_proxy_check routine.                                 */
5602 	/*                                                               */
5603 	/*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
5604 	/*      with a map rule, we attempt to match the packet's        */
5605 	/*      source port against in_dport, otherwise we'd compare the */
5606 	/*      packet's destination.                                    */
5607 	/* ------------------------------------------------------------- */
5608 		if (np->in_apr != NULL) {
5609 			i = ipf_proxy_check(fin, nat);
5610 			if (i == -1) {
5611 				NBUMPSIDED(0, ns_ipf_proxy_fail);
5612 				return -1;
5613 			}
5614 		}
5615 	}
5616 
5617 	ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
5618 
5619 	ipsumd = nat->nat_ipsumd;
5620 	/*
5621 	 * Fix up checksums, not by recalculating them, but
5622 	 * simply computing adjustments.
5623 	 * Why only do this for some platforms on inbound packets ?
5624 	 * Because for those that it is done, IP processing is yet to happen
5625 	 * and so the IPv4 header checksum has not yet been evaluated.
5626 	 * Perhaps it should always be done for the benefit of things like
5627 	 * fast forwarding (so that it doesn't need to be recomputed) but with
5628 	 * header checksum offloading, perhaps it is a moot point.
5629 	 */
5630 
5631 	switch (nat->nat_dir)
5632 	{
5633 	case NAT_INBOUND :
5634 		if ((fin->fin_flx & FI_ICMPERR) == 0) {
5635 			fin->fin_ip->ip_src = nat->nat_nsrcip;
5636 			fin->fin_saddr = nat->nat_nsrcaddr;
5637 		} else {
5638 			sum1 = nat->nat_osrcaddr;
5639 			sum2 = nat->nat_nsrcaddr;
5640 			CALC_SUMD(sum1, sum2, sumd);
5641 			ipsumd -= sumd;
5642 		}
5643 		fin->fin_ip->ip_dst = nat->nat_ndstip;
5644 		fin->fin_daddr = nat->nat_ndstaddr;
5645 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5646      defined(__osf__) || defined(linux)
5647 		ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
5648 #endif
5649 		break;
5650 
5651 	case NAT_OUTBOUND :
5652 		if ((fin->fin_flx & FI_ICMPERR) == 0) {
5653 			fin->fin_ip->ip_src = nat->nat_odstip;
5654 			fin->fin_saddr = nat->nat_odstaddr;
5655 		} else {
5656 			sum1 = nat->nat_odstaddr;
5657 			sum2 = nat->nat_ndstaddr;
5658 			CALC_SUMD(sum1, sum2, sumd);
5659 			ipsumd -= sumd;
5660 		}
5661 		fin->fin_ip->ip_dst = nat->nat_osrcip;
5662 		fin->fin_daddr = nat->nat_osrcaddr;
5663 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5664      defined(__osf__) || defined(linux)
5665 		ipf_fix_incksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
5666 #endif
5667 		break;
5668 
5669 	case NAT_DIVERTIN :
5670 	    {
5671 		udphdr_t *uh;
5672 		ip_t *ip;
5673 		mb_t *m;
5674 
5675 		m = M_DUP(np->in_divmp);
5676 		if (m == NULL) {
5677 			NBUMPSIDED(0, ns_divert_dup);
5678 			return -1;
5679 		}
5680 
5681 		ip = MTOD(m, ip_t *);
5682 		ip->ip_id = htons(ipf_nextipid(fin));
5683 		sum1 = ntohs(ip->ip_len);
5684 		ip->ip_len = ntohs(ip->ip_len);
5685 		ip->ip_len += fin->fin_plen;
5686 		ip->ip_len = htons(ip->ip_len);
5687 
5688 		uh = (udphdr_t *)(ip + 1);
5689 		uh->uh_ulen += fin->fin_plen;
5690 		uh->uh_ulen = htons(uh->uh_ulen);
5691 
5692 		sum2 = ntohs(ip->ip_id) + ntohs(ip->ip_len);
5693 		sum2 += ntohs(ip->ip_off) & IP_DF;
5694 		CALC_SUMD(sum1, sum2, sumd);
5695 
5696 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
5697      defined(__osf__) || defined(linux)
5698 		ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
5699 #endif
5700 		PREP_MB_T(fin, m);
5701 
5702 		fin->fin_ip = ip;
5703 		fin->fin_plen += sizeof(ip_t) + 8;	/* UDP + new IPv4 hdr */
5704 		fin->fin_dlen += sizeof(ip_t) + 8;	/* UDP + old IPv4 hdr */
5705 
5706 		nflags &= ~IPN_TCPUDPICMP;
5707 
5708 		break;
5709 	    }
5710 
5711 	case NAT_DIVERTOUT :
5712 	    {
5713 		mb_t *m;
5714 
5715 		skip = ipf_nat_decap(fin, nat);
5716 		if (skip <= 0) {
5717 			NBUMPSIDED(0, ns_decap_fail);
5718 			return -1;
5719 		}
5720 
5721 		m = fin->fin_m;
5722 
5723 #if defined(MENTAT) && defined(_KERNEL)
5724 		m->b_rptr += skip;
5725 #else
5726 		m->m_data += skip;
5727 		m->m_len -= skip;
5728 
5729 # ifdef M_PKTHDR
5730 		if (m->m_flags & M_PKTHDR)
5731 			m->m_pkthdr.len -= skip;
5732 # endif
5733 #endif
5734 
5735 		ipf_nat_update(fin, nat);
5736 		nflags &= ~IPN_TCPUDPICMP;
5737 		fin->fin_flx |= FI_NATED;
5738 		if (np != NULL && np->in_tag.ipt_num[0] != 0)
5739 			fin->fin_nattag = &np->in_tag;
5740 		return 1;
5741 		/* NOTREACHED */
5742 	    }
5743 	}
5744 	if (nflags & IPN_TCPUDP)
5745 		tcp = fin->fin_dp;
5746 
5747 	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
5748 		u_short *csump;
5749 
5750 		if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) {
5751 			switch (nat->nat_dir)
5752 			{
5753 			case NAT_INBOUND :
5754 				tcp->th_sport = nat->nat_nsport;
5755 				fin->fin_data[0] = ntohs(nat->nat_nsport);
5756 				tcp->th_dport = nat->nat_ndport;
5757 				fin->fin_data[1] = ntohs(nat->nat_ndport);
5758 				break;
5759 
5760 			case NAT_OUTBOUND :
5761 				tcp->th_sport = nat->nat_odport;
5762 				fin->fin_data[0] = ntohs(nat->nat_odport);
5763 				tcp->th_dport = nat->nat_osport;
5764 				fin->fin_data[1] = ntohs(nat->nat_osport);
5765 				break;
5766 			}
5767 		}
5768 
5769 
5770 		if ((nat->nat_odport != 0) && (nflags & IPN_ICMPQUERY)) {
5771 			icmp = fin->fin_dp;
5772 
5773 			icmp->icmp_id = nat->nat_nicmpid;
5774 		}
5775 
5776 		csump = ipf_nat_proto(fin, nat, nflags);
5777 
5778 		/*
5779 		 * The above comments do not hold for layer 4 (or higher)
5780 		 * checksums...
5781 		 */
5782 		if (csump != NULL) {
5783 			if (nat->nat_dir == NAT_OUTBOUND)
5784 				ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0);
5785 			else
5786 				ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0);
5787 		}
5788 	}
5789 
5790 	fin->fin_flx |= FI_NATED;
5791 	if (np != NULL && np->in_tag.ipt_num[0] != 0)
5792 		fin->fin_nattag = &np->in_tag;
5793 	return 1;
5794 }
5795 
5796 
5797 /* ------------------------------------------------------------------------ */
5798 /* Function:    ipf_nat_proto                                               */
5799 /* Returns:     u_short* - pointer to transport header checksum to update,  */
5800 /*                         NULL if the transport protocol is not recognised */
5801 /*                         as needing a checksum update.                    */
5802 /* Parameters:  fin(I)    - pointer to packet information                   */
5803 /*              nat(I)    - pointer to NAT structure                        */
5804 /*              nflags(I) - NAT flags set for this packet                   */
5805 /*                                                                          */
5806 /* Return the pointer to the checksum field for each protocol so understood.*/
5807 /* If support for making other changes to a protocol header is required,    */
5808 /* that is not strictly 'address' translation, such as clamping the MSS in  */
5809 /* TCP down to a specific value, then do it from here.                      */
5810 /* ------------------------------------------------------------------------ */
5811 u_short *
ipf_nat_proto(fin,nat,nflags)5812 ipf_nat_proto(fin, nat, nflags)
5813 	fr_info_t *fin;
5814 	nat_t *nat;
5815 	u_int nflags;
5816 {
5817 	icmphdr_t *icmp;
5818 	u_short *csump;
5819 	tcphdr_t *tcp;
5820 	udphdr_t *udp;
5821 
5822 	csump = NULL;
5823 	if (fin->fin_out == 0) {
5824 		fin->fin_rev = (nat->nat_dir & NAT_OUTBOUND);
5825 	} else {
5826 		fin->fin_rev = ((nat->nat_dir & NAT_OUTBOUND) == 0);
5827 	}
5828 
5829 	switch (fin->fin_p)
5830 	{
5831 	case IPPROTO_TCP :
5832 		tcp = fin->fin_dp;
5833 
5834 		if ((nflags & IPN_TCP) != 0)
5835 			csump = &tcp->th_sum;
5836 
5837 		/*
5838 		 * Do a MSS CLAMPING on a SYN packet,
5839 		 * only deal IPv4 for now.
5840 		 */
5841 		if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0)
5842 			ipf_nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump);
5843 
5844 		break;
5845 
5846 	case IPPROTO_UDP :
5847 		udp = fin->fin_dp;
5848 
5849 		if ((nflags & IPN_UDP) != 0) {
5850 			if (udp->uh_sum != 0)
5851 				csump = &udp->uh_sum;
5852 		}
5853 		break;
5854 
5855 	case IPPROTO_ICMP :
5856 		icmp = fin->fin_dp;
5857 
5858 		if ((nflags & IPN_ICMPQUERY) != 0) {
5859 			if (icmp->icmp_cksum != 0)
5860 				csump = &icmp->icmp_cksum;
5861 		}
5862 		break;
5863 
5864 #ifdef USE_INET6
5865 	case IPPROTO_ICMPV6 :
5866 	    {
5867 		struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)fin->fin_dp;
5868 
5869 		icmp6 = fin->fin_dp;
5870 
5871 		if ((nflags & IPN_ICMPQUERY) != 0) {
5872 			if (icmp6->icmp6_cksum != 0)
5873 				csump = &icmp6->icmp6_cksum;
5874 		}
5875 		break;
5876 	    }
5877 #endif
5878 	}
5879 	return csump;
5880 }
5881 
5882 
5883 /* ------------------------------------------------------------------------ */
5884 /* Function:    ipf_nat_expire                                              */
5885 /* Returns:     Nil                                                         */
5886 /* Parameters:  softc(I) - pointer to soft context main structure           */
5887 /*                                                                          */
5888 /* Check all of the timeout queues for entries at the top which need to be  */
5889 /* expired.                                                                 */
5890 /* ------------------------------------------------------------------------ */
5891 void
ipf_nat_expire(softc)5892 ipf_nat_expire(softc)
5893 	ipf_main_softc_t *softc;
5894 {
5895 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5896 	ipftq_t *ifq, *ifqnext;
5897 	ipftqent_t *tqe, *tqn;
5898 	int i;
5899 	SPL_INT(s);
5900 
5901 	SPL_NET(s);
5902 	WRITE_ENTER(&softc->ipf_nat);
5903 	for (ifq = softn->ipf_nat_tcptq, i = 0; ifq != NULL;
5904 	     ifq = ifq->ifq_next) {
5905 		for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
5906 			if (tqe->tqe_die > softc->ipf_ticks)
5907 				break;
5908 			tqn = tqe->tqe_next;
5909 			ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
5910 		}
5911 	}
5912 
5913 	for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifq->ifq_next) {
5914 		for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
5915 			if (tqe->tqe_die > softc->ipf_ticks)
5916 				break;
5917 			tqn = tqe->tqe_next;
5918 			ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
5919 		}
5920 	}
5921 
5922 	for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) {
5923 		ifqnext = ifq->ifq_next;
5924 
5925 		if (((ifq->ifq_flags & IFQF_DELETE) != 0) &&
5926 		    (ifq->ifq_ref == 0)) {
5927 			ipf_freetimeoutqueue(softc, ifq);
5928 		}
5929 	}
5930 
5931 	if (softn->ipf_nat_doflush != 0) {
5932 		ipf_nat_extraflush(softc, softn, 2);
5933 		softn->ipf_nat_doflush = 0;
5934 	}
5935 
5936 	RWLOCK_EXIT(&softc->ipf_nat);
5937 	SPL_X(s);
5938 }
5939 
5940 
5941 /* ------------------------------------------------------------------------ */
5942 /* Function:    ipf_nat_sync                                                */
5943 /* Returns:     Nil                                                         */
5944 /* Parameters:  softc(I) - pointer to soft context main structure           */
5945 /*              ifp(I) - pointer to network interface                       */
5946 /*                                                                          */
5947 /* Walk through all of the currently active NAT sessions, looking for those */
5948 /* which need to have their translated address updated.                     */
5949 /* ------------------------------------------------------------------------ */
5950 void
ipf_nat_sync(softc,ifp)5951 ipf_nat_sync(softc, ifp)
5952 	ipf_main_softc_t *softc;
5953 	void *ifp;
5954 {
5955 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5956 	u_32_t sum1, sum2, sumd;
5957 	i6addr_t in;
5958 	ipnat_t *n;
5959 	nat_t *nat;
5960 	void *ifp2;
5961 	int idx;
5962 	SPL_INT(s);
5963 
5964 	if (softc->ipf_running <= 0)
5965 		return;
5966 
5967 	/*
5968 	 * Change IP addresses for NAT sessions for any protocol except TCP
5969 	 * since it will break the TCP connection anyway.  The only rules
5970 	 * which will get changed are those which are "map ... -> 0/32",
5971 	 * where the rule specifies the address is taken from the interface.
5972 	 */
5973 	SPL_NET(s);
5974 	WRITE_ENTER(&softc->ipf_nat);
5975 
5976 	if (softc->ipf_running <= 0) {
5977 		RWLOCK_EXIT(&softc->ipf_nat);
5978 		return;
5979 	}
5980 
5981 	for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) {
5982 		if ((nat->nat_flags & IPN_TCP) != 0)
5983 			continue;
5984 
5985 		n = nat->nat_ptr;
5986 		if (n != NULL) {
5987 			if (n->in_v[1] == 4) {
5988 				if (n->in_redir & NAT_MAP) {
5989 					if ((n->in_nsrcaddr != 0) ||
5990 					    (n->in_nsrcmsk != 0xffffffff))
5991 						continue;
5992 				} else if (n->in_redir & NAT_REDIRECT) {
5993 					if ((n->in_ndstaddr != 0) ||
5994 					    (n->in_ndstmsk != 0xffffffff))
5995 						continue;
5996 				}
5997 			}
5998 #ifdef USE_INET6
5999 			if (n->in_v[1] == 4) {
6000 				if (n->in_redir & NAT_MAP) {
6001 					if (!IP6_ISZERO(&n->in_nsrcaddr) ||
6002 					    !IP6_ISONES(&n->in_nsrcmsk))
6003 						continue;
6004 				} else if (n->in_redir & NAT_REDIRECT) {
6005 					if (!IP6_ISZERO(&n->in_ndstaddr) ||
6006 					    !IP6_ISONES(&n->in_ndstmsk))
6007 						continue;
6008 				}
6009 			}
6010 #endif
6011 		}
6012 
6013 		if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) ||
6014 		     (ifp == nat->nat_ifps[1]))) {
6015 			nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0],
6016 						  nat->nat_v[0]);
6017 			if ((nat->nat_ifps[0] != NULL) &&
6018 			    (nat->nat_ifps[0] != (void *)-1)) {
6019 				nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
6020 			}
6021 			if (nat->nat_ifnames[1][0] != '\0') {
6022 				nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1],
6023 							  nat->nat_v[1]);
6024 			} else {
6025 				nat->nat_ifps[1] = nat->nat_ifps[0];
6026 			}
6027 			if ((nat->nat_ifps[1] != NULL) &&
6028 			    (nat->nat_ifps[1] != (void *)-1)) {
6029 				nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
6030 			}
6031 			ifp2 = nat->nat_ifps[0];
6032 			if (ifp2 == NULL)
6033 				continue;
6034 
6035 			/*
6036 			 * Change the map-to address to be the same as the
6037 			 * new one.
6038 			 */
6039 			sum1 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
6040 			if (ipf_ifpaddr(softc, nat->nat_v[0], FRI_NORMAL, ifp2,
6041 				       &in, NULL) != -1) {
6042 				if (nat->nat_v[0] == 4)
6043 					nat->nat_nsrcip = in.in4;
6044 			}
6045 			sum2 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
6046 
6047 			if (sum1 == sum2)
6048 				continue;
6049 			/*
6050 			 * Readjust the checksum adjustment to take into
6051 			 * account the new IP#.
6052 			 */
6053 			CALC_SUMD(sum1, sum2, sumd);
6054 			/* XXX - dont change for TCP when solaris does
6055 			 * hardware checksumming.
6056 			 */
6057 			sumd += nat->nat_sumd[0];
6058 			nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
6059 			nat->nat_sumd[1] = nat->nat_sumd[0];
6060 		}
6061 	}
6062 
6063 	for (n = softn->ipf_nat_list; (n != NULL); n = n->in_next) {
6064 		char *base = n->in_names;
6065 
6066 		if ((ifp == NULL) || (n->in_ifps[0] == ifp))
6067 			n->in_ifps[0] = ipf_resolvenic(softc,
6068 						       base + n->in_ifnames[0],
6069 						       n->in_v[0]);
6070 		if ((ifp == NULL) || (n->in_ifps[1] == ifp))
6071 			n->in_ifps[1] = ipf_resolvenic(softc,
6072 						       base + n->in_ifnames[1],
6073 						       n->in_v[1]);
6074 
6075 		if (n->in_redir & NAT_REDIRECT)
6076 			idx = 1;
6077 		else
6078 			idx = 0;
6079 
6080 		if (((ifp == NULL) || (n->in_ifps[idx] == ifp)) &&
6081 		    (n->in_ifps[idx] != NULL &&
6082 		     n->in_ifps[idx] != (void *)-1)) {
6083 
6084 			ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc,
6085 					     0, n->in_ifps[idx]);
6086 			ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst,
6087 					     0, n->in_ifps[idx]);
6088 			ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc,
6089 					     0, n->in_ifps[idx]);
6090 			ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst,
6091 					     0, n->in_ifps[idx]);
6092 		}
6093 	}
6094 	RWLOCK_EXIT(&softc->ipf_nat);
6095 	SPL_X(s);
6096 }
6097 
6098 
6099 /* ------------------------------------------------------------------------ */
6100 /* Function:    ipf_nat_icmpquerytype                                       */
6101 /* Returns:     int - 1 == success, 0 == failure                            */
6102 /* Parameters:  icmptype(I) - ICMP type number                              */
6103 /*                                                                          */
6104 /* Tests to see if the ICMP type number passed is a query/response type or  */
6105 /* not.                                                                     */
6106 /* ------------------------------------------------------------------------ */
6107 static int
ipf_nat_icmpquerytype(icmptype)6108 ipf_nat_icmpquerytype(icmptype)
6109 	int icmptype;
6110 {
6111 
6112 	/*
6113 	 * For the ICMP query NAT code, it is essential that both the query
6114 	 * and the reply match on the NAT rule. Because the NAT structure
6115 	 * does not keep track of the icmptype, and a single NAT structure
6116 	 * is used for all icmp types with the same src, dest and id, we
6117 	 * simply define the replies as queries as well. The funny thing is,
6118 	 * altough it seems silly to call a reply a query, this is exactly
6119 	 * as it is defined in the IPv4 specification
6120 	 */
6121 	switch (icmptype)
6122 	{
6123 	case ICMP_ECHOREPLY:
6124 	case ICMP_ECHO:
6125 	/* route advertisement/solicitation is currently unsupported: */
6126 	/* it would require rewriting the ICMP data section          */
6127 	case ICMP_TSTAMP:
6128 	case ICMP_TSTAMPREPLY:
6129 	case ICMP_IREQ:
6130 	case ICMP_IREQREPLY:
6131 	case ICMP_MASKREQ:
6132 	case ICMP_MASKREPLY:
6133 		return 1;
6134 	default:
6135 		return 0;
6136 	}
6137 }
6138 
6139 
6140 /* ------------------------------------------------------------------------ */
6141 /* Function:    nat_log                                                     */
6142 /* Returns:     Nil                                                         */
6143 /* Parameters:  softc(I) - pointer to soft context main structure           */
6144 /*              softn(I) - pointer to NAT context structure                 */
6145 /*              nat(I)    - pointer to NAT structure                        */
6146 /*              action(I) - action related to NAT structure being performed */
6147 /*                                                                          */
6148 /* Creates a NAT log entry.                                                 */
6149 /* ------------------------------------------------------------------------ */
6150 void
ipf_nat_log(softc,softn,nat,action)6151 ipf_nat_log(softc, softn, nat, action)
6152 	ipf_main_softc_t *softc;
6153 	ipf_nat_softc_t *softn;
6154 	struct nat *nat;
6155 	u_int action;
6156 {
6157 #ifdef	IPFILTER_LOG
6158 # ifndef LARGE_NAT
6159 	struct ipnat *np;
6160 	int rulen;
6161 # endif
6162 	struct natlog natl;
6163 	void *items[1];
6164 	size_t sizes[1];
6165 	int types[1];
6166 
6167 	bcopy((char *)&nat->nat_osrc6, (char *)&natl.nl_osrcip,
6168 	      sizeof(natl.nl_osrcip));
6169 	bcopy((char *)&nat->nat_nsrc6, (char *)&natl.nl_nsrcip,
6170 	      sizeof(natl.nl_nsrcip));
6171 	bcopy((char *)&nat->nat_odst6, (char *)&natl.nl_odstip,
6172 	      sizeof(natl.nl_odstip));
6173 	bcopy((char *)&nat->nat_ndst6, (char *)&natl.nl_ndstip,
6174 	      sizeof(natl.nl_ndstip));
6175 
6176 	natl.nl_bytes[0] = nat->nat_bytes[0];
6177 	natl.nl_bytes[1] = nat->nat_bytes[1];
6178 	natl.nl_pkts[0] = nat->nat_pkts[0];
6179 	natl.nl_pkts[1] = nat->nat_pkts[1];
6180 	natl.nl_odstport = nat->nat_odport;
6181 	natl.nl_osrcport = nat->nat_osport;
6182 	natl.nl_nsrcport = nat->nat_nsport;
6183 	natl.nl_ndstport = nat->nat_ndport;
6184 	natl.nl_p[0] = nat->nat_pr[0];
6185 	natl.nl_p[1] = nat->nat_pr[1];
6186 	natl.nl_v[0] = nat->nat_v[0];
6187 	natl.nl_v[1] = nat->nat_v[1];
6188 	natl.nl_type = nat->nat_redir;
6189 	natl.nl_action = action;
6190 	natl.nl_rule = -1;
6191 
6192 	bcopy(nat->nat_ifnames[0], natl.nl_ifnames[0],
6193 	      sizeof(nat->nat_ifnames[0]));
6194 	bcopy(nat->nat_ifnames[1], natl.nl_ifnames[1],
6195 	      sizeof(nat->nat_ifnames[1]));
6196 
6197 # ifndef LARGE_NAT
6198 	if (nat->nat_ptr != NULL) {
6199 		for (rulen = 0, np = softn->ipf_nat_list; np != NULL;
6200 		     np = np->in_next, rulen++)
6201 			if (np == nat->nat_ptr) {
6202 				natl.nl_rule = rulen;
6203 				break;
6204 			}
6205 	}
6206 # endif
6207 	items[0] = &natl;
6208 	sizes[0] = sizeof(natl);
6209 	types[0] = 0;
6210 
6211 	(void) ipf_log_items(softc, IPL_LOGNAT, NULL, items, sizes, types, 1);
6212 #endif
6213 }
6214 
6215 
6216 #if defined(__OpenBSD__)
6217 /* ------------------------------------------------------------------------ */
6218 /* Function:    ipf_nat_ifdetach                                            */
6219 /* Returns:     Nil                                                         */
6220 /* Parameters:  ifp(I) - pointer to network interface                       */
6221 /*                                                                          */
6222 /* Compatibility interface for OpenBSD to trigger the correct updating of   */
6223 /* interface references within IPFilter.                                    */
6224 /* ------------------------------------------------------------------------ */
6225 void
ipf_nat_ifdetach(ifp)6226 ipf_nat_ifdetach(ifp)
6227 	void *ifp;
6228 {
6229 	ipf_main_softc_t *softc;
6230 
6231 	softc = ipf_get_softc(0);
6232 
6233 	ipf_sync(ifp);
6234 	return;
6235 }
6236 #endif
6237 
6238 
6239 /* ------------------------------------------------------------------------ */
6240 /* Function:    ipf_nat_rule_deref                                          */
6241 /* Returns:     Nil                                                         */
6242 /* Parameters:  softc(I) - pointer to soft context main structure           */
6243 /*              inp(I)   - pointer to pointer to NAT rule                   */
6244 /* Write Locks: ipf_nat                                                     */
6245 /*                                                                          */
6246 /* Dropping the refernce count for a rule means that whatever held the      */
6247 /* pointer to this rule (*inp) is no longer interested in it and when the   */
6248 /* reference count drops to zero, any resources allocated for the rule can  */
6249 /* be released and the rule itself free'd.                                  */
6250 /* ------------------------------------------------------------------------ */
6251 void
ipf_nat_rule_deref(softc,inp)6252 ipf_nat_rule_deref(softc, inp)
6253 	ipf_main_softc_t *softc;
6254 	ipnat_t **inp;
6255 {
6256 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
6257 	ipnat_t *n;
6258 
6259 	n = *inp;
6260 	*inp = NULL;
6261 	n->in_use--;
6262 	if (n->in_use > 0)
6263 		return;
6264 
6265 	if (n->in_apr != NULL)
6266 		ipf_proxy_deref(n->in_apr);
6267 
6268 	ipf_nat_rule_fini(softc, n);
6269 
6270 	if (n->in_redir & NAT_REDIRECT) {
6271 		if ((n->in_flags & IPN_PROXYRULE) == 0) {
6272 			ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_rdr);
6273 		}
6274 	}
6275 	if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
6276 		if ((n->in_flags & IPN_PROXYRULE) == 0) {
6277 			ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_map);
6278 		}
6279 	}
6280 
6281 	if (n->in_tqehead[0] != NULL) {
6282 		if (ipf_deletetimeoutqueue(n->in_tqehead[0]) == 0) {
6283 			ipf_freetimeoutqueue(softc, n->in_tqehead[1]);
6284 		}
6285 	}
6286 
6287 	if (n->in_tqehead[1] != NULL) {
6288 		if (ipf_deletetimeoutqueue(n->in_tqehead[1]) == 0) {
6289 			ipf_freetimeoutqueue(softc, n->in_tqehead[1]);
6290 		}
6291 	}
6292 
6293 	if ((n->in_flags & IPN_PROXYRULE) == 0) {
6294 		ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules);
6295 	}
6296 
6297 	MUTEX_DESTROY(&n->in_lock);
6298 
6299 	KFREES(n, n->in_size);
6300 
6301 #if SOLARIS && !defined(INSTANCES)
6302 	if (softn->ipf_nat_stats.ns_rules == 0)
6303 		pfil_delayed_copy = 1;
6304 #endif
6305 }
6306 
6307 
6308 /* ------------------------------------------------------------------------ */
6309 /* Function:    ipf_nat_deref                                               */
6310 /* Returns:     Nil                                                         */
6311 /* Parameters:  softc(I) - pointer to soft context main structure           */
6312 /*              natp(I)  - pointer to pointer to NAT table entry            */
6313 /*                                                                          */
6314 /* Decrement the reference counter for this NAT table entry and free it if  */
6315 /* there are no more things using it.                                       */
6316 /*                                                                          */
6317 /* IF nat_ref == 1 when this function is called, then we have an orphan nat */
6318 /* structure *because* it only gets called on paths _after_ nat_ref has been*/
6319 /* incremented.  If nat_ref == 1 then we shouldn't decrement it here        */
6320 /* because nat_delete() will do that and send nat_ref to -1.                */
6321 /*                                                                          */
6322 /* Holding the lock on nat_lock is required to serialise nat_delete() being */
6323 /* called from a NAT flush ioctl with a deref happening because of a packet.*/
6324 /* ------------------------------------------------------------------------ */
6325 void
ipf_nat_deref(softc,natp)6326 ipf_nat_deref(softc, natp)
6327 	ipf_main_softc_t *softc;
6328 	nat_t **natp;
6329 {
6330 	nat_t *nat;
6331 
6332 	nat = *natp;
6333 	*natp = NULL;
6334 
6335 	MUTEX_ENTER(&nat->nat_lock);
6336 	if (nat->nat_ref > 1) {
6337 		nat->nat_ref--;
6338 		ASSERT(nat->nat_ref >= 0);
6339 		MUTEX_EXIT(&nat->nat_lock);
6340 		return;
6341 	}
6342 	MUTEX_EXIT(&nat->nat_lock);
6343 
6344 	WRITE_ENTER(&softc->ipf_nat);
6345 	ipf_nat_delete(softc, nat, NL_EXPIRE);
6346 	RWLOCK_EXIT(&softc->ipf_nat);
6347 }
6348 
6349 
6350 /* ------------------------------------------------------------------------ */
6351 /* Function:    ipf_nat_clone                                               */
6352 /* Returns:     ipstate_t* - NULL == cloning failed,                        */
6353 /*                           else pointer to new state structure            */
6354 /* Parameters:  fin(I) - pointer to packet information                      */
6355 /*              is(I)  - pointer to master state structure                  */
6356 /* Write Lock:  ipf_nat                                                     */
6357 /*                                                                          */
6358 /* Create a "duplcate" state table entry from the master.                   */
6359 /* ------------------------------------------------------------------------ */
6360 nat_t *
ipf_nat_clone(fin,nat)6361 ipf_nat_clone(fin, nat)
6362 	fr_info_t *fin;
6363 	nat_t *nat;
6364 {
6365 	ipf_main_softc_t *softc = fin->fin_main_soft;
6366 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
6367 	frentry_t *fr;
6368 	nat_t *clone;
6369 	ipnat_t *np;
6370 
6371 	KMALLOC(clone, nat_t *);
6372 	if (clone == NULL) {
6373 		NBUMPSIDED(fin->fin_out, ns_clone_nomem);
6374 		return NULL;
6375 	}
6376 	bcopy((char *)nat, (char *)clone, sizeof(*clone));
6377 
6378 	MUTEX_NUKE(&clone->nat_lock);
6379 
6380 	clone->nat_rev = fin->fin_rev;
6381 	clone->nat_aps = NULL;
6382 	/*
6383 	 * Initialize all these so that ipf_nat_delete() doesn't cause a crash.
6384 	 */
6385 	clone->nat_tqe.tqe_pnext = NULL;
6386 	clone->nat_tqe.tqe_next = NULL;
6387 	clone->nat_tqe.tqe_ifq = NULL;
6388 	clone->nat_tqe.tqe_parent = clone;
6389 
6390 	clone->nat_flags &= ~SI_CLONE;
6391 	clone->nat_flags |= SI_CLONED;
6392 
6393 	if (clone->nat_hm)
6394 		clone->nat_hm->hm_ref++;
6395 
6396 	if (ipf_nat_insert(softc, softn, clone) == -1) {
6397 		KFREE(clone);
6398 		NBUMPSIDED(fin->fin_out, ns_insert_fail);
6399 		return NULL;
6400 	}
6401 
6402 	np = clone->nat_ptr;
6403 	if (np != NULL) {
6404 		if (softn->ipf_nat_logging)
6405 			ipf_nat_log(softc, softn, clone, NL_CLONE);
6406 		np->in_use++;
6407 	}
6408 	fr = clone->nat_fr;
6409 	if (fr != NULL) {
6410 		MUTEX_ENTER(&fr->fr_lock);
6411 		fr->fr_ref++;
6412 		MUTEX_EXIT(&fr->fr_lock);
6413 	}
6414 
6415 
6416 	/*
6417 	 * Because the clone is created outside the normal loop of things and
6418 	 * TCP has special needs in terms of state, initialise the timeout
6419 	 * state of the new NAT from here.
6420 	 */
6421 	if (clone->nat_pr[0] == IPPROTO_TCP) {
6422 		(void) ipf_tcp_age(&clone->nat_tqe, fin, softn->ipf_nat_tcptq,
6423 				   clone->nat_flags, 2);
6424 	}
6425 	clone->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, clone);
6426 	if (softn->ipf_nat_logging)
6427 		ipf_nat_log(softc, softn, clone, NL_CLONE);
6428 	return clone;
6429 }
6430 
6431 
6432 /* ------------------------------------------------------------------------ */
6433 /* Function:   ipf_nat_wildok                                               */
6434 /* Returns:    int - 1 == packet's ports match wildcards                    */
6435 /*                   0 == packet's ports don't match wildcards              */
6436 /* Parameters: nat(I)   - NAT entry                                         */
6437 /*             sport(I) - source port                                       */
6438 /*             dport(I) - destination port                                  */
6439 /*             flags(I) - wildcard flags                                    */
6440 /*             dir(I)   - packet direction                                  */
6441 /*                                                                          */
6442 /* Use NAT entry and packet direction to determine which combination of     */
6443 /* wildcard flags should be used.                                           */
6444 /* ------------------------------------------------------------------------ */
6445 int
ipf_nat_wildok(nat,sport,dport,flags,dir)6446 ipf_nat_wildok(nat, sport, dport, flags, dir)
6447 	nat_t *nat;
6448 	int sport, dport, flags, dir;
6449 {
6450 	/*
6451 	 * When called by       dir is set to
6452 	 * nat_inlookup         NAT_INBOUND (0)
6453 	 * nat_outlookup        NAT_OUTBOUND (1)
6454 	 *
6455 	 * We simply combine the packet's direction in dir with the original
6456 	 * "intended" direction of that NAT entry in nat->nat_dir to decide
6457 	 * which combination of wildcard flags to allow.
6458 	 */
6459 	switch ((dir << 1) | (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND)))
6460 	{
6461 	case 3: /* outbound packet / outbound entry */
6462 		if (((nat->nat_osport == sport) ||
6463 		    (flags & SI_W_SPORT)) &&
6464 		    ((nat->nat_odport == dport) ||
6465 		    (flags & SI_W_DPORT)))
6466 			return 1;
6467 		break;
6468 	case 2: /* outbound packet / inbound entry */
6469 		if (((nat->nat_osport == dport) ||
6470 		    (flags & SI_W_SPORT)) &&
6471 		    ((nat->nat_odport == sport) ||
6472 		    (flags & SI_W_DPORT)))
6473 			return 1;
6474 		break;
6475 	case 1: /* inbound packet / outbound entry */
6476 		if (((nat->nat_osport == dport) ||
6477 		    (flags & SI_W_SPORT)) &&
6478 		    ((nat->nat_odport == sport) ||
6479 		    (flags & SI_W_DPORT)))
6480 			return 1;
6481 		break;
6482 	case 0: /* inbound packet / inbound entry */
6483 		if (((nat->nat_osport == sport) ||
6484 		    (flags & SI_W_SPORT)) &&
6485 		    ((nat->nat_odport == dport) ||
6486 		    (flags & SI_W_DPORT)))
6487 			return 1;
6488 		break;
6489 	default:
6490 		break;
6491 	}
6492 
6493 	return(0);
6494 }
6495 
6496 
6497 /* ------------------------------------------------------------------------ */
6498 /* Function:    nat_mssclamp                                                */
6499 /* Returns:     Nil                                                         */
6500 /* Parameters:  tcp(I)    - pointer to TCP header                           */
6501 /*              maxmss(I) - value to clamp the TCP MSS to                   */
6502 /*              fin(I)    - pointer to packet information                   */
6503 /*              csump(I)  - pointer to TCP checksum                         */
6504 /*                                                                          */
6505 /* Check for MSS option and clamp it if necessary.  If found and changed,   */
6506 /* then the TCP header checksum will be updated to reflect the change in    */
6507 /* the MSS.                                                                 */
6508 /* ------------------------------------------------------------------------ */
6509 static void
ipf_nat_mssclamp(tcp,maxmss,fin,csump)6510 ipf_nat_mssclamp(tcp, maxmss, fin, csump)
6511 	tcphdr_t *tcp;
6512 	u_32_t maxmss;
6513 	fr_info_t *fin;
6514 	u_short *csump;
6515 {
6516 	u_char *cp, *ep, opt;
6517 	int hlen, advance;
6518 	u_32_t mss, sumd;
6519 
6520 	hlen = TCP_OFF(tcp) << 2;
6521 	if (hlen > sizeof(*tcp)) {
6522 		cp = (u_char *)tcp + sizeof(*tcp);
6523 		ep = (u_char *)tcp + hlen;
6524 
6525 		while (cp < ep) {
6526 			opt = cp[0];
6527 			if (opt == TCPOPT_EOL)
6528 				break;
6529 			else if (opt == TCPOPT_NOP) {
6530 				cp++;
6531 				continue;
6532 			}
6533 
6534 			if (cp + 1 >= ep)
6535 				break;
6536 			advance = cp[1];
6537 			if ((cp + advance > ep) || (advance <= 0))
6538 				break;
6539 			switch (opt)
6540 			{
6541 			case TCPOPT_MAXSEG:
6542 				if (advance != 4)
6543 					break;
6544 				mss = cp[2] * 256 + cp[3];
6545 				if (mss > maxmss) {
6546 					cp[2] = maxmss / 256;
6547 					cp[3] = maxmss & 0xff;
6548 					CALC_SUMD(mss, maxmss, sumd);
6549 					ipf_fix_outcksum(0, csump, sumd, 0);
6550 				}
6551 				break;
6552 			default:
6553 				/* ignore unknown options */
6554 				break;
6555 			}
6556 
6557 			cp += advance;
6558 		}
6559 	}
6560 }
6561 
6562 
6563 /* ------------------------------------------------------------------------ */
6564 /* Function:    ipf_nat_setqueue                                            */
6565 /* Returns:     Nil                                                         */
6566 /* Parameters:  softc(I) - pointer to soft context main structure           */
6567 /*              softn(I) - pointer to NAT context structure                 */
6568 /*              nat(I)- pointer to NAT structure                            */
6569 /* Locks:       ipf_nat (read or write)                                     */
6570 /*                                                                          */
6571 /* Put the NAT entry on its default queue entry, using rev as a helped in   */
6572 /* determining which queue it should be placed on.                          */
6573 /* ------------------------------------------------------------------------ */
6574 void
ipf_nat_setqueue(softc,softn,nat)6575 ipf_nat_setqueue(softc, softn, nat)
6576 	ipf_main_softc_t *softc;
6577 	ipf_nat_softc_t *softn;
6578 	nat_t *nat;
6579 {
6580 	ipftq_t *oifq, *nifq;
6581 	int rev = nat->nat_rev;
6582 
6583 	if (nat->nat_ptr != NULL)
6584 		nifq = nat->nat_ptr->in_tqehead[rev];
6585 	else
6586 		nifq = NULL;
6587 
6588 	if (nifq == NULL) {
6589 		switch (nat->nat_pr[0])
6590 		{
6591 		case IPPROTO_UDP :
6592 			nifq = &softn->ipf_nat_udptq;
6593 			break;
6594 		case IPPROTO_ICMP :
6595 			nifq = &softn->ipf_nat_icmptq;
6596 			break;
6597 		case IPPROTO_TCP :
6598 			nifq = softn->ipf_nat_tcptq +
6599 			       nat->nat_tqe.tqe_state[rev];
6600 			break;
6601 		default :
6602 			nifq = &softn->ipf_nat_iptq;
6603 			break;
6604 		}
6605 	}
6606 
6607 	oifq = nat->nat_tqe.tqe_ifq;
6608 	/*
6609 	 * If it's currently on a timeout queue, move it from one queue to
6610 	 * another, else put it on the end of the newly determined queue.
6611 	 */
6612 	if (oifq != NULL)
6613 		ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, nifq);
6614 	else
6615 		ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, nifq, nat);
6616 	return;
6617 }
6618 
6619 
6620 /* ------------------------------------------------------------------------ */
6621 /* Function:    nat_getnext                                                 */
6622 /* Returns:     int - 0 == ok, else error                                   */
6623 /* Parameters:  softc(I) - pointer to soft context main structure           */
6624 /*              t(I)   - pointer to ipftoken structure                      */
6625 /*              itp(I) - pointer to ipfgeniter_t structure                  */
6626 /*                                                                          */
6627 /* Fetch the next nat/ipnat structure pointer from the linked list and      */
6628 /* copy it out to the storage space pointed to by itp_data.  The next item  */
6629 /* in the list to look at is put back in the ipftoken struture.             */
6630 /* ------------------------------------------------------------------------ */
6631 static int
ipf_nat_getnext(softc,t,itp,objp)6632 ipf_nat_getnext(softc, t, itp, objp)
6633 	ipf_main_softc_t *softc;
6634 	ipftoken_t *t;
6635 	ipfgeniter_t *itp;
6636 	ipfobj_t *objp;
6637 {
6638 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
6639 	hostmap_t *hm, *nexthm = NULL, zerohm;
6640 	ipnat_t *ipn, *nextipnat = NULL, zeroipn;
6641 	nat_t *nat, *nextnat = NULL, zeronat;
6642 	int error = 0;
6643 	void *nnext;
6644 
6645 	if (itp->igi_nitems != 1) {
6646 		IPFERROR(60075);
6647 		return ENOSPC;
6648 	}
6649 
6650 	READ_ENTER(&softc->ipf_nat);
6651 
6652 	switch (itp->igi_type)
6653 	{
6654 	case IPFGENITER_HOSTMAP :
6655 		hm = t->ipt_data;
6656 		if (hm == NULL) {
6657 			nexthm = softn->ipf_hm_maplist;
6658 		} else {
6659 			nexthm = hm->hm_next;
6660 		}
6661 		if (nexthm != NULL) {
6662 			ATOMIC_INC32(nexthm->hm_ref);
6663 			t->ipt_data = nexthm;
6664 		} else {
6665 			bzero(&zerohm, sizeof(zerohm));
6666 			nexthm = &zerohm;
6667 			t->ipt_data = NULL;
6668 		}
6669 		nnext = nexthm->hm_next;
6670 		break;
6671 
6672 	case IPFGENITER_IPNAT :
6673 		ipn = t->ipt_data;
6674 		if (ipn == NULL) {
6675 			nextipnat = softn->ipf_nat_list;
6676 		} else {
6677 			nextipnat = ipn->in_next;
6678 		}
6679 		if (nextipnat != NULL) {
6680 			ATOMIC_INC32(nextipnat->in_use);
6681 			t->ipt_data = nextipnat;
6682 		} else {
6683 			bzero(&zeroipn, sizeof(zeroipn));
6684 			nextipnat = &zeroipn;
6685 			t->ipt_data = NULL;
6686 		}
6687 		nnext = nextipnat->in_next;
6688 		break;
6689 
6690 	case IPFGENITER_NAT :
6691 		nat = t->ipt_data;
6692 		if (nat == NULL) {
6693 			nextnat = softn->ipf_nat_instances;
6694 		} else {
6695 			nextnat = nat->nat_next;
6696 		}
6697 		if (nextnat != NULL) {
6698 			MUTEX_ENTER(&nextnat->nat_lock);
6699 			nextnat->nat_ref++;
6700 			MUTEX_EXIT(&nextnat->nat_lock);
6701 			t->ipt_data = nextnat;
6702 		} else {
6703 			bzero(&zeronat, sizeof(zeronat));
6704 			nextnat = &zeronat;
6705 			t->ipt_data = NULL;
6706 		}
6707 		nnext = nextnat->nat_next;
6708 		break;
6709 
6710 	default :
6711 		RWLOCK_EXIT(&softc->ipf_nat);
6712 		IPFERROR(60055);
6713 		return EINVAL;
6714 	}
6715 
6716 	RWLOCK_EXIT(&softc->ipf_nat);
6717 
6718 	objp->ipfo_ptr = itp->igi_data;
6719 
6720 	switch (itp->igi_type)
6721 	{
6722 	case IPFGENITER_HOSTMAP :
6723 		error = COPYOUT(nexthm, objp->ipfo_ptr, sizeof(*nexthm));
6724 		if (error != 0) {
6725 			IPFERROR(60049);
6726 			error = EFAULT;
6727 		}
6728 		if (hm != NULL) {
6729 			WRITE_ENTER(&softc->ipf_nat);
6730 			ipf_nat_hostmapdel(softc, &hm);
6731 			RWLOCK_EXIT(&softc->ipf_nat);
6732 		}
6733 		break;
6734 
6735 	case IPFGENITER_IPNAT :
6736 		objp->ipfo_size = nextipnat->in_size;
6737 		objp->ipfo_type = IPFOBJ_IPNAT;
6738 		error = ipf_outobjk(softc, objp, nextipnat);
6739 		if (ipn != NULL) {
6740 			WRITE_ENTER(&softc->ipf_nat);
6741 			ipf_nat_rule_deref(softc, &ipn);
6742 			RWLOCK_EXIT(&softc->ipf_nat);
6743 		}
6744 		break;
6745 
6746 	case IPFGENITER_NAT :
6747 		objp->ipfo_size = sizeof(nat_t);
6748 		objp->ipfo_type = IPFOBJ_NAT;
6749 		error = ipf_outobjk(softc, objp, nextnat);
6750 		if (nat != NULL)
6751 			ipf_nat_deref(softc, &nat);
6752 
6753 		break;
6754 	}
6755 
6756 	if (nnext == NULL)
6757 		ipf_token_mark_complete(t);
6758 
6759 	return error;
6760 }
6761 
6762 
6763 /* ------------------------------------------------------------------------ */
6764 /* Function:    nat_extraflush                                              */
6765 /* Returns:     int - 0 == success, -1 == failure                           */
6766 /* Parameters:  softc(I) - pointer to soft context main structure           */
6767 /*              softn(I) - pointer to NAT context structure                 */
6768 /*              which(I) - how to flush the active NAT table                */
6769 /* Write Locks: ipf_nat                                                     */
6770 /*                                                                          */
6771 /* Flush nat tables.  Three actions currently defined:                      */
6772 /* which == 0 : flush all nat table entries                                 */
6773 /* which == 1 : flush TCP connections which have started to close but are   */
6774 /*	      stuck for some reason.                                        */
6775 /* which == 2 : flush TCP connections which have been idle for a long time, */
6776 /*	      starting at > 4 days idle and working back in successive half-*/
6777 /*	      days to at most 12 hours old.  If this fails to free enough   */
6778 /*            slots then work backwards in half hour slots to 30 minutes.   */
6779 /*            If that too fails, then work backwards in 30 second intervals */
6780 /*            for the last 30 minutes to at worst 30 seconds idle.          */
6781 /* ------------------------------------------------------------------------ */
6782 static int
ipf_nat_extraflush(softc,softn,which)6783 ipf_nat_extraflush(softc, softn, which)
6784 	ipf_main_softc_t *softc;
6785 	ipf_nat_softc_t *softn;
6786 	int which;
6787 {
6788 	nat_t *nat, **natp;
6789 	ipftqent_t *tqn;
6790 	ipftq_t *ifq;
6791 	int removed;
6792 	SPL_INT(s);
6793 
6794 	removed = 0;
6795 
6796 	SPL_NET(s);
6797 	switch (which)
6798 	{
6799 	case 0 :
6800 		softn->ipf_nat_stats.ns_flush_all++;
6801 		/*
6802 		 * Style 0 flush removes everything...
6803 		 */
6804 		for (natp = &softn->ipf_nat_instances;
6805 		     ((nat = *natp) != NULL); ) {
6806 			ipf_nat_delete(softc, nat, NL_FLUSH);
6807 			removed++;
6808 		}
6809 		break;
6810 
6811 	case 1 :
6812 		softn->ipf_nat_stats.ns_flush_closing++;
6813 		/*
6814 		 * Since we're only interested in things that are closing,
6815 		 * we can start with the appropriate timeout queue.
6816 		 */
6817 		for (ifq = softn->ipf_nat_tcptq + IPF_TCPS_CLOSE_WAIT;
6818 		     ifq != NULL; ifq = ifq->ifq_next) {
6819 
6820 			for (tqn = ifq->ifq_head; tqn != NULL; ) {
6821 				nat = tqn->tqe_parent;
6822 				tqn = tqn->tqe_next;
6823 				if (nat->nat_pr[0] != IPPROTO_TCP ||
6824 				    nat->nat_pr[1] != IPPROTO_TCP)
6825 					break;
6826 				ipf_nat_delete(softc, nat, NL_EXPIRE);
6827 				removed++;
6828 			}
6829 		}
6830 
6831 		/*
6832 		 * Also need to look through the user defined queues.
6833 		 */
6834 		for (ifq = softn->ipf_nat_utqe; ifq != NULL;
6835 		     ifq = ifq->ifq_next) {
6836 			for (tqn = ifq->ifq_head; tqn != NULL; ) {
6837 				nat = tqn->tqe_parent;
6838 				tqn = tqn->tqe_next;
6839 				if (nat->nat_pr[0] != IPPROTO_TCP ||
6840 				    nat->nat_pr[1] != IPPROTO_TCP)
6841 					continue;
6842 
6843 				if ((nat->nat_tcpstate[0] >
6844 				     IPF_TCPS_ESTABLISHED) &&
6845 				    (nat->nat_tcpstate[1] >
6846 				     IPF_TCPS_ESTABLISHED)) {
6847 					ipf_nat_delete(softc, nat, NL_EXPIRE);
6848 					removed++;
6849 				}
6850 			}
6851 		}
6852 		break;
6853 
6854 		/*
6855 		 * Args 5-11 correspond to flushing those particular states
6856 		 * for TCP connections.
6857 		 */
6858 	case IPF_TCPS_CLOSE_WAIT :
6859 	case IPF_TCPS_FIN_WAIT_1 :
6860 	case IPF_TCPS_CLOSING :
6861 	case IPF_TCPS_LAST_ACK :
6862 	case IPF_TCPS_FIN_WAIT_2 :
6863 	case IPF_TCPS_TIME_WAIT :
6864 	case IPF_TCPS_CLOSED :
6865 		softn->ipf_nat_stats.ns_flush_state++;
6866 		tqn = softn->ipf_nat_tcptq[which].ifq_head;
6867 		while (tqn != NULL) {
6868 			nat = tqn->tqe_parent;
6869 			tqn = tqn->tqe_next;
6870 			ipf_nat_delete(softc, nat, NL_FLUSH);
6871 			removed++;
6872 		}
6873 		break;
6874 
6875 	default :
6876 		if (which < 30)
6877 			break;
6878 
6879 		softn->ipf_nat_stats.ns_flush_timeout++;
6880 		/*
6881 		 * Take a large arbitrary number to mean the number of seconds
6882 		 * for which which consider to be the maximum value we'll allow
6883 		 * the expiration to be.
6884 		 */
6885 		which = IPF_TTLVAL(which);
6886 		for (natp = &softn->ipf_nat_instances;
6887 		     ((nat = *natp) != NULL); ) {
6888 			if (softc->ipf_ticks - nat->nat_touched > which) {
6889 				ipf_nat_delete(softc, nat, NL_FLUSH);
6890 				removed++;
6891 			} else
6892 				natp = &nat->nat_next;
6893 		}
6894 		break;
6895 	}
6896 
6897 	if (which != 2) {
6898 		SPL_X(s);
6899 		return removed;
6900 	}
6901 
6902 	softn->ipf_nat_stats.ns_flush_queue++;
6903 
6904 	/*
6905 	 * Asked to remove inactive entries because the table is full, try
6906 	 * again, 3 times, if first attempt failed with a different criteria
6907 	 * each time.  The order tried in must be in decreasing age.
6908 	 * Another alternative is to implement random drop and drop N entries
6909 	 * at random until N have been freed up.
6910 	 */
6911 	if (softc->ipf_ticks - softn->ipf_nat_last_force_flush >
6912 	    IPF_TTLVAL(5)) {
6913 		softn->ipf_nat_last_force_flush = softc->ipf_ticks;
6914 
6915 		removed = ipf_queueflush(softc, ipf_nat_flush_entry,
6916 					 softn->ipf_nat_tcptq,
6917 					 softn->ipf_nat_utqe,
6918 					 &softn->ipf_nat_stats.ns_active,
6919 					 softn->ipf_nat_table_sz,
6920 					 softn->ipf_nat_table_wm_low);
6921 	}
6922 
6923 	SPL_X(s);
6924 	return removed;
6925 }
6926 
6927 
6928 /* ------------------------------------------------------------------------ */
6929 /* Function:    ipf_nat_flush_entry                                         */
6930 /* Returns:     0 - always succeeds                                         */
6931 /* Parameters:  softc(I) - pointer to soft context main structure           */
6932 /*              entry(I) - pointer to NAT entry                             */
6933 /* Write Locks: ipf_nat                                                     */
6934 /*                                                                          */
6935 /* This function is a stepping stone between ipf_queueflush() and           */
6936 /* nat_dlete().  It is used so we can provide a uniform interface via the   */
6937 /* ipf_queueflush() function.  Since the nat_delete() function returns void */
6938 /* we translate that to mean it always succeeds in deleting something.      */
6939 /* ------------------------------------------------------------------------ */
6940 static int
ipf_nat_flush_entry(softc,entry)6941 ipf_nat_flush_entry(softc, entry)
6942 	ipf_main_softc_t *softc;
6943 	void *entry;
6944 {
6945 	ipf_nat_delete(softc, entry, NL_FLUSH);
6946 	return 0;
6947 }
6948 
6949 
6950 /* ------------------------------------------------------------------------ */
6951 /* Function:    ipf_nat_iterator                                            */
6952 /* Returns:     int - 0 == ok, else error                                   */
6953 /* Parameters:  softc(I) - pointer to soft context main structure           */
6954 /*              token(I) - pointer to ipftoken structure                    */
6955 /*              itp(I)   - pointer to ipfgeniter_t structure                */
6956 /*              obj(I)   - pointer to data description structure            */
6957 /*                                                                          */
6958 /* This function acts as a handler for the SIOCGENITER ioctls that use a    */
6959 /* generic structure to iterate through a list.  There are three different  */
6960 /* linked lists of NAT related information to go through: NAT rules, active */
6961 /* NAT mappings and the NAT fragment cache.                                 */
6962 /* ------------------------------------------------------------------------ */
6963 static int
ipf_nat_iterator(softc,token,itp,obj)6964 ipf_nat_iterator(softc, token, itp, obj)
6965 	ipf_main_softc_t *softc;
6966 	ipftoken_t *token;
6967 	ipfgeniter_t *itp;
6968 	ipfobj_t *obj;
6969 {
6970 	int error;
6971 
6972 	if (itp->igi_data == NULL) {
6973 		IPFERROR(60052);
6974 		return EFAULT;
6975 	}
6976 
6977 	switch (itp->igi_type)
6978 	{
6979 	case IPFGENITER_HOSTMAP :
6980 	case IPFGENITER_IPNAT :
6981 	case IPFGENITER_NAT :
6982 		error = ipf_nat_getnext(softc, token, itp, obj);
6983 		break;
6984 
6985 	case IPFGENITER_NATFRAG :
6986 		error = ipf_frag_nat_next(softc, token, itp);
6987 		break;
6988 	default :
6989 		IPFERROR(60053);
6990 		error = EINVAL;
6991 		break;
6992 	}
6993 
6994 	return error;
6995 }
6996 
6997 
6998 /* ------------------------------------------------------------------------ */
6999 /* Function:    ipf_nat_setpending                                          */
7000 /* Returns:     Nil                                                         */
7001 /* Parameters:  softc(I) - pointer to soft context main structure           */
7002 /*              nat(I)   - pointer to NAT structure                         */
7003 /* Locks:       ipf_nat (read or write)                                     */
7004 /*                                                                          */
7005 /* Put the NAT entry on to the pending queue - this queue has a very short  */
7006 /* lifetime where items are put that can't be deleted straight away because */
7007 /* of locking issues but we want to delete them ASAP, anyway.  In calling   */
7008 /* this function, it is assumed that the owner (if there is one, as shown   */
7009 /* by nat_me) is no longer interested in it.                                */
7010 /* ------------------------------------------------------------------------ */
7011 void
ipf_nat_setpending(softc,nat)7012 ipf_nat_setpending(softc, nat)
7013 	ipf_main_softc_t *softc;
7014 	nat_t *nat;
7015 {
7016 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7017 	ipftq_t *oifq;
7018 
7019 	oifq = nat->nat_tqe.tqe_ifq;
7020 	if (oifq != NULL)
7021 		ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq,
7022 			      &softn->ipf_nat_pending);
7023 	else
7024 		ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe,
7025 				&softn->ipf_nat_pending, nat);
7026 
7027 	if (nat->nat_me != NULL) {
7028 		*nat->nat_me = NULL;
7029 		nat->nat_me = NULL;
7030 		nat->nat_ref--;
7031 		ASSERT(nat->nat_ref >= 0);
7032 	}
7033 }
7034 
7035 
7036 /* ------------------------------------------------------------------------ */
7037 /* Function:    nat_newrewrite                                              */
7038 /* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
7039 /*                    allow rule to be moved if IPN_ROUNDR is set.          */
7040 /* Parameters:  fin(I) - pointer to packet information                      */
7041 /*              nat(I) - pointer to NAT entry                               */
7042 /*              ni(I)  - pointer to structure with misc. information needed */
7043 /*                       to create new NAT entry.                           */
7044 /* Write Lock:  ipf_nat                                                     */
7045 /*                                                                          */
7046 /* This function is responsible for setting up an active NAT session where  */
7047 /* we are changing both the source and destination parameters at the same   */
7048 /* time.  The loop in here works differently to elsewhere - each iteration  */
7049 /* is responsible for changing a single parameter that can be incremented.  */
7050 /* So one pass may increase the source IP#, next source port, next dest. IP#*/
7051 /* and the last destination port for a total of 4 iterations to try each.   */
7052 /* This is done to try and exhaustively use the translation space available.*/
7053 /* ------------------------------------------------------------------------ */
7054 static int
ipf_nat_newrewrite(fin,nat,nai)7055 ipf_nat_newrewrite(fin, nat, nai)
7056 	fr_info_t *fin;
7057 	nat_t *nat;
7058 	natinfo_t *nai;
7059 {
7060 	int src_search = 1;
7061 	int dst_search = 1;
7062 	fr_info_t frnat;
7063 	u_32_t flags;
7064 	u_short swap;
7065 	ipnat_t *np;
7066 	nat_t *natl;
7067 	int l = 0;
7068 	int changed;
7069 
7070 	natl = NULL;
7071 	changed = -1;
7072 	np = nai->nai_np;
7073 	flags = nat->nat_flags;
7074 	bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
7075 
7076 	nat->nat_hm = NULL;
7077 
7078 	do {
7079 		changed = -1;
7080 		/* TRACE (l, src_search, dst_search, np) */
7081 		DT4(ipf_nat_rewrite_1, int, l, int, src_search, int, dst_search, ipnat_t *, np);
7082 
7083 		if ((src_search == 0) && (np->in_spnext == 0) &&
7084 		    (dst_search == 0) && (np->in_dpnext == 0)) {
7085 			if (l > 0)
7086 				return -1;
7087 		}
7088 
7089 		/*
7090 		 * Find a new source address
7091 		 */
7092 		if (ipf_nat_nextaddr(fin, &np->in_nsrc, &frnat.fin_saddr,
7093 				     &frnat.fin_saddr) == -1) {
7094 			return -1;
7095 		}
7096 
7097 		if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0xffffffff)) {
7098 			src_search = 0;
7099 			if (np->in_stepnext == 0)
7100 				np->in_stepnext = 1;
7101 
7102 		} else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) {
7103 			src_search = 0;
7104 			if (np->in_stepnext == 0)
7105 				np->in_stepnext = 1;
7106 
7107 		} else if (np->in_nsrcmsk == 0xffffffff) {
7108 			src_search = 0;
7109 			if (np->in_stepnext == 0)
7110 				np->in_stepnext = 1;
7111 
7112 		} else if (np->in_nsrcmsk != 0xffffffff) {
7113 			if (np->in_stepnext == 0 && changed == -1) {
7114 				np->in_snip++;
7115 				np->in_stepnext++;
7116 				changed = 0;
7117 			}
7118 		}
7119 
7120 		if ((flags & IPN_TCPUDPICMP) != 0) {
7121 			if (np->in_spnext != 0)
7122 				frnat.fin_data[0] = np->in_spnext;
7123 
7124 			/*
7125 			 * Standard port translation.  Select next port.
7126 			 */
7127 			if ((flags & IPN_FIXEDSPORT) != 0) {
7128 				np->in_stepnext = 2;
7129 			} else if ((np->in_stepnext == 1) &&
7130 				   (changed == -1) && (natl != NULL)) {
7131 				np->in_spnext++;
7132 				np->in_stepnext++;
7133 				changed = 1;
7134 				if (np->in_spnext > np->in_spmax)
7135 					np->in_spnext = np->in_spmin;
7136 			}
7137 		} else {
7138 			np->in_stepnext = 2;
7139 		}
7140 		np->in_stepnext &= 0x3;
7141 
7142 		/*
7143 		 * Find a new destination address
7144 		 */
7145 		/* TRACE (fin, np, l, frnat) */
7146 		DT4(ipf_nat_rewrite_2, frinfo_t *, fin, ipnat_t *, np, int, l, frinfo_t *, &frnat);
7147 
7148 		if (ipf_nat_nextaddr(fin, &np->in_ndst, &frnat.fin_daddr,
7149 				     &frnat.fin_daddr) == -1)
7150 			return -1;
7151 		if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) {
7152 			dst_search = 0;
7153 			if (np->in_stepnext == 2)
7154 				np->in_stepnext = 3;
7155 
7156 		} else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0)) {
7157 			dst_search = 0;
7158 			if (np->in_stepnext == 2)
7159 				np->in_stepnext = 3;
7160 
7161 		} else if (np->in_ndstmsk == 0xffffffff) {
7162 			dst_search = 0;
7163 			if (np->in_stepnext == 2)
7164 				np->in_stepnext = 3;
7165 
7166 		} else if (np->in_ndstmsk != 0xffffffff) {
7167 			if ((np->in_stepnext == 2) && (changed == -1) &&
7168 			    (natl != NULL)) {
7169 				changed = 2;
7170 				np->in_stepnext++;
7171 				np->in_dnip++;
7172 			}
7173 		}
7174 
7175 		if ((flags & IPN_TCPUDPICMP) != 0) {
7176 			if (np->in_dpnext != 0)
7177 				frnat.fin_data[1] = np->in_dpnext;
7178 
7179 			/*
7180 			 * Standard port translation.  Select next port.
7181 			 */
7182 			if ((flags & IPN_FIXEDDPORT) != 0) {
7183 				np->in_stepnext = 0;
7184 			} else if (np->in_stepnext == 3 && changed == -1) {
7185 				np->in_dpnext++;
7186 				np->in_stepnext++;
7187 				changed = 3;
7188 				if (np->in_dpnext > np->in_dpmax)
7189 					np->in_dpnext = np->in_dpmin;
7190 			}
7191 		} else {
7192 			if (np->in_stepnext == 3)
7193 				np->in_stepnext = 0;
7194 		}
7195 
7196 		/* TRACE (frnat) */
7197 		DT1(ipf_nat_rewrite_3, frinfo_t *, &frnat);
7198 
7199 		/*
7200 		 * Here we do a lookup of the connection as seen from
7201 		 * the outside.  If an IP# pair already exists, try
7202 		 * again.  So if you have A->B becomes C->B, you can
7203 		 * also have D->E become C->E but not D->B causing
7204 		 * another C->B.  Also take protocol and ports into
7205 		 * account when determining whether a pre-existing
7206 		 * NAT setup will cause an external conflict where
7207 		 * this is appropriate.
7208 		 *
7209 		 * fin_data[] is swapped around because we are doing a
7210 		 * lookup of the packet is if it were moving in the opposite
7211 		 * direction of the one we are working with now.
7212 		 */
7213 		if (flags & IPN_TCPUDP) {
7214 			swap = frnat.fin_data[0];
7215 			frnat.fin_data[0] = frnat.fin_data[1];
7216 			frnat.fin_data[1] = swap;
7217 		}
7218 		if (fin->fin_out == 1) {
7219 			natl = ipf_nat_inlookup(&frnat,
7220 						flags & ~(SI_WILDP|NAT_SEARCH),
7221 						(u_int)frnat.fin_p,
7222 						frnat.fin_dst, frnat.fin_src);
7223 
7224 		} else {
7225 			natl = ipf_nat_outlookup(&frnat,
7226 						 flags & ~(SI_WILDP|NAT_SEARCH),
7227 						 (u_int)frnat.fin_p,
7228 						 frnat.fin_dst, frnat.fin_src);
7229 		}
7230 		if (flags & IPN_TCPUDP) {
7231 			swap = frnat.fin_data[0];
7232 			frnat.fin_data[0] = frnat.fin_data[1];
7233 			frnat.fin_data[1] = swap;
7234 		}
7235 
7236 		/* TRACE natl, in_stepnext, l */
7237 		DT3(ipf_nat_rewrite_2, nat_t *, natl, ipnat_t *, np , int, l);
7238 
7239 		if ((natl != NULL) && (l > 8))	/* XXX 8 is arbitrary */
7240 			return -1;
7241 
7242 		np->in_stepnext &= 0x3;
7243 
7244 		l++;
7245 		changed = -1;
7246 	} while (natl != NULL);
7247 
7248 	nat->nat_osrcip = fin->fin_src;
7249 	nat->nat_odstip = fin->fin_dst;
7250 	nat->nat_nsrcip = frnat.fin_src;
7251 	nat->nat_ndstip = frnat.fin_dst;
7252 
7253 	if ((flags & IPN_TCPUDP) != 0) {
7254 		nat->nat_osport = htons(fin->fin_data[0]);
7255 		nat->nat_odport = htons(fin->fin_data[1]);
7256 		nat->nat_nsport = htons(frnat.fin_data[0]);
7257 		nat->nat_ndport = htons(frnat.fin_data[1]);
7258 	} else if ((flags & IPN_ICMPQUERY) != 0) {
7259 		nat->nat_oicmpid = fin->fin_data[1];
7260 		nat->nat_nicmpid = frnat.fin_data[1];
7261 	}
7262 
7263 	return 0;
7264 }
7265 
7266 
7267 /* ------------------------------------------------------------------------ */
7268 /* Function:    nat_newdivert                                               */
7269 /* Returns:     int - -1 == error, 0 == success                             */
7270 /* Parameters:  fin(I) - pointer to packet information                      */
7271 /*              nat(I) - pointer to NAT entry                               */
7272 /*              ni(I)  - pointer to structure with misc. information needed */
7273 /*                       to create new NAT entry.                           */
7274 /* Write Lock:  ipf_nat                                                     */
7275 /*                                                                          */
7276 /* Create a new NAT  divert session as defined by the NAT rule.  This is    */
7277 /* somewhat different to other NAT session creation routines because we     */
7278 /* do not iterate through either port numbers or IP addresses, searching    */
7279 /* for a unique mapping, however, a complimentary duplicate check is made.  */
7280 /* ------------------------------------------------------------------------ */
7281 static int
ipf_nat_newdivert(fin,nat,nai)7282 ipf_nat_newdivert(fin, nat, nai)
7283 	fr_info_t *fin;
7284 	nat_t *nat;
7285 	natinfo_t *nai;
7286 {
7287 	ipf_main_softc_t *softc = fin->fin_main_soft;
7288 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7289 	fr_info_t frnat;
7290 	ipnat_t *np;
7291 	nat_t *natl;
7292 	int p;
7293 
7294 	np = nai->nai_np;
7295 	bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
7296 
7297 	nat->nat_pr[0] = 0;
7298 	nat->nat_osrcaddr = fin->fin_saddr;
7299 	nat->nat_odstaddr = fin->fin_daddr;
7300 	frnat.fin_saddr = htonl(np->in_snip);
7301 	frnat.fin_daddr = htonl(np->in_dnip);
7302 	if ((nat->nat_flags & IPN_TCPUDP) != 0) {
7303 		nat->nat_osport = htons(fin->fin_data[0]);
7304 		nat->nat_odport = htons(fin->fin_data[1]);
7305 	} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
7306 		nat->nat_oicmpid = fin->fin_data[1];
7307 	}
7308 
7309 	if (np->in_redir & NAT_DIVERTUDP) {
7310 		frnat.fin_data[0] = np->in_spnext;
7311 		frnat.fin_data[1] = np->in_dpnext;
7312 		frnat.fin_flx |= FI_TCPUDP;
7313 		p = IPPROTO_UDP;
7314 	} else {
7315 		frnat.fin_flx &= ~FI_TCPUDP;
7316 		p = IPPROTO_IPIP;
7317 	}
7318 
7319 	if (fin->fin_out == 1) {
7320 		natl = ipf_nat_inlookup(&frnat, 0, p,
7321 					frnat.fin_dst, frnat.fin_src);
7322 
7323 	} else {
7324 		natl = ipf_nat_outlookup(&frnat, 0, p,
7325 					 frnat.fin_dst, frnat.fin_src);
7326 	}
7327 
7328 	if (natl != NULL) {
7329 		NBUMPSIDED(fin->fin_out, ns_divert_exist);
7330 		DT3(ns_divert_exist, fr_info_t *, fin, nat_t *, nat, natinfo_t, nai);
7331 		return -1;
7332 	}
7333 
7334 	nat->nat_nsrcaddr = frnat.fin_saddr;
7335 	nat->nat_ndstaddr = frnat.fin_daddr;
7336 	if ((nat->nat_flags & IPN_TCPUDP) != 0) {
7337 		nat->nat_nsport = htons(frnat.fin_data[0]);
7338 		nat->nat_ndport = htons(frnat.fin_data[1]);
7339 	} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
7340 		nat->nat_nicmpid = frnat.fin_data[1];
7341 	}
7342 
7343 	nat->nat_pr[fin->fin_out] = fin->fin_p;
7344 	nat->nat_pr[1 - fin->fin_out] = p;
7345 
7346 	if (np->in_redir & NAT_REDIRECT)
7347 		nat->nat_dir = NAT_DIVERTIN;
7348 	else
7349 		nat->nat_dir = NAT_DIVERTOUT;
7350 
7351 	return 0;
7352 }
7353 
7354 
7355 /* ------------------------------------------------------------------------ */
7356 /* Function:    nat_builddivertmp                                           */
7357 /* Returns:     int - -1 == error, 0 == success                             */
7358 /* Parameters:  softn(I) - pointer to NAT context structure                 */
7359 /*              np(I)    - pointer to a NAT rule                            */
7360 /*                                                                          */
7361 /* For divert rules, a skeleton packet representing what will be prepended  */
7362 /* to the real packet is created.  Even though we don't have the full       */
7363 /* packet here, a checksum is calculated that we update later when we       */
7364 /* fill in the final details.  At present a 0 checksum for UDP is being set */
7365 /* here because it is expected that divert will be used for localhost.      */
7366 /* ------------------------------------------------------------------------ */
7367 static int
ipf_nat_builddivertmp(softn,np)7368 ipf_nat_builddivertmp(softn, np)
7369 	ipf_nat_softc_t *softn;
7370 	ipnat_t *np;
7371 {
7372 	udphdr_t *uh;
7373 	size_t len;
7374 	ip_t *ip;
7375 
7376 	if ((np->in_redir & NAT_DIVERTUDP) != 0)
7377 		len = sizeof(ip_t) + sizeof(udphdr_t);
7378 	else
7379 		len = sizeof(ip_t);
7380 
7381 	ALLOC_MB_T(np->in_divmp, len);
7382 	if (np->in_divmp == NULL) {
7383 		NBUMPD(ipf_nat_stats, ns_divert_build);
7384 		return -1;
7385 	}
7386 
7387 	/*
7388 	 * First, the header to get the packet diverted to the new destination
7389 	 */
7390 	ip = MTOD(np->in_divmp, ip_t *);
7391 	IP_V_A(ip, 4);
7392 	IP_HL_A(ip, 5);
7393 	ip->ip_tos = 0;
7394 	if ((np->in_redir & NAT_DIVERTUDP) != 0)
7395 		ip->ip_p = IPPROTO_UDP;
7396 	else
7397 		ip->ip_p = IPPROTO_IPIP;
7398 	ip->ip_ttl = 255;
7399 	ip->ip_off = 0;
7400 	ip->ip_sum = 0;
7401 	ip->ip_len = htons(len);
7402 	ip->ip_id = 0;
7403 	ip->ip_src.s_addr = htonl(np->in_snip);
7404 	ip->ip_dst.s_addr = htonl(np->in_dnip);
7405 	ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip));
7406 
7407 	if (np->in_redir & NAT_DIVERTUDP) {
7408 		uh = (udphdr_t *)(ip + 1);
7409 		uh->uh_sum = 0;
7410 		uh->uh_ulen = 8;
7411 		uh->uh_sport = htons(np->in_spnext);
7412 		uh->uh_dport = htons(np->in_dpnext);
7413 	}
7414 
7415 	return 0;
7416 }
7417 
7418 
7419 #define	MINDECAP	(sizeof(ip_t) + sizeof(udphdr_t) + sizeof(ip_t))
7420 
7421 /* ------------------------------------------------------------------------ */
7422 /* Function:    nat_decap                                                   */
7423 /* Returns:     int - -1 == error, 0 == success                             */
7424 /* Parameters:  fin(I) - pointer to packet information                      */
7425 /*              nat(I) - pointer to current NAT session                     */
7426 /*                                                                          */
7427 /* This function is responsible for undoing a packet's encapsulation in the */
7428 /* reverse of an encap/divert rule.  After removing the outer encapsulation */
7429 /* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/
7430 /* match the "new" packet as it may still be used by IPFilter elsewhere.    */
7431 /* We use "dir" here as the basis for some of the expectations about the    */
7432 /* outer header.  If we return an error, the goal is to leave the original  */
7433 /* packet information undisturbed - this falls short at the end where we'd  */
7434 /* need to back a backup copy of "fin" - expensive.                         */
7435 /* ------------------------------------------------------------------------ */
7436 static int
ipf_nat_decap(fin,nat)7437 ipf_nat_decap(fin, nat)
7438 	fr_info_t *fin;
7439 	nat_t *nat;
7440 {
7441 	ipf_main_softc_t *softc = fin->fin_main_soft;
7442 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7443 	char *hdr;
7444 	int hlen;
7445 	int skip;
7446 	mb_t *m;
7447 
7448 	if ((fin->fin_flx & FI_ICMPERR) != 0) {
7449 		/*
7450 		 * ICMP packets don't get decapsulated, instead what we need
7451 		 * to do is change the ICMP reply from including (in the data
7452 		 * portion for errors) the encapsulated packet that we sent
7453 		 * out to something that resembles the original packet prior
7454 		 * to encapsulation.  This isn't done here - all we're doing
7455 		 * here is changing the outer address to ensure that it gets
7456 		 * targetted back to the correct system.
7457 		 */
7458 
7459 		if (nat->nat_dir & NAT_OUTBOUND) {
7460 			u_32_t sum1, sum2, sumd;
7461 
7462 			sum1 = ntohl(fin->fin_daddr);
7463 			sum2 = ntohl(nat->nat_osrcaddr);
7464 			CALC_SUMD(sum1, sum2, sumd);
7465 			fin->fin_ip->ip_dst = nat->nat_osrcip;
7466 			fin->fin_daddr = nat->nat_osrcaddr;
7467 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
7468      defined(__osf__) || defined(linux)
7469 			ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, sumd, 0);
7470 #endif
7471 		}
7472 		return 0;
7473 	}
7474 
7475 	m = fin->fin_m;
7476 	skip = fin->fin_hlen;
7477 
7478 	switch (nat->nat_dir)
7479 	{
7480 	case NAT_DIVERTIN :
7481 	case NAT_DIVERTOUT :
7482 		if (fin->fin_plen < MINDECAP)
7483 			return -1;
7484 		skip += sizeof(udphdr_t);
7485 		break;
7486 
7487 	case NAT_ENCAPIN :
7488 	case NAT_ENCAPOUT :
7489 		if (fin->fin_plen < (skip + sizeof(ip_t)))
7490 			return -1;
7491 		break;
7492 	default :
7493 		return -1;
7494 		/* NOTREACHED */
7495 	}
7496 
7497 	/*
7498 	 * The aim here is to keep the original packet details in "fin" for
7499 	 * as long as possible so that returning with an error is for the
7500 	 * original packet and there is little undoing work to do.
7501 	 */
7502 	if (M_LEN(m) < skip + sizeof(ip_t)) {
7503 		if (ipf_pr_pullup(fin, skip + sizeof(ip_t)) == -1)
7504 			return -1;
7505 	}
7506 
7507 	hdr = MTOD(fin->fin_m, char *);
7508 	fin->fin_ip = (ip_t *)(hdr + skip);
7509 	hlen = IP_HL(fin->fin_ip) << 2;
7510 
7511 	if (ipf_pr_pullup(fin, skip + hlen) == -1) {
7512 		NBUMPSIDED(fin->fin_out, ns_decap_pullup);
7513 		return -1;
7514 	}
7515 
7516 	fin->fin_hlen = hlen;
7517 	fin->fin_dlen -= skip;
7518 	fin->fin_plen -= skip;
7519 	fin->fin_ipoff += skip;
7520 
7521 	if (ipf_makefrip(hlen, (ip_t *)hdr, fin) == -1) {
7522 		NBUMPSIDED(fin->fin_out, ns_decap_bad);
7523 		return -1;
7524 	}
7525 
7526 	return skip;
7527 }
7528 
7529 
7530 /* ------------------------------------------------------------------------ */
7531 /* Function:    nat_nextaddr                                                */
7532 /* Returns:     int - -1 == bad input (no new address),                     */
7533 /*                     0 == success and dst has new address                 */
7534 /* Parameters:  fin(I) - pointer to packet information                      */
7535 /*              na(I)  - how to generate new address                        */
7536 /*              old(I) - original address being replaced                    */
7537 /*              dst(O) - where to put the new address                       */
7538 /* Write Lock:  ipf_nat                                                     */
7539 /*                                                                          */
7540 /* This function uses the contents of the "na" structure, in combination    */
7541 /* with "old" to produce a new address to store in "dst".  Not all of the   */
7542 /* possible uses of "na" will result in a new address.                      */
7543 /* ------------------------------------------------------------------------ */
7544 static int
ipf_nat_nextaddr(fin,na,old,dst)7545 ipf_nat_nextaddr(fin, na, old, dst)
7546 	fr_info_t *fin;
7547 	nat_addr_t *na;
7548 	u_32_t *old, *dst;
7549 {
7550 	ipf_main_softc_t *softc = fin->fin_main_soft;
7551 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7552 	u_32_t amin, amax, new;
7553 	i6addr_t newip;
7554 	int error;
7555 
7556 	new = 0;
7557 	amin = na->na_addr[0].in4.s_addr;
7558 
7559 	switch (na->na_atype)
7560 	{
7561 	case FRI_RANGE :
7562 		amax = na->na_addr[1].in4.s_addr;
7563 		break;
7564 
7565 	case FRI_NETMASKED :
7566 	case FRI_DYNAMIC :
7567 	case FRI_NORMAL :
7568 		/*
7569 		 * Compute the maximum address by adding the inverse of the
7570 		 * netmask to the minimum address.
7571 		 */
7572 		amax = ~na->na_addr[1].in4.s_addr;
7573 		amax |= amin;
7574 		break;
7575 
7576 	case FRI_LOOKUP :
7577 		break;
7578 
7579 	case FRI_BROADCAST :
7580 	case FRI_PEERADDR :
7581 	case FRI_NETWORK :
7582 	default :
7583 		DT4(ns_na_atype, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new);
7584 		return -1;
7585 	}
7586 
7587 	error = -1;
7588 
7589 	if (na->na_atype == FRI_LOOKUP) {
7590 		if (na->na_type == IPLT_DSTLIST) {
7591 			error = ipf_dstlist_select_node(fin, na->na_ptr, dst,
7592 							NULL);
7593 		} else {
7594 			NBUMPSIDE(fin->fin_out, ns_badnextaddr);
7595 			DT4(ns_badnextaddr_1, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new);
7596 		}
7597 
7598 	} else if (na->na_atype == IPLT_NONE) {
7599 		/*
7600 		 * 0/0 as the new address means leave it alone.
7601 		 */
7602 		if (na->na_addr[0].in4.s_addr == 0 &&
7603 		    na->na_addr[1].in4.s_addr == 0) {
7604 			new = *old;
7605 
7606 		/*
7607 		 * 0/32 means get the interface's address
7608 		 */
7609 		} else if (na->na_addr[0].in4.s_addr == 0 &&
7610 			   na->na_addr[1].in4.s_addr == 0xffffffff) {
7611 			if (ipf_ifpaddr(softc, 4, na->na_atype,
7612 					fin->fin_ifp, &newip, NULL) == -1) {
7613 				NBUMPSIDED(fin->fin_out, ns_ifpaddrfail);
7614 				DT4(ns_ifpaddrfail, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new);
7615 				return -1;
7616 			}
7617 			new = newip.in4.s_addr;
7618 		} else {
7619 			new = htonl(na->na_nextip);
7620 		}
7621 		*dst = new;
7622 		error = 0;
7623 
7624 	} else {
7625 		NBUMPSIDE(fin->fin_out, ns_badnextaddr);
7626 		DT4(ns_badnextaddr_2, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new);
7627 	}
7628 
7629 	return error;
7630 }
7631 
7632 
7633 /* ------------------------------------------------------------------------ */
7634 /* Function:    nat_nextaddrinit                                            */
7635 /* Returns:     int - 0 == success, else error number                       */
7636 /* Parameters:  softc(I) - pointer to soft context main structure           */
7637 /*              na(I)      - NAT address information for generating new addr*/
7638 /*              initial(I) - flag indicating if it is the first call for    */
7639 /*                           this "na" structure.                           */
7640 /*              ifp(I)     - network interface to derive address            */
7641 /*                           information from.                              */
7642 /*                                                                          */
7643 /* This function is expected to be called in two scenarious: when a new NAT */
7644 /* rule is loaded into the kernel and when the list of NAT rules is sync'd  */
7645 /* up with the valid network interfaces (possibly due to them changing.)    */
7646 /* To distinguish between these, the "initial" parameter is used.  If it is */
7647 /* 1 then this indicates the rule has just been reloaded and 0 for when we  */
7648 /* are updating information.  This difference is important because in       */
7649 /* instances where we are not updating address information associated with  */
7650 /* a network interface, we don't want to disturb what the "next" address to */
7651 /* come out of ipf_nat_nextaddr() will be.                                  */
7652 /* ------------------------------------------------------------------------ */
7653 static int
ipf_nat_nextaddrinit(softc,base,na,initial,ifp)7654 ipf_nat_nextaddrinit(softc, base, na, initial, ifp)
7655 	ipf_main_softc_t *softc;
7656 	char *base;
7657 	nat_addr_t *na;
7658 	int initial;
7659 	void *ifp;
7660 {
7661 
7662 	switch (na->na_atype)
7663 	{
7664 	case FRI_LOOKUP :
7665 		if (na->na_subtype == 0) {
7666 			na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT,
7667 							na->na_type,
7668 							na->na_num,
7669 							&na->na_func);
7670 		} else if (na->na_subtype == 1) {
7671 			na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT,
7672 							 na->na_type,
7673 							 base + na->na_num,
7674 							 &na->na_func);
7675 		}
7676 		if (na->na_func == NULL) {
7677 			IPFERROR(60060);
7678 			return ESRCH;
7679 		}
7680 		if (na->na_ptr == NULL) {
7681 			IPFERROR(60056);
7682 			return ESRCH;
7683 		}
7684 		break;
7685 
7686 	case FRI_DYNAMIC :
7687 	case FRI_BROADCAST :
7688 	case FRI_NETWORK :
7689 	case FRI_NETMASKED :
7690 	case FRI_PEERADDR :
7691 		if (ifp != NULL)
7692 			(void )ipf_ifpaddr(softc, 4, na->na_atype, ifp,
7693 					   &na->na_addr[0], &na->na_addr[1]);
7694 		break;
7695 
7696 	case FRI_SPLIT :
7697 	case FRI_RANGE :
7698 		if (initial)
7699 			na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
7700 		break;
7701 
7702 	case FRI_NONE :
7703 		na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
7704 		return 0;
7705 
7706 	case FRI_NORMAL :
7707 		na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
7708 		break;
7709 
7710 	default :
7711 		IPFERROR(60054);
7712 		return EINVAL;
7713 	}
7714 
7715 	if (initial && (na->na_atype == FRI_NORMAL)) {
7716 		if (na->na_addr[0].in4.s_addr == 0) {
7717 			if ((na->na_addr[1].in4.s_addr == 0xffffffff) ||
7718 			    (na->na_addr[1].in4.s_addr == 0)) {
7719 				return 0;
7720 			}
7721 		}
7722 
7723 		if (na->na_addr[1].in4.s_addr == 0xffffffff) {
7724 			na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
7725 		} else {
7726 			na->na_nextip = ntohl(na->na_addr[0].in4.s_addr) + 1;
7727 		}
7728 	}
7729 
7730 	return 0;
7731 }
7732 
7733 
7734 /* ------------------------------------------------------------------------ */
7735 /* Function:    ipf_nat_matchflush                                          */
7736 /* Returns:     int - -1 == error, 0 == success                             */
7737 /* Parameters:  softc(I) - pointer to soft context main structure           */
7738 /*              softn(I) - pointer to NAT context structure                 */
7739 /*              nat(I)   - pointer to current NAT session                   */
7740 /*                                                                          */
7741 /* ------------------------------------------------------------------------ */
7742 static int
ipf_nat_matchflush(softc,softn,data)7743 ipf_nat_matchflush(softc, softn, data)
7744 	ipf_main_softc_t *softc;
7745 	ipf_nat_softc_t *softn;
7746 	caddr_t data;
7747 {
7748 	int *array, flushed, error;
7749 	nat_t *nat, *natnext;
7750 	ipfobj_t obj;
7751 
7752 	error = ipf_matcharray_load(softc, data, &obj, &array);
7753 	if (error != 0)
7754 		return error;
7755 
7756 	flushed = 0;
7757 
7758 	for (nat = softn->ipf_nat_instances; nat != NULL; nat = natnext) {
7759 		natnext = nat->nat_next;
7760 		if (ipf_nat_matcharray(nat, array, softc->ipf_ticks) == 0) {
7761 			ipf_nat_delete(softc, nat, NL_FLUSH);
7762 			flushed++;
7763 		}
7764 	}
7765 
7766 	obj.ipfo_retval = flushed;
7767 	error = BCOPYOUT(&obj, data, sizeof(obj));
7768 
7769 	KFREES(array, array[0] * sizeof(*array));
7770 
7771 	return error;
7772 }
7773 
7774 
7775 /* ------------------------------------------------------------------------ */
7776 /* Function:    ipf_nat_matcharray                                          */
7777 /* Returns:     int - -1 == error, 0 == success                             */
7778 /* Parameters:  fin(I) - pointer to packet information                      */
7779 /*              nat(I) - pointer to current NAT session                     */
7780 /*                                                                          */
7781 /* ------------------------------------------------------------------------ */
7782 static int
ipf_nat_matcharray(nat,array,ticks)7783 ipf_nat_matcharray(nat, array, ticks)
7784 	nat_t *nat;
7785 	int *array;
7786 	u_long ticks;
7787 {
7788 	int i, n, *x, e, p;
7789 
7790 	e = 0;
7791 	n = array[0];
7792 	x = array + 1;
7793 
7794 	for (; n > 0; x += 3 + x[2]) {
7795 		if (x[0] == IPF_EXP_END)
7796 			break;
7797 		e = 0;
7798 
7799 		n -= x[2] + 3;
7800 		if (n < 0)
7801 			break;
7802 
7803 		p = x[0] >> 16;
7804 		if (p != 0 && p != nat->nat_pr[1])
7805 			break;
7806 
7807 		switch (x[0])
7808 		{
7809 		case IPF_EXP_IP_PR :
7810 			for (i = 0; !e && i < x[2]; i++) {
7811 				e |= (nat->nat_pr[1] == x[i + 3]);
7812 			}
7813 			break;
7814 
7815 		case IPF_EXP_IP_SRCADDR :
7816 			if (nat->nat_v[0] == 4) {
7817 				for (i = 0; !e && i < x[2]; i++) {
7818 					e |= ((nat->nat_osrcaddr & x[i + 4]) ==
7819 					      x[i + 3]);
7820 				}
7821 			}
7822 			if (nat->nat_v[1] == 4) {
7823 				for (i = 0; !e && i < x[2]; i++) {
7824 					e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
7825 					      x[i + 3]);
7826 				}
7827 			}
7828 			break;
7829 
7830 		case IPF_EXP_IP_DSTADDR :
7831 			if (nat->nat_v[0] == 4) {
7832 				for (i = 0; !e && i < x[2]; i++) {
7833 					e |= ((nat->nat_odstaddr & x[i + 4]) ==
7834 					      x[i + 3]);
7835 				}
7836 			}
7837 			if (nat->nat_v[1] == 4) {
7838 				for (i = 0; !e && i < x[2]; i++) {
7839 					e |= ((nat->nat_ndstaddr & x[i + 4]) ==
7840 					      x[i + 3]);
7841 				}
7842 			}
7843 			break;
7844 
7845 		case IPF_EXP_IP_ADDR :
7846 			for (i = 0; !e && i < x[2]; i++) {
7847 				if (nat->nat_v[0] == 4) {
7848 					e |= ((nat->nat_osrcaddr & x[i + 4]) ==
7849 					      x[i + 3]);
7850 				}
7851 				if (nat->nat_v[1] == 4) {
7852 					e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
7853 					      x[i + 3]);
7854 				}
7855 				if (nat->nat_v[0] == 4) {
7856 					e |= ((nat->nat_odstaddr & x[i + 4]) ==
7857 					      x[i + 3]);
7858 				}
7859 				if (nat->nat_v[1] == 4) {
7860 					e |= ((nat->nat_ndstaddr & x[i + 4]) ==
7861 					      x[i + 3]);
7862 				}
7863 			}
7864 			break;
7865 
7866 #ifdef USE_INET6
7867 		case IPF_EXP_IP6_SRCADDR :
7868 			if (nat->nat_v[0] == 6) {
7869 				for (i = 0; !e && i < x[3]; i++) {
7870 					e |= IP6_MASKEQ(&nat->nat_osrc6,
7871 							x + i + 7, x + i + 3);
7872 				}
7873 			}
7874 			if (nat->nat_v[1] == 6) {
7875 				for (i = 0; !e && i < x[3]; i++) {
7876 					e |= IP6_MASKEQ(&nat->nat_nsrc6,
7877 							x + i + 7, x + i + 3);
7878 				}
7879 			}
7880 			break;
7881 
7882 		case IPF_EXP_IP6_DSTADDR :
7883 			if (nat->nat_v[0] == 6) {
7884 				for (i = 0; !e && i < x[3]; i++) {
7885 					e |= IP6_MASKEQ(&nat->nat_odst6,
7886 							x + i + 7,
7887 							x + i + 3);
7888 				}
7889 			}
7890 			if (nat->nat_v[1] == 6) {
7891 				for (i = 0; !e && i < x[3]; i++) {
7892 					e |= IP6_MASKEQ(&nat->nat_ndst6,
7893 							x + i + 7,
7894 							x + i + 3);
7895 				}
7896 			}
7897 			break;
7898 
7899 		case IPF_EXP_IP6_ADDR :
7900 			for (i = 0; !e && i < x[3]; i++) {
7901 				if (nat->nat_v[0] == 6) {
7902 					e |= IP6_MASKEQ(&nat->nat_osrc6,
7903 							x + i + 7,
7904 							x + i + 3);
7905 				}
7906 				if (nat->nat_v[0] == 6) {
7907 					e |= IP6_MASKEQ(&nat->nat_odst6,
7908 							x + i + 7,
7909 							x + i + 3);
7910 				}
7911 				if (nat->nat_v[1] == 6) {
7912 					e |= IP6_MASKEQ(&nat->nat_nsrc6,
7913 							x + i + 7,
7914 							x + i + 3);
7915 				}
7916 				if (nat->nat_v[1] == 6) {
7917 					e |= IP6_MASKEQ(&nat->nat_ndst6,
7918 							x + i + 7,
7919 							x + i + 3);
7920 				}
7921 			}
7922 			break;
7923 #endif
7924 
7925 		case IPF_EXP_UDP_PORT :
7926 		case IPF_EXP_TCP_PORT :
7927 			for (i = 0; !e && i < x[2]; i++) {
7928 				e |= (nat->nat_nsport == x[i + 3]) ||
7929 				     (nat->nat_ndport == x[i + 3]);
7930 			}
7931 			break;
7932 
7933 		case IPF_EXP_UDP_SPORT :
7934 		case IPF_EXP_TCP_SPORT :
7935 			for (i = 0; !e && i < x[2]; i++) {
7936 				e |= (nat->nat_nsport == x[i + 3]);
7937 			}
7938 			break;
7939 
7940 		case IPF_EXP_UDP_DPORT :
7941 		case IPF_EXP_TCP_DPORT :
7942 			for (i = 0; !e && i < x[2]; i++) {
7943 				e |= (nat->nat_ndport == x[i + 3]);
7944 			}
7945 			break;
7946 
7947 		case IPF_EXP_TCP_STATE :
7948 			for (i = 0; !e && i < x[2]; i++) {
7949 				e |= (nat->nat_tcpstate[0] == x[i + 3]) ||
7950 				     (nat->nat_tcpstate[1] == x[i + 3]);
7951 			}
7952 			break;
7953 
7954 		case IPF_EXP_IDLE_GT :
7955 			e |= (ticks - nat->nat_touched > x[3]);
7956 			break;
7957 		}
7958 		e ^= x[1];
7959 
7960 		if (!e)
7961 			break;
7962 	}
7963 
7964 	return e;
7965 }
7966 
7967 
7968 /* ------------------------------------------------------------------------ */
7969 /* Function:    ipf_nat_gettable                                            */
7970 /* Returns:     int     - 0 = success, else error                           */
7971 /* Parameters:  softc(I) - pointer to soft context main structure           */
7972 /*              softn(I) - pointer to NAT context structure                 */
7973 /*              data(I)  - pointer to ioctl data                            */
7974 /*                                                                          */
7975 /* This function handles ioctl requests for tables of nat information.      */
7976 /* At present the only table it deals with is the hash bucket statistics.   */
7977 /* ------------------------------------------------------------------------ */
7978 static int
ipf_nat_gettable(softc,softn,data)7979 ipf_nat_gettable(softc, softn, data)
7980 	ipf_main_softc_t *softc;
7981 	ipf_nat_softc_t *softn;
7982 	char *data;
7983 {
7984 	ipftable_t table;
7985 	int error;
7986 
7987 	error = ipf_inobj(softc, data, NULL, &table, IPFOBJ_GTABLE);
7988 	if (error != 0)
7989 		return error;
7990 
7991 	switch (table.ita_type)
7992 	{
7993 	case IPFTABLE_BUCKETS_NATIN :
7994 		error = COPYOUT(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
7995 				table.ita_table,
7996 				softn->ipf_nat_table_sz * sizeof(u_int));
7997 		break;
7998 
7999 	case IPFTABLE_BUCKETS_NATOUT :
8000 		error = COPYOUT(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
8001 				table.ita_table,
8002 				softn->ipf_nat_table_sz * sizeof(u_int));
8003 		break;
8004 
8005 	default :
8006 		IPFERROR(60058);
8007 		return EINVAL;
8008 	}
8009 
8010 	if (error != 0) {
8011 		IPFERROR(60059);
8012 		error = EFAULT;
8013 	}
8014 	return error;
8015 }
8016 
8017 
8018 /* ------------------------------------------------------------------------ */
8019 /* Function:    ipf_nat_settimeout                                          */
8020 /* Returns:     int  - 0 = success, else failure			    */
8021 /* Parameters:  softc(I) - pointer to soft context main structure           */
8022 /*              t(I) - pointer to tunable                                   */
8023 /*              p(I) - pointer to new tuning data                           */
8024 /*                                                                          */
8025 /* Apply the timeout change to the NAT timeout queues.                      */
8026 /* ------------------------------------------------------------------------ */
8027 int
ipf_nat_settimeout(softc,t,p)8028 ipf_nat_settimeout(softc, t, p)
8029 	struct ipf_main_softc_s *softc;
8030 	ipftuneable_t *t;
8031 	ipftuneval_t *p;
8032 {
8033 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8034 
8035 	if (!strncmp(t->ipft_name, "tcp_", 4))
8036 		return ipf_settimeout_tcp(t, p, softn->ipf_nat_tcptq);
8037 
8038 	if (!strcmp(t->ipft_name, "udp_timeout")) {
8039 		ipf_apply_timeout(&softn->ipf_nat_udptq, p->ipftu_int);
8040 	} else if (!strcmp(t->ipft_name, "udp_ack_timeout")) {
8041 		ipf_apply_timeout(&softn->ipf_nat_udpacktq, p->ipftu_int);
8042 	} else if (!strcmp(t->ipft_name, "icmp_timeout")) {
8043 		ipf_apply_timeout(&softn->ipf_nat_icmptq, p->ipftu_int);
8044 	} else if (!strcmp(t->ipft_name, "icmp_ack_timeout")) {
8045 		ipf_apply_timeout(&softn->ipf_nat_icmpacktq, p->ipftu_int);
8046 	} else if (!strcmp(t->ipft_name, "ip_timeout")) {
8047 		ipf_apply_timeout(&softn->ipf_nat_iptq, p->ipftu_int);
8048 	} else {
8049 		IPFERROR(60062);
8050 		return ESRCH;
8051 	}
8052 	return 0;
8053 }
8054 
8055 
8056 /* ------------------------------------------------------------------------ */
8057 /* Function:    ipf_nat_rehash                                              */
8058 /* Returns:     int  - 0 = success, else failure			    */
8059 /* Parameters:  softc(I) - pointer to soft context main structure           */
8060 /*              t(I) - pointer to tunable                                   */
8061 /*              p(I) - pointer to new tuning data                           */
8062 /*                                                                          */
8063 /* To change the size of the basic NAT table, we need to first allocate the */
8064 /* new tables (lest it fails and we've got nowhere to store all of the NAT  */
8065 /* sessions currently active) and then walk through the entire list and     */
8066 /* insert them into the table.  There are two tables here: an inbound one   */
8067 /* and an outbound one.  Each NAT entry goes into each table once.          */
8068 /* ------------------------------------------------------------------------ */
8069 int
ipf_nat_rehash(softc,t,p)8070 ipf_nat_rehash(softc, t, p)
8071 	ipf_main_softc_t *softc;
8072 	ipftuneable_t *t;
8073 	ipftuneval_t *p;
8074 {
8075 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8076 	nat_t **newtab[2], *nat, **natp;
8077 	u_int *bucketlens[2];
8078 	u_int maxbucket;
8079 	u_int newsize;
8080 	int error;
8081 	u_int hv;
8082 	int i;
8083 
8084 	newsize = p->ipftu_int;
8085 	/*
8086 	 * In case there is nothing to do...
8087 	 */
8088 	if (newsize == softn->ipf_nat_table_sz)
8089 		return 0;
8090 
8091 	newtab[0] = NULL;
8092 	newtab[1] = NULL;
8093 	bucketlens[0] = NULL;
8094 	bucketlens[1] = NULL;
8095 	/*
8096 	 * 4 tables depend on the NAT table size: the inbound looking table,
8097 	 * the outbound lookup table and the hash chain length for each.
8098 	 */
8099 	KMALLOCS(newtab[0], nat_t **, newsize * sizeof(nat_t *));
8100 	if (newtab == NULL) {
8101 		error = 60063;
8102 		goto badrehash;
8103 	}
8104 
8105 	KMALLOCS(newtab[1], nat_t **, newsize * sizeof(nat_t *));
8106 	if (newtab == NULL) {
8107 		error = 60064;
8108 		goto badrehash;
8109 	}
8110 
8111 	KMALLOCS(bucketlens[0], u_int *, newsize * sizeof(u_int));
8112 	if (bucketlens[0] == NULL) {
8113 		error = 60065;
8114 		goto badrehash;
8115 	}
8116 
8117 	KMALLOCS(bucketlens[1], u_int *, newsize * sizeof(u_int));
8118 	if (bucketlens[1] == NULL) {
8119 		error = 60066;
8120 		goto badrehash;
8121 	}
8122 
8123 	/*
8124 	 * Recalculate the maximum length based on the new size.
8125 	 */
8126 	for (maxbucket = 0, i = newsize; i > 0; i >>= 1)
8127 		maxbucket++;
8128 	maxbucket *= 2;
8129 
8130 	bzero((char *)newtab[0], newsize * sizeof(nat_t *));
8131 	bzero((char *)newtab[1], newsize * sizeof(nat_t *));
8132 	bzero((char *)bucketlens[0], newsize * sizeof(u_int));
8133 	bzero((char *)bucketlens[1], newsize * sizeof(u_int));
8134 
8135 	WRITE_ENTER(&softc->ipf_nat);
8136 
8137 	if (softn->ipf_nat_table[0] != NULL) {
8138 		KFREES(softn->ipf_nat_table[0],
8139 		       softn->ipf_nat_table_sz *
8140 		       sizeof(*softn->ipf_nat_table[0]));
8141 	}
8142 	softn->ipf_nat_table[0] = newtab[0];
8143 
8144 	if (softn->ipf_nat_table[1] != NULL) {
8145 		KFREES(softn->ipf_nat_table[1],
8146 		       softn->ipf_nat_table_sz *
8147 		       sizeof(*softn->ipf_nat_table[1]));
8148 	}
8149 	softn->ipf_nat_table[1] = newtab[1];
8150 
8151 	if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) {
8152 		KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
8153 		       softn->ipf_nat_table_sz * sizeof(u_int));
8154 	}
8155 	softn->ipf_nat_stats.ns_side[0].ns_bucketlen = bucketlens[0];
8156 
8157 	if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) {
8158 		KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
8159 		       softn->ipf_nat_table_sz * sizeof(u_int));
8160 	}
8161 	softn->ipf_nat_stats.ns_side[1].ns_bucketlen = bucketlens[1];
8162 
8163 #ifdef USE_INET6
8164 	if (softn->ipf_nat_stats.ns_side6[0].ns_bucketlen != NULL) {
8165 		KFREES(softn->ipf_nat_stats.ns_side6[0].ns_bucketlen,
8166 		       softn->ipf_nat_table_sz * sizeof(u_int));
8167 	}
8168 	softn->ipf_nat_stats.ns_side6[0].ns_bucketlen = bucketlens[0];
8169 
8170 	if (softn->ipf_nat_stats.ns_side6[1].ns_bucketlen != NULL) {
8171 		KFREES(softn->ipf_nat_stats.ns_side6[1].ns_bucketlen,
8172 		       softn->ipf_nat_table_sz * sizeof(u_int));
8173 	}
8174 	softn->ipf_nat_stats.ns_side6[1].ns_bucketlen = bucketlens[1];
8175 #endif
8176 
8177 	softn->ipf_nat_maxbucket = maxbucket;
8178 	softn->ipf_nat_table_sz = newsize;
8179 	/*
8180 	 * Walk through the entire list of NAT table entries and put them
8181 	 * in the new NAT table, somewhere.  Because we have a new table,
8182 	 * we need to restart the counter of how many chains are in use.
8183 	 */
8184 	softn->ipf_nat_stats.ns_side[0].ns_inuse = 0;
8185 	softn->ipf_nat_stats.ns_side[1].ns_inuse = 0;
8186 #ifdef USE_INET6
8187 	softn->ipf_nat_stats.ns_side6[0].ns_inuse = 0;
8188 	softn->ipf_nat_stats.ns_side6[1].ns_inuse = 0;
8189 #endif
8190 
8191 	for (nat = softn->ipf_nat_instances; nat != NULL; nat = nat->nat_next) {
8192 		nat->nat_hnext[0] = NULL;
8193 		nat->nat_phnext[0] = NULL;
8194 		hv = nat->nat_hv[0] % softn->ipf_nat_table_sz;
8195 
8196 		natp = &softn->ipf_nat_table[0][hv];
8197 		if (*natp) {
8198 			(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
8199 		} else {
8200 			NBUMPSIDE(0, ns_inuse);
8201 		}
8202 		nat->nat_phnext[0] = natp;
8203 		nat->nat_hnext[0] = *natp;
8204 		*natp = nat;
8205 		NBUMPSIDE(0, ns_bucketlen[hv]);
8206 
8207 		nat->nat_hnext[1] = NULL;
8208 		nat->nat_phnext[1] = NULL;
8209 		hv = nat->nat_hv[1] % softn->ipf_nat_table_sz;
8210 
8211 		natp = &softn->ipf_nat_table[1][hv];
8212 		if (*natp) {
8213 			(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
8214 		} else {
8215 			NBUMPSIDE(1, ns_inuse);
8216 		}
8217 		nat->nat_phnext[1] = natp;
8218 		nat->nat_hnext[1] = *natp;
8219 		*natp = nat;
8220 		NBUMPSIDE(1, ns_bucketlen[hv]);
8221 	}
8222 	RWLOCK_EXIT(&softc->ipf_nat);
8223 
8224 	return 0;
8225 
8226 badrehash:
8227 	if (bucketlens[1] != NULL) {
8228 		KFREES(bucketlens[0], newsize * sizeof(u_int));
8229 	}
8230 	if (bucketlens[0] != NULL) {
8231 		KFREES(bucketlens[0], newsize * sizeof(u_int));
8232 	}
8233 	if (newtab[0] != NULL) {
8234 		KFREES(newtab[0], newsize * sizeof(nat_t *));
8235 	}
8236 	if (newtab[1] != NULL) {
8237 		KFREES(newtab[1], newsize * sizeof(nat_t *));
8238 	}
8239 	IPFERROR(error);
8240 	return ENOMEM;
8241 }
8242 
8243 
8244 /* ------------------------------------------------------------------------ */
8245 /* Function:    ipf_nat_rehash_rules                                        */
8246 /* Returns:     int  - 0 = success, else failure			    */
8247 /* Parameters:  softc(I) - pointer to soft context main structure           */
8248 /*              t(I) - pointer to tunable                                   */
8249 /*              p(I) - pointer to new tuning data                           */
8250 /*                                                                          */
8251 /* All of the NAT rules hang off of a hash table that is searched with a    */
8252 /* hash on address after the netmask is applied.  There is a different table*/
8253 /* for both inbound rules (rdr) and outbound (map.)  The resizing will only */
8254 /* affect one of these two tables.                                          */
8255 /* ------------------------------------------------------------------------ */
8256 int
ipf_nat_rehash_rules(softc,t,p)8257 ipf_nat_rehash_rules(softc, t, p)
8258 	ipf_main_softc_t *softc;
8259 	ipftuneable_t *t;
8260 	ipftuneval_t *p;
8261 {
8262 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8263 	ipnat_t **newtab, *np, ***old, **npp;
8264 	u_int newsize;
8265 	u_int mask;
8266 	u_int hv;
8267 
8268 	newsize = p->ipftu_int;
8269 	/*
8270 	 * In case there is nothing to do...
8271 	 */
8272 	if (newsize == *t->ipft_pint)
8273 		return 0;
8274 
8275 	/*
8276 	 * All inbound rules have the NAT_REDIRECT bit set in in_redir and
8277 	 * all outbound rules have either NAT_MAP or MAT_MAPBLK set.
8278 	 * This if statement allows for some more generic code to be below,
8279 	 * rather than two huge gobs of code that almost do the same thing.
8280 	 */
8281 	if (t->ipft_pint == &softn->ipf_nat_rdrrules_sz) {
8282 		old = &softn->ipf_nat_rdr_rules;
8283 		mask = NAT_REDIRECT;
8284 	} else {
8285 		old = &softn->ipf_nat_map_rules;
8286 		mask = NAT_MAP|NAT_MAPBLK;
8287 	}
8288 
8289 	KMALLOCS(newtab, ipnat_t **, newsize * sizeof(ipnat_t *));
8290 	if (newtab == NULL) {
8291 		IPFERROR(60067);
8292 		return ENOMEM;
8293 	}
8294 
8295 	bzero((char *)newtab, newsize * sizeof(ipnat_t *));
8296 
8297 	WRITE_ENTER(&softc->ipf_nat);
8298 
8299 	if (*old != NULL) {
8300 		KFREES(*old, *t->ipft_pint * sizeof(ipnat_t **));
8301 	}
8302 	*old = newtab;
8303 	*t->ipft_pint = newsize;
8304 
8305 	for (np = softn->ipf_nat_list; np != NULL; np = np->in_next) {
8306 		if ((np->in_redir & mask) == 0)
8307 			continue;
8308 
8309 		if (np->in_redir & NAT_REDIRECT) {
8310 			np->in_rnext = NULL;
8311 			hv = np->in_hv[0] % newsize;
8312 			for (npp = newtab + hv; *npp != NULL; )
8313 				npp = &(*npp)->in_rnext;
8314 			np->in_prnext = npp;
8315 			*npp = np;
8316 		}
8317 		if (np->in_redir & NAT_MAP) {
8318 			np->in_mnext = NULL;
8319 			hv = np->in_hv[1] % newsize;
8320 			for (npp = newtab + hv; *npp != NULL; )
8321 				npp = &(*npp)->in_mnext;
8322 			np->in_pmnext = npp;
8323 			*npp = np;
8324 		}
8325 
8326 	}
8327 	RWLOCK_EXIT(&softc->ipf_nat);
8328 
8329 	return 0;
8330 }
8331 
8332 
8333 /* ------------------------------------------------------------------------ */
8334 /* Function:    ipf_nat_hostmap_rehash                                      */
8335 /* Returns:     int  - 0 = success, else failure			    */
8336 /* Parameters:  softc(I) - pointer to soft context main structure           */
8337 /*              t(I) - pointer to tunable                                   */
8338 /*              p(I) - pointer to new tuning data                           */
8339 /*                                                                          */
8340 /* Allocate and populate a new hash table that will contain a reference to  */
8341 /* all of the active IP# translations currently in place.                   */
8342 /* ------------------------------------------------------------------------ */
8343 int
ipf_nat_hostmap_rehash(softc,t,p)8344 ipf_nat_hostmap_rehash(softc, t, p)
8345 	ipf_main_softc_t *softc;
8346 	ipftuneable_t *t;
8347 	ipftuneval_t *p;
8348 {
8349 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8350 	hostmap_t *hm, **newtab;
8351 	u_int newsize;
8352 	u_int hv;
8353 
8354 	newsize = p->ipftu_int;
8355 	/*
8356 	 * In case there is nothing to do...
8357 	 */
8358 	if (newsize == *t->ipft_pint)
8359 		return 0;
8360 
8361 	KMALLOCS(newtab, hostmap_t **, newsize * sizeof(hostmap_t *));
8362 	if (newtab == NULL) {
8363 		IPFERROR(60068);
8364 		return ENOMEM;
8365 	}
8366 
8367 	bzero((char *)newtab, newsize * sizeof(hostmap_t *));
8368 
8369 	WRITE_ENTER(&softc->ipf_nat);
8370 	if (softn->ipf_hm_maptable != NULL) {
8371 		KFREES(softn->ipf_hm_maptable,
8372 		       softn->ipf_nat_hostmap_sz * sizeof(hostmap_t *));
8373 	}
8374 	softn->ipf_hm_maptable = newtab;
8375 	softn->ipf_nat_hostmap_sz = newsize;
8376 
8377 	for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next) {
8378 		hv = hm->hm_hv % softn->ipf_nat_hostmap_sz;
8379 		hm->hm_hnext = softn->ipf_hm_maptable[hv];
8380 		hm->hm_phnext = softn->ipf_hm_maptable + hv;
8381 		if (softn->ipf_hm_maptable[hv] != NULL)
8382 			softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
8383 		softn->ipf_hm_maptable[hv] = hm;
8384 	}
8385 	RWLOCK_EXIT(&softc->ipf_nat);
8386 
8387 	return 0;
8388 }
8389 
8390 
8391 /* ------------------------------------------------------------------------ */
8392 /* Function:    ipf_nat_add_tq                                              */
8393 /* Parameters:  softc(I) - pointer to soft context main structure           */
8394 /*                                                                          */
8395 /* ------------------------------------------------------------------------ */
8396 ipftq_t *
ipf_nat_add_tq(softc,ttl)8397 ipf_nat_add_tq(softc, ttl)
8398 	ipf_main_softc_t *softc;
8399 	int ttl;
8400 {
8401 	ipf_nat_softc_t *softs = softc->ipf_nat_soft;
8402 
8403 	return ipf_addtimeoutqueue(softc, &softs->ipf_nat_utqe, ttl);
8404 }
8405 
8406 /* ------------------------------------------------------------------------ */
8407 /* Function:    ipf_nat_uncreate                                            */
8408 /* Returns:     Nil                                                         */
8409 /* Parameters:  fin(I) - pointer to packet information                      */
8410 /*                                                                          */
8411 /* This function is used to remove a NAT entry from the NAT table when we   */
8412 /* decide that the create was actually in error. It is thus assumed that    */
8413 /* fin_flx will have both FI_NATED and FI_NATNEW set. Because we're dealing */
8414 /* with the translated packet (not the original), we have to reverse the    */
8415 /* lookup. Although doing the lookup is expensive (relatively speaking), it */
8416 /* is not anticipated that this will be a frequent occurance for normal     */
8417 /* traffic patterns.                                                        */
8418 /* ------------------------------------------------------------------------ */
8419 void
ipf_nat_uncreate(fin)8420 ipf_nat_uncreate(fin)
8421 	fr_info_t *fin;
8422 {
8423 	ipf_main_softc_t *softc = fin->fin_main_soft;
8424 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8425 	int nflags;
8426 	nat_t *nat;
8427 
8428 	switch (fin->fin_p)
8429 	{
8430 	case IPPROTO_TCP :
8431 		nflags = IPN_TCP;
8432 		break;
8433 	case IPPROTO_UDP :
8434 		nflags = IPN_UDP;
8435 		break;
8436 	default :
8437 		nflags = 0;
8438 		break;
8439 	}
8440 
8441 	WRITE_ENTER(&softc->ipf_nat);
8442 
8443 	if (fin->fin_out == 0) {
8444 		nat = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p,
8445 					fin->fin_dst, fin->fin_src);
8446 	} else {
8447 		nat = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p,
8448 				       fin->fin_src, fin->fin_dst);
8449 	}
8450 
8451 	if (nat != NULL) {
8452 		NBUMPSIDE(fin->fin_out, ns_uncreate[0]);
8453 		ipf_nat_delete(softc, nat, NL_DESTROY);
8454 	} else {
8455 		NBUMPSIDE(fin->fin_out, ns_uncreate[1]);
8456 	}
8457 
8458 	RWLOCK_EXIT(&softc->ipf_nat);
8459 }
8460 
8461 
8462 /* ------------------------------------------------------------------------ */
8463 /* Function:    ipf_nat_cmp_rules                                           */
8464 /* Returns:     int   - 0 == success, else rules do not match.              */
8465 /* Parameters:  n1(I) - first rule to compare                               */
8466 /*              n2(I) - first rule to compare                               */
8467 /*                                                                          */
8468 /* Compare two rules using pointers to each rule. A straight bcmp will not  */
8469 /* work as some fields (such as in_dst, in_pkts) actually do change once    */
8470 /* the rule has been loaded into the kernel. Whilst this function returns   */
8471 /* various non-zero returns, they're strictly to aid in debugging. Use of   */
8472 /* this function should simply care if the result is zero or not.           */
8473 /* ------------------------------------------------------------------------ */
8474 static int
ipf_nat_cmp_rules(n1,n2)8475 ipf_nat_cmp_rules(n1, n2)
8476 	ipnat_t *n1, *n2;
8477 {
8478 	if (n1->in_size != n2->in_size)
8479 		return 1;
8480 
8481 	if (bcmp((char *)&n1->in_v, (char *)&n2->in_v,
8482 		 offsetof(ipnat_t, in_ndst) - offsetof(ipnat_t, in_v)) != 0)
8483 		return 2;
8484 
8485 	if (bcmp((char *)&n1->in_tuc, (char *)&n2->in_tuc,
8486 		 n1->in_size - offsetof(ipnat_t, in_tuc)) != 0)
8487 		return 3;
8488 	if (n1->in_ndst.na_atype != n2->in_ndst.na_atype)
8489 		return 5;
8490 	if (n1->in_ndst.na_function != n2->in_ndst.na_function)
8491 		return 6;
8492 	if (bcmp((char *)&n1->in_ndst.na_addr, (char *)&n2->in_ndst.na_addr,
8493 		 sizeof(n1->in_ndst.na_addr)))
8494 		return 7;
8495 	if (n1->in_nsrc.na_atype != n2->in_nsrc.na_atype)
8496 		return 8;
8497 	if (n1->in_nsrc.na_function != n2->in_nsrc.na_function)
8498 		return 9;
8499 	if (bcmp((char *)&n1->in_nsrc.na_addr, (char *)&n2->in_nsrc.na_addr,
8500 		 sizeof(n1->in_nsrc.na_addr)))
8501 		return 10;
8502 	if (n1->in_odst.na_atype != n2->in_odst.na_atype)
8503 		return 11;
8504 	if (n1->in_odst.na_function != n2->in_odst.na_function)
8505 		return 12;
8506 	if (bcmp((char *)&n1->in_odst.na_addr, (char *)&n2->in_odst.na_addr,
8507 		 sizeof(n1->in_odst.na_addr)))
8508 		return 13;
8509 	if (n1->in_osrc.na_atype != n2->in_osrc.na_atype)
8510 		return 14;
8511 	if (n1->in_osrc.na_function != n2->in_osrc.na_function)
8512 		return 15;
8513 	if (bcmp((char *)&n1->in_osrc.na_addr, (char *)&n2->in_osrc.na_addr,
8514 		 sizeof(n1->in_osrc.na_addr)))
8515 		return 16;
8516 	return 0;
8517 }
8518 
8519 
8520 /* ------------------------------------------------------------------------ */
8521 /* Function:    ipf_nat_rule_init                                           */
8522 /* Returns:     int   - 0 == success, else rules do not match.              */
8523 /* Parameters:  softc(I) - pointer to soft context main structure           */
8524 /*              softn(I) - pointer to NAT context structure                 */
8525 /*              n(I)     - first rule to compare                            */
8526 /*                                                                          */
8527 /* ------------------------------------------------------------------------ */
8528 static int
ipf_nat_rule_init(softc,softn,n)8529 ipf_nat_rule_init(softc, softn, n)
8530 	ipf_main_softc_t *softc;
8531 	ipf_nat_softc_t *softn;
8532 	ipnat_t *n;
8533 {
8534 	int error = 0;
8535 
8536 	if ((n->in_flags & IPN_SIPRANGE) != 0)
8537 		n->in_nsrcatype = FRI_RANGE;
8538 
8539 	if ((n->in_flags & IPN_DIPRANGE) != 0)
8540 		n->in_ndstatype = FRI_RANGE;
8541 
8542 	if ((n->in_flags & IPN_SPLIT) != 0)
8543 		n->in_ndstatype = FRI_SPLIT;
8544 
8545 	if ((n->in_redir & (NAT_MAP|NAT_REWRITE|NAT_DIVERTUDP)) != 0)
8546 		n->in_spnext = n->in_spmin;
8547 
8548 	if ((n->in_redir & (NAT_REWRITE|NAT_DIVERTUDP)) != 0) {
8549 		n->in_dpnext = n->in_dpmin;
8550 	} else if (n->in_redir == NAT_REDIRECT) {
8551 		n->in_dpnext = n->in_dpmin;
8552 	}
8553 
8554 	n->in_stepnext = 0;
8555 
8556 	switch (n->in_v[0])
8557 	{
8558 	case 4 :
8559 		error = ipf_nat_ruleaddrinit(softc, softn, n);
8560 		if (error != 0)
8561 			return error;
8562 		break;
8563 #ifdef USE_INET6
8564 	case 6 :
8565 		error = ipf_nat6_ruleaddrinit(softc, softn, n);
8566 		if (error != 0)
8567 			return error;
8568 		break;
8569 #endif
8570 	default :
8571 		break;
8572 	}
8573 
8574 	if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) {
8575 		/*
8576 		 * Prerecord whether or not the destination of the divert
8577 		 * is local or not to the interface the packet is going
8578 		 * to be sent out.
8579 		 */
8580 		n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1],
8581 						n->in_ifps[1], &n->in_ndstip6);
8582 	}
8583 
8584 	return error;
8585 }
8586 
8587 
8588 /* ------------------------------------------------------------------------ */
8589 /* Function:    ipf_nat_rule_fini                                           */
8590 /* Returns:     int   - 0 == success, else rules do not match.              */
8591 /* Parameters:  softc(I) - pointer to soft context main structure           */
8592 /*              n(I)     - rule to work on                                  */
8593 /*                                                                          */
8594 /* This function is used to release any objects that were referenced during */
8595 /* the rule initialisation. This is useful both when free'ing the rule and  */
8596 /* when handling ioctls that need to initialise these fields but not        */
8597 /* actually use them after the ioctl processing has finished.               */
8598 /* ------------------------------------------------------------------------ */
8599 static void
ipf_nat_rule_fini(softc,n)8600 ipf_nat_rule_fini(softc, n)
8601 	ipf_main_softc_t *softc;
8602 	ipnat_t *n;
8603 {
8604 	if (n->in_odst.na_atype == FRI_LOOKUP && n->in_odst.na_ptr != NULL)
8605 		ipf_lookup_deref(softc, n->in_odst.na_type, n->in_odst.na_ptr);
8606 
8607 	if (n->in_osrc.na_atype == FRI_LOOKUP && n->in_osrc.na_ptr != NULL)
8608 		ipf_lookup_deref(softc, n->in_osrc.na_type, n->in_osrc.na_ptr);
8609 
8610 	if (n->in_ndst.na_atype == FRI_LOOKUP && n->in_ndst.na_ptr != NULL)
8611 		ipf_lookup_deref(softc, n->in_ndst.na_type, n->in_ndst.na_ptr);
8612 
8613 	if (n->in_nsrc.na_atype == FRI_LOOKUP && n->in_nsrc.na_ptr != NULL)
8614 		ipf_lookup_deref(softc, n->in_nsrc.na_type, n->in_nsrc.na_ptr);
8615 
8616 	if (n->in_divmp != NULL)
8617 		FREE_MB_T(n->in_divmp);
8618 }
8619