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