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