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