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(),
118  size);
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(),
145  size);
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();
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  const TCPHdr *tcph = PacketGetTCP(p);
761 
762  /* If we have reached the defined depth for either of the stream, then stop
763  reassembling the TCP session */
764  uint32_t size =
765  StreamTcpReassembleCheckDepth(ssn, stream, TCP_GET_RAW_SEQ(tcph), p->payload_len);
766  SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size);
767 
770  /* increment stream depth counter */
773  }
774  if (size == 0) {
775  SCLogDebug("ssn %p: depth reached, not reassembling", ssn);
776  SCReturnInt(0);
777  }
778 
780  if (size > p->payload_len)
781  size = p->payload_len;
782 
783  TcpSegment *seg = StreamTcpGetSegment(tv, ra_ctx);
784  if (seg == NULL) {
785  SCLogDebug("segment_pool is empty");
788  SCReturnInt(-1);
789  }
790 
791  DEBUG_VALIDATE_BUG_ON(size > UINT16_MAX);
792  TCP_SEG_LEN(seg) = (uint16_t)size;
793  seg->seq = TCP_GET_RAW_SEQ(tcph);
794 
795  /* HACK: for TFO SYN packets the seq for data starts at + 1 */
796  if (TCP_HAS_TFO(p) && p->payload_len && (tcph->th_flags & TH_SYN))
797  seg->seq += 1;
798 
799  /* proto detection skipped, but now we do get data. Set event. */
800  if (RB_EMPTY(&stream->seg_tree) &&
802 
805  }
806 
808  tv, ra_ctx, stream, seg, p, TCP_GET_RAW_SEQ(tcph), p->payload, p->payload_len);
809  if (r < 0) {
810  if (r == -SC_ENOMEM) {
812  }
813  SCLogDebug("StreamTcpReassembleInsertSegment failed");
814  SCReturnInt(-1);
815  }
816  SCReturnInt(0);
817 }
818 
819 static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream,
820  Packet *p)
821 {
822  uint8_t flag = 0;
823 
825  flag |= STREAM_START;
826  }
827 
828  if (ssn->state == TCP_CLOSED) {
829  flag |= STREAM_EOF;
830  }
831 
832  if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
833  flag |= STREAM_MIDSTREAM;
834  }
835 
836  if (p->flags & PKT_PSEUDO_STREAM_END) {
837  flag |= STREAM_EOF;
838  }
839 
840  if (&ssn->client == stream) {
841  flag |= STREAM_TOSERVER;
842  } else {
843  flag |= STREAM_TOCLIENT;
844  }
846  flag |= STREAM_DEPTH;
847  }
848  return flag;
849 }
850 
851 /**
852  * \brief Check the minimum size limits for reassembly.
853  *
854  * \retval 0 don't reassemble yet
855  * \retval 1 do reassemble
856  */
857 static int StreamTcpReassembleRawCheckLimit(const TcpSession *ssn,
858  const TcpStream *stream, const Packet *p)
859 {
860  SCEnter();
861 
862  /* if any of these flags is set we always inspect immediately */
863 #define STREAMTCP_STREAM_FLAG_FLUSH_FLAGS \
864  ( STREAMTCP_STREAM_FLAG_DEPTH_REACHED \
865  | STREAMTCP_STREAM_FLAG_TRIGGER_RAW \
866  | STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)
867 
870  SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_DEPTH_REACHED "
871  "is set, so not expecting any new data segments");
872  }
874  SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_TRIGGER_RAW is set");
875  }
877  SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED is set, "
878  "so no new segments will be considered");
879  }
880  SCReturnInt(1);
881  }
882 #undef STREAMTCP_STREAM_FLAG_FLUSH_FLAGS
883 
884  /* some states mean we reassemble no matter how much data we have */
885  if (ssn->state > TCP_TIME_WAIT)
886  SCReturnInt(1);
887 
888  if (p->flags & PKT_PSEUDO_STREAM_END)
889  SCReturnInt(1);
890 
891  const uint64_t last_ack_abs = GetAbsLastAck(stream);
892  int64_t diff = last_ack_abs - STREAM_RAW_PROGRESS(stream);
893  int64_t chunk_size = PKT_IS_TOSERVER(p) ? (int64_t)stream_config.reassembly_toserver_chunk_size
895 
896  /* check if we have enough data to do raw reassembly */
897  if (chunk_size <= diff) {
898  SCReturnInt(1);
899  } else {
900  SCLogDebug("%s min chunk len not yet reached: "
901  "last_ack %" PRIu32 ", ra_raw_base_seq %" PRIu32 ", %" PRIu32 " < "
902  "%" PRIi64,
903  PKT_IS_TOSERVER(p) ? "toserver" : "toclient", stream->last_ack, stream->base_seq,
904  (stream->last_ack - stream->base_seq), chunk_size);
905  SCReturnInt(0);
906  }
907 
908  SCReturnInt(0);
909 }
910 
911 /**
912  * \brief see what if any work the TCP session still needs
913  */
914 uint8_t StreamNeedsReassembly(const TcpSession *ssn, uint8_t direction)
915 {
916  const TcpStream *stream = NULL;
917 #ifdef DEBUG
918  const char *dirstr = NULL;
919 #endif
920  if (direction == STREAM_TOSERVER) {
921  stream = &ssn->client;
922 #ifdef DEBUG
923  dirstr = "client";
924 #endif
925  } else {
926  stream = &ssn->server;
927 #ifdef DEBUG
928  dirstr = "server";
929 #endif
930  }
931  int use_app = 1;
932  int use_raw = 1;
933 
935  // app is dead
936  use_app = 0;
937  }
938 
940  // raw is dead
941  use_raw = 0;
942  }
943  if (use_raw) {
944  const uint64_t right_edge =
945  STREAM_BASE_OFFSET(stream) + stream->segs_right_edge - stream->base_seq;
946  SCLogDebug("%s: app %" PRIu64 " (use: %s), raw %" PRIu64
947  " (use: %s). Stream right edge: %" PRIu64,
948  dirstr, STREAM_APP_PROGRESS(stream), use_app ? "yes" : "no",
949  STREAM_RAW_PROGRESS(stream), use_raw ? "yes" : "no", right_edge);
950  if (right_edge > STREAM_RAW_PROGRESS(stream)) {
951  SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION", dirstr);
953  }
954  }
955  if (use_app) {
956  const uint64_t right_edge = StreamingBufferGetConsecutiveDataRightEdge(&stream->sb);
957  SCLogDebug("%s: app %" PRIu64 " (use: %s), raw %" PRIu64
958  " (use: %s). Stream right edge: %" PRIu64,
959  dirstr, STREAM_APP_PROGRESS(stream), use_app ? "yes" : "no",
960  STREAM_RAW_PROGRESS(stream), use_raw ? "yes" : "no", right_edge);
961  if (right_edge > STREAM_APP_PROGRESS(stream)) {
962  SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION", dirstr);
964  }
965  }
966 
967  SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NONE", dirstr);
969 }
970 
971 #ifdef DEBUG
972 static uint64_t GetStreamSize(TcpStream *stream)
973 {
974  if (stream) {
975  uint64_t size = 0;
976  uint32_t cnt = 0;
977  uint64_t last_ack_abs = GetAbsLastAck(stream);
978  uint64_t last_re = 0;
979 
980  SCLogDebug("stream_offset %" PRIu64, stream->sb.region.stream_offset);
981 
982  TcpSegment *seg;
983  RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
984  const uint64_t seg_abs =
985  STREAM_BASE_OFFSET(stream) + (uint64_t)(seg->seq - stream->base_seq);
986  if (last_re != 0 && last_re < seg_abs) {
987  const char *gacked = NULL;
988  if (last_ack_abs >= seg_abs) {
989  gacked = "fully ack'd";
990  } else if (last_ack_abs > last_re) {
991  gacked = "partly ack'd";
992  } else {
993  gacked = "not yet ack'd";
994  }
995  SCLogDebug(" -> gap of size %" PRIu64 ", ack:%s", seg_abs - last_re, gacked);
996  }
997 
998  const char *acked = NULL;
999  if (last_ack_abs >= seg_abs + (uint64_t)TCP_SEG_LEN(seg)) {
1000  acked = "fully ack'd";
1001  } else if (last_ack_abs > seg_abs) {
1002  acked = "partly ack'd";
1003  } else {
1004  acked = "not yet ack'd";
1005  }
1006 
1007  SCLogDebug("%u -> seg %p seq %u abs %" PRIu64 " size %u abs %" PRIu64 " (%" PRIu64
1008  ") ack:%s",
1009  cnt, seg, seg->seq, seg_abs, TCP_SEG_LEN(seg),
1010  seg_abs + (uint64_t)TCP_SEG_LEN(seg), STREAM_BASE_OFFSET(stream), acked);
1011  last_re = seg_abs + (uint64_t)TCP_SEG_LEN(seg);
1012  cnt++;
1013  size += (uint64_t)TCP_SEG_LEN(seg);
1014  }
1015 
1016  SCLogDebug("size %"PRIu64", cnt %"PRIu32, size, cnt);
1017  return size;
1018  }
1019  return (uint64_t)0;
1020 }
1021 
1022 static void GetSessionSize(TcpSession *ssn, Packet *p)
1023 {
1024  uint64_t size = 0;
1025  if (ssn) {
1026  size = GetStreamSize(&ssn->client);
1027  size += GetStreamSize(&ssn->server);
1028 
1029  //if (size > 900000)
1030  // SCLogInfo("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
1031  SCLogDebug("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
1032  }
1033 }
1034 #endif
1035 
1036 static inline bool GapAhead(const TcpStream *stream, StreamingBufferBlock *cur_blk)
1037 {
1038  StreamingBufferBlock *nblk = SBB_RB_NEXT(cur_blk);
1039  if (nblk && (cur_blk->offset + cur_blk->len < nblk->offset) &&
1040  GetAbsLastAck(stream) > (cur_blk->offset + cur_blk->len)) {
1041  return true;
1042  }
1043  return false;
1044 }
1045 
1046 /** \internal
1047  *
1048  * Get buffer, or first part of the buffer if data gaps exist.
1049  *
1050  * \brief get stream data from offset
1051  * \param offset stream offset
1052  * \param check_for_gap check if there is a gap ahead. Optional as it is only
1053  * needed for app-layer incomplete support.
1054  * \retval bool pkt loss ahead */
1055 static bool GetAppBuffer(const TcpStream *stream, const uint8_t **data, uint32_t *data_len,
1056  uint64_t offset, const bool check_for_gap)
1057 {
1058  const uint8_t *mydata;
1059  uint32_t mydata_len;
1060  bool gap_ahead = false;
1061 
1062  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1063  SCLogDebug("getting one blob");
1064 
1065  StreamingBufferGetDataAtOffset(&stream->sb, &mydata, &mydata_len, offset);
1066 
1067  *data = mydata;
1068  *data_len = mydata_len;
1069  } else {
1070  SCLogDebug("block mode");
1071  StreamingBufferBlock key = { .offset = offset, .len = 0 };
1072  StreamingBufferBlock *blk = SBB_RB_FIND_INCLUSIVE((struct SBB *)&stream->sb.sbb_tree, &key);
1073  if (blk == NULL) {
1074  *data = NULL;
1075  *data_len = 0;
1076  return false;
1077  }
1078  SCLogDebug("blk %p blk->offset %" PRIu64 ", blk->len %u", blk, blk->offset, blk->len);
1079 
1080  /* block at expected offset */
1081  if (blk->offset == offset) {
1082  SCLogDebug("blk at offset");
1083 
1084  StreamingBufferSBBGetData(&stream->sb, blk, data, data_len);
1085  BUG_ON(blk->len != *data_len);
1086 
1087  gap_ahead = check_for_gap && GapAhead(stream, blk);
1088 
1089  /* block past out offset */
1090  } else if (blk->offset > offset) {
1091  SCLogDebug("gap, want data at offset %"PRIu64", "
1092  "got data at %"PRIu64". GAP of size %"PRIu64,
1093  offset, blk->offset, blk->offset - offset);
1094  *data = NULL;
1095  *data_len = (uint32_t)(blk->offset - offset);
1096 
1097  /* block starts before offset, but ends after */
1098  } else if (offset > blk->offset && offset <= (blk->offset + blk->len)) {
1099  SCLogDebug("get data from offset %"PRIu64". SBB %"PRIu64"/%u",
1100  offset, blk->offset, blk->len);
1101  StreamingBufferSBBGetDataAtOffset(&stream->sb, blk, data, data_len, offset);
1102  SCLogDebug("data %p, data_len %u", *data, *data_len);
1103 
1104  gap_ahead = check_for_gap && GapAhead(stream, blk);
1105 
1106  } else {
1107  *data = NULL;
1108  *data_len = 0;
1109  }
1110  }
1111  return gap_ahead;
1112 }
1113 
1114 /** \internal
1115  * \brief check to see if we should declare a GAP
1116  * Call this when the app layer didn't get data at the requested
1117  * offset.
1118  */
1119 static inline bool CheckGap(TcpSession *ssn, TcpStream *stream, Packet *p)
1120 {
1121  const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
1122  const int ackadded = (ssn->state >= TCP_FIN_WAIT1) ? 1 : 0;
1123  const uint64_t last_ack_abs = GetAbsLastAck(stream) - (uint64_t)ackadded;
1124 
1125  SCLogDebug("last_ack %u abs %" PRIu64, stream->last_ack, last_ack_abs);
1126  SCLogDebug("next_seq %u", stream->next_seq);
1127 
1128  /* if last_ack_abs is beyond the app_progress data that we haven't seen
1129  * has been ack'd. This looks like a GAP. */
1130  if (last_ack_abs > app_progress) {
1131  /* however, we can accept ACKs a bit too liberally. If last_ack
1132  * is beyond next_seq, we only consider it a gap now if we do
1133  * already have data beyond the gap. */
1134  if (SEQ_GT(stream->last_ack, stream->next_seq)) {
1135  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1136  SCLogDebug("packet %" PRIu64 ": no GAP. "
1137  "next_seq %u < last_ack %u, but no data in list",
1138  p->pcap_cnt, stream->next_seq, stream->last_ack);
1139  return false;
1140  } else {
1141  const uint64_t next_seq_abs =
1142  STREAM_BASE_OFFSET(stream) + (stream->next_seq - stream->base_seq);
1143  const StreamingBufferBlock *blk = stream->sb.head;
1144  if (blk->offset > next_seq_abs && blk->offset < last_ack_abs) {
1145  /* ack'd data after the gap */
1146  SCLogDebug("packet %" PRIu64 ": GAP. "
1147  "next_seq %u < last_ack %u, but ACK'd data beyond gap.",
1148  p->pcap_cnt, stream->next_seq, stream->last_ack);
1149  return true;
1150  }
1151  }
1152  }
1153 
1154  SCLogDebug("packet %" PRIu64 ": GAP! "
1155  "last_ack_abs %" PRIu64 " > app_progress %" PRIu64 ", "
1156  "but we have no data.",
1157  p->pcap_cnt, last_ack_abs, app_progress);
1158  return true;
1159  }
1160  SCLogDebug("packet %"PRIu64": no GAP. "
1161  "last_ack_abs %"PRIu64" <= app_progress %"PRIu64,
1162  p->pcap_cnt, last_ack_abs, app_progress);
1163  return false;
1164 }
1165 
1166 static inline uint32_t AdjustToAcked(const Packet *p,
1167  const TcpSession *ssn, const TcpStream *stream,
1168  const uint64_t app_progress, const uint32_t data_len)
1169 {
1170  uint32_t adjusted = data_len;
1171 
1172  /* get window of data that is acked */
1173  if (!StreamTcpInlineMode()) {
1174  SCLogDebug("ssn->state %s", StreamTcpStateAsString(ssn->state));
1175  if (data_len == 0 || ((ssn->state < TCP_CLOSED ||
1176  (ssn->state == TCP_CLOSED &&
1177  (ssn->flags & STREAMTCP_FLAG_CLOSED_BY_RST) != 0)) &&
1178  (p->flags & PKT_PSEUDO_STREAM_END))) {
1179  // fall through, we use all available data
1180  } else {
1181  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1182  DEBUG_VALIDATE_BUG_ON(app_progress > last_ack_abs);
1183 
1184  /* see if the buffer contains unack'd data as well */
1185  if (app_progress <= last_ack_abs && app_progress + data_len > last_ack_abs) {
1186  uint32_t check = data_len;
1187  adjusted = (uint32_t)(last_ack_abs - app_progress);
1188  BUG_ON(adjusted > check);
1189  SCLogDebug("data len adjusted to %u to make sure only ACK'd "
1190  "data is considered", adjusted);
1191  }
1192  }
1193  }
1194  return adjusted;
1195 }
1196 
1197 /** \internal
1198  * \brief get stream buffer and update the app-layer
1199  * \param stream pointer to pointer as app-layer can switch flow dir
1200  * \retval 0 success
1201  */
1202 static int ReassembleUpdateAppLayer(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn,
1203  TcpStream **stream, Packet *p, enum StreamUpdateDir app_update_dir)
1204 {
1205  uint64_t app_progress = STREAM_APP_PROGRESS(*stream);
1206 
1207  SCLogDebug("app progress %"PRIu64, app_progress);
1208 #ifdef DEBUG
1209  uint64_t last_ack_abs = GetAbsLastAck(*stream);
1210  SCLogDebug("last_ack %u (abs %" PRIu64 "), base_seq %u", (*stream)->last_ack, last_ack_abs,
1211  (*stream)->base_seq);
1212 #endif
1213  const uint8_t *mydata;
1214  uint32_t mydata_len;
1215  bool last_was_gap = false;
1216 
1217  while (1) {
1218  const uint8_t flags = StreamGetAppLayerFlags(ssn, *stream, p);
1219  bool check_for_gap_ahead = ((*stream)->data_required > 0);
1220  bool gap_ahead =
1221  GetAppBuffer(*stream, &mydata, &mydata_len, app_progress, check_for_gap_ahead);
1222  SCLogDebug("gap_ahead %s mydata_len %u", BOOL2STR(gap_ahead), mydata_len);
1223  if (last_was_gap && mydata_len == 0) {
1224  break;
1225  }
1226  last_was_gap = false;
1227 
1228  /* make sure to only deal with ACK'd data */
1229  mydata_len = AdjustToAcked(p, ssn, *stream, app_progress, mydata_len);
1230  DEBUG_VALIDATE_BUG_ON(mydata_len > (uint32_t)INT_MAX);
1231  if (mydata == NULL && mydata_len > 0 && CheckGap(ssn, *stream, p)) {
1232  SCLogDebug("sending GAP to app-layer (size: %u)", mydata_len);
1233 
1234  int r = AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, NULL, mydata_len,
1235  StreamGetAppLayerFlags(ssn, *stream, p) | STREAM_GAP, app_update_dir);
1236  AppLayerProfilingStore(ra_ctx->app_tctx, p);
1237 
1239  (*stream)->flags |= STREAMTCP_STREAM_FLAG_HAS_GAP;
1242 
1243  /* AppLayerHandleTCPData has likely updated progress. */
1244  const bool no_progress_update = (app_progress == STREAM_APP_PROGRESS(*stream));
1245  app_progress = STREAM_APP_PROGRESS(*stream);
1246 
1247  /* a GAP also consumes 'data required'. TODO perhaps we can use
1248  * this to skip post GAP data until the start of a next record. */
1249  if ((*stream)->data_required > 0) {
1250  if ((*stream)->data_required > mydata_len) {
1251  (*stream)->data_required -= mydata_len;
1252  } else {
1253  (*stream)->data_required = 0;
1254  }
1255  }
1256  if (r < 0)
1257  return 0;
1258  if (no_progress_update)
1259  break;
1260  last_was_gap = true;
1261  continue;
1262 
1263  } else if (flags & STREAM_DEPTH) {
1264  SCLogDebug("DEPTH");
1265  // we're just called once with this flag, so make sure we pass it on
1266  if (mydata == NULL && mydata_len > 0) {
1267  mydata_len = 0;
1268  }
1269  } else if (mydata == NULL || (mydata_len == 0 && ((flags & STREAM_EOF) == 0))) {
1270  SCLogDebug("GAP?1");
1271  /* Possibly a gap, but no new data. */
1272  if ((p->flags & PKT_PSEUDO_STREAM_END) == 0 || ssn->state < TCP_CLOSED)
1273  SCReturnInt(0);
1274 
1275  mydata = NULL;
1276  mydata_len = 0;
1277  SCLogDebug("%"PRIu64" got %p/%u", p->pcap_cnt, mydata, mydata_len);
1278  break;
1279  }
1280  DEBUG_VALIDATE_BUG_ON(mydata == NULL && mydata_len > 0);
1281 
1282  SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64,
1283  *stream, &(*stream)->sb, mydata_len, app_progress);
1284 
1285  if ((p->flags & PKT_PSEUDO_STREAM_END) == 0 || ssn->state < TCP_CLOSED) {
1286  SCLogDebug("GAP?2");
1287  if (mydata_len < (*stream)->data_required) {
1288  SCLogDebug("GAP?3 gap_head %s", BOOL2STR(gap_ahead));
1289  if (gap_ahead) {
1290  SCLogDebug("GAP while expecting more data (expect %u, gap size %u)",
1291  (*stream)->data_required, mydata_len);
1292  (*stream)->app_progress_rel += mydata_len;
1293  (*stream)->data_required -= mydata_len;
1294  // TODO send incomplete data to app-layer with special flag
1295  // indicating its all there is for this rec?
1296  } else {
1297  SCReturnInt(0);
1298  }
1299  app_progress = STREAM_APP_PROGRESS(*stream);
1300  continue;
1301  }
1302  }
1303  (*stream)->data_required = 0;
1304 
1305  SCLogDebug("parser");
1306  /* update the app-layer */
1307  (void)AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, (uint8_t *)mydata,
1308  mydata_len, flags, app_update_dir);
1309  AppLayerProfilingStore(ra_ctx->app_tctx, p);
1310  AppLayerFrameDump(p->flow);
1311  uint64_t new_app_progress = STREAM_APP_PROGRESS(*stream);
1312  if (new_app_progress == app_progress || FlowChangeProto(p->flow))
1313  break;
1314  app_progress = new_app_progress;
1315  if (flags & STREAM_DEPTH)
1316  break;
1317  }
1318 
1319  SCReturnInt(0);
1320 }
1321 
1322 /**
1323  * \brief Update the stream reassembly upon receiving a packet.
1324  *
1325  * For IDS mode, the stream is in the opposite direction of the packet,
1326  * as the ACK-packet is ACK'ing the stream.
1327  *
1328  * One of the utilities call by this function AppLayerHandleTCPData(),
1329  * has a feature where it will call this very same function for the
1330  * stream opposing the stream it is called with. This shouldn't cause
1331  * any issues, since processing of each stream is independent of the
1332  * other stream.
1333  */
1335  TcpStream *stream, Packet *p, enum StreamUpdateDir app_update_dir)
1336 {
1337  SCEnter();
1338 
1339  /* this function can be directly called by app layer protocol
1340  * detection. */
1343  SCLogDebug("stream no reassembly flag set or app-layer disabled.");
1344  SCReturnInt(0);
1345  }
1346 
1347 #ifdef DEBUG
1348  SCLogDebug("stream->seg_tree RB_MIN %p", RB_MIN(TCPSEG, &stream->seg_tree));
1349  GetSessionSize(ssn, p);
1350 #endif
1351  /* if no segments are in the list or all are already processed,
1352  * and state is beyond established, we send an empty msg */
1353  if (!STREAM_HAS_SEEN_DATA(stream) || STREAM_RIGHT_EDGE(stream) <= STREAM_APP_PROGRESS(stream))
1354  {
1355  /* send an empty EOF msg if we have no segments but TCP state
1356  * is beyond ESTABLISHED */
1357  if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) {
1358  SCLogDebug("sending empty eof message");
1359  /* send EOF to app layer */
1360  AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, &stream, NULL, 0,
1361  StreamGetAppLayerFlags(ssn, stream, p), app_update_dir);
1362  AppLayerProfilingStore(ra_ctx->app_tctx, p);
1363 
1364  SCReturnInt(0);
1365  }
1366  }
1367 
1368  /* with all that out of the way, lets update the app-layer */
1369  return ReassembleUpdateAppLayer(tv, ra_ctx, ssn, &stream, p, app_update_dir);
1370 }
1371 
1372 /** \internal
1373  * \brief get stream data from offset
1374  * \param offset stream offset */
1375 static int GetRawBuffer(const TcpStream *stream, const uint8_t **data, uint32_t *data_len,
1376  StreamingBufferBlock **iter, uint64_t offset, uint64_t *data_offset)
1377 {
1378  const uint8_t *mydata;
1379  uint32_t mydata_len;
1380  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1381  SCLogDebug("getting one blob for offset %"PRIu64, offset);
1382 
1383  uint64_t roffset = offset;
1384  if (offset)
1385  StreamingBufferGetDataAtOffset(&stream->sb, &mydata, &mydata_len, offset);
1386  else {
1387  StreamingBufferGetData(&stream->sb, &mydata, &mydata_len, &roffset);
1388  }
1389 
1390  *data = mydata;
1391  *data_len = mydata_len;
1392  *data_offset = roffset;
1393  } else {
1394  SCLogDebug("multiblob %s. Want offset %"PRIu64,
1395  *iter == NULL ? "starting" : "continuing", offset);
1396  if (*iter == NULL) {
1397  StreamingBufferBlock key = { .offset = offset, .len = 0 };
1398  *iter = SBB_RB_FIND_INCLUSIVE((struct SBB *)&stream->sb.sbb_tree, &key);
1399  SCLogDebug("*iter %p", *iter);
1400  }
1401  if (*iter == NULL) {
1402  SCLogDebug("no data");
1403  *data = NULL;
1404  *data_len = 0;
1405  *data_offset = 0;
1406  return 0;
1407  }
1408  SCLogDebug("getting multiple blobs. Iter %p, %"PRIu64"/%u", *iter, (*iter)->offset, (*iter)->len);
1409 
1410  StreamingBufferSBBGetData(&stream->sb, (*iter), &mydata, &mydata_len);
1411  SCLogDebug("mydata %p", mydata);
1412 
1413  if ((*iter)->offset < offset) {
1414  uint64_t delta = offset - (*iter)->offset;
1415  if (delta < mydata_len) {
1416  *data = mydata + delta;
1417  *data_len = (uint32_t)(mydata_len - delta);
1418  *data_offset = offset;
1419  } else {
1420  SCLogDebug("no data (yet)");
1421  *data = NULL;
1422  *data_len = 0;
1423  *data_offset = 0;
1424  }
1425 
1426  } else {
1427  *data = mydata;
1428  *data_len = mydata_len;
1429  *data_offset = (*iter)->offset;
1430  }
1431 
1432  *iter = SBB_RB_NEXT(*iter);
1433  SCLogDebug("*iter %p", *iter);
1434  }
1435  return 0;
1436 }
1437 
1438 /** \brief does the stream engine have data to inspect?
1439  *
1440  * Returns true if there is data to inspect. In IDS case this is
1441  * about ACK'd data in the packet's direction.
1442  *
1443  * In the IPS case this is about the packet itself.
1444  */
1446 {
1447  TcpStream *stream;
1448  if (PKT_IS_TOSERVER(p)) {
1449  stream = &ssn->client;
1450  } else {
1451  stream = &ssn->server;
1452  }
1453 
1454  if (RB_EMPTY(&stream->seg_tree)) {
1455  return false;
1456  }
1457 
1460  return false;
1461 
1462  if (!StreamTcpInlineMode()) {
1463  const uint64_t segs_re_abs =
1464  STREAM_BASE_OFFSET(stream) + stream->segs_right_edge - stream->base_seq;
1465  if (STREAM_RAW_PROGRESS(stream) == segs_re_abs) {
1466  return false;
1467  }
1468  if (StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 1) {
1469  return true;
1470  }
1471  } else {
1472  if (p->payload_len > 0 && (p->flags & PKT_STREAM_ADD)) {
1473  return true;
1474  }
1475  }
1476  return false;
1477 }
1478 
1479 /** \brief update stream engine after detection
1480  *
1481  * Tasked with progressing the 'progress' for Raw reassembly.
1482  * 2 main scenario's:
1483  * 1. progress is != 0, so we use this
1484  * 2. progress is 0, meaning the detect engine didn't touch
1485  * raw at all. In this case we need to look into progressing
1486  * raw anyway.
1487  *
1488  * Additionally, this function is tasked with disabling raw
1489  * reassembly if the app-layer requested to disable it.
1490  */
1491 void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, const uint64_t progress)
1492 {
1493  TcpStream *stream;
1494  if (PKT_IS_TOSERVER(p)) {
1495  stream = &ssn->client;
1496  } else {
1497  stream = &ssn->server;
1498  }
1499 
1500  if (progress > STREAM_RAW_PROGRESS(stream)) {
1501  DEBUG_VALIDATE_BUG_ON(progress - STREAM_RAW_PROGRESS(stream) > UINT32_MAX);
1502  uint32_t slide = (uint32_t)(progress - STREAM_RAW_PROGRESS(stream));
1503  stream->raw_progress_rel += slide;
1505 
1506  } else if (progress == 0) {
1507  uint64_t target;
1508  if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) == 0) {
1509  target = STREAM_APP_PROGRESS(stream);
1510  } else {
1511  target = GetAbsLastAck(stream);
1512  }
1513  if (target > STREAM_RAW_PROGRESS(stream)) {
1514  DEBUG_VALIDATE_BUG_ON(target - STREAM_RAW_PROGRESS(stream) > UINT32_MAX);
1515  uint32_t slide = (uint32_t)(target - STREAM_RAW_PROGRESS(stream));
1516  stream->raw_progress_rel += slide;
1517  }
1519 
1520  } else {
1521  SCLogDebug("p->pcap_cnt %"PRIu64": progress %"PRIu64" app %"PRIu64" raw %"PRIu64" tcp win %"PRIu32,
1522  p->pcap_cnt, progress, STREAM_APP_PROGRESS(stream),
1523  STREAM_RAW_PROGRESS(stream), stream->window);
1524  }
1525 
1526  /* if we were told to accept no more raw data, we can mark raw as
1527  * disabled now. */
1530  SCLogDebug("ssn %p: STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED set, "
1531  "now that detect ran also set STREAMTCP_STREAM_FLAG_DISABLE_RAW", ssn);
1532  }
1533 
1534  SCLogDebug("stream raw progress now %"PRIu64, STREAM_RAW_PROGRESS(stream));
1535 }
1536 
1537 /** \internal
1538  * \brief get a buffer around the current packet and run the callback on it
1539  *
1540  * The inline/IPS scanning method takes the current payload and wraps it in
1541  * data from other segments.
1542  *
1543  * How much data is inspected is controlled by the available data, chunk_size
1544  * and the payload size of the packet.
1545  *
1546  * Large packets: if payload size is close to the chunk_size, where close is
1547  * defined as more than 67% of the chunk_size, a larger chunk_size will be
1548  * used: payload_len + 33% of the chunk_size.
1549  * If the payload size if equal to or bigger than the chunk_size, we use
1550  * payload len + 33% of the chunk size.
1551  */
1552 static int StreamReassembleRawInline(TcpSession *ssn, const Packet *p,
1553  StreamReassembleRawFunc Callback, void *cb_data, uint64_t *progress_out)
1554 {
1555  SCEnter();
1556  int r = 0;
1557 
1558  TcpStream *stream;
1559  if (PKT_IS_TOSERVER(p)) {
1560  stream = &ssn->client;
1561  } else {
1562  stream = &ssn->server;
1563  }
1564 
1565  if (p->payload_len == 0 || (p->flags & PKT_STREAM_ADD) == 0 ||
1567  {
1568  *progress_out = STREAM_RAW_PROGRESS(stream);
1569  return 0;
1570  }
1571 
1572  uint32_t chunk_size = PKT_IS_TOSERVER(p) ?
1575  if (chunk_size <= p->payload_len) {
1576  chunk_size = p->payload_len + (chunk_size / 3);
1577  SCLogDebug("packet payload len %u, so chunk_size adjusted to %u",
1578  p->payload_len, chunk_size);
1579  } else if (((chunk_size / 3 ) * 2) < p->payload_len) {
1580  chunk_size = p->payload_len + ((chunk_size / 3));
1581  SCLogDebug("packet payload len %u, so chunk_size adjusted to %u",
1582  p->payload_len, chunk_size);
1583  }
1584 
1585  const TCPHdr *tcph = PacketGetTCP(p);
1586  uint64_t packet_leftedge_abs =
1587  STREAM_BASE_OFFSET(stream) + (TCP_GET_RAW_SEQ(tcph) - stream->base_seq);
1588  uint64_t packet_rightedge_abs = packet_leftedge_abs + p->payload_len;
1589  SCLogDebug("packet_leftedge_abs %"PRIu64", rightedge %"PRIu64,
1590  packet_leftedge_abs, packet_rightedge_abs);
1591 
1592  const uint8_t *mydata = NULL;
1593  uint32_t mydata_len = 0;
1594  uint64_t mydata_offset = 0;
1595  /* simply return progress from the block we inspected. */
1596  bool return_progress = false;
1597 
1598  if (RB_EMPTY(&stream->sb.sbb_tree)) {
1599  /* continues block */
1600  StreamingBufferGetData(&stream->sb, &mydata, &mydata_len, &mydata_offset);
1601  return_progress = true;
1602 
1603  } else {
1604  SCLogDebug("finding our SBB from offset %"PRIu64, packet_leftedge_abs);
1605  /* find our block */
1606  StreamingBufferBlock key = { .offset = packet_leftedge_abs, .len = p->payload_len };
1607  StreamingBufferBlock *sbb = SBB_RB_FIND_INCLUSIVE(&stream->sb.sbb_tree, &key);
1608  if (sbb) {
1609  SCLogDebug("found %p offset %"PRIu64" len %u", sbb, sbb->offset, sbb->len);
1610  StreamingBufferSBBGetData(&stream->sb, sbb, &mydata, &mydata_len);
1611  mydata_offset = sbb->offset;
1612  }
1613  }
1614 
1615  /* this can only happen if the segment insert of our current 'p' failed */
1616  uint64_t mydata_rightedge_abs = mydata_offset + mydata_len;
1617  if ((mydata == NULL || mydata_len == 0) || /* no data */
1618  (mydata_offset >= packet_rightedge_abs || /* data all to the right */
1619  packet_leftedge_abs >= mydata_rightedge_abs) || /* data all to the left */
1620  (packet_leftedge_abs < mydata_offset || /* data missing at the start */
1621  packet_rightedge_abs > mydata_rightedge_abs)) /* data missing at the end */
1622  {
1623  /* no data, or data is incomplete or wrong: use packet data */
1624  mydata = p->payload;
1625  mydata_len = p->payload_len;
1626  mydata_offset = packet_leftedge_abs;
1627  //mydata_rightedge_abs = packet_rightedge_abs;
1628  } else {
1629  /* adjust buffer to match chunk_size */
1630  SCLogDebug("chunk_size %u mydata_len %u", chunk_size, mydata_len);
1631  if (mydata_len > chunk_size) {
1632  uint32_t excess = mydata_len - chunk_size;
1633  SCLogDebug("chunk_size %u mydata_len %u excess %u", chunk_size, mydata_len, excess);
1634 
1635  if (mydata_rightedge_abs == packet_rightedge_abs) {
1636  mydata += excess;
1637  mydata_len -= excess;
1638  mydata_offset += excess;
1639  SCLogDebug("cutting front of the buffer with %u", excess);
1640  } else if (mydata_offset == packet_leftedge_abs) {
1641  mydata_len -= excess;
1642  SCLogDebug("cutting tail of the buffer with %u", excess);
1643  } else {
1644  uint32_t before = (uint32_t)(packet_leftedge_abs - mydata_offset);
1645  uint32_t after = (uint32_t)(mydata_rightedge_abs - packet_rightedge_abs);
1646  SCLogDebug("before %u after %u", before, after);
1647 
1648  if (after >= (chunk_size - p->payload_len) / 2) {
1649  // more trailing data than we need
1650 
1651  if (before >= (chunk_size - p->payload_len) / 2) {
1652  // also more heading data, divide evenly
1653  before = after = (chunk_size - p->payload_len) / 2;
1654  } else {
1655  // heading data is less than requested, give the
1656  // rest to the trailing data
1657  after = (chunk_size - p->payload_len) - before;
1658  }
1659  } else {
1660  // less trailing data than requested
1661 
1662  if (before >= (chunk_size - p->payload_len) / 2) {
1663  before = (chunk_size - p->payload_len) - after;
1664  } else {
1665  // both smaller than their requested size
1666  }
1667  }
1668 
1669  /* adjust the buffer */
1670  uint32_t skip = (uint32_t)(packet_leftedge_abs - mydata_offset) - before;
1671  uint32_t cut = (uint32_t)(mydata_rightedge_abs - packet_rightedge_abs) - after;
1672  DEBUG_VALIDATE_BUG_ON(skip > mydata_len);
1673  DEBUG_VALIDATE_BUG_ON(cut > mydata_len);
1674  DEBUG_VALIDATE_BUG_ON(skip + cut > mydata_len);
1675  mydata += skip;
1676  mydata_len -= (skip + cut);
1677  mydata_offset += skip;
1678  }
1679  }
1680  }
1681 
1682  /* run the callback */
1683  r = Callback(cb_data, mydata, mydata_len, mydata_offset);
1684  BUG_ON(r < 0);
1685 
1686  if (return_progress) {
1687  *progress_out = (mydata_offset + mydata_len);
1688  } else {
1689  /* several blocks of data, so we need to be a bit more careful:
1690  * - if last_ack is beyond last progress, move progress forward to last_ack
1691  * - if our block matches or starts before last ack, return right edge of
1692  * our block.
1693  */
1694  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1695  SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs);
1696 
1697  if (STREAM_RAW_PROGRESS(stream) < last_ack_abs) {
1698  if (mydata_offset > last_ack_abs) {
1699  /* gap between us and last ack, set progress to last ack */
1700  *progress_out = last_ack_abs;
1701  } else {
1702  *progress_out = (mydata_offset + mydata_len);
1703  }
1704  } else {
1705  *progress_out = STREAM_RAW_PROGRESS(stream);
1706  }
1707  }
1708  return r;
1709 }
1710 
1711 /** \brief access 'raw' reassembly data.
1712  *
1713  * Access data as tracked by 'raw' tracker. Data is made available to
1714  * callback that is passed to this function.
1715  *
1716  * In the case of IDS the callback may be run multiple times if data
1717  * contains gaps. It will then be run for each block of data that is
1718  * continuous.
1719  *
1720  * The callback should give on of 2 return values:
1721  * - 0 ok
1722  * - 1 done
1723  * The value 1 will break the loop if there is a block list that is
1724  * inspected.
1725  *
1726  * This function will return the 'progress' value that has been
1727  * consumed until now.
1728  *
1729  * \param ssn tcp session
1730  * \param stream tcp stream
1731  * \param Callback the function pointer to the callback function
1732  * \param cb_data callback data
1733  * \param[in] progress_in progress to work from
1734  * \param[in] re right edge of data to consider
1735  * \param[out] progress_out absolute progress value of the data this
1736  * call handled.
1737  * \param eof we're wrapping up so inspect all data we have, incl unACKd
1738  * \param respect_inspect_depth use Stream::min_inspect_depth if set
1739  *
1740  * `respect_inspect_depth` is used to avoid useless inspection of too
1741  * much data.
1742  */
1743 static int StreamReassembleRawDo(const TcpSession *ssn, const TcpStream *stream,
1744  StreamReassembleRawFunc Callback, void *cb_data, const uint64_t progress_in,
1745  const uint64_t re, uint64_t *progress_out, bool eof, bool respect_inspect_depth)
1746 {
1747  SCEnter();
1748  int r = 0;
1749 
1750  StreamingBufferBlock *iter = NULL;
1751  uint64_t progress = progress_in;
1752 
1753  /* loop through available buffers. On no packet loss we'll have a single
1754  * iteration. On missing data we'll walk the blocks */
1755  while (1) {
1756  const uint8_t *mydata;
1757  uint32_t mydata_len;
1758  uint64_t mydata_offset = 0;
1759 
1760  GetRawBuffer(stream, &mydata, &mydata_len, &iter, progress, &mydata_offset);
1761  if (mydata_len == 0) {
1762  SCLogDebug("no data");
1763  break;
1764  }
1765  //PrintRawDataFp(stdout, mydata, mydata_len);
1766 
1767  SCLogDebug("raw progress %"PRIu64, progress);
1768  SCLogDebug("stream %p data in buffer %p of len %u and offset %"PRIu64,
1769  stream, &stream->sb, mydata_len, progress);
1770 
1771  if (eof) {
1772  // inspect all remaining data, ack'd or not
1773  } else {
1774  if (re < progress) {
1775  SCLogDebug("nothing to do");
1776  goto end;
1777  }
1778 
1779  SCLogDebug("re %" PRIu64 ", raw_progress %" PRIu64, re, progress);
1780  SCLogDebug("raw_progress + mydata_len %" PRIu64 ", re %" PRIu64, progress + mydata_len,
1781  re);
1782 
1783  /* see if the buffer contains unack'd data as well */
1784  if (progress + mydata_len > re) {
1785  uint32_t check = mydata_len;
1786  mydata_len = (uint32_t)(re - progress);
1787  BUG_ON(check < mydata_len);
1788  SCLogDebug("data len adjusted to %u to make sure only ACK'd "
1789  "data is considered", mydata_len);
1790  }
1791  }
1792  if (mydata_len == 0)
1793  break;
1794 
1795  SCLogDebug("data %p len %u", mydata, mydata_len);
1796 
1797  /* we have data. */
1798  r = Callback(cb_data, mydata, mydata_len, mydata_offset);
1799  BUG_ON(r < 0);
1800 
1801  if (mydata_offset == progress) {
1802  SCLogDebug("progress %"PRIu64" increasing with data len %u to %"PRIu64,
1803  progress, mydata_len, progress_in + mydata_len);
1804 
1805  progress += mydata_len;
1806  SCLogDebug("raw progress now %"PRIu64, progress);
1807 
1808  /* data is beyond the progress we'd like, and before last ack. Gap. */
1809  } else if (mydata_offset > progress && mydata_offset < re) {
1810  SCLogDebug("GAP: data is missing from %"PRIu64" (%u bytes), setting to first data we have: %"PRIu64, progress, (uint32_t)(mydata_offset - progress), mydata_offset);
1811  SCLogDebug("re %" PRIu64, re);
1812  progress = mydata_offset;
1813  SCLogDebug("raw progress now %"PRIu64, progress);
1814 
1815  } else {
1816  SCLogDebug("not increasing progress, data gap => mydata_offset "
1817  "%"PRIu64" != progress %"PRIu64, mydata_offset, progress);
1818  }
1819 
1820  if (iter == NULL || r == 1)
1821  break;
1822  }
1823 end:
1824  *progress_out = progress;
1825  return r;
1826 }
1827 
1829  void *cb_data, const uint64_t offset, const bool eof)
1830 {
1831  /* take app progress as the right edge of used data. */
1832  const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
1833  SCLogDebug("app_progress %" PRIu64, app_progress);
1834 
1835  uint64_t unused = 0;
1836  return StreamReassembleRawDo(
1837  ssn, stream, Callback, cb_data, offset, app_progress, &unused, eof, false);
1838 }
1839 
1841  StreamReassembleRawFunc Callback, void *cb_data,
1842  uint64_t *progress_out, bool respect_inspect_depth)
1843 {
1844  /* handle inline separately as the logic is very different */
1845  if (StreamTcpInlineMode()) {
1846  return StreamReassembleRawInline(ssn, p, Callback, cb_data, progress_out);
1847  }
1848 
1849  TcpStream *stream;
1850  if (PKT_IS_TOSERVER(p)) {
1851  stream = &ssn->client;
1852  } else {
1853  stream = &ssn->server;
1854  }
1855 
1857  StreamTcpReassembleRawCheckLimit(ssn, stream, p) == 0)
1858  {
1859  *progress_out = STREAM_RAW_PROGRESS(stream);
1860  return 0;
1861  }
1862 
1863  uint64_t progress = STREAM_RAW_PROGRESS(stream);
1864  /* if the app layer triggered a flush, and we're supposed to
1865  * use a minimal inspect depth, we actually take the app progress
1866  * as that is the right edge of the data. Then we take the window
1867  * of 'min_inspect_depth' before that. */
1868 
1869  SCLogDebug("respect_inspect_depth %s STREAMTCP_STREAM_FLAG_TRIGGER_RAW %s "
1870  "stream->min_inspect_depth %u",
1871  respect_inspect_depth ? "true" : "false",
1872  (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) ? "true" : "false",
1873  stream->min_inspect_depth);
1874 
1875  if (respect_inspect_depth && (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW) &&
1876  stream->min_inspect_depth) {
1877  progress = STREAM_APP_PROGRESS(stream);
1878  if (stream->min_inspect_depth >= progress) {
1879  progress = 0;
1880  } else {
1881  progress -= stream->min_inspect_depth;
1882  }
1883 
1884  SCLogDebug("stream app %" PRIu64 ", raw %" PRIu64, STREAM_APP_PROGRESS(stream),
1885  STREAM_RAW_PROGRESS(stream));
1886 
1887  progress = MIN(progress, STREAM_RAW_PROGRESS(stream));
1888  SCLogDebug("applied min inspect depth due to STREAMTCP_STREAM_FLAG_TRIGGER_RAW: progress "
1889  "%" PRIu64,
1890  progress);
1891  }
1892 
1893  SCLogDebug("progress %" PRIu64 ", min inspect depth %u %s", progress, stream->min_inspect_depth,
1894  stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW ? "STREAMTCP_STREAM_FLAG_TRIGGER_RAW"
1895  : "(no trigger)");
1896 
1897  /* absolute right edge of ack'd data */
1898  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1899  SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs);
1900 
1901  return StreamReassembleRawDo(ssn, stream, Callback, cb_data, progress, last_ack_abs,
1902  progress_out, (p->flags & PKT_PSEUDO_STREAM_END), respect_inspect_depth);
1903 }
1904 
1905 int StreamReassembleLog(const TcpSession *ssn, const TcpStream *stream,
1906  StreamReassembleRawFunc Callback, void *cb_data, const uint64_t progress_in,
1907  uint64_t *progress_out, const bool eof)
1908 {
1909  if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY))
1910  return 0;
1911 
1912  /* absolute right edge of ack'd data */
1913  const uint64_t last_ack_abs = GetAbsLastAck(stream);
1914  SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs);
1915 
1916  return StreamReassembleRawDo(
1917  ssn, stream, Callback, cb_data, progress_in, last_ack_abs, progress_out, eof, false);
1918 }
1919 
1920 /** \internal
1921  * \brief update app layer based on received ACK
1922  *
1923  * \retval r 0 on success, -1 on error
1924  */
1925 static int StreamTcpReassembleHandleSegmentUpdateACK (ThreadVars *tv,
1926  TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p)
1927 {
1928  SCEnter();
1929 
1930  if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, UPDATE_DIR_OPPOSING) < 0)
1931  SCReturnInt(-1);
1932 
1933  SCReturnInt(0);
1934 }
1935 
1936 static void StreamTcpReassembleExceptionPolicyStatsIncr(
1937  ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, enum ExceptionPolicy policy)
1938 {
1939  uint16_t id = ra_ctx->counter_tcp_reas_eps.eps_id[policy];
1940  if (likely(tv && id > 0)) {
1941  StatsIncr(tv, id);
1942  }
1943 }
1944 
1946  TcpSession *ssn, TcpStream *stream, Packet *p)
1947 {
1948  SCEnter();
1949 
1950  DEBUG_VALIDATE_BUG_ON(!PacketIsTCP(p));
1951  const TCPHdr *tcph = PacketGetTCP(p);
1952 
1953  SCLogDebug("ssn %p, stream %p, p %p, p->payload_len %"PRIu16"",
1954  ssn, stream, p, p->payload_len);
1955 
1956  /* default IDS: update opposing side (triggered by ACK) */
1958  /* inline and stream end and flow timeout packets trigger same dir handling */
1959  if (StreamTcpInlineMode()) {
1960  dir = UPDATE_DIR_PACKET;
1961  } else if (p->flags & PKT_PSEUDO_STREAM_END) {
1962  dir = UPDATE_DIR_PACKET;
1963  } else if (tcph->th_flags & TH_RST) { // accepted rst
1964  dir = UPDATE_DIR_PACKET;
1965  } else if ((tcph->th_flags & TH_FIN) && ssn->state > TCP_TIME_WAIT) {
1966  if (tcph->th_flags & TH_ACK) {
1967  dir = UPDATE_DIR_BOTH;
1968  } else {
1969  dir = UPDATE_DIR_PACKET;
1970  }
1971  } else if (ssn->state == TCP_CLOSED) {
1972  dir = UPDATE_DIR_BOTH;
1973  } else if ((ssn->flags & STREAMTCP_FLAG_ASYNC) != 0) {
1974  dir = UPDATE_DIR_PACKET;
1975  SCLogDebug("%" PRIu64 ": ASYNC: UPDATE_DIR_PACKET", p->pcap_cnt);
1976  }
1977 
1978  /* handle ack received */
1979  if ((dir == UPDATE_DIR_OPPOSING || dir == UPDATE_DIR_BOTH)) {
1980  /* we need to update the opposing stream in
1981  * StreamTcpReassembleHandleSegmentUpdateACK */
1982  TcpStream *opposing_stream = NULL;
1983  if (stream == &ssn->client) {
1984  opposing_stream = &ssn->server;
1985  } else {
1986  opposing_stream = &ssn->client;
1987  }
1988 
1989  const bool reversed_before_ack_handling = (p->flow->flags & FLOW_DIR_REVERSED) != 0;
1990 
1991  if (StreamTcpReassembleHandleSegmentUpdateACK(tv, ra_ctx, ssn, opposing_stream, p) != 0) {
1992  SCLogDebug("StreamTcpReassembleHandleSegmentUpdateACK error");
1993  SCReturnInt(-1);
1994  }
1995 
1996  /* StreamTcpReassembleHandleSegmentUpdateACK
1997  * may swap content of ssn->server and ssn->client structures.
1998  * We have to continue with initial content of the stream in such case */
1999  const bool reversed_after_ack_handling = (p->flow->flags & FLOW_DIR_REVERSED) != 0;
2000  if (reversed_before_ack_handling != reversed_after_ack_handling) {
2001  SCLogDebug("TCP streams were swapped");
2002  stream = opposing_stream;
2003  }
2004  }
2005  /* if this segment contains data, insert it */
2006  if (p->payload_len > 0 && !(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) &&
2007  (tcph->th_flags & TH_RST) == 0) {
2008  SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData");
2009 
2010  if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) {
2011  SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error");
2012  /* failure can only be because of memcap hit, so see if this should lead to a drop */
2015  StreamTcpReassembleExceptionPolicyStatsIncr(
2017  SCReturnInt(-1);
2018  }
2019 
2020  SCLogDebug("packet %"PRIu64" set PKT_STREAM_ADD", p->pcap_cnt);
2021  p->flags |= PKT_STREAM_ADD;
2022  } else {
2023  SCLogDebug("ssn %p / stream %p: not calling StreamTcpReassembleHandleSegmentHandleData:"
2024  " p->payload_len %u, STREAMTCP_STREAM_FLAG_NOREASSEMBLY %s",
2025  ssn, stream, p->payload_len,
2026  (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ? "true" : "false");
2027  }
2028 
2029  /* if the STREAMTCP_STREAM_FLAG_DEPTH_REACHED is set, but not the
2030  * STREAMTCP_STREAM_FLAG_NOREASSEMBLY flag, it means the DEPTH flag
2031  * was *just* set. In this case we trigger the AppLayer Truncate
2032  * logic, to inform the applayer no more data in this direction is
2033  * to be expected. */
2034  if ((stream->flags &
2037  {
2038  SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED, truncate applayer");
2039  if (dir != UPDATE_DIR_PACKET) {
2040  SCLogDebug("override: direction now UPDATE_DIR_PACKET so we "
2041  "can trigger Truncate");
2042  dir = UPDATE_DIR_PACKET;
2043  }
2044  }
2045 
2046  /* in stream inline mode even if we have no data we call the reassembly
2047  * functions to handle EOF */
2048  if (dir == UPDATE_DIR_PACKET || dir == UPDATE_DIR_BOTH) {
2049  SCLogDebug("inline (%s) or PKT_PSEUDO_STREAM_END (%s)",
2050  StreamTcpInlineMode()?"true":"false",
2051  (p->flags & PKT_PSEUDO_STREAM_END) ?"true":"false");
2052  if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, dir) < 0) {
2053  SCReturnInt(-1);
2054  }
2055  }
2056 
2057  SCReturnInt(0);
2058 }
2059 
2060 /**
2061  * \brief get a segment from the pool
2062  *
2063  * \retval seg Segment from the pool or NULL
2064  */
2066 {
2068  if (seg) {
2070  memset(&seg->sbseg, 0, sizeof(seg->sbseg));
2071  return seg;
2072  }
2073 
2074  seg = (TcpSegment *)PoolThreadGetById(
2075  segment_thread_pool, (uint16_t)ra_ctx->segment_thread_pool_id);
2076  SCLogDebug("seg we return is %p", seg);
2077  if (seg == NULL) {
2078  /* Increment the counter to show that we are not able to serve the
2079  segment request due to memcap limit */
2081  } else {
2082  memset(&seg->sbseg, 0, sizeof(seg->sbseg));
2084  }
2085 
2086  return seg;
2087 }
2088 
2089 /**
2090  * \brief Trigger RAW stream reassembly
2091  *
2092  * Used by AppLayerTriggerRawStreamReassembly to trigger RAW stream
2093  * reassembly from the applayer, for example upon completion of a
2094  * HTTP request.
2095  *
2096  * It sets a flag in the stream so that the next Raw call will return
2097  * the data.
2098  *
2099  * \param ssn TcpSession
2100  */
2102 {
2103 #ifdef DEBUG
2104  BUG_ON(ssn == NULL);
2105 #endif
2106 
2107  if (ssn != NULL) {
2108  if (direction == STREAM_TOSERVER) {
2110  } else {
2112  }
2113 
2114  SCLogDebug("flagged ssn %p for immediate raw reassembly", ssn);
2115  }
2116 }
2117 
2118 void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
2119 {
2120 #ifdef DEBUG
2121  BUG_ON(ssn == NULL);
2122 #endif
2123 
2124  if (ssn != NULL) {
2125  if (direction == STREAM_TOSERVER) {
2126  ssn->client.min_inspect_depth = depth;
2127  SCLogDebug("ssn %p: set client.min_inspect_depth to %u", ssn, depth);
2128  } else {
2129  ssn->server.min_inspect_depth = depth;
2130  SCLogDebug("ssn %p: set server.min_inspect_depth to %u", ssn, depth);
2131  }
2132  }
2133 }
2134 
2135 #ifdef UNITTESTS
2136 /** unit tests and it's support functions below */
2137 
2138 #define SET_ISN(stream, setseq) \
2139  (stream)->isn = (setseq); \
2140  (stream)->base_seq = (setseq) + 1
2141 
2142 /** \brief The Function to create the packet with given payload, which is used
2143  * to test the reassembly of the engine.
2144  *
2145  * \param payload The variable used to store the payload contents of the
2146  * current packet.
2147  * \param value The value which current payload will have for this packet
2148  * \param payload_len The length of the filed payload for current packet.
2149  * \param len Length of the payload array
2150  */
2151 
2152 void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value,
2153  uint8_t payload_len, uint8_t len)
2154 {
2155  uint8_t i;
2156  for (i = 0; i < payload_len; i++)
2157  payload[i] = value;
2158  for (; i < len; i++)
2159  payload = NULL;
2160 }
2161 
2162 /** \brief The Function Checks the reassembled stream contents against predefined
2163  * stream contents according to OS policy used.
2164  *
2165  * \param stream_policy Predefined value of stream for different OS policies
2166  * \param stream Reassembled stream returned from the reassembly functions
2167  */
2168 
2169 static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len)
2170 {
2171  if (StreamingBufferCompareRawData(&stream->sb,
2172  data, data_len) == 0)
2173  {
2174  SCReturnInt(0);
2175  }
2176  SCLogInfo("OK");
2177  PrintRawDataFp(stdout, data, data_len);
2178  return 1;
2179 }
2180 
2181 #define MISSED_START(isn) \
2182  TcpReassemblyThreadCtx *ra_ctx = NULL; \
2183  TcpSession ssn; \
2184  ThreadVars tv; \
2185  memset(&tv, 0, sizeof(tv)); \
2186  \
2187  StreamTcpUTInit(&ra_ctx); \
2188  \
2189  StreamTcpUTSetupSession(&ssn); \
2190  StreamTcpUTSetupStream(&ssn.server, (isn)); \
2191  StreamTcpUTSetupStream(&ssn.client, (isn)); \
2192  \
2193  TcpStream *stream = &ssn.client;
2194 
2195 #define MISSED_END \
2196  StreamTcpUTClearSession(&ssn); \
2197  StreamTcpUTDeinit(ra_ctx); \
2198  PASS
2199 
2200 #define MISSED_STEP(seq, seg, seglen, buf, buflen) \
2201  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen)); \
2202  FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen))));
2203 
2204 #define MISSED_ADD_PAYLOAD(seq, seg, seglen) \
2205  StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen));
2206 
2207 int UTHCheckGapAtPosition(TcpStream *stream, int pos, uint64_t offset, uint32_t len);
2208 
2209 int UTHCheckGapAtPosition(TcpStream *stream, int pos, uint64_t offset, uint32_t len)
2210 {
2211  int cnt = 0;
2212  uint64_t last_re = 0;
2213  StreamingBufferBlock *sbb = NULL;
2214  RB_FOREACH(sbb, SBB, &stream->sb.sbb_tree)
2215  {
2216  if (sbb->offset != last_re) {
2217  // gap before us
2218  if (cnt == pos && last_re == offset && len == sbb->offset - last_re) {
2219  return 1;
2220  }
2221  cnt++;
2222  }
2223  last_re = sbb->offset + sbb->len;
2224  cnt++;
2225  }
2226  return 0;
2227 }
2228 
2230  TcpStream *stream, int pos, uint64_t offset, const char *data, uint32_t len);
2231 
2233  TcpStream *stream, int pos, uint64_t offset, const char *data, uint32_t len)
2234 {
2235  int cnt = 0;
2236  uint64_t last_re = 0;
2237  StreamingBufferBlock *sbb = NULL;
2238  RB_FOREACH(sbb, SBB, &stream->sb.sbb_tree)
2239  {
2240  if (sbb->offset != last_re) {
2241  // gap before us
2242  cnt++;
2243  }
2244 
2245  if (cnt == pos && sbb->offset == offset) {
2246  const uint8_t *buf = NULL;
2247  uint32_t buf_len = 0;
2248  StreamingBufferSBBGetData(&stream->sb, sbb, &buf, &buf_len);
2249 
2250  if (len == buf_len) {
2251  return (memcmp(data, buf, len) == 0);
2252  }
2253  }
2254 
2255  last_re = sbb->offset + sbb->len;
2256  cnt++;
2257  }
2258  return 0;
2259 }
2260 
2261 /**
2262  * \test Test the handling of packets missed by both IDS and the end host.
2263  * The packet is missed in the starting of the stream.
2264  *
2265  * \retval On success it returns 1 and on failure 0.
2266  */
2267 
2268 static int StreamTcpReassembleTest25 (void)
2269 {
2270  MISSED_START(6);
2271  MISSED_ADD_PAYLOAD(10, "BB", 2);
2272  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2273  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "BB", 2) == 1);
2274  MISSED_ADD_PAYLOAD(12, "CC", 2);
2275  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2276  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "BBCC", 4) == 1);
2277  MISSED_STEP(7, "AAA", 3, "AAABBCC", 7);
2278  MISSED_END;
2279  PASS;
2280 }
2281 
2282 /**
2283  * \test Test the handling of packets missed by both IDS and the end host.
2284  * The packet is missed in the middle of the stream.
2285  *
2286  * \retval On success it returns 1 and on failure 0.
2287  */
2288 
2289 static int StreamTcpReassembleTest26 (void)
2290 {
2291  MISSED_START(9);
2292  MISSED_STEP(10, "AAA", 3, "AAA", 3);
2293  MISSED_ADD_PAYLOAD(15, "CC", 2);
2294  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 0, 0, "AAA", 3) == 1);
2295  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 1, 3, 2) == 1);
2296  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 2, 5, "CC", 2) == 1);
2297  MISSED_STEP(13, "BB", 2, "AAABBCC", 7);
2298  MISSED_END;
2299 }
2300 
2301 /**
2302  * \test Test the handling of packets missed by both IDS and the end host.
2303  * The packet is missed in the end of the stream.
2304  *
2305  * \retval On success it returns 1 and on failure 0.
2306  */
2307 
2308 static int StreamTcpReassembleTest27 (void)
2309 {
2310  MISSED_START(9);
2311  MISSED_STEP(10, "AAA", 3, "AAA", 3);
2312  MISSED_STEP(13, "BB", 2, "AAABB", 5);
2313  MISSED_STEP(15, "CC", 2, "AAABBCC", 7);
2314  MISSED_END;
2315 }
2316 
2317 /**
2318  * \test Test the handling of packets missed by IDS, but the end host has
2319  * received it and send the acknowledgment of it. The packet is missed
2320  * in the starting of the stream.
2321  *
2322  * \retval On success it returns 1 and on failure 0.
2323  */
2324 
2325 static int StreamTcpReassembleTest28 (void)
2326 {
2327  MISSED_START(6);
2328  MISSED_ADD_PAYLOAD(10, "AAA", 3);
2329  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2330  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAA", 3) == 1);
2331  MISSED_ADD_PAYLOAD(13, "BB", 2);
2332  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2333  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAABB", 5) == 1);
2334  ssn.state = TCP_TIME_WAIT;
2335  MISSED_ADD_PAYLOAD(15, "CC", 2);
2336  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 0, 0, 3) == 1);
2337  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 1, 3, "AAABBCC", 7) == 1);
2338  MISSED_END;
2339 }
2340 
2341 /**
2342  * \test Test the handling of packets missed by IDS, but the end host has
2343  * received it and send the acknowledgment of it. The packet is missed
2344  * in the middle of the stream.
2345  *
2346  * \retval On success it returns 1 and on failure 0.
2347  */
2348 
2349 static int StreamTcpReassembleTest29 (void)
2350 {
2351  MISSED_START(9);
2352  MISSED_STEP(10, "AAA", 3, "AAA", 3);
2353  ssn.state = TCP_TIME_WAIT;
2354  MISSED_ADD_PAYLOAD(15, "CC", 2);
2355  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 0, 0, "AAA", 3) == 1);
2356  FAIL_IF_NOT(UTHCheckGapAtPosition(stream, 1, 3, 2) == 1);
2357  FAIL_IF_NOT(UTHCheckDataAtPosition(stream, 2, 5, "CC", 2) == 1);
2358  MISSED_END;
2359 }
2360 
2361 static int StreamTcpReassembleTest33(void)
2362 {
2363  TcpSession ssn;
2364  Packet *p = PacketGetFromAlloc();
2365  FAIL_IF(unlikely(p == NULL));
2366  Flow f;
2367  TCPHdr tcph;
2368  TcpReassemblyThreadCtx *ra_ctx = NULL;
2370  uint8_t packet[1460] = "";
2371 
2372  StreamTcpUTInit(&ra_ctx);
2374 
2375  memset(&f, 0, sizeof (Flow));
2376  memset(&tcph, 0, sizeof (TCPHdr));
2377  ThreadVars tv;
2378  memset(&tv, 0, sizeof (ThreadVars));
2379  FLOW_INITIALIZE(&f);
2380  f.protoctx = &ssn;
2381  f.proto = IPPROTO_TCP;
2382  p->src.family = AF_INET;
2383  p->dst.family = AF_INET;
2384  p->proto = IPPROTO_TCP;
2385  p->flow = &f;
2386  tcph.th_win = 5480;
2387  tcph.th_flags = TH_PUSH | TH_ACK;
2388  UTHSetTCPHdr(p, &tcph);
2390  p->payload = packet;
2391 
2392  tcph.th_seq = htonl(10);
2393  tcph.th_ack = htonl(31);
2394  p->payload_len = 10;
2395 
2396  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2397 
2398  tcph.th_seq = htonl(20);
2399  tcph.th_ack = htonl(31);
2400  p->payload_len = 10;
2401 
2402  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2403 
2404  tcph.th_seq = htonl(40);
2405  tcph.th_ack = htonl(31);
2406  p->payload_len = 10;
2407 
2408  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2409 
2410  tcph.th_seq = htonl(5);
2411  tcph.th_ack = htonl(31);
2412  p->payload_len = 30;
2413 
2414  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2415 
2417  StreamTcpUTDeinit(ra_ctx);
2418  SCFree(p);
2419  PASS;
2420 }
2421 
2422 static int StreamTcpReassembleTest34(void)
2423 {
2424  TcpSession ssn;
2425  Packet *p = PacketGetFromAlloc();
2426  FAIL_IF(unlikely(p == NULL));
2427  Flow f;
2428  TCPHdr tcph;
2429  TcpReassemblyThreadCtx *ra_ctx = NULL;
2431  uint8_t packet[1460] = "";
2432 
2433  StreamTcpUTInit(&ra_ctx);
2435  memset(&f, 0, sizeof (Flow));
2436  memset(&tcph, 0, sizeof (TCPHdr));
2437  ThreadVars tv;
2438  memset(&tv, 0, sizeof (ThreadVars));
2439  FLOW_INITIALIZE(&f);
2440  f.protoctx = &ssn;
2441  f.proto = IPPROTO_TCP;
2442  p->src.family = AF_INET;
2443  p->dst.family = AF_INET;
2444  p->proto = IPPROTO_TCP;
2445  p->flow = &f;
2446  tcph.th_win = 5480;
2447  tcph.th_flags = TH_PUSH | TH_ACK;
2448  UTHSetTCPHdr(p, &tcph);
2450  p->payload = packet;
2451  SET_ISN(&ssn.client, 857961230);
2452 
2453  tcph.th_seq = htonl(857961230);
2454  tcph.th_ack = htonl(31);
2455  p->payload_len = 304;
2456 
2457  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2458 
2459  tcph.th_seq = htonl(857961534);
2460  tcph.th_ack = htonl(31);
2461  p->payload_len = 1460;
2462 
2463  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2464 
2465  tcph.th_seq = htonl(857963582);
2466  tcph.th_ack = htonl(31);
2467  p->payload_len = 1460;
2468 
2469  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2470 
2471  tcph.th_seq = htonl(857960946);
2472  tcph.th_ack = htonl(31);
2473  p->payload_len = 1460;
2474 
2475  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, &ssn.client, p) == -1);
2476 
2478  StreamTcpUTDeinit(ra_ctx);
2479  SCFree(p);
2480  PASS;
2481 }
2482 
2483 /**
2484  * \test Test to make sure that we don't return the segments until the app
2485  * layer proto has been detected and after that remove the processed
2486  * segments.
2487  *
2488  * \retval On success it returns 1 and on failure 0.
2489  */
2490 
2491 static int StreamTcpReassembleTest39 (void)
2492 {
2493  Packet *p = PacketGetFromAlloc();
2494  FAIL_IF(unlikely(p == NULL));
2495  Flow f;
2496  ThreadVars tv;
2497  StreamTcpThread stt;
2498  TCPHdr tcph;
2499  PacketQueueNoLock pq;
2500  memset(&pq,0,sizeof(PacketQueueNoLock));
2501  memset (&f, 0, sizeof(Flow));
2502  memset(&tv, 0, sizeof (ThreadVars));
2503  memset(&stt, 0, sizeof (stt));
2504  memset(&tcph, 0, sizeof (TCPHdr));
2505 
2506  FLOW_INITIALIZE(&f);
2507  f.flags = FLOW_IPV4;
2508  f.proto = IPPROTO_TCP;
2509  p->flow = &f;
2510  UTHSetTCPHdr(p, &tcph);
2511 
2512  StreamTcpUTInit(&stt.ra_ctx);
2513 
2514  /* handshake */
2515  tcph.th_win = htons(5480);
2516  tcph.th_flags = TH_SYN;
2518  p->payload_len = 0;
2519  p->payload = NULL;
2520  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2521 
2522  TcpSession *ssn = (TcpSession *)f.protoctx;
2523  FAIL_IF_NULL(ssn);
2524 
2531  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2532  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2533  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2534  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2535  FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
2536  FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2537  FAIL_IF(ssn->data_first_seen_dir != 0);
2538 
2539  /* handshake */
2540  tcph.th_ack = htonl(1);
2541  tcph.th_flags = TH_SYN | TH_ACK;
2543  p->payload_len = 0;
2544  p->payload = NULL;
2545  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2552  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2553  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2554  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2555  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2556  FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
2557  FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2558  FAIL_IF(ssn->data_first_seen_dir != 0);
2559 
2560  /* handshake */
2561  tcph.th_ack = htonl(1);
2562  tcph.th_seq = htonl(1);
2563  tcph.th_flags = TH_ACK;
2565  p->payload_len = 0;
2566  p->payload = NULL;
2567  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2574  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2575  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2576  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2577  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2578  FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
2579  FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2580  FAIL_IF(ssn->data_first_seen_dir != 0);
2581 
2582  /* partial request */
2583  uint8_t request1[] = { 0x47, 0x45, };
2584  tcph.th_ack = htonl(1);
2585  tcph.th_seq = htonl(1);
2586  tcph.th_flags = TH_PUSH | TH_ACK;
2588  p->payload_len = sizeof(request1);
2589  p->payload = request1;
2590  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2597  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2598  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2599  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2600  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2601  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2602  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2603  FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2604  FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
2605 
2606  /* response ack against partial request */
2607  tcph.th_ack = htonl(3);
2608  tcph.th_seq = htonl(1);
2609  tcph.th_flags = TH_ACK;
2611  p->payload_len = 0;
2612  p->payload = NULL;
2613  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2620  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2621  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2622  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2623  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2624  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2625  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2626  FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2627  FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
2628 
2629  /* complete partial request */
2630  uint8_t request2[] = {
2631  0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64,
2632  0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20,
2633  0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30,
2634  0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20,
2635  0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73,
2636  0x74, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d,
2637  0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x41,
2638  0x70, 0x61, 0x63, 0x68, 0x65, 0x42, 0x65, 0x6e,
2639  0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a,
2640  0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20,
2641  0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a };
2642  tcph.th_ack = htonl(1);
2643  tcph.th_seq = htonl(3);
2644  tcph.th_flags = TH_PUSH | TH_ACK;
2646  p->payload_len = sizeof(request2);
2647  p->payload = request2;
2648  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2655  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2656  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2657  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2658  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2659  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2660  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2661  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2662  FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
2663  FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
2664 
2665  /* response - request ack */
2666  uint8_t response[] = {
2667  0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31,
2668  0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d,
2669  0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x46,
2670  0x72, 0x69, 0x2c, 0x20, 0x32, 0x33, 0x20, 0x53,
2671  0x65, 0x70, 0x20, 0x32, 0x30, 0x31, 0x31, 0x20,
2672  0x30, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x39,
2673  0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65,
2674  0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x41, 0x70,
2675  0x61, 0x63, 0x68, 0x65, 0x2f, 0x32, 0x2e, 0x32,
2676  0x2e, 0x31, 0x35, 0x20, 0x28, 0x55, 0x6e, 0x69,
2677  0x78, 0x29, 0x20, 0x44, 0x41, 0x56, 0x2f, 0x32,
2678  0x0d, 0x0a, 0x4c, 0x61, 0x73, 0x74, 0x2d, 0x4d,
2679  0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x3a,
2680  0x20, 0x54, 0x68, 0x75, 0x2c, 0x20, 0x30, 0x34,
2681  0x20, 0x4e, 0x6f, 0x76, 0x20, 0x32, 0x30, 0x31,
2682  0x30, 0x20, 0x31, 0x35, 0x3a, 0x30, 0x34, 0x3a,
2683  0x34, 0x36, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a,
2684  0x45, 0x54, 0x61, 0x67, 0x3a, 0x20, 0x22, 0x61,
2685  0x62, 0x38, 0x39, 0x36, 0x35, 0x2d, 0x32, 0x63,
2686  0x2d, 0x34, 0x39, 0x34, 0x33, 0x62, 0x37, 0x61,
2687  0x37, 0x66, 0x37, 0x66, 0x38, 0x30, 0x22, 0x0d,
2688  0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d,
2689  0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x3a, 0x20,
2690  0x62, 0x79, 0x74, 0x65, 0x73, 0x0d, 0x0a, 0x43,
2691  0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c,
2692  0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x34,
2693  0x34, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
2694  0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63,
2695  0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, 0x43, 0x6f,
2696  0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79,
2697  0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74,
2698  0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x58,
2699  0x2d, 0x50, 0x61, 0x64, 0x3a, 0x20, 0x61, 0x76,
2700  0x6f, 0x69, 0x64, 0x20, 0x62, 0x72, 0x6f, 0x77,
2701  0x73, 0x65, 0x72, 0x20, 0x62, 0x75, 0x67, 0x0d,
2702  0x0a, 0x0d, 0x0a, 0x3c, 0x68, 0x74, 0x6d, 0x6c,
2703  0x3e, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c,
2704  0x68, 0x31, 0x3e, 0x49, 0x74, 0x20, 0x77, 0x6f,
2705  0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31,
2706  0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e,
2707  0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e };
2708  tcph.th_ack = htonl(88);
2709  tcph.th_seq = htonl(1);
2710  tcph.th_flags = TH_PUSH | TH_ACK;
2712  p->payload_len = sizeof(response);
2713  p->payload = response;
2714 
2715  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2722  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2723  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2724  FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2725  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2727  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2728  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2729  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2730  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2731 
2732  /* response ack from request */
2733  tcph.th_ack = htonl(328);
2734  tcph.th_seq = htonl(88);
2735  tcph.th_flags = TH_ACK;
2737  p->payload_len = 0;
2738  p->payload = NULL;
2739  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2746  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2747  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2748  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2749  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2751  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2752  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2753  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2754  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2755  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2756 
2757  /* response - acking */
2758  tcph.th_ack = htonl(88);
2759  tcph.th_seq = htonl(328);
2760  tcph.th_flags = TH_PUSH | TH_ACK;
2762  p->payload_len = 0;
2763  p->payload = NULL;
2764  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2771  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2772  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2773  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2774  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2776  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2777  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2778  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2779  FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2780  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2781 
2782  /* response ack from request */
2783  tcph.th_ack = htonl(328);
2784  tcph.th_seq = htonl(88);
2785  tcph.th_flags = TH_ACK;
2787  p->payload_len = 0;
2788  p->payload = NULL;
2789  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2796  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2797  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2798  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2799  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2801  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2802  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2803  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2804  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2805 
2806  /* response - acking the request again*/
2807  tcph.th_ack = htonl(88);
2808  tcph.th_seq = htonl(328);
2809  tcph.th_flags = TH_PUSH | TH_ACK;
2811  p->payload_len = 0;
2812  p->payload = NULL;
2813  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2820  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2821  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2822  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2823  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2825  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2826  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2827  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2828  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2829 
2830  /*** New Request ***/
2831 
2832  /* partial request */
2833  tcph.th_ack = htonl(328);
2834  tcph.th_seq = htonl(88);
2835  tcph.th_flags = TH_PUSH | TH_ACK;
2837  p->payload_len = sizeof(request1);
2838  p->payload = request1;
2839  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2846  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2847  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2848  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2849  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2851  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2852  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2853  FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2854  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2855  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2856 
2857  /* response ack against partial request */
2858  tcph.th_ack = htonl(90);
2859  tcph.th_seq = htonl(328);
2860  tcph.th_flags = TH_ACK;
2862  p->payload_len = 0;
2863  p->payload = NULL;
2864  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2865  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2872  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2873  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2874  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2875  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2877  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2878  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2879  FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2880  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2881  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2882 
2883  /* complete request */
2884  tcph.th_ack = htonl(328);
2885  tcph.th_seq = htonl(90);
2886  tcph.th_flags = TH_PUSH | TH_ACK;
2888  p->payload_len = sizeof(request2);
2889  p->payload = request2;
2890  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2897  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2898  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2899  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2900  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2902  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2903  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2904  FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2905  FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
2906  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2907  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2908 
2909  /* response ack against second partial request */
2910  tcph.th_ack = htonl(175);
2911  tcph.th_seq = htonl(328);
2912  tcph.th_flags = TH_ACK;
2914  p->payload_len = 0;
2915  p->payload = NULL;
2916 
2917  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2924  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
2925  FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
2926  FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
2927  FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
2929  FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
2930  FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
2931  FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
2932  FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
2933  FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
2934  FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
2935 
2936  /* response acking a request */
2937  tcph.th_ack = htonl(175);
2938  tcph.th_seq = htonl(328);
2939  tcph.th_flags = TH_ACK;
2941  p->payload_len = 0;
2942  p->payload = NULL;
2943  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2949 
2950  StreamTcpPruneSession(&f, STREAM_TOSERVER);
2951  StreamTcpPruneSession(&f, STREAM_TOCLIENT);
2952 
2953  /* request acking a response */
2954  tcph.th_ack = htonl(328);
2955  tcph.th_seq = htonl(175);
2956  tcph.th_flags = TH_ACK;
2958  p->payload_len = 0;
2959  p->payload = NULL;
2960  FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
2961 
2962  StreamTcpSessionClear(ssn);
2964  SCFree(p);
2965  PASS;
2966 }
2967 
2968 /**
2969  * \test Test to make sure that we sent all the segments from the initial
2970  * segments to app layer until we have detected the app layer proto.
2971  *
2972  * \retval On success it returns 1 and on failure 0.
2973  */
2974 
2975 static int StreamTcpReassembleTest40 (void)
2976 {
2977  Packet *p = PacketGetFromAlloc();
2978  FAIL_IF_NULL(p);
2979  Flow *f = NULL;
2980  TCPHdr tcph;
2981  TcpSession ssn;
2982  memset(&tcph, 0, sizeof (TCPHdr));
2983  ThreadVars tv;
2984  memset(&tv, 0, sizeof (ThreadVars));
2985 
2986  StreamTcpInitConfig(true);
2988 
2990  FAIL_IF_NULL(ra_ctx);
2991 
2992  uint8_t httpbuf1[] = "P";
2993  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
2994  uint8_t httpbuf3[] = "O";
2995  uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
2996  uint8_t httpbuf4[] = "S";
2997  uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
2998  uint8_t httpbuf5[] = "T \r\n";
2999  uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
3000 
3001  uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
3002  uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
3003 
3004  SET_ISN(&ssn.server, 9);
3005  ssn.server.last_ack = 10;
3006  SET_ISN(&ssn.client, 9);
3007  ssn.client.isn = 9;
3008 
3009  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
3010  FAIL_IF_NULL(f);
3011  f->protoctx = &ssn;
3012  f->proto = IPPROTO_TCP;
3013  p->flow = f;
3014 
3015  tcph.th_win = htons(5480);
3016  tcph.th_seq = htonl(10);
3017  tcph.th_ack = htonl(10);
3018  tcph.th_flags = TH_ACK|TH_PUSH;
3019  UTHSetTCPHdr(p, &tcph);
3021  p->payload = httpbuf1;
3022  p->payload_len = httplen1;
3023  ssn.state = TCP_ESTABLISHED;
3024  TcpStream *s = &ssn.client;
3025  SCLogDebug("1 -- start");
3026  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3027 
3029  p->payload = httpbuf2;
3030  p->payload_len = httplen2;
3031  tcph.th_seq = htonl(10);
3032  tcph.th_ack = htonl(11);
3033  s = &ssn.server;
3034  ssn.server.last_ack = 11;
3035  SCLogDebug("2 -- start");
3036  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3037 
3039  p->payload = httpbuf3;
3040  p->payload_len = httplen3;
3041  tcph.th_seq = htonl(11);
3042  tcph.th_ack = htonl(55);
3043  s = &ssn.client;
3044  ssn.client.last_ack = 55;
3045  SCLogDebug("3 -- start");
3046  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3047 
3049  p->payload = httpbuf2;
3050  p->payload_len = httplen2;
3051  tcph.th_seq = htonl(55);
3052  tcph.th_ack = htonl(12);
3053  s = &ssn.server;
3054  ssn.server.last_ack = 12;
3055  SCLogDebug("4 -- start");
3056  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3057 
3058  /* check is have the segment in the list and flagged or not */
3059  TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3060  FAIL_IF_NULL(seg);
3061  FAIL_IF(SEGMENT_BEFORE_OFFSET(&ssn.client, seg, STREAM_APP_PROGRESS(&ssn.client)));
3062 
3064  p->payload = httpbuf4;
3065  p->payload_len = httplen4;
3066  tcph.th_seq = htonl(12);
3067  tcph.th_ack = htonl(100);
3068  s = &ssn.client;
3069  ssn.client.last_ack = 100;
3070  SCLogDebug("5 -- start");
3071  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3072 
3074  p->payload = httpbuf2;
3075  p->payload_len = httplen2;
3076  tcph.th_seq = htonl(100);
3077  tcph.th_ack = htonl(13);
3078  s = &ssn.server;
3079  ssn.server.last_ack = 13;
3080  SCLogDebug("6 -- start");
3081  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3082 
3084  p->payload = httpbuf5;
3085  p->payload_len = httplen5;
3086  tcph.th_seq = htonl(13);
3087  tcph.th_ack = htonl(145);
3088  s = &ssn.client;
3089  ssn.client.last_ack = 145;
3090  SCLogDebug("7 -- start");
3091  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3092 
3094  p->payload = httpbuf2;
3095  p->payload_len = httplen2;
3096  tcph.th_seq = htonl(145);
3097  tcph.th_ack = htonl(16);
3098  s = &ssn.server;
3099  ssn.server.last_ack = 16;
3100  SCLogDebug("8 -- start");
3101  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3102  FAIL_IF(f->alproto != ALPROTO_HTTP1);
3103 
3106  StreamTcpFreeConfig(true);
3107  SCFree(p);
3108  UTHFreeFlow(f);
3109  PASS;
3110 }
3111 
3112 /** \test Test the memcap incrementing/decrementing and memcap check */
3113 static int StreamTcpReassembleTest44(void)
3114 {
3115  StreamTcpInitConfig(true);
3116  uint32_t memuse = SC_ATOMIC_GET(ra_memuse);
3118  FAIL_IF(SC_ATOMIC_GET(ra_memuse) != (memuse+500));
3120  FAIL_IF(SC_ATOMIC_GET(ra_memuse) != memuse);
3122  FAIL_IF(StreamTcpReassembleCheckMemcap((1 + memuse + SC_ATOMIC_GET(stream_config.reassembly_memcap))) != 0);
3123  StreamTcpFreeConfig(true);
3124  FAIL_IF(SC_ATOMIC_GET(ra_memuse) != 0);
3125  PASS;
3126 }
3127 
3128 /**
3129  * \test Test to make sure that reassembly_depth is enforced.
3130  *
3131  * \retval On success it returns 1 and on failure 0.
3132  */
3133 
3134 static int StreamTcpReassembleTest45 (void)
3135 {
3136  TcpReassemblyThreadCtx *ra_ctx = NULL;
3137  TcpSession ssn;
3138  ThreadVars tv;
3139  memset(&tv, 0, sizeof(tv));
3140  uint8_t payload[100] = {0};
3141  uint16_t payload_size = 100;
3142 
3143  StreamTcpUTInit(&ra_ctx);
3145 
3147  ssn.reassembly_depth = 100;
3148  StreamTcpUTSetupStream(&ssn.server, 100);
3149  StreamTcpUTSetupStream(&ssn.client, 100);
3150 
3151  int r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size);
3152  FAIL_IF(r != 0);
3154 
3155  r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size);
3156  FAIL_IF(r != 0);
3158 
3162  StreamTcpUTDeinit(ra_ctx);
3163  PASS;
3164 }
3165 
3166 /**
3167  * \test Test the unlimited config value of reassembly depth.
3168  *
3169  * \retval On success it returns 1 and on failure 0.
3170  */
3171 
3172 static int StreamTcpReassembleTest46 (void)
3173 {
3174  int result = 0;
3175  TcpReassemblyThreadCtx *ra_ctx = NULL;
3176  TcpSession ssn;
3177  ThreadVars tv;
3178  memset(&tv, 0, sizeof(tv));
3179  uint8_t payload[100] = {0};
3180  uint16_t payload_size = 100;
3181 
3182  StreamTcpUTInit(&ra_ctx);
3184 
3186  StreamTcpUTSetupStream(&ssn.server, 100);
3187  StreamTcpUTSetupStream(&ssn.client, 100);
3188 
3189  int r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size);
3190  if (r != 0)
3191  goto end;
3193  printf("STREAMTCP_STREAM_FLAG_NOREASSEMBLY set: ");
3194  goto end;
3195  }
3196 
3197  r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size);
3198  if (r != 0)
3199  goto end;
3201  printf("STREAMTCP_STREAM_FLAG_NOREASSEMBLY set: ");
3202  goto end;
3203  }
3204 
3205  result = 1;
3206 end:
3210  StreamTcpUTDeinit(ra_ctx);
3211  return result;
3212 }
3213 
3214 /**
3215  * \test Test to make sure we detect the sequence wrap around and continue
3216  * stream reassembly properly.
3217  *
3218  * \retval On success it returns 1 and on failure 0.
3219  */
3220 
3221 static int StreamTcpReassembleTest47 (void)
3222 {
3223  Packet *p = PacketGetFromAlloc();
3224  FAIL_IF(unlikely(p == NULL));
3225  Flow *f = NULL;
3226  TCPHdr tcph;
3227  TcpSession ssn;
3228  ThreadVars tv;
3229  memset(&tcph, 0, sizeof (TCPHdr));
3230  UTHSetTCPHdr(p, &tcph);
3231  memset(&tv, 0, sizeof (ThreadVars));
3232  StreamTcpInitConfig(true);
3235 
3236  uint8_t httpbuf1[] = "GET /EVILSUFF HTTP/1.1\r\n\r\n";
3237  uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
3238 
3239  SET_ISN(&ssn.server, 572799781UL);
3240  ssn.server.last_ack = 572799782UL;
3241 
3242  SET_ISN(&ssn.client, 4294967289UL);
3243  ssn.client.last_ack = 21;
3244 
3245  f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
3246  FAIL_IF(f == NULL);
3247  f->protoctx = &ssn;
3248  f->proto = IPPROTO_TCP;
3249  p->flow = f;
3250 
3251  tcph.th_win = htons(5480);
3252  ssn.state = TCP_ESTABLISHED;
3253  TcpStream *s = NULL;
3254  uint8_t cnt = 0;
3255 
3256  for (cnt=0; cnt < httplen1; cnt++) {
3257  tcph.th_seq = htonl(ssn.client.isn + 1 + cnt);
3258  tcph.th_ack = htonl(572799782UL);
3259  tcph.th_flags = TH_ACK | TH_PUSH;
3261  p->payload = &httpbuf1[cnt];
3262  p->payload_len = 1;
3263  s = &ssn.client;
3264 
3265  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3266 
3268  p->payload = NULL;
3269  p->payload_len = 0;
3270  tcph.th_seq = htonl(572799782UL);
3271  tcph.th_ack = htonl(ssn.client.isn + 1 + cnt);
3272  tcph.th_flags = TH_ACK;
3273  s = &ssn.server;
3274 
3275  FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p) == -1);
3276  }
3277 
3278  FAIL_IF(f->alproto != ALPROTO_HTTP1);
3279 
3282  StreamTcpFreeConfig(true);
3283  SCFree(p);
3284  UTHFreeFlow(f);
3285  PASS;
3286 }
3287 
3288 /** \test 3 in order segments in inline reassembly */
3289 static int StreamTcpReassembleInlineTest01(void)
3290 {
3291  int ret = 0;
3292  TcpReassemblyThreadCtx *ra_ctx = NULL;
3293  ThreadVars tv;
3294  TcpSession ssn;
3295  Flow f;
3296 
3297  memset(&tv, 0x00, sizeof(tv));
3298 
3299  StreamTcpUTInit(&ra_ctx);
3302  StreamTcpUTSetupStream(&ssn.client, 1);
3303  FLOW_INITIALIZE(&f);
3304 
3305  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3306  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3307  if (p == NULL) {
3308  printf("couldn't get a packet: ");
3309  goto end;
3310  }
3311  p->l4.hdrs.tcph->th_seq = htonl(12);
3312  p->flow = &f;
3313 
3314  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) {
3315  printf("failed to add segment 1: ");
3316  goto end;
3317  }
3318  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) {
3319  printf("failed to add segment 2: ");
3320  goto end;
3321  }
3322  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3323  printf("failed to add segment 3: ");
3324  goto end;
3325  }
3326  ssn.client.next_seq = 17;
3327  ret = 1;
3328 end:
3329  FLOW_DESTROY(&f);
3330  UTHFreePacket(p);
3332  StreamTcpUTDeinit(ra_ctx);
3333  return ret;
3334 }
3335 
3336 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3337  * test the sliding window reassembly.
3338  */
3339 static int StreamTcpReassembleInlineTest02(void)
3340 {
3341  int ret = 0;
3342  TcpReassemblyThreadCtx *ra_ctx = NULL;
3343  ThreadVars tv;
3344  TcpSession ssn;
3345  Flow f;
3346 
3347  memset(&tv, 0x00, sizeof(tv));
3348 
3349  StreamTcpUTInit(&ra_ctx);
3352  StreamTcpUTSetupStream(&ssn.client, 1);
3353  FLOW_INITIALIZE(&f);
3354 
3355  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3356  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3357  if (p == NULL) {
3358  printf("couldn't get a packet: ");
3359  goto end;
3360  }
3361  p->l4.hdrs.tcph->th_seq = htonl(12);
3362  p->flow = &f;
3363 
3364  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) {
3365  printf("failed to add segment 1: ");
3366  goto end;
3367  }
3368  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) {
3369  printf("failed to add segment 2: ");
3370  goto end;
3371  }
3372  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3373  printf("failed to add segment 3: ");
3374  goto end;
3375  }
3376  ssn.client.next_seq = 17;
3377  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3378  printf("failed to add segment 4: ");
3379  goto end;
3380  }
3381  ssn.client.next_seq = 22;
3382  ret = 1;
3383 end:
3384  FLOW_DESTROY(&f);
3385  UTHFreePacket(p);
3387  StreamTcpUTDeinit(ra_ctx);
3388  return ret;
3389 }
3390 
3391 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3392  * test the sliding window reassembly with a small window size so that we
3393  * cutting off at the start (left edge)
3394  */
3395 static int StreamTcpReassembleInlineTest03(void)
3396 {
3397  int ret = 0;
3398  TcpReassemblyThreadCtx *ra_ctx = NULL;
3399  ThreadVars tv;
3400  TcpSession ssn;
3401  Flow f;
3402 
3403  memset(&tv, 0x00, sizeof(tv));
3404 
3405  StreamTcpUTInit(&ra_ctx);
3408  StreamTcpUTSetupStream(&ssn.client, 1);
3409  FLOW_INITIALIZE(&f);
3410 
3412 
3413  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3414  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3415  if (p == NULL) {
3416  printf("couldn't get a packet: ");
3417  goto end;
3418  }
3419  p->l4.hdrs.tcph->th_seq = htonl(12);
3420  p->flow = &f;
3422 
3423  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) {
3424  printf("failed to add segment 1: ");
3425  goto end;
3426  }
3427  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) {
3428  printf("failed to add segment 2: ");
3429  goto end;
3430  }
3431  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3432  printf("failed to add segment 3: ");
3433  goto end;
3434  }
3435  ssn.client.next_seq = 17;
3436  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3437  printf("failed to add segment 4: ");
3438  goto end;
3439  }
3440  ssn.client.next_seq = 22;
3441 
3442  p->l4.hdrs.tcph->th_seq = htonl(17);
3443  ret = 1;
3444 end:
3445  FLOW_DESTROY(&f);
3446  UTHFreePacket(p);
3448  StreamTcpUTDeinit(ra_ctx);
3449  return ret;
3450 }
3451 
3452 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3453  * test the sliding window reassembly with a small window size so that we
3454  * cutting off at the start (left edge) with small packet overlap.
3455  */
3456 static int StreamTcpReassembleInlineTest04(void)
3457 {
3458  int ret = 0;
3459  TcpReassemblyThreadCtx *ra_ctx = NULL;
3460  ThreadVars tv;
3461  TcpSession ssn;
3462  Flow f;
3463 
3464  memset(&tv, 0x00, sizeof(tv));
3465 
3466  StreamTcpUTInit(&ra_ctx);
3469  StreamTcpUTSetupStream(&ssn.client, 1);
3470  FLOW_INITIALIZE(&f);
3471 
3473 
3474  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3475  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3476  if (p == NULL) {
3477  printf("couldn't get a packet: ");
3478  goto end;
3479  }
3480  p->l4.hdrs.tcph->th_seq = htonl(12);
3481  p->flow = &f;
3483 
3484  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) {
3485  printf("failed to add segment 1: ");
3486  goto end;
3487  }
3488  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) {
3489  printf("failed to add segment 2: ");
3490  goto end;
3491  }
3492  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3493  printf("failed to add segment 3: ");
3494  goto end;
3495  }
3496  ssn.client.next_seq = 17;
3497  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3498  printf("failed to add segment 4: ");
3499  goto end;
3500  }
3501  ssn.client.next_seq = 22;
3502 
3503  p->l4.hdrs.tcph->th_seq = htonl(17);
3504  ret = 1;
3505 end:
3506  FLOW_DESTROY(&f);
3507  UTHFreePacket(p);
3509  StreamTcpUTDeinit(ra_ctx);
3510  return ret;
3511 }
3512 
3513 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3514  * test the sliding window reassembly with a small window size so that we
3515  * cutting off at the start (left edge). Test if the first segment is
3516  * removed from the list.
3517  */
3518 static int StreamTcpReassembleInlineTest08(void)
3519 {
3520  TcpReassemblyThreadCtx *ra_ctx = NULL;
3521  ThreadVars tv;
3522  memset(&tv, 0x00, sizeof(tv));
3523  TcpSession ssn;
3524  Flow f;
3525  StreamTcpUTInit(&ra_ctx);
3528  StreamTcpUTSetupStream(&ssn.client, 1);
3529  FLOW_INITIALIZE(&f);
3530 
3532  f.protoctx = &ssn;
3533 
3534  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3535  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3536  FAIL_IF(p == NULL);
3537  p->l4.hdrs.tcph->th_seq = htonl(12);
3538  p->flow = &f;
3540 
3541  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3542  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3543  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3544  ssn.client.next_seq = 17;
3545  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
3546  ssn.client.next_seq = 22;
3547  p->l4.hdrs.tcph->th_seq = htonl(17);
3548  StreamTcpPruneSession(&f, STREAM_TOSERVER);
3549 
3550  TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3551  FAIL_IF_NULL(seg);
3552  FAIL_IF_NOT(seg->seq == 2);
3553 
3554  FLOW_DESTROY(&f);
3555  UTHFreePacket(p);
3557  StreamTcpUTDeinit(ra_ctx);
3558  PASS;
3559 }
3560 
3561 /** \test 3 in order segments, then reassemble, add one more and reassemble again.
3562  * test the sliding window reassembly with a small window size so that we
3563  * cutting off at the start (left edge). Test if the first segment is
3564  * removed from the list.
3565  */
3566 static int StreamTcpReassembleInlineTest09(void)
3567 {
3568  int ret = 0;
3569  TcpReassemblyThreadCtx *ra_ctx = NULL;
3570  ThreadVars tv;
3571  TcpSession ssn;
3572  Flow f;
3573 
3574  memset(&tv, 0x00, sizeof(tv));
3575 
3576  StreamTcpUTInit(&ra_ctx);
3579  StreamTcpUTSetupStream(&ssn.client, 1);
3580  FLOW_INITIALIZE(&f);
3581 
3583 
3584  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3585  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3586  if (p == NULL) {
3587  printf("couldn't get a packet: ");
3588  goto end;
3589  }
3590  p->l4.hdrs.tcph->th_seq = htonl(17);
3591  p->flow = &f;
3593 
3594  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) {
3595  printf("failed to add segment 1: ");
3596  goto end;
3597  }
3598  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) {
3599  printf("failed to add segment 2: ");
3600  goto end;
3601  }
3602  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
3603  printf("failed to add segment 3: ");
3604  goto end;
3605  }
3606  ssn.client.next_seq = 12;
3607  ssn.client.last_ack = 10;
3608 
3609  /* close the GAP and see if we properly reassemble and update base_seq */
3610  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
3611  printf("failed to add segment 4: ");
3612  goto end;
3613  }
3614  ssn.client.next_seq = 22;
3615 
3616  p->l4.hdrs.tcph->th_seq = htonl(12);
3617 
3618  TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
3619  FAIL_IF_NULL(seg);
3620  FAIL_IF_NOT(seg->seq == 2);
3621 
3622  ret = 1;
3623 end:
3624  FLOW_DESTROY(&f);
3625  UTHFreePacket(p);
3627  StreamTcpUTDeinit(ra_ctx);
3628  return ret;
3629 }
3630 
3631 /** \test App Layer reassembly.
3632  */
3633 static int StreamTcpReassembleInlineTest10(void)
3634 {
3635  int ret = 0;
3636  TcpReassemblyThreadCtx *ra_ctx = NULL;
3637  ThreadVars tv;
3638  TcpSession ssn;
3639  Flow *f = NULL;
3640  Packet *p = NULL;
3641 
3642  memset(&tv, 0x00, sizeof(tv));
3643 
3644  StreamTcpUTInit(&ra_ctx);
3647  StreamTcpUTSetupStream(&ssn.server, 1);
3648  ssn.server.last_ack = 2;
3649  StreamTcpUTSetupStream(&ssn.client, 1);
3650  ssn.client.last_ack = 2;
3651  ssn.data_first_seen_dir = STREAM_TOSERVER;
3652 
3653  f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
3654  if (f == NULL)
3655  goto end;
3656  f->protoctx = &ssn;
3657  f->proto = IPPROTO_TCP;
3658 
3659  uint8_t stream_payload1[] = "GE";
3660  uint8_t stream_payload2[] = "T /";
3661  uint8_t stream_payload3[] = "HTTP/1.0\r\n\r\n";
3662 
3663  p = UTHBuildPacketReal(stream_payload3, 12, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3664  if (p == NULL) {
3665  printf("couldn't get a packet: ");
3666  goto end;
3667  }
3668  p->l4.hdrs.tcph->th_seq = htonl(7);
3669  p->flow = f;
3671 
3672  if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 2, stream_payload1, 2) == -1) {
3673  printf("failed to add segment 1: ");
3674  goto end;
3675  }
3676  ssn.client.next_seq = 4;
3677 
3678  int r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET);
3679  if (r < 0) {
3680  printf("StreamTcpReassembleAppLayer failed: ");
3681  goto end;
3682  }
3683 
3684  /* ssn.server.ra_app_base_seq should be isn here. */
3685  if (ssn.client.base_seq != 2 || ssn.client.base_seq != ssn.client.isn+1) {
3686  printf("expected ra_app_base_seq 1, got %u: ", ssn.client.base_seq);
3687  goto end;
3688  }
3689 
3690  if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 4, stream_payload2, 3) == -1) {
3691  printf("failed to add segment 2: ");
3692  goto end;
3693  }
3694  if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.client, 7, stream_payload3, 12) == -1) {
3695  printf("failed to add segment 3: ");
3696  goto end;
3697  }
3698  ssn.client.next_seq = 19;
3699 
3700  r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.client, p, UPDATE_DIR_PACKET);
3701  if (r < 0) {
3702  printf("StreamTcpReassembleAppLayer failed: ");
3703  goto end;
3704  }
3705 
3706  FAIL_IF_NOT(STREAM_APP_PROGRESS(&ssn.client) == 17);
3707 
3708  ret = 1;
3709 end:
3710  UTHFreePacket(p);
3712  StreamTcpUTDeinit(ra_ctx);
3713  UTHFreeFlow(f);
3714  return ret;
3715 }
3716 
3717 /** \test test insert with overlap
3718  */
3719 static int StreamTcpReassembleInsertTest01(void)
3720 {
3721  TcpReassemblyThreadCtx *ra_ctx = NULL;
3722  ThreadVars tv;
3723  TcpSession ssn;
3724  Flow f;
3725 
3726  memset(&tv, 0x00, sizeof(tv));
3727 
3728  StreamTcpUTInit(&ra_ctx);
3730  StreamTcpUTSetupStream(&ssn.client, 1);
3732  FLOW_INITIALIZE(&f);
3733 
3734  uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
3735  Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
3736  FAIL_IF(p == NULL);
3737  p->l4.hdrs.tcph->th_seq = htonl(12);
3738  p->flow = &f;
3739 
3740  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
3741  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
3742  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 14, 'D', 2) == -1);
3743  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 16, 'D', 6) == -1);
3744  FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
3745  ssn.client.next_seq = 21;
3746 
3747  FLOW_DESTROY(&f);
3748  UTHFreePacket(p);
3750  StreamTcpUTDeinit(ra_ctx);
3751  PASS;
3752 }
3753 
3754 /** \test test insert with overlaps
3755  */
3756 static int StreamTcpReassembleInsertTest02(void)
3757 {
3758  int ret = 0;
3759  TcpReassemblyThreadCtx *ra_ctx = NULL;
3760  ThreadVars tv;
3761  TcpSession ssn;
3762 
3763  memset(&tv, 0x00, sizeof(tv));
3764 
3765  StreamTcpUTInit(&ra_ctx);
3767  StreamTcpUTSetupStream(&ssn.client, 1);
3768 
3769  int i;
3770  for (i = 2; i < 10; i++) {
3771  int len;
3772  len = i % 2;
3773  if (len == 0)
3774  len = 1;
3775  int seq;
3776  seq = i * 10;
3777  if (seq < 2)
3778  seq = 2;
3779 
3780  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'A', len) == -1) {
3781  printf("failed to add segment 1: ");
3782  goto end;
3783  }
3784  }
3785  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'B', 1024) == -1) {
3786  printf("failed to add segment 2: ");
3787  goto end;
3788  }
3789 
3790  ret = 1;
3791 end:
3793  StreamTcpUTDeinit(ra_ctx);
3794  return ret;
3795 }
3796 
3797 /** \test test insert with overlaps
3798  */
3799 static int StreamTcpReassembleInsertTest03(void)
3800 {
3801  int ret = 0;
3802  TcpReassemblyThreadCtx *ra_ctx = NULL;
3803  ThreadVars tv;
3804  TcpSession ssn;
3805 
3806  memset(&tv, 0x00, sizeof(tv));
3807 
3808  StreamTcpUTInit(&ra_ctx);
3810  StreamTcpUTSetupStream(&ssn.client, 1);
3811 
3812  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 1024) == -1) {
3813  printf("failed to add segment 2: ");
3814  goto end;
3815  }
3816 
3817  int i;
3818  for (i = 2; i < 10; i++) {
3819  int len;
3820  len = i % 2;
3821  if (len == 0)
3822  len = 1;
3823  int seq;
3824  seq = i * 10;
3825  if (seq < 2)
3826  seq = 2;
3827 
3828  if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'B', len) == -1) {
3829  printf("failed to add segment 2: ");
3830  goto end;
3831  }
3832  }
3833  ret = 1;
3834 end:
3836  StreamTcpUTDeinit(ra_ctx);
3837  return ret;
3838 }
3839 
3841 #endif /* UNITTESTS */
3842 
3843 /** \brief The Function Register the Unit tests to test the reassembly engine
3844  * for various OS policies.
3845  */
3846 
3848 {
3849 #ifdef UNITTESTS
3850  UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test",
3851  StreamTcpReassembleTest25);
3852  UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test",
3853  StreamTcpReassembleTest26);
3854  UtRegisterTest("StreamTcpReassembleTest27 -- Gap at after Reassembly Test",
3855  StreamTcpReassembleTest27);
3856  UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test",
3857  StreamTcpReassembleTest28);
3858  UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test",
3859  StreamTcpReassembleTest29);
3860  UtRegisterTest("StreamTcpReassembleTest33 -- Bug test",
3861  StreamTcpReassembleTest33);
3862  UtRegisterTest("StreamTcpReassembleTest34 -- Bug test",
3863  StreamTcpReassembleTest34);
3864  UtRegisterTest("StreamTcpReassembleTest39 -- app proto test",
3865  StreamTcpReassembleTest39);
3866  UtRegisterTest("StreamTcpReassembleTest40 -- app proto test",
3867  StreamTcpReassembleTest40);
3868  UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test",
3869  StreamTcpReassembleTest44);
3870  UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test",
3871  StreamTcpReassembleTest45);
3872  UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test",
3873  StreamTcpReassembleTest46);
3874  UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test",
3875  StreamTcpReassembleTest47);
3876 
3877  UtRegisterTest("StreamTcpReassembleInlineTest01 -- inline RAW ra",
3878  StreamTcpReassembleInlineTest01);
3879  UtRegisterTest("StreamTcpReassembleInlineTest02 -- inline RAW ra 2",
3880  StreamTcpReassembleInlineTest02);
3881  UtRegisterTest("StreamTcpReassembleInlineTest03 -- inline RAW ra 3",
3882  StreamTcpReassembleInlineTest03);
3883  UtRegisterTest("StreamTcpReassembleInlineTest04 -- inline RAW ra 4",
3884  StreamTcpReassembleInlineTest04);
3885  UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup",
3886  StreamTcpReassembleInlineTest08);
3887  UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup",
3888  StreamTcpReassembleInlineTest09);
3889 
3890  UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10",
3891  StreamTcpReassembleInlineTest10);
3892 
3893  UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap",
3894  StreamTcpReassembleInsertTest01);
3895  UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap",
3896  StreamTcpReassembleInsertTest02);
3897  UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap",
3898  StreamTcpReassembleInsertTest03);
3899 
3903  StreamTcpReassembleRawRegisterTests();
3904 #endif /* UNITTESTS */
3905 }
StreamReassembleRawFunc
int(* StreamReassembleRawFunc)(void *data, const uint8_t *input, const uint32_t input_len, const uint64_t offset)
Definition: stream-tcp.h:133
StreamTcpSetEvent
#define StreamTcpSetEvent(p, e)
Definition: stream-tcp-private.h:270
APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER
#define APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER
Definition: app-layer.h:40
TCP_GET_RAW_SEQ
#define TCP_GET_RAW_SEQ(tcph)
Definition: decode-tcp.h:80
PoolThreadInit
PoolThread * PoolThreadInit(int threads, uint32_t size, uint32_t prealloc_size, uint32_t elt_size, void *(*Alloc)(void), int(*Init)(void *, void *), void *InitData, void(*Cleanup)(void *), void(*Free)(void *))
per thread Pool, initialization function
Definition: util-pool-thread.c: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:2209
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:495
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:2065
StatsIncr
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:166
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:1840
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:482
stream-tcp.h
StreamTcpInlineMode
bool StreamTcpInlineMode(void)
See if stream engine is operating in inline mode.
Definition: stream-tcp.c:7063
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:634
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:2138
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:592
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:1009
StreamTcpThread_
Definition: stream-tcp.h:80
Flow_::proto
uint8_t proto
Definition: flow.h:378
STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION
@ STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION
Definition: stream-tcp.h:179
Packet_::payload
uint8_t * payload
Definition: decode.h:571
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:2118
TcpReassemblyThreadCtx_::app_tctx
void * app_tctx
Definition: stream-tcp-reassemble.h:62
Packet_::flags
uint32_t flags
Definition: decode.h:510
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:356
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:2101
TH_FIN
#define TH_FIN
Definition: decode-tcp.h:34
TCPHdr_::th_win
uint16_t th_win
Definition: decode-tcp.h:156
TcpSegmentPcapHdrStorage
struct TcpSegmentPcapHdrStorage_ TcpSegmentPcapHdrStorage
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:332
StringParseUint16
int StringParseUint16(uint16_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:337
TCP_FIN_WAIT1
@ TCP_FIN_WAIT1
Definition: stream-tcp-private.h:156
StreamTcpReassembleAppLayer
int StreamTcpReassembleAppLayer(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p, enum StreamUpdateDir app_update_dir)
Update the stream reassembly upon receiving a packet.
Definition: stream-tcp-reassemble.c:1334
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:371
StreamTcpUtilRegisterTests
void StreamTcpUtilRegisterTests(void)
Definition: stream-tcp-util.c:247
StreamingBufferGetData
int StreamingBufferGetData(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t *stream_offset)
Definition: util-streaming-buffer.c:1786
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
AppLayerHandleTCPData
int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, Packet *p, Flow *f, TcpSession *ssn, TcpStream **stream, uint8_t *data, uint32_t data_len, uint8_t flags, enum StreamUpdateDir app_update_dir)
handle TCP data for the app-layer.
Definition: app-layer.c:708
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:232
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
UTHSetTCPHdr
void UTHSetTCPHdr(Packet *p, TCPHdr *tcph)
Definition: util-unittest-helper.c:136
StreamTcpThreadCacheGetSegment
TcpSegment * StreamTcpThreadCacheGetSegment(void)
Definition: stream-tcp-cache.c:179
TcpStream_::flags
uint16_t flags
Definition: stream-tcp-private.h:107
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
APPLAYER_PROTO_DETECTION_SKIPPED
@ APPLAYER_PROTO_DETECTION_SKIPPED
Definition: app-layer-events.h:52
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:1803
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:504
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:260
Flow_::protoctx
void * protoctx
Definition: flow.h:446
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:99
Packet_::payload_len
uint16_t payload_len
Definition: decode.h:572
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:598
util-unittest.h
TcpSegmentPcapHdrStorage_::pktlen
uint32_t pktlen
Definition: stream-tcp-private.h:67
AppLayerProfilingStore
#define AppLayerProfilingStore(app_tctx, p)
Definition: app-layer.h:128
MISSED_STEP
#define MISSED_STEP(seq, seg, seglen, buf, buflen)
Definition: stream-tcp-reassemble.c:2200
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
STREAM_HAS_UNPROCESSED_SEGMENTS_NONE
@ STREAM_HAS_UNPROCESSED_SEGMENTS_NONE
Definition: stream-tcp.h:176
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:153
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:278
TcpStream_::last_ack
uint32_t last_ack
Definition: stream-tcp-private.h:115
Flow_::alparser
AppLayerParserState * alparser
Definition: flow.h:480
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:461
UTHBuildFlow
Flow * UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
Definition: util-unittest-helper.c:482
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:155
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:234
UTHCheckDataAtPosition
int UTHCheckDataAtPosition(TcpStream *stream, int pos, uint64_t offset, const char *data, uint32_t len)
Definition: stream-tcp-reassemble.c:2232
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:279
STREAMTCP_FLAG_ASYNC
#define STREAMTCP_FLAG_ASYNC
Definition: stream-tcp-private.h:182
TCPHdr_::th_seq
uint32_t th_seq
Definition: decode-tcp.h:152
PKT_STREAM_ADD
#define PKT_STREAM_ADD
Definition: decode.h:1259
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
PKT_PSEUDO_STREAM_END
#define PKT_PSEUDO_STREAM_END
Definition: decode.h:1266
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
RB_FOREACH_SAFE
#define RB_FOREACH_SAFE(x, name, head, y)
Definition: tree.h:791
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
StreamTcpPacket
int StreamTcpPacket(ThreadVars *tv, Packet *p, StreamTcpThread *stt, PacketQueueNoLock *pq)
Definition: stream-tcp.c:5500
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:914
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:1445
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:2152
StreamTcpPruneSession
void StreamTcpPruneSession(Flow *f, uint8_t flags)
Remove idle TcpSegments from TcpSession.
Definition: stream-tcp-list.c:887
PrintRawDataFp
void PrintRawDataFp(FILE *fp, const uint8_t *buf, uint32_t buflen)
Definition: util-print.c:111
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
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:351
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:473
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
Packet_::l4
struct PacketL4 l4
Definition: decode.h:567
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:1825
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
AppLayerGetCtxThread
AppLayerThreadCtx * AppLayerGetCtxThread(void)
Creates a new app layer thread context.
Definition: app-layer.c:1059
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:233
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:251
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:104
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:487
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
UPDATE_DIR_OPPOSING
@ UPDATE_DIR_OPPOSING
Definition: stream-tcp-reassemble.h:57
StreamingBuffer_::sbb_tree
struct SBB sbb_tree
Definition: util-streaming-buffer.h:110
StreamTcpUTClearSession
void StreamTcpUTClearSession(TcpSession *ssn)
Definition: stream-tcp-util.c: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:1752
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:1696
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:512
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
SEQ_GEQ
#define SEQ_GEQ(a, b)
Definition: stream-tcp-private.h:260
StreamTcpFreeConfig
void StreamTcpFreeConfig(bool quiet)
Definition: stream-tcp.c:792
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
OS_POLICY_BSD
@ OS_POLICY_BSD
Definition: stream-tcp-reassemble.h:37
TcpStream_::base_seq
uint32_t base_seq
Definition: stream-tcp-private.h:124
STREAM_REASSEMBLY_DEPTH_REACHED
@ STREAM_REASSEMBLY_DEPTH_REACHED
Definition: decode-events.h:295
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:94
MISSED_START
#define MISSED_START(isn)
Definition: stream-tcp-reassemble.c:2181
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:507
STREAM_REASSEMBLY_SEQ_GAP
@ STREAM_REASSEMBLY_SEQ_GAP
Definition: decode-events.h:293
StreamTcpThreadCacheReturnSegment
void StreamTcpThreadCacheReturnSegment(TcpSegment *seg)
Definition: stream-tcp-cache.c:53
STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED
#define STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED
Definition: stream-tcp-private.h:236
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:1945
TCP_CLOSING
@ TCP_CLOSING
Definition: stream-tcp-private.h:161
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
StreamTcpUTAddSegmentWithPayload
int StreamTcpUTAddSegmentWithPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, uint32_t seq, uint8_t *payload, uint16_t len)
Definition: stream-tcp-util.c:113
STREAM_REASSEMBLY_NO_SEGMENT
@ STREAM_REASSEMBLY_NO_SEGMENT
Definition: decode-events.h:292
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
OS_POLICY_LAST
@ OS_POLICY_LAST
Definition: stream-tcp-reassemble.h:51
threadvars.h
util-validate.h
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:232
StreamReassembleRawUpdateProgress
void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, const uint64_t progress)
update stream engine after detection
Definition: stream-tcp-reassemble.c:1491
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
PacketL4::L4Hdrs::tcph
TCPHdr * tcph
Definition: decode.h:441
StreamTcpUTSetupSession
void StreamTcpUTSetupSession(TcpSession *ssn)
Definition: stream-tcp-util.c:62
TcpSession_::server
TcpStream server
Definition: stream-tcp-private.h:294
StreamTcpReassembleIncrMemuse
void StreamTcpReassembleIncrMemuse(uint64_t size)
Function to Increment the memory usage counter for the TCP reassembly segments.
Definition: stream-tcp-reassemble.c:114
TcpSegmentPcapHdrStorage_::pkt_hdr
uint8_t * pkt_hdr
Definition: stream-tcp-private.h:69
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
TcpSegment::pcap_hdr_storage
TcpSegmentPcapHdrStorage * pcap_hdr_storage
Definition: stream-tcp-private.h:78
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Flow_::alproto_ts
AppProto alproto_ts
Definition: flow.h:456
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:467
StreamTcpUTAddSegmentWithByte
int StreamTcpUTAddSegmentWithByte(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpStream *stream, uint32_t seq, uint8_t byte, uint16_t len)
Definition: stream-tcp-util.c:137
AppLayerDestroyCtxThread
void AppLayerDestroyCtxThread(AppLayerThreadCtx *app_tctx)
Destroys the context created by AppLayerGetCtxThread().
Definition: app-layer.c:1080
SEQ_LT
#define SEQ_LT(a, b)
Definition: stream-tcp-private.h:257
Flow_::flags
uint32_t flags
Definition: flow.h:426
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:940
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:2195
stream-tcp-cache.h
stream-tcp-util.h
TCP_TIME_WAIT
@ TCP_TIME_WAIT
Definition: stream-tcp-private.h:158
PacketL4::hdrs
union PacketL4::L4Hdrs hdrs
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
StreamTcpThread_::ra_ctx
TcpReassemblyThreadCtx * ra_ctx
Definition: stream-tcp.h:107
MISSED_ADD_PAYLOAD
#define MISSED_ADD_PAYLOAD(seq, seg, seglen)
Definition: stream-tcp-reassemble.c:2204
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:573
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:109
Packet_::dst
Address dst
Definition: decode.h:478
StreamTcpStateAsString
const char * StreamTcpStateAsString(const enum TcpState state)
Definition: stream-tcp.c:7076
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:3847
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:204
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:457
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:455
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:1905
ExceptionPolicy
ExceptionPolicy
Definition: util-exception-policy-types.h:25
FLOW_DIR_REVERSED
#define FLOW_DIR_REVERSED
Definition: flow.h:111
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
STREAMTCP_STREAM_FLAG_TRIGGER_RAW
#define STREAMTCP_STREAM_FLAG_TRIGGER_RAW
Definition: stream-tcp-private.h:225
StreamingBufferConfig_::region_gap
uint32_t region_gap
Definition: util-streaming-buffer.h:68
PoolThreadSize
int PoolThreadSize(PoolThread *pt)
get size of PoolThread (number of 'threads', so array elements)
Definition: util-pool-thread.c: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:1828
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:1660
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:102
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:149
Packet_::src
Address src
Definition: decode.h:477
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