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