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