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