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