]>
git.saurik.com Git - apple/xnu.git/blob - bsd/net/pf_norm.c
2 * Copyright (c) 2008 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
;
98 LIST_ENTRY(pf_frcache
) fr_next
;
103 #define PFFRAG_SEENLAST 0x0001 /* Seen the last fragment for this */
104 #define PFFRAG_NOBUFFER 0x0002 /* Non-buffering fragment cache */
105 #define PFFRAG_DROP 0x0004 /* Drop all fragments */
106 #define BUFFER_FRAGMENTS(fr) (!((fr)->fr_flags & PFFRAG_NOBUFFER))
109 RB_ENTRY(pf_fragment
) fr_entry
;
110 TAILQ_ENTRY(pf_fragment
) frag_next
;
111 struct in_addr fr_src
;
112 struct in_addr fr_dst
;
113 u_int8_t fr_p
; /* protocol of this fragment */
114 u_int8_t fr_flags
; /* status flags */
115 u_int16_t fr_id
; /* fragment id for reassemble */
116 u_int16_t fr_max
; /* fragment data max */
117 u_int32_t fr_timeout
;
118 #define fr_queue fr_u.fru_queue
119 #define fr_cache fr_u.fru_cache
121 LIST_HEAD(pf_fragq
, pf_frent
) fru_queue
; /* buffering */
122 LIST_HEAD(pf_cacheq
, pf_frcache
) fru_cache
; /* non-buf */
126 static TAILQ_HEAD(pf_fragqueue
, pf_fragment
) pf_fragqueue
;
127 static TAILQ_HEAD(pf_cachequeue
, pf_fragment
) pf_cachequeue
;
129 static __inline
int pf_frag_compare(struct pf_fragment
*,
130 struct pf_fragment
*);
131 static RB_HEAD(pf_frag_tree
, pf_fragment
) pf_frag_tree
, pf_cache_tree
;
132 RB_PROTOTYPE_SC(__private_extern__
, pf_frag_tree
, pf_fragment
, fr_entry
,
134 RB_GENERATE(pf_frag_tree
, pf_fragment
, fr_entry
, pf_frag_compare
);
136 /* Private prototypes */
137 static void pf_ip2key(struct pf_fragment
*, struct ip
*);
138 static void pf_remove_fragment(struct pf_fragment
*);
139 static void pf_flush_fragments(void);
140 static void pf_free_fragment(struct pf_fragment
*);
141 static struct pf_fragment
*pf_find_fragment(struct ip
*, struct pf_frag_tree
*);
142 static struct mbuf
*pf_reassemble(struct mbuf
**, struct pf_fragment
**,
143 struct pf_frent
*, int);
144 static struct mbuf
*pf_fragcache(struct mbuf
**, struct ip
*,
145 struct pf_fragment
**, int, int, int *);
146 #ifndef NO_APPLE_MODIFICATIONS
147 static int pf_normalize_tcpopt(struct pf_rule
*, int, struct pfi_kif
*,
148 struct pf_pdesc
*, struct mbuf
*, struct tcphdr
*, int, int *);
150 static int pf_normalize_tcpopt(struct pf_rule
*, struct mbuf
*,
151 struct tcphdr
*, int, sa_family_t
);
154 #define DPFPRINTF(x) do { \
155 if (pf_status.debug >= PF_DEBUG_MISC) { \
156 printf("%s: ", __func__); \
162 struct pool pf_frent_pl
, pf_frag_pl
;
163 static struct pool pf_cache_pl
, pf_cent_pl
;
164 struct pool pf_state_scrub_pl
;
166 static int pf_nfrents
, pf_ncache
;
169 pf_normalize_init(void)
171 pool_init(&pf_frent_pl
, sizeof (struct pf_frent
), 0, 0, 0, "pffrent",
173 pool_init(&pf_frag_pl
, sizeof (struct pf_fragment
), 0, 0, 0, "pffrag",
175 pool_init(&pf_cache_pl
, sizeof (struct pf_fragment
), 0, 0, 0,
177 pool_init(&pf_cent_pl
, sizeof (struct pf_frcache
), 0, 0, 0, "pffrcent",
179 pool_init(&pf_state_scrub_pl
, sizeof (struct pf_state_scrub
), 0, 0, 0,
182 pool_sethiwat(&pf_frag_pl
, PFFRAG_FRAG_HIWAT
);
183 pool_sethardlimit(&pf_frent_pl
, PFFRAG_FRENT_HIWAT
, NULL
, 0);
184 pool_sethardlimit(&pf_cache_pl
, PFFRAG_FRCACHE_HIWAT
, NULL
, 0);
185 pool_sethardlimit(&pf_cent_pl
, PFFRAG_FRCENT_HIWAT
, NULL
, 0);
187 TAILQ_INIT(&pf_fragqueue
);
188 TAILQ_INIT(&pf_cachequeue
);
193 pf_normalize_destroy(void)
195 pool_destroy(&pf_state_scrub_pl
);
196 pool_destroy(&pf_cent_pl
);
197 pool_destroy(&pf_cache_pl
);
198 pool_destroy(&pf_frag_pl
);
199 pool_destroy(&pf_frent_pl
);
204 pf_normalize_isempty(void)
206 return (TAILQ_EMPTY(&pf_fragqueue
) && TAILQ_EMPTY(&pf_cachequeue
));
210 pf_frag_compare(struct pf_fragment
*a
, struct pf_fragment
*b
)
214 if ((diff
= a
->fr_id
- b
->fr_id
))
216 else if ((diff
= a
->fr_p
- b
->fr_p
))
218 else if (a
->fr_src
.s_addr
< b
->fr_src
.s_addr
)
220 else if (a
->fr_src
.s_addr
> b
->fr_src
.s_addr
)
222 else if (a
->fr_dst
.s_addr
< b
->fr_dst
.s_addr
)
224 else if (a
->fr_dst
.s_addr
> b
->fr_dst
.s_addr
)
230 pf_purge_expired_fragments(void)
232 struct pf_fragment
*frag
;
233 u_int32_t expire
= pf_time_second() -
234 pf_default_rule
.timeout
[PFTM_FRAG
];
236 while ((frag
= TAILQ_LAST(&pf_fragqueue
, pf_fragqueue
)) != NULL
) {
237 VERIFY(BUFFER_FRAGMENTS(frag
));
238 if (frag
->fr_timeout
> expire
)
241 DPFPRINTF(("expiring %d(%p)\n", frag
->fr_id
, frag
));
242 pf_free_fragment(frag
);
245 while ((frag
= TAILQ_LAST(&pf_cachequeue
, pf_cachequeue
)) != NULL
) {
246 VERIFY(!BUFFER_FRAGMENTS(frag
));
247 if (frag
->fr_timeout
> expire
)
250 DPFPRINTF(("expiring %d(%p)\n", frag
->fr_id
, frag
));
251 pf_free_fragment(frag
);
252 VERIFY(TAILQ_EMPTY(&pf_cachequeue
) ||
253 TAILQ_LAST(&pf_cachequeue
, pf_cachequeue
) != frag
);
258 * Try to flush old fragments to make space for new ones
262 pf_flush_fragments(void)
264 struct pf_fragment
*frag
;
267 goal
= pf_nfrents
* 9 / 10;
268 DPFPRINTF(("trying to free > %d frents\n",
270 while (goal
< pf_nfrents
) {
271 frag
= TAILQ_LAST(&pf_fragqueue
, pf_fragqueue
);
274 pf_free_fragment(frag
);
278 goal
= pf_ncache
* 9 / 10;
279 DPFPRINTF(("trying to free > %d cache entries\n",
281 while (goal
< pf_ncache
) {
282 frag
= TAILQ_LAST(&pf_cachequeue
, pf_cachequeue
);
285 pf_free_fragment(frag
);
289 /* Frees the fragments and all associated entries */
292 pf_free_fragment(struct pf_fragment
*frag
)
294 struct pf_frent
*frent
;
295 struct pf_frcache
*frcache
;
297 /* Free all fragments */
298 if (BUFFER_FRAGMENTS(frag
)) {
299 for (frent
= LIST_FIRST(&frag
->fr_queue
); frent
;
300 frent
= LIST_FIRST(&frag
->fr_queue
)) {
301 LIST_REMOVE(frent
, fr_next
);
303 m_freem(frent
->fr_m
);
304 pool_put(&pf_frent_pl
, frent
);
308 for (frcache
= LIST_FIRST(&frag
->fr_cache
); frcache
;
309 frcache
= LIST_FIRST(&frag
->fr_cache
)) {
310 LIST_REMOVE(frcache
, fr_next
);
312 VERIFY(LIST_EMPTY(&frag
->fr_cache
) ||
313 LIST_FIRST(&frag
->fr_cache
)->fr_off
>
316 pool_put(&pf_cent_pl
, frcache
);
321 pf_remove_fragment(frag
);
325 pf_ip2key(struct pf_fragment
*key
, struct ip
*ip
)
327 key
->fr_p
= ip
->ip_p
;
328 key
->fr_id
= ip
->ip_id
;
329 key
->fr_src
.s_addr
= ip
->ip_src
.s_addr
;
330 key
->fr_dst
.s_addr
= ip
->ip_dst
.s_addr
;
333 static struct pf_fragment
*
334 pf_find_fragment(struct ip
*ip
, struct pf_frag_tree
*tree
)
336 struct pf_fragment key
;
337 struct pf_fragment
*frag
;
341 frag
= RB_FIND(pf_frag_tree
, tree
, &key
);
343 /* XXX Are we sure we want to update the timeout? */
344 frag
->fr_timeout
= pf_time_second();
345 if (BUFFER_FRAGMENTS(frag
)) {
346 TAILQ_REMOVE(&pf_fragqueue
, frag
, frag_next
);
347 TAILQ_INSERT_HEAD(&pf_fragqueue
, frag
, frag_next
);
349 TAILQ_REMOVE(&pf_cachequeue
, frag
, frag_next
);
350 TAILQ_INSERT_HEAD(&pf_cachequeue
, frag
, frag_next
);
357 /* Removes a fragment from the fragment queue and frees the fragment */
360 pf_remove_fragment(struct pf_fragment
*frag
)
362 if (BUFFER_FRAGMENTS(frag
)) {
363 RB_REMOVE(pf_frag_tree
, &pf_frag_tree
, frag
);
364 TAILQ_REMOVE(&pf_fragqueue
, frag
, frag_next
);
365 pool_put(&pf_frag_pl
, frag
);
367 RB_REMOVE(pf_frag_tree
, &pf_cache_tree
, frag
);
368 TAILQ_REMOVE(&pf_cachequeue
, frag
, frag_next
);
369 pool_put(&pf_cache_pl
, frag
);
373 #define FR_IP_OFF(fr) ((ntohs((fr)->fr_ip->ip_off) & IP_OFFMASK) << 3)
375 pf_reassemble(struct mbuf
**m0
, struct pf_fragment
**frag
,
376 struct pf_frent
*frent
, int mff
)
378 struct mbuf
*m
= *m0
, *m2
;
379 struct pf_frent
*frea
, *next
;
380 struct pf_frent
*frep
= NULL
;
381 struct ip
*ip
= frent
->fr_ip
;
382 int hlen
= ip
->ip_hl
<< 2;
383 u_int16_t off
= (ntohs(ip
->ip_off
) & IP_OFFMASK
) << 3;
384 u_int16_t ip_len
= ntohs(ip
->ip_len
) - ip
->ip_hl
* 4;
385 u_int16_t fr_max
= ip_len
+ off
;
387 VERIFY(*frag
== NULL
|| BUFFER_FRAGMENTS(*frag
));
389 /* Strip off ip header */
393 /* Create a new reassembly queue for this packet */
395 *frag
= pool_get(&pf_frag_pl
, PR_NOWAIT
);
397 pf_flush_fragments();
398 *frag
= pool_get(&pf_frag_pl
, PR_NOWAIT
);
403 (*frag
)->fr_flags
= 0;
405 (*frag
)->fr_src
= frent
->fr_ip
->ip_src
;
406 (*frag
)->fr_dst
= frent
->fr_ip
->ip_dst
;
407 (*frag
)->fr_p
= frent
->fr_ip
->ip_p
;
408 (*frag
)->fr_id
= frent
->fr_ip
->ip_id
;
409 (*frag
)->fr_timeout
= pf_time_second();
410 LIST_INIT(&(*frag
)->fr_queue
);
412 RB_INSERT(pf_frag_tree
, &pf_frag_tree
, *frag
);
413 TAILQ_INSERT_HEAD(&pf_fragqueue
, *frag
, frag_next
);
415 /* We do not have a previous fragment */
421 * Find a fragment after the current one:
422 * - off contains the real shifted offset.
424 LIST_FOREACH(frea
, &(*frag
)->fr_queue
, fr_next
) {
425 if (FR_IP_OFF(frea
) > off
)
430 VERIFY(frep
!= NULL
|| frea
!= NULL
);
433 FR_IP_OFF(frep
) + ntohs(frep
->fr_ip
->ip_len
) - frep
->fr_ip
->ip_hl
*
437 precut
= FR_IP_OFF(frep
) + ntohs(frep
->fr_ip
->ip_len
) -
438 frep
->fr_ip
->ip_hl
* 4 - off
;
439 if (precut
>= ip_len
)
441 m_adj(frent
->fr_m
, precut
);
442 DPFPRINTF(("overlap -%d\n", precut
));
443 /* Enforce 8 byte boundaries */
444 ip
->ip_off
= htons(ntohs(ip
->ip_off
) + (precut
>> 3));
445 off
= (ntohs(ip
->ip_off
) & IP_OFFMASK
) << 3;
447 ip
->ip_len
= htons(ip_len
);
450 for (; frea
!= NULL
&& ip_len
+ off
> FR_IP_OFF(frea
);
454 aftercut
= ip_len
+ off
- FR_IP_OFF(frea
);
455 DPFPRINTF(("adjust overlap %d\n", aftercut
));
456 if (aftercut
< ntohs(frea
->fr_ip
->ip_len
) - frea
->fr_ip
->ip_hl
458 frea
->fr_ip
->ip_len
=
459 htons(ntohs(frea
->fr_ip
->ip_len
) - aftercut
);
460 frea
->fr_ip
->ip_off
= htons(ntohs(frea
->fr_ip
->ip_off
) +
462 m_adj(frea
->fr_m
, aftercut
);
466 /* This fragment is completely overlapped, lose it */
467 next
= LIST_NEXT(frea
, fr_next
);
469 LIST_REMOVE(frea
, fr_next
);
470 pool_put(&pf_frent_pl
, frea
);
475 /* Update maximum data size */
476 if ((*frag
)->fr_max
< fr_max
)
477 (*frag
)->fr_max
= fr_max
;
478 /* This is the last segment */
480 (*frag
)->fr_flags
|= PFFRAG_SEENLAST
;
483 LIST_INSERT_HEAD(&(*frag
)->fr_queue
, frent
, fr_next
);
485 LIST_INSERT_AFTER(frep
, frent
, fr_next
);
487 /* Check if we are completely reassembled */
488 if (!((*frag
)->fr_flags
& PFFRAG_SEENLAST
))
491 /* Check if we have all the data */
493 for (frep
= LIST_FIRST(&(*frag
)->fr_queue
); frep
; frep
= next
) {
494 next
= LIST_NEXT(frep
, fr_next
);
496 off
+= ntohs(frep
->fr_ip
->ip_len
) - frep
->fr_ip
->ip_hl
* 4;
497 if (off
< (*frag
)->fr_max
&&
498 (next
== NULL
|| FR_IP_OFF(next
) != off
)) {
499 DPFPRINTF(("missing fragment at %d, next %d, max %d\n",
500 off
, next
== NULL
? -1 : FR_IP_OFF(next
),
505 DPFPRINTF(("%d < %d?\n", off
, (*frag
)->fr_max
));
506 if (off
< (*frag
)->fr_max
)
509 /* We have all the data */
510 frent
= LIST_FIRST(&(*frag
)->fr_queue
);
511 VERIFY(frent
!= NULL
);
512 if ((frent
->fr_ip
->ip_hl
<< 2) + off
> IP_MAXPACKET
) {
513 DPFPRINTF(("drop: too big: %d\n", off
));
514 pf_free_fragment(*frag
);
518 next
= LIST_NEXT(frent
, fr_next
);
520 /* Magic from ip_input */
526 pool_put(&pf_frent_pl
, frent
);
528 for (frent
= next
; frent
!= NULL
; frent
= next
) {
529 next
= LIST_NEXT(frent
, fr_next
);
532 pool_put(&pf_frent_pl
, frent
);
537 ip
->ip_src
= (*frag
)->fr_src
;
538 ip
->ip_dst
= (*frag
)->fr_dst
;
540 /* Remove from fragment queue */
541 pf_remove_fragment(*frag
);
544 hlen
= ip
->ip_hl
<< 2;
545 ip
->ip_len
= htons(off
+ hlen
);
549 /* some debugging cruft by sklower, below, will go away soon */
550 /* XXX this should be done elsewhere */
551 if (m
->m_flags
& M_PKTHDR
) {
553 for (m2
= m
; m2
; m2
= m2
->m_next
)
555 m
->m_pkthdr
.len
= plen
;
558 DPFPRINTF(("complete: %p(%d)\n", m
, ntohs(ip
->ip_len
)));
562 /* Oops - fail safe - drop packet */
563 pool_put(&pf_frent_pl
, frent
);
570 pf_fragcache(struct mbuf
**m0
, struct ip
*h
, struct pf_fragment
**frag
, int mff
,
571 int drop
, int *nomem
)
573 struct mbuf
*m
= *m0
;
574 struct pf_frcache
*frp
, *fra
, *cur
= NULL
;
575 int ip_len
= ntohs(h
->ip_len
) - (h
->ip_hl
<< 2);
576 u_int16_t off
= ntohs(h
->ip_off
) << 3;
577 u_int16_t fr_max
= ip_len
+ off
;
580 VERIFY(*frag
== NULL
|| !BUFFER_FRAGMENTS(*frag
));
582 /* Create a new range queue for this packet */
584 *frag
= pool_get(&pf_cache_pl
, PR_NOWAIT
);
586 pf_flush_fragments();
587 *frag
= pool_get(&pf_cache_pl
, PR_NOWAIT
);
592 /* Get an entry for the queue */
593 cur
= pool_get(&pf_cent_pl
, PR_NOWAIT
);
595 pool_put(&pf_cache_pl
, *frag
);
601 (*frag
)->fr_flags
= PFFRAG_NOBUFFER
;
603 (*frag
)->fr_src
= h
->ip_src
;
604 (*frag
)->fr_dst
= h
->ip_dst
;
605 (*frag
)->fr_p
= h
->ip_p
;
606 (*frag
)->fr_id
= h
->ip_id
;
607 (*frag
)->fr_timeout
= pf_time_second();
610 cur
->fr_end
= fr_max
;
611 LIST_INIT(&(*frag
)->fr_cache
);
612 LIST_INSERT_HEAD(&(*frag
)->fr_cache
, cur
, fr_next
);
614 RB_INSERT(pf_frag_tree
, &pf_cache_tree
, *frag
);
615 TAILQ_INSERT_HEAD(&pf_cachequeue
, *frag
, frag_next
);
617 DPFPRINTF(("fragcache[%d]: new %d-%d\n", h
->ip_id
, off
,
624 * Find a fragment after the current one:
625 * - off contains the real shifted offset.
628 LIST_FOREACH(fra
, &(*frag
)->fr_cache
, fr_next
) {
629 if (fra
->fr_off
> off
)
634 VERIFY(frp
!= NULL
|| fra
!= NULL
);
639 precut
= frp
->fr_end
- off
;
640 if (precut
>= ip_len
) {
641 /* Fragment is entirely a duplicate */
642 DPFPRINTF(("fragcache[%d]: dead (%d-%d) %d-%d\n",
643 h
->ip_id
, frp
->fr_off
, frp
->fr_end
, off
, fr_max
));
647 /* They are adjacent. Fixup cache entry */
648 DPFPRINTF(("fragcache[%d]: adjacent (%d-%d) %d-%d\n",
649 h
->ip_id
, frp
->fr_off
, frp
->fr_end
, off
, fr_max
));
650 frp
->fr_end
= fr_max
;
651 } else if (precut
> 0) {
653 * The first part of this payload overlaps with a
654 * fragment that has already been passed.
655 * Need to trim off the first part of the payload.
656 * But to do so easily, we need to create another
657 * mbuf to throw the original header into.
660 DPFPRINTF(("fragcache[%d]: chop %d (%d-%d) %d-%d\n",
661 h
->ip_id
, precut
, frp
->fr_off
, frp
->fr_end
, off
,
666 /* Update the previous frag to encompass this one */
667 frp
->fr_end
= fr_max
;
671 * XXX Optimization opportunity
672 * This is a very heavy way to trim the payload.
673 * we could do it much faster by diddling mbuf
674 * internals but that would be even less legible
675 * than this mbuf magic. For my next trick,
676 * I'll pull a rabbit out of my laptop.
678 *m0
= m_copym(m
, 0, h
->ip_hl
<< 2, M_NOWAIT
);
681 VERIFY((*m0
)->m_next
== NULL
);
682 m_adj(m
, precut
+ (h
->ip_hl
<< 2));
685 if (m
->m_flags
& M_PKTHDR
) {
688 for (t
= m
; t
; t
= t
->m_next
)
690 m
->m_pkthdr
.len
= plen
;
694 h
= mtod(m
, struct ip
*);
697 VERIFY((int)m
->m_len
==
698 ntohs(h
->ip_len
) - precut
);
699 h
->ip_off
= htons(ntohs(h
->ip_off
) +
701 h
->ip_len
= htons(ntohs(h
->ip_len
) - precut
);
706 /* There is a gap between fragments */
708 DPFPRINTF(("fragcache[%d]: gap %d (%d-%d) %d-%d\n",
709 h
->ip_id
, -precut
, frp
->fr_off
, frp
->fr_end
, off
,
712 cur
= pool_get(&pf_cent_pl
, PR_NOWAIT
);
718 cur
->fr_end
= fr_max
;
719 LIST_INSERT_AFTER(frp
, cur
, fr_next
);
727 aftercut
= fr_max
- fra
->fr_off
;
729 /* Adjacent fragments */
730 DPFPRINTF(("fragcache[%d]: adjacent %d-%d (%d-%d)\n",
731 h
->ip_id
, off
, fr_max
, fra
->fr_off
, fra
->fr_end
));
734 } else if (aftercut
> 0) {
735 /* Need to chop off the tail of this fragment */
736 DPFPRINTF(("fragcache[%d]: chop %d %d-%d (%d-%d)\n",
737 h
->ip_id
, aftercut
, off
, fr_max
, fra
->fr_off
,
746 if (m
->m_flags
& M_PKTHDR
) {
749 for (t
= m
; t
; t
= t
->m_next
)
751 m
->m_pkthdr
.len
= plen
;
753 h
= mtod(m
, struct ip
*);
754 VERIFY((int)m
->m_len
==
755 ntohs(h
->ip_len
) - aftercut
);
756 h
->ip_len
= htons(ntohs(h
->ip_len
) - aftercut
);
760 } else if (frp
== NULL
) {
761 /* There is a gap between fragments */
762 DPFPRINTF(("fragcache[%d]: gap %d %d-%d (%d-%d)\n",
763 h
->ip_id
, -aftercut
, off
, fr_max
, fra
->fr_off
,
766 cur
= pool_get(&pf_cent_pl
, PR_NOWAIT
);
772 cur
->fr_end
= fr_max
;
773 LIST_INSERT_BEFORE(fra
, cur
, fr_next
);
777 /* Need to glue together two separate fragment descriptors */
779 if (cur
&& fra
->fr_off
<= cur
->fr_end
) {
780 /* Need to merge in a previous 'cur' */
781 DPFPRINTF(("fragcache[%d]: adjacent(merge "
782 "%d-%d) %d-%d (%d-%d)\n",
783 h
->ip_id
, cur
->fr_off
, cur
->fr_end
, off
,
784 fr_max
, fra
->fr_off
, fra
->fr_end
));
785 fra
->fr_off
= cur
->fr_off
;
786 LIST_REMOVE(cur
, fr_next
);
787 pool_put(&pf_cent_pl
, cur
);
791 } else if (frp
&& fra
->fr_off
<= frp
->fr_end
) {
792 /* Need to merge in a modified 'frp' */
794 DPFPRINTF(("fragcache[%d]: adjacent(merge "
795 "%d-%d) %d-%d (%d-%d)\n",
796 h
->ip_id
, frp
->fr_off
, frp
->fr_end
, off
,
797 fr_max
, fra
->fr_off
, fra
->fr_end
));
798 fra
->fr_off
= frp
->fr_off
;
799 LIST_REMOVE(frp
, fr_next
);
800 pool_put(&pf_cent_pl
, frp
);
810 * We must keep tracking the overall fragment even when
811 * we're going to drop it anyway so that we know when to
812 * free the overall descriptor. Thus we drop the frag late.
819 /* Update maximum data size */
820 if ((*frag
)->fr_max
< fr_max
)
821 (*frag
)->fr_max
= fr_max
;
823 /* This is the last segment */
825 (*frag
)->fr_flags
|= PFFRAG_SEENLAST
;
827 /* Check if we are completely reassembled */
828 if (((*frag
)->fr_flags
& PFFRAG_SEENLAST
) &&
829 LIST_FIRST(&(*frag
)->fr_cache
)->fr_off
== 0 &&
830 LIST_FIRST(&(*frag
)->fr_cache
)->fr_end
== (*frag
)->fr_max
) {
831 /* Remove from fragment queue */
832 DPFPRINTF(("fragcache[%d]: done 0-%d\n", h
->ip_id
,
834 pf_free_fragment(*frag
);
843 /* Still need to pay attention to !IP_MF */
844 if (!mff
&& *frag
!= NULL
)
845 (*frag
)->fr_flags
|= PFFRAG_SEENLAST
;
852 /* Still need to pay attention to !IP_MF */
853 if (!mff
&& *frag
!= NULL
)
854 (*frag
)->fr_flags
|= PFFRAG_SEENLAST
;
857 /* This fragment has been deemed bad. Don't reass */
858 if (((*frag
)->fr_flags
& PFFRAG_DROP
) == 0)
859 DPFPRINTF(("fragcache[%d]: dropping overall fragment\n",
861 (*frag
)->fr_flags
|= PFFRAG_DROP
;
869 pf_normalize_ip(struct mbuf
**m0
, int dir
, struct pfi_kif
*kif
, u_short
*reason
,
872 struct mbuf
*m
= *m0
;
874 struct pf_frent
*frent
;
875 struct pf_fragment
*frag
= NULL
;
876 struct ip
*h
= mtod(m
, struct ip
*);
877 int mff
= (ntohs(h
->ip_off
) & IP_MF
);
878 int hlen
= h
->ip_hl
<< 2;
879 u_int16_t fragoff
= (ntohs(h
->ip_off
) & IP_OFFMASK
) << 3;
884 r
= TAILQ_FIRST(pf_main_ruleset
.rules
[PF_RULESET_SCRUB
].active
.ptr
);
887 if (pfi_kif_match(r
->kif
, kif
) == r
->ifnot
)
888 r
= r
->skip
[PF_SKIP_IFP
].ptr
;
889 else if (r
->direction
&& r
->direction
!= dir
)
890 r
= r
->skip
[PF_SKIP_DIR
].ptr
;
891 else if (r
->af
&& r
->af
!= AF_INET
)
892 r
= r
->skip
[PF_SKIP_AF
].ptr
;
893 else if (r
->proto
&& r
->proto
!= h
->ip_p
)
894 r
= r
->skip
[PF_SKIP_PROTO
].ptr
;
895 else if (PF_MISMATCHAW(&r
->src
.addr
,
896 (struct pf_addr
*)&h
->ip_src
.s_addr
, AF_INET
,
898 r
= r
->skip
[PF_SKIP_SRC_ADDR
].ptr
;
899 else if (PF_MISMATCHAW(&r
->dst
.addr
,
900 (struct pf_addr
*)&h
->ip_dst
.s_addr
, AF_INET
,
902 r
= r
->skip
[PF_SKIP_DST_ADDR
].ptr
;
907 if (r
== NULL
|| r
->action
== PF_NOSCRUB
)
910 r
->packets
[dir
== PF_OUT
]++;
911 r
->bytes
[dir
== PF_OUT
] += pd
->tot_len
;
914 /* Check for illegal packets */
915 if (hlen
< (int)sizeof (struct ip
))
918 if (hlen
> ntohs(h
->ip_len
))
921 /* Clear IP_DF if the rule uses the no-df option */
922 if (r
->rule_flag
& PFRULE_NODF
&& h
->ip_off
& htons(IP_DF
)) {
923 u_int16_t ipoff
= h
->ip_off
;
925 h
->ip_off
&= htons(~IP_DF
);
926 h
->ip_sum
= pf_cksum_fixup(h
->ip_sum
, ipoff
, h
->ip_off
, 0);
929 /* We will need other tests here */
930 if (!fragoff
&& !mff
)
934 * We're dealing with a fragment now. Don't allow fragments
935 * with IP_DF to enter the cache. If the flag was cleared by
936 * no-df above, fine. Otherwise drop it.
938 if (h
->ip_off
& htons(IP_DF
)) {
939 DPFPRINTF(("IP_DF\n"));
943 ip_len
= ntohs(h
->ip_len
) - hlen
;
944 ip_off
= (ntohs(h
->ip_off
) & IP_OFFMASK
) << 3;
946 /* All fragments are 8 byte aligned */
947 if (mff
&& (ip_len
& 0x7)) {
948 DPFPRINTF(("mff and %d\n", ip_len
));
952 /* Respect maximum length */
953 if (fragoff
+ ip_len
> IP_MAXPACKET
) {
954 DPFPRINTF(("max packet %d\n", fragoff
+ ip_len
));
957 fr_max
= fragoff
+ ip_len
;
959 if ((r
->rule_flag
& (PFRULE_FRAGCROP
|PFRULE_FRAGDROP
)) == 0) {
960 /* Fully buffer all of the fragments */
962 frag
= pf_find_fragment(h
, &pf_frag_tree
);
964 /* Check if we saw the last fragment already */
965 if (frag
!= NULL
&& (frag
->fr_flags
& PFFRAG_SEENLAST
) &&
966 fr_max
> frag
->fr_max
)
969 /* Get an entry for the fragment queue */
970 frent
= pool_get(&pf_frent_pl
, PR_NOWAIT
);
972 REASON_SET(reason
, PFRES_MEMORY
);
979 /* Might return a completely reassembled mbuf, or NULL */
980 DPFPRINTF(("reass frag %d @ %d-%d\n", h
->ip_id
, fragoff
,
982 *m0
= m
= pf_reassemble(m0
, &frag
, frent
, mff
);
987 /* use mtag from concatenated mbuf chain */
988 pd
->pf_mtag
= pf_find_mtag(m
);
990 if (pd
->pf_mtag
== NULL
) {
991 printf("%s: pf_find_mtag returned NULL(1)\n", __func__
);
992 if ((pd
->pf_mtag
= pf_get_mtag(m
)) == NULL
) {
999 if (frag
!= NULL
&& (frag
->fr_flags
& PFFRAG_DROP
))
1002 h
= mtod(m
, struct ip
*);
1004 /* non-buffering fragment cache (drops or masks overlaps) */
1007 if (dir
== PF_OUT
&& (pd
->pf_mtag
->flags
& PF_TAG_FRAGCACHE
)) {
1009 * Already passed the fragment cache in the
1010 * input direction. If we continued, it would
1011 * appear to be a dup and would be dropped.
1016 frag
= pf_find_fragment(h
, &pf_cache_tree
);
1018 /* Check if we saw the last fragment already */
1019 if (frag
!= NULL
&& (frag
->fr_flags
& PFFRAG_SEENLAST
) &&
1020 fr_max
> frag
->fr_max
) {
1021 if (r
->rule_flag
& PFRULE_FRAGDROP
)
1022 frag
->fr_flags
|= PFFRAG_DROP
;
1026 *m0
= m
= pf_fragcache(m0
, h
, &frag
, mff
,
1027 (r
->rule_flag
& PFRULE_FRAGDROP
) ? 1 : 0, &nomem
);
1034 /* use mtag from copied and trimmed mbuf chain */
1035 pd
->pf_mtag
= pf_find_mtag(m
);
1037 if (pd
->pf_mtag
== NULL
) {
1038 printf("%s: pf_find_mtag returned NULL(2)\n", __func__
);
1039 if ((pd
->pf_mtag
= pf_get_mtag(m
)) == NULL
) {
1047 pd
->pf_mtag
->flags
|= PF_TAG_FRAGCACHE
;
1049 if (frag
!= NULL
&& (frag
->fr_flags
& PFFRAG_DROP
))
1055 /* At this point, only IP_DF is allowed in ip_off */
1056 if (h
->ip_off
& ~htons(IP_DF
)) {
1057 u_int16_t ipoff
= h
->ip_off
;
1059 h
->ip_off
&= htons(IP_DF
);
1060 h
->ip_sum
= pf_cksum_fixup(h
->ip_sum
, ipoff
, h
->ip_off
, 0);
1063 /* Enforce a minimum ttl, may cause endless packet loops */
1064 if (r
->min_ttl
&& h
->ip_ttl
< r
->min_ttl
) {
1065 u_int16_t ip_ttl
= h
->ip_ttl
;
1067 h
->ip_ttl
= r
->min_ttl
;
1068 h
->ip_sum
= pf_cksum_fixup(h
->ip_sum
, ip_ttl
, h
->ip_ttl
, 0);
1071 if (r
->rule_flag
& PFRULE_RANDOMID
) {
1072 u_int16_t ip_id
= h
->ip_id
;
1074 h
->ip_id
= ip_randomid();
1075 h
->ip_sum
= pf_cksum_fixup(h
->ip_sum
, ip_id
, h
->ip_id
, 0);
1077 #endif /* RANDOM_IP_ID */
1078 if ((r
->rule_flag
& (PFRULE_FRAGCROP
|PFRULE_FRAGDROP
)) == 0)
1079 pd
->flags
|= PFDESC_IP_REAS
;
1084 /* Enforce a minimum ttl, may cause endless packet loops */
1085 if (r
->min_ttl
&& h
->ip_ttl
< r
->min_ttl
) {
1086 u_int16_t ip_ttl
= h
->ip_ttl
;
1088 h
->ip_ttl
= r
->min_ttl
;
1089 h
->ip_sum
= pf_cksum_fixup(h
->ip_sum
, ip_ttl
, h
->ip_ttl
, 0);
1091 if ((r
->rule_flag
& (PFRULE_FRAGCROP
|PFRULE_FRAGDROP
)) == 0)
1092 pd
->flags
|= PFDESC_IP_REAS
;
1096 REASON_SET(reason
, PFRES_MEMORY
);
1097 if (r
!= NULL
&& r
->log
)
1098 PFLOG_PACKET(kif
, h
, m
, AF_INET
, dir
, *reason
, r
,
1103 REASON_SET(reason
, PFRES_NORM
);
1104 if (r
!= NULL
&& r
->log
)
1105 PFLOG_PACKET(kif
, h
, m
, AF_INET
, dir
, *reason
, r
,
1110 DPFPRINTF(("dropping bad fragment\n"));
1112 /* Free associated fragments */
1114 pf_free_fragment(frag
);
1116 REASON_SET(reason
, PFRES_FRAG
);
1117 if (r
!= NULL
&& r
->log
)
1118 PFLOG_PACKET(kif
, h
, m
, AF_INET
, dir
, *reason
, r
, NULL
, NULL
, pd
);
1125 pf_normalize_ip6(struct mbuf
**m0
, int dir
, struct pfi_kif
*kif
,
1126 u_short
*reason
, struct pf_pdesc
*pd
)
1128 struct mbuf
*m
= *m0
;
1130 struct ip6_hdr
*h
= mtod(m
, struct ip6_hdr
*);
1136 struct ip6_opt_jumbo jumbo
;
1140 struct ip6_frag frag
;
1141 u_int32_t jumbolen
= 0, plen
;
1142 u_int16_t fragoff
= 0;
1146 r
= TAILQ_FIRST(pf_main_ruleset
.rules
[PF_RULESET_SCRUB
].active
.ptr
);
1149 if (pfi_kif_match(r
->kif
, kif
) == r
->ifnot
)
1150 r
= r
->skip
[PF_SKIP_IFP
].ptr
;
1151 else if (r
->direction
&& r
->direction
!= dir
)
1152 r
= r
->skip
[PF_SKIP_DIR
].ptr
;
1153 else if (r
->af
&& r
->af
!= AF_INET6
)
1154 r
= r
->skip
[PF_SKIP_AF
].ptr
;
1155 #if 0 /* header chain! */
1156 else if (r
->proto
&& r
->proto
!= h
->ip6_nxt
)
1157 r
= r
->skip
[PF_SKIP_PROTO
].ptr
;
1159 else if (PF_MISMATCHAW(&r
->src
.addr
,
1160 (struct pf_addr
*)&h
->ip6_src
, AF_INET6
,
1162 r
= r
->skip
[PF_SKIP_SRC_ADDR
].ptr
;
1163 else if (PF_MISMATCHAW(&r
->dst
.addr
,
1164 (struct pf_addr
*)&h
->ip6_dst
, AF_INET6
,
1166 r
= r
->skip
[PF_SKIP_DST_ADDR
].ptr
;
1171 if (r
== NULL
|| r
->action
== PF_NOSCRUB
)
1174 r
->packets
[dir
== PF_OUT
]++;
1175 r
->bytes
[dir
== PF_OUT
] += pd
->tot_len
;
1178 /* Check for illegal packets */
1179 if ((int)(sizeof (struct ip6_hdr
) + IPV6_MAXPACKET
) < m
->m_pkthdr
.len
)
1182 off
= sizeof (struct ip6_hdr
);
1187 case IPPROTO_FRAGMENT
:
1191 case IPPROTO_ROUTING
:
1192 case IPPROTO_DSTOPTS
:
1193 if (!pf_pull_hdr(m
, off
, &ext
, sizeof (ext
), NULL
,
1196 #ifndef NO_APPLE_EXTENSIONS
1199 * Routing header type zero considered harmful.
1201 if (proto
== IPPROTO_ROUTING
) {
1202 const struct ip6_rthdr
*rh
=
1203 (const struct ip6_rthdr
*)&ext
;
1204 if (rh
->ip6r_type
== IPV6_RTHDR_TYPE_0
)
1209 if (proto
== IPPROTO_AH
)
1210 off
+= (ext
.ip6e_len
+ 2) * 4;
1212 off
+= (ext
.ip6e_len
+ 1) * 8;
1213 proto
= ext
.ip6e_nxt
;
1215 case IPPROTO_HOPOPTS
:
1218 if (!pf_pull_hdr(m
, off
, &ext
, sizeof (ext
), NULL
,
1221 optend
= off
+ (ext
.ip6e_len
+ 1) * 8;
1222 ooff
= off
+ sizeof (ext
);
1224 if (!pf_pull_hdr(m
, ooff
, &opt
.ip6o_type
,
1225 sizeof (opt
.ip6o_type
), NULL
, NULL
,
1228 if (opt
.ip6o_type
== IP6OPT_PAD1
) {
1232 if (!pf_pull_hdr(m
, ooff
, &opt
, sizeof (opt
),
1233 NULL
, NULL
, AF_INET6
))
1235 if (ooff
+ sizeof (opt
) + opt
.ip6o_len
> optend
)
1237 switch (opt
.ip6o_type
) {
1239 if (h
->ip6_plen
!= 0)
1241 if (!pf_pull_hdr(m
, ooff
, &jumbo
,
1242 sizeof (jumbo
), NULL
, NULL
,
1245 memcpy(&jumbolen
, jumbo
.ip6oj_jumbo_len
,
1247 jumbolen
= ntohl(jumbolen
);
1248 if (jumbolen
<= IPV6_MAXPACKET
)
1250 if (sizeof (struct ip6_hdr
) +
1251 jumbolen
!= m
->m_pkthdr
.len
)
1257 ooff
+= sizeof (opt
) + opt
.ip6o_len
;
1258 } while (ooff
< optend
);
1261 proto
= ext
.ip6e_nxt
;
1268 } while (!terminal
);
1270 /* jumbo payload option must be present, or plen > 0 */
1271 if (ntohs(h
->ip6_plen
) == 0)
1274 plen
= ntohs(h
->ip6_plen
);
1277 if ((int)(sizeof (struct ip6_hdr
) + plen
) > m
->m_pkthdr
.len
)
1280 /* Enforce a minimum ttl, may cause endless packet loops */
1281 if (r
->min_ttl
&& h
->ip6_hlim
< r
->min_ttl
)
1282 h
->ip6_hlim
= r
->min_ttl
;
1287 if (ntohs(h
->ip6_plen
) == 0 || jumbolen
)
1289 plen
= ntohs(h
->ip6_plen
);
1291 if (!pf_pull_hdr(m
, off
, &frag
, sizeof (frag
), NULL
, NULL
, AF_INET6
))
1293 fragoff
= ntohs(frag
.ip6f_offlg
& IP6F_OFF_MASK
);
1294 if (fragoff
+ (plen
- off
- sizeof (frag
)) > IPV6_MAXPACKET
)
1297 /* do something about it */
1298 /* remember to set pd->flags |= PFDESC_IP_REAS */
1302 REASON_SET(reason
, PFRES_SHORT
);
1303 if (r
!= NULL
&& r
->log
)
1304 PFLOG_PACKET(kif
, h
, m
, AF_INET6
, dir
, *reason
, r
,
1309 REASON_SET(reason
, PFRES_NORM
);
1310 if (r
!= NULL
&& r
->log
)
1311 PFLOG_PACKET(kif
, h
, m
, AF_INET6
, dir
, *reason
, r
,
1316 REASON_SET(reason
, PFRES_FRAG
);
1317 if (r
!= NULL
&& r
->log
)
1318 PFLOG_PACKET(kif
, h
, m
, AF_INET6
, dir
, *reason
, r
,
1325 pf_normalize_tcp(int dir
, struct pfi_kif
*kif
, struct mbuf
*m
, int ipoff
,
1326 int off
, void *h
, struct pf_pdesc
*pd
)
1328 #pragma unused(ipoff, h)
1329 struct pf_rule
*r
, *rm
= NULL
;
1330 struct tcphdr
*th
= pd
->hdr
.tcp
;
1334 sa_family_t af
= pd
->af
;
1335 #ifndef NO_APPLE_EXTENSIONS
1336 union pf_state_xport sxport
, dxport
;
1338 sxport
.port
= th
->th_sport
;
1339 dxport
.port
= th
->th_dport
;
1342 r
= TAILQ_FIRST(pf_main_ruleset
.rules
[PF_RULESET_SCRUB
].active
.ptr
);
1345 if (pfi_kif_match(r
->kif
, kif
) == r
->ifnot
)
1346 r
= r
->skip
[PF_SKIP_IFP
].ptr
;
1347 else if (r
->direction
&& r
->direction
!= dir
)
1348 r
= r
->skip
[PF_SKIP_DIR
].ptr
;
1349 else if (r
->af
&& r
->af
!= af
)
1350 r
= r
->skip
[PF_SKIP_AF
].ptr
;
1351 else if (r
->proto
&& r
->proto
!= pd
->proto
)
1352 r
= r
->skip
[PF_SKIP_PROTO
].ptr
;
1353 else if (PF_MISMATCHAW(&r
->src
.addr
, pd
->src
, af
,
1355 r
= r
->skip
[PF_SKIP_SRC_ADDR
].ptr
;
1356 #ifndef NO_APPLE_EXTENSIONS
1357 else if (r
->src
.xport
.range
.op
&&
1358 !pf_match_xport(r
->src
.xport
.range
.op
, r
->proto_variant
,
1359 &r
->src
.xport
, &sxport
))
1361 else if (r
->src
.port_op
&& !pf_match_port(r
->src
.port_op
,
1362 r
->src
.port
[0], r
->src
.port
[1], th
->th_sport
))
1364 r
= r
->skip
[PF_SKIP_SRC_PORT
].ptr
;
1365 else if (PF_MISMATCHAW(&r
->dst
.addr
, pd
->dst
, af
,
1367 r
= r
->skip
[PF_SKIP_DST_ADDR
].ptr
;
1368 #ifndef NO_APPLE_EXTENSIONS
1369 else if (r
->dst
.xport
.range
.op
&&
1370 !pf_match_xport(r
->dst
.xport
.range
.op
, r
->proto_variant
,
1371 &r
->dst
.xport
, &dxport
))
1373 else if (r
->dst
.port_op
&& !pf_match_port(r
->dst
.port_op
,
1374 r
->dst
.port
[0], r
->dst
.port
[1], th
->th_dport
))
1376 r
= r
->skip
[PF_SKIP_DST_PORT
].ptr
;
1377 else if (r
->os_fingerprint
!= PF_OSFP_ANY
&&
1378 !pf_osfp_match(pf_osfp_fingerprint(pd
, m
, off
, th
),
1380 r
= TAILQ_NEXT(r
, entries
);
1387 if (rm
== NULL
|| rm
->action
== PF_NOSCRUB
)
1390 r
->packets
[dir
== PF_OUT
]++;
1391 r
->bytes
[dir
== PF_OUT
] += pd
->tot_len
;
1394 if (rm
->rule_flag
& PFRULE_REASSEMBLE_TCP
)
1395 pd
->flags
|= PFDESC_TCP_NORM
;
1397 flags
= th
->th_flags
;
1398 if (flags
& TH_SYN
) {
1399 /* Illegal packet */
1406 /* Illegal packet */
1407 if (!(flags
& (TH_ACK
|TH_RST
)))
1411 if (!(flags
& TH_ACK
)) {
1412 /* These flags are only valid if ACK is set */
1413 if ((flags
& TH_FIN
) || (flags
& TH_PUSH
) || (flags
& TH_URG
))
1417 /* Check for illegal header length */
1418 if (th
->th_off
< (sizeof (struct tcphdr
) >> 2))
1421 /* If flags changed, or reserved data set, then adjust */
1422 if (flags
!= th
->th_flags
|| th
->th_x2
!= 0) {
1425 ov
= *(u_int16_t
*)(&th
->th_ack
+ 1);
1426 th
->th_flags
= flags
;
1428 nv
= *(u_int16_t
*)(&th
->th_ack
+ 1);
1430 th
->th_sum
= pf_cksum_fixup(th
->th_sum
, ov
, nv
, 0);
1434 /* Remove urgent pointer, if TH_URG is not set */
1435 if (!(flags
& TH_URG
) && th
->th_urp
) {
1436 th
->th_sum
= pf_cksum_fixup(th
->th_sum
, th
->th_urp
, 0, 0);
1441 /* copy back packet headers if we sanitized */
1442 #ifndef NO_APPLE_EXTENSIONS
1443 /* Process options */
1445 int rv
= pf_normalize_tcpopt(r
, dir
, kif
, pd
, m
, th
, off
,
1453 struct mbuf
*mw
= pf_lazy_makewritable(pd
, m
,
1454 off
+ sizeof (*th
));
1456 REASON_SET(&reason
, PFRES_MEMORY
);
1458 PFLOG_PACKET(kif
, h
, m
, AF_INET
, dir
, reason
,
1463 m_copyback(mw
, off
, sizeof (*th
), th
);
1466 /* Process options */
1467 if (r
->max_mss
&& pf_normalize_tcpopt(r
, m
, th
, off
, pd
->af
))
1471 m_copyback(m
, off
, sizeof (*th
), th
);
1477 REASON_SET(&reason
, PFRES_NORM
);
1478 if (rm
!= NULL
&& r
->log
)
1479 PFLOG_PACKET(kif
, h
, m
, AF_INET
, dir
, reason
, r
, NULL
, NULL
, pd
);
1484 pf_normalize_tcp_init(struct mbuf
*m
, int off
, struct pf_pdesc
*pd
,
1485 struct tcphdr
*th
, struct pf_state_peer
*src
, struct pf_state_peer
*dst
)
1488 u_int32_t tsval
, tsecr
;
1492 VERIFY(src
->scrub
== NULL
);
1494 src
->scrub
= pool_get(&pf_state_scrub_pl
, PR_NOWAIT
);
1495 if (src
->scrub
== NULL
)
1497 bzero(src
->scrub
, sizeof (*src
->scrub
));
1502 struct ip
*h
= mtod(m
, struct ip
*);
1503 src
->scrub
->pfss_ttl
= h
->ip_ttl
;
1509 struct ip6_hdr
*h
= mtod(m
, struct ip6_hdr
*);
1510 src
->scrub
->pfss_ttl
= h
->ip6_hlim
;
1518 * All normalizations below are only begun if we see the start of
1519 * the connections. They must all set an enabled bit in pfss_flags
1521 if ((th
->th_flags
& TH_SYN
) == 0)
1525 if (th
->th_off
> (sizeof (struct tcphdr
) >> 2) && src
->scrub
&&
1526 pf_pull_hdr(m
, off
, hdr
, th
->th_off
<< 2, NULL
, NULL
, pd
->af
)) {
1527 /* Diddle with TCP options */
1529 opt
= hdr
+ sizeof (struct tcphdr
);
1530 hlen
= (th
->th_off
<< 2) - sizeof (struct tcphdr
);
1531 while (hlen
>= TCPOLEN_TIMESTAMP
) {
1533 case TCPOPT_EOL
: /* FALLTHROUGH */
1538 case TCPOPT_TIMESTAMP
:
1539 if (opt
[1] >= TCPOLEN_TIMESTAMP
) {
1540 src
->scrub
->pfss_flags
|=
1542 src
->scrub
->pfss_ts_mod
=
1545 /* note PFSS_PAWS not set yet */
1546 memcpy(&tsval
, &opt
[2],
1547 sizeof (u_int32_t
));
1548 memcpy(&tsecr
, &opt
[6],
1549 sizeof (u_int32_t
));
1550 src
->scrub
->pfss_tsval0
= ntohl(tsval
);
1551 src
->scrub
->pfss_tsval
= ntohl(tsval
);
1552 src
->scrub
->pfss_tsecr
= ntohl(tsecr
);
1553 getmicrouptime(&src
->scrub
->pfss_last
);
1557 hlen
-= MAX(opt
[1], 2);
1558 opt
+= MAX(opt
[1], 2);
1568 pf_normalize_tcp_cleanup(struct pf_state
*state
)
1570 if (state
->src
.scrub
)
1571 pool_put(&pf_state_scrub_pl
, state
->src
.scrub
);
1572 if (state
->dst
.scrub
)
1573 pool_put(&pf_state_scrub_pl
, state
->dst
.scrub
);
1575 /* Someday... flush the TCP segment reassembly descriptors. */
1579 pf_normalize_tcp_stateful(struct mbuf
*m
, int off
, struct pf_pdesc
*pd
,
1580 u_short
*reason
, struct tcphdr
*th
, struct pf_state
*state
,
1581 struct pf_state_peer
*src
, struct pf_state_peer
*dst
, int *writeback
)
1583 struct timeval uptime
;
1584 u_int32_t tsval
, tsecr
;
1585 u_int tsval_from_last
;
1591 VERIFY(src
->scrub
|| dst
->scrub
);
1594 * Enforce the minimum TTL seen for this connection. Negate a common
1595 * technique to evade an intrusion detection system and confuse
1596 * firewall state code.
1602 struct ip
*h
= mtod(m
, struct ip
*);
1603 if (h
->ip_ttl
> src
->scrub
->pfss_ttl
)
1604 src
->scrub
->pfss_ttl
= h
->ip_ttl
;
1605 h
->ip_ttl
= src
->scrub
->pfss_ttl
;
1613 struct ip6_hdr
*h
= mtod(m
, struct ip6_hdr
*);
1614 if (h
->ip6_hlim
> src
->scrub
->pfss_ttl
)
1615 src
->scrub
->pfss_ttl
= h
->ip6_hlim
;
1616 h
->ip6_hlim
= src
->scrub
->pfss_ttl
;
1623 if (th
->th_off
> (sizeof (struct tcphdr
) >> 2) &&
1624 ((src
->scrub
&& (src
->scrub
->pfss_flags
& PFSS_TIMESTAMP
)) ||
1625 (dst
->scrub
&& (dst
->scrub
->pfss_flags
& PFSS_TIMESTAMP
))) &&
1626 pf_pull_hdr(m
, off
, hdr
, th
->th_off
<< 2, NULL
, NULL
, pd
->af
)) {
1627 /* Diddle with TCP options */
1629 opt
= hdr
+ sizeof (struct tcphdr
);
1630 hlen
= (th
->th_off
<< 2) - sizeof (struct tcphdr
);
1631 while (hlen
>= TCPOLEN_TIMESTAMP
) {
1633 case TCPOPT_EOL
: /* FALLTHROUGH */
1638 case TCPOPT_TIMESTAMP
:
1640 * Modulate the timestamps. Can be used for
1641 * NAT detection, OS uptime determination or
1646 /* Huh? Multiple timestamps!? */
1647 if (pf_status
.debug
>= PF_DEBUG_MISC
) {
1648 DPFPRINTF(("multiple TS??"));
1649 pf_print_state(state
);
1652 REASON_SET(reason
, PFRES_TS
);
1655 if (opt
[1] >= TCPOLEN_TIMESTAMP
) {
1656 memcpy(&tsval
, &opt
[2],
1657 sizeof (u_int32_t
));
1658 if (tsval
&& src
->scrub
&&
1659 (src
->scrub
->pfss_flags
&
1661 tsval
= ntohl(tsval
);
1662 pf_change_a(&opt
[2],
1665 src
->scrub
->pfss_ts_mod
),
1670 /* Modulate TS reply iff valid (!0) */
1671 memcpy(&tsecr
, &opt
[6],
1672 sizeof (u_int32_t
));
1673 if (tsecr
&& dst
->scrub
&&
1674 (dst
->scrub
->pfss_flags
&
1676 tsecr
= ntohl(tsecr
)
1677 - dst
->scrub
->pfss_ts_mod
;
1678 pf_change_a(&opt
[6],
1679 &th
->th_sum
, htonl(tsecr
),
1687 hlen
-= MAX(opt
[1], 2);
1688 opt
+= MAX(opt
[1], 2);
1693 /* Copyback the options, caller copys back header */
1694 #ifndef NO_APPLE_EXTENSIONS
1695 int optoff
= off
+ sizeof (*th
);
1696 int optlen
= (th
->th_off
<< 2) - sizeof (*th
);
1697 m
= pf_lazy_makewritable(pd
, m
, optoff
+ optlen
);
1699 REASON_SET(reason
, PFRES_MEMORY
);
1702 *writeback
= optoff
+ optlen
;
1703 m_copyback(m
, optoff
, optlen
, hdr
+ sizeof (*th
));
1706 m_copyback(m
, off
+ sizeof (struct tcphdr
),
1707 (th
->th_off
<< 2) - sizeof (struct tcphdr
), hdr
+
1708 sizeof (struct tcphdr
));
1715 * Must invalidate PAWS checks on connections idle for too long.
1716 * The fastest allowed timestamp clock is 1ms. That turns out to
1717 * be about 24 days before it wraps. XXX Right now our lowerbound
1718 * TS echo check only works for the first 12 days of a connection
1719 * when the TS has exhausted half its 32bit space
1721 #define TS_MAX_IDLE (24*24*60*60)
1722 #define TS_MAX_CONN (12*24*60*60) /* XXX remove when better tsecr check */
1724 getmicrouptime(&uptime
);
1725 if (src
->scrub
&& (src
->scrub
->pfss_flags
& PFSS_PAWS
) &&
1726 (uptime
.tv_sec
- src
->scrub
->pfss_last
.tv_sec
> TS_MAX_IDLE
||
1727 pf_time_second() - state
->creation
> TS_MAX_CONN
)) {
1728 if (pf_status
.debug
>= PF_DEBUG_MISC
) {
1729 DPFPRINTF(("src idled out of PAWS\n"));
1730 pf_print_state(state
);
1733 src
->scrub
->pfss_flags
= (src
->scrub
->pfss_flags
& ~PFSS_PAWS
)
1736 if (dst
->scrub
&& (dst
->scrub
->pfss_flags
& PFSS_PAWS
) &&
1737 uptime
.tv_sec
- dst
->scrub
->pfss_last
.tv_sec
> TS_MAX_IDLE
) {
1738 if (pf_status
.debug
>= PF_DEBUG_MISC
) {
1739 DPFPRINTF(("dst idled out of PAWS\n"));
1740 pf_print_state(state
);
1743 dst
->scrub
->pfss_flags
= (dst
->scrub
->pfss_flags
& ~PFSS_PAWS
)
1747 if (got_ts
&& src
->scrub
&& dst
->scrub
&&
1748 (src
->scrub
->pfss_flags
& PFSS_PAWS
) &&
1749 (dst
->scrub
->pfss_flags
& PFSS_PAWS
)) {
1751 * Validate that the timestamps are "in-window".
1752 * RFC1323 describes TCP Timestamp options that allow
1753 * measurement of RTT (round trip time) and PAWS
1754 * (protection against wrapped sequence numbers). PAWS
1755 * gives us a set of rules for rejecting packets on
1756 * long fat pipes (packets that were somehow delayed
1757 * in transit longer than the time it took to send the
1758 * full TCP sequence space of 4Gb). We can use these
1759 * rules and infer a few others that will let us treat
1760 * the 32bit timestamp and the 32bit echoed timestamp
1761 * as sequence numbers to prevent a blind attacker from
1762 * inserting packets into a connection.
1765 * - The timestamp on this packet must be greater than
1766 * or equal to the last value echoed by the other
1767 * endpoint. The RFC says those will be discarded
1768 * since it is a dup that has already been acked.
1769 * This gives us a lowerbound on the timestamp.
1770 * timestamp >= other last echoed timestamp
1771 * - The timestamp will be less than or equal to
1772 * the last timestamp plus the time between the
1773 * last packet and now. The RFC defines the max
1774 * clock rate as 1ms. We will allow clocks to be
1775 * up to 10% fast and will allow a total difference
1776 * or 30 seconds due to a route change. And this
1777 * gives us an upperbound on the timestamp.
1778 * timestamp <= last timestamp + max ticks
1779 * We have to be careful here. Windows will send an
1780 * initial timestamp of zero and then initialize it
1781 * to a random value after the 3whs; presumably to
1782 * avoid a DoS by having to call an expensive RNG
1783 * during a SYN flood. Proof MS has at least one
1784 * good security geek.
1786 * - The TCP timestamp option must also echo the other
1787 * endpoints timestamp. The timestamp echoed is the
1788 * one carried on the earliest unacknowledged segment
1789 * on the left edge of the sequence window. The RFC
1790 * states that the host will reject any echoed
1791 * timestamps that were larger than any ever sent.
1792 * This gives us an upperbound on the TS echo.
1793 * tescr <= largest_tsval
1794 * - The lowerbound on the TS echo is a little more
1795 * tricky to determine. The other endpoint's echoed
1796 * values will not decrease. But there may be
1797 * network conditions that re-order packets and
1798 * cause our view of them to decrease. For now the
1799 * only lowerbound we can safely determine is that
1800 * the TS echo will never be less than the original
1801 * TS. XXX There is probably a better lowerbound.
1802 * Remove TS_MAX_CONN with better lowerbound check.
1803 * tescr >= other original TS
1805 * It is also important to note that the fastest
1806 * timestamp clock of 1ms will wrap its 32bit space in
1807 * 24 days. So we just disable TS checking after 24
1808 * days of idle time. We actually must use a 12d
1809 * connection limit until we can come up with a better
1810 * lowerbound to the TS echo check.
1812 struct timeval delta_ts
;
1817 * PFTM_TS_DIFF is how many seconds of leeway to allow
1818 * a host's timestamp. This can happen if the previous
1819 * packet got delayed in transit for much longer than
1822 if ((ts_fudge
= state
->rule
.ptr
->timeout
[PFTM_TS_DIFF
]) == 0)
1823 ts_fudge
= pf_default_rule
.timeout
[PFTM_TS_DIFF
];
1826 /* Calculate max ticks since the last timestamp */
1827 #define TS_MAXFREQ 1100 /* RFC max TS freq of 1Khz + 10% skew */
1828 #define TS_MICROSECS 1000000 /* microseconds per second */
1829 timersub(&uptime
, &src
->scrub
->pfss_last
, &delta_ts
);
1830 tsval_from_last
= (delta_ts
.tv_sec
+ ts_fudge
) * TS_MAXFREQ
;
1831 tsval_from_last
+= delta_ts
.tv_usec
/ (TS_MICROSECS
/TS_MAXFREQ
);
1834 if ((src
->state
>= TCPS_ESTABLISHED
&&
1835 dst
->state
>= TCPS_ESTABLISHED
) &&
1836 (SEQ_LT(tsval
, dst
->scrub
->pfss_tsecr
) ||
1837 SEQ_GT(tsval
, src
->scrub
->pfss_tsval
+ tsval_from_last
) ||
1838 (tsecr
&& (SEQ_GT(tsecr
, dst
->scrub
->pfss_tsval
) ||
1839 SEQ_LT(tsecr
, dst
->scrub
->pfss_tsval0
))))) {
1841 * Bad RFC1323 implementation or an insertion attack.
1843 * - Solaris 2.6 and 2.7 are known to send another ACK
1844 * after the FIN,FIN|ACK,ACK closing that carries
1848 DPFPRINTF(("Timestamp failed %c%c%c%c\n",
1849 SEQ_LT(tsval
, dst
->scrub
->pfss_tsecr
) ? '0' : ' ',
1850 SEQ_GT(tsval
, src
->scrub
->pfss_tsval
+
1851 tsval_from_last
) ? '1' : ' ',
1852 SEQ_GT(tsecr
, dst
->scrub
->pfss_tsval
) ? '2' : ' ',
1853 SEQ_LT(tsecr
, dst
->scrub
->pfss_tsval0
)? '3' : ' '));
1854 DPFPRINTF((" tsval: %u tsecr: %u +ticks: %u "
1855 "idle: %lus %ums\n",
1856 tsval
, tsecr
, tsval_from_last
, delta_ts
.tv_sec
,
1857 delta_ts
.tv_usec
/ 1000));
1858 DPFPRINTF((" src->tsval: %u tsecr: %u\n",
1859 src
->scrub
->pfss_tsval
, src
->scrub
->pfss_tsecr
));
1860 DPFPRINTF((" dst->tsval: %u tsecr: %u tsval0: %u\n",
1861 dst
->scrub
->pfss_tsval
, dst
->scrub
->pfss_tsecr
,
1862 dst
->scrub
->pfss_tsval0
));
1863 if (pf_status
.debug
>= PF_DEBUG_MISC
) {
1864 pf_print_state(state
);
1865 pf_print_flags(th
->th_flags
);
1868 REASON_SET(reason
, PFRES_TS
);
1872 /* XXX I'd really like to require tsecr but it's optional */
1874 } else if (!got_ts
&& (th
->th_flags
& TH_RST
) == 0 &&
1875 ((src
->state
== TCPS_ESTABLISHED
&& dst
->state
== TCPS_ESTABLISHED
)
1876 || pd
->p_len
> 0 || (th
->th_flags
& TH_SYN
)) &&
1877 src
->scrub
&& dst
->scrub
&&
1878 (src
->scrub
->pfss_flags
& PFSS_PAWS
) &&
1879 (dst
->scrub
->pfss_flags
& PFSS_PAWS
)) {
1881 * Didn't send a timestamp. Timestamps aren't really useful
1883 * - connection opening or closing (often not even sent).
1884 * but we must not let an attacker to put a FIN on a
1885 * data packet to sneak it through our ESTABLISHED check.
1886 * - on a TCP reset. RFC suggests not even looking at TS.
1887 * - on an empty ACK. The TS will not be echoed so it will
1888 * probably not help keep the RTT calculation in sync and
1889 * there isn't as much danger when the sequence numbers
1890 * got wrapped. So some stacks don't include TS on empty
1893 * To minimize the disruption to mostly RFC1323 conformant
1894 * stacks, we will only require timestamps on data packets.
1896 * And what do ya know, we cannot require timestamps on data
1897 * packets. There appear to be devices that do legitimate
1898 * TCP connection hijacking. There are HTTP devices that allow
1899 * a 3whs (with timestamps) and then buffer the HTTP request.
1900 * If the intermediate device has the HTTP response cache, it
1901 * will spoof the response but not bother timestamping its
1902 * packets. So we can look for the presence of a timestamp in
1903 * the first data packet and if there, require it in all future
1907 if (pd
->p_len
> 0 && (src
->scrub
->pfss_flags
& PFSS_DATA_TS
)) {
1909 * Hey! Someone tried to sneak a packet in. Or the
1910 * stack changed its RFC1323 behavior?!?!
1912 if (pf_status
.debug
>= PF_DEBUG_MISC
) {
1913 DPFPRINTF(("Did not receive expected RFC1323 "
1915 pf_print_state(state
);
1916 pf_print_flags(th
->th_flags
);
1919 REASON_SET(reason
, PFRES_TS
);
1926 * We will note if a host sends his data packets with or without
1927 * timestamps. And require all data packets to contain a timestamp
1928 * if the first does. PAWS implicitly requires that all data packets be
1929 * timestamped. But I think there are middle-man devices that hijack
1930 * TCP streams immediately after the 3whs and don't timestamp their
1931 * packets (seen in a WWW accelerator or cache).
1933 if (pd
->p_len
> 0 && src
->scrub
&& (src
->scrub
->pfss_flags
&
1934 (PFSS_TIMESTAMP
|PFSS_DATA_TS
|PFSS_DATA_NOTS
)) == PFSS_TIMESTAMP
) {
1936 src
->scrub
->pfss_flags
|= PFSS_DATA_TS
;
1938 src
->scrub
->pfss_flags
|= PFSS_DATA_NOTS
;
1939 if (pf_status
.debug
>= PF_DEBUG_MISC
&& dst
->scrub
&&
1940 (dst
->scrub
->pfss_flags
& PFSS_TIMESTAMP
)) {
1941 /* Don't warn if other host rejected RFC1323 */
1942 DPFPRINTF(("Broken RFC1323 stack did not "
1943 "timestamp data packet. Disabled PAWS "
1945 pf_print_state(state
);
1946 pf_print_flags(th
->th_flags
);
1954 * Update PAWS values
1956 if (got_ts
&& src
->scrub
&& PFSS_TIMESTAMP
== (src
->scrub
->pfss_flags
&
1957 (PFSS_PAWS_IDLED
|PFSS_TIMESTAMP
))) {
1958 getmicrouptime(&src
->scrub
->pfss_last
);
1959 if (SEQ_GEQ(tsval
, src
->scrub
->pfss_tsval
) ||
1960 (src
->scrub
->pfss_flags
& PFSS_PAWS
) == 0)
1961 src
->scrub
->pfss_tsval
= tsval
;
1964 if (SEQ_GEQ(tsecr
, src
->scrub
->pfss_tsecr
) ||
1965 (src
->scrub
->pfss_flags
& PFSS_PAWS
) == 0)
1966 src
->scrub
->pfss_tsecr
= tsecr
;
1968 if ((src
->scrub
->pfss_flags
& PFSS_PAWS
) == 0 &&
1969 (SEQ_LT(tsval
, src
->scrub
->pfss_tsval0
) ||
1970 src
->scrub
->pfss_tsval0
== 0)) {
1971 /* tsval0 MUST be the lowest timestamp */
1972 src
->scrub
->pfss_tsval0
= tsval
;
1975 /* Only fully initialized after a TS gets echoed */
1976 if ((src
->scrub
->pfss_flags
& PFSS_PAWS
) == 0)
1977 src
->scrub
->pfss_flags
|= PFSS_PAWS
;
1981 /* I have a dream.... TCP segment reassembly.... */
1985 #ifndef NO_APPLE_EXTENSIONS
1987 pf_normalize_tcpopt(struct pf_rule
*r
, int dir
, struct pfi_kif
*kif
,
1988 struct pf_pdesc
*pd
, struct mbuf
*m
, struct tcphdr
*th
, int off
,
1991 #pragma unused(dir, kif)
1992 sa_family_t af
= pd
->af
;
1995 pf_normalize_tcpopt(struct pf_rule
*r
, struct mbuf
*m
, struct tcphdr
*th
,
1996 int off
, sa_family_t af
)
2001 int opt
, cnt
, optlen
= 0;
2003 u_char opts
[MAX_TCPOPTLEN
];
2004 u_char
*optp
= opts
;
2006 thoff
= th
->th_off
<< 2;
2007 cnt
= thoff
- sizeof (struct tcphdr
);
2009 #ifndef NO_APPLE_MODIFICATIONS
2010 if (cnt
> 0 && !pf_pull_hdr(m
, off
+ sizeof (*th
), opts
, cnt
,
2014 if (cnt
> 0 && !pf_pull_hdr(m
, off
+ sizeof (*th
), opts
, cnt
,
2019 for (; cnt
> 0; cnt
-= optlen
, optp
+= optlen
) {
2021 if (opt
== TCPOPT_EOL
)
2023 if (opt
== TCPOPT_NOP
)
2029 if (optlen
< 2 || optlen
> cnt
)
2034 mss
= (u_int16_t
*)(optp
+ 2);
2035 if ((ntohs(*mss
)) > r
->max_mss
) {
2036 #ifndef NO_APPLE_MODIFICATIONS
2039 * Only do the TCP checksum fixup if delayed
2040 * checksum calculation will not be performed.
2042 if (m
->m_pkthdr
.rcvif
||
2043 !(m
->m_pkthdr
.csum_flags
& CSUM_TCP
))
2044 th
->th_sum
= pf_cksum_fixup(th
->th_sum
,
2045 *mss
, htons(r
->max_mss
), 0);
2047 th
->th_sum
= pf_cksum_fixup(th
->th_sum
,
2048 *mss
, htons(r
->max_mss
), 0);
2050 *mss
= htons(r
->max_mss
);
2059 #ifndef NO_APPLE_MODIFICATIONS
2064 mw
= pf_lazy_makewritable(pd
, pd
->mp
,
2065 off
+ sizeof (*th
) + thoff
);
2067 REASON_SET(&reason
, PFRES_MEMORY
);
2069 PFLOG_PACKET(kif
, h
, m
, AF_INET
, dir
, reason
,
2075 m_copyback(mw
, off
+ sizeof (*th
), thoff
- sizeof (*th
), opts
);
2081 m_copyback(m
, off
+ sizeof (*th
), thoff
- sizeof (*th
), opts
);