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