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