1 /* Copyright (C) 2007-2012 Open Information Security Foundation
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * \author Endace Technology Limited, Jason Ish <jason.ish@endace.com>
23 * Defragmentation module.
26 * - OpenBSD PF's IP normalizaton (pf_norm.c)
28 * \todo pool for frag packet storage
29 * \todo policy bsd-right
30 * \todo profile hash function
34 #include "suricata-common.h"
41 #include "decode-ipv6.h"
42 #include "util-hashlist.h"
43 #include "util-pool.h"
44 #include "util-time.h"
45 #include "util-print.h"
46 #include "util-debug.h"
47 #include "util-fix_checksum.h"
48 #include "util-random.h"
49 #include "stream-tcp-private.h"
50 #include "stream-tcp-reassemble.h"
51 #include "util-host-os-info.h"
54 #include "defrag-hash.h"
55 #include "defrag-queue.h"
56 #include "defrag-config.h"
58 #include "tmqh-packetpool.h"
62 #include "util-unittest.h"
65 #define DEFAULT_DEFRAG_HASH_SIZE 0xffff
66 #define DEFAULT_DEFRAG_POOL_SIZE 0xffff
69 * Default timeout (in seconds) before a defragmentation tracker will
72 #define TIMEOUT_DEFAULT 60
75 * Maximum allowed timeout, 24 hours.
77 #define TIMEOUT_MAX (60 * 60 * 24)
80 * Minimum allowed timeout, 1 second.
84 /** Fragment reassembly policies. */
85 enum defrag_policies
{
86 DEFRAG_POLICY_FIRST
= 1,
89 DEFRAG_POLICY_BSD_RIGHT
,
91 DEFRAG_POLICY_WINDOWS
,
92 DEFRAG_POLICY_SOLARIS
,
94 DEFRAG_POLICY_DEFAULT
= DEFRAG_POLICY_BSD
,
97 static int default_policy
= DEFRAG_POLICY_BSD
;
99 /** The global DefragContext so all threads operate from the same
101 static DefragContext
*defrag_context
;
103 RB_GENERATE(IP_FRAGMENTS
, Frag_
, rb
, DefragRbFragCompare
);
106 * Utility/debugging function to dump the frags associated with a
107 * tracker. Only enable when unit tests are enabled.
112 DumpFrags(DefragTracker
*tracker
)
116 printf("Dumping frags for packet: ID=%d\n", tracker
->id
);
117 TAILQ_FOREACH(frag
, &tracker
->frags
, next
) {
118 printf("-> Frag: frag_offset=%d, frag_len=%d, data_len=%d, ltrim=%d, skip=%d\n", frag
->offset
, frag
->len
, frag
->data_len
, frag
->ltrim
, frag
->skip
);
119 PrintRawDataFp(stdout
, frag
->pkt
, frag
->len
);
122 #endif /* UNITTESTS */
126 * \brief Reset a frag for reuse in a pool.
129 DefragFragReset(Frag
*frag
)
131 if (frag
->pkt
!= NULL
)
133 memset(frag
, 0, sizeof(*frag
));
137 * \brief Allocate a new frag for use in a pool.
140 DefragFragInit(void *data
, void *initdata
)
144 memset(frag
, 0, sizeof(*frag
));
149 * \brief Free all frags associated with a tracker.
152 DefragTrackerFreeFrags(DefragTracker
*tracker
)
156 /* Lock the frag pool as we'll be return items to it. */
157 SCMutexLock(&defrag_context
->frag_pool_lock
);
159 RB_FOREACH_SAFE(frag
, IP_FRAGMENTS
, &tracker
->fragment_tree
, tmp
) {
160 RB_REMOVE(IP_FRAGMENTS
, &tracker
->fragment_tree
, frag
);
161 DefragFragReset(frag
);
162 PoolReturn(defrag_context
->frag_pool
, frag
);
165 SCMutexUnlock(&defrag_context
->frag_pool_lock
);
169 * \brief Create a new DefragContext.
171 * \retval On success a return an initialized DefragContext, otherwise
172 * NULL will be returned.
174 static DefragContext
*
175 DefragContextNew(void)
179 dc
= SCCalloc(1, sizeof(*dc
));
180 if (unlikely(dc
== NULL
))
183 /* Initialize the pool of trackers. */
184 intmax_t tracker_pool_size
;
185 if (!ConfGetInt("defrag.trackers", &tracker_pool_size
) || tracker_pool_size
== 0) {
186 tracker_pool_size
= DEFAULT_DEFRAG_HASH_SIZE
;
189 /* Initialize the pool of frags. */
190 intmax_t frag_pool_size
;
191 if (!ConfGetInt("defrag.max-frags", &frag_pool_size
) || frag_pool_size
== 0) {
192 frag_pool_size
= DEFAULT_DEFRAG_POOL_SIZE
;
194 intmax_t frag_pool_prealloc
= frag_pool_size
/ 2;
195 dc
->frag_pool
= PoolInit(frag_pool_size
, frag_pool_prealloc
,
197 NULL
, DefragFragInit
, dc
, NULL
, NULL
);
198 if (dc
->frag_pool
== NULL
) {
199 FatalError(SC_ERR_FATAL
,
200 "Defrag: Failed to initialize fragment pool.");
202 if (SCMutexInit(&dc
->frag_pool_lock
, NULL
) != 0) {
203 FatalError(SC_ERR_FATAL
,
204 "Defrag: Failed to initialize frag pool mutex.");
207 /* Set the default timeout. */
209 if (!ConfGetInt("defrag.timeout", &timeout
)) {
210 dc
->timeout
= TIMEOUT_DEFAULT
;
213 if (timeout
< TIMEOUT_MIN
) {
214 FatalError(SC_ERR_FATAL
,
215 "defrag: Timeout less than minimum allowed value.");
217 else if (timeout
> TIMEOUT_MAX
) {
218 FatalError(SC_ERR_FATAL
,
219 "defrag: Tiemout greater than maximum allowed value.");
221 dc
->timeout
= timeout
;
224 SCLogDebug("Defrag Initialized:");
225 SCLogDebug("\tTimeout: %"PRIuMAX
, (uintmax_t)dc
->timeout
);
226 SCLogDebug("\tMaximum defrag trackers: %"PRIuMAX
, tracker_pool_size
);
227 SCLogDebug("\tPreallocated defrag trackers: %"PRIuMAX
, tracker_pool_size
);
228 SCLogDebug("\tMaximum fragments: %"PRIuMAX
, (uintmax_t)frag_pool_size
);
229 SCLogDebug("\tPreallocated fragments: %"PRIuMAX
, (uintmax_t)frag_pool_prealloc
);
235 DefragContextDestroy(DefragContext
*dc
)
240 PoolFree(dc
->frag_pool
);
245 * Attempt to re-assemble a packet.
247 * \param tracker The defragmentation tracker to reassemble from.
250 Defrag4Reassemble(ThreadVars
*tv
, DefragTracker
*tracker
, Packet
*p
)
254 /* Should not be here unless we have seen the last fragment. */
255 if (!tracker
->seen_last
) {
259 /* Check that we have the first fragment and its of a valid size. */
260 Frag
*first
= RB_MIN(IP_FRAGMENTS
, &tracker
->fragment_tree
);
263 } else if (first
->offset
!= 0) {
264 /* Still waiting for the first fragment. */
266 } else if (first
->len
< sizeof(IPV4Hdr
)) {
267 /* First fragment isn't enough for an IPv6 header. */
268 goto error_remove_tracker
;
271 /* Check that we have all the data. Relies on the fact that
272 * fragments are inserted if frag_offset order. */
275 RB_FOREACH_FROM(frag
, IP_FRAGMENTS
, first
) {
276 if (frag
->offset
> len
) {
277 /* This fragment starts after the end of the previous
278 * fragment. We have a hole. */
282 len
+= frag
->data_len
;
286 /* Allocate a Packet for the reassembled packet. On failure we
287 * SCFree all the resources held by this tracker. */
288 rp
= PacketDefragPktSetup(p
, NULL
, 0, IPV4_GET_IPPROTO(p
));
290 SCLogError(SC_ERR_MEM_ALLOC
, "Failed to allocate packet for "
291 "fragmentation re-assembly, dumping fragments.");
292 goto error_remove_tracker
;
294 PKT_SET_SRC(rp
, PKT_SRC_DEFRAG
);
295 rp
->flags
|= PKT_REBUILT_FRAGMENT
;
296 rp
->recursion_level
= p
->recursion_level
;
298 int fragmentable_offset
= 0;
299 int fragmentable_len
= 0;
301 int ip_hdr_offset
= 0;
303 RB_FOREACH(frag
, IP_FRAGMENTS
, &tracker
->fragment_tree
) {
304 SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64
,
305 frag
, frag
->data_len
, frag
->offset
, frag
->pcap_cnt
);
309 if (frag
->ltrim
>= frag
->data_len
)
311 if (frag
->offset
== 0) {
313 if (PacketCopyData(rp
, frag
->pkt
, frag
->len
) == -1)
314 goto error_remove_tracker
;
317 ip_hdr_offset
= frag
->ip_hdr_offset
;
319 /* This is the start of the fragmentable portion of the
320 * first packet. All fragment offsets are relative to
322 fragmentable_offset
= frag
->ip_hdr_offset
+ frag
->hlen
;
323 fragmentable_len
= frag
->data_len
;
326 int pkt_end
= fragmentable_offset
+ frag
->offset
+ frag
->data_len
;
327 if (pkt_end
> (int)MAX_PAYLOAD_SIZE
) {
328 SCLogWarning(SC_ERR_REASSEMBLY
, "Failed re-assemble "
329 "fragmented packet, exceeds size of packet buffer.");
330 goto error_remove_tracker
;
332 if (PacketCopyDataOffset(rp
,
333 fragmentable_offset
+ frag
->offset
+ frag
->ltrim
,
334 frag
->pkt
+ frag
->data_offset
+ frag
->ltrim
,
335 frag
->data_len
- frag
->ltrim
) == -1) {
336 goto error_remove_tracker
;
338 if (frag
->offset
+ frag
->data_len
> fragmentable_len
)
339 fragmentable_len
= frag
->offset
+ frag
->data_len
;
342 if (!frag
->more_frags
) {
347 SCLogDebug("ip_hdr_offset %u, hlen %u, fragmentable_len %u",
348 ip_hdr_offset
, hlen
, fragmentable_len
);
350 rp
->ip4h
= (IPV4Hdr
*)(GET_PKT_DATA(rp
) + ip_hdr_offset
);
351 int old
= rp
->ip4h
->ip_len
+ rp
->ip4h
->ip_off
;
352 rp
->ip4h
->ip_len
= htons(fragmentable_len
+ hlen
);
353 rp
->ip4h
->ip_off
= 0;
354 rp
->ip4h
->ip_csum
= FixChecksum(rp
->ip4h
->ip_csum
,
355 old
, rp
->ip4h
->ip_len
+ rp
->ip4h
->ip_off
);
356 SET_PKT_LEN(rp
, ip_hdr_offset
+ hlen
+ fragmentable_len
);
359 DefragTrackerFreeFrags(tracker
);
363 error_remove_tracker
:
365 DefragTrackerFreeFrags(tracker
);
367 PacketFreeOrRelease(rp
);
372 * Attempt to re-assemble a packet.
374 * \param tracker The defragmentation tracker to reassemble from.
377 Defrag6Reassemble(ThreadVars
*tv
, DefragTracker
*tracker
, Packet
*p
)
381 /* Should not be here unless we have seen the last fragment. */
382 if (!tracker
->seen_last
)
385 /* Check that we have the first fragment and its of a valid size. */
386 Frag
*first
= RB_MIN(IP_FRAGMENTS
, &tracker
->fragment_tree
);
389 } else if (first
->offset
!= 0) {
390 /* Still waiting for the first fragment. */
392 } else if (first
->len
< sizeof(IPV6Hdr
)) {
393 /* First fragment isn't enough for an IPv6 header. */
394 goto error_remove_tracker
;
397 /* Check that we have all the data. Relies on the fact that
398 * fragments are inserted if frag_offset order. */
401 RB_FOREACH_FROM(frag
, IP_FRAGMENTS
, first
) {
407 if (frag
->offset
!= 0) {
410 len
= frag
->data_len
;
413 if (frag
->offset
> len
) {
414 /* This fragment starts after the end of the previous
415 * fragment. We have a hole. */
419 len
+= frag
->data_len
;
424 /* Allocate a Packet for the reassembled packet. On failure we
425 * SCFree all the resources held by this tracker. */
426 rp
= PacketDefragPktSetup(p
, (uint8_t *)p
->ip6h
,
427 IPV6_GET_PLEN(p
) + sizeof(IPV6Hdr
), 0);
429 SCLogError(SC_ERR_MEM_ALLOC
, "Failed to allocate packet for "
430 "fragmentation re-assembly, dumping fragments.");
431 goto error_remove_tracker
;
433 PKT_SET_SRC(rp
, PKT_SRC_DEFRAG
);
435 int unfragmentable_len
= 0;
436 int fragmentable_offset
= 0;
437 int fragmentable_len
= 0;
438 int ip_hdr_offset
= 0;
439 uint8_t next_hdr
= 0;
440 RB_FOREACH(frag
, IP_FRAGMENTS
, &tracker
->fragment_tree
) {
443 if (frag
->data_len
- frag
->ltrim
<= 0)
445 if (frag
->offset
== 0) {
446 IPV6FragHdr
*frag_hdr
= (IPV6FragHdr
*)(frag
->pkt
+
447 frag
->frag_hdr_offset
);
448 next_hdr
= frag_hdr
->ip6fh_nxt
;
450 /* This is the first packet, we use this packets link and
451 * IPv6 headers. We also copy in its data, but remove the
452 * fragmentation header. */
453 if (PacketCopyData(rp
, frag
->pkt
, frag
->frag_hdr_offset
) == -1)
454 goto error_remove_tracker
;
455 if (PacketCopyDataOffset(rp
, frag
->frag_hdr_offset
,
456 frag
->pkt
+ frag
->frag_hdr_offset
+ sizeof(IPV6FragHdr
),
457 frag
->data_len
) == -1)
458 goto error_remove_tracker
;
459 ip_hdr_offset
= frag
->ip_hdr_offset
;
461 /* This is the start of the fragmentable portion of the
462 * first packet. All fragment offsets are relative to
464 fragmentable_offset
= frag
->frag_hdr_offset
;
465 fragmentable_len
= frag
->data_len
;
467 /* unfragmentable part is the part between the ipv6 header
468 * and the frag header. */
469 unfragmentable_len
= (fragmentable_offset
- ip_hdr_offset
) - IPV6_HEADER_LEN
;
470 if (unfragmentable_len
>= fragmentable_offset
)
471 goto error_remove_tracker
;
474 if (PacketCopyDataOffset(rp
, fragmentable_offset
+ frag
->offset
+ frag
->ltrim
,
475 frag
->pkt
+ frag
->data_offset
+ frag
->ltrim
,
476 frag
->data_len
- frag
->ltrim
) == -1)
477 goto error_remove_tracker
;
478 if (frag
->offset
+ frag
->data_len
> fragmentable_len
)
479 fragmentable_len
= frag
->offset
+ frag
->data_len
;
482 if (!frag
->more_frags
) {
487 rp
->ip6h
= (IPV6Hdr
*)(GET_PKT_DATA(rp
) + ip_hdr_offset
);
488 rp
->ip6h
->s_ip6_plen
= htons(fragmentable_len
+ unfragmentable_len
);
489 /* if we have no unfragmentable part, so no ext hdrs before the frag
490 * header, we need to update the ipv6 headers next header field. This
491 * points to the frag header, and we will make it point to the layer
492 * directly after the frag header. */
493 if (unfragmentable_len
== 0)
494 rp
->ip6h
->s_ip6_nxt
= next_hdr
;
495 SET_PKT_LEN(rp
, ip_hdr_offset
+ sizeof(IPV6Hdr
) +
496 unfragmentable_len
+ fragmentable_len
);
499 DefragTrackerFreeFrags(tracker
);
503 error_remove_tracker
:
505 DefragTrackerFreeFrags(tracker
);
507 PacketFreeOrRelease(rp
);
512 * The RB_TREE compare function for fragments.
514 * When it comes to adding fragments, we want subsequent ones with the
515 * same offset to be treated as greater than, so we don't have an
516 * equal return value here.
518 int DefragRbFragCompare(struct Frag_
*a
, struct Frag_
*b
) {
519 if (a
->offset
< b
->offset
) {
526 * Insert a new IPv4/IPv6 fragment into a tracker.
528 * \todo Allocate packet buffers from a pool.
531 DefragInsertFrag(ThreadVars
*tv
, DecodeThreadVars
*dtv
, DefragTracker
*tracker
, Packet
*p
)
537 uint16_t frag_offset
;
539 /* IPv4 header length - IPv4 only. */
542 /* This is the offset of the start of the data in the packet that
543 * falls after the IP header. */
544 uint16_t data_offset
;
546 /* The length of the (fragmented) data. This is the length of the
547 * data that falls after the IP header. */
550 /* Where the fragment ends. */
553 /* Offset in the packet to the IPv6 header. */
554 uint16_t ip_hdr_offset
;
556 /* Offset in the packet to the IPv6 frag header. IPv6 only. */
557 uint16_t frag_hdr_offset
= 0;
560 int af
= tracker
->af
;
562 /* settings for updating a payload when an ip6 fragment with
563 * unfragmentable exthdrs are encountered. */
564 int ip6_nh_set_offset
= 0;
565 uint8_t ip6_nh_set_value
= 0;
568 uint64_t pcap_cnt
= p
->pcap_cnt
;
571 if (tracker
->af
== AF_INET
) {
572 more_frags
= IPV4_GET_MF(p
);
573 frag_offset
= IPV4_GET_IPOFFSET(p
) << 3;
574 hlen
= IPV4_GET_HLEN(p
);
575 data_offset
= (uint8_t *)p
->ip4h
+ hlen
- GET_PKT_DATA(p
);
576 data_len
= IPV4_GET_IPLEN(p
) - hlen
;
577 frag_end
= frag_offset
+ data_len
;
578 ip_hdr_offset
= (uint8_t *)p
->ip4h
- GET_PKT_DATA(p
);
580 /* Ignore fragment if the end of packet extends past the
581 * maximum size of a packet. */
582 if (IPV4_HEADER_LEN
+ frag_offset
+ data_len
> IPV4_MAXPACKET_LEN
) {
583 ENGINE_SET_EVENT(p
, IPV4_FRAG_PKT_TOO_LARGE
);
587 else if (tracker
->af
== AF_INET6
) {
588 more_frags
= IPV6_EXTHDR_GET_FH_FLAG(p
);
589 frag_offset
= IPV6_EXTHDR_GET_FH_OFFSET(p
);
590 data_offset
= p
->ip6eh
.fh_data_offset
;
591 data_len
= p
->ip6eh
.fh_data_len
;
592 frag_end
= frag_offset
+ data_len
;
593 ip_hdr_offset
= (uint8_t *)p
->ip6h
- GET_PKT_DATA(p
);
594 frag_hdr_offset
= p
->ip6eh
.fh_header_offset
;
596 SCLogDebug("mf %s frag_offset %u data_offset %u, data_len %u, "
597 "frag_end %u, ip_hdr_offset %u, frag_hdr_offset %u",
598 more_frags
? "true" : "false", frag_offset
, data_offset
,
599 data_len
, frag_end
, ip_hdr_offset
, frag_hdr_offset
);
601 /* handle unfragmentable exthdrs */
602 if (ip_hdr_offset
+ IPV6_HEADER_LEN
< frag_hdr_offset
) {
603 SCLogDebug("we have exthdrs before fraghdr %u bytes",
604 (uint32_t)(frag_hdr_offset
- (ip_hdr_offset
+ IPV6_HEADER_LEN
)));
606 /* get the offset of the 'next' field in exthdr before the FH,
607 * relative to the buffer start */
609 /* store offset and FH 'next' value for updating frag buffer below */
610 ip6_nh_set_offset
= p
->ip6eh
.fh_prev_hdr_offset
;
611 ip6_nh_set_value
= IPV6_EXTHDR_GET_FH_NH(p
);
612 SCLogDebug("offset %d, value %u", ip6_nh_set_offset
, ip6_nh_set_value
);
615 /* Ignore fragment if the end of packet extends past the
616 * maximum size of a packet. */
617 if (frag_offset
+ data_len
> IPV6_MAXPACKET
) {
618 ENGINE_SET_EVENT(p
, IPV6_FRAG_PKT_TOO_LARGE
);
623 /* Abort - should not happen. */
624 SCLogWarning(SC_ERR_INVALID_ARGUMENT
, "Invalid address family, aborting.");
628 /* Update timeout. */
629 tracker
->timeout
.tv_sec
= p
->ts
.tv_sec
+ tracker
->host_timeout
;
630 tracker
->timeout
.tv_usec
= p
->ts
.tv_usec
;
632 Frag
*prev
= NULL
, *next
= NULL
;
633 bool overlap
= false;
636 if (!RB_EMPTY(&tracker
->fragment_tree
)) {
638 .offset
= frag_offset
- 1,
640 next
= RB_NFIND(IP_FRAGMENTS
, &tracker
->fragment_tree
, &key
);
642 prev
= RB_MIN(IP_FRAGMENTS
, &tracker
->fragment_tree
);
643 next
= IP_FRAGMENTS_RB_NEXT(prev
);
645 prev
= IP_FRAGMENTS_RB_PREV(next
);
648 next
= IP_FRAGMENTS_RB_NEXT(prev
);
651 while (prev
!= NULL
) {
655 if (frag_offset
< prev
->offset
+ prev
->data_len
&& prev
->offset
< frag_end
) {
659 switch (tracker
->policy
) {
660 case DEFRAG_POLICY_BSD
:
661 if (frag_offset
< prev
->offset
+ prev
->data_len
) {
662 if (frag_offset
>= prev
->offset
) {
663 ltrim
= prev
->offset
+ prev
->data_len
- frag_offset
;
665 if ((next
!= NULL
) && (frag_end
> next
->offset
)) {
666 next
->ltrim
= frag_end
- next
->offset
;
668 if ((frag_offset
< prev
->offset
) &&
669 (frag_end
>= prev
->offset
+ prev
->data_len
)) {
675 case DEFRAG_POLICY_LINUX
:
676 /* Check if new fragment overlaps the end of previous
677 * fragment, if it does, trim the new fragment.
679 * Old: AAAAAAAA AAAAAAAA AAAAAAAA
680 * New: BBBBBBBB BBBBBBBB BBBBBBBB
681 * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
683 if (prev
->offset
+ prev
->ltrim
< frag_offset
+ ltrim
&&
684 prev
->offset
+ prev
->data_len
> frag_offset
+ ltrim
) {
685 ltrim
+= prev
->offset
+ prev
->data_len
- frag_offset
;
688 /* Check if new fragment overlaps the beginning of
689 * previous fragment, if it does, tim the previous
692 * Old: AAAAAAAA AAAAAAAA
693 * New: BBBBBBBB BBBBBBBB BBBBBBBB
694 * Res: BBBBBBBB BBBBBBBB BBBBBBBB
696 if (frag_offset
+ ltrim
< prev
->offset
+ prev
->ltrim
&&
697 frag_end
> prev
->offset
+ prev
->ltrim
) {
698 prev
->ltrim
+= frag_end
- (prev
->offset
+ prev
->ltrim
);
702 /* If the new fragment completely overlaps the
703 * previous fragment, mark the previous to be
704 * skipped. Re-assembly would succeed without doing
705 * this, but this will prevent the bytes from being
706 * copied just to be overwritten. */
707 if (frag_offset
+ ltrim
<= prev
->offset
+ prev
->ltrim
&&
708 frag_end
>= prev
->offset
+ prev
->data_len
) {
714 case DEFRAG_POLICY_WINDOWS
:
715 /* If new fragment fits inside a previous fragment, drop it. */
716 if (frag_offset
+ ltrim
>= prev
->offset
+ ltrim
&&
717 frag_end
<= prev
->offset
+ prev
->data_len
) {
721 /* If new fragment starts before and ends after
722 * previous fragment, drop the previous fragment. */
723 if (frag_offset
+ ltrim
< prev
->offset
+ ltrim
&&
724 frag_end
> prev
->offset
+ prev
->data_len
) {
729 /* Check if new fragment overlaps the end of previous
730 * fragment, if it does, trim the new fragment.
732 * Old: AAAAAAAA AAAAAAAA AAAAAAAA
733 * New: BBBBBBBB BBBBBBBB BBBBBBBB
734 * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
736 if (frag_offset
+ ltrim
> prev
->offset
+ prev
->ltrim
&&
737 frag_offset
+ ltrim
< prev
->offset
+ prev
->data_len
) {
738 ltrim
+= prev
->offset
+ prev
->data_len
- frag_offset
;
742 /* If new fragment starts at same offset as an
743 * existing fragment, but ends after it, trim the new
745 if (frag_offset
+ ltrim
== prev
->offset
+ ltrim
&&
746 frag_end
> prev
->offset
+ prev
->data_len
) {
747 ltrim
+= prev
->offset
+ prev
->data_len
- frag_offset
;
751 case DEFRAG_POLICY_SOLARIS
:
752 if (frag_offset
< prev
->offset
+ prev
->data_len
) {
753 if (frag_offset
>= prev
->offset
) {
754 ltrim
= prev
->offset
+ prev
->data_len
- frag_offset
;
756 if ((frag_offset
< prev
->offset
) &&
757 (frag_end
>= prev
->offset
+ prev
->data_len
)) {
763 case DEFRAG_POLICY_FIRST
:
764 if ((frag_offset
>= prev
->offset
) &&
765 (frag_end
<= prev
->offset
+ prev
->data_len
)) {
768 if (frag_offset
< prev
->offset
) {
771 if (frag_offset
< prev
->offset
+ prev
->data_len
) {
772 ltrim
= prev
->offset
+ prev
->data_len
- frag_offset
;
776 case DEFRAG_POLICY_LAST
:
777 if (frag_offset
<= prev
->offset
) {
778 if (frag_end
> prev
->offset
) {
779 prev
->ltrim
= frag_end
- prev
->offset
;
791 next
= IP_FRAGMENTS_RB_NEXT(next
);
796 /* If existing fragment has been trimmed up completely
797 * (complete overlap), remove it now instead of holding
799 if (prev
->skip
|| prev
->ltrim
>= prev
->data_len
) {
800 RB_REMOVE(IP_FRAGMENTS
, &tracker
->fragment_tree
, prev
);
801 DefragFragReset(prev
);
802 SCMutexLock(&defrag_context
->frag_pool_lock
);
803 PoolReturn(defrag_context
->frag_pool
, prev
);
804 SCMutexUnlock(&defrag_context
->frag_pool_lock
);
810 if (ltrim
> data_len
) {
811 /* Full packet has been trimmed due to the overlap policy. Overlap
816 /* Allocate fragment and insert. */
817 SCMutexLock(&defrag_context
->frag_pool_lock
);
818 Frag
*new = PoolGet(defrag_context
->frag_pool
);
819 SCMutexUnlock(&defrag_context
->frag_pool_lock
);
822 ENGINE_SET_EVENT(p
, IPV4_FRAG_IGNORED
);
824 ENGINE_SET_EVENT(p
, IPV6_FRAG_IGNORED
);
828 new->pkt
= SCMalloc(GET_PKT_LEN(p
));
829 if (new->pkt
== NULL
) {
830 SCMutexLock(&defrag_context
->frag_pool_lock
);
831 PoolReturn(defrag_context
->frag_pool
, new);
832 SCMutexUnlock(&defrag_context
->frag_pool_lock
);
834 ENGINE_SET_EVENT(p
, IPV4_FRAG_IGNORED
);
836 ENGINE_SET_EVENT(p
, IPV6_FRAG_IGNORED
);
840 memcpy(new->pkt
, GET_PKT_DATA(p
) + ltrim
, GET_PKT_LEN(p
) - ltrim
);
841 new->len
= GET_PKT_LEN(p
) - ltrim
;
842 /* in case of unfragmentable exthdrs, update the 'next hdr' field
843 * in the raw buffer so the reassembled packet will point to the
844 * correct next header after stripping the frag header */
845 if (ip6_nh_set_offset
> 0 && frag_offset
== 0 && ltrim
== 0) {
846 if (new->len
> ip6_nh_set_offset
) {
847 SCLogDebug("updating frag to have 'correct' nh value: %u -> %u",
848 new->pkt
[ip6_nh_set_offset
], ip6_nh_set_value
);
849 new->pkt
[ip6_nh_set_offset
] = ip6_nh_set_value
;
854 new->offset
= frag_offset
+ ltrim
;
855 new->data_offset
= data_offset
;
856 new->data_len
= data_len
- ltrim
;
857 new->ip_hdr_offset
= ip_hdr_offset
;
858 new->frag_hdr_offset
= frag_hdr_offset
;
859 new->more_frags
= more_frags
;
861 new->pcap_cnt
= pcap_cnt
;
864 IP_FRAGMENTS_RB_INSERT(&tracker
->fragment_tree
, new);
867 tracker
->seen_last
= 1;
870 if (tracker
->seen_last
) {
871 if (tracker
->af
== AF_INET
) {
872 r
= Defrag4Reassemble(tv
, tracker
, p
);
873 if (r
!= NULL
&& tv
!= NULL
&& dtv
!= NULL
) {
874 StatsIncr(tv
, dtv
->counter_defrag_ipv4_reassembled
);
875 if (DecodeIPV4(tv
, dtv
, r
, (void *)r
->ip4h
,
876 IPV4_GET_IPLEN(r
)) != TM_ECODE_OK
) {
880 TmqhOutputPacketpool(tv
, r
);
883 PacketDefragPktSetupParent(p
);
887 else if (tracker
->af
== AF_INET6
) {
888 r
= Defrag6Reassemble(tv
, tracker
, p
);
889 if (r
!= NULL
&& tv
!= NULL
&& dtv
!= NULL
) {
890 StatsIncr(tv
, dtv
->counter_defrag_ipv6_reassembled
);
891 if (DecodeIPV6(tv
, dtv
, r
, (uint8_t *)r
->ip6h
,
892 IPV6_GET_PLEN(r
) + IPV6_HEADER_LEN
)
897 TmqhOutputPacketpool(tv
, r
);
900 PacketDefragPktSetupParent(p
);
910 ENGINE_SET_EVENT(p
, IPV4_FRAG_OVERLAP
);
913 ENGINE_SET_EVENT(p
, IPV6_FRAG_OVERLAP
);
920 * \brief Get the defrag policy based on the destination address of
923 * \param p The packet used to get the destination address.
925 * \retval The defrag policy to use.
928 DefragGetOsPolicy(Packet
*p
)
932 if (PKT_IS_IPV4(p
)) {
933 policy
= SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p
));
935 else if (PKT_IS_IPV6(p
)) {
936 policy
= SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p
));
940 return default_policy
;
943 /* Map the OS policies returned from the configured host info to
944 * defrag specific policies. */
948 case OS_POLICY_HPUX10
:
950 return DEFRAG_POLICY_BSD
;
953 case OS_POLICY_BSD_RIGHT
:
954 return DEFRAG_POLICY_BSD_RIGHT
;
957 case OS_POLICY_OLD_LINUX
:
958 case OS_POLICY_LINUX
:
959 return DEFRAG_POLICY_LINUX
;
962 case OS_POLICY_OLD_SOLARIS
:
963 case OS_POLICY_HPUX11
:
964 case OS_POLICY_MACOS
:
965 case OS_POLICY_FIRST
:
966 return DEFRAG_POLICY_FIRST
;
969 case OS_POLICY_SOLARIS
:
970 return DEFRAG_POLICY_SOLARIS
;
973 case OS_POLICY_WINDOWS
:
974 case OS_POLICY_VISTA
:
975 case OS_POLICY_WINDOWS2K3
:
976 return DEFRAG_POLICY_WINDOWS
;
980 return DEFRAG_POLICY_LAST
;
983 return default_policy
;
989 * \retval NULL or a *LOCKED* tracker */
990 static DefragTracker
*
991 DefragGetTracker(ThreadVars
*tv
, DecodeThreadVars
*dtv
, Packet
*p
)
993 return DefragGetTrackerFromHash(p
);
997 * \brief Entry point for IPv4 and IPv6 fragments.
999 * \param tv ThreadVars for the calling decoder.
1000 * \param p The packet fragment.
1002 * \retval A new Packet resembling the re-assembled packet if the most
1003 * recent fragment allowed the packet to be re-assembled, otherwise
1007 Defrag(ThreadVars
*tv
, DecodeThreadVars
*dtv
, Packet
*p
)
1009 uint16_t frag_offset
;
1011 DefragTracker
*tracker
;
1014 if (PKT_IS_IPV4(p
)) {
1016 more_frags
= IPV4_GET_MF(p
);
1017 frag_offset
= IPV4_GET_IPOFFSET(p
);
1019 else if (PKT_IS_IPV6(p
)) {
1021 frag_offset
= IPV6_EXTHDR_GET_FH_OFFSET(p
);
1022 more_frags
= IPV6_EXTHDR_GET_FH_FLAG(p
);
1028 if (frag_offset
== 0 && more_frags
== 0) {
1032 if (tv
!= NULL
&& dtv
!= NULL
) {
1033 if (af
== AF_INET
) {
1034 StatsIncr(tv
, dtv
->counter_defrag_ipv4_fragments
);
1036 else if (af
== AF_INET6
) {
1037 StatsIncr(tv
, dtv
->counter_defrag_ipv6_fragments
);
1041 /* return a locked tracker or NULL */
1042 tracker
= DefragGetTracker(tv
, dtv
, p
);
1043 if (tracker
== NULL
)
1046 Packet
*rp
= DefragInsertFrag(tv
, dtv
, tracker
, p
);
1047 DefragTrackerRelease(tracker
);
1055 intmax_t tracker_pool_size
;
1056 if (!ConfGetInt("defrag.trackers", &tracker_pool_size
)) {
1057 tracker_pool_size
= DEFAULT_DEFRAG_HASH_SIZE
;
1060 /* Load the defrag-per-host lookup. */
1061 DefragPolicyLoadFromConfig();
1063 /* Allocate the DefragContext. */
1064 defrag_context
= DefragContextNew();
1065 if (defrag_context
== NULL
) {
1066 FatalError(SC_ERR_FATAL
,
1067 "Failed to allocate memory for the Defrag module.");
1070 DefragSetDefaultTimeout(defrag_context
->timeout
);
1071 DefragInitConfig(false);
1074 void DefragDestroy(void)
1076 DefragHashShutdown();
1077 DefragContextDestroy(defrag_context
);
1078 defrag_context
= NULL
;
1079 DefragTreeDestroy();
1083 #define IP_MF 0x2000
1086 * Allocate a test packet. Nothing to fancy, just a simple IP packet
1087 * with some payload of no particular protocol.
1089 static Packet
*BuildTestPacket(uint8_t proto
, uint16_t id
, uint16_t off
, int mf
,
1090 const char content
, int content_len
)
1098 p
= SCCalloc(1, sizeof(*p
) + default_packet_size
);
1099 if (unlikely(p
== NULL
))
1102 PACKET_INITIALIZE(p
);
1104 gettimeofday(&p
->ts
, NULL
);
1105 //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1106 ip4h
.ip_verhl
= 4 << 4;
1107 ip4h
.ip_verhl
|= hlen
>> 2;
1108 ip4h
.ip_len
= htons(hlen
+ content_len
);
1109 ip4h
.ip_id
= htons(id
);
1111 ip4h
.ip_off
= htons(IP_MF
| off
);
1113 ip4h
.ip_off
= htons(off
);
1115 ip4h
.ip_proto
= proto
;
1117 ip4h
.s_ip_src
.s_addr
= 0x01010101; /* 1.1.1.1 */
1118 ip4h
.s_ip_dst
.s_addr
= 0x02020202; /* 2.2.2.2 */
1120 /* copy content_len crap, we need full length */
1121 PacketCopyData(p
, (uint8_t *)&ip4h
, sizeof(ip4h
));
1122 p
->ip4h
= (IPV4Hdr
*)GET_PKT_DATA(p
);
1123 SET_IPV4_SRC_ADDR(p
, &p
->src
);
1124 SET_IPV4_DST_ADDR(p
, &p
->dst
);
1126 pcontent
= SCCalloc(1, content_len
);
1127 if (unlikely(pcontent
== NULL
))
1129 memset(pcontent
, content
, content_len
);
1130 PacketCopyDataOffset(p
, hlen
, pcontent
, content_len
);
1131 SET_PKT_LEN(p
, hlen
+ content_len
);
1134 p
->ip4h
->ip_csum
= IPV4Checksum((uint16_t *)GET_PKT_DATA(p
), hlen
, 0);
1137 if (IPV4_GET_VER(p
) != 4)
1139 if (IPV4_GET_HLEN(p
) != hlen
)
1141 if (IPV4_GET_IPLEN(p
) != hlen
+ content_len
)
1143 if (IPV4_GET_IPID(p
) != id
)
1145 if (IPV4_GET_IPOFFSET(p
) != off
)
1147 if (IPV4_GET_MF(p
) != mf
)
1149 if (IPV4_GET_IPTTL(p
) != ttl
)
1151 if (IPV4_GET_IPPROTO(p
) != proto
)
1161 static Packet
*IPV6BuildTestPacket(uint8_t proto
, uint32_t id
, uint16_t off
,
1162 int mf
, const char content
, int content_len
)
1168 p
= SCCalloc(1, sizeof(*p
) + default_packet_size
);
1169 if (unlikely(p
== NULL
))
1172 PACKET_INITIALIZE(p
);
1174 gettimeofday(&p
->ts
, NULL
);
1176 ip6h
.s_ip6_nxt
= 44;
1177 ip6h
.s_ip6_hlim
= 2;
1179 /* Source and dest address - very bogus addresses. */
1180 ip6h
.s_ip6_src
[0] = 0x01010101;
1181 ip6h
.s_ip6_src
[1] = 0x01010101;
1182 ip6h
.s_ip6_src
[2] = 0x01010101;
1183 ip6h
.s_ip6_src
[3] = 0x01010101;
1184 ip6h
.s_ip6_dst
[0] = 0x02020202;
1185 ip6h
.s_ip6_dst
[1] = 0x02020202;
1186 ip6h
.s_ip6_dst
[2] = 0x02020202;
1187 ip6h
.s_ip6_dst
[3] = 0x02020202;
1189 /* copy content_len crap, we need full length */
1190 PacketCopyData(p
, (uint8_t *)&ip6h
, sizeof(IPV6Hdr
));
1192 p
->ip6h
= (IPV6Hdr
*)GET_PKT_DATA(p
);
1193 IPV6_SET_RAW_VER(p
->ip6h
, 6);
1194 /* Fragmentation header. */
1195 IPV6FragHdr
*fh
= (IPV6FragHdr
*)(GET_PKT_DATA(p
) + sizeof(IPV6Hdr
));
1196 fh
->ip6fh_nxt
= proto
;
1197 fh
->ip6fh_ident
= htonl(id
);
1198 fh
->ip6fh_offlg
= htons((off
<< 3) | mf
);
1200 DecodeIPV6FragHeader(p
, (uint8_t *)fh
, 8, 8 + content_len
, 0);
1202 pcontent
= SCCalloc(1, content_len
);
1203 if (unlikely(pcontent
== NULL
))
1205 memset(pcontent
, content
, content_len
);
1206 PacketCopyDataOffset(p
, sizeof(IPV6Hdr
) + sizeof(IPV6FragHdr
), pcontent
, content_len
);
1207 SET_PKT_LEN(p
, sizeof(IPV6Hdr
) + sizeof(IPV6FragHdr
) + content_len
);
1210 p
->ip6h
->s_ip6_plen
= htons(sizeof(IPV6FragHdr
) + content_len
);
1212 SET_IPV6_SRC_ADDR(p
, &p
->src
);
1213 SET_IPV6_DST_ADDR(p
, &p
->dst
);
1216 if (IPV6_GET_VER(p
) != 6)
1218 if (IPV6_GET_NH(p
) != 44)
1220 if (IPV6_GET_PLEN(p
) != sizeof(IPV6FragHdr
) + content_len
)
1231 * Test the simplest possible re-assembly scenario. All packet in
1232 * order and no overlaps.
1234 static int DefragInOrderSimpleTest(void)
1236 Packet
*p1
= NULL
, *p2
= NULL
, *p3
= NULL
;
1237 Packet
*reassembled
= NULL
;
1243 p1
= BuildTestPacket(IPPROTO_ICMP
, id
, 0, 1, 'A', 8);
1245 p2
= BuildTestPacket(IPPROTO_ICMP
, id
, 1, 1, 'B', 8);
1247 p3
= BuildTestPacket(IPPROTO_ICMP
, id
, 2, 0, 'C', 3);
1250 FAIL_IF(Defrag(NULL
, NULL
, p1
) != NULL
);
1251 FAIL_IF(Defrag(NULL
, NULL
, p2
) != NULL
);
1253 reassembled
= Defrag(NULL
, NULL
, p3
);
1254 FAIL_IF_NULL(reassembled
);
1256 FAIL_IF(IPV4_GET_HLEN(reassembled
) != 20);
1257 FAIL_IF(IPV4_GET_IPLEN(reassembled
) != 39);
1259 /* 20 bytes in we should find 8 bytes of A. */
1260 for (i
= 20; i
< 20 + 8; i
++) {
1261 FAIL_IF(GET_PKT_DATA(reassembled
)[i
] != 'A');
1264 /* 28 bytes in we should find 8 bytes of B. */
1265 for (i
= 28; i
< 28 + 8; i
++) {
1266 FAIL_IF(GET_PKT_DATA(reassembled
)[i
] != 'B');
1269 /* And 36 bytes in we should find 3 bytes of C. */
1270 for (i
= 36; i
< 36 + 3; i
++) {
1271 FAIL_IF(GET_PKT_DATA(reassembled
)[i
] != 'C');
1277 SCFree(reassembled
);
1284 * Simple fragmented packet in reverse order.
1286 static int DefragReverseSimpleTest(void)
1288 Packet
*p1
= NULL
, *p2
= NULL
, *p3
= NULL
;
1289 Packet
*reassembled
= NULL
;
1295 p1
= BuildTestPacket(IPPROTO_ICMP
, id
, 0, 1, 'A', 8);
1297 p2
= BuildTestPacket(IPPROTO_ICMP
, id
, 1, 1, 'B', 8);
1299 p3
= BuildTestPacket(IPPROTO_ICMP
, id
, 2, 0, 'C', 3);
1302 FAIL_IF(Defrag(NULL
, NULL
, p3
) != NULL
);
1303 FAIL_IF(Defrag(NULL
, NULL
, p2
) != NULL
);
1305 reassembled
= Defrag(NULL
, NULL
, p1
);
1306 FAIL_IF_NULL(reassembled
);
1308 FAIL_IF(IPV4_GET_HLEN(reassembled
) != 20);
1309 FAIL_IF(IPV4_GET_IPLEN(reassembled
) != 39);
1311 /* 20 bytes in we should find 8 bytes of A. */
1312 for (i
= 20; i
< 20 + 8; i
++) {
1313 FAIL_IF(GET_PKT_DATA(reassembled
)[i
] != 'A');
1316 /* 28 bytes in we should find 8 bytes of B. */
1317 for (i
= 28; i
< 28 + 8; i
++) {
1318 FAIL_IF(GET_PKT_DATA(reassembled
)[i
] != 'B');
1321 /* And 36 bytes in we should find 3 bytes of C. */
1322 for (i
= 36; i
< 36 + 3; i
++) {
1323 FAIL_IF(GET_PKT_DATA(reassembled
)[i
] != 'C');
1329 SCFree(reassembled
);
1336 * Test the simplest possible re-assembly scenario. All packet in
1337 * order and no overlaps.
1339 static int IPV6DefragInOrderSimpleTest(void)
1341 Packet
*p1
= NULL
, *p2
= NULL
, *p3
= NULL
;
1342 Packet
*reassembled
= NULL
;
1348 p1
= IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 0, 1, 'A', 8);
1350 p2
= IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 1, 1, 'B', 8);
1352 p3
= IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 2, 0, 'C', 3);
1355 FAIL_IF(Defrag(NULL
, NULL
, p1
) != NULL
);
1356 FAIL_IF(Defrag(NULL
, NULL
, p2
) != NULL
);
1357 reassembled
= Defrag(NULL
, NULL
, p3
);
1358 FAIL_IF_NULL(reassembled
);
1360 FAIL_IF(IPV6_GET_PLEN(reassembled
) != 19);
1362 /* 40 bytes in we should find 8 bytes of A. */
1363 for (i
= 40; i
< 40 + 8; i
++) {
1364 FAIL_IF(GET_PKT_DATA(reassembled
)[i
] != 'A');
1367 /* 28 bytes in we should find 8 bytes of B. */
1368 for (i
= 48; i
< 48 + 8; i
++) {
1369 FAIL_IF(GET_PKT_DATA(reassembled
)[i
] != 'B');
1372 /* And 36 bytes in we should find 3 bytes of C. */
1373 for (i
= 56; i
< 56 + 3; i
++) {
1374 FAIL_IF(GET_PKT_DATA(reassembled
)[i
] != 'C');
1380 SCFree(reassembled
);
1386 static int IPV6DefragReverseSimpleTest(void)
1388 DefragContext
*dc
= NULL
;
1389 Packet
*p1
= NULL
, *p2
= NULL
, *p3
= NULL
;
1390 Packet
*reassembled
= NULL
;
1396 dc
= DefragContextNew();
1399 p1
= IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 0, 1, 'A', 8);
1401 p2
= IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 1, 1, 'B', 8);
1403 p3
= IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 2, 0, 'C', 3);
1406 FAIL_IF(Defrag(NULL
, NULL
, p3
) != NULL
);
1407 FAIL_IF(Defrag(NULL
, NULL
, p2
) != NULL
);
1408 reassembled
= Defrag(NULL
, NULL
, p1
);
1409 FAIL_IF_NULL(reassembled
);
1411 /* 40 bytes in we should find 8 bytes of A. */
1412 for (i
= 40; i
< 40 + 8; i
++) {
1413 FAIL_IF(GET_PKT_DATA(reassembled
)[i
] != 'A');
1416 /* 28 bytes in we should find 8 bytes of B. */
1417 for (i
= 48; i
< 48 + 8; i
++) {
1418 FAIL_IF(GET_PKT_DATA(reassembled
)[i
] != 'B');
1421 /* And 36 bytes in we should find 3 bytes of C. */
1422 for (i
= 56; i
< 56 + 3; i
++) {
1423 FAIL_IF(GET_PKT_DATA(reassembled
)[i
] != 'C');
1426 DefragContextDestroy(dc
);
1430 SCFree(reassembled
);
1436 static int DefragDoSturgesNovakTest(int policy
, u_char
*expected
,
1437 size_t expected_len
)
1444 * Build the packets.
1448 Packet
*packets
[17];
1449 memset(packets
, 0x00, sizeof(packets
));
1452 * Original fragments.
1456 packets
[0] = BuildTestPacket(IPPROTO_ICMP
, id
, 0, 1, 'A', 24);
1459 packets
[1] = BuildTestPacket(IPPROTO_ICMP
, id
, 32 >> 3, 1, 'B', 16);
1462 packets
[2] = BuildTestPacket(IPPROTO_ICMP
, id
, 48 >> 3, 1, 'C', 24);
1465 packets
[3] = BuildTestPacket(IPPROTO_ICMP
, id
, 80 >> 3, 1, 'D', 8);
1468 packets
[4] = BuildTestPacket(IPPROTO_ICMP
, id
, 104 >> 3, 1, 'E', 16);
1471 packets
[5] = BuildTestPacket(IPPROTO_ICMP
, id
, 120 >> 3, 1, 'F', 24);
1474 packets
[6] = BuildTestPacket(IPPROTO_ICMP
, id
, 144 >> 3, 1, 'G', 16);
1477 packets
[7] = BuildTestPacket(IPPROTO_ICMP
, id
, 160 >> 3, 1, 'H', 16);
1480 packets
[8] = BuildTestPacket(IPPROTO_ICMP
, id
, 176 >> 3, 1, 'I', 8);
1483 * Overlapping subsequent fragments.
1487 packets
[9] = BuildTestPacket(IPPROTO_ICMP
, id
, 8 >> 3, 1, 'J', 32);
1490 packets
[10] = BuildTestPacket(IPPROTO_ICMP
, id
, 48 >> 3, 1, 'K', 24);
1493 packets
[11] = BuildTestPacket(IPPROTO_ICMP
, id
, 72 >> 3, 1, 'L', 24);
1496 packets
[12] = BuildTestPacket(IPPROTO_ICMP
, id
, 96 >> 3, 1, 'M', 24);
1499 packets
[13] = BuildTestPacket(IPPROTO_ICMP
, id
, 128 >> 3, 1, 'N', 8);
1502 packets
[14] = BuildTestPacket(IPPROTO_ICMP
, id
, 152 >> 3, 1, 'O', 8);
1505 packets
[15] = BuildTestPacket(IPPROTO_ICMP
, id
, 160 >> 3, 1, 'P', 8);
1508 packets
[16] = BuildTestPacket(IPPROTO_ICMP
, id
, 176 >> 3, 0, 'Q', 16);
1510 default_policy
= policy
;
1512 /* Send all but the last. */
1513 for (i
= 0; i
< 9; i
++) {
1514 Packet
*tp
= Defrag(NULL
, NULL
, packets
[i
]);
1515 FAIL_IF_NOT_NULL(tp
);
1516 FAIL_IF(ENGINE_ISSET_EVENT(packets
[i
], IPV4_FRAG_OVERLAP
));
1519 for (; i
< 16; i
++) {
1520 Packet
*tp
= Defrag(NULL
, NULL
, packets
[i
]);
1521 FAIL_IF_NOT_NULL(tp
);
1522 if (ENGINE_ISSET_EVENT(packets
[i
], IPV4_FRAG_OVERLAP
)) {
1526 FAIL_IF_NOT(overlap
);
1528 /* And now the last one. */
1529 Packet
*reassembled
= Defrag(NULL
, NULL
, packets
[16]);
1530 FAIL_IF_NULL(reassembled
);
1532 FAIL_IF(IPV4_GET_HLEN(reassembled
) != 20);
1533 FAIL_IF(IPV4_GET_IPLEN(reassembled
) != 20 + 192);
1535 FAIL_IF(memcmp(GET_PKT_DATA(reassembled
) + 20, expected
, expected_len
) != 0);
1536 SCFree(reassembled
);
1538 /* Make sure all frags were returned back to the pool. */
1539 FAIL_IF(defrag_context
->frag_pool
->outstanding
!= 0);
1541 for (i
= 0; i
< 17; i
++) {
1548 static int IPV6DefragDoSturgesNovakTest(int policy
, u_char
*expected
,
1549 size_t expected_len
)
1556 * Build the packets.
1560 Packet
*packets
[17];
1561 memset(packets
, 0x00, sizeof(packets
));
1564 * Original fragments.
1568 packets
[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 0, 1, 'A', 24);
1571 packets
[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 32 >> 3, 1, 'B', 16);
1574 packets
[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 48 >> 3, 1, 'C', 24);
1577 packets
[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 80 >> 3, 1, 'D', 8);
1580 packets
[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 104 >> 3, 1, 'E', 16);
1583 packets
[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 120 >> 3, 1, 'F', 24);
1586 packets
[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 144 >> 3, 1, 'G', 16);
1589 packets
[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 160 >> 3, 1, 'H', 16);
1592 packets
[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 176 >> 3, 1, 'I', 8);
1595 * Overlapping subsequent fragments.
1599 packets
[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 8 >> 3, 1, 'J', 32);
1602 packets
[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 48 >> 3, 1, 'K', 24);
1605 packets
[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 72 >> 3, 1, 'L', 24);
1608 packets
[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 96 >> 3, 1, 'M', 24);
1611 packets
[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 128 >> 3, 1, 'N', 8);
1614 packets
[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 152 >> 3, 1, 'O', 8);
1617 packets
[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 160 >> 3, 1, 'P', 8);
1620 packets
[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6
, id
, 176 >> 3, 0, 'Q', 16);
1622 default_policy
= policy
;
1624 /* Send all but the last. */
1625 for (i
= 0; i
< 9; i
++) {
1626 Packet
*tp
= Defrag(NULL
, NULL
, packets
[i
]);
1627 FAIL_IF_NOT_NULL(tp
);
1628 FAIL_IF(ENGINE_ISSET_EVENT(packets
[i
], IPV6_FRAG_OVERLAP
));
1631 for (; i
< 16; i
++) {
1632 Packet
*tp
= Defrag(NULL
, NULL
, packets
[i
]);
1633 FAIL_IF_NOT_NULL(tp
);
1634 if (ENGINE_ISSET_EVENT(packets
[i
], IPV6_FRAG_OVERLAP
)) {
1638 FAIL_IF_NOT(overlap
);
1640 /* And now the last one. */
1641 Packet
*reassembled
= Defrag(NULL
, NULL
, packets
[16]);
1642 FAIL_IF_NULL(reassembled
);
1643 FAIL_IF(memcmp(GET_PKT_DATA(reassembled
) + 40, expected
, expected_len
) != 0);
1645 FAIL_IF(IPV6_GET_PLEN(reassembled
) != 192);
1647 SCFree(reassembled
);
1649 /* Make sure all frags were returned to the pool. */
1650 FAIL_IF(defrag_context
->frag_pool
->outstanding
!= 0);
1652 for (i
= 0; i
< 17; i
++) {
1660 DefragSturgesNovakBsdTest(void)
1662 /* Expected data. */
1663 u_char expected
[] = {
1690 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD
, expected
,
1695 static int IPV6DefragSturgesNovakBsdTest(void)
1697 /* Expected data. */
1698 u_char expected
[] = {
1725 FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD
, expected
,
1730 static int DefragSturgesNovakLinuxIpv4Test(void)
1732 /* Expected data. */
1733 u_char expected
[] = {
1760 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX
, expected
,
1765 static int IPV6DefragSturgesNovakLinuxTest(void)
1767 /* Expected data. */
1768 u_char expected
[] = {
1795 FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX
, expected
,
1800 static int DefragSturgesNovakWindowsIpv4Test(void)
1802 /* Expected data. */
1803 u_char expected
[] = {
1830 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS
, expected
,
1835 static int IPV6DefragSturgesNovakWindowsTest(void)
1837 /* Expected data. */
1838 u_char expected
[] = {
1865 FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS
, expected
,
1870 static int DefragSturgesNovakSolarisTest(void)
1872 /* Expected data. */
1873 u_char expected
[] = {
1900 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS
, expected
,
1905 static int IPV6DefragSturgesNovakSolarisTest(void)
1907 /* Expected data. */
1908 u_char expected
[] = {
1935 FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS
, expected
,
1940 static int DefragSturgesNovakFirstTest(void)
1942 /* Expected data. */
1943 u_char expected
[] = {
1970 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST
, expected
,
1975 static int IPV6DefragSturgesNovakFirstTest(void)
1977 /* Expected data. */
1978 u_char expected
[] = {
2005 return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST
, expected
,
2010 DefragSturgesNovakLastTest(void)
2012 /* Expected data. */
2013 u_char expected
[] = {
2040 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST
, expected
,
2045 static int IPV6DefragSturgesNovakLastTest(void)
2047 /* Expected data. */
2048 u_char expected
[] = {
2075 FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST
, expected
,
2080 static int DefragTimeoutTest(void)
2084 /* Setup a small numberr of trackers. */
2085 FAIL_IF_NOT(ConfSet("defrag.trackers", "16"));
2089 /* Load in 16 packets. */
2090 for (i
= 0; i
< 16; i
++) {
2091 Packet
*p
= BuildTestPacket(IPPROTO_ICMP
,i
, 0, 1, 'A' + i
, 16);
2094 Packet
*tp
= Defrag(NULL
, NULL
, p
);
2096 FAIL_IF_NOT_NULL(tp
);
2099 /* Build a new packet but push the timestamp out by our timeout.
2100 * This should force our previous fragments to be timed out. */
2101 Packet
*p
= BuildTestPacket(IPPROTO_ICMP
, 99, 0, 1, 'A' + i
, 16);
2104 p
->ts
.tv_sec
+= (defrag_context
->timeout
+ 1);
2105 Packet
*tp
= Defrag(NULL
, NULL
, p
);
2106 FAIL_IF_NOT_NULL(tp
);
2108 DefragTracker
*tracker
= DefragLookupTrackerFromHash(p
);
2109 FAIL_IF_NULL(tracker
);
2111 FAIL_IF(tracker
->id
!= 99);
2113 SCMutexUnlock(&tracker
->lock
);
2121 * QA found that if you send a packet where more frags is 0, offset is
2122 * > 0 and there is no data in the packet that the re-assembler will
2123 * fail. The fix was simple, but this unit test is just to make sure
2124 * its not introduced.
2126 static int DefragIPv4NoDataTest(void)
2128 DefragContext
*dc
= NULL
;
2134 dc
= DefragContextNew();
2137 /* This packet has an offset > 0, more frags set to 0 and no data. */
2138 p
= BuildTestPacket(IPPROTO_ICMP
, id
, 1, 0, 'A', 0);
2141 /* We do not expect a packet returned. */
2142 FAIL_IF(Defrag(NULL
, NULL
, p
) != NULL
);
2144 /* The fragment should have been ignored so no fragments should
2145 * have been allocated from the pool. */
2146 FAIL_IF(dc
->frag_pool
->outstanding
!= 0);
2148 DefragContextDestroy(dc
);
2155 static int DefragIPv4TooLargeTest(void)
2157 DefragContext
*dc
= NULL
;
2162 dc
= DefragContextNew();
2165 /* Create a fragment that would extend past the max allowable size
2166 * for an IPv4 packet. */
2167 p
= BuildTestPacket(IPPROTO_ICMP
, 1, 8183, 0, 'A', 71);
2170 /* We do not expect a packet returned. */
2171 FAIL_IF(Defrag(NULL
, NULL
, p
) != NULL
);
2173 /* We do expect an event. */
2174 FAIL_IF_NOT(ENGINE_ISSET_EVENT(p
, IPV4_FRAG_PKT_TOO_LARGE
));
2176 /* The fragment should have been ignored so no fragments should have
2177 * been allocated from the pool. */
2178 FAIL_IF(dc
->frag_pool
->outstanding
!= 0);
2180 DefragContextDestroy(dc
);
2188 * Test that fragments in different VLANs that would otherwise be
2189 * re-assembled, are not re-assembled. Just use simple in-order
2192 static int DefragVlanTest(void)
2194 Packet
*p1
= NULL
, *p2
= NULL
, *r
= NULL
;
2198 p1
= BuildTestPacket(IPPROTO_ICMP
, 1, 0, 1, 'A', 8);
2200 p2
= BuildTestPacket(IPPROTO_ICMP
, 1, 1, 0, 'B', 8);
2203 /* With no VLAN IDs set, packets should re-assemble. */
2204 FAIL_IF((r
= Defrag(NULL
, NULL
, p1
)) != NULL
);
2205 FAIL_IF((r
= Defrag(NULL
, NULL
, p2
)) == NULL
);
2208 /* With mismatched VLANs, packets should not re-assemble. */
2211 FAIL_IF((r
= Defrag(NULL
, NULL
, p1
)) != NULL
);
2212 FAIL_IF((r
= Defrag(NULL
, NULL
, p2
)) != NULL
);
2222 * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID.
2224 static int DefragVlanQinQTest(void)
2226 Packet
*p1
= NULL
, *p2
= NULL
, *r
= NULL
;
2230 p1
= BuildTestPacket(IPPROTO_ICMP
, 1, 0, 1, 'A', 8);
2232 p2
= BuildTestPacket(IPPROTO_ICMP
, 1, 1, 0, 'B', 8);
2235 /* With no VLAN IDs set, packets should re-assemble. */
2236 FAIL_IF((r
= Defrag(NULL
, NULL
, p1
)) != NULL
);
2237 FAIL_IF((r
= Defrag(NULL
, NULL
, p2
)) == NULL
);
2240 /* With mismatched VLANs, packets should not re-assemble. */
2245 FAIL_IF((r
= Defrag(NULL
, NULL
, p1
)) != NULL
);
2246 FAIL_IF((r
= Defrag(NULL
, NULL
, p2
)) != NULL
);
2255 static int DefragTrackerReuseTest(void)
2259 DefragTracker
*tracker1
= NULL
, *tracker2
= NULL
;
2263 /* Build a packet, its not a fragment but shouldn't matter for
2265 p1
= BuildTestPacket(IPPROTO_ICMP
, id
, 0, 0, 'A', 8);
2268 /* Get a tracker. It shouldn't look like its already in use. */
2269 tracker1
= DefragGetTracker(NULL
, NULL
, p1
);
2270 FAIL_IF_NULL(tracker1
);
2271 FAIL_IF(tracker1
->seen_last
);
2272 FAIL_IF(tracker1
->remove
);
2273 DefragTrackerRelease(tracker1
);
2275 /* Get a tracker again, it should be the same one. */
2276 tracker2
= DefragGetTracker(NULL
, NULL
, p1
);
2277 FAIL_IF_NULL(tracker2
);
2278 FAIL_IF(tracker2
!= tracker1
);
2279 DefragTrackerRelease(tracker1
);
2281 /* Now mark the tracker for removal. It should not be returned
2282 * when we get a tracker for a packet that may have the same
2284 tracker1
->remove
= 1;
2286 tracker2
= DefragGetTracker(NULL
, NULL
, p1
);
2287 FAIL_IF_NULL(tracker2
);
2288 FAIL_IF(tracker2
== tracker1
);
2289 FAIL_IF(tracker2
->remove
);
2297 * IPV4: Test the case where you have a packet fragmented in 3 parts
2299 * - Offset: 2; MF: 1
2300 * - Offset: 0; MF: 1
2301 * - Offset: 1; MF: 0
2303 * Only the fragments with offset 0 and 1 should be reassembled.
2305 static int DefragMfIpv4Test(void)
2312 Packet
*p1
= BuildTestPacket(IPPROTO_ICMP
, ip_id
, 2, 1, 'C', 8);
2313 Packet
*p2
= BuildTestPacket(IPPROTO_ICMP
, ip_id
, 0, 1, 'A', 8);
2314 Packet
*p3
= BuildTestPacket(IPPROTO_ICMP
, ip_id
, 1, 0, 'B', 8);
2315 FAIL_IF(p1
== NULL
|| p2
== NULL
|| p3
== NULL
);
2317 p
= Defrag(NULL
, NULL
, p1
);
2318 FAIL_IF_NOT_NULL(p
);
2320 p
= Defrag(NULL
, NULL
, p2
);
2321 FAIL_IF_NOT_NULL(p
);
2323 /* This should return a packet as MF=0. */
2324 p
= Defrag(NULL
, NULL
, p3
);
2327 /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the
2328 * fragments should be in the re-assembled packet. */
2329 FAIL_IF(IPV4_GET_IPLEN(p
) != 36);
2340 * IPV6: Test the case where you have a packet fragmented in 3 parts
2342 * - Offset: 2; MF: 1
2343 * - Offset: 0; MF: 1
2344 * - Offset: 1; MF: 0
2346 * Only the fragments with offset 0 and 1 should be reassembled.
2348 static int DefragMfIpv6Test(void)
2355 Packet
*p1
= IPV6BuildTestPacket(IPPROTO_ICMPV6
, ip_id
, 2, 1, 'C', 8);
2356 Packet
*p2
= IPV6BuildTestPacket(IPPROTO_ICMPV6
, ip_id
, 0, 1, 'A', 8);
2357 Packet
*p3
= IPV6BuildTestPacket(IPPROTO_ICMPV6
, ip_id
, 1, 0, 'B', 8);
2358 FAIL_IF(p1
== NULL
|| p2
== NULL
|| p3
== NULL
);
2360 p
= Defrag(NULL
, NULL
, p1
);
2361 FAIL_IF_NOT_NULL(p
);
2363 p
= Defrag(NULL
, NULL
, p2
);
2364 FAIL_IF_NOT_NULL(p
);
2366 /* This should return a packet as MF=0. */
2367 p
= Defrag(NULL
, NULL
, p3
);
2370 /* For IPv6 the expected length is just the length of the payload
2371 * of 2 fragments, so 16. */
2372 FAIL_IF(IPV6_GET_PLEN(p
) != 16);
2383 * \brief Test that fragments that match other than the proto don't
2384 * actually get matched.
2386 static int DefragTestBadProto(void)
2388 Packet
*p1
= NULL
, *p2
= NULL
, *p3
= NULL
;
2393 p1
= BuildTestPacket(IPPROTO_ICMP
, id
, 0, 1, 'A', 8);
2395 p2
= BuildTestPacket(IPPROTO_UDP
, id
, 1, 1, 'B', 8);
2397 p3
= BuildTestPacket(IPPROTO_ICMP
, id
, 2, 0, 'C', 3);
2400 FAIL_IF_NOT_NULL(Defrag(NULL
, NULL
, p1
));
2401 FAIL_IF_NOT_NULL(Defrag(NULL
, NULL
, p2
));
2402 FAIL_IF_NOT_NULL(Defrag(NULL
, NULL
, p3
));
2413 * \test Test a report Linux overlap issue that doesn't appear to be
2414 * covered by the Sturges/Novak tests above.
2416 static int DefragTestJeremyLinux(void)
2418 char expected
[] = "AAAAAAAA"
2433 default_policy
= DEFRAG_POLICY_LINUX
;
2439 packets
[0] = BuildTestPacket(IPPROTO_ICMP
, id
, 0, 1, 'A', 24);
2440 packets
[1] = BuildTestPacket(IPPROTO_ICMP
, id
, 40 >> 3, 1, 'B', 48);
2441 packets
[2] = BuildTestPacket(IPPROTO_ICMP
, id
, 24 >> 3, 1, 'C', 48);
2442 packets
[3] = BuildTestPacket(IPPROTO_ICMP
, id
, 88 >> 3, 0, 'D', 14);
2444 Packet
*r
= Defrag(NULL
, NULL
, packets
[0]);
2445 FAIL_IF_NOT_NULL(r
);
2447 r
= Defrag(NULL
, NULL
, packets
[1]);
2448 FAIL_IF_NOT_NULL(r
);
2450 r
= Defrag(NULL
, NULL
, packets
[2]);
2451 FAIL_IF_NOT_NULL(r
);
2453 r
= Defrag(NULL
, NULL
, packets
[3]);
2456 FAIL_IF(memcmp(expected
, GET_PKT_DATA(r
) + 20, sizeof(expected
)) != 0);
2458 for (i
= 0; i
< 4; i
++) {
2467 #endif /* UNITTESTS */
2469 void DefragRegisterTests(void)
2472 UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest
);
2473 UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest
);
2474 UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest
);
2475 UtRegisterTest("DefragSturgesNovakLinuxIpv4Test",
2476 DefragSturgesNovakLinuxIpv4Test
);
2477 UtRegisterTest("DefragSturgesNovakWindowsIpv4Test",
2478 DefragSturgesNovakWindowsIpv4Test
);
2479 UtRegisterTest("DefragSturgesNovakSolarisTest",
2480 DefragSturgesNovakSolarisTest
);
2481 UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest
);
2482 UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest
);
2484 UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest
);
2485 UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest
);
2487 UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest
);
2488 UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest
);
2489 UtRegisterTest("IPV6DefragSturgesNovakBsdTest",
2490 IPV6DefragSturgesNovakBsdTest
);
2491 UtRegisterTest("IPV6DefragSturgesNovakLinuxTest",
2492 IPV6DefragSturgesNovakLinuxTest
);
2493 UtRegisterTest("IPV6DefragSturgesNovakWindowsTest",
2494 IPV6DefragSturgesNovakWindowsTest
);
2495 UtRegisterTest("IPV6DefragSturgesNovakSolarisTest",
2496 IPV6DefragSturgesNovakSolarisTest
);
2497 UtRegisterTest("IPV6DefragSturgesNovakFirstTest",
2498 IPV6DefragSturgesNovakFirstTest
);
2499 UtRegisterTest("IPV6DefragSturgesNovakLastTest",
2500 IPV6DefragSturgesNovakLastTest
);
2502 UtRegisterTest("DefragVlanTest", DefragVlanTest
);
2503 UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest
);
2504 UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest
);
2505 UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest
);
2506 UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test
);
2507 UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test
);
2508 UtRegisterTest("DefragTestBadProto", DefragTestBadProto
);
2510 UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux
);
2511 #endif /* UNITTESTS */