suricata
stream-tcp-list.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2022 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /** \file
19  *
20  * Segment list functions for insertions, overlap handling, removal and
21  * more.
22  */
23 
24 #include "suricata-common.h"
25 #include "rust.h"
26 #include "stream-tcp-private.h"
27 #include "stream-tcp.h"
28 #include "stream-tcp-reassemble.h"
29 #include "stream-tcp-inline.h"
30 #include "stream-tcp-list.h"
31 #include "util-streaming-buffer.h"
32 #include "util-print.h"
33 #include "util-validate.h"
34 #include "app-layer-frames.h"
35 
36 static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg);
37 
38 static int check_overlap_different_data = 0;
39 
41 {
42  check_overlap_different_data = 1;
43 }
44 
45 /*
46  * Inserts and overlap handling
47  */
48 
50 
51 int TcpSegmentCompare(struct TcpSegment *a, struct TcpSegment *b)
52 {
53  if (SEQ_GT(a->seq, b->seq))
54  return 1;
55  else if (SEQ_LT(a->seq, b->seq))
56  return -1;
57  else {
58  if (a->payload_len == b->payload_len)
59  return 0;
60  else if (a->payload_len > b->payload_len)
61  return 1;
62  else
63  return -1;
64  }
65 }
66 
67 /** \internal
68  * \brief insert segment data into the streaming buffer
69  * \param seg segment to store stream offset in
70  * \param data segment data after overlap handling (if any)
71  * \param data_len data length
72  *
73  * \return 0 on success
74  * \return -1 on error (memory allocation error)
75  */
76 static inline int InsertSegmentDataCustom(TcpStream *stream, TcpSegment *seg, uint8_t *data, uint16_t data_len)
77 {
78  uint64_t stream_offset;
79  uint32_t data_offset;
80 
81  if (likely(SEQ_GEQ(seg->seq, stream->base_seq))) {
82  stream_offset = STREAM_BASE_OFFSET(stream) + (seg->seq - stream->base_seq);
83  data_offset = 0;
84  } else {
85  /* segment is partly before base_seq */
86  data_offset = stream->base_seq - seg->seq;
88  }
89 
90  SCLogDebug("stream %p buffer %p, stream_offset %"PRIu64", "
91  "data_offset %"PRIu16", SEQ %u BASE %u, data_len %u",
92  stream, &stream->sb, stream_offset,
93  data_offset, seg->seq, stream->base_seq, data_len);
94  DEBUG_VALIDATE_BUG_ON(data_offset > data_len);
95  if (data_len <= data_offset) {
96  SCReturnInt(0);
97  }
98 
99  int ret = StreamingBufferInsertAt(
100  &stream->sb, &seg->sbseg, data + data_offset, data_len - data_offset, stream_offset);
101  if (ret != 0) {
102  /* StreamingBufferInsertAt can return -2 only if the offset is wrong, which should be
103  * impossible in this path. */
104  DEBUG_VALIDATE_BUG_ON(ret != -1);
105  SCReturnInt(-1);
106  }
107 #ifdef DEBUG
108  {
109  const uint8_t *mydata;
110  uint32_t mydata_len;
111  uint64_t mydata_offset;
112  StreamingBufferGetData(&stream->sb, &mydata, &mydata_len, &mydata_offset);
113 
114  SCLogDebug("stream %p seg %p data in buffer %p of len %u and offset %"PRIu64,
115  stream, seg, &stream->sb, mydata_len, mydata_offset);
116  //PrintRawDataFp(stdout, mydata, mydata_len);
117  }
118 #endif
119  SCReturnInt(0);
120 }
121 
122 /** \internal
123  * \brief check if this segments overlaps with an in-tree seg.
124  * \retval true
125  * \retval false
126  */
127 static inline bool CheckOverlap(struct TCPSEG *tree, TcpSegment *seg)
128 {
129  const uint32_t re = SEG_SEQ_RIGHT_EDGE(seg);
130  SCLogDebug("start. SEQ %u payload_len %u. Right edge: %u. Seg %p",
131  seg->seq, seg->payload_len, re, seg);
132 
133  /* check forward */
134  TcpSegment *next = TCPSEG_RB_NEXT(seg);
135  if (next) {
136  // next has same seq, so data must overlap
137  if (SEQ_EQ(next->seq, seg->seq))
138  return true;
139  // our right edge is beyond next seq, overlap
140  if (SEQ_GT(re, next->seq))
141  return true;
142  }
143  /* check backwards */
144  TcpSegment *prev = TCPSEG_RB_PREV(seg);
145  if (prev) {
146  // prev has same seq, so data must overlap
147  if (SEQ_EQ(prev->seq, seg->seq))
148  return true;
149  // prev's right edge is beyond our seq, overlap
150  const uint32_t prev_re = SEG_SEQ_RIGHT_EDGE(prev);
151  if (SEQ_GT(prev_re, seg->seq))
152  return true;
153  }
154 
155  SCLogDebug("no overlap");
156  return false;
157 }
158 
159 /** \internal
160  * \brief insert the segment into the proper place in the tree
161  * don't worry about the data or overlaps
162  *
163  * \retval 2 not inserted, data overlap
164  * \retval 1 inserted with overlap detected
165  * \retval 0 inserted, no overlap
166  */
167 static int DoInsertSegment (TcpStream *stream, TcpSegment *seg, TcpSegment **dup_seg, Packet *p)
168 {
169  BUG_ON(SEQ_LEQ(SEG_SEQ_RIGHT_EDGE(seg), stream->base_seq));
170 
171  /* fast track */
172  if (RB_EMPTY(&stream->seg_tree)) {
173  SCLogDebug("empty tree, inserting seg %p seq %" PRIu32 ", "
174  "len %" PRIu32 "", seg, seg->seq, TCP_SEG_LEN(seg));
175  TCPSEG_RB_INSERT(&stream->seg_tree, seg);
176  stream->segs_right_edge = SEG_SEQ_RIGHT_EDGE(seg);
177  return 0;
178  }
179 
180  /* insert and then check if there was any overlap with other segments */
181  TcpSegment *res = TCPSEG_RB_INSERT(&stream->seg_tree, seg);
182  if (res) {
183  SCLogDebug("seg has a duplicate in the tree seq %u/%u",
184  res->seq, res->payload_len);
185  /* exact duplicate SEQ + payload_len */
186  *dup_seg = res;
187  return 2; // duplicate has overlap by definition.
188  } else {
189  if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg), stream->segs_right_edge))
190  stream->segs_right_edge = SEG_SEQ_RIGHT_EDGE(seg);
191 
192  /* insert succeeded, now check if we overlap with someone */
193  if (CheckOverlap(&stream->seg_tree, seg) == true) {
194  SCLogDebug("seg %u has overlap in the tree", seg->seq);
195  return 1;
196  }
197  }
198  SCLogDebug("seg %u: no overlap", seg->seq);
199  return 0;
200 }
201 
202 /** \internal
203  * \brief handle overlap per list segment
204  *
205  * For a list segment handle the overlap according to the policy.
206  *
207  * The 'buf' parameter points to the memory that will be inserted into
208  * the stream after the overlap checks are complete. As it will
209  * unconditionally overwrite whats in the stream now, the overlap
210  * policies are applied to this buffer. It starts with the 'new' data,
211  * so when the policy states 'old' data has to be used, 'buf' is
212  * updated to contain the 'old' data here.
213  *
214  * \param buf stack allocated buffer sized p->payload_len that will be
215  * inserted into the stream buffer
216  *
217  * \retval 1 if data was different
218  * \retval 0 data was the same or we didn't check for differences
219  */
220 static int DoHandleDataOverlap(TcpStream *stream, const TcpSegment *list,
221  const TcpSegment *seg, uint8_t *buf, Packet *p)
222 {
223  SCLogDebug("handle overlap for segment %p seq %u len %u re %u, "
224  "list segment %p seq %u len %u re %u", seg, seg->seq,
226  list, list->seq, TCP_SEG_LEN(list), SEG_SEQ_RIGHT_EDGE(list));
227 
228  int data_is_different = 0;
229  int use_new_data = 0;
230 
231  if (StreamTcpInlineMode()) {
232  SCLogDebug("inline mode");
233  if (StreamTcpInlineSegmentCompare(stream, p, list) != 0) {
234  SCLogDebug("already accepted data not the same as packet data, rewrite packet");
235  StreamTcpInlineSegmentReplacePacket(stream, p, list);
236  data_is_different = 1;
237 
238  /* in inline mode we check for different data unconditionally,
239  * but setting events still depends on config */
240  if (check_overlap_different_data) {
242  }
243  }
244 
245  /* IDS mode */
246  } else {
247  if (check_overlap_different_data) {
248  if (StreamTcpInlineSegmentCompare(stream, p, list) != 0) {
249  SCLogDebug("data is different from what is in the list");
250  data_is_different = 1;
251  }
252  } else {
253  /* if we're not checking, assume it's different */
254  data_is_different = 1;
255  }
256 
257  /* apply overlap policies */
258 
259  if (stream->os_policy == OS_POLICY_LAST) {
260  /* buf will start with LAST data (from the segment),
261  * so if policy is LAST we're now done here. */
262  return (check_overlap_different_data && data_is_different);
263  }
264 
265  /* start at the same seq */
266  if (SEQ_EQ(seg->seq, list->seq)) {
267  SCLogDebug("seg starts at list segment");
268 
269  if (SEQ_LT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
270  SCLogDebug("seg ends before list end, end overlapped by list");
271  } else {
272  if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
273  SCLogDebug("seg ends beyond list end, list overlapped and more");
274  switch (stream->os_policy) {
275  case OS_POLICY_LINUX:
276  if (data_is_different) {
277  use_new_data = 1;
278  }
279  break;
280  }
281  } else {
282  SCLogDebug("full overlap");
283  }
284 
285  switch (stream->os_policy) {
286  case OS_POLICY_OLD_LINUX:
287  case OS_POLICY_SOLARIS:
288  case OS_POLICY_HPUX11:
289  if (data_is_different) {
290  use_new_data = 1;
291  }
292  break;
293  }
294  }
295 
296  /* new seg starts before list segment */
297  } else if (SEQ_LT(seg->seq, list->seq)) {
298  SCLogDebug("seg starts before list segment");
299 
300  if (SEQ_LT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
301  SCLogDebug("seg ends before list end, end overlapped by list");
302  } else {
303  if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
304  SCLogDebug("seg starts before and fully overlaps list and beyond");
305  } else {
306  SCLogDebug("seg starts before and fully overlaps list");
307  }
308 
309  switch (stream->os_policy) {
310  case OS_POLICY_SOLARIS:
311  case OS_POLICY_HPUX11:
312  if (data_is_different) {
313  use_new_data = 1;
314  }
315  break;
316  }
317  }
318 
319  switch (stream->os_policy) {
320  case OS_POLICY_BSD:
321  case OS_POLICY_HPUX10:
322  case OS_POLICY_IRIX:
323  case OS_POLICY_WINDOWS:
325  case OS_POLICY_OLD_LINUX:
326  case OS_POLICY_LINUX:
327  case OS_POLICY_MACOS:
328  if (data_is_different) {
329  use_new_data = 1;
330  }
331  break;
332  }
333 
334  /* new seg starts after list segment */
335  } else { //if (SEQ_GT(seg->seq, list->seq)) {
336  SCLogDebug("seg starts after list segment");
337 
338  if (SEQ_EQ(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
339  SCLogDebug("seg after and is fully overlapped by list");
340  } else if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
341  SCLogDebug("seg starts after list and ends after list");
342 
343  switch (stream->os_policy) {
344  case OS_POLICY_SOLARIS:
345  case OS_POLICY_HPUX11:
346  if (data_is_different) {
347  use_new_data = 1;
348  }
349  break;
350  }
351  } else {
352  SCLogDebug("seg starts after list and ends before list end");
353 
354  }
355  }
356  }
357 
358  SCLogDebug("data_is_different %s, use_new_data %s",
359  data_is_different ? "yes" : "no",
360  use_new_data ? "yes" : "no");
361 
362  /* if the data is different and we don't want to use the new (seg)
363  * data, we have to update buf with the list data */
364  if (data_is_different && !use_new_data) {
365  /* we need to copy list into seg */
366  uint32_t list_offset = 0;
367  uint32_t seg_offset = 0;
368  uint32_t list_len;
369  uint16_t seg_len = p->payload_len;
370  uint32_t list_seq = list->seq;
371 
372  const uint8_t *list_data;
373  StreamingBufferSegmentGetData(&stream->sb, &list->sbseg, &list_data, &list_len);
374  if (list_data == NULL || list_len == 0)
375  return 0;
376  BUG_ON(list_len > USHRT_MAX);
377 
378  /* if list seg is partially before base_seq, list_len (from stream) and
379  * TCP_SEG_LEN(list) will not be the same */
380  if (SEQ_GEQ(list->seq, stream->base_seq)) {
381  ;
382  } else {
383  list_seq = stream->base_seq;
384  list_len = SEG_SEQ_RIGHT_EDGE(list) - stream->base_seq;
385  }
386 
387  if (SEQ_LT(seg->seq, list_seq)) {
388  seg_offset = list_seq - seg->seq;
389  seg_len -= seg_offset;
390  } else if (SEQ_GT(seg->seq, list_seq)) {
391  list_offset = seg->seq - list_seq;
392  list_len -= list_offset;
393  }
394 
395  if (SEQ_LT(seg->seq + seg_offset + seg_len, list_seq + list_offset + list_len)) {
396  list_len -= (list_seq + list_offset + list_len) - (seg->seq + seg_offset + seg_len);
397  }
398  SCLogDebug("here goes nothing: list %u %u, seg %u %u", list_offset, list_len, seg_offset, seg_len);
399 
400  //PrintRawDataFp(stdout, list_data + list_offset, list_len);
401  //PrintRawDataFp(stdout, buf + seg_offset, seg_len);
402 
403  memcpy(buf + seg_offset, list_data + list_offset, list_len);
404  //PrintRawDataFp(stdout, buf, p->payload_len);
405  }
406  return (check_overlap_different_data && data_is_different);
407 }
408 
409 /** \internal
410  * \brief walk segment tree backwards to see if there are overlaps
411  *
412  * Walk back from the current segment which is already in the tree.
413  * We walk until we can't possibly overlap anymore.
414  */
415 static int DoHandleDataCheckBackwards(TcpStream *stream,
416  TcpSegment *seg, uint8_t *buf, Packet *p)
417 {
418  int retval = 0;
419 
420  SCLogDebug("check tree backwards: insert data for segment %p seq %u len %u re %u",
421  seg, seg->seq, TCP_SEG_LEN(seg), SEG_SEQ_RIGHT_EDGE(seg));
422 
423  /* check backwards */
424  TcpSegment *tree_seg = NULL, *s = seg;
425  RB_FOREACH_REVERSE_FROM(tree_seg, TCPSEG, s) {
426  if (tree_seg == seg)
427  continue;
428 
429  int overlap = 0;
430  if (SEQ_LEQ(SEG_SEQ_RIGHT_EDGE(tree_seg), stream->base_seq)) {
431  // segment entirely before base_seq
432  ;
433  } else if (SEQ_LEQ(tree_seg->seq + tree_seg->payload_len, seg->seq)) {
434  SCLogDebug("list segment too far to the left, no more overlap will be found");
435  break;
436  } else if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(tree_seg), seg->seq)) {
437  overlap = 1;
438  }
439 
440  SCLogDebug("(back) tree seg %u len %u re %u overlap? %s",
441  tree_seg->seq, TCP_SEG_LEN(tree_seg),
442  SEG_SEQ_RIGHT_EDGE(tree_seg), overlap ? "yes" : "no");
443 
444  if (overlap) {
445  retval |= DoHandleDataOverlap(stream, tree_seg, seg, buf, p);
446  }
447  }
448  return retval;
449 }
450 
451 /** \internal
452  * \brief walk segment tree in forward direction to see if there are overlaps
453  *
454  * Walk forward from the current segment which is already in the tree.
455  * We walk until the next segs start with a SEQ beyond our right edge.
456  *
457  * \retval 1 data was different
458  * \retval 0 data was the same
459  */
460 static int DoHandleDataCheckForward(TcpStream *stream,
461  TcpSegment *seg, uint8_t *buf, Packet *p)
462 {
463  int retval = 0;
464 
465  uint32_t seg_re = SEG_SEQ_RIGHT_EDGE(seg);
466 
467  SCLogDebug("check list forward: insert data for segment %p seq %u len %u re %u",
468  seg, seg->seq, TCP_SEG_LEN(seg), seg_re);
469 
470  TcpSegment *tree_seg = NULL, *s = seg;
471  RB_FOREACH_FROM(tree_seg, TCPSEG, s) {
472  if (tree_seg == seg)
473  continue;
474 
475  int overlap = 0;
476  if (SEQ_GT(seg_re, tree_seg->seq))
477  overlap = 1;
478  else if (SEQ_LEQ(seg_re, tree_seg->seq)) {
479  SCLogDebug("tree segment %u too far ahead, "
480  "no more overlaps can happen", tree_seg->seq);
481  break;
482  }
483 
484  SCLogDebug("(fwd) in-tree seg %u len %u re %u overlap? %s",
485  tree_seg->seq, TCP_SEG_LEN(tree_seg),
486  SEG_SEQ_RIGHT_EDGE(tree_seg), overlap ? "yes" : "no");
487 
488  if (overlap) {
489  retval |= DoHandleDataOverlap(stream, tree_seg, seg, buf, p);
490  }
491  }
492  return retval;
493 }
494 
495 /**
496  * \param tree_seg in-tree duplicate of `seg`
497  * \retval res 0 ok, -1 insertion error due to memcap
498  */
499 static int DoHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
500  TcpStream *stream, TcpSegment *seg, TcpSegment *tree_seg, Packet *p)
501 {
502  int result = 0;
503  TcpSegment *handle = seg;
504 
505  SCLogDebug("insert data for segment %p seq %u len %u re %u",
506  seg, seg->seq, TCP_SEG_LEN(seg), SEG_SEQ_RIGHT_EDGE(seg));
507 
508  /* create temporary buffer to contain the data we will insert. Overlap
509  * handling may update it. By using this we don't have to track whether
510  * parts of the data are already inserted or not. */
511  uint8_t buf[p->payload_len];
512  memcpy(buf, p->payload, p->payload_len);
513 
514  /* if tree_seg is set, we have an exact duplicate that we need to check */
515  if (tree_seg) {
516  DoHandleDataOverlap(stream, tree_seg, seg, buf, p);
517  handle = tree_seg;
518  }
519 
520  const bool is_head = !(TCPSEG_RB_PREV(handle));
521  const bool is_tail = !(TCPSEG_RB_NEXT(handle));
522 
523  /* new list head */
524  if (is_head && !is_tail) {
525  result = DoHandleDataCheckForward(stream, handle, buf, p);
526 
527  /* new list tail */
528  } else if (!is_head && is_tail) {
529  result = DoHandleDataCheckBackwards(stream, handle, buf, p);
530 
531  /* middle of the list */
532  } else if (!is_head && !is_tail) {
533  result = DoHandleDataCheckBackwards(stream, handle, buf, p);
534  result |= DoHandleDataCheckForward(stream, handle, buf, p);
535  }
536 
537  /* we had an overlap with different data */
538  if (result) {
541  }
542 
543  /* insert the temp buffer now that we've (possibly) updated
544  * it to account for the overlap policies */
545  int res = InsertSegmentDataCustom(stream, handle, buf, p->payload_len);
546  if (res < 0) {
547  if (res == -1) {
549  }
550  return -1;
551  }
552 
553  return 0;
554 }
555 
556 /** \internal
557  * \brief Add the header data to the segment
558  * \param rp packet to take the headers from. Might differ from `pp` in tunnels.
559  * \param pp packet to take the payload size from.
560  */
561 static void StreamTcpSegmentAddPacketDataDo(TcpSegment *seg, const Packet *rp, const Packet *pp)
562 {
563  if (GET_PKT_DATA(rp) != NULL && GET_PKT_LEN(rp) > pp->payload_len) {
564  seg->pcap_hdr_storage->ts.tv_sec = rp->ts.tv_sec;
565  seg->pcap_hdr_storage->ts.tv_usec = rp->ts.tv_usec;
567  /*
568  * pkt_hdr members are initially allocated 64 bytes of memory. Thus,
569  * need to check that this is sufficient and allocate more memory if
570  * not.
571  */
572  if (seg->pcap_hdr_storage->pktlen > seg->pcap_hdr_storage->alloclen) {
573  uint8_t *tmp_pkt_hdr = StreamTcpReassembleRealloc(seg->pcap_hdr_storage->pkt_hdr,
575  if (tmp_pkt_hdr == NULL) {
576  SCLogDebug("Failed to realloc");
577  seg->pcap_hdr_storage->ts.tv_sec = 0;
578  seg->pcap_hdr_storage->ts.tv_usec = 0;
579  seg->pcap_hdr_storage->pktlen = 0;
580  return;
581  } else {
582  seg->pcap_hdr_storage->pkt_hdr = tmp_pkt_hdr;
584  }
585  }
586  memcpy(seg->pcap_hdr_storage->pkt_hdr, GET_PKT_DATA(rp),
587  (size_t)GET_PKT_LEN(rp) - pp->payload_len);
588  } else {
589  seg->pcap_hdr_storage->ts.tv_sec = 0;
590  seg->pcap_hdr_storage->ts.tv_usec = 0;
591  seg->pcap_hdr_storage->pktlen = 0;
592  }
593 }
594 
595 /**
596  * \brief Adds the following information to the TcpSegment from the current
597  * packet being processed: time values, packet length, and the
598  * header data of the packet. This information is added to the TcpSegment so
599  * that it can be used in pcap capturing (log-pcap-stream) to dump the tcp
600  * session at the beginning of the pcap capture.
601  * \param seg TcpSegment where information is being stored.
602  * \param p Packet being processed.
603  * \param tv Thread-specific variables.
604  * \param ra_ctx TcpReassembly thread-specific variables
605  */
606 static void StreamTcpSegmentAddPacketData(
608 {
609  if (seg->pcap_hdr_storage == NULL || seg->pcap_hdr_storage->pkt_hdr == NULL) {
610  return;
611  }
612 
613  if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
614  Packet *rp = p->root;
615  StreamTcpSegmentAddPacketDataDo(seg, rp, p);
616  } else {
617  StreamTcpSegmentAddPacketDataDo(seg, p, p);
618  }
619 }
620 
621 /**
622  * \return 0 ok
623  * \return -1 segment not inserted due to memcap issue
624  *
625  * \param seg segment, this function takes total ownership
626  *
627  * In case of error, this function returns the segment to the pool
628  */
630  TcpStream *stream, TcpSegment *seg, Packet *p,
631  uint32_t pkt_seq, uint8_t *pkt_data, uint16_t pkt_datalen)
632 {
633  SCEnter();
634 
635  TcpSegment *dup_seg = NULL;
636 
637  /* insert segment into list. Note: doesn't handle the data */
638  int r = DoInsertSegment (stream, seg, &dup_seg, p);
639 
641  StreamTcpSegmentAddPacketData(seg, p, tv, ra_ctx);
642  }
643 
644  if (likely(r == 0)) {
645  /* no overlap, straight data insert */
646  int res = InsertSegmentDataCustom(stream, seg, pkt_data, pkt_datalen);
647  if (res < 0) {
648  if (res == -1) {
650  }
652  StreamTcpRemoveSegmentFromStream(stream, seg);
654  if (res == -1) {
655  SCReturnInt(-ENOMEM);
656  }
657  SCReturnInt(-1);
658  }
659 
660  } else if (r == 1 || r == 2) {
661  SCLogDebug("overlap (%s%s)", r == 1 ? "normal" : "", r == 2 ? "duplicate" : "");
662 
663  if (r == 2) {
664  SCLogDebug("dup_seg %p", dup_seg);
665  }
666 
667  /* XXX should we exclude 'retransmissions' here? */
669 
670  /* now let's consider the data in the overlap case */
671  int res = DoHandleData(tv, ra_ctx, stream, seg, dup_seg, p);
672  if (res < 0) {
674 
675  if (r == 1) // r == 2 mean seg wasn't added to stream
676  StreamTcpRemoveSegmentFromStream(stream, seg);
677 
679  SCReturnInt(-1);
680  }
681  if (r == 2) {
682  SCLogDebug("duplicate segment %u/%u, discard it",
683  seg->seq, seg->payload_len);
684 
686 #ifdef DEBUG
687  if (SCLogDebugEnabled()) {
688  TcpSegment *s = NULL, *safe = NULL;
689  RB_FOREACH_SAFE(s, TCPSEG, &stream->seg_tree, safe)
690  {
691  SCLogDebug("tree: seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32"%s%s%s",
692  s, s->seq, TCP_SEG_LEN(s),
693  (uint32_t)(s->seq + TCP_SEG_LEN(s)),
694  s->seq == seg->seq ? " DUPLICATE" : "",
695  TCPSEG_RB_PREV(s) == NULL ? " HEAD" : "",
696  TCPSEG_RB_NEXT(s) == NULL ? " TAIL" : "");
697  }
698  }
699 #endif
700  }
701  }
702 
703  SCReturnInt(0);
704 }
705 
706 
707 /*
708  * Pruning & removal
709  */
710 
711 
712 static inline bool SegmentInUse(const TcpStream *stream, const TcpSegment *seg)
713 {
714  /* if proto detect isn't done, we're not returning */
715  if (!(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
717  SCReturnInt(true);
718  }
719  }
720 
721  SCReturnInt(false);
722 }
723 
724 
725 /** \internal
726  * \brief check if we can remove a segment from our segment list
727  *
728  * \retval true
729  * \retval false
730  */
731 static inline bool StreamTcpReturnSegmentCheck(const TcpStream *stream, const TcpSegment *seg)
732 {
733  if (SegmentInUse(stream, seg)) {
734  SCReturnInt(false);
735  }
736 
737  if (!(StreamingBufferSegmentIsBeforeWindow(&stream->sb, &seg->sbseg))) {
738  SCReturnInt(false);
739  }
740 
741  SCReturnInt(true);
742 }
743 
744 static inline uint64_t GetLeftEdgeForApp(Flow *f, TcpSession *ssn, TcpStream *stream)
745 {
746  const FramesContainer *frames_container = AppLayerFramesGetContainer(f);
747  if (frames_container == NULL)
748  return STREAM_APP_PROGRESS(stream);
749 
750  const Frames *frames =
751  stream == &ssn->client ? &frames_container->toserver : &frames_container->toclient;
752  // const uint64_t x = FramesLeftEdge(stream, frames);
753  // BUG_ON(x != (frames->left_edge_rel + STREAM_BASE_OFFSET(stream)));
754  // return x;
755  const uint64_t o = (uint64_t)frames->left_edge_rel + STREAM_BASE_OFFSET(stream);
756  SCLogDebug(
757  "%s: frames left edge: %" PRIu64, &ssn->client == stream ? "toserver" : "toclient", o);
758  return o;
759 }
760 
761 static inline uint64_t GetLeftEdge(Flow *f, TcpSession *ssn, TcpStream *stream)
762 {
763  bool use_app = true;
764  bool use_raw = true;
765  bool use_log = true;
766 
767  uint64_t left_edge = 0;
769  use_app = false; // app is dead
770  }
771 
773  use_raw = false; // raw is dead
774  }
776  use_log = false;
777  }
778 
779  SCLogDebug("use_app %d use_raw %d use_log %d", use_app, use_raw, use_log);
780 
781  if (use_raw) {
782  uint64_t raw_progress = STREAM_RAW_PROGRESS(stream);
783 
784  if (StreamTcpInlineMode() == TRUE) {
785  uint32_t chunk_size = (stream == &ssn->client) ?
788  if (raw_progress < (uint64_t)chunk_size) {
789  raw_progress = 0;
790  } else {
791  raw_progress -= (uint64_t)chunk_size;
792  }
793  }
794 
795  /* apply min inspect depth: if it is set we need to keep data
796  * before the raw progress. */
797  if (use_app && stream->min_inspect_depth && ssn->state < TCP_CLOSED) {
798  if (raw_progress < stream->min_inspect_depth)
799  raw_progress = 0;
800  else
801  raw_progress -= stream->min_inspect_depth;
802 
803  SCLogDebug("stream->min_inspect_depth %u, raw_progress %"PRIu64,
804  stream->min_inspect_depth, raw_progress);
805  }
806 
807  if (use_app) {
808  const uint64_t app_le = GetLeftEdgeForApp(f, ssn, stream);
809  left_edge = MIN(app_le, raw_progress);
810  SCLogDebug("left_edge %" PRIu64 ", using both app:%" PRIu64 ", raw:%" PRIu64, left_edge,
811  app_le, raw_progress);
812  } else {
813  left_edge = raw_progress;
814  SCLogDebug("left_edge %"PRIu64", using only raw:%"PRIu64,
815  left_edge, raw_progress);
816  }
817  } else if (use_app) {
818  const uint64_t app_le = GetLeftEdgeForApp(f, ssn, stream);
819  left_edge = app_le;
820  SCLogDebug("left_edge %" PRIu64 ", using only app:%" PRIu64, left_edge, app_le);
821  } else {
822  left_edge = STREAM_BASE_OFFSET(stream) + stream->sb.buf_offset;
823  SCLogDebug("no app & raw: left_edge %"PRIu64" (full stream)", left_edge);
824  }
825 
826  if (use_log) {
827  if (use_app || use_raw) {
828  left_edge = MIN(left_edge, STREAM_LOG_PROGRESS(stream));
829  } else {
830  left_edge = STREAM_LOG_PROGRESS(stream);
831  }
832  }
833 
834  /* in inline mode keep at least unack'd segments so we can check for overlaps */
835  if (StreamTcpInlineMode() == TRUE) {
836  uint64_t last_ack_abs = STREAM_BASE_OFFSET(stream);
837  if (STREAM_LASTACK_GT_BASESEQ(stream)) {
838  /* get window of data that is acked */
839  const uint32_t delta = stream->last_ack - stream->base_seq;
840  /* get max absolute offset */
841  last_ack_abs += delta;
842  }
843  left_edge = MIN(left_edge, last_ack_abs);
844 
845  /* if we're told to look for overlaps with different data we should
846  * consider data that is ack'd as well. Injected packets may have
847  * been ack'd or injected packet may be too late. */
848  } else if (check_overlap_different_data) {
849  const uint32_t window = stream->window ? stream->window : 4096;
850  if (window < left_edge)
851  left_edge -= window;
852  else
853  left_edge = 0;
854 
855  SCLogDebug("stream:%p left_edge %"PRIu64, stream, left_edge);
856  }
857 
858  if (left_edge > 0) {
859  /* we know left edge based on the progress values now,
860  * lets adjust it to make sure in-use segments still have
861  * data */
862  TcpSegment *seg = NULL;
863  RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
864  if (TCP_SEG_OFFSET(seg) > left_edge) {
865  SCLogDebug("seg beyond left_edge, we're done");
866  break;
867  }
868 
869  if (SegmentInUse(stream, seg)) {
870  left_edge = TCP_SEG_OFFSET(seg);
871  SCLogDebug("in-use seg before left_edge, adjust to %"PRIu64" and bail", left_edge);
872  break;
873  }
874  }
875  }
876 
877  return left_edge;
878 }
879 
880 static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg)
881 {
882  RB_REMOVE(TCPSEG, &stream->seg_tree, seg);
883 }
884 
885 /** \brief Remove idle TcpSegments from TcpSession
886  *
887  * Checks app progress and raw progress and progresses them
888  * if needed, slides the streaming buffer, then gets rid of
889  * excess segments.
890  *
891  * \param f flow
892  * \param flags direction flags
893  */
895 {
896  SCEnter();
897 
898  if (f == NULL || f->protoctx == NULL) {
899  SCReturn;
900  }
901 
902  TcpSession *ssn = f->protoctx;
903  TcpStream *stream = NULL;
904 
905  if (flags & STREAM_TOSERVER) {
906  stream = &ssn->client;
907  } else if (flags & STREAM_TOCLIENT) {
908  stream = &ssn->server;
909  } else {
910  SCReturn;
911  }
912 
914  return;
915  }
916 
919  SCLogDebug("ssn %p / stream %p: reassembly depth reached, "
920  "STREAMTCP_STREAM_FLAG_NOREASSEMBLY set", ssn, stream);
922  StreamingBufferClear(&stream->sb);
923  return;
924 
925  } else if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) &&
927  SCLogDebug("ssn %p / stream %p: both app and raw are done, "
928  "STREAMTCP_STREAM_FLAG_NOREASSEMBLY set", ssn, stream);
931  StreamingBufferClear(&stream->sb);
932  return;
933  }
934 
935  const uint64_t left_edge = GetLeftEdge(f, ssn, stream);
936  if (left_edge && left_edge > STREAM_BASE_OFFSET(stream)) {
937  uint32_t slide = left_edge - STREAM_BASE_OFFSET(stream);
938  SCLogDebug("buffer sliding %u to offset %"PRIu64, slide, left_edge);
939 
941  AppLayerFramesSlide(f, slide, flags & (STREAM_TOSERVER | STREAM_TOCLIENT));
942  }
943  StreamingBufferSlideToOffset(&stream->sb, left_edge);
944  stream->base_seq += slide;
945 
946  if (slide <= stream->app_progress_rel) {
947  stream->app_progress_rel -= slide;
948  } else {
949  stream->app_progress_rel = 0;
950  }
951  if (slide <= stream->raw_progress_rel) {
952  stream->raw_progress_rel -= slide;
953  } else {
954  stream->raw_progress_rel = 0;
955  }
956  if (slide <= stream->log_progress_rel) {
957  stream->log_progress_rel -= slide;
958  } else {
959  stream->log_progress_rel = 0;
960  }
961 
962  SCLogDebug("stream base_seq %u at stream offset %"PRIu64,
963  stream->base_seq, STREAM_BASE_OFFSET(stream));
964  }
965 
966  /* loop through the segments and remove all not in use */
967  TcpSegment *seg = NULL, *safe = NULL;
968  RB_FOREACH_SAFE(seg, TCPSEG, &stream->seg_tree, safe)
969  {
970  SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32,
971  seg, seg->seq, TCP_SEG_LEN(seg),
972  (uint32_t)(seg->seq + TCP_SEG_LEN(seg)));
973 
974  if (StreamTcpReturnSegmentCheck(stream, seg) == 0) {
975  SCLogDebug("not removing segment");
976  break;
977  }
978 
979  StreamTcpRemoveSegmentFromStream(stream, seg);
981  SCLogDebug("removed segment");
982  continue;
983  }
984 
985  SCReturn;
986 }
987 
988 
989 /*
990  * unittests
991  */
992 
993 #ifdef UNITTESTS
994 #include "tests/stream-tcp-list.c"
995 #endif
StreamTcpSetEvent
#define StreamTcpSetEvent(p, e)
Definition: stream-tcp-private.h:263
TcpStream_
Definition: stream-tcp-private.h:109
StreamingBuffer_::buf_offset
uint32_t buf_offset
Definition: util-streaming-buffer.h:99
RB_GENERATE
RB_GENERATE(TCPSEG, TcpSegment, rb, TcpSegmentCompare)
StatsIncr
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:169
StreamTcpSegmentReturntoPool
void StreamTcpSegmentReturntoPool(TcpSegment *seg)
Function to return the segment back to the pool.
Definition: stream-tcp-reassemble.c:369
IsTcpSessionDumpingEnabled
bool IsTcpSessionDumpingEnabled(void)
Definition: stream-tcp-reassemble.c:89
TCP_SEG_LEN
#define TCP_SEG_LEN(seg)
Definition: stream-tcp-private.h:97
stream-tcp-inline.h
stream-tcp.h
RB_REMOVE
#define RB_REMOVE(name, x, y)
Definition: tree.h:773
OS_POLICY_IRIX
@ OS_POLICY_IRIX
Definition: stream-tcp-reassemble.h:45
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:629
TcpStream_::seg_tree
struct TCPSEG seg_tree
Definition: stream-tcp-private.h:138
TcpStream_::log_progress_rel
uint32_t log_progress_rel
Definition: stream-tcp-private.h:131
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
Packet_::payload
uint8_t * payload
Definition: decode.h:582
StreamTcpInlineMode
int StreamTcpInlineMode(void)
See if stream engine is operating in inline mode.
Definition: stream-tcp.c:6530
FramesContainer::toserver
Frames toserver
Definition: app-layer-frames.h:76
TcpStream_::os_policy
uint8_t os_policy
Definition: stream-tcp-private.h:113
Flow_
Flow data structure.
Definition: flow.h:356
TcpSegment::sbseg
StreamingBufferSegment sbseg
Definition: stream-tcp-private.h:80
StreamTcpReassembleConfigEnableOverlapCheck
void StreamTcpReassembleConfigEnableOverlapCheck(void)
Definition: stream-tcp-list.c:40
IS_TUNNEL_ROOT_PKT
#define IS_TUNNEL_ROOT_PKT(p)
Definition: decode.h:982
OS_POLICY_BSD
@ OS_POLICY_BSD
Definition: stream-tcp-reassemble.h:37
StreamingBufferGetData
int StreamingBufferGetData(const StreamingBuffer *sb, const uint8_t **data, uint32_t *data_len, uint64_t *stream_offset)
Definition: util-streaming-buffer.c:830
StreamTcpInlineSegmentReplacePacket
void StreamTcpInlineSegmentReplacePacket(const TcpStream *stream, Packet *p, const TcpSegment *seg)
Replace (part of) the payload portion of a packet by the data in a TCP segment.
Definition: stream-tcp-inline.c:112
rust.h
TcpReassemblyThreadCtx_::counter_tcp_reass_overlap
uint16_t counter_tcp_reass_overlap
Definition: stream-tcp-reassemble.h:73
MIN
#define MIN(x, y)
Definition: suricata-common.h:372
Frames
Definition: app-layer-frames.h:61
FramesContainer
Definition: app-layer-frames.h:75
stream-tcp-reassemble.h
TcpSegment::seq
uint32_t seq
Definition: stream-tcp-private.h:78
TcpStream_::flags
uint16_t flags
Definition: stream-tcp-private.h:110
STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA
@ STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA
Definition: decode-events.h:289
TcpReassemblyThreadCtx_::counter_tcp_reass_overlap_diff_data
uint16_t counter_tcp_reass_overlap_diff_data
Definition: stream-tcp-reassemble.h:75
TcpStreamCnf_::streaming_log_api
bool streaming_log_api
Definition: stream-tcp.h:65
Frames::left_edge_rel
uint32_t left_edge_rel
Definition: app-layer-frames.h:64
stream_config
TcpStreamCnf stream_config
Definition: stream-tcp.c:113
Flow_::protoctx
void * protoctx
Definition: flow.h:454
stream_offset
uint64_t stream_offset
Definition: util-streaming-buffer.h:1
Packet_::payload_len
uint16_t payload_len
Definition: decode.h:583
STREAMTCP_STREAM_FLAG_DEPTH_REACHED
#define STREAMTCP_STREAM_FLAG_DEPTH_REACHED
Definition: stream-tcp-private.h:218
TcpSegmentPcapHdrStorage_::pktlen
uint32_t pktlen
Definition: stream-tcp-private.h:70
TcpSession_::flags
uint16_t flags
Definition: stream-tcp-private.h:283
STREAM_LOG_PROGRESS
#define STREAM_LOG_PROGRESS(stream)
Definition: stream-tcp-private.h:149
StreamingBufferClear
void StreamingBufferClear(StreamingBuffer *sb)
Definition: util-streaming-buffer.c:130
TCP_SEG_OFFSET
#define TCP_SEG_OFFSET(seg)
Definition: stream-tcp-private.h:98
TcpReassemblyThreadCtx_::counter_tcp_reass_data_normal_fail
uint16_t counter_tcp_reass_data_normal_fail
Definition: stream-tcp-reassemble.h:77
TcpStream_::last_ack
uint32_t last_ack
Definition: stream-tcp-private.h:118
FramesContainer::toclient
Frames toclient
Definition: app-layer-frames.h:77
RB_EMPTY
#define RB_EMPTY(head)
Definition: tree.h:327
StreamTcpReassembleRealloc
void * StreamTcpReassembleRealloc(void *optr, size_t orig_size, size_t size)
Definition: stream-tcp-reassemble.c:223
StreamingBufferSegmentIsBeforeWindow
int StreamingBufferSegmentIsBeforeWindow(const StreamingBuffer *sb, const StreamingBufferSegment *seg)
Definition: util-streaming-buffer.c:712
STREAM_BASE_OFFSET
#define STREAM_BASE_OFFSET(stream)
Definition: stream-tcp-private.h:146
res
PoolThreadReserved res
Definition: stream-tcp-private.h:0
TcpStream_::min_inspect_depth
uint32_t min_inspect_depth
Definition: stream-tcp-private.h:133
TcpSegmentCompare
int TcpSegmentCompare(struct TcpSegment *a, struct TcpSegment *b)
compare function for the Segment tree
Definition: stream-tcp-list.c:51
util-print.h
RB_FOREACH_SAFE
#define RB_FOREACH_SAFE(x, name, head, y)
Definition: tree.h:791
SCEnter
#define SCEnter(...)
Definition: util-debug.h:300
GET_PKT_DATA
#define GET_PKT_DATA(p)
Definition: decode.h:236
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
OS_POLICY_HPUX11
@ OS_POLICY_HPUX11
Definition: stream-tcp-reassemble.h:44
TcpSession_::state
uint8_t state
Definition: stream-tcp-private.h:276
TcpStream_::segs_right_edge
uint32_t segs_right_edge
Definition: stream-tcp-private.h:139
AppLayerFramesSlide
void AppLayerFramesSlide(Flow *f, const uint32_t slide, const uint8_t direction)
Definition: app-layer-frames.c:328
stream-tcp-list.h
OS_POLICY_MACOS
@ OS_POLICY_MACOS
Definition: stream-tcp-reassemble.h:46
StreamTcpPruneSession
void StreamTcpPruneSession(Flow *f, uint8_t flags)
Remove idle TcpSegments from TcpSession.
Definition: stream-tcp-list.c:894
TRUE
#define TRUE
Definition: suricata-common.h:33
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:281
RB_FOREACH
#define RB_FOREACH(x, name, head)
Definition: tree.h:781
SCReturn
#define SCReturn
Definition: util-debug.h:302
TcpSegment
Definition: stream-tcp-private.h:75
StreamTcpIsSetStreamFlagAppProtoDetectionCompleted
#define StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)
Definition: stream-tcp-private.h:293
Packet_
Definition: decode.h:442
AppLayerFramesGetContainer
FramesContainer * AppLayerFramesGetContainer(Flow *f)
Definition: app-layer-parser.c:199
GET_PKT_LEN
#define GET_PKT_LEN(p)
Definition: decode.h:235
stream-tcp-private.h
OS_POLICY_HPUX10
@ OS_POLICY_HPUX10
Definition: stream-tcp-reassemble.h:43
TcpStream_::window
uint32_t window
Definition: stream-tcp-private.h:120
SEG_SEQ_RIGHT_EDGE
#define SEG_SEQ_RIGHT_EDGE(seg)
Definition: stream-tcp-private.h:100
IS_TUNNEL_PKT
#define IS_TUNNEL_PKT(p)
Definition: decode.h:979
StreamTcpReturnStreamSegments
void StreamTcpReturnStreamSegments(TcpStream *stream)
return all segments in this stream into the pool(s)
Definition: stream-tcp-reassemble.c:386
TcpSegment::payload_len
uint16_t payload_len
Definition: stream-tcp-private.h:77
OS_POLICY_SOLARIS
@ OS_POLICY_SOLARIS
Definition: stream-tcp-reassemble.h:42
TcpStream_::raw_progress_rel
uint32_t raw_progress_rel
Definition: stream-tcp-private.h:130
stream-tcp-list.c
TCP_CLOSED
@ TCP_CLOSED
Definition: stream-tcp-private.h:164
app-layer-frames.h
SEQ_GEQ
#define SEQ_GEQ(a, b)
Definition: stream-tcp-private.h:255
OS_POLICY_LAST
@ OS_POLICY_LAST
Definition: stream-tcp-reassemble.h:51
flags
uint8_t flags
Definition: decode-gre.h:0
Packet_::ts
struct timeval ts
Definition: decode.h:485
suricata-common.h
SEQ_GT
#define SEQ_GT(a, b)
Definition: stream-tcp-private.h:254
util-streaming-buffer.h
TcpSegmentPcapHdrStorage_::ts
struct timeval ts
Definition: stream-tcp-private.h:69
TcpStream_::base_seq
uint32_t base_seq
Definition: stream-tcp-private.h:127
TcpStream_::sb
StreamingBuffer sb
Definition: stream-tcp-private.h:137
TcpSegmentPcapHdrStorage_::alloclen
uint32_t alloclen
Definition: stream-tcp-private.h:71
OS_POLICY_OLD_LINUX
@ OS_POLICY_OLD_LINUX
Definition: stream-tcp-reassemble.h:39
TcpSession_::client
TcpStream client
Definition: stream-tcp-private.h:287
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:29
TcpStreamCnf_::reassembly_toclient_chunk_size
uint16_t reassembly_toclient_chunk_size
Definition: stream-tcp.h:63
util-validate.h
OS_POLICY_WINDOWS
@ OS_POLICY_WINDOWS
Definition: stream-tcp-reassemble.h:47
StreamTcpInlineSegmentCompare
int StreamTcpInlineSegmentCompare(const TcpStream *stream, const Packet *p, const TcpSegment *seg)
Compare the shared data portion of two segments.
Definition: stream-tcp-inline.c:47
Packet_::root
struct Packet_ * root
Definition: decode.h:627
TcpSession_::server
TcpStream server
Definition: stream-tcp-private.h:286
TcpSegmentPcapHdrStorage_::pkt_hdr
uint8_t * pkt_hdr
Definition: stream-tcp-private.h:72
StreamingBufferSlideToOffset
void StreamingBufferSlideToOffset(StreamingBuffer *sb, uint64_t offset)
slide to absolute offset
Definition: util-streaming-buffer.c:504
TcpSegment::pcap_hdr_storage
TcpSegmentPcapHdrStorage * pcap_hdr_storage
Definition: stream-tcp-private.h:81
SEQ_LT
#define SEQ_LT(a, b)
Definition: stream-tcp-private.h:252
TcpStream_::app_progress_rel
uint32_t app_progress_rel
Definition: stream-tcp-private.h:129
TcpReassemblyThreadCtx_::counter_tcp_reass_data_overlap_fail
uint16_t counter_tcp_reass_data_overlap_fail
Definition: stream-tcp-reassemble.h:78
SEQ_EQ
#define SEQ_EQ(a, b)
Definition: stream-tcp-private.h:251
TcpReassemblyThreadCtx_
Definition: stream-tcp-reassemble.h:60
StreamingBufferInsertAt
int StreamingBufferInsertAt(StreamingBuffer *sb, StreamingBufferSegment *seg, const uint8_t *data, uint32_t data_len, uint64_t offset)
Definition: util-streaming-buffer.c:650
STREAMTCP_FLAG_APP_LAYER_DISABLED
#define STREAMTCP_FLAG_APP_LAYER_DISABLED
Definition: stream-tcp-private.h:202
STREAMTCP_STREAM_FLAG_NOREASSEMBLY
#define STREAMTCP_STREAM_FLAG_NOREASSEMBLY
Definition: stream-tcp-private.h:214
SEQ_LEQ
#define SEQ_LEQ(a, b)
Definition: stream-tcp-private.h:253
OS_POLICY_WINDOWS2K3
@ OS_POLICY_WINDOWS2K3
Definition: stream-tcp-reassemble.h:49
RB_FOREACH_REVERSE_FROM
#define RB_FOREACH_REVERSE_FROM(x, name, y)
Definition: tree.h:801
STREAMTCP_STREAM_FLAG_DISABLE_RAW
#define STREAMTCP_STREAM_FLAG_DISABLE_RAW
Definition: stream-tcp-private.h:233
likely
#define likely(expr)
Definition: util-optimize.h:32
STREAM_APP_PROGRESS
#define STREAM_APP_PROGRESS(stream)
Definition: stream-tcp-private.h:147
TcpSession_
Definition: stream-tcp-private.h:274
RB_FOREACH_FROM
#define RB_FOREACH_FROM(x, name, y)
Definition: tree.h:786
StreamingBufferSegmentGetData
void StreamingBufferSegmentGetData(const StreamingBuffer *sb, const StreamingBufferSegment *seg, const uint8_t **data, uint32_t *data_len)
Definition: util-streaming-buffer.c:783
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:304
OS_POLICY_LINUX
@ OS_POLICY_LINUX
Definition: stream-tcp-reassemble.h:40
TcpReassemblyThreadCtx_::counter_tcp_segment_memcap
uint16_t counter_tcp_segment_memcap
Definition: stream-tcp-reassemble.h:66
SCLogDebugEnabled
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition: util-debug.c:647
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
STREAM_RAW_PROGRESS
#define STREAM_RAW_PROGRESS(stream)
Definition: stream-tcp-private.h:148