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