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