1 /* 2 * Copyright (C) 1995-2003 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 7 * Use is subject to license terms. 8 */ 9 10 #pragma ident "%Z%%M% %I% %E% SMI"$ 11 12 #if defined(KERNEL) || defined(_KERNEL) 13 # undef KERNEL 14 # undef _KERNEL 15 # define KERNEL 1 16 # define _KERNEL 1 17 #endif 18 #include <sys/errno.h> 19 #include <sys/types.h> 20 #include <sys/param.h> 21 #include <sys/time.h> 22 #include <sys/file.h> 23 #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ 24 defined(_KERNEL) 25 # include "opt_ipfilter_log.h" 26 #endif 27 #if !defined(_KERNEL) 28 # include <stdio.h> 29 # include <string.h> 30 # include <stdlib.h> 31 # define _KERNEL 32 # ifdef __OpenBSD__ 33 struct file; 34 # endif 35 # include <sys/uio.h> 36 # undef _KERNEL 37 #endif 38 #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 39 # include <sys/filio.h> 40 # include <sys/fcntl.h> 41 #else 42 # include <sys/ioctl.h> 43 #endif 44 #if !defined(AIX) 45 # include <sys/fcntl.h> 46 #endif 47 #if !defined(linux) 48 # include <sys/protosw.h> 49 #endif 50 #include <sys/socket.h> 51 #if defined(_KERNEL) 52 # include <sys/systm.h> 53 # if !defined(__SVR4) && !defined(__svr4__) 54 # include <sys/mbuf.h> 55 # endif 56 #endif 57 #if defined(__SVR4) || defined(__svr4__) 58 # include <sys/filio.h> 59 # include <sys/byteorder.h> 60 # ifdef _KERNEL 61 # include <sys/dditypes.h> 62 # endif 63 # include <sys/stream.h> 64 # include <sys/kmem.h> 65 #endif 66 #if __FreeBSD_version >= 300000 67 # include <sys/queue.h> 68 #endif 69 #include <net/if.h> 70 #if __FreeBSD_version >= 300000 71 # include <net/if_var.h> 72 # if defined(_KERNEL) && !defined(IPFILTER_LKM) 73 # include "opt_ipfilter.h" 74 # endif 75 #endif 76 #ifdef sun 77 # include <net/af.h> 78 #endif 79 #include <net/route.h> 80 #include <netinet/in.h> 81 #include <netinet/in_systm.h> 82 #include <netinet/ip.h> 83 84 #ifdef RFC1825 85 # include <vpn/md5.h> 86 # include <vpn/ipsec.h> 87 extern struct ifnet vpnif; 88 #endif 89 90 #if !defined(linux) 91 # include <netinet/ip_var.h> 92 #endif 93 #include <netinet/tcp.h> 94 #include <netinet/udp.h> 95 #include <netinet/ip_icmp.h> 96 #include "netinet/ip_compat.h" 97 #include <netinet/tcpip.h> 98 #include "netinet/ip_fil.h" 99 #include "netinet/ip_nat.h" 100 #include "netinet/ip_frag.h" 101 #include "netinet/ip_state.h" 102 #include "netinet/ip_proxy.h" 103 #include "netinet/ipf_stack.h" 104 #ifdef IPFILTER_SYNC 105 #include "netinet/ip_sync.h" 106 #endif 107 #if (__FreeBSD_version >= 300000) 108 # include <sys/malloc.h> 109 #endif 110 /* END OF INCLUDES */ 111 112 #undef SOCKADDR_IN 113 #define SOCKADDR_IN struct sockaddr_in 114 115 #if !defined(lint) 116 static const char rcsid[] = "@(#)$Id: ip_nat6.c,v 1.2 2008/02/14 21:05:50 darrenr Exp $"; 117 #endif 118 119 static hostmap_t *nat6_hostmap __P((ipnat_t *, i6addr_t *, i6addr_t *, 120 i6addr_t *, u_32_t, ipf_stack_t *)); 121 static INLINE int nat6_newmap __P((fr_info_t *, nat_t *, natinfo_t *)); 122 static INLINE int nat6_newrdr __P((fr_info_t *, nat_t *, natinfo_t *)); 123 static INLINE int nat6_finalise __P((fr_info_t *, nat_t *, natinfo_t *, 124 tcphdr_t *, nat_t **, int)); 125 static void nat6_tabmove __P((nat_t *, ipf_stack_t *)); 126 static int nat6_match __P((fr_info_t *, ipnat_t *)); 127 static INLINE int nat_icmpquerytype6 __P((int)); 128 129 130 /* ------------------------------------------------------------------------ */ 131 /* Function: nat6_addrdr */ 132 /* Returns: Nil */ 133 /* Parameters: n(I) - pointer to NAT rule to add */ 134 /* */ 135 /* Adds a redirect rule to the hash table of redirect rules and the list of */ 136 /* loaded NAT rules. Updates the bitmask indicating which netmasks are in */ 137 /* use by redirect rules. */ 138 /* ------------------------------------------------------------------------ */ 139 void nat6_addrdr(n, ifs) 140 ipnat_t *n; 141 ipf_stack_t *ifs; 142 { 143 ipnat_t **np; 144 i6addr_t j; 145 u_int hv; 146 int k; 147 148 k = count6bits(n->in_out[1].i6); 149 if ((k >= 0) && (k != 128)) 150 ifs->ifs_rdr6_masks[k >> 5] |= 1 << (k & 31); 151 IP6_AND(&n->in_out[0], &n->in_out[1], &j); 152 hv = NAT_HASH_FN6(&j, 0, ifs->ifs_ipf_rdrrules_sz); 153 np = ifs->ifs_rdr_rules + hv; 154 while (*np != NULL) 155 np = &(*np)->in_rnext; 156 n->in_rnext = NULL; 157 n->in_prnext = np; 158 n->in_hv = hv; 159 *np = n; 160 } 161 162 163 /* ------------------------------------------------------------------------ */ 164 /* Function: nat6_addnat */ 165 /* Returns: Nil */ 166 /* Parameters: n(I) - pointer to NAT rule to add */ 167 /* */ 168 /* Adds a NAT map rule to the hash table of rules and the list of loaded */ 169 /* NAT rules. Updates the bitmask indicating which netmasks are in use by */ 170 /* redirect rules. */ 171 /* ------------------------------------------------------------------------ */ 172 void nat6_addnat(n, ifs) 173 ipnat_t *n; 174 ipf_stack_t *ifs; 175 { 176 ipnat_t **np; 177 i6addr_t j; 178 u_int hv; 179 int k; 180 181 k = count6bits(n->in_in[1].i6); 182 if ((k >= 0) && (k != 128)) 183 ifs->ifs_nat6_masks[k >> 5] |= 1 << (k & 31); 184 IP6_AND(&n->in_in[0], &n->in_in[1], &j); 185 hv = NAT_HASH_FN6(&j, 0, ifs->ifs_ipf_natrules_sz); 186 np = ifs->ifs_nat_rules + hv; 187 while (*np != NULL) 188 np = &(*np)->in_mnext; 189 n->in_mnext = NULL; 190 n->in_pmnext = np; 191 n->in_hv = hv; 192 *np = n; 193 } 194 195 196 /* ------------------------------------------------------------------------ */ 197 /* Function: nat6_hostmap */ 198 /* Returns: struct hostmap* - NULL if no hostmap could be created, */ 199 /* else a pointer to the hostmapping to use */ 200 /* Parameters: np(I) - pointer to NAT rule */ 201 /* real(I) - real IP address */ 202 /* map(I) - mapped IP address */ 203 /* port(I) - destination port number */ 204 /* Write Locks: ipf_nat */ 205 /* */ 206 /* Check if an ip address has already been allocated for a given mapping */ 207 /* that is not doing port based translation. If is not yet allocated, then */ 208 /* create a new entry if a non-NULL NAT rule pointer has been supplied. */ 209 /* ------------------------------------------------------------------------ */ 210 static struct hostmap *nat6_hostmap(np, src, dst, map, port, ifs) 211 ipnat_t *np; 212 i6addr_t *src, *dst, *map; 213 u_32_t port; 214 ipf_stack_t *ifs; 215 { 216 hostmap_t *hm; 217 u_int hv; 218 219 hv = (src->i6[3] ^ dst->i6[3]); 220 hv += (src->i6[2] ^ dst->i6[2]); 221 hv += (src->i6[1] ^ dst->i6[1]); 222 hv += (src->i6[0] ^ dst->i6[0]); 223 hv += src->i6[3]; 224 hv += src->i6[2]; 225 hv += src->i6[1]; 226 hv += src->i6[0]; 227 hv += dst->i6[3]; 228 hv += dst->i6[2]; 229 hv += dst->i6[1]; 230 hv += dst->i6[0]; 231 hv %= HOSTMAP_SIZE; 232 for (hm = ifs->ifs_maptable[hv]; hm; hm = hm->hm_next) 233 if (IP6_EQ(&hm->hm_srcip6, src) && 234 IP6_EQ(&hm->hm_dstip6, dst) && 235 ((np == NULL) || (np == hm->hm_ipnat)) && 236 ((port == 0) || (port == hm->hm_port))) { 237 hm->hm_ref++; 238 return hm; 239 } 240 241 if (np == NULL) 242 return NULL; 243 244 KMALLOC(hm, hostmap_t *); 245 if (hm) { 246 hm->hm_hnext = ifs->ifs_ipf_hm_maplist; 247 hm->hm_phnext = &ifs->ifs_ipf_hm_maplist; 248 if (ifs->ifs_ipf_hm_maplist != NULL) 249 ifs->ifs_ipf_hm_maplist->hm_phnext = &hm->hm_hnext; 250 ifs->ifs_ipf_hm_maplist = hm; 251 252 hm->hm_next = ifs->ifs_maptable[hv]; 253 hm->hm_pnext = ifs->ifs_maptable + hv; 254 if (ifs->ifs_maptable[hv] != NULL) 255 ifs->ifs_maptable[hv]->hm_pnext = &hm->hm_next; 256 ifs->ifs_maptable[hv] = hm; 257 hm->hm_ipnat = np; 258 hm->hm_src = *src; 259 hm->hm_dst = *dst; 260 hm->hm_map = *map; 261 hm->hm_ref = 1; 262 hm->hm_port = port; 263 hm->hm_v = 6; 264 } 265 return hm; 266 } 267 268 269 /* ------------------------------------------------------------------------ */ 270 /* Function: nat6_newmap */ 271 /* Returns: int - -1 == error, 0 == success */ 272 /* Parameters: fin(I) - pointer to packet information */ 273 /* nat(I) - pointer to NAT entry */ 274 /* ni(I) - pointer to structure with misc. information needed */ 275 /* to create new NAT entry. */ 276 /* */ 277 /* Given an empty NAT structure, populate it with new information about a */ 278 /* new NAT session, as defined by the matching NAT rule. */ 279 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 280 /* to the new IP address for the translation. */ 281 /* ------------------------------------------------------------------------ */ 282 static INLINE int nat6_newmap(fin, nat, ni) 283 fr_info_t *fin; 284 nat_t *nat; 285 natinfo_t *ni; 286 { 287 u_short st_port, dport, sport, port, sp, dp; 288 i6addr_t in, st_ip; 289 hostmap_t *hm; 290 u_32_t flags; 291 ipnat_t *np; 292 nat_t *natl; 293 int l; 294 ipf_stack_t *ifs = fin->fin_ifs; 295 296 /* 297 * If it's an outbound packet which doesn't match any existing 298 * record, then create a new port 299 */ 300 l = 0; 301 hm = NULL; 302 np = ni->nai_np; 303 st_ip = np->in_next6; 304 st_port = np->in_pnext; 305 flags = ni->nai_flags; 306 sport = ni->nai_sport; 307 dport = ni->nai_dport; 308 309 /* 310 * Do a loop until we either run out of entries to try or we find 311 * a NAT mapping that isn't currently being used. This is done 312 * because the change to the source is not (usually) being fixed. 313 */ 314 do { 315 port = 0; 316 in = np->in_next6; 317 if (l == 0) { 318 /* 319 * Check to see if there is an existing NAT 320 * setup for this IP address pair. 321 */ 322 hm = nat6_hostmap(np, &fin->fin_src6, &fin->fin_dst6, 323 &in, 0, ifs); 324 if (hm != NULL) 325 in = hm->hm_map; 326 } else if ((l == 1) && (hm != NULL)) { 327 fr_hostmapdel(&hm); 328 } 329 330 nat->nat_hm = hm; 331 332 if (IP6_ISONES(&np->in_out[1]) && (np->in_pnext == 0)) { 333 if (l > 0) 334 return -1; 335 } 336 337 if (np->in_redir == NAT_BIMAP && 338 IP6_EQ(&np->in_in[1], &np->in_out[1])) { 339 i6addr_t temp; 340 /* 341 * map the address block in a 1:1 fashion 342 */ 343 temp.i6[0] = fin->fin_src6.i6[0] & 344 ~np->in_in[1].i6[0]; 345 temp.i6[1] = fin->fin_src6.i6[1] & 346 ~np->in_in[1].i6[1]; 347 temp.i6[2] = fin->fin_src6.i6[2] & 348 ~np->in_in[1].i6[2]; 349 temp.i6[3] = fin->fin_src6.i6[3] & 350 ~np->in_in[1].i6[3]; 351 in = np->in_out[0]; 352 IP6_MERGE(&in, &temp, &np->in_in[0]); 353 354 #ifdef NEED_128BIT_MATH 355 } else if (np->in_redir & NAT_MAPBLK) { 356 if ((l >= np->in_ppip) || ((l > 0) && 357 !(flags & IPN_TCPUDP))) 358 return -1; 359 /* 360 * map-block - Calculate destination address. 361 */ 362 IP6_MASK(&in, &fin->fin_src6, &np->in_in[1]); 363 in = ntol(in); 364 inb = in; 365 in /= np->in_ippip; 366 in &= ntohl(~np->in_out[1]); 367 in += ntohl(np->in_out[0]); 368 /* 369 * Calculate destination port. 370 */ 371 if ((flags & IPN_TCPUDP) && 372 (np->in_ppip != 0)) { 373 port = ntohs(sport) + l; 374 port %= np->in_ppip; 375 port += np->in_ppip * 376 (inb.s_addr % np->in_ippip); 377 port += MAPBLK_MINPORT; 378 port = htons(port); 379 } 380 #endif 381 382 } else if (IP6_ISZERO(&np->in_out[0]) && 383 IP6_ISONES(&np->in_out[1])) { 384 /* 385 * 0/128 - use the interface's IP address. 386 */ 387 if ((l > 0) || 388 fr_ifpaddr(6, FRI_NORMAL, fin->fin_ifp, 389 (void *)&in, NULL, fin->fin_ifs) == -1) 390 return -1; 391 392 } else if (IP6_ISZERO(&np->in_out[0]) && 393 IP6_ISZERO(&np->in_out[1])) { 394 /* 395 * 0/0 - use the original source address/port. 396 */ 397 if (l > 0) 398 return -1; 399 in = fin->fin_src6; 400 401 } else if (!IP6_ISONES(&np->in_out[1]) && 402 (np->in_pnext == 0) && ((l > 0) || (hm == NULL))) { 403 IP6_INC(&np->in_next6); 404 } 405 406 natl = NULL; 407 408 if ((flags & IPN_TCPUDP) && 409 ((np->in_redir & NAT_MAPBLK) == 0) && 410 (np->in_flags & IPN_AUTOPORTMAP)) { 411 /*EMPTY*/; 412 #ifdef NEED_128BIT_MATH 413 /* 414 * XXX "ports auto" (without map-block) 415 */ 416 if ((l > 0) && (l % np->in_ppip == 0)) { 417 if (l > np->in_space) { 418 return -1; 419 } else if ((l > np->in_ppip) && 420 !IP6_ISONES(&np->in_out[1])) { 421 IP6_INC(&np->in_next6); 422 } 423 } 424 if (np->in_ppip != 0) { 425 port = ntohs(sport); 426 port += (l % np->in_ppip); 427 port %= np->in_ppip; 428 port += np->in_ppip * 429 (ntohl(fin->fin_src6) % 430 np->in_ippip); 431 port += MAPBLK_MINPORT; 432 port = htons(port); 433 } 434 #endif 435 436 } else if (((np->in_redir & NAT_MAPBLK) == 0) && 437 (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) { 438 /* 439 * Standard port translation. Select next port. 440 */ 441 port = htons(np->in_pnext++); 442 443 if (np->in_pnext > ntohs(np->in_pmax)) { 444 np->in_pnext = ntohs(np->in_pmin); 445 if (!IP6_ISONES(&np->in_out[1])) { 446 IP6_INC(&np->in_next6); 447 } 448 } 449 } 450 451 if (np->in_flags & IPN_IPRANGE) { 452 if (IP6_GT(&np->in_next6, &np->in_out[1])) 453 np->in_next6 = np->in_out[0]; 454 } else { 455 i6addr_t a1, a2; 456 457 a1 = np->in_next6; 458 IP6_INC(&a1); 459 IP6_AND(&a1, &np->in_out[1], &a2); 460 if (!IP6_ISONES(&np->in_out[1]) && 461 IP6_GT(&a2, &np->in_out[0])) { 462 IP6_ADD(&np->in_out[0], 1, &np->in_next6); 463 } 464 } 465 466 if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY))) 467 port = sport; 468 469 /* 470 * Here we do a lookup of the connection as seen from 471 * the outside. If an IP# pair already exists, try 472 * again. So if you have A->B becomes C->B, you can 473 * also have D->E become C->E but not D->B causing 474 * another C->B. Also take protocol and ports into 475 * account when determining whether a pre-existing 476 * NAT setup will cause an external conflict where 477 * this is appropriate. 478 */ 479 sp = fin->fin_data[0]; 480 dp = fin->fin_data[1]; 481 fin->fin_data[0] = fin->fin_data[1]; 482 fin->fin_data[1] = htons(port); 483 natl = nat6_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 484 (u_int)fin->fin_p, &fin->fin_dst6.in6, &in.in6); 485 fin->fin_data[0] = sp; 486 fin->fin_data[1] = dp; 487 488 /* 489 * Has the search wrapped around and come back to the 490 * start ? 491 */ 492 if ((natl != NULL) && 493 (np->in_pnext != 0) && (st_port == np->in_pnext) && 494 !IP6_ISZERO(&np->in_next6) && 495 IP6_EQ(&st_ip, &np->in_next6)) 496 return -1; 497 l++; 498 } while (natl != NULL); 499 500 if (np->in_space > 0) 501 np->in_space--; 502 503 /* Setup the NAT table */ 504 nat->nat_inip6 = fin->fin_src6; 505 nat->nat_outip6 = in; 506 nat->nat_oip6 = fin->fin_dst6; 507 if (nat->nat_hm == NULL) 508 nat->nat_hm = nat6_hostmap(np, &fin->fin_src6, &fin->fin_dst6, 509 &nat->nat_outip6, 0, ifs); 510 511 if (flags & IPN_TCPUDP) { 512 nat->nat_inport = sport; 513 nat->nat_outport = port; /* sport */ 514 nat->nat_oport = dport; 515 ((tcphdr_t *)fin->fin_dp)->th_sport = port; 516 } else if (flags & IPN_ICMPQUERY) { 517 ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = port; 518 nat->nat_inport = port; 519 nat->nat_outport = port; 520 } 521 522 ni->nai_port = port; 523 ni->nai_nport = dport; 524 return 0; 525 } 526 527 528 /* ------------------------------------------------------------------------ */ 529 /* Function: nat6_newrdr */ 530 /* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ 531 /* allow rule to be moved if IPN_ROUNDR is set. */ 532 /* Parameters: fin(I) - pointer to packet information */ 533 /* nat(I) - pointer to NAT entry */ 534 /* ni(I) - pointer to structure with misc. information needed */ 535 /* to create new NAT entry. */ 536 /* */ 537 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ 538 /* to the new IP address for the translation. */ 539 /* ------------------------------------------------------------------------ */ 540 static INLINE int nat6_newrdr(fin, nat, ni) 541 fr_info_t *fin; 542 nat_t *nat; 543 natinfo_t *ni; 544 { 545 u_short nport, dport, sport; 546 i6addr_t in; 547 u_short sp, dp; 548 hostmap_t *hm; 549 u_32_t flags; 550 ipnat_t *np; 551 nat_t *natl; 552 int move; 553 ipf_stack_t *ifs = fin->fin_ifs; 554 555 move = 1; 556 hm = NULL; 557 in.i6[0] = 0; 558 in.i6[1] = 0; 559 in.i6[2] = 0; 560 in.i6[3] = 0; 561 np = ni->nai_np; 562 flags = ni->nai_flags; 563 sport = ni->nai_sport; 564 dport = ni->nai_dport; 565 566 /* 567 * If the matching rule has IPN_STICKY set, then we want to have the 568 * same rule kick in as before. Why would this happen? If you have 569 * a collection of rdr rules with "round-robin sticky", the current 570 * packet might match a different one to the previous connection but 571 * we want the same destination to be used. 572 */ 573 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == 574 (IPN_ROUNDR|IPN_STICKY)) { 575 hm = nat6_hostmap(NULL, &fin->fin_src6, &fin->fin_dst6, &in, 576 (u_32_t)dport, ifs); 577 if (hm != NULL) { 578 in = hm->hm_map; 579 np = hm->hm_ipnat; 580 ni->nai_np = np; 581 move = 0; 582 } 583 } 584 585 /* 586 * Otherwise, it's an inbound packet. Most likely, we don't 587 * want to rewrite source ports and source addresses. Instead, 588 * we want to rewrite to a fixed internal address and fixed 589 * internal port. 590 */ 591 if (np->in_flags & IPN_SPLIT) { 592 in = np->in_next6; 593 594 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) { 595 hm = nat6_hostmap(np, &fin->fin_src6, &fin->fin_dst6, 596 &in, (u_32_t)dport, ifs); 597 if (hm != NULL) { 598 in = hm->hm_map; 599 move = 0; 600 } 601 } 602 603 if (hm == NULL || hm->hm_ref == 1) { 604 if (IP6_EQ(&np->in_in[0], &in)) { 605 np->in_next6 = np->in_in[1]; 606 move = 0; 607 } else { 608 np->in_next6 = np->in_in[0]; 609 } 610 } 611 612 } else if (IP6_ISZERO(&np->in_in[0]) && 613 IP6_ISONES(&np->in_in[1])) { 614 /* 615 * 0/128 - use the interface's IP address. 616 */ 617 if (fr_ifpaddr(6, FRI_NORMAL, fin->fin_ifp, (void *)&in, NULL, 618 fin->fin_ifs) == -1) 619 return -1; 620 621 } else if (IP6_ISZERO(&np->in_in[0]) && 622 IP6_ISZERO(&np->in_in[1])) { 623 /* 624 * 0/0 - use the original destination address/port. 625 */ 626 in = fin->fin_dst6; 627 628 } else if (np->in_redir == NAT_BIMAP && 629 IP6_EQ(&np->in_in[1], &np->in_out[1])) { 630 i6addr_t temp; 631 /* 632 * map the address block in a 1:1 fashion 633 */ 634 temp.i6[0] = fin->fin_dst6.i6[0] & ~np->in_in[1].i6[0]; 635 temp.i6[1] = fin->fin_dst6.i6[1] & ~np->in_in[1].i6[1]; 636 temp.i6[2] = fin->fin_dst6.i6[2] & ~np->in_in[1].i6[2]; 637 temp.i6[3] = fin->fin_dst6.i6[3] & ~np->in_in[1].i6[3]; 638 in = np->in_in[0]; 639 IP6_MERGE(&in, &temp, &np->in_in[1]); 640 } else { 641 in = np->in_in[0]; 642 } 643 644 if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0)) 645 nport = dport; 646 else { 647 /* 648 * Whilst not optimized for the case where 649 * pmin == pmax, the gain is not significant. 650 */ 651 if (((np->in_flags & IPN_FIXEDDPORT) == 0) && 652 (np->in_pmin != np->in_pmax)) { 653 nport = ntohs(dport) - ntohs(np->in_pmin) + 654 ntohs(np->in_pnext); 655 nport = htons(nport); 656 } else 657 nport = np->in_pnext; 658 } 659 660 /* 661 * When the redirect-to address is set to 0.0.0.0, just 662 * assume a blank `forwarding' of the packet. We don't 663 * setup any translation for this either. 664 */ 665 if (IP6_ISZERO(&in)) { 666 if (nport == dport) 667 return -1; 668 in = fin->fin_dst6; 669 } 670 671 /* 672 * Check to see if this redirect mapping already exists and if 673 * it does, return "failure" (allowing it to be created will just 674 * cause one or both of these "connections" to stop working.) 675 */ 676 sp = fin->fin_data[0]; 677 dp = fin->fin_data[1]; 678 fin->fin_data[1] = fin->fin_data[0]; 679 fin->fin_data[0] = ntohs(nport); 680 natl = nat6_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), 681 (u_int)fin->fin_p, &in.in6, &fin->fin_src6.in6); 682 fin->fin_data[0] = sp; 683 fin->fin_data[1] = dp; 684 if (natl != NULL) 685 return -1; 686 687 nat->nat_inip6 = in; 688 nat->nat_outip6 = fin->fin_dst6; 689 nat->nat_oip6 = fin->fin_src6; 690 if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0)) 691 nat->nat_hm = nat6_hostmap(np, &fin->fin_src6, 692 &fin->fin_dst6, &in, (u_32_t)dport, ifs); 693 694 ni->nai_nport = nport; 695 ni->nai_port = sport; 696 697 if (flags & IPN_TCPUDP) { 698 nat->nat_inport = nport; 699 nat->nat_outport = dport; 700 nat->nat_oport = sport; 701 ((tcphdr_t *)fin->fin_dp)->th_dport = nport; 702 } else if (flags & IPN_ICMPQUERY) { 703 ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = nport; 704 nat->nat_inport = nport; 705 nat->nat_outport = nport; 706 } 707 708 return move; 709 } 710 711 /* ------------------------------------------------------------------------ */ 712 /* Function: nat6_new */ 713 /* Returns: nat_t* - NULL == failure to create new NAT structure, */ 714 /* else pointer to new NAT structure */ 715 /* Parameters: fin(I) - pointer to packet information */ 716 /* np(I) - pointer to NAT rule */ 717 /* natsave(I) - pointer to where to store NAT struct pointer */ 718 /* flags(I) - flags describing the current packet */ 719 /* direction(I) - direction of packet (in/out) */ 720 /* Write Lock: ipf_nat */ 721 /* */ 722 /* Attempts to create a new NAT entry. Does not actually change the packet */ 723 /* in any way. */ 724 /* */ 725 /* This fucntion is in three main parts: (1) deal with creating a new NAT */ 726 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */ 727 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */ 728 /* and (3) building that structure and putting it into the NAT table(s). */ 729 /* ------------------------------------------------------------------------ */ 730 nat_t *nat6_new(fin, np, natsave, flags, direction) 731 fr_info_t *fin; 732 ipnat_t *np; 733 nat_t **natsave; 734 u_int flags; 735 int direction; 736 { 737 tcphdr_t *tcp = NULL; 738 hostmap_t *hm = NULL; 739 nat_t *nat, *natl; 740 u_int nflags; 741 natinfo_t ni; 742 int move; 743 ipf_stack_t *ifs = fin->fin_ifs; 744 745 /* 746 * Trigger automatic call to nat_extraflush() if the 747 * table has reached capcity specified by hi watermark. 748 */ 749 if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_lvl_hi) 750 ifs->ifs_nat_doflush = 1; 751 752 if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) { 753 ifs->ifs_nat_stats.ns_memfail++; 754 return NULL; 755 } 756 757 move = 1; 758 nflags = np->in_flags & flags; 759 nflags &= NAT_FROMRULE; 760 761 ni.nai_np = np; 762 ni.nai_nflags = nflags; 763 ni.nai_flags = flags; 764 765 /* Give me a new nat */ 766 KMALLOC(nat, nat_t *); 767 if (nat == NULL) { 768 ifs->ifs_nat_stats.ns_memfail++; 769 /* 770 * Try to automatically tune the max # of entries in the 771 * table allowed to be less than what will cause kmem_alloc() 772 * to fail and try to eliminate panics due to out of memory 773 * conditions arising. 774 */ 775 if (ifs->ifs_ipf_nattable_max > ifs->ifs_ipf_nattable_sz) { 776 ifs->ifs_ipf_nattable_max = 777 ifs->ifs_nat_stats.ns_inuse - 100; 778 printf("ipf_nattable_max reduced to %d\n", 779 ifs->ifs_ipf_nattable_max); 780 } 781 return NULL; 782 } 783 784 if (flags & IPN_TCPUDP) { 785 tcp = fin->fin_dp; 786 ni.nai_sport = htons(fin->fin_sport); 787 ni.nai_dport = htons(fin->fin_dport); 788 } else if (flags & IPN_ICMPQUERY) { 789 /* 790 * In the ICMP query NAT code, we translate the ICMP id fields 791 * to make them unique. This is indepedent of the ICMP type 792 * (e.g. in the unlikely event that a host sends an echo and 793 * an tstamp request with the same id, both packets will have 794 * their ip address/id field changed in the same way). 795 * 796 * The icmp_id field is used by the sender to identify the 797 * process making the icmp request. (the receiver justs 798 * copies it back in its response). So, it closely matches 799 * the concept of source port. We overlay sport, so we can 800 * maximally reuse the existing code. 801 */ 802 ni.nai_sport = ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id; 803 ni.nai_dport = ni.nai_sport; 804 } 805 806 bzero((char *)nat, sizeof (*nat)); 807 nat->nat_flags = flags; 808 nat->nat_redir = np->in_redir; 809 810 if ((flags & NAT_SLAVE) == 0) { 811 MUTEX_ENTER(&ifs->ifs_ipf_nat_new); 812 } 813 814 /* 815 * Search the current table for a match. 816 */ 817 if (direction == NAT_OUTBOUND) { 818 /* 819 * We can now arrange to call this for the same connection 820 * because ipf_nat_new doesn't protect the code path into 821 * this function. 822 */ 823 natl = nat6_outlookup(fin, nflags, (u_int)fin->fin_p, 824 &fin->fin_src6.in6, &fin->fin_dst6.in6); 825 if (natl != NULL) { 826 KFREE(nat); 827 nat = natl; 828 goto done; 829 } 830 831 move = nat6_newmap(fin, nat, &ni); 832 if (move == -1) 833 goto badnat; 834 835 np = ni.nai_np; 836 } else { 837 /* 838 * NAT_INBOUND is used only for redirects rules 839 */ 840 natl = nat6_inlookup(fin, nflags, (u_int)fin->fin_p, 841 &fin->fin_src6.in6, &fin->fin_dst6.in6); 842 if (natl != NULL) { 843 KFREE(nat); 844 nat = natl; 845 goto done; 846 } 847 848 move = nat6_newrdr(fin, nat, &ni); 849 if (move == -1) 850 goto badnat; 851 852 np = ni.nai_np; 853 } 854 855 if ((move == 1) && (np->in_flags & IPN_ROUNDR)) { 856 if (np->in_redir == NAT_REDIRECT) { 857 nat_delrdr(np); 858 nat6_addrdr(np, ifs); 859 } else if (np->in_redir == NAT_MAP) { 860 nat_delnat(np); 861 nat6_addnat(np, ifs); 862 } 863 } 864 865 if (nat6_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) { 866 goto badnat; 867 } 868 869 nat_calc_chksum_diffs(nat); 870 871 if (flags & SI_WILDP) 872 ifs->ifs_nat_stats.ns_wilds++; 873 goto done; 874 badnat: 875 ifs->ifs_nat_stats.ns_badnat++; 876 if ((hm = nat->nat_hm) != NULL) 877 fr_hostmapdel(&hm); 878 KFREE(nat); 879 nat = NULL; 880 done: 881 if ((flags & NAT_SLAVE) == 0) { 882 MUTEX_EXIT(&ifs->ifs_ipf_nat_new); 883 } 884 return nat; 885 } 886 887 888 /* ------------------------------------------------------------------------ */ 889 /* Function: nat6_finalise */ 890 /* Returns: int - 0 == sucess, -1 == failure */ 891 /* Parameters: fin(I) - pointer to packet information */ 892 /* nat(I) - pointer to NAT entry */ 893 /* ni(I) - pointer to structure with misc. information needed */ 894 /* to create new NAT entry. */ 895 /* Write Lock: ipf_nat */ 896 /* */ 897 /* This is the tail end of constructing a new NAT entry and is the same */ 898 /* for both IPv4 and IPv6. */ 899 /* ------------------------------------------------------------------------ */ 900 /*ARGSUSED*/ 901 static INLINE int nat6_finalise(fin, nat, ni, tcp, natsave, direction) 902 fr_info_t *fin; 903 nat_t *nat; 904 natinfo_t *ni; 905 tcphdr_t *tcp; 906 nat_t **natsave; 907 int direction; 908 { 909 frentry_t *fr; 910 ipnat_t *np; 911 ipf_stack_t *ifs = fin->fin_ifs; 912 913 np = ni->nai_np; 914 915 COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0], fin->fin_v); 916 917 #ifdef IPFILTER_SYNC 918 if ((nat->nat_flags & SI_CLONE) == 0) 919 nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat); 920 #endif 921 922 nat->nat_me = natsave; 923 nat->nat_dir = direction; 924 nat->nat_ifps[0] = np->in_ifps[0]; 925 nat->nat_ifps[1] = np->in_ifps[1]; 926 nat->nat_ptr = np; 927 nat->nat_p = fin->fin_p; 928 nat->nat_v = fin->fin_v; 929 nat->nat_mssclamp = np->in_mssclamp; 930 fr = fin->fin_fr; 931 nat->nat_fr = fr; 932 nat->nat_v = 6; 933 934 #ifdef IPF_V6_PROXIES 935 if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0)) 936 if (appr_new(fin, nat) == -1) 937 return -1; 938 #endif 939 940 if (nat6_insert(nat, fin->fin_rev, ifs) == 0) { 941 if (ifs->ifs_nat_logging) 942 nat_log(nat, (u_int)np->in_redir, ifs); 943 np->in_use++; 944 if (fr != NULL) { 945 MUTEX_ENTER(&fr->fr_lock); 946 fr->fr_ref++; 947 MUTEX_EXIT(&fr->fr_lock); 948 } 949 return 0; 950 } 951 952 /* 953 * nat6_insert failed, so cleanup time... 954 */ 955 return -1; 956 } 957 958 959 /* ------------------------------------------------------------------------ */ 960 /* Function: nat6_insert */ 961 /* Returns: int - 0 == sucess, -1 == failure */ 962 /* Parameters: nat(I) - pointer to NAT structure */ 963 /* rev(I) - flag indicating forward/reverse direction of packet */ 964 /* Write Lock: ipf_nat */ 965 /* */ 966 /* Insert a NAT entry into the hash tables for searching and add it to the */ 967 /* list of active NAT entries. Adjust global counters when complete. */ 968 /* ------------------------------------------------------------------------ */ 969 int nat6_insert(nat, rev, ifs) 970 nat_t *nat; 971 int rev; 972 ipf_stack_t *ifs; 973 { 974 u_int hv1, hv2; 975 nat_t **natp; 976 977 /* 978 * Try and return an error as early as possible, so calculate the hash 979 * entry numbers first and then proceed. 980 */ 981 if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) { 982 hv1 = NAT_HASH_FN6(&nat->nat_inip6, nat->nat_inport, 983 0xffffffff); 984 hv1 = NAT_HASH_FN6(&nat->nat_oip6, hv1 + nat->nat_oport, 985 ifs->ifs_ipf_nattable_sz); 986 hv2 = NAT_HASH_FN6(&nat->nat_outip6, nat->nat_outport, 987 0xffffffff); 988 hv2 = NAT_HASH_FN6(&nat->nat_oip6, hv2 + nat->nat_oport, 989 ifs->ifs_ipf_nattable_sz); 990 } else { 991 hv1 = NAT_HASH_FN6(&nat->nat_inip6, 0, 0xffffffff); 992 hv1 = NAT_HASH_FN6(&nat->nat_oip6, hv1, 993 ifs->ifs_ipf_nattable_sz); 994 hv2 = NAT_HASH_FN6(&nat->nat_outip6, 0, 0xffffffff); 995 hv2 = NAT_HASH_FN6(&nat->nat_oip6, hv2, 996 ifs->ifs_ipf_nattable_sz); 997 } 998 999 if ((ifs->ifs_nat_stats.ns_bucketlen[0][hv1] >= 1000 ifs->ifs_fr_nat_maxbucket) || 1001 (ifs->ifs_nat_stats.ns_bucketlen[1][hv2] >= 1002 ifs->ifs_fr_nat_maxbucket)) { 1003 return -1; 1004 } 1005 1006 nat->nat_hv[0] = hv1; 1007 nat->nat_hv[1] = hv2; 1008 1009 MUTEX_INIT(&nat->nat_lock, "nat entry lock"); 1010 1011 nat->nat_rev = rev; 1012 nat->nat_ref = 1; 1013 nat->nat_bytes[0] = 0; 1014 nat->nat_pkts[0] = 0; 1015 nat->nat_bytes[1] = 0; 1016 nat->nat_pkts[1] = 0; 1017 1018 nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0'; 1019 nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 6, ifs); 1020 1021 if (nat->nat_ifnames[1][0] !='\0') { 1022 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 1023 nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 6, ifs); 1024 } else { 1025 (void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0], 1026 LIFNAMSIZ); 1027 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; 1028 nat->nat_ifps[1] = nat->nat_ifps[0]; 1029 } 1030 1031 nat->nat_next = ifs->ifs_nat_instances; 1032 nat->nat_pnext = &ifs->ifs_nat_instances; 1033 if (ifs->ifs_nat_instances) 1034 ifs->ifs_nat_instances->nat_pnext = &nat->nat_next; 1035 ifs->ifs_nat_instances = nat; 1036 1037 natp = &ifs->ifs_nat_table[0][hv1]; 1038 if (*natp) 1039 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 1040 nat->nat_phnext[0] = natp; 1041 nat->nat_hnext[0] = *natp; 1042 *natp = nat; 1043 ifs->ifs_nat_stats.ns_bucketlen[0][hv1]++; 1044 1045 natp = &ifs->ifs_nat_table[1][hv2]; 1046 if (*natp) 1047 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 1048 nat->nat_phnext[1] = natp; 1049 nat->nat_hnext[1] = *natp; 1050 *natp = nat; 1051 ifs->ifs_nat_stats.ns_bucketlen[1][hv2]++; 1052 1053 fr_setnatqueue(nat, rev, ifs); 1054 1055 ifs->ifs_nat_stats.ns_added++; 1056 ifs->ifs_nat_stats.ns_inuse++; 1057 return 0; 1058 } 1059 1060 1061 /* ------------------------------------------------------------------------ */ 1062 /* Function: nat6_icmperrorlookup */ 1063 /* Returns: nat_t* - point to matching NAT structure */ 1064 /* Parameters: fin(I) - pointer to packet information */ 1065 /* dir(I) - direction of packet (in/out) */ 1066 /* */ 1067 /* Check if the ICMP error message is related to an existing TCP, UDP or */ 1068 /* ICMP query nat entry. It is assumed that the packet is already of the */ 1069 /* the required length. */ 1070 /* ------------------------------------------------------------------------ */ 1071 nat_t *nat6_icmperrorlookup(fin, dir) 1072 fr_info_t *fin; 1073 int dir; 1074 { 1075 int flags = 0, minlen; 1076 struct icmp6_hdr *orgicmp; 1077 tcphdr_t *tcp = NULL; 1078 u_short data[2]; 1079 nat_t *nat; 1080 ip6_t *oip6; 1081 u_int p; 1082 1083 minlen = 40; 1084 /* 1085 * Does it at least have the return (basic) IP header ? 1086 * Only a basic IP header (no options) should be with an ICMP error 1087 * header. Also, if it's not an error type, then return. 1088 */ 1089 if (!(fin->fin_flx & FI_ICMPERR)) 1090 return NULL; 1091 1092 /* 1093 * Check packet size 1094 */ 1095 if (fin->fin_plen < ICMP6ERR_IPICMPHLEN) 1096 return NULL; 1097 oip6 = (ip6_t *)((char *)fin->fin_dp + 8); 1098 1099 /* 1100 * Is the buffer big enough for all of it ? It's the size of the IP 1101 * header claimed in the encapsulated part which is of concern. It 1102 * may be too big to be in this buffer but not so big that it's 1103 * outside the ICMP packet, leading to TCP deref's causing problems. 1104 * This is possible because we don't know how big oip_hl is when we 1105 * do the pullup early in fr_check() and thus can't gaurantee it is 1106 * all here now. 1107 */ 1108 #ifdef _KERNEL 1109 { 1110 mb_t *m; 1111 1112 m = fin->fin_m; 1113 # if defined(MENTAT) 1114 if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr) 1115 return NULL; 1116 # else 1117 if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN > 1118 (char *)fin->fin_ip + M_LEN(m)) 1119 return NULL; 1120 # endif 1121 } 1122 #endif 1123 1124 if (IP6_NEQ(&fin->fin_dst6, &oip6->ip6_src)) 1125 return NULL; 1126 1127 p = oip6->ip6_nxt; 1128 if (p == IPPROTO_TCP) 1129 flags = IPN_TCP; 1130 else if (p == IPPROTO_UDP) 1131 flags = IPN_UDP; 1132 else if (p == IPPROTO_ICMPV6) { 1133 orgicmp = (struct icmp6_hdr *)(oip6 + 1); 1134 1135 /* see if this is related to an ICMP query */ 1136 if (nat_icmpquerytype6(orgicmp->icmp6_type)) { 1137 data[0] = fin->fin_data[0]; 1138 data[1] = fin->fin_data[1]; 1139 fin->fin_data[0] = 0; 1140 fin->fin_data[1] = orgicmp->icmp6_id; 1141 1142 flags = IPN_ICMPERR|IPN_ICMPQUERY; 1143 /* 1144 * NOTE : dir refers to the direction of the original 1145 * ip packet. By definition the icmp error 1146 * message flows in the opposite direction. 1147 */ 1148 if (dir == NAT_INBOUND) 1149 nat = nat6_inlookup(fin, flags, p, 1150 &oip6->ip6_dst, &oip6->ip6_src); 1151 else 1152 nat = nat6_outlookup(fin, flags, p, 1153 &oip6->ip6_dst, &oip6->ip6_src); 1154 fin->fin_data[0] = data[0]; 1155 fin->fin_data[1] = data[1]; 1156 return nat; 1157 } 1158 } 1159 1160 if (flags & IPN_TCPUDP) { 1161 minlen += 8; /* + 64bits of data to get ports */ 1162 if (fin->fin_plen < ICMPERR_ICMPHLEN + minlen) 1163 return NULL; 1164 1165 data[0] = fin->fin_data[0]; 1166 data[1] = fin->fin_data[1]; 1167 tcp = (tcphdr_t *)(oip6 + 1); 1168 fin->fin_data[0] = ntohs(tcp->th_dport); 1169 fin->fin_data[1] = ntohs(tcp->th_sport); 1170 1171 if (dir == NAT_INBOUND) { 1172 nat = nat6_inlookup(fin, flags, p, 1173 &oip6->ip6_dst, &oip6->ip6_src); 1174 } else { 1175 nat = nat6_outlookup(fin, flags, p, 1176 &oip6->ip6_dst, &oip6->ip6_src); 1177 } 1178 fin->fin_data[0] = data[0]; 1179 fin->fin_data[1] = data[1]; 1180 return nat; 1181 } 1182 if (dir == NAT_INBOUND) 1183 return nat6_inlookup(fin, 0, p, &oip6->ip6_dst, &oip6->ip6_src); 1184 else 1185 return nat6_outlookup(fin, 0, p, &oip6->ip6_dst, 1186 &oip6->ip6_src); 1187 } 1188 1189 1190 /* ------------------------------------------------------------------------ */ 1191 /* Function: nat6_icmperror */ 1192 /* Returns: nat_t* - point to matching NAT structure */ 1193 /* Parameters: fin(I) - pointer to packet information */ 1194 /* nflags(I) - NAT flags for this packet */ 1195 /* dir(I) - direction of packet (in/out) */ 1196 /* */ 1197 /* Fix up an ICMP packet which is an error message for an existing NAT */ 1198 /* session. This will correct both packet header data and checksums. */ 1199 /* */ 1200 /* This should *ONLY* be used for incoming ICMP error packets to make sure */ 1201 /* a NAT'd ICMP packet gets correctly recognised. */ 1202 /* ------------------------------------------------------------------------ */ 1203 nat_t *nat6_icmperror(fin, nflags, dir) 1204 fr_info_t *fin; 1205 u_int *nflags; 1206 int dir; 1207 { 1208 u_32_t sum1, sum2, sumd, psum1, psum2, psumd, sumd1; 1209 i6addr_t in; 1210 struct icmp6_hdr *icmp6, *orgicmp; 1211 int dlen; 1212 udphdr_t *udp; 1213 tcphdr_t *tcp; 1214 nat_t *nat; 1215 ip6_t *oip6; 1216 if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) 1217 return NULL; 1218 1219 /* 1220 * nat6_icmperrorlookup() looks up nat entry associated with the 1221 * offending IP packet and returns pointer to the entry, or NULL 1222 * if packet wasn't natted or for `defective' packets. 1223 */ 1224 1225 if ((fin->fin_v != 6) || !(nat = nat6_icmperrorlookup(fin, dir))) 1226 return NULL; 1227 1228 sumd1 = 0; 1229 *nflags = IPN_ICMPERR; 1230 icmp6 = fin->fin_dp; 1231 oip6 = (ip6_t *)((char *)icmp6 + sizeof (*icmp6)); 1232 udp = (udphdr_t *)(((char *)oip6) + sizeof (*oip6)); 1233 tcp = (tcphdr_t *)udp; 1234 dlen = fin->fin_plen - ((char *)udp - (char *)fin->fin_ip); 1235 1236 /* 1237 * Need to adjust ICMP header to include the real IP#'s and 1238 * port #'s. There are three steps required. 1239 * 1240 * Step 1 1241 * No update needed for ip6 header checksum. 1242 * 1243 * Unlike IPv4, we need to update icmp_cksum for IPv6 address 1244 * changes because there's no ip_sum change to cancel it. 1245 */ 1246 1247 if (IP6_EQ((i6addr_t *)&oip6->ip6_dst, &nat->nat_oip6)) { 1248 sum1 = LONG_SUM6((i6addr_t *)&oip6->ip6_src); 1249 in = nat->nat_inip6; 1250 oip6->ip6_src = in.in6; 1251 } else { 1252 sum1 = LONG_SUM6((i6addr_t *)&oip6->ip6_dst); 1253 in = nat->nat_outip6; 1254 oip6->ip6_dst = in.in6; 1255 } 1256 1257 sum2 = LONG_SUM6(&in); 1258 CALC_SUMD(sum1, sum2, sumd); 1259 1260 /* 1261 * Step 2 1262 * Perform other adjustments based on protocol of offending packet. 1263 */ 1264 1265 switch (oip6->ip6_nxt) { 1266 case IPPROTO_TCP : 1267 case IPPROTO_UDP : 1268 1269 /* 1270 * For offending TCP/UDP IP packets, translate the ports 1271 * based on the NAT specification. 1272 * 1273 * Advance notice : Now it becomes complicated :-) 1274 * 1275 * Since the port and IP addresse fields are both part 1276 * of the TCP/UDP checksum of the offending IP packet, 1277 * we need to adjust that checksum as well. 1278 * 1279 * To further complicate things, the TCP/UDP checksum 1280 * may not be present. We must check to see if the 1281 * length of the data portion is big enough to hold 1282 * the checksum. In the UDP case, a test to determine 1283 * if the checksum is even set is also required. 1284 * 1285 * Any changes to an IP address, port or checksum within 1286 * the ICMP packet requires a change to icmp_cksum. 1287 * 1288 * Be extremely careful here ... The change is dependent 1289 * upon whether or not the TCP/UPD checksum is present. 1290 * 1291 * If TCP/UPD checksum is present, the icmp_cksum must 1292 * compensate for checksum modification resulting from 1293 * IP address change only. Port change and resulting 1294 * data checksum adjustments cancel each other out. 1295 * 1296 * If TCP/UDP checksum is not present, icmp_cksum must 1297 * compensate for port change only. The IP address 1298 * change does not modify anything else in this case. 1299 */ 1300 1301 psum1 = 0; 1302 psum2 = 0; 1303 psumd = 0; 1304 1305 if ((tcp->th_dport == nat->nat_oport) && 1306 (tcp->th_sport != nat->nat_inport)) { 1307 1308 /* 1309 * Translate the source port. 1310 */ 1311 1312 psum1 = ntohs(tcp->th_sport); 1313 psum2 = ntohs(nat->nat_inport); 1314 tcp->th_sport = nat->nat_inport; 1315 1316 } else if ((tcp->th_sport == nat->nat_oport) && 1317 (tcp->th_dport != nat->nat_outport)) { 1318 1319 /* 1320 * Translate the destination port. 1321 */ 1322 1323 psum1 = ntohs(tcp->th_dport); 1324 psum2 = ntohs(nat->nat_outport); 1325 tcp->th_dport = nat->nat_outport; 1326 } 1327 1328 if ((oip6->ip6_nxt == IPPROTO_TCP) && (dlen >= 18)) { 1329 1330 /* 1331 * TCP checksum present. 1332 * 1333 * Adjust data checksum and icmp checksum to 1334 * compensate for any IP address change. 1335 */ 1336 1337 sum1 = ntohs(tcp->th_sum); 1338 fix_datacksum(&tcp->th_sum, sumd); 1339 sum2 = ntohs(tcp->th_sum); 1340 CALC_SUMD(sum1, sum2, sumd); 1341 sumd1 += sumd; 1342 1343 /* 1344 * Also make data checksum adjustment to 1345 * compensate for any port change. 1346 */ 1347 1348 if (psum1 != psum2) { 1349 CALC_SUMD(psum1, psum2, psumd); 1350 fix_datacksum(&tcp->th_sum, psumd); 1351 } 1352 1353 } else if ((oip6->ip6_nxt == IPPROTO_UDP) && 1354 (dlen >= 8) && (udp->uh_sum != 0)) { 1355 1356 /* 1357 * The UDP checksum is present and set. 1358 * 1359 * Adjust data checksum and icmp checksum to 1360 * compensate for any IP address change. 1361 */ 1362 1363 sum1 = ntohs(udp->uh_sum); 1364 fix_datacksum(&udp->uh_sum, sumd); 1365 sum2 = ntohs(udp->uh_sum); 1366 CALC_SUMD(sum1, sum2, sumd); 1367 sumd1 += sumd; 1368 1369 /* 1370 * Also make data checksum adjustment to 1371 * compensate for any port change. 1372 */ 1373 1374 if (psum1 != psum2) { 1375 CALC_SUMD(psum1, psum2, psumd); 1376 fix_datacksum(&udp->uh_sum, psumd); 1377 } 1378 1379 } else { 1380 1381 /* 1382 * Data checksum was not present. 1383 * 1384 * Compensate for any port change. 1385 */ 1386 1387 CALC_SUMD(psum2, psum1, psumd); 1388 sumd1 += psumd; 1389 } 1390 break; 1391 1392 case IPPROTO_ICMPV6 : 1393 1394 orgicmp = (struct icmp6_hdr *)udp; 1395 1396 if ((nat->nat_dir == NAT_OUTBOUND) && 1397 (orgicmp->icmp6_id != nat->nat_inport) && 1398 (dlen >= 8)) { 1399 1400 /* 1401 * Fix ICMP checksum (of the offening ICMP 1402 * query packet) to compensate the change 1403 * in the ICMP id of the offending ICMP 1404 * packet. 1405 * 1406 * Since you modify orgicmp->icmp_id with 1407 * a delta (say x) and you compensate that 1408 * in origicmp->icmp_cksum with a delta 1409 * minus x, you don't have to adjust the 1410 * overall icmp->icmp_cksum 1411 */ 1412 1413 sum1 = ntohs(orgicmp->icmp6_id); 1414 sum2 = ntohs(nat->nat_inport); 1415 CALC_SUMD(sum1, sum2, sumd); 1416 orgicmp->icmp6_id = nat->nat_inport; 1417 fix_datacksum(&orgicmp->icmp6_cksum, sumd); 1418 1419 } /* nat_dir can't be NAT_INBOUND for icmp queries */ 1420 1421 break; 1422 1423 default : 1424 1425 break; 1426 1427 } /* switch (oip6->ip6_nxt) */ 1428 1429 /* 1430 * Step 3 1431 * Make the adjustments to icmp checksum. 1432 */ 1433 1434 if (sumd1 != 0) { 1435 sumd1 = (sumd1 & 0xffff) + (sumd1 >> 16); 1436 sumd1 = (sumd1 & 0xffff) + (sumd1 >> 16); 1437 fix_incksum(&icmp6->icmp6_cksum, sumd1); 1438 } 1439 return nat; 1440 } 1441 1442 1443 /* 1444 * NB: these lookups don't lock access to the list, it assumed that it has 1445 * already been done! 1446 */ 1447 1448 /* ------------------------------------------------------------------------ */ 1449 /* Function: nat6_inlookup */ 1450 /* Returns: nat_t* - NULL == no match, */ 1451 /* else pointer to matching NAT entry */ 1452 /* Parameters: fin(I) - pointer to packet information */ 1453 /* flags(I) - NAT flags for this packet */ 1454 /* p(I) - protocol for this packet */ 1455 /* src(I) - source IP address */ 1456 /* mapdst(I) - destination IP address */ 1457 /* */ 1458 /* Lookup a nat entry based on the mapped destination ip address/port and */ 1459 /* real source address/port. We use this lookup when receiving a packet, */ 1460 /* we're looking for a table entry, based on the destination address. */ 1461 /* */ 1462 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 1463 /* */ 1464 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ 1465 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 1466 /* */ 1467 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 1468 /* the packet is of said protocol */ 1469 /* ------------------------------------------------------------------------ */ 1470 nat_t *nat6_inlookup(fin, flags, p, src, mapdst) 1471 fr_info_t *fin; 1472 u_int flags, p; 1473 struct in6_addr *src, *mapdst; 1474 { 1475 u_short sport, dport; 1476 u_int sflags; 1477 nat_t *nat; 1478 int nflags; 1479 i6addr_t dst; 1480 void *ifp; 1481 u_int hv; 1482 ipf_stack_t *ifs = fin->fin_ifs; 1483 1484 if (fin != NULL) 1485 ifp = fin->fin_ifp; 1486 else 1487 ifp = NULL; 1488 sport = 0; 1489 dport = 0; 1490 dst.in6 = *mapdst; 1491 sflags = flags & NAT_TCPUDPICMP; 1492 1493 switch (p) 1494 { 1495 case IPPROTO_TCP : 1496 case IPPROTO_UDP : 1497 sport = htons(fin->fin_data[0]); 1498 dport = htons(fin->fin_data[1]); 1499 break; 1500 case IPPROTO_ICMPV6 : 1501 if (flags & IPN_ICMPERR) 1502 sport = fin->fin_data[1]; 1503 else 1504 dport = fin->fin_data[1]; 1505 break; 1506 default : 1507 break; 1508 } 1509 1510 1511 if ((flags & SI_WILDP) != 0) 1512 goto find_in_wild_ports; 1513 1514 hv = NAT_HASH_FN6(&dst, dport, 0xffffffff); 1515 hv = NAT_HASH_FN6(src, hv + sport, ifs->ifs_ipf_nattable_sz); 1516 nat = ifs->ifs_nat_table[1][hv]; 1517 for (; nat; nat = nat->nat_hnext[1]) { 1518 if (nat->nat_v != 6) 1519 continue; 1520 1521 if (nat->nat_ifps[0] != NULL) { 1522 if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 1523 continue; 1524 } else if (ifp != NULL) 1525 nat->nat_ifps[0] = ifp; 1526 1527 nflags = nat->nat_flags; 1528 1529 if (IP6_EQ(&nat->nat_oip6, src) && 1530 IP6_EQ(&nat->nat_outip6, &dst) && 1531 (((p == 0) && 1532 (sflags == (nat->nat_flags & IPN_TCPUDPICMP))) || 1533 (p == nat->nat_p))) { 1534 switch (p) 1535 { 1536 #if 0 1537 case IPPROTO_GRE : 1538 if (nat->nat_call[1] != fin->fin_data[0]) 1539 continue; 1540 break; 1541 #endif 1542 case IPPROTO_ICMPV6 : 1543 if ((flags & IPN_ICMPERR) != 0) { 1544 if (nat->nat_outport != sport) 1545 continue; 1546 } else { 1547 if (nat->nat_outport != dport) 1548 continue; 1549 } 1550 break; 1551 case IPPROTO_TCP : 1552 case IPPROTO_UDP : 1553 if (nat->nat_oport != sport) 1554 continue; 1555 if (nat->nat_outport != dport) 1556 continue; 1557 break; 1558 default : 1559 break; 1560 } 1561 1562 #ifdef IPF_V6_PROXIES 1563 ipn = nat->nat_ptr; 1564 if ((ipn != NULL) && (nat->nat_aps != NULL)) 1565 if (appr_match(fin, nat) != 0) 1566 continue; 1567 #endif 1568 return nat; 1569 } 1570 } 1571 1572 /* 1573 * So if we didn't find it but there are wildcard members in the hash 1574 * table, go back and look for them. We do this search and update here 1575 * because it is modifying the NAT table and we want to do this only 1576 * for the first packet that matches. The exception, of course, is 1577 * for "dummy" (FI_IGNORE) lookups. 1578 */ 1579 find_in_wild_ports: 1580 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) 1581 return NULL; 1582 if (ifs->ifs_nat_stats.ns_wilds == 0) 1583 return NULL; 1584 1585 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1586 1587 hv = NAT_HASH_FN6(&dst, 0, 0xffffffff); 1588 hv = NAT_HASH_FN6(src, hv, ifs->ifs_ipf_nattable_sz); 1589 1590 WRITE_ENTER(&ifs->ifs_ipf_nat); 1591 1592 nat = ifs->ifs_nat_table[1][hv]; 1593 for (; nat; nat = nat->nat_hnext[1]) { 1594 if (nat->nat_v != 6) 1595 continue; 1596 1597 if (nat->nat_ifps[0] != NULL) { 1598 if ((ifp != NULL) && (ifp != nat->nat_ifps[0])) 1599 continue; 1600 } else if (ifp != NULL) 1601 nat->nat_ifps[0] = ifp; 1602 1603 if (nat->nat_p != fin->fin_p) 1604 continue; 1605 if (IP6_NEQ(&nat->nat_oip6, src) || 1606 IP6_NEQ(&nat->nat_outip6, &dst)) 1607 continue; 1608 1609 nflags = nat->nat_flags; 1610 if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 1611 continue; 1612 1613 if (nat_wildok(nat, (int)sport, (int)dport, nflags, 1614 NAT_INBOUND) == 1) { 1615 if ((fin->fin_flx & FI_IGNORE) != 0) 1616 break; 1617 if ((nflags & SI_CLONE) != 0) { 1618 nat = fr_natclone(fin, nat); 1619 if (nat == NULL) 1620 break; 1621 } else { 1622 MUTEX_ENTER(&ifs->ifs_ipf_nat_new); 1623 ifs->ifs_nat_stats.ns_wilds--; 1624 MUTEX_EXIT(&ifs->ifs_ipf_nat_new); 1625 } 1626 nat->nat_oport = sport; 1627 nat->nat_outport = dport; 1628 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 1629 nat6_tabmove(nat, ifs); 1630 break; 1631 } 1632 } 1633 1634 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 1635 1636 return nat; 1637 } 1638 1639 1640 /* ------------------------------------------------------------------------ */ 1641 /* Function: nat6_tabmove */ 1642 /* Returns: Nil */ 1643 /* Parameters: nat(I) - pointer to NAT structure */ 1644 /* Write Lock: ipf_nat */ 1645 /* */ 1646 /* This function is only called for TCP/UDP NAT table entries where the */ 1647 /* original was placed in the table without hashing on the ports and we now */ 1648 /* want to include hashing on port numbers. */ 1649 /* ------------------------------------------------------------------------ */ 1650 static void nat6_tabmove(nat, ifs) 1651 nat_t *nat; 1652 ipf_stack_t *ifs; 1653 { 1654 nat_t **natp; 1655 u_int hv; 1656 1657 if (nat->nat_flags & SI_CLONE) 1658 return; 1659 1660 /* 1661 * Remove the NAT entry from the old location 1662 */ 1663 if (nat->nat_hnext[0]) 1664 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; 1665 *nat->nat_phnext[0] = nat->nat_hnext[0]; 1666 ifs->ifs_nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--; 1667 1668 if (nat->nat_hnext[1]) 1669 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; 1670 *nat->nat_phnext[1] = nat->nat_hnext[1]; 1671 ifs->ifs_nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; 1672 1673 /* 1674 * Add into the NAT table in the new position 1675 */ 1676 hv = NAT_HASH_FN6(&nat->nat_inip6, nat->nat_inport, 0xffffffff); 1677 hv = NAT_HASH_FN6(&nat->nat_oip6, hv + nat->nat_oport, 1678 ifs->ifs_ipf_nattable_sz); 1679 nat->nat_hv[0] = hv; 1680 natp = &ifs->ifs_nat_table[0][hv]; 1681 if (*natp) 1682 (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; 1683 nat->nat_phnext[0] = natp; 1684 nat->nat_hnext[0] = *natp; 1685 *natp = nat; 1686 ifs->ifs_nat_stats.ns_bucketlen[0][hv]++; 1687 1688 hv = NAT_HASH_FN6(&nat->nat_outip6, nat->nat_outport, 0xffffffff); 1689 hv = NAT_HASH_FN6(&nat->nat_oip6, hv + nat->nat_oport, 1690 ifs->ifs_ipf_nattable_sz); 1691 nat->nat_hv[1] = hv; 1692 natp = &ifs->ifs_nat_table[1][hv]; 1693 if (*natp) 1694 (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; 1695 nat->nat_phnext[1] = natp; 1696 nat->nat_hnext[1] = *natp; 1697 *natp = nat; 1698 ifs->ifs_nat_stats.ns_bucketlen[1][hv]++; 1699 } 1700 1701 1702 /* ------------------------------------------------------------------------ */ 1703 /* Function: nat6_outlookup */ 1704 /* Returns: nat_t* - NULL == no match, */ 1705 /* else pointer to matching NAT entry */ 1706 /* Parameters: fin(I) - pointer to packet information */ 1707 /* flags(I) - NAT flags for this packet */ 1708 /* p(I) - protocol for this packet */ 1709 /* src(I) - source IP address */ 1710 /* dst(I) - destination IP address */ 1711 /* rw(I) - 1 == write lock on ipf_nat held, 0 == read lock. */ 1712 /* */ 1713 /* Lookup a nat entry based on the source 'real' ip address/port and */ 1714 /* destination address/port. We use this lookup when sending a packet out, */ 1715 /* we're looking for a table entry, based on the source address. */ 1716 /* */ 1717 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ 1718 /* */ 1719 /* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ 1720 /* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ 1721 /* */ 1722 /* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ 1723 /* the packet is of said protocol */ 1724 /* ------------------------------------------------------------------------ */ 1725 nat_t *nat6_outlookup(fin, flags, p, src, dst) 1726 fr_info_t *fin; 1727 u_int flags, p; 1728 struct in6_addr *src , *dst; 1729 { 1730 u_short sport, dport; 1731 u_int sflags; 1732 nat_t *nat; 1733 int nflags; 1734 void *ifp; 1735 u_int hv; 1736 ipf_stack_t *ifs = fin->fin_ifs; 1737 1738 ifp = fin->fin_ifp; 1739 1740 sflags = flags & IPN_TCPUDPICMP; 1741 sport = 0; 1742 dport = 0; 1743 1744 switch (p) 1745 { 1746 case IPPROTO_TCP : 1747 case IPPROTO_UDP : 1748 sport = htons(fin->fin_data[0]); 1749 dport = htons(fin->fin_data[1]); 1750 break; 1751 case IPPROTO_ICMPV6 : 1752 if (flags & IPN_ICMPERR) 1753 sport = fin->fin_data[1]; 1754 else 1755 dport = fin->fin_data[1]; 1756 break; 1757 default : 1758 break; 1759 } 1760 1761 if ((flags & SI_WILDP) != 0) 1762 goto find_out_wild_ports; 1763 1764 hv = NAT_HASH_FN6(src, sport, 0xffffffff); 1765 hv = NAT_HASH_FN6(dst, hv + dport, ifs->ifs_ipf_nattable_sz); 1766 nat = ifs->ifs_nat_table[0][hv]; 1767 for (; nat; nat = nat->nat_hnext[0]) { 1768 if (nat->nat_v != 6) 1769 continue; 1770 1771 if (nat->nat_ifps[1] != NULL) { 1772 if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 1773 continue; 1774 } else if (ifp != NULL) 1775 nat->nat_ifps[1] = ifp; 1776 1777 nflags = nat->nat_flags; 1778 1779 if (IP6_EQ(&nat->nat_inip6, src) && 1780 IP6_EQ(&nat->nat_oip6, dst) && 1781 (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP))) || 1782 (p == nat->nat_p))) { 1783 switch (p) 1784 { 1785 #if 0 1786 case IPPROTO_GRE : 1787 if (nat->nat_call[1] != fin->fin_data[0]) 1788 continue; 1789 break; 1790 #endif 1791 case IPPROTO_TCP : 1792 case IPPROTO_UDP : 1793 if (nat->nat_oport != dport) 1794 continue; 1795 if (nat->nat_inport != sport) 1796 continue; 1797 break; 1798 default : 1799 break; 1800 } 1801 1802 #ifdef IPF_V6_PROXIES 1803 ipn = nat->nat_ptr; 1804 if ((ipn != NULL) && (nat->nat_aps != NULL)) 1805 if (appr_match(fin, nat) != 0) 1806 continue; 1807 #endif 1808 return nat; 1809 } 1810 } 1811 1812 /* 1813 * So if we didn't find it but there are wildcard members in the hash 1814 * table, go back and look for them. We do this search and update here 1815 * because it is modifying the NAT table and we want to do this only 1816 * for the first packet that matches. The exception, of course, is 1817 * for "dummy" (FI_IGNORE) lookups. 1818 */ 1819 find_out_wild_ports: 1820 if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) 1821 return NULL; 1822 if (ifs->ifs_nat_stats.ns_wilds == 0) 1823 return NULL; 1824 1825 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 1826 1827 hv = NAT_HASH_FN6(src, 0, 0xffffffff); 1828 hv = NAT_HASH_FN6(dst, hv, ifs->ifs_ipf_nattable_sz); 1829 1830 WRITE_ENTER(&ifs->ifs_ipf_nat); 1831 1832 nat = ifs->ifs_nat_table[0][hv]; 1833 for (; nat; nat = nat->nat_hnext[0]) { 1834 if (nat->nat_v != 6) 1835 continue; 1836 1837 if (nat->nat_ifps[1] != NULL) { 1838 if ((ifp != NULL) && (ifp != nat->nat_ifps[1])) 1839 continue; 1840 } else if (ifp != NULL) 1841 nat->nat_ifps[1] = ifp; 1842 1843 if (nat->nat_p != fin->fin_p) 1844 continue; 1845 if (IP6_NEQ(&nat->nat_inip6, src) || 1846 IP6_NEQ(&nat->nat_oip6, dst)) 1847 continue; 1848 1849 nflags = nat->nat_flags; 1850 if (!(nflags & (NAT_TCPUDP|SI_WILDP))) 1851 continue; 1852 1853 if (nat_wildok(nat, (int)sport, (int)dport, nflags, 1854 NAT_OUTBOUND) == 1) { 1855 if ((fin->fin_flx & FI_IGNORE) != 0) 1856 break; 1857 if ((nflags & SI_CLONE) != 0) { 1858 nat = fr_natclone(fin, nat); 1859 if (nat == NULL) 1860 break; 1861 } else { 1862 MUTEX_ENTER(&ifs->ifs_ipf_nat_new); 1863 ifs->ifs_nat_stats.ns_wilds--; 1864 MUTEX_EXIT(&ifs->ifs_ipf_nat_new); 1865 } 1866 nat->nat_inport = sport; 1867 nat->nat_oport = dport; 1868 if (nat->nat_outport == 0) 1869 nat->nat_outport = sport; 1870 nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); 1871 nat6_tabmove(nat, ifs); 1872 break; 1873 } 1874 } 1875 1876 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 1877 1878 return nat; 1879 } 1880 1881 1882 /* ------------------------------------------------------------------------ */ 1883 /* Function: nat6_lookupredir */ 1884 /* Returns: nat_t* - NULL == no match, */ 1885 /* else pointer to matching NAT entry */ 1886 /* Parameters: np(I) - pointer to description of packet to find NAT table */ 1887 /* entry for. */ 1888 /* */ 1889 /* Lookup the NAT tables to search for a matching redirect */ 1890 /* ------------------------------------------------------------------------ */ 1891 nat_t *nat6_lookupredir(np, ifs) 1892 natlookup_t *np; 1893 ipf_stack_t *ifs; 1894 { 1895 fr_info_t fi; 1896 nat_t *nat; 1897 1898 bzero((char *)&fi, sizeof (fi)); 1899 if (np->nl_flags & IPN_IN) { 1900 fi.fin_data[0] = ntohs(np->nl_realport); 1901 fi.fin_data[1] = ntohs(np->nl_outport); 1902 } else { 1903 fi.fin_data[0] = ntohs(np->nl_inport); 1904 fi.fin_data[1] = ntohs(np->nl_outport); 1905 } 1906 if (np->nl_flags & IPN_TCP) 1907 fi.fin_p = IPPROTO_TCP; 1908 else if (np->nl_flags & IPN_UDP) 1909 fi.fin_p = IPPROTO_UDP; 1910 else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY)) 1911 fi.fin_p = IPPROTO_ICMPV6; 1912 1913 fi.fin_ifs = ifs; 1914 /* 1915 * We can do two sorts of lookups: 1916 * - IPN_IN: we have the `real' and `out' address, look for `in'. 1917 * - default: we have the `in' and `out' address, look for `real'. 1918 */ 1919 if (np->nl_flags & IPN_IN) { 1920 if ((nat = nat6_inlookup(&fi, np->nl_flags, fi.fin_p, 1921 &np->nl_realip6, &np->nl_outip6))) { 1922 np->nl_inipaddr = nat->nat_inip6; 1923 np->nl_inport = nat->nat_inport; 1924 } 1925 } else { 1926 /* 1927 * If nl_inip is non null, this is a lookup based on the real 1928 * ip address. Else, we use the fake. 1929 */ 1930 if ((nat = nat6_outlookup(&fi, np->nl_flags, fi.fin_p, 1931 &np->nl_inip6, &np->nl_outip6))) { 1932 if ((np->nl_flags & IPN_FINDFORWARD) != 0) { 1933 fr_info_t fin; 1934 bzero((char *)&fin, sizeof (fin)); 1935 fin.fin_p = nat->nat_p; 1936 fin.fin_data[0] = ntohs(nat->nat_outport); 1937 fin.fin_data[1] = ntohs(nat->nat_oport); 1938 fin.fin_ifs = ifs; 1939 if (nat6_inlookup(&fin, np->nl_flags, fin.fin_p, 1940 &nat->nat_outip6.in6, 1941 &nat->nat_oip6.in6) != NULL) { 1942 np->nl_flags &= ~IPN_FINDFORWARD; 1943 } 1944 } 1945 1946 np->nl_realip6 = nat->nat_outip6.in6; 1947 np->nl_realport = nat->nat_outport; 1948 } 1949 } 1950 1951 return nat; 1952 } 1953 1954 1955 /* ------------------------------------------------------------------------ */ 1956 /* Function: nat6_match */ 1957 /* Returns: int - 0 == no match, 1 == match */ 1958 /* Parameters: fin(I) - pointer to packet information */ 1959 /* np(I) - pointer to NAT rule */ 1960 /* */ 1961 /* Pull the matching of a packet against a NAT rule out of that complex */ 1962 /* loop inside fr_checknat6in() and lay it out properly in its own function.*/ 1963 /* ------------------------------------------------------------------------ */ 1964 static int nat6_match(fin, np) 1965 fr_info_t *fin; 1966 ipnat_t *np; 1967 { 1968 frtuc_t *ft; 1969 1970 if (fin->fin_v != 6) 1971 return 0; 1972 1973 if (np->in_p && fin->fin_p != np->in_p) 1974 return 0; 1975 1976 if (fin->fin_out) { 1977 if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) 1978 return 0; 1979 if (IP6_MASKNEQ(&fin->fin_src6, &np->in_in[1], &np->in_in[0]) 1980 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 1981 return 0; 1982 if (IP6_MASKNEQ(&fin->fin_dst6, &np->in_src[1], &np->in_src[0]) 1983 ^ ((np->in_flags & IPN_NOTDST) != 0)) 1984 return 0; 1985 } else { 1986 if (!(np->in_redir & NAT_REDIRECT)) 1987 return 0; 1988 if (IP6_MASKNEQ(&fin->fin_src6, &np->in_src[1], &np->in_src[0]) 1989 ^ ((np->in_flags & IPN_NOTSRC) != 0)) 1990 return 0; 1991 if (IP6_MASKNEQ(&fin->fin_dst6, &np->in_out[1], &np->in_out[0]) 1992 ^ ((np->in_flags & IPN_NOTDST) != 0)) 1993 return 0; 1994 } 1995 1996 ft = &np->in_tuc; 1997 if (!(fin->fin_flx & FI_TCPUDP) || 1998 (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) { 1999 if (ft->ftu_scmp || ft->ftu_dcmp) 2000 return 0; 2001 return 1; 2002 } 2003 2004 return fr_tcpudpchk(fin, ft); 2005 } 2006 2007 2008 /* ------------------------------------------------------------------------ */ 2009 /* Function: fr_checknat6out */ 2010 /* Returns: int - -1 == packet failed NAT checks so block it, */ 2011 /* 0 == no packet translation occurred, */ 2012 /* 1 == packet was successfully translated. */ 2013 /* Parameters: fin(I) - pointer to packet information */ 2014 /* passp(I) - pointer to filtering result flags */ 2015 /* */ 2016 /* Check to see if an outcoming packet should be changed. ICMP packets are */ 2017 /* first checked to see if they match an existing entry (if an error), */ 2018 /* otherwise a search of the current NAT table is made. If neither results */ 2019 /* in a match then a search for a matching NAT rule is made. Create a new */ 2020 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 2021 /* packet header(s) as required. */ 2022 /* ------------------------------------------------------------------------ */ 2023 int fr_checknat6out(fin, passp) 2024 fr_info_t *fin; 2025 u_32_t *passp; 2026 { 2027 struct ifnet *ifp, *sifp; 2028 int rval, natfailed; 2029 ipnat_t *np = NULL; 2030 u_int nflags = 0; 2031 i6addr_t ipa, iph; 2032 int natadd = 1; 2033 frentry_t *fr; 2034 nat_t *nat; 2035 ipf_stack_t *ifs = fin->fin_ifs; 2036 2037 if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0) 2038 return 0; 2039 2040 natfailed = 0; 2041 fr = fin->fin_fr; 2042 sifp = fin->fin_ifp; 2043 if ((fr != NULL) && !(fr->fr_flags & FR_DUP) && 2044 fr->fr_tifs[fin->fin_rev].fd_ifp && 2045 fr->fr_tifs[fin->fin_rev].fd_ifp != (void *)-1) 2046 fin->fin_ifp = fr->fr_tifs[fin->fin_rev].fd_ifp; 2047 ifp = fin->fin_ifp; 2048 2049 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 2050 switch (fin->fin_p) 2051 { 2052 case IPPROTO_TCP : 2053 nflags = IPN_TCP; 2054 break; 2055 case IPPROTO_UDP : 2056 nflags = IPN_UDP; 2057 break; 2058 case IPPROTO_ICMPV6 : 2059 /* 2060 * This is an incoming packet, so the destination is 2061 * the icmp6_id and the source port equals 0 2062 */ 2063 if ((fin->fin_flx & FI_ICMPQUERY) != 0) 2064 nflags = IPN_ICMPQUERY; 2065 break; 2066 default : 2067 break; 2068 } 2069 2070 #ifdef IPF_V6_PROXIES 2071 if ((nflags & IPN_TCPUDP)) 2072 tcp = fin->fin_dp; 2073 #endif 2074 } 2075 2076 ipa = fin->fin_src6; 2077 2078 READ_ENTER(&ifs->ifs_ipf_nat); 2079 2080 if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) && 2081 (nat = nat6_icmperror(fin, &nflags, NAT_OUTBOUND))) 2082 /*EMPTY*/; 2083 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) 2084 natadd = 0; 2085 else if ((nat = nat6_outlookup(fin, nflags|NAT_SEARCH, 2086 (u_int)fin->fin_p, &fin->fin_src6.in6, 2087 &fin->fin_dst6.in6))) { 2088 nflags = nat->nat_flags; 2089 } else { 2090 u_32_t hv, nmsk; 2091 i6addr_t msk; 2092 int i; 2093 2094 /* 2095 * If there is no current entry in the nat table for this IP#, 2096 * create one for it (if there is a matching rule). 2097 */ 2098 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 2099 i = 3; 2100 msk.i6[0] = 0xffffffff; 2101 msk.i6[1] = 0xffffffff; 2102 msk.i6[2] = 0xffffffff; 2103 msk.i6[3] = 0xffffffff; 2104 nmsk = ifs->ifs_nat6_masks[3]; 2105 WRITE_ENTER(&ifs->ifs_ipf_nat); 2106 maskloop: 2107 IP6_AND(&ipa, &msk, &iph); 2108 hv = NAT_HASH_FN6(&iph, 0, ifs->ifs_ipf_natrules_sz); 2109 for (np = ifs->ifs_nat_rules[hv]; np; np = np->in_mnext) 2110 { 2111 if ((np->in_ifps[1] && (np->in_ifps[1] != ifp))) 2112 continue; 2113 if (np->in_v != 6) 2114 continue; 2115 if (np->in_p && (np->in_p != fin->fin_p)) 2116 continue; 2117 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 2118 continue; 2119 if (np->in_flags & IPN_FILTER) { 2120 if (!nat6_match(fin, np)) 2121 continue; 2122 } else if (!IP6_MASKEQ(&ipa, &np->in_in[1], 2123 &np->in_in[0])) 2124 continue; 2125 2126 if ((fr != NULL) && 2127 !fr_matchtag(&np->in_tag, &fr->fr_nattag)) 2128 continue; 2129 2130 #ifdef IPF_V6_PROXIES 2131 if (*np->in_plabel != '\0') { 2132 if (((np->in_flags & IPN_FILTER) == 0) && 2133 (np->in_dport != tcp->th_dport)) 2134 continue; 2135 if (appr_ok(fin, tcp, np) == 0) 2136 continue; 2137 } 2138 #endif 2139 2140 if (nat = nat6_new(fin, np, NULL, nflags, 2141 NAT_OUTBOUND)) { 2142 np->in_hits++; 2143 break; 2144 } else 2145 natfailed = -1; 2146 } 2147 if ((np == NULL) && (i >= 0)) { 2148 while (i >= 0) { 2149 while (nmsk) { 2150 msk.i6[i] = htonl(ntohl(msk.i6[i])<<1); 2151 if ((nmsk & 0x80000000) != 0) { 2152 nmsk <<= 1; 2153 goto maskloop; 2154 } 2155 nmsk <<= 1; 2156 } 2157 msk.i6[i--] = 0; 2158 if (i >= 0) { 2159 nmsk = ifs->ifs_nat6_masks[i]; 2160 if (nmsk != 0) 2161 goto maskloop; 2162 } 2163 } 2164 } 2165 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 2166 } 2167 2168 if (nat != NULL) { 2169 rval = fr_nat6out(fin, nat, natadd, nflags); 2170 if (rval == 1) { 2171 MUTEX_ENTER(&nat->nat_lock); 2172 nat->nat_ref++; 2173 MUTEX_EXIT(&nat->nat_lock); 2174 nat->nat_touched = ifs->ifs_fr_ticks; 2175 fin->fin_nat = nat; 2176 } 2177 } else 2178 rval = natfailed; 2179 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 2180 2181 if (rval == -1) { 2182 if (passp != NULL) 2183 *passp = FR_BLOCK; 2184 fin->fin_flx |= FI_BADNAT; 2185 } 2186 fin->fin_ifp = sifp; 2187 return rval; 2188 } 2189 2190 /* ------------------------------------------------------------------------ */ 2191 /* Function: fr_nat6out */ 2192 /* Returns: int - -1 == packet failed NAT checks so block it, */ 2193 /* 1 == packet was successfully translated. */ 2194 /* Parameters: fin(I) - pointer to packet information */ 2195 /* nat(I) - pointer to NAT structure */ 2196 /* natadd(I) - flag indicating if it is safe to add frag cache */ 2197 /* nflags(I) - NAT flags set for this packet */ 2198 /* */ 2199 /* Translate a packet coming "out" on an interface. */ 2200 /* ------------------------------------------------------------------------ */ 2201 int fr_nat6out(fin, nat, natadd, nflags) 2202 fr_info_t *fin; 2203 nat_t *nat; 2204 int natadd; 2205 u_32_t nflags; 2206 { 2207 struct icmp6_hdr *icmp6; 2208 u_short *csump; 2209 tcphdr_t *tcp; 2210 ipnat_t *np; 2211 int i; 2212 ipf_stack_t *ifs = fin->fin_ifs; 2213 2214 #if SOLARIS && defined(_KERNEL) 2215 net_data_t net_data_p = ifs->ifs_ipf_ipv6; 2216 #endif 2217 2218 tcp = NULL; 2219 icmp6 = NULL; 2220 csump = NULL; 2221 np = nat->nat_ptr; 2222 2223 if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) 2224 (void) fr_nat_newfrag(fin, 0, nat); 2225 2226 MUTEX_ENTER(&nat->nat_lock); 2227 nat->nat_bytes[1] += fin->fin_plen; 2228 nat->nat_pkts[1]++; 2229 MUTEX_EXIT(&nat->nat_lock); 2230 2231 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 2232 if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { 2233 tcp = fin->fin_dp; 2234 2235 tcp->th_sport = nat->nat_outport; 2236 fin->fin_data[0] = ntohs(nat->nat_outport); 2237 } 2238 2239 if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) { 2240 icmp6 = fin->fin_dp; 2241 icmp6->icmp6_id = nat->nat_outport; 2242 } 2243 2244 csump = nat_proto(fin, nat, nflags); 2245 } 2246 2247 fin->fin_ip6->ip6_src = nat->nat_outip6.in6; 2248 fin->fin_src6 = nat->nat_outip6; 2249 2250 nat_update(fin, nat, np); 2251 2252 /* 2253 * TCP/UDP/ICMPv6 checksum needs to be adjusted. 2254 */ 2255 if (csump != NULL && (!(nflags & IPN_TCPUDP) || 2256 !NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m))) { 2257 if (nflags & IPN_TCPUDP && 2258 NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) { 2259 if (nat->nat_dir == NAT_OUTBOUND) 2260 fix_outcksum(csump, nat->nat_sumd[1]); 2261 else 2262 fix_incksum(csump, nat->nat_sumd[1]); 2263 } else { 2264 if (nat->nat_dir == NAT_OUTBOUND) 2265 fix_outcksum(csump, nat->nat_sumd[0]); 2266 else 2267 fix_incksum(csump, nat->nat_sumd[0]); 2268 } 2269 } 2270 #ifdef IPFILTER_SYNC 2271 ipfsync_update(SMC_NAT, fin, nat->nat_sync); 2272 #endif 2273 /* ------------------------------------------------------------- */ 2274 /* A few quick notes: */ 2275 /* Following are test conditions prior to calling the */ 2276 /* appr_check routine. */ 2277 /* */ 2278 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 2279 /* with a redirect rule, we attempt to match the packet's */ 2280 /* source port against in_dport, otherwise we'd compare the */ 2281 /* packet's destination. */ 2282 /* ------------------------------------------------------------- */ 2283 if ((np != NULL) && (np->in_apr != NULL)) { 2284 i = appr_check(fin, nat); 2285 if (i == 0) 2286 i = 1; 2287 } else 2288 i = 1; 2289 ATOMIC_INCL(ifs->ifs_nat_stats.ns_mapped[1]); 2290 fin->fin_flx |= FI_NATED; 2291 return i; 2292 } 2293 2294 2295 /* ------------------------------------------------------------------------ */ 2296 /* Function: fr_checknat6in */ 2297 /* Returns: int - -1 == packet failed NAT checks so block it, */ 2298 /* 0 == no packet translation occurred, */ 2299 /* 1 == packet was successfully translated. */ 2300 /* Parameters: fin(I) - pointer to packet information */ 2301 /* passp(I) - pointer to filtering result flags */ 2302 /* */ 2303 /* Check to see if an incoming packet should be changed. ICMP packets are */ 2304 /* first checked to see if they match an existing entry (if an error), */ 2305 /* otherwise a search of the current NAT table is made. If neither results */ 2306 /* in a match then a search for a matching NAT rule is made. Create a new */ 2307 /* NAT entry if a we matched a NAT rule. Lastly, actually change the */ 2308 /* packet header(s) as required. */ 2309 /* ------------------------------------------------------------------------ */ 2310 int fr_checknat6in(fin, passp) 2311 fr_info_t *fin; 2312 u_32_t *passp; 2313 { 2314 u_int nflags, natadd; 2315 int rval, natfailed; 2316 struct ifnet *ifp; 2317 struct icmp6_hdr *icmp6; 2318 tcphdr_t *tcp; 2319 u_short dport; 2320 ipnat_t *np; 2321 nat_t *nat; 2322 i6addr_t ipa, iph; 2323 ipf_stack_t *ifs = fin->fin_ifs; 2324 2325 if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0) 2326 return 0; 2327 2328 tcp = NULL; 2329 icmp6 = NULL; 2330 dport = 0; 2331 natadd = 1; 2332 nflags = 0; 2333 natfailed = 0; 2334 ifp = fin->fin_ifp; 2335 2336 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 2337 switch (fin->fin_p) 2338 { 2339 case IPPROTO_TCP : 2340 nflags = IPN_TCP; 2341 break; 2342 case IPPROTO_UDP : 2343 nflags = IPN_UDP; 2344 break; 2345 case IPPROTO_ICMPV6 : 2346 icmp6 = fin->fin_dp; 2347 2348 /* 2349 * This is an incoming packet, so the destination is 2350 * the icmp_id and the source port equals 0 2351 */ 2352 if ((fin->fin_flx & FI_ICMPQUERY) != 0) { 2353 nflags = IPN_ICMPQUERY; 2354 dport = icmp6->icmp6_id; 2355 } break; 2356 default : 2357 break; 2358 } 2359 2360 if ((nflags & IPN_TCPUDP)) { 2361 tcp = fin->fin_dp; 2362 dport = tcp->th_dport; 2363 } 2364 } 2365 2366 ipa = fin->fin_dst6; 2367 2368 READ_ENTER(&ifs->ifs_ipf_nat); 2369 2370 if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) && 2371 (nat = nat6_icmperror(fin, &nflags, NAT_INBOUND))) 2372 /*EMPTY*/; 2373 else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) 2374 natadd = 0; 2375 else if ((nat = nat6_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, 2376 &fin->fin_src6.in6, &ipa.in6))) { 2377 nflags = nat->nat_flags; 2378 } else { 2379 u_32_t hv, rmsk; 2380 i6addr_t msk; 2381 int i; 2382 2383 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 2384 i = 3; 2385 msk.i6[0] = 0xffffffff; 2386 msk.i6[1] = 0xffffffff; 2387 msk.i6[2] = 0xffffffff; 2388 msk.i6[3] = 0xffffffff; 2389 rmsk = ifs->ifs_rdr6_masks[3]; 2390 WRITE_ENTER(&ifs->ifs_ipf_nat); 2391 /* 2392 * If there is no current entry in the nat table for this IP#, 2393 * create one for it (if there is a matching rule). 2394 */ 2395 maskloop: 2396 IP6_AND(&ipa, &msk, &iph); 2397 hv = NAT_HASH_FN6(&iph, 0, ifs->ifs_ipf_rdrrules_sz); 2398 for (np = ifs->ifs_rdr_rules[hv]; np; np = np->in_rnext) { 2399 if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) 2400 continue; 2401 if (np->in_v != fin->fin_v) 2402 continue; 2403 if (np->in_p && (np->in_p != fin->fin_p)) 2404 continue; 2405 if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) 2406 continue; 2407 if (np->in_flags & IPN_FILTER) { 2408 if (!nat6_match(fin, np)) 2409 continue; 2410 } else { 2411 if (!IP6_MASKEQ(&ipa, &np->in_out[1], 2412 &np->in_out[0])) 2413 continue; 2414 if (np->in_pmin && 2415 ((ntohs(np->in_pmax) < ntohs(dport)) || 2416 (ntohs(dport) < ntohs(np->in_pmin)))) 2417 continue; 2418 } 2419 2420 #ifdef IPF_V6_PROXIES 2421 if (*np->in_plabel != '\0') { 2422 if (!appr_ok(fin, tcp, np)) { 2423 continue; 2424 } 2425 } 2426 #endif 2427 2428 nat = nat6_new(fin, np, NULL, nflags, NAT_INBOUND); 2429 if (nat != NULL) { 2430 np->in_hits++; 2431 break; 2432 } else 2433 natfailed = -1; 2434 } 2435 2436 if ((np == NULL) && (i >= 0)) { 2437 while (i >= 0) { 2438 while (rmsk) { 2439 msk.i6[i] = htonl(ntohl(msk.i6[i])<<1); 2440 if ((rmsk & 0x80000000) != 0) { 2441 rmsk <<= 1; 2442 goto maskloop; 2443 } 2444 rmsk <<= 1; 2445 } 2446 msk.i6[i--] = 0; 2447 if (i >= 0) { 2448 rmsk = ifs->ifs_rdr6_masks[i]; 2449 if (rmsk != 0) 2450 goto maskloop; 2451 } 2452 } 2453 } 2454 MUTEX_DOWNGRADE(&ifs->ifs_ipf_nat); 2455 } 2456 if (nat != NULL) { 2457 rval = fr_nat6in(fin, nat, natadd, nflags); 2458 if (rval == 1) { 2459 MUTEX_ENTER(&nat->nat_lock); 2460 nat->nat_ref++; 2461 MUTEX_EXIT(&nat->nat_lock); 2462 nat->nat_touched = ifs->ifs_fr_ticks; 2463 fin->fin_nat = nat; 2464 fin->fin_state = nat->nat_state; 2465 } 2466 } else 2467 rval = natfailed; 2468 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 2469 2470 if (rval == -1) { 2471 if (passp != NULL) 2472 *passp = FR_BLOCK; 2473 fin->fin_flx |= FI_BADNAT; 2474 } 2475 return rval; 2476 } 2477 2478 2479 /* ------------------------------------------------------------------------ */ 2480 /* Function: fr_nat6in */ 2481 /* Returns: int - -1 == packet failed NAT checks so block it, */ 2482 /* 1 == packet was successfully translated. */ 2483 /* Parameters: fin(I) - pointer to packet information */ 2484 /* nat(I) - pointer to NAT structure */ 2485 /* natadd(I) - flag indicating if it is safe to add frag cache */ 2486 /* nflags(I) - NAT flags set for this packet */ 2487 /* Locks Held: ipf_nat (READ) */ 2488 /* */ 2489 /* Translate a packet coming "in" on an interface. */ 2490 /* ------------------------------------------------------------------------ */ 2491 int fr_nat6in(fin, nat, natadd, nflags) 2492 fr_info_t *fin; 2493 nat_t *nat; 2494 int natadd; 2495 u_32_t nflags; 2496 { 2497 struct icmp6_hdr *icmp6; 2498 u_short *csump; 2499 tcphdr_t *tcp; 2500 ipnat_t *np; 2501 ipf_stack_t *ifs = fin->fin_ifs; 2502 2503 #if SOLARIS && defined(_KERNEL) 2504 net_data_t net_data_p = ifs->ifs_ipf_ipv6; 2505 #endif 2506 2507 tcp = NULL; 2508 csump = NULL; 2509 np = nat->nat_ptr; 2510 fin->fin_fr = nat->nat_fr; 2511 2512 if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) 2513 (void) fr_nat_newfrag(fin, 0, nat); 2514 2515 #ifdef IPF_V6_PROXIES 2516 if (np != NULL) { 2517 2518 /* ------------------------------------------------------------- */ 2519 /* A few quick notes: */ 2520 /* Following are test conditions prior to calling the */ 2521 /* appr_check routine. */ 2522 /* */ 2523 /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ 2524 /* with a map rule, we attempt to match the packet's */ 2525 /* source port against in_dport, otherwise we'd compare the */ 2526 /* packet's destination. */ 2527 /* ------------------------------------------------------------- */ 2528 if (np->in_apr != NULL) { 2529 i = appr_check(fin, nat); 2530 if (i == -1) { 2531 return -1; 2532 } 2533 } 2534 } 2535 #endif 2536 2537 #ifdef IPFILTER_SYNC 2538 ipfsync_update(SMC_NAT, fin, nat->nat_sync); 2539 #endif 2540 2541 MUTEX_ENTER(&nat->nat_lock); 2542 nat->nat_bytes[0] += fin->fin_plen; 2543 nat->nat_pkts[0]++; 2544 MUTEX_EXIT(&nat->nat_lock); 2545 2546 fin->fin_ip6->ip6_dst = nat->nat_inip6.in6; 2547 fin->fin_dst6 = nat->nat_inip6; 2548 2549 if (nflags & IPN_TCPUDP) 2550 tcp = fin->fin_dp; 2551 2552 if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { 2553 if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) { 2554 tcp->th_dport = nat->nat_inport; 2555 fin->fin_data[1] = ntohs(nat->nat_inport); 2556 } 2557 2558 2559 if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) { 2560 icmp6 = fin->fin_dp; 2561 2562 icmp6->icmp6_id = nat->nat_inport; 2563 } 2564 2565 csump = nat_proto(fin, nat, nflags); 2566 } 2567 2568 nat_update(fin, nat, np); 2569 2570 /* 2571 * In case they are being forwarded, inbound packets always need to have 2572 * their checksum adjusted even if hardware checksum validation said OK. 2573 */ 2574 if (csump != NULL) { 2575 if (nat->nat_dir == NAT_OUTBOUND) 2576 fix_incksum(csump, nat->nat_sumd[0]); 2577 else 2578 fix_outcksum(csump, nat->nat_sumd[0]); 2579 } 2580 2581 #if SOLARIS && defined(_KERNEL) 2582 if (nflags & IPN_TCPUDP && 2583 NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) { 2584 /* 2585 * Need to adjust the partial checksum result stored in 2586 * db_cksum16, which will be used for validation in IP. 2587 * See IP_CKSUM_RECV(). 2588 * Adjustment data should be the inverse of the IP address 2589 * changes, because db_cksum16 is supposed to be the complement 2590 * of the pesudo header. 2591 */ 2592 csump = &fin->fin_m->b_datap->db_cksum16; 2593 if (nat->nat_dir == NAT_OUTBOUND) 2594 fix_outcksum(csump, nat->nat_sumd[1]); 2595 else 2596 fix_incksum(csump, nat->nat_sumd[1]); 2597 } 2598 #endif 2599 2600 ATOMIC_INCL(ifs->ifs_nat_stats.ns_mapped[0]); 2601 fin->fin_flx |= FI_NATED; 2602 if (np != NULL && np->in_tag.ipt_num[0] != 0) 2603 fin->fin_nattag = &np->in_tag; 2604 return 1; 2605 } 2606 2607 2608 /* ------------------------------------------------------------------------ */ 2609 /* Function: nat_icmpquerytype6 */ 2610 /* Returns: int - 1 == success, 0 == failure */ 2611 /* Parameters: icmptype(I) - ICMP type number */ 2612 /* */ 2613 /* Tests to see if the ICMP type number passed is a query/response type or */ 2614 /* not. */ 2615 /* ------------------------------------------------------------------------ */ 2616 static INLINE int nat_icmpquerytype6(icmptype) 2617 int icmptype; 2618 { 2619 2620 /* 2621 * For the ICMP query NAT code, it is essential that both the query 2622 * and the reply match on the NAT rule. Because the NAT structure 2623 * does not keep track of the icmptype, and a single NAT structure 2624 * is used for all icmp types with the same src, dest and id, we 2625 * simply define the replies as queries as well. The funny thing is, 2626 * altough it seems silly to call a reply a query, this is exactly 2627 * as it is defined in the IPv4 specification 2628 */ 2629 2630 switch (icmptype) 2631 { 2632 2633 case ICMP6_ECHO_REPLY: 2634 case ICMP6_ECHO_REQUEST: 2635 /* route aedvertisement/solliciation is currently unsupported: */ 2636 /* it would require rewriting the ICMP data section */ 2637 case ICMP6_MEMBERSHIP_QUERY: 2638 case ICMP6_MEMBERSHIP_REPORT: 2639 case ICMP6_MEMBERSHIP_REDUCTION: 2640 case ICMP6_WRUREQUEST: 2641 case ICMP6_WRUREPLY: 2642 case MLD6_MTRACE_RESP: 2643 case MLD6_MTRACE: 2644 return 1; 2645 default: 2646 return 0; 2647 } 2648 } 2649