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