diff options
author | Ashlee Young <ashlee@wildernessvoice.com> | 2016-01-20 01:10:01 +0000 |
---|---|---|
committer | Ashlee Young <ashlee@wildernessvoice.com> | 2016-01-20 01:10:11 +0000 |
commit | 19d701ddf07d855128ded0cf2b573ce468e3bdd6 (patch) | |
tree | 0edcd3461ca903c76e431bb7c6348c42a0f12488 /framework/src/suricata/src/stream-tcp-reassemble.c | |
parent | fac6fbefbfad1cf837ddd88bc0d330559c8eb6f9 (diff) |
Removing Suricata and Audit from source repo, and updated build.sh to avoid building suricata. Will re-address this in C release via tar balls.
Change-Id: I3710076f8b7f3313cb3cb5260c4eb0a6834d4f6e
Signed-off-by: Ashlee Young <ashlee@wildernessvoice.com>
Diffstat (limited to 'framework/src/suricata/src/stream-tcp-reassemble.c')
-rw-r--r-- | framework/src/suricata/src/stream-tcp-reassemble.c | 8757 |
1 files changed, 0 insertions, 8757 deletions
diff --git a/framework/src/suricata/src/stream-tcp-reassemble.c b/framework/src/suricata/src/stream-tcp-reassemble.c deleted file mode 100644 index a947fab3..00000000 --- a/framework/src/suricata/src/stream-tcp-reassemble.c +++ /dev/null @@ -1,8757 +0,0 @@ -/* Copyright (C) 2007-2013 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 - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Gurvinder Singh <gurvindersinghdahiya@gmail.com> - * \author Victor Julien <victor@inliniac.net> - * - * Reference: - * Judy Novak, Steve Sturges: Target-Based TCP Stream Reassembly August, 2007 - * - */ - -#include "suricata-common.h" -#include "suricata.h" -#include "debug.h" -#include "detect.h" -#include "flow.h" -#include "threads.h" -#include "conf.h" - -#include "flow-util.h" - -#include "threadvars.h" -#include "tm-threads.h" - -#include "util-pool.h" -#include "util-unittest.h" -#include "util-print.h" -#include "util-host-os-info.h" -#include "util-unittest-helper.h" -#include "util-byte.h" - -#include "stream-tcp.h" -#include "stream-tcp-private.h" -#include "stream-tcp-reassemble.h" -#include "stream-tcp-inline.h" -#include "stream-tcp-util.h" - -#include "stream.h" - -#include "util-debug.h" -#include "app-layer-protos.h" -#include "app-layer.h" -#include "app-layer-events.h" - -#include "detect-engine-state.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; -static uint64_t segment_pool_memcnt = 0; -#endif - -/* We define several pools with prealloced segments with fixed size - * payloads. We do this to prevent having to do an SCMalloc call for every - * data segment we receive, which would be a large performance penalty. - * The cost is in memory of course. The number of pools and the properties - * of the pools are determined by the yaml. */ -static int segment_pool_num = 0; -static Pool **segment_pool = NULL; -static SCMutex *segment_pool_mutex = NULL; -static uint16_t *segment_pool_pktsizes = NULL; -#ifdef DEBUG -static SCMutex segment_pool_cnt_mutex; -static uint64_t segment_pool_cnt = 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 - * segments - * - * \param size Size of the TCP segment and its payload length memory allocated - */ -void StreamTcpReassembleIncrMemuse(uint64_t size) -{ - (void) SC_ATOMIC_ADD(ra_memuse, size); - return; -} - -/** - * \brief Function to Decrease the memory usage counter for the TCP reassembly - * segments - * - * \param size Size of the TCP segment and its payload length memory allocated - */ -void StreamTcpReassembleDecrMemuse(uint64_t size) -{ - (void) SC_ATOMIC_SUB(ra_memuse, size); - return; -} - -uint64_t StreamTcpReassembleMemuseGlobalCounter(void) -{ - uint64_t smemuse = SC_ATOMIC_GET(ra_memuse); - return smemuse; -} - -/** - * \brief Function to Check the reassembly memory usage counter against the - * allowed max memory usgae for TCP segments. - * - * \param size Size of the TCP segment and its payload length memory allocated - * \retval 1 if in bounds - * \retval 0 if not in bounds - */ -int StreamTcpReassembleCheckMemcap(uint32_t size) -{ - if (stream_config.reassembly_memcap == 0 || - (uint64_t)((uint64_t)size + SC_ATOMIC_GET(ra_memuse)) <= stream_config.reassembly_memcap) - return 1; - return 0; -} - -/** \brief alloc a tcp segment pool entry */ -void *TcpSegmentPoolAlloc() -{ - if (StreamTcpReassembleCheckMemcap((uint32_t)sizeof(TcpSegment)) == 0) { - return NULL; - } - - TcpSegment *seg = NULL; - - seg = SCMalloc(sizeof (TcpSegment)); - if (unlikely(seg == NULL)) - return NULL; - return seg; -} - -int TcpSegmentPoolInit(void *data, void *payload_len) -{ - TcpSegment *seg = (TcpSegment *) data; - uint16_t size = *((uint16_t *) payload_len); - - /* do this before the can bail, so TcpSegmentPoolCleanup - * won't have uninitialized memory to consider. */ - memset(seg, 0, sizeof (TcpSegment)); - - if (StreamTcpReassembleCheckMemcap((uint32_t)size + (uint32_t)sizeof(TcpSegment)) == 0) { - return 0; - } - - seg->pool_size = size; - seg->payload_len = seg->pool_size; - - seg->payload = SCMalloc(seg->payload_len); - if (seg->payload == NULL) { - return 0; - } - -#ifdef DEBUG - SCMutexLock(&segment_pool_memuse_mutex); - segment_pool_memuse += seg->payload_len; - segment_pool_memcnt++; - SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt); - SCMutexUnlock(&segment_pool_memuse_mutex); -#endif - - StreamTcpReassembleIncrMemuse((uint32_t)seg->pool_size + sizeof(TcpSegment)); - return 1; -} - -/** \brief clean up a tcp segment pool entry */ -void TcpSegmentPoolCleanup(void *ptr) -{ - if (ptr == NULL) - return; - - TcpSegment *seg = (TcpSegment *) ptr; - - StreamTcpReassembleDecrMemuse((uint32_t)seg->pool_size + sizeof(TcpSegment)); - -#ifdef DEBUG - SCMutexLock(&segment_pool_memuse_mutex); - segment_pool_memuse -= seg->pool_size; - segment_pool_memcnt--; - SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt); - SCMutexUnlock(&segment_pool_memuse_mutex); -#endif - - SCFree(seg->payload); - return; -} - -/** - * \brief Function to return the segment back to the pool. - * - * \param seg Segment which will be returned back to the pool. - */ -void StreamTcpSegmentReturntoPool(TcpSegment *seg) -{ - if (seg == NULL) - return; - - seg->next = NULL; - seg->prev = NULL; - - uint16_t idx = segment_pool_idx[seg->pool_size]; - SCMutexLock(&segment_pool_mutex[idx]); - PoolReturn(segment_pool[idx], (void *) seg); - SCLogDebug("segment_pool[%"PRIu16"]->empty_stack_size %"PRIu32"", - idx,segment_pool[idx]->empty_stack_size); - SCMutexUnlock(&segment_pool_mutex[idx]); - -#ifdef DEBUG - SCMutexLock(&segment_pool_cnt_mutex); - segment_pool_cnt--; - SCMutexUnlock(&segment_pool_cnt_mutex); -#endif -} - -/** - * \brief return all segments in this stream into the pool(s) - * - * \param stream the stream to cleanup - */ -void StreamTcpReturnStreamSegments (TcpStream *stream) -{ - TcpSegment *seg = stream->seg_list; - TcpSegment *next_seg; - - if (seg == NULL) - return; - - while (seg != NULL) { - next_seg = seg->next; - StreamTcpSegmentReturntoPool(seg); - seg = next_seg; - } - - stream->seg_list = NULL; - stream->seg_list_tail = NULL; -} - -/** \param f locked flow */ -void StreamTcpDisableAppLayer(Flow *f) -{ - if (f->protoctx == NULL) - return; - - TcpSession *ssn = (TcpSession *)f->protoctx; - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->client); - StreamTcpSetStreamFlagAppProtoDetectionCompleted(&ssn->server); - StreamTcpDisableAppLayerReassembly(ssn); -} - -/** \param f locked flow */ -int StreamTcpAppLayerIsDisabled(Flow *f) -{ - if (f->protoctx == NULL || f->proto != IPPROTO_TCP) - return 0; - - TcpSession *ssn = (TcpSession *)f->protoctx; - return (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED); -} - -typedef struct SegmentSizes_ -{ - uint16_t pktsize; - uint32_t prealloc; -} SegmentSizes; - -/* sort small to big */ -static int SortByPktsize(const void *a, const void *b) -{ - const SegmentSizes *s0 = a; - const SegmentSizes *s1 = b; - return s0->pktsize - s1->pktsize; -} - -int StreamTcpReassemblyConfig(char quiet) -{ - Pool **my_segment_pool = NULL; - SCMutex *my_segment_lock = NULL; - uint16_t *my_segment_pktsizes = NULL; - SegmentSizes sizes[256]; - memset(&sizes, 0x00, sizeof(sizes)); - - int npools = 0; - ConfNode *segs = ConfGetNode("stream.reassembly.segments"); - if (segs != NULL) { - ConfNode *seg; - TAILQ_FOREACH(seg, &segs->head, next) { - ConfNode *segsize = ConfNodeLookupChild(seg,"size"); - if (segsize == NULL) - continue; - ConfNode *segpre = ConfNodeLookupChild(seg,"prealloc"); - if (segpre == NULL) - continue; - - if (npools >= 256) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "too many segment packet " - "pools defined, max is 256"); - return -1; - } - - SCLogDebug("segsize->val %s", segsize->val); - SCLogDebug("segpre->val %s", segpre->val); - - uint16_t pktsize = 0; - if (ByteExtractStringUint16(&pktsize, 10, strlen(segsize->val), - segsize->val) == -1) - { - SCLogError(SC_ERR_INVALID_ARGUMENT, "segment packet size " - "of %s is invalid", segsize->val); - return -1; - } - uint32_t prealloc = 0; - if (ByteExtractStringUint32(&prealloc, 10, strlen(segpre->val), - segpre->val) == -1) - { - SCLogError(SC_ERR_INVALID_ARGUMENT, "segment prealloc of " - "%s is invalid", segpre->val); - return -1; - } - - sizes[npools].pktsize = pktsize; - sizes[npools].prealloc = prealloc; - SCLogDebug("pktsize %u, prealloc %u", sizes[npools].pktsize, - sizes[npools].prealloc); - npools++; - } - } - - SCLogDebug("npools %d", npools); - if (npools > 0) { - /* sort the array as the index code below relies on it */ - qsort(&sizes, npools, sizeof(sizes[0]), SortByPktsize); - if (sizes[npools - 1].pktsize != 0xffff) { - sizes[npools].pktsize = 0xffff; - sizes[npools].prealloc = 8; - npools++; - SCLogInfo("appended a segment pool for pktsize 65536"); - } - } else if (npools == 0) { - /* defaults */ - sizes[0].pktsize = 4; - sizes[0].prealloc = 256; - sizes[1].pktsize = 16; - sizes[1].prealloc = 512; - sizes[2].pktsize = 112; - sizes[2].prealloc = 512; - sizes[3].pktsize = 248; - sizes[3].prealloc = 512; - sizes[4].pktsize = 512; - sizes[4].prealloc = 512; - sizes[5].pktsize = 768; - sizes[5].prealloc = 1024; - sizes[6].pktsize = 1448; - sizes[6].prealloc = 1024; - sizes[7].pktsize = 0xffff; - sizes[7].prealloc = 128; - npools = 8; - } - - int i = 0; - for (i = 0; i < npools; i++) { - SCLogDebug("pktsize %u, prealloc %u", sizes[i].pktsize, sizes[i].prealloc); - } - - my_segment_pool = SCMalloc(npools * sizeof(Pool *)); - if (my_segment_pool == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "malloc failed"); - return -1; - } - my_segment_lock = SCMalloc(npools * sizeof(SCMutex)); - if (my_segment_lock == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "malloc failed"); - - SCFree(my_segment_pool); - return -1; - } - my_segment_pktsizes = SCMalloc(npools * sizeof(uint16_t)); - if (my_segment_pktsizes == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "malloc failed"); - - SCFree(my_segment_lock); - SCFree(my_segment_pool); - return -1; - } - uint32_t my_segment_poolsizes[npools]; - - for (i = 0; i < npools; i++) { - my_segment_pktsizes[i] = sizes[i].pktsize; - my_segment_poolsizes[i] = sizes[i].prealloc; - SCMutexInit(&my_segment_lock[i], NULL); - - /* setup the pool */ - SCMutexLock(&my_segment_lock[i]); - my_segment_pool[i] = PoolInit(0, my_segment_poolsizes[i], 0, - TcpSegmentPoolAlloc, TcpSegmentPoolInit, - (void *) &my_segment_pktsizes[i], - TcpSegmentPoolCleanup, NULL); - SCMutexUnlock(&my_segment_lock[i]); - - if (my_segment_pool[i] == NULL) { - SCLogError(SC_ERR_INITIALIZATION, "couldn't set up segment pool " - "for packet size %u. Memcap too low?", my_segment_pktsizes[i]); - exit(EXIT_FAILURE); - } - - SCLogDebug("my_segment_pktsizes[i] %u, my_segment_poolsizes[i] %u", - my_segment_pktsizes[i], my_segment_poolsizes[i]); - if (!quiet) - SCLogInfo("segment pool: pktsize %u, prealloc %u", - my_segment_pktsizes[i], my_segment_poolsizes[i]); - } - - uint16_t idx = 0; - uint16_t u16 = 0; - while (1) { - if (idx <= my_segment_pktsizes[u16]) { - segment_pool_idx[idx] = u16; - if (my_segment_pktsizes[u16] == idx) - u16++; - } - - if (idx == 0xffff) - break; - - idx++; - } - /* set the globals */ - segment_pool = my_segment_pool; - segment_pool_mutex = my_segment_lock; - segment_pool_pktsizes = my_segment_pktsizes; - segment_pool_num = npools; - - uint32_t stream_chunk_prealloc = 250; - ConfNode *chunk = ConfGetNode("stream.reassembly.chunk-prealloc"); - if (chunk) { - uint32_t prealloc = 0; - if (ByteExtractStringUint32(&prealloc, 10, strlen(chunk->val), chunk->val) == -1) - { - SCLogError(SC_ERR_INVALID_ARGUMENT, "chunk-prealloc of " - "%s is invalid", chunk->val); - return -1; - } - stream_chunk_prealloc = prealloc; - } - if (!quiet) - SCLogInfo("stream.reassembly \"chunk-prealloc\": %u", stream_chunk_prealloc); - StreamMsgQueuesInit(stream_chunk_prealloc); - - intmax_t zero_copy_size = 128; - if (ConfGetInt("stream.reassembly.zero-copy-size", &zero_copy_size) == 1) { - if (zero_copy_size < 0 || zero_copy_size > 0xffff) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "stream.reassembly.zero-copy-size of " - "%"PRIiMAX" is invalid: valid values are 0 to 65535", zero_copy_size); - return -1; - } - } - stream_config.zero_copy_size = (uint16_t)zero_copy_size; - if (!quiet) - SCLogInfo("stream.reassembly \"zero-copy-size\": %u", stream_config.zero_copy_size); - - return 0; -} - -int StreamTcpReassembleInit(char quiet) -{ - /* init the memcap/use tracker */ - SC_ATOMIC_INIT(ra_memuse); - - if (StreamTcpReassemblyConfig(quiet) < 0) - return -1; -#ifdef DEBUG - SCMutexInit(&segment_pool_memuse_mutex, NULL); - SCMutexInit(&segment_pool_cnt_mutex, NULL); -#endif - - StatsRegisterGlobalCounter("tcp.reassembly_memuse", - StreamTcpReassembleMemuseGlobalCounter); - 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; - for (u16 = 0; u16 < segment_pool_num; u16++) { - SCMutexLock(&segment_pool_mutex[u16]); - - if (quiet == FALSE) { - PoolPrintSaturation(segment_pool[u16]); - SCLogDebug("segment_pool[u16]->empty_stack_size %"PRIu32", " - "segment_pool[u16]->alloc_stack_size %"PRIu32", alloced " - "%"PRIu32"", segment_pool[u16]->empty_stack_size, - segment_pool[u16]->alloc_stack_size, - segment_pool[u16]->allocated); - - if (segment_pool[u16]->max_outstanding > segment_pool[u16]->allocated) { - SCLogInfo("TCP segment pool of size %u had a peak use of %u segments, " - "more than the prealloc setting of %u", segment_pool_pktsizes[u16], - segment_pool[u16]->max_outstanding, segment_pool[u16]->allocated); - } - } - PoolFree(segment_pool[u16]); - - SCMutexUnlock(&segment_pool_mutex[u16]); - SCMutexDestroy(&segment_pool_mutex[u16]); - } - SCFree(segment_pool); - SCFree(segment_pool_mutex); - SCFree(segment_pool_pktsizes); - segment_pool = NULL; - segment_pool_mutex = NULL; - segment_pool_pktsizes = NULL; - - StreamMsgQueuesDeinit(quiet); - -#ifdef DEBUG - SCLogDebug("segment_pool_cnt %"PRIu64"", segment_pool_cnt); - SCLogDebug("segment_pool_memuse %"PRIu64"", segment_pool_memuse); - SCLogDebug("segment_pool_memcnt %"PRIu64"", segment_pool_memcnt); - SCMutexDestroy(&segment_pool_memuse_mutex); - SCMutexDestroy(&segment_pool_cnt_mutex); - SCLogInfo("dbg_app_layer_gap %u", dbg_app_layer_gap); - SCLogInfo("dbg_app_layer_gap_candidate %u", dbg_app_layer_gap_candidate); -#endif -} - -TcpReassemblyThreadCtx *StreamTcpReassembleInitThreadCtx(ThreadVars *tv) -{ - SCEnter(); - TcpReassemblyThreadCtx *ra_ctx = SCMalloc(sizeof(TcpReassemblyThreadCtx)); - if (unlikely(ra_ctx == NULL)) - return NULL; - - memset(ra_ctx, 0x00, sizeof(TcpReassemblyThreadCtx)); - - ra_ctx->app_tctx = AppLayerGetCtxThread(tv); - - SCReturnPtr(ra_ctx, "TcpReassemblyThreadCtx"); -} - -void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *ra_ctx) -{ - SCEnter(); - AppLayerDestroyCtxThread(ra_ctx->app_tctx); -#ifdef DEBUG - SCLogDebug("reassembly fast path stats: fp1 %"PRIu64" fp2 %"PRIu64" sp %"PRIu64, - ra_ctx->fp1, ra_ctx->fp2, ra_ctx->sp); -#endif - SCFree(ra_ctx); - 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 - * - * \retval seq the active ra_base_seq - */ -static inline uint32_t StreamTcpReassembleGetRaBaseSeq(TcpStream *stream) -{ - if (!(stream->flags & STREAMTCP_STREAM_FLAG_GAP)) { - SCReturnUInt(stream->ra_app_base_seq); - } else { - SCReturnUInt(stream->ra_raw_base_seq); - } -} - -/** - * \internal - * \brief Function to handle the insertion newly arrived segment, - * The packet is handled based on its target OS. - * - * \param stream The given TCP stream to which this new segment belongs - * \param seg Newly arrived segment - * \param p received packet - * - * \retval 0 success - * \retval -1 error -- either we hit a memory issue (OOM/memcap) or we received - * a segment before ra_base_seq. - */ -int StreamTcpReassembleInsertSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, - TcpStream *stream, TcpSegment *seg, Packet *p) -{ - 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; - } - - 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; - } - - /* 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; - } - - /* 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; - - goto end; - } - - /* If the OS policy is not set then set the OS policy for this stream */ - if (stream->os_policy == 0) { - StreamTcpSetOSPolicy(stream, p); - } - - 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; - - goto end; - - /* 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; - } - } - - /* 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; - } - - /* 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; - } - } - } - } - -end: - if (return_seg == TRUE && seg != NULL) { - StreamTcpSegmentReturntoPool(seg); - } - -#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. - * - * \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 - * - * \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) -{ - 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 (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; - } - - packet_length = list_seg->seq - new_seq; - if (packet_length > seg->payload_len) { - packet_length = 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; - - new_seg->seq = new_seq; - - SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len " - "%" PRIu16"", new_seg->seq, new_seg->payload_len); - - 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 - } - - /* 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; - } - - SCLogDebug("entered here packet_length %" PRIu32 ", seg->payload_len" - " %" PRIu32 ", list->payload_len %" PRIu32 "", - packet_length, seg->payload_len, 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; - new_seg->seq = seg->seq; - new_seg->next = list_seg->next; - new_seg->prev = list_seg->prev; - - StreamTcpSegmentDataCopy(new_seg, list_seg); - - /* 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); - - /* 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); - } - - /* 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; - } - - stream->seg_list = new_seg; - SCLogDebug("list_seg now %p, stream->seg_list now %p", list_seg, - stream->seg_list); - - } 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)); - } - - 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; - - 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)); - } - - 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; - } - - /*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; - } - } - - 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); - } - - 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); - } - } - - SCReturnInt(0); -} - -/** - * \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 - */ - -static int HandleSegmentStartsAtSameListSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, - TcpStream *stream, TcpSegment *list_seg, TcpSegment *seg, Packet *p) -{ - 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; - } - - 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; - } - - SCLogDebug("packet_length %"PRIu16"", packet_length); - - TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length); - if (new_seg == NULL) { - SCLogDebug("egment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]); - - 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 (check_overlap_different_data && - !StreamTcpSegmentDataCompare(list_seg, seg, seg->seq, overlap)) { - /* interesting, overlap with different data */ - StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA); - } - - 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; - } - } - - /* return 1 if we're done */ - if (end_before == TRUE || end_same == TRUE || handle_beyond == FALSE) { - return 1; - } - } - 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 - - * \retval 1 success and done - * \retval 0 success, but not done yet - * \retval -1 error, will *only* happen on memory errors - */ - -static int HandleSegmentStartsAfterListSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, - TcpStream *stream, TcpSegment *list_seg, TcpSegment *seg, Packet *p) -{ - 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; - } - - /* 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; - } - - 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 */ - if (list_seg->next != NULL) { - SCLogDebug("filling gap: list_seg->next->seq %"PRIu32"", - list_seg->next?list_seg->next->seq: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); - - 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; - 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 (check_overlap_different_data && - !StreamTcpSegmentDataCompare(list_seg, seg, seg->seq, overlap)) { - /* interesting, overlap with different data */ - StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA); - } - - if (StreamTcpInlineMode()) { - if (StreamTcpInlineSegmentCompare(list_seg, seg) != 0) { - StreamTcpInlineSegmentReplacePacket(p, list_seg); - } - } 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); - } - } - 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 - */ -int StreamTcpReassembleDepthReached(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; - } - - return (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) ? 1 : 0; - } - - return 0; -} - -/** - * \internal - * \brief Function to Check the reassembly depth valuer against the - * allowed max depth of the stream reassmbly for TCP streams. - * - * \param stream stream direction - * \param seq sequence number where "size" starts - * \param size size of the segment that is added - * - * \retval size Part of the size that fits in the depth, 0 if none - */ -static uint32_t StreamTcpReassembleCheckDepth(TcpStream *stream, - uint32_t seq, uint32_t size) -{ - SCEnter(); - - /* if the configured depth value is 0, it means there is no limit on - reassembly depth. Otherwise carry on my boy ;) */ - if (stream_config.reassembly_depth == 0) { - SCReturnUInt(size); - } - - /* if the final flag is set, we're not accepting anymore */ - if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { - SCReturnUInt(0); - } - - /* 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 + stream_config.reassembly_depth))) { - stream->flags |= STREAMTCP_STREAM_FLAG_DEPTH_REACHED; - SCReturnUInt(0); - } - - SCLogDebug("full Depth not yet reached: %"PRIu32" <= %"PRIu32, - (StreamTcpReassembleGetRaBaseSeq(stream)+1), - (stream->isn + stream_config.reassembly_depth)); - - if (SEQ_GEQ(seq, stream->isn) && SEQ_LT(seq, (stream->isn + stream_config.reassembly_depth))) { - /* packet (partly?) fits the depth window */ - - if (SEQ_LEQ((seq + size),(stream->isn + stream_config.reassembly_depth))) { - /* complete fit */ - SCReturnUInt(size); - } else { - /* partial fit, return only what fits */ - uint32_t part = (stream->isn + stream_config.reassembly_depth) - seq; -#if DEBUG - BUG_ON(part > size); -#else - if (part > size) - part = size; -#endif - SCReturnUInt(part); - } - } - - SCReturnUInt(0); -} - -static void StreamTcpStoreStreamChunk(TcpSession *ssn, StreamMsg *smsg, const Packet *p, int streaminline) -{ - uint8_t direction = 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"); - } - - /* store the smsg in the tcp stream */ - if (direction == STREAM_TOSERVER) { - SCLogDebug("storing smsg in the to_server"); - - /* 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"); - - /* 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; - } - } -} - -/** - * \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. - * - */ -int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, - 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; - } - } - - 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); - } - - /* If we have reached the defined depth for either of the stream, then stop - reassembling the TCP session */ - uint32_t size = StreamTcpReassembleCheckDepth(stream, TCP_GET_SEQ(p), p->payload_len); - SCLogDebug("ssn %p: check depth returned %"PRIu32, ssn, size); - - if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { - /* increment stream depth counter */ - StatsIncr(tv, ra_ctx->counter_tcp_stream_depth); - - 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); - } - -#if DEBUG - BUG_ON(size > p->payload_len); -#else - if (size > p->payload_len) - size = p->payload_len; -#endif - - TcpSegment *seg = StreamTcpGetSegment(tv, ra_ctx, size); - if (seg == NULL) { - SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[size]); - - StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT); - SCReturnInt(-1); - } - - memcpy(seg->payload, p->payload, size); - seg->payload_len = size; - seg->seq = TCP_GET_SEQ(p); - - if (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) - seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED; - - /* 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); - } - - /* proto detection skipped, but now we do get data. Set event. */ - if (stream->seg_list == NULL && - stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED) { - - AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, - APPLAYER_PROTO_DETECTION_SKIPPED); - } - - if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, seg, p) != 0) { - SCLogDebug("StreamTcpReassembleInsertSegment failed"); - SCReturnInt(-1); - } - - SCReturnInt(0); -} - -static uint8_t StreamGetAppLayerFlags(TcpSession *ssn, TcpStream *stream, - Packet *p) -{ - uint8_t flag = 0; - - if (!(stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED)) { - flag |= STREAM_START; - } - - if (ssn->state == TCP_CLOSED) { - flag |= STREAM_EOF; - } - if (p->flags & PKT_PSEUDO_STREAM_END) { - flag |= STREAM_EOF; - } - - 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; - } - } - - if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) { - flag |= STREAM_DEPTH; - } - return flag; -} - -static void StreamTcpSetupMsg(TcpSession *ssn, TcpStream *stream, Packet *p, - StreamMsg *smsg) -{ - SCEnter(); - smsg->data_len = 0; - SCLogDebug("smsg %p", smsg); - SCReturn; -} - -/** - * \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(); - - 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); - } - - 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); - } - - 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); - } - - /* some states mean we reassemble no matter how much data we have */ - if (ssn->state >= TCP_TIME_WAIT) - SCReturnInt(1); - - if (p->flags & PKT_PSEUDO_STREAM_END) - 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)); - - 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)); - - 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); - } - } - - SCReturnInt(1); -} - -/** - * \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 - * - * If a segment is entirely before the oldest smsg, we can discard it. Otherwise - * we keep it around to be able to log it. - * - * \retval 1 yes - * \retval 0 no - */ -static inline int StreamTcpReturnSegmentCheck(const Flow *f, TcpSession *ssn, TcpStream *stream, TcpSegment *seg) -{ - 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); - } - - /* check raw reassembly conditions */ - if (!(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) { - SCReturnInt(0); - } - - SCReturnInt(1); -} - -static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg) -{ - if (seg->prev == NULL) { - stream->seg_list = seg->next; - if (stream->seg_list != NULL) - stream->seg_list->prev = NULL; - } else { - seg->prev->next = seg->next; - if (seg->next != NULL) - seg->next->prev = seg->prev; - } - - if (stream->seg_list_tail == seg) - stream->seg_list_tail = seg->prev; -} - -/** - * \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 - * - * GAP situation: each chunk that is uninterrupted has it's own smsg - * [aaabbb].[dddeeefff] - * [aaa].[ccc].[eeefff] - * - * A flag will be set to indicate where the *NEW* payload starts. This - * is to aid the detection code for alert only sigs. - * - * \todo this function is too long, we need to break it up. It needs it BAD - */ -static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx, - TcpSession *ssn, TcpStream *stream, Packet *p) -{ - SCEnter(); - SCLogDebug("start p %p, seq %"PRIu32, p, TCP_GET_SEQ(p)); - - if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW) - SCReturnInt(0); - if (stream->seg_list == NULL) { - SCReturnInt(0); - } - - 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; - - uint32_t chunk_size = PKT_IS_TOSERVER(p) ? - stream_config.reassembly_toserver_chunk_size : - stream_config.reassembly_toclient_chunk_size; - - /* 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; - - /* 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; - } - - 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 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); - - /* 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))) { - payload_len = (stream->last_ack - seg->seq); - SCLogDebug("payload_len %u", payload_len); - } 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_len) { - copy_size = payload_len; - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(rd->data)); - } - 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) { - 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)) { - payload_len = (stream->last_ack - seg->seq); - } 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_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; - } - - SCMutexLock(&f.m); - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, ssn, s, p, &pq) == -1) { - SCMutexUnlock(&f.m); - SCFree(p); - return -1; - } - - SCMutexUnlock(&f.m); - 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. - * - * \retval On success it returns 1 and on failure 0. - */ - -static int StreamTcpReassembleTest28 (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}; - TcpSession ssn; - memset(&ssn, 0, sizeof (TcpSession)); - TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL); - - StreamTcpInitConfig(TRUE); - StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096); - StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096); - - 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)); - - 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; - } - - 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; - } - - 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; - } - - 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; - } - - 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; - } - - 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; - } - - 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 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; - } - - 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; - } - - 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; - } - - 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; - } - - if (StreamTcpCheckStreamContents(check_contents, 5, &ssn.server) == 0) { - printf("failed in stream matching: "); - goto end; - } - - if (ssn.server.seg_list_tail->seq != 16) { - printf("failed in fast track handling: "); - goto end; - } - - ret = 1; -end: - StreamTcpReassembleFreeThreadCtx(ra_ctx); - StreamTcpFreeConfig(TRUE); - return ret; -} - -static int StreamTcpReassembleTest32(void) -{ - TcpSession ssn; - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - 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); - 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->tcph->th_seq = htonl(20); - 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->tcph->th_seq = htonl(40); - 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->tcph->th_seq = htonl(5); - 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: "); - } - - -end: - StreamTcpFreeConfig(TRUE); - SCFree(p); - return ret; -} - -static int StreamTcpReassembleTest33(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, 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->payload = packet; - - p->tcph->th_seq = htonl(10); - p->tcph->th_ack = htonl(31); - p->payload_len = 10; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { - SCFree(p); - return 0; - } - - p->tcph->th_seq = htonl(20); - p->tcph->th_ack = htonl(31); - p->payload_len = 10; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { - SCFree(p); - return 0; - } - - p->tcph->th_seq = htonl(40); - p->tcph->th_ack = htonl(31); - p->payload_len = 10; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { - SCFree(p); - return 0; - } - - p->tcph->th_seq = htonl(5); - p->tcph->th_ack = htonl(31); - p->payload_len = 30; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { - SCFree(p); - return 0; - } - - StreamTcpFreeConfig(TRUE); - SCFree(p); - return 1; -} - -static int StreamTcpReassembleTest34(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, 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->payload = packet; - - 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(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; - } - - 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(857960946); - 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 56 condition */ -static int StreamTcpReassembleTest35(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(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; - - 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; - - 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; - - 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; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) == -1) { - SCFree(p); - return 0; - } - - StreamTcpFreeConfig(TRUE); - SCFree(p); - return 1; -} - -/** \test Test the bug 76 condition */ -static int StreamTcpReassembleTest37(void) -{ - TcpSession ssn; - Flow f; - TCPHdr tcph; - TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL); - TcpStream stream; - uint8_t packet[1460] = ""; - PacketQueue pq; - ThreadVars tv; - - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - - StreamTcpInitConfig(TRUE); - - /* prevent L7 from kicking in */ - StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 10); - StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 10); - - memset(&stream, 0, sizeof (TcpStream)); - memset(&pq,0,sizeof(PacketQueue)); - memset(&ssn, 0, sizeof (TcpSession)); - memset(&f, 0, sizeof (Flow)); - memset(&tcph, 0, sizeof (TCPHdr)); - 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; - stream.os_policy = OS_POLICY_BSD; - - p->tcph->th_seq = htonl(3061088537UL); - 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; - - /* pre base_seq, so should be rejected */ - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &stream, p, &pq) != -1) { - SCFree(p); - return 0; - } - - p->tcph->th_seq = htonl(3061089928UL); - 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); - return 0; - } - - p->tcph->th_seq = htonl(3061091319UL); - 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); - return 0; - } - - StreamTcpFreeConfig(TRUE); - SCFree(p); - return 1; -} - -/** - * \test Test to make sure we don't send the smsg from toclient to app layer - * 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) -{ - int ret = 0; - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - Flow f; - TCPHdr tcph; - Port sp; - Port dp; - struct in_addr in; - TcpSession ssn; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset(&f, 0, sizeof (Flow)); - memset(&tcph, 0, sizeof (TCPHdr)); - memset(&ssn, 0, sizeof(TcpSession)); - ThreadVars tv; - memset(&tv, 0, sizeof (ThreadVars)); - - StreamTcpInitConfig(TRUE); - TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL); - - uint8_t httpbuf2[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\n"; - uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */ - - uint8_t httpbuf1[] = "HTTP/1.0 200 OK\r\nServer: VictorServer/1.0\r\n\r\n"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - - FLOW_INITIALIZE(&f); - if (inet_pton(AF_INET, "1.2.3.4", &in) != 1) - goto end; - f.src.addr_data32[0] = in.s_addr; - if (inet_pton(AF_INET, "1.2.3.5", &in) != 1) - goto end; - f.dst.addr_data32[0] = in.s_addr; - sp = 200; - dp = 220; - - ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9; - ssn.server.isn = 9; - ssn.server.last_ack = 60; - ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9; - ssn.client.isn = 9; - ssn.client.last_ack = 9; - f.alproto = ALPROTO_UNKNOWN; - - 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(10); - tcph.th_ack = htonl(20); - tcph.th_flags = TH_ACK|TH_PUSH; - p->tcph = &tcph; - p->flowflags = FLOW_PKT_TOSERVER; - - p->payload = httpbuf2; - p->payload_len = httplen2; - ssn.state = TCP_ESTABLISHED; - - TcpStream *s = NULL; - s = &ssn.server; - - SCMutexLock(&f.m); - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (1): "); - goto end; - } - - /* Check if we have stream smsgs in queue */ - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) > 0) { - printf("there shouldn't be any stream smsgs in the queue (2): "); - goto end; - } - - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload = httpbuf1; - p->payload_len = httplen1; - tcph.th_seq = htonl(10); - tcph.th_ack = htonl(55); - s = &ssn.client; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (3): "); - goto end; - } - - /* Check if we have stream smsgs in queue */ - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 1) { - printf("there should one stream smsg in the queue (6): "); - goto end; - } - - ret = 1; -end: - StreamTcpReassembleFreeThreadCtx(ra_ctx); - StreamTcpFreeConfig(TRUE); - SCMutexUnlock(&f.m); - SCFree(p); - return ret; -} - -/** - * \test Test to make sure that we don't return the segments until the app - * layer proto has been detected and after that remove the processed - * segments. - * - * \retval On success it returns 1 and on failure 0. - */ - -static int StreamTcpReassembleTest39 (void) -{ - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - Flow f; - ThreadVars tv; - StreamTcpThread *stt = NULL; - TCPHdr tcph; - PacketQueue pq; - memset(&pq,0,sizeof(PacketQueue)); - memset (&f, 0, sizeof(Flow)); - memset(&tv, 0, sizeof (ThreadVars)); - StreamTcpThreadInit(&tv, NULL, (void **)&stt); - memset(&tcph, 0, sizeof (TCPHdr)); - - FLOW_INITIALIZE(&f); - f.flags = FLOW_IPV4; - f.proto = IPPROTO_TCP; - p->flow = &f; - p->tcph = &tcph; - - SCMutexLock(&f.m); - int ret = 0; - - StreamTcpInitConfig(TRUE); - - /* handshake */ - tcph.th_win = htons(5480); - tcph.th_flags = TH_SYN; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - - TcpSession *ssn = (TcpSession *)f.protoctx; - - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - 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->toserver_smsg_head != NULL || - ssn->toclient_smsg_head != NULL || - ssn->data_first_seen_dir != 0) { - printf("failure 1\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_flags = TH_SYN | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - 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->toserver_smsg_head != NULL || - ssn->toclient_smsg_head != NULL || - ssn->data_first_seen_dir != 0) { - printf("failure 2\n"); - goto end; - } - - /* handshake */ - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - 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->toserver_smsg_head != NULL || - ssn->toclient_smsg_head != NULL || - ssn->data_first_seen_dir != 0) { - printf("failure 3\n"); - goto end; - } - - /* partial request */ - uint8_t request1[] = { 0x47, 0x45, }; - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_PUSH | TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = sizeof(request1); - p->payload = request1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->client.seg_list == NULL || - ssn->client.seg_list->next != NULL || - ssn->server.seg_list != NULL || - ssn->toserver_smsg_head != NULL || - ssn->toclient_smsg_head != NULL || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 4\n"); - goto end; - } - - - /* response ack against partial request */ - p->tcph->th_ack = htonl(3); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->client.seg_list == NULL || - ssn->client.seg_list->next != NULL || - ssn->server.seg_list != NULL || - ssn->toserver_smsg_head != NULL || - ssn->toclient_smsg_head != NULL || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 5\n"); - goto end; - } - - /* complete partial request */ - uint8_t request2[] = { - 0x54, 0x20, 0x2f, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, - 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, - 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, - 0x74, 0x0d, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x2d, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x41, - 0x70, 0x61, 0x63, 0x68, 0x65, 0x42, 0x65, 0x6e, - 0x63, 0x68, 0x2f, 0x32, 0x2e, 0x33, 0x0d, 0x0a, - 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, - 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, 0x0d, 0x0a }; - p->tcph->th_ack = htonl(1); - p->tcph->th_seq = htonl(3); - p->tcph->th_flags = TH_PUSH | TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = sizeof(request2); - p->payload = request2; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_UNKNOWN || - f.alproto_ts != ALPROTO_UNKNOWN || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->client.seg_list == NULL || - ssn->client.seg_list->next == NULL || - ssn->client.seg_list->next->next != NULL || - ssn->server.seg_list != NULL || - ssn->toserver_smsg_head != NULL || - ssn->toclient_smsg_head != NULL || - ssn->data_first_seen_dir != STREAM_TOSERVER) { - printf("failure 6\n"); - goto end; - } - - /* response - request ack */ - uint8_t response[] = { - 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, - 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d, - 0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x46, - 0x72, 0x69, 0x2c, 0x20, 0x32, 0x33, 0x20, 0x53, - 0x65, 0x70, 0x20, 0x32, 0x30, 0x31, 0x31, 0x20, - 0x30, 0x36, 0x3a, 0x32, 0x39, 0x3a, 0x33, 0x39, - 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x41, 0x70, - 0x61, 0x63, 0x68, 0x65, 0x2f, 0x32, 0x2e, 0x32, - 0x2e, 0x31, 0x35, 0x20, 0x28, 0x55, 0x6e, 0x69, - 0x78, 0x29, 0x20, 0x44, 0x41, 0x56, 0x2f, 0x32, - 0x0d, 0x0a, 0x4c, 0x61, 0x73, 0x74, 0x2d, 0x4d, - 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x3a, - 0x20, 0x54, 0x68, 0x75, 0x2c, 0x20, 0x30, 0x34, - 0x20, 0x4e, 0x6f, 0x76, 0x20, 0x32, 0x30, 0x31, - 0x30, 0x20, 0x31, 0x35, 0x3a, 0x30, 0x34, 0x3a, - 0x34, 0x36, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, - 0x45, 0x54, 0x61, 0x67, 0x3a, 0x20, 0x22, 0x61, - 0x62, 0x38, 0x39, 0x36, 0x35, 0x2d, 0x32, 0x63, - 0x2d, 0x34, 0x39, 0x34, 0x33, 0x62, 0x37, 0x61, - 0x37, 0x66, 0x37, 0x66, 0x38, 0x30, 0x22, 0x0d, - 0x0a, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, - 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x3a, 0x20, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x0d, 0x0a, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, - 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x34, - 0x34, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x63, - 0x6c, 0x6f, 0x73, 0x65, 0x0d, 0x0a, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, - 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, - 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x0d, 0x0a, 0x58, - 0x2d, 0x50, 0x61, 0x64, 0x3a, 0x20, 0x61, 0x76, - 0x6f, 0x69, 0x64, 0x20, 0x62, 0x72, 0x6f, 0x77, - 0x73, 0x65, 0x72, 0x20, 0x62, 0x75, 0x67, 0x0d, - 0x0a, 0x0d, 0x0a, 0x3c, 0x68, 0x74, 0x6d, 0x6c, - 0x3e, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, - 0x68, 0x31, 0x3e, 0x49, 0x74, 0x20, 0x77, 0x6f, - 0x72, 0x6b, 0x73, 0x21, 0x3c, 0x2f, 0x68, 0x31, - 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, - 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e }; - p->tcph->th_ack = htonl(88); - p->tcph->th_seq = htonl(1); - p->tcph->th_flags = TH_PUSH | TH_ACK; - 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) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_UNKNOWN || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->client.seg_list == NULL || - ssn->client.seg_list->next == NULL || - ssn->client.seg_list->next->next != NULL || - ssn->server.seg_list == NULL || - ssn->server.seg_list->next != NULL || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 7\n"); - goto end; - } - - /* response ack from request */ - p->tcph->th_ack = htonl(328); - p->tcph->th_seq = htonl(88); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->client.seg_list == NULL || - ssn->client.seg_list->next == NULL || - ssn->client.seg_list->next->next != NULL || - ssn->server.seg_list == NULL || - ssn->server.seg_list->next != NULL || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 8\n"); - goto end; - } - - /* response - acking */ - p->tcph->th_ack = htonl(88); - p->tcph->th_seq = htonl(328); - p->tcph->th_flags = TH_PUSH | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->client.seg_list == NULL || - ssn->client.seg_list->next == NULL || - ssn->server.seg_list == NULL || - ssn->server.seg_list->next != NULL || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 9\n"); - goto end; - } - - /* response ack from request */ - p->tcph->th_ack = htonl(328); - p->tcph->th_seq = htonl(88); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->client.seg_list == NULL || - ssn->client.seg_list->next == NULL || - ssn->server.seg_list == NULL || - ssn->server.seg_list->next != NULL || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 10\n"); - goto end; - } - - /* response - acking the request again*/ - p->tcph->th_ack = htonl(88); - p->tcph->th_seq = htonl(328); - p->tcph->th_flags = TH_PUSH | TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->client.seg_list == NULL || - ssn->client.seg_list->next == NULL || - ssn->server.seg_list == NULL || - ssn->server.seg_list->next != NULL || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 11\n"); - goto end; - } - - /*** New Request ***/ - - /* partial request */ - p->tcph->th_ack = htonl(328); - p->tcph->th_seq = htonl(88); - p->tcph->th_flags = TH_PUSH | TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = sizeof(request1); - p->payload = request1; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->client.seg_list == NULL || - ssn->client.seg_list->next == NULL || - ssn->client.seg_list->next->next == NULL || - ssn->server.seg_list == NULL || - ssn->server.seg_list->next != NULL || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 12\n"); - goto end; - } - - - /* response ack against partial request */ - p->tcph->th_ack = htonl(90); - p->tcph->th_seq = htonl(328); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->client.seg_list == NULL || - ssn->client.seg_list->next == NULL || - ssn->client.seg_list->next->next == NULL || - ssn->server.seg_list == NULL || - ssn->server.seg_list->next != NULL || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 13\n"); - goto end; - } - - /* complete request */ - p->tcph->th_ack = htonl(328); - p->tcph->th_seq = htonl(90); - p->tcph->th_flags = TH_PUSH | TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = sizeof(request2); - p->payload = request2; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->client.seg_list == NULL || - ssn->client.seg_list->next == NULL || - ssn->client.seg_list->next->next == NULL || - ssn->client.seg_list->next->next->next == NULL || - ssn->server.seg_list == NULL || - ssn->server.seg_list->next != NULL || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 14\n"); - goto end; - } - - /* response ack against second partial request */ - p->tcph->th_ack = htonl(175); - p->tcph->th_seq = htonl(328); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED || - !FLOW_IS_PM_DONE(&f, STREAM_TOSERVER) || !FLOW_IS_PP_DONE(&f, STREAM_TOSERVER) || - !FLOW_IS_PM_DONE(&f, STREAM_TOCLIENT) || FLOW_IS_PP_DONE(&f, STREAM_TOCLIENT) || - ssn->client.seg_list->next == NULL || - ssn->client.seg_list->next->next == NULL || - ssn->client.seg_list->next->next->next == NULL || - ssn->server.seg_list == NULL || - ssn->server.seg_list->next != NULL || - ssn->data_first_seen_dir != APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER) { - printf("failure 15\n"); - goto end; - } - - if (ssn->toserver_smsg_head == NULL || - ssn->toserver_smsg_head->next == NULL || - ssn->toserver_smsg_head->next->next != NULL || - ssn->toclient_smsg_head == NULL || - ssn->toclient_smsg_head->next != NULL) { - printf("failure 16\n"); - goto end; - } - - StreamMsgReturnListToPool(ssn->toserver_smsg_head); - ssn->toserver_smsg_head = ssn->toserver_smsg_tail = NULL; - StreamMsgReturnListToPool(ssn->toclient_smsg_head); - ssn->toclient_smsg_head = ssn->toclient_smsg_tail = NULL; - - /* response acking a request */ - p->tcph->th_ack = htonl(175); - p->tcph->th_seq = htonl(328); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - 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; - } - - /* request acking a response */ - p->tcph->th_ack = htonl(328); - p->tcph->th_seq = htonl(175); - p->tcph->th_flags = TH_ACK; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload_len = 0; - p->payload = NULL; - if (StreamTcpPacket(&tv, p, stt, &pq) == -1) - goto end; - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->server) || - !StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn->client) || - f.alproto != ALPROTO_HTTP || - f.alproto_ts != ALPROTO_HTTP || - f.alproto_tc != ALPROTO_HTTP || - f.data_al_so_far[0] != 0 || - f.data_al_so_far[1] != 0 || - 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"); - goto end; - } - - - ret = 1; -end: - StreamTcpThreadDeinit(&tv, (void *)stt); - StreamTcpSessionClear(p->flow->protoctx); - StreamTcpFreeConfig(TRUE); - SCFree(p); - SCMutexUnlock(&f.m); - return ret; -} - -/** - * \test Test to make sure that we sent all the segments from the initial - * segments to app layer until we have detected the app layer proto. - * - * \retval On success it returns 1 and on failure 0. - */ - -static int StreamTcpReassembleTest40 (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)); - - StreamTcpInitConfig(TRUE); - StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 130); - - TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL); - - uint8_t httpbuf1[] = "P"; - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - uint8_t httpbuf3[] = "O"; - uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */ - uint8_t httpbuf4[] = "S"; - uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */ - uint8_t httpbuf5[] = "T \r\n"; - uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */ - - 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; - ssn.server.last_ack = 10; - ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 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) - 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(10); - tcph.th_flags = TH_ACK|TH_PUSH; - p->tcph = &tcph; - p->flowflags = FLOW_PKT_TOSERVER; - - p->payload = httpbuf1; - p->payload_len = httplen1; - ssn.state = TCP_ESTABLISHED; - - TcpStream *s = NULL; - s = &ssn.client; - - SCMutexLock(&f->m); - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (1): "); - goto end; - } - - /* Check if we have stream smsgs in queue */ - if (UtSsnSmsgCnt(&ssn, STREAM_TOCLIENT) > 0) { - printf("there shouldn't be any stream smsgs in the queue, as we didn't" - " processed any smsg from toserver side till yet (2): "); - goto end; - } - - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload = httpbuf2; - p->payload_len = httplen2; - tcph.th_seq = htonl(10); - tcph.th_ack = htonl(11); - s = &ssn.server; - ssn.server.last_ack = 11; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (3): "); - goto end; - } - - p->flowflags = FLOW_PKT_TOSERVER; - p->payload = httpbuf3; - p->payload_len = httplen3; - tcph.th_seq = htonl(11); - tcph.th_ack = htonl(55); - s = &ssn.client; - ssn.client.last_ack = 55; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (5): "); - goto end; - } - - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload = httpbuf2; - p->payload_len = httplen2; - tcph.th_seq = htonl(55); - tcph.th_ack = htonl(12); - s = &ssn.server; - ssn.server.last_ack = 12; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (6): "); - goto end; - } - - /* 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)) - { - printf("the list is NULL or the processed segment has not been flaged (7): "); - goto end; - } - - p->flowflags = FLOW_PKT_TOSERVER; - p->payload = httpbuf4; - p->payload_len = httplen4; - tcph.th_seq = htonl(12); - tcph.th_ack = htonl(100); - s = &ssn.client; - ssn.client.last_ack = 100; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (10): "); - goto end; - } - - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload = httpbuf2; - p->payload_len = httplen2; - tcph.th_seq = htonl(100); - tcph.th_ack = htonl(13); - s = &ssn.server; - ssn.server.last_ack = 13; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (11): "); - goto end; - } - - p->flowflags = FLOW_PKT_TOSERVER; - p->payload = httpbuf5; - p->payload_len = httplen5; - tcph.th_seq = htonl(13); - tcph.th_ack = htonl(145); - s = &ssn.client; - ssn.client.last_ack = 145; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (14): "); - goto end; - } - - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload = httpbuf2; - p->payload_len = httplen2; - tcph.th_seq = htonl(145); - tcph.th_ack = htonl(16); - s = &ssn.server; - ssn.server.last_ack = 16; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (15): "); - goto end; - } - - /* Check if we have stream smsgs in queue */ - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) == 0) { - printf("there should be a stream smsgs in the queue, as we have detected" - " the app layer protocol and one smsg from toserver side has " - "been sent (16): "); - goto end; - } - - if (f->alproto != ALPROTO_HTTP) { - printf("app layer proto has not been detected (18): "); - goto end; - } - - ret = 1; -end: - StreamTcpReassembleFreeThreadCtx(ra_ctx); - StreamTcpFreeConfig(TRUE); - SCFree(p); - SCMutexUnlock(&f->m); - UTHFreeFlow(f); - return ret; -} - -/** - * \retval On success it returns 1 and on failure 0. - */ - -static int StreamTcpReassembleTest43 (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)); - - StreamTcpInitConfig(TRUE); - TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL); - - uint8_t httpbuf1[] = "/ HTTP/1.0\r\nUser-Agent: Victor/1.0"; - - uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */ - - 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 */ - - uint8_t httpbuf3[] = "W2dyb3VwMV0NCnBob25lMT1wMDB3ODgyMTMxMzAyMTINCmxvZ2lu" - "MT0NCnBhc3N3b3JkMT0NCnBob25lMj1wMDB3ODgyMTMxMzAyMTIN" - "CmxvZ2luMj0NCnBhc3N3b3JkMj0NCnBob25lMz0NCmxvZ2luMz0N" - "CnBhc3N3b3JkMz0NCnBob25lND0NCmxvZ2luND0NCnBhc3N3b3Jk" - "ND0NCnBob25lNT0NCmxvZ2luNT0NCnBhc3N3b3JkNT0NCnBob25l" - "Nj0NCmxvZ2luNj0NCnBhc3N3b3JkNj0NCmNhbGxfdGltZTE9MzIN" - "CmNhbGxfdGltZTI9MjMyDQpkYXlfbGltaXQ9NQ0KbW9udGhfbGlt" - "aXQ9MTUNCltncm91cDJdDQpwaG9uZTE9DQpsb2dpbjE9DQpwYXNz" - "d29yZDE9DQpwaG9uZTI9DQpsb2dpbjI9DQpwYXNzd29yZDI9DQpw" - "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.isn = 9; - ssn.server.last_ack = 600; - ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9; - ssn.client.isn = 9; - ssn.client.last_ack = 600; - - 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(10); - tcph.th_flags = TH_ACK|TH_PUSH; - p->tcph = &tcph; - p->flowflags = FLOW_PKT_TOCLIENT; - - p->payload = httpbuf2; - p->payload_len = httplen2; - ssn.state = TCP_ESTABLISHED; - - TcpStream *s = NULL; - s = &ssn.server; - - SCMutexLock(&f->m); - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (1): "); - goto end; - } - - /* Check if we have stream smsgs in queue */ - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) > 0) { - printf("there shouldn't be any stream smsgs in the queue (2): "); - goto end; - } - - p->flowflags = FLOW_PKT_TOSERVER; - p->payload = httpbuf1; - p->payload_len = httplen1; - tcph.th_seq = htonl(10); - tcph.th_ack = htonl(55); - s = &ssn.client; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (3): "); - goto end; - } - - /* Check if we have stream smsgs in queue */ - if (UtSsnSmsgCnt(&ssn, STREAM_TOCLIENT) > 0) { - printf("there shouldn't be any stream smsgs in the queue, as we didn't" - " processed any smsg from toserver side till yet (4): "); - goto end; - } - - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload = httpbuf2; - p->payload_len = httplen2; - tcph.th_seq = htonl(55); - tcph.th_ack = htonl(44); - s = &ssn.server; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (5): "); - goto end; - } - if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(&ssn.client)) { - printf("app layer detected flag isn't set, it should be (8): "); - goto end; - } - - /* This packets induces a packet gap and also shows why we need to - process the current segment completely, even if it results in sending more - than one smsg to the app layer. If we don't send more than one smsg in - this case, then the first segment of lentgh 34 bytes will be sent to - app layer and protocol can not be detected in that message and moreover - the segment lentgh is less than the max. signature size for protocol - detection, so this will keep looping !! */ - p->flowflags = FLOW_PKT_TOSERVER; - p->payload = httpbuf3; - p->payload_len = httplen3; - tcph.th_seq = htonl(54); - tcph.th_ack = htonl(100); - s = &ssn.client; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet (9): "); - goto end; - } - - /* Check if we have stream smsgs in queue */ - if (UtSsnSmsgCnt(&ssn, STREAM_TOCLIENT) > 0) { - printf("there shouldn't be any stream smsgs in the queue, as we didn't" - " detected the app layer protocol till yet (10): "); - 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); - SCMutexUnlock(&f->m); - 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 */ - stream_config.reassembly_depth = httplen1 + 1; - - TcpStream *s = NULL; - s = &ssn.server; - - SCMutexLock(&f->m); - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toclient packet: "); - 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: "); - 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; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet: "); - 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: "); - 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 (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet: "); - 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); - goto end; - } - - ret = 1; -end: - StreamTcpReassembleFreeThreadCtx(ra_ctx); - StreamTcpFreeConfig(TRUE); - SCFree(p); - SCMutexUnlock(&f->m); - 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 - * - * \retval On success it returns 1 and on failure 0. - */ - -static int StreamTcpReassembleTest46 (void) -{ - int ret = 0; - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - Flow *f = NULL; - TCPHdr tcph; - 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); - - 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; - - 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; - - stream_config.reassembly_depth = 0; - - TcpStream *s = NULL; - s = &ssn.server; - - SCMutexLock(&f->m); - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toclient packet\n"); - 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"); - 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; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver packet\n"); - 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"); - 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"); - 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); - goto end; - } - - ret = 1; -end: - StreamTcpReassembleFreeThreadCtx(ra_ctx); - StreamTcpFreeConfig(TRUE); - SCFree(p); - SCMutexUnlock(&f->m); - UTHFreeFlow(f); - return ret; -} - -/** - * \test Test to make sure we detect the sequence wrap around and continue - * stream reassembly properly. - * - * \retval On success it returns 1 and on failure 0. - */ - -static int StreamTcpReassembleTest47 (void) -{ - int ret = 0; - Packet *p = PacketGetFromAlloc(); - if (unlikely(p == NULL)) - return 0; - Flow *f = NULL; - TCPHdr tcph; - 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)); - - /* prevent L7 from kicking in */ - StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 0); - StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 0); - - StreamTcpInitConfig(TRUE); - TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL); - - 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; - ssn.server.last_ack = 572799782UL; - ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 4294967289UL; - ssn.client.isn = 4294967289UL; - ssn.client.last_ack = 21; - - 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); - ssn.state = TCP_ESTABLISHED; - TcpStream *s = NULL; - uint8_t cnt = 0; - - SCMutexLock(&f->m); - for (cnt=0; cnt < httplen1; cnt++) { - tcph.th_seq = htonl(ssn.client.isn + 1 + cnt); - tcph.th_ack = htonl(572799782UL); - tcph.th_flags = TH_ACK|TH_PUSH; - p->tcph = &tcph; - p->flowflags = FLOW_PKT_TOSERVER; - p->payload = &httpbuf1[cnt]; - p->payload_len = 1; - s = &ssn.client; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver " - "packet\n"); - goto end; - } - - p->flowflags = FLOW_PKT_TOCLIENT; - p->payload = NULL; - p->payload_len = 0; - tcph.th_seq = htonl(572799782UL); - tcph.th_ack = htonl(ssn.client.isn + 1 + cnt); - tcph.th_flags = TH_ACK; - p->tcph = &tcph; - s = &ssn.server; - - if (StreamTcpReassembleHandleSegment(&tv, ra_ctx, &ssn, s, p, &pq) == -1) { - printf("failed in segments reassembly, while processing toserver " - "packet\n"); - goto end; - } - } - - if (f->alproto != ALPROTO_HTTP) { - printf("App layer protocol (HTTP) should have been detected\n"); - goto end; - } - - ret = 1; -end: - StreamTcpReassembleFreeThreadCtx(ra_ctx); - StreamTcpFreeConfig(TRUE); - SCFree(p); - SCMutexUnlock(&f->m); - UTHFreeFlow(f); - return ret; -} - -/** \test 3 in order segments in inline reassembly */ -static int StreamTcpReassembleInlineTest01(void) -{ - int ret = 0; - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow f; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.client, 1); - FLOW_INITIALIZE(&f); - - uint8_t stream_payload[] = "AAAAABBBBBCCCCC"; - 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; - } - p->tcph->th_seq = htonl(12); - p->flow = &f; - - SCMutexLock(&f.m); - 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; - } - 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; - } - - StreamMsg *smsg = ssn.toserver_smsg_head; - if (UtTestSmsg(smsg, stream_payload, 15) == 0) - goto end; - - ret = 1; -end: - SCMutexUnlock(&f.m); - FLOW_DESTROY(&f); - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - return ret; -} - -/** \test 3 in order segments, then reassemble, add one more and reassemble again. - * test the sliding window reassembly. - */ -static int StreamTcpReassembleInlineTest02(void) -{ - int ret = 0; - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow f; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.client, 1); - FLOW_INITIALIZE(&f); - - uint8_t stream_payload1[] = "AAAAABBBBBCCCCC"; - uint8_t stream_payload2[] = "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; - } - p->tcph->th_seq = htonl(12); - p->flow = &f; - - SCMutexLock(&f.m); - 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; - } - 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; - } - - StreamMsg *smsg = ssn.toserver_smsg_head; - if (UtTestSmsg(smsg, stream_payload1, 15) == 0) - goto end; - - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { - printf("failed to add segment 4: "); - goto end; - } - ssn.client.next_seq = 22; - - r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); - if (r < 0) { - printf("StreamTcpReassembleInlineRaw failed 2: "); - goto end; - } - - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 2) { - printf("expected a single stream message: "); - goto end; - } - - smsg = ssn.toserver_smsg_head->next; - if (UtTestSmsg(smsg, stream_payload2, 20) == 0) - goto end; - - ret = 1; -end: - SCMutexUnlock(&f.m); - FLOW_DESTROY(&f); - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - return ret; -} - -/** \test 3 in order segments, then reassemble, add one more and reassemble again. - * test the sliding window reassembly with a small window size so that we - * cutting off at the start (left edge) - */ -static int StreamTcpReassembleInlineTest03(void) -{ - int ret = 0; - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow f; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.client, 1); - FLOW_INITIALIZE(&f); - - stream_config.reassembly_toserver_chunk_size = 15; - - 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; - } - p->tcph->th_seq = htonl(12); - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - - SCMutexLock(&f.m); - 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; - } - 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 1: "); - goto end; - } - - StreamMsg *smsg = ssn.toserver_smsg_head; - if (UtTestSmsg(smsg, stream_payload1, 15) == 0) - goto end; - - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { - printf("failed to add segment 4: "); - goto end; - } - 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; - } - - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 2) { - printf("expected two stream messages: "); - goto end; - } - - smsg = ssn.toserver_smsg_head->next; - if (UtTestSmsg(smsg, stream_payload2, 15) == 0) - goto end; - - ret = 1; -end: - SCMutexUnlock(&f.m); - FLOW_DESTROY(&f); - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - return ret; -} - -/** \test 3 in order segments, then reassemble, add one more and reassemble again. - * test the sliding window reassembly with a small window size so that we - * cutting off at the start (left edge) with small packet overlap. - */ -static int StreamTcpReassembleInlineTest04(void) -{ - int ret = 0; - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow f; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.client, 1); - FLOW_INITIALIZE(&f); - - stream_config.reassembly_toserver_chunk_size = 16; - - uint8_t stream_payload1[] = "AAAAABBBBBCCCCC"; - uint8_t stream_payload2[] = "ABBBBBCCCCCDDDDD"; - 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; - } - p->tcph->th_seq = htonl(12); - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - - SCMutexLock(&f.m); - 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; - } - 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; - } - - StreamMsg *smsg = ssn.toserver_smsg_head; - if (UtTestSmsg(smsg, stream_payload1, 15) == 0) - goto end; - - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { - printf("failed to add segment 4: "); - goto end; - } - 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; - } - - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 2) { - printf("expected a single stream message: "); - goto end; - } - - smsg = ssn.toserver_smsg_head->next; - if (UtTestSmsg(smsg, stream_payload2, 16) == 0) - goto end; - - ret = 1; -end: - SCMutexUnlock(&f.m); - FLOW_DESTROY(&f); - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - return ret; -} - -/** \test with a GAP we should have 2 smsgs */ -static int StreamTcpReassembleInlineTest05(void) -{ - int ret = 0; - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow f; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.client, 1); - FLOW_INITIALIZE(&f); - - uint8_t stream_payload1[] = "AAAAABBBBB"; - uint8_t stream_payload2[] = "DDDDD"; - 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; - } - p->tcph->th_seq = htonl(12); - p->flow = &f; - - SCMutexLock(&f.m); - 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; - } - ssn.client.next_seq = 12; - - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { - printf("failed to add segment 4: "); - goto end; - } - - p->tcph->th_seq = htonl(17); - - int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); - if (r < 0) { - printf("StreamTcpReassembleInlineRaw failed: "); - goto end; - } - - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 2) { - printf("expected a single stream message: "); - goto end; - } - - StreamMsg *smsg = ssn.toserver_smsg_head; - if (UtTestSmsg(smsg, stream_payload1, 10) == 0) - goto end; - - smsg = ssn.toserver_smsg_head->next; - if (UtTestSmsg(smsg, stream_payload2, 5) == 0) - goto end; - - ret = 1; -end: - SCMutexUnlock(&f.m); - FLOW_DESTROY(&f); - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - return ret; -} - -/** \test with a GAP we should have 2 smsgs, with filling the GAP later */ -static int StreamTcpReassembleInlineTest06(void) -{ - int ret = 0; - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow f; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.client, 1); - FLOW_INITIALIZE(&f); - - uint8_t stream_payload1[] = "AAAAABBBBB"; - uint8_t stream_payload2[] = "DDDDD"; - uint8_t stream_payload3[] = "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; - } - p->tcph->th_seq = htonl(12); - p->flow = &f; - - SCMutexLock(&f.m); - 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; - } - ssn.client.next_seq = 12; - - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { - printf("failed to add segment 4: "); - goto end; - } - - p->tcph->th_seq = htonl(17); - - int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); - if (r < 0) { - printf("StreamTcpReassembleInlineRaw failed: "); - goto end; - } - - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 2) { - printf("expected two stream messages: "); - goto end; - } - - StreamMsg *smsg = ssn.toserver_smsg_head; - if (UtTestSmsg(smsg, stream_payload1, 10) == 0) - goto end; - - smsg = ssn.toserver_smsg_head->next; - if (UtTestSmsg(smsg, stream_payload2, 5) == 0) - goto end; - - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { - printf("failed to add segment 3: "); - goto end; - } - ssn.client.next_seq = 22; - - p->tcph->th_seq = htonl(12); - - r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); - if (r < 0) { - printf("StreamTcpReassembleInlineRaw failed: "); - goto end; - } - - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 3) { - printf("expected a single stream message, got %u: ", UtSsnSmsgCnt(&ssn, STREAM_TOSERVER)); - goto end; - } - - smsg = ssn.toserver_smsg_head->next->next; - if (UtTestSmsg(smsg, stream_payload3, 20) == 0) - goto end; - - ret = 1; -end: - SCMutexUnlock(&f.m); - FLOW_DESTROY(&f); - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - return ret; -} - -/** \test with a GAP we should have 2 smsgs, with filling the GAP later, small - * window */ -static int StreamTcpReassembleInlineTest07(void) -{ - int ret = 0; - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow f; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.client, 1); - FLOW_INITIALIZE(&f); - - stream_config.reassembly_toserver_chunk_size = 16; - - uint8_t stream_payload1[] = "ABBBBB"; - uint8_t stream_payload2[] = "DDDDD"; - uint8_t stream_payload3[] = "AAAAABBBBBCCCCCD"; - 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; - } - p->tcph->th_seq = htonl(12); - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - - SCMutexLock(&f.m); - 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; - } - ssn.client.next_seq = 12; - - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { - printf("failed to add segment 4: "); - goto end; - } - - p->tcph->th_seq = htonl(17); - - int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); - if (r < 0) { - printf("StreamTcpReassembleInlineRaw failed: "); - goto end; - } - - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 2) { - printf("expected a single stream message, got %u: ", UtSsnSmsgCnt(&ssn, STREAM_TOSERVER)); - goto end; - } - - StreamMsg *smsg = ssn.toserver_smsg_head; - if (UtTestSmsg(smsg, stream_payload1, 6) == 0) - goto end; - - smsg = ssn.toserver_smsg_head->next; - if (UtTestSmsg(smsg, stream_payload2, 5) == 0) - goto end; - - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { - printf("failed to add segment 3: "); - goto end; - } - ssn.client.next_seq = 22; - - p->tcph->th_seq = htonl(12); - - r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); - if (r < 0) { - printf("StreamTcpReassembleInlineRaw failed: "); - goto end; - } - - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 3) { - printf("expected a single stream message, got %u: ", UtSsnSmsgCnt(&ssn, STREAM_TOSERVER)); - goto end; - } - - smsg = ssn.toserver_smsg_head->next->next; - if (UtTestSmsg(smsg, stream_payload3, 16) == 0) - goto end; - - ret = 1; -end: - SCMutexUnlock(&f.m); - FLOW_DESTROY(&f); - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - return ret; -} - -/** \test 3 in order segments, then reassemble, add one more and reassemble again. - * test the sliding window reassembly with a small window size so that we - * cutting off at the start (left edge). Test if the first segment is - * removed from the list. - */ -static int StreamTcpReassembleInlineTest08(void) -{ - int ret = 0; - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow f; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.client, 1); - FLOW_INITIALIZE(&f); - - stream_config.reassembly_toserver_chunk_size = 15; - ssn.client.flags |= STREAMTCP_STREAM_FLAG_GAP; - - 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; - } - p->tcph->th_seq = htonl(12); - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - - SCMutexLock(&f.m); - 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; - } - 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; - } - - 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; - } - - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) { - printf("failed to add segment 4: "); - goto end; - } - 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; - } - - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 2) { - printf("expected a single stream message, got %u: ", UtSsnSmsgCnt(&ssn, STREAM_TOSERVER)); - goto end; - } - - smsg = ssn.toserver_smsg_head->next; - if (UtTestSmsg(smsg, stream_payload2, 15) == 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); - goto end; - } - - 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; - } - - ret = 1; -end: - SCMutexUnlock(&f.m); - FLOW_DESTROY(&f); - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - return ret; -} - -/** \test 3 in order segments, then reassemble, add one more and reassemble again. - * test the sliding window reassembly with a small window size so that we - * cutting off at the start (left edge). Test if the first segment is - * removed from the list. - */ -static int StreamTcpReassembleInlineTest09(void) -{ - int ret = 0; - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow f; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.client, 1); - FLOW_INITIALIZE(&f); - - stream_config.reassembly_toserver_chunk_size = 20; - ssn.client.flags |= STREAMTCP_STREAM_FLAG_GAP; - - uint8_t stream_payload1[] = "AAAAABBBBBCCCCC"; - uint8_t stream_payload2[] = "DDDDD"; - uint8_t stream_payload3[] = "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; - } - p->tcph->th_seq = htonl(17); - p->flow = &f; - p->flowflags |= FLOW_PKT_TOSERVER; - - SCMutexLock(&f.m); - 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, 17, 'D', 5) == -1) { - printf("failed to add segment 3: "); - goto end; - } - ssn.client.next_seq = 12; - - int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); - if (r < 0) { - printf("StreamTcpReassembleInlineRaw failed: "); - goto end; - } - - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 2) { - printf("expected 2 stream message2, got %u: ", UtSsnSmsgCnt(&ssn, STREAM_TOSERVER)); - goto end; - } - - StreamMsg *smsg = ssn.toserver_smsg_head; - if (UtTestSmsg(smsg, stream_payload1, 10) == 0) - goto end; - - smsg = ssn.toserver_smsg_head->next; - 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); - goto end; - } - - /* close the GAP and see if we properly reassemble and update ra_base_seq */ - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { - printf("failed to add segment 4: "); - goto end; - } - ssn.client.next_seq = 22; - - p->tcph->th_seq = htonl(12); - - r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); - if (r < 0) { - printf("StreamTcpReassembleInlineRaw failed 2: "); - goto end; - } - - if (UtSsnSmsgCnt(&ssn, STREAM_TOSERVER) != 3) { - printf("expected 3 stream messages: "); - goto end; - } - - smsg = ssn.toserver_smsg_head->next->next; - 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); - goto end; - } - - if (ssn.client.seg_list->seq != 2) { - printf("expected segment 1 (seq 2) to be first in the list, got seq %"PRIu32": ", ssn.client.seg_list->seq); - goto end; - } - - ret = 1; -end: - SCMutexUnlock(&f.m); - FLOW_DESTROY(&f); - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - return ret; -} - -/** \test App Layer reassembly. - */ -static int StreamTcpReassembleInlineTest10(void) -{ - int ret = 0; - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow *f = NULL; - Packet *p = NULL; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTInitInline(); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.server, 1); - ssn.server.last_ack = 2; - StreamTcpUTSetupStream(&ssn.client, 1); - ssn.client.last_ack = 2; - - f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80); - if (f == NULL) - goto end; - f->protoctx = &ssn; - f->proto = IPPROTO_TCP; - - uint8_t stream_payload1[] = "GE"; - uint8_t stream_payload2[] = "T /"; - uint8_t stream_payload3[] = "HTTP/1.0\r\n\r\n"; - - p = UTHBuildPacketReal(stream_payload3, 12, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); - if (p == NULL) { - printf("couldn't get a packet: "); - goto end; - } - p->tcph->th_seq = htonl(7); - p->flow = f; - p->flowflags |= FLOW_PKT_TOSERVER; - - SCMutexLock(&f->m); - if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, 2, stream_payload1, 2) == -1) { - printf("failed to add segment 1: "); - goto end; - } - ssn.server.next_seq = 4; - - int r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p); - if (r < 0) { - printf("StreamTcpReassembleAppLayer failed: "); - 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); - goto end; - } - - if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, 4, stream_payload2, 3) == -1) { - printf("failed to add segment 2: "); - goto end; - } - if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, 7, stream_payload3, 12) == -1) { - printf("failed to add segment 3: "); - goto end; - } - ssn.server.next_seq = 19; - - r = StreamTcpReassembleAppLayer(&tv, ra_ctx, &ssn, &ssn.server, p); - if (r < 0) { - printf("StreamTcpReassembleAppLayer failed: "); - 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); - goto end; - } - - ret = 1; -end: - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - SCMutexUnlock(&f->m); - UTHFreeFlow(f); - return ret; -} - -/** \test test insert with overlap - */ -static int StreamTcpReassembleInsertTest01(void) -{ - int ret = 0; - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - Flow f; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.client, 1); - 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; - } - p->tcph->th_seq = htonl(12); - p->flow = &f; - - SCMutexLock(&f.m); - 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; - } - 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; - } - - StreamMsg *smsg = ssn.toserver_smsg_head; - if (UtTestSmsg(smsg, stream_payload1, 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); - goto end; - } - ret = 1; -end: - SCMutexUnlock(&f.m); - FLOW_DESTROY(&f); - UTHFreePacket(p); - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - return ret; -} - -/** \test test insert with overlaps - */ -static int StreamTcpReassembleInsertTest02(void) -{ - int ret = 0; - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.client, 1); - - int i; - for (i = 2; i < 10; i++) { - int len; - len = i % 2; - if (len == 0) - len = 1; - int seq; - seq = i * 10; - if (seq < 2) - seq = 2; - - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'A', len) == -1) { - printf("failed to add segment 1: "); - goto end; - } - } - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'B', 1024) == -1) { - printf("failed to add segment 2: "); - goto end; - } - - ret = 1; -end: - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - return ret; -} - -/** \test test insert with overlaps - */ -static int StreamTcpReassembleInsertTest03(void) -{ - int ret = 0; - TcpReassemblyThreadCtx *ra_ctx = NULL; - ThreadVars tv; - TcpSession ssn; - - memset(&tv, 0x00, sizeof(tv)); - - StreamTcpUTInit(&ra_ctx); - StreamTcpUTSetupSession(&ssn); - StreamTcpUTSetupStream(&ssn.client, 1); - - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 1024) == -1) { - printf("failed to add segment 2: "); - goto end; - } - - int i; - for (i = 2; i < 10; i++) { - int len; - len = i % 2; - if (len == 0) - len = 1; - int seq; - seq = i * 10; - if (seq < 2) - seq = 2; - - if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, seq, 'B', len) == -1) { - printf("failed to add segment 2: "); - goto end; - } - } - ret = 1; -end: - StreamTcpUTClearSession(&ssn); - StreamTcpUTDeinit(ra_ctx); - return ret; -} - -#endif /* UNITTESTS */ - -/** \brief The Function Register the Unit tests to test the reassembly engine - * for various OS policies. - */ - -void StreamTcpReassembleRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("StreamTcpReassembleTest01 -- BSD OS Before Reassembly Test", StreamTcpReassembleTest01, 1); - UtRegisterTest("StreamTcpReassembleTest02 -- BSD OS At Same Reassembly Test", StreamTcpReassembleTest02, 1); - UtRegisterTest("StreamTcpReassembleTest03 -- BSD OS After Reassembly Test", StreamTcpReassembleTest03, 1); - UtRegisterTest("StreamTcpReassembleTest04 -- BSD OS Complete Reassembly Test", StreamTcpReassembleTest04, 1); - UtRegisterTest("StreamTcpReassembleTest05 -- VISTA OS Before Reassembly Test", StreamTcpReassembleTest05, 1); - UtRegisterTest("StreamTcpReassembleTest06 -- VISTA OS At Same Reassembly Test", StreamTcpReassembleTest06, 1); - UtRegisterTest("StreamTcpReassembleTest07 -- VISTA OS After Reassembly Test", StreamTcpReassembleTest07, 1); - UtRegisterTest("StreamTcpReassembleTest08 -- VISTA OS Complete Reassembly Test", StreamTcpReassembleTest08, 1); - UtRegisterTest("StreamTcpReassembleTest09 -- LINUX OS Before Reassembly Test", StreamTcpReassembleTest09, 1); - UtRegisterTest("StreamTcpReassembleTest10 -- LINUX OS At Same Reassembly Test", StreamTcpReassembleTest10, 1); - UtRegisterTest("StreamTcpReassembleTest11 -- LINUX OS After Reassembly Test", StreamTcpReassembleTest11, 1); - UtRegisterTest("StreamTcpReassembleTest12 -- LINUX OS Complete Reassembly Test", StreamTcpReassembleTest12, 1); - UtRegisterTest("StreamTcpReassembleTest13 -- LINUX_OLD OS Before Reassembly Test", StreamTcpReassembleTest13, 1); - UtRegisterTest("StreamTcpReassembleTest14 -- LINUX_OLD At Same Reassembly Test", StreamTcpReassembleTest14, 1); - UtRegisterTest("StreamTcpReassembleTest15 -- LINUX_OLD OS After Reassembly Test", StreamTcpReassembleTest15, 1); - UtRegisterTest("StreamTcpReassembleTest16 -- LINUX_OLD OS Complete Reassembly Test", StreamTcpReassembleTest16, 1); - UtRegisterTest("StreamTcpReassembleTest17 -- SOLARIS OS Before Reassembly Test", StreamTcpReassembleTest17, 1); - UtRegisterTest("StreamTcpReassembleTest18 -- SOLARIS At Same Reassembly Test", StreamTcpReassembleTest18, 1); - UtRegisterTest("StreamTcpReassembleTest19 -- SOLARIS OS After Reassembly Test", StreamTcpReassembleTest19, 1); - UtRegisterTest("StreamTcpReassembleTest20 -- SOLARIS OS Complete Reassembly Test", StreamTcpReassembleTest20, 1); - UtRegisterTest("StreamTcpReassembleTest21 -- LAST OS Before Reassembly Test", StreamTcpReassembleTest21, 1); - UtRegisterTest("StreamTcpReassembleTest22 -- LAST OS At Same Reassembly Test", StreamTcpReassembleTest22, 1); - UtRegisterTest("StreamTcpReassembleTest23 -- LAST OS After Reassembly Test", StreamTcpReassembleTest23, 1); - UtRegisterTest("StreamTcpReassembleTest24 -- LAST OS Complete Reassembly Test", StreamTcpReassembleTest24, 1); - UtRegisterTest("StreamTcpReassembleTest25 -- Gap at Start Reassembly Test", StreamTcpReassembleTest25, 1); - UtRegisterTest("StreamTcpReassembleTest26 -- Gap at middle Reassembly Test", StreamTcpReassembleTest26, 1); - UtRegisterTest("StreamTcpReassembleTest27 -- Gap at after Reassembly Test", StreamTcpReassembleTest27, 1); - UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test", StreamTcpReassembleTest28, 1); - UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test", StreamTcpReassembleTest29, 1); - UtRegisterTest("StreamTcpReassembleTest30 -- Gap at End IDS missed packet Reassembly Test", StreamTcpReassembleTest30, 1); - UtRegisterTest("StreamTcpReassembleTest31 -- Fast Track Reassembly Test", StreamTcpReassembleTest31, 1); - UtRegisterTest("StreamTcpReassembleTest32 -- Bug test", StreamTcpReassembleTest32, 1); - UtRegisterTest("StreamTcpReassembleTest33 -- Bug test", StreamTcpReassembleTest33, 1); - UtRegisterTest("StreamTcpReassembleTest34 -- Bug test", StreamTcpReassembleTest34, 1); - UtRegisterTest("StreamTcpReassembleTest35 -- Bug56 test", StreamTcpReassembleTest35, 1); - UtRegisterTest("StreamTcpReassembleTest36 -- Bug57 test", StreamTcpReassembleTest36, 1); - UtRegisterTest("StreamTcpReassembleTest37 -- Bug76 test", StreamTcpReassembleTest37, 1); - UtRegisterTest("StreamTcpReassembleTest38 -- app proto test", StreamTcpReassembleTest38, 1); - UtRegisterTest("StreamTcpReassembleTest39 -- app proto test", StreamTcpReassembleTest39, 1); - UtRegisterTest("StreamTcpReassembleTest40 -- app proto test", StreamTcpReassembleTest40, 1); - UtRegisterTest("StreamTcpReassembleTest43 -- min smsg size test", StreamTcpReassembleTest43, 1); - UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test", StreamTcpReassembleTest44, 1); - UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test", StreamTcpReassembleTest45, 1); - UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test", StreamTcpReassembleTest46, 1); - UtRegisterTest("StreamTcpReassembleTest47 -- TCP Sequence Wraparound Test", StreamTcpReassembleTest47, 1); - - UtRegisterTest("StreamTcpReassembleInlineTest01 -- inline RAW ra", StreamTcpReassembleInlineTest01, 1); - UtRegisterTest("StreamTcpReassembleInlineTest02 -- inline RAW ra 2", StreamTcpReassembleInlineTest02, 1); - UtRegisterTest("StreamTcpReassembleInlineTest03 -- inline RAW ra 3", StreamTcpReassembleInlineTest03, 1); - UtRegisterTest("StreamTcpReassembleInlineTest04 -- inline RAW ra 4", StreamTcpReassembleInlineTest04, 1); - UtRegisterTest("StreamTcpReassembleInlineTest05 -- inline RAW ra 5 GAP", StreamTcpReassembleInlineTest05, 1); - UtRegisterTest("StreamTcpReassembleInlineTest06 -- inline RAW ra 6 GAP", StreamTcpReassembleInlineTest06, 1); - UtRegisterTest("StreamTcpReassembleInlineTest07 -- inline RAW ra 7 GAP", StreamTcpReassembleInlineTest07, 1); - UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup", StreamTcpReassembleInlineTest08, 1); - UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup", StreamTcpReassembleInlineTest09, 1); - - UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10", StreamTcpReassembleInlineTest10, 1); - - UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap", StreamTcpReassembleInsertTest01, 1); - UtRegisterTest("StreamTcpReassembleInsertTest02 -- insert with overlap", StreamTcpReassembleInsertTest02, 1); - UtRegisterTest("StreamTcpReassembleInsertTest03 -- insert with overlap", StreamTcpReassembleInsertTest03, 1); - - StreamTcpInlineRegisterTests(); - StreamTcpUtilRegisterTests(); -#endif /* UNITTESTS */ -} |