Annotation of XNU/bsd/netinet/ip_nat.c, revision 1.1.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.