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