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