source: rtems-libbsd/freebsd/sys/contrib/pf/net/pf_norm.c @ 66659ff

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 66659ff was 66659ff, checked in by Sebastian Huber <sebastian.huber@…>, on 11/06/13 at 15:20:21

Update to FreeBSD 9.2

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