suricata
defrag.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2024 Open Information Security Foundation
2 *
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
5 * Software Foundation.
6 *
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.
11 *
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
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author Endace Technology Limited, Jason Ish <jason.ish@endace.com>
22 *
23 * Defragmentation module.
24 * References:
25 * - RFC 815
26 * - OpenBSD PF's IP normalization (pf_norm.c)
27 *
28 * \todo pool for frag packet storage
29 * \todo policy bsd-right
30 * \todo profile hash function
31 * \todo log anomalies
32 */
33
34#include "suricata-common.h"
35
36#include "queue.h"
37
38#include "suricata.h"
39#include "threads.h"
40#include "conf.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"
51#include "util-host-os-info.h"
52#include "util-validate.h"
53
54#include "defrag.h"
55#include "defrag-hash.h"
56#include "defrag-config.h"
57
58#include "tmqh-packetpool.h"
59#include "decode.h"
60
61#ifdef UNITTESTS
62#include "util-unittest.h"
63#endif
64
65#define DEFAULT_DEFRAG_HASH_SIZE 0xffff
66#define DEFAULT_DEFRAG_POOL_SIZE 0xffff
67
68/**
69 * Default timeout (in seconds) before a defragmentation tracker will
70 * be released.
71 */
72#define TIMEOUT_DEFAULT 60
73
74/**
75 * Maximum allowed timeout, 24 hours.
76 */
77#define TIMEOUT_MAX (60 * 60 * 24)
78
79/**
80 * Minimum allowed timeout, 1 second.
81 */
82#define TIMEOUT_MIN 1
83
84/** Fragment reassembly policies. */
96
97static uint8_t default_policy = DEFRAG_POLICY_BSD;
98
99/** The global DefragContext so all threads operate from the same
100 * context. */
101static DefragContext *defrag_context;
102
104
105/**
106 * \brief Reset a frag for reuse in a pool.
107 */
108static void
109DefragFragReset(Frag *frag)
110{
111 if (frag->pkt != NULL)
112 SCFree(frag->pkt);
113 memset(frag, 0, sizeof(*frag));
114}
115
116/**
117 * \brief Allocate a new frag for use in a pool.
118 */
119static int
120DefragFragInit(void *data, void *initdata)
121{
122 Frag *frag = data;
123
124 memset(frag, 0, sizeof(*frag));
125 return 1;
126}
127
128/**
129 * \brief Free all frags associated with a tracker.
130 */
131void
133{
134 Frag *frag, *tmp;
135
136 /* Lock the frag pool as we'll be return items to it. */
137 SCMutexLock(&defrag_context->frag_pool_lock);
138
139 RB_FOREACH_SAFE(frag, IP_FRAGMENTS, &tracker->fragment_tree, tmp) {
140 RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, frag);
141 DefragFragReset(frag);
142 PoolReturn(defrag_context->frag_pool, frag);
143 }
144
145 SCMutexUnlock(&defrag_context->frag_pool_lock);
146}
147
148/**
149 * \brief Create a new DefragContext.
150 *
151 * \retval On success a return an initialized DefragContext, otherwise
152 * NULL will be returned.
153 */
154static DefragContext *
155DefragContextNew(void)
156{
157 DefragContext *dc;
158
159 dc = SCCalloc(1, sizeof(*dc));
160 if (unlikely(dc == NULL))
161 return NULL;
162
163 /* Initialize the pool of trackers. */
164 intmax_t tracker_pool_size;
165 if (!SCConfGetInt("defrag.trackers", &tracker_pool_size) || tracker_pool_size == 0) {
166 tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
167 }
168
169 /* Initialize the pool of frags. */
170 intmax_t frag_pool_size;
171 if (!SCConfGetInt("defrag.max-frags", &frag_pool_size) || frag_pool_size == 0 ||
172 frag_pool_size > UINT32_MAX) {
173 frag_pool_size = DEFAULT_DEFRAG_POOL_SIZE;
174 }
175 uint32_t frag_pool_prealloc = (uint32_t)frag_pool_size / 2;
176 dc->frag_pool = PoolInit((uint32_t)frag_pool_size, frag_pool_prealloc, sizeof(Frag), NULL,
177 DefragFragInit, dc, NULL, NULL);
178 if (dc->frag_pool == NULL) {
179 FatalError("Defrag: Failed to initialize fragment pool.");
180 }
181 if (SCMutexInit(&dc->frag_pool_lock, NULL) != 0) {
182 FatalError("Defrag: Failed to initialize frag pool mutex.");
183 }
184
185 /* Set the default timeout. */
186 intmax_t timeout;
187 if (!SCConfGetInt("defrag.timeout", &timeout)) {
189 } else {
190 if (timeout < TIMEOUT_MIN) {
191 FatalError("defrag: Timeout less than minimum allowed value.");
192 }
193 else if (timeout > TIMEOUT_MAX) {
194 FatalError("defrag: Timeout greater than maximum allowed value.");
195 }
196 dc->timeout = (uint32_t)timeout;
197 }
198
199 SCLogDebug("Defrag Initialized:");
200 SCLogDebug("\tTimeout: %"PRIuMAX, (uintmax_t)dc->timeout);
201 SCLogDebug("\tMaximum defrag trackers: %"PRIuMAX, tracker_pool_size);
202 SCLogDebug("\tPreallocated defrag trackers: %"PRIuMAX, tracker_pool_size);
203 SCLogDebug("\tMaximum fragments: %"PRIuMAX, (uintmax_t)frag_pool_size);
204 SCLogDebug("\tPreallocated fragments: %"PRIuMAX, (uintmax_t)frag_pool_prealloc);
205
206 return dc;
207}
208
209static void
210DefragContextDestroy(DefragContext *dc)
211{
212 if (dc == NULL)
213 return;
214
215 PoolFree(dc->frag_pool);
216 SCFree(dc);
217}
218
219/**
220 * Attempt to re-assemble a packet.
221 *
222 * \param tracker The defragmentation tracker to reassemble from.
223 */
224static Packet *
225Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
226{
227 Packet *rp = NULL;
228
229 /* Should not be here unless we have seen the last fragment. */
230 if (!tracker->seen_last) {
231 return NULL;
232 }
233
234 /* Check that we have the first fragment and its of a valid size. */
235 Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
236 if (first == NULL) {
237 goto done;
238 } else if (first->offset != 0) {
239 /* Still waiting for the first fragment. */
240 goto done;
241 } else if (first->len < sizeof(IPV4Hdr)) {
242 /* First fragment isn't enough for an IPv6 header. */
243 goto error_remove_tracker;
244 }
245
246 /* Check that we have all the data. Relies on the fact that
247 * fragments are inserted in frag_offset order. */
248 Frag *frag = NULL;
249 size_t len = 0;
250 RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
251 if (frag->offset > len) {
252 /* This fragment starts after the end of the previous
253 * fragment. We have a hole. */
254 goto done;
255 }
256 else {
257 /* Update the packet length to the largest known data offset. */
258 len = MAX(len, frag->offset + frag->data_len);
259 }
260 }
261
262 const IPV4Hdr *oip4h = PacketGetIPv4(p);
263
264 /* Allocate a Packet for the reassembled packet. On failure we
265 * SCFree all the resources held by this tracker. */
266 rp = PacketDefragPktSetup(p, NULL, 0, IPV4_GET_RAW_IPPROTO(oip4h));
267 if (rp == NULL) {
268 goto error_remove_tracker;
269 }
272 rp->datalink = tracker->datalink;
273
274 int fragmentable_offset = 0;
275 uint16_t fragmentable_len = 0;
276 uint16_t hlen = 0;
277 int ip_hdr_offset = 0;
278
279 /* Assume more frags. */
280 uint16_t prev_offset = 0;
281 bool more_frags = 1;
282
283 RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
284 SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64,
285 frag, frag->data_len, frag->offset, frag->pcap_cnt);
286
287 /* Previous fragment has no more fragments, and this packet
288 * doesn't overlap. We're done. */
289 if (!more_frags && frag->offset > prev_offset) {
290 break;
291 }
292
293 if (frag->skip)
294 continue;
295 if (frag->ltrim >= frag->data_len)
296 continue;
297 if (frag->offset == 0) {
298
299 if (PacketCopyData(rp, frag->pkt, frag->len) == -1)
300 goto error_remove_tracker;
301
302 hlen = frag->hlen;
303 ip_hdr_offset = tracker->ip_hdr_offset;
304
305 /* This is the start of the fragmentable portion of the
306 * first packet. All fragment offsets are relative to
307 * this. */
308 fragmentable_offset = tracker->ip_hdr_offset + frag->hlen;
309 fragmentable_len = frag->data_len;
310 }
311 else {
312 int pkt_end = fragmentable_offset + frag->offset + frag->data_len;
313 if (pkt_end > (int)MAX_PAYLOAD_SIZE) {
314 SCLogDebug("Failed re-assemble "
315 "fragmented packet, exceeds size of packet buffer.");
316 goto error_remove_tracker;
317 }
319 fragmentable_offset + frag->offset + frag->ltrim,
320 frag->pkt + frag->data_offset + frag->ltrim,
321 frag->data_len - frag->ltrim) == -1) {
322 goto error_remove_tracker;
323 }
324 if (frag->offset > UINT16_MAX - frag->data_len) {
325 SCLogDebug("Failed re-assemble "
326 "fragmentable_len exceeds UINT16_MAX");
327 goto error_remove_tracker;
328 }
329 if (frag->offset + frag->data_len > fragmentable_len)
330 fragmentable_len = frag->offset + frag->data_len;
331 }
332
333 /* Even if this fragment is flagged as having no more
334 * fragments, still continue. The next fragment may have the
335 * same offset with data that is preferred.
336 *
337 * For example, DefragBsdFragmentAfterNoMfIpv{4,6}Test
338 *
339 * This is due to not all fragments being completely trimmed,
340 * but relying on the copy ordering. */
341 more_frags = frag->more_frags;
342 prev_offset = frag->offset;
343 }
344
345 SCLogDebug("ip_hdr_offset %u, hlen %" PRIu16 ", fragmentable_len %" PRIu16, ip_hdr_offset, hlen,
346 fragmentable_len);
347
348 IPV4Hdr *ip4h = (IPV4Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
349 uint16_t old = ip4h->ip_len + ip4h->ip_off;
350 DEBUG_VALIDATE_BUG_ON(hlen > UINT16_MAX - fragmentable_len);
351 ip4h->ip_len = htons(fragmentable_len + hlen);
352 ip4h->ip_off = 0;
353 ip4h->ip_csum = FixChecksum(ip4h->ip_csum, old, ip4h->ip_len + ip4h->ip_off);
354 SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len);
355
356 tracker->remove = 1;
357 DefragTrackerFreeFrags(tracker);
358done:
359 return rp;
360
361error_remove_tracker:
362 tracker->remove = 1;
363 DefragTrackerFreeFrags(tracker);
364 if (rp != NULL)
366 return NULL;
367}
368
369/**
370 * Attempt to re-assemble a packet.
371 *
372 * \param tracker The defragmentation tracker to reassemble from.
373 */
374static Packet *
375Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
376{
377 Packet *rp = NULL;
378
379 /* Should not be here unless we have seen the last fragment. */
380 if (!tracker->seen_last)
381 return NULL;
382
383 /* Check that we have the first fragment and its of a valid size. */
384 Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
385 if (first == NULL) {
386 goto done;
387 } else if (first->offset != 0) {
388 /* Still waiting for the first fragment. */
389 goto done;
390 } else if (first->len < sizeof(IPV6Hdr)) {
391 /* First fragment isn't enough for an IPv6 header. */
392 goto error_remove_tracker;
393 }
394
395 /* Check that we have all the data. Relies on the fact that
396 * fragments are inserted if frag_offset order. */
397 size_t len = 0;
398 Frag *frag = NULL;
399 RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
400 if (frag->skip) {
401 continue;
402 }
403
404 if (frag == first) {
405 if (frag->offset != 0) {
406 goto done;
407 }
408 len = frag->data_len;
409 }
410 else {
411 if (frag->offset > len) {
412 /* This fragment starts after the end of the previous
413 * fragment. We have a hole. */
414 goto done;
415 }
416 else {
417 len = MAX(len, frag->offset + frag->data_len);
418 }
419 }
420 }
421
422 const IPV6Hdr *oip6h = PacketGetIPv6(p);
423
424 /* Allocate a Packet for the reassembled packet. On failure we
425 * SCFree all the resources held by this tracker. */
427 p, (const uint8_t *)oip6h, IPV6_GET_RAW_PLEN(oip6h) + sizeof(IPV6Hdr), 0);
428 if (rp == NULL) {
429 goto error_remove_tracker;
430 }
433 rp->datalink = tracker->datalink;
434
435 uint16_t unfragmentable_len = 0;
436 int fragmentable_offset = 0;
437 uint16_t fragmentable_len = 0;
438 int ip_hdr_offset = 0;
439 uint8_t next_hdr = 0;
440
441 /* Assume more frags. */
442 uint16_t prev_offset = 0;
443 bool more_frags = 1;
444
445 RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
446 if (!more_frags && frag->offset > prev_offset) {
447 break;
448 }
449 if (frag->skip)
450 continue;
451 if (frag->data_len - frag->ltrim <= 0)
452 continue;
453 if (frag->offset == 0) {
454 IPV6FragHdr *frag_hdr = (IPV6FragHdr *)(frag->pkt +
455 frag->frag_hdr_offset);
456 next_hdr = frag_hdr->ip6fh_nxt;
457
458 /* This is the first packet, we use this packets link and
459 * IPv6 headers. We also copy in its data, but remove the
460 * fragmentation header. */
461 if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1)
462 goto error_remove_tracker;
464 frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr),
465 frag->data_len) == -1)
466 goto error_remove_tracker;
467 ip_hdr_offset = tracker->ip_hdr_offset;
468
469 /* This is the start of the fragmentable portion of the
470 * first packet. All fragment offsets are relative to
471 * this. */
472 fragmentable_offset = frag->frag_hdr_offset;
473 fragmentable_len = frag->data_len;
474
475 /* unfragmentable part is the part between the ipv6 header
476 * and the frag header. */
477 DEBUG_VALIDATE_BUG_ON(fragmentable_offset < ip_hdr_offset + IPV6_HEADER_LEN);
479 fragmentable_offset - ip_hdr_offset - IPV6_HEADER_LEN > UINT16_MAX);
480 unfragmentable_len = (uint16_t)(fragmentable_offset - ip_hdr_offset - IPV6_HEADER_LEN);
481 if (unfragmentable_len >= fragmentable_offset)
482 goto error_remove_tracker;
483 }
484 else {
485 if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim,
486 frag->pkt + frag->data_offset + frag->ltrim,
487 frag->data_len - frag->ltrim) == -1)
488 goto error_remove_tracker;
489 if (frag->offset + frag->data_len > fragmentable_len)
490 fragmentable_len = frag->offset + frag->data_len;
491 }
492
493 /* Even if this fragment is flagged as having no more
494 * fragments, still continue. The next fragment may have the
495 * same offset with data that is preferred.
496 *
497 * For example, DefragBsdFragmentAfterNoMfIpv{4,6}Test
498 *
499 * This is due to not all fragments being completely trimmed,
500 * but relying on the copy ordering. */
501 more_frags = frag->more_frags;
502 prev_offset = frag->offset;
503 }
504
505 IPV6Hdr *ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + tracker->ip_hdr_offset);
506 DEBUG_VALIDATE_BUG_ON(unfragmentable_len > UINT16_MAX - fragmentable_len);
507 ip6h->s_ip6_plen = htons(fragmentable_len + unfragmentable_len);
508 /* if we have no unfragmentable part, so no ext hdrs before the frag
509 * header, we need to update the ipv6 headers next header field. This
510 * points to the frag header, and we will make it point to the layer
511 * directly after the frag header. */
512 if (unfragmentable_len == 0)
513 ip6h->s_ip6_nxt = next_hdr;
514 SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) +
515 unfragmentable_len + fragmentable_len);
516
517 tracker->remove = 1;
518 DefragTrackerFreeFrags(tracker);
519done:
520 return rp;
521
522error_remove_tracker:
523 tracker->remove = 1;
524 DefragTrackerFreeFrags(tracker);
525 if (rp != NULL)
527 return NULL;
528}
529
530/**
531 * The RB_TREE compare function for fragments.
532 *
533 * When it comes to adding fragments, we want subsequent ones with the
534 * same offset to be treated as greater than, so we don't have an
535 * equal return value here.
536 */
537int DefragRbFragCompare(struct Frag_ *a, struct Frag_ *b) {
538 if (a->offset < b->offset) {
539 return -1;
540 }
541 return 1;
542}
543
544/**
545 * Insert a new IPv4/IPv6 fragment into a tracker.
546 *
547 * \todo Allocate packet buffers from a pool.
548 */
549static Packet *
550DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
551{
552 Packet *r = NULL;
553 uint16_t ltrim = 0;
554
555 bool more_frags;
556 uint16_t frag_offset;
557
558 /* IPv4 header length - IPv4 only. */
559 uint8_t hlen = 0;
560
561 /* This is the offset of the start of the data in the packet that
562 * falls after the IP header. */
563 uint16_t data_offset;
564
565 /* The length of the (fragmented) data. This is the length of the
566 * data that falls after the IP header. */
567 uint16_t data_len;
568
569 /* Where the fragment ends. */
570 uint16_t frag_end;
571
572 /* Offset in the packet to the IPv6 header. */
573 uint16_t ip_hdr_offset;
574
575 /* Offset in the packet to the IPv6 frag header. IPv6 only. */
576 uint16_t frag_hdr_offset = 0;
577
578 /* Address family */
579 int af = tracker->af;
580
581 /* settings for updating a payload when an ip6 fragment with
582 * unfragmentable exthdrs are encountered. */
583 uint32_t ip6_nh_set_offset = 0;
584 uint8_t ip6_nh_set_value = 0;
585
586#ifdef DEBUG
587 uint64_t pcap_cnt = p->pcap_cnt;
588#endif
589
590 if (tracker->af == AF_INET) {
591 const IPV4Hdr *ip4h = PacketGetIPv4(p);
592 more_frags = IPV4_GET_RAW_FLAG_MF(ip4h);
593 frag_offset = (uint16_t)((uint16_t)IPV4_GET_RAW_FRAGOFFSET(ip4h) << (uint16_t)3);
594 hlen = IPV4_GET_RAW_HLEN(ip4h);
595 data_offset = (uint16_t)((uint8_t *)ip4h + hlen - GET_PKT_DATA(p));
596 data_len = IPV4_GET_RAW_IPLEN(ip4h) - hlen;
597 frag_end = frag_offset + data_len;
598 ip_hdr_offset = (uint16_t)((uint8_t *)ip4h - GET_PKT_DATA(p));
599
600 /* Ignore fragment if the end of packet extends past the
601 * maximum size of a packet. */
602 if (IPV4_HEADER_LEN + frag_offset + data_len > IPV4_MAXPACKET_LEN) {
604 return NULL;
605 }
606 }
607 else if (tracker->af == AF_INET6) {
608 const IPV6Hdr *ip6h = PacketGetIPv6(p);
609 more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
610 frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
611 data_offset = p->l3.vars.ip6.eh.fh_data_offset;
612 data_len = p->l3.vars.ip6.eh.fh_data_len;
613 frag_end = frag_offset + data_len;
614 ip_hdr_offset = (uint16_t)((uint8_t *)ip6h - GET_PKT_DATA(p));
615 frag_hdr_offset = p->l3.vars.ip6.eh.fh_header_offset;
616
617 SCLogDebug("mf %s frag_offset %u data_offset %u, data_len %u, "
618 "frag_end %u, ip_hdr_offset %u, frag_hdr_offset %u",
619 more_frags ? "true" : "false", frag_offset, data_offset,
620 data_len, frag_end, ip_hdr_offset, frag_hdr_offset);
621
622 /* handle unfragmentable exthdrs */
623 if (ip_hdr_offset + IPV6_HEADER_LEN < frag_hdr_offset) {
624 SCLogDebug("we have exthdrs before fraghdr %u bytes",
625 (uint32_t)(frag_hdr_offset - (ip_hdr_offset + IPV6_HEADER_LEN)));
626
627 /* get the offset of the 'next' field in exthdr before the FH,
628 * relative to the buffer start */
629
630 /* store offset and FH 'next' value for updating frag buffer below */
631 ip6_nh_set_offset = p->l3.vars.ip6.eh.fh_prev_hdr_offset;
632 ip6_nh_set_value = IPV6_EXTHDR_GET_FH_NH(p);
633 SCLogDebug("offset %d, value %u", ip6_nh_set_offset, ip6_nh_set_value);
634 }
635
636 /* Ignore fragment if the end of packet extends past the
637 * maximum size of a packet. */
638 if (frag_offset + data_len > IPV6_MAXPACKET) {
640 return NULL;
641 }
642 }
643 else {
645 return NULL;
646 }
647
648 /* Update timeout. */
649 tracker->timeout = SCTIME_FROM_SECS(SCTIME_SECS(p->ts) + tracker->host_timeout);
650
651 Frag *prev = NULL, *next = NULL;
652 bool overlap = false;
653 ltrim = 0;
654
655 if (!RB_EMPTY(&tracker->fragment_tree)) {
656 Frag key = {
657 .offset = frag_offset - 1,
658 };
659 next = RB_NFIND(IP_FRAGMENTS, &tracker->fragment_tree, &key);
660 if (next == NULL) {
661 prev = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
662 next = IP_FRAGMENTS_RB_NEXT(prev);
663 } else {
664 prev = IP_FRAGMENTS_RB_PREV(next);
665 if (prev == NULL) {
666 prev = next;
667 next = IP_FRAGMENTS_RB_NEXT(prev);
668 }
669 }
670 while (prev != NULL) {
671 if (prev->skip) {
672 goto next;
673 }
674 if (frag_offset < prev->offset + prev->data_len && prev->offset < frag_end) {
675 overlap = true;
676 }
677
678 switch (tracker->policy) {
680 if (frag_offset < prev->offset + prev->data_len) {
681 if (prev->offset <= frag_offset) {
682 /* We prefer the data from the previous
683 * fragment, so trim off the data in the new
684 * fragment that exists in the previous
685 * fragment. */
686 uint16_t prev_end = prev->offset + prev->data_len;
687 if (prev_end > frag_end) {
688 /* Just skip. */
689 /* TODO: Set overlap flag. */
690 goto done;
691 }
692 ltrim = prev_end - frag_offset;
693
694 if ((next != NULL) && (frag_end > next->offset)) {
695 next->ltrim = frag_end - next->offset;
696 }
697
698 goto insert;
699 }
700
701 /* If the end of this fragment overlaps the start
702 * of the previous fragment, then trim up the
703 * start of previous fragment so this fragment is
704 * used.
705 *
706 * See:
707 * DefragBsdSubsequentOverlapsStartOfOriginal.
708 */
709 if (frag_offset <= prev->offset && frag_end > prev->offset + prev->ltrim) {
710 uint16_t prev_ltrim = frag_end - prev->offset;
711 if (prev_ltrim > prev->ltrim) {
712 prev->ltrim = prev_ltrim;
713 }
714 }
715
716 if ((next != NULL) && (frag_end > next->offset)) {
717 next->ltrim = frag_end - next->offset;
718 }
719
720 goto insert;
721 }
722 break;
724 /* Check if new fragment overlaps the end of previous
725 * fragment, if it does, trim the new fragment.
726 *
727 * Old: AAAAAAAA AAAAAAAA AAAAAAAA
728 * New: BBBBBBBB BBBBBBBB BBBBBBBB
729 * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
730 */
731 if (prev->offset + prev->ltrim < frag_offset + ltrim &&
732 prev->offset + prev->data_len > frag_offset + ltrim) {
733 ltrim += prev->offset + prev->data_len - frag_offset;
734 }
735
736 /* Check if new fragment overlaps the beginning of
737 * previous fragment, if it does, tim the previous
738 * fragment.
739 *
740 * Old: AAAAAAAA AAAAAAAA
741 * New: BBBBBBBB BBBBBBBB BBBBBBBB
742 * Res: BBBBBBBB BBBBBBBB BBBBBBBB
743 */
744 if (frag_offset + ltrim < prev->offset + prev->ltrim &&
745 frag_end > prev->offset + prev->ltrim) {
746 prev->ltrim += frag_end - (prev->offset + prev->ltrim);
747 goto insert;
748 }
749
750 /* If the new fragment completely overlaps the
751 * previous fragment, mark the previous to be
752 * skipped. Re-assembly would succeed without doing
753 * this, but this will prevent the bytes from being
754 * copied just to be overwritten. */
755 if (frag_offset + ltrim <= prev->offset + prev->ltrim &&
756 frag_end >= prev->offset + prev->data_len) {
757 prev->skip = 1;
758 goto insert;
759 }
760
761 break;
763 /* If new fragment fits inside a previous fragment, drop it. */
764 if (frag_offset + ltrim >= prev->offset + ltrim &&
765 frag_end <= prev->offset + prev->data_len) {
766 goto done;
767 }
768
769 /* If new fragment starts before and ends after
770 * previous fragment, drop the previous fragment. */
771 if (frag_offset + ltrim < prev->offset + ltrim &&
772 frag_end > prev->offset + prev->data_len) {
773 prev->skip = 1;
774 goto insert;
775 }
776
777 /* Check if new fragment overlaps the end of previous
778 * fragment, if it does, trim the new fragment.
779 *
780 * Old: AAAAAAAA AAAAAAAA AAAAAAAA
781 * New: BBBBBBBB BBBBBBBB BBBBBBBB
782 * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
783 */
784 if (frag_offset + ltrim > prev->offset + prev->ltrim &&
785 frag_offset + ltrim < prev->offset + prev->data_len) {
786 ltrim += prev->offset + prev->data_len - frag_offset;
787 goto insert;
788 }
789
790 /* If new fragment starts at same offset as an
791 * existing fragment, but ends after it, trim the new
792 * fragment. */
793 if (frag_offset + ltrim == prev->offset + ltrim &&
794 frag_end > prev->offset + prev->data_len) {
795 ltrim += prev->offset + prev->data_len - frag_offset;
796 goto insert;
797 }
798 break;
800 if (frag_offset < prev->offset + prev->data_len) {
801 if (frag_offset >= prev->offset) {
802 ltrim = prev->offset + prev->data_len - frag_offset;
803 }
804 if ((frag_offset < prev->offset) &&
805 (frag_end >= prev->offset + prev->data_len)) {
806 prev->skip = 1;
807 }
808 goto insert;
809 }
810 break;
812 if ((frag_offset >= prev->offset) &&
813 (frag_end <= prev->offset + prev->data_len)) {
814 goto done;
815 }
816 if (frag_offset < prev->offset) {
817 goto insert;
818 }
819 if (frag_offset < prev->offset + prev->data_len) {
820 ltrim = prev->offset + prev->data_len - frag_offset;
821 goto insert;
822 }
823 break;
825 if (frag_offset <= prev->offset) {
826 if (frag_end > prev->offset) {
827 prev->ltrim = frag_end - prev->offset;
828 }
829 goto insert;
830 }
831 break;
832 default:
833 break;
834 }
835
836 next:
837 prev = next;
838 if (next != NULL) {
839 next = IP_FRAGMENTS_RB_NEXT(next);
840 }
841 continue;
842
843 insert:
844 /* If existing fragment has been trimmed up completely
845 * (complete overlap), remove it now instead of holding
846 * onto it. */
847 if (prev->skip || prev->ltrim >= prev->data_len) {
848 RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, prev);
849 DefragFragReset(prev);
850 SCMutexLock(&defrag_context->frag_pool_lock);
851 PoolReturn(defrag_context->frag_pool, prev);
852 SCMutexUnlock(&defrag_context->frag_pool_lock);
853 }
854 break;
855 }
856 }
857
858 if (ltrim >= data_len) {
859 /* Full packet has been trimmed due to the overlap policy. Overlap
860 * already set. */
861 goto done;
862 }
863
864 /* Allocate fragment and insert. */
865 SCMutexLock(&defrag_context->frag_pool_lock);
866 Frag *new = PoolGet(defrag_context->frag_pool);
867 SCMutexUnlock(&defrag_context->frag_pool_lock);
868 if (new == NULL) {
869 if (af == AF_INET) {
871 } else {
873 }
874 if (tv != NULL && dtv != NULL) {
876 }
877 goto error_remove_tracker;
878 }
879 new->pkt = SCMalloc(GET_PKT_LEN(p));
880 if (new->pkt == NULL) {
881 SCMutexLock(&defrag_context->frag_pool_lock);
882 PoolReturn(defrag_context->frag_pool, new);
883 SCMutexUnlock(&defrag_context->frag_pool_lock);
884 if (af == AF_INET) {
886 } else {
888 }
889 goto error_remove_tracker;
890 }
891 memcpy(new->pkt, GET_PKT_DATA(p) + ltrim, GET_PKT_LEN(p) - ltrim);
892 new->len = (GET_PKT_LEN(p) - ltrim);
893 /* in case of unfragmentable exthdrs, update the 'next hdr' field
894 * in the raw buffer so the reassembled packet will point to the
895 * correct next header after stripping the frag header */
896 if (ip6_nh_set_offset > 0 && frag_offset == 0 && ltrim == 0) {
897 if (new->len > ip6_nh_set_offset) {
898 SCLogDebug("updating frag to have 'correct' nh value: %u -> %u",
899 new->pkt[ip6_nh_set_offset], ip6_nh_set_value);
900 new->pkt[ip6_nh_set_offset] = ip6_nh_set_value;
901 }
902 }
903
904 new->hlen = hlen;
905 new->offset = frag_offset + ltrim;
906 new->data_offset = data_offset;
907 new->data_len = data_len - ltrim;
908 new->frag_hdr_offset = frag_hdr_offset;
909 new->more_frags = more_frags;
910#ifdef DEBUG
911 new->pcap_cnt = pcap_cnt;
912#endif
913 if (new->offset == 0) {
914 tracker->ip_hdr_offset = ip_hdr_offset;
915 tracker->datalink = p->datalink;
916 }
917
918 IP_FRAGMENTS_RB_INSERT(&tracker->fragment_tree, new);
919
920 if (!more_frags) {
921 tracker->seen_last = 1;
922 }
923
924 if (tracker->seen_last) {
925 if (tracker->af == AF_INET) {
926 r = Defrag4Reassemble(tv, tracker, p);
927 if (r != NULL && tv != NULL && dtv != NULL) {
929 const uint32_t len = GET_PKT_LEN(r) - (uint32_t)tracker->ip_hdr_offset;
930 DEBUG_VALIDATE_BUG_ON(len > UINT16_MAX);
931 if (DecodeIPV4(tv, dtv, r, GET_PKT_DATA(r) + tracker->ip_hdr_offset,
932 (uint16_t)len) != TM_ECODE_OK) {
933 r->root = NULL;
935 r = NULL;
936 } else {
938 }
939 }
940 }
941 else if (tracker->af == AF_INET6) {
942 r = Defrag6Reassemble(tv, tracker, p);
943 if (r != NULL && tv != NULL && dtv != NULL) {
945 const uint32_t len = GET_PKT_LEN(r) - (uint32_t)tracker->ip_hdr_offset;
946 DEBUG_VALIDATE_BUG_ON(len > UINT16_MAX);
947 if (DecodeIPV6(tv, dtv, r, GET_PKT_DATA(r) + tracker->ip_hdr_offset,
948 (uint16_t)len) != TM_ECODE_OK) {
949 r->root = NULL;
951 r = NULL;
952 } else {
954 }
955 }
956 }
957 }
958
959
960done:
961 if (overlap) {
962 if (af == AF_INET) {
964 }
965 else {
967 }
968 }
969 return r;
970error_remove_tracker:
971 tracker->remove = 1;
972 DefragTrackerFreeFrags(tracker);
973 return NULL;
974}
975
976/**
977 * \brief Get the defrag policy based on the destination address of
978 * the packet.
979 *
980 * \param p The packet used to get the destination address.
981 *
982 * \retval The defrag policy to use.
983 */
984uint8_t
986{
987 int policy = -1;
988
989 if (PacketIsIPv4(p)) {
991 } else if (PacketIsIPv6(p)) {
992 policy = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
993 }
994
995 if (policy == -1) {
996 return default_policy;
997 }
998
999 /* Map the OS policies returned from the configured host info to
1000 * defrag specific policies. */
1001 switch (policy) {
1002 /* BSD. */
1003 case OS_POLICY_BSD:
1004 case OS_POLICY_HPUX10:
1005 case OS_POLICY_IRIX:
1006 return DEFRAG_POLICY_BSD;
1007
1008 /* BSD-Right. */
1011
1012 /* Linux. */
1014 case OS_POLICY_LINUX:
1015 return DEFRAG_POLICY_LINUX;
1016
1017 /* First. */
1019 case OS_POLICY_HPUX11:
1020 case OS_POLICY_MACOS:
1021 case OS_POLICY_FIRST:
1022 return DEFRAG_POLICY_FIRST;
1023
1024 /* Solaris. */
1025 case OS_POLICY_SOLARIS:
1026 return DEFRAG_POLICY_SOLARIS;
1027
1028 /* Windows. */
1029 case OS_POLICY_WINDOWS:
1030 case OS_POLICY_VISTA:
1032 return DEFRAG_POLICY_WINDOWS;
1033
1034 /* Last. */
1035 case OS_POLICY_LAST:
1036 return DEFRAG_POLICY_LAST;
1037
1038 default:
1039 return default_policy;
1040 }
1041}
1042
1043/** \internal
1044 *
1045 * \retval NULL or a *LOCKED* tracker */
1046static DefragTracker *
1047DefragGetTracker(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
1048{
1049 return DefragGetTrackerFromHash(tv, dtv, p);
1050}
1051
1052/**
1053 * \brief Entry point for IPv4 and IPv6 fragments.
1054 *
1055 * \param tv ThreadVars for the calling decoder.
1056 * \param p The packet fragment.
1057 *
1058 * \retval A new Packet resembling the re-assembled packet if the most
1059 * recent fragment allowed the packet to be re-assembled, otherwise
1060 * NULL is returned.
1061 */
1062Packet *
1064{
1065 uint16_t frag_offset;
1066 uint8_t more_frags;
1067 DefragTracker *tracker;
1068 int af;
1069
1070 if (PacketIsIPv4(p)) {
1071 const IPV4Hdr *ip4h = PacketGetIPv4(p);
1072 af = AF_INET;
1073 more_frags = IPV4_GET_RAW_FLAG_MF(ip4h);
1074 frag_offset = IPV4_GET_RAW_FRAGOFFSET(ip4h);
1075 } else if (PacketIsIPv6(p)) {
1076 af = AF_INET6;
1077 frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
1078 more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
1079 } else {
1080 return NULL;
1081 }
1082
1083 if (frag_offset == 0 && more_frags == 0) {
1084 return NULL;
1085 }
1086
1087 if (af == AF_INET) {
1089 } else if (af == AF_INET6) {
1091 }
1092
1093 /* return a locked tracker or NULL */
1094 tracker = DefragGetTracker(tv, dtv, p);
1095 if (tracker == NULL) {
1096 if (tv != NULL && dtv != NULL) {
1098 }
1099 return NULL;
1100 }
1101
1102 Packet *rp = DefragInsertFrag(tv, dtv, tracker, p);
1103 DefragTrackerRelease(tracker);
1104
1105 return rp;
1106}
1107
1108void
1110{
1111 intmax_t tracker_pool_size;
1112 if (!SCConfGetInt("defrag.trackers", &tracker_pool_size)) {
1113 tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
1114 }
1115
1116 /* Load the defrag-per-host lookup. */
1118
1119 /* Allocate the DefragContext. */
1120 defrag_context = DefragContextNew();
1121 if (defrag_context == NULL) {
1122 FatalError("Failed to allocate memory for the Defrag module.");
1123 }
1124
1125 DefragSetDefaultTimeout(defrag_context->timeout);
1126 DefragInitConfig(false);
1127}
1128
1130{
1132 DefragContextDestroy(defrag_context);
1133 defrag_context = NULL;
1135}
1136
1137#ifdef UNITTESTS
1138#include "util-unittest-helper.h"
1139#include "packet.h"
1140
1141#define IP_MF 0x2000
1142
1145
1146/**
1147 * Allocate a test packet. Nothing to fancy, just a simple IP packet
1148 * with some payload of no particular protocol.
1149 */
1150static Packet *BuildIpv4TestPacket(
1151 uint8_t proto, uint16_t id, uint16_t off, int mf, const char content, int content_len)
1152{
1153 Packet *p = NULL;
1154 int hlen = 20;
1155 int ttl = 64;
1156 uint8_t *pcontent;
1157 IPV4Hdr ip4h;
1158
1159 p = SCCalloc(1, sizeof(*p) + default_packet_size);
1160 if (unlikely(p == NULL))
1161 return NULL;
1162
1163 PacketInit(p);
1164
1165 struct timeval tval;
1166 gettimeofday(&tval, NULL);
1167 p->ts = SCTIME_FROM_TIMEVAL(&tval);
1168 //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1169 ip4h.ip_verhl = 4 << 4;
1170 ip4h.ip_verhl |= hlen >> 2;
1171 ip4h.ip_len = htons(hlen + content_len);
1172 ip4h.ip_id = htons(id);
1173 if (mf)
1174 ip4h.ip_off = htons(IP_MF | off);
1175 else
1176 ip4h.ip_off = htons(off);
1177 ip4h.ip_ttl = ttl;
1178 ip4h.ip_proto = proto;
1179
1180 ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1181 ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1182
1183 /* copy content_len crap, we need full length */
1184 PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1185 IPV4Hdr *ip4p = PacketSetIPV4(p, GET_PKT_DATA(p));
1186 SET_IPV4_SRC_ADDR(ip4p, &p->src);
1187 SET_IPV4_DST_ADDR(ip4p, &p->dst);
1188
1189 pcontent = SCCalloc(1, content_len);
1190 if (unlikely(pcontent == NULL))
1191 return NULL;
1192 memset(pcontent, content, content_len);
1193 PacketCopyDataOffset(p, hlen, pcontent, content_len);
1194 SET_PKT_LEN(p, hlen + content_len);
1195 SCFree(pcontent);
1196
1197 ip4p->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1198
1199 /* Self test. */
1200 FAIL_IF(IPV4_GET_RAW_VER(ip4p) != 4);
1201 FAIL_IF(IPV4_GET_RAW_HLEN(ip4p) != hlen);
1202 FAIL_IF(IPV4_GET_RAW_IPLEN(ip4p) != hlen + content_len);
1203 FAIL_IF(IPV4_GET_RAW_IPID(ip4p) != id);
1204 FAIL_IF(IPV4_GET_RAW_FRAGOFFSET(ip4p) != off);
1205 FAIL_IF(IPV4_GET_RAW_FLAG_MF(ip4p) != mf);
1206 FAIL_IF(IPV4_GET_RAW_IPTTL(ip4p) != ttl);
1208
1209 return p;
1210}
1211
1212/**
1213 * Allocate a test packet, much like BuildIpv4TestPacket, but with
1214 * the full content provided by the caller.
1215 */
1216static int BuildIpv4TestPacketWithContent(Packet **packet, uint8_t proto, uint16_t id, uint16_t off,
1217 int mf, const uint8_t *content, int content_len)
1218{
1219 Packet *p = NULL;
1220 int hlen = 20;
1221 int ttl = 64;
1222 IPV4Hdr ip4h;
1223
1224 p = SCCalloc(1, sizeof(*p) + default_packet_size);
1225 FAIL_IF_NULL(p);
1226
1227 PacketInit(p);
1228
1229 struct timeval tval;
1230 gettimeofday(&tval, NULL);
1231 p->ts = SCTIME_FROM_TIMEVAL(&tval);
1232 ip4h.ip_verhl = 4 << 4;
1233 ip4h.ip_verhl |= hlen >> 2;
1234 ip4h.ip_len = htons(hlen + content_len);
1235 ip4h.ip_id = htons(id);
1236 if (mf)
1237 ip4h.ip_off = htons(IP_MF | off);
1238 else
1239 ip4h.ip_off = htons(off);
1240 ip4h.ip_ttl = ttl;
1241 ip4h.ip_proto = proto;
1242
1243 ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1244 ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1245
1246 /* copy content_len crap, we need full length */
1247 PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1248 IPV4Hdr *ip4p = PacketSetIPV4(p, GET_PKT_DATA(p));
1249 SET_IPV4_SRC_ADDR(ip4p, &p->src);
1250 SET_IPV4_DST_ADDR(ip4p, &p->dst);
1251
1252 PacketCopyDataOffset(p, hlen, content, content_len);
1253 SET_PKT_LEN(p, hlen + content_len);
1254
1255 ip4p->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1256
1257 /* Self test. */
1258 FAIL_IF(IPV4_GET_RAW_VER(ip4p) != 4);
1259 FAIL_IF(IPV4_GET_RAW_HLEN(ip4p) != hlen);
1260 FAIL_IF(IPV4_GET_RAW_IPLEN(ip4p) != hlen + content_len);
1261 FAIL_IF(IPV4_GET_RAW_IPID(ip4p) != id);
1262 FAIL_IF(IPV4_GET_RAW_FRAGOFFSET(ip4p) != off);
1263 FAIL_IF(IPV4_GET_RAW_FLAG_MF(ip4p) != mf);
1264 FAIL_IF(IPV4_GET_RAW_IPTTL(ip4p) != ttl);
1266
1267 *packet = p;
1268 PASS;
1269}
1270
1271static Packet *BuildIpv6TestPacket(
1272 uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t content, int content_len)
1273{
1274 Packet *p = NULL;
1275 uint8_t *pcontent;
1276 IPV6Hdr ip6h;
1277
1278 p = SCCalloc(1, sizeof(*p) + default_packet_size);
1279 if (unlikely(p == NULL))
1280 return NULL;
1281
1282 PacketInit(p);
1283
1284 struct timeval tval;
1285 gettimeofday(&tval, NULL);
1286 p->ts = SCTIME_FROM_TIMEVAL(&tval);
1287
1288 ip6h.s_ip6_nxt = 44;
1289 ip6h.s_ip6_hlim = 2;
1290
1291 /* Source and dest address - very bogus addresses. */
1292 ip6h.s_ip6_src[0] = 0x01010101;
1293 ip6h.s_ip6_src[1] = 0x01010101;
1294 ip6h.s_ip6_src[2] = 0x01010101;
1295 ip6h.s_ip6_src[3] = 0x01010101;
1296 ip6h.s_ip6_dst[0] = 0x02020202;
1297 ip6h.s_ip6_dst[1] = 0x02020202;
1298 ip6h.s_ip6_dst[2] = 0x02020202;
1299 ip6h.s_ip6_dst[3] = 0x02020202;
1300
1301 /* copy content_len crap, we need full length */
1302 PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1303
1304 IPV6Hdr *ip6p = PacketSetIPV6(p, GET_PKT_DATA(p));
1305 IPV6_SET_RAW_VER(ip6p, 6);
1306 /* Fragmentation header. */
1307 IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1308 fh->ip6fh_nxt = proto;
1309 fh->ip6fh_ident = htonl(id);
1310 fh->ip6fh_offlg = htons((off << 3) | mf);
1311
1312 DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1313
1314 pcontent = SCCalloc(1, content_len);
1315 if (unlikely(pcontent == NULL))
1316 return NULL;
1317 memset(pcontent, content, content_len);
1318 PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), pcontent, content_len);
1319 SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1320 SCFree(pcontent);
1321
1322 ip6p->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1323
1324 SET_IPV6_SRC_ADDR(ip6p, &p->src);
1325 SET_IPV6_DST_ADDR(ip6p, &p->dst);
1326
1327 /* Self test. */
1328 if (IPV6_GET_RAW_VER(ip6p) != 6)
1329 goto error;
1330 if (IPV6_GET_RAW_NH(ip6p) != 44)
1331 goto error;
1332 if (IPV6_GET_RAW_PLEN(ip6p) != sizeof(IPV6FragHdr) + content_len)
1333 goto error;
1334
1335 return p;
1336error:
1337 if (p != NULL)
1338 SCFree(p);
1339 return NULL;
1340}
1341
1342static Packet *BuildIpv6TestPacketWithContent(
1343 uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t *content, int content_len)
1344{
1345 Packet *p = NULL;
1346 IPV6Hdr ip6h;
1347
1348 p = SCCalloc(1, sizeof(*p) + default_packet_size);
1349 if (unlikely(p == NULL))
1350 return NULL;
1351
1352 PacketInit(p);
1353
1354 struct timeval tval;
1355 gettimeofday(&tval, NULL);
1356 p->ts = SCTIME_FROM_TIMEVAL(&tval);
1357
1358 ip6h.s_ip6_nxt = 44;
1359 ip6h.s_ip6_hlim = 2;
1360
1361 /* Source and dest address - very bogus addresses. */
1362 ip6h.s_ip6_src[0] = 0x01010101;
1363 ip6h.s_ip6_src[1] = 0x01010101;
1364 ip6h.s_ip6_src[2] = 0x01010101;
1365 ip6h.s_ip6_src[3] = 0x01010101;
1366 ip6h.s_ip6_dst[0] = 0x02020202;
1367 ip6h.s_ip6_dst[1] = 0x02020202;
1368 ip6h.s_ip6_dst[2] = 0x02020202;
1369 ip6h.s_ip6_dst[3] = 0x02020202;
1370
1371 /* copy content_len crap, we need full length */
1372 PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1373
1374 IPV6Hdr *ip6p = PacketSetIPV6(p, GET_PKT_DATA(p));
1375 IPV6_SET_RAW_VER(ip6p, 6);
1376 /* Fragmentation header. */
1377 IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1378 fh->ip6fh_nxt = proto;
1379 fh->ip6fh_ident = htonl(id);
1380 fh->ip6fh_offlg = htons((off << 3) | mf);
1381
1382 DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1383
1384 PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), content, content_len);
1385 SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1386
1387 ip6p->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1388
1389 SET_IPV6_SRC_ADDR(ip6p, &p->src);
1390 SET_IPV6_DST_ADDR(ip6p, &p->dst);
1391
1392 /* Self test. */
1393 if (IPV6_GET_RAW_VER(ip6p) != 6)
1394 goto error;
1395 if (IPV6_GET_RAW_NH(ip6p) != 44)
1396 goto error;
1397 if (IPV6_GET_RAW_PLEN(ip6p) != sizeof(IPV6FragHdr) + content_len)
1398 goto error;
1399
1400 return p;
1401error:
1402 if (p != NULL)
1403 SCFree(p);
1404 return NULL;
1405}
1406
1407/**
1408 * Test the simplest possible re-assembly scenario. All packet in
1409 * order and no overlaps.
1410 */
1411static int DefragInOrderSimpleTest(void)
1412{
1413 Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1414 Packet *reassembled = NULL;
1415 int id = 12;
1416
1417 DefragInit();
1418
1419 p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1420 FAIL_IF_NULL(p1);
1421 p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1422 FAIL_IF_NULL(p2);
1423 p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1424 FAIL_IF_NULL(p3);
1425
1426 FAIL_IF(Defrag(&test_tv, &test_dtv, p1) != NULL);
1427 FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1428
1429 reassembled = Defrag(&test_tv, &test_dtv, p3);
1430 FAIL_IF_NULL(reassembled);
1431
1432 FAIL_IF(IPV4_GET_RAW_HLEN(PacketGetIPv4(reassembled)) != 20);
1433 FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(reassembled)) != 39);
1434
1435 /* 20 bytes in we should find 8 bytes of A. */
1436 for (int i = 20; i < 20 + 8; i++) {
1437 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1438 }
1439
1440 /* 28 bytes in we should find 8 bytes of B. */
1441 for (int i = 28; i < 28 + 8; i++) {
1442 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1443 }
1444
1445 /* And 36 bytes in we should find 3 bytes of C. */
1446 for (int i = 36; i < 36 + 3; i++) {
1447 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1448 }
1449
1450 SCFree(p1);
1451 SCFree(p2);
1452 SCFree(p3);
1453 SCFree(reassembled);
1454
1455 DefragDestroy();
1456 PASS;
1457}
1458
1459/**
1460 * Simple fragmented packet in reverse order.
1461 */
1462static int DefragReverseSimpleTest(void)
1463{
1464 Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1465 Packet *reassembled = NULL;
1466 int id = 12;
1467
1468 DefragInit();
1469
1470 p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1471 FAIL_IF_NULL(p1);
1472 p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1473 FAIL_IF_NULL(p2);
1474 p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1475 FAIL_IF_NULL(p3);
1476
1477 FAIL_IF(Defrag(&test_tv, &test_dtv, p3) != NULL);
1478 FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1479 reassembled = Defrag(&test_tv, &test_dtv, p1);
1480 FAIL_IF_NULL(reassembled);
1481
1482 FAIL_IF(IPV4_GET_RAW_HLEN(PacketGetIPv4(reassembled)) != 20);
1483 FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(reassembled)) != 39);
1484
1485 /* 20 bytes in we should find 8 bytes of A. */
1486 for (int i = 20; i < 20 + 8; i++) {
1487 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1488 }
1489
1490 /* 28 bytes in we should find 8 bytes of B. */
1491 for (int i = 28; i < 28 + 8; i++) {
1492 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1493 }
1494
1495 /* And 36 bytes in we should find 3 bytes of C. */
1496 for (int i = 36; i < 36 + 3; i++) {
1497 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1498 }
1499
1500 SCFree(p1);
1501 SCFree(p2);
1502 SCFree(p3);
1503 SCFree(reassembled);
1504
1505 DefragDestroy();
1506 PASS;
1507}
1508
1509/**
1510 * Test the simplest possible re-assembly scenario. All packet in
1511 * order and no overlaps.
1512 */
1513static int DefragInOrderSimpleIpv6Test(void)
1514{
1515 Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1516 Packet *reassembled = NULL;
1517 int id = 12;
1518
1519 DefragInit();
1520
1521 p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1522 FAIL_IF_NULL(p1);
1523 p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1524 FAIL_IF_NULL(p2);
1525 p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1526 FAIL_IF_NULL(p3);
1527
1528 FAIL_IF(Defrag(&test_tv, &test_dtv, p1) != NULL);
1529 FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1530 reassembled = Defrag(&test_tv, &test_dtv, p3);
1531 FAIL_IF_NULL(reassembled);
1532
1533 const IPV6Hdr *ip6h = PacketGetIPv6(reassembled);
1534 FAIL_IF(IPV6_GET_RAW_PLEN(ip6h) != 19);
1535
1536 /* 40 bytes in we should find 8 bytes of A. */
1537 for (int i = 40; i < 40 + 8; i++) {
1538 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1539 }
1540
1541 /* 28 bytes in we should find 8 bytes of B. */
1542 for (int i = 48; i < 48 + 8; i++) {
1543 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1544 }
1545
1546 /* And 36 bytes in we should find 3 bytes of C. */
1547 for (int i = 56; i < 56 + 3; i++) {
1548 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1549 }
1550
1551 SCFree(p1);
1552 SCFree(p2);
1553 SCFree(p3);
1554 SCFree(reassembled);
1555
1556 DefragDestroy();
1557 PASS;
1558}
1559
1560static int DefragReverseSimpleIpv6Test(void)
1561{
1562 DefragContext *dc = NULL;
1563 Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1564 Packet *reassembled = NULL;
1565 int id = 12;
1566
1567 DefragInit();
1568
1569 dc = DefragContextNew();
1570 FAIL_IF_NULL(dc);
1571
1572 p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1573 FAIL_IF_NULL(p1);
1574 p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1575 FAIL_IF_NULL(p2);
1576 p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1577 FAIL_IF_NULL(p3);
1578
1579 FAIL_IF(Defrag(&test_tv, &test_dtv, p3) != NULL);
1580 FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1581 reassembled = Defrag(&test_tv, &test_dtv, p1);
1582 FAIL_IF_NULL(reassembled);
1583
1584 /* 40 bytes in we should find 8 bytes of A. */
1585 for (int i = 40; i < 40 + 8; i++) {
1586 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1587 }
1588
1589 /* 28 bytes in we should find 8 bytes of B. */
1590 for (int i = 48; i < 48 + 8; i++) {
1591 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1592 }
1593
1594 /* And 36 bytes in we should find 3 bytes of C. */
1595 for (int i = 56; i < 56 + 3; i++) {
1596 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1597 }
1598
1599 DefragContextDestroy(dc);
1600 SCFree(p1);
1601 SCFree(p2);
1602 SCFree(p3);
1603 SCFree(reassembled);
1604
1605 DefragDestroy();
1606 PASS;
1607}
1608
1609static int DefragDoSturgesNovakTest(int policy, uint8_t *expected, size_t expected_len)
1610{
1611 int i;
1612
1613 DefragInit();
1614
1615 /*
1616 * Build the packets.
1617 */
1618
1619 int id = 1;
1620 Packet *packets[17];
1621 memset(packets, 0x00, sizeof(packets));
1622
1623 /*
1624 * Original fragments.
1625 */
1626
1627 /* <1> A*24 at 0. */
1628 packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
1629
1630 /* <2> B*16 at 32. */
1631 packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
1632
1633 /* <3> C*24 at 48. */
1634 packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
1635
1636 /* <3_1> D*8 at 80. */
1637 packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
1638
1639 /* <3_2> E*16 at 104. */
1640 packets[4] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
1641
1642 /* <3_3> F*24 at 120. */
1643 packets[5] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
1644
1645 /* <3_4> G*16 at 144. */
1646 packets[6] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
1647
1648 /* <3_5> H*16 at 160. */
1649 packets[7] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
1650
1651 /* <3_6> I*8 at 176. */
1652 packets[8] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
1653
1654 /*
1655 * Overlapping subsequent fragments.
1656 */
1657
1658 /* <4> J*32 at 8. */
1659 packets[9] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
1660
1661 /* <5> K*24 at 48. */
1662 packets[10] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
1663
1664 /* <6> L*24 at 72. */
1665 packets[11] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
1666
1667 /* <7> M*24 at 96. */
1668 packets[12] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
1669
1670 /* <8> N*8 at 128. */
1671 packets[13] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
1672
1673 /* <9> O*8 at 152. */
1674 packets[14] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
1675
1676 /* <10> P*8 at 160. */
1677 packets[15] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
1678
1679 /* <11> Q*16 at 176. */
1680 packets[16] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
1681
1682 default_policy = policy;
1683
1684 /* Send all but the last. */
1685 for (i = 0; i < 9; i++) {
1686 Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
1687 FAIL_IF_NOT_NULL(tp);
1689 }
1690 int overlap = 0;
1691 for (; i < 16; i++) {
1692 Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
1693 FAIL_IF_NOT_NULL(tp);
1694 if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) {
1695 overlap++;
1696 }
1697 }
1698 FAIL_IF_NOT(overlap);
1699
1700 /* And now the last one. */
1701 Packet *reassembled = Defrag(&test_tv, &test_dtv, packets[16]);
1702 FAIL_IF_NULL(reassembled);
1703
1704 FAIL_IF(IPV4_GET_RAW_HLEN(PacketGetIPv4(reassembled)) != 20);
1705 FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(reassembled)) != 20 + 192);
1706 FAIL_IF(expected_len != 192);
1707
1708 if (memcmp(expected, GET_PKT_DATA(reassembled) + 20, expected_len) != 0) {
1709 printf("Expected:\n");
1710 PrintRawDataFp(stdout, expected, expected_len);
1711 printf("Got:\n");
1712 PrintRawDataFp(stdout, GET_PKT_DATA(reassembled) + 20, GET_PKT_LEN(reassembled) - 20);
1713 FAIL;
1714 }
1715 SCFree(reassembled);
1716
1717 /* Make sure all frags were returned back to the pool. */
1718 FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1719
1720 for (i = 0; i < 17; i++) {
1721 SCFree(packets[i]);
1722 }
1723 DefragDestroy();
1724 PASS;
1725}
1726
1727static int DefragDoSturgesNovakIpv6Test(int policy, uint8_t *expected, size_t expected_len)
1728{
1729 int i;
1730
1731 DefragInit();
1732
1733 /*
1734 * Build the packets.
1735 */
1736
1737 int id = 1;
1738 Packet *packets[17];
1739 memset(packets, 0x00, sizeof(packets));
1740
1741 /*
1742 * Original fragments.
1743 */
1744
1745 /* <1> A*24 at 0. */
1746 packets[0] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
1747
1748 /* <2> B*16 at 32. */
1749 packets[1] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
1750
1751 /* <3> C*24 at 48. */
1752 packets[2] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
1753
1754 /* <3_1> D*8 at 80. */
1755 packets[3] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
1756
1757 /* <3_2> E*16 at 104. */
1758 packets[4] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
1759
1760 /* <3_3> F*24 at 120. */
1761 packets[5] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
1762
1763 /* <3_4> G*16 at 144. */
1764 packets[6] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
1765
1766 /* <3_5> H*16 at 160. */
1767 packets[7] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
1768
1769 /* <3_6> I*8 at 176. */
1770 packets[8] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
1771
1772 /*
1773 * Overlapping subsequent fragments.
1774 */
1775
1776 /* <4> J*32 at 8. */
1777 packets[9] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
1778
1779 /* <5> K*24 at 48. */
1780 packets[10] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
1781
1782 /* <6> L*24 at 72. */
1783 packets[11] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
1784
1785 /* <7> M*24 at 96. */
1786 packets[12] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
1787
1788 /* <8> N*8 at 128. */
1789 packets[13] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
1790
1791 /* <9> O*8 at 152. */
1792 packets[14] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
1793
1794 /* <10> P*8 at 160. */
1795 packets[15] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
1796
1797 /* <11> Q*16 at 176. */
1798 packets[16] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
1799
1800 default_policy = policy;
1801
1802 /* Send all but the last. */
1803 for (i = 0; i < 9; i++) {
1804 Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
1805 FAIL_IF_NOT_NULL(tp);
1807 }
1808 int overlap = 0;
1809 for (; i < 16; i++) {
1810 Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
1811 FAIL_IF_NOT_NULL(tp);
1812 if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) {
1813 overlap++;
1814 }
1815 }
1816 FAIL_IF_NOT(overlap);
1817
1818 /* And now the last one. */
1819 Packet *reassembled = Defrag(&test_tv, &test_dtv, packets[16]);
1820 FAIL_IF_NULL(reassembled);
1821 FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0);
1822
1823 FAIL_IF(IPV6_GET_RAW_PLEN(PacketGetIPv6(reassembled)) != 192);
1824
1825 SCFree(reassembled);
1826
1827 /* Make sure all frags were returned to the pool. */
1828 FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1829
1830 for (i = 0; i < 17; i++) {
1831 SCFree(packets[i]);
1832 }
1833 DefragDestroy();
1834 PASS;
1835}
1836
1837/* Define data that matches the naming "Target-Based Fragmentation
1838 * Reassembly".
1839 *
1840 * For example, the data refers to a fragment of data as <1>, or <3_6>
1841 * and uses these to diagram the input fragments and the resulting
1842 * policies. We build test cases for the papers scenario but assign
1843 * specific values to each segment.
1844 */
1845#define D_1 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'
1846#define D_2 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B'
1847#define D_3 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C'
1848#define D_3_1 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D'
1849#define D_3_2 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E'
1850#define D_3_3 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F'
1851#define D_3_4 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G'
1852#define D_3_5 'H', 'H', 'H', 'H', 'H', 'H', 'H', 'H'
1853#define D_3_6 'I', 'I', 'I', 'I', 'I', 'I', 'I', 'I'
1854#define D_4 'J', 'J', 'J', 'J', 'J', 'J', 'J', 'J'
1855#define D_5 'K', 'K', 'K', 'K', 'K', 'K', 'K', 'K'
1856#define D_6 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
1857#define D_7 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M'
1858#define D_8 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'
1859#define D_9 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'
1860#define D_10 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'
1861#define D_11 'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q'
1862
1863static int
1864DefragSturgesNovakBsdTest(void)
1865{
1866 /* Expected data. */
1867 uint8_t expected[] = {
1868 D_1,
1869 D_1,
1870 D_1,
1871 D_4,
1872 D_4,
1873 D_2,
1874 D_3,
1875 D_3,
1876 D_3,
1877 D_6,
1878 D_6,
1879 D_6,
1880 D_7,
1881 D_7,
1882 D_7,
1883 D_3_3,
1884 D_3_3,
1885 D_3_3,
1886 D_3_4,
1887 D_3_4,
1888 D_3_5,
1889 D_3_5,
1890 D_3_6,
1891 D_11,
1892 };
1893
1894 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1895 sizeof(expected)));
1896 PASS;
1897}
1898
1899static int DefragSturgesNovakBsdIpv6Test(void)
1900{
1901 /* Expected data. */
1902 uint8_t expected[] = {
1903 D_1,
1904 D_1,
1905 D_1,
1906 D_4,
1907 D_4,
1908 D_2,
1909 D_3,
1910 D_3,
1911 D_3,
1912 D_6,
1913 D_6,
1914 D_6,
1915 D_7,
1916 D_7,
1917 D_7,
1918 D_3_3,
1919 D_3_3,
1920 D_3_3,
1921 D_3_4,
1922 D_3_4,
1923 D_3_5,
1924 D_3_5,
1925 D_3_6,
1926 D_11,
1927 };
1928
1929 FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_BSD, expected, sizeof(expected)));
1930 PASS;
1931}
1932
1933static int DefragSturgesNovakLinuxIpv4Test(void)
1934{
1935 /* Expected data. */
1936 uint8_t expected[] = {
1937 D_1,
1938 D_1,
1939 D_1,
1940 D_4,
1941 D_4,
1942 D_2,
1943 D_5,
1944 D_5,
1945 D_5,
1946 D_6,
1947 D_6,
1948 D_6,
1949 D_7,
1950 D_7,
1951 D_7,
1952 D_3_3,
1953 D_3_3,
1954 D_3_3,
1955 D_3_4,
1956 D_3_4,
1957 D_10,
1958 D_3_5,
1959 D_11,
1960 D_11,
1961 };
1962
1963 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1964 sizeof(expected)));
1965 PASS;
1966}
1967
1968static int DefragSturgesNovakLinuxIpv6Test(void)
1969{
1970 /* Expected data. */
1971 uint8_t expected[] = {
1972 D_1,
1973 D_1,
1974 D_1,
1975 D_4,
1976 D_4,
1977 D_2,
1978 D_5,
1979 D_5,
1980 D_5,
1981 D_6,
1982 D_6,
1983 D_6,
1984 D_7,
1985 D_7,
1986 D_7,
1987 D_3_3,
1988 D_3_3,
1989 D_3_3,
1990 D_3_4,
1991 D_3_4,
1992 D_10,
1993 D_3_5,
1994 D_11,
1995 D_11,
1996 };
1997
1998 FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LINUX, expected, sizeof(expected)));
1999 PASS;
2000}
2001
2002static int DefragSturgesNovakWindowsIpv4Test(void)
2003{
2004 /* Expected data. */
2005 uint8_t expected[] = {
2006 D_1,
2007 D_1,
2008 D_1,
2009 D_4,
2010 D_2,
2011 D_2,
2012 D_3,
2013 D_3,
2014 D_3,
2015 D_6,
2016 D_6,
2017 D_6,
2018 D_7,
2019 D_3_2,
2020 D_3_2,
2021 D_3_3,
2022 D_3_3,
2023 D_3_3,
2024 D_3_4,
2025 D_3_4,
2026 D_3_5,
2027 D_3_5,
2028 D_3_6,
2029 D_11,
2030 };
2031
2032 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
2033 sizeof(expected)));
2034 PASS;
2035}
2036
2037static int DefragSturgesNovakWindowsIpv6Test(void)
2038{
2039 /* Expected data. */
2040 uint8_t expected[] = {
2041 D_1,
2042 D_1,
2043 D_1,
2044 D_4,
2045 D_2,
2046 D_2,
2047 D_3,
2048 D_3,
2049 D_3,
2050 D_6,
2051 D_6,
2052 D_6,
2053 D_7,
2054 D_3_2,
2055 D_3_2,
2056 D_3_3,
2057 D_3_3,
2058 D_3_3,
2059 D_3_4,
2060 D_3_4,
2061 D_3_5,
2062 D_3_5,
2063 D_3_6,
2064 D_11,
2065 };
2066
2067 FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected)));
2068 PASS;
2069}
2070
2071static int DefragSturgesNovakSolarisTest(void)
2072{
2073 /* Expected data. */
2074 uint8_t expected[] = {
2075 D_1,
2076 D_1,
2077 D_1,
2078 D_4,
2079 D_2,
2080 D_2,
2081 D_3,
2082 D_3,
2083 D_3,
2084 D_6,
2085 D_6,
2086 D_6,
2087 D_7,
2088 D_7,
2089 D_7,
2090 D_3_3,
2091 D_3_3,
2092 D_3_3,
2093 D_3_4,
2094 D_3_4,
2095 D_3_5,
2096 D_3_5,
2097 D_3_6,
2098 D_11,
2099 };
2100
2101 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
2102 sizeof(expected)));
2103 PASS;
2104}
2105
2106static int DefragSturgesNovakSolarisIpv6Test(void)
2107{
2108 /* Expected data. */
2109 uint8_t expected[] = {
2110 D_1,
2111 D_1,
2112 D_1,
2113 D_4,
2114 D_2,
2115 D_2,
2116 D_3,
2117 D_3,
2118 D_3,
2119 D_6,
2120 D_6,
2121 D_6,
2122 D_7,
2123 D_7,
2124 D_7,
2125 D_3_3,
2126 D_3_3,
2127 D_3_3,
2128 D_3_4,
2129 D_3_4,
2130 D_3_5,
2131 D_3_5,
2132 D_3_6,
2133 D_11,
2134 };
2135
2136 FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected)));
2137 PASS;
2138}
2139
2140static int DefragSturgesNovakFirstTest(void)
2141{
2142 /* Expected data. */
2143 uint8_t expected[] = {
2144 D_1,
2145 D_1,
2146 D_1,
2147 D_4,
2148 D_2,
2149 D_2,
2150 D_3,
2151 D_3,
2152 D_3,
2153 D_6,
2154 D_3_1,
2155 D_6,
2156 D_7,
2157 D_3_2,
2158 D_3_2,
2159 D_3_3,
2160 D_3_3,
2161 D_3_3,
2162 D_3_4,
2163 D_3_4,
2164 D_3_5,
2165 D_3_5,
2166 D_3_6,
2167 D_11,
2168 };
2169
2170 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
2171 sizeof(expected)));
2172 PASS;
2173}
2174
2175static int DefragSturgesNovakFirstIpv6Test(void)
2176{
2177 /* Expected data. */
2178 uint8_t expected[] = {
2179 D_1,
2180 D_1,
2181 D_1,
2182 D_4,
2183 D_2,
2184 D_2,
2185 D_3,
2186 D_3,
2187 D_3,
2188 D_6,
2189 D_3_1,
2190 D_6,
2191 D_7,
2192 D_3_2,
2193 D_3_2,
2194 D_3_3,
2195 D_3_3,
2196 D_3_3,
2197 D_3_4,
2198 D_3_4,
2199 D_3_5,
2200 D_3_5,
2201 D_3_6,
2202 D_11,
2203 };
2204
2205 return DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_FIRST, expected, sizeof(expected));
2206}
2207
2208static int
2209DefragSturgesNovakLastTest(void)
2210{
2211 /* Expected data. */
2212 uint8_t expected[] = {
2213 D_1,
2214 D_4,
2215 D_4,
2216 D_4,
2217 D_4,
2218 D_2,
2219 D_5,
2220 D_5,
2221 D_5,
2222 D_6,
2223 D_6,
2224 D_6,
2225 D_7,
2226 D_7,
2227 D_7,
2228 D_3_3,
2229 D_8,
2230 D_3_3,
2231 D_3_4,
2232 D_9,
2233 D_10,
2234 D_3_5,
2235 D_11,
2236 D_11,
2237 };
2238
2239 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2240 sizeof(expected)));
2241 PASS;
2242}
2243
2244static int DefragSturgesNovakLastIpv6Test(void)
2245{
2246 /* Expected data. */
2247 uint8_t expected[] = {
2248 D_1,
2249 D_4,
2250 D_4,
2251 D_4,
2252 D_4,
2253 D_2,
2254 D_5,
2255 D_5,
2256 D_5,
2257 D_6,
2258 D_6,
2259 D_6,
2260 D_7,
2261 D_7,
2262 D_7,
2263 D_3_3,
2264 D_8,
2265 D_3_3,
2266 D_3_4,
2267 D_9,
2268 D_10,
2269 D_3_5,
2270 D_11,
2271 D_11,
2272 };
2273
2274 FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LAST, expected, sizeof(expected)));
2275 PASS;
2276}
2277
2278static int DefragTimeoutTest(void)
2279{
2280 int i;
2281
2282 /* Setup a small number of trackers. */
2283 FAIL_IF_NOT(SCConfSet("defrag.trackers", "16"));
2284
2285 DefragInit();
2286
2287 /* Load in 16 packets. */
2288 for (i = 0; i < 16; i++) {
2289 Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, i, 0, 1, 'A' + i, 16);
2290 FAIL_IF_NULL(p);
2291
2292 Packet *tp = Defrag(&test_tv, &test_dtv, p);
2293 SCFree(p);
2294 FAIL_IF_NOT_NULL(tp);
2295 }
2296
2297 /* Build a new packet but push the timestamp out by our timeout.
2298 * This should force our previous fragments to be timed out. */
2299 Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
2300 FAIL_IF_NULL(p);
2301
2302 p->ts = SCTIME_ADD_SECS(p->ts, defrag_context->timeout + 1);
2303 Packet *tp = Defrag(&test_tv, &test_dtv, p);
2304 FAIL_IF_NOT_NULL(tp);
2305
2307 FAIL_IF_NULL(tracker);
2308
2309 FAIL_IF(tracker->id != 99);
2310
2311 SCMutexUnlock(&tracker->lock);
2312 SCFree(p);
2313
2314 DefragDestroy();
2315 PASS;
2316}
2317
2318/**
2319 * QA found that if you send a packet where more frags is 0, offset is
2320 * > 0 and there is no data in the packet that the re-assembler will
2321 * fail. The fix was simple, but this unit test is just to make sure
2322 * its not introduced.
2323 */
2324static int DefragNoDataIpv4Test(void)
2325{
2326 DefragContext *dc = NULL;
2327 Packet *p = NULL;
2328 int id = 12;
2329
2330 DefragInit();
2331
2332 dc = DefragContextNew();
2333 FAIL_IF_NULL(dc);
2334
2335 /* This packet has an offset > 0, more frags set to 0 and no data. */
2336 p = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
2337 FAIL_IF_NULL(p);
2338
2339 /* We do not expect a packet returned. */
2340 FAIL_IF(Defrag(&test_tv, &test_dtv, p) != NULL);
2341
2342 /* The fragment should have been ignored so no fragments should
2343 * have been allocated from the pool. */
2344 FAIL_IF(dc->frag_pool->outstanding != 0);
2345
2346 DefragContextDestroy(dc);
2347 SCFree(p);
2348
2349 DefragDestroy();
2350 PASS;
2351}
2352
2353static int DefragTooLargeIpv4Test(void)
2354{
2355 DefragContext *dc = NULL;
2356 Packet *p = NULL;
2357
2358 DefragInit();
2359
2360 dc = DefragContextNew();
2361 FAIL_IF_NULL(dc);
2362
2363 /* Create a fragment that would extend past the max allowable size
2364 * for an IPv4 packet. */
2365 p = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
2366 FAIL_IF_NULL(p);
2367
2368 /* We do not expect a packet returned. */
2369 FAIL_IF(Defrag(&test_tv, &test_dtv, p) != NULL);
2370
2371 /* We do expect an event. */
2373
2374 /* The fragment should have been ignored so no fragments should have
2375 * been allocated from the pool. */
2376 FAIL_IF(dc->frag_pool->outstanding != 0);
2377
2378 DefragContextDestroy(dc);
2379 SCFree(p);
2380
2381 DefragDestroy();
2382 PASS;
2383}
2384
2385/**
2386 * Test that fragments in different VLANs that would otherwise be
2387 * re-assembled, are not re-assembled. Just use simple in-order
2388 * fragments.
2389 */
2390static int DefragVlanTest(void)
2391{
2392 Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2393
2394 DefragInit();
2395
2396 p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2397 FAIL_IF_NULL(p1);
2398 p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2399 FAIL_IF_NULL(p2);
2400
2401 /* With no VLAN IDs set, packets should re-assemble. */
2402 FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2403 FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) == NULL);
2404 SCFree(r);
2405
2406 /* With mismatched VLANs, packets should not re-assemble. */
2407 p1->vlan_id[0] = 1;
2408 p2->vlan_id[0] = 2;
2409 FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2410 FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) != NULL);
2411
2412 SCFree(p1);
2413 SCFree(p2);
2414 DefragDestroy();
2415
2416 PASS;
2417}
2418
2419/**
2420 * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID.
2421 */
2422static int DefragVlanQinQTest(void)
2423{
2424 Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2425
2426 DefragInit();
2427
2428 p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2429 FAIL_IF_NULL(p1);
2430 p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2431 FAIL_IF_NULL(p2);
2432
2433 /* With no VLAN IDs set, packets should re-assemble. */
2434 FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2435 FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) == NULL);
2436 SCFree(r);
2437
2438 /* With mismatched VLANs, packets should not re-assemble. */
2439 p1->vlan_id[0] = 1;
2440 p2->vlan_id[0] = 1;
2441 p1->vlan_id[1] = 1;
2442 p2->vlan_id[1] = 2;
2443 FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2444 FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) != NULL);
2445
2446 SCFree(p1);
2447 SCFree(p2);
2448 DefragDestroy();
2449
2450 PASS;
2451}
2452
2453/**
2454 * Like DefragVlanTest, but for QinQinQ, testing the third level VLAN ID.
2455 */
2456static int DefragVlanQinQinQTest(void)
2457{
2458 Packet *r = NULL;
2459
2460 DefragInit();
2461
2462 Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2463 FAIL_IF_NULL(p1);
2464 Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2465 FAIL_IF_NULL(p2);
2466
2467 /* With no VLAN IDs set, packets should re-assemble. */
2468 FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2469 FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) == NULL);
2470 SCFree(r);
2471
2472 /* With mismatched VLANs, packets should not re-assemble. */
2473 p1->vlan_id[0] = 1;
2474 p2->vlan_id[0] = 1;
2475 p1->vlan_id[1] = 2;
2476 p2->vlan_id[1] = 2;
2477 p1->vlan_id[2] = 3;
2478 p2->vlan_id[2] = 4;
2479 FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2480 FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) != NULL);
2481
2482 PacketFree(p1);
2483 PacketFree(p2);
2484 DefragDestroy();
2485
2486 PASS;
2487}
2488static int DefragTrackerReuseTest(void)
2489{
2490 int id = 1;
2491 Packet *p1 = NULL;
2492 DefragTracker *tracker1 = NULL, *tracker2 = NULL;
2493
2494 DefragInit();
2495
2496 /* Build a packet, its not a fragment but shouldn't matter for
2497 * this test. */
2498 p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
2499 FAIL_IF_NULL(p1);
2500
2501 /* Get a tracker. It shouldn't look like its already in use. */
2502 tracker1 = DefragGetTracker(&test_tv, &test_dtv, p1);
2503 FAIL_IF_NULL(tracker1);
2504 FAIL_IF(tracker1->seen_last);
2505 FAIL_IF(tracker1->remove);
2506 DefragTrackerRelease(tracker1);
2507
2508 /* Get a tracker again, it should be the same one. */
2509 tracker2 = DefragGetTracker(&test_tv, &test_dtv, p1);
2510 FAIL_IF_NULL(tracker2);
2511 FAIL_IF(tracker2 != tracker1);
2512 DefragTrackerRelease(tracker1);
2513
2514 /* Now mark the tracker for removal. It should not be returned
2515 * when we get a tracker for a packet that may have the same
2516 * attributes. */
2517 tracker1->remove = 1;
2518
2519 tracker2 = DefragGetTracker(&test_tv, &test_dtv, p1);
2520 FAIL_IF_NULL(tracker2);
2521 /* DefragGetTracker will have returned tracker1 to the stack,
2522 * the set up a new tracker. Since it pops the stack, it got
2523 * tracker1. */
2524 FAIL_IF(tracker2 != tracker1);
2525 FAIL_IF(tracker2->remove);
2526
2527 SCFree(p1);
2528 DefragDestroy();
2529 PASS;
2530}
2531
2532/**
2533 * IPV4: Test the case where you have a packet fragmented in 3 parts
2534 * and send like:
2535 * - Offset: 2; MF: 1
2536 * - Offset: 0; MF: 1
2537 * - Offset: 1; MF: 0
2538 *
2539 * Only the fragments with offset 0 and 1 should be reassembled.
2540 */
2541static int DefragMfIpv4Test(void)
2542{
2543 int ip_id = 9;
2544 Packet *p = NULL;
2545
2546 DefragInit();
2547
2548 Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
2549 Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
2550 Packet *p3 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
2551 FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2552
2553 p = Defrag(&test_tv, &test_dtv, p1);
2555
2556 p = Defrag(&test_tv, &test_dtv, p2);
2558
2559 /* This should return a packet as MF=0. */
2560 p = Defrag(&test_tv, &test_dtv, p3);
2561 FAIL_IF_NULL(p);
2562
2563 /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the
2564 * fragments should be in the re-assembled packet. */
2565 FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(p)) != 36);
2566
2567 /* Verify the payload of the IPv4 packet. */
2568 uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
2569 FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV4Hdr), expected_payload, sizeof(expected_payload)));
2570
2571 SCFree(p1);
2572 SCFree(p2);
2573 SCFree(p3);
2574 SCFree(p);
2575 DefragDestroy();
2576 PASS;
2577}
2578
2579/**
2580 * IPV6: Test the case where you have a packet fragmented in 3 parts
2581 * and send like:
2582 * - Offset: 2; MF: 1
2583 * - Offset: 0; MF: 1
2584 * - Offset: 1; MF: 0
2585 *
2586 * Only the fragments with offset 0 and 1 should be reassembled.
2587 */
2588static int DefragMfIpv6Test(void)
2589{
2590 int ip_id = 9;
2591 Packet *p = NULL;
2592
2593 DefragInit();
2594
2595 Packet *p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
2596 Packet *p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
2597 Packet *p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
2598 FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2599
2600 p = Defrag(&test_tv, &test_dtv, p1);
2602
2603 p = Defrag(&test_tv, &test_dtv, p2);
2605
2606 /* This should return a packet as MF=0. */
2607 p = Defrag(&test_tv, &test_dtv, p3);
2608 FAIL_IF_NULL(p);
2609
2610 /* For IPv6 the expected length is just the length of the payload
2611 * of 2 fragments, so 16. */
2612 FAIL_IF(IPV6_GET_RAW_PLEN(PacketGetIPv6(p)) != 16);
2613
2614 /* Verify the payload of the IPv4 packet. */
2615 uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
2616 FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV6Hdr), expected_payload, sizeof(expected_payload)));
2617
2618 SCFree(p1);
2619 SCFree(p2);
2620 SCFree(p3);
2621 SCFree(p);
2622 DefragDestroy();
2623 PASS;
2624}
2625
2626/**
2627 * \brief Test that fragments that match other than the proto don't
2628 * actually get matched.
2629 */
2630static int DefragTestBadProto(void)
2631{
2632 Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
2633 int id = 12;
2634
2635 DefragInit();
2636
2637 p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
2638 FAIL_IF_NULL(p1);
2639 p2 = BuildIpv4TestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
2640 FAIL_IF_NULL(p2);
2641 p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
2642 FAIL_IF_NULL(p3);
2643
2647
2648 SCFree(p1);
2649 SCFree(p2);
2650 SCFree(p3);
2651
2652 DefragDestroy();
2653 PASS;
2654}
2655
2656/**
2657 * \test Test a report Linux overlap issue that doesn't appear to be
2658 * covered by the Sturges/Novak tests above.
2659 */
2660static int DefragTestJeremyLinux(void)
2661{
2662
2663 uint8_t expected[] = "AAAAAAAA"
2664 "AAAAAAAA"
2665 "AAAAAAAA"
2666 "CCCCCCCC"
2667 "CCCCCCCC"
2668 "CCCCCCCC"
2669 "CCCCCCCC"
2670 "CCCCCCCC"
2671 "CCCCCCCC"
2672 "BBBBBBBB"
2673 "BBBBBBBB"
2674 "DDDDDDDD"
2675 "DDDDDD";
2676
2677 DefragInit();
2678 default_policy = DEFRAG_POLICY_LINUX;
2679
2680 int id = 1;
2681 Packet *packets[4];
2682 int i = 0;
2683
2684 packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
2685 packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
2686 packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
2687 packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
2688
2689 Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2691
2692 r = Defrag(&test_tv, &test_dtv, packets[1]);
2694
2695 r = Defrag(&test_tv, &test_dtv, packets[2]);
2697
2698 r = Defrag(&test_tv, &test_dtv, packets[3]);
2699 FAIL_IF_NULL(r);
2700
2701 FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0);
2702
2703 for (i = 0; i < 4; i++) {
2704 SCFree(packets[i]);
2705 }
2706 SCFree(r);
2707
2708 DefragDestroy();
2709 PASS;
2710}
2711
2712/**
2713 * | 0 | 8 | 16 | 24 | 32 |
2714 * |----------|----------|----------|----------|----------|
2715 * | AAAAAAAA | AAAAAAAA |
2716 * | | BBBBBBBB | BBBBBBBB | | |
2717 * | | | CCCCCCCC | CCCCCCCC | |
2718 * | DDDDDDDD | | | | |
2719 *
2720 * | DDDDDDDD | BBBBBBBB | BBBBBBBB | CCCCCCCC | AAAAAAAA |
2721 */
2722static int DefragBsdFragmentAfterNoMfIpv4Test(void)
2723{
2724 DefragInit();
2725 default_policy = DEFRAG_POLICY_BSD;
2726 Packet *packets[4];
2727
2728 packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
2729 packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
2730 packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
2731 packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
2732
2733 Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2735
2736 r = Defrag(&test_tv, &test_dtv, packets[1]);
2738
2739 r = Defrag(&test_tv, &test_dtv, packets[2]);
2741
2742 r = Defrag(&test_tv, &test_dtv, packets[3]);
2743 FAIL_IF_NULL(r);
2744
2745 // clang-format off
2746 uint8_t expected[] = {
2747 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
2748 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2749 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2750 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
2751 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
2752 };
2753 // clang-format on
2754
2755 if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
2756 printf("Expected:\n");
2757 PrintRawDataFp(stdout, expected, sizeof(expected));
2758 printf("Got:\n");
2759 PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
2760 FAIL;
2761 }
2762
2763 DefragDestroy();
2764 PASS;
2765}
2766
2767static int DefragBsdFragmentAfterNoMfIpv6Test(void)
2768{
2769 DefragInit();
2770 default_policy = DEFRAG_POLICY_BSD;
2771 Packet *packets[4];
2772
2773 packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
2774 packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
2775 packets[2] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
2776 packets[3] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
2777
2778 Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2780
2781 r = Defrag(&test_tv, &test_dtv, packets[1]);
2783
2784 r = Defrag(&test_tv, &test_dtv, packets[2]);
2786
2787 r = Defrag(&test_tv, &test_dtv, packets[3]);
2788 FAIL_IF_NULL(r);
2789
2790 // clang-format off
2791 uint8_t expected[] = {
2792 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
2793 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2794 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2795 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
2796 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
2797 };
2798 // clang-format on
2799
2800 if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
2801 printf("Expected:\n");
2802 PrintRawDataFp(stdout, expected, sizeof(expected));
2803 printf("Got:\n");
2804 PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
2805 FAIL;
2806 }
2807
2808 DefragDestroy();
2809 PASS;
2810}
2811
2812static int DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2(void)
2813{
2814 DefragInit();
2815 default_policy = DEFRAG_POLICY_BSD;
2816 Packet *packets[4];
2817
2818 /* Packet 1: off=16, mf=1 */
2819 FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
2820 &packets[0], IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16));
2821
2822 /* Packet 2: off=8, mf=1 */
2823 FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
2824 &packets[1], IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16));
2825
2826 /* Packet 3: off=0, mf=1: IP and ICMP header. */
2827 FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
2828 &packets[2], IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8));
2829
2830 /* Packet 4: off=8, mf=1 */
2831 FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
2832 &packets[3], IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8));
2833
2834 Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2836
2837 r = Defrag(&test_tv, &test_dtv, packets[1]);
2839
2840 r = Defrag(&test_tv, &test_dtv, packets[2]);
2842
2843 r = Defrag(&test_tv, &test_dtv, packets[3]);
2844 FAIL_IF_NULL(r);
2845
2846 // clang-format off
2847 const uint8_t expected[] = {
2848 // AACCBBDD
2849 // AACCDDBB
2850 // AABBDDCC
2851 // DDCCBBAA
2852 'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
2853 'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
2854 'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
2855 'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
2856 };
2857 // clang-format on
2858
2859 FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20 + 8, sizeof(expected)) != 0);
2860
2861 DefragDestroy();
2862 PASS;
2863}
2864
2865static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2(void)
2866{
2867 DefragInit();
2868 default_policy = DEFRAG_POLICY_BSD;
2869 Packet *packets[4];
2870
2871 /* Packet 1: off=16, mf=1 */
2872 packets[0] = BuildIpv6TestPacketWithContent(
2873 IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
2874
2875 /* Packet 2: off=8, mf=1 */
2876 packets[1] = BuildIpv6TestPacketWithContent(
2877 IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16);
2878
2879 /* Packet 3: off=0, mf=1: IP and ICMP header. */
2880 packets[2] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
2881
2882 /* Packet 4: off=8, mf=1 */
2883 packets[3] =
2884 BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
2885
2886 Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2888
2889 r = Defrag(&test_tv, &test_dtv, packets[1]);
2891
2892 r = Defrag(&test_tv, &test_dtv, packets[2]);
2894
2895 r = Defrag(&test_tv, &test_dtv, packets[3]);
2896 FAIL_IF_NULL(r);
2897
2898 // clang-format off
2899 const uint8_t expected[] = {
2900 // AACCBBDD
2901 // AACCDDBB
2902 // AABBDDCC
2903 // DDCCBBAA
2904 'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
2905 'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
2906 'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
2907 'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
2908 };
2909 // clang-format on
2910
2911 FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 40 + 8, sizeof(expected)) != 0);
2912
2913 DefragDestroy();
2914 PASS;
2915}
2916
2917/**
2918 * #### Input
2919 *
2920 * | 96 (0) | 104 (8) | 112 (16) | 120 (24) |
2921 * |----------|----------|----------|----------|
2922 * | | EEEEEEEE | EEEEEEEE | EEEEEEEE |
2923 * | MMMMMMMM | MMMMMMMM | MMMMMMMM | |
2924 *
2925 * #### Expected Output
2926 *
2927 * | MMMMMMMM | MMMMMMMM | MMMMMMMM | EEEEEEEE |
2928 */
2929static int DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test(void)
2930{
2931 DefragInit();
2932 default_policy = DEFRAG_POLICY_BSD;
2933 Packet *packets[2];
2934
2935 packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
2936 packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
2937
2938 Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2940
2941 r = Defrag(&test_tv, &test_dtv, packets[1]);
2942 FAIL_IF_NULL(r);
2943
2944 // clang-format off
2945 const uint8_t expected[] = {
2946 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2947 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2948 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2949 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
2950 };
2951 // clang-format on
2952
2953 if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
2954 printf("Expected:\n");
2955 PrintRawDataFp(stdout, expected, sizeof(expected));
2956 printf("Got:\n");
2957 PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
2958 FAIL;
2959 }
2960
2961 PASS;
2962}
2963
2964static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test(void)
2965{
2966 DefragInit();
2967 default_policy = DEFRAG_POLICY_BSD;
2968 Packet *packets[2];
2969
2970 packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
2971 packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
2972
2973 Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2975
2976 r = Defrag(&test_tv, &test_dtv, packets[1]);
2977 FAIL_IF_NULL(r);
2978
2979 // clang-format off
2980 const uint8_t expected[] = {
2981 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2982 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2983 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2984 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
2985 };
2986 // clang-format on
2987
2988 if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
2989 printf("Expected:\n");
2990 PrintRawDataFp(stdout, expected, sizeof(expected));
2991 printf("Got:\n");
2992 PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
2993 FAIL;
2994 }
2995
2996 PASS;
2997}
2998
2999/**
3000 * Reassembly should fail.
3001 *
3002 * |0 |8 |16 |24 |32 |40 |48 |
3003 * |========|========|========|========|========|========|========|
3004 * | | |AABBCCDD|AABBDDCC| | | |
3005 * | | | | | |AACCBBDD| |
3006 * | |AACCDDBB|AADDBBCC| | | | |
3007 * |ZZZZZZZZ| | | | | | |
3008 * | | | | | | |DDCCBBAA|
3009 */
3010static int DefragBsdMissingFragmentIpv4Test(void)
3011{
3012 DefragInit();
3013 default_policy = DEFRAG_POLICY_BSD;
3014 Packet *packets[5];
3015
3016 FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3017 &packets[0], IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16));
3018
3019 FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3020 &packets[1], IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8));
3021
3022 FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3023 &packets[2], IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16));
3024
3025 /* ICMP header. */
3026 FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3027 &packets[3], IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8));
3028
3029 FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3030 &packets[4], IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8));
3031
3032 Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
3034
3035 r = Defrag(&test_tv, &test_dtv, packets[1]);
3037
3038 r = Defrag(&test_tv, &test_dtv, packets[2]);
3040
3041 r = Defrag(&test_tv, &test_dtv, packets[3]);
3043
3044 r = Defrag(&test_tv, &test_dtv, packets[4]);
3046
3047#if 0
3048 PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
3049#endif
3050
3051 for (int i = 0; i < 5; i++) {
3052 SCFree(packets[i]);
3053 }
3054
3055 DefragDestroy();
3056
3057 PASS;
3058}
3059
3060static int DefragBsdMissingFragmentIpv6Test(void)
3061{
3062 DefragInit();
3063 default_policy = DEFRAG_POLICY_BSD;
3064 Packet *packets[5];
3065
3066 packets[0] = BuildIpv6TestPacketWithContent(
3067 IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
3068
3069 packets[1] =
3070 BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8);
3071
3072 packets[2] = BuildIpv6TestPacketWithContent(
3073 IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16);
3074
3075 /* ICMP header. */
3076 packets[3] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
3077
3078 packets[4] =
3079 BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
3080
3081 Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
3083
3084 r = Defrag(&test_tv, &test_dtv, packets[1]);
3086
3087 r = Defrag(&test_tv, &test_dtv, packets[2]);
3089
3090 r = Defrag(&test_tv, &test_dtv, packets[3]);
3092
3093 r = Defrag(&test_tv, &test_dtv, packets[4]);
3095
3096#if 0
3097 PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
3098#endif
3099
3100 for (int i = 0; i < 5; i++) {
3101 SCFree(packets[i]);
3102 }
3103
3104 DefragDestroy();
3105
3106 PASS;
3107}
3108
3109#endif /* UNITTESTS */
3110
3112{
3113#ifdef UNITTESTS
3114 UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest);
3115 UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest);
3116 UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest);
3117 UtRegisterTest("DefragSturgesNovakLinuxIpv4Test",
3118 DefragSturgesNovakLinuxIpv4Test);
3119 UtRegisterTest("DefragSturgesNovakWindowsIpv4Test",
3120 DefragSturgesNovakWindowsIpv4Test);
3121 UtRegisterTest("DefragSturgesNovakSolarisTest",
3122 DefragSturgesNovakSolarisTest);
3123 UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
3124 UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
3125
3126 UtRegisterTest("DefragNoDataIpv4Test", DefragNoDataIpv4Test);
3127 UtRegisterTest("DefragTooLargeIpv4Test", DefragTooLargeIpv4Test);
3128
3129 UtRegisterTest("DefragInOrderSimpleIpv6Test", DefragInOrderSimpleIpv6Test);
3130 UtRegisterTest("DefragReverseSimpleIpv6Test", DefragReverseSimpleIpv6Test);
3131 UtRegisterTest("DefragSturgesNovakBsdIpv6Test", DefragSturgesNovakBsdIpv6Test);
3132 UtRegisterTest("DefragSturgesNovakLinuxIpv6Test", DefragSturgesNovakLinuxIpv6Test);
3133 UtRegisterTest("DefragSturgesNovakWindowsIpv6Test", DefragSturgesNovakWindowsIpv6Test);
3134 UtRegisterTest("DefragSturgesNovakSolarisIpv6Test", DefragSturgesNovakSolarisIpv6Test);
3135 UtRegisterTest("DefragSturgesNovakFirstIpv6Test", DefragSturgesNovakFirstIpv6Test);
3136 UtRegisterTest("DefragSturgesNovakLastIpv6Test", DefragSturgesNovakLastIpv6Test);
3137
3138 UtRegisterTest("DefragVlanTest", DefragVlanTest);
3139 UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
3140 UtRegisterTest("DefragVlanQinQinQTest", DefragVlanQinQinQTest);
3141 UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest);
3142 UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest);
3143 UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test);
3144 UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test);
3145 UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
3146
3147 UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux);
3148
3149 UtRegisterTest("DefragBsdFragmentAfterNoMfIpv4Test", DefragBsdFragmentAfterNoMfIpv4Test);
3150 UtRegisterTest("DefragBsdFragmentAfterNoMfIpv6Test", DefragBsdFragmentAfterNoMfIpv6Test);
3151 UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test",
3152 DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test);
3153 UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test",
3154 DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test);
3155 UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2",
3156 DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2);
3157 UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2",
3158 DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2);
3159 UtRegisterTest("DefragBsdMissingFragmentIpv4Test", DefragBsdMissingFragmentIpv4Test);
3160 UtRegisterTest("DefragBsdMissingFragmentIpv6Test", DefragBsdMissingFragmentIpv6Test);
3161#endif /* UNITTESTS */
3162}
uint8_t len
struct HtpBodyChunk_ * next
int SCConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition conf.c:414
int SCConfSet(const char *name, const char *val)
Set a configuration value.
Definition conf.c:239
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition counters.c:166
@ IPV6_FRAG_PKT_TOO_LARGE
@ IPV6_FRAG_IGNORED
@ IPV6_FRAG_OVERLAP
@ IPV4_FRAG_IGNORED
@ IPV4_FRAG_OVERLAP
@ IPV4_FRAG_PKT_TOO_LARGE
uint16_t af
Definition decode-gre.h:0
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
#define IPV4_GET_RAW_FRAGOFFSET(ip4h)
#define IPV4_GET_RAW_IPLEN(ip4h)
Definition decode-ipv4.h:98
#define IPV4_MAXPACKET_LEN
Definition decode-ipv4.h:30
#define IPV4_HEADER_LEN
Definition decode-ipv4.h:28
#define IPV4_GET_RAW_IPTTL(ip4h)
#define IPV4_GET_RAW_VER(ip4h)
Definition decode-ipv4.h:95
#define IPV4_GET_RAW_HLEN(ip4h)
Definition decode-ipv4.h:96
#define IPV4_GET_RAW_FLAG_MF(ip4h)
#define IPV4_GET_RAW_IPID(ip4h)
Definition decode-ipv4.h:99
#define IPV4_GET_RAW_IPPROTO(ip4h)
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
void DecodeIPV6FragHeader(Packet *p, const uint8_t *pkt, uint16_t hdrextlen, uint16_t plen, uint16_t prev_hdrextlen)
Definition decode-ipv6.c:94
#define IPV6_GET_RAW_PLEN(ip6h)
Definition decode-ipv6.h:66
#define IPV6_EXTHDR_GET_FH_OFFSET(p)
#define IPV6_GET_RAW_VER(ip6h)
Definition decode-ipv6.h:62
#define IPV6_MAXPACKET
Definition decode-ipv6.h:28
#define IPV6_GET_RAW_NH(ip6h)
Definition decode-ipv6.h:65
#define IPV6_SET_RAW_VER(ip6h, value)
Definition decode-ipv6.h:69
struct IPV6Hdr_ IPV6Hdr
#define IPV6_HEADER_LEN
Definition decode-ipv6.h:27
#define IPV6_EXTHDR_GET_FH_FLAG(p)
#define IPV6_EXTHDR_GET_FH_NH(p)
uint8_t proto
#define GET_IPV6_DST_ADDR(p)
Definition decode.h:204
#define SET_IPV6_SRC_ADDR(ip6h, a)
Definition decode.h:159
#define SET_PKT_LEN(p, len)
Definition decode.h:213
#define PKT_REBUILT_FRAGMENT
Definition decode.h:1302
#define PKT_SET_SRC(p, src_val)
Definition decode.h:1325
#define GET_PKT_DATA(p)
Definition decode.h:209
#define MAX_PAYLOAD_SIZE
Definition decode.h:701
#define ENGINE_ISSET_EVENT(p, e)
Definition decode.h:1199
#define SET_IPV4_SRC_ADDR(ip4h, a)
Definition decode.h:140
#define SET_IPV6_DST_ADDR(ip6h, a)
Definition decode.h:168
#define GET_PKT_LEN(p)
Definition decode.h:208
#define SET_IPV4_DST_ADDR(ip4h, a)
Definition decode.h:149
#define ENGINE_SET_EVENT(p, e)
Definition decode.h:1186
@ PKT_SRC_DEFRAG
Definition decode.h:57
#define GET_IPV4_DST_ADDR_PTR(p)
Definition decode.h:199
void DefragPolicyLoadFromConfig(void)
void DefragTreeDestroy(void)
void DefragSetDefaultTimeout(int timeout)
void DefragTrackerRelease(DefragTracker *t)
DefragTracker * DefragLookupTrackerFromHash(Packet *p)
look up a tracker in the hash
DefragTracker * DefragGetTrackerFromHash(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
void DefragInitConfig(bool quiet)
initialize the configuration
void DefragHashShutdown(void)
shutdown the flow engine
#define D_3_2
Definition defrag.c:1849
void DefragInit(void)
Definition defrag.c:1109
#define D_3
Definition defrag.c:1847
#define D_10
Definition defrag.c:1860
ThreadVars test_tv
Definition defrag.c:1143
#define D_3_1
Definition defrag.c:1848
uint8_t DefragGetOsPolicy(Packet *p)
Get the defrag policy based on the destination address of the packet.
Definition defrag.c:985
#define D_3_4
Definition defrag.c:1851
#define D_4
Definition defrag.c:1854
#define D_8
Definition defrag.c:1858
#define D_2
Definition defrag.c:1846
#define D_11
Definition defrag.c:1861
#define TIMEOUT_MIN
Definition defrag.c:82
#define TIMEOUT_MAX
Definition defrag.c:77
int DefragRbFragCompare(struct Frag_ *a, struct Frag_ *b)
Definition defrag.c:537
#define D_5
Definition defrag.c:1855
#define DEFAULT_DEFRAG_POOL_SIZE
Definition defrag.c:66
defrag_policies
Definition defrag.c:85
@ DEFRAG_POLICY_BSD_RIGHT
Definition defrag.c:89
@ DEFRAG_POLICY_DEFAULT
Definition defrag.c:94
@ DEFRAG_POLICY_LINUX
Definition defrag.c:90
@ DEFRAG_POLICY_BSD
Definition defrag.c:88
@ DEFRAG_POLICY_SOLARIS
Definition defrag.c:92
@ DEFRAG_POLICY_LAST
Definition defrag.c:87
@ DEFRAG_POLICY_WINDOWS
Definition defrag.c:91
@ DEFRAG_POLICY_FIRST
Definition defrag.c:86
#define D_9
Definition defrag.c:1859
#define D_7
Definition defrag.c:1857
#define D_1
Definition defrag.c:1845
void DefragTrackerFreeFrags(DefragTracker *tracker)
Free all frags associated with a tracker.
Definition defrag.c:132
#define D_3_5
Definition defrag.c:1852
#define TIMEOUT_DEFAULT
Definition defrag.c:72
#define D_6
Definition defrag.c:1856
Packet * Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Entry point for IPv4 and IPv6 fragments.
Definition defrag.c:1063
void DefragRegisterTests(void)
Definition defrag.c:3111
#define D_3_3
Definition defrag.c:1850
DecodeThreadVars test_dtv
Definition defrag.c:1144
void DefragDestroy(void)
Definition defrag.c:1129
#define IP_MF
Definition defrag.c:1141
#define DEFAULT_DEFRAG_HASH_SIZE
Definition defrag.c:65
#define D_3_6
Definition defrag.c:1853
DecodeThreadVars * dtv
ThreadVars * tv
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
#define FAIL
Fail a test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
void PacketDefragPktSetupParent(Packet *parent)
inform defrag "parent" that a pseudo packet is now associated to it.
Definition decode.c:512
int PacketCopyDataOffset(Packet *p, uint32_t offset, const uint8_t *data, uint32_t datalen)
Copy data to Packet payload at given offset.
Definition decode.c:335
int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Copy data to Packet payload and set packet length.
Definition decode.c:377
uint32_t default_packet_size
Definition decode.c:77
Packet * PacketDefragPktSetup(Packet *parent, const uint8_t *pkt, uint32_t len, uint8_t proto)
Setup a pseudo packet (reassembled frags)
Definition decode.c:473
void PacketFreeOrRelease(Packet *p)
Return a packet to where it was allocated.
Definition decode.c:276
void PacketFree(Packet *p)
Return a malloced packet.
Definition decode.c:219
void PoolFree(Pool *p)
Definition util-pool.c:223
Pool * PoolInit(uint32_t size, uint32_t prealloc_size, uint32_t elt_size, void *(*Alloc)(void), int(*Init)(void *, void *), void *InitData, void(*Cleanup)(void *), void(*Free)(void *))
Init a Pool.
Definition util-pool.c:84
void PoolReturn(Pool *p, void *data)
Definition util-pool.c:329
void * PoolGet(Pool *p)
Definition util-pool.c:271
void PacketInit(Packet *p)
Initialize a packet structure for use.
Definition packet.c:63
@ OS_POLICY_LAST
@ OS_POLICY_MACOS
@ OS_POLICY_WINDOWS
@ OS_POLICY_IRIX
@ OS_POLICY_HPUX10
@ OS_POLICY_VISTA
@ OS_POLICY_LINUX
@ OS_POLICY_OLD_LINUX
@ OS_POLICY_BSD
@ OS_POLICY_BSD_RIGHT
@ OS_POLICY_FIRST
@ OS_POLICY_WINDOWS2K3
@ OS_POLICY_OLD_SOLARIS
@ OS_POLICY_HPUX11
@ OS_POLICY_SOLARIS
Structure to hold thread specific data for all decode modules.
Definition decode.h:963
uint16_t counter_defrag_max_hit
Definition decode.h:1022
uint16_t counter_defrag_ipv4_reassembled
Definition decode.h:1019
uint16_t counter_defrag_ipv6_fragments
Definition decode.h:1020
uint16_t counter_defrag_ipv6_reassembled
Definition decode.h:1021
uint16_t counter_defrag_ipv4_fragments
Definition decode.h:1018
uint16_t counter_defrag_no_frags
Definition decode.h:1023
uint32_t timeout
Definition defrag.h:40
SCMutex frag_pool_lock
Definition defrag.h:38
Pool * frag_pool
Definition defrag.h:37
uint8_t remove
Definition defrag.h:104
uint16_t ip_hdr_offset
Definition defrag.h:89
SCMutex lock
Definition defrag.h:85
uint8_t seen_last
Definition defrag.h:102
SCTime_t timeout
Definition defrag.h:110
uint8_t policy
Definition defrag.h:97
uint32_t id
Definition defrag.h:92
struct IP_FRAGMENTS fragment_tree
Definition defrag.h:116
uint8_t af
Definition defrag.h:99
uint32_t host_timeout
Definition defrag.h:111
Definition defrag.h:46
uint16_t frag_hdr_offset
Definition defrag.h:57
uint16_t offset
Definition defrag.h:47
uint8_t more_frags
Definition defrag.h:54
uint16_t data_offset
Definition defrag.h:60
uint8_t skip
Definition defrag.h:55
uint16_t data_len
Definition defrag.h:61
uint32_t len
Definition defrag.h:50
uint8_t * pkt
Definition defrag.h:66
uint16_t ltrim
Definition defrag.h:63
uint8_t hlen
Definition defrag.h:52
uint8_t ip_verhl
Definition decode-ipv4.h:73
uint16_t ip_id
Definition decode-ipv4.h:76
uint16_t ip_off
Definition decode-ipv4.h:77
uint16_t ip_csum
Definition decode-ipv4.h:80
uint8_t ip_proto
Definition decode-ipv4.h:79
uint8_t ip_ttl
Definition decode-ipv4.h:78
uint16_t ip_len
Definition decode-ipv4.h:75
uint16_t fh_data_len
uint16_t fh_header_offset
uint16_t fh_data_offset
uint16_t fh_prev_hdr_offset
union PacketL3::@31 vars
IPV6ExtHdrs eh
Definition decode.h:448
struct PacketL3::@31::@32 ip6
uint64_t pcap_cnt
Definition decode.h:626
SCTime_t ts
Definition decode.h:555
Address src
Definition decode.h:505
struct PacketL3 l3
Definition decode.h:600
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition decode.h:528
int datalink
Definition decode.h:639
struct Packet_ * root
Definition decode.h:653
uint32_t flags
Definition decode.h:544
Address dst
Definition decode.h:506
uint32_t outstanding
Definition util-pool.h:67
Per thread variable structure.
Definition threadvars.h:58
#define MAX(x, y)
#define SCMutexUnlock(mut)
#define SCMutexInit(mut, mutattrs)
#define SCMutexLock(mut)
@ TM_ECODE_OK
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
#define RB_MIN(name, x)
Definition tree.h:778
#define RB_EMPTY(head)
Definition tree.h:327
#define RB_FOREACH(x, name, head)
Definition tree.h:781
#define RB_FOREACH_FROM(x, name, y)
Definition tree.h:786
#define RB_NFIND(name, x, y)
Definition tree.h:775
#define RB_FOREACH_SAFE(x, name, head, y)
Definition tree.h:791
#define RB_REMOVE(name, x, y)
Definition tree.h:773
#define RB_GENERATE(name, type, field, cmp)
Definition tree.h:421
#define FatalError(...)
Definition util-debug.h:510
#define SCLogDebug(...)
Definition util-debug.h:275
uint16_t FixChecksum(uint16_t sum, uint16_t old, uint16_t new)
Fix-up an IP checksum.
int SCHInfoGetIPv6HostOSFlavour(uint8_t *addr)
Retrieves the host os flavour, given an ipv6 address in the raw address format.
int SCHInfoGetIPv4HostOSFlavour(uint8_t *addr)
Retrieves the host os flavour, given an ipv4 address in the raw address format.
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define unlikely(expr)
void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen)
Definition util-print.c:112
uint64_t offset
#define SCTIME_FROM_SECS(s)
Definition util-time.h:69
#define SCTIME_SECS(t)
Definition util-time.h:57
#define SCTIME_ADD_SECS(ts, s)
Definition util-time.h:64
#define SCTIME_FROM_TIMEVAL(tv)
Definition util-time.h:79
#define DEBUG_VALIDATE_BUG_ON(exp)