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