Annotation of XNU/bsd/netinet/ip_frag.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) 1993-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: #if !defined(lint)
        !            30: /* static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-1995 Darren Reed"; */
        !            31: #endif
        !            32: 
        !            33: 
        !            34: #if !defined(KERNEL)
        !            35: # include <string.h>
        !            36: # include <stdlib.h>
        !            37: #endif
        !            38: #include <sys/errno.h>
        !            39: #include <sys/types.h>
        !            40: #include <sys/param.h>
        !            41: #include <sys/time.h>
        !            42: #include <sys/file.h>
        !            43: #if defined(KERNEL)
        !            44: #include <sys/filio.h>
        !            45: #include <sys/fcntl.h>
        !            46: #include <sys/malloc.h>
        !            47: #else
        !            48: #include <sys/ioctl.h>
        !            49: #endif
        !            50: #include <sys/uio.h>
        !            51: #ifndef linux
        !            52: #include <sys/protosw.h>
        !            53: #endif
        !            54: #include <sys/socket.h>
        !            55: #if defined(KERNEL)
        !            56: # include <sys/systm.h>
        !            57: #endif
        !            58: #if !defined(__SVR4) && !defined(__svr4__)
        !            59: # ifndef linux
        !            60: #  include <sys/mbuf.h>
        !            61: # endif
        !            62: #else
        !            63: # include <sys/byteorder.h>
        !            64: # include <sys/dditypes.h>
        !            65: # include <sys/stream.h>
        !            66: # include <sys/kmem.h>
        !            67: #endif
        !            68: #if defined(KERNEL)
        !            69: #include <sys/malloc.h>
        !            70: #endif
        !            71: 
        !            72: #include <net/if.h>
        !            73: #ifdef sun
        !            74: #include <net/af.h>
        !            75: #endif
        !            76: #include <net/route.h>
        !            77: #include <netinet/in.h>
        !            78: #include <netinet/in_systm.h>
        !            79: #include <netinet/ip.h>
        !            80: #ifndef linux
        !            81: #include <netinet/ip_var.h>
        !            82: #endif
        !            83: #include <netinet/tcp.h>
        !            84: #include <netinet/udp.h>
        !            85: #include <netinet/ip_icmp.h>
        !            86: #include "netinet/ip_compat.h"
        !            87: #include <netinet/tcpip.h>
        !            88: #include "netinet/ip_fil.h"
        !            89: #include "netinet/ip_proxy.h"
        !            90: #include "netinet/ip_nat.h"
        !            91: #include "netinet/ip_frag.h"
        !            92: #include "netinet/ip_state.h"
        !            93: #include "netinet/ip_auth.h"
        !            94: 
        !            95: static ipfr_t  *ipfr_heads[IPFT_SIZE];
        !            96: static ipfr_t  *ipfr_nattab[IPFT_SIZE];
        !            97: static ipfrstat_t ipfr_stats;
        !            98: static int     ipfr_inuse = 0;
        !            99:        int     fr_ipfrttl = 120;       /* 60 seconds */
        !           100: #ifdef KERNEL
        !           101: extern int     ipfr_timer_id;
        !           102: #endif
        !           103: #if    (SOLARIS || defined(__sgi)) && defined(KERNEL)
        !           104: extern kmutex_t        ipf_frag;
        !           105: extern kmutex_t        ipf_natfrag;
        !           106: extern kmutex_t        ipf_nat;
        !           107: #endif
        !           108: 
        !           109: 
        !           110: static ipfr_t *ipfr_new __P((ip_t *, fr_info_t *, int, ipfr_t **));
        !           111: static ipfr_t *ipfr_lookup __P((ip_t *, fr_info_t *, ipfr_t **));
        !           112: 
        !           113: 
        !           114: ipfrstat_t *ipfr_fragstats()
        !           115: {
        !           116:        ipfr_stats.ifs_table = ipfr_heads;
        !           117:        ipfr_stats.ifs_nattab = ipfr_nattab;
        !           118:        ipfr_stats.ifs_inuse = ipfr_inuse;
        !           119:        return &ipfr_stats;
        !           120: }
        !           121: 
        !           122: 
        !           123: /*
        !           124:  * add a new entry to the fragment cache, registering it as having come
        !           125:  * through this box, with the result of the filter operation.
        !           126:  */
        !           127: static ipfr_t *ipfr_new(ip, fin, pass, table)
        !           128: ip_t *ip;
        !           129: fr_info_t *fin;
        !           130: int pass;
        !           131: ipfr_t *table[];
        !           132: {
        !           133:        ipfr_t  **fp, *fr, frag;
        !           134:        u_int   idx;
        !           135: 
        !           136:        frag.ipfr_p = ip->ip_p;
        !           137:        idx = ip->ip_p;
        !           138:        frag.ipfr_id = ip->ip_id;
        !           139:        idx += ip->ip_id;
        !           140:        frag.ipfr_tos = ip->ip_tos;
        !           141:        frag.ipfr_src.s_addr = ip->ip_src.s_addr;
        !           142:        idx += ip->ip_src.s_addr;
        !           143:        frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
        !           144:        idx += ip->ip_dst.s_addr;
        !           145:        idx *= 127;
        !           146:        idx %= IPFT_SIZE;
        !           147: 
        !           148:        /*
        !           149:         * first, make sure it isn't already there...
        !           150:         */
        !           151:        for (fp = &table[idx]; (fr = *fp); fp = &fr->ipfr_next)
        !           152:                if (!bcmp((char *)&frag.ipfr_src, (char *)&fr->ipfr_src,
        !           153:                          IPFR_CMPSZ)) {
        !           154:                        ipfr_stats.ifs_exists++;
        !           155:                        return NULL;
        !           156:                }
        !           157: 
        !           158:        /*
        !           159:         * allocate some memory, if possible, if not, just record that we
        !           160:         * failed to do so.
        !           161:         */
        !           162:        KMALLOC(fr, ipfr_t *, sizeof(*fr));
        !           163:        if (fr == NULL) {
        !           164:                ipfr_stats.ifs_nomem++;
        !           165:                return NULL;
        !           166:        }
        !           167: 
        !           168:        /*
        !           169:         * Instert the fragment into the fragment table, copy the struct used
        !           170:         * in the search using bcopy rather than reassign each field.
        !           171:         * Set the ttl to the default and mask out logging from "pass"
        !           172:         */
        !           173:        if ((fr->ipfr_next = table[idx]))
        !           174:                table[idx]->ipfr_prev = fr;
        !           175:        fr->ipfr_prev = NULL;
        !           176:        fr->ipfr_data = NULL;
        !           177:        table[idx] = fr;
        !           178:        bcopy((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, IPFR_CMPSZ);
        !           179:        fr->ipfr_ttl = fr_ipfrttl;
        !           180:        fr->ipfr_pass = pass & ~(FR_LOGFIRST|FR_LOG);
        !           181:        /*
        !           182:         * Compute the offset of the expected start of the next packet.
        !           183:         */
        !           184:        fr->ipfr_off = (ip->ip_off & 0x1fff) + (fin->fin_dlen >> 3);
        !           185:        ipfr_stats.ifs_new++;
        !           186:        ipfr_inuse++;
        !           187:        return fr;
        !           188: }
        !           189: 
        !           190: 
        !           191: int ipfr_newfrag(ip, fin, pass)
        !           192: ip_t *ip;
        !           193: fr_info_t *fin;
        !           194: int pass;
        !           195: {
        !           196:        ipfr_t  *ipf;
        !           197: 
        !           198:        MUTEX_ENTER(&ipf_frag);
        !           199:        ipf = ipfr_new(ip, fin, pass, ipfr_heads);
        !           200:        MUTEX_EXIT(&ipf_frag);
        !           201:        return ipf ? 0 : -1;
        !           202: }
        !           203: 
        !           204: 
        !           205: int ipfr_nat_newfrag(ip, fin, pass, nat)
        !           206: ip_t *ip;
        !           207: fr_info_t *fin;
        !           208: int pass;
        !           209: nat_t *nat;
        !           210: {
        !           211:        ipfr_t  *ipf;
        !           212: 
        !           213:        MUTEX_ENTER(&ipf_natfrag);
        !           214:        if ((ipf = ipfr_new(ip, fin, pass, ipfr_nattab))) {
        !           215:                ipf->ipfr_data = nat;
        !           216:                nat->nat_data = ipf;
        !           217:        }
        !           218:        MUTEX_EXIT(&ipf_natfrag);
        !           219:        return ipf ? 0 : -1;
        !           220: }
        !           221: 
        !           222: 
        !           223: /*
        !           224:  * check the fragment cache to see if there is already a record of this packet
        !           225:  * with its filter result known.
        !           226:  */
        !           227: static ipfr_t *ipfr_lookup(ip, fin, table)
        !           228: ip_t *ip;
        !           229: fr_info_t *fin;
        !           230: ipfr_t *table[];
        !           231: {
        !           232:        ipfr_t  *f, frag;
        !           233:        u_int   idx;
        !           234: 
        !           235:        /*
        !           236:         * For fragments, we record protocol, packet id, TOS and both IP#'s
        !           237:         * (these should all be the same for all fragments of a packet).
        !           238:         *
        !           239:         * build up a hash value to index the table with.
        !           240:         */
        !           241:        frag.ipfr_p = ip->ip_p;
        !           242:        idx = ip->ip_p;
        !           243:        frag.ipfr_id = ip->ip_id;
        !           244:        idx += ip->ip_id;
        !           245:        frag.ipfr_tos = ip->ip_tos;
        !           246:        frag.ipfr_src.s_addr = ip->ip_src.s_addr;
        !           247:        idx += ip->ip_src.s_addr;
        !           248:        frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
        !           249:        idx += ip->ip_dst.s_addr;
        !           250:        idx *= 127;
        !           251:        idx %= IPFT_SIZE;
        !           252: 
        !           253:        /*
        !           254:         * check the table, careful to only compare the right amount of data
        !           255:         */
        !           256:        for (f = table[idx]; f; f = f->ipfr_next)
        !           257:                if (!bcmp((char *)&frag.ipfr_src, (char *)&f->ipfr_src,
        !           258:                          IPFR_CMPSZ)) {
        !           259:                        u_short atoff, off;
        !           260: 
        !           261:                        if (f != table[idx]) {
        !           262:                                /*
        !           263:                                 * move fragment info. to the top of the list
        !           264:                                 * to speed up searches.
        !           265:                                 */
        !           266:                                if ((f->ipfr_prev->ipfr_next = f->ipfr_next))
        !           267:                                        f->ipfr_next->ipfr_prev = f->ipfr_prev;
        !           268:                                f->ipfr_next = table[idx];
        !           269:                                table[idx]->ipfr_prev = f;
        !           270:                                f->ipfr_prev = NULL;
        !           271:                                table[idx] = f;
        !           272:                        }
        !           273:                        off = ip->ip_off;
        !           274:                        atoff = off + (fin->fin_dlen >> 3);
        !           275:                        /*
        !           276:                         * If we've follwed the fragments, and this is the
        !           277:                         * last (in order), shrink expiration time.
        !           278:                         */
        !           279:                        if ((off & 0x1fff) == f->ipfr_off) {
        !           280:                                if (!(off & IP_MF))
        !           281:                                        f->ipfr_ttl = 1;
        !           282:                                else
        !           283:                                        f->ipfr_off = atoff;
        !           284:                        }
        !           285:                        ipfr_stats.ifs_hits++;
        !           286:                        return f;
        !           287:                }
        !           288:        return NULL;
        !           289: }
        !           290: 
        !           291: 
        !           292: /*
        !           293:  * functional interface for NAT lookups of the NAT fragment cache
        !           294:  */
        !           295: nat_t *ipfr_nat_knownfrag(ip, fin)
        !           296: ip_t *ip;
        !           297: fr_info_t *fin;
        !           298: {
        !           299:        nat_t   *nat;
        !           300:        ipfr_t  *ipf;
        !           301: 
        !           302:        MUTEX_ENTER(&ipf_natfrag);
        !           303:        ipf = ipfr_lookup(ip, fin, ipfr_nattab);
        !           304:        if (ipf) {
        !           305:                nat = ipf->ipfr_data;
        !           306:                /*
        !           307:                 * This is the last fragment for this packet.
        !           308:                 */
        !           309:                if (ipf->ipfr_ttl == 1) {
        !           310:                        nat->nat_data = NULL;
        !           311:                        ipf->ipfr_data = NULL;
        !           312:                }
        !           313:        } else
        !           314:                nat = NULL;
        !           315:        MUTEX_EXIT(&ipf_natfrag);
        !           316:        return nat;
        !           317: }
        !           318: 
        !           319: 
        !           320: /*
        !           321:  * functional interface for normal lookups of the fragment cache
        !           322:  */
        !           323: int ipfr_knownfrag(ip, fin)
        !           324: ip_t *ip;
        !           325: fr_info_t *fin;
        !           326: {
        !           327:        int     ret;
        !           328:        ipfr_t  *ipf;
        !           329: 
        !           330:        MUTEX_ENTER(&ipf_frag);
        !           331:        ipf = ipfr_lookup(ip, fin, ipfr_heads);
        !           332:        ret = ipf ? ipf->ipfr_pass : 0;
        !           333:        MUTEX_EXIT(&ipf_frag);
        !           334:        return ret;
        !           335: }
        !           336: 
        !           337: 
        !           338: /*
        !           339:  * forget any references to this external object.
        !           340:  */
        !           341: void ipfr_forget(nat)
        !           342: void *nat;
        !           343: {
        !           344:        ipfr_t  *fr;
        !           345:        int     idx;
        !           346: 
        !           347:        MUTEX_ENTER(&ipf_natfrag);
        !           348:        for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
        !           349:                for (fr = ipfr_heads[idx]; fr; fr = fr->ipfr_next)
        !           350:                        if (fr->ipfr_data == nat)
        !           351:                                fr->ipfr_data = NULL;
        !           352: 
        !           353:        MUTEX_EXIT(&ipf_natfrag);
        !           354: }
        !           355: 
        !           356: 
        !           357: /*
        !           358:  * Free memory in use by fragment state info. kept.
        !           359:  */
        !           360: void ipfr_unload()
        !           361: {
        !           362:        ipfr_t  **fp, *fr;
        !           363:        nat_t   *nat;
        !           364:        int     idx;
        !           365: 
        !           366:        MUTEX_ENTER(&ipf_frag);
        !           367:        for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
        !           368:                for (fp = &ipfr_heads[idx]; (fr = *fp); ) {
        !           369:                        *fp = fr->ipfr_next;
        !           370:                        KFREE(fr);
        !           371:                }
        !           372:        MUTEX_EXIT(&ipf_frag);
        !           373: 
        !           374:        MUTEX_ENTER(&ipf_nat);
        !           375:        MUTEX_ENTER(&ipf_natfrag);
        !           376:        for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
        !           377:                for (fp = &ipfr_nattab[idx]; (fr = *fp); ) {
        !           378:                        *fp = fr->ipfr_next;
        !           379:                        if ((nat = (nat_t *)fr->ipfr_data)) {
        !           380:                                if (nat->nat_data == fr)
        !           381:                                        nat->nat_data = NULL;
        !           382:                        }
        !           383:                        KFREE(fr);
        !           384:                }
        !           385:        MUTEX_EXIT(&ipf_natfrag);
        !           386:        MUTEX_EXIT(&ipf_nat);
        !           387: }
        !           388: 
        !           389: 
        !           390: #ifdef KERNEL
        !           391: /*
        !           392:  * Slowly expire held state for fragments.  Timeouts are set * in expectation
        !           393:  * of this being called twice per second.
        !           394:  */
        !           395: # if (BSD >= 199306) || SOLARIS || defined(__sgi)
        !           396: void ipfr_slowtimer()
        !           397: # else
        !           398: int ipfr_slowtimer()
        !           399: # endif
        !           400: {
        !           401:        ipfr_t  **fp, *fr;
        !           402:        nat_t   *nat;
        !           403:        int     s, idx;
        !           404: 
        !           405: #ifdef __sgi
        !           406:        ipfilter_sgi_intfsync();
        !           407: #endif
        !           408: 
        !           409:        SPL_NET(s);
        !           410:        MUTEX_ENTER(&ipf_frag);
        !           411: 
        !           412:        /*
        !           413:         * Go through the entire table, looking for entries to expire,
        !           414:         * decreasing the ttl by one for each entry.  If it reaches 0,
        !           415:         * remove it from the chain and free it.
        !           416:         */
        !           417:        for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
        !           418:                for (fp = &ipfr_heads[idx]; (fr = *fp); ) {
        !           419:                        --fr->ipfr_ttl;
        !           420:                        if (fr->ipfr_ttl == 0) {
        !           421:                                if (fr->ipfr_prev)
        !           422:                                        fr->ipfr_prev->ipfr_next =
        !           423:                                             fr->ipfr_next;
        !           424:                                if (fr->ipfr_next)
        !           425:                                        fr->ipfr_next->ipfr_prev =
        !           426:                                             fr->ipfr_prev;
        !           427:                                *fp = fr->ipfr_next;
        !           428:                                ipfr_stats.ifs_expire++;
        !           429:                                ipfr_inuse--;
        !           430:                                KFREE(fr);
        !           431:                        } else
        !           432:                                fp = &fr->ipfr_next;
        !           433:                }
        !           434:        MUTEX_EXIT(&ipf_frag);
        !           435: 
        !           436:        /*
        !           437:         * Same again for the NAT table, except that if the structure also
        !           438:         * still points to a NAT structure, and the NAT structure points back
        !           439:         * at the one to be free'd, NULL the reference from the NAT struct.
        !           440:         * NOTE: We need to grab both mutex's early, and in this order so as
        !           441:         * to prevent a deadlock if both try to expire at the same time.
        !           442:         */
        !           443:        MUTEX_ENTER(&ipf_nat);
        !           444:        MUTEX_ENTER(&ipf_natfrag);
        !           445:        for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
        !           446:                for (fp = &ipfr_nattab[idx]; (fr = *fp); ) {
        !           447:                        --fr->ipfr_ttl;
        !           448:                        if (fr->ipfr_ttl == 0) {
        !           449:                                if (fr->ipfr_prev)
        !           450:                                        fr->ipfr_prev->ipfr_next =
        !           451:                                             fr->ipfr_next;
        !           452:                                if (fr->ipfr_next)
        !           453:                                        fr->ipfr_next->ipfr_prev =
        !           454:                                             fr->ipfr_prev;
        !           455:                                *fp = fr->ipfr_next;
        !           456:                                ipfr_stats.ifs_expire++;
        !           457:                                ipfr_inuse--;
        !           458:                                if ((nat = (nat_t *)fr->ipfr_data)) {
        !           459:                                        if (nat->nat_data == fr)
        !           460:                                                nat->nat_data = NULL;
        !           461:                                }
        !           462:                                KFREE(fr);
        !           463:                        } else
        !           464:                                fp = &fr->ipfr_next;
        !           465:                }
        !           466:        MUTEX_EXIT(&ipf_natfrag);
        !           467:        MUTEX_EXIT(&ipf_nat);
        !           468:        SPL_X(s);
        !           469:        fr_timeoutstate();
        !           470:        ip_natexpire();
        !           471:        fr_authexpire();
        !           472: # if   SOLARIS
        !           473:        ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000));
        !           474: # else
        !           475: #  ifndef linux
        !           476:        ip_slowtimo();
        !           477: #  endif
        !           478: #  if (BSD < 199306) && !defined(__sgi)
        !           479:        return 0;
        !           480: #  endif
        !           481: # endif
        !           482: }
        !           483: #endif /* defined(KERNEL) */

unix.superglobalmegacorp.com

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