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