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