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 
454  if (f->alparser) {
455  const uint16_t eof_flags = APP_LAYER_PARSER_EOF_TS | APP_LAYER_PARSER_EOF_TC;
456  const bool was_eof = SCAppLayerParserStateIssetFlag(f->alparser, eof_flags) == eof_flags;
458  /* The app layer is at EOF from here on: no further app-layer
459  * update will reach the tx loggers, while the flow may end up
460  * dropped (flow end skips FLOW_ACTION_DROP flows), so the txs
461  * still pending would never be logged. Ask the next output
462  * stage to run the loggers once. Only on the transition, so
463  * the flush does not repeat per packet. */
464  if (!was_eof) {
466  }
467  }
468 }
469 
470 /** \param f locked flow */
472 {
473  if (f->protoctx == NULL || f->proto != IPPROTO_TCP)
474  return 0;
475 
478 }
479 
480 static int StreamTcpReassemblyConfig(bool quiet)
481 {
482  uint32_t segment_prealloc = 2048;
483  SCConfNode *seg = SCConfGetNode("stream.reassembly.segment-prealloc");
484  if (seg) {
485  uint32_t prealloc = 0;
486  if (StringParseUint32(&prealloc, 10, (uint16_t)strlen(seg->val), seg->val) < 0) {
487  SCLogError("segment-prealloc of "
488  "%s is invalid",
489  seg->val);
490  return -1;
491  }
492  segment_prealloc = prealloc;
493  }
494  if (!quiet)
495  SCLogConfig("stream.reassembly \"segment-prealloc\": %u", segment_prealloc);
496  stream_config.prealloc_segments = segment_prealloc;
497 
498  int overlap_diff_data = 0;
499  (void)SCConfGetBool("stream.reassembly.check-overlap-different-data", &overlap_diff_data);
500  if (overlap_diff_data) {
502  }
503  if (StreamTcpInlineMode()) {
505  }
506 
507  uint16_t max_regions = 8;
508  SCConfNode *mr = SCConfGetNode("stream.reassembly.max-regions");
509  if (mr) {
510  uint16_t max_r = 0;
511  if (StringParseUint16(&max_r, 10, (uint16_t)strlen(mr->val), mr->val) < 0) {
512  SCLogError("max-regions %s is invalid", mr->val);
513  return -1;
514  }
515  max_regions = max_r;
516  }
517  if (!quiet)
518  SCLogConfig("stream.reassembly \"max-regions\": %u", max_regions);
519 
520  stream_config.prealloc_segments = segment_prealloc;
522  stream_config.sbcnf.max_regions = max_regions;
524  stream_config.sbcnf.Calloc = ReassembleCalloc;
526  stream_config.sbcnf.Free = ReassembleFree;
527 
528  return 0;
529 }
530 
531 int StreamTcpReassembleInit(bool quiet)
532 {
533  /* init the memcap/use tracker */
535 
536  if (StreamTcpReassemblyConfig(quiet) < 0)
537  return -1;
538 
539 #ifdef DEBUG
540  SCMutexInit(&segment_pool_memuse_mutex, NULL);
541 #endif
542  StatsRegisterGlobalCounter("tcp.reassembly_memuse",
544  return 0;
545 }
546 
547 void StreamTcpReassembleFree(bool quiet)
548 {
549  SCMutexLock(&segment_thread_pool_mutex);
550  if (segment_thread_pool != NULL) {
552  segment_thread_pool = NULL;
553  }
554  SCMutexUnlock(&segment_thread_pool_mutex);
555  SCMutexDestroy(&segment_thread_pool_mutex);
556 
557 #ifdef DEBUG
558  if (segment_pool_memuse > 0)
559  SCLogDebug("segment_pool_memuse %" PRIu64 " segment_pool_memcnt %" PRIu64 "",
560  segment_pool_memuse, segment_pool_memcnt);
561  SCMutexDestroy(&segment_pool_memuse_mutex);
562 #endif
563 }
564 
566 {
567  SCEnter();
569  if (unlikely(ra_ctx == NULL))
570  return NULL;
571 
572  ra_ctx->app_tctx = AppLayerGetCtxThread();
573 
574  SCMutexLock(&segment_thread_pool_mutex);
575  if (segment_thread_pool == NULL) {
576  segment_thread_pool = PoolThreadInit(1, /* thread */
577  0, /* unlimited */
578  stream_config.prealloc_segments, sizeof(TcpSegment), TcpSegmentPoolAlloc,
579  TcpSegmentPoolInit, TcpSegmentPoolCleanup);
580  ra_ctx->segment_thread_pool_id = 0;
581  SCLogDebug("pool size %d, thread segment_thread_pool_id %d",
583  ra_ctx->segment_thread_pool_id);
584  } else {
585  /* grow segment_thread_pool until we have an element for our thread id */
587  SCLogDebug("pool size %d, thread segment_thread_pool_id %d",
589  ra_ctx->segment_thread_pool_id);
590  }
591  SCMutexUnlock(&segment_thread_pool_mutex);
592  if (ra_ctx->segment_thread_pool_id < 0 || segment_thread_pool == NULL) {
593  SCLogError("failed to setup/expand stream segment pool. Expand stream.reassembly.memcap?");
595  SCReturnPtr(NULL, "TcpReassemblyThreadCtx");
596  }
597 
598  SCReturnPtr(ra_ctx, "TcpReassemblyThreadCtx");
599 }
600 
602 {
603  SCEnter();
605 
606  if (ra_ctx) {
608  SCFree(ra_ctx);
609  }
610  SCReturn;
611 }
612 
613 static void StreamTcpReassembleExceptionPolicyStatsIncr(
614  ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, enum ExceptionPolicy policy)
615 {
616  StatsCounterId id = ra_ctx->counter_tcp_reas_eps.eps_id[policy];
617  if (likely(tv && id.id > 0)) {
618  StatsCounterIncr(&tv->stats, id);
619  }
620 }
621 
622 /**
623  * \brief check if stream in pkt direction has depth reached
624  *
625  * \param p packet with *LOCKED* flow
626  *
627  * \retval true stream has depth reached
628  * \retval false stream does not have depth reached
629  */
631 {
632  if (p->flow != NULL && p->flow->protoctx != NULL) {
634  TcpStream *stream;
635  if (p->flowflags & FLOW_PKT_TOSERVER) {
636  stream = &ssn->client;
637  } else {
638  stream = &ssn->server;
639  }
640 
641  return (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) != 0;
642  }
643 
644  return false;
645 }
646 
647 /**
648  * \internal
649  * \brief Function to check the reassembly depth value against the
650  * allowed max depth of the stream reassembly for TCP streams.
651  *
652  * \param stream stream direction
653  * \param seq sequence number where "size" starts
654  * \param size size of the segment that is added
655  *
656  * \retval size Part of the size that fits in the depth, 0 if none
657  */
658 static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream,
659  uint32_t seq, uint32_t size)
660 {
661  SCEnter();
662 
663  /* if the configured depth value is 0, it means there is no limit on
664  reassembly depth. Otherwise carry on my boy ;) */
665  if (ssn->reassembly_depth == 0) {
666  SCReturnUInt(size);
667  }
668 
669  /* if the final flag is set, we're not accepting anymore */
671  SCReturnUInt(0);
672  }
673 
674  uint64_t seg_depth;
675  if (SEQ_GT(stream->base_seq, seq)) {
676  if (SEQ_LEQ(seq+size, stream->base_seq)) {
677  SCLogDebug("segment entirely before base_seq, weird: base %u, seq %u, re %u",
678  stream->base_seq, seq, seq+size);
679  SCReturnUInt(0);
680  }
681 
682  seg_depth = STREAM_BASE_OFFSET(stream) + size - (stream->base_seq - seq);
683  } else {
684  seg_depth = STREAM_BASE_OFFSET(stream) + ((seq + size) - stream->base_seq);
685  }
686 
687  /* if the base_seq has moved past the depth window we stop
688  * checking and just reject the rest of the packets including
689  * retransmissions. Saves us the hassle of dealing with sequence
690  * wraps as well */
691  SCLogDebug("seq + size %u, base %u, seg_depth %"PRIu64" limit %u", (seq + size),
692  stream->base_seq, seg_depth,
694 
695  if (seg_depth > (uint64_t)ssn->reassembly_depth) {
696  SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED");
698  SCReturnUInt(0);
699  }
700  SCLogDebug("NOT STREAMTCP_STREAM_FLAG_DEPTH_REACHED");
701  SCLogDebug("%"PRIu64" <= %u", seg_depth, ssn->reassembly_depth);
702 #if 0
703  SCLogDebug("full depth not yet reached: %"PRIu64" <= %"PRIu32,
704  (stream->base_seq_offset + stream->base_seq + size),
705  (stream->isn + ssn->reassembly_depth));
706 #endif
707  if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + ssn->reassembly_depth))) {
708  /* packet (partly?) fits the depth window */
709 
710  if (SEQ_LEQ((seq + size),(stream->isn + 1 + ssn->reassembly_depth))) {
711  /* complete fit */
712  SCReturnUInt(size);
713  } else {
715  /* partial fit, return only what fits */
716  uint32_t part = (stream->isn + 1 + ssn->reassembly_depth) - seq;
717  DEBUG_VALIDATE_BUG_ON(part > size);
718  if (part > size)
719  part = size;
720  SCReturnUInt(part);
721  }
722  }
723 
724  SCReturnUInt(0);
725 }
726 
728 {
729  if (RB_EMPTY(&stream->sb.sbb_tree)) {
730  if (stream->sb.region.stream_offset != 0)
731  return 0;
732 
733  return stream->sb.region.buf_offset;
734  }
735 
736  DEBUG_VALIDATE_BUG_ON(stream->sb.head == NULL);
737  DEBUG_VALIDATE_BUG_ON(stream->sb.sbb_size == 0);
738  return stream->sb.sbb_size;
739 }
740 
741 /**
742  * \brief Insert a TCP packet data into the stream reassembly engine.
743  *
744  * \retval 0 good segment, as far as we checked.
745  * \retval -1 insert failure due to memcap
746  *
747  * If the retval is 0 the segment is inserted correctly, or overlap is handled,
748  * or it wasn't added because of reassembly depth.
749  *
750  */
752  TcpSession *ssn, TcpStream *stream, Packet *p)
753 {
754  SCEnter();
755 
756  if (ssn->data_first_seen_dir == 0) {
757  if (PKT_IS_TOSERVER(p)) {
758  ssn->data_first_seen_dir = STREAM_TOSERVER;
759  } else {
760  ssn->data_first_seen_dir = STREAM_TOCLIENT;
761  }
762  }
763 
764  /* If the OS policy is not set then set the OS policy for this stream */
765  if (stream->os_policy == 0) {
766  StreamTcpSetOSPolicy(stream, p);
767  }
768 
771  SCLogDebug("ssn %p: both app and raw reassembly disabled, not reassembling", ssn);
772  SCReturnInt(0);
773  }
774 
775  uint16_t *urg_offset;
776  if (PKT_IS_TOSERVER(p)) {
777  urg_offset = &ssn->urg_offset_ts;
778  } else {
779  urg_offset = &ssn->urg_offset_tc;
780  }
781 
782  const TCPHdr *tcph = PacketGetTCP(p);
783  /* segment sequence number, offset by previously accepted
784  * URG OOB data. */
785  uint32_t seg_seq = TCP_GET_RAW_SEQ(tcph) - (*urg_offset);
786  uint8_t urg_data = 0;
787 
788  /* if stream_config.urgent_policy == TCP_STREAM_URGENT_DROP, we won't get here */
789  if (tcph->th_flags & TH_URG) {
790  const uint16_t urg_ptr = SCNtohs(tcph->th_urp);
791  if (urg_ptr > 0 && urg_ptr <= p->payload_len &&
794  /* track up to 64k out of band URG bytes. Fall back to inline
795  * when that budget is exceeded. */
796  if ((*urg_offset) < UINT16_MAX) {
798  (*urg_offset)++;
799 
800  if ((*urg_offset) == UINT16_MAX) {
802  }
803  } else {
804  /* OOB limit DROP is handled here */
807  SCReturnInt(0);
808  }
809  }
810  urg_data = 1; /* only treat last 1 byte as out of band. */
813  }
814 
815  /* depending on hitting the OOB limit, update urg_data or not */
817  (*urg_offset) == UINT16_MAX &&
819  urg_data = 0;
820  } else {
821  if (urg_ptr == 1 && p->payload_len == 1) {
822  SCLogDebug("no non-URG data");
823  SCReturnInt(0);
824  }
825  }
826  }
827  }
828 
829  const uint16_t payload_len = p->payload_len - urg_data;
830 
831  /* If we have reached the defined depth for either of the stream, then stop
832  reassembling the TCP session */
833  uint32_t size = StreamTcpReassembleCheckDepth(ssn, stream, seg_seq, payload_len);
834  SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size);
835 
838  /* increment stream depth counter */
841  }
842  if (size == 0) {
843  SCLogDebug("ssn %p: depth reached, not reassembling", ssn);
844  SCReturnInt(0);
845  }
846 
848  if (size > payload_len)
849  size = payload_len;
850 
851  TcpSegment *seg = StreamTcpGetSegment(tv, ra_ctx);
852  if (seg == NULL) {
853  SCLogDebug("segment_pool is empty");
856  SCReturnInt(-1);
857  }
858 
859  DEBUG_VALIDATE_BUG_ON(size > UINT16_MAX);
860  TCP_SEG_LEN(seg) = (uint16_t)size;
861  /* set SEQUENCE number, adjusted to any URG pointer offset */
862  seg->seq = seg_seq;
863 
864  /* HACK: for TFO SYN packets the seq for data starts at + 1 */
865  if (TCP_HAS_TFO(p) && p->payload_len && (tcph->th_flags & TH_SYN))
866  seg->seq += 1;
867 
868  /* proto detection skipped, but now we do get data. Set event. */
869  if (RB_EMPTY(&stream->seg_tree) &&
871 
873  }
874 
875  int r = StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, seg, p, p->payload, payload_len);
876  if (r < 0) {
877  if (r == -SC_ENOMEM) {
879  }
880  SCLogDebug("StreamTcpReassembleInsertSegment failed");
881  SCReturnInt(-1);
882  }
883  SCReturnInt(0);
884 }
885 
886 static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream,
887  Packet *p)
888 {
889  uint8_t flag = 0;
890 
892  flag |= STREAM_START;
893  }
894 
895  if (ssn->state == TCP_CLOSED) {
896  flag |= STREAM_EOF;
897  }
898 
900  flag |= STREAM_MIDSTREAM;
901  }
902 
903  if (p->flags & PKT_PSEUDO_STREAM_END) {
904  flag |= STREAM_EOF;
905  }
906 
907  if (&ssn->client == stream) {
908  flag |= STREAM_TOSERVER;
909  } else {
910  flag |= STREAM_TOCLIENT;
911  }
913  flag |= STREAM_DEPTH;
914  }
915  return flag;
916 }
917 
918 /**
919  * \brief Check the minimum size limits for reassembly.
920  *
921  * \retval false don't reassemble yet
922  * \retval true do reassemble
923  */
924 static bool StreamTcpReassembleRawCheckLimit(
925  const TcpSession *ssn, const TcpStream *stream, const Packet *p)
926 {
927  SCEnter();
928 
929  /* if any of these flags is set we always inspect immediately */
930 #define STREAMTCP_STREAM_FLAG_FLUSH_FLAGS \
931  ( STREAMTCP_STREAM_FLAG_DEPTH_REACHED \
932  | STREAMTCP_STREAM_FLAG_TRIGGER_RAW \
933  | STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)
934 
937  SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_DEPTH_REACHED "
938  "is set, so not expecting any new data segments");
939  }
941  SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_TRIGGER_RAW is set");
942  }
944  SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED is set, "
945  "so no new segments will be considered");
946  }
947  SCReturnBool(true);
948  }
949 #undef STREAMTCP_STREAM_FLAG_FLUSH_FLAGS
950 
951  /* some states mean we reassemble no matter how much data we have */
952  if (ssn->state > TCP_TIME_WAIT)
953  SCReturnBool(true);
954 
956  SCReturnBool(true);
957 
958  const uint64_t last_ack_abs = GetAbsLastAck(stream);
959  int64_t diff = last_ack_abs - STREAM_RAW_PROGRESS(stream);
960  int64_t chunk_size = PKT_IS_TOSERVER(p) ? (int64_t)stream_config.reassembly_toserver_chunk_size
962 
963  /* check if we have enough data to do raw reassembly */
964  if (chunk_size <= diff) {
965  SCReturnBool(true);
966  } else {
967  SCLogDebug("%s min chunk len not yet reached: "
968  "last_ack %" PRIu32 ", ra_raw_base_seq %" PRIu32 ", %" PRIu32 " < "
969  "%" PRIi64,
970  PKT_IS_TOSERVER(p) ? "toserver" : "toclient", stream->last_ack, stream->base_seq,
971  (stream->last_ack - stream->base_seq), chunk_size);
972  SCReturnBool(false);
973  }
974 
975  SCReturnBool(false);
976 }
977 
978 /**
979  * \brief see what if any work the TCP session still needs
980  */
981 uint8_t StreamNeedsReassembly(const TcpSession *ssn, uint8_t direction)
982 {
983  const TcpStream *stream = NULL;
984 #ifdef DEBUG
985  const char *dirstr = NULL;
986 #endif
987  if (direction == STREAM_TOSERVER) {
988  stream = &ssn->client;
989 #ifdef DEBUG
990  dirstr = "client";
991 #endif
992  } else {
993  stream = &ssn->server;
994 #ifdef DEBUG
995  dirstr = "server";
996 #endif
997  }
998  int use_app = 1;
999  int use_raw = 1;
1000 
1002  // app is dead
1003  use_app = 0;
1004  }
1005 
1006  if (stream->flags & STREAMTCP_STREAM_FLAG_DISABLE_RAW) {
1007  // raw is dead
1008  use_raw = 0;
1009  }
1010  if (use_raw) {
1011  const uint64_t right_edge =
1012  STREAM_BASE_OFFSET(stream) + stream->segs_right_edge - stream->base_seq;
1013  SCLogDebug("%s: app %" PRIu64 " (use: %s), raw %" PRIu64
1014  " (use: %s). Stream right edge: %" PRIu64,
1015  dirstr, STREAM_APP_PROGRESS(stream), use_app ? "yes" : "no",
1016  STREAM_RAW_PROGRESS(stream), use_raw ? "yes" : "no", right_edge);
1017  if (right_edge > STREAM_RAW_PROGRESS(stream)) {
1018  SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION", dirstr);
1020  }
1021  }
1022  if (use_app) {
1023  const uint64_t right_edge = StreamingBufferGetConsecutiveDataRightEdge(&stream->sb);
1024  SCLogDebug("%s: app %" PRIu64 " (use: %s), raw %" PRIu64
1025  " (use: %s). Stream right edge: %" PRIu64,
1026  dirstr, STREAM_APP_PROGRESS(stream), use_app ? "yes" : "no",
1027  STREAM_RAW_PROGRESS(stream), use_raw ? "yes" : "no", right_edge);
1028  if (right_edge > STREAM_APP_PROGRESS(stream)) {
1029  SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION", dirstr);
1031  }
1032  }
1033 
1034  SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NONE", dirstr);
1036 }
1037 
1038 #ifdef DEBUG
1039 static uint64_t GetStreamSize(TcpStream *stream)
1040 {
1041  if (stream) {
1042  uint64_t size = 0;
1043  uint32_t cnt = 0;
1044  uint64_t last_ack_abs = GetAbsLastAck(stream);
1045  uint64_t last_re = 0;
1046 
1047  SCLogDebug("stream_offset %" PRIu64, stream->sb.region.stream_offset);
1048 
1049  TcpSegment *seg;
1050  RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
1051  const uint64_t seg_abs =
1052  STREAM_BASE_OFFSET(stream) + (uint64_t)(seg->seq - stream->base_seq);
1053  if (last_re != 0 && last_re < seg_abs) {
1054  const char *gacked = NULL;
1055  if (last_ack_abs >= seg_abs) {
1056  gacked = "fully ack'd";
1057  } else if (last_ack_abs > last_re) {
1058  gacked = "partly ack'd";
1059  } else {
1060  gacked = "not yet ack'd";
1061  }
1062  SCLogDebug(" -> gap of size %" PRIu64 ", ack:%s", seg_abs - last_re, gacked);
1063  }
1064 
1065  const char *acked = NULL;
1066  if (last_ack_abs >= seg_abs + (uint64_t)TCP_SEG_LEN(seg)) {
1067  acked = "fully ack'd";
1068  } else if (last_ack_abs > seg_abs) {
1069  acked = "partly ack'd";
1070  } else {
1071  acked = "not yet ack'd";
1072  }
1073 
1074  SCLogDebug("%u -> seg %p seq %u abs %" PRIu64 " size %u abs %" PRIu64 " (%" PRIu64
1075  ") ack:%s",
1076  cnt, seg, seg->seq, seg_abs, TCP_SEG_LEN(seg),
1077  seg_abs + (uint64_t)TCP_SEG_LEN(seg), STREAM_BASE_OFFSET(stream), acked);
1078  last_re = seg_abs + (uint64_t)TCP_SEG_LEN(seg);
1079  cnt++;
1080  size += (uint64_t)TCP_SEG_LEN(seg);
1081  }
1082 
1083  SCLogDebug("size %"PRIu64", cnt %"PRIu32, size, cnt);
1084  return size;
1085  }
1086  return (uint64_t)0;
1087 }
1088 
1089 static void GetSessionSize(TcpSession *ssn, Packet *p)
1090 {
1091  uint64_t size = 0;
1092  if (ssn) {
1093  size = GetStreamSize(&ssn->client);
1094  size += GetStreamSize(&ssn->server);
1095 
1096  SCLogDebug("size %" PRIu64 ", packet %" PRIu64, size, PcapPacketCntGet(p));
1097  }
1098 }
1099 #endif
1100 
1101 static inline bool GapAhead(const TcpStream *stream, StreamingBufferBlock *cur_blk)
1102 {
1103  StreamingBufferBlock *nblk = SBB_RB_NEXT(cur_blk);
1104  /* only if the stream has been ack'd, consider a gap for sure
1105  * otherwise there may still be a chance of pkts coming in */
1106  return nblk && (cur_blk->offset + cur_blk->len < nblk->offset) &&
1107  GetAbsLastAck(stream) > (cur_blk->offset + cur_blk->len);
1108 }
1109 
1110 /** \internal
1111  *
1112  * Get buffer, or first part of the buffer if data gaps exist.
1113  *
1114  * \brief get stream data from offset
1115  * \param offset stream offset
1116  * \param check_for_gap check if there is a gap ahead. Optional as it is only
1117  * needed for app-layer incomplete support.
1118  * \retval bool pkt loss ahead */
1119 static bool GetAppBuffer(const TcpStream *stream, const uint8_t **data, uint32_t *data_len,
1120  uint64_t offset, const bool check_for_gap)
1121 {
1122  const uint8_t *mydata;
1123  uint32_t mydata_len;
1124  bool gap_ahead = false;
1125 
1126  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1127  SCLogDebug("getting one blob");
1128 
1129  StreamingBufferGetDataAtOffset(&stream->sb, &mydata, &mydata_len, offset);
1130 
1131  *data = mydata;
1132  *data_len = mydata_len;
1133  } else {
1134  SCLogDebug("block mode");
1135  StreamingBufferBlock key = { .offset = offset, .len = 0 };
1136  StreamingBufferBlock *blk = SBB_RB_FIND_INCLUSIVE((struct SBB *)&stream->sb.sbb_tree, &key);
1137  if (blk == NULL) {
1138  *data = NULL;
1139  *data_len = 0;
1140  return false;
1141  }
1142  SCLogDebug("blk %p blk->offset %" PRIu64 ", blk->len %u", blk, blk->offset, blk->len);
1143 
1144  /* block at expected offset */
1145  if (blk->offset == offset) {
1146  SCLogDebug("blk at offset");
1147 
1148  StreamingBufferSBBGetData(&stream->sb, blk, data, data_len);
1149  DEBUG_VALIDATE_BUG_ON(blk->len != *data_len);
1150 
1151  gap_ahead = check_for_gap && GapAhead(stream, blk);
1152 
1153  /* block past out offset */
1154  } else if (blk->offset > offset) {
1155  SCLogDebug("gap, want data at offset %"PRIu64", "
1156  "got data at %"PRIu64". GAP of size %"PRIu64,
1157  offset, blk->offset, blk->offset - offset);
1158  *data = NULL;
1159  *data_len = (uint32_t)(blk->offset - offset);
1160 
1161  /* block starts before offset, but ends after */
1162  } else if (offset > blk->offset && offset <= (blk->offset + blk->len)) {
1163  SCLogDebug("get data from offset %"PRIu64". SBB %"PRIu64"/%u",
1164  offset, blk->offset, blk->len);
1165  StreamingBufferSBBGetDataAtOffset(&stream->sb, blk, data, data_len, offset);
1166  SCLogDebug("data %p, data_len %u", *data, *data_len);
1167 
1168  gap_ahead = check_for_gap && GapAhead(stream, blk);
1169 
1170  } else {
1171  *data = NULL;
1172  *data_len = 0;
1173  }
1174  }
1175  return gap_ahead;
1176 }
1177 
1178 /** \internal
1179  * \brief check to see if we should declare a GAP
1180  * Call this when the app layer didn't get data at the requested
1181  * offset.
1182  */
1183 static inline bool CheckGap(TcpSession *ssn, TcpStream *stream, Packet *p)
1184 {
1185  const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
1186  const int ackadded = (ssn->state >= TCP_FIN_WAIT1) ? 1 : 0;
1187  const uint64_t last_ack_abs = GetAbsLastAck(stream) - (uint64_t)ackadded;
1188 
1189  SCLogDebug("last_ack %u abs %" PRIu64, stream->last_ack, last_ack_abs);
1190  SCLogDebug("next_seq %u", stream->next_seq);
1191 
1192  /* if last_ack_abs is beyond the app_progress data that we haven't seen
1193  * has been ack'd. This looks like a GAP. */
1194  if (last_ack_abs > app_progress) {
1195  /* however, we can accept ACKs a bit too liberally. If last_ack
1196  * is beyond next_seq, we only consider it a gap now if we do
1197  * already have data beyond the gap. */
1198  if (SEQ_GT(stream->last_ack, stream->next_seq)) {
1199  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1200  SCLogDebug("packet %" PRIu64 ": no GAP. "
1201  "next_seq %u < last_ack %u, but no data in list",
1202  PcapPacketCntGet(p), stream->next_seq, stream->last_ack);
1203  return false;
1204  }
1205  const uint64_t next_seq_abs =
1206  STREAM_BASE_OFFSET(stream) + (stream->next_seq - stream->base_seq);
1207  const StreamingBufferBlock *blk = stream->sb.head;
1208  if (blk->offset > next_seq_abs && blk->offset < last_ack_abs) {
1209  /* ack'd data after the gap */
1210  SCLogDebug("packet %" PRIu64 ": GAP. "
1211  "next_seq %u < last_ack %u, but ACK'd data beyond gap.",
1212  PcapPacketCntGet(p), stream->next_seq, stream->last_ack);
1213  return true;
1214  }
1215  }
1216 
1217  SCLogDebug("packet %" PRIu64 ": GAP! "
1218  "last_ack_abs %" PRIu64 " > app_progress %" PRIu64 ", "
1219  "but we have no data.",
1220  PcapPacketCntGet(p), last_ack_abs, app_progress);
1221  return true;
1222  }
1223  SCLogDebug("packet %" PRIu64 ": no GAP. "
1224  "last_ack_abs %" PRIu64 " <= app_progress %" PRIu64,
1225  PcapPacketCntGet(p), last_ack_abs, app_progress);
1226  return false;
1227 }
1228 
1229 static inline uint32_t AdjustToAcked(const Packet *p,
1230  const TcpSession *ssn, const TcpStream *stream,
1231  const uint64_t app_progress, const uint32_t data_len)
1232 {
1233  uint32_t adjusted = data_len;
1234 
1235  /* get window of data that is acked */
1236  if (!StreamTcpInlineMode()) {
1237  SCLogDebug("ssn->state %s", StreamTcpStateAsString(ssn->state));
1238  if (data_len == 0 || ((ssn->state < TCP_CLOSED ||
1239  (ssn->state == TCP_CLOSED &&
1240  (ssn->flags & STREAMTCP_FLAG_CLOSED_BY_RST) != 0)) &&
1241  (p->flags & PKT_PSEUDO_STREAM_END))) {
1242  // fall through, we use all available data
1243  } else {
1244  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1245  DEBUG_VALIDATE_BUG_ON(app_progress > last_ack_abs);
1246 
1247  /* see if the buffer contains unack'd data as well */
1248  if (app_progress <= last_ack_abs && app_progress + data_len > last_ack_abs) {
1249  adjusted = (uint32_t)(last_ack_abs - app_progress);
1250  DEBUG_VALIDATE_BUG_ON(adjusted > data_len);
1251  SCLogDebug("data len adjusted to %u to make sure only ACK'd "
1252  "data is considered", adjusted);
1253  }
1254  }
1255  }
1256  return adjusted;
1257 }
1258 
1259 /** \internal
1260  * \brief get stream buffer and update the app-layer
1261  * \param stream pointer to pointer as app-layer can switch flow dir
1262  * \retval 0 success
1263  */
1264 static int ReassembleUpdateAppLayer(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn,
1265  TcpStream **stream, Packet *p, enum StreamUpdateDir app_update_dir)
1266 {
1267  uint64_t app_progress = STREAM_APP_PROGRESS(*stream);
1268 
1269  SCLogDebug("app progress %"PRIu64, app_progress);
1270 #ifdef DEBUG
1271  uint64_t last_ack_abs = GetAbsLastAck(*stream);
1272  SCLogDebug("last_ack %u (abs %" PRIu64 "), base_seq %u", (*stream)->last_ack, last_ack_abs,
1273  (*stream)->base_seq);
1274 #endif
1275  const uint8_t *mydata;
1276  uint32_t mydata_len;
1277  bool last_was_gap = false;
1278 
1279  while (1) {
1280  const uint8_t flags = StreamGetAppLayerFlags(ssn, *stream, p);
1281  bool check_for_gap_ahead = ((*stream)->data_required > 0);
1282  bool gap_ahead =
1283  GetAppBuffer(*stream, &mydata, &mydata_len, app_progress, check_for_gap_ahead);
1284  SCLogDebug("gap_ahead %s mydata_len %u", BOOL2STR(gap_ahead), mydata_len);
1285  if (last_was_gap && mydata_len == 0) {
1286  break;
1287  }
1288  last_was_gap = false;
1289 
1290  /* make sure to only deal with ACK'd data */
1291  mydata_len = AdjustToAcked(p, ssn, *stream, app_progress, mydata_len);
1292  DEBUG_VALIDATE_BUG_ON(mydata_len > (uint32_t)INT_MAX);
1293  if (mydata == NULL && mydata_len > 0 && CheckGap(ssn, *stream, p)) {
1294  SCLogDebug("sending GAP to app-layer (size: %u)", mydata_len);
1295 
1296  int r = AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, NULL, mydata_len,
1297  StreamGetAppLayerFlags(ssn, *stream, p) | STREAM_GAP, app_update_dir);
1298  AppLayerProfilingStore(ra_ctx->app_tctx, p);
1299 
1301  (*stream)->flags |= STREAMTCP_STREAM_FLAG_HAS_GAP;
1304 
1305  /* AppLayerHandleTCPData has likely updated progress. */
1306  const bool no_progress_update = (app_progress == STREAM_APP_PROGRESS(*stream));
1307  app_progress = STREAM_APP_PROGRESS(*stream);
1308 
1309  /* a GAP also consumes 'data required'. TODO perhaps we can use
1310  * this to skip post GAP data until the start of a next record. */
1311  if ((*stream)->data_required > 0) {
1312  if ((*stream)->data_required > mydata_len) {
1313  (*stream)->data_required -= mydata_len;
1314  } else {
1315  (*stream)->data_required = 0;
1316  }
1317  }
1318  if (r < 0)
1319  return 0;
1320  if (no_progress_update)
1321  break;
1322  last_was_gap = true;
1323  continue;
1324 
1325  } else if (flags & STREAM_DEPTH) {
1326  SCLogDebug("DEPTH");
1327  // we're just called once with this flag, so make sure we pass it on
1328  if (mydata == NULL && mydata_len > 0) {
1329  mydata_len = 0;
1330  }
1331  } else if (mydata == NULL || (mydata_len == 0 && ((flags & STREAM_EOF) == 0))) {
1332  SCLogDebug("GAP?1");
1333  /* Possibly a gap, but no new data. */
1334  if ((p->flags & PKT_PSEUDO_STREAM_END) == 0 || ssn->state < TCP_CLOSED)
1335  SCReturnInt(0);
1336 
1337  mydata = NULL;
1338  mydata_len = 0;
1339  SCLogDebug("%" PRIu64 " got %p/%u", PcapPacketCntGet(p), mydata, mydata_len);
1340  break;
1341  }
1342  DEBUG_VALIDATE_BUG_ON(mydata == NULL && mydata_len > 0);
1343 
1344  SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64,
1345  *stream, &(*stream)->sb, mydata_len, app_progress);
1346 
1347  if ((p->flags & PKT_PSEUDO_STREAM_END) == 0 || ssn->state < TCP_CLOSED) {
1348  SCLogDebug("GAP?2");
1349  if (mydata_len < (*stream)->data_required) {
1350  SCLogDebug("GAP?3 gap_head %s", BOOL2STR(gap_ahead));
1351  if (gap_ahead) {
1352  SCLogDebug("GAP while expecting more data (expect %u, gap size %u)",
1353  (*stream)->data_required, mydata_len);
1354  (*stream)->app_progress_rel += mydata_len;
1355  (*stream)->data_required -= mydata_len;
1356  // TODO send incomplete data to app-layer with special flag
1357  // indicating its all there is for this rec?
1358  } else {
1359  SCReturnInt(0);
1360  }
1361  app_progress = STREAM_APP_PROGRESS(*stream);
1362  continue;
1363  }
1364  }
1365  (*stream)->data_required = 0;
1366 
1367  SCLogDebug("parser");
1368  /* update the app-layer */
1369  (void)AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, (uint8_t *)mydata,
1370  mydata_len, flags, app_update_dir);
1371  AppLayerProfilingStore(ra_ctx->app_tctx, p);
1373  uint64_t new_app_progress = STREAM_APP_PROGRESS(*stream);
1374  if (new_app_progress == app_progress || FlowChangeProto(p->flow))
1375  break;
1376  app_progress = new_app_progress;
1377  if (flags & STREAM_DEPTH)
1378  break;
1379  }
1380 
1381  SCReturnInt(0);
1382 }
1383 
1384 /**
1385  * \brief Update the stream reassembly upon receiving a packet.
1386  *
1387  * For IDS mode, the stream is in the opposite direction of the packet,
1388  * as the ACK-packet is ACK'ing the stream.
1389  *
1390  * One of the utilities call by this function AppLayerHandleTCPData(),
1391  * has a feature where it will call this very same function for the
1392  * stream opposing the stream it is called with. This shouldn't cause
1393  * any issues, since processing of each stream is independent of the
1394  * other stream.
1395  */
1397  TcpStream *stream, Packet *p, enum StreamUpdateDir app_update_dir)
1398 {
1399  SCEnter();
1400 
1401  /* this function can be directly called by app layer protocol
1402  * detection. */
1405  SCLogDebug("stream no reassembly flag set or app-layer disabled.");
1406  SCReturnInt(0);
1407  }
1408 
1409 #ifdef DEBUG
1410  SCLogDebug("stream->seg_tree RB_MIN %p", RB_MIN(TCPSEG, &stream->seg_tree));
1411  GetSessionSize(ssn, p);
1412 #endif
1413  /* if no segments are in the list or all are already processed,
1414  * and state is beyond established, we send an empty msg */
1415  if (!STREAM_HAS_SEEN_DATA(stream) || STREAM_RIGHT_EDGE(stream) <= STREAM_APP_PROGRESS(stream))
1416  {
1417  /* send an empty EOF msg if we have no segments but TCP state
1418  * is beyond ESTABLISHED */
1419  if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) {
1420  SCLogDebug("sending empty eof message");
1421  /* send EOF to app layer */
1422  uint8_t stream_flags = StreamGetAppLayerFlags(ssn, stream, p);
1424  tv, ra_ctx, p, p->flow, ssn, &stream, NULL, 0, stream_flags, app_update_dir);
1425  AppLayerProfilingStore(ra_ctx->app_tctx, p);
1426 
1427  SCReturnInt(0);
1428  }
1429  }
1430 
1431  /* with all that out of the way, lets update the app-layer */
1432  return ReassembleUpdateAppLayer(tv, ra_ctx, ssn, &stream, p, app_update_dir);
1433 }
1434 
1435 /** \internal
1436  * \brief get stream data from offset
1437  * \param offset stream offset */
1438 static int GetRawBuffer(const TcpStream *stream, const uint8_t **data, uint32_t *data_len,
1439  StreamingBufferBlock **iter, uint64_t offset, uint64_t *data_offset)
1440 {
1441  const uint8_t *mydata;
1442  uint32_t mydata_len;
1443  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1444  SCLogDebug("getting one blob for offset %"PRIu64, offset);
1445 
1446  /* No gaps in the stream, data must exist in the streaming buffer array */
1447  uint64_t roffset = offset;
1448  if (offset) {
1449  StreamingBufferGetDataAtOffset(&stream->sb, &mydata, &mydata_len, offset);
1450  } else {
1451  StreamingBufferGetData(&stream->sb, &mydata, &mydata_len, &roffset);
1452  }
1453 
1454  *data = mydata;
1455  *data_len = mydata_len;
1456  *data_offset = roffset;
1457  } else {
1458  SCLogDebug("multiblob %s. Want offset %"PRIu64,
1459  *iter == NULL ? "starting" : "continuing", offset);
1460  if (*iter == NULL) {
1461  StreamingBufferBlock key = { .offset = offset, .len = 0 };
1462  *iter = SBB_RB_FIND_INCLUSIVE((struct SBB *)&stream->sb.sbb_tree, &key);
1463  SCLogDebug("*iter %p", *iter);
1464  }
1465  if (*iter == NULL) {
1466  SCLogDebug("no data");
1467  *data = NULL;
1468  *data_len = 0;
1469  *data_offset = 0;
1470  return 0;
1471  }
1472  SCLogDebug("getting multiple blobs. Iter %p, %"PRIu64"/%u", *iter, (*iter)->offset, (*iter)->len);
1473 
1474  StreamingBufferSBBGetData(&stream->sb, (*iter), &mydata, &mydata_len);
1475  SCLogDebug("mydata %p", mydata);
1476 
1477  if ((*iter)->offset < offset) {
1478  uint64_t delta = offset - (*iter)->offset;
1479  if (delta < mydata_len) {
1480  *data = mydata + delta;
1481  *data_len = (uint32_t)(mydata_len - delta);
1482  *data_offset = offset;
1483  } else {
1484  SCLogDebug("no data (yet)");
1485  *data = NULL;
1486  *data_len = 0;
1487  *data_offset = 0;
1488  }
1489 
1490  } else {
1491  *data = mydata;
1492  *data_len = mydata_len;
1493  *data_offset = (*iter)->offset;
1494  }
1495 
1496  *iter = SBB_RB_NEXT(*iter);
1497  SCLogDebug("*iter %p", *iter);
1498  }
1499  return 0;
1500 }
1501 
1502 /** \brief does the stream engine have data to inspect?
1503  *
1504  * Returns true if there is data to inspect. In IDS case this is
1505  * about ACK'd data in the packet's direction.
1506  *
1507  * In the IPS case this is about the packet itself.
1508  */
1510 {
1511  TcpStream *stream;
1512  if (PKT_IS_TOSERVER(p)) {
1513  stream = &ssn->client;
1514  } else {
1515  stream = &ssn->server;
1516  }
1517 
1518  if (RB_EMPTY(&stream->seg_tree)) {
1519  return false;
1520  }
1521 
1524  return false;
1525 
1526  if (!StreamTcpInlineMode()) {
1527  const uint64_t segs_re_abs =
1528  STREAM_BASE_OFFSET(stream) + stream->segs_right_edge - stream->base_seq;
1529  if (STREAM_RAW_PROGRESS(stream) == segs_re_abs) {
1530  return false;
1531  }
1532  if (StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 1) {
1533  return true;
1534  }
1535  } else {
1536  if (p->payload_len > 0 && (p->flags & PKT_STREAM_ADD)) {
1537  return true;
1538  }
1539  }
1540  return false;
1541 }
1542 
1543 /** \brief update stream engine after detection
1544  *
1545  * Tasked with progressing the 'progress' for Raw reassembly.
1546  * 2 main scenario's:
1547  * 1. progress is != 0, so we use this
1548  * 2. progress is 0, meaning the detect engine didn't touch
1549  * raw at all. In this case we need to look into progressing
1550  * raw anyway.
1551  *
1552  * Additionally, this function is tasked with disabling raw
1553  * reassembly if the app-layer requested to disable it.
1554  */
1555 void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, const uint64_t progress)
1556 {
1557  TcpStream *stream;
1558  if (PKT_IS_TOSERVER(p)) {
1559  stream = &ssn->client;
1560  } else {
1561  stream = &ssn->server;
1562  }
1563 
1564  if (progress > STREAM_RAW_PROGRESS(stream)) {
1565  DEBUG_VALIDATE_BUG_ON(progress - STREAM_RAW_PROGRESS(stream) > UINT32_MAX);
1566  uint32_t slide = (uint32_t)(progress - STREAM_RAW_PROGRESS(stream));
1567  stream->raw_progress_rel += slide;
1569 
1570  } else if (progress == 0) {
1571  uint64_t target;
1573  target = STREAM_APP_PROGRESS(stream);
1574  } else {
1575  target = GetAbsLastAck(stream);
1576  }
1577  if (target > STREAM_RAW_PROGRESS(stream)) {
1578  DEBUG_VALIDATE_BUG_ON(target - STREAM_RAW_PROGRESS(stream) > UINT32_MAX);
1579  uint32_t slide = (uint32_t)(target - STREAM_RAW_PROGRESS(stream));
1580  stream->raw_progress_rel += slide;
1581  }
1583 
1584  } else {
1585  SCLogDebug("pcap_cnt %" PRIu64 ": progress %" PRIu64 " app %" PRIu64 " raw %" PRIu64
1586  " tcp win %" PRIu32,
1587  PcapPacketCntGet(p), progress, STREAM_APP_PROGRESS(stream),
1588  STREAM_RAW_PROGRESS(stream), stream->window);
1589  }
1590 
1591  /* if we were told to accept no more raw data, we can mark raw as
1592  * disabled now. */
1595  SCLogDebug("ssn %p: STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED set, "
1596  "now that detect ran also set STREAMTCP_STREAM_FLAG_DISABLE_RAW", ssn);
1597  }
1598 
1599  SCLogDebug("stream raw progress now %"PRIu64, STREAM_RAW_PROGRESS(stream));
1600 }
1601 
1602 /** \internal
1603  * \brief get a buffer around the current packet and run the callback on it
1604  *
1605  * The inline/IPS scanning method takes the current payload and wraps it in
1606  * data from other segments.
1607  *
1608  * How much data is inspected is controlled by the available data, chunk_size
1609  * and the payload size of the packet.
1610  *
1611  * Large packets: if payload size is close to the chunk_size, where close is
1612  * defined as more than 67% of the chunk_size, a larger chunk_size will be
1613  * used: payload_len + 33% of the chunk_size.
1614  * If the payload size if equal to or bigger than the chunk_size, we use
1615  * payload len + 33% of the chunk size.
1616  */
1617 static int StreamReassembleRawInline(TcpSession *ssn, const Packet *p,
1618  StreamReassembleRawFunc Callback, void *cb_data, uint64_t *progress_out)
1619 {
1620  SCEnter();
1621  int r = 0;
1622 
1623  TcpStream *stream;
1624  if (PKT_IS_TOSERVER(p)) {
1625  stream = &ssn->client;
1626  } else {
1627  stream = &ssn->server;
1628  }
1629 
1630  if (p->payload_len == 0 || (p->flags & PKT_STREAM_ADD) == 0 ||
1632  {
1633  *progress_out = STREAM_RAW_PROGRESS(stream);
1634  return 0;
1635  }
1636 
1637  uint32_t chunk_size = PKT_IS_TOSERVER(p) ?
1640  if ((chunk_size <= p->payload_len) || (((chunk_size / 3) * 2) < p->payload_len)) {
1641  chunk_size = p->payload_len + (chunk_size / 3);
1642  SCLogDebug(
1643  "packet payload len %u, so chunk_size adjusted to %u", p->payload_len, chunk_size);
1644  }
1645 
1646  const TCPHdr *tcph = PacketGetTCP(p);
1647  /* use packet SEQ, but account for TFO needing a + 1 */
1648  const uint32_t tfo_add = (TCP_HAS_TFO(p));
1649  const uint32_t pkt_seq = TCP_GET_RAW_SEQ(tcph) + tfo_add;
1650  uint64_t packet_leftedge_abs = STREAM_BASE_OFFSET(stream) + (pkt_seq - stream->base_seq);
1651  uint64_t packet_rightedge_abs = packet_leftedge_abs + p->payload_len;
1652  SCLogDebug("packet_leftedge_abs %"PRIu64", rightedge %"PRIu64,
1653  packet_leftedge_abs, packet_rightedge_abs);
1654 
1655  const uint8_t *mydata = NULL;
1656  uint32_t mydata_len = 0;
1657  uint64_t mydata_offset = 0;
1658  /* simply return progress from the block we inspected. */
1659  bool return_progress = false;
1660 
1661  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1662  /* continues block */
1663  StreamingBufferGetData(&stream->sb, &mydata, &mydata_len, &mydata_offset);
1664  return_progress = true;
1665 
1666  } else {
1667  SCLogDebug("finding our SBB from offset %"PRIu64, packet_leftedge_abs);
1668  /* find our block */
1669  StreamingBufferBlock key = { .offset = packet_leftedge_abs, .len = p->payload_len };
1670  StreamingBufferBlock *sbb = SBB_RB_FIND_INCLUSIVE(&stream->sb.sbb_tree, &key);
1671  if (sbb) {
1672  SCLogDebug("found %p offset %"PRIu64" len %u", sbb, sbb->offset, sbb->len);
1673  StreamingBufferSBBGetData(&stream->sb, sbb, &mydata, &mydata_len);
1674  mydata_offset = sbb->offset;
1675  }
1676  }
1677 
1678  /* this can only happen if the segment insert of our current 'p' failed */
1679  uint64_t mydata_rightedge_abs = mydata_offset + mydata_len;
1680  if ((mydata == NULL || mydata_len == 0) || /* no data */
1681  (mydata_offset >= packet_rightedge_abs || /* data all to the right */
1682  packet_leftedge_abs >= mydata_rightedge_abs) || /* data all to the left */
1683  (packet_leftedge_abs < mydata_offset || /* data missing at the start */
1684  packet_rightedge_abs > mydata_rightedge_abs)) /* data missing at the end */
1685  {
1686  /* no data, or data is incomplete or wrong: use packet data */
1687  mydata = p->payload;
1688  mydata_len = p->payload_len;
1689  mydata_offset = packet_leftedge_abs;
1690  //mydata_rightedge_abs = packet_rightedge_abs;
1691  } else {
1692  /* adjust buffer to match chunk_size */
1693  SCLogDebug("chunk_size %u mydata_len %u", chunk_size, mydata_len);
1694  if (mydata_len > chunk_size) {
1695  uint32_t excess = mydata_len - chunk_size;
1696  SCLogDebug("chunk_size %u mydata_len %u excess %u", chunk_size, mydata_len, excess);
1697 
1698  if (mydata_rightedge_abs == packet_rightedge_abs) {
1699  mydata += excess;
1700  mydata_len -= excess;
1701  mydata_offset += excess;
1702  SCLogDebug("cutting front of the buffer with %u", excess);
1703  } else if (mydata_offset == packet_leftedge_abs) {
1704  mydata_len -= excess;
1705  SCLogDebug("cutting tail of the buffer with %u", excess);
1706  } else {
1707  DEBUG_VALIDATE_BUG_ON(mydata_offset > packet_leftedge_abs);
1708  uint32_t abs_before = (uint32_t)(packet_leftedge_abs - mydata_offset);
1709  DEBUG_VALIDATE_BUG_ON(packet_rightedge_abs > mydata_rightedge_abs);
1710  uint32_t abs_after = (uint32_t)(mydata_rightedge_abs - packet_rightedge_abs);
1711  uint32_t before = abs_before;
1712  uint32_t after = abs_after;
1713  SCLogDebug("before %u after %u", before, after);
1714 
1715  if (after >= (chunk_size - p->payload_len) / 2) {
1716  // more trailing data than we need
1717 
1718  if (before >= (chunk_size - p->payload_len) / 2) {
1719  // also more heading data, divide evenly
1720  before = after = (chunk_size - p->payload_len) / 2;
1721  } else {
1722  // heading data is less than requested, give the
1723  // rest to the trailing data
1724  after = (chunk_size - p->payload_len) - before;
1725  }
1726  } else {
1727  // less trailing data than requested
1728 
1729  if (before >= (chunk_size - p->payload_len) / 2) {
1730  before = (chunk_size - p->payload_len) - after;
1731  } else {
1732  // both smaller than their requested size
1733  }
1734  }
1735 
1736  /* adjust the buffer */
1737  DEBUG_VALIDATE_BUG_ON(before > abs_before);
1738  uint32_t skip = abs_before - before;
1739  DEBUG_VALIDATE_BUG_ON(after > abs_after);
1740  uint32_t cut = abs_after - after;
1741  DEBUG_VALIDATE_BUG_ON(skip > mydata_len);
1742  DEBUG_VALIDATE_BUG_ON(cut > mydata_len);
1743  DEBUG_VALIDATE_BUG_ON(skip + cut > mydata_len);
1744  mydata += skip;
1745  mydata_len -= (skip + cut);
1746  mydata_offset += skip;
1747  }
1748  }
1749  }
1750 
1751  /* run the callback */
1752  r = Callback(cb_data, mydata, mydata_len, mydata_offset);
1753  DEBUG_VALIDATE_BUG_ON(r < 0);
1754 
1755  if (return_progress) {
1756  *progress_out = (mydata_offset + mydata_len);
1757  } else {
1758  /* several blocks of data, so we need to be a bit more careful:
1759  * - if last_ack is beyond last progress, move progress forward to last_ack
1760  * - if our block matches or starts before last ack, return right edge of
1761  * our block.
1762  */
1763  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1764  SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs);
1765 
1766  if (STREAM_RAW_PROGRESS(stream) < last_ack_abs) {
1767  if (mydata_offset > last_ack_abs) {
1768  /* gap between us and last ack, set progress to last ack */
1769  *progress_out = last_ack_abs;
1770  } else {
1771  *progress_out = (mydata_offset + mydata_len);
1772  }
1773  } else {
1774  *progress_out = STREAM_RAW_PROGRESS(stream);
1775  }
1776  }
1777  return r;
1778 }
1779 
1780 /** \brief access 'raw' reassembly data.
1781  *
1782  * Access data as tracked by 'raw' tracker. Data is made available to
1783  * callback that is passed to this function.
1784  *
1785  * In the case of IDS the callback may be run multiple times if data
1786  * contains gaps. It will then be run for each block of data that is
1787  * continuous.
1788  *
1789  * The callback should give on of 2 return values:
1790  * - 0 ok
1791  * - 1 done
1792  * The value 1 will break the loop if there is a block list that is
1793  * inspected.
1794  *
1795  * This function will return the 'progress' value that has been
1796  * consumed until now.
1797  *
1798  * \param ssn tcp session
1799  * \param stream tcp stream
1800  * \param Callback the function pointer to the callback function
1801  * \param cb_data callback data
1802  * \param[in] progress_in progress to work from
1803  * \param[in] re right edge of data to consider
1804  * \param[out] progress_out absolute progress value of the data this
1805  * call handled.
1806  * \param eof we're wrapping up so inspect all data we have, incl unACKd
1807  */
1808 static int StreamReassembleRawDo(const TcpSession *ssn, const TcpStream *stream,
1809  StreamReassembleRawFunc Callback, void *cb_data, const uint64_t progress_in,
1810  const uint64_t re, uint64_t *progress_out, bool eof)
1811 {
1812  SCEnter();
1813  int r = 0;
1814 
1815  StreamingBufferBlock *iter = NULL;
1816  uint64_t progress = progress_in;
1817 
1818  /* loop through available buffers. On no packet loss we'll have a single
1819  * iteration. On missing data we'll walk the blocks */
1820  while (1) {
1821  const uint8_t *mydata;
1822  uint32_t mydata_len;
1823  uint64_t mydata_offset = 0;
1824 
1825  GetRawBuffer(stream, &mydata, &mydata_len, &iter, progress, &mydata_offset);
1826  if (mydata_len == 0) {
1827  SCLogDebug("no data");
1828  break;
1829  }
1830  //PrintRawDataFp(stdout, mydata, mydata_len);
1831 
1832  SCLogDebug("raw progress %"PRIu64, progress);
1833  SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64,
1834  stream, &stream->sb, mydata_len, progress);
1835 
1836  if (eof) {
1837  // inspect all remaining data, ack'd or not
1838  } else {
1839  if (re < progress) {
1840  SCLogDebug("nothing to do");
1841  goto end;
1842  }
1843 
1844  SCLogDebug("re %" PRIu64 ", raw_progress %" PRIu64, re, progress);
1845  SCLogDebug("raw_progress + mydata_len %" PRIu64 ", re %" PRIu64, progress + mydata_len,
1846  re);
1847 
1848  /* see if the buffer contains unack'd data as well */
1849  if (progress + mydata_len > re) {
1850 #ifdef DEBUG_VALIDATION
1851  uint32_t check = mydata_len;
1852 #endif
1853  mydata_len = (uint32_t)(re - progress);
1854  DEBUG_VALIDATE_BUG_ON(check < mydata_len);
1855  SCLogDebug("data len adjusted to %u to make sure only ACK'd "
1856  "data is considered", mydata_len);
1857  }
1858  }
1859  if (mydata_len == 0)
1860  break;
1861 
1862  SCLogDebug("data %p len %u", mydata, mydata_len);
1863 
1864  /* we have data. */
1865  r = Callback(cb_data, mydata, mydata_len, mydata_offset);
1866  DEBUG_VALIDATE_BUG_ON(r < 0);
1867 
1868  if (mydata_offset == progress) {
1869  SCLogDebug("progress %"PRIu64" increasing with data len %u to %"PRIu64,
1870  progress, mydata_len, progress_in + mydata_len);
1871 
1872  progress += mydata_len;
1873  SCLogDebug("raw progress now %"PRIu64, progress);
1874 
1875  /* data is beyond the progress we'd like, and before last ack. Gap. */
1876  } else if (mydata_offset > progress && mydata_offset < re) {
1877  SCLogDebug("GAP: data is missing from %"PRIu64" (%u bytes), setting to first data we have: %"PRIu64, progress, (uint32_t)(mydata_offset - progress), mydata_offset);
1878  SCLogDebug("re %" PRIu64, re);
1879  progress = mydata_offset;
1880  SCLogDebug("raw progress now %"PRIu64, progress);
1881 
1882  /* data is beyond the progress we'd like, and also beyond the last ack:
1883  * there is a gap and we can't expect it to get filled anymore. */
1884  } else if (mydata_offset > progress && mydata_offset == re) {
1885  SCLogDebug("mydata_offset %" PRIu64 ", progress %" PRIu64 ", re %" PRIu64,
1886  mydata_offset, progress, re);
1887  progress = re;
1888  } else {
1889  SCLogDebug("not increasing progress, data gap => mydata_offset "
1890  "%"PRIu64" != progress %"PRIu64, mydata_offset, progress);
1891  }
1892 
1893  if (iter == NULL || r == 1)
1894  break;
1895  }
1896 end:
1897  *progress_out = progress;
1898  return r;
1899 }
1900 
1902  void *cb_data, const uint64_t offset, const bool eof)
1903 {
1904  /* take app progress as the right edge of used data. */
1905  const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
1906  SCLogDebug("app_progress %" PRIu64, app_progress);
1907 
1908  uint64_t unused = 0;
1909  return StreamReassembleRawDo(
1910  ssn, stream, Callback, cb_data, offset, app_progress, &unused, eof);
1911 }
1912 
1914  StreamReassembleRawFunc Callback, void *cb_data,
1915  uint64_t *progress_out, bool respect_inspect_depth)
1916 {
1917  /* handle inline separately as the logic is very different */
1918  if (StreamTcpInlineMode()) {
1919  return StreamReassembleRawInline(ssn, p, Callback, cb_data, progress_out);
1920  }
1921 
1922  TcpStream *stream;
1923  if (PKT_IS_TOSERVER(p)) {
1924  stream = &ssn->client;
1925  } else {
1926  stream = &ssn->server;
1927  }
1928 
1930  StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 0)
1931  {
1932  *progress_out = STREAM_RAW_PROGRESS(stream);
1933  return 0;
1934  }
1935 
1936  uint64_t progress = STREAM_RAW_PROGRESS(stream);
1937  /* if the app layer triggered a flush, and we're supposed to
1938  * use a minimal inspect depth, we actually take the app progress
1939  * as that is the right edge of the data. Then we take the window
1940  * of 'min_inspect_depth' before that. */
1941 
1942  SCLogDebug("respect_inspect_depth %s STREAMTCP_STREAM_FLAG_TRIGGER_RAW %s "
1943  "stream->min_inspect_depth %u",
1944  respect_inspect_depth ? "true" : "false",
1945  (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) ? "true" : "false",
1946  stream->min_inspect_depth);
1947 
1948  if (respect_inspect_depth && (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) &&
1949  stream->min_inspect_depth) {
1950  progress = STREAM_APP_PROGRESS(stream);
1951  if (stream->min_inspect_depth >= progress) {
1952  progress = 0;
1953  } else {
1954  progress -= stream->min_inspect_depth;
1955  }
1956 
1957  SCLogDebug("stream app %" PRIu64 ", raw %" PRIu64, STREAM_APP_PROGRESS(stream),
1958  STREAM_RAW_PROGRESS(stream));
1959 
1960  progress = MIN(progress, STREAM_RAW_PROGRESS(stream));
1961  SCLogDebug("applied min inspect depth due to STREAMTCP_STREAM_FLAG_TRIGGER_RAW: progress "
1962  "%" PRIu64,
1963  progress);
1964  }
1965 
1966  SCLogDebug("progress %" PRIu64 ", min inspect depth %u %s", progress, stream->min_inspect_depth,
1967  stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW ? "STREAMTCP_STREAM_FLAG_TRIGGER_RAW"
1968  : "(no trigger)");
1969 
1970  /* absolute right edge of ack'd data */
1971  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1972  SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs);
1973 
1974  return StreamReassembleRawDo(ssn, stream, Callback, cb_data, progress, last_ack_abs,
1975  progress_out, (p->flags & PKT_PSEUDO_STREAM_END));
1976 }
1977 
1978 int StreamReassembleLog(const TcpSession *ssn, const TcpStream *stream,
1979  StreamReassembleRawFunc Callback, void *cb_data, const uint64_t progress_in,
1980  uint64_t *progress_out, const bool eof)
1981 {
1982  if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY))
1983  return 0;
1984 
1985  /* absolute right edge of ack'd data */
1986  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1987  SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs);
1988 
1989  return StreamReassembleRawDo(
1990  ssn, stream, Callback, cb_data, progress_in, last_ack_abs, progress_out, eof);
1991 }
1992 
1993 /** \internal
1994  * \brief update app layer based on received ACK
1995  *
1996  * \retval r 0 on success, -1 on error
1997  */
1998 static int StreamTcpReassembleHandleSegmentUpdateACK (ThreadVars *tv,
1999  TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p)
2000 {
2001  SCEnter();
2002 
2003  if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, UPDATE_DIR_OPPOSING) < 0)
2004  SCReturnInt(-1);
2005 
2006  SCReturnInt(0);
2007 }
2008 
2010  TcpSession *ssn, TcpStream *stream, Packet *p)
2011 {
2012  SCEnter();
2013 
2014  DEBUG_VALIDATE_BUG_ON(!PacketIsTCP(p));
2015  const TCPHdr *tcph = PacketGetTCP(p);
2016 
2017  SCLogDebug("ssn %p, stream %p, p %p, p->payload_len %"PRIu16"",
2018  ssn, stream, p, p->payload_len);
2019 
2020  /* default IDS: update opposing side (triggered by ACK) */
2022  /* inline and stream end and flow timeout packets trigger same dir handling */
2023  if (StreamTcpInlineMode()) {
2024  dir = UPDATE_DIR_PACKET;
2025  } else if (p->flags & PKT_PSEUDO_STREAM_END) {
2026  dir = UPDATE_DIR_PACKET;
2027  } else if (tcph->th_flags & TH_RST) { // accepted rst
2028  dir = UPDATE_DIR_PACKET;
2029  } else if ((tcph->th_flags & TH_FIN) && ssn->state > TCP_TIME_WAIT) {
2030  if (tcph->th_flags & TH_ACK) {
2031  dir = UPDATE_DIR_BOTH;
2032  } else {
2033  dir = UPDATE_DIR_PACKET;
2034  }
2035  } else if (ssn->state == TCP_CLOSED) {
2036  dir = UPDATE_DIR_BOTH;
2037  } else if ((ssn->flags & STREAMTCP_FLAG_ASYNC) != 0) {
2038  dir = UPDATE_DIR_PACKET;
2039  SCLogDebug("%" PRIu64 ": ASYNC: UPDATE_DIR_PACKET", PcapPacketCntGet(p));
2040  }
2041 
2042  /* handle ack received */
2043  if ((dir == UPDATE_DIR_OPPOSING || dir == UPDATE_DIR_BOTH)) {
2044  /* we need to update the opposing stream in
2045  * StreamTcpReassembleHandleSegmentUpdateACK */
2046  TcpStream *opposing_stream = NULL;
2047  if (stream == &ssn->client) {
2048  opposing_stream = &ssn->server;
2049  } else {
2050  opposing_stream = &ssn->client;
2051  }
2052 
2053  const bool reversed_before_ack_handling = (p->flow->flags & FLOW_DIR_REVERSED) != 0;
2054 
2055  if (StreamTcpReassembleHandleSegmentUpdateACK(tv, ra_ctx, ssn, opposing_stream, p) != 0) {
2056  SCLogDebug("StreamTcpReassembleHandleSegmentUpdateACK error");
2057  SCReturnInt(-1);
2058  }
2059 
2060  /* StreamTcpReassembleHandleSegmentUpdateACK
2061  * may swap content of ssn->server and ssn->client structures.
2062  * We have to continue with initial content of the stream in such case */
2063  const bool reversed_after_ack_handling = (p->flow->flags & FLOW_DIR_REVERSED) != 0;
2064  if (reversed_before_ack_handling != reversed_after_ack_handling) {
2065  SCLogDebug("TCP streams were swapped");
2066  stream = opposing_stream;
2067  }
2068  }
2069  /* if this segment contains data, insert it */
2070  if (p->payload_len > 0 && !(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) &&
2071  (tcph->th_flags & TH_RST) == 0) {
2072  SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData");
2073 
2074  if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) {
2075  SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error");
2076  /* failure can only be because of memcap hit, so see if this should lead to a drop */
2079  StreamTcpReassembleExceptionPolicyStatsIncr(
2081  SCReturnInt(-1);
2082  }
2083 
2084  SCLogDebug("packet %" PRIu64 " set PKT_STREAM_ADD", PcapPacketCntGet(p));
2085  p->flags |= PKT_STREAM_ADD;
2086  } else {
2087  SCLogDebug("ssn %p / stream %p: not calling StreamTcpReassembleHandleSegmentHandleData:"
2088  " p->payload_len %u, STREAMTCP_STREAM_FLAG_NOREASSEMBLY %s",
2089  ssn, stream, p->payload_len,
2090  (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ? "true" : "false");
2091  }
2092 
2093  /* if the STREAMTCP_STREAM_FLAG_DEPTH_REACHED is set, but not the
2094  * STREAMTCP_STREAM_FLAG_NOREASSEMBLY flag, it means the DEPTH flag
2095  * was *just* set. In this case we trigger the AppLayer Truncate
2096  * logic, to inform the applayer no more data in this direction is
2097  * to be expected. */
2098  if ((stream->flags &
2101  {
2102  SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED, truncate applayer");
2103  if (dir != UPDATE_DIR_PACKET) {
2104  SCLogDebug("override: direction now UPDATE_DIR_PACKET so we "
2105  "can trigger Truncate");
2106  dir = UPDATE_DIR_PACKET;
2107  }
2108  }
2109 
2110  /* in stream inline mode even if we have no data we call the reassembly
2111  * functions to handle EOF */
2112  if (dir == UPDATE_DIR_PACKET || dir == UPDATE_DIR_BOTH) {
2113  SCLogDebug("inline (%s) or PKT_PSEUDO_STREAM_END (%s)",
2114  StreamTcpInlineMode()?"true":"false",
2115  (p->flags & PKT_PSEUDO_STREAM_END) ?"true":"false");
2116  if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, dir) < 0) {
2117  SCReturnInt(-1);
2118  }
2119  }
2120 
2121  SCReturnInt(0);
2122 }
2123 
2124 /**
2125  * \brief get a segment from the pool
2126  *
2127  * \retval seg Segment from the pool or NULL
2128  */
2130 {
2132  if (seg) {
2134  return seg;
2135  }
2136 
2137  seg = (TcpSegment *)PoolThreadGetById(
2138  segment_thread_pool, (uint16_t)ra_ctx->segment_thread_pool_id);
2139  SCLogDebug("seg we return is %p", seg);
2140  if (seg == NULL) {
2141  /* Increment the counter to show that we are not able to serve the
2142  segment request due to memcap limit */
2144  } else {
2145  memset(&seg->sbseg, 0, sizeof(seg->sbseg));
2147  }
2148 
2149  return seg;
2150 }
2151 
2152 /**
2153  * \brief Trigger RAW stream inspection
2154  *
2155  * Used by AppLayerTriggerRawStreamInspection to trigger RAW stream
2156  * inspection from the applayer, for example upon completion of a
2157  * HTTP request.
2158  *
2159  * It sets a flag in the stream so that the next Raw call will return
2160  * the data.
2161  *
2162  * \param ssn TcpSession
2163  */
2165 {
2166 #ifdef DEBUG
2167  BUG_ON(ssn == NULL);
2168 #endif
2169 
2170  if (ssn != NULL) {
2171  if (direction == STREAM_TOSERVER) {
2173  } else {
2175  }
2176 
2177  SCLogDebug("flagged ssn %p for immediate raw reassembly", ssn);
2178  }
2179 }
2180 
2181 void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
2182 {
2183 #ifdef DEBUG
2184  BUG_ON(ssn == NULL);
2185 #endif
2186 
2187  if (ssn != NULL) {
2188  if (direction == STREAM_TOSERVER) {
2189  ssn->client.min_inspect_depth = depth;
2190  SCLogDebug("ssn %p: set client.min_inspect_depth to %u", ssn, depth);
2191  } else {
2192  ssn->server.min_inspect_depth = depth;
2193  SCLogDebug("ssn %p: set server.min_inspect_depth to %u", ssn, depth);
2194  }
2195  }
2196 }
2197 
2198 #ifdef UNITTESTS
2199 /** unit tests and it's support functions below */
2200 
2201 #define SET_ISN(stream, setseq) \
2202  (stream)->isn = (setseq); \
2203  (stream)->base_seq = (setseq) + 1
2204 
2205 /** \brief The Function to create the packet with given payload, which is used
2206  * to test the reassembly of the engine.
2207  *
2208  * \param payload The variable used to store the payload contents of the
2209  * current packet.
2210  * \param value The value which current payload will have for this packet
2211  * \param payload_len The length of the filed payload for current packet.
2212  * \param len Length of the payload array
2213  */
2214 
2215 void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value,
2216  uint8_t payload_len, uint8_t len)
2217 {
2218  uint8_t i;
2219  for (i = 0; i < payload_len; i++)
2220  payload[i] = value;
2221  for (; i < len; i++)
2222  payload = NULL;
2223 }
2224 
2225 /** \brief The Function Checks the reassembled stream contents against predefined
2226  * stream contents according to OS policy used.
2227  *
2228  * \param stream_policy Predefined value of stream for different OS policies
2229  * \param stream Reassembled stream returned from the reassembly functions
2230  */
2231 
2232 static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len)
2233 {
2234  if (StreamingBufferCompareRawData(&stream->sb,
2235  data, data_len) == 0)
2236  {
2237  SCReturnInt(0);
2238  }
2239  SCLogInfo("OK");
2240  PrintRawDataFp(stdout, data, data_len);
2241  return 1;
2242 }
2243 
2244 #define MISSED_START(isn) \
2245  TcpReassemblyThreadCtx *ra_ctx = NULL; \
2246  TcpSession ssn; \
2247  ThreadVars tv; \
2248  memset(&tv, 0, sizeof(tv)); \
2249  \
2250  StreamTcpUTInit(&ra_ctx); \
2251  \
2252  StreamTcpUTSetupSession(&ssn); \
2253  StreamTcpUTSetupStream(&ssn.server, (isn)); \
2254  StreamTcpUTSetupStream(&ssn.client, (isn)); \
2255  \
2256  TcpStream *stream = &ssn.client;
2257 
2258 #define MISSED_END \
2259  StreamTcpUTClearSession(&ssn); \
2260  StreamTcpUTDeinit(ra_ctx); \
2261  PASS
2262 
2263 #define MISSED_STEP(seq, seg, seglen, buf, buflen) \
2264  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen)); \
2265  FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen))));
2266 
2267 #define MISSED_ADD_PAYLOAD(seq, seg, seglen) \
2268  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen));
2269 
2270 int UTHCheckGapAtPosition(TcpStream *stream, int pos, uint64_t offset, uint32_t len);
2271 
2272 int UTHCheckGapAtPosition(TcpStream *stream, int pos, uint64_t offset, uint32_t len)
2273 {
2274  int cnt = 0;
2275  uint64_t last_re = 0;
2276  StreamingBufferBlock *sbb = NULL;
2277  RB_FOREACH(sbb, SBB, &stream->sb.sbb_tree)
2278  {
2279  if (sbb->offset != last_re) {
2280  // gap before us
2281  if (cnt == pos && last_re == offset && len == sbb->offset - last_re) {
2282  return 1;
2283  }
2284  cnt++;
2285  }
2286  last_re = sbb->offset + sbb->len;
2287  cnt++;
2288  }
2289  return 0;
2290 }
2291 
2293  TcpStream *stream, int pos, uint64_t offset, const char *data, uint32_t len);
2294 
2296  TcpStream *stream, int pos, uint64_t offset, const char *data, uint32_t len)
2297 {
2298  int cnt = 0;
2299  uint64_t last_re = 0;
2300  StreamingBufferBlock *sbb = NULL;
2301  RB_FOREACH(sbb, SBB, &stream->sb.sbb_tree)
2302  {
2303  if (sbb->offset != last_re) {
2304  // gap before us
2305  cnt++;
2306  }
2307 
2308  if (cnt == pos && sbb->offset == offset) {
2309  const uint8_t *buf = NULL;
2310  uint32_t buf_len = 0;
2311  StreamingBufferSBBGetData(&stream->sb, sbb, &buf, &buf_len);
2312 
2313  if (len == buf_len) {
2314  return (memcmp(data, buf, len) == 0);
2315  }
2316  }
2317 
2318  last_re = sbb->offset + sbb->len;
2319  cnt++;
2320  }
2321  return 0;
2322 }
2323 
2324 /**
2325  * \test Test the handling of packets missed by both IDS and the end host.
2326  * The packet is missed in the starting of the stream.
2327  *
2328  * \retval On success it returns 1 and on failure 0.
2329  */
2330 
2331 static int StreamTcpReassembleTest25 (void)
2332 {
2333  MISSED_START(6);
2334  MISSED_ADD_PAYLOAD(10, "BB", 2);
2335  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2336  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "BB", 2) == 1);
2337  MISSED_ADD_PAYLOAD(12, "CC", 2);
2338  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2339  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "BBCC", 4) == 1);
2340  MISSED_STEP(7, "AAA", 3, "AAABBCC", 7);
2341  MISSED_END;
2342  PASS;
2343 }
2344 
2345 /**
2346  * \test Test the handling of packets missed by both IDS and the end host.
2347  * The packet is missed in the middle of the stream.
2348  *
2349  * \retval On success it returns 1 and on failure 0.
2350  */
2351 
2352 static int StreamTcpReassembleTest26 (void)
2353 {
2354  MISSED_START(9);
2355  MISSED_STEP(10, "AAA", 3, "AAA", 3);
2356  MISSED_ADD_PAYLOAD(15, "CC", 2);
2357  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 0, 0, "AAA", 3) == 1);
2358  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 1, 3, 2) == 1);
2359  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 2, 5, "CC", 2) == 1);
2360  MISSED_STEP(13, "BB", 2, "AAABBCC", 7);
2361  MISSED_END;
2362 }
2363 
2364 /**
2365  * \test Test the handling of packets missed by both IDS and the end host.
2366  * The packet is missed in the end of the stream.
2367  *
2368  * \retval On success it returns 1 and on failure 0.
2369  */
2370 
2371 static int StreamTcpReassembleTest27 (void)
2372 {
2373  MISSED_START(9);
2374  MISSED_STEP(10, "AAA", 3, "AAA", 3);
2375  MISSED_STEP(13, "BB", 2, "AAABB", 5);
2376  MISSED_STEP(15, "CC", 2, "AAABBCC", 7);
2377  MISSED_END;
2378 }
2379 
2380 /**
2381  * \test Test the handling of packets missed by IDS, but the end host has
2382  * received it and send the acknowledgment of it. The packet is missed
2383  * in the starting of the stream.
2384  *
2385  * \retval On success it returns 1 and on failure 0.
2386  */
2387 
2388 static int StreamTcpReassembleTest28 (void)
2389 {
2390  MISSED_START(6);
2391  MISSED_ADD_PAYLOAD(10, "AAA", 3);
2392  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2393  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAA", 3) == 1);
2394  MISSED_ADD_PAYLOAD(13, "BB", 2);
2395  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2396  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAABB", 5) == 1);
2398  MISSED_ADD_PAYLOAD(15, "CC", 2);
2399  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2400  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAABBCC", 7) == 1);
2401  MISSED_END;
2402 }
2403 
2404 /**
2405  * \test Test the handling of packets missed by IDS, but the end host has
2406  * received it and send the acknowledgment of it. The packet is missed
2407  * in the middle of the stream.
2408  *
2409  * \retval On success it returns 1 and on failure 0.
2410  */
2411 
2412 static int StreamTcpReassembleTest29 (void)
2413 {
2414  MISSED_START(9);
2415  MISSED_STEP(10, "AAA", 3, "AAA", 3);
2417  MISSED_ADD_PAYLOAD(15, "CC", 2);
2418  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 0, 0, "AAA", 3) == 1);
2419  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 1, 3, 2) == 1);
2420  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 2, 5, "CC", 2) == 1);
2421  MISSED_END;
2422 }
2423 
2424 static int StreamTcpReassembleTest33(void)
2425 {
2426  TcpSession ssn;
2428  FAIL_IF(unlikely(p == NULL));
2429  Flow f;
2430  TCPHdr tcph;
2431  TcpReassemblyThreadCtx *ra_ctx = NULL;
2433  uint8_t packet[1460] = "";
2434 
2435  StreamTcpUTInit(&ra_ctx);
2437 
2438  memset(&f, 0, sizeof (Flow));
2439  memset(&tcph, 0, sizeof (TCPHdr));
2440  ThreadVars tv;
2441  memset(&tv, 0, sizeof (ThreadVars));
2442  FLOW_INITIALIZE(&f);
2443  f.protoctx = &ssn;
2444  f.proto = IPPROTO_TCP;
2445  p->src.family = AF_INET;
2446  p->dst.family = AF_INET;
2447  p->proto = IPPROTO_TCP;
2448  p->flow = &f;
2449  tcph.th_win = 5480;
2450  tcph.th_flags = TH_PUSH | TH_ACK;
2451  UTHSetTCPHdr(p, &tcph);
2453  p->payload = packet;
2454 
2455  tcph.th_seq = htonl(10);
2456  tcph.th_ack = htonl(31);
2457  p->payload_len = 10;
2458 
2459  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2460 
2461  tcph.th_seq = htonl(20);
2462  tcph.th_ack = htonl(31);
2463  p->payload_len = 10;
2464 
2465  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2466 
2467  tcph.th_seq = htonl(40);
2468  tcph.th_ack = htonl(31);
2469  p->payload_len = 10;
2470 
2471  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2472 
2473  tcph.th_seq = htonl(5);
2474  tcph.th_ack = htonl(31);
2475  p->payload_len = 30;
2476 
2477  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2478 
2480  FLOW_DESTROY(&f);
2481  PacketFree(p);
2482  StreamTcpUTDeinit(ra_ctx);
2483  PASS;
2484 }
2485 
2486 static int StreamTcpReassembleTest34(void)
2487 {
2488  TcpSession ssn;
2490  FAIL_IF(unlikely(p == NULL));
2491  Flow f;
2492  TCPHdr tcph;
2493  TcpReassemblyThreadCtx *ra_ctx = NULL;
2495  uint8_t packet[1460] = "";
2496 
2497  StreamTcpUTInit(&ra_ctx);
2499  memset(&f, 0, sizeof (Flow));
2500  memset(&tcph, 0, sizeof (TCPHdr));
2501  ThreadVars tv;
2502  memset(&tv, 0, sizeof (ThreadVars));
2503  FLOW_INITIALIZE(&f);
2504  f.protoctx = &ssn;
2505  f.proto = IPPROTO_TCP;
2506  p->src.family = AF_INET;
2507  p->dst.family = AF_INET;
2508  p->proto = IPPROTO_TCP;
2509  p->flow = &f;
2510  tcph.th_win = 5480;
2511  tcph.th_flags = TH_PUSH | TH_ACK;
2512  UTHSetTCPHdr(p, &tcph);
2514  p->payload = packet;
2515  SET_ISN(&ssn.client, 857961230);
2516 
2517  tcph.th_seq = htonl(857961230);
2518  tcph.th_ack = htonl(31);
2519  p->payload_len = 304;
2520 
2521  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2522 
2523  tcph.th_seq = htonl(857961534);
2524  tcph.th_ack = htonl(31);
2525  p->payload_len = 1460;
2526 
2527  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2528 
2529  tcph.th_seq = htonl(857963582);
2530  tcph.th_ack = htonl(31);
2531  p->payload_len = 1460;
2532 
2533  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2534 
2535  tcph.th_seq = htonl(857960946);
2536  tcph.th_ack = htonl(31);
2537  p->payload_len = 1460;
2538 
2539  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2540 
2542  FLOW_DESTROY(&f);
2543  StreamTcpUTDeinit(ra_ctx);
2544  PacketFree(p);
2545  PASS;
2546 }
2547 
2548 /**
2549  * \test Test to make sure that we don't return the segments until the app
2550  * layer proto has been detected and after that remove the processed
2551  * segments.
2552  *
2553  * \retval On success it returns 1 and on failure 0.
2554  */
2555 
2556 static int StreamTcpReassembleTest39 (void)
2557 {
2559  FAIL_IF(unlikely(p == NULL));
2560  Flow f;
2561  ThreadVars tv;
2562  StreamTcpThread stt;
2563  TCPHdr tcph;
2564  PacketQueueNoLock pq;
2565  memset(&pq,0,sizeof(PacketQueueNoLock));
2566  memset (&f, 0, sizeof(Flow));
2567  memset(&tv, 0, sizeof (ThreadVars));
2568  memset(&stt, 0, sizeof (stt));
2569  memset(&tcph, 0, sizeof (TCPHdr));
2570 
2571  FLOW_INITIALIZE(&f);
2572  f.flags = FLOW_IPV4;
2573  f.proto = IPPROTO_TCP;
2574  p->flow = &f;
2575  UTHSetTCPHdr(p, &tcph);
2576 
2577  StreamTcpUTInit(&stt.ra_ctx);
2578 
2579  /* handshake */
2580  tcph.th_win = htons(5480);
2581  tcph.th_flags = TH_SYN;
2583  p->payload_len = 0;
2584  p->payload = NULL;
2585  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2586 
2588  FAIL_IF_NULL(ssn);
2589 
2596  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2597  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2598  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2599  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2603 
2604  /* handshake */
2605  tcph.th_ack = htonl(1);
2606  tcph.th_flags = TH_SYN | TH_ACK;
2608  p->payload_len = 0;
2609  p->payload = NULL;
2610  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2617  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2618  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2619  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2620  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2624 
2625  /* handshake */
2626  tcph.th_ack = htonl(1);
2627  tcph.th_seq = htonl(1);
2628  tcph.th_flags = TH_ACK;
2630  p->payload_len = 0;
2631  p->payload = NULL;
2632  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2639  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2640  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2641  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2642  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2646 
2647  /* partial request */
2648  uint8_t request1[] = { 0x47, 0x45, };
2649  tcph.th_ack = htonl(1);
2650  tcph.th_seq = htonl(1);
2651  tcph.th_flags = TH_PUSH | TH_ACK;
2653  p->payload_len = sizeof(request1);
2654  p->payload = request1;
2655  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2662  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2663  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2664  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2665  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2667  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2669  FAIL_IF_NOT(ssn->data_first_seen_dir == STREAM_TOSERVER);
2670 
2671  /* response ack against partial request */
2672  tcph.th_ack = htonl(3);
2673  tcph.th_seq = htonl(1);
2674  tcph.th_flags = TH_ACK;
2676  p->payload_len = 0;
2677  p->payload = NULL;
2678  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2685  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2686  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2687  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2688  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2690  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2692  FAIL_IF_NOT(ssn->data_first_seen_dir == STREAM_TOSERVER);
2693 
2694  /* complete partial request */
2695  uint8_t request2[] = {
2696  0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64,
2697  0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20,
2698  0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30,
2699  0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20,
2700  0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73,
2701  0x74, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d,
2702  0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x41,
2703  0x70, 0x61, 0x63, 0x68, 0x65, 0x42, 0x65, 0x6e,
2704  0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a,
2705  0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20,
2706  0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a };
2707  tcph.th_ack = htonl(1);
2708  tcph.th_seq = htonl(3);
2709  tcph.th_flags = TH_PUSH | TH_ACK;
2711  p->payload_len = sizeof(request2);
2712  p->payload = request2;
2713  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2720  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2721  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2722  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2723  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2725  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2726  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2728  FAIL_IF_NOT(ssn->data_first_seen_dir == STREAM_TOSERVER);
2729 
2730  /* response - request ack */
2731  uint8_t response[] = {
2732  0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31,
2733  0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d,
2734  0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x46,
2735  0x72, 0x69, 0x2c, 0x20, 0x32, 0x33, 0x20, 0x53,
2736  0x65, 0x70, 0x20, 0x32, 0x30, 0x31, 0x31, 0x20,
2737  0x30, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x39,
2738  0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65,
2739  0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x41, 0x70,
2740  0x61, 0x63, 0x68, 0x65, 0x2f, 0x32, 0x2e, 0x32,
2741  0x2e, 0x31, 0x35, 0x20, 0x28, 0x55, 0x6e, 0x69,
2742  0x78, 0x29, 0x20, 0x44, 0x41, 0x56, 0x2f, 0x32,
2743  0x0d, 0x0a, 0x4c, 0x61, 0x73, 0x74, 0x2d, 0x4d,
2744  0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x3a,
2745  0x20, 0x54, 0x68, 0x75, 0x2c, 0x20, 0x30, 0x34,
2746  0x20, 0x4e, 0x6f, 0x76, 0x20, 0x32, 0x30, 0x31,
2747  0x30, 0x20, 0x31, 0x35, 0x3a, 0x30, 0x34, 0x3a,
2748  0x34, 0x36, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a,
2749  0x45, 0x54, 0x61, 0x67, 0x3a, 0x20, 0x22, 0x61,
2750  0x62, 0x38, 0x39, 0x36, 0x35, 0x2d, 0x32, 0x63,
2751  0x2d, 0x34, 0x39, 0x34, 0x33, 0x62, 0x37, 0x61,
2752  0x37, 0x66, 0x37, 0x66, 0x38, 0x30, 0x22, 0x0d,
2753  0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d,
2754  0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x3a, 0x20,
2755  0x62, 0x79, 0x74, 0x65, 0x73, 0x0d, 0x0a, 0x43,
2756  0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c,
2757  0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x34,
2758  0x34, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
2759  0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63,
2760  0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, 0x43, 0x6f,
2761  0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79,
2762  0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74,
2763  0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x58,
2764  0x2d, 0x50, 0x61, 0x64, 0x3a, 0x20, 0x61, 0x76,
2765  0x6f, 0x69, 0x64, 0x20, 0x62, 0x72, 0x6f, 0x77,
2766  0x73, 0x65, 0x72, 0x20, 0x62, 0x75, 0x67, 0x0d,
2767  0x0a, 0x0d, 0x0a, 0x3c, 0x68, 0x74, 0x6d, 0x6c,
2768  0x3e, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c,
2769  0x68, 0x31, 0x3e, 0x49, 0x74, 0x20, 0x77, 0x6f,
2770  0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31,
2771  0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e,
2772  0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e };
2773  tcph.th_ack = htonl(88);
2774  tcph.th_seq = htonl(1);
2775  tcph.th_flags = TH_PUSH | TH_ACK;
2777  p->payload_len = sizeof(response);
2778  p->payload = response;
2779 
2780  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2787  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2788  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2789  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2790  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2794  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2795  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2796 
2797  /* response ack from request */
2798  tcph.th_ack = htonl(328);
2799  tcph.th_seq = htonl(88);
2800  tcph.th_flags = TH_ACK;
2802  p->payload_len = 0;
2803  p->payload = NULL;
2804  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2811  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2812  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2813  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2814  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2818  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2819  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2820  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2821 
2822  /* response - acking */
2823  tcph.th_ack = htonl(88);
2824  tcph.th_seq = htonl(328);
2825  tcph.th_flags = TH_PUSH | TH_ACK;
2827  p->payload_len = 0;
2828  p->payload = NULL;
2829  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2836  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2837  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2838  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2839  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2843  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2844  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2845  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2846 
2847  /* response ack from request */
2848  tcph.th_ack = htonl(328);
2849  tcph.th_seq = htonl(88);
2850  tcph.th_flags = TH_ACK;
2852  p->payload_len = 0;
2853  p->payload = NULL;
2854  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2861  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2862  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2863  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2864  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2867  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2869  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2870 
2871  /* response - acking the request again*/
2872  tcph.th_ack = htonl(88);
2873  tcph.th_seq = htonl(328);
2874  tcph.th_flags = TH_PUSH | TH_ACK;
2876  p->payload_len = 0;
2877  p->payload = NULL;
2878  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2885  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2886  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2887  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2888  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2891  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2893  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2894 
2895  /*** New Request ***/
2896 
2897  /* partial request */
2898  tcph.th_ack = htonl(328);
2899  tcph.th_seq = htonl(88);
2900  tcph.th_flags = TH_PUSH | TH_ACK;
2902  p->payload_len = sizeof(request1);
2903  p->payload = request1;
2904  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2911  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2912  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2913  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2914  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2917  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2918  FAIL_IF_NOT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2920  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2921 
2922  /* response ack against partial request */
2923  tcph.th_ack = htonl(90);
2924  tcph.th_seq = htonl(328);
2925  tcph.th_flags = TH_ACK;
2927  p->payload_len = 0;
2928  p->payload = NULL;
2929  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2930  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2937  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2938  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2939  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2940  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2943  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2944  FAIL_IF_NOT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2946  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2947 
2948  /* complete request */
2949  tcph.th_ack = htonl(328);
2950  tcph.th_seq = htonl(90);
2951  tcph.th_flags = TH_PUSH | TH_ACK;
2953  p->payload_len = sizeof(request2);
2954  p->payload = request2;
2955  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2962  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2963  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2964  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2965  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2968  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2969  FAIL_IF_NOT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2970  FAIL_IF_NOT(
2971  TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
2973  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2974 
2975  /* response ack against second partial request */
2976  tcph.th_ack = htonl(175);
2977  tcph.th_seq = htonl(328);
2978  tcph.th_flags = TH_ACK;
2980  p->payload_len = 0;
2981  p->payload = NULL;
2982 
2983  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2990  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2991  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2992  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2993  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2996  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2997  FAIL_IF_NOT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2998  FAIL_IF_NOT(
2999  TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
3001  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
3002 
3003  /* response acking a request */
3004  tcph.th_ack = htonl(175);
3005  tcph.th_seq = htonl(328);
3006  tcph.th_flags = TH_ACK;
3008  p->payload_len = 0;
3009  p->payload = NULL;
3010  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
3016 
3017  StreamTcpPruneSession(&f, STREAM_TOSERVER);
3018  StreamTcpPruneSession(&f, STREAM_TOCLIENT);
3019 
3020  /* request acking a response */
3021  tcph.th_ack = htonl(328);
3022  tcph.th_seq = htonl(175);
3023  tcph.th_flags = TH_ACK;
3025  p->payload_len = 0;
3026  p->payload = NULL;
3027  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
3028 
3029  PacketFree(p);
3031  FLOW_DESTROY(&f);
3033  PASS;
3034 }
3035 
3036 /**
3037  * \test Test to make sure that we sent all the segments from the initial
3038  * segments to app layer until we have detected the app layer proto.
3039  *
3040  * \retval On success it returns 1 and on failure 0.
3041  */
3042 
3043 static int StreamTcpReassembleTest40 (void)
3044 {
3046  FAIL_IF_NULL(p);
3047  Flow *f = NULL;
3048  TCPHdr tcph;
3049  TcpSession ssn;
3050  memset(&tcph, 0, sizeof (TCPHdr));
3051  ThreadVars tv;
3052  memset(&tv, 0, sizeof (ThreadVars));
3053 
3054  StreamTcpInitConfig(true);
3056 
3058  FAIL_IF_NULL(ra_ctx);
3059 
3060  uint8_t httpbuf1[] = "P";
3061  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3062  uint8_t httpbuf3[] = "O";
3063  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
3064  uint8_t httpbuf4[] = "S";
3065  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
3066  uint8_t httpbuf5[] = "T \r\n";
3067  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
3068 
3069  uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
3070  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3071 
3072  SET_ISN(&ssn.server, 9);
3073  ssn.server.last_ack = 10;
3074  SET_ISN(&ssn.client, 9);
3075  ssn.client.isn = 9;
3076 
3077  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
3078  FAIL_IF_NULL(f);
3079  f->protoctx = &ssn;
3080  f->proto = IPPROTO_TCP;
3081  p->flow = f;
3082 
3083  tcph.th_win = htons(5480);
3084  tcph.th_seq = htonl(10);
3085  tcph.th_ack = htonl(10);
3086  tcph.th_flags = TH_ACK|TH_PUSH;
3087  UTHSetTCPHdr(p, &tcph);
3089  p->payload = httpbuf1;
3090  p->payload_len = httplen1;
3092  TcpStream *s = &ssn.client;
3093  SCLogDebug("1 -- start");
3094  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3095 
3097  p->payload = httpbuf2;
3098  p->payload_len = httplen2;
3099  tcph.th_seq = htonl(10);
3100  tcph.th_ack = htonl(11);
3101  s = &ssn.server;
3102  ssn.server.last_ack = 11;
3103  SCLogDebug("2 -- start");
3104  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3105 
3107  p->payload = httpbuf3;
3108  p->payload_len = httplen3;
3109  tcph.th_seq = htonl(11);
3110  tcph.th_ack = htonl(55);
3111  s = &ssn.client;
3112  ssn.client.last_ack = 55;
3113  SCLogDebug("3 -- start");
3114  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3115 
3117  p->payload = httpbuf2;
3118  p->payload_len = httplen2;
3119  tcph.th_seq = htonl(55);
3120  tcph.th_ack = htonl(12);
3121  s = &ssn.server;
3122  ssn.server.last_ack = 12;
3123  SCLogDebug("4 -- start");
3124  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3125 
3126  /* check is have the segment in the list and flagged or not */
3127  TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3128  FAIL_IF_NULL(seg);
3129  FAIL_IF(SEGMENT_BEFORE_OFFSET(&ssn.client, seg, STREAM_APP_PROGRESS(&ssn.client)));
3130 
3132  p->payload = httpbuf4;
3133  p->payload_len = httplen4;
3134  tcph.th_seq = htonl(12);
3135  tcph.th_ack = htonl(100);
3136  s = &ssn.client;
3137  ssn.client.last_ack = 100;
3138  SCLogDebug("5 -- start");
3139  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3140 
3142  p->payload = httpbuf2;
3143  p->payload_len = httplen2;
3144  tcph.th_seq = htonl(100);
3145  tcph.th_ack = htonl(13);
3146  s = &ssn.server;
3147  ssn.server.last_ack = 13;
3148  SCLogDebug("6 -- start");
3149  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3150 
3152  p->payload = httpbuf5;
3153  p->payload_len = httplen5;
3154  tcph.th_seq = htonl(13);
3155  tcph.th_ack = htonl(145);
3156  s = &ssn.client;
3157  ssn.client.last_ack = 145;
3158  SCLogDebug("7 -- start");
3159  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3160 
3162  p->payload = httpbuf2;
3163  p->payload_len = httplen2;
3164  tcph.th_seq = htonl(145);
3165  tcph.th_ack = htonl(16);
3166  s = &ssn.server;
3167  ssn.server.last_ack = 16;
3168  SCLogDebug("8 -- start");
3169  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3171 
3173  PacketFree(p);
3174  UTHFreeFlow(f);
3176  StreamTcpFreeConfig(true);
3177  PASS;
3178 }
3179 
3180 /** \test Test the memcap incrementing/decrementing and memcap check */
3181 static int StreamTcpReassembleTest44(void)
3182 {
3183  StreamTcpInitConfig(true);
3184  uint32_t memuse = SC_ATOMIC_GET(ra_memuse);
3185  StreamTcpReassembleIncrMemuse(500);
3186  FAIL_IF_NOT(SC_ATOMIC_GET(ra_memuse) == (memuse + 500));
3187  StreamTcpReassembleDecrMemuse(500);
3188  FAIL_IF_NOT(SC_ATOMIC_GET(ra_memuse) == memuse);
3191  (1 + memuse + SC_ATOMIC_GET(stream_config.reassembly_memcap))) == 0);
3192  StreamTcpFreeConfig(true);
3193  FAIL_IF_NOT(SC_ATOMIC_GET(ra_memuse) == 0);
3194  PASS;
3195 }
3196 
3197 /**
3198  * \test Test to make sure that reassembly_depth is enforced.
3199  *
3200  * \retval On success it returns 1 and on failure 0.
3201  */
3202 
3203 static int StreamTcpReassembleTest45 (void)
3204 {
3205  TcpReassemblyThreadCtx *ra_ctx = NULL;
3206  TcpSession ssn;
3207  ThreadVars tv;
3208  memset(&tv, 0, sizeof(tv));
3209  uint8_t payload[100] = {0};
3210  uint16_t payload_size = 100;
3211 
3212  StreamTcpUTInit(&ra_ctx);
3214 
3216  ssn.reassembly_depth = 100;
3219 
3220  FAIL_IF_NOT(
3221  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size) == 0);
3223 
3224  FAIL_IF_NOT(
3225  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size) == 0);
3227 
3231  StreamTcpUTDeinit(ra_ctx);
3232  PASS;
3233 }
3234 
3235 /**
3236  * \test Test the unlimited config value of reassembly depth.
3237  *
3238  * \retval On success it returns 1 and on failure 0.
3239  */
3240 
3241 static int StreamTcpReassembleTest46 (void)
3242 {
3243  TcpReassemblyThreadCtx *ra_ctx = NULL;
3244  TcpSession ssn;
3245  ThreadVars tv;
3246  memset(&tv, 0, sizeof(tv));
3247  uint8_t payload[100] = {0};
3248  uint16_t payload_size = 100;
3249 
3250  StreamTcpUTInit(&ra_ctx);
3252 
3256 
3257  FAIL_IF_NOT(
3258  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size) == 0);
3260 
3261  FAIL_IF_NOT(
3262  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size) == 0);
3264 
3268  StreamTcpUTDeinit(ra_ctx);
3269  PASS;
3270 }
3271 
3272 /**
3273  * \test Test to make sure we detect the sequence wrap around and continue
3274  * stream reassembly properly.
3275  *
3276  * \retval On success it returns 1 and on failure 0.
3277  */
3278 
3279 static int StreamTcpReassembleTest47 (void)
3280 {
3282  FAIL_IF(unlikely(p == NULL));
3283  Flow *f = NULL;
3284  TCPHdr tcph;
3285  TcpSession ssn;
3286  ThreadVars tv;
3287  memset(&tcph, 0, sizeof (TCPHdr));
3288  UTHSetTCPHdr(p, &tcph);
3289  memset(&tv, 0, sizeof (ThreadVars));
3290  StreamTcpInitConfig(true);
3293 
3294  uint8_t httpbuf1[] = "GET /EVILSUFF HTTP/1.1\r\n\r\n";
3295  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3296 
3297  SET_ISN(&ssn.server, 572799781UL);
3298  ssn.server.last_ack = 572799782UL;
3299 
3300  SET_ISN(&ssn.client, 4294967289UL);
3301  ssn.client.last_ack = 21;
3302 
3303  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
3304  FAIL_IF_NULL(f);
3305  f->protoctx = &ssn;
3306  f->proto = IPPROTO_TCP;
3307  p->flow = f;
3308 
3309  tcph.th_win = htons(5480);
3311  TcpStream *s = NULL;
3312  uint8_t cnt = 0;
3313 
3314  for (cnt=0; cnt < httplen1; cnt++) {
3315  tcph.th_seq = htonl(ssn.client.isn + 1 + cnt);
3316  tcph.th_ack = htonl(572799782UL);
3317  tcph.th_flags = TH_ACK | TH_PUSH;
3319  p->payload = &httpbuf1[cnt];
3320  p->payload_len = 1;
3321  s = &ssn.client;
3322 
3323  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3324 
3326  p->payload = NULL;
3327  p->payload_len = 0;
3328  tcph.th_seq = htonl(572799782UL);
3329  tcph.th_ack = htonl(ssn.client.isn + 1 + cnt);
3330  tcph.th_flags = TH_ACK;
3331  s = &ssn.server;
3332 
3333  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3334  }
3335 
3337 
3339  PacketFree(p);
3340  UTHFreeFlow(f);
3342  StreamTcpFreeConfig(true);
3343  PASS;
3344 }
3345 
3346 /** \test 3 in order segments in inline reassembly */
3347 static int StreamTcpReassembleInlineTest01(void)
3348 {
3349  TcpReassemblyThreadCtx *ra_ctx = NULL;
3350  ThreadVars tv;
3351  TcpSession ssn;
3352  Flow f;
3353 
3354  memset(&tv, 0x00, sizeof(tv));
3355 
3356  StreamTcpUTInit(&ra_ctx);
3360  FLOW_INITIALIZE(&f);
3361 
3362  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3363  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3364  FAIL_IF_NULL(p);
3365  p->l4.hdrs.tcph->th_seq = htonl(12);
3366  p->flow = &f;
3367 
3368  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3369  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3370  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3371  ssn.client.next_seq = 17;
3372  FLOW_DESTROY(&f);
3373  UTHFreePacket(p);
3375  StreamTcpUTDeinit(ra_ctx);
3376  PASS;
3377 }
3378 
3379 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3380  * test the sliding window reassembly.
3381  */
3382 static int StreamTcpReassembleInlineTest02(void)
3383 {
3384  TcpReassemblyThreadCtx *ra_ctx = NULL;
3385  ThreadVars tv;
3386  TcpSession ssn;
3387  Flow f;
3388 
3389  memset(&tv, 0x00, sizeof(tv));
3390 
3391  StreamTcpUTInit(&ra_ctx);
3395  FLOW_INITIALIZE(&f);
3396 
3397  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3398  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3399  FAIL_IF_NULL(p);
3400  p->l4.hdrs.tcph->th_seq = htonl(12);
3401  p->flow = &f;
3402 
3403  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3404  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3405  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3406  ssn.client.next_seq = 17;
3407  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3408  ssn.client.next_seq = 22;
3409  FLOW_DESTROY(&f);
3410  UTHFreePacket(p);
3412  StreamTcpUTDeinit(ra_ctx);
3413  PASS;
3414 }
3415 
3416 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3417  * test the sliding window reassembly with a small window size so that we
3418  * cutting off at the start (left edge)
3419  */
3420 static int StreamTcpReassembleInlineTest03(void)
3421 {
3422  TcpReassemblyThreadCtx *ra_ctx = NULL;
3423  ThreadVars tv;
3424  TcpSession ssn;
3425  Flow f;
3426 
3427  memset(&tv, 0x00, sizeof(tv));
3428 
3429  StreamTcpUTInit(&ra_ctx);
3433  FLOW_INITIALIZE(&f);
3434 
3436 
3437  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3438  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3439  FAIL_IF_NULL(p);
3440  p->l4.hdrs.tcph->th_seq = htonl(12);
3441  p->flow = &f;
3443 
3444  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3445  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3446  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3447  ssn.client.next_seq = 17;
3448  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3449  ssn.client.next_seq = 22;
3450 
3451  p->l4.hdrs.tcph->th_seq = htonl(17);
3452  FLOW_DESTROY(&f);
3453  UTHFreePacket(p);
3455  StreamTcpUTDeinit(ra_ctx);
3456  PASS;
3457 }
3458 
3459 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3460  * test the sliding window reassembly with a small window size so that we
3461  * cutting off at the start (left edge) with small packet overlap.
3462  */
3463 static int StreamTcpReassembleInlineTest04(void)
3464 {
3465  TcpReassemblyThreadCtx *ra_ctx = NULL;
3466  ThreadVars tv;
3467  TcpSession ssn;
3468  Flow f;
3469 
3470  memset(&tv, 0x00, sizeof(tv));
3471 
3472  StreamTcpUTInit(&ra_ctx);
3476  FLOW_INITIALIZE(&f);
3477 
3479 
3480  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3481  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3482  FAIL_IF_NULL(p);
3483  p->l4.hdrs.tcph->th_seq = htonl(12);
3484  p->flow = &f;
3486 
3487  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3488  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3489  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3490  ssn.client.next_seq = 17;
3491  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3492  ssn.client.next_seq = 22;
3493 
3494  p->l4.hdrs.tcph->th_seq = htonl(17);
3495  FLOW_DESTROY(&f);
3496  UTHFreePacket(p);
3498  StreamTcpUTDeinit(ra_ctx);
3499  PASS;
3500 }
3501 
3502 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3503  * test the sliding window reassembly with a small window size so that we
3504  * cutting off at the start (left edge). Test if the first segment is
3505  * removed from the list.
3506  */
3507 static int StreamTcpReassembleInlineTest08(void)
3508 {
3509  TcpReassemblyThreadCtx *ra_ctx = NULL;
3510  ThreadVars tv;
3511  memset(&tv, 0x00, sizeof(tv));
3512  TcpSession ssn;
3513  Flow f;
3514  StreamTcpUTInit(&ra_ctx);
3518  FLOW_INITIALIZE(&f);
3519 
3521  f.protoctx = &ssn;
3522 
3523  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3524  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3525  FAIL_IF_NULL(p);
3526  p->l4.hdrs.tcph->th_seq = htonl(12);
3527  p->flow = &f;
3529 
3530  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3531  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3532  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3533  ssn.client.next_seq = 17;
3534  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3535  ssn.client.next_seq = 22;
3536  p->l4.hdrs.tcph->th_seq = htonl(17);
3537  StreamTcpPruneSession(&f, STREAM_TOSERVER);
3538 
3539  TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3540  FAIL_IF_NULL(seg);
3541  FAIL_IF_NOT(seg->seq == 2);
3542 
3543  FLOW_DESTROY(&f);
3544  UTHFreePacket(p);
3546  StreamTcpUTDeinit(ra_ctx);
3547  PASS;
3548 }
3549 
3550 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3551  * test the sliding window reassembly with a small window size so that we
3552  * cutting off at the start (left edge). Test if the first segment is
3553  * removed from the list.
3554  */
3555 static int StreamTcpReassembleInlineTest09(void)
3556 {
3557  TcpReassemblyThreadCtx *ra_ctx = NULL;
3558  ThreadVars tv;
3559  TcpSession ssn;
3560  Flow f;
3561 
3562  memset(&tv, 0x00, sizeof(tv));
3563 
3564  StreamTcpUTInit(&ra_ctx);
3568  FLOW_INITIALIZE(&f);
3569 
3571 
3572  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3573  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3574  FAIL_IF_NULL(p);
3575  p->l4.hdrs.tcph->th_seq = htonl(17);
3576  p->flow = &f;
3578 
3579  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3580  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3581  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3582  ssn.client.next_seq = 12;
3583  ssn.client.last_ack = 10;
3584 
3585  /* close the GAP and see if we properly reassemble and update base_seq */
3586  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3587  ssn.client.next_seq = 22;
3588 
3589  p->l4.hdrs.tcph->th_seq = htonl(12);
3590 
3591  TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3592  FAIL_IF_NULL(seg);
3593  FAIL_IF_NOT(seg->seq == 2);
3594 
3595  FLOW_DESTROY(&f);
3596  UTHFreePacket(p);
3598  StreamTcpUTDeinit(ra_ctx);
3599  PASS;
3600 }
3601 
3602 /** \test App Layer reassembly.
3603  */
3604 static int StreamTcpReassembleInlineTest10(void)
3605 {
3606  TcpReassemblyThreadCtx *ra_ctx = NULL;
3607  ThreadVars tv;
3608  TcpSession ssn;
3609  Packet *p = NULL;
3610 
3611  memset(&tv, 0x00, sizeof(tv));
3612 
3613  StreamTcpUTInit(&ra_ctx);
3617  ssn.server.last_ack = 2;
3619  ssn.client.last_ack = 2;
3620  ssn.data_first_seen_dir = STREAM_TOSERVER;
3621 
3622  Flow *f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
3623  FAIL_IF_NULL(f);
3624  f->protoctx = &ssn;
3625  f->proto = IPPROTO_TCP;
3626 
3627  uint8_t stream_payload1[] = "GE";
3628  uint8_t stream_payload2[] = "T /";
3629  uint8_t stream_payload3[] = "HTTP/1.0\r\n\r\n";
3630 
3631  p = UTHBuildPacketReal(stream_payload3, 12, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3632  FAIL_IF_NULL(p);
3633  p->l4.hdrs.tcph->th_seq = htonl(7);
3634  p->flow = f;
3636 
3637  FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 2, stream_payload1, 2) ==
3638  -1);
3639  ssn.client.next_seq = 4;
3640 
3642 
3643  /* ssn.server.ra_app_base_seq should be isn here. */
3645 
3646  FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 4, stream_payload2, 3) ==
3647  -1);
3648  FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 7, stream_payload3, 12) ==
3649  -1);
3650  ssn.client.next_seq = 19;
3651 
3653 
3655 
3656  UTHFreePacket(p);
3658  StreamTcpUTDeinit(ra_ctx);
3659  UTHFreeFlow(f);
3660  PASS;
3661 }
3662 
3663 /** \test test insert with overlap
3664  */
3665 static int StreamTcpReassembleInsertTest01(void)
3666 {
3667  TcpReassemblyThreadCtx *ra_ctx = NULL;
3668  ThreadVars tv;
3669  TcpSession ssn;
3670  Flow f;
3671 
3672  memset(&tv, 0x00, sizeof(tv));
3673 
3674  StreamTcpUTInit(&ra_ctx);
3678  FLOW_INITIALIZE(&f);
3679 
3680  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3681  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3682  FAIL_IF_NULL(p);
3683  p->l4.hdrs.tcph->th_seq = htonl(12);
3684  p->flow = &f;
3685 
3686  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3687  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3688  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 14, 'D', 2) == -1);
3689  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 16, 'D', 6) == -1);
3690  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3691  ssn.client.next_seq = 21;
3692 
3693  FLOW_DESTROY(&f);
3694  UTHFreePacket(p);
3696  StreamTcpUTDeinit(ra_ctx);
3697  PASS;
3698 }
3699 
3700 /** \test test insert with overlaps
3701  */
3702 static int StreamTcpReassembleInsertTest02(void)
3703 {
3704  TcpReassemblyThreadCtx *ra_ctx = NULL;
3705  ThreadVars tv;
3706  TcpSession ssn;
3707 
3708  memset(&tv, 0x00, sizeof(tv));
3709 
3710  StreamTcpUTInit(&ra_ctx);
3713 
3714  int i;
3715  for (i = 2; i < 10; i++) {
3716  int len;
3717  len = i % 2;
3718  if (len == 0)
3719  len = 1;
3720  int seq;
3721  seq = i * 10;
3722  if (seq < 2)
3723  seq = 2;
3724 
3725  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'A', len) == -1);
3726  }
3727  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'B', 1024) == -1);
3728 
3730  StreamTcpUTDeinit(ra_ctx);
3731  PASS;
3732 }
3733 
3734 /** \test test insert with overlaps
3735  */
3736 static int StreamTcpReassembleInsertTest03(void)
3737 {
3738  TcpReassemblyThreadCtx *ra_ctx = NULL;
3739  ThreadVars tv;
3740  TcpSession ssn;
3741 
3742  memset(&tv, 0x00, sizeof(tv));
3743 
3744  StreamTcpUTInit(&ra_ctx);
3747 
3748  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 1024) == -1);
3749 
3750  int i;
3751  for (i = 2; i < 10; i++) {
3752  int len;
3753  len = i % 2;
3754  if (len == 0)
3755  len = 1;
3756  int seq;
3757  seq = i * 10;
3758  if (seq < 2)
3759  seq = 2;
3760 
3761  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'B', len) == -1);
3762  }
3764  StreamTcpUTDeinit(ra_ctx);
3765  PASS;
3766 }
3767 
3769 #endif /* UNITTESTS */
3770 
3771 /** \brief The Function Register the Unit tests to test the reassembly engine
3772  * for various OS policies.
3773  */
3774 
3776 {
3777 #ifdef UNITTESTS
3778  UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test",
3779  StreamTcpReassembleTest25);
3780  UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test",
3781  StreamTcpReassembleTest26);
3783  "StreamTcpReassembleTest27 -- Gap at after Reassembly Test", StreamTcpReassembleTest27);
3784  UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test",
3785  StreamTcpReassembleTest28);
3786  UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test",
3787  StreamTcpReassembleTest29);
3788  UtRegisterTest("StreamTcpReassembleTest33 -- Bug test",
3789  StreamTcpReassembleTest33);
3790  UtRegisterTest("StreamTcpReassembleTest34 -- Bug test",
3791  StreamTcpReassembleTest34);
3792  UtRegisterTest("StreamTcpReassembleTest39 -- app proto test",
3793  StreamTcpReassembleTest39);
3794  UtRegisterTest("StreamTcpReassembleTest40 -- app proto test",
3795  StreamTcpReassembleTest40);
3796  UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test",
3797  StreamTcpReassembleTest44);
3798  UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test",
3799  StreamTcpReassembleTest45);
3800  UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test",
3801  StreamTcpReassembleTest46);
3802  UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test",
3803  StreamTcpReassembleTest47);
3804 
3805  UtRegisterTest("StreamTcpReassembleInlineTest01 -- inline RAW ra",
3806  StreamTcpReassembleInlineTest01);
3807  UtRegisterTest("StreamTcpReassembleInlineTest02 -- inline RAW ra 2",
3808  StreamTcpReassembleInlineTest02);
3809  UtRegisterTest("StreamTcpReassembleInlineTest03 -- inline RAW ra 3",
3810  StreamTcpReassembleInlineTest03);
3811  UtRegisterTest("StreamTcpReassembleInlineTest04 -- inline RAW ra 4",
3812  StreamTcpReassembleInlineTest04);
3813  UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup",
3814  StreamTcpReassembleInlineTest08);
3815  UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup",
3816  StreamTcpReassembleInlineTest09);
3817 
3818  UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10",
3819  StreamTcpReassembleInlineTest10);
3820 
3821  UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap",
3822  StreamTcpReassembleInsertTest01);
3823  UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap",
3824  StreamTcpReassembleInsertTest02);
3825  UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap",
3826  StreamTcpReassembleInsertTest03);
3827 
3831  StreamTcpReassembleRawRegisterTests();
3832 #endif /* UNITTESTS */
3833 }
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:2272
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:538
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
SCAppLayerParserStateIssetFlag
uint16_t SCAppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:2079
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:2129
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:409
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:1913
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-tcp.h
StreamTcpInlineMode
bool StreamTcpInlineMode(void)
See if stream engine is operating in inline mode.
Definition: stream-tcp.c:7276
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:1193
SET_ISN
#define SET_ISN(stream, setseq)
Definition: stream-tcp-reassemble.c:2201
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:382
Packet_::payload
uint8_t * payload
Definition: decode.h:620
StreamTcpReassemblySetMinInspectDepth
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
Definition: stream-tcp-reassemble.c:2181
STREAM_REASSEMBLY_URGENT_OOB_LIMIT_REACHED
@ STREAM_REASSEMBLY_URGENT_OOB_LIMIT_REACHED
Definition: decode-events.h:323
action-globals.h
TcpReassemblyThreadCtx_::app_tctx
void * app_tctx
Definition: stream-tcp-reassemble.h:62
Packet_::flags
uint32_t flags
Definition: decode.h:562
SCAppLayerParserStateSetFlag
void SCAppLayerParserStateSetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:2071
ssn
TcpSession ssn
Definition: fuzz_dataset.c:31
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:360
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
OS_POLICY_BSD
@ OS_POLICY_BSD
Definition: stream-tcp-reassemble.h:37
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:1396
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:398
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:1811
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:713
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:237
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:422
SCConfGetBool
int SCConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
Definition: conf.c:524
TcpSession_::urg_offset_ts
uint16_t urg_offset_ts
Definition: stream-tcp-private.h:291
FLOW_APP_LAYER_FLUSH_PENDING
#define FLOW_APP_LAYER_FLUSH_PENDING
Definition: flow.h:133
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
p
Packet * p
Definition: fuzz_dataset.c:30
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
StreamingBufferGetDataAtOffset
int StreamingBufferGetDataAtOffset(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t offset)
Definition: util-streaming-buffer.c:1828
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:547
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:439
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:100
Packet_::payload_len
uint16_t payload_len
Definition: decode.h:621
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:645
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:2263
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:97
StreamTcpReassembleInit
int StreamTcpReassembleInit(bool quiet)
Definition: stream-tcp-reassemble.c:531
PKT_DROP_REASON_STREAM_URG
@ PKT_DROP_REASON_STREAM_URG
Definition: decode.h:399
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
STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION
@ STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION
Definition: stream-tcp.h:192
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:2164
SCReturnBool
#define SCReturnBool(x)
Definition: util-debug.h:302
FLOW_IS_PM_DONE
#define FLOW_IS_PM_DONE(f, dir)
Definition: flow.h:282
TcpStream_::last_ack
uint32_t last_ack
Definition: stream-tcp-private.h:115
Flow_::alparser
AppLayerParserState * alparser
Definition: flow.h:484
StreamTcpReassembleInitThreadCtx
TcpReassemblyThreadCtx * StreamTcpReassembleInitThreadCtx(ThreadVars *tv)
Definition: stream-tcp-reassemble.c:565
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:630
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:471
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:2295
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:283
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
STREAM_HAS_UNPROCESSED_SEGMENTS_NONE
@ STREAM_HAS_UNPROCESSED_SEGMENTS_NONE
Definition: stream-tcp.h:189
PKT_STREAM_ADD
#define PKT_STREAM_ADD
Definition: decode.h:1305
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:1313
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:5680
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:981
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:1509
PacketFree
void PacketFree(Packet *p)
Return a malloced packet.
Definition: decode.c:221
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:2215
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:331
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:516
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:616
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:1851
TcpStream_::window
uint32_t window
Definition: stream-tcp-private.h:117
STREAM_REASSEMBLY_DEPTH_REACHED
@ STREAM_REASSEMBLY_DEPTH_REACHED
Definition: decode-events.h:319
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:601
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:300
StreamDataAvailableForProtoDetect
uint32_t StreamDataAvailableForProtoDetect(TcpStream *stream)
Definition: stream-tcp-reassemble.c:727
AppLayerGetCtxThread
AppLayerThreadCtx * AppLayerGetCtxThread(void)
Creates a new app layer thread context.
Definition: app-layer.c:1117
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:238
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:547
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
OS_POLICY_LAST
@ OS_POLICY_LAST
Definition: stream-tcp-reassemble.h:51
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:751
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:1718
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:564
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:445
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:2244
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:550
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:2009
TCP_CLOSING
@ TCP_CLOSING
Definition: stream-tcp-private.h:161
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:34
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:260
StreamReassembleRawUpdateProgress
void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, const uint64_t progress)
update stream engine after detection
Definition: stream-tcp-reassemble.c:1555
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:481
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:184
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:457
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:1138
SEQ_LT
#define SEQ_LT(a, b)
Definition: stream-tcp-private.h:257
STREAM_REASSEMBLY_SEQ_GAP
@ STREAM_REASSEMBLY_SEQ_GAP
Definition: decode-events.h:317
STREAM_REASSEMBLY_NO_SEGMENT
@ STREAM_REASSEMBLY_NO_SEGMENT
Definition: decode-events.h:316
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:2258
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:2267
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:596
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:521
StreamTcpStateAsString
const char * StreamTcpStateAsString(const enum TcpState state)
Definition: stream-tcp.c:7289
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:3775
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:196
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:458
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:456
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:1978
ExceptionPolicy
ExceptionPolicy
Definition: util-exception-policy-types.h:26
FLOW_DIR_REVERSED
#define FLOW_DIR_REVERSED
Definition: flow.h:112
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:1901
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:1682
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:520
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
f
Flow f
Definition: fuzz_dataset.c:32