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