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 #include "util-validate.h"
67 
68 #define DEFAULT_DEFRAG_HASH_SIZE 0xffff
69 #define DEFAULT_DEFRAG_POOL_SIZE 0xffff
70 
71 /**
72  * Default timeout (in seconds) before a defragmentation tracker will
73  * be released.
74  */
75 #define TIMEOUT_DEFAULT 60
76 
77 /**
78  * Maximum allowed timeout, 24 hours.
79  */
80 #define TIMEOUT_MAX (60 * 60 * 24)
81 
82 /**
83  * Minimum allowed timeout, 1 second.
84  */
85 #define TIMEOUT_MIN 1
86 
87 /** Fragment reassembly policies. */
96 
98 };
99 
100 static uint8_t default_policy = DEFRAG_POLICY_BSD;
101 
102 /** The global DefragContext so all threads operate from the same
103  * context. */
104 static DefragContext *defrag_context;
105 
107 
108 /**
109  * Utility/debugging function to dump the frags associated with a
110  * tracker. Only enable when unit tests are enabled.
111  */
112 #if 0
113 #ifdef UNITTESTS
114 static void
115 DumpFrags(DefragTracker *tracker)
116 {
117  Frag *frag;
118 
119  printf("Dumping frags for packet: ID=%d\n", tracker->id);
120  TAILQ_FOREACH(frag, &tracker->frags, next) {
121  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);
122  PrintRawDataFp(stdout, frag->pkt, frag->len);
123  }
124 }
125 #endif /* UNITTESTS */
126 #endif
127 
128 /**
129  * \brief Reset a frag for reuse in a pool.
130  */
131 static void
132 DefragFragReset(Frag *frag)
133 {
134  if (frag->pkt != NULL)
135  SCFree(frag->pkt);
136  memset(frag, 0, sizeof(*frag));
137 }
138 
139 /**
140  * \brief Allocate a new frag for use in a pool.
141  */
142 static int
143 DefragFragInit(void *data, void *initdata)
144 {
145  Frag *frag = data;
146 
147  memset(frag, 0, sizeof(*frag));
148  return 1;
149 }
150 
151 /**
152  * \brief Free all frags associated with a tracker.
153  */
154 void
156 {
157  Frag *frag, *tmp;
158 
159  /* Lock the frag pool as we'll be return items to it. */
160  SCMutexLock(&defrag_context->frag_pool_lock);
161 
162  RB_FOREACH_SAFE(frag, IP_FRAGMENTS, &tracker->fragment_tree, tmp) {
163  RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, frag);
164  DefragFragReset(frag);
165  PoolReturn(defrag_context->frag_pool, frag);
166  }
167 
168  SCMutexUnlock(&defrag_context->frag_pool_lock);
169 }
170 
171 /**
172  * \brief Create a new DefragContext.
173  *
174  * \retval On success a return an initialized DefragContext, otherwise
175  * NULL will be returned.
176  */
177 static DefragContext *
178 DefragContextNew(void)
179 {
180  DefragContext *dc;
181 
182  dc = SCCalloc(1, sizeof(*dc));
183  if (unlikely(dc == NULL))
184  return NULL;
185 
186  /* Initialize the pool of trackers. */
187  intmax_t tracker_pool_size;
188  if (!ConfGetInt("defrag.trackers", &tracker_pool_size) || tracker_pool_size == 0) {
189  tracker_pool_size = DEFAULT_DEFRAG_HASH_SIZE;
190  }
191 
192  /* Initialize the pool of frags. */
193  intmax_t frag_pool_size;
194  if (!ConfGetInt("defrag.max-frags", &frag_pool_size) || frag_pool_size == 0) {
195  frag_pool_size = DEFAULT_DEFRAG_POOL_SIZE;
196  }
197  intmax_t frag_pool_prealloc = frag_pool_size / 2;
198  dc->frag_pool = PoolInit(frag_pool_size, frag_pool_prealloc,
199  sizeof(Frag),
200  NULL, DefragFragInit, dc, NULL, NULL);
201  if (dc->frag_pool == NULL) {
203  "Defrag: Failed to initialize fragment pool.");
204  }
205  if (SCMutexInit(&dc->frag_pool_lock, NULL) != 0) {
207  "Defrag: Failed to initialize frag pool mutex.");
208  }
209 
210  /* Set the default timeout. */
211  intmax_t timeout;
212  if (!ConfGetInt("defrag.timeout", &timeout)) {
213  dc->timeout = TIMEOUT_DEFAULT;
214  }
215  else {
216  if (timeout < TIMEOUT_MIN) {
218  "defrag: Timeout less than minimum allowed value.");
219  }
220  else if (timeout > TIMEOUT_MAX) {
222  "defrag: Tiemout greater than maximum allowed value.");
223  }
224  dc->timeout = timeout;
225  }
226 
227  SCLogDebug("Defrag Initialized:");
228  SCLogDebug("\tTimeout: %"PRIuMAX, (uintmax_t)dc->timeout);
229  SCLogDebug("\tMaximum defrag trackers: %"PRIuMAX, tracker_pool_size);
230  SCLogDebug("\tPreallocated defrag trackers: %"PRIuMAX, tracker_pool_size);
231  SCLogDebug("\tMaximum fragments: %"PRIuMAX, (uintmax_t)frag_pool_size);
232  SCLogDebug("\tPreallocated fragments: %"PRIuMAX, (uintmax_t)frag_pool_prealloc);
233 
234  return dc;
235 }
236 
237 static void
238 DefragContextDestroy(DefragContext *dc)
239 {
240  if (dc == NULL)
241  return;
242 
243  PoolFree(dc->frag_pool);
244  SCFree(dc);
245 }
246 
247 /**
248  * Attempt to re-assemble a packet.
249  *
250  * \param tracker The defragmentation tracker to reassemble from.
251  */
252 static Packet *
253 Defrag4Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
254 {
255  Packet *rp = NULL;
256 
257  /* Should not be here unless we have seen the last fragment. */
258  if (!tracker->seen_last) {
259  return NULL;
260  }
261 
262  /* Check that we have the first fragment and its of a valid size. */
263  Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
264  if (first == NULL) {
265  goto done;
266  } else if (first->offset != 0) {
267  /* Still waiting for the first fragment. */
268  goto done;
269  } else if (first->len < sizeof(IPV4Hdr)) {
270  /* First fragment isn't enough for an IPv6 header. */
271  goto error_remove_tracker;
272  }
273 
274  /* Check that we have all the data. Relies on the fact that
275  * fragments are inserted if frag_offset order. */
276  Frag *frag = NULL;
277  size_t len = 0;
278  RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
279  if (frag->offset > len) {
280  /* This fragment starts after the end of the previous
281  * fragment. We have a hole. */
282  goto done;
283  }
284  else {
285  len += frag->data_len;
286  }
287  }
288 
289  /* Allocate a Packet for the reassembled packet. On failure we
290  * SCFree all the resources held by this tracker. */
291  rp = PacketDefragPktSetup(p, NULL, 0, IPV4_GET_IPPROTO(p));
292  if (rp == NULL) {
293  SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for "
294  "fragmentation re-assembly, dumping fragments.");
295  goto error_remove_tracker;
296  }
300 
301  int fragmentable_offset = 0;
302  int fragmentable_len = 0;
303  int hlen = 0;
304  int ip_hdr_offset = 0;
305 
306  RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
307  SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64,
308  frag, frag->data_len, frag->offset, frag->pcap_cnt);
309 
310  if (frag->skip)
311  continue;
312  if (frag->ltrim >= frag->data_len)
313  continue;
314  if (frag->offset == 0) {
315 
316  if (PacketCopyData(rp, frag->pkt, frag->len) == -1)
317  goto error_remove_tracker;
318 
319  hlen = frag->hlen;
320  ip_hdr_offset = frag->ip_hdr_offset;
321 
322  /* This is the start of the fragmentable portion of the
323  * first packet. All fragment offsets are relative to
324  * this. */
325  fragmentable_offset = frag->ip_hdr_offset + frag->hlen;
326  fragmentable_len = frag->data_len;
327  }
328  else {
329  int pkt_end = fragmentable_offset + frag->offset + frag->data_len;
330  if (pkt_end > (int)MAX_PAYLOAD_SIZE) {
331  SCLogWarning(SC_ERR_REASSEMBLY, "Failed re-assemble "
332  "fragmented packet, exceeds size of packet buffer.");
333  goto error_remove_tracker;
334  }
335  if (PacketCopyDataOffset(rp,
336  fragmentable_offset + frag->offset + frag->ltrim,
337  frag->pkt + frag->data_offset + frag->ltrim,
338  frag->data_len - frag->ltrim) == -1) {
339  goto error_remove_tracker;
340  }
341  if (frag->offset + frag->data_len > fragmentable_len)
342  fragmentable_len = frag->offset + frag->data_len;
343  }
344 
345  if (!frag->more_frags) {
346  break;
347  }
348  }
349 
350  SCLogDebug("ip_hdr_offset %u, hlen %u, fragmentable_len %u",
351  ip_hdr_offset, hlen, fragmentable_len);
352 
353  rp->ip4h = (IPV4Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
354  uint16_t old = rp->ip4h->ip_len + rp->ip4h->ip_off;
355  rp->ip4h->ip_len = htons(fragmentable_len + hlen);
356  rp->ip4h->ip_off = 0;
357  rp->ip4h->ip_csum = FixChecksum(rp->ip4h->ip_csum,
358  old, rp->ip4h->ip_len + rp->ip4h->ip_off);
359  SET_PKT_LEN(rp, ip_hdr_offset + hlen + fragmentable_len);
360 
361  tracker->remove = 1;
362  DefragTrackerFreeFrags(tracker);
363 done:
364  return rp;
365 
366 error_remove_tracker:
367  tracker->remove = 1;
368  DefragTrackerFreeFrags(tracker);
369  if (rp != NULL)
371  return NULL;
372 }
373 
374 /**
375  * Attempt to re-assemble a packet.
376  *
377  * \param tracker The defragmentation tracker to reassemble from.
378  */
379 static Packet *
380 Defrag6Reassemble(ThreadVars *tv, DefragTracker *tracker, Packet *p)
381 {
382  Packet *rp = NULL;
383 
384  /* Should not be here unless we have seen the last fragment. */
385  if (!tracker->seen_last)
386  return NULL;
387 
388  /* Check that we have the first fragment and its of a valid size. */
389  Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
390  if (first == NULL) {
391  goto done;
392  } else if (first->offset != 0) {
393  /* Still waiting for the first fragment. */
394  goto done;
395  } else if (first->len < sizeof(IPV6Hdr)) {
396  /* First fragment isn't enough for an IPv6 header. */
397  goto error_remove_tracker;
398  }
399 
400  /* Check that we have all the data. Relies on the fact that
401  * fragments are inserted if frag_offset order. */
402  size_t len = 0;
403  Frag *frag = NULL;
404  RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
405  if (frag->skip) {
406  continue;
407  }
408 
409  if (frag == first) {
410  if (frag->offset != 0) {
411  goto done;
412  }
413  len = frag->data_len;
414  }
415  else {
416  if (frag->offset > len) {
417  /* This fragment starts after the end of the previous
418  * fragment. We have a hole. */
419  goto done;
420  }
421  else {
422  len += frag->data_len;
423  }
424  }
425  }
426 
427  /* Allocate a Packet for the reassembled packet. On failure we
428  * SCFree all the resources held by this tracker. */
429  rp = PacketDefragPktSetup(p, (uint8_t *)p->ip6h,
430  IPV6_GET_PLEN(p) + sizeof(IPV6Hdr), 0);
431  if (rp == NULL) {
432  SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate packet for "
433  "fragmentation re-assembly, dumping fragments.");
434  goto error_remove_tracker;
435  }
437 
438  int unfragmentable_len = 0;
439  int fragmentable_offset = 0;
440  int fragmentable_len = 0;
441  int ip_hdr_offset = 0;
442  uint8_t next_hdr = 0;
443  RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
444  if (frag->skip)
445  continue;
446  if (frag->data_len - frag->ltrim <= 0)
447  continue;
448  if (frag->offset == 0) {
449  IPV6FragHdr *frag_hdr = (IPV6FragHdr *)(frag->pkt +
450  frag->frag_hdr_offset);
451  next_hdr = frag_hdr->ip6fh_nxt;
452 
453  /* This is the first packet, we use this packets link and
454  * IPv6 headers. We also copy in its data, but remove the
455  * fragmentation header. */
456  if (PacketCopyData(rp, frag->pkt, frag->frag_hdr_offset) == -1)
457  goto error_remove_tracker;
459  frag->pkt + frag->frag_hdr_offset + sizeof(IPV6FragHdr),
460  frag->data_len) == -1)
461  goto error_remove_tracker;
462  ip_hdr_offset = frag->ip_hdr_offset;
463 
464  /* This is the start of the fragmentable portion of the
465  * first packet. All fragment offsets are relative to
466  * this. */
467  fragmentable_offset = frag->frag_hdr_offset;
468  fragmentable_len = frag->data_len;
469 
470  /* unfragmentable part is the part between the ipv6 header
471  * and the frag header. */
472  unfragmentable_len = (fragmentable_offset - ip_hdr_offset) - IPV6_HEADER_LEN;
473  if (unfragmentable_len >= fragmentable_offset)
474  goto error_remove_tracker;
475  }
476  else {
477  if (PacketCopyDataOffset(rp, fragmentable_offset + frag->offset + frag->ltrim,
478  frag->pkt + frag->data_offset + frag->ltrim,
479  frag->data_len - frag->ltrim) == -1)
480  goto error_remove_tracker;
481  if (frag->offset + frag->data_len > fragmentable_len)
482  fragmentable_len = frag->offset + frag->data_len;
483  }
484 
485  if (!frag->more_frags) {
486  break;
487  }
488  }
489 
490  rp->ip6h = (IPV6Hdr *)(GET_PKT_DATA(rp) + ip_hdr_offset);
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 = TimevalWithSeconds(&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) {
1068  "Failed to allocate memory for the Defrag module.");
1069  }
1070 
1071  DefragSetDefaultTimeout(defrag_context->timeout);
1072  DefragInitConfig(false);
1073 }
1074 
1075 void DefragDestroy(void)
1076 {
1078  DefragContextDestroy(defrag_context);
1079  defrag_context = NULL;
1081 }
1082 
1083 #ifdef UNITTESTS
1084 #define IP_MF 0x2000
1086 /**
1087  * Allocate a test packet. Nothing to fancy, just a simple IP packet
1088  * with some payload of no particular protocol.
1089  */
1090 static Packet *BuildTestPacket(uint8_t proto, uint16_t id, uint16_t off, int mf,
1091  const char content, int content_len)
1092 {
1093  Packet *p = NULL;
1094  int hlen = 20;
1095  int ttl = 64;
1096  uint8_t *pcontent;
1097  IPV4Hdr ip4h;
1098 
1099  p = SCCalloc(1, sizeof(*p) + default_packet_size);
1100  if (unlikely(p == NULL))
1101  return NULL;
1102 
1103  PACKET_INITIALIZE(p);
1104 
1105  gettimeofday(&p->ts, NULL);
1106  //p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1107  ip4h.ip_verhl = 4 << 4;
1108  ip4h.ip_verhl |= hlen >> 2;
1109  ip4h.ip_len = htons(hlen + content_len);
1110  ip4h.ip_id = htons(id);
1111  if (mf)
1112  ip4h.ip_off = htons(IP_MF | off);
1113  else
1114  ip4h.ip_off = htons(off);
1115  ip4h.ip_ttl = ttl;
1116  ip4h.ip_proto = proto;
1117 
1118  ip4h.s_ip_src.s_addr = 0x01010101; /* 1.1.1.1 */
1119  ip4h.s_ip_dst.s_addr = 0x02020202; /* 2.2.2.2 */
1120 
1121  /* copy content_len crap, we need full length */
1122  PacketCopyData(p, (uint8_t *)&ip4h, sizeof(ip4h));
1123  p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
1124  SET_IPV4_SRC_ADDR(p, &p->src);
1125  SET_IPV4_DST_ADDR(p, &p->dst);
1126 
1127  pcontent = SCCalloc(1, content_len);
1128  if (unlikely(pcontent == NULL))
1129  return NULL;
1130  memset(pcontent, content, content_len);
1131  PacketCopyDataOffset(p, hlen, pcontent, content_len);
1132  SET_PKT_LEN(p, hlen + content_len);
1133  SCFree(pcontent);
1134 
1135  p->ip4h->ip_csum = IPV4Checksum((uint16_t *)GET_PKT_DATA(p), hlen, 0);
1136 
1137  /* Self test. */
1138  if (IPV4_GET_VER(p) != 4)
1139  goto error;
1140  if (IPV4_GET_HLEN(p) != hlen)
1141  goto error;
1142  if (IPV4_GET_IPLEN(p) != hlen + content_len)
1143  goto error;
1144  if (IPV4_GET_IPID(p) != id)
1145  goto error;
1146  if (IPV4_GET_IPOFFSET(p) != off)
1147  goto error;
1148  if (IPV4_GET_MF(p) != mf)
1149  goto error;
1150  if (IPV4_GET_IPTTL(p) != ttl)
1151  goto error;
1152  if (IPV4_GET_IPPROTO(p) != proto)
1153  goto error;
1154 
1155  return p;
1156 error:
1157  if (p != NULL)
1158  SCFree(p);
1159  return NULL;
1160 }
1161 
1162 static Packet *IPV6BuildTestPacket(uint8_t proto, uint32_t id, uint16_t off,
1163  int mf, const char content, int content_len)
1164 {
1165  Packet *p = NULL;
1166  uint8_t *pcontent;
1167  IPV6Hdr ip6h;
1168 
1169  p = SCCalloc(1, sizeof(*p) + default_packet_size);
1170  if (unlikely(p == NULL))
1171  return NULL;
1172 
1173  PACKET_INITIALIZE(p);
1174 
1175  gettimeofday(&p->ts, NULL);
1176 
1177  ip6h.s_ip6_nxt = 44;
1178  ip6h.s_ip6_hlim = 2;
1179 
1180  /* Source and dest address - very bogus addresses. */
1181  ip6h.s_ip6_src[0] = 0x01010101;
1182  ip6h.s_ip6_src[1] = 0x01010101;
1183  ip6h.s_ip6_src[2] = 0x01010101;
1184  ip6h.s_ip6_src[3] = 0x01010101;
1185  ip6h.s_ip6_dst[0] = 0x02020202;
1186  ip6h.s_ip6_dst[1] = 0x02020202;
1187  ip6h.s_ip6_dst[2] = 0x02020202;
1188  ip6h.s_ip6_dst[3] = 0x02020202;
1189 
1190  /* copy content_len crap, we need full length */
1191  PacketCopyData(p, (uint8_t *)&ip6h, sizeof(IPV6Hdr));
1192 
1193  p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
1194  IPV6_SET_RAW_VER(p->ip6h, 6);
1195  /* Fragmentation header. */
1196  IPV6FragHdr *fh = (IPV6FragHdr *)(GET_PKT_DATA(p) + sizeof(IPV6Hdr));
1197  fh->ip6fh_nxt = proto;
1198  fh->ip6fh_ident = htonl(id);
1199  fh->ip6fh_offlg = htons((off << 3) | mf);
1200 
1201  DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0);
1202 
1203  pcontent = SCCalloc(1, content_len);
1204  if (unlikely(pcontent == NULL))
1205  return NULL;
1206  memset(pcontent, content, content_len);
1207  PacketCopyDataOffset(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr), pcontent, content_len);
1208  SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(IPV6FragHdr) + content_len);
1209  SCFree(pcontent);
1210 
1211  p->ip6h->s_ip6_plen = htons(sizeof(IPV6FragHdr) + content_len);
1212 
1213  SET_IPV6_SRC_ADDR(p, &p->src);
1214  SET_IPV6_DST_ADDR(p, &p->dst);
1215 
1216  /* Self test. */
1217  if (IPV6_GET_VER(p) != 6)
1218  goto error;
1219  if (IPV6_GET_NH(p) != 44)
1220  goto error;
1221  if (IPV6_GET_PLEN(p) != sizeof(IPV6FragHdr) + content_len)
1222  goto error;
1223 
1224  return p;
1225 error:
1226  if (p != NULL)
1227  SCFree(p);
1228  return NULL;
1229 }
1230 
1231 /**
1232  * Test the simplest possible re-assembly scenario. All packet in
1233  * order and no overlaps.
1234  */
1235 static int DefragInOrderSimpleTest(void)
1236 {
1237  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1238  Packet *reassembled = NULL;
1239  int id = 12;
1240  int i;
1241 
1242  DefragInit();
1243 
1244  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1245  FAIL_IF_NULL(p1);
1246  p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1247  FAIL_IF_NULL(p2);
1248  p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1249  FAIL_IF_NULL(p3);
1250 
1251  FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1252  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1253 
1254  reassembled = Defrag(NULL, NULL, p3);
1255  FAIL_IF_NULL(reassembled);
1256 
1257  FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1258  FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1259 
1260  /* 20 bytes in we should find 8 bytes of A. */
1261  for (i = 20; i < 20 + 8; i++) {
1262  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1263  }
1264 
1265  /* 28 bytes in we should find 8 bytes of B. */
1266  for (i = 28; i < 28 + 8; i++) {
1267  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1268  }
1269 
1270  /* And 36 bytes in we should find 3 bytes of C. */
1271  for (i = 36; i < 36 + 3; i++) {
1272  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1273  }
1274 
1275  SCFree(p1);
1276  SCFree(p2);
1277  SCFree(p3);
1278  SCFree(reassembled);
1279 
1280  DefragDestroy();
1281  PASS;
1282 }
1283 
1284 /**
1285  * Simple fragmented packet in reverse order.
1286  */
1287 static int DefragReverseSimpleTest(void)
1288 {
1289  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1290  Packet *reassembled = NULL;
1291  int id = 12;
1292  int i;
1293 
1294  DefragInit();
1295 
1296  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
1297  FAIL_IF_NULL(p1);
1298  p2 = BuildTestPacket(IPPROTO_ICMP, id, 1, 1, 'B', 8);
1299  FAIL_IF_NULL(p2);
1300  p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
1301  FAIL_IF_NULL(p3);
1302 
1303  FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1304  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1305 
1306  reassembled = Defrag(NULL, NULL, p1);
1307  FAIL_IF_NULL(reassembled);
1308 
1309  FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1310  FAIL_IF(IPV4_GET_IPLEN(reassembled) != 39);
1311 
1312  /* 20 bytes in we should find 8 bytes of A. */
1313  for (i = 20; i < 20 + 8; i++) {
1314  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1315  }
1316 
1317  /* 28 bytes in we should find 8 bytes of B. */
1318  for (i = 28; i < 28 + 8; i++) {
1319  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1320  }
1321 
1322  /* And 36 bytes in we should find 3 bytes of C. */
1323  for (i = 36; i < 36 + 3; i++) {
1324  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1325  }
1326 
1327  SCFree(p1);
1328  SCFree(p2);
1329  SCFree(p3);
1330  SCFree(reassembled);
1331 
1332  DefragDestroy();
1333  PASS;
1334 }
1335 
1336 /**
1337  * Test the simplest possible re-assembly scenario. All packet in
1338  * order and no overlaps.
1339  */
1340 static int IPV6DefragInOrderSimpleTest(void)
1341 {
1342  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1343  Packet *reassembled = NULL;
1344  int id = 12;
1345  int i;
1346 
1347  DefragInit();
1348 
1349  p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1350  FAIL_IF_NULL(p1);
1351  p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1352  FAIL_IF_NULL(p2);
1353  p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1354  FAIL_IF_NULL(p3);
1355 
1356  FAIL_IF(Defrag(NULL, NULL, p1) != NULL);
1357  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1358  reassembled = Defrag(NULL, NULL, p3);
1359  FAIL_IF_NULL(reassembled);
1360 
1361  FAIL_IF(IPV6_GET_PLEN(reassembled) != 19);
1362 
1363  /* 40 bytes in we should find 8 bytes of A. */
1364  for (i = 40; i < 40 + 8; i++) {
1365  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1366  }
1367 
1368  /* 28 bytes in we should find 8 bytes of B. */
1369  for (i = 48; i < 48 + 8; i++) {
1370  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1371  }
1372 
1373  /* And 36 bytes in we should find 3 bytes of C. */
1374  for (i = 56; i < 56 + 3; i++) {
1375  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1376  }
1377 
1378  SCFree(p1);
1379  SCFree(p2);
1380  SCFree(p3);
1381  SCFree(reassembled);
1382 
1383  DefragDestroy();
1384  PASS;
1385 }
1386 
1387 static int IPV6DefragReverseSimpleTest(void)
1388 {
1389  DefragContext *dc = NULL;
1390  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
1391  Packet *reassembled = NULL;
1392  int id = 12;
1393  int i;
1394 
1395  DefragInit();
1396 
1397  dc = DefragContextNew();
1398  FAIL_IF_NULL(dc);
1399 
1400  p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 8);
1401  FAIL_IF_NULL(p1);
1402  p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 1, 1, 'B', 8);
1403  FAIL_IF_NULL(p2);
1404  p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 2, 0, 'C', 3);
1405  FAIL_IF_NULL(p3);
1406 
1407  FAIL_IF(Defrag(NULL, NULL, p3) != NULL);
1408  FAIL_IF(Defrag(NULL, NULL, p2) != NULL);
1409  reassembled = Defrag(NULL, NULL, p1);
1410  FAIL_IF_NULL(reassembled);
1411 
1412  /* 40 bytes in we should find 8 bytes of A. */
1413  for (i = 40; i < 40 + 8; i++) {
1414  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'A');
1415  }
1416 
1417  /* 28 bytes in we should find 8 bytes of B. */
1418  for (i = 48; i < 48 + 8; i++) {
1419  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'B');
1420  }
1421 
1422  /* And 36 bytes in we should find 3 bytes of C. */
1423  for (i = 56; i < 56 + 3; i++) {
1424  FAIL_IF(GET_PKT_DATA(reassembled)[i] != 'C');
1425  }
1426 
1427  DefragContextDestroy(dc);
1428  SCFree(p1);
1429  SCFree(p2);
1430  SCFree(p3);
1431  SCFree(reassembled);
1432 
1433  DefragDestroy();
1434  PASS;
1435 }
1436 
1437 static int DefragDoSturgesNovakTest(int policy, u_char *expected,
1438  size_t expected_len)
1439 {
1440  int i;
1441 
1442  DefragInit();
1443 
1444  /*
1445  * Build the packets.
1446  */
1447 
1448  int id = 1;
1449  Packet *packets[17];
1450  memset(packets, 0x00, sizeof(packets));
1451 
1452  /*
1453  * Original fragments.
1454  */
1455 
1456  /* A*24 at 0. */
1457  packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
1458 
1459  /* B*15 at 32. */
1460  packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 32 >> 3, 1, 'B', 16);
1461 
1462  /* C*24 at 48. */
1463  packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'C', 24);
1464 
1465  /* D*8 at 80. */
1466  packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 80 >> 3, 1, 'D', 8);
1467 
1468  /* E*16 at 104. */
1469  packets[4] = BuildTestPacket(IPPROTO_ICMP, id, 104 >> 3, 1, 'E', 16);
1470 
1471  /* F*24 at 120. */
1472  packets[5] = BuildTestPacket(IPPROTO_ICMP, id, 120 >> 3, 1, 'F', 24);
1473 
1474  /* G*16 at 144. */
1475  packets[6] = BuildTestPacket(IPPROTO_ICMP, id, 144 >> 3, 1, 'G', 16);
1476 
1477  /* H*16 at 160. */
1478  packets[7] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'H', 16);
1479 
1480  /* I*8 at 176. */
1481  packets[8] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 1, 'I', 8);
1482 
1483  /*
1484  * Overlapping subsequent fragments.
1485  */
1486 
1487  /* J*32 at 8. */
1488  packets[9] = BuildTestPacket(IPPROTO_ICMP, id, 8 >> 3, 1, 'J', 32);
1489 
1490  /* K*24 at 48. */
1491  packets[10] = BuildTestPacket(IPPROTO_ICMP, id, 48 >> 3, 1, 'K', 24);
1492 
1493  /* L*24 at 72. */
1494  packets[11] = BuildTestPacket(IPPROTO_ICMP, id, 72 >> 3, 1, 'L', 24);
1495 
1496  /* M*24 at 96. */
1497  packets[12] = BuildTestPacket(IPPROTO_ICMP, id, 96 >> 3, 1, 'M', 24);
1498 
1499  /* N*8 at 128. */
1500  packets[13] = BuildTestPacket(IPPROTO_ICMP, id, 128 >> 3, 1, 'N', 8);
1501 
1502  /* O*8 at 152. */
1503  packets[14] = BuildTestPacket(IPPROTO_ICMP, id, 152 >> 3, 1, 'O', 8);
1504 
1505  /* P*8 at 160. */
1506  packets[15] = BuildTestPacket(IPPROTO_ICMP, id, 160 >> 3, 1, 'P', 8);
1507 
1508  /* Q*16 at 176. */
1509  packets[16] = BuildTestPacket(IPPROTO_ICMP, id, 176 >> 3, 0, 'Q', 16);
1510 
1511  default_policy = policy;
1512 
1513  /* Send all but the last. */
1514  for (i = 0; i < 9; i++) {
1515  Packet *tp = Defrag(NULL, NULL, packets[i]);
1516  FAIL_IF_NOT_NULL(tp);
1518  }
1519  int overlap = 0;
1520  for (; i < 16; i++) {
1521  Packet *tp = Defrag(NULL, NULL, packets[i]);
1522  FAIL_IF_NOT_NULL(tp);
1523  if (ENGINE_ISSET_EVENT(packets[i], IPV4_FRAG_OVERLAP)) {
1524  overlap++;
1525  }
1526  }
1527  FAIL_IF_NOT(overlap);
1528 
1529  /* And now the last one. */
1530  Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1531  FAIL_IF_NULL(reassembled);
1532 
1533  FAIL_IF(IPV4_GET_HLEN(reassembled) != 20);
1534  FAIL_IF(IPV4_GET_IPLEN(reassembled) != 20 + 192);
1535 
1536  FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 20, expected, expected_len) != 0);
1537  SCFree(reassembled);
1538 
1539  /* Make sure all frags were returned back to the pool. */
1540  FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1541 
1542  for (i = 0; i < 17; i++) {
1543  SCFree(packets[i]);
1544  }
1545  DefragDestroy();
1546  PASS;
1547 }
1548 
1549 static int IPV6DefragDoSturgesNovakTest(int policy, u_char *expected,
1550  size_t expected_len)
1551 {
1552  int i;
1553 
1554  DefragInit();
1555 
1556  /*
1557  * Build the packets.
1558  */
1559 
1560  int id = 1;
1561  Packet *packets[17];
1562  memset(packets, 0x00, sizeof(packets));
1563 
1564  /*
1565  * Original fragments.
1566  */
1567 
1568  /* A*24 at 0. */
1569  packets[0] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 0, 1, 'A', 24);
1570 
1571  /* B*15 at 32. */
1572  packets[1] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 32 >> 3, 1, 'B', 16);
1573 
1574  /* C*24 at 48. */
1575  packets[2] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'C', 24);
1576 
1577  /* D*8 at 80. */
1578  packets[3] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 80 >> 3, 1, 'D', 8);
1579 
1580  /* E*16 at 104. */
1581  packets[4] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 104 >> 3, 1, 'E', 16);
1582 
1583  /* F*24 at 120. */
1584  packets[5] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 120 >> 3, 1, 'F', 24);
1585 
1586  /* G*16 at 144. */
1587  packets[6] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 144 >> 3, 1, 'G', 16);
1588 
1589  /* H*16 at 160. */
1590  packets[7] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'H', 16);
1591 
1592  /* I*8 at 176. */
1593  packets[8] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 1, 'I', 8);
1594 
1595  /*
1596  * Overlapping subsequent fragments.
1597  */
1598 
1599  /* J*32 at 8. */
1600  packets[9] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 8 >> 3, 1, 'J', 32);
1601 
1602  /* K*24 at 48. */
1603  packets[10] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 48 >> 3, 1, 'K', 24);
1604 
1605  /* L*24 at 72. */
1606  packets[11] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 72 >> 3, 1, 'L', 24);
1607 
1608  /* M*24 at 96. */
1609  packets[12] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 96 >> 3, 1, 'M', 24);
1610 
1611  /* N*8 at 128. */
1612  packets[13] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 128 >> 3, 1, 'N', 8);
1613 
1614  /* O*8 at 152. */
1615  packets[14] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 152 >> 3, 1, 'O', 8);
1616 
1617  /* P*8 at 160. */
1618  packets[15] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 160 >> 3, 1, 'P', 8);
1619 
1620  /* Q*16 at 176. */
1621  packets[16] = IPV6BuildTestPacket(IPPROTO_ICMPV6, id, 176 >> 3, 0, 'Q', 16);
1622 
1623  default_policy = policy;
1624 
1625  /* Send all but the last. */
1626  for (i = 0; i < 9; i++) {
1627  Packet *tp = Defrag(NULL, NULL, packets[i]);
1628  FAIL_IF_NOT_NULL(tp);
1630  }
1631  int overlap = 0;
1632  for (; i < 16; i++) {
1633  Packet *tp = Defrag(NULL, NULL, packets[i]);
1634  FAIL_IF_NOT_NULL(tp);
1635  if (ENGINE_ISSET_EVENT(packets[i], IPV6_FRAG_OVERLAP)) {
1636  overlap++;
1637  }
1638  }
1639  FAIL_IF_NOT(overlap);
1640 
1641  /* And now the last one. */
1642  Packet *reassembled = Defrag(NULL, NULL, packets[16]);
1643  FAIL_IF_NULL(reassembled);
1644  FAIL_IF(memcmp(GET_PKT_DATA(reassembled) + 40, expected, expected_len) != 0);
1645 
1646  FAIL_IF(IPV6_GET_PLEN(reassembled) != 192);
1647 
1648  SCFree(reassembled);
1649 
1650  /* Make sure all frags were returned to the pool. */
1651  FAIL_IF(defrag_context->frag_pool->outstanding != 0);
1652 
1653  for (i = 0; i < 17; i++) {
1654  SCFree(packets[i]);
1655  }
1656  DefragDestroy();
1657  PASS;
1658 }
1659 
1660 static int
1661 DefragSturgesNovakBsdTest(void)
1662 {
1663  /* Expected data. */
1664  u_char expected[] = {
1665  "AAAAAAAA"
1666  "AAAAAAAA"
1667  "AAAAAAAA"
1668  "JJJJJJJJ"
1669  "JJJJJJJJ"
1670  "BBBBBBBB"
1671  "CCCCCCCC"
1672  "CCCCCCCC"
1673  "CCCCCCCC"
1674  "LLLLLLLL"
1675  "LLLLLLLL"
1676  "LLLLLLLL"
1677  "MMMMMMMM"
1678  "MMMMMMMM"
1679  "MMMMMMMM"
1680  "FFFFFFFF"
1681  "FFFFFFFF"
1682  "FFFFFFFF"
1683  "GGGGGGGG"
1684  "GGGGGGGG"
1685  "HHHHHHHH"
1686  "HHHHHHHH"
1687  "IIIIIIII"
1688  "QQQQQQQQ"
1689  };
1690 
1691  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1692  sizeof(expected)));
1693  PASS;
1694 }
1695 
1696 static int IPV6DefragSturgesNovakBsdTest(void)
1697 {
1698  /* Expected data. */
1699  u_char expected[] = {
1700  "AAAAAAAA"
1701  "AAAAAAAA"
1702  "AAAAAAAA"
1703  "JJJJJJJJ"
1704  "JJJJJJJJ"
1705  "BBBBBBBB"
1706  "CCCCCCCC"
1707  "CCCCCCCC"
1708  "CCCCCCCC"
1709  "LLLLLLLL"
1710  "LLLLLLLL"
1711  "LLLLLLLL"
1712  "MMMMMMMM"
1713  "MMMMMMMM"
1714  "MMMMMMMM"
1715  "FFFFFFFF"
1716  "FFFFFFFF"
1717  "FFFFFFFF"
1718  "GGGGGGGG"
1719  "GGGGGGGG"
1720  "HHHHHHHH"
1721  "HHHHHHHH"
1722  "IIIIIIII"
1723  "QQQQQQQQ"
1724  };
1725 
1726  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_BSD, expected,
1727  sizeof(expected)));
1728  PASS;
1729 }
1730 
1731 static int DefragSturgesNovakLinuxIpv4Test(void)
1732 {
1733  /* Expected data. */
1734  u_char expected[] = {
1735  "AAAAAAAA"
1736  "AAAAAAAA"
1737  "AAAAAAAA"
1738  "JJJJJJJJ"
1739  "JJJJJJJJ"
1740  "BBBBBBBB"
1741  "KKKKKKKK"
1742  "KKKKKKKK"
1743  "KKKKKKKK"
1744  "LLLLLLLL"
1745  "LLLLLLLL"
1746  "LLLLLLLL"
1747  "MMMMMMMM"
1748  "MMMMMMMM"
1749  "MMMMMMMM"
1750  "FFFFFFFF"
1751  "FFFFFFFF"
1752  "FFFFFFFF"
1753  "GGGGGGGG"
1754  "GGGGGGGG"
1755  "PPPPPPPP"
1756  "HHHHHHHH"
1757  "QQQQQQQQ"
1758  "QQQQQQQQ"
1759  };
1760 
1761  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1762  sizeof(expected)));
1763  PASS;
1764 }
1765 
1766 static int IPV6DefragSturgesNovakLinuxTest(void)
1767 {
1768  /* Expected data. */
1769  u_char expected[] = {
1770  "AAAAAAAA"
1771  "AAAAAAAA"
1772  "AAAAAAAA"
1773  "JJJJJJJJ"
1774  "JJJJJJJJ"
1775  "BBBBBBBB"
1776  "KKKKKKKK"
1777  "KKKKKKKK"
1778  "KKKKKKKK"
1779  "LLLLLLLL"
1780  "LLLLLLLL"
1781  "LLLLLLLL"
1782  "MMMMMMMM"
1783  "MMMMMMMM"
1784  "MMMMMMMM"
1785  "FFFFFFFF"
1786  "FFFFFFFF"
1787  "FFFFFFFF"
1788  "GGGGGGGG"
1789  "GGGGGGGG"
1790  "PPPPPPPP"
1791  "HHHHHHHH"
1792  "QQQQQQQQ"
1793  "QQQQQQQQ"
1794  };
1795 
1796  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LINUX, expected,
1797  sizeof(expected)));
1798  PASS;
1799 }
1800 
1801 static int DefragSturgesNovakWindowsIpv4Test(void)
1802 {
1803  /* Expected data. */
1804  u_char expected[] = {
1805  "AAAAAAAA"
1806  "AAAAAAAA"
1807  "AAAAAAAA"
1808  "JJJJJJJJ"
1809  "BBBBBBBB"
1810  "BBBBBBBB"
1811  "CCCCCCCC"
1812  "CCCCCCCC"
1813  "CCCCCCCC"
1814  "LLLLLLLL"
1815  "LLLLLLLL"
1816  "LLLLLLLL"
1817  "MMMMMMMM"
1818  "EEEEEEEE"
1819  "EEEEEEEE"
1820  "FFFFFFFF"
1821  "FFFFFFFF"
1822  "FFFFFFFF"
1823  "GGGGGGGG"
1824  "GGGGGGGG"
1825  "HHHHHHHH"
1826  "HHHHHHHH"
1827  "IIIIIIII"
1828  "QQQQQQQQ"
1829  };
1830 
1831  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
1832  sizeof(expected)));
1833  PASS;
1834 }
1835 
1836 static int IPV6DefragSturgesNovakWindowsTest(void)
1837 {
1838  /* Expected data. */
1839  u_char expected[] = {
1840  "AAAAAAAA"
1841  "AAAAAAAA"
1842  "AAAAAAAA"
1843  "JJJJJJJJ"
1844  "BBBBBBBB"
1845  "BBBBBBBB"
1846  "CCCCCCCC"
1847  "CCCCCCCC"
1848  "CCCCCCCC"
1849  "LLLLLLLL"
1850  "LLLLLLLL"
1851  "LLLLLLLL"
1852  "MMMMMMMM"
1853  "EEEEEEEE"
1854  "EEEEEEEE"
1855  "FFFFFFFF"
1856  "FFFFFFFF"
1857  "FFFFFFFF"
1858  "GGGGGGGG"
1859  "GGGGGGGG"
1860  "HHHHHHHH"
1861  "HHHHHHHH"
1862  "IIIIIIII"
1863  "QQQQQQQQ"
1864  };
1865 
1866  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_WINDOWS, expected,
1867  sizeof(expected)));
1868  PASS;
1869 }
1870 
1871 static int DefragSturgesNovakSolarisTest(void)
1872 {
1873  /* Expected data. */
1874  u_char expected[] = {
1875  "AAAAAAAA"
1876  "AAAAAAAA"
1877  "AAAAAAAA"
1878  "JJJJJJJJ"
1879  "BBBBBBBB"
1880  "BBBBBBBB"
1881  "CCCCCCCC"
1882  "CCCCCCCC"
1883  "CCCCCCCC"
1884  "LLLLLLLL"
1885  "LLLLLLLL"
1886  "LLLLLLLL"
1887  "MMMMMMMM"
1888  "MMMMMMMM"
1889  "MMMMMMMM"
1890  "FFFFFFFF"
1891  "FFFFFFFF"
1892  "FFFFFFFF"
1893  "GGGGGGGG"
1894  "GGGGGGGG"
1895  "HHHHHHHH"
1896  "HHHHHHHH"
1897  "IIIIIIII"
1898  "QQQQQQQQ"
1899  };
1900 
1901  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
1902  sizeof(expected)));
1903  PASS;
1904 }
1905 
1906 static int IPV6DefragSturgesNovakSolarisTest(void)
1907 {
1908  /* Expected data. */
1909  u_char expected[] = {
1910  "AAAAAAAA"
1911  "AAAAAAAA"
1912  "AAAAAAAA"
1913  "JJJJJJJJ"
1914  "BBBBBBBB"
1915  "BBBBBBBB"
1916  "CCCCCCCC"
1917  "CCCCCCCC"
1918  "CCCCCCCC"
1919  "LLLLLLLL"
1920  "LLLLLLLL"
1921  "LLLLLLLL"
1922  "MMMMMMMM"
1923  "MMMMMMMM"
1924  "MMMMMMMM"
1925  "FFFFFFFF"
1926  "FFFFFFFF"
1927  "FFFFFFFF"
1928  "GGGGGGGG"
1929  "GGGGGGGG"
1930  "HHHHHHHH"
1931  "HHHHHHHH"
1932  "IIIIIIII"
1933  "QQQQQQQQ"
1934  };
1935 
1936  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_SOLARIS, expected,
1937  sizeof(expected)));
1938  PASS;
1939 }
1940 
1941 static int DefragSturgesNovakFirstTest(void)
1942 {
1943  /* Expected data. */
1944  u_char expected[] = {
1945  "AAAAAAAA"
1946  "AAAAAAAA"
1947  "AAAAAAAA"
1948  "JJJJJJJJ"
1949  "BBBBBBBB"
1950  "BBBBBBBB"
1951  "CCCCCCCC"
1952  "CCCCCCCC"
1953  "CCCCCCCC"
1954  "LLLLLLLL"
1955  "DDDDDDDD"
1956  "LLLLLLLL"
1957  "MMMMMMMM"
1958  "EEEEEEEE"
1959  "EEEEEEEE"
1960  "FFFFFFFF"
1961  "FFFFFFFF"
1962  "FFFFFFFF"
1963  "GGGGGGGG"
1964  "GGGGGGGG"
1965  "HHHHHHHH"
1966  "HHHHHHHH"
1967  "IIIIIIII"
1968  "QQQQQQQQ"
1969  };
1970 
1971  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
1972  sizeof(expected)));
1973  PASS;
1974 }
1975 
1976 static int IPV6DefragSturgesNovakFirstTest(void)
1977 {
1978  /* Expected data. */
1979  u_char expected[] = {
1980  "AAAAAAAA"
1981  "AAAAAAAA"
1982  "AAAAAAAA"
1983  "JJJJJJJJ"
1984  "BBBBBBBB"
1985  "BBBBBBBB"
1986  "CCCCCCCC"
1987  "CCCCCCCC"
1988  "CCCCCCCC"
1989  "LLLLLLLL"
1990  "DDDDDDDD"
1991  "LLLLLLLL"
1992  "MMMMMMMM"
1993  "EEEEEEEE"
1994  "EEEEEEEE"
1995  "FFFFFFFF"
1996  "FFFFFFFF"
1997  "FFFFFFFF"
1998  "GGGGGGGG"
1999  "GGGGGGGG"
2000  "HHHHHHHH"
2001  "HHHHHHHH"
2002  "IIIIIIII"
2003  "QQQQQQQQ"
2004  };
2005 
2006  return IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_FIRST, expected,
2007  sizeof(expected));
2008 }
2009 
2010 static int
2011 DefragSturgesNovakLastTest(void)
2012 {
2013  /* Expected data. */
2014  u_char expected[] = {
2015  "AAAAAAAA"
2016  "JJJJJJJJ"
2017  "JJJJJJJJ"
2018  "JJJJJJJJ"
2019  "JJJJJJJJ"
2020  "BBBBBBBB"
2021  "KKKKKKKK"
2022  "KKKKKKKK"
2023  "KKKKKKKK"
2024  "LLLLLLLL"
2025  "LLLLLLLL"
2026  "LLLLLLLL"
2027  "MMMMMMMM"
2028  "MMMMMMMM"
2029  "MMMMMMMM"
2030  "FFFFFFFF"
2031  "NNNNNNNN"
2032  "FFFFFFFF"
2033  "GGGGGGGG"
2034  "OOOOOOOO"
2035  "PPPPPPPP"
2036  "HHHHHHHH"
2037  "QQQQQQQQ"
2038  "QQQQQQQQ"
2039  };
2040 
2041  FAIL_IF_NOT(DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2042  sizeof(expected)));
2043  PASS;
2044 }
2045 
2046 static int IPV6DefragSturgesNovakLastTest(void)
2047 {
2048  /* Expected data. */
2049  u_char expected[] = {
2050  "AAAAAAAA"
2051  "JJJJJJJJ"
2052  "JJJJJJJJ"
2053  "JJJJJJJJ"
2054  "JJJJJJJJ"
2055  "BBBBBBBB"
2056  "KKKKKKKK"
2057  "KKKKKKKK"
2058  "KKKKKKKK"
2059  "LLLLLLLL"
2060  "LLLLLLLL"
2061  "LLLLLLLL"
2062  "MMMMMMMM"
2063  "MMMMMMMM"
2064  "MMMMMMMM"
2065  "FFFFFFFF"
2066  "NNNNNNNN"
2067  "FFFFFFFF"
2068  "GGGGGGGG"
2069  "OOOOOOOO"
2070  "PPPPPPPP"
2071  "HHHHHHHH"
2072  "QQQQQQQQ"
2073  "QQQQQQQQ"
2074  };
2075 
2076  FAIL_IF_NOT(IPV6DefragDoSturgesNovakTest(DEFRAG_POLICY_LAST, expected,
2077  sizeof(expected)));
2078  PASS;
2079 }
2080 
2081 static int DefragTimeoutTest(void)
2082 {
2083  int i;
2084 
2085  /* Setup a small numberr of trackers. */
2086  FAIL_IF_NOT(ConfSet("defrag.trackers", "16"));
2087 
2088  DefragInit();
2089 
2090  /* Load in 16 packets. */
2091  for (i = 0; i < 16; i++) {
2092  Packet *p = BuildTestPacket(IPPROTO_ICMP,i, 0, 1, 'A' + i, 16);
2093  FAIL_IF_NULL(p);
2094 
2095  Packet *tp = Defrag(NULL, NULL, p);
2096  SCFree(p);
2097  FAIL_IF_NOT_NULL(tp);
2098  }
2099 
2100  /* Build a new packet but push the timestamp out by our timeout.
2101  * This should force our previous fragments to be timed out. */
2102  Packet *p = BuildTestPacket(IPPROTO_ICMP, 99, 0, 1, 'A' + i, 16);
2103  FAIL_IF_NULL(p);
2104 
2105  p->ts.tv_sec += (defrag_context->timeout + 1);
2106  Packet *tp = Defrag(NULL, NULL, p);
2107  FAIL_IF_NOT_NULL(tp);
2108 
2110  FAIL_IF_NULL(tracker);
2111 
2112  FAIL_IF(tracker->id != 99);
2113 
2114  SCMutexUnlock(&tracker->lock);
2115  SCFree(p);
2116 
2117  DefragDestroy();
2118  PASS;
2119 }
2120 
2121 /**
2122  * QA found that if you send a packet where more frags is 0, offset is
2123  * > 0 and there is no data in the packet that the re-assembler will
2124  * fail. The fix was simple, but this unit test is just to make sure
2125  * its not introduced.
2126  */
2127 static int DefragIPv4NoDataTest(void)
2128 {
2129  DefragContext *dc = NULL;
2130  Packet *p = NULL;
2131  int id = 12;
2132 
2133  DefragInit();
2134 
2135  dc = DefragContextNew();
2136  FAIL_IF_NULL(dc);
2137 
2138  /* This packet has an offset > 0, more frags set to 0 and no data. */
2139  p = BuildTestPacket(IPPROTO_ICMP, id, 1, 0, 'A', 0);
2140  FAIL_IF_NULL(p);
2141 
2142  /* We do not expect a packet returned. */
2143  FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2144 
2145  /* The fragment should have been ignored so no fragments should
2146  * have been allocated from the pool. */
2147  FAIL_IF(dc->frag_pool->outstanding != 0);
2148 
2149  DefragContextDestroy(dc);
2150  SCFree(p);
2151 
2152  DefragDestroy();
2153  PASS;
2154 }
2155 
2156 static int DefragIPv4TooLargeTest(void)
2157 {
2158  DefragContext *dc = NULL;
2159  Packet *p = NULL;
2160 
2161  DefragInit();
2162 
2163  dc = DefragContextNew();
2164  FAIL_IF_NULL(dc);
2165 
2166  /* Create a fragment that would extend past the max allowable size
2167  * for an IPv4 packet. */
2168  p = BuildTestPacket(IPPROTO_ICMP, 1, 8183, 0, 'A', 71);
2169  FAIL_IF_NULL(p);
2170 
2171  /* We do not expect a packet returned. */
2172  FAIL_IF(Defrag(NULL, NULL, p) != NULL);
2173 
2174  /* We do expect an event. */
2176 
2177  /* The fragment should have been ignored so no fragments should have
2178  * been allocated from the pool. */
2179  FAIL_IF(dc->frag_pool->outstanding != 0);
2180 
2181  DefragContextDestroy(dc);
2182  SCFree(p);
2183 
2184  DefragDestroy();
2185  PASS;
2186 }
2187 
2188 /**
2189  * Test that fragments in different VLANs that would otherwise be
2190  * re-assembled, are not re-assembled. Just use simple in-order
2191  * fragments.
2192  */
2193 static int DefragVlanTest(void)
2194 {
2195  Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2196 
2197  DefragInit();
2198 
2199  p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2200  FAIL_IF_NULL(p1);
2201  p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2202  FAIL_IF_NULL(p2);
2203 
2204  /* With no VLAN IDs set, packets should re-assemble. */
2205  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2206  FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2207  SCFree(r);
2208 
2209  /* With mismatched VLANs, packets should not re-assemble. */
2210  p1->vlan_id[0] = 1;
2211  p2->vlan_id[0] = 2;
2212  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2213  FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2214 
2215  SCFree(p1);
2216  SCFree(p2);
2217  DefragDestroy();
2218 
2219  PASS;
2220 }
2221 
2222 /**
2223  * Like DefragVlanTest, but for QinQ, testing the second level VLAN ID.
2224  */
2225 static int DefragVlanQinQTest(void)
2226 {
2227  Packet *p1 = NULL, *p2 = NULL, *r = NULL;
2228 
2229  DefragInit();
2230 
2231  p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8);
2232  FAIL_IF_NULL(p1);
2233  p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8);
2234  FAIL_IF_NULL(p2);
2235 
2236  /* With no VLAN IDs set, packets should re-assemble. */
2237  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2238  FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL);
2239  SCFree(r);
2240 
2241  /* With mismatched VLANs, packets should not re-assemble. */
2242  p1->vlan_id[0] = 1;
2243  p2->vlan_id[0] = 1;
2244  p1->vlan_id[1] = 1;
2245  p2->vlan_id[1] = 2;
2246  FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL);
2247  FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL);
2248 
2249  SCFree(p1);
2250  SCFree(p2);
2251  DefragDestroy();
2252 
2253  PASS;
2254 }
2255 
2256 static int DefragTrackerReuseTest(void)
2257 {
2258  int id = 1;
2259  Packet *p1 = NULL;
2260  DefragTracker *tracker1 = NULL, *tracker2 = NULL;
2261 
2262  DefragInit();
2263 
2264  /* Build a packet, its not a fragment but shouldn't matter for
2265  * this test. */
2266  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 0, 'A', 8);
2267  FAIL_IF_NULL(p1);
2268 
2269  /* Get a tracker. It shouldn't look like its already in use. */
2270  tracker1 = DefragGetTracker(NULL, NULL, p1);
2271  FAIL_IF_NULL(tracker1);
2272  FAIL_IF(tracker1->seen_last);
2273  FAIL_IF(tracker1->remove);
2274  DefragTrackerRelease(tracker1);
2275 
2276  /* Get a tracker again, it should be the same one. */
2277  tracker2 = DefragGetTracker(NULL, NULL, p1);
2278  FAIL_IF_NULL(tracker2);
2279  FAIL_IF(tracker2 != tracker1);
2280  DefragTrackerRelease(tracker1);
2281 
2282  /* Now mark the tracker for removal. It should not be returned
2283  * when we get a tracker for a packet that may have the same
2284  * attributes. */
2285  tracker1->remove = 1;
2286 
2287  tracker2 = DefragGetTracker(NULL, NULL, p1);
2288  FAIL_IF_NULL(tracker2);
2289  FAIL_IF(tracker2 == tracker1);
2290  FAIL_IF(tracker2->remove);
2291 
2292  SCFree(p1);
2293  DefragDestroy();
2294  PASS;
2295 }
2296 
2297 /**
2298  * IPV4: Test the case where you have a packet fragmented in 3 parts
2299  * and send like:
2300  * - Offset: 2; MF: 1
2301  * - Offset: 0; MF: 1
2302  * - Offset: 1; MF: 0
2303  *
2304  * Only the fragments with offset 0 and 1 should be reassembled.
2305  */
2306 static int DefragMfIpv4Test(void)
2307 {
2308  int ip_id = 9;
2309  Packet *p = NULL;
2310 
2311  DefragInit();
2312 
2313  Packet *p1 = BuildTestPacket(IPPROTO_ICMP, ip_id, 2, 1, 'C', 8);
2314  Packet *p2 = BuildTestPacket(IPPROTO_ICMP, ip_id, 0, 1, 'A', 8);
2315  Packet *p3 = BuildTestPacket(IPPROTO_ICMP, ip_id, 1, 0, 'B', 8);
2316  FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2317 
2318  p = Defrag(NULL, NULL, p1);
2319  FAIL_IF_NOT_NULL(p);
2320 
2321  p = Defrag(NULL, NULL, p2);
2322  FAIL_IF_NOT_NULL(p);
2323 
2324  /* This should return a packet as MF=0. */
2325  p = Defrag(NULL, NULL, p3);
2326  FAIL_IF_NULL(p);
2327 
2328  /* Expected IP length is 20 + 8 + 8 = 36 as only 2 of the
2329  * fragments should be in the re-assembled packet. */
2330  FAIL_IF(IPV4_GET_IPLEN(p) != 36);
2331 
2332  SCFree(p1);
2333  SCFree(p2);
2334  SCFree(p3);
2335  SCFree(p);
2336  DefragDestroy();
2337  PASS;
2338 }
2339 
2340 /**
2341  * IPV6: Test the case where you have a packet fragmented in 3 parts
2342  * and send like:
2343  * - Offset: 2; MF: 1
2344  * - Offset: 0; MF: 1
2345  * - Offset: 1; MF: 0
2346  *
2347  * Only the fragments with offset 0 and 1 should be reassembled.
2348  */
2349 static int DefragMfIpv6Test(void)
2350 {
2351  int ip_id = 9;
2352  Packet *p = NULL;
2353 
2354  DefragInit();
2355 
2356  Packet *p1 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 2, 1, 'C', 8);
2357  Packet *p2 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 0, 1, 'A', 8);
2358  Packet *p3 = IPV6BuildTestPacket(IPPROTO_ICMPV6, ip_id, 1, 0, 'B', 8);
2359  FAIL_IF(p1 == NULL || p2 == NULL || p3 == NULL);
2360 
2361  p = Defrag(NULL, NULL, p1);
2362  FAIL_IF_NOT_NULL(p);
2363 
2364  p = Defrag(NULL, NULL, p2);
2365  FAIL_IF_NOT_NULL(p);
2366 
2367  /* This should return a packet as MF=0. */
2368  p = Defrag(NULL, NULL, p3);
2369  FAIL_IF_NULL(p);
2370 
2371  /* For IPv6 the expected length is just the length of the payload
2372  * of 2 fragments, so 16. */
2373  FAIL_IF(IPV6_GET_PLEN(p) != 16);
2374 
2375  SCFree(p1);
2376  SCFree(p2);
2377  SCFree(p3);
2378  SCFree(p);
2379  DefragDestroy();
2380  PASS;
2381 }
2382 
2383 /**
2384  * \brief Test that fragments that match other than the proto don't
2385  * actually get matched.
2386  */
2387 static int DefragTestBadProto(void)
2388 {
2389  Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
2390  int id = 12;
2391 
2392  DefragInit();
2393 
2394  p1 = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 8);
2395  FAIL_IF_NULL(p1);
2396  p2 = BuildTestPacket(IPPROTO_UDP, id, 1, 1, 'B', 8);
2397  FAIL_IF_NULL(p2);
2398  p3 = BuildTestPacket(IPPROTO_ICMP, id, 2, 0, 'C', 3);
2399  FAIL_IF_NULL(p3);
2400 
2401  FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p1));
2402  FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p2));
2403  FAIL_IF_NOT_NULL(Defrag(NULL, NULL, p3));
2404 
2405  SCFree(p1);
2406  SCFree(p2);
2407  SCFree(p3);
2408 
2409  DefragDestroy();
2410  PASS;
2411 }
2412 
2413 /**
2414  * \test Test a report Linux overlap issue that doesn't appear to be
2415  * covered by the Sturges/Novak tests above.
2416  */
2417 static int DefragTestJeremyLinux(void)
2418 {
2419  char expected[] = "AAAAAAAA"
2420  "AAAAAAAA"
2421  "AAAAAAAA"
2422  "CCCCCCCC"
2423  "CCCCCCCC"
2424  "CCCCCCCC"
2425  "CCCCCCCC"
2426  "CCCCCCCC"
2427  "CCCCCCCC"
2428  "BBBBBBBB"
2429  "BBBBBBBB"
2430  "DDDDDDDD"
2431  "DDDDDD";
2432 
2433  DefragInit();
2434  default_policy = DEFRAG_POLICY_LINUX;
2435 
2436  int id = 1;
2437  Packet *packets[4];
2438  int i = 0;
2439 
2440  packets[0] = BuildTestPacket(IPPROTO_ICMP, id, 0, 1, 'A', 24);
2441  packets[1] = BuildTestPacket(IPPROTO_ICMP, id, 40 >> 3, 1, 'B', 48);
2442  packets[2] = BuildTestPacket(IPPROTO_ICMP, id, 24 >> 3, 1, 'C', 48);
2443  packets[3] = BuildTestPacket(IPPROTO_ICMP, id, 88 >> 3, 0, 'D', 14);
2444 
2445  Packet *r = Defrag(NULL, NULL, packets[0]);
2446  FAIL_IF_NOT_NULL(r);
2447 
2448  r = Defrag(NULL, NULL, packets[1]);
2449  FAIL_IF_NOT_NULL(r);
2450 
2451  r = Defrag(NULL, NULL, packets[2]);
2452  FAIL_IF_NOT_NULL(r);
2453 
2454  r = Defrag(NULL, NULL, packets[3]);
2455  FAIL_IF_NULL(r);
2456 
2457  FAIL_IF(memcmp(expected, GET_PKT_DATA(r) + 20, sizeof(expected)) != 0);
2458 
2459  for (i = 0; i < 4; i++) {
2460  SCFree(packets[i]);
2461  }
2462  SCFree(r);
2463 
2464  DefragDestroy();
2465  PASS;
2466 }
2467 
2468 #endif /* UNITTESTS */
2469 
2471 {
2472 #ifdef UNITTESTS
2473  UtRegisterTest("DefragInOrderSimpleTest", DefragInOrderSimpleTest);
2474  UtRegisterTest("DefragReverseSimpleTest", DefragReverseSimpleTest);
2475  UtRegisterTest("DefragSturgesNovakBsdTest", DefragSturgesNovakBsdTest);
2476  UtRegisterTest("DefragSturgesNovakLinuxIpv4Test",
2477  DefragSturgesNovakLinuxIpv4Test);
2478  UtRegisterTest("DefragSturgesNovakWindowsIpv4Test",
2479  DefragSturgesNovakWindowsIpv4Test);
2480  UtRegisterTest("DefragSturgesNovakSolarisTest",
2481  DefragSturgesNovakSolarisTest);
2482  UtRegisterTest("DefragSturgesNovakFirstTest", DefragSturgesNovakFirstTest);
2483  UtRegisterTest("DefragSturgesNovakLastTest", DefragSturgesNovakLastTest);
2484 
2485  UtRegisterTest("DefragIPv4NoDataTest", DefragIPv4NoDataTest);
2486  UtRegisterTest("DefragIPv4TooLargeTest", DefragIPv4TooLargeTest);
2487 
2488  UtRegisterTest("IPV6DefragInOrderSimpleTest", IPV6DefragInOrderSimpleTest);
2489  UtRegisterTest("IPV6DefragReverseSimpleTest", IPV6DefragReverseSimpleTest);
2490  UtRegisterTest("IPV6DefragSturgesNovakBsdTest",
2491  IPV6DefragSturgesNovakBsdTest);
2492  UtRegisterTest("IPV6DefragSturgesNovakLinuxTest",
2493  IPV6DefragSturgesNovakLinuxTest);
2494  UtRegisterTest("IPV6DefragSturgesNovakWindowsTest",
2495  IPV6DefragSturgesNovakWindowsTest);
2496  UtRegisterTest("IPV6DefragSturgesNovakSolarisTest",
2497  IPV6DefragSturgesNovakSolarisTest);
2498  UtRegisterTest("IPV6DefragSturgesNovakFirstTest",
2499  IPV6DefragSturgesNovakFirstTest);
2500  UtRegisterTest("IPV6DefragSturgesNovakLastTest",
2501  IPV6DefragSturgesNovakLastTest);
2502 
2503  UtRegisterTest("DefragVlanTest", DefragVlanTest);
2504  UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest);
2505  UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest);
2506  UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest);
2507  UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test);
2508  UtRegisterTest("DefragMfIpv6Test", DefragMfIpv6Test);
2509  UtRegisterTest("DefragTestBadProto", DefragTestBadProto);
2510 
2511  UtRegisterTest("DefragTestJeremyLinux", DefragTestJeremyLinux);
2512 #endif /* UNITTESTS */
2513 }
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:1053
DEFAULT_DEFRAG_HASH_SIZE
#define DEFAULT_DEFRAG_HASH_SIZE
Definition: defrag.c:68
Frag_
Definition: defrag.h:43
DEFRAG_POLICY_LINUX
@ DEFRAG_POLICY_LINUX
Definition: defrag.c:93
DefragDestroy
void DefragDestroy(void)
Definition: defrag.c:1075
ConfGetInt
int ConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition: conf.c:392
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:710
DefragTrackerFreeFrags
void DefragTrackerFreeFrags(DefragTracker *tracker)
Free all frags associated with a tracker.
Definition: defrag.c:155
DefragLookupTrackerFromHash
DefragTracker * DefragLookupTrackerFromHash(Packet *p)
look up a tracker in the hash
Definition: defrag-hash.c:634
len
uint8_t len
Definition: app-layer-dnp3.h:2
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
IPV4_FRAG_OVERLAP
@ IPV4_FRAG_OVERLAP
Definition: decode-events.h:170
TIMEOUT_MIN
#define TIMEOUT_MIN
Definition: defrag.c:85
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:78
PacketFreeOrRelease
void PacketFreeOrRelease(Packet *p)
Return a packet to where it was allocated.
Definition: decode.c:197
util-hashlist.h
IPV6_EXTHDR_GET_FH_OFFSET
#define IPV6_EXTHDR_GET_FH_OFFSET(p)
Definition: decode-ipv6.h:128
PacketCopyData
int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Copy data to Packet payload and set packet length.
Definition: decode.c:298
Packet_::vlan_id
uint16_t vlan_id[2]
Definition: decode.h:461
PKT_IS_IPV6
#define PKT_IS_IPV6(p)
Definition: decode.h:254
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:47
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:1068
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:296
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:595
SET_IPV6_DST_ADDR
#define SET_IPV6_DST_ADDR(p, a)
Definition: decode.h:176
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
TIMEOUT_MAX
#define TIMEOUT_MAX
Definition: defrag.c:80
PacketDefragPktSetup
Packet * PacketDefragPktSetup(Packet *parent, const uint8_t *pkt, uint32_t len, uint8_t proto)
Setup a pseudo packet (reassembled frags)
Definition: decode.c:388
Packet_::flags
uint32_t flags
Definition: decode.h:469
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:1084
Frag_::data_len
uint16_t data_len
Definition: defrag.h:60
DefragContext_::timeout
time_t timeout
Definition: defrag.h:37
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
OS_POLICY_BSD
@ OS_POLICY_BSD
Definition: stream-tcp-reassemble.h:39
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:256
IPV4_FRAG_IGNORED
@ IPV4_FRAG_IGNORED
Definition: decode-events.h:175
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:34
PACKET_INITIALIZE
#define PACKET_INITIALIZE(p)
Initialize a packet structure for use.
Definition: decode.h:783
DefragTracker_::host_timeout
uint32_t host_timeout
Definition: defrag.h:107
stream-tcp-reassemble.h
IPV6_FRAG_OVERLAP
@ IPV6_FRAG_OVERLAP
Definition: decode-events.h:171
proto
uint8_t proto
Definition: decode-template.h:0
defrag-config.h
TmqhOutputPacketpool
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
Definition: tmqh-packetpool.c:376
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:222
tmqh-packetpool.h
util-unittest.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:82
DEFRAG_POLICY_LAST
@ DEFRAG_POLICY_LAST
Definition: defrag.c:90
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:141
DefragTracker_::lock
SCMutex lock
Definition: defrag.h:84
IPV6_FRAG_PKT_TOO_LARGE
@ IPV6_FRAG_PKT_TOO_LARGE
Definition: decode-events.h:169
PKT_SET_SRC
#define PKT_SET_SRC(p, src_val)
Definition: decode.h:1225
defrag_policies
defrag_policies
Definition: defrag.c:88
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:50
SET_PKT_LEN
#define SET_PKT_LEN(p, len)
Definition: decode.h:231
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:35
DefragTracker_::remove
uint8_t remove
Definition: defrag.h:101
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:94
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:217
DefragTracker_::seen_last
uint8_t seen_last
Definition: defrag.h:99
DefragTracker_::policy
uint8_t policy
Definition: defrag.h:94
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:101
DefragTracker_
Definition: defrag.h:83
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:227
IPV4_MAXPACKET_LEN
#define IPV4_MAXPACKET_LEN
Definition: decode-ipv4.h:30
DefragRegisterTests
void DefragRegisterTests(void)
Definition: defrag.c:2470
UNSET_TUNNEL_PKT
#define UNSET_TUNNEL_PKT(p)
Definition: decode.h:965
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:56
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
OS_POLICY_HPUX11
@ OS_POLICY_HPUX11
Definition: stream-tcp-reassemble.h:46
SET_IPV6_SRC_ADDR
#define SET_IPV6_SRC_ADDR(p, a)
Definition: decode.h:168
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:48
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
DefragTracker_::timeout
struct timeval timeout
Definition: defrag.h:106
IPV6Hdr_
Definition: decode-ipv6.h:32
Packet_
Definition: decode.h:434
DefragTracker_::id
uint32_t id
Definition: defrag.h:89
DEFRAG_POLICY_FIRST
@ DEFRAG_POLICY_FIRST
Definition: defrag.c:89
DecodeIPV6
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv6.c:572
GET_PKT_LEN
#define GET_PKT_LEN(p)
Definition: decode.h:226
PoolFree
void PoolFree(Pool *p)
Definition: util-pool.c:220
stream-tcp-private.h
OS_POLICY_HPUX10
@ OS_POLICY_HPUX10
Definition: stream-tcp-reassemble.h:45
conf.h
Packet_::ip4h
IPV4Hdr * ip4h
Definition: decode.h:532
Frag_::skip
uint8_t skip
Definition: defrag.h:52
DefragInitConfig
void DefragInitConfig(bool quiet)
initialize the configuration
Definition: defrag-hash.c:167
Frag_::pkt
uint8_t * pkt
Definition: defrag.h:65
Frag_::data_offset
uint16_t data_offset
Definition: defrag.h:59
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:44
DefragTrackerRelease
void DefragTrackerRelease(DefragTracker *t)
Definition: defrag-hash.c:150
SCMutexInit
#define SCMutexInit(mut, mutattrs)
Definition: threads-debug.h:116
DefragContext_
Definition: defrag.h:33
Frag_::ltrim
uint16_t ltrim
Definition: defrag.h:62
util-host-os-info.h
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:32
OS_POLICY_FIRST
@ OS_POLICY_FIRST
Definition: stream-tcp-reassemble.h:52
IPV4Hdr_
Definition: decode-ipv4.h:72
default_packet_size
uint32_t default_packet_size
Definition: decode.c:75
PoolReturn
void PoolReturn(Pool *p, void *data)
Definition: util-pool.c:333
DefragTracker_::fragment_tree
struct IP_FRAGMENTS fragment_tree
Definition: defrag.h:112
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
DefragTreeDestroy
void DefragTreeDestroy(void)
Definition: defrag-config.c:162
IPV6Hdr
struct IPV6Hdr_ IPV6Hdr
OS_POLICY_LAST
@ OS_POLICY_LAST
Definition: stream-tcp-reassemble.h:53
Packet_::ts
struct timeval ts
Definition: decode.h:477
suricata-common.h
Frag_::len
uint32_t len
Definition: defrag.h:47
DefragGetTrackerFromHash
DefragTracker * DefragGetTrackerFromHash(Packet *p)
Definition: defrag-hash.c:535
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
OS_POLICY_OLD_LINUX
@ OS_POLICY_OLD_LINUX
Definition: stream-tcp-reassemble.h:41
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:255
DecodeThreadVars_::counter_defrag_ipv6_reassembled
uint16_t counter_defrag_ipv6_reassembled
Definition: decode.h:713
IPV6ExtHdrs_::fh_prev_hdr_offset
uint16_t fh_prev_hdr_offset
Definition: decode-ipv6.h:224
FatalError
#define FatalError(x,...)
Definition: util-debug.h:530
PKT_SRC_DEFRAG
@ PKT_SRC_DEFRAG
Definition: decode.h:59
DefragPolicyLoadFromConfig
void DefragPolicyLoadFromConfig(void)
Definition: defrag-config.c:133
DEFRAG_POLICY_SOLARIS
@ DEFRAG_POLICY_SOLARIS
Definition: defrag.c:95
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:31
Frag_::frag_hdr_offset
uint16_t frag_hdr_offset
Definition: defrag.h:56
util-validate.h
OS_POLICY_WINDOWS
@ OS_POLICY_WINDOWS
Definition: stream-tcp-reassemble.h:49
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:619
PoolGet
void * PoolGet(Pool *p)
Definition: util-pool.c:275
PKT_REBUILT_FRAGMENT
#define PKT_REBUILT_FRAGMENT
Definition: decode.h:1205
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
SCLogWarning
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:242
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:51
DefragTracker_::af
uint8_t af
Definition: defrag.h:96
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:459
IPV4_GET_MF
#define IPV4_GET_MF(p)
Definition: decode-ipv4.h:144
SC_ERR_REASSEMBLY
@ SC_ERR_REASSEMBLY
Definition: util-error.h:95
util-random.h
IPV4Hdr_::ip_csum
uint16_t ip_csum
Definition: decode-ipv4.h:80
SC_ERR_MEM_ALLOC
@ SC_ERR_MEM_ALLOC
Definition: util-error.h:31
DEFRAG_POLICY_DEFAULT
@ DEFRAG_POLICY_DEFAULT
Definition: defrag.c:97
suricata.h
defrag-hash.h
Packet_::dst
Address dst
Definition: decode.h:439
TIMEOUT_DEFAULT
#define TIMEOUT_DEFAULT
Definition: defrag.c:75
OS_POLICY_WINDOWS2K3
@ OS_POLICY_WINDOWS2K3
Definition: stream-tcp-reassemble.h:51
DecodeThreadVars_::counter_defrag_ipv6_fragments
uint16_t counter_defrag_ipv6_fragments
Definition: decode.h:712
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:49
OS_POLICY_OLD_SOLARIS
@ OS_POLICY_OLD_SOLARIS
Definition: stream-tcp-reassemble.h:43
DEFAULT_DEFRAG_POOL_SIZE
#define DEFAULT_DEFRAG_POOL_SIZE
Definition: defrag.c:69
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:301
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:534
SET_IPV4_DST_ADDR
#define SET_IPV4_DST_ADDR(p, a)
Definition: decode.h:149
IPV4_FRAG_PKT_TOO_LARGE
@ IPV4_FRAG_PKT_TOO_LARGE
Definition: decode-events.h:168
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:127
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:528
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
IPV6_FRAG_IGNORED
@ IPV6_FRAG_IGNORED
Definition: decode-events.h:176
PKT_IS_IPV4
#define PKT_IS_IPV4(p)
Definition: decode.h:253
OS_POLICY_LINUX
@ OS_POLICY_LINUX
Definition: stream-tcp-reassemble.h:42
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:40
DEFRAG_POLICY_BSD
@ DEFRAG_POLICY_BSD
Definition: defrag.c:91
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:111
Frag_::offset
uint16_t offset
Definition: defrag.h:44
Packet_::src
Address src
Definition: decode.h:438
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:541
Frag_::ip_hdr_offset
uint16_t ip_hdr_offset
Definition: defrag.h:54
DEFRAG_POLICY_BSD_RIGHT
@ DEFRAG_POLICY_BSD_RIGHT
Definition: defrag.c:92
DecodeThreadVars_::counter_defrag_ipv4_fragments
uint16_t counter_defrag_ipv4_fragments
Definition: decode.h:709