suricata
stream-tcp-reassemble.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2021 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 Gurvinder Singh <gurvindersinghdahiya@gmail.com>
22  * \author Victor Julien <victor@inliniac.net>
23  *
24  * Reference:
25  * Judy Novak, Steve Sturges: Target-Based TCP Stream Reassembly August, 2007
26  *
27  */
28 
29 #include "suricata-common.h"
30 #include "suricata.h"
31 #include "debug.h"
32 #include "detect.h"
33 #include "flow.h"
34 #include "threads.h"
35 #include "conf.h"
36 
37 #include "flow-util.h"
38 
39 #include "threadvars.h"
40 #include "tm-threads.h"
41 
42 #include "util-pool.h"
43 #include "util-unittest.h"
44 #include "util-print.h"
45 #include "util-host-os-info.h"
46 #include "util-unittest-helper.h"
47 #include "util-byte.h"
48 #include "util-device.h"
49 
50 #include "stream-tcp.h"
51 #include "stream-tcp-private.h"
52 #include "stream-tcp-reassemble.h"
53 #include "stream-tcp-inline.h"
54 #include "stream-tcp-list.h"
55 #include "stream-tcp-util.h"
56 
57 #include "stream.h"
58 
59 #include "util-debug.h"
60 #include "app-layer-protos.h"
61 #include "app-layer.h"
62 #include "app-layer-events.h"
63 #include "app-layer-parser.h"
64 #include "app-layer-frames.h"
65 
66 #include "detect-engine-state.h"
67 
68 #include "util-profiling.h"
69 #include "util-validate.h"
70 
71 #ifdef DEBUG
72 static SCMutex segment_pool_memuse_mutex;
73 static uint64_t segment_pool_memuse = 0;
74 static uint64_t segment_pool_memcnt = 0;
75 #endif
76 
77 static PoolThread *segment_thread_pool = NULL;
78 /* init only, protect initializing and growing pool */
79 static SCMutex segment_thread_pool_mutex = SCMUTEX_INITIALIZER;
80 
81 /* Memory use counter */
82 SC_ATOMIC_DECLARE(uint64_t, ra_memuse);
83 
84 /* prototypes */
86 void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t);
87 
89 {
90  SC_ATOMIC_INIT(ra_memuse);
91 }
92 
93 /**
94  * \brief Function to Increment the memory usage counter for the TCP reassembly
95  * segments
96  *
97  * \param size Size of the TCP segment and its payload length memory allocated
98  */
99 void StreamTcpReassembleIncrMemuse(uint64_t size)
100 {
101  (void) SC_ATOMIC_ADD(ra_memuse, size);
102  SCLogDebug("REASSEMBLY %"PRIu64", incr %"PRIu64, StreamTcpReassembleMemuseGlobalCounter(), size);
103  return;
104 }
105 
106 /**
107  * \brief Function to Decrease the memory usage counter for the TCP reassembly
108  * segments
109  *
110  * \param size Size of the TCP segment and its payload length memory allocated
111  */
112 void StreamTcpReassembleDecrMemuse(uint64_t size)
113 {
114 #ifdef UNITTESTS
115  uint64_t presize = SC_ATOMIC_GET(ra_memuse);
116  if (RunmodeIsUnittests()) {
117  BUG_ON(presize > UINT_MAX);
118  }
119 #endif
120 
121  (void) SC_ATOMIC_SUB(ra_memuse, size);
122 
123 #ifdef UNITTESTS
124  if (RunmodeIsUnittests()) {
125  uint64_t postsize = SC_ATOMIC_GET(ra_memuse);
126  BUG_ON(postsize > presize);
127  }
128 #endif
129  SCLogDebug("REASSEMBLY %"PRIu64", decr %"PRIu64, StreamTcpReassembleMemuseGlobalCounter(), size);
130  return;
131 }
132 
134 {
135  uint64_t smemuse = SC_ATOMIC_GET(ra_memuse);
136  return smemuse;
137 }
138 
139 /**
140  * \brief Function to Check the reassembly memory usage counter against the
141  * allowed max memory usage for TCP segments.
142  *
143  * \param size Size of the TCP segment and its payload length memory allocated
144  * \retval 1 if in bounds
145  * \retval 0 if not in bounds
146  */
148 {
149  uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.reassembly_memcap);
150  if (memcapcopy == 0 ||
151  (uint64_t)((uint64_t)size + SC_ATOMIC_GET(ra_memuse)) <= memcapcopy)
152  return 1;
153  return 0;
154 }
155 
156 /**
157  * \brief Update memcap value
158  *
159  * \param size new memcap value
160  */
162 {
163  if (size == 0 || (uint64_t)SC_ATOMIC_GET(ra_memuse) < size) {
164  SC_ATOMIC_SET(stream_config.reassembly_memcap, size);
165  return 1;
166  }
167 
168  return 0;
169 }
170 
171 /**
172  * \brief Return memcap value
173  *
174  * \return memcap memcap value
175  */
177 {
178  uint64_t memcapcopy = SC_ATOMIC_GET(stream_config.reassembly_memcap);
179  return memcapcopy;
180 }
181 
182 /* memory functions for the streaming buffer API */
183 
184 /*
185  void *(*Malloc)(size_t size);
186 */
187 static void *ReassembleMalloc(size_t size)
188 {
189  if (StreamTcpReassembleCheckMemcap(size) == 0)
190  return NULL;
191  void *ptr = SCMalloc(size);
192  if (ptr == NULL)
193  return NULL;
195  return ptr;
196 }
197 
198 /*
199  void *(*Calloc)(size_t n, size_t size);
200 */
201 static void *ReassembleCalloc(size_t n, size_t size)
202 {
203  if (StreamTcpReassembleCheckMemcap(n * size) == 0)
204  return NULL;
205  void *ptr = SCCalloc(n, size);
206  if (ptr == NULL)
207  return NULL;
209  return ptr;
210 }
211 
212 /*
213  void *(*Realloc)(void *ptr, size_t orig_size, size_t size);
214 */
215 static void *ReassembleRealloc(void *optr, size_t orig_size, size_t size)
216 {
217  if (size > orig_size) {
218  if (StreamTcpReassembleCheckMemcap(size - orig_size) == 0)
219  return NULL;
220  }
221  void *nptr = SCRealloc(optr, size);
222  if (nptr == NULL)
223  return NULL;
224 
225  if (size > orig_size) {
226  StreamTcpReassembleIncrMemuse(size - orig_size);
227  } else {
228  StreamTcpReassembleDecrMemuse(orig_size - size);
229  }
230  return nptr;
231 }
232 
233 /*
234  void (*Free)(void *ptr, size_t size);
235 */
236 static void ReassembleFree(void *ptr, size_t size)
237 {
238  SCFree(ptr);
240 }
241 
242 /** \brief alloc a tcp segment pool entry */
243 static void *TcpSegmentPoolAlloc(void)
244 {
245  if (StreamTcpReassembleCheckMemcap((uint32_t)sizeof(TcpSegment)) == 0) {
246  return NULL;
247  }
248 
249  TcpSegment *seg = NULL;
250 
251  seg = SCMalloc(sizeof (TcpSegment));
252  if (unlikely(seg == NULL))
253  return NULL;
254  return seg;
255 }
256 
257 static int TcpSegmentPoolInit(void *data, void *initdata)
258 {
259  TcpSegment *seg = (TcpSegment *) data;
260 
261  /* do this before the can bail, so TcpSegmentPoolCleanup
262  * won't have uninitialized memory to consider. */
263  memset(seg, 0, sizeof (TcpSegment));
264 
265  if (StreamTcpReassembleCheckMemcap((uint32_t)sizeof(TcpSegment)) == 0) {
266  return 0;
267  }
268 
269 #ifdef DEBUG
270  SCMutexLock(&segment_pool_memuse_mutex);
271  segment_pool_memuse += sizeof(TcpSegment);
272  segment_pool_memcnt++;
273  SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt);
274  SCMutexUnlock(&segment_pool_memuse_mutex);
275 #endif
276 
277  StreamTcpReassembleIncrMemuse((uint32_t)sizeof(TcpSegment));
278  return 1;
279 }
280 
281 /** \brief clean up a tcp segment pool entry */
282 static void TcpSegmentPoolCleanup(void *ptr)
283 {
284  if (ptr == NULL)
285  return;
286 
287  StreamTcpReassembleDecrMemuse((uint32_t)sizeof(TcpSegment));
288 
289 #ifdef DEBUG
290  SCMutexLock(&segment_pool_memuse_mutex);
291  segment_pool_memuse -= sizeof(TcpSegment);
292  segment_pool_memcnt--;
293  SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt);
294  SCMutexUnlock(&segment_pool_memuse_mutex);
295 #endif
296 }
297 
298 /**
299  * \brief Function to return the segment back to the pool.
300  *
301  * \param seg Segment which will be returned back to the pool.
302  */
304 {
305  if (seg == NULL)
306  return;
307 
308  PoolThreadReturn(segment_thread_pool, seg);
309 }
310 
311 /**
312  * \brief return all segments in this stream into the pool(s)
313  *
314  * \param stream the stream to cleanup
315  */
317 {
318  TcpSegment *seg = NULL, *safe = NULL;
319  RB_FOREACH_SAFE(seg, TCPSEG, &stream->seg_tree, safe)
320  {
321  RB_REMOVE(TCPSEG, &stream->seg_tree, seg);
323  }
324 }
325 
326 static inline uint64_t GetAbsLastAck(const TcpStream *stream)
327 {
328  if (STREAM_LASTACK_GT_BASESEQ(stream)) {
329  return STREAM_BASE_OFFSET(stream) + (stream->last_ack - stream->base_seq);
330  } else {
331  return STREAM_BASE_OFFSET(stream);
332  }
333 }
334 
335 uint64_t StreamTcpGetAcked(const TcpStream *stream)
336 {
337  return GetAbsLastAck(stream);
338 }
339 
340 uint64_t StreamTcpGetUsable(const TcpStream *stream, const bool eof)
341 {
342  uint64_t right_edge = STREAM_BASE_OFFSET(stream) + stream->sb.buf_offset;
343  if (!eof && StreamTcpInlineMode() == FALSE) {
344  right_edge = MIN(GetAbsLastAck(stream), right_edge);
345  }
346  return right_edge;
347 }
348 
349 #ifdef UNITTESTS
350 /** \internal
351  * \brief check if segments falls before stream 'offset' */
352 static inline int SEGMENT_BEFORE_OFFSET(TcpStream *stream, TcpSegment *seg, uint64_t offset)
353 {
354  if (seg->sbseg.stream_offset + seg->sbseg.segment_len <= offset)
355  return 1;
356  return 0;
357 }
358 #endif
359 
360 /** \param f locked flow */
362 {
363  if (f->protoctx == NULL)
364  return;
365 
366  TcpSession *ssn = (TcpSession *)f->protoctx;
370  if (f->alparser) {
373  }
374 }
375 
376 /** \param f locked flow */
378 {
379  if (f->protoctx == NULL || f->proto != IPPROTO_TCP)
380  return 0;
381 
382  TcpSession *ssn = (TcpSession *)f->protoctx;
384 }
385 
386 static int StreamTcpReassemblyConfig(bool quiet)
387 {
388  uint32_t segment_prealloc = 2048;
389  ConfNode *seg = ConfGetNode("stream.reassembly.segment-prealloc");
390  if (seg) {
391  uint32_t prealloc = 0;
392  if (StringParseUint32(&prealloc, 10, strlen(seg->val), seg->val) < 0)
393  {
394  SCLogError(SC_ERR_INVALID_ARGUMENT, "segment-prealloc of "
395  "%s is invalid", seg->val);
396  return -1;
397  }
398  segment_prealloc = prealloc;
399  }
400  if (!quiet)
401  SCLogConfig("stream.reassembly \"segment-prealloc\": %u", segment_prealloc);
402  stream_config.prealloc_segments = segment_prealloc;
403 
404  int overlap_diff_data = 0;
405  (void)ConfGetBool("stream.reassembly.check-overlap-different-data", &overlap_diff_data);
406  if (overlap_diff_data) {
408  }
409  if (StreamTcpInlineMode() == TRUE) {
411  }
412 
415  stream_config.sbcnf.Malloc = ReassembleMalloc;
416  stream_config.sbcnf.Calloc = ReassembleCalloc;
417  stream_config.sbcnf.Realloc = ReassembleRealloc;
418  stream_config.sbcnf.Free = ReassembleFree;
419 
420  return 0;
421 }
422 
423 int StreamTcpReassembleInit(bool quiet)
424 {
425  /* init the memcap/use tracker */
427 
428  if (StreamTcpReassemblyConfig(quiet) < 0)
429  return -1;
430 
431 #ifdef DEBUG
432  SCMutexInit(&segment_pool_memuse_mutex, NULL);
433 #endif
434  StatsRegisterGlobalCounter("tcp.reassembly_memuse",
436  return 0;
437 }
438 
439 void StreamTcpReassembleFree(bool quiet)
440 {
441  SCMutexLock(&segment_thread_pool_mutex);
442  if (segment_thread_pool != NULL) {
443  PoolThreadFree(segment_thread_pool);
444  segment_thread_pool = NULL;
445  }
446  SCMutexUnlock(&segment_thread_pool_mutex);
447  SCMutexDestroy(&segment_thread_pool_mutex);
448 
449 #ifdef DEBUG
450  if (segment_pool_memuse > 0)
451  SCLogInfo("segment_pool_memuse %"PRIu64"", segment_pool_memuse);
452  if (segment_pool_memcnt > 0)
453  SCLogInfo("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt);
454  SCMutexDestroy(&segment_pool_memuse_mutex);
455 #endif
456 }
457 
459 {
460  SCEnter();
462  if (unlikely(ra_ctx == NULL))
463  return NULL;
464 
465  memset(ra_ctx, 0x00, sizeof(TcpReassemblyThreadCtx));
466 
467  ra_ctx->app_tctx = AppLayerGetCtxThread(tv);
468 
469  SCMutexLock(&segment_thread_pool_mutex);
470  if (segment_thread_pool == NULL) {
471  segment_thread_pool = PoolThreadInit(1, /* thread */
472  0, /* unlimited */
474  sizeof(TcpSegment),
475  TcpSegmentPoolAlloc,
476  TcpSegmentPoolInit, NULL,
477  TcpSegmentPoolCleanup, NULL);
478  ra_ctx->segment_thread_pool_id = 0;
479  SCLogDebug("pool size %d, thread segment_thread_pool_id %d",
480  PoolThreadSize(segment_thread_pool),
481  ra_ctx->segment_thread_pool_id);
482  } else {
483  /* grow segment_thread_pool until we have an element for our thread id */
484  ra_ctx->segment_thread_pool_id = PoolThreadExpand(segment_thread_pool);
485  SCLogDebug("pool size %d, thread segment_thread_pool_id %d",
486  PoolThreadSize(segment_thread_pool),
487  ra_ctx->segment_thread_pool_id);
488  }
489  SCMutexUnlock(&segment_thread_pool_mutex);
490  if (ra_ctx->segment_thread_pool_id < 0 || segment_thread_pool == NULL) {
491  SCLogError(SC_ERR_MEM_ALLOC, "failed to setup/expand stream segment pool. Expand stream.reassembly.memcap?");
493  SCReturnPtr(NULL, "TcpReassemblyThreadCtx");
494  }
495 
496  SCReturnPtr(ra_ctx, "TcpReassemblyThreadCtx");
497 }
498 
500 {
501  SCEnter();
502  if (ra_ctx) {
504  SCFree(ra_ctx);
505  }
506  SCReturn;
507 }
508 
509 /**
510  * \brief check if stream in pkt direction has depth reached
511  *
512  * \param p packet with *LOCKED* flow
513  *
514  * \retval 1 stream has depth reached
515  * \retval 0 stream does not have depth reached
516  */
518 {
519  if (p->flow != NULL && p->flow->protoctx != NULL) {
520  TcpSession *ssn = p->flow->protoctx;
521  TcpStream *stream;
522  if (p->flowflags & FLOW_PKT_TOSERVER) {
523  stream = &ssn->client;
524  } else {
525  stream = &ssn->server;
526  }
527 
528  return (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) ? 1 : 0;
529  }
530 
531  return 0;
532 }
533 
534 /**
535  * \internal
536  * \brief Function to Check the reassembly depth valuer against the
537  * allowed max depth of the stream reassembly for TCP streams.
538  *
539  * \param stream stream direction
540  * \param seq sequence number where "size" starts
541  * \param size size of the segment that is added
542  *
543  * \retval size Part of the size that fits in the depth, 0 if none
544  */
545 static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream,
546  uint32_t seq, uint32_t size)
547 {
548  SCEnter();
549 
550  /* if the configured depth value is 0, it means there is no limit on
551  reassembly depth. Otherwise carry on my boy ;) */
552  if (ssn->reassembly_depth == 0) {
553  SCReturnUInt(size);
554  }
555 
556  /* if the final flag is set, we're not accepting anymore */
558  SCReturnUInt(0);
559  }
560 
561  uint64_t seg_depth;
562  if (SEQ_GT(stream->base_seq, seq)) {
563  if (SEQ_LEQ(seq+size, stream->base_seq)) {
564  SCLogDebug("segment entirely before base_seq, weird: base %u, seq %u, re %u",
565  stream->base_seq, seq, seq+size);
566  SCReturnUInt(0);
567  }
568 
569  seg_depth = STREAM_BASE_OFFSET(stream) + size - (stream->base_seq - seq);
570  } else {
571  seg_depth = STREAM_BASE_OFFSET(stream) + ((seq + size) - stream->base_seq);
572  }
573 
574  /* if the base_seq has moved passed the depth window we stop
575  * checking and just reject the rest of the packets including
576  * retransmissions. Saves us the hassle of dealing with sequence
577  * wraps as well */
578  SCLogDebug("seq + size %u, base %u, seg_depth %"PRIu64" limit %u", (seq + size),
579  stream->base_seq, seg_depth,
580  ssn->reassembly_depth);
581 
582  if (seg_depth > (uint64_t)ssn->reassembly_depth) {
583  SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED");
585  SCReturnUInt(0);
586  }
587  SCLogDebug("NOT STREAMTCP_STREAM_FLAG_DEPTH_REACHED");
588  SCLogDebug("%"PRIu64" <= %u", seg_depth, ssn->reassembly_depth);
589 #if 0
590  SCLogDebug("full depth not yet reached: %"PRIu64" <= %"PRIu32,
591  (stream->base_seq_offset + stream->base_seq + size),
592  (stream->isn + ssn->reassembly_depth));
593 #endif
594  if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + ssn->reassembly_depth))) {
595  /* packet (partly?) fits the depth window */
596 
597  if (SEQ_LEQ((seq + size),(stream->isn + 1 + ssn->reassembly_depth))) {
598  /* complete fit */
599  SCReturnUInt(size);
600  } else {
602  /* partial fit, return only what fits */
603  uint32_t part = (stream->isn + 1 + ssn->reassembly_depth) - seq;
604  DEBUG_VALIDATE_BUG_ON(part > size);
605  if (part > size)
606  part = size;
607  SCReturnUInt(part);
608  }
609  }
610 
611  SCReturnUInt(0);
612 }
613 
615 {
616  if (RB_EMPTY(&stream->sb.sbb_tree)) {
617  if (stream->sb.stream_offset != 0)
618  return 0;
619 
620  return stream->sb.buf_offset;
621  } else {
622  DEBUG_VALIDATE_BUG_ON(stream->sb.head == NULL);
623  DEBUG_VALIDATE_BUG_ON(stream->sb.sbb_size == 0);
624  return stream->sb.sbb_size;
625  }
626 }
627 
628 /**
629  * \brief Insert a packets TCP data into the stream reassembly engine.
630  *
631  * \retval 0 good segment, as far as we checked.
632  * \retval -1 badness, reason to drop in inline mode
633  *
634  * If the retval is 0 the segment is inserted correctly, or overlap is handled,
635  * or it wasn't added because of reassembly depth.
636  *
637  */
639  TcpSession *ssn, TcpStream *stream, Packet *p)
640 {
641  SCEnter();
642 
643  if (ssn->data_first_seen_dir == 0) {
644  if (PKT_IS_TOSERVER(p)) {
645  ssn->data_first_seen_dir = STREAM_TOSERVER;
646  } else {
647  ssn->data_first_seen_dir = STREAM_TOCLIENT;
648  }
649  }
650 
651  /* If the OS policy is not set then set the OS policy for this stream */
652  if (stream->os_policy == 0) {
653  StreamTcpSetOSPolicy(stream, p);
654  }
655 
658  SCLogDebug("ssn %p: both app and raw reassembly disabled, not reassembling", ssn);
659  SCReturnInt(0);
660  }
661 
662  /* If we have reached the defined depth for either of the stream, then stop
663  reassembling the TCP session */
664  uint32_t size = StreamTcpReassembleCheckDepth(ssn, stream, TCP_GET_SEQ(p), p->payload_len);
665  SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size);
666 
668  /* increment stream depth counter */
670  }
671  if (size == 0) {
672  SCLogDebug("ssn %p: depth reached, not reassembling", ssn);
673  SCReturnInt(0);
674  }
675 
677  if (size > p->payload_len)
678  size = p->payload_len;
679 
680  TcpSegment *seg = StreamTcpGetSegment(tv, ra_ctx);
681  if (seg == NULL) {
682  SCLogDebug("segment_pool is empty");
684  SCReturnInt(-1);
685  }
686 
687  TCP_SEG_LEN(seg) = size;
688  seg->seq = TCP_GET_SEQ(p);
689 
690  /* HACK: for TFO SYN packets the seq for data starts at + 1 */
691  if (TCP_HAS_TFO(p) && p->payload_len && p->tcph->th_flags == TH_SYN)
692  seg->seq += 1;
693 
694  /* proto detection skipped, but now we do get data. Set event. */
695  if (RB_EMPTY(&stream->seg_tree) &&
697 
700  }
701 
702  if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, seg, p, TCP_GET_SEQ(p), p->payload, p->payload_len) != 0) {
703  SCLogDebug("StreamTcpReassembleInsertSegment failed");
704  SCReturnInt(-1);
705  }
706  SCReturnInt(0);
707 }
708 
709 static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream,
710  Packet *p)
711 {
712  uint8_t flag = 0;
713 
715  flag |= STREAM_START;
716  }
717 
718  if (ssn->state == TCP_CLOSED) {
719  flag |= STREAM_EOF;
720  }
721 
722  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
723  flag |= STREAM_MIDSTREAM;
724  }
725 
726  if (p->flags & PKT_PSEUDO_STREAM_END) {
727  flag |= STREAM_EOF;
728  }
729 
730  if (&ssn->client == stream) {
731  flag |= STREAM_TOSERVER;
732  } else {
733  flag |= STREAM_TOCLIENT;
734  }
736  flag |= STREAM_DEPTH;
737  }
738  return flag;
739 }
740 
741 /**
742  * \brief Check the minimum size limits for reassembly.
743  *
744  * \retval 0 don't reassemble yet
745  * \retval 1 do reassemble
746  */
747 static int StreamTcpReassembleRawCheckLimit(const TcpSession *ssn,
748  const TcpStream *stream, const Packet *p)
749 {
750  SCEnter();
751 
752  /* if any of these flags is set we always inspect immediately */
753 #define STREAMTCP_STREAM_FLAG_FLUSH_FLAGS \
754  ( STREAMTCP_STREAM_FLAG_DEPTH_REACHED \
755  | STREAMTCP_STREAM_FLAG_TRIGGER_RAW \
756  | STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)
757 
760  SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_DEPTH_REACHED "
761  "is set, so not expecting any new data segments");
762  }
764  SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_TRIGGER_RAW is set");
765  }
767  SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED is set, "
768  "so no new segments will be considered");
769  }
770  SCReturnInt(1);
771  }
772 #undef STREAMTCP_STREAM_FLAG_FLUSH_FLAGS
773 
774  /* some states mean we reassemble no matter how much data we have */
775  if (ssn->state > TCP_TIME_WAIT)
776  SCReturnInt(1);
777 
778  if (p->flags & PKT_PSEUDO_STREAM_END)
779  SCReturnInt(1);
780 
781  const uint64_t last_ack_abs = GetAbsLastAck(stream);
782  int64_t diff = last_ack_abs - STREAM_RAW_PROGRESS(stream);
783  int64_t chunk_size = PKT_IS_TOSERVER(p) ? (int64_t)stream_config.reassembly_toserver_chunk_size
785 
786  /* check if we have enough data to do raw reassembly */
787  if (chunk_size <= diff) {
788  SCReturnInt(1);
789  } else {
790  SCLogDebug("%s min chunk len not yet reached: "
791  "last_ack %" PRIu32 ", ra_raw_base_seq %" PRIu32 ", %" PRIu32 " < "
792  "%" PRIi64,
793  PKT_IS_TOSERVER(p) ? "toserver" : "toclient", stream->last_ack, stream->base_seq,
794  (stream->last_ack - stream->base_seq), chunk_size);
795  SCReturnInt(0);
796  }
797 
798  SCReturnInt(0);
799 }
800 
801 /**
802  * \brief see what if any work the TCP session still needs
803  */
804 int StreamNeedsReassembly(const TcpSession *ssn, uint8_t direction)
805 {
806  const TcpStream *stream = NULL;
807 #ifdef DEBUG
808  const char *dirstr = NULL;
809 #endif
810  if (direction == STREAM_TOSERVER) {
811  stream = &ssn->client;
812 #ifdef DEBUG
813  dirstr = "client";
814 #endif
815  } else {
816  stream = &ssn->server;
817 #ifdef DEBUG
818  dirstr = "server";
819 #endif
820  }
821 
822  int use_app = 1;
823  int use_raw = 1;
824 
826  // app is dead
827  use_app = 0;
828  }
829 
831  // raw is dead
832  use_raw = 0;
833  }
834 
835  uint64_t right_edge = STREAM_BASE_OFFSET(stream) + stream->sb.buf_offset;
836 
837  SCLogDebug("%s: app %"PRIu64" (use: %s), raw %"PRIu64" (use: %s). Stream right edge: %"PRIu64,
838  dirstr,
839  STREAM_APP_PROGRESS(stream), use_app ? "yes" : "no",
840  STREAM_RAW_PROGRESS(stream), use_raw ? "yes" : "no",
841  right_edge);
842  if (use_raw) {
843  if (right_edge > STREAM_RAW_PROGRESS(stream)) {
844  SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION", dirstr);
846  }
847  }
848  if (use_app) {
849  if (right_edge > STREAM_APP_PROGRESS(stream)) {
850  SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION", dirstr);
852  }
853  }
854 
855  SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NONE", dirstr);
857 }
858 
859 #ifdef DEBUG
860 static uint64_t GetStreamSize(TcpStream *stream)
861 {
862  if (stream) {
863  uint64_t size = 0;
864  uint32_t cnt = 0;
865  uint64_t last_ack_abs = GetAbsLastAck(stream);
866  uint64_t last_re = 0;
867 
868  SCLogDebug("stream_offset %" PRIu64, stream->sb.stream_offset);
869 
870  TcpSegment *seg;
871  RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
872  const uint64_t seg_abs =
873  STREAM_BASE_OFFSET(stream) + (uint64_t)(seg->seq - stream->base_seq);
874  if (last_re != 0 && last_re < seg_abs) {
875  const char *gacked = NULL;
876  if (last_ack_abs >= seg_abs) {
877  gacked = "fully ack'd";
878  } else if (last_ack_abs > last_re) {
879  gacked = "partly ack'd";
880  } else {
881  gacked = "not yet ack'd";
882  }
883  SCLogDebug(" -> gap of size %" PRIu64 ", ack:%s", seg_abs - last_re, gacked);
884  }
885 
886  const char *acked = NULL;
887  if (last_ack_abs >= seg_abs + (uint64_t)TCP_SEG_LEN(seg)) {
888  acked = "fully ack'd";
889  } else if (last_ack_abs > seg_abs) {
890  acked = "partly ack'd";
891  } else {
892  acked = "not yet ack'd";
893  }
894 
895  SCLogDebug("%u -> seg %p seq %u abs %" PRIu64 " size %u abs %" PRIu64 " (%" PRIu64
896  ") ack:%s",
897  cnt, seg, seg->seq, seg_abs, TCP_SEG_LEN(seg),
898  seg_abs + (uint64_t)TCP_SEG_LEN(seg), STREAM_BASE_OFFSET(stream), acked);
899  last_re = seg_abs + (uint64_t)TCP_SEG_LEN(seg);
900  cnt++;
901  size += (uint64_t)TCP_SEG_LEN(seg);
902  }
903 
904  SCLogDebug("size %"PRIu64", cnt %"PRIu32, size, cnt);
905  return size;
906  }
907  return (uint64_t)0;
908 }
909 
910 static void GetSessionSize(TcpSession *ssn, Packet *p)
911 {
912  uint64_t size = 0;
913  if (ssn) {
914  size = GetStreamSize(&ssn->client);
915  size += GetStreamSize(&ssn->server);
916 
917  //if (size > 900000)
918  // SCLogInfo("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
919  SCLogDebug("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
920  }
921 }
922 #endif
923 
924 static StreamingBufferBlock *GetBlock(StreamingBuffer *sb, const uint64_t offset)
925 {
926  StreamingBufferBlock *blk = sb->head;
927  if (blk == NULL)
928  return NULL;
929 
930  for ( ; blk != NULL; blk = SBB_RB_NEXT(blk)) {
931  if (blk->offset >= offset)
932  return blk;
933  else if ((blk->offset + blk->len) > offset) {
934  return blk;
935  }
936  }
937  return NULL;
938 }
939 
940 static inline bool GapAhead(TcpStream *stream, StreamingBufferBlock *cur_blk)
941 {
942  StreamingBufferBlock *nblk = SBB_RB_NEXT(cur_blk);
943  if (nblk && (cur_blk->offset + cur_blk->len < nblk->offset) &&
944  GetAbsLastAck(stream) >= (cur_blk->offset + cur_blk->len)) {
945  return true;
946  }
947  return false;
948 }
949 
950 /** \internal
951  *
952  * Get buffer, or first part of the buffer if data gaps exist.
953  *
954  * \brief get stream data from offset
955  * \param offset stream offset
956  * \param check_for_gap check if there is a gap ahead. Optional as it is only
957  * needed for app-layer incomplete support.
958  * \retval bool pkt loss ahead */
959 static bool GetAppBuffer(TcpStream *stream, const uint8_t **data, uint32_t *data_len,
960  uint64_t offset, const bool check_for_gap)
961 {
962  const uint8_t *mydata;
963  uint32_t mydata_len;
964  bool gap_ahead = false;
965 
966  if (RB_EMPTY(&stream->sb.sbb_tree)) {
967  SCLogDebug("getting one blob");
968 
969  StreamingBufferGetDataAtOffset(&stream->sb, &mydata, &mydata_len, offset);
970 
971  *data = mydata;
972  *data_len = mydata_len;
973  } else {
974  StreamingBufferBlock *blk = GetBlock(&stream->sb, offset);
975  if (blk == NULL) {
976  *data = NULL;
977  *data_len = 0;
978  return false;
979  }
980  SCLogDebug("blk %p blk->offset %" PRIu64 ", blk->len %u", blk, blk->offset, blk->len);
981 
982  /* block at expected offset */
983  if (blk->offset == offset) {
984 
985  StreamingBufferSBBGetData(&stream->sb, blk, data, data_len);
986 
987  gap_ahead = check_for_gap && GapAhead(stream, blk);
988 
989  /* block past out offset */
990  } else if (blk->offset > offset) {
991  SCLogDebug("gap, want data at offset %"PRIu64", "
992  "got data at %"PRIu64". GAP of size %"PRIu64,
993  offset, blk->offset, blk->offset - offset);
994  *data = NULL;
995  *data_len = blk->offset - offset;
996 
997  /* block starts before offset, but ends after */
998  } else if (offset > blk->offset && offset <= (blk->offset + blk->len)) {
999  SCLogDebug("get data from offset %"PRIu64". SBB %"PRIu64"/%u",
1000  offset, blk->offset, blk->len);
1001  StreamingBufferSBBGetDataAtOffset(&stream->sb, blk, data, data_len, offset);
1002  SCLogDebug("data %p, data_len %u", *data, *data_len);
1003 
1004  gap_ahead = check_for_gap && GapAhead(stream, blk);
1005 
1006  } else {
1007  *data = NULL;
1008  *data_len = 0;
1009  }
1010  }
1011  return gap_ahead;
1012 }
1013 
1014 /** \internal
1015  * \brief check to see if we should declare a GAP
1016  * Call this when the app layer didn't get data at the requested
1017  * offset.
1018  */
1019 static inline bool CheckGap(TcpSession *ssn, TcpStream *stream, Packet *p)
1020 {
1021  const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
1022  const int ackadded = (ssn->state >= TCP_FIN_WAIT1) ? 1 : 0;
1023  const uint64_t last_ack_abs = GetAbsLastAck(stream) - (uint64_t)ackadded;
1024 
1025  SCLogDebug("last_ack %u abs %" PRIu64, stream->last_ack, last_ack_abs);
1026  SCLogDebug("next_seq %u", stream->next_seq);
1027 
1028  /* if last_ack_abs is beyond the app_progress data that we haven't seen
1029  * has been ack'd. This looks like a GAP. */
1030  if (last_ack_abs > app_progress) {
1031  /* however, we can accept ACKs a bit too liberally. If last_ack
1032  * is beyond next_seq, we only consider it a gap now if we do
1033  * already have data beyond the gap. */
1034  if (SEQ_GT(stream->last_ack, stream->next_seq)) {
1035  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1036  SCLogDebug("packet %" PRIu64 ": no GAP. "
1037  "next_seq %u < last_ack %u, but no data in list",
1038  p->pcap_cnt, stream->next_seq, stream->last_ack);
1039  return false;
1040  } else {
1041  const uint64_t next_seq_abs =
1042  STREAM_BASE_OFFSET(stream) + (stream->next_seq - stream->base_seq);
1043  const StreamingBufferBlock *blk = stream->sb.head;
1044  if (blk->offset > next_seq_abs && blk->offset < last_ack_abs) {
1045  /* ack'd data after the gap */
1046  SCLogDebug("packet %" PRIu64 ": GAP. "
1047  "next_seq %u < last_ack %u, but ACK'd data beyond gap.",
1048  p->pcap_cnt, stream->next_seq, stream->last_ack);
1049  return true;
1050  }
1051  }
1052  }
1053 
1054  SCLogDebug("packet %" PRIu64 ": GAP! "
1055  "last_ack_abs %" PRIu64 " > app_progress %" PRIu64 ", "
1056  "but we have no data.",
1057  p->pcap_cnt, last_ack_abs, app_progress);
1058  return true;
1059  }
1060  SCLogDebug("packet %"PRIu64": no GAP. "
1061  "last_ack_abs %"PRIu64" <= app_progress %"PRIu64,
1062  p->pcap_cnt, last_ack_abs, app_progress);
1063  return false;
1064 }
1065 
1066 static inline uint32_t AdjustToAcked(const Packet *p,
1067  const TcpSession *ssn, const TcpStream *stream,
1068  const uint64_t app_progress, const uint32_t data_len)
1069 {
1070  uint32_t adjusted = data_len;
1071 
1072  /* get window of data that is acked */
1073  if (StreamTcpInlineMode() == FALSE) {
1074  SCLogDebug("ssn->state %s", StreamTcpStateAsString(ssn->state));
1075  if (data_len == 0 || ((ssn->state < TCP_CLOSED ||
1076  (ssn->state == TCP_CLOSED &&
1077  (ssn->flags & STREAMTCP_FLAG_CLOSED_BY_RST) != 0)) &&
1078  (p->flags & PKT_PSEUDO_STREAM_END))) {
1079  // fall through, we use all available data
1080  } else {
1081  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1082  DEBUG_VALIDATE_BUG_ON(app_progress > last_ack_abs);
1083 
1084  /* see if the buffer contains unack'd data as well */
1085  if (app_progress <= last_ack_abs && app_progress + data_len > last_ack_abs) {
1086  uint32_t check = data_len;
1087  adjusted = last_ack_abs - app_progress;
1088  BUG_ON(adjusted > check);
1089  SCLogDebug("data len adjusted to %u to make sure only ACK'd "
1090  "data is considered", adjusted);
1091  }
1092  }
1093  }
1094  return adjusted;
1095 }
1096 
1097 /** \internal
1098  * \brief get stream buffer and update the app-layer
1099  * \param stream pointer to pointer as app-layer can switch flow dir
1100  * \retval 0 success
1101  */
1102 static int ReassembleUpdateAppLayer (ThreadVars *tv,
1103  TcpReassemblyThreadCtx *ra_ctx,
1104  TcpSession *ssn, TcpStream **stream,
1105  Packet *p, enum StreamUpdateDir dir)
1106 {
1107  uint64_t app_progress = STREAM_APP_PROGRESS(*stream);
1108 
1109  SCLogDebug("app progress %"PRIu64, app_progress);
1110  SCLogDebug("last_ack %u, base_seq %u", (*stream)->last_ack, (*stream)->base_seq);
1111 
1112  const uint8_t *mydata;
1113  uint32_t mydata_len;
1114  bool gap_ahead = false;
1115  bool last_was_gap = false;
1116 
1117  while (1) {
1118  const uint8_t flags = StreamGetAppLayerFlags(ssn, *stream, p);
1119  bool check_for_gap_ahead = ((*stream)->data_required > 0);
1120  gap_ahead = GetAppBuffer(*stream, &mydata, &mydata_len,
1121  app_progress, check_for_gap_ahead);
1122  if (last_was_gap && mydata_len == 0) {
1123  break;
1124  }
1125  last_was_gap = false;
1126 
1127  /* make sure to only deal with ACK'd data */
1128  mydata_len = AdjustToAcked(p, ssn, *stream, app_progress, mydata_len);
1129  DEBUG_VALIDATE_BUG_ON(mydata_len > (uint32_t)INT_MAX);
1130  if (mydata == NULL && mydata_len > 0 && CheckGap(ssn, *stream, p)) {
1131  SCLogDebug("sending GAP to app-layer (size: %u)", mydata_len);
1132 
1133  int r = AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
1134  NULL, mydata_len,
1135  StreamGetAppLayerFlags(ssn, *stream, p)|STREAM_GAP);
1136  AppLayerProfilingStore(ra_ctx->app_tctx, p);
1137 
1140 
1141  /* AppLayerHandleTCPData has likely updated progress. */
1142  const bool no_progress_update = (app_progress == STREAM_APP_PROGRESS(*stream));
1143  app_progress = STREAM_APP_PROGRESS(*stream);
1144 
1145  /* a GAP also consumes 'data required'. TODO perhaps we can use
1146  * this to skip post GAP data until the start of a next record. */
1147  if ((*stream)->data_required > 0) {
1148  if ((*stream)->data_required > mydata_len) {
1149  (*stream)->data_required -= mydata_len;
1150  } else {
1151  (*stream)->data_required = 0;
1152  }
1153  }
1154  if (r < 0)
1155  return 0;
1156  if (no_progress_update)
1157  break;
1158  last_was_gap = true;
1159  continue;
1160 
1161  } else if (flags & STREAM_DEPTH) {
1162  // we're just called once with this flag, so make sure we pass it on
1163  if (mydata == NULL && mydata_len > 0) {
1164  mydata_len = 0;
1165  }
1166  } else if (mydata == NULL || (mydata_len == 0 && ((flags & STREAM_EOF) == 0))) {
1167  /* Possibly a gap, but no new data. */
1168  if ((p->flags & PKT_PSEUDO_STREAM_END) == 0 || ssn->state < TCP_CLOSED)
1169  SCReturnInt(0);
1170 
1171  mydata = NULL;
1172  mydata_len = 0;
1173  SCLogDebug("%"PRIu64" got %p/%u", p->pcap_cnt, mydata, mydata_len);
1174  break;
1175  }
1176  DEBUG_VALIDATE_BUG_ON(mydata == NULL && mydata_len > 0);
1177 
1178  SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64,
1179  *stream, &(*stream)->sb, mydata_len, app_progress);
1180 
1181  if ((p->flags & PKT_PSEUDO_STREAM_END) == 0 || ssn->state < TCP_CLOSED) {
1182  if (mydata_len < (*stream)->data_required) {
1183  if (gap_ahead) {
1184  SCLogDebug("GAP while expecting more data (expect %u, gap size %u)",
1185  (*stream)->data_required, mydata_len);
1186  (*stream)->app_progress_rel += mydata_len;
1187  (*stream)->data_required -= mydata_len;
1188  // TODO send incomplete data to app-layer with special flag
1189  // indicating its all there is for this rec?
1190  } else {
1191  SCReturnInt(0);
1192  }
1193  app_progress = STREAM_APP_PROGRESS(*stream);
1194  continue;
1195  }
1196  }
1197  (*stream)->data_required = 0;
1198 
1199  /* update the app-layer */
1200  (void)AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
1201  (uint8_t *)mydata, mydata_len, flags);
1202  AppLayerProfilingStore(ra_ctx->app_tctx, p);
1203  AppLayerFrameDump(p->flow);
1204  uint64_t new_app_progress = STREAM_APP_PROGRESS(*stream);
1205  if (new_app_progress == app_progress || FlowChangeProto(p->flow))
1206  break;
1207  app_progress = new_app_progress;
1208  if (flags & STREAM_DEPTH)
1209  break;
1210  }
1211 
1212  SCReturnInt(0);
1213 }
1214 
1215 /**
1216  * \brief Update the stream reassembly upon receiving a packet.
1217  *
1218  * For IDS mode, the stream is in the opposite direction of the packet,
1219  * as the ACK-packet is ACK'ing the stream.
1220  *
1221  * One of the utilities call by this function AppLayerHandleTCPData(),
1222  * has a feature where it will call this very same function for the
1223  * stream opposing the stream it is called with. This shouldn't cause
1224  * any issues, since processing of each stream is independent of the
1225  * other stream.
1226  */
1228  TcpSession *ssn, TcpStream *stream,
1229  Packet *p, enum StreamUpdateDir dir)
1230 {
1231  SCEnter();
1232 
1233  /* this function can be directly called by app layer protocol
1234  * detection. */
1237  SCLogDebug("stream no reassembly flag set or app-layer disabled.");
1238  SCReturnInt(0);
1239  }
1240 
1241 #ifdef DEBUG
1242  SCLogDebug("stream->seg_tree RB_MIN %p", RB_MIN(TCPSEG, &stream->seg_tree));
1243  GetSessionSize(ssn, p);
1244 #endif
1245  /* if no segments are in the list or all are already processed,
1246  * and state is beyond established, we send an empty msg */
1247  if (!STREAM_HAS_SEEN_DATA(stream) || STREAM_RIGHT_EDGE(stream) <= STREAM_APP_PROGRESS(stream))
1248  {
1249  /* send an empty EOF msg if we have no segments but TCP state
1250  * is beyond ESTABLISHED */
1251  if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) {
1252  SCLogDebug("sending empty eof message");
1253  /* send EOF to app layer */
1254  AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, &stream,
1255  NULL, 0,
1256  StreamGetAppLayerFlags(ssn, stream, p));
1257  AppLayerProfilingStore(ra_ctx->app_tctx, p);
1258 
1259  SCReturnInt(0);
1260  }
1261  }
1262 
1263  /* with all that out of the way, lets update the app-layer */
1264  return ReassembleUpdateAppLayer(tv, ra_ctx, ssn, &stream, p, dir);
1265 }
1266 
1267 /** \internal
1268  * \brief get stream data from offset
1269  * \param offset stream offset */
1270 static int GetRawBuffer(TcpStream *stream, const uint8_t **data, uint32_t *data_len,
1271  StreamingBufferBlock **iter, uint64_t offset, uint64_t *data_offset)
1272 {
1273  const uint8_t *mydata;
1274  uint32_t mydata_len;
1275  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1276  SCLogDebug("getting one blob for offset %"PRIu64, offset);
1277 
1278  uint64_t roffset = offset;
1279  if (offset)
1280  StreamingBufferGetDataAtOffset(&stream->sb, &mydata, &mydata_len, offset);
1281  else {
1282  StreamingBufferGetData(&stream->sb, &mydata, &mydata_len, &roffset);
1283  }
1284 
1285  *data = mydata;
1286  *data_len = mydata_len;
1287  *data_offset = roffset;
1288  } else {
1289  SCLogDebug("multiblob %s. Want offset %"PRIu64,
1290  *iter == NULL ? "starting" : "continuing", offset);
1291  if (*iter == NULL) {
1292  StreamingBufferBlock key = { .offset = offset, .len = 0 };
1293  *iter = SBB_RB_FIND_INCLUSIVE(&stream->sb.sbb_tree, &key);
1294  SCLogDebug("*iter %p", *iter);
1295  }
1296  if (*iter == NULL) {
1297  SCLogDebug("no data");
1298  *data = NULL;
1299  *data_len = 0;
1300  *data_offset = 0;
1301  return 0;
1302  }
1303  SCLogDebug("getting multiple blobs. Iter %p, %"PRIu64"/%u", *iter, (*iter)->offset, (*iter)->len);
1304 
1305  StreamingBufferSBBGetData(&stream->sb, (*iter), &mydata, &mydata_len);
1306  SCLogDebug("mydata %p", mydata);
1307 
1308  if ((*iter)->offset < offset) {
1309  uint64_t delta = offset - (*iter)->offset;
1310  if (delta < mydata_len) {
1311  *data = mydata + delta;
1312  *data_len = mydata_len - delta;
1313  *data_offset = offset;
1314  } else {
1315  SCLogDebug("no data (yet)");
1316  *data = NULL;
1317  *data_len = 0;
1318  *data_offset = 0;
1319  }
1320 
1321  } else {
1322  *data = mydata;
1323  *data_len = mydata_len;
1324  *data_offset = (*iter)->offset;
1325  }
1326 
1327  *iter = SBB_RB_NEXT(*iter);
1328  SCLogDebug("*iter %p", *iter);
1329  }
1330  return 0;
1331 }
1332 
1333 /** \brief does the stream engine have data to inspect?
1334  *
1335  * Returns true if there is data to inspect. In IDS case this is
1336  * about ACK'd data in the packet's direction.
1337  *
1338  * In the IPS case this is about the packet itself.
1339  */
1341 {
1342  TcpStream *stream;
1343  if (PKT_IS_TOSERVER(p)) {
1344  stream = &ssn->client;
1345  } else {
1346  stream = &ssn->server;
1347  }
1348 
1349  if (RB_EMPTY(&stream->seg_tree)) {
1350  return false;
1351  }
1352 
1355  return false;
1356 
1357  if (StreamTcpInlineMode() == FALSE) {
1358  if ((STREAM_RAW_PROGRESS(stream) == STREAM_BASE_OFFSET(stream) + stream->sb.buf_offset)) {
1359  return false;
1360  }
1361  if (StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 1) {
1362  return true;
1363  }
1364  } else {
1365  if (p->payload_len > 0 && (p->flags & PKT_STREAM_ADD)) {
1366  return true;
1367  }
1368  }
1369  return false;
1370 }
1371 
1372 /** \brief update stream engine after detection
1373  *
1374  * Tasked with progressing the 'progress' for Raw reassembly.
1375  * 2 main scenario's:
1376  * 1. progress is != 0, so we use this
1377  * 2. progress is 0, meaning the detect engine didn't touch
1378  * raw at all. In this case we need to look into progressing
1379  * raw anyway.
1380  *
1381  * Additionally, this function is tasked with disabling raw
1382  * reassembly if the app-layer requested to disable it.
1383  */
1384 void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, uint64_t progress)
1385 {
1386  TcpStream *stream;
1387  if (PKT_IS_TOSERVER(p)) {
1388  stream = &ssn->client;
1389  } else {
1390  stream = &ssn->server;
1391  }
1392 
1393  /* Record updates */
1394  if (!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) {
1395  if (progress > STREAM_APP_PROGRESS(stream)) {
1396  AppLayerFramesUpdateProgress(p->flow, stream, progress,
1397  PKT_IS_TOSERVER(p) ? STREAM_TOSERVER : STREAM_TOCLIENT);
1398  }
1399  }
1400 
1401  if (progress > STREAM_RAW_PROGRESS(stream)) {
1402  uint32_t slide = progress - STREAM_RAW_PROGRESS(stream);
1403  stream->raw_progress_rel += slide;
1405 
1406  /* if app is active and beyond raw, sync raw to app */
1407  } else if (progress == 0 && STREAM_APP_PROGRESS(stream) > STREAM_RAW_PROGRESS(stream) &&
1409  /* if trigger raw is set we sync the 2 trackers */
1411  {
1412  uint32_t slide = STREAM_APP_PROGRESS(stream) - STREAM_RAW_PROGRESS(stream);
1413  stream->raw_progress_rel += slide;
1415 
1416  /* otherwise mix in the tcp window */
1417  } else {
1418  uint64_t tcp_window = stream->window;
1419  if (tcp_window > 0 && STREAM_APP_PROGRESS(stream) > tcp_window) {
1420  uint64_t new_raw = STREAM_APP_PROGRESS(stream) - tcp_window;
1421  if (new_raw > STREAM_RAW_PROGRESS(stream)) {
1422  uint32_t slide = new_raw - STREAM_RAW_PROGRESS(stream);
1423  stream->raw_progress_rel += slide;
1424  }
1425  }
1426  }
1427  /* app is dead */
1428  } else if (progress == 0) {
1429  uint64_t tcp_window = stream->window;
1430  uint64_t stream_right_edge = STREAM_BASE_OFFSET(stream) + stream->sb.buf_offset;
1431  if (tcp_window < stream_right_edge) {
1432  uint64_t new_raw = stream_right_edge - tcp_window;
1433  if (new_raw > STREAM_RAW_PROGRESS(stream)) {
1434  uint32_t slide = new_raw - STREAM_RAW_PROGRESS(stream);
1435  stream->raw_progress_rel += slide;
1436  }
1437  }
1439 
1440  } else {
1441  SCLogDebug("p->pcap_cnt %"PRIu64": progress %"PRIu64" app %"PRIu64" raw %"PRIu64" tcp win %"PRIu32,
1442  p->pcap_cnt, progress, STREAM_APP_PROGRESS(stream),
1443  STREAM_RAW_PROGRESS(stream), stream->window);
1444  }
1445 
1446  /* if we were told to accept no more raw data, we can mark raw as
1447  * disabled now. */
1450  SCLogDebug("ssn %p: STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED set, "
1451  "now that detect ran also set STREAMTCP_STREAM_FLAG_DISABLE_RAW", ssn);
1452  }
1453 
1454  SCLogDebug("stream raw progress now %"PRIu64, STREAM_RAW_PROGRESS(stream));
1455 }
1456 
1457 /** \internal
1458  * \brief get a buffer around the current packet and run the callback on it
1459  *
1460  * The inline/IPS scanning method takes the current payload and wraps it in
1461  * data from other segments.
1462  *
1463  * How much data is inspected is controlled by the available data, chunk_size
1464  * and the payload size of the packet.
1465  *
1466  * Large packets: if payload size is close to the chunk_size, where close is
1467  * defined as more than 67% of the chunk_size, a larger chunk_size will be
1468  * used: payload_len + 33% of the chunk_size.
1469  * If the payload size if equal to or bigger than the chunk_size, we use
1470  * payload len + 33% of the chunk size.
1471  */
1472 static int StreamReassembleRawInline(TcpSession *ssn, const Packet *p,
1473  StreamReassembleRawFunc Callback, void *cb_data, uint64_t *progress_out)
1474 {
1475  SCEnter();
1476  int r = 0;
1477 
1478  TcpStream *stream;
1479  if (PKT_IS_TOSERVER(p)) {
1480  stream = &ssn->client;
1481  } else {
1482  stream = &ssn->server;
1483  }
1484 
1485  if (p->payload_len == 0 || (p->flags & PKT_STREAM_ADD) == 0 ||
1487  {
1488  *progress_out = STREAM_RAW_PROGRESS(stream);
1489  return 0;
1490  }
1491 
1492  uint32_t chunk_size = PKT_IS_TOSERVER(p) ?
1495  if (chunk_size <= p->payload_len) {
1496  chunk_size = p->payload_len + (chunk_size / 3);
1497  SCLogDebug("packet payload len %u, so chunk_size adjusted to %u",
1498  p->payload_len, chunk_size);
1499  } else if (((chunk_size / 3 ) * 2) < p->payload_len) {
1500  chunk_size = p->payload_len + ((chunk_size / 3));
1501  SCLogDebug("packet payload len %u, so chunk_size adjusted to %u",
1502  p->payload_len, chunk_size);
1503  }
1504 
1505  uint64_t packet_leftedge_abs = STREAM_BASE_OFFSET(stream) + (TCP_GET_SEQ(p) - stream->base_seq);
1506  uint64_t packet_rightedge_abs = packet_leftedge_abs + p->payload_len;
1507  SCLogDebug("packet_leftedge_abs %"PRIu64", rightedge %"PRIu64,
1508  packet_leftedge_abs, packet_rightedge_abs);
1509 
1510  const uint8_t *mydata = NULL;
1511  uint32_t mydata_len = 0;
1512  uint64_t mydata_offset = 0;
1513  /* simply return progress from the block we inspected. */
1514  bool return_progress = false;
1515 
1516  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1517  /* continues block */
1518  StreamingBufferGetData(&stream->sb, &mydata, &mydata_len, &mydata_offset);
1519  return_progress = true;
1520 
1521  } else {
1522  SCLogDebug("finding our SBB from offset %"PRIu64, packet_leftedge_abs);
1523  /* find our block */
1524  StreamingBufferBlock key = { .offset = packet_leftedge_abs, .len = p->payload_len };
1525  StreamingBufferBlock *sbb = SBB_RB_FIND_INCLUSIVE(&stream->sb.sbb_tree, &key);
1526  if (sbb) {
1527  SCLogDebug("found %p offset %"PRIu64" len %u", sbb, sbb->offset, sbb->len);
1528  StreamingBufferSBBGetData(&stream->sb, sbb, &mydata, &mydata_len);
1529  mydata_offset = sbb->offset;
1530  }
1531  }
1532 
1533  /* this can only happen if the segment insert of our current 'p' failed */
1534  uint64_t mydata_rightedge_abs = mydata_offset + mydata_len;
1535  if ((mydata == NULL || mydata_len == 0) || /* no data */
1536  (mydata_offset >= packet_rightedge_abs || /* data all to the right */
1537  packet_leftedge_abs >= mydata_rightedge_abs) || /* data all to the left */
1538  (packet_leftedge_abs < mydata_offset || /* data missing at the start */
1539  packet_rightedge_abs > mydata_rightedge_abs)) /* data missing at the end */
1540  {
1541  /* no data, or data is incomplete or wrong: use packet data */
1542  mydata = p->payload;
1543  mydata_len = p->payload_len;
1544  mydata_offset = packet_leftedge_abs;
1545  //mydata_rightedge_abs = packet_rightedge_abs;
1546  } else {
1547  /* adjust buffer to match chunk_size */
1548  SCLogDebug("chunk_size %u mydata_len %u", chunk_size, mydata_len);
1549  if (mydata_len > chunk_size) {
1550  uint32_t excess = mydata_len - chunk_size;
1551  SCLogDebug("chunk_size %u mydata_len %u excess %u", chunk_size, mydata_len, excess);
1552 
1553  if (mydata_rightedge_abs == packet_rightedge_abs) {
1554  mydata += excess;
1555  mydata_len -= excess;
1556  mydata_offset += excess;
1557  SCLogDebug("cutting front of the buffer with %u", excess);
1558  } else if (mydata_offset == packet_leftedge_abs) {
1559  mydata_len -= excess;
1560  SCLogDebug("cutting tail of the buffer with %u", excess);
1561  } else {
1562  uint32_t before = (uint32_t)(packet_leftedge_abs - mydata_offset);
1563  uint32_t after = (uint32_t)(mydata_rightedge_abs - packet_rightedge_abs);
1564  SCLogDebug("before %u after %u", before, after);
1565 
1566  if (after >= (chunk_size - p->payload_len) / 2) {
1567  // more trailing data than we need
1568 
1569  if (before >= (chunk_size - p->payload_len) / 2) {
1570  // also more heading data, divide evenly
1571  before = after = (chunk_size - p->payload_len) / 2;
1572  } else {
1573  // heading data is less than requested, give the
1574  // rest to the trailing data
1575  after = (chunk_size - p->payload_len) - before;
1576  }
1577  } else {
1578  // less trailing data than requested
1579 
1580  if (before >= (chunk_size - p->payload_len) / 2) {
1581  before = (chunk_size - p->payload_len) - after;
1582  } else {
1583  // both smaller than their requested size
1584  }
1585  }
1586 
1587  /* adjust the buffer */
1588  uint32_t skip = (uint32_t)(packet_leftedge_abs - mydata_offset) - before;
1589  uint32_t cut = (uint32_t)(mydata_rightedge_abs - packet_rightedge_abs) - after;
1590  DEBUG_VALIDATE_BUG_ON(skip > mydata_len);
1591  DEBUG_VALIDATE_BUG_ON(cut > mydata_len);
1592  DEBUG_VALIDATE_BUG_ON(skip + cut > mydata_len);
1593  mydata += skip;
1594  mydata_len -= (skip + cut);
1595  mydata_offset += skip;
1596  }
1597  }
1598  }
1599 
1600  /* run the callback */
1601  r = Callback(cb_data, mydata, mydata_len);
1602  BUG_ON(r < 0);
1603 
1604  if (return_progress) {
1605  *progress_out = (mydata_offset + mydata_len);
1606  } else {
1607  /* several blocks of data, so we need to be a bit more careful:
1608  * - if last_ack is beyond last progress, move progress forward to last_ack
1609  * - if our block matches or starts before last ack, return right edge of
1610  * our block.
1611  */
1612  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1613  SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs);
1614 
1615  if (STREAM_RAW_PROGRESS(stream) < last_ack_abs) {
1616  if (mydata_offset > last_ack_abs) {
1617  /* gap between us and last ack, set progress to last ack */
1618  *progress_out = last_ack_abs;
1619  } else {
1620  *progress_out = (mydata_offset + mydata_len);
1621  }
1622  } else {
1623  *progress_out = STREAM_RAW_PROGRESS(stream);
1624  }
1625  }
1626  return r;
1627 }
1628 
1629 /** \brief access 'raw' reassembly data.
1630  *
1631  * Access data as tracked by 'raw' tracker. Data is made available to
1632  * callback that is passed to this function.
1633  *
1634  * In the case of IDS the callback may be run multiple times if data
1635  * contains gaps. It will then be run for each block of data that is
1636  * continuous.
1637  *
1638  * The callback should give on of 2 return values:
1639  * - 0 ok
1640  * - 1 done
1641  * The value 1 will break the loop if there is a block list that is
1642  * inspected.
1643  *
1644  * This function will return the 'progress' value that has been
1645  * consumed until now.
1646  *
1647  * \param ssn tcp session
1648  * \param stream tcp stream
1649  * \param Callback the function pointer to the callback function
1650  * \param cb_data callback data
1651  * \param[in] progress_in progress to work from
1652  * \param[out] progress_out absolute progress value of the data this
1653  * call handled.
1654  * \param eof we're wrapping up so inspect all data we have, incl unACKd
1655  * \param respect_inspect_depth use Stream::min_inspect_depth if set
1656  *
1657  * `respect_inspect_depth` is used to avoid useless inspection of too
1658  * much data.
1659  */
1660 static int StreamReassembleRawDo(TcpSession *ssn, TcpStream *stream,
1661  StreamReassembleRawFunc Callback, void *cb_data,
1662  const uint64_t progress_in,
1663  uint64_t *progress_out, bool eof,
1664  bool respect_inspect_depth)
1665 {
1666  SCEnter();
1667  int r = 0;
1668 
1669  StreamingBufferBlock *iter = NULL;
1670  uint64_t progress = progress_in;
1671  /* absolute right edge of ack'd data */
1672  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1673  SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs);
1674 
1675  /* if the app layer triggered a flush, and we're supposed to
1676  * use a minimal inspect depth, we actually take the app progress
1677  * as that is the right edge of the data. Then we take the window
1678  * of 'min_inspect_depth' before that. */
1679 
1680  SCLogDebug("respect_inspect_depth %s STREAMTCP_STREAM_FLAG_TRIGGER_RAW %s stream->min_inspect_depth %u",
1681  respect_inspect_depth ? "true" : "false",
1682  (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) ? "true" : "false",
1683  stream->min_inspect_depth);
1684 
1685  if (respect_inspect_depth &&
1687  && stream->min_inspect_depth)
1688  {
1689  progress = STREAM_APP_PROGRESS(stream);
1690  if (stream->min_inspect_depth >= progress) {
1691  progress = 0;
1692  } else {
1693  progress -= stream->min_inspect_depth;
1694  }
1695 
1696  SCLogDebug("stream app %"PRIu64", raw %"PRIu64, STREAM_APP_PROGRESS(stream), STREAM_RAW_PROGRESS(stream));
1697 
1698  progress = MIN(progress, STREAM_RAW_PROGRESS(stream));
1699  SCLogDebug("applied min inspect depth due to STREAMTCP_STREAM_FLAG_TRIGGER_RAW: progress %"PRIu64, progress);
1700  }
1701 
1702  SCLogDebug("progress %"PRIu64", min inspect depth %u %s", progress, stream->min_inspect_depth, stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW ? "STREAMTCP_STREAM_FLAG_TRIGGER_RAW":"(no trigger)");
1703 
1704  /* loop through available buffers. On no packet loss we'll have a single
1705  * iteration. On missing data we'll walk the blocks */
1706  while (1) {
1707  const uint8_t *mydata;
1708  uint32_t mydata_len;
1709  uint64_t mydata_offset = 0;
1710 
1711  GetRawBuffer(stream, &mydata, &mydata_len, &iter, progress, &mydata_offset);
1712  if (mydata_len == 0) {
1713  SCLogDebug("no data");
1714  break;
1715  }
1716  //PrintRawDataFp(stdout, mydata, mydata_len);
1717 
1718  SCLogDebug("raw progress %"PRIu64, progress);
1719  SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64,
1720  stream, &stream->sb, mydata_len, progress);
1721 
1722  if (eof) {
1723  // inspect all remaining data, ack'd or not
1724  } else {
1725  if (last_ack_abs < progress) {
1726  SCLogDebug("nothing to do");
1727  goto end;
1728  }
1729 
1730  SCLogDebug("last_ack_abs %"PRIu64", raw_progress %"PRIu64, last_ack_abs, progress);
1731  SCLogDebug("raw_progress + mydata_len %"PRIu64", last_ack_abs %"PRIu64, progress + mydata_len, last_ack_abs);
1732 
1733  /* see if the buffer contains unack'd data as well */
1734  if (progress + mydata_len > last_ack_abs) {
1735  uint32_t check = mydata_len;
1736  mydata_len = last_ack_abs - progress;
1737  BUG_ON(check < mydata_len);
1738  SCLogDebug("data len adjusted to %u to make sure only ACK'd "
1739  "data is considered", mydata_len);
1740  }
1741 
1742  }
1743  if (mydata_len == 0)
1744  break;
1745 
1746  SCLogDebug("data %p len %u", mydata, mydata_len);
1747 
1748  /* we have data. */
1749  r = Callback(cb_data, mydata, mydata_len);
1750  BUG_ON(r < 0);
1751 
1752  if (mydata_offset == progress) {
1753  SCLogDebug("progress %"PRIu64" increasing with data len %u to %"PRIu64,
1754  progress, mydata_len, progress_in + mydata_len);
1755 
1756  progress += mydata_len;
1757  SCLogDebug("raw progress now %"PRIu64, progress);
1758 
1759  /* data is beyond the progress we'd like, and before last ack. Gap. */
1760  } else if (mydata_offset > progress && mydata_offset < last_ack_abs) {
1761  SCLogDebug("GAP: data is missing from %"PRIu64" (%u bytes), setting to first data we have: %"PRIu64, progress, (uint32_t)(mydata_offset - progress), mydata_offset);
1762  SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs);
1763  progress = mydata_offset;
1764  SCLogDebug("raw progress now %"PRIu64, progress);
1765 
1766  } else {
1767  SCLogDebug("not increasing progress, data gap => mydata_offset "
1768  "%"PRIu64" != progress %"PRIu64, mydata_offset, progress);
1769  }
1770 
1771  if (iter == NULL || r == 1)
1772  break;
1773  }
1774 end:
1775  *progress_out = progress;
1776  return r;
1777 }
1778 
1780  StreamReassembleRawFunc Callback, void *cb_data,
1781  uint64_t *progress_out, bool respect_inspect_depth)
1782 {
1783  /* handle inline separately as the logic is very different */
1784  if (StreamTcpInlineMode() == TRUE) {
1785  return StreamReassembleRawInline(ssn, p, Callback, cb_data, progress_out);
1786  }
1787 
1788  TcpStream *stream;
1789  if (PKT_IS_TOSERVER(p)) {
1790  stream = &ssn->client;
1791  } else {
1792  stream = &ssn->server;
1793  }
1794 
1796  StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 0)
1797  {
1798  *progress_out = STREAM_RAW_PROGRESS(stream);
1799  return 0;
1800  }
1801 
1802  return StreamReassembleRawDo(ssn, stream, Callback, cb_data,
1803  STREAM_RAW_PROGRESS(stream), progress_out,
1804  (p->flags & PKT_PSEUDO_STREAM_END), respect_inspect_depth);
1805 }
1806 
1808  StreamReassembleRawFunc Callback, void *cb_data,
1809  uint64_t progress_in,
1810  uint64_t *progress_out, bool eof)
1811 {
1812  if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY))
1813  return 0;
1814 
1815  return StreamReassembleRawDo(ssn, stream, Callback, cb_data,
1816  progress_in, progress_out, eof, false);
1817 }
1818 
1819 /** \internal
1820  * \brief update app layer based on received ACK
1821  *
1822  * \retval r 0 on success, -1 on error
1823  */
1824 static int StreamTcpReassembleHandleSegmentUpdateACK (ThreadVars *tv,
1825  TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p)
1826 {
1827  SCEnter();
1828 
1829  if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, UPDATE_DIR_OPPOSING) < 0)
1830  SCReturnInt(-1);
1831 
1832  SCReturnInt(0);
1833 }
1834 
1836  TcpSession *ssn, TcpStream *stream,
1837  Packet *p, PacketQueueNoLock *pq)
1838 {
1839  SCEnter();
1840 
1841  DEBUG_VALIDATE_BUG_ON(p->tcph == NULL);
1842 
1843  SCLogDebug("ssn %p, stream %p, p %p, p->payload_len %"PRIu16"",
1844  ssn, stream, p, p->payload_len);
1845 
1846  /* default IDS: update opposing side (triggered by ACK) */
1848  /* inline and stream end and flow timeout packets trigger same dir handling */
1849  if (StreamTcpInlineMode()) {
1850  dir = UPDATE_DIR_PACKET;
1851  } else if (p->flags & PKT_PSEUDO_STREAM_END) {
1852  dir = UPDATE_DIR_PACKET;
1853  } else if (p->tcph->th_flags & TH_RST) { // accepted rst
1854  dir = UPDATE_DIR_PACKET;
1855  } else if ((p->tcph->th_flags & TH_FIN) && ssn->state > TCP_TIME_WAIT) {
1856  dir = UPDATE_DIR_PACKET;
1857  } else if (ssn->state == TCP_CLOSED) {
1858  dir = UPDATE_DIR_BOTH;
1859  }
1860 
1861  /* handle ack received */
1862  if ((dir == UPDATE_DIR_OPPOSING || dir == UPDATE_DIR_BOTH)) {
1863  /* we need to update the opposing stream in
1864  * StreamTcpReassembleHandleSegmentUpdateACK */
1865  TcpStream *opposing_stream = NULL;
1866  if (stream == &ssn->client) {
1867  opposing_stream = &ssn->server;
1868  } else {
1869  opposing_stream = &ssn->client;
1870  }
1871 
1872  const bool reversed_before_ack_handling = (p->flow->flags & FLOW_DIR_REVERSED) != 0;
1873 
1874  if (StreamTcpReassembleHandleSegmentUpdateACK(tv, ra_ctx, ssn, opposing_stream, p) != 0) {
1875  SCLogDebug("StreamTcpReassembleHandleSegmentUpdateACK error");
1876  SCReturnInt(-1);
1877  }
1878 
1879  /* StreamTcpReassembleHandleSegmentUpdateACK
1880  * may swap content of ssn->server and ssn->client structures.
1881  * We have to continue with initial content of the stream in such case */
1882  const bool reversed_after_ack_handling = (p->flow->flags & FLOW_DIR_REVERSED) != 0;
1883  if (reversed_before_ack_handling != reversed_after_ack_handling) {
1884  SCLogDebug("TCP streams were swapped");
1885  stream = opposing_stream;
1886  }
1887  }
1888  /* if this segment contains data, insert it */
1889  if (p->payload_len > 0 && !(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
1890  SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData");
1891 
1892  if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) {
1893  SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error");
1894  SCReturnInt(-1);
1895  }
1896 
1897  SCLogDebug("packet %"PRIu64" set PKT_STREAM_ADD", p->pcap_cnt);
1898  p->flags |= PKT_STREAM_ADD;
1899  } else {
1900  SCLogDebug("ssn %p / stream %p: not calling StreamTcpReassembleHandleSegmentHandleData:"
1901  " p->payload_len %u, STREAMTCP_STREAM_FLAG_NOREASSEMBLY %s",
1902  ssn, stream, p->payload_len,
1903  (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ? "true" : "false");
1904 
1905  }
1906 
1907  /* if the STREAMTCP_STREAM_FLAG_DEPTH_REACHED is set, but not the
1908  * STREAMTCP_STREAM_FLAG_NOREASSEMBLY flag, it means the DEPTH flag
1909  * was *just* set. In this case we trigger the AppLayer Truncate
1910  * logic, to inform the applayer no more data in this direction is
1911  * to be expected. */
1912  if ((stream->flags &
1915  {
1916  SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED, truncate applayer");
1917  if (dir != UPDATE_DIR_PACKET) {
1918  SCLogDebug("override: direction now UPDATE_DIR_PACKET so we "
1919  "can trigger Truncate");
1920  dir = UPDATE_DIR_PACKET;
1921  }
1922  }
1923 
1924  /* in stream inline mode even if we have no data we call the reassembly
1925  * functions to handle EOF */
1926  if (dir == UPDATE_DIR_PACKET || dir == UPDATE_DIR_BOTH) {
1927  SCLogDebug("inline (%s) or PKT_PSEUDO_STREAM_END (%s)",
1928  StreamTcpInlineMode()?"true":"false",
1929  (p->flags & PKT_PSEUDO_STREAM_END) ?"true":"false");
1930  if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, dir) < 0) {
1931  SCReturnInt(-1);
1932  }
1933  }
1934 
1935  SCReturnInt(0);
1936 }
1937 
1938 /**
1939  * \brief get a segment from the pool
1940  *
1941  * \retval seg Segment from the pool or NULL
1942  */
1944 {
1945  TcpSegment *seg = (TcpSegment *) PoolThreadGetById(segment_thread_pool, ra_ctx->segment_thread_pool_id);
1946  SCLogDebug("seg we return is %p", seg);
1947  if (seg == NULL) {
1948  /* Increment the counter to show that we are not able to serve the
1949  segment request due to memcap limit */
1951  } else {
1952  memset(&seg->sbseg, 0, sizeof(seg->sbseg));
1953  }
1954 
1955  return seg;
1956 }
1957 
1958 /**
1959  * \brief Trigger RAW stream reassembly
1960  *
1961  * Used by AppLayerTriggerRawStreamReassembly to trigger RAW stream
1962  * reassembly from the applayer, for example upon completion of a
1963  * HTTP request.
1964  *
1965  * It sets a flag in the stream so that the next Raw call will return
1966  * the data.
1967  *
1968  * \param ssn TcpSession
1969  */
1971 {
1972 #ifdef DEBUG
1973  BUG_ON(ssn == NULL);
1974 #endif
1975 
1976  if (ssn != NULL) {
1977  if (direction == STREAM_TOSERVER) {
1979  } else {
1981  }
1982 
1983  SCLogDebug("flagged ssn %p for immediate raw reassembly", ssn);
1984  }
1985 }
1986 
1987 void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
1988 {
1989 #ifdef DEBUG
1990  BUG_ON(ssn == NULL);
1991 #endif
1992 
1993  if (ssn != NULL) {
1994  if (direction == STREAM_TOSERVER) {
1995  ssn->client.min_inspect_depth = depth;
1996  SCLogDebug("ssn %p: set client.min_inspect_depth to %u", ssn, depth);
1997  } else {
1998  ssn->server.min_inspect_depth = depth;
1999  SCLogDebug("ssn %p: set server.min_inspect_depth to %u", ssn, depth);
2000  }
2001  }
2002 }
2003 
2004 #ifdef UNITTESTS
2005 /** unit tests and it's support functions below */
2006 
2007 #define SET_ISN(stream, setseq) \
2008  (stream)->isn = (setseq); \
2009  (stream)->base_seq = (setseq) + 1
2010 
2011 /** \brief The Function to create the packet with given payload, which is used
2012  * to test the reassembly of the engine.
2013  *
2014  * \param payload The variable used to store the payload contents of the
2015  * current packet.
2016  * \param value The value which current payload will have for this packet
2017  * \param payload_len The length of the filed payload for current packet.
2018  * \param len Length of the payload array
2019  */
2020 
2021 void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value,
2022  uint8_t payload_len, uint8_t len)
2023 {
2024  uint8_t i;
2025  for (i = 0; i < payload_len; i++)
2026  payload[i] = value;
2027  for (; i < len; i++)
2028  payload = NULL;
2029 }
2030 
2031 /** \brief The Function Checks the reassembled stream contents against predefined
2032  * stream contents according to OS policy used.
2033  *
2034  * \param stream_policy Predefined value of stream for different OS policies
2035  * \param stream Reassembled stream returned from the reassembly functions
2036  */
2037 
2038 int StreamTcpCheckStreamContents(uint8_t *stream_policy, uint16_t sp_size, TcpStream *stream)
2039 {
2040  if (StreamingBufferCompareRawData(&stream->sb, stream_policy,(uint32_t)sp_size) == 0)
2041  {
2042  //PrintRawDataFp(stdout, stream_policy, sp_size);
2043  return 0;
2044  }
2045  return 1;
2046 }
2047 
2048 static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len)
2049 {
2050  if (StreamingBufferCompareRawData(&stream->sb,
2051  data, data_len) == 0)
2052  {
2053  SCReturnInt(0);
2054  }
2055  SCLogInfo("OK");
2056  PrintRawDataFp(stdout, data, data_len);
2057  return 1;
2058 }
2059 
2060 #define MISSED_START(isn) \
2061  TcpReassemblyThreadCtx *ra_ctx = NULL; \
2062  TcpSession ssn; \
2063  ThreadVars tv; \
2064  memset(&tv, 0, sizeof(tv)); \
2065  \
2066  StreamTcpUTInit(&ra_ctx); \
2067  \
2068  StreamTcpUTSetupSession(&ssn); \
2069  StreamTcpUTSetupStream(&ssn.server, (isn)); \
2070  StreamTcpUTSetupStream(&ssn.client, (isn)); \
2071  \
2072  TcpStream *stream = &ssn.client;
2073 
2074 #define MISSED_END \
2075  StreamTcpUTClearSession(&ssn); \
2076  StreamTcpUTDeinit(ra_ctx); \
2077  PASS
2078 
2079 #define MISSED_STEP(seq, seg, seglen, buf, buflen) \
2080  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen)); \
2081  FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen))));
2082 
2083 /**
2084  * \test Test the handling of packets missed by both IDS and the end host.
2085  * The packet is missed in the starting of the stream.
2086  *
2087  * \retval On success it returns 1 and on failure 0.
2088  */
2089 
2090 static int StreamTcpReassembleTest25 (void)
2091 {
2092  MISSED_START(6);
2093  MISSED_STEP(10, "BB", 2, "\0\0\0BB", 5);
2094  MISSED_STEP(12, "CC", 2, "\0\0\0BBCC", 7);
2095  MISSED_STEP(7, "AAA", 3, "AAABBCC", 7);
2096  MISSED_END;
2097 }
2098 
2099 /**
2100  * \test Test the handling of packets missed by both IDS and the end host.
2101  * The packet is missed in the middle of the stream.
2102  *
2103  * \retval On success it returns 1 and on failure 0.
2104  */
2105 
2106 static int StreamTcpReassembleTest26 (void)
2107 {
2108  MISSED_START(9);
2109  MISSED_STEP(10, "AAA", 3, "AAA", 3);
2110  MISSED_STEP(15, "CC", 2, "AAA\0\0CC", 7);
2111  MISSED_STEP(13, "BB", 2, "AAABBCC", 7);
2112  MISSED_END;
2113 }
2114 
2115 /**
2116  * \test Test the handling of packets missed by both IDS and the end host.
2117  * The packet is missed in the end of the stream.
2118  *
2119  * \retval On success it returns 1 and on failure 0.
2120  */
2121 
2122 static int StreamTcpReassembleTest27 (void)
2123 {
2124  MISSED_START(9);
2125  MISSED_STEP(10, "AAA", 3, "AAA", 3);
2126  MISSED_STEP(13, "BB", 2, "AAABB", 5);
2127  MISSED_STEP(15, "CC", 2, "AAABBCC", 7);
2128  MISSED_END;
2129 }
2130 
2131 /**
2132  * \test Test the handling of packets missed by IDS, but the end host has
2133  * received it and send the acknowledgment of it. The packet is missed
2134  * in the starting of the stream.
2135  *
2136  * \retval On success it returns 1 and on failure 0.
2137  */
2138 
2139 static int StreamTcpReassembleTest28 (void)
2140 {
2141  MISSED_START(6);
2142  MISSED_STEP(10, "AAA", 3, "\0\0\0AAA", 6);
2143  MISSED_STEP(13, "BB", 2, "\0\0\0AAABB", 8);
2144  ssn.state = TCP_TIME_WAIT;
2145  MISSED_STEP(15, "CC", 2, "\0\0\0AAABBCC", 10);
2146  MISSED_END;
2147 }
2148 
2149 /**
2150  * \test Test the handling of packets missed by IDS, but the end host has
2151  * received it and send the acknowledgment of it. The packet is missed
2152  * in the middle of the stream.
2153  *
2154  * \retval On success it returns 1 and on failure 0.
2155  */
2156 
2157 static int StreamTcpReassembleTest29 (void)
2158 {
2159  MISSED_START(9);
2160  MISSED_STEP(10, "AAA", 3, "AAA", 3);
2161  ssn.state = TCP_TIME_WAIT;
2162  MISSED_STEP(15, "CC", 2, "AAA\0\0CC", 7);
2163  MISSED_END;
2164 }
2165 
2166 static int StreamTcpReassembleTest33(void)
2167 {
2168  TcpSession ssn;
2169  Packet *p = PacketGetFromAlloc();
2170  FAIL_IF(unlikely(p == NULL));
2171  Flow f;
2172  TCPHdr tcph;
2173  TcpReassemblyThreadCtx *ra_ctx = NULL;
2175  uint8_t packet[1460] = "";
2176 
2177  StreamTcpUTInit(&ra_ctx);
2179 
2180  PacketQueueNoLock pq;
2181  memset(&pq,0,sizeof(PacketQueueNoLock));
2182  memset(&f, 0, sizeof (Flow));
2183  memset(&tcph, 0, sizeof (TCPHdr));
2184  ThreadVars tv;
2185  memset(&tv, 0, sizeof (ThreadVars));
2186  FLOW_INITIALIZE(&f);
2187  f.protoctx = &ssn;
2188  f.proto = IPPROTO_TCP;
2189  p->src.family = AF_INET;
2190  p->dst.family = AF_INET;
2191  p->proto = IPPROTO_TCP;
2192  p->flow = &f;
2193  tcph.th_win = 5480;
2194  tcph.th_flags = TH_PUSH | TH_ACK;
2195  p->tcph = &tcph;
2197  p->payload = packet;
2198 
2199  p->tcph->th_seq = htonl(10);
2200  p->tcph->th_ack = htonl(31);
2201  p->payload_len = 10;
2202 
2203  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
2204 
2205  p->tcph->th_seq = htonl(20);
2206  p->tcph->th_ack = htonl(31);
2207  p->payload_len = 10;
2208 
2209  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
2210 
2211  p->tcph->th_seq = htonl(40);
2212  p->tcph->th_ack = htonl(31);
2213  p->payload_len = 10;
2214 
2215  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
2216 
2217  p->tcph->th_seq = htonl(5);
2218  p->tcph->th_ack = htonl(31);
2219  p->payload_len = 30;
2220 
2221  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
2222 
2224  StreamTcpUTDeinit(ra_ctx);
2225  SCFree(p);
2226  PASS;
2227 }
2228 
2229 static int StreamTcpReassembleTest34(void)
2230 {
2231  TcpSession ssn;
2232  Packet *p = PacketGetFromAlloc();
2233  FAIL_IF(unlikely(p == NULL));
2234  Flow f;
2235  TCPHdr tcph;
2236  TcpReassemblyThreadCtx *ra_ctx = NULL;
2238  uint8_t packet[1460] = "";
2239 
2240  StreamTcpUTInit(&ra_ctx);
2242  PacketQueueNoLock pq;
2243  memset(&pq,0,sizeof(PacketQueueNoLock));
2244  memset(&f, 0, sizeof (Flow));
2245  memset(&tcph, 0, sizeof (TCPHdr));
2246  ThreadVars tv;
2247  memset(&tv, 0, sizeof (ThreadVars));
2248  FLOW_INITIALIZE(&f);
2249  f.protoctx = &ssn;
2250  f.proto = IPPROTO_TCP;
2251  p->src.family = AF_INET;
2252  p->dst.family = AF_INET;
2253  p->proto = IPPROTO_TCP;
2254  p->flow = &f;
2255  tcph.th_win = 5480;
2256  tcph.th_flags = TH_PUSH | TH_ACK;
2257  p->tcph = &tcph;
2259  p->payload = packet;
2260  SET_ISN(&ssn.client, 857961230);
2261 
2262  p->tcph->th_seq = htonl(857961230);
2263  p->tcph->th_ack = htonl(31);
2264  p->payload_len = 304;
2265 
2266  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
2267 
2268  p->tcph->th_seq = htonl(857961534);
2269  p->tcph->th_ack = htonl(31);
2270  p->payload_len = 1460;
2271 
2272  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
2273 
2274  p->tcph->th_seq = htonl(857963582);
2275  p->tcph->th_ack = htonl(31);
2276  p->payload_len = 1460;
2277 
2278  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
2279 
2280  p->tcph->th_seq = htonl(857960946);
2281  p->tcph->th_ack = htonl(31);
2282  p->payload_len = 1460;
2283 
2284  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
2285 
2287  StreamTcpUTDeinit(ra_ctx);
2288  SCFree(p);
2289  PASS;
2290 }
2291 
2292 /** \test Test the bug 76 condition */
2293 static int StreamTcpReassembleTest37(void)
2294 {
2295  TcpSession ssn;
2296  Flow f;
2297  TCPHdr tcph;
2298  TcpReassemblyThreadCtx *ra_ctx = NULL;
2299  uint8_t packet[1460] = "";
2300  PacketQueueNoLock pq;
2301  ThreadVars tv;
2302  memset(&tv, 0, sizeof (ThreadVars));
2303 
2304  Packet *p = PacketGetFromAlloc();
2305  FAIL_IF(unlikely(p == NULL));
2306 
2307  StreamTcpUTInit(&ra_ctx);
2309  memset(&pq,0,sizeof(PacketQueueNoLock));
2310  memset(&f, 0, sizeof (Flow));
2311  memset(&tcph, 0, sizeof (TCPHdr));
2312  memset(&tv, 0, sizeof (ThreadVars));
2313 
2314  FLOW_INITIALIZE(&f);
2315  f.protoctx = &ssn;
2316  f.proto = IPPROTO_TCP;
2317  p->src.family = AF_INET;
2318  p->dst.family = AF_INET;
2319  p->proto = IPPROTO_TCP;
2320  p->flow = &f;
2321  tcph.th_win = 5480;
2322  tcph.th_flags = TH_PUSH | TH_ACK;
2323  p->tcph = &tcph;
2325  p->payload = packet;
2327 
2328  p->tcph->th_seq = htonl(3061088537UL);
2329  p->tcph->th_ack = htonl(1729548549UL);
2330  p->payload_len = 1391;
2331  ssn.client.last_ack = 3061091137UL;
2332  SET_ISN(&ssn.client, 3061091309UL);
2333 
2334  /* pre base_seq, so should be rejected */
2335  FAIL_IF (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) != -1);
2336 
2337  p->tcph->th_seq = htonl(3061089928UL);
2338  p->tcph->th_ack = htonl(1729548549UL);
2339  p->payload_len = 1391;
2340  ssn.client.last_ack = 3061091137UL;
2341 
2342  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
2343 
2344  p->tcph->th_seq = htonl(3061091319UL);
2345  p->tcph->th_ack = htonl(1729548549UL);
2346  p->payload_len = 1391;
2347  ssn.client.last_ack = 3061091137UL;
2348 
2349  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
2350 
2352  StreamTcpUTDeinit(ra_ctx);
2353  SCFree(p);
2354  PASS;
2355 }
2356 
2357 /**
2358  * \test Test to make sure that we don't return the segments until the app
2359  * layer proto has been detected and after that remove the processed
2360  * segments.
2361  *
2362  * \retval On success it returns 1 and on failure 0.
2363  */
2364 
2365 static int StreamTcpReassembleTest39 (void)
2366 {
2367  Packet *p = PacketGetFromAlloc();
2368  FAIL_IF(unlikely(p == NULL));
2369  Flow f;
2370  ThreadVars tv;
2371  StreamTcpThread stt;
2372  TCPHdr tcph;
2373  PacketQueueNoLock pq;
2374  memset(&pq,0,sizeof(PacketQueueNoLock));
2375  memset (&f, 0, sizeof(Flow));
2376  memset(&tv, 0, sizeof (ThreadVars));
2377  memset(&stt, 0, sizeof (stt));
2378  memset(&tcph, 0, sizeof (TCPHdr));
2379 
2380  FLOW_INITIALIZE(&f);
2381  f.flags = FLOW_IPV4;
2382  f.proto = IPPROTO_TCP;
2383  p->flow = &f;
2384  p->tcph = &tcph;
2385 
2386  StreamTcpUTInit(&stt.ra_ctx);
2387 
2388  /* handshake */
2389  tcph.th_win = htons(5480);
2390  tcph.th_flags = TH_SYN;
2392  p->payload_len = 0;
2393  p->payload = NULL;
2394  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2395 
2396  TcpSession *ssn = (TcpSession *)f.protoctx;
2397  FAIL_IF_NULL(ssn);
2398 
2405  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2406  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2407  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2408  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2409  FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
2410  FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2411  FAIL_IF(ssn->data_first_seen_dir != 0);
2412 
2413  /* handshake */
2414  p->tcph->th_ack = htonl(1);
2415  p->tcph->th_flags = TH_SYN | TH_ACK;
2417  p->payload_len = 0;
2418  p->payload = NULL;
2419  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2426  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2427  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2428  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2429  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2430  FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
2431  FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2432  FAIL_IF(ssn->data_first_seen_dir != 0);
2433 
2434  /* handshake */
2435  p->tcph->th_ack = htonl(1);
2436  p->tcph->th_seq = htonl(1);
2437  p->tcph->th_flags = TH_ACK;
2439  p->payload_len = 0;
2440  p->payload = NULL;
2441  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2448  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2449  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2450  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2451  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2452  FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
2453  FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2454  FAIL_IF(ssn->data_first_seen_dir != 0);
2455 
2456  /* partial request */
2457  uint8_t request1[] = { 0x47, 0x45, };
2458  p->tcph->th_ack = htonl(1);
2459  p->tcph->th_seq = htonl(1);
2460  p->tcph->th_flags = TH_PUSH | TH_ACK;
2462  p->payload_len = sizeof(request1);
2463  p->payload = request1;
2464  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2471  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2472  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2473  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2474  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2475  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2476  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2477  FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2478  FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
2479 
2480  /* response ack against partial request */
2481  p->tcph->th_ack = htonl(3);
2482  p->tcph->th_seq = htonl(1);
2483  p->tcph->th_flags = TH_ACK;
2485  p->payload_len = 0;
2486  p->payload = NULL;
2487  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2494  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2495  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2496  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2497  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2498  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2499  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2500  FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2501  FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
2502 
2503  /* complete partial request */
2504  uint8_t request2[] = {
2505  0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64,
2506  0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20,
2507  0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30,
2508  0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20,
2509  0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73,
2510  0x74, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d,
2511  0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x41,
2512  0x70, 0x61, 0x63, 0x68, 0x65, 0x42, 0x65, 0x6e,
2513  0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a,
2514  0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20,
2515  0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a };
2516  p->tcph->th_ack = htonl(1);
2517  p->tcph->th_seq = htonl(3);
2518  p->tcph->th_flags = TH_PUSH | TH_ACK;
2520  p->payload_len = sizeof(request2);
2521  p->payload = request2;
2522  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2529  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2530  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2531  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2532  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2533  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2534  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2535  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2536  FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2537  FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
2538 
2539  /* response - request ack */
2540  uint8_t response[] = {
2541  0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31,
2542  0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d,
2543  0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x46,
2544  0x72, 0x69, 0x2c, 0x20, 0x32, 0x33, 0x20, 0x53,
2545  0x65, 0x70, 0x20, 0x32, 0x30, 0x31, 0x31, 0x20,
2546  0x30, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x39,
2547  0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65,
2548  0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x41, 0x70,
2549  0x61, 0x63, 0x68, 0x65, 0x2f, 0x32, 0x2e, 0x32,
2550  0x2e, 0x31, 0x35, 0x20, 0x28, 0x55, 0x6e, 0x69,
2551  0x78, 0x29, 0x20, 0x44, 0x41, 0x56, 0x2f, 0x32,
2552  0x0d, 0x0a, 0x4c, 0x61, 0x73, 0x74, 0x2d, 0x4d,
2553  0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x3a,
2554  0x20, 0x54, 0x68, 0x75, 0x2c, 0x20, 0x30, 0x34,
2555  0x20, 0x4e, 0x6f, 0x76, 0x20, 0x32, 0x30, 0x31,
2556  0x30, 0x20, 0x31, 0x35, 0x3a, 0x30, 0x34, 0x3a,
2557  0x34, 0x36, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a,
2558  0x45, 0x54, 0x61, 0x67, 0x3a, 0x20, 0x22, 0x61,
2559  0x62, 0x38, 0x39, 0x36, 0x35, 0x2d, 0x32, 0x63,
2560  0x2d, 0x34, 0x39, 0x34, 0x33, 0x62, 0x37, 0x61,
2561  0x37, 0x66, 0x37, 0x66, 0x38, 0x30, 0x22, 0x0d,
2562  0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d,
2563  0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x3a, 0x20,
2564  0x62, 0x79, 0x74, 0x65, 0x73, 0x0d, 0x0a, 0x43,
2565  0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c,
2566  0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x34,
2567  0x34, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
2568  0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63,
2569  0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, 0x43, 0x6f,
2570  0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79,
2571  0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74,
2572  0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x58,
2573  0x2d, 0x50, 0x61, 0x64, 0x3a, 0x20, 0x61, 0x76,
2574  0x6f, 0x69, 0x64, 0x20, 0x62, 0x72, 0x6f, 0x77,
2575  0x73, 0x65, 0x72, 0x20, 0x62, 0x75, 0x67, 0x0d,
2576  0x0a, 0x0d, 0x0a, 0x3c, 0x68, 0x74, 0x6d, 0x6c,
2577  0x3e, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c,
2578  0x68, 0x31, 0x3e, 0x49, 0x74, 0x20, 0x77, 0x6f,
2579  0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31,
2580  0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e,
2581  0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e };
2582  p->tcph->th_ack = htonl(88);
2583  p->tcph->th_seq = htonl(1);
2584  p->tcph->th_flags = TH_PUSH | TH_ACK;
2586  p->payload_len = sizeof(response);
2587  p->payload = response;
2588 
2589  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2596  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2597  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2598  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2599  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2601  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2602  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2603  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2604  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2605 
2606  /* response ack from request */
2607  p->tcph->th_ack = htonl(328);
2608  p->tcph->th_seq = htonl(88);
2609  p->tcph->th_flags = TH_ACK;
2611  p->payload_len = 0;
2612  p->payload = NULL;
2613  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2620  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2621  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2622  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2623  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2625  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2626  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2627  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2628  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2629  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2630 
2631  /* response - acking */
2632  p->tcph->th_ack = htonl(88);
2633  p->tcph->th_seq = htonl(328);
2634  p->tcph->th_flags = TH_PUSH | TH_ACK;
2636  p->payload_len = 0;
2637  p->payload = NULL;
2638  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2645  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2646  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2647  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2648  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2650  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2651  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2652  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2653  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2654  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2655 
2656  /* response ack from request */
2657  p->tcph->th_ack = htonl(328);
2658  p->tcph->th_seq = htonl(88);
2659  p->tcph->th_flags = TH_ACK;
2661  p->payload_len = 0;
2662  p->payload = NULL;
2663  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2670  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2671  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2672  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2673  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2675  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2676  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2677  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2678  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2679 
2680  /* response - acking the request again*/
2681  p->tcph->th_ack = htonl(88);
2682  p->tcph->th_seq = htonl(328);
2683  p->tcph->th_flags = TH_PUSH | TH_ACK;
2685  p->payload_len = 0;
2686  p->payload = NULL;
2687  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2694  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2695  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2696  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2697  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2699  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2700  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2701  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2702  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2703 
2704  /*** New Request ***/
2705 
2706  /* partial request */
2707  p->tcph->th_ack = htonl(328);
2708  p->tcph->th_seq = htonl(88);
2709  p->tcph->th_flags = TH_PUSH | TH_ACK;
2711  p->payload_len = sizeof(request1);
2712  p->payload = request1;
2713  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2720  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2721  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2722  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2723  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2725  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2726  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2727  FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2728  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2729  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2730 
2731  /* response ack against partial request */
2732  p->tcph->th_ack = htonl(90);
2733  p->tcph->th_seq = htonl(328);
2734  p->tcph->th_flags = TH_ACK;
2736  p->payload_len = 0;
2737  p->payload = NULL;
2738  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2739  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2746  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2747  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2748  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2749  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2751  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2752  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2753  FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2754  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2755  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2756 
2757  /* complete request */
2758  p->tcph->th_ack = htonl(328);
2759  p->tcph->th_seq = htonl(90);
2760  p->tcph->th_flags = TH_PUSH | TH_ACK;
2762  p->payload_len = sizeof(request2);
2763  p->payload = request2;
2764  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2771  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2772  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2773  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2774  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2776  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2777  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2778  FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2779  FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
2780  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2781  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2782 
2783  /* response ack against second partial request */
2784  p->tcph->th_ack = htonl(175);
2785  p->tcph->th_seq = htonl(328);
2786  p->tcph->th_flags = TH_ACK;
2788  p->payload_len = 0;
2789  p->payload = NULL;
2790 
2791  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2798  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2799  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2800  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2801  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2803  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2804  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2805  FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2806  FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
2807  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2808  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2809 
2810  /* response acking a request */
2811  p->tcph->th_ack = htonl(175);
2812  p->tcph->th_seq = htonl(328);
2813  p->tcph->th_flags = TH_ACK;
2815  p->payload_len = 0;
2816  p->payload = NULL;
2817  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2823 
2824  StreamTcpPruneSession(&f, STREAM_TOSERVER);
2825  StreamTcpPruneSession(&f, STREAM_TOCLIENT);
2826 
2827  /* request acking a response */
2828  p->tcph->th_ack = htonl(328);
2829  p->tcph->th_seq = htonl(175);
2830  p->tcph->th_flags = TH_ACK;
2832  p->payload_len = 0;
2833  p->payload = NULL;
2834  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2835 
2836  StreamTcpSessionClear(ssn);
2838  SCFree(p);
2839  PASS;
2840 }
2841 
2842 /**
2843  * \test Test to make sure that we sent all the segments from the initial
2844  * segments to app layer until we have detected the app layer proto.
2845  *
2846  * \retval On success it returns 1 and on failure 0.
2847  */
2848 
2849 static int StreamTcpReassembleTest40 (void)
2850 {
2851  Packet *p = PacketGetFromAlloc();
2852  FAIL_IF_NULL(p);
2853  Flow *f = NULL;
2854  TCPHdr tcph;
2855  TcpSession ssn;
2856  PacketQueueNoLock pq;
2857  memset(&pq,0,sizeof(PacketQueueNoLock));
2858  memset(&tcph, 0, sizeof (TCPHdr));
2859  ThreadVars tv;
2860  memset(&tv, 0, sizeof (ThreadVars));
2861 
2862  StreamTcpInitConfig(true);
2864 
2866  FAIL_IF_NULL(ra_ctx);
2867 
2868  uint8_t httpbuf1[] = "P";
2869  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2870  uint8_t httpbuf3[] = "O";
2871  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
2872  uint8_t httpbuf4[] = "S";
2873  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
2874  uint8_t httpbuf5[] = "T \r\n";
2875  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
2876 
2877  uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
2878  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
2879 
2880  SET_ISN(&ssn.server, 9);
2881  ssn.server.last_ack = 10;
2882  SET_ISN(&ssn.client, 9);
2883  ssn.client.isn = 9;
2884 
2885  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
2886  FAIL_IF_NULL(f);
2887  f->protoctx = &ssn;
2888  f->proto = IPPROTO_TCP;
2889  p->flow = f;
2890 
2891  tcph.th_win = htons(5480);
2892  tcph.th_seq = htonl(10);
2893  tcph.th_ack = htonl(10);
2894  tcph.th_flags = TH_ACK|TH_PUSH;
2895  p->tcph = &tcph;
2897  p->payload = httpbuf1;
2898  p->payload_len = httplen1;
2899  ssn.state = TCP_ESTABLISHED;
2900  TcpStream *s = &ssn.client;
2901  SCLogDebug("1 -- start");
2902  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1);
2903 
2905  p->payload = httpbuf2;
2906  p->payload_len = httplen2;
2907  tcph.th_seq = htonl(10);
2908  tcph.th_ack = htonl(11);
2909  s = &ssn.server;
2910  ssn.server.last_ack = 11;
2911  SCLogDebug("2 -- start");
2912  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1);
2913 
2915  p->payload = httpbuf3;
2916  p->payload_len = httplen3;
2917  tcph.th_seq = htonl(11);
2918  tcph.th_ack = htonl(55);
2919  s = &ssn.client;
2920  ssn.client.last_ack = 55;
2921  SCLogDebug("3 -- start");
2922  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1);
2923 
2925  p->payload = httpbuf2;
2926  p->payload_len = httplen2;
2927  tcph.th_seq = htonl(55);
2928  tcph.th_ack = htonl(12);
2929  s = &ssn.server;
2930  ssn.server.last_ack = 12;
2931  SCLogDebug("4 -- start");
2932  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1);
2933 
2934  /* check is have the segment in the list and flagged or not */
2935  TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
2936  FAIL_IF_NULL(seg);
2937  FAIL_IF(SEGMENT_BEFORE_OFFSET(&ssn.client, seg, STREAM_APP_PROGRESS(&ssn.client)));
2938 
2940  p->payload = httpbuf4;
2941  p->payload_len = httplen4;
2942  tcph.th_seq = htonl(12);
2943  tcph.th_ack = htonl(100);
2944  s = &ssn.client;
2945  ssn.client.last_ack = 100;
2946  SCLogDebug("5 -- start");
2947  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1);
2948 
2950  p->payload = httpbuf2;
2951  p->payload_len = httplen2;
2952  tcph.th_seq = htonl(100);
2953  tcph.th_ack = htonl(13);
2954  s = &ssn.server;
2955  ssn.server.last_ack = 13;
2956  SCLogDebug("6 -- start");
2957  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1);
2958 
2960  p->payload = httpbuf5;
2961  p->payload_len = httplen5;
2962  tcph.th_seq = htonl(13);
2963  tcph.th_ack = htonl(145);
2964  s = &ssn.client;
2965  ssn.client.last_ack = 145;
2966  SCLogDebug("7 -- start");
2967  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1);
2968 
2970  p->payload = httpbuf2;
2971  p->payload_len = httplen2;
2972  tcph.th_seq = htonl(145);
2973  tcph.th_ack = htonl(16);
2974  s = &ssn.server;
2975  ssn.server.last_ack = 16;
2976  SCLogDebug("8 -- start");
2977  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1);
2978  FAIL_IF(f->alproto != ALPROTO_HTTP1);
2979 
2982  StreamTcpFreeConfig(true);
2983  SCFree(p);
2984  UTHFreeFlow(f);
2985  PASS;
2986 }
2987 
2988 /** \test Test the memcap incrementing/decrementing and memcap check */
2989 static int StreamTcpReassembleTest44(void)
2990 {
2991  StreamTcpInitConfig(true);
2992  uint32_t memuse = SC_ATOMIC_GET(ra_memuse);
2994  FAIL_IF(SC_ATOMIC_GET(ra_memuse) != (memuse+500));
2996  FAIL_IF(SC_ATOMIC_GET(ra_memuse) != memuse);
2998  FAIL_IF(StreamTcpReassembleCheckMemcap((1 + memuse + SC_ATOMIC_GET(stream_config.reassembly_memcap))) != 0);
2999  StreamTcpFreeConfig(true);
3000  FAIL_IF(SC_ATOMIC_GET(ra_memuse) != 0);
3001  PASS;
3002 }
3003 
3004 /**
3005  * \test Test to make sure that reassembly_depth is enforced.
3006  *
3007  * \retval On success it returns 1 and on failure 0.
3008  */
3009 
3010 static int StreamTcpReassembleTest45 (void)
3011 {
3012  TcpReassemblyThreadCtx *ra_ctx = NULL;
3013  TcpSession ssn;
3014  ThreadVars tv;
3015  memset(&tv, 0, sizeof(tv));
3016  uint8_t payload[100] = {0};
3017  uint16_t payload_size = 100;
3018 
3019  StreamTcpUTInit(&ra_ctx);
3021 
3023  ssn.reassembly_depth = 100;
3024  StreamTcpUTSetupStream(&ssn.server, 100);
3025  StreamTcpUTSetupStream(&ssn.client, 100);
3026 
3027  int r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size);
3028  FAIL_IF(r != 0);
3030 
3031  r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size);
3032  FAIL_IF(r != 0);
3034 
3038  StreamTcpUTDeinit(ra_ctx);
3039  PASS;
3040 }
3041 
3042 /**
3043  * \test Test the unlimited config value of reassembly depth.
3044  *
3045  * \retval On success it returns 1 and on failure 0.
3046  */
3047 
3048 static int StreamTcpReassembleTest46 (void)
3049 {
3050  int result = 0;
3051  TcpReassemblyThreadCtx *ra_ctx = NULL;
3052  TcpSession ssn;
3053  ThreadVars tv;
3054  memset(&tv, 0, sizeof(tv));
3055  uint8_t payload[100] = {0};
3056  uint16_t payload_size = 100;
3057 
3058  StreamTcpUTInit(&ra_ctx);
3060 
3062  StreamTcpUTSetupStream(&ssn.server, 100);
3063  StreamTcpUTSetupStream(&ssn.client, 100);
3064 
3065  int r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size);
3066  if (r != 0)
3067  goto end;
3069  printf("STREAMTCP_STREAM_FLAG_NOREASSEMBLY set: ");
3070  goto end;
3071  }
3072 
3073  r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size);
3074  if (r != 0)
3075  goto end;
3077  printf("STREAMTCP_STREAM_FLAG_NOREASSEMBLY set: ");
3078  goto end;
3079  }
3080 
3081  result = 1;
3082 end:
3086  StreamTcpUTDeinit(ra_ctx);
3087  return result;
3088 }
3089 
3090 /**
3091  * \test Test to make sure we detect the sequence wrap around and continue
3092  * stream reassembly properly.
3093  *
3094  * \retval On success it returns 1 and on failure 0.
3095  */
3096 
3097 static int StreamTcpReassembleTest47 (void)
3098 {
3099  Packet *p = PacketGetFromAlloc();
3100  FAIL_IF(unlikely(p == NULL));
3101  Flow *f = NULL;
3102  TCPHdr tcph;
3103  TcpSession ssn;
3104  ThreadVars tv;
3105  PacketQueueNoLock pq;
3106  memset(&pq,0,sizeof(PacketQueueNoLock));
3107  memset(&tcph, 0, sizeof (TCPHdr));
3108  memset(&tv, 0, sizeof (ThreadVars));
3109  StreamTcpInitConfig(true);
3112 
3113  uint8_t httpbuf1[] = "GET /EVILSUFF HTTP/1.1\r\n\r\n";
3114  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3115 
3116  SET_ISN(&ssn.server, 572799781UL);
3117  ssn.server.last_ack = 572799782UL;
3118 
3119  SET_ISN(&ssn.client, 4294967289UL);
3120  ssn.client.last_ack = 21;
3121 
3122  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
3123  FAIL_IF(f == NULL);
3124  f->protoctx = &ssn;
3125  f->proto = IPPROTO_TCP;
3126  p->flow = f;
3127 
3128  tcph.th_win = htons(5480);
3129  ssn.state = TCP_ESTABLISHED;
3130  TcpStream *s = NULL;
3131  uint8_t cnt = 0;
3132 
3133  for (cnt=0; cnt < httplen1; cnt++) {
3134  tcph.th_seq = htonl(ssn.client.isn + 1 + cnt);
3135  tcph.th_ack = htonl(572799782UL);
3136  tcph.th_flags = TH_ACK|TH_PUSH;
3137  p->tcph = &tcph;
3139  p->payload = &httpbuf1[cnt];
3140  p->payload_len = 1;
3141  s = &ssn.client;
3142 
3143  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1);
3144 
3146  p->payload = NULL;
3147  p->payload_len = 0;
3148  tcph.th_seq = htonl(572799782UL);
3149  tcph.th_ack = htonl(ssn.client.isn + 1 + cnt);
3150  tcph.th_flags = TH_ACK;
3151  p->tcph = &tcph;
3152  s = &ssn.server;
3153 
3154  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1);
3155  }
3156 
3157  FAIL_IF(f->alproto != ALPROTO_HTTP1);
3158 
3161  StreamTcpFreeConfig(true);
3162  SCFree(p);
3163  UTHFreeFlow(f);
3164  PASS;
3165 }
3166 
3167 /** \test 3 in order segments in inline reassembly */
3168 static int StreamTcpReassembleInlineTest01(void)
3169 {
3170  int ret = 0;
3171  TcpReassemblyThreadCtx *ra_ctx = NULL;
3172  ThreadVars tv;
3173  TcpSession ssn;
3174  Flow f;
3175 
3176  memset(&tv, 0x00, sizeof(tv));
3177 
3178  StreamTcpUTInit(&ra_ctx);
3181  StreamTcpUTSetupStream(&ssn.client, 1);
3182  FLOW_INITIALIZE(&f);
3183 
3184  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3185  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3186  if (p == NULL) {
3187  printf("couldn't get a packet: ");
3188  goto end;
3189  }
3190  p->tcph->th_seq = htonl(12);
3191  p->flow = &f;
3192 
3193  FLOWLOCK_WRLOCK(&f);
3194  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) {
3195  printf("failed to add segment 1: ");
3196  goto end;
3197  }
3198  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) {
3199  printf("failed to add segment 2: ");
3200  goto end;
3201  }
3202  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3203  printf("failed to add segment 3: ");
3204  goto end;
3205  }
3206  ssn.client.next_seq = 17;
3207  ret = 1;
3208 end:
3209  FLOWLOCK_UNLOCK(&f);
3210  FLOW_DESTROY(&f);
3211  UTHFreePacket(p);
3213  StreamTcpUTDeinit(ra_ctx);
3214  return ret;
3215 }
3216 
3217 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3218  * test the sliding window reassembly.
3219  */
3220 static int StreamTcpReassembleInlineTest02(void)
3221 {
3222  int ret = 0;
3223  TcpReassemblyThreadCtx *ra_ctx = NULL;
3224  ThreadVars tv;
3225  TcpSession ssn;
3226  Flow f;
3227 
3228  memset(&tv, 0x00, sizeof(tv));
3229 
3230  StreamTcpUTInit(&ra_ctx);
3233  StreamTcpUTSetupStream(&ssn.client, 1);
3234  FLOW_INITIALIZE(&f);
3235 
3236  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3237  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3238  if (p == NULL) {
3239  printf("couldn't get a packet: ");
3240  goto end;
3241  }
3242  p->tcph->th_seq = htonl(12);
3243  p->flow = &f;
3244 
3245  FLOWLOCK_WRLOCK(&f);
3246  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) {
3247  printf("failed to add segment 1: ");
3248  goto end;
3249  }
3250  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) {
3251  printf("failed to add segment 2: ");
3252  goto end;
3253  }
3254  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3255  printf("failed to add segment 3: ");
3256  goto end;
3257  }
3258  ssn.client.next_seq = 17;
3259  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3260  printf("failed to add segment 4: ");
3261  goto end;
3262  }
3263  ssn.client.next_seq = 22;
3264  ret = 1;
3265 end:
3266  FLOWLOCK_UNLOCK(&f);
3267  FLOW_DESTROY(&f);
3268  UTHFreePacket(p);
3270  StreamTcpUTDeinit(ra_ctx);
3271  return ret;
3272 }
3273 
3274 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3275  * test the sliding window reassembly with a small window size so that we
3276  * cutting off at the start (left edge)
3277  */
3278 static int StreamTcpReassembleInlineTest03(void)
3279 {
3280  int ret = 0;
3281  TcpReassemblyThreadCtx *ra_ctx = NULL;
3282  ThreadVars tv;
3283  TcpSession ssn;
3284  Flow f;
3285 
3286  memset(&tv, 0x00, sizeof(tv));
3287 
3288  StreamTcpUTInit(&ra_ctx);
3291  StreamTcpUTSetupStream(&ssn.client, 1);
3292  FLOW_INITIALIZE(&f);
3293 
3295 
3296  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3297  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3298  if (p == NULL) {
3299  printf("couldn't get a packet: ");
3300  goto end;
3301  }
3302  p->tcph->th_seq = htonl(12);
3303  p->flow = &f;
3305 
3306  FLOWLOCK_WRLOCK(&f);
3307  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) {
3308  printf("failed to add segment 1: ");
3309  goto end;
3310  }
3311  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) {
3312  printf("failed to add segment 2: ");
3313  goto end;
3314  }
3315  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3316  printf("failed to add segment 3: ");
3317  goto end;
3318  }
3319  ssn.client.next_seq = 17;
3320  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3321  printf("failed to add segment 4: ");
3322  goto end;
3323  }
3324  ssn.client.next_seq = 22;
3325 
3326  p->tcph->th_seq = htonl(17);
3327  ret = 1;
3328 end:
3329  FLOWLOCK_UNLOCK(&f);
3330  FLOW_DESTROY(&f);
3331  UTHFreePacket(p);
3333  StreamTcpUTDeinit(ra_ctx);
3334  return ret;
3335 }
3336 
3337 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3338  * test the sliding window reassembly with a small window size so that we
3339  * cutting off at the start (left edge) with small packet overlap.
3340  */
3341 static int StreamTcpReassembleInlineTest04(void)
3342 {
3343  int ret = 0;
3344  TcpReassemblyThreadCtx *ra_ctx = NULL;
3345  ThreadVars tv;
3346  TcpSession ssn;
3347  Flow f;
3348 
3349  memset(&tv, 0x00, sizeof(tv));
3350 
3351  StreamTcpUTInit(&ra_ctx);
3354  StreamTcpUTSetupStream(&ssn.client, 1);
3355  FLOW_INITIALIZE(&f);
3356 
3358 
3359  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3360  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3361  if (p == NULL) {
3362  printf("couldn't get a packet: ");
3363  goto end;
3364  }
3365  p->tcph->th_seq = htonl(12);
3366  p->flow = &f;
3368 
3369  FLOWLOCK_WRLOCK(&f);
3370  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) {
3371  printf("failed to add segment 1: ");
3372  goto end;
3373  }
3374  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) {
3375  printf("failed to add segment 2: ");
3376  goto end;
3377  }
3378  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3379  printf("failed to add segment 3: ");
3380  goto end;
3381  }
3382  ssn.client.next_seq = 17;
3383  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3384  printf("failed to add segment 4: ");
3385  goto end;
3386  }
3387  ssn.client.next_seq = 22;
3388 
3389  p->tcph->th_seq = htonl(17);
3390  ret = 1;
3391 end:
3392  FLOWLOCK_UNLOCK(&f);
3393  FLOW_DESTROY(&f);
3394  UTHFreePacket(p);
3396  StreamTcpUTDeinit(ra_ctx);
3397  return ret;
3398 }
3399 
3400 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3401  * test the sliding window reassembly with a small window size so that we
3402  * cutting off at the start (left edge). Test if the first segment is
3403  * removed from the list.
3404  */
3405 static int StreamTcpReassembleInlineTest08(void)
3406 {
3407  TcpReassemblyThreadCtx *ra_ctx = NULL;
3408  ThreadVars tv;
3409  memset(&tv, 0x00, sizeof(tv));
3410  TcpSession ssn;
3411  Flow f;
3412  StreamTcpUTInit(&ra_ctx);
3415  StreamTcpUTSetupStream(&ssn.client, 1);
3416  FLOW_INITIALIZE(&f);
3417 
3419  f.protoctx = &ssn;
3420 
3421  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3422  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3423  FAIL_IF(p == NULL);
3424  p->tcph->th_seq = htonl(12);
3425  p->flow = &f;
3427 
3428  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3429  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3430  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3431  ssn.client.next_seq = 17;
3432  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3433  ssn.client.next_seq = 22;
3434  p->tcph->th_seq = htonl(17);
3435  StreamTcpPruneSession(&f, STREAM_TOSERVER);
3436 
3437  TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3438  FAIL_IF_NULL(seg);
3439  FAIL_IF_NOT(seg->seq == 2);
3440 
3441  FLOW_DESTROY(&f);
3442  UTHFreePacket(p);
3444  StreamTcpUTDeinit(ra_ctx);
3445  PASS;
3446 }
3447 
3448 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3449  * test the sliding window reassembly with a small window size so that we
3450  * cutting off at the start (left edge). Test if the first segment is
3451  * removed from the list.
3452  */
3453 static int StreamTcpReassembleInlineTest09(void)
3454 {
3455  int ret = 0;
3456  TcpReassemblyThreadCtx *ra_ctx = NULL;
3457  ThreadVars tv;
3458  TcpSession ssn;
3459  Flow f;
3460 
3461  memset(&tv, 0x00, sizeof(tv));
3462 
3463  StreamTcpUTInit(&ra_ctx);
3466  StreamTcpUTSetupStream(&ssn.client, 1);
3467  FLOW_INITIALIZE(&f);
3468 
3470 
3471  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3472  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3473  if (p == NULL) {
3474  printf("couldn't get a packet: ");
3475  goto end;
3476  }
3477  p->tcph->th_seq = htonl(17);
3478  p->flow = &f;
3480 
3481  FLOWLOCK_WRLOCK(&f);
3482  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) {
3483  printf("failed to add segment 1: ");
3484  goto end;
3485  }
3486  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) {
3487  printf("failed to add segment 2: ");
3488  goto end;
3489  }
3490  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3491  printf("failed to add segment 3: ");
3492  goto end;
3493  }
3494  ssn.client.next_seq = 12;
3495  ssn.client.last_ack = 10;
3496 
3497  /* close the GAP and see if we properly reassemble and update base_seq */
3498  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3499  printf("failed to add segment 4: ");
3500  goto end;
3501  }
3502  ssn.client.next_seq = 22;
3503 
3504  p->tcph->th_seq = htonl(12);
3505 
3506  TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3507  FAIL_IF_NULL(seg);
3508  FAIL_IF_NOT(seg->seq == 2);
3509 
3510  ret = 1;
3511 end:
3512  FLOWLOCK_UNLOCK(&f);
3513  FLOW_DESTROY(&f);
3514  UTHFreePacket(p);
3516  StreamTcpUTDeinit(ra_ctx);
3517  return ret;
3518 }
3519 
3520 /** \test App Layer reassembly.
3521  */
3522 static int StreamTcpReassembleInlineTest10(void)
3523 {
3524  int ret = 0;
3525  TcpReassemblyThreadCtx *ra_ctx = NULL;
3526  ThreadVars tv;
3527  TcpSession ssn;
3528  Flow *f = NULL;
3529  Packet *p = NULL;
3530 
3531  memset(&tv, 0x00, sizeof(tv));
3532 
3533  StreamTcpUTInit(&ra_ctx);
3536  StreamTcpUTSetupStream(&ssn.server, 1);
3537  ssn.server.last_ack = 2;
3538  StreamTcpUTSetupStream(&ssn.client, 1);
3539  ssn.client.last_ack = 2;
3540  ssn.data_first_seen_dir = STREAM_TOSERVER;
3541 
3542  f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
3543  if (f == NULL)
3544  goto end;
3545  f->protoctx = &ssn;
3546  f->proto = IPPROTO_TCP;
3547 
3548  uint8_t stream_payload1[] = "GE";
3549  uint8_t stream_payload2[] = "T /";
3550  uint8_t stream_payload3[] = "HTTP/1.0\r\n\r\n";
3551 
3552  p = UTHBuildPacketReal(stream_payload3, 12, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3553  if (p == NULL) {
3554  printf("couldn't get a packet: ");
3555  goto end;
3556  }
3557  p->tcph->th_seq = htonl(7);
3558  p->flow = f;
3560 
3561  FLOWLOCK_WRLOCK(f);
3562  if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 2, stream_payload1, 2) == -1) {
3563  printf("failed to add segment 1: ");
3564  goto end;
3565  }
3566  ssn.client.next_seq = 4;
3567 
3568  int r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET);
3569  if (r < 0) {
3570  printf("StreamTcpReassembleAppLayer failed: ");
3571  goto end;
3572  }
3573 
3574  /* ssn.server.ra_app_base_seq should be isn here. */
3575  if (ssn.client.base_seq != 2 || ssn.client.base_seq != ssn.client.isn+1) {
3576  printf("expected ra_app_base_seq 1, got %u: ", ssn.client.base_seq);
3577  goto end;
3578  }
3579 
3580  if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 4, stream_payload2, 3) == -1) {
3581  printf("failed to add segment 2: ");
3582  goto end;
3583  }
3584  if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 7, stream_payload3, 12) == -1) {
3585  printf("failed to add segment 3: ");
3586  goto end;
3587  }
3588  ssn.client.next_seq = 19;
3589 
3590  r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET);
3591  if (r < 0) {
3592  printf("StreamTcpReassembleAppLayer failed: ");
3593  goto end;
3594  }
3595 
3596  FAIL_IF_NOT(STREAM_APP_PROGRESS(&ssn.client) == 17);
3597 
3598  ret = 1;
3599 end:
3600  UTHFreePacket(p);
3602  StreamTcpUTDeinit(ra_ctx);
3603  FLOWLOCK_UNLOCK(f);
3604  UTHFreeFlow(f);
3605  return ret;
3606 }
3607 
3608 /** \test test insert with overlap
3609  */
3610 static int StreamTcpReassembleInsertTest01(void)
3611 {
3612  TcpReassemblyThreadCtx *ra_ctx = NULL;
3613  ThreadVars tv;
3614  TcpSession ssn;
3615  Flow f;
3616 
3617  memset(&tv, 0x00, sizeof(tv));
3618 
3619  StreamTcpUTInit(&ra_ctx);
3621  StreamTcpUTSetupStream(&ssn.client, 1);
3623  FLOW_INITIALIZE(&f);
3624 
3625  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3626  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3627  FAIL_IF(p == NULL);
3628  p->tcph->th_seq = htonl(12);
3629  p->flow = &f;
3630 
3631  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3632  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3633  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 14, 'D', 2) == -1);
3634  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 16, 'D', 6) == -1);
3635  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3636  ssn.client.next_seq = 21;
3637 
3638  FLOW_DESTROY(&f);
3639  UTHFreePacket(p);
3641  StreamTcpUTDeinit(ra_ctx);
3642  PASS;
3643 }
3644 
3645 /** \test test insert with overlaps
3646  */
3647 static int StreamTcpReassembleInsertTest02(void)
3648 {
3649  int ret = 0;
3650  TcpReassemblyThreadCtx *ra_ctx = NULL;
3651  ThreadVars tv;
3652  TcpSession ssn;
3653 
3654  memset(&tv, 0x00, sizeof(tv));
3655 
3656  StreamTcpUTInit(&ra_ctx);
3658  StreamTcpUTSetupStream(&ssn.client, 1);
3659 
3660  int i;
3661  for (i = 2; i < 10; i++) {
3662  int len;
3663  len = i % 2;
3664  if (len == 0)
3665  len = 1;
3666  int seq;
3667  seq = i * 10;
3668  if (seq < 2)
3669  seq = 2;
3670 
3671  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'A', len) == -1) {
3672  printf("failed to add segment 1: ");
3673  goto end;
3674  }
3675  }
3676  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'B', 1024) == -1) {
3677  printf("failed to add segment 2: ");
3678  goto end;
3679  }
3680 
3681  ret = 1;
3682 end:
3684  StreamTcpUTDeinit(ra_ctx);
3685  return ret;
3686 }
3687 
3688 /** \test test insert with overlaps
3689  */
3690 static int StreamTcpReassembleInsertTest03(void)
3691 {
3692  int ret = 0;
3693  TcpReassemblyThreadCtx *ra_ctx = NULL;
3694  ThreadVars tv;
3695  TcpSession ssn;
3696 
3697  memset(&tv, 0x00, sizeof(tv));
3698 
3699  StreamTcpUTInit(&ra_ctx);
3701  StreamTcpUTSetupStream(&ssn.client, 1);
3702 
3703  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 1024) == -1) {
3704  printf("failed to add segment 2: ");
3705  goto end;
3706  }
3707 
3708  int i;
3709  for (i = 2; i < 10; i++) {
3710  int len;
3711  len = i % 2;
3712  if (len == 0)
3713  len = 1;
3714  int seq;
3715  seq = i * 10;
3716  if (seq < 2)
3717  seq = 2;
3718 
3719  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'B', len) == -1) {
3720  printf("failed to add segment 2: ");
3721  goto end;
3722  }
3723  }
3724  ret = 1;
3725 end:
3727  StreamTcpUTDeinit(ra_ctx);
3728  return ret;
3729 }
3730 
3732 #endif /* UNITTESTS */
3733 
3734 /** \brief The Function Register the Unit tests to test the reassembly engine
3735  * for various OS policies.
3736  */
3737 
3739 {
3740 #ifdef UNITTESTS
3741  UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test",
3742  StreamTcpReassembleTest25);
3743  UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test",
3744  StreamTcpReassembleTest26);
3745  UtRegisterTest("StreamTcpReassembleTest27 -- Gap at after Reassembly Test",
3746  StreamTcpReassembleTest27);
3747  UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test",
3748  StreamTcpReassembleTest28);
3749  UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test",
3750  StreamTcpReassembleTest29);
3751  UtRegisterTest("StreamTcpReassembleTest33 -- Bug test",
3752  StreamTcpReassembleTest33);
3753  UtRegisterTest("StreamTcpReassembleTest34 -- Bug test",
3754  StreamTcpReassembleTest34);
3755  UtRegisterTest("StreamTcpReassembleTest37 -- Bug76 test",
3756  StreamTcpReassembleTest37);
3757  UtRegisterTest("StreamTcpReassembleTest39 -- app proto test",
3758  StreamTcpReassembleTest39);
3759  UtRegisterTest("StreamTcpReassembleTest40 -- app proto test",
3760  StreamTcpReassembleTest40);
3761  UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test",
3762  StreamTcpReassembleTest44);
3763  UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test",
3764  StreamTcpReassembleTest45);
3765  UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test",
3766  StreamTcpReassembleTest46);
3767  UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test",
3768  StreamTcpReassembleTest47);
3769 
3770  UtRegisterTest("StreamTcpReassembleInlineTest01 -- inline RAW ra",
3771  StreamTcpReassembleInlineTest01);
3772  UtRegisterTest("StreamTcpReassembleInlineTest02 -- inline RAW ra 2",
3773  StreamTcpReassembleInlineTest02);
3774  UtRegisterTest("StreamTcpReassembleInlineTest03 -- inline RAW ra 3",
3775  StreamTcpReassembleInlineTest03);
3776  UtRegisterTest("StreamTcpReassembleInlineTest04 -- inline RAW ra 4",
3777  StreamTcpReassembleInlineTest04);
3778  UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup",
3779  StreamTcpReassembleInlineTest08);
3780  UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup",
3781  StreamTcpReassembleInlineTest09);
3782 
3783  UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10",
3784  StreamTcpReassembleInlineTest10);
3785 
3786  UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap",
3787  StreamTcpReassembleInsertTest01);
3788  UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap",
3789  StreamTcpReassembleInsertTest02);
3790  UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap",
3791  StreamTcpReassembleInsertTest03);
3792 
3796  StreamTcpReassembleRawRegisterTests();
3797 #endif /* UNITTESTS */
3798 }
StreamTcpSetEvent
#define StreamTcpSetEvent(p, e)
Definition: stream-tcp-private.h:249
APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER
#define APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER
Definition: app-layer.h:38
PoolThreadInit
PoolThread * PoolThreadInit(int threads, 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 *))
per thread Pool, initialization function
Definition: util-pool-thread.c:43
UPDATE_DIR_BOTH
@ UPDATE_DIR_BOTH
Definition: stream-tcp-reassemble.h:57
UPDATE_DIR_PACKET
@ UPDATE_DIR_PACKET
Definition: stream-tcp-reassemble.h:55
util-byte.h
tm-threads.h
StreamTcpUTAddPayload
int StreamTcpUTAddPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len)
wrapper for StreamTcpReassembleHandleSegmentHandleData
Definition: stream-tcp-util.c:97
Packet_::proto
uint8_t proto
Definition: decode.h:442
TcpStream_
Definition: stream-tcp-private.h:94
StreamingBuffer_::stream_offset
uint64_t stream_offset
Definition: util-streaming-buffer.h:97
len
uint8_t len
Definition: app-layer-dnp3.h:2
StreamTcpUTDeinit
void StreamTcpUTDeinit(TcpReassemblyThreadCtx *ra_ctx)
Definition: stream-tcp-util.c:51
StreamTcpInlineRegisterTests
void StreamTcpInlineRegisterTests(void)
Definition: stream-tcp-inline.c:149
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
StreamingBuffer_::buf_offset
uint32_t buf_offset
Definition: util-streaming-buffer.h:101
TcpStream_::isn
uint32_t isn
Definition: stream-tcp-private.h:101
StreamTcpGetSegment
TcpSegment * StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *)
get a segment from the pool
Definition: stream-tcp-reassemble.c:1943
StreamingBufferConfig_::Malloc
void *(* Malloc)(size_t size)
Definition: util-streaming-buffer.h:71
StatsIncr
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:169
StreamTcpSegmentReturntoPool
void StreamTcpSegmentReturntoPool(TcpSegment *seg)
Function to return the segment back to the pool.
Definition: stream-tcp-reassemble.c:303
PoolThreadExpand
int PoolThreadExpand(PoolThread *pt)
expand pool by one for a new thread
Definition: util-pool-thread.c:92
StreamingBufferConfig_::buf_size
uint32_t buf_size
Definition: util-streaming-buffer.h:70
StreamReassembleRaw
int StreamReassembleRaw(TcpSession *ssn, const Packet *p, StreamReassembleRawFunc Callback, void *cb_data, uint64_t *progress_out, bool respect_inspect_depth)
Definition: stream-tcp-reassemble.c:1779
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
TCP_HAS_TFO
#define TCP_HAS_TFO(p)
Definition: decode-tcp.h:97
TCP_SEG_LEN
#define TCP_SEG_LEN(seg)
Definition: stream-tcp-private.h:82
stream-tcp-inline.h
StreamTcpUTClearStream
void StreamTcpUTClearStream(TcpStream *s)
Definition: stream-tcp-util.c:91
flow-util.h
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:315
StreamingBufferConfig_::Calloc
void *(* Calloc)(size_t n, size_t size)
Definition: util-streaming-buffer.h:72
StreamingBuffer_::head
StreamingBufferBlock * head
Definition: util-streaming-buffer.h:104
ConfNode_::val
char * val
Definition: conf.h:34
ConfGetBool
int ConfGetBool(const char *name, int *val)
Retrieve a configuration value as an boolen.
Definition: conf.c:516
stream-tcp.h
RB_REMOVE
#define RB_REMOVE(name, x, y)
Definition: tree.h:773
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SC_ATOMIC_SET
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:387
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
StreamTcpReassembleDepthReached
int StreamTcpReassembleDepthReached(Packet *p)
check if stream in pkt direction has depth reached
Definition: stream-tcp-reassemble.c:517
StreamTcpReassembleGetMemcap
uint64_t StreamTcpReassembleGetMemcap()
Return memcap value.
Definition: stream-tcp-reassemble.c:176
StreamTcpReassembleInsertSegment
int StreamTcpReassembleInsertSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, TcpSegment *seg, Packet *p, uint32_t pkt_seq, uint8_t *pkt_data, uint16_t pkt_datalen)
Definition: stream-tcp-list.c:566
TcpStream_::seg_tree
struct TCPSEG seg_tree
Definition: stream-tcp-private.h:123
SET_ISN
#define SET_ISN(stream, setseq)
Definition: stream-tcp-reassemble.c:2007
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:581
seq
uint32_t seq
Definition: stream-tcp-private.h:2
StatsRegisterGlobalCounter
uint16_t StatsRegisterGlobalCounter(const char *name, uint64_t(*Func)(void))
Registers a counter, which represents a global value.
Definition: counters.c:1000
StreamTcpThread_
Definition: stream-tcp.h:70
Flow_::proto
uint8_t proto
Definition: flow.h:375
Packet_::payload
uint8_t * payload
Definition: decode.h:560
StreamTcpInlineMode
int StreamTcpInlineMode(void)
See if stream engine is operating in inline mode.
Definition: stream-tcp.c:6381
StreamTcpReassemblySetMinInspectDepth
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
Definition: stream-tcp-reassemble.c:1987
TcpReassemblyThreadCtx_::app_tctx
void * app_tctx
Definition: stream-tcp-reassemble.h:61
Packet_::flags
uint32_t flags
Definition: decode.h:455
AppLayerFramesUpdateProgress
void AppLayerFramesUpdateProgress(Flow *f, TcpStream *stream, const uint64_t progress, const uint8_t direction)
Definition: app-layer-frames.c:351
ConfGetNode
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:175
threads.h
TH_RST
#define TH_RST
Definition: decode-tcp.h:36
TcpStream_::os_policy
uint8_t os_policy
Definition: stream-tcp-private.h:98
TcpStreamCnf_::reassembly_depth
uint32_t reassembly_depth
Definition: stream-tcp.h:60
Flow_
Flow data structure.
Definition: flow.h:353
TcpSegment::sbseg
StreamingBufferSegment sbseg
Definition: stream-tcp-private.h:66
TcpReassemblyThreadCtx_::counter_tcp_stream_depth
uint16_t counter_tcp_stream_depth
Definition: stream-tcp-reassemble.h:68
StreamTcpReassembleTriggerRawReassembly
void StreamTcpReassembleTriggerRawReassembly(TcpSession *ssn, int direction)
Trigger RAW stream reassembly.
Definition: stream-tcp-reassemble.c:1970
TH_FIN
#define TH_FIN
Definition: decode-tcp.h:34
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:333
TCP_FIN_WAIT1
@ TCP_FIN_WAIT1
Definition: stream-tcp-private.h:144
StreamTcpReassembleConfigEnableOverlapCheck
void StreamTcpReassembleConfigEnableOverlapCheck(void)
Definition: stream-tcp-list.c:40
TcpStreamCnf_::sbcnf
StreamingBufferConfig sbcnf
Definition: stream-tcp.h:67
StreamTcpUtilRegisterTests
void StreamTcpUtilRegisterTests(void)
Definition: stream-tcp-util.c:245
OS_POLICY_BSD
@ OS_POLICY_BSD
Definition: stream-tcp-reassemble.h:37
StreamReassembleRawUpdateProgress
void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, uint64_t progress)
update stream engine after detection
Definition: stream-tcp-reassemble.c:1384
StreamingBufferGetData
int StreamingBufferGetData(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t *stream_offset)
Definition: util-streaming-buffer.c:867
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:225
RB_MIN
#define RB_MIN(name, x)
Definition: tree.h:778
TCP_ESTABLISHED
@ TCP_ESTABLISHED
Definition: stream-tcp-private.h:143
StreamNeedsReassembly
int StreamNeedsReassembly(const TcpSession *ssn, uint8_t direction)
see what if any work the TCP session still needs
Definition: stream-tcp-reassemble.c:804
MIN
#define MIN(x, y)
Definition: suricata-common.h:372
stream-tcp-reassemble.h
TcpSegment::seq
uint32_t seq
Definition: stream-tcp-private.h:64
TcpStream_::flags
uint16_t flags
Definition: stream-tcp-private.h:95
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
StreamingBufferConfig_::flags
uint32_t flags
Definition: util-streaming-buffer.h:68
PoolThreadFree
void PoolThreadFree(PoolThread *pt)
destroy the thread pool
Definition: util-pool-thread.c:150
StreamingBufferGetDataAtOffset
int StreamingBufferGetDataAtOffset(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t offset)
Definition: util-streaming-buffer.c:884
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:451
stream_config
TcpStreamCnf stream_config
Definition: stream-tcp.c:119
APP_LAYER_PARSER_EOF_TS
#define APP_LAYER_PARSER_EOF_TS
Definition: app-layer-parser.h:42
UTHBuildPacketReal
Packet * UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len, uint8_t ipproto, const char *src, const char *dst, uint16_t sport, uint16_t dport)
UTHBuildPacketReal is a function that create tcp/udp packets for unittests specifying ip and port sou...
Definition: util-unittest-helper.c:242
Flow_::protoctx
void * protoctx
Definition: flow.h:451
StreamTcpListRegisterTests
void StreamTcpListRegisterTests(void)
Definition: stream-tcp-list.c:711
StreamTcpUTInitInline
void StreamTcpUTInitInline(void)
Definition: stream-tcp-util.c:58
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:98
Packet_::payload_len
uint16_t payload_len
Definition: decode.h:561
PacketQueueNoLock_
simple fifo queue for packets
Definition: packet-queue.h:32
STREAMTCP_STREAM_FLAG_DEPTH_REACHED
#define STREAMTCP_STREAM_FLAG_DEPTH_REACHED
Definition: stream-tcp-private.h:204
Packet_::app_layer_events
AppLayerDecoderEvents * app_layer_events
Definition: decode.h:587
util-unittest.h
MISSED_STEP
#define MISSED_STEP(seq, seg, seglen, buf, buflen)
Definition: stream-tcp-reassemble.c:2079
util-unittest-helper.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
TcpSession_::flags
uint16_t flags
Definition: stream-tcp-private.h:269
FLOWLOCK_UNLOCK
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:270
StreamTcpReassembleInit
int StreamTcpReassembleInit(bool quiet)
Definition: stream-tcp-reassemble.c:423
StreamTcpGetUsable
uint64_t StreamTcpGetUsable(const TcpStream *stream, const bool eof)
Definition: stream-tcp-reassemble.c:340
STREAMTCP_FLAG_MIDSTREAM
#define STREAMTCP_FLAG_MIDSTREAM
Definition: stream-tcp-private.h:158
FLOW_IS_PM_DONE
#define FLOW_IS_PM_DONE(f, dir)
Definition: flow.h:275
TcpStream_::last_ack
uint32_t last_ack
Definition: stream-tcp-private.h:103
Flow_::alparser
AppLayerParserState * alparser
Definition: flow.h:485
StreamTcpReassembleInitThreadCtx
TcpReassemblyThreadCtx * StreamTcpReassembleInitThreadCtx(ThreadVars *tv)
Definition: stream-tcp-reassemble.c:458
StreamTcpUTInit
void StreamTcpUTInit(TcpReassemblyThreadCtx **ra_ctx)
Definition: stream-tcp-util.c:44
StreamTcpInitConfig
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition: stream-tcp.c:365
UTHBuildFlow
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
Definition: util-unittest-helper.c:521
StreamTcpReassembleAppLayer
int StreamTcpReassembleAppLayer(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p, enum StreamUpdateDir dir)
Update the stream reassembly upon receiving a packet.
Definition: stream-tcp-reassemble.c:1227
FLOW_INITIALIZE
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
TcpSession_::reassembly_depth
uint32_t reassembly_depth
Definition: stream-tcp-private.h:270
RB_EMPTY
#define RB_EMPTY(head)
Definition: tree.h:327
util-device.h
util-debug.h
StreamTcpAppLayerIsDisabled
int StreamTcpAppLayerIsDisabled(Flow *f)
Definition: stream-tcp-reassemble.c:377
AppLayerHandleTCPData
int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, Packet *p, Flow *f, TcpSession *ssn, TcpStream **stream, uint8_t *data, uint32_t data_len, uint8_t flags)
handle TCP data for the app-layer.
Definition: app-layer.c:587
STREAM_HAS_UNPROCESSED_SEGMENTS_NONE
@ STREAM_HAS_UNPROCESSED_SEGMENTS_NONE
Definition: stream-tcp.h:171
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
PKT_IS_TOSERVER
#define PKT_IS_TOSERVER(p)
Definition: decode.h:268
STREAM_HAS_SEEN_DATA
#define STREAM_HAS_SEEN_DATA(stream)
Definition: stream-tcp-private.h:92
FLOW_IS_PP_DONE
#define FLOW_IS_PP_DONE(f, dir)
Definition: flow.h:276
PKT_STREAM_ADD
#define PKT_STREAM_ADD
Definition: decode.h:1156
StreamTcpGetAcked
uint64_t StreamTcpGetAcked(const TcpStream *stream)
Definition: stream-tcp-reassemble.c:335
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
PKT_PSEUDO_STREAM_END
#define PKT_PSEUDO_STREAM_END
Definition: decode.h:1163
STREAM_BASE_OFFSET
#define STREAM_BASE_OFFSET(stream)
Definition: stream-tcp-private.h:131
FLOWLOCK_WRLOCK
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:267
TcpStream_::min_inspect_depth
uint32_t min_inspect_depth
Definition: stream-tcp-private.h:118
StreamReassembleLog
int StreamReassembleLog(TcpSession *ssn, TcpStream *stream, StreamReassembleRawFunc Callback, void *cb_data, uint64_t progress_in, uint64_t *progress_out, bool eof)
Definition: stream-tcp-reassemble.c:1807
util-print.h
APPLAYER_PROTO_DETECTION_SKIPPED
@ APPLAYER_PROTO_DETECTION_SKIPPED
Definition: app-layer-events.h:50
RB_FOREACH_SAFE
#define RB_FOREACH_SAFE(x, name, head, y)
Definition: tree.h:791
AppLayerGetCtxThread
AppLayerThreadCtx * AppLayerGetCtxThread(ThreadVars *tv)
Creates a new app layer thread context.
Definition: app-layer.c:878
SCEnter
#define SCEnter(...)
Definition: util-debug.h:300
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
StreamTcpPacket
int StreamTcpPacket(ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueueNoLock *pq)
Definition: stream-tcp.c:4861
SC_ATOMIC_DECLARE
SC_ATOMIC_DECLARE(uint64_t, ra_memuse)
StreamTcpUTSetupStream
void StreamTcpUTSetupStream(TcpStream *s, uint32_t isn)
Definition: stream-tcp-util.c:79
StreamReassembleRawHasDataReady
bool StreamReassembleRawHasDataReady(TcpSession *ssn, Packet *p)
does the stream engine have data to inspect?
Definition: stream-tcp-reassemble.c:1340
TcpSession_::state
uint8_t state
Definition: stream-tcp-private.h:262
TH_ACK
#define TH_ACK
Definition: decode-tcp.h:38
StreamTcpReassembleInitMemuse
void StreamTcpReassembleInitMemuse(void)
Definition: stream-tcp-reassemble.c:88
stream-tcp-list.h
StreamTcpCreateTestPacket
void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t)
The Function to create the packet with given payload, which is used to test the reassembly of the eng...
Definition: stream-tcp-reassemble.c:2021
StreamTcpPruneSession
void StreamTcpPruneSession(Flow *f, uint8_t flags)
Remove idle TcpSegments from TcpSession.
Definition: stream-tcp-list.c:830
PrintRawDataFp
void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen)
Definition: util-print.c:141
SC_ERR_INVALID_ARGUMENT
@ SC_ERR_INVALID_ARGUMENT
Definition: util-error.h:43
app-layer-parser.h
StreamTcpReassembleCheckMemcap
int StreamTcpReassembleCheckMemcap(uint64_t size)
Function to Check the reassembly memory usage counter against the allowed max memory usage for TCP se...
Definition: stream-tcp-reassemble.c:147
TRUE
#define TRUE
Definition: suricata-common.h:33
StreamTcpReassembleHandleSegment
int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p, PacketQueueNoLock *pq)
Definition: stream-tcp-reassemble.c:1835
STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION
@ STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION
Definition: stream-tcp.h:174
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:281
TCP_GET_SEQ
#define TCP_GET_SEQ(p)
Definition: decode-tcp.h:114
RB_FOREACH
#define RB_FOREACH(x, name, head)
Definition: tree.h:781
stream-tcp-reassemble.c
util-profiling.h
SC_ATOMIC_SUB
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:342
StreamingBuffer_::sbb_size
uint32_t sbb_size
Definition: util-streaming-buffer.h:105
StreamTcpSessionClear
void StreamTcpSessionClear(void *ssnptr)
Function to return the stream back to the pool. It returns the segments in the stream to the segment ...
Definition: stream-tcp.c:249
FALSE
#define FALSE
Definition: suricata-common.h:34
SCReturn
#define SCReturn
Definition: util-debug.h:302
stream.h
TcpSegment
Definition: stream-tcp-private.h:61
StreamTcpIsSetStreamFlagAppProtoDetectionCompleted
#define StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)
Definition: stream-tcp-private.h:278
Packet_
Definition: decode.h:420
STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED
#define STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED
Definition: stream-tcp-private.h:215
stream-tcp-private.h
PoolThreadReturn
void PoolThreadReturn(PoolThread *pt, void *data)
return data to thread pool
Definition: util-pool-thread.c:187
APP_LAYER_PARSER_EOF_TC
#define APP_LAYER_PARSER_EOF_TC
Definition: app-layer-parser.h:43
SCReturnUInt
#define SCReturnUInt(x)
Definition: util-debug.h:306
conf.h
StreamTcpSetStreamFlagAppProtoDetectionCompleted
#define StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream)
Definition: stream-tcp-private.h:276
StreamingBufferCompareRawData
int StreamingBufferCompareRawData(const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len)
Definition: util-streaming-buffer.c:907
TcpStream_::window
uint32_t window
Definition: stream-tcp-private.h:105
StreamTcpReassembleFreeThreadCtx
void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *ra_ctx)
Definition: stream-tcp-reassemble.c:499
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:316
StreamDataAvailableForProtoDetect
uint32_t StreamDataAvailableForProtoDetect(TcpStream *stream)
Definition: stream-tcp-reassemble.c:614
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
StreamTcpReturnStreamSegments
void StreamTcpReturnStreamSegments(TcpStream *stream)
return all segments in this stream into the pool(s)
Definition: stream-tcp-reassemble.c:316
STREAM_REASSEMBLY_NO_SEGMENT
@ STREAM_REASSEMBLY_NO_SEGMENT
Definition: decode-events.h:286
FLOW_PKT_TOCLIENT
#define FLOW_PKT_TOCLIENT
Definition: flow.h:226
RunmodeIsUnittests
int RunmodeIsUnittests(void)
Definition: suricata.c:271
StreamTcpReassembleFree
void StreamTcpReassembleFree(bool quiet)
Definition: stream-tcp-reassemble.c:439
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:217
TcpReassemblyThreadCtx_::counter_tcp_reass_gap
uint16_t counter_tcp_reass_gap
Definition: stream-tcp-reassemble.h:70
TcpStream_::raw_progress_rel
uint32_t raw_progress_rel
Definition: stream-tcp-private.h:115
SBB_RB_FIND_INCLUSIVE
StreamingBufferBlock * SBB_RB_FIND_INCLUSIVE(struct SBB *head, StreamingBufferBlock *elm)
Definition: util-streaming-buffer.c:79
SCMutexInit
#define SCMutexInit(mut, mutattrs)
Definition: threads-debug.h:116
util-host-os-info.h
UTHFreeFlow
void UTHFreeFlow(Flow *flow)
Definition: util-unittest-helper.c:526
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
UPDATE_DIR_OPPOSING
@ UPDATE_DIR_OPPOSING
Definition: stream-tcp-reassemble.h:56
StreamingBuffer_::sbb_tree
struct SBB sbb_tree
Definition: util-streaming-buffer.h:103
StreamingBuffer_
Definition: util-streaming-buffer.h:95
StreamTcpUTClearSession
void StreamTcpUTClearSession(TcpSession *ssn)
Definition: stream-tcp-util.c:71
StreamTcpReassembleHandleSegmentHandleData
int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p)
Insert a packets TCP data into the stream reassembly engine.
Definition: stream-tcp-reassemble.c:638
TcpReassemblyThreadCtx_::segment_thread_pool_id
int segment_thread_pool_id
Definition: stream-tcp-reassemble.h:63
TCP_CLOSED
@ TCP_CLOSED
Definition: stream-tcp-private.h:150
StreamingBufferSBBGetDataAtOffset
void StreamingBufferSBBGetDataAtOffset(const StreamingBuffer *sb, const StreamingBufferBlock *sbb, const uint8_t **data, uint32_t *data_len, uint64_t offset)
get the data for one SBB
Definition: util-streaming-buffer.c:787
StringParseUint32
int StringParseUint32(uint32_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:313
TH_PUSH
#define TH_PUSH
Definition: decode-tcp.h:37
app-layer-frames.h
STREAMTCP_FLAG_CLOSED_BY_RST
#define STREAMTCP_FLAG_CLOSED_BY_RST
Definition: stream-tcp-private.h:168
Packet_::flow
struct Flow_ * flow
Definition: decode.h:457
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
SEQ_GEQ
#define SEQ_GEQ(a, b)
Definition: stream-tcp-private.h:241
StreamTcpFreeConfig
void StreamTcpFreeConfig(bool quiet)
Definition: stream-tcp.c:670
OS_POLICY_LAST
@ OS_POLICY_LAST
Definition: stream-tcp-reassemble.h:51
TH_SYN
#define TH_SYN
Definition: decode-tcp.h:35
flags
uint8_t flags
Definition: decode-gre.h:0
STREAM_REASSEMBLY_SEQ_GAP
@ STREAM_REASSEMBLY_SEQ_GAP
Definition: decode-events.h:287
StreamTcpDisableAppLayer
void StreamTcpDisableAppLayer(Flow *f)
Definition: stream-tcp-reassemble.c:361
suricata-common.h
SEQ_GT
#define SEQ_GT(a, b)
Definition: stream-tcp-private.h:240
Packet_::tcph
TCPHdr * tcph
Definition: decode.h:540
TcpStream_::base_seq
uint32_t base_seq
Definition: stream-tcp-private.h:112
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:30
AppLayerDecoderEventsSetEventRaw
void AppLayerDecoderEventsSetEventRaw(AppLayerDecoderEvents **sevents, uint8_t event)
Set an app layer decoder event.
Definition: app-layer-events.c:89
MISSED_START
#define MISSED_START(isn)
Definition: stream-tcp-reassemble.c:2060
TcpStream_::sb
StreamingBuffer sb
Definition: stream-tcp-private.h:122
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED
#define STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED
Definition: stream-tcp-private.h:217
TcpSession_::client
TcpStream client
Definition: stream-tcp-private.h:272
TCP_CLOSING
@ TCP_CLOSING
Definition: stream-tcp-private.h:149
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:29
StreamTcpUTAddSegmentWithPayload
int StreamTcpUTAddSegmentWithPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len)
Definition: stream-tcp-util.c:113
TcpStreamCnf_::reassembly_toclient_chunk_size
uint16_t reassembly_toclient_chunk_size
Definition: stream-tcp.h:63
app-layer-events.h
TcpStream_::next_seq
uint32_t next_seq
Definition: stream-tcp-private.h:102
threadvars.h
util-validate.h
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:151
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
StreamTcpUTSetupSession
void StreamTcpUTSetupSession(TcpSession *ssn)
Definition: stream-tcp-util.c:62
TcpSession_::server
TcpStream server
Definition: stream-tcp-private.h:271
StreamTcpReassembleIncrMemuse
void StreamTcpReassembleIncrMemuse(uint64_t size)
Function to Increment the memory usage counter for the TCP reassembly segments.
Definition: stream-tcp-reassemble.c:99
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Flow_::alproto_ts
AppProto alproto_ts
Definition: flow.h:461
ConfNode_
Definition: conf.h:32
UTHFreePacket
void UTHFreePacket(Packet *p)
UTHFreePacket: function to release the allocated data from UTHBuildPacket and the packet itself.
Definition: util-unittest-helper.c:485
StreamTcpUTAddSegmentWithByte
int StreamTcpUTAddSegmentWithByte(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, uint32_t seq, uint8_t byte, uint16_t len)
Definition: stream-tcp-util.c:136
AppLayerDestroyCtxThread
void AppLayerDestroyCtxThread(AppLayerThreadCtx *app_tctx)
Destroys the context created by AppLayeGetCtxThread().
Definition: app-layer.c:900
SEQ_LT
#define SEQ_LT(a, b)
Definition: stream-tcp-private.h:238
Flow_::flags
uint32_t flags
Definition: flow.h:431
StreamTcpSetOSPolicy
void StreamTcpSetOSPolicy(TcpStream *, Packet *)
Function to set the OS policy for the given stream based on the destination of the received packet.
Definition: stream-tcp.c:768
StreamingBufferConfig_::Free
void(* Free)(void *ptr, size_t size)
Definition: util-streaming-buffer.h:74
payload_len
uint16_t payload_len
Definition: stream-tcp-private.h:1
PoolThread_
Definition: util-pool-thread.h:50
StreamTcpReassembleMemuseGlobalCounter
uint64_t StreamTcpReassembleMemuseGlobalCounter(void)
Definition: stream-tcp-reassemble.c:133
StreamTcpDisableAppLayerReassembly
#define StreamTcpDisableAppLayerReassembly(ssn)
Definition: stream-tcp-private.h:282
MISSED_END
#define MISSED_END
Definition: stream-tcp-reassemble.c:2074
stream-tcp-util.h
TCP_TIME_WAIT
@ TCP_TIME_WAIT
Definition: stream-tcp-private.h:146
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
StreamTcpThread_::ra_ctx
TcpReassemblyThreadCtx * ra_ctx
Definition: stream-tcp.h:103
TcpReassemblyThreadCtx_
Definition: stream-tcp-reassemble.h:60
TcpStreamCnf_::prealloc_segments
uint32_t prealloc_segments
Definition: stream-tcp.h:57
AppLayerFrameDump
void AppLayerFrameDump(Flow *f)
Definition: app-layer-frames.c:530
app-layer-protos.h
PoolThreadGetById
void * PoolThreadGetById(PoolThread *pt, uint16_t id)
get data from thread pool by thread id
Definition: util-pool-thread.c:168
SC_ERR_MEM_ALLOC
@ SC_ERR_MEM_ALLOC
Definition: util-error.h:31
STREAMTCP_FLAG_APP_LAYER_DISABLED
#define STREAMTCP_FLAG_APP_LAYER_DISABLED
Definition: stream-tcp-private.h:188
STREAMTCP_STREAM_FLAG_NOREASSEMBLY
#define STREAMTCP_STREAM_FLAG_NOREASSEMBLY
Definition: stream-tcp-private.h:200
suricata.h
Address_::family
char family
Definition: decode.h:123
Packet_::dst
Address dst
Definition: decode.h:425
StreamTcpStateAsString
const char * StreamTcpStateAsString(const enum TcpState state)
Definition: stream-tcp.c:6396
SEQ_LEQ
#define SEQ_LEQ(a, b)
Definition: stream-tcp-private.h:239
StreamUpdateDir
StreamUpdateDir
Definition: stream-tcp-reassemble.h:54
AppLayerParserStateSetFlag
void AppLayerParserStateSetFlag(AppLayerParserState *pstate, uint8_t flag)
Definition: app-layer-parser.c:1688
STREAMTCP_STREAM_FLAG_DISABLE_RAW
#define STREAMTCP_STREAM_FLAG_DISABLE_RAW
Definition: stream-tcp-private.h:219
STREAMING_BUFFER_NOFLAGS
#define STREAMING_BUFFER_NOFLAGS
Definition: util-streaming-buffer.h:64
StreamTcpReassembleRegisterTests
void StreamTcpReassembleRegisterTests(void)
The Function Register the Unit tests to test the reassembly engine for various OS policies.
Definition: stream-tcp-reassemble.c:3738
STREAM_RIGHT_EDGE
#define STREAM_RIGHT_EDGE(stream)
Definition: stream-tcp-private.h:90
STREAM_APP_PROGRESS
#define STREAM_APP_PROGRESS(stream)
Definition: stream-tcp-private.h:132
FlowChangeProto
int FlowChangeProto(Flow *f)
Check if change proto flag is set for flow.
Definition: flow.c:212
StreamTcpReassembleDecrMemuse
void StreamTcpReassembleDecrMemuse(uint64_t size)
Function to Decrease the memory usage counter for the TCP reassembly segments.
Definition: stream-tcp-reassemble.c:112
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:376
TcpSession_
Definition: stream-tcp-private.h:260
TcpSession_::data_first_seen_dir
int8_t data_first_seen_dir
Definition: stream-tcp-private.h:265
StreamTcpReassembleSetMemcap
int StreamTcpReassembleSetMemcap(uint64_t size)
Update memcap value.
Definition: stream-tcp-reassemble.c:161
flow.h
Flow_::alproto_tc
AppProto alproto_tc
Definition: flow.h:462
StreamReassembleRawFunc
int(* StreamReassembleRawFunc)(void *data, const uint8_t *input, const uint32_t input_len)
Definition: stream-tcp.h:130
STREAMTCP_STREAM_FLAG_FLUSH_FLAGS
#define STREAMTCP_STREAM_FLAG_FLUSH_FLAGS
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:460
FLOW_DIR_REVERSED
#define FLOW_DIR_REVERSED
Definition: flow.h:110
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
STREAMTCP_STREAM_FLAG_TRIGGER_RAW
#define STREAMTCP_STREAM_FLAG_TRIGGER_RAW
Definition: stream-tcp-private.h:206
PoolThreadSize
int PoolThreadSize(PoolThread *pt)
get size of PoolThread (number of 'threads', so array elements)
Definition: util-pool-thread.c:143
util-pool.h
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:304
SCMutexDestroy
#define SCMutexDestroy
Definition: threads-debug.h:120
StreamingBufferBlock::len
uint32_t len
Definition: util-streaming-buffer.h:85
StreamingBufferBlock::offset
uint64_t offset
Definition: util-streaming-buffer.h:83
TcpReassemblyThreadCtx_::counter_tcp_segment_memcap
uint16_t counter_tcp_segment_memcap
Definition: stream-tcp-reassemble.h:66
StreamingBufferSBBGetData
void StreamingBufferSBBGetData(const StreamingBuffer *sb, const StreamingBufferBlock *sbb, const uint8_t **data, uint32_t *data_len)
get the data for one SBB
Definition: util-streaming-buffer.c:761
SCMutex
#define SCMutex
Definition: threads-debug.h:114
TcpStreamCnf_::reassembly_toserver_chunk_size
uint16_t reassembly_toserver_chunk_size
Definition: stream-tcp.h:62
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:111
StreamingBufferBlock
block of continues data
Definition: util-streaming-buffer.h:82
FLOW_DESTROY
#define FLOW_DESTROY(f)
Definition: flow-util.h:130
Packet_::src
Address src
Definition: decode.h:424
debug.h
StreamingBufferConfig_::Realloc
void *(* Realloc)(void *ptr, size_t orig_size, size_t size)
Definition: util-streaming-buffer.h:73
STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED
#define STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED
Definition: stream-tcp-private.h:213
STREAM_RAW_PROGRESS
#define STREAM_RAW_PROGRESS(stream)
Definition: stream-tcp-private.h:133
app-layer.h
StreamTcpCheckStreamContents
int StreamTcpCheckStreamContents(uint8_t *stream_policy, uint16_t sp_size, TcpStream *stream)
The Function Checks the reassembled stream contents against predefined stream contents according to O...
Definition: stream-tcp-reassemble.c:2038