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