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