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