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