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