|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (C) 1995-1997 by Darren Reed. ! 24: * ! 25: * Redistribution and use in source and binary forms are permitted ! 26: * provided that this notice is preserved and due credit is given ! 27: * to the original author and the contributors. ! 28: * ! 29: * Added redirect stuff and a LOT of bug fixes. ([email protected]) ! 30: */ ! 31: #if !defined(lint) ! 32: /* static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; */ ! 33: #endif ! 34: ! 35: #include "opt_ipfilter.h" ! 36: #define __FreeBSD_version 300000 /* it's a hack, but close enough */ ! 37: ! 38: #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) ! 39: #define _KERNEL ! 40: #endif ! 41: ! 42: #if !defined(_KERNEL) && !defined(KERNEL) ! 43: # include <stdio.h> ! 44: # include <string.h> ! 45: # include <stdlib.h> ! 46: #endif ! 47: #include <sys/errno.h> ! 48: #include <sys/types.h> ! 49: #include <sys/param.h> ! 50: #include <sys/time.h> ! 51: #include <sys/file.h> ! 52: #if defined(KERNEL) && (__FreeBSD_version >= 220000) ! 53: # include <sys/filio.h> ! 54: # include <sys/fcntl.h> ! 55: #else ! 56: # include <sys/ioctl.h> ! 57: #endif ! 58: #include <sys/fcntl.h> ! 59: #include <sys/uio.h> ! 60: #ifndef linux ! 61: # include <sys/protosw.h> ! 62: #endif ! 63: #include <sys/socket.h> ! 64: #if defined(_KERNEL) && !defined(linux) ! 65: # include <sys/systm.h> ! 66: #endif ! 67: #if !defined(__SVR4) && !defined(__svr4__) ! 68: # ifndef linux ! 69: # include <sys/mbuf.h> ! 70: # endif ! 71: #else ! 72: # include <sys/filio.h> ! 73: # include <sys/byteorder.h> ! 74: # include <sys/dditypes.h> ! 75: # include <sys/stream.h> ! 76: # include <sys/kmem.h> ! 77: #endif ! 78: #if __FreeBSD_version >= 300000 ! 79: # include <sys/queue.h> ! 80: # include <sys/malloc.h> ! 81: #endif ! 82: #include <net/if.h> ! 83: #if __FreeBSD_version >= 300000 ! 84: # include <net/if_var.h> ! 85: #endif ! 86: #ifdef sun ! 87: #include <net/af.h> ! 88: #endif ! 89: #include <net/route.h> ! 90: #include <netinet/in.h> ! 91: #include <netinet/in_systm.h> ! 92: #include <netinet/ip.h> ! 93: ! 94: #ifdef __sgi ! 95: # ifdef IFF_DRVRLOCK /* IRIX6 */ ! 96: #include <sys/hashing.h> ! 97: #include <netinet/in_var.h> ! 98: # endif ! 99: #endif ! 100: ! 101: #if RFC1825 ! 102: #include <vpn/md5.h> ! 103: #include <vpn/ipsec.h> ! 104: extern struct ifnet vpnif; ! 105: #endif ! 106: ! 107: #ifndef linux ! 108: # include <netinet/ip_var.h> ! 109: #endif ! 110: #include <netinet/tcp.h> ! 111: #include <netinet/udp.h> ! 112: #include <netinet/ip_icmp.h> ! 113: #include "netinet/ip_compat.h" ! 114: #include <netinet/tcpip.h> ! 115: #include "netinet/ip_fil.h" ! 116: #include "netinet/ip_proxy.h" ! 117: #include "netinet/ip_nat.h" ! 118: #include "netinet/ip_frag.h" ! 119: #include "netinet/ip_state.h" ! 120: #ifndef MIN ! 121: #define MIN(a,b) (((a)<(b))?(a):(b)) ! 122: #endif ! 123: #undef SOCKADDR_IN ! 124: #define SOCKADDR_IN struct sockaddr_in ! 125: ! 126: nat_t *nat_table[2][NAT_SIZE], *nat_instances = NULL; ! 127: static ipnat_t *nat_list = NULL; ! 128: u_long fr_defnatage = 1200, /* 10 minutes (600 seconds) */ ! 129: fr_defnaticmpage = 6; /* 3 seconds */ ! 130: static natstat_t nat_stats; ! 131: #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) ! 132: extern kmutex_t ipf_nat; ! 133: #endif ! 134: ! 135: static int nat_flushtable __P((void)); ! 136: static int nat_clearlist __P((void)); ! 137: static void nat_delete __P((struct nat *)); ! 138: static int nat_ifpaddr __P((nat_t *, void *, struct in_addr *)); ! 139: ! 140: ! 141: #define LONG_SUM(in) (((in) & 0xffff) + ((in) >> 16)) ! 142: ! 143: #define CALC_SUMD(s1, s2, sd) { \ ! 144: /* Do it twice */ \ ! 145: (s1) = ((s1) & 0xffff) + ((s1) >> 16); \ ! 146: (s1) = ((s1) & 0xffff) + ((s1) >> 16); \ ! 147: /* Do it twice */ \ ! 148: (s2) = ((s2) & 0xffff) + ((s2) >> 16); \ ! 149: (s2) = ((s2) & 0xffff) + ((s2) >> 16); \ ! 150: /* Because ~1 == -2, We really need ~1 == -1 */ \ ! 151: if ((s1) > (s2)) (s2)--; \ ! 152: (sd) = (s2) - (s1); \ ! 153: (sd) = ((sd) & 0xffff) + ((sd) >> 16); } ! 154: ! 155: void fix_outcksum(sp, n) ! 156: u_short *sp; ! 157: u_32_t n; ! 158: { ! 159: register u_short sumshort; ! 160: register u_32_t sum1; ! 161: ! 162: if (!n) ! 163: return; ! 164: sum1 = (~ntohs(*sp)) & 0xffff; ! 165: sum1 += (n); ! 166: sum1 = (sum1 >> 16) + (sum1 & 0xffff); ! 167: /* Again */ ! 168: sum1 = (sum1 >> 16) + (sum1 & 0xffff); ! 169: sumshort = ~(u_short)sum1; ! 170: *(sp) = htons(sumshort); ! 171: } ! 172: ! 173: ! 174: void fix_incksum(sp, n) ! 175: u_short *sp; ! 176: u_32_t n; ! 177: { ! 178: register u_short sumshort; ! 179: register u_32_t sum1; ! 180: ! 181: if (!n) ! 182: return; ! 183: #if sparc ! 184: sum1 = (~(*sp)) & 0xffff; ! 185: #else ! 186: sum1 = (~ntohs(*sp)) & 0xffff; ! 187: #endif ! 188: sum1 += ~(n) & 0xffff; ! 189: sum1 = (sum1 >> 16) + (sum1 & 0xffff); ! 190: /* Again */ ! 191: sum1 = (sum1 >> 16) + (sum1 & 0xffff); ! 192: sumshort = ~(u_short)sum1; ! 193: *(sp) = htons(sumshort); ! 194: } ! 195: ! 196: ! 197: /* ! 198: * How the NAT is organised and works. ! 199: * ! 200: * Inside (interface y) NAT Outside (interface x) ! 201: * -------------------- -+- ------------------------------------- ! 202: * Packet going | out, processsed by ip_natout() for x ! 203: * ------------> | ------------> ! 204: * src=10.1.1.1 | src=192.1.1.1 ! 205: * | ! 206: * | in, processed by ip_natin() for x ! 207: * <------------ | <------------ ! 208: * dst=10.1.1.1 | dst=192.1.1.1 ! 209: * -------------------- -+- ------------------------------------- ! 210: * ip_natout() - changes ip_src and if required, sport ! 211: * - creates a new mapping, if required. ! 212: * ip_natin() - changes ip_dst and if required, dport ! 213: * ! 214: * In the NAT table, internal source is recorded as "in" and externally ! 215: * seen as "out". ! 216: */ ! 217: ! 218: /* ! 219: * Handle ioctls which manipulate the NAT. ! 220: */ ! 221: int nat_ioctl(data, cmd, mode) ! 222: #if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) ! 223: u_long cmd; ! 224: #else ! 225: int cmd; ! 226: #endif ! 227: caddr_t data; ! 228: int mode; ! 229: { ! 230: register ipnat_t *nat, *n = NULL, **np = NULL; ! 231: ipnat_t natd; ! 232: int error = 0, ret; ! 233: #if defined(_KERNEL) && !SOLARIS ! 234: int s; ! 235: #endif ! 236: ! 237: nat = NULL; /* XXX gcc -Wuninitialized */ ! 238: ! 239: /* ! 240: * For add/delete, look to see if the NAT entry is already present ! 241: */ ! 242: SPL_NET(s); ! 243: MUTEX_ENTER(&ipf_nat); ! 244: if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) { ! 245: IRCOPY(data, (char *)&natd, sizeof(natd)); ! 246: nat = &natd; ! 247: nat->in_inip &= nat->in_inmsk; ! 248: nat->in_outip &= nat->in_outmsk; ! 249: for (np = &nat_list; (n = *np); np = &n->in_next) ! 250: if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags, ! 251: IPN_CMPSIZ)) ! 252: break; ! 253: } ! 254: ! 255: switch (cmd) ! 256: { ! 257: case SIOCADNAT : ! 258: if (!(mode & FWRITE)) { ! 259: error = EPERM; ! 260: break; ! 261: } ! 262: if (n) { ! 263: error = EEXIST; ! 264: break; ! 265: } ! 266: KMALLOC(n, ipnat_t *, sizeof(*n)); ! 267: if (n == NULL) { ! 268: error = ENOMEM; ! 269: break; ! 270: } ! 271: bcopy((char *)nat, (char *)n, sizeof(*n)); ! 272: n->in_ifp = (void *)GETUNIT(n->in_ifname); ! 273: if (!n->in_ifp) ! 274: n->in_ifp = (void *)-1; ! 275: n->in_apr = ap_match(n->in_p, n->in_plabel); ! 276: n->in_next = *np; ! 277: n->in_use = 0; ! 278: n->in_space = ~(0xffffffff & ntohl(n->in_outmsk)); ! 279: if (n->in_space) /* lose 2: broadcast + network address */ ! 280: n->in_space -= 2; ! 281: else ! 282: n->in_space = 1; /* single IP# mapping */ ! 283: if ((n->in_outmsk != 0xffffffff) && n->in_outmsk) ! 284: n->in_nip = ntohl(n->in_outip) + 1; ! 285: else ! 286: n->in_nip = ntohl(n->in_outip); ! 287: if (n->in_redir & NAT_MAP) { ! 288: n->in_pnext = ntohs(n->in_pmin); ! 289: /* ! 290: * Multiply by the number of ports made available. ! 291: */ ! 292: if (ntohs(n->in_pmax) > ntohs(n->in_pmin)) ! 293: n->in_space *= (ntohs(n->in_pmax) - ! 294: ntohs(n->in_pmin)); ! 295: } ! 296: /* Otherwise, these fields are preset */ ! 297: *np = n; ! 298: nat_stats.ns_rules++; ! 299: break; ! 300: case SIOCRMNAT : ! 301: if (!(mode & FWRITE)) { ! 302: error = EPERM; ! 303: break; ! 304: } ! 305: if (!n) { ! 306: error = ESRCH; ! 307: break; ! 308: } ! 309: *np = n->in_next; ! 310: if (!n->in_use) { ! 311: if (n->in_apr) ! 312: ap_free(n->in_apr); ! 313: KFREE(n); ! 314: nat_stats.ns_rules--; ! 315: } else { ! 316: n->in_flags |= IPN_DELETE; ! 317: n->in_next = NULL; ! 318: } ! 319: break; ! 320: case SIOCGNATS : ! 321: nat_stats.ns_table[0] = nat_table[0]; ! 322: nat_stats.ns_table[1] = nat_table[1]; ! 323: nat_stats.ns_list = nat_list; ! 324: IWCOPY((char *)&nat_stats, (char *)data, sizeof(nat_stats)); ! 325: break; ! 326: case SIOCGNATL : ! 327: { ! 328: natlookup_t nl; ! 329: ! 330: IRCOPY((char *)data, (char *)&nl, sizeof(nl)); ! 331: ! 332: if (nat_lookupredir(&nl)) { ! 333: IWCOPY((char *)&nl, (char *)data, sizeof(nl)); ! 334: } else ! 335: error = ESRCH; ! 336: break; ! 337: } ! 338: case SIOCFLNAT : ! 339: if (!(mode & FWRITE)) { ! 340: error = EPERM; ! 341: break; ! 342: } ! 343: ret = nat_flushtable(); ! 344: (void) ap_unload(); ! 345: IWCOPY((caddr_t)&ret, data, sizeof(ret)); ! 346: break; ! 347: case SIOCCNATL : ! 348: if (!(mode & FWRITE)) { ! 349: error = EPERM; ! 350: break; ! 351: } ! 352: ret = nat_clearlist(); ! 353: IWCOPY((caddr_t)&ret, data, sizeof(ret)); ! 354: break; ! 355: case FIONREAD : ! 356: #if IPFILTER_LOG ! 357: IWCOPY((caddr_t)&iplused[IPL_LOGNAT], (caddr_t)data, ! 358: sizeof(iplused[IPL_LOGNAT])); ! 359: #endif ! 360: break; ! 361: } ! 362: MUTEX_EXIT(&ipf_nat); ! 363: SPL_X(s); ! 364: return error; ! 365: } ! 366: ! 367: ! 368: /* ! 369: * Delete a nat entry from the various lists and table. ! 370: */ ! 371: static void nat_delete(natd) ! 372: struct nat *natd; ! 373: { ! 374: register struct nat **natp, *nat; ! 375: struct ipnat *ipn; ! 376: ! 377: for (natp = natd->nat_hstart[0]; (nat = *natp); ! 378: natp = &nat->nat_hnext[0]) ! 379: if (nat == natd) { ! 380: *natp = nat->nat_hnext[0]; ! 381: break; ! 382: } ! 383: ! 384: for (natp = natd->nat_hstart[1]; (nat = *natp); ! 385: natp = &nat->nat_hnext[1]) ! 386: if (nat == natd) { ! 387: *natp = nat->nat_hnext[1]; ! 388: break; ! 389: } ! 390: ! 391: /* ! 392: * If there is an active reference from the nat entry to its parent ! 393: * rule, decrement the rule's reference count and free it too if no ! 394: * longer being used. ! 395: */ ! 396: if ((ipn = natd->nat_ptr)) { ! 397: ipn->in_space++; ! 398: ipn->in_use--; ! 399: if (!ipn->in_use && (ipn->in_flags & IPN_DELETE)) { ! 400: if (ipn->in_apr) ! 401: ap_free(ipn->in_apr); ! 402: KFREE(ipn); ! 403: nat_stats.ns_rules--; ! 404: } ! 405: } ! 406: ! 407: /* ! 408: * If there's a fragment table entry too for this nat entry, then ! 409: * dereference that as well. ! 410: */ ! 411: ipfr_forget((void *)natd); ! 412: KFREE(natd); ! 413: } ! 414: ! 415: ! 416: /* ! 417: * nat_flushtable - clear the NAT table of all mapping entries. ! 418: */ ! 419: static int nat_flushtable() ! 420: { ! 421: register nat_t *nat, **natp; ! 422: register int j = 0; ! 423: ! 424: /* ! 425: * Everything will be deleted, so lets just make it the deletions ! 426: * quicker. ! 427: */ ! 428: bzero((char *)nat_table[0], sizeof(nat_table[0])); ! 429: bzero((char *)nat_table[1], sizeof(nat_table[1])); ! 430: ! 431: for (natp = &nat_instances; (nat = *natp); ) { ! 432: *natp = nat->nat_next; ! 433: nat_delete(nat); ! 434: j++; ! 435: } ! 436: ! 437: return j; ! 438: } ! 439: ! 440: ! 441: /* ! 442: * nat_clearlist - delete all entries in the active NAT mapping list. ! 443: */ ! 444: static int nat_clearlist() ! 445: { ! 446: register ipnat_t *n, **np = &nat_list; ! 447: int i = 0; ! 448: ! 449: while ((n = *np)) { ! 450: *np = n->in_next; ! 451: if (!n->in_use) { ! 452: if (n->in_apr) ! 453: ap_free(n->in_apr); ! 454: KFREE(n); ! 455: nat_stats.ns_rules--; ! 456: i++; ! 457: } else { ! 458: n->in_flags |= IPN_DELETE; ! 459: n->in_next = NULL; ! 460: } ! 461: } ! 462: nat_stats.ns_inuse = 0; ! 463: return i; ! 464: } ! 465: ! 466: ! 467: /* ! 468: * return the first IP Address associated with an interface ! 469: */ ! 470: static int nat_ifpaddr(nat, ifptr, inp) ! 471: nat_t *nat; ! 472: void *ifptr; ! 473: struct in_addr *inp; ! 474: { ! 475: #if SOLARIS ! 476: ill_t *ill = ifptr; ! 477: #else ! 478: struct ifnet *ifp = ifptr; ! 479: #endif ! 480: struct in_addr in; ! 481: ! 482: #if SOLARIS ! 483: in.s_addr = ntohl(ill->ill_ipif->ipif_local_addr); ! 484: #else /* SOLARIS */ ! 485: # if linux ! 486: ; ! 487: # else /* linux */ ! 488: struct ifaddr *ifa; ! 489: struct sockaddr_in *sin; ! 490: ! 491: # if (__FreeBSD_version >= 300000) ! 492: ifa = TAILQ_FIRST(&ifp->if_addrhead); ! 493: # else ! 494: # if defined(__NetBSD__) || defined(__OpenBSD__) ! 495: ifa = ifp->if_addrlist.tqh_first; ! 496: # else ! 497: # if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ ! 498: ifa = &((struct in_ifaddr *)ifp->in_ifaddr)->ia_ifa; ! 499: # else ! 500: ifa = ifp->if_addrlist; ! 501: # endif ! 502: # endif /* __NetBSD__ || __OpenBSD__ */ ! 503: # endif /* __FreeBSD_version >= 300000 */ ! 504: # if (BSD < 199306) && !(/*IRIX6*/defined(__sgi) && defined(IFF_DRVRLOCK)) ! 505: sin = (SOCKADDR_IN *)&ifa->ifa_addr; ! 506: # else ! 507: sin = (SOCKADDR_IN *)ifa->ifa_addr; ! 508: while (sin && ifa && ! 509: sin->sin_family != AF_INET) { ! 510: # if (__FreeBSD_version >= 300000) ! 511: ifa = TAILQ_NEXT(ifa, ifa_link); ! 512: # else ! 513: # if defined(__NetBSD__) || defined(__OpenBSD__) ! 514: ifa = ifa->ifa_list.tqe_next; ! 515: # else ! 516: ifa = ifa->ifa_next; ! 517: # endif ! 518: # endif /* __FreeBSD_version >= 300000 */ ! 519: if (ifa) ! 520: sin = (SOCKADDR_IN *)ifa->ifa_addr; ! 521: } ! 522: if (!ifa) ! 523: sin = NULL; ! 524: if (!sin) { ! 525: KFREE(nat); ! 526: return -1; ! 527: } ! 528: # endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */ ! 529: in = sin->sin_addr; ! 530: in.s_addr = ntohl(in.s_addr); ! 531: # endif /* linux */ ! 532: #endif /* SOLARIS */ ! 533: *inp = in; ! 534: return 0; ! 535: } ! 536: ! 537: ! 538: /* ! 539: * Create a new NAT table entry. ! 540: */ ! 541: nat_t *nat_new(np, ip, fin, flags, direction) ! 542: ipnat_t *np; ! 543: ip_t *ip; ! 544: fr_info_t *fin; ! 545: u_short flags; ! 546: int direction; ! 547: { ! 548: register u_32_t sum1, sum2, sumd, l; ! 549: u_short port = 0, sport = 0, dport = 0, nport = 0; ! 550: struct in_addr in; ! 551: tcphdr_t *tcp = NULL; ! 552: nat_t *nat, **natp; ! 553: u_short nflags; ! 554: ! 555: nflags = flags & np->in_flags; ! 556: if (flags & IPN_TCPUDP) { ! 557: tcp = (tcphdr_t *)fin->fin_dp; ! 558: sport = tcp->th_sport; ! 559: dport = tcp->th_dport; ! 560: } ! 561: ! 562: /* Give me a new nat */ ! 563: KMALLOC(nat, nat_t *, sizeof(*nat)); ! 564: if (nat == NULL) ! 565: return NULL; ! 566: ! 567: bzero((char *)nat, sizeof(*nat)); ! 568: nat->nat_flags = flags; ! 569: ! 570: /* ! 571: * Search the current table for a match. ! 572: */ ! 573: if (direction == NAT_OUTBOUND) { ! 574: /* ! 575: * If it's an outbound packet which doesn't match any existing ! 576: * record, then create a new port ! 577: */ ! 578: l = 0; ! 579: do { ! 580: l++; ! 581: port = 0; ! 582: in.s_addr = np->in_nip; ! 583: if (!in.s_addr && (np->in_outmsk == 0xffffffff)) { ! 584: if ((l > 1) || ! 585: nat_ifpaddr(nat, fin->fin_ifp, &in) == -1) { ! 586: KFREE(nat); ! 587: return NULL; ! 588: } ! 589: } else if (!in.s_addr && !np->in_outmsk) { ! 590: if (l > 1) { ! 591: KFREE(nat); ! 592: return NULL; ! 593: } ! 594: in.s_addr = ntohl(ip->ip_src.s_addr); ! 595: if (nflags & IPN_TCPUDP) ! 596: port = sport; ! 597: } else if (nflags & IPN_TCPUDP) { ! 598: port = htons(np->in_pnext++); ! 599: if (np->in_pnext >= ntohs(np->in_pmax)) { ! 600: np->in_pnext = ntohs(np->in_pmin); ! 601: np->in_space--; ! 602: if (np->in_outmsk != 0xffffffff) ! 603: np->in_nip++; ! 604: } ! 605: } else if (np->in_outmsk != 0xffffffff) { ! 606: np->in_space--; ! 607: np->in_nip++; ! 608: } ! 609: ! 610: if (!port && (flags & IPN_TCPUDP)) ! 611: port = sport; ! 612: if ((np->in_nip & ntohl(np->in_outmsk)) > ! 613: ntohl(np->in_outip)) ! 614: np->in_nip = ntohl(np->in_outip) + 1; ! 615: } while (nat_inlookup(fin->fin_ifp, flags, ip->ip_dst, ! 616: dport, in, port)); ! 617: ! 618: /* Setup the NAT table */ ! 619: nat->nat_inip = ip->ip_src; ! 620: nat->nat_outip.s_addr = htonl(in.s_addr); ! 621: nat->nat_oip = ip->ip_dst; ! 622: ! 623: sum1 = (ntohl(ip->ip_src.s_addr) & 0xffff) + ! 624: (ntohl(ip->ip_src.s_addr) >> 16) + ntohs(sport); ! 625: ! 626: sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(port); ! 627: ! 628: if (flags & IPN_TCPUDP) { ! 629: nat->nat_inport = sport; ! 630: nat->nat_outport = port; ! 631: nat->nat_oport = dport; ! 632: } ! 633: } else { ! 634: ! 635: /* ! 636: * Otherwise, it's an inbound packet. Most likely, we don't ! 637: * want to rewrite source ports and source addresses. Instead, ! 638: * we want to rewrite to a fixed internal address and fixed ! 639: * internal port. ! 640: */ ! 641: in.s_addr = ntohl(np->in_inip); ! 642: if (!(nport = np->in_pnext)) ! 643: nport = dport; ! 644: ! 645: nat->nat_inip.s_addr = htonl(in.s_addr); ! 646: nat->nat_outip = ip->ip_dst; ! 647: nat->nat_oip = ip->ip_src; ! 648: ! 649: sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) + ! 650: (ntohl(ip->ip_dst.s_addr) >> 16) + ntohs(dport); ! 651: ! 652: sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(nport); ! 653: ! 654: if (flags & IPN_TCPUDP) { ! 655: nat->nat_inport = nport; ! 656: nat->nat_outport = dport; ! 657: nat->nat_oport = sport; ! 658: } ! 659: } ! 660: ! 661: /* Do it twice */ ! 662: sum1 = (sum1 & 0xffff) + (sum1 >> 16); ! 663: sum1 = (sum1 & 0xffff) + (sum1 >> 16); ! 664: ! 665: /* Do it twice */ ! 666: sum2 = (sum2 & 0xffff) + (sum2 >> 16); ! 667: sum2 = (sum2 & 0xffff) + (sum2 >> 16); ! 668: ! 669: if (sum1 > sum2) ! 670: sum2--; /* Because ~1 == -2, We really need ~1 == -1 */ ! 671: sumd = sum2 - sum1; ! 672: sumd = (sumd & 0xffff) + (sumd >> 16); ! 673: nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16); ! 674: ! 675: if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) { ! 676: if (direction == NAT_OUTBOUND) ! 677: sum1 = (ntohl(ip->ip_src.s_addr) & 0xffff) + ! 678: (ntohl(ip->ip_src.s_addr) >> 16); ! 679: else ! 680: sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) + ! 681: (ntohl(ip->ip_dst.s_addr) >> 16); ! 682: ! 683: sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16); ! 684: ! 685: /* Do it twice */ ! 686: sum1 = (sum1 & 0xffff) + (sum1 >> 16); ! 687: sum1 = (sum1 & 0xffff) + (sum1 >> 16); ! 688: ! 689: /* Do it twice */ ! 690: sum2 = (sum2 & 0xffff) + (sum2 >> 16); ! 691: sum2 = (sum2 & 0xffff) + (sum2 >> 16); ! 692: ! 693: if (sum1 > sum2) ! 694: sum2--; /* Because ~1 == -2, We really need ~1 == -1 */ ! 695: sumd = sum2 - sum1; ! 696: sumd = (sumd & 0xffff) + (sumd >> 16); ! 697: nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); ! 698: } else ! 699: nat->nat_ipsumd = nat->nat_sumd; ! 700: ! 701: in.s_addr = htonl(in.s_addr); ! 702: nat->nat_next = nat_instances; ! 703: nat_instances = nat; ! 704: natp = &nat_table[0][nat->nat_inip.s_addr % NAT_SIZE]; ! 705: nat->nat_hstart[0] = natp; ! 706: nat->nat_hnext[0] = *natp; ! 707: *natp = nat; ! 708: natp = &nat_table[1][nat->nat_outip.s_addr % NAT_SIZE]; ! 709: nat->nat_hstart[1] = natp; ! 710: nat->nat_hnext[1] = *natp; ! 711: *natp = nat; ! 712: nat->nat_ptr = np; ! 713: nat->nat_bytes = 0; ! 714: nat->nat_pkts = 0; ! 715: nat->nat_ifp = fin->fin_ifp; ! 716: nat->nat_dir = direction; ! 717: if (direction == NAT_OUTBOUND) { ! 718: if (flags & IPN_TCPUDP) ! 719: tcp->th_sport = port; ! 720: } else { ! 721: if (flags & IPN_TCPUDP) ! 722: tcp->th_dport = nport; ! 723: } ! 724: nat_stats.ns_added++; ! 725: nat_stats.ns_inuse++; ! 726: np->in_use++; ! 727: return nat; ! 728: } ! 729: ! 730: ! 731: nat_t *nat_icmpinlookup(ip, fin) ! 732: ip_t *ip; ! 733: fr_info_t *fin; ! 734: { ! 735: icmphdr_t *icmp; ! 736: tcphdr_t *tcp = NULL; ! 737: ip_t *oip; ! 738: int flags = 0, type; ! 739: ! 740: icmp = (icmphdr_t *)fin->fin_dp; ! 741: /* ! 742: * Does it at least have the return (basic) IP header ? ! 743: * Only a basic IP header (no options) should be with an ICMP error ! 744: * header. ! 745: */ ! 746: if ((ip->ip_hl != 5) || (ip->ip_len < sizeof(*icmp) + sizeof(ip_t))) ! 747: return NULL; ! 748: type = icmp->icmp_type; ! 749: /* ! 750: * If it's not an error type, then return. ! 751: */ ! 752: if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) && ! 753: (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) && ! 754: (type != ICMP_PARAMPROB)) ! 755: return NULL; ! 756: ! 757: oip = (ip_t *)((char *)fin->fin_dp + 8); ! 758: if (oip->ip_p == IPPROTO_TCP) ! 759: flags = IPN_TCP; ! 760: else if (oip->ip_p == IPPROTO_UDP) ! 761: flags = IPN_UDP; ! 762: if (flags & IPN_TCPUDP) { ! 763: tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2)); ! 764: return nat_inlookup(fin->fin_ifp, flags, oip->ip_dst, ! 765: tcp->th_dport, oip->ip_src, tcp->th_sport); ! 766: } ! 767: return nat_inlookup(fin->fin_ifp, 0, oip->ip_src, 0, oip->ip_dst, 0); ! 768: } ! 769: ! 770: ! 771: /* ! 772: * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP ! 773: * packet gets correctly recognised. ! 774: */ ! 775: nat_t *nat_icmpin(ip, fin, nflags) ! 776: ip_t *ip; ! 777: fr_info_t *fin; ! 778: int *nflags; ! 779: { ! 780: icmphdr_t *icmp; ! 781: nat_t *nat; ! 782: ip_t *oip; ! 783: int flags = 0; ! 784: ! 785: if (!(nat = nat_icmpinlookup(ip, fin))) ! 786: return NULL; ! 787: ! 788: *nflags = IPN_ICMPERR; ! 789: icmp = (icmphdr_t *)fin->fin_dp; ! 790: oip = (ip_t *)((char *)icmp + 8); ! 791: if (oip->ip_p == IPPROTO_TCP) ! 792: flags = IPN_TCP; ! 793: else if (oip->ip_p == IPPROTO_UDP) ! 794: flags = IPN_UDP; ! 795: /* ! 796: * Need to adjust ICMP header to include the real IP#'s and ! 797: * port #'s. Only apply a checksum change relative to the ! 798: * IP address change is it will be modified again in ip_natout ! 799: * for both address and port. Two checksum changes are ! 800: * necessary for the two header address changes. Be careful ! 801: * to only modify the checksum once for the port # and twice ! 802: * for the IP#. ! 803: */ ! 804: if (flags & IPN_TCPUDP) { ! 805: tcphdr_t *tcp = (tcphdr_t *)(oip + 1); ! 806: u_32_t sum1, sum2, sumd; ! 807: struct in_addr in; ! 808: ! 809: if (nat->nat_dir == NAT_OUTBOUND) { ! 810: sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); ! 811: in = nat->nat_outip; ! 812: oip->ip_src = in; ! 813: tcp->th_sport = nat->nat_outport; ! 814: } else { ! 815: sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr)); ! 816: in = nat->nat_inip; ! 817: oip->ip_dst = in; ! 818: tcp->th_dport = nat->nat_inport; ! 819: } ! 820: ! 821: sum2 = LONG_SUM(in.s_addr); ! 822: ! 823: CALC_SUMD(sum1, sum2, sumd); ! 824: sumd = (sumd & 0xffff) + (sumd >> 16); ! 825: ! 826: if (nat->nat_dir == NAT_OUTBOUND) { ! 827: fix_incksum(&oip->ip_sum, sumd); ! 828: fix_incksum(&icmp->icmp_cksum, sumd); ! 829: } else { ! 830: fix_outcksum(&oip->ip_sum, sumd); ! 831: fix_outcksum(&icmp->icmp_cksum, sumd); ! 832: } ! 833: ! 834: /* ! 835: * TCP checksum doesn't make it into the 1st eight ! 836: * bytes but UDP does. ! 837: */ ! 838: if (ip->ip_p == IPPROTO_UDP) { ! 839: udphdr_t *udp = (udphdr_t *)tcp; ! 840: ! 841: if (udp->uh_sum) { ! 842: if (nat->nat_dir == NAT_OUTBOUND) ! 843: fix_incksum(&udp->uh_sum, ! 844: nat->nat_sumd); ! 845: else ! 846: fix_outcksum(&udp->uh_sum, ! 847: nat->nat_sumd); ! 848: } ! 849: } ! 850: } else ! 851: ip->ip_dst = nat->nat_outip; ! 852: nat->nat_age = fr_defnaticmpage; ! 853: return nat; ! 854: } ! 855: ! 856: ! 857: /* ! 858: * NB: these lookups don't lock access to the list, it assume it has already ! 859: * been done! ! 860: */ ! 861: /* ! 862: * Lookup a nat entry based on the mapped destination ip address/port and ! 863: * real source address/port. We use this lookup when receiving a packet, ! 864: * we're looking for a table entry, based on the destination address. ! 865: * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. ! 866: */ ! 867: #ifdef __STDC__ ! 868: nat_t *nat_inlookup(void *ifp, int flags, struct in_addr src, u_short sport, struct in_addr mapdst, u_short mapdport) ! 869: #else ! 870: nat_t *nat_inlookup(ifp, flags, src, sport, mapdst, mapdport) ! 871: void *ifp; ! 872: register int flags; ! 873: struct in_addr src , mapdst; ! 874: u_short sport, mapdport; ! 875: #endif ! 876: { ! 877: register nat_t *nat; ! 878: ! 879: flags &= IPN_TCPUDP; ! 880: ! 881: nat = nat_table[1][mapdst.s_addr % NAT_SIZE]; ! 882: for (; nat; nat = nat->nat_hnext[1]) ! 883: if ((!ifp || ifp == nat->nat_ifp) && ! 884: nat->nat_oip.s_addr == src.s_addr && ! 885: nat->nat_outip.s_addr == mapdst.s_addr && ! 886: flags == nat->nat_flags && (!flags || ! 887: (nat->nat_oport == sport && ! 888: nat->nat_outport == mapdport))) ! 889: return nat; ! 890: return NULL; ! 891: } ! 892: ! 893: ! 894: /* ! 895: * Lookup a nat entry based on the source 'real' ip address/port and ! 896: * destination address/port. We use this lookup when sending a packet out, ! 897: * we're looking for a table entry, based on the source address. ! 898: * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. ! 899: */ ! 900: #ifdef __STDC__ ! 901: nat_t *nat_outlookup(void *ifp, int flags, struct in_addr src, u_short sport, struct in_addr dst, u_short dport) ! 902: #else ! 903: nat_t *nat_outlookup(ifp, flags, src, sport, dst, dport) ! 904: void *ifp; ! 905: register int flags; ! 906: struct in_addr src , dst; ! 907: u_short sport, dport; ! 908: #endif ! 909: { ! 910: register nat_t *nat; ! 911: ! 912: flags &= IPN_TCPUDP; ! 913: ! 914: nat = nat_table[0][src.s_addr % NAT_SIZE]; ! 915: for (; nat; nat = nat->nat_hnext[0]) { ! 916: if ((!ifp || ifp == nat->nat_ifp) && ! 917: nat->nat_inip.s_addr == src.s_addr && ! 918: nat->nat_oip.s_addr == dst.s_addr && ! 919: flags == nat->nat_flags && (!flags || ! 920: (nat->nat_inport == sport && nat->nat_oport == dport))) ! 921: return nat; ! 922: } ! 923: return NULL; ! 924: } ! 925: ! 926: ! 927: /* ! 928: * Lookup a nat entry based on the mapped source ip address/port and ! 929: * real destination address/port. We use this lookup when sending a packet ! 930: * out, we're looking for a table entry, based on the source address. ! 931: */ ! 932: #ifdef __STDC__ ! 933: nat_t *nat_lookupmapip(void *ifp, int flags, struct in_addr mapsrc, u_short mapsport, struct in_addr dst, u_short dport) ! 934: #else ! 935: nat_t *nat_lookupmapip(ifp, flags, mapsrc, mapsport, dst, dport) ! 936: void *ifp; ! 937: register int flags; ! 938: struct in_addr mapsrc , dst; ! 939: u_short mapsport, dport; ! 940: #endif ! 941: { ! 942: register nat_t *nat; ! 943: ! 944: flags &= IPN_TCPUDP; ! 945: ! 946: nat = nat_table[1][mapsrc.s_addr % NAT_SIZE]; ! 947: for (; nat; nat = nat->nat_hnext[0]) ! 948: if ((!ifp || ifp == nat->nat_ifp) && ! 949: nat->nat_oip.s_addr == dst.s_addr && ! 950: nat->nat_outip.s_addr == mapsrc.s_addr && ! 951: flags == nat->nat_flags && (!flags || ! 952: (nat->nat_outport == mapsport && ! 953: nat->nat_oport == dport))) ! 954: return nat; ! 955: return NULL; ! 956: } ! 957: ! 958: ! 959: /* ! 960: * Lookup the NAT tables to search for a matching redirect ! 961: */ ! 962: nat_t *nat_lookupredir(np) ! 963: register natlookup_t *np; ! 964: { ! 965: nat_t *nat; ! 966: ! 967: /* ! 968: * If nl_inip is non null, this is a lookup based on the real ! 969: * ip address. Else, we use the fake. ! 970: */ ! 971: if ((nat = nat_outlookup(NULL, np->nl_flags, np->nl_inip, ! 972: np->nl_inport, np->nl_outip, ! 973: np->nl_outport))) { ! 974: np->nl_realip = nat->nat_outip; ! 975: np->nl_realport = nat->nat_outport; ! 976: } ! 977: return nat; ! 978: } ! 979: ! 980: ! 981: /* ! 982: * Packets going out on the external interface go through this. ! 983: * Here, the source address requires alteration, if anything. ! 984: */ ! 985: int ip_natout(ip, hlen, fin) ! 986: ip_t *ip; ! 987: int hlen; ! 988: fr_info_t *fin; ! 989: { ! 990: register ipnat_t *np; ! 991: register u_32_t ipa; ! 992: tcphdr_t *tcp = NULL; ! 993: u_short nflags = 0, sport = 0, dport = 0, *csump = NULL; ! 994: struct ifnet *ifp; ! 995: frentry_t *fr; ! 996: nat_t *nat; ! 997: int natadd = 1; ! 998: ! 999: if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) && ! 1000: fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) ! 1001: ifp = fr->fr_tif.fd_ifp; ! 1002: else ! 1003: ifp = fin->fin_ifp; ! 1004: ! 1005: if (!(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) { ! 1006: if (ip->ip_p == IPPROTO_TCP) ! 1007: nflags = IPN_TCP; ! 1008: else if (ip->ip_p == IPPROTO_UDP) ! 1009: nflags = IPN_UDP; ! 1010: if (nflags) { ! 1011: tcp = (tcphdr_t *)fin->fin_dp; ! 1012: sport = tcp->th_sport; ! 1013: dport = tcp->th_dport; ! 1014: } ! 1015: } ! 1016: ! 1017: ipa = ip->ip_src.s_addr; ! 1018: ! 1019: MUTEX_ENTER(&ipf_nat); ! 1020: if ((ip->ip_off & (IP_OFFMASK|IP_MF)) && ! 1021: (nat = ipfr_nat_knownfrag(ip, fin))) ! 1022: natadd = 0; ! 1023: else if ((nat = nat_outlookup(ifp, nflags, ip->ip_src, sport, ! 1024: ip->ip_dst, dport))) ! 1025: ; ! 1026: else ! 1027: /* ! 1028: * If there is no current entry in the nat table for this IP#, ! 1029: * create one for it (if there is a matching rule). ! 1030: */ ! 1031: for (np = nat_list; np; np = np->in_next) ! 1032: if ((np->in_ifp == ifp) && np->in_space && ! 1033: (!np->in_flags || (np->in_flags & nflags)) && ! 1034: ((ipa & np->in_inmsk) == np->in_inip) && ! 1035: ((np->in_redir & NAT_MAP) || ! 1036: (np->in_pnext == sport))) { ! 1037: if (*np->in_plabel && !ap_ok(ip, tcp, np)) ! 1038: continue; ! 1039: /* ! 1040: * If it's a redirection, then we don't want to ! 1041: * create new outgoing port stuff. ! 1042: * Redirections are only for incoming ! 1043: * connections. ! 1044: */ ! 1045: if (!(np->in_redir & NAT_MAP)) ! 1046: continue; ! 1047: if ((nat = nat_new(np, ip, fin, nflags, ! 1048: NAT_OUTBOUND))) ! 1049: #if IPFILTER_LOG ! 1050: nat_log(nat, (u_short)np->in_redir); ! 1051: #else ! 1052: ; ! 1053: #endif ! 1054: break; ! 1055: } ! 1056: ! 1057: if (nat) { ! 1058: if (natadd && fin->fin_fi.fi_fl & FI_FRAG) ! 1059: ipfr_nat_newfrag(ip, fin, 0, nat); ! 1060: nat->nat_age = fr_defnatage; ! 1061: ip->ip_src = nat->nat_outip; ! 1062: nat->nat_bytes += ip->ip_len; ! 1063: nat->nat_pkts++; ! 1064: ! 1065: /* ! 1066: * Fix up checksums, not by recalculating them, but ! 1067: * simply computing adjustments. ! 1068: */ ! 1069: #if SOLARIS || defined(__sgi) ! 1070: if (nat->nat_dir == NAT_OUTBOUND) ! 1071: fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); ! 1072: else ! 1073: fix_incksum(&ip->ip_sum, nat->nat_ipsumd); ! 1074: #endif ! 1075: ! 1076: if (nflags && !(ip->ip_off & 0x1fff) && ! 1077: !(fin->fin_fi.fi_fl & FI_SHORT)) { ! 1078: ! 1079: if (nat->nat_outport) ! 1080: tcp->th_sport = nat->nat_outport; ! 1081: ! 1082: if (ip->ip_p == IPPROTO_TCP) { ! 1083: csump = &tcp->th_sum; ! 1084: fr_tcp_age(&nat->nat_age, ! 1085: nat->nat_state, ip, fin,1); ! 1086: /* ! 1087: * Increase this because we may have ! 1088: * "keep state" following this too and ! 1089: * packet storms can occur if this is ! 1090: * removed too quickly. ! 1091: */ ! 1092: if (nat->nat_age == fr_tcpclosed) ! 1093: nat->nat_age = fr_tcplastack; ! 1094: } else if (ip->ip_p == IPPROTO_UDP) { ! 1095: udphdr_t *udp = (udphdr_t *)tcp; ! 1096: ! 1097: if (udp->uh_sum) ! 1098: csump = &udp->uh_sum; ! 1099: } else if (ip->ip_p == IPPROTO_ICMP) { ! 1100: icmphdr_t *ic = (icmphdr_t *)tcp; ! 1101: ! 1102: csump = &ic->icmp_cksum; ! 1103: } ! 1104: if (csump) { ! 1105: if (nat->nat_dir == NAT_OUTBOUND) ! 1106: fix_outcksum(csump, ! 1107: nat->nat_sumd); ! 1108: else ! 1109: fix_incksum(csump, ! 1110: nat->nat_sumd); ! 1111: } ! 1112: } ! 1113: (void) ap_check(ip, tcp, fin, nat); ! 1114: nat_stats.ns_mapped[1]++; ! 1115: MUTEX_EXIT(&ipf_nat); ! 1116: return -2; ! 1117: } ! 1118: MUTEX_EXIT(&ipf_nat); ! 1119: return 0; ! 1120: } ! 1121: ! 1122: ! 1123: /* ! 1124: * Packets coming in from the external interface go through this. ! 1125: * Here, the destination address requires alteration, if anything. ! 1126: */ ! 1127: int ip_natin(ip, hlen, fin) ! 1128: ip_t *ip; ! 1129: int hlen; ! 1130: fr_info_t *fin; ! 1131: { ! 1132: register ipnat_t *np; ! 1133: register struct in_addr in; ! 1134: struct ifnet *ifp = fin->fin_ifp; ! 1135: tcphdr_t *tcp = NULL; ! 1136: u_short sport = 0, dport = 0, *csump = NULL; ! 1137: nat_t *nat; ! 1138: int nflags = 0, natadd = 1; ! 1139: ! 1140: if (!(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) { ! 1141: if (ip->ip_p == IPPROTO_TCP) ! 1142: nflags = IPN_TCP; ! 1143: else if (ip->ip_p == IPPROTO_UDP) ! 1144: nflags = IPN_UDP; ! 1145: if (nflags) { ! 1146: tcp = (tcphdr_t *)((char *)ip + hlen); ! 1147: dport = tcp->th_dport; ! 1148: sport = tcp->th_sport; ! 1149: } ! 1150: } ! 1151: ! 1152: in = ip->ip_dst; ! 1153: ! 1154: MUTEX_ENTER(&ipf_nat); ! 1155: ! 1156: if ((ip->ip_p == IPPROTO_ICMP) && (nat = nat_icmpin(ip, fin, &nflags))) ! 1157: ; ! 1158: else if ((ip->ip_off & IP_OFFMASK) && ! 1159: (nat = ipfr_nat_knownfrag(ip, fin))) ! 1160: natadd = 0; ! 1161: else if ((nat = nat_inlookup(fin->fin_ifp, nflags, ip->ip_src, sport, ! 1162: ip->ip_dst, dport))) ! 1163: ; ! 1164: else ! 1165: /* ! 1166: * If there is no current entry in the nat table for this IP#, ! 1167: * create one for it (if there is a matching rule). ! 1168: */ ! 1169: for (np = nat_list; np; np = np->in_next) ! 1170: if ((np->in_ifp == ifp) && ! 1171: (!np->in_flags || (nflags & np->in_flags)) && ! 1172: ((in.s_addr & np->in_outmsk) == np->in_outip) && ! 1173: (np->in_redir & NAT_REDIRECT) && ! 1174: (!np->in_pmin || np->in_pmin == dport)) { ! 1175: if ((nat = nat_new(np, ip, fin, nflags, ! 1176: NAT_INBOUND))) ! 1177: #if IPFILTER_LOG ! 1178: nat_log(nat, (u_short)np->in_redir); ! 1179: #else ! 1180: ; ! 1181: #endif ! 1182: break; ! 1183: } ! 1184: if (nat) { ! 1185: if (natadd && fin->fin_fi.fi_fl & FI_FRAG) ! 1186: ipfr_nat_newfrag(ip, fin, 0, nat); ! 1187: (void) ap_check(ip, tcp, fin, nat); ! 1188: ! 1189: if (nflags != IPN_ICMPERR) ! 1190: nat->nat_age = fr_defnatage; ! 1191: ! 1192: ip->ip_dst = nat->nat_inip; ! 1193: nat->nat_bytes += ip->ip_len; ! 1194: nat->nat_pkts++; ! 1195: ! 1196: /* ! 1197: * Fix up checksums, not by recalculating them, but ! 1198: * simply computing adjustments. ! 1199: */ ! 1200: #if SOLARIS || defined(__sgi) ! 1201: if (nat->nat_dir == NAT_OUTBOUND) ! 1202: fix_incksum(&ip->ip_sum, nat->nat_ipsumd); ! 1203: else ! 1204: fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); ! 1205: #endif ! 1206: if ((nflags & IPN_TCPUDP) && !(ip->ip_off & 0x1fff) && ! 1207: !(fin->fin_fi.fi_fl & FI_SHORT)) { ! 1208: ! 1209: if (nat->nat_inport) ! 1210: tcp->th_dport = nat->nat_inport; ! 1211: ! 1212: if (ip->ip_p == IPPROTO_TCP) { ! 1213: csump = &tcp->th_sum; ! 1214: fr_tcp_age(&nat->nat_age, ! 1215: nat->nat_state, ip, fin,0); ! 1216: /* ! 1217: * Increase this because we may have ! 1218: * "keep state" following this too and ! 1219: * packet storms can occur if this is ! 1220: * removed too quickly. ! 1221: */ ! 1222: if (nat->nat_age == fr_tcpclosed) ! 1223: nat->nat_age = fr_tcplastack; ! 1224: } else if (ip->ip_p == IPPROTO_UDP) { ! 1225: udphdr_t *udp = (udphdr_t *)tcp; ! 1226: ! 1227: if (udp->uh_sum) ! 1228: csump = &udp->uh_sum; ! 1229: } else if (ip->ip_p == IPPROTO_ICMP) { ! 1230: icmphdr_t *ic = (icmphdr_t *)tcp; ! 1231: ! 1232: csump = &ic->icmp_cksum; ! 1233: } ! 1234: if (csump) { ! 1235: if (nat->nat_dir == NAT_OUTBOUND) ! 1236: fix_incksum(csump, ! 1237: nat->nat_sumd); ! 1238: else ! 1239: fix_outcksum(csump, ! 1240: nat->nat_sumd); ! 1241: } ! 1242: } ! 1243: nat_stats.ns_mapped[0]++; ! 1244: MUTEX_EXIT(&ipf_nat); ! 1245: return -2; ! 1246: } ! 1247: MUTEX_EXIT(&ipf_nat); ! 1248: return 0; ! 1249: } ! 1250: ! 1251: ! 1252: /* ! 1253: * Free all memory used by NAT structures allocated at runtime. ! 1254: */ ! 1255: void ip_natunload() ! 1256: { ! 1257: MUTEX_ENTER(&ipf_nat); ! 1258: (void) nat_clearlist(); ! 1259: (void) nat_flushtable(); ! 1260: (void) ap_unload(); ! 1261: MUTEX_EXIT(&ipf_nat); ! 1262: } ! 1263: ! 1264: ! 1265: /* ! 1266: * Slowly expire held state for NAT entries. Timeouts are set in ! 1267: * expectation of this being called twice per second. ! 1268: */ ! 1269: void ip_natexpire() ! 1270: { ! 1271: register struct nat *nat, **natp; ! 1272: #if defined(_KERNEL) && !SOLARIS ! 1273: int s; ! 1274: #endif ! 1275: ! 1276: SPL_NET(s); ! 1277: MUTEX_ENTER(&ipf_nat); ! 1278: for (natp = &nat_instances; (nat = *natp); ) { ! 1279: if (--nat->nat_age) { ! 1280: natp = &nat->nat_next; ! 1281: continue; ! 1282: } ! 1283: *natp = nat->nat_next; ! 1284: #if IPFILTER_LOG ! 1285: nat_log(nat, NL_EXPIRE); ! 1286: #endif ! 1287: nat_delete(nat); ! 1288: nat_stats.ns_expire++; ! 1289: } ! 1290: ! 1291: ap_expire(); ! 1292: ! 1293: MUTEX_EXIT(&ipf_nat); ! 1294: SPL_X(s); ! 1295: } ! 1296: ! 1297: ! 1298: /* ! 1299: */ ! 1300: #ifdef __STDC__ ! 1301: void ip_natsync(void *ifp) ! 1302: #else ! 1303: void ip_natsync(ifp) ! 1304: void *ifp; ! 1305: #endif ! 1306: { ! 1307: register nat_t *nat; ! 1308: register u_32_t sum1, sum2, sumd; ! 1309: struct in_addr in; ! 1310: ipnat_t *np; ! 1311: #if defined(_KERNEL) && !SOLARIS ! 1312: int s; ! 1313: #endif ! 1314: ! 1315: SPL_NET(s); ! 1316: MUTEX_ENTER(&ipf_nat); ! 1317: for (nat = nat_instances; nat; nat = nat->nat_next) ! 1318: if ((ifp == nat->nat_ifp) && (np = nat->nat_ptr)) ! 1319: if ((np->in_outmsk == 0xffffffff) && !np->in_nip) { ! 1320: /* ! 1321: * Change the map-to address to be the same ! 1322: * as the new one. ! 1323: */ ! 1324: sum1 = nat->nat_outip.s_addr; ! 1325: if (nat_ifpaddr(nat, ifp, &in) == -1) ! 1326: nat->nat_outip.s_addr = htonl(in.s_addr); ! 1327: sum2 = nat->nat_outip.s_addr; ! 1328: ! 1329: /* ! 1330: * Readjust the checksum adjustment to take ! 1331: * into account the new IP#. ! 1332: * ! 1333: * Do it twice ! 1334: */ ! 1335: sum1 = (sum1 & 0xffff) + (sum1 >> 16); ! 1336: sum1 = (sum1 & 0xffff) + (sum1 >> 16); ! 1337: ! 1338: /* Do it twice */ ! 1339: sum2 = (sum2 & 0xffff) + (sum2 >> 16); ! 1340: sum2 = (sum2 & 0xffff) + (sum2 >> 16); ! 1341: ! 1342: /* Because ~1 == -2, We really need ~1 == -1 */ ! 1343: if (sum1 > sum2) ! 1344: sum2--; ! 1345: sumd = sum2 - sum1; ! 1346: sumd = (sumd & 0xffff) + (sumd >> 16); ! 1347: sumd += nat->nat_sumd; ! 1348: nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16); ! 1349: } ! 1350: MUTEX_EXIT(&ipf_nat); ! 1351: SPL_X(s); ! 1352: } ! 1353: ! 1354: ! 1355: #if IPFILTER_LOG ! 1356: # ifdef __STDC__ ! 1357: void nat_log(struct nat *nat, u_short type) ! 1358: # else ! 1359: void nat_log(nat, type) ! 1360: struct nat *nat; ! 1361: u_short type; ! 1362: # endif ! 1363: { ! 1364: struct ipnat *np; ! 1365: struct natlog natl; ! 1366: void *items[1]; ! 1367: size_t sizes[1]; ! 1368: int rulen, types[1]; ! 1369: ! 1370: natl.nl_inip = nat->nat_inip; ! 1371: natl.nl_outip = nat->nat_outip; ! 1372: natl.nl_origip = nat->nat_oip; ! 1373: natl.nl_bytes = nat->nat_bytes; ! 1374: natl.nl_pkts = nat->nat_pkts; ! 1375: natl.nl_origport = nat->nat_oport; ! 1376: natl.nl_inport = nat->nat_inport; ! 1377: natl.nl_outport = nat->nat_outport; ! 1378: natl.nl_type = type; ! 1379: natl.nl_rule = -1; ! 1380: if (nat->nat_ptr) { ! 1381: for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++) ! 1382: if (np == nat->nat_ptr) { ! 1383: natl.nl_rule = rulen; ! 1384: break; ! 1385: } ! 1386: } ! 1387: items[0] = &natl; ! 1388: sizes[0] = sizeof(natl); ! 1389: types[0] = 0; ! 1390: ! 1391: (void) ipllog(IPL_LOGNAT, 0, items, sizes, types, 1); ! 1392: } ! 1393: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.