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  PacketInit(p);
1162 
1163  struct timeval tval;
1164  gettimeofday(&tval, NULL);
1165  p->ts = SCTIME_FROM_TIMEVAL(&tval);
1166  //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1167  ip4h.ip_verhl = 4 << 4;
1168  ip4h.ip_verhl |= hlen >> 2;
1169  ip4h.ip_len = htons(hlen + content_len);
1170  ip4h.ip_id = htons(id);
1171  if (mf)
1172  ip4h.ip_off = htons(IP_MF | off);
1173  else
1174  ip4h.ip_off = htons(off);
1175  ip4h.ip_ttl = ttl;
1176  ip4h.ip_proto = proto;
1177 
1178  ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1179  ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1180 
1181  /* copy content_len crap, we need full length */
1182  PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1183  IPV4Hdr *ip4p = PacketSetIPV4(p, GET_PKT_DATA(p));
1184  SET_IPV4_SRC_ADDR(ip4p, &p->src);
1185  SET_IPV4_DST_ADDR(ip4p, &p->dst);
1186 
1187  pcontent = SCCalloc(1, content_len);
1188  if (unlikely(pcontent == NULL))
1189  return NULL;
1190  memset(pcontent, content, content_len);
1191  PacketCopyDataOffset(p, hlen, pcontent, content_len);
1192  SET_PKT_LEN(p, hlen + content_len);
1193  SCFree(pcontent);
1194 
1195  ip4p->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1196 
1197  /* Self test. */
1198  FAIL_IF(IPV4_GET_RAW_VER(ip4p) != 4);
1199  FAIL_IF(IPV4_GET_RAW_HLEN(ip4p) != hlen);
1200  FAIL_IF(IPV4_GET_RAW_IPLEN(ip4p) != hlen + content_len);
1201  FAIL_IF(IPV4_GET_RAW_IPID(ip4p) != id);
1202  FAIL_IF(IPV4_GET_RAW_FRAGOFFSET(ip4p) != off);
1203  FAIL_IF(IPV4_GET_RAW_FLAG_MF(ip4p) != mf);
1204  FAIL_IF(IPV4_GET_RAW_IPTTL(ip4p) != ttl);
1206 
1207  return p;
1208 }
1209 
1210 /**
1211  * Allocate a test packet, much like BuildIpv4TestPacket, but with
1212  * the full content provided by the caller.
1213  */
1214 static int BuildIpv4TestPacketWithContent(Packet **packet, uint8_t proto, uint16_t id, uint16_t off,
1215  int mf, const uint8_t *content, int content_len)
1216 {
1217  Packet *p = NULL;
1218  int hlen = 20;
1219  int ttl = 64;
1220  IPV4Hdr ip4h;
1221 
1222  p = SCCalloc(1, sizeof(*p) + default_packet_size);
1223  FAIL_IF_NULL(p);
1224 
1225  PacketInit(p);
1226 
1227  struct timeval tval;
1228  gettimeofday(&tval, NULL);
1229  p->ts = SCTIME_FROM_TIMEVAL(&tval);
1230  ip4h.ip_verhl = 4 << 4;
1231  ip4h.ip_verhl |= hlen >> 2;
1232  ip4h.ip_len = htons(hlen + content_len);
1233  ip4h.ip_id = htons(id);
1234  if (mf)
1235  ip4h.ip_off = htons(IP_MF | off);
1236  else
1237  ip4h.ip_off = htons(off);
1238  ip4h.ip_ttl = ttl;
1239  ip4h.ip_proto = proto;
1240 
1241  ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1242  ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1243 
1244  /* copy content_len crap, we need full length */
1245  PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1246  IPV4Hdr *ip4p = PacketSetIPV4(p, GET_PKT_DATA(p));
1247  SET_IPV4_SRC_ADDR(ip4p, &p->src);
1248  SET_IPV4_DST_ADDR(ip4p, &p->dst);
1249 
1250  PacketCopyDataOffset(p, hlen, content, content_len);
1251  SET_PKT_LEN(p, hlen + content_len);
1252 
1253  ip4p->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1254 
1255  /* Self test. */
1256  FAIL_IF(IPV4_GET_RAW_VER(ip4p) != 4);
1257  FAIL_IF(IPV4_GET_RAW_HLEN(ip4p) != hlen);
1258  FAIL_IF(IPV4_GET_RAW_IPLEN(ip4p) != hlen + content_len);
1259  FAIL_IF(IPV4_GET_RAW_IPID(ip4p) != id);
1260  FAIL_IF(IPV4_GET_RAW_FRAGOFFSET(ip4p) != off);
1261  FAIL_IF(IPV4_GET_RAW_FLAG_MF(ip4p) != mf);
1262  FAIL_IF(IPV4_GET_RAW_IPTTL(ip4p) != ttl);
1264 
1265  *packet = p;
1266  PASS;
1267 }
1268 
1269 static Packet *BuildIpv6TestPacket(
1270  uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t content, int content_len)
1271 {
1272  Packet *p = NULL;
1273  uint8_t *pcontent;
1274  IPV6Hdr ip6h;
1275 
1276  p = SCCalloc(1, sizeof(*p) + default_packet_size);
1277  if (unlikely(p == NULL))
1278  return NULL;
1279 
1280  PacketInit(p);
1281 
1282  struct timeval tval;
1283  gettimeofday(&tval, NULL);
1284  p->ts = SCTIME_FROM_TIMEVAL(&tval);
1285 
1286  ip6h.s_ip6_nxt = 44;
1287  ip6h.s_ip6_hlim = 2;
1288 
1289  /* Source and dest address - very bogus addresses. */
1290  ip6h.s_ip6_src[0] = 0x01010101;
1291  ip6h.s_ip6_src[1] = 0x01010101;
1292  ip6h.s_ip6_src[2] = 0x01010101;
1293  ip6h.s_ip6_src[3] = 0x01010101;
1294  ip6h.s_ip6_dst[0] = 0x02020202;
1295  ip6h.s_ip6_dst[1] = 0x02020202;
1296  ip6h.s_ip6_dst[2] = 0x02020202;
1297  ip6h.s_ip6_dst[3] = 0x02020202;
1298 
1299  /* copy content_len crap, we need full length */
1300  PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1301 
1302  IPV6Hdr *ip6p = PacketSetIPV6(p, GET_PKT_DATA(p));
1303  IPV6_SET_RAW_VER(ip6p, 6);
1304  /* Fragmentation header. */
1305  IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1306  fh->ip6fh_nxt = proto;
1307  fh->ip6fh_ident = htonl(id);
1308  fh->ip6fh_offlg = htons((off << 3) | mf);
1309 
1310  DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1311 
1312  pcontent = SCCalloc(1, content_len);
1313  if (unlikely(pcontent == NULL))
1314  return NULL;
1315  memset(pcontent, content, content_len);
1316  PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), pcontent, content_len);
1317  SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1318  SCFree(pcontent);
1319 
1320  ip6p->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1321 
1322  SET_IPV6_SRC_ADDR(ip6p, &p->src);
1323  SET_IPV6_DST_ADDR(ip6p, &p->dst);
1324 
1325  /* Self test. */
1326  if (IPV6_GET_RAW_VER(ip6p) != 6)
1327  goto error;
1328  if (IPV6_GET_RAW_NH(ip6p) != 44)
1329  goto error;
1330  if (IPV6_GET_RAW_PLEN(ip6p) != sizeof(IPV6FragHdr) + content_len)
1331  goto error;
1332 
1333  return p;
1334 error:
1335  if (p != NULL)
1336  PacketFree(p);
1337  return NULL;
1338 }
1339 
1340 static Packet *BuildIpv6TestPacketWithContent(
1341  uint8_t proto, uint32_t id, uint16_t off, int mf, const uint8_t *content, int content_len)
1342 {
1343  Packet *p = NULL;
1344  IPV6Hdr ip6h;
1345 
1346  p = SCCalloc(1, sizeof(*p) + default_packet_size);
1347  if (unlikely(p == NULL))
1348  return NULL;
1349 
1350  PacketInit(p);
1351 
1352  struct timeval tval;
1353  gettimeofday(&tval, NULL);
1354  p->ts = SCTIME_FROM_TIMEVAL(&tval);
1355 
1356  ip6h.s_ip6_nxt = 44;
1357  ip6h.s_ip6_hlim = 2;
1358 
1359  /* Source and dest address - very bogus addresses. */
1360  ip6h.s_ip6_src[0] = 0x01010101;
1361  ip6h.s_ip6_src[1] = 0x01010101;
1362  ip6h.s_ip6_src[2] = 0x01010101;
1363  ip6h.s_ip6_src[3] = 0x01010101;
1364  ip6h.s_ip6_dst[0] = 0x02020202;
1365  ip6h.s_ip6_dst[1] = 0x02020202;
1366  ip6h.s_ip6_dst[2] = 0x02020202;
1367  ip6h.s_ip6_dst[3] = 0x02020202;
1368 
1369  /* copy content_len crap, we need full length */
1370  PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1371 
1372  IPV6Hdr *ip6p = PacketSetIPV6(p, GET_PKT_DATA(p));
1373  IPV6_SET_RAW_VER(ip6p, 6);
1374  /* Fragmentation header. */
1375  IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1376  fh->ip6fh_nxt = proto;
1377  fh->ip6fh_ident = htonl(id);
1378  fh->ip6fh_offlg = htons((off << 3) | mf);
1379 
1380  DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1381 
1382  PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), content, content_len);
1383  SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1384 
1385  ip6p->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1386 
1387  SET_IPV6_SRC_ADDR(ip6p, &p->src);
1388  SET_IPV6_DST_ADDR(ip6p, &p->dst);
1389 
1390  /* Self test. */
1391  if (IPV6_GET_RAW_VER(ip6p) != 6)
1392  goto error;
1393  if (IPV6_GET_RAW_NH(ip6p) != 44)
1394  goto error;
1395  if (IPV6_GET_RAW_PLEN(ip6p) != sizeof(IPV6FragHdr) + content_len)
1396  goto error;
1397 
1398  return p;
1399 error:
1400  if (p != NULL)
1401  PacketFree(p);
1402  return NULL;
1403 }
1404 
1405 /**
1406  * Test the simplest possible re-assembly scenario. All packet in
1407  * order and no overlaps.
1408  */
1409 static int DefragInOrderSimpleTest(void)
1410 {
1411  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1412  Packet *reassembled = NULL;
1413  int id = 12;
1414 
1415  DefragInit();
1416 
1417  p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1418  FAIL_IF_NULL(p1);
1419  p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1420  FAIL_IF_NULL(p2);
1421  p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1422  FAIL_IF_NULL(p3);
1423 
1424  FAIL_IF(Defrag(&test_tv, &test_dtv, p1) != NULL);
1425  FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1426 
1427  reassembled = Defrag(&test_tv, &test_dtv, p3);
1428  FAIL_IF_NULL(reassembled);
1429 
1430  FAIL_IF(IPV4_GET_RAW_HLEN(PacketGetIPv4(reassembled)) != 20);
1431  FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(reassembled)) != 39);
1432 
1433  /* 20 bytes in we should find 8 bytes of A. */
1434  for (int i = 20; i < 20 + 8; i++) {
1435  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1436  }
1437 
1438  /* 28 bytes in we should find 8 bytes of B. */
1439  for (int i = 28; i < 28 + 8; i++) {
1440  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1441  }
1442 
1443  /* And 36 bytes in we should find 3 bytes of C. */
1444  for (int i = 36; i < 36 + 3; i++) {
1445  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1446  }
1447 
1448  PacketFree(p1);
1449  PacketFree(p2);
1450  PacketFree(p3);
1451  PacketFree(reassembled);
1452 
1453  DefragDestroy();
1454  PASS;
1455 }
1456 
1457 /**
1458  * Simple fragmented packet in reverse order.
1459  */
1460 static int DefragReverseSimpleTest(void)
1461 {
1462  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1463  Packet *reassembled = NULL;
1464  int id = 12;
1465 
1466  DefragInit();
1467 
1468  p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1469  FAIL_IF_NULL(p1);
1470  p2 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1471  FAIL_IF_NULL(p2);
1472  p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1473  FAIL_IF_NULL(p3);
1474 
1475  FAIL_IF(Defrag(&test_tv, &test_dtv, p3) != NULL);
1476  FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1477  reassembled = Defrag(&test_tv, &test_dtv, p1);
1478  FAIL_IF_NULL(reassembled);
1479 
1480  FAIL_IF(IPV4_GET_RAW_HLEN(PacketGetIPv4(reassembled)) != 20);
1481  FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(reassembled)) != 39);
1482 
1483  /* 20 bytes in we should find 8 bytes of A. */
1484  for (int i = 20; i < 20 + 8; i++) {
1485  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1486  }
1487 
1488  /* 28 bytes in we should find 8 bytes of B. */
1489  for (int i = 28; i < 28 + 8; i++) {
1490  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1491  }
1492 
1493  /* And 36 bytes in we should find 3 bytes of C. */
1494  for (int i = 36; i < 36 + 3; i++) {
1495  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1496  }
1497 
1498  PacketFree(p1);
1499  PacketFree(p2);
1500  PacketFree(p3);
1501  PacketFree(reassembled);
1502 
1503  DefragDestroy();
1504  PASS;
1505 }
1506 
1507 /**
1508  * Test the simplest possible re-assembly scenario. All packet in
1509  * order and no overlaps.
1510  */
1511 static int DefragInOrderSimpleIpv6Test(void)
1512 {
1513  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1514  Packet *reassembled = NULL;
1515  int id = 12;
1516 
1517  DefragInit();
1518 
1519  p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1520  FAIL_IF_NULL(p1);
1521  p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1522  FAIL_IF_NULL(p2);
1523  p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1524  FAIL_IF_NULL(p3);
1525 
1526  FAIL_IF(Defrag(&test_tv, &test_dtv, p1) != NULL);
1527  FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1528  reassembled = Defrag(&test_tv, &test_dtv, p3);
1529  FAIL_IF_NULL(reassembled);
1530 
1531  const IPV6Hdr *ip6h = PacketGetIPv6(reassembled);
1532  FAIL_IF(IPV6_GET_RAW_PLEN(ip6h) != 19);
1533 
1534  /* 40 bytes in we should find 8 bytes of A. */
1535  for (int i = 40; i < 40 + 8; i++) {
1536  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1537  }
1538 
1539  /* 28 bytes in we should find 8 bytes of B. */
1540  for (int i = 48; i < 48 + 8; i++) {
1541  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1542  }
1543 
1544  /* And 36 bytes in we should find 3 bytes of C. */
1545  for (int i = 56; i < 56 + 3; i++) {
1546  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1547  }
1548 
1549  PacketFree(p1);
1550  PacketFree(p2);
1551  PacketFree(p3);
1552  PacketFree(reassembled);
1553 
1554  DefragDestroy();
1555  PASS;
1556 }
1557 
1558 static int DefragReverseSimpleIpv6Test(void)
1559 {
1560  DefragContext *dc = NULL;
1561  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1562  Packet *reassembled = NULL;
1563  int id = 12;
1564 
1565  DefragInit();
1566 
1567  dc = DefragContextNew();
1568  FAIL_IF_NULL(dc);
1569 
1570  p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1571  FAIL_IF_NULL(p1);
1572  p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1573  FAIL_IF_NULL(p2);
1574  p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1575  FAIL_IF_NULL(p3);
1576 
1577  FAIL_IF(Defrag(&test_tv, &test_dtv, p3) != NULL);
1578  FAIL_IF(Defrag(&test_tv, &test_dtv, p2) != NULL);
1579  reassembled = Defrag(&test_tv, &test_dtv, p1);
1580  FAIL_IF_NULL(reassembled);
1581 
1582  /* 40 bytes in we should find 8 bytes of A. */
1583  for (int i = 40; i < 40 + 8; i++) {
1584  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1585  }
1586 
1587  /* 28 bytes in we should find 8 bytes of B. */
1588  for (int i = 48; i < 48 + 8; i++) {
1589  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1590  }
1591 
1592  /* And 36 bytes in we should find 3 bytes of C. */
1593  for (int i = 56; i < 56 + 3; i++) {
1594  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1595  }
1596 
1597  DefragContextDestroy(dc);
1598  PacketFree(p1);
1599  PacketFree(p2);
1600  PacketFree(p3);
1601  PacketFree(reassembled);
1602 
1603  DefragDestroy();
1604  PASS;
1605 }
1606 
1607 static int DefragDoSturgesNovakTest(int policy, uint8_t *expected, size_t expected_len)
1608 {
1609  int i;
1610 
1611  DefragInit();
1612 
1613  /*
1614  * Build the packets.
1615  */
1616 
1617  int id = 1;
1618  Packet *packets[17];
1619  memset(packets, 0x00, sizeof(packets));
1620 
1621  /*
1622  * Original fragments.
1623  */
1624 
1625  /* <1> A*24 at 0. */
1626  packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
1627 
1628  /* <2> B*16 at 32. */
1629  packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
1630 
1631  /* <3> C*24 at 48. */
1632  packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
1633 
1634  /* <3_1> D*8 at 80. */
1635  packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
1636 
1637  /* <3_2> E*16 at 104. */
1638  packets[4] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
1639 
1640  /* <3_3> F*24 at 120. */
1641  packets[5] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
1642 
1643  /* <3_4> G*16 at 144. */
1644  packets[6] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
1645 
1646  /* <3_5> H*16 at 160. */
1647  packets[7] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
1648 
1649  /* <3_6> I*8 at 176. */
1650  packets[8] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
1651 
1652  /*
1653  * Overlapping subsequent fragments.
1654  */
1655 
1656  /* <4> J*32 at 8. */
1657  packets[9] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
1658 
1659  /* <5> K*24 at 48. */
1660  packets[10] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
1661 
1662  /* <6> L*24 at 72. */
1663  packets[11] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
1664 
1665  /* <7> M*24 at 96. */
1666  packets[12] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
1667 
1668  /* <8> N*8 at 128. */
1669  packets[13] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
1670 
1671  /* <9> O*8 at 152. */
1672  packets[14] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
1673 
1674  /* <10> P*8 at 160. */
1675  packets[15] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
1676 
1677  /* <11> Q*16 at 176. */
1678  packets[16] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
1679 
1680  default_policy = policy;
1681 
1682  /* Send all but the last. */
1683  for (i = 0; i < 9; i++) {
1684  Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
1685  FAIL_IF_NOT_NULL(tp);
1687  }
1688  int overlap = 0;
1689  for (; i < 16; i++) {
1690  Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
1691  FAIL_IF_NOT_NULL(tp);
1692  if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) {
1693  overlap++;
1694  }
1695  }
1696  FAIL_IF_NOT(overlap);
1697 
1698  /* And now the last one. */
1699  Packet *reassembled = Defrag(&test_tv, &test_dtv, packets[16]);
1700  FAIL_IF_NULL(reassembled);
1701 
1702  FAIL_IF(IPV4_GET_RAW_HLEN(PacketGetIPv4(reassembled)) != 20);
1703  FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(reassembled)) != 20 + 192);
1704  FAIL_IF(expected_len != 192);
1705 
1706  if (memcmp(expected, GET_PKT_DATA(reassembled) + 20, expected_len) != 0) {
1707  printf("Expected:\n");
1708  PrintRawDataFp(stdout, expected, expected_len);
1709  printf("Got:\n");
1710  PrintRawDataFp(stdout, GET_PKT_DATA(reassembled) + 20, GET_PKT_LEN(reassembled) - 20);
1711  FAIL;
1712  }
1713  PacketFree(reassembled);
1714 
1715  /* Make sure all frags were returned back to the pool. */
1716  FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1717 
1718  for (i = 0; i < 17; i++) {
1719  PacketFree(packets[i]);
1720  }
1721  DefragDestroy();
1722  PASS;
1723 }
1724 
1725 static int DefragDoSturgesNovakIpv6Test(int policy, uint8_t *expected, size_t expected_len)
1726 {
1727  int i;
1728 
1729  DefragInit();
1730 
1731  /*
1732  * Build the packets.
1733  */
1734 
1735  int id = 1;
1736  Packet *packets[17];
1737  memset(packets, 0x00, sizeof(packets));
1738 
1739  /*
1740  * Original fragments.
1741  */
1742 
1743  /* <1> A*24 at 0. */
1744  packets[0] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
1745 
1746  /* <2> B*16 at 32. */
1747  packets[1] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
1748 
1749  /* <3> C*24 at 48. */
1750  packets[2] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
1751 
1752  /* <3_1> D*8 at 80. */
1753  packets[3] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
1754 
1755  /* <3_2> E*16 at 104. */
1756  packets[4] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
1757 
1758  /* <3_3> F*24 at 120. */
1759  packets[5] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
1760 
1761  /* <3_4> G*16 at 144. */
1762  packets[6] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
1763 
1764  /* <3_5> H*16 at 160. */
1765  packets[7] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
1766 
1767  /* <3_6> I*8 at 176. */
1768  packets[8] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
1769 
1770  /*
1771  * Overlapping subsequent fragments.
1772  */
1773 
1774  /* <4> J*32 at 8. */
1775  packets[9] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
1776 
1777  /* <5> K*24 at 48. */
1778  packets[10] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
1779 
1780  /* <6> L*24 at 72. */
1781  packets[11] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
1782 
1783  /* <7> M*24 at 96. */
1784  packets[12] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
1785 
1786  /* <8> N*8 at 128. */
1787  packets[13] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
1788 
1789  /* <9> O*8 at 152. */
1790  packets[14] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
1791 
1792  /* <10> P*8 at 160. */
1793  packets[15] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
1794 
1795  /* <11> Q*16 at 176. */
1796  packets[16] = BuildIpv6TestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
1797 
1798  default_policy = policy;
1799 
1800  /* Send all but the last. */
1801  for (i = 0; i < 9; i++) {
1802  Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
1803  FAIL_IF_NOT_NULL(tp);
1805  }
1806  int overlap = 0;
1807  for (; i < 16; i++) {
1808  Packet *tp = Defrag(&test_tv, &test_dtv, packets[i]);
1809  FAIL_IF_NOT_NULL(tp);
1810  if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) {
1811  overlap++;
1812  }
1813  }
1814  FAIL_IF_NOT(overlap);
1815 
1816  /* And now the last one. */
1817  Packet *reassembled = Defrag(&test_tv, &test_dtv, packets[16]);
1818  FAIL_IF_NULL(reassembled);
1819  FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0);
1820 
1821  FAIL_IF(IPV6_GET_RAW_PLEN(PacketGetIPv6(reassembled)) != 192);
1822 
1823  PacketFree(reassembled);
1824 
1825  /* Make sure all frags were returned to the pool. */
1826  FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1827 
1828  for (i = 0; i < 17; i++) {
1829  PacketFree(packets[i]);
1830  }
1831  DefragDestroy();
1832  PASS;
1833 }
1834 
1835 /* Define data that matches the naming "Target-Based Fragmentation
1836  * Reassembly".
1837  *
1838  * For example, the data refers to a fragment of data as <1>, or <3_6>
1839  * and uses these to diagram the input fragments and the resulting
1840  * policies. We build test cases for the papers scenario but assign
1841  * specific values to each segment.
1842  */
1843 #define D_1 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'
1844 #define D_2 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B'
1845 #define D_3 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C'
1846 #define D_3_1 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D'
1847 #define D_3_2 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E'
1848 #define D_3_3 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F'
1849 #define D_3_4 'G', 'G', 'G', 'G', 'G', 'G', 'G', 'G'
1850 #define D_3_5 'H', 'H', 'H', 'H', 'H', 'H', 'H', 'H'
1851 #define D_3_6 'I', 'I', 'I', 'I', 'I', 'I', 'I', 'I'
1852 #define D_4 'J', 'J', 'J', 'J', 'J', 'J', 'J', 'J'
1853 #define D_5 'K', 'K', 'K', 'K', 'K', 'K', 'K', 'K'
1854 #define D_6 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'
1855 #define D_7 'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M'
1856 #define D_8 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'
1857 #define D_9 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O'
1858 #define D_10 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'
1859 #define D_11 'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q', 'Q'
1861 static int
1862 DefragSturgesNovakBsdTest(void)
1863 {
1864  /* Expected data. */
1865  uint8_t expected[] = {
1866  D_1,
1867  D_1,
1868  D_1,
1869  D_4,
1870  D_4,
1871  D_2,
1872  D_3,
1873  D_3,
1874  D_3,
1875  D_6,
1876  D_6,
1877  D_6,
1878  D_7,
1879  D_7,
1880  D_7,
1881  D_3_3,
1882  D_3_3,
1883  D_3_3,
1884  D_3_4,
1885  D_3_4,
1886  D_3_5,
1887  D_3_5,
1888  D_3_6,
1889  D_11,
1890  };
1891 
1892  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1893  sizeof(expected)));
1894  PASS;
1895 }
1896 
1897 static int DefragSturgesNovakBsdIpv6Test(void)
1898 {
1899  /* Expected data. */
1900  uint8_t expected[] = {
1901  D_1,
1902  D_1,
1903  D_1,
1904  D_4,
1905  D_4,
1906  D_2,
1907  D_3,
1908  D_3,
1909  D_3,
1910  D_6,
1911  D_6,
1912  D_6,
1913  D_7,
1914  D_7,
1915  D_7,
1916  D_3_3,
1917  D_3_3,
1918  D_3_3,
1919  D_3_4,
1920  D_3_4,
1921  D_3_5,
1922  D_3_5,
1923  D_3_6,
1924  D_11,
1925  };
1926 
1927  FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_BSD, expected, sizeof(expected)));
1928  PASS;
1929 }
1930 
1931 static int DefragSturgesNovakLinuxIpv4Test(void)
1932 {
1933  /* Expected data. */
1934  uint8_t expected[] = {
1935  D_1,
1936  D_1,
1937  D_1,
1938  D_4,
1939  D_4,
1940  D_2,
1941  D_5,
1942  D_5,
1943  D_5,
1944  D_6,
1945  D_6,
1946  D_6,
1947  D_7,
1948  D_7,
1949  D_7,
1950  D_3_3,
1951  D_3_3,
1952  D_3_3,
1953  D_3_4,
1954  D_3_4,
1955  D_10,
1956  D_3_5,
1957  D_11,
1958  D_11,
1959  };
1960 
1961  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1962  sizeof(expected)));
1963  PASS;
1964 }
1965 
1966 static int DefragSturgesNovakLinuxIpv6Test(void)
1967 {
1968  /* Expected data. */
1969  uint8_t expected[] = {
1970  D_1,
1971  D_1,
1972  D_1,
1973  D_4,
1974  D_4,
1975  D_2,
1976  D_5,
1977  D_5,
1978  D_5,
1979  D_6,
1980  D_6,
1981  D_6,
1982  D_7,
1983  D_7,
1984  D_7,
1985  D_3_3,
1986  D_3_3,
1987  D_3_3,
1988  D_3_4,
1989  D_3_4,
1990  D_10,
1991  D_3_5,
1992  D_11,
1993  D_11,
1994  };
1995 
1996  FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LINUX, expected, sizeof(expected)));
1997  PASS;
1998 }
1999 
2000 static int DefragSturgesNovakWindowsIpv4Test(void)
2001 {
2002  /* Expected data. */
2003  uint8_t expected[] = {
2004  D_1,
2005  D_1,
2006  D_1,
2007  D_4,
2008  D_2,
2009  D_2,
2010  D_3,
2011  D_3,
2012  D_3,
2013  D_6,
2014  D_6,
2015  D_6,
2016  D_7,
2017  D_3_2,
2018  D_3_2,
2019  D_3_3,
2020  D_3_3,
2021  D_3_3,
2022  D_3_4,
2023  D_3_4,
2024  D_3_5,
2025  D_3_5,
2026  D_3_6,
2027  D_11,
2028  };
2029 
2030  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
2031  sizeof(expected)));
2032  PASS;
2033 }
2034 
2035 static int DefragSturgesNovakWindowsIpv6Test(void)
2036 {
2037  /* Expected data. */
2038  uint8_t expected[] = {
2039  D_1,
2040  D_1,
2041  D_1,
2042  D_4,
2043  D_2,
2044  D_2,
2045  D_3,
2046  D_3,
2047  D_3,
2048  D_6,
2049  D_6,
2050  D_6,
2051  D_7,
2052  D_3_2,
2053  D_3_2,
2054  D_3_3,
2055  D_3_3,
2056  D_3_3,
2057  D_3_4,
2058  D_3_4,
2059  D_3_5,
2060  D_3_5,
2061  D_3_6,
2062  D_11,
2063  };
2064 
2065  FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_WINDOWS, expected, sizeof(expected)));
2066  PASS;
2067 }
2068 
2069 static int DefragSturgesNovakSolarisTest(void)
2070 {
2071  /* Expected data. */
2072  uint8_t expected[] = {
2073  D_1,
2074  D_1,
2075  D_1,
2076  D_4,
2077  D_2,
2078  D_2,
2079  D_3,
2080  D_3,
2081  D_3,
2082  D_6,
2083  D_6,
2084  D_6,
2085  D_7,
2086  D_7,
2087  D_7,
2088  D_3_3,
2089  D_3_3,
2090  D_3_3,
2091  D_3_4,
2092  D_3_4,
2093  D_3_5,
2094  D_3_5,
2095  D_3_6,
2096  D_11,
2097  };
2098 
2099  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
2100  sizeof(expected)));
2101  PASS;
2102 }
2103 
2104 static int DefragSturgesNovakSolarisIpv6Test(void)
2105 {
2106  /* Expected data. */
2107  uint8_t expected[] = {
2108  D_1,
2109  D_1,
2110  D_1,
2111  D_4,
2112  D_2,
2113  D_2,
2114  D_3,
2115  D_3,
2116  D_3,
2117  D_6,
2118  D_6,
2119  D_6,
2120  D_7,
2121  D_7,
2122  D_7,
2123  D_3_3,
2124  D_3_3,
2125  D_3_3,
2126  D_3_4,
2127  D_3_4,
2128  D_3_5,
2129  D_3_5,
2130  D_3_6,
2131  D_11,
2132  };
2133 
2134  FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_SOLARIS, expected, sizeof(expected)));
2135  PASS;
2136 }
2137 
2138 static int DefragSturgesNovakFirstTest(void)
2139 {
2140  /* Expected data. */
2141  uint8_t expected[] = {
2142  D_1,
2143  D_1,
2144  D_1,
2145  D_4,
2146  D_2,
2147  D_2,
2148  D_3,
2149  D_3,
2150  D_3,
2151  D_6,
2152  D_3_1,
2153  D_6,
2154  D_7,
2155  D_3_2,
2156  D_3_2,
2157  D_3_3,
2158  D_3_3,
2159  D_3_3,
2160  D_3_4,
2161  D_3_4,
2162  D_3_5,
2163  D_3_5,
2164  D_3_6,
2165  D_11,
2166  };
2167 
2168  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
2169  sizeof(expected)));
2170  PASS;
2171 }
2172 
2173 static int DefragSturgesNovakFirstIpv6Test(void)
2174 {
2175  /* Expected data. */
2176  uint8_t expected[] = {
2177  D_1,
2178  D_1,
2179  D_1,
2180  D_4,
2181  D_2,
2182  D_2,
2183  D_3,
2184  D_3,
2185  D_3,
2186  D_6,
2187  D_3_1,
2188  D_6,
2189  D_7,
2190  D_3_2,
2191  D_3_2,
2192  D_3_3,
2193  D_3_3,
2194  D_3_3,
2195  D_3_4,
2196  D_3_4,
2197  D_3_5,
2198  D_3_5,
2199  D_3_6,
2200  D_11,
2201  };
2202 
2203  return DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_FIRST, expected, sizeof(expected));
2204 }
2205 
2206 static int
2207 DefragSturgesNovakLastTest(void)
2208 {
2209  /* Expected data. */
2210  uint8_t expected[] = {
2211  D_1,
2212  D_4,
2213  D_4,
2214  D_4,
2215  D_4,
2216  D_2,
2217  D_5,
2218  D_5,
2219  D_5,
2220  D_6,
2221  D_6,
2222  D_6,
2223  D_7,
2224  D_7,
2225  D_7,
2226  D_3_3,
2227  D_8,
2228  D_3_3,
2229  D_3_4,
2230  D_9,
2231  D_10,
2232  D_3_5,
2233  D_11,
2234  D_11,
2235  };
2236 
2237  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2238  sizeof(expected)));
2239  PASS;
2240 }
2241 
2242 static int DefragSturgesNovakLastIpv6Test(void)
2243 {
2244  /* Expected data. */
2245  uint8_t expected[] = {
2246  D_1,
2247  D_4,
2248  D_4,
2249  D_4,
2250  D_4,
2251  D_2,
2252  D_5,
2253  D_5,
2254  D_5,
2255  D_6,
2256  D_6,
2257  D_6,
2258  D_7,
2259  D_7,
2260  D_7,
2261  D_3_3,
2262  D_8,
2263  D_3_3,
2264  D_3_4,
2265  D_9,
2266  D_10,
2267  D_3_5,
2268  D_11,
2269  D_11,
2270  };
2271 
2272  FAIL_IF_NOT(DefragDoSturgesNovakIpv6Test(DEFRAG_POLICY_LAST, expected, sizeof(expected)));
2273  PASS;
2274 }
2275 
2276 static int DefragTimeoutTest(void)
2277 {
2278  int i;
2279 
2280  /* Setup a small number of trackers. */
2281  FAIL_IF_NOT(SCConfSet("defrag.trackers", "16"));
2282 
2283  DefragInit();
2284 
2285  /* Load in 16 packets. */
2286  for (i = 0; i < 16; i++) {
2287  Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, i, 0, 1, 'A' + i, 16);
2288  FAIL_IF_NULL(p);
2289 
2290  Packet *tp = Defrag(&test_tv, &test_dtv, p);
2291  PacketFree(p);
2292  FAIL_IF_NOT_NULL(tp);
2293  }
2294 
2295  /* Build a new packet but push the timestamp out by our timeout.
2296  * This should force our previous fragments to be timed out. */
2297  Packet *p = BuildIpv4TestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
2298  FAIL_IF_NULL(p);
2299 
2300  p->ts = SCTIME_ADD_SECS(p->ts, defrag_context->timeout + 1);
2301  Packet *tp = Defrag(&test_tv, &test_dtv, p);
2302  FAIL_IF_NOT_NULL(tp);
2303 
2305  FAIL_IF_NULL(tracker);
2306 
2307  FAIL_IF(tracker->id != 99);
2308 
2309  SCMutexUnlock(&tracker->lock);
2310  PacketFree(p);
2311 
2312  DefragDestroy();
2313  PASS;
2314 }
2315 
2316 /**
2317  * QA found that if you send a packet where more frags is 0, offset is
2318  * > 0 and there is no data in the packet that the re-assembler will
2319  * fail. The fix was simple, but this unit test is just to make sure
2320  * its not introduced.
2321  */
2322 static int DefragNoDataIpv4Test(void)
2323 {
2324  DefragContext *dc = NULL;
2325  Packet *p = NULL;
2326  int id = 12;
2327 
2328  DefragInit();
2329 
2330  dc = DefragContextNew();
2331  FAIL_IF_NULL(dc);
2332 
2333  /* This packet has an offset > 0, more frags set to 0 and no data. */
2334  p = BuildIpv4TestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
2335  FAIL_IF_NULL(p);
2336 
2337  /* We do not expect a packet returned. */
2338  FAIL_IF(Defrag(&test_tv, &test_dtv, p) != NULL);
2339 
2340  /* The fragment should have been ignored so no fragments should
2341  * have been allocated from the pool. */
2342  FAIL_IF(dc->frag_pool->outstanding != 0);
2343 
2344  DefragContextDestroy(dc);
2345  PacketFree(p);
2346 
2347  DefragDestroy();
2348  PASS;
2349 }
2350 
2351 static int DefragTooLargeIpv4Test(void)
2352 {
2353  DefragContext *dc = NULL;
2354  Packet *p = NULL;
2355 
2356  DefragInit();
2357 
2358  dc = DefragContextNew();
2359  FAIL_IF_NULL(dc);
2360 
2361  /* Create a fragment that would extend past the max allowable size
2362  * for an IPv4 packet. */
2363  p = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
2364  FAIL_IF_NULL(p);
2365 
2366  /* We do not expect a packet returned. */
2367  FAIL_IF(Defrag(&test_tv, &test_dtv, p) != NULL);
2368 
2369  /* We do expect an event. */
2371 
2372  /* The fragment should have been ignored so no fragments should have
2373  * been allocated from the pool. */
2374  FAIL_IF(dc->frag_pool->outstanding != 0);
2375 
2376  DefragContextDestroy(dc);
2377  PacketFree(p);
2378 
2379  DefragDestroy();
2380  PASS;
2381 }
2382 
2383 /**
2384  * Test that fragments in different VLANs that would otherwise be
2385  * re-assembled, are not re-assembled. Just use simple in-order
2386  * fragments.
2387  */
2388 static int DefragVlanTest(void)
2389 {
2390  Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2391 
2392  DefragInit();
2393 
2394  p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2395  FAIL_IF_NULL(p1);
2396  p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2397  FAIL_IF_NULL(p2);
2398 
2399  /* With no VLAN IDs set, packets should re-assemble. */
2400  FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2401  FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) == NULL);
2402  PacketFree(r);
2403 
2404  /* With mismatched VLANs, packets should not re-assemble. */
2405  p1->vlan_id[0] = 1;
2406  p2->vlan_id[0] = 2;
2407  FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2408  FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) != NULL);
2409 
2410  PacketFree(p1);
2411  PacketFree(p2);
2412  DefragDestroy();
2413 
2414  PASS;
2415 }
2416 
2417 /**
2418  * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID.
2419  */
2420 static int DefragVlanQinQTest(void)
2421 {
2422  Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2423 
2424  DefragInit();
2425 
2426  p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2427  FAIL_IF_NULL(p1);
2428  p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2429  FAIL_IF_NULL(p2);
2430 
2431  /* With no VLAN IDs set, packets should re-assemble. */
2432  FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2433  FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) == NULL);
2434  PacketFree(r);
2435 
2436  /* With mismatched VLANs, packets should not re-assemble. */
2437  p1->vlan_id[0] = 1;
2438  p2->vlan_id[0] = 1;
2439  p1->vlan_id[1] = 1;
2440  p2->vlan_id[1] = 2;
2441  FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2442  FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) != NULL);
2443 
2444  PacketFree(p1);
2445  PacketFree(p2);
2446  DefragDestroy();
2447 
2448  PASS;
2449 }
2450 
2451 /**
2452  * Like DefragVlanTest, but for QinQinQ, testing the third level VLAN ID.
2453  */
2454 static int DefragVlanQinQinQTest(void)
2455 {
2456  Packet *r = NULL;
2457 
2458  DefragInit();
2459 
2460  Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2461  FAIL_IF_NULL(p1);
2462  Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2463  FAIL_IF_NULL(p2);
2464 
2465  /* With no VLAN IDs set, packets should re-assemble. */
2466  FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2467  FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) == NULL);
2468  PacketFree(r);
2469 
2470  /* With mismatched VLANs, packets should not re-assemble. */
2471  p1->vlan_id[0] = 1;
2472  p2->vlan_id[0] = 1;
2473  p1->vlan_id[1] = 2;
2474  p2->vlan_id[1] = 2;
2475  p1->vlan_id[2] = 3;
2476  p2->vlan_id[2] = 4;
2477  FAIL_IF((r = Defrag(&test_tv, &test_dtv, p1)) != NULL);
2478  FAIL_IF((r = Defrag(&test_tv, &test_dtv, p2)) != NULL);
2479 
2480  PacketFree(p1);
2481  PacketFree(p2);
2482  DefragDestroy();
2483 
2484  PASS;
2485 }
2486 static int DefragTrackerReuseTest(void)
2487 {
2488  int id = 1;
2489  Packet *p1 = NULL;
2490  DefragTracker *tracker1 = NULL, *tracker2 = NULL;
2491 
2492  DefragInit();
2493 
2494  /* Build a packet, its not a fragment but shouldn't matter for
2495  * this test. */
2496  p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
2497  FAIL_IF_NULL(p1);
2498 
2499  /* Get a tracker. It shouldn't look like its already in use. */
2500  tracker1 = DefragGetTracker(&test_tv, &test_dtv, p1);
2501  FAIL_IF_NULL(tracker1);
2502  FAIL_IF(tracker1->seen_last);
2503  FAIL_IF(tracker1->remove);
2504  DefragTrackerRelease(tracker1);
2505 
2506  /* Get a tracker again, it should be the same one. */
2507  tracker2 = DefragGetTracker(&test_tv, &test_dtv, p1);
2508  FAIL_IF_NULL(tracker2);
2509  FAIL_IF(tracker2 != tracker1);
2510  DefragTrackerRelease(tracker1);
2511 
2512  /* Now mark the tracker for removal. It should not be returned
2513  * when we get a tracker for a packet that may have the same
2514  * attributes. */
2515  tracker1->remove = 1;
2516 
2517  tracker2 = DefragGetTracker(&test_tv, &test_dtv, p1);
2518  FAIL_IF_NULL(tracker2);
2519  /* DefragGetTracker will have returned tracker1 to the stack,
2520  * the set up a new tracker. Since it pops the stack, it got
2521  * tracker1. */
2522  FAIL_IF(tracker2 != tracker1);
2523  FAIL_IF(tracker2->remove);
2524 
2525  PacketFree(p1);
2526  DefragDestroy();
2527  PASS;
2528 }
2529 
2530 /**
2531  * IPV4: Test the case where you have a packet fragmented in 3 parts
2532  * and send like:
2533  * - Offset: 2; MF: 1
2534  * - Offset: 0; MF: 1
2535  * - Offset: 1; MF: 0
2536  *
2537  * Only the fragments with offset 0 and 1 should be reassembled.
2538  */
2539 static int DefragMfIpv4Test(void)
2540 {
2541  int ip_id = 9;
2542  Packet *p = NULL;
2543 
2544  DefragInit();
2545 
2546  Packet *p1 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
2547  Packet *p2 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
2548  Packet *p3 = BuildIpv4TestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
2549  FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2550 
2551  p = Defrag(&test_tv, &test_dtv, p1);
2553 
2554  p = Defrag(&test_tv, &test_dtv, p2);
2556 
2557  /* This should return a packet as MF=0. */
2558  p = Defrag(&test_tv, &test_dtv, p3);
2559  FAIL_IF_NULL(p);
2560 
2561  /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the
2562  * fragments should be in the re-assembled packet. */
2563  FAIL_IF(IPV4_GET_RAW_IPLEN(PacketGetIPv4(p)) != 36);
2564 
2565  /* Verify the payload of the IPv4 packet. */
2566  uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
2567  FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV4Hdr), expected_payload, sizeof(expected_payload)));
2568 
2569  PacketFree(p1);
2570  PacketFree(p2);
2571  PacketFree(p3);
2572  PacketFree(p);
2573  DefragDestroy();
2574  PASS;
2575 }
2576 
2577 /**
2578  * IPV6: Test the case where you have a packet fragmented in 3 parts
2579  * and send like:
2580  * - Offset: 2; MF: 1
2581  * - Offset: 0; MF: 1
2582  * - Offset: 1; MF: 0
2583  *
2584  * Only the fragments with offset 0 and 1 should be reassembled.
2585  */
2586 static int DefragMfIpv6Test(void)
2587 {
2588  int ip_id = 9;
2589  Packet *p = NULL;
2590 
2591  DefragInit();
2592 
2593  Packet *p1 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
2594  Packet *p2 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
2595  Packet *p3 = BuildIpv6TestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
2596  FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2597 
2598  p = Defrag(&test_tv, &test_dtv, p1);
2600 
2601  p = Defrag(&test_tv, &test_dtv, p2);
2603 
2604  /* This should return a packet as MF=0. */
2605  p = Defrag(&test_tv, &test_dtv, p3);
2606  FAIL_IF_NULL(p);
2607 
2608  /* For IPv6 the expected length is just the length of the payload
2609  * of 2 fragments, so 16. */
2610  FAIL_IF(IPV6_GET_RAW_PLEN(PacketGetIPv6(p)) != 16);
2611 
2612  /* Verify the payload of the IPv4 packet. */
2613  uint8_t expected_payload[] = "AAAAAAAABBBBBBBB";
2614  FAIL_IF(memcmp(GET_PKT_DATA(p) + sizeof(IPV6Hdr), expected_payload, sizeof(expected_payload)));
2615 
2616  PacketFree(p1);
2617  PacketFree(p2);
2618  PacketFree(p3);
2619  PacketFree(p);
2620  DefragDestroy();
2621  PASS;
2622 }
2623 
2624 /**
2625  * \brief Test that fragments that match other than the proto don't
2626  * actually get matched.
2627  */
2628 static int DefragTestBadProto(void)
2629 {
2630  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
2631  int id = 12;
2632 
2633  DefragInit();
2634 
2635  p1 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
2636  FAIL_IF_NULL(p1);
2637  p2 = BuildIpv4TestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
2638  FAIL_IF_NULL(p2);
2639  p3 = BuildIpv4TestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
2640  FAIL_IF_NULL(p3);
2641 
2645 
2646  PacketFree(p1);
2647  PacketFree(p2);
2648  PacketFree(p3);
2649 
2650  DefragDestroy();
2651  PASS;
2652 }
2653 
2654 /**
2655  * \test Test a report Linux overlap issue that doesn't appear to be
2656  * covered by the Sturges/Novak tests above.
2657  */
2658 static int DefragTestJeremyLinux(void)
2659 {
2660 
2661  uint8_t expected[] = "AAAAAAAA"
2662  "AAAAAAAA"
2663  "AAAAAAAA"
2664  "CCCCCCCC"
2665  "CCCCCCCC"
2666  "CCCCCCCC"
2667  "CCCCCCCC"
2668  "CCCCCCCC"
2669  "CCCCCCCC"
2670  "BBBBBBBB"
2671  "BBBBBBBB"
2672  "DDDDDDDD"
2673  "DDDDDD";
2674 
2675  DefragInit();
2676  default_policy = DEFRAG_POLICY_LINUX;
2677 
2678  int id = 1;
2679  Packet *packets[4];
2680  int i = 0;
2681 
2682  packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
2683  packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
2684  packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
2685  packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
2686 
2687  Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2688  FAIL_IF_NOT_NULL(r);
2689 
2690  r = Defrag(&test_tv, &test_dtv, packets[1]);
2691  FAIL_IF_NOT_NULL(r);
2692 
2693  r = Defrag(&test_tv, &test_dtv, packets[2]);
2694  FAIL_IF_NOT_NULL(r);
2695 
2696  r = Defrag(&test_tv, &test_dtv, packets[3]);
2697  FAIL_IF_NULL(r);
2698 
2699  FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0);
2700 
2701  for (i = 0; i < 4; i++) {
2702  PacketFree(packets[i]);
2703  }
2704  PacketFree(r);
2705 
2706  DefragDestroy();
2707  PASS;
2708 }
2709 
2710 /**
2711  * | 0 | 8 | 16 | 24 | 32 |
2712  * |----------|----------|----------|----------|----------|
2713  * | AAAAAAAA | AAAAAAAA |
2714  * | | BBBBBBBB | BBBBBBBB | | |
2715  * | | | CCCCCCCC | CCCCCCCC | |
2716  * | DDDDDDDD | | | | |
2717  *
2718  * | DDDDDDDD | BBBBBBBB | BBBBBBBB | CCCCCCCC | AAAAAAAA |
2719  */
2720 static int DefragBsdFragmentAfterNoMfIpv4Test(void)
2721 {
2722  DefragInit();
2723  default_policy = DEFRAG_POLICY_BSD;
2724  Packet *packets[4];
2725 
2726  packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
2727  packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
2728  packets[2] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
2729  packets[3] = BuildIpv4TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
2730 
2731  Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2732  FAIL_IF_NOT_NULL(r);
2733 
2734  r = Defrag(&test_tv, &test_dtv, packets[1]);
2735  FAIL_IF_NOT_NULL(r);
2736 
2737  r = Defrag(&test_tv, &test_dtv, packets[2]);
2738  FAIL_IF_NOT_NULL(r);
2739 
2740  r = Defrag(&test_tv, &test_dtv, packets[3]);
2741  FAIL_IF_NULL(r);
2742 
2743  // clang-format off
2744  uint8_t expected[] = {
2745  'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
2746  'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2747  'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2748  'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
2749  'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
2750  };
2751  // clang-format on
2752 
2753  if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
2754  printf("Expected:\n");
2755  PrintRawDataFp(stdout, expected, sizeof(expected));
2756  printf("Got:\n");
2757  PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
2758  FAIL;
2759  }
2760 
2761  for (int i = 0; i < 4; i++) {
2762  PacketFree(packets[i]);
2763  }
2764  PacketFree(r);
2765  DefragDestroy();
2766  PASS;
2767 }
2768 
2769 static int DefragBsdFragmentAfterNoMfIpv6Test(void)
2770 {
2771  DefragInit();
2772  default_policy = DEFRAG_POLICY_BSD;
2773  Packet *packets[4];
2774 
2775  packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 24 >> 3, 0, 'A', 16);
2776  packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 8 >> 3, 1, 'B', 16);
2777  packets[2] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 16 >> 3, 1, 'C', 16);
2778  packets[3] = BuildIpv6TestPacket(IPPROTO_ICMP, 0x96, 0, 1, 'D', 8);
2779 
2780  Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2781  FAIL_IF_NOT_NULL(r);
2782 
2783  r = Defrag(&test_tv, &test_dtv, packets[1]);
2784  FAIL_IF_NOT_NULL(r);
2785 
2786  r = Defrag(&test_tv, &test_dtv, packets[2]);
2787  FAIL_IF_NOT_NULL(r);
2788 
2789  r = Defrag(&test_tv, &test_dtv, packets[3]);
2790  FAIL_IF_NULL(r);
2791 
2792  // clang-format off
2793  uint8_t expected[] = {
2794  'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
2795  'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2796  'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B',
2797  'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C',
2798  'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
2799  };
2800  // clang-format on
2801 
2802  if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
2803  printf("Expected:\n");
2804  PrintRawDataFp(stdout, expected, sizeof(expected));
2805  printf("Got:\n");
2806  PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
2807  FAIL;
2808  }
2809 
2810  for (int i = 0; i < 4; i++) {
2811  PacketFree(packets[i]);
2812  }
2813  PacketFree(r);
2814  DefragDestroy();
2815  PASS;
2816 }
2817 
2818 static int DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2(void)
2819 {
2820  DefragInit();
2821  default_policy = DEFRAG_POLICY_BSD;
2822  Packet *packets[4];
2823 
2824  /* Packet 1: off=16, mf=1 */
2825  FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
2826  &packets[0], IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16));
2827 
2828  /* Packet 2: off=8, mf=1 */
2829  FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
2830  &packets[1], IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16));
2831 
2832  /* Packet 3: off=0, mf=1: IP and ICMP header. */
2833  FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
2834  &packets[2], IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8));
2835 
2836  /* Packet 4: off=8, mf=1 */
2837  FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
2838  &packets[3], IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8));
2839 
2840  Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2841  FAIL_IF_NOT_NULL(r);
2842 
2843  r = Defrag(&test_tv, &test_dtv, packets[1]);
2844  FAIL_IF_NOT_NULL(r);
2845 
2846  r = Defrag(&test_tv, &test_dtv, packets[2]);
2847  FAIL_IF_NOT_NULL(r);
2848 
2849  r = Defrag(&test_tv, &test_dtv, packets[3]);
2850  FAIL_IF_NULL(r);
2851 
2852  // clang-format off
2853  const uint8_t expected[] = {
2854  // AACCBBDD
2855  // AACCDDBB
2856  // AABBDDCC
2857  // DDCCBBAA
2858  'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
2859  'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
2860  'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
2861  'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
2862  };
2863  // clang-format on
2864 
2865  FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20 + 8, sizeof(expected)) != 0);
2866 
2867  for (int i = 0; i < 4; i++) {
2868  PacketFree(packets[i]);
2869  }
2870  PacketFree(r);
2871  DefragDestroy();
2872  PASS;
2873 }
2874 
2875 static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2(void)
2876 {
2877  DefragInit();
2878  default_policy = DEFRAG_POLICY_BSD;
2879  Packet *packets[4];
2880 
2881  /* Packet 1: off=16, mf=1 */
2882  packets[0] = BuildIpv6TestPacketWithContent(
2883  IPPROTO_ICMP, 6, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
2884 
2885  /* Packet 2: off=8, mf=1 */
2886  packets[1] = BuildIpv6TestPacketWithContent(
2887  IPPROTO_ICMP, 6, 8 >> 3, 1, (uint8_t *)"AACCBBDDAACCDDBB", 16);
2888 
2889  /* Packet 3: off=0, mf=1: IP and ICMP header. */
2890  packets[2] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
2891 
2892  /* Packet 4: off=8, mf=1 */
2893  packets[3] =
2894  BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 6, 32 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
2895 
2896  Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2897  FAIL_IF_NOT_NULL(r);
2898 
2899  r = Defrag(&test_tv, &test_dtv, packets[1]);
2900  FAIL_IF_NOT_NULL(r);
2901 
2902  r = Defrag(&test_tv, &test_dtv, packets[2]);
2903  FAIL_IF_NOT_NULL(r);
2904 
2905  r = Defrag(&test_tv, &test_dtv, packets[3]);
2906  FAIL_IF_NULL(r);
2907 
2908  // clang-format off
2909  const uint8_t expected[] = {
2910  // AACCBBDD
2911  // AACCDDBB
2912  // AABBDDCC
2913  // DDCCBBAA
2914  'A', 'A', 'C', 'C', 'B', 'B', 'D', 'D',
2915  'A', 'A', 'C', 'C', 'D', 'D', 'B', 'B',
2916  'A', 'A', 'B', 'B', 'D', 'D', 'C', 'C',
2917  'D', 'D', 'C', 'C', 'B', 'B', 'A', 'A',
2918  };
2919  // clang-format on
2920 
2921  FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 40 + 8, sizeof(expected)) != 0);
2922 
2923  for (int i = 0; i < 4; i++) {
2924  PacketFree(packets[i]);
2925  }
2926  PacketFree(r);
2927  DefragDestroy();
2928  PASS;
2929 }
2930 
2931 /**
2932  * #### Input
2933  *
2934  * | 96 (0) | 104 (8) | 112 (16) | 120 (24) |
2935  * |----------|----------|----------|----------|
2936  * | | EEEEEEEE | EEEEEEEE | EEEEEEEE |
2937  * | MMMMMMMM | MMMMMMMM | MMMMMMMM | |
2938  *
2939  * #### Expected Output
2940  *
2941  * | MMMMMMMM | MMMMMMMM | MMMMMMMM | EEEEEEEE |
2942  */
2943 static int DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test(void)
2944 {
2945  DefragInit();
2946  default_policy = DEFRAG_POLICY_BSD;
2947  Packet *packets[2];
2948 
2949  packets[0] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
2950  packets[1] = BuildIpv4TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
2951 
2952  Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2953  FAIL_IF_NOT_NULL(r);
2954 
2955  r = Defrag(&test_tv, &test_dtv, packets[1]);
2956  FAIL_IF_NULL(r);
2957 
2958  // clang-format off
2959  const uint8_t expected[] = {
2960  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2961  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2962  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
2963  'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
2964  };
2965  // clang-format on
2966 
2967  if (memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0) {
2968  printf("Expected:\n");
2969  PrintRawDataFp(stdout, expected, sizeof(expected));
2970  printf("Got:\n");
2971  PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
2972  FAIL;
2973  }
2974 
2975  for (int i = 0; i < 2; i++) {
2976  PacketFree(packets[i]);
2977  }
2978  PacketFree(r);
2979  DefragDestroy();
2980  PASS;
2981 }
2982 
2983 static int DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test(void)
2984 {
2985  DefragInit();
2986  default_policy = DEFRAG_POLICY_BSD;
2987  Packet *packets[2];
2988 
2989  packets[0] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 8 >> 3, 0, 'E', 24);
2990  packets[1] = BuildIpv6TestPacket(IPPROTO_ICMP, 1, 0, 1, 'M', 24);
2991 
2992  Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
2993  FAIL_IF_NOT_NULL(r);
2994 
2995  r = Defrag(&test_tv, &test_dtv, packets[1]);
2996  FAIL_IF_NULL(r);
2997 
2998  // clang-format off
2999  const uint8_t expected[] = {
3000  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
3001  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
3002  'M', 'M', 'M', 'M', 'M', 'M', 'M', 'M',
3003  'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E',
3004  };
3005  // clang-format on
3006 
3007  if (memcmp(expected, GET_PKT_DATA(r) + 40, sizeof(expected)) != 0) {
3008  printf("Expected:\n");
3009  PrintRawDataFp(stdout, expected, sizeof(expected));
3010  printf("Got:\n");
3011  PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
3012  FAIL;
3013  }
3014 
3015  for (int i = 0; i < 2; i++) {
3016  PacketFree(packets[i]);
3017  }
3018  PacketFree(r);
3019  DefragDestroy();
3020  PASS;
3021 }
3022 
3023 /**
3024  * Reassembly should fail.
3025  *
3026  * |0 |8 |16 |24 |32 |40 |48 |
3027  * |========|========|========|========|========|========|========|
3028  * | | |AABBCCDD|AABBDDCC| | | |
3029  * | | | | | |AACCBBDD| |
3030  * | |AACCDDBB|AADDBBCC| | | | |
3031  * |ZZZZZZZZ| | | | | | |
3032  * | | | | | | |DDCCBBAA|
3033  */
3034 static int DefragBsdMissingFragmentIpv4Test(void)
3035 {
3036  DefragInit();
3037  default_policy = DEFRAG_POLICY_BSD;
3038  Packet *packets[5];
3039 
3040  FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3041  &packets[0], IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16));
3042 
3043  FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3044  &packets[1], IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8));
3045 
3046  FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3047  &packets[2], IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16));
3048 
3049  /* ICMP header. */
3050  FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3051  &packets[3], IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8));
3052 
3053  FAIL_IF_NOT(BuildIpv4TestPacketWithContent(
3054  &packets[4], IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8));
3055 
3056  Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
3057  FAIL_IF_NOT_NULL(r);
3058 
3059  r = Defrag(&test_tv, &test_dtv, packets[1]);
3060  FAIL_IF_NOT_NULL(r);
3061 
3062  r = Defrag(&test_tv, &test_dtv, packets[2]);
3063  FAIL_IF_NOT_NULL(r);
3064 
3065  r = Defrag(&test_tv, &test_dtv, packets[3]);
3066  FAIL_IF_NOT_NULL(r);
3067 
3068  r = Defrag(&test_tv, &test_dtv, packets[4]);
3069  FAIL_IF_NOT_NULL(r);
3070 
3071 #if 0
3072  PrintRawDataFp(stdout, GET_PKT_DATA(r) + 20, GET_PKT_LEN(r) - 20);
3073 #endif
3074 
3075  for (int i = 0; i < 5; i++) {
3076  PacketFree(packets[i]);
3077  }
3078  DefragDestroy();
3079  PASS;
3080 }
3081 
3082 static int DefragBsdMissingFragmentIpv6Test(void)
3083 {
3084  DefragInit();
3085  default_policy = DEFRAG_POLICY_BSD;
3086  Packet *packets[5];
3087 
3088  packets[0] = BuildIpv6TestPacketWithContent(
3089  IPPROTO_ICMP, 189, 16 >> 3, 1, (uint8_t *)"AABBCCDDAABBDDCC", 16);
3090 
3091  packets[1] =
3092  BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 40 >> 3, 1, (uint8_t *)"AACCBBDD", 8);
3093 
3094  packets[2] = BuildIpv6TestPacketWithContent(
3095  IPPROTO_ICMP, 189, 8 >> 3, 1, (uint8_t *)"AACCDDBBAADDBBCC", 16);
3096 
3097  /* ICMP header. */
3098  packets[3] = BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 0, 1, (uint8_t *)"ZZZZZZZZ", 8);
3099 
3100  packets[4] =
3101  BuildIpv6TestPacketWithContent(IPPROTO_ICMP, 189, 48 >> 3, 0, (uint8_t *)"DDCCBBAA", 8);
3102 
3103  Packet *r = Defrag(&test_tv, &test_dtv, packets[0]);
3104  FAIL_IF_NOT_NULL(r);
3105 
3106  r = Defrag(&test_tv, &test_dtv, packets[1]);
3107  FAIL_IF_NOT_NULL(r);
3108 
3109  r = Defrag(&test_tv, &test_dtv, packets[2]);
3110  FAIL_IF_NOT_NULL(r);
3111 
3112  r = Defrag(&test_tv, &test_dtv, packets[3]);
3113  FAIL_IF_NOT_NULL(r);
3114 
3115  r = Defrag(&test_tv, &test_dtv, packets[4]);
3116  FAIL_IF_NOT_NULL(r);
3117 
3118 #if 0
3119  PrintRawDataFp(stdout, GET_PKT_DATA(r) + 40, GET_PKT_LEN(r) - 40);
3120 #endif
3121 
3122  for (int i = 0; i < 5; i++) {
3123  PacketFree(packets[i]);
3124  }
3125  DefragDestroy();
3126  PASS;
3127 }
3128 
3129 #endif /* UNITTESTS */
3130 
3132 {
3133 #ifdef UNITTESTS
3134  UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest);
3135  UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest);
3136  UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest);
3137  UtRegisterTest("DefragSturgesNovakLinuxIpv4Test",
3138  DefragSturgesNovakLinuxIpv4Test);
3139  UtRegisterTest("DefragSturgesNovakWindowsIpv4Test",
3140  DefragSturgesNovakWindowsIpv4Test);
3141  UtRegisterTest("DefragSturgesNovakSolarisTest",
3142  DefragSturgesNovakSolarisTest);
3143  UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
3144  UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
3145 
3146  UtRegisterTest("DefragNoDataIpv4Test", DefragNoDataIpv4Test);
3147  UtRegisterTest("DefragTooLargeIpv4Test", DefragTooLargeIpv4Test);
3148 
3149  UtRegisterTest("DefragInOrderSimpleIpv6Test", DefragInOrderSimpleIpv6Test);
3150  UtRegisterTest("DefragReverseSimpleIpv6Test", DefragReverseSimpleIpv6Test);
3151  UtRegisterTest("DefragSturgesNovakBsdIpv6Test", DefragSturgesNovakBsdIpv6Test);
3152  UtRegisterTest("DefragSturgesNovakLinuxIpv6Test", DefragSturgesNovakLinuxIpv6Test);
3153  UtRegisterTest("DefragSturgesNovakWindowsIpv6Test", DefragSturgesNovakWindowsIpv6Test);
3154  UtRegisterTest("DefragSturgesNovakSolarisIpv6Test", DefragSturgesNovakSolarisIpv6Test);
3155  UtRegisterTest("DefragSturgesNovakFirstIpv6Test", DefragSturgesNovakFirstIpv6Test);
3156  UtRegisterTest("DefragSturgesNovakLastIpv6Test", DefragSturgesNovakLastIpv6Test);
3157 
3158  UtRegisterTest("DefragVlanTest", DefragVlanTest);
3159  UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
3160  UtRegisterTest("DefragVlanQinQinQTest", DefragVlanQinQinQTest);
3161  UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest);
3162  UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest);
3163  UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test);
3164  UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test);
3165  UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
3166 
3167  UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux);
3168 
3169  UtRegisterTest("DefragBsdFragmentAfterNoMfIpv4Test", DefragBsdFragmentAfterNoMfIpv4Test);
3170  UtRegisterTest("DefragBsdFragmentAfterNoMfIpv6Test", DefragBsdFragmentAfterNoMfIpv6Test);
3171  UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test",
3172  DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test);
3173  UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test",
3174  DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test);
3175  UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2",
3176  DefragBsdSubsequentOverlapsStartOfOriginalIpv4Test_2);
3177  UtRegisterTest("DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2",
3178  DefragBsdSubsequentOverlapsStartOfOriginalIpv6Test_2);
3179  UtRegisterTest("DefragBsdMissingFragmentIpv4Test", DefragBsdMissingFragmentIpv4Test);
3180  UtRegisterTest("DefragBsdMissingFragmentIpv6Test", DefragBsdMissingFragmentIpv6Test);
3181 #endif /* UNITTESTS */
3182 }
ENGINE_SET_EVENT
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:1224
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:1053
D_7
#define D_7
Definition: defrag.c:1855
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:1859
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:1849
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:1848
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:1852
ENGINE_ISSET_EVENT
#define ENGINE_ISSET_EVENT(p, e)
Definition: decode.h:1237
PcapPacketCntGet
uint64_t PcapPacketCntGet(const Packet *p)
Definition: decode.c:1175
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
DecodeThreadVars_::counter_defrag_no_frags
StatsCounterId counter_defrag_no_frags
Definition: decode.h:1056
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:560
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:184
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:1850
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:1845
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:1844
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:1052
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:1858
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:650
DefragTracker_::lock
SCMutex lock
Definition: defrag.h:85
PKT_SET_SRC
#define PKT_SET_SRC(p, src_val)
Definition: decode.h:1359
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:1055
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:189
Packet_::ts
SCTime_t ts
Definition: decode.h:568
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:415
IPV4_FRAG_PKT_TOO_LARGE
@ IPV4_FRAG_PKT_TOO_LARGE
Definition: decode-events.h:181
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:3131
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:182
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:225
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:1847
Packet_
Definition: decode.h:514
DefragTracker_::id
uint32_t id
Definition: defrag.h:92
D_8
#define D_8
Definition: defrag.c:1856
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:1854
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:1857
DefragTrackerRelease
void DefragTrackerRelease(DefragTracker *t)
Definition: defrag-hash.c:150
D_3_6
#define D_3_6
Definition: defrag.c:1851
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:1843
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:613
Packet_::root
struct Packet_ * root
Definition: decode.h:664
PoolGet
void * PoolGet(Pool *p)
Definition: util-pool.c:251
PKT_REBUILT_FRAGMENT
#define PKT_REBUILT_FRAGMENT
Definition: decode.h:1340
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:993
MAX_PAYLOAD_SIZE
#define MAX_PAYLOAD_SIZE
Definition: decode.h:712
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:1051
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:240
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:1054
DEFRAG_POLICY_DEFAULT
@ DEFRAG_POLICY_DEFAULT
Definition: defrag.c:94
suricata.h
defrag-hash.h
Packet_::dst
Address dst
Definition: decode.h:519
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:1846
D_5
#define D_5
Definition: defrag.c:1853
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:541
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
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
PacketInit
void PacketInit(Packet *p)
Initialize a packet structure for use.
Definition: packet.c:73
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:183
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:518
DefragInit
void DefragInit(void)
Definition: defrag.c:1107
IPV4_FRAG_IGNORED
@ IPV4_FRAG_IGNORED
Definition: decode-events.h:188
DEFRAG_POLICY_BSD_RIGHT
@ DEFRAG_POLICY_BSD_RIGHT
Definition: defrag.c:89