[BACK]Return to pf_norm.c CVS log [TXT][DIR] Up to [local] / sys / net

Annotation of sys/net/pf_norm.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: pf_norm.c,v 1.109 2007/05/28 17:16:39 henning Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright 2001 Niels Provos <provos@citi.umich.edu>
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  *
        !            16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            18:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            19:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            20:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            21:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            22:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            23:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            24:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            25:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            26:  */
        !            27:
        !            28: #include "pflog.h"
        !            29:
        !            30: #include <sys/param.h>
        !            31: #include <sys/systm.h>
        !            32: #include <sys/mbuf.h>
        !            33: #include <sys/filio.h>
        !            34: #include <sys/fcntl.h>
        !            35: #include <sys/socket.h>
        !            36: #include <sys/kernel.h>
        !            37: #include <sys/time.h>
        !            38: #include <sys/pool.h>
        !            39:
        !            40: #include <dev/rndvar.h>
        !            41: #include <net/if.h>
        !            42: #include <net/if_types.h>
        !            43: #include <net/bpf.h>
        !            44: #include <net/route.h>
        !            45: #include <net/if_pflog.h>
        !            46:
        !            47: #include <netinet/in.h>
        !            48: #include <netinet/in_var.h>
        !            49: #include <netinet/in_systm.h>
        !            50: #include <netinet/ip.h>
        !            51: #include <netinet/ip_var.h>
        !            52: #include <netinet/tcp.h>
        !            53: #include <netinet/tcp_seq.h>
        !            54: #include <netinet/udp.h>
        !            55: #include <netinet/ip_icmp.h>
        !            56:
        !            57: #ifdef INET6
        !            58: #include <netinet/ip6.h>
        !            59: #endif /* INET6 */
        !            60:
        !            61: #include <net/pfvar.h>
        !            62:
        !            63: struct pf_frent {
        !            64:        LIST_ENTRY(pf_frent) fr_next;
        !            65:        struct ip *fr_ip;
        !            66:        struct mbuf *fr_m;
        !            67: };
        !            68:
        !            69: struct pf_frcache {
        !            70:        LIST_ENTRY(pf_frcache) fr_next;
        !            71:        uint16_t        fr_off;
        !            72:        uint16_t        fr_end;
        !            73: };
        !            74:
        !            75: #define PFFRAG_SEENLAST        0x0001          /* Seen the last fragment for this */
        !            76: #define PFFRAG_NOBUFFER        0x0002          /* Non-buffering fragment cache */
        !            77: #define PFFRAG_DROP    0x0004          /* Drop all fragments */
        !            78: #define BUFFER_FRAGMENTS(fr)   (!((fr)->fr_flags & PFFRAG_NOBUFFER))
        !            79:
        !            80: struct pf_fragment {
        !            81:        RB_ENTRY(pf_fragment) fr_entry;
        !            82:        TAILQ_ENTRY(pf_fragment) frag_next;
        !            83:        struct in_addr  fr_src;
        !            84:        struct in_addr  fr_dst;
        !            85:        u_int8_t        fr_p;           /* protocol of this fragment */
        !            86:        u_int8_t        fr_flags;       /* status flags */
        !            87:        u_int16_t       fr_id;          /* fragment id for reassemble */
        !            88:        u_int16_t       fr_max;         /* fragment data max */
        !            89:        u_int32_t       fr_timeout;
        !            90: #define fr_queue       fr_u.fru_queue
        !            91: #define fr_cache       fr_u.fru_cache
        !            92:        union {
        !            93:                LIST_HEAD(pf_fragq, pf_frent) fru_queue;        /* buffering */
        !            94:                LIST_HEAD(pf_cacheq, pf_frcache) fru_cache;     /* non-buf */
        !            95:        } fr_u;
        !            96: };
        !            97:
        !            98: TAILQ_HEAD(pf_fragqueue, pf_fragment)  pf_fragqueue;
        !            99: TAILQ_HEAD(pf_cachequeue, pf_fragment) pf_cachequeue;
        !           100:
        !           101: static __inline int     pf_frag_compare(struct pf_fragment *,
        !           102:                            struct pf_fragment *);
        !           103: RB_HEAD(pf_frag_tree, pf_fragment)     pf_frag_tree, pf_cache_tree;
        !           104: RB_PROTOTYPE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare);
        !           105: RB_GENERATE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare);
        !           106:
        !           107: /* Private prototypes */
        !           108: void                    pf_ip2key(struct pf_fragment *, struct ip *);
        !           109: void                    pf_remove_fragment(struct pf_fragment *);
        !           110: void                    pf_flush_fragments(void);
        !           111: void                    pf_free_fragment(struct pf_fragment *);
        !           112: struct pf_fragment     *pf_find_fragment(struct ip *, struct pf_frag_tree *);
        !           113: struct mbuf            *pf_reassemble(struct mbuf **, struct pf_fragment **,
        !           114:                            struct pf_frent *, int);
        !           115: struct mbuf            *pf_fragcache(struct mbuf **, struct ip*,
        !           116:                            struct pf_fragment **, int, int, int *);
        !           117: int                     pf_normalize_tcpopt(struct pf_rule *, struct mbuf *,
        !           118:                            struct tcphdr *, int);
        !           119:
        !           120: #define        DPFPRINTF(x) do {                               \
        !           121:        if (pf_status.debug >= PF_DEBUG_MISC) {         \
        !           122:                printf("%s: ", __func__);               \
        !           123:                printf x ;                              \
        !           124:        }                                               \
        !           125: } while(0)
        !           126:
        !           127: /* Globals */
        !           128: struct pool             pf_frent_pl, pf_frag_pl, pf_cache_pl, pf_cent_pl;
        !           129: struct pool             pf_state_scrub_pl;
        !           130: int                     pf_nfrents, pf_ncache;
        !           131:
        !           132: void
        !           133: pf_normalize_init(void)
        !           134: {
        !           135:        pool_init(&pf_frent_pl, sizeof(struct pf_frent), 0, 0, 0, "pffrent",
        !           136:            NULL);
        !           137:        pool_init(&pf_frag_pl, sizeof(struct pf_fragment), 0, 0, 0, "pffrag",
        !           138:            NULL);
        !           139:        pool_init(&pf_cache_pl, sizeof(struct pf_fragment), 0, 0, 0,
        !           140:            "pffrcache", NULL);
        !           141:        pool_init(&pf_cent_pl, sizeof(struct pf_frcache), 0, 0, 0, "pffrcent",
        !           142:            NULL);
        !           143:        pool_init(&pf_state_scrub_pl, sizeof(struct pf_state_scrub), 0, 0, 0,
        !           144:            "pfstscr", NULL);
        !           145:
        !           146:        pool_sethiwat(&pf_frag_pl, PFFRAG_FRAG_HIWAT);
        !           147:        pool_sethardlimit(&pf_frent_pl, PFFRAG_FRENT_HIWAT, NULL, 0);
        !           148:        pool_sethardlimit(&pf_cache_pl, PFFRAG_FRCACHE_HIWAT, NULL, 0);
        !           149:        pool_sethardlimit(&pf_cent_pl, PFFRAG_FRCENT_HIWAT, NULL, 0);
        !           150:
        !           151:        TAILQ_INIT(&pf_fragqueue);
        !           152:        TAILQ_INIT(&pf_cachequeue);
        !           153: }
        !           154:
        !           155: static __inline int
        !           156: pf_frag_compare(struct pf_fragment *a, struct pf_fragment *b)
        !           157: {
        !           158:        int     diff;
        !           159:
        !           160:        if ((diff = a->fr_id - b->fr_id))
        !           161:                return (diff);
        !           162:        else if ((diff = a->fr_p - b->fr_p))
        !           163:                return (diff);
        !           164:        else if (a->fr_src.s_addr < b->fr_src.s_addr)
        !           165:                return (-1);
        !           166:        else if (a->fr_src.s_addr > b->fr_src.s_addr)
        !           167:                return (1);
        !           168:        else if (a->fr_dst.s_addr < b->fr_dst.s_addr)
        !           169:                return (-1);
        !           170:        else if (a->fr_dst.s_addr > b->fr_dst.s_addr)
        !           171:                return (1);
        !           172:        return (0);
        !           173: }
        !           174:
        !           175: void
        !           176: pf_purge_expired_fragments(void)
        !           177: {
        !           178:        struct pf_fragment      *frag;
        !           179:        u_int32_t                expire = time_second -
        !           180:                                    pf_default_rule.timeout[PFTM_FRAG];
        !           181:
        !           182:        while ((frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue)) != NULL) {
        !           183:                KASSERT(BUFFER_FRAGMENTS(frag));
        !           184:                if (frag->fr_timeout > expire)
        !           185:                        break;
        !           186:
        !           187:                DPFPRINTF(("expiring %d(%p)\n", frag->fr_id, frag));
        !           188:                pf_free_fragment(frag);
        !           189:        }
        !           190:
        !           191:        while ((frag = TAILQ_LAST(&pf_cachequeue, pf_cachequeue)) != NULL) {
        !           192:                KASSERT(!BUFFER_FRAGMENTS(frag));
        !           193:                if (frag->fr_timeout > expire)
        !           194:                        break;
        !           195:
        !           196:                DPFPRINTF(("expiring %d(%p)\n", frag->fr_id, frag));
        !           197:                pf_free_fragment(frag);
        !           198:                KASSERT(TAILQ_EMPTY(&pf_cachequeue) ||
        !           199:                    TAILQ_LAST(&pf_cachequeue, pf_cachequeue) != frag);
        !           200:        }
        !           201: }
        !           202:
        !           203: /*
        !           204:  * Try to flush old fragments to make space for new ones
        !           205:  */
        !           206:
        !           207: void
        !           208: pf_flush_fragments(void)
        !           209: {
        !           210:        struct pf_fragment      *frag;
        !           211:        int                      goal;
        !           212:
        !           213:        goal = pf_nfrents * 9 / 10;
        !           214:        DPFPRINTF(("trying to free > %d frents\n",
        !           215:            pf_nfrents - goal));
        !           216:        while (goal < pf_nfrents) {
        !           217:                frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue);
        !           218:                if (frag == NULL)
        !           219:                        break;
        !           220:                pf_free_fragment(frag);
        !           221:        }
        !           222:
        !           223:
        !           224:        goal = pf_ncache * 9 / 10;
        !           225:        DPFPRINTF(("trying to free > %d cache entries\n",
        !           226:            pf_ncache - goal));
        !           227:        while (goal < pf_ncache) {
        !           228:                frag = TAILQ_LAST(&pf_cachequeue, pf_cachequeue);
        !           229:                if (frag == NULL)
        !           230:                        break;
        !           231:                pf_free_fragment(frag);
        !           232:        }
        !           233: }
        !           234:
        !           235: /* Frees the fragments and all associated entries */
        !           236:
        !           237: void
        !           238: pf_free_fragment(struct pf_fragment *frag)
        !           239: {
        !           240:        struct pf_frent         *frent;
        !           241:        struct pf_frcache       *frcache;
        !           242:
        !           243:        /* Free all fragments */
        !           244:        if (BUFFER_FRAGMENTS(frag)) {
        !           245:                for (frent = LIST_FIRST(&frag->fr_queue); frent;
        !           246:                    frent = LIST_FIRST(&frag->fr_queue)) {
        !           247:                        LIST_REMOVE(frent, fr_next);
        !           248:
        !           249:                        m_freem(frent->fr_m);
        !           250:                        pool_put(&pf_frent_pl, frent);
        !           251:                        pf_nfrents--;
        !           252:                }
        !           253:        } else {
        !           254:                for (frcache = LIST_FIRST(&frag->fr_cache); frcache;
        !           255:                    frcache = LIST_FIRST(&frag->fr_cache)) {
        !           256:                        LIST_REMOVE(frcache, fr_next);
        !           257:
        !           258:                        KASSERT(LIST_EMPTY(&frag->fr_cache) ||
        !           259:                            LIST_FIRST(&frag->fr_cache)->fr_off >
        !           260:                            frcache->fr_end);
        !           261:
        !           262:                        pool_put(&pf_cent_pl, frcache);
        !           263:                        pf_ncache--;
        !           264:                }
        !           265:        }
        !           266:
        !           267:        pf_remove_fragment(frag);
        !           268: }
        !           269:
        !           270: void
        !           271: pf_ip2key(struct pf_fragment *key, struct ip *ip)
        !           272: {
        !           273:        key->fr_p = ip->ip_p;
        !           274:        key->fr_id = ip->ip_id;
        !           275:        key->fr_src.s_addr = ip->ip_src.s_addr;
        !           276:        key->fr_dst.s_addr = ip->ip_dst.s_addr;
        !           277: }
        !           278:
        !           279: struct pf_fragment *
        !           280: pf_find_fragment(struct ip *ip, struct pf_frag_tree *tree)
        !           281: {
        !           282:        struct pf_fragment       key;
        !           283:        struct pf_fragment      *frag;
        !           284:
        !           285:        pf_ip2key(&key, ip);
        !           286:
        !           287:        frag = RB_FIND(pf_frag_tree, tree, &key);
        !           288:        if (frag != NULL) {
        !           289:                /* XXX Are we sure we want to update the timeout? */
        !           290:                frag->fr_timeout = time_second;
        !           291:                if (BUFFER_FRAGMENTS(frag)) {
        !           292:                        TAILQ_REMOVE(&pf_fragqueue, frag, frag_next);
        !           293:                        TAILQ_INSERT_HEAD(&pf_fragqueue, frag, frag_next);
        !           294:                } else {
        !           295:                        TAILQ_REMOVE(&pf_cachequeue, frag, frag_next);
        !           296:                        TAILQ_INSERT_HEAD(&pf_cachequeue, frag, frag_next);
        !           297:                }
        !           298:        }
        !           299:
        !           300:        return (frag);
        !           301: }
        !           302:
        !           303: /* Removes a fragment from the fragment queue and frees the fragment */
        !           304:
        !           305: void
        !           306: pf_remove_fragment(struct pf_fragment *frag)
        !           307: {
        !           308:        if (BUFFER_FRAGMENTS(frag)) {
        !           309:                RB_REMOVE(pf_frag_tree, &pf_frag_tree, frag);
        !           310:                TAILQ_REMOVE(&pf_fragqueue, frag, frag_next);
        !           311:                pool_put(&pf_frag_pl, frag);
        !           312:        } else {
        !           313:                RB_REMOVE(pf_frag_tree, &pf_cache_tree, frag);
        !           314:                TAILQ_REMOVE(&pf_cachequeue, frag, frag_next);
        !           315:                pool_put(&pf_cache_pl, frag);
        !           316:        }
        !           317: }
        !           318:
        !           319: #define FR_IP_OFF(fr)  ((ntohs((fr)->fr_ip->ip_off) & IP_OFFMASK) << 3)
        !           320: struct mbuf *
        !           321: pf_reassemble(struct mbuf **m0, struct pf_fragment **frag,
        !           322:     struct pf_frent *frent, int mff)
        !           323: {
        !           324:        struct mbuf     *m = *m0, *m2;
        !           325:        struct pf_frent *frea, *next;
        !           326:        struct pf_frent *frep = NULL;
        !           327:        struct ip       *ip = frent->fr_ip;
        !           328:        int              hlen = ip->ip_hl << 2;
        !           329:        u_int16_t        off = (ntohs(ip->ip_off) & IP_OFFMASK) << 3;
        !           330:        u_int16_t        ip_len = ntohs(ip->ip_len) - ip->ip_hl * 4;
        !           331:        u_int16_t        max = ip_len + off;
        !           332:
        !           333:        KASSERT(*frag == NULL || BUFFER_FRAGMENTS(*frag));
        !           334:
        !           335:        /* Strip off ip header */
        !           336:        m->m_data += hlen;
        !           337:        m->m_len -= hlen;
        !           338:
        !           339:        /* Create a new reassembly queue for this packet */
        !           340:        if (*frag == NULL) {
        !           341:                *frag = pool_get(&pf_frag_pl, PR_NOWAIT);
        !           342:                if (*frag == NULL) {
        !           343:                        pf_flush_fragments();
        !           344:                        *frag = pool_get(&pf_frag_pl, PR_NOWAIT);
        !           345:                        if (*frag == NULL)
        !           346:                                goto drop_fragment;
        !           347:                }
        !           348:
        !           349:                (*frag)->fr_flags = 0;
        !           350:                (*frag)->fr_max = 0;
        !           351:                (*frag)->fr_src = frent->fr_ip->ip_src;
        !           352:                (*frag)->fr_dst = frent->fr_ip->ip_dst;
        !           353:                (*frag)->fr_p = frent->fr_ip->ip_p;
        !           354:                (*frag)->fr_id = frent->fr_ip->ip_id;
        !           355:                (*frag)->fr_timeout = time_second;
        !           356:                LIST_INIT(&(*frag)->fr_queue);
        !           357:
        !           358:                RB_INSERT(pf_frag_tree, &pf_frag_tree, *frag);
        !           359:                TAILQ_INSERT_HEAD(&pf_fragqueue, *frag, frag_next);
        !           360:
        !           361:                /* We do not have a previous fragment */
        !           362:                frep = NULL;
        !           363:                goto insert;
        !           364:        }
        !           365:
        !           366:        /*
        !           367:         * Find a fragment after the current one:
        !           368:         *  - off contains the real shifted offset.
        !           369:         */
        !           370:        LIST_FOREACH(frea, &(*frag)->fr_queue, fr_next) {
        !           371:                if (FR_IP_OFF(frea) > off)
        !           372:                        break;
        !           373:                frep = frea;
        !           374:        }
        !           375:
        !           376:        KASSERT(frep != NULL || frea != NULL);
        !           377:
        !           378:        if (frep != NULL &&
        !           379:            FR_IP_OFF(frep) + ntohs(frep->fr_ip->ip_len) - frep->fr_ip->ip_hl *
        !           380:            4 > off)
        !           381:        {
        !           382:                u_int16_t       precut;
        !           383:
        !           384:                precut = FR_IP_OFF(frep) + ntohs(frep->fr_ip->ip_len) -
        !           385:                    frep->fr_ip->ip_hl * 4 - off;
        !           386:                if (precut >= ip_len)
        !           387:                        goto drop_fragment;
        !           388:                m_adj(frent->fr_m, precut);
        !           389:                DPFPRINTF(("overlap -%d\n", precut));
        !           390:                /* Enforce 8 byte boundaries */
        !           391:                ip->ip_off = htons(ntohs(ip->ip_off) + (precut >> 3));
        !           392:                off = (ntohs(ip->ip_off) & IP_OFFMASK) << 3;
        !           393:                ip_len -= precut;
        !           394:                ip->ip_len = htons(ip_len);
        !           395:        }
        !           396:
        !           397:        for (; frea != NULL && ip_len + off > FR_IP_OFF(frea);
        !           398:            frea = next)
        !           399:        {
        !           400:                u_int16_t       aftercut;
        !           401:
        !           402:                aftercut = ip_len + off - FR_IP_OFF(frea);
        !           403:                DPFPRINTF(("adjust overlap %d\n", aftercut));
        !           404:                if (aftercut < ntohs(frea->fr_ip->ip_len) - frea->fr_ip->ip_hl
        !           405:                    * 4)
        !           406:                {
        !           407:                        frea->fr_ip->ip_len =
        !           408:                            htons(ntohs(frea->fr_ip->ip_len) - aftercut);
        !           409:                        frea->fr_ip->ip_off = htons(ntohs(frea->fr_ip->ip_off) +
        !           410:                            (aftercut >> 3));
        !           411:                        m_adj(frea->fr_m, aftercut);
        !           412:                        break;
        !           413:                }
        !           414:
        !           415:                /* This fragment is completely overlapped, lose it */
        !           416:                next = LIST_NEXT(frea, fr_next);
        !           417:                m_freem(frea->fr_m);
        !           418:                LIST_REMOVE(frea, fr_next);
        !           419:                pool_put(&pf_frent_pl, frea);
        !           420:                pf_nfrents--;
        !           421:        }
        !           422:
        !           423:  insert:
        !           424:        /* Update maximum data size */
        !           425:        if ((*frag)->fr_max < max)
        !           426:                (*frag)->fr_max = max;
        !           427:        /* This is the last segment */
        !           428:        if (!mff)
        !           429:                (*frag)->fr_flags |= PFFRAG_SEENLAST;
        !           430:
        !           431:        if (frep == NULL)
        !           432:                LIST_INSERT_HEAD(&(*frag)->fr_queue, frent, fr_next);
        !           433:        else
        !           434:                LIST_INSERT_AFTER(frep, frent, fr_next);
        !           435:
        !           436:        /* Check if we are completely reassembled */
        !           437:        if (!((*frag)->fr_flags & PFFRAG_SEENLAST))
        !           438:                return (NULL);
        !           439:
        !           440:        /* Check if we have all the data */
        !           441:        off = 0;
        !           442:        for (frep = LIST_FIRST(&(*frag)->fr_queue); frep; frep = next) {
        !           443:                next = LIST_NEXT(frep, fr_next);
        !           444:
        !           445:                off += ntohs(frep->fr_ip->ip_len) - frep->fr_ip->ip_hl * 4;
        !           446:                if (off < (*frag)->fr_max &&
        !           447:                    (next == NULL || FR_IP_OFF(next) != off))
        !           448:                {
        !           449:                        DPFPRINTF(("missing fragment at %d, next %d, max %d\n",
        !           450:                            off, next == NULL ? -1 : FR_IP_OFF(next),
        !           451:                            (*frag)->fr_max));
        !           452:                        return (NULL);
        !           453:                }
        !           454:        }
        !           455:        DPFPRINTF(("%d < %d?\n", off, (*frag)->fr_max));
        !           456:        if (off < (*frag)->fr_max)
        !           457:                return (NULL);
        !           458:
        !           459:        /* We have all the data */
        !           460:        frent = LIST_FIRST(&(*frag)->fr_queue);
        !           461:        KASSERT(frent != NULL);
        !           462:        if ((frent->fr_ip->ip_hl << 2) + off > IP_MAXPACKET) {
        !           463:                DPFPRINTF(("drop: too big: %d\n", off));
        !           464:                pf_free_fragment(*frag);
        !           465:                *frag = NULL;
        !           466:                return (NULL);
        !           467:        }
        !           468:        next = LIST_NEXT(frent, fr_next);
        !           469:
        !           470:        /* Magic from ip_input */
        !           471:        ip = frent->fr_ip;
        !           472:        m = frent->fr_m;
        !           473:        m2 = m->m_next;
        !           474:        m->m_next = NULL;
        !           475:        m_cat(m, m2);
        !           476:        pool_put(&pf_frent_pl, frent);
        !           477:        pf_nfrents--;
        !           478:        for (frent = next; frent != NULL; frent = next) {
        !           479:                next = LIST_NEXT(frent, fr_next);
        !           480:
        !           481:                m2 = frent->fr_m;
        !           482:                pool_put(&pf_frent_pl, frent);
        !           483:                pf_nfrents--;
        !           484:                m_cat(m, m2);
        !           485:        }
        !           486:
        !           487:        ip->ip_src = (*frag)->fr_src;
        !           488:        ip->ip_dst = (*frag)->fr_dst;
        !           489:
        !           490:        /* Remove from fragment queue */
        !           491:        pf_remove_fragment(*frag);
        !           492:        *frag = NULL;
        !           493:
        !           494:        hlen = ip->ip_hl << 2;
        !           495:        ip->ip_len = htons(off + hlen);
        !           496:        m->m_len += hlen;
        !           497:        m->m_data -= hlen;
        !           498:
        !           499:        /* some debugging cruft by sklower, below, will go away soon */
        !           500:        /* XXX this should be done elsewhere */
        !           501:        if (m->m_flags & M_PKTHDR) {
        !           502:                int plen = 0;
        !           503:                for (m2 = m; m2; m2 = m2->m_next)
        !           504:                        plen += m2->m_len;
        !           505:                m->m_pkthdr.len = plen;
        !           506:        }
        !           507:
        !           508:        DPFPRINTF(("complete: %p(%d)\n", m, ntohs(ip->ip_len)));
        !           509:        return (m);
        !           510:
        !           511:  drop_fragment:
        !           512:        /* Oops - fail safe - drop packet */
        !           513:        pool_put(&pf_frent_pl, frent);
        !           514:        pf_nfrents--;
        !           515:        m_freem(m);
        !           516:        return (NULL);
        !           517: }
        !           518:
        !           519: struct mbuf *
        !           520: pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
        !           521:     int drop, int *nomem)
        !           522: {
        !           523:        struct mbuf             *m = *m0;
        !           524:        struct pf_frcache       *frp, *fra, *cur = NULL;
        !           525:        int                      ip_len = ntohs(h->ip_len) - (h->ip_hl << 2);
        !           526:        u_int16_t                off = ntohs(h->ip_off) << 3;
        !           527:        u_int16_t                max = ip_len + off;
        !           528:        int                      hosed = 0;
        !           529:
        !           530:        KASSERT(*frag == NULL || !BUFFER_FRAGMENTS(*frag));
        !           531:
        !           532:        /* Create a new range queue for this packet */
        !           533:        if (*frag == NULL) {
        !           534:                *frag = pool_get(&pf_cache_pl, PR_NOWAIT);
        !           535:                if (*frag == NULL) {
        !           536:                        pf_flush_fragments();
        !           537:                        *frag = pool_get(&pf_cache_pl, PR_NOWAIT);
        !           538:                        if (*frag == NULL)
        !           539:                                goto no_mem;
        !           540:                }
        !           541:
        !           542:                /* Get an entry for the queue */
        !           543:                cur = pool_get(&pf_cent_pl, PR_NOWAIT);
        !           544:                if (cur == NULL) {
        !           545:                        pool_put(&pf_cache_pl, *frag);
        !           546:                        *frag = NULL;
        !           547:                        goto no_mem;
        !           548:                }
        !           549:                pf_ncache++;
        !           550:
        !           551:                (*frag)->fr_flags = PFFRAG_NOBUFFER;
        !           552:                (*frag)->fr_max = 0;
        !           553:                (*frag)->fr_src = h->ip_src;
        !           554:                (*frag)->fr_dst = h->ip_dst;
        !           555:                (*frag)->fr_p = h->ip_p;
        !           556:                (*frag)->fr_id = h->ip_id;
        !           557:                (*frag)->fr_timeout = time_second;
        !           558:
        !           559:                cur->fr_off = off;
        !           560:                cur->fr_end = max;
        !           561:                LIST_INIT(&(*frag)->fr_cache);
        !           562:                LIST_INSERT_HEAD(&(*frag)->fr_cache, cur, fr_next);
        !           563:
        !           564:                RB_INSERT(pf_frag_tree, &pf_cache_tree, *frag);
        !           565:                TAILQ_INSERT_HEAD(&pf_cachequeue, *frag, frag_next);
        !           566:
        !           567:                DPFPRINTF(("fragcache[%d]: new %d-%d\n", h->ip_id, off, max));
        !           568:
        !           569:                goto pass;
        !           570:        }
        !           571:
        !           572:        /*
        !           573:         * Find a fragment after the current one:
        !           574:         *  - off contains the real shifted offset.
        !           575:         */
        !           576:        frp = NULL;
        !           577:        LIST_FOREACH(fra, &(*frag)->fr_cache, fr_next) {
        !           578:                if (fra->fr_off > off)
        !           579:                        break;
        !           580:                frp = fra;
        !           581:        }
        !           582:
        !           583:        KASSERT(frp != NULL || fra != NULL);
        !           584:
        !           585:        if (frp != NULL) {
        !           586:                int     precut;
        !           587:
        !           588:                precut = frp->fr_end - off;
        !           589:                if (precut >= ip_len) {
        !           590:                        /* Fragment is entirely a duplicate */
        !           591:                        DPFPRINTF(("fragcache[%d]: dead (%d-%d) %d-%d\n",
        !           592:                            h->ip_id, frp->fr_off, frp->fr_end, off, max));
        !           593:                        goto drop_fragment;
        !           594:                }
        !           595:                if (precut == 0) {
        !           596:                        /* They are adjacent.  Fixup cache entry */
        !           597:                        DPFPRINTF(("fragcache[%d]: adjacent (%d-%d) %d-%d\n",
        !           598:                            h->ip_id, frp->fr_off, frp->fr_end, off, max));
        !           599:                        frp->fr_end = max;
        !           600:                } else if (precut > 0) {
        !           601:                        /* The first part of this payload overlaps with a
        !           602:                         * fragment that has already been passed.
        !           603:                         * Need to trim off the first part of the payload.
        !           604:                         * But to do so easily, we need to create another
        !           605:                         * mbuf to throw the original header into.
        !           606:                         */
        !           607:
        !           608:                        DPFPRINTF(("fragcache[%d]: chop %d (%d-%d) %d-%d\n",
        !           609:                            h->ip_id, precut, frp->fr_off, frp->fr_end, off,
        !           610:                            max));
        !           611:
        !           612:                        off += precut;
        !           613:                        max -= precut;
        !           614:                        /* Update the previous frag to encompass this one */
        !           615:                        frp->fr_end = max;
        !           616:
        !           617:                        if (!drop) {
        !           618:                                /* XXX Optimization opportunity
        !           619:                                 * This is a very heavy way to trim the payload.
        !           620:                                 * we could do it much faster by diddling mbuf
        !           621:                                 * internals but that would be even less legible
        !           622:                                 * than this mbuf magic.  For my next trick,
        !           623:                                 * I'll pull a rabbit out of my laptop.
        !           624:                                 */
        !           625:                                *m0 = m_copym2(m, 0, h->ip_hl << 2, M_NOWAIT);
        !           626:                                if (*m0 == NULL)
        !           627:                                        goto no_mem;
        !           628:                                KASSERT((*m0)->m_next == NULL);
        !           629:                                m_adj(m, precut + (h->ip_hl << 2));
        !           630:                                m_cat(*m0, m);
        !           631:                                m = *m0;
        !           632:                                if (m->m_flags & M_PKTHDR) {
        !           633:                                        int plen = 0;
        !           634:                                        struct mbuf *t;
        !           635:                                        for (t = m; t; t = t->m_next)
        !           636:                                                plen += t->m_len;
        !           637:                                        m->m_pkthdr.len = plen;
        !           638:                                }
        !           639:
        !           640:
        !           641:                                h = mtod(m, struct ip *);
        !           642:
        !           643:
        !           644:                                KASSERT((int)m->m_len ==
        !           645:                                    ntohs(h->ip_len) - precut);
        !           646:                                h->ip_off = htons(ntohs(h->ip_off) +
        !           647:                                    (precut >> 3));
        !           648:                                h->ip_len = htons(ntohs(h->ip_len) - precut);
        !           649:                        } else {
        !           650:                                hosed++;
        !           651:                        }
        !           652:                } else {
        !           653:                        /* There is a gap between fragments */
        !           654:
        !           655:                        DPFPRINTF(("fragcache[%d]: gap %d (%d-%d) %d-%d\n",
        !           656:                            h->ip_id, -precut, frp->fr_off, frp->fr_end, off,
        !           657:                            max));
        !           658:
        !           659:                        cur = pool_get(&pf_cent_pl, PR_NOWAIT);
        !           660:                        if (cur == NULL)
        !           661:                                goto no_mem;
        !           662:                        pf_ncache++;
        !           663:
        !           664:                        cur->fr_off = off;
        !           665:                        cur->fr_end = max;
        !           666:                        LIST_INSERT_AFTER(frp, cur, fr_next);
        !           667:                }
        !           668:        }
        !           669:
        !           670:        if (fra != NULL) {
        !           671:                int     aftercut;
        !           672:                int     merge = 0;
        !           673:
        !           674:                aftercut = max - fra->fr_off;
        !           675:                if (aftercut == 0) {
        !           676:                        /* Adjacent fragments */
        !           677:                        DPFPRINTF(("fragcache[%d]: adjacent %d-%d (%d-%d)\n",
        !           678:                            h->ip_id, off, max, fra->fr_off, fra->fr_end));
        !           679:                        fra->fr_off = off;
        !           680:                        merge = 1;
        !           681:                } else if (aftercut > 0) {
        !           682:                        /* Need to chop off the tail of this fragment */
        !           683:                        DPFPRINTF(("fragcache[%d]: chop %d %d-%d (%d-%d)\n",
        !           684:                            h->ip_id, aftercut, off, max, fra->fr_off,
        !           685:                            fra->fr_end));
        !           686:                        fra->fr_off = off;
        !           687:                        max -= aftercut;
        !           688:
        !           689:                        merge = 1;
        !           690:
        !           691:                        if (!drop) {
        !           692:                                m_adj(m, -aftercut);
        !           693:                                if (m->m_flags & M_PKTHDR) {
        !           694:                                        int plen = 0;
        !           695:                                        struct mbuf *t;
        !           696:                                        for (t = m; t; t = t->m_next)
        !           697:                                                plen += t->m_len;
        !           698:                                        m->m_pkthdr.len = plen;
        !           699:                                }
        !           700:                                h = mtod(m, struct ip *);
        !           701:                                KASSERT((int)m->m_len ==
        !           702:                                    ntohs(h->ip_len) - aftercut);
        !           703:                                h->ip_len = htons(ntohs(h->ip_len) - aftercut);
        !           704:                        } else {
        !           705:                                hosed++;
        !           706:                        }
        !           707:                } else if (frp == NULL) {
        !           708:                        /* There is a gap between fragments */
        !           709:                        DPFPRINTF(("fragcache[%d]: gap %d %d-%d (%d-%d)\n",
        !           710:                            h->ip_id, -aftercut, off, max, fra->fr_off,
        !           711:                            fra->fr_end));
        !           712:
        !           713:                        cur = pool_get(&pf_cent_pl, PR_NOWAIT);
        !           714:                        if (cur == NULL)
        !           715:                                goto no_mem;
        !           716:                        pf_ncache++;
        !           717:
        !           718:                        cur->fr_off = off;
        !           719:                        cur->fr_end = max;
        !           720:                        LIST_INSERT_BEFORE(fra, cur, fr_next);
        !           721:                }
        !           722:
        !           723:
        !           724:                /* Need to glue together two separate fragment descriptors */
        !           725:                if (merge) {
        !           726:                        if (cur && fra->fr_off <= cur->fr_end) {
        !           727:                                /* Need to merge in a previous 'cur' */
        !           728:                                DPFPRINTF(("fragcache[%d]: adjacent(merge "
        !           729:                                    "%d-%d) %d-%d (%d-%d)\n",
        !           730:                                    h->ip_id, cur->fr_off, cur->fr_end, off,
        !           731:                                    max, fra->fr_off, fra->fr_end));
        !           732:                                fra->fr_off = cur->fr_off;
        !           733:                                LIST_REMOVE(cur, fr_next);
        !           734:                                pool_put(&pf_cent_pl, cur);
        !           735:                                pf_ncache--;
        !           736:                                cur = NULL;
        !           737:
        !           738:                        } else if (frp && fra->fr_off <= frp->fr_end) {
        !           739:                                /* Need to merge in a modified 'frp' */
        !           740:                                KASSERT(cur == NULL);
        !           741:                                DPFPRINTF(("fragcache[%d]: adjacent(merge "
        !           742:                                    "%d-%d) %d-%d (%d-%d)\n",
        !           743:                                    h->ip_id, frp->fr_off, frp->fr_end, off,
        !           744:                                    max, fra->fr_off, fra->fr_end));
        !           745:                                fra->fr_off = frp->fr_off;
        !           746:                                LIST_REMOVE(frp, fr_next);
        !           747:                                pool_put(&pf_cent_pl, frp);
        !           748:                                pf_ncache--;
        !           749:                                frp = NULL;
        !           750:
        !           751:                        }
        !           752:                }
        !           753:        }
        !           754:
        !           755:        if (hosed) {
        !           756:                /*
        !           757:                 * We must keep tracking the overall fragment even when
        !           758:                 * we're going to drop it anyway so that we know when to
        !           759:                 * free the overall descriptor.  Thus we drop the frag late.
        !           760:                 */
        !           761:                goto drop_fragment;
        !           762:        }
        !           763:
        !           764:
        !           765:  pass:
        !           766:        /* Update maximum data size */
        !           767:        if ((*frag)->fr_max < max)
        !           768:                (*frag)->fr_max = max;
        !           769:
        !           770:        /* This is the last segment */
        !           771:        if (!mff)
        !           772:                (*frag)->fr_flags |= PFFRAG_SEENLAST;
        !           773:
        !           774:        /* Check if we are completely reassembled */
        !           775:        if (((*frag)->fr_flags & PFFRAG_SEENLAST) &&
        !           776:            LIST_FIRST(&(*frag)->fr_cache)->fr_off == 0 &&
        !           777:            LIST_FIRST(&(*frag)->fr_cache)->fr_end == (*frag)->fr_max) {
        !           778:                /* Remove from fragment queue */
        !           779:                DPFPRINTF(("fragcache[%d]: done 0-%d\n", h->ip_id,
        !           780:                    (*frag)->fr_max));
        !           781:                pf_free_fragment(*frag);
        !           782:                *frag = NULL;
        !           783:        }
        !           784:
        !           785:        return (m);
        !           786:
        !           787:  no_mem:
        !           788:        *nomem = 1;
        !           789:
        !           790:        /* Still need to pay attention to !IP_MF */
        !           791:        if (!mff && *frag != NULL)
        !           792:                (*frag)->fr_flags |= PFFRAG_SEENLAST;
        !           793:
        !           794:        m_freem(m);
        !           795:        return (NULL);
        !           796:
        !           797:  drop_fragment:
        !           798:
        !           799:        /* Still need to pay attention to !IP_MF */
        !           800:        if (!mff && *frag != NULL)
        !           801:                (*frag)->fr_flags |= PFFRAG_SEENLAST;
        !           802:
        !           803:        if (drop) {
        !           804:                /* This fragment has been deemed bad.  Don't reass */
        !           805:                if (((*frag)->fr_flags & PFFRAG_DROP) == 0)
        !           806:                        DPFPRINTF(("fragcache[%d]: dropping overall fragment\n",
        !           807:                            h->ip_id));
        !           808:                (*frag)->fr_flags |= PFFRAG_DROP;
        !           809:        }
        !           810:
        !           811:        m_freem(m);
        !           812:        return (NULL);
        !           813: }
        !           814:
        !           815: int
        !           816: pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
        !           817:     struct pf_pdesc *pd)
        !           818: {
        !           819:        struct mbuf             *m = *m0;
        !           820:        struct pf_rule          *r;
        !           821:        struct pf_frent         *frent;
        !           822:        struct pf_fragment      *frag = NULL;
        !           823:        struct ip               *h = mtod(m, struct ip *);
        !           824:        int                      mff = (ntohs(h->ip_off) & IP_MF);
        !           825:        int                      hlen = h->ip_hl << 2;
        !           826:        u_int16_t                fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3;
        !           827:        u_int16_t                max;
        !           828:        int                      ip_len;
        !           829:        int                      ip_off;
        !           830:
        !           831:        r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
        !           832:        while (r != NULL) {
        !           833:                r->evaluations++;
        !           834:                if (pfi_kif_match(r->kif, kif) == r->ifnot)
        !           835:                        r = r->skip[PF_SKIP_IFP].ptr;
        !           836:                else if (r->direction && r->direction != dir)
        !           837:                        r = r->skip[PF_SKIP_DIR].ptr;
        !           838:                else if (r->af && r->af != AF_INET)
        !           839:                        r = r->skip[PF_SKIP_AF].ptr;
        !           840:                else if (r->proto && r->proto != h->ip_p)
        !           841:                        r = r->skip[PF_SKIP_PROTO].ptr;
        !           842:                else if (PF_MISMATCHAW(&r->src.addr,
        !           843:                    (struct pf_addr *)&h->ip_src.s_addr, AF_INET,
        !           844:                    r->src.neg, kif))
        !           845:                        r = r->skip[PF_SKIP_SRC_ADDR].ptr;
        !           846:                else if (PF_MISMATCHAW(&r->dst.addr,
        !           847:                    (struct pf_addr *)&h->ip_dst.s_addr, AF_INET,
        !           848:                    r->dst.neg, NULL))
        !           849:                        r = r->skip[PF_SKIP_DST_ADDR].ptr;
        !           850:                else
        !           851:                        break;
        !           852:        }
        !           853:
        !           854:        if (r == NULL || r->action == PF_NOSCRUB)
        !           855:                return (PF_PASS);
        !           856:        else {
        !           857:                r->packets[dir == PF_OUT]++;
        !           858:                r->bytes[dir == PF_OUT] += pd->tot_len;
        !           859:        }
        !           860:
        !           861:        /* Check for illegal packets */
        !           862:        if (hlen < (int)sizeof(struct ip))
        !           863:                goto drop;
        !           864:
        !           865:        if (hlen > ntohs(h->ip_len))
        !           866:                goto drop;
        !           867:
        !           868:        /* Clear IP_DF if the rule uses the no-df option */
        !           869:        if (r->rule_flag & PFRULE_NODF && h->ip_off & htons(IP_DF)) {
        !           870:                u_int16_t ip_off = h->ip_off;
        !           871:
        !           872:                h->ip_off &= htons(~IP_DF);
        !           873:                h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_off, h->ip_off, 0);
        !           874:        }
        !           875:
        !           876:        /* We will need other tests here */
        !           877:        if (!fragoff && !mff)
        !           878:                goto no_fragment;
        !           879:
        !           880:        /* We're dealing with a fragment now. Don't allow fragments
        !           881:         * with IP_DF to enter the cache. If the flag was cleared by
        !           882:         * no-df above, fine. Otherwise drop it.
        !           883:         */
        !           884:        if (h->ip_off & htons(IP_DF)) {
        !           885:                DPFPRINTF(("IP_DF\n"));
        !           886:                goto bad;
        !           887:        }
        !           888:
        !           889:        ip_len = ntohs(h->ip_len) - hlen;
        !           890:        ip_off = (ntohs(h->ip_off) & IP_OFFMASK) << 3;
        !           891:
        !           892:        /* All fragments are 8 byte aligned */
        !           893:        if (mff && (ip_len & 0x7)) {
        !           894:                DPFPRINTF(("mff and %d\n", ip_len));
        !           895:                goto bad;
        !           896:        }
        !           897:
        !           898:        /* Respect maximum length */
        !           899:        if (fragoff + ip_len > IP_MAXPACKET) {
        !           900:                DPFPRINTF(("max packet %d\n", fragoff + ip_len));
        !           901:                goto bad;
        !           902:        }
        !           903:        max = fragoff + ip_len;
        !           904:
        !           905:        if ((r->rule_flag & (PFRULE_FRAGCROP|PFRULE_FRAGDROP)) == 0) {
        !           906:                /* Fully buffer all of the fragments */
        !           907:
        !           908:                frag = pf_find_fragment(h, &pf_frag_tree);
        !           909:
        !           910:                /* Check if we saw the last fragment already */
        !           911:                if (frag != NULL && (frag->fr_flags & PFFRAG_SEENLAST) &&
        !           912:                    max > frag->fr_max)
        !           913:                        goto bad;
        !           914:
        !           915:                /* Get an entry for the fragment queue */
        !           916:                frent = pool_get(&pf_frent_pl, PR_NOWAIT);
        !           917:                if (frent == NULL) {
        !           918:                        REASON_SET(reason, PFRES_MEMORY);
        !           919:                        return (PF_DROP);
        !           920:                }
        !           921:                pf_nfrents++;
        !           922:                frent->fr_ip = h;
        !           923:                frent->fr_m = m;
        !           924:
        !           925:                /* Might return a completely reassembled mbuf, or NULL */
        !           926:                DPFPRINTF(("reass frag %d @ %d-%d\n", h->ip_id, fragoff, max));
        !           927:                *m0 = m = pf_reassemble(m0, &frag, frent, mff);
        !           928:
        !           929:                if (m == NULL)
        !           930:                        return (PF_DROP);
        !           931:
        !           932:                if (frag != NULL && (frag->fr_flags & PFFRAG_DROP))
        !           933:                        goto drop;
        !           934:
        !           935:                h = mtod(m, struct ip *);
        !           936:        } else {
        !           937:                /* non-buffering fragment cache (drops or masks overlaps) */
        !           938:                int     nomem = 0;
        !           939:
        !           940:                if (dir == PF_OUT && m->m_pkthdr.pf.flags & PF_TAG_FRAGCACHE) {
        !           941:                        /*
        !           942:                         * Already passed the fragment cache in the
        !           943:                         * input direction.  If we continued, it would
        !           944:                         * appear to be a dup and would be dropped.
        !           945:                         */
        !           946:                        goto fragment_pass;
        !           947:                }
        !           948:
        !           949:                frag = pf_find_fragment(h, &pf_cache_tree);
        !           950:
        !           951:                /* Check if we saw the last fragment already */
        !           952:                if (frag != NULL && (frag->fr_flags & PFFRAG_SEENLAST) &&
        !           953:                    max > frag->fr_max) {
        !           954:                        if (r->rule_flag & PFRULE_FRAGDROP)
        !           955:                                frag->fr_flags |= PFFRAG_DROP;
        !           956:                        goto bad;
        !           957:                }
        !           958:
        !           959:                *m0 = m = pf_fragcache(m0, h, &frag, mff,
        !           960:                    (r->rule_flag & PFRULE_FRAGDROP) ? 1 : 0, &nomem);
        !           961:                if (m == NULL) {
        !           962:                        if (nomem)
        !           963:                                goto no_mem;
        !           964:                        goto drop;
        !           965:                }
        !           966:
        !           967:                if (dir == PF_IN)
        !           968:                        m->m_pkthdr.pf.flags |= PF_TAG_FRAGCACHE;
        !           969:
        !           970:                if (frag != NULL && (frag->fr_flags & PFFRAG_DROP))
        !           971:                        goto drop;
        !           972:                goto fragment_pass;
        !           973:        }
        !           974:
        !           975:  no_fragment:
        !           976:        /* At this point, only IP_DF is allowed in ip_off */
        !           977:        if (h->ip_off & ~htons(IP_DF)) {
        !           978:                u_int16_t ip_off = h->ip_off;
        !           979:
        !           980:                h->ip_off &= htons(IP_DF);
        !           981:                h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_off, h->ip_off, 0);
        !           982:        }
        !           983:
        !           984:        /* Enforce a minimum ttl, may cause endless packet loops */
        !           985:        if (r->min_ttl && h->ip_ttl < r->min_ttl) {
        !           986:                u_int16_t ip_ttl = h->ip_ttl;
        !           987:
        !           988:                h->ip_ttl = r->min_ttl;
        !           989:                h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_ttl, h->ip_ttl, 0);
        !           990:        }
        !           991:
        !           992:        if (r->rule_flag & PFRULE_RANDOMID) {
        !           993:                u_int16_t ip_id = h->ip_id;
        !           994:
        !           995:                h->ip_id = ip_randomid();
        !           996:                h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_id, h->ip_id, 0);
        !           997:        }
        !           998:        if ((r->rule_flag & (PFRULE_FRAGCROP|PFRULE_FRAGDROP)) == 0)
        !           999:                pd->flags |= PFDESC_IP_REAS;
        !          1000:
        !          1001:        return (PF_PASS);
        !          1002:
        !          1003:  fragment_pass:
        !          1004:        /* Enforce a minimum ttl, may cause endless packet loops */
        !          1005:        if (r->min_ttl && h->ip_ttl < r->min_ttl) {
        !          1006:                u_int16_t ip_ttl = h->ip_ttl;
        !          1007:
        !          1008:                h->ip_ttl = r->min_ttl;
        !          1009:                h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_ttl, h->ip_ttl, 0);
        !          1010:        }
        !          1011:        if ((r->rule_flag & (PFRULE_FRAGCROP|PFRULE_FRAGDROP)) == 0)
        !          1012:                pd->flags |= PFDESC_IP_REAS;
        !          1013:        return (PF_PASS);
        !          1014:
        !          1015:  no_mem:
        !          1016:        REASON_SET(reason, PFRES_MEMORY);
        !          1017:        if (r != NULL && r->log)
        !          1018:                PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd);
        !          1019:        return (PF_DROP);
        !          1020:
        !          1021:  drop:
        !          1022:        REASON_SET(reason, PFRES_NORM);
        !          1023:        if (r != NULL && r->log)
        !          1024:                PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd);
        !          1025:        return (PF_DROP);
        !          1026:
        !          1027:  bad:
        !          1028:        DPFPRINTF(("dropping bad fragment\n"));
        !          1029:
        !          1030:        /* Free associated fragments */
        !          1031:        if (frag != NULL)
        !          1032:                pf_free_fragment(frag);
        !          1033:
        !          1034:        REASON_SET(reason, PFRES_FRAG);
        !          1035:        if (r != NULL && r->log)
        !          1036:                PFLOG_PACKET(kif, h, m, AF_INET, dir, *reason, r, NULL, NULL, pd);
        !          1037:
        !          1038:        return (PF_DROP);
        !          1039: }
        !          1040:
        !          1041: #ifdef INET6
        !          1042: int
        !          1043: pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif,
        !          1044:     u_short *reason, struct pf_pdesc *pd)
        !          1045: {
        !          1046:        struct mbuf             *m = *m0;
        !          1047:        struct pf_rule          *r;
        !          1048:        struct ip6_hdr          *h = mtod(m, struct ip6_hdr *);
        !          1049:        int                      off;
        !          1050:        struct ip6_ext           ext;
        !          1051:        struct ip6_opt           opt;
        !          1052:        struct ip6_opt_jumbo     jumbo;
        !          1053:        struct ip6_frag          frag;
        !          1054:        u_int32_t                jumbolen = 0, plen;
        !          1055:        u_int16_t                fragoff = 0;
        !          1056:        int                      optend;
        !          1057:        int                      ooff;
        !          1058:        u_int8_t                 proto;
        !          1059:        int                      terminal;
        !          1060:
        !          1061:        r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
        !          1062:        while (r != NULL) {
        !          1063:                r->evaluations++;
        !          1064:                if (pfi_kif_match(r->kif, kif) == r->ifnot)
        !          1065:                        r = r->skip[PF_SKIP_IFP].ptr;
        !          1066:                else if (r->direction && r->direction != dir)
        !          1067:                        r = r->skip[PF_SKIP_DIR].ptr;
        !          1068:                else if (r->af && r->af != AF_INET6)
        !          1069:                        r = r->skip[PF_SKIP_AF].ptr;
        !          1070: #if 0 /* header chain! */
        !          1071:                else if (r->proto && r->proto != h->ip6_nxt)
        !          1072:                        r = r->skip[PF_SKIP_PROTO].ptr;
        !          1073: #endif
        !          1074:                else if (PF_MISMATCHAW(&r->src.addr,
        !          1075:                    (struct pf_addr *)&h->ip6_src, AF_INET6,
        !          1076:                    r->src.neg, kif))
        !          1077:                        r = r->skip[PF_SKIP_SRC_ADDR].ptr;
        !          1078:                else if (PF_MISMATCHAW(&r->dst.addr,
        !          1079:                    (struct pf_addr *)&h->ip6_dst, AF_INET6,
        !          1080:                    r->dst.neg, NULL))
        !          1081:                        r = r->skip[PF_SKIP_DST_ADDR].ptr;
        !          1082:                else
        !          1083:                        break;
        !          1084:        }
        !          1085:
        !          1086:        if (r == NULL || r->action == PF_NOSCRUB)
        !          1087:                return (PF_PASS);
        !          1088:        else {
        !          1089:                r->packets[dir == PF_OUT]++;
        !          1090:                r->bytes[dir == PF_OUT] += pd->tot_len;
        !          1091:        }
        !          1092:
        !          1093:        /* Check for illegal packets */
        !          1094:        if (sizeof(struct ip6_hdr) + IPV6_MAXPACKET < m->m_pkthdr.len)
        !          1095:                goto drop;
        !          1096:
        !          1097:        off = sizeof(struct ip6_hdr);
        !          1098:        proto = h->ip6_nxt;
        !          1099:        terminal = 0;
        !          1100:        do {
        !          1101:                switch (proto) {
        !          1102:                case IPPROTO_FRAGMENT:
        !          1103:                        goto fragment;
        !          1104:                        break;
        !          1105:                case IPPROTO_AH:
        !          1106:                case IPPROTO_ROUTING:
        !          1107:                case IPPROTO_DSTOPTS:
        !          1108:                        if (!pf_pull_hdr(m, off, &ext, sizeof(ext), NULL,
        !          1109:                            NULL, AF_INET6))
        !          1110:                                goto shortpkt;
        !          1111:                        if (proto == IPPROTO_AH)
        !          1112:                                off += (ext.ip6e_len + 2) * 4;
        !          1113:                        else
        !          1114:                                off += (ext.ip6e_len + 1) * 8;
        !          1115:                        proto = ext.ip6e_nxt;
        !          1116:                        break;
        !          1117:                case IPPROTO_HOPOPTS:
        !          1118:                        if (!pf_pull_hdr(m, off, &ext, sizeof(ext), NULL,
        !          1119:                            NULL, AF_INET6))
        !          1120:                                goto shortpkt;
        !          1121:                        optend = off + (ext.ip6e_len + 1) * 8;
        !          1122:                        ooff = off + sizeof(ext);
        !          1123:                        do {
        !          1124:                                if (!pf_pull_hdr(m, ooff, &opt.ip6o_type,
        !          1125:                                    sizeof(opt.ip6o_type), NULL, NULL,
        !          1126:                                    AF_INET6))
        !          1127:                                        goto shortpkt;
        !          1128:                                if (opt.ip6o_type == IP6OPT_PAD1) {
        !          1129:                                        ooff++;
        !          1130:                                        continue;
        !          1131:                                }
        !          1132:                                if (!pf_pull_hdr(m, ooff, &opt, sizeof(opt),
        !          1133:                                    NULL, NULL, AF_INET6))
        !          1134:                                        goto shortpkt;
        !          1135:                                if (ooff + sizeof(opt) + opt.ip6o_len > optend)
        !          1136:                                        goto drop;
        !          1137:                                switch (opt.ip6o_type) {
        !          1138:                                case IP6OPT_JUMBO:
        !          1139:                                        if (h->ip6_plen != 0)
        !          1140:                                                goto drop;
        !          1141:                                        if (!pf_pull_hdr(m, ooff, &jumbo,
        !          1142:                                            sizeof(jumbo), NULL, NULL,
        !          1143:                                            AF_INET6))
        !          1144:                                                goto shortpkt;
        !          1145:                                        memcpy(&jumbolen, jumbo.ip6oj_jumbo_len,
        !          1146:                                            sizeof(jumbolen));
        !          1147:                                        jumbolen = ntohl(jumbolen);
        !          1148:                                        if (jumbolen <= IPV6_MAXPACKET)
        !          1149:                                                goto drop;
        !          1150:                                        if (sizeof(struct ip6_hdr) + jumbolen !=
        !          1151:                                            m->m_pkthdr.len)
        !          1152:                                                goto drop;
        !          1153:                                        break;
        !          1154:                                default:
        !          1155:                                        break;
        !          1156:                                }
        !          1157:                                ooff += sizeof(opt) + opt.ip6o_len;
        !          1158:                        } while (ooff < optend);
        !          1159:
        !          1160:                        off = optend;
        !          1161:                        proto = ext.ip6e_nxt;
        !          1162:                        break;
        !          1163:                default:
        !          1164:                        terminal = 1;
        !          1165:                        break;
        !          1166:                }
        !          1167:        } while (!terminal);
        !          1168:
        !          1169:        /* jumbo payload option must be present, or plen > 0 */
        !          1170:        if (ntohs(h->ip6_plen) == 0)
        !          1171:                plen = jumbolen;
        !          1172:        else
        !          1173:                plen = ntohs(h->ip6_plen);
        !          1174:        if (plen == 0)
        !          1175:                goto drop;
        !          1176:        if (sizeof(struct ip6_hdr) + plen > m->m_pkthdr.len)
        !          1177:                goto shortpkt;
        !          1178:
        !          1179:        /* Enforce a minimum ttl, may cause endless packet loops */
        !          1180:        if (r->min_ttl && h->ip6_hlim < r->min_ttl)
        !          1181:                h->ip6_hlim = r->min_ttl;
        !          1182:
        !          1183:        return (PF_PASS);
        !          1184:
        !          1185:  fragment:
        !          1186:        if (ntohs(h->ip6_plen) == 0 || jumbolen)
        !          1187:                goto drop;
        !          1188:        plen = ntohs(h->ip6_plen);
        !          1189:
        !          1190:        if (!pf_pull_hdr(m, off, &frag, sizeof(frag), NULL, NULL, AF_INET6))
        !          1191:                goto shortpkt;
        !          1192:        fragoff = ntohs(frag.ip6f_offlg & IP6F_OFF_MASK);
        !          1193:        if (fragoff + (plen - off - sizeof(frag)) > IPV6_MAXPACKET)
        !          1194:                goto badfrag;
        !          1195:
        !          1196:        /* do something about it */
        !          1197:        /* remember to set pd->flags |= PFDESC_IP_REAS */
        !          1198:        return (PF_PASS);
        !          1199:
        !          1200:  shortpkt:
        !          1201:        REASON_SET(reason, PFRES_SHORT);
        !          1202:        if (r != NULL && r->log)
        !          1203:                PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd);
        !          1204:        return (PF_DROP);
        !          1205:
        !          1206:  drop:
        !          1207:        REASON_SET(reason, PFRES_NORM);
        !          1208:        if (r != NULL && r->log)
        !          1209:                PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd);
        !          1210:        return (PF_DROP);
        !          1211:
        !          1212:  badfrag:
        !          1213:        REASON_SET(reason, PFRES_FRAG);
        !          1214:        if (r != NULL && r->log)
        !          1215:                PFLOG_PACKET(kif, h, m, AF_INET6, dir, *reason, r, NULL, NULL, pd);
        !          1216:        return (PF_DROP);
        !          1217: }
        !          1218: #endif /* INET6 */
        !          1219:
        !          1220: int
        !          1221: pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
        !          1222:     int off, void *h, struct pf_pdesc *pd)
        !          1223: {
        !          1224:        struct pf_rule  *r, *rm = NULL;
        !          1225:        struct tcphdr   *th = pd->hdr.tcp;
        !          1226:        int              rewrite = 0;
        !          1227:        u_short          reason;
        !          1228:        u_int8_t         flags;
        !          1229:        sa_family_t      af = pd->af;
        !          1230:
        !          1231:        r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
        !          1232:        while (r != NULL) {
        !          1233:                r->evaluations++;
        !          1234:                if (pfi_kif_match(r->kif, kif) == r->ifnot)
        !          1235:                        r = r->skip[PF_SKIP_IFP].ptr;
        !          1236:                else if (r->direction && r->direction != dir)
        !          1237:                        r = r->skip[PF_SKIP_DIR].ptr;
        !          1238:                else if (r->af && r->af != af)
        !          1239:                        r = r->skip[PF_SKIP_AF].ptr;
        !          1240:                else if (r->proto && r->proto != pd->proto)
        !          1241:                        r = r->skip[PF_SKIP_PROTO].ptr;
        !          1242:                else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
        !          1243:                    r->src.neg, kif))
        !          1244:                        r = r->skip[PF_SKIP_SRC_ADDR].ptr;
        !          1245:                else if (r->src.port_op && !pf_match_port(r->src.port_op,
        !          1246:                            r->src.port[0], r->src.port[1], th->th_sport))
        !          1247:                        r = r->skip[PF_SKIP_SRC_PORT].ptr;
        !          1248:                else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
        !          1249:                    r->dst.neg, NULL))
        !          1250:                        r = r->skip[PF_SKIP_DST_ADDR].ptr;
        !          1251:                else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
        !          1252:                            r->dst.port[0], r->dst.port[1], th->th_dport))
        !          1253:                        r = r->skip[PF_SKIP_DST_PORT].ptr;
        !          1254:                else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
        !          1255:                            pf_osfp_fingerprint(pd, m, off, th),
        !          1256:                            r->os_fingerprint))
        !          1257:                        r = TAILQ_NEXT(r, entries);
        !          1258:                else {
        !          1259:                        rm = r;
        !          1260:                        break;
        !          1261:                }
        !          1262:        }
        !          1263:
        !          1264:        if (rm == NULL || rm->action == PF_NOSCRUB)
        !          1265:                return (PF_PASS);
        !          1266:        else {
        !          1267:                r->packets[dir == PF_OUT]++;
        !          1268:                r->bytes[dir == PF_OUT] += pd->tot_len;
        !          1269:        }
        !          1270:
        !          1271:        if (rm->rule_flag & PFRULE_REASSEMBLE_TCP)
        !          1272:                pd->flags |= PFDESC_TCP_NORM;
        !          1273:
        !          1274:        flags = th->th_flags;
        !          1275:        if (flags & TH_SYN) {
        !          1276:                /* Illegal packet */
        !          1277:                if (flags & TH_RST)
        !          1278:                        goto tcp_drop;
        !          1279:
        !          1280:                if (flags & TH_FIN)
        !          1281:                        flags &= ~TH_FIN;
        !          1282:        } else {
        !          1283:                /* Illegal packet */
        !          1284:                if (!(flags & (TH_ACK|TH_RST)))
        !          1285:                        goto tcp_drop;
        !          1286:        }
        !          1287:
        !          1288:        if (!(flags & TH_ACK)) {
        !          1289:                /* These flags are only valid if ACK is set */
        !          1290:                if ((flags & TH_FIN) || (flags & TH_PUSH) || (flags & TH_URG))
        !          1291:                        goto tcp_drop;
        !          1292:        }
        !          1293:
        !          1294:        /* Check for illegal header length */
        !          1295:        if (th->th_off < (sizeof(struct tcphdr) >> 2))
        !          1296:                goto tcp_drop;
        !          1297:
        !          1298:        /* If flags changed, or reserved data set, then adjust */
        !          1299:        if (flags != th->th_flags || th->th_x2 != 0) {
        !          1300:                u_int16_t       ov, nv;
        !          1301:
        !          1302:                ov = *(u_int16_t *)(&th->th_ack + 1);
        !          1303:                th->th_flags = flags;
        !          1304:                th->th_x2 = 0;
        !          1305:                nv = *(u_int16_t *)(&th->th_ack + 1);
        !          1306:
        !          1307:                th->th_sum = pf_cksum_fixup(th->th_sum, ov, nv, 0);
        !          1308:                rewrite = 1;
        !          1309:        }
        !          1310:
        !          1311:        /* Remove urgent pointer, if TH_URG is not set */
        !          1312:        if (!(flags & TH_URG) && th->th_urp) {
        !          1313:                th->th_sum = pf_cksum_fixup(th->th_sum, th->th_urp, 0, 0);
        !          1314:                th->th_urp = 0;
        !          1315:                rewrite = 1;
        !          1316:        }
        !          1317:
        !          1318:        /* Process options */
        !          1319:        if (r->max_mss && pf_normalize_tcpopt(r, m, th, off))
        !          1320:                rewrite = 1;
        !          1321:
        !          1322:        /* copy back packet headers if we sanitized */
        !          1323:        if (rewrite)
        !          1324:                m_copyback(m, off, sizeof(*th), th);
        !          1325:
        !          1326:        return (PF_PASS);
        !          1327:
        !          1328:  tcp_drop:
        !          1329:        REASON_SET(&reason, PFRES_NORM);
        !          1330:        if (rm != NULL && r->log)
        !          1331:                PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, NULL, NULL, pd);
        !          1332:        return (PF_DROP);
        !          1333: }
        !          1334:
        !          1335: int
        !          1336: pf_normalize_tcp_init(struct mbuf *m, int off, struct pf_pdesc *pd,
        !          1337:     struct tcphdr *th, struct pf_state_peer *src, struct pf_state_peer *dst)
        !          1338: {
        !          1339:        u_int32_t tsval, tsecr;
        !          1340:        u_int8_t hdr[60];
        !          1341:        u_int8_t *opt;
        !          1342:
        !          1343:        KASSERT(src->scrub == NULL);
        !          1344:
        !          1345:        src->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT);
        !          1346:        if (src->scrub == NULL)
        !          1347:                return (1);
        !          1348:        bzero(src->scrub, sizeof(*src->scrub));
        !          1349:
        !          1350:        switch (pd->af) {
        !          1351: #ifdef INET
        !          1352:        case AF_INET: {
        !          1353:                struct ip *h = mtod(m, struct ip *);
        !          1354:                src->scrub->pfss_ttl = h->ip_ttl;
        !          1355:                break;
        !          1356:        }
        !          1357: #endif /* INET */
        !          1358: #ifdef INET6
        !          1359:        case AF_INET6: {
        !          1360:                struct ip6_hdr *h = mtod(m, struct ip6_hdr *);
        !          1361:                src->scrub->pfss_ttl = h->ip6_hlim;
        !          1362:                break;
        !          1363:        }
        !          1364: #endif /* INET6 */
        !          1365:        }
        !          1366:
        !          1367:
        !          1368:        /*
        !          1369:         * All normalizations below are only begun if we see the start of
        !          1370:         * the connections.  They must all set an enabled bit in pfss_flags
        !          1371:         */
        !          1372:        if ((th->th_flags & TH_SYN) == 0)
        !          1373:                return (0);
        !          1374:
        !          1375:
        !          1376:        if (th->th_off > (sizeof(struct tcphdr) >> 2) && src->scrub &&
        !          1377:            pf_pull_hdr(m, off, hdr, th->th_off << 2, NULL, NULL, pd->af)) {
        !          1378:                /* Diddle with TCP options */
        !          1379:                int hlen;
        !          1380:                opt = hdr + sizeof(struct tcphdr);
        !          1381:                hlen = (th->th_off << 2) - sizeof(struct tcphdr);
        !          1382:                while (hlen >= TCPOLEN_TIMESTAMP) {
        !          1383:                        switch (*opt) {
        !          1384:                        case TCPOPT_EOL:        /* FALLTHROUGH */
        !          1385:                        case TCPOPT_NOP:
        !          1386:                                opt++;
        !          1387:                                hlen--;
        !          1388:                                break;
        !          1389:                        case TCPOPT_TIMESTAMP:
        !          1390:                                if (opt[1] >= TCPOLEN_TIMESTAMP) {
        !          1391:                                        src->scrub->pfss_flags |=
        !          1392:                                            PFSS_TIMESTAMP;
        !          1393:                                        src->scrub->pfss_ts_mod =
        !          1394:                                            htonl(arc4random());
        !          1395:
        !          1396:                                        /* note PFSS_PAWS not set yet */
        !          1397:                                        memcpy(&tsval, &opt[2],
        !          1398:                                            sizeof(u_int32_t));
        !          1399:                                        memcpy(&tsecr, &opt[6],
        !          1400:                                            sizeof(u_int32_t));
        !          1401:                                        src->scrub->pfss_tsval0 = ntohl(tsval);
        !          1402:                                        src->scrub->pfss_tsval = ntohl(tsval);
        !          1403:                                        src->scrub->pfss_tsecr = ntohl(tsecr);
        !          1404:                                        getmicrouptime(&src->scrub->pfss_last);
        !          1405:                                }
        !          1406:                                /* FALLTHROUGH */
        !          1407:                        default:
        !          1408:                                hlen -= MAX(opt[1], 2);
        !          1409:                                opt += MAX(opt[1], 2);
        !          1410:                                break;
        !          1411:                        }
        !          1412:                }
        !          1413:        }
        !          1414:
        !          1415:        return (0);
        !          1416: }
        !          1417:
        !          1418: void
        !          1419: pf_normalize_tcp_cleanup(struct pf_state *state)
        !          1420: {
        !          1421:        if (state->src.scrub)
        !          1422:                pool_put(&pf_state_scrub_pl, state->src.scrub);
        !          1423:        if (state->dst.scrub)
        !          1424:                pool_put(&pf_state_scrub_pl, state->dst.scrub);
        !          1425:
        !          1426:        /* Someday... flush the TCP segment reassembly descriptors. */
        !          1427: }
        !          1428:
        !          1429: int
        !          1430: pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd,
        !          1431:     u_short *reason, struct tcphdr *th, struct pf_state *state,
        !          1432:     struct pf_state_peer *src, struct pf_state_peer *dst, int *writeback)
        !          1433: {
        !          1434:        struct timeval uptime;
        !          1435:        u_int32_t tsval, tsecr;
        !          1436:        u_int tsval_from_last;
        !          1437:        u_int8_t hdr[60];
        !          1438:        u_int8_t *opt;
        !          1439:        int copyback = 0;
        !          1440:        int got_ts = 0;
        !          1441:
        !          1442:        KASSERT(src->scrub || dst->scrub);
        !          1443:
        !          1444:        /*
        !          1445:         * Enforce the minimum TTL seen for this connection.  Negate a common
        !          1446:         * technique to evade an intrusion detection system and confuse
        !          1447:         * firewall state code.
        !          1448:         */
        !          1449:        switch (pd->af) {
        !          1450: #ifdef INET
        !          1451:        case AF_INET: {
        !          1452:                if (src->scrub) {
        !          1453:                        struct ip *h = mtod(m, struct ip *);
        !          1454:                        if (h->ip_ttl > src->scrub->pfss_ttl)
        !          1455:                                src->scrub->pfss_ttl = h->ip_ttl;
        !          1456:                        h->ip_ttl = src->scrub->pfss_ttl;
        !          1457:                }
        !          1458:                break;
        !          1459:        }
        !          1460: #endif /* INET */
        !          1461: #ifdef INET6
        !          1462:        case AF_INET6: {
        !          1463:                if (src->scrub) {
        !          1464:                        struct ip6_hdr *h = mtod(m, struct ip6_hdr *);
        !          1465:                        if (h->ip6_hlim > src->scrub->pfss_ttl)
        !          1466:                                src->scrub->pfss_ttl = h->ip6_hlim;
        !          1467:                        h->ip6_hlim = src->scrub->pfss_ttl;
        !          1468:                }
        !          1469:                break;
        !          1470:        }
        !          1471: #endif /* INET6 */
        !          1472:        }
        !          1473:
        !          1474:        if (th->th_off > (sizeof(struct tcphdr) >> 2) &&
        !          1475:            ((src->scrub && (src->scrub->pfss_flags & PFSS_TIMESTAMP)) ||
        !          1476:            (dst->scrub && (dst->scrub->pfss_flags & PFSS_TIMESTAMP))) &&
        !          1477:            pf_pull_hdr(m, off, hdr, th->th_off << 2, NULL, NULL, pd->af)) {
        !          1478:                /* Diddle with TCP options */
        !          1479:                int hlen;
        !          1480:                opt = hdr + sizeof(struct tcphdr);
        !          1481:                hlen = (th->th_off << 2) - sizeof(struct tcphdr);
        !          1482:                while (hlen >= TCPOLEN_TIMESTAMP) {
        !          1483:                        switch (*opt) {
        !          1484:                        case TCPOPT_EOL:        /* FALLTHROUGH */
        !          1485:                        case TCPOPT_NOP:
        !          1486:                                opt++;
        !          1487:                                hlen--;
        !          1488:                                break;
        !          1489:                        case TCPOPT_TIMESTAMP:
        !          1490:                                /* Modulate the timestamps.  Can be used for
        !          1491:                                 * NAT detection, OS uptime determination or
        !          1492:                                 * reboot detection.
        !          1493:                                 */
        !          1494:
        !          1495:                                if (got_ts) {
        !          1496:                                        /* Huh?  Multiple timestamps!? */
        !          1497:                                        if (pf_status.debug >= PF_DEBUG_MISC) {
        !          1498:                                                DPFPRINTF(("multiple TS??"));
        !          1499:                                                pf_print_state(state);
        !          1500:                                                printf("\n");
        !          1501:                                        }
        !          1502:                                        REASON_SET(reason, PFRES_TS);
        !          1503:                                        return (PF_DROP);
        !          1504:                                }
        !          1505:                                if (opt[1] >= TCPOLEN_TIMESTAMP) {
        !          1506:                                        memcpy(&tsval, &opt[2],
        !          1507:                                            sizeof(u_int32_t));
        !          1508:                                        if (tsval && src->scrub &&
        !          1509:                                            (src->scrub->pfss_flags &
        !          1510:                                            PFSS_TIMESTAMP)) {
        !          1511:                                                tsval = ntohl(tsval);
        !          1512:                                                pf_change_a(&opt[2],
        !          1513:                                                    &th->th_sum,
        !          1514:                                                    htonl(tsval +
        !          1515:                                                    src->scrub->pfss_ts_mod),
        !          1516:                                                    0);
        !          1517:                                                copyback = 1;
        !          1518:                                        }
        !          1519:
        !          1520:                                        /* Modulate TS reply iff valid (!0) */
        !          1521:                                        memcpy(&tsecr, &opt[6],
        !          1522:                                            sizeof(u_int32_t));
        !          1523:                                        if (tsecr && dst->scrub &&
        !          1524:                                            (dst->scrub->pfss_flags &
        !          1525:                                            PFSS_TIMESTAMP)) {
        !          1526:                                                tsecr = ntohl(tsecr)
        !          1527:                                                    - dst->scrub->pfss_ts_mod;
        !          1528:                                                pf_change_a(&opt[6],
        !          1529:                                                    &th->th_sum, htonl(tsecr),
        !          1530:                                                    0);
        !          1531:                                                copyback = 1;
        !          1532:                                        }
        !          1533:                                        got_ts = 1;
        !          1534:                                }
        !          1535:                                /* FALLTHROUGH */
        !          1536:                        default:
        !          1537:                                hlen -= MAX(opt[1], 2);
        !          1538:                                opt += MAX(opt[1], 2);
        !          1539:                                break;
        !          1540:                        }
        !          1541:                }
        !          1542:                if (copyback) {
        !          1543:                        /* Copyback the options, caller copys back header */
        !          1544:                        *writeback = 1;
        !          1545:                        m_copyback(m, off + sizeof(struct tcphdr),
        !          1546:                            (th->th_off << 2) - sizeof(struct tcphdr), hdr +
        !          1547:                            sizeof(struct tcphdr));
        !          1548:                }
        !          1549:        }
        !          1550:
        !          1551:
        !          1552:        /*
        !          1553:         * Must invalidate PAWS checks on connections idle for too long.
        !          1554:         * The fastest allowed timestamp clock is 1ms.  That turns out to
        !          1555:         * be about 24 days before it wraps.  XXX Right now our lowerbound
        !          1556:         * TS echo check only works for the first 12 days of a connection
        !          1557:         * when the TS has exhausted half its 32bit space
        !          1558:         */
        !          1559: #define TS_MAX_IDLE    (24*24*60*60)
        !          1560: #define TS_MAX_CONN    (12*24*60*60)   /* XXX remove when better tsecr check */
        !          1561:
        !          1562:        getmicrouptime(&uptime);
        !          1563:        if (src->scrub && (src->scrub->pfss_flags & PFSS_PAWS) &&
        !          1564:            (uptime.tv_sec - src->scrub->pfss_last.tv_sec > TS_MAX_IDLE ||
        !          1565:            time_second - state->creation > TS_MAX_CONN))  {
        !          1566:                if (pf_status.debug >= PF_DEBUG_MISC) {
        !          1567:                        DPFPRINTF(("src idled out of PAWS\n"));
        !          1568:                        pf_print_state(state);
        !          1569:                        printf("\n");
        !          1570:                }
        !          1571:                src->scrub->pfss_flags = (src->scrub->pfss_flags & ~PFSS_PAWS)
        !          1572:                    | PFSS_PAWS_IDLED;
        !          1573:        }
        !          1574:        if (dst->scrub && (dst->scrub->pfss_flags & PFSS_PAWS) &&
        !          1575:            uptime.tv_sec - dst->scrub->pfss_last.tv_sec > TS_MAX_IDLE) {
        !          1576:                if (pf_status.debug >= PF_DEBUG_MISC) {
        !          1577:                        DPFPRINTF(("dst idled out of PAWS\n"));
        !          1578:                        pf_print_state(state);
        !          1579:                        printf("\n");
        !          1580:                }
        !          1581:                dst->scrub->pfss_flags = (dst->scrub->pfss_flags & ~PFSS_PAWS)
        !          1582:                    | PFSS_PAWS_IDLED;
        !          1583:        }
        !          1584:
        !          1585:        if (got_ts && src->scrub && dst->scrub &&
        !          1586:            (src->scrub->pfss_flags & PFSS_PAWS) &&
        !          1587:            (dst->scrub->pfss_flags & PFSS_PAWS)) {
        !          1588:                /* Validate that the timestamps are "in-window".
        !          1589:                 * RFC1323 describes TCP Timestamp options that allow
        !          1590:                 * measurement of RTT (round trip time) and PAWS
        !          1591:                 * (protection against wrapped sequence numbers).  PAWS
        !          1592:                 * gives us a set of rules for rejecting packets on
        !          1593:                 * long fat pipes (packets that were somehow delayed
        !          1594:                 * in transit longer than the time it took to send the
        !          1595:                 * full TCP sequence space of 4Gb).  We can use these
        !          1596:                 * rules and infer a few others that will let us treat
        !          1597:                 * the 32bit timestamp and the 32bit echoed timestamp
        !          1598:                 * as sequence numbers to prevent a blind attacker from
        !          1599:                 * inserting packets into a connection.
        !          1600:                 *
        !          1601:                 * RFC1323 tells us:
        !          1602:                 *  - The timestamp on this packet must be greater than
        !          1603:                 *    or equal to the last value echoed by the other
        !          1604:                 *    endpoint.  The RFC says those will be discarded
        !          1605:                 *    since it is a dup that has already been acked.
        !          1606:                 *    This gives us a lowerbound on the timestamp.
        !          1607:                 *        timestamp >= other last echoed timestamp
        !          1608:                 *  - The timestamp will be less than or equal to
        !          1609:                 *    the last timestamp plus the time between the
        !          1610:                 *    last packet and now.  The RFC defines the max
        !          1611:                 *    clock rate as 1ms.  We will allow clocks to be
        !          1612:                 *    up to 10% fast and will allow a total difference
        !          1613:                 *    or 30 seconds due to a route change.  And this
        !          1614:                 *    gives us an upperbound on the timestamp.
        !          1615:                 *        timestamp <= last timestamp + max ticks
        !          1616:                 *    We have to be careful here.  Windows will send an
        !          1617:                 *    initial timestamp of zero and then initialize it
        !          1618:                 *    to a random value after the 3whs; presumably to
        !          1619:                 *    avoid a DoS by having to call an expensive RNG
        !          1620:                 *    during a SYN flood.  Proof MS has at least one
        !          1621:                 *    good security geek.
        !          1622:                 *
        !          1623:                 *  - The TCP timestamp option must also echo the other
        !          1624:                 *    endpoints timestamp.  The timestamp echoed is the
        !          1625:                 *    one carried on the earliest unacknowledged segment
        !          1626:                 *    on the left edge of the sequence window.  The RFC
        !          1627:                 *    states that the host will reject any echoed
        !          1628:                 *    timestamps that were larger than any ever sent.
        !          1629:                 *    This gives us an upperbound on the TS echo.
        !          1630:                 *        tescr <= largest_tsval
        !          1631:                 *  - The lowerbound on the TS echo is a little more
        !          1632:                 *    tricky to determine.  The other endpoint's echoed
        !          1633:                 *    values will not decrease.  But there may be
        !          1634:                 *    network conditions that re-order packets and
        !          1635:                 *    cause our view of them to decrease.  For now the
        !          1636:                 *    only lowerbound we can safely determine is that
        !          1637:                 *    the TS echo will never be less than the original
        !          1638:                 *    TS.  XXX There is probably a better lowerbound.
        !          1639:                 *    Remove TS_MAX_CONN with better lowerbound check.
        !          1640:                 *        tescr >= other original TS
        !          1641:                 *
        !          1642:                 * It is also important to note that the fastest
        !          1643:                 * timestamp clock of 1ms will wrap its 32bit space in
        !          1644:                 * 24 days.  So we just disable TS checking after 24
        !          1645:                 * days of idle time.  We actually must use a 12d
        !          1646:                 * connection limit until we can come up with a better
        !          1647:                 * lowerbound to the TS echo check.
        !          1648:                 */
        !          1649:                struct timeval delta_ts;
        !          1650:                int ts_fudge;
        !          1651:
        !          1652:
        !          1653:                /*
        !          1654:                 * PFTM_TS_DIFF is how many seconds of leeway to allow
        !          1655:                 * a host's timestamp.  This can happen if the previous
        !          1656:                 * packet got delayed in transit for much longer than
        !          1657:                 * this packet.
        !          1658:                 */
        !          1659:                if ((ts_fudge = state->rule.ptr->timeout[PFTM_TS_DIFF]) == 0)
        !          1660:                        ts_fudge = pf_default_rule.timeout[PFTM_TS_DIFF];
        !          1661:
        !          1662:
        !          1663:                /* Calculate max ticks since the last timestamp */
        !          1664: #define TS_MAXFREQ     1100            /* RFC max TS freq of 1Khz + 10% skew */
        !          1665: #define TS_MICROSECS   1000000         /* microseconds per second */
        !          1666:                timersub(&uptime, &src->scrub->pfss_last, &delta_ts);
        !          1667:                tsval_from_last = (delta_ts.tv_sec + ts_fudge) * TS_MAXFREQ;
        !          1668:                tsval_from_last += delta_ts.tv_usec / (TS_MICROSECS/TS_MAXFREQ);
        !          1669:
        !          1670:
        !          1671:                if ((src->state >= TCPS_ESTABLISHED &&
        !          1672:                    dst->state >= TCPS_ESTABLISHED) &&
        !          1673:                    (SEQ_LT(tsval, dst->scrub->pfss_tsecr) ||
        !          1674:                    SEQ_GT(tsval, src->scrub->pfss_tsval + tsval_from_last) ||
        !          1675:                    (tsecr && (SEQ_GT(tsecr, dst->scrub->pfss_tsval) ||
        !          1676:                    SEQ_LT(tsecr, dst->scrub->pfss_tsval0))))) {
        !          1677:                        /* Bad RFC1323 implementation or an insertion attack.
        !          1678:                         *
        !          1679:                         * - Solaris 2.6 and 2.7 are known to send another ACK
        !          1680:                         *   after the FIN,FIN|ACK,ACK closing that carries
        !          1681:                         *   an old timestamp.
        !          1682:                         */
        !          1683:
        !          1684:                        DPFPRINTF(("Timestamp failed %c%c%c%c\n",
        !          1685:                            SEQ_LT(tsval, dst->scrub->pfss_tsecr) ? '0' : ' ',
        !          1686:                            SEQ_GT(tsval, src->scrub->pfss_tsval +
        !          1687:                            tsval_from_last) ? '1' : ' ',
        !          1688:                            SEQ_GT(tsecr, dst->scrub->pfss_tsval) ? '2' : ' ',
        !          1689:                            SEQ_LT(tsecr, dst->scrub->pfss_tsval0)? '3' : ' '));
        !          1690:                        DPFPRINTF((" tsval: %lu  tsecr: %lu  +ticks: %lu  "
        !          1691:                            "idle: %lus %lums\n",
        !          1692:                            tsval, tsecr, tsval_from_last, delta_ts.tv_sec,
        !          1693:                            delta_ts.tv_usec / 1000));
        !          1694:                        DPFPRINTF((" src->tsval: %lu  tsecr: %lu\n",
        !          1695:                            src->scrub->pfss_tsval, src->scrub->pfss_tsecr));
        !          1696:                        DPFPRINTF((" dst->tsval: %lu  tsecr: %lu  tsval0: %lu"
        !          1697:                            "\n", dst->scrub->pfss_tsval,
        !          1698:                            dst->scrub->pfss_tsecr, dst->scrub->pfss_tsval0));
        !          1699:                        if (pf_status.debug >= PF_DEBUG_MISC) {
        !          1700:                                pf_print_state(state);
        !          1701:                                pf_print_flags(th->th_flags);
        !          1702:                                printf("\n");
        !          1703:                        }
        !          1704:                        REASON_SET(reason, PFRES_TS);
        !          1705:                        return (PF_DROP);
        !          1706:                }
        !          1707:
        !          1708:                /* XXX I'd really like to require tsecr but it's optional */
        !          1709:
        !          1710:        } else if (!got_ts && (th->th_flags & TH_RST) == 0 &&
        !          1711:            ((src->state == TCPS_ESTABLISHED && dst->state == TCPS_ESTABLISHED)
        !          1712:            || pd->p_len > 0 || (th->th_flags & TH_SYN)) &&
        !          1713:            src->scrub && dst->scrub &&
        !          1714:            (src->scrub->pfss_flags & PFSS_PAWS) &&
        !          1715:            (dst->scrub->pfss_flags & PFSS_PAWS)) {
        !          1716:                /* Didn't send a timestamp.  Timestamps aren't really useful
        !          1717:                 * when:
        !          1718:                 *  - connection opening or closing (often not even sent).
        !          1719:                 *    but we must not let an attacker to put a FIN on a
        !          1720:                 *    data packet to sneak it through our ESTABLISHED check.
        !          1721:                 *  - on a TCP reset.  RFC suggests not even looking at TS.
        !          1722:                 *  - on an empty ACK.  The TS will not be echoed so it will
        !          1723:                 *    probably not help keep the RTT calculation in sync and
        !          1724:                 *    there isn't as much danger when the sequence numbers
        !          1725:                 *    got wrapped.  So some stacks don't include TS on empty
        !          1726:                 *    ACKs :-(
        !          1727:                 *
        !          1728:                 * To minimize the disruption to mostly RFC1323 conformant
        !          1729:                 * stacks, we will only require timestamps on data packets.
        !          1730:                 *
        !          1731:                 * And what do ya know, we cannot require timestamps on data
        !          1732:                 * packets.  There appear to be devices that do legitimate
        !          1733:                 * TCP connection hijacking.  There are HTTP devices that allow
        !          1734:                 * a 3whs (with timestamps) and then buffer the HTTP request.
        !          1735:                 * If the intermediate device has the HTTP response cache, it
        !          1736:                 * will spoof the response but not bother timestamping its
        !          1737:                 * packets.  So we can look for the presence of a timestamp in
        !          1738:                 * the first data packet and if there, require it in all future
        !          1739:                 * packets.
        !          1740:                 */
        !          1741:
        !          1742:                if (pd->p_len > 0 && (src->scrub->pfss_flags & PFSS_DATA_TS)) {
        !          1743:                        /*
        !          1744:                         * Hey!  Someone tried to sneak a packet in.  Or the
        !          1745:                         * stack changed its RFC1323 behavior?!?!
        !          1746:                         */
        !          1747:                        if (pf_status.debug >= PF_DEBUG_MISC) {
        !          1748:                                DPFPRINTF(("Did not receive expected RFC1323 "
        !          1749:                                    "timestamp\n"));
        !          1750:                                pf_print_state(state);
        !          1751:                                pf_print_flags(th->th_flags);
        !          1752:                                printf("\n");
        !          1753:                        }
        !          1754:                        REASON_SET(reason, PFRES_TS);
        !          1755:                        return (PF_DROP);
        !          1756:                }
        !          1757:        }
        !          1758:
        !          1759:
        !          1760:        /*
        !          1761:         * We will note if a host sends his data packets with or without
        !          1762:         * timestamps.  And require all data packets to contain a timestamp
        !          1763:         * if the first does.  PAWS implicitly requires that all data packets be
        !          1764:         * timestamped.  But I think there are middle-man devices that hijack
        !          1765:         * TCP streams immediately after the 3whs and don't timestamp their
        !          1766:         * packets (seen in a WWW accelerator or cache).
        !          1767:         */
        !          1768:        if (pd->p_len > 0 && src->scrub && (src->scrub->pfss_flags &
        !          1769:            (PFSS_TIMESTAMP|PFSS_DATA_TS|PFSS_DATA_NOTS)) == PFSS_TIMESTAMP) {
        !          1770:                if (got_ts)
        !          1771:                        src->scrub->pfss_flags |= PFSS_DATA_TS;
        !          1772:                else {
        !          1773:                        src->scrub->pfss_flags |= PFSS_DATA_NOTS;
        !          1774:                        if (pf_status.debug >= PF_DEBUG_MISC && dst->scrub &&
        !          1775:                            (dst->scrub->pfss_flags & PFSS_TIMESTAMP)) {
        !          1776:                                /* Don't warn if other host rejected RFC1323 */
        !          1777:                                DPFPRINTF(("Broken RFC1323 stack did not "
        !          1778:                                    "timestamp data packet. Disabled PAWS "
        !          1779:                                    "security.\n"));
        !          1780:                                pf_print_state(state);
        !          1781:                                pf_print_flags(th->th_flags);
        !          1782:                                printf("\n");
        !          1783:                        }
        !          1784:                }
        !          1785:        }
        !          1786:
        !          1787:
        !          1788:        /*
        !          1789:         * Update PAWS values
        !          1790:         */
        !          1791:        if (got_ts && src->scrub && PFSS_TIMESTAMP == (src->scrub->pfss_flags &
        !          1792:            (PFSS_PAWS_IDLED|PFSS_TIMESTAMP))) {
        !          1793:                getmicrouptime(&src->scrub->pfss_last);
        !          1794:                if (SEQ_GEQ(tsval, src->scrub->pfss_tsval) ||
        !          1795:                    (src->scrub->pfss_flags & PFSS_PAWS) == 0)
        !          1796:                        src->scrub->pfss_tsval = tsval;
        !          1797:
        !          1798:                if (tsecr) {
        !          1799:                        if (SEQ_GEQ(tsecr, src->scrub->pfss_tsecr) ||
        !          1800:                            (src->scrub->pfss_flags & PFSS_PAWS) == 0)
        !          1801:                                src->scrub->pfss_tsecr = tsecr;
        !          1802:
        !          1803:                        if ((src->scrub->pfss_flags & PFSS_PAWS) == 0 &&
        !          1804:                            (SEQ_LT(tsval, src->scrub->pfss_tsval0) ||
        !          1805:                            src->scrub->pfss_tsval0 == 0)) {
        !          1806:                                /* tsval0 MUST be the lowest timestamp */
        !          1807:                                src->scrub->pfss_tsval0 = tsval;
        !          1808:                        }
        !          1809:
        !          1810:                        /* Only fully initialized after a TS gets echoed */
        !          1811:                        if ((src->scrub->pfss_flags & PFSS_PAWS) == 0)
        !          1812:                                src->scrub->pfss_flags |= PFSS_PAWS;
        !          1813:                }
        !          1814:        }
        !          1815:
        !          1816:        /* I have a dream....  TCP segment reassembly.... */
        !          1817:        return (0);
        !          1818: }
        !          1819:
        !          1820: int
        !          1821: pf_normalize_tcpopt(struct pf_rule *r, struct mbuf *m, struct tcphdr *th,
        !          1822:     int off)
        !          1823: {
        !          1824:        u_int16_t       *mss;
        !          1825:        int              thoff;
        !          1826:        int              opt, cnt, optlen = 0;
        !          1827:        int              rewrite = 0;
        !          1828:        u_char          *optp;
        !          1829:
        !          1830:        thoff = th->th_off << 2;
        !          1831:        cnt = thoff - sizeof(struct tcphdr);
        !          1832:        optp = mtod(m, caddr_t) + off + sizeof(struct tcphdr);
        !          1833:
        !          1834:        for (; cnt > 0; cnt -= optlen, optp += optlen) {
        !          1835:                opt = optp[0];
        !          1836:                if (opt == TCPOPT_EOL)
        !          1837:                        break;
        !          1838:                if (opt == TCPOPT_NOP)
        !          1839:                        optlen = 1;
        !          1840:                else {
        !          1841:                        if (cnt < 2)
        !          1842:                                break;
        !          1843:                        optlen = optp[1];
        !          1844:                        if (optlen < 2 || optlen > cnt)
        !          1845:                                break;
        !          1846:                }
        !          1847:                switch (opt) {
        !          1848:                case TCPOPT_MAXSEG:
        !          1849:                        mss = (u_int16_t *)(optp + 2);
        !          1850:                        if ((ntohs(*mss)) > r->max_mss) {
        !          1851:                                th->th_sum = pf_cksum_fixup(th->th_sum,
        !          1852:                                    *mss, htons(r->max_mss), 0);
        !          1853:                                *mss = htons(r->max_mss);
        !          1854:                                rewrite = 1;
        !          1855:                        }
        !          1856:                        break;
        !          1857:                default:
        !          1858:                        break;
        !          1859:                }
        !          1860:        }
        !          1861:
        !          1862:        return (rewrite);
        !          1863: }

CVSweb