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