stream/segments: turn linked list into rbtree

To improve worst case performance turn the segments list into a rbtree.
This greatly improves inserts, lookups and removals if the number of
segments gets very large.

The tree is sorted by the segment sequence number as its primary key.
If 2 segments have the same seq, the payload_len (segment length) is
used. Then the larger segment will be places after the smaller segment.
Exact matches are not added to the tree.
pull/3479/head
Victor Julien 7 years ago
parent 6a0cf0dd74
commit 26b5e1ed13

@ -1204,9 +1204,7 @@ static int FlowMgrTest02 (void)
TimeGet(&ts);
TCP_SEG_LEN(&seg) = 3;
seg.next = NULL;
seg.prev = NULL;
client.seg_list = &seg;
TCPSEG_RB_INSERT(&client.seg_tree, &seg);
ssn.client = client;
ssn.server = client;
ssn.state = TCP_ESTABLISHED;
@ -1310,9 +1308,7 @@ static int FlowMgrTest04 (void)
TimeGet(&ts);
TCP_SEG_LEN(&seg) = 3;
seg.next = NULL;
seg.prev = NULL;
client.seg_list = &seg;
TCPSEG_RB_INSERT(&client.seg_tree, &seg);
ssn.client = client;
ssn.server = client;
ssn.state = TCP_ESTABLISHED;

@ -44,7 +44,8 @@
* \retval 0 shared data is the same (or no data is shared)
* \retval 1 shared data is different
*/
int StreamTcpInlineSegmentCompare(TcpStream *stream, Packet *p, TcpSegment *seg)
int StreamTcpInlineSegmentCompare(const TcpStream *stream,
const Packet *p, const TcpSegment *seg)
{
SCEnter();
@ -108,7 +109,8 @@ int StreamTcpInlineSegmentCompare(TcpStream *stream, Packet *p, TcpSegment *seg)
* \todo What about reassembled fragments?
* \todo What about unwrapped tunnel packets?
*/
void StreamTcpInlineSegmentReplacePacket(TcpStream *stream, Packet *p, TcpSegment *seg)
void StreamTcpInlineSegmentReplacePacket(const TcpStream *stream,
Packet *p, const TcpSegment *seg)
{
SCEnter();

@ -26,8 +26,10 @@
#include "stream-tcp-private.h"
int StreamTcpInlineSegmentCompare(TcpStream *, Packet *, TcpSegment *);
void StreamTcpInlineSegmentReplacePacket(TcpStream *, Packet *, TcpSegment *);
int StreamTcpInlineSegmentCompare(const TcpStream *,
const Packet *, const TcpSegment *);
void StreamTcpInlineSegmentReplacePacket(const TcpStream *,
Packet *, const TcpSegment *);
void StreamTcpInlineRegisterTests(void);

@ -31,8 +31,6 @@
#include "util-print.h"
#include "util-validate.h"
//static void PrintList2(TcpSegment *seg);
static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg);
static int check_overlap_different_data = 0;
@ -46,6 +44,23 @@ void StreamTcpReassembleConfigEnableOverlapCheck(void)
* Inserts and overlap handling
*/
RB_GENERATE(TCPSEG, TcpSegment, rb, TcpSegmentCompare);
int TcpSegmentCompare(struct TcpSegment *a, struct TcpSegment *b)
{
if (SEQ_GT(a->seq, b->seq))
return 1;
else if (SEQ_LT(a->seq, b->seq))
return -1;
else {
if (a->payload_len == b->payload_len)
return 0;
else if (a->payload_len > b->payload_len)
return 1;
else
return -1;
}
}
/** \internal
* \brief insert segment data into the streaming buffer
@ -98,22 +113,55 @@ static inline int InsertSegmentDataCustom(TcpStream *stream, TcpSegment *seg, ui
}
/** \internal
* \brief insert the segment into the proper place in the list
* \brief check if this segments overlaps with an in-tree seg.
* \retval true
* \retval false
*/
static inline bool CheckOverlap(struct TCPSEG *tree, TcpSegment *seg)
{
const uint32_t re = SEG_SEQ_RIGHT_EDGE(seg);
SCLogDebug("start. SEQ %u payload_len %u. Right edge: %u. Seg %p",
seg->seq, seg->payload_len, re, seg);
/* check forward */
TcpSegment *next = TCPSEG_RB_NEXT(seg);
if (next) {
// next has same seq, so data must overlap
if (SEQ_EQ(next->seq, seg->seq))
return true;
// our right edge is beyond next seq, overlap
if (SEQ_GT(re, next->seq))
return true;
}
/* check backwards */
TcpSegment *prev = TCPSEG_RB_PREV(seg);
if (prev) {
// prev has same seq, so data must overlap
if (SEQ_EQ(prev->seq, seg->seq))
return true;
// prev's right edge is beyond our seq, overlap
const uint32_t prev_re = SEG_SEQ_RIGHT_EDGE(prev);
if (SEQ_GT(prev_re, prev->seq))
return true;
}
SCLogDebug("no overlap");
return false;
}
/** \internal
* \brief insert the segment into the proper place in the tree
* don't worry about the data or overlaps
*
* If seq is equal to list seq, keep sorted by insert time.
* 1. seg 123 len 12
* 2. seg 123 len 14
* 3. seg 124 len 1
*
* \retval 2 not inserted, data overlap
* \retval 1 inserted with overlap detected
* \retval 0 inserted, no overlap
* \retval -1 error
*/
static int DoInsertSegment (TcpStream *stream, TcpSegment *seg, Packet *p)
static int DoInsertSegment (TcpStream *stream, TcpSegment *seg, TcpSegment **dup_seg, Packet *p)
{
/* before our base_seq we don't insert it in our list */
if (SEQ_LEQ((seg->seq + TCP_SEG_LEN(seg)), stream->base_seq))
if (SEQ_LEQ(SEG_SEQ_RIGHT_EDGE(seg), stream->base_seq))
{
SCLogDebug("not inserting: SEQ+payload %"PRIu32", last_ack %"PRIu32", "
"base_seq %"PRIu32, (seg->seq + TCP_SEG_LEN(seg)),
@ -123,74 +171,39 @@ static int DoInsertSegment (TcpStream *stream, TcpSegment *seg, Packet *p)
}
/* fast track */
if (stream->seg_list == NULL) {
SCLogDebug("empty list, inserting seg %p seq %" PRIu32 ", "
if (RB_EMPTY(&stream->seg_tree)) {
SCLogDebug("empty tree, inserting seg %p seq %" PRIu32 ", "
"len %" PRIu32 "", seg, seg->seq, TCP_SEG_LEN(seg));
stream->seg_list = seg;
seg->prev = NULL;
stream->seg_list_tail = seg;
TCPSEG_RB_INSERT(&stream->seg_tree, seg);
return 0;
}
/* insert the segment in the stream list using this fast track, if seg->seq
is equal or higher than stream->seg_list_tail.*/
if (SEQ_GEQ(seg->seq, (stream->seg_list_tail->seq +
TCP_SEG_LEN(stream->seg_list_tail))))
/* insert the segment in the stream tree using this fast track, if seg->seq
is equal or higher than last segments tail. */
TcpSegment *last = RB_MAX(TCPSEG, &stream->seg_tree);
if (last && SEQ_GEQ(seg->seq, (uint32_t)SEG_SEQ_RIGHT_EDGE(last)))
{
SCLogDebug("seg beyond list tail, append");
stream->seg_list_tail->next = seg;
seg->prev = stream->seg_list_tail;
stream->seg_list_tail = seg;
SCLogDebug("seg beyond tree tail, append");
TCPSEG_RB_INSERT(&stream->seg_tree, seg);
return 0;
}
/* walk the list to see where we can insert the segment.
* Check if a segment overlaps with us, if so we return 1 to indicate
* to the caller that we need to handle overlaps. */
TcpSegment *list_seg;
for (list_seg = stream->seg_list; list_seg != NULL; list_seg = list_seg->next)
{
if (SEQ_LT(seg->seq, list_seg->seq)) {
if (list_seg->prev != NULL) {
list_seg->prev->next = seg;
} else {
stream->seg_list = seg;
}
seg->prev = list_seg->prev;
seg->next = list_seg;
list_seg->prev = seg;
SCLogDebug("inserted %u before %p seq %u", seg->seq, list_seg, list_seg->seq);
if (seg->prev != NULL) {
SCLogDebug("previous %u", seg->prev->seq);
}
if (seg->next != NULL) {
SCLogDebug("next %u", seg->next->seq);
}
if (seg->prev != NULL && SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg->prev), seg->seq)) {
SCLogDebug("seg inserted with overlap (before)");
return 1;
}
else if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg), seg->next->seq)) {
SCLogDebug("seg inserted with overlap (after)");
return 1;
}
return 0;
/* insert and then check if there was any overlap with other segments */
TcpSegment *res = TCPSEG_RB_INSERT(&stream->seg_tree, seg);
if (res) {
SCLogDebug("seg has a duplicate in the tree seq %u/%u",
res->seq, res->payload_len);
/* exact duplicate SEQ + payload_len */
*dup_seg = res;
return 2; // duplicate has overlap by definition.
} else {
/* insert succeeded, now check if we overlap with someone */
if (CheckOverlap(&stream->seg_tree, seg) == true) {
SCLogDebug("seg %u has overlap in the tree", seg->seq);
return 1;
}
}
/* if we got here we didn't insert. Append */
seg->prev = stream->seg_list_tail;
stream->seg_list_tail->next = seg;
stream->seg_list_tail = seg;
if (seg->prev != NULL && SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg->prev), seg->seq)) {
SCLogDebug("seg inserted with overlap (before)");
return 1;
}
SCLogDebug("default: append");
SCLogDebug("seg %u: no overlap", seg->seq);
return 0;
}
@ -212,10 +225,12 @@ static int DoInsertSegment (TcpStream *stream, TcpSegment *seg, Packet *p)
* \retval 1 if data was different
* \retval 0 data was the same or we didn't check for differences
*/
static int DoHandleDataOverlap(TcpStream *stream, TcpSegment *list, TcpSegment *seg, uint8_t *buf, Packet *p)
static int DoHandleDataOverlap(TcpStream *stream, const TcpSegment *list,
const TcpSegment *seg, uint8_t *buf, Packet *p)
{
SCLogDebug("handle overlap for segment %p seq %u len %u re %u, "
"list segment %p seq %u len %u re %u", seg, seg->seq, p->payload_len, SEG_SEQ_RIGHT_EDGE(seg),
"list segment %p seq %u len %u re %u", seg, seg->seq,
p->payload_len, SEG_SEQ_RIGHT_EDGE(seg),
list, list->seq, TCP_SEG_LEN(list), SEG_SEQ_RIGHT_EDGE(list));
int data_is_different = 0;
@ -402,51 +417,55 @@ static int DoHandleDataOverlap(TcpStream *stream, TcpSegment *list, TcpSegment *
#define MAX_IP_DATA (uint32_t)(65536 - 40) // min ip header and min tcp header
/** \internal
* \brief walk segment list backwards to see if there are overlaps
* \brief walk segment tree backwards to see if there are overlaps
*
* Walk back from the current segment which is already in the list.
* Walk back from the current segment which is already in the tree.
* We walk until we can't possibly overlap anymore.
*/
static int DoHandleDataCheckBackwards(TcpStream *stream, TcpSegment *seg, uint8_t *buf, Packet *p)
static int DoHandleDataCheckBackwards(TcpStream *stream,
TcpSegment *seg, uint8_t *buf, Packet *p)
{
int retval = 0;
SCLogDebug("check list backwards: insert data for segment %p seq %u len %u re %u",
SCLogDebug("check tree backwards: insert data for segment %p seq %u len %u re %u",
seg, seg->seq, TCP_SEG_LEN(seg), SEG_SEQ_RIGHT_EDGE(seg));
TcpSegment *list = seg->prev;
do {
/* check backwards */
TcpSegment *tree_seg = NULL, *s = seg;
RB_FOREACH_REVERSE_FROM(tree_seg, TCPSEG, s) {
if (tree_seg == seg)
continue;
int overlap = 0;
if (SEQ_LEQ(SEG_SEQ_RIGHT_EDGE(list), stream->base_seq)) {
if (SEQ_LEQ(SEG_SEQ_RIGHT_EDGE(tree_seg), stream->base_seq)) {
// segment entirely before base_seq
;
} else if (SEQ_LEQ(list->seq + MAX_IP_DATA, seg->seq)) {
} else if (SEQ_LEQ(tree_seg->seq + MAX_IP_DATA, seg->seq)) {
SCLogDebug("list segment too far to the left, no more overlap will be found");
break;
} else if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(list), seg->seq)) {
} else if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(tree_seg), seg->seq)) {
overlap = 1;
}
SCLogDebug("(back) list seg %u len %u re %u overlap? %s", list->seq, TCP_SEG_LEN(list),
SEG_SEQ_RIGHT_EDGE(list), overlap ? "yes" : "no");
SCLogDebug("(back) tree seg %u len %u re %u overlap? %s",
tree_seg->seq, TCP_SEG_LEN(tree_seg),
SEG_SEQ_RIGHT_EDGE(tree_seg), overlap ? "yes" : "no");
if (overlap) {
retval |= DoHandleDataOverlap(stream, list, seg, buf, p);
retval |= DoHandleDataOverlap(stream, tree_seg, seg, buf, p);
}
list = list->prev;
} while (list != NULL);
}
return retval;
}
/** \internal
* \brief walk segment list in forward direction to see if there are overlaps
* \brief walk segment tree in forward direction to see if there are overlaps
*
* Walk forward from the current segment which is already in the list.
* Walk forward from the current segment which is already in the tree.
* We walk until the next segs start with a SEQ beyond our right edge.
*/
static int DoHandleDataCheckForward(TcpStream *stream, TcpSegment *seg, uint8_t *buf, Packet *p)
static int DoHandleDataCheckForward(TcpStream *stream,
TcpSegment *seg, uint8_t *buf, Packet *p)
{
int retval = 0;
@ -455,34 +474,39 @@ static int DoHandleDataCheckForward(TcpStream *stream, TcpSegment *seg, uint8_t
SCLogDebug("check list forward: insert data for segment %p seq %u len %u re %u",
seg, seg->seq, TCP_SEG_LEN(seg), seg_re);
TcpSegment *list = seg->next;
do {
TcpSegment *tree_seg = NULL, *s = seg;
RB_FOREACH_FROM(tree_seg, TCPSEG, s) {
if (tree_seg == seg)
continue;
int overlap = 0;
if (SEQ_GT(seg_re, list->seq))
if (SEQ_GT(seg_re, tree_seg->seq))
overlap = 1;
else if (SEQ_LEQ(seg_re, list->seq)) {
SCLogDebug("list segment %u too far ahead, "
"no more overlaps can happen", list->seq);
else if (SEQ_LEQ(seg_re, tree_seg->seq)) {
SCLogDebug("tree segment %u too far ahead, "
"no more overlaps can happen", tree_seg->seq);
break;
}
SCLogDebug("(fwd) list seg %u len %u re %u overlap? %s", list->seq,
TCP_SEG_LEN(list), SEG_SEQ_RIGHT_EDGE(list), overlap ? "yes" : "no");
SCLogDebug("(fwd) in-tree seg %u len %u re %u overlap? %s",
tree_seg->seq, TCP_SEG_LEN(tree_seg),
SEG_SEQ_RIGHT_EDGE(tree_seg), overlap ? "yes" : "no");
if (overlap) {
retval |= DoHandleDataOverlap(stream, list, seg, buf, p);
retval |= DoHandleDataOverlap(stream, tree_seg, seg, buf, p);
}
list = list->next;
} while (list != NULL);
}
return retval;
}
/**
* \param dup_seg in-tree duplicate of `seg`
*/
static int DoHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
TcpStream *stream, TcpSegment *seg, Packet *p)
TcpStream *stream, TcpSegment *seg, TcpSegment *tree_seg, Packet *p)
{
int result = 0;
TcpSegment *handle = seg;
SCLogDebug("insert data for segment %p seq %u len %u re %u",
seg, seg->seq, TCP_SEG_LEN(seg), SEG_SEQ_RIGHT_EDGE(seg));
@ -493,18 +517,24 @@ static int DoHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
uint8_t buf[p->payload_len];
memcpy(buf, p->payload, p->payload_len);
/* if tree_seg is set, we have an exact duplicate that we need to check */
if (tree_seg) {
DoHandleDataOverlap(stream, tree_seg, seg, buf, p);
handle = tree_seg;
}
/* new list head */
if (seg->next != NULL && seg->prev == NULL) {
result = DoHandleDataCheckForward(stream, seg, buf, p);
if (handle == RB_MIN(TCPSEG, &stream->seg_tree) && TCPSEG_RB_NEXT(handle)) {
result = DoHandleDataCheckForward(stream, handle, buf, p);
/* new list tail */
} else if (seg->next == NULL && seg->prev != NULL) {
result = DoHandleDataCheckBackwards(stream, seg, buf, p);
} else if (handle == RB_MAX(TCPSEG, &stream->seg_tree) && TCPSEG_RB_PREV(handle)) {
result = DoHandleDataCheckBackwards(stream, handle, buf, p);
/* middle of the list */
} else if (seg->next != NULL && seg->prev != NULL) {
result = DoHandleDataCheckBackwards(stream, seg, buf, p);
result |= DoHandleDataCheckForward(stream, seg, buf, p);
} else if (TCPSEG_RB_NEXT(handle) && TCPSEG_RB_PREV(handle)) {
result = DoHandleDataCheckBackwards(stream, handle, buf, p);
result |= DoHandleDataCheckForward(stream, handle, buf, p);
}
/* we had an overlap with different data */
@ -515,7 +545,7 @@ static int DoHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
/* insert the temp buffer now that we've (possibly) updated
* it to account for the overlap policies */
if (InsertSegmentDataCustom(stream, seg, buf, p->payload_len) < 0) {
if (InsertSegmentDataCustom(stream, handle, buf, p->payload_len) < 0) {
return -1;
}
@ -530,26 +560,22 @@ static int DoHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
* In case of error, this function returns the segment to the pool
*/
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)
TcpStream *stream, TcpSegment *seg, Packet *p,
uint32_t pkt_seq, uint8_t *pkt_data, uint16_t pkt_datalen)
{
#ifdef DEBUG
SCLogDebug("pre insert");
PrintList(stream->seg_list);
#endif
SCEnter();
TcpSegment *dup_seg = NULL;
/* insert segment into list. Note: doesn't handle the data */
int r = DoInsertSegment (stream, seg, p);
int r = DoInsertSegment (stream, seg, &dup_seg, p);
SCLogDebug("DoInsertSegment returned %d", r);
if (r < 0) {
StatsIncr(tv, ra_ctx->counter_tcp_reass_list_fail);
StreamTcpSegmentReturntoPool(seg);
SCReturnInt(-1);
}
#ifdef DEBUG
SCLogDebug("post insert");
PrintList(stream->seg_list);
#endif
if (likely(r == 0)) {
/* no overlap, straight data insert */
int res = InsertSegmentDataCustom(stream, seg, pkt_data, pkt_datalen);
@ -560,18 +586,47 @@ int StreamTcpReassembleInsertSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_
SCReturnInt(-1);
}
} else if (r == 1) {
} else if (r == 1 || r == 2) {
SCLogDebug("overlap (%s%s)", r == 1 ? "normal" : "", r == 2 ? "duplicate" : "");
if (r == 2) {
SCLogDebug("dup_seg %p", dup_seg);
}
/* XXX should we exclude 'retransmissions' here? */
StatsIncr(tv, ra_ctx->counter_tcp_reass_overlap);
/* now let's consider the data in the overlap case */
int res = DoHandleData(tv, ra_ctx, stream, seg, p);
int res = DoHandleData(tv, ra_ctx, stream, seg, dup_seg, p);
if (res < 0) {
StatsIncr(tv, ra_ctx->counter_tcp_reass_data_overlap_fail);
StreamTcpRemoveSegmentFromStream(stream, seg);
if (r == 1) // r == 2 mean seg wasn't added to stream
StreamTcpRemoveSegmentFromStream(stream, seg);
StreamTcpSegmentReturntoPool(seg);
SCReturnInt(-1);
}
if (r == 2) {
SCLogDebug("duplicate segment %u/%u, discard it",
seg->seq, seg->payload_len);
StreamTcpSegmentReturntoPool(seg);
#ifdef DEBUG
if (SCLogDebugEnabled()) {
TcpSegment *s = NULL, *safe = NULL;
RB_FOREACH_SAFE(s, TCPSEG, &stream->seg_tree, safe)
{
SCLogDebug("tree: seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32"%s%s%s",
s, s->seq, TCP_SEG_LEN(s),
(uint32_t)(s->seq + TCP_SEG_LEN(s)),
s->seq == seg->seq ? " DUPLICATE" : "",
TCPSEG_RB_PREV(s) == NULL ? " HEAD" : "",
TCPSEG_RB_NEXT(s) == NULL ? " TAIL" : "");
}
}
#endif
}
}
SCReturnInt(0);
@ -703,9 +758,8 @@ static inline uint64_t GetLeftEdge(TcpSession *ssn, TcpStream *stream)
/* we know left edge based on the progress values now,
* lets adjust it to make sure in-use segments still have
* data */
const TcpSegment *seg;
for (seg = stream->seg_list; seg != NULL; seg = seg->next)
{
TcpSegment *seg = NULL;
RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
if (TCP_SEG_OFFSET(seg) > left_edge) {
SCLogDebug("seg beyond left_edge, we're done");
break;
@ -724,18 +778,7 @@ static inline uint64_t GetLeftEdge(TcpSession *ssn, TcpStream *stream)
static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg)
{
if (seg->prev == NULL) {
stream->seg_list = seg->next;
if (stream->seg_list != NULL)
stream->seg_list->prev = NULL;
} else {
seg->prev->next = seg->next;
if (seg->next != NULL)
seg->next->prev = seg->prev;
}
if (stream->seg_list_tail == seg)
stream->seg_list_tail = seg->prev;
RB_REMOVE(TCPSEG, &stream->seg_tree, seg);
}
/** \brief Remove idle TcpSegments from TcpSession
@ -817,9 +860,9 @@ void StreamTcpPruneSession(Flow *f, uint8_t flags)
stream->base_seq, STREAM_BASE_OFFSET(stream));
}
/* loop through the segments and fill one or more msgs */
TcpSegment *seg = stream->seg_list;
while (seg != NULL)
/* loop through the segments and remove all not in use */
TcpSegment *seg = NULL, *safe = NULL;
RB_FOREACH_SAFE(seg, TCPSEG, &stream->seg_tree, safe)
{
SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32,
seg, seg->seq, TCP_SEG_LEN(seg),
@ -830,147 +873,15 @@ void StreamTcpPruneSession(Flow *f, uint8_t flags)
break;
}
TcpSegment *next_seg = seg->next;
StreamTcpRemoveSegmentFromStream(stream, seg);
StreamTcpSegmentReturntoPool(seg);
seg = next_seg;
SCLogDebug("removed segment");
continue;
}
#ifdef DEBUG
PrintList(stream->seg_list);
#endif
SCReturn;
}
/*
* Utils
*/
#if 0
void PrintList2(TcpSegment *seg)
{
TcpSegment *prev_seg = NULL;
if (seg == NULL)
return;
uint32_t next_seq = seg->seq;
while (seg != NULL) {
if (SEQ_LT(next_seq,seg->seq)) {
SCLogDebug("missing segment(s) for %" PRIu32 " bytes of data",
(seg->seq - next_seq));
}
SCLogDebug("seg %10"PRIu32" len %" PRIu16 ", seg %p, prev %p, next %p",
seg->seq, TCP_SEG_LEN(seg), seg, seg->prev, seg->next);
if (seg->prev != NULL && SEQ_LT(seg->seq,seg->prev->seq)) {
/* check for SEQ_LT cornercase where a - b is exactly 2147483648,
* which makes the marco return TRUE in both directions. This is
* a hack though, we're going to check next how we end up with
* a segment list with seq differences that big */
if (!(SEQ_LT(seg->prev->seq,seg->seq))) {
SCLogDebug("inconsistent list: SEQ_LT(seg->seq,seg->prev->seq)) =="
" TRUE, seg->seq %" PRIu32 ", seg->prev->seq %" PRIu32 ""
"", seg->seq, seg->prev->seq);
}
}
if (SEQ_LT(seg->seq,next_seq)) {
SCLogDebug("inconsistent list: SEQ_LT(seg->seq,next_seq)) == TRUE, "
"seg->seq %" PRIu32 ", next_seq %" PRIu32 "", seg->seq,
next_seq);
}
if (prev_seg != seg->prev) {
SCLogDebug("inconsistent list: prev_seg %p != seg->prev %p",
prev_seg, seg->prev);
}
next_seq = seg->seq + TCP_SEG_LEN(seg);
SCLogDebug("next_seq is now %"PRIu32"", next_seq);
prev_seg = seg;
seg = seg->next;
}
}
#endif
void PrintList(TcpSegment *seg)
{
TcpSegment *prev_seg = NULL;
// TcpSegment *head_seg = seg;
if (seg == NULL)
return;
uint32_t next_seq = seg->seq;
while (seg != NULL) {
if (SEQ_LT(next_seq,seg->seq)) {
SCLogDebug("missing segment(s) for %" PRIu32 " bytes of data",
(seg->seq - next_seq));
}
SCLogDebug("seg %10"PRIu32" len %" PRIu16 ", seg %p, prev %p, next %p",
seg->seq, TCP_SEG_LEN(seg), seg, seg->prev, seg->next);
if (seg->prev != NULL && SEQ_LT(seg->seq,seg->prev->seq)) {
/* check for SEQ_LT cornercase where a - b is exactly 2147483648,
* which makes the marco return TRUE in both directions. This is
* a hack though, we're going to check next how we end up with
* a segment list with seq differences that big */
if (!(SEQ_LT(seg->prev->seq,seg->seq))) {
SCLogDebug("inconsistent list: SEQ_LT(seg->seq,seg->prev->seq)) == "
"TRUE, seg->seq %" PRIu32 ", seg->prev->seq %" PRIu32 "",
seg->seq, seg->prev->seq);
// PrintList2(head_seg);
// abort();
}
}
if (SEQ_LT(seg->seq,next_seq)) {
SCLogDebug("inconsistent list: SEQ_LT(seg->seq,next_seq)) == TRUE, "
"seg->seq %" PRIu32 ", next_seq %" PRIu32 "", seg->seq,
next_seq);
// PrintList2(head_seg);
// abort();
}
if (prev_seg != seg->prev) {
SCLogDebug("inconsistent list: prev_seg %p != seg->prev %p",
prev_seg, seg->prev);
// PrintList2(head_seg);
abort();
}
next_seq = seg->seq + TCP_SEG_LEN(seg);
SCLogDebug("next_seq is now %"PRIu32"", next_seq);
prev_seg = seg;
seg = seg->next;
}
SCReturn;
}
#if 0
void ValidateList(const TcpStream *stream)
{
TcpSegment *seg = stream->seg_list;
TcpSegment *prev_seg = NULL;
BUG_ON(seg && seg->next == NULL && stream->seg_list != stream->seg_list_tail);
BUG_ON(stream->seg_list != stream->seg_list_tail && stream->seg_list_tail->prev == NULL);
while (seg != NULL) {
prev_seg = seg;
seg = seg->next;
BUG_ON(seg && seg->prev != prev_seg);
// equal is possible
BUG_ON(seg && SEQ_LT(seg->seq, prev_seg->seq));
}
}
#endif
/*
* unittests

@ -26,8 +26,6 @@
#include "stream-tcp-private.h"
void PrintList(TcpSegment *);
#ifdef UNITTESTS
void StreamTcpListRegisterTests(void);
#endif

@ -24,6 +24,7 @@
#ifndef __STREAM_TCP_PRIVATE_H__
#define __STREAM_TCP_PRIVATE_H__
#include "tree.h"
#include "decode.h"
#include "util-pool.h"
#include "util-pool-thread.h"
@ -51,15 +52,27 @@ typedef struct StreamTcpSackRecord_ {
struct StreamTcpSackRecord_ *next;
} StreamTcpSackRecord;
typedef struct TcpSegment_ {
typedef struct TcpSegment {
PoolThreadReserved res;
uint16_t payload_len; /**< actual size of the payload */
uint32_t seq;
StreamingBufferSegment sbseg;
struct TcpSegment_ *next;
struct TcpSegment_ *prev;
RB_ENTRY(TcpSegment) rb;
} TcpSegment;
/** \brief compare function for the Segment tree
*
* Main sort point is the sequence number. When sequence numbers
* are equal compare payload_len as well. This way the tree is
* sorted by seq, and in case of duplicate seqs we are sorted
* small to large.
*/
int TcpSegmentCompare(struct TcpSegment *a, struct TcpSegment *b);
/* red-black tree prototype for TcpSegment */
RB_HEAD(TCPSEG, TcpSegment);
RB_PROTOTYPE(TCPSEG, TcpSegment, rb, TcpSegmentCompare);
#define TCP_SEG_LEN(seg) (seg)->payload_len
#define TCP_SEG_OFFSET(seg) (seg)->sbseg.stream_offset
@ -90,9 +103,7 @@ typedef struct TcpStream_ {
uint32_t log_progress_rel; /**< streaming logger progress relative to STREAM_BASE_OFFSET */
StreamingBuffer sb;
TcpSegment *seg_list; /**< list of TCP segments that are not yet (fully) used in reassembly */
TcpSegment *seg_list_tail; /**< Last segment in the reassembled stream seg list*/
struct TCPSEG seg_tree; /**< red black tree of TCP segments. Data is stored in TcpStream::sb */
StreamTcpSackRecord *sack_head; /**< head of list of SACK records */
StreamTcpSackRecord *sack_tail; /**< tail of list of SACK records */

@ -304,8 +304,6 @@ void StreamTcpSegmentReturntoPool(TcpSegment *seg)
if (seg == NULL)
return;
seg->next = NULL;
seg->prev = NULL;
PoolThreadReturn(segment_thread_pool, seg);
}
@ -316,20 +314,12 @@ void StreamTcpSegmentReturntoPool(TcpSegment *seg)
*/
void StreamTcpReturnStreamSegments (TcpStream *stream)
{
TcpSegment *seg = stream->seg_list;
TcpSegment *next_seg;
if (seg == NULL)
return;
while (seg != NULL) {
next_seg = seg->next;
TcpSegment *seg = NULL, *safe = NULL;
RB_FOREACH_SAFE(seg, TCPSEG, &stream->seg_tree, safe)
{
RB_REMOVE(TCPSEG, &stream->seg_tree, seg);
StreamTcpSegmentReturntoPool(seg);
seg = next_seg;
}
stream->seg_list = NULL;
stream->seg_list_tail = NULL;
}
/** \internal
@ -656,7 +646,7 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre
seg->seq = TCP_GET_SEQ(p);
/* proto detection skipped, but now we do get data. Set event. */
if (stream->seg_list == NULL &&
if (RB_EMPTY(&stream->seg_tree) &&
stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED) {
AppLayerDecoderEventsSetEventRaw(&p->app_layer_events,
@ -832,9 +822,8 @@ int StreamNeedsReassembly(const TcpSession *ssn, uint8_t direction)
uint64_t right_edge = STREAM_BASE_OFFSET(stream) + stream->sb.buf_offset;
SCLogDebug("%s: list %p app %"PRIu64" (use: %s), raw %"PRIu64" (use: %s). Stream right edge: %"PRIu64,
SCLogDebug("%s: app %"PRIu64" (use: %s), raw %"PRIu64" (use: %s). Stream right edge: %"PRIu64,
dirstr,
stream->seg_list,
STREAM_APP_PROGRESS(stream), use_app ? "yes" : "no",
STREAM_RAW_PROGRESS(stream), use_raw ? "yes" : "no",
right_edge);
@ -862,12 +851,10 @@ static uint64_t GetStreamSize(TcpStream *stream)
uint64_t size = 0;
uint32_t cnt = 0;
TcpSegment *seg = stream->seg_list;
while (seg) {
TcpSegment *seg;
RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
cnt++;
size += (uint64_t)TCP_SEG_LEN(seg);
seg = seg->next;
}
SCLogDebug("size %"PRIu64", cnt %"PRIu32, size, cnt);
@ -1123,14 +1110,13 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
SCReturnInt(0);
}
SCLogDebug("stream->seg_list %p", stream->seg_list);
#ifdef DEBUG
PrintList(stream->seg_list);
SCLogDebug("stream->seg_tree RB_MIN %p", RB_MIN(TCPSEG, &stream->seg_tree));
GetSessionSize(ssn, p);
#endif
/* if no segments are in the list or all are already processed,
* and state is beyond established, we send an empty msg */
TcpSegment *seg_tail = stream->seg_list_tail;
TcpSegment *seg_tail = RB_MAX(TCPSEG, &stream->seg_tree);
if (seg_tail == NULL ||
SEGMENT_BEFORE_OFFSET(stream, seg_tail, STREAM_APP_PROGRESS(stream)))
{
@ -1237,7 +1223,7 @@ bool StreamReassembleRawHasDataReady(TcpSession *ssn, Packet *p)
stream = &ssn->server;
}
if (stream->seg_list == NULL) {
if (RB_EMPTY(&stream->seg_tree)) {
return false;
}
@ -1695,14 +1681,11 @@ static int StreamTcpReassembleHandleSegmentUpdateACK (ThreadVars *tv,
TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p)
{
SCEnter();
SCLogDebug("stream->seg_list %p", stream->seg_list);
int r = 0;
if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p, UPDATE_DIR_OPPOSING) < 0)
r = -1;
SCReturnInt(-1);
SCLogDebug("stream->seg_list %p", stream->seg_list);
SCReturnInt(r);
SCReturnInt(0);
}
int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
@ -1809,9 +1792,6 @@ TcpSegment *StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx)
segment request due to memcap limit */
StatsIncr(tv, ra_ctx->counter_tcp_segment_memcap);
} else {
seg->next = NULL;
seg->prev = NULL;
memset(&seg->sbseg, 0, sizeof(seg->sbseg));
}
@ -2221,7 +2201,6 @@ static int StreamTcpReassembleTest39 (void)
memset(&tv, 0, sizeof (ThreadVars));
memset(&stt, 0, sizeof (stt));
memset(&tcph, 0, sizeof (TCPHdr));
TcpSession *ssn = NULL;
FLOW_INITIALIZE(&f);
f.flags = FLOW_IPV4;
@ -2229,9 +2208,6 @@ static int StreamTcpReassembleTest39 (void)
p->flow = &f;
p->tcph = &tcph;
FLOWLOCK_WRLOCK(&f);
int ret = 0;
StreamTcpUTInit(&stt.ra_ctx);
/* handshake */
@ -2240,25 +2216,24 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOSERVER;
p->payload_len = 0;
p->payload = NULL;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
ssn = (TcpSession *)f.protoctx;
if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_UNKNOWN ||
f.alproto_ts != ALPROTO_UNKNOWN ||
f.alproto_tc != ALPROTO_UNKNOWN ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list != NULL ||
ssn->server.seg_list != NULL ||
ssn->data_first_seen_dir != 0) {
printf("failure 1\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
TcpSession *ssn = (TcpSession *)f.protoctx;
FAIL_IF_NULL(ssn);
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(ssn->data_first_seen_dir != 0);
/* handshake */
p->tcph->th_ack = htonl(1);
@ -2266,22 +2241,20 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOCLIENT;
p->payload_len = 0;
p->payload = NULL;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_UNKNOWN ||
f.alproto_ts != ALPROTO_UNKNOWN ||
f.alproto_tc != ALPROTO_UNKNOWN ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list != NULL ||
ssn->server.seg_list != NULL ||
ssn->data_first_seen_dir != 0) {
printf("failure 2\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(ssn->data_first_seen_dir != 0);
/* handshake */
p->tcph->th_ack = htonl(1);
@ -2290,22 +2263,20 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOSERVER;
p->payload_len = 0;
p->payload = NULL;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_UNKNOWN ||
f.alproto_ts != ALPROTO_UNKNOWN ||
f.alproto_tc != ALPROTO_UNKNOWN ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list != NULL ||
ssn->server.seg_list != NULL ||
ssn->data_first_seen_dir != 0) {
printf("failure 3\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(!RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(ssn->data_first_seen_dir != 0);
/* partial request */
uint8_t request1[] = { 0x47, 0x45, };
@ -2315,24 +2286,21 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOSERVER;
p->payload_len = sizeof(request1);
p->payload = request1;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_UNKNOWN ||
f.alproto_ts != ALPROTO_UNKNOWN ||
f.alproto_tc != ALPROTO_UNKNOWN ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list == NULL ||
ssn->client.seg_list->next != NULL ||
ssn->server.seg_list != NULL ||
ssn->data_first_seen_dir != STREAM_TOSERVER) {
printf("failure 4\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
/* response ack against partial request */
p->tcph->th_ack = htonl(3);
@ -2341,23 +2309,21 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOCLIENT;
p->payload_len = 0;
p->payload = NULL;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_UNKNOWN ||
f.alproto_ts != ALPROTO_UNKNOWN ||
f.alproto_tc != ALPROTO_UNKNOWN ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list == NULL ||
ssn->client.seg_list->next != NULL ||
ssn->server.seg_list != NULL ||
ssn->data_first_seen_dir != STREAM_TOSERVER) {
printf("failure 5\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
/* complete partial request */
uint8_t request2[] = {
@ -2378,24 +2344,22 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOSERVER;
p->payload_len = sizeof(request2);
p->payload = request2;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_UNKNOWN ||
f.alproto_ts != ALPROTO_UNKNOWN ||
f.alproto_tc != ALPROTO_UNKNOWN ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list == NULL ||
ssn->client.seg_list->next == NULL ||
ssn->client.seg_list->next->next != NULL ||
ssn->server.seg_list != NULL ||
ssn->data_first_seen_dir != STREAM_TOSERVER) {
printf("failure 6\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_UNKNOWN);
FAIL_IF(f.alproto_ts != ALPROTO_UNKNOWN);
FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
FAIL_IF(!RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(ssn->data_first_seen_dir != STREAM_TOSERVER);
/* response - request ack */
uint8_t response[] = {
@ -2447,25 +2411,22 @@ static int StreamTcpReassembleTest39 (void)
p->payload_len = sizeof(response);
p->payload = response;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_HTTP ||
f.alproto_ts != ALPROTO_HTTP ||
f.alproto_tc != ALPROTO_UNKNOWN ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list == NULL ||
ssn->client.seg_list->next == NULL ||
ssn->client.seg_list->next->next != NULL ||
ssn->server.seg_list == NULL ||
ssn->server.seg_list->next != NULL ||
ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) {
printf("failure 7\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_HTTP);
FAIL_IF(f.alproto_ts != ALPROTO_HTTP);
FAIL_IF(f.alproto_tc != ALPROTO_UNKNOWN);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
/* response ack from request */
p->tcph->th_ack = htonl(328);
@ -2474,25 +2435,23 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOSERVER;
p->payload_len = 0;
p->payload = NULL;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_HTTP ||
f.alproto_ts != ALPROTO_HTTP ||
f.alproto_tc != ALPROTO_HTTP ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list == NULL ||
ssn->client.seg_list->next == NULL ||
ssn->client.seg_list->next->next != NULL ||
ssn->server.seg_list == NULL ||
ssn->server.seg_list->next != NULL ||
ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) {
printf("failure 8\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_HTTP);
FAIL_IF(f.alproto_ts != ALPROTO_HTTP);
FAIL_IF(f.alproto_tc != ALPROTO_HTTP);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
/* response - acking */
p->tcph->th_ack = htonl(88);
@ -2501,24 +2460,23 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOCLIENT;
p->payload_len = 0;
p->payload = NULL;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_HTTP ||
f.alproto_ts != ALPROTO_HTTP ||
f.alproto_tc != ALPROTO_HTTP ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list == NULL ||
ssn->client.seg_list->next == NULL ||
ssn->server.seg_list == NULL ||
ssn->server.seg_list->next != NULL ||
ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) {
printf("failure 9\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_HTTP);
FAIL_IF(f.alproto_ts != ALPROTO_HTTP);
FAIL_IF(f.alproto_tc != ALPROTO_HTTP);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
FAIL_IF(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
/* response ack from request */
p->tcph->th_ack = htonl(328);
@ -2527,24 +2485,22 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOSERVER;
p->payload_len = 0;
p->payload = NULL;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_HTTP ||
f.alproto_ts != ALPROTO_HTTP ||
f.alproto_tc != ALPROTO_HTTP ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list == NULL ||
ssn->client.seg_list->next == NULL ||
ssn->server.seg_list == NULL ||
ssn->server.seg_list->next != NULL ||
ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) {
printf("failure 10\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_HTTP);
FAIL_IF(f.alproto_ts != ALPROTO_HTTP);
FAIL_IF(f.alproto_tc != ALPROTO_HTTP);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
/* response - acking the request again*/
p->tcph->th_ack = htonl(88);
@ -2553,24 +2509,22 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOCLIENT;
p->payload_len = 0;
p->payload = NULL;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_HTTP ||
f.alproto_ts != ALPROTO_HTTP ||
f.alproto_tc != ALPROTO_HTTP ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list == NULL ||
ssn->client.seg_list->next == NULL ||
ssn->server.seg_list == NULL ||
ssn->server.seg_list->next != NULL ||
ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) {
printf("failure 11\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_HTTP);
FAIL_IF(f.alproto_ts != ALPROTO_HTTP);
FAIL_IF(f.alproto_tc != ALPROTO_HTTP);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
/*** New Request ***/
@ -2581,26 +2535,23 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOSERVER;
p->payload_len = sizeof(request1);
p->payload = request1;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_HTTP ||
f.alproto_ts != ALPROTO_HTTP ||
f.alproto_tc != ALPROTO_HTTP ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list == NULL ||
ssn->client.seg_list->next == NULL ||
ssn->client.seg_list->next->next == NULL ||
ssn->server.seg_list == NULL ||
ssn->server.seg_list->next != NULL ||
ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) {
printf("failure 12\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_HTTP);
FAIL_IF(f.alproto_ts != ALPROTO_HTTP);
FAIL_IF(f.alproto_tc != ALPROTO_HTTP);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
/* response ack against partial request */
p->tcph->th_ack = htonl(90);
@ -2609,25 +2560,24 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOCLIENT;
p->payload_len = 0;
p->payload = NULL;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_HTTP ||
f.alproto_ts != ALPROTO_HTTP ||
f.alproto_tc != ALPROTO_HTTP ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list == NULL ||
ssn->client.seg_list->next == NULL ||
ssn->client.seg_list->next->next == NULL ||
ssn->server.seg_list == NULL ||
ssn->server.seg_list->next != NULL ||
ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) {
printf("failure 13\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_HTTP);
FAIL_IF(f.alproto_ts != ALPROTO_HTTP);
FAIL_IF(f.alproto_tc != ALPROTO_HTTP);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
/* complete request */
p->tcph->th_ack = htonl(328);
@ -2636,26 +2586,24 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOSERVER;
p->payload_len = sizeof(request2);
p->payload = request2;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_HTTP ||
f.alproto_ts != ALPROTO_HTTP ||
f.alproto_tc != ALPROTO_HTTP ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list == NULL ||
ssn->client.seg_list->next == NULL ||
ssn->client.seg_list->next->next == NULL ||
ssn->client.seg_list->next->next->next == NULL ||
ssn->server.seg_list == NULL ||
ssn->server.seg_list->next != NULL ||
ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) {
printf("failure 14\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_HTTP);
FAIL_IF(f.alproto_ts != ALPROTO_HTTP);
FAIL_IF(f.alproto_tc != ALPROTO_HTTP);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
/* response ack against second partial request */
p->tcph->th_ack = htonl(175);
@ -2664,25 +2612,26 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOCLIENT;
p->payload_len = 0;
p->payload = NULL;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_HTTP ||
f.alproto_ts != ALPROTO_HTTP ||
f.alproto_tc != ALPROTO_HTTP ||
ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list->next == NULL ||
ssn->client.seg_list->next->next == NULL ||
ssn->client.seg_list->next->next->next == NULL ||
ssn->server.seg_list == NULL ||
ssn->server.seg_list->next != NULL ||
ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) {
printf("failure 15\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_HTTP);
FAIL_IF(f.alproto_ts != ALPROTO_HTTP);
FAIL_IF(f.alproto_tc != ALPROTO_HTTP);
FAIL_IF(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED);
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PP_DONE(&f, STREAM_TOSERVER));
FAIL_IF(!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT));
FAIL_IF(ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER);
FAIL_IF(RB_EMPTY(&ssn->client.seg_tree));
FAIL_IF(!TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)));
FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree))));
FAIL_IF(!TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->client.seg_tree)))));
FAIL_IF(RB_EMPTY(&ssn->server.seg_tree));
FAIL_IF(TCPSEG_RB_NEXT(RB_MIN(TCPSEG, &ssn->server.seg_tree)));
/* response acking a request */
p->tcph->th_ack = htonl(175);
p->tcph->th_seq = htonl(328);
@ -2690,32 +2639,12 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOCLIENT;
p->payload_len = 0;
p->payload = NULL;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
SCLogDebug("StreamTcpIsSetStreamFlagAppProtoDetectionCompleted %s, "
"StreamTcpIsSetStreamFlagAppProtoDetectionCompleted %s, "
"f.alproto %u f.alproto_ts %u f.alproto_tc %u",
StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ? "true" : "false",
StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ? "true" : "false",
f.alproto, f.alproto_ts, f.alproto_tc);
if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
f.alproto != ALPROTO_HTTP ||
f.alproto_ts != ALPROTO_HTTP ||
f.alproto_tc != ALPROTO_HTTP)// ||
//ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)// ||
//!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
//!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
//ssn->client.seg_list != NULL ||
//ssn->server.seg_list == NULL ||
//ssn->server.seg_list->next != NULL ||
//ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER)
{
printf("failure 15\n");
goto end;
}
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server));
FAIL_IF(!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client));
FAIL_IF(f.alproto != ALPROTO_HTTP);
FAIL_IF(f.alproto_ts != ALPROTO_HTTP);
FAIL_IF(f.alproto_tc != ALPROTO_HTTP);
StreamTcpPruneSession(&f, STREAM_TOSERVER);
StreamTcpPruneSession(&f, STREAM_TOCLIENT);
@ -2727,34 +2656,12 @@ static int StreamTcpReassembleTest39 (void)
p->flowflags = FLOW_PKT_TOSERVER;
p->payload_len = 0;
p->payload = NULL;
if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
goto end;
#if 0
if (//!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
//!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) ||
//f.alproto != ALPROTO_HTTP ||
//f.alproto_ts != ALPROTO_HTTP ||
//f.alproto_tc != ALPROTO_HTTP ||
//ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED ||
!FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) ||
!FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) ||
ssn->client.seg_list != NULL ||
ssn->server.seg_list != NULL ||
ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER
) {
printf("failure 16\n");
abort();
goto end;
}
#endif
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
ret = 1;
end:
StreamTcpSessionClear(ssn);
StreamTcpUTDeinit(stt.ra_ctx);
SCFree(p);
FLOWLOCK_UNLOCK(&f);
return ret;
PASS;
}
/**
@ -2867,12 +2774,9 @@ static int StreamTcpReassembleTest40 (void)
}
/* check is have the segment in the list and flagged or not */
if (ssn.client.seg_list == NULL ||
SEGMENT_BEFORE_OFFSET(&ssn.client, ssn.client.seg_list, STREAM_APP_PROGRESS(&ssn.client)))
{
printf("the list is NULL or the processed segment has not been flaged (7): ");
goto end;
}
TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
FAIL_IF_NULL(seg);
FAIL_IF(SEGMENT_BEFORE_OFFSET(&ssn.client, seg, STREAM_APP_PROGRESS(&ssn.client)));
p->flowflags = FLOW_PKT_TOSERVER;
p->payload = httpbuf4;
@ -3391,7 +3295,9 @@ static int StreamTcpReassembleInlineTest08(void)
p->tcph->th_seq = htonl(17);
StreamTcpPruneSession(&f, STREAM_TOSERVER);
FAIL_IF (ssn.client.seg_list->seq != 2);
TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
FAIL_IF_NULL(seg);
FAIL_IF_NOT(seg->seq == 2);
FLOW_DESTROY(&f);
UTHFreePacket(p);
@ -3459,10 +3365,9 @@ static int StreamTcpReassembleInlineTest09(void)
p->tcph->th_seq = htonl(12);
if (ssn.client.seg_list->seq != 2) {
printf("expected segment 1 (seq 2) to be first in the list, got seq %"PRIu32": ", ssn.client.seg_list->seq);
goto end;
}
TcpSegment *seg = RB_MIN(TCPSEG, &ssn.client.seg_tree);
FAIL_IF_NULL(seg);
FAIL_IF_NOT(seg->seq == 2);
ret = 1;
end:

@ -180,102 +180,64 @@ end:
static int StreamTcpUtilStreamTest01(void)
{
int ret = 0;
TcpReassemblyThreadCtx *ra_ctx = NULL;
ThreadVars tv;
TcpStream stream;
ThreadVars tv;
memset(&tv, 0x00, sizeof(tv));
StreamTcpUTInit(&ra_ctx);
StreamTcpUTSetupStream(&stream, 1);
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 2, 'A', 5) == -1) {
printf("failed to add segment 1: ");
goto end;
}
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 7, 'B', 5) == -1) {
printf("failed to add segment 2: ");
goto end;
}
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 12, 'C', 5) == -1) {
printf("failed to add segment 3: ");
goto end;
}
FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 2, 'A', 5) == -1);
FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 7, 'B', 5) == -1);
FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 12, 'C', 5) == -1);
TcpSegment *seg = stream.seg_list;
if (seg->seq != 2) {
printf("first seg in the list should have seq 2: ");
goto end;
}
TcpSegment *seg = RB_MIN(TCPSEG, &stream.seg_tree);
FAIL_IF_NULL(seg);
FAIL_IF(seg->seq != 2);
seg = seg->next;
if (seg->seq != 7) {
printf("first seg in the list should have seq 7: ");
goto end;
}
seg = TCPSEG_RB_NEXT(seg);
FAIL_IF_NULL(seg);
FAIL_IF(seg->seq != 7);
seg = seg->next;
if (seg->seq != 12) {
printf("first seg in the list should have seq 12: ");
goto end;
}
seg = TCPSEG_RB_NEXT(seg);
FAIL_IF_NULL(seg);
FAIL_IF(seg->seq != 12);
ret = 1;
end:
StreamTcpUTClearStream(&stream);
StreamTcpUTDeinit(ra_ctx);
return ret;
PASS;
}
static int StreamTcpUtilStreamTest02(void)
{
int ret = 0;
TcpReassemblyThreadCtx *ra_ctx = NULL;
ThreadVars tv;
TcpStream stream;
ThreadVars tv;
memset(&tv, 0x00, sizeof(tv));
StreamTcpUTInit(&ra_ctx);
StreamTcpUTSetupStream(&stream, 1);
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 7, 'B', 5) == -1) {
printf("failed to add segment 2: ");
goto end;
}
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 12, 'C', 5) == -1) {
printf("failed to add segment 3: ");
goto end;
}
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 2, 'A', 5) == -1) {
printf("failed to add segment 1: ");
goto end;
}
FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 7, 'B', 5) == -1);
FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 12, 'C', 5) == -1);
FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &stream, 2, 'A', 5) == -1);
TcpSegment *seg = stream.seg_list;
if (seg->seq != 2) {
printf("first seg in the list should have seq 2: ");
goto end;
}
TcpSegment *seg = RB_MIN(TCPSEG, &stream.seg_tree);
FAIL_IF_NULL(seg);
FAIL_IF(seg->seq != 2);
seg = seg->next;
if (seg->seq != 7) {
printf("first seg in the list should have seq 7: ");
goto end;
}
seg = TCPSEG_RB_NEXT(seg);
FAIL_IF_NULL(seg);
FAIL_IF(seg->seq != 7);
seg = seg->next;
if (seg->seq != 12) {
printf("first seg in the list should have seq 12: ");
goto end;
}
seg = TCPSEG_RB_NEXT(seg);
FAIL_IF_NULL(seg);
FAIL_IF(seg->seq != 12);
ret = 1;
end:
StreamTcpUTClearStream(&stream);
StreamTcpUTDeinit(ra_ctx);
return ret;
PASS;
}
#endif

@ -2399,10 +2399,11 @@ static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq)
{
uint32_t ack = seq;
if (stream->seg_list_tail != NULL) {
if (SEQ_GT((stream->seg_list_tail->seq + TCP_SEG_LEN(stream->seg_list_tail)), ack))
{
ack = stream->seg_list_tail->seq + TCP_SEG_LEN(stream->seg_list_tail);
const TcpSegment *seg = RB_MAX(TCPSEG, &stream->seg_tree);
if (seg != NULL) {
const uint32_t tail_seq = seg->seq + TCP_SEG_LEN(seg);
if (SEQ_GT(tail_seq, ack)) {
ack = tail_seq;
}
}
@ -4824,7 +4825,6 @@ int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt,
if (p->flags & PKT_STREAM_MODIFIED) {
ReCalculateChecksum(p);
}
/* check for conditions that may make us not want to log this packet */
/* streams that hit depth */
@ -5942,7 +5942,7 @@ void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread
}
/* no need for a pseudo packet if there is nothing left to reassemble */
if (ssn->server.seg_list == NULL && ssn->client.seg_list == NULL) {
if (RB_EMPTY(&ssn->server.seg_tree) && RB_EMPTY(&ssn->client.seg_tree)) {
SCReturn;
}
@ -6234,11 +6234,12 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback
}
/* for IDS, return ack'd segments. For IPS all. */
TcpSegment *seg = stream->seg_list;
for (; seg != NULL &&
((stream_config.flags & STREAMTCP_INIT_FLAG_INLINE)
|| SEQ_LT(seg->seq, stream->last_ack));)
{
TcpSegment *seg;
RB_FOREACH(seg, TCPSEG, &stream->seg_tree) {
if (!((stream_config.flags & STREAMTCP_INIT_FLAG_INLINE)
|| SEQ_LT(seg->seq, stream->last_ack)))
break;
const uint8_t *seg_data;
uint32_t seg_datalen;
StreamingBufferSegmentGetData(&stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
@ -6248,7 +6249,7 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback
SCLogDebug("Callback function has failed");
return -1;
}
seg = seg->next;
cnt++;
}
return cnt;
@ -6914,7 +6915,11 @@ static int StreamTcpTest09 (void)
FAIL_IF(StreamTcpPacket(&tv, p, &stt, &pq) == -1);
FAIL_IF(((TcpSession *) (p->flow->protoctx))->client.seg_list->next != NULL);
TcpSession *ssn = p->flow->protoctx;
FAIL_IF_NULL(ssn);
TcpSegment *seg = RB_MIN(TCPSEG, &ssn->client.seg_tree);
FAIL_IF_NULL(seg);
FAIL_IF(TCPSEG_RB_NEXT(seg) != NULL);
StreamTcpSessionClear(p->flow->protoctx);
SCFree(p);
@ -8596,8 +8601,9 @@ static int StreamTcpTest23(void)
FAIL_IF(StreamTcpReassembleHandleSegment(&tv, stt.ra_ctx, &ssn, &ssn.client, p, &pq) == -1);
FAIL_IF(ssn.client.seg_list_tail == NULL);
FAIL_IF(TCP_SEG_LEN(ssn.client.seg_list_tail) != 2);
TcpSegment *seg = RB_MAX(TCPSEG, &ssn.client.seg_tree);
FAIL_IF_NULL(seg);
FAIL_IF(TCP_SEG_LEN(seg) != 2);
StreamTcpUTClearSession(&ssn);
SCFree(p);
@ -8661,8 +8667,9 @@ static int StreamTcpTest24(void)
FAIL_IF(StreamTcpReassembleHandleSegment(&tv, stt.ra_ctx, &ssn, &ssn.client, p, &pq) == -1);
FAIL_IF(ssn.client.seg_list_tail == NULL);
FAIL_IF(TCP_SEG_LEN(ssn.client.seg_list_tail) != 4);
TcpSegment *seg = RB_MAX(TCPSEG, &ssn.client.seg_tree);
FAIL_IF_NULL(seg);
FAIL_IF(TCP_SEG_LEN(seg) != 4);
StreamTcpUTClearSession(&ssn);
SCFree(p);

Loading…
Cancel
Save