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