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