1/*	$FreeBSD: stable/11/sys/contrib/ipfilter/netinet/ip_nat.c 369541 2021-04-01 13:29:16Z git2svn $	*/
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__)
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__)
59# include <sys/queue.h>
60#endif
61#include <net/if.h>
62#if defined(__FreeBSD__)
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__)
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 369541 2021-04-01 13:29:16Z git2svn $";
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(ipf_main_softc_t *, void *);
208static	int	ipf_nat_getent(ipf_main_softc_t *, caddr_t, int);
209static	int	ipf_nat_getsz(ipf_main_softc_t *, caddr_t, int);
210static	int	ipf_nat_putent(ipf_main_softc_t *, caddr_t, int);
211static	void	ipf_nat_addmap(ipf_nat_softc_t *, ipnat_t *);
212static	void	ipf_nat_addrdr(ipf_nat_softc_t *, ipnat_t *);
213static	int	ipf_nat_builddivertmp(ipf_nat_softc_t *, ipnat_t *);
214static	int	ipf_nat_clearlist(ipf_main_softc_t *, ipf_nat_softc_t *);
215static	int	ipf_nat_cmp_rules(ipnat_t *, ipnat_t *);
216static	int	ipf_nat_decap(fr_info_t *, nat_t *);
217static	void	ipf_nat_delrule(ipf_main_softc_t *, ipf_nat_softc_t *,
218				     ipnat_t *, int);
219static	int	ipf_nat_extraflush(ipf_main_softc_t *, ipf_nat_softc_t *, int);
220static	int	ipf_nat_finalise(fr_info_t *, nat_t *);
221static	int	ipf_nat_flushtable(ipf_main_softc_t *, ipf_nat_softc_t *);
222static	int	ipf_nat_getnext(ipf_main_softc_t *, ipftoken_t *,
223				     ipfgeniter_t *, ipfobj_t *);
224static	int	ipf_nat_gettable(ipf_main_softc_t *, ipf_nat_softc_t *,
225				      char *);
226static	hostmap_t *ipf_nat_hostmap(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(int);
230static	int	ipf_nat_iterator(ipf_main_softc_t *, ipftoken_t *,
231				      ipfgeniter_t *, ipfobj_t *);
232static	int	ipf_nat_match(fr_info_t *, ipnat_t *);
233static	int	ipf_nat_matcharray(nat_t *, int *, u_long);
234static	int	ipf_nat_matchflush(ipf_main_softc_t *, ipf_nat_softc_t *,
235					caddr_t);
236static	void	ipf_nat_mssclamp(tcphdr_t *, u_32_t, fr_info_t *,
237				      u_short *);
238static	int	ipf_nat_newmap(fr_info_t *, nat_t *, natinfo_t *);
239static	int	ipf_nat_newdivert(fr_info_t *, nat_t *, natinfo_t *);
240static	int	ipf_nat_newrdr(fr_info_t *, nat_t *, natinfo_t *);
241static	int	ipf_nat_newrewrite(fr_info_t *, nat_t *, natinfo_t *);
242static	int	ipf_nat_nextaddr(fr_info_t *, nat_addr_t *, u_32_t *,
243				      u_32_t *);
244static	int	ipf_nat_nextaddrinit(ipf_main_softc_t *, char *,
245					  nat_addr_t *, int, void *);
246static	int	ipf_nat_resolverule(ipf_main_softc_t *, ipnat_t *);
247static	int	ipf_nat_ruleaddrinit(ipf_main_softc_t *,
248					  ipf_nat_softc_t *, ipnat_t *);
249static	void	ipf_nat_rule_fini(ipf_main_softc_t *, ipnat_t *);
250static	int	ipf_nat_rule_init(ipf_main_softc_t *, ipf_nat_softc_t *,
251				       ipnat_t *);
252static	int	ipf_nat_siocaddnat(ipf_main_softc_t *, ipf_nat_softc_t *,
253					ipnat_t *, int);
254static	void	ipf_nat_siocdelnat(ipf_main_softc_t *, ipf_nat_softc_t *,
255					ipnat_t *, int);
256static	void	ipf_nat_tabmove(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 !SOLARIS && 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__)
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 function 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 to 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	int ret;
3410
3411	/*
3412	 * Try and return an error as early as possible, so calculate the hash
3413	 * entry numbers first and then proceed.
3414	 */
3415	if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
3416		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
3417			sp = nat->nat_osport;
3418			dp = nat->nat_odport;
3419		} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
3420			sp = 0;
3421			dp = nat->nat_oicmpid;
3422		} else {
3423			sp = 0;
3424			dp = 0;
3425		}
3426		hv0 = NAT_HASH_FN(nat->nat_osrcaddr, sp, 0xffffffff);
3427		hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0 + dp, 0xffffffff);
3428		/*
3429		 * TRACE nat_osrcaddr, nat_osport, nat_odstaddr,
3430		 * nat_odport, hv0
3431		 */
3432
3433		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
3434			sp = nat->nat_nsport;
3435			dp = nat->nat_ndport;
3436		} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
3437			sp = 0;
3438			dp = nat->nat_nicmpid;
3439		} else {
3440			sp = 0;
3441			dp = 0;
3442		}
3443		hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, sp, 0xffffffff);
3444		hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1 + dp, 0xffffffff);
3445		/*
3446		 * TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr,
3447		 * nat_ndport, hv1
3448		 */
3449	} else {
3450		hv0 = NAT_HASH_FN(nat->nat_osrcaddr, 0, 0xffffffff);
3451		hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0, 0xffffffff);
3452		/* TRACE nat_osrcaddr, nat_odstaddr, hv0 */
3453
3454		hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, 0, 0xffffffff);
3455		hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1, 0xffffffff);
3456		/* TRACE nat_nsrcaddr, nat_ndstaddr, hv1 */
3457	}
3458
3459	nat->nat_hv[0] = hv0;
3460	nat->nat_hv[1] = hv1;
3461
3462	MUTEX_INIT(&nat->nat_lock, "nat entry lock");
3463
3464	in = nat->nat_ptr;
3465	nat->nat_ref = nat->nat_me ? 2 : 1;
3466
3467	nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
3468	nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0], 4);
3469
3470	if (nat->nat_ifnames[1][0] != '\0') {
3471		nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
3472		nat->nat_ifps[1] = ipf_resolvenic(softc,
3473						  nat->nat_ifnames[1], 4);
3474	} else if (in->in_ifnames[1] != -1) {
3475		char *name;
3476
3477		name = in->in_names + in->in_ifnames[1];
3478		if (name[1] != '\0' && name[0] != '-' && name[0] != '*') {
3479			(void) strncpy(nat->nat_ifnames[1],
3480				       nat->nat_ifnames[0], LIFNAMSIZ);
3481			nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
3482			nat->nat_ifps[1] = nat->nat_ifps[0];
3483		}
3484	}
3485	if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
3486		nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
3487	}
3488	if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
3489		nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
3490	}
3491
3492	ret = ipf_nat_hashtab_add(softc, softn, nat);
3493	if (ret == -1)
3494		MUTEX_DESTROY(&nat->nat_lock);
3495	return ret;
3496}
3497
3498
3499/* ------------------------------------------------------------------------ */
3500/* Function:    ipf_nat_hashtab_add                                         */
3501/* Returns:     int - 0 == sucess, -1 == failure                            */
3502/* Parameters:  softc(I) - pointer to soft context main structure           */
3503/*              softn(I) - pointer to NAT context structure                 */
3504/*              nat(I) - pointer to NAT structure                           */
3505/*                                                                          */
3506/* Handle the insertion of a NAT entry into the table/list.                 */
3507/* ------------------------------------------------------------------------ */
3508int
3509ipf_nat_hashtab_add(softc, softn, nat)
3510	ipf_main_softc_t *softc;
3511	ipf_nat_softc_t *softn;
3512	nat_t *nat;
3513{
3514	nat_t **natp;
3515	u_int hv0;
3516	u_int hv1;
3517
3518	hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz;
3519	hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz;
3520
3521	if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
3522		u_int swap;
3523
3524		swap = hv0;
3525		hv0 = hv1;
3526		hv1 = swap;
3527	}
3528
3529	if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0] >=
3530	    softn->ipf_nat_maxbucket) {
3531		DT1(ns_bucket_max_0, int,
3532		    softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]);
3533		NBUMPSIDE(0, ns_bucket_max);
3534		return -1;
3535	}
3536
3537	if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1] >=
3538	    softn->ipf_nat_maxbucket) {
3539		DT1(ns_bucket_max_1, int,
3540		    softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]);
3541		NBUMPSIDE(1, ns_bucket_max);
3542		return -1;
3543	}
3544
3545	/*
3546	 * The ordering of operations in the list and hash table insertion
3547	 * is very important.  The last operation for each task should be
3548	 * to update the top of the list, after all the "nexts" have been
3549	 * done so that walking the list while it is being done does not
3550	 * find strange pointers.
3551	 *
3552	 * Global list of NAT instances
3553	 */
3554	nat->nat_next = softn->ipf_nat_instances;
3555	nat->nat_pnext = &softn->ipf_nat_instances;
3556	if (softn->ipf_nat_instances)
3557		softn->ipf_nat_instances->nat_pnext = &nat->nat_next;
3558	softn->ipf_nat_instances = nat;
3559
3560	/*
3561	 * Inbound hash table.
3562	 */
3563	natp = &softn->ipf_nat_table[0][hv0];
3564	nat->nat_phnext[0] = natp;
3565	nat->nat_hnext[0] = *natp;
3566	if (*natp) {
3567		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
3568	} else {
3569		NBUMPSIDE(0, ns_inuse);
3570	}
3571	*natp = nat;
3572	NBUMPSIDE(0, ns_bucketlen[hv0]);
3573
3574	/*
3575	 * Outbound hash table.
3576	 */
3577	natp = &softn->ipf_nat_table[1][hv1];
3578	nat->nat_phnext[1] = natp;
3579	nat->nat_hnext[1] = *natp;
3580	if (*natp)
3581		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
3582	else {
3583		NBUMPSIDE(1, ns_inuse);
3584	}
3585	*natp = nat;
3586	NBUMPSIDE(1, ns_bucketlen[hv1]);
3587
3588	ipf_nat_setqueue(softc, softn, nat);
3589
3590	if (nat->nat_dir & NAT_OUTBOUND) {
3591		NBUMPSIDE(1, ns_added);
3592	} else {
3593		NBUMPSIDE(0, ns_added);
3594	}
3595	softn->ipf_nat_stats.ns_active++;
3596	return 0;
3597}
3598
3599
3600/* ------------------------------------------------------------------------ */
3601/* Function:    ipf_nat_icmperrorlookup                                     */
3602/* Returns:     nat_t* - point to matching NAT structure                    */
3603/* Parameters:  fin(I) - pointer to packet information                      */
3604/*              dir(I) - direction of packet (in/out)                       */
3605/*                                                                          */
3606/* Check if the ICMP error message is related to an existing TCP, UDP or    */
3607/* ICMP query nat entry.  It is assumed that the packet is already of the   */
3608/* the required length.                                                     */
3609/* ------------------------------------------------------------------------ */
3610nat_t *
3611ipf_nat_icmperrorlookup(fin, dir)
3612	fr_info_t *fin;
3613	int dir;
3614{
3615	ipf_main_softc_t *softc = fin->fin_main_soft;
3616	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3617	int flags = 0, type, minlen;
3618	icmphdr_t *icmp, *orgicmp;
3619	nat_stat_side_t *nside;
3620	tcphdr_t *tcp = NULL;
3621	u_short data[2];
3622	nat_t *nat;
3623	ip_t *oip;
3624	u_int p;
3625
3626	icmp = fin->fin_dp;
3627	type = icmp->icmp_type;
3628	nside = &softn->ipf_nat_stats.ns_side[fin->fin_out];
3629	/*
3630	 * Does it at least have the return (basic) IP header ?
3631	 * Only a basic IP header (no options) should be with an ICMP error
3632	 * header.  Also, if it's not an error type, then return.
3633	 */
3634	if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) {
3635		ATOMIC_INCL(nside->ns_icmp_basic);
3636		return NULL;
3637	}
3638
3639	/*
3640	 * Check packet size
3641	 */
3642	oip = (ip_t *)((char *)fin->fin_dp + 8);
3643	minlen = IP_HL(oip) << 2;
3644	if ((minlen < sizeof(ip_t)) ||
3645	    (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) {
3646		ATOMIC_INCL(nside->ns_icmp_size);
3647		return NULL;
3648	}
3649
3650	/*
3651	 * Is the buffer big enough for all of it ?  It's the size of the IP
3652	 * header claimed in the encapsulated part which is of concern.  It
3653	 * may be too big to be in this buffer but not so big that it's
3654	 * outside the ICMP packet, leading to TCP deref's causing problems.
3655	 * This is possible because we don't know how big oip_hl is when we
3656	 * do the pullup early in ipf_check() and thus can't gaurantee it is
3657	 * all here now.
3658	 */
3659#ifdef  ipf_nat_KERNEL
3660	{
3661	mb_t *m;
3662
3663	m = fin->fin_m;
3664# if SOLARIS
3665	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
3666	    (char *)m->b_wptr) {
3667		ATOMIC_INCL(nside->ns_icmp_mbuf);
3668		return NULL;
3669	}
3670# else
3671	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
3672	    (char *)fin->fin_ip + M_LEN(m)) {
3673		ATOMIC_INCL(nside->ns_icmp_mbuf);
3674		return NULL;
3675	}
3676# endif
3677	}
3678#endif
3679
3680	if (fin->fin_daddr != oip->ip_src.s_addr) {
3681		ATOMIC_INCL(nside->ns_icmp_address);
3682		return NULL;
3683	}
3684
3685	p = oip->ip_p;
3686	if (p == IPPROTO_TCP)
3687		flags = IPN_TCP;
3688	else if (p == IPPROTO_UDP)
3689		flags = IPN_UDP;
3690	else if (p == IPPROTO_ICMP) {
3691		orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2));
3692
3693		/* see if this is related to an ICMP query */
3694		if (ipf_nat_icmpquerytype(orgicmp->icmp_type)) {
3695			data[0] = fin->fin_data[0];
3696			data[1] = fin->fin_data[1];
3697			fin->fin_data[0] = 0;
3698			fin->fin_data[1] = orgicmp->icmp_id;
3699
3700			flags = IPN_ICMPERR|IPN_ICMPQUERY;
3701			/*
3702			 * NOTE : dir refers to the direction of the original
3703			 *        ip packet. By definition the icmp error
3704			 *        message flows in the opposite direction.
3705			 */
3706			if (dir == NAT_INBOUND)
3707				nat = ipf_nat_inlookup(fin, flags, p,
3708						       oip->ip_dst,
3709						       oip->ip_src);
3710			else
3711				nat = ipf_nat_outlookup(fin, flags, p,
3712							oip->ip_dst,
3713							oip->ip_src);
3714			fin->fin_data[0] = data[0];
3715			fin->fin_data[1] = data[1];
3716			return nat;
3717		}
3718	}
3719
3720	if (flags & IPN_TCPUDP) {
3721		minlen += 8;		/* + 64bits of data to get ports */
3722		/* TRACE (fin,minlen) */
3723		if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) {
3724			ATOMIC_INCL(nside->ns_icmp_short);
3725			return NULL;
3726		}
3727
3728		data[0] = fin->fin_data[0];
3729		data[1] = fin->fin_data[1];
3730		tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2));
3731		fin->fin_data[0] = ntohs(tcp->th_dport);
3732		fin->fin_data[1] = ntohs(tcp->th_sport);
3733
3734		if (dir == NAT_INBOUND) {
3735			nat = ipf_nat_inlookup(fin, flags, p, oip->ip_dst,
3736					       oip->ip_src);
3737		} else {
3738			nat = ipf_nat_outlookup(fin, flags, p, oip->ip_dst,
3739					    oip->ip_src);
3740		}
3741		fin->fin_data[0] = data[0];
3742		fin->fin_data[1] = data[1];
3743		return nat;
3744	}
3745	if (dir == NAT_INBOUND)
3746		nat = ipf_nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
3747	else
3748		nat = ipf_nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
3749
3750	return nat;
3751}
3752
3753
3754/* ------------------------------------------------------------------------ */
3755/* Function:    ipf_nat_icmperror                                           */
3756/* Returns:     nat_t* - point to matching NAT structure                    */
3757/* Parameters:  fin(I)    - pointer to packet information                   */
3758/*              nflags(I) - NAT flags for this packet                       */
3759/*              dir(I)    - direction of packet (in/out)                    */
3760/*                                                                          */
3761/* Fix up an ICMP packet which is an error message for an existing NAT      */
3762/* session.  This will correct both packet header data and checksums.       */
3763/*                                                                          */
3764/* This should *ONLY* be used for incoming ICMP error packets to make sure  */
3765/* a NAT'd ICMP packet gets correctly recognised.                           */
3766/* ------------------------------------------------------------------------ */
3767nat_t *
3768ipf_nat_icmperror(fin, nflags, dir)
3769	fr_info_t *fin;
3770	u_int *nflags;
3771	int dir;
3772{
3773	ipf_main_softc_t *softc = fin->fin_main_soft;
3774	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3775	u_32_t sum1, sum2, sumd, sumd2;
3776	struct in_addr a1, a2, a3, a4;
3777	int flags, dlen, odst;
3778	icmphdr_t *icmp;
3779	u_short *csump;
3780	tcphdr_t *tcp;
3781	nat_t *nat;
3782	ip_t *oip;
3783	void *dp;
3784
3785	if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
3786		NBUMPSIDED(fin->fin_out, ns_icmp_short);
3787		return NULL;
3788	}
3789
3790	/*
3791	 * ipf_nat_icmperrorlookup() will return NULL for `defective' packets.
3792	 */
3793	if ((fin->fin_v != 4) || !(nat = ipf_nat_icmperrorlookup(fin, dir))) {
3794		NBUMPSIDED(fin->fin_out, ns_icmp_notfound);
3795		return NULL;
3796	}
3797
3798	tcp = NULL;
3799	csump = NULL;
3800	flags = 0;
3801	sumd2 = 0;
3802	*nflags = IPN_ICMPERR;
3803	icmp = fin->fin_dp;
3804	oip = (ip_t *)&icmp->icmp_ip;
3805	dp = (((char *)oip) + (IP_HL(oip) << 2));
3806	if (oip->ip_p == IPPROTO_TCP) {
3807		tcp = (tcphdr_t *)dp;
3808		csump = (u_short *)&tcp->th_sum;
3809		flags = IPN_TCP;
3810	} else if (oip->ip_p == IPPROTO_UDP) {
3811		udphdr_t *udp;
3812
3813		udp = (udphdr_t *)dp;
3814		tcp = (tcphdr_t *)dp;
3815		csump = (u_short *)&udp->uh_sum;
3816		flags = IPN_UDP;
3817	} else if (oip->ip_p == IPPROTO_ICMP)
3818		flags = IPN_ICMPQUERY;
3819	dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip);
3820
3821	/*
3822	 * Need to adjust ICMP header to include the real IP#'s and
3823	 * port #'s.  Only apply a checksum change relative to the
3824	 * IP address change as it will be modified again in ipf_nat_checkout
3825	 * for both address and port.  Two checksum changes are
3826	 * necessary for the two header address changes.  Be careful
3827	 * to only modify the checksum once for the port # and twice
3828	 * for the IP#.
3829	 */
3830
3831	/*
3832	 * Step 1
3833	 * Fix the IP addresses in the offending IP packet. You also need
3834	 * to adjust the IP header checksum of that offending IP packet.
3835	 *
3836	 * Normally, you would expect that the ICMP checksum of the
3837	 * ICMP error message needs to be adjusted as well for the
3838	 * IP address change in oip.
3839	 * However, this is a NOP, because the ICMP checksum is
3840	 * calculated over the complete ICMP packet, which includes the
3841	 * changed oip IP addresses and oip->ip_sum. However, these
3842	 * two changes cancel each other out (if the delta for
3843	 * the IP address is x, then the delta for ip_sum is minus x),
3844	 * so no change in the icmp_cksum is necessary.
3845	 *
3846	 * Inbound ICMP
3847	 * ------------
3848	 * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
3849	 * - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b)
3850	 * - OIP_SRC(c)=nat_newsrcip,          OIP_DST(b)=nat_newdstip
3851	 *=> OIP_SRC(c)=nat_oldsrcip,          OIP_DST(b)=nat_olddstip
3852	 *
3853	 * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
3854	 * - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a)
3855	 * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
3856	 *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3857	 *
3858	 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
3859	 * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d)
3860	 * - OIP_SRC(c)=nat_newsrcip,          OIP_DST(d)=nat_newdstip
3861	 *=> OIP_SRC(c)=nat_oldsrcip,          OIP_DST(d)=nat_olddstip
3862	 *
3863	 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
3864	 * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
3865	 * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
3866	 *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3867	 *
3868	 * Outbound ICMP
3869	 * -------------
3870	 * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
3871	 * - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
3872	 * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
3873	 *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3874	 *
3875	 * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
3876	 * - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c)
3877	 * - OIP_SRC(a)=nat_newsrcip,          OIP_DST(c)=nat_newdstip
3878	 *=> OIP_SRC(a)=nat_oldsrcip,          OIP_DST(c)=nat_olddstip
3879	 *
3880	 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
3881	 * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d)
3882	 * - OIP_SRC(c)=nat_olddstip,          OIP_DST(d)=nat_oldsrcip
3883	 *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
3884	 *
3885	 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
3886	 * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a)
3887	 * - OIP_SRC(b)=nat_newsrcip,          OIP_DST(a)=nat_newdstip
3888	 *=> OIP_SRC(a)=nat_oldsrcip,          OIP_DST(c)=nat_olddstip
3889	 */
3890
3891	if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) ||
3892	    ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) {
3893		a1.s_addr = ntohl(nat->nat_osrcaddr);
3894		a4.s_addr = ntohl(oip->ip_src.s_addr);
3895		a3.s_addr = ntohl(nat->nat_odstaddr);
3896		a2.s_addr = ntohl(oip->ip_dst.s_addr);
3897		oip->ip_src.s_addr = htonl(a1.s_addr);
3898		oip->ip_dst.s_addr = htonl(a3.s_addr);
3899		odst = 1;
3900	} else {
3901		a1.s_addr = ntohl(nat->nat_ndstaddr);
3902		a2.s_addr = ntohl(oip->ip_dst.s_addr);
3903		a3.s_addr = ntohl(nat->nat_nsrcaddr);
3904		a4.s_addr = ntohl(oip->ip_src.s_addr);
3905		oip->ip_dst.s_addr = htonl(a3.s_addr);
3906		oip->ip_src.s_addr = htonl(a1.s_addr);
3907		odst = 0;
3908	}
3909	sum1 = 0;
3910	sum2 = 0;
3911	sumd = 0;
3912	CALC_SUMD(a2.s_addr, a3.s_addr, sum1);
3913	CALC_SUMD(a4.s_addr, a1.s_addr, sum2);
3914	sumd = sum2 + sum1;
3915	if (sumd != 0)
3916		ipf_fix_datacksum(&oip->ip_sum, sumd);
3917
3918	sumd2 = sumd;
3919	sum1 = 0;
3920	sum2 = 0;
3921
3922	/*
3923	 * Fix UDP pseudo header checksum to compensate for the
3924	 * IP address change.
3925	 */
3926	if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) {
3927		u_32_t sum3, sum4, sumt;
3928
3929		/*
3930		 * Step 2 :
3931		 * For offending TCP/UDP IP packets, translate the ports as
3932		 * well, based on the NAT specification. Of course such
3933		 * a change may be reflected in the ICMP checksum as well.
3934		 *
3935		 * Since the port fields are part of the TCP/UDP checksum
3936		 * of the offending IP packet, you need to adjust that checksum
3937		 * as well... except that the change in the port numbers should
3938		 * be offset by the checksum change.  However, the TCP/UDP
3939		 * checksum will also need to change if there has been an
3940		 * IP address change.
3941		 */
3942		if (odst == 1) {
3943			sum1 = ntohs(nat->nat_osport);
3944			sum4 = ntohs(tcp->th_sport);
3945			sum3 = ntohs(nat->nat_odport);
3946			sum2 = ntohs(tcp->th_dport);
3947
3948			tcp->th_sport = htons(sum1);
3949			tcp->th_dport = htons(sum3);
3950		} else {
3951			sum1 = ntohs(nat->nat_ndport);
3952			sum2 = ntohs(tcp->th_dport);
3953			sum3 = ntohs(nat->nat_nsport);
3954			sum4 = ntohs(tcp->th_sport);
3955
3956			tcp->th_dport = htons(sum3);
3957			tcp->th_sport = htons(sum1);
3958		}
3959		CALC_SUMD(sum4, sum1, sumt);
3960		sumd += sumt;
3961		CALC_SUMD(sum2, sum3, sumt);
3962		sumd += sumt;
3963
3964		if (sumd != 0 || sumd2 != 0) {
3965			/*
3966			 * At this point, sumd is the delta to apply to the
3967			 * TCP/UDP header, given the changes in both the IP
3968			 * address and the ports and sumd2 is the delta to
3969			 * apply to the ICMP header, given the IP address
3970			 * change delta that may need to be applied to the
3971			 * TCP/UDP checksum instead.
3972			 *
3973			 * If we will both the IP and TCP/UDP checksums
3974			 * then the ICMP checksum changes by the address
3975			 * delta applied to the TCP/UDP checksum.  If we
3976			 * do not change the TCP/UDP checksum them we
3977			 * apply the delta in ports to the ICMP checksum.
3978			 */
3979			if (oip->ip_p == IPPROTO_UDP) {
3980				if ((dlen >= 8) && (*csump != 0)) {
3981					ipf_fix_datacksum(csump, sumd);
3982				} else {
3983					CALC_SUMD(sum1, sum4, sumd2);
3984					CALC_SUMD(sum3, sum2, sumt);
3985					sumd2 += sumt;
3986				}
3987			} else if (oip->ip_p == IPPROTO_TCP) {
3988				if (dlen >= 18) {
3989					ipf_fix_datacksum(csump, sumd);
3990				} else {
3991					CALC_SUMD(sum1, sum4, sumd2);
3992					CALC_SUMD(sum3, sum2, sumt);
3993					sumd2 += sumt;
3994				}
3995			}
3996			if (sumd2 != 0) {
3997				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
3998				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
3999				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
4000				ipf_fix_incksum(0, &icmp->icmp_cksum, sumd2, 0);
4001			}
4002		}
4003	} else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) {
4004		icmphdr_t *orgicmp;
4005
4006		/*
4007		 * XXX - what if this is bogus hl and we go off the end ?
4008		 * In this case, ipf_nat_icmperrorlookup() will have
4009		 * returned NULL.
4010		 */
4011		orgicmp = (icmphdr_t *)dp;
4012
4013		if (odst == 1) {
4014			if (orgicmp->icmp_id != nat->nat_osport) {
4015
4016				/*
4017				 * Fix ICMP checksum (of the offening ICMP
4018				 * query packet) to compensate the change
4019				 * in the ICMP id of the offending ICMP
4020				 * packet.
4021				 *
4022				 * Since you modify orgicmp->icmp_id with
4023				 * a delta (say x) and you compensate that
4024				 * in origicmp->icmp_cksum with a delta
4025				 * minus x, you don't have to adjust the
4026				 * overall icmp->icmp_cksum
4027				 */
4028				sum1 = ntohs(orgicmp->icmp_id);
4029				sum2 = ntohs(nat->nat_oicmpid);
4030				CALC_SUMD(sum1, sum2, sumd);
4031				orgicmp->icmp_id = nat->nat_oicmpid;
4032				ipf_fix_datacksum(&orgicmp->icmp_cksum, sumd);
4033			}
4034		} /* nat_dir == NAT_INBOUND is impossible for icmp queries */
4035	}
4036	return nat;
4037}
4038
4039
4040/*
4041 *       MAP-IN    MAP-OUT   RDR-IN   RDR-OUT
4042 * osrc    X       == src    == src      X
4043 * odst    X       == dst    == dst      X
4044 * nsrc  == dst      X         X      == dst
4045 * ndst  == src      X         X      == src
4046 * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND
4047 */
4048/*
4049 * NB: these lookups don't lock access to the list, it assumed that it has
4050 * already been done!
4051 */
4052/* ------------------------------------------------------------------------ */
4053/* Function:    ipf_nat_inlookup                                            */
4054/* Returns:     nat_t* - NULL == no match,                                  */
4055/*                       else pointer to matching NAT entry                 */
4056/* Parameters:  fin(I)    - pointer to packet information                   */
4057/*              flags(I)  - NAT flags for this packet                       */
4058/*              p(I)      - protocol for this packet                        */
4059/*              src(I)    - source IP address                               */
4060/*              mapdst(I) - destination IP address                          */
4061/*                                                                          */
4062/* Lookup a nat entry based on the mapped destination ip address/port and   */
4063/* real source address/port.  We use this lookup when receiving a packet,   */
4064/* we're looking for a table entry, based on the destination address.       */
4065/*                                                                          */
4066/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
4067/*                                                                          */
4068/* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
4069/*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
4070/*                                                                          */
4071/* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
4072/*            the packet is of said protocol                                */
4073/* ------------------------------------------------------------------------ */
4074nat_t *
4075ipf_nat_inlookup(fin, flags, p, src, mapdst)
4076	fr_info_t *fin;
4077	u_int flags, p;
4078	struct in_addr src , mapdst;
4079{
4080	ipf_main_softc_t *softc = fin->fin_main_soft;
4081	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4082	u_short sport, dport;
4083	grehdr_t *gre;
4084	ipnat_t *ipn;
4085	u_int sflags;
4086	nat_t *nat;
4087	int nflags;
4088	u_32_t dst;
4089	void *ifp;
4090	u_int hv, rhv;
4091
4092	ifp = fin->fin_ifp;
4093	gre = NULL;
4094	dst = mapdst.s_addr;
4095	sflags = flags & NAT_TCPUDPICMP;
4096
4097	switch (p)
4098	{
4099	case IPPROTO_TCP :
4100	case IPPROTO_UDP :
4101		sport = htons(fin->fin_data[0]);
4102		dport = htons(fin->fin_data[1]);
4103		break;
4104	case IPPROTO_ICMP :
4105		sport = 0;
4106		dport = fin->fin_data[1];
4107		break;
4108	default :
4109		sport = 0;
4110		dport = 0;
4111		break;
4112	}
4113
4114
4115	if ((flags & SI_WILDP) != 0)
4116		goto find_in_wild_ports;
4117
4118	rhv = NAT_HASH_FN(dst, dport, 0xffffffff);
4119	rhv = NAT_HASH_FN(src.s_addr, rhv + sport, 0xffffffff);
4120	hv = rhv % softn->ipf_nat_table_sz;
4121	nat = softn->ipf_nat_table[1][hv];
4122	/* TRACE dst, dport, src, sport, hv, nat */
4123
4124	for (; nat; nat = nat->nat_hnext[1]) {
4125		if (nat->nat_ifps[0] != NULL) {
4126			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
4127				continue;
4128		}
4129
4130		if (nat->nat_pr[0] != p)
4131			continue;
4132
4133		switch (nat->nat_dir)
4134		{
4135		case NAT_INBOUND :
4136		case NAT_DIVERTIN :
4137			if (nat->nat_v[0] != 4)
4138				continue;
4139			if (nat->nat_osrcaddr != src.s_addr ||
4140			    nat->nat_odstaddr != dst)
4141				continue;
4142			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4143				if (nat->nat_osport != sport)
4144					continue;
4145				if (nat->nat_odport != dport)
4146					continue;
4147
4148			} else if (p == IPPROTO_ICMP) {
4149				if (nat->nat_osport != dport) {
4150					continue;
4151				}
4152			}
4153			break;
4154		case NAT_DIVERTOUT :
4155			if (nat->nat_dlocal)
4156				continue;
4157		case NAT_OUTBOUND :
4158			if (nat->nat_v[1] != 4)
4159				continue;
4160			if (nat->nat_dlocal)
4161				continue;
4162			if (nat->nat_dlocal)
4163				continue;
4164			if (nat->nat_ndstaddr != src.s_addr ||
4165			    nat->nat_nsrcaddr != dst)
4166				continue;
4167			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4168				if (nat->nat_ndport != sport)
4169					continue;
4170				if (nat->nat_nsport != dport)
4171					continue;
4172
4173			} else if (p == IPPROTO_ICMP) {
4174				if (nat->nat_osport != dport) {
4175					continue;
4176				}
4177			}
4178			break;
4179		}
4180
4181
4182		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4183			ipn = nat->nat_ptr;
4184			if ((ipn != NULL) && (nat->nat_aps != NULL))
4185				if (ipf_proxy_match(fin, nat) != 0)
4186					continue;
4187		}
4188		if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
4189			nat->nat_ifps[0] = ifp;
4190			nat->nat_mtu[0] = GETIFMTU_4(ifp);
4191		}
4192		return nat;
4193	}
4194
4195	/*
4196	 * So if we didn't find it but there are wildcard members in the hash
4197	 * table, go back and look for them.  We do this search and update here
4198	 * because it is modifying the NAT table and we want to do this only
4199	 * for the first packet that matches.  The exception, of course, is
4200	 * for "dummy" (FI_IGNORE) lookups.
4201	 */
4202find_in_wild_ports:
4203	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
4204		NBUMPSIDEX(0, ns_lookup_miss, ns_lookup_miss_0);
4205		return NULL;
4206	}
4207	if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
4208		NBUMPSIDEX(0, ns_lookup_nowild, ns_lookup_nowild_0);
4209		return NULL;
4210	}
4211
4212	RWLOCK_EXIT(&softc->ipf_nat);
4213
4214	hv = NAT_HASH_FN(dst, 0, 0xffffffff);
4215	hv = NAT_HASH_FN(src.s_addr, hv, softn->ipf_nat_table_sz);
4216	WRITE_ENTER(&softc->ipf_nat);
4217
4218	nat = softn->ipf_nat_table[1][hv];
4219	/* TRACE dst, src, hv, nat */
4220	for (; nat; nat = nat->nat_hnext[1]) {
4221		if (nat->nat_ifps[0] != NULL) {
4222			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
4223				continue;
4224		}
4225
4226		if (nat->nat_pr[0] != fin->fin_p)
4227			continue;
4228
4229		switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
4230		{
4231		case NAT_INBOUND :
4232			if (nat->nat_v[0] != 4)
4233				continue;
4234			if (nat->nat_osrcaddr != src.s_addr ||
4235			    nat->nat_odstaddr != dst)
4236				continue;
4237			break;
4238		case NAT_OUTBOUND :
4239			if (nat->nat_v[1] != 4)
4240				continue;
4241			if (nat->nat_ndstaddr != src.s_addr ||
4242			    nat->nat_nsrcaddr != dst)
4243				continue;
4244			break;
4245		}
4246
4247		nflags = nat->nat_flags;
4248		if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
4249			continue;
4250
4251		if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags,
4252				   NAT_INBOUND) == 1) {
4253			if ((fin->fin_flx & FI_IGNORE) != 0)
4254				break;
4255			if ((nflags & SI_CLONE) != 0) {
4256				nat = ipf_nat_clone(fin, nat);
4257				if (nat == NULL)
4258					break;
4259			} else {
4260				MUTEX_ENTER(&softn->ipf_nat_new);
4261				softn->ipf_nat_stats.ns_wilds--;
4262				MUTEX_EXIT(&softn->ipf_nat_new);
4263			}
4264
4265			if (nat->nat_dir == NAT_INBOUND) {
4266				if (nat->nat_osport == 0) {
4267					nat->nat_osport = sport;
4268					nat->nat_nsport = sport;
4269				}
4270				if (nat->nat_odport == 0) {
4271					nat->nat_odport = dport;
4272					nat->nat_ndport = dport;
4273				}
4274			} else if (nat->nat_dir == NAT_OUTBOUND) {
4275				if (nat->nat_osport == 0) {
4276					nat->nat_osport = dport;
4277					nat->nat_nsport = dport;
4278				}
4279				if (nat->nat_odport == 0) {
4280					nat->nat_odport = sport;
4281					nat->nat_ndport = sport;
4282				}
4283			}
4284			if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
4285				nat->nat_ifps[0] = ifp;
4286				nat->nat_mtu[0] = GETIFMTU_4(ifp);
4287			}
4288			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
4289			ipf_nat_tabmove(softn, nat);
4290			break;
4291		}
4292	}
4293
4294	MUTEX_DOWNGRADE(&softc->ipf_nat);
4295
4296	if (nat == NULL) {
4297		NBUMPSIDE(0, ns_lookup_miss);
4298	}
4299	return nat;
4300}
4301
4302
4303/* ------------------------------------------------------------------------ */
4304/* Function:    ipf_nat_tabmove                                             */
4305/* Returns:     Nil                                                         */
4306/* Parameters:  softn(I) - pointer to NAT context structure                 */
4307/*              nat(I)   - pointer to NAT structure                         */
4308/* Write Lock:  ipf_nat                                                     */
4309/*                                                                          */
4310/* This function is only called for TCP/UDP NAT table entries where the     */
4311/* original was placed in the table without hashing on the ports and we now */
4312/* want to include hashing on port numbers.                                 */
4313/* ------------------------------------------------------------------------ */
4314static void
4315ipf_nat_tabmove(softn, nat)
4316	ipf_nat_softc_t *softn;
4317	nat_t *nat;
4318{
4319	u_int hv0, hv1, rhv0, rhv1;
4320	natstat_t *nsp;
4321	nat_t **natp;
4322
4323	if (nat->nat_flags & SI_CLONE)
4324		return;
4325
4326	nsp = &softn->ipf_nat_stats;
4327	/*
4328	 * Remove the NAT entry from the old location
4329	 */
4330	if (nat->nat_hnext[0])
4331		nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
4332	*nat->nat_phnext[0] = nat->nat_hnext[0];
4333	nsp->ns_side[0].ns_bucketlen[nat->nat_hv[0] %
4334				     softn->ipf_nat_table_sz]--;
4335
4336	if (nat->nat_hnext[1])
4337		nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
4338	*nat->nat_phnext[1] = nat->nat_hnext[1];
4339	nsp->ns_side[1].ns_bucketlen[nat->nat_hv[1] %
4340				     softn->ipf_nat_table_sz]--;
4341
4342	/*
4343	 * Add into the NAT table in the new position
4344	 */
4345	rhv0 = NAT_HASH_FN(nat->nat_osrcaddr, nat->nat_osport, 0xffffffff);
4346	rhv0 = NAT_HASH_FN(nat->nat_odstaddr, rhv0 + nat->nat_odport,
4347			   0xffffffff);
4348	rhv1 = NAT_HASH_FN(nat->nat_nsrcaddr, nat->nat_nsport, 0xffffffff);
4349	rhv1 = NAT_HASH_FN(nat->nat_ndstaddr, rhv1 + nat->nat_ndport,
4350			   0xffffffff);
4351
4352	hv0 = rhv0 % softn->ipf_nat_table_sz;
4353	hv1 = rhv1 % softn->ipf_nat_table_sz;
4354
4355	if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
4356		u_int swap;
4357
4358		swap = hv0;
4359		hv0 = hv1;
4360		hv1 = swap;
4361	}
4362
4363	/* TRACE nat_osrcaddr, nat_osport, nat_odstaddr, nat_odport, hv0 */
4364	/* TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr, nat_ndport, hv1 */
4365
4366	nat->nat_hv[0] = rhv0;
4367	natp = &softn->ipf_nat_table[0][hv0];
4368	if (*natp)
4369		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
4370	nat->nat_phnext[0] = natp;
4371	nat->nat_hnext[0] = *natp;
4372	*natp = nat;
4373	nsp->ns_side[0].ns_bucketlen[hv0]++;
4374
4375	nat->nat_hv[1] = rhv1;
4376	natp = &softn->ipf_nat_table[1][hv1];
4377	if (*natp)
4378		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
4379	nat->nat_phnext[1] = natp;
4380	nat->nat_hnext[1] = *natp;
4381	*natp = nat;
4382	nsp->ns_side[1].ns_bucketlen[hv1]++;
4383}
4384
4385
4386/* ------------------------------------------------------------------------ */
4387/* Function:    ipf_nat_outlookup                                           */
4388/* Returns:     nat_t* - NULL == no match,                                  */
4389/*                       else pointer to matching NAT entry                 */
4390/* Parameters:  fin(I)   - pointer to packet information                    */
4391/*              flags(I) - NAT flags for this packet                        */
4392/*              p(I)     - protocol for this packet                         */
4393/*              src(I)   - source IP address                                */
4394/*              dst(I)   - destination IP address                           */
4395/*              rw(I)    - 1 == write lock on  held, 0 == read lock.        */
4396/*                                                                          */
4397/* Lookup a nat entry based on the source 'real' ip address/port and        */
4398/* destination address/port.  We use this lookup when sending a packet out, */
4399/* we're looking for a table entry, based on the source address.            */
4400/*                                                                          */
4401/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
4402/*                                                                          */
4403/* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
4404/*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
4405/*                                                                          */
4406/* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
4407/*            the packet is of said protocol                                */
4408/* ------------------------------------------------------------------------ */
4409nat_t *
4410ipf_nat_outlookup(fin, flags, p, src, dst)
4411	fr_info_t *fin;
4412	u_int flags, p;
4413	struct in_addr src , dst;
4414{
4415	ipf_main_softc_t *softc = fin->fin_main_soft;
4416	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4417	u_short sport, dport;
4418	u_int sflags;
4419	ipnat_t *ipn;
4420	nat_t *nat;
4421	void *ifp;
4422	u_int hv;
4423
4424	ifp = fin->fin_ifp;
4425	sflags = flags & IPN_TCPUDPICMP;
4426
4427	switch (p)
4428	{
4429	case IPPROTO_TCP :
4430	case IPPROTO_UDP :
4431		sport = htons(fin->fin_data[0]);
4432		dport = htons(fin->fin_data[1]);
4433		break;
4434	case IPPROTO_ICMP :
4435		sport = 0;
4436		dport = fin->fin_data[1];
4437		break;
4438	default :
4439		sport = 0;
4440		dport = 0;
4441		break;
4442	}
4443
4444	if ((flags & SI_WILDP) != 0)
4445		goto find_out_wild_ports;
4446
4447	hv = NAT_HASH_FN(src.s_addr, sport, 0xffffffff);
4448	hv = NAT_HASH_FN(dst.s_addr, hv + dport, softn->ipf_nat_table_sz);
4449	nat = softn->ipf_nat_table[0][hv];
4450
4451	/* TRACE src, sport, dst, dport, hv, nat */
4452
4453	for (; nat; nat = nat->nat_hnext[0]) {
4454		if (nat->nat_ifps[1] != NULL) {
4455			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
4456				continue;
4457		}
4458
4459		if (nat->nat_pr[1] != p)
4460			continue;
4461
4462		switch (nat->nat_dir)
4463		{
4464		case NAT_INBOUND :
4465		case NAT_DIVERTIN :
4466			if (nat->nat_v[1] != 4)
4467				continue;
4468			if (nat->nat_ndstaddr != src.s_addr ||
4469			    nat->nat_nsrcaddr != dst.s_addr)
4470				continue;
4471
4472			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4473				if (nat->nat_ndport != sport)
4474					continue;
4475				if (nat->nat_nsport != dport)
4476					continue;
4477
4478			} else if (p == IPPROTO_ICMP) {
4479				if (nat->nat_osport != dport) {
4480					continue;
4481				}
4482			}
4483			break;
4484		case NAT_OUTBOUND :
4485		case NAT_DIVERTOUT :
4486			if (nat->nat_v[0] != 4)
4487				continue;
4488			if (nat->nat_osrcaddr != src.s_addr ||
4489			    nat->nat_odstaddr != dst.s_addr)
4490				continue;
4491
4492			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
4493				if (nat->nat_odport != dport)
4494					continue;
4495				if (nat->nat_osport != sport)
4496					continue;
4497
4498			} else if (p == IPPROTO_ICMP) {
4499				if (nat->nat_osport != dport) {
4500					continue;
4501				}
4502			}
4503			break;
4504		}
4505
4506		ipn = nat->nat_ptr;
4507		if ((ipn != NULL) && (nat->nat_aps != NULL))
4508			if (ipf_proxy_match(fin, nat) != 0)
4509				continue;
4510
4511		if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
4512			nat->nat_ifps[1] = ifp;
4513			nat->nat_mtu[1] = GETIFMTU_4(ifp);
4514		}
4515		return nat;
4516	}
4517
4518	/*
4519	 * So if we didn't find it but there are wildcard members in the hash
4520	 * table, go back and look for them.  We do this search and update here
4521	 * because it is modifying the NAT table and we want to do this only
4522	 * for the first packet that matches.  The exception, of course, is
4523	 * for "dummy" (FI_IGNORE) lookups.
4524	 */
4525find_out_wild_ports:
4526	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
4527		NBUMPSIDEX(1, ns_lookup_miss, ns_lookup_miss_1);
4528		return NULL;
4529	}
4530	if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
4531		NBUMPSIDEX(1, ns_lookup_nowild, ns_lookup_nowild_1);
4532		return NULL;
4533	}
4534
4535	RWLOCK_EXIT(&softc->ipf_nat);
4536
4537	hv = NAT_HASH_FN(src.s_addr, 0, 0xffffffff);
4538	hv = NAT_HASH_FN(dst.s_addr, hv, softn->ipf_nat_table_sz);
4539
4540	WRITE_ENTER(&softc->ipf_nat);
4541
4542	nat = softn->ipf_nat_table[0][hv];
4543	for (; nat; nat = nat->nat_hnext[0]) {
4544		if (nat->nat_ifps[1] != NULL) {
4545			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
4546				continue;
4547		}
4548
4549		if (nat->nat_pr[1] != fin->fin_p)
4550			continue;
4551
4552		switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
4553		{
4554		case NAT_INBOUND :
4555			if (nat->nat_v[1] != 4)
4556				continue;
4557			if (nat->nat_ndstaddr != src.s_addr ||
4558			    nat->nat_nsrcaddr != dst.s_addr)
4559				continue;
4560			break;
4561		case NAT_OUTBOUND :
4562			if (nat->nat_v[0] != 4)
4563				continue;
4564			if (nat->nat_osrcaddr != src.s_addr ||
4565			    nat->nat_odstaddr != dst.s_addr)
4566				continue;
4567			break;
4568		}
4569
4570		if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP)))
4571			continue;
4572
4573		if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags,
4574				   NAT_OUTBOUND) == 1) {
4575			if ((fin->fin_flx & FI_IGNORE) != 0)
4576				break;
4577			if ((nat->nat_flags & SI_CLONE) != 0) {
4578				nat = ipf_nat_clone(fin, nat);
4579				if (nat == NULL)
4580					break;
4581			} else {
4582				MUTEX_ENTER(&softn->ipf_nat_new);
4583				softn->ipf_nat_stats.ns_wilds--;
4584				MUTEX_EXIT(&softn->ipf_nat_new);
4585			}
4586
4587			if (nat->nat_dir == NAT_OUTBOUND) {
4588				if (nat->nat_osport == 0) {
4589					nat->nat_osport = sport;
4590					nat->nat_nsport = sport;
4591				}
4592				if (nat->nat_odport == 0) {
4593					nat->nat_odport = dport;
4594					nat->nat_ndport = dport;
4595				}
4596			} else if (nat->nat_dir == NAT_INBOUND) {
4597				if (nat->nat_osport == 0) {
4598					nat->nat_osport = dport;
4599					nat->nat_nsport = dport;
4600				}
4601				if (nat->nat_odport == 0) {
4602					nat->nat_odport = sport;
4603					nat->nat_ndport = sport;
4604				}
4605			}
4606			if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
4607				nat->nat_ifps[1] = ifp;
4608				nat->nat_mtu[1] = GETIFMTU_4(ifp);
4609			}
4610			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
4611			ipf_nat_tabmove(softn, nat);
4612			break;
4613		}
4614	}
4615
4616	MUTEX_DOWNGRADE(&softc->ipf_nat);
4617
4618	if (nat == NULL) {
4619		NBUMPSIDE(1, ns_lookup_miss);
4620	}
4621	return nat;
4622}
4623
4624
4625/* ------------------------------------------------------------------------ */
4626/* Function:    ipf_nat_lookupredir                                         */
4627/* Returns:     nat_t* - NULL == no match,                                  */
4628/*                       else pointer to matching NAT entry                 */
4629/* Parameters:  np(I) - pointer to description of packet to find NAT table  */
4630/*                      entry for.                                          */
4631/*                                                                          */
4632/* Lookup the NAT tables to search for a matching redirect                  */
4633/* The contents of natlookup_t should imitate those found in a packet that  */
4634/* would be translated - ie a packet coming in for RDR or going out for MAP.*/
4635/* We can do the lookup in one of two ways, imitating an inbound or         */
4636/* outbound  packet.  By default we assume outbound, unless IPN_IN is set.  */
4637/* For IN, the fields are set as follows:                                   */
4638/*     nl_real* = source information                                        */
4639/*     nl_out* = destination information (translated)                       */
4640/* For an out packet, the fields are set like this:                         */
4641/*     nl_in* = source information (untranslated)                           */
4642/*     nl_out* = destination information (translated)                       */
4643/* ------------------------------------------------------------------------ */
4644nat_t *
4645ipf_nat_lookupredir(np)
4646	natlookup_t *np;
4647{
4648	fr_info_t fi;
4649	nat_t *nat;
4650
4651	bzero((char *)&fi, sizeof(fi));
4652	if (np->nl_flags & IPN_IN) {
4653		fi.fin_data[0] = ntohs(np->nl_realport);
4654		fi.fin_data[1] = ntohs(np->nl_outport);
4655	} else {
4656		fi.fin_data[0] = ntohs(np->nl_inport);
4657		fi.fin_data[1] = ntohs(np->nl_outport);
4658	}
4659	if (np->nl_flags & IPN_TCP)
4660		fi.fin_p = IPPROTO_TCP;
4661	else if (np->nl_flags & IPN_UDP)
4662		fi.fin_p = IPPROTO_UDP;
4663	else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY))
4664		fi.fin_p = IPPROTO_ICMP;
4665
4666	/*
4667	 * We can do two sorts of lookups:
4668	 * - IPN_IN: we have the `real' and `out' address, look for `in'.
4669	 * - default: we have the `in' and `out' address, look for `real'.
4670	 */
4671	if (np->nl_flags & IPN_IN) {
4672		if ((nat = ipf_nat_inlookup(&fi, np->nl_flags, fi.fin_p,
4673					    np->nl_realip, np->nl_outip))) {
4674			np->nl_inip = nat->nat_odstip;
4675			np->nl_inport = nat->nat_odport;
4676		}
4677	} else {
4678		/*
4679		 * If nl_inip is non null, this is a lookup based on the real
4680		 * ip address. Else, we use the fake.
4681		 */
4682		if ((nat = ipf_nat_outlookup(&fi, np->nl_flags, fi.fin_p,
4683					 np->nl_inip, np->nl_outip))) {
4684
4685			if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
4686				fr_info_t fin;
4687				bzero((char *)&fin, sizeof(fin));
4688				fin.fin_p = nat->nat_pr[0];
4689				fin.fin_data[0] = ntohs(nat->nat_ndport);
4690				fin.fin_data[1] = ntohs(nat->nat_nsport);
4691				if (ipf_nat_inlookup(&fin, np->nl_flags,
4692						     fin.fin_p, nat->nat_ndstip,
4693						     nat->nat_nsrcip) != NULL) {
4694					np->nl_flags &= ~IPN_FINDFORWARD;
4695				}
4696			}
4697
4698			np->nl_realip = nat->nat_odstip;
4699			np->nl_realport = nat->nat_odport;
4700		}
4701 	}
4702
4703	return nat;
4704}
4705
4706
4707/* ------------------------------------------------------------------------ */
4708/* Function:    ipf_nat_match                                               */
4709/* Returns:     int - 0 == no match, 1 == match                             */
4710/* Parameters:  fin(I)   - pointer to packet information                    */
4711/*              np(I)    - pointer to NAT rule                              */
4712/*                                                                          */
4713/* Pull the matching of a packet against a NAT rule out of that complex     */
4714/* loop inside ipf_nat_checkin() and lay it out properly in its own function. */
4715/* ------------------------------------------------------------------------ */
4716static int
4717ipf_nat_match(fin, np)
4718	fr_info_t *fin;
4719	ipnat_t *np;
4720{
4721	ipf_main_softc_t *softc = fin->fin_main_soft;
4722	frtuc_t *ft;
4723	int match;
4724
4725	match = 0;
4726	switch (np->in_osrcatype)
4727	{
4728	case FRI_NORMAL :
4729		match = ((fin->fin_saddr & np->in_osrcmsk) != np->in_osrcaddr);
4730		break;
4731	case FRI_LOOKUP :
4732		match = (*np->in_osrcfunc)(softc, np->in_osrcptr,
4733					   4, &fin->fin_saddr, fin->fin_plen);
4734		break;
4735	}
4736	match ^= ((np->in_flags & IPN_NOTSRC) != 0);
4737	if (match)
4738		return 0;
4739
4740	match = 0;
4741	switch (np->in_odstatype)
4742	{
4743	case FRI_NORMAL :
4744		match = ((fin->fin_daddr & np->in_odstmsk) != np->in_odstaddr);
4745		break;
4746	case FRI_LOOKUP :
4747		match = (*np->in_odstfunc)(softc, np->in_odstptr,
4748					   4, &fin->fin_daddr, fin->fin_plen);
4749		break;
4750	}
4751
4752	match ^= ((np->in_flags & IPN_NOTDST) != 0);
4753	if (match)
4754		return 0;
4755
4756	ft = &np->in_tuc;
4757	if (!(fin->fin_flx & FI_TCPUDP) ||
4758	    (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
4759		if (ft->ftu_scmp || ft->ftu_dcmp)
4760			return 0;
4761		return 1;
4762	}
4763
4764	return ipf_tcpudpchk(&fin->fin_fi, ft);
4765}
4766
4767
4768/* ------------------------------------------------------------------------ */
4769/* Function:    ipf_nat_update                                              */
4770/* Returns:     Nil                                                         */
4771/* Parameters:  fin(I) - pointer to packet information                      */
4772/*              nat(I) - pointer to NAT structure                           */
4773/*                                                                          */
4774/* Updates the lifetime of a NAT table entry for non-TCP packets.  Must be  */
4775/* called with fin_rev updated - i.e. after calling ipf_nat_proto().        */
4776/*                                                                          */
4777/* This *MUST* be called after ipf_nat_proto() as it expects fin_rev to     */
4778/* already be set.                                                          */
4779/* ------------------------------------------------------------------------ */
4780void
4781ipf_nat_update(fin, nat)
4782	fr_info_t *fin;
4783	nat_t *nat;
4784{
4785	ipf_main_softc_t *softc = fin->fin_main_soft;
4786	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
4787	ipftq_t *ifq, *ifq2;
4788	ipftqent_t *tqe;
4789	ipnat_t *np = nat->nat_ptr;
4790
4791	tqe = &nat->nat_tqe;
4792	ifq = tqe->tqe_ifq;
4793
4794	/*
4795	 * We allow over-riding of NAT timeouts from NAT rules, even for
4796	 * TCP, however, if it is TCP and there is no rule timeout set,
4797	 * then do not update the timeout here.
4798	 */
4799	if (np != NULL) {
4800		np->in_bytes[fin->fin_rev] += fin->fin_plen;
4801		ifq2 = np->in_tqehead[fin->fin_rev];
4802	} else {
4803		ifq2 = NULL;
4804	}
4805
4806	if (nat->nat_pr[0] == IPPROTO_TCP && ifq2 == NULL) {
4807		(void) ipf_tcp_age(&nat->nat_tqe, fin, softn->ipf_nat_tcptq,
4808				   0, 2);
4809	} else {
4810		if (ifq2 == NULL) {
4811			if (nat->nat_pr[0] == IPPROTO_UDP)
4812				ifq2 = fin->fin_rev ? &softn->ipf_nat_udpacktq :
4813						      &softn->ipf_nat_udptq;
4814			else if (nat->nat_pr[0] == IPPROTO_ICMP ||
4815				 nat->nat_pr[0] == IPPROTO_ICMPV6)
4816				ifq2 = fin->fin_rev ? &softn->ipf_nat_icmpacktq:
4817						      &softn->ipf_nat_icmptq;
4818			else
4819				ifq2 = &softn->ipf_nat_iptq;
4820		}
4821
4822		ipf_movequeue(softc->ipf_ticks, tqe, ifq, ifq2);
4823	}
4824}
4825
4826
4827/* ------------------------------------------------------------------------ */
4828/* Function:    ipf_nat_checkout                                            */
4829/* Returns:     int - -1 == packet failed NAT checks so block it,           */
4830/*                     0 == no packet translation occurred,                 */
4831/*                     1 == packet was successfully translated.             */
4832/* Parameters:  fin(I)   - pointer to packet information                    */
4833/*              passp(I) - pointer to filtering result flags                */
4834/*                                                                          */
4835/* Check to see if an outcoming packet should be changed.  ICMP packets are */
4836/* first checked to see if they match an existing entry (if an error),      */
4837/* otherwise a search of the current NAT table is made.  If neither results */
4838/* in a match then a search for a matching NAT rule is made.  Create a new  */
4839/* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
4840/* packet header(s) as required.                                            */
4841/* ------------------------------------------------------------------------ */
4842int
4843ipf_nat_checkout(fin, passp)
4844	fr_info_t *fin;
4845	u_32_t *passp;
4846{
4847	ipnat_t *np = NULL, *npnext;
4848	struct ifnet *ifp, *sifp;
4849	ipf_main_softc_t *softc;
4850	ipf_nat_softc_t *softn;
4851	icmphdr_t *icmp = NULL;
4852	tcphdr_t *tcp = NULL;
4853	int rval, natfailed;
4854	u_int nflags = 0;
4855	u_32_t ipa, iph;
4856	int natadd = 1;
4857	frentry_t *fr;
4858	nat_t *nat;
4859
4860	if (fin->fin_v == 6) {
4861#ifdef USE_INET6
4862		return ipf_nat6_checkout(fin, passp);
4863#else
4864		return 0;
4865#endif
4866	}
4867
4868	softc = fin->fin_main_soft;
4869	softn = softc->ipf_nat_soft;
4870
4871	if (softn->ipf_nat_lock != 0)
4872		return 0;
4873	if (softn->ipf_nat_stats.ns_rules == 0 &&
4874	    softn->ipf_nat_instances == NULL)
4875		return 0;
4876
4877	natfailed = 0;
4878	fr = fin->fin_fr;
4879	sifp = fin->fin_ifp;
4880	if (fr != NULL) {
4881		ifp = fr->fr_tifs[fin->fin_rev].fd_ptr;
4882		if ((ifp != NULL) && (ifp != (void *)-1))
4883			fin->fin_ifp = ifp;
4884	}
4885	ifp = fin->fin_ifp;
4886
4887	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
4888		switch (fin->fin_p)
4889		{
4890		case IPPROTO_TCP :
4891			nflags = IPN_TCP;
4892			break;
4893		case IPPROTO_UDP :
4894			nflags = IPN_UDP;
4895			break;
4896		case IPPROTO_ICMP :
4897			icmp = fin->fin_dp;
4898
4899			/*
4900			 * This is an incoming packet, so the destination is
4901			 * the icmp_id and the source port equals 0
4902			 */
4903			if ((fin->fin_flx & FI_ICMPQUERY) != 0)
4904				nflags = IPN_ICMPQUERY;
4905			break;
4906		default :
4907			break;
4908		}
4909
4910		if ((nflags & IPN_TCPUDP))
4911			tcp = fin->fin_dp;
4912	}
4913
4914	ipa = fin->fin_saddr;
4915
4916	READ_ENTER(&softc->ipf_nat);
4917
4918	if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
4919	    (nat = ipf_nat_icmperror(fin, &nflags, NAT_OUTBOUND)))
4920		/*EMPTY*/;
4921	else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
4922		natadd = 0;
4923	else if ((nat = ipf_nat_outlookup(fin, nflags|NAT_SEARCH,
4924				      (u_int)fin->fin_p, fin->fin_src,
4925				      fin->fin_dst))) {
4926		nflags = nat->nat_flags;
4927	} else if (fin->fin_off == 0) {
4928		u_32_t hv, msk, nmsk = 0;
4929
4930		/*
4931		 * If there is no current entry in the nat table for this IP#,
4932		 * create one for it (if there is a matching rule).
4933		 */
4934maskloop:
4935		msk = softn->ipf_nat_map_active_masks[nmsk];
4936		iph = ipa & msk;
4937		hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_maprules_sz);
4938retry_roundrobin:
4939		for (np = softn->ipf_nat_map_rules[hv]; np; np = npnext) {
4940			npnext = np->in_mnext;
4941			if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
4942				continue;
4943			if (np->in_v[0] != 4)
4944				continue;
4945			if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p))
4946				continue;
4947			if ((np->in_flags & IPN_RF) &&
4948			    !(np->in_flags & nflags))
4949				continue;
4950			if (np->in_flags & IPN_FILTER) {
4951				switch (ipf_nat_match(fin, np))
4952				{
4953				case 0 :
4954					continue;
4955				case -1 :
4956					rval = -3;
4957					goto outmatchfail;
4958				case 1 :
4959				default :
4960					break;
4961				}
4962			} else if ((ipa & np->in_osrcmsk) != np->in_osrcaddr)
4963				continue;
4964
4965			if ((fr != NULL) &&
4966			    !ipf_matchtag(&np->in_tag, &fr->fr_nattag))
4967				continue;
4968
4969			if (np->in_plabel != -1) {
4970				if (((np->in_flags & IPN_FILTER) == 0) &&
4971				    (np->in_odport != fin->fin_data[1]))
4972					continue;
4973				if (ipf_proxy_ok(fin, tcp, np) == 0)
4974					continue;
4975			}
4976
4977			if (np->in_flags & IPN_NO) {
4978				np->in_hits++;
4979				break;
4980			}
4981			MUTEX_ENTER(&softn->ipf_nat_new);
4982			/*
4983			 * If we've matched a round-robin rule but it has
4984			 * moved in the list since we got it, start over as
4985			 * this is now no longer correct.
4986			 */
4987			if (npnext != np->in_mnext) {
4988				if ((np->in_flags & IPN_ROUNDR) != 0) {
4989					MUTEX_EXIT(&softn->ipf_nat_new);
4990					goto retry_roundrobin;
4991				}
4992				npnext = np->in_mnext;
4993			}
4994
4995			nat = ipf_nat_add(fin, np, NULL, nflags, NAT_OUTBOUND);
4996			MUTEX_EXIT(&softn->ipf_nat_new);
4997			if (nat != NULL) {
4998				natfailed = 0;
4999				break;
5000			}
5001			natfailed = -2;
5002		}
5003		if ((np == NULL) && (nmsk < softn->ipf_nat_map_max)) {
5004			nmsk++;
5005			goto maskloop;
5006		}
5007	}
5008
5009	if (nat != NULL) {
5010		rval = ipf_nat_out(fin, nat, natadd, nflags);
5011		if (rval == 1) {
5012			MUTEX_ENTER(&nat->nat_lock);
5013			ipf_nat_update(fin, nat);
5014			nat->nat_bytes[1] += fin->fin_plen;
5015			nat->nat_pkts[1]++;
5016			fin->fin_pktnum = nat->nat_pkts[1];
5017			MUTEX_EXIT(&nat->nat_lock);
5018		}
5019	} else
5020		rval = natfailed;
5021outmatchfail:
5022	RWLOCK_EXIT(&softc->ipf_nat);
5023
5024	switch (rval)
5025	{
5026	case -3 :
5027		/* ipf_nat_match() failure */
5028		/* FALLTHROUGH */
5029	case -2 :
5030		/* retry_roundrobin loop failure */
5031		/* FALLTHROUGH */
5032	case -1 :
5033		/* proxy failure detected by ipf_nat_out() */
5034		if (passp != NULL) {
5035			DT2(frb_natv4out, fr_info_t *, fin, int, rval);
5036			NBUMPSIDED(1, ns_drop);
5037			*passp = FR_BLOCK;
5038			fin->fin_reason = FRB_NATV4;
5039		}
5040		fin->fin_flx |= FI_BADNAT;
5041		NBUMPSIDED(1, ns_badnat);
5042		rval = -1;	/* We only return -1 on error. */
5043		break;
5044	case 0 :
5045		NBUMPSIDE(1, ns_ignored);
5046		break;
5047	case 1 :
5048		NBUMPSIDE(1, ns_translated);
5049		break;
5050	}
5051	fin->fin_ifp = sifp;
5052	return rval;
5053}
5054
5055/* ------------------------------------------------------------------------ */
5056/* Function:    ipf_nat_out                                                 */
5057/* Returns:     int - -1 == packet failed NAT checks so block it,           */
5058/*                     1 == packet was successfully translated.             */
5059/* Parameters:  fin(I)    - pointer to packet information                   */
5060/*              nat(I)    - pointer to NAT structure                        */
5061/*              natadd(I) - flag indicating if it is safe to add frag cache */
5062/*              nflags(I) - NAT flags set for this packet                   */
5063/*                                                                          */
5064/* Translate a packet coming "out" on an interface.                         */
5065/* ------------------------------------------------------------------------ */
5066int
5067ipf_nat_out(fin, nat, natadd, nflags)
5068	fr_info_t *fin;
5069	nat_t *nat;
5070	int natadd;
5071	u_32_t nflags;
5072{
5073	ipf_main_softc_t *softc = fin->fin_main_soft;
5074	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5075	icmphdr_t *icmp;
5076	tcphdr_t *tcp;
5077	ipnat_t *np;
5078	int skip;
5079	int i;
5080
5081	tcp = NULL;
5082	icmp = NULL;
5083	np = nat->nat_ptr;
5084
5085	if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL))
5086		(void) ipf_frag_natnew(softc, fin, 0, nat);
5087
5088	/*
5089	 * Fix up checksums, not by recalculating them, but
5090	 * simply computing adjustments.
5091	 * This is only done for STREAMS based IP implementations where the
5092	 * checksum has already been calculated by IP.  In all other cases,
5093	 * IPFilter is called before the checksum needs calculating so there
5094	 * is no call to modify whatever is in the header now.
5095	 */
5096	if (nflags == IPN_ICMPERR) {
5097		u_32_t s1, s2, sumd, msumd;
5098
5099		s1 = LONG_SUM(ntohl(fin->fin_saddr));
5100		if (nat->nat_dir == NAT_OUTBOUND) {
5101			s2 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
5102		} else {
5103			s2 = LONG_SUM(ntohl(nat->nat_odstaddr));
5104		}
5105		CALC_SUMD(s1, s2, sumd);
5106		msumd = sumd;
5107
5108		s1 = LONG_SUM(ntohl(fin->fin_daddr));
5109		if (nat->nat_dir == NAT_OUTBOUND) {
5110			s2 = LONG_SUM(ntohl(nat->nat_ndstaddr));
5111		} else {
5112			s2 = LONG_SUM(ntohl(nat->nat_osrcaddr));
5113		}
5114		CALC_SUMD(s1, s2, sumd);
5115		msumd += sumd;
5116
5117		ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, msumd, 0);
5118	}
5119#if !defined(_KERNEL) || SOLARIS || \
5120    defined(BRIDGE_IPF) || defined(__FreeBSD__)
5121	else {
5122		/*
5123		 * Strictly speaking, this isn't necessary on BSD
5124		 * kernels because they do checksum calculation after
5125		 * this code has run BUT if ipfilter is being used
5126		 * to do NAT as a bridge, that code doesn't exist.
5127		 */
5128		switch (nat->nat_dir)
5129		{
5130		case NAT_OUTBOUND :
5131			ipf_fix_outcksum(fin->fin_cksum & FI_CK_L4PART,
5132					 &fin->fin_ip->ip_sum,
5133					 nat->nat_ipsumd, 0);
5134			break;
5135
5136		case NAT_INBOUND :
5137			ipf_fix_incksum(fin->fin_cksum & FI_CK_L4PART,
5138					&fin->fin_ip->ip_sum,
5139					nat->nat_ipsumd, 0);
5140			break;
5141
5142		default :
5143			break;
5144		}
5145	}
5146#endif
5147
5148	/*
5149	 * Address assignment is after the checksum modification because
5150	 * we are using the address in the packet for determining the
5151	 * correct checksum offset (the ICMP error could be coming from
5152	 * anyone...)
5153	 */
5154	switch (nat->nat_dir)
5155	{
5156	case NAT_OUTBOUND :
5157		fin->fin_ip->ip_src = nat->nat_nsrcip;
5158		fin->fin_saddr = nat->nat_nsrcaddr;
5159		fin->fin_ip->ip_dst = nat->nat_ndstip;
5160		fin->fin_daddr = nat->nat_ndstaddr;
5161		break;
5162
5163	case NAT_INBOUND :
5164		fin->fin_ip->ip_src = nat->nat_odstip;
5165		fin->fin_saddr = nat->nat_ndstaddr;
5166		fin->fin_ip->ip_dst = nat->nat_osrcip;
5167		fin->fin_daddr = nat->nat_nsrcaddr;
5168		break;
5169
5170	case NAT_DIVERTIN :
5171	    {
5172		mb_t *m;
5173
5174		skip = ipf_nat_decap(fin, nat);
5175		if (skip <= 0) {
5176			NBUMPSIDED(1, ns_decap_fail);
5177			return -1;
5178		}
5179
5180		m = fin->fin_m;
5181
5182#if SOLARIS && defined(_KERNEL)
5183		m->b_rptr += skip;
5184#else
5185		m->m_data += skip;
5186		m->m_len -= skip;
5187
5188# ifdef M_PKTHDR
5189		if (m->m_flags & M_PKTHDR)
5190			m->m_pkthdr.len -= skip;
5191# endif
5192#endif
5193
5194		MUTEX_ENTER(&nat->nat_lock);
5195		ipf_nat_update(fin, nat);
5196		MUTEX_EXIT(&nat->nat_lock);
5197		fin->fin_flx |= FI_NATED;
5198		if (np != NULL && np->in_tag.ipt_num[0] != 0)
5199			fin->fin_nattag = &np->in_tag;
5200		return 1;
5201		/* NOTREACHED */
5202	    }
5203
5204	case NAT_DIVERTOUT :
5205	    {
5206		u_32_t s1, s2, sumd;
5207		udphdr_t *uh;
5208		ip_t *ip;
5209		mb_t *m;
5210
5211		m = M_DUP(np->in_divmp);
5212		if (m == NULL) {
5213			NBUMPSIDED(1, ns_divert_dup);
5214			return -1;
5215		}
5216
5217		ip = MTOD(m, ip_t *);
5218		ip_fillid(ip);
5219		s2 = ntohs(ip->ip_id);
5220
5221		s1 = ip->ip_len;
5222		ip->ip_len = ntohs(ip->ip_len);
5223		ip->ip_len += fin->fin_plen;
5224		ip->ip_len = htons(ip->ip_len);
5225		s2 += ntohs(ip->ip_len);
5226		CALC_SUMD(s1, s2, sumd);
5227
5228		uh = (udphdr_t *)(ip + 1);
5229		uh->uh_ulen += fin->fin_plen;
5230		uh->uh_ulen = htons(uh->uh_ulen);
5231#if !defined(_KERNEL) || SOLARIS || \
5232    defined(BRIDGE_IPF) || defined(__FreeBSD__)
5233		ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
5234#endif
5235
5236		PREP_MB_T(fin, m);
5237
5238		fin->fin_src = ip->ip_src;
5239		fin->fin_dst = ip->ip_dst;
5240		fin->fin_ip = ip;
5241		fin->fin_plen += sizeof(ip_t) + 8;	/* UDP + IPv4 hdr */
5242		fin->fin_dlen += sizeof(ip_t) + 8;	/* UDP + IPv4 hdr */
5243
5244		nflags &= ~IPN_TCPUDPICMP;
5245
5246		break;
5247	    }
5248
5249	default :
5250		break;
5251	}
5252
5253	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
5254		u_short *csump;
5255
5256		if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) {
5257			tcp = fin->fin_dp;
5258
5259			switch (nat->nat_dir)
5260			{
5261			case NAT_OUTBOUND :
5262				tcp->th_sport = nat->nat_nsport;
5263				fin->fin_data[0] = ntohs(nat->nat_nsport);
5264				tcp->th_dport = nat->nat_ndport;
5265				fin->fin_data[1] = ntohs(nat->nat_ndport);
5266				break;
5267
5268			case NAT_INBOUND :
5269				tcp->th_sport = nat->nat_odport;
5270				fin->fin_data[0] = ntohs(nat->nat_odport);
5271				tcp->th_dport = nat->nat_osport;
5272				fin->fin_data[1] = ntohs(nat->nat_osport);
5273				break;
5274			}
5275		}
5276
5277		if ((nat->nat_nsport != 0) && (nflags & IPN_ICMPQUERY)) {
5278			icmp = fin->fin_dp;
5279			icmp->icmp_id = nat->nat_nicmpid;
5280		}
5281
5282		csump = ipf_nat_proto(fin, nat, nflags);
5283
5284		/*
5285		 * The above comments do not hold for layer 4 (or higher)
5286		 * checksums...
5287		 */
5288		if (csump != NULL) {
5289			if (nat->nat_dir == NAT_OUTBOUND)
5290				ipf_fix_outcksum(fin->fin_cksum, csump,
5291						 nat->nat_sumd[0],
5292						 nat->nat_sumd[1] +
5293						 fin->fin_dlen);
5294			else
5295				ipf_fix_incksum(fin->fin_cksum, csump,
5296						nat->nat_sumd[0],
5297						nat->nat_sumd[1] +
5298						fin->fin_dlen);
5299		}
5300	}
5301
5302	ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
5303	/* ------------------------------------------------------------- */
5304	/* A few quick notes:                                            */
5305	/*      Following are test conditions prior to calling the       */
5306	/*      ipf_proxy_check routine.                                 */
5307	/*                                                               */
5308	/*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
5309	/*      with a redirect rule, we attempt to match the packet's   */
5310	/*      source port against in_dport, otherwise we'd compare the */
5311	/*      packet's destination.                                    */
5312	/* ------------------------------------------------------------- */
5313	if ((np != NULL) && (np->in_apr != NULL)) {
5314		i = ipf_proxy_check(fin, nat);
5315		if (i == -1) {
5316			NBUMPSIDED(1, ns_ipf_proxy_fail);
5317		}
5318	} else {
5319		i = 1;
5320	}
5321	fin->fin_flx |= FI_NATED;
5322	return i;
5323}
5324
5325
5326/* ------------------------------------------------------------------------ */
5327/* Function:    ipf_nat_checkin                                             */
5328/* Returns:     int - -1 == packet failed NAT checks so block it,           */
5329/*                     0 == no packet translation occurred,                 */
5330/*                     1 == packet was successfully translated.             */
5331/* Parameters:  fin(I)   - pointer to packet information                    */
5332/*              passp(I) - pointer to filtering result flags                */
5333/*                                                                          */
5334/* Check to see if an incoming packet should be changed.  ICMP packets are  */
5335/* first checked to see if they match an existing entry (if an error),      */
5336/* otherwise a search of the current NAT table is made.  If neither results */
5337/* in a match then a search for a matching NAT rule is made.  Create a new  */
5338/* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
5339/* packet header(s) as required.                                            */
5340/* ------------------------------------------------------------------------ */
5341int
5342ipf_nat_checkin(fin, passp)
5343	fr_info_t *fin;
5344	u_32_t *passp;
5345{
5346	ipf_main_softc_t *softc;
5347	ipf_nat_softc_t *softn;
5348	u_int nflags, natadd;
5349	ipnat_t *np, *npnext;
5350	int rval, natfailed;
5351	struct ifnet *ifp;
5352	struct in_addr in;
5353	icmphdr_t *icmp;
5354	tcphdr_t *tcp;
5355	u_short dport;
5356	nat_t *nat;
5357	u_32_t iph;
5358
5359	softc = fin->fin_main_soft;
5360	softn = softc->ipf_nat_soft;
5361
5362	if (softn->ipf_nat_lock != 0)
5363		return 0;
5364	if (softn->ipf_nat_stats.ns_rules == 0 &&
5365	    softn->ipf_nat_instances == NULL)
5366		return 0;
5367
5368	tcp = NULL;
5369	icmp = NULL;
5370	dport = 0;
5371	natadd = 1;
5372	nflags = 0;
5373	natfailed = 0;
5374	ifp = fin->fin_ifp;
5375
5376	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
5377		switch (fin->fin_p)
5378		{
5379		case IPPROTO_TCP :
5380			nflags = IPN_TCP;
5381			break;
5382		case IPPROTO_UDP :
5383			nflags = IPN_UDP;
5384			break;
5385		case IPPROTO_ICMP :
5386			icmp = fin->fin_dp;
5387
5388			/*
5389			 * This is an incoming packet, so the destination is
5390			 * the icmp_id and the source port equals 0
5391			 */
5392			if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
5393				nflags = IPN_ICMPQUERY;
5394				dport = icmp->icmp_id;
5395			} break;
5396		default :
5397			break;
5398		}
5399
5400		if ((nflags & IPN_TCPUDP)) {
5401			tcp = fin->fin_dp;
5402			dport = fin->fin_data[1];
5403		}
5404	}
5405
5406	in = fin->fin_dst;
5407
5408	READ_ENTER(&softc->ipf_nat);
5409
5410	if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
5411	    (nat = ipf_nat_icmperror(fin, &nflags, NAT_INBOUND)))
5412		/*EMPTY*/;
5413	else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
5414		natadd = 0;
5415	else if ((nat = ipf_nat_inlookup(fin, nflags|NAT_SEARCH,
5416					 (u_int)fin->fin_p,
5417					 fin->fin_src, in))) {
5418		nflags = nat->nat_flags;
5419	} else if (fin->fin_off == 0) {
5420		u_32_t hv, msk, rmsk = 0;
5421
5422		/*
5423		 * If there is no current entry in the nat table for this IP#,
5424		 * create one for it (if there is a matching rule).
5425		 */
5426maskloop:
5427		msk = softn->ipf_nat_rdr_active_masks[rmsk];
5428		iph = in.s_addr & msk;
5429		hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_rdrrules_sz);
5430retry_roundrobin:
5431		/* TRACE (iph,msk,rmsk,hv,softn->ipf_nat_rdrrules_sz) */
5432		for (np = softn->ipf_nat_rdr_rules[hv]; np; np = npnext) {
5433			npnext = np->in_rnext;
5434			if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
5435				continue;
5436			if (np->in_v[0] != 4)
5437				continue;
5438			if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p))
5439				continue;
5440			if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
5441				continue;
5442			if (np->in_flags & IPN_FILTER) {
5443				switch (ipf_nat_match(fin, np))
5444				{
5445				case 0 :
5446					continue;
5447				case -1 :
5448					rval = -3;
5449					goto inmatchfail;
5450				case 1 :
5451				default :
5452					break;
5453				}
5454			} else {
5455				if ((in.s_addr & np->in_odstmsk) !=
5456				    np->in_odstaddr)
5457					continue;
5458				if (np->in_odport &&
5459				    ((np->in_dtop < dport) ||
5460				     (dport < np->in_odport)))
5461					continue;
5462			}
5463
5464			if (np->in_plabel != -1) {
5465				if (!ipf_proxy_ok(fin, tcp, np)) {
5466					continue;
5467				}
5468			}
5469
5470			if (np->in_flags & IPN_NO) {
5471				np->in_hits++;
5472				break;
5473			}
5474
5475			MUTEX_ENTER(&softn->ipf_nat_new);
5476			/*
5477			 * If we've matched a round-robin rule but it has
5478			 * moved in the list since we got it, start over as
5479			 * this is now no longer correct.
5480			 */
5481			if (npnext != np->in_rnext) {
5482				if ((np->in_flags & IPN_ROUNDR) != 0) {
5483					MUTEX_EXIT(&softn->ipf_nat_new);
5484					goto retry_roundrobin;
5485				}
5486				npnext = np->in_rnext;
5487			}
5488
5489			nat = ipf_nat_add(fin, np, NULL, nflags, NAT_INBOUND);
5490			MUTEX_EXIT(&softn->ipf_nat_new);
5491			if (nat != NULL) {
5492				natfailed = 0;
5493				break;
5494			}
5495			natfailed = -2;
5496		}
5497		if ((np == NULL) && (rmsk < softn->ipf_nat_rdr_max)) {
5498			rmsk++;
5499			goto maskloop;
5500		}
5501	}
5502
5503	if (nat != NULL) {
5504		rval = ipf_nat_in(fin, nat, natadd, nflags);
5505		if (rval == 1) {
5506			MUTEX_ENTER(&nat->nat_lock);
5507			ipf_nat_update(fin, nat);
5508			nat->nat_bytes[0] += fin->fin_plen;
5509			nat->nat_pkts[0]++;
5510			fin->fin_pktnum = nat->nat_pkts[0];
5511			MUTEX_EXIT(&nat->nat_lock);
5512		}
5513	} else
5514		rval = natfailed;
5515inmatchfail:
5516	RWLOCK_EXIT(&softc->ipf_nat);
5517
5518	switch (rval)
5519	{
5520	case -3 :
5521		/* ipf_nat_match() failure */
5522		/* FALLTHROUGH */
5523	case -2 :
5524		/* retry_roundrobin loop failure */
5525		/* FALLTHROUGH */
5526	case -1 :
5527		/* proxy failure detected by ipf_nat_out() */
5528		if (passp != NULL) {
5529			DT2(frb_natv4in, fr_info_t *, fin, int, rval);
5530			NBUMPSIDED(0, ns_drop);
5531			*passp = FR_BLOCK;
5532			fin->fin_reason = FRB_NATV4;
5533		}
5534		fin->fin_flx |= FI_BADNAT;
5535		NBUMPSIDED(0, ns_badnat);
5536		rval = -1;	/* We only return -1 on error. */
5537		break;
5538	case 0 :
5539		NBUMPSIDE(0, ns_ignored);
5540		break;
5541	case 1 :
5542		NBUMPSIDE(0, ns_translated);
5543		break;
5544	}
5545	return rval;
5546}
5547
5548
5549/* ------------------------------------------------------------------------ */
5550/* Function:    ipf_nat_in                                                  */
5551/* Returns:     int - -1 == packet failed NAT checks so block it,           */
5552/*                     1 == packet was successfully translated.             */
5553/* Parameters:  fin(I)    - pointer to packet information                   */
5554/*              nat(I)    - pointer to NAT structure                        */
5555/*              natadd(I) - flag indicating if it is safe to add frag cache */
5556/*              nflags(I) - NAT flags set for this packet                   */
5557/* Locks Held:  ipf_nat(READ)                                               */
5558/*                                                                          */
5559/* Translate a packet coming "in" on an interface.                          */
5560/* ------------------------------------------------------------------------ */
5561int
5562ipf_nat_in(fin, nat, natadd, nflags)
5563	fr_info_t *fin;
5564	nat_t *nat;
5565	int natadd;
5566	u_32_t nflags;
5567{
5568	ipf_main_softc_t *softc = fin->fin_main_soft;
5569	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5570	u_32_t sumd, ipsumd, sum1, sum2;
5571	icmphdr_t *icmp;
5572	tcphdr_t *tcp;
5573	ipnat_t *np;
5574	int skip;
5575	int i;
5576
5577	tcp = NULL;
5578	np = nat->nat_ptr;
5579	fin->fin_fr = nat->nat_fr;
5580
5581	if (np != NULL) {
5582		if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
5583			(void) ipf_frag_natnew(softc, fin, 0, nat);
5584
5585	/* ------------------------------------------------------------- */
5586	/* A few quick notes:                                            */
5587	/*      Following are test conditions prior to calling the       */
5588	/*      ipf_proxy_check routine.                                 */
5589	/*                                                               */
5590	/*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
5591	/*      with a map rule, we attempt to match the packet's        */
5592	/*      source port against in_dport, otherwise we'd compare the */
5593	/*      packet's destination.                                    */
5594	/* ------------------------------------------------------------- */
5595		if (np->in_apr != NULL) {
5596			i = ipf_proxy_check(fin, nat);
5597			if (i == -1) {
5598				NBUMPSIDED(0, ns_ipf_proxy_fail);
5599				return -1;
5600			}
5601		}
5602	}
5603
5604	ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
5605
5606	ipsumd = nat->nat_ipsumd;
5607	/*
5608	 * Fix up checksums, not by recalculating them, but
5609	 * simply computing adjustments.
5610	 * Why only do this for some platforms on inbound packets ?
5611	 * Because for those that it is done, IP processing is yet to happen
5612	 * and so the IPv4 header checksum has not yet been evaluated.
5613	 * Perhaps it should always be done for the benefit of things like
5614	 * fast forwarding (so that it doesn't need to be recomputed) but with
5615	 * header checksum offloading, perhaps it is a moot point.
5616	 */
5617
5618	switch (nat->nat_dir)
5619	{
5620	case NAT_INBOUND :
5621		if ((fin->fin_flx & FI_ICMPERR) == 0) {
5622			fin->fin_ip->ip_src = nat->nat_nsrcip;
5623			fin->fin_saddr = nat->nat_nsrcaddr;
5624		} else {
5625			sum1 = nat->nat_osrcaddr;
5626			sum2 = nat->nat_nsrcaddr;
5627			CALC_SUMD(sum1, sum2, sumd);
5628			ipsumd -= sumd;
5629		}
5630		fin->fin_ip->ip_dst = nat->nat_ndstip;
5631		fin->fin_daddr = nat->nat_ndstaddr;
5632#if !defined(_KERNEL) || SOLARIS
5633		ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
5634#endif
5635		break;
5636
5637	case NAT_OUTBOUND :
5638		if ((fin->fin_flx & FI_ICMPERR) == 0) {
5639			fin->fin_ip->ip_src = nat->nat_odstip;
5640			fin->fin_saddr = nat->nat_odstaddr;
5641		} else {
5642			sum1 = nat->nat_odstaddr;
5643			sum2 = nat->nat_ndstaddr;
5644			CALC_SUMD(sum1, sum2, sumd);
5645			ipsumd -= sumd;
5646		}
5647		fin->fin_ip->ip_dst = nat->nat_osrcip;
5648		fin->fin_daddr = nat->nat_osrcaddr;
5649#if !defined(_KERNEL) || SOLARIS
5650		ipf_fix_incksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
5651#endif
5652		break;
5653
5654	case NAT_DIVERTIN :
5655	    {
5656		udphdr_t *uh;
5657		ip_t *ip;
5658		mb_t *m;
5659
5660		m = M_DUP(np->in_divmp);
5661		if (m == NULL) {
5662			NBUMPSIDED(0, ns_divert_dup);
5663			return -1;
5664		}
5665
5666		ip = MTOD(m, ip_t *);
5667		ip_fillid(ip);
5668		sum1 = ntohs(ip->ip_len);
5669		ip->ip_len = ntohs(ip->ip_len);
5670		ip->ip_len += fin->fin_plen;
5671		ip->ip_len = htons(ip->ip_len);
5672
5673		uh = (udphdr_t *)(ip + 1);
5674		uh->uh_ulen += fin->fin_plen;
5675		uh->uh_ulen = htons(uh->uh_ulen);
5676
5677		sum2 = ntohs(ip->ip_id) + ntohs(ip->ip_len);
5678		sum2 += ntohs(ip->ip_off) & IP_DF;
5679		CALC_SUMD(sum1, sum2, sumd);
5680
5681#if !defined(_KERNEL) || SOLARIS
5682		ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
5683#endif
5684		PREP_MB_T(fin, m);
5685
5686		fin->fin_ip = ip;
5687		fin->fin_plen += sizeof(ip_t) + 8;	/* UDP + new IPv4 hdr */
5688		fin->fin_dlen += sizeof(ip_t) + 8;	/* UDP + old IPv4 hdr */
5689
5690		nflags &= ~IPN_TCPUDPICMP;
5691
5692		break;
5693	    }
5694
5695	case NAT_DIVERTOUT :
5696	    {
5697		mb_t *m;
5698
5699		skip = ipf_nat_decap(fin, nat);
5700		if (skip <= 0) {
5701			NBUMPSIDED(0, ns_decap_fail);
5702			return -1;
5703		}
5704
5705		m = fin->fin_m;
5706
5707#if SOLARIS && defined(_KERNEL)
5708		m->b_rptr += skip;
5709#else
5710		m->m_data += skip;
5711		m->m_len -= skip;
5712
5713# ifdef M_PKTHDR
5714		if (m->m_flags & M_PKTHDR)
5715			m->m_pkthdr.len -= skip;
5716# endif
5717#endif
5718
5719		ipf_nat_update(fin, nat);
5720		nflags &= ~IPN_TCPUDPICMP;
5721		fin->fin_flx |= FI_NATED;
5722		if (np != NULL && np->in_tag.ipt_num[0] != 0)
5723			fin->fin_nattag = &np->in_tag;
5724		return 1;
5725		/* NOTREACHED */
5726	    }
5727	}
5728	if (nflags & IPN_TCPUDP)
5729		tcp = fin->fin_dp;
5730
5731	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
5732		u_short *csump;
5733
5734		if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) {
5735			switch (nat->nat_dir)
5736			{
5737			case NAT_INBOUND :
5738				tcp->th_sport = nat->nat_nsport;
5739				fin->fin_data[0] = ntohs(nat->nat_nsport);
5740				tcp->th_dport = nat->nat_ndport;
5741				fin->fin_data[1] = ntohs(nat->nat_ndport);
5742				break;
5743
5744			case NAT_OUTBOUND :
5745				tcp->th_sport = nat->nat_odport;
5746				fin->fin_data[0] = ntohs(nat->nat_odport);
5747				tcp->th_dport = nat->nat_osport;
5748				fin->fin_data[1] = ntohs(nat->nat_osport);
5749				break;
5750			}
5751		}
5752
5753
5754		if ((nat->nat_odport != 0) && (nflags & IPN_ICMPQUERY)) {
5755			icmp = fin->fin_dp;
5756
5757			icmp->icmp_id = nat->nat_nicmpid;
5758		}
5759
5760		csump = ipf_nat_proto(fin, nat, nflags);
5761
5762		/*
5763		 * The above comments do not hold for layer 4 (or higher)
5764		 * checksums...
5765		 */
5766		if (csump != NULL) {
5767			if (nat->nat_dir == NAT_OUTBOUND)
5768				ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0);
5769			else
5770				ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0);
5771		}
5772	}
5773
5774	fin->fin_flx |= FI_NATED;
5775	if (np != NULL && np->in_tag.ipt_num[0] != 0)
5776		fin->fin_nattag = &np->in_tag;
5777	return 1;
5778}
5779
5780
5781/* ------------------------------------------------------------------------ */
5782/* Function:    ipf_nat_proto                                               */
5783/* Returns:     u_short* - pointer to transport header checksum to update,  */
5784/*                         NULL if the transport protocol is not recognised */
5785/*                         as needing a checksum update.                    */
5786/* Parameters:  fin(I)    - pointer to packet information                   */
5787/*              nat(I)    - pointer to NAT structure                        */
5788/*              nflags(I) - NAT flags set for this packet                   */
5789/*                                                                          */
5790/* Return the pointer to the checksum field for each protocol so understood.*/
5791/* If support for making other changes to a protocol header is required,    */
5792/* that is not strictly 'address' translation, such as clamping the MSS in  */
5793/* TCP down to a specific value, then do it from here.                      */
5794/* ------------------------------------------------------------------------ */
5795u_short *
5796ipf_nat_proto(fin, nat, nflags)
5797	fr_info_t *fin;
5798	nat_t *nat;
5799	u_int nflags;
5800{
5801	icmphdr_t *icmp;
5802	u_short *csump;
5803	tcphdr_t *tcp;
5804	udphdr_t *udp;
5805
5806	csump = NULL;
5807	if (fin->fin_out == 0) {
5808		fin->fin_rev = (nat->nat_dir & NAT_OUTBOUND);
5809	} else {
5810		fin->fin_rev = ((nat->nat_dir & NAT_OUTBOUND) == 0);
5811	}
5812
5813	switch (fin->fin_p)
5814	{
5815	case IPPROTO_TCP :
5816		tcp = fin->fin_dp;
5817
5818		if ((nflags & IPN_TCP) != 0)
5819			csump = &tcp->th_sum;
5820
5821		/*
5822		 * Do a MSS CLAMPING on a SYN packet,
5823		 * only deal IPv4 for now.
5824		 */
5825		if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0)
5826			ipf_nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump);
5827
5828		break;
5829
5830	case IPPROTO_UDP :
5831		udp = fin->fin_dp;
5832
5833		if ((nflags & IPN_UDP) != 0) {
5834			if (udp->uh_sum != 0)
5835				csump = &udp->uh_sum;
5836		}
5837		break;
5838
5839	case IPPROTO_ICMP :
5840		icmp = fin->fin_dp;
5841
5842		if ((nflags & IPN_ICMPQUERY) != 0) {
5843			if (icmp->icmp_cksum != 0)
5844				csump = &icmp->icmp_cksum;
5845		}
5846		break;
5847
5848#ifdef USE_INET6
5849	case IPPROTO_ICMPV6 :
5850	    {
5851		struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)fin->fin_dp;
5852
5853		icmp6 = fin->fin_dp;
5854
5855		if ((nflags & IPN_ICMPQUERY) != 0) {
5856			if (icmp6->icmp6_cksum != 0)
5857				csump = &icmp6->icmp6_cksum;
5858		}
5859		break;
5860	    }
5861#endif
5862	}
5863	return csump;
5864}
5865
5866
5867/* ------------------------------------------------------------------------ */
5868/* Function:    ipf_nat_expire                                              */
5869/* Returns:     Nil                                                         */
5870/* Parameters:  softc(I) - pointer to soft context main structure           */
5871/*                                                                          */
5872/* Check all of the timeout queues for entries at the top which need to be  */
5873/* expired.                                                                 */
5874/* ------------------------------------------------------------------------ */
5875void
5876ipf_nat_expire(softc)
5877	ipf_main_softc_t *softc;
5878{
5879	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5880	ipftq_t *ifq, *ifqnext;
5881	ipftqent_t *tqe, *tqn;
5882	int i;
5883	SPL_INT(s);
5884
5885	SPL_NET(s);
5886	WRITE_ENTER(&softc->ipf_nat);
5887	for (ifq = softn->ipf_nat_tcptq, i = 0; ifq != NULL;
5888	     ifq = ifq->ifq_next) {
5889		for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
5890			if (tqe->tqe_die > softc->ipf_ticks)
5891				break;
5892			tqn = tqe->tqe_next;
5893			ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
5894		}
5895	}
5896
5897	for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifq->ifq_next) {
5898		for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
5899			if (tqe->tqe_die > softc->ipf_ticks)
5900				break;
5901			tqn = tqe->tqe_next;
5902			ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
5903		}
5904	}
5905
5906	for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) {
5907		ifqnext = ifq->ifq_next;
5908
5909		if (((ifq->ifq_flags & IFQF_DELETE) != 0) &&
5910		    (ifq->ifq_ref == 0)) {
5911			ipf_freetimeoutqueue(softc, ifq);
5912		}
5913	}
5914
5915	if (softn->ipf_nat_doflush != 0) {
5916		ipf_nat_extraflush(softc, softn, 2);
5917		softn->ipf_nat_doflush = 0;
5918	}
5919
5920	RWLOCK_EXIT(&softc->ipf_nat);
5921	SPL_X(s);
5922}
5923
5924
5925/* ------------------------------------------------------------------------ */
5926/* Function:    ipf_nat_sync                                                */
5927/* Returns:     Nil                                                         */
5928/* Parameters:  softc(I) - pointer to soft context main structure           */
5929/*              ifp(I) - pointer to network interface                       */
5930/*                                                                          */
5931/* Walk through all of the currently active NAT sessions, looking for those */
5932/* which need to have their translated address updated.                     */
5933/* ------------------------------------------------------------------------ */
5934void
5935ipf_nat_sync(softc, ifp)
5936	ipf_main_softc_t *softc;
5937	void *ifp;
5938{
5939	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
5940	u_32_t sum1, sum2, sumd;
5941	i6addr_t in;
5942	ipnat_t *n;
5943	nat_t *nat;
5944	void *ifp2;
5945	int idx;
5946	SPL_INT(s);
5947
5948	if (softc->ipf_running <= 0)
5949		return;
5950
5951	/*
5952	 * Change IP addresses for NAT sessions for any protocol except TCP
5953	 * since it will break the TCP connection anyway.  The only rules
5954	 * which will get changed are those which are "map ... -> 0/32",
5955	 * where the rule specifies the address is taken from the interface.
5956	 */
5957	SPL_NET(s);
5958	WRITE_ENTER(&softc->ipf_nat);
5959
5960	if (softc->ipf_running <= 0) {
5961		RWLOCK_EXIT(&softc->ipf_nat);
5962		return;
5963	}
5964
5965	for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) {
5966		if ((nat->nat_flags & IPN_TCP) != 0)
5967			continue;
5968
5969		n = nat->nat_ptr;
5970		if (n != NULL) {
5971			if (n->in_v[1] == 4) {
5972				if (n->in_redir & NAT_MAP) {
5973					if ((n->in_nsrcaddr != 0) ||
5974					    (n->in_nsrcmsk != 0xffffffff))
5975						continue;
5976				} else if (n->in_redir & NAT_REDIRECT) {
5977					if ((n->in_ndstaddr != 0) ||
5978					    (n->in_ndstmsk != 0xffffffff))
5979						continue;
5980				}
5981			}
5982#ifdef USE_INET6
5983			if (n->in_v[1] == 4) {
5984				if (n->in_redir & NAT_MAP) {
5985					if (!IP6_ISZERO(&n->in_nsrcaddr) ||
5986					    !IP6_ISONES(&n->in_nsrcmsk))
5987						continue;
5988				} else if (n->in_redir & NAT_REDIRECT) {
5989					if (!IP6_ISZERO(&n->in_ndstaddr) ||
5990					    !IP6_ISONES(&n->in_ndstmsk))
5991						continue;
5992				}
5993			}
5994#endif
5995		}
5996
5997		if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) ||
5998		     (ifp == nat->nat_ifps[1]))) {
5999			nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0],
6000						  nat->nat_v[0]);
6001			if ((nat->nat_ifps[0] != NULL) &&
6002			    (nat->nat_ifps[0] != (void *)-1)) {
6003				nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
6004			}
6005			if (nat->nat_ifnames[1][0] != '\0') {
6006				nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1],
6007							  nat->nat_v[1]);
6008			} else {
6009				nat->nat_ifps[1] = nat->nat_ifps[0];
6010			}
6011			if ((nat->nat_ifps[1] != NULL) &&
6012			    (nat->nat_ifps[1] != (void *)-1)) {
6013				nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
6014			}
6015			ifp2 = nat->nat_ifps[0];
6016			if (ifp2 == NULL)
6017				continue;
6018
6019			/*
6020			 * Change the map-to address to be the same as the
6021			 * new one.
6022			 */
6023			sum1 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
6024			if (ipf_ifpaddr(softc, nat->nat_v[0], FRI_NORMAL, ifp2,
6025				       &in, NULL) != -1) {
6026				if (nat->nat_v[0] == 4)
6027					nat->nat_nsrcip = in.in4;
6028			}
6029			sum2 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
6030
6031			if (sum1 == sum2)
6032				continue;
6033			/*
6034			 * Readjust the checksum adjustment to take into
6035			 * account the new IP#.
6036			 */
6037			CALC_SUMD(sum1, sum2, sumd);
6038			/* XXX - dont change for TCP when solaris does
6039			 * hardware checksumming.
6040			 */
6041			sumd += nat->nat_sumd[0];
6042			nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
6043			nat->nat_sumd[1] = nat->nat_sumd[0];
6044		}
6045	}
6046
6047	for (n = softn->ipf_nat_list; (n != NULL); n = n->in_next) {
6048		char *base = n->in_names;
6049
6050		if ((ifp == NULL) || (n->in_ifps[0] == ifp))
6051			n->in_ifps[0] = ipf_resolvenic(softc,
6052						       base + n->in_ifnames[0],
6053						       n->in_v[0]);
6054		if ((ifp == NULL) || (n->in_ifps[1] == ifp))
6055			n->in_ifps[1] = ipf_resolvenic(softc,
6056						       base + n->in_ifnames[1],
6057						       n->in_v[1]);
6058
6059		if (n->in_redir & NAT_REDIRECT)
6060			idx = 1;
6061		else
6062			idx = 0;
6063
6064		if (((ifp == NULL) || (n->in_ifps[idx] == ifp)) &&
6065		    (n->in_ifps[idx] != NULL &&
6066		     n->in_ifps[idx] != (void *)-1)) {
6067
6068			ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc,
6069					     0, n->in_ifps[idx]);
6070			ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst,
6071					     0, n->in_ifps[idx]);
6072			ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc,
6073					     0, n->in_ifps[idx]);
6074			ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst,
6075					     0, n->in_ifps[idx]);
6076		}
6077	}
6078	RWLOCK_EXIT(&softc->ipf_nat);
6079	SPL_X(s);
6080}
6081
6082
6083/* ------------------------------------------------------------------------ */
6084/* Function:    ipf_nat_icmpquerytype                                       */
6085/* Returns:     int - 1 == success, 0 == failure                            */
6086/* Parameters:  icmptype(I) - ICMP type number                              */
6087/*                                                                          */
6088/* Tests to see if the ICMP type number passed is a query/response type or  */
6089/* not.                                                                     */
6090/* ------------------------------------------------------------------------ */
6091static int
6092ipf_nat_icmpquerytype(icmptype)
6093	int icmptype;
6094{
6095
6096	/*
6097	 * For the ICMP query NAT code, it is essential that both the query
6098	 * and the reply match on the NAT rule. Because the NAT structure
6099	 * does not keep track of the icmptype, and a single NAT structure
6100	 * is used for all icmp types with the same src, dest and id, we
6101	 * simply define the replies as queries as well. The funny thing is,
6102	 * altough it seems silly to call a reply a query, this is exactly
6103	 * as it is defined in the IPv4 specification
6104	 */
6105	switch (icmptype)
6106	{
6107	case ICMP_ECHOREPLY:
6108	case ICMP_ECHO:
6109	/* route advertisement/solicitation is currently unsupported: */
6110	/* it would require rewriting the ICMP data section          */
6111	case ICMP_TSTAMP:
6112	case ICMP_TSTAMPREPLY:
6113	case ICMP_IREQ:
6114	case ICMP_IREQREPLY:
6115	case ICMP_MASKREQ:
6116	case ICMP_MASKREPLY:
6117		return 1;
6118	default:
6119		return 0;
6120	}
6121}
6122
6123
6124/* ------------------------------------------------------------------------ */
6125/* Function:    nat_log                                                     */
6126/* Returns:     Nil                                                         */
6127/* Parameters:  softc(I) - pointer to soft context main structure           */
6128/*              softn(I) - pointer to NAT context structure                 */
6129/*              nat(I)    - pointer to NAT structure                        */
6130/*              action(I) - action related to NAT structure being performed */
6131/*                                                                          */
6132/* Creates a NAT log entry.                                                 */
6133/* ------------------------------------------------------------------------ */
6134void
6135ipf_nat_log(softc, softn, nat, action)
6136	ipf_main_softc_t *softc;
6137	ipf_nat_softc_t *softn;
6138	struct nat *nat;
6139	u_int action;
6140{
6141#ifdef	IPFILTER_LOG
6142# ifndef LARGE_NAT
6143	struct ipnat *np;
6144	int rulen;
6145# endif
6146	struct natlog natl;
6147	void *items[1];
6148	size_t sizes[1];
6149	int types[1];
6150
6151	bcopy((char *)&nat->nat_osrc6, (char *)&natl.nl_osrcip,
6152	      sizeof(natl.nl_osrcip));
6153	bcopy((char *)&nat->nat_nsrc6, (char *)&natl.nl_nsrcip,
6154	      sizeof(natl.nl_nsrcip));
6155	bcopy((char *)&nat->nat_odst6, (char *)&natl.nl_odstip,
6156	      sizeof(natl.nl_odstip));
6157	bcopy((char *)&nat->nat_ndst6, (char *)&natl.nl_ndstip,
6158	      sizeof(natl.nl_ndstip));
6159
6160	natl.nl_bytes[0] = nat->nat_bytes[0];
6161	natl.nl_bytes[1] = nat->nat_bytes[1];
6162	natl.nl_pkts[0] = nat->nat_pkts[0];
6163	natl.nl_pkts[1] = nat->nat_pkts[1];
6164	natl.nl_odstport = nat->nat_odport;
6165	natl.nl_osrcport = nat->nat_osport;
6166	natl.nl_nsrcport = nat->nat_nsport;
6167	natl.nl_ndstport = nat->nat_ndport;
6168	natl.nl_p[0] = nat->nat_pr[0];
6169	natl.nl_p[1] = nat->nat_pr[1];
6170	natl.nl_v[0] = nat->nat_v[0];
6171	natl.nl_v[1] = nat->nat_v[1];
6172	natl.nl_type = nat->nat_redir;
6173	natl.nl_action = action;
6174	natl.nl_rule = -1;
6175
6176	bcopy(nat->nat_ifnames[0], natl.nl_ifnames[0],
6177	      sizeof(nat->nat_ifnames[0]));
6178	bcopy(nat->nat_ifnames[1], natl.nl_ifnames[1],
6179	      sizeof(nat->nat_ifnames[1]));
6180
6181# ifndef LARGE_NAT
6182	if (nat->nat_ptr != NULL) {
6183		for (rulen = 0, np = softn->ipf_nat_list; np != NULL;
6184		     np = np->in_next, rulen++)
6185			if (np == nat->nat_ptr) {
6186				natl.nl_rule = rulen;
6187				break;
6188			}
6189	}
6190# endif
6191	items[0] = &natl;
6192	sizes[0] = sizeof(natl);
6193	types[0] = 0;
6194
6195	(void) ipf_log_items(softc, IPL_LOGNAT, NULL, items, sizes, types, 1);
6196#endif
6197}
6198
6199
6200
6201
6202/* ------------------------------------------------------------------------ */
6203/* Function:    ipf_nat_rule_deref                                          */
6204/* Returns:     Nil                                                         */
6205/* Parameters:  softc(I) - pointer to soft context main structure           */
6206/*              inp(I)   - pointer to pointer to NAT rule                   */
6207/* Write Locks: ipf_nat                                                     */
6208/*                                                                          */
6209/* Dropping the refernce count for a rule means that whatever held the      */
6210/* pointer to this rule (*inp) is no longer interested in it and when the   */
6211/* reference count drops to zero, any resources allocated for the rule can  */
6212/* be released and the rule itself free'd.                                  */
6213/* ------------------------------------------------------------------------ */
6214void
6215ipf_nat_rule_deref(softc, inp)
6216	ipf_main_softc_t *softc;
6217	ipnat_t **inp;
6218{
6219	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
6220	ipnat_t *n;
6221
6222	n = *inp;
6223	*inp = NULL;
6224	n->in_use--;
6225	if (n->in_use > 0)
6226		return;
6227
6228	if (n->in_apr != NULL)
6229		ipf_proxy_deref(n->in_apr);
6230
6231	ipf_nat_rule_fini(softc, n);
6232
6233	if (n->in_redir & NAT_REDIRECT) {
6234		if ((n->in_flags & IPN_PROXYRULE) == 0) {
6235			ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_rdr);
6236		}
6237	}
6238	if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
6239		if ((n->in_flags & IPN_PROXYRULE) == 0) {
6240			ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_map);
6241		}
6242	}
6243
6244	if (n->in_tqehead[0] != NULL) {
6245		if (ipf_deletetimeoutqueue(n->in_tqehead[0]) == 0) {
6246			ipf_freetimeoutqueue(softc, n->in_tqehead[1]);
6247		}
6248	}
6249
6250	if (n->in_tqehead[1] != NULL) {
6251		if (ipf_deletetimeoutqueue(n->in_tqehead[1]) == 0) {
6252			ipf_freetimeoutqueue(softc, n->in_tqehead[1]);
6253		}
6254	}
6255
6256	if ((n->in_flags & IPN_PROXYRULE) == 0) {
6257		ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules);
6258	}
6259
6260	MUTEX_DESTROY(&n->in_lock);
6261
6262	KFREES(n, n->in_size);
6263
6264#if SOLARIS && !defined(INSTANCES)
6265	if (softn->ipf_nat_stats.ns_rules == 0)
6266		pfil_delayed_copy = 1;
6267#endif
6268}
6269
6270
6271/* ------------------------------------------------------------------------ */
6272/* Function:    ipf_nat_deref                                               */
6273/* Returns:     Nil                                                         */
6274/* Parameters:  softc(I) - pointer to soft context main structure           */
6275/*              natp(I)  - pointer to pointer to NAT table entry            */
6276/*                                                                          */
6277/* Decrement the reference counter for this NAT table entry and free it if  */
6278/* there are no more things using it.                                       */
6279/*                                                                          */
6280/* IF nat_ref == 1 when this function is called, then we have an orphan nat */
6281/* structure *because* it only gets called on paths _after_ nat_ref has been*/
6282/* incremented.  If nat_ref == 1 then we shouldn't decrement it here        */
6283/* because nat_delete() will do that and send nat_ref to -1.                */
6284/*                                                                          */
6285/* Holding the lock on nat_lock is required to serialise nat_delete() being */
6286/* called from a NAT flush ioctl with a deref happening because of a packet.*/
6287/* ------------------------------------------------------------------------ */
6288void
6289ipf_nat_deref(softc, natp)
6290	ipf_main_softc_t *softc;
6291	nat_t **natp;
6292{
6293	nat_t *nat;
6294
6295	nat = *natp;
6296	*natp = NULL;
6297
6298	MUTEX_ENTER(&nat->nat_lock);
6299	if (nat->nat_ref > 1) {
6300		nat->nat_ref--;
6301		ASSERT(nat->nat_ref >= 0);
6302		MUTEX_EXIT(&nat->nat_lock);
6303		return;
6304	}
6305	MUTEX_EXIT(&nat->nat_lock);
6306
6307	WRITE_ENTER(&softc->ipf_nat);
6308	ipf_nat_delete(softc, nat, NL_EXPIRE);
6309	RWLOCK_EXIT(&softc->ipf_nat);
6310}
6311
6312
6313/* ------------------------------------------------------------------------ */
6314/* Function:    ipf_nat_clone                                               */
6315/* Returns:     ipstate_t* - NULL == cloning failed,                        */
6316/*                           else pointer to new state structure            */
6317/* Parameters:  fin(I) - pointer to packet information                      */
6318/*              is(I)  - pointer to master state structure                  */
6319/* Write Lock:  ipf_nat                                                     */
6320/*                                                                          */
6321/* Create a "duplcate" state table entry from the master.                   */
6322/* ------------------------------------------------------------------------ */
6323nat_t *
6324ipf_nat_clone(fin, nat)
6325	fr_info_t *fin;
6326	nat_t *nat;
6327{
6328	ipf_main_softc_t *softc = fin->fin_main_soft;
6329	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
6330	frentry_t *fr;
6331	nat_t *clone;
6332	ipnat_t *np;
6333
6334	KMALLOC(clone, nat_t *);
6335	if (clone == NULL) {
6336		NBUMPSIDED(fin->fin_out, ns_clone_nomem);
6337		return NULL;
6338	}
6339	bcopy((char *)nat, (char *)clone, sizeof(*clone));
6340
6341	MUTEX_NUKE(&clone->nat_lock);
6342
6343	clone->nat_rev = fin->fin_rev;
6344	clone->nat_aps = NULL;
6345	/*
6346	 * Initialize all these so that ipf_nat_delete() doesn't cause a crash.
6347	 */
6348	clone->nat_tqe.tqe_pnext = NULL;
6349	clone->nat_tqe.tqe_next = NULL;
6350	clone->nat_tqe.tqe_ifq = NULL;
6351	clone->nat_tqe.tqe_parent = clone;
6352
6353	clone->nat_flags &= ~SI_CLONE;
6354	clone->nat_flags |= SI_CLONED;
6355
6356	if (clone->nat_hm)
6357		clone->nat_hm->hm_ref++;
6358
6359	if (ipf_nat_insert(softc, softn, clone) == -1) {
6360		KFREE(clone);
6361		NBUMPSIDED(fin->fin_out, ns_insert_fail);
6362		return NULL;
6363	}
6364
6365	np = clone->nat_ptr;
6366	if (np != NULL) {
6367		if (softn->ipf_nat_logging)
6368			ipf_nat_log(softc, softn, clone, NL_CLONE);
6369		np->in_use++;
6370	}
6371	fr = clone->nat_fr;
6372	if (fr != NULL) {
6373		MUTEX_ENTER(&fr->fr_lock);
6374		fr->fr_ref++;
6375		MUTEX_EXIT(&fr->fr_lock);
6376	}
6377
6378
6379	/*
6380	 * Because the clone is created outside the normal loop of things and
6381	 * TCP has special needs in terms of state, initialise the timeout
6382	 * state of the new NAT from here.
6383	 */
6384	if (clone->nat_pr[0] == IPPROTO_TCP) {
6385		(void) ipf_tcp_age(&clone->nat_tqe, fin, softn->ipf_nat_tcptq,
6386				   clone->nat_flags, 2);
6387	}
6388	clone->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, clone);
6389	if (softn->ipf_nat_logging)
6390		ipf_nat_log(softc, softn, clone, NL_CLONE);
6391	return clone;
6392}
6393
6394
6395/* ------------------------------------------------------------------------ */
6396/* Function:   ipf_nat_wildok                                               */
6397/* Returns:    int - 1 == packet's ports match wildcards                    */
6398/*                   0 == packet's ports don't match wildcards              */
6399/* Parameters: nat(I)   - NAT entry                                         */
6400/*             sport(I) - source port                                       */
6401/*             dport(I) - destination port                                  */
6402/*             flags(I) - wildcard flags                                    */
6403/*             dir(I)   - packet direction                                  */
6404/*                                                                          */
6405/* Use NAT entry and packet direction to determine which combination of     */
6406/* wildcard flags should be used.                                           */
6407/* ------------------------------------------------------------------------ */
6408int
6409ipf_nat_wildok(nat, sport, dport, flags, dir)
6410	nat_t *nat;
6411	int sport, dport, flags, dir;
6412{
6413	/*
6414	 * When called by       dir is set to
6415	 * nat_inlookup         NAT_INBOUND (0)
6416	 * nat_outlookup        NAT_OUTBOUND (1)
6417	 *
6418	 * We simply combine the packet's direction in dir with the original
6419	 * "intended" direction of that NAT entry in nat->nat_dir to decide
6420	 * which combination of wildcard flags to allow.
6421	 */
6422	switch ((dir << 1) | (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND)))
6423	{
6424	case 3: /* outbound packet / outbound entry */
6425		if (((nat->nat_osport == sport) ||
6426		    (flags & SI_W_SPORT)) &&
6427		    ((nat->nat_odport == dport) ||
6428		    (flags & SI_W_DPORT)))
6429			return 1;
6430		break;
6431	case 2: /* outbound packet / inbound entry */
6432		if (((nat->nat_osport == dport) ||
6433		    (flags & SI_W_SPORT)) &&
6434		    ((nat->nat_odport == sport) ||
6435		    (flags & SI_W_DPORT)))
6436			return 1;
6437		break;
6438	case 1: /* inbound packet / outbound entry */
6439		if (((nat->nat_osport == dport) ||
6440		    (flags & SI_W_SPORT)) &&
6441		    ((nat->nat_odport == sport) ||
6442		    (flags & SI_W_DPORT)))
6443			return 1;
6444		break;
6445	case 0: /* inbound packet / inbound entry */
6446		if (((nat->nat_osport == sport) ||
6447		    (flags & SI_W_SPORT)) &&
6448		    ((nat->nat_odport == dport) ||
6449		    (flags & SI_W_DPORT)))
6450			return 1;
6451		break;
6452	default:
6453		break;
6454	}
6455
6456	return(0);
6457}
6458
6459
6460/* ------------------------------------------------------------------------ */
6461/* Function:    nat_mssclamp                                                */
6462/* Returns:     Nil                                                         */
6463/* Parameters:  tcp(I)    - pointer to TCP header                           */
6464/*              maxmss(I) - value to clamp the TCP MSS to                   */
6465/*              fin(I)    - pointer to packet information                   */
6466/*              csump(I)  - pointer to TCP checksum                         */
6467/*                                                                          */
6468/* Check for MSS option and clamp it if necessary.  If found and changed,   */
6469/* then the TCP header checksum will be updated to reflect the change in    */
6470/* the MSS.                                                                 */
6471/* ------------------------------------------------------------------------ */
6472static void
6473ipf_nat_mssclamp(tcp, maxmss, fin, csump)
6474	tcphdr_t *tcp;
6475	u_32_t maxmss;
6476	fr_info_t *fin;
6477	u_short *csump;
6478{
6479	u_char *cp, *ep, opt;
6480	int hlen, advance;
6481	u_32_t mss, sumd;
6482
6483	hlen = TCP_OFF(tcp) << 2;
6484	if (hlen > sizeof(*tcp)) {
6485		cp = (u_char *)tcp + sizeof(*tcp);
6486		ep = (u_char *)tcp + hlen;
6487
6488		while (cp < ep) {
6489			opt = cp[0];
6490			if (opt == TCPOPT_EOL)
6491				break;
6492			else if (opt == TCPOPT_NOP) {
6493				cp++;
6494				continue;
6495			}
6496
6497			if (cp + 1 >= ep)
6498				break;
6499			advance = cp[1];
6500			if ((cp + advance > ep) || (advance <= 0))
6501				break;
6502			switch (opt)
6503			{
6504			case TCPOPT_MAXSEG:
6505				if (advance != 4)
6506					break;
6507				mss = cp[2] * 256 + cp[3];
6508				if (mss > maxmss) {
6509					cp[2] = maxmss / 256;
6510					cp[3] = maxmss & 0xff;
6511					CALC_SUMD(mss, maxmss, sumd);
6512					ipf_fix_outcksum(0, csump, sumd, 0);
6513				}
6514				break;
6515			default:
6516				/* ignore unknown options */
6517				break;
6518			}
6519
6520			cp += advance;
6521		}
6522	}
6523}
6524
6525
6526/* ------------------------------------------------------------------------ */
6527/* Function:    ipf_nat_setqueue                                            */
6528/* Returns:     Nil                                                         */
6529/* Parameters:  softc(I) - pointer to soft context main structure           */
6530/*              softn(I) - pointer to NAT context structure                 */
6531/*              nat(I)- pointer to NAT structure                            */
6532/* Locks:       ipf_nat (read or write)                                     */
6533/*                                                                          */
6534/* Put the NAT entry on its default queue entry, using rev as a helped in   */
6535/* determining which queue it should be placed on.                          */
6536/* ------------------------------------------------------------------------ */
6537void
6538ipf_nat_setqueue(softc, softn, nat)
6539	ipf_main_softc_t *softc;
6540	ipf_nat_softc_t *softn;
6541	nat_t *nat;
6542{
6543	ipftq_t *oifq, *nifq;
6544	int rev = nat->nat_rev;
6545
6546	if (nat->nat_ptr != NULL)
6547		nifq = nat->nat_ptr->in_tqehead[rev];
6548	else
6549		nifq = NULL;
6550
6551	if (nifq == NULL) {
6552		switch (nat->nat_pr[0])
6553		{
6554		case IPPROTO_UDP :
6555			nifq = &softn->ipf_nat_udptq;
6556			break;
6557		case IPPROTO_ICMP :
6558			nifq = &softn->ipf_nat_icmptq;
6559			break;
6560		case IPPROTO_TCP :
6561			nifq = softn->ipf_nat_tcptq +
6562			       nat->nat_tqe.tqe_state[rev];
6563			break;
6564		default :
6565			nifq = &softn->ipf_nat_iptq;
6566			break;
6567		}
6568	}
6569
6570	oifq = nat->nat_tqe.tqe_ifq;
6571	/*
6572	 * If it's currently on a timeout queue, move it from one queue to
6573	 * another, else put it on the end of the newly determined queue.
6574	 */
6575	if (oifq != NULL)
6576		ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, nifq);
6577	else
6578		ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, nifq, nat);
6579	return;
6580}
6581
6582
6583/* ------------------------------------------------------------------------ */
6584/* Function:    nat_getnext                                                 */
6585/* Returns:     int - 0 == ok, else error                                   */
6586/* Parameters:  softc(I) - pointer to soft context main structure           */
6587/*              t(I)   - pointer to ipftoken structure                      */
6588/*              itp(I) - pointer to ipfgeniter_t structure                  */
6589/*                                                                          */
6590/* Fetch the next nat/ipnat structure pointer from the linked list and      */
6591/* copy it out to the storage space pointed to by itp_data.  The next item  */
6592/* in the list to look at is put back in the ipftoken struture.             */
6593/* ------------------------------------------------------------------------ */
6594static int
6595ipf_nat_getnext(softc, t, itp, objp)
6596	ipf_main_softc_t *softc;
6597	ipftoken_t *t;
6598	ipfgeniter_t *itp;
6599	ipfobj_t *objp;
6600{
6601	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
6602	hostmap_t *hm, *nexthm = NULL, zerohm;
6603	ipnat_t *ipn, *nextipnat = NULL, zeroipn;
6604	nat_t *nat, *nextnat = NULL, zeronat;
6605	int error = 0;
6606	void *nnext;
6607
6608	if (itp->igi_nitems != 1) {
6609		IPFERROR(60075);
6610		return ENOSPC;
6611	}
6612
6613	READ_ENTER(&softc->ipf_nat);
6614
6615	switch (itp->igi_type)
6616	{
6617	case IPFGENITER_HOSTMAP :
6618		hm = t->ipt_data;
6619		if (hm == NULL) {
6620			nexthm = softn->ipf_hm_maplist;
6621		} else {
6622			nexthm = hm->hm_next;
6623		}
6624		if (nexthm != NULL) {
6625			ATOMIC_INC32(nexthm->hm_ref);
6626			t->ipt_data = nexthm;
6627		} else {
6628			bzero(&zerohm, sizeof(zerohm));
6629			nexthm = &zerohm;
6630			t->ipt_data = NULL;
6631		}
6632		nnext = nexthm->hm_next;
6633		break;
6634
6635	case IPFGENITER_IPNAT :
6636		ipn = t->ipt_data;
6637		if (ipn == NULL) {
6638			nextipnat = softn->ipf_nat_list;
6639		} else {
6640			nextipnat = ipn->in_next;
6641		}
6642		if (nextipnat != NULL) {
6643			ATOMIC_INC32(nextipnat->in_use);
6644			t->ipt_data = nextipnat;
6645		} else {
6646			bzero(&zeroipn, sizeof(zeroipn));
6647			nextipnat = &zeroipn;
6648			t->ipt_data = NULL;
6649		}
6650		nnext = nextipnat->in_next;
6651		break;
6652
6653	case IPFGENITER_NAT :
6654		nat = t->ipt_data;
6655		if (nat == NULL) {
6656			nextnat = softn->ipf_nat_instances;
6657		} else {
6658			nextnat = nat->nat_next;
6659		}
6660		if (nextnat != NULL) {
6661			MUTEX_ENTER(&nextnat->nat_lock);
6662			nextnat->nat_ref++;
6663			MUTEX_EXIT(&nextnat->nat_lock);
6664			t->ipt_data = nextnat;
6665		} else {
6666			bzero(&zeronat, sizeof(zeronat));
6667			nextnat = &zeronat;
6668			t->ipt_data = NULL;
6669		}
6670		nnext = nextnat->nat_next;
6671		break;
6672
6673	default :
6674		RWLOCK_EXIT(&softc->ipf_nat);
6675		IPFERROR(60055);
6676		return EINVAL;
6677	}
6678
6679	RWLOCK_EXIT(&softc->ipf_nat);
6680
6681	objp->ipfo_ptr = itp->igi_data;
6682
6683	switch (itp->igi_type)
6684	{
6685	case IPFGENITER_HOSTMAP :
6686		error = COPYOUT(nexthm, objp->ipfo_ptr, sizeof(*nexthm));
6687		if (error != 0) {
6688			IPFERROR(60049);
6689			error = EFAULT;
6690		}
6691		if (hm != NULL) {
6692			WRITE_ENTER(&softc->ipf_nat);
6693			ipf_nat_hostmapdel(softc, &hm);
6694			RWLOCK_EXIT(&softc->ipf_nat);
6695		}
6696		break;
6697
6698	case IPFGENITER_IPNAT :
6699		objp->ipfo_size = nextipnat->in_size;
6700		objp->ipfo_type = IPFOBJ_IPNAT;
6701		error = ipf_outobjk(softc, objp, nextipnat);
6702		if (ipn != NULL) {
6703			WRITE_ENTER(&softc->ipf_nat);
6704			ipf_nat_rule_deref(softc, &ipn);
6705			RWLOCK_EXIT(&softc->ipf_nat);
6706		}
6707		break;
6708
6709	case IPFGENITER_NAT :
6710		objp->ipfo_size = sizeof(nat_t);
6711		objp->ipfo_type = IPFOBJ_NAT;
6712		error = ipf_outobjk(softc, objp, nextnat);
6713		if (nat != NULL)
6714			ipf_nat_deref(softc, &nat);
6715
6716		break;
6717	}
6718
6719	if (nnext == NULL)
6720		ipf_token_mark_complete(t);
6721
6722	return error;
6723}
6724
6725
6726/* ------------------------------------------------------------------------ */
6727/* Function:    nat_extraflush                                              */
6728/* Returns:     int - 0 == success, -1 == failure                           */
6729/* Parameters:  softc(I) - pointer to soft context main structure           */
6730/*              softn(I) - pointer to NAT context structure                 */
6731/*              which(I) - how to flush the active NAT table                */
6732/* Write Locks: ipf_nat                                                     */
6733/*                                                                          */
6734/* Flush nat tables.  Three actions currently defined:                      */
6735/* which == 0 : flush all nat table entries                                 */
6736/* which == 1 : flush TCP connections which have started to close but are   */
6737/*	      stuck for some reason.                                        */
6738/* which == 2 : flush TCP connections which have been idle for a long time, */
6739/*	      starting at > 4 days idle and working back in successive half-*/
6740/*	      days to at most 12 hours old.  If this fails to free enough   */
6741/*            slots then work backwards in half hour slots to 30 minutes.   */
6742/*            If that too fails, then work backwards in 30 second intervals */
6743/*            for the last 30 minutes to at worst 30 seconds idle.          */
6744/* ------------------------------------------------------------------------ */
6745static int
6746ipf_nat_extraflush(softc, softn, which)
6747	ipf_main_softc_t *softc;
6748	ipf_nat_softc_t *softn;
6749	int which;
6750{
6751	nat_t *nat, **natp;
6752	ipftqent_t *tqn;
6753	ipftq_t *ifq;
6754	int removed;
6755	SPL_INT(s);
6756
6757	removed = 0;
6758
6759	SPL_NET(s);
6760	switch (which)
6761	{
6762	case 0 :
6763		softn->ipf_nat_stats.ns_flush_all++;
6764		/*
6765		 * Style 0 flush removes everything...
6766		 */
6767		for (natp = &softn->ipf_nat_instances;
6768		     ((nat = *natp) != NULL); ) {
6769			ipf_nat_delete(softc, nat, NL_FLUSH);
6770			removed++;
6771		}
6772		break;
6773
6774	case 1 :
6775		softn->ipf_nat_stats.ns_flush_closing++;
6776		/*
6777		 * Since we're only interested in things that are closing,
6778		 * we can start with the appropriate timeout queue.
6779		 */
6780		for (ifq = softn->ipf_nat_tcptq + IPF_TCPS_CLOSE_WAIT;
6781		     ifq != NULL; ifq = ifq->ifq_next) {
6782
6783			for (tqn = ifq->ifq_head; tqn != NULL; ) {
6784				nat = tqn->tqe_parent;
6785				tqn = tqn->tqe_next;
6786				if (nat->nat_pr[0] != IPPROTO_TCP ||
6787				    nat->nat_pr[1] != IPPROTO_TCP)
6788					break;
6789				ipf_nat_delete(softc, nat, NL_EXPIRE);
6790				removed++;
6791			}
6792		}
6793
6794		/*
6795		 * Also need to look through the user defined queues.
6796		 */
6797		for (ifq = softn->ipf_nat_utqe; ifq != NULL;
6798		     ifq = ifq->ifq_next) {
6799			for (tqn = ifq->ifq_head; tqn != NULL; ) {
6800				nat = tqn->tqe_parent;
6801				tqn = tqn->tqe_next;
6802				if (nat->nat_pr[0] != IPPROTO_TCP ||
6803				    nat->nat_pr[1] != IPPROTO_TCP)
6804					continue;
6805
6806				if ((nat->nat_tcpstate[0] >
6807				     IPF_TCPS_ESTABLISHED) &&
6808				    (nat->nat_tcpstate[1] >
6809				     IPF_TCPS_ESTABLISHED)) {
6810					ipf_nat_delete(softc, nat, NL_EXPIRE);
6811					removed++;
6812				}
6813			}
6814		}
6815		break;
6816
6817		/*
6818		 * Args 5-11 correspond to flushing those particular states
6819		 * for TCP connections.
6820		 */
6821	case IPF_TCPS_CLOSE_WAIT :
6822	case IPF_TCPS_FIN_WAIT_1 :
6823	case IPF_TCPS_CLOSING :
6824	case IPF_TCPS_LAST_ACK :
6825	case IPF_TCPS_FIN_WAIT_2 :
6826	case IPF_TCPS_TIME_WAIT :
6827	case IPF_TCPS_CLOSED :
6828		softn->ipf_nat_stats.ns_flush_state++;
6829		tqn = softn->ipf_nat_tcptq[which].ifq_head;
6830		while (tqn != NULL) {
6831			nat = tqn->tqe_parent;
6832			tqn = tqn->tqe_next;
6833			ipf_nat_delete(softc, nat, NL_FLUSH);
6834			removed++;
6835		}
6836		break;
6837
6838	default :
6839		if (which < 30)
6840			break;
6841
6842		softn->ipf_nat_stats.ns_flush_timeout++;
6843		/*
6844		 * Take a large arbitrary number to mean the number of seconds
6845		 * for which which consider to be the maximum value we'll allow
6846		 * the expiration to be.
6847		 */
6848		which = IPF_TTLVAL(which);
6849		for (natp = &softn->ipf_nat_instances;
6850		     ((nat = *natp) != NULL); ) {
6851			if (softc->ipf_ticks - nat->nat_touched > which) {
6852				ipf_nat_delete(softc, nat, NL_FLUSH);
6853				removed++;
6854			} else
6855				natp = &nat->nat_next;
6856		}
6857		break;
6858	}
6859
6860	if (which != 2) {
6861		SPL_X(s);
6862		return removed;
6863	}
6864
6865	softn->ipf_nat_stats.ns_flush_queue++;
6866
6867	/*
6868	 * Asked to remove inactive entries because the table is full, try
6869	 * again, 3 times, if first attempt failed with a different criteria
6870	 * each time.  The order tried in must be in decreasing age.
6871	 * Another alternative is to implement random drop and drop N entries
6872	 * at random until N have been freed up.
6873	 */
6874	if (softc->ipf_ticks - softn->ipf_nat_last_force_flush >
6875	    IPF_TTLVAL(5)) {
6876		softn->ipf_nat_last_force_flush = softc->ipf_ticks;
6877
6878		removed = ipf_queueflush(softc, ipf_nat_flush_entry,
6879					 softn->ipf_nat_tcptq,
6880					 softn->ipf_nat_utqe,
6881					 &softn->ipf_nat_stats.ns_active,
6882					 softn->ipf_nat_table_sz,
6883					 softn->ipf_nat_table_wm_low);
6884	}
6885
6886	SPL_X(s);
6887	return removed;
6888}
6889
6890
6891/* ------------------------------------------------------------------------ */
6892/* Function:    ipf_nat_flush_entry                                         */
6893/* Returns:     0 - always succeeds                                         */
6894/* Parameters:  softc(I) - pointer to soft context main structure           */
6895/*              entry(I) - pointer to NAT entry                             */
6896/* Write Locks: ipf_nat                                                     */
6897/*                                                                          */
6898/* This function is a stepping stone between ipf_queueflush() and           */
6899/* nat_dlete().  It is used so we can provide a uniform interface via the   */
6900/* ipf_queueflush() function.  Since the nat_delete() function returns void */
6901/* we translate that to mean it always succeeds in deleting something.      */
6902/* ------------------------------------------------------------------------ */
6903static int
6904ipf_nat_flush_entry(softc, entry)
6905	ipf_main_softc_t *softc;
6906	void *entry;
6907{
6908	ipf_nat_delete(softc, entry, NL_FLUSH);
6909	return 0;
6910}
6911
6912
6913/* ------------------------------------------------------------------------ */
6914/* Function:    ipf_nat_iterator                                            */
6915/* Returns:     int - 0 == ok, else error                                   */
6916/* Parameters:  softc(I) - pointer to soft context main structure           */
6917/*              token(I) - pointer to ipftoken structure                    */
6918/*              itp(I)   - pointer to ipfgeniter_t structure                */
6919/*              obj(I)   - pointer to data description structure            */
6920/*                                                                          */
6921/* This function acts as a handler for the SIOCGENITER ioctls that use a    */
6922/* generic structure to iterate through a list.  There are three different  */
6923/* linked lists of NAT related information to go through: NAT rules, active */
6924/* NAT mappings and the NAT fragment cache.                                 */
6925/* ------------------------------------------------------------------------ */
6926static int
6927ipf_nat_iterator(softc, token, itp, obj)
6928	ipf_main_softc_t *softc;
6929	ipftoken_t *token;
6930	ipfgeniter_t *itp;
6931	ipfobj_t *obj;
6932{
6933	int error;
6934
6935	if (itp->igi_data == NULL) {
6936		IPFERROR(60052);
6937		return EFAULT;
6938	}
6939
6940	switch (itp->igi_type)
6941	{
6942	case IPFGENITER_HOSTMAP :
6943	case IPFGENITER_IPNAT :
6944	case IPFGENITER_NAT :
6945		error = ipf_nat_getnext(softc, token, itp, obj);
6946		break;
6947
6948	case IPFGENITER_NATFRAG :
6949		error = ipf_frag_nat_next(softc, token, itp);
6950		break;
6951	default :
6952		IPFERROR(60053);
6953		error = EINVAL;
6954		break;
6955	}
6956
6957	return error;
6958}
6959
6960
6961/* ------------------------------------------------------------------------ */
6962/* Function:    ipf_nat_setpending                                          */
6963/* Returns:     Nil                                                         */
6964/* Parameters:  softc(I) - pointer to soft context main structure           */
6965/*              nat(I)   - pointer to NAT structure                         */
6966/* Locks:       ipf_nat (read or write)                                     */
6967/*                                                                          */
6968/* Put the NAT entry on to the pending queue - this queue has a very short  */
6969/* lifetime where items are put that can't be deleted straight away because */
6970/* of locking issues but we want to delete them ASAP, anyway.  In calling   */
6971/* this function, it is assumed that the owner (if there is one, as shown   */
6972/* by nat_me) is no longer interested in it.                                */
6973/* ------------------------------------------------------------------------ */
6974void
6975ipf_nat_setpending(softc, nat)
6976	ipf_main_softc_t *softc;
6977	nat_t *nat;
6978{
6979	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
6980	ipftq_t *oifq;
6981
6982	oifq = nat->nat_tqe.tqe_ifq;
6983	if (oifq != NULL)
6984		ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq,
6985			      &softn->ipf_nat_pending);
6986	else
6987		ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe,
6988				&softn->ipf_nat_pending, nat);
6989
6990	if (nat->nat_me != NULL) {
6991		*nat->nat_me = NULL;
6992		nat->nat_me = NULL;
6993		nat->nat_ref--;
6994		ASSERT(nat->nat_ref >= 0);
6995	}
6996}
6997
6998
6999/* ------------------------------------------------------------------------ */
7000/* Function:    nat_newrewrite                                              */
7001/* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
7002/*                    allow rule to be moved if IPN_ROUNDR is set.          */
7003/* Parameters:  fin(I) - pointer to packet information                      */
7004/*              nat(I) - pointer to NAT entry                               */
7005/*              ni(I)  - pointer to structure with misc. information needed */
7006/*                       to create new NAT entry.                           */
7007/* Write Lock:  ipf_nat                                                     */
7008/*                                                                          */
7009/* This function is responsible for setting up an active NAT session where  */
7010/* we are changing both the source and destination parameters at the same   */
7011/* time.  The loop in here works differently to elsewhere - each iteration  */
7012/* is responsible for changing a single parameter that can be incremented.  */
7013/* So one pass may increase the source IP#, next source port, next dest. IP#*/
7014/* and the last destination port for a total of 4 iterations to try each.   */
7015/* This is done to try and exhaustively use the translation space available.*/
7016/* ------------------------------------------------------------------------ */
7017static int
7018ipf_nat_newrewrite(fin, nat, nai)
7019	fr_info_t *fin;
7020	nat_t *nat;
7021	natinfo_t *nai;
7022{
7023	int src_search = 1;
7024	int dst_search = 1;
7025	fr_info_t frnat;
7026	u_32_t flags;
7027	u_short swap;
7028	ipnat_t *np;
7029	nat_t *natl;
7030	int l = 0;
7031	int changed;
7032
7033	natl = NULL;
7034	changed = -1;
7035	np = nai->nai_np;
7036	flags = nat->nat_flags;
7037	bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
7038
7039	nat->nat_hm = NULL;
7040
7041	do {
7042		changed = -1;
7043		/* TRACE (l, src_search, dst_search, np) */
7044		DT4(ipf_nat_rewrite_1, int, l, int, src_search, int, dst_search, ipnat_t *, np);
7045
7046		if ((src_search == 0) && (np->in_spnext == 0) &&
7047		    (dst_search == 0) && (np->in_dpnext == 0)) {
7048			if (l > 0)
7049				return -1;
7050		}
7051
7052		/*
7053		 * Find a new source address
7054		 */
7055		if (ipf_nat_nextaddr(fin, &np->in_nsrc, &frnat.fin_saddr,
7056				     &frnat.fin_saddr) == -1) {
7057			return -1;
7058		}
7059
7060		if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0xffffffff)) {
7061			src_search = 0;
7062			if (np->in_stepnext == 0)
7063				np->in_stepnext = 1;
7064
7065		} else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) {
7066			src_search = 0;
7067			if (np->in_stepnext == 0)
7068				np->in_stepnext = 1;
7069
7070		} else if (np->in_nsrcmsk == 0xffffffff) {
7071			src_search = 0;
7072			if (np->in_stepnext == 0)
7073				np->in_stepnext = 1;
7074
7075		} else if (np->in_nsrcmsk != 0xffffffff) {
7076			if (np->in_stepnext == 0 && changed == -1) {
7077				np->in_snip++;
7078				np->in_stepnext++;
7079				changed = 0;
7080			}
7081		}
7082
7083		if ((flags & IPN_TCPUDPICMP) != 0) {
7084			if (np->in_spnext != 0)
7085				frnat.fin_data[0] = np->in_spnext;
7086
7087			/*
7088			 * Standard port translation.  Select next port.
7089			 */
7090			if ((flags & IPN_FIXEDSPORT) != 0) {
7091				np->in_stepnext = 2;
7092			} else if ((np->in_stepnext == 1) &&
7093				   (changed == -1) && (natl != NULL)) {
7094				np->in_spnext++;
7095				np->in_stepnext++;
7096				changed = 1;
7097				if (np->in_spnext > np->in_spmax)
7098					np->in_spnext = np->in_spmin;
7099			}
7100		} else {
7101			np->in_stepnext = 2;
7102		}
7103		np->in_stepnext &= 0x3;
7104
7105		/*
7106		 * Find a new destination address
7107		 */
7108		/* TRACE (fin, np, l, frnat) */
7109		DT4(ipf_nat_rewrite_2, frinfo_t *, fin, ipnat_t *, np, int, l, frinfo_t *, &frnat);
7110
7111		if (ipf_nat_nextaddr(fin, &np->in_ndst, &frnat.fin_daddr,
7112				     &frnat.fin_daddr) == -1)
7113			return -1;
7114		if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) {
7115			dst_search = 0;
7116			if (np->in_stepnext == 2)
7117				np->in_stepnext = 3;
7118
7119		} else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0)) {
7120			dst_search = 0;
7121			if (np->in_stepnext == 2)
7122				np->in_stepnext = 3;
7123
7124		} else if (np->in_ndstmsk == 0xffffffff) {
7125			dst_search = 0;
7126			if (np->in_stepnext == 2)
7127				np->in_stepnext = 3;
7128
7129		} else if (np->in_ndstmsk != 0xffffffff) {
7130			if ((np->in_stepnext == 2) && (changed == -1) &&
7131			    (natl != NULL)) {
7132				changed = 2;
7133				np->in_stepnext++;
7134				np->in_dnip++;
7135			}
7136		}
7137
7138		if ((flags & IPN_TCPUDPICMP) != 0) {
7139			if (np->in_dpnext != 0)
7140				frnat.fin_data[1] = np->in_dpnext;
7141
7142			/*
7143			 * Standard port translation.  Select next port.
7144			 */
7145			if ((flags & IPN_FIXEDDPORT) != 0) {
7146				np->in_stepnext = 0;
7147			} else if (np->in_stepnext == 3 && changed == -1) {
7148				np->in_dpnext++;
7149				np->in_stepnext++;
7150				changed = 3;
7151				if (np->in_dpnext > np->in_dpmax)
7152					np->in_dpnext = np->in_dpmin;
7153			}
7154		} else {
7155			if (np->in_stepnext == 3)
7156				np->in_stepnext = 0;
7157		}
7158
7159		/* TRACE (frnat) */
7160		DT1(ipf_nat_rewrite_3, frinfo_t *, &frnat);
7161
7162		/*
7163		 * Here we do a lookup of the connection as seen from
7164		 * the outside.  If an IP# pair already exists, try
7165		 * again.  So if you have A->B becomes C->B, you can
7166		 * also have D->E become C->E but not D->B causing
7167		 * another C->B.  Also take protocol and ports into
7168		 * account when determining whether a pre-existing
7169		 * NAT setup will cause an external conflict where
7170		 * this is appropriate.
7171		 *
7172		 * fin_data[] is swapped around because we are doing a
7173		 * lookup of the packet is if it were moving in the opposite
7174		 * direction of the one we are working with now.
7175		 */
7176		if (flags & IPN_TCPUDP) {
7177			swap = frnat.fin_data[0];
7178			frnat.fin_data[0] = frnat.fin_data[1];
7179			frnat.fin_data[1] = swap;
7180		}
7181		if (fin->fin_out == 1) {
7182			natl = ipf_nat_inlookup(&frnat,
7183						flags & ~(SI_WILDP|NAT_SEARCH),
7184						(u_int)frnat.fin_p,
7185						frnat.fin_dst, frnat.fin_src);
7186
7187		} else {
7188			natl = ipf_nat_outlookup(&frnat,
7189						 flags & ~(SI_WILDP|NAT_SEARCH),
7190						 (u_int)frnat.fin_p,
7191						 frnat.fin_dst, frnat.fin_src);
7192		}
7193		if (flags & IPN_TCPUDP) {
7194			swap = frnat.fin_data[0];
7195			frnat.fin_data[0] = frnat.fin_data[1];
7196			frnat.fin_data[1] = swap;
7197		}
7198
7199		/* TRACE natl, in_stepnext, l */
7200		DT3(ipf_nat_rewrite_2, nat_t *, natl, ipnat_t *, np , int, l);
7201
7202		if ((natl != NULL) && (l > 8))	/* XXX 8 is arbitrary */
7203			return -1;
7204
7205		np->in_stepnext &= 0x3;
7206
7207		l++;
7208		changed = -1;
7209	} while (natl != NULL);
7210
7211	nat->nat_osrcip = fin->fin_src;
7212	nat->nat_odstip = fin->fin_dst;
7213	nat->nat_nsrcip = frnat.fin_src;
7214	nat->nat_ndstip = frnat.fin_dst;
7215
7216	if ((flags & IPN_TCPUDP) != 0) {
7217		nat->nat_osport = htons(fin->fin_data[0]);
7218		nat->nat_odport = htons(fin->fin_data[1]);
7219		nat->nat_nsport = htons(frnat.fin_data[0]);
7220		nat->nat_ndport = htons(frnat.fin_data[1]);
7221	} else if ((flags & IPN_ICMPQUERY) != 0) {
7222		nat->nat_oicmpid = fin->fin_data[1];
7223		nat->nat_nicmpid = frnat.fin_data[1];
7224	}
7225
7226	return 0;
7227}
7228
7229
7230/* ------------------------------------------------------------------------ */
7231/* Function:    nat_newdivert                                               */
7232/* Returns:     int - -1 == error, 0 == success                             */
7233/* Parameters:  fin(I) - pointer to packet information                      */
7234/*              nat(I) - pointer to NAT entry                               */
7235/*              ni(I)  - pointer to structure with misc. information needed */
7236/*                       to create new NAT entry.                           */
7237/* Write Lock:  ipf_nat                                                     */
7238/*                                                                          */
7239/* Create a new NAT  divert session as defined by the NAT rule.  This is    */
7240/* somewhat different to other NAT session creation routines because we     */
7241/* do not iterate through either port numbers or IP addresses, searching    */
7242/* for a unique mapping, however, a complimentary duplicate check is made.  */
7243/* ------------------------------------------------------------------------ */
7244static int
7245ipf_nat_newdivert(fin, nat, nai)
7246	fr_info_t *fin;
7247	nat_t *nat;
7248	natinfo_t *nai;
7249{
7250	ipf_main_softc_t *softc = fin->fin_main_soft;
7251	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7252	fr_info_t frnat;
7253	ipnat_t *np;
7254	nat_t *natl;
7255	int p;
7256
7257	np = nai->nai_np;
7258	bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
7259
7260	nat->nat_pr[0] = 0;
7261	nat->nat_osrcaddr = fin->fin_saddr;
7262	nat->nat_odstaddr = fin->fin_daddr;
7263	frnat.fin_saddr = htonl(np->in_snip);
7264	frnat.fin_daddr = htonl(np->in_dnip);
7265	if ((nat->nat_flags & IPN_TCPUDP) != 0) {
7266		nat->nat_osport = htons(fin->fin_data[0]);
7267		nat->nat_odport = htons(fin->fin_data[1]);
7268	} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
7269		nat->nat_oicmpid = fin->fin_data[1];
7270	}
7271
7272	if (np->in_redir & NAT_DIVERTUDP) {
7273		frnat.fin_data[0] = np->in_spnext;
7274		frnat.fin_data[1] = np->in_dpnext;
7275		frnat.fin_flx |= FI_TCPUDP;
7276		p = IPPROTO_UDP;
7277	} else {
7278		frnat.fin_flx &= ~FI_TCPUDP;
7279		p = IPPROTO_IPIP;
7280	}
7281
7282	if (fin->fin_out == 1) {
7283		natl = ipf_nat_inlookup(&frnat, 0, p,
7284					frnat.fin_dst, frnat.fin_src);
7285
7286	} else {
7287		natl = ipf_nat_outlookup(&frnat, 0, p,
7288					 frnat.fin_dst, frnat.fin_src);
7289	}
7290
7291	if (natl != NULL) {
7292		NBUMPSIDED(fin->fin_out, ns_divert_exist);
7293		DT3(ns_divert_exist, fr_info_t *, fin, nat_t *, nat, natinfo_t, nai);
7294		return -1;
7295	}
7296
7297	nat->nat_nsrcaddr = frnat.fin_saddr;
7298	nat->nat_ndstaddr = frnat.fin_daddr;
7299	if ((nat->nat_flags & IPN_TCPUDP) != 0) {
7300		nat->nat_nsport = htons(frnat.fin_data[0]);
7301		nat->nat_ndport = htons(frnat.fin_data[1]);
7302	} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
7303		nat->nat_nicmpid = frnat.fin_data[1];
7304	}
7305
7306	nat->nat_pr[fin->fin_out] = fin->fin_p;
7307	nat->nat_pr[1 - fin->fin_out] = p;
7308
7309	if (np->in_redir & NAT_REDIRECT)
7310		nat->nat_dir = NAT_DIVERTIN;
7311	else
7312		nat->nat_dir = NAT_DIVERTOUT;
7313
7314	return 0;
7315}
7316
7317
7318/* ------------------------------------------------------------------------ */
7319/* Function:    nat_builddivertmp                                           */
7320/* Returns:     int - -1 == error, 0 == success                             */
7321/* Parameters:  softn(I) - pointer to NAT context structure                 */
7322/*              np(I)    - pointer to a NAT rule                            */
7323/*                                                                          */
7324/* For divert rules, a skeleton packet representing what will be prepended  */
7325/* to the real packet is created.  Even though we don't have the full       */
7326/* packet here, a checksum is calculated that we update later when we       */
7327/* fill in the final details.  At present a 0 checksum for UDP is being set */
7328/* here because it is expected that divert will be used for localhost.      */
7329/* ------------------------------------------------------------------------ */
7330static int
7331ipf_nat_builddivertmp(softn, np)
7332	ipf_nat_softc_t *softn;
7333	ipnat_t *np;
7334{
7335	udphdr_t *uh;
7336	size_t len;
7337	ip_t *ip;
7338
7339	if ((np->in_redir & NAT_DIVERTUDP) != 0)
7340		len = sizeof(ip_t) + sizeof(udphdr_t);
7341	else
7342		len = sizeof(ip_t);
7343
7344	ALLOC_MB_T(np->in_divmp, len);
7345	if (np->in_divmp == NULL) {
7346		NBUMPD(ipf_nat_stats, ns_divert_build);
7347		return -1;
7348	}
7349
7350	/*
7351	 * First, the header to get the packet diverted to the new destination
7352	 */
7353	ip = MTOD(np->in_divmp, ip_t *);
7354	IP_V_A(ip, 4);
7355	IP_HL_A(ip, 5);
7356	ip->ip_tos = 0;
7357	if ((np->in_redir & NAT_DIVERTUDP) != 0)
7358		ip->ip_p = IPPROTO_UDP;
7359	else
7360		ip->ip_p = IPPROTO_IPIP;
7361	ip->ip_ttl = 255;
7362	ip->ip_off = 0;
7363	ip->ip_sum = 0;
7364	ip->ip_len = htons(len);
7365	ip->ip_id = 0;
7366	ip->ip_src.s_addr = htonl(np->in_snip);
7367	ip->ip_dst.s_addr = htonl(np->in_dnip);
7368	ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip));
7369
7370	if (np->in_redir & NAT_DIVERTUDP) {
7371		uh = (udphdr_t *)(ip + 1);
7372		uh->uh_sum = 0;
7373		uh->uh_ulen = 8;
7374		uh->uh_sport = htons(np->in_spnext);
7375		uh->uh_dport = htons(np->in_dpnext);
7376	}
7377
7378	return 0;
7379}
7380
7381
7382#define	MINDECAP	(sizeof(ip_t) + sizeof(udphdr_t) + sizeof(ip_t))
7383
7384/* ------------------------------------------------------------------------ */
7385/* Function:    nat_decap                                                   */
7386/* Returns:     int - -1 == error, 0 == success                             */
7387/* Parameters:  fin(I) - pointer to packet information                      */
7388/*              nat(I) - pointer to current NAT session                     */
7389/*                                                                          */
7390/* This function is responsible for undoing a packet's encapsulation in the */
7391/* reverse of an encap/divert rule.  After removing the outer encapsulation */
7392/* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/
7393/* match the "new" packet as it may still be used by IPFilter elsewhere.    */
7394/* We use "dir" here as the basis for some of the expectations about the    */
7395/* outer header.  If we return an error, the goal is to leave the original  */
7396/* packet information undisturbed - this falls short at the end where we'd  */
7397/* need to back a backup copy of "fin" - expensive.                         */
7398/* ------------------------------------------------------------------------ */
7399static int
7400ipf_nat_decap(fin, nat)
7401	fr_info_t *fin;
7402	nat_t *nat;
7403{
7404	ipf_main_softc_t *softc = fin->fin_main_soft;
7405	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7406	char *hdr;
7407	int hlen;
7408	int skip;
7409	mb_t *m;
7410
7411	if ((fin->fin_flx & FI_ICMPERR) != 0) {
7412		/*
7413		 * ICMP packets don't get decapsulated, instead what we need
7414		 * to do is change the ICMP reply from including (in the data
7415		 * portion for errors) the encapsulated packet that we sent
7416		 * out to something that resembles the original packet prior
7417		 * to encapsulation.  This isn't done here - all we're doing
7418		 * here is changing the outer address to ensure that it gets
7419		 * targetted back to the correct system.
7420		 */
7421
7422		if (nat->nat_dir & NAT_OUTBOUND) {
7423			u_32_t sum1, sum2, sumd;
7424
7425			sum1 = ntohl(fin->fin_daddr);
7426			sum2 = ntohl(nat->nat_osrcaddr);
7427			CALC_SUMD(sum1, sum2, sumd);
7428			fin->fin_ip->ip_dst = nat->nat_osrcip;
7429			fin->fin_daddr = nat->nat_osrcaddr;
7430#if !defined(_KERNEL) || SOLARIS
7431			ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, sumd, 0);
7432#endif
7433		}
7434		return 0;
7435	}
7436
7437	m = fin->fin_m;
7438	skip = fin->fin_hlen;
7439
7440	switch (nat->nat_dir)
7441	{
7442	case NAT_DIVERTIN :
7443	case NAT_DIVERTOUT :
7444		if (fin->fin_plen < MINDECAP)
7445			return -1;
7446		skip += sizeof(udphdr_t);
7447		break;
7448
7449	case NAT_ENCAPIN :
7450	case NAT_ENCAPOUT :
7451		if (fin->fin_plen < (skip + sizeof(ip_t)))
7452			return -1;
7453		break;
7454	default :
7455		return -1;
7456		/* NOTREACHED */
7457	}
7458
7459	/*
7460	 * The aim here is to keep the original packet details in "fin" for
7461	 * as long as possible so that returning with an error is for the
7462	 * original packet and there is little undoing work to do.
7463	 */
7464	if (M_LEN(m) < skip + sizeof(ip_t)) {
7465		if (ipf_pr_pullup(fin, skip + sizeof(ip_t)) == -1)
7466			return -1;
7467	}
7468
7469	hdr = MTOD(fin->fin_m, char *);
7470	fin->fin_ip = (ip_t *)(hdr + skip);
7471	hlen = IP_HL(fin->fin_ip) << 2;
7472
7473	if (ipf_pr_pullup(fin, skip + hlen) == -1) {
7474		NBUMPSIDED(fin->fin_out, ns_decap_pullup);
7475		return -1;
7476	}
7477
7478	fin->fin_hlen = hlen;
7479	fin->fin_dlen -= skip;
7480	fin->fin_plen -= skip;
7481	fin->fin_ipoff += skip;
7482
7483	if (ipf_makefrip(hlen, (ip_t *)hdr, fin) == -1) {
7484		NBUMPSIDED(fin->fin_out, ns_decap_bad);
7485		return -1;
7486	}
7487
7488	return skip;
7489}
7490
7491
7492/* ------------------------------------------------------------------------ */
7493/* Function:    nat_nextaddr                                                */
7494/* Returns:     int - -1 == bad input (no new address),                     */
7495/*                     0 == success and dst has new address                 */
7496/* Parameters:  fin(I) - pointer to packet information                      */
7497/*              na(I)  - how to generate new address                        */
7498/*              old(I) - original address being replaced                    */
7499/*              dst(O) - where to put the new address                       */
7500/* Write Lock:  ipf_nat                                                     */
7501/*                                                                          */
7502/* This function uses the contents of the "na" structure, in combination    */
7503/* with "old" to produce a new address to store in "dst".  Not all of the   */
7504/* possible uses of "na" will result in a new address.                      */
7505/* ------------------------------------------------------------------------ */
7506static int
7507ipf_nat_nextaddr(fin, na, old, dst)
7508	fr_info_t *fin;
7509	nat_addr_t *na;
7510	u_32_t *old, *dst;
7511{
7512	ipf_main_softc_t *softc = fin->fin_main_soft;
7513	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7514	u_32_t amin, amax, new;
7515	i6addr_t newip;
7516	int error;
7517
7518	new = 0;
7519	amin = na->na_addr[0].in4.s_addr;
7520
7521	switch (na->na_atype)
7522	{
7523	case FRI_RANGE :
7524		amax = na->na_addr[1].in4.s_addr;
7525		break;
7526
7527	case FRI_NETMASKED :
7528	case FRI_DYNAMIC :
7529	case FRI_NORMAL :
7530		/*
7531		 * Compute the maximum address by adding the inverse of the
7532		 * netmask to the minimum address.
7533		 */
7534		amax = ~na->na_addr[1].in4.s_addr;
7535		amax |= amin;
7536		break;
7537
7538	case FRI_LOOKUP :
7539		break;
7540
7541	case FRI_BROADCAST :
7542	case FRI_PEERADDR :
7543	case FRI_NETWORK :
7544	default :
7545		DT4(ns_na_atype, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new);
7546		return -1;
7547	}
7548
7549	error = -1;
7550
7551	if (na->na_atype == FRI_LOOKUP) {
7552		if (na->na_type == IPLT_DSTLIST) {
7553			error = ipf_dstlist_select_node(fin, na->na_ptr, dst,
7554							NULL);
7555		} else {
7556			NBUMPSIDE(fin->fin_out, ns_badnextaddr);
7557			DT4(ns_badnextaddr_1, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new);
7558		}
7559
7560	} else if (na->na_atype == IPLT_NONE) {
7561		/*
7562		 * 0/0 as the new address means leave it alone.
7563		 */
7564		if (na->na_addr[0].in4.s_addr == 0 &&
7565		    na->na_addr[1].in4.s_addr == 0) {
7566			new = *old;
7567
7568		/*
7569		 * 0/32 means get the interface's address
7570		 */
7571		} else if (na->na_addr[0].in4.s_addr == 0 &&
7572			   na->na_addr[1].in4.s_addr == 0xffffffff) {
7573			if (ipf_ifpaddr(softc, 4, na->na_atype,
7574					fin->fin_ifp, &newip, NULL) == -1) {
7575				NBUMPSIDED(fin->fin_out, ns_ifpaddrfail);
7576				DT4(ns_ifpaddrfail, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new);
7577				return -1;
7578			}
7579			new = newip.in4.s_addr;
7580		} else {
7581			new = htonl(na->na_nextip);
7582		}
7583		*dst = new;
7584		error = 0;
7585
7586	} else {
7587		NBUMPSIDE(fin->fin_out, ns_badnextaddr);
7588		DT4(ns_badnextaddr_2, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new);
7589	}
7590
7591	return error;
7592}
7593
7594
7595/* ------------------------------------------------------------------------ */
7596/* Function:    nat_nextaddrinit                                            */
7597/* Returns:     int - 0 == success, else error number                       */
7598/* Parameters:  softc(I) - pointer to soft context main structure           */
7599/*              na(I)      - NAT address information for generating new addr*/
7600/*              initial(I) - flag indicating if it is the first call for    */
7601/*                           this "na" structure.                           */
7602/*              ifp(I)     - network interface to derive address            */
7603/*                           information from.                              */
7604/*                                                                          */
7605/* This function is expected to be called in two scenarious: when a new NAT */
7606/* rule is loaded into the kernel and when the list of NAT rules is sync'd  */
7607/* up with the valid network interfaces (possibly due to them changing.)    */
7608/* To distinguish between these, the "initial" parameter is used.  If it is */
7609/* 1 then this indicates the rule has just been reloaded and 0 for when we  */
7610/* are updating information.  This difference is important because in       */
7611/* instances where we are not updating address information associated with  */
7612/* a network interface, we don't want to disturb what the "next" address to */
7613/* come out of ipf_nat_nextaddr() will be.                                  */
7614/* ------------------------------------------------------------------------ */
7615static int
7616ipf_nat_nextaddrinit(softc, base, na, initial, ifp)
7617	ipf_main_softc_t *softc;
7618	char *base;
7619	nat_addr_t *na;
7620	int initial;
7621	void *ifp;
7622{
7623
7624	switch (na->na_atype)
7625	{
7626	case FRI_LOOKUP :
7627		if (na->na_subtype == 0) {
7628			na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT,
7629							na->na_type,
7630							na->na_num,
7631							&na->na_func);
7632		} else if (na->na_subtype == 1) {
7633			na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT,
7634							 na->na_type,
7635							 base + na->na_num,
7636							 &na->na_func);
7637		}
7638		if (na->na_func == NULL) {
7639			IPFERROR(60060);
7640			return ESRCH;
7641		}
7642		if (na->na_ptr == NULL) {
7643			IPFERROR(60056);
7644			return ESRCH;
7645		}
7646		break;
7647
7648	case FRI_DYNAMIC :
7649	case FRI_BROADCAST :
7650	case FRI_NETWORK :
7651	case FRI_NETMASKED :
7652	case FRI_PEERADDR :
7653		if (ifp != NULL)
7654			(void )ipf_ifpaddr(softc, 4, na->na_atype, ifp,
7655					   &na->na_addr[0], &na->na_addr[1]);
7656		break;
7657
7658	case FRI_SPLIT :
7659	case FRI_RANGE :
7660		if (initial)
7661			na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
7662		break;
7663
7664	case FRI_NONE :
7665		na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
7666		return 0;
7667
7668	case FRI_NORMAL :
7669		na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
7670		break;
7671
7672	default :
7673		IPFERROR(60054);
7674		return EINVAL;
7675	}
7676
7677	if (initial && (na->na_atype == FRI_NORMAL)) {
7678		if (na->na_addr[0].in4.s_addr == 0) {
7679			if ((na->na_addr[1].in4.s_addr == 0xffffffff) ||
7680			    (na->na_addr[1].in4.s_addr == 0)) {
7681				return 0;
7682			}
7683		}
7684
7685		if (na->na_addr[1].in4.s_addr == 0xffffffff) {
7686			na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
7687		} else {
7688			na->na_nextip = ntohl(na->na_addr[0].in4.s_addr) + 1;
7689		}
7690	}
7691
7692	return 0;
7693}
7694
7695
7696/* ------------------------------------------------------------------------ */
7697/* Function:    ipf_nat_matchflush                                          */
7698/* Returns:     int - -1 == error, 0 == success                             */
7699/* Parameters:  softc(I) - pointer to soft context main structure           */
7700/*              softn(I) - pointer to NAT context structure                 */
7701/*              nat(I)   - pointer to current NAT session                   */
7702/*                                                                          */
7703/* ------------------------------------------------------------------------ */
7704static int
7705ipf_nat_matchflush(softc, softn, data)
7706	ipf_main_softc_t *softc;
7707	ipf_nat_softc_t *softn;
7708	caddr_t data;
7709{
7710	int *array, flushed, error;
7711	nat_t *nat, *natnext;
7712	ipfobj_t obj;
7713
7714	error = ipf_matcharray_load(softc, data, &obj, &array);
7715	if (error != 0)
7716		return error;
7717
7718	flushed = 0;
7719
7720	for (nat = softn->ipf_nat_instances; nat != NULL; nat = natnext) {
7721		natnext = nat->nat_next;
7722		if (ipf_nat_matcharray(nat, array, softc->ipf_ticks) == 0) {
7723			ipf_nat_delete(softc, nat, NL_FLUSH);
7724			flushed++;
7725		}
7726	}
7727
7728	obj.ipfo_retval = flushed;
7729	error = BCOPYOUT(&obj, data, sizeof(obj));
7730
7731	KFREES(array, array[0] * sizeof(*array));
7732
7733	return error;
7734}
7735
7736
7737/* ------------------------------------------------------------------------ */
7738/* Function:    ipf_nat_matcharray                                          */
7739/* Returns:     int - -1 == error, 0 == success                             */
7740/* Parameters:  fin(I) - pointer to packet information                      */
7741/*              nat(I) - pointer to current NAT session                     */
7742/*                                                                          */
7743/* ------------------------------------------------------------------------ */
7744static int
7745ipf_nat_matcharray(nat, array, ticks)
7746	nat_t *nat;
7747	int *array;
7748	u_long ticks;
7749{
7750	int i, n, *x, e, p;
7751
7752	e = 0;
7753	n = array[0];
7754	x = array + 1;
7755
7756	for (; n > 0; x += 3 + x[2]) {
7757		if (x[0] == IPF_EXP_END)
7758			break;
7759		e = 0;
7760
7761		n -= x[2] + 3;
7762		if (n < 0)
7763			break;
7764
7765		p = x[0] >> 16;
7766		if (p != 0 && p != nat->nat_pr[1])
7767			break;
7768
7769		switch (x[0])
7770		{
7771		case IPF_EXP_IP_PR :
7772			for (i = 0; !e && i < x[2]; i++) {
7773				e |= (nat->nat_pr[1] == x[i + 3]);
7774			}
7775			break;
7776
7777		case IPF_EXP_IP_SRCADDR :
7778			if (nat->nat_v[0] == 4) {
7779				for (i = 0; !e && i < x[2]; i++) {
7780					e |= ((nat->nat_osrcaddr & x[i + 4]) ==
7781					      x[i + 3]);
7782				}
7783			}
7784			if (nat->nat_v[1] == 4) {
7785				for (i = 0; !e && i < x[2]; i++) {
7786					e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
7787					      x[i + 3]);
7788				}
7789			}
7790			break;
7791
7792		case IPF_EXP_IP_DSTADDR :
7793			if (nat->nat_v[0] == 4) {
7794				for (i = 0; !e && i < x[2]; i++) {
7795					e |= ((nat->nat_odstaddr & x[i + 4]) ==
7796					      x[i + 3]);
7797				}
7798			}
7799			if (nat->nat_v[1] == 4) {
7800				for (i = 0; !e && i < x[2]; i++) {
7801					e |= ((nat->nat_ndstaddr & x[i + 4]) ==
7802					      x[i + 3]);
7803				}
7804			}
7805			break;
7806
7807		case IPF_EXP_IP_ADDR :
7808			for (i = 0; !e && i < x[2]; i++) {
7809				if (nat->nat_v[0] == 4) {
7810					e |= ((nat->nat_osrcaddr & x[i + 4]) ==
7811					      x[i + 3]);
7812				}
7813				if (nat->nat_v[1] == 4) {
7814					e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
7815					      x[i + 3]);
7816				}
7817				if (nat->nat_v[0] == 4) {
7818					e |= ((nat->nat_odstaddr & x[i + 4]) ==
7819					      x[i + 3]);
7820				}
7821				if (nat->nat_v[1] == 4) {
7822					e |= ((nat->nat_ndstaddr & x[i + 4]) ==
7823					      x[i + 3]);
7824				}
7825			}
7826			break;
7827
7828#ifdef USE_INET6
7829		case IPF_EXP_IP6_SRCADDR :
7830			if (nat->nat_v[0] == 6) {
7831				for (i = 0; !e && i < x[3]; i++) {
7832					e |= IP6_MASKEQ(&nat->nat_osrc6,
7833							x + i + 7, x + i + 3);
7834				}
7835			}
7836			if (nat->nat_v[1] == 6) {
7837				for (i = 0; !e && i < x[3]; i++) {
7838					e |= IP6_MASKEQ(&nat->nat_nsrc6,
7839							x + i + 7, x + i + 3);
7840				}
7841			}
7842			break;
7843
7844		case IPF_EXP_IP6_DSTADDR :
7845			if (nat->nat_v[0] == 6) {
7846				for (i = 0; !e && i < x[3]; i++) {
7847					e |= IP6_MASKEQ(&nat->nat_odst6,
7848							x + i + 7,
7849							x + i + 3);
7850				}
7851			}
7852			if (nat->nat_v[1] == 6) {
7853				for (i = 0; !e && i < x[3]; i++) {
7854					e |= IP6_MASKEQ(&nat->nat_ndst6,
7855							x + i + 7,
7856							x + i + 3);
7857				}
7858			}
7859			break;
7860
7861		case IPF_EXP_IP6_ADDR :
7862			for (i = 0; !e && i < x[3]; i++) {
7863				if (nat->nat_v[0] == 6) {
7864					e |= IP6_MASKEQ(&nat->nat_osrc6,
7865							x + i + 7,
7866							x + i + 3);
7867				}
7868				if (nat->nat_v[0] == 6) {
7869					e |= IP6_MASKEQ(&nat->nat_odst6,
7870							x + i + 7,
7871							x + i + 3);
7872				}
7873				if (nat->nat_v[1] == 6) {
7874					e |= IP6_MASKEQ(&nat->nat_nsrc6,
7875							x + i + 7,
7876							x + i + 3);
7877				}
7878				if (nat->nat_v[1] == 6) {
7879					e |= IP6_MASKEQ(&nat->nat_ndst6,
7880							x + i + 7,
7881							x + i + 3);
7882				}
7883			}
7884			break;
7885#endif
7886
7887		case IPF_EXP_UDP_PORT :
7888		case IPF_EXP_TCP_PORT :
7889			for (i = 0; !e && i < x[2]; i++) {
7890				e |= (nat->nat_nsport == x[i + 3]) ||
7891				     (nat->nat_ndport == x[i + 3]);
7892			}
7893			break;
7894
7895		case IPF_EXP_UDP_SPORT :
7896		case IPF_EXP_TCP_SPORT :
7897			for (i = 0; !e && i < x[2]; i++) {
7898				e |= (nat->nat_nsport == x[i + 3]);
7899			}
7900			break;
7901
7902		case IPF_EXP_UDP_DPORT :
7903		case IPF_EXP_TCP_DPORT :
7904			for (i = 0; !e && i < x[2]; i++) {
7905				e |= (nat->nat_ndport == x[i + 3]);
7906			}
7907			break;
7908
7909		case IPF_EXP_TCP_STATE :
7910			for (i = 0; !e && i < x[2]; i++) {
7911				e |= (nat->nat_tcpstate[0] == x[i + 3]) ||
7912				     (nat->nat_tcpstate[1] == x[i + 3]);
7913			}
7914			break;
7915
7916		case IPF_EXP_IDLE_GT :
7917			e |= (ticks - nat->nat_touched > x[3]);
7918			break;
7919		}
7920		e ^= x[1];
7921
7922		if (!e)
7923			break;
7924	}
7925
7926	return e;
7927}
7928
7929
7930/* ------------------------------------------------------------------------ */
7931/* Function:    ipf_nat_gettable                                            */
7932/* Returns:     int     - 0 = success, else error                           */
7933/* Parameters:  softc(I) - pointer to soft context main structure           */
7934/*              softn(I) - pointer to NAT context structure                 */
7935/*              data(I)  - pointer to ioctl data                            */
7936/*                                                                          */
7937/* This function handles ioctl requests for tables of nat information.      */
7938/* At present the only table it deals with is the hash bucket statistics.   */
7939/* ------------------------------------------------------------------------ */
7940static int
7941ipf_nat_gettable(softc, softn, data)
7942	ipf_main_softc_t *softc;
7943	ipf_nat_softc_t *softn;
7944	char *data;
7945{
7946	ipftable_t table;
7947	int error;
7948
7949	error = ipf_inobj(softc, data, NULL, &table, IPFOBJ_GTABLE);
7950	if (error != 0)
7951		return error;
7952
7953	switch (table.ita_type)
7954	{
7955	case IPFTABLE_BUCKETS_NATIN :
7956		error = COPYOUT(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
7957				table.ita_table,
7958				softn->ipf_nat_table_sz * sizeof(u_int));
7959		break;
7960
7961	case IPFTABLE_BUCKETS_NATOUT :
7962		error = COPYOUT(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
7963				table.ita_table,
7964				softn->ipf_nat_table_sz * sizeof(u_int));
7965		break;
7966
7967	default :
7968		IPFERROR(60058);
7969		return EINVAL;
7970	}
7971
7972	if (error != 0) {
7973		IPFERROR(60059);
7974		error = EFAULT;
7975	}
7976	return error;
7977}
7978
7979
7980/* ------------------------------------------------------------------------ */
7981/* Function:    ipf_nat_settimeout                                          */
7982/* Returns:     int  - 0 = success, else failure			    */
7983/* Parameters:  softc(I) - pointer to soft context main structure           */
7984/*              t(I) - pointer to tunable                                   */
7985/*              p(I) - pointer to new tuning data                           */
7986/*                                                                          */
7987/* Apply the timeout change to the NAT timeout queues.                      */
7988/* ------------------------------------------------------------------------ */
7989int
7990ipf_nat_settimeout(softc, t, p)
7991	struct ipf_main_softc_s *softc;
7992	ipftuneable_t *t;
7993	ipftuneval_t *p;
7994{
7995	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
7996
7997	if (!strncmp(t->ipft_name, "tcp_", 4))
7998		return ipf_settimeout_tcp(t, p, softn->ipf_nat_tcptq);
7999
8000	if (!strcmp(t->ipft_name, "udp_timeout")) {
8001		ipf_apply_timeout(&softn->ipf_nat_udptq, p->ipftu_int);
8002	} else if (!strcmp(t->ipft_name, "udp_ack_timeout")) {
8003		ipf_apply_timeout(&softn->ipf_nat_udpacktq, p->ipftu_int);
8004	} else if (!strcmp(t->ipft_name, "icmp_timeout")) {
8005		ipf_apply_timeout(&softn->ipf_nat_icmptq, p->ipftu_int);
8006	} else if (!strcmp(t->ipft_name, "icmp_ack_timeout")) {
8007		ipf_apply_timeout(&softn->ipf_nat_icmpacktq, p->ipftu_int);
8008	} else if (!strcmp(t->ipft_name, "ip_timeout")) {
8009		ipf_apply_timeout(&softn->ipf_nat_iptq, p->ipftu_int);
8010	} else {
8011		IPFERROR(60062);
8012		return ESRCH;
8013	}
8014	return 0;
8015}
8016
8017
8018/* ------------------------------------------------------------------------ */
8019/* Function:    ipf_nat_rehash                                              */
8020/* Returns:     int  - 0 = success, else failure			    */
8021/* Parameters:  softc(I) - pointer to soft context main structure           */
8022/*              t(I) - pointer to tunable                                   */
8023/*              p(I) - pointer to new tuning data                           */
8024/*                                                                          */
8025/* To change the size of the basic NAT table, we need to first allocate the */
8026/* new tables (lest it fails and we've got nowhere to store all of the NAT  */
8027/* sessions currently active) and then walk through the entire list and     */
8028/* insert them into the table.  There are two tables here: an inbound one   */
8029/* and an outbound one.  Each NAT entry goes into each table once.          */
8030/* ------------------------------------------------------------------------ */
8031int
8032ipf_nat_rehash(softc, t, p)
8033	ipf_main_softc_t *softc;
8034	ipftuneable_t *t;
8035	ipftuneval_t *p;
8036{
8037	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8038	nat_t **newtab[2], *nat, **natp;
8039	u_int *bucketlens[2];
8040	u_int maxbucket;
8041	u_int newsize;
8042	int error;
8043	u_int hv;
8044	int i;
8045
8046	newsize = p->ipftu_int;
8047	/*
8048	 * In case there is nothing to do...
8049	 */
8050	if (newsize == softn->ipf_nat_table_sz)
8051		return 0;
8052
8053	newtab[0] = NULL;
8054	newtab[1] = NULL;
8055	bucketlens[0] = NULL;
8056	bucketlens[1] = NULL;
8057	/*
8058	 * 4 tables depend on the NAT table size: the inbound looking table,
8059	 * the outbound lookup table and the hash chain length for each.
8060	 */
8061	KMALLOCS(newtab[0], nat_t **, newsize * sizeof(nat_t *));
8062	if (newtab[0] == NULL) {
8063		error = 60063;
8064		goto badrehash;
8065	}
8066
8067	KMALLOCS(newtab[1], nat_t **, newsize * sizeof(nat_t *));
8068	if (newtab[1] == NULL) {
8069		error = 60064;
8070		goto badrehash;
8071	}
8072
8073	KMALLOCS(bucketlens[0], u_int *, newsize * sizeof(u_int));
8074	if (bucketlens[0] == NULL) {
8075		error = 60065;
8076		goto badrehash;
8077	}
8078
8079	KMALLOCS(bucketlens[1], u_int *, newsize * sizeof(u_int));
8080	if (bucketlens[1] == NULL) {
8081		error = 60066;
8082		goto badrehash;
8083	}
8084
8085	/*
8086	 * Recalculate the maximum length based on the new size.
8087	 */
8088	for (maxbucket = 0, i = newsize; i > 0; i >>= 1)
8089		maxbucket++;
8090	maxbucket *= 2;
8091
8092	bzero((char *)newtab[0], newsize * sizeof(nat_t *));
8093	bzero((char *)newtab[1], newsize * sizeof(nat_t *));
8094	bzero((char *)bucketlens[0], newsize * sizeof(u_int));
8095	bzero((char *)bucketlens[1], newsize * sizeof(u_int));
8096
8097	WRITE_ENTER(&softc->ipf_nat);
8098
8099	if (softn->ipf_nat_table[0] != NULL) {
8100		KFREES(softn->ipf_nat_table[0],
8101		       softn->ipf_nat_table_sz *
8102		       sizeof(*softn->ipf_nat_table[0]));
8103	}
8104	softn->ipf_nat_table[0] = newtab[0];
8105
8106	if (softn->ipf_nat_table[1] != NULL) {
8107		KFREES(softn->ipf_nat_table[1],
8108		       softn->ipf_nat_table_sz *
8109		       sizeof(*softn->ipf_nat_table[1]));
8110	}
8111	softn->ipf_nat_table[1] = newtab[1];
8112
8113	if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) {
8114		KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
8115		       softn->ipf_nat_table_sz * sizeof(u_int));
8116	}
8117	softn->ipf_nat_stats.ns_side[0].ns_bucketlen = bucketlens[0];
8118
8119	if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) {
8120		KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
8121		       softn->ipf_nat_table_sz * sizeof(u_int));
8122	}
8123	softn->ipf_nat_stats.ns_side[1].ns_bucketlen = bucketlens[1];
8124
8125#ifdef USE_INET6
8126	if (softn->ipf_nat_stats.ns_side6[0].ns_bucketlen != NULL) {
8127		KFREES(softn->ipf_nat_stats.ns_side6[0].ns_bucketlen,
8128		       softn->ipf_nat_table_sz * sizeof(u_int));
8129	}
8130	softn->ipf_nat_stats.ns_side6[0].ns_bucketlen = bucketlens[0];
8131
8132	if (softn->ipf_nat_stats.ns_side6[1].ns_bucketlen != NULL) {
8133		KFREES(softn->ipf_nat_stats.ns_side6[1].ns_bucketlen,
8134		       softn->ipf_nat_table_sz * sizeof(u_int));
8135	}
8136	softn->ipf_nat_stats.ns_side6[1].ns_bucketlen = bucketlens[1];
8137#endif
8138
8139	softn->ipf_nat_maxbucket = maxbucket;
8140	softn->ipf_nat_table_sz = newsize;
8141	/*
8142	 * Walk through the entire list of NAT table entries and put them
8143	 * in the new NAT table, somewhere.  Because we have a new table,
8144	 * we need to restart the counter of how many chains are in use.
8145	 */
8146	softn->ipf_nat_stats.ns_side[0].ns_inuse = 0;
8147	softn->ipf_nat_stats.ns_side[1].ns_inuse = 0;
8148#ifdef USE_INET6
8149	softn->ipf_nat_stats.ns_side6[0].ns_inuse = 0;
8150	softn->ipf_nat_stats.ns_side6[1].ns_inuse = 0;
8151#endif
8152
8153	for (nat = softn->ipf_nat_instances; nat != NULL; nat = nat->nat_next) {
8154		nat->nat_hnext[0] = NULL;
8155		nat->nat_phnext[0] = NULL;
8156		hv = nat->nat_hv[0] % softn->ipf_nat_table_sz;
8157
8158		natp = &softn->ipf_nat_table[0][hv];
8159		if (*natp) {
8160			(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
8161		} else {
8162			NBUMPSIDE(0, ns_inuse);
8163		}
8164		nat->nat_phnext[0] = natp;
8165		nat->nat_hnext[0] = *natp;
8166		*natp = nat;
8167		NBUMPSIDE(0, ns_bucketlen[hv]);
8168
8169		nat->nat_hnext[1] = NULL;
8170		nat->nat_phnext[1] = NULL;
8171		hv = nat->nat_hv[1] % softn->ipf_nat_table_sz;
8172
8173		natp = &softn->ipf_nat_table[1][hv];
8174		if (*natp) {
8175			(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
8176		} else {
8177			NBUMPSIDE(1, ns_inuse);
8178		}
8179		nat->nat_phnext[1] = natp;
8180		nat->nat_hnext[1] = *natp;
8181		*natp = nat;
8182		NBUMPSIDE(1, ns_bucketlen[hv]);
8183	}
8184	RWLOCK_EXIT(&softc->ipf_nat);
8185
8186	return 0;
8187
8188badrehash:
8189	if (bucketlens[1] != NULL) {
8190		KFREES(bucketlens[0], newsize * sizeof(u_int));
8191	}
8192	if (bucketlens[0] != NULL) {
8193		KFREES(bucketlens[0], newsize * sizeof(u_int));
8194	}
8195	if (newtab[0] != NULL) {
8196		KFREES(newtab[0], newsize * sizeof(nat_t *));
8197	}
8198	if (newtab[1] != NULL) {
8199		KFREES(newtab[1], newsize * sizeof(nat_t *));
8200	}
8201	IPFERROR(error);
8202	return ENOMEM;
8203}
8204
8205
8206/* ------------------------------------------------------------------------ */
8207/* Function:    ipf_nat_rehash_rules                                        */
8208/* Returns:     int  - 0 = success, else failure			    */
8209/* Parameters:  softc(I) - pointer to soft context main structure           */
8210/*              t(I) - pointer to tunable                                   */
8211/*              p(I) - pointer to new tuning data                           */
8212/*                                                                          */
8213/* All of the NAT rules hang off of a hash table that is searched with a    */
8214/* hash on address after the netmask is applied.  There is a different table*/
8215/* for both inbound rules (rdr) and outbound (map.)  The resizing will only */
8216/* affect one of these two tables.                                          */
8217/* ------------------------------------------------------------------------ */
8218int
8219ipf_nat_rehash_rules(softc, t, p)
8220	ipf_main_softc_t *softc;
8221	ipftuneable_t *t;
8222	ipftuneval_t *p;
8223{
8224	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8225	ipnat_t **newtab, *np, ***old, **npp;
8226	u_int newsize;
8227	u_int mask;
8228	u_int hv;
8229
8230	newsize = p->ipftu_int;
8231	/*
8232	 * In case there is nothing to do...
8233	 */
8234	if (newsize == *t->ipft_pint)
8235		return 0;
8236
8237	/*
8238	 * All inbound rules have the NAT_REDIRECT bit set in in_redir and
8239	 * all outbound rules have either NAT_MAP or MAT_MAPBLK set.
8240	 * This if statement allows for some more generic code to be below,
8241	 * rather than two huge gobs of code that almost do the same thing.
8242	 */
8243	if (t->ipft_pint == &softn->ipf_nat_rdrrules_sz) {
8244		old = &softn->ipf_nat_rdr_rules;
8245		mask = NAT_REDIRECT;
8246	} else {
8247		old = &softn->ipf_nat_map_rules;
8248		mask = NAT_MAP|NAT_MAPBLK;
8249	}
8250
8251	KMALLOCS(newtab, ipnat_t **, newsize * sizeof(ipnat_t *));
8252	if (newtab == NULL) {
8253		IPFERROR(60067);
8254		return ENOMEM;
8255	}
8256
8257	bzero((char *)newtab, newsize * sizeof(ipnat_t *));
8258
8259	WRITE_ENTER(&softc->ipf_nat);
8260
8261	if (*old != NULL) {
8262		KFREES(*old, *t->ipft_pint * sizeof(ipnat_t **));
8263	}
8264	*old = newtab;
8265	*t->ipft_pint = newsize;
8266
8267	for (np = softn->ipf_nat_list; np != NULL; np = np->in_next) {
8268		if ((np->in_redir & mask) == 0)
8269			continue;
8270
8271		if (np->in_redir & NAT_REDIRECT) {
8272			np->in_rnext = NULL;
8273			hv = np->in_hv[0] % newsize;
8274			for (npp = newtab + hv; *npp != NULL; )
8275				npp = &(*npp)->in_rnext;
8276			np->in_prnext = npp;
8277			*npp = np;
8278		}
8279		if (np->in_redir & NAT_MAP) {
8280			np->in_mnext = NULL;
8281			hv = np->in_hv[1] % newsize;
8282			for (npp = newtab + hv; *npp != NULL; )
8283				npp = &(*npp)->in_mnext;
8284			np->in_pmnext = npp;
8285			*npp = np;
8286		}
8287
8288	}
8289	RWLOCK_EXIT(&softc->ipf_nat);
8290
8291	return 0;
8292}
8293
8294
8295/* ------------------------------------------------------------------------ */
8296/* Function:    ipf_nat_hostmap_rehash                                      */
8297/* Returns:     int  - 0 = success, else failure			    */
8298/* Parameters:  softc(I) - pointer to soft context main structure           */
8299/*              t(I) - pointer to tunable                                   */
8300/*              p(I) - pointer to new tuning data                           */
8301/*                                                                          */
8302/* Allocate and populate a new hash table that will contain a reference to  */
8303/* all of the active IP# translations currently in place.                   */
8304/* ------------------------------------------------------------------------ */
8305int
8306ipf_nat_hostmap_rehash(softc, t, p)
8307	ipf_main_softc_t *softc;
8308	ipftuneable_t *t;
8309	ipftuneval_t *p;
8310{
8311	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8312	hostmap_t *hm, **newtab;
8313	u_int newsize;
8314	u_int hv;
8315
8316	newsize = p->ipftu_int;
8317	/*
8318	 * In case there is nothing to do...
8319	 */
8320	if (newsize == *t->ipft_pint)
8321		return 0;
8322
8323	KMALLOCS(newtab, hostmap_t **, newsize * sizeof(hostmap_t *));
8324	if (newtab == NULL) {
8325		IPFERROR(60068);
8326		return ENOMEM;
8327	}
8328
8329	bzero((char *)newtab, newsize * sizeof(hostmap_t *));
8330
8331	WRITE_ENTER(&softc->ipf_nat);
8332	if (softn->ipf_hm_maptable != NULL) {
8333		KFREES(softn->ipf_hm_maptable,
8334		       softn->ipf_nat_hostmap_sz * sizeof(hostmap_t *));
8335	}
8336	softn->ipf_hm_maptable = newtab;
8337	softn->ipf_nat_hostmap_sz = newsize;
8338
8339	for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next) {
8340		hv = hm->hm_hv % softn->ipf_nat_hostmap_sz;
8341		hm->hm_hnext = softn->ipf_hm_maptable[hv];
8342		hm->hm_phnext = softn->ipf_hm_maptable + hv;
8343		if (softn->ipf_hm_maptable[hv] != NULL)
8344			softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
8345		softn->ipf_hm_maptable[hv] = hm;
8346	}
8347	RWLOCK_EXIT(&softc->ipf_nat);
8348
8349	return 0;
8350}
8351
8352
8353/* ------------------------------------------------------------------------ */
8354/* Function:    ipf_nat_add_tq                                              */
8355/* Parameters:  softc(I) - pointer to soft context main structure           */
8356/*                                                                          */
8357/* ------------------------------------------------------------------------ */
8358ipftq_t *
8359ipf_nat_add_tq(softc, ttl)
8360	ipf_main_softc_t *softc;
8361	int ttl;
8362{
8363	ipf_nat_softc_t *softs = softc->ipf_nat_soft;
8364
8365	return ipf_addtimeoutqueue(softc, &softs->ipf_nat_utqe, ttl);
8366}
8367
8368/* ------------------------------------------------------------------------ */
8369/* Function:    ipf_nat_uncreate                                            */
8370/* Returns:     Nil                                                         */
8371/* Parameters:  fin(I) - pointer to packet information                      */
8372/*                                                                          */
8373/* This function is used to remove a NAT entry from the NAT table when we   */
8374/* decide that the create was actually in error. It is thus assumed that    */
8375/* fin_flx will have both FI_NATED and FI_NATNEW set. Because we're dealing */
8376/* with the translated packet (not the original), we have to reverse the    */
8377/* lookup. Although doing the lookup is expensive (relatively speaking), it */
8378/* is not anticipated that this will be a frequent occurance for normal     */
8379/* traffic patterns.                                                        */
8380/* ------------------------------------------------------------------------ */
8381void
8382ipf_nat_uncreate(fin)
8383	fr_info_t *fin;
8384{
8385	ipf_main_softc_t *softc = fin->fin_main_soft;
8386	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
8387	int nflags;
8388	nat_t *nat;
8389
8390	switch (fin->fin_p)
8391	{
8392	case IPPROTO_TCP :
8393		nflags = IPN_TCP;
8394		break;
8395	case IPPROTO_UDP :
8396		nflags = IPN_UDP;
8397		break;
8398	default :
8399		nflags = 0;
8400		break;
8401	}
8402
8403	WRITE_ENTER(&softc->ipf_nat);
8404
8405	if (fin->fin_out == 0) {
8406		nat = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p,
8407					fin->fin_dst, fin->fin_src);
8408	} else {
8409		nat = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p,
8410				       fin->fin_src, fin->fin_dst);
8411	}
8412
8413	if (nat != NULL) {
8414		NBUMPSIDE(fin->fin_out, ns_uncreate[0]);
8415		ipf_nat_delete(softc, nat, NL_DESTROY);
8416	} else {
8417		NBUMPSIDE(fin->fin_out, ns_uncreate[1]);
8418	}
8419
8420	RWLOCK_EXIT(&softc->ipf_nat);
8421}
8422
8423
8424/* ------------------------------------------------------------------------ */
8425/* Function:    ipf_nat_cmp_rules                                           */
8426/* Returns:     int   - 0 == success, else rules do not match.              */
8427/* Parameters:  n1(I) - first rule to compare                               */
8428/*              n2(I) - first rule to compare                               */
8429/*                                                                          */
8430/* Compare two rules using pointers to each rule. A straight bcmp will not  */
8431/* work as some fields (such as in_dst, in_pkts) actually do change once    */
8432/* the rule has been loaded into the kernel. Whilst this function returns   */
8433/* various non-zero returns, they're strictly to aid in debugging. Use of   */
8434/* this function should simply care if the result is zero or not.           */
8435/* ------------------------------------------------------------------------ */
8436static int
8437ipf_nat_cmp_rules(n1, n2)
8438	ipnat_t *n1, *n2;
8439{
8440	if (n1->in_size != n2->in_size)
8441		return 1;
8442
8443	if (bcmp((char *)&n1->in_v, (char *)&n2->in_v,
8444		 offsetof(ipnat_t, in_ndst) - offsetof(ipnat_t, in_v)) != 0)
8445		return 2;
8446
8447	if (bcmp((char *)&n1->in_tuc, (char *)&n2->in_tuc,
8448		 n1->in_size - offsetof(ipnat_t, in_tuc)) != 0)
8449		return 3;
8450	if (n1->in_ndst.na_atype != n2->in_ndst.na_atype)
8451		return 5;
8452	if (n1->in_ndst.na_function != n2->in_ndst.na_function)
8453		return 6;
8454	if (bcmp((char *)&n1->in_ndst.na_addr, (char *)&n2->in_ndst.na_addr,
8455		 sizeof(n1->in_ndst.na_addr)))
8456		return 7;
8457	if (n1->in_nsrc.na_atype != n2->in_nsrc.na_atype)
8458		return 8;
8459	if (n1->in_nsrc.na_function != n2->in_nsrc.na_function)
8460		return 9;
8461	if (bcmp((char *)&n1->in_nsrc.na_addr, (char *)&n2->in_nsrc.na_addr,
8462		 sizeof(n1->in_nsrc.na_addr)))
8463		return 10;
8464	if (n1->in_odst.na_atype != n2->in_odst.na_atype)
8465		return 11;
8466	if (n1->in_odst.na_function != n2->in_odst.na_function)
8467		return 12;
8468	if (bcmp((char *)&n1->in_odst.na_addr, (char *)&n2->in_odst.na_addr,
8469		 sizeof(n1->in_odst.na_addr)))
8470		return 13;
8471	if (n1->in_osrc.na_atype != n2->in_osrc.na_atype)
8472		return 14;
8473	if (n1->in_osrc.na_function != n2->in_osrc.na_function)
8474		return 15;
8475	if (bcmp((char *)&n1->in_osrc.na_addr, (char *)&n2->in_osrc.na_addr,
8476		 sizeof(n1->in_osrc.na_addr)))
8477		return 16;
8478	return 0;
8479}
8480
8481
8482/* ------------------------------------------------------------------------ */
8483/* Function:    ipf_nat_rule_init                                           */
8484/* Returns:     int   - 0 == success, else rules do not match.              */
8485/* Parameters:  softc(I) - pointer to soft context main structure           */
8486/*              softn(I) - pointer to NAT context structure                 */
8487/*              n(I)     - first rule to compare                            */
8488/*                                                                          */
8489/* ------------------------------------------------------------------------ */
8490static int
8491ipf_nat_rule_init(softc, softn, n)
8492	ipf_main_softc_t *softc;
8493	ipf_nat_softc_t *softn;
8494	ipnat_t *n;
8495{
8496	int error = 0;
8497
8498	if ((n->in_flags & IPN_SIPRANGE) != 0)
8499		n->in_nsrcatype = FRI_RANGE;
8500
8501	if ((n->in_flags & IPN_DIPRANGE) != 0)
8502		n->in_ndstatype = FRI_RANGE;
8503
8504	if ((n->in_flags & IPN_SPLIT) != 0)
8505		n->in_ndstatype = FRI_SPLIT;
8506
8507	if ((n->in_redir & (NAT_MAP|NAT_REWRITE|NAT_DIVERTUDP)) != 0)
8508		n->in_spnext = n->in_spmin;
8509
8510	if ((n->in_redir & (NAT_REWRITE|NAT_DIVERTUDP)) != 0) {
8511		n->in_dpnext = n->in_dpmin;
8512	} else if (n->in_redir == NAT_REDIRECT) {
8513		n->in_dpnext = n->in_dpmin;
8514	}
8515
8516	n->in_stepnext = 0;
8517
8518	switch (n->in_v[0])
8519	{
8520	case 4 :
8521		error = ipf_nat_ruleaddrinit(softc, softn, n);
8522		if (error != 0)
8523			return error;
8524		break;
8525#ifdef USE_INET6
8526	case 6 :
8527		error = ipf_nat6_ruleaddrinit(softc, softn, n);
8528		if (error != 0)
8529			return error;
8530		break;
8531#endif
8532	default :
8533		break;
8534	}
8535
8536	if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) {
8537		/*
8538		 * Prerecord whether or not the destination of the divert
8539		 * is local or not to the interface the packet is going
8540		 * to be sent out.
8541		 */
8542		n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1],
8543						n->in_ifps[1], &n->in_ndstip6);
8544	}
8545
8546	return error;
8547}
8548
8549
8550/* ------------------------------------------------------------------------ */
8551/* Function:    ipf_nat_rule_fini                                           */
8552/* Returns:     int   - 0 == success, else rules do not match.              */
8553/* Parameters:  softc(I) - pointer to soft context main structure           */
8554/*              n(I)     - rule to work on                                  */
8555/*                                                                          */
8556/* This function is used to release any objects that were referenced during */
8557/* the rule initialisation. This is useful both when free'ing the rule and  */
8558/* when handling ioctls that need to initialise these fields but not        */
8559/* actually use them after the ioctl processing has finished.               */
8560/* ------------------------------------------------------------------------ */
8561static void
8562ipf_nat_rule_fini(softc, n)
8563	ipf_main_softc_t *softc;
8564	ipnat_t *n;
8565{
8566	if (n->in_odst.na_atype == FRI_LOOKUP && n->in_odst.na_ptr != NULL)
8567		ipf_lookup_deref(softc, n->in_odst.na_type, n->in_odst.na_ptr);
8568
8569	if (n->in_osrc.na_atype == FRI_LOOKUP && n->in_osrc.na_ptr != NULL)
8570		ipf_lookup_deref(softc, n->in_osrc.na_type, n->in_osrc.na_ptr);
8571
8572	if (n->in_ndst.na_atype == FRI_LOOKUP && n->in_ndst.na_ptr != NULL)
8573		ipf_lookup_deref(softc, n->in_ndst.na_type, n->in_ndst.na_ptr);
8574
8575	if (n->in_nsrc.na_atype == FRI_LOOKUP && n->in_nsrc.na_ptr != NULL)
8576		ipf_lookup_deref(softc, n->in_nsrc.na_type, n->in_nsrc.na_ptr);
8577
8578	if (n->in_divmp != NULL)
8579		FREE_MB_T(n->in_divmp);
8580}
8581