]>
git.saurik.com Git - apple/xnu.git/blob - bsd/net/pf_norm.c
2 * Copyright (c) 2007-2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 /* $apfw: pf_norm.c,v 1.10 2008/08/28 19:10:53 jhw Exp $ */
30 /* $OpenBSD: pf_norm.c,v 1.107 2006/04/16 00:59:52 pascoe Exp $ */
33 * Copyright 2001 Niels Provos <provos@citi.umich.edu>
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 #include <sys/param.h>
58 #include <sys/systm.h>
60 #include <sys/filio.h>
61 #include <sys/fcntl.h>
62 #include <sys/socket.h>
63 #include <sys/kernel.h>
65 #include <sys/random.h>
66 #include <sys/mcache.h>
69 #include <net/if_types.h>
71 #include <net/route.h>
72 #include <net/if_pflog.h>
74 #include <netinet/in.h>
75 #include <netinet/in_var.h>
76 #include <netinet/in_systm.h>
77 #include <netinet/ip.h>
78 #include <netinet/ip_var.h>
79 #include <netinet/tcp.h>
80 #include <netinet/tcp_seq.h>
81 #include <netinet/tcp_fsm.h>
82 #include <netinet/udp.h>
83 #include <netinet/ip_icmp.h>
86 #include <netinet/ip6.h>
89 #include <net/pfvar.h>
92 LIST_ENTRY(pf_frent
) fr_next
;
94 #define fr_ip fr_u.fru_ipv4
95 #define fr_ip6 fr_u.fru_ipv6
98 struct ip6_hdr
*fru_ipv6
;
100 struct ip6_frag fr_ip6f_opt
;
105 LIST_ENTRY(pf_frcache
) fr_next
;
110 #define PFFRAG_SEENLAST 0x0001 /* Seen the last fragment for this */
111 #define PFFRAG_NOBUFFER 0x0002 /* Non-buffering fragment cache */
112 #define PFFRAG_DROP 0x0004 /* Drop all fragments */
113 #define BUFFER_FRAGMENTS(fr) (!((fr)->fr_flags & PFFRAG_NOBUFFER))
116 RB_ENTRY(pf_fragment
) fr_entry
;
117 TAILQ_ENTRY(pf_fragment
) frag_next
;
118 struct pf_addr fr_srcx
;
119 struct pf_addr fr_dstx
;
120 u_int8_t fr_p
; /* protocol of this fragment */
121 u_int8_t fr_flags
; /* status flags */
122 u_int16_t fr_max
; /* fragment data max */
123 #define fr_id fr_uid.fru_id4
124 #define fr_id6 fr_uid.fru_id6
130 u_int32_t fr_timeout
;
131 #define fr_queue fr_u.fru_queue
132 #define fr_cache fr_u.fru_cache
134 LIST_HEAD(pf_fragq
, pf_frent
) fru_queue
; /* buffering */
135 LIST_HEAD(pf_cacheq
, pf_frcache
) fru_cache
; /* non-buf */
139 static TAILQ_HEAD(pf_fragqueue
, pf_fragment
) pf_fragqueue
;
140 static TAILQ_HEAD(pf_cachequeue
, pf_fragment
) pf_cachequeue
;
142 static __inline
int pf_frag_compare(struct pf_fragment
*,
143 struct pf_fragment
*);
144 static RB_HEAD(pf_frag_tree
, pf_fragment
) pf_frag_tree
, pf_cache_tree
;
145 RB_PROTOTYPE_SC(__private_extern__
, pf_frag_tree
, pf_fragment
, fr_entry
,
147 RB_GENERATE(pf_frag_tree
, pf_fragment
, fr_entry
, pf_frag_compare
);
149 /* Private prototypes */
150 static void pf_ip6hdr2key(struct pf_fragment
*, struct ip6_hdr
*,
152 static void pf_ip2key(struct pf_fragment
*, struct ip
*);
153 static void pf_remove_fragment(struct pf_fragment
*);
154 static void pf_flush_fragments(void);
155 static void pf_free_fragment(struct pf_fragment
*);
156 static struct pf_fragment
*pf_find_fragment_by_key(struct pf_fragment
*,
157 struct pf_frag_tree
*);
158 static __inline
struct pf_fragment
*
159 pf_find_fragment_by_ipv4_header(struct ip
*, struct pf_frag_tree
*);
160 static __inline
struct pf_fragment
*
161 pf_find_fragment_by_ipv6_header(struct ip6_hdr
*, struct ip6_frag
*,
162 struct pf_frag_tree
*);
163 static struct mbuf
*pf_reassemble(struct mbuf
**, struct pf_fragment
**,
164 struct pf_frent
*, int);
165 static struct mbuf
*pf_fragcache(struct mbuf
**, struct ip
*,
166 struct pf_fragment
**, int, int, int *);
167 static struct mbuf
*pf_reassemble6(struct mbuf
**, struct pf_fragment
**,
168 struct pf_frent
*, int);
169 static struct mbuf
*pf_frag6cache(struct mbuf
**, struct ip6_hdr
*,
170 struct ip6_frag
*, struct pf_fragment
**, int, int, int, int *);
171 static int pf_normalize_tcpopt(struct pf_rule
*, int, struct pfi_kif
*,
172 struct pf_pdesc
*, struct mbuf
*, struct tcphdr
*, int, int *);
174 #define DPFPRINTF(x) do { \
175 if (pf_status.debug >= PF_DEBUG_MISC) { \
176 printf("%s: ", __func__); \
182 struct pool pf_frent_pl
, pf_frag_pl
;
183 static struct pool pf_cache_pl
, pf_cent_pl
;
184 struct pool pf_state_scrub_pl
;
186 static int pf_nfrents
, pf_ncache
;
189 pf_normalize_init(void)
191 pool_init(&pf_frent_pl
, sizeof (struct pf_frent
), 0, 0, 0, "pffrent",
193 pool_init(&pf_frag_pl
, sizeof (struct pf_fragment
), 0, 0, 0, "pffrag",
195 pool_init(&pf_cache_pl
, sizeof (struct pf_fragment
), 0, 0, 0,
197 pool_init(&pf_cent_pl
, sizeof (struct pf_frcache
), 0, 0, 0, "pffrcent",
199 pool_init(&pf_state_scrub_pl
, sizeof (struct pf_state_scrub
), 0, 0, 0,
202 pool_sethiwat(&pf_frag_pl
, PFFRAG_FRAG_HIWAT
);
203 pool_sethardlimit(&pf_frent_pl
, PFFRAG_FRENT_HIWAT
, NULL
, 0);
204 pool_sethardlimit(&pf_cache_pl
, PFFRAG_FRCACHE_HIWAT
, NULL
, 0);
205 pool_sethardlimit(&pf_cent_pl
, PFFRAG_FRCENT_HIWAT
, NULL
, 0);
207 TAILQ_INIT(&pf_fragqueue
);
208 TAILQ_INIT(&pf_cachequeue
);
213 pf_normalize_destroy(void)
215 pool_destroy(&pf_state_scrub_pl
);
216 pool_destroy(&pf_cent_pl
);
217 pool_destroy(&pf_cache_pl
);
218 pool_destroy(&pf_frag_pl
);
219 pool_destroy(&pf_frent_pl
);
224 pf_normalize_isempty(void)
226 return (TAILQ_EMPTY(&pf_fragqueue
) && TAILQ_EMPTY(&pf_cachequeue
));
230 pf_frag_compare(struct pf_fragment
*a
, struct pf_fragment
*b
)
234 if ((diff
= a
->fr_af
- b
->fr_af
))
236 else if ((diff
= a
->fr_p
- b
->fr_p
))
239 struct pf_addr
*sa
= &a
->fr_srcx
;
240 struct pf_addr
*sb
= &b
->fr_srcx
;
241 struct pf_addr
*da
= &a
->fr_dstx
;
242 struct pf_addr
*db
= &b
->fr_dstx
;
247 if ((diff
= a
->fr_id
- b
->fr_id
))
249 else if (sa
->v4
.s_addr
< sb
->v4
.s_addr
)
251 else if (sa
->v4
.s_addr
> sb
->v4
.s_addr
)
253 else if (da
->v4
.s_addr
< db
->v4
.s_addr
)
255 else if (da
->v4
.s_addr
> db
->v4
.s_addr
)
261 if ((diff
= a
->fr_id6
- b
->fr_id6
))
263 else if (sa
->addr32
[3] < sb
->addr32
[3])
265 else if (sa
->addr32
[3] > sb
->addr32
[3])
267 else if (sa
->addr32
[2] < sb
->addr32
[2])
269 else if (sa
->addr32
[2] > sb
->addr32
[2])
271 else if (sa
->addr32
[1] < sb
->addr32
[1])
273 else if (sa
->addr32
[1] > sb
->addr32
[1])
275 else if (sa
->addr32
[0] < sb
->addr32
[0])
277 else if (sa
->addr32
[0] > sb
->addr32
[0])
279 else if (da
->addr32
[3] < db
->addr32
[3])
281 else if (da
->addr32
[3] > db
->addr32
[3])
283 else if (da
->addr32
[2] < db
->addr32
[2])
285 else if (da
->addr32
[2] > db
->addr32
[2])
287 else if (da
->addr32
[1] < db
->addr32
[1])
289 else if (da
->addr32
[1] > db
->addr32
[1])
291 else if (da
->addr32
[0] < db
->addr32
[0])
293 else if (da
->addr32
[0] > db
->addr32
[0])
298 VERIFY(!0 && "only IPv4 and IPv6 supported!");
306 pf_purge_expired_fragments(void)
308 struct pf_fragment
*frag
;
309 u_int32_t expire
= pf_time_second() -
310 pf_default_rule
.timeout
[PFTM_FRAG
];
312 while ((frag
= TAILQ_LAST(&pf_fragqueue
, pf_fragqueue
)) != NULL
) {
313 VERIFY(BUFFER_FRAGMENTS(frag
));
314 if (frag
->fr_timeout
> expire
)
317 switch (frag
->fr_af
) {
319 DPFPRINTF(("expiring IPv4 %d(0x%llx) from queue.\n",
321 (uint64_t)VM_KERNEL_ADDRPERM(frag
)));
324 DPFPRINTF(("expiring IPv6 %d(0x%llx) from queue.\n",
326 (uint64_t)VM_KERNEL_ADDRPERM(frag
)));
329 VERIFY(0 && "only IPv4 and IPv6 supported");
332 pf_free_fragment(frag
);
335 while ((frag
= TAILQ_LAST(&pf_cachequeue
, pf_cachequeue
)) != NULL
) {
336 VERIFY(!BUFFER_FRAGMENTS(frag
));
337 if (frag
->fr_timeout
> expire
)
340 switch (frag
->fr_af
) {
342 DPFPRINTF(("expiring IPv4 %d(0x%llx) from cache.\n",
344 (uint64_t)VM_KERNEL_ADDRPERM(frag
)));
347 DPFPRINTF(("expiring IPv6 %d(0x%llx) from cache.\n",
349 (uint64_t)VM_KERNEL_ADDRPERM(frag
)));
352 VERIFY(0 && "only IPv4 and IPv6 supported");
355 pf_free_fragment(frag
);
356 VERIFY(TAILQ_EMPTY(&pf_cachequeue
) ||
357 TAILQ_LAST(&pf_cachequeue
, pf_cachequeue
) != frag
);
362 * Try to flush old fragments to make space for new ones
366 pf_flush_fragments(void)
368 struct pf_fragment
*frag
;
371 goal
= pf_nfrents
* 9 / 10;
372 DPFPRINTF(("trying to free > %d frents\n",
374 while (goal
< pf_nfrents
) {
375 frag
= TAILQ_LAST(&pf_fragqueue
, pf_fragqueue
);
378 pf_free_fragment(frag
);
382 goal
= pf_ncache
* 9 / 10;
383 DPFPRINTF(("trying to free > %d cache entries\n",
385 while (goal
< pf_ncache
) {
386 frag
= TAILQ_LAST(&pf_cachequeue
, pf_cachequeue
);
389 pf_free_fragment(frag
);
393 /* Frees the fragments and all associated entries */
396 pf_free_fragment(struct pf_fragment
*frag
)
398 struct pf_frent
*frent
;
399 struct pf_frcache
*frcache
;
401 /* Free all fragments */
402 if (BUFFER_FRAGMENTS(frag
)) {
403 for (frent
= LIST_FIRST(&frag
->fr_queue
); frent
;
404 frent
= LIST_FIRST(&frag
->fr_queue
)) {
405 LIST_REMOVE(frent
, fr_next
);
407 m_freem(frent
->fr_m
);
408 pool_put(&pf_frent_pl
, frent
);
412 for (frcache
= LIST_FIRST(&frag
->fr_cache
); frcache
;
413 frcache
= LIST_FIRST(&frag
->fr_cache
)) {
414 LIST_REMOVE(frcache
, fr_next
);
416 VERIFY(LIST_EMPTY(&frag
->fr_cache
) ||
417 LIST_FIRST(&frag
->fr_cache
)->fr_off
>
420 pool_put(&pf_cent_pl
, frcache
);
425 pf_remove_fragment(frag
);
429 pf_ip6hdr2key(struct pf_fragment
*key
, struct ip6_hdr
*ip6
,
432 key
->fr_p
= fh
->ip6f_nxt
;
433 key
->fr_id6
= fh
->ip6f_ident
;
434 key
->fr_af
= AF_INET6
;
435 key
->fr_srcx
.v6
= ip6
->ip6_src
;
436 key
->fr_dstx
.v6
= ip6
->ip6_dst
;
440 pf_ip2key(struct pf_fragment
*key
, struct ip
*ip
)
442 key
->fr_p
= ip
->ip_p
;
443 key
->fr_id
= ip
->ip_id
;
444 key
->fr_af
= AF_INET
;
445 key
->fr_srcx
.v4
.s_addr
= ip
->ip_src
.s_addr
;
446 key
->fr_dstx
.v4
.s_addr
= ip
->ip_dst
.s_addr
;
449 static struct pf_fragment
*
450 pf_find_fragment_by_key(struct pf_fragment
*key
, struct pf_frag_tree
*tree
)
452 struct pf_fragment
*frag
;
454 frag
= RB_FIND(pf_frag_tree
, tree
, key
);
456 /* XXX Are we sure we want to update the timeout? */
457 frag
->fr_timeout
= pf_time_second();
458 if (BUFFER_FRAGMENTS(frag
)) {
459 TAILQ_REMOVE(&pf_fragqueue
, frag
, frag_next
);
460 TAILQ_INSERT_HEAD(&pf_fragqueue
, frag
, frag_next
);
462 TAILQ_REMOVE(&pf_cachequeue
, frag
, frag_next
);
463 TAILQ_INSERT_HEAD(&pf_cachequeue
, frag
, frag_next
);
470 static __inline
struct pf_fragment
*
471 pf_find_fragment_by_ipv4_header(struct ip
*ip
, struct pf_frag_tree
*tree
)
473 struct pf_fragment key
;
475 return pf_find_fragment_by_key(&key
, tree
);
478 static __inline
struct pf_fragment
*
479 pf_find_fragment_by_ipv6_header(struct ip6_hdr
*ip6
, struct ip6_frag
*fh
,
480 struct pf_frag_tree
*tree
)
482 struct pf_fragment key
;
483 pf_ip6hdr2key(&key
, ip6
, fh
);
484 return pf_find_fragment_by_key(&key
, tree
);
487 /* Removes a fragment from the fragment queue and frees the fragment */
490 pf_remove_fragment(struct pf_fragment
*frag
)
492 if (BUFFER_FRAGMENTS(frag
)) {
493 RB_REMOVE(pf_frag_tree
, &pf_frag_tree
, frag
);
494 TAILQ_REMOVE(&pf_fragqueue
, frag
, frag_next
);
495 pool_put(&pf_frag_pl
, frag
);
497 RB_REMOVE(pf_frag_tree
, &pf_cache_tree
, frag
);
498 TAILQ_REMOVE(&pf_cachequeue
, frag
, frag_next
);
499 pool_put(&pf_cache_pl
, frag
);
503 #define FR_IP_OFF(fr) ((ntohs((fr)->fr_ip->ip_off) & IP_OFFMASK) << 3)
505 pf_reassemble(struct mbuf
**m0
, struct pf_fragment
**frag
,
506 struct pf_frent
*frent
, int mff
)
508 struct mbuf
*m
= *m0
, *m2
;
509 struct pf_frent
*frea
, *next
;
510 struct pf_frent
*frep
= NULL
;
511 struct ip
*ip
= frent
->fr_ip
;
512 int hlen
= ip
->ip_hl
<< 2;
513 u_int16_t off
= (ntohs(ip
->ip_off
) & IP_OFFMASK
) << 3;
514 u_int16_t ip_len
= ntohs(ip
->ip_len
) - ip
->ip_hl
* 4;
515 u_int16_t fr_max
= ip_len
+ off
;
517 VERIFY(*frag
== NULL
|| BUFFER_FRAGMENTS(*frag
));
519 /* Strip off ip header */
523 /* Create a new reassembly queue for this packet */
525 *frag
= pool_get(&pf_frag_pl
, PR_NOWAIT
);
527 pf_flush_fragments();
528 *frag
= pool_get(&pf_frag_pl
, PR_NOWAIT
);
533 (*frag
)->fr_flags
= 0;
535 (*frag
)->fr_af
= AF_INET
;
536 (*frag
)->fr_srcx
.v4
= frent
->fr_ip
->ip_src
;
537 (*frag
)->fr_dstx
.v4
= frent
->fr_ip
->ip_dst
;
538 (*frag
)->fr_p
= frent
->fr_ip
->ip_p
;
539 (*frag
)->fr_id
= frent
->fr_ip
->ip_id
;
540 (*frag
)->fr_timeout
= pf_time_second();
541 LIST_INIT(&(*frag
)->fr_queue
);
543 RB_INSERT(pf_frag_tree
, &pf_frag_tree
, *frag
);
544 TAILQ_INSERT_HEAD(&pf_fragqueue
, *frag
, frag_next
);
546 /* We do not have a previous fragment */
552 * Find a fragment after the current one:
553 * - off contains the real shifted offset.
555 LIST_FOREACH(frea
, &(*frag
)->fr_queue
, fr_next
) {
556 if (FR_IP_OFF(frea
) > off
)
561 VERIFY(frep
!= NULL
|| frea
!= NULL
);
564 FR_IP_OFF(frep
) + ntohs(frep
->fr_ip
->ip_len
) - frep
->fr_ip
->ip_hl
*
568 precut
= FR_IP_OFF(frep
) + ntohs(frep
->fr_ip
->ip_len
) -
569 frep
->fr_ip
->ip_hl
* 4 - off
;
570 if (precut
>= ip_len
)
572 m_adj(frent
->fr_m
, precut
);
573 DPFPRINTF(("overlap -%d\n", precut
));
574 /* Enforce 8 byte boundaries */
575 ip
->ip_off
= htons(ntohs(ip
->ip_off
) + (precut
>> 3));
576 off
= (ntohs(ip
->ip_off
) & IP_OFFMASK
) << 3;
578 ip
->ip_len
= htons(ip_len
);
581 for (; frea
!= NULL
&& ip_len
+ off
> FR_IP_OFF(frea
);
585 aftercut
= ip_len
+ off
- FR_IP_OFF(frea
);
586 DPFPRINTF(("adjust overlap %d\n", aftercut
));
587 if (aftercut
< ntohs(frea
->fr_ip
->ip_len
) - frea
->fr_ip
->ip_hl
589 frea
->fr_ip
->ip_len
=
590 htons(ntohs(frea
->fr_ip
->ip_len
) - aftercut
);
591 frea
->fr_ip
->ip_off
= htons(ntohs(frea
->fr_ip
->ip_off
) +
593 m_adj(frea
->fr_m
, aftercut
);
597 /* This fragment is completely overlapped, lose it */
598 next
= LIST_NEXT(frea
, fr_next
);
600 LIST_REMOVE(frea
, fr_next
);
601 pool_put(&pf_frent_pl
, frea
);
606 /* Update maximum data size */
607 if ((*frag
)->fr_max
< fr_max
)
608 (*frag
)->fr_max
= fr_max
;
609 /* This is the last segment */
611 (*frag
)->fr_flags
|= PFFRAG_SEENLAST
;
614 LIST_INSERT_HEAD(&(*frag
)->fr_queue
, frent
, fr_next
);
616 LIST_INSERT_AFTER(frep
, frent
, fr_next
);
618 /* Check if we are completely reassembled */
619 if (!((*frag
)->fr_flags
& PFFRAG_SEENLAST
))
622 /* Check if we have all the data */
624 for (frep
= LIST_FIRST(&(*frag
)->fr_queue
); frep
; frep
= next
) {
625 next
= LIST_NEXT(frep
, fr_next
);
627 off
+= ntohs(frep
->fr_ip
->ip_len
) - frep
->fr_ip
->ip_hl
* 4;
628 if (off
< (*frag
)->fr_max
&&
629 (next
== NULL
|| FR_IP_OFF(next
) != off
)) {
630 DPFPRINTF(("missing fragment at %d, next %d, max %d\n",
631 off
, next
== NULL
? -1 : FR_IP_OFF(next
),
636 DPFPRINTF(("%d < %d?\n", off
, (*frag
)->fr_max
));
637 if (off
< (*frag
)->fr_max
)
640 /* We have all the data */
641 frent
= LIST_FIRST(&(*frag
)->fr_queue
);
642 VERIFY(frent
!= NULL
);
643 if ((frent
->fr_ip
->ip_hl
<< 2) + off
> IP_MAXPACKET
) {
644 DPFPRINTF(("drop: too big: %d\n", off
));
645 pf_free_fragment(*frag
);
649 next
= LIST_NEXT(frent
, fr_next
);
651 /* Magic from ip_input */
657 pool_put(&pf_frent_pl
, frent
);
659 for (frent
= next
; frent
!= NULL
; frent
= next
) {
660 next
= LIST_NEXT(frent
, fr_next
);
663 pool_put(&pf_frent_pl
, frent
);
668 ip
->ip_src
= (*frag
)->fr_srcx
.v4
;
669 ip
->ip_dst
= (*frag
)->fr_dstx
.v4
;
671 /* Remove from fragment queue */
672 pf_remove_fragment(*frag
);
675 hlen
= ip
->ip_hl
<< 2;
676 ip
->ip_len
= htons(off
+ hlen
);
680 /* some debugging cruft by sklower, below, will go away soon */
681 /* XXX this should be done elsewhere */
682 if (m
->m_flags
& M_PKTHDR
) {
684 for (m2
= m
; m2
; m2
= m2
->m_next
)
686 m
->m_pkthdr
.len
= plen
;
689 DPFPRINTF(("complete: 0x%llx(%d)\n",
690 (uint64_t)VM_KERNEL_ADDRPERM(m
), ntohs(ip
->ip_len
)));
694 /* Oops - fail safe - drop packet */
695 pool_put(&pf_frent_pl
, frent
);
702 pf_fragcache(struct mbuf
**m0
, struct ip
*h
, struct pf_fragment
**frag
, int mff
,
703 int drop
, int *nomem
)
705 struct mbuf
*m
= *m0
;
706 struct pf_frcache
*frp
, *fra
, *cur
= NULL
;
707 int ip_len
= ntohs(h
->ip_len
) - (h
->ip_hl
<< 2);
708 u_int16_t off
= ntohs(h
->ip_off
) << 3;
709 u_int16_t fr_max
= ip_len
+ off
;
712 VERIFY(*frag
== NULL
|| !BUFFER_FRAGMENTS(*frag
));
714 /* Create a new range queue for this packet */
716 *frag
= pool_get(&pf_cache_pl
, PR_NOWAIT
);
718 pf_flush_fragments();
719 *frag
= pool_get(&pf_cache_pl
, PR_NOWAIT
);
724 /* Get an entry for the queue */
725 cur
= pool_get(&pf_cent_pl
, PR_NOWAIT
);
727 pool_put(&pf_cache_pl
, *frag
);
733 (*frag
)->fr_flags
= PFFRAG_NOBUFFER
;
735 (*frag
)->fr_af
= AF_INET
;
736 (*frag
)->fr_srcx
.v4
= h
->ip_src
;
737 (*frag
)->fr_dstx
.v4
= h
->ip_dst
;
738 (*frag
)->fr_p
= h
->ip_p
;
739 (*frag
)->fr_id
= h
->ip_id
;
740 (*frag
)->fr_timeout
= pf_time_second();
743 cur
->fr_end
= fr_max
;
744 LIST_INIT(&(*frag
)->fr_cache
);
745 LIST_INSERT_HEAD(&(*frag
)->fr_cache
, cur
, fr_next
);
747 RB_INSERT(pf_frag_tree
, &pf_cache_tree
, *frag
);
748 TAILQ_INSERT_HEAD(&pf_cachequeue
, *frag
, frag_next
);
750 DPFPRINTF(("fragcache[%d]: new %d-%d\n", h
->ip_id
, off
,
757 * Find a fragment after the current one:
758 * - off contains the real shifted offset.
761 LIST_FOREACH(fra
, &(*frag
)->fr_cache
, fr_next
) {
762 if (fra
->fr_off
> off
)
767 VERIFY(frp
!= NULL
|| fra
!= NULL
);
772 precut
= frp
->fr_end
- off
;
773 if (precut
>= ip_len
) {
774 /* Fragment is entirely a duplicate */
775 DPFPRINTF(("fragcache[%d]: dead (%d-%d) %d-%d\n",
776 h
->ip_id
, frp
->fr_off
, frp
->fr_end
, off
, fr_max
));
780 /* They are adjacent. Fixup cache entry */
781 DPFPRINTF(("fragcache[%d]: adjacent (%d-%d) %d-%d\n",
782 h
->ip_id
, frp
->fr_off
, frp
->fr_end
, off
, fr_max
));
783 frp
->fr_end
= fr_max
;
784 } else if (precut
> 0) {
786 * The first part of this payload overlaps with a
787 * fragment that has already been passed.
788 * Need to trim off the first part of the payload.
789 * But to do so easily, we need to create another
790 * mbuf to throw the original header into.
793 DPFPRINTF(("fragcache[%d]: chop %d (%d-%d) %d-%d\n",
794 h
->ip_id
, precut
, frp
->fr_off
, frp
->fr_end
, off
,
799 /* Update the previous frag to encompass this one */
800 frp
->fr_end
= fr_max
;
804 * XXX Optimization opportunity
805 * This is a very heavy way to trim the payload.
806 * we could do it much faster by diddling mbuf
807 * internals but that would be even less legible
808 * than this mbuf magic. For my next trick,
809 * I'll pull a rabbit out of my laptop.
811 *m0
= m_copym(m
, 0, h
->ip_hl
<< 2, M_NOWAIT
);
814 VERIFY((*m0
)->m_next
== NULL
);
815 m_adj(m
, precut
+ (h
->ip_hl
<< 2));
818 if (m
->m_flags
& M_PKTHDR
) {
821 for (t
= m
; t
; t
= t
->m_next
)
823 m
->m_pkthdr
.len
= plen
;
827 h
= mtod(m
, struct ip
*);
830 VERIFY((int)m
->m_len
==
831 ntohs(h
->ip_len
) - precut
);
832 h
->ip_off
= htons(ntohs(h
->ip_off
) +
834 h
->ip_len
= htons(ntohs(h
->ip_len
) - precut
);
839 /* There is a gap between fragments */
841 DPFPRINTF(("fragcache[%d]: gap %d (%d-%d) %d-%d\n",
842 h
->ip_id
, -precut
, frp
->fr_off
, frp
->fr_end
, off
,
845 cur
= pool_get(&pf_cent_pl
, PR_NOWAIT
);
851 cur
->fr_end
= fr_max
;
852 LIST_INSERT_AFTER(frp
, cur
, fr_next
);
860 aftercut
= fr_max
- fra
->fr_off
;
862 /* Adjacent fragments */
863 DPFPRINTF(("fragcache[%d]: adjacent %d-%d (%d-%d)\n",
864 h
->ip_id
, off
, fr_max
, fra
->fr_off
, fra
->fr_end
));
867 } else if (aftercut
> 0) {
868 /* Need to chop off the tail of this fragment */
869 DPFPRINTF(("fragcache[%d]: chop %d %d-%d (%d-%d)\n",
870 h
->ip_id
, aftercut
, off
, fr_max
, fra
->fr_off
,
879 if (m
->m_flags
& M_PKTHDR
) {
882 for (t
= m
; t
; t
= t
->m_next
)
884 m
->m_pkthdr
.len
= plen
;
886 h
= mtod(m
, struct ip
*);
887 VERIFY((int)m
->m_len
==
888 ntohs(h
->ip_len
) - aftercut
);
889 h
->ip_len
= htons(ntohs(h
->ip_len
) - aftercut
);
893 } else if (frp
== NULL
) {
894 /* There is a gap between fragments */
895 DPFPRINTF(("fragcache[%d]: gap %d %d-%d (%d-%d)\n",
896 h
->ip_id
, -aftercut
, off
, fr_max
, fra
->fr_off
,
899 cur
= pool_get(&pf_cent_pl
, PR_NOWAIT
);
905 cur
->fr_end
= fr_max
;
906 LIST_INSERT_BEFORE(fra
, cur
, fr_next
);
910 /* Need to glue together two separate fragment descriptors */
912 if (cur
&& fra
->fr_off
<= cur
->fr_end
) {
913 /* Need to merge in a previous 'cur' */
914 DPFPRINTF(("fragcache[%d]: adjacent(merge "
915 "%d-%d) %d-%d (%d-%d)\n",
916 h
->ip_id
, cur
->fr_off
, cur
->fr_end
, off
,
917 fr_max
, fra
->fr_off
, fra
->fr_end
));
918 fra
->fr_off
= cur
->fr_off
;
919 LIST_REMOVE(cur
, fr_next
);
920 pool_put(&pf_cent_pl
, cur
);
924 } else if (frp
&& fra
->fr_off
<= frp
->fr_end
) {
925 /* Need to merge in a modified 'frp' */
927 DPFPRINTF(("fragcache[%d]: adjacent(merge "
928 "%d-%d) %d-%d (%d-%d)\n",
929 h
->ip_id
, frp
->fr_off
, frp
->fr_end
, off
,
930 fr_max
, fra
->fr_off
, fra
->fr_end
));
931 fra
->fr_off
= frp
->fr_off
;
932 LIST_REMOVE(frp
, fr_next
);
933 pool_put(&pf_cent_pl
, frp
);
943 * We must keep tracking the overall fragment even when
944 * we're going to drop it anyway so that we know when to
945 * free the overall descriptor. Thus we drop the frag late.
952 /* Update maximum data size */
953 if ((*frag
)->fr_max
< fr_max
)
954 (*frag
)->fr_max
= fr_max
;
956 /* This is the last segment */
958 (*frag
)->fr_flags
|= PFFRAG_SEENLAST
;
960 /* Check if we are completely reassembled */
961 if (((*frag
)->fr_flags
& PFFRAG_SEENLAST
) &&
962 LIST_FIRST(&(*frag
)->fr_cache
)->fr_off
== 0 &&
963 LIST_FIRST(&(*frag
)->fr_cache
)->fr_end
== (*frag
)->fr_max
) {
964 /* Remove from fragment queue */
965 DPFPRINTF(("fragcache[%d]: done 0-%d\n", h
->ip_id
,
967 pf_free_fragment(*frag
);
976 /* Still need to pay attention to !IP_MF */
977 if (!mff
&& *frag
!= NULL
)
978 (*frag
)->fr_flags
|= PFFRAG_SEENLAST
;
985 /* Still need to pay attention to !IP_MF */
986 if (!mff
&& *frag
!= NULL
)
987 (*frag
)->fr_flags
|= PFFRAG_SEENLAST
;
990 /* This fragment has been deemed bad. Don't reass */
991 if (((*frag
)->fr_flags
& PFFRAG_DROP
) == 0)
992 DPFPRINTF(("fragcache[%d]: dropping overall fragment\n",
994 (*frag
)->fr_flags
|= PFFRAG_DROP
;
1001 #define FR_IP6_OFF(fr) \
1002 (ntohs((fr)->fr_ip6f_opt.ip6f_offlg & IP6F_OFF_MASK))
1003 #define FR_IP6_PLEN(fr) (ntohs((fr)->fr_ip6->ip6_plen))
1005 pf_reassemble6(struct mbuf
**m0
, struct pf_fragment
**frag
,
1006 struct pf_frent
*frent
, int mff
)
1008 struct mbuf
*m
, *m2
;
1009 struct pf_frent
*frea
, *frep
, *next
;
1010 struct ip6_hdr
*ip6
;
1011 int plen
, off
, fr_max
;
1013 VERIFY(*frag
== NULL
|| BUFFER_FRAGMENTS(*frag
));
1016 ip6
= frent
->fr_ip6
;
1017 off
= FR_IP6_OFF(frent
);
1018 plen
= FR_IP6_PLEN(frent
);
1019 fr_max
= off
+ plen
- (frent
->fr_ip6f_hlen
- sizeof *ip6
);
1021 DPFPRINTF(("0x%llx IPv6 frag plen %u off %u fr_ip6f_hlen %u "
1022 "fr_max %u m_len %u\n", (uint64_t)VM_KERNEL_ADDRPERM(m
), plen
, off
,
1023 frent
->fr_ip6f_hlen
, fr_max
, m
->m_len
));
1025 /* strip off headers up to the fragment payload */
1026 m
->m_data
+= frent
->fr_ip6f_hlen
;
1027 m
->m_len
-= frent
->fr_ip6f_hlen
;
1029 /* Create a new reassembly queue for this packet */
1030 if (*frag
== NULL
) {
1031 *frag
= pool_get(&pf_frag_pl
, PR_NOWAIT
);
1032 if (*frag
== NULL
) {
1033 pf_flush_fragments();
1034 *frag
= pool_get(&pf_frag_pl
, PR_NOWAIT
);
1039 (*frag
)->fr_flags
= 0;
1040 (*frag
)->fr_max
= 0;
1041 (*frag
)->fr_af
= AF_INET6
;
1042 (*frag
)->fr_srcx
.v6
= frent
->fr_ip6
->ip6_src
;
1043 (*frag
)->fr_dstx
.v6
= frent
->fr_ip6
->ip6_dst
;
1044 (*frag
)->fr_p
= frent
->fr_ip6f_opt
.ip6f_nxt
;
1045 (*frag
)->fr_id6
= frent
->fr_ip6f_opt
.ip6f_ident
;
1046 (*frag
)->fr_timeout
= pf_time_second();
1047 LIST_INIT(&(*frag
)->fr_queue
);
1049 RB_INSERT(pf_frag_tree
, &pf_frag_tree
, *frag
);
1050 TAILQ_INSERT_HEAD(&pf_fragqueue
, *frag
, frag_next
);
1052 /* We do not have a previous fragment */
1058 * Find a fragment after the current one:
1059 * - off contains the real shifted offset.
1061 LIST_FOREACH(frea
, &(*frag
)->fr_queue
, fr_next
) {
1062 if (FR_IP6_OFF(frea
) > off
)
1067 VERIFY(frep
!= NULL
|| frea
!= NULL
);
1070 FR_IP6_OFF(frep
) + FR_IP6_PLEN(frep
) - frep
->fr_ip6f_hlen
> off
)
1074 precut
= FR_IP6_OFF(frep
) + FR_IP6_PLEN(frep
) -
1075 frep
->fr_ip6f_hlen
- off
;
1078 m_adj(frent
->fr_m
, precut
);
1079 DPFPRINTF(("overlap -%d\n", precut
));
1080 /* Enforce 8 byte boundaries */
1081 frent
->fr_ip6f_opt
.ip6f_offlg
=
1082 htons(ntohs(frent
->fr_ip6f_opt
.ip6f_offlg
) +
1084 off
= FR_IP6_OFF(frent
);
1086 ip6
->ip6_plen
= htons(plen
);
1089 for (; frea
!= NULL
&& plen
+ off
> FR_IP6_OFF(frea
); frea
= next
) {
1092 aftercut
= plen
+ off
- FR_IP6_OFF(frea
);
1093 DPFPRINTF(("adjust overlap %d\n", aftercut
));
1094 if (aftercut
< FR_IP6_PLEN(frea
) - frea
->fr_ip6f_hlen
) {
1095 frea
->fr_ip6
->ip6_plen
= htons(FR_IP6_PLEN(frea
) -
1097 frea
->fr_ip6f_opt
.ip6f_offlg
=
1098 htons(ntohs(frea
->fr_ip6f_opt
.ip6f_offlg
) +
1100 m_adj(frea
->fr_m
, aftercut
);
1104 /* This fragment is completely overlapped, lose it */
1105 next
= LIST_NEXT(frea
, fr_next
);
1106 m_freem(frea
->fr_m
);
1107 LIST_REMOVE(frea
, fr_next
);
1108 pool_put(&pf_frent_pl
, frea
);
1113 /* Update maximum data size */
1114 if ((*frag
)->fr_max
< fr_max
)
1115 (*frag
)->fr_max
= fr_max
;
1116 /* This is the last segment */
1118 (*frag
)->fr_flags
|= PFFRAG_SEENLAST
;
1121 LIST_INSERT_HEAD(&(*frag
)->fr_queue
, frent
, fr_next
);
1123 LIST_INSERT_AFTER(frep
, frent
, fr_next
);
1125 /* Check if we are completely reassembled */
1126 if (!((*frag
)->fr_flags
& PFFRAG_SEENLAST
))
1129 /* Check if we have all the data */
1131 for (frep
= LIST_FIRST(&(*frag
)->fr_queue
); frep
; frep
= next
) {
1132 next
= LIST_NEXT(frep
, fr_next
);
1133 off
+= FR_IP6_PLEN(frep
) - (frent
->fr_ip6f_hlen
- sizeof *ip6
);
1134 DPFPRINTF(("frep at %d, next %d, max %d\n",
1135 off
, next
== NULL
? -1 : FR_IP6_OFF(next
),
1137 if (off
< (*frag
)->fr_max
&&
1138 (next
== NULL
|| FR_IP6_OFF(next
) != off
)) {
1139 DPFPRINTF(("missing fragment at %d, next %d, max %d\n",
1140 off
, next
== NULL
? -1 : FR_IP6_OFF(next
),
1145 DPFPRINTF(("%d < %d?\n", off
, (*frag
)->fr_max
));
1146 if (off
< (*frag
)->fr_max
)
1149 /* We have all the data */
1150 frent
= LIST_FIRST(&(*frag
)->fr_queue
);
1151 VERIFY(frent
!= NULL
);
1152 if (frent
->fr_ip6f_hlen
+ off
> IP_MAXPACKET
) {
1153 DPFPRINTF(("drop: too big: %d\n", off
));
1154 pf_free_fragment(*frag
);
1159 ip6
= frent
->fr_ip6
;
1160 ip6
->ip6_nxt
= (*frag
)->fr_p
;
1161 ip6
->ip6_plen
= htons(off
);
1162 ip6
->ip6_src
= (*frag
)->fr_srcx
.v6
;
1163 ip6
->ip6_dst
= (*frag
)->fr_dstx
.v6
;
1165 /* Remove from fragment queue */
1166 pf_remove_fragment(*frag
);
1170 m
->m_len
+= sizeof(struct ip6_hdr
);
1171 m
->m_data
-= sizeof(struct ip6_hdr
);
1172 memmove(m
->m_data
, ip6
, sizeof(struct ip6_hdr
));
1174 next
= LIST_NEXT(frent
, fr_next
);
1175 pool_put(&pf_frent_pl
, frent
);
1177 for (frent
= next
; next
!= NULL
; frent
= next
) {
1181 next
= LIST_NEXT(frent
, fr_next
);
1182 pool_put(&pf_frent_pl
, frent
);
1186 /* XXX this should be done elsewhere */
1187 if (m
->m_flags
& M_PKTHDR
) {
1189 for (m2
= m
; m2
; m2
= m2
->m_next
)
1190 pktlen
+= m2
->m_len
;
1191 m
->m_pkthdr
.len
= pktlen
;
1194 DPFPRINTF(("complete: 0x%llx ip6_plen %d m_pkthdr.len %d\n",
1195 (uint64_t)VM_KERNEL_ADDRPERM(m
), ntohs(ip6
->ip6_plen
),
1201 /* Oops - fail safe - drop packet */
1202 pool_put(&pf_frent_pl
, frent
);
1208 static struct mbuf
*
1209 pf_frag6cache(struct mbuf
**m0
, struct ip6_hdr
*h
, struct ip6_frag
*fh
,
1210 struct pf_fragment
**frag
, int hlen
, int mff
, int drop
, int *nomem
)
1212 struct mbuf
*m
= *m0
;
1213 u_int16_t plen
, off
, fr_max
;
1214 struct pf_frcache
*frp
, *fra
, *cur
= NULL
;
1217 VERIFY(*frag
== NULL
|| !BUFFER_FRAGMENTS(*frag
));
1219 off
= ntohs(fh
->ip6f_offlg
& IP6F_OFF_MASK
);
1220 plen
= ntohs(h
->ip6_plen
) - (hlen
- sizeof *h
);
1223 * Apple Modification: dimambro@apple.com. The hlen, being passed
1224 * into this function Includes all the headers associated with
1225 * the packet, and may include routing headers, so to get to
1226 * the data payload as stored in the original IPv6 header we need
1227 * to subtract al those headers and the IP header.
1229 * The 'max' local variable should also contain the offset from the start
1230 * of the reassembled packet to the octet just past the end of the octets
1231 * in the current fragment where:
1232 * - 'off' is the offset from the start of the reassembled packet to the
1233 * first octet in the fragment,
1234 * - 'plen' is the length of the "payload data length" Excluding all the
1235 * IPv6 headers of the fragment.
1236 * - 'hlen' is computed in pf_normalize_ip6() as the offset from the start
1237 * of the IPv6 packet to the beginning of the data.
1239 fr_max
= off
+ plen
;
1241 DPFPRINTF(("0x%llx plen %u off %u fr_max %u\n",
1242 (uint64_t)VM_KERNEL_ADDRPERM(m
), plen
, off
, fr_max
));
1244 /* Create a new range queue for this packet */
1245 if (*frag
== NULL
) {
1246 *frag
= pool_get(&pf_cache_pl
, PR_NOWAIT
);
1247 if (*frag
== NULL
) {
1248 pf_flush_fragments();
1249 *frag
= pool_get(&pf_cache_pl
, PR_NOWAIT
);
1254 /* Get an entry for the queue */
1255 cur
= pool_get(&pf_cent_pl
, PR_NOWAIT
);
1257 pool_put(&pf_cache_pl
, *frag
);
1263 (*frag
)->fr_flags
= PFFRAG_NOBUFFER
;
1264 (*frag
)->fr_max
= 0;
1265 (*frag
)->fr_af
= AF_INET6
;
1266 (*frag
)->fr_srcx
.v6
= h
->ip6_src
;
1267 (*frag
)->fr_dstx
.v6
= h
->ip6_dst
;
1268 (*frag
)->fr_p
= fh
->ip6f_nxt
;
1269 (*frag
)->fr_id6
= fh
->ip6f_ident
;
1270 (*frag
)->fr_timeout
= pf_time_second();
1273 cur
->fr_end
= fr_max
;
1274 LIST_INIT(&(*frag
)->fr_cache
);
1275 LIST_INSERT_HEAD(&(*frag
)->fr_cache
, cur
, fr_next
);
1277 RB_INSERT(pf_frag_tree
, &pf_cache_tree
, *frag
);
1278 TAILQ_INSERT_HEAD(&pf_cachequeue
, *frag
, frag_next
);
1280 DPFPRINTF(("frag6cache[%d]: new %d-%d\n", ntohl(fh
->ip6f_ident
),
1287 * Find a fragment after the current one:
1288 * - off contains the real shifted offset.
1291 LIST_FOREACH(fra
, &(*frag
)->fr_cache
, fr_next
) {
1292 if (fra
->fr_off
> off
)
1297 VERIFY(frp
!= NULL
|| fra
!= NULL
);
1302 precut
= frp
->fr_end
- off
;
1303 if (precut
>= plen
) {
1304 /* Fragment is entirely a duplicate */
1305 DPFPRINTF(("frag6cache[%u]: dead (%d-%d) %d-%d\n",
1306 ntohl(fh
->ip6f_ident
), frp
->fr_off
, frp
->fr_end
,
1311 /* They are adjacent. Fixup cache entry */
1312 DPFPRINTF(("frag6cache[%u]: adjacent (%d-%d) %d-%d\n",
1313 ntohl(fh
->ip6f_ident
), frp
->fr_off
, frp
->fr_end
,
1315 frp
->fr_end
= fr_max
;
1316 } else if (precut
> 0) {
1317 /* The first part of this payload overlaps with a
1318 * fragment that has already been passed.
1319 * Need to trim off the first part of the payload.
1320 * But to do so easily, we need to create another
1321 * mbuf to throw the original header into.
1324 DPFPRINTF(("frag6cache[%u]: chop %d (%d-%d) %d-%d\n",
1325 ntohl(fh
->ip6f_ident
), precut
, frp
->fr_off
,
1326 frp
->fr_end
, off
, fr_max
));
1330 /* Update the previous frag to encompass this one */
1331 frp
->fr_end
= fr_max
;
1334 /* XXX Optimization opportunity
1335 * This is a very heavy way to trim the payload.
1336 * we could do it much faster by diddling mbuf
1337 * internals but that would be even less legible
1338 * than this mbuf magic. For my next trick,
1339 * I'll pull a rabbit out of my laptop.
1341 *m0
= m_copym(m
, 0, hlen
, M_NOWAIT
);
1344 VERIFY((*m0
)->m_next
== NULL
);
1345 m_adj(m
, precut
+ hlen
);
1348 if (m
->m_flags
& M_PKTHDR
) {
1351 for (t
= m
; t
; t
= t
->m_next
)
1353 m
->m_pkthdr
.len
= pktlen
;
1356 h
= mtod(m
, struct ip6_hdr
*);
1358 VERIFY((int)m
->m_len
==
1359 ntohs(h
->ip6_plen
) - precut
);
1360 fh
->ip6f_offlg
&= ~IP6F_OFF_MASK
;
1362 htons(ntohs(fh
->ip6f_offlg
& IP6F_OFF_MASK
)
1364 h
->ip6_plen
= htons(ntohs(h
->ip6_plen
) -
1370 /* There is a gap between fragments */
1372 DPFPRINTF(("frag6cache[%u]: gap %d (%d-%d) %d-%d\n",
1373 ntohl(fh
->ip6f_ident
), -precut
, frp
->fr_off
,
1374 frp
->fr_end
, off
, fr_max
));
1376 cur
= pool_get(&pf_cent_pl
, PR_NOWAIT
);
1382 cur
->fr_end
= fr_max
;
1383 LIST_INSERT_AFTER(frp
, cur
, fr_next
);
1391 aftercut
= fr_max
- fra
->fr_off
;
1392 if (aftercut
== 0) {
1393 /* Adjacent fragments */
1394 DPFPRINTF(("frag6cache[%u]: adjacent %d-%d (%d-%d)\n",
1395 ntohl(fh
->ip6f_ident
), off
, fr_max
, fra
->fr_off
,
1399 } else if (aftercut
> 0) {
1400 /* Need to chop off the tail of this fragment */
1401 DPFPRINTF(("frag6cache[%u]: chop %d %d-%d (%d-%d)\n",
1402 ntohl(fh
->ip6f_ident
), aftercut
, off
, fr_max
,
1403 fra
->fr_off
, fra
->fr_end
));
1410 m_adj(m
, -aftercut
);
1411 if (m
->m_flags
& M_PKTHDR
) {
1414 for (t
= m
; t
; t
= t
->m_next
)
1416 m
->m_pkthdr
.len
= pktlen
;
1418 h
= mtod(m
, struct ip6_hdr
*);
1419 VERIFY((int)m
->m_len
==
1420 ntohs(h
->ip6_plen
) - aftercut
);
1422 htons(ntohs(h
->ip6_plen
) - aftercut
);
1426 } else if (frp
== NULL
) {
1427 /* There is a gap between fragments */
1428 DPFPRINTF(("frag6cache[%u]: gap %d %d-%d (%d-%d)\n",
1429 ntohl(fh
->ip6f_ident
), -aftercut
, off
, fr_max
,
1430 fra
->fr_off
, fra
->fr_end
));
1432 cur
= pool_get(&pf_cent_pl
, PR_NOWAIT
);
1438 cur
->fr_end
= fr_max
;
1439 LIST_INSERT_BEFORE(fra
, cur
, fr_next
);
1442 /* Need to glue together two separate fragment descriptors */
1444 if (cur
&& fra
->fr_off
<= cur
->fr_end
) {
1445 /* Need to merge in a previous 'cur' */
1446 DPFPRINTF(("frag6cache[%u]: adjacent(merge "
1447 "%d-%d) %d-%d (%d-%d)\n",
1448 ntohl(fh
->ip6f_ident
), cur
->fr_off
,
1449 cur
->fr_end
, off
, fr_max
, fra
->fr_off
,
1451 fra
->fr_off
= cur
->fr_off
;
1452 LIST_REMOVE(cur
, fr_next
);
1453 pool_put(&pf_cent_pl
, cur
);
1456 } else if (frp
&& fra
->fr_off
<= frp
->fr_end
) {
1457 /* Need to merge in a modified 'frp' */
1458 VERIFY(cur
== NULL
);
1459 DPFPRINTF(("frag6cache[%u]: adjacent(merge "
1460 "%d-%d) %d-%d (%d-%d)\n",
1461 ntohl(fh
->ip6f_ident
), frp
->fr_off
,
1462 frp
->fr_end
, off
, fr_max
, fra
->fr_off
,
1464 fra
->fr_off
= frp
->fr_off
;
1465 LIST_REMOVE(frp
, fr_next
);
1466 pool_put(&pf_cent_pl
, frp
);
1475 * We must keep tracking the overall fragment even when
1476 * we're going to drop it anyway so that we know when to
1477 * free the overall descriptor. Thus we drop the frag late.
1483 /* Update maximum data size */
1484 if ((*frag
)->fr_max
< fr_max
)
1485 (*frag
)->fr_max
= fr_max
;
1487 /* This is the last segment */
1489 (*frag
)->fr_flags
|= PFFRAG_SEENLAST
;
1491 /* Check if we are completely reassembled */
1492 if (((*frag
)->fr_flags
& PFFRAG_SEENLAST
) &&
1493 LIST_FIRST(&(*frag
)->fr_cache
)->fr_off
== 0 &&
1494 LIST_FIRST(&(*frag
)->fr_cache
)->fr_end
== (*frag
)->fr_max
) {
1495 /* Remove from fragment queue */
1496 DPFPRINTF(("frag6cache[%u]: done 0-%d\n",
1497 ntohl(fh
->ip6f_ident
), (*frag
)->fr_max
));
1498 pf_free_fragment(*frag
);
1507 /* Still need to pay attention to !IP_MF */
1508 if (!mff
&& *frag
!= NULL
)
1509 (*frag
)->fr_flags
|= PFFRAG_SEENLAST
;
1516 /* Still need to pay attention to !IP_MF */
1517 if (!mff
&& *frag
!= NULL
)
1518 (*frag
)->fr_flags
|= PFFRAG_SEENLAST
;
1521 /* This fragment has been deemed bad. Don't reass */
1522 if (((*frag
)->fr_flags
& PFFRAG_DROP
) == 0)
1523 DPFPRINTF(("frag6cache[%u]: dropping overall fragment\n",
1524 ntohl(fh
->ip6f_ident
)));
1525 (*frag
)->fr_flags
|= PFFRAG_DROP
;
1533 pf_normalize_ip(struct mbuf
**m0
, int dir
, struct pfi_kif
*kif
, u_short
*reason
,
1534 struct pf_pdesc
*pd
)
1536 struct mbuf
*m
= *m0
;
1538 struct pf_frent
*frent
;
1539 struct pf_fragment
*frag
= NULL
;
1540 struct ip
*h
= mtod(m
, struct ip
*);
1541 int mff
= (ntohs(h
->ip_off
) & IP_MF
);
1542 int hlen
= h
->ip_hl
<< 2;
1543 u_int16_t fragoff
= (ntohs(h
->ip_off
) & IP_OFFMASK
) << 3;
1548 struct pf_ruleset
*ruleset
= NULL
;
1550 r
= TAILQ_FIRST(pf_main_ruleset
.rules
[PF_RULESET_SCRUB
].active
.ptr
);
1553 if (pfi_kif_match(r
->kif
, kif
) == r
->ifnot
)
1554 r
= r
->skip
[PF_SKIP_IFP
].ptr
;
1555 else if (r
->direction
&& r
->direction
!= dir
)
1556 r
= r
->skip
[PF_SKIP_DIR
].ptr
;
1557 else if (r
->af
&& r
->af
!= AF_INET
)
1558 r
= r
->skip
[PF_SKIP_AF
].ptr
;
1559 else if (r
->proto
&& r
->proto
!= h
->ip_p
)
1560 r
= r
->skip
[PF_SKIP_PROTO
].ptr
;
1561 else if (PF_MISMATCHAW(&r
->src
.addr
,
1562 (struct pf_addr
*)&h
->ip_src
.s_addr
, AF_INET
,
1564 r
= r
->skip
[PF_SKIP_SRC_ADDR
].ptr
;
1565 else if (PF_MISMATCHAW(&r
->dst
.addr
,
1566 (struct pf_addr
*)&h
->ip_dst
.s_addr
, AF_INET
,
1568 r
= r
->skip
[PF_SKIP_DST_ADDR
].ptr
;
1570 if (r
->anchor
== NULL
)
1573 pf_step_into_anchor(&asd
, &ruleset
,
1574 PF_RULESET_SCRUB
, &r
, NULL
, NULL
);
1576 if (r
== NULL
&& pf_step_out_of_anchor(&asd
, &ruleset
,
1577 PF_RULESET_SCRUB
, &r
, NULL
, NULL
))
1581 if (r
== NULL
|| r
->action
== PF_NOSCRUB
)
1584 r
->packets
[dir
== PF_OUT
]++;
1585 r
->bytes
[dir
== PF_OUT
] += pd
->tot_len
;
1588 /* Check for illegal packets */
1589 if (hlen
< (int)sizeof (struct ip
))
1592 if (hlen
> ntohs(h
->ip_len
))
1595 /* Clear IP_DF if the rule uses the no-df option */
1596 if (r
->rule_flag
& PFRULE_NODF
&& h
->ip_off
& htons(IP_DF
)) {
1597 u_int16_t ipoff
= h
->ip_off
;
1599 h
->ip_off
&= htons(~IP_DF
);
1600 h
->ip_sum
= pf_cksum_fixup(h
->ip_sum
, ipoff
, h
->ip_off
, 0);
1603 /* We will need other tests here */
1604 if (!fragoff
&& !mff
)
1608 * We're dealing with a fragment now. Don't allow fragments
1609 * with IP_DF to enter the cache. If the flag was cleared by
1610 * no-df above, fine. Otherwise drop it.
1612 if (h
->ip_off
& htons(IP_DF
)) {
1613 DPFPRINTF(("IP_DF\n"));
1617 ip_len
= ntohs(h
->ip_len
) - hlen
;
1618 ip_off
= (ntohs(h
->ip_off
) & IP_OFFMASK
) << 3;
1620 /* All fragments are 8 byte aligned */
1621 if (mff
&& (ip_len
& 0x7)) {
1622 DPFPRINTF(("mff and %d\n", ip_len
));
1626 /* Respect maximum length */
1627 if (fragoff
+ ip_len
> IP_MAXPACKET
) {
1628 DPFPRINTF(("max packet %d\n", fragoff
+ ip_len
));
1631 fr_max
= fragoff
+ ip_len
;
1633 if ((r
->rule_flag
& (PFRULE_FRAGCROP
|PFRULE_FRAGDROP
)) == 0) {
1634 /* Fully buffer all of the fragments */
1636 frag
= pf_find_fragment_by_ipv4_header(h
, &pf_frag_tree
);
1637 /* Check if we saw the last fragment already */
1638 if (frag
!= NULL
&& (frag
->fr_flags
& PFFRAG_SEENLAST
) &&
1639 fr_max
> frag
->fr_max
)
1642 /* Get an entry for the fragment queue */
1643 frent
= pool_get(&pf_frent_pl
, PR_NOWAIT
);
1644 if (frent
== NULL
) {
1645 REASON_SET(reason
, PFRES_MEMORY
);
1652 /* Might return a completely reassembled mbuf, or NULL */
1653 DPFPRINTF(("reass IPv4 frag %d @ %d-%d\n", ntohs(h
->ip_id
),
1655 *m0
= m
= pf_reassemble(m0
, &frag
, frent
, mff
);
1660 VERIFY(m
->m_flags
& M_PKTHDR
);
1662 /* use mtag from concatenated mbuf chain */
1663 pd
->pf_mtag
= pf_find_mtag(m
);
1665 if (pd
->pf_mtag
== NULL
) {
1666 printf("%s: pf_find_mtag returned NULL(1)\n", __func__
);
1667 if ((pd
->pf_mtag
= pf_get_mtag(m
)) == NULL
) {
1674 if (frag
!= NULL
&& (frag
->fr_flags
& PFFRAG_DROP
))
1677 h
= mtod(m
, struct ip
*);
1679 /* non-buffering fragment cache (drops or masks overlaps) */
1682 if (dir
== PF_OUT
&& (pd
->pf_mtag
->pftag_flags
& PF_TAG_FRAGCACHE
)) {
1684 * Already passed the fragment cache in the
1685 * input direction. If we continued, it would
1686 * appear to be a dup and would be dropped.
1691 frag
= pf_find_fragment_by_ipv4_header(h
, &pf_cache_tree
);
1693 /* Check if we saw the last fragment already */
1694 if (frag
!= NULL
&& (frag
->fr_flags
& PFFRAG_SEENLAST
) &&
1695 fr_max
> frag
->fr_max
) {
1696 if (r
->rule_flag
& PFRULE_FRAGDROP
)
1697 frag
->fr_flags
|= PFFRAG_DROP
;
1701 *m0
= m
= pf_fragcache(m0
, h
, &frag
, mff
,
1702 (r
->rule_flag
& PFRULE_FRAGDROP
) ? 1 : 0, &nomem
);
1709 VERIFY(m
->m_flags
& M_PKTHDR
);
1711 /* use mtag from copied and trimmed mbuf chain */
1712 pd
->pf_mtag
= pf_find_mtag(m
);
1714 if (pd
->pf_mtag
== NULL
) {
1715 printf("%s: pf_find_mtag returned NULL(2)\n", __func__
);
1716 if ((pd
->pf_mtag
= pf_get_mtag(m
)) == NULL
) {
1724 pd
->pf_mtag
->pftag_flags
|= PF_TAG_FRAGCACHE
;
1726 if (frag
!= NULL
&& (frag
->fr_flags
& PFFRAG_DROP
))
1732 /* At this point, only IP_DF is allowed in ip_off */
1733 if (h
->ip_off
& ~htons(IP_DF
)) {
1734 u_int16_t ipoff
= h
->ip_off
;
1736 h
->ip_off
&= htons(IP_DF
);
1737 h
->ip_sum
= pf_cksum_fixup(h
->ip_sum
, ipoff
, h
->ip_off
, 0);
1740 /* Enforce a minimum ttl, may cause endless packet loops */
1741 if (r
->min_ttl
&& h
->ip_ttl
< r
->min_ttl
) {
1742 u_int16_t ip_ttl
= h
->ip_ttl
;
1744 h
->ip_ttl
= r
->min_ttl
;
1745 h
->ip_sum
= pf_cksum_fixup(h
->ip_sum
, ip_ttl
, h
->ip_ttl
, 0);
1747 if (r
->rule_flag
& PFRULE_RANDOMID
) {
1748 u_int16_t oip_id
= h
->ip_id
;
1750 h
->ip_id
= ip_randomid();
1751 h
->ip_sum
= pf_cksum_fixup(h
->ip_sum
, oip_id
, h
->ip_id
, 0);
1753 if ((r
->rule_flag
& (PFRULE_FRAGCROP
|PFRULE_FRAGDROP
)) == 0)
1754 pd
->flags
|= PFDESC_IP_REAS
;
1759 /* Enforce a minimum ttl, may cause endless packet loops */
1760 if (r
->min_ttl
&& h
->ip_ttl
< r
->min_ttl
) {
1761 u_int16_t ip_ttl
= h
->ip_ttl
;
1763 h
->ip_ttl
= r
->min_ttl
;
1764 h
->ip_sum
= pf_cksum_fixup(h
->ip_sum
, ip_ttl
, h
->ip_ttl
, 0);
1766 if ((r
->rule_flag
& (PFRULE_FRAGCROP
|PFRULE_FRAGDROP
)) == 0)
1767 pd
->flags
|= PFDESC_IP_REAS
;
1771 REASON_SET(reason
, PFRES_MEMORY
);
1772 if (r
!= NULL
&& r
->log
)
1773 PFLOG_PACKET(kif
, h
, m
, AF_INET
, dir
, *reason
, r
,
1778 REASON_SET(reason
, PFRES_NORM
);
1779 if (r
!= NULL
&& r
->log
)
1780 PFLOG_PACKET(kif
, h
, m
, AF_INET
, dir
, *reason
, r
,
1785 DPFPRINTF(("dropping bad IPv4 fragment\n"));
1787 /* Free associated fragments */
1789 pf_free_fragment(frag
);
1791 REASON_SET(reason
, PFRES_FRAG
);
1792 if (r
!= NULL
&& r
->log
)
1793 PFLOG_PACKET(kif
, h
, m
, AF_INET
, dir
, *reason
, r
, NULL
, NULL
, pd
);
1800 pf_normalize_ip6(struct mbuf
**m0
, int dir
, struct pfi_kif
*kif
,
1801 u_short
*reason
, struct pf_pdesc
*pd
)
1803 struct mbuf
*m
= *m0
;
1805 struct ip6_hdr
*h
= mtod(m
, struct ip6_hdr
*);
1811 struct ip6_opt_jumbo jumbo
;
1815 struct ip6_frag frag
;
1816 u_int32_t jumbolen
= 0, plen
;
1817 u_int16_t fragoff
= 0;
1820 struct pf_frent
*frent
;
1821 struct pf_fragment
*pff
= NULL
;
1822 int mff
= 0, rh_cnt
= 0;
1825 struct pf_ruleset
*ruleset
= NULL
;
1827 r
= TAILQ_FIRST(pf_main_ruleset
.rules
[PF_RULESET_SCRUB
].active
.ptr
);
1830 if (pfi_kif_match(r
->kif
, kif
) == r
->ifnot
)
1831 r
= r
->skip
[PF_SKIP_IFP
].ptr
;
1832 else if (r
->direction
&& r
->direction
!= dir
)
1833 r
= r
->skip
[PF_SKIP_DIR
].ptr
;
1834 else if (r
->af
&& r
->af
!= AF_INET6
)
1835 r
= r
->skip
[PF_SKIP_AF
].ptr
;
1836 #if 0 /* header chain! */
1837 else if (r
->proto
&& r
->proto
!= h
->ip6_nxt
)
1838 r
= r
->skip
[PF_SKIP_PROTO
].ptr
;
1840 else if (PF_MISMATCHAW(&r
->src
.addr
,
1841 (struct pf_addr
*)&h
->ip6_src
, AF_INET6
,
1843 r
= r
->skip
[PF_SKIP_SRC_ADDR
].ptr
;
1844 else if (PF_MISMATCHAW(&r
->dst
.addr
,
1845 (struct pf_addr
*)&h
->ip6_dst
, AF_INET6
,
1847 r
= r
->skip
[PF_SKIP_DST_ADDR
].ptr
;
1849 if (r
->anchor
== NULL
)
1852 pf_step_into_anchor(&asd
, &ruleset
,
1853 PF_RULESET_SCRUB
, &r
, NULL
, NULL
);
1855 if (r
== NULL
&& pf_step_out_of_anchor(&asd
, &ruleset
,
1856 PF_RULESET_SCRUB
, &r
, NULL
, NULL
))
1860 if (r
== NULL
|| r
->action
== PF_NOSCRUB
)
1863 r
->packets
[dir
== PF_OUT
]++;
1864 r
->bytes
[dir
== PF_OUT
] += pd
->tot_len
;
1867 /* Check for illegal packets */
1868 if ((int)(sizeof (struct ip6_hdr
) + IPV6_MAXPACKET
) < m
->m_pkthdr
.len
)
1871 off
= sizeof (struct ip6_hdr
);
1877 case IPPROTO_FRAGMENT
:
1880 case IPPROTO_ROUTING
:
1881 case IPPROTO_DSTOPTS
:
1882 if (!pf_pull_hdr(m
, off
, &ext
, sizeof (ext
), NULL
,
1887 * Multiple routing headers not allowed.
1888 * Routing header type zero considered harmful.
1890 if (proto
== IPPROTO_ROUTING
) {
1891 const struct ip6_rthdr
*rh
=
1892 (const struct ip6_rthdr
*)&ext
;
1895 if (rh
->ip6r_type
== IPV6_RTHDR_TYPE_0
)
1899 if (proto
== IPPROTO_AH
)
1900 off
+= (ext
.ip6e_len
+ 2) * 4;
1902 off
+= (ext
.ip6e_len
+ 1) * 8;
1903 proto
= ext
.ip6e_nxt
;
1905 case IPPROTO_HOPOPTS
:
1908 if (!pf_pull_hdr(m
, off
, &ext
, sizeof (ext
), NULL
,
1911 optend
= off
+ (ext
.ip6e_len
+ 1) * 8;
1912 ooff
= off
+ sizeof (ext
);
1914 if (!pf_pull_hdr(m
, ooff
, &opt
.ip6o_type
,
1915 sizeof (opt
.ip6o_type
), NULL
, NULL
,
1918 if (opt
.ip6o_type
== IP6OPT_PAD1
) {
1922 if (!pf_pull_hdr(m
, ooff
, &opt
, sizeof (opt
),
1923 NULL
, NULL
, AF_INET6
))
1925 if (ooff
+ sizeof (opt
) + opt
.ip6o_len
> optend
)
1927 switch (opt
.ip6o_type
) {
1929 if (h
->ip6_plen
!= 0)
1931 if (!pf_pull_hdr(m
, ooff
, &jumbo
,
1932 sizeof (jumbo
), NULL
, NULL
,
1935 memcpy(&jumbolen
, jumbo
.ip6oj_jumbo_len
,
1937 jumbolen
= ntohl(jumbolen
);
1938 if (jumbolen
<= IPV6_MAXPACKET
)
1940 if (sizeof (struct ip6_hdr
) +
1941 jumbolen
!= m
->m_pkthdr
.len
)
1947 ooff
+= sizeof (opt
) + opt
.ip6o_len
;
1948 } while (ooff
< optend
);
1951 proto
= ext
.ip6e_nxt
;
1958 } while (!terminal
);
1960 /* jumbo payload option must be present, or plen > 0 */
1961 if (ntohs(h
->ip6_plen
) == 0)
1964 plen
= ntohs(h
->ip6_plen
);
1967 if ((int)(sizeof (struct ip6_hdr
) + plen
) > m
->m_pkthdr
.len
)
1970 /* Enforce a minimum ttl, may cause endless packet loops */
1971 if (r
->min_ttl
&& h
->ip6_hlim
< r
->min_ttl
)
1972 h
->ip6_hlim
= r
->min_ttl
;
1977 if (ntohs(h
->ip6_plen
) == 0 || jumbolen
)
1979 plen
= ntohs(h
->ip6_plen
);
1981 if (!pf_pull_hdr(m
, off
, &frag
, sizeof (frag
), NULL
, NULL
, AF_INET6
))
1983 fragoff
= ntohs(frag
.ip6f_offlg
& IP6F_OFF_MASK
);
1984 pd
->proto
= frag
.ip6f_nxt
;
1985 mff
= ntohs(frag
.ip6f_offlg
& IP6F_MORE_FRAG
);
1987 if (fragoff
+ (plen
- off
) > IPV6_MAXPACKET
)
1990 fr_max
= fragoff
+ plen
- (off
- sizeof(struct ip6_hdr
));
1991 DPFPRINTF(("0x%llx IPv6 frag plen %u mff %d off %u fragoff %u "
1992 "fr_max %u\n", (uint64_t)VM_KERNEL_ADDRPERM(m
), plen
, mff
, off
,
1995 if ((r
->rule_flag
& (PFRULE_FRAGCROP
|PFRULE_FRAGDROP
)) == 0) {
1996 /* Fully buffer all of the fragments */
1997 pd
->flags
|= PFDESC_IP_REAS
;
1999 pff
= pf_find_fragment_by_ipv6_header(h
, &frag
,
2002 /* Check if we saw the last fragment already */
2003 if (pff
!= NULL
&& (pff
->fr_flags
& PFFRAG_SEENLAST
) &&
2004 fr_max
> pff
->fr_max
)
2007 /* Get an entry for the fragment queue */
2008 frent
= pool_get(&pf_frent_pl
, PR_NOWAIT
);
2009 if (frent
== NULL
) {
2010 REASON_SET(reason
, PFRES_MEMORY
);
2016 frent
->fr_ip6f_opt
= frag
;
2017 frent
->fr_ip6f_hlen
= off
;
2019 /* Might return a completely reassembled mbuf, or NULL */
2020 DPFPRINTF(("reass IPv6 frag %d @ %d-%d\n",
2021 ntohl(frag
.ip6f_ident
), fragoff
, fr_max
));
2022 *m0
= m
= pf_reassemble6(m0
, &pff
, frent
, mff
);
2027 if (pff
!= NULL
&& (pff
->fr_flags
& PFFRAG_DROP
))
2030 h
= mtod(m
, struct ip6_hdr
*);
2032 else if (dir
== PF_IN
|| !(pd
->pf_mtag
->pftag_flags
& PF_TAG_FRAGCACHE
)) {
2033 /* non-buffering fragment cache (overlaps: see RFC 5722) */
2036 pff
= pf_find_fragment_by_ipv6_header(h
, &frag
,
2039 /* Check if we saw the last fragment already */
2040 if (pff
!= NULL
&& (pff
->fr_flags
& PFFRAG_SEENLAST
) &&
2041 fr_max
> pff
->fr_max
) {
2042 if (r
->rule_flag
& PFRULE_FRAGDROP
)
2043 pff
->fr_flags
|= PFFRAG_DROP
;
2047 *m0
= m
= pf_frag6cache(m0
, h
, &frag
, &pff
, off
, mff
,
2048 (r
->rule_flag
& PFRULE_FRAGDROP
) ? 1 : 0, &nomem
);
2056 pd
->pf_mtag
->pftag_flags
|= PF_TAG_FRAGCACHE
;
2058 if (pff
!= NULL
&& (pff
->fr_flags
& PFFRAG_DROP
))
2062 /* Enforce a minimum ttl, may cause endless packet loops */
2063 if (r
->min_ttl
&& h
->ip6_hlim
< r
->min_ttl
)
2064 h
->ip6_hlim
= r
->min_ttl
;
2068 REASON_SET(reason
, PFRES_MEMORY
);
2072 REASON_SET(reason
, PFRES_SHORT
);
2076 REASON_SET(reason
, PFRES_NORM
);
2080 DPFPRINTF(("dropping bad IPv6 fragment\n"));
2081 REASON_SET(reason
, PFRES_FRAG
);
2086 pf_free_fragment(pff
);
2087 if (r
!= NULL
&& r
->log
)
2088 PFLOG_PACKET(kif
, h
, m
, AF_INET6
, dir
, *reason
, r
, NULL
, NULL
, pd
);
2094 pf_normalize_tcp(int dir
, struct pfi_kif
*kif
, struct mbuf
*m
, int ipoff
,
2095 int off
, void *h
, struct pf_pdesc
*pd
)
2097 #pragma unused(ipoff, h)
2098 struct pf_rule
*r
, *rm
= NULL
;
2099 struct tcphdr
*th
= pd
->hdr
.tcp
;
2104 sa_family_t af
= pd
->af
;
2105 struct pf_ruleset
*ruleset
= NULL
;
2106 union pf_state_xport sxport
, dxport
;
2108 sxport
.port
= th
->th_sport
;
2109 dxport
.port
= th
->th_dport
;
2111 r
= TAILQ_FIRST(pf_main_ruleset
.rules
[PF_RULESET_SCRUB
].active
.ptr
);
2114 if (pfi_kif_match(r
->kif
, kif
) == r
->ifnot
)
2115 r
= r
->skip
[PF_SKIP_IFP
].ptr
;
2116 else if (r
->direction
&& r
->direction
!= dir
)
2117 r
= r
->skip
[PF_SKIP_DIR
].ptr
;
2118 else if (r
->af
&& r
->af
!= af
)
2119 r
= r
->skip
[PF_SKIP_AF
].ptr
;
2120 else if (r
->proto
&& r
->proto
!= pd
->proto
)
2121 r
= r
->skip
[PF_SKIP_PROTO
].ptr
;
2122 else if (PF_MISMATCHAW(&r
->src
.addr
, pd
->src
, af
,
2124 r
= r
->skip
[PF_SKIP_SRC_ADDR
].ptr
;
2125 else if (r
->src
.xport
.range
.op
&&
2126 !pf_match_xport(r
->src
.xport
.range
.op
, r
->proto_variant
,
2127 &r
->src
.xport
, &sxport
))
2128 r
= r
->skip
[PF_SKIP_SRC_PORT
].ptr
;
2129 else if (PF_MISMATCHAW(&r
->dst
.addr
, pd
->dst
, af
,
2131 r
= r
->skip
[PF_SKIP_DST_ADDR
].ptr
;
2132 else if (r
->dst
.xport
.range
.op
&&
2133 !pf_match_xport(r
->dst
.xport
.range
.op
, r
->proto_variant
,
2134 &r
->dst
.xport
, &dxport
))
2135 r
= r
->skip
[PF_SKIP_DST_PORT
].ptr
;
2136 else if (r
->os_fingerprint
!= PF_OSFP_ANY
&&
2137 !pf_osfp_match(pf_osfp_fingerprint(pd
, m
, off
, th
),
2139 r
= TAILQ_NEXT(r
, entries
);
2141 if (r
->anchor
== NULL
) {
2145 pf_step_into_anchor(&asd
, &ruleset
,
2146 PF_RULESET_SCRUB
, &r
, NULL
, NULL
);
2149 if (r
== NULL
&& pf_step_out_of_anchor(&asd
, &ruleset
,
2150 PF_RULESET_SCRUB
, &r
, NULL
, NULL
))
2154 if (rm
== NULL
|| rm
->action
== PF_NOSCRUB
)
2157 r
->packets
[dir
== PF_OUT
]++;
2158 r
->bytes
[dir
== PF_OUT
] += pd
->tot_len
;
2161 if (rm
->rule_flag
& PFRULE_REASSEMBLE_TCP
)
2162 pd
->flags
|= PFDESC_TCP_NORM
;
2164 flags
= th
->th_flags
;
2165 if (flags
& TH_SYN
) {
2166 /* Illegal packet */
2173 /* Illegal packet */
2174 if (!(flags
& (TH_ACK
|TH_RST
)))
2178 if (!(flags
& TH_ACK
)) {
2179 /* These flags are only valid if ACK is set */
2180 if ((flags
& TH_FIN
) || (flags
& TH_PUSH
) || (flags
& TH_URG
))
2184 /* Check for illegal header length */
2185 if (th
->th_off
< (sizeof (struct tcphdr
) >> 2))
2188 /* If flags changed, or reserved data set, then adjust */
2189 if (flags
!= th
->th_flags
|| th
->th_x2
!= 0) {
2192 ov
= *(u_int16_t
*)(&th
->th_ack
+ 1);
2193 th
->th_flags
= flags
;
2195 nv
= *(u_int16_t
*)(&th
->th_ack
+ 1);
2197 th
->th_sum
= pf_cksum_fixup(th
->th_sum
, ov
, nv
, 0);
2201 /* Remove urgent pointer, if TH_URG is not set */
2202 if (!(flags
& TH_URG
) && th
->th_urp
) {
2203 th
->th_sum
= pf_cksum_fixup(th
->th_sum
, th
->th_urp
, 0, 0);
2208 /* copy back packet headers if we sanitized */
2209 /* Process options */
2211 int rv
= pf_normalize_tcpopt(r
, dir
, kif
, pd
, m
, th
, off
,
2219 struct mbuf
*mw
= pf_lazy_makewritable(pd
, m
,
2220 off
+ sizeof (*th
));
2222 REASON_SET(&reason
, PFRES_MEMORY
);
2224 PFLOG_PACKET(kif
, h
, m
, AF_INET
, dir
, reason
,
2229 m_copyback(mw
, off
, sizeof (*th
), th
);
2235 REASON_SET(&reason
, PFRES_NORM
);
2236 if (rm
!= NULL
&& r
->log
)
2237 PFLOG_PACKET(kif
, h
, m
, AF_INET
, dir
, reason
, r
, NULL
, NULL
, pd
);
2242 pf_normalize_tcp_init(struct mbuf
*m
, int off
, struct pf_pdesc
*pd
,
2243 struct tcphdr
*th
, struct pf_state_peer
*src
, struct pf_state_peer
*dst
)
2246 u_int32_t tsval
, tsecr
;
2250 VERIFY(src
->scrub
== NULL
);
2252 src
->scrub
= pool_get(&pf_state_scrub_pl
, PR_NOWAIT
);
2253 if (src
->scrub
== NULL
)
2255 bzero(src
->scrub
, sizeof (*src
->scrub
));
2260 struct ip
*h
= mtod(m
, struct ip
*);
2261 src
->scrub
->pfss_ttl
= h
->ip_ttl
;
2267 struct ip6_hdr
*h
= mtod(m
, struct ip6_hdr
*);
2268 src
->scrub
->pfss_ttl
= h
->ip6_hlim
;
2276 * All normalizations below are only begun if we see the start of
2277 * the connections. They must all set an enabled bit in pfss_flags
2279 if ((th
->th_flags
& TH_SYN
) == 0)
2283 if (th
->th_off
> (sizeof (struct tcphdr
) >> 2) && src
->scrub
&&
2284 pf_pull_hdr(m
, off
, hdr
, th
->th_off
<< 2, NULL
, NULL
, pd
->af
)) {
2285 /* Diddle with TCP options */
2287 opt
= hdr
+ sizeof (struct tcphdr
);
2288 hlen
= (th
->th_off
<< 2) - sizeof (struct tcphdr
);
2289 while (hlen
>= TCPOLEN_TIMESTAMP
) {
2291 case TCPOPT_EOL
: /* FALLTHROUGH */
2296 case TCPOPT_TIMESTAMP
:
2297 if (opt
[1] >= TCPOLEN_TIMESTAMP
) {
2298 src
->scrub
->pfss_flags
|=
2300 src
->scrub
->pfss_ts_mod
=
2303 /* note PFSS_PAWS not set yet */
2304 memcpy(&tsval
, &opt
[2],
2305 sizeof (u_int32_t
));
2306 memcpy(&tsecr
, &opt
[6],
2307 sizeof (u_int32_t
));
2308 src
->scrub
->pfss_tsval0
= ntohl(tsval
);
2309 src
->scrub
->pfss_tsval
= ntohl(tsval
);
2310 src
->scrub
->pfss_tsecr
= ntohl(tsecr
);
2311 getmicrouptime(&src
->scrub
->pfss_last
);
2315 hlen
-= MAX(opt
[1], 2);
2316 opt
+= MAX(opt
[1], 2);
2326 pf_normalize_tcp_cleanup(struct pf_state
*state
)
2328 if (state
->src
.scrub
)
2329 pool_put(&pf_state_scrub_pl
, state
->src
.scrub
);
2330 if (state
->dst
.scrub
)
2331 pool_put(&pf_state_scrub_pl
, state
->dst
.scrub
);
2333 /* Someday... flush the TCP segment reassembly descriptors. */
2337 pf_normalize_tcp_stateful(struct mbuf
*m
, int off
, struct pf_pdesc
*pd
,
2338 u_short
*reason
, struct tcphdr
*th
, struct pf_state
*state
,
2339 struct pf_state_peer
*src
, struct pf_state_peer
*dst
, int *writeback
)
2341 struct timeval uptime
;
2342 u_int32_t tsval
, tsecr
;
2343 u_int tsval_from_last
;
2349 VERIFY(src
->scrub
|| dst
->scrub
);
2352 * Enforce the minimum TTL seen for this connection. Negate a common
2353 * technique to evade an intrusion detection system and confuse
2354 * firewall state code.
2360 struct ip
*h
= mtod(m
, struct ip
*);
2361 if (h
->ip_ttl
> src
->scrub
->pfss_ttl
)
2362 src
->scrub
->pfss_ttl
= h
->ip_ttl
;
2363 h
->ip_ttl
= src
->scrub
->pfss_ttl
;
2371 struct ip6_hdr
*h
= mtod(m
, struct ip6_hdr
*);
2372 if (h
->ip6_hlim
> src
->scrub
->pfss_ttl
)
2373 src
->scrub
->pfss_ttl
= h
->ip6_hlim
;
2374 h
->ip6_hlim
= src
->scrub
->pfss_ttl
;
2381 if (th
->th_off
> (sizeof (struct tcphdr
) >> 2) &&
2382 ((src
->scrub
&& (src
->scrub
->pfss_flags
& PFSS_TIMESTAMP
)) ||
2383 (dst
->scrub
&& (dst
->scrub
->pfss_flags
& PFSS_TIMESTAMP
))) &&
2384 pf_pull_hdr(m
, off
, hdr
, th
->th_off
<< 2, NULL
, NULL
, pd
->af
)) {
2385 /* Diddle with TCP options */
2387 opt
= hdr
+ sizeof (struct tcphdr
);
2388 hlen
= (th
->th_off
<< 2) - sizeof (struct tcphdr
);
2389 while (hlen
>= TCPOLEN_TIMESTAMP
) {
2391 case TCPOPT_EOL
: /* FALLTHROUGH */
2396 case TCPOPT_TIMESTAMP
:
2398 * Modulate the timestamps. Can be used for
2399 * NAT detection, OS uptime determination or
2404 /* Huh? Multiple timestamps!? */
2405 if (pf_status
.debug
>= PF_DEBUG_MISC
) {
2406 DPFPRINTF(("multiple TS??"));
2407 pf_print_state(state
);
2410 REASON_SET(reason
, PFRES_TS
);
2413 if (opt
[1] >= TCPOLEN_TIMESTAMP
) {
2414 memcpy(&tsval
, &opt
[2],
2415 sizeof (u_int32_t
));
2416 if (tsval
&& src
->scrub
&&
2417 (src
->scrub
->pfss_flags
&
2419 tsval
= ntohl(tsval
);
2420 pf_change_a(&opt
[2],
2423 src
->scrub
->pfss_ts_mod
),
2428 /* Modulate TS reply iff valid (!0) */
2429 memcpy(&tsecr
, &opt
[6],
2430 sizeof (u_int32_t
));
2431 if (tsecr
&& dst
->scrub
&&
2432 (dst
->scrub
->pfss_flags
&
2434 tsecr
= ntohl(tsecr
)
2435 - dst
->scrub
->pfss_ts_mod
;
2436 pf_change_a(&opt
[6],
2437 &th
->th_sum
, htonl(tsecr
),
2445 hlen
-= MAX(opt
[1], 2);
2446 opt
+= MAX(opt
[1], 2);
2451 /* Copyback the options, caller copys back header */
2452 int optoff
= off
+ sizeof (*th
);
2453 int optlen
= (th
->th_off
<< 2) - sizeof (*th
);
2454 m
= pf_lazy_makewritable(pd
, m
, optoff
+ optlen
);
2456 REASON_SET(reason
, PFRES_MEMORY
);
2459 *writeback
= optoff
+ optlen
;
2460 m_copyback(m
, optoff
, optlen
, hdr
+ sizeof (*th
));
2466 * Must invalidate PAWS checks on connections idle for too long.
2467 * The fastest allowed timestamp clock is 1ms. That turns out to
2468 * be about 24 days before it wraps. XXX Right now our lowerbound
2469 * TS echo check only works for the first 12 days of a connection
2470 * when the TS has exhausted half its 32bit space
2472 #define TS_MAX_IDLE (24*24*60*60)
2473 #define TS_MAX_CONN (12*24*60*60) /* XXX remove when better tsecr check */
2475 getmicrouptime(&uptime
);
2476 if (src
->scrub
&& (src
->scrub
->pfss_flags
& PFSS_PAWS
) &&
2477 (uptime
.tv_sec
- src
->scrub
->pfss_last
.tv_sec
> TS_MAX_IDLE
||
2478 pf_time_second() - state
->creation
> TS_MAX_CONN
)) {
2479 if (pf_status
.debug
>= PF_DEBUG_MISC
) {
2480 DPFPRINTF(("src idled out of PAWS\n"));
2481 pf_print_state(state
);
2484 src
->scrub
->pfss_flags
= (src
->scrub
->pfss_flags
& ~PFSS_PAWS
)
2487 if (dst
->scrub
&& (dst
->scrub
->pfss_flags
& PFSS_PAWS
) &&
2488 uptime
.tv_sec
- dst
->scrub
->pfss_last
.tv_sec
> TS_MAX_IDLE
) {
2489 if (pf_status
.debug
>= PF_DEBUG_MISC
) {
2490 DPFPRINTF(("dst idled out of PAWS\n"));
2491 pf_print_state(state
);
2494 dst
->scrub
->pfss_flags
= (dst
->scrub
->pfss_flags
& ~PFSS_PAWS
)
2498 if (got_ts
&& src
->scrub
&& dst
->scrub
&&
2499 (src
->scrub
->pfss_flags
& PFSS_PAWS
) &&
2500 (dst
->scrub
->pfss_flags
& PFSS_PAWS
)) {
2502 * Validate that the timestamps are "in-window".
2503 * RFC1323 describes TCP Timestamp options that allow
2504 * measurement of RTT (round trip time) and PAWS
2505 * (protection against wrapped sequence numbers). PAWS
2506 * gives us a set of rules for rejecting packets on
2507 * long fat pipes (packets that were somehow delayed
2508 * in transit longer than the time it took to send the
2509 * full TCP sequence space of 4Gb). We can use these
2510 * rules and infer a few others that will let us treat
2511 * the 32bit timestamp and the 32bit echoed timestamp
2512 * as sequence numbers to prevent a blind attacker from
2513 * inserting packets into a connection.
2516 * - The timestamp on this packet must be greater than
2517 * or equal to the last value echoed by the other
2518 * endpoint. The RFC says those will be discarded
2519 * since it is a dup that has already been acked.
2520 * This gives us a lowerbound on the timestamp.
2521 * timestamp >= other last echoed timestamp
2522 * - The timestamp will be less than or equal to
2523 * the last timestamp plus the time between the
2524 * last packet and now. The RFC defines the max
2525 * clock rate as 1ms. We will allow clocks to be
2526 * up to 10% fast and will allow a total difference
2527 * or 30 seconds due to a route change. And this
2528 * gives us an upperbound on the timestamp.
2529 * timestamp <= last timestamp + max ticks
2530 * We have to be careful here. Windows will send an
2531 * initial timestamp of zero and then initialize it
2532 * to a random value after the 3whs; presumably to
2533 * avoid a DoS by having to call an expensive RNG
2534 * during a SYN flood. Proof MS has at least one
2535 * good security geek.
2537 * - The TCP timestamp option must also echo the other
2538 * endpoints timestamp. The timestamp echoed is the
2539 * one carried on the earliest unacknowledged segment
2540 * on the left edge of the sequence window. The RFC
2541 * states that the host will reject any echoed
2542 * timestamps that were larger than any ever sent.
2543 * This gives us an upperbound on the TS echo.
2544 * tescr <= largest_tsval
2545 * - The lowerbound on the TS echo is a little more
2546 * tricky to determine. The other endpoint's echoed
2547 * values will not decrease. But there may be
2548 * network conditions that re-order packets and
2549 * cause our view of them to decrease. For now the
2550 * only lowerbound we can safely determine is that
2551 * the TS echo will never be less than the original
2552 * TS. XXX There is probably a better lowerbound.
2553 * Remove TS_MAX_CONN with better lowerbound check.
2554 * tescr >= other original TS
2556 * It is also important to note that the fastest
2557 * timestamp clock of 1ms will wrap its 32bit space in
2558 * 24 days. So we just disable TS checking after 24
2559 * days of idle time. We actually must use a 12d
2560 * connection limit until we can come up with a better
2561 * lowerbound to the TS echo check.
2563 struct timeval delta_ts
;
2568 * PFTM_TS_DIFF is how many seconds of leeway to allow
2569 * a host's timestamp. This can happen if the previous
2570 * packet got delayed in transit for much longer than
2573 if ((ts_fudge
= state
->rule
.ptr
->timeout
[PFTM_TS_DIFF
]) == 0)
2574 ts_fudge
= pf_default_rule
.timeout
[PFTM_TS_DIFF
];
2577 /* Calculate max ticks since the last timestamp */
2578 #define TS_MAXFREQ 1100 /* RFC max TS freq of 1Khz + 10% skew */
2579 #define TS_MICROSECS 1000000 /* microseconds per second */
2580 timersub(&uptime
, &src
->scrub
->pfss_last
, &delta_ts
);
2581 tsval_from_last
= (delta_ts
.tv_sec
+ ts_fudge
) * TS_MAXFREQ
;
2582 tsval_from_last
+= delta_ts
.tv_usec
/ (TS_MICROSECS
/TS_MAXFREQ
);
2585 if ((src
->state
>= TCPS_ESTABLISHED
&&
2586 dst
->state
>= TCPS_ESTABLISHED
) &&
2587 (SEQ_LT(tsval
, dst
->scrub
->pfss_tsecr
) ||
2588 SEQ_GT(tsval
, src
->scrub
->pfss_tsval
+ tsval_from_last
) ||
2589 (tsecr
&& (SEQ_GT(tsecr
, dst
->scrub
->pfss_tsval
) ||
2590 SEQ_LT(tsecr
, dst
->scrub
->pfss_tsval0
))))) {
2592 * Bad RFC1323 implementation or an insertion attack.
2594 * - Solaris 2.6 and 2.7 are known to send another ACK
2595 * after the FIN,FIN|ACK,ACK closing that carries
2599 DPFPRINTF(("Timestamp failed %c%c%c%c\n",
2600 SEQ_LT(tsval
, dst
->scrub
->pfss_tsecr
) ? '0' : ' ',
2601 SEQ_GT(tsval
, src
->scrub
->pfss_tsval
+
2602 tsval_from_last
) ? '1' : ' ',
2603 SEQ_GT(tsecr
, dst
->scrub
->pfss_tsval
) ? '2' : ' ',
2604 SEQ_LT(tsecr
, dst
->scrub
->pfss_tsval0
)? '3' : ' '));
2605 DPFPRINTF((" tsval: %u tsecr: %u +ticks: %u "
2606 "idle: %lus %ums\n",
2607 tsval
, tsecr
, tsval_from_last
, delta_ts
.tv_sec
,
2608 delta_ts
.tv_usec
/ 1000));
2609 DPFPRINTF((" src->tsval: %u tsecr: %u\n",
2610 src
->scrub
->pfss_tsval
, src
->scrub
->pfss_tsecr
));
2611 DPFPRINTF((" dst->tsval: %u tsecr: %u tsval0: %u\n",
2612 dst
->scrub
->pfss_tsval
, dst
->scrub
->pfss_tsecr
,
2613 dst
->scrub
->pfss_tsval0
));
2614 if (pf_status
.debug
>= PF_DEBUG_MISC
) {
2615 pf_print_state(state
);
2616 pf_print_flags(th
->th_flags
);
2619 REASON_SET(reason
, PFRES_TS
);
2623 /* XXX I'd really like to require tsecr but it's optional */
2625 } else if (!got_ts
&& (th
->th_flags
& TH_RST
) == 0 &&
2626 ((src
->state
== TCPS_ESTABLISHED
&& dst
->state
== TCPS_ESTABLISHED
)
2627 || pd
->p_len
> 0 || (th
->th_flags
& TH_SYN
)) &&
2628 src
->scrub
&& dst
->scrub
&&
2629 (src
->scrub
->pfss_flags
& PFSS_PAWS
) &&
2630 (dst
->scrub
->pfss_flags
& PFSS_PAWS
)) {
2632 * Didn't send a timestamp. Timestamps aren't really useful
2634 * - connection opening or closing (often not even sent).
2635 * but we must not let an attacker to put a FIN on a
2636 * data packet to sneak it through our ESTABLISHED check.
2637 * - on a TCP reset. RFC suggests not even looking at TS.
2638 * - on an empty ACK. The TS will not be echoed so it will
2639 * probably not help keep the RTT calculation in sync and
2640 * there isn't as much danger when the sequence numbers
2641 * got wrapped. So some stacks don't include TS on empty
2644 * To minimize the disruption to mostly RFC1323 conformant
2645 * stacks, we will only require timestamps on data packets.
2647 * And what do ya know, we cannot require timestamps on data
2648 * packets. There appear to be devices that do legitimate
2649 * TCP connection hijacking. There are HTTP devices that allow
2650 * a 3whs (with timestamps) and then buffer the HTTP request.
2651 * If the intermediate device has the HTTP response cache, it
2652 * will spoof the response but not bother timestamping its
2653 * packets. So we can look for the presence of a timestamp in
2654 * the first data packet and if there, require it in all future
2658 if (pd
->p_len
> 0 && (src
->scrub
->pfss_flags
& PFSS_DATA_TS
)) {
2660 * Hey! Someone tried to sneak a packet in. Or the
2661 * stack changed its RFC1323 behavior?!?!
2663 if (pf_status
.debug
>= PF_DEBUG_MISC
) {
2664 DPFPRINTF(("Did not receive expected RFC1323 "
2666 pf_print_state(state
);
2667 pf_print_flags(th
->th_flags
);
2670 REASON_SET(reason
, PFRES_TS
);
2677 * We will note if a host sends his data packets with or without
2678 * timestamps. And require all data packets to contain a timestamp
2679 * if the first does. PAWS implicitly requires that all data packets be
2680 * timestamped. But I think there are middle-man devices that hijack
2681 * TCP streams immediately after the 3whs and don't timestamp their
2682 * packets (seen in a WWW accelerator or cache).
2684 if (pd
->p_len
> 0 && src
->scrub
&& (src
->scrub
->pfss_flags
&
2685 (PFSS_TIMESTAMP
|PFSS_DATA_TS
|PFSS_DATA_NOTS
)) == PFSS_TIMESTAMP
) {
2687 src
->scrub
->pfss_flags
|= PFSS_DATA_TS
;
2689 src
->scrub
->pfss_flags
|= PFSS_DATA_NOTS
;
2690 if (pf_status
.debug
>= PF_DEBUG_MISC
&& dst
->scrub
&&
2691 (dst
->scrub
->pfss_flags
& PFSS_TIMESTAMP
)) {
2692 /* Don't warn if other host rejected RFC1323 */
2693 DPFPRINTF(("Broken RFC1323 stack did not "
2694 "timestamp data packet. Disabled PAWS "
2696 pf_print_state(state
);
2697 pf_print_flags(th
->th_flags
);
2705 * Update PAWS values
2707 if (got_ts
&& src
->scrub
&& PFSS_TIMESTAMP
== (src
->scrub
->pfss_flags
&
2708 (PFSS_PAWS_IDLED
|PFSS_TIMESTAMP
))) {
2709 getmicrouptime(&src
->scrub
->pfss_last
);
2710 if (SEQ_GEQ(tsval
, src
->scrub
->pfss_tsval
) ||
2711 (src
->scrub
->pfss_flags
& PFSS_PAWS
) == 0)
2712 src
->scrub
->pfss_tsval
= tsval
;
2715 if (SEQ_GEQ(tsecr
, src
->scrub
->pfss_tsecr
) ||
2716 (src
->scrub
->pfss_flags
& PFSS_PAWS
) == 0)
2717 src
->scrub
->pfss_tsecr
= tsecr
;
2719 if ((src
->scrub
->pfss_flags
& PFSS_PAWS
) == 0 &&
2720 (SEQ_LT(tsval
, src
->scrub
->pfss_tsval0
) ||
2721 src
->scrub
->pfss_tsval0
== 0)) {
2722 /* tsval0 MUST be the lowest timestamp */
2723 src
->scrub
->pfss_tsval0
= tsval
;
2726 /* Only fully initialized after a TS gets echoed */
2727 if ((src
->scrub
->pfss_flags
& PFSS_PAWS
) == 0)
2728 src
->scrub
->pfss_flags
|= PFSS_PAWS
;
2732 /* I have a dream.... TCP segment reassembly.... */
2737 pf_normalize_tcpopt(struct pf_rule
*r
, int dir
, struct pfi_kif
*kif
,
2738 struct pf_pdesc
*pd
, struct mbuf
*m
, struct tcphdr
*th
, int off
,
2741 #pragma unused(dir, kif)
2742 sa_family_t af
= pd
->af
;
2745 int opt
, cnt
, optlen
= 0;
2747 u_char opts
[MAX_TCPOPTLEN
];
2748 u_char
*optp
= opts
;
2750 thoff
= th
->th_off
<< 2;
2751 cnt
= thoff
- sizeof (struct tcphdr
);
2753 if (cnt
> 0 && !pf_pull_hdr(m
, off
+ sizeof (*th
), opts
, cnt
,
2757 for (; cnt
> 0; cnt
-= optlen
, optp
+= optlen
) {
2759 if (opt
== TCPOPT_EOL
)
2761 if (opt
== TCPOPT_NOP
)
2767 if (optlen
< 2 || optlen
> cnt
)
2772 mss
= (u_int16_t
*)(void *)(optp
+ 2);
2773 if ((ntohs(*mss
)) > r
->max_mss
) {
2776 * Only do the TCP checksum fixup if delayed
2777 * checksum calculation will not be performed.
2779 if (m
->m_pkthdr
.rcvif
||
2780 !(m
->m_pkthdr
.csum_flags
& CSUM_TCP
))
2781 th
->th_sum
= pf_cksum_fixup(th
->th_sum
,
2782 *mss
, htons(r
->max_mss
), 0);
2783 *mss
= htons(r
->max_mss
);
2796 mw
= pf_lazy_makewritable(pd
, pd
->mp
,
2797 off
+ sizeof (*th
) + thoff
);
2799 REASON_SET(&reason
, PFRES_MEMORY
);
2801 PFLOG_PACKET(kif
, h
, m
, AF_INET
, dir
, reason
,
2807 m_copyback(mw
, off
+ sizeof (*th
), thoff
- sizeof (*th
), opts
);