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