1/*
2 * Copyright (C) 1995-2003 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 *
6 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
7 * Use is subject to license terms.
8 */
9
10#if defined(KERNEL) || defined(_KERNEL)
11# undef KERNEL
12# undef _KERNEL
13# define        KERNEL	1
14# define        _KERNEL	1
15#endif
16#include <sys/errno.h>
17#include <sys/types.h>
18#include <sys/param.h>
19#include <sys/time.h>
20#include <sys/file.h>
21#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
22    defined(_KERNEL)
23# include "opt_ipfilter_log.h"
24#endif
25#if !defined(_KERNEL)
26# include <stdio.h>
27# include <string.h>
28# include <stdlib.h>
29# define _KERNEL
30# ifdef __OpenBSD__
31struct file;
32# endif
33# include <sys/uio.h>
34# undef _KERNEL
35#endif
36#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
37# include <sys/filio.h>
38# include <sys/fcntl.h>
39#else
40# include <sys/ioctl.h>
41#endif
42#if !defined(AIX)
43# include <sys/fcntl.h>
44#endif
45#if !defined(linux)
46# include <sys/protosw.h>
47#endif
48#include <sys/socket.h>
49#if defined(_KERNEL)
50# include <sys/systm.h>
51# if !defined(__SVR4) && !defined(__svr4__)
52#  include <sys/mbuf.h>
53# endif
54#endif
55#if defined(__SVR4) || defined(__svr4__)
56# include <sys/filio.h>
57# include <sys/byteorder.h>
58# ifdef _KERNEL
59#  include <sys/dditypes.h>
60# endif
61# include <sys/stream.h>
62# include <sys/kmem.h>
63#endif
64#if __FreeBSD_version >= 300000
65# include <sys/queue.h>
66#endif
67#include <net/if.h>
68#if __FreeBSD_version >= 300000
69# include <net/if_var.h>
70# if defined(_KERNEL) && !defined(IPFILTER_LKM)
71#  include "opt_ipfilter.h"
72# endif
73#endif
74#ifdef sun
75# include <net/af.h>
76#endif
77#include <net/route.h>
78#include <netinet/in.h>
79#include <netinet/in_systm.h>
80#include <netinet/ip.h>
81
82#ifdef RFC1825
83# include <vpn/md5.h>
84# include <vpn/ipsec.h>
85extern struct ifnet vpnif;
86#endif
87
88#if !defined(linux)
89# include <netinet/ip_var.h>
90#endif
91#include <netinet/tcp.h>
92#include <netinet/udp.h>
93#include <netinet/ip_icmp.h>
94#include "netinet/ip_compat.h"
95#include <netinet/tcpip.h>
96#include "netinet/ip_fil.h"
97#include "netinet/ip_nat.h"
98#include "netinet/ip_frag.h"
99#include "netinet/ip_state.h"
100#include "netinet/ip_proxy.h"
101#include "netinet/ipf_stack.h"
102#ifdef	IPFILTER_SYNC
103#include "netinet/ip_sync.h"
104#endif
105#if (__FreeBSD_version >= 300000)
106# include <sys/malloc.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 rcsid[] = "@(#)$Id: ip_nat6.c,v 1.2 2008/02/14 21:05:50 darrenr Exp $";
115#endif
116
117static	hostmap_t *nat6_hostmap __P((ipnat_t *, i6addr_t *, i6addr_t *,
118				    i6addr_t *, u_32_t, ipf_stack_t *));
119static	INLINE	int nat6_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
120static	INLINE	int nat6_newrdr __P((fr_info_t *, nat_t *, natinfo_t *));
121static	INLINE	int nat6_finalise __P((fr_info_t *, nat_t *, natinfo_t *,
122				      tcphdr_t *, nat_t **, int));
123static	void	nat6_tabmove __P((nat_t *, ipf_stack_t *));
124static	int	nat6_match __P((fr_info_t *, ipnat_t *));
125static	INLINE	int nat_icmpquerytype6 __P((int));
126
127
128/* ------------------------------------------------------------------------ */
129/* Function:    nat6_addrdr                                                 */
130/* Returns:     Nil                                                         */
131/* Parameters:  n(I) - pointer to NAT rule to add                           */
132/*                                                                          */
133/* Adds a redirect rule to the hash table of redirect rules and the list of */
134/* loaded NAT rules.  Updates the bitmask indicating which netmasks are in  */
135/* use by redirect rules.                                                   */
136/* ------------------------------------------------------------------------ */
137void nat6_addrdr(n, ifs)
138ipnat_t *n;
139ipf_stack_t *ifs;
140{
141	ipnat_t **np;
142	i6addr_t j;
143	u_int hv;
144	int k;
145
146	k = count6bits(n->in_out[1].i6);
147	if ((k >= 0) && (k != 128))
148		ifs->ifs_rdr6_masks[k >> 5] |= 1 << (k & 31);
149	IP6_AND(&n->in_out[0], &n->in_out[1], &j);
150	hv = NAT_HASH_FN6(&j, 0, ifs->ifs_ipf_rdrrules_sz);
151	np = ifs->ifs_rdr_rules + hv;
152	while (*np != NULL)
153		np = &(*np)->in_rnext;
154	n->in_rnext = NULL;
155	n->in_prnext = np;
156	n->in_hv = hv;
157	*np = n;
158}
159
160
161/* ------------------------------------------------------------------------ */
162/* Function:    nat6_addnat                                                 */
163/* Returns:     Nil                                                         */
164/* Parameters:  n(I) - pointer to NAT rule to add                           */
165/*                                                                          */
166/* Adds a NAT map rule to the hash table of rules and the list of  loaded   */
167/* NAT rules.  Updates the bitmask indicating which netmasks are in use by  */
168/* redirect rules.                                                          */
169/* ------------------------------------------------------------------------ */
170void nat6_addnat(n, ifs)
171ipnat_t *n;
172ipf_stack_t *ifs;
173{
174	ipnat_t **np;
175	i6addr_t j;
176	u_int hv;
177	int k;
178
179	k = count6bits(n->in_in[1].i6);
180	if ((k >= 0) && (k != 128))
181		ifs->ifs_nat6_masks[k >> 5] |= 1 << (k & 31);
182	IP6_AND(&n->in_in[0], &n->in_in[1], &j);
183	hv = NAT_HASH_FN6(&j, 0, ifs->ifs_ipf_natrules_sz);
184	np = ifs->ifs_nat_rules + hv;
185	while (*np != NULL)
186		np = &(*np)->in_mnext;
187	n->in_mnext = NULL;
188	n->in_pmnext = np;
189	n->in_hv = hv;
190	*np = n;
191}
192
193
194/* ------------------------------------------------------------------------ */
195/* Function:    nat6_hostmap                                                */
196/* Returns:     struct hostmap* - NULL if no hostmap could be created,      */
197/*                                else a pointer to the hostmapping to use  */
198/* Parameters:  np(I)   - pointer to NAT rule                               */
199/*              real(I) - real IP address                                   */
200/*              map(I)  - mapped IP address                                 */
201/*              port(I) - destination port number                           */
202/* Write Locks: ipf_nat                                                     */
203/*                                                                          */
204/* Check if an ip address has already been allocated for a given mapping    */
205/* that is not doing port based translation.  If is not yet allocated, then */
206/* create a new entry if a non-NULL NAT rule pointer has been supplied.     */
207/* ------------------------------------------------------------------------ */
208static struct hostmap *nat6_hostmap(np, src, dst, map, port, ifs)
209ipnat_t *np;
210i6addr_t *src, *dst, *map;
211u_32_t port;
212ipf_stack_t *ifs;
213{
214	hostmap_t *hm;
215	u_int hv;
216
217	hv = (src->i6[3] ^ dst->i6[3]);
218	hv += (src->i6[2] ^ dst->i6[2]);
219	hv += (src->i6[1] ^ dst->i6[1]);
220	hv += (src->i6[0] ^ dst->i6[0]);
221	hv += src->i6[3];
222	hv += src->i6[2];
223	hv += src->i6[1];
224	hv += src->i6[0];
225	hv += dst->i6[3];
226	hv += dst->i6[2];
227	hv += dst->i6[1];
228	hv += dst->i6[0];
229	hv %= HOSTMAP_SIZE;
230	for (hm = ifs->ifs_maptable[hv]; hm; hm = hm->hm_next)
231		if (IP6_EQ(&hm->hm_srcip6, src) &&
232		    IP6_EQ(&hm->hm_dstip6, dst) &&
233		    ((np == NULL) || (np == hm->hm_ipnat)) &&
234		    ((port == 0) || (port == hm->hm_port))) {
235			hm->hm_ref++;
236			return hm;
237		}
238
239	if (np == NULL)
240		return NULL;
241
242	KMALLOC(hm, hostmap_t *);
243	if (hm) {
244		hm->hm_hnext = ifs->ifs_ipf_hm_maplist;
245		hm->hm_phnext = &ifs->ifs_ipf_hm_maplist;
246		if (ifs->ifs_ipf_hm_maplist != NULL)
247			ifs->ifs_ipf_hm_maplist->hm_phnext = &hm->hm_hnext;
248		ifs->ifs_ipf_hm_maplist = hm;
249
250		hm->hm_next = ifs->ifs_maptable[hv];
251		hm->hm_pnext = ifs->ifs_maptable + hv;
252		if (ifs->ifs_maptable[hv] != NULL)
253			ifs->ifs_maptable[hv]->hm_pnext = &hm->hm_next;
254		ifs->ifs_maptable[hv] = hm;
255		hm->hm_ipnat = np;
256		hm->hm_src = *src;
257		hm->hm_dst = *dst;
258		hm->hm_map = *map;
259		hm->hm_ref = 1;
260		hm->hm_port = port;
261		hm->hm_v = 6;
262	}
263	return hm;
264}
265
266
267/* ------------------------------------------------------------------------ */
268/* Function:    nat6_newmap                                                 */
269/* Returns:     int - -1 == error, 0 == success                             */
270/* Parameters:  fin(I) - pointer to packet information                      */
271/*              nat(I) - pointer to NAT entry                               */
272/*              ni(I)  - pointer to structure with misc. information needed */
273/*                       to create new NAT entry.                           */
274/*                                                                          */
275/* Given an empty NAT structure, populate it with new information about a   */
276/* new NAT session, as defined by the matching NAT rule.                    */
277/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
278/* to the new IP address for the translation.                               */
279/* ------------------------------------------------------------------------ */
280static INLINE int nat6_newmap(fin, nat, ni)
281fr_info_t *fin;
282nat_t *nat;
283natinfo_t *ni;
284{
285	u_short st_port, dport, sport, port, sp, dp;
286	i6addr_t in, st_ip;
287	hostmap_t *hm;
288	u_32_t flags;
289	ipnat_t *np;
290	nat_t *natl;
291	int l;
292	ipf_stack_t *ifs = fin->fin_ifs;
293
294	/*
295	 * If it's an outbound packet which doesn't match any existing
296	 * record, then create a new port
297	 */
298	l = 0;
299	hm = NULL;
300	np = ni->nai_np;
301	st_ip = np->in_next6;
302	st_port = np->in_pnext;
303	flags = ni->nai_flags;
304	sport = ni->nai_sport;
305	dport = ni->nai_dport;
306
307	/*
308	 * Do a loop until we either run out of entries to try or we find
309	 * a NAT mapping that isn't currently being used.  This is done
310	 * because the change to the source is not (usually) being fixed.
311	 */
312	do {
313		port = 0;
314		in = np->in_next6;
315		if (l == 0) {
316			/*
317			 * Check to see if there is an existing NAT
318			 * setup for this IP address pair.
319			 */
320			hm = nat6_hostmap(np, &fin->fin_src6, &fin->fin_dst6,
321					 &in, 0, ifs);
322			if (hm != NULL)
323				in = hm->hm_map;
324		} else if ((l == 1) && (hm != NULL)) {
325			fr_hostmapdel(&hm);
326		}
327
328		nat->nat_hm = hm;
329
330		if (IP6_ISONES(&np->in_out[1]) && (np->in_pnext == 0)) {
331			if (l > 0)
332				return -1;
333		}
334
335		if (np->in_redir == NAT_BIMAP &&
336		    IP6_EQ(&np->in_in[1], &np->in_out[1])) {
337			i6addr_t temp;
338			/*
339			 * map the address block in a 1:1 fashion
340			 */
341			temp.i6[0] = fin->fin_src6.i6[0] &
342					~np->in_in[1].i6[0];
343			temp.i6[1] = fin->fin_src6.i6[1] &
344					~np->in_in[1].i6[1];
345			temp.i6[2] = fin->fin_src6.i6[2] &
346					~np->in_in[1].i6[2];
347			temp.i6[3] = fin->fin_src6.i6[3] &
348					~np->in_in[1].i6[3];
349			in = np->in_out[0];
350			IP6_MERGE(&in, &temp, &np->in_in[0]);
351
352#ifdef	NEED_128BIT_MATH
353		} else if (np->in_redir & NAT_MAPBLK) {
354			if ((l >= np->in_ppip) || ((l > 0) &&
355			     !(flags & IPN_TCPUDP)))
356				return -1;
357			/*
358			 * map-block - Calculate destination address.
359			 */
360			IP6_MASK(&in, &fin->fin_src6, &np->in_in[1]);
361			in = ntol(in);
362			inb = in;
363			in /= np->in_ippip;
364			in &= ntohl(~np->in_out[1]);
365			in += ntohl(np->in_out[0]);
366			/*
367			 * Calculate destination port.
368			 */
369			if ((flags & IPN_TCPUDP) &&
370			    (np->in_ppip != 0)) {
371				port = ntohs(sport) + l;
372				port %= np->in_ppip;
373				port += np->in_ppip *
374					(inb.s_addr % np->in_ippip);
375				port += MAPBLK_MINPORT;
376				port = htons(port);
377			}
378#endif
379
380		} else if (IP6_ISZERO(&np->in_out[0]) &&
381		    IP6_ISONES(&np->in_out[1])) {
382			/*
383			 * 0/128 - use the interface's IP address.
384			 */
385			if ((l > 0) ||
386			    fr_ifpaddr(6, FRI_NORMAL, fin->fin_ifp,
387				       (void *)&in, NULL, fin->fin_ifs) == -1)
388				return -1;
389
390		} else if (IP6_ISZERO(&np->in_out[0]) &&
391		    IP6_ISZERO(&np->in_out[1])) {
392			/*
393			 * 0/0 - use the original source address/port.
394			 */
395			if (l > 0)
396				return -1;
397			in = fin->fin_src6;
398
399		} else if (!IP6_ISONES(&np->in_out[1]) &&
400			   (np->in_pnext == 0) && ((l > 0) || (hm == NULL))) {
401			IP6_INC(&np->in_next6);
402		}
403
404		natl = NULL;
405
406		if ((flags & IPN_TCPUDP) &&
407		    ((np->in_redir & NAT_MAPBLK) == 0) &&
408		    (np->in_flags & IPN_AUTOPORTMAP)) {
409			/*EMPTY*/;
410#ifdef	NEED_128BIT_MATH
411			/*
412			 * XXX "ports auto" (without map-block)
413			 */
414			if ((l > 0) && (l % np->in_ppip == 0)) {
415				if (l > np->in_space) {
416					return -1;
417				} else if ((l > np->in_ppip) &&
418				    !IP6_ISONES(&np->in_out[1])) {
419					IP6_INC(&np->in_next6);
420				}
421			}
422			if (np->in_ppip != 0) {
423				port = ntohs(sport);
424				port += (l % np->in_ppip);
425				port %= np->in_ppip;
426				port += np->in_ppip *
427					(ntohl(fin->fin_src6) %
428					 np->in_ippip);
429				port += MAPBLK_MINPORT;
430				port = htons(port);
431			}
432#endif
433
434		} else if (((np->in_redir & NAT_MAPBLK) == 0) &&
435			   (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) {
436			/*
437			 * Standard port translation.  Select next port.
438			 */
439			if (np->in_flags & IPN_SEQUENTIAL) {
440				port = np->in_pnext;
441			} else {
442				port = ipf_random() % (ntohs(np->in_pmax) -
443						       ntohs(np->in_pmin));
444				port += ntohs(np->in_pmin);
445			}
446			port = htons(port);
447			np->in_pnext++;
448
449			if (np->in_pnext > ntohs(np->in_pmax)) {
450				np->in_pnext = ntohs(np->in_pmin);
451				if (!IP6_ISONES(&np->in_out[1])) {
452					IP6_INC(&np->in_next6);
453				}
454			}
455		}
456
457		if (np->in_flags & IPN_IPRANGE) {
458			if (IP6_GT(&np->in_next6, &np->in_out[1]))
459				np->in_next6 = np->in_out[0];
460		} else {
461			i6addr_t a1, a2;
462
463			a1 = np->in_next6;
464			IP6_INC(&a1);
465			IP6_AND(&a1, &np->in_out[1], &a2);
466			if (!IP6_ISONES(&np->in_out[1]) &&
467			    IP6_GT(&a2, &np->in_out[0])) {
468				IP6_ADD(&np->in_out[0], 1, &np->in_next6);
469			}
470		}
471
472		if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
473			port = sport;
474
475		/*
476		 * Here we do a lookup of the connection as seen from
477		 * the outside.  If an IP# pair already exists, try
478		 * again.  So if you have A->B becomes C->B, you can
479		 * also have D->E become C->E but not D->B causing
480		 * another C->B.  Also take protocol and ports into
481		 * account when determining whether a pre-existing
482		 * NAT setup will cause an external conflict where
483		 * this is appropriate.
484		 */
485		sp = fin->fin_data[0];
486		dp = fin->fin_data[1];
487		fin->fin_data[0] = fin->fin_data[1];
488		fin->fin_data[1] = htons(port);
489		natl = nat6_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
490		    (u_int)fin->fin_p, &fin->fin_dst6.in6, &in.in6);
491		fin->fin_data[0] = sp;
492		fin->fin_data[1] = dp;
493
494		/*
495		 * Has the search wrapped around and come back to the
496		 * start ?
497		 */
498		if ((natl != NULL) &&
499		    (np->in_pnext != 0) && (st_port == np->in_pnext) &&
500		    !IP6_ISZERO(&np->in_next6) &&
501		    IP6_EQ(&st_ip, &np->in_next6))
502			return -1;
503		l++;
504	} while (natl != NULL);
505
506	if (np->in_space > 0)
507		np->in_space--;
508
509	/* Setup the NAT table */
510	nat->nat_inip6 = fin->fin_src6;
511	nat->nat_outip6 = in;
512	nat->nat_oip6 = fin->fin_dst6;
513	if (nat->nat_hm == NULL)
514		nat->nat_hm = nat6_hostmap(np, &fin->fin_src6, &fin->fin_dst6,
515		    &nat->nat_outip6, 0, ifs);
516
517	if (flags & IPN_TCPUDP) {
518		nat->nat_inport = sport;
519		nat->nat_outport = port;	/* sport */
520		nat->nat_oport = dport;
521		((tcphdr_t *)fin->fin_dp)->th_sport = port;
522	} else if (flags & IPN_ICMPQUERY) {
523		((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = port;
524		nat->nat_inport = port;
525		nat->nat_outport = port;
526	}
527
528	ni->nai_port = port;
529	ni->nai_nport = dport;
530	return 0;
531}
532
533
534/* ------------------------------------------------------------------------ */
535/* Function:    nat6_newrdr                                                 */
536/* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
537/*                    allow rule to be moved if IPN_ROUNDR is set.          */
538/* Parameters:  fin(I) - pointer to packet information                      */
539/*              nat(I) - pointer to NAT entry                               */
540/*              ni(I)  - pointer to structure with misc. information needed */
541/*                       to create new NAT entry.                           */
542/*                                                                          */
543/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
544/* to the new IP address for the translation.                               */
545/* ------------------------------------------------------------------------ */
546static INLINE int nat6_newrdr(fin, nat, ni)
547fr_info_t *fin;
548nat_t *nat;
549natinfo_t *ni;
550{
551	u_short nport, dport, sport;
552	i6addr_t in;
553	u_short sp, dp;
554	hostmap_t *hm;
555	u_32_t flags;
556	ipnat_t *np;
557	nat_t *natl;
558	int move;
559	ipf_stack_t *ifs = fin->fin_ifs;
560
561	move = 1;
562	hm = NULL;
563	in.i6[0] = 0;
564	in.i6[1] = 0;
565	in.i6[2] = 0;
566	in.i6[3] = 0;
567	np = ni->nai_np;
568	flags = ni->nai_flags;
569	sport = ni->nai_sport;
570	dport = ni->nai_dport;
571
572	/*
573	 * If the matching rule has IPN_STICKY set, then we want to have the
574	 * same rule kick in as before.  Why would this happen?  If you have
575	 * a collection of rdr rules with "round-robin sticky", the current
576	 * packet might match a different one to the previous connection but
577	 * we want the same destination to be used.
578	 */
579	if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) ==
580	    (IPN_ROUNDR|IPN_STICKY)) {
581		hm = nat6_hostmap(NULL, &fin->fin_src6, &fin->fin_dst6, &in,
582		    (u_32_t)dport, ifs);
583		if (hm != NULL) {
584			in = hm->hm_map;
585			np = hm->hm_ipnat;
586			ni->nai_np = np;
587			move = 0;
588		}
589	}
590
591	/*
592	 * Otherwise, it's an inbound packet. Most likely, we don't
593	 * want to rewrite source ports and source addresses. Instead,
594	 * we want to rewrite to a fixed internal address and fixed
595	 * internal port.
596	 */
597	if (np->in_flags & IPN_SPLIT) {
598		in = np->in_next6;
599
600		if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
601			hm = nat6_hostmap(np, &fin->fin_src6, &fin->fin_dst6,
602			    &in, (u_32_t)dport, ifs);
603			if (hm != NULL) {
604				in = hm->hm_map;
605				move = 0;
606			}
607		}
608
609		if (hm == NULL || hm->hm_ref == 1) {
610			if (IP6_EQ(&np->in_in[0], &in)) {
611				np->in_next6 = np->in_in[1];
612				move = 0;
613			} else {
614				np->in_next6 = np->in_in[0];
615			}
616		}
617
618	} else if (IP6_ISZERO(&np->in_in[0]) &&
619	    IP6_ISONES(&np->in_in[1])) {
620		/*
621		 * 0/128 - use the interface's IP address.
622		 */
623		if (fr_ifpaddr(6, FRI_NORMAL, fin->fin_ifp, (void *)&in, NULL,
624			   fin->fin_ifs) == -1)
625			return -1;
626
627	} else if (IP6_ISZERO(&np->in_in[0]) &&
628	    IP6_ISZERO(&np->in_in[1])) {
629		/*
630		 * 0/0 - use the original destination address/port.
631		 */
632		in = fin->fin_dst6;
633
634	} else if (np->in_redir == NAT_BIMAP &&
635	    IP6_EQ(&np->in_in[1], &np->in_out[1])) {
636		i6addr_t temp;
637		/*
638		 * map the address block in a 1:1 fashion
639		 */
640		temp.i6[0] = fin->fin_dst6.i6[0] & ~np->in_in[1].i6[0];
641		temp.i6[1] = fin->fin_dst6.i6[1] & ~np->in_in[1].i6[1];
642		temp.i6[2] = fin->fin_dst6.i6[2] & ~np->in_in[1].i6[2];
643		temp.i6[3] = fin->fin_dst6.i6[3] & ~np->in_in[1].i6[3];
644		in = np->in_in[0];
645		IP6_MERGE(&in, &temp, &np->in_in[1]);
646	} else {
647		in = np->in_in[0];
648	}
649
650	if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
651		nport = dport;
652	else {
653		/*
654		 * Whilst not optimized for the case where
655		 * pmin == pmax, the gain is not significant.
656		 */
657		if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
658		    (np->in_pmin != np->in_pmax)) {
659			nport = ntohs(dport) - ntohs(np->in_pmin) +
660				ntohs(np->in_pnext);
661			nport = htons(nport);
662		} else
663			nport = np->in_pnext;
664	}
665
666	/*
667	 * When the redirect-to address is set to 0.0.0.0, just
668	 * assume a blank `forwarding' of the packet.  We don't
669	 * setup any translation for this either.
670	 */
671	if (IP6_ISZERO(&in)) {
672		if (nport == dport)
673			return -1;
674		in = fin->fin_dst6;
675	}
676
677	/*
678	 * Check to see if this redirect mapping already exists and if
679	 * it does, return "failure" (allowing it to be created will just
680	 * cause one or both of these "connections" to stop working.)
681	 */
682	sp = fin->fin_data[0];
683	dp = fin->fin_data[1];
684	fin->fin_data[1] = fin->fin_data[0];
685	fin->fin_data[0] = ntohs(nport);
686	natl = nat6_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
687	    (u_int)fin->fin_p, &in.in6, &fin->fin_src6.in6);
688	fin->fin_data[0] = sp;
689	fin->fin_data[1] = dp;
690	if (natl != NULL)
691		return -1;
692
693	nat->nat_inip6 = in;
694	nat->nat_outip6 = fin->fin_dst6;
695	nat->nat_oip6 = fin->fin_src6;
696	if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0))
697		nat->nat_hm = nat6_hostmap(np, &fin->fin_src6,
698		    &fin->fin_dst6, &in, (u_32_t)dport, ifs);
699
700	ni->nai_nport = nport;
701	ni->nai_port = sport;
702
703	if (flags & IPN_TCPUDP) {
704		nat->nat_inport = nport;
705		nat->nat_outport = dport;
706		nat->nat_oport = sport;
707		((tcphdr_t *)fin->fin_dp)->th_dport = nport;
708	} else if (flags & IPN_ICMPQUERY) {
709		((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = nport;
710		nat->nat_inport = nport;
711		nat->nat_outport = nport;
712	}
713
714	return move;
715}
716
717/* ------------------------------------------------------------------------ */
718/* Function:    nat6_new                                                    */
719/* Returns:     nat_t* - NULL == failure to create new NAT structure,       */
720/*                       else pointer to new NAT structure                  */
721/* Parameters:  fin(I)       - pointer to packet information                */
722/*              np(I)        - pointer to NAT rule                          */
723/*              natsave(I)   - pointer to where to store NAT struct pointer */
724/*              flags(I)     - flags describing the current packet          */
725/*              direction(I) - direction of packet (in/out)                 */
726/* Write Lock:  ipf_nat                                                     */
727/*                                                                          */
728/* Attempts to create a new NAT entry.  Does not actually change the packet */
729/* in any way.                                                              */
730/*                                                                          */
731/* This fucntion is in three main parts: (1) deal with creating a new NAT   */
732/* structure for a "MAP" rule (outgoing NAT translation); (2) deal with     */
733/* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
734/* and (3) building that structure and putting it into the NAT table(s).    */
735/* ------------------------------------------------------------------------ */
736nat_t *nat6_new(fin, np, natsave, flags, direction)
737fr_info_t *fin;
738ipnat_t *np;
739nat_t **natsave;
740u_int flags;
741int direction;
742{
743	tcphdr_t *tcp = NULL;
744	hostmap_t *hm = NULL;
745	nat_t *nat, *natl;
746	u_int nflags;
747	natinfo_t ni;
748	int move;
749	ipf_stack_t *ifs = fin->fin_ifs;
750
751	/*
752	 * Trigger automatic call to ipf_extraflush() if the
753	 * table has reached capcity specified by hi watermark.
754	 */
755	if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_level_hi)
756		ifs->ifs_nat_doflush = 1;
757
758	if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) {
759		ifs->ifs_nat_stats.ns_memfail++;
760		return NULL;
761	}
762
763	move = 1;
764	nflags = np->in_flags & flags;
765	nflags &= NAT_FROMRULE;
766
767	ni.nai_np = np;
768	ni.nai_nflags = nflags;
769	ni.nai_flags = flags;
770
771	/* Give me a new nat */
772	KMALLOC(nat, nat_t *);
773	if (nat == NULL) {
774		ifs->ifs_nat_stats.ns_memfail++;
775		/*
776		 * Try to automatically tune the max # of entries in the
777		 * table allowed to be less than what will cause kmem_alloc()
778		 * to fail and try to eliminate panics due to out of memory
779		 * conditions arising.
780		 */
781		if (ifs->ifs_ipf_nattable_max > ifs->ifs_ipf_nattable_sz) {
782			ifs->ifs_ipf_nattable_max =
783			    ifs->ifs_nat_stats.ns_inuse - 100;
784			printf("ipf_nattable_max reduced to %d\n",
785			    ifs->ifs_ipf_nattable_max);
786		}
787		return NULL;
788	}
789
790	if (flags & IPN_TCPUDP) {
791		tcp = fin->fin_dp;
792		ni.nai_sport = htons(fin->fin_sport);
793		ni.nai_dport = htons(fin->fin_dport);
794	} else if (flags & IPN_ICMPQUERY) {
795		/*
796		 * In the ICMP query NAT code, we translate the ICMP id fields
797		 * to make them unique. This is indepedent of the ICMP type
798		 * (e.g. in the unlikely event that a host sends an echo and
799		 * an tstamp request with the same id, both packets will have
800		 * their ip address/id field changed in the same way).
801		 *
802		 * The icmp_id field is used by the sender to identify the
803		 * process making the icmp request. (the receiver justs
804		 * copies it back in its response). So, it closely matches
805		 * the concept of source port. We overlay sport, so we can
806		 * maximally reuse the existing code.
807		 */
808		ni.nai_sport = ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id;
809		ni.nai_dport = ni.nai_sport;
810	}
811
812	bzero((char *)nat, sizeof (*nat));
813	nat->nat_flags = flags;
814	nat->nat_redir = np->in_redir;
815
816	if ((flags & NAT_SLAVE) == 0) {
817		MUTEX_ENTER(&ifs->ifs_ipf_nat_new);
818	}
819
820	/*
821	 * Search the current table for a match.
822	 */
823	if (direction == NAT_OUTBOUND) {
824		/*
825		 * We can now arrange to call this for the same connection
826		 * because ipf_nat_new doesn't protect the code path into
827		 * this function.
828		 */
829		natl = nat6_outlookup(fin, nflags, (u_int)fin->fin_p,
830		    &fin->fin_src6.in6, &fin->fin_dst6.in6);
831		if (natl != NULL) {
832			KFREE(nat);
833			nat = natl;
834			goto done;
835		}
836
837		move = nat6_newmap(fin, nat, &ni);
838		if (move == -1)
839			goto badnat;
840
841		np = ni.nai_np;
842	} else {
843		/*
844		 * NAT_INBOUND is used only for redirects rules
845		 */
846		natl = nat6_inlookup(fin, nflags, (u_int)fin->fin_p,
847		    &fin->fin_src6.in6, &fin->fin_dst6.in6);
848		if (natl != NULL) {
849			KFREE(nat);
850			nat = natl;
851			goto done;
852		}
853
854		move = nat6_newrdr(fin, nat, &ni);
855		if (move == -1)
856			goto badnat;
857
858		np = ni.nai_np;
859	}
860
861	if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
862		if (np->in_redir == NAT_REDIRECT) {
863			nat_delrdr(np);
864			nat6_addrdr(np, ifs);
865		} else if (np->in_redir == NAT_MAP) {
866			nat_delnat(np);
867			nat6_addnat(np, ifs);
868		}
869	}
870
871	if (nat6_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) {
872		goto badnat;
873	}
874
875	nat_calc_chksum_diffs(nat);
876
877	if (flags & SI_WILDP)
878		ifs->ifs_nat_stats.ns_wilds++;
879	goto done;
880badnat:
881	ifs->ifs_nat_stats.ns_badnat++;
882	if ((hm = nat->nat_hm) != NULL)
883		fr_hostmapdel(&hm);
884	KFREE(nat);
885	nat = NULL;
886done:
887	if ((flags & NAT_SLAVE) == 0) {
888		MUTEX_EXIT(&ifs->ifs_ipf_nat_new);
889	}
890	return nat;
891}
892
893
894/* ------------------------------------------------------------------------ */
895/* Function:    nat6_finalise                                               */
896/* Returns:     int - 0 == sucess, -1 == failure                            */
897/* Parameters:  fin(I) - pointer to packet information                      */
898/*              nat(I) - pointer to NAT entry                               */
899/*              ni(I)  - pointer to structure with misc. information needed */
900/*                       to create new NAT entry.                           */
901/* Write Lock:  ipf_nat                                                     */
902/*                                                                          */
903/* This is the tail end of constructing a new NAT entry and is the same     */
904/* for both IPv4 and IPv6.                                                  */
905/* ------------------------------------------------------------------------ */
906/*ARGSUSED*/
907static INLINE int nat6_finalise(fin, nat, ni, tcp, natsave, direction)
908fr_info_t *fin;
909nat_t *nat;
910natinfo_t *ni;
911tcphdr_t *tcp;
912nat_t **natsave;
913int direction;
914{
915	frentry_t *fr;
916	ipnat_t *np;
917	ipf_stack_t *ifs = fin->fin_ifs;
918
919	np = ni->nai_np;
920
921	COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0], fin->fin_v);
922
923#ifdef	IPFILTER_SYNC
924	if ((nat->nat_flags & SI_CLONE) == 0)
925		nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat);
926#endif
927
928	nat->nat_me = natsave;
929	nat->nat_dir = direction;
930	nat->nat_ifps[0] = np->in_ifps[0];
931	nat->nat_ifps[1] = np->in_ifps[1];
932	nat->nat_ptr = np;
933	nat->nat_p = fin->fin_p;
934	nat->nat_v = fin->fin_v;
935	nat->nat_mssclamp = np->in_mssclamp;
936	fr = fin->fin_fr;
937	nat->nat_fr = fr;
938	nat->nat_v = 6;
939
940#ifdef	IPF_V6_PROXIES
941	if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0))
942		if (appr_new(fin, nat) == -1)
943			return -1;
944#endif
945
946	if (nat6_insert(nat, fin->fin_rev, ifs) == 0) {
947		if (ifs->ifs_nat_logging)
948			nat_log(nat, (u_int)np->in_redir, ifs);
949		np->in_use++;
950		if (fr != NULL) {
951			MUTEX_ENTER(&fr->fr_lock);
952			fr->fr_ref++;
953			MUTEX_EXIT(&fr->fr_lock);
954		}
955		return 0;
956	}
957
958	/*
959	 * nat6_insert failed, so cleanup time...
960	 */
961	return -1;
962}
963
964
965/* ------------------------------------------------------------------------ */
966/* Function:   nat6_insert                                                  */
967/* Returns:    int - 0 == sucess, -1 == failure                             */
968/* Parameters: nat(I) - pointer to NAT structure                            */
969/*             rev(I) - flag indicating forward/reverse direction of packet */
970/* Write Lock: ipf_nat                                                      */
971/*                                                                          */
972/* Insert a NAT entry into the hash tables for searching and add it to the  */
973/* list of active NAT entries.  Adjust global counters when complete.       */
974/* ------------------------------------------------------------------------ */
975int nat6_insert(nat, rev, ifs)
976nat_t	*nat;
977int	rev;
978ipf_stack_t *ifs;
979{
980	u_int hv1, hv2;
981	nat_t **natp;
982
983	/*
984	 * Try and return an error as early as possible, so calculate the hash
985	 * entry numbers first and then proceed.
986	 */
987	if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
988		hv1 = NAT_HASH_FN6(&nat->nat_inip6, nat->nat_inport,
989				  0xffffffff);
990		hv1 = NAT_HASH_FN6(&nat->nat_oip6, hv1 + nat->nat_oport,
991				  ifs->ifs_ipf_nattable_sz);
992		hv2 = NAT_HASH_FN6(&nat->nat_outip6, nat->nat_outport,
993				  0xffffffff);
994		hv2 = NAT_HASH_FN6(&nat->nat_oip6, hv2 + nat->nat_oport,
995				  ifs->ifs_ipf_nattable_sz);
996	} else {
997		hv1 = NAT_HASH_FN6(&nat->nat_inip6, 0, 0xffffffff);
998		hv1 = NAT_HASH_FN6(&nat->nat_oip6, hv1,
999				  ifs->ifs_ipf_nattable_sz);
1000		hv2 = NAT_HASH_FN6(&nat->nat_outip6, 0, 0xffffffff);
1001		hv2 = NAT_HASH_FN6(&nat->nat_oip6, hv2,
1002				  ifs->ifs_ipf_nattable_sz);
1003	}
1004
1005	if ((ifs->ifs_nat_stats.ns_bucketlen[0][hv1] >=
1006	    ifs->ifs_fr_nat_maxbucket) ||
1007	    (ifs->ifs_nat_stats.ns_bucketlen[1][hv2] >=
1008	    ifs->ifs_fr_nat_maxbucket)) {
1009		return -1;
1010	}
1011
1012	nat->nat_hv[0] = hv1;
1013	nat->nat_hv[1] = hv2;
1014
1015	MUTEX_INIT(&nat->nat_lock, "nat entry lock");
1016
1017	nat->nat_rev = rev;
1018	nat->nat_ref = 1;
1019	nat->nat_bytes[0] = 0;
1020	nat->nat_pkts[0] = 0;
1021	nat->nat_bytes[1] = 0;
1022	nat->nat_pkts[1] = 0;
1023
1024	nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
1025	nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 6, ifs);
1026
1027	if (nat->nat_ifnames[1][0] !='\0') {
1028		nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
1029		nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 6, ifs);
1030	} else {
1031		(void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0],
1032			       LIFNAMSIZ);
1033		nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
1034		nat->nat_ifps[1] = nat->nat_ifps[0];
1035	}
1036
1037	nat->nat_next = ifs->ifs_nat_instances;
1038	nat->nat_pnext = &ifs->ifs_nat_instances;
1039	if (ifs->ifs_nat_instances)
1040		ifs->ifs_nat_instances->nat_pnext = &nat->nat_next;
1041	ifs->ifs_nat_instances = nat;
1042
1043	natp = &ifs->ifs_nat_table[0][hv1];
1044	if (*natp)
1045		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
1046	nat->nat_phnext[0] = natp;
1047	nat->nat_hnext[0] = *natp;
1048	*natp = nat;
1049	ifs->ifs_nat_stats.ns_bucketlen[0][hv1]++;
1050
1051	natp = &ifs->ifs_nat_table[1][hv2];
1052	if (*natp)
1053		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
1054	nat->nat_phnext[1] = natp;
1055	nat->nat_hnext[1] = *natp;
1056	*natp = nat;
1057	ifs->ifs_nat_stats.ns_bucketlen[1][hv2]++;
1058
1059	fr_setnatqueue(nat, rev, ifs);
1060
1061	ifs->ifs_nat_stats.ns_added++;
1062	ifs->ifs_nat_stats.ns_inuse++;
1063	return 0;
1064}
1065
1066
1067/* ------------------------------------------------------------------------ */
1068/* Function:    nat6_icmperrorlookup                                        */
1069/* Returns:     nat_t* - point to matching NAT structure                    */
1070/* Parameters:  fin(I) - pointer to packet information                      */
1071/*              dir(I) - direction of packet (in/out)                       */
1072/*                                                                          */
1073/* Check if the ICMP error message is related to an existing TCP, UDP or    */
1074/* ICMP query nat entry.  It is assumed that the packet is already of the   */
1075/* the required length.                                                     */
1076/* ------------------------------------------------------------------------ */
1077nat_t *nat6_icmperrorlookup(fin, dir)
1078fr_info_t *fin;
1079int dir;
1080{
1081	int flags = 0, minlen;
1082	struct icmp6_hdr *orgicmp;
1083	tcphdr_t *tcp = NULL;
1084	u_short data[2];
1085	nat_t *nat;
1086	ip6_t *oip6;
1087	u_int p;
1088
1089	minlen = 40;
1090	/*
1091	 * Does it at least have the return (basic) IP header ?
1092	 * Only a basic IP header (no options) should be with an ICMP error
1093	 * header.  Also, if it's not an error type, then return.
1094	 */
1095	if (!(fin->fin_flx & FI_ICMPERR))
1096		return NULL;
1097
1098	/*
1099	 * Check packet size
1100	 */
1101	if (fin->fin_plen < ICMP6ERR_IPICMPHLEN)
1102		return NULL;
1103	oip6 = (ip6_t *)((char *)fin->fin_dp + 8);
1104
1105	/*
1106	 * Is the buffer big enough for all of it ?  It's the size of the IP
1107	 * header claimed in the encapsulated part which is of concern.  It
1108	 * may be too big to be in this buffer but not so big that it's
1109	 * outside the ICMP packet, leading to TCP deref's causing problems.
1110	 * This is possible because we don't know how big oip_hl is when we
1111	 * do the pullup early in fr_check() and thus can't gaurantee it is
1112	 * all here now.
1113	 */
1114#ifdef  _KERNEL
1115	{
1116	mb_t *m;
1117
1118	m = fin->fin_m;
1119# if defined(MENTAT)
1120	if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr)
1121		return NULL;
1122# else
1123	if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN >
1124	    (char *)fin->fin_ip + M_LEN(m))
1125		return NULL;
1126# endif
1127	}
1128#endif
1129
1130	if (IP6_NEQ(&fin->fin_dst6, &oip6->ip6_src))
1131		return NULL;
1132
1133	p = oip6->ip6_nxt;
1134	if (p == IPPROTO_TCP)
1135		flags = IPN_TCP;
1136	else if (p == IPPROTO_UDP)
1137		flags = IPN_UDP;
1138	else if (p == IPPROTO_ICMPV6) {
1139		orgicmp = (struct icmp6_hdr *)(oip6 + 1);
1140
1141		/* see if this is related to an ICMP query */
1142		if (nat_icmpquerytype6(orgicmp->icmp6_type)) {
1143			data[0] = fin->fin_data[0];
1144			data[1] = fin->fin_data[1];
1145			fin->fin_data[0] = 0;
1146			fin->fin_data[1] = orgicmp->icmp6_id;
1147
1148			flags = IPN_ICMPERR|IPN_ICMPQUERY;
1149			/*
1150			 * NOTE : dir refers to the direction of the original
1151			 *        ip packet. By definition the icmp error
1152			 *        message flows in the opposite direction.
1153			 */
1154			if (dir == NAT_INBOUND)
1155				nat = nat6_inlookup(fin, flags, p,
1156				    &oip6->ip6_dst, &oip6->ip6_src);
1157			else
1158				nat = nat6_outlookup(fin, flags, p,
1159				    &oip6->ip6_dst, &oip6->ip6_src);
1160			fin->fin_data[0] = data[0];
1161			fin->fin_data[1] = data[1];
1162			return nat;
1163		}
1164	}
1165
1166	if (flags & IPN_TCPUDP) {
1167		minlen += 8;		/* + 64bits of data to get ports */
1168		if (fin->fin_plen < ICMPERR_ICMPHLEN + minlen)
1169			return NULL;
1170
1171		data[0] = fin->fin_data[0];
1172		data[1] = fin->fin_data[1];
1173		tcp = (tcphdr_t *)(oip6 + 1);
1174		fin->fin_data[0] = ntohs(tcp->th_dport);
1175		fin->fin_data[1] = ntohs(tcp->th_sport);
1176
1177		if (dir == NAT_INBOUND) {
1178			nat = nat6_inlookup(fin, flags, p,
1179			    &oip6->ip6_dst, &oip6->ip6_src);
1180		} else {
1181			nat = nat6_outlookup(fin, flags, p,
1182			    &oip6->ip6_dst, &oip6->ip6_src);
1183		}
1184		fin->fin_data[0] = data[0];
1185		fin->fin_data[1] = data[1];
1186		return nat;
1187	}
1188	if (dir == NAT_INBOUND)
1189		return nat6_inlookup(fin, 0, p, &oip6->ip6_dst, &oip6->ip6_src);
1190	else
1191		return nat6_outlookup(fin, 0, p, &oip6->ip6_dst,
1192		    &oip6->ip6_src);
1193}
1194
1195
1196/* ------------------------------------------------------------------------ */
1197/* Function:    nat6_icmperror                                              */
1198/* Returns:     nat_t* - point to matching NAT structure                    */
1199/* Parameters:  fin(I)    - pointer to packet information                   */
1200/*              nflags(I) - NAT flags for this packet                       */
1201/*              dir(I)    - direction of packet (in/out)                    */
1202/*                                                                          */
1203/* Fix up an ICMP packet which is an error message for an existing NAT      */
1204/* session.  This will correct both packet header data and checksums.       */
1205/*                                                                          */
1206/* This should *ONLY* be used for incoming ICMP error packets to make sure  */
1207/* a NAT'd ICMP packet gets correctly recognised.                           */
1208/* ------------------------------------------------------------------------ */
1209nat_t *nat6_icmperror(fin, nflags, dir)
1210fr_info_t *fin;
1211u_int *nflags;
1212int dir;
1213{
1214	u_32_t sum1, sum2, sumd, psum1, psum2, psumd, sumd1;
1215	i6addr_t in;
1216	struct icmp6_hdr *icmp6, *orgicmp;
1217	int dlen;
1218	udphdr_t *udp;
1219	tcphdr_t *tcp;
1220	nat_t *nat;
1221	ip6_t *oip6;
1222	if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY)))
1223		return NULL;
1224
1225	/*
1226	 * nat6_icmperrorlookup() looks up nat entry associated with the
1227	 * offending IP packet and returns pointer to the entry, or NULL
1228	 * if packet wasn't natted or for `defective' packets.
1229	 */
1230
1231	if ((fin->fin_v != 6) || !(nat = nat6_icmperrorlookup(fin, dir)))
1232		return NULL;
1233
1234	sumd1 = 0;
1235	*nflags = IPN_ICMPERR;
1236	icmp6 = fin->fin_dp;
1237	oip6 = (ip6_t *)((char *)icmp6 + sizeof (*icmp6));
1238	udp = (udphdr_t *)(((char *)oip6) + sizeof (*oip6));
1239	tcp = (tcphdr_t *)udp;
1240	dlen = fin->fin_plen - ((char *)udp - (char *)fin->fin_ip);
1241
1242	/*
1243	 * Need to adjust ICMP header to include the real IP#'s and
1244	 * port #'s.  There are three steps required.
1245	 *
1246	 * Step 1
1247	 * No update needed for ip6 header checksum.
1248	 *
1249	 * Unlike IPv4, we need to update icmp_cksum for IPv6 address
1250	 * changes because there's no ip_sum change to cancel it.
1251	 */
1252
1253	if (IP6_EQ((i6addr_t *)&oip6->ip6_dst, &nat->nat_oip6)) {
1254		sum1 = LONG_SUM6((i6addr_t *)&oip6->ip6_src);
1255		in = nat->nat_inip6;
1256		oip6->ip6_src = in.in6;
1257	} else {
1258		sum1 = LONG_SUM6((i6addr_t *)&oip6->ip6_dst);
1259		in = nat->nat_outip6;
1260		oip6->ip6_dst = in.in6;
1261	}
1262
1263	sum2 = LONG_SUM6(&in);
1264	CALC_SUMD(sum1, sum2, sumd);
1265
1266	/*
1267	 * Step 2
1268	 * Perform other adjustments based on protocol of offending packet.
1269	 */
1270
1271	switch (oip6->ip6_nxt) {
1272		case IPPROTO_TCP :
1273		case IPPROTO_UDP :
1274
1275			/*
1276			* For offending TCP/UDP IP packets, translate the ports
1277			* based on the NAT specification.
1278			*
1279			* Advance notice : Now it becomes complicated :-)
1280			*
1281			* Since the port and IP addresse fields are both part
1282			* of the TCP/UDP checksum of the offending IP packet,
1283			* we need to adjust that checksum as well.
1284			*
1285			* To further complicate things, the TCP/UDP checksum
1286			* may not be present.  We must check to see if the
1287			* length of the data portion is big enough to hold
1288			* the checksum.  In the UDP case, a test to determine
1289			* if the checksum is even set is also required.
1290			*
1291			* Any changes to an IP address, port or checksum within
1292			* the ICMP packet requires a change to icmp_cksum.
1293			*
1294			* Be extremely careful here ... The change is dependent
1295			* upon whether or not the TCP/UPD checksum is present.
1296			*
1297			* If TCP/UPD checksum is present, the icmp_cksum must
1298			* compensate for checksum modification resulting from
1299			* IP address change only.  Port change and resulting
1300			* data checksum adjustments cancel each other out.
1301			*
1302			* If TCP/UDP checksum is not present, icmp_cksum must
1303			* compensate for port change only.  The IP address
1304			* change does not modify anything else in this case.
1305			*/
1306
1307			psum1 = 0;
1308			psum2 = 0;
1309			psumd = 0;
1310
1311			if ((tcp->th_dport == nat->nat_oport) &&
1312			    (tcp->th_sport != nat->nat_inport)) {
1313
1314				/*
1315				 * Translate the source port.
1316				 */
1317
1318				psum1 = ntohs(tcp->th_sport);
1319				psum2 = ntohs(nat->nat_inport);
1320				tcp->th_sport = nat->nat_inport;
1321
1322			} else if ((tcp->th_sport == nat->nat_oport) &&
1323				    (tcp->th_dport != nat->nat_outport)) {
1324
1325				/*
1326				 * Translate the destination port.
1327				 */
1328
1329				psum1 = ntohs(tcp->th_dport);
1330				psum2 = ntohs(nat->nat_outport);
1331				tcp->th_dport = nat->nat_outport;
1332			}
1333
1334			if ((oip6->ip6_nxt == IPPROTO_TCP) && (dlen >= 18)) {
1335
1336				/*
1337				 * TCP checksum present.
1338				 *
1339				 * Adjust data checksum and icmp checksum to
1340				 * compensate for any IP address change.
1341				 */
1342
1343				sum1 = ntohs(tcp->th_sum);
1344				fix_datacksum(&tcp->th_sum, sumd);
1345				sum2 = ntohs(tcp->th_sum);
1346				CALC_SUMD(sum1, sum2, sumd);
1347				sumd1 += sumd;
1348
1349				/*
1350				 * Also make data checksum adjustment to
1351				 * compensate for any port change.
1352				 */
1353
1354				if (psum1 != psum2) {
1355					CALC_SUMD(psum1, psum2, psumd);
1356					fix_datacksum(&tcp->th_sum, psumd);
1357				}
1358
1359			} else if ((oip6->ip6_nxt == IPPROTO_UDP) &&
1360				   (dlen >= 8) && (udp->uh_sum != 0)) {
1361
1362				/*
1363				 * The UDP checksum is present and set.
1364				 *
1365				 * Adjust data checksum and icmp checksum to
1366				 * compensate for any IP address change.
1367				 */
1368
1369				sum1 = ntohs(udp->uh_sum);
1370				fix_datacksum(&udp->uh_sum, sumd);
1371				sum2 = ntohs(udp->uh_sum);
1372				CALC_SUMD(sum1, sum2, sumd);
1373				sumd1 += sumd;
1374
1375				/*
1376				 * Also make data checksum adjustment to
1377				 * compensate for any port change.
1378				 */
1379
1380				if (psum1 != psum2) {
1381					CALC_SUMD(psum1, psum2, psumd);
1382					fix_datacksum(&udp->uh_sum, psumd);
1383				}
1384
1385			} else {
1386
1387				/*
1388				 * Data checksum was not present.
1389				 *
1390				 * Compensate for any port change.
1391				 */
1392
1393				CALC_SUMD(psum2, psum1, psumd);
1394				sumd1 += psumd;
1395			}
1396			break;
1397
1398		case IPPROTO_ICMPV6 :
1399
1400			orgicmp = (struct icmp6_hdr *)udp;
1401
1402			if ((nat->nat_dir == NAT_OUTBOUND) &&
1403			    (orgicmp->icmp6_id != nat->nat_inport) &&
1404			    (dlen >= 8)) {
1405
1406				/*
1407				 * Fix ICMP checksum (of the offening ICMP
1408				 * query packet) to compensate the change
1409				 * in the ICMP id of the offending ICMP
1410				 * packet.
1411				 *
1412				 * Since you modify orgicmp->icmp_id with
1413				 * a delta (say x) and you compensate that
1414				 * in origicmp->icmp_cksum with a delta
1415				 * minus x, you don't have to adjust the
1416				 * overall icmp->icmp_cksum
1417				 */
1418
1419				sum1 = ntohs(orgicmp->icmp6_id);
1420				sum2 = ntohs(nat->nat_inport);
1421				CALC_SUMD(sum1, sum2, sumd);
1422				orgicmp->icmp6_id = nat->nat_inport;
1423				fix_datacksum(&orgicmp->icmp6_cksum, sumd);
1424
1425			} /* nat_dir can't be NAT_INBOUND for icmp queries */
1426
1427			break;
1428
1429		default :
1430
1431			break;
1432
1433	} /* switch (oip6->ip6_nxt) */
1434
1435	/*
1436	 * Step 3
1437	 * Make the adjustments to icmp checksum.
1438	 */
1439
1440	if (sumd1 != 0) {
1441		sumd1 = (sumd1 & 0xffff) + (sumd1 >> 16);
1442		sumd1 = (sumd1 & 0xffff) + (sumd1 >> 16);
1443		fix_incksum(&icmp6->icmp6_cksum, sumd1);
1444	}
1445	return nat;
1446}
1447
1448
1449/*
1450 * NB: these lookups don't lock access to the list, it assumed that it has
1451 * already been done!
1452 */
1453
1454/* ------------------------------------------------------------------------ */
1455/* Function:    nat6_inlookup                                               */
1456/* Returns:     nat_t* - NULL == no match,                                  */
1457/*                       else pointer to matching NAT entry                 */
1458/* Parameters:  fin(I)    - pointer to packet information                   */
1459/*              flags(I)  - NAT flags for this packet                       */
1460/*              p(I)      - protocol for this packet                        */
1461/*              src(I)    - source IP address                               */
1462/*              mapdst(I) - destination IP address                          */
1463/*                                                                          */
1464/* Lookup a nat entry based on the mapped destination ip address/port and   */
1465/* real source address/port.  We use this lookup when receiving a packet,   */
1466/* we're looking for a table entry, based on the destination address.       */
1467/*                                                                          */
1468/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
1469/*                                                                          */
1470/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN      */
1471/*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
1472/*                                                                          */
1473/* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
1474/*            the packet is of said protocol                                */
1475/* ------------------------------------------------------------------------ */
1476nat_t *nat6_inlookup(fin, flags, p, src, mapdst)
1477fr_info_t *fin;
1478u_int flags, p;
1479struct in6_addr *src, *mapdst;
1480{
1481	u_short sport, dport;
1482	u_int sflags;
1483	nat_t *nat;
1484	int nflags;
1485	i6addr_t dst;
1486	void *ifp;
1487	u_int hv;
1488	ipf_stack_t *ifs = fin->fin_ifs;
1489
1490	if (fin != NULL)
1491		ifp = fin->fin_ifp;
1492	else
1493		ifp = NULL;
1494	sport = 0;
1495	dport = 0;
1496	dst.in6 = *mapdst;
1497	sflags = flags & NAT_TCPUDPICMP;
1498
1499	switch (p)
1500	{
1501	case IPPROTO_TCP :
1502	case IPPROTO_UDP :
1503		sport = htons(fin->fin_data[0]);
1504		dport = htons(fin->fin_data[1]);
1505		break;
1506	case IPPROTO_ICMPV6 :
1507		if (flags & IPN_ICMPERR)
1508			sport = fin->fin_data[1];
1509		else
1510			dport = fin->fin_data[1];
1511		break;
1512	default :
1513		break;
1514	}
1515
1516
1517	if ((flags & SI_WILDP) != 0)
1518		goto find_in_wild_ports;
1519
1520	hv = NAT_HASH_FN6(&dst, dport, 0xffffffff);
1521	hv = NAT_HASH_FN6(src, hv + sport, ifs->ifs_ipf_nattable_sz);
1522	nat = ifs->ifs_nat_table[1][hv];
1523	for (; nat; nat = nat->nat_hnext[1]) {
1524		if (nat->nat_v != 6)
1525			continue;
1526
1527		if (nat->nat_ifps[0] != NULL) {
1528			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
1529				continue;
1530		} else if (ifp != NULL)
1531			nat->nat_ifps[0] = ifp;
1532
1533		nflags = nat->nat_flags;
1534
1535		if (IP6_EQ(&nat->nat_oip6, src) &&
1536		    IP6_EQ(&nat->nat_outip6, &dst) &&
1537		    (((p == 0) &&
1538		    (sflags == (nat->nat_flags & IPN_TCPUDPICMP))) ||
1539		    (p == nat->nat_p))) {
1540			switch (p)
1541			{
1542#if 0
1543			case IPPROTO_GRE :
1544				if (nat->nat_call[1] != fin->fin_data[0])
1545					continue;
1546				break;
1547#endif
1548			case IPPROTO_ICMPV6 :
1549				if ((flags & IPN_ICMPERR) != 0) {
1550					if (nat->nat_outport != sport)
1551						continue;
1552				} else {
1553					if (nat->nat_outport != dport)
1554						continue;
1555				}
1556				break;
1557			case IPPROTO_TCP :
1558			case IPPROTO_UDP :
1559				if (nat->nat_oport != sport)
1560					continue;
1561				if (nat->nat_outport != dport)
1562					continue;
1563				break;
1564			default :
1565				break;
1566			}
1567
1568#ifdef	IPF_V6_PROXIES
1569			ipn = nat->nat_ptr;
1570			if ((ipn != NULL) && (nat->nat_aps != NULL))
1571				if (appr_match(fin, nat) != 0)
1572					continue;
1573#endif
1574			return nat;
1575		}
1576	}
1577
1578	/*
1579	 * So if we didn't find it but there are wildcard members in the hash
1580	 * table, go back and look for them.  We do this search and update here
1581	 * because it is modifying the NAT table and we want to do this only
1582	 * for the first packet that matches.  The exception, of course, is
1583	 * for "dummy" (FI_IGNORE) lookups.
1584	 */
1585find_in_wild_ports:
1586	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH))
1587		return NULL;
1588	if (ifs->ifs_nat_stats.ns_wilds == 0)
1589		return NULL;
1590
1591	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
1592
1593	hv = NAT_HASH_FN6(&dst, 0, 0xffffffff);
1594	hv = NAT_HASH_FN6(src, hv, ifs->ifs_ipf_nattable_sz);
1595
1596	WRITE_ENTER(&ifs->ifs_ipf_nat);
1597
1598	nat = ifs->ifs_nat_table[1][hv];
1599	for (; nat; nat = nat->nat_hnext[1]) {
1600		if (nat->nat_v != 6)
1601			continue;
1602
1603		if (nat->nat_ifps[0] != NULL) {
1604			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
1605				continue;
1606		} else if (ifp != NULL)
1607			nat->nat_ifps[0] = ifp;
1608
1609		if (nat->nat_p != fin->fin_p)
1610			continue;
1611		if (IP6_NEQ(&nat->nat_oip6, src) ||
1612		    IP6_NEQ(&nat->nat_outip6, &dst))
1613			continue;
1614
1615		nflags = nat->nat_flags;
1616		if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
1617			continue;
1618
1619		if (nat_wildok(nat, (int)sport, (int)dport, nflags,
1620			       NAT_INBOUND) == 1) {
1621			if ((fin->fin_flx & FI_IGNORE) != 0)
1622				break;
1623			if ((nflags & SI_CLONE) != 0) {
1624				nat = fr_natclone(fin, nat);
1625				if (nat == NULL)
1626					break;
1627			} else {
1628				MUTEX_ENTER(&ifs->ifs_ipf_nat_new);
1629				ifs->ifs_nat_stats.ns_wilds--;
1630				MUTEX_EXIT(&ifs->ifs_ipf_nat_new);
1631			}
1632			nat->nat_oport = sport;
1633			nat->nat_outport = dport;
1634			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
1635			nat6_tabmove(nat, ifs);
1636			break;
1637		}
1638	}
1639
1640	MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
1641
1642	return nat;
1643}
1644
1645
1646/* ------------------------------------------------------------------------ */
1647/* Function:    nat6_tabmove                                                */
1648/* Returns:     Nil                                                         */
1649/* Parameters:  nat(I) - pointer to NAT structure                           */
1650/* Write Lock:  ipf_nat                                                     */
1651/*                                                                          */
1652/* This function is only called for TCP/UDP NAT table entries where the     */
1653/* original was placed in the table without hashing on the ports and we now */
1654/* want to include hashing on port numbers.                                 */
1655/* ------------------------------------------------------------------------ */
1656static void nat6_tabmove(nat, ifs)
1657nat_t *nat;
1658ipf_stack_t *ifs;
1659{
1660	nat_t **natp;
1661	u_int hv;
1662
1663	if (nat->nat_flags & SI_CLONE)
1664		return;
1665
1666	/*
1667	 * Remove the NAT entry from the old location
1668	 */
1669	if (nat->nat_hnext[0])
1670		nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
1671	*nat->nat_phnext[0] = nat->nat_hnext[0];
1672	ifs->ifs_nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--;
1673
1674	if (nat->nat_hnext[1])
1675		nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
1676	*nat->nat_phnext[1] = nat->nat_hnext[1];
1677	ifs->ifs_nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--;
1678
1679	/*
1680	 * Add into the NAT table in the new position
1681	 */
1682	hv = NAT_HASH_FN6(&nat->nat_inip6, nat->nat_inport, 0xffffffff);
1683	hv = NAT_HASH_FN6(&nat->nat_oip6, hv + nat->nat_oport,
1684			 ifs->ifs_ipf_nattable_sz);
1685	nat->nat_hv[0] = hv;
1686	natp = &ifs->ifs_nat_table[0][hv];
1687	if (*natp)
1688		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
1689	nat->nat_phnext[0] = natp;
1690	nat->nat_hnext[0] = *natp;
1691	*natp = nat;
1692	ifs->ifs_nat_stats.ns_bucketlen[0][hv]++;
1693
1694	hv = NAT_HASH_FN6(&nat->nat_outip6, nat->nat_outport, 0xffffffff);
1695	hv = NAT_HASH_FN6(&nat->nat_oip6, hv + nat->nat_oport,
1696			 ifs->ifs_ipf_nattable_sz);
1697	nat->nat_hv[1] = hv;
1698	natp = &ifs->ifs_nat_table[1][hv];
1699	if (*natp)
1700		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
1701	nat->nat_phnext[1] = natp;
1702	nat->nat_hnext[1] = *natp;
1703	*natp = nat;
1704	ifs->ifs_nat_stats.ns_bucketlen[1][hv]++;
1705}
1706
1707
1708/* ------------------------------------------------------------------------ */
1709/* Function:    nat6_outlookup                                              */
1710/* Returns:     nat_t* - NULL == no match,                                  */
1711/*                       else pointer to matching NAT entry                 */
1712/* Parameters:  fin(I)   - pointer to packet information                    */
1713/*              flags(I) - NAT flags for this packet                        */
1714/*              p(I)     - protocol for this packet                         */
1715/*              src(I)   - source IP address                                */
1716/*              dst(I)   - destination IP address                           */
1717/*              rw(I)    - 1 == write lock on ipf_nat held, 0 == read lock. */
1718/*                                                                          */
1719/* Lookup a nat entry based on the source 'real' ip address/port and        */
1720/* destination address/port.  We use this lookup when sending a packet out, */
1721/* we're looking for a table entry, based on the source address.            */
1722/*                                                                          */
1723/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
1724/*                                                                          */
1725/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN      */
1726/*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
1727/*                                                                          */
1728/* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
1729/*            the packet is of said protocol                                */
1730/* ------------------------------------------------------------------------ */
1731nat_t *nat6_outlookup(fin, flags, p, src, dst)
1732fr_info_t *fin;
1733u_int flags, p;
1734struct in6_addr *src , *dst;
1735{
1736	u_short sport, dport;
1737	u_int sflags;
1738	nat_t *nat;
1739	int nflags;
1740	void *ifp;
1741	u_int hv;
1742	ipf_stack_t *ifs = fin->fin_ifs;
1743
1744	ifp = fin->fin_ifp;
1745
1746	sflags = flags & IPN_TCPUDPICMP;
1747	sport = 0;
1748	dport = 0;
1749
1750	switch (p)
1751	{
1752	case IPPROTO_TCP :
1753	case IPPROTO_UDP :
1754		sport = htons(fin->fin_data[0]);
1755		dport = htons(fin->fin_data[1]);
1756		break;
1757	case IPPROTO_ICMPV6 :
1758		if (flags & IPN_ICMPERR)
1759			sport = fin->fin_data[1];
1760		else
1761			dport = fin->fin_data[1];
1762		break;
1763	default :
1764		break;
1765	}
1766
1767	if ((flags & SI_WILDP) != 0)
1768		goto find_out_wild_ports;
1769
1770	hv = NAT_HASH_FN6(src, sport, 0xffffffff);
1771	hv = NAT_HASH_FN6(dst, hv + dport, ifs->ifs_ipf_nattable_sz);
1772	nat = ifs->ifs_nat_table[0][hv];
1773	for (; nat; nat = nat->nat_hnext[0]) {
1774		if (nat->nat_v != 6)
1775			continue;
1776
1777		if (nat->nat_ifps[1] != NULL) {
1778			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
1779				continue;
1780		} else if (ifp != NULL)
1781			nat->nat_ifps[1] = ifp;
1782
1783		nflags = nat->nat_flags;
1784
1785		if (IP6_EQ(&nat->nat_inip6, src) &&
1786		    IP6_EQ(&nat->nat_oip6, dst) &&
1787		    (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP))) ||
1788		    (p == nat->nat_p))) {
1789			switch (p)
1790			{
1791#if 0
1792			case IPPROTO_GRE :
1793				if (nat->nat_call[1] != fin->fin_data[0])
1794					continue;
1795				break;
1796#endif
1797			case IPPROTO_TCP :
1798			case IPPROTO_UDP :
1799				if (nat->nat_oport != dport)
1800					continue;
1801				if (nat->nat_inport != sport)
1802					continue;
1803				break;
1804			default :
1805				break;
1806			}
1807
1808#ifdef	IPF_V6_PROXIES
1809			ipn = nat->nat_ptr;
1810			if ((ipn != NULL) && (nat->nat_aps != NULL))
1811				if (appr_match(fin, nat) != 0)
1812					continue;
1813#endif
1814			return nat;
1815		}
1816	}
1817
1818	/*
1819	 * So if we didn't find it but there are wildcard members in the hash
1820	 * table, go back and look for them.  We do this search and update here
1821	 * because it is modifying the NAT table and we want to do this only
1822	 * for the first packet that matches.  The exception, of course, is
1823	 * for "dummy" (FI_IGNORE) lookups.
1824	 */
1825find_out_wild_ports:
1826	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH))
1827		return NULL;
1828	if (ifs->ifs_nat_stats.ns_wilds == 0)
1829		return NULL;
1830
1831	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
1832
1833	hv = NAT_HASH_FN6(src, 0, 0xffffffff);
1834	hv = NAT_HASH_FN6(dst, hv, ifs->ifs_ipf_nattable_sz);
1835
1836	WRITE_ENTER(&ifs->ifs_ipf_nat);
1837
1838	nat = ifs->ifs_nat_table[0][hv];
1839	for (; nat; nat = nat->nat_hnext[0]) {
1840		if (nat->nat_v != 6)
1841			continue;
1842
1843		if (nat->nat_ifps[1] != NULL) {
1844			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
1845				continue;
1846		} else if (ifp != NULL)
1847			nat->nat_ifps[1] = ifp;
1848
1849		if (nat->nat_p != fin->fin_p)
1850			continue;
1851		if (IP6_NEQ(&nat->nat_inip6, src) ||
1852		    IP6_NEQ(&nat->nat_oip6, dst))
1853			continue;
1854
1855		nflags = nat->nat_flags;
1856		if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
1857			continue;
1858
1859		if (nat_wildok(nat, (int)sport, (int)dport, nflags,
1860			       NAT_OUTBOUND) == 1) {
1861			if ((fin->fin_flx & FI_IGNORE) != 0)
1862				break;
1863			if ((nflags & SI_CLONE) != 0) {
1864				nat = fr_natclone(fin, nat);
1865				if (nat == NULL)
1866					break;
1867			} else {
1868				MUTEX_ENTER(&ifs->ifs_ipf_nat_new);
1869				ifs->ifs_nat_stats.ns_wilds--;
1870				MUTEX_EXIT(&ifs->ifs_ipf_nat_new);
1871			}
1872			nat->nat_inport = sport;
1873			nat->nat_oport = dport;
1874			if (nat->nat_outport == 0)
1875				nat->nat_outport = sport;
1876			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
1877			nat6_tabmove(nat, ifs);
1878			break;
1879		}
1880	}
1881
1882	MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
1883
1884	return nat;
1885}
1886
1887
1888/* ------------------------------------------------------------------------ */
1889/* Function:    nat6_lookupredir                                            */
1890/* Returns:     nat_t* - NULL == no match,                                  */
1891/*                       else pointer to matching NAT entry                 */
1892/* Parameters:  np(I) - pointer to description of packet to find NAT table  */
1893/*                      entry for.                                          */
1894/*                                                                          */
1895/* Lookup the NAT tables to search for a matching redirect                  */
1896/* ------------------------------------------------------------------------ */
1897nat_t *nat6_lookupredir(np, ifs)
1898natlookup_t *np;
1899ipf_stack_t *ifs;
1900{
1901	fr_info_t fi;
1902	nat_t *nat;
1903
1904	bzero((char *)&fi, sizeof (fi));
1905	if (np->nl_flags & IPN_IN) {
1906		fi.fin_data[0] = ntohs(np->nl_realport);
1907		fi.fin_data[1] = ntohs(np->nl_outport);
1908	} else {
1909		fi.fin_data[0] = ntohs(np->nl_inport);
1910		fi.fin_data[1] = ntohs(np->nl_outport);
1911	}
1912	if (np->nl_flags & IPN_TCP)
1913		fi.fin_p = IPPROTO_TCP;
1914	else if (np->nl_flags & IPN_UDP)
1915		fi.fin_p = IPPROTO_UDP;
1916	else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY))
1917		fi.fin_p = IPPROTO_ICMPV6;
1918
1919	fi.fin_ifs = ifs;
1920	/*
1921	 * We can do two sorts of lookups:
1922	 * - IPN_IN: we have the `real' and `out' address, look for `in'.
1923	 * - default: we have the `in' and `out' address, look for `real'.
1924	 */
1925	if (np->nl_flags & IPN_IN) {
1926		if ((nat = nat6_inlookup(&fi, np->nl_flags, fi.fin_p,
1927					 &np->nl_realip6, &np->nl_outip6))) {
1928			np->nl_inipaddr = nat->nat_inip6;
1929			np->nl_inport = nat->nat_inport;
1930		}
1931	} else {
1932		/*
1933		 * If nl_inip is non null, this is a lookup based on the real
1934		 * ip address. Else, we use the fake.
1935		 */
1936		if ((nat = nat6_outlookup(&fi, np->nl_flags, fi.fin_p,
1937					  &np->nl_inip6, &np->nl_outip6))) {
1938			if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
1939				fr_info_t fin;
1940				bzero((char *)&fin, sizeof (fin));
1941				fin.fin_p = nat->nat_p;
1942				fin.fin_data[0] = ntohs(nat->nat_outport);
1943				fin.fin_data[1] = ntohs(nat->nat_oport);
1944				fin.fin_ifs = ifs;
1945				if (nat6_inlookup(&fin, np->nl_flags, fin.fin_p,
1946						 &nat->nat_outip6.in6,
1947						 &nat->nat_oip6.in6) != NULL) {
1948					np->nl_flags &= ~IPN_FINDFORWARD;
1949				}
1950			}
1951
1952			np->nl_realip6 = nat->nat_outip6.in6;
1953			np->nl_realport = nat->nat_outport;
1954		}
1955 	}
1956
1957	return nat;
1958}
1959
1960
1961/* ------------------------------------------------------------------------ */
1962/* Function:    nat6_match                                                  */
1963/* Returns:     int - 0 == no match, 1 == match                             */
1964/* Parameters:  fin(I)   - pointer to packet information                    */
1965/*              np(I)    - pointer to NAT rule                              */
1966/*                                                                          */
1967/* Pull the matching of a packet against a NAT rule out of that complex     */
1968/* loop inside fr_checknat6in() and lay it out properly in its own function.*/
1969/* ------------------------------------------------------------------------ */
1970static int nat6_match(fin, np)
1971fr_info_t *fin;
1972ipnat_t *np;
1973{
1974	frtuc_t *ft;
1975
1976	if (fin->fin_v != 6)
1977		return 0;
1978
1979	if (np->in_p && fin->fin_p != np->in_p)
1980		return 0;
1981
1982	if (fin->fin_out) {
1983		if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK)))
1984			return 0;
1985		if (IP6_MASKNEQ(&fin->fin_src6, &np->in_in[1], &np->in_in[0])
1986		    ^ ((np->in_flags & IPN_NOTSRC) != 0))
1987			return 0;
1988		if (IP6_MASKNEQ(&fin->fin_dst6, &np->in_src[1], &np->in_src[0])
1989		    ^ ((np->in_flags & IPN_NOTDST) != 0))
1990			return 0;
1991	} else {
1992		if (!(np->in_redir & NAT_REDIRECT))
1993			return 0;
1994		if (IP6_MASKNEQ(&fin->fin_src6, &np->in_src[1], &np->in_src[0])
1995		    ^ ((np->in_flags & IPN_NOTSRC) != 0))
1996			return 0;
1997		if (IP6_MASKNEQ(&fin->fin_dst6, &np->in_out[1], &np->in_out[0])
1998		    ^ ((np->in_flags & IPN_NOTDST) != 0))
1999			return 0;
2000	}
2001
2002	ft = &np->in_tuc;
2003	if (!(fin->fin_flx & FI_TCPUDP) ||
2004	    (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
2005		if (ft->ftu_scmp || ft->ftu_dcmp)
2006			return 0;
2007		return 1;
2008	}
2009
2010	return fr_tcpudpchk(fin, ft);
2011}
2012
2013
2014/* ------------------------------------------------------------------------ */
2015/* Function:    fr_checknat6out                                             */
2016/* Returns:     int - -1 == packet failed NAT checks so block it,           */
2017/*                     0 == no packet translation occurred,                 */
2018/*                     1 == packet was successfully translated.             */
2019/* Parameters:  fin(I)   - pointer to packet information                    */
2020/*              passp(I) - pointer to filtering result flags                */
2021/*                                                                          */
2022/* Check to see if an outcoming packet should be changed.  ICMP packets are */
2023/* first checked to see if they match an existing entry (if an error),      */
2024/* otherwise a search of the current NAT table is made.  If neither results */
2025/* in a match then a search for a matching NAT rule is made.  Create a new  */
2026/* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
2027/* packet header(s) as required.                                            */
2028/* ------------------------------------------------------------------------ */
2029int fr_checknat6out(fin, passp)
2030fr_info_t *fin;
2031u_32_t *passp;
2032{
2033	struct ifnet *ifp, *sifp;
2034	int rval, natfailed;
2035	ipnat_t *np = NULL;
2036	u_int nflags = 0;
2037	i6addr_t ipa, iph;
2038	int natadd = 1;
2039	frentry_t *fr;
2040	nat_t *nat;
2041	ipf_stack_t *ifs = fin->fin_ifs;
2042
2043	if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0)
2044		return 0;
2045
2046	natfailed = 0;
2047	fr = fin->fin_fr;
2048	sifp = fin->fin_ifp;
2049	if ((fr != NULL) && !(fr->fr_flags & FR_DUP) &&
2050	    fr->fr_tifs[fin->fin_rev].fd_ifp &&
2051	    fr->fr_tifs[fin->fin_rev].fd_ifp != (void *)-1)
2052		fin->fin_ifp = fr->fr_tifs[fin->fin_rev].fd_ifp;
2053	ifp = fin->fin_ifp;
2054
2055	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
2056		switch (fin->fin_p)
2057		{
2058		case IPPROTO_TCP :
2059			nflags = IPN_TCP;
2060			break;
2061		case IPPROTO_UDP :
2062			nflags = IPN_UDP;
2063			break;
2064		case IPPROTO_ICMPV6 :
2065			/*
2066			 * This is an incoming packet, so the destination is
2067			 * the icmp6_id and the source port equals 0
2068			 */
2069			if ((fin->fin_flx & FI_ICMPQUERY) != 0)
2070				nflags = IPN_ICMPQUERY;
2071			break;
2072		default :
2073			break;
2074		}
2075
2076#ifdef	IPF_V6_PROXIES
2077		if ((nflags & IPN_TCPUDP))
2078			tcp = fin->fin_dp;
2079#endif
2080	}
2081
2082	ipa = fin->fin_src6;
2083
2084	READ_ENTER(&ifs->ifs_ipf_nat);
2085
2086	if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
2087	    (nat = nat6_icmperror(fin, &nflags, NAT_OUTBOUND)))
2088		/*EMPTY*/;
2089	else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin)))
2090		natadd = 0;
2091	else if ((nat = nat6_outlookup(fin, nflags|NAT_SEARCH,
2092		    (u_int)fin->fin_p, &fin->fin_src6.in6,
2093		    &fin->fin_dst6.in6))) {
2094		nflags = nat->nat_flags;
2095	} else {
2096		u_32_t hv, nmsk;
2097		i6addr_t msk;
2098		int i;
2099
2100		/*
2101		 * If there is no current entry in the nat table for this IP#,
2102		 * create one for it (if there is a matching rule).
2103		 */
2104		RWLOCK_EXIT(&ifs->ifs_ipf_nat);
2105		i = 3;
2106		msk.i6[0] = 0xffffffff;
2107		msk.i6[1] = 0xffffffff;
2108		msk.i6[2] = 0xffffffff;
2109		msk.i6[3] = 0xffffffff;
2110		nmsk = ifs->ifs_nat6_masks[3];
2111		WRITE_ENTER(&ifs->ifs_ipf_nat);
2112maskloop:
2113		IP6_AND(&ipa, &msk, &iph);
2114		hv = NAT_HASH_FN6(&iph, 0, ifs->ifs_ipf_natrules_sz);
2115		for (np = ifs->ifs_nat_rules[hv]; np; np = np->in_mnext)
2116		{
2117			if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
2118				continue;
2119			if (np->in_v != 6)
2120				continue;
2121			if (np->in_p && (np->in_p != fin->fin_p))
2122				continue;
2123			if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
2124				continue;
2125			if (np->in_flags & IPN_FILTER) {
2126				if (!nat6_match(fin, np))
2127					continue;
2128			} else if (!IP6_MASKEQ(&ipa, &np->in_in[1],
2129			    &np->in_in[0]))
2130				continue;
2131
2132			if ((fr != NULL) &&
2133			    !fr_matchtag(&np->in_tag, &fr->fr_nattag))
2134				continue;
2135
2136#ifdef	IPF_V6_PROXIES
2137			if (*np->in_plabel != '\0') {
2138				if (((np->in_flags & IPN_FILTER) == 0) &&
2139				    (np->in_dport != tcp->th_dport))
2140					continue;
2141				if (appr_ok(fin, tcp, np) == 0)
2142					continue;
2143			}
2144#endif
2145
2146			if (nat = nat6_new(fin, np, NULL, nflags,
2147					   NAT_OUTBOUND)) {
2148				np->in_hits++;
2149				break;
2150			} else
2151				natfailed = -1;
2152		}
2153		if ((np == NULL) && (i >= 0)) {
2154			while (i >= 0) {
2155				while (nmsk) {
2156					msk.i6[i] = htonl(ntohl(msk.i6[i])<<1);
2157					if ((nmsk & 0x80000000) != 0) {
2158						nmsk <<= 1;
2159						goto maskloop;
2160					}
2161					nmsk <<= 1;
2162				}
2163				msk.i6[i--] = 0;
2164				if (i >= 0) {
2165					nmsk = ifs->ifs_nat6_masks[i];
2166					if (nmsk != 0)
2167						goto maskloop;
2168				}
2169			}
2170		}
2171		MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
2172	}
2173
2174	if (nat != NULL) {
2175		rval = fr_nat6out(fin, nat, natadd, nflags);
2176	} else {
2177		rval = natfailed;
2178	}
2179	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
2180
2181	if (rval == -1) {
2182		if (passp != NULL)
2183			*passp = FR_BLOCK;
2184		fin->fin_flx |= FI_BADNAT;
2185	}
2186	fin->fin_ifp = sifp;
2187	return rval;
2188}
2189
2190/* ------------------------------------------------------------------------ */
2191/* Function:    fr_nat6out                                                  */
2192/* Returns:     int - -1 == packet failed NAT checks so block it,           */
2193/*                     1 == packet was successfully translated.             */
2194/* Parameters:  fin(I)    - pointer to packet information                   */
2195/*              nat(I)    - pointer to NAT structure                        */
2196/*              natadd(I) - flag indicating if it is safe to add frag cache */
2197/*              nflags(I) - NAT flags set for this packet                   */
2198/*                                                                          */
2199/* Translate a packet coming "out" on an interface.                         */
2200/* ------------------------------------------------------------------------ */
2201int fr_nat6out(fin, nat, natadd, nflags)
2202fr_info_t *fin;
2203nat_t *nat;
2204int natadd;
2205u_32_t nflags;
2206{
2207	struct icmp6_hdr *icmp6;
2208	u_short *csump;
2209	tcphdr_t *tcp;
2210	ipnat_t *np;
2211	int i;
2212	ipf_stack_t *ifs = fin->fin_ifs;
2213
2214#if defined(SOLARIS) && defined(_KERNEL)
2215	net_handle_t net_data_p = ifs->ifs_ipf_ipv6;
2216#endif
2217
2218	tcp = NULL;
2219	icmp6 = NULL;
2220	csump = NULL;
2221	np = nat->nat_ptr;
2222
2223	if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
2224		(void) fr_nat_newfrag(fin, 0, nat);
2225
2226	MUTEX_ENTER(&nat->nat_lock);
2227	nat->nat_bytes[1] += fin->fin_plen;
2228	nat->nat_pkts[1]++;
2229	MUTEX_EXIT(&nat->nat_lock);
2230
2231	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
2232		if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) {
2233			tcp = fin->fin_dp;
2234
2235			tcp->th_sport = nat->nat_outport;
2236			fin->fin_data[0] = ntohs(nat->nat_outport);
2237		}
2238
2239		if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) {
2240			icmp6 = fin->fin_dp;
2241			icmp6->icmp6_id = nat->nat_outport;
2242		}
2243
2244		csump = nat_proto(fin, nat, nflags);
2245	}
2246
2247	fin->fin_ip6->ip6_src = nat->nat_outip6.in6;
2248	fin->fin_src6 = nat->nat_outip6;
2249
2250	nat_update(fin, nat, np);
2251
2252	/*
2253	 * TCP/UDP/ICMPv6 checksum needs to be adjusted.
2254	 */
2255	if (csump != NULL && (!(nflags & IPN_TCPUDP) ||
2256	    !NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m))) {
2257		if (nflags & IPN_TCPUDP &&
2258	   	    NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) {
2259			if (nat->nat_dir == NAT_OUTBOUND)
2260				fix_outcksum(csump, nat->nat_sumd[1]);
2261			else
2262				fix_incksum(csump, nat->nat_sumd[1]);
2263		} else {
2264			if (nat->nat_dir == NAT_OUTBOUND)
2265				fix_outcksum(csump, nat->nat_sumd[0]);
2266			else
2267				fix_incksum(csump, nat->nat_sumd[0]);
2268		}
2269	}
2270#ifdef	IPFILTER_SYNC
2271	ipfsync_update(SMC_NAT, fin, nat->nat_sync);
2272#endif
2273	/* ------------------------------------------------------------- */
2274	/* A few quick notes:						 */
2275	/*	Following are test conditions prior to calling the 	 */
2276	/*	appr_check routine.					 */
2277	/*								 */
2278	/* 	A NULL tcp indicates a non TCP/UDP packet.  When dealing */
2279	/*	with a redirect rule, we attempt to match the packet's	 */
2280	/*	source port against in_dport, otherwise	we'd compare the */
2281	/*	packet's destination.			 		 */
2282	/* ------------------------------------------------------------- */
2283	if ((np != NULL) && (np->in_apr != NULL)) {
2284		i = appr_check(fin, nat);
2285		if (i == 0)
2286			i = 1;
2287	} else
2288		i = 1;
2289	ATOMIC_INCL(ifs->ifs_nat_stats.ns_mapped[1]);
2290	fin->fin_flx |= FI_NATED;
2291	return i;
2292}
2293
2294
2295/* ------------------------------------------------------------------------ */
2296/* Function:    fr_checknat6in                                              */
2297/* Returns:     int - -1 == packet failed NAT checks so block it,           */
2298/*                     0 == no packet translation occurred,                 */
2299/*                     1 == packet was successfully translated.             */
2300/* Parameters:  fin(I)   - pointer to packet information                    */
2301/*              passp(I) - pointer to filtering result flags                */
2302/*                                                                          */
2303/* Check to see if an incoming packet should be changed.  ICMP packets are  */
2304/* first checked to see if they match an existing entry (if an error),      */
2305/* otherwise a search of the current NAT table is made.  If neither results */
2306/* in a match then a search for a matching NAT rule is made.  Create a new  */
2307/* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
2308/* packet header(s) as required.                                            */
2309/* ------------------------------------------------------------------------ */
2310int fr_checknat6in(fin, passp)
2311fr_info_t *fin;
2312u_32_t *passp;
2313{
2314	u_int nflags, natadd;
2315	int rval, natfailed;
2316	struct ifnet *ifp;
2317	struct icmp6_hdr *icmp6;
2318	tcphdr_t *tcp;
2319	u_short dport;
2320	ipnat_t *np;
2321	nat_t *nat;
2322	i6addr_t ipa, iph;
2323	ipf_stack_t *ifs = fin->fin_ifs;
2324
2325	if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0)
2326		return 0;
2327
2328	tcp = NULL;
2329	icmp6 = NULL;
2330	dport = 0;
2331	natadd = 1;
2332	nflags = 0;
2333	natfailed = 0;
2334	ifp = fin->fin_ifp;
2335
2336	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
2337		switch (fin->fin_p)
2338		{
2339		case IPPROTO_TCP :
2340			nflags = IPN_TCP;
2341			break;
2342		case IPPROTO_UDP :
2343			nflags = IPN_UDP;
2344			break;
2345		case IPPROTO_ICMPV6 :
2346			icmp6 = fin->fin_dp;
2347
2348			/*
2349			 * This is an incoming packet, so the destination is
2350			 * the icmp_id and the source port equals 0
2351			 */
2352			if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
2353				nflags = IPN_ICMPQUERY;
2354				dport = icmp6->icmp6_id;
2355			} break;
2356		default :
2357			break;
2358		}
2359
2360		if ((nflags & IPN_TCPUDP)) {
2361			tcp = fin->fin_dp;
2362			dport = tcp->th_dport;
2363		}
2364	}
2365
2366	ipa = fin->fin_dst6;
2367
2368	READ_ENTER(&ifs->ifs_ipf_nat);
2369
2370	if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
2371	    (nat = nat6_icmperror(fin, &nflags, NAT_INBOUND)))
2372		/*EMPTY*/;
2373	else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin)))
2374		natadd = 0;
2375	else if ((nat = nat6_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p,
2376	    &fin->fin_src6.in6, &ipa.in6))) {
2377		nflags = nat->nat_flags;
2378	} else {
2379		u_32_t hv, rmsk;
2380		i6addr_t msk;
2381		int i;
2382
2383		RWLOCK_EXIT(&ifs->ifs_ipf_nat);
2384		i = 3;
2385		msk.i6[0] = 0xffffffff;
2386		msk.i6[1] = 0xffffffff;
2387		msk.i6[2] = 0xffffffff;
2388		msk.i6[3] = 0xffffffff;
2389		rmsk = ifs->ifs_rdr6_masks[3];
2390		WRITE_ENTER(&ifs->ifs_ipf_nat);
2391		/*
2392		 * If there is no current entry in the nat table for this IP#,
2393		 * create one for it (if there is a matching rule).
2394		 */
2395maskloop:
2396		IP6_AND(&ipa, &msk, &iph);
2397		hv = NAT_HASH_FN6(&iph, 0, ifs->ifs_ipf_rdrrules_sz);
2398		for (np = ifs->ifs_rdr_rules[hv]; np; np = np->in_rnext) {
2399			if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
2400				continue;
2401			if (np->in_v != fin->fin_v)
2402				continue;
2403			if (np->in_p && (np->in_p != fin->fin_p))
2404				continue;
2405			if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
2406				continue;
2407			if (np->in_flags & IPN_FILTER) {
2408				if (!nat6_match(fin, np))
2409					continue;
2410			} else {
2411				if (!IP6_MASKEQ(&ipa, &np->in_out[1],
2412				    &np->in_out[0]))
2413					continue;
2414				if (np->in_pmin &&
2415				    ((ntohs(np->in_pmax) < ntohs(dport)) ||
2416				     (ntohs(dport) < ntohs(np->in_pmin))))
2417					continue;
2418			}
2419
2420#ifdef	IPF_V6_PROXIES
2421			if (*np->in_plabel != '\0') {
2422				if (!appr_ok(fin, tcp, np)) {
2423					continue;
2424				}
2425			}
2426#endif
2427
2428			nat = nat6_new(fin, np, NULL, nflags, NAT_INBOUND);
2429			if (nat != NULL) {
2430				np->in_hits++;
2431				break;
2432			} else
2433				natfailed = -1;
2434		}
2435
2436		if ((np == NULL) && (i >= 0)) {
2437			while (i >= 0) {
2438				while (rmsk) {
2439					msk.i6[i] = htonl(ntohl(msk.i6[i])<<1);
2440					if ((rmsk & 0x80000000) != 0) {
2441						rmsk <<= 1;
2442						goto maskloop;
2443					}
2444					rmsk <<= 1;
2445				}
2446				msk.i6[i--] = 0;
2447				if (i >= 0) {
2448					rmsk = ifs->ifs_rdr6_masks[i];
2449					if (rmsk != 0)
2450						goto maskloop;
2451				}
2452			}
2453		}
2454		MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat);
2455	}
2456	if (nat != NULL) {
2457		rval = fr_nat6in(fin, nat, natadd, nflags);
2458	} else {
2459		rval = natfailed;
2460	}
2461	RWLOCK_EXIT(&ifs->ifs_ipf_nat);
2462
2463	if (rval == -1) {
2464		if (passp != NULL)
2465			*passp = FR_BLOCK;
2466		fin->fin_flx |= FI_BADNAT;
2467	}
2468	return rval;
2469}
2470
2471
2472/* ------------------------------------------------------------------------ */
2473/* Function:    fr_nat6in                                                   */
2474/* Returns:     int - -1 == packet failed NAT checks so block it,           */
2475/*                     1 == packet was successfully translated.             */
2476/* Parameters:  fin(I)    - pointer to packet information                   */
2477/*              nat(I)    - pointer to NAT structure                        */
2478/*              natadd(I) - flag indicating if it is safe to add frag cache */
2479/*              nflags(I) - NAT flags set for this packet                   */
2480/* Locks Held:  ipf_nat (READ)                                              */
2481/*                                                                          */
2482/* Translate a packet coming "in" on an interface.                          */
2483/* ------------------------------------------------------------------------ */
2484int fr_nat6in(fin, nat, natadd, nflags)
2485fr_info_t *fin;
2486nat_t *nat;
2487int natadd;
2488u_32_t nflags;
2489{
2490	struct icmp6_hdr *icmp6;
2491	u_short *csump;
2492	tcphdr_t *tcp;
2493	ipnat_t *np;
2494	ipf_stack_t *ifs = fin->fin_ifs;
2495
2496#if defined(SOLARIS) && defined(_KERNEL)
2497	net_handle_t net_data_p = ifs->ifs_ipf_ipv6;
2498#endif
2499
2500	tcp = NULL;
2501	csump = NULL;
2502	np = nat->nat_ptr;
2503	fin->fin_fr = nat->nat_fr;
2504
2505	if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
2506		(void) fr_nat_newfrag(fin, 0, nat);
2507
2508#ifdef	IPF_V6_PROXIES
2509	if (np != NULL) {
2510
2511	/* ------------------------------------------------------------- */
2512	/* A few quick notes:						 */
2513	/*	Following are test conditions prior to calling the 	 */
2514	/*	appr_check routine.					 */
2515	/*								 */
2516	/* 	A NULL tcp indicates a non TCP/UDP packet.  When dealing */
2517	/*	with a map rule, we attempt to match the packet's	 */
2518	/*	source port against in_dport, otherwise	we'd compare the */
2519	/*	packet's destination.			 		 */
2520	/* ------------------------------------------------------------- */
2521		if (np->in_apr != NULL) {
2522			i = appr_check(fin, nat);
2523			if (i == -1) {
2524				return -1;
2525			}
2526		}
2527	}
2528#endif
2529
2530#ifdef	IPFILTER_SYNC
2531	ipfsync_update(SMC_NAT, fin, nat->nat_sync);
2532#endif
2533
2534	MUTEX_ENTER(&nat->nat_lock);
2535	nat->nat_bytes[0] += fin->fin_plen;
2536	nat->nat_pkts[0]++;
2537	MUTEX_EXIT(&nat->nat_lock);
2538
2539	fin->fin_ip6->ip6_dst = nat->nat_inip6.in6;
2540	fin->fin_dst6 = nat->nat_inip6;
2541
2542	if (nflags & IPN_TCPUDP)
2543		tcp = fin->fin_dp;
2544
2545	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
2546		if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) {
2547			tcp->th_dport = nat->nat_inport;
2548			fin->fin_data[1] = ntohs(nat->nat_inport);
2549		}
2550
2551
2552		if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) {
2553			icmp6 = fin->fin_dp;
2554
2555			icmp6->icmp6_id = nat->nat_inport;
2556		}
2557
2558		csump = nat_proto(fin, nat, nflags);
2559	}
2560
2561	nat_update(fin, nat, np);
2562
2563	/*
2564	 * In case they are being forwarded, inbound packets always need to have
2565	 * their checksum adjusted even if hardware checksum validation said OK.
2566	 */
2567	if (csump != NULL) {
2568		if (nat->nat_dir == NAT_OUTBOUND)
2569			fix_incksum(csump, nat->nat_sumd[0]);
2570		else
2571			fix_outcksum(csump, nat->nat_sumd[0]);
2572	}
2573
2574#if defined(SOLARIS) && defined(_KERNEL)
2575	if (nflags & IPN_TCPUDP &&
2576	    NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) {
2577		/*
2578		 * Need to adjust the partial checksum result stored in
2579		 * db_cksum16, which will be used for validation in IP.
2580		 * See IP_CKSUM_RECV().
2581		 * Adjustment data should be the inverse of the IP address
2582		 * changes, because db_cksum16 is supposed to be the complement
2583		 * of the pesudo header.
2584		 */
2585		csump = &fin->fin_m->b_datap->db_cksum16;
2586		if (nat->nat_dir == NAT_OUTBOUND)
2587			fix_outcksum(csump, nat->nat_sumd[1]);
2588		else
2589			fix_incksum(csump, nat->nat_sumd[1]);
2590	}
2591#endif
2592
2593	ATOMIC_INCL(ifs->ifs_nat_stats.ns_mapped[0]);
2594	fin->fin_flx |= FI_NATED;
2595	if (np != NULL && np->in_tag.ipt_num[0] != 0)
2596		fin->fin_nattag = &np->in_tag;
2597	return 1;
2598}
2599
2600
2601/* ------------------------------------------------------------------------ */
2602/* Function:    nat_icmpquerytype6                                          */
2603/* Returns:     int - 1 == success, 0 == failure                            */
2604/* Parameters:  icmptype(I) - ICMP type number                              */
2605/*                                                                          */
2606/* Tests to see if the ICMP type number passed is a query/response type or  */
2607/* not.                                                                     */
2608/* ------------------------------------------------------------------------ */
2609static INLINE int nat_icmpquerytype6(icmptype)
2610int icmptype;
2611{
2612
2613	/*
2614	 * For the ICMP query NAT code, it is essential that both the query
2615	 * and the reply match on the NAT rule. Because the NAT structure
2616	 * does not keep track of the icmptype, and a single NAT structure
2617	 * is used for all icmp types with the same src, dest and id, we
2618	 * simply define the replies as queries as well. The funny thing is,
2619	 * altough it seems silly to call a reply a query, this is exactly
2620	 * as it is defined in the IPv4 specification
2621	 */
2622
2623	switch (icmptype)
2624	{
2625
2626	case ICMP6_ECHO_REPLY:
2627	case ICMP6_ECHO_REQUEST:
2628	/* route aedvertisement/solliciation is currently unsupported: */
2629	/* it would require rewriting the ICMP data section            */
2630	case ICMP6_MEMBERSHIP_QUERY:
2631	case ICMP6_MEMBERSHIP_REPORT:
2632	case ICMP6_MEMBERSHIP_REDUCTION:
2633	case ICMP6_WRUREQUEST:
2634	case ICMP6_WRUREPLY:
2635	case MLD6_MTRACE_RESP:
2636	case MLD6_MTRACE:
2637		return 1;
2638	default:
2639		return 0;
2640	}
2641}
2642