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