]> git.ipfire.org Git - people/ms/suricata.git/blob - src/defrag.c
core: Remove unneeded consts
[people/ms/suricata.git] / src / defrag.c
1 /* Copyright (C) 2007-2012 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 normalizaton (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"
50 #include "stream-tcp-reassemble.h"
51 #include "util-host-os-info.h"
52
53 #include "defrag.h"
54 #include "defrag-hash.h"
55 #include "defrag-queue.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. */
85 enum defrag_policies {
86 DEFRAG_POLICY_FIRST = 1,
87 DEFRAG_POLICY_LAST,
88 DEFRAG_POLICY_BSD,
89 DEFRAG_POLICY_BSD_RIGHT,
90 DEFRAG_POLICY_LINUX,
91 DEFRAG_POLICY_WINDOWS,
92 DEFRAG_POLICY_SOLARIS,
93
94 DEFRAG_POLICY_DEFAULT = DEFRAG_POLICY_BSD,
95 };
96
97 static int default_policy = DEFRAG_POLICY_BSD;
98
99 /** The global DefragContext so all threads operate from the same
100 * context. */
101 static DefragContext *defrag_context;
102
103 RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
104
105 /**
106 * Utility/debugging function to dump the frags associated with a
107 * tracker. Only enable when unit tests are enabled.
108 */
109 #if 0
110 #ifdef UNITTESTS
111 static void
112 DumpFrags(DefragTracker *tracker)
113 {
114 Frag *frag;
115
116 printf("Dumping frags for packet: ID=%d\n", tracker->id);
117 TAILQ_FOREACH(frag, &tracker->frags, next) {
118 printf("-> Frag: frag_offset=%d, frag_len=%d, data_len=%d, ltrim=%d, skip=%d\n", frag->offset, frag->len, frag->data_len, frag->ltrim, frag->skip);
119 PrintRawDataFp(stdout, frag->pkt, frag->len);
120 }
121 }
122 #endif /* UNITTESTS */
123 #endif
124
125 /**
126 * \brief Reset a frag for reuse in a pool.
127 */
128 static void
129 DefragFragReset(Frag *frag)
130 {
131 if (frag->pkt != NULL)
132 SCFree(frag->pkt);
133 memset(frag, 0, sizeof(*frag));
134 }
135
136 /**
137 * \brief Allocate a new frag for use in a pool.
138 */
139 static int
140 DefragFragInit(void *data, void *initdata)
141 {
142 Frag *frag = data;
143
144 memset(frag, 0, sizeof(*frag));
145 return 1;
146 }
147
148 /**
149 * \brief Free all frags associated with a tracker.
150 */
151 void
152 DefragTrackerFreeFrags(DefragTracker *tracker)
153 {
154 Frag *frag, *tmp;
155
156 /* Lock the frag pool as we'll be return items to it. */
157 SCMutexLock(&defrag_context->frag_pool_lock);
158
159 RB_FOREACH_SAFE(frag, IP_FRAGMENTS, &tracker->fragment_tree, tmp) {
160 RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, frag);
161 DefragFragReset(frag);
162 PoolReturn(defrag_context->frag_pool, frag);
163 }
164
165 SCMutexUnlock(&defrag_context->frag_pool_lock);
166 }
167
168 /**
169 * \brief Create a new DefragContext.
170 *
171 * \retval On success a return an initialized DefragContext, otherwise
172 * NULL will be returned.
173 */
174 static DefragContext *
175 DefragContextNew(void)
176 {
177 DefragContext *dc;
178
179 dc = SCCalloc(1, sizeof(*dc));
180 if (unlikely(dc == NULL))
181 return NULL;
182
183 /* Initialize the pool of trackers. */
184 intmax_t tracker_pool_size;
185 if (!ConfGetInt("defrag.trackers", &tracker_pool_size) || tracker_pool_size == 0) {
186 tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
187 }
188
189 /* Initialize the pool of frags. */
190 intmax_t frag_pool_size;
191 if (!ConfGetInt("defrag.max-frags", &frag_pool_size) || frag_pool_size == 0) {
192 frag_pool_size = DEFAULT_DEFRAG_POOL_SIZE;
193 }
194 intmax_t frag_pool_prealloc = frag_pool_size / 2;
195 dc->frag_pool = PoolInit(frag_pool_size, frag_pool_prealloc,
196 sizeof(Frag),
197 NULL, DefragFragInit, dc, NULL, NULL);
198 if (dc->frag_pool == NULL) {
199 FatalError(SC_ERR_FATAL,
200 "Defrag: Failed to initialize fragment pool.");
201 }
202 if (SCMutexInit(&dc->frag_pool_lock, NULL) != 0) {
203 FatalError(SC_ERR_FATAL,
204 "Defrag: Failed to initialize frag pool mutex.");
205 }
206
207 /* Set the default timeout. */
208 intmax_t timeout;
209 if (!ConfGetInt("defrag.timeout", &timeout)) {
210 dc->timeout = TIMEOUT_DEFAULT;
211 }
212 else {
213 if (timeout < TIMEOUT_MIN) {
214 FatalError(SC_ERR_FATAL,
215 "defrag: Timeout less than minimum allowed value.");
216 }
217 else if (timeout > TIMEOUT_MAX) {
218 FatalError(SC_ERR_FATAL,
219 "defrag: Tiemout greater than maximum allowed value.");
220 }
221 dc->timeout = timeout;
222 }
223
224 SCLogDebug("Defrag Initialized:");
225 SCLogDebug("\tTimeout: %"PRIuMAX, (uintmax_t)dc->timeout);
226 SCLogDebug("\tMaximum defrag trackers: %"PRIuMAX, tracker_pool_size);
227 SCLogDebug("\tPreallocated defrag trackers: %"PRIuMAX, tracker_pool_size);
228 SCLogDebug("\tMaximum fragments: %"PRIuMAX, (uintmax_t)frag_pool_size);
229 SCLogDebug("\tPreallocated fragments: %"PRIuMAX, (uintmax_t)frag_pool_prealloc);
230
231 return dc;
232 }
233
234 static void
235 DefragContextDestroy(DefragContext *dc)
236 {
237 if (dc == NULL)
238 return;
239
240 PoolFree(dc->frag_pool);
241 SCFree(dc);
242 }
243
244 /**
245 * Attempt to re-assemble a packet.
246 *
247 * \param tracker The defragmentation tracker to reassemble from.
248 */
249 static Packet *
250 Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
251 {
252 Packet *rp = NULL;
253
254 /* Should not be here unless we have seen the last fragment. */
255 if (!tracker->seen_last) {
256 return NULL;
257 }
258
259 /* Check that we have the first fragment and its of a valid size. */
260 Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
261 if (first == NULL) {
262 goto done;
263 } else if (first->offset != 0) {
264 /* Still waiting for the first fragment. */
265 goto done;
266 } else if (first->len < sizeof(IPV4Hdr)) {
267 /* First fragment isn't enough for an IPv6 header. */
268 goto error_remove_tracker;
269 }
270
271 /* Check that we have all the data. Relies on the fact that
272 * fragments are inserted if frag_offset order. */
273 Frag *frag = NULL;
274 size_t len = 0;
275 RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
276 if (frag->offset > len) {
277 /* This fragment starts after the end of the previous
278 * fragment. We have a hole. */
279 goto done;
280 }
281 else {
282 len += frag->data_len;
283 }
284 }
285
286 /* Allocate a Packet for the reassembled packet. On failure we
287 * SCFree all the resources held by this tracker. */
288 rp = PacketDefragPktSetup(p, NULL, 0, IPV4_GET_IPPROTO(p));
289 if (rp == NULL) {
290 SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for "
291 "fragmentation re-assembly, dumping fragments.");
292 goto error_remove_tracker;
293 }
294 PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
295 rp->flags |= PKT_REBUILT_FRAGMENT;
296 rp->recursion_level = p->recursion_level;
297
298 int fragmentable_offset = 0;
299 int fragmentable_len = 0;
300 int hlen = 0;
301 int ip_hdr_offset = 0;
302
303 RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
304 SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64,
305 frag, frag->data_len, frag->offset, frag->pcap_cnt);
306
307 if (frag->skip)
308 continue;
309 if (frag->ltrim >= frag->data_len)
310 continue;
311 if (frag->offset == 0) {
312
313 if (PacketCopyData(rp, frag->pkt, frag->len) == -1)
314 goto error_remove_tracker;
315
316 hlen = frag->hlen;
317 ip_hdr_offset = frag->ip_hdr_offset;
318
319 /* This is the start of the fragmentable portion of the
320 * first packet. All fragment offsets are relative to
321 * this. */
322 fragmentable_offset = frag->ip_hdr_offset + frag->hlen;
323 fragmentable_len = frag->data_len;
324 }
325 else {
326 int pkt_end = fragmentable_offset + frag->offset + frag->data_len;
327 if (pkt_end > (int)MAX_PAYLOAD_SIZE) {
328 SCLogWarning(SC_ERR_REASSEMBLY, "Failed re-assemble "
329 "fragmented packet, exceeds size of packet buffer.");
330 goto error_remove_tracker;
331 }
332 if (PacketCopyDataOffset(rp,
333 fragmentable_offset + frag->offset + frag->ltrim,
334 frag->pkt + frag->data_offset + frag->ltrim,
335 frag->data_len - frag->ltrim) == -1) {
336 goto error_remove_tracker;
337 }
338 if (frag->offset + frag->data_len > fragmentable_len)
339 fragmentable_len = frag->offset + frag->data_len;
340 }
341
342 if (!frag->more_frags) {
343 break;
344 }
345 }
346
347 SCLogDebug("ip_hdr_offset %u, hlen %u, fragmentable_len %u",
348 ip_hdr_offset, hlen, fragmentable_len);
349
350 rp->ip4h = (IPV4Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
351 int old = rp->ip4h->ip_len + rp->ip4h->ip_off;
352 rp->ip4h->ip_len = htons(fragmentable_len + hlen);
353 rp->ip4h->ip_off = 0;
354 rp->ip4h->ip_csum = FixChecksum(rp->ip4h->ip_csum,
355 old, rp->ip4h->ip_len + rp->ip4h->ip_off);
356 SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len);
357
358 tracker->remove = 1;
359 DefragTrackerFreeFrags(tracker);
360 done:
361 return rp;
362
363 error_remove_tracker:
364 tracker->remove = 1;
365 DefragTrackerFreeFrags(tracker);
366 if (rp != NULL)
367 PacketFreeOrRelease(rp);
368 return NULL;
369 }
370
371 /**
372 * Attempt to re-assemble a packet.
373 *
374 * \param tracker The defragmentation tracker to reassemble from.
375 */
376 static Packet *
377 Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
378 {
379 Packet *rp = NULL;
380
381 /* Should not be here unless we have seen the last fragment. */
382 if (!tracker->seen_last)
383 return NULL;
384
385 /* Check that we have the first fragment and its of a valid size. */
386 Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
387 if (first == NULL) {
388 goto done;
389 } else if (first->offset != 0) {
390 /* Still waiting for the first fragment. */
391 goto done;
392 } else if (first->len < sizeof(IPV6Hdr)) {
393 /* First fragment isn't enough for an IPv6 header. */
394 goto error_remove_tracker;
395 }
396
397 /* Check that we have all the data. Relies on the fact that
398 * fragments are inserted if frag_offset order. */
399 size_t len = 0;
400 Frag *frag = NULL;
401 RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
402 if (frag->skip) {
403 continue;
404 }
405
406 if (frag == first) {
407 if (frag->offset != 0) {
408 goto done;
409 }
410 len = frag->data_len;
411 }
412 else {
413 if (frag->offset > len) {
414 /* This fragment starts after the end of the previous
415 * fragment. We have a hole. */
416 goto done;
417 }
418 else {
419 len += frag->data_len;
420 }
421 }
422 }
423
424 /* Allocate a Packet for the reassembled packet. On failure we
425 * SCFree all the resources held by this tracker. */
426 rp = PacketDefragPktSetup(p, (uint8_t *)p->ip6h,
427 IPV6_GET_PLEN(p) + sizeof(IPV6Hdr), 0);
428 if (rp == NULL) {
429 SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for "
430 "fragmentation re-assembly, dumping fragments.");
431 goto error_remove_tracker;
432 }
433 PKT_SET_SRC(rp, PKT_SRC_DEFRAG);
434
435 int unfragmentable_len = 0;
436 int fragmentable_offset = 0;
437 int fragmentable_len = 0;
438 int ip_hdr_offset = 0;
439 uint8_t next_hdr = 0;
440 RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
441 if (frag->skip)
442 continue;
443 if (frag->data_len - frag->ltrim <= 0)
444 continue;
445 if (frag->offset == 0) {
446 IPV6FragHdr *frag_hdr = (IPV6FragHdr *)(frag->pkt +
447 frag->frag_hdr_offset);
448 next_hdr = frag_hdr->ip6fh_nxt;
449
450 /* This is the first packet, we use this packets link and
451 * IPv6 headers. We also copy in its data, but remove the
452 * fragmentation header. */
453 if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1)
454 goto error_remove_tracker;
455 if (PacketCopyDataOffset(rp, frag->frag_hdr_offset,
456 frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr),
457 frag->data_len) == -1)
458 goto error_remove_tracker;
459 ip_hdr_offset = frag->ip_hdr_offset;
460
461 /* This is the start of the fragmentable portion of the
462 * first packet. All fragment offsets are relative to
463 * this. */
464 fragmentable_offset = frag->frag_hdr_offset;
465 fragmentable_len = frag->data_len;
466
467 /* unfragmentable part is the part between the ipv6 header
468 * and the frag header. */
469 unfragmentable_len = (fragmentable_offset - ip_hdr_offset) - IPV6_HEADER_LEN;
470 if (unfragmentable_len >= fragmentable_offset)
471 goto error_remove_tracker;
472 }
473 else {
474 if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim,
475 frag->pkt + frag->data_offset + frag->ltrim,
476 frag->data_len - frag->ltrim) == -1)
477 goto error_remove_tracker;
478 if (frag->offset + frag->data_len > fragmentable_len)
479 fragmentable_len = frag->offset + frag->data_len;
480 }
481
482 if (!frag->more_frags) {
483 break;
484 }
485 }
486
487 rp->ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
488 rp->ip6h->s_ip6_plen = htons(fragmentable_len + unfragmentable_len);
489 /* if we have no unfragmentable part, so no ext hdrs before the frag
490 * header, we need to update the ipv6 headers next header field. This
491 * points to the frag header, and we will make it point to the layer
492 * directly after the frag header. */
493 if (unfragmentable_len == 0)
494 rp->ip6h->s_ip6_nxt = next_hdr;
495 SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) +
496 unfragmentable_len + fragmentable_len);
497
498 tracker->remove = 1;
499 DefragTrackerFreeFrags(tracker);
500 done:
501 return rp;
502
503 error_remove_tracker:
504 tracker->remove = 1;
505 DefragTrackerFreeFrags(tracker);
506 if (rp != NULL)
507 PacketFreeOrRelease(rp);
508 return NULL;
509 }
510
511 /**
512 * The RB_TREE compare function for fragments.
513 *
514 * When it comes to adding fragments, we want subsequent ones with the
515 * same offset to be treated as greater than, so we don't have an
516 * equal return value here.
517 */
518 int DefragRbFragCompare(struct Frag_ *a, struct Frag_ *b) {
519 if (a->offset < b->offset) {
520 return -1;
521 }
522 return 1;
523 }
524
525 /**
526 * Insert a new IPv4/IPv6 fragment into a tracker.
527 *
528 * \todo Allocate packet buffers from a pool.
529 */
530 static Packet *
531 DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
532 {
533 Packet *r = NULL;
534 int ltrim = 0;
535
536 uint8_t more_frags;
537 uint16_t frag_offset;
538
539 /* IPv4 header length - IPv4 only. */
540 uint16_t hlen = 0;
541
542 /* This is the offset of the start of the data in the packet that
543 * falls after the IP header. */
544 uint16_t data_offset;
545
546 /* The length of the (fragmented) data. This is the length of the
547 * data that falls after the IP header. */
548 uint16_t data_len;
549
550 /* Where the fragment ends. */
551 uint16_t frag_end;
552
553 /* Offset in the packet to the IPv6 header. */
554 uint16_t ip_hdr_offset;
555
556 /* Offset in the packet to the IPv6 frag header. IPv6 only. */
557 uint16_t frag_hdr_offset = 0;
558
559 /* Address family */
560 int af = tracker->af;
561
562 /* settings for updating a payload when an ip6 fragment with
563 * unfragmentable exthdrs are encountered. */
564 int ip6_nh_set_offset = 0;
565 uint8_t ip6_nh_set_value = 0;
566
567 #ifdef DEBUG
568 uint64_t pcap_cnt = p->pcap_cnt;
569 #endif
570
571 if (tracker->af == AF_INET) {
572 more_frags = IPV4_GET_MF(p);
573 frag_offset = IPV4_GET_IPOFFSET(p) << 3;
574 hlen = IPV4_GET_HLEN(p);
575 data_offset = (uint8_t *)p->ip4h + hlen - GET_PKT_DATA(p);
576 data_len = IPV4_GET_IPLEN(p) - hlen;
577 frag_end = frag_offset + data_len;
578 ip_hdr_offset = (uint8_t *)p->ip4h - GET_PKT_DATA(p);
579
580 /* Ignore fragment if the end of packet extends past the
581 * maximum size of a packet. */
582 if (IPV4_HEADER_LEN + frag_offset + data_len > IPV4_MAXPACKET_LEN) {
583 ENGINE_SET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE);
584 return NULL;
585 }
586 }
587 else if (tracker->af == AF_INET6) {
588 more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
589 frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
590 data_offset = p->ip6eh.fh_data_offset;
591 data_len = p->ip6eh.fh_data_len;
592 frag_end = frag_offset + data_len;
593 ip_hdr_offset = (uint8_t *)p->ip6h - GET_PKT_DATA(p);
594 frag_hdr_offset = p->ip6eh.fh_header_offset;
595
596 SCLogDebug("mf %s frag_offset %u data_offset %u, data_len %u, "
597 "frag_end %u, ip_hdr_offset %u, frag_hdr_offset %u",
598 more_frags ? "true" : "false", frag_offset, data_offset,
599 data_len, frag_end, ip_hdr_offset, frag_hdr_offset);
600
601 /* handle unfragmentable exthdrs */
602 if (ip_hdr_offset + IPV6_HEADER_LEN < frag_hdr_offset) {
603 SCLogDebug("we have exthdrs before fraghdr %u bytes",
604 (uint32_t)(frag_hdr_offset - (ip_hdr_offset + IPV6_HEADER_LEN)));
605
606 /* get the offset of the 'next' field in exthdr before the FH,
607 * relative to the buffer start */
608
609 /* store offset and FH 'next' value for updating frag buffer below */
610 ip6_nh_set_offset = p->ip6eh.fh_prev_hdr_offset;
611 ip6_nh_set_value = IPV6_EXTHDR_GET_FH_NH(p);
612 SCLogDebug("offset %d, value %u", ip6_nh_set_offset, ip6_nh_set_value);
613 }
614
615 /* Ignore fragment if the end of packet extends past the
616 * maximum size of a packet. */
617 if (frag_offset + data_len > IPV6_MAXPACKET) {
618 ENGINE_SET_EVENT(p, IPV6_FRAG_PKT_TOO_LARGE);
619 return NULL;
620 }
621 }
622 else {
623 /* Abort - should not happen. */
624 SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid address family, aborting.");
625 return NULL;
626 }
627
628 /* Update timeout. */
629 tracker->timeout.tv_sec = p->ts.tv_sec + tracker->host_timeout;
630 tracker->timeout.tv_usec = p->ts.tv_usec;
631
632 Frag *prev = NULL, *next = NULL;
633 bool overlap = false;
634 ltrim = 0;
635
636 if (!RB_EMPTY(&tracker->fragment_tree)) {
637 Frag key = {
638 .offset = frag_offset - 1,
639 };
640 next = RB_NFIND(IP_FRAGMENTS, &tracker->fragment_tree, &key);
641 if (next == NULL) {
642 prev = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
643 next = IP_FRAGMENTS_RB_NEXT(prev);
644 } else {
645 prev = IP_FRAGMENTS_RB_PREV(next);
646 if (prev == NULL) {
647 prev = next;
648 next = IP_FRAGMENTS_RB_NEXT(prev);
649 }
650 }
651 while (prev != NULL) {
652 if (prev->skip) {
653 goto next;
654 }
655 if (frag_offset < prev->offset + prev->data_len && prev->offset < frag_end) {
656 overlap = true;
657 }
658
659 switch (tracker->policy) {
660 case DEFRAG_POLICY_BSD:
661 if (frag_offset < prev->offset + prev->data_len) {
662 if (frag_offset >= prev->offset) {
663 ltrim = prev->offset + prev->data_len - frag_offset;
664 }
665 if ((next != NULL) && (frag_end > next->offset)) {
666 next->ltrim = frag_end - next->offset;
667 }
668 if ((frag_offset < prev->offset) &&
669 (frag_end >= prev->offset + prev->data_len)) {
670 prev->skip = 1;
671 }
672 goto insert;
673 }
674 break;
675 case DEFRAG_POLICY_LINUX:
676 /* Check if new fragment overlaps the end of previous
677 * fragment, if it does, trim the new fragment.
678 *
679 * Old: AAAAAAAA AAAAAAAA AAAAAAAA
680 * New: BBBBBBBB BBBBBBBB BBBBBBBB
681 * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
682 */
683 if (prev->offset + prev->ltrim < frag_offset + ltrim &&
684 prev->offset + prev->data_len > frag_offset + ltrim) {
685 ltrim += prev->offset + prev->data_len - frag_offset;
686 }
687
688 /* Check if new fragment overlaps the beginning of
689 * previous fragment, if it does, tim the previous
690 * fragment.
691 *
692 * Old: AAAAAAAA AAAAAAAA
693 * New: BBBBBBBB BBBBBBBB BBBBBBBB
694 * Res: BBBBBBBB BBBBBBBB BBBBBBBB
695 */
696 if (frag_offset + ltrim < prev->offset + prev->ltrim &&
697 frag_end > prev->offset + prev->ltrim) {
698 prev->ltrim += frag_end - (prev->offset + prev->ltrim);
699 goto insert;
700 }
701
702 /* If the new fragment completely overlaps the
703 * previous fragment, mark the previous to be
704 * skipped. Re-assembly would succeed without doing
705 * this, but this will prevent the bytes from being
706 * copied just to be overwritten. */
707 if (frag_offset + ltrim <= prev->offset + prev->ltrim &&
708 frag_end >= prev->offset + prev->data_len) {
709 prev->skip = 1;
710 goto insert;
711 }
712
713 break;
714 case DEFRAG_POLICY_WINDOWS:
715 /* If new fragment fits inside a previous fragment, drop it. */
716 if (frag_offset + ltrim >= prev->offset + ltrim &&
717 frag_end <= prev->offset + prev->data_len) {
718 goto done;
719 }
720
721 /* If new fragment starts before and ends after
722 * previous fragment, drop the previous fragment. */
723 if (frag_offset + ltrim < prev->offset + ltrim &&
724 frag_end > prev->offset + prev->data_len) {
725 prev->skip = 1;
726 goto insert;
727 }
728
729 /* Check if new fragment overlaps the end of previous
730 * fragment, if it does, trim the new fragment.
731 *
732 * Old: AAAAAAAA AAAAAAAA AAAAAAAA
733 * New: BBBBBBBB BBBBBBBB BBBBBBBB
734 * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
735 */
736 if (frag_offset + ltrim > prev->offset + prev->ltrim &&
737 frag_offset + ltrim < prev->offset + prev->data_len) {
738 ltrim += prev->offset + prev->data_len - frag_offset;
739 goto insert;
740 }
741
742 /* If new fragment starts at same offset as an
743 * existing fragment, but ends after it, trim the new
744 * fragment. */
745 if (frag_offset + ltrim == prev->offset + ltrim &&
746 frag_end > prev->offset + prev->data_len) {
747 ltrim += prev->offset + prev->data_len - frag_offset;
748 goto insert;
749 }
750 break;
751 case DEFRAG_POLICY_SOLARIS:
752 if (frag_offset < prev->offset + prev->data_len) {
753 if (frag_offset >= prev->offset) {
754 ltrim = prev->offset + prev->data_len - frag_offset;
755 }
756 if ((frag_offset < prev->offset) &&
757 (frag_end >= prev->offset + prev->data_len)) {
758 prev->skip = 1;
759 }
760 goto insert;
761 }
762 break;
763 case DEFRAG_POLICY_FIRST:
764 if ((frag_offset >= prev->offset) &&
765 (frag_end <= prev->offset + prev->data_len)) {
766 goto done;
767 }
768 if (frag_offset < prev->offset) {
769 goto insert;
770 }
771 if (frag_offset < prev->offset + prev->data_len) {
772 ltrim = prev->offset + prev->data_len - frag_offset;
773 goto insert;
774 }
775 break;
776 case DEFRAG_POLICY_LAST:
777 if (frag_offset <= prev->offset) {
778 if (frag_end > prev->offset) {
779 prev->ltrim = frag_end - prev->offset;
780 }
781 goto insert;
782 }
783 break;
784 default:
785 break;
786 }
787
788 next:
789 prev = next;
790 if (next != NULL) {
791 next = IP_FRAGMENTS_RB_NEXT(next);
792 }
793 continue;
794
795 insert:
796 /* If existing fragment has been trimmed up completely
797 * (complete overlap), remove it now instead of holding
798 * onto it. */
799 if (prev->skip || prev->ltrim >= prev->data_len) {
800 RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, prev);
801 DefragFragReset(prev);
802 SCMutexLock(&defrag_context->frag_pool_lock);
803 PoolReturn(defrag_context->frag_pool, prev);
804 SCMutexUnlock(&defrag_context->frag_pool_lock);
805 }
806 break;
807 }
808 }
809
810 if (ltrim > data_len) {
811 /* Full packet has been trimmed due to the overlap policy. Overlap
812 * already set. */
813 goto done;
814 }
815
816 /* Allocate fragment and insert. */
817 SCMutexLock(&defrag_context->frag_pool_lock);
818 Frag *new = PoolGet(defrag_context->frag_pool);
819 SCMutexUnlock(&defrag_context->frag_pool_lock);
820 if (new == NULL) {
821 if (af == AF_INET) {
822 ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED);
823 } else {
824 ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED);
825 }
826 goto done;
827 }
828 new->pkt = SCMalloc(GET_PKT_LEN(p));
829 if (new->pkt == NULL) {
830 SCMutexLock(&defrag_context->frag_pool_lock);
831 PoolReturn(defrag_context->frag_pool, new);
832 SCMutexUnlock(&defrag_context->frag_pool_lock);
833 if (af == AF_INET) {
834 ENGINE_SET_EVENT(p, IPV4_FRAG_IGNORED);
835 } else {
836 ENGINE_SET_EVENT(p, IPV6_FRAG_IGNORED);
837 }
838 goto done;
839 }
840 memcpy(new->pkt, GET_PKT_DATA(p) + ltrim, GET_PKT_LEN(p) - ltrim);
841 new->len = GET_PKT_LEN(p) - ltrim;
842 /* in case of unfragmentable exthdrs, update the 'next hdr' field
843 * in the raw buffer so the reassembled packet will point to the
844 * correct next header after stripping the frag header */
845 if (ip6_nh_set_offset > 0 && frag_offset == 0 && ltrim == 0) {
846 if (new->len > ip6_nh_set_offset) {
847 SCLogDebug("updating frag to have 'correct' nh value: %u -> %u",
848 new->pkt[ip6_nh_set_offset], ip6_nh_set_value);
849 new->pkt[ip6_nh_set_offset] = ip6_nh_set_value;
850 }
851 }
852
853 new->hlen = hlen;
854 new->offset = frag_offset + ltrim;
855 new->data_offset = data_offset;
856 new->data_len = data_len - ltrim;
857 new->ip_hdr_offset = ip_hdr_offset;
858 new->frag_hdr_offset = frag_hdr_offset;
859 new->more_frags = more_frags;
860 #ifdef DEBUG
861 new->pcap_cnt = pcap_cnt;
862 #endif
863
864 IP_FRAGMENTS_RB_INSERT(&tracker->fragment_tree, new);
865
866 if (!more_frags) {
867 tracker->seen_last = 1;
868 }
869
870 if (tracker->seen_last) {
871 if (tracker->af == AF_INET) {
872 r = Defrag4Reassemble(tv, tracker, p);
873 if (r != NULL && tv != NULL && dtv != NULL) {
874 StatsIncr(tv, dtv->counter_defrag_ipv4_reassembled);
875 if (DecodeIPV4(tv, dtv, r, (void *)r->ip4h,
876 IPV4_GET_IPLEN(r)) != TM_ECODE_OK) {
877
878 UNSET_TUNNEL_PKT(r);
879 r->root = NULL;
880 TmqhOutputPacketpool(tv, r);
881 r = NULL;
882 } else {
883 PacketDefragPktSetupParent(p);
884 }
885 }
886 }
887 else if (tracker->af == AF_INET6) {
888 r = Defrag6Reassemble(tv, tracker, p);
889 if (r != NULL && tv != NULL && dtv != NULL) {
890 StatsIncr(tv, dtv->counter_defrag_ipv6_reassembled);
891 if (DecodeIPV6(tv, dtv, r, (uint8_t *)r->ip6h,
892 IPV6_GET_PLEN(r) + IPV6_HEADER_LEN)
893 != TM_ECODE_OK) {
894
895 UNSET_TUNNEL_PKT(r);
896 r->root = NULL;
897 TmqhOutputPacketpool(tv, r);
898 r = NULL;
899 } else {
900 PacketDefragPktSetupParent(p);
901 }
902 }
903 }
904 }
905
906
907 done:
908 if (overlap) {
909 if (af == AF_INET) {
910 ENGINE_SET_EVENT(p, IPV4_FRAG_OVERLAP);
911 }
912 else {
913 ENGINE_SET_EVENT(p, IPV6_FRAG_OVERLAP);
914 }
915 }
916 return r;
917 }
918
919 /**
920 * \brief Get the defrag policy based on the destination address of
921 * the packet.
922 *
923 * \param p The packet used to get the destination address.
924 *
925 * \retval The defrag policy to use.
926 */
927 uint8_t
928 DefragGetOsPolicy(Packet *p)
929 {
930 int policy = -1;
931
932 if (PKT_IS_IPV4(p)) {
933 policy = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
934 }
935 else if (PKT_IS_IPV6(p)) {
936 policy = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
937 }
938
939 if (policy == -1) {
940 return default_policy;
941 }
942
943 /* Map the OS policies returned from the configured host info to
944 * defrag specific policies. */
945 switch (policy) {
946 /* BSD. */
947 case OS_POLICY_BSD:
948 case OS_POLICY_HPUX10:
949 case OS_POLICY_IRIX:
950 return DEFRAG_POLICY_BSD;
951
952 /* BSD-Right. */
953 case OS_POLICY_BSD_RIGHT:
954 return DEFRAG_POLICY_BSD_RIGHT;
955
956 /* Linux. */
957 case OS_POLICY_OLD_LINUX:
958 case OS_POLICY_LINUX:
959 return DEFRAG_POLICY_LINUX;
960
961 /* First. */
962 case OS_POLICY_OLD_SOLARIS:
963 case OS_POLICY_HPUX11:
964 case OS_POLICY_MACOS:
965 case OS_POLICY_FIRST:
966 return DEFRAG_POLICY_FIRST;
967
968 /* Solaris. */
969 case OS_POLICY_SOLARIS:
970 return DEFRAG_POLICY_SOLARIS;
971
972 /* Windows. */
973 case OS_POLICY_WINDOWS:
974 case OS_POLICY_VISTA:
975 case OS_POLICY_WINDOWS2K3:
976 return DEFRAG_POLICY_WINDOWS;
977
978 /* Last. */
979 case OS_POLICY_LAST:
980 return DEFRAG_POLICY_LAST;
981
982 default:
983 return default_policy;
984 }
985 }
986
987 /** \internal
988 *
989 * \retval NULL or a *LOCKED* tracker */
990 static DefragTracker *
991 DefragGetTracker(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
992 {
993 return DefragGetTrackerFromHash(p);
994 }
995
996 /**
997 * \brief Entry point for IPv4 and IPv6 fragments.
998 *
999 * \param tv ThreadVars for the calling decoder.
1000 * \param p The packet fragment.
1001 *
1002 * \retval A new Packet resembling the re-assembled packet if the most
1003 * recent fragment allowed the packet to be re-assembled, otherwise
1004 * NULL is returned.
1005 */
1006 Packet *
1007 Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
1008 {
1009 uint16_t frag_offset;
1010 uint8_t more_frags;
1011 DefragTracker *tracker;
1012 int af;
1013
1014 if (PKT_IS_IPV4(p)) {
1015 af = AF_INET;
1016 more_frags = IPV4_GET_MF(p);
1017 frag_offset = IPV4_GET_IPOFFSET(p);
1018 }
1019 else if (PKT_IS_IPV6(p)) {
1020 af = AF_INET6;
1021 frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
1022 more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
1023 }
1024 else {
1025 return NULL;
1026 }
1027
1028 if (frag_offset == 0 && more_frags == 0) {
1029 return NULL;
1030 }
1031
1032 if (tv != NULL && dtv != NULL) {
1033 if (af == AF_INET) {
1034 StatsIncr(tv, dtv->counter_defrag_ipv4_fragments);
1035 }
1036 else if (af == AF_INET6) {
1037 StatsIncr(tv, dtv->counter_defrag_ipv6_fragments);
1038 }
1039 }
1040
1041 /* return a locked tracker or NULL */
1042 tracker = DefragGetTracker(tv, dtv, p);
1043 if (tracker == NULL)
1044 return NULL;
1045
1046 Packet *rp = DefragInsertFrag(tv, dtv, tracker, p);
1047 DefragTrackerRelease(tracker);
1048
1049 return rp;
1050 }
1051
1052 void
1053 DefragInit(void)
1054 {
1055 intmax_t tracker_pool_size;
1056 if (!ConfGetInt("defrag.trackers", &tracker_pool_size)) {
1057 tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
1058 }
1059
1060 /* Load the defrag-per-host lookup. */
1061 DefragPolicyLoadFromConfig();
1062
1063 /* Allocate the DefragContext. */
1064 defrag_context = DefragContextNew();
1065 if (defrag_context == NULL) {
1066 FatalError(SC_ERR_FATAL,
1067 "Failed to allocate memory for the Defrag module.");
1068 }
1069
1070 DefragSetDefaultTimeout(defrag_context->timeout);
1071 DefragInitConfig(false);
1072 }
1073
1074 void DefragDestroy(void)
1075 {
1076 DefragHashShutdown();
1077 DefragContextDestroy(defrag_context);
1078 defrag_context = NULL;
1079 DefragTreeDestroy();
1080 }
1081
1082 #ifdef UNITTESTS
1083 #define IP_MF 0x2000
1084
1085 /**
1086 * Allocate a test packet. Nothing to fancy, just a simple IP packet
1087 * with some payload of no particular protocol.
1088 */
1089 static Packet *BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf,
1090 const char content, int content_len)
1091 {
1092 Packet *p = NULL;
1093 int hlen = 20;
1094 int ttl = 64;
1095 uint8_t *pcontent;
1096 IPV4Hdr ip4h;
1097
1098 p = SCCalloc(1, sizeof(*p) + default_packet_size);
1099 if (unlikely(p == NULL))
1100 return NULL;
1101
1102 PACKET_INITIALIZE(p);
1103
1104 gettimeofday(&p->ts, NULL);
1105 //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1106 ip4h.ip_verhl = 4 << 4;
1107 ip4h.ip_verhl |= hlen >> 2;
1108 ip4h.ip_len = htons(hlen + content_len);
1109 ip4h.ip_id = htons(id);
1110 if (mf)
1111 ip4h.ip_off = htons(IP_MF | off);
1112 else
1113 ip4h.ip_off = htons(off);
1114 ip4h.ip_ttl = ttl;
1115 ip4h.ip_proto = proto;
1116
1117 ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1118 ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1119
1120 /* copy content_len crap, we need full length */
1121 PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1122 p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1123 SET_IPV4_SRC_ADDR(p, &p->src);
1124 SET_IPV4_DST_ADDR(p, &p->dst);
1125
1126 pcontent = SCCalloc(1, content_len);
1127 if (unlikely(pcontent == NULL))
1128 return NULL;
1129 memset(pcontent, content, content_len);
1130 PacketCopyDataOffset(p, hlen, pcontent, content_len);
1131 SET_PKT_LEN(p, hlen + content_len);
1132 SCFree(pcontent);
1133
1134 p->ip4h->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1135
1136 /* Self test. */
1137 if (IPV4_GET_VER(p) != 4)
1138 goto error;
1139 if (IPV4_GET_HLEN(p) != hlen)
1140 goto error;
1141 if (IPV4_GET_IPLEN(p) != hlen + content_len)
1142 goto error;
1143 if (IPV4_GET_IPID(p) != id)
1144 goto error;
1145 if (IPV4_GET_IPOFFSET(p) != off)
1146 goto error;
1147 if (IPV4_GET_MF(p) != mf)
1148 goto error;
1149 if (IPV4_GET_IPTTL(p) != ttl)
1150 goto error;
1151 if (IPV4_GET_IPPROTO(p) != proto)
1152 goto error;
1153
1154 return p;
1155 error:
1156 if (p != NULL)
1157 SCFree(p);
1158 return NULL;
1159 }
1160
1161 static Packet *IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off,
1162 int mf, const char content, int content_len)
1163 {
1164 Packet *p = NULL;
1165 uint8_t *pcontent;
1166 IPV6Hdr ip6h;
1167
1168 p = SCCalloc(1, sizeof(*p) + default_packet_size);
1169 if (unlikely(p == NULL))
1170 return NULL;
1171
1172 PACKET_INITIALIZE(p);
1173
1174 gettimeofday(&p->ts, NULL);
1175
1176 ip6h.s_ip6_nxt = 44;
1177 ip6h.s_ip6_hlim = 2;
1178
1179 /* Source and dest address - very bogus addresses. */
1180 ip6h.s_ip6_src[0] = 0x01010101;
1181 ip6h.s_ip6_src[1] = 0x01010101;
1182 ip6h.s_ip6_src[2] = 0x01010101;
1183 ip6h.s_ip6_src[3] = 0x01010101;
1184 ip6h.s_ip6_dst[0] = 0x02020202;
1185 ip6h.s_ip6_dst[1] = 0x02020202;
1186 ip6h.s_ip6_dst[2] = 0x02020202;
1187 ip6h.s_ip6_dst[3] = 0x02020202;
1188
1189 /* copy content_len crap, we need full length */
1190 PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1191
1192 p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
1193 IPV6_SET_RAW_VER(p->ip6h, 6);
1194 /* Fragmentation header. */
1195 IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1196 fh->ip6fh_nxt = proto;
1197 fh->ip6fh_ident = htonl(id);
1198 fh->ip6fh_offlg = htons((off << 3) | mf);
1199
1200 DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1201
1202 pcontent = SCCalloc(1, content_len);
1203 if (unlikely(pcontent == NULL))
1204 return NULL;
1205 memset(pcontent, content, content_len);
1206 PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), pcontent, content_len);
1207 SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1208 SCFree(pcontent);
1209
1210 p->ip6h->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1211
1212 SET_IPV6_SRC_ADDR(p, &p->src);
1213 SET_IPV6_DST_ADDR(p, &p->dst);
1214
1215 /* Self test. */
1216 if (IPV6_GET_VER(p) != 6)
1217 goto error;
1218 if (IPV6_GET_NH(p) != 44)
1219 goto error;
1220 if (IPV6_GET_PLEN(p) != sizeof(IPV6FragHdr) + content_len)
1221 goto error;
1222
1223 return p;
1224 error:
1225 if (p != NULL)
1226 SCFree(p);
1227 return NULL;
1228 }
1229
1230 /**
1231 * Test the simplest possible re-assembly scenario. All packet in
1232 * order and no overlaps.
1233 */
1234 static int DefragInOrderSimpleTest(void)
1235 {
1236 Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1237 Packet *reassembled = NULL;
1238 int id = 12;
1239 int i;
1240
1241 DefragInit();
1242
1243 p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1244 FAIL_IF_NULL(p1);
1245 p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1246 FAIL_IF_NULL(p2);
1247 p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1248 FAIL_IF_NULL(p3);
1249
1250 FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1251 FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1252
1253 reassembled = Defrag(NULL, NULL, p3);
1254 FAIL_IF_NULL(reassembled);
1255
1256 FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1257 FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1258
1259 /* 20 bytes in we should find 8 bytes of A. */
1260 for (i = 20; i < 20 + 8; i++) {
1261 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1262 }
1263
1264 /* 28 bytes in we should find 8 bytes of B. */
1265 for (i = 28; i < 28 + 8; i++) {
1266 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1267 }
1268
1269 /* And 36 bytes in we should find 3 bytes of C. */
1270 for (i = 36; i < 36 + 3; i++) {
1271 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1272 }
1273
1274 SCFree(p1);
1275 SCFree(p2);
1276 SCFree(p3);
1277 SCFree(reassembled);
1278
1279 DefragDestroy();
1280 PASS;
1281 }
1282
1283 /**
1284 * Simple fragmented packet in reverse order.
1285 */
1286 static int DefragReverseSimpleTest(void)
1287 {
1288 Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1289 Packet *reassembled = NULL;
1290 int id = 12;
1291 int i;
1292
1293 DefragInit();
1294
1295 p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1296 FAIL_IF_NULL(p1);
1297 p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1298 FAIL_IF_NULL(p2);
1299 p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1300 FAIL_IF_NULL(p3);
1301
1302 FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1303 FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1304
1305 reassembled = Defrag(NULL, NULL, p1);
1306 FAIL_IF_NULL(reassembled);
1307
1308 FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1309 FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1310
1311 /* 20 bytes in we should find 8 bytes of A. */
1312 for (i = 20; i < 20 + 8; i++) {
1313 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1314 }
1315
1316 /* 28 bytes in we should find 8 bytes of B. */
1317 for (i = 28; i < 28 + 8; i++) {
1318 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1319 }
1320
1321 /* And 36 bytes in we should find 3 bytes of C. */
1322 for (i = 36; i < 36 + 3; i++) {
1323 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1324 }
1325
1326 SCFree(p1);
1327 SCFree(p2);
1328 SCFree(p3);
1329 SCFree(reassembled);
1330
1331 DefragDestroy();
1332 PASS;
1333 }
1334
1335 /**
1336 * Test the simplest possible re-assembly scenario. All packet in
1337 * order and no overlaps.
1338 */
1339 static int IPV6DefragInOrderSimpleTest(void)
1340 {
1341 Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1342 Packet *reassembled = NULL;
1343 int id = 12;
1344 int i;
1345
1346 DefragInit();
1347
1348 p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1349 FAIL_IF_NULL(p1);
1350 p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1351 FAIL_IF_NULL(p2);
1352 p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1353 FAIL_IF_NULL(p3);
1354
1355 FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1356 FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1357 reassembled = Defrag(NULL, NULL, p3);
1358 FAIL_IF_NULL(reassembled);
1359
1360 FAIL_IF(IPV6_GET_PLEN(reassembled) != 19);
1361
1362 /* 40 bytes in we should find 8 bytes of A. */
1363 for (i = 40; i < 40 + 8; i++) {
1364 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1365 }
1366
1367 /* 28 bytes in we should find 8 bytes of B. */
1368 for (i = 48; i < 48 + 8; i++) {
1369 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1370 }
1371
1372 /* And 36 bytes in we should find 3 bytes of C. */
1373 for (i = 56; i < 56 + 3; i++) {
1374 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1375 }
1376
1377 SCFree(p1);
1378 SCFree(p2);
1379 SCFree(p3);
1380 SCFree(reassembled);
1381
1382 DefragDestroy();
1383 PASS;
1384 }
1385
1386 static int IPV6DefragReverseSimpleTest(void)
1387 {
1388 DefragContext *dc = NULL;
1389 Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1390 Packet *reassembled = NULL;
1391 int id = 12;
1392 int i;
1393
1394 DefragInit();
1395
1396 dc = DefragContextNew();
1397 FAIL_IF_NULL(dc);
1398
1399 p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1400 FAIL_IF_NULL(p1);
1401 p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1402 FAIL_IF_NULL(p2);
1403 p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1404 FAIL_IF_NULL(p3);
1405
1406 FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1407 FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1408 reassembled = Defrag(NULL, NULL, p1);
1409 FAIL_IF_NULL(reassembled);
1410
1411 /* 40 bytes in we should find 8 bytes of A. */
1412 for (i = 40; i < 40 + 8; i++) {
1413 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1414 }
1415
1416 /* 28 bytes in we should find 8 bytes of B. */
1417 for (i = 48; i < 48 + 8; i++) {
1418 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1419 }
1420
1421 /* And 36 bytes in we should find 3 bytes of C. */
1422 for (i = 56; i < 56 + 3; i++) {
1423 FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1424 }
1425
1426 DefragContextDestroy(dc);
1427 SCFree(p1);
1428 SCFree(p2);
1429 SCFree(p3);
1430 SCFree(reassembled);
1431
1432 DefragDestroy();
1433 PASS;
1434 }
1435
1436 static int DefragDoSturgesNovakTest(int policy, u_char *expected,
1437 size_t expected_len)
1438 {
1439 int i;
1440
1441 DefragInit();
1442
1443 /*
1444 * Build the packets.
1445 */
1446
1447 int id = 1;
1448 Packet *packets[17];
1449 memset(packets, 0x00, sizeof(packets));
1450
1451 /*
1452 * Original fragments.
1453 */
1454
1455 /* A*24 at 0. */
1456 packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
1457
1458 /* B*15 at 32. */
1459 packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
1460
1461 /* C*24 at 48. */
1462 packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
1463
1464 /* D*8 at 80. */
1465 packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
1466
1467 /* E*16 at 104. */
1468 packets[4] = BuildTestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
1469
1470 /* F*24 at 120. */
1471 packets[5] = BuildTestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
1472
1473 /* G*16 at 144. */
1474 packets[6] = BuildTestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
1475
1476 /* H*16 at 160. */
1477 packets[7] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
1478
1479 /* I*8 at 176. */
1480 packets[8] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
1481
1482 /*
1483 * Overlapping subsequent fragments.
1484 */
1485
1486 /* J*32 at 8. */
1487 packets[9] = BuildTestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
1488
1489 /* K*24 at 48. */
1490 packets[10] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
1491
1492 /* L*24 at 72. */
1493 packets[11] = BuildTestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
1494
1495 /* M*24 at 96. */
1496 packets[12] = BuildTestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
1497
1498 /* N*8 at 128. */
1499 packets[13] = BuildTestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
1500
1501 /* O*8 at 152. */
1502 packets[14] = BuildTestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
1503
1504 /* P*8 at 160. */
1505 packets[15] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
1506
1507 /* Q*16 at 176. */
1508 packets[16] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
1509
1510 default_policy = policy;
1511
1512 /* Send all but the last. */
1513 for (i = 0; i < 9; i++) {
1514 Packet *tp = Defrag(NULL, NULL, packets[i]);
1515 FAIL_IF_NOT_NULL(tp);
1516 FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP));
1517 }
1518 int overlap = 0;
1519 for (; i < 16; i++) {
1520 Packet *tp = Defrag(NULL, NULL, packets[i]);
1521 FAIL_IF_NOT_NULL(tp);
1522 if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) {
1523 overlap++;
1524 }
1525 }
1526 FAIL_IF_NOT(overlap);
1527
1528 /* And now the last one. */
1529 Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1530 FAIL_IF_NULL(reassembled);
1531
1532 FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1533 FAIL_IF(IPV4_GET_IPLEN(reassembled) != 20 + 192);
1534
1535 FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0);
1536 SCFree(reassembled);
1537
1538 /* Make sure all frags were returned back to the pool. */
1539 FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1540
1541 for (i = 0; i < 17; i++) {
1542 SCFree(packets[i]);
1543 }
1544 DefragDestroy();
1545 PASS;
1546 }
1547
1548 static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected,
1549 size_t expected_len)
1550 {
1551 int i;
1552
1553 DefragInit();
1554
1555 /*
1556 * Build the packets.
1557 */
1558
1559 int id = 1;
1560 Packet *packets[17];
1561 memset(packets, 0x00, sizeof(packets));
1562
1563 /*
1564 * Original fragments.
1565 */
1566
1567 /* A*24 at 0. */
1568 packets[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
1569
1570 /* B*15 at 32. */
1571 packets[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
1572
1573 /* C*24 at 48. */
1574 packets[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
1575
1576 /* D*8 at 80. */
1577 packets[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
1578
1579 /* E*16 at 104. */
1580 packets[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
1581
1582 /* F*24 at 120. */
1583 packets[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
1584
1585 /* G*16 at 144. */
1586 packets[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
1587
1588 /* H*16 at 160. */
1589 packets[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
1590
1591 /* I*8 at 176. */
1592 packets[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
1593
1594 /*
1595 * Overlapping subsequent fragments.
1596 */
1597
1598 /* J*32 at 8. */
1599 packets[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
1600
1601 /* K*24 at 48. */
1602 packets[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
1603
1604 /* L*24 at 72. */
1605 packets[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
1606
1607 /* M*24 at 96. */
1608 packets[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
1609
1610 /* N*8 at 128. */
1611 packets[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
1612
1613 /* O*8 at 152. */
1614 packets[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
1615
1616 /* P*8 at 160. */
1617 packets[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
1618
1619 /* Q*16 at 176. */
1620 packets[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
1621
1622 default_policy = policy;
1623
1624 /* Send all but the last. */
1625 for (i = 0; i < 9; i++) {
1626 Packet *tp = Defrag(NULL, NULL, packets[i]);
1627 FAIL_IF_NOT_NULL(tp);
1628 FAIL_IF(ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP));
1629 }
1630 int overlap = 0;
1631 for (; i < 16; i++) {
1632 Packet *tp = Defrag(NULL, NULL, packets[i]);
1633 FAIL_IF_NOT_NULL(tp);
1634 if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) {
1635 overlap++;
1636 }
1637 }
1638 FAIL_IF_NOT(overlap);
1639
1640 /* And now the last one. */
1641 Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1642 FAIL_IF_NULL(reassembled);
1643 FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0);
1644
1645 FAIL_IF(IPV6_GET_PLEN(reassembled) != 192);
1646
1647 SCFree(reassembled);
1648
1649 /* Make sure all frags were returned to the pool. */
1650 FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1651
1652 for (i = 0; i < 17; i++) {
1653 SCFree(packets[i]);
1654 }
1655 DefragDestroy();
1656 PASS;
1657 }
1658
1659 static int
1660 DefragSturgesNovakBsdTest(void)
1661 {
1662 /* Expected data. */
1663 u_char expected[] = {
1664 "AAAAAAAA"
1665 "AAAAAAAA"
1666 "AAAAAAAA"
1667 "JJJJJJJJ"
1668 "JJJJJJJJ"
1669 "BBBBBBBB"
1670 "CCCCCCCC"
1671 "CCCCCCCC"
1672 "CCCCCCCC"
1673 "LLLLLLLL"
1674 "LLLLLLLL"
1675 "LLLLLLLL"
1676 "MMMMMMMM"
1677 "MMMMMMMM"
1678 "MMMMMMMM"
1679 "FFFFFFFF"
1680 "FFFFFFFF"
1681 "FFFFFFFF"
1682 "GGGGGGGG"
1683 "GGGGGGGG"
1684 "HHHHHHHH"
1685 "HHHHHHHH"
1686 "IIIIIIII"
1687 "QQQQQQQQ"
1688 };
1689
1690 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1691 sizeof(expected)));
1692 PASS;
1693 }
1694
1695 static int IPV6DefragSturgesNovakBsdTest(void)
1696 {
1697 /* Expected data. */
1698 u_char expected[] = {
1699 "AAAAAAAA"
1700 "AAAAAAAA"
1701 "AAAAAAAA"
1702 "JJJJJJJJ"
1703 "JJJJJJJJ"
1704 "BBBBBBBB"
1705 "CCCCCCCC"
1706 "CCCCCCCC"
1707 "CCCCCCCC"
1708 "LLLLLLLL"
1709 "LLLLLLLL"
1710 "LLLLLLLL"
1711 "MMMMMMMM"
1712 "MMMMMMMM"
1713 "MMMMMMMM"
1714 "FFFFFFFF"
1715 "FFFFFFFF"
1716 "FFFFFFFF"
1717 "GGGGGGGG"
1718 "GGGGGGGG"
1719 "HHHHHHHH"
1720 "HHHHHHHH"
1721 "IIIIIIII"
1722 "QQQQQQQQ"
1723 };
1724
1725 FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1726 sizeof(expected)));
1727 PASS;
1728 }
1729
1730 static int DefragSturgesNovakLinuxIpv4Test(void)
1731 {
1732 /* Expected data. */
1733 u_char expected[] = {
1734 "AAAAAAAA"
1735 "AAAAAAAA"
1736 "AAAAAAAA"
1737 "JJJJJJJJ"
1738 "JJJJJJJJ"
1739 "BBBBBBBB"
1740 "KKKKKKKK"
1741 "KKKKKKKK"
1742 "KKKKKKKK"
1743 "LLLLLLLL"
1744 "LLLLLLLL"
1745 "LLLLLLLL"
1746 "MMMMMMMM"
1747 "MMMMMMMM"
1748 "MMMMMMMM"
1749 "FFFFFFFF"
1750 "FFFFFFFF"
1751 "FFFFFFFF"
1752 "GGGGGGGG"
1753 "GGGGGGGG"
1754 "PPPPPPPP"
1755 "HHHHHHHH"
1756 "QQQQQQQQ"
1757 "QQQQQQQQ"
1758 };
1759
1760 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1761 sizeof(expected)));
1762 PASS;
1763 }
1764
1765 static int IPV6DefragSturgesNovakLinuxTest(void)
1766 {
1767 /* Expected data. */
1768 u_char expected[] = {
1769 "AAAAAAAA"
1770 "AAAAAAAA"
1771 "AAAAAAAA"
1772 "JJJJJJJJ"
1773 "JJJJJJJJ"
1774 "BBBBBBBB"
1775 "KKKKKKKK"
1776 "KKKKKKKK"
1777 "KKKKKKKK"
1778 "LLLLLLLL"
1779 "LLLLLLLL"
1780 "LLLLLLLL"
1781 "MMMMMMMM"
1782 "MMMMMMMM"
1783 "MMMMMMMM"
1784 "FFFFFFFF"
1785 "FFFFFFFF"
1786 "FFFFFFFF"
1787 "GGGGGGGG"
1788 "GGGGGGGG"
1789 "PPPPPPPP"
1790 "HHHHHHHH"
1791 "QQQQQQQQ"
1792 "QQQQQQQQ"
1793 };
1794
1795 FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1796 sizeof(expected)));
1797 PASS;
1798 }
1799
1800 static int DefragSturgesNovakWindowsIpv4Test(void)
1801 {
1802 /* Expected data. */
1803 u_char expected[] = {
1804 "AAAAAAAA"
1805 "AAAAAAAA"
1806 "AAAAAAAA"
1807 "JJJJJJJJ"
1808 "BBBBBBBB"
1809 "BBBBBBBB"
1810 "CCCCCCCC"
1811 "CCCCCCCC"
1812 "CCCCCCCC"
1813 "LLLLLLLL"
1814 "LLLLLLLL"
1815 "LLLLLLLL"
1816 "MMMMMMMM"
1817 "EEEEEEEE"
1818 "EEEEEEEE"
1819 "FFFFFFFF"
1820 "FFFFFFFF"
1821 "FFFFFFFF"
1822 "GGGGGGGG"
1823 "GGGGGGGG"
1824 "HHHHHHHH"
1825 "HHHHHHHH"
1826 "IIIIIIII"
1827 "QQQQQQQQ"
1828 };
1829
1830 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
1831 sizeof(expected)));
1832 PASS;
1833 }
1834
1835 static int IPV6DefragSturgesNovakWindowsTest(void)
1836 {
1837 /* Expected data. */
1838 u_char expected[] = {
1839 "AAAAAAAA"
1840 "AAAAAAAA"
1841 "AAAAAAAA"
1842 "JJJJJJJJ"
1843 "BBBBBBBB"
1844 "BBBBBBBB"
1845 "CCCCCCCC"
1846 "CCCCCCCC"
1847 "CCCCCCCC"
1848 "LLLLLLLL"
1849 "LLLLLLLL"
1850 "LLLLLLLL"
1851 "MMMMMMMM"
1852 "EEEEEEEE"
1853 "EEEEEEEE"
1854 "FFFFFFFF"
1855 "FFFFFFFF"
1856 "FFFFFFFF"
1857 "GGGGGGGG"
1858 "GGGGGGGG"
1859 "HHHHHHHH"
1860 "HHHHHHHH"
1861 "IIIIIIII"
1862 "QQQQQQQQ"
1863 };
1864
1865 FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
1866 sizeof(expected)));
1867 PASS;
1868 }
1869
1870 static int DefragSturgesNovakSolarisTest(void)
1871 {
1872 /* Expected data. */
1873 u_char expected[] = {
1874 "AAAAAAAA"
1875 "AAAAAAAA"
1876 "AAAAAAAA"
1877 "JJJJJJJJ"
1878 "BBBBBBBB"
1879 "BBBBBBBB"
1880 "CCCCCCCC"
1881 "CCCCCCCC"
1882 "CCCCCCCC"
1883 "LLLLLLLL"
1884 "LLLLLLLL"
1885 "LLLLLLLL"
1886 "MMMMMMMM"
1887 "MMMMMMMM"
1888 "MMMMMMMM"
1889 "FFFFFFFF"
1890 "FFFFFFFF"
1891 "FFFFFFFF"
1892 "GGGGGGGG"
1893 "GGGGGGGG"
1894 "HHHHHHHH"
1895 "HHHHHHHH"
1896 "IIIIIIII"
1897 "QQQQQQQQ"
1898 };
1899
1900 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
1901 sizeof(expected)));
1902 PASS;
1903 }
1904
1905 static int IPV6DefragSturgesNovakSolarisTest(void)
1906 {
1907 /* Expected data. */
1908 u_char expected[] = {
1909 "AAAAAAAA"
1910 "AAAAAAAA"
1911 "AAAAAAAA"
1912 "JJJJJJJJ"
1913 "BBBBBBBB"
1914 "BBBBBBBB"
1915 "CCCCCCCC"
1916 "CCCCCCCC"
1917 "CCCCCCCC"
1918 "LLLLLLLL"
1919 "LLLLLLLL"
1920 "LLLLLLLL"
1921 "MMMMMMMM"
1922 "MMMMMMMM"
1923 "MMMMMMMM"
1924 "FFFFFFFF"
1925 "FFFFFFFF"
1926 "FFFFFFFF"
1927 "GGGGGGGG"
1928 "GGGGGGGG"
1929 "HHHHHHHH"
1930 "HHHHHHHH"
1931 "IIIIIIII"
1932 "QQQQQQQQ"
1933 };
1934
1935 FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
1936 sizeof(expected)));
1937 PASS;
1938 }
1939
1940 static int DefragSturgesNovakFirstTest(void)
1941 {
1942 /* Expected data. */
1943 u_char expected[] = {
1944 "AAAAAAAA"
1945 "AAAAAAAA"
1946 "AAAAAAAA"
1947 "JJJJJJJJ"
1948 "BBBBBBBB"
1949 "BBBBBBBB"
1950 "CCCCCCCC"
1951 "CCCCCCCC"
1952 "CCCCCCCC"
1953 "LLLLLLLL"
1954 "DDDDDDDD"
1955 "LLLLLLLL"
1956 "MMMMMMMM"
1957 "EEEEEEEE"
1958 "EEEEEEEE"
1959 "FFFFFFFF"
1960 "FFFFFFFF"
1961 "FFFFFFFF"
1962 "GGGGGGGG"
1963 "GGGGGGGG"
1964 "HHHHHHHH"
1965 "HHHHHHHH"
1966 "IIIIIIII"
1967 "QQQQQQQQ"
1968 };
1969
1970 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
1971 sizeof(expected)));
1972 PASS;
1973 }
1974
1975 static int IPV6DefragSturgesNovakFirstTest(void)
1976 {
1977 /* Expected data. */
1978 u_char expected[] = {
1979 "AAAAAAAA"
1980 "AAAAAAAA"
1981 "AAAAAAAA"
1982 "JJJJJJJJ"
1983 "BBBBBBBB"
1984 "BBBBBBBB"
1985 "CCCCCCCC"
1986 "CCCCCCCC"
1987 "CCCCCCCC"
1988 "LLLLLLLL"
1989 "DDDDDDDD"
1990 "LLLLLLLL"
1991 "MMMMMMMM"
1992 "EEEEEEEE"
1993 "EEEEEEEE"
1994 "FFFFFFFF"
1995 "FFFFFFFF"
1996 "FFFFFFFF"
1997 "GGGGGGGG"
1998 "GGGGGGGG"
1999 "HHHHHHHH"
2000 "HHHHHHHH"
2001 "IIIIIIII"
2002 "QQQQQQQQ"
2003 };
2004
2005 return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
2006 sizeof(expected));
2007 }
2008
2009 static int
2010 DefragSturgesNovakLastTest(void)
2011 {
2012 /* Expected data. */
2013 u_char expected[] = {
2014 "AAAAAAAA"
2015 "JJJJJJJJ"
2016 "JJJJJJJJ"
2017 "JJJJJJJJ"
2018 "JJJJJJJJ"
2019 "BBBBBBBB"
2020 "KKKKKKKK"
2021 "KKKKKKKK"
2022 "KKKKKKKK"
2023 "LLLLLLLL"
2024 "LLLLLLLL"
2025 "LLLLLLLL"
2026 "MMMMMMMM"
2027 "MMMMMMMM"
2028 "MMMMMMMM"
2029 "FFFFFFFF"
2030 "NNNNNNNN"
2031 "FFFFFFFF"
2032 "GGGGGGGG"
2033 "OOOOOOOO"
2034 "PPPPPPPP"
2035 "HHHHHHHH"
2036 "QQQQQQQQ"
2037 "QQQQQQQQ"
2038 };
2039
2040 FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2041 sizeof(expected)));
2042 PASS;
2043 }
2044
2045 static int IPV6DefragSturgesNovakLastTest(void)
2046 {
2047 /* Expected data. */
2048 u_char expected[] = {
2049 "AAAAAAAA"
2050 "JJJJJJJJ"
2051 "JJJJJJJJ"
2052 "JJJJJJJJ"
2053 "JJJJJJJJ"
2054 "BBBBBBBB"
2055 "KKKKKKKK"
2056 "KKKKKKKK"
2057 "KKKKKKKK"
2058 "LLLLLLLL"
2059 "LLLLLLLL"
2060 "LLLLLLLL"
2061 "MMMMMMMM"
2062 "MMMMMMMM"
2063 "MMMMMMMM"
2064 "FFFFFFFF"
2065 "NNNNNNNN"
2066 "FFFFFFFF"
2067 "GGGGGGGG"
2068 "OOOOOOOO"
2069 "PPPPPPPP"
2070 "HHHHHHHH"
2071 "QQQQQQQQ"
2072 "QQQQQQQQ"
2073 };
2074
2075 FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2076 sizeof(expected)));
2077 PASS;
2078 }
2079
2080 static int DefragTimeoutTest(void)
2081 {
2082 int i;
2083
2084 /* Setup a small numberr of trackers. */
2085 FAIL_IF_NOT(ConfSet("defrag.trackers", "16"));
2086
2087 DefragInit();
2088
2089 /* Load in 16 packets. */
2090 for (i = 0; i < 16; i++) {
2091 Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16);
2092 FAIL_IF_NULL(p);
2093
2094 Packet *tp = Defrag(NULL, NULL, p);
2095 SCFree(p);
2096 FAIL_IF_NOT_NULL(tp);
2097 }
2098
2099 /* Build a new packet but push the timestamp out by our timeout.
2100 * This should force our previous fragments to be timed out. */
2101 Packet *p = BuildTestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
2102 FAIL_IF_NULL(p);
2103
2104 p->ts.tv_sec += (defrag_context->timeout + 1);
2105 Packet *tp = Defrag(NULL, NULL, p);
2106 FAIL_IF_NOT_NULL(tp);
2107
2108 DefragTracker *tracker = DefragLookupTrackerFromHash(p);
2109 FAIL_IF_NULL(tracker);
2110
2111 FAIL_IF(tracker->id != 99);
2112
2113 SCMutexUnlock(&tracker->lock);
2114 SCFree(p);
2115
2116 DefragDestroy();
2117 PASS;
2118 }
2119
2120 /**
2121 * QA found that if you send a packet where more frags is 0, offset is
2122 * > 0 and there is no data in the packet that the re-assembler will
2123 * fail. The fix was simple, but this unit test is just to make sure
2124 * its not introduced.
2125 */
2126 static int DefragIPv4NoDataTest(void)
2127 {
2128 DefragContext *dc = NULL;
2129 Packet *p = NULL;
2130 int id = 12;
2131
2132 DefragInit();
2133
2134 dc = DefragContextNew();
2135 FAIL_IF_NULL(dc);
2136
2137 /* This packet has an offset > 0, more frags set to 0 and no data. */
2138 p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
2139 FAIL_IF_NULL(p);
2140
2141 /* We do not expect a packet returned. */
2142 FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2143
2144 /* The fragment should have been ignored so no fragments should
2145 * have been allocated from the pool. */
2146 FAIL_IF(dc->frag_pool->outstanding != 0);
2147
2148 DefragContextDestroy(dc);
2149 SCFree(p);
2150
2151 DefragDestroy();
2152 PASS;
2153 }
2154
2155 static int DefragIPv4TooLargeTest(void)
2156 {
2157 DefragContext *dc = NULL;
2158 Packet *p = NULL;
2159
2160 DefragInit();
2161
2162 dc = DefragContextNew();
2163 FAIL_IF_NULL(dc);
2164
2165 /* Create a fragment that would extend past the max allowable size
2166 * for an IPv4 packet. */
2167 p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
2168 FAIL_IF_NULL(p);
2169
2170 /* We do not expect a packet returned. */
2171 FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2172
2173 /* We do expect an event. */
2174 FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, IPV4_FRAG_PKT_TOO_LARGE));
2175
2176 /* The fragment should have been ignored so no fragments should have
2177 * been allocated from the pool. */
2178 FAIL_IF(dc->frag_pool->outstanding != 0);
2179
2180 DefragContextDestroy(dc);
2181 SCFree(p);
2182
2183 DefragDestroy();
2184 PASS;
2185 }
2186
2187 /**
2188 * Test that fragments in different VLANs that would otherwise be
2189 * re-assembled, are not re-assembled. Just use simple in-order
2190 * fragments.
2191 */
2192 static int DefragVlanTest(void)
2193 {
2194 Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2195
2196 DefragInit();
2197
2198 p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2199 FAIL_IF_NULL(p1);
2200 p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2201 FAIL_IF_NULL(p2);
2202
2203 /* With no VLAN IDs set, packets should re-assemble. */
2204 FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2205 FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2206 SCFree(r);
2207
2208 /* With mismatched VLANs, packets should not re-assemble. */
2209 p1->vlan_id[0] = 1;
2210 p2->vlan_id[0] = 2;
2211 FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2212 FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2213
2214 SCFree(p1);
2215 SCFree(p2);
2216 DefragDestroy();
2217
2218 PASS;
2219 }
2220
2221 /**
2222 * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID.
2223 */
2224 static int DefragVlanQinQTest(void)
2225 {
2226 Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2227
2228 DefragInit();
2229
2230 p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2231 FAIL_IF_NULL(p1);
2232 p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2233 FAIL_IF_NULL(p2);
2234
2235 /* With no VLAN IDs set, packets should re-assemble. */
2236 FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2237 FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2238 SCFree(r);
2239
2240 /* With mismatched VLANs, packets should not re-assemble. */
2241 p1->vlan_id[0] = 1;
2242 p2->vlan_id[0] = 1;
2243 p1->vlan_id[1] = 1;
2244 p2->vlan_id[1] = 2;
2245 FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2246 FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2247
2248 SCFree(p1);
2249 SCFree(p2);
2250 DefragDestroy();
2251
2252 PASS;
2253 }
2254
2255 static int DefragTrackerReuseTest(void)
2256 {
2257 int id = 1;
2258 Packet *p1 = NULL;
2259 DefragTracker *tracker1 = NULL, *tracker2 = NULL;
2260
2261 DefragInit();
2262
2263 /* Build a packet, its not a fragment but shouldn't matter for
2264 * this test. */
2265 p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
2266 FAIL_IF_NULL(p1);
2267
2268 /* Get a tracker. It shouldn't look like its already in use. */
2269 tracker1 = DefragGetTracker(NULL, NULL, p1);
2270 FAIL_IF_NULL(tracker1);
2271 FAIL_IF(tracker1->seen_last);
2272 FAIL_IF(tracker1->remove);
2273 DefragTrackerRelease(tracker1);
2274
2275 /* Get a tracker again, it should be the same one. */
2276 tracker2 = DefragGetTracker(NULL, NULL, p1);
2277 FAIL_IF_NULL(tracker2);
2278 FAIL_IF(tracker2 != tracker1);
2279 DefragTrackerRelease(tracker1);
2280
2281 /* Now mark the tracker for removal. It should not be returned
2282 * when we get a tracker for a packet that may have the same
2283 * attributes. */
2284 tracker1->remove = 1;
2285
2286 tracker2 = DefragGetTracker(NULL, NULL, p1);
2287 FAIL_IF_NULL(tracker2);
2288 FAIL_IF(tracker2 == tracker1);
2289 FAIL_IF(tracker2->remove);
2290
2291 SCFree(p1);
2292 DefragDestroy();
2293 PASS;
2294 }
2295
2296 /**
2297 * IPV4: Test the case where you have a packet fragmented in 3 parts
2298 * and send like:
2299 * - Offset: 2; MF: 1
2300 * - Offset: 0; MF: 1
2301 * - Offset: 1; MF: 0
2302 *
2303 * Only the fragments with offset 0 and 1 should be reassembled.
2304 */
2305 static int DefragMfIpv4Test(void)
2306 {
2307 int ip_id = 9;
2308 Packet *p = NULL;
2309
2310 DefragInit();
2311
2312 Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
2313 Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
2314 Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
2315 FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2316
2317 p = Defrag(NULL, NULL, p1);
2318 FAIL_IF_NOT_NULL(p);
2319
2320 p = Defrag(NULL, NULL, p2);
2321 FAIL_IF_NOT_NULL(p);
2322
2323 /* This should return a packet as MF=0. */
2324 p = Defrag(NULL, NULL, p3);
2325 FAIL_IF_NULL(p);
2326
2327 /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the
2328 * fragments should be in the re-assembled packet. */
2329 FAIL_IF(IPV4_GET_IPLEN(p) != 36);
2330
2331 SCFree(p1);
2332 SCFree(p2);
2333 SCFree(p3);
2334 SCFree(p);
2335 DefragDestroy();
2336 PASS;
2337 }
2338
2339 /**
2340 * IPV6: Test the case where you have a packet fragmented in 3 parts
2341 * and send like:
2342 * - Offset: 2; MF: 1
2343 * - Offset: 0; MF: 1
2344 * - Offset: 1; MF: 0
2345 *
2346 * Only the fragments with offset 0 and 1 should be reassembled.
2347 */
2348 static int DefragMfIpv6Test(void)
2349 {
2350 int ip_id = 9;
2351 Packet *p = NULL;
2352
2353 DefragInit();
2354
2355 Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
2356 Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
2357 Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
2358 FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2359
2360 p = Defrag(NULL, NULL, p1);
2361 FAIL_IF_NOT_NULL(p);
2362
2363 p = Defrag(NULL, NULL, p2);
2364 FAIL_IF_NOT_NULL(p);
2365
2366 /* This should return a packet as MF=0. */
2367 p = Defrag(NULL, NULL, p3);
2368 FAIL_IF_NULL(p);
2369
2370 /* For IPv6 the expected length is just the length of the payload
2371 * of 2 fragments, so 16. */
2372 FAIL_IF(IPV6_GET_PLEN(p) != 16);
2373
2374 SCFree(p1);
2375 SCFree(p2);
2376 SCFree(p3);
2377 SCFree(p);
2378 DefragDestroy();
2379 PASS;
2380 }
2381
2382 /**
2383 * \brief Test that fragments that match other than the proto don't
2384 * actually get matched.
2385 */
2386 static int DefragTestBadProto(void)
2387 {
2388 Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
2389 int id = 12;
2390
2391 DefragInit();
2392
2393 p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
2394 FAIL_IF_NULL(p1);
2395 p2 = BuildTestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
2396 FAIL_IF_NULL(p2);
2397 p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
2398 FAIL_IF_NULL(p3);
2399
2400 FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1));
2401 FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p2));
2402 FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p3));
2403
2404 SCFree(p1);
2405 SCFree(p2);
2406 SCFree(p3);
2407
2408 DefragDestroy();
2409 PASS;
2410 }
2411
2412 /**
2413 * \test Test a report Linux overlap issue that doesn't appear to be
2414 * covered by the Sturges/Novak tests above.
2415 */
2416 static int DefragTestJeremyLinux(void)
2417 {
2418 char expected[] = "AAAAAAAA"
2419 "AAAAAAAA"
2420 "AAAAAAAA"
2421 "CCCCCCCC"
2422 "CCCCCCCC"
2423 "CCCCCCCC"
2424 "CCCCCCCC"
2425 "CCCCCCCC"
2426 "CCCCCCCC"
2427 "BBBBBBBB"
2428 "BBBBBBBB"
2429 "DDDDDDDD"
2430 "DDDDDD";
2431
2432 DefragInit();
2433 default_policy = DEFRAG_POLICY_LINUX;
2434
2435 int id = 1;
2436 Packet *packets[4];
2437 int i = 0;
2438
2439 packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
2440 packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
2441 packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
2442 packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
2443
2444 Packet *r = Defrag(NULL, NULL, packets[0]);
2445 FAIL_IF_NOT_NULL(r);
2446
2447 r = Defrag(NULL, NULL, packets[1]);
2448 FAIL_IF_NOT_NULL(r);
2449
2450 r = Defrag(NULL, NULL, packets[2]);
2451 FAIL_IF_NOT_NULL(r);
2452
2453 r = Defrag(NULL, NULL, packets[3]);
2454 FAIL_IF_NULL(r);
2455
2456 FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0);
2457
2458 for (i = 0; i < 4; i++) {
2459 SCFree(packets[i]);
2460 }
2461 SCFree(r);
2462
2463 DefragDestroy();
2464 PASS;
2465 }
2466
2467 #endif /* UNITTESTS */
2468
2469 void DefragRegisterTests(void)
2470 {
2471 #ifdef UNITTESTS
2472 UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest);
2473 UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest);
2474 UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest);
2475 UtRegisterTest("DefragSturgesNovakLinuxIpv4Test",
2476 DefragSturgesNovakLinuxIpv4Test);
2477 UtRegisterTest("DefragSturgesNovakWindowsIpv4Test",
2478 DefragSturgesNovakWindowsIpv4Test);
2479 UtRegisterTest("DefragSturgesNovakSolarisTest",
2480 DefragSturgesNovakSolarisTest);
2481 UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
2482 UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
2483
2484 UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest);
2485 UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest);
2486
2487 UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest);
2488 UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest);
2489 UtRegisterTest("IPV6DefragSturgesNovakBsdTest",
2490 IPV6DefragSturgesNovakBsdTest);
2491 UtRegisterTest("IPV6DefragSturgesNovakLinuxTest",
2492 IPV6DefragSturgesNovakLinuxTest);
2493 UtRegisterTest("IPV6DefragSturgesNovakWindowsTest",
2494 IPV6DefragSturgesNovakWindowsTest);
2495 UtRegisterTest("IPV6DefragSturgesNovakSolarisTest",
2496 IPV6DefragSturgesNovakSolarisTest);
2497 UtRegisterTest("IPV6DefragSturgesNovakFirstTest",
2498 IPV6DefragSturgesNovakFirstTest);
2499 UtRegisterTest("IPV6DefragSturgesNovakLastTest",
2500 IPV6DefragSturgesNovakLastTest);
2501
2502 UtRegisterTest("DefragVlanTest", DefragVlanTest);
2503 UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
2504 UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest);
2505 UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest);
2506 UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test);
2507 UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test);
2508 UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
2509
2510 UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux);
2511 #endif /* UNITTESTS */
2512 }