suricata
defrag.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2012 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 normalizaton (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: Tiemout 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  return NULL;
1046 
1047  Packet *rp = DefragInsertFrag(tv, dtv, tracker, p);
1048  DefragTrackerRelease(tracker);
1049 
1050  return rp;
1051 }
1052 
1053 void
1055 {
1056  intmax_t tracker_pool_size;
1057  if (!ConfGetInt("defrag.trackers", &tracker_pool_size)) {
1058  tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
1059  }
1060 
1061  /* Load the defrag-per-host lookup. */
1063 
1064  /* Allocate the DefragContext. */
1065  defrag_context = DefragContextNew();
1066  if (defrag_context == NULL) {
1067  FatalError("Failed to allocate memory for the Defrag module.");
1068  }
1069 
1070  DefragSetDefaultTimeout(defrag_context->timeout);
1071  DefragInitConfig(false);
1072 }
1073 
1074 void DefragDestroy(void)
1075 {
1077  DefragContextDestroy(defrag_context);
1078  defrag_context = NULL;
1080 }
1081 
1082 #ifdef UNITTESTS
1083 #include "util-unittest-helper.h"
1084 #include "packet.h"
1085 
1086 #define IP_MF 0x2000
1088 /**
1089  * Allocate a test packet. Nothing to fancy, just a simple IP packet
1090  * with some payload of no particular protocol.
1091  */
1092 static Packet *BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf,
1093  const char content, int content_len)
1094 {
1095  Packet *p = NULL;
1096  int hlen = 20;
1097  int ttl = 64;
1098  uint8_t *pcontent;
1099  IPV4Hdr ip4h;
1100 
1101  p = SCCalloc(1, sizeof(*p) + default_packet_size);
1102  if (unlikely(p == NULL))
1103  return NULL;
1104 
1105  PacketInit(p);
1106 
1107  struct timeval tval;
1108  gettimeofday(&tval, NULL);
1109  p->ts = SCTIME_FROM_TIMEVAL(&tval);
1110  //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1111  ip4h.ip_verhl = 4 << 4;
1112  ip4h.ip_verhl |= hlen >> 2;
1113  ip4h.ip_len = htons(hlen + content_len);
1114  ip4h.ip_id = htons(id);
1115  if (mf)
1116  ip4h.ip_off = htons(IP_MF | off);
1117  else
1118  ip4h.ip_off = htons(off);
1119  ip4h.ip_ttl = ttl;
1120  ip4h.ip_proto = proto;
1121 
1122  ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1123  ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1124 
1125  /* copy content_len crap, we need full length */
1126  PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1127  p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1128  SET_IPV4_SRC_ADDR(p, &p->src);
1129  SET_IPV4_DST_ADDR(p, &p->dst);
1130 
1131  pcontent = SCCalloc(1, content_len);
1132  if (unlikely(pcontent == NULL))
1133  return NULL;
1134  memset(pcontent, content, content_len);
1135  PacketCopyDataOffset(p, hlen, pcontent, content_len);
1136  SET_PKT_LEN(p, hlen + content_len);
1137  SCFree(pcontent);
1138 
1139  p->ip4h->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1140 
1141  /* Self test. */
1142  if (IPV4_GET_VER(p) != 4)
1143  goto error;
1144  if (IPV4_GET_HLEN(p) != hlen)
1145  goto error;
1146  if (IPV4_GET_IPLEN(p) != hlen + content_len)
1147  goto error;
1148  if (IPV4_GET_IPID(p) != id)
1149  goto error;
1150  if (IPV4_GET_IPOFFSET(p) != off)
1151  goto error;
1152  if (IPV4_GET_MF(p) != mf)
1153  goto error;
1154  if (IPV4_GET_IPTTL(p) != ttl)
1155  goto error;
1156  if (IPV4_GET_IPPROTO(p) != proto)
1157  goto error;
1158 
1159  return p;
1160 error:
1161  if (p != NULL)
1162  SCFree(p);
1163  return NULL;
1164 }
1165 
1166 static Packet *IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off,
1167  int mf, const char content, int content_len)
1168 {
1169  Packet *p = NULL;
1170  uint8_t *pcontent;
1171  IPV6Hdr ip6h;
1172 
1173  p = SCCalloc(1, sizeof(*p) + default_packet_size);
1174  if (unlikely(p == NULL))
1175  return NULL;
1176 
1177  PacketInit(p);
1178 
1179  struct timeval tval;
1180  gettimeofday(&tval, NULL);
1181  p->ts = SCTIME_FROM_TIMEVAL(&tval);
1182 
1183  ip6h.s_ip6_nxt = 44;
1184  ip6h.s_ip6_hlim = 2;
1185 
1186  /* Source and dest address - very bogus addresses. */
1187  ip6h.s_ip6_src[0] = 0x01010101;
1188  ip6h.s_ip6_src[1] = 0x01010101;
1189  ip6h.s_ip6_src[2] = 0x01010101;
1190  ip6h.s_ip6_src[3] = 0x01010101;
1191  ip6h.s_ip6_dst[0] = 0x02020202;
1192  ip6h.s_ip6_dst[1] = 0x02020202;
1193  ip6h.s_ip6_dst[2] = 0x02020202;
1194  ip6h.s_ip6_dst[3] = 0x02020202;
1195 
1196  /* copy content_len crap, we need full length */
1197  PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1198 
1199  p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
1200  IPV6_SET_RAW_VER(p->ip6h, 6);
1201  /* Fragmentation header. */
1202  IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1203  fh->ip6fh_nxt = proto;
1204  fh->ip6fh_ident = htonl(id);
1205  fh->ip6fh_offlg = htons((off << 3) | mf);
1206 
1207  DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1208 
1209  pcontent = SCCalloc(1, content_len);
1210  if (unlikely(pcontent == NULL))
1211  return NULL;
1212  memset(pcontent, content, content_len);
1213  PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), pcontent, content_len);
1214  SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1215  SCFree(pcontent);
1216 
1217  p->ip6h->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1218 
1219  SET_IPV6_SRC_ADDR(p, &p->src);
1220  SET_IPV6_DST_ADDR(p, &p->dst);
1221 
1222  /* Self test. */
1223  if (IPV6_GET_VER(p) != 6)
1224  goto error;
1225  if (IPV6_GET_NH(p) != 44)
1226  goto error;
1227  if (IPV6_GET_PLEN(p) != sizeof(IPV6FragHdr) + content_len)
1228  goto error;
1229 
1230  return p;
1231 error:
1232  if (p != NULL)
1233  SCFree(p);
1234  return NULL;
1235 }
1236 
1237 /**
1238  * Test the simplest possible re-assembly scenario. All packet in
1239  * order and no overlaps.
1240  */
1241 static int DefragInOrderSimpleTest(void)
1242 {
1243  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1244  Packet *reassembled = NULL;
1245  int id = 12;
1246  int i;
1247 
1248  DefragInit();
1249 
1250  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1251  FAIL_IF_NULL(p1);
1252  p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1253  FAIL_IF_NULL(p2);
1254  p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1255  FAIL_IF_NULL(p3);
1256 
1257  FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1258  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1259 
1260  reassembled = Defrag(NULL, NULL, p3);
1261  FAIL_IF_NULL(reassembled);
1262 
1263  FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1264  FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1265 
1266  /* 20 bytes in we should find 8 bytes of A. */
1267  for (i = 20; i < 20 + 8; i++) {
1268  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1269  }
1270 
1271  /* 28 bytes in we should find 8 bytes of B. */
1272  for (i = 28; i < 28 + 8; i++) {
1273  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1274  }
1275 
1276  /* And 36 bytes in we should find 3 bytes of C. */
1277  for (i = 36; i < 36 + 3; i++) {
1278  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1279  }
1280 
1281  SCFree(p1);
1282  SCFree(p2);
1283  SCFree(p3);
1284  SCFree(reassembled);
1285 
1286  DefragDestroy();
1287  PASS;
1288 }
1289 
1290 /**
1291  * Simple fragmented packet in reverse order.
1292  */
1293 static int DefragReverseSimpleTest(void)
1294 {
1295  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1296  Packet *reassembled = NULL;
1297  int id = 12;
1298  int i;
1299 
1300  DefragInit();
1301 
1302  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1303  FAIL_IF_NULL(p1);
1304  p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1305  FAIL_IF_NULL(p2);
1306  p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1307  FAIL_IF_NULL(p3);
1308 
1309  FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1310  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1311 
1312  reassembled = Defrag(NULL, NULL, p1);
1313  FAIL_IF_NULL(reassembled);
1314 
1315  FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1316  FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1317 
1318  /* 20 bytes in we should find 8 bytes of A. */
1319  for (i = 20; i < 20 + 8; i++) {
1320  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1321  }
1322 
1323  /* 28 bytes in we should find 8 bytes of B. */
1324  for (i = 28; i < 28 + 8; i++) {
1325  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1326  }
1327 
1328  /* And 36 bytes in we should find 3 bytes of C. */
1329  for (i = 36; i < 36 + 3; i++) {
1330  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1331  }
1332 
1333  SCFree(p1);
1334  SCFree(p2);
1335  SCFree(p3);
1336  SCFree(reassembled);
1337 
1338  DefragDestroy();
1339  PASS;
1340 }
1341 
1342 /**
1343  * Test the simplest possible re-assembly scenario. All packet in
1344  * order and no overlaps.
1345  */
1346 static int IPV6DefragInOrderSimpleTest(void)
1347 {
1348  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1349  Packet *reassembled = NULL;
1350  int id = 12;
1351  int i;
1352 
1353  DefragInit();
1354 
1355  p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1356  FAIL_IF_NULL(p1);
1357  p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1358  FAIL_IF_NULL(p2);
1359  p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1360  FAIL_IF_NULL(p3);
1361 
1362  FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1363  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1364  reassembled = Defrag(NULL, NULL, p3);
1365  FAIL_IF_NULL(reassembled);
1366 
1367  FAIL_IF(IPV6_GET_PLEN(reassembled) != 19);
1368 
1369  /* 40 bytes in we should find 8 bytes of A. */
1370  for (i = 40; i < 40 + 8; i++) {
1371  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1372  }
1373 
1374  /* 28 bytes in we should find 8 bytes of B. */
1375  for (i = 48; i < 48 + 8; i++) {
1376  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1377  }
1378 
1379  /* And 36 bytes in we should find 3 bytes of C. */
1380  for (i = 56; i < 56 + 3; i++) {
1381  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1382  }
1383 
1384  SCFree(p1);
1385  SCFree(p2);
1386  SCFree(p3);
1387  SCFree(reassembled);
1388 
1389  DefragDestroy();
1390  PASS;
1391 }
1392 
1393 static int IPV6DefragReverseSimpleTest(void)
1394 {
1395  DefragContext *dc = NULL;
1396  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1397  Packet *reassembled = NULL;
1398  int id = 12;
1399  int i;
1400 
1401  DefragInit();
1402 
1403  dc = DefragContextNew();
1404  FAIL_IF_NULL(dc);
1405 
1406  p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1407  FAIL_IF_NULL(p1);
1408  p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1409  FAIL_IF_NULL(p2);
1410  p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1411  FAIL_IF_NULL(p3);
1412 
1413  FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1414  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1415  reassembled = Defrag(NULL, NULL, p1);
1416  FAIL_IF_NULL(reassembled);
1417 
1418  /* 40 bytes in we should find 8 bytes of A. */
1419  for (i = 40; i < 40 + 8; i++) {
1420  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1421  }
1422 
1423  /* 28 bytes in we should find 8 bytes of B. */
1424  for (i = 48; i < 48 + 8; i++) {
1425  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1426  }
1427 
1428  /* And 36 bytes in we should find 3 bytes of C. */
1429  for (i = 56; i < 56 + 3; i++) {
1430  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1431  }
1432 
1433  DefragContextDestroy(dc);
1434  SCFree(p1);
1435  SCFree(p2);
1436  SCFree(p3);
1437  SCFree(reassembled);
1438 
1439  DefragDestroy();
1440  PASS;
1441 }
1442 
1443 static int DefragDoSturgesNovakTest(int policy, u_char *expected,
1444  size_t expected_len)
1445 {
1446  int i;
1447 
1448  DefragInit();
1449 
1450  /*
1451  * Build the packets.
1452  */
1453 
1454  int id = 1;
1455  Packet *packets[17];
1456  memset(packets, 0x00, sizeof(packets));
1457 
1458  /*
1459  * Original fragments.
1460  */
1461 
1462  /* A*24 at 0. */
1463  packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
1464 
1465  /* B*15 at 32. */
1466  packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
1467 
1468  /* C*24 at 48. */
1469  packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
1470 
1471  /* D*8 at 80. */
1472  packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
1473 
1474  /* E*16 at 104. */
1475  packets[4] = BuildTestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
1476 
1477  /* F*24 at 120. */
1478  packets[5] = BuildTestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
1479 
1480  /* G*16 at 144. */
1481  packets[6] = BuildTestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
1482 
1483  /* H*16 at 160. */
1484  packets[7] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
1485 
1486  /* I*8 at 176. */
1487  packets[8] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
1488 
1489  /*
1490  * Overlapping subsequent fragments.
1491  */
1492 
1493  /* J*32 at 8. */
1494  packets[9] = BuildTestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
1495 
1496  /* K*24 at 48. */
1497  packets[10] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
1498 
1499  /* L*24 at 72. */
1500  packets[11] = BuildTestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
1501 
1502  /* M*24 at 96. */
1503  packets[12] = BuildTestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
1504 
1505  /* N*8 at 128. */
1506  packets[13] = BuildTestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
1507 
1508  /* O*8 at 152. */
1509  packets[14] = BuildTestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
1510 
1511  /* P*8 at 160. */
1512  packets[15] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
1513 
1514  /* Q*16 at 176. */
1515  packets[16] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
1516 
1517  default_policy = policy;
1518 
1519  /* Send all but the last. */
1520  for (i = 0; i < 9; i++) {
1521  Packet *tp = Defrag(NULL, NULL, packets[i]);
1522  FAIL_IF_NOT_NULL(tp);
1524  }
1525  int overlap = 0;
1526  for (; i < 16; i++) {
1527  Packet *tp = Defrag(NULL, NULL, packets[i]);
1528  FAIL_IF_NOT_NULL(tp);
1529  if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) {
1530  overlap++;
1531  }
1532  }
1533  FAIL_IF_NOT(overlap);
1534 
1535  /* And now the last one. */
1536  Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1537  FAIL_IF_NULL(reassembled);
1538 
1539  FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1540  FAIL_IF(IPV4_GET_IPLEN(reassembled) != 20 + 192);
1541 
1542  FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0);
1543  SCFree(reassembled);
1544 
1545  /* Make sure all frags were returned back to the pool. */
1546  FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1547 
1548  for (i = 0; i < 17; i++) {
1549  SCFree(packets[i]);
1550  }
1551  DefragDestroy();
1552  PASS;
1553 }
1554 
1555 static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected,
1556  size_t expected_len)
1557 {
1558  int i;
1559 
1560  DefragInit();
1561 
1562  /*
1563  * Build the packets.
1564  */
1565 
1566  int id = 1;
1567  Packet *packets[17];
1568  memset(packets, 0x00, sizeof(packets));
1569 
1570  /*
1571  * Original fragments.
1572  */
1573 
1574  /* A*24 at 0. */
1575  packets[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
1576 
1577  /* B*15 at 32. */
1578  packets[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
1579 
1580  /* C*24 at 48. */
1581  packets[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
1582 
1583  /* D*8 at 80. */
1584  packets[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
1585 
1586  /* E*16 at 104. */
1587  packets[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
1588 
1589  /* F*24 at 120. */
1590  packets[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
1591 
1592  /* G*16 at 144. */
1593  packets[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
1594 
1595  /* H*16 at 160. */
1596  packets[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
1597 
1598  /* I*8 at 176. */
1599  packets[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
1600 
1601  /*
1602  * Overlapping subsequent fragments.
1603  */
1604 
1605  /* J*32 at 8. */
1606  packets[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
1607 
1608  /* K*24 at 48. */
1609  packets[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
1610 
1611  /* L*24 at 72. */
1612  packets[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
1613 
1614  /* M*24 at 96. */
1615  packets[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
1616 
1617  /* N*8 at 128. */
1618  packets[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
1619 
1620  /* O*8 at 152. */
1621  packets[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
1622 
1623  /* P*8 at 160. */
1624  packets[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
1625 
1626  /* Q*16 at 176. */
1627  packets[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
1628 
1629  default_policy = policy;
1630 
1631  /* Send all but the last. */
1632  for (i = 0; i < 9; i++) {
1633  Packet *tp = Defrag(NULL, NULL, packets[i]);
1634  FAIL_IF_NOT_NULL(tp);
1636  }
1637  int overlap = 0;
1638  for (; i < 16; i++) {
1639  Packet *tp = Defrag(NULL, NULL, packets[i]);
1640  FAIL_IF_NOT_NULL(tp);
1641  if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) {
1642  overlap++;
1643  }
1644  }
1645  FAIL_IF_NOT(overlap);
1646 
1647  /* And now the last one. */
1648  Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1649  FAIL_IF_NULL(reassembled);
1650  FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0);
1651 
1652  FAIL_IF(IPV6_GET_PLEN(reassembled) != 192);
1653 
1654  SCFree(reassembled);
1655 
1656  /* Make sure all frags were returned to the pool. */
1657  FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1658 
1659  for (i = 0; i < 17; i++) {
1660  SCFree(packets[i]);
1661  }
1662  DefragDestroy();
1663  PASS;
1664 }
1665 
1666 static int
1667 DefragSturgesNovakBsdTest(void)
1668 {
1669  /* Expected data. */
1670  u_char expected[] = {
1671  "AAAAAAAA"
1672  "AAAAAAAA"
1673  "AAAAAAAA"
1674  "JJJJJJJJ"
1675  "JJJJJJJJ"
1676  "BBBBBBBB"
1677  "CCCCCCCC"
1678  "CCCCCCCC"
1679  "CCCCCCCC"
1680  "LLLLLLLL"
1681  "LLLLLLLL"
1682  "LLLLLLLL"
1683  "MMMMMMMM"
1684  "MMMMMMMM"
1685  "MMMMMMMM"
1686  "FFFFFFFF"
1687  "FFFFFFFF"
1688  "FFFFFFFF"
1689  "GGGGGGGG"
1690  "GGGGGGGG"
1691  "HHHHHHHH"
1692  "HHHHHHHH"
1693  "IIIIIIII"
1694  "QQQQQQQQ"
1695  };
1696 
1697  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1698  sizeof(expected)));
1699  PASS;
1700 }
1701 
1702 static int IPV6DefragSturgesNovakBsdTest(void)
1703 {
1704  /* Expected data. */
1705  u_char expected[] = {
1706  "AAAAAAAA"
1707  "AAAAAAAA"
1708  "AAAAAAAA"
1709  "JJJJJJJJ"
1710  "JJJJJJJJ"
1711  "BBBBBBBB"
1712  "CCCCCCCC"
1713  "CCCCCCCC"
1714  "CCCCCCCC"
1715  "LLLLLLLL"
1716  "LLLLLLLL"
1717  "LLLLLLLL"
1718  "MMMMMMMM"
1719  "MMMMMMMM"
1720  "MMMMMMMM"
1721  "FFFFFFFF"
1722  "FFFFFFFF"
1723  "FFFFFFFF"
1724  "GGGGGGGG"
1725  "GGGGGGGG"
1726  "HHHHHHHH"
1727  "HHHHHHHH"
1728  "IIIIIIII"
1729  "QQQQQQQQ"
1730  };
1731 
1732  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1733  sizeof(expected)));
1734  PASS;
1735 }
1736 
1737 static int DefragSturgesNovakLinuxIpv4Test(void)
1738 {
1739  /* Expected data. */
1740  u_char expected[] = {
1741  "AAAAAAAA"
1742  "AAAAAAAA"
1743  "AAAAAAAA"
1744  "JJJJJJJJ"
1745  "JJJJJJJJ"
1746  "BBBBBBBB"
1747  "KKKKKKKK"
1748  "KKKKKKKK"
1749  "KKKKKKKK"
1750  "LLLLLLLL"
1751  "LLLLLLLL"
1752  "LLLLLLLL"
1753  "MMMMMMMM"
1754  "MMMMMMMM"
1755  "MMMMMMMM"
1756  "FFFFFFFF"
1757  "FFFFFFFF"
1758  "FFFFFFFF"
1759  "GGGGGGGG"
1760  "GGGGGGGG"
1761  "PPPPPPPP"
1762  "HHHHHHHH"
1763  "QQQQQQQQ"
1764  "QQQQQQQQ"
1765  };
1766 
1767  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1768  sizeof(expected)));
1769  PASS;
1770 }
1771 
1772 static int IPV6DefragSturgesNovakLinuxTest(void)
1773 {
1774  /* Expected data. */
1775  u_char expected[] = {
1776  "AAAAAAAA"
1777  "AAAAAAAA"
1778  "AAAAAAAA"
1779  "JJJJJJJJ"
1780  "JJJJJJJJ"
1781  "BBBBBBBB"
1782  "KKKKKKKK"
1783  "KKKKKKKK"
1784  "KKKKKKKK"
1785  "LLLLLLLL"
1786  "LLLLLLLL"
1787  "LLLLLLLL"
1788  "MMMMMMMM"
1789  "MMMMMMMM"
1790  "MMMMMMMM"
1791  "FFFFFFFF"
1792  "FFFFFFFF"
1793  "FFFFFFFF"
1794  "GGGGGGGG"
1795  "GGGGGGGG"
1796  "PPPPPPPP"
1797  "HHHHHHHH"
1798  "QQQQQQQQ"
1799  "QQQQQQQQ"
1800  };
1801 
1802  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1803  sizeof(expected)));
1804  PASS;
1805 }
1806 
1807 static int DefragSturgesNovakWindowsIpv4Test(void)
1808 {
1809  /* Expected data. */
1810  u_char expected[] = {
1811  "AAAAAAAA"
1812  "AAAAAAAA"
1813  "AAAAAAAA"
1814  "JJJJJJJJ"
1815  "BBBBBBBB"
1816  "BBBBBBBB"
1817  "CCCCCCCC"
1818  "CCCCCCCC"
1819  "CCCCCCCC"
1820  "LLLLLLLL"
1821  "LLLLLLLL"
1822  "LLLLLLLL"
1823  "MMMMMMMM"
1824  "EEEEEEEE"
1825  "EEEEEEEE"
1826  "FFFFFFFF"
1827  "FFFFFFFF"
1828  "FFFFFFFF"
1829  "GGGGGGGG"
1830  "GGGGGGGG"
1831  "HHHHHHHH"
1832  "HHHHHHHH"
1833  "IIIIIIII"
1834  "QQQQQQQQ"
1835  };
1836 
1837  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
1838  sizeof(expected)));
1839  PASS;
1840 }
1841 
1842 static int IPV6DefragSturgesNovakWindowsTest(void)
1843 {
1844  /* Expected data. */
1845  u_char expected[] = {
1846  "AAAAAAAA"
1847  "AAAAAAAA"
1848  "AAAAAAAA"
1849  "JJJJJJJJ"
1850  "BBBBBBBB"
1851  "BBBBBBBB"
1852  "CCCCCCCC"
1853  "CCCCCCCC"
1854  "CCCCCCCC"
1855  "LLLLLLLL"
1856  "LLLLLLLL"
1857  "LLLLLLLL"
1858  "MMMMMMMM"
1859  "EEEEEEEE"
1860  "EEEEEEEE"
1861  "FFFFFFFF"
1862  "FFFFFFFF"
1863  "FFFFFFFF"
1864  "GGGGGGGG"
1865  "GGGGGGGG"
1866  "HHHHHHHH"
1867  "HHHHHHHH"
1868  "IIIIIIII"
1869  "QQQQQQQQ"
1870  };
1871 
1872  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
1873  sizeof(expected)));
1874  PASS;
1875 }
1876 
1877 static int DefragSturgesNovakSolarisTest(void)
1878 {
1879  /* Expected data. */
1880  u_char expected[] = {
1881  "AAAAAAAA"
1882  "AAAAAAAA"
1883  "AAAAAAAA"
1884  "JJJJJJJJ"
1885  "BBBBBBBB"
1886  "BBBBBBBB"
1887  "CCCCCCCC"
1888  "CCCCCCCC"
1889  "CCCCCCCC"
1890  "LLLLLLLL"
1891  "LLLLLLLL"
1892  "LLLLLLLL"
1893  "MMMMMMMM"
1894  "MMMMMMMM"
1895  "MMMMMMMM"
1896  "FFFFFFFF"
1897  "FFFFFFFF"
1898  "FFFFFFFF"
1899  "GGGGGGGG"
1900  "GGGGGGGG"
1901  "HHHHHHHH"
1902  "HHHHHHHH"
1903  "IIIIIIII"
1904  "QQQQQQQQ"
1905  };
1906 
1907  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
1908  sizeof(expected)));
1909  PASS;
1910 }
1911 
1912 static int IPV6DefragSturgesNovakSolarisTest(void)
1913 {
1914  /* Expected data. */
1915  u_char expected[] = {
1916  "AAAAAAAA"
1917  "AAAAAAAA"
1918  "AAAAAAAA"
1919  "JJJJJJJJ"
1920  "BBBBBBBB"
1921  "BBBBBBBB"
1922  "CCCCCCCC"
1923  "CCCCCCCC"
1924  "CCCCCCCC"
1925  "LLLLLLLL"
1926  "LLLLLLLL"
1927  "LLLLLLLL"
1928  "MMMMMMMM"
1929  "MMMMMMMM"
1930  "MMMMMMMM"
1931  "FFFFFFFF"
1932  "FFFFFFFF"
1933  "FFFFFFFF"
1934  "GGGGGGGG"
1935  "GGGGGGGG"
1936  "HHHHHHHH"
1937  "HHHHHHHH"
1938  "IIIIIIII"
1939  "QQQQQQQQ"
1940  };
1941 
1942  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
1943  sizeof(expected)));
1944  PASS;
1945 }
1946 
1947 static int DefragSturgesNovakFirstTest(void)
1948 {
1949  /* Expected data. */
1950  u_char expected[] = {
1951  "AAAAAAAA"
1952  "AAAAAAAA"
1953  "AAAAAAAA"
1954  "JJJJJJJJ"
1955  "BBBBBBBB"
1956  "BBBBBBBB"
1957  "CCCCCCCC"
1958  "CCCCCCCC"
1959  "CCCCCCCC"
1960  "LLLLLLLL"
1961  "DDDDDDDD"
1962  "LLLLLLLL"
1963  "MMMMMMMM"
1964  "EEEEEEEE"
1965  "EEEEEEEE"
1966  "FFFFFFFF"
1967  "FFFFFFFF"
1968  "FFFFFFFF"
1969  "GGGGGGGG"
1970  "GGGGGGGG"
1971  "HHHHHHHH"
1972  "HHHHHHHH"
1973  "IIIIIIII"
1974  "QQQQQQQQ"
1975  };
1976 
1977  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
1978  sizeof(expected)));
1979  PASS;
1980 }
1981 
1982 static int IPV6DefragSturgesNovakFirstTest(void)
1983 {
1984  /* Expected data. */
1985  u_char expected[] = {
1986  "AAAAAAAA"
1987  "AAAAAAAA"
1988  "AAAAAAAA"
1989  "JJJJJJJJ"
1990  "BBBBBBBB"
1991  "BBBBBBBB"
1992  "CCCCCCCC"
1993  "CCCCCCCC"
1994  "CCCCCCCC"
1995  "LLLLLLLL"
1996  "DDDDDDDD"
1997  "LLLLLLLL"
1998  "MMMMMMMM"
1999  "EEEEEEEE"
2000  "EEEEEEEE"
2001  "FFFFFFFF"
2002  "FFFFFFFF"
2003  "FFFFFFFF"
2004  "GGGGGGGG"
2005  "GGGGGGGG"
2006  "HHHHHHHH"
2007  "HHHHHHHH"
2008  "IIIIIIII"
2009  "QQQQQQQQ"
2010  };
2011 
2012  return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
2013  sizeof(expected));
2014 }
2015 
2016 static int
2017 DefragSturgesNovakLastTest(void)
2018 {
2019  /* Expected data. */
2020  u_char expected[] = {
2021  "AAAAAAAA"
2022  "JJJJJJJJ"
2023  "JJJJJJJJ"
2024  "JJJJJJJJ"
2025  "JJJJJJJJ"
2026  "BBBBBBBB"
2027  "KKKKKKKK"
2028  "KKKKKKKK"
2029  "KKKKKKKK"
2030  "LLLLLLLL"
2031  "LLLLLLLL"
2032  "LLLLLLLL"
2033  "MMMMMMMM"
2034  "MMMMMMMM"
2035  "MMMMMMMM"
2036  "FFFFFFFF"
2037  "NNNNNNNN"
2038  "FFFFFFFF"
2039  "GGGGGGGG"
2040  "OOOOOOOO"
2041  "PPPPPPPP"
2042  "HHHHHHHH"
2043  "QQQQQQQQ"
2044  "QQQQQQQQ"
2045  };
2046 
2047  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2048  sizeof(expected)));
2049  PASS;
2050 }
2051 
2052 static int IPV6DefragSturgesNovakLastTest(void)
2053 {
2054  /* Expected data. */
2055  u_char expected[] = {
2056  "AAAAAAAA"
2057  "JJJJJJJJ"
2058  "JJJJJJJJ"
2059  "JJJJJJJJ"
2060  "JJJJJJJJ"
2061  "BBBBBBBB"
2062  "KKKKKKKK"
2063  "KKKKKKKK"
2064  "KKKKKKKK"
2065  "LLLLLLLL"
2066  "LLLLLLLL"
2067  "LLLLLLLL"
2068  "MMMMMMMM"
2069  "MMMMMMMM"
2070  "MMMMMMMM"
2071  "FFFFFFFF"
2072  "NNNNNNNN"
2073  "FFFFFFFF"
2074  "GGGGGGGG"
2075  "OOOOOOOO"
2076  "PPPPPPPP"
2077  "HHHHHHHH"
2078  "QQQQQQQQ"
2079  "QQQQQQQQ"
2080  };
2081 
2082  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2083  sizeof(expected)));
2084  PASS;
2085 }
2086 
2087 static int DefragTimeoutTest(void)
2088 {
2089  int i;
2090 
2091  /* Setup a small numberr of trackers. */
2092  FAIL_IF_NOT(ConfSet("defrag.trackers", "16"));
2093 
2094  DefragInit();
2095 
2096  /* Load in 16 packets. */
2097  for (i = 0; i < 16; i++) {
2098  Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16);
2099  FAIL_IF_NULL(p);
2100 
2101  Packet *tp = Defrag(NULL, NULL, p);
2102  SCFree(p);
2103  FAIL_IF_NOT_NULL(tp);
2104  }
2105 
2106  /* Build a new packet but push the timestamp out by our timeout.
2107  * This should force our previous fragments to be timed out. */
2108  Packet *p = BuildTestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
2109  FAIL_IF_NULL(p);
2110 
2111  p->ts = SCTIME_ADD_SECS(p->ts, defrag_context->timeout + 1);
2112  Packet *tp = Defrag(NULL, NULL, p);
2113  FAIL_IF_NOT_NULL(tp);
2114 
2116  FAIL_IF_NULL(tracker);
2117 
2118  FAIL_IF(tracker->id != 99);
2119 
2120  SCMutexUnlock(&tracker->lock);
2121  SCFree(p);
2122 
2123  DefragDestroy();
2124  PASS;
2125 }
2126 
2127 /**
2128  * QA found that if you send a packet where more frags is 0, offset is
2129  * > 0 and there is no data in the packet that the re-assembler will
2130  * fail. The fix was simple, but this unit test is just to make sure
2131  * its not introduced.
2132  */
2133 static int DefragIPv4NoDataTest(void)
2134 {
2135  DefragContext *dc = NULL;
2136  Packet *p = NULL;
2137  int id = 12;
2138 
2139  DefragInit();
2140 
2141  dc = DefragContextNew();
2142  FAIL_IF_NULL(dc);
2143 
2144  /* This packet has an offset > 0, more frags set to 0 and no data. */
2145  p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
2146  FAIL_IF_NULL(p);
2147 
2148  /* We do not expect a packet returned. */
2149  FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2150 
2151  /* The fragment should have been ignored so no fragments should
2152  * have been allocated from the pool. */
2153  FAIL_IF(dc->frag_pool->outstanding != 0);
2154 
2155  DefragContextDestroy(dc);
2156  SCFree(p);
2157 
2158  DefragDestroy();
2159  PASS;
2160 }
2161 
2162 static int DefragIPv4TooLargeTest(void)
2163 {
2164  DefragContext *dc = NULL;
2165  Packet *p = NULL;
2166 
2167  DefragInit();
2168 
2169  dc = DefragContextNew();
2170  FAIL_IF_NULL(dc);
2171 
2172  /* Create a fragment that would extend past the max allowable size
2173  * for an IPv4 packet. */
2174  p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
2175  FAIL_IF_NULL(p);
2176 
2177  /* We do not expect a packet returned. */
2178  FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2179 
2180  /* We do expect an event. */
2182 
2183  /* The fragment should have been ignored so no fragments should have
2184  * been allocated from the pool. */
2185  FAIL_IF(dc->frag_pool->outstanding != 0);
2186 
2187  DefragContextDestroy(dc);
2188  SCFree(p);
2189 
2190  DefragDestroy();
2191  PASS;
2192 }
2193 
2194 /**
2195  * Test that fragments in different VLANs that would otherwise be
2196  * re-assembled, are not re-assembled. Just use simple in-order
2197  * fragments.
2198  */
2199 static int DefragVlanTest(void)
2200 {
2201  Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2202 
2203  DefragInit();
2204 
2205  p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2206  FAIL_IF_NULL(p1);
2207  p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2208  FAIL_IF_NULL(p2);
2209 
2210  /* With no VLAN IDs set, packets should re-assemble. */
2211  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2212  FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2213  SCFree(r);
2214 
2215  /* With mismatched VLANs, packets should not re-assemble. */
2216  p1->vlan_id[0] = 1;
2217  p2->vlan_id[0] = 2;
2218  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2219  FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2220 
2221  SCFree(p1);
2222  SCFree(p2);
2223  DefragDestroy();
2224 
2225  PASS;
2226 }
2227 
2228 /**
2229  * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID.
2230  */
2231 static int DefragVlanQinQTest(void)
2232 {
2233  Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2234 
2235  DefragInit();
2236 
2237  p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2238  FAIL_IF_NULL(p1);
2239  p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2240  FAIL_IF_NULL(p2);
2241 
2242  /* With no VLAN IDs set, packets should re-assemble. */
2243  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2244  FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2245  SCFree(r);
2246 
2247  /* With mismatched VLANs, packets should not re-assemble. */
2248  p1->vlan_id[0] = 1;
2249  p2->vlan_id[0] = 1;
2250  p1->vlan_id[1] = 1;
2251  p2->vlan_id[1] = 2;
2252  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2253  FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2254 
2255  SCFree(p1);
2256  SCFree(p2);
2257  DefragDestroy();
2258 
2259  PASS;
2260 }
2261 
2262 static int DefragTrackerReuseTest(void)
2263 {
2264  int id = 1;
2265  Packet *p1 = NULL;
2266  DefragTracker *tracker1 = NULL, *tracker2 = NULL;
2267 
2268  DefragInit();
2269 
2270  /* Build a packet, its not a fragment but shouldn't matter for
2271  * this test. */
2272  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
2273  FAIL_IF_NULL(p1);
2274 
2275  /* Get a tracker. It shouldn't look like its already in use. */
2276  tracker1 = DefragGetTracker(NULL, NULL, p1);
2277  FAIL_IF_NULL(tracker1);
2278  FAIL_IF(tracker1->seen_last);
2279  FAIL_IF(tracker1->remove);
2280  DefragTrackerRelease(tracker1);
2281 
2282  /* Get a tracker again, it should be the same one. */
2283  tracker2 = DefragGetTracker(NULL, NULL, p1);
2284  FAIL_IF_NULL(tracker2);
2285  FAIL_IF(tracker2 != tracker1);
2286  DefragTrackerRelease(tracker1);
2287 
2288  /* Now mark the tracker for removal. It should not be returned
2289  * when we get a tracker for a packet that may have the same
2290  * attributes. */
2291  tracker1->remove = 1;
2292 
2293  tracker2 = DefragGetTracker(NULL, NULL, p1);
2294  FAIL_IF_NULL(tracker2);
2295  FAIL_IF(tracker2 == tracker1);
2296  FAIL_IF(tracker2->remove);
2297 
2298  SCFree(p1);
2299  DefragDestroy();
2300  PASS;
2301 }
2302 
2303 /**
2304  * IPV4: Test the case where you have a packet fragmented in 3 parts
2305  * and send like:
2306  * - Offset: 2; MF: 1
2307  * - Offset: 0; MF: 1
2308  * - Offset: 1; MF: 0
2309  *
2310  * Only the fragments with offset 0 and 1 should be reassembled.
2311  */
2312 static int DefragMfIpv4Test(void)
2313 {
2314  int ip_id = 9;
2315  Packet *p = NULL;
2316 
2317  DefragInit();
2318 
2319  Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
2320  Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
2321  Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
2322  FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2323 
2324  p = Defrag(NULL, NULL, p1);
2325  FAIL_IF_NOT_NULL(p);
2326 
2327  p = Defrag(NULL, NULL, p2);
2328  FAIL_IF_NOT_NULL(p);
2329 
2330  /* This should return a packet as MF=0. */
2331  p = Defrag(NULL, NULL, p3);
2332  FAIL_IF_NULL(p);
2333 
2334  /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the
2335  * fragments should be in the re-assembled packet. */
2336  FAIL_IF(IPV4_GET_IPLEN(p) != 36);
2337 
2338  SCFree(p1);
2339  SCFree(p2);
2340  SCFree(p3);
2341  SCFree(p);
2342  DefragDestroy();
2343  PASS;
2344 }
2345 
2346 /**
2347  * IPV6: Test the case where you have a packet fragmented in 3 parts
2348  * and send like:
2349  * - Offset: 2; MF: 1
2350  * - Offset: 0; MF: 1
2351  * - Offset: 1; MF: 0
2352  *
2353  * Only the fragments with offset 0 and 1 should be reassembled.
2354  */
2355 static int DefragMfIpv6Test(void)
2356 {
2357  int ip_id = 9;
2358  Packet *p = NULL;
2359 
2360  DefragInit();
2361 
2362  Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
2363  Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
2364  Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
2365  FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2366 
2367  p = Defrag(NULL, NULL, p1);
2368  FAIL_IF_NOT_NULL(p);
2369 
2370  p = Defrag(NULL, NULL, p2);
2371  FAIL_IF_NOT_NULL(p);
2372 
2373  /* This should return a packet as MF=0. */
2374  p = Defrag(NULL, NULL, p3);
2375  FAIL_IF_NULL(p);
2376 
2377  /* For IPv6 the expected length is just the length of the payload
2378  * of 2 fragments, so 16. */
2379  FAIL_IF(IPV6_GET_PLEN(p) != 16);
2380 
2381  SCFree(p1);
2382  SCFree(p2);
2383  SCFree(p3);
2384  SCFree(p);
2385  DefragDestroy();
2386  PASS;
2387 }
2388 
2389 /**
2390  * \brief Test that fragments that match other than the proto don't
2391  * actually get matched.
2392  */
2393 static int DefragTestBadProto(void)
2394 {
2395  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
2396  int id = 12;
2397 
2398  DefragInit();
2399 
2400  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
2401  FAIL_IF_NULL(p1);
2402  p2 = BuildTestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
2403  FAIL_IF_NULL(p2);
2404  p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
2405  FAIL_IF_NULL(p3);
2406 
2407  FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1));
2408  FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p2));
2409  FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p3));
2410 
2411  SCFree(p1);
2412  SCFree(p2);
2413  SCFree(p3);
2414 
2415  DefragDestroy();
2416  PASS;
2417 }
2418 
2419 /**
2420  * \test Test a report Linux overlap issue that doesn't appear to be
2421  * covered by the Sturges/Novak tests above.
2422  */
2423 static int DefragTestJeremyLinux(void)
2424 {
2425  char expected[] = "AAAAAAAA"
2426  "AAAAAAAA"
2427  "AAAAAAAA"
2428  "CCCCCCCC"
2429  "CCCCCCCC"
2430  "CCCCCCCC"
2431  "CCCCCCCC"
2432  "CCCCCCCC"
2433  "CCCCCCCC"
2434  "BBBBBBBB"
2435  "BBBBBBBB"
2436  "DDDDDDDD"
2437  "DDDDDD";
2438 
2439  DefragInit();
2440  default_policy = DEFRAG_POLICY_LINUX;
2441 
2442  int id = 1;
2443  Packet *packets[4];
2444  int i = 0;
2445 
2446  packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
2447  packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
2448  packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
2449  packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
2450 
2451  Packet *r = Defrag(NULL, NULL, packets[0]);
2452  FAIL_IF_NOT_NULL(r);
2453 
2454  r = Defrag(NULL, NULL, packets[1]);
2455  FAIL_IF_NOT_NULL(r);
2456 
2457  r = Defrag(NULL, NULL, packets[2]);
2458  FAIL_IF_NOT_NULL(r);
2459 
2460  r = Defrag(NULL, NULL, packets[3]);
2461  FAIL_IF_NULL(r);
2462 
2463  FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0);
2464 
2465  for (i = 0; i < 4; i++) {
2466  SCFree(packets[i]);
2467  }
2468  SCFree(r);
2469 
2470  DefragDestroy();
2471  PASS;
2472 }
2473 
2474 #endif /* UNITTESTS */
2475 
2477 {
2478 #ifdef UNITTESTS
2479  UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest);
2480  UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest);
2481  UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest);
2482  UtRegisterTest("DefragSturgesNovakLinuxIpv4Test",
2483  DefragSturgesNovakLinuxIpv4Test);
2484  UtRegisterTest("DefragSturgesNovakWindowsIpv4Test",
2485  DefragSturgesNovakWindowsIpv4Test);
2486  UtRegisterTest("DefragSturgesNovakSolarisTest",
2487  DefragSturgesNovakSolarisTest);
2488  UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
2489  UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
2490 
2491  UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest);
2492  UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest);
2493 
2494  UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest);
2495  UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest);
2496  UtRegisterTest("IPV6DefragSturgesNovakBsdTest",
2497  IPV6DefragSturgesNovakBsdTest);
2498  UtRegisterTest("IPV6DefragSturgesNovakLinuxTest",
2499  IPV6DefragSturgesNovakLinuxTest);
2500  UtRegisterTest("IPV6DefragSturgesNovakWindowsTest",
2501  IPV6DefragSturgesNovakWindowsTest);
2502  UtRegisterTest("IPV6DefragSturgesNovakSolarisTest",
2503  IPV6DefragSturgesNovakSolarisTest);
2504  UtRegisterTest("IPV6DefragSturgesNovakFirstTest",
2505  IPV6DefragSturgesNovakFirstTest);
2506  UtRegisterTest("IPV6DefragSturgesNovakLastTest",
2507  IPV6DefragSturgesNovakLastTest);
2508 
2509  UtRegisterTest("DefragVlanTest", DefragVlanTest);
2510  UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
2511  UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest);
2512  UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest);
2513  UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test);
2514  UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test);
2515  UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
2516 
2517  UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux);
2518 #endif /* UNITTESTS */
2519 }
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:887
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:1074
ConfGetInt
int ConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition: conf.c:397
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:712
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:636
len
uint8_t len
Definition: app-layer-dnp3.h:2
IPV6_FRAG_OVERLAP
@ IPV6_FRAG_OVERLAP
Definition: decode-events.h:172
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
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_FRAG_PKT_TOO_LARGE
@ IPV6_FRAG_PKT_TOO_LARGE
Definition: decode-events.h:170
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
Packet_::vlan_id
uint16_t vlan_id[2]
Definition: decode.h:455
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
OS_POLICY_IRIX
@ OS_POLICY_IRIX
Definition: stream-tcp-reassemble.h:44
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:902
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:594
SET_IPV6_DST_ADDR
#define SET_IPV6_DST_ADDR(p, a)
Definition: decode.h:168
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:463
IPV6_SET_RAW_VER
#define IPV6_SET_RAW_VER(ip6h, value)
Definition: decode-ipv6.h:69
threads.h
IP_MF
#define IP_MF
Definition: defrag.c:1086
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
OS_POLICY_BSD
@ OS_POLICY_BSD
Definition: stream-tcp-reassemble.h:36
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:214
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:142
DefragTracker_::lock
SCMutex lock
Definition: defrag.h:87
PKT_SET_SRC
#define PKT_SET_SRC(p, src_val)
Definition: decode.h:1062
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
OS_POLICY_VISTA
@ OS_POLICY_VISTA
Definition: stream-tcp-reassemble.h:47
SET_PKT_LEN
#define SET_PKT_LEN(p, len)
Definition: decode.h:223
SCTIME_FROM_SECS
#define SCTIME_FROM_SECS(s)
Definition: util-time.h:55
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:209
Packet_::ts
SCTime_t ts
Definition: decode.h:471
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
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:219
IPV4_MAXPACKET_LEN
#define IPV4_MAXPACKET_LEN
Definition: decode-ipv4.h:30
DefragRegisterTests
void DefragRegisterTests(void)
Definition: defrag.c:2476
UNSET_TUNNEL_PKT
#define UNSET_TUNNEL_PKT(p)
Definition: decode.h:799
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:65
OS_POLICY_HPUX11
@ OS_POLICY_HPUX11
Definition: stream-tcp-reassemble.h:43
SET_IPV6_SRC_ADDR
#define SET_IPV6_SRC_ADDR(p, a)
Definition: decode.h:160
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
OS_POLICY_MACOS
@ OS_POLICY_MACOS
Definition: stream-tcp-reassemble.h:45
IPV4_FRAG_OVERLAP
@ IPV4_FRAG_OVERLAP
Definition: decode-events.h:171
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:428
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:218
PoolFree
void PoolFree(Pool *p)
Definition: util-pool.c:222
IPV6_FRAG_IGNORED
@ IPV6_FRAG_IGNORED
Definition: decode-events.h:177
stream-tcp-private.h
OS_POLICY_HPUX10
@ OS_POLICY_HPUX10
Definition: stream-tcp-reassemble.h:42
conf.h
Packet_::ip4h
IPV4Hdr * ip4h
Definition: decode.h:531
Frag_::skip
uint8_t skip
Definition: defrag.h:55
DefragInitConfig
void DefragInitConfig(bool quiet)
initialize the configuration
Definition: defrag-hash.c:167
Frag_::pkt
uint8_t * pkt
Definition: defrag.h:68
Frag_::data_offset
uint16_t data_offset
Definition: defrag.h:62
queue.h
defrag.h
IPV6ExtHdrs_::fh_data_len
uint16_t fh_data_len
Definition: decode-ipv6.h:228
OS_POLICY_SOLARIS
@ OS_POLICY_SOLARIS
Definition: stream-tcp-reassemble.h:41
DefragTrackerRelease
void DefragTrackerRelease(DefragTracker *t)
Definition: defrag-hash.c:150
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
OS_POLICY_FIRST
@ OS_POLICY_FIRST
Definition: stream-tcp-reassemble.h:49
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:335
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:156
IPV6Hdr
struct IPV6Hdr_ IPV6Hdr
OS_POLICY_LAST
@ OS_POLICY_LAST
Definition: stream-tcp-reassemble.h:50
suricata-common.h
IPV4_FRAG_PKT_TOO_LARGE
@ IPV4_FRAG_PKT_TOO_LARGE
Definition: decode-events.h:169
Frag_::len
uint32_t len
Definition: defrag.h:50
DefragGetTrackerFromHash
DefragTracker * DefragGetTrackerFromHash(Packet *p)
Definition: defrag-hash.c:537
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:51
IPV6ExtHdrs_::fh_header_offset
uint16_t fh_header_offset
Definition: decode-ipv6.h:226
OS_POLICY_OLD_LINUX
@ OS_POLICY_OLD_LINUX
Definition: stream-tcp-reassemble.h:38
DecodeThreadVars_::counter_defrag_ipv6_reassembled
uint16_t counter_defrag_ipv6_reassembled
Definition: decode.h:715
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:128
DEFRAG_POLICY_SOLARIS
@ DEFRAG_POLICY_SOLARIS
Definition: defrag.c:93
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
Frag_::frag_hdr_offset
uint16_t frag_hdr_offset
Definition: defrag.h:59
util-validate.h
OS_POLICY_WINDOWS
@ OS_POLICY_WINDOWS
Definition: stream-tcp-reassemble.h:46
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
Packet_::root
struct Packet_ * root
Definition: decode.h:618
PoolGet
void * PoolGet(Pool *p)
Definition: util-pool.c:277
PKT_REBUILT_FRAGMENT
#define PKT_REBUILT_FRAGMENT
Definition: decode.h:1039
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:664
MAX_PAYLOAD_SIZE
#define MAX_PAYLOAD_SIZE
Definition: decode.h:658
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:453
IPV4_GET_MF
#define IPV4_GET_MF(p)
Definition: decode-ipv4.h:144
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
Packet_::dst
Address dst
Definition: decode.h:433
TIMEOUT_DEFAULT
#define TIMEOUT_DEFAULT
Definition: defrag.c:73
OS_POLICY_WINDOWS2K3
@ OS_POLICY_WINDOWS2K3
Definition: stream-tcp-reassemble.h:48
DecodeThreadVars_::counter_defrag_ipv6_fragments
uint16_t counter_defrag_ipv6_fragments
Definition: decode.h:714
IPV6_HEADER_LEN
#define IPV6_HEADER_LEN
Definition: decode-ipv6.h:27
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
OS_POLICY_OLD_SOLARIS
@ OS_POLICY_OLD_SOLARIS
Definition: stream-tcp-reassemble.h:40
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:427
DefragHashShutdown
void DefragHashShutdown(void)
shutdown the flow engine
Definition: defrag-hash.c:303
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:533
SET_IPV4_DST_ADDR
#define SET_IPV4_DST_ADDR(p, a)
Definition: decode.h:150
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:122
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:53
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
OS_POLICY_LINUX
@ OS_POLICY_LINUX
Definition: stream-tcp-reassemble.h:39
IPV4_FRAG_IGNORED
@ IPV4_FRAG_IGNORED
Definition: decode-events.h:176
IPV4Hdr_::ip_verhl
uint8_t ip_verhl
Definition: decode-ipv4.h:73
OS_POLICY_BSD_RIGHT
@ OS_POLICY_BSD_RIGHT
Definition: stream-tcp-reassemble.h:37
DEFRAG_POLICY_BSD
@ DEFRAG_POLICY_BSD
Definition: defrag.c:89
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:111
Frag_::offset
uint16_t offset
Definition: defrag.h:47
Packet_::src
Address src
Definition: decode.h:432
DefragInit
void DefragInit(void)
Definition: defrag.c:1054
IPV4_GET_IPTTL
#define IPV4_GET_IPTTL(p)
Definition: decode-ipv4.h:146
Packet_::ip6eh
IPV6ExtHdrs ip6eh
Definition: decode.h:540
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:711