1/*
2 * Copyright (C) 2012 by Darren Reed.
3 *
4 * See the IPFILTER.LICENCE file for details on licencing.
5 */
6#if defined(KERNEL) || defined(_KERNEL)
7# undef KERNEL
8# undef _KERNEL
9# define        KERNEL	1
10# define        _KERNEL	1
11#endif
12#include <sys/errno.h>
13#include <sys/types.h>
14#include <sys/param.h>
15#include <sys/time.h>
16#include <sys/file.h>
17#if defined(_KERNEL) && defined(__NetBSD_Version__) && \
18    (__NetBSD_Version__ >= 399002000)
19# include <sys/kauth.h>
20#endif
21#if !defined(_KERNEL)
22# include <stdio.h>
23# include <string.h>
24# include <stdlib.h>
25# define _KERNEL
26# ifdef ipf_nat6__OpenBSD__
27struct file;
28# endif
29# include <sys/uio.h>
30# undef _KERNEL
31#endif
32#if defined(_KERNEL) && defined(__FreeBSD__)
33# include <sys/filio.h>
34# include <sys/fcntl.h>
35#else
36# include <sys/ioctl.h>
37#endif
38# include <sys/fcntl.h>
39# include <sys/protosw.h>
40#include <sys/socket.h>
41#if defined(_KERNEL)
42# include <sys/systm.h>
43# if !defined(__SVR4)
44#  include <sys/mbuf.h>
45# endif
46#endif
47#if defined(__SVR4)
48# include <sys/filio.h>
49# include <sys/byteorder.h>
50# ifdef _KERNEL
51#  include <sys/dditypes.h>
52# endif
53# include <sys/stream.h>
54# include <sys/kmem.h>
55#endif
56#if defined(__FreeBSD__)
57# include <sys/queue.h>
58#endif
59#include <net/if.h>
60#if defined(__FreeBSD__)
61# include <net/if_var.h>
62#endif
63#ifdef sun
64# include <net/af.h>
65#endif
66#include <net/route.h>
67#include <netinet/in.h>
68#include <netinet/in_systm.h>
69#include <netinet/ip.h>
70
71#ifdef RFC1825
72# include <vpn/md5.h>
73# include <vpn/ipsec.h>
74extern struct ifnet vpnif;
75#endif
76
77# include <netinet/ip_var.h>
78#include <netinet/tcp.h>
79#include <netinet/udp.h>
80#include <netinet/ip_icmp.h>
81#include "netinet/ip_compat.h"
82#include <netinet/tcpip.h>
83#include "netinet/ip_fil.h"
84#include "netinet/ip_nat.h"
85#include "netinet/ip_frag.h"
86#include "netinet/ip_state.h"
87#include "netinet/ip_proxy.h"
88#include "netinet/ip_lookup.h"
89#include "netinet/ip_dstlist.h"
90#include "netinet/ip_sync.h"
91#if defined(__FreeBSD__)
92# include <sys/malloc.h>
93#endif
94#ifdef HAS_SYS_MD5_H
95# include <sys/md5.h>
96#else
97# include "md5.h"
98#endif
99/* END OF INCLUDES */
100
101#undef	SOCKADDR_IN
102#define	SOCKADDR_IN	struct sockaddr_in
103
104
105#ifdef USE_INET6
106static struct hostmap *ipf_nat6_hostmap(ipf_nat_softc_t *, ipnat_t *,
107					     i6addr_t *, i6addr_t *,
108					     i6addr_t *, u_32_t);
109static int ipf_nat6_match(fr_info_t *, ipnat_t *);
110static void ipf_nat6_tabmove(ipf_nat_softc_t *, nat_t *);
111static int ipf_nat6_decap(fr_info_t *, nat_t *);
112static int ipf_nat6_nextaddr(fr_info_t *, nat_addr_t *, i6addr_t *,
113				  i6addr_t *);
114static int ipf_nat6_icmpquerytype(int);
115static int ipf_nat6_out(fr_info_t *, nat_t *, int, u_32_t);
116static int ipf_nat6_in(fr_info_t *, nat_t *, int, u_32_t);
117static int ipf_nat6_builddivertmp(ipf_nat_softc_t *, ipnat_t *);
118static int ipf_nat6_nextaddrinit(ipf_main_softc_t *, char *,
119				      nat_addr_t *, int, void *);
120static int ipf_nat6_insert(ipf_main_softc_t *, ipf_nat_softc_t *,
121				nat_t *);
122
123
124#define	NINCLSIDE6(y,x)	ATOMIC_INCL(softn->ipf_nat_stats.ns_side6[y].x)
125#define	NBUMPSIDE(y,x)	softn->ipf_nat_stats.ns_side[y].x++
126#define	NBUMPSIDE6(y,x)	softn->ipf_nat_stats.ns_side6[y].x++
127#define	NBUMPSIDE6D(y,x) \
128			do { \
129				softn->ipf_nat_stats.ns_side6[y].x++; \
130				DT(x); \
131			} while (0)
132#define	NBUMPSIDE6DX(y,x,z) \
133			do { \
134				softn->ipf_nat_stats.ns_side6[y].x++; \
135				DT(z); \
136			} while (0)
137
138
139/* ------------------------------------------------------------------------ */
140/* Function:    ipf_nat6_ruleaddrinit                                       */
141/* Returns:     int   - 0 == success, else failure                          */
142/* Parameters:  in(I) - NAT rule that requires address fields to be init'd  */
143/*                                                                          */
144/* For each of the source/destination address fields in a NAT rule, call    */
145/* ipf_nat6_nextaddrinit() to prepare the structure for active duty.  Other */
146/* IPv6 specific actions can also be taken care of here.                    */
147/* ------------------------------------------------------------------------ */
148int
149ipf_nat6_ruleaddrinit(ipf_main_softc_t *softc, ipf_nat_softc_t *softn,
150	ipnat_t *n)
151{
152	int idx, error;
153
154	if (n->in_redir == NAT_BIMAP) {
155		n->in_ndstip6 = n->in_osrcip6;
156		n->in_ndstmsk6 = n->in_osrcmsk6;
157		n->in_odstip6 = n->in_nsrcip6;
158		n->in_odstmsk6 = n->in_nsrcmsk6;
159
160	}
161
162	if (n->in_redir & NAT_REDIRECT)
163		idx = 1;
164	else
165		idx = 0;
166	/*
167	 * Initialise all of the address fields.
168	 */
169	error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_osrc, 1,
170				      n->in_ifps[idx]);
171	if (error != 0)
172		return (error);
173
174	error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_odst, 1,
175				      n->in_ifps[idx]);
176	if (error != 0)
177		return (error);
178
179	error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_nsrc, 1,
180				      n->in_ifps[idx]);
181	if (error != 0)
182		return (error);
183
184	error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_ndst, 1,
185				      n->in_ifps[idx]);
186	if (error != 0)
187		return (error);
188
189	if (n->in_redir & NAT_DIVERTUDP)
190		ipf_nat6_builddivertmp(softn, n);
191	return (0);
192}
193
194
195/* ------------------------------------------------------------------------ */
196/* Function:    ipf_nat6_addrdr                                             */
197/* Returns:     Nil                                                         */
198/* Parameters:  n(I) - pointer to NAT rule to add                           */
199/*                                                                          */
200/* Adds a redirect rule to the hash table of redirect rules and the list of */
201/* loaded NAT rules.  Updates the bitmask indicating which netmasks are in  */
202/* use by redirect rules.                                                   */
203/* ------------------------------------------------------------------------ */
204void
205ipf_nat6_addrdr(ipf_nat_softc_t *softn, ipnat_t *n)
206{
207	i6addr_t *mask;
208	ipnat_t **np;
209	i6addr_t j;
210	u_int hv;
211	int k;
212
213	if ((n->in_redir & NAT_BIMAP) == NAT_BIMAP) {
214		k = count6bits(n->in_nsrcmsk6.i6);
215		mask = &n->in_nsrcmsk6;
216		IP6_AND(&n->in_odstip6, &n->in_odstmsk6, &j);
217		hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_rdrrules_sz);
218
219	} else if (n->in_odstatype == FRI_NORMAL) {
220		k = count6bits(n->in_odstmsk6.i6);
221		mask = &n->in_odstmsk6;
222		IP6_AND(&n->in_odstip6, &n->in_odstmsk6, &j);
223		hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_rdrrules_sz);
224	} else {
225		k = 0;
226		hv = 0;
227		mask = NULL;
228	}
229	ipf_inet6_mask_add(k, mask, &softn->ipf_nat6_rdr_mask);
230
231	np = softn->ipf_nat_rdr_rules + hv;
232	while (*np != NULL)
233		np = &(*np)->in_rnext;
234	n->in_rnext = NULL;
235	n->in_prnext = np;
236	n->in_hv[0] = hv;
237	n->in_use++;
238	*np = n;
239}
240
241
242/* ------------------------------------------------------------------------ */
243/* Function:    ipf_nat6_addmap                                             */
244/* Returns:     Nil                                                         */
245/* Parameters:  n(I) - pointer to NAT rule to add                           */
246/*                                                                          */
247/* Adds a NAT map rule to the hash table of rules and the list of  loaded   */
248/* NAT rules.  Updates the bitmask indicating which netmasks are in use by  */
249/* redirect rules.                                                          */
250/* ------------------------------------------------------------------------ */
251void
252ipf_nat6_addmap(ipf_nat_softc_t *softn, ipnat_t *n)
253{
254	i6addr_t *mask;
255	ipnat_t **np;
256	i6addr_t j;
257	u_int hv;
258	int k;
259
260	if (n->in_osrcatype == FRI_NORMAL) {
261		k = count6bits(n->in_osrcmsk6.i6);
262		mask = &n->in_osrcmsk6;
263		IP6_AND(&n->in_osrcip6, &n->in_osrcmsk6, &j);
264		hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_maprules_sz);
265	} else {
266		k = 0;
267		hv = 0;
268		mask = NULL;
269	}
270	ipf_inet6_mask_add(k, mask, &softn->ipf_nat6_map_mask);
271
272	np = softn->ipf_nat_map_rules + hv;
273	while (*np != NULL)
274		np = &(*np)->in_mnext;
275	n->in_mnext = NULL;
276	n->in_pmnext = np;
277	n->in_hv[1] = hv;
278	n->in_use++;
279	*np = n;
280}
281
282
283/* ------------------------------------------------------------------------ */
284/* Function:    ipf_nat6_del_rdr                                             */
285/* Returns:     Nil                                                         */
286/* Parameters:  n(I) - pointer to NAT rule to delete                        */
287/*                                                                          */
288/* Removes a NAT rdr rule from the hash table of NAT rdr rules.             */
289/* ------------------------------------------------------------------------ */
290void
291ipf_nat6_delrdr(ipf_nat_softc_t *softn, ipnat_t *n)
292{
293	i6addr_t *mask;
294	int k;
295
296	if ((n->in_redir & NAT_BIMAP) == NAT_BIMAP) {
297		k = count6bits(n->in_nsrcmsk6.i6);
298		mask = &n->in_nsrcmsk6;
299	} else if (n->in_odstatype == FRI_NORMAL) {
300		k = count6bits(n->in_odstmsk6.i6);
301		mask = &n->in_odstmsk6;
302	} else {
303		k = 0;
304		mask = NULL;
305	}
306	ipf_inet6_mask_del(k, mask, &softn->ipf_nat6_rdr_mask);
307
308	if (n->in_rnext != NULL)
309		n->in_rnext->in_prnext = n->in_prnext;
310	*n->in_prnext = n->in_rnext;
311	n->in_use--;
312}
313
314
315/* ------------------------------------------------------------------------ */
316/* Function:    ipf_nat6_delmap                                             */
317/* Returns:     Nil                                                         */
318/* Parameters:  n(I) - pointer to NAT rule to delete                        */
319/*                                                                          */
320/* Removes a NAT map rule from the hash table of NAT map rules.             */
321/* ------------------------------------------------------------------------ */
322void
323ipf_nat6_delmap(ipf_nat_softc_t *softn, ipnat_t *n)
324{
325	i6addr_t *mask;
326	int k;
327
328	if (n->in_osrcatype == FRI_NORMAL) {
329		k = count6bits(n->in_osrcmsk6.i6);
330		mask = &n->in_osrcmsk6;
331	} else {
332		k = 0;
333		mask = NULL;
334	}
335	ipf_inet6_mask_del(k, mask, &softn->ipf_nat6_map_mask);
336
337	if (n->in_mnext != NULL)
338		n->in_mnext->in_pmnext = n->in_pmnext;
339	*n->in_pmnext = n->in_mnext;
340	n->in_use--;
341}
342
343
344/* ------------------------------------------------------------------------ */
345/* Function:    ipf_nat6_hostmap                                            */
346/* Returns:     struct hostmap* - NULL if no hostmap could be created,      */
347/*                                else a pointer to the hostmapping to use  */
348/* Parameters:  np(I)   - pointer to NAT rule                               */
349/*              real(I) - real IP address                                   */
350/*              map(I)  - mapped IP address                                 */
351/*              port(I) - destination port number                           */
352/* Write Locks: ipf_nat                                                     */
353/*                                                                          */
354/* Check if an ip address has already been allocated for a given mapping    */
355/* that is not doing port based translation.  If is not yet allocated, then */
356/* create a new entry if a non-NULL NAT rule pointer has been supplied.     */
357/* ------------------------------------------------------------------------ */
358static struct hostmap *
359ipf_nat6_hostmap(ipf_nat_softc_t *softn, ipnat_t *np,
360	i6addr_t *src, i6addr_t *dst, i6addr_t *map, u_32_t port)
361{
362	hostmap_t *hm;
363	u_int hv;
364
365	hv = (src->i6[3] ^ dst->i6[3]);
366	hv += (src->i6[2] ^ dst->i6[2]);
367	hv += (src->i6[1] ^ dst->i6[1]);
368	hv += (src->i6[0] ^ dst->i6[0]);
369	hv += src->i6[3];
370	hv += src->i6[2];
371	hv += src->i6[1];
372	hv += src->i6[0];
373	hv += dst->i6[3];
374	hv += dst->i6[2];
375	hv += dst->i6[1];
376	hv += dst->i6[0];
377	hv %= softn->ipf_nat_hostmap_sz;
378	for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_next)
379		if (IP6_EQ(&hm->hm_osrc6, src) &&
380		    IP6_EQ(&hm->hm_odst6, dst) &&
381		    ((np == NULL) || (np == hm->hm_ipnat)) &&
382		    ((port == 0) || (port == hm->hm_port))) {
383			softn->ipf_nat_stats.ns_hm_addref++;
384			hm->hm_ref++;
385			return (hm);
386		}
387
388	if (np == NULL) {
389		softn->ipf_nat_stats.ns_hm_nullnp++;
390		return (NULL);
391	}
392
393	KMALLOC(hm, hostmap_t *);
394	if (hm) {
395		hm->hm_next = softn->ipf_hm_maplist;
396		hm->hm_pnext = &softn->ipf_hm_maplist;
397		if (softn->ipf_hm_maplist != NULL)
398			softn->ipf_hm_maplist->hm_pnext = &hm->hm_next;
399		softn->ipf_hm_maplist = hm;
400		hm->hm_hnext = softn->ipf_hm_maptable[hv];
401		hm->hm_phnext = softn->ipf_hm_maptable + hv;
402		if (softn->ipf_hm_maptable[hv] != NULL)
403			softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
404		softn->ipf_hm_maptable[hv] = hm;
405		hm->hm_ipnat = np;
406		np->in_use++;
407		hm->hm_osrcip6 = *src;
408		hm->hm_odstip6 = *dst;
409		hm->hm_nsrcip6 = *map;
410		hm->hm_ndstip6.i6[0] = 0;
411		hm->hm_ndstip6.i6[1] = 0;
412		hm->hm_ndstip6.i6[2] = 0;
413		hm->hm_ndstip6.i6[3] = 0;
414		hm->hm_ref = 1;
415		hm->hm_port = port;
416		hm->hm_hv = hv;
417		hm->hm_v = 6;
418		softn->ipf_nat_stats.ns_hm_new++;
419	} else {
420		softn->ipf_nat_stats.ns_hm_newfail++;
421	}
422	return (hm);
423}
424
425
426/* ------------------------------------------------------------------------ */
427/* Function:    ipf_nat6_newmap                                             */
428/* Returns:     int - -1 == error, 0 == success                             */
429/* Parameters:  fin(I) - pointer to packet information                      */
430/*              nat(I) - pointer to NAT entry                               */
431/*              ni(I)  - pointer to structure with misc. information needed */
432/*                       to create new NAT entry.                           */
433/*                                                                          */
434/* Given an empty NAT structure, populate it with new information about a   */
435/* new NAT session, as defined by the matching NAT rule.                    */
436/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
437/* to the new IP address for the translation.                               */
438/* ------------------------------------------------------------------------ */
439int
440ipf_nat6_newmap(fr_info_t *fin, nat_t *nat, natinfo_t *ni)
441{
442	ipf_main_softc_t *softc = fin->fin_main_soft;
443	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
444	u_short st_port, dport, sport, port, sp, dp;
445	i6addr_t in, st_ip;
446	hostmap_t *hm;
447	u_32_t flags;
448	ipnat_t *np;
449	nat_t *natl;
450	int l;
451
452	/*
453	 * If it's an outbound packet which doesn't match any existing
454	 * record, then create a new port
455	 */
456	l = 0;
457	hm = NULL;
458	np = ni->nai_np;
459	st_ip = np->in_snip6;
460	st_port = np->in_spnext;
461	flags = nat->nat_flags;
462
463	if (flags & IPN_ICMPQUERY) {
464		sport = fin->fin_data[1];
465		dport = 0;
466	} else {
467		sport = htons(fin->fin_data[0]);
468		dport = htons(fin->fin_data[1]);
469	}
470
471	/*
472	 * Do a loop until we either run out of entries to try or we find
473	 * a NAT mapping that isn't currently being used.  This is done
474	 * because the change to the source is not (usually) being fixed.
475	 */
476	do {
477		port = 0;
478		in = np->in_nsrc.na_nextaddr;
479		if (l == 0) {
480			/*
481			 * Check to see if there is an existing NAT
482			 * setup for this IP address pair.
483			 */
484			hm = ipf_nat6_hostmap(softn, np, &fin->fin_src6,
485					      &fin->fin_dst6, &in, 0);
486			if (hm != NULL)
487				in = hm->hm_nsrcip6;
488		} else if ((l == 1) && (hm != NULL)) {
489			ipf_nat_hostmapdel(softc, &hm);
490		}
491
492		nat->nat_hm = hm;
493
494		if (IP6_ISONES(&np->in_nsrcmsk6) && (np->in_spnext == 0)) {
495			if (l > 0) {
496				NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_1);
497				return (-1);
498			}
499		}
500
501		if ((np->in_redir == NAT_BIMAP) &&
502		    IP6_EQ(&np->in_osrcmsk6, &np->in_nsrcmsk6)) {
503			i6addr_t temp;
504			/*
505			 * map the address block in a 1:1 fashion
506			 */
507			temp.i6[0] = fin->fin_src6.i6[0] &
508				     ~np->in_osrcmsk6.i6[0];
509			temp.i6[1] = fin->fin_src6.i6[1] &
510				     ~np->in_osrcmsk6.i6[1];
511			temp.i6[2] = fin->fin_src6.i6[2] &
512				     ~np->in_osrcmsk6.i6[0];
513			temp.i6[3] = fin->fin_src6.i6[3] &
514				     ~np->in_osrcmsk6.i6[3];
515			in = np->in_nsrcip6;
516			IP6_MERGE(&in, &temp, &np->in_osrc);
517
518#ifdef NEED_128BIT_MATH
519		} else if (np->in_redir & NAT_MAPBLK) {
520			if ((l >= np->in_ppip) || ((l > 0) &&
521			     !(flags & IPN_TCPUDP))) {
522				NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_2);
523				return (-1);
524			}
525			/*
526			 * map-block - Calculate destination address.
527			 */
528			IP6_MASK(&in, &fin->fin_src6, &np->in_osrcmsk6);
529			in = ntohl(in);
530			inb = in;
531			in.s_addr /= np->in_ippip;
532			in.s_addr &= ntohl(~np->in_nsrcmsk6);
533			in.s_addr += ntohl(np->in_nsrcaddr6);
534			/*
535			 * Calculate destination port.
536			 */
537			if ((flags & IPN_TCPUDP) &&
538			    (np->in_ppip != 0)) {
539				port = ntohs(sport) + l;
540				port %= np->in_ppip;
541				port += np->in_ppip *
542					(inb.s_addr % np->in_ippip);
543				port += MAPBLK_MINPORT;
544				port = htons(port);
545			}
546#endif
547
548		} else if (IP6_ISZERO(&np->in_nsrcaddr) &&
549			   IP6_ISONES(&np->in_nsrcmsk)) {
550			/*
551			 * 0/32 - use the interface's IP address.
552			 */
553			if ((l > 0) ||
554			    ipf_ifpaddr(softc, 6, FRI_NORMAL, fin->fin_ifp,
555				       &in, NULL) == -1) {
556				NBUMPSIDE6DX(1, ns_new_ifpaddr,
557					     ns_new_ifpaddr_1);
558				return (-1);
559			}
560
561		} else if (IP6_ISZERO(&np->in_nsrcip6) &&
562			   IP6_ISZERO(&np->in_nsrcmsk6)) {
563			/*
564			 * 0/0 - use the original source address/port.
565			 */
566			if (l > 0) {
567				NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_3);
568				return (-1);
569			}
570			in = fin->fin_src6;
571
572		} else if (!IP6_ISONES(&np->in_nsrcmsk6) &&
573			   (np->in_spnext == 0) && ((l > 0) || (hm == NULL))) {
574			IP6_INC(&np->in_snip6);
575		}
576
577		natl = NULL;
578
579		if ((flags & IPN_TCPUDP) &&
580		    ((np->in_redir & NAT_MAPBLK) == 0) &&
581		    (np->in_flags & IPN_AUTOPORTMAP)) {
582#ifdef NEED_128BIT_MATH
583			/*
584			 * "ports auto" (without map-block)
585			 */
586			if ((l > 0) && (l % np->in_ppip == 0)) {
587				if ((l > np->in_ppip) &&
588				    !IP6_ISONES(&np->in_nsrcmsk)) {
589					IP6_INC(&np->in_snip6)
590				}
591			}
592			if (np->in_ppip != 0) {
593				port = ntohs(sport);
594				port += (l % np->in_ppip);
595				port %= np->in_ppip;
596				port += np->in_ppip *
597					(ntohl(fin->fin_src6) %
598					 np->in_ippip);
599				port += MAPBLK_MINPORT;
600				port = htons(port);
601			}
602#endif
603
604		} else if (((np->in_redir & NAT_MAPBLK) == 0) &&
605			   (flags & IPN_TCPUDPICMP) && (np->in_spnext != 0)) {
606		        /*
607		         * Standard port translation.  Select next port.
608		         */
609		        if (np->in_flags & IPN_SEQUENTIAL) {
610		                port = np->in_spnext;
611		        } else {
612				port = ipf_random() % (np->in_spmax -
613						       np->in_spmin + 1);
614		                port += np->in_spmin;
615		        }
616		        port = htons(port);
617		        np->in_spnext++;
618
619			if (np->in_spnext > np->in_spmax) {
620				np->in_spnext = np->in_spmin;
621				if (!IP6_ISONES(&np->in_nsrcmsk6)) {
622					IP6_INC(&np->in_snip6);
623				}
624			}
625		}
626
627		if (np->in_flags & IPN_SIPRANGE) {
628			if (IP6_GT(&np->in_snip, &np->in_nsrcmsk))
629				np->in_snip6 = np->in_nsrcip6;
630		} else {
631			i6addr_t a1, a2;
632
633			a1 = np->in_snip6;
634			IP6_INC(&a1);
635			IP6_AND(&a1, &np->in_nsrcmsk6, &a2);
636
637			if (!IP6_ISONES(&np->in_nsrcmsk6) &&
638			    IP6_GT(&a2, &np->in_nsrcip6)) {
639				IP6_ADD(&np->in_nsrcip6, 1, &np->in_snip6);
640			}
641		}
642
643		if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
644			port = sport;
645
646		/*
647		 * Here we do a lookup of the connection as seen from
648		 * the outside.  If an IP# pair already exists, try
649		 * again.  So if you have A->B becomes C->B, you can
650		 * also have D->E become C->E but not D->B causing
651		 * another C->B.  Also take protocol and ports into
652		 * account when determining whether a pre-existing
653		 * NAT setup will cause an external conflict where
654		 * this is appropriate.
655		 */
656		sp = fin->fin_data[0];
657		dp = fin->fin_data[1];
658		fin->fin_data[0] = fin->fin_data[1];
659		fin->fin_data[1] = ntohs(port);
660		natl = ipf_nat6_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
661					 (u_int)fin->fin_p, &fin->fin_dst6.in6,
662					 &in.in6);
663		fin->fin_data[0] = sp;
664		fin->fin_data[1] = dp;
665
666		/*
667		 * Has the search wrapped around and come back to the
668		 * start ?
669		 */
670		if ((natl != NULL) &&
671		    (np->in_spnext != 0) && (st_port == np->in_spnext) &&
672		    (!IP6_ISZERO(&np->in_snip6) &&
673		     IP6_EQ(&st_ip, &np->in_snip6))) {
674			NBUMPSIDE6D(1, ns_wrap);
675			return (-1);
676		}
677		l++;
678	} while (natl != NULL);
679
680	/* Setup the NAT table */
681	nat->nat_osrc6 = fin->fin_src6;
682	nat->nat_nsrc6 = in;
683	nat->nat_odst6 = fin->fin_dst6;
684	nat->nat_ndst6 = fin->fin_dst6;
685	if (nat->nat_hm == NULL)
686		nat->nat_hm = ipf_nat6_hostmap(softn, np, &fin->fin_src6,
687					       &fin->fin_dst6,
688					       &nat->nat_nsrc6, 0);
689
690	if (flags & IPN_TCPUDP) {
691		nat->nat_osport = sport;
692		nat->nat_nsport = port;	/* sport */
693		nat->nat_odport = dport;
694		nat->nat_ndport = dport;
695		((tcphdr_t *)fin->fin_dp)->th_sport = port;
696	} else if (flags & IPN_ICMPQUERY) {
697		nat->nat_oicmpid = fin->fin_data[1];
698		((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = port;
699		nat->nat_nicmpid = port;
700	}
701	return (0);
702}
703
704
705/* ------------------------------------------------------------------------ */
706/* Function:    ipf_nat6_newrdr                                             */
707/* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
708/*                    allow rule to be moved if IPN_ROUNDR is set.          */
709/* Parameters:  fin(I) - pointer to packet information                      */
710/*              nat(I) - pointer to NAT entry                               */
711/*              ni(I)  - pointer to structure with misc. information needed */
712/*                       to create new NAT entry.                           */
713/*                                                                          */
714/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
715/* to the new IP address for the translation.                               */
716/* ------------------------------------------------------------------------ */
717int
718ipf_nat6_newrdr(fr_info_t *fin, nat_t *nat, natinfo_t *ni)
719{
720	ipf_main_softc_t *softc = fin->fin_main_soft;
721	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
722	u_short nport, dport, sport;
723	u_short sp, dp;
724	hostmap_t *hm;
725	u_32_t flags;
726	i6addr_t in;
727	ipnat_t *np;
728	nat_t *natl;
729	int move;
730
731	move = 1;
732	hm = NULL;
733	in.i6[0] = 0;
734	in.i6[1] = 0;
735	in.i6[2] = 0;
736	in.i6[3] = 0;
737	np = ni->nai_np;
738	flags = nat->nat_flags;
739
740	if (flags & IPN_ICMPQUERY) {
741		dport = fin->fin_data[1];
742		sport = 0;
743	} else {
744		sport = htons(fin->fin_data[0]);
745		dport = htons(fin->fin_data[1]);
746	}
747
748	/* TRACE sport, dport */
749
750
751	/*
752	 * If the matching rule has IPN_STICKY set, then we want to have the
753	 * same rule kick in as before.  Why would this happen?  If you have
754	 * a collection of rdr rules with "round-robin sticky", the current
755	 * packet might match a different one to the previous connection but
756	 * we want the same destination to be used.
757	 */
758	if (((np->in_flags & (IPN_ROUNDR|IPN_SPLIT)) != 0) &&
759	    ((np->in_flags & IPN_STICKY) != 0)) {
760		hm = ipf_nat6_hostmap(softn, NULL, &fin->fin_src6,
761				      &fin->fin_dst6, &in, (u_32_t)dport);
762		if (hm != NULL) {
763			in = hm->hm_ndstip6;
764			np = hm->hm_ipnat;
765			ni->nai_np = np;
766			move = 0;
767		}
768	}
769
770	/*
771	 * Otherwise, it's an inbound packet. Most likely, we don't
772	 * want to rewrite source ports and source addresses. Instead,
773	 * we want to rewrite to a fixed internal address and fixed
774	 * internal port.
775	 */
776	if (np->in_flags & IPN_SPLIT) {
777		in = np->in_dnip6;
778
779		if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
780			hm = ipf_nat6_hostmap(softn, NULL, &fin->fin_src6,
781					      &fin->fin_dst6, &in,
782					      (u_32_t)dport);
783			if (hm != NULL) {
784				in = hm->hm_ndstip6;
785				move = 0;
786			}
787		}
788
789		if (hm == NULL || hm->hm_ref == 1) {
790			if (IP6_EQ(&np->in_ndstip6, &in)) {
791				np->in_dnip6 = np->in_ndstmsk6;
792				move = 0;
793			} else {
794				np->in_dnip6 = np->in_ndstip6;
795			}
796		}
797
798	} else if (IP6_ISZERO(&np->in_ndstaddr) &&
799		   IP6_ISONES(&np->in_ndstmsk)) {
800		/*
801		 * 0/32 - use the interface's IP address.
802		 */
803		if (ipf_ifpaddr(softc, 6, FRI_NORMAL, fin->fin_ifp,
804			       &in, NULL) == -1) {
805			NBUMPSIDE6DX(0, ns_new_ifpaddr, ns_new_ifpaddr_2);
806			return (-1);
807		}
808
809	} else if (IP6_ISZERO(&np->in_ndstip6) &&
810		   IP6_ISZERO(&np->in_ndstmsk6)) {
811		/*
812		 * 0/0 - use the original destination address/port.
813		 */
814		in = fin->fin_dst6;
815
816	} else if (np->in_redir == NAT_BIMAP &&
817		   IP6_EQ(&np->in_ndstmsk6, &np->in_odstmsk6)) {
818		i6addr_t temp;
819		/*
820		 * map the address block in a 1:1 fashion
821		 */
822		temp.i6[0] = fin->fin_dst6.i6[0] & ~np->in_osrcmsk6.i6[0];
823		temp.i6[1] = fin->fin_dst6.i6[1] & ~np->in_osrcmsk6.i6[1];
824		temp.i6[2] = fin->fin_dst6.i6[2] & ~np->in_osrcmsk6.i6[0];
825		temp.i6[3] = fin->fin_dst6.i6[3] & ~np->in_osrcmsk6.i6[3];
826		in = np->in_ndstip6;
827		IP6_MERGE(&in, &temp, &np->in_ndstmsk6);
828	} else {
829		in = np->in_ndstip6;
830	}
831
832	if ((np->in_dpnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
833		nport = dport;
834	else {
835		/*
836		 * Whilst not optimized for the case where
837		 * pmin == pmax, the gain is not significant.
838		 */
839		if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
840		    (np->in_odport != np->in_dtop)) {
841			nport = ntohs(dport) - np->in_odport + np->in_dpmax;
842			nport = htons(nport);
843		} else {
844			nport = htons(np->in_dpnext);
845			np->in_dpnext++;
846			if (np->in_dpnext > np->in_dpmax)
847				np->in_dpnext = np->in_dpmin;
848		}
849	}
850
851	/*
852	 * When the redirect-to address is set to 0.0.0.0, just
853	 * assume a blank `forwarding' of the packet.  We don't
854	 * setup any translation for this either.
855	 */
856	if (IP6_ISZERO(&in)) {
857		if (nport == dport) {
858			NBUMPSIDE6D(0, ns_xlate_null);
859			return (-1);
860		}
861		in = fin->fin_dst6;
862	}
863
864	/*
865	 * Check to see if this redirect mapping already exists and if
866	* it does, return "failure" (allowing it to be created will just
867	 * cause one or both of these "connections" to stop working.)
868	 */
869	sp = fin->fin_data[0];
870	dp = fin->fin_data[1];
871	fin->fin_data[1] = fin->fin_data[0];
872	fin->fin_data[0] = ntohs(nport);
873	natl = ipf_nat6_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
874				  (u_int)fin->fin_p, &in.in6,
875				  &fin->fin_src6.in6);
876	fin->fin_data[0] = sp;
877	fin->fin_data[1] = dp;
878	if (natl != NULL) {
879		NBUMPSIDE6D(0, ns_xlate_exists);
880		return (-1);
881	}
882
883	nat->nat_ndst6 = in;
884	nat->nat_odst6 = fin->fin_dst6;
885	nat->nat_nsrc6 = fin->fin_src6;
886	nat->nat_osrc6 = fin->fin_src6;
887	if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0))
888		nat->nat_hm = ipf_nat6_hostmap(softn, np, &fin->fin_src6,
889					       &fin->fin_dst6, &in,
890					       (u_32_t)dport);
891
892	if (flags & IPN_TCPUDP) {
893		nat->nat_odport = dport;
894		nat->nat_ndport = nport;
895		nat->nat_osport = sport;
896		nat->nat_nsport = sport;
897		((tcphdr_t *)fin->fin_dp)->th_dport = nport;
898	} else if (flags & IPN_ICMPQUERY) {
899		nat->nat_oicmpid = fin->fin_data[1];
900		((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = nport;
901		nat->nat_nicmpid = nport;
902	}
903
904	return (move);
905}
906
907/* ------------------------------------------------------------------------ */
908/* Function:    ipf_nat6_add                                                */
909/* Returns:     nat6_t*      - NULL == failure to create new NAT structure, */
910/*                             else pointer to new NAT structure            */
911/* Parameters:  fin(I)       - pointer to packet information                */
912/*              np(I)        - pointer to NAT rule                          */
913/*              natsave(I)   - pointer to where to store NAT struct pointer */
914/*              flags(I)     - flags describing the current packet          */
915/*              direction(I) - direction of packet (in/out)                 */
916/* Write Lock:  ipf_nat                                                     */
917/*                                                                          */
918/* Attempts to create a new NAT entry.  Does not actually change the packet */
919/* in any way.                                                              */
920/*                                                                          */
921/* This fucntion is in three main parts: (1) deal with creating a new NAT   */
922/* structure for a "MAP" rule (outgoing NAT translation); (2) deal with     */
923/* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
924/* and (3) building that structure and putting it into the NAT table(s).    */
925/*                                                                          */
926/* NOTE: natsave should NOT be used top point back to an ipstate_t struct   */
927/*       as it can result in memory being corrupted.                        */
928/* ------------------------------------------------------------------------ */
929nat_t *
930ipf_nat6_add(fr_info_t *fin, ipnat_t *np, nat_t **natsave, u_int flags,
931	int direction)
932{
933	ipf_main_softc_t *softc = fin->fin_main_soft;
934	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
935	hostmap_t *hm = NULL;
936	nat_t *nat, *natl;
937	natstat_t *nsp;
938	u_int nflags;
939	natinfo_t ni;
940	int move;
941#if SOLARIS && defined(_KERNEL) && defined(ICK_M_CTL_MAGIC)
942	qpktinfo_t *qpi = fin->fin_qpi;
943#endif
944
945	nsp = &softn->ipf_nat_stats;
946
947	if ((nsp->ns_active * 100 / softn->ipf_nat_table_max) >
948	    softn->ipf_nat_table_wm_high) {
949		softn->ipf_nat_doflush = 1;
950	}
951
952	if (nsp->ns_active >= softn->ipf_nat_table_max) {
953		NBUMPSIDE6(fin->fin_out, ns_table_max);
954		return (NULL);
955	}
956
957	move = 1;
958	nflags = np->in_flags & flags;
959	nflags &= NAT_FROMRULE;
960
961	ni.nai_np = np;
962	ni.nai_dport = 0;
963	ni.nai_sport = 0;
964
965	/* Give me a new nat */
966	KMALLOC(nat, nat_t *);
967	if (nat == NULL) {
968		NBUMPSIDE6(fin->fin_out, ns_memfail);
969		/*
970		 * Try to automatically tune the max # of entries in the
971		 * table allowed to be less than what will cause kmem_alloc()
972		 * to fail and try to eliminate panics due to out of memory
973		 * conditions arising.
974		 */
975		if ((softn->ipf_nat_table_max > softn->ipf_nat_table_sz) &&
976		    (nsp->ns_active > 100)) {
977			softn->ipf_nat_table_max = nsp->ns_active - 100;
978			printf("table_max reduced to %d\n",
979				softn->ipf_nat_table_max);
980		}
981		return (NULL);
982	}
983
984	if (flags & IPN_ICMPQUERY) {
985		/*
986		 * In the ICMP query NAT code, we translate the ICMP id fields
987		 * to make them unique. This is indepedent of the ICMP type
988		 * (e.g. in the unlikely event that a host sends an echo and
989		 * an tstamp request with the same id, both packets will have
990		 * their ip address/id field changed in the same way).
991		 */
992		/* The icmp6_id field is used by the sender to identify the
993		 * process making the icmp request. (the receiver justs
994		 * copies it back in its response). So, it closely matches
995		 * the concept of source port. We overlay sport, so we can
996		 * maximally reuse the existing code.
997		 */
998		ni.nai_sport = fin->fin_data[1];
999		ni.nai_dport = 0;
1000	}
1001
1002	bzero((char *)nat, sizeof(*nat));
1003	nat->nat_flags = flags;
1004	nat->nat_redir = np->in_redir;
1005	nat->nat_dir = direction;
1006	nat->nat_pr[0] = fin->fin_p;
1007	nat->nat_pr[1] = fin->fin_p;
1008
1009	/*
1010	 * Search the current table for a match and create a new mapping
1011	 * if there is none found.
1012	 */
1013	if (np->in_redir & NAT_DIVERTUDP) {
1014		move = ipf_nat6_newdivert(fin, nat, &ni);
1015
1016	} else if (np->in_redir & NAT_REWRITE) {
1017		move = ipf_nat6_newrewrite(fin, nat, &ni);
1018
1019	} else if (direction == NAT_OUTBOUND) {
1020		/*
1021		 * We can now arrange to call this for the same connection
1022		 * because ipf_nat6_new doesn't protect the code path into
1023		 * this function.
1024		 */
1025		natl = ipf_nat6_outlookup(fin, nflags, (u_int)fin->fin_p,
1026					  &fin->fin_src6.in6,
1027					  &fin->fin_dst6.in6);
1028		if (natl != NULL) {
1029			KFREE(nat);
1030			nat = natl;
1031			goto done;
1032		}
1033
1034		move = ipf_nat6_newmap(fin, nat, &ni);
1035	} else {
1036		/*
1037		 * NAT_INBOUND is used for redirects rules
1038		 */
1039		natl = ipf_nat6_inlookup(fin, nflags, (u_int)fin->fin_p,
1040					 &fin->fin_src6.in6,
1041					 &fin->fin_dst6.in6);
1042		if (natl != NULL) {
1043			KFREE(nat);
1044			nat = natl;
1045			goto done;
1046		}
1047
1048		move = ipf_nat6_newrdr(fin, nat, &ni);
1049	}
1050	if (move == -1)
1051		goto badnat;
1052
1053	np = ni.nai_np;
1054
1055	nat->nat_mssclamp = np->in_mssclamp;
1056	nat->nat_me = natsave;
1057	nat->nat_fr = fin->fin_fr;
1058	nat->nat_rev = fin->fin_rev;
1059	nat->nat_ptr = np;
1060	nat->nat_dlocal = np->in_dlocal;
1061
1062	if ((np->in_apr != NULL) && ((nat->nat_flags & NAT_SLAVE) == 0)) {
1063		if (ipf_proxy_new(fin, nat) == -1) {
1064			NBUMPSIDE6D(fin->fin_out, ns_appr_fail);
1065			goto badnat;
1066		}
1067	}
1068
1069	nat->nat_ifps[0] = np->in_ifps[0];
1070	if (np->in_ifps[0] != NULL) {
1071		COPYIFNAME(np->in_v[0], np->in_ifps[0], nat->nat_ifnames[0]);
1072	}
1073
1074	nat->nat_ifps[1] = np->in_ifps[1];
1075	if (np->in_ifps[1] != NULL) {
1076		COPYIFNAME(np->in_v[1], np->in_ifps[1], nat->nat_ifnames[1]);
1077	}
1078
1079	if (ipf_nat6_finalise(fin, nat) == -1) {
1080		goto badnat;
1081	}
1082
1083	np->in_use++;
1084
1085	if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
1086		if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_REDIRECT) {
1087			ipf_nat6_delrdr(softn, np);
1088			ipf_nat6_addrdr(softn, np);
1089		} else if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_MAP) {
1090			ipf_nat6_delmap(softn, np);
1091			ipf_nat6_addmap(softn, np);
1092		}
1093	}
1094
1095	if (flags & SI_WILDP)
1096		nsp->ns_wilds++;
1097	softn->ipf_nat_stats.ns_proto[nat->nat_pr[0]]++;
1098
1099	goto done;
1100badnat:
1101	NBUMPSIDE6(fin->fin_out, ns_badnatnew);
1102	if ((hm = nat->nat_hm) != NULL)
1103		ipf_nat_hostmapdel(softc, &hm);
1104	KFREE(nat);
1105	nat = NULL;
1106done:
1107	if (nat != NULL && np != NULL)
1108		np->in_hits++;
1109	if (natsave != NULL)
1110		*natsave = nat;
1111	return (nat);
1112}
1113
1114
1115/* ------------------------------------------------------------------------ */
1116/* Function:    ipf_nat6_finalise                                           */
1117/* Returns:     int - 0 == sucess, -1 == failure                            */
1118/* Parameters:  fin(I) - pointer to packet information                      */
1119/*              nat(I) - pointer to NAT entry                               */
1120/* Write Lock:  ipf_nat                                                     */
1121/*                                                                          */
1122/* This is the tail end of constructing a new NAT entry and is the same     */
1123/* for both IPv4 and IPv6.                                                  */
1124/* ------------------------------------------------------------------------ */
1125/*ARGSUSED*/
1126int
1127ipf_nat6_finalise(fr_info_t *fin, nat_t *nat)
1128{
1129	ipf_main_softc_t *softc = fin->fin_main_soft;
1130	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1131	u_32_t sum1, sum2, sumd;
1132	frentry_t *fr;
1133	u_32_t flags;
1134
1135	flags = nat->nat_flags;
1136
1137	switch (fin->fin_p)
1138	{
1139	case IPPROTO_ICMPV6 :
1140		sum1 = LONG_SUM6(&nat->nat_osrc6);
1141		sum1 += ntohs(nat->nat_oicmpid);
1142		sum2 = LONG_SUM6(&nat->nat_nsrc6);
1143		sum2 += ntohs(nat->nat_nicmpid);
1144		CALC_SUMD(sum1, sum2, sumd);
1145		nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
1146
1147		sum1 = LONG_SUM6(&nat->nat_odst6);
1148		sum2 = LONG_SUM6(&nat->nat_ndst6);
1149		CALC_SUMD(sum1, sum2, sumd);
1150		nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
1151		break;
1152
1153	case IPPROTO_TCP :
1154	case IPPROTO_UDP :
1155		sum1 = LONG_SUM6(&nat->nat_osrc6);
1156		sum1 += ntohs(nat->nat_osport);
1157		sum2 = LONG_SUM6(&nat->nat_nsrc6);
1158		sum2 += ntohs(nat->nat_nsport);
1159		CALC_SUMD(sum1, sum2, sumd);
1160		nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
1161
1162		sum1 = LONG_SUM6(&nat->nat_odst6);
1163		sum1 += ntohs(nat->nat_odport);
1164		sum2 = LONG_SUM6(&nat->nat_ndst6);
1165		sum2 += ntohs(nat->nat_ndport);
1166		CALC_SUMD(sum1, sum2, sumd);
1167		nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
1168		break;
1169
1170	default :
1171		sum1 = LONG_SUM6(&nat->nat_osrc6);
1172		sum2 = LONG_SUM6(&nat->nat_nsrc6);
1173		CALC_SUMD(sum1, sum2, sumd);
1174		nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
1175
1176		sum1 = LONG_SUM6(&nat->nat_odst6);
1177		sum2 = LONG_SUM6(&nat->nat_ndst6);
1178		CALC_SUMD(sum1, sum2, sumd);
1179		nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
1180		break;
1181	}
1182
1183	/*
1184	 * Compute the partial checksum, just in case.
1185	 * This is only ever placed into outbound packets so care needs
1186	 * to be taken over which pair of addresses are used.
1187	 */
1188	if (nat->nat_dir == NAT_OUTBOUND) {
1189		sum1 = LONG_SUM6(&nat->nat_nsrc6);
1190		sum1 += LONG_SUM6(&nat->nat_ndst6);
1191	} else {
1192		sum1 = LONG_SUM6(&nat->nat_osrc6);
1193		sum1 += LONG_SUM6(&nat->nat_odst6);
1194	}
1195	sum1 += nat->nat_pr[1];
1196	nat->nat_sumd[1] = (sum1 & 0xffff) + (sum1 >> 16);
1197
1198	if ((nat->nat_flags & SI_CLONE) == 0)
1199		nat->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, nat);
1200
1201	if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
1202		nat->nat_mtu[0] = GETIFMTU_6(nat->nat_ifps[0]);
1203	}
1204
1205	if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
1206		nat->nat_mtu[1] = GETIFMTU_6(nat->nat_ifps[1]);
1207	}
1208
1209	nat->nat_v[0] = 6;
1210	nat->nat_v[1] = 6;
1211
1212	if (ipf_nat6_insert(softc, softn, nat) == 0) {
1213		if (softn->ipf_nat_logging)
1214			ipf_nat_log(softc, softn, nat, NL_NEW);
1215		fr = nat->nat_fr;
1216		if (fr != NULL) {
1217			MUTEX_ENTER(&fr->fr_lock);
1218			fr->fr_ref++;
1219			MUTEX_EXIT(&fr->fr_lock);
1220		}
1221		return (0);
1222	}
1223
1224	NBUMPSIDE6D(fin->fin_out, ns_unfinalised);
1225	/*
1226	 * nat6_insert failed, so cleanup time...
1227	 */
1228	if (nat->nat_sync != NULL)
1229		ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
1230	return (-1);
1231}
1232
1233
1234/* ------------------------------------------------------------------------ */
1235/* Function:    ipf_nat6_insert                                             */
1236/* Returns:     int - 0 == sucess, -1 == failure                            */
1237/* Parameters:  softc(I) - pointer to soft context main structure           */
1238/*              softn(I) - pointer to NAT context structure                 */
1239/*              nat(I) - pointer to NAT structure                           */
1240/* Write Lock:  ipf_nat                                                     */
1241/*                                                                          */
1242/* Insert a NAT entry into the hash tables for searching and add it to the  */
1243/* list of active NAT entries.  Adjust global counters when complete.       */
1244/* ------------------------------------------------------------------------ */
1245static int
1246ipf_nat6_insert(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, nat_t *nat)
1247{
1248	u_int hv1, hv2;
1249	u_32_t sp, dp;
1250	ipnat_t *in;
1251
1252	/*
1253	* Try and return an error as early as possible, so calculate the hash
1254	 * entry numbers first and then proceed.
1255	 */
1256	if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
1257		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
1258			sp = nat->nat_osport;
1259			dp = nat->nat_odport;
1260		} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
1261			sp = 0;
1262			dp = nat->nat_oicmpid;
1263		} else {
1264			sp = 0;
1265			dp = 0;
1266		}
1267		hv1 = NAT_HASH_FN6(&nat->nat_osrc6, sp, 0xffffffff);
1268		hv1 = NAT_HASH_FN6(&nat->nat_odst6, hv1 + dp,
1269				   softn->ipf_nat_table_sz);
1270
1271		/*
1272		 * TRACE nat6_osrc6, nat6_osport, nat6_odst6,
1273		 * nat6_odport, hv1
1274		 */
1275
1276		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
1277			sp = nat->nat_nsport;
1278			dp = nat->nat_ndport;
1279		} else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
1280			sp = 0;
1281			dp = nat->nat_nicmpid;
1282		} else {
1283			sp = 0;
1284			dp = 0;
1285		}
1286		hv2 = NAT_HASH_FN6(&nat->nat_nsrc6, sp, 0xffffffff);
1287		hv2 = NAT_HASH_FN6(&nat->nat_ndst6, hv2 + dp,
1288				   softn->ipf_nat_table_sz);
1289		/*
1290		 * TRACE nat6_nsrcaddr, nat6_nsport, nat6_ndstaddr,
1291		 * nat6_ndport, hv1
1292		 */
1293	} else {
1294		hv1 = NAT_HASH_FN6(&nat->nat_osrc6, 0, 0xffffffff);
1295		hv1 = NAT_HASH_FN6(&nat->nat_odst6, hv1,
1296				   softn->ipf_nat_table_sz);
1297		/* TRACE nat6_osrcip6, nat6_odstip6, hv1 */
1298
1299		hv2 = NAT_HASH_FN6(&nat->nat_nsrc6, 0, 0xffffffff);
1300		hv2 = NAT_HASH_FN6(&nat->nat_ndst6, hv2,
1301				   softn->ipf_nat_table_sz);
1302		/* TRACE nat6_nsrcip6, nat6_ndstip6, hv2 */
1303	}
1304
1305	nat->nat_hv[0] = hv1;
1306	nat->nat_hv[1] = hv2;
1307
1308	MUTEX_INIT(&nat->nat_lock, "nat entry lock");
1309
1310	in = nat->nat_ptr;
1311	nat->nat_ref = nat->nat_me ? 2 : 1;
1312
1313	nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
1314	nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0],
1315					  nat->nat_v[0]);
1316
1317	if (nat->nat_ifnames[1][0] != '\0') {
1318		nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
1319		nat->nat_ifps[1] = ipf_resolvenic(softc, nat->nat_ifnames[1],
1320						  nat->nat_v[1]);
1321	} else if (in->in_ifnames[1] != -1) {
1322		char *name;
1323
1324		name = in->in_names + in->in_ifnames[1];
1325		if (name[1] != '\0' && name[0] != '-' && name[0] != '*') {
1326			(void) strncpy(nat->nat_ifnames[1],
1327				       nat->nat_ifnames[0], LIFNAMSIZ);
1328			nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
1329			nat->nat_ifps[1] = nat->nat_ifps[0];
1330		}
1331	}
1332	if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
1333		nat->nat_mtu[0] = GETIFMTU_6(nat->nat_ifps[0]);
1334	}
1335	if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
1336		nat->nat_mtu[1] = GETIFMTU_6(nat->nat_ifps[1]);
1337	}
1338
1339	return (ipf_nat_hashtab_add(softc, softn, nat));
1340}
1341
1342
1343/* ------------------------------------------------------------------------ */
1344/* Function:    ipf_nat6_icmperrorlookup                                    */
1345/* Returns:     nat6_t* - point to matching NAT structure                    */
1346/* Parameters:  fin(I) - pointer to packet information                      */
1347/*              dir(I) - direction of packet (in/out)                       */
1348/*                                                                          */
1349/* Check if the ICMP error message is related to an existing TCP, UDP or    */
1350/* ICMP query nat entry.  It is assumed that the packet is already of the   */
1351/* the required length.                                                     */
1352/* ------------------------------------------------------------------------ */
1353nat_t *
1354ipf_nat6_icmperrorlookup(fr_info_t *fin, int dir)
1355{
1356	ipf_main_softc_t *softc = fin->fin_main_soft;
1357	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1358	struct icmp6_hdr *icmp6, *orgicmp;
1359	int flags = 0, type, minlen;
1360	nat_stat_side_t *nside;
1361	tcphdr_t *tcp = NULL;
1362	u_short data[2];
1363	ip6_t *oip6;
1364	nat_t *nat;
1365	u_int p;
1366
1367	minlen = 40;
1368	icmp6 = fin->fin_dp;
1369	type = icmp6->icmp6_type;
1370	nside = &softn->ipf_nat_stats.ns_side6[fin->fin_out];
1371	/*
1372	 * Does it at least have the return (basic) IP header ?
1373	 * Only a basic IP header (no options) should be with an ICMP error
1374	 * header.  Also, if it's not an error type, then return.
1375	 */
1376	if (!(fin->fin_flx & FI_ICMPERR)) {
1377		ATOMIC_INCL(nside->ns_icmp_basic);
1378		return (NULL);
1379	}
1380
1381	/*
1382	 * Check packet size
1383	 */
1384	if (fin->fin_plen < ICMP6ERR_IPICMPHLEN) {
1385		ATOMIC_INCL(nside->ns_icmp_size);
1386		return (NULL);
1387	}
1388	oip6 = (ip6_t *)((char *)fin->fin_dp + 8);
1389
1390	/*
1391	 * Is the buffer big enough for all of it ?  It's the size of the IP
1392	 * header claimed in the encapsulated part which is of concern.  It
1393	 * may be too big to be in this buffer but not so big that it's
1394	 * outside the ICMP packet, leading to TCP deref's causing problems.
1395	 * This is possible because we don't know how big oip_hl is when we
1396	 * do the pullup early in ipf_check() and thus can't gaurantee it is
1397	 * all here now.
1398	 */
1399#ifdef  _KERNEL
1400	{
1401	mb_t *m;
1402
1403	m = fin->fin_m;
1404# if SOLARIS
1405	if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN >
1406	    (char *)m->b_wptr) {
1407		ATOMIC_INCL(nside->ns_icmp_mbuf);
1408		return (NULL);
1409	}
1410# else
1411	if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN >
1412	    (char *)fin->fin_ip + M_LEN(m)) {
1413		ATOMIC_INCL(nside->ns_icmp_mbuf);
1414		return (NULL);
1415	}
1416# endif
1417	}
1418#endif
1419
1420	if (IP6_NEQ(&fin->fin_dst6, &oip6->ip6_src)) {
1421		ATOMIC_INCL(nside->ns_icmp_address);
1422		return (NULL);
1423	}
1424
1425	p = oip6->ip6_nxt;
1426	if (p == IPPROTO_TCP)
1427		flags = IPN_TCP;
1428	else if (p == IPPROTO_UDP)
1429		flags = IPN_UDP;
1430	else if (p == IPPROTO_ICMPV6) {
1431		orgicmp = (struct icmp6_hdr *)(oip6 + 1);
1432
1433		/* see if this is related to an ICMP query */
1434		if (ipf_nat6_icmpquerytype(orgicmp->icmp6_type)) {
1435			data[0] = fin->fin_data[0];
1436			data[1] = fin->fin_data[1];
1437			fin->fin_data[0] = 0;
1438			fin->fin_data[1] = orgicmp->icmp6_id;
1439
1440			flags = IPN_ICMPERR|IPN_ICMPQUERY;
1441			/*
1442			 * NOTE : dir refers to the direction of the original
1443			 *        ip packet. By definition the icmp error
1444			 *        message flows in the opposite direction.
1445			 */
1446			if (dir == NAT_INBOUND)
1447				nat = ipf_nat6_inlookup(fin, flags, p,
1448						        &oip6->ip6_dst,
1449						        &oip6->ip6_src);
1450			else
1451				nat = ipf_nat6_outlookup(fin, flags, p,
1452							 &oip6->ip6_dst,
1453							 &oip6->ip6_src);
1454			fin->fin_data[0] = data[0];
1455			fin->fin_data[1] = data[1];
1456			return (nat);
1457		}
1458	}
1459
1460	if (flags & IPN_TCPUDP) {
1461		minlen += 8;		/* + 64bits of data to get ports */
1462		/* TRACE (fin,minlen) */
1463		if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) {
1464			ATOMIC_INCL(nside->ns_icmp_short);
1465			return (NULL);
1466		}
1467
1468		data[0] = fin->fin_data[0];
1469		data[1] = fin->fin_data[1];
1470		tcp = (tcphdr_t *)(oip6 + 1);
1471		fin->fin_data[0] = ntohs(tcp->th_dport);
1472		fin->fin_data[1] = ntohs(tcp->th_sport);
1473
1474		if (dir == NAT_INBOUND) {
1475			nat = ipf_nat6_inlookup(fin, flags, p, &oip6->ip6_dst,
1476						&oip6->ip6_src);
1477		} else {
1478			nat = ipf_nat6_outlookup(fin, flags, p, &oip6->ip6_dst,
1479						 &oip6->ip6_src);
1480		}
1481		fin->fin_data[0] = data[0];
1482		fin->fin_data[1] = data[1];
1483		return (nat);
1484	}
1485	if (dir == NAT_INBOUND)
1486		nat = ipf_nat6_inlookup(fin, 0, p, &oip6->ip6_dst,
1487					&oip6->ip6_src);
1488	else
1489		nat = ipf_nat6_outlookup(fin, 0, p, &oip6->ip6_dst,
1490					 &oip6->ip6_src);
1491
1492	return (nat);
1493}
1494
1495
1496/* result = ip1 - ip2 */
1497u_32_t
1498ipf_nat6_ip6subtract(i6addr_t *ip1, i6addr_t *ip2)
1499{
1500	i6addr_t l1, l2, d;
1501	u_short *s1, *s2, *ds;
1502	u_32_t r;
1503	int i, neg;
1504
1505	neg = 0;
1506	l1 = *ip1;
1507	l2 = *ip2;
1508	s1 = (u_short *)&l1;
1509	s2 = (u_short *)&l2;
1510	ds = (u_short *)&d;
1511
1512	for (i = 7; i > 0; i--) {
1513		if (s1[i] > s2[i]) {
1514			ds[i] = s2[i] + 0x10000 - s1[i];
1515			s2[i - 1] += 0x10000;
1516		} else {
1517			ds[i] = s2[i] - s1[i];
1518		}
1519	}
1520	if (s2[0] > s1[0]) {
1521		ds[0] = s2[0] + 0x10000 - s1[0];
1522		neg = 1;
1523	} else {
1524		ds[0] = s2[0] - s1[0];
1525	}
1526
1527	for (i = 0, r = 0; i < 8; i++) {
1528		r += ds[i];
1529	}
1530
1531	return (r);
1532}
1533
1534
1535/* ------------------------------------------------------------------------ */
1536/* Function:    ipf_nat6_icmperror                                          */
1537/* Returns:     nat6_t* - point to matching NAT structure                    */
1538/* Parameters:  fin(I)    - pointer to packet information                   */
1539/*              nflags(I) - NAT flags for this packet                       */
1540/*              dir(I)    - direction of packet (in/out)                    */
1541/*                                                                          */
1542/* Fix up an ICMP packet which is an error message for an existing NAT      */
1543/* session.  This will correct both packet header data and checksums.       */
1544/*                                                                          */
1545/* This should *ONLY* be used for incoming ICMP error packets to make sure  */
1546/* a NAT'd ICMP packet gets correctly recognised.                           */
1547/* ------------------------------------------------------------------------ */
1548nat_t *
1549ipf_nat6_icmperror(fr_info_t *fin, u_int *nflags, int dir)
1550{
1551	ipf_main_softc_t *softc = fin->fin_main_soft;
1552	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1553	u_32_t sum1, sum2, sumd, sumd2;
1554	i6addr_t a1, a2, a3, a4;
1555	struct icmp6_hdr *icmp6;
1556	int flags, dlen, odst;
1557	u_short *csump;
1558	tcphdr_t *tcp;
1559	ip6_t *oip6;
1560	nat_t *nat;
1561	void *dp;
1562
1563	if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
1564		NBUMPSIDE6D(fin->fin_out, ns_icmp_short);
1565		return (NULL);
1566	}
1567
1568	/*
1569	* ipf_nat6_icmperrorlookup() will return NULL for `defective' packets.
1570	 */
1571	if ((fin->fin_v != 6) || !(nat = ipf_nat6_icmperrorlookup(fin, dir))) {
1572		NBUMPSIDE6D(fin->fin_out, ns_icmp_notfound);
1573		return (NULL);
1574	}
1575
1576	tcp = NULL;
1577	csump = NULL;
1578	flags = 0;
1579	sumd2 = 0;
1580	*nflags = IPN_ICMPERR;
1581	icmp6 = fin->fin_dp;
1582	oip6 = (ip6_t *)((u_char *)icmp6 + sizeof(*icmp6));
1583	dp = (u_char *)oip6 + sizeof(*oip6);
1584	if (oip6->ip6_nxt == IPPROTO_TCP) {
1585		tcp = (tcphdr_t *)dp;
1586		csump = (u_short *)&tcp->th_sum;
1587		flags = IPN_TCP;
1588	} else if (oip6->ip6_nxt == IPPROTO_UDP) {
1589		udphdr_t *udp;
1590
1591		udp = (udphdr_t *)dp;
1592		tcp = (tcphdr_t *)dp;
1593		csump = (u_short *)&udp->uh_sum;
1594		flags = IPN_UDP;
1595	} else if (oip6->ip6_nxt == IPPROTO_ICMPV6)
1596		flags = IPN_ICMPQUERY;
1597	dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip);
1598
1599	/*
1600	 * Need to adjust ICMP header to include the real IP#'s and
1601	 * port #'s.  Only apply a checksum change relative to the
1602	 * IP address change as it will be modified again in ipf_nat6_checkout
1603	 * for both address and port.  Two checksum changes are
1604	 * necessary for the two header address changes.  Be careful
1605	 * to only modify the checksum once for the port # and twice
1606	 * for the IP#.
1607	 */
1608
1609	/*
1610	 * Step 1
1611	 * Fix the IP addresses in the offending IP packet. You also need
1612	 * to adjust the IP header checksum of that offending IP packet.
1613	 *
1614	 * Normally, you would expect that the ICMP checksum of the
1615	 * ICMP error message needs to be adjusted as well for the
1616	 * IP address change in oip.
1617	 * However, this is a NOP, because the ICMP checksum is
1618	 * calculated over the complete ICMP packet, which includes the
1619	 * changed oip IP addresses and oip6->ip6_sum. However, these
1620	 * two changes cancel each other out (if the delta for
1621	 * the IP address is x, then the delta for ip_sum is minus x),
1622	 * so no change in the icmp_cksum is necessary.
1623	 *
1624	 * Inbound ICMP
1625	 * ------------
1626	 * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
1627	 * - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b)
1628	 * - OIP_SRC(c)=nat6_newsrcip,          OIP_DST(b)=nat6_newdstip
1629	 *=> OIP_SRC(c)=nat6_oldsrcip,          OIP_DST(b)=nat6_olddstip
1630	 *
1631	 * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
1632	 * - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a)
1633	 * - OIP_SRC(b)=nat6_olddstip,          OIP_DST(a)=nat6_oldsrcip
1634	 *=> OIP_SRC(b)=nat6_newdstip,          OIP_DST(a)=nat6_newsrcip
1635	 *
1636	 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
1637	 * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d)
1638	 * - OIP_SRC(c)=nat6_newsrcip,          OIP_DST(d)=nat6_newdstip
1639	 *=> OIP_SRC(c)=nat6_oldsrcip,          OIP_DST(d)=nat6_olddstip
1640	 *
1641	 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
1642	 * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
1643	 * - OIP_SRC(b)=nat6_olddstip,          OIP_DST(a)=nat6_oldsrcip
1644	 *=> OIP_SRC(b)=nat6_newdstip,          OIP_DST(a)=nat6_newsrcip
1645	 *
1646	 * Outbound ICMP
1647	 * -------------
1648	 * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
1649	 * - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
1650	 * - OIP_SRC(b)=nat6_olddstip,          OIP_DST(a)=nat6_oldsrcip
1651	 *=> OIP_SRC(b)=nat6_newdstip,          OIP_DST(a)=nat6_newsrcip
1652	 *
1653	 * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
1654	 * - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c)
1655	 * - OIP_SRC(a)=nat6_newsrcip,          OIP_DST(c)=nat6_newdstip
1656	 *=> OIP_SRC(a)=nat6_oldsrcip,          OIP_DST(c)=nat6_olddstip
1657	 *
1658	 * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
1659	 * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d)
1660	 * - OIP_SRC(c)=nat6_olddstip,          OIP_DST(d)=nat6_oldsrcip
1661	 *=> OIP_SRC(b)=nat6_newdstip,          OIP_DST(a)=nat6_newsrcip
1662	 *
1663	 * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
1664	 * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a)
1665	 * - OIP_SRC(b)=nat6_newsrcip,          OIP_DST(a)=nat6_newdstip
1666	 *=> OIP_SRC(a)=nat6_oldsrcip,          OIP_DST(c)=nat6_olddstip
1667	 */
1668
1669	if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) ||
1670	    ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) {
1671		a1 = nat->nat_osrc6;
1672		a4.in6 = oip6->ip6_src;
1673		a3 = nat->nat_odst6;
1674		a2.in6 = oip6->ip6_dst;
1675		oip6->ip6_src = a1.in6;
1676		oip6->ip6_dst = a3.in6;
1677		odst = 1;
1678	} else {
1679		a1 = nat->nat_ndst6;
1680		a2.in6 = oip6->ip6_dst;
1681		a3 = nat->nat_nsrc6;
1682		a4.in6 = oip6->ip6_src;
1683		oip6->ip6_dst = a3.in6;
1684		oip6->ip6_src = a1.in6;
1685		odst = 0;
1686	}
1687
1688	sumd = 0;
1689	if (IP6_NEQ(&a3, &a2) || IP6_NEQ(&a1, &a4)) {
1690		if (IP6_GT(&a3, &a2)) {
1691			sumd = ipf_nat6_ip6subtract(&a2, &a3);
1692			sumd--;
1693		} else {
1694			sumd = ipf_nat6_ip6subtract(&a2, &a3);
1695		}
1696		if (IP6_GT(&a1, &a4)) {
1697			sumd += ipf_nat6_ip6subtract(&a4, &a1);
1698			sumd--;
1699		} else {
1700			sumd += ipf_nat6_ip6subtract(&a4, &a1);
1701		}
1702		sumd = ~sumd;
1703	}
1704
1705	sumd2 = sumd;
1706	sum1 = 0;
1707	sum2 = 0;
1708
1709	/*
1710	 * Fix UDP pseudo header checksum to compensate for the
1711	 * IP address change.
1712	 */
1713	if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) {
1714		u_32_t sum3, sum4;
1715		/*
1716		 * Step 2 :
1717		 * For offending TCP/UDP IP packets, translate the ports as
1718		 * well, based on the NAT specification. Of course such
1719		 * a change may be reflected in the ICMP checksum as well.
1720		 *
1721		 * Since the port fields are part of the TCP/UDP checksum
1722		 * of the offending IP packet, you need to adjust that checksum
1723		 * as well... except that the change in the port numbers should
1724		 * be offset by the checksum change.  However, the TCP/UDP
1725		 * checksum will also need to change if there has been an
1726		 * IP address change.
1727		 */
1728		if (odst == 1) {
1729			sum1 = ntohs(nat->nat_osport);
1730			sum4 = ntohs(tcp->th_sport);
1731			sum3 = ntohs(nat->nat_odport);
1732			sum2 = ntohs(tcp->th_dport);
1733
1734			tcp->th_sport = htons(sum1);
1735			tcp->th_dport = htons(sum3);
1736		} else {
1737			sum1 = ntohs(nat->nat_ndport);
1738			sum2 = ntohs(tcp->th_dport);
1739			sum3 = ntohs(nat->nat_nsport);
1740			sum4 = ntohs(tcp->th_sport);
1741
1742			tcp->th_dport = htons(sum3);
1743			tcp->th_sport = htons(sum1);
1744		}
1745		sumd += sum1 - sum4;
1746		sumd += sum3 - sum2;
1747
1748		if (sumd != 0 || sumd2 != 0) {
1749			/*
1750			 * At this point, sumd is the delta to apply to the
1751			 * TCP/UDP header, given the changes in both the IP
1752			 * address and the ports and sumd2 is the delta to
1753			 * apply to the ICMP header, given the IP address
1754			 * change delta that may need to be applied to the
1755			 * TCP/UDP checksum instead.
1756			 *
1757			 * If we will both the IP and TCP/UDP checksums
1758			 * then the ICMP checksum changes by the address
1759			 * delta applied to the TCP/UDP checksum.  If we
1760			 * do not change the TCP/UDP checksum them we
1761			 * apply the delta in ports to the ICMP checksum.
1762			 */
1763			if (oip6->ip6_nxt == IPPROTO_UDP) {
1764				if ((dlen >= 8) && (*csump != 0)) {
1765					ipf_fix_datacksum(csump, sumd);
1766				} else {
1767					sumd2 = sum4 - sum1;
1768					if (sum1 > sum4)
1769						sumd2--;
1770					sumd2 += sum2 - sum3;
1771					if (sum3 > sum2)
1772						sumd2--;
1773				}
1774			} else if (oip6->ip6_nxt == IPPROTO_TCP) {
1775				if (dlen >= 18) {
1776					ipf_fix_datacksum(csump, sumd);
1777				} else {
1778					sumd2 = sum4 - sum1;
1779					if (sum1 > sum4)
1780						sumd2--;
1781					sumd2 += sum2 - sum3;
1782					if (sum3 > sum2)
1783						sumd2--;
1784				}
1785			}
1786			if (sumd2 != 0) {
1787				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
1788				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
1789				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
1790				ipf_fix_incksum(0, &icmp6->icmp6_cksum,
1791						sumd2, 0);
1792			}
1793		}
1794	} else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) {
1795		struct icmp6_hdr *orgicmp;
1796
1797		/*
1798		 * XXX - what if this is bogus hl and we go off the end ?
1799		 * In this case, ipf_nat6_icmperrorlookup() will have
1800		 * returned NULL.
1801		 */
1802		orgicmp = (struct icmp6_hdr *)dp;
1803
1804		if (odst == 1) {
1805			if (orgicmp->icmp6_id != nat->nat_osport) {
1806
1807				/*
1808				 * Fix ICMP checksum (of the offening ICMP
1809				 * query packet) to compensate the change
1810				 * in the ICMP id of the offending ICMP
1811				 * packet.
1812				 *
1813				 * Since you modify orgicmp->icmp6_id with
1814				 * a delta (say x) and you compensate that
1815				 * in origicmp->icmp6_cksum with a delta
1816				 * minus x, you don't have to adjust the
1817				 * overall icmp->icmp6_cksum
1818				 */
1819				sum1 = ntohs(orgicmp->icmp6_id);
1820				sum2 = ntohs(nat->nat_osport);
1821				CALC_SUMD(sum1, sum2, sumd);
1822				orgicmp->icmp6_id = nat->nat_oicmpid;
1823				ipf_fix_datacksum(&orgicmp->icmp6_cksum, sumd);
1824			}
1825		} /* nat6_dir == NAT_INBOUND is impossible for icmp queries */
1826	}
1827	return (nat);
1828}
1829
1830
1831/*
1832 *       MAP-IN    MAP-OUT   RDR-IN   RDR-OUT
1833 * osrc    X       == src    == src      X
1834 * odst    X       == dst    == dst      X
1835 * nsrc  == dst      X         X      == dst
1836 * ndst  == src      X         X      == src
1837 * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND
1838 */
1839/*
1840 * NB: these lookups don't lock access to the list, it assumed that it has
1841 * already been done!
1842 */
1843/* ------------------------------------------------------------------------ */
1844/* Function:    ipf_nat6_inlookup                                           */
1845/* Returns:     nat6_t*   - NULL == no match,                               */
1846/*                          else pointer to matching NAT entry              */
1847/* Parameters:  fin(I)    - pointer to packet information                   */
1848/*              flags(I)  - NAT flags for this packet                       */
1849/*              p(I)      - protocol for this packet                        */
1850/*              src(I)    - source IP address                               */
1851/*              mapdst(I) - destination IP address                          */
1852/*                                                                          */
1853/* Lookup a nat entry based on the mapped destination ip address/port and   */
1854/* real source address/port.  We use this lookup when receiving a packet,   */
1855/* we're looking for a table entry, based on the destination address.       */
1856/*                                                                          */
1857/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
1858/*                                                                          */
1859/* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
1860/*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
1861/*                                                                          */
1862/* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
1863/*            the packet is of said protocol                                */
1864/* ------------------------------------------------------------------------ */
1865nat_t *
1866ipf_nat6_inlookup(fr_info_t *fin, u_int flags, u_int p,
1867	struct in6_addr *src , struct in6_addr *mapdst)
1868{
1869	ipf_main_softc_t *softc = fin->fin_main_soft;
1870	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1871	u_short sport, dport;
1872	grehdr_t *gre;
1873	ipnat_t *ipn;
1874	u_int sflags;
1875	nat_t *nat;
1876	int nflags;
1877	i6addr_t dst;
1878	void *ifp;
1879	u_int hv;
1880
1881	ifp = fin->fin_ifp;
1882	sport = 0;
1883	dport = 0;
1884	gre = NULL;
1885	dst.in6 = *mapdst;
1886	sflags = flags & NAT_TCPUDPICMP;
1887
1888	switch (p)
1889	{
1890	case IPPROTO_TCP :
1891	case IPPROTO_UDP :
1892		sport = htons(fin->fin_data[0]);
1893		dport = htons(fin->fin_data[1]);
1894		break;
1895	case IPPROTO_ICMPV6 :
1896		if (flags & IPN_ICMPERR)
1897			sport = fin->fin_data[1];
1898		else
1899			dport = fin->fin_data[1];
1900		break;
1901	default :
1902		break;
1903	}
1904
1905
1906	if ((flags & SI_WILDP) != 0)
1907		goto find_in_wild_ports;
1908
1909	hv = NAT_HASH_FN6(&dst, dport, 0xffffffff);
1910	hv = NAT_HASH_FN6(src, hv + sport, softn->ipf_nat_table_sz);
1911	nat = softn->ipf_nat_table[1][hv];
1912	/* TRACE dst, dport, src, sport, hv, nat */
1913
1914	for (; nat; nat = nat->nat_hnext[1]) {
1915		if (nat->nat_ifps[0] != NULL) {
1916			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
1917				continue;
1918		}
1919
1920		if (nat->nat_pr[0] != p)
1921			continue;
1922
1923		switch (nat->nat_dir)
1924		{
1925		case NAT_INBOUND :
1926			if (nat->nat_v[0] != 6)
1927				continue;
1928			if (IP6_NEQ(&nat->nat_osrc6, src) ||
1929			    IP6_NEQ(&nat->nat_odst6, &dst))
1930				continue;
1931			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
1932				if (nat->nat_osport != sport)
1933					continue;
1934				if (nat->nat_odport != dport)
1935					continue;
1936
1937			} else if (p == IPPROTO_ICMPV6) {
1938				if (nat->nat_osport != dport) {
1939					continue;
1940				}
1941			}
1942			break;
1943		case NAT_OUTBOUND :
1944			if (nat->nat_v[1] != 6)
1945				continue;
1946			if (IP6_NEQ(&nat->nat_ndst6, src) ||
1947			    IP6_NEQ(&nat->nat_nsrc6, &dst))
1948				continue;
1949			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
1950				if (nat->nat_ndport != sport)
1951					continue;
1952				if (nat->nat_nsport != dport)
1953					continue;
1954
1955			} else if (p == IPPROTO_ICMPV6) {
1956				if (nat->nat_osport != dport) {
1957					continue;
1958				}
1959			}
1960			break;
1961		}
1962
1963
1964		if ((nat->nat_flags & IPN_TCPUDP) != 0) {
1965			ipn = nat->nat_ptr;
1966#ifdef IPF_V6_PROXIES
1967			if ((ipn != NULL) && (nat->nat_aps != NULL))
1968				if (appr_match(fin, nat) != 0)
1969					continue;
1970#endif
1971		}
1972		if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
1973			nat->nat_ifps[0] = ifp;
1974			nat->nat_mtu[0] = GETIFMTU_6(ifp);
1975		}
1976		return (nat);
1977	}
1978
1979	/*
1980	 * So if we didn't find it but there are wildcard members in the hash
1981	 * table, go back and look for them.  We do this search and update here
1982	 * because it is modifying the NAT table and we want to do this only
1983	 * for the first packet that matches.  The exception, of course, is
1984	 * for "dummy" (FI_IGNORE) lookups.
1985	 */
1986find_in_wild_ports:
1987	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
1988		NBUMPSIDE6DX(0, ns_lookup_miss, ns_lookup_miss_1);
1989		return (NULL);
1990	}
1991	if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
1992		NBUMPSIDE6D(0, ns_lookup_nowild);
1993		return (NULL);
1994	}
1995
1996	RWLOCK_EXIT(&softc->ipf_nat);
1997
1998	hv = NAT_HASH_FN6(&dst, 0, 0xffffffff);
1999	hv = NAT_HASH_FN6(src, hv, softn->ipf_nat_table_sz);
2000	WRITE_ENTER(&softc->ipf_nat);
2001
2002	nat = softn->ipf_nat_table[1][hv];
2003	/* TRACE dst, src, hv, nat */
2004	for (; nat; nat = nat->nat_hnext[1]) {
2005		if (nat->nat_ifps[0] != NULL) {
2006			if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
2007				continue;
2008		}
2009
2010		if (nat->nat_pr[0] != fin->fin_p)
2011			continue;
2012
2013		switch (nat->nat_dir)
2014		{
2015		case NAT_INBOUND :
2016			if (nat->nat_v[0] != 6)
2017				continue;
2018			if (IP6_NEQ(&nat->nat_osrc6, src) ||
2019			    IP6_NEQ(&nat->nat_odst6, &dst))
2020				continue;
2021			break;
2022		case NAT_OUTBOUND :
2023			if (nat->nat_v[1] != 6)
2024				continue;
2025			if (IP6_NEQ(&nat->nat_ndst6, src) ||
2026			    IP6_NEQ(&nat->nat_nsrc6, &dst))
2027				continue;
2028			break;
2029		}
2030
2031		nflags = nat->nat_flags;
2032		if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
2033			continue;
2034
2035		if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags,
2036				   NAT_INBOUND) == 1) {
2037			if ((fin->fin_flx & FI_IGNORE) != 0)
2038				break;
2039			if ((nflags & SI_CLONE) != 0) {
2040				nat = ipf_nat_clone(fin, nat);
2041				if (nat == NULL)
2042					break;
2043			} else {
2044				MUTEX_ENTER(&softn->ipf_nat_new);
2045				softn->ipf_nat_stats.ns_wilds--;
2046				MUTEX_EXIT(&softn->ipf_nat_new);
2047			}
2048
2049			if (nat->nat_dir == NAT_INBOUND) {
2050				if (nat->nat_osport == 0) {
2051					nat->nat_osport = sport;
2052					nat->nat_nsport = sport;
2053				}
2054				if (nat->nat_odport == 0) {
2055					nat->nat_odport = dport;
2056					nat->nat_ndport = dport;
2057				}
2058			} else {
2059				if (nat->nat_osport == 0) {
2060					nat->nat_osport = dport;
2061					nat->nat_nsport = dport;
2062				}
2063				if (nat->nat_odport == 0) {
2064					nat->nat_odport = sport;
2065					nat->nat_ndport = sport;
2066				}
2067			}
2068			if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
2069				nat->nat_ifps[0] = ifp;
2070				nat->nat_mtu[0] = GETIFMTU_6(ifp);
2071			}
2072			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
2073			ipf_nat6_tabmove(softn, nat);
2074			break;
2075		}
2076	}
2077
2078	MUTEX_DOWNGRADE(&softc->ipf_nat);
2079
2080	if (nat == NULL) {
2081		NBUMPSIDE6DX(0, ns_lookup_miss, ns_lookup_miss_2);
2082	}
2083	return (nat);
2084}
2085
2086
2087/* ------------------------------------------------------------------------ */
2088/* Function:    ipf_nat6_tabmove                                            */
2089/* Returns:     Nil                                                         */
2090/* Parameters:  nat(I) - pointer to NAT structure                           */
2091/* Write Lock:  ipf_nat                                                     */
2092/*                                                                          */
2093/* This function is only called for TCP/UDP NAT table entries where the     */
2094/* original was placed in the table without hashing on the ports and we now */
2095/* want to include hashing on port numbers.                                 */
2096/* ------------------------------------------------------------------------ */
2097static void
2098ipf_nat6_tabmove(ipf_nat_softc_t *softn, nat_t *nat)
2099{
2100	nat_t **natp;
2101	u_int hv0, hv1;
2102
2103	if (nat->nat_flags & SI_CLONE)
2104		return;
2105
2106	/*
2107	 * Remove the NAT entry from the old location
2108	 */
2109	if (nat->nat_hnext[0])
2110		nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
2111	*nat->nat_phnext[0] = nat->nat_hnext[0];
2112	softn->ipf_nat_stats.ns_side[0].ns_bucketlen[nat->nat_hv[0]]--;
2113
2114	if (nat->nat_hnext[1])
2115		nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
2116	*nat->nat_phnext[1] = nat->nat_hnext[1];
2117	softn->ipf_nat_stats.ns_side[1].ns_bucketlen[nat->nat_hv[1]]--;
2118
2119	/*
2120	 * Add into the NAT table in the new position
2121	 */
2122	if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
2123		hv1 = NAT_HASH_FN6(&nat->nat_osrc6,
2124			nat->nat_osport, 0xffffffff);
2125		hv1 = NAT_HASH_FN6(&nat->nat_odst6, hv1 + nat->nat_odport,
2126			softn->ipf_nat_table_sz);
2127		hv0 = NAT_HASH_FN6(&nat->nat_nsrc6,
2128			nat->nat_nsport, 0xffffffff);
2129		hv0 = NAT_HASH_FN6(&nat->nat_ndst6, hv0 + nat->nat_ndport,
2130			softn->ipf_nat_table_sz);
2131	} else {
2132		hv0 = NAT_HASH_FN6(&nat->nat_osrc6,
2133			nat->nat_osport, 0xffffffff);
2134		hv0 = NAT_HASH_FN6(&nat->nat_odst6, hv0 + nat->nat_odport,
2135			softn->ipf_nat_table_sz);
2136		hv1 = NAT_HASH_FN6(&nat->nat_nsrc6,
2137			nat->nat_nsport, 0xffffffff);
2138		hv1 = NAT_HASH_FN6(&nat->nat_ndst6, hv1 + nat->nat_ndport,
2139			softn->ipf_nat_table_sz);
2140	}
2141
2142	/* TRACE nat_osrc6, nat_osport, nat_odst6, nat_odport, hv0 */
2143	/* TRACE nat_nsrc6, nat_nsport, nat_ndst6, nat_ndport, hv1 */
2144
2145	nat->nat_hv[0] = hv0;
2146	natp = &softn->ipf_nat_table[0][hv0];
2147	if (*natp)
2148		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
2149	nat->nat_phnext[0] = natp;
2150	nat->nat_hnext[0] = *natp;
2151	*natp = nat;
2152	softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]++;
2153
2154	nat->nat_hv[1] = hv1;
2155	natp = &softn->ipf_nat_table[1][hv1];
2156	if (*natp)
2157		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
2158	nat->nat_phnext[1] = natp;
2159	nat->nat_hnext[1] = *natp;
2160	*natp = nat;
2161	softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]++;
2162}
2163
2164
2165/* ------------------------------------------------------------------------ */
2166/* Function:    ipf_nat6_outlookup                                          */
2167/* Returns:     nat6_t*  - NULL == no match,                                */
2168/*                         else pointer to matching NAT entry               */
2169/* Parameters:  fin(I)   - pointer to packet information                    */
2170/*              flags(I) - NAT flags for this packet                        */
2171/*              p(I)     - protocol for this packet                         */
2172/*              src(I)   - source IP address                                */
2173/*              dst(I)   - destination IP address                           */
2174/*              rw(I)    - 1 == write lock on  held, 0 == read lock.        */
2175/*                                                                          */
2176/* Lookup a nat entry based on the source 'real' ip address/port and        */
2177/* destination address/port.  We use this lookup when sending a packet out, */
2178/* we're looking for a table entry, based on the source address.            */
2179/*                                                                          */
2180/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
2181/*                                                                          */
2182/* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
2183/*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
2184/*                                                                          */
2185/* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
2186/*            the packet is of said protocol                                */
2187/* ------------------------------------------------------------------------ */
2188nat_t *
2189ipf_nat6_outlookup(fr_info_t *fin, u_int flags, u_int p,
2190	struct in6_addr *src, struct in6_addr *dst)
2191{
2192	ipf_main_softc_t *softc = fin->fin_main_soft;
2193	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2194	u_short sport, dport;
2195	u_int sflags;
2196	ipnat_t *ipn;
2197	nat_t *nat;
2198	void *ifp;
2199	u_int hv;
2200
2201	ifp = fin->fin_ifp;
2202	sflags = flags & IPN_TCPUDPICMP;
2203	sport = 0;
2204	dport = 0;
2205
2206	switch (p)
2207	{
2208	case IPPROTO_TCP :
2209	case IPPROTO_UDP :
2210		sport = htons(fin->fin_data[0]);
2211		dport = htons(fin->fin_data[1]);
2212		break;
2213	case IPPROTO_ICMPV6 :
2214		if (flags & IPN_ICMPERR)
2215			sport = fin->fin_data[1];
2216		else
2217			dport = fin->fin_data[1];
2218		break;
2219	default :
2220		break;
2221	}
2222
2223	if ((flags & SI_WILDP) != 0)
2224		goto find_out_wild_ports;
2225
2226	hv = NAT_HASH_FN6(src, sport, 0xffffffff);
2227	hv = NAT_HASH_FN6(dst, hv + dport, softn->ipf_nat_table_sz);
2228	nat = softn->ipf_nat_table[0][hv];
2229
2230	/* TRACE src, sport, dst, dport, hv, nat */
2231
2232	for (; nat; nat = nat->nat_hnext[0]) {
2233		if (nat->nat_ifps[1] != NULL) {
2234			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
2235				continue;
2236		}
2237
2238		if (nat->nat_pr[1] != p)
2239			continue;
2240
2241		switch (nat->nat_dir)
2242		{
2243		case NAT_INBOUND :
2244			if (nat->nat_v[1] != 6)
2245				continue;
2246			if (IP6_NEQ(&nat->nat_ndst6, src) ||
2247			    IP6_NEQ(&nat->nat_nsrc6, dst))
2248				continue;
2249
2250			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
2251				if (nat->nat_ndport != sport)
2252					continue;
2253				if (nat->nat_nsport != dport)
2254					continue;
2255
2256			} else if (p == IPPROTO_ICMPV6) {
2257				if (nat->nat_osport != dport) {
2258					continue;
2259				}
2260			}
2261			break;
2262		case NAT_OUTBOUND :
2263			if (nat->nat_v[0] != 6)
2264				continue;
2265			if (IP6_NEQ(&nat->nat_osrc6, src) ||
2266			    IP6_NEQ(&nat->nat_odst6, dst))
2267				continue;
2268
2269			if ((nat->nat_flags & IPN_TCPUDP) != 0) {
2270				if (nat->nat_odport != dport)
2271					continue;
2272				if (nat->nat_osport != sport)
2273					continue;
2274
2275			} else if (p == IPPROTO_ICMPV6) {
2276				if (nat->nat_osport != dport) {
2277					continue;
2278				}
2279			}
2280			break;
2281		}
2282
2283		ipn = nat->nat_ptr;
2284#ifdef IPF_V6_PROXIES
2285		if ((ipn != NULL) && (nat->nat_aps != NULL))
2286			if (appr_match(fin, nat) != 0)
2287				continue;
2288#endif
2289
2290		if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
2291			nat->nat_ifps[1] = ifp;
2292			nat->nat_mtu[1] = GETIFMTU_6(ifp);
2293		}
2294		return (nat);
2295	}
2296
2297	/*
2298	 * So if we didn't find it but there are wildcard members in the hash
2299	 * table, go back and look for them.  We do this search and update here
2300	 * because it is modifying the NAT table and we want to do this only
2301	 * for the first packet that matches.  The exception, of course, is
2302	 * for "dummy" (FI_IGNORE) lookups.
2303	 */
2304find_out_wild_ports:
2305	if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
2306		NBUMPSIDE6DX(1, ns_lookup_miss, ns_lookup_miss_3);
2307		return (NULL);
2308	}
2309	if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
2310		NBUMPSIDE6D(1, ns_lookup_nowild);
2311		return (NULL);
2312	}
2313
2314	RWLOCK_EXIT(&softc->ipf_nat);
2315
2316	hv = NAT_HASH_FN6(src, 0, 0xffffffff);
2317	hv = NAT_HASH_FN6(dst, hv, softn->ipf_nat_table_sz);
2318
2319	WRITE_ENTER(&softc->ipf_nat);
2320
2321	nat = softn->ipf_nat_table[0][hv];
2322	for (; nat; nat = nat->nat_hnext[0]) {
2323		if (nat->nat_ifps[1] != NULL) {
2324			if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
2325				continue;
2326		}
2327
2328		if (nat->nat_pr[1] != fin->fin_p)
2329			continue;
2330
2331		switch (nat->nat_dir)
2332		{
2333		case NAT_INBOUND :
2334			if (nat->nat_v[1] != 6)
2335				continue;
2336			if (IP6_NEQ(&nat->nat_ndst6, src) ||
2337			    IP6_NEQ(&nat->nat_nsrc6, dst))
2338				continue;
2339			break;
2340		case NAT_OUTBOUND :
2341			if (nat->nat_v[0] != 6)
2342			continue;
2343			if (IP6_NEQ(&nat->nat_osrc6, src) ||
2344			    IP6_NEQ(&nat->nat_odst6, dst))
2345				continue;
2346			break;
2347		}
2348
2349		if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP)))
2350			continue;
2351
2352		if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags,
2353				   NAT_OUTBOUND) == 1) {
2354			if ((fin->fin_flx & FI_IGNORE) != 0)
2355				break;
2356			if ((nat->nat_flags & SI_CLONE) != 0) {
2357				nat = ipf_nat_clone(fin, nat);
2358				if (nat == NULL)
2359					break;
2360			} else {
2361				MUTEX_ENTER(&softn->ipf_nat_new);
2362				softn->ipf_nat_stats.ns_wilds--;
2363				MUTEX_EXIT(&softn->ipf_nat_new);
2364			}
2365
2366			if (nat->nat_dir == NAT_OUTBOUND) {
2367				if (nat->nat_osport == 0) {
2368					nat->nat_osport = sport;
2369					nat->nat_nsport = sport;
2370				}
2371				if (nat->nat_odport == 0) {
2372					nat->nat_odport = dport;
2373					nat->nat_ndport = dport;
2374				}
2375			} else {
2376				if (nat->nat_osport == 0) {
2377					nat->nat_osport = dport;
2378					nat->nat_nsport = dport;
2379				}
2380				if (nat->nat_odport == 0) {
2381					nat->nat_odport = sport;
2382					nat->nat_ndport = sport;
2383				}
2384			}
2385			if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
2386				nat->nat_ifps[1] = ifp;
2387				nat->nat_mtu[1] = GETIFMTU_6(ifp);
2388			}
2389			nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
2390			ipf_nat6_tabmove(softn, nat);
2391			break;
2392		}
2393	}
2394
2395	MUTEX_DOWNGRADE(&softc->ipf_nat);
2396
2397	if (nat == NULL) {
2398		NBUMPSIDE6DX(1, ns_lookup_miss, ns_lookup_miss_4);
2399	}
2400	return (nat);
2401}
2402
2403
2404/* ------------------------------------------------------------------------ */
2405/* Function:    ipf_nat6_lookupredir                                        */
2406/* Returns:     nat6_t* - NULL == no match,                                 */
2407/*                       else pointer to matching NAT entry                 */
2408/* Parameters:  np(I) - pointer to description of packet to find NAT table  */
2409/*                      entry for.                                          */
2410/*                                                                          */
2411/* Lookup the NAT tables to search for a matching redirect                  */
2412/* The contents of natlookup_t should imitate those found in a packet that  */
2413/* would be translated - ie a packet coming in for RDR or going out for MAP.*/
2414/* We can do the lookup in one of two ways, imitating an inbound or         */
2415/* outbound  packet.  By default we assume outbound, unless IPN_IN is set.  */
2416/* For IN, the fields are set as follows:                                   */
2417/*     nl_real* = source information                                        */
2418/*     nl_out* = destination information (translated)                       */
2419/* For an out packet, the fields are set like this:                         */
2420/*     nl_in* = source information (untranslated)                           */
2421/*     nl_out* = destination information (translated)                       */
2422/* ------------------------------------------------------------------------ */
2423nat_t *
2424ipf_nat6_lookupredir(natlookup_t *np)
2425{
2426	fr_info_t fi;
2427	nat_t *nat;
2428
2429	bzero((char *)&fi, sizeof(fi));
2430	if (np->nl_flags & IPN_IN) {
2431		fi.fin_data[0] = ntohs(np->nl_realport);
2432		fi.fin_data[1] = ntohs(np->nl_outport);
2433	} else {
2434		fi.fin_data[0] = ntohs(np->nl_inport);
2435		fi.fin_data[1] = ntohs(np->nl_outport);
2436	}
2437	if (np->nl_flags & IPN_TCP)
2438		fi.fin_p = IPPROTO_TCP;
2439	else if (np->nl_flags & IPN_UDP)
2440		fi.fin_p = IPPROTO_UDP;
2441	else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY))
2442		fi.fin_p = IPPROTO_ICMPV6;
2443
2444	/*
2445	 * We can do two sorts of lookups:
2446	 * - IPN_IN: we have the `real' and `out' address, look for `in'.
2447	 * - default: we have the `in' and `out' address, look for `real'.
2448	 */
2449	if (np->nl_flags & IPN_IN) {
2450		if ((nat = ipf_nat6_inlookup(&fi, np->nl_flags, fi.fin_p,
2451					     &np->nl_realip6,
2452					     &np->nl_outip6))) {
2453			np->nl_inip6 = nat->nat_odst6.in6;
2454			np->nl_inport = nat->nat_odport;
2455		}
2456	} else {
2457		/*
2458		 * If nl_inip is non null, this is a lookup based on the real
2459		 * ip address. Else, we use the fake.
2460		 */
2461		if ((nat = ipf_nat6_outlookup(&fi, np->nl_flags, fi.fin_p,
2462					      &np->nl_inip6, &np->nl_outip6))) {
2463
2464			if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
2465				fr_info_t fin;
2466				bzero((char *)&fin, sizeof(fin));
2467				fin.fin_p = nat->nat_pr[0];
2468				fin.fin_data[0] = ntohs(nat->nat_ndport);
2469				fin.fin_data[1] = ntohs(nat->nat_nsport);
2470				if (ipf_nat6_inlookup(&fin, np->nl_flags,
2471						     fin.fin_p,
2472						     &nat->nat_ndst6.in6,
2473						     &nat->nat_nsrc6.in6) !=
2474				    NULL) {
2475					np->nl_flags &= ~IPN_FINDFORWARD;
2476				}
2477			}
2478
2479			np->nl_realip6 = nat->nat_odst6.in6;
2480			np->nl_realport = nat->nat_odport;
2481		}
2482 	}
2483
2484	return (nat);
2485}
2486
2487
2488/* ------------------------------------------------------------------------ */
2489/* Function:    ipf_nat6_match                                              */
2490/* Returns:     int - 0 == no match, 1 == match                             */
2491/* Parameters:  fin(I)   - pointer to packet information                    */
2492/*              np(I)    - pointer to NAT rule                              */
2493/*                                                                          */
2494/* Pull the matching of a packet against a NAT rule out of that complex     */
2495/* loop inside ipf_nat6_checkin() and lay it out properly in its own        */
2496/* function.                                                                */
2497/* ------------------------------------------------------------------------ */
2498static int
2499ipf_nat6_match(fr_info_t *fin, ipnat_t *np)
2500{
2501	frtuc_t *ft;
2502	int match;
2503
2504	match = 0;
2505	switch (np->in_osrcatype)
2506	{
2507	case FRI_NORMAL :
2508		match = IP6_MASKNEQ(&fin->fin_src6, &np->in_osrcmsk6,
2509				    &np->in_osrcip6);
2510		break;
2511	case FRI_LOOKUP :
2512		match = (*np->in_osrcfunc)(fin->fin_main_soft, np->in_osrcptr,
2513					   6, &fin->fin_src6, fin->fin_plen);
2514		break;
2515	}
2516	match ^= ((np->in_flags & IPN_NOTSRC) != 0);
2517	if (match)
2518		return (0);
2519
2520	match = 0;
2521	switch (np->in_odstatype)
2522	{
2523	case FRI_NORMAL :
2524		match = IP6_MASKNEQ(&fin->fin_dst6, &np->in_odstmsk6,
2525				    &np->in_odstip6);
2526		break;
2527	case FRI_LOOKUP :
2528		match = (*np->in_odstfunc)(fin->fin_main_soft, np->in_odstptr,
2529					   6, &fin->fin_dst6, fin->fin_plen);
2530		break;
2531	}
2532
2533	match ^= ((np->in_flags & IPN_NOTDST) != 0);
2534	if (match)
2535		return (0);
2536
2537	ft = &np->in_tuc;
2538	if (!(fin->fin_flx & FI_TCPUDP) ||
2539	    (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
2540		if (ft->ftu_scmp || ft->ftu_dcmp)
2541			return (0);
2542		return (1);
2543	}
2544
2545	return (ipf_tcpudpchk(&fin->fin_fi, ft));
2546}
2547
2548
2549/* ------------------------------------------------------------------------ */
2550/* Function:    ipf_nat6_checkout                                           */
2551/* Returns:     int - -1 == packet failed NAT checks so block it,           */
2552/*                     0 == no packet translation occurred,                 */
2553/*                     1 == packet was successfully translated.             */
2554/* Parameters:  fin(I)   - pointer to packet information                    */
2555/*              passp(I) - pointer to filtering result flags                */
2556/*                                                                          */
2557/* Check to see if an outcoming packet should be changed.  ICMP packets are */
2558/* first checked to see if they match an existing entry (if an error),      */
2559/* otherwise a search of the current NAT table is made.  If neither results */
2560/* in a match then a search for a matching NAT rule is made.  Create a new  */
2561/* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
2562/* packet header(s) as required.                                            */
2563/* ------------------------------------------------------------------------ */
2564int
2565ipf_nat6_checkout(fr_info_t *fin, u_32_t *passp)
2566{
2567	ipf_main_softc_t *softc = fin->fin_main_soft;
2568	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2569	struct icmp6_hdr *icmp6 = NULL;
2570	struct ifnet *ifp, *sifp;
2571	tcphdr_t *tcp = NULL;
2572	int rval, natfailed;
2573	ipnat_t *np = NULL;
2574	u_int nflags = 0;
2575	i6addr_t ipa, iph;
2576	int natadd = 1;
2577	frentry_t *fr;
2578	nat_t *nat;
2579
2580	if (softn->ipf_nat_stats.ns_rules == 0 || softn->ipf_nat_lock != 0)
2581		return (0);
2582
2583	icmp6 = NULL;
2584	natfailed = 0;
2585	fr = fin->fin_fr;
2586	sifp = fin->fin_ifp;
2587	if (fr != NULL) {
2588		ifp = fr->fr_tifs[fin->fin_rev].fd_ptr;
2589		if ((ifp != NULL) && (ifp != (void *)-1))
2590			fin->fin_ifp = ifp;
2591	}
2592	ifp = fin->fin_ifp;
2593
2594	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
2595		switch (fin->fin_p)
2596		{
2597		case IPPROTO_TCP :
2598			nflags = IPN_TCP;
2599			break;
2600		case IPPROTO_UDP :
2601			nflags = IPN_UDP;
2602			break;
2603		case IPPROTO_ICMPV6 :
2604			icmp6 = fin->fin_dp;
2605
2606			/*
2607			 * Apart from ECHO request and reply, all other
2608			 * informational messages should not be translated
2609			 * so as to keep IPv6 working.
2610			 */
2611			if (icmp6->icmp6_type > ICMP6_ECHO_REPLY)
2612				return (0);
2613
2614			/*
2615			 * This is an incoming packet, so the destination is
2616			 * the icmp6_id and the source port equals 0
2617			 */
2618			if ((fin->fin_flx & FI_ICMPQUERY) != 0)
2619				nflags = IPN_ICMPQUERY;
2620			break;
2621		default :
2622			break;
2623		}
2624
2625		if ((nflags & IPN_TCPUDP))
2626			tcp = fin->fin_dp;
2627	}
2628
2629	ipa = fin->fin_src6;
2630
2631	READ_ENTER(&softc->ipf_nat);
2632
2633	if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
2634	    (nat = ipf_nat6_icmperror(fin, &nflags, NAT_OUTBOUND)))
2635		/*EMPTY*/;
2636	else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
2637		natadd = 0;
2638	else if ((nat = ipf_nat6_outlookup(fin, nflags|NAT_SEARCH,
2639					   (u_int)fin->fin_p,
2640					   &fin->fin_src6.in6,
2641					   &fin->fin_dst6.in6))) {
2642		nflags = nat->nat_flags;
2643	} else if (fin->fin_off == 0) {
2644		u_32_t hv, nmsk = 0;
2645		i6addr_t *msk;
2646
2647		/*
2648		 * If there is no current entry in the nat table for this IP#,
2649		 * create one for it (if there is a matching rule).
2650		 */
2651maskloop:
2652		msk = &softn->ipf_nat6_map_active_masks[nmsk];
2653		IP6_AND(&ipa, msk, &iph);
2654		hv = NAT_HASH_FN6(&iph, 0, softn->ipf_nat_maprules_sz);
2655		for (np = softn->ipf_nat_map_rules[hv]; np; np = np->in_mnext) {
2656			if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
2657				continue;
2658			if (np->in_v[0] != 6)
2659				continue;
2660			if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p))
2661				continue;
2662			if ((np->in_flags & IPN_RF) &&
2663			    !(np->in_flags & nflags))
2664				continue;
2665			if (np->in_flags & IPN_FILTER) {
2666				switch (ipf_nat6_match(fin, np))
2667				{
2668				case 0 :
2669					continue;
2670				case -1 :
2671					rval = -1;
2672					goto outmatchfail;
2673				case 1 :
2674				default :
2675					break;
2676				}
2677			} else if (!IP6_MASKEQ(&ipa, &np->in_osrcmsk,
2678					       &np->in_osrcip6))
2679				continue;
2680
2681			if ((fr != NULL) &&
2682			    !ipf_matchtag(&np->in_tag, &fr->fr_nattag))
2683				continue;
2684
2685#ifdef IPF_V6_PROXIES
2686			if (np->in_plabel != -1) {
2687				if (((np->in_flags & IPN_FILTER) == 0) &&
2688				    (np->in_odport != fin->fin_data[1]))
2689					continue;
2690				if (appr_ok(fin, tcp, np) == 0)
2691					continue;
2692			}
2693#endif
2694
2695			if (np->in_flags & IPN_NO) {
2696				np->in_hits++;
2697				break;
2698			}
2699
2700			MUTEX_ENTER(&softn->ipf_nat_new);
2701			nat = ipf_nat6_add(fin, np, NULL, nflags, NAT_OUTBOUND);
2702			MUTEX_EXIT(&softn->ipf_nat_new);
2703			if (nat != NULL) {
2704				np->in_hits++;
2705				break;
2706			}
2707			natfailed = -1;
2708		}
2709		if ((np == NULL) && (nmsk < softn->ipf_nat6_map_max)) {
2710			nmsk++;
2711			goto maskloop;
2712		}
2713	}
2714
2715	if (nat != NULL) {
2716		rval = ipf_nat6_out(fin, nat, natadd, nflags);
2717		if (rval == 1) {
2718			MUTEX_ENTER(&nat->nat_lock);
2719			ipf_nat_update(fin, nat);
2720			nat->nat_bytes[1] += fin->fin_plen;
2721			nat->nat_pkts[1]++;
2722			MUTEX_EXIT(&nat->nat_lock);
2723		}
2724	} else
2725		rval = natfailed;
2726outmatchfail:
2727	RWLOCK_EXIT(&softc->ipf_nat);
2728
2729	switch (rval)
2730	{
2731	case -1 :
2732		if (passp != NULL) {
2733			NBUMPSIDE6D(1, ns_drop);
2734			*passp = FR_BLOCK;
2735			fin->fin_reason = FRB_NATV6;
2736		}
2737		fin->fin_flx |= FI_BADNAT;
2738		NBUMPSIDE6D(1, ns_badnat);
2739		break;
2740	case 0 :
2741		NBUMPSIDE6D(1, ns_ignored);
2742		break;
2743	case 1 :
2744		NBUMPSIDE6D(1, ns_translated);
2745		break;
2746	}
2747	fin->fin_ifp = sifp;
2748	return (rval);
2749}
2750
2751/* ------------------------------------------------------------------------ */
2752/* Function:    ipf_nat6_out                                                */
2753/* Returns:     int - -1 == packet failed NAT checks so block it,           */
2754/*                     1 == packet was successfully translated.             */
2755/* Parameters:  fin(I)    - pointer to packet information                   */
2756/*              nat(I)    - pointer to NAT structure                        */
2757/*              natadd(I) - flag indicating if it is safe to add frag cache */
2758/*              nflags(I) - NAT flags set for this packet                   */
2759/*                                                                          */
2760/* Translate a packet coming "out" on an interface.                         */
2761/* ------------------------------------------------------------------------ */
2762static int
2763ipf_nat6_out(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags)
2764{
2765	ipf_main_softc_t *softc = fin->fin_main_soft;
2766	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2767	struct icmp6_hdr *icmp6;
2768	tcphdr_t *tcp;
2769	ipnat_t *np;
2770	int skip;
2771	int i;
2772
2773	tcp = NULL;
2774	icmp6 = NULL;
2775	np = nat->nat_ptr;
2776
2777	if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL))
2778		(void) ipf_frag_natnew(softc, fin, 0, nat);
2779
2780	/*
2781	 * Address assignment is after the checksum modification because
2782	 * we are using the address in the packet for determining the
2783	 * correct checksum offset (the ICMP error could be coming from
2784	 * anyone...)
2785	 */
2786	switch (nat->nat_dir)
2787	{
2788	case NAT_OUTBOUND :
2789		fin->fin_ip6->ip6_src = nat->nat_nsrc6.in6;
2790		fin->fin_src6 = nat->nat_nsrc6;
2791		fin->fin_ip6->ip6_dst = nat->nat_ndst6.in6;
2792		fin->fin_dst6 = nat->nat_ndst6;
2793		break;
2794
2795	case NAT_INBOUND :
2796		fin->fin_ip6->ip6_src = nat->nat_odst6.in6;
2797		fin->fin_src6 = nat->nat_ndst6;
2798		fin->fin_ip6->ip6_dst = nat->nat_osrc6.in6;
2799		fin->fin_dst6 = nat->nat_nsrc6;
2800		break;
2801
2802	case NAT_DIVERTIN :
2803	    {
2804		mb_t *m;
2805
2806		skip = ipf_nat6_decap(fin, nat);
2807		if (skip <= 0) {
2808			NBUMPSIDE6D(1, ns_decap_fail);
2809			return (-1);
2810		}
2811
2812		m = fin->fin_m;
2813
2814#if SOLARIS && defined(_KERNEL)
2815		m->b_rptr += skip;
2816#else
2817		m->m_data += skip;
2818		m->m_len -= skip;
2819
2820# ifdef M_PKTHDR
2821		if (m->m_flags & M_PKTHDR)
2822			m->m_pkthdr.len -= skip;
2823# endif
2824#endif
2825
2826		MUTEX_ENTER(&nat->nat_lock);
2827		ipf_nat_update(fin, nat);
2828		MUTEX_EXIT(&nat->nat_lock);
2829		fin->fin_flx |= FI_NATED;
2830		if (np != NULL && np->in_tag.ipt_num[0] != 0)
2831			fin->fin_nattag = &np->in_tag;
2832		return (1);
2833		/* NOTREACHED */
2834	    }
2835
2836	case NAT_DIVERTOUT :
2837	    {
2838		udphdr_t *uh;
2839		ip6_t *ip6;
2840		mb_t *m;
2841
2842		m = M_DUP(np->in_divmp);
2843		if (m == NULL) {
2844			NBUMPSIDE6D(1, ns_divert_dup);
2845			return (-1);
2846		}
2847
2848		ip6 = MTOD(m, ip6_t *);
2849
2850		ip6->ip6_plen = htons(fin->fin_plen + 8);
2851
2852		uh = (udphdr_t *)(ip6 + 1);
2853		uh->uh_ulen = htons(fin->fin_plen);
2854
2855		PREP_MB_T(fin, m);
2856
2857		fin->fin_ip6 = ip6;
2858		fin->fin_plen += sizeof(ip6_t) + 8;	/* UDP + new IPv4 hdr */
2859		fin->fin_dlen += sizeof(ip6_t) + 8;	/* UDP + old IPv4 hdr */
2860
2861		nflags &= ~IPN_TCPUDPICMP;
2862
2863		break;
2864	    }
2865
2866	default :
2867		break;
2868	}
2869
2870	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
2871		u_short *csump;
2872
2873		if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) {
2874			tcp = fin->fin_dp;
2875
2876			switch (nat->nat_dir)
2877			{
2878			case NAT_OUTBOUND :
2879				tcp->th_sport = nat->nat_nsport;
2880				fin->fin_data[0] = ntohs(nat->nat_nsport);
2881				tcp->th_dport = nat->nat_ndport;
2882				fin->fin_data[1] = ntohs(nat->nat_ndport);
2883				break;
2884
2885			case NAT_INBOUND :
2886				tcp->th_sport = nat->nat_odport;
2887				fin->fin_data[0] = ntohs(nat->nat_odport);
2888				tcp->th_dport = nat->nat_osport;
2889				fin->fin_data[1] = ntohs(nat->nat_osport);
2890				break;
2891			}
2892		}
2893
2894		if ((nat->nat_nsport != 0) && (nflags & IPN_ICMPQUERY)) {
2895			icmp6 = fin->fin_dp;
2896			icmp6->icmp6_id = nat->nat_nicmpid;
2897		}
2898
2899		csump = ipf_nat_proto(fin, nat, nflags);
2900
2901		/*
2902		 * The above comments do not hold for layer 4 (or higher)
2903		 * checksums...
2904		 */
2905		if (csump != NULL) {
2906			if (nat->nat_dir == NAT_OUTBOUND)
2907				ipf_fix_outcksum(fin->fin_cksum, csump,
2908						 nat->nat_sumd[0],
2909						 nat->nat_sumd[1] +
2910						 fin->fin_dlen);
2911			else
2912				ipf_fix_incksum(fin->fin_cksum, csump,
2913						nat->nat_sumd[0],
2914						nat->nat_sumd[1] +
2915						fin->fin_dlen);
2916		}
2917	}
2918
2919	ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
2920	/* ------------------------------------------------------------- */
2921	/* A few quick notes:                                            */
2922	/*      Following are test conditions prior to calling the       */
2923	/*      ipf_proxy_check routine.                                 */
2924	/*                                                               */
2925	/*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
2926	/*      with a redirect rule, we attempt to match the packet's   */
2927	/*      source port against in_dport, otherwise we'd compare the */
2928	/*      packet's destination.                                    */
2929	/* ------------------------------------------------------------- */
2930	if ((np != NULL) && (np->in_apr != NULL)) {
2931		i = ipf_proxy_check(fin, nat);
2932		if (i == -1) {
2933			NBUMPSIDE6D(1, ns_ipf_proxy_fail);
2934		}
2935	} else {
2936		i = 1;
2937	}
2938	fin->fin_flx |= FI_NATED;
2939	return (i);
2940}
2941
2942
2943/* ------------------------------------------------------------------------ */
2944/* Function:    ipf_nat6_checkin                                            */
2945/* Returns:     int - -1 == packet failed NAT checks so block it,           */
2946/*                     0 == no packet translation occurred,                 */
2947/*                     1 == packet was successfully translated.             */
2948/* Parameters:  fin(I)   - pointer to packet information                    */
2949/*              passp(I) - pointer to filtering result flags                */
2950/*                                                                          */
2951/* Check to see if an incoming packet should be changed.  ICMP packets are  */
2952/* first checked to see if they match an existing entry (if an error),      */
2953/* otherwise a search of the current NAT table is made.  If neither results */
2954/* in a match then a search for a matching NAT rule is made.  Create a new  */
2955/* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
2956/* packet header(s) as required.                                            */
2957/* ------------------------------------------------------------------------ */
2958int
2959ipf_nat6_checkin(fr_info_t *fin, u_32_t *passp)
2960{
2961	ipf_main_softc_t *softc = fin->fin_main_soft;
2962	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2963	struct icmp6_hdr *icmp6;
2964	u_int nflags, natadd;
2965	int rval, natfailed;
2966	struct ifnet *ifp;
2967	i6addr_t ipa, iph;
2968	tcphdr_t *tcp;
2969	u_short dport;
2970	ipnat_t *np;
2971	nat_t *nat;
2972
2973	if (softn->ipf_nat_stats.ns_rules == 0 || softn->ipf_nat_lock != 0)
2974		return (0);
2975
2976	tcp = NULL;
2977	icmp6 = NULL;
2978	dport = 0;
2979	natadd = 1;
2980	nflags = 0;
2981	natfailed = 0;
2982	ifp = fin->fin_ifp;
2983
2984	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
2985		switch (fin->fin_p)
2986		{
2987		case IPPROTO_TCP :
2988			nflags = IPN_TCP;
2989			break;
2990		case IPPROTO_UDP :
2991			nflags = IPN_UDP;
2992			break;
2993		case IPPROTO_ICMPV6 :
2994			icmp6 = fin->fin_dp;
2995
2996			/*
2997			 * Apart from ECHO request and reply, all other
2998			 * informational messages should not be translated
2999			 * so as to keep IPv6 working.
3000			 */
3001			if (icmp6->icmp6_type > ICMP6_ECHO_REPLY)
3002				return (0);
3003
3004			/*
3005			 * This is an incoming packet, so the destination is
3006			 * the icmp6_id and the source port equals 0
3007			 */
3008			if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
3009				nflags = IPN_ICMPQUERY;
3010				dport = icmp6->icmp6_id;
3011			} break;
3012		default :
3013			break;
3014		}
3015
3016		if ((nflags & IPN_TCPUDP)) {
3017			tcp = fin->fin_dp;
3018			dport = fin->fin_data[1];
3019		}
3020	}
3021
3022	ipa = fin->fin_dst6;
3023
3024	READ_ENTER(&softc->ipf_nat);
3025
3026	if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
3027	    (nat = ipf_nat6_icmperror(fin, &nflags, NAT_INBOUND)))
3028		/*EMPTY*/;
3029	else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
3030		natadd = 0;
3031	else if ((nat = ipf_nat6_inlookup(fin, nflags|NAT_SEARCH,
3032					  (u_int)fin->fin_p,
3033					  &fin->fin_src6.in6, &ipa.in6))) {
3034		nflags = nat->nat_flags;
3035	} else if (fin->fin_off == 0) {
3036		u_32_t hv, rmsk = 0;
3037		i6addr_t *msk;
3038
3039		/*
3040		 * If there is no current entry in the nat table for this IP#,
3041		 * create one for it (if there is a matching rule).
3042		 */
3043maskloop:
3044		msk = &softn->ipf_nat6_rdr_active_masks[rmsk];
3045		IP6_AND(&ipa, msk, &iph);
3046		hv = NAT_HASH_FN6(&iph, 0, softn->ipf_nat_rdrrules_sz);
3047		for (np = softn->ipf_nat_rdr_rules[hv]; np; np = np->in_rnext) {
3048			if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
3049				continue;
3050			if (np->in_v[0] != 6)
3051				continue;
3052			if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p))
3053				continue;
3054			if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
3055				continue;
3056			if (np->in_flags & IPN_FILTER) {
3057				switch (ipf_nat6_match(fin, np))
3058				{
3059				case 0 :
3060					continue;
3061				case -1 :
3062					rval = -1;
3063					goto inmatchfail;
3064				case 1 :
3065				default :
3066					break;
3067				}
3068			} else {
3069				if (!IP6_MASKEQ(&ipa, &np->in_odstmsk6,
3070						&np->in_odstip6)) {
3071					continue;
3072				}
3073				if (np->in_odport &&
3074				    ((np->in_dtop < dport) ||
3075				     (dport < np->in_odport)))
3076					continue;
3077			}
3078
3079#ifdef IPF_V6_PROXIES
3080			if (np->in_plabel != -1) {
3081				if (!appr_ok(fin, tcp, np)) {
3082					continue;
3083				}
3084			}
3085#endif
3086
3087			if (np->in_flags & IPN_NO) {
3088				np->in_hits++;
3089				break;
3090			}
3091
3092			MUTEX_ENTER(&softn->ipf_nat_new);
3093			nat = ipf_nat6_add(fin, np, NULL, nflags, NAT_INBOUND);
3094			MUTEX_EXIT(&softn->ipf_nat_new);
3095			if (nat != NULL) {
3096				np->in_hits++;
3097				break;
3098			}
3099			natfailed = -1;
3100		}
3101
3102		if ((np == NULL) && (rmsk < softn->ipf_nat6_rdr_max)) {
3103			rmsk++;
3104			goto maskloop;
3105		}
3106	}
3107	if (nat != NULL) {
3108		rval = ipf_nat6_in(fin, nat, natadd, nflags);
3109		if (rval == 1) {
3110			MUTEX_ENTER(&nat->nat_lock);
3111			ipf_nat_update(fin, nat);
3112			nat->nat_bytes[0] += fin->fin_plen;
3113			nat->nat_pkts[0]++;
3114			MUTEX_EXIT(&nat->nat_lock);
3115		}
3116	} else
3117		rval = natfailed;
3118inmatchfail:
3119	RWLOCK_EXIT(&softc->ipf_nat);
3120
3121	DT2(frb_natv6in, fr_info_t *, fin, int, rval);
3122	switch (rval)
3123	{
3124	case -1 :
3125		if (passp != NULL) {
3126			NBUMPSIDE6D(0, ns_drop);
3127			*passp = FR_BLOCK;
3128			fin->fin_reason = FRB_NATV6;
3129		}
3130		fin->fin_flx |= FI_BADNAT;
3131		NBUMPSIDE6D(0, ns_badnat);
3132		break;
3133	case 0 :
3134		NBUMPSIDE6D(0, ns_ignored);
3135		break;
3136	case 1 :
3137		NBUMPSIDE6D(0, ns_translated);
3138		break;
3139	}
3140	return (rval);
3141}
3142
3143
3144/* ------------------------------------------------------------------------ */
3145/* Function:    ipf_nat6_in                                                 */
3146/* Returns:     int - -1 == packet failed NAT checks so block it,           */
3147/*                     1 == packet was successfully translated.             */
3148/* Parameters:  fin(I)    - pointer to packet information                   */
3149/*              nat(I)    - pointer to NAT structure                        */
3150/*              natadd(I) - flag indicating if it is safe to add frag cache */
3151/*              nflags(I) - NAT flags set for this packet                   */
3152/* Locks Held:   (READ)                                              */
3153/*                                                                          */
3154/* Translate a packet coming "in" on an interface.                          */
3155/* ------------------------------------------------------------------------ */
3156static int
3157ipf_nat6_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags)
3158{
3159	ipf_main_softc_t *softc = fin->fin_main_soft;
3160	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3161	struct icmp6_hdr *icmp6;
3162	u_short *csump;
3163	tcphdr_t *tcp;
3164	ipnat_t *np;
3165	int skip;
3166	int i;
3167
3168	tcp = NULL;
3169	csump = NULL;
3170	np = nat->nat_ptr;
3171	fin->fin_fr = nat->nat_fr;
3172
3173	if (np != NULL) {
3174		if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
3175			(void) ipf_frag_natnew(softc, fin, 0, nat);
3176
3177	/* ------------------------------------------------------------- */
3178	/* A few quick notes:                                            */
3179	/*      Following are test conditions prior to calling the       */
3180	/*      ipf_proxy_check routine.                                 */
3181	/*                                                               */
3182	/*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
3183	/*      with a map rule, we attempt to match the packet's        */
3184	/*      source port against in_dport, otherwise we'd compare the */
3185	/*      packet's destination.                                    */
3186	/* ------------------------------------------------------------- */
3187		if (np->in_apr != NULL) {
3188			i = ipf_proxy_check(fin, nat);
3189			if (i == -1) {
3190				NBUMPSIDE6D(0, ns_ipf_proxy_fail);
3191				return (-1);
3192			}
3193		}
3194	}
3195
3196	ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
3197
3198	/*
3199	 * Fix up checksums, not by recalculating them, but
3200	 * simply computing adjustments.
3201	 * Why only do this for some platforms on inbound packets ?
3202	 * Because for those that it is done, IP processing is yet to happen
3203	 * and so the IPv4 header checksum has not yet been evaluated.
3204	 * Perhaps it should always be done for the benefit of things like
3205	 * fast forwarding (so that it doesn't need to be recomputed) but with
3206	 * header checksum offloading, perhaps it is a moot point.
3207	 */
3208
3209	switch (nat->nat_dir)
3210	{
3211	case NAT_INBOUND :
3212		if ((fin->fin_flx & FI_ICMPERR) == 0) {
3213			fin->fin_ip6->ip6_src = nat->nat_nsrc6.in6;
3214			fin->fin_src6 = nat->nat_nsrc6;
3215		}
3216		fin->fin_ip6->ip6_dst = nat->nat_ndst6.in6;
3217		fin->fin_dst6 = nat->nat_ndst6;
3218		break;
3219
3220	case NAT_OUTBOUND :
3221		if ((fin->fin_flx & FI_ICMPERR) == 0) {
3222			fin->fin_ip6->ip6_src = nat->nat_odst6.in6;
3223			fin->fin_src6 = nat->nat_odst6;
3224		}
3225		fin->fin_ip6->ip6_dst = nat->nat_osrc6.in6;
3226		fin->fin_dst6 = nat->nat_osrc6;
3227		break;
3228
3229	case NAT_DIVERTIN :
3230	    {
3231		udphdr_t *uh;
3232		ip6_t *ip6;
3233		mb_t *m;
3234
3235		m = M_DUP(np->in_divmp);
3236		if (m == NULL) {
3237			NBUMPSIDE6D(0, ns_divert_dup);
3238			return (-1);
3239		}
3240
3241		ip6 = MTOD(m, ip6_t *);
3242		ip6->ip6_plen = htons(fin->fin_plen + sizeof(udphdr_t));
3243
3244		uh = (udphdr_t *)(ip6 + 1);
3245		uh->uh_ulen = ntohs(fin->fin_plen);
3246
3247		PREP_MB_T(fin, m);
3248
3249		fin->fin_ip6 = ip6;
3250		fin->fin_plen += sizeof(ip6_t) + 8;	/* UDP + new IPv6 hdr */
3251		fin->fin_dlen += sizeof(ip6_t) + 8;	/* UDP + old IPv6 hdr */
3252
3253		nflags &= ~IPN_TCPUDPICMP;
3254
3255		break;
3256	    }
3257
3258	case NAT_DIVERTOUT :
3259	    {
3260		mb_t *m;
3261
3262		skip = ipf_nat6_decap(fin, nat);
3263		if (skip <= 0) {
3264			NBUMPSIDE6D(0, ns_decap_fail);
3265			return (-1);
3266		}
3267
3268		m = fin->fin_m;
3269
3270#if SOLARIS && defined(_KERNEL)
3271		m->b_rptr += skip;
3272#else
3273		m->m_data += skip;
3274		m->m_len -= skip;
3275
3276# ifdef M_PKTHDR
3277		if (m->m_flags & M_PKTHDR)
3278			m->m_pkthdr.len -= skip;
3279# endif
3280#endif
3281
3282		ipf_nat_update(fin, nat);
3283		fin->fin_flx |= FI_NATED;
3284		if (np != NULL && np->in_tag.ipt_num[0] != 0)
3285			fin->fin_nattag = &np->in_tag;
3286		return (1);
3287		/* NOTREACHED */
3288	    }
3289	}
3290	if (nflags & IPN_TCPUDP)
3291		tcp = fin->fin_dp;
3292
3293	if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
3294		if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) {
3295			switch (nat->nat_dir)
3296			{
3297			case NAT_INBOUND :
3298				tcp->th_sport = nat->nat_nsport;
3299				fin->fin_data[0] = ntohs(nat->nat_nsport);
3300				tcp->th_dport = nat->nat_ndport;
3301				fin->fin_data[1] = ntohs(nat->nat_ndport);
3302				break;
3303
3304			case NAT_OUTBOUND :
3305				tcp->th_sport = nat->nat_odport;
3306				fin->fin_data[0] = ntohs(nat->nat_odport);
3307				tcp->th_dport = nat->nat_osport;
3308				fin->fin_data[1] = ntohs(nat->nat_osport);
3309				break;
3310			}
3311		}
3312
3313
3314		if ((nat->nat_odport != 0) && (nflags & IPN_ICMPQUERY)) {
3315			icmp6 = fin->fin_dp;
3316
3317			icmp6->icmp6_id = nat->nat_nicmpid;
3318		}
3319
3320		csump = ipf_nat_proto(fin, nat, nflags);
3321	}
3322
3323	/*
3324	 * The above comments do not hold for layer 4 (or higher) checksums...
3325	 */
3326	if (csump != NULL) {
3327		if (nat->nat_dir == NAT_OUTBOUND)
3328			ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0);
3329		else
3330			ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0);
3331	}
3332	fin->fin_flx |= FI_NATED;
3333	if (np != NULL && np->in_tag.ipt_num[0] != 0)
3334		fin->fin_nattag = &np->in_tag;
3335	return (1);
3336}
3337
3338
3339/* ------------------------------------------------------------------------ */
3340/* Function:    ipf_nat6_newrewrite                                         */
3341/* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
3342/*                    allow rule to be moved if IPN_ROUNDR is set.          */
3343/* Parameters:  fin(I) - pointer to packet information                      */
3344/*              nat(I) - pointer to NAT entry                               */
3345/*              ni(I)  - pointer to structure with misc. information needed */
3346/*                       to create new NAT entry.                           */
3347/* Write Lock:  ipf_nat                                                     */
3348/*                                                                          */
3349/* This function is responsible for setting up an active NAT session where  */
3350/* we are changing both the source and destination parameters at the same   */
3351/* time.  The loop in here works differently to elsewhere - each iteration  */
3352/* is responsible for changing a single parameter that can be incremented.  */
3353/* So one pass may increase the source IP#, next source port, next dest. IP#*/
3354/* and the last destination port for a total of 4 iterations to try each.   */
3355/* This is done to try and exhaustively use the translation space available.*/
3356/* ------------------------------------------------------------------------ */
3357int
3358ipf_nat6_newrewrite(fr_info_t *fin, nat_t *nat, natinfo_t *nai)
3359{
3360	int src_search = 1;
3361	int dst_search = 1;
3362	fr_info_t frnat;
3363	u_32_t flags;
3364	u_short swap;
3365	ipnat_t *np;
3366	nat_t *natl;
3367	int l = 0;
3368	int changed;
3369
3370	natl = NULL;
3371	changed = -1;
3372	np = nai->nai_np;
3373	flags = nat->nat_flags;
3374	bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
3375
3376	nat->nat_hm = NULL;
3377
3378	do {
3379		changed = -1;
3380		/* TRACE (l, src_search, dst_search, np) */
3381
3382		if ((src_search == 0) && (np->in_spnext == 0) &&
3383		    (dst_search == 0) && (np->in_dpnext == 0)) {
3384			if (l > 0)
3385				return (-1);
3386		}
3387
3388		/*
3389		 * Find a new source address
3390		 */
3391		if (ipf_nat6_nextaddr(fin, &np->in_nsrc, &frnat.fin_src6,
3392				 &frnat.fin_src6) == -1) {
3393			return (-1);
3394		}
3395
3396		if (IP6_ISZERO(&np->in_nsrcip6) &&
3397		    IP6_ISONES(&np->in_nsrcmsk6)) {
3398			src_search = 0;
3399			if (np->in_stepnext == 0)
3400				np->in_stepnext = 1;
3401
3402		} else if (IP6_ISZERO(&np->in_nsrcip6) &&
3403			   IP6_ISZERO(&np->in_nsrcmsk6)) {
3404			src_search = 0;
3405			if (np->in_stepnext == 0)
3406				np->in_stepnext = 1;
3407
3408		} else if (IP6_ISONES(&np->in_nsrcmsk)) {
3409			src_search = 0;
3410			if (np->in_stepnext == 0)
3411				np->in_stepnext = 1;
3412
3413		} else if (!IP6_ISONES(&np->in_nsrcmsk6)) {
3414			if (np->in_stepnext == 0 && changed == -1) {
3415				IP6_INC(&np->in_snip);
3416				np->in_stepnext++;
3417				changed = 0;
3418			}
3419		}
3420
3421		if ((flags & IPN_TCPUDPICMP) != 0) {
3422			if (np->in_spnext != 0)
3423				frnat.fin_data[0] = np->in_spnext;
3424
3425			/*
3426			 * Standard port translation.  Select next port.
3427			 */
3428			if ((flags & IPN_FIXEDSPORT) != 0) {
3429				np->in_stepnext = 2;
3430			} else if ((np->in_stepnext == 1) &&
3431				   (changed == -1) && (natl != NULL)) {
3432				np->in_spnext++;
3433				np->in_stepnext++;
3434				changed = 1;
3435				if (np->in_spnext > np->in_spmax)
3436					np->in_spnext = np->in_spmin;
3437			}
3438		} else {
3439			np->in_stepnext = 2;
3440		}
3441		np->in_stepnext &= 0x3;
3442
3443		/*
3444		 * Find a new destination address
3445		 */
3446		/* TRACE (fin, np, l, frnat) */
3447
3448		if (ipf_nat6_nextaddr(fin, &np->in_ndst, &frnat.fin_dst6,
3449				      &frnat.fin_dst6) == -1)
3450			return (-1);
3451
3452		if (IP6_ISZERO(&np->in_ndstip6) &&
3453		    IP6_ISONES(&np->in_ndstmsk6)) {
3454			dst_search = 0;
3455			if (np->in_stepnext == 2)
3456				np->in_stepnext = 3;
3457
3458		} else if (IP6_ISZERO(&np->in_ndstip6) &&
3459			   IP6_ISZERO(&np->in_ndstmsk6)) {
3460			dst_search = 0;
3461			if (np->in_stepnext == 2)
3462				np->in_stepnext = 3;
3463
3464		} else if (IP6_ISONES(&np->in_ndstmsk6)) {
3465			dst_search = 0;
3466			if (np->in_stepnext == 2)
3467				np->in_stepnext = 3;
3468
3469		} else if (!IP6_ISONES(&np->in_ndstmsk6)) {
3470			if ((np->in_stepnext == 2) && (changed == -1) &&
3471			    (natl != NULL)) {
3472				changed = 2;
3473				np->in_stepnext++;
3474				IP6_INC(&np->in_dnip6);
3475			}
3476		}
3477
3478		if ((flags & IPN_TCPUDPICMP) != 0) {
3479			if (np->in_dpnext != 0)
3480				frnat.fin_data[1] = np->in_dpnext;
3481
3482			/*
3483			 * Standard port translation.  Select next port.
3484			 */
3485			if ((flags & IPN_FIXEDDPORT) != 0) {
3486				np->in_stepnext = 0;
3487			} else if (np->in_stepnext == 3 && changed == -1) {
3488				np->in_dpnext++;
3489				np->in_stepnext++;
3490				changed = 3;
3491				if (np->in_dpnext > np->in_dpmax)
3492					np->in_dpnext = np->in_dpmin;
3493			}
3494		} else {
3495			if (np->in_stepnext == 3)
3496				np->in_stepnext = 0;
3497		}
3498
3499		/* TRACE (frnat) */
3500
3501		/*
3502		 * Here we do a lookup of the connection as seen from
3503		 * the outside.  If an IP# pair already exists, try
3504		 * again.  So if you have A->B becomes C->B, you can
3505		 * also have D->E become C->E but not D->B causing
3506		 * another C->B.  Also take protocol and ports into
3507		 * account when determining whether a pre-existing
3508		 * NAT setup will cause an external conflict where
3509		 * this is appropriate.
3510		 *
3511		 * fin_data[] is swapped around because we are doing a
3512		 * lookup of the packet is if it were moving in the opposite
3513		 * direction of the one we are working with now.
3514		 */
3515		if (flags & IPN_TCPUDP) {
3516			swap = frnat.fin_data[0];
3517			frnat.fin_data[0] = frnat.fin_data[1];
3518			frnat.fin_data[1] = swap;
3519		}
3520		if (fin->fin_out == 1) {
3521			natl = ipf_nat6_inlookup(&frnat,
3522					    flags & ~(SI_WILDP|NAT_SEARCH),
3523					    (u_int)frnat.fin_p,
3524					    &frnat.fin_dst6.in6,
3525					    &frnat.fin_src6.in6);
3526
3527		} else {
3528			natl = ipf_nat6_outlookup(&frnat,
3529					     flags & ~(SI_WILDP|NAT_SEARCH),
3530					     (u_int)frnat.fin_p,
3531					     &frnat.fin_dst6.in6,
3532					     &frnat.fin_src6.in6);
3533		}
3534		if (flags & IPN_TCPUDP) {
3535			swap = frnat.fin_data[0];
3536			frnat.fin_data[0] = frnat.fin_data[1];
3537			frnat.fin_data[1] = swap;
3538		}
3539
3540		/* TRACE natl, in_stepnext, l */
3541
3542		if ((natl != NULL) && (l > 8))	/* XXX 8 is arbitrary */
3543			return (-1);
3544
3545		np->in_stepnext &= 0x3;
3546
3547		l++;
3548		changed = -1;
3549	} while (natl != NULL);
3550	nat->nat_osrc6 = fin->fin_src6;
3551	nat->nat_odst6 = fin->fin_dst6;
3552	nat->nat_nsrc6 = frnat.fin_src6;
3553	nat->nat_ndst6 = frnat.fin_dst6;
3554
3555	if ((flags & IPN_TCPUDP) != 0) {
3556		nat->nat_osport = htons(fin->fin_data[0]);
3557		nat->nat_odport = htons(fin->fin_data[1]);
3558		nat->nat_nsport = htons(frnat.fin_data[0]);
3559		nat->nat_ndport = htons(frnat.fin_data[1]);
3560	} else if ((flags & IPN_ICMPQUERY) != 0) {
3561		nat->nat_oicmpid = fin->fin_data[1];
3562		nat->nat_nicmpid = frnat.fin_data[1];
3563	}
3564
3565	return (0);
3566}
3567
3568
3569/* ------------------------------------------------------------------------ */
3570/* Function:    ipf_nat6_newdivert                                          */
3571/* Returns:     int - -1 == error, 0 == success                             */
3572/* Parameters:  fin(I) - pointer to packet information                      */
3573/*              nat(I) - pointer to NAT entry                               */
3574/*              ni(I)  - pointer to structure with misc. information needed */
3575/*                       to create new NAT entry.                           */
3576/* Write Lock:  ipf_nat                                                     */
3577/*                                                                          */
3578/* Create a new NAT divert session as defined by the NAT rule.  This is     */
3579/* somewhat different to other NAT session creation routines because we     */
3580/* do not iterate through either port numbers or IP addresses, searching    */
3581/* for a unique mapping, however, a complimentary duplicate check is made.  */
3582/* ------------------------------------------------------------------------ */
3583int
3584ipf_nat6_newdivert(fr_info_t *fin, nat_t *nat, natinfo_t *nai)
3585{
3586	ipf_main_softc_t *softc = fin->fin_main_soft;
3587	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3588	fr_info_t frnat;
3589	ipnat_t *np;
3590	nat_t *natl;
3591	int p;
3592
3593	np = nai->nai_np;
3594	bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
3595
3596	nat->nat_pr[0] = 0;
3597	nat->nat_osrc6 = fin->fin_src6;
3598	nat->nat_odst6 = fin->fin_dst6;
3599	nat->nat_osport = htons(fin->fin_data[0]);
3600	nat->nat_odport = htons(fin->fin_data[1]);
3601	frnat.fin_src6 = np->in_snip6;
3602	frnat.fin_dst6 = np->in_dnip6;
3603
3604	if (np->in_redir & NAT_DIVERTUDP) {
3605		frnat.fin_data[0] = np->in_spnext;
3606		frnat.fin_data[1] = np->in_dpnext;
3607		frnat.fin_flx |= FI_TCPUDP;
3608		p = IPPROTO_UDP;
3609	} else {
3610		frnat.fin_flx &= ~FI_TCPUDP;
3611		p = IPPROTO_IPIP;
3612	}
3613
3614	if (fin->fin_out == 1) {
3615		natl = ipf_nat6_inlookup(&frnat, 0, p, &frnat.fin_dst6.in6,
3616					 &frnat.fin_src6.in6);
3617
3618	} else {
3619		natl = ipf_nat6_outlookup(&frnat, 0, p, &frnat.fin_dst6.in6,
3620					  &frnat.fin_src6.in6);
3621	}
3622
3623	if (natl != NULL) {
3624		NBUMPSIDE6D(fin->fin_out, ns_divert_exist);
3625		return (-1);
3626	}
3627
3628	nat->nat_nsrc6 = frnat.fin_src6;
3629	nat->nat_ndst6 = frnat.fin_dst6;
3630	if (np->in_redir & NAT_DIVERTUDP) {
3631		nat->nat_nsport = htons(frnat.fin_data[0]);
3632		nat->nat_ndport = htons(frnat.fin_data[1]);
3633	}
3634	nat->nat_pr[fin->fin_out] = fin->fin_p;
3635	nat->nat_pr[1 - fin->fin_out] = p;
3636
3637	if (np->in_redir & NAT_REDIRECT)
3638		nat->nat_dir = NAT_DIVERTIN;
3639	else
3640		nat->nat_dir = NAT_DIVERTOUT;
3641
3642	return (0);
3643}
3644
3645
3646/* ------------------------------------------------------------------------ */
3647/* Function:    nat6_builddivertmp                                          */
3648/* Returns:     int - -1 == error, 0 == success                             */
3649/* Parameters:  np(I) - pointer to a NAT rule                               */
3650/*                                                                          */
3651/* For divert rules, a skeleton packet representing what will be prepended  */
3652/* to the real packet is created.  Even though we don't have the full       */
3653/* packet here, a checksum is calculated that we update later when we       */
3654/* fill in the final details.  At present a 0 checksum for UDP is being set */
3655/* here because it is expected that divert will be used for localhost.      */
3656/* ------------------------------------------------------------------------ */
3657static int
3658ipf_nat6_builddivertmp(ipf_nat_softc_t *softn, ipnat_t *np)
3659{
3660	udphdr_t *uh;
3661	size_t len;
3662	ip6_t *ip6;
3663
3664	if ((np->in_redir & NAT_DIVERTUDP) != 0)
3665		len = sizeof(ip6_t) + sizeof(udphdr_t);
3666	else
3667		len = sizeof(ip6_t);
3668
3669	ALLOC_MB_T(np->in_divmp, len);
3670	if (np->in_divmp == NULL) {
3671		ATOMIC_INCL(softn->ipf_nat_stats.ns_divert_build);
3672		return (-1);
3673	}
3674
3675	/*
3676	 * First, the header to get the packet diverted to the new destination
3677	 */
3678	ip6 = MTOD(np->in_divmp, ip6_t *);
3679	ip6->ip6_vfc = 0x60;
3680	if ((np->in_redir & NAT_DIVERTUDP) != 0)
3681		ip6->ip6_nxt = IPPROTO_UDP;
3682	else
3683		ip6->ip6_nxt = IPPROTO_IPIP;
3684	ip6->ip6_hlim = 255;
3685	ip6->ip6_plen = 0;
3686	ip6->ip6_src = np->in_snip6.in6;
3687	ip6->ip6_dst = np->in_dnip6.in6;
3688
3689	if (np->in_redir & NAT_DIVERTUDP) {
3690		uh = (udphdr_t *)((u_char *)ip6 + sizeof(*ip6));
3691		uh->uh_sum = 0;
3692		uh->uh_ulen = 8;
3693		uh->uh_sport = htons(np->in_spnext);
3694		uh->uh_dport = htons(np->in_dpnext);
3695	}
3696
3697	return (0);
3698}
3699
3700
3701#define	MINDECAP	(sizeof(ip6_t) + sizeof(udphdr_t) + sizeof(ip6_t))
3702
3703/* ------------------------------------------------------------------------ */
3704/* Function:    nat6_decap                                                  */
3705/* Returns:     int - -1 == error, 0 == success                             */
3706/* Parameters:  fin(I) - pointer to packet information                      */
3707/*              nat(I) - pointer to current NAT session                     */
3708/*                                                                          */
3709/* This function is responsible for undoing a packet's encapsulation in the */
3710/* reverse of an encap/divert rule.  After removing the outer encapsulation */
3711/* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/
3712/* match the "new" packet as it may still be used by IPFilter elsewhere.    */
3713/* We use "dir" here as the basis for some of the expectations about the    */
3714/* outer header.  If we return an error, the goal is to leave the original  */
3715/* packet information undisturbed - this falls short at the end where we'd  */
3716/* need to back a backup copy of "fin" - expensive.                         */
3717/* ------------------------------------------------------------------------ */
3718static int
3719ipf_nat6_decap(fr_info_t *fin, nat_t *nat)
3720{
3721	ipf_main_softc_t *softc = fin->fin_main_soft;
3722	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3723	char *hdr;
3724	int skip;
3725	mb_t *m;
3726
3727	if ((fin->fin_flx & FI_ICMPERR) != 0) {
3728		return (0);
3729	}
3730
3731	m = fin->fin_m;
3732	skip = fin->fin_hlen;
3733
3734	switch (nat->nat_dir)
3735	{
3736	case NAT_DIVERTIN :
3737	case NAT_DIVERTOUT :
3738		if (fin->fin_plen < MINDECAP)
3739			return (-1);
3740		skip += sizeof(udphdr_t);
3741		break;
3742
3743	case NAT_ENCAPIN :
3744	case NAT_ENCAPOUT :
3745		if (fin->fin_plen < (skip + sizeof(ip6_t)))
3746			return (-1);
3747		break;
3748	default :
3749		return (-1);
3750		/* NOTREACHED */
3751	}
3752
3753	/*
3754	 * The aim here is to keep the original packet details in "fin" for
3755	 * as long as possible so that returning with an error is for the
3756	 * original packet and there is little undoing work to do.
3757	 */
3758	if (M_LEN(m) < skip + sizeof(ip6_t)) {
3759		if (ipf_pr_pullup(fin, skip + sizeof(ip6_t)) == -1)
3760			return (-1);
3761	}
3762
3763	hdr = MTOD(fin->fin_m, char *);
3764	fin->fin_ip6 = (ip6_t *)(hdr + skip);
3765
3766	if (ipf_pr_pullup(fin, skip + sizeof(ip6_t)) == -1) {
3767		NBUMPSIDE6D(fin->fin_out, ns_decap_pullup);
3768		return (-1);
3769	}
3770
3771	fin->fin_hlen = sizeof(ip6_t);
3772	fin->fin_dlen -= skip;
3773	fin->fin_plen -= skip;
3774	fin->fin_ipoff += skip;
3775
3776	if (ipf_makefrip(sizeof(ip6_t), (ip_t *)hdr, fin) == -1) {
3777		NBUMPSIDE6D(fin->fin_out, ns_decap_bad);
3778		return (-1);
3779	}
3780
3781	return (skip);
3782}
3783
3784
3785/* ------------------------------------------------------------------------ */
3786/* Function:    nat6_nextaddr                                               */
3787/* Returns:     int - -1 == bad input (no new address),                     */
3788/*                     0 == success and dst has new address                 */
3789/* Parameters:  fin(I) - pointer to packet information                      */
3790/*              na(I)  - how to generate new address                        */
3791/*              old(I) - original address being replaced                    */
3792/*              dst(O) - where to put the new address                       */
3793/* Write Lock:  ipf_nat                                                     */
3794/*                                                                          */
3795/* This function uses the contents of the "na" structure, in combination    */
3796/* with "old" to produce a new address to store in "dst".  Not all of the   */
3797/* possible uses of "na" will result in a new address.                      */
3798/* ------------------------------------------------------------------------ */
3799static int
3800ipf_nat6_nextaddr(fr_info_t *fin, nat_addr_t *na, i6addr_t *old, i6addr_t *dst)
3801{
3802	ipf_main_softc_t *softc = fin->fin_main_soft;
3803	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
3804	i6addr_t newip, new;
3805	u_32_t amin, amax;
3806	int error;
3807
3808	new.i6[0] = 0;
3809	new.i6[1] = 0;
3810	new.i6[2] = 0;
3811	new.i6[3] = 0;
3812	amin = na->na_addr[0].in4.s_addr;
3813
3814	switch (na->na_atype)
3815	{
3816	case FRI_RANGE :
3817		amax = na->na_addr[1].in4.s_addr;
3818		break;
3819
3820	case FRI_NETMASKED :
3821	case FRI_DYNAMIC :
3822	case FRI_NORMAL :
3823		/*
3824		 * Compute the maximum address by adding the inverse of the
3825		 * netmask to the minimum address.
3826		 */
3827		amax = ~na->na_addr[1].in4.s_addr;
3828		amax |= amin;
3829		break;
3830
3831	case FRI_LOOKUP :
3832		break;
3833
3834	case FRI_BROADCAST :
3835	case FRI_PEERADDR :
3836	case FRI_NETWORK :
3837	default :
3838		return (-1);
3839	}
3840
3841	error = -1;
3842	switch (na->na_function)
3843	{
3844	case IPLT_DSTLIST :
3845		error = ipf_dstlist_select_node(fin, na->na_ptr, dst->i6,
3846						NULL);
3847		break;
3848
3849	case IPLT_NONE :
3850		/*
3851		 * 0/0 as the new address means leave it alone.
3852		 */
3853		if (na->na_addr[0].in4.s_addr == 0 &&
3854		    na->na_addr[1].in4.s_addr == 0) {
3855			new = *old;
3856
3857		/*
3858		 * 0/32 means get the interface's address
3859		 */
3860		} else if (IP6_ISZERO(&na->na_addr[0].in6) &&
3861			   IP6_ISONES(&na->na_addr[1].in6)) {
3862			if (ipf_ifpaddr(softc, 6, na->na_atype,
3863				       fin->fin_ifp, &newip, NULL) == -1) {
3864				NBUMPSIDE6(fin->fin_out, ns_ifpaddrfail);
3865				return (-1);
3866			}
3867			new = newip;
3868		} else {
3869			new.in6 = na->na_nextip6;
3870		}
3871		*dst = new;
3872		error = 0;
3873		break;
3874
3875	default :
3876		NBUMPSIDE6(fin->fin_out, ns_badnextaddr);
3877		break;
3878	}
3879
3880	return (error);
3881}
3882
3883
3884/* ------------------------------------------------------------------------ */
3885/* Function:    ipf_nat6_nextaddrinit                                       */
3886/* Returns:     int - 0 == success, else error number                       */
3887/* Parameters:  na(I)      - NAT address information for generating new addr*/
3888/*              base(I)    - start of where to find strings                 */
3889/*              initial(I) - flag indicating if it is the first call for    */
3890/*                           this "na" structure.                           */
3891/*              ifp(I)     - network interface to derive address            */
3892/*                           information from.                              */
3893/*                                                                          */
3894/* This function is expected to be called in two scenarious: when a new NAT */
3895/* rule is loaded into the kernel and when the list of NAT rules is sync'd  */
3896/* up with the valid network interfaces (possibly due to them changing.)    */
3897/* To distinguish between these, the "initial" parameter is used.  If it is */
3898/* 1 then this indicates the rule has just been reloaded and 0 for when we  */
3899/* are updating information.  This difference is important because in       */
3900/* instances where we are not updating address information associated with  */
3901/* a network interface, we don't want to disturb what the "next" address to */
3902/* come out of ipf_nat6_nextaddr() will be.                                 */
3903/* ------------------------------------------------------------------------ */
3904static int
3905ipf_nat6_nextaddrinit(ipf_main_softc_t *softc, char *base, nat_addr_t *na,
3906	int initial, void *ifp)
3907{
3908	switch (na->na_atype)
3909	{
3910	case FRI_LOOKUP :
3911		if (na->na_subtype == 0) {
3912			na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT,
3913							na->na_type,
3914							na->na_num,
3915							&na->na_func);
3916		} else if (na->na_subtype == 1) {
3917			na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT,
3918							 na->na_type,
3919							 base + na->na_num,
3920							 &na->na_func);
3921		}
3922		if (na->na_func == NULL) {
3923			IPFERROR(60072);
3924			return (ESRCH);
3925		}
3926		if (na->na_ptr == NULL) {
3927			IPFERROR(60073);
3928			return (ESRCH);
3929		}
3930		break;
3931	case FRI_DYNAMIC :
3932	case FRI_BROADCAST :
3933	case FRI_NETWORK :
3934	case FRI_NETMASKED :
3935	case FRI_PEERADDR :
3936		if (ifp != NULL)
3937			(void )ipf_ifpaddr(softc, 6, na->na_atype, ifp,
3938					   &na->na_addr[0],
3939					   &na->na_addr[1]);
3940		break;
3941
3942	case FRI_SPLIT :
3943	case FRI_RANGE :
3944		if (initial)
3945			na->na_nextip6 = na->na_addr[0].in6;
3946		break;
3947
3948	case FRI_NONE :
3949		IP6_ANDASSIGN(&na->na_addr[0].in6, &na->na_addr[1].in6);
3950		return (0);
3951
3952	case FRI_NORMAL :
3953		IP6_ANDASSIGN(&na->na_addr[0].in6, &na->na_addr[1].in6);
3954		break;
3955
3956	default :
3957		IPFERROR(60074);
3958		return (EINVAL);
3959	}
3960
3961	if (initial && (na->na_atype == FRI_NORMAL)) {
3962		if (IP6_ISZERO(&na->na_addr[0].in6)) {
3963			if (IP6_ISONES(&na->na_addr[1].in6) ||
3964			    IP6_ISZERO(&na->na_addr[1].in6)) {
3965				return (0);
3966			}
3967		}
3968
3969		na->na_nextip6 = na->na_addr[0].in6;
3970		if (!IP6_ISONES(&na->na_addr[1].in6)) {
3971			IP6_INC(&na->na_nextip6);
3972		}
3973	}
3974
3975	return (0);
3976}
3977
3978
3979/* ------------------------------------------------------------------------ */
3980/* Function:    ipf_nat6_icmpquerytype                                      */
3981/* Returns:     int - 1 == success, 0 == failure                            */
3982/* Parameters:  icmptype(I) - ICMP type number                              */
3983/*                                                                          */
3984/* Tests to see if the ICMP type number passed is a query/response type or  */
3985/* not.                                                                     */
3986/* ------------------------------------------------------------------------ */
3987static int
3988ipf_nat6_icmpquerytype(int icmptype)
3989{
3990
3991	/*
3992	 * For the ICMP query NAT code, it is essential that both the query
3993	 * and the reply match on the NAT rule. Because the NAT structure
3994	 * does not keep track of the icmptype, and a single NAT structure
3995	 * is used for all icmp types with the same src, dest and id, we
3996	 * simply define the replies as queries as well. The funny thing is,
3997	 * altough it seems silly to call a reply a query, this is exactly
3998	 * as it is defined in the IPv4 specification
3999	 */
4000
4001	switch (icmptype)
4002	{
4003
4004	case ICMP6_ECHO_REPLY:
4005	case ICMP6_ECHO_REQUEST:
4006	/* route aedvertisement/solliciation is currently unsupported: */
4007	/* it would require rewriting the ICMP data section            */
4008	case ICMP6_MEMBERSHIP_QUERY:
4009	case ICMP6_MEMBERSHIP_REPORT:
4010	case ICMP6_MEMBERSHIP_REDUCTION:
4011	case ICMP6_WRUREQUEST:
4012	case ICMP6_WRUREPLY:
4013	case MLD6_MTRACE_RESP:
4014	case MLD6_MTRACE:
4015		return (1);
4016	default:
4017		return (0);
4018	}
4019}
4020#endif /* USE_INET6 */
4021