Annotation of XNU/bsd/netinet/ip_frag.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) 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.