-/* Copyright (C) 2007-2013 Open Information Security Foundation
+/* Copyright (C) 2007-2016 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
#include "stream-tcp-private.h"
#include "stream-tcp-reassemble.h"
#include "stream-tcp-inline.h"
+#include "stream-tcp-list.h"
#include "stream-tcp-util.h"
#include "stream.h"
#include "util-profiling.h"
-#define PSEUDO_PACKET_PAYLOAD_SIZE 65416 /* 64 Kb minus max IP and TCP header */
-
#ifdef DEBUG
static SCMutex segment_pool_memuse_mutex;
static uint64_t segment_pool_memuse = 0;
#endif
/* index to the right pool for all packet sizes. */
static uint16_t segment_pool_idx[65536]; /* O(1) lookups of the pool */
-static int check_overlap_different_data = 0;
/* Memory use counter */
SC_ATOMIC_DECLARE(uint64_t, ra_memuse);
/* prototypes */
-static int HandleSegmentStartsBeforeListSegment(ThreadVars *, TcpReassemblyThreadCtx *,
- TcpStream *, TcpSegment *, TcpSegment *, Packet *);
-static int HandleSegmentStartsAtSameListSegment(ThreadVars *, TcpReassemblyThreadCtx *,
- TcpStream *, TcpSegment *, TcpSegment *, Packet *);
-static int HandleSegmentStartsAfterListSegment(ThreadVars *, TcpReassemblyThreadCtx *,
- TcpStream *, TcpSegment *, TcpSegment *, Packet *);
-void StreamTcpSegmentDataReplace(TcpSegment *, TcpSegment *, uint32_t, uint16_t);
-void StreamTcpSegmentDataCopy(TcpSegment *, TcpSegment *);
TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *, uint16_t);
void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t);
void StreamTcpReassemblePseudoPacketCreate(TcpStream *, Packet *, PacketQueue *);
-static int StreamTcpSegmentDataCompare(TcpSegment *dst_seg, TcpSegment *src_seg,
- uint32_t start_point, uint16_t len);
-
-void StreamTcpReassembleConfigEnableOverlapCheck(void)
-{
- check_overlap_different_data = 1;
-}
/**
* \brief Function to Increment the memory usage counter for the TCP reassembly
}
seg->pool_size = size;
- seg->payload_len = seg->pool_size;
-
- seg->payload = SCMalloc(seg->payload_len);
- if (seg->payload == NULL) {
+ TCP_SEG_LEN(seg) = seg->pool_size;
+#if 0
+ TCP_SEG_PAYLOAD(seg) = SCMalloc(TCP_SEG_LEN(seg));
+ if (TCP_SEG_PAYLOAD(seg) == NULL) {
return 0;
}
-
+#endif
#ifdef DEBUG
SCMutexLock(&segment_pool_memuse_mutex);
- segment_pool_memuse += seg->payload_len;
+ segment_pool_memuse += TCP_SEG_LEN(seg);
segment_pool_memcnt++;
SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt);
SCMutexUnlock(&segment_pool_memuse_mutex);
SCMutexUnlock(&segment_pool_memuse_mutex);
#endif
- SCFree(seg->payload);
+ //SCFree(TCP_SEG_PAYLOAD(seg));
return;
}
stream->seg_list_tail = NULL;
}
+static inline bool STREAM_LASTACK_GT_BASESEQ(const TcpStream *stream)
+{
+ /* last ack not yet initialized */
+ if (stream->base_seq_offset == 0 && stream->last_ack == 0)
+ return false;
+ if (SEQ_GT(stream->last_ack, stream->base_seq))
+ return true;
+ return false;
+}
+
+/** \internal
+ * \brief check if segments falls before stream 'offset' */
+static inline int SEGMENT_BEFORE_OFFSET(TcpStream *stream, TcpSegment *seg, uint64_t offset)
+{
+ if (seg->sbseg.stream_offset + seg->sbseg.segment_len <= offset)
+ return 1;
+ return 0;
+}
+
/** \param f locked flow */
void StreamTcpDisableAppLayer(Flow *f)
{
if (!quiet)
SCLogConfig("stream.reassembly \"zero-copy-size\": %u", stream_config.zero_copy_size);
+ stream_config.sbcnf.flags = STREAMING_BUFFER_NOFLAGS;
+ stream_config.sbcnf.buf_size = 2048;
+
return 0;
}
return 0;
}
-#ifdef DEBUG
-static uint32_t dbg_app_layer_gap;
-static uint32_t dbg_app_layer_gap_candidate;
-#endif
-
void StreamTcpReassembleFree(char quiet)
{
uint16_t u16 = 0;
SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt);
SCMutexDestroy(&segment_pool_memuse_mutex);
SCMutexDestroy(&segment_pool_cnt_mutex);
- SCLogPerf("dbg_app_layer_gap %u", dbg_app_layer_gap);
- SCLogPerf("dbg_app_layer_gap_candidate %u", dbg_app_layer_gap_candidate);
#endif
}
SCReturn;
}
-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, seg->payload_len, 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 + seg->payload_len;
- SCLogDebug("next_seq is now %"PRIu32"", next_seq);
- prev_seg = seg;
- seg = seg->next;
- }
-}
-
-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, flags 0x%02x",
- seg->seq, seg->payload_len, seg, seg->prev, seg->next, seg->flags);
-
- 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 + seg->payload_len;
- SCLogDebug("next_seq is now %"PRIu32"", next_seq);
- prev_seg = seg;
- seg = seg->next;
- }
-}
-
/**
- * \internal
- * \brief Get the active ra_base_seq, considering stream gaps
+ * \brief check if stream in pkt direction has depth reached
+ *
+ * \param p packet with *LOCKED* flow
*
- * \retval seq the active ra_base_seq
+ * \retval 1 stream has depth reached
+ * \retval 0 stream does not have depth reached
*/
-static inline uint32_t StreamTcpReassembleGetRaBaseSeq(TcpStream *stream)
+int StreamTcpReassembleDepthReached(Packet *p)
{
- if (!(stream->flags & STREAMTCP_STREAM_FLAG_GAP)) {
- SCReturnUInt(stream->ra_app_base_seq);
- } else {
- SCReturnUInt(stream->ra_raw_base_seq);
+ if (p->flow != NULL && p->flow->protoctx != NULL) {
+ TcpSession *ssn = p->flow->protoctx;
+ TcpStream *stream;
+ if (p->flowflags & FLOW_PKT_TOSERVER) {
+ stream = &ssn->client;
+ } else {
+ stream = &ssn->server;
+ }
+
+ return (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) ? 1 : 0;
}
+
+ return 0;
}
/**
* \internal
- * \brief Function to handle the insertion newly arrived segment,
- * The packet is handled based on its target OS.
+ * \brief Function to Check the reassembly depth valuer against the
+ * allowed max depth of the stream reassmbly for TCP streams.
*
- * \param stream The given TCP stream to which this new segment belongs
- * \param seg Newly arrived segment
- * \param p received packet
+ * \param stream stream direction
+ * \param seq sequence number where "size" starts
+ * \param size size of the segment that is added
*
- * \retval 0 success
- * \retval -1 error -- either we hit a memory issue (OOM/memcap) or we received
- * a segment before ra_base_seq.
+ * \retval size Part of the size that fits in the depth, 0 if none
*/
-int StreamTcpReassembleInsertSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
- TcpStream *stream, TcpSegment *seg, Packet *p)
+static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream,
+ uint32_t seq, uint32_t size)
{
SCEnter();
- TcpSegment *list_seg = stream->seg_list;
- TcpSegment *next_list_seg = NULL;
-
-#if DEBUG
- PrintList(stream->seg_list);
-#endif
-
- int ret_value = 0;
- char return_seg = FALSE;
-
- /* before our ra_app_base_seq we don't insert it in our list,
- * or ra_raw_base_seq if in stream gap state */
- if (SEQ_LT((TCP_GET_SEQ(p)+p->payload_len),(StreamTcpReassembleGetRaBaseSeq(stream)+1)))
- {
- SCLogDebug("not inserting: SEQ+payload %"PRIu32", last_ack %"PRIu32", "
- "ra_(app|raw)_base_seq %"PRIu32, (TCP_GET_SEQ(p)+p->payload_len),
- stream->last_ack, StreamTcpReassembleGetRaBaseSeq(stream)+1);
- return_seg = TRUE;
- ret_value = -1;
-
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEGMENT_BEFORE_BASE_SEQ);
- goto end;
+ /* if the configured depth value is 0, it means there is no limit on
+ reassembly depth. Otherwise carry on my boy ;) */
+ if (ssn->reassembly_depth == 0) {
+ SCReturnUInt(size);
}
- SCLogDebug("SEQ %"PRIu32", SEQ+payload %"PRIu32", last_ack %"PRIu32", "
- "ra_app_base_seq %"PRIu32, TCP_GET_SEQ(p), (TCP_GET_SEQ(p)+p->payload_len),
- stream->last_ack, stream->ra_app_base_seq);
-
- if (seg == NULL) {
- goto end;
+ /* if the final flag is set, we're not accepting anymore */
+ if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
+ SCReturnUInt(0);
}
- /* fast track */
- if (list_seg == NULL) {
- SCLogDebug("empty list, inserting seg %p seq %" PRIu32 ", "
- "len %" PRIu32 "", seg, seg->seq, seg->payload_len);
- stream->seg_list = seg;
- seg->prev = NULL;
- stream->seg_list_tail = seg;
- goto end;
+ uint64_t seg_depth;
+ if (SEQ_GT(stream->base_seq, seq)) {
+ if (SEQ_LEQ(seq+size, stream->base_seq)) {
+ SCLogDebug("segment entirely before base_seq, weird: base %u, seq %u, re %u",
+ stream->base_seq, seq, seq+size);
+ SCReturnUInt(0);
+ }
+
+ seg_depth = stream->base_seq_offset + size - (stream->base_seq - seq);
+ } else {
+ seg_depth = stream->base_seq_offset + ((seq + size) - stream->base_seq);
}
- /* 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 +
- stream->seg_list_tail->payload_len)))
- {
- stream->seg_list_tail->next = seg;
- seg->prev = stream->seg_list_tail;
- stream->seg_list_tail = seg;
+ /* if the base_seq has moved passed the depth window we stop
+ * checking and just reject the rest of the packets including
+ * retransmissions. Saves us the hassle of dealing with sequence
+ * wraps as well */
+ SCLogDebug("seq + size %u, base %u, seg_depth %"PRIu64" limit %u", (seq + size),
+ stream->base_seq, seg_depth,
+ stream_config.reassembly_depth);
- goto end;
+ if (seg_depth > (uint64_t)stream_config.reassembly_depth) {
+ SCLogDebug("STREAMTCP_STREAM_FLAG_DEPTH_REACHED");
+ stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED;
+ SCReturnUInt(0);
}
+ SCLogDebug("NOT STREAMTCP_STREAM_FLAG_DEPTH_REACHED");
+ SCLogDebug("%"PRIu64" <= %u", seg_depth, stream_config.reassembly_depth);
+#if 0
+ SCLogDebug("full depth not yet reached: %"PRIu64" <= %"PRIu32,
+ (stream->base_seq_offset + stream->base_seq + size),
+ (stream->isn + stream_config.reassembly_depth));
+#endif
+ if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + stream_config.reassembly_depth))) {
+ /* packet (partly?) fits the depth window */
- /* If the OS policy is not set then set the OS policy for this stream */
- if (stream->os_policy == 0) {
- StreamTcpSetOSPolicy(stream, p);
+ if (SEQ_LEQ((seq + size),(stream->isn + 1 + ssn->reassembly_depth))) {
+ /* complete fit */
+ SCReturnUInt(size);
+ } else {
+ stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED;
+ /* partial fit, return only what fits */
+ uint32_t part = (stream->isn + 1 + ssn->reassembly_depth) - seq;
+#if DEBUG
+ BUG_ON(part > size);
+#else
+ if (part > size)
+ part = size;
+#endif
+ SCReturnUInt(part);
+ }
}
- for (; list_seg != NULL; list_seg = next_list_seg) {
- next_list_seg = list_seg->next;
-
- SCLogDebug("seg %p, list_seg %p, list_prev %p list_seg->next %p, "
- "segment length %" PRIu32 "", seg, list_seg, list_seg->prev,
- list_seg->next, seg->payload_len);
- SCLogDebug("seg->seq %"PRIu32", list_seg->seq %"PRIu32"",
- seg->seq, list_seg->seq);
-
- /* segment starts before list */
- if (SEQ_LT(seg->seq, list_seg->seq)) {
- /* seg is entirely before list_seg */
- if (SEQ_LEQ((seg->seq + seg->payload_len), list_seg->seq)) {
- SCLogDebug("before list seg: seg->seq %" PRIu32 ", list_seg->seq"
- " %" PRIu32 ", list_seg->payload_len %" PRIu32 ", "
- "list_seg->prev %p", seg->seq, list_seg->seq,
- list_seg->payload_len, list_seg->prev);
- seg->next = list_seg;
- if (list_seg->prev == NULL) {
- stream->seg_list = seg;
- }
- if (list_seg->prev != NULL) {
- list_seg->prev->next = seg;
- seg->prev = list_seg->prev;
- }
- list_seg->prev = seg;
+ SCReturnUInt(0);
+}
- goto end;
+static void StreamTcpStoreStreamChunk(TcpSession *ssn, StreamMsg *smsg, const Packet *p, int streaminline)
+{
+ uint8_t direction = 0;
- /* seg overlap with next seg(s) */
- } else {
- ret_value = HandleSegmentStartsBeforeListSegment(tv, ra_ctx, stream, list_seg, seg, p);
- if (ret_value == 1) {
- ret_value = 0;
- return_seg = TRUE;
- goto end;
- } else if (ret_value == -1) {
- SCLogDebug("HandleSegmentStartsBeforeListSegment failed");
- ret_value = -1;
- return_seg = TRUE;
- goto end;
- }
- }
+ if ((!streaminline && (p->flowflags & FLOW_PKT_TOSERVER)) ||
+ ( streaminline && (p->flowflags & FLOW_PKT_TOCLIENT)))
+ {
+ direction = STREAM_TOCLIENT;
+ SCLogDebug("stream chunk is to_client");
+ } else {
+ direction = STREAM_TOSERVER;
+ SCLogDebug("stream chunk is to_server");
+ }
- /* seg starts at same sequence number as list_seg */
- } else if (SEQ_EQ(seg->seq, list_seg->seq)) {
- ret_value = HandleSegmentStartsAtSameListSegment(tv, ra_ctx, stream, list_seg, seg, p);
- if (ret_value == 1) {
- ret_value = 0;
- return_seg = TRUE;
- goto end;
- } else if (ret_value == -1) {
- SCLogDebug("HandleSegmentStartsAtSameListSegment failed");
- ret_value = -1;
- return_seg = TRUE;
- goto end;
- }
+ /* store the smsg in the tcp stream */
+ if (direction == STREAM_TOSERVER) {
+ SCLogDebug("storing smsg in the to_server");
- /* seg starts at sequence number higher than list_seg */
- } else if (SEQ_GT(seg->seq, list_seg->seq)) {
- if (((SEQ_GEQ(seg->seq, (list_seg->seq + list_seg->payload_len))))
- && SEQ_GT((seg->seq + seg->payload_len),
- (list_seg->seq + list_seg->payload_len)))
- {
- SCLogDebug("starts beyond list end, ends after list end: "
- "seg->seq %" PRIu32 ", list_seg->seq %" PRIu32 ", "
- "list_seg->payload_len %" PRIu32 " (%" PRIu32 ")",
- seg->seq, list_seg->seq, list_seg->payload_len,
- list_seg->seq + list_seg->payload_len);
-
- if (list_seg->next == NULL) {
- list_seg->next = seg;
- seg->prev = list_seg;
- stream->seg_list_tail = seg;
- goto end;
- }
- } else {
- ret_value = HandleSegmentStartsAfterListSegment(tv, ra_ctx, stream, list_seg, seg, p);
- if (ret_value == 1) {
- ret_value = 0;
- return_seg = TRUE;
- goto end;
- } else if (ret_value == -1) {
- SCLogDebug("HandleSegmentStartsAfterListSegment failed");
- ret_value = -1;
- return_seg = TRUE;
- goto end;
- }
- }
+ /* put the smsg in the stream list */
+ if (ssn->toserver_smsg_head == NULL) {
+ ssn->toserver_smsg_head = smsg;
+ ssn->toserver_smsg_tail = smsg;
+ smsg->next = NULL;
+ smsg->prev = NULL;
+ } else {
+ StreamMsg *cur = ssn->toserver_smsg_tail;
+ cur->next = smsg;
+ smsg->prev = cur;
+ smsg->next = NULL;
+ ssn->toserver_smsg_tail = smsg;
}
- }
+ } else {
+ SCLogDebug("storing smsg in the to_client");
-end:
- if (return_seg == TRUE && seg != NULL) {
- StreamTcpSegmentReturntoPool(seg);
+ /* put the smsg in the stream list */
+ if (ssn->toclient_smsg_head == NULL) {
+ ssn->toclient_smsg_head = smsg;
+ ssn->toclient_smsg_tail = smsg;
+ smsg->next = NULL;
+ smsg->prev = NULL;
+ } else {
+ StreamMsg *cur = ssn->toclient_smsg_tail;
+ cur->next = smsg;
+ smsg->prev = cur;
+ smsg->next = NULL;
+ ssn->toclient_smsg_tail = smsg;
+ }
}
-
-#ifdef DEBUG
- PrintList(stream->seg_list);
-#endif
- SCReturnInt(ret_value);
}
/**
- * \brief Function to handle the newly arrived segment, when newly arrived
- * starts with the sequence number lower than the original segment and
- * ends at different position relative to original segment.
- * The packet is handled based on its target OS.
+ * \brief Insert a packets TCP data into the stream reassembly engine.
+ *
+ * \retval 0 good segment, as far as we checked.
+ * \retval -1 badness, reason to drop in inline mode
*
- * \param list_seg Original Segment in the stream
- * \param seg Newly arrived segment
- * \param prev_seg Previous segment in the stream segment list
- * \param p Packet
+ * If the retval is 0 the segment is inserted correctly, or overlap is handled,
+ * or it wasn't added because of reassembly depth.
*
- * \retval 1 success and done
- * \retval 0 success, but not done yet
- * \retval -1 error, will *only* happen on memory errors
*/
-
-static int HandleSegmentStartsBeforeListSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
- TcpStream *stream, TcpSegment *list_seg, TcpSegment *seg, Packet *p)
+int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
+ TcpSession *ssn, TcpStream *stream, Packet *p)
{
SCEnter();
- uint16_t overlap = 0;
- uint16_t packet_length = 0;
- uint32_t overlap_point = 0;
- char end_before = FALSE;
- char end_after = FALSE;
- char end_same = FALSE;
- char return_after = FALSE;
- uint8_t os_policy = stream->os_policy;
-#ifdef DEBUG
- SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 "", seg->seq,
- seg->payload_len);
- PrintList(stream->seg_list);
-#endif
+ if (ssn->data_first_seen_dir == 0) {
+ if (PKT_IS_TOSERVER(p)) {
+ ssn->data_first_seen_dir = STREAM_TOSERVER;
+ } else {
+ ssn->data_first_seen_dir = STREAM_TOCLIENT;
+ }
+ }
- if (SEQ_GT((seg->seq + seg->payload_len), list_seg->seq) &&
- SEQ_LT((seg->seq + seg->payload_len),(list_seg->seq +
- list_seg->payload_len)))
- {
- /* seg starts before list seg, ends beyond it but before list end */
- end_before = TRUE;
-
- /* [aaaa[abab]bbbb] a = seg, b = list_seg, overlap is the part [abab]
- * We know seg->seq + seg->payload_len is bigger than list_seg->seq */
- overlap = (seg->seq + seg->payload_len) - list_seg->seq;
- overlap_point = list_seg->seq;
- SCLogDebug("starts before list seg, ends before list end: seg->seq "
- "%" PRIu32 ", list_seg->seq %" PRIu32 ", "
- "list_seg->payload_len %" PRIu16 " overlap is %" PRIu32 ", "
- "overlap point %"PRIu32"", seg->seq, list_seg->seq,
- list_seg->payload_len, overlap, overlap_point);
- } else if (SEQ_EQ((seg->seq + seg->payload_len), (list_seg->seq +
- list_seg->payload_len)))
- {
- /* seg fully overlaps list_seg, starts before, at end point
- * [aaa[ababab]] where a = seg, b = list_seg
- * overlap is [ababab], which is list_seg->payload_len */
- overlap = list_seg->payload_len;
- end_same = TRUE;
- overlap_point = list_seg->seq;
- SCLogDebug("starts before list seg, ends at list end: list prev %p"
- "seg->seq %" PRIu32 ", list_seg->seq %" PRIu32 ","
- "list_seg->payload_len %" PRIu32 " overlap is %" PRIu32 "",
- list_seg->prev, seg->seq, list_seg->seq,
- list_seg->payload_len, overlap);
- /* seg fully overlaps list_seg, starts before, ends after list endpoint */
- } else if (SEQ_GT((seg->seq + seg->payload_len), (list_seg->seq +
- list_seg->payload_len)))
- {
- /* seg fully overlaps list_seg, starts before, ends after list endpoint
- * [aaa[ababab]aaa] where a = seg, b = list_seg
- * overlap is [ababab] which is list_seg->payload_len */
- overlap = list_seg->payload_len;
- end_after = TRUE;
- overlap_point = list_seg->seq;
- SCLogDebug("starts before list seg, ends after list end: seg->seq "
- "%" PRIu32 ", seg->payload_len %"PRIu32" list_seg->seq "
- "%" PRIu32 ", list_seg->payload_len %" PRIu32 " overlap is"
- " %" PRIu32 "", seg->seq, seg->payload_len,
- list_seg->seq, list_seg->payload_len, overlap);
- }
-
- if (overlap > 0) {
- /* handle the case where we need to fill a gap before list_seg first */
- if (list_seg->prev != NULL && SEQ_LT((list_seg->prev->seq + list_seg->prev->payload_len), list_seg->seq)) {
- SCLogDebug("GAP to fill before list segment, size %u", list_seg->seq - (list_seg->prev->seq + list_seg->prev->payload_len));
-
- uint32_t new_seq = (list_seg->prev->seq + list_seg->prev->payload_len);
- if (SEQ_GT(seg->seq, new_seq)) {
- new_seq = seg->seq;
- }
+ /* If the OS policy is not set then set the OS policy for this stream */
+ if (stream->os_policy == 0) {
+ StreamTcpSetOSPolicy(stream, p);
+ }
- packet_length = list_seg->seq - new_seq;
- if (packet_length > seg->payload_len) {
- packet_length = seg->payload_len;
- }
+ if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) &&
+ (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)) {
+ SCLogDebug("ssn %p: both app and raw reassembly disabled, not reassembling", ssn);
+ SCReturnInt(0);
+ }
- TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
- if (new_seg == NULL) {
- SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
+ /* If we have reached the defined depth for either of the stream, then stop
+ reassembling the TCP session */
+ uint32_t size = StreamTcpReassembleCheckDepth(ssn, stream, TCP_GET_SEQ(p), p->payload_len);
+ SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size);
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
- SCReturnInt(-1);
- }
- new_seg->payload_len = packet_length;
+ if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
+ /* increment stream depth counter */
+ StatsIncr(tv, ra_ctx->counter_tcp_stream_depth);
- new_seg->seq = new_seq;
+ stream->flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY;
+ SCLogDebug("ssn %p: reassembly depth reached, "
+ "STREAMTCP_STREAM_FLAG_NOREASSEMBLY set", ssn);
+ }
+ if (size == 0) {
+ SCLogDebug("ssn %p: depth reached, not reassembling", ssn);
+ SCReturnInt(0);
+ }
- SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len "
- "%" PRIu16"", new_seg->seq, new_seg->payload_len);
+#if DEBUG
+ BUG_ON(size > p->payload_len);
+#else
+ if (size > p->payload_len)
+ size = p->payload_len;
+#endif
- new_seg->next = list_seg;
- new_seg->prev = list_seg->prev;
- list_seg->prev->next = new_seg;
- list_seg->prev = new_seg;
-
- /* create a new seg, copy the list_seg data over */
- StreamTcpSegmentDataCopy(new_seg, seg);
-
-#ifdef DEBUG
- PrintList(stream->seg_list);
-#endif
- }
+ TcpSegment *seg = StreamTcpGetSegment(tv, ra_ctx, size);
+ if (seg == NULL) {
+ SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[size]);
- /* Handling case when the segment starts before the first segment in
- * the list */
- if (list_seg->prev == NULL) {
- if (end_after == TRUE && list_seg->next != NULL &&
- SEQ_LT(list_seg->next->seq, (seg->seq + seg->payload_len)))
- {
- packet_length = (list_seg->seq - seg->seq) + list_seg->payload_len;
- } else {
- packet_length = seg->payload_len + (list_seg->payload_len - overlap);
- return_after = TRUE;
- }
+ StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
+ SCReturnInt(-1);
+ }
- SCLogDebug("entered here packet_length %" PRIu32 ", seg->payload_len"
- " %" PRIu32 ", list->payload_len %" PRIu32 "",
- packet_length, seg->payload_len, list_seg->payload_len);
+ TCP_SEG_LEN(seg) = size;
+ seg->seq = TCP_GET_SEQ(p);
- TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
- if (new_seg == NULL) {
- SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
+ /* proto detection skipped, but now we do get data. Set event. */
+ if (stream->seg_list == NULL &&
+ stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED) {
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
- SCReturnInt(-1);
- }
- new_seg->payload_len = packet_length;
- new_seg->seq = seg->seq;
- new_seg->next = list_seg->next;
- new_seg->prev = list_seg->prev;
+ AppLayerDecoderEventsSetEventRaw(&p->app_layer_events,
+ APPLAYER_PROTO_DETECTION_SKIPPED);
+ }
- StreamTcpSegmentDataCopy(new_seg, list_seg);
+ if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, seg, p, TCP_GET_SEQ(p), p->payload, p->payload_len) != 0) {
+ SCLogDebug("StreamTcpReassembleInsertSegment failed");
+ SCReturnInt(-1);
+ }
+ SCReturnInt(0);
+}
- /* first the data before the list_seg->seq */
- uint16_t replace = (uint16_t) (list_seg->seq - seg->seq);
- SCLogDebug("copying %"PRIu16" bytes to new_seg", replace);
- StreamTcpSegmentDataReplace(new_seg, seg, seg->seq, replace);
+static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream,
+ Packet *p)
+{
+ uint8_t flag = 0;
- /* if any, data after list_seg->seq + list_seg->payload_len */
- if (SEQ_GT((seg->seq + seg->payload_len), (list_seg->seq +
- list_seg->payload_len)) && return_after == TRUE)
- {
- replace = (uint16_t)(((seg->seq + seg->payload_len) -
- (list_seg->seq +
- list_seg->payload_len)));
- SCLogDebug("replacing %"PRIu16"", replace);
- StreamTcpSegmentDataReplace(new_seg, seg, (list_seg->seq +
- list_seg->payload_len), replace);
- }
+ if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {
+ flag |= STREAM_START;
+ }
- /* update the stream last_seg in case of removal of list_seg */
- if (stream->seg_list_tail == list_seg)
- stream->seg_list_tail = new_seg;
+ if (ssn->state == TCP_CLOSED) {
+ flag |= STREAM_EOF;
+ }
+ if (p->flags & PKT_PSEUDO_STREAM_END) {
+ flag |= STREAM_EOF;
+ }
- StreamTcpSegmentReturntoPool(list_seg);
- list_seg = new_seg;
- if (new_seg->prev != NULL) {
- new_seg->prev->next = new_seg;
- }
- if (new_seg->next != NULL) {
- new_seg->next->prev = new_seg;
- }
+ if (StreamTcpInlineMode() == 0) {
+ if (p->flowflags & FLOW_PKT_TOSERVER) {
+ flag |= STREAM_TOCLIENT;
+ } else {
+ flag |= STREAM_TOSERVER;
+ }
+ } else {
+ if (p->flowflags & FLOW_PKT_TOSERVER) {
+ flag |= STREAM_TOSERVER;
+ } else {
+ flag |= STREAM_TOCLIENT;
+ }
+ }
- stream->seg_list = new_seg;
- SCLogDebug("list_seg now %p, stream->seg_list now %p", list_seg,
- stream->seg_list);
+ if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
+ flag |= STREAM_DEPTH;
+ }
+ return flag;
+}
- } else if (end_before == TRUE || end_same == TRUE) {
- /* Handling overlapping with more than one segment and filling gap */
- if (SEQ_GT(list_seg->seq, (list_seg->prev->seq +
- list_seg->prev->payload_len)))
- {
- SCLogDebug("list_seg->prev %p list_seg->prev->seq %"PRIu32" "
- "list_seg->prev->payload_len %"PRIu16"",
- list_seg->prev, list_seg->prev->seq,
- list_seg->prev->payload_len);
- if (SEQ_LT(list_seg->prev->seq, seg->seq)) {
- packet_length = list_seg->payload_len + (list_seg->seq -
- seg->seq);
- } else {
- packet_length = list_seg->payload_len + (list_seg->seq -
- (list_seg->prev->seq + list_seg->prev->payload_len));
- }
+/**
+ * \brief Check the minimum size limits for reassembly.
+ *
+ * \retval 0 don't reassemble yet
+ * \retval 1 do reassemble
+ */
+static int StreamTcpReassembleRawCheckLimit(TcpSession *ssn, TcpStream *stream,
+ Packet *p)
+{
+ SCEnter();
- TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
- if (new_seg == NULL) {
- SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
+ if (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
+ SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NOREASSEMBLY is set, so not expecting any new packets");
+ SCReturnInt(1);
+ }
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
- SCReturnInt(-1);
- }
+ if (ssn->flags & STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY) {
+ SCLogDebug("reassembling now as STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY is set");
+ ssn->flags &= ~STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY;
+ SCReturnInt(1);
+ }
- new_seg->payload_len = packet_length;
- if (SEQ_GT((list_seg->prev->seq + list_seg->prev->payload_len),
- seg->seq))
- {
- new_seg->seq = (list_seg->prev->seq +
- list_seg->prev->payload_len);
- } else {
- new_seg->seq = seg->seq;
- }
- SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len "
- "%" PRIu16"", new_seg->seq, new_seg->payload_len);
- new_seg->next = list_seg->next;
- new_seg->prev = list_seg->prev;
-
- StreamTcpSegmentDataCopy(new_seg, list_seg);
-
- uint16_t copy_len = (uint16_t) (list_seg->seq - seg->seq);
- SCLogDebug("copy_len %" PRIu32 " (%" PRIu32 " - %" PRIu32 ")",
- copy_len, list_seg->seq, seg->seq);
- StreamTcpSegmentDataReplace(new_seg, seg, seg->seq, copy_len);
-
- /*update the stream last_seg in case of removal of list_seg*/
- if (stream->seg_list_tail == list_seg)
- stream->seg_list_tail = new_seg;
-
- StreamTcpSegmentReturntoPool(list_seg);
- list_seg = new_seg;
- if (new_seg->prev != NULL) {
- new_seg->prev->next = new_seg;
- }
- if (new_seg->next != NULL) {
- new_seg->next->prev = new_seg;
- }
- }
- } else if (end_after == TRUE) {
- if (list_seg->next != NULL) {
- if (SEQ_LEQ((seg->seq + seg->payload_len), list_seg->next->seq))
- {
- if (SEQ_GT(seg->seq, (list_seg->prev->seq +
- list_seg->prev->payload_len)))
- {
- packet_length = list_seg->payload_len + (list_seg->seq -
- seg->seq);
- } else {
- packet_length = list_seg->payload_len + (list_seg->seq -
- (list_seg->prev->seq +
- list_seg->prev->payload_len));
- }
-
- packet_length += (seg->seq + seg->payload_len) -
- (list_seg->seq + list_seg->payload_len);
-
- TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
- if (new_seg == NULL) {
- SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
-
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
- SCReturnInt(-1);
- }
- new_seg->payload_len = packet_length;
- if (SEQ_GT((list_seg->prev->seq +
- list_seg->prev->payload_len), seg->seq))
- {
- new_seg->seq = (list_seg->prev->seq +
- list_seg->prev->payload_len);
- } else {
- new_seg->seq = seg->seq;
- }
- SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len "
- "%" PRIu16"", new_seg->seq, new_seg->payload_len);
- new_seg->next = list_seg->next;
- new_seg->prev = list_seg->prev;
-
- /* create a new seg, copy the list_seg data over */
- StreamTcpSegmentDataCopy(new_seg, list_seg);
-
- /* copy the part before list_seg */
- uint16_t copy_len = list_seg->seq - new_seg->seq;
- StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq,
- copy_len);
-
- /* copy the part after list_seg */
- copy_len = (seg->seq + seg->payload_len) -
- (list_seg->seq + list_seg->payload_len);
- StreamTcpSegmentDataReplace(new_seg, seg, (list_seg->seq +
- list_seg->payload_len), copy_len);
-
- if (new_seg->prev != NULL) {
- new_seg->prev->next = new_seg;
- }
- if (new_seg->next != NULL) {
- new_seg->next->prev = new_seg;
- }
- /*update the stream last_seg in case of removal of list_seg*/
- if (stream->seg_list_tail == list_seg)
- stream->seg_list_tail = new_seg;
-
- StreamTcpSegmentReturntoPool(list_seg);
- list_seg = new_seg;
- return_after = TRUE;
- }
- /* Handle the case, when list_seg is the end of segment list, but
- seg is ending after the list_seg. So we need to copy the data
- from newly received segment. After copying return the newly
- received seg to pool */
- } else {
- if (SEQ_GT(seg->seq, (list_seg->prev->seq +
- list_seg->prev->payload_len)))
- {
- packet_length = list_seg->payload_len + (list_seg->seq -
- seg->seq);
- } else {
- packet_length = list_seg->payload_len + (list_seg->seq -
- (list_seg->prev->seq +
- list_seg->prev->payload_len));
- }
+ if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) {
+ SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED is set, "
+ "so no new segments will be considered");
+ SCReturnInt(1);
+ }
- packet_length += (seg->seq + seg->payload_len) -
- (list_seg->seq + list_seg->payload_len);
+ /* some states mean we reassemble no matter how much data we have */
+ if (ssn->state >= TCP_TIME_WAIT)
+ SCReturnInt(1);
- TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
- if (new_seg == NULL) {
- SCLogDebug("segment_pool[%"PRIu16"] is empty",
- segment_pool_idx[packet_length]);
+ if (p->flags & PKT_PSEUDO_STREAM_END)
+ SCReturnInt(1);
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
- SCReturnInt(-1);
- }
- new_seg->payload_len = packet_length;
+ /* check if we have enough data to do raw reassembly */
+ if (p->flowflags & FLOW_PKT_TOCLIENT) {
+ SCLogDebug("StreamMsgQueueGetMinChunkLen(STREAM_TOSERVER) %"PRIu32,
+ StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER));
- if (SEQ_GT((list_seg->prev->seq +
- list_seg->prev->payload_len), seg->seq))
- {
- new_seg->seq = (list_seg->prev->seq +
- list_seg->prev->payload_len);
- } else {
- new_seg->seq = seg->seq;
- }
- SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len "
- "%" PRIu16"", new_seg->seq, new_seg->payload_len);
- new_seg->next = list_seg->next;
- new_seg->prev = list_seg->prev;
-
- /* create a new seg, copy the list_seg data over */
- StreamTcpSegmentDataCopy(new_seg, list_seg);
-
- /* copy the part before list_seg */
- uint16_t copy_len = list_seg->seq - new_seg->seq;
- StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq,
- copy_len);
-
- /* copy the part after list_seg */
- copy_len = (seg->seq + seg->payload_len) -
- (list_seg->seq + list_seg->payload_len);
- StreamTcpSegmentDataReplace(new_seg, seg, (list_seg->seq +
- list_seg->payload_len), copy_len);
-
- if (new_seg->prev != NULL) {
- new_seg->prev->next = new_seg;
- }
+ uint32_t delta = stream->last_ack - stream->base_seq;
+ /* get max absolute offset */
+ uint64_t max_offset = stream->base_seq_offset + delta;
- /*update the stream last_seg in case of removal of list_seg*/
- if (stream->seg_list_tail == list_seg)
- stream->seg_list_tail = new_seg;
+ int64_t diff = max_offset - stream->raw_progress;
- StreamTcpSegmentReturntoPool(list_seg);
- list_seg = new_seg;
- return_after = TRUE;
- }
+ if ((int64_t)StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER) >
+ diff) {
+ SCLogDebug("toserver min chunk len not yet reached: "
+ "last_ack %"PRIu32", ra_raw_base_seq %"PRIu32", %"PRIu32" < "
+ "%"PRIu32"", stream->last_ack, stream->base_seq,
+ (stream->last_ack - stream->base_seq),
+ StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER));
+ SCReturnInt(0);
}
+ } else {
+ SCLogDebug("StreamMsgQueueGetMinChunkLen(STREAM_TOCLIENT) %"PRIu32,
+ StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT));
- if (check_overlap_different_data &&
- !StreamTcpSegmentDataCompare(seg, list_seg, list_seg->seq, overlap)) {
- /* interesting, overlap with different data */
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA);
- }
+ uint32_t delta = stream->last_ack - stream->base_seq;
+ /* get max absolute offset */
+ uint64_t max_offset = stream->base_seq_offset + delta;
- if (StreamTcpInlineMode()) {
- if (StreamTcpInlineSegmentCompare(seg, list_seg) != 0) {
- StreamTcpInlineSegmentReplacePacket(p, list_seg);
- }
- } else {
- switch (os_policy) {
- case OS_POLICY_SOLARIS:
- case OS_POLICY_HPUX11:
- if (end_after == TRUE || end_same == TRUE) {
- StreamTcpSegmentDataReplace(list_seg, seg, overlap_point,
- overlap);
- } else {
- SCLogDebug("using old data in starts before list case, "
- "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
- "overlap %" PRIu32 "", list_seg->seq, os_policy,
- overlap);
- }
- break;
- case OS_POLICY_VISTA:
- case OS_POLICY_FIRST:
- SCLogDebug("using old data in starts before list case, "
- "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
- "overlap %" PRIu32 "", list_seg->seq, os_policy,
- overlap);
- break;
- case OS_POLICY_BSD:
- case OS_POLICY_HPUX10:
- case OS_POLICY_IRIX:
- case OS_POLICY_WINDOWS:
- case OS_POLICY_WINDOWS2K3:
- case OS_POLICY_OLD_LINUX:
- case OS_POLICY_LINUX:
- case OS_POLICY_MACOS:
- case OS_POLICY_LAST:
- default:
- SCLogDebug("replacing old data in starts before list seg "
- "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
- "overlap %" PRIu32 "", list_seg->seq, os_policy,
- overlap);
- StreamTcpSegmentDataReplace(list_seg, seg, overlap_point,
- overlap);
- break;
- }
- }
- /* To return from for loop as seg is finished with current list_seg
- no need to check further (improve performance) */
- if (end_before == TRUE || end_same == TRUE || return_after == TRUE) {
- SCReturnInt(1);
+ int64_t diff = max_offset - stream->raw_progress;
+
+ if ((int64_t)StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT) >
+ diff) {
+ SCLogDebug("toclient min chunk len not yet reached: "
+ "last_ack %"PRIu32", base_seq %"PRIu32", %"PRIu32" < "
+ "%"PRIu32"", stream->last_ack, stream->base_seq,
+ (stream->last_ack - stream->base_seq),
+ StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT));
+ SCReturnInt(0);
}
}
- SCReturnInt(0);
+ SCReturnInt(1);
}
/**
- * \brief Function to handle the newly arrived segment, when newly arrived
- * starts with the same sequence number as the original segment and
- * ends at different position relative to original segment.
- * The packet is handled based on its target OS.
- *
- * \param list_seg Original Segment in the stream
- * \param seg Newly arrived segment
- * \param prev_seg Previous segment in the stream segment list
- *
- * \retval 1 success and done
- * \retval 0 success, but not done yet
- * \retval -1 error, will *only* happen on memory errors
+ * \brief see what if any work the TCP session still needs
*/
-
-static int HandleSegmentStartsAtSameListSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
- TcpStream *stream, TcpSegment *list_seg, TcpSegment *seg, Packet *p)
+int StreamNeedsReassembly(TcpSession *ssn, int direction)
{
- uint16_t overlap = 0;
- uint16_t packet_length;
- char end_before = FALSE;
- char end_after = FALSE;
- char end_same = FALSE;
- char handle_beyond = FALSE;
- uint8_t os_policy = stream->os_policy;
-
- if (SEQ_LT((seg->seq + seg->payload_len), (list_seg->seq +
- list_seg->payload_len)))
- {
- /* seg->seg == list_seg->seq and list_seg->payload_len > seg->payload_len
- * [[ababab]bbbb] where a = seg, b = list_seg
- * overlap is the [ababab] part, which equals seg->payload_len. */
- overlap = seg->payload_len;
- end_before = TRUE;
- SCLogDebug("starts at list seq, ends before list end: seg->seq "
- "%" PRIu32 ", list_seg->seq %" PRIu32 ", "
- "list_seg->payload_len %" PRIu32 " overlap is %" PRIu32,
- seg->seq, list_seg->seq, list_seg->payload_len, overlap);
-
- } else if (SEQ_EQ((seg->seq + seg->payload_len), (list_seg->seq +
- list_seg->payload_len)))
- {
- /* seg starts at seq, ends at seq, retransmission.
- * both segments are the same, so overlap is either
- * seg->payload_len or list_seg->payload_len */
-
- /* check csum, ack, other differences? */
- overlap = seg->payload_len;
- end_same = TRUE;
- SCLogDebug("(retransmission) starts at list seq, ends at list end: "
- "seg->seq %" PRIu32 ", list_seg->seq %" PRIu32 ", "
- "list_seg->payload_len %" PRIu32 " overlap is %"PRIu32"",
- seg->seq, list_seg->seq, list_seg->payload_len, overlap);
-
- } else if (SEQ_GT((seg->seq + seg->payload_len),
- (list_seg->seq + list_seg->payload_len))) {
- /* seg starts at seq, ends beyond seq. */
- /* seg->seg == list_seg->seq and seg->payload_len > list_seg->payload_len
- * [[ababab]aaaa] where a = seg, b = list_seg
- * overlap is the [ababab] part, which equals list_seg->payload_len. */
- overlap = list_seg->payload_len;
- end_after = TRUE;
- SCLogDebug("starts at list seq, ends beyond list end: seg->seq "
- "%" PRIu32 ", list_seg->seq %" PRIu32 ", "
- "list_seg->payload_len %" PRIu32 " overlap is %" PRIu32 "",
- seg->seq, list_seg->seq, list_seg->payload_len, overlap);
- }
- if (overlap > 0) {
- /*Handle the case when newly arrived segment ends after original
- segment and original segment is the last segment in the list
- or the next segment in the list starts after the end of new segment*/
- if (end_after == TRUE) {
- char fill_gap = FALSE;
-
- if (list_seg->next != NULL) {
- /* first see if we have space left to fill up */
- if (SEQ_LT((list_seg->seq + list_seg->payload_len),
- list_seg->next->seq))
- {
- fill_gap = TRUE;
- }
-
- /* then see if we overlap (partly) with the next seg */
- if (SEQ_GT((seg->seq + seg->payload_len), list_seg->next->seq))
- {
- handle_beyond = TRUE;
- }
- /* Handle the case, when list_seg is the end of segment list, but
- seg is ending after the list_seg. So we need to copy the data
- from newly received segment. After copying return the newly
- received seg to pool */
- } else {
- fill_gap = TRUE;
- }
+ TcpStream *stream = NULL;
+ StreamMsg *head = NULL;
+#ifdef DEBUG
+ char *dirstr = NULL;
+#endif
+ /* TODO use STREAM_TOCLIENT/STREAM_TOSERVER */
+ if (direction == 0) {
+ stream = &ssn->client;
+ head = ssn->toserver_smsg_head;
+#ifdef DEBUG
+ dirstr = "client";
+#endif
+ } else {
+ stream = &ssn->server;
+ head = ssn->toclient_smsg_head;
+#ifdef DEBUG
+ dirstr = "server";
+#endif
+ }
- SCLogDebug("fill_gap %s, handle_beyond %s", fill_gap?"TRUE":"FALSE",
- handle_beyond?"TRUE":"FALSE");
-
- if (fill_gap == TRUE) {
- /* if there is a gap after this list_seg we fill it now with a
- * new seg */
- SCLogDebug("filling gap: list_seg->next->seq %"PRIu32"",
- list_seg->next?list_seg->next->seq:0);
- if (handle_beyond == TRUE) {
- packet_length = list_seg->next->seq -
- (list_seg->seq + list_seg->payload_len);
- } else {
- packet_length = seg->payload_len - list_seg->payload_len;
- }
+ int use_app = 1;
+ int use_raw = 1;
- SCLogDebug("packet_length %"PRIu16"", packet_length);
+ if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) ||
+ (stream->flags & STREAMTCP_STREAM_FLAG_GAP))
+ {
+ // app is dead
+ use_app = 0;
+ }
- TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
- if (new_seg == NULL) {
- SCLogDebug("egment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
+ if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW) {
+ // raw is dead
+ use_raw = 0;
+ }
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
- return -1;
- }
- new_seg->payload_len = packet_length;
- new_seg->seq = list_seg->seq + list_seg->payload_len;
- new_seg->next = list_seg->next;
- if (new_seg->next != NULL)
- new_seg->next->prev = new_seg;
- new_seg->prev = list_seg;
- list_seg->next = new_seg;
- SCLogDebug("new_seg %p, new_seg->next %p, new_seg->prev %p, "
- "list_seg->next %p", new_seg, new_seg->next,
- new_seg->prev, list_seg->next);
- StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq,
- new_seg->payload_len);
-
- /*update the stream last_seg in case of removal of list_seg*/
- if (stream->seg_list_tail == list_seg)
- stream->seg_list_tail = new_seg;
- }
- }
+ if (stream->seg_list_tail != NULL) {
+ uint64_t right_edge = TCP_SEG_OFFSET(stream->seg_list_tail) +
+ TCP_SEG_LEN(stream->seg_list_tail);
- if (check_overlap_different_data &&
- !StreamTcpSegmentDataCompare(list_seg, seg, seg->seq, overlap)) {
- /* interesting, overlap with different data */
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA);
- }
+ SCLogDebug("%s: list %p app %"PRIu64" (use: %s), raw %"PRIu64" (use: %s). Stream right edge: %"PRIu64,
+ dirstr,
+ stream->seg_list,
+ stream->app_progress, use_app ? "yes" : "no",
+ stream->raw_progress, use_raw ? "yes" : "no",
+ right_edge);
- if (StreamTcpInlineMode()) {
- if (StreamTcpInlineSegmentCompare(list_seg, seg) != 0) {
- StreamTcpInlineSegmentReplacePacket(p, list_seg);
- }
- } else {
- switch (os_policy) {
- case OS_POLICY_OLD_LINUX:
- case OS_POLICY_SOLARIS:
- case OS_POLICY_HPUX11:
- if (end_after == TRUE || end_same == TRUE) {
- StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap);
- } else {
- SCLogDebug("using old data in starts at list case, "
- "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
- "overlap %" PRIu32 "", list_seg->seq, os_policy,
- overlap);
- }
- break;
- case OS_POLICY_LAST:
- StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap);
- break;
- case OS_POLICY_LINUX:
- if (end_after == TRUE) {
- StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap);
- } else {
- SCLogDebug("using old data in starts at list case, "
- "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
- "overlap %" PRIu32 "", list_seg->seq, os_policy,
- overlap);
- }
- break;
- case OS_POLICY_BSD:
- case OS_POLICY_HPUX10:
- case OS_POLICY_IRIX:
- case OS_POLICY_WINDOWS:
- case OS_POLICY_WINDOWS2K3:
- case OS_POLICY_VISTA:
- case OS_POLICY_MACOS:
- case OS_POLICY_FIRST:
- default:
- SCLogDebug("using old data in starts at list case, list_seg->seq"
- " %" PRIu32 " policy %" PRIu32 " overlap %" PRIu32 "",
- list_seg->seq, os_policy, overlap);
- break;
+ if (use_raw) {
+ if (right_edge > stream->raw_progress) {
+ SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY", dirstr);
+ return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY;
}
}
-
- /* return 1 if we're done */
- if (end_before == TRUE || end_same == TRUE || handle_beyond == FALSE) {
- return 1;
+ if (use_app) {
+ if (right_edge > stream->app_progress) {
+ SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY", dirstr);
+ return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY;
+ }
}
+ } else {
+ SCLogDebug("%s: no list", dirstr);
}
- return 0;
-}
-/**
- * \internal
- * \brief Function to handle the newly arrived segment, when newly arrived
- * starts with the sequence number higher than the original segment and
- * ends at different position relative to original segment.
- * The packet is handled based on its target OS.
- *
- * \param list_seg Original Segment in the stream
- * \param seg Newly arrived segment
- * \param prev_seg Previous segment in the stream segment list
+ if (head != NULL) {
+ SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION", dirstr);
+ return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
+ }
- * \retval 1 success and done
- * \retval 0 success, but not done yet
- * \retval -1 error, will *only* happen on memory errors
- */
+ SCLogDebug("%s: STREAM_HAS_UNPROCESSED_SEGMENTS_NONE", dirstr);
+ return STREAM_HAS_UNPROCESSED_SEGMENTS_NONE;
+}
-static int HandleSegmentStartsAfterListSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
- TcpStream *stream, TcpSegment *list_seg, TcpSegment *seg, Packet *p)
+#ifdef DEBUG
+static uint64_t GetStreamSize(TcpStream *stream)
{
- SCEnter();
- uint16_t overlap = 0;
- uint16_t packet_length;
- char end_before = FALSE;
- char end_after = FALSE;
- char end_same = FALSE;
- char handle_beyond = FALSE;
- uint8_t os_policy = stream->os_policy;
-
- if (SEQ_LT((seg->seq + seg->payload_len), (list_seg->seq +
- list_seg->payload_len)))
- {
- /* seg starts after list, ends before list end
- * [bbbb[ababab]bbbb] where a = seg, b = list_seg
- * overlap is the part [ababab] which is seg->payload_len */
- overlap = seg->payload_len;
- end_before = TRUE;
-
- SCLogDebug("starts beyond list seq, ends before list end: seg->seq"
- " %" PRIu32 ", list_seg->seq %" PRIu32 ", list_seg->payload_len "
- "%" PRIu32 " overlap is %" PRIu32 "", seg->seq, list_seg->seq,
- list_seg->payload_len, overlap);
-
- } else if (SEQ_EQ((seg->seq + seg->payload_len),
- (list_seg->seq + list_seg->payload_len))) {
- /* seg starts after seq, before end, ends at seq
- * [bbbb[ababab]] where a = seg, b = list_seg
- * overlapping part is [ababab], thus seg->payload_len */
- overlap = seg->payload_len;
- end_same = TRUE;
-
- SCLogDebug("starts beyond list seq, ends at list end: seg->seq"
- " %" PRIu32 ", list_seg->seq %" PRIu32 ", list_seg->payload_len "
- "%" PRIu32 " overlap is %" PRIu32 "", seg->seq, list_seg->seq,
- list_seg->payload_len, overlap);
-
- } else if (SEQ_LT(seg->seq, list_seg->seq + list_seg->payload_len) &&
- SEQ_GT((seg->seq + seg->payload_len), (list_seg->seq +
- list_seg->payload_len)))
- {
- /* seg starts after seq, before end, ends beyond seq.
- *
- * [bbb[ababab]aaa] where a = seg, b = list_seg.
- * overlap is the [ababab] part, which can be get using:
- * (list_seg->seq + list_seg->payload_len) - seg->seg */
- overlap = (list_seg->seq + list_seg->payload_len) - seg->seq;
- end_after = TRUE;
-
- SCLogDebug("starts beyond list seq, ends after list seq end: "
- "seg->seq %" PRIu32 ", seg->payload_len %"PRIu16" (%"PRIu32") "
- "list_seg->seq %" PRIu32 ", list_seg->payload_len %" PRIu32 " "
- "(%"PRIu32") overlap is %" PRIu32 "", seg->seq, seg->payload_len,
- seg->seq + seg->payload_len, list_seg->seq, list_seg->payload_len,
- list_seg->seq + list_seg->payload_len, overlap);
- }
- if (overlap > 0) {
- /*Handle the case when newly arrived segment ends after original
- segment and original segment is the last segment in the list*/
- if (end_after == TRUE) {
- char fill_gap = FALSE;
-
- if (list_seg->next != NULL) {
- /* first see if we have space left to fill up */
- if (SEQ_LT((list_seg->seq + list_seg->payload_len),
- list_seg->next->seq))
- {
- fill_gap = TRUE;
- }
+ if (stream) {
+ uint64_t size = 0;
+ uint32_t cnt = 0;
- /* then see if we overlap (partly) with the next seg */
- if (SEQ_GT((seg->seq + seg->payload_len), list_seg->next->seq))
- {
- handle_beyond = TRUE;
- }
- } else {
- fill_gap = TRUE;
- }
+ TcpSegment *seg = stream->seg_list;
+ while (seg) {
+ cnt++;
+ size += (uint64_t)TCP_SEG_LEN(seg);
- SCLogDebug("fill_gap %s, handle_beyond %s", fill_gap?"TRUE":"FALSE",
- handle_beyond?"TRUE":"FALSE");
+ seg = seg->next;
+ }
- if (fill_gap == TRUE) {
- /* if there is a gap after this list_seg we fill it now with a
- * new seg */
- if (list_seg->next != NULL) {
- SCLogDebug("filling gap: list_seg->next->seq %"PRIu32"",
- list_seg->next?list_seg->next->seq:0);
+ SCLogDebug("size %"PRIu64", cnt %"PRIu32, size, cnt);
+ return size;
+ }
+ return (uint64_t)0;
+}
- packet_length = list_seg->next->seq - (list_seg->seq +
- list_seg->payload_len);
- } else {
- packet_length = seg->payload_len - overlap;
- }
- if (packet_length > (seg->payload_len - overlap)) {
- packet_length = seg->payload_len - overlap;
- }
- SCLogDebug("packet_length %"PRIu16"", packet_length);
+static void GetSessionSize(TcpSession *ssn, Packet *p)
+{
+ uint64_t size = 0;
+ if (ssn) {
+ size = GetStreamSize(&ssn->client);
+ size += GetStreamSize(&ssn->server);
+
+ //if (size > 900000)
+ // SCLogInfo("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
+ SCLogDebug("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
+ }
+}
+#endif
- TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length);
- if (new_seg == NULL) {
- SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]);
+/** \internal
+ *
+ * Get buffer, or first part of the buffer if data gaps exist.
+ *
+ * \brief get stream data from offset
+ * \param offset stream offset */
+static void GetAppBuffer(TcpStream *stream, const uint8_t **data, uint32_t *data_len, uint64_t offset)
+{
+ const uint8_t *mydata;
+ uint32_t mydata_len;
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
- SCReturnInt(-1);
- }
- new_seg->payload_len = packet_length;
- new_seg->seq = list_seg->seq + list_seg->payload_len;
- new_seg->next = list_seg->next;
- if (new_seg->next != NULL)
- new_seg->next->prev = new_seg;
- new_seg->prev = list_seg;
- list_seg->next = new_seg;
-
- SCLogDebug("new_seg %p, new_seg->next %p, new_seg->prev %p, "
- "list_seg->next %p new_seg->seq %"PRIu32"", new_seg,
- new_seg->next, new_seg->prev, list_seg->next,
- new_seg->seq);
-
- StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq,
- new_seg->payload_len);
-
- /* update the stream last_seg in case of removal of list_seg */
- if (stream->seg_list_tail == list_seg)
- stream->seg_list_tail = new_seg;
- }
- }
+ if (stream->sb->block_list == NULL) {
+ SCLogDebug("getting one blob");
- if (check_overlap_different_data &&
- !StreamTcpSegmentDataCompare(list_seg, seg, seg->seq, overlap)) {
- /* interesting, overlap with different data */
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA);
- }
+ StreamingBufferGetDataAtOffset(stream->sb, &mydata, &mydata_len, offset);
- if (StreamTcpInlineMode()) {
- if (StreamTcpInlineSegmentCompare(list_seg, seg) != 0) {
- StreamTcpInlineSegmentReplacePacket(p, list_seg);
- }
+ *data = mydata;
+ *data_len = mydata_len;
+ } else {
+ StreamingBufferBlock *blk = stream->sb->block_list;
+
+ if (blk->offset > offset) {
+ SCLogDebug("gap, want data at offset %"PRIu64", got data at %"PRIu64,
+ offset, blk->offset);
+ *data = NULL;
+ *data_len = 0;
+
+ } else if (offset > blk->offset && offset <= (blk->offset + blk->len)) {
+ SCLogDebug("get data from offset %"PRIu64". SBB %"PRIu64"/%u",
+ offset, blk->offset, blk->len);
+ StreamingBufferSBBGetDataAtOffset(stream->sb, blk, data, data_len, offset);
+ SCLogDebug("data %p, data_len %u", *data, *data_len);
} else {
- switch (os_policy) {
- case OS_POLICY_SOLARIS:
- case OS_POLICY_HPUX11:
- if (end_after == TRUE) {
- StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap);
- } else {
- SCLogDebug("using old data in starts beyond list case, "
- "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
- "overlap %" PRIu32 "", list_seg->seq, os_policy,
- overlap);
- }
- break;
- case OS_POLICY_LAST:
- StreamTcpSegmentDataReplace(list_seg, seg, seg->seq, overlap);
- break;
- case OS_POLICY_BSD:
- case OS_POLICY_HPUX10:
- case OS_POLICY_IRIX:
- case OS_POLICY_WINDOWS:
- case OS_POLICY_WINDOWS2K3:
- case OS_POLICY_VISTA:
- case OS_POLICY_OLD_LINUX:
- case OS_POLICY_LINUX:
- case OS_POLICY_MACOS:
- case OS_POLICY_FIRST:
- default: /* DEFAULT POLICY */
- SCLogDebug("using old data in starts beyond list case, "
- "list_seg->seq %" PRIu32 " policy %" PRIu32 " "
- "overlap %" PRIu32 "", list_seg->seq, os_policy,
- overlap);
- break;
- }
- }
- if (end_before == TRUE || end_same == TRUE || handle_beyond == FALSE) {
- SCReturnInt(1);
+ StreamingBufferSBBGetData(stream->sb, blk, data, data_len);
}
}
- SCReturnInt(0);
}
-/**
- * \brief check if stream in pkt direction has depth reached
- *
- * \param p packet with *LOCKED* flow
- *
- * \retval 1 stream has depth reached
- * \retval 0 stream does not have depth reached
+/** \internal
+ * \brief get stream buffer and update the app-layer
+ * \retval 0 success
*/
-int StreamTcpReassembleDepthReached(Packet *p)
+static int ReassembleUpdateAppLayer (ThreadVars *tv,
+ TcpReassemblyThreadCtx *ra_ctx,
+ TcpSession *ssn, TcpStream *stream,
+ Packet *p)
{
- if (p->flow != NULL && p->flow->protoctx != NULL) {
- TcpSession *ssn = p->flow->protoctx;
- TcpStream *stream;
- if (p->flowflags & FLOW_PKT_TOSERVER) {
- stream = &ssn->client;
- } else {
- stream = &ssn->server;
+ const uint64_t app_progress = stream->app_progress;
+ uint64_t last_ack_abs = app_progress; /* absolute right edge of ack'd data */
+
+ SCLogDebug("app progress %"PRIu64, stream->app_progress);
+ SCLogDebug("last_ack %u, base_seq %u", stream->last_ack, stream->base_seq);
+
+ if (STREAM_LASTACK_GT_BASESEQ(stream)) {
+ /* get window of data that is acked */
+ uint32_t delta = stream->last_ack - stream->base_seq;
+ /* get max absolute offset */
+ last_ack_abs += delta;
+ }
+
+ const uint8_t *mydata;
+ uint32_t mydata_len;
+ GetAppBuffer(stream, &mydata, &mydata_len, stream->app_progress);
+ //PrintRawDataFp(stdout, mydata, mydata_len);
+
+ SCLogDebug("stream %p data in buffer %p of len %u and offset %u",
+ stream, stream->sb, mydata_len, (uint)stream->app_progress);
+
+ /* get window of data that is acked */
+ if (StreamTcpInlineMode() == 0 && (p->flags & PKT_PSEUDO_STREAM_END)) {
+ //
+ } else if (StreamTcpInlineMode() == 0) {
+ /* see if the buffer contains unack'd data as well */
+ if (stream->app_progress + mydata_len > last_ack_abs) {
+ mydata_len = last_ack_abs - stream->app_progress;
+ SCLogDebug("data len adjusted to %u to make sure only ACK'd "
+ "data is considered", mydata_len);
}
+ }
- return (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) ? 1 : 0;
+ /* update the app-layer */
+ int r = AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
+ (uint8_t *)mydata, mydata_len,
+ StreamGetAppLayerFlags(ssn, stream, p));
+
+ /* see if we can update the progress */
+ if (r == 0 && StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
+ if (mydata_len > 0) {
+ SCLogDebug("app progress %"PRIu64" increasing with data len %u to %"PRIu64,
+ stream->app_progress, mydata_len, stream->app_progress + mydata_len);
+
+ stream->app_progress += mydata_len;
+ SCLogDebug("app progress now %"PRIu64, stream->app_progress);
+ }
+ } else {
+ SCLogDebug("NOT UPDATED app progress now %"PRIu64, stream->app_progress);
}
- return 0;
+ SCReturnInt(0);
}
/**
- * \internal
- * \brief Function to Check the reassembly depth valuer against the
- * allowed max depth of the stream reassmbly for TCP streams.
+ * \brief Update the stream reassembly upon receiving an ACK packet.
*
- * \param stream stream direction
- * \param seq sequence number where "size" starts
- * \param size size of the segment that is added
+ * Stream is in the opposite direction of the packet, as the ACK-packet
+ * is ACK'ing the stream.
*
- * \retval size Part of the size that fits in the depth, 0 if none
+ * One of the utilities call by this function AppLayerHandleTCPData(),
+ * has a feature where it will call this very same function for the
+ * stream opposing the stream it is called with. This shouldn't cause
+ * any issues, since processing of each stream is independent of the
+ * other stream.
+ *
+ * \todo this function is too long, we need to break it up. It needs it BAD
*/
-static uint32_t StreamTcpReassembleCheckDepth(TcpSession *ssn, TcpStream *stream,
- uint32_t seq, uint32_t size)
+int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
+ TcpSession *ssn, TcpStream *stream,
+ Packet *p)
{
SCEnter();
- /* if the configured depth value is 0, it means there is no limit on
- reassembly depth. Otherwise carry on my boy ;) */
- if (ssn->reassembly_depth == 0) {
- SCReturnUInt(size);
+ /* this function can be directly called by app layer protocol
+ * detection. */
+ if (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
+ SCLogDebug("stream no reassembly flag set. Mostly called via "
+ "app proto detection.");
+ SCReturnInt(0);
}
- /* if the final flag is set, we're not accepting anymore */
- if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
- SCReturnUInt(0);
- }
+ SCLogDebug("stream->seg_list %p", stream->seg_list);
+#ifdef DEBUG
+ PrintList(stream->seg_list);
+ GetSessionSize(ssn, p);
+#endif
- /* if the ra_base_seq has moved passed the depth window we stop
- * checking and just reject the rest of the packets including
- * retransmissions. Saves us the hassle of dealing with sequence
- * wraps as well */
- if (SEQ_GEQ((StreamTcpReassembleGetRaBaseSeq(stream)+1),(stream->isn + ssn->reassembly_depth))) {
- stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED;
- SCReturnUInt(0);
- }
+ /* Check if we have a gap at the start of the stream. 2 conditions:
+ * 1. no segments, but last_ack moved fwd
+ * 2. segments, but clearly some missing: if last_ack is
+ * bigger than the list start and the list start is bigger than
+ * next_seq, we know we are missing data that has been ack'd. That
+ * won't get retransmitted, so it's a data gap.
+ */
+ if (!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) {
+ int ackadd = (ssn->state >= TCP_FIN_WAIT2) ? 2 : 1;
+ if ((stream->seg_list == NULL && /*1*/
+ stream->base_seq == stream->isn+1 &&
+ SEQ_GT(stream->last_ack, stream->isn + ackadd))
+ ||
+ (stream->seg_list != NULL && /*2*/
+ SEQ_GT(stream->seg_list->seq, stream->base_seq) &&
+ SEQ_LT(stream->seg_list->seq, stream->last_ack)))
+ {
+ if (stream->seg_list == NULL) {
+ SCLogDebug("no segs, last_ack moved fwd so GAP "
+ "(base %u, isn %u, last_ack %u => diff %u) p %"PRIu64,
+ stream->base_seq, stream->isn, stream->last_ack,
+ stream->last_ack - (stream->isn + ackadd), p->pcap_cnt);
+ }
+
+ /* send gap signal */
+ SCLogDebug("sending GAP to app-layer");
+ AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
+ NULL, 0,
+ StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP);
+ AppLayerProfilingStore(ra_ctx->app_tctx, p);
- SCLogDebug("full Depth not yet reached: %"PRIu32" <= %"PRIu32,
- (StreamTcpReassembleGetRaBaseSeq(stream)+1),
- (stream->isn + ssn->reassembly_depth));
+ /* set a GAP flag and make sure not bothering this stream anymore */
+ SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set");
+ stream->flags |= STREAMTCP_STREAM_FLAG_GAP;
- if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + ssn->reassembly_depth))) {
- /* packet (partly?) fits the depth window */
+ StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP);
+ StatsIncr(tv, ra_ctx->counter_tcp_reass_gap);
- if (SEQ_LEQ((seq + size),(stream->isn + ssn->reassembly_depth))) {
- /* complete fit */
- SCReturnUInt(size);
- } else {
- stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED;
- /* partial fit, return only what fits */
- uint32_t part = (stream->isn + ssn->reassembly_depth) - seq;
-#if DEBUG
- BUG_ON(part > size);
-#else
- if (part > size)
- part = size;
-#endif
- SCReturnUInt(part);
+ SCReturnInt(0);
}
}
- SCReturnUInt(0);
-}
+ /* 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;
+ if (seg_tail == NULL ||
+ SEGMENT_BEFORE_OFFSET(stream, seg_tail, stream->app_progress))
+ {
+ /* send an empty EOF msg if we have no segments but TCP state
+ * is beyond ESTABLISHED */
+ if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) {
+ SCLogDebug("sending empty eof message");
+ /* send EOF to app layer */
+ AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
+ NULL, 0,
+ StreamGetAppLayerFlags(ssn, stream, p));
+ AppLayerProfilingStore(ra_ctx->app_tctx, p);
-static void StreamTcpStoreStreamChunk(TcpSession *ssn, StreamMsg *smsg, const Packet *p, int streaminline)
-{
- uint8_t direction = 0;
+ SCReturnInt(0);
+ }
+ }
- if ((!streaminline && (p->flowflags & FLOW_PKT_TOSERVER)) ||
- ( streaminline && (p->flowflags & FLOW_PKT_TOCLIENT)))
- {
- direction = STREAM_TOCLIENT;
- SCLogDebug("stream chunk is to_client");
- } else {
- direction = STREAM_TOSERVER;
- SCLogDebug("stream chunk is to_server");
+ /* no segments, nothing to do */
+ if (stream->seg_list == NULL) {
+ SCLogDebug("no segments in the list to reassemble");
+ SCReturnInt(0);
}
- /* store the smsg in the tcp stream */
- if (direction == STREAM_TOSERVER) {
- SCLogDebug("storing smsg in the to_server");
+ if (stream->flags & STREAMTCP_STREAM_FLAG_GAP) {
+ SCReturnInt(0);
+ }
- /* put the smsg in the stream list */
- if (ssn->toserver_smsg_head == NULL) {
- ssn->toserver_smsg_head = smsg;
- ssn->toserver_smsg_tail = smsg;
- smsg->next = NULL;
- smsg->prev = NULL;
- } else {
- StreamMsg *cur = ssn->toserver_smsg_tail;
- cur->next = smsg;
- smsg->prev = cur;
- smsg->next = NULL;
- ssn->toserver_smsg_tail = smsg;
+ /* with all that out of the way, lets update the app-layer */
+ ReassembleUpdateAppLayer(tv, ra_ctx, ssn, stream, p);
+
+ SCReturnInt(0);
+}
+
+/** \internal
+ * \brief get stream data from offset
+ * \param offset stream offset */
+static int GetRawBuffer(TcpStream *stream, const uint8_t **data, uint32_t *data_len,
+ StreamingBufferBlock **iter, uint64_t offset, uint64_t *data_offset)
+{
+ const uint8_t *mydata;
+ uint32_t mydata_len;
+ if (stream->sb->block_list == NULL) {
+ SCLogDebug("getting one blob");
+
+ uint64_t roffset = offset;
+ if (offset)
+ StreamingBufferGetDataAtOffset(stream->sb, &mydata, &mydata_len, offset);
+ else {
+ StreamingBufferGetData(stream->sb, &mydata, &mydata_len, &roffset);
}
+
+ *data = mydata;
+ *data_len = mydata_len;
+ *data_offset = roffset;
} else {
- SCLogDebug("storing smsg in the to_client");
+ if (*iter == NULL)
+ *iter = stream->sb->block_list;
+ if (*iter == NULL) {
+ *data = NULL;
+ *data_len = 0;
+ return 0;
+ }
+
+ if (offset) {
+ while (*iter && ((*iter)->offset + (*iter)->len < offset))
+ *iter = (*iter)->next;
+ if (*iter == NULL) {
+ *data = NULL;
+ *data_len = 0;
+ *data_offset = 0;
+ return 0;
+ }
+ }
+
+ SCLogDebug("getting multiple blobs. Iter %p, %"PRIu64"/%u (next? %s)", *iter, (*iter)->offset, (*iter)->len, (*iter)->next ? "yes":"no");
+
+ StreamingBufferSBBGetData(stream->sb, (*iter), &mydata, &mydata_len);
+
+ if ((*iter)->offset < offset) {
+ uint64_t delta = offset - (*iter)->offset;
+ if (delta < mydata_len) {
+ *data = mydata + delta;
+ *data_len = mydata_len - delta;
+ *data_offset = offset;
+ } else {
+ *data = NULL;
+ *data_len = 0;
+ *data_offset = 0;
+ }
- /* put the smsg in the stream list */
- if (ssn->toclient_smsg_head == NULL) {
- ssn->toclient_smsg_head = smsg;
- ssn->toclient_smsg_tail = smsg;
- smsg->next = NULL;
- smsg->prev = NULL;
} else {
- StreamMsg *cur = ssn->toclient_smsg_tail;
- cur->next = smsg;
- smsg->prev = cur;
- smsg->next = NULL;
- ssn->toclient_smsg_tail = smsg;
+ *data = mydata;
+ *data_len = mydata_len;
+ *data_offset = (*iter)->offset;
}
+
+ *iter = (*iter)->next;
}
+ return 0;
}
-/**
- * \brief Insert a packets TCP data into the stream reassembly engine.
- *
- * \retval 0 good segment, as far as we checked.
- * \retval -1 badness, reason to drop in inline mode
- *
- * If the retval is 0 the segment is inserted correctly, or overlap is handled,
- * or it wasn't added because of reassembly depth.
- *
+/** \internal
+ * \brief based on the data in the streaming buffer setup StreamMsgs
*/
-int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
- TcpSession *ssn, TcpStream *stream, Packet *p)
+static int ReassembleRaw(TcpSession *ssn, TcpStream *stream, Packet *p)
{
SCEnter();
- if (ssn->data_first_seen_dir == 0) {
- if (p->flowflags & FLOW_PKT_TOSERVER) {
- ssn->data_first_seen_dir = STREAM_TOSERVER;
- } else {
- ssn->data_first_seen_dir = STREAM_TOCLIENT;
+ StreamingBufferBlock *iter = NULL;
+ uint64_t progress = stream->raw_progress;
+ uint64_t last_ack_abs = 0; /* absolute right edge of ack'd data */
+ uint64_t right_edge_abs = 0;
+
+ /* get window of data that is acked */
+ SCLogDebug("last_ack %u, base_seq %u", stream->last_ack, stream->base_seq);
+ uint32_t delta = stream->last_ack - stream->base_seq;
+ /* get max absolute offset */
+ last_ack_abs = stream->base_seq_offset + delta;
+ right_edge_abs = last_ack_abs;
+
+ if (StreamTcpInlineMode() == TRUE) {
+ uint32_t chunk_size = PKT_IS_TOSERVER(p) ?
+ stream_config.reassembly_toserver_chunk_size :
+ stream_config.reassembly_toclient_chunk_size;
+ SCLogDebug("pkt SEQ %u, payload_len %u; base_seq %u => base_seq_offset %"PRIu64,
+ TCP_GET_SEQ(p), p->payload_len,
+ stream->base_seq, stream->base_seq_offset);
+
+ SCLogDebug("progress before adjust %"PRIu64", chunk_size %"PRIu32, progress, chunk_size);
+
+ /* determine the left edge and right edge */
+ uint32_t rel_right_edge = TCP_GET_SEQ(p) + p->payload_len;
+ uint32_t rel_left_edge = rel_right_edge - chunk_size;
+ SCLogDebug("left_edge %"PRIu32", right_edge %"PRIu32", chunk_size %u", rel_left_edge, rel_right_edge, chunk_size);
+
+ if (SEQ_LT(rel_left_edge, stream->base_seq)) {
+ rel_left_edge = stream->base_seq;
+ rel_right_edge = rel_left_edge + chunk_size;
+ SCLogDebug("adjusting left_edge to not be before base_seq: left_edge %u", rel_left_edge);
}
- }
- if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) &&
- (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED)) {
- SCLogDebug("ssn %p: both app and raw reassembly disabled, not reassembling", ssn);
- SCReturnInt(0);
+ progress = stream->base_seq_offset + (rel_left_edge - stream->base_seq);
+ right_edge_abs = progress + chunk_size;
+ SCLogDebug("working with progress %"PRIu64, progress);
+
+ SCLogDebug("left_edge %"PRIu32", right_edge %"PRIu32, rel_left_edge, rel_right_edge);
}
- /* If we have reached the defined depth for either of the stream, then stop
- reassembling the TCP session */
- uint32_t size = StreamTcpReassembleCheckDepth(ssn, stream, TCP_GET_SEQ(p), p->payload_len);
- SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size);
+ /* loop through available buffers. On no packet loss we'll have a single
+ * iteration. On missing data we'll walk the blocks */
+ while (1) {
+ const uint8_t *mydata;
+ uint32_t mydata_len;
+ uint64_t mydata_offset = 0;
- if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
- /* increment stream depth counter */
- StatsIncr(tv, ra_ctx->counter_tcp_stream_depth);
+ GetRawBuffer(stream, &mydata, &mydata_len, &iter, progress, &mydata_offset);
+ if (mydata_len == 0)
+ break;
+ //PrintRawDataFp(stdout, mydata, mydata_len);
- stream->flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY;
- SCLogDebug("ssn %p: reassembly depth reached, "
- "STREAMTCP_STREAM_FLAG_NOREASSEMBLY set", ssn);
- }
- if (size == 0) {
- SCLogDebug("ssn %p: depth reached, not reassembling", ssn);
- SCReturnInt(0);
- }
+ SCLogDebug("raw progress %"PRIu64, progress);
+ SCLogDebug("stream %p data in buffer %p of len %u and offset %u",
+ stream, stream->sb, mydata_len, (uint)progress);
-#if DEBUG
- BUG_ON(size > p->payload_len);
-#else
- if (size > p->payload_len)
- size = p->payload_len;
-#endif
+ if (StreamTcpInlineMode() == 0 && (p->flags & PKT_PSEUDO_STREAM_END)) {
+ //
+ } else if (StreamTcpInlineMode() == FALSE) {
+ if (right_edge_abs < progress) {
+ SCLogDebug("nothing to do");
+ goto end;
+ }
- TcpSegment *seg = StreamTcpGetSegment(tv, ra_ctx, size);
- if (seg == NULL) {
- SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[size]);
+ SCLogDebug("delta %u, right_edge_abs %"PRIu64", raw_progress %"PRIu64, delta, right_edge_abs, progress);
+ SCLogDebug("raw_progress + mydata_len %"PRIu64", right_edge_abs %"PRIu64, progress + mydata_len, right_edge_abs);
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT);
- SCReturnInt(-1);
- }
+ /* see if the buffer contains unack'd data as well */
+ if (progress + mydata_len > last_ack_abs) {
+ mydata_len = last_ack_abs - progress;
+ SCLogDebug("data len adjusted to %u to make sure only ACK'd "
+ "data is considered", mydata_len);
+ }
- memcpy(seg->payload, p->payload, size);
- seg->payload_len = size;
- seg->seq = TCP_GET_SEQ(p);
+ /* StreamTcpInlineMode() == TRUE */
+ } else {
+ if (progress + mydata_len > right_edge_abs) {
+ uint32_t delta = (progress + mydata_len) - right_edge_abs;
+ SCLogDebug("adjusting mydata_len %u to subtract %u", mydata_len, delta);
+ mydata_len -= delta;
+ }
+ }
+ if (mydata_len == 0)
+ break;
- if (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)
- seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED;
+ SCLogDebug("data %p len %u", mydata, mydata_len);
+
+ /*
+ [buffer with segment data]
+ ^
+ |
+ base_seq_offset (0 on start start)
+ base_seq (ISN on start start)
+
+ going from 'progress' to SEQ => (progress - base_seq_offset) + base_seq;
+ */
+#define GET_SEQ_FOR_PROGRESS(stream, progress) \
+ (((progress) - (stream)->base_seq_offset) + (stream->base_seq))
+
+ /* we have data. Use it to setup StreamMsg(s) */
+ StreamMsg *smsg = NULL;
+ uint32_t data_offset = 0;
+ uint32_t data_left = mydata_len;
+ while (data_left) {
+ smsg = StreamMsgGetFromPool();
+ if (smsg == NULL)
+ break;
- /* if raw reassembly is disabled for new segments, flag each
- * segment as complete for raw before insert */
- if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) {
- seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED;
- SCLogDebug("segment %p flagged with SEGMENTTCP_FLAG_RAW_PROCESSED, "
- "flags %02x", seg, seg->flags);
- }
+ uint32_t copy_len = (data_left > smsg->data_size) ? smsg->data_size : data_left;
+ SCLogDebug("copy_len %u, data_left %u", copy_len, data_left);
- /* proto detection skipped, but now we do get data. Set event. */
- if (stream->seg_list == NULL &&
- stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED) {
+ memcpy(smsg->data, mydata + data_offset, copy_len);
+ smsg->data_len = copy_len;
+ smsg->seq = GET_SEQ_FOR_PROGRESS(stream, (mydata_offset + data_offset));
+ SCLogDebug("smsg %p seq %u", smsg, smsg->seq);
- AppLayerDecoderEventsSetEventRaw(&p->app_layer_events,
- APPLAYER_PROTO_DETECTION_SKIPPED);
- }
+ BUG_ON(copy_len > data_left);
+ data_left -= copy_len;
+ BUG_ON(data_left > mydata_len);
+ data_offset += copy_len;
- if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, seg, p) != 0) {
- SCLogDebug("StreamTcpReassembleInsertSegment failed");
- SCReturnInt(-1);
- }
+ SCLogDebug("smsg %p %u/%u", smsg, smsg->data_len, smsg->data_size);
+ //PrintRawDataFp(stdout, smsg->data, smsg->data_len);
- SCReturnInt(0);
-}
+ StreamTcpStoreStreamChunk(ssn, smsg, p, StreamTcpInlineMode());
+ }
-static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream,
- Packet *p)
-{
- uint8_t flag = 0;
+ if (mydata_offset == progress) {
+ SCLogDebug("raw progress %"PRIu64" increasing with data len %u to %"PRIu64,
+ progress, mydata_len, stream->raw_progress + mydata_len);
- if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) {
- flag |= STREAM_START;
- }
+ //if (StreamTcpInlineMode() == TRUE) {
+ //progress = right_edge_abs;
+ //} else {
+ progress += mydata_len;
+ //}
+ SCLogDebug("raw progress now %"PRIu64, progress);
- if (ssn->state == TCP_CLOSED) {
- flag |= STREAM_EOF;
- }
- if (p->flags & PKT_PSEUDO_STREAM_END) {
- flag |= STREAM_EOF;
- }
+ /* data is beyond the progress we'd like, and before last ack. Gap. */
+ } else if (mydata_offset > progress && mydata_offset < last_ack_abs) {
+ SCLogDebug("GAP: data is missing from %"PRIu64" (%u bytes), setting to first data we have: %"PRIu64, progress, (uint32_t)(mydata_offset - progress), mydata_offset);
+ SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs);
+ progress = mydata_offset;
+ SCLogDebug("raw progress now %"PRIu64, progress);
- if (StreamTcpInlineMode() == 0) {
- if (p->flowflags & FLOW_PKT_TOSERVER) {
- flag |= STREAM_TOCLIENT;
- } else {
- flag |= STREAM_TOSERVER;
- }
- } else {
- if (p->flowflags & FLOW_PKT_TOSERVER) {
- flag |= STREAM_TOSERVER;
} else {
- flag |= STREAM_TOCLIENT;
+ SCLogDebug("not increasing progress, data gap => mydata_offset "
+ "%"PRIu64" != progress %"PRIu64, mydata_offset, progress);
}
- }
- if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
- flag |= STREAM_DEPTH;
+ if (iter == NULL)
+ break;
}
- return flag;
+end:
+ stream->raw_progress = progress;
+ SCLogDebug("stream raw progress now %"PRIu64, stream->raw_progress);
+ return 0;
}
-static void StreamTcpSetupMsg(TcpSession *ssn, TcpStream *stream, Packet *p,
- StreamMsg *smsg)
+/**
+ * \brief Update the stream reassembly upon receiving an ACK packet.
+ * \todo this function is too long, we need to break it up. It needs it BAD
+ */
+int StreamTcpReassembleRaw (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
+ TcpSession *ssn, TcpStream *stream, Packet *p)
{
SCEnter();
- smsg->data_len = 0;
- SCLogDebug("smsg %p", smsg);
- SCReturn;
+ SCLogDebug("start p %p", p);
+
+ if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW)
+ SCReturnInt(0);
+
+ if (stream->seg_list == NULL) {
+ SCLogDebug("no segments in the list to reassemble");
+ SCReturnInt(0);
+ }
+
+#if 0
+ if (ssn->state <= TCP_ESTABLISHED &&
+ !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
+ SCLogDebug("only starting raw reassembly after app layer protocol "
+ "detection has completed.");
+ SCReturnInt(0);
+ }
+#endif
+ /* check if we have enough data */
+ if (StreamTcpInlineMode() == FALSE &&
+ StreamTcpReassembleRawCheckLimit(ssn,stream,p) == 0)
+ {
+ SCLogDebug("not yet reassembling");
+ SCReturnInt(0);
+ }
+
+ /* take the data we have, and turn it into StreamMsgs */
+ ReassembleRaw(ssn, stream, p);
+ SCReturnInt(0);
}
-/**
- * \brief Check the minimum size limits for reassembly.
+/** \brief update app layer and raw reassembly
*
- * \retval 0 don't reassemble yet
- * \retval 1 do reassemble
+ * \retval r 0 on success, -1 on error
*/
-static int StreamTcpReassembleRawCheckLimit(TcpSession *ssn, TcpStream *stream,
- Packet *p)
+int StreamTcpReassembleHandleSegmentUpdateACK (ThreadVars *tv,
+ TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p)
{
SCEnter();
- if (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
- SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NOREASSEMBLY is set, so not expecting any new packets");
- SCReturnInt(1);
+ SCLogDebug("stream->seg_list %p", stream->seg_list);
+
+ int r = 0;
+ if (!(StreamTcpInlineMode())) {
+ if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p) < 0)
+ r = -1;
+ if (StreamTcpReassembleRaw(tv, ra_ctx, ssn, stream, p) < 0)
+ r = -1;
}
- if (ssn->flags & STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY) {
- SCLogDebug("reassembling now as STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY is set");
- ssn->flags &= ~STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY;
- SCReturnInt(1);
+ SCLogDebug("stream->seg_list %p", stream->seg_list);
+ SCReturnInt(r);
+}
+
+int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
+ TcpSession *ssn, TcpStream *stream,
+ Packet *p, PacketQueue *pq)
+{
+ SCEnter();
+ SCLogDebug("ssn %p, stream %p, p %p, p->payload_len %"PRIu16"",
+ ssn, stream, p, p->payload_len);
+
+ /* we need to update the opposing stream in
+ * StreamTcpReassembleHandleSegmentUpdateACK */
+ TcpStream *opposing_stream = NULL;
+ if (stream == &ssn->client) {
+ opposing_stream = &ssn->server;
+ } else {
+ opposing_stream = &ssn->client;
}
- if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) {
- SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED is set, "
- "so no new segments will be considered");
- SCReturnInt(1);
+ /* handle ack received */
+ if (StreamTcpReassembleHandleSegmentUpdateACK(tv, ra_ctx, ssn, opposing_stream, p) != 0)
+ {
+ SCLogDebug("StreamTcpReassembleHandleSegmentUpdateACK error");
+ SCReturnInt(-1);
}
- /* some states mean we reassemble no matter how much data we have */
- if (ssn->state >= TCP_TIME_WAIT)
- SCReturnInt(1);
+ /* If no stream reassembly/application layer protocol inspection, then
+ simple return */
+ if (p->payload_len > 0 && !(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
+ SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData");
- if (p->flags & PKT_PSEUDO_STREAM_END)
- SCReturnInt(1);
+ if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) {
+ SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error");
+ SCReturnInt(-1);
+ }
- /* check if we have enough data to send to L7 */
- if (p->flowflags & FLOW_PKT_TOCLIENT) {
- SCLogDebug("StreamMsgQueueGetMinChunkLen(STREAM_TOSERVER) %"PRIu32,
- StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER));
+ p->flags |= PKT_STREAM_ADD;
+ }
- if (StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER) >
- (stream->last_ack - stream->ra_raw_base_seq)) {
- SCLogDebug("toserver min chunk len not yet reached: "
- "last_ack %"PRIu32", ra_raw_base_seq %"PRIu32", %"PRIu32" < "
- "%"PRIu32"", stream->last_ack, stream->ra_raw_base_seq,
- (stream->last_ack - stream->ra_raw_base_seq),
- StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOSERVER));
- SCReturnInt(0);
- }
- } else {
- SCLogDebug("StreamMsgQueueGetMinChunkLen(STREAM_TOCLIENT) %"PRIu32,
- StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT));
+ /* in stream inline mode even if we have no data we call the reassembly
+ * functions to handle EOF */
+ if (StreamTcpInlineMode()) {
+ int r = 0;
+ if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p) < 0)
+ r = -1;
+ if (StreamTcpReassembleRaw(tv, ra_ctx, ssn, stream, p) < 0)
+ r = -1;
- if (StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT) >
- (stream->last_ack - stream->ra_raw_base_seq)) {
- SCLogDebug("toclient min chunk len not yet reached: "
- "last_ack %"PRIu32", ra_base_seq %"PRIu32", %"PRIu32" < "
- "%"PRIu32"", stream->last_ack, stream->ra_raw_base_seq,
- (stream->last_ack - stream->ra_raw_base_seq),
- StreamMsgQueueGetMinChunkLen(FLOW_PKT_TOCLIENT));
- SCReturnInt(0);
+ if (r < 0) {
+ SCReturnInt(-1);
}
}
- SCReturnInt(1);
+ SCReturnInt(0);
}
/**
- * \brief see if app layer is done with a segment
- *
- * \retval 1 app layer is done with this segment
- * \retval 0 not done yet
- */
-#define StreamTcpAppLayerSegmentProcessed(ssn, stream, segment) \
- (( ( (ssn)->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) || \
- ( (stream)->flags & STREAMTCP_STREAM_FLAG_GAP ) || \
- ( (segment)->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED ) ? 1 :0 ))
-
-/** \internal
- * \brief check if we can remove a segment from our segment list
+ * \brief Function to get the segment of required length from the pool.
*
- * If a segment is entirely before the oldest smsg, we can discard it. Otherwise
- * we keep it around to be able to log it.
+ * \param len Length which tells the required size of needed segment.
*
- * \retval 1 yes
- * \retval 0 no
+ * \retval seg Segment from the pool or NULL
*/
-static inline int StreamTcpReturnSegmentCheck(const Flow *f, TcpSession *ssn, TcpStream *stream, TcpSegment *seg)
+TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, uint16_t len)
{
- if (stream == &ssn->client && ssn->toserver_smsg_head != NULL) {
- /* not (seg is entirely before first smsg, skip) */
- if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toserver_smsg_head->seq))) {
- SCReturnInt(0);
- }
- } else if (stream == &ssn->server && ssn->toclient_smsg_head != NULL) {
- /* not (seg is entirely before first smsg, skip) */
- if (!(SEQ_LEQ(seg->seq + seg->payload_len, ssn->toclient_smsg_head->seq))) {
- SCReturnInt(0);
- }
- }
-
- /* if proto detect isn't done, we're not returning */
- if (!(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream))) {
- SCReturnInt(0);
- }
-
- /* check app layer conditions */
- if (!(StreamTcpAppLayerSegmentProcessed(ssn, stream, seg))) {
- SCReturnInt(0);
- }
+ uint16_t idx = segment_pool_idx[len];
+ SCLogDebug("segment_pool_idx %" PRIu32 " for payload_len %" PRIu32 "",
+ idx, len);
- /* check raw reassembly conditions */
- if (!(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) {
- SCReturnInt(0);
- }
+ SCMutexLock(&segment_pool_mutex[idx]);
+ TcpSegment *seg = (TcpSegment *) PoolGet(segment_pool[idx]);
- SCReturnInt(1);
-}
+ SCLogDebug("segment_pool[%u]->empty_stack_size %u, segment_pool[%u]->alloc_"
+ "list_size %u, alloc %u", idx, segment_pool[idx]->empty_stack_size,
+ idx, segment_pool[idx]->alloc_stack_size,
+ segment_pool[idx]->allocated);
+ SCMutexUnlock(&segment_pool_mutex[idx]);
-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;
+ SCLogDebug("seg we return is %p", seg);
+ if (seg == NULL) {
+ SCLogDebug("segment_pool[%u]->empty_stack_size %u, "
+ "alloc %u", idx, segment_pool[idx]->empty_stack_size,
+ segment_pool[idx]->allocated);
+ /* Increment the counter to show that we are not able to serve the
+ segment request due to memcap limit */
+ StatsIncr(tv, ra_ctx->counter_tcp_segment_memcap);
} else {
- seg->prev->next = seg->next;
- if (seg->next != NULL)
- seg->next->prev = seg->prev;
+ seg->flags = stream_config.segment_init_flags;
+ seg->next = NULL;
+ seg->prev = NULL;
+
+ memset(&seg->sbseg, 0, sizeof(seg->sbseg));
}
- if (stream->seg_list_tail == seg)
- stream->seg_list_tail = seg->prev;
+#ifdef DEBUG
+ SCMutexLock(&segment_pool_cnt_mutex);
+ segment_pool_cnt++;
+ SCMutexUnlock(&segment_pool_cnt_mutex);
+#endif
+
+ return seg;
}
/**
- * \brief Update the stream reassembly upon receiving a data segment
- *
- * | left edge | right edge based on sliding window size
- * [aaa]
- * [aaabbb]
- * ...
- * [aaabbbcccdddeeefff]
- * [bbbcccdddeeefffggg] <- cut off aaa to adhere to the window size
+ * \brief Trigger RAW stream reassembly
*
- * GAP situation: each chunk that is uninterrupted has it's own smsg
- * [aaabbb].[dddeeefff]
- * [aaa].[ccc].[eeefff]
+ * Used by AppLayerTriggerRawStreamReassembly to trigger RAW stream
+ * reassembly from the applayer, for example upon completion of a
+ * HTTP request.
*
- * A flag will be set to indicate where the *NEW* payload starts. This
- * is to aid the detection code for alert only sigs.
+ * Works by setting a flag in the TcpSession that is unset as soon
+ * as it's checked. Since everything happens when operating under
+ * a single lock period, no side effects are expected.
*
- * \todo this function is too long, we need to break it up. It needs it BAD
+ * \param ssn TcpSession
*/
-static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx,
- TcpSession *ssn, TcpStream *stream, Packet *p)
+void StreamTcpReassembleTriggerRawReassembly(TcpSession *ssn)
{
- SCEnter();
- SCLogDebug("start p %p, seq %"PRIu32, p, TCP_GET_SEQ(p));
+#ifdef DEBUG
+ BUG_ON(ssn == NULL);
+#endif
- if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW)
- SCReturnInt(0);
- if (stream->seg_list == NULL) {
- SCReturnInt(0);
+ if (ssn != NULL) {
+ SCLogDebug("flagged ssn %p for immediate raw reassembly", ssn);
+ ssn->flags |= STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY;
}
+}
- uint32_t ra_base_seq = stream->ra_raw_base_seq;
- StreamMsg *smsg = NULL;
- uint32_t smsg_offset = 0;
- uint16_t payload_offset = 0;
- uint16_t payload_len = 0;
- TcpSegment *seg = stream->seg_list;
- uint32_t next_seq = ra_base_seq + 1;
- int gap = 0;
+#ifdef UNITTESTS
+/** unit tests and it's support functions below */
- uint32_t chunk_size = PKT_IS_TOSERVER(p) ?
- stream_config.reassembly_toserver_chunk_size :
- stream_config.reassembly_toclient_chunk_size;
+#define SET_ISN(stream, setseq) \
+ (stream)->isn = (setseq); \
+ (stream)->base_seq = (setseq) + 1
- /* determine the left edge and right edge */
- uint32_t right_edge = TCP_GET_SEQ(p) + p->payload_len;
- uint32_t left_edge = right_edge - chunk_size;
+static int UtTestSmsg(StreamMsg *smsg, const uint8_t *buf, uint32_t buf_len)
+{
+ if (smsg == NULL)
+ return 0;
- /* shift the window to the right if the left edge doesn't cover segments */
- if (SEQ_GT(seg->seq,left_edge)) {
- right_edge += (seg->seq - left_edge);
- left_edge = seg->seq;
+ if (smsg->data_len != buf_len) {
+ printf("Got: data_len %u, expected %u\n", smsg->data_len, buf_len);
+ PrintRawDataFp(stdout, smsg->data, smsg->data_len);
+ return 0;
}
- SCLogDebug("left_edge %"PRIu32", right_edge %"PRIu32, left_edge, right_edge);
-
- /* loop through the segments and fill one or more msgs */
- for (; seg != NULL && SEQ_LT(seg->seq, right_edge); ) {
- SCLogDebug("seg %p", seg);
+ if (!(memcmp(buf, smsg->data, buf_len) == 0)) {
+ printf("data is not what we expected:\nExpected:\n");
+ PrintRawDataFp(stdout, (uint8_t *)buf, buf_len);
+ printf("Got:\n");
+ PrintRawDataFp(stdout, smsg->data, smsg->data_len);
+ return 0;
+ }
+ return 1;
+}
- /* If packets are fully before ra_base_seq, skip them. We do this
- * because we've reassembled up to the ra_base_seq point already,
- * so we won't do anything with segments before it anyway. */
- SCLogDebug("checking for pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32""
- " len %"PRIu16", combined %"PRIu32" and right_edge "
- "%"PRIu32"", ra_base_seq, seg, seg->seq,
- seg->payload_len, seg->seq+seg->payload_len, right_edge);
+static uint32_t UtSsnSmsgCnt(TcpSession *ssn, uint8_t direction)
+{
+ uint32_t cnt = 0;
+ StreamMsg *smsg = (direction == STREAM_TOSERVER) ?
+ ssn->toserver_smsg_head :
+ ssn->toclient_smsg_head;
+ while (smsg) {
+ cnt++;
+ smsg = smsg->next;
+ }
+ return cnt;
+}
- /* Remove the segments which are completely before the ra_base_seq */
- if (SEQ_LT((seg->seq + seg->payload_len), (ra_base_seq - chunk_size)))
- {
- SCLogDebug("removing pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32""
- " len %"PRIu16"", ra_base_seq, seg, seg->seq,
- seg->payload_len);
-
- /* only remove if app layer reassembly is ready too */
- if (StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) {
- TcpSegment *next_seg = seg->next;
- StreamTcpRemoveSegmentFromStream(stream, seg);
- StreamTcpSegmentReturntoPool(seg);
- seg = next_seg;
- /* otherwise, just flag it for removal */
- } else {
- seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED;
- seg = seg->next;
- }
- continue;
- }
-
- /* if app layer protocol has been detected, then remove all the segments
- * which has been previously processed and reassembled
- *
- * If the stream is in GAP state the app layer flag won't be set */
- if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream) &&
- (seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) &&
- StreamTcpAppLayerSegmentProcessed(ssn, stream, seg))
- {
- SCLogDebug("segment(%p) of length %"PRIu16" has been processed,"
- " so return it to pool", seg, seg->payload_len);
- TcpSegment *next_seg = seg->next;
- StreamTcpRemoveSegmentFromStream(stream, seg);
- StreamTcpSegmentReturntoPool(seg);
- seg = next_seg;
- continue;
- }
-
- /* we've run into a sequence gap, wrap up any existing smsg and
- * queue it so the next chunk (if any) is in a new smsg */
- if (SEQ_GT(seg->seq, next_seq)) {
- /* pass on pre existing smsg (if any) */
- if (smsg != NULL && smsg->data_len > 0) {
- StreamTcpStoreStreamChunk(ssn, smsg, p, 1);
- stream->ra_raw_base_seq = ra_base_seq;
- smsg = NULL;
- }
-
- gap = 1;
- }
-
- /* if the segment ends beyond left_edge we need to consider it */
- if (SEQ_GT((seg->seq + seg->payload_len), left_edge)) {
- SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", "
- "left_edge %" PRIu32 "", seg->seq,
- seg->payload_len, left_edge);
-
- /* handle segments partly before ra_base_seq */
- if (SEQ_GT(left_edge, seg->seq)) {
- payload_offset = left_edge - seg->seq;
-
- if (SEQ_LT(right_edge, (seg->seq + seg->payload_len))) {
- payload_len = (right_edge - seg->seq) - payload_offset;
- } else {
- payload_len = seg->payload_len - payload_offset;
- }
-
- if (SCLogDebugEnabled()) {
- BUG_ON(payload_offset > seg->payload_len);
- BUG_ON((payload_len + payload_offset) > seg->payload_len);
- }
- } else {
- payload_offset = 0;
-
- if (SEQ_LT(right_edge, (seg->seq + seg->payload_len))) {
- payload_len = right_edge - seg->seq;
- } else {
- payload_len = seg->payload_len;
- }
- }
- SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16""
- " and stream->last_ack is %"PRIu32"", payload_offset,
- payload_len, stream->last_ack);
-
- if (payload_len == 0) {
- SCLogDebug("no payload_len, so bail out");
- break;
- }
-
- if (smsg == NULL) {
- smsg = StreamMsgGetFromPool();
- if (smsg == NULL) {
- SCLogDebug("stream_msg_pool is empty");
- return -1;
- }
-
- smsg_offset = 0;
-
- StreamTcpSetupMsg(ssn, stream, p, smsg);
- smsg->seq = ra_base_seq + 1;
- }
-
- /* copy the data into the smsg */
- uint32_t copy_size = smsg->data_size - smsg_offset;
- if (copy_size > payload_len) {
- copy_size = payload_len;
- }
- if (SCLogDebugEnabled()) {
- BUG_ON(copy_size > smsg->data_size);
- }
- SCLogDebug("copy_size is %"PRIu16"", copy_size);
- memcpy(smsg->data + smsg_offset, seg->payload + payload_offset,
- copy_size);
- smsg_offset += copy_size;
-
- SCLogDebug("seg total %u, seq %u off %u copy %u, ra_base_seq %u",
- (seg->seq + payload_offset + copy_size), seg->seq,
- payload_offset, copy_size, ra_base_seq);
- if (gap == 0 && SEQ_GT((seg->seq + payload_offset + copy_size),ra_base_seq+1)) {
- ra_base_seq += copy_size;
- }
- SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq);
-
- smsg->data_len += copy_size;
-
- /* queue the smsg if it's full */
- if (smsg->data_len == smsg->data_size) {
- StreamTcpStoreStreamChunk(ssn, smsg, p, 1);
- stream->ra_raw_base_seq = ra_base_seq;
- smsg = NULL;
- }
-
- /* if the payload len is bigger than what we copied, we handle the
- * rest of the payload next... */
- if (copy_size < payload_len) {
- SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size,
- payload_len);
- payload_offset += copy_size;
- payload_len -= copy_size;
- SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is "
- "%"PRIu16" and stream->last_ack is %"PRIu32"",
- payload_offset, seg->payload_len, stream->last_ack);
- if (SCLogDebugEnabled()) {
- BUG_ON(payload_offset > seg->payload_len);
- }
-
- /* we need a while loop here as the packets theoretically can be
- * 64k */
- char segment_done = FALSE;
- while (segment_done == FALSE) {
- SCLogDebug("new msg at offset %" PRIu32 ", payload_len "
- "%" PRIu32 "", payload_offset, payload_len);
-
- /* get a new message
- XXX we need a setup function */
- smsg = StreamMsgGetFromPool();
- if (smsg == NULL) {
- SCLogDebug("stream_msg_pool is empty");
- SCReturnInt(-1);
- }
- smsg_offset = 0;
-
- StreamTcpSetupMsg(ssn, stream,p,smsg);
- smsg->seq = ra_base_seq + 1;
-
- copy_size = smsg->data_size - smsg_offset;
- if ((int32_t)copy_size > (seg->payload_len - payload_offset)) {
- copy_size = (seg->payload_len - payload_offset);
- }
- if (SCLogDebugEnabled()) {
- BUG_ON(copy_size > smsg->data_size);
- }
-
- SCLogDebug("copy payload_offset %" PRIu32 ", smsg_offset "
- "%" PRIu32 ", copy_size %" PRIu32 "",
- payload_offset, smsg_offset, copy_size);
- memcpy(smsg->data + smsg_offset, seg->payload +
- payload_offset, copy_size);
- smsg_offset += copy_size;
- if (gap == 0 && SEQ_GT((seg->seq + payload_offset + copy_size),ra_base_seq+1)) {
- ra_base_seq += copy_size;
- }
- SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq);
- smsg->data_len += copy_size;
- SCLogDebug("copied payload_offset %" PRIu32 ", "
- "smsg_offset %" PRIu32 ", copy_size %" PRIu32 "",
- payload_offset, smsg_offset, copy_size);
- if (smsg->data_len == smsg->data_size) {
- StreamTcpStoreStreamChunk(ssn, smsg, p, 1);
- stream->ra_raw_base_seq = ra_base_seq;
- smsg = NULL;
- }
-
- /* see if we have segment payload left to process */
- if ((copy_size + payload_offset) < seg->payload_len) {
- payload_offset += copy_size;
- payload_len -= copy_size;
-
- if (SCLogDebugEnabled()) {
- BUG_ON(payload_offset > seg->payload_len);
- }
- } else {
- payload_offset = 0;
- segment_done = TRUE;
- }
- }
- }
- }
-
- /* done with this segment, return it to the pool */
- TcpSegment *next_seg = seg->next;
- next_seq = seg->seq + seg->payload_len;
-
- if (SEQ_LT((seg->seq + seg->payload_len), (ra_base_seq - chunk_size))) {
- if (seg->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED) {
- StreamTcpRemoveSegmentFromStream(stream, seg);
- SCLogDebug("removing seg %p, seg->next %p", seg, seg->next);
- StreamTcpSegmentReturntoPool(seg);
- } else {
- seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED;
- }
- }
- seg = next_seg;
- }
-
- /* put the partly filled smsg in the queue */
- if (smsg != NULL) {
- StreamTcpStoreStreamChunk(ssn, smsg, p, 1);
- smsg = NULL;
- stream->ra_raw_base_seq = ra_base_seq;
- }
-
- /* see if we can clean up some segments */
- left_edge = (ra_base_seq + 1) - chunk_size;
- SCLogDebug("left_edge %"PRIu32", ra_base_seq %"PRIu32, left_edge, ra_base_seq);
-
- /* loop through the segments to remove unneeded segments */
- for (seg = stream->seg_list; seg != NULL && SEQ_LEQ((seg->seq + p->payload_len), left_edge); ) {
- SCLogDebug("seg %p seq %"PRIu32", len %"PRIu16", sum %"PRIu32, seg, seg->seq, seg->payload_len, seg->seq+seg->payload_len);
-
- /* only remove if app layer reassembly is ready too */
- if (StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) {
- TcpSegment *next_seg = seg->next;
- StreamTcpRemoveSegmentFromStream(stream, seg);
- StreamTcpSegmentReturntoPool(seg);
- seg = next_seg;
- } else {
- break;
- }
- }
- SCLogDebug("stream->ra_raw_base_seq %u", stream->ra_raw_base_seq);
- SCReturnInt(0);
-}
-
-/** \brief Remove idle TcpSegments from TcpSession
- *
- * \param f flow
- * \param flags direction flags
- */
-void StreamTcpPruneSession(Flow *f, uint8_t flags)
-{
- if (f == NULL || f->protoctx == NULL)
- return;
-
- TcpSession *ssn = f->protoctx;
- TcpStream *stream = NULL;
-
- if (flags & STREAM_TOSERVER) {
- stream = &ssn->client;
- } else if (flags & STREAM_TOCLIENT) {
- stream = &ssn->server;
- } else {
- return;
- }
-
- /* loop through the segments and fill one or more msgs */
- TcpSegment *seg = stream->seg_list;
-
- for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);)
- {
- SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32", FLAGS %02x",
- seg, seg->seq, seg->payload_len,
- (uint32_t)(seg->seq + seg->payload_len), seg->flags);
-
- if (StreamTcpReturnSegmentCheck(f, ssn, stream, seg) == 0) {
- break;
- }
-
- TcpSegment *next_seg = seg->next;
- StreamTcpRemoveSegmentFromStream(stream, seg);
- StreamTcpSegmentReturntoPool(seg);
- seg = next_seg;
- continue;
- }
-}
-
-#ifdef DEBUG
-static uint64_t GetStreamSize(TcpStream *stream)
-{
- if (stream) {
- uint64_t size = 0;
- uint32_t cnt = 0;
-
- TcpSegment *seg = stream->seg_list;
- while (seg) {
- cnt++;
- size += (uint64_t)seg->payload_len;
-
- seg = seg->next;
- }
-
- SCLogDebug("size %"PRIu64", cnt %"PRIu32, size, cnt);
- return size;
- }
- return (uint64_t)0;
-}
-
-static void GetSessionSize(TcpSession *ssn, Packet *p)
-{
- uint64_t size = 0;
- if (ssn) {
- size = GetStreamSize(&ssn->client);
- size += GetStreamSize(&ssn->server);
-
- //if (size > 900000)
- // SCLogInfo("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
- SCLogDebug("size %"PRIu64", packet %"PRIu64, size, p->pcap_cnt);
- }
-}
-#endif
-
-typedef struct ReassembleData_ {
- uint32_t ra_base_seq;
- uint32_t data_len;
- uint8_t data[4096];
- int partial; /* last segment was processed only partially */
- uint32_t data_sent; /* data passed on this run */
-} ReassembleData;
-
-/** \internal
- * \brief test if segment follows a gap. If so, handle the gap
- *
- * If in inline mode, segment may be un-ack'd. In this case we
- * consider it a gap, but it's not 'final' yet.
- *
- * \retval bool 1 gap 0 no gap
- */
-int DoHandleGap(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
- TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd,
- Packet *p, uint32_t next_seq)
-{
- if (unlikely(SEQ_GT(seg->seq, next_seq))) {
- /* we've run into a sequence gap */
-
- if (StreamTcpInlineMode()) {
- /* don't conclude it's a gap until we see that the data
- * that is missing was acked. */
- if (SEQ_GT(seg->seq,stream->last_ack) && ssn->state != TCP_CLOSED)
- return 1;
- }
-
- /* first, pass on data before the gap */
- if (rd->data_len > 0) {
- SCLogDebug("pre GAP data");
-
- /* process what we have so far */
- AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
- rd->data, rd->data_len,
- StreamGetAppLayerFlags(ssn, stream, p));
- AppLayerProfilingStore(ra_ctx->app_tctx, p);
- rd->data_sent += rd->data_len;
- rd->data_len = 0;
- }
-
-#ifdef DEBUG
- uint32_t gap_len = seg->seq - next_seq;
- SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , "
- "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"",
- next_seq, seg->seq, stream->last_ack, gap_len);
-#endif
- /* We have missed the packet and end host has ack'd it, so
- * IDS should advance it's ra_base_seq and should not consider this
- * packet any longer, even if it is retransmitted, as end host will
- * drop it anyway */
- rd->ra_base_seq = seg->seq - 1;
-
- /* send gap "signal" */
- AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
- NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP);
- AppLayerProfilingStore(ra_ctx->app_tctx, p);
-
- /* set a GAP flag and make sure not bothering this stream anymore */
- SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set");
- stream->flags |= STREAMTCP_STREAM_FLAG_GAP;
-
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP);
- StatsIncr(tv, ra_ctx->counter_tcp_reass_gap);
-#ifdef DEBUG
- dbg_app_layer_gap++;
-#endif
- return 1;
- }
- return 0;
-}
-
-static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
- TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd,
- Packet *p)
-{
- /* fast paths: send data directly into the app layer, w/o first doing
- * a copy step. However, don't use the fast path until protocol detection
- * has been completed
- * TODO if initial data is big enough for proto detect, we could do the
- * fast path anyway. */
- if (stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) {
- /* fast path 1: segment is exactly what we need */
- if (likely(rd->data_len == 0 &&
- SEQ_EQ(seg->seq, rd->ra_base_seq+1) &&
- SEQ_EQ(stream->last_ack, (seg->seq + seg->payload_len))))
- {
- /* process single segment directly */
- AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
- seg->payload, seg->payload_len,
- StreamGetAppLayerFlags(ssn, stream, p));
- AppLayerProfilingStore(ra_ctx->app_tctx, p);
- rd->data_sent += seg->payload_len;
- rd->ra_base_seq += seg->payload_len;
-#ifdef DEBUG
- ra_ctx->fp1++;
-#endif
- /* if after the first data chunk we have no alproto yet,
- * there is no point in continueing here. */
- if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
- SCLogDebug("no alproto after first data chunk");
- return 0;
- }
- return 1;
- /* fast path 2: segment acked completely, meets minimal size req for 0copy processing */
- } else if (rd->data_len == 0 &&
- SEQ_EQ(seg->seq, rd->ra_base_seq+1) &&
- SEQ_GT(stream->last_ack, (seg->seq + seg->payload_len)) &&
- seg->payload_len >= stream_config.zero_copy_size)
- {
- /* process single segment directly */
- AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
- seg->payload, seg->payload_len,
- StreamGetAppLayerFlags(ssn, stream, p));
- AppLayerProfilingStore(ra_ctx->app_tctx, p);
- rd->data_sent += seg->payload_len;
- rd->ra_base_seq += seg->payload_len;
-#ifdef DEBUG
- ra_ctx->fp2++;
-#endif
- /* if after the first data chunk we have no alproto yet,
- * there is no point in continueing here. */
- if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
- SCLogDebug("no alproto after first data chunk");
- return 0;
- }
- return 1;
- }
- }
-#ifdef DEBUG
- ra_ctx->sp++;
-#endif
- uint16_t payload_offset = 0;
- uint16_t payload_len = 0;
-
- /* start clean */
- rd->partial = FALSE;
-
- /* if the segment ends beyond ra_base_seq we need to consider it */
- if (SEQ_GT((seg->seq + seg->payload_len), rd->ra_base_seq+1)) {
- SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", "
- "ra_base_seq %" PRIu32 ", last_ack %"PRIu32, seg->seq,
- seg->payload_len, rd->ra_base_seq, stream->last_ack);
-
- if (StreamTcpInlineMode() == 0) {
- /* handle segments partly before ra_base_seq */
- if (SEQ_GT(rd->ra_base_seq, seg->seq)) {
- payload_offset = (rd->ra_base_seq + 1) - seg->seq;
- SCLogDebug("payload_offset %u", payload_offset);
-
- if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) {
- if (SEQ_LT(stream->last_ack, (rd->ra_base_seq + 1))) {
- return 1;
- } else {
- payload_len = (stream->last_ack - seg->seq) - payload_offset;
- SCLogDebug("payload_len %u", payload_len);
- }
- rd->partial = TRUE;
- } else {
- payload_len = seg->payload_len - payload_offset;
- SCLogDebug("payload_len %u", payload_len);
- }
-
- if (SCLogDebugEnabled()) {
- BUG_ON(payload_offset > seg->payload_len);
- BUG_ON((payload_len + payload_offset) > seg->payload_len);
- }
- } else {
- payload_offset = 0;
-
- if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) {
- payload_len = stream->last_ack - seg->seq;
- SCLogDebug("payload_len %u", payload_len);
-
- rd->partial = TRUE;
- } else {
- payload_len = seg->payload_len;
- SCLogDebug("payload_len %u", payload_len);
- }
- }
- /* inline mode, don't consider last_ack as we process un-ACK'd segments */
- } else {
- /* handle segments partly before ra_base_seq */
- if (SEQ_GT(rd->ra_base_seq, seg->seq)) {
- payload_offset = rd->ra_base_seq - seg->seq - 1;
- payload_len = seg->payload_len - payload_offset;
-
- if (SCLogDebugEnabled()) {
- BUG_ON(payload_offset > seg->payload_len);
- BUG_ON((payload_len + payload_offset) > seg->payload_len);
- }
- } else {
- payload_offset = 0;
- payload_len = seg->payload_len;
- }
- }
- SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16""
- " and stream->last_ack is %"PRIu32"", payload_offset,
- payload_len, stream->last_ack);
-
- if (payload_len == 0) {
- SCLogDebug("no payload_len, so bail out");
- return 0;
- }
-
- /* copy the data into the buffer */
- uint16_t copy_size = sizeof(rd->data) - rd->data_len;
- if (copy_size + payload_offset > seg->payload_len) {
- copy_size = seg->payload_len - payload_offset;
- }
- if (copy_size > payload_len) {
- copy_size = payload_len;
- }
- if (SCLogDebugEnabled()) {
- BUG_ON(copy_size > sizeof(rd->data));
- BUG_ON(copy_size+payload_offset > seg->payload_len);
- BUG_ON(copy_size+payload_offset > seg->pool_size);
- }
-
- SCLogDebug("copy_size is %"PRIu16"", copy_size);
- memcpy(rd->data + rd->data_len, seg->payload + payload_offset, copy_size);
- rd->data_len += copy_size;
- rd->ra_base_seq += copy_size;
- SCLogDebug("ra_base_seq %"PRIu32", data_len %"PRIu32, rd->ra_base_seq, rd->data_len);
-
- /* queue the smsg if it's full */
- if (rd->data_len == sizeof(rd->data)) {
- /* process what we have so far */
- AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
- rd->data, rd->data_len,
- StreamGetAppLayerFlags(ssn, stream, p));
- AppLayerProfilingStore(ra_ctx->app_tctx, p);
- rd->data_sent += rd->data_len;
- rd->data_len = 0;
-
- /* if after the first data chunk we have no alproto yet,
- * there is no point in continueing here. */
- if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
- SCLogDebug("no alproto after first data chunk");
- return 0;
- }
- }
-
- /* if the payload len is bigger than what we copied, we handle the
- * rest of the payload next... */
- if (copy_size < payload_len) {
- SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size,
- payload_len);
-
- payload_offset += copy_size;
- payload_len -= copy_size;
- SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is "
- "%"PRIu16" and stream->last_ack is %"PRIu32"",
- payload_offset, seg->payload_len, stream->last_ack);
- if (SCLogDebugEnabled()) {
- BUG_ON(payload_offset > seg->payload_len);
- }
-
- /* we need a while loop here as the packets theoretically can be
- * 64k */
- char segment_done = FALSE;
- while (segment_done == FALSE) {
- SCLogDebug("new msg at offset %" PRIu32 ", payload_len "
- "%" PRIu32 "", payload_offset, payload_len);
- rd->data_len = 0;
-
- copy_size = sizeof(rd->data) - rd->data_len;
- if (copy_size > (seg->payload_len - payload_offset)) {
- copy_size = (seg->payload_len - payload_offset);
- }
- if (SCLogDebugEnabled()) {
- BUG_ON(copy_size > sizeof(rd->data));
- }
-
- SCLogDebug("copy payload_offset %" PRIu32 ", data_len "
- "%" PRIu32 ", copy_size %" PRIu32 "",
- payload_offset, rd->data_len, copy_size);
- memcpy(rd->data + rd->data_len, seg->payload +
- payload_offset, copy_size);
- rd->data_len += copy_size;
- rd->ra_base_seq += copy_size;
- SCLogDebug("ra_base_seq %"PRIu32, rd->ra_base_seq);
- SCLogDebug("copied payload_offset %" PRIu32 ", "
- "data_len %" PRIu32 ", copy_size %" PRIu32 "",
- payload_offset, rd->data_len, copy_size);
-
- if (rd->data_len == sizeof(rd->data)) {
- /* process what we have so far */
- AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
- rd->data, rd->data_len,
- StreamGetAppLayerFlags(ssn, stream, p));
- AppLayerProfilingStore(ra_ctx->app_tctx, p);
- rd->data_sent += rd->data_len;
- rd->data_len = 0;
-
- /* if after the first data chunk we have no alproto yet,
- * there is no point in continueing here. */
- if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
- SCLogDebug("no alproto after first data chunk");
- return 0;
- }
- }
-
- /* see if we have segment payload left to process */
- if ((copy_size + payload_offset) < seg->payload_len) {
- payload_offset += copy_size;
- payload_len -= copy_size;
-
- if (SCLogDebugEnabled()) {
- BUG_ON(payload_offset > seg->payload_len);
- }
- } else {
- payload_offset = 0;
- segment_done = TRUE;
- }
- }
- }
- }
-
- return 1;
-}
-
-/**
- * \brief Update the stream reassembly upon receiving an ACK packet.
- *
- * Stream is in the opposite direction of the packet, as the ACK-packet
- * is ACK'ing the stream.
- *
- * One of the utilities call by this function AppLayerHandleTCPData(),
- * has a feature where it will call this very same function for the
- * stream opposing the stream it is called with. This shouldn't cause
- * any issues, since processing of each stream is independent of the
- * other stream.
- *
- * \todo this function is too long, we need to break it up. It needs it BAD
- */
-int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
- TcpSession *ssn, TcpStream *stream,
- Packet *p)
-{
- SCEnter();
-
- /* this function can be directly called by app layer protocol
- * detection. */
- if (stream->flags & (STREAMTCP_STREAM_FLAG_NOREASSEMBLY|STREAMTCP_STREAM_FLAG_GAP)) {
- SCLogDebug("stream no reassembly flag set. Mostly called via "
- "app proto detection.");
- SCReturnInt(0);
- }
-
- SCLogDebug("stream->seg_list %p", stream->seg_list);
-#ifdef DEBUG
- PrintList(stream->seg_list);
- GetSessionSize(ssn, p);
-#endif
-
- /* Check if we have a gap at the start of the stream. 2 conditions:
- * 1. no segments, but last_ack moved fwd
- * 2. segments, but clearly some missing: if last_ack is
- * bigger than the list start and the list start is bigger than
- * next_seq, we know we are missing data that has been ack'd. That
- * won't get retransmitted, so it's a data gap.
- */
- if (!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) {
- int ackadd = (ssn->state >= TCP_FIN_WAIT2) ? 2 : 1;
- if ((stream->seg_list == NULL && /*1*/
- stream->ra_app_base_seq == stream->isn &&
- SEQ_GT(stream->last_ack, stream->isn + ackadd))
- ||
- (stream->seg_list != NULL && /*2*/
- SEQ_GT(stream->seg_list->seq, stream->ra_app_base_seq+1) &&
- SEQ_LT(stream->seg_list->seq, stream->last_ack)))
- {
- if (stream->seg_list == NULL) {
- SCLogDebug("no segs, last_ack moved fwd so GAP "
- "(base %u, isn %u, last_ack %u => diff %u) p %"PRIu64,
- stream->ra_app_base_seq, stream->isn, stream->last_ack,
- stream->last_ack - (stream->isn + ackadd), p->pcap_cnt);
- }
-
- /* send gap signal */
- AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
- NULL, 0,
- StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP);
- AppLayerProfilingStore(ra_ctx->app_tctx, p);
-
- /* set a GAP flag and make sure not bothering this stream anymore */
- SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set");
- stream->flags |= STREAMTCP_STREAM_FLAG_GAP;
-
- StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP);
- StatsIncr(tv, ra_ctx->counter_tcp_reass_gap);
-#ifdef DEBUG
- dbg_app_layer_gap++;
-#endif
- SCReturnInt(0);
- }
- }
-
- /* 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;
- if (seg_tail == NULL ||
- (seg_tail->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED))
- {
- /* send an empty EOF msg if we have no segments but TCP state
- * is beyond ESTABLISHED */
- if (ssn->state >= TCP_CLOSING || (p->flags & PKT_PSEUDO_STREAM_END)) {
- SCLogDebug("sending empty eof message");
- /* send EOF to app layer */
- AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
- NULL, 0,
- StreamGetAppLayerFlags(ssn, stream, p));
- AppLayerProfilingStore(ra_ctx->app_tctx, p);
-
- SCReturnInt(0);
- }
- }
-
- /* no segments, nothing to do */
- if (stream->seg_list == NULL) {
- SCLogDebug("no segments in the list to reassemble");
- SCReturnInt(0);
- }
-
-
- if (stream->flags & STREAMTCP_STREAM_FLAG_GAP) {
- SCReturnInt(0);
- }
-
- /* stream->ra_app_base_seq remains at stream->isn until protocol is
- * detected. */
- ReassembleData rd;
- rd.ra_base_seq = stream->ra_app_base_seq;
- rd.data_len = 0;
- rd.data_sent = 0;
- rd.partial = FALSE;
- uint32_t next_seq = rd.ra_base_seq + 1;
-
- SCLogDebug("ra_base_seq %"PRIu32", last_ack %"PRIu32", next_seq %"PRIu32,
- rd.ra_base_seq, stream->last_ack, next_seq);
-
- /* loop through the segments and fill one or more msgs */
- TcpSegment *seg = stream->seg_list;
- SCLogDebug("pre-loop seg %p", seg);
-#ifdef DEBUG_VALIDATION
- uint64_t bytes = 0;
-#endif
- for (; seg != NULL; )
- {
-#ifdef DEBUG_VALIDATION
- bytes += seg->payload_len;
-#endif
- /* if in inline mode, we process all segments regardless of whether
- * they are ack'd or not. In non-inline, we process only those that
- * are at least partly ack'd. */
- if (StreamTcpInlineMode() == 0 && SEQ_GEQ(seg->seq, stream->last_ack))
- break;
-
- SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32,
- seg, seg->seq, seg->payload_len,
- (uint32_t)(seg->seq + seg->payload_len));
-
- if (StreamTcpReturnSegmentCheck(p->flow, ssn, stream, seg) == 1) {
- SCLogDebug("removing segment");
- TcpSegment *next_seg = seg->next;
- StreamTcpRemoveSegmentFromStream(stream, seg);
- StreamTcpSegmentReturntoPool(seg);
- seg = next_seg;
- continue;
- } else if (StreamTcpAppLayerSegmentProcessed(ssn, stream, seg)) {
- TcpSegment *next_seg = seg->next;
- seg = next_seg;
- continue;
- }
-
- /* check if we have a sequence gap and if so, handle it */
- if (DoHandleGap(tv, ra_ctx, ssn, stream, seg, &rd, p, next_seq) == 1)
- break;
-
- /* process this segment */
- if (DoReassemble(tv, ra_ctx, ssn, stream, seg, &rd, p) == 0)
- break;
-
- /* done with this segment, return it to the pool */
- TcpSegment *next_seg = seg->next;
- next_seq = seg->seq + seg->payload_len;
- if (rd.partial == FALSE) {
- SCLogDebug("fully done with segment in app layer reassembly (seg %p seq %"PRIu32")",
- seg, seg->seq);
- seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED;
- SCLogDebug("flags now %02x", seg->flags);
- } else {
- SCLogDebug("not yet fully done with segment in app layer reassembly");
- }
- seg = next_seg;
- }
-#ifdef DEBUG_VALIDATION /* we should never have this much data queued */
- BUG_ON(bytes > 1000000ULL && bytes > (stream->window * 1.5));
-#endif
-
- /* put the partly filled smsg in the queue to the l7 handler */
- if (rd.data_len > 0) {
- SCLogDebug("data_len > 0, %u", rd.data_len);
- /* process what we have so far */
- BUG_ON(rd.data_len > sizeof(rd.data));
- AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
- rd.data, rd.data_len,
- StreamGetAppLayerFlags(ssn, stream, p));
- AppLayerProfilingStore(ra_ctx->app_tctx, p);
- }
-
- /* if no data was sent to the applayer, we send it a empty 'nudge'
- * when in inline mode */
- if (StreamTcpInlineMode() && rd.data_sent == 0 && ssn->state > TCP_ESTABLISHED) {
- SCLogDebug("sending empty eof message");
- /* send EOF to app layer */
- AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
- NULL, 0, StreamGetAppLayerFlags(ssn, stream, p));
- AppLayerProfilingStore(ra_ctx->app_tctx, p);
- }
-
- /* store ra_base_seq in the stream */
- if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
- stream->ra_app_base_seq = rd.ra_base_seq;
- } else {
- TcpSegment *tmp_seg = stream->seg_list;
- while (tmp_seg != NULL) {
- if (!(tmp_seg->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED))
- break;
- tmp_seg->flags &= ~SEGMENTTCP_FLAG_APPLAYER_PROCESSED;
- tmp_seg = tmp_seg->next;
- }
- }
- SCLogDebug("stream->ra_app_base_seq %u", stream->ra_app_base_seq);
- SCReturnInt(0);
-}
-
-typedef struct ReassembleRawData_ {
- uint32_t ra_base_seq;
- int partial; /* last segment was processed only partially */
- StreamMsg *smsg;
- uint32_t smsg_offset; // TODO diff with smsg->data_len?
-} ReassembleRawData;
-
-static void DoHandleRawGap(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, Packet *p,
- ReassembleRawData *rd, uint32_t next_seq)
-{
- /* we've run into a sequence gap */
- if (SEQ_GT(seg->seq, next_seq)) {
- /* pass on pre existing smsg (if any) */
- if (rd->smsg != NULL && rd->smsg->data_len > 0) {
- /* if app layer protocol has not been detected till yet,
- then check did we have sent message to app layer already
- or not. If not then sent the message and set flag that first
- message has been sent. No more data till proto has not
- been detected */
- StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0);
- stream->ra_raw_base_seq = rd->ra_base_seq;
- rd->smsg = NULL;
- }
-
- /* see what the length of the gap is, gap length is seg->seq -
- * (ra_base_seq +1) */
-#ifdef DEBUG
- uint32_t gap_len = seg->seq - next_seq;
- SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , "
- "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"",
- next_seq, seg->seq, stream->last_ack, gap_len);
-#endif
- stream->ra_raw_base_seq = rd->ra_base_seq;
-
- /* We have missed the packet and end host has ack'd it, so
- * IDS should advance it's ra_base_seq and should not consider this
- * packet any longer, even if it is retransmitted, as end host will
- * drop it anyway */
- rd->ra_base_seq = seg->seq - 1;
- }
-}
-
-static int DoRawReassemble(TcpSession *ssn, TcpStream *stream, TcpSegment *seg, Packet *p,
- ReassembleRawData *rd)
-{
- uint16_t payload_offset = 0;
- uint16_t payload_len = 0;
-
- /* start clean */
- rd->partial = FALSE;
-
- /* if the segment ends beyond ra_base_seq we need to consider it */
- if (SEQ_GT((seg->seq + seg->payload_len), rd->ra_base_seq+1)) {
- SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", "
- "ra_base_seq %" PRIu32 "", seg->seq,
- seg->payload_len, rd->ra_base_seq);
-
- /* handle segments partly before ra_base_seq */
- if (SEQ_GT(rd->ra_base_seq, seg->seq)) {
- payload_offset = rd->ra_base_seq - seg->seq;
-
- if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) {
-
- if (SEQ_LT(stream->last_ack, rd->ra_base_seq)) {
- return 1;
- } else {
- payload_len = (stream->last_ack - seg->seq) - payload_offset;
- }
- rd->partial = TRUE;
- } else {
- payload_len = seg->payload_len - payload_offset;
- }
-
- if (SCLogDebugEnabled()) {
- BUG_ON(payload_offset > seg->payload_len);
- BUG_ON((payload_len + payload_offset) > seg->payload_len);
- }
- } else {
- payload_offset = 0;
-
- if (SEQ_LT(stream->last_ack, (seg->seq + seg->payload_len))) {
- payload_len = stream->last_ack - seg->seq;
- rd->partial = TRUE;
- } else {
- payload_len = seg->payload_len;
- }
- }
- SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16""
- " and stream->last_ack is %"PRIu32"", payload_offset,
- payload_len, stream->last_ack);
-
- if (payload_len == 0) {
- SCLogDebug("no payload_len, so bail out");
- return 1; // TODO
- }
-
- if (rd->smsg == NULL) {
- rd->smsg = StreamMsgGetFromPool();
- if (rd->smsg == NULL) {
- SCLogDebug("stream_msg_pool is empty");
- return -1;
- }
-
- rd->smsg_offset = 0;
-
- StreamTcpSetupMsg(ssn, stream, p, rd->smsg);
- rd->smsg->seq = rd->ra_base_seq + 1;
- SCLogDebug("smsg->seq %u", rd->smsg->seq);
- }
-
- /* copy the data into the smsg */
- uint32_t copy_size = rd->smsg->data_size - rd->smsg_offset;
- if (copy_size + payload_offset > seg->payload_len) {
- copy_size = seg->payload_len - payload_offset;
- }
- if (copy_size > payload_len) {
- copy_size = payload_len;
- }
- if (SCLogDebugEnabled()) {
- BUG_ON(copy_size > rd->smsg->data_size);
- }
- SCLogDebug("copy_size is %"PRIu16"", copy_size);
- memcpy(rd->smsg->data + rd->smsg_offset, seg->payload + payload_offset,
- copy_size);
- rd->smsg_offset += copy_size;
- rd->ra_base_seq += copy_size;
- SCLogDebug("ra_base_seq %"PRIu32, rd->ra_base_seq);
-
- rd->smsg->data_len += copy_size;
-
- /* queue the smsg if it's full */
- if (rd->smsg->data_len == rd->smsg->data_size) {
- StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0);
- stream->ra_raw_base_seq = rd->ra_base_seq;
- rd->smsg = NULL;
- }
-
- /* if the payload len is bigger than what we copied, we handle the
- * rest of the payload next... */
- if (copy_size < payload_len) {
- SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size,
- payload_len);
-
- payload_offset += copy_size;
- payload_len -= copy_size;
- SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is "
- "%"PRIu16" and stream->last_ack is %"PRIu32"",
- payload_offset, seg->payload_len, stream->last_ack);
- if (SCLogDebugEnabled()) {
- BUG_ON(payload_offset > seg->payload_len);
- }
-
- /* we need a while loop here as the packets theoretically can be
- * 64k */
- char segment_done = FALSE;
- while (segment_done == FALSE) {
- SCLogDebug("new msg at offset %" PRIu32 ", payload_len "
- "%" PRIu32 "", payload_offset, payload_len);
-
- /* get a new message
- XXX we need a setup function */
- rd->smsg = StreamMsgGetFromPool();
- if (rd->smsg == NULL) {
- SCLogDebug("stream_msg_pool is empty");
- SCReturnInt(-1);
- }
- rd->smsg_offset = 0;
-
- StreamTcpSetupMsg(ssn, stream, p, rd->smsg);
- rd->smsg->seq = rd->ra_base_seq + 1;
-
- copy_size = rd->smsg->data_size - rd->smsg_offset;
- if (copy_size > payload_len) {
- copy_size = payload_len;
- }
- if (SCLogDebugEnabled()) {
- BUG_ON(copy_size > rd->smsg->data_size);
- }
-
- SCLogDebug("copy payload_offset %" PRIu32 ", smsg_offset "
- "%" PRIu32 ", copy_size %" PRIu32 "",
- payload_offset, rd->smsg_offset, copy_size);
- memcpy(rd->smsg->data + rd->smsg_offset, seg->payload +
- payload_offset, copy_size);
- rd->smsg_offset += copy_size;
- rd->ra_base_seq += copy_size;
- SCLogDebug("ra_base_seq %"PRIu32, rd->ra_base_seq);
- rd->smsg->data_len += copy_size;
- SCLogDebug("copied payload_offset %" PRIu32 ", "
- "smsg_offset %" PRIu32 ", copy_size %" PRIu32 "",
- payload_offset, rd->smsg_offset, copy_size);
- if (rd->smsg->data_len == rd->smsg->data_size) {
- StreamTcpStoreStreamChunk(ssn, rd->smsg, p, 0);
- stream->ra_raw_base_seq = rd->ra_base_seq;
- rd->smsg = NULL;
- }
-
- /* see if we have segment payload left to process */
- if (copy_size < payload_len) {
- payload_offset += copy_size;
- payload_len -= copy_size;
-
- if (SCLogDebugEnabled()) {
- BUG_ON(payload_offset > seg->payload_len);
- }
- } else {
- payload_offset = 0;
- segment_done = TRUE;
- }
- }
- }
- }
- return 1;
-}
-
-/**
- * \brief Update the stream reassembly upon receiving an ACK packet.
- * \todo this function is too long, we need to break it up. It needs it BAD
- */
-static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx,
- TcpSession *ssn, TcpStream *stream, Packet *p)
-{
- SCEnter();
- SCLogDebug("start p %p", p);
-
- if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW)
- SCReturnInt(0);
-
- if (stream->seg_list == NULL) {
- SCLogDebug("no segments in the list to reassemble");
- SCReturnInt(0);
- }
-
-#if 0
- if (ssn->state <= TCP_ESTABLISHED &&
- !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
- SCLogDebug("only starting raw reassembly after app layer protocol "
- "detection has completed.");
- SCReturnInt(0);
- }
-#endif
- /* check if we have enough data */
- if (StreamTcpReassembleRawCheckLimit(ssn,stream,p) == 0) {
- SCLogDebug("not yet reassembling");
- SCReturnInt(0);
- }
-
- TcpSegment *seg = stream->seg_list;
- ReassembleRawData rd;
- rd.smsg = NULL;
- rd.ra_base_seq = stream->ra_raw_base_seq;
- rd.smsg_offset = 0;
- uint32_t next_seq = rd.ra_base_seq + 1;
-
- SCLogDebug("ra_base_seq %"PRIu32", last_ack %"PRIu32", next_seq %"PRIu32,
- rd.ra_base_seq, stream->last_ack, next_seq);
-
- /* loop through the segments and fill one or more msgs */
- for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);)
- {
- SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32", flags %02x",
- seg, seg->seq, seg->payload_len,
- (uint32_t)(seg->seq + seg->payload_len), seg->flags);
-
- if (StreamTcpReturnSegmentCheck(p->flow, ssn, stream, seg) == 1) {
- SCLogDebug("removing segment");
- TcpSegment *next_seg = seg->next;
- StreamTcpRemoveSegmentFromStream(stream, seg);
- StreamTcpSegmentReturntoPool(seg);
- seg = next_seg;
- continue;
- } else if(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) {
- TcpSegment *next_seg = seg->next;
- seg = next_seg;
- continue;
- }
-
- DoHandleRawGap(ssn, stream, seg, p, &rd, next_seq);
-
- if (DoRawReassemble(ssn, stream, seg, p, &rd) == 0)
- break;
-
- /* done with this segment, return it to the pool */
- TcpSegment *next_seg = seg->next;
- next_seq = seg->seq + seg->payload_len;
- if (rd.partial == FALSE) {
- SCLogDebug("fully done with segment in raw reassembly (seg %p seq %"PRIu32")",
- seg, seg->seq);
- seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED;
- SCLogDebug("flags now %02x", seg->flags);
- } else {
- SCLogDebug("not yet fully done with segment in raw reassembly");
- }
- seg = next_seg;
- }
-
- /* put the partly filled smsg in the queue to the l7 handler */
- if (rd.smsg != NULL) {
- StreamTcpStoreStreamChunk(ssn, rd.smsg, p, 0);
- rd.smsg = NULL;
- stream->ra_raw_base_seq = rd.ra_base_seq;
- }
-
- SCReturnInt(0);
-}
-
-/** \brief update app layer and raw reassembly
- *
- * \retval r 0 on success, -1 on error
- */
-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 (!(StreamTcpInlineMode())) {
- if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p) < 0)
- r = -1;
- if (StreamTcpReassembleRaw(ra_ctx, ssn, stream, p) < 0)
- r = -1;
- }
-
- SCLogDebug("stream->seg_list %p", stream->seg_list);
- SCReturnInt(r);
-}
-
-int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
- TcpSession *ssn, TcpStream *stream,
- Packet *p, PacketQueue *pq)
-{
- SCEnter();
- SCLogDebug("ssn %p, stream %p, p %p, p->payload_len %"PRIu16"",
- ssn, stream, p, p->payload_len);
-
- /* we need to update the opposing stream in
- * StreamTcpReassembleHandleSegmentUpdateACK */
- TcpStream *opposing_stream = NULL;
- if (stream == &ssn->client) {
- opposing_stream = &ssn->server;
- } else {
- opposing_stream = &ssn->client;
- }
-
- /* handle ack received */
- if (StreamTcpReassembleHandleSegmentUpdateACK(tv, ra_ctx, ssn, opposing_stream, p) != 0)
- {
- SCLogDebug("StreamTcpReassembleHandleSegmentUpdateACK error");
- SCReturnInt(-1);
- }
-
- /* If no stream reassembly/application layer protocol inspection, then
- simple return */
- if (p->payload_len > 0 && !(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
- SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData");
-
- if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) {
- SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error");
- SCReturnInt(-1);
- }
-
- p->flags |= PKT_STREAM_ADD;
- }
-
- /* in stream inline mode even if we have no data we call the reassembly
- * functions to handle EOF */
- if (StreamTcpInlineMode()) {
- int r = 0;
- if (StreamTcpReassembleAppLayer(tv, ra_ctx, ssn, stream, p) < 0)
- r = -1;
- if (StreamTcpReassembleInlineRaw(ra_ctx, ssn, stream, p) < 0)
- r = -1;
-
- if (r < 0) {
- SCReturnInt(-1);
- }
- }
-
- SCReturnInt(0);
-}
-
-/**
- * \brief Function to replace the data from a specific point up to given length.
- *
- * \param dst_seg Destination segment to replace the data
- * \param src_seg Source segment of which data is to be written to destination
- * \param start_point Starting point to replace the data onwards
- * \param len Length up to which data is need to be replaced
- *
- * \todo VJ We can remove the abort()s later.
- * \todo VJ Why not memcpy?
- */
-void StreamTcpSegmentDataReplace(TcpSegment *dst_seg, TcpSegment *src_seg,
- uint32_t start_point, uint16_t len)
-{
- uint32_t seq;
- uint16_t src_pos = 0;
- uint16_t dst_pos = 0;
-
- SCLogDebug("start_point %u", start_point);
-
- if (SEQ_GT(start_point, dst_seg->seq)) {
- dst_pos = start_point - dst_seg->seq;
- } else if (SEQ_LT(start_point, dst_seg->seq)) {
- dst_pos = dst_seg->seq - start_point;
- }
-
- if (SCLogDebugEnabled()) {
- BUG_ON(((len + dst_pos) - 1) > dst_seg->payload_len);
- } else {
- if (((len + dst_pos) - 1) > dst_seg->payload_len)
- return;
- }
-
- src_pos = (uint16_t)(start_point - src_seg->seq);
-
- SCLogDebug("Replacing data from dst_pos %"PRIu16"", dst_pos);
-
- for (seq = start_point; SEQ_LT(seq, (start_point + len)) &&
- src_pos < src_seg->payload_len && dst_pos < dst_seg->payload_len;
- seq++, dst_pos++, src_pos++)
- {
- dst_seg->payload[dst_pos] = src_seg->payload[src_pos];
- }
-
- SCLogDebug("Replaced data of size %"PRIu16" up to src_pos %"PRIu16
- " dst_pos %"PRIu16, len, src_pos, dst_pos);
-}
-
-/**
- * \brief Function to compare the data from a specific point up to given length.
- *
- * \param dst_seg Destination segment to compare the data
- * \param src_seg Source segment of which data is to be compared to destination
- * \param start_point Starting point to compare the data onwards
- * \param len Length up to which data is need to be compared
- *
- * \retval 1 same
- * \retval 0 different
- */
-static int StreamTcpSegmentDataCompare(TcpSegment *dst_seg, TcpSegment *src_seg,
- uint32_t start_point, uint16_t len)
-{
- uint32_t seq;
- uint16_t src_pos = 0;
- uint16_t dst_pos = 0;
-
- SCLogDebug("start_point %u dst_seg %u src_seg %u", start_point, dst_seg->seq, src_seg->seq);
-
- if (SEQ_GT(start_point, dst_seg->seq)) {
- SCLogDebug("start_point %u > dst %u", start_point, dst_seg->seq);
- dst_pos = start_point - dst_seg->seq;
- } else if (SEQ_LT(start_point, dst_seg->seq)) {
- SCLogDebug("start_point %u < dst %u", start_point, dst_seg->seq);
- dst_pos = dst_seg->seq - start_point;
- }
-
- if (SCLogDebugEnabled()) {
- BUG_ON(((len + dst_pos) - 1) > dst_seg->payload_len);
- } else {
- if (((len + dst_pos) - 1) > dst_seg->payload_len)
- return 1;
- }
-
- src_pos = (uint16_t)(start_point - src_seg->seq);
-
- SCLogDebug("Comparing data from dst_pos %"PRIu16", src_pos %u", dst_pos, src_pos);
-
- for (seq = start_point; SEQ_LT(seq, (start_point + len)) &&
- src_pos < src_seg->payload_len && dst_pos < dst_seg->payload_len;
- seq++, dst_pos++, src_pos++)
- {
- if (dst_seg->payload[dst_pos] != src_seg->payload[src_pos]) {
- SCLogDebug("data is different %02x != %02x, dst_pos %u, src_pos %u", dst_seg->payload[dst_pos], src_seg->payload[src_pos], dst_pos, src_pos);
- return 0;
- }
- }
-
- SCLogDebug("Compared data of size %"PRIu16" up to src_pos %"PRIu16
- " dst_pos %"PRIu16, len, src_pos, dst_pos);
- return 1;
-}
-
-/**
- * \brief Function to copy the data from src_seg to dst_seg.
- *
- * \param dst_seg Destination segment for copying the contents
- * \param src_seg Source segment to copy its contents
- *
- * \todo VJ wouldn't a memcpy be more appropriate here?
- *
- * \warning Both segments need to be properly initialized.
- */
-
-void StreamTcpSegmentDataCopy(TcpSegment *dst_seg, TcpSegment *src_seg)
-{
- uint32_t u;
- uint16_t dst_pos = 0;
- uint16_t src_pos = 0;
- uint32_t seq;
-
- if (SEQ_GT(dst_seg->seq, src_seg->seq)) {
- src_pos = dst_seg->seq - src_seg->seq;
- seq = dst_seg->seq;
- } else {
- dst_pos = src_seg->seq - dst_seg->seq;
- seq = src_seg->seq;
- }
-
- SCLogDebug("Copying data from seq %"PRIu32"", seq);
- for (u = seq;
- (SEQ_LT(u, (src_seg->seq + src_seg->payload_len)) &&
- SEQ_LT(u, (dst_seg->seq + dst_seg->payload_len))); u++)
- {
- //SCLogDebug("u %"PRIu32, u);
-
- dst_seg->payload[dst_pos] = src_seg->payload[src_pos];
-
- dst_pos++;
- src_pos++;
- }
- SCLogDebug("Copyied data of size %"PRIu16" up to dst_pos %"PRIu16"",
- src_pos, dst_pos);
-}
-
-/**
- * \brief Function to get the segment of required length from the pool.
- *
- * \param len Length which tells the required size of needed segment.
- *
- * \retval seg Segment from the pool or NULL
- */
-TcpSegment* StreamTcpGetSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, uint16_t len)
-{
- uint16_t idx = segment_pool_idx[len];
- SCLogDebug("segment_pool_idx %" PRIu32 " for payload_len %" PRIu32 "",
- idx, len);
-
- SCMutexLock(&segment_pool_mutex[idx]);
- TcpSegment *seg = (TcpSegment *) PoolGet(segment_pool[idx]);
-
- SCLogDebug("segment_pool[%u]->empty_stack_size %u, segment_pool[%u]->alloc_"
- "list_size %u, alloc %u", idx, segment_pool[idx]->empty_stack_size,
- idx, segment_pool[idx]->alloc_stack_size,
- segment_pool[idx]->allocated);
- SCMutexUnlock(&segment_pool_mutex[idx]);
-
- SCLogDebug("seg we return is %p", seg);
- if (seg == NULL) {
- SCLogDebug("segment_pool[%u]->empty_stack_size %u, "
- "alloc %u", idx, segment_pool[idx]->empty_stack_size,
- segment_pool[idx]->allocated);
- /* Increment the counter to show that we are not able to serve the
- segment request due to memcap limit */
- StatsIncr(tv, ra_ctx->counter_tcp_segment_memcap);
- } else {
- seg->flags = stream_config.segment_init_flags;
- seg->next = NULL;
- seg->prev = NULL;
- }
-
-#ifdef DEBUG
- SCMutexLock(&segment_pool_cnt_mutex);
- segment_pool_cnt++;
- SCMutexUnlock(&segment_pool_cnt_mutex);
-#endif
-
- return seg;
-}
-
-/**
- * \brief Trigger RAW stream reassembly
- *
- * Used by AppLayerTriggerRawStreamReassembly to trigger RAW stream
- * reassembly from the applayer, for example upon completion of a
- * HTTP request.
- *
- * Works by setting a flag in the TcpSession that is unset as soon
- * as it's checked. Since everything happens when operating under
- * a single lock period, no side effects are expected.
- *
- * \param ssn TcpSession
- */
-void StreamTcpReassembleTriggerRawReassembly(TcpSession *ssn)
-{
-#ifdef DEBUG
- BUG_ON(ssn == NULL);
-#endif
-
- if (ssn != NULL) {
- SCLogDebug("flagged ssn %p for immediate raw reassembly", ssn);
- ssn->flags |= STREAMTCP_FLAG_TRIGGER_RAW_REASSEMBLY;
- }
-}
-
-#ifdef UNITTESTS
-/** unit tests and it's support functions below */
-
-static int UtTestSmsg(StreamMsg *smsg, const uint8_t *buf, uint32_t buf_len)
-{
- if (smsg == NULL)
- return 0;
-
- if (smsg->data_len != buf_len) {
- return 0;
- }
-
- if (!(memcmp(buf, smsg->data, buf_len) == 0)) {
- printf("data is not what we expected:\nExpected:\n");
- PrintRawDataFp(stdout, (uint8_t *)buf, buf_len);
- printf("Got:\n");
- PrintRawDataFp(stdout, smsg->data, smsg->data_len);
- return 0;
- }
- return 1;
-}
-
-static uint32_t UtSsnSmsgCnt(TcpSession *ssn, uint8_t direction)
-{
- uint32_t cnt = 0;
- StreamMsg *smsg = (direction == STREAM_TOSERVER) ?
- ssn->toserver_smsg_head :
- ssn->toclient_smsg_head;
- while (smsg) {
- cnt++;
- smsg = smsg->next;
- }
- return cnt;
-}
-
-/** \brief The Function tests the reassembly engine working for different
- * OSes supported. It includes all the OS cases and send
- * crafted packets to test the reassembly.
- *
- * \param stream The stream which will contain the reassembled segments
- */
-
-static int StreamTcpReassembleStreamTest(TcpStream *stream)
-{
-
- TcpSession ssn;
- Packet *p = PacketGetFromAlloc();
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- uint8_t payload[4];
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- memset(&ssn, 0, sizeof (TcpSession));
- memset(&f, 0, sizeof (Flow));
- memset(&tcph, 0, sizeof (TCPHdr));
- ThreadVars tv;
- memset(&tv, 0, sizeof (ThreadVars));
- FLOW_INITIALIZE(&f);
- f.protoctx = &ssn;
- f.proto = IPPROTO_TCP;
- p->src.family = AF_INET;
- p->dst.family = AF_INET;
- p->proto = IPPROTO_TCP;
- p->flow = &f;
- tcph.th_win = 5480;
- tcph.th_flags = TH_PUSH | TH_ACK;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p->tcph->th_seq = htonl(12);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 3;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/
- p->tcph->th_seq = htonl(16);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 2;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x43, 3, 4); /*CCC*/
- p->tcph->th_seq = htonl(18);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 3;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x44, 1, 4); /*D*/
- p->tcph->th_seq = htonl(22);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 1;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x45, 2, 4); /*EE*/
- p->tcph->th_seq = htonl(25);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 2;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x46, 3, 4); /*FFF*/
- p->tcph->th_seq = htonl(27);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 3;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x47, 2, 4); /*GG*/
- p->tcph->th_seq = htonl(30);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 2;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x48, 2, 4); /*HH*/
- p->tcph->th_seq = htonl(32);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 2;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x49, 1, 4); /*I*/
- p->tcph->th_seq = htonl(34);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 1;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x4a, 4, 4); /*JJJJ*/
- p->tcph->th_seq = htonl(13);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 4;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x4b, 3, 4); /*KKK*/
- p->tcph->th_seq = htonl(18);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 3;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x4c, 3, 4); /*LLL*/
- p->tcph->th_seq = htonl(21);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 3;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x4d, 3, 4); /*MMM*/
- p->tcph->th_seq = htonl(24);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 3;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x4e, 1, 4); /*N*/
- p->tcph->th_seq = htonl(28);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 1;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x4f, 1, 4); /*O*/
- p->tcph->th_seq = htonl(31);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 1;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x50, 1, 4); /*P*/
- p->tcph->th_seq = htonl(32);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 1;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x51, 2, 4); /*QQ*/
- p->tcph->th_seq = htonl(34);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 2;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x30, 1, 4); /*0*/
- p->tcph->th_seq = htonl(11);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 1;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpReassembleFreeThreadCtx(ra_ctx);
-
- SCFree(p);
- return 1;
-}
-
-/** \brief The Function to create the packet with given payload, which is used
- * to test the reassembly of the engine.
- *
- * \param payload The variable used to store the payload contents of the
- * current packet.
- * \param value The value which current payload will have for this packet
- * \param payload_len The length of the filed payload for current packet.
- * \param len Length of the payload array
- */
-
-void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value,
- uint8_t payload_len, uint8_t len)
-{
- uint8_t i;
- for (i = 0; i < payload_len; i++)
- payload[i] = value;
- for (; i < len; i++)
- payload = NULL;
-}
-
-/** \brief The Function Checks the reassembled stream contents against predefined
- * stream contents according to OS policy used.
- *
- * \param stream_policy Predefined value of stream for different OS policies
- * \param stream Reassembled stream returned from the reassembly functions
- */
-
-int StreamTcpCheckStreamContents(uint8_t *stream_policy, uint16_t sp_size, TcpStream *stream)
-{
- TcpSegment *temp;
- uint16_t i = 0;
- uint8_t j;
-
-#ifdef DEBUG
- if (SCLogDebugEnabled()) {
- TcpSegment *temp1;
- for (temp1 = stream->seg_list; temp1 != NULL; temp1 = temp1->next)
- PrintRawDataFp(stdout, temp1->payload, temp1->payload_len);
-
- PrintRawDataFp(stdout, stream_policy, sp_size);
- }
-#endif
-
- for (temp = stream->seg_list; temp != NULL; temp = temp->next) {
- j = 0;
- for (; j < temp->payload_len; j++) {
- SCLogDebug("i %"PRIu16", len %"PRIu32", stream %"PRIx32" and temp is %"PRIx8"",
- i, temp->payload_len, stream_policy[i], temp->payload[j]);
-
- if (stream_policy[i] == temp->payload[j]) {
- i++;
- continue;
- } else
- return 0;
- }
- }
- return 1;
-}
-
-/** \brief The Function Checks the Stream Queue contents against predefined
- * stream contents.
- *
- * \param stream_contents Predefined value of stream contents
- * \param stream Queue which has the stream contents
- *
- * \retval On success the function returns 1, on failure 0.
- */
-static int StreamTcpCheckChunks (TcpSession *ssn, uint8_t *stream_contents)
-{
- SCEnter();
-
- StreamMsg *msg;
- uint16_t i = 0;
- uint8_t j;
- uint8_t cnt = 0;
-
- if (ssn == NULL) {
- printf("ssn == NULL, ");
- SCReturnInt(0);
- }
-
- if (ssn->toserver_smsg_head == NULL) {
- printf("ssn->toserver_smsg_head == NULL, ");
- SCReturnInt(0);
- }
-
- msg = ssn->toserver_smsg_head;
- while(msg != NULL) {
- cnt++;
- j = 0;
- for (; j < msg->data_len; j++) {
- SCLogDebug("i is %" PRIu32 " and len is %" PRIu32 " and temp is %" PRIx32 "", i, msg->data_len, msg->data[j]);
-
- if (stream_contents[i] == msg->data[j]) {
- i++;
- continue;
- } else {
- SCReturnInt(0);
- }
- }
- msg = msg->next;
- }
- SCReturnInt(1);
-}
-
-/* \brief The function craft packets to test the overlapping, where
- * new segment stats before the list segment.
- *
- * \param stream The stream which will contain the reassembled segments and
- * also tells the OS policy used for reassembling the segments.
- */
-
-static int StreamTcpTestStartsBeforeListSegment(TcpStream *stream) {
- TcpSession ssn;
- Packet *p = PacketGetFromAlloc();
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- uint8_t payload[4];
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- memset(&ssn, 0, sizeof (TcpSession));
- memset(&f, 0, sizeof (Flow));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- ThreadVars tv;
- memset(&tv, 0, sizeof (ThreadVars));
- FLOW_INITIALIZE(&f);
- f.protoctx = &ssn;
- f.proto = IPPROTO_TCP;
- p->src.family = AF_INET;
- p->dst.family = AF_INET;
- p->proto = IPPROTO_TCP;
- p->flow = &f;
- tcph.th_win = 5480;
- tcph.th_flags = TH_PUSH | TH_ACK;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x42, 1, 4); /*B*/
- p->tcph->th_seq = htonl(16);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 1;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x44, 1, 4); /*D*/
- p->tcph->th_seq = htonl(22);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 1;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x45, 2, 4); /*EE*/
- p->tcph->th_seq = htonl(25);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 2;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/
- p->tcph->th_seq = htonl(15);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 2;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x4a, 4, 4); /*JJJJ*/
- p->tcph->th_seq = htonl(14);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 4;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- SCLogDebug("sending segment with SEQ 21, len 3");
- StreamTcpCreateTestPacket(payload, 0x4c, 3, 4); /*LLL*/
- p->tcph->th_seq = htonl(21);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 3;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x4d, 3, 4); /*MMM*/
- p->tcph->th_seq = htonl(24);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 3;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- SCFree(p);
- return 1;
-}
-
-/* \brief The function craft packets to test the overlapping, where
- * new segment stats at the same seq no. as the list segment.
- *
- * \param stream The stream which will contain the reassembled segments and
- * also tells the OS policy used for reassembling the segments.
- */
-
-static int StreamTcpTestStartsAtSameListSegment(TcpStream *stream)
-{
- TcpSession ssn;
- Packet *p = PacketGetFromAlloc();
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- uint8_t payload[4];
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- memset(&ssn, 0, sizeof (TcpSession));
- memset(&f, 0, sizeof (Flow));
- memset(&tcph, 0, sizeof (TCPHdr));
- ThreadVars tv;
- memset(&tv, 0, sizeof (ThreadVars));
- FLOW_INITIALIZE(&f);
- f.protoctx = &ssn;
- f.proto = IPPROTO_TCP;
- p->src.family = AF_INET;
- p->dst.family = AF_INET;
- p->proto = IPPROTO_TCP;
- p->flow = &f;
- tcph.th_win = 5480;
- tcph.th_flags = TH_PUSH | TH_ACK;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x43, 3, 4); /*CCC*/
- p->tcph->th_seq = htonl(18);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 3;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x48, 2, 4); /*HH*/
- p->tcph->th_seq = htonl(32);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 2;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x49, 1, 4); /*I*/
- p->tcph->th_seq = htonl(34);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 1;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x4b, 3, 4); /*KKK*/
- p->tcph->th_seq = htonl(18);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 3;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x4c, 4, 4); /*LLLL*/
- p->tcph->th_seq = htonl(18);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 4;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x50, 1, 4); /*P*/
- p->tcph->th_seq = htonl(32);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 1;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x51, 2, 4); /*QQ*/
- p->tcph->th_seq = htonl(34);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 2;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- SCFree(p);
- return 1;
-}
-
-/* \brief The function craft packets to test the overlapping, where
- * new segment stats after the list segment.
- *
- * \param stream The stream which will contain the reassembled segments and
- * also tells the OS policy used for reassembling the segments.
- */
-
-
-static int StreamTcpTestStartsAfterListSegment(TcpStream *stream)
-{
- TcpSession ssn;
- Packet *p = PacketGetFromAlloc();
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- uint8_t payload[4];
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- memset(&ssn, 0, sizeof (TcpSession));
- memset(&f, 0, sizeof (Flow));
- memset(&tcph, 0, sizeof (TCPHdr));
- ThreadVars tv;
- memset(&tv, 0, sizeof (ThreadVars));
- FLOW_INITIALIZE(&f);
- f.protoctx = &ssn;
- f.proto = IPPROTO_TCP;
- p->src.family = AF_INET;
- p->dst.family = AF_INET;
- p->proto = IPPROTO_TCP;
- p->flow = &f;
- tcph.th_win = 5480;
- tcph.th_flags = TH_PUSH | TH_ACK;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/
- p->tcph->th_seq = htonl(12);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 2;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x46, 3, 4); /*FFF*/
- p->tcph->th_seq = htonl(27);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 3;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x47, 2, 4); /*GG*/
- p->tcph->th_seq = htonl(30);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 2;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x4a, 2, 4); /*JJ*/
- p->tcph->th_seq = htonl(13);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 2;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x4f, 1, 4); /*O*/
- p->tcph->th_seq = htonl(31);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 1;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- StreamTcpCreateTestPacket(payload, 0x4e, 1, 4); /*N*/
- p->tcph->th_seq = htonl(28);
- p->tcph->th_ack = htonl(31);
- p->payload = payload;
- p->payload_len = 1;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
-
- SCFree(p);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * before the list segment and BSD policy is used to reassemble
- * segments.
- */
-
-static int StreamTcpReassembleTest01(void)
-{
- TcpStream stream;
- uint8_t stream_before_bsd[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c,
- 0x4c, 0x4d, 0x4d, 0x4d};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_BSD;
-
- StreamTcpInitConfig(TRUE);
-
- if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_before_bsd,sizeof(stream_before_bsd), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
-
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * at the same seq no. as the list segment and BSD policy is used
- * to reassemble segments.
- */
-
-static int StreamTcpReassembleTest02(void)
-{
- TcpStream stream;
- uint8_t stream_same_bsd[8] = {0x43, 0x43, 0x43, 0x4c, 0x48, 0x48,
- 0x49, 0x51};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_BSD;
-
- StreamTcpInitConfig(TRUE);
-
- if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_same_bsd, sizeof(stream_same_bsd), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * after the list segment and BSD policy is used to reassemble
- * segments.
- */
-
-static int StreamTcpReassembleTest03(void)
-{
- TcpStream stream;
- uint8_t stream_after_bsd[8] = {0x41, 0x41, 0x4a, 0x46, 0x46, 0x46,
- 0x47, 0x47};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_BSD;
-
- StreamTcpInitConfig(TRUE);
-
- if (StreamTcpTestStartsAfterListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_after_bsd, sizeof(stream_after_bsd), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly engine for all the case
- * before, same and after overlapping and BSD policy is used to
- * reassemble segments.
- */
-
-static int StreamTcpReassembleTest04(void)
-{
- TcpStream stream;
- uint8_t stream_bsd[25] = {0x30, 0x41, 0x41, 0x41, 0x4a, 0x4a, 0x42, 0x43,
- 0x43, 0x43, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d,
- 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x49, 0x51};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_BSD;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpReassembleStreamTest(&stream) == 0) {
- printf("failed in segments reassembly: ");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_bsd, sizeof(stream_bsd), &stream) == 0) {
- printf("failed in stream matching: ");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * before the list segment and VISTA policy is used to reassemble
- * segments.
- */
-
-static int StreamTcpReassembleTest05(void)
-{
- TcpStream stream;
- uint8_t stream_before_vista[10] = {0x4a, 0x41, 0x42, 0x4a, 0x4c, 0x44,
- 0x4c, 0x4d, 0x45, 0x45};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_VISTA;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_before_vista, sizeof(stream_before_vista), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * at the same seq no. as the list segment and VISTA policy is used
- * to reassemble segments.
- */
-
-static int StreamTcpReassembleTest06(void)
-{
- TcpStream stream;
- uint8_t stream_same_vista[8] = {0x43, 0x43, 0x43, 0x4c, 0x48, 0x48,
- 0x49, 0x51};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_VISTA;
-
- StreamTcpInitConfig(TRUE);
-
- if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_same_vista, sizeof(stream_same_vista), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * after the list segment and BSD policy is used to reassemble
- * segments.
- */
-
-static int StreamTcpReassembleTest07(void)
-{
- TcpStream stream;
- uint8_t stream_after_vista[8] = {0x41, 0x41, 0x4a, 0x46, 0x46, 0x46,
- 0x47, 0x47};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_VISTA;
-
- StreamTcpInitConfig(TRUE);
-
- if (StreamTcpTestStartsAfterListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_after_vista, sizeof(stream_after_vista), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly engine for all the case
- * before, same and after overlapping and VISTA policy is used to
- * reassemble segments.
- */
-
-static int StreamTcpReassembleTest08(void)
-{
- TcpStream stream;
- uint8_t stream_vista[25] = {0x30, 0x41, 0x41, 0x41, 0x4a, 0x42, 0x42, 0x43,
- 0x43, 0x43, 0x4c, 0x44, 0x4c, 0x4d, 0x45, 0x45,
- 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x49, 0x51};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_VISTA;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpReassembleStreamTest(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_vista, sizeof(stream_vista), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * before the list segment and LINUX policy is used to reassemble
- * segments.
- */
-
-static int StreamTcpReassembleTest09(void)
-{
- TcpStream stream;
- uint8_t stream_before_linux[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c,
- 0x4c, 0x4d, 0x4d, 0x4d};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_LINUX;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_before_linux, sizeof(stream_before_linux), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * at the same seq no. as the list segment and LINUX policy is used
- * to reassemble segments.
- */
-
-static int StreamTcpReassembleTest10(void)
-{
- TcpStream stream;
- uint8_t stream_same_linux[8] = {0x4c, 0x4c, 0x4c, 0x4c, 0x48, 0x48,
- 0x51, 0x51};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_LINUX;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_same_linux, sizeof(stream_same_linux), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * after the list segment and LINUX policy is used to reassemble
- * segments.
- */
-
-static int StreamTcpReassembleTest11(void)
-{
- TcpStream stream;
- uint8_t stream_after_linux[8] = {0x41, 0x41, 0x4a, 0x46, 0x46, 0x46,
- 0x47, 0x47};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_LINUX;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpTestStartsAfterListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_after_linux, sizeof(stream_after_linux), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly engine for all the case
- * before, same and after overlapping and LINUX policy is used to
- * reassemble segments.
- */
-
-static int StreamTcpReassembleTest12(void)
-{
- TcpStream stream;
- uint8_t stream_linux[25] = {0x30, 0x41, 0x41, 0x41, 0x4a, 0x4a, 0x42, 0x43,
- 0x43, 0x43, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d,
- 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x51, 0x51};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_LINUX;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpReassembleStreamTest(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_linux, sizeof(stream_linux), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * before the list segment and OLD_LINUX policy is used to reassemble
- * segments.
- */
-
-static int StreamTcpReassembleTest13(void)
-{
- TcpStream stream;
- uint8_t stream_before_old_linux[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c,
- 0x4c, 0x4d, 0x4d, 0x4d};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_OLD_LINUX;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_before_old_linux, sizeof(stream_before_old_linux), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * at the same seq no. as the list segment and OLD_LINUX policy is
- * used to reassemble segments.
- */
-
-static int StreamTcpReassembleTest14(void)
-{
- TcpStream stream;
- uint8_t stream_same_old_linux[8] = {0x4c, 0x4c, 0x4c, 0x4c, 0x48, 0x48,
- 0x51, 0x51};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_OLD_LINUX;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_same_old_linux, sizeof(stream_same_old_linux), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * after the list segment and OLD_LINUX policy is used to reassemble
- * segments.
- */
-
-static int StreamTcpReassembleTest15(void)
-{
- TcpStream stream;
- uint8_t stream_after_old_linux[8] = {0x41, 0x41, 0x4a, 0x46, 0x46, 0x46,
- 0x47, 0x47};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_OLD_LINUX;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpTestStartsAfterListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_after_old_linux, sizeof(stream_after_old_linux), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly engine for all the case
- * before, same and after overlapping and OLD_LINUX policy is used to
- * reassemble segments.
- */
-
-static int StreamTcpReassembleTest16(void)
-{
- TcpStream stream;
- uint8_t stream_old_linux[25] = {0x30, 0x41, 0x41, 0x41, 0x4a, 0x4a, 0x42, 0x4b,
- 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d,
- 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x51, 0x51};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_OLD_LINUX;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpReassembleStreamTest(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_old_linux, sizeof(stream_old_linux), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * before the list segment and SOLARIS policy is used to reassemble
- * segments.
- */
-
-static int StreamTcpReassembleTest17(void)
-{
- TcpStream stream;
- uint8_t stream_before_solaris[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c,
- 0x4c, 0x4d, 0x4d, 0x4d};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_SOLARIS;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_before_solaris, sizeof(stream_before_solaris), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * at the same seq no. as the list segment and SOLARIS policy is used
- * to reassemble segments.
- */
-
-static int StreamTcpReassembleTest18(void)
-{
- TcpStream stream;
- uint8_t stream_same_solaris[8] = {0x4c, 0x4c, 0x4c, 0x4c, 0x48, 0x48,
- 0x51, 0x51};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_SOLARIS;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_same_solaris, sizeof(stream_same_solaris), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * after the list segment and SOLARIS policy is used to reassemble
- * segments.
- */
-
-static int StreamTcpReassembleTest19(void)
-{
- TcpStream stream;
- uint8_t stream_after_solaris[8] = {0x41, 0x4a, 0x4a, 0x46, 0x46, 0x46,
- 0x47, 0x47};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_SOLARIS;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpTestStartsAfterListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- StreamTcpFreeConfig(TRUE);
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_after_solaris, sizeof(stream_after_solaris), &stream) == 0) {
- printf("failed in stream matching!!\n");
- StreamTcpFreeConfig(TRUE);
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly engine for all the case
- * before, same and after overlapping and SOLARIS policy is used to
- * reassemble segments.
- */
-
-static int StreamTcpReassembleTest20(void)
-{
- TcpStream stream;
- uint8_t stream_solaris[25] = {0x30, 0x41, 0x4a, 0x4a, 0x4a, 0x42, 0x42, 0x4b,
- 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d,
- 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x51, 0x51};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_SOLARIS;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpReassembleStreamTest(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- StreamTcpFreeConfig(TRUE);
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_solaris, sizeof(stream_solaris), &stream) == 0) {
- printf("failed in stream matching!!\n");
- StreamTcpFreeConfig(TRUE);
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * before the list segment and LAST policy is used to reassemble
- * segments.
- */
-
-static int StreamTcpReassembleTest21(void)
-{
- TcpStream stream;
- uint8_t stream_before_last[10] = {0x4a, 0x4a, 0x4a, 0x4a, 0x4c, 0x4c,
- 0x4c, 0x4d, 0x4d, 0x4d};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_LAST;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpTestStartsBeforeListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_before_last, sizeof(stream_before_last), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * at the same seq no. as the list segment and LAST policy is used
- * to reassemble segments.
- */
-
-static int StreamTcpReassembleTest22(void)
-{
- TcpStream stream;
- uint8_t stream_same_last[8] = {0x4c, 0x4c, 0x4c, 0x4c, 0x50, 0x48,
- 0x51, 0x51};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_LAST;
- StreamTcpInitConfig(TRUE);
- if (StreamTcpTestStartsAtSameListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_same_last, sizeof(stream_same_last), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly when new segment starts
- * after the list segment and LAST policy is used to reassemble
- * segments.
- */
-static int StreamTcpReassembleTest23(void)
-{
- TcpStream stream;
- uint8_t stream_after_last[8] = {0x41, 0x4a, 0x4a, 0x46, 0x4e, 0x46, 0x47, 0x4f};
- memset(&stream, 0, sizeof (TcpStream));
-
- stream.os_policy = OS_POLICY_LAST;
- StreamTcpInitConfig(TRUE);
-
- if (StreamTcpTestStartsAfterListSegment(&stream) == 0) {
- printf("failed in segments reassembly!!\n");
- return 0;
- }
- if (StreamTcpCheckStreamContents(stream_after_last, sizeof(stream_after_last), &stream) == 0) {
- printf("failed in stream matching!!\n");
- return 0;
- }
- StreamTcpFreeConfig(TRUE);
- return 1;
-}
-
-/** \brief The Function to test the reassembly engine for all the case
- * before, same and after overlapping and LAST policy is used to
- * reassemble segments.
- */
-
-static int StreamTcpReassembleTest24(void)
-{
- int ret = 0;
- TcpStream stream;
- uint8_t stream_last[25] = {0x30, 0x41, 0x4a, 0x4a, 0x4a, 0x4a, 0x42, 0x4b,
- 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d,
- 0x46, 0x4e, 0x46, 0x47, 0x4f, 0x50, 0x48, 0x51, 0x51};
- memset(&stream, 0, sizeof (TcpStream));
-
- stream.os_policy = OS_POLICY_LAST;
- StreamTcpInitConfig(TRUE);
-
- if (StreamTcpReassembleStreamTest(&stream) == 0) {
- printf("failed in segments reassembly: ");
- goto end;
- }
- if (StreamTcpCheckStreamContents(stream_last, sizeof(stream_last), &stream) == 0) {
- printf("failed in stream matching: ");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-/** \brief The Function to test the missed packets handling with given payload,
- * which is used to test the reassembly of the engine.
- *
- * \param stream Stream which contain the packets
- * \param seq Sequence number of the packet
- * \param ack Acknowledgment number of the packet
- * \param payload The variable used to store the payload contents of the
- * current packet.
- * \param len The length of the payload for current packet.
- * \param th_flag The TCP flags
- * \param flowflags The packet flow direction
- * \param state The TCP session state
- *
- * \retval On success it returns 0 and on failure it return -1.
- */
-
-static int StreamTcpTestMissedPacket (TcpReassemblyThreadCtx *ra_ctx,
- TcpSession *ssn, uint32_t seq, uint32_t ack, uint8_t *payload,
- uint16_t len, uint8_t th_flags, uint8_t flowflags, uint8_t state)
-{
- Packet *p = PacketGetFromAlloc();
- if (unlikely(p == NULL))
- return -1;
- Flow f;
- TCPHdr tcph;
- Port sp;
- Port dp;
- struct in_addr in;
- ThreadVars tv;
- PacketQueue pq;
-
- memset(&pq,0,sizeof(PacketQueue));
- memset(&f, 0, sizeof (Flow));
- memset(&tcph, 0, sizeof (TCPHdr));
- memset(&tv, 0, sizeof (ThreadVars));
-
- sp = 200;
- dp = 220;
-
- FLOW_INITIALIZE(&f);
- if (inet_pton(AF_INET, "1.2.3.4", &in) != 1) {
- SCFree(p);
- return -1;
- }
- f.src.addr_data32[0] = in.s_addr;
- if (inet_pton(AF_INET, "1.2.3.5", &in) != 1) {
- SCFree(p);
- return -1;
- }
- f.dst.addr_data32[0] = in.s_addr;
- f.flags |= FLOW_IPV4;
- f.sp = sp;
- f.dp = dp;
- f.protoctx = ssn;
- f.proto = IPPROTO_TCP;
- p->flow = &f;
-
- tcph.th_win = htons(5480);
- tcph.th_seq = htonl(seq);
- tcph.th_ack = htonl(ack);
- tcph.th_flags = th_flags;
- p->tcph = &tcph;
- p->flowflags = flowflags;
-
- p->payload = payload;
- p->payload_len = len;
- ssn->state = state;
-
- TcpStream *s = NULL;
- if (flowflags & FLOW_PKT_TOSERVER) {
- s = &ssn->server;
- } else {
- s = &ssn->client;
- }
-
- FLOWLOCK_WRLOCK(&f);
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, ssn, s, p, &pq) == -1) {
- FLOWLOCK_UNLOCK(&f);
- SCFree(p);
- return -1;
- }
-
- FLOWLOCK_UNLOCK(&f);
- SCFree(p);
- return 0;
-}
-
-/**
- * \test Test the handling of packets missed by both IDS and the end host.
- * The packet is missed in the starting of the stream.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest25 (void)
-{
- int ret = 0;
- uint8_t payload[4];
- uint32_t seq;
- uint32_t ack;
- TcpSession ssn;
- uint8_t th_flag;
- uint8_t flowflags;
- uint8_t check_contents[7] = {0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43};
-
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- memset(&ssn, 0, sizeof (TcpSession));
-
- flowflags = FLOW_PKT_TOSERVER;
- th_flag = TH_ACK|TH_PUSH;
- ack = 20;
- StreamTcpInitConfig(TRUE);
-
- StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/
- seq = 10;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
- printf("failed in segments reassembly: ");
- goto end;
- }
-
- StreamTcpCreateTestPacket(payload, 0x43, 2, 4); /*CC*/
- seq = 12;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
- printf("failed in segments reassembly: ");
- goto end;
- }
- ssn.server.next_seq = 14;
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- seq = 7;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
- printf("failed in segments reassembly: ");
- goto end;
- }
-
- if (StreamTcpCheckStreamContents(check_contents, sizeof(check_contents), &ssn.server) == 0) {
- printf("failed in stream matching: ");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpReassembleFreeThreadCtx(ra_ctx);
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-/**
- * \test Test the handling of packets missed by both IDS and the end host.
- * The packet is missed in the middle of the stream.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest26 (void)
-{
- int ret = 0;
- uint8_t payload[4];
- uint32_t seq;
- uint32_t ack;
- TcpSession ssn;
- uint8_t th_flag;
- uint8_t flowflags;
- uint8_t check_contents[7] = {0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43};
- memset(&ssn, 0, sizeof (TcpSession));
- flowflags = FLOW_PKT_TOSERVER;
- th_flag = TH_ACK|TH_PUSH;
- ack = 20;
- StreamTcpInitConfig(TRUE);
-
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- seq = 10;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1){
- printf("failed in segments reassembly: ");
- goto end;
- }
-
- StreamTcpCreateTestPacket(payload, 0x43, 2, 4); /*CC*/
- seq = 15;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
- printf("failed in segments reassembly: ");
- goto end;
- }
-
- StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/
- seq = 13;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
- printf("failed in segments reassembly: ");
- goto end;
- }
-
- if (StreamTcpCheckStreamContents(check_contents, sizeof(check_contents), &ssn.server) == 0) {
- printf("failed in stream matching: ");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpReassembleFreeThreadCtx(ra_ctx);
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-/**
- * \test Test the handling of packets missed by both IDS and the end host.
- * The packet is missed in the end of the stream.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest27 (void)
-{
- int ret = 0;
- uint8_t payload[4];
- uint32_t seq;
- uint32_t ack;
- TcpSession ssn;
- uint8_t th_flag;
- uint8_t flowflags;
- uint8_t check_contents[7] = {0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43};
- memset(&ssn, 0, sizeof (TcpSession));
- flowflags = FLOW_PKT_TOSERVER;
- th_flag = TH_ACK|TH_PUSH;
- ack = 20;
- StreamTcpInitConfig(TRUE);
-
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- seq = 10;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1){
- printf("failed in segments reassembly: ");
- goto end;
- }
-
- StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/
- seq = 13;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
- printf("failed in segments reassembly: ");
- goto end;
- }
-
- StreamTcpCreateTestPacket(payload, 0x43, 2, 4); /*CC*/
- seq = 15;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
- printf("failed in segments reassembly: ");
- goto end;
- }
-
- if (StreamTcpCheckStreamContents(check_contents, sizeof(check_contents), &ssn.server) == 0) {
- printf("failed in stream matching: ");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpReassembleFreeThreadCtx(ra_ctx);
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-/**
- * \test Test the handling of packets missed by IDS, but the end host has
- * received it and send the acknowledgment of it. The packet is missed
- * in the starting of the stream.
+#if 0
+/** \brief The Function tests the reassembly engine working for different
+ * OSes supported. It includes all the OS cases and send
+ * crafted packets to test the reassembly.
*
- * \retval On success it returns 1 and on failure 0.
+ * \param stream The stream which will contain the reassembled segments
*/
-static int StreamTcpReassembleTest28 (void)
+static int StreamTcpReassembleStreamTest(TcpStream *stream)
{
- int ret = 0;
- uint8_t payload[4];
- uint32_t seq;
- uint32_t ack;
- uint8_t th_flag;
- uint8_t th_flags;
- uint8_t flowflags;
- uint8_t check_contents[5] = {0x41, 0x41, 0x42, 0x42, 0x42};
+
TcpSession ssn;
- memset(&ssn, 0, sizeof (TcpSession));
+ Packet *p = PacketGetFromAlloc();
+ if (unlikely(p == NULL))
+ return 0;
+ Flow f;
+ uint8_t payload[4];
+ TCPHdr tcph;
TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- StreamTcpInitConfig(TRUE);
+ /* prevent L7 from kicking in */
StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
+ PacketQueue pq;
+ memset(&pq,0,sizeof(PacketQueue));
- flowflags = FLOW_PKT_TOSERVER;
- th_flag = TH_ACK|TH_PUSH;
- th_flags = TH_ACK;
-
- ssn.server.last_ack = 22;
- ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 6;
- ssn.server.isn = 6;
-
- StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/
- seq = 10;
- ack = 20;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
- printf("failed in segments reassembly (1): ");
- goto end;
- }
-
- flowflags = FLOW_PKT_TOCLIENT;
- StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
- seq = 20;
- ack = 12;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_ESTABLISHED) == -1) {
- printf("failed in segments reassembly (2): ");
- goto end;
- }
-
- flowflags = FLOW_PKT_TOSERVER;
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- seq = 12;
- ack = 20;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
- printf("failed in segments reassembly (4): ");
- goto end;
- }
-
- flowflags = FLOW_PKT_TOCLIENT;
- StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
- seq = 20;
- ack = 15;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_TIME_WAIT) == -1) {
- printf("failed in segments reassembly (5): ");
- goto end;
- }
-
- if (StreamTcpCheckChunks(&ssn, check_contents) == 0) {
- printf("failed in stream matching (6): ");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpReassembleFreeThreadCtx(ra_ctx);
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-/**
- * \test Test the handling of packets missed by IDS, but the end host has
- * received it and send the acknowledgment of it. The packet is missed
- * in the middle of the stream.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest29 (void)
-{
- int ret = 0;
- uint8_t payload[4];
- uint32_t seq;
- uint32_t ack;
- uint8_t th_flag;
- uint8_t th_flags;
- uint8_t flowflags;
- uint8_t check_contents[5] = {0x41, 0x41, 0x42, 0x42, 0x42};
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- TcpSession ssn;
- memset(&ssn, 0, sizeof (TcpSession));
-
- flowflags = FLOW_PKT_TOSERVER;
- th_flag = TH_ACK|TH_PUSH;
- th_flags = TH_ACK;
-
- ssn.server.last_ack = 22;
- ssn.server.ra_raw_base_seq = 9;
- ssn.server.isn = 9;
- StreamTcpInitConfig(TRUE);
-
- StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/
- seq = 10;
- ack = 20;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
- printf("failed in segments reassembly: ");
- goto end;
- }
-
- flowflags = FLOW_PKT_TOCLIENT;
- StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
- seq = 20;
- ack = 15;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_ESTABLISHED) == -1){
- printf("failed in segments reassembly: ");
- goto end;
- }
-
- flowflags = FLOW_PKT_TOSERVER;
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- seq = 15;
- ack = 20;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
- printf("failed in segments reassembly: ");
- goto end;
- }
-
- flowflags = FLOW_PKT_TOCLIENT;
- StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
- seq = 20;
- ack = 18;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_TIME_WAIT) == -1) {
- printf("failed in segments reassembly: ");
- goto end;
- }
-
- if (StreamTcpCheckChunks(&ssn, check_contents) == 0) {
- printf("failed in stream matching: ");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpReassembleFreeThreadCtx(ra_ctx);
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-/**
- * \test Test the handling of packets missed by IDS, but the end host has
- * received it and send the acknowledgment of it. The packet is missed
- * at the end of the stream.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest30 (void)
-{
- int ret = 0;
- uint8_t payload[4];
- uint32_t seq;
- uint32_t ack;
- uint8_t th_flag;
- uint8_t th_flags;
- uint8_t flowflags;
- uint8_t check_contents[6] = {0x41, 0x41, 0x42, 0x42, 0x42, 0x00};
- TcpSession ssn;
memset(&ssn, 0, sizeof (TcpSession));
+ memset(&f, 0, sizeof (Flow));
+ memset(&tcph, 0, sizeof (TCPHdr));
+ ThreadVars tv;
+ memset(&tv, 0, sizeof (ThreadVars));
+ FLOW_INITIALIZE(&f);
+ f.protoctx = &ssn;
+ f.proto = IPPROTO_TCP;
+ p->src.family = AF_INET;
+ p->dst.family = AF_INET;
+ p->proto = IPPROTO_TCP;
+ p->flow = &f;
+ tcph.th_win = 5480;
+ tcph.th_flags = TH_PUSH | TH_ACK;
+ p->tcph = &tcph;
+ p->flowflags = FLOW_PKT_TOSERVER;
+ SET_ISN(&ssn.client, 10);
+ SET_ISN(&ssn.server, 10);
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-
- flowflags = FLOW_PKT_TOSERVER;
- th_flag = TH_ACK|TH_PUSH;
- th_flags = TH_ACK;
-
- ssn.client.last_ack = 2;
- ssn.client.isn = 1;
-
- ssn.server.last_ack = 22;
- ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9;
- ssn.server.isn = 9;
-
- StreamTcpInitConfig(TRUE);
- StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/
- seq = 10;
- ack = 20;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
- printf("failed in segments reassembly: ");
- goto end;
+ StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
+ p->tcph->th_seq = htonl(12);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 3;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
- flowflags = FLOW_PKT_TOCLIENT;
- StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
- seq = 20;
- ack = 12;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_ESTABLISHED) == -1){
- printf("failed in segments reassembly: ");
- goto end;
+ StreamTcpCreateTestPacket(payload, 0x42, 2, 4); /*BB*/
+ p->tcph->th_seq = htonl(16);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 2;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
- flowflags = FLOW_PKT_TOSERVER;
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- seq = 12;
- ack = 20;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
- printf("failed in segments reassembly: ");
- goto end;
+ StreamTcpCreateTestPacket(payload, 0x43, 3, 4); /*CCC*/
+ p->tcph->th_seq = htonl(18);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 3;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
- flowflags = FLOW_PKT_TOCLIENT;
- StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
- seq = 20;
- ack = 18;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flags, flowflags, TCP_ESTABLISHED) == -1) {
- printf("failed in segments reassembly: ");
- goto end;
+ StreamTcpCreateTestPacket(payload, 0x44, 1, 4); /*D*/
+ p->tcph->th_seq = htonl(22);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 1;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
- th_flag = TH_FIN|TH_ACK;
- seq = 18;
- ack = 20;
- flowflags = FLOW_PKT_TOSERVER;
- StreamTcpCreateTestPacket(payload, 0x00, 1, 4);
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
- printf("failed in segments reassembly: ");
- goto end;
+ StreamTcpCreateTestPacket(payload, 0x45, 2, 4); /*EE*/
+ p->tcph->th_seq = htonl(25);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 2;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
- flowflags = FLOW_PKT_TOCLIENT;
- StreamTcpCreateTestPacket(payload, 0x00, 0, 4);
- seq = 20;
- ack = 18;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 0, th_flag, flowflags, TCP_TIME_WAIT) == -1) {
- printf("failed in segments reassembly: ");
- goto end;
+ StreamTcpCreateTestPacket(payload, 0x46, 3, 4); /*FFF*/
+ p->tcph->th_seq = htonl(27);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 3;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
- if (StreamTcpCheckChunks(&ssn, check_contents) == 0) {
- printf("failed in stream matching: ");
- goto end;
+ StreamTcpCreateTestPacket(payload, 0x47, 2, 4); /*GG*/
+ p->tcph->th_seq = htonl(30);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 2;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
- ret = 1;
-end:
- StreamTcpReassembleFreeThreadCtx(ra_ctx);
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-/**
- * \test Test to reassemble the packets using the fast track method, as most
- * packets arrives in order.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest31 (void)
-{
- int ret = 0;
- uint8_t payload[4];
- uint32_t seq;
- uint32_t ack;
- uint8_t th_flag;
- uint8_t flowflags;
- uint8_t check_contents[5] = {0x41, 0x41, 0x42, 0x42, 0x42};
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- TcpSession ssn;
- memset(&ssn, 0, sizeof (TcpSession));
-
- flowflags = FLOW_PKT_TOSERVER;
- th_flag = TH_ACK|TH_PUSH;
-
- ssn.server.ra_raw_base_seq = 9;
- ssn.server.isn = 9;
- StreamTcpInitConfig(TRUE);
-
- StreamTcpCreateTestPacket(payload, 0x41, 2, 4); /*AA*/
- seq = 10;
- ack = 20;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){
- printf("failed in segments reassembly: ");
- goto end;
+ StreamTcpCreateTestPacket(payload, 0x48, 2, 4); /*HH*/
+ p->tcph->th_seq = htonl(32);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 2;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
- flowflags = FLOW_PKT_TOSERVER;
- StreamTcpCreateTestPacket(payload, 0x42, 1, 4); /*B*/
- seq = 15;
- ack = 20;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
- printf("failed in segments reassembly: ");
- goto end;
+ StreamTcpCreateTestPacket(payload, 0x49, 1, 4); /*I*/
+ p->tcph->th_seq = htonl(34);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 1;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
- flowflags = FLOW_PKT_TOSERVER;
- StreamTcpCreateTestPacket(payload, 0x42, 1, 4); /*B*/
- seq = 12;
- ack = 20;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
- printf("failed in segments reassembly: ");
- goto end;
+ StreamTcpCreateTestPacket(payload, 0x4a, 4, 4); /*JJJJ*/
+ p->tcph->th_seq = htonl(13);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 4;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
- flowflags = FLOW_PKT_TOSERVER;
- StreamTcpCreateTestPacket(payload, 0x42, 1, 4); /*B*/
- seq = 16;
- ack = 20;
- if (StreamTcpTestMissedPacket (ra_ctx, &ssn, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) {
- printf("failed in segments reassembly: ");
- goto end;
+ StreamTcpCreateTestPacket(payload, 0x4b, 3, 4); /*KKK*/
+ p->tcph->th_seq = htonl(18);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 3;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
- if (StreamTcpCheckStreamContents(check_contents, 5, &ssn.server) == 0) {
- printf("failed in stream matching: ");
- goto end;
+ StreamTcpCreateTestPacket(payload, 0x4c, 3, 4); /*LLL*/
+ p->tcph->th_seq = htonl(21);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 3;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
- if (ssn.server.seg_list_tail->seq != 16) {
- printf("failed in fast track handling: ");
- goto end;
+ StreamTcpCreateTestPacket(payload, 0x4d, 3, 4); /*MMM*/
+ p->tcph->th_seq = htonl(24);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 3;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
- ret = 1;
-end:
- StreamTcpReassembleFreeThreadCtx(ra_ctx);
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-static int StreamTcpReassembleTest32(void)
-{
- TcpSession ssn;
- Packet *p = PacketGetFromAlloc();
- if (unlikely(p == NULL))
+ StreamTcpCreateTestPacket(payload, 0x4e, 1, 4); /*N*/
+ p->tcph->th_seq = htonl(28);
+ p->tcph->th_ack = htonl(31);
+ p->payload = payload;
+ p->payload_len = 1;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
return 0;
- Flow f;
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- TcpStream stream;
- uint8_t ret = 0;
- uint8_t check_contents[35] = {0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
- 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
- 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42,
- 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43,
- 0x43, 0x43, 0x43};
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_BSD;
- uint8_t payload[20] = "";
-
- StreamTcpInitConfig(TRUE);
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset(&ssn, 0, sizeof (TcpSession));
- memset(&f, 0, sizeof (Flow));
- memset(&tcph, 0, sizeof (TCPHdr));
- ThreadVars tv;
- memset(&tv, 0, sizeof (ThreadVars));
- FLOW_INITIALIZE(&f);
- f.protoctx = &ssn;
- f.proto = IPPROTO_TCP;
- p->src.family = AF_INET;
- p->dst.family = AF_INET;
- p->proto = IPPROTO_TCP;
- p->flow = &f;
- tcph.th_win = 5480;
- tcph.th_flags = TH_PUSH | TH_ACK;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
+ }
- p->tcph->th_seq = htonl(10);
+ StreamTcpCreateTestPacket(payload, 0x4f, 1, 4); /*O*/
+ p->tcph->th_seq = htonl(31);
p->tcph->th_ack = htonl(31);
- p->payload_len = 10;
- StreamTcpCreateTestPacket(payload, 0x41, 10, 20); /*AA*/
p->payload = payload;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1)
- goto end;
+ p->payload_len = 1;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
+ }
- p->tcph->th_seq = htonl(20);
+ StreamTcpCreateTestPacket(payload, 0x50, 1, 4); /*P*/
+ p->tcph->th_seq = htonl(32);
p->tcph->th_ack = htonl(31);
- p->payload_len = 10;
- StreamTcpCreateTestPacket(payload, 0x42, 10, 20); /*BB*/
p->payload = payload;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1)
- goto end;
+ p->payload_len = 1;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
+ }
- p->tcph->th_seq = htonl(40);
+ StreamTcpCreateTestPacket(payload, 0x51, 2, 4); /*QQ*/
+ p->tcph->th_seq = htonl(34);
p->tcph->th_ack = htonl(31);
- p->payload_len = 10;
- StreamTcpCreateTestPacket(payload, 0x43, 10, 20); /*CC*/
p->payload = payload;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1)
- goto end;
+ p->payload_len = 2;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
+ }
- p->tcph->th_seq = htonl(5);
+ StreamTcpCreateTestPacket(payload, 0x30, 1, 4); /*0*/
+ p->tcph->th_seq = htonl(11);
p->tcph->th_ack = htonl(31);
- p->payload_len = 20;
- StreamTcpCreateTestPacket(payload, 0x41, 20, 20); /*AA*/
p->payload = payload;
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1)
- goto end;
-
- if (StreamTcpCheckStreamContents(check_contents, 35, &stream) != 0) {
- ret = 1;
- } else {
- printf("failed in stream matching: ");
+ p->payload_len = 1;
+ if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, stream, p, &pq) == -1) {
+ SCFree(p);
+ return 0;
}
+ StreamTcpReassembleFreeThreadCtx(ra_ctx);
-end:
- StreamTcpFreeConfig(TRUE);
SCFree(p);
- return ret;
+ return 1;
}
+#endif
-static int StreamTcpReassembleTest33(void)
+/** \brief The Function to create the packet with given payload, which is used
+ * to test the reassembly of the engine.
+ *
+ * \param payload The variable used to store the payload contents of the
+ * current packet.
+ * \param value The value which current payload will have for this packet
+ * \param payload_len The length of the filed payload for current packet.
+ * \param len Length of the payload array
+ */
+
+void StreamTcpCreateTestPacket(uint8_t *payload, uint8_t value,
+ uint8_t payload_len, uint8_t len)
{
- TcpSession ssn;
- Packet *p = PacketGetFromAlloc();
- if (unlikely(p == NULL))
+ uint8_t i;
+ for (i = 0; i < payload_len; i++)
+ payload[i] = value;
+ for (; i < len; i++)
+ payload = NULL;
+}
+
+/** \brief The Function Checks the reassembled stream contents against predefined
+ * stream contents according to OS policy used.
+ *
+ * \param stream_policy Predefined value of stream for different OS policies
+ * \param stream Reassembled stream returned from the reassembly functions
+ */
+
+int StreamTcpCheckStreamContents(uint8_t *stream_policy, uint16_t sp_size, TcpStream *stream)
+{
+ if (StreamingBufferCompareRawData(stream->sb, stream_policy,(uint32_t)sp_size) == 0)
+ {
+ //PrintRawDataFp(stdout, stream_policy, sp_size);
return 0;
- Flow f;
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- TcpStream stream;
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_BSD;
- uint8_t packet[1460] = "";
+ }
+ return 1;
+}
- StreamTcpInitConfig(TRUE);
+static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len)
+{
+ if (StreamingBufferCompareRawData(stream->sb,
+ data, data_len) == 0)
+ {
+ SCReturnInt(0);
+ }
+ SCLogInfo("OK");
+ PrintRawDataFp(stdout, data, data_len);
+ return 1;
+}
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
+#define MISSED_START(isn) \
+ TcpReassemblyThreadCtx *ra_ctx = NULL; \
+ TcpSession ssn; \
+ ThreadVars tv; \
+ memset(&tv, 0, sizeof(tv)); \
+ \
+ StreamTcpUTInit(&ra_ctx); \
+ \
+ StreamTcpUTSetupSession(&ssn); \
+ StreamTcpUTSetupStream(&ssn.server, (isn)); \
+ StreamTcpUTSetupStream(&ssn.client, (isn)); \
+ \
+ TcpStream *stream = &ssn.client;
+
+#define MISSED_END \
+ PASS
+
+#define MISSED_STEP(seq, seg, seglen, buf, buflen) \
+ StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, (seq), (uint8_t *)(seg), (seglen)); \
+ FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen))));
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset(&ssn, 0, sizeof (TcpSession));
- memset(&f, 0, sizeof (Flow));
- memset(&tcph, 0, sizeof (TCPHdr));
- ThreadVars tv;
- memset(&tv, 0, sizeof (ThreadVars));
- FLOW_INITIALIZE(&f);
- f.protoctx = &ssn;
- f.proto = IPPROTO_TCP;
- p->src.family = AF_INET;
- p->dst.family = AF_INET;
- p->proto = IPPROTO_TCP;
- p->flow = &f;
- tcph.th_win = 5480;
- tcph.th_flags = TH_PUSH | TH_ACK;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
- p->payload = packet;
+/**
+ * \test Test the handling of packets missed by both IDS and the end host.
+ * The packet is missed in the starting of the stream.
+ *
+ * \retval On success it returns 1 and on failure 0.
+ */
- p->tcph->th_seq = htonl(10);
- p->tcph->th_ack = htonl(31);
- p->payload_len = 10;
+static int StreamTcpReassembleTest25 (void)
+{
+ MISSED_START(6);
+ MISSED_STEP(10, "BB", 2, "\0\0\0BB", 5);
+ MISSED_STEP(12, "CC", 2, "\0\0\0BBCC", 7);
+ MISSED_STEP(7, "AAA", 3, "AAABBCC", 7);
+ MISSED_END;
+}
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
+/**
+ * \test Test the handling of packets missed by both IDS and the end host.
+ * The packet is missed in the middle of the stream.
+ *
+ * \retval On success it returns 1 and on failure 0.
+ */
- p->tcph->th_seq = htonl(20);
- p->tcph->th_ack = htonl(31);
- p->payload_len = 10;
+static int StreamTcpReassembleTest26 (void)
+{
+ MISSED_START(9);
+ MISSED_STEP(10, "AAA", 3, "AAA", 3);
+ MISSED_STEP(15, "CC", 2, "AAA\0\0CC", 7);
+ MISSED_STEP(13, "BB", 2, "AAABBCC", 7);
+ MISSED_END;
+}
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
+/**
+ * \test Test the handling of packets missed by both IDS and the end host.
+ * The packet is missed in the end of the stream.
+ *
+ * \retval On success it returns 1 and on failure 0.
+ */
- p->tcph->th_seq = htonl(40);
- p->tcph->th_ack = htonl(31);
- p->payload_len = 10;
+static int StreamTcpReassembleTest27 (void)
+{
+ MISSED_START(9);
+ MISSED_STEP(10, "AAA", 3, "AAA", 3);
+ MISSED_STEP(13, "BB", 2, "AAABB", 5);
+ MISSED_STEP(15, "CC", 2, "AAABBCC", 7);
+ MISSED_END;
+}
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
+/**
+ * \test Test the handling of packets missed by IDS, but the end host has
+ * received it and send the acknowledgment of it. The packet is missed
+ * in the starting of the stream.
+ *
+ * \retval On success it returns 1 and on failure 0.
+ */
- p->tcph->th_seq = htonl(5);
- p->tcph->th_ack = htonl(31);
- p->payload_len = 30;
+static int StreamTcpReassembleTest28 (void)
+{
+ MISSED_START(6);
+ MISSED_STEP(10, "AAA", 3, "\0\0\0AAA", 6);
+ MISSED_STEP(13, "BB", 2, "\0\0\0AAABB", 8);
+ ssn.state = TCP_TIME_WAIT;
+ MISSED_STEP(15, "CC", 2, "\0\0\0AAABBCC", 10);
+ MISSED_END;
+}
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
- SCFree(p);
- return 0;
- }
+/**
+ * \test Test the handling of packets missed by IDS, but the end host has
+ * received it and send the acknowledgment of it. The packet is missed
+ * in the middle of the stream.
+ *
+ * \retval On success it returns 1 and on failure 0.
+ */
- StreamTcpFreeConfig(TRUE);
- SCFree(p);
- return 1;
+static int StreamTcpReassembleTest29 (void)
+{
+ MISSED_START(9);
+ MISSED_STEP(10, "AAA", 3, "AAA", 3);
+ ssn.state = TCP_TIME_WAIT;
+ MISSED_STEP(15, "CC", 2, "AAA\0\0CC", 7);
+ MISSED_END;
}
-static int StreamTcpReassembleTest34(void)
+static int StreamTcpReassembleTest33(void)
{
TcpSession ssn;
Packet *p = PacketGetFromAlloc();
p->flowflags = FLOW_PKT_TOSERVER;
p->payload = packet;
- p->tcph->th_seq = htonl(857961230);
+ p->tcph->th_seq = htonl(10);
p->tcph->th_ack = htonl(31);
- p->payload_len = 304;
+ p->payload_len = 10;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
SCFree(p);
return 0;
}
- p->tcph->th_seq = htonl(857961534);
+ p->tcph->th_seq = htonl(20);
p->tcph->th_ack = htonl(31);
- p->payload_len = 1460;
+ p->payload_len = 10;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
SCFree(p);
return 0;
}
- p->tcph->th_seq = htonl(857963582);
+ p->tcph->th_seq = htonl(40);
p->tcph->th_ack = htonl(31);
- p->payload_len = 1460;
+ p->payload_len = 10;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
SCFree(p);
return 0;
}
- p->tcph->th_seq = htonl(857960946);
+ p->tcph->th_seq = htonl(5);
p->tcph->th_ack = htonl(31);
- p->payload_len = 1460;
+ p->payload_len = 30;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
SCFree(p);
return 1;
}
-/** \test Test the bug 56 condition */
-static int StreamTcpReassembleTest35(void)
+static int StreamTcpReassembleTest34(void)
{
TcpSession ssn;
Packet *p = PacketGetFromAlloc();
StreamTcpInitConfig(TRUE);
/* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 10);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 10);
+ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
+ StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
PacketQueue pq;
memset(&pq,0,sizeof(PacketQueue));
p->tcph = &tcph;
p->flowflags = FLOW_PKT_TOSERVER;
p->payload = packet;
+ SET_ISN(&stream, 857961230);
- p->tcph->th_seq = htonl(2257022155UL);
- p->tcph->th_ack = htonl(1374943142);
- p->payload_len = 142;
- stream.last_ack = 2257022285UL;
- stream.ra_raw_base_seq = 2257022172UL;
- stream.ra_app_base_seq = 2257022172UL;
+ p->tcph->th_seq = htonl(857961230);
+ p->tcph->th_ack = htonl(31);
+ p->payload_len = 304;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
SCFree(p);
return 0;
}
- p->tcph->th_seq = htonl(2257022285UL);
- p->tcph->th_ack = htonl(1374943142);
- p->payload_len = 34;
- stream.last_ack = 2257022285UL;
- stream.ra_raw_base_seq = 2257022172UL;
+ p->tcph->th_seq = htonl(857961534);
+ p->tcph->th_ack = htonl(31);
+ p->payload_len = 1460;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
SCFree(p);
return 0;
}
- StreamTcpFreeConfig(TRUE);
- SCFree(p);
- return 1;
-}
-
-/** \test Test the bug 57 condition */
-static int StreamTcpReassembleTest36(void)
-{
- TcpSession ssn;
- Packet *p = PacketGetFromAlloc();
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- TcpStream stream;
- memset(&stream, 0, sizeof (TcpStream));
- stream.os_policy = OS_POLICY_BSD;
- uint8_t packet[1460] = "";
-
- StreamTcpInitConfig(TRUE);
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 10);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 10);
-
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset(&ssn, 0, sizeof (TcpSession));
- memset(&f, 0, sizeof (Flow));
- memset(&tcph, 0, sizeof (TCPHdr));
- ThreadVars tv;
- memset(&tv, 0, sizeof (ThreadVars));
- FLOW_INITIALIZE(&f);
- f.protoctx = &ssn;
- f.proto = IPPROTO_TCP;
- p->src.family = AF_INET;
- p->dst.family = AF_INET;
- p->proto = IPPROTO_TCP;
- p->flow = &f;
- tcph.th_win = 5480;
- tcph.th_flags = TH_PUSH | TH_ACK;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
- p->payload = packet;
-
- p->tcph->th_seq = htonl(1549588966);
- p->tcph->th_ack = htonl(4162241372UL);
- p->payload_len = 204;
- stream.last_ack = 1549589007;
- stream.ra_raw_base_seq = 1549589101;
+ p->tcph->th_seq = htonl(857963582);
+ p->tcph->th_ack = htonl(31);
+ p->payload_len = 1460;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
SCFree(p);
return 0;
}
- p->tcph->th_seq = htonl(1549589007);
- p->tcph->th_ack = htonl(4162241372UL);
- p->payload_len = 23;
- stream.last_ack = 1549589007;
- stream.ra_raw_base_seq = 1549589101;
+ p->tcph->th_seq = htonl(857960946);
+ p->tcph->th_ack = htonl(31);
+ p->payload_len = 1460;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
SCFree(p);
p->tcph->th_ack = htonl(1729548549UL);
p->payload_len = 1391;
stream.last_ack = 3061091137UL;
- stream.ra_raw_base_seq = 3061091309UL;
- stream.ra_app_base_seq = 3061091309UL;
+ SET_ISN(&stream, 3061091309UL);
/* pre base_seq, so should be rejected */
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) != -1) {
p->tcph->th_ack = htonl(1729548549UL);
p->payload_len = 1391;
stream.last_ack = 3061091137UL;
- stream.ra_raw_base_seq = 3061091309UL;
- stream.ra_app_base_seq = 3061091309UL;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
SCFree(p);
p->tcph->th_ack = htonl(1729548549UL);
p->payload_len = 1391;
stream.last_ack = 3061091137UL;
- stream.ra_raw_base_seq = 3061091309UL;
- stream.ra_app_base_seq = 3061091309UL;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) {
SCFree(p);
* until the app layer protocol has been detected and one smsg from
* toserver side has been sent to app layer.
*
- * Unittest modified by commit -
- *
- * commit bab1636377bb4f1b7b889f4e3fd594795085eaa4
- * Author: Anoop Saldanha <anoopsaldanha@gmail.com>
- * Date: Fri Feb 15 18:58:33 2013 +0530
- *
- * Improved app protocol detection.
- *
* \retval On success it returns 1 and on failure 0.
*/
static int StreamTcpReassembleTest38 (void)
sp = 200;
dp = 220;
- ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9;
- ssn.server.isn = 9;
+ SET_ISN(&ssn.server, 9);
ssn.server.last_ack = 60;
- ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9;
- ssn.client.isn = 9;
+ SET_ISN(&ssn.client, 9);
ssn.client.last_ack = 9;
f.alproto = ALPROTO_UNKNOWN;
p->flowflags = FLOW_PKT_TOCLIENT;
p->payload_len = sizeof(response);
p->payload = response;
+
if (StreamTcpPacket(&tv, p, stt, &pq) == -1)
goto end;
if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) ||
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) {
+ 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;
}
+ StreamTcpPruneSession(&f, STREAM_TOSERVER);
+ StreamTcpPruneSession(&f, STREAM_TOCLIENT);
+
/* request acking a response */
p->tcph->th_ack = htonl(328);
p->tcph->th_seq = htonl(175);
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 ||
+ 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 15\n");
+ ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER
+ ) {
+ printf("failure 16\n");
+ abort();
goto end;
}
uint8_t httpbuf2[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
- ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9;
- ssn.server.isn = 9;
+ SET_ISN(&ssn.server, 9);
ssn.server.last_ack = 10;
- ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9;
+ SET_ISN(&ssn.client, 9);
ssn.client.isn = 9;
- ssn.client.last_ack = 10;
f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
if (f == NULL)
/* check is have the segment in the list and flagged or not */
if (ssn.client.seg_list == NULL ||
- (ssn.client.seg_list->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED))
+ SEGMENT_BEFORE_OFFSET(&ssn.client, ssn.client.seg_list, ssn.client.app_progress))
+// (ssn.client.seg_list->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED))
{
printf("the list is NULL or the processed segment has not been flaged (7): ");
goto end;
"aG9uZT\r\n\r\n";
uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
- ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9;
+ ssn.server.base_seq= 10;
ssn.server.isn = 9;
ssn.server.last_ack = 600;
- ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9;
+ ssn.client.base_seq = 10;
ssn.client.isn = 9;
ssn.client.last_ack = 600;
goto end;
}
- p->flowflags = FLOW_PKT_TOCLIENT;
- p->payload = httpbuf2;
- p->payload_len = httplen2;
- tcph.th_seq = htonl(100);
- tcph.th_ack = htonl(53);
- s = &ssn.server;
-
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
- printf("failed in segments reassembly, while processing toserver packet (11): ");
- goto end;
- }
- /* the flag should be set, as the smsg scanned size has crossed the max.
- signature size for app proto detection */
- if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn.client)) {
- printf("app layer detected flag is not set, it should be (14): ");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpReassembleFreeThreadCtx(ra_ctx);
- StreamTcpFreeConfig(TRUE);
- SCFree(p);
- FLOWLOCK_UNLOCK(f);
- UTHFreeFlow(f);
- return ret;
-}
-
-/** \test Test the memcap incrementing/decrementing and memcap check */
-static int StreamTcpReassembleTest44(void)
-{
- uint8_t ret = 0;
- StreamTcpInitConfig(TRUE);
- uint32_t memuse = SC_ATOMIC_GET(ra_memuse);
-
- StreamTcpReassembleIncrMemuse(500);
- if (SC_ATOMIC_GET(ra_memuse) != (memuse+500)) {
- printf("failed in incrementing the memory");
- goto end;
- }
-
- StreamTcpReassembleDecrMemuse(500);
- if (SC_ATOMIC_GET(ra_memuse) != memuse) {
- printf("failed in decrementing the memory");
- goto end;
- }
-
- if (StreamTcpReassembleCheckMemcap(500) != 1) {
- printf("failed in validating the memcap");
- goto end;
- }
-
- if (StreamTcpReassembleCheckMemcap((memuse + stream_config.reassembly_memcap)) != 0) {
- printf("failed in validating the memcap");
- goto end;
- }
-
- StreamTcpFreeConfig(TRUE);
-
- if (SC_ATOMIC_GET(ra_memuse) != 0) {
- printf("failed in clearing the memory");
- goto end;
- }
-
- ret = 1;
- return ret;
-end:
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-/**
- * \test Test to make sure that reassembly_depth is enforced.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpReassembleTest45 (void)
-{
- int ret = 0;
- Packet *p = PacketGetFromAlloc();
- if (unlikely(p == NULL))
- return 0;
- Flow *f = NULL;
- TCPHdr tcph;
- TcpSession ssn;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset(&tcph, 0, sizeof (TCPHdr));
- memset(&ssn, 0, sizeof(TcpSession));
- ThreadVars tv;
- memset(&tv, 0, sizeof (ThreadVars));
-
- uint8_t httpbuf1[] = "/ HTTP/1.0\r\nUser-Agent: Victor/1.0";
-
- uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
-
- StreamTcpInitConfig(TRUE);
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
-
- STREAMTCP_SET_RA_BASE_SEQ(&ssn.server, 9);
- ssn.server.isn = 9;
- ssn.server.last_ack = 60;
- STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, 9);
- ssn.client.isn = 9;
- ssn.client.last_ack = 9;
-
- f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
- if (f == NULL)
- goto end;
- f->protoctx = &ssn;
- f->proto = IPPROTO_TCP;
- p->flow = f;
-
- tcph.th_win = htons(5480);
- tcph.th_seq = htonl(10);
- tcph.th_ack = htonl(20);
- tcph.th_flags = TH_ACK|TH_PUSH;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- p->payload = httpbuf1;
- p->payload_len = httplen1;
- ssn.state = TCP_ESTABLISHED;
-
- /* set the default value of reassembly depth, as there is no config file */
- ssn.reassembly_depth = httplen1 + 1;
-
- TcpStream *s = NULL;
+ p->flowflags = FLOW_PKT_TOCLIENT;
+ p->payload = httpbuf2;
+ p->payload_len = httplen2;
+ tcph.th_seq = htonl(100);
+ tcph.th_ack = htonl(53);
s = &ssn.server;
- FLOWLOCK_WRLOCK(f);
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
- printf("failed in segments reassembly, while processing toclient packet: ");
+ printf("failed in segments reassembly, while processing toserver packet (11): ");
goto end;
}
-
- /* Check if we have flags set or not */
- if (s->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
- printf("there shouldn't be a noreassembly flag be set: ");
+ /* the flag should be set, as the smsg scanned size has crossed the max.
+ signature size for app proto detection */
+ if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn.client)) {
+ printf("app layer detected flag is not set, it should be (14): ");
goto end;
}
- STREAMTCP_SET_RA_BASE_SEQ(&ssn.server, ssn.server.isn + httplen1);
- p->flowflags = FLOW_PKT_TOSERVER;
- p->payload_len = httplen1;
- s = &ssn.client;
+ ret = 1;
+end:
+ StreamTcpReassembleFreeThreadCtx(ra_ctx);
+ StreamTcpFreeConfig(TRUE);
+ SCFree(p);
+ SCMutexUnlock(&f->m);
+ UTHFreeFlow(f);
+ return ret;
+}
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
- printf("failed in segments reassembly, while processing toserver packet: ");
+/** \test Test the memcap incrementing/decrementing and memcap check */
+static int StreamTcpReassembleTest44(void)
+{
+ uint8_t ret = 0;
+ StreamTcpInitConfig(TRUE);
+ uint32_t memuse = SC_ATOMIC_GET(ra_memuse);
+
+ StreamTcpReassembleIncrMemuse(500);
+ if (SC_ATOMIC_GET(ra_memuse) != (memuse+500)) {
+ printf("failed in incrementing the memory");
goto end;
}
- /* Check if we have flags set or not */
- if (s->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
- printf("there shouldn't be a noreassembly flag be set: ");
+ StreamTcpReassembleDecrMemuse(500);
+ if (SC_ATOMIC_GET(ra_memuse) != memuse) {
+ printf("failed in decrementing the memory");
goto end;
}
- STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, ssn.client.isn + httplen1);
- p->flowflags = FLOW_PKT_TOCLIENT;
- p->payload_len = httplen1;
- s = &ssn.server;
+ if (StreamTcpReassembleCheckMemcap(500) != 1) {
+ printf("failed in validating the memcap");
+ goto end;
+ }
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
- printf("failed in segments reassembly, while processing toserver packet: ");
+ if (StreamTcpReassembleCheckMemcap((memuse + stream_config.reassembly_memcap)) != 0) {
+ printf("failed in validating the memcap");
goto end;
}
- /* Check if we have flags set or not */
- if (!(s->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
- printf("the noreassembly flags should be set, "
- "p.payload_len %"PRIu16" stream_config.reassembly_"
- "depth %"PRIu32": ", p->payload_len,
- stream_config.reassembly_depth);
+ StreamTcpFreeConfig(TRUE);
+
+ if (SC_ATOMIC_GET(ra_memuse) != 0) {
+ printf("failed in clearing the memory");
goto end;
}
ret = 1;
+ return ret;
end:
- StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
- SCFree(p);
- FLOWLOCK_UNLOCK(f);
- UTHFreeFlow(f);
return ret;
}
/**
- * \test Test the undefined config value of reassembly depth.
- * the default value of 0 will be loaded and stream will be reassembled
- * until the session ended
+ * \test Test to make sure that reassembly_depth is enforced.
*
* \retval On success it returns 1 and on failure 0.
*/
-static int StreamTcpReassembleTest46 (void)
+static int StreamTcpReassembleTest45 (void)
{
- int ret = 0;
- Packet *p = PacketGetFromAlloc();
- if (unlikely(p == NULL))
- return 0;
- Flow *f = NULL;
- TCPHdr tcph;
+ TcpReassemblyThreadCtx *ra_ctx = NULL;
TcpSession ssn;
ThreadVars tv;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset(&tcph, 0, sizeof (TCPHdr));
- memset(&ssn, 0, sizeof(TcpSession));
- memset(&tv, 0, sizeof (ThreadVars));
-
- uint8_t httpbuf1[] = "/ HTTP/1.0\r\nUser-Agent: Victor/1.0";
- uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
-
- StreamTcpInitConfig(TRUE);
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
+ memset(&tv, 0, sizeof(tv));
+ uint8_t payload[100] = {0};
+ uint16_t payload_size = 100;
- STREAMTCP_SET_RA_BASE_SEQ(&ssn.server, 9);
- ssn.server.isn = 9;
- ssn.server.last_ack = 60;
- ssn.server.next_seq = ssn.server.isn;
- STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, 9);
- ssn.client.isn = 9;
- ssn.client.last_ack = 9;
- ssn.client.next_seq = ssn.client.isn;
+ StreamTcpUTInit(&ra_ctx);
+ stream_config.reassembly_depth = 100;
- f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
- if (f == NULL)
- goto end;
- f->protoctx = &ssn;
- f->proto = IPPROTO_TCP;
- p->flow = f;
+ StreamTcpUTSetupSession(&ssn);
+ ssn.reassembly_depth = 100;
+ StreamTcpUTSetupStream(&ssn.server, 100);
+ StreamTcpUTSetupStream(&ssn.client, 100);
- tcph.th_win = htons(5480);
- tcph.th_seq = htonl(10);
- tcph.th_ack = htonl(20);
- tcph.th_flags = TH_ACK|TH_PUSH;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOCLIENT;
+ int r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size);
+ FAIL_IF(r != 0);
+ FAIL_IF(ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY);
- p->payload = httpbuf1;
- p->payload_len = httplen1;
- ssn.state = TCP_ESTABLISHED;
+ r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size);
+ FAIL_IF(r != 0);
+ FAIL_IF(!(ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY));
- stream_config.reassembly_depth = 0;
+ StreamTcpUTClearStream(&ssn.server);
+ StreamTcpUTClearStream(&ssn.client);
+ StreamTcpUTClearSession(&ssn);
+ StreamTcpUTDeinit(ra_ctx);
+ PASS;
+}
- TcpStream *s = NULL;
- s = &ssn.server;
+/**
+ * \test Test the unlimited config value of reassembly depth.
+ *
+ * \retval On success it returns 1 and on failure 0.
+ */
- FLOWLOCK_WRLOCK(f);
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
- printf("failed in segments reassembly, while processing toclient packet\n");
- goto end;
- }
+static int StreamTcpReassembleTest46 (void)
+{
+ int result = 0;
+ TcpReassemblyThreadCtx *ra_ctx = NULL;
+ TcpSession ssn;
+ ThreadVars tv;
+ memset(&tv, 0, sizeof(tv));
+ uint8_t payload[100] = {0};
+ uint16_t payload_size = 100;
- /* Check if we have flags set or not */
- if ((ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
- (ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
- printf("there shouldn't be any no reassembly flag be set \n");
- goto end;
- }
- STREAMTCP_SET_RA_BASE_SEQ(&ssn.server, ssn.server.isn + httplen1);
+ StreamTcpUTInit(&ra_ctx);
+ stream_config.reassembly_depth = 0;
- p->flowflags = FLOW_PKT_TOSERVER;
- p->payload_len = httplen1;
- s = &ssn.client;
+ StreamTcpUTSetupSession(&ssn);
+ StreamTcpUTSetupStream(&ssn.server, 100);
+ StreamTcpUTSetupStream(&ssn.client, 100);
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
- printf("failed in segments reassembly, while processing toserver packet\n");
+ int r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 101, payload, payload_size);
+ if (r != 0)
goto end;
- }
-
- /* Check if we have flags set or not */
- if ((ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
- (ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
- printf("there shouldn't be any no reassembly flag be set \n");
+ if (ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
+ printf("STREAMTCP_STREAM_FLAG_NOREASSEMBLY set: ");
goto end;
}
- STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, ssn.client.isn + httplen1);
- p->flowflags = FLOW_PKT_TOCLIENT;
- p->payload_len = httplen1;
- tcph.th_seq = htonl(10 + httplen1);
- tcph.th_ack = htonl(20 + httplen1);
- s = &ssn.server;
-
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) {
- printf("failed in segments reassembly, while processing toserver packet\n");
+ r = StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, &ssn.client, 201, payload, payload_size);
+ if (r != 0)
goto end;
- }
-
- /* Check if we have flags set or not */
- if ((ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
- (ssn.server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
- printf("the no_reassembly flags should not be set, "
- "p->payload_len %"PRIu16" stream_config.reassembly_"
- "depth %"PRIu32": ", p->payload_len,
- stream_config.reassembly_depth);
+ if (ssn.client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) {
+ printf("STREAMTCP_STREAM_FLAG_NOREASSEMBLY set: ");
goto end;
}
- ret = 1;
+ result = 1;
end:
- StreamTcpReassembleFreeThreadCtx(ra_ctx);
- StreamTcpFreeConfig(TRUE);
- SCFree(p);
- FLOWLOCK_UNLOCK(f);
- UTHFreeFlow(f);
- return ret;
+ StreamTcpUTClearStream(&ssn.server);
+ StreamTcpUTClearStream(&ssn.client);
+ StreamTcpUTClearSession(&ssn);
+ StreamTcpUTDeinit(ra_ctx);
+ return result;
}
/**
uint8_t httpbuf1[] = "GET /EVILSUFF HTTP/1.1\r\n\r\n";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
- ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 572799781UL;
- ssn.server.isn = 572799781UL;
+ SET_ISN(&ssn.server, 572799781UL);
ssn.server.last_ack = 572799782UL;
- ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 4294967289UL;
- ssn.client.isn = 4294967289UL;
+
+ SET_ISN(&ssn.client, 4294967289UL);
ssn.client.last_ack = 21;
f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
}
ssn.client.next_seq = 17;
- int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed: ");
goto end;
}
- if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1) {
- printf("expected a single stream message: ");
- goto end;
- }
+ FAIL_IF(UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1);
StreamMsg *smsg = ssn.toserver_smsg_head;
if (UtTestSmsg(smsg, stream_payload, 15) == 0)
}
ssn.client.next_seq = 17;
- int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed: ");
goto end;
}
ssn.client.next_seq = 22;
- r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed 2: ");
goto end;
}
ssn.client.next_seq = 17;
- int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed: ");
goto end;
}
if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1) {
- printf("expected a single stream message 1: ");
+ printf("expected a single stream message 1, got %u: ", UtSsnSmsgCnt(&ssn, STREAM_TOSERVER));
goto end;
}
p->tcph->th_seq = htonl(17);
- r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed 2: ");
goto end;
}
ssn.client.next_seq = 17;
- int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed: ");
goto end;
p->tcph->th_seq = htonl(17);
- r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed 2: ");
goto end;
p->tcph->th_seq = htonl(17);
- int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed: ");
goto end;
p->tcph->th_seq = htonl(17);
- int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed: ");
goto end;
p->tcph->th_seq = htonl(12);
- r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed: ");
goto end;
p->tcph->th_seq = htonl(17);
- int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed: ");
goto end;
}
StreamMsg *smsg = ssn.toserver_smsg_head;
- if (UtTestSmsg(smsg, stream_payload1, 6) == 0)
+ if (UtTestSmsg(smsg, stream_payload1, 6) == 0) {
+ printf("stream_payload1 failed: ");
goto end;
+ }
smsg = ssn.toserver_smsg_head->next;
- if (UtTestSmsg(smsg, stream_payload2, 5) == 0)
+ if (UtTestSmsg(smsg, stream_payload2, 5) == 0) {
+ printf("stream_payload2 failed: ");
goto end;
+ }
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
printf("failed to add segment 3: ");
p->tcph->th_seq = htonl(12);
- r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed: ");
goto end;
}
smsg = ssn.toserver_smsg_head->next->next;
- if (UtTestSmsg(smsg, stream_payload3, 16) == 0)
+ if (UtTestSmsg(smsg, stream_payload3, 16) == 0) {
+ printf("stream_payload3 failed: ");
goto end;
+ }
ret = 1;
end:
*/
static int StreamTcpReassembleInlineTest08(void)
{
- int ret = 0;
TcpReassemblyThreadCtx *ra_ctx = NULL;
ThreadVars tv;
+ memset(&tv, 0x00, sizeof(tv));
TcpSession ssn;
Flow f;
-
- memset(&tv, 0x00, sizeof(tv));
-
StreamTcpUTInit(&ra_ctx);
StreamTcpUTInitInline();
StreamTcpUTSetupSession(&ssn);
stream_config.reassembly_toserver_chunk_size = 15;
ssn.client.flags |= STREAMTCP_STREAM_FLAG_GAP;
+ f.protoctx = &ssn;
uint8_t stream_payload1[] = "AAAAABBBBBCCCCC";
uint8_t stream_payload2[] = "BBBBBCCCCCDDDDD";
uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
- if (p == NULL) {
- printf("couldn't get a packet: ");
- goto end;
- }
+ FAIL_IF(p == NULL);
p->tcph->th_seq = htonl(12);
p->flow = &f;
p->flowflags |= FLOW_PKT_TOSERVER;
- FLOWLOCK_WRLOCK(&f);
- if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) {
- printf("failed to add segment 1: ");
- goto end;
- }
- if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) {
- printf("failed to add segment 2: ");
- goto end;
- }
- if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
- printf("failed to add segment 3: ");
- goto end;
- }
+ FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
+ FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
+ FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
ssn.client.next_seq = 17;
- int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
- if (r < 0) {
- printf("StreamTcpReassembleInlineRaw failed: ");
- goto end;
- }
-
- if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1) {
- printf("expected a single stream message: ");
- goto end;
- }
+ int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
+ FAIL_IF(r < 0);
+ FAIL_IF(UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1);
StreamMsg *smsg = ssn.toserver_smsg_head;
- if (UtTestSmsg(smsg, stream_payload1, 15) == 0)
- goto end;
-
- if (ssn.client.ra_raw_base_seq != 16) {
- printf("ra_raw_base_seq %"PRIu32", expected 16: ", ssn.client.ra_raw_base_seq);
- goto end;
- }
+ FAIL_IF(UtTestSmsg(smsg, stream_payload1, 15) == 0);
- if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
- printf("failed to add segment 4: ");
- goto end;
- }
+ FAIL_IF(ssn.client.raw_progress != 15);
+ FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1);
ssn.client.next_seq = 22;
-
p->tcph->th_seq = htonl(17);
- r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
- if (r < 0) {
- printf("StreamTcpReassembleInlineRaw failed 2: ");
- goto end;
- }
+ r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
+ FAIL_IF (r < 0);
- if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 2) {
- printf("expected a single stream message, got %u: ", UtSsnSmsgCnt(&ssn, STREAM_TOSERVER));
- goto end;
- }
+ FAIL_IF(UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 2);
smsg = ssn.toserver_smsg_head->next;
- if (UtTestSmsg(smsg, stream_payload2, 15) == 0)
- goto end;
+ FAIL_IF(UtTestSmsg(smsg, stream_payload2, 15) == 0);
- if (ssn.client.ra_raw_base_seq != 21) {
- printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq);
- goto end;
- }
+ FAIL_IF(ssn.client.raw_progress != 20);
- if (ssn.client.seg_list->seq != 7) {
- printf("expected segment 2 (seq 7) to be first in the list, got seq %"PRIu32": ", ssn.client.seg_list->seq);
- goto end;
- }
+ smsg = ssn.toserver_smsg_head;
+ StreamMsgReturnToPool(smsg);
+ ssn.toserver_smsg_head = ssn.toserver_smsg_head->next;
+
+ StreamTcpPruneSession(&f, STREAM_TOSERVER);
+
+ FAIL_IF (ssn.client.seg_list->seq != 2);
- ret = 1;
-end:
- FLOWLOCK_UNLOCK(&f);
FLOW_DESTROY(&f);
UTHFreePacket(p);
StreamTcpUTClearSession(&ssn);
StreamTcpUTDeinit(ra_ctx);
- return ret;
+ PASS;
}
/** \test 3 in order segments, then reassemble, add one more and reassemble again.
goto end;
}
ssn.client.next_seq = 12;
+ ssn.client.last_ack = 10;
- int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed: ");
goto end;
if (UtTestSmsg(smsg, stream_payload2, 5) == 0)
goto end;
- if (ssn.client.ra_raw_base_seq != 11) {
- printf("ra_raw_base_seq %"PRIu32", expected 11: ", ssn.client.ra_raw_base_seq);
+ if (ssn.client.raw_progress != 10) {
+ printf("raw_progress %"PRIu64", expected 10: ", ssn.client.raw_progress);
goto end;
}
- /* close the GAP and see if we properly reassemble and update ra_base_seq */
+ /* close the GAP and see if we properly reassemble and update base_seq */
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
printf("failed to add segment 4: ");
goto end;
p->tcph->th_seq = htonl(12);
- r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
+ r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed 2: ");
goto end;
if (UtTestSmsg(smsg, stream_payload3, 20) == 0)
goto end;
- if (ssn.client.ra_raw_base_seq != 21) {
- printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq);
+ if (ssn.client.raw_progress != 20) {
+ printf("raw_progress %"PRIu64", expected 20: ", ssn.client.raw_progress);
goto end;
}
}
/* ssn.server.ra_app_base_seq should be isn here. */
- if (ssn.server.ra_app_base_seq != 1 || ssn.server.ra_app_base_seq != ssn.server.isn) {
- printf("expected ra_app_base_seq 1, got %u: ", ssn.server.ra_app_base_seq);
+ if (ssn.server.base_seq != 2 || ssn.server.base_seq != ssn.server.isn+1) {
+ printf("expected ra_app_base_seq 1, got %u: ", ssn.server.base_seq);
goto end;
}
goto end;
}
- if (ssn.server.ra_app_base_seq != 18) {
- printf("expected ra_app_base_seq 18, got %u: ", ssn.server.ra_app_base_seq);
+ if (ssn.server.app_progress != 17) {
+ printf("expected ssn.server.app_progress == 17got %"PRIu64": ",
+ ssn.server.app_progress);
goto end;
}
*/
static int StreamTcpReassembleInsertTest01(void)
{
- int ret = 0;
TcpReassemblyThreadCtx *ra_ctx = NULL;
ThreadVars tv;
TcpSession ssn;
StreamTcpUTInit(&ra_ctx);
StreamTcpUTSetupSession(&ssn);
StreamTcpUTSetupStream(&ssn.client, 1);
+ ssn.client.os_policy = OS_POLICY_LAST;
FLOW_INITIALIZE(&f);
uint8_t stream_payload1[] = "AAAAABBBBBCCCCCDDDDD";
uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
- if (p == NULL) {
- printf("couldn't get a packet: ");
- goto end;
- }
+ FAIL_IF(p == NULL);
p->tcph->th_seq = htonl(12);
p->flow = &f;
- FLOWLOCK_WRLOCK(&f);
- if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) {
- printf("failed to add segment 1: ");
- goto end;
- }
- if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) {
- printf("failed to add segment 2: ");
- goto end;
- }
- if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 14, 'D', 2) == -1) {
- printf("failed to add segment 3: ");
- goto end;
- }
- if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 16, 'D', 6) == -1) {
- printf("failed to add segment 4: ");
- goto end;
- }
- if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
- printf("failed to add segment 5: ");
- goto end;
- }
+ FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1);
+ FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1);
+ FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 14, 'D', 2) == -1);
+ FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 16, 'D', 6) == -1);
+ FAIL_IF(StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1);
ssn.client.next_seq = 21;
- int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
- if (r < 0) {
- printf("StreamTcpReassembleInlineRaw failed: ");
- goto end;
- }
-
- if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1) {
- printf("expected a single stream message: ");
- goto end;
- }
-
+ int r = StreamTcpReassembleRaw(&tv, ra_ctx, &ssn, &ssn.client, p);
+ FAIL_IF (r < 0);
+ FAIL_IF (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1);
StreamMsg *smsg = ssn.toserver_smsg_head;
- if (UtTestSmsg(smsg, stream_payload1, 20) == 0)
- goto end;
+ FAIL_IF(UtTestSmsg(smsg, stream_payload1, 20) == 0);
+ FAIL_IF(ssn.client.raw_progress != 20);
- if (ssn.client.ra_raw_base_seq != 21) {
- printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq);
- goto end;
- }
- ret = 1;
-end:
- FLOWLOCK_UNLOCK(&f);
FLOW_DESTROY(&f);
UTHFreePacket(p);
StreamTcpUTClearSession(&ssn);
StreamTcpUTDeinit(ra_ctx);
- return ret;
+ PASS;
}
/** \test test insert with overlaps
void StreamTcpReassembleRegisterTests(void)
{
#ifdef UNITTESTS
- UtRegisterTest("StreamTcpReassembleTest01 -- BSD OS Before Reassembly Test",
- StreamTcpReassembleTest01);
- UtRegisterTest("StreamTcpReassembleTest02 -- BSD OS At Same Reassembly Test",
- StreamTcpReassembleTest02);
- UtRegisterTest("StreamTcpReassembleTest03 -- BSD OS After Reassembly Test",
- StreamTcpReassembleTest03);
- UtRegisterTest("StreamTcpReassembleTest04 -- BSD OS Complete Reassembly Test",
- StreamTcpReassembleTest04);
- UtRegisterTest("StreamTcpReassembleTest05 -- VISTA OS Before Reassembly Test",
- StreamTcpReassembleTest05);
- UtRegisterTest("StreamTcpReassembleTest06 -- VISTA OS At Same Reassembly Test",
- StreamTcpReassembleTest06);
- UtRegisterTest("StreamTcpReassembleTest07 -- VISTA OS After Reassembly Test",
- StreamTcpReassembleTest07);
- UtRegisterTest("StreamTcpReassembleTest08 -- VISTA OS Complete Reassembly Test",
- StreamTcpReassembleTest08);
- UtRegisterTest("StreamTcpReassembleTest09 -- LINUX OS Before Reassembly Test",
- StreamTcpReassembleTest09);
- UtRegisterTest("StreamTcpReassembleTest10 -- LINUX OS At Same Reassembly Test",
- StreamTcpReassembleTest10);
- UtRegisterTest("StreamTcpReassembleTest11 -- LINUX OS After Reassembly Test",
- StreamTcpReassembleTest11);
- UtRegisterTest("StreamTcpReassembleTest12 -- LINUX OS Complete Reassembly Test",
- StreamTcpReassembleTest12);
- UtRegisterTest("StreamTcpReassembleTest13 -- LINUX_OLD OS Before Reassembly Test",
- StreamTcpReassembleTest13);
- UtRegisterTest("StreamTcpReassembleTest14 -- LINUX_OLD At Same Reassembly Test",
- StreamTcpReassembleTest14);
- UtRegisterTest("StreamTcpReassembleTest15 -- LINUX_OLD OS After Reassembly Test",
- StreamTcpReassembleTest15);
- UtRegisterTest("StreamTcpReassembleTest16 -- LINUX_OLD OS Complete Reassembly Test",
- StreamTcpReassembleTest16);
- UtRegisterTest("StreamTcpReassembleTest17 -- SOLARIS OS Before Reassembly Test",
- StreamTcpReassembleTest17);
- UtRegisterTest("StreamTcpReassembleTest18 -- SOLARIS At Same Reassembly Test",
- StreamTcpReassembleTest18);
- UtRegisterTest("StreamTcpReassembleTest19 -- SOLARIS OS After Reassembly Test",
- StreamTcpReassembleTest19);
- UtRegisterTest("StreamTcpReassembleTest20 -- SOLARIS OS Complete Reassembly Test",
- StreamTcpReassembleTest20);
- UtRegisterTest("StreamTcpReassembleTest21 -- LAST OS Before Reassembly Test",
- StreamTcpReassembleTest21);
- UtRegisterTest("StreamTcpReassembleTest22 -- LAST OS At Same Reassembly Test",
- StreamTcpReassembleTest22);
- UtRegisterTest("StreamTcpReassembleTest23 -- LAST OS After Reassembly Test",
- StreamTcpReassembleTest23);
- UtRegisterTest("StreamTcpReassembleTest24 -- LAST OS Complete Reassembly Test",
- StreamTcpReassembleTest24);
UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test",
StreamTcpReassembleTest25);
UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test",
StreamTcpReassembleTest28);
UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test",
StreamTcpReassembleTest29);
- UtRegisterTest("StreamTcpReassembleTest30 -- Gap at End IDS missed packet Reassembly Test",
- StreamTcpReassembleTest30);
- UtRegisterTest("StreamTcpReassembleTest31 -- Fast Track Reassembly Test",
- StreamTcpReassembleTest31);
- UtRegisterTest("StreamTcpReassembleTest32 -- Bug test",
- StreamTcpReassembleTest32);
UtRegisterTest("StreamTcpReassembleTest33 -- Bug test",
StreamTcpReassembleTest33);
UtRegisterTest("StreamTcpReassembleTest34 -- Bug test",
StreamTcpReassembleTest34);
- UtRegisterTest("StreamTcpReassembleTest35 -- Bug56 test",
- StreamTcpReassembleTest35);
- UtRegisterTest("StreamTcpReassembleTest36 -- Bug57 test",
- StreamTcpReassembleTest36);
UtRegisterTest("StreamTcpReassembleTest37 -- Bug76 test",
StreamTcpReassembleTest37);
UtRegisterTest("StreamTcpReassembleTest38 -- app proto test",
StreamTcpInlineRegisterTests();
StreamTcpUtilRegisterTests();
+ StreamTcpListRegisterTests();
#endif /* UNITTESTS */
}