Annotation of XNU/bsd/netinet/ip_nat.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.