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) != 0;
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  return nblk && (cur_blk->offset + cur_blk->len < nblk->offset) &&
1103  GetAbsLastAck(stream) > (cur_blk->offset + cur_blk->len);
1104 }
1105 
1106 /** \internal
1107  *
1108  * Get buffer, or first part of the buffer if data gaps exist.
1109  *
1110  * \brief get stream data from offset
1111  * \param offset stream offset
1112  * \param check_for_gap check if there is a gap ahead. Optional as it is only
1113  * needed for app-layer incomplete support.
1114  * \retval bool pkt loss ahead */
1115 static bool GetAppBuffer(const TcpStream *stream, const uint8_t **data, uint32_t *data_len,
1116  uint64_t offset, const bool check_for_gap)
1117 {
1118  const uint8_t *mydata;
1119  uint32_t mydata_len;
1120  bool gap_ahead = false;
1121 
1122  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1123  SCLogDebug("getting one blob");
1124 
1125  StreamingBufferGetDataAtOffset(&stream->sb, &mydata, &mydata_len, offset);
1126 
1127  *data = mydata;
1128  *data_len = mydata_len;
1129  } else {
1130  SCLogDebug("block mode");
1131  StreamingBufferBlock key = { .offset = offset, .len = 0 };
1132  StreamingBufferBlock *blk = SBB_RB_FIND_INCLUSIVE((struct SBB *)&stream->sb.sbb_tree, &key);
1133  if (blk == NULL) {
1134  *data = NULL;
1135  *data_len = 0;
1136  return false;
1137  }
1138  SCLogDebug("blk %p blk->offset %" PRIu64 ", blk->len %u", blk, blk->offset, blk->len);
1139 
1140  /* block at expected offset */
1141  if (blk->offset == offset) {
1142  SCLogDebug("blk at offset");
1143 
1144  StreamingBufferSBBGetData(&stream->sb, blk, data, data_len);
1145  DEBUG_VALIDATE_BUG_ON(blk->len != *data_len);
1146 
1147  gap_ahead = check_for_gap && GapAhead(stream, blk);
1148 
1149  /* block past out offset */
1150  } else if (blk->offset > offset) {
1151  SCLogDebug("gap, want data at offset %"PRIu64", "
1152  "got data at %"PRIu64". GAP of size %"PRIu64,
1153  offset, blk->offset, blk->offset - offset);
1154  *data = NULL;
1155  *data_len = (uint32_t)(blk->offset - offset);
1156 
1157  /* block starts before offset, but ends after */
1158  } else if (offset > blk->offset && offset <= (blk->offset + blk->len)) {
1159  SCLogDebug("get data from offset %"PRIu64". SBB %"PRIu64"/%u",
1160  offset, blk->offset, blk->len);
1161  StreamingBufferSBBGetDataAtOffset(&stream->sb, blk, data, data_len, offset);
1162  SCLogDebug("data %p, data_len %u", *data, *data_len);
1163 
1164  gap_ahead = check_for_gap && GapAhead(stream, blk);
1165 
1166  } else {
1167  *data = NULL;
1168  *data_len = 0;
1169  }
1170  }
1171  return gap_ahead;
1172 }
1173 
1174 /** \internal
1175  * \brief check to see if we should declare a GAP
1176  * Call this when the app layer didn't get data at the requested
1177  * offset.
1178  */
1179 static inline bool CheckGap(TcpSession *ssn, TcpStream *stream, Packet *p)
1180 {
1181  const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
1182  const int ackadded = (ssn->state >= TCP_FIN_WAIT1) ? 1 : 0;
1183  const uint64_t last_ack_abs = GetAbsLastAck(stream) - (uint64_t)ackadded;
1184 
1185  SCLogDebug("last_ack %u abs %" PRIu64, stream->last_ack, last_ack_abs);
1186  SCLogDebug("next_seq %u", stream->next_seq);
1187 
1188  /* if last_ack_abs is beyond the app_progress data that we haven't seen
1189  * has been ack'd. This looks like a GAP. */
1190  if (last_ack_abs > app_progress) {
1191  /* however, we can accept ACKs a bit too liberally. If last_ack
1192  * is beyond next_seq, we only consider it a gap now if we do
1193  * already have data beyond the gap. */
1194  if (SEQ_GT(stream->last_ack, stream->next_seq)) {
1195  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1196  SCLogDebug("packet %" PRIu64 ": no GAP. "
1197  "next_seq %u < last_ack %u, but no data in list",
1198  PcapPacketCntGet(p), stream->next_seq, stream->last_ack);
1199  return false;
1200  }
1201  const uint64_t next_seq_abs =
1202  STREAM_BASE_OFFSET(stream) + (stream->next_seq - stream->base_seq);
1203  const StreamingBufferBlock *blk = stream->sb.head;
1204  if (blk->offset > next_seq_abs && blk->offset < last_ack_abs) {
1205  /* ack'd data after the gap */
1206  SCLogDebug("packet %" PRIu64 ": GAP. "
1207  "next_seq %u < last_ack %u, but ACK'd data beyond gap.",
1208  PcapPacketCntGet(p), stream->next_seq, stream->last_ack);
1209  return true;
1210  }
1211  }
1212 
1213  SCLogDebug("packet %" PRIu64 ": GAP! "
1214  "last_ack_abs %" PRIu64 " > app_progress %" PRIu64 ", "
1215  "but we have no data.",
1216  PcapPacketCntGet(p), last_ack_abs, app_progress);
1217  return true;
1218  }
1219  SCLogDebug("packet %" PRIu64 ": no GAP. "
1220  "last_ack_abs %" PRIu64 " <= app_progress %" PRIu64,
1221  PcapPacketCntGet(p), last_ack_abs, app_progress);
1222  return false;
1223 }
1224 
1225 static inline uint32_t AdjustToAcked(const Packet *p,
1226  const TcpSession *ssn, const TcpStream *stream,
1227  const uint64_t app_progress, const uint32_t data_len)
1228 {
1229  uint32_t adjusted = data_len;
1230 
1231  /* get window of data that is acked */
1232  if (!StreamTcpInlineMode()) {
1233  SCLogDebug("ssn->state %s", StreamTcpStateAsString(ssn->state));
1234  if (data_len == 0 || ((ssn->state < TCP_CLOSED ||
1235  (ssn->state == TCP_CLOSED &&
1236  (ssn->flags & STREAMTCP_FLAG_CLOSED_BY_RST) != 0)) &&
1237  (p->flags & PKT_PSEUDO_STREAM_END))) {
1238  // fall through, we use all available data
1239  } else {
1240  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1241  DEBUG_VALIDATE_BUG_ON(app_progress > last_ack_abs);
1242 
1243  /* see if the buffer contains unack'd data as well */
1244  if (app_progress <= last_ack_abs && app_progress + data_len > last_ack_abs) {
1245  adjusted = (uint32_t)(last_ack_abs - app_progress);
1246  DEBUG_VALIDATE_BUG_ON(adjusted > data_len);
1247  SCLogDebug("data len adjusted to %u to make sure only ACK'd "
1248  "data is considered", adjusted);
1249  }
1250  }
1251  }
1252  return adjusted;
1253 }
1254 
1255 /** \internal
1256  * \brief get stream buffer and update the app-layer
1257  * \param stream pointer to pointer as app-layer can switch flow dir
1258  * \retval 0 success
1259  */
1260 static int ReassembleUpdateAppLayer(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn,
1261  TcpStream **stream, Packet *p, enum StreamUpdateDir app_update_dir)
1262 {
1263  uint64_t app_progress = STREAM_APP_PROGRESS(*stream);
1264 
1265  SCLogDebug("app progress %"PRIu64, app_progress);
1266 #ifdef DEBUG
1267  uint64_t last_ack_abs = GetAbsLastAck(*stream);
1268  SCLogDebug("last_ack %u (abs %" PRIu64 "), base_seq %u", (*stream)->last_ack, last_ack_abs,
1269  (*stream)->base_seq);
1270 #endif
1271  const uint8_t *mydata;
1272  uint32_t mydata_len;
1273  bool last_was_gap = false;
1274 
1275  while (1) {
1276  const uint8_t flags = StreamGetAppLayerFlags(ssn, *stream, p);
1277  bool check_for_gap_ahead = ((*stream)->data_required > 0);
1278  bool gap_ahead =
1279  GetAppBuffer(*stream, &mydata, &mydata_len, app_progress, check_for_gap_ahead);
1280  SCLogDebug("gap_ahead %s mydata_len %u", BOOL2STR(gap_ahead), mydata_len);
1281  if (last_was_gap && mydata_len == 0) {
1282  break;
1283  }
1284  last_was_gap = false;
1285 
1286  /* make sure to only deal with ACK'd data */
1287  mydata_len = AdjustToAcked(p, ssn, *stream, app_progress, mydata_len);
1288  DEBUG_VALIDATE_BUG_ON(mydata_len > (uint32_t)INT_MAX);
1289  if (mydata == NULL && mydata_len > 0 && CheckGap(ssn, *stream, p)) {
1290  SCLogDebug("sending GAP to app-layer (size: %u)", mydata_len);
1291 
1292  int r = AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, NULL, mydata_len,
1293  StreamGetAppLayerFlags(ssn, *stream, p) | STREAM_GAP, app_update_dir);
1294  AppLayerProfilingStore(ra_ctx->app_tctx, p);
1295 
1297  (*stream)->flags |= STREAMTCP_STREAM_FLAG_HAS_GAP;
1300 
1301  /* AppLayerHandleTCPData has likely updated progress. */
1302  const bool no_progress_update = (app_progress == STREAM_APP_PROGRESS(*stream));
1303  app_progress = STREAM_APP_PROGRESS(*stream);
1304 
1305  /* a GAP also consumes 'data required'. TODO perhaps we can use
1306  * this to skip post GAP data until the start of a next record. */
1307  if ((*stream)->data_required > 0) {
1308  if ((*stream)->data_required > mydata_len) {
1309  (*stream)->data_required -= mydata_len;
1310  } else {
1311  (*stream)->data_required = 0;
1312  }
1313  }
1314  if (r < 0)
1315  return 0;
1316  if (no_progress_update)
1317  break;
1318  last_was_gap = true;
1319  continue;
1320 
1321  } else if (flags & STREAM_DEPTH) {
1322  SCLogDebug("DEPTH");
1323  // we're just called once with this flag, so make sure we pass it on
1324  if (mydata == NULL && mydata_len > 0) {
1325  mydata_len = 0;
1326  }
1327  } else if (mydata == NULL || (mydata_len == 0 && ((flags & STREAM_EOF) == 0))) {
1328  SCLogDebug("GAP?1");
1329  /* Possibly a gap, but no new data. */
1330  if ((p->flags & PKT_PSEUDO_STREAM_END) == 0 || ssn->state < TCP_CLOSED)
1331  SCReturnInt(0);
1332 
1333  mydata = NULL;
1334  mydata_len = 0;
1335  SCLogDebug("%" PRIu64 " got %p/%u", PcapPacketCntGet(p), mydata, mydata_len);
1336  break;
1337  }
1338  DEBUG_VALIDATE_BUG_ON(mydata == NULL && mydata_len > 0);
1339 
1340  SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64,
1341  *stream, &(*stream)->sb, mydata_len, app_progress);
1342 
1343  if ((p->flags & PKT_PSEUDO_STREAM_END) == 0 || ssn->state < TCP_CLOSED) {
1344  SCLogDebug("GAP?2");
1345  if (mydata_len < (*stream)->data_required) {
1346  SCLogDebug("GAP?3 gap_head %s", BOOL2STR(gap_ahead));
1347  if (gap_ahead) {
1348  SCLogDebug("GAP while expecting more data (expect %u, gap size %u)",
1349  (*stream)->data_required, mydata_len);
1350  (*stream)->app_progress_rel += mydata_len;
1351  (*stream)->data_required -= mydata_len;
1352  // TODO send incomplete data to app-layer with special flag
1353  // indicating its all there is for this rec?
1354  } else {
1355  SCReturnInt(0);
1356  }
1357  app_progress = STREAM_APP_PROGRESS(*stream);
1358  continue;
1359  }
1360  }
1361  (*stream)->data_required = 0;
1362 
1363  SCLogDebug("parser");
1364  /* update the app-layer */
1365  (void)AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, (uint8_t *)mydata,
1366  mydata_len, flags, app_update_dir);
1367  AppLayerProfilingStore(ra_ctx->app_tctx, p);
1368  AppLayerFrameDump(p->flow);
1369  uint64_t new_app_progress = STREAM_APP_PROGRESS(*stream);
1370  if (new_app_progress == app_progress || FlowChangeProto(p->flow))
1371  break;
1372  app_progress = new_app_progress;
1373  if (flags & STREAM_DEPTH)
1374  break;
1375  }
1376 
1377  SCReturnInt(0);
1378 }
1379 
1380 /**
1381  * \brief Update the stream reassembly upon receiving a packet.
1382  *
1383  * For IDS mode, the stream is in the opposite direction of the packet,
1384  * as the ACK-packet is ACK'ing the stream.
1385  *
1386  * One of the utilities call by this function AppLayerHandleTCPData(),
1387  * has a feature where it will call this very same function for the
1388  * stream opposing the stream it is called with. This shouldn't cause
1389  * any issues, since processing of each stream is independent of the
1390  * other stream.
1391  */
1393  TcpStream *stream, Packet *p, enum StreamUpdateDir app_update_dir)
1394 {
1395  SCEnter();
1396 
1397  /* this function can be directly called by app layer protocol
1398  * detection. */
1401  SCLogDebug("stream no reassembly flag set or app-layer disabled.");
1402  SCReturnInt(0);
1403  }
1404 
1405 #ifdef DEBUG
1406  SCLogDebug("stream->seg_tree RB_MIN %p", RB_MIN(TCPSEG, &stream->seg_tree));
1407  GetSessionSize(ssn, p);
1408 #endif
1409  /* if no segments are in the list or all are already processed,
1410  * and state is beyond established, we send an empty msg */
1411  if (!STREAM_HAS_SEEN_DATA(stream) || STREAM_RIGHT_EDGE(stream) <= STREAM_APP_PROGRESS(stream))
1412  {
1413  /* send an empty EOF msg if we have no segments but TCP state
1414  * is beyond ESTABLISHED */
1415  if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) {
1416  SCLogDebug("sending empty eof message");
1417  /* send EOF to app layer */
1418  uint8_t stream_flags = StreamGetAppLayerFlags(ssn, stream, p);
1420  tv, ra_ctx, p, p->flow, ssn, &stream, NULL, 0, stream_flags, app_update_dir);
1421  AppLayerProfilingStore(ra_ctx->app_tctx, p);
1422 
1423  SCReturnInt(0);
1424  }
1425  }
1426 
1427  /* with all that out of the way, lets update the app-layer */
1428  return ReassembleUpdateAppLayer(tv, ra_ctx, ssn, &stream, p, app_update_dir);
1429 }
1430 
1431 /** \internal
1432  * \brief get stream data from offset
1433  * \param offset stream offset */
1434 static int GetRawBuffer(const TcpStream *stream, const uint8_t **data, uint32_t *data_len,
1435  StreamingBufferBlock **iter, uint64_t offset, uint64_t *data_offset)
1436 {
1437  const uint8_t *mydata;
1438  uint32_t mydata_len;
1439  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1440  SCLogDebug("getting one blob for offset %"PRIu64, offset);
1441 
1442  /* No gaps in the stream, data must exist in the streaming buffer array */
1443  uint64_t roffset = offset;
1444  if (offset) {
1445  StreamingBufferGetDataAtOffset(&stream->sb, &mydata, &mydata_len, offset);
1446  } else {
1447  StreamingBufferGetData(&stream->sb, &mydata, &mydata_len, &roffset);
1448  }
1449 
1450  *data = mydata;
1451  *data_len = mydata_len;
1452  *data_offset = roffset;
1453  } else {
1454  SCLogDebug("multiblob %s. Want offset %"PRIu64,
1455  *iter == NULL ? "starting" : "continuing", offset);
1456  if (*iter == NULL) {
1457  StreamingBufferBlock key = { .offset = offset, .len = 0 };
1458  *iter = SBB_RB_FIND_INCLUSIVE((struct SBB *)&stream->sb.sbb_tree, &key);
1459  SCLogDebug("*iter %p", *iter);
1460  }
1461  if (*iter == NULL) {
1462  SCLogDebug("no data");
1463  *data = NULL;
1464  *data_len = 0;
1465  *data_offset = 0;
1466  return 0;
1467  }
1468  SCLogDebug("getting multiple blobs. Iter %p, %"PRIu64"/%u", *iter, (*iter)->offset, (*iter)->len);
1469 
1470  StreamingBufferSBBGetData(&stream->sb, (*iter), &mydata, &mydata_len);
1471  SCLogDebug("mydata %p", mydata);
1472 
1473  if ((*iter)->offset < offset) {
1474  uint64_t delta = offset - (*iter)->offset;
1475  if (delta < mydata_len) {
1476  *data = mydata + delta;
1477  *data_len = (uint32_t)(mydata_len - delta);
1478  *data_offset = offset;
1479  } else {
1480  SCLogDebug("no data (yet)");
1481  *data = NULL;
1482  *data_len = 0;
1483  *data_offset = 0;
1484  }
1485 
1486  } else {
1487  *data = mydata;
1488  *data_len = mydata_len;
1489  *data_offset = (*iter)->offset;
1490  }
1491 
1492  *iter = SBB_RB_NEXT(*iter);
1493  SCLogDebug("*iter %p", *iter);
1494  }
1495  return 0;
1496 }
1497 
1498 /** \brief does the stream engine have data to inspect?
1499  *
1500  * Returns true if there is data to inspect. In IDS case this is
1501  * about ACK'd data in the packet's direction.
1502  *
1503  * In the IPS case this is about the packet itself.
1504  */
1506 {
1507  TcpStream *stream;
1508  if (PKT_IS_TOSERVER(p)) {
1509  stream = &ssn->client;
1510  } else {
1511  stream = &ssn->server;
1512  }
1513 
1514  if (RB_EMPTY(&stream->seg_tree)) {
1515  return false;
1516  }
1517 
1520  return false;
1521 
1522  if (!StreamTcpInlineMode()) {
1523  const uint64_t segs_re_abs =
1524  STREAM_BASE_OFFSET(stream) + stream->segs_right_edge - stream->base_seq;
1525  if (STREAM_RAW_PROGRESS(stream) == segs_re_abs) {
1526  return false;
1527  }
1528  if (StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 1) {
1529  return true;
1530  }
1531  } else {
1532  if (p->payload_len > 0 && (p->flags & PKT_STREAM_ADD)) {
1533  return true;
1534  }
1535  }
1536  return false;
1537 }
1538 
1539 /** \brief update stream engine after detection
1540  *
1541  * Tasked with progressing the 'progress' for Raw reassembly.
1542  * 2 main scenario's:
1543  * 1. progress is != 0, so we use this
1544  * 2. progress is 0, meaning the detect engine didn't touch
1545  * raw at all. In this case we need to look into progressing
1546  * raw anyway.
1547  *
1548  * Additionally, this function is tasked with disabling raw
1549  * reassembly if the app-layer requested to disable it.
1550  */
1551 void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, const uint64_t progress)
1552 {
1553  TcpStream *stream;
1554  if (PKT_IS_TOSERVER(p)) {
1555  stream = &ssn->client;
1556  } else {
1557  stream = &ssn->server;
1558  }
1559 
1560  if (progress > STREAM_RAW_PROGRESS(stream)) {
1561  DEBUG_VALIDATE_BUG_ON(progress - STREAM_RAW_PROGRESS(stream) > UINT32_MAX);
1562  uint32_t slide = (uint32_t)(progress - STREAM_RAW_PROGRESS(stream));
1563  stream->raw_progress_rel += slide;
1565 
1566  } else if (progress == 0) {
1567  uint64_t target;
1568  if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) == 0) {
1569  target = STREAM_APP_PROGRESS(stream);
1570  } else {
1571  target = GetAbsLastAck(stream);
1572  }
1573  if (target > STREAM_RAW_PROGRESS(stream)) {
1574  DEBUG_VALIDATE_BUG_ON(target - STREAM_RAW_PROGRESS(stream) > UINT32_MAX);
1575  uint32_t slide = (uint32_t)(target - STREAM_RAW_PROGRESS(stream));
1576  stream->raw_progress_rel += slide;
1577  }
1579 
1580  } else {
1581  SCLogDebug("pcap_cnt %" PRIu64 ": progress %" PRIu64 " app %" PRIu64 " raw %" PRIu64
1582  " tcp win %" PRIu32,
1583  PcapPacketCntGet(p), progress, STREAM_APP_PROGRESS(stream),
1584  STREAM_RAW_PROGRESS(stream), stream->window);
1585  }
1586 
1587  /* if we were told to accept no more raw data, we can mark raw as
1588  * disabled now. */
1591  SCLogDebug("ssn %p: STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED set, "
1592  "now that detect ran also set STREAMTCP_STREAM_FLAG_DISABLE_RAW", ssn);
1593  }
1594 
1595  SCLogDebug("stream raw progress now %"PRIu64, STREAM_RAW_PROGRESS(stream));
1596 }
1597 
1598 /** \internal
1599  * \brief get a buffer around the current packet and run the callback on it
1600  *
1601  * The inline/IPS scanning method takes the current payload and wraps it in
1602  * data from other segments.
1603  *
1604  * How much data is inspected is controlled by the available data, chunk_size
1605  * and the payload size of the packet.
1606  *
1607  * Large packets: if payload size is close to the chunk_size, where close is
1608  * defined as more than 67% of the chunk_size, a larger chunk_size will be
1609  * used: payload_len + 33% of the chunk_size.
1610  * If the payload size if equal to or bigger than the chunk_size, we use
1611  * payload len + 33% of the chunk size.
1612  */
1613 static int StreamReassembleRawInline(TcpSession *ssn, const Packet *p,
1614  StreamReassembleRawFunc Callback, void *cb_data, uint64_t *progress_out)
1615 {
1616  SCEnter();
1617  int r = 0;
1618 
1619  TcpStream *stream;
1620  if (PKT_IS_TOSERVER(p)) {
1621  stream = &ssn->client;
1622  } else {
1623  stream = &ssn->server;
1624  }
1625 
1626  if (p->payload_len == 0 || (p->flags & PKT_STREAM_ADD) == 0 ||
1628  {
1629  *progress_out = STREAM_RAW_PROGRESS(stream);
1630  return 0;
1631  }
1632 
1633  uint32_t chunk_size = PKT_IS_TOSERVER(p) ?
1636  if ((chunk_size <= p->payload_len) || (((chunk_size / 3) * 2) < p->payload_len)) {
1637  chunk_size = p->payload_len + (chunk_size / 3);
1638  SCLogDebug(
1639  "packet payload len %u, so chunk_size adjusted to %u", p->payload_len, chunk_size);
1640  }
1641 
1642  const TCPHdr *tcph = PacketGetTCP(p);
1643  /* use packet SEQ, but account for TFO needing a + 1 */
1644  const uint32_t tfo_add = (TCP_HAS_TFO(p));
1645  const uint32_t pkt_seq = TCP_GET_RAW_SEQ(tcph) + tfo_add;
1646  uint64_t packet_leftedge_abs = STREAM_BASE_OFFSET(stream) + (pkt_seq - stream->base_seq);
1647  uint64_t packet_rightedge_abs = packet_leftedge_abs + p->payload_len;
1648  SCLogDebug("packet_leftedge_abs %"PRIu64", rightedge %"PRIu64,
1649  packet_leftedge_abs, packet_rightedge_abs);
1650 
1651  const uint8_t *mydata = NULL;
1652  uint32_t mydata_len = 0;
1653  uint64_t mydata_offset = 0;
1654  /* simply return progress from the block we inspected. */
1655  bool return_progress = false;
1656 
1657  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1658  /* continues block */
1659  StreamingBufferGetData(&stream->sb, &mydata, &mydata_len, &mydata_offset);
1660  return_progress = true;
1661 
1662  } else {
1663  SCLogDebug("finding our SBB from offset %"PRIu64, packet_leftedge_abs);
1664  /* find our block */
1665  StreamingBufferBlock key = { .offset = packet_leftedge_abs, .len = p->payload_len };
1666  StreamingBufferBlock *sbb = SBB_RB_FIND_INCLUSIVE(&stream->sb.sbb_tree, &key);
1667  if (sbb) {
1668  SCLogDebug("found %p offset %"PRIu64" len %u", sbb, sbb->offset, sbb->len);
1669  StreamingBufferSBBGetData(&stream->sb, sbb, &mydata, &mydata_len);
1670  mydata_offset = sbb->offset;
1671  }
1672  }
1673 
1674  /* this can only happen if the segment insert of our current 'p' failed */
1675  uint64_t mydata_rightedge_abs = mydata_offset + mydata_len;
1676  if ((mydata == NULL || mydata_len == 0) || /* no data */
1677  (mydata_offset >= packet_rightedge_abs || /* data all to the right */
1678  packet_leftedge_abs >= mydata_rightedge_abs) || /* data all to the left */
1679  (packet_leftedge_abs < mydata_offset || /* data missing at the start */
1680  packet_rightedge_abs > mydata_rightedge_abs)) /* data missing at the end */
1681  {
1682  /* no data, or data is incomplete or wrong: use packet data */
1683  mydata = p->payload;
1684  mydata_len = p->payload_len;
1685  mydata_offset = packet_leftedge_abs;
1686  //mydata_rightedge_abs = packet_rightedge_abs;
1687  } else {
1688  /* adjust buffer to match chunk_size */
1689  SCLogDebug("chunk_size %u mydata_len %u", chunk_size, mydata_len);
1690  if (mydata_len > chunk_size) {
1691  uint32_t excess = mydata_len - chunk_size;
1692  SCLogDebug("chunk_size %u mydata_len %u excess %u", chunk_size, mydata_len, excess);
1693 
1694  if (mydata_rightedge_abs == packet_rightedge_abs) {
1695  mydata += excess;
1696  mydata_len -= excess;
1697  mydata_offset += excess;
1698  SCLogDebug("cutting front of the buffer with %u", excess);
1699  } else if (mydata_offset == packet_leftedge_abs) {
1700  mydata_len -= excess;
1701  SCLogDebug("cutting tail of the buffer with %u", excess);
1702  } else {
1703  DEBUG_VALIDATE_BUG_ON(mydata_offset > packet_leftedge_abs);
1704  uint32_t abs_before = (uint32_t)(packet_leftedge_abs - mydata_offset);
1705  DEBUG_VALIDATE_BUG_ON(packet_rightedge_abs > mydata_rightedge_abs);
1706  uint32_t abs_after = (uint32_t)(mydata_rightedge_abs - packet_rightedge_abs);
1707  uint32_t before = abs_before;
1708  uint32_t after = abs_after;
1709  SCLogDebug("before %u after %u", before, after);
1710 
1711  if (after >= (chunk_size - p->payload_len) / 2) {
1712  // more trailing data than we need
1713 
1714  if (before >= (chunk_size - p->payload_len) / 2) {
1715  // also more heading data, divide evenly
1716  before = after = (chunk_size - p->payload_len) / 2;
1717  } else {
1718  // heading data is less than requested, give the
1719  // rest to the trailing data
1720  after = (chunk_size - p->payload_len) - before;
1721  }
1722  } else {
1723  // less trailing data than requested
1724 
1725  if (before >= (chunk_size - p->payload_len) / 2) {
1726  before = (chunk_size - p->payload_len) - after;
1727  } else {
1728  // both smaller than their requested size
1729  }
1730  }
1731 
1732  /* adjust the buffer */
1733  DEBUG_VALIDATE_BUG_ON(before > abs_before);
1734  uint32_t skip = abs_before - before;
1735  DEBUG_VALIDATE_BUG_ON(after > abs_after);
1736  uint32_t cut = abs_after - after;
1737  DEBUG_VALIDATE_BUG_ON(skip > mydata_len);
1738  DEBUG_VALIDATE_BUG_ON(cut > mydata_len);
1739  DEBUG_VALIDATE_BUG_ON(skip + cut > mydata_len);
1740  mydata += skip;
1741  mydata_len -= (skip + cut);
1742  mydata_offset += skip;
1743  }
1744  }
1745  }
1746 
1747  /* run the callback */
1748  r = Callback(cb_data, mydata, mydata_len, mydata_offset);
1749  DEBUG_VALIDATE_BUG_ON(r < 0);
1750 
1751  if (return_progress) {
1752  *progress_out = (mydata_offset + mydata_len);
1753  } else {
1754  /* several blocks of data, so we need to be a bit more careful:
1755  * - if last_ack is beyond last progress, move progress forward to last_ack
1756  * - if our block matches or starts before last ack, return right edge of
1757  * our block.
1758  */
1759  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1760  SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs);
1761 
1762  if (STREAM_RAW_PROGRESS(stream) < last_ack_abs) {
1763  if (mydata_offset > last_ack_abs) {
1764  /* gap between us and last ack, set progress to last ack */
1765  *progress_out = last_ack_abs;
1766  } else {
1767  *progress_out = (mydata_offset + mydata_len);
1768  }
1769  } else {
1770  *progress_out = STREAM_RAW_PROGRESS(stream);
1771  }
1772  }
1773  return r;
1774 }
1775 
1776 /** \brief access 'raw' reassembly data.
1777  *
1778  * Access data as tracked by 'raw' tracker. Data is made available to
1779  * callback that is passed to this function.
1780  *
1781  * In the case of IDS the callback may be run multiple times if data
1782  * contains gaps. It will then be run for each block of data that is
1783  * continuous.
1784  *
1785  * The callback should give on of 2 return values:
1786  * - 0 ok
1787  * - 1 done
1788  * The value 1 will break the loop if there is a block list that is
1789  * inspected.
1790  *
1791  * This function will return the 'progress' value that has been
1792  * consumed until now.
1793  *
1794  * \param ssn tcp session
1795  * \param stream tcp stream
1796  * \param Callback the function pointer to the callback function
1797  * \param cb_data callback data
1798  * \param[in] progress_in progress to work from
1799  * \param[in] re right edge of data to consider
1800  * \param[out] progress_out absolute progress value of the data this
1801  * call handled.
1802  * \param eof we're wrapping up so inspect all data we have, incl unACKd
1803  */
1804 static int StreamReassembleRawDo(const TcpSession *ssn, const TcpStream *stream,
1805  StreamReassembleRawFunc Callback, void *cb_data, const uint64_t progress_in,
1806  const uint64_t re, uint64_t *progress_out, bool eof)
1807 {
1808  SCEnter();
1809  int r = 0;
1810 
1811  StreamingBufferBlock *iter = NULL;
1812  uint64_t progress = progress_in;
1813 
1814  /* loop through available buffers. On no packet loss we'll have a single
1815  * iteration. On missing data we'll walk the blocks */
1816  while (1) {
1817  const uint8_t *mydata;
1818  uint32_t mydata_len;
1819  uint64_t mydata_offset = 0;
1820 
1821  GetRawBuffer(stream, &mydata, &mydata_len, &iter, progress, &mydata_offset);
1822  if (mydata_len == 0) {
1823  SCLogDebug("no data");
1824  break;
1825  }
1826  //PrintRawDataFp(stdout, mydata, mydata_len);
1827 
1828  SCLogDebug("raw progress %"PRIu64, progress);
1829  SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64,
1830  stream, &stream->sb, mydata_len, progress);
1831 
1832  if (eof) {
1833  // inspect all remaining data, ack'd or not
1834  } else {
1835  if (re < progress) {
1836  SCLogDebug("nothing to do");
1837  goto end;
1838  }
1839 
1840  SCLogDebug("re %" PRIu64 ", raw_progress %" PRIu64, re, progress);
1841  SCLogDebug("raw_progress + mydata_len %" PRIu64 ", re %" PRIu64, progress + mydata_len,
1842  re);
1843 
1844  /* see if the buffer contains unack'd data as well */
1845  if (progress + mydata_len > re) {
1846 #ifdef DEBUG_VALIDATION
1847  uint32_t check = mydata_len;
1848 #endif
1849  mydata_len = (uint32_t)(re - progress);
1850  DEBUG_VALIDATE_BUG_ON(check < mydata_len);
1851  SCLogDebug("data len adjusted to %u to make sure only ACK'd "
1852  "data is considered", mydata_len);
1853  }
1854  }
1855  if (mydata_len == 0)
1856  break;
1857 
1858  SCLogDebug("data %p len %u", mydata, mydata_len);
1859 
1860  /* we have data. */
1861  r = Callback(cb_data, mydata, mydata_len, mydata_offset);
1862  DEBUG_VALIDATE_BUG_ON(r < 0);
1863 
1864  if (mydata_offset == progress) {
1865  SCLogDebug("progress %"PRIu64" increasing with data len %u to %"PRIu64,
1866  progress, mydata_len, progress_in + mydata_len);
1867 
1868  progress += mydata_len;
1869  SCLogDebug("raw progress now %"PRIu64, progress);
1870 
1871  /* data is beyond the progress we'd like, and before last ack. Gap. */
1872  } else if (mydata_offset > progress && mydata_offset < re) {
1873  SCLogDebug("GAP: data is missing from %"PRIu64" (%u bytes), setting to first data we have: %"PRIu64, progress, (uint32_t)(mydata_offset - progress), mydata_offset);
1874  SCLogDebug("re %" PRIu64, re);
1875  progress = mydata_offset;
1876  SCLogDebug("raw progress now %"PRIu64, progress);
1877 
1878  /* data is beyond the progress we'd like, and also beyond the last ack:
1879  * there is a gap and we can't expect it to get filled anymore. */
1880  } else if (mydata_offset > progress && mydata_offset == re) {
1881  SCLogDebug("mydata_offset %" PRIu64 ", progress %" PRIu64 ", re %" PRIu64,
1882  mydata_offset, progress, re);
1883  progress = re;
1884  } else {
1885  SCLogDebug("not increasing progress, data gap => mydata_offset "
1886  "%"PRIu64" != progress %"PRIu64, mydata_offset, progress);
1887  }
1888 
1889  if (iter == NULL || r == 1)
1890  break;
1891  }
1892 end:
1893  *progress_out = progress;
1894  return r;
1895 }
1896 
1898  void *cb_data, const uint64_t offset, const bool eof)
1899 {
1900  /* take app progress as the right edge of used data. */
1901  const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
1902  SCLogDebug("app_progress %" PRIu64, app_progress);
1903 
1904  uint64_t unused = 0;
1905  return StreamReassembleRawDo(
1906  ssn, stream, Callback, cb_data, offset, app_progress, &unused, eof);
1907 }
1908 
1910  StreamReassembleRawFunc Callback, void *cb_data,
1911  uint64_t *progress_out, bool respect_inspect_depth)
1912 {
1913  /* handle inline separately as the logic is very different */
1914  if (StreamTcpInlineMode()) {
1915  return StreamReassembleRawInline(ssn, p, Callback, cb_data, progress_out);
1916  }
1917 
1918  TcpStream *stream;
1919  if (PKT_IS_TOSERVER(p)) {
1920  stream = &ssn->client;
1921  } else {
1922  stream = &ssn->server;
1923  }
1924 
1926  StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 0)
1927  {
1928  *progress_out = STREAM_RAW_PROGRESS(stream);
1929  return 0;
1930  }
1931 
1932  uint64_t progress = STREAM_RAW_PROGRESS(stream);
1933  /* if the app layer triggered a flush, and we're supposed to
1934  * use a minimal inspect depth, we actually take the app progress
1935  * as that is the right edge of the data. Then we take the window
1936  * of 'min_inspect_depth' before that. */
1937 
1938  SCLogDebug("respect_inspect_depth %s STREAMTCP_STREAM_FLAG_TRIGGER_RAW %s "
1939  "stream->min_inspect_depth %u",
1940  respect_inspect_depth ? "true" : "false",
1941  (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) ? "true" : "false",
1942  stream->min_inspect_depth);
1943 
1944  if (respect_inspect_depth && (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) &&
1945  stream->min_inspect_depth) {
1946  progress = STREAM_APP_PROGRESS(stream);
1947  if (stream->min_inspect_depth >= progress) {
1948  progress = 0;
1949  } else {
1950  progress -= stream->min_inspect_depth;
1951  }
1952 
1953  SCLogDebug("stream app %" PRIu64 ", raw %" PRIu64, STREAM_APP_PROGRESS(stream),
1954  STREAM_RAW_PROGRESS(stream));
1955 
1956  progress = MIN(progress, STREAM_RAW_PROGRESS(stream));
1957  SCLogDebug("applied min inspect depth due to STREAMTCP_STREAM_FLAG_TRIGGER_RAW: progress "
1958  "%" PRIu64,
1959  progress);
1960  }
1961 
1962  SCLogDebug("progress %" PRIu64 ", min inspect depth %u %s", progress, stream->min_inspect_depth,
1963  stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW ? "STREAMTCP_STREAM_FLAG_TRIGGER_RAW"
1964  : "(no trigger)");
1965 
1966  /* absolute right edge of ack'd data */
1967  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1968  SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs);
1969 
1970  return StreamReassembleRawDo(ssn, stream, Callback, cb_data, progress, last_ack_abs,
1971  progress_out, (p->flags & PKT_PSEUDO_STREAM_END));
1972 }
1973 
1974 int StreamReassembleLog(const TcpSession *ssn, const TcpStream *stream,
1975  StreamReassembleRawFunc Callback, void *cb_data, const uint64_t progress_in,
1976  uint64_t *progress_out, const bool eof)
1977 {
1978  if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY))
1979  return 0;
1980 
1981  /* absolute right edge of ack'd data */
1982  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1983  SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs);
1984 
1985  return StreamReassembleRawDo(
1986  ssn, stream, Callback, cb_data, progress_in, last_ack_abs, progress_out, eof);
1987 }
1988 
1989 /** \internal
1990  * \brief update app layer based on received ACK
1991  *
1992  * \retval r 0 on success, -1 on error
1993  */
1994 static int StreamTcpReassembleHandleSegmentUpdateACK (ThreadVars *tv,
1995  TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p)
1996 {
1997  SCEnter();
1998 
1999  if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, UPDATE_DIR_OPPOSING) < 0)
2000  SCReturnInt(-1);
2001 
2002  SCReturnInt(0);
2003 }
2004 
2006  TcpSession *ssn, TcpStream *stream, Packet *p)
2007 {
2008  SCEnter();
2009 
2010  DEBUG_VALIDATE_BUG_ON(!PacketIsTCP(p));
2011  const TCPHdr *tcph = PacketGetTCP(p);
2012 
2013  SCLogDebug("ssn %p, stream %p, p %p, p->payload_len %"PRIu16"",
2014  ssn, stream, p, p->payload_len);
2015 
2016  /* default IDS: update opposing side (triggered by ACK) */
2018  /* inline and stream end and flow timeout packets trigger same dir handling */
2019  if (StreamTcpInlineMode()) {
2020  dir = UPDATE_DIR_PACKET;
2021  } else if (p->flags & PKT_PSEUDO_STREAM_END) {
2022  dir = UPDATE_DIR_PACKET;
2023  } else if (tcph->th_flags & TH_RST) { // accepted rst
2024  dir = UPDATE_DIR_PACKET;
2025  } else if ((tcph->th_flags & TH_FIN) && ssn->state > TCP_TIME_WAIT) {
2026  if (tcph->th_flags & TH_ACK) {
2027  dir = UPDATE_DIR_BOTH;
2028  } else {
2029  dir = UPDATE_DIR_PACKET;
2030  }
2031  } else if (ssn->state == TCP_CLOSED) {
2032  dir = UPDATE_DIR_BOTH;
2033  } else if ((ssn->flags & STREAMTCP_FLAG_ASYNC) != 0) {
2034  dir = UPDATE_DIR_PACKET;
2035  SCLogDebug("%" PRIu64 ": ASYNC: UPDATE_DIR_PACKET", PcapPacketCntGet(p));
2036  }
2037 
2038  /* handle ack received */
2039  if ((dir == UPDATE_DIR_OPPOSING || dir == UPDATE_DIR_BOTH)) {
2040  /* we need to update the opposing stream in
2041  * StreamTcpReassembleHandleSegmentUpdateACK */
2042  TcpStream *opposing_stream = NULL;
2043  if (stream == &ssn->client) {
2044  opposing_stream = &ssn->server;
2045  } else {
2046  opposing_stream = &ssn->client;
2047  }
2048 
2049  const bool reversed_before_ack_handling = (p->flow->flags & FLOW_DIR_REVERSED) != 0;
2050 
2051  if (StreamTcpReassembleHandleSegmentUpdateACK(tv, ra_ctx, ssn, opposing_stream, p) != 0) {
2052  SCLogDebug("StreamTcpReassembleHandleSegmentUpdateACK error");
2053  SCReturnInt(-1);
2054  }
2055 
2056  /* StreamTcpReassembleHandleSegmentUpdateACK
2057  * may swap content of ssn->server and ssn->client structures.
2058  * We have to continue with initial content of the stream in such case */
2059  const bool reversed_after_ack_handling = (p->flow->flags & FLOW_DIR_REVERSED) != 0;
2060  if (reversed_before_ack_handling != reversed_after_ack_handling) {
2061  SCLogDebug("TCP streams were swapped");
2062  stream = opposing_stream;
2063  }
2064  }
2065  /* if this segment contains data, insert it */
2066  if (p->payload_len > 0 && !(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) &&
2067  (tcph->th_flags & TH_RST) == 0) {
2068  SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData");
2069 
2070  if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) {
2071  SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error");
2072  /* failure can only be because of memcap hit, so see if this should lead to a drop */
2075  StreamTcpReassembleExceptionPolicyStatsIncr(
2077  SCReturnInt(-1);
2078  }
2079 
2080  SCLogDebug("packet %" PRIu64 " set PKT_STREAM_ADD", PcapPacketCntGet(p));
2081  p->flags |= PKT_STREAM_ADD;
2082  } else {
2083  SCLogDebug("ssn %p / stream %p: not calling StreamTcpReassembleHandleSegmentHandleData:"
2084  " p->payload_len %u, STREAMTCP_STREAM_FLAG_NOREASSEMBLY %s",
2085  ssn, stream, p->payload_len,
2086  (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ? "true" : "false");
2087  }
2088 
2089  /* if the STREAMTCP_STREAM_FLAG_DEPTH_REACHED is set, but not the
2090  * STREAMTCP_STREAM_FLAG_NOREASSEMBLY flag, it means the DEPTH flag
2091  * was *just* set. In this case we trigger the AppLayer Truncate
2092  * logic, to inform the applayer no more data in this direction is
2093  * to be expected. */
2094  if ((stream->flags &
2097  {
2098  SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED, truncate applayer");
2099  if (dir != UPDATE_DIR_PACKET) {
2100  SCLogDebug("override: direction now UPDATE_DIR_PACKET so we "
2101  "can trigger Truncate");
2102  dir = UPDATE_DIR_PACKET;
2103  }
2104  }
2105 
2106  /* in stream inline mode even if we have no data we call the reassembly
2107  * functions to handle EOF */
2108  if (dir == UPDATE_DIR_PACKET || dir == UPDATE_DIR_BOTH) {
2109  SCLogDebug("inline (%s) or PKT_PSEUDO_STREAM_END (%s)",
2110  StreamTcpInlineMode()?"true":"false",
2111  (p->flags & PKT_PSEUDO_STREAM_END) ?"true":"false");
2112  if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, dir) < 0) {
2113  SCReturnInt(-1);
2114  }
2115  }
2116 
2117  SCReturnInt(0);
2118 }
2119 
2120 /**
2121  * \brief get a segment from the pool
2122  *
2123  * \retval seg Segment from the pool or NULL
2124  */
2126 {
2128  if (seg) {
2130  memset(&seg->sbseg, 0, sizeof(seg->sbseg));
2131  return seg;
2132  }
2133 
2134  seg = (TcpSegment *)PoolThreadGetById(
2135  segment_thread_pool, (uint16_t)ra_ctx->segment_thread_pool_id);
2136  SCLogDebug("seg we return is %p", seg);
2137  if (seg == NULL) {
2138  /* Increment the counter to show that we are not able to serve the
2139  segment request due to memcap limit */
2141  } else {
2142  memset(&seg->sbseg, 0, sizeof(seg->sbseg));
2144  }
2145 
2146  return seg;
2147 }
2148 
2149 /**
2150  * \brief Trigger RAW stream inspection
2151  *
2152  * Used by AppLayerTriggerRawStreamInspection to trigger RAW stream
2153  * inspection from the applayer, for example upon completion of a
2154  * HTTP request.
2155  *
2156  * It sets a flag in the stream so that the next Raw call will return
2157  * the data.
2158  *
2159  * \param ssn TcpSession
2160  */
2162 {
2163 #ifdef DEBUG
2164  BUG_ON(ssn == NULL);
2165 #endif
2166 
2167  if (ssn != NULL) {
2168  if (direction == STREAM_TOSERVER) {
2170  } else {
2172  }
2173 
2174  SCLogDebug("flagged ssn %p for immediate raw reassembly", ssn);
2175  }
2176 }
2177 
2178 void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
2179 {
2180 #ifdef DEBUG
2181  BUG_ON(ssn == NULL);
2182 #endif
2183 
2184  if (ssn != NULL) {
2185  if (direction == STREAM_TOSERVER) {
2186  ssn->client.min_inspect_depth = depth;
2187  SCLogDebug("ssn %p: set client.min_inspect_depth to %u", ssn, depth);
2188  } else {
2189  ssn->server.min_inspect_depth = depth;
2190  SCLogDebug("ssn %p: set server.min_inspect_depth to %u", ssn, depth);
2191  }
2192  }
2193 }
2194 
2195 #ifdef UNITTESTS
2196 /** unit tests and it's support functions below */
2197 
2198 #define SET_ISN(stream, setseq) \
2199  (stream)->isn = (setseq); \
2200  (stream)->base_seq = (setseq) + 1
2201 
2202 /** \brief The Function to create the packet with given payload, which is used
2203  * to test the reassembly of the engine.
2204  *
2205  * \param payload The variable used to store the payload contents of the
2206  * current packet.
2207  * \param value The value which current payload will have for this packet
2208  * \param payload_len The length of the filed payload for current packet.
2209  * \param len Length of the payload array
2210  */
2211 
2212 void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value,
2213  uint8_t payload_len, uint8_t len)
2214 {
2215  uint8_t i;
2216  for (i = 0; i < payload_len; i++)
2217  payload[i] = value;
2218  for (; i < len; i++)
2219  payload = NULL;
2220 }
2221 
2222 /** \brief The Function Checks the reassembled stream contents against predefined
2223  * stream contents according to OS policy used.
2224  *
2225  * \param stream_policy Predefined value of stream for different OS policies
2226  * \param stream Reassembled stream returned from the reassembly functions
2227  */
2228 
2229 static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len)
2230 {
2231  if (StreamingBufferCompareRawData(&stream->sb,
2232  data, data_len) == 0)
2233  {
2234  SCReturnInt(0);
2235  }
2236  SCLogInfo("OK");
2237  PrintRawDataFp(stdout, data, data_len);
2238  return 1;
2239 }
2240 
2241 #define MISSED_START(isn) \
2242  TcpReassemblyThreadCtx *ra_ctx = NULL; \
2243  TcpSession ssn; \
2244  ThreadVars tv; \
2245  memset(&tv, 0, sizeof(tv)); \
2246  \
2247  StreamTcpUTInit(&ra_ctx); \
2248  \
2249  StreamTcpUTSetupSession(&ssn); \
2250  StreamTcpUTSetupStream(&ssn.server, (isn)); \
2251  StreamTcpUTSetupStream(&ssn.client, (isn)); \
2252  \
2253  TcpStream *stream = &ssn.client;
2254 
2255 #define MISSED_END \
2256  StreamTcpUTClearSession(&ssn); \
2257  StreamTcpUTDeinit(ra_ctx); \
2258  PASS
2259 
2260 #define MISSED_STEP(seq, seg, seglen, buf, buflen) \
2261  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen)); \
2262  FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen))));
2263 
2264 #define MISSED_ADD_PAYLOAD(seq, seg, seglen) \
2265  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen));
2266 
2267 int UTHCheckGapAtPosition(TcpStream *stream, int pos, uint64_t offset, uint32_t len);
2268 
2269 int UTHCheckGapAtPosition(TcpStream *stream, int pos, uint64_t offset, uint32_t len)
2270 {
2271  int cnt = 0;
2272  uint64_t last_re = 0;
2273  StreamingBufferBlock *sbb = NULL;
2274  RB_FOREACH(sbb, SBB, &stream->sb.sbb_tree)
2275  {
2276  if (sbb->offset != last_re) {
2277  // gap before us
2278  if (cnt == pos && last_re == offset && len == sbb->offset - last_re) {
2279  return 1;
2280  }
2281  cnt++;
2282  }
2283  last_re = sbb->offset + sbb->len;
2284  cnt++;
2285  }
2286  return 0;
2287 }
2288 
2290  TcpStream *stream, int pos, uint64_t offset, const char *data, uint32_t len);
2291 
2293  TcpStream *stream, int pos, uint64_t offset, const char *data, uint32_t len)
2294 {
2295  int cnt = 0;
2296  uint64_t last_re = 0;
2297  StreamingBufferBlock *sbb = NULL;
2298  RB_FOREACH(sbb, SBB, &stream->sb.sbb_tree)
2299  {
2300  if (sbb->offset != last_re) {
2301  // gap before us
2302  cnt++;
2303  }
2304 
2305  if (cnt == pos && sbb->offset == offset) {
2306  const uint8_t *buf = NULL;
2307  uint32_t buf_len = 0;
2308  StreamingBufferSBBGetData(&stream->sb, sbb, &buf, &buf_len);
2309 
2310  if (len == buf_len) {
2311  return (memcmp(data, buf, len) == 0);
2312  }
2313  }
2314 
2315  last_re = sbb->offset + sbb->len;
2316  cnt++;
2317  }
2318  return 0;
2319 }
2320 
2321 /**
2322  * \test Test the handling of packets missed by both IDS and the end host.
2323  * The packet is missed in the starting of the stream.
2324  *
2325  * \retval On success it returns 1 and on failure 0.
2326  */
2327 
2328 static int StreamTcpReassembleTest25 (void)
2329 {
2330  MISSED_START(6);
2331  MISSED_ADD_PAYLOAD(10, "BB", 2);
2332  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2333  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "BB", 2) == 1);
2334  MISSED_ADD_PAYLOAD(12, "CC", 2);
2335  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2336  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "BBCC", 4) == 1);
2337  MISSED_STEP(7, "AAA", 3, "AAABBCC", 7);
2338  MISSED_END;
2339  PASS;
2340 }
2341 
2342 /**
2343  * \test Test the handling of packets missed by both IDS and the end host.
2344  * The packet is missed in the middle of the stream.
2345  *
2346  * \retval On success it returns 1 and on failure 0.
2347  */
2348 
2349 static int StreamTcpReassembleTest26 (void)
2350 {
2351  MISSED_START(9);
2352  MISSED_STEP(10, "AAA", 3, "AAA", 3);
2353  MISSED_ADD_PAYLOAD(15, "CC", 2);
2354  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 0, 0, "AAA", 3) == 1);
2355  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 1, 3, 2) == 1);
2356  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 2, 5, "CC", 2) == 1);
2357  MISSED_STEP(13, "BB", 2, "AAABBCC", 7);
2358  MISSED_END;
2359 }
2360 
2361 /**
2362  * \test Test the handling of packets missed by both IDS and the end host.
2363  * The packet is missed in the end of the stream.
2364  *
2365  * \retval On success it returns 1 and on failure 0.
2366  */
2367 
2368 static int StreamTcpReassembleTest27 (void)
2369 {
2370  MISSED_START(9);
2371  MISSED_STEP(10, "AAA", 3, "AAA", 3);
2372  MISSED_STEP(13, "BB", 2, "AAABB", 5);
2373  MISSED_STEP(15, "CC", 2, "AAABBCC", 7);
2374  MISSED_END;
2375 }
2376 
2377 /**
2378  * \test Test the handling of packets missed by IDS, but the end host has
2379  * received it and send the acknowledgment of it. The packet is missed
2380  * in the starting of the stream.
2381  *
2382  * \retval On success it returns 1 and on failure 0.
2383  */
2384 
2385 static int StreamTcpReassembleTest28 (void)
2386 {
2387  MISSED_START(6);
2388  MISSED_ADD_PAYLOAD(10, "AAA", 3);
2389  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2390  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAA", 3) == 1);
2391  MISSED_ADD_PAYLOAD(13, "BB", 2);
2392  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2393  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAABB", 5) == 1);
2394  ssn.state = TCP_TIME_WAIT;
2395  MISSED_ADD_PAYLOAD(15, "CC", 2);
2396  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2397  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAABBCC", 7) == 1);
2398  MISSED_END;
2399 }
2400 
2401 /**
2402  * \test Test the handling of packets missed by IDS, but the end host has
2403  * received it and send the acknowledgment of it. The packet is missed
2404  * in the middle of the stream.
2405  *
2406  * \retval On success it returns 1 and on failure 0.
2407  */
2408 
2409 static int StreamTcpReassembleTest29 (void)
2410 {
2411  MISSED_START(9);
2412  MISSED_STEP(10, "AAA", 3, "AAA", 3);
2413  ssn.state = TCP_TIME_WAIT;
2414  MISSED_ADD_PAYLOAD(15, "CC", 2);
2415  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 0, 0, "AAA", 3) == 1);
2416  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 1, 3, 2) == 1);
2417  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 2, 5, "CC", 2) == 1);
2418  MISSED_END;
2419 }
2420 
2421 static int StreamTcpReassembleTest33(void)
2422 {
2423  TcpSession ssn;
2424  Packet *p = PacketGetFromAlloc();
2425  FAIL_IF(unlikely(p == NULL));
2426  Flow f;
2427  TCPHdr tcph;
2428  TcpReassemblyThreadCtx *ra_ctx = NULL;
2430  uint8_t packet[1460] = "";
2431 
2432  StreamTcpUTInit(&ra_ctx);
2434 
2435  memset(&f, 0, sizeof (Flow));
2436  memset(&tcph, 0, sizeof (TCPHdr));
2437  ThreadVars tv;
2438  memset(&tv, 0, sizeof (ThreadVars));
2439  FLOW_INITIALIZE(&f);
2440  f.protoctx = &ssn;
2441  f.proto = IPPROTO_TCP;
2442  p->src.family = AF_INET;
2443  p->dst.family = AF_INET;
2444  p->proto = IPPROTO_TCP;
2445  p->flow = &f;
2446  tcph.th_win = 5480;
2447  tcph.th_flags = TH_PUSH | TH_ACK;
2448  UTHSetTCPHdr(p, &tcph);
2450  p->payload = packet;
2451 
2452  tcph.th_seq = htonl(10);
2453  tcph.th_ack = htonl(31);
2454  p->payload_len = 10;
2455 
2456  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2457 
2458  tcph.th_seq = htonl(20);
2459  tcph.th_ack = htonl(31);
2460  p->payload_len = 10;
2461 
2462  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2463 
2464  tcph.th_seq = htonl(40);
2465  tcph.th_ack = htonl(31);
2466  p->payload_len = 10;
2467 
2468  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2469 
2470  tcph.th_seq = htonl(5);
2471  tcph.th_ack = htonl(31);
2472  p->payload_len = 30;
2473 
2474  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2475 
2477  FLOW_DESTROY(&f);
2478  PacketFree(p);
2479  StreamTcpUTDeinit(ra_ctx);
2480  PASS;
2481 }
2482 
2483 static int StreamTcpReassembleTest34(void)
2484 {
2485  TcpSession ssn;
2486  Packet *p = PacketGetFromAlloc();
2487  FAIL_IF(unlikely(p == NULL));
2488  Flow f;
2489  TCPHdr tcph;
2490  TcpReassemblyThreadCtx *ra_ctx = NULL;
2492  uint8_t packet[1460] = "";
2493 
2494  StreamTcpUTInit(&ra_ctx);
2496  memset(&f, 0, sizeof (Flow));
2497  memset(&tcph, 0, sizeof (TCPHdr));
2498  ThreadVars tv;
2499  memset(&tv, 0, sizeof (ThreadVars));
2500  FLOW_INITIALIZE(&f);
2501  f.protoctx = &ssn;
2502  f.proto = IPPROTO_TCP;
2503  p->src.family = AF_INET;
2504  p->dst.family = AF_INET;
2505  p->proto = IPPROTO_TCP;
2506  p->flow = &f;
2507  tcph.th_win = 5480;
2508  tcph.th_flags = TH_PUSH | TH_ACK;
2509  UTHSetTCPHdr(p, &tcph);
2511  p->payload = packet;
2512  SET_ISN(&ssn.client, 857961230);
2513 
2514  tcph.th_seq = htonl(857961230);
2515  tcph.th_ack = htonl(31);
2516  p->payload_len = 304;
2517 
2518  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2519 
2520  tcph.th_seq = htonl(857961534);
2521  tcph.th_ack = htonl(31);
2522  p->payload_len = 1460;
2523 
2524  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2525 
2526  tcph.th_seq = htonl(857963582);
2527  tcph.th_ack = htonl(31);
2528  p->payload_len = 1460;
2529 
2530  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2531 
2532  tcph.th_seq = htonl(857960946);
2533  tcph.th_ack = htonl(31);
2534  p->payload_len = 1460;
2535 
2536  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2537 
2539  FLOW_DESTROY(&f);
2540  StreamTcpUTDeinit(ra_ctx);
2541  PacketFree(p);
2542  PASS;
2543 }
2544 
2545 /**
2546  * \test Test to make sure that we don't return the segments until the app
2547  * layer proto has been detected and after that remove the processed
2548  * segments.
2549  *
2550  * \retval On success it returns 1 and on failure 0.
2551  */
2552 
2553 static int StreamTcpReassembleTest39 (void)
2554 {
2555  Packet *p = PacketGetFromAlloc();
2556  FAIL_IF(unlikely(p == NULL));
2557  Flow f;
2558  ThreadVars tv;
2559  StreamTcpThread stt;
2560  TCPHdr tcph;
2561  PacketQueueNoLock pq;
2562  memset(&pq,0,sizeof(PacketQueueNoLock));
2563  memset (&f, 0, sizeof(Flow));
2564  memset(&tv, 0, sizeof (ThreadVars));
2565  memset(&stt, 0, sizeof (stt));
2566  memset(&tcph, 0, sizeof (TCPHdr));
2567 
2568  FLOW_INITIALIZE(&f);
2569  f.flags = FLOW_IPV4;
2570  f.proto = IPPROTO_TCP;
2571  p->flow = &f;
2572  UTHSetTCPHdr(p, &tcph);
2573 
2574  StreamTcpUTInit(&stt.ra_ctx);
2575 
2576  /* handshake */
2577  tcph.th_win = htons(5480);
2578  tcph.th_flags = TH_SYN;
2580  p->payload_len = 0;
2581  p->payload = NULL;
2582  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2583 
2584  TcpSession *ssn = (TcpSession *)f.protoctx;
2585  FAIL_IF_NULL(ssn);
2586 
2593  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2594  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2595  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2596  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2599  FAIL_IF(ssn->data_first_seen_dir != 0);
2600 
2601  /* handshake */
2602  tcph.th_ack = htonl(1);
2603  tcph.th_flags = TH_SYN | TH_ACK;
2605  p->payload_len = 0;
2606  p->payload = NULL;
2607  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2614  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2615  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2616  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2617  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2620  FAIL_IF(ssn->data_first_seen_dir != 0);
2621 
2622  /* handshake */
2623  tcph.th_ack = htonl(1);
2624  tcph.th_seq = htonl(1);
2625  tcph.th_flags = TH_ACK;
2627  p->payload_len = 0;
2628  p->payload = NULL;
2629  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2636  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2637  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2638  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2639  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2642  FAIL_IF(ssn->data_first_seen_dir != 0);
2643 
2644  /* partial request */
2645  uint8_t request1[] = { 0x47, 0x45, };
2646  tcph.th_ack = htonl(1);
2647  tcph.th_seq = htonl(1);
2648  tcph.th_flags = TH_PUSH | TH_ACK;
2650  p->payload_len = sizeof(request1);
2651  p->payload = request1;
2652  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2659  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2660  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2661  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2662  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2663  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2664  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2666  FAIL_IF_NOT(ssn->data_first_seen_dir == STREAM_TOSERVER);
2667 
2668  /* response ack against partial request */
2669  tcph.th_ack = htonl(3);
2670  tcph.th_seq = htonl(1);
2671  tcph.th_flags = TH_ACK;
2673  p->payload_len = 0;
2674  p->payload = NULL;
2675  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2682  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2683  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2684  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2685  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2686  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2687  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2689  FAIL_IF_NOT(ssn->data_first_seen_dir == STREAM_TOSERVER);
2690 
2691  /* complete partial request */
2692  uint8_t request2[] = {
2693  0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64,
2694  0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20,
2695  0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30,
2696  0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20,
2697  0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73,
2698  0x74, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d,
2699  0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x41,
2700  0x70, 0x61, 0x63, 0x68, 0x65, 0x42, 0x65, 0x6e,
2701  0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a,
2702  0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20,
2703  0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a };
2704  tcph.th_ack = htonl(1);
2705  tcph.th_seq = htonl(3);
2706  tcph.th_flags = TH_PUSH | TH_ACK;
2708  p->payload_len = sizeof(request2);
2709  p->payload = request2;
2710  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2717  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2718  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2719  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2720  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2721  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2722  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2723  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2725  FAIL_IF_NOT(ssn->data_first_seen_dir == STREAM_TOSERVER);
2726 
2727  /* response - request ack */
2728  uint8_t response[] = {
2729  0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31,
2730  0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d,
2731  0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x46,
2732  0x72, 0x69, 0x2c, 0x20, 0x32, 0x33, 0x20, 0x53,
2733  0x65, 0x70, 0x20, 0x32, 0x30, 0x31, 0x31, 0x20,
2734  0x30, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x39,
2735  0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65,
2736  0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x41, 0x70,
2737  0x61, 0x63, 0x68, 0x65, 0x2f, 0x32, 0x2e, 0x32,
2738  0x2e, 0x31, 0x35, 0x20, 0x28, 0x55, 0x6e, 0x69,
2739  0x78, 0x29, 0x20, 0x44, 0x41, 0x56, 0x2f, 0x32,
2740  0x0d, 0x0a, 0x4c, 0x61, 0x73, 0x74, 0x2d, 0x4d,
2741  0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x3a,
2742  0x20, 0x54, 0x68, 0x75, 0x2c, 0x20, 0x30, 0x34,
2743  0x20, 0x4e, 0x6f, 0x76, 0x20, 0x32, 0x30, 0x31,
2744  0x30, 0x20, 0x31, 0x35, 0x3a, 0x30, 0x34, 0x3a,
2745  0x34, 0x36, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a,
2746  0x45, 0x54, 0x61, 0x67, 0x3a, 0x20, 0x22, 0x61,
2747  0x62, 0x38, 0x39, 0x36, 0x35, 0x2d, 0x32, 0x63,
2748  0x2d, 0x34, 0x39, 0x34, 0x33, 0x62, 0x37, 0x61,
2749  0x37, 0x66, 0x37, 0x66, 0x38, 0x30, 0x22, 0x0d,
2750  0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d,
2751  0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x3a, 0x20,
2752  0x62, 0x79, 0x74, 0x65, 0x73, 0x0d, 0x0a, 0x43,
2753  0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c,
2754  0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x34,
2755  0x34, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
2756  0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63,
2757  0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, 0x43, 0x6f,
2758  0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79,
2759  0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74,
2760  0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x58,
2761  0x2d, 0x50, 0x61, 0x64, 0x3a, 0x20, 0x61, 0x76,
2762  0x6f, 0x69, 0x64, 0x20, 0x62, 0x72, 0x6f, 0x77,
2763  0x73, 0x65, 0x72, 0x20, 0x62, 0x75, 0x67, 0x0d,
2764  0x0a, 0x0d, 0x0a, 0x3c, 0x68, 0x74, 0x6d, 0x6c,
2765  0x3e, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c,
2766  0x68, 0x31, 0x3e, 0x49, 0x74, 0x20, 0x77, 0x6f,
2767  0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31,
2768  0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e,
2769  0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e };
2770  tcph.th_ack = htonl(88);
2771  tcph.th_seq = htonl(1);
2772  tcph.th_flags = TH_PUSH | TH_ACK;
2774  p->payload_len = sizeof(response);
2775  p->payload = response;
2776 
2777  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2784  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2785  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2786  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2787  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2789  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2790  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2791  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2792  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2793 
2794  /* response ack from request */
2795  tcph.th_ack = htonl(328);
2796  tcph.th_seq = htonl(88);
2797  tcph.th_flags = TH_ACK;
2799  p->payload_len = 0;
2800  p->payload = NULL;
2801  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2808  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2809  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2810  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2811  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2813  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2814  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2815  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2816  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2817  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2818 
2819  /* response - acking */
2820  tcph.th_ack = htonl(88);
2821  tcph.th_seq = htonl(328);
2822  tcph.th_flags = TH_PUSH | TH_ACK;
2824  p->payload_len = 0;
2825  p->payload = NULL;
2826  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2833  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2834  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2835  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2836  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2838  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2839  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2840  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2841  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2842  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2843 
2844  /* response ack from request */
2845  tcph.th_ack = htonl(328);
2846  tcph.th_seq = htonl(88);
2847  tcph.th_flags = TH_ACK;
2849  p->payload_len = 0;
2850  p->payload = NULL;
2851  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2858  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2859  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2860  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2861  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2863  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2864  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2865  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2866  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2867 
2868  /* response - acking the request again*/
2869  tcph.th_ack = htonl(88);
2870  tcph.th_seq = htonl(328);
2871  tcph.th_flags = TH_PUSH | TH_ACK;
2873  p->payload_len = 0;
2874  p->payload = NULL;
2875  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2882  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2883  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2884  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2885  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2887  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2888  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2889  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2890  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2891 
2892  /*** New Request ***/
2893 
2894  /* partial request */
2895  tcph.th_ack = htonl(328);
2896  tcph.th_seq = htonl(88);
2897  tcph.th_flags = TH_PUSH | TH_ACK;
2899  p->payload_len = sizeof(request1);
2900  p->payload = request1;
2901  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2908  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2909  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2910  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2911  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2913  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2914  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2915  FAIL_IF_NOT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2916  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2917  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2918 
2919  /* response ack against partial request */
2920  tcph.th_ack = htonl(90);
2921  tcph.th_seq = htonl(328);
2922  tcph.th_flags = TH_ACK;
2924  p->payload_len = 0;
2925  p->payload = NULL;
2926  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2927  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2934  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2935  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2936  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2937  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2939  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2940  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2941  FAIL_IF_NOT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2942  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2943  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2944 
2945  /* complete request */
2946  tcph.th_ack = htonl(328);
2947  tcph.th_seq = htonl(90);
2948  tcph.th_flags = TH_PUSH | TH_ACK;
2950  p->payload_len = sizeof(request2);
2951  p->payload = request2;
2952  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2959  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2960  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2961  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2962  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2964  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2965  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2966  FAIL_IF_NOT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2967  FAIL_IF_NOT(
2968  TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
2969  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2970  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2971 
2972  /* response ack against second partial request */
2973  tcph.th_ack = htonl(175);
2974  tcph.th_seq = htonl(328);
2975  tcph.th_flags = TH_ACK;
2977  p->payload_len = 0;
2978  p->payload = NULL;
2979 
2980  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2987  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2988  FAIL_IF_NOT(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2989  FAIL_IF_NOT(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2990  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2992  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2993  FAIL_IF_NOT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2994  FAIL_IF_NOT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2995  FAIL_IF_NOT(
2996  TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
2997  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2998  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2999 
3000  /* response acking a request */
3001  tcph.th_ack = htonl(175);
3002  tcph.th_seq = htonl(328);
3003  tcph.th_flags = TH_ACK;
3005  p->payload_len = 0;
3006  p->payload = NULL;
3007  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
3013 
3014  StreamTcpPruneSession(&f, STREAM_TOSERVER);
3015  StreamTcpPruneSession(&f, STREAM_TOCLIENT);
3016 
3017  /* request acking a response */
3018  tcph.th_ack = htonl(328);
3019  tcph.th_seq = htonl(175);
3020  tcph.th_flags = TH_ACK;
3022  p->payload_len = 0;
3023  p->payload = NULL;
3024  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
3025 
3026  PacketFree(p);
3027  StreamTcpSessionClear(ssn);
3028  FLOW_DESTROY(&f);
3030  PASS;
3031 }
3032 
3033 /**
3034  * \test Test to make sure that we sent all the segments from the initial
3035  * segments to app layer until we have detected the app layer proto.
3036  *
3037  * \retval On success it returns 1 and on failure 0.
3038  */
3039 
3040 static int StreamTcpReassembleTest40 (void)
3041 {
3042  Packet *p = PacketGetFromAlloc();
3043  FAIL_IF_NULL(p);
3044  Flow *f = NULL;
3045  TCPHdr tcph;
3046  TcpSession ssn;
3047  memset(&tcph, 0, sizeof (TCPHdr));
3048  ThreadVars tv;
3049  memset(&tv, 0, sizeof (ThreadVars));
3050 
3051  StreamTcpInitConfig(true);
3053 
3055  FAIL_IF_NULL(ra_ctx);
3056 
3057  uint8_t httpbuf1[] = "P";
3058  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3059  uint8_t httpbuf3[] = "O";
3060  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
3061  uint8_t httpbuf4[] = "S";
3062  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
3063  uint8_t httpbuf5[] = "T \r\n";
3064  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
3065 
3066  uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
3067  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3068 
3069  SET_ISN(&ssn.server, 9);
3070  ssn.server.last_ack = 10;
3071  SET_ISN(&ssn.client, 9);
3072  ssn.client.isn = 9;
3073 
3074  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
3075  FAIL_IF_NULL(f);
3076  f->protoctx = &ssn;
3077  f->proto = IPPROTO_TCP;
3078  p->flow = f;
3079 
3080  tcph.th_win = htons(5480);
3081  tcph.th_seq = htonl(10);
3082  tcph.th_ack = htonl(10);
3083  tcph.th_flags = TH_ACK|TH_PUSH;
3084  UTHSetTCPHdr(p, &tcph);
3086  p->payload = httpbuf1;
3087  p->payload_len = httplen1;
3088  ssn.state = TCP_ESTABLISHED;
3089  TcpStream *s = &ssn.client;
3090  SCLogDebug("1 -- start");
3091  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3092 
3094  p->payload = httpbuf2;
3095  p->payload_len = httplen2;
3096  tcph.th_seq = htonl(10);
3097  tcph.th_ack = htonl(11);
3098  s = &ssn.server;
3099  ssn.server.last_ack = 11;
3100  SCLogDebug("2 -- start");
3101  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3102 
3104  p->payload = httpbuf3;
3105  p->payload_len = httplen3;
3106  tcph.th_seq = htonl(11);
3107  tcph.th_ack = htonl(55);
3108  s = &ssn.client;
3109  ssn.client.last_ack = 55;
3110  SCLogDebug("3 -- start");
3111  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3112 
3114  p->payload = httpbuf2;
3115  p->payload_len = httplen2;
3116  tcph.th_seq = htonl(55);
3117  tcph.th_ack = htonl(12);
3118  s = &ssn.server;
3119  ssn.server.last_ack = 12;
3120  SCLogDebug("4 -- start");
3121  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3122 
3123  /* check is have the segment in the list and flagged or not */
3124  TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3125  FAIL_IF_NULL(seg);
3126  FAIL_IF(SEGMENT_BEFORE_OFFSET(&ssn.client, seg, STREAM_APP_PROGRESS(&ssn.client)));
3127 
3129  p->payload = httpbuf4;
3130  p->payload_len = httplen4;
3131  tcph.th_seq = htonl(12);
3132  tcph.th_ack = htonl(100);
3133  s = &ssn.client;
3134  ssn.client.last_ack = 100;
3135  SCLogDebug("5 -- start");
3136  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3137 
3139  p->payload = httpbuf2;
3140  p->payload_len = httplen2;
3141  tcph.th_seq = htonl(100);
3142  tcph.th_ack = htonl(13);
3143  s = &ssn.server;
3144  ssn.server.last_ack = 13;
3145  SCLogDebug("6 -- start");
3146  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3147 
3149  p->payload = httpbuf5;
3150  p->payload_len = httplen5;
3151  tcph.th_seq = htonl(13);
3152  tcph.th_ack = htonl(145);
3153  s = &ssn.client;
3154  ssn.client.last_ack = 145;
3155  SCLogDebug("7 -- start");
3156  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3157 
3159  p->payload = httpbuf2;
3160  p->payload_len = httplen2;
3161  tcph.th_seq = htonl(145);
3162  tcph.th_ack = htonl(16);
3163  s = &ssn.server;
3164  ssn.server.last_ack = 16;
3165  SCLogDebug("8 -- start");
3166  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3168 
3170  PacketFree(p);
3171  UTHFreeFlow(f);
3173  StreamTcpFreeConfig(true);
3174  PASS;
3175 }
3176 
3177 /** \test Test the memcap incrementing/decrementing and memcap check */
3178 static int StreamTcpReassembleTest44(void)
3179 {
3180  StreamTcpInitConfig(true);
3181  uint32_t memuse = SC_ATOMIC_GET(ra_memuse);
3182  StreamTcpReassembleIncrMemuse(500);
3183  FAIL_IF_NOT(SC_ATOMIC_GET(ra_memuse) == (memuse + 500));
3184  StreamTcpReassembleDecrMemuse(500);
3185  FAIL_IF_NOT(SC_ATOMIC_GET(ra_memuse) == memuse);
3188  (1 + memuse + SC_ATOMIC_GET(stream_config.reassembly_memcap))) == 0);
3189  StreamTcpFreeConfig(true);
3190  FAIL_IF_NOT(SC_ATOMIC_GET(ra_memuse) == 0);
3191  PASS;
3192 }
3193 
3194 /**
3195  * \test Test to make sure that reassembly_depth is enforced.
3196  *
3197  * \retval On success it returns 1 and on failure 0.
3198  */
3199 
3200 static int StreamTcpReassembleTest45 (void)
3201 {
3202  TcpReassemblyThreadCtx *ra_ctx = NULL;
3203  TcpSession ssn;
3204  ThreadVars tv;
3205  memset(&tv, 0, sizeof(tv));
3206  uint8_t payload[100] = {0};
3207  uint16_t payload_size = 100;
3208 
3209  StreamTcpUTInit(&ra_ctx);
3211 
3213  ssn.reassembly_depth = 100;
3214  StreamTcpUTSetupStream(&ssn.server, 100);
3215  StreamTcpUTSetupStream(&ssn.client, 100);
3216 
3217  FAIL_IF_NOT(
3218  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size) == 0);
3220 
3221  FAIL_IF_NOT(
3222  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size) == 0);
3224 
3228  StreamTcpUTDeinit(ra_ctx);
3229  PASS;
3230 }
3231 
3232 /**
3233  * \test Test the unlimited config value of reassembly depth.
3234  *
3235  * \retval On success it returns 1 and on failure 0.
3236  */
3237 
3238 static int StreamTcpReassembleTest46 (void)
3239 {
3240  TcpReassemblyThreadCtx *ra_ctx = NULL;
3241  TcpSession ssn;
3242  ThreadVars tv;
3243  memset(&tv, 0, sizeof(tv));
3244  uint8_t payload[100] = {0};
3245  uint16_t payload_size = 100;
3246 
3247  StreamTcpUTInit(&ra_ctx);
3249 
3251  StreamTcpUTSetupStream(&ssn.server, 100);
3252  StreamTcpUTSetupStream(&ssn.client, 100);
3253 
3254  FAIL_IF_NOT(
3255  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size) == 0);
3257 
3258  FAIL_IF_NOT(
3259  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size) == 0);
3261 
3265  StreamTcpUTDeinit(ra_ctx);
3266  PASS;
3267 }
3268 
3269 /**
3270  * \test Test to make sure we detect the sequence wrap around and continue
3271  * stream reassembly properly.
3272  *
3273  * \retval On success it returns 1 and on failure 0.
3274  */
3275 
3276 static int StreamTcpReassembleTest47 (void)
3277 {
3278  Packet *p = PacketGetFromAlloc();
3279  FAIL_IF(unlikely(p == NULL));
3280  Flow *f = NULL;
3281  TCPHdr tcph;
3282  TcpSession ssn;
3283  ThreadVars tv;
3284  memset(&tcph, 0, sizeof (TCPHdr));
3285  UTHSetTCPHdr(p, &tcph);
3286  memset(&tv, 0, sizeof (ThreadVars));
3287  StreamTcpInitConfig(true);
3290 
3291  uint8_t httpbuf1[] = "GET /EVILSUFF HTTP/1.1\r\n\r\n";
3292  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3293 
3294  SET_ISN(&ssn.server, 572799781UL);
3295  ssn.server.last_ack = 572799782UL;
3296 
3297  SET_ISN(&ssn.client, 4294967289UL);
3298  ssn.client.last_ack = 21;
3299 
3300  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
3301  FAIL_IF_NULL(f);
3302  f->protoctx = &ssn;
3303  f->proto = IPPROTO_TCP;
3304  p->flow = f;
3305 
3306  tcph.th_win = htons(5480);
3307  ssn.state = TCP_ESTABLISHED;
3308  TcpStream *s = NULL;
3309  uint8_t cnt = 0;
3310 
3311  for (cnt=0; cnt < httplen1; cnt++) {
3312  tcph.th_seq = htonl(ssn.client.isn + 1 + cnt);
3313  tcph.th_ack = htonl(572799782UL);
3314  tcph.th_flags = TH_ACK | TH_PUSH;
3316  p->payload = &httpbuf1[cnt];
3317  p->payload_len = 1;
3318  s = &ssn.client;
3319 
3320  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3321 
3323  p->payload = NULL;
3324  p->payload_len = 0;
3325  tcph.th_seq = htonl(572799782UL);
3326  tcph.th_ack = htonl(ssn.client.isn + 1 + cnt);
3327  tcph.th_flags = TH_ACK;
3328  s = &ssn.server;
3329 
3330  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3331  }
3332 
3333  FAIL_IF(f->alproto != ALPROTO_HTTP1);
3334 
3336  PacketFree(p);
3337  UTHFreeFlow(f);
3339  StreamTcpFreeConfig(true);
3340  PASS;
3341 }
3342 
3343 /** \test 3 in order segments in inline reassembly */
3344 static int StreamTcpReassembleInlineTest01(void)
3345 {
3346  TcpReassemblyThreadCtx *ra_ctx = NULL;
3347  ThreadVars tv;
3348  TcpSession ssn;
3349  Flow f;
3350 
3351  memset(&tv, 0x00, sizeof(tv));
3352 
3353  StreamTcpUTInit(&ra_ctx);
3356  StreamTcpUTSetupStream(&ssn.client, 1);
3357  FLOW_INITIALIZE(&f);
3358 
3359  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3360  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3361  FAIL_IF_NULL(p);
3362  p->l4.hdrs.tcph->th_seq = htonl(12);
3363  p->flow = &f;
3364 
3365  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3366  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3367  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3368  ssn.client.next_seq = 17;
3369  FLOW_DESTROY(&f);
3370  UTHFreePacket(p);
3372  StreamTcpUTDeinit(ra_ctx);
3373  PASS;
3374 }
3375 
3376 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3377  * test the sliding window reassembly.
3378  */
3379 static int StreamTcpReassembleInlineTest02(void)
3380 {
3381  TcpReassemblyThreadCtx *ra_ctx = NULL;
3382  ThreadVars tv;
3383  TcpSession ssn;
3384  Flow f;
3385 
3386  memset(&tv, 0x00, sizeof(tv));
3387 
3388  StreamTcpUTInit(&ra_ctx);
3391  StreamTcpUTSetupStream(&ssn.client, 1);
3392  FLOW_INITIALIZE(&f);
3393 
3394  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3395  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3396  FAIL_IF_NULL(p);
3397  p->l4.hdrs.tcph->th_seq = htonl(12);
3398  p->flow = &f;
3399 
3400  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3401  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3402  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3403  ssn.client.next_seq = 17;
3404  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3405  ssn.client.next_seq = 22;
3406  FLOW_DESTROY(&f);
3407  UTHFreePacket(p);
3409  StreamTcpUTDeinit(ra_ctx);
3410  PASS;
3411 }
3412 
3413 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3414  * test the sliding window reassembly with a small window size so that we
3415  * cutting off at the start (left edge)
3416  */
3417 static int StreamTcpReassembleInlineTest03(void)
3418 {
3419  TcpReassemblyThreadCtx *ra_ctx = NULL;
3420  ThreadVars tv;
3421  TcpSession ssn;
3422  Flow f;
3423 
3424  memset(&tv, 0x00, sizeof(tv));
3425 
3426  StreamTcpUTInit(&ra_ctx);
3429  StreamTcpUTSetupStream(&ssn.client, 1);
3430  FLOW_INITIALIZE(&f);
3431 
3433 
3434  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3435  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3436  FAIL_IF_NULL(p);
3437  p->l4.hdrs.tcph->th_seq = htonl(12);
3438  p->flow = &f;
3440 
3441  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3442  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3443  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3444  ssn.client.next_seq = 17;
3445  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3446  ssn.client.next_seq = 22;
3447 
3448  p->l4.hdrs.tcph->th_seq = htonl(17);
3449  FLOW_DESTROY(&f);
3450  UTHFreePacket(p);
3452  StreamTcpUTDeinit(ra_ctx);
3453  PASS;
3454 }
3455 
3456 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3457  * test the sliding window reassembly with a small window size so that we
3458  * cutting off at the start (left edge) with small packet overlap.
3459  */
3460 static int StreamTcpReassembleInlineTest04(void)
3461 {
3462  TcpReassemblyThreadCtx *ra_ctx = NULL;
3463  ThreadVars tv;
3464  TcpSession ssn;
3465  Flow f;
3466 
3467  memset(&tv, 0x00, sizeof(tv));
3468 
3469  StreamTcpUTInit(&ra_ctx);
3472  StreamTcpUTSetupStream(&ssn.client, 1);
3473  FLOW_INITIALIZE(&f);
3474 
3476 
3477  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3478  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3479  FAIL_IF_NULL(p);
3480  p->l4.hdrs.tcph->th_seq = htonl(12);
3481  p->flow = &f;
3483 
3484  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3485  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3486  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3487  ssn.client.next_seq = 17;
3488  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3489  ssn.client.next_seq = 22;
3490 
3491  p->l4.hdrs.tcph->th_seq = htonl(17);
3492  FLOW_DESTROY(&f);
3493  UTHFreePacket(p);
3495  StreamTcpUTDeinit(ra_ctx);
3496  PASS;
3497 }
3498 
3499 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3500  * test the sliding window reassembly with a small window size so that we
3501  * cutting off at the start (left edge). Test if the first segment is
3502  * removed from the list.
3503  */
3504 static int StreamTcpReassembleInlineTest08(void)
3505 {
3506  TcpReassemblyThreadCtx *ra_ctx = NULL;
3507  ThreadVars tv;
3508  memset(&tv, 0x00, sizeof(tv));
3509  TcpSession ssn;
3510  Flow f;
3511  StreamTcpUTInit(&ra_ctx);
3514  StreamTcpUTSetupStream(&ssn.client, 1);
3515  FLOW_INITIALIZE(&f);
3516 
3518  f.protoctx = &ssn;
3519 
3520  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3521  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3522  FAIL_IF_NULL(p);
3523  p->l4.hdrs.tcph->th_seq = htonl(12);
3524  p->flow = &f;
3526 
3527  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3528  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3529  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3530  ssn.client.next_seq = 17;
3531  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3532  ssn.client.next_seq = 22;
3533  p->l4.hdrs.tcph->th_seq = htonl(17);
3534  StreamTcpPruneSession(&f, STREAM_TOSERVER);
3535 
3536  TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3537  FAIL_IF_NULL(seg);
3538  FAIL_IF_NOT(seg->seq == 2);
3539 
3540  FLOW_DESTROY(&f);
3541  UTHFreePacket(p);
3543  StreamTcpUTDeinit(ra_ctx);
3544  PASS;
3545 }
3546 
3547 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3548  * test the sliding window reassembly with a small window size so that we
3549  * cutting off at the start (left edge). Test if the first segment is
3550  * removed from the list.
3551  */
3552 static int StreamTcpReassembleInlineTest09(void)
3553 {
3554  TcpReassemblyThreadCtx *ra_ctx = NULL;
3555  ThreadVars tv;
3556  TcpSession ssn;
3557  Flow f;
3558 
3559  memset(&tv, 0x00, sizeof(tv));
3560 
3561  StreamTcpUTInit(&ra_ctx);
3564  StreamTcpUTSetupStream(&ssn.client, 1);
3565  FLOW_INITIALIZE(&f);
3566 
3568 
3569  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3570  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3571  FAIL_IF_NULL(p);
3572  p->l4.hdrs.tcph->th_seq = htonl(17);
3573  p->flow = &f;
3575 
3576  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3577  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3578  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3579  ssn.client.next_seq = 12;
3580  ssn.client.last_ack = 10;
3581 
3582  /* close the GAP and see if we properly reassemble and update base_seq */
3583  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3584  ssn.client.next_seq = 22;
3585 
3586  p->l4.hdrs.tcph->th_seq = htonl(12);
3587 
3588  TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3589  FAIL_IF_NULL(seg);
3590  FAIL_IF_NOT(seg->seq == 2);
3591 
3592  FLOW_DESTROY(&f);
3593  UTHFreePacket(p);
3595  StreamTcpUTDeinit(ra_ctx);
3596  PASS;
3597 }
3598 
3599 /** \test App Layer reassembly.
3600  */
3601 static int StreamTcpReassembleInlineTest10(void)
3602 {
3603  TcpReassemblyThreadCtx *ra_ctx = NULL;
3604  ThreadVars tv;
3605  TcpSession ssn;
3606  Packet *p = NULL;
3607 
3608  memset(&tv, 0x00, sizeof(tv));
3609 
3610  StreamTcpUTInit(&ra_ctx);
3613  StreamTcpUTSetupStream(&ssn.server, 1);
3614  ssn.server.last_ack = 2;
3615  StreamTcpUTSetupStream(&ssn.client, 1);
3616  ssn.client.last_ack = 2;
3617  ssn.data_first_seen_dir = STREAM_TOSERVER;
3618 
3619  Flow *f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
3620  FAIL_IF_NULL(f);
3621  f->protoctx = &ssn;
3622  f->proto = IPPROTO_TCP;
3623 
3624  uint8_t stream_payload1[] = "GE";
3625  uint8_t stream_payload2[] = "T /";
3626  uint8_t stream_payload3[] = "HTTP/1.0\r\n\r\n";
3627 
3628  p = UTHBuildPacketReal(stream_payload3, 12, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3629  FAIL_IF_NULL(p);
3630  p->l4.hdrs.tcph->th_seq = htonl(7);
3631  p->flow = f;
3633 
3634  FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 2, stream_payload1, 2) ==
3635  -1);
3636  ssn.client.next_seq = 4;
3637 
3638  FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
3639 
3640  /* ssn.server.ra_app_base_seq should be isn here. */
3641  FAIL_IF_NOT(ssn.client.base_seq == 2 && ssn.client.base_seq == ssn.client.isn + 1);
3642 
3643  FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 4, stream_payload2, 3) ==
3644  -1);
3645  FAIL_IF(StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 7, stream_payload3, 12) ==
3646  -1);
3647  ssn.client.next_seq = 19;
3648 
3649  FAIL_IF(StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET) < 0);
3650 
3651  FAIL_IF_NOT(STREAM_APP_PROGRESS(&ssn.client) == 17);
3652 
3653  UTHFreePacket(p);
3655  StreamTcpUTDeinit(ra_ctx);
3656  UTHFreeFlow(f);
3657  PASS;
3658 }
3659 
3660 /** \test test insert with overlap
3661  */
3662 static int StreamTcpReassembleInsertTest01(void)
3663 {
3664  TcpReassemblyThreadCtx *ra_ctx = NULL;
3665  ThreadVars tv;
3666  TcpSession ssn;
3667  Flow f;
3668 
3669  memset(&tv, 0x00, sizeof(tv));
3670 
3671  StreamTcpUTInit(&ra_ctx);
3673  StreamTcpUTSetupStream(&ssn.client, 1);
3675  FLOW_INITIALIZE(&f);
3676 
3677  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3678  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3679  FAIL_IF_NULL(p);
3680  p->l4.hdrs.tcph->th_seq = htonl(12);
3681  p->flow = &f;
3682 
3683  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3684  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3685  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 14, 'D', 2) == -1);
3686  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 16, 'D', 6) == -1);
3687  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3688  ssn.client.next_seq = 21;
3689 
3690  FLOW_DESTROY(&f);
3691  UTHFreePacket(p);
3693  StreamTcpUTDeinit(ra_ctx);
3694  PASS;
3695 }
3696 
3697 /** \test test insert with overlaps
3698  */
3699 static int StreamTcpReassembleInsertTest02(void)
3700 {
3701  TcpReassemblyThreadCtx *ra_ctx = NULL;
3702  ThreadVars tv;
3703  TcpSession ssn;
3704 
3705  memset(&tv, 0x00, sizeof(tv));
3706 
3707  StreamTcpUTInit(&ra_ctx);
3709  StreamTcpUTSetupStream(&ssn.client, 1);
3710 
3711  int i;
3712  for (i = 2; i < 10; i++) {
3713  int len;
3714  len = i % 2;
3715  if (len == 0)
3716  len = 1;
3717  int seq;
3718  seq = i * 10;
3719  if (seq < 2)
3720  seq = 2;
3721 
3722  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'A', len) == -1);
3723  }
3724  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'B', 1024) == -1);
3725 
3727  StreamTcpUTDeinit(ra_ctx);
3728  PASS;
3729 }
3730 
3731 /** \test test insert with overlaps
3732  */
3733 static int StreamTcpReassembleInsertTest03(void)
3734 {
3735  TcpReassemblyThreadCtx *ra_ctx = NULL;
3736  ThreadVars tv;
3737  TcpSession ssn;
3738 
3739  memset(&tv, 0x00, sizeof(tv));
3740 
3741  StreamTcpUTInit(&ra_ctx);
3743  StreamTcpUTSetupStream(&ssn.client, 1);
3744 
3745  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 1024) == -1);
3746 
3747  int i;
3748  for (i = 2; i < 10; i++) {
3749  int len;
3750  len = i % 2;
3751  if (len == 0)
3752  len = 1;
3753  int seq;
3754  seq = i * 10;
3755  if (seq < 2)
3756  seq = 2;
3757 
3758  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'B', len) == -1);
3759  }
3761  StreamTcpUTDeinit(ra_ctx);
3762  PASS;
3763 }
3764 
3766 #endif /* UNITTESTS */
3767 
3768 /** \brief The Function Register the Unit tests to test the reassembly engine
3769  * for various OS policies.
3770  */
3771 
3773 {
3774 #ifdef UNITTESTS
3775  UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test",
3776  StreamTcpReassembleTest25);
3777  UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test",
3778  StreamTcpReassembleTest26);
3780  "StreamTcpReassembleTest27 -- Gap at after Reassembly Test", StreamTcpReassembleTest27);
3781  UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test",
3782  StreamTcpReassembleTest28);
3783  UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test",
3784  StreamTcpReassembleTest29);
3785  UtRegisterTest("StreamTcpReassembleTest33 -- Bug test",
3786  StreamTcpReassembleTest33);
3787  UtRegisterTest("StreamTcpReassembleTest34 -- Bug test",
3788  StreamTcpReassembleTest34);
3789  UtRegisterTest("StreamTcpReassembleTest39 -- app proto test",
3790  StreamTcpReassembleTest39);
3791  UtRegisterTest("StreamTcpReassembleTest40 -- app proto test",
3792  StreamTcpReassembleTest40);
3793  UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test",
3794  StreamTcpReassembleTest44);
3795  UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test",
3796  StreamTcpReassembleTest45);
3797  UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test",
3798  StreamTcpReassembleTest46);
3799  UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test",
3800  StreamTcpReassembleTest47);
3801 
3802  UtRegisterTest("StreamTcpReassembleInlineTest01 -- inline RAW ra",
3803  StreamTcpReassembleInlineTest01);
3804  UtRegisterTest("StreamTcpReassembleInlineTest02 -- inline RAW ra 2",
3805  StreamTcpReassembleInlineTest02);
3806  UtRegisterTest("StreamTcpReassembleInlineTest03 -- inline RAW ra 3",
3807  StreamTcpReassembleInlineTest03);
3808  UtRegisterTest("StreamTcpReassembleInlineTest04 -- inline RAW ra 4",
3809  StreamTcpReassembleInlineTest04);
3810  UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup",
3811  StreamTcpReassembleInlineTest08);
3812  UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup",
3813  StreamTcpReassembleInlineTest09);
3814 
3815  UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10",
3816  StreamTcpReassembleInlineTest10);
3817 
3818  UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap",
3819  StreamTcpReassembleInsertTest01);
3820  UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap",
3821  StreamTcpReassembleInsertTest02);
3822  UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap",
3823  StreamTcpReassembleInsertTest03);
3824 
3828  StreamTcpReassembleRawRegisterTests();
3829 #endif /* UNITTESTS */
3830 }
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:2269
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:527
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:2125
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:1909
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:1107
SET_ISN
#define SET_ISN(stream, setseq)
Definition: stream-tcp-reassemble.c:2198
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:609
StreamTcpReassemblySetMinInspectDepth
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
Definition: stream-tcp-reassemble.c:2178
STREAM_REASSEMBLY_URGENT_OOB_LIMIT_REACHED
@ STREAM_REASSEMBLY_URGENT_OOB_LIMIT_REACHED
Definition: decode-events.h:316
action-globals.h
TcpReassemblyThreadCtx_::app_tctx
void * app_tctx
Definition: stream-tcp-reassemble.h:62
Packet_::flags
uint32_t flags
Definition: decode.h:551
SCAppLayerParserStateSetFlag
void SCAppLayerParserStateSetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:1863
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:1392
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:395
StreamTcpUtilRegisterTests
void StreamTcpUtilRegisterTests(void)
Definition: stream-tcp-util.c:246
StreamingBufferGetData
int StreamingBufferGetData(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t *stream_offset)
Definition: util-streaming-buffer.c:1810
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
AppLayerHandleTCPData
int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, Packet *p, Flow *f, TcpSession *ssn, TcpStream **stream, uint8_t *data, uint32_t data_len, uint8_t flags, enum StreamUpdateDir app_update_dir)
handle TCP data for the app-layer.
Definition: app-layer.c:710
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h: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:1827
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:536
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:610
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:632
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:2260
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:396
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:2161
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:239
UTHCheckDataAtPosition
int UTHCheckDataAtPosition(TcpStream *stream, int pos, uint64_t offset, const char *data, uint32_t len)
Definition: stream-tcp-reassemble.c:2292
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:1287
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:1295
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:1505
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:2212
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:505
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:605
StreamTcpSetStreamFlagAppProtoDetectionCompleted
#define StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream)
Definition: stream-tcp-private.h:301
StreamingBufferCompareRawData
int StreamingBufferCompareRawData(const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len)
Definition: util-streaming-buffer.c:1850
TcpStream_::window
uint32_t window
Definition: stream-tcp-private.h:117
STREAM_REASSEMBLY_DEPTH_REACHED
@ STREAM_REASSEMBLY_DEPTH_REACHED
Definition: decode-events.h:312
STREAMTCP_STREAM_FLAG_HAS_GAP
#define STREAMTCP_STREAM_FLAG_HAS_GAP
Definition: stream-tcp-private.h:217
StreamTcpReassembleFreeThreadCtx
void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *ra_ctx)
Definition: stream-tcp-reassemble.c: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:280
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:1717
TH_PUSH
#define TH_PUSH
Definition: decode-tcp.h:37
cnt
uint32_t cnt
Definition: tmqh-packetpool.h:7
app-layer-frames.h
STREAMTCP_FLAG_CLOSED_BY_RST
#define STREAMTCP_FLAG_CLOSED_BY_RST
Definition: stream-tcp-private.h:180
Packet_::flow
struct Flow_ * flow
Definition: decode.h:553
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:2241
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:539
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:2005
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:1551
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:471
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:310
STREAM_REASSEMBLY_NO_SEGMENT
@ STREAM_REASSEMBLY_NO_SEGMENT
Definition: decode-events.h:309
StreamTcpSetOSPolicy
void StreamTcpSetOSPolicy(TcpStream *, Packet *)
Function to set the OS policy for the given stream based on the destination of the received packet.
Definition: stream-tcp.c: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:2255
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:2264
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:114
Packet_::dst
Address dst
Definition: decode.h:510
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:3772
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:1974
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:1897
StreamingBufferSBBGetData
void StreamingBufferSBBGetData(const StreamingBuffer *sb, const StreamingBufferBlock *sbb, const uint8_t **data, uint32_t *data_len)
get the data for one SBB
Definition: util-streaming-buffer.c:1681
SCMutex
#define SCMutex
Definition: threads-debug.h:114
ExceptionPolicyCounters_::eps_id
StatsCounterId eps_id[EXCEPTION_POLICY_MAX]
Definition: util-exception-policy-types.h:56
TcpStreamCnf_::reassembly_toserver_chunk_size
uint16_t reassembly_toserver_chunk_size
Definition: stream-tcp.h:77
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h: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:509
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