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