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