suricata
defrag.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2022 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-queue.h"
57 #include "defrag-config.h"
58 
59 #include "tmqh-packetpool.h"
60 #include "decode.h"
61 
62 #ifdef UNITTESTS
63 #include "util-unittest.h"
64 #endif
65 
66 #define DEFAULT_DEFRAG_HASH_SIZE 0xffff
67 #define DEFAULT_DEFRAG_POOL_SIZE 0xffff
68 
69 /**
70  * Default timeout (in seconds) before a defragmentation tracker will
71  * be released.
72  */
73 #define TIMEOUT_DEFAULT 60
74 
75 /**
76  * Maximum allowed timeout, 24 hours.
77  */
78 #define TIMEOUT_MAX (60 * 60 * 24)
79 
80 /**
81  * Minimum allowed timeout, 1 second.
82  */
83 #define TIMEOUT_MIN 1
84 
85 /** Fragment reassembly policies. */
94 
96 };
97 
98 static uint8_t default_policy = DEFRAG_POLICY_BSD;
99 
100 /** The global DefragContext so all threads operate from the same
101  * context. */
102 static DefragContext *defrag_context;
103 
105 
106 /**
107  * Utility/debugging function to dump the frags associated with a
108  * tracker. Only enable when unit tests are enabled.
109  */
110 #if 0
111 #ifdef UNITTESTS
112 static void
113 DumpFrags(DefragTracker *tracker)
114 {
115  Frag *frag;
116 
117  printf("Dumping frags for packet: ID=%d\n", tracker->id);
118  TAILQ_FOREACH(frag, &tracker->frags, next) {
119  printf("-> Frag: frag_offset=%d, frag_len=%d, data_len=%d, ltrim=%d, skip=%d\n", frag->offset, frag->len, frag->data_len, frag->ltrim, frag->skip);
120  PrintRawDataFp(stdout, frag->pkt, frag->len);
121  }
122 }
123 #endif /* UNITTESTS */
124 #endif
125 
126 /**
127  * \brief Reset a frag for reuse in a pool.
128  */
129 static void
130 DefragFragReset(Frag *frag)
131 {
132  if (frag->pkt != NULL)
133  SCFree(frag->pkt);
134  memset(frag, 0, sizeof(*frag));
135 }
136 
137 /**
138  * \brief Allocate a new frag for use in a pool.
139  */
140 static int
141 DefragFragInit(void *data, void *initdata)
142 {
143  Frag *frag = data;
144 
145  memset(frag, 0, sizeof(*frag));
146  return 1;
147 }
148 
149 /**
150  * \brief Free all frags associated with a tracker.
151  */
152 void
154 {
155  Frag *frag, *tmp;
156 
157  /* Lock the frag pool as we'll be return items to it. */
158  SCMutexLock(&defrag_context->frag_pool_lock);
159 
160  RB_FOREACH_SAFE(frag, IP_FRAGMENTS, &tracker->fragment_tree, tmp) {
161  RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, frag);
162  DefragFragReset(frag);
163  PoolReturn(defrag_context->frag_pool, frag);
164  }
165 
166  SCMutexUnlock(&defrag_context->frag_pool_lock);
167 }
168 
169 /**
170  * \brief Create a new DefragContext.
171  *
172  * \retval On success a return an initialized DefragContext, otherwise
173  * NULL will be returned.
174  */
175 static DefragContext *
176 DefragContextNew(void)
177 {
178  DefragContext *dc;
179 
180  dc = SCCalloc(1, sizeof(*dc));
181  if (unlikely(dc == NULL))
182  return NULL;
183 
184  /* Initialize the pool of trackers. */
185  intmax_t tracker_pool_size;
186  if (!ConfGetInt("defrag.trackers", &tracker_pool_size) || tracker_pool_size == 0) {
187  tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
188  }
189 
190  /* Initialize the pool of frags. */
191  intmax_t frag_pool_size;
192  if (!ConfGetInt("defrag.max-frags", &frag_pool_size) || frag_pool_size == 0) {
193  frag_pool_size = DEFAULT_DEFRAG_POOL_SIZE;
194  }
195  intmax_t frag_pool_prealloc = frag_pool_size / 2;
196  dc->frag_pool = PoolInit(frag_pool_size, frag_pool_prealloc,
197  sizeof(Frag),
198  NULL, DefragFragInit, dc, NULL, NULL);
199  if (dc->frag_pool == NULL) {
200  FatalError("Defrag: Failed to initialize fragment pool.");
201  }
202  if (SCMutexInit(&dc->frag_pool_lock, NULL) != 0) {
203  FatalError("Defrag: Failed to initialize frag pool mutex.");
204  }
205 
206  /* Set the default timeout. */
207  intmax_t timeout;
208  if (!ConfGetInt("defrag.timeout", &timeout)) {
209  dc->timeout = TIMEOUT_DEFAULT;
210  }
211  else {
212  if (timeout < TIMEOUT_MIN) {
213  FatalError("defrag: Timeout less than minimum allowed value.");
214  }
215  else if (timeout > TIMEOUT_MAX) {
216  FatalError("defrag: Timeout greater than maximum allowed value.");
217  }
218  dc->timeout = timeout;
219  }
220 
221  SCLogDebug("Defrag Initialized:");
222  SCLogDebug("\tTimeout: %"PRIuMAX, (uintmax_t)dc->timeout);
223  SCLogDebug("\tMaximum defrag trackers: %"PRIuMAX, tracker_pool_size);
224  SCLogDebug("\tPreallocated defrag trackers: %"PRIuMAX, tracker_pool_size);
225  SCLogDebug("\tMaximum fragments: %"PRIuMAX, (uintmax_t)frag_pool_size);
226  SCLogDebug("\tPreallocated fragments: %"PRIuMAX, (uintmax_t)frag_pool_prealloc);
227 
228  return dc;
229 }
230 
231 static void
232 DefragContextDestroy(DefragContext *dc)
233 {
234  if (dc == NULL)
235  return;
236 
237  PoolFree(dc->frag_pool);
238  SCFree(dc);
239 }
240 
241 /**
242  * Attempt to re-assemble a packet.
243  *
244  * \param tracker The defragmentation tracker to reassemble from.
245  */
246 static Packet *
247 Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
248 {
249  Packet *rp = NULL;
250 
251  /* Should not be here unless we have seen the last fragment. */
252  if (!tracker->seen_last) {
253  return NULL;
254  }
255 
256  /* Check that we have the first fragment and its of a valid size. */
257  Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
258  if (first == NULL) {
259  goto done;
260  } else if (first->offset != 0) {
261  /* Still waiting for the first fragment. */
262  goto done;
263  } else if (first->len < sizeof(IPV4Hdr)) {
264  /* First fragment isn't enough for an IPv6 header. */
265  goto error_remove_tracker;
266  }
267 
268  /* Check that we have all the data. Relies on the fact that
269  * fragments are inserted if frag_offset order. */
270  Frag *frag = NULL;
271  size_t len = 0;
272  RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
273  if (frag->offset > len) {
274  /* This fragment starts after the end of the previous
275  * fragment. We have a hole. */
276  goto done;
277  }
278  else {
279  len += frag->data_len;
280  }
281  }
282 
283  /* Allocate a Packet for the reassembled packet. On failure we
284  * SCFree all the resources held by this tracker. */
285  rp = PacketDefragPktSetup(p, NULL, 0, IPV4_GET_IPPROTO(p));
286  if (rp == NULL) {
287  goto error_remove_tracker;
288  }
292 
293  int fragmentable_offset = 0;
294  uint16_t fragmentable_len = 0;
295  uint16_t hlen = 0;
296  int ip_hdr_offset = 0;
297 
298  RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
299  SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64,
300  frag, frag->data_len, frag->offset, frag->pcap_cnt);
301 
302  if (frag->skip)
303  continue;
304  if (frag->ltrim >= frag->data_len)
305  continue;
306  if (frag->offset == 0) {
307 
308  if (PacketCopyData(rp, frag->pkt, frag->len) == -1)
309  goto error_remove_tracker;
310 
311  hlen = frag->hlen;
312  ip_hdr_offset = frag->ip_hdr_offset;
313 
314  /* This is the start of the fragmentable portion of the
315  * first packet. All fragment offsets are relative to
316  * this. */
317  fragmentable_offset = frag->ip_hdr_offset + frag->hlen;
318  fragmentable_len = frag->data_len;
319  }
320  else {
321  int pkt_end = fragmentable_offset + frag->offset + frag->data_len;
322  if (pkt_end > (int)MAX_PAYLOAD_SIZE) {
323  SCLogDebug("Failed re-assemble "
324  "fragmented packet, exceeds size of packet buffer.");
325  goto error_remove_tracker;
326  }
327  if (PacketCopyDataOffset(rp,
328  fragmentable_offset + frag->offset + frag->ltrim,
329  frag->pkt + frag->data_offset + frag->ltrim,
330  frag->data_len - frag->ltrim) == -1) {
331  goto error_remove_tracker;
332  }
333  if (frag->offset > UINT16_MAX - frag->data_len) {
334  SCLogDebug("Failed re-assemble "
335  "fragmentable_len exceeds UINT16_MAX");
336  goto error_remove_tracker;
337  }
338  if (frag->offset + frag->data_len > fragmentable_len)
339  fragmentable_len = frag->offset + frag->data_len;
340  }
341 
342  if (!frag->more_frags) {
343  break;
344  }
345  }
346 
347  SCLogDebug("ip_hdr_offset %u, hlen %" PRIu16 ", fragmentable_len %" PRIu16, ip_hdr_offset, hlen,
348  fragmentable_len);
349 
350  rp->ip4h = (IPV4Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
351  uint16_t old = rp->ip4h->ip_len + rp->ip4h->ip_off;
352  DEBUG_VALIDATE_BUG_ON(hlen > UINT16_MAX - fragmentable_len);
353  rp->ip4h->ip_len = htons(fragmentable_len + hlen);
354  rp->ip4h->ip_off = 0;
355  rp->ip4h->ip_csum = FixChecksum(rp->ip4h->ip_csum,
356  old, rp->ip4h->ip_len + rp->ip4h->ip_off);
357  SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len);
358 
359  tracker->remove = 1;
360  DefragTrackerFreeFrags(tracker);
361 done:
362  return rp;
363 
364 error_remove_tracker:
365  tracker->remove = 1;
366  DefragTrackerFreeFrags(tracker);
367  if (rp != NULL)
369  return NULL;
370 }
371 
372 /**
373  * Attempt to re-assemble a packet.
374  *
375  * \param tracker The defragmentation tracker to reassemble from.
376  */
377 static Packet *
378 Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
379 {
380  Packet *rp = NULL;
381 
382  /* Should not be here unless we have seen the last fragment. */
383  if (!tracker->seen_last)
384  return NULL;
385 
386  /* Check that we have the first fragment and its of a valid size. */
387  Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
388  if (first == NULL) {
389  goto done;
390  } else if (first->offset != 0) {
391  /* Still waiting for the first fragment. */
392  goto done;
393  } else if (first->len < sizeof(IPV6Hdr)) {
394  /* First fragment isn't enough for an IPv6 header. */
395  goto error_remove_tracker;
396  }
397 
398  /* Check that we have all the data. Relies on the fact that
399  * fragments are inserted if frag_offset order. */
400  size_t len = 0;
401  Frag *frag = NULL;
402  RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
403  if (frag->skip) {
404  continue;
405  }
406 
407  if (frag == first) {
408  if (frag->offset != 0) {
409  goto done;
410  }
411  len = frag->data_len;
412  }
413  else {
414  if (frag->offset > len) {
415  /* This fragment starts after the end of the previous
416  * fragment. We have a hole. */
417  goto done;
418  }
419  else {
420  len += frag->data_len;
421  }
422  }
423  }
424 
425  /* Allocate a Packet for the reassembled packet. On failure we
426  * SCFree all the resources held by this tracker. */
427  rp = PacketDefragPktSetup(p, (uint8_t *)p->ip6h,
428  IPV6_GET_PLEN(p) + sizeof(IPV6Hdr), 0);
429  if (rp == NULL) {
430  goto error_remove_tracker;
431  }
433 
434  uint16_t unfragmentable_len = 0;
435  int fragmentable_offset = 0;
436  uint16_t fragmentable_len = 0;
437  int ip_hdr_offset = 0;
438  uint8_t next_hdr = 0;
439  RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
440  if (frag->skip)
441  continue;
442  if (frag->data_len - frag->ltrim <= 0)
443  continue;
444  if (frag->offset == 0) {
445  IPV6FragHdr *frag_hdr = (IPV6FragHdr *)(frag->pkt +
446  frag->frag_hdr_offset);
447  next_hdr = frag_hdr->ip6fh_nxt;
448 
449  /* This is the first packet, we use this packets link and
450  * IPv6 headers. We also copy in its data, but remove the
451  * fragmentation header. */
452  if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1)
453  goto error_remove_tracker;
455  frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr),
456  frag->data_len) == -1)
457  goto error_remove_tracker;
458  ip_hdr_offset = frag->ip_hdr_offset;
459 
460  /* This is the start of the fragmentable portion of the
461  * first packet. All fragment offsets are relative to
462  * this. */
463  fragmentable_offset = frag->frag_hdr_offset;
464  fragmentable_len = frag->data_len;
465 
466  /* unfragmentable part is the part between the ipv6 header
467  * and the frag header. */
468  DEBUG_VALIDATE_BUG_ON(fragmentable_offset < ip_hdr_offset + IPV6_HEADER_LEN);
470  fragmentable_offset - ip_hdr_offset - IPV6_HEADER_LEN > UINT16_MAX);
471  unfragmentable_len = (uint16_t)(fragmentable_offset - ip_hdr_offset - IPV6_HEADER_LEN);
472  if (unfragmentable_len >= fragmentable_offset)
473  goto error_remove_tracker;
474  }
475  else {
476  if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim,
477  frag->pkt + frag->data_offset + frag->ltrim,
478  frag->data_len - frag->ltrim) == -1)
479  goto error_remove_tracker;
480  if (frag->offset + frag->data_len > fragmentable_len)
481  fragmentable_len = frag->offset + frag->data_len;
482  }
483 
484  if (!frag->more_frags) {
485  break;
486  }
487  }
488 
489  rp->ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
490  DEBUG_VALIDATE_BUG_ON(unfragmentable_len > UINT16_MAX - fragmentable_len);
491  rp->ip6h->s_ip6_plen = htons(fragmentable_len + unfragmentable_len);
492  /* if we have no unfragmentable part, so no ext hdrs before the frag
493  * header, we need to update the ipv6 headers next header field. This
494  * points to the frag header, and we will make it point to the layer
495  * directly after the frag header. */
496  if (unfragmentable_len == 0)
497  rp->ip6h->s_ip6_nxt = next_hdr;
498  SET_PKT_LEN(rp, ip_hdr_offset + sizeof(IPV6Hdr) +
499  unfragmentable_len + fragmentable_len);
500 
501  tracker->remove = 1;
502  DefragTrackerFreeFrags(tracker);
503 done:
504  return rp;
505 
506 error_remove_tracker:
507  tracker->remove = 1;
508  DefragTrackerFreeFrags(tracker);
509  if (rp != NULL)
511  return NULL;
512 }
513 
514 /**
515  * The RB_TREE compare function for fragments.
516  *
517  * When it comes to adding fragments, we want subsequent ones with the
518  * same offset to be treated as greater than, so we don't have an
519  * equal return value here.
520  */
521 int DefragRbFragCompare(struct Frag_ *a, struct Frag_ *b) {
522  if (a->offset < b->offset) {
523  return -1;
524  }
525  return 1;
526 }
527 
528 /**
529  * Insert a new IPv4/IPv6 fragment into a tracker.
530  *
531  * \todo Allocate packet buffers from a pool.
532  */
533 static Packet *
534 DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
535 {
536  Packet *r = NULL;
537  uint16_t ltrim = 0;
538 
539  uint8_t more_frags;
540  uint16_t frag_offset;
541 
542  /* IPv4 header length - IPv4 only. */
543  uint8_t hlen = 0;
544 
545  /* This is the offset of the start of the data in the packet that
546  * falls after the IP header. */
547  uint16_t data_offset;
548 
549  /* The length of the (fragmented) data. This is the length of the
550  * data that falls after the IP header. */
551  uint16_t data_len;
552 
553  /* Where the fragment ends. */
554  uint16_t frag_end;
555 
556  /* Offset in the packet to the IPv6 header. */
557  uint16_t ip_hdr_offset;
558 
559  /* Offset in the packet to the IPv6 frag header. IPv6 only. */
560  uint16_t frag_hdr_offset = 0;
561 
562  /* Address family */
563  int af = tracker->af;
564 
565  /* settings for updating a payload when an ip6 fragment with
566  * unfragmentable exthdrs are encountered. */
567  uint32_t ip6_nh_set_offset = 0;
568  uint8_t ip6_nh_set_value = 0;
569 
570 #ifdef DEBUG
571  uint64_t pcap_cnt = p->pcap_cnt;
572 #endif
573 
574  if (tracker->af == AF_INET) {
575  more_frags = IPV4_GET_MF(p);
576  frag_offset = (uint16_t)(IPV4_GET_IPOFFSET(p) << 3);
577  hlen = IPV4_GET_HLEN(p);
578  data_offset = (uint16_t)((uint8_t *)p->ip4h + hlen - GET_PKT_DATA(p));
579  data_len = IPV4_GET_IPLEN(p) - hlen;
580  frag_end = frag_offset + data_len;
581  ip_hdr_offset = (uint16_t)((uint8_t *)p->ip4h - GET_PKT_DATA(p));
582 
583  /* Ignore fragment if the end of packet extends past the
584  * maximum size of a packet. */
585  if (IPV4_HEADER_LEN + frag_offset + data_len > IPV4_MAXPACKET_LEN) {
587  return NULL;
588  }
589  }
590  else if (tracker->af == AF_INET6) {
591  more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
592  frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
593  data_offset = p->ip6eh.fh_data_offset;
594  data_len = p->ip6eh.fh_data_len;
595  frag_end = frag_offset + data_len;
596  ip_hdr_offset = (uint16_t)((uint8_t *)p->ip6h - GET_PKT_DATA(p));
597  frag_hdr_offset = p->ip6eh.fh_header_offset;
598 
599  SCLogDebug("mf %s frag_offset %u data_offset %u, data_len %u, "
600  "frag_end %u, ip_hdr_offset %u, frag_hdr_offset %u",
601  more_frags ? "true" : "false", frag_offset, data_offset,
602  data_len, frag_end, ip_hdr_offset, frag_hdr_offset);
603 
604  /* handle unfragmentable exthdrs */
605  if (ip_hdr_offset + IPV6_HEADER_LEN < frag_hdr_offset) {
606  SCLogDebug("we have exthdrs before fraghdr %u bytes",
607  (uint32_t)(frag_hdr_offset - (ip_hdr_offset + IPV6_HEADER_LEN)));
608 
609  /* get the offset of the 'next' field in exthdr before the FH,
610  * relative to the buffer start */
611 
612  /* store offset and FH 'next' value for updating frag buffer below */
613  ip6_nh_set_offset = p->ip6eh.fh_prev_hdr_offset;
614  ip6_nh_set_value = IPV6_EXTHDR_GET_FH_NH(p);
615  SCLogDebug("offset %d, value %u", ip6_nh_set_offset, ip6_nh_set_value);
616  }
617 
618  /* Ignore fragment if the end of packet extends past the
619  * maximum size of a packet. */
620  if (frag_offset + data_len > IPV6_MAXPACKET) {
622  return NULL;
623  }
624  }
625  else {
627  return NULL;
628  }
629 
630  /* Update timeout. */
631  tracker->timeout = SCTIME_FROM_SECS(SCTIME_SECS(p->ts) + tracker->host_timeout);
632 
633  Frag *prev = NULL, *next = NULL;
634  bool overlap = false;
635  ltrim = 0;
636 
637  if (!RB_EMPTY(&tracker->fragment_tree)) {
638  Frag key = {
639  .offset = frag_offset - 1,
640  };
641  next = RB_NFIND(IP_FRAGMENTS, &tracker->fragment_tree, &key);
642  if (next == NULL) {
643  prev = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
644  next = IP_FRAGMENTS_RB_NEXT(prev);
645  } else {
646  prev = IP_FRAGMENTS_RB_PREV(next);
647  if (prev == NULL) {
648  prev = next;
649  next = IP_FRAGMENTS_RB_NEXT(prev);
650  }
651  }
652  while (prev != NULL) {
653  if (prev->skip) {
654  goto next;
655  }
656  if (frag_offset < prev->offset + prev->data_len && prev->offset < frag_end) {
657  overlap = true;
658  }
659 
660  switch (tracker->policy) {
661  case DEFRAG_POLICY_BSD:
662  if (frag_offset < prev->offset + prev->data_len) {
663  if (frag_offset >= prev->offset) {
664  ltrim = prev->offset + prev->data_len - frag_offset;
665  }
666  if ((next != NULL) && (frag_end > next->offset)) {
667  next->ltrim = frag_end - next->offset;
668  }
669  if ((frag_offset < prev->offset) &&
670  (frag_end >= prev->offset + prev->data_len)) {
671  prev->skip = 1;
672  }
673  goto insert;
674  }
675  break;
676  case DEFRAG_POLICY_LINUX:
677  /* Check if new fragment overlaps the end of previous
678  * fragment, if it does, trim the new fragment.
679  *
680  * Old: AAAAAAAA AAAAAAAA AAAAAAAA
681  * New: BBBBBBBB BBBBBBBB BBBBBBBB
682  * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
683  */
684  if (prev->offset + prev->ltrim < frag_offset + ltrim &&
685  prev->offset + prev->data_len > frag_offset + ltrim) {
686  ltrim += prev->offset + prev->data_len - frag_offset;
687  }
688 
689  /* Check if new fragment overlaps the beginning of
690  * previous fragment, if it does, tim the previous
691  * fragment.
692  *
693  * Old: AAAAAAAA AAAAAAAA
694  * New: BBBBBBBB BBBBBBBB BBBBBBBB
695  * Res: BBBBBBBB BBBBBBBB BBBBBBBB
696  */
697  if (frag_offset + ltrim < prev->offset + prev->ltrim &&
698  frag_end > prev->offset + prev->ltrim) {
699  prev->ltrim += frag_end - (prev->offset + prev->ltrim);
700  goto insert;
701  }
702 
703  /* If the new fragment completely overlaps the
704  * previous fragment, mark the previous to be
705  * skipped. Re-assembly would succeed without doing
706  * this, but this will prevent the bytes from being
707  * copied just to be overwritten. */
708  if (frag_offset + ltrim <= prev->offset + prev->ltrim &&
709  frag_end >= prev->offset + prev->data_len) {
710  prev->skip = 1;
711  goto insert;
712  }
713 
714  break;
716  /* If new fragment fits inside a previous fragment, drop it. */
717  if (frag_offset + ltrim >= prev->offset + ltrim &&
718  frag_end <= prev->offset + prev->data_len) {
719  goto done;
720  }
721 
722  /* If new fragment starts before and ends after
723  * previous fragment, drop the previous fragment. */
724  if (frag_offset + ltrim < prev->offset + ltrim &&
725  frag_end > prev->offset + prev->data_len) {
726  prev->skip = 1;
727  goto insert;
728  }
729 
730  /* Check if new fragment overlaps the end of previous
731  * fragment, if it does, trim the new fragment.
732  *
733  * Old: AAAAAAAA AAAAAAAA AAAAAAAA
734  * New: BBBBBBBB BBBBBBBB BBBBBBBB
735  * Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB
736  */
737  if (frag_offset + ltrim > prev->offset + prev->ltrim &&
738  frag_offset + ltrim < prev->offset + prev->data_len) {
739  ltrim += prev->offset + prev->data_len - frag_offset;
740  goto insert;
741  }
742 
743  /* If new fragment starts at same offset as an
744  * existing fragment, but ends after it, trim the new
745  * fragment. */
746  if (frag_offset + ltrim == prev->offset + ltrim &&
747  frag_end > prev->offset + prev->data_len) {
748  ltrim += prev->offset + prev->data_len - frag_offset;
749  goto insert;
750  }
751  break;
753  if (frag_offset < prev->offset + prev->data_len) {
754  if (frag_offset >= prev->offset) {
755  ltrim = prev->offset + prev->data_len - frag_offset;
756  }
757  if ((frag_offset < prev->offset) &&
758  (frag_end >= prev->offset + prev->data_len)) {
759  prev->skip = 1;
760  }
761  goto insert;
762  }
763  break;
764  case DEFRAG_POLICY_FIRST:
765  if ((frag_offset >= prev->offset) &&
766  (frag_end <= prev->offset + prev->data_len)) {
767  goto done;
768  }
769  if (frag_offset < prev->offset) {
770  goto insert;
771  }
772  if (frag_offset < prev->offset + prev->data_len) {
773  ltrim = prev->offset + prev->data_len - frag_offset;
774  goto insert;
775  }
776  break;
777  case DEFRAG_POLICY_LAST:
778  if (frag_offset <= prev->offset) {
779  if (frag_end > prev->offset) {
780  prev->ltrim = frag_end - prev->offset;
781  }
782  goto insert;
783  }
784  break;
785  default:
786  break;
787  }
788 
789  next:
790  prev = next;
791  if (next != NULL) {
792  next = IP_FRAGMENTS_RB_NEXT(next);
793  }
794  continue;
795 
796  insert:
797  /* If existing fragment has been trimmed up completely
798  * (complete overlap), remove it now instead of holding
799  * onto it. */
800  if (prev->skip || prev->ltrim >= prev->data_len) {
801  RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, prev);
802  DefragFragReset(prev);
803  SCMutexLock(&defrag_context->frag_pool_lock);
804  PoolReturn(defrag_context->frag_pool, prev);
805  SCMutexUnlock(&defrag_context->frag_pool_lock);
806  }
807  break;
808  }
809  }
810 
811  if (ltrim > data_len) {
812  /* Full packet has been trimmed due to the overlap policy. Overlap
813  * already set. */
814  goto done;
815  }
816 
817  /* Allocate fragment and insert. */
818  SCMutexLock(&defrag_context->frag_pool_lock);
819  Frag *new = PoolGet(defrag_context->frag_pool);
820  SCMutexUnlock(&defrag_context->frag_pool_lock);
821  if (new == NULL) {
822  if (af == AF_INET) {
824  } else {
826  }
827  goto done;
828  }
829  new->pkt = SCMalloc(GET_PKT_LEN(p));
830  if (new->pkt == NULL) {
831  SCMutexLock(&defrag_context->frag_pool_lock);
832  PoolReturn(defrag_context->frag_pool, new);
833  SCMutexUnlock(&defrag_context->frag_pool_lock);
834  if (af == AF_INET) {
836  } else {
838  }
839  goto done;
840  }
841  memcpy(new->pkt, GET_PKT_DATA(p) + ltrim, GET_PKT_LEN(p) - ltrim);
842  new->len = (GET_PKT_LEN(p) - ltrim);
843  /* in case of unfragmentable exthdrs, update the 'next hdr' field
844  * in the raw buffer so the reassembled packet will point to the
845  * correct next header after stripping the frag header */
846  if (ip6_nh_set_offset > 0 && frag_offset == 0 && ltrim == 0) {
847  if (new->len > ip6_nh_set_offset) {
848  SCLogDebug("updating frag to have 'correct' nh value: %u -> %u",
849  new->pkt[ip6_nh_set_offset], ip6_nh_set_value);
850  new->pkt[ip6_nh_set_offset] = ip6_nh_set_value;
851  }
852  }
853 
854  new->hlen = hlen;
855  new->offset = frag_offset + ltrim;
856  new->data_offset = data_offset;
857  new->data_len = data_len - ltrim;
858  new->ip_hdr_offset = ip_hdr_offset;
859  new->frag_hdr_offset = frag_hdr_offset;
860  new->more_frags = more_frags;
861 #ifdef DEBUG
862  new->pcap_cnt = pcap_cnt;
863 #endif
864 
865  IP_FRAGMENTS_RB_INSERT(&tracker->fragment_tree, new);
866 
867  if (!more_frags) {
868  tracker->seen_last = 1;
869  }
870 
871  if (tracker->seen_last) {
872  if (tracker->af == AF_INET) {
873  r = Defrag4Reassemble(tv, tracker, p);
874  if (r != NULL && tv != NULL && dtv != NULL) {
876  if (DecodeIPV4(tv, dtv, r, (void *)r->ip4h,
877  IPV4_GET_IPLEN(r)) != TM_ECODE_OK) {
878 
879  UNSET_TUNNEL_PKT(r);
880  r->root = NULL;
882  r = NULL;
883  } else {
885  }
886  }
887  }
888  else if (tracker->af == AF_INET6) {
889  r = Defrag6Reassemble(tv, tracker, p);
890  if (r != NULL && tv != NULL && dtv != NULL) {
892  if (DecodeIPV6(tv, dtv, r, (uint8_t *)r->ip6h,
894  != TM_ECODE_OK) {
895 
896  UNSET_TUNNEL_PKT(r);
897  r->root = NULL;
899  r = NULL;
900  } else {
902  }
903  }
904  }
905  }
906 
907 
908 done:
909  if (overlap) {
910  if (af == AF_INET) {
912  }
913  else {
915  }
916  }
917  return r;
918 }
919 
920 /**
921  * \brief Get the defrag policy based on the destination address of
922  * the packet.
923  *
924  * \param p The packet used to get the destination address.
925  *
926  * \retval The defrag policy to use.
927  */
928 uint8_t
930 {
931  int policy = -1;
932 
933  if (PKT_IS_IPV4(p)) {
934  policy = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
935  }
936  else if (PKT_IS_IPV6(p)) {
937  policy = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
938  }
939 
940  if (policy == -1) {
941  return default_policy;
942  }
943 
944  /* Map the OS policies returned from the configured host info to
945  * defrag specific policies. */
946  switch (policy) {
947  /* BSD. */
948  case OS_POLICY_BSD:
949  case OS_POLICY_HPUX10:
950  case OS_POLICY_IRIX:
951  return DEFRAG_POLICY_BSD;
952 
953  /* BSD-Right. */
954  case OS_POLICY_BSD_RIGHT:
956 
957  /* Linux. */
958  case OS_POLICY_OLD_LINUX:
959  case OS_POLICY_LINUX:
960  return DEFRAG_POLICY_LINUX;
961 
962  /* First. */
964  case OS_POLICY_HPUX11:
965  case OS_POLICY_MACOS:
966  case OS_POLICY_FIRST:
967  return DEFRAG_POLICY_FIRST;
968 
969  /* Solaris. */
970  case OS_POLICY_SOLARIS:
971  return DEFRAG_POLICY_SOLARIS;
972 
973  /* Windows. */
974  case OS_POLICY_WINDOWS:
975  case OS_POLICY_VISTA:
977  return DEFRAG_POLICY_WINDOWS;
978 
979  /* Last. */
980  case OS_POLICY_LAST:
981  return DEFRAG_POLICY_LAST;
982 
983  default:
984  return default_policy;
985  }
986 }
987 
988 /** \internal
989  *
990  * \retval NULL or a *LOCKED* tracker */
991 static DefragTracker *
992 DefragGetTracker(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
993 {
994  return DefragGetTrackerFromHash(p);
995 }
996 
997 /**
998  * \brief Entry point for IPv4 and IPv6 fragments.
999  *
1000  * \param tv ThreadVars for the calling decoder.
1001  * \param p The packet fragment.
1002  *
1003  * \retval A new Packet resembling the re-assembled packet if the most
1004  * recent fragment allowed the packet to be re-assembled, otherwise
1005  * NULL is returned.
1006  */
1007 Packet *
1009 {
1010  uint16_t frag_offset;
1011  uint8_t more_frags;
1012  DefragTracker *tracker;
1013  int af;
1014 
1015  if (PKT_IS_IPV4(p)) {
1016  af = AF_INET;
1017  more_frags = IPV4_GET_MF(p);
1018  frag_offset = IPV4_GET_IPOFFSET(p);
1019  }
1020  else if (PKT_IS_IPV6(p)) {
1021  af = AF_INET6;
1022  frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
1023  more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
1024  }
1025  else {
1026  return NULL;
1027  }
1028 
1029  if (frag_offset == 0 && more_frags == 0) {
1030  return NULL;
1031  }
1032 
1033  if (tv != NULL && dtv != NULL) {
1034  if (af == AF_INET) {
1036  }
1037  else if (af == AF_INET6) {
1039  }
1040  }
1041 
1042  /* return a locked tracker or NULL */
1043  tracker = DefragGetTracker(tv, dtv, p);
1044  if (tracker == NULL) {
1045  if (tv != NULL && dtv != NULL) {
1047  }
1048  return NULL;
1049  }
1050 
1051  Packet *rp = DefragInsertFrag(tv, dtv, tracker, p);
1052  DefragTrackerRelease(tracker);
1053 
1054  return rp;
1055 }
1056 
1057 void
1059 {
1060  intmax_t tracker_pool_size;
1061  if (!ConfGetInt("defrag.trackers", &tracker_pool_size)) {
1062  tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
1063  }
1064 
1065  /* Load the defrag-per-host lookup. */
1067 
1068  /* Allocate the DefragContext. */
1069  defrag_context = DefragContextNew();
1070  if (defrag_context == NULL) {
1071  FatalError("Failed to allocate memory for the Defrag module.");
1072  }
1073 
1074  DefragSetDefaultTimeout(defrag_context->timeout);
1075  DefragInitConfig(false);
1076 }
1077 
1078 void DefragDestroy(void)
1079 {
1081  DefragContextDestroy(defrag_context);
1082  defrag_context = NULL;
1084 }
1085 
1086 #ifdef UNITTESTS
1087 #include "util-unittest-helper.h"
1088 #include "packet.h"
1089 
1090 #define IP_MF 0x2000
1092 /**
1093  * Allocate a test packet. Nothing to fancy, just a simple IP packet
1094  * with some payload of no particular protocol.
1095  */
1096 static Packet *BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf,
1097  const char content, int content_len)
1098 {
1099  Packet *p = NULL;
1100  int hlen = 20;
1101  int ttl = 64;
1102  uint8_t *pcontent;
1103  IPV4Hdr ip4h;
1104 
1105  p = SCCalloc(1, sizeof(*p) + default_packet_size);
1106  if (unlikely(p == NULL))
1107  return NULL;
1108 
1109  PacketInit(p);
1110 
1111  struct timeval tval;
1112  gettimeofday(&tval, NULL);
1113  p->ts = SCTIME_FROM_TIMEVAL(&tval);
1114  //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1115  ip4h.ip_verhl = 4 << 4;
1116  ip4h.ip_verhl |= hlen >> 2;
1117  ip4h.ip_len = htons(hlen + content_len);
1118  ip4h.ip_id = htons(id);
1119  if (mf)
1120  ip4h.ip_off = htons(IP_MF | off);
1121  else
1122  ip4h.ip_off = htons(off);
1123  ip4h.ip_ttl = ttl;
1124  ip4h.ip_proto = proto;
1125 
1126  ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1127  ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1128 
1129  /* copy content_len crap, we need full length */
1130  PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1131  p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1132  SET_IPV4_SRC_ADDR(p, &p->src);
1133  SET_IPV4_DST_ADDR(p, &p->dst);
1134 
1135  pcontent = SCCalloc(1, content_len);
1136  if (unlikely(pcontent == NULL))
1137  return NULL;
1138  memset(pcontent, content, content_len);
1139  PacketCopyDataOffset(p, hlen, pcontent, content_len);
1140  SET_PKT_LEN(p, hlen + content_len);
1141  SCFree(pcontent);
1142 
1143  p->ip4h->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1144 
1145  /* Self test. */
1146  if (IPV4_GET_VER(p) != 4)
1147  goto error;
1148  if (IPV4_GET_HLEN(p) != hlen)
1149  goto error;
1150  if (IPV4_GET_IPLEN(p) != hlen + content_len)
1151  goto error;
1152  if (IPV4_GET_IPID(p) != id)
1153  goto error;
1154  if (IPV4_GET_IPOFFSET(p) != off)
1155  goto error;
1156  if (IPV4_GET_MF(p) != mf)
1157  goto error;
1158  if (IPV4_GET_IPTTL(p) != ttl)
1159  goto error;
1160  if (IPV4_GET_IPPROTO(p) != proto)
1161  goto error;
1162 
1163  return p;
1164 error:
1165  if (p != NULL)
1166  SCFree(p);
1167  return NULL;
1168 }
1169 
1170 static Packet *IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off,
1171  int mf, const char content, int content_len)
1172 {
1173  Packet *p = NULL;
1174  uint8_t *pcontent;
1175  IPV6Hdr ip6h;
1176 
1177  p = SCCalloc(1, sizeof(*p) + default_packet_size);
1178  if (unlikely(p == NULL))
1179  return NULL;
1180 
1181  PacketInit(p);
1182 
1183  struct timeval tval;
1184  gettimeofday(&tval, NULL);
1185  p->ts = SCTIME_FROM_TIMEVAL(&tval);
1186 
1187  ip6h.s_ip6_nxt = 44;
1188  ip6h.s_ip6_hlim = 2;
1189 
1190  /* Source and dest address - very bogus addresses. */
1191  ip6h.s_ip6_src[0] = 0x01010101;
1192  ip6h.s_ip6_src[1] = 0x01010101;
1193  ip6h.s_ip6_src[2] = 0x01010101;
1194  ip6h.s_ip6_src[3] = 0x01010101;
1195  ip6h.s_ip6_dst[0] = 0x02020202;
1196  ip6h.s_ip6_dst[1] = 0x02020202;
1197  ip6h.s_ip6_dst[2] = 0x02020202;
1198  ip6h.s_ip6_dst[3] = 0x02020202;
1199 
1200  /* copy content_len crap, we need full length */
1201  PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1202 
1203  p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
1204  IPV6_SET_RAW_VER(p->ip6h, 6);
1205  /* Fragmentation header. */
1206  IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1207  fh->ip6fh_nxt = proto;
1208  fh->ip6fh_ident = htonl(id);
1209  fh->ip6fh_offlg = htons((off << 3) | mf);
1210 
1211  DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1212 
1213  pcontent = SCCalloc(1, content_len);
1214  if (unlikely(pcontent == NULL))
1215  return NULL;
1216  memset(pcontent, content, content_len);
1217  PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), pcontent, content_len);
1218  SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1219  SCFree(pcontent);
1220 
1221  p->ip6h->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1222 
1223  SET_IPV6_SRC_ADDR(p, &p->src);
1224  SET_IPV6_DST_ADDR(p, &p->dst);
1225 
1226  /* Self test. */
1227  if (IPV6_GET_VER(p) != 6)
1228  goto error;
1229  if (IPV6_GET_NH(p) != 44)
1230  goto error;
1231  if (IPV6_GET_PLEN(p) != sizeof(IPV6FragHdr) + content_len)
1232  goto error;
1233 
1234  return p;
1235 error:
1236  if (p != NULL)
1237  SCFree(p);
1238  return NULL;
1239 }
1240 
1241 /**
1242  * Test the simplest possible re-assembly scenario. All packet in
1243  * order and no overlaps.
1244  */
1245 static int DefragInOrderSimpleTest(void)
1246 {
1247  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1248  Packet *reassembled = NULL;
1249  int id = 12;
1250  int i;
1251 
1252  DefragInit();
1253 
1254  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1255  FAIL_IF_NULL(p1);
1256  p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1257  FAIL_IF_NULL(p2);
1258  p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1259  FAIL_IF_NULL(p3);
1260 
1261  FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1262  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1263 
1264  reassembled = Defrag(NULL, NULL, p3);
1265  FAIL_IF_NULL(reassembled);
1266 
1267  FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1268  FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1269 
1270  /* 20 bytes in we should find 8 bytes of A. */
1271  for (i = 20; i < 20 + 8; i++) {
1272  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1273  }
1274 
1275  /* 28 bytes in we should find 8 bytes of B. */
1276  for (i = 28; i < 28 + 8; i++) {
1277  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1278  }
1279 
1280  /* And 36 bytes in we should find 3 bytes of C. */
1281  for (i = 36; i < 36 + 3; i++) {
1282  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1283  }
1284 
1285  SCFree(p1);
1286  SCFree(p2);
1287  SCFree(p3);
1288  SCFree(reassembled);
1289 
1290  DefragDestroy();
1291  PASS;
1292 }
1293 
1294 /**
1295  * Simple fragmented packet in reverse order.
1296  */
1297 static int DefragReverseSimpleTest(void)
1298 {
1299  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1300  Packet *reassembled = NULL;
1301  int id = 12;
1302  int i;
1303 
1304  DefragInit();
1305 
1306  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1307  FAIL_IF_NULL(p1);
1308  p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1309  FAIL_IF_NULL(p2);
1310  p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1311  FAIL_IF_NULL(p3);
1312 
1313  FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1314  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1315 
1316  reassembled = Defrag(NULL, NULL, p1);
1317  FAIL_IF_NULL(reassembled);
1318 
1319  FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1320  FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1321 
1322  /* 20 bytes in we should find 8 bytes of A. */
1323  for (i = 20; i < 20 + 8; i++) {
1324  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1325  }
1326 
1327  /* 28 bytes in we should find 8 bytes of B. */
1328  for (i = 28; i < 28 + 8; i++) {
1329  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1330  }
1331 
1332  /* And 36 bytes in we should find 3 bytes of C. */
1333  for (i = 36; i < 36 + 3; i++) {
1334  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1335  }
1336 
1337  SCFree(p1);
1338  SCFree(p2);
1339  SCFree(p3);
1340  SCFree(reassembled);
1341 
1342  DefragDestroy();
1343  PASS;
1344 }
1345 
1346 /**
1347  * Test the simplest possible re-assembly scenario. All packet in
1348  * order and no overlaps.
1349  */
1350 static int IPV6DefragInOrderSimpleTest(void)
1351 {
1352  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1353  Packet *reassembled = NULL;
1354  int id = 12;
1355  int i;
1356 
1357  DefragInit();
1358 
1359  p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1360  FAIL_IF_NULL(p1);
1361  p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1362  FAIL_IF_NULL(p2);
1363  p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1364  FAIL_IF_NULL(p3);
1365 
1366  FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1367  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1368  reassembled = Defrag(NULL, NULL, p3);
1369  FAIL_IF_NULL(reassembled);
1370 
1371  FAIL_IF(IPV6_GET_PLEN(reassembled) != 19);
1372 
1373  /* 40 bytes in we should find 8 bytes of A. */
1374  for (i = 40; i < 40 + 8; i++) {
1375  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1376  }
1377 
1378  /* 28 bytes in we should find 8 bytes of B. */
1379  for (i = 48; i < 48 + 8; i++) {
1380  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1381  }
1382 
1383  /* And 36 bytes in we should find 3 bytes of C. */
1384  for (i = 56; i < 56 + 3; i++) {
1385  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1386  }
1387 
1388  SCFree(p1);
1389  SCFree(p2);
1390  SCFree(p3);
1391  SCFree(reassembled);
1392 
1393  DefragDestroy();
1394  PASS;
1395 }
1396 
1397 static int IPV6DefragReverseSimpleTest(void)
1398 {
1399  DefragContext *dc = NULL;
1400  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1401  Packet *reassembled = NULL;
1402  int id = 12;
1403  int i;
1404 
1405  DefragInit();
1406 
1407  dc = DefragContextNew();
1408  FAIL_IF_NULL(dc);
1409 
1410  p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1411  FAIL_IF_NULL(p1);
1412  p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1413  FAIL_IF_NULL(p2);
1414  p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1415  FAIL_IF_NULL(p3);
1416 
1417  FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1418  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1419  reassembled = Defrag(NULL, NULL, p1);
1420  FAIL_IF_NULL(reassembled);
1421 
1422  /* 40 bytes in we should find 8 bytes of A. */
1423  for (i = 40; i < 40 + 8; i++) {
1424  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1425  }
1426 
1427  /* 28 bytes in we should find 8 bytes of B. */
1428  for (i = 48; i < 48 + 8; i++) {
1429  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1430  }
1431 
1432  /* And 36 bytes in we should find 3 bytes of C. */
1433  for (i = 56; i < 56 + 3; i++) {
1434  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1435  }
1436 
1437  DefragContextDestroy(dc);
1438  SCFree(p1);
1439  SCFree(p2);
1440  SCFree(p3);
1441  SCFree(reassembled);
1442 
1443  DefragDestroy();
1444  PASS;
1445 }
1446 
1447 static int DefragDoSturgesNovakTest(int policy, u_char *expected,
1448  size_t expected_len)
1449 {
1450  int i;
1451 
1452  DefragInit();
1453 
1454  /*
1455  * Build the packets.
1456  */
1457 
1458  int id = 1;
1459  Packet *packets[17];
1460  memset(packets, 0x00, sizeof(packets));
1461 
1462  /*
1463  * Original fragments.
1464  */
1465 
1466  /* A*24 at 0. */
1467  packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
1468 
1469  /* B*15 at 32. */
1470  packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
1471 
1472  /* C*24 at 48. */
1473  packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
1474 
1475  /* D*8 at 80. */
1476  packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
1477 
1478  /* E*16 at 104. */
1479  packets[4] = BuildTestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
1480 
1481  /* F*24 at 120. */
1482  packets[5] = BuildTestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
1483 
1484  /* G*16 at 144. */
1485  packets[6] = BuildTestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
1486 
1487  /* H*16 at 160. */
1488  packets[7] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
1489 
1490  /* I*8 at 176. */
1491  packets[8] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
1492 
1493  /*
1494  * Overlapping subsequent fragments.
1495  */
1496 
1497  /* J*32 at 8. */
1498  packets[9] = BuildTestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
1499 
1500  /* K*24 at 48. */
1501  packets[10] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
1502 
1503  /* L*24 at 72. */
1504  packets[11] = BuildTestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
1505 
1506  /* M*24 at 96. */
1507  packets[12] = BuildTestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
1508 
1509  /* N*8 at 128. */
1510  packets[13] = BuildTestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
1511 
1512  /* O*8 at 152. */
1513  packets[14] = BuildTestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
1514 
1515  /* P*8 at 160. */
1516  packets[15] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
1517 
1518  /* Q*16 at 176. */
1519  packets[16] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
1520 
1521  default_policy = policy;
1522 
1523  /* Send all but the last. */
1524  for (i = 0; i < 9; i++) {
1525  Packet *tp = Defrag(NULL, NULL, packets[i]);
1526  FAIL_IF_NOT_NULL(tp);
1528  }
1529  int overlap = 0;
1530  for (; i < 16; i++) {
1531  Packet *tp = Defrag(NULL, NULL, packets[i]);
1532  FAIL_IF_NOT_NULL(tp);
1533  if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) {
1534  overlap++;
1535  }
1536  }
1537  FAIL_IF_NOT(overlap);
1538 
1539  /* And now the last one. */
1540  Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1541  FAIL_IF_NULL(reassembled);
1542 
1543  FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1544  FAIL_IF(IPV4_GET_IPLEN(reassembled) != 20 + 192);
1545 
1546  FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0);
1547  SCFree(reassembled);
1548 
1549  /* Make sure all frags were returned back to the pool. */
1550  FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1551 
1552  for (i = 0; i < 17; i++) {
1553  SCFree(packets[i]);
1554  }
1555  DefragDestroy();
1556  PASS;
1557 }
1558 
1559 static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected,
1560  size_t expected_len)
1561 {
1562  int i;
1563 
1564  DefragInit();
1565 
1566  /*
1567  * Build the packets.
1568  */
1569 
1570  int id = 1;
1571  Packet *packets[17];
1572  memset(packets, 0x00, sizeof(packets));
1573 
1574  /*
1575  * Original fragments.
1576  */
1577 
1578  /* A*24 at 0. */
1579  packets[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
1580 
1581  /* B*15 at 32. */
1582  packets[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
1583 
1584  /* C*24 at 48. */
1585  packets[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
1586 
1587  /* D*8 at 80. */
1588  packets[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
1589 
1590  /* E*16 at 104. */
1591  packets[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
1592 
1593  /* F*24 at 120. */
1594  packets[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
1595 
1596  /* G*16 at 144. */
1597  packets[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
1598 
1599  /* H*16 at 160. */
1600  packets[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
1601 
1602  /* I*8 at 176. */
1603  packets[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
1604 
1605  /*
1606  * Overlapping subsequent fragments.
1607  */
1608 
1609  /* J*32 at 8. */
1610  packets[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
1611 
1612  /* K*24 at 48. */
1613  packets[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
1614 
1615  /* L*24 at 72. */
1616  packets[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
1617 
1618  /* M*24 at 96. */
1619  packets[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
1620 
1621  /* N*8 at 128. */
1622  packets[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
1623 
1624  /* O*8 at 152. */
1625  packets[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
1626 
1627  /* P*8 at 160. */
1628  packets[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
1629 
1630  /* Q*16 at 176. */
1631  packets[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
1632 
1633  default_policy = policy;
1634 
1635  /* Send all but the last. */
1636  for (i = 0; i < 9; i++) {
1637  Packet *tp = Defrag(NULL, NULL, packets[i]);
1638  FAIL_IF_NOT_NULL(tp);
1640  }
1641  int overlap = 0;
1642  for (; i < 16; i++) {
1643  Packet *tp = Defrag(NULL, NULL, packets[i]);
1644  FAIL_IF_NOT_NULL(tp);
1645  if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) {
1646  overlap++;
1647  }
1648  }
1649  FAIL_IF_NOT(overlap);
1650 
1651  /* And now the last one. */
1652  Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1653  FAIL_IF_NULL(reassembled);
1654  FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0);
1655 
1656  FAIL_IF(IPV6_GET_PLEN(reassembled) != 192);
1657 
1658  SCFree(reassembled);
1659 
1660  /* Make sure all frags were returned to the pool. */
1661  FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1662 
1663  for (i = 0; i < 17; i++) {
1664  SCFree(packets[i]);
1665  }
1666  DefragDestroy();
1667  PASS;
1668 }
1669 
1670 static int
1671 DefragSturgesNovakBsdTest(void)
1672 {
1673  /* Expected data. */
1674  u_char expected[] = {
1675  "AAAAAAAA"
1676  "AAAAAAAA"
1677  "AAAAAAAA"
1678  "JJJJJJJJ"
1679  "JJJJJJJJ"
1680  "BBBBBBBB"
1681  "CCCCCCCC"
1682  "CCCCCCCC"
1683  "CCCCCCCC"
1684  "LLLLLLLL"
1685  "LLLLLLLL"
1686  "LLLLLLLL"
1687  "MMMMMMMM"
1688  "MMMMMMMM"
1689  "MMMMMMMM"
1690  "FFFFFFFF"
1691  "FFFFFFFF"
1692  "FFFFFFFF"
1693  "GGGGGGGG"
1694  "GGGGGGGG"
1695  "HHHHHHHH"
1696  "HHHHHHHH"
1697  "IIIIIIII"
1698  "QQQQQQQQ"
1699  };
1700 
1701  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1702  sizeof(expected)));
1703  PASS;
1704 }
1705 
1706 static int IPV6DefragSturgesNovakBsdTest(void)
1707 {
1708  /* Expected data. */
1709  u_char expected[] = {
1710  "AAAAAAAA"
1711  "AAAAAAAA"
1712  "AAAAAAAA"
1713  "JJJJJJJJ"
1714  "JJJJJJJJ"
1715  "BBBBBBBB"
1716  "CCCCCCCC"
1717  "CCCCCCCC"
1718  "CCCCCCCC"
1719  "LLLLLLLL"
1720  "LLLLLLLL"
1721  "LLLLLLLL"
1722  "MMMMMMMM"
1723  "MMMMMMMM"
1724  "MMMMMMMM"
1725  "FFFFFFFF"
1726  "FFFFFFFF"
1727  "FFFFFFFF"
1728  "GGGGGGGG"
1729  "GGGGGGGG"
1730  "HHHHHHHH"
1731  "HHHHHHHH"
1732  "IIIIIIII"
1733  "QQQQQQQQ"
1734  };
1735 
1736  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1737  sizeof(expected)));
1738  PASS;
1739 }
1740 
1741 static int DefragSturgesNovakLinuxIpv4Test(void)
1742 {
1743  /* Expected data. */
1744  u_char expected[] = {
1745  "AAAAAAAA"
1746  "AAAAAAAA"
1747  "AAAAAAAA"
1748  "JJJJJJJJ"
1749  "JJJJJJJJ"
1750  "BBBBBBBB"
1751  "KKKKKKKK"
1752  "KKKKKKKK"
1753  "KKKKKKKK"
1754  "LLLLLLLL"
1755  "LLLLLLLL"
1756  "LLLLLLLL"
1757  "MMMMMMMM"
1758  "MMMMMMMM"
1759  "MMMMMMMM"
1760  "FFFFFFFF"
1761  "FFFFFFFF"
1762  "FFFFFFFF"
1763  "GGGGGGGG"
1764  "GGGGGGGG"
1765  "PPPPPPPP"
1766  "HHHHHHHH"
1767  "QQQQQQQQ"
1768  "QQQQQQQQ"
1769  };
1770 
1771  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1772  sizeof(expected)));
1773  PASS;
1774 }
1775 
1776 static int IPV6DefragSturgesNovakLinuxTest(void)
1777 {
1778  /* Expected data. */
1779  u_char expected[] = {
1780  "AAAAAAAA"
1781  "AAAAAAAA"
1782  "AAAAAAAA"
1783  "JJJJJJJJ"
1784  "JJJJJJJJ"
1785  "BBBBBBBB"
1786  "KKKKKKKK"
1787  "KKKKKKKK"
1788  "KKKKKKKK"
1789  "LLLLLLLL"
1790  "LLLLLLLL"
1791  "LLLLLLLL"
1792  "MMMMMMMM"
1793  "MMMMMMMM"
1794  "MMMMMMMM"
1795  "FFFFFFFF"
1796  "FFFFFFFF"
1797  "FFFFFFFF"
1798  "GGGGGGGG"
1799  "GGGGGGGG"
1800  "PPPPPPPP"
1801  "HHHHHHHH"
1802  "QQQQQQQQ"
1803  "QQQQQQQQ"
1804  };
1805 
1806  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1807  sizeof(expected)));
1808  PASS;
1809 }
1810 
1811 static int DefragSturgesNovakWindowsIpv4Test(void)
1812 {
1813  /* Expected data. */
1814  u_char expected[] = {
1815  "AAAAAAAA"
1816  "AAAAAAAA"
1817  "AAAAAAAA"
1818  "JJJJJJJJ"
1819  "BBBBBBBB"
1820  "BBBBBBBB"
1821  "CCCCCCCC"
1822  "CCCCCCCC"
1823  "CCCCCCCC"
1824  "LLLLLLLL"
1825  "LLLLLLLL"
1826  "LLLLLLLL"
1827  "MMMMMMMM"
1828  "EEEEEEEE"
1829  "EEEEEEEE"
1830  "FFFFFFFF"
1831  "FFFFFFFF"
1832  "FFFFFFFF"
1833  "GGGGGGGG"
1834  "GGGGGGGG"
1835  "HHHHHHHH"
1836  "HHHHHHHH"
1837  "IIIIIIII"
1838  "QQQQQQQQ"
1839  };
1840 
1841  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
1842  sizeof(expected)));
1843  PASS;
1844 }
1845 
1846 static int IPV6DefragSturgesNovakWindowsTest(void)
1847 {
1848  /* Expected data. */
1849  u_char expected[] = {
1850  "AAAAAAAA"
1851  "AAAAAAAA"
1852  "AAAAAAAA"
1853  "JJJJJJJJ"
1854  "BBBBBBBB"
1855  "BBBBBBBB"
1856  "CCCCCCCC"
1857  "CCCCCCCC"
1858  "CCCCCCCC"
1859  "LLLLLLLL"
1860  "LLLLLLLL"
1861  "LLLLLLLL"
1862  "MMMMMMMM"
1863  "EEEEEEEE"
1864  "EEEEEEEE"
1865  "FFFFFFFF"
1866  "FFFFFFFF"
1867  "FFFFFFFF"
1868  "GGGGGGGG"
1869  "GGGGGGGG"
1870  "HHHHHHHH"
1871  "HHHHHHHH"
1872  "IIIIIIII"
1873  "QQQQQQQQ"
1874  };
1875 
1876  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
1877  sizeof(expected)));
1878  PASS;
1879 }
1880 
1881 static int DefragSturgesNovakSolarisTest(void)
1882 {
1883  /* Expected data. */
1884  u_char expected[] = {
1885  "AAAAAAAA"
1886  "AAAAAAAA"
1887  "AAAAAAAA"
1888  "JJJJJJJJ"
1889  "BBBBBBBB"
1890  "BBBBBBBB"
1891  "CCCCCCCC"
1892  "CCCCCCCC"
1893  "CCCCCCCC"
1894  "LLLLLLLL"
1895  "LLLLLLLL"
1896  "LLLLLLLL"
1897  "MMMMMMMM"
1898  "MMMMMMMM"
1899  "MMMMMMMM"
1900  "FFFFFFFF"
1901  "FFFFFFFF"
1902  "FFFFFFFF"
1903  "GGGGGGGG"
1904  "GGGGGGGG"
1905  "HHHHHHHH"
1906  "HHHHHHHH"
1907  "IIIIIIII"
1908  "QQQQQQQQ"
1909  };
1910 
1911  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
1912  sizeof(expected)));
1913  PASS;
1914 }
1915 
1916 static int IPV6DefragSturgesNovakSolarisTest(void)
1917 {
1918  /* Expected data. */
1919  u_char expected[] = {
1920  "AAAAAAAA"
1921  "AAAAAAAA"
1922  "AAAAAAAA"
1923  "JJJJJJJJ"
1924  "BBBBBBBB"
1925  "BBBBBBBB"
1926  "CCCCCCCC"
1927  "CCCCCCCC"
1928  "CCCCCCCC"
1929  "LLLLLLLL"
1930  "LLLLLLLL"
1931  "LLLLLLLL"
1932  "MMMMMMMM"
1933  "MMMMMMMM"
1934  "MMMMMMMM"
1935  "FFFFFFFF"
1936  "FFFFFFFF"
1937  "FFFFFFFF"
1938  "GGGGGGGG"
1939  "GGGGGGGG"
1940  "HHHHHHHH"
1941  "HHHHHHHH"
1942  "IIIIIIII"
1943  "QQQQQQQQ"
1944  };
1945 
1946  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
1947  sizeof(expected)));
1948  PASS;
1949 }
1950 
1951 static int DefragSturgesNovakFirstTest(void)
1952 {
1953  /* Expected data. */
1954  u_char expected[] = {
1955  "AAAAAAAA"
1956  "AAAAAAAA"
1957  "AAAAAAAA"
1958  "JJJJJJJJ"
1959  "BBBBBBBB"
1960  "BBBBBBBB"
1961  "CCCCCCCC"
1962  "CCCCCCCC"
1963  "CCCCCCCC"
1964  "LLLLLLLL"
1965  "DDDDDDDD"
1966  "LLLLLLLL"
1967  "MMMMMMMM"
1968  "EEEEEEEE"
1969  "EEEEEEEE"
1970  "FFFFFFFF"
1971  "FFFFFFFF"
1972  "FFFFFFFF"
1973  "GGGGGGGG"
1974  "GGGGGGGG"
1975  "HHHHHHHH"
1976  "HHHHHHHH"
1977  "IIIIIIII"
1978  "QQQQQQQQ"
1979  };
1980 
1981  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
1982  sizeof(expected)));
1983  PASS;
1984 }
1985 
1986 static int IPV6DefragSturgesNovakFirstTest(void)
1987 {
1988  /* Expected data. */
1989  u_char expected[] = {
1990  "AAAAAAAA"
1991  "AAAAAAAA"
1992  "AAAAAAAA"
1993  "JJJJJJJJ"
1994  "BBBBBBBB"
1995  "BBBBBBBB"
1996  "CCCCCCCC"
1997  "CCCCCCCC"
1998  "CCCCCCCC"
1999  "LLLLLLLL"
2000  "DDDDDDDD"
2001  "LLLLLLLL"
2002  "MMMMMMMM"
2003  "EEEEEEEE"
2004  "EEEEEEEE"
2005  "FFFFFFFF"
2006  "FFFFFFFF"
2007  "FFFFFFFF"
2008  "GGGGGGGG"
2009  "GGGGGGGG"
2010  "HHHHHHHH"
2011  "HHHHHHHH"
2012  "IIIIIIII"
2013  "QQQQQQQQ"
2014  };
2015 
2016  return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
2017  sizeof(expected));
2018 }
2019 
2020 static int
2021 DefragSturgesNovakLastTest(void)
2022 {
2023  /* Expected data. */
2024  u_char expected[] = {
2025  "AAAAAAAA"
2026  "JJJJJJJJ"
2027  "JJJJJJJJ"
2028  "JJJJJJJJ"
2029  "JJJJJJJJ"
2030  "BBBBBBBB"
2031  "KKKKKKKK"
2032  "KKKKKKKK"
2033  "KKKKKKKK"
2034  "LLLLLLLL"
2035  "LLLLLLLL"
2036  "LLLLLLLL"
2037  "MMMMMMMM"
2038  "MMMMMMMM"
2039  "MMMMMMMM"
2040  "FFFFFFFF"
2041  "NNNNNNNN"
2042  "FFFFFFFF"
2043  "GGGGGGGG"
2044  "OOOOOOOO"
2045  "PPPPPPPP"
2046  "HHHHHHHH"
2047  "QQQQQQQQ"
2048  "QQQQQQQQ"
2049  };
2050 
2051  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2052  sizeof(expected)));
2053  PASS;
2054 }
2055 
2056 static int IPV6DefragSturgesNovakLastTest(void)
2057 {
2058  /* Expected data. */
2059  u_char expected[] = {
2060  "AAAAAAAA"
2061  "JJJJJJJJ"
2062  "JJJJJJJJ"
2063  "JJJJJJJJ"
2064  "JJJJJJJJ"
2065  "BBBBBBBB"
2066  "KKKKKKKK"
2067  "KKKKKKKK"
2068  "KKKKKKKK"
2069  "LLLLLLLL"
2070  "LLLLLLLL"
2071  "LLLLLLLL"
2072  "MMMMMMMM"
2073  "MMMMMMMM"
2074  "MMMMMMMM"
2075  "FFFFFFFF"
2076  "NNNNNNNN"
2077  "FFFFFFFF"
2078  "GGGGGGGG"
2079  "OOOOOOOO"
2080  "PPPPPPPP"
2081  "HHHHHHHH"
2082  "QQQQQQQQ"
2083  "QQQQQQQQ"
2084  };
2085 
2086  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2087  sizeof(expected)));
2088  PASS;
2089 }
2090 
2091 static int DefragTimeoutTest(void)
2092 {
2093  int i;
2094 
2095  /* Setup a small number of trackers. */
2096  FAIL_IF_NOT(ConfSet("defrag.trackers", "16"));
2097 
2098  DefragInit();
2099 
2100  /* Load in 16 packets. */
2101  for (i = 0; i < 16; i++) {
2102  Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16);
2103  FAIL_IF_NULL(p);
2104 
2105  Packet *tp = Defrag(NULL, NULL, p);
2106  SCFree(p);
2107  FAIL_IF_NOT_NULL(tp);
2108  }
2109 
2110  /* Build a new packet but push the timestamp out by our timeout.
2111  * This should force our previous fragments to be timed out. */
2112  Packet *p = BuildTestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
2113  FAIL_IF_NULL(p);
2114 
2115  p->ts = SCTIME_ADD_SECS(p->ts, defrag_context->timeout + 1);
2116  Packet *tp = Defrag(NULL, NULL, p);
2117  FAIL_IF_NOT_NULL(tp);
2118 
2120  FAIL_IF_NULL(tracker);
2121 
2122  FAIL_IF(tracker->id != 99);
2123 
2124  SCMutexUnlock(&tracker->lock);
2125  SCFree(p);
2126 
2127  DefragDestroy();
2128  PASS;
2129 }
2130 
2131 /**
2132  * QA found that if you send a packet where more frags is 0, offset is
2133  * > 0 and there is no data in the packet that the re-assembler will
2134  * fail. The fix was simple, but this unit test is just to make sure
2135  * its not introduced.
2136  */
2137 static int DefragIPv4NoDataTest(void)
2138 {
2139  DefragContext *dc = NULL;
2140  Packet *p = NULL;
2141  int id = 12;
2142 
2143  DefragInit();
2144 
2145  dc = DefragContextNew();
2146  FAIL_IF_NULL(dc);
2147 
2148  /* This packet has an offset > 0, more frags set to 0 and no data. */
2149  p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
2150  FAIL_IF_NULL(p);
2151 
2152  /* We do not expect a packet returned. */
2153  FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2154 
2155  /* The fragment should have been ignored so no fragments should
2156  * have been allocated from the pool. */
2157  FAIL_IF(dc->frag_pool->outstanding != 0);
2158 
2159  DefragContextDestroy(dc);
2160  SCFree(p);
2161 
2162  DefragDestroy();
2163  PASS;
2164 }
2165 
2166 static int DefragIPv4TooLargeTest(void)
2167 {
2168  DefragContext *dc = NULL;
2169  Packet *p = NULL;
2170 
2171  DefragInit();
2172 
2173  dc = DefragContextNew();
2174  FAIL_IF_NULL(dc);
2175 
2176  /* Create a fragment that would extend past the max allowable size
2177  * for an IPv4 packet. */
2178  p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
2179  FAIL_IF_NULL(p);
2180 
2181  /* We do not expect a packet returned. */
2182  FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2183 
2184  /* We do expect an event. */
2186 
2187  /* The fragment should have been ignored so no fragments should have
2188  * been allocated from the pool. */
2189  FAIL_IF(dc->frag_pool->outstanding != 0);
2190 
2191  DefragContextDestroy(dc);
2192  SCFree(p);
2193 
2194  DefragDestroy();
2195  PASS;
2196 }
2197 
2198 /**
2199  * Test that fragments in different VLANs that would otherwise be
2200  * re-assembled, are not re-assembled. Just use simple in-order
2201  * fragments.
2202  */
2203 static int DefragVlanTest(void)
2204 {
2205  Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2206 
2207  DefragInit();
2208 
2209  p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2210  FAIL_IF_NULL(p1);
2211  p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2212  FAIL_IF_NULL(p2);
2213 
2214  /* With no VLAN IDs set, packets should re-assemble. */
2215  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2216  FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2217  SCFree(r);
2218 
2219  /* With mismatched VLANs, packets should not re-assemble. */
2220  p1->vlan_id[0] = 1;
2221  p2->vlan_id[0] = 2;
2222  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2223  FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2224 
2225  SCFree(p1);
2226  SCFree(p2);
2227  DefragDestroy();
2228 
2229  PASS;
2230 }
2231 
2232 /**
2233  * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID.
2234  */
2235 static int DefragVlanQinQTest(void)
2236 {
2237  Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2238 
2239  DefragInit();
2240 
2241  p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2242  FAIL_IF_NULL(p1);
2243  p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2244  FAIL_IF_NULL(p2);
2245 
2246  /* With no VLAN IDs set, packets should re-assemble. */
2247  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2248  FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2249  SCFree(r);
2250 
2251  /* With mismatched VLANs, packets should not re-assemble. */
2252  p1->vlan_id[0] = 1;
2253  p2->vlan_id[0] = 1;
2254  p1->vlan_id[1] = 1;
2255  p2->vlan_id[1] = 2;
2256  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2257  FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2258 
2259  SCFree(p1);
2260  SCFree(p2);
2261  DefragDestroy();
2262 
2263  PASS;
2264 }
2265 
2266 /**
2267  * Like DefragVlanTest, but for QinQinQ, testing the third level VLAN ID.
2268  */
2269 static int DefragVlanQinQinQTest(void)
2270 {
2271  Packet *r = NULL;
2272 
2273  DefragInit();
2274 
2275  Packet *p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2276  FAIL_IF_NULL(p1);
2277  Packet *p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2278  FAIL_IF_NULL(p2);
2279 
2280  /* With no VLAN IDs set, packets should re-assemble. */
2281  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2282  FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2283  SCFree(r);
2284 
2285  /* With mismatched VLANs, packets should not re-assemble. */
2286  p1->vlan_id[0] = 1;
2287  p2->vlan_id[0] = 1;
2288  p1->vlan_id[1] = 2;
2289  p2->vlan_id[1] = 2;
2290  p1->vlan_id[2] = 3;
2291  p2->vlan_id[2] = 4;
2292  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2293  FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2294 
2295  PacketFree(p1);
2296  PacketFree(p2);
2297  DefragDestroy();
2298 
2299  PASS;
2300 }
2301 static int DefragTrackerReuseTest(void)
2302 {
2303  int id = 1;
2304  Packet *p1 = NULL;
2305  DefragTracker *tracker1 = NULL, *tracker2 = NULL;
2306 
2307  DefragInit();
2308 
2309  /* Build a packet, its not a fragment but shouldn't matter for
2310  * this test. */
2311  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
2312  FAIL_IF_NULL(p1);
2313 
2314  /* Get a tracker. It shouldn't look like its already in use. */
2315  tracker1 = DefragGetTracker(NULL, NULL, p1);
2316  FAIL_IF_NULL(tracker1);
2317  FAIL_IF(tracker1->seen_last);
2318  FAIL_IF(tracker1->remove);
2319  DefragTrackerRelease(tracker1);
2320 
2321  /* Get a tracker again, it should be the same one. */
2322  tracker2 = DefragGetTracker(NULL, NULL, p1);
2323  FAIL_IF_NULL(tracker2);
2324  FAIL_IF(tracker2 != tracker1);
2325  DefragTrackerRelease(tracker1);
2326 
2327  /* Now mark the tracker for removal. It should not be returned
2328  * when we get a tracker for a packet that may have the same
2329  * attributes. */
2330  tracker1->remove = 1;
2331 
2332  tracker2 = DefragGetTracker(NULL, NULL, p1);
2333  FAIL_IF_NULL(tracker2);
2334  FAIL_IF(tracker2 == tracker1);
2335  FAIL_IF(tracker2->remove);
2336 
2337  SCFree(p1);
2338  DefragDestroy();
2339  PASS;
2340 }
2341 
2342 /**
2343  * IPV4: Test the case where you have a packet fragmented in 3 parts
2344  * and send like:
2345  * - Offset: 2; MF: 1
2346  * - Offset: 0; MF: 1
2347  * - Offset: 1; MF: 0
2348  *
2349  * Only the fragments with offset 0 and 1 should be reassembled.
2350  */
2351 static int DefragMfIpv4Test(void)
2352 {
2353  int ip_id = 9;
2354  Packet *p = NULL;
2355 
2356  DefragInit();
2357 
2358  Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
2359  Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
2360  Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
2361  FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2362 
2363  p = Defrag(NULL, NULL, p1);
2364  FAIL_IF_NOT_NULL(p);
2365 
2366  p = Defrag(NULL, NULL, p2);
2367  FAIL_IF_NOT_NULL(p);
2368 
2369  /* This should return a packet as MF=0. */
2370  p = Defrag(NULL, NULL, p3);
2371  FAIL_IF_NULL(p);
2372 
2373  /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the
2374  * fragments should be in the re-assembled packet. */
2375  FAIL_IF(IPV4_GET_IPLEN(p) != 36);
2376 
2377  SCFree(p1);
2378  SCFree(p2);
2379  SCFree(p3);
2380  SCFree(p);
2381  DefragDestroy();
2382  PASS;
2383 }
2384 
2385 /**
2386  * IPV6: Test the case where you have a packet fragmented in 3 parts
2387  * and send like:
2388  * - Offset: 2; MF: 1
2389  * - Offset: 0; MF: 1
2390  * - Offset: 1; MF: 0
2391  *
2392  * Only the fragments with offset 0 and 1 should be reassembled.
2393  */
2394 static int DefragMfIpv6Test(void)
2395 {
2396  int ip_id = 9;
2397  Packet *p = NULL;
2398 
2399  DefragInit();
2400 
2401  Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
2402  Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
2403  Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
2404  FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2405 
2406  p = Defrag(NULL, NULL, p1);
2407  FAIL_IF_NOT_NULL(p);
2408 
2409  p = Defrag(NULL, NULL, p2);
2410  FAIL_IF_NOT_NULL(p);
2411 
2412  /* This should return a packet as MF=0. */
2413  p = Defrag(NULL, NULL, p3);
2414  FAIL_IF_NULL(p);
2415 
2416  /* For IPv6 the expected length is just the length of the payload
2417  * of 2 fragments, so 16. */
2418  FAIL_IF(IPV6_GET_PLEN(p) != 16);
2419 
2420  SCFree(p1);
2421  SCFree(p2);
2422  SCFree(p3);
2423  SCFree(p);
2424  DefragDestroy();
2425  PASS;
2426 }
2427 
2428 /**
2429  * \brief Test that fragments that match other than the proto don't
2430  * actually get matched.
2431  */
2432 static int DefragTestBadProto(void)
2433 {
2434  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
2435  int id = 12;
2436 
2437  DefragInit();
2438 
2439  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
2440  FAIL_IF_NULL(p1);
2441  p2 = BuildTestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
2442  FAIL_IF_NULL(p2);
2443  p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
2444  FAIL_IF_NULL(p3);
2445 
2446  FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1));
2447  FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p2));
2448  FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p3));
2449 
2450  SCFree(p1);
2451  SCFree(p2);
2452  SCFree(p3);
2453 
2454  DefragDestroy();
2455  PASS;
2456 }
2457 
2458 /**
2459  * \test Test a report Linux overlap issue that doesn't appear to be
2460  * covered by the Sturges/Novak tests above.
2461  */
2462 static int DefragTestJeremyLinux(void)
2463 {
2464  char expected[] = "AAAAAAAA"
2465  "AAAAAAAA"
2466  "AAAAAAAA"
2467  "CCCCCCCC"
2468  "CCCCCCCC"
2469  "CCCCCCCC"
2470  "CCCCCCCC"
2471  "CCCCCCCC"
2472  "CCCCCCCC"
2473  "BBBBBBBB"
2474  "BBBBBBBB"
2475  "DDDDDDDD"
2476  "DDDDDD";
2477 
2478  DefragInit();
2479  default_policy = DEFRAG_POLICY_LINUX;
2480 
2481  int id = 1;
2482  Packet *packets[4];
2483  int i = 0;
2484 
2485  packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
2486  packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
2487  packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
2488  packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
2489 
2490  Packet *r = Defrag(NULL, NULL, packets[0]);
2491  FAIL_IF_NOT_NULL(r);
2492 
2493  r = Defrag(NULL, NULL, packets[1]);
2494  FAIL_IF_NOT_NULL(r);
2495 
2496  r = Defrag(NULL, NULL, packets[2]);
2497  FAIL_IF_NOT_NULL(r);
2498 
2499  r = Defrag(NULL, NULL, packets[3]);
2500  FAIL_IF_NULL(r);
2501 
2502  FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0);
2503 
2504  for (i = 0; i < 4; i++) {
2505  SCFree(packets[i]);
2506  }
2507  SCFree(r);
2508 
2509  DefragDestroy();
2510  PASS;
2511 }
2512 
2513 #endif /* UNITTESTS */
2514 
2516 {
2517 #ifdef UNITTESTS
2518  UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest);
2519  UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest);
2520  UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest);
2521  UtRegisterTest("DefragSturgesNovakLinuxIpv4Test",
2522  DefragSturgesNovakLinuxIpv4Test);
2523  UtRegisterTest("DefragSturgesNovakWindowsIpv4Test",
2524  DefragSturgesNovakWindowsIpv4Test);
2525  UtRegisterTest("DefragSturgesNovakSolarisTest",
2526  DefragSturgesNovakSolarisTest);
2527  UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
2528  UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
2529 
2530  UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest);
2531  UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest);
2532 
2533  UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest);
2534  UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest);
2535  UtRegisterTest("IPV6DefragSturgesNovakBsdTest",
2536  IPV6DefragSturgesNovakBsdTest);
2537  UtRegisterTest("IPV6DefragSturgesNovakLinuxTest",
2538  IPV6DefragSturgesNovakLinuxTest);
2539  UtRegisterTest("IPV6DefragSturgesNovakWindowsTest",
2540  IPV6DefragSturgesNovakWindowsTest);
2541  UtRegisterTest("IPV6DefragSturgesNovakSolarisTest",
2542  IPV6DefragSturgesNovakSolarisTest);
2543  UtRegisterTest("IPV6DefragSturgesNovakFirstTest",
2544  IPV6DefragSturgesNovakFirstTest);
2545  UtRegisterTest("IPV6DefragSturgesNovakLastTest",
2546  IPV6DefragSturgesNovakLastTest);
2547 
2548  UtRegisterTest("DefragVlanTest", DefragVlanTest);
2549  UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
2550  UtRegisterTest("DefragVlanQinQinQTest", DefragVlanQinQinQTest);
2551  UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest);
2552  UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest);
2553  UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test);
2554  UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test);
2555  UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
2556 
2557  UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux);
2558 #endif /* UNITTESTS */
2559 }
IPV6_GET_VER
#define IPV6_GET_VER(p)
Definition: decode-ipv6.h:80
ENGINE_SET_EVENT
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:884
DEFAULT_DEFRAG_HASH_SIZE
#define DEFAULT_DEFRAG_HASH_SIZE
Definition: defrag.c:66
Frag_
Definition: defrag.h:46
DEFRAG_POLICY_LINUX
@ DEFRAG_POLICY_LINUX
Definition: defrag.c:91
DefragDestroy
void DefragDestroy(void)
Definition: defrag.c:1078
ConfGetInt
int ConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition: conf.c:399
OS_POLICY_MACOS
@ OS_POLICY_MACOS
Definition: stream-tcp-reassemble.h:45
IPV6ExtHdrs_::fh_data_offset
uint16_t fh_data_offset
Definition: decode-ipv6.h:227
DecodeThreadVars_::counter_defrag_ipv4_reassembled
uint16_t counter_defrag_ipv4_reassembled
Definition: decode.h:720
OS_POLICY_BSD_RIGHT
@ OS_POLICY_BSD_RIGHT
Definition: stream-tcp-reassemble.h:37
DefragTrackerFreeFrags
void DefragTrackerFreeFrags(DefragTracker *tracker)
Free all frags associated with a tracker.
Definition: defrag.c:153
DefragLookupTrackerFromHash
DefragTracker * DefragLookupTrackerFromHash(Packet *p)
look up a tracker in the hash
Definition: defrag-hash.c:634
len
uint8_t len
Definition: app-layer-dnp3.h:2
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
IPV6_FRAG_IGNORED
@ IPV6_FRAG_IGNORED
Definition: decode-events.h:177
TIMEOUT_MIN
#define TIMEOUT_MIN
Definition: defrag.c:83
StatsIncr
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:167
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
OS_POLICY_FIRST
@ OS_POLICY_FIRST
Definition: stream-tcp-reassemble.h:49
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:191
util-hashlist.h
IPV6_EXTHDR_GET_FH_OFFSET
#define IPV6_EXTHDR_GET_FH_OFFSET(p)
Definition: decode-ipv6.h:128
PacketCopyData
int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Copy data to Packet payload and set packet length.
Definition: decode.c:292
PKT_IS_IPV6
#define PKT_IS_IPV6(p)
Definition: decode.h:246
IPV4_GET_IPOFFSET
#define IPV4_GET_IPOFFSET(p)
Definition: decode-ipv4.h:135
RB_REMOVE
#define RB_REMOVE(name, x, y)
Definition: tree.h:773
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
ENGINE_ISSET_EVENT
#define ENGINE_ISSET_EVENT(p, e)
Definition: decode.h:899
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:598
SET_IPV6_DST_ADDR
#define SET_IPV6_DST_ADDR(p, a)
Definition: decode.h:169
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
TIMEOUT_MAX
#define TIMEOUT_MAX
Definition: defrag.c:78
PacketDefragPktSetup
Packet * PacketDefragPktSetup(Packet *parent, const uint8_t *pkt, uint32_t len, uint8_t proto)
Setup a pseudo packet (reassembled frags)
Definition: decode.c:389
Packet_::flags
uint32_t flags
Definition: decode.h:467
IPV6_SET_RAW_VER
#define IPV6_SET_RAW_VER(ip6h, value)
Definition: decode-ipv6.h:69
threads.h
IPV6_FRAG_PKT_TOO_LARGE
@ IPV6_FRAG_PKT_TOO_LARGE
Definition: decode-events.h:170
IP_MF
#define IP_MF
Definition: defrag.c:1090
Frag_::data_len
uint16_t data_len
Definition: defrag.h:63
OS_POLICY_HPUX10
@ OS_POLICY_HPUX10
Definition: stream-tcp-reassemble.h:42
DefragContext_::timeout
time_t timeout
Definition: defrag.h:40
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
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:250
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
DefragTracker_::host_timeout
uint32_t host_timeout
Definition: defrag.h:110
stream-tcp-reassemble.h
proto
uint8_t proto
Definition: decode-template.h:0
defrag-config.h
TmqhOutputPacketpool
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
Definition: tmqh-packetpool.c:356
DefragRbFragCompare
int DefragRbFragCompare(struct Frag_ *a, struct Frag_ *b)
Definition: defrag.c:521
GET_IPV6_DST_ADDR
#define GET_IPV6_DST_ADDR(p)
Definition: decode.h:215
tmqh-packetpool.h
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:84
DEFRAG_POLICY_LAST
@ DEFRAG_POLICY_LAST
Definition: defrag.c:88
OS_POLICY_OLD_LINUX
@ OS_POLICY_OLD_LINUX
Definition: stream-tcp-reassemble.h:38
IPV6_GET_PLEN
#define IPV6_GET_PLEN(p)
Definition: decode-ipv6.h:88
SET_IPV4_SRC_ADDR
#define SET_IPV4_SRC_ADDR(p, a)
Definition: decode.h:143
DefragTracker_::lock
SCMutex lock
Definition: defrag.h:87
PKT_SET_SRC
#define PKT_SET_SRC(p, src_val)
Definition: decode.h:1056
defrag_policies
defrag_policies
Definition: defrag.c:86
DefragGetOsPolicy
uint8_t DefragGetOsPolicy(Packet *p)
Get the defrag policy based on the destination address of the packet.
Definition: defrag.c:929
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:224
SCTIME_FROM_SECS
#define SCTIME_FROM_SECS(s)
Definition: util-time.h:61
IPV6_EXTHDR_GET_FH_FLAG
#define IPV6_EXTHDR_GET_FH_FLAG(p)
Definition: decode-ipv6.h:129
decode-ipv6.h
DefragContext_::frag_pool_lock
SCMutex frag_pool_lock
Definition: defrag.h:38
DefragTracker_::remove
uint8_t remove
Definition: defrag.h:104
IPV4_GET_IPPROTO
#define IPV4_GET_IPPROTO(p)
Definition: decode-ipv4.h:148
OS_POLICY_LAST
@ OS_POLICY_LAST
Definition: stream-tcp-reassemble.h:50
decode.h
RB_EMPTY
#define RB_EMPTY(head)
Definition: tree.h:327
FAIL_IF_NOT_NULL
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
util-debug.h
RB_NFIND
#define RB_NFIND(name, x, y)
Definition: tree.h:775
DEFRAG_POLICY_WINDOWS
@ DEFRAG_POLICY_WINDOWS
Definition: defrag.c:92
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:210
Packet_::ts
SCTime_t ts
Definition: decode.h:475
DefragTracker_::seen_last
uint8_t seen_last
Definition: defrag.h:102
OS_POLICY_LINUX
@ OS_POLICY_LINUX
Definition: stream-tcp-reassemble.h:39
DefragTracker_::policy
uint8_t policy
Definition: defrag.h:97
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
DecodeIPV6FragHeader
void DecodeIPV6FragHeader(Packet *p, const uint8_t *pkt, uint16_t hdrextlen, uint16_t plen, uint16_t prev_hdrextlen)
Definition: decode-ipv6.c:93
DefragTracker_
Definition: defrag.h:86
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:220
IPV4_MAXPACKET_LEN
#define IPV4_MAXPACKET_LEN
Definition: decode-ipv4.h:30
OS_POLICY_SOLARIS
@ OS_POLICY_SOLARIS
Definition: stream-tcp-reassemble.h:41
DefragRegisterTests
void DefragRegisterTests(void)
Definition: defrag.c:2515
UNSET_TUNNEL_PKT
#define UNSET_TUNNEL_PKT(p)
Definition: decode.h:796
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
IPV4_GET_IPLEN
#define IPV4_GET_IPLEN(p)
Definition: decode-ipv4.h:127
Pool_::outstanding
uint32_t outstanding
Definition: util-pool.h:67
SCHInfoGetIPv6HostOSFlavour
int SCHInfoGetIPv6HostOSFlavour(uint8_t *ipv6_addr)
Retrieves the host os flavour, given an ipv6 address in the raw address format.
Definition: util-host-os-info.c:310
SCTIME_FROM_TIMEVAL
#define SCTIME_FROM_TIMEVAL(tv)
Definition: util-time.h:71
SET_IPV6_SRC_ADDR
#define SET_IPV6_SRC_ADDR(p, a)
Definition: decode.h:161
PacketFree
void PacketFree(Packet *p)
Return a malloced packet.
Definition: decode.c:134
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
defrag-queue.h
PrintRawDataFp
void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen)
Definition: util-print.c:143
IPV6_GET_NH
#define IPV6_GET_NH(p)
Definition: decode-ipv6.h:86
IPV4_GET_IPID
#define IPV4_GET_IPID(p)
Definition: decode-ipv4.h:129
RB_FOREACH
#define RB_FOREACH(x, name, head)
Definition: tree.h:781
IPV6Hdr_
Definition: decode-ipv6.h:32
Packet_
Definition: decode.h:430
DefragTracker_::id
uint32_t id
Definition: defrag.h:92
OS_POLICY_BSD
@ OS_POLICY_BSD
Definition: stream-tcp-reassemble.h:36
DEFRAG_POLICY_FIRST
@ DEFRAG_POLICY_FIRST
Definition: defrag.c:87
DecodeIPV6
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv6.c:564
GET_PKT_LEN
#define GET_PKT_LEN(p)
Definition: decode.h:219
PoolFree
void PoolFree(Pool *p)
Definition: util-pool.c:226
stream-tcp-private.h
conf.h
Packet_::ip4h
IPV4Hdr * ip4h
Definition: decode.h:535
Frag_::skip
uint8_t skip
Definition: defrag.h:55
DefragInitConfig
void DefragInitConfig(bool quiet)
initialize the configuration
Definition: defrag-hash.c:166
Frag_::pkt
uint8_t * pkt
Definition: defrag.h:68
Frag_::data_offset
uint16_t data_offset
Definition: defrag.h:62
queue.h
IPV6_FRAG_OVERLAP
@ IPV6_FRAG_OVERLAP
Definition: decode-events.h:172
defrag.h
OS_POLICY_VISTA
@ OS_POLICY_VISTA
Definition: stream-tcp-reassemble.h:47
IPV6ExtHdrs_::fh_data_len
uint16_t fh_data_len
Definition: decode-ipv6.h:228
DefragTrackerRelease
void DefragTrackerRelease(DefragTracker *t)
Definition: defrag-hash.c:149
SCMutexInit
#define SCMutexInit(mut, mutattrs)
Definition: threads-debug.h:116
DefragContext_
Definition: defrag.h:36
Frag_::ltrim
uint16_t ltrim
Definition: defrag.h:65
util-host-os-info.h
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:33
IPV4Hdr_
Definition: decode-ipv4.h:72
default_packet_size
uint32_t default_packet_size
Definition: decode.c:72
PoolReturn
void PoolReturn(Pool *p, void *data)
Definition: util-pool.c:339
DefragTracker_::fragment_tree
struct IP_FRAGMENTS fragment_tree
Definition: defrag.h:115
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:162
IPV6Hdr
struct IPV6Hdr_ IPV6Hdr
suricata-common.h
Frag_::len
uint32_t len
Definition: defrag.h:50
DefragGetTrackerFromHash
DefragTracker * DefragGetTrackerFromHash(Packet *p)
Definition: defrag-hash.c:535
IPV4_HEADER_LEN
#define IPV4_HEADER_LEN
Definition: decode-ipv4.h:28
packet.h
DefragTracker_::timeout
SCTime_t timeout
Definition: defrag.h:109
SCTIME_SECS
#define SCTIME_SECS(t)
Definition: util-time.h:57
IPV6ExtHdrs_::fh_header_offset
uint16_t fh_header_offset
Definition: decode-ipv6.h:226
OS_POLICY_OLD_SOLARIS
@ OS_POLICY_OLD_SOLARIS
Definition: stream-tcp-reassemble.h:40
DecodeThreadVars_::counter_defrag_ipv6_reassembled
uint16_t counter_defrag_ipv6_reassembled
Definition: decode.h:722
IPV6ExtHdrs_::fh_prev_hdr_offset
uint16_t fh_prev_hdr_offset
Definition: decode-ipv6.h:224
FatalError
#define FatalError(...)
Definition: util-debug.h:502
PKT_SRC_DEFRAG
@ PKT_SRC_DEFRAG
Definition: decode.h:59
DefragPolicyLoadFromConfig
void DefragPolicyLoadFromConfig(void)
Definition: defrag-config.c:134
DEFRAG_POLICY_SOLARIS
@ DEFRAG_POLICY_SOLARIS
Definition: defrag.c:93
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
OS_POLICY_HPUX11
@ OS_POLICY_HPUX11
Definition: stream-tcp-reassemble.h:43
Frag_::frag_hdr_offset
uint16_t frag_hdr_offset
Definition: defrag.h:59
util-validate.h
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
IPV6_MAXPACKET
#define IPV6_MAXPACKET
Definition: decode-ipv6.h:28
IPV4_GET_HLEN
#define IPV4_GET_HLEN(p)
Definition: decode-ipv4.h:124
IPV4_FRAG_OVERLAP
@ IPV4_FRAG_OVERLAP
Definition: decode-events.h:171
Packet_::root
struct Packet_ * root
Definition: decode.h:622
PoolGet
void * PoolGet(Pool *p)
Definition: util-pool.c:281
PKT_REBUILT_FRAGMENT
#define PKT_REBUILT_FRAGMENT
Definition: decode.h:1036
SCHInfoGetIPv4HostOSFlavour
int SCHInfoGetIPv4HostOSFlavour(uint8_t *ipv4_addr)
Retrieves the host os flavour, given an ipv4 address in the raw address format.
Definition: util-host-os-info.c:292
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:668
MAX_PAYLOAD_SIZE
#define MAX_PAYLOAD_SIZE
Definition: decode.h:662
Frag_::more_frags
uint8_t more_frags
Definition: defrag.h:54
DefragTracker_::af
uint8_t af
Definition: defrag.h:99
IPV6_EXTHDR_GET_FH_NH
#define IPV6_EXTHDR_GET_FH_NH(p)
Definition: decode-ipv6.h:127
Packet_::recursion_level
uint8_t recursion_level
Definition: decode.h:455
IPV4_GET_MF
#define IPV4_GET_MF(p)
Definition: decode-ipv4.h:144
DecodeThreadVars_::counter_defrag_max_hit
uint16_t counter_defrag_max_hit
Definition: decode.h:723
util-random.h
IPV4Hdr_::ip_csum
uint16_t ip_csum
Definition: decode-ipv4.h:80
DEFRAG_POLICY_DEFAULT
@ DEFRAG_POLICY_DEFAULT
Definition: defrag.c:95
suricata.h
defrag-hash.h
IPV4_FRAG_IGNORED
@ IPV4_FRAG_IGNORED
Definition: decode-events.h:176
Packet_::dst
Address dst
Definition: decode.h:435
TIMEOUT_DEFAULT
#define TIMEOUT_DEFAULT
Definition: defrag.c:73
DecodeThreadVars_::counter_defrag_ipv6_fragments
uint16_t counter_defrag_ipv6_fragments
Definition: decode.h:721
IPV6_HEADER_LEN
#define IPV6_HEADER_LEN
Definition: decode-ipv6.h:27
Packet_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: decode.h:457
ConfSet
int ConfSet(const char *name, const char *val)
Set a configuration value.
Definition: conf.c:224
af
uint16_t af
Definition: decode-gre.h:0
Frag_::hlen
uint8_t hlen
Definition: defrag.h:52
DEFAULT_DEFRAG_POOL_SIZE
#define DEFAULT_DEFRAG_POOL_SIZE
Definition: defrag.c:67
OS_POLICY_WINDOWS
@ OS_POLICY_WINDOWS
Definition: stream-tcp-reassemble.h:46
PacketDefragPktSetupParent
void PacketDefragPktSetupParent(Packet *parent)
inform defrag "parent" that a pseudo packet is now associated to it.
Definition: decode.c:426
DefragHashShutdown
void DefragHashShutdown(void)
shutdown the flow engine
Definition: defrag-hash.c:302
RB_GENERATE
RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare)
IPV4Hdr_::ip_off
uint16_t ip_off
Definition: decode-ipv4.h:77
Packet_::ip6h
IPV6Hdr * ip6h
Definition: decode.h:537
SET_IPV4_DST_ADDR
#define SET_IPV4_DST_ADDR(p, a)
Definition: decode.h:151
OS_POLICY_WINDOWS2K3
@ OS_POLICY_WINDOWS2K3
Definition: stream-tcp-reassemble.h:48
RB_FOREACH_FROM
#define RB_FOREACH_FROM(x, name, y)
Definition: tree.h:786
IPV4_GET_VER
#define IPV4_GET_VER(p)
Definition: decode-ipv4.h:122
DefragSetDefaultTimeout
void DefragSetDefaultTimeout(intmax_t timeout)
Definition: defrag-config.c:128
Defrag
Packet * Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Entry point for IPv4 and IPv6 fragments.
Definition: defrag.c:1008
DecodeIPV4
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv4.c:520
PacketInit
void PacketInit(Packet *p)
Initialize a packet structure for use.
Definition: packet.c:62
SCTIME_ADD_SECS
#define SCTIME_ADD_SECS(ts, s)
Definition: util-time.h:59
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
IPV4Hdr_::ip_proto
uint8_t ip_proto
Definition: decode-ipv4.h:79
util-pool.h
PoolInit
Pool * PoolInit(uint32_t size, uint32_t prealloc_size, uint32_t elt_size, void *(*Alloc)(void), int(*Init)(void *, void *), void *InitData, void(*Cleanup)(void *), void(*Free)(void *))
Init a Pool.
Definition: util-pool.c:84
PKT_IS_IPV4
#define PKT_IS_IPV4(p)
Definition: decode.h:245
IPV4Hdr_::ip_verhl
uint8_t ip_verhl
Definition: decode-ipv4.h:73
DEFRAG_POLICY_BSD
@ DEFRAG_POLICY_BSD
Definition: defrag.c:89
IPV4_FRAG_PKT_TOO_LARGE
@ IPV4_FRAG_PKT_TOO_LARGE
Definition: decode-events.h:169
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:104
Frag_::offset
uint16_t offset
Definition: defrag.h:47
Packet_::src
Address src
Definition: decode.h:434
OS_POLICY_IRIX
@ OS_POLICY_IRIX
Definition: stream-tcp-reassemble.h:44
DefragInit
void DefragInit(void)
Definition: defrag.c:1058
IPV4_GET_IPTTL
#define IPV4_GET_IPTTL(p)
Definition: decode-ipv4.h:146
Packet_::ip6eh
IPV6ExtHdrs ip6eh
Definition: decode.h:544
Frag_::ip_hdr_offset
uint16_t ip_hdr_offset
Definition: defrag.h:57
DEFRAG_POLICY_BSD_RIGHT
@ DEFRAG_POLICY_BSD_RIGHT
Definition: defrag.c:90
DecodeThreadVars_::counter_defrag_ipv4_fragments
uint16_t counter_defrag_ipv4_fragments
Definition: decode.h:719