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