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