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