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