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  }
291 
292  int fragmentable_offset = 0;
293  uint16_t fragmentable_len = 0;
294  uint16_t hlen = 0;
295  int ip_hdr_offset = 0;
296 
297  RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
298  SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64,
299  frag, frag->data_len, frag->offset, frag->pcap_cnt);
300 
301  if (frag->skip)
302  continue;
303  if (frag->ltrim >= frag->data_len)
304  continue;
305  if (frag->offset == 0) {
306 
307  if (PacketCopyData(rp, frag->pkt, frag->len) == -1)
308  goto error_remove_tracker;
309 
310  hlen = frag->hlen;
311  ip_hdr_offset = frag->ip_hdr_offset;
312 
313  /* This is the start of the fragmentable portion of the
314  * first packet. All fragment offsets are relative to
315  * this. */
316  fragmentable_offset = frag->ip_hdr_offset + frag->hlen;
317  fragmentable_len = frag->data_len;
318  }
319  else {
320  int pkt_end = fragmentable_offset + frag->offset + frag->data_len;
321  if (pkt_end > (int)MAX_PAYLOAD_SIZE) {
322  SCLogDebug("Failed re-assemble "
323  "fragmented packet, exceeds size of packet buffer.");
324  goto error_remove_tracker;
325  }
326  if (PacketCopyDataOffset(rp,
327  fragmentable_offset + frag->offset + frag->ltrim,
328  frag->pkt + frag->data_offset + frag->ltrim,
329  frag->data_len - frag->ltrim) == -1) {
330  goto error_remove_tracker;
331  }
332  if (frag->offset > UINT16_MAX - frag->data_len) {
333  SCLogDebug("Failed re-assemble "
334  "fragmentable_len exceeds UINT16_MAX");
335  goto error_remove_tracker;
336  }
337  if (frag->offset + frag->data_len > fragmentable_len)
338  fragmentable_len = frag->offset + frag->data_len;
339  }
340 
341  if (!frag->more_frags) {
342  break;
343  }
344  }
345 
346  SCLogDebug("ip_hdr_offset %u, hlen %" PRIu16 ", fragmentable_len %" PRIu16, ip_hdr_offset, hlen,
347  fragmentable_len);
348 
349  rp->ip4h = (IPV4Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
350  uint16_t old = rp->ip4h->ip_len + rp->ip4h->ip_off;
351  DEBUG_VALIDATE_BUG_ON(hlen > UINT16_MAX - fragmentable_len);
352  rp->ip4h->ip_len = htons(fragmentable_len + hlen);
353  rp->ip4h->ip_off = 0;
354  rp->ip4h->ip_csum = FixChecksum(rp->ip4h->ip_csum,
355  old, rp->ip4h->ip_len + rp->ip4h->ip_off);
356  SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len);
357 
358  tracker->remove = 1;
359  DefragTrackerFreeFrags(tracker);
360 done:
361  return rp;
362 
363 error_remove_tracker:
364  tracker->remove = 1;
365  DefragTrackerFreeFrags(tracker);
366  if (rp != NULL)
368  return NULL;
369 }
370 
371 /**
372  * Attempt to re-assemble a packet.
373  *
374  * \param tracker The defragmentation tracker to reassemble from.
375  */
376 static Packet *
377 Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
378 {
379  Packet *rp = NULL;
380 
381  /* Should not be here unless we have seen the last fragment. */
382  if (!tracker->seen_last)
383  return NULL;
384 
385  /* Check that we have the first fragment and its of a valid size. */
386  Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
387  if (first == NULL) {
388  goto done;
389  } else if (first->offset != 0) {
390  /* Still waiting for the first fragment. */
391  goto done;
392  } else if (first->len < sizeof(IPV6Hdr)) {
393  /* First fragment isn't enough for an IPv6 header. */
394  goto error_remove_tracker;
395  }
396 
397  /* Check that we have all the data. Relies on the fact that
398  * fragments are inserted if frag_offset order. */
399  size_t len = 0;
400  Frag *frag = NULL;
401  RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
402  if (frag->skip) {
403  continue;
404  }
405 
406  if (frag == first) {
407  if (frag->offset != 0) {
408  goto done;
409  }
410  len = frag->data_len;
411  }
412  else {
413  if (frag->offset > len) {
414  /* This fragment starts after the end of the previous
415  * fragment. We have a hole. */
416  goto done;
417  }
418  else {
419  len += frag->data_len;
420  }
421  }
422  }
423 
424  /* Allocate a Packet for the reassembled packet. On failure we
425  * SCFree all the resources held by this tracker. */
426  rp = PacketDefragPktSetup(p, (uint8_t *)p->ip6h,
427  IPV6_GET_PLEN(p) + sizeof(IPV6Hdr), 0);
428  if (rp == NULL) {
429  goto error_remove_tracker;
430  }
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, IPV4_GET_IPLEN(r)) != TM_ECODE_OK) {
877  r->root = NULL;
879  r = NULL;
880  } else {
882  }
883  }
884  }
885  else if (tracker->af == AF_INET6) {
886  r = Defrag6Reassemble(tv, tracker, p);
887  if (r != NULL && tv != NULL && dtv != NULL) {
889  if (DecodeIPV6(tv, dtv, r, (uint8_t *)r->ip6h,
891  r->root = NULL;
893  r = NULL;
894  } else {
896  }
897  }
898  }
899  }
900 
901 
902 done:
903  if (overlap) {
904  if (af == AF_INET) {
906  }
907  else {
909  }
910  }
911  return r;
912 }
913 
914 /**
915  * \brief Get the defrag policy based on the destination address of
916  * the packet.
917  *
918  * \param p The packet used to get the destination address.
919  *
920  * \retval The defrag policy to use.
921  */
922 uint8_t
924 {
925  int policy = -1;
926 
927  if (PKT_IS_IPV4(p)) {
928  policy = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
929  }
930  else if (PKT_IS_IPV6(p)) {
931  policy = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
932  }
933 
934  if (policy == -1) {
935  return default_policy;
936  }
937 
938  /* Map the OS policies returned from the configured host info to
939  * defrag specific policies. */
940  switch (policy) {
941  /* BSD. */
942  case OS_POLICY_BSD:
943  case OS_POLICY_HPUX10:
944  case OS_POLICY_IRIX:
945  return DEFRAG_POLICY_BSD;
946 
947  /* BSD-Right. */
948  case OS_POLICY_BSD_RIGHT:
950 
951  /* Linux. */
952  case OS_POLICY_OLD_LINUX:
953  case OS_POLICY_LINUX:
954  return DEFRAG_POLICY_LINUX;
955 
956  /* First. */
958  case OS_POLICY_HPUX11:
959  case OS_POLICY_MACOS:
960  case OS_POLICY_FIRST:
961  return DEFRAG_POLICY_FIRST;
962 
963  /* Solaris. */
964  case OS_POLICY_SOLARIS:
965  return DEFRAG_POLICY_SOLARIS;
966 
967  /* Windows. */
968  case OS_POLICY_WINDOWS:
969  case OS_POLICY_VISTA:
971  return DEFRAG_POLICY_WINDOWS;
972 
973  /* Last. */
974  case OS_POLICY_LAST:
975  return DEFRAG_POLICY_LAST;
976 
977  default:
978  return default_policy;
979  }
980 }
981 
982 /** \internal
983  *
984  * \retval NULL or a *LOCKED* tracker */
985 static DefragTracker *
986 DefragGetTracker(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
987 {
988  return DefragGetTrackerFromHash(p);
989 }
990 
991 /**
992  * \brief Entry point for IPv4 and IPv6 fragments.
993  *
994  * \param tv ThreadVars for the calling decoder.
995  * \param p The packet fragment.
996  *
997  * \retval A new Packet resembling the re-assembled packet if the most
998  * recent fragment allowed the packet to be re-assembled, otherwise
999  * NULL is returned.
1000  */
1001 Packet *
1003 {
1004  uint16_t frag_offset;
1005  uint8_t more_frags;
1006  DefragTracker *tracker;
1007  int af;
1008 
1009  if (PKT_IS_IPV4(p)) {
1010  af = AF_INET;
1011  more_frags = IPV4_GET_MF(p);
1012  frag_offset = IPV4_GET_IPOFFSET(p);
1013  }
1014  else if (PKT_IS_IPV6(p)) {
1015  af = AF_INET6;
1016  frag_offset = IPV6_EXTHDR_GET_FH_OFFSET(p);
1017  more_frags = IPV6_EXTHDR_GET_FH_FLAG(p);
1018  }
1019  else {
1020  return NULL;
1021  }
1022 
1023  if (frag_offset == 0 && more_frags == 0) {
1024  return NULL;
1025  }
1026 
1027  if (tv != NULL && dtv != NULL) {
1028  if (af == AF_INET) {
1030  }
1031  else if (af == AF_INET6) {
1033  }
1034  }
1035 
1036  /* return a locked tracker or NULL */
1037  tracker = DefragGetTracker(tv, dtv, p);
1038  if (tracker == NULL) {
1039  if (tv != NULL && dtv != NULL) {
1041  }
1042  return NULL;
1043  }
1044 
1045  Packet *rp = DefragInsertFrag(tv, dtv, tracker, p);
1046  DefragTrackerRelease(tracker);
1047 
1048  return rp;
1049 }
1050 
1051 void
1053 {
1054  intmax_t tracker_pool_size;
1055  if (!ConfGetInt("defrag.trackers", &tracker_pool_size)) {
1056  tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
1057  }
1058 
1059  /* Load the defrag-per-host lookup. */
1061 
1062  /* Allocate the DefragContext. */
1063  defrag_context = DefragContextNew();
1064  if (defrag_context == NULL) {
1065  FatalError("Failed to allocate memory for the Defrag module.");
1066  }
1067 
1068  DefragSetDefaultTimeout(defrag_context->timeout);
1069  DefragInitConfig(false);
1070 }
1071 
1072 void DefragDestroy(void)
1073 {
1075  DefragContextDestroy(defrag_context);
1076  defrag_context = NULL;
1078 }
1079 
1080 #ifdef UNITTESTS
1081 #include "util-unittest-helper.h"
1082 #include "packet.h"
1083 
1084 #define IP_MF 0x2000
1086 /**
1087  * Allocate a test packet. Nothing to fancy, just a simple IP packet
1088  * with some payload of no particular protocol.
1089  */
1090 static Packet *BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf,
1091  const char content, int content_len)
1092 {
1093  Packet *p = NULL;
1094  int hlen = 20;
1095  int ttl = 64;
1096  uint8_t *pcontent;
1097  IPV4Hdr ip4h;
1098 
1099  p = SCCalloc(1, sizeof(*p) + default_packet_size);
1100  if (unlikely(p == NULL))
1101  return NULL;
1102 
1103  PacketInit(p);
1104 
1105  struct timeval tval;
1106  gettimeofday(&tval, NULL);
1107  p->ts = SCTIME_FROM_TIMEVAL(&tval);
1108  //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1109  ip4h.ip_verhl = 4 << 4;
1110  ip4h.ip_verhl |= hlen >> 2;
1111  ip4h.ip_len = htons(hlen + content_len);
1112  ip4h.ip_id = htons(id);
1113  if (mf)
1114  ip4h.ip_off = htons(IP_MF | off);
1115  else
1116  ip4h.ip_off = htons(off);
1117  ip4h.ip_ttl = ttl;
1118  ip4h.ip_proto = proto;
1119 
1120  ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1121  ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1122 
1123  /* copy content_len crap, we need full length */
1124  PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1125  p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1126  SET_IPV4_SRC_ADDR(p, &p->src);
1127  SET_IPV4_DST_ADDR(p, &p->dst);
1128 
1129  pcontent = SCCalloc(1, content_len);
1130  if (unlikely(pcontent == NULL))
1131  return NULL;
1132  memset(pcontent, content, content_len);
1133  PacketCopyDataOffset(p, hlen, pcontent, content_len);
1134  SET_PKT_LEN(p, hlen + content_len);
1135  SCFree(pcontent);
1136 
1137  p->ip4h->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1138 
1139  /* Self test. */
1140  if (IPV4_GET_VER(p) != 4)
1141  goto error;
1142  if (IPV4_GET_HLEN(p) != hlen)
1143  goto error;
1144  if (IPV4_GET_IPLEN(p) != hlen + content_len)
1145  goto error;
1146  if (IPV4_GET_IPID(p) != id)
1147  goto error;
1148  if (IPV4_GET_IPOFFSET(p) != off)
1149  goto error;
1150  if (IPV4_GET_MF(p) != mf)
1151  goto error;
1152  if (IPV4_GET_IPTTL(p) != ttl)
1153  goto error;
1154  if (IPV4_GET_IPPROTO(p) != proto)
1155  goto error;
1156 
1157  return p;
1158 error:
1159  if (p != NULL)
1160  SCFree(p);
1161  return NULL;
1162 }
1163 
1164 static Packet *IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off,
1165  int mf, const char content, int content_len)
1166 {
1167  Packet *p = NULL;
1168  uint8_t *pcontent;
1169  IPV6Hdr ip6h;
1170 
1171  p = SCCalloc(1, sizeof(*p) + default_packet_size);
1172  if (unlikely(p == NULL))
1173  return NULL;
1174 
1175  PacketInit(p);
1176 
1177  struct timeval tval;
1178  gettimeofday(&tval, NULL);
1179  p->ts = SCTIME_FROM_TIMEVAL(&tval);
1180 
1181  ip6h.s_ip6_nxt = 44;
1182  ip6h.s_ip6_hlim = 2;
1183 
1184  /* Source and dest address - very bogus addresses. */
1185  ip6h.s_ip6_src[0] = 0x01010101;
1186  ip6h.s_ip6_src[1] = 0x01010101;
1187  ip6h.s_ip6_src[2] = 0x01010101;
1188  ip6h.s_ip6_src[3] = 0x01010101;
1189  ip6h.s_ip6_dst[0] = 0x02020202;
1190  ip6h.s_ip6_dst[1] = 0x02020202;
1191  ip6h.s_ip6_dst[2] = 0x02020202;
1192  ip6h.s_ip6_dst[3] = 0x02020202;
1193 
1194  /* copy content_len crap, we need full length */
1195  PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1196 
1197  p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
1198  IPV6_SET_RAW_VER(p->ip6h, 6);
1199  /* Fragmentation header. */
1200  IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1201  fh->ip6fh_nxt = proto;
1202  fh->ip6fh_ident = htonl(id);
1203  fh->ip6fh_offlg = htons((off << 3) | mf);
1204 
1205  DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1206 
1207  pcontent = SCCalloc(1, content_len);
1208  if (unlikely(pcontent == NULL))
1209  return NULL;
1210  memset(pcontent, content, content_len);
1211  PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), pcontent, content_len);
1212  SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1213  SCFree(pcontent);
1214 
1215  p->ip6h->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1216 
1217  SET_IPV6_SRC_ADDR(p, &p->src);
1218  SET_IPV6_DST_ADDR(p, &p->dst);
1219 
1220  /* Self test. */
1221  if (IPV6_GET_VER(p) != 6)
1222  goto error;
1223  if (IPV6_GET_NH(p) != 44)
1224  goto error;
1225  if (IPV6_GET_PLEN(p) != sizeof(IPV6FragHdr) + content_len)
1226  goto error;
1227 
1228  return p;
1229 error:
1230  if (p != NULL)
1231  SCFree(p);
1232  return NULL;
1233 }
1234 
1235 /**
1236  * Test the simplest possible re-assembly scenario. All packet in
1237  * order and no overlaps.
1238  */
1239 static int DefragInOrderSimpleTest(void)
1240 {
1241  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1242  Packet *reassembled = NULL;
1243  int id = 12;
1244  int i;
1245 
1246  DefragInit();
1247 
1248  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1249  FAIL_IF_NULL(p1);
1250  p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1251  FAIL_IF_NULL(p2);
1252  p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1253  FAIL_IF_NULL(p3);
1254 
1255  FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1256  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1257 
1258  reassembled = Defrag(NULL, NULL, p3);
1259  FAIL_IF_NULL(reassembled);
1260 
1261  FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1262  FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1263 
1264  /* 20 bytes in we should find 8 bytes of A. */
1265  for (i = 20; i < 20 + 8; i++) {
1266  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1267  }
1268 
1269  /* 28 bytes in we should find 8 bytes of B. */
1270  for (i = 28; i < 28 + 8; i++) {
1271  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1272  }
1273 
1274  /* And 36 bytes in we should find 3 bytes of C. */
1275  for (i = 36; i < 36 + 3; i++) {
1276  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1277  }
1278 
1279  SCFree(p1);
1280  SCFree(p2);
1281  SCFree(p3);
1282  SCFree(reassembled);
1283 
1284  DefragDestroy();
1285  PASS;
1286 }
1287 
1288 /**
1289  * Simple fragmented packet in reverse order.
1290  */
1291 static int DefragReverseSimpleTest(void)
1292 {
1293  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1294  Packet *reassembled = NULL;
1295  int id = 12;
1296  int i;
1297 
1298  DefragInit();
1299 
1300  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1301  FAIL_IF_NULL(p1);
1302  p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1303  FAIL_IF_NULL(p2);
1304  p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1305  FAIL_IF_NULL(p3);
1306 
1307  FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1308  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1309 
1310  reassembled = Defrag(NULL, NULL, p1);
1311  FAIL_IF_NULL(reassembled);
1312 
1313  FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1314  FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1315 
1316  /* 20 bytes in we should find 8 bytes of A. */
1317  for (i = 20; i < 20 + 8; i++) {
1318  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1319  }
1320 
1321  /* 28 bytes in we should find 8 bytes of B. */
1322  for (i = 28; i < 28 + 8; i++) {
1323  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1324  }
1325 
1326  /* And 36 bytes in we should find 3 bytes of C. */
1327  for (i = 36; i < 36 + 3; i++) {
1328  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1329  }
1330 
1331  SCFree(p1);
1332  SCFree(p2);
1333  SCFree(p3);
1334  SCFree(reassembled);
1335 
1336  DefragDestroy();
1337  PASS;
1338 }
1339 
1340 /**
1341  * Test the simplest possible re-assembly scenario. All packet in
1342  * order and no overlaps.
1343  */
1344 static int IPV6DefragInOrderSimpleTest(void)
1345 {
1346  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1347  Packet *reassembled = NULL;
1348  int id = 12;
1349  int i;
1350 
1351  DefragInit();
1352 
1353  p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1354  FAIL_IF_NULL(p1);
1355  p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1356  FAIL_IF_NULL(p2);
1357  p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1358  FAIL_IF_NULL(p3);
1359 
1360  FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1361  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1362  reassembled = Defrag(NULL, NULL, p3);
1363  FAIL_IF_NULL(reassembled);
1364 
1365  FAIL_IF(IPV6_GET_PLEN(reassembled) != 19);
1366 
1367  /* 40 bytes in we should find 8 bytes of A. */
1368  for (i = 40; i < 40 + 8; i++) {
1369  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1370  }
1371 
1372  /* 28 bytes in we should find 8 bytes of B. */
1373  for (i = 48; i < 48 + 8; i++) {
1374  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1375  }
1376 
1377  /* And 36 bytes in we should find 3 bytes of C. */
1378  for (i = 56; i < 56 + 3; i++) {
1379  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1380  }
1381 
1382  SCFree(p1);
1383  SCFree(p2);
1384  SCFree(p3);
1385  SCFree(reassembled);
1386 
1387  DefragDestroy();
1388  PASS;
1389 }
1390 
1391 static int IPV6DefragReverseSimpleTest(void)
1392 {
1393  DefragContext *dc = NULL;
1394  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1395  Packet *reassembled = NULL;
1396  int id = 12;
1397  int i;
1398 
1399  DefragInit();
1400 
1401  dc = DefragContextNew();
1402  FAIL_IF_NULL(dc);
1403 
1404  p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1405  FAIL_IF_NULL(p1);
1406  p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1407  FAIL_IF_NULL(p2);
1408  p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1409  FAIL_IF_NULL(p3);
1410 
1411  FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1412  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1413  reassembled = Defrag(NULL, NULL, p1);
1414  FAIL_IF_NULL(reassembled);
1415 
1416  /* 40 bytes in we should find 8 bytes of A. */
1417  for (i = 40; i < 40 + 8; i++) {
1418  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1419  }
1420 
1421  /* 28 bytes in we should find 8 bytes of B. */
1422  for (i = 48; i < 48 + 8; i++) {
1423  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1424  }
1425 
1426  /* And 36 bytes in we should find 3 bytes of C. */
1427  for (i = 56; i < 56 + 3; i++) {
1428  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1429  }
1430 
1431  DefragContextDestroy(dc);
1432  SCFree(p1);
1433  SCFree(p2);
1434  SCFree(p3);
1435  SCFree(reassembled);
1436 
1437  DefragDestroy();
1438  PASS;
1439 }
1440 
1441 static int DefragDoSturgesNovakTest(int policy, u_char *expected,
1442  size_t expected_len)
1443 {
1444  int i;
1445 
1446  DefragInit();
1447 
1448  /*
1449  * Build the packets.
1450  */
1451 
1452  int id = 1;
1453  Packet *packets[17];
1454  memset(packets, 0x00, sizeof(packets));
1455 
1456  /*
1457  * Original fragments.
1458  */
1459 
1460  /* A*24 at 0. */
1461  packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
1462 
1463  /* B*15 at 32. */
1464  packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
1465 
1466  /* C*24 at 48. */
1467  packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
1468 
1469  /* D*8 at 80. */
1470  packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
1471 
1472  /* E*16 at 104. */
1473  packets[4] = BuildTestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
1474 
1475  /* F*24 at 120. */
1476  packets[5] = BuildTestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
1477 
1478  /* G*16 at 144. */
1479  packets[6] = BuildTestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
1480 
1481  /* H*16 at 160. */
1482  packets[7] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
1483 
1484  /* I*8 at 176. */
1485  packets[8] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
1486 
1487  /*
1488  * Overlapping subsequent fragments.
1489  */
1490 
1491  /* J*32 at 8. */
1492  packets[9] = BuildTestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
1493 
1494  /* K*24 at 48. */
1495  packets[10] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
1496 
1497  /* L*24 at 72. */
1498  packets[11] = BuildTestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
1499 
1500  /* M*24 at 96. */
1501  packets[12] = BuildTestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
1502 
1503  /* N*8 at 128. */
1504  packets[13] = BuildTestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
1505 
1506  /* O*8 at 152. */
1507  packets[14] = BuildTestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
1508 
1509  /* P*8 at 160. */
1510  packets[15] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
1511 
1512  /* Q*16 at 176. */
1513  packets[16] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
1514 
1515  default_policy = policy;
1516 
1517  /* Send all but the last. */
1518  for (i = 0; i < 9; i++) {
1519  Packet *tp = Defrag(NULL, NULL, packets[i]);
1520  FAIL_IF_NOT_NULL(tp);
1522  }
1523  int overlap = 0;
1524  for (; i < 16; i++) {
1525  Packet *tp = Defrag(NULL, NULL, packets[i]);
1526  FAIL_IF_NOT_NULL(tp);
1527  if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) {
1528  overlap++;
1529  }
1530  }
1531  FAIL_IF_NOT(overlap);
1532 
1533  /* And now the last one. */
1534  Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1535  FAIL_IF_NULL(reassembled);
1536 
1537  FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1538  FAIL_IF(IPV4_GET_IPLEN(reassembled) != 20 + 192);
1539 
1540  FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0);
1541  SCFree(reassembled);
1542 
1543  /* Make sure all frags were returned back to the pool. */
1544  FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1545 
1546  for (i = 0; i < 17; i++) {
1547  SCFree(packets[i]);
1548  }
1549  DefragDestroy();
1550  PASS;
1551 }
1552 
1553 static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected,
1554  size_t expected_len)
1555 {
1556  int i;
1557 
1558  DefragInit();
1559 
1560  /*
1561  * Build the packets.
1562  */
1563 
1564  int id = 1;
1565  Packet *packets[17];
1566  memset(packets, 0x00, sizeof(packets));
1567 
1568  /*
1569  * Original fragments.
1570  */
1571 
1572  /* A*24 at 0. */
1573  packets[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
1574 
1575  /* B*15 at 32. */
1576  packets[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
1577 
1578  /* C*24 at 48. */
1579  packets[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
1580 
1581  /* D*8 at 80. */
1582  packets[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
1583 
1584  /* E*16 at 104. */
1585  packets[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
1586 
1587  /* F*24 at 120. */
1588  packets[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
1589 
1590  /* G*16 at 144. */
1591  packets[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
1592 
1593  /* H*16 at 160. */
1594  packets[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
1595 
1596  /* I*8 at 176. */
1597  packets[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
1598 
1599  /*
1600  * Overlapping subsequent fragments.
1601  */
1602 
1603  /* J*32 at 8. */
1604  packets[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
1605 
1606  /* K*24 at 48. */
1607  packets[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
1608 
1609  /* L*24 at 72. */
1610  packets[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
1611 
1612  /* M*24 at 96. */
1613  packets[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
1614 
1615  /* N*8 at 128. */
1616  packets[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
1617 
1618  /* O*8 at 152. */
1619  packets[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
1620 
1621  /* P*8 at 160. */
1622  packets[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
1623 
1624  /* Q*16 at 176. */
1625  packets[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
1626 
1627  default_policy = policy;
1628 
1629  /* Send all but the last. */
1630  for (i = 0; i < 9; i++) {
1631  Packet *tp = Defrag(NULL, NULL, packets[i]);
1632  FAIL_IF_NOT_NULL(tp);
1634  }
1635  int overlap = 0;
1636  for (; i < 16; i++) {
1637  Packet *tp = Defrag(NULL, NULL, packets[i]);
1638  FAIL_IF_NOT_NULL(tp);
1639  if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) {
1640  overlap++;
1641  }
1642  }
1643  FAIL_IF_NOT(overlap);
1644 
1645  /* And now the last one. */
1646  Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1647  FAIL_IF_NULL(reassembled);
1648  FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0);
1649 
1650  FAIL_IF(IPV6_GET_PLEN(reassembled) != 192);
1651 
1652  SCFree(reassembled);
1653 
1654  /* Make sure all frags were returned to the pool. */
1655  FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1656 
1657  for (i = 0; i < 17; i++) {
1658  SCFree(packets[i]);
1659  }
1660  DefragDestroy();
1661  PASS;
1662 }
1663 
1664 static int
1665 DefragSturgesNovakBsdTest(void)
1666 {
1667  /* Expected data. */
1668  u_char expected[] = {
1669  "AAAAAAAA"
1670  "AAAAAAAA"
1671  "AAAAAAAA"
1672  "JJJJJJJJ"
1673  "JJJJJJJJ"
1674  "BBBBBBBB"
1675  "CCCCCCCC"
1676  "CCCCCCCC"
1677  "CCCCCCCC"
1678  "LLLLLLLL"
1679  "LLLLLLLL"
1680  "LLLLLLLL"
1681  "MMMMMMMM"
1682  "MMMMMMMM"
1683  "MMMMMMMM"
1684  "FFFFFFFF"
1685  "FFFFFFFF"
1686  "FFFFFFFF"
1687  "GGGGGGGG"
1688  "GGGGGGGG"
1689  "HHHHHHHH"
1690  "HHHHHHHH"
1691  "IIIIIIII"
1692  "QQQQQQQQ"
1693  };
1694 
1695  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1696  sizeof(expected)));
1697  PASS;
1698 }
1699 
1700 static int IPV6DefragSturgesNovakBsdTest(void)
1701 {
1702  /* Expected data. */
1703  u_char expected[] = {
1704  "AAAAAAAA"
1705  "AAAAAAAA"
1706  "AAAAAAAA"
1707  "JJJJJJJJ"
1708  "JJJJJJJJ"
1709  "BBBBBBBB"
1710  "CCCCCCCC"
1711  "CCCCCCCC"
1712  "CCCCCCCC"
1713  "LLLLLLLL"
1714  "LLLLLLLL"
1715  "LLLLLLLL"
1716  "MMMMMMMM"
1717  "MMMMMMMM"
1718  "MMMMMMMM"
1719  "FFFFFFFF"
1720  "FFFFFFFF"
1721  "FFFFFFFF"
1722  "GGGGGGGG"
1723  "GGGGGGGG"
1724  "HHHHHHHH"
1725  "HHHHHHHH"
1726  "IIIIIIII"
1727  "QQQQQQQQ"
1728  };
1729 
1730  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1731  sizeof(expected)));
1732  PASS;
1733 }
1734 
1735 static int DefragSturgesNovakLinuxIpv4Test(void)
1736 {
1737  /* Expected data. */
1738  u_char expected[] = {
1739  "AAAAAAAA"
1740  "AAAAAAAA"
1741  "AAAAAAAA"
1742  "JJJJJJJJ"
1743  "JJJJJJJJ"
1744  "BBBBBBBB"
1745  "KKKKKKKK"
1746  "KKKKKKKK"
1747  "KKKKKKKK"
1748  "LLLLLLLL"
1749  "LLLLLLLL"
1750  "LLLLLLLL"
1751  "MMMMMMMM"
1752  "MMMMMMMM"
1753  "MMMMMMMM"
1754  "FFFFFFFF"
1755  "FFFFFFFF"
1756  "FFFFFFFF"
1757  "GGGGGGGG"
1758  "GGGGGGGG"
1759  "PPPPPPPP"
1760  "HHHHHHHH"
1761  "QQQQQQQQ"
1762  "QQQQQQQQ"
1763  };
1764 
1765  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1766  sizeof(expected)));
1767  PASS;
1768 }
1769 
1770 static int IPV6DefragSturgesNovakLinuxTest(void)
1771 {
1772  /* Expected data. */
1773  u_char expected[] = {
1774  "AAAAAAAA"
1775  "AAAAAAAA"
1776  "AAAAAAAA"
1777  "JJJJJJJJ"
1778  "JJJJJJJJ"
1779  "BBBBBBBB"
1780  "KKKKKKKK"
1781  "KKKKKKKK"
1782  "KKKKKKKK"
1783  "LLLLLLLL"
1784  "LLLLLLLL"
1785  "LLLLLLLL"
1786  "MMMMMMMM"
1787  "MMMMMMMM"
1788  "MMMMMMMM"
1789  "FFFFFFFF"
1790  "FFFFFFFF"
1791  "FFFFFFFF"
1792  "GGGGGGGG"
1793  "GGGGGGGG"
1794  "PPPPPPPP"
1795  "HHHHHHHH"
1796  "QQQQQQQQ"
1797  "QQQQQQQQ"
1798  };
1799 
1800  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1801  sizeof(expected)));
1802  PASS;
1803 }
1804 
1805 static int DefragSturgesNovakWindowsIpv4Test(void)
1806 {
1807  /* Expected data. */
1808  u_char expected[] = {
1809  "AAAAAAAA"
1810  "AAAAAAAA"
1811  "AAAAAAAA"
1812  "JJJJJJJJ"
1813  "BBBBBBBB"
1814  "BBBBBBBB"
1815  "CCCCCCCC"
1816  "CCCCCCCC"
1817  "CCCCCCCC"
1818  "LLLLLLLL"
1819  "LLLLLLLL"
1820  "LLLLLLLL"
1821  "MMMMMMMM"
1822  "EEEEEEEE"
1823  "EEEEEEEE"
1824  "FFFFFFFF"
1825  "FFFFFFFF"
1826  "FFFFFFFF"
1827  "GGGGGGGG"
1828  "GGGGGGGG"
1829  "HHHHHHHH"
1830  "HHHHHHHH"
1831  "IIIIIIII"
1832  "QQQQQQQQ"
1833  };
1834 
1835  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
1836  sizeof(expected)));
1837  PASS;
1838 }
1839 
1840 static int IPV6DefragSturgesNovakWindowsTest(void)
1841 {
1842  /* Expected data. */
1843  u_char expected[] = {
1844  "AAAAAAAA"
1845  "AAAAAAAA"
1846  "AAAAAAAA"
1847  "JJJJJJJJ"
1848  "BBBBBBBB"
1849  "BBBBBBBB"
1850  "CCCCCCCC"
1851  "CCCCCCCC"
1852  "CCCCCCCC"
1853  "LLLLLLLL"
1854  "LLLLLLLL"
1855  "LLLLLLLL"
1856  "MMMMMMMM"
1857  "EEEEEEEE"
1858  "EEEEEEEE"
1859  "FFFFFFFF"
1860  "FFFFFFFF"
1861  "FFFFFFFF"
1862  "GGGGGGGG"
1863  "GGGGGGGG"
1864  "HHHHHHHH"
1865  "HHHHHHHH"
1866  "IIIIIIII"
1867  "QQQQQQQQ"
1868  };
1869 
1870  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
1871  sizeof(expected)));
1872  PASS;
1873 }
1874 
1875 static int DefragSturgesNovakSolarisTest(void)
1876 {
1877  /* Expected data. */
1878  u_char expected[] = {
1879  "AAAAAAAA"
1880  "AAAAAAAA"
1881  "AAAAAAAA"
1882  "JJJJJJJJ"
1883  "BBBBBBBB"
1884  "BBBBBBBB"
1885  "CCCCCCCC"
1886  "CCCCCCCC"
1887  "CCCCCCCC"
1888  "LLLLLLLL"
1889  "LLLLLLLL"
1890  "LLLLLLLL"
1891  "MMMMMMMM"
1892  "MMMMMMMM"
1893  "MMMMMMMM"
1894  "FFFFFFFF"
1895  "FFFFFFFF"
1896  "FFFFFFFF"
1897  "GGGGGGGG"
1898  "GGGGGGGG"
1899  "HHHHHHHH"
1900  "HHHHHHHH"
1901  "IIIIIIII"
1902  "QQQQQQQQ"
1903  };
1904 
1905  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
1906  sizeof(expected)));
1907  PASS;
1908 }
1909 
1910 static int IPV6DefragSturgesNovakSolarisTest(void)
1911 {
1912  /* Expected data. */
1913  u_char expected[] = {
1914  "AAAAAAAA"
1915  "AAAAAAAA"
1916  "AAAAAAAA"
1917  "JJJJJJJJ"
1918  "BBBBBBBB"
1919  "BBBBBBBB"
1920  "CCCCCCCC"
1921  "CCCCCCCC"
1922  "CCCCCCCC"
1923  "LLLLLLLL"
1924  "LLLLLLLL"
1925  "LLLLLLLL"
1926  "MMMMMMMM"
1927  "MMMMMMMM"
1928  "MMMMMMMM"
1929  "FFFFFFFF"
1930  "FFFFFFFF"
1931  "FFFFFFFF"
1932  "GGGGGGGG"
1933  "GGGGGGGG"
1934  "HHHHHHHH"
1935  "HHHHHHHH"
1936  "IIIIIIII"
1937  "QQQQQQQQ"
1938  };
1939 
1940  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
1941  sizeof(expected)));
1942  PASS;
1943 }
1944 
1945 static int DefragSturgesNovakFirstTest(void)
1946 {
1947  /* Expected data. */
1948  u_char expected[] = {
1949  "AAAAAAAA"
1950  "AAAAAAAA"
1951  "AAAAAAAA"
1952  "JJJJJJJJ"
1953  "BBBBBBBB"
1954  "BBBBBBBB"
1955  "CCCCCCCC"
1956  "CCCCCCCC"
1957  "CCCCCCCC"
1958  "LLLLLLLL"
1959  "DDDDDDDD"
1960  "LLLLLLLL"
1961  "MMMMMMMM"
1962  "EEEEEEEE"
1963  "EEEEEEEE"
1964  "FFFFFFFF"
1965  "FFFFFFFF"
1966  "FFFFFFFF"
1967  "GGGGGGGG"
1968  "GGGGGGGG"
1969  "HHHHHHHH"
1970  "HHHHHHHH"
1971  "IIIIIIII"
1972  "QQQQQQQQ"
1973  };
1974 
1975  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
1976  sizeof(expected)));
1977  PASS;
1978 }
1979 
1980 static int IPV6DefragSturgesNovakFirstTest(void)
1981 {
1982  /* Expected data. */
1983  u_char expected[] = {
1984  "AAAAAAAA"
1985  "AAAAAAAA"
1986  "AAAAAAAA"
1987  "JJJJJJJJ"
1988  "BBBBBBBB"
1989  "BBBBBBBB"
1990  "CCCCCCCC"
1991  "CCCCCCCC"
1992  "CCCCCCCC"
1993  "LLLLLLLL"
1994  "DDDDDDDD"
1995  "LLLLLLLL"
1996  "MMMMMMMM"
1997  "EEEEEEEE"
1998  "EEEEEEEE"
1999  "FFFFFFFF"
2000  "FFFFFFFF"
2001  "FFFFFFFF"
2002  "GGGGGGGG"
2003  "GGGGGGGG"
2004  "HHHHHHHH"
2005  "HHHHHHHH"
2006  "IIIIIIII"
2007  "QQQQQQQQ"
2008  };
2009 
2010  return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
2011  sizeof(expected));
2012 }
2013 
2014 static int
2015 DefragSturgesNovakLastTest(void)
2016 {
2017  /* Expected data. */
2018  u_char expected[] = {
2019  "AAAAAAAA"
2020  "JJJJJJJJ"
2021  "JJJJJJJJ"
2022  "JJJJJJJJ"
2023  "JJJJJJJJ"
2024  "BBBBBBBB"
2025  "KKKKKKKK"
2026  "KKKKKKKK"
2027  "KKKKKKKK"
2028  "LLLLLLLL"
2029  "LLLLLLLL"
2030  "LLLLLLLL"
2031  "MMMMMMMM"
2032  "MMMMMMMM"
2033  "MMMMMMMM"
2034  "FFFFFFFF"
2035  "NNNNNNNN"
2036  "FFFFFFFF"
2037  "GGGGGGGG"
2038  "OOOOOOOO"
2039  "PPPPPPPP"
2040  "HHHHHHHH"
2041  "QQQQQQQQ"
2042  "QQQQQQQQ"
2043  };
2044 
2045  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2046  sizeof(expected)));
2047  PASS;
2048 }
2049 
2050 static int IPV6DefragSturgesNovakLastTest(void)
2051 {
2052  /* Expected data. */
2053  u_char expected[] = {
2054  "AAAAAAAA"
2055  "JJJJJJJJ"
2056  "JJJJJJJJ"
2057  "JJJJJJJJ"
2058  "JJJJJJJJ"
2059  "BBBBBBBB"
2060  "KKKKKKKK"
2061  "KKKKKKKK"
2062  "KKKKKKKK"
2063  "LLLLLLLL"
2064  "LLLLLLLL"
2065  "LLLLLLLL"
2066  "MMMMMMMM"
2067  "MMMMMMMM"
2068  "MMMMMMMM"
2069  "FFFFFFFF"
2070  "NNNNNNNN"
2071  "FFFFFFFF"
2072  "GGGGGGGG"
2073  "OOOOOOOO"
2074  "PPPPPPPP"
2075  "HHHHHHHH"
2076  "QQQQQQQQ"
2077  "QQQQQQQQ"
2078  };
2079 
2080  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2081  sizeof(expected)));
2082  PASS;
2083 }
2084 
2085 static int DefragTimeoutTest(void)
2086 {
2087  int i;
2088 
2089  /* Setup a small number of trackers. */
2090  FAIL_IF_NOT(ConfSet("defrag.trackers", "16"));
2091 
2092  DefragInit();
2093 
2094  /* Load in 16 packets. */
2095  for (i = 0; i < 16; i++) {
2096  Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16);
2097  FAIL_IF_NULL(p);
2098 
2099  Packet *tp = Defrag(NULL, NULL, p);
2100  SCFree(p);
2101  FAIL_IF_NOT_NULL(tp);
2102  }
2103 
2104  /* Build a new packet but push the timestamp out by our timeout.
2105  * This should force our previous fragments to be timed out. */
2106  Packet *p = BuildTestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
2107  FAIL_IF_NULL(p);
2108 
2109  p->ts = SCTIME_ADD_SECS(p->ts, defrag_context->timeout + 1);
2110  Packet *tp = Defrag(NULL, NULL, p);
2111  FAIL_IF_NOT_NULL(tp);
2112 
2114  FAIL_IF_NULL(tracker);
2115 
2116  FAIL_IF(tracker->id != 99);
2117 
2118  SCMutexUnlock(&tracker->lock);
2119  SCFree(p);
2120 
2121  DefragDestroy();
2122  PASS;
2123 }
2124 
2125 /**
2126  * QA found that if you send a packet where more frags is 0, offset is
2127  * > 0 and there is no data in the packet that the re-assembler will
2128  * fail. The fix was simple, but this unit test is just to make sure
2129  * its not introduced.
2130  */
2131 static int DefragIPv4NoDataTest(void)
2132 {
2133  DefragContext *dc = NULL;
2134  Packet *p = NULL;
2135  int id = 12;
2136 
2137  DefragInit();
2138 
2139  dc = DefragContextNew();
2140  FAIL_IF_NULL(dc);
2141 
2142  /* This packet has an offset > 0, more frags set to 0 and no data. */
2143  p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
2144  FAIL_IF_NULL(p);
2145 
2146  /* We do not expect a packet returned. */
2147  FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2148 
2149  /* The fragment should have been ignored so no fragments should
2150  * have been allocated from the pool. */
2151  FAIL_IF(dc->frag_pool->outstanding != 0);
2152 
2153  DefragContextDestroy(dc);
2154  SCFree(p);
2155 
2156  DefragDestroy();
2157  PASS;
2158 }
2159 
2160 static int DefragIPv4TooLargeTest(void)
2161 {
2162  DefragContext *dc = NULL;
2163  Packet *p = NULL;
2164 
2165  DefragInit();
2166 
2167  dc = DefragContextNew();
2168  FAIL_IF_NULL(dc);
2169 
2170  /* Create a fragment that would extend past the max allowable size
2171  * for an IPv4 packet. */
2172  p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
2173  FAIL_IF_NULL(p);
2174 
2175  /* We do not expect a packet returned. */
2176  FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2177 
2178  /* We do expect an event. */
2180 
2181  /* The fragment should have been ignored so no fragments should have
2182  * been allocated from the pool. */
2183  FAIL_IF(dc->frag_pool->outstanding != 0);
2184 
2185  DefragContextDestroy(dc);
2186  SCFree(p);
2187 
2188  DefragDestroy();
2189  PASS;
2190 }
2191 
2192 /**
2193  * Test that fragments in different VLANs that would otherwise be
2194  * re-assembled, are not re-assembled. Just use simple in-order
2195  * fragments.
2196  */
2197 static int DefragVlanTest(void)
2198 {
2199  Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2200 
2201  DefragInit();
2202 
2203  p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2204  FAIL_IF_NULL(p1);
2205  p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2206  FAIL_IF_NULL(p2);
2207 
2208  /* With no VLAN IDs set, packets should re-assemble. */
2209  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2210  FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2211  SCFree(r);
2212 
2213  /* With mismatched VLANs, packets should not re-assemble. */
2214  p1->vlan_id[0] = 1;
2215  p2->vlan_id[0] = 2;
2216  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2217  FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2218 
2219  SCFree(p1);
2220  SCFree(p2);
2221  DefragDestroy();
2222 
2223  PASS;
2224 }
2225 
2226 /**
2227  * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID.
2228  */
2229 static int DefragVlanQinQTest(void)
2230 {
2231  Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2232 
2233  DefragInit();
2234 
2235  p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2236  FAIL_IF_NULL(p1);
2237  p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2238  FAIL_IF_NULL(p2);
2239 
2240  /* With no VLAN IDs set, packets should re-assemble. */
2241  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2242  FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2243  SCFree(r);
2244 
2245  /* With mismatched VLANs, packets should not re-assemble. */
2246  p1->vlan_id[0] = 1;
2247  p2->vlan_id[0] = 1;
2248  p1->vlan_id[1] = 1;
2249  p2->vlan_id[1] = 2;
2250  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2251  FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2252 
2253  SCFree(p1);
2254  SCFree(p2);
2255  DefragDestroy();
2256 
2257  PASS;
2258 }
2259 
2260 /**
2261  * Like DefragVlanTest, but for QinQinQ, testing the third level VLAN ID.
2262  */
2263 static int DefragVlanQinQinQTest(void)
2264 {
2265  Packet *r = NULL;
2266 
2267  DefragInit();
2268 
2269  Packet *p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2270  FAIL_IF_NULL(p1);
2271  Packet *p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2272  FAIL_IF_NULL(p2);
2273 
2274  /* With no VLAN IDs set, packets should re-assemble. */
2275  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2276  FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2277  SCFree(r);
2278 
2279  /* With mismatched VLANs, packets should not re-assemble. */
2280  p1->vlan_id[0] = 1;
2281  p2->vlan_id[0] = 1;
2282  p1->vlan_id[1] = 2;
2283  p2->vlan_id[1] = 2;
2284  p1->vlan_id[2] = 3;
2285  p2->vlan_id[2] = 4;
2286  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2287  FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2288 
2289  PacketFree(p1);
2290  PacketFree(p2);
2291  DefragDestroy();
2292 
2293  PASS;
2294 }
2295 static int DefragTrackerReuseTest(void)
2296 {
2297  int id = 1;
2298  Packet *p1 = NULL;
2299  DefragTracker *tracker1 = NULL, *tracker2 = NULL;
2300 
2301  DefragInit();
2302 
2303  /* Build a packet, its not a fragment but shouldn't matter for
2304  * this test. */
2305  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
2306  FAIL_IF_NULL(p1);
2307 
2308  /* Get a tracker. It shouldn't look like its already in use. */
2309  tracker1 = DefragGetTracker(NULL, NULL, p1);
2310  FAIL_IF_NULL(tracker1);
2311  FAIL_IF(tracker1->seen_last);
2312  FAIL_IF(tracker1->remove);
2313  DefragTrackerRelease(tracker1);
2314 
2315  /* Get a tracker again, it should be the same one. */
2316  tracker2 = DefragGetTracker(NULL, NULL, p1);
2317  FAIL_IF_NULL(tracker2);
2318  FAIL_IF(tracker2 != tracker1);
2319  DefragTrackerRelease(tracker1);
2320 
2321  /* Now mark the tracker for removal. It should not be returned
2322  * when we get a tracker for a packet that may have the same
2323  * attributes. */
2324  tracker1->remove = 1;
2325 
2326  tracker2 = DefragGetTracker(NULL, NULL, p1);
2327  FAIL_IF_NULL(tracker2);
2328  FAIL_IF(tracker2 == tracker1);
2329  FAIL_IF(tracker2->remove);
2330 
2331  SCFree(p1);
2332  DefragDestroy();
2333  PASS;
2334 }
2335 
2336 /**
2337  * IPV4: Test the case where you have a packet fragmented in 3 parts
2338  * and send like:
2339  * - Offset: 2; MF: 1
2340  * - Offset: 0; MF: 1
2341  * - Offset: 1; MF: 0
2342  *
2343  * Only the fragments with offset 0 and 1 should be reassembled.
2344  */
2345 static int DefragMfIpv4Test(void)
2346 {
2347  int ip_id = 9;
2348  Packet *p = NULL;
2349 
2350  DefragInit();
2351 
2352  Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
2353  Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
2354  Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
2355  FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2356 
2357  p = Defrag(NULL, NULL, p1);
2358  FAIL_IF_NOT_NULL(p);
2359 
2360  p = Defrag(NULL, NULL, p2);
2361  FAIL_IF_NOT_NULL(p);
2362 
2363  /* This should return a packet as MF=0. */
2364  p = Defrag(NULL, NULL, p3);
2365  FAIL_IF_NULL(p);
2366 
2367  /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the
2368  * fragments should be in the re-assembled packet. */
2369  FAIL_IF(IPV4_GET_IPLEN(p) != 36);
2370 
2371  SCFree(p1);
2372  SCFree(p2);
2373  SCFree(p3);
2374  SCFree(p);
2375  DefragDestroy();
2376  PASS;
2377 }
2378 
2379 /**
2380  * IPV6: Test the case where you have a packet fragmented in 3 parts
2381  * and send like:
2382  * - Offset: 2; MF: 1
2383  * - Offset: 0; MF: 1
2384  * - Offset: 1; MF: 0
2385  *
2386  * Only the fragments with offset 0 and 1 should be reassembled.
2387  */
2388 static int DefragMfIpv6Test(void)
2389 {
2390  int ip_id = 9;
2391  Packet *p = NULL;
2392 
2393  DefragInit();
2394 
2395  Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
2396  Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
2397  Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
2398  FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2399 
2400  p = Defrag(NULL, NULL, p1);
2401  FAIL_IF_NOT_NULL(p);
2402 
2403  p = Defrag(NULL, NULL, p2);
2404  FAIL_IF_NOT_NULL(p);
2405 
2406  /* This should return a packet as MF=0. */
2407  p = Defrag(NULL, NULL, p3);
2408  FAIL_IF_NULL(p);
2409 
2410  /* For IPv6 the expected length is just the length of the payload
2411  * of 2 fragments, so 16. */
2412  FAIL_IF(IPV6_GET_PLEN(p) != 16);
2413 
2414  SCFree(p1);
2415  SCFree(p2);
2416  SCFree(p3);
2417  SCFree(p);
2418  DefragDestroy();
2419  PASS;
2420 }
2421 
2422 /**
2423  * \brief Test that fragments that match other than the proto don't
2424  * actually get matched.
2425  */
2426 static int DefragTestBadProto(void)
2427 {
2428  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
2429  int id = 12;
2430 
2431  DefragInit();
2432 
2433  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
2434  FAIL_IF_NULL(p1);
2435  p2 = BuildTestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
2436  FAIL_IF_NULL(p2);
2437  p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
2438  FAIL_IF_NULL(p3);
2439 
2440  FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1));
2441  FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p2));
2442  FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p3));
2443 
2444  SCFree(p1);
2445  SCFree(p2);
2446  SCFree(p3);
2447 
2448  DefragDestroy();
2449  PASS;
2450 }
2451 
2452 /**
2453  * \test Test a report Linux overlap issue that doesn't appear to be
2454  * covered by the Sturges/Novak tests above.
2455  */
2456 static int DefragTestJeremyLinux(void)
2457 {
2458  char expected[] = "AAAAAAAA"
2459  "AAAAAAAA"
2460  "AAAAAAAA"
2461  "CCCCCCCC"
2462  "CCCCCCCC"
2463  "CCCCCCCC"
2464  "CCCCCCCC"
2465  "CCCCCCCC"
2466  "CCCCCCCC"
2467  "BBBBBBBB"
2468  "BBBBBBBB"
2469  "DDDDDDDD"
2470  "DDDDDD";
2471 
2472  DefragInit();
2473  default_policy = DEFRAG_POLICY_LINUX;
2474 
2475  int id = 1;
2476  Packet *packets[4];
2477  int i = 0;
2478 
2479  packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
2480  packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
2481  packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
2482  packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
2483 
2484  Packet *r = Defrag(NULL, NULL, packets[0]);
2485  FAIL_IF_NOT_NULL(r);
2486 
2487  r = Defrag(NULL, NULL, packets[1]);
2488  FAIL_IF_NOT_NULL(r);
2489 
2490  r = Defrag(NULL, NULL, packets[2]);
2491  FAIL_IF_NOT_NULL(r);
2492 
2493  r = Defrag(NULL, NULL, packets[3]);
2494  FAIL_IF_NULL(r);
2495 
2496  FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0);
2497 
2498  for (i = 0; i < 4; i++) {
2499  SCFree(packets[i]);
2500  }
2501  SCFree(r);
2502 
2503  DefragDestroy();
2504  PASS;
2505 }
2506 
2507 #endif /* UNITTESTS */
2508 
2510 {
2511 #ifdef UNITTESTS
2512  UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest);
2513  UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest);
2514  UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest);
2515  UtRegisterTest("DefragSturgesNovakLinuxIpv4Test",
2516  DefragSturgesNovakLinuxIpv4Test);
2517  UtRegisterTest("DefragSturgesNovakWindowsIpv4Test",
2518  DefragSturgesNovakWindowsIpv4Test);
2519  UtRegisterTest("DefragSturgesNovakSolarisTest",
2520  DefragSturgesNovakSolarisTest);
2521  UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
2522  UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
2523 
2524  UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest);
2525  UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest);
2526 
2527  UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest);
2528  UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest);
2529  UtRegisterTest("IPV6DefragSturgesNovakBsdTest",
2530  IPV6DefragSturgesNovakBsdTest);
2531  UtRegisterTest("IPV6DefragSturgesNovakLinuxTest",
2532  IPV6DefragSturgesNovakLinuxTest);
2533  UtRegisterTest("IPV6DefragSturgesNovakWindowsTest",
2534  IPV6DefragSturgesNovakWindowsTest);
2535  UtRegisterTest("IPV6DefragSturgesNovakSolarisTest",
2536  IPV6DefragSturgesNovakSolarisTest);
2537  UtRegisterTest("IPV6DefragSturgesNovakFirstTest",
2538  IPV6DefragSturgesNovakFirstTest);
2539  UtRegisterTest("IPV6DefragSturgesNovakLastTest",
2540  IPV6DefragSturgesNovakLastTest);
2541 
2542  UtRegisterTest("DefragVlanTest", DefragVlanTest);
2543  UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
2544  UtRegisterTest("DefragVlanQinQinQTest", DefragVlanQinQinQTest);
2545  UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest);
2546  UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest);
2547  UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test);
2548  UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test);
2549  UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
2550 
2551  UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux);
2552 #endif /* UNITTESTS */
2553 }
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:902
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:1072
ConfGetInt
int ConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition: conf.c:399
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:737
OS_POLICY_FIRST
@ OS_POLICY_FIRST
Definition: stream-tcp-reassemble.h:49
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:632
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
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:917
OS_POLICY_MACOS
@ OS_POLICY_MACOS
Definition: stream-tcp-reassemble.h:45
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:607
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:388
OS_POLICY_OLD_LINUX
@ OS_POLICY_OLD_LINUX
Definition: stream-tcp-reassemble.h:38
Packet_::flags
uint32_t flags
Definition: decode.h:473
IPV6_SET_RAW_VER
#define IPV6_SET_RAW_VER(ip6h, value)
Definition: decode-ipv6.h:69
OS_POLICY_IRIX
@ OS_POLICY_IRIX
Definition: stream-tcp-reassemble.h:44
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:1084
Frag_::data_len
uint16_t data_len
Definition: defrag.h:63
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:333
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
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:1074
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:923
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:69
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
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:484
DefragTracker_::seen_last
uint8_t seen_last
Definition: defrag.h:102
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
OS_POLICY_BSD
@ OS_POLICY_BSD
Definition: stream-tcp-reassemble.h:36
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
DefragRegisterTests
void DefragRegisterTests(void)
Definition: defrag.c:2509
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:79
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:135
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:436
DefragTracker_::id
uint32_t id
Definition: defrag.h:92
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:223
stream-tcp-private.h
conf.h
Packet_::ip4h
IPV4Hdr * ip4h
Definition: decode.h:544
Frag_::skip
uint8_t skip
Definition: defrag.h:55
DefragInitConfig
void DefragInitConfig(bool quiet)
initialize the configuration
Definition: defrag-hash.c:164
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
IPV6ExtHdrs_::fh_data_len
uint16_t fh_data_len
Definition: decode-ipv6.h:228
DefragTrackerRelease
void DefragTrackerRelease(DefragTracker *t)
Definition: defrag-hash.c:147
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:336
DefragTracker_::fragment_tree
struct IP_FRAGMENTS fragment_tree
Definition: defrag.h:115
OS_POLICY_OLD_SOLARIS
@ OS_POLICY_OLD_SOLARIS
Definition: stream-tcp-reassemble.h:40
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:163
IPV6Hdr
struct IPV6Hdr_ IPV6Hdr
OS_POLICY_HPUX10
@ OS_POLICY_HPUX10
Definition: stream-tcp-reassemble.h:42
suricata-common.h
Frag_::len
uint32_t len
Definition: defrag.h:50
DefragGetTrackerFromHash
DefragTracker * DefragGetTrackerFromHash(Packet *p)
Definition: defrag-hash.c:533
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
DecodeThreadVars_::counter_defrag_ipv6_reassembled
uint16_t counter_defrag_ipv6_reassembled
Definition: decode.h:739
OS_POLICY_VISTA
@ OS_POLICY_VISTA
Definition: stream-tcp-reassemble.h:47
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
OS_POLICY_SOLARIS
@ OS_POLICY_SOLARIS
Definition: stream-tcp-reassemble.h:41
DefragPolicyLoadFromConfig
void DefragPolicyLoadFromConfig(void)
Definition: defrag-config.c:135
DEFRAG_POLICY_SOLARIS
@ DEFRAG_POLICY_SOLARIS
Definition: defrag.c:93
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
OS_POLICY_WINDOWS
@ OS_POLICY_WINDOWS
Definition: stream-tcp-reassemble.h:46
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:634
PoolGet
void * PoolGet(Pool *p)
Definition: util-pool.c:278
OS_POLICY_LAST
@ OS_POLICY_LAST
Definition: stream-tcp-reassemble.h:50
PKT_REBUILT_FRAGMENT
#define PKT_REBUILT_FRAGMENT
Definition: decode.h:1054
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:685
MAX_PAYLOAD_SIZE
#define MAX_PAYLOAD_SIZE
Definition: decode.h:679
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
OS_POLICY_LINUX
@ OS_POLICY_LINUX
Definition: stream-tcp-reassemble.h:39
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:740
util-random.h
OS_POLICY_HPUX11
@ OS_POLICY_HPUX11
Definition: stream-tcp-reassemble.h:43
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:441
OS_POLICY_WINDOWS2K3
@ OS_POLICY_WINDOWS2K3
Definition: stream-tcp-reassemble.h:48
TIMEOUT_DEFAULT
#define TIMEOUT_DEFAULT
Definition: defrag.c:73
DecodeThreadVars_::counter_defrag_ipv6_fragments
uint16_t counter_defrag_ipv6_fragments
Definition: decode.h:738
OS_POLICY_BSD_RIGHT
@ OS_POLICY_BSD_RIGHT
Definition: stream-tcp-reassemble.h:37
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:463
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
PacketDefragPktSetupParent
void PacketDefragPktSetupParent(Packet *parent)
inform defrag "parent" that a pseudo packet is now associated to it.
Definition: decode.c:428
DefragHashShutdown
void DefragHashShutdown(void)
shutdown the flow engine
Definition: defrag-hash.c:300
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:546
SET_IPV4_DST_ADDR
#define SET_IPV4_DST_ADDR(p, a)
Definition: decode.h:151
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:129
Defrag
Packet * Defrag(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Entry point for IPv4 and IPv6 fragments.
Definition: defrag.c:1002
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:64
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:103
Frag_::offset
uint16_t offset
Definition: defrag.h:47
Packet_::src
Address src
Definition: decode.h:440
DefragInit
void DefragInit(void)
Definition: defrag.c:1052
IPV4_GET_IPTTL
#define IPV4_GET_IPTTL(p)
Definition: decode-ipv4.h:146
Packet_::ip6eh
IPV6ExtHdrs ip6eh
Definition: decode.h:553
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:736