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