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