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