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