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