aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/stream-tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src/stream-tcp.c')
-rw-r--r--framework/src/suricata/src/stream-tcp.c10820
1 files changed, 0 insertions, 10820 deletions
diff --git a/framework/src/suricata/src/stream-tcp.c b/framework/src/suricata/src/stream-tcp.c
deleted file mode 100644
index 9dce7070..00000000
--- a/framework/src/suricata/src/stream-tcp.c
+++ /dev/null
@@ -1,10820 +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 Victor Julien <victor@inliniac.net>
- * \author Gurvinder Singh <gurvindersinghdahiya@gmail.com>
- *
- * TCP stream tracking and reassembly engine.
- *
- * \todo - 4WHS: what if after the 2nd SYN we turn out to be normal 3WHS anyway?
- */
-
-#include "suricata-common.h"
-#include "suricata.h"
-
-#include "decode.h"
-#include "debug.h"
-#include "detect.h"
-
-#include "flow.h"
-#include "flow-util.h"
-
-#include "conf.h"
-#include "conf-yaml-loader.h"
-
-#include "threads.h"
-#include "threadvars.h"
-#include "tm-threads.h"
-
-#include "util-pool.h"
-#include "util-pool-thread.h"
-#include "util-checksum.h"
-#include "util-unittest.h"
-#include "util-print.h"
-#include "util-debug.h"
-#include "util-device.h"
-
-#include "stream-tcp-private.h"
-#include "stream-tcp-reassemble.h"
-#include "stream-tcp.h"
-#include "stream-tcp-inline.h"
-#include "stream-tcp-sack.h"
-#include "stream-tcp-util.h"
-#include "stream.h"
-
-#include "pkt-var.h"
-#include "host.h"
-
-#include "app-layer.h"
-#include "app-layer-parser.h"
-#include "app-layer-protos.h"
-#include "app-layer-htp-mem.h"
-
-#include "util-host-os-info.h"
-#include "util-privs.h"
-#include "util-profiling.h"
-#include "util-misc.h"
-#include "util-validate.h"
-#include "util-runmodes.h"
-
-#include "source-pcap-file.h"
-
-//#define DEBUG
-
-#define STREAMTCP_DEFAULT_PREALLOC 2048
-#define STREAMTCP_DEFAULT_MEMCAP (32 * 1024 * 1024) /* 32mb */
-#define STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP (64 * 1024 * 1024) /* 64mb */
-#define STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE 2560
-#define STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE 2560
-#define STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED 5
-
-#define STREAMTCP_NEW_TIMEOUT 60
-#define STREAMTCP_EST_TIMEOUT 3600
-#define STREAMTCP_CLOSED_TIMEOUT 120
-
-#define STREAMTCP_EMERG_NEW_TIMEOUT 10
-#define STREAMTCP_EMERG_EST_TIMEOUT 300
-#define STREAMTCP_EMERG_CLOSED_TIMEOUT 20
-
-TmEcode StreamTcp (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
-TmEcode StreamTcpThreadInit(ThreadVars *, void *, void **);
-TmEcode StreamTcpThreadDeinit(ThreadVars *, void *);
-void StreamTcpExitPrintStats(ThreadVars *, void *);
-static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *, TcpSession *, Packet *, PacketQueue *);
-void StreamTcpRegisterTests (void);
-void StreamTcpReturnStreamSegments (TcpStream *);
-void StreamTcpInitConfig(char);
-int StreamTcpGetFlowState(void *);
-void StreamTcpSetOSPolicy(TcpStream*, Packet*);
-void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread *stt, Packet *p, TcpSession *ssn, PacketQueue *pq);
-
-static int StreamTcpValidateTimestamp(TcpSession * , Packet *);
-static int StreamTcpHandleTimestamp(TcpSession * , Packet *);
-static int StreamTcpValidateRst(TcpSession * , Packet *);
-static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *, Packet *);
-
-static PoolThread *ssn_pool = NULL;
-static SCMutex ssn_pool_mutex = SCMUTEX_INITIALIZER; /**< init only, protect initializing and growing pool */
-#ifdef DEBUG
-static uint64_t ssn_pool_cnt = 0; /** counts ssns, protected by ssn_pool_mutex */
-#endif
-
-uint64_t StreamTcpReassembleMemuseGlobalCounter(void);
-SC_ATOMIC_DECLARE(uint64_t, st_memuse);
-
-/* stream engine running in "inline" mode. */
-int stream_inline = 0;
-
-void TmModuleStreamTcpRegister (void)
-{
- tmm_modules[TMM_STREAMTCP].name = "StreamTcp";
- tmm_modules[TMM_STREAMTCP].ThreadInit = StreamTcpThreadInit;
- tmm_modules[TMM_STREAMTCP].Func = StreamTcp;
- tmm_modules[TMM_STREAMTCP].ThreadExitPrintStats = StreamTcpExitPrintStats;
- tmm_modules[TMM_STREAMTCP].ThreadDeinit = StreamTcpThreadDeinit;
- tmm_modules[TMM_STREAMTCP].RegisterTests = StreamTcpRegisterTests;
- tmm_modules[TMM_STREAMTCP].cap_flags = 0;
- tmm_modules[TMM_STREAMTCP].flags = TM_FLAG_STREAM_TM;
-}
-
-void StreamTcpIncrMemuse(uint64_t size)
-{
- (void) SC_ATOMIC_ADD(st_memuse, size);
- return;
-}
-
-void StreamTcpDecrMemuse(uint64_t size)
-{
- (void) SC_ATOMIC_SUB(st_memuse, size);
- return;
-}
-
-uint64_t StreamTcpMemuseCounter(void)
-{
- uint64_t memusecopy = SC_ATOMIC_GET(st_memuse);
- return memusecopy;
-}
-
-/**
- * \brief Check if alloc'ing "size" would mean we're over memcap
- *
- * \retval 1 if in bounds
- * \retval 0 if not in bounds
- */
-int StreamTcpCheckMemcap(uint64_t size)
-{
- if (stream_config.memcap == 0 || size + SC_ATOMIC_GET(st_memuse) <= stream_config.memcap)
- return 1;
- return 0;
-}
-
-/**
- * \brief Function to return the stream back to the pool. It returns the
- * segments in the stream to the segment pool.
- *
- * This function is called when the flow is destroyed, so it should free
- * *everything* related to the tcp session. So including the app layer
- * data. We are guaranteed to only get here when the flow's use_cnt is 0.
- *
- * \param ssn Void ptr to the ssn.
- */
-void StreamTcpSessionClear(void *ssnptr)
-{
- SCEnter();
- StreamMsg *smsg = NULL;
- TcpStateQueue *q, *q_next;
-
- TcpSession *ssn = (TcpSession *)ssnptr;
- if (ssn == NULL)
- SCReturn;
-
- StreamTcpReturnStreamSegments(&ssn->client);
- StreamTcpReturnStreamSegments(&ssn->server);
-
- //AppLayerParserCleanupState(ssn);
-
- StreamTcpSackFreeList(&ssn->client);
- StreamTcpSackFreeList(&ssn->server);
-
- /* if we have (a) smsg(s), return to the pool */
- smsg = ssn->toserver_smsg_head;
- while(smsg != NULL) {
- StreamMsg *smsg_next = smsg->next;
- SCLogDebug("returning smsg %p to pool", smsg);
- smsg->next = NULL;
- smsg->prev = NULL;
- StreamMsgReturnToPool(smsg);
- smsg = smsg_next;
- }
- ssn->toserver_smsg_head = NULL;
-
- smsg = ssn->toclient_smsg_head;
- while(smsg != NULL) {
- StreamMsg *smsg_next = smsg->next;
- SCLogDebug("returning smsg %p to pool", smsg);
- smsg->next = NULL;
- smsg->prev = NULL;
- StreamMsgReturnToPool(smsg);
- smsg = smsg_next;
- }
- ssn->toclient_smsg_head = NULL;
-
- q = ssn->queue;
- while (q != NULL) {
- q_next = q->next;
- SCFree(q);
- q = q_next;
- StreamTcpDecrMemuse((uint64_t)sizeof(TcpStateQueue));
- }
- ssn->queue = NULL;
- ssn->queue_len = 0;
-
- memset(ssn, 0, sizeof(TcpSession));
- PoolThreadReturn(ssn_pool, ssn);
-#ifdef DEBUG
- SCMutexLock(&ssn_pool_mutex);
- ssn_pool_cnt--;
- SCMutexUnlock(&ssn_pool_mutex);
-#endif
-
- SCReturn;
-}
-
-/**
- * \brief Function to return the stream segments back to the pool.
- *
- * We don't clear out the app layer storage here as that is under protection
- * of the "use_cnt" reference counter in the flow. This function is called
- * when the use_cnt is always at least 1 (this pkt has incremented the flow
- * use_cnt itself), so we don't bother.
- *
- * \param p Packet used to identify the stream.
- */
-void StreamTcpSessionPktFree (Packet *p)
-{
- SCEnter();
-
- TcpSession *ssn = (TcpSession *)p->flow->protoctx;
- if (ssn == NULL)
- SCReturn;
-
- StreamTcpReturnStreamSegments(&ssn->client);
- StreamTcpReturnStreamSegments(&ssn->server);
-
- SCReturn;
-}
-
-/** \brief Stream alloc function for the Pool
- * \retval ptr void ptr to TcpSession structure with all vars set to 0/NULL
- */
-void *StreamTcpSessionPoolAlloc()
-{
- void *ptr = NULL;
-
- if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpSession)) == 0)
- return NULL;
-
- ptr = SCMalloc(sizeof(TcpSession));
- if (unlikely(ptr == NULL))
- return NULL;
-
- return ptr;
-}
-
-int StreamTcpSessionPoolInit(void *data, void* initdata)
-{
- memset(data, 0, sizeof(TcpSession));
- StreamTcpIncrMemuse((uint64_t)sizeof(TcpSession));
-
- return 1;
-}
-
-/** \brief Pool free function
- * \param s Void ptr to TcpSession memory */
-void StreamTcpSessionPoolCleanup(void *s)
-{
- StreamMsg *smsg = NULL;
- TcpStateQueue *q, *q_next;
-
- if (s == NULL)
- return;
-
- TcpSession *ssn = (TcpSession *)s;
-
- StreamTcpReturnStreamSegments(&ssn->client);
- StreamTcpReturnStreamSegments(&ssn->server);
-
- /* if we have (a) smsg(s), return to the pool */
- smsg = ssn->toserver_smsg_head;
- while(smsg != NULL) {
- StreamMsg *smsg_next = smsg->next;
- SCLogDebug("returning smsg %p to pool", smsg);
- smsg->next = NULL;
- smsg->prev = NULL;
- StreamMsgReturnToPool(smsg);
- smsg = smsg_next;
- }
- ssn->toserver_smsg_head = NULL;
-
- smsg = ssn->toclient_smsg_head;
- while(smsg != NULL) {
- StreamMsg *smsg_next = smsg->next;
- SCLogDebug("returning smsg %p to pool", smsg);
- smsg->next = NULL;
- smsg->prev = NULL;
- StreamMsgReturnToPool(smsg);
- smsg = smsg_next;
- }
- ssn->toclient_smsg_head = NULL;
-
- q = ssn->queue;
- while (q != NULL) {
- q_next = q->next;
- SCFree(q);
- q = q_next;
- StreamTcpDecrMemuse((uint64_t)sizeof(TcpStateQueue));
- }
- ssn->queue = NULL;
- ssn->queue_len = 0;
-
- StreamTcpDecrMemuse((uint64_t)sizeof(TcpSession));
-}
-
-/** \brief To initialize the stream global configuration data
- *
- * \param quiet It tells the mode of operation, if it is TRUE nothing will
- * be get printed.
- */
-
-void StreamTcpInitConfig(char quiet)
-{
- intmax_t value = 0;
- uint16_t rdrange = 10;
-
- SCLogDebug("Initializing Stream");
-
- memset(&stream_config, 0, sizeof(stream_config));
-
- if ((ConfGetInt("stream.max-sessions", &value)) == 1) {
- SCLogWarning(SC_WARN_OPTION_OBSOLETE, "max-sessions is obsolete. "
- "Number of concurrent sessions is now only limited by Flow and "
- "TCP stream engine memcaps.");
- }
-
- if ((ConfGetInt("stream.prealloc-sessions", &value)) == 1) {
- stream_config.prealloc_sessions = (uint32_t)value;
- } else {
- if (RunmodeIsUnittests()) {
- stream_config.prealloc_sessions = 128;
- } else {
- stream_config.prealloc_sessions = STREAMTCP_DEFAULT_PREALLOC;
- if (ConfGetNode("stream.prealloc-sessions") != NULL) {
- WarnInvalidConfEntry("stream.prealloc_sessions",
- "%"PRIu32,
- stream_config.prealloc_sessions);
- }
- }
- }
- if (!quiet) {
- SCLogInfo("stream \"prealloc-sessions\": %"PRIu32" (per thread)",
- stream_config.prealloc_sessions);
- }
-
- char *temp_stream_memcap_str;
- if (ConfGet("stream.memcap", &temp_stream_memcap_str) == 1) {
- if (ParseSizeStringU64(temp_stream_memcap_str, &stream_config.memcap) < 0) {
- SCLogError(SC_ERR_SIZE_PARSE, "Error parsing stream.memcap "
- "from conf file - %s. Killing engine",
- temp_stream_memcap_str);
- exit(EXIT_FAILURE);
- }
- } else {
- stream_config.memcap = STREAMTCP_DEFAULT_MEMCAP;
- }
-
- if (!quiet) {
- SCLogInfo("stream \"memcap\": %"PRIu64, stream_config.memcap);
- }
-
- ConfGetBool("stream.midstream", &stream_config.midstream);
-
- if (!quiet) {
- SCLogInfo("stream \"midstream\" session pickups: %s", stream_config.midstream ? "enabled" : "disabled");
- }
-
- ConfGetBool("stream.async-oneside", &stream_config.async_oneside);
-
- if (!quiet) {
- SCLogInfo("stream \"async-oneside\": %s", stream_config.async_oneside ? "enabled" : "disabled");
- }
-
- int csum = 0;
-
- if ((ConfGetBool("stream.checksum-validation", &csum)) == 1) {
- if (csum == 1) {
- stream_config.flags |= STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION;
- }
- /* Default is that we validate the checksum of all the packets */
- } else {
- stream_config.flags |= STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION;
- }
-
- if (!quiet) {
- SCLogInfo("stream \"checksum-validation\": %s",
- stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION ?
- "enabled" : "disabled");
- }
-
- int inl = 0;
-
-
- char *temp_stream_inline_str;
- if (ConfGet("stream.inline", &temp_stream_inline_str) == 1) {
- /* checking for "auto" and falling back to boolean to provide
- * backward compatibility */
- if (strcmp(temp_stream_inline_str, "auto") == 0) {
- if (EngineModeIsIPS()) {
- stream_inline = 1;
- } else {
- stream_inline = 0;
- }
- } else if (ConfGetBool("stream.inline", &inl) == 1) {
- stream_inline = inl;
- }
- }
-
- if (!quiet) {
- SCLogInfo("stream.\"inline\": %s", stream_inline ? "enabled" : "disabled");
- }
-
- if ((ConfGetInt("stream.max-synack-queued", &value)) == 1) {
- if (value >= 0 && value <= 255) {
- stream_config.max_synack_queued = (uint8_t)value;
- } else {
- stream_config.max_synack_queued = (uint8_t)STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED;
- }
- } else {
- stream_config.max_synack_queued = (uint8_t)STREAMTCP_DEFAULT_MAX_SYNACK_QUEUED;
- }
- if (!quiet) {
- SCLogInfo("stream \"max-synack-queued\": %"PRIu8, stream_config.max_synack_queued);
- }
-
- char *temp_stream_reassembly_memcap_str;
- if (ConfGet("stream.reassembly.memcap", &temp_stream_reassembly_memcap_str) == 1) {
- if (ParseSizeStringU64(temp_stream_reassembly_memcap_str,
- &stream_config.reassembly_memcap) < 0) {
- SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
- "stream.reassembly.memcap "
- "from conf file - %s. Killing engine",
- temp_stream_reassembly_memcap_str);
- exit(EXIT_FAILURE);
- }
- } else {
- stream_config.reassembly_memcap = STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP;
- }
-
- if (!quiet) {
- SCLogInfo("stream.reassembly \"memcap\": %"PRIu64"", stream_config.reassembly_memcap);
- }
-
- char *temp_stream_reassembly_depth_str;
- if (ConfGet("stream.reassembly.depth", &temp_stream_reassembly_depth_str) == 1) {
- if (ParseSizeStringU32(temp_stream_reassembly_depth_str,
- &stream_config.reassembly_depth) < 0) {
- SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
- "stream.reassembly.depth "
- "from conf file - %s. Killing engine",
- temp_stream_reassembly_depth_str);
- exit(EXIT_FAILURE);
- }
- } else {
- stream_config.reassembly_depth = 0;
- }
-
- if (!quiet) {
- SCLogInfo("stream.reassembly \"depth\": %"PRIu32"", stream_config.reassembly_depth);
- }
-
- int randomize = 0;
- if ((ConfGetBool("stream.reassembly.randomize-chunk-size", &randomize)) == 0) {
- /* randomize by default if value not set
- * In ut mode we disable, to get predictible test results */
- if (!(RunmodeIsUnittests()))
- randomize = 1;
- }
-
- if (randomize) {
- char *temp_rdrange;
- if (ConfGet("stream.reassembly.randomize-chunk-range",
- &temp_rdrange) == 1) {
- if (ParseSizeStringU16(temp_rdrange, &rdrange) < 0) {
- SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
- "stream.reassembly.randomize-chunk-range "
- "from conf file - %s. Killing engine",
- temp_rdrange);
- exit(EXIT_FAILURE);
- } else if (rdrange >= 100) {
- SCLogError(SC_ERR_INVALID_VALUE,
- "stream.reassembly.randomize-chunk-range "
- "must be lower than 100");
- exit(EXIT_FAILURE);
- }
- }
- /* set a "random" seed */
- srandom(time(0));
- }
-
- char *temp_stream_reassembly_toserver_chunk_size_str;
- if (ConfGet("stream.reassembly.toserver-chunk-size",
- &temp_stream_reassembly_toserver_chunk_size_str) == 1) {
- if (ParseSizeStringU16(temp_stream_reassembly_toserver_chunk_size_str,
- &stream_config.reassembly_toserver_chunk_size) < 0) {
- SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
- "stream.reassembly.toserver-chunk-size "
- "from conf file - %s. Killing engine",
- temp_stream_reassembly_toserver_chunk_size_str);
- exit(EXIT_FAILURE);
- }
- } else {
- stream_config.reassembly_toserver_chunk_size =
- STREAMTCP_DEFAULT_TOSERVER_CHUNK_SIZE;
- }
-
- if (randomize) {
- stream_config.reassembly_toserver_chunk_size +=
- (int) (stream_config.reassembly_toserver_chunk_size *
- (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
- }
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER,
- stream_config.reassembly_toserver_chunk_size);
-
- char *temp_stream_reassembly_toclient_chunk_size_str;
- if (ConfGet("stream.reassembly.toclient-chunk-size",
- &temp_stream_reassembly_toclient_chunk_size_str) == 1) {
- if (ParseSizeStringU16(temp_stream_reassembly_toclient_chunk_size_str,
- &stream_config.reassembly_toclient_chunk_size) < 0) {
- SCLogError(SC_ERR_SIZE_PARSE, "Error parsing "
- "stream.reassembly.toclient-chunk-size "
- "from conf file - %s. Killing engine",
- temp_stream_reassembly_toclient_chunk_size_str);
- exit(EXIT_FAILURE);
- }
- } else {
- stream_config.reassembly_toclient_chunk_size =
- STREAMTCP_DEFAULT_TOCLIENT_CHUNK_SIZE;
- }
-
- if (randomize) {
- stream_config.reassembly_toclient_chunk_size +=
- (int) (stream_config.reassembly_toclient_chunk_size *
- (random() * 1.0 / RAND_MAX - 0.5) * rdrange / 100);
- }
-
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT,
- stream_config.reassembly_toclient_chunk_size);
-
- if (!quiet) {
- SCLogInfo("stream.reassembly \"toserver-chunk-size\": %"PRIu16,
- stream_config.reassembly_toserver_chunk_size);
- SCLogInfo("stream.reassembly \"toclient-chunk-size\": %"PRIu16,
- stream_config.reassembly_toclient_chunk_size);
- }
-
- int enable_raw = 1;
- if (ConfGetBool("stream.reassembly.raw", &enable_raw) == 1) {
- if (!enable_raw) {
- stream_config.ssn_init_flags = STREAMTCP_FLAG_DISABLE_RAW;
- stream_config.segment_init_flags = SEGMENTTCP_FLAG_RAW_PROCESSED;
- }
- } else {
- enable_raw = 1;
- }
- if (!quiet)
- SCLogInfo("stream.reassembly.raw: %s", enable_raw ? "enabled" : "disabled");
-
- /* init the memcap/use tracking */
- SC_ATOMIC_INIT(st_memuse);
- StatsRegisterGlobalCounter("tcp.memuse", StreamTcpMemuseCounter);
-
- StreamTcpReassembleInit(quiet);
-
- /* set the default free function and flow state function
- * values. */
- FlowSetProtoFreeFunc(IPPROTO_TCP, StreamTcpSessionClear);
-
-#ifdef UNITTESTS
- if (RunmodeIsUnittests()) {
- SCMutexLock(&ssn_pool_mutex);
- if (ssn_pool == NULL) {
- ssn_pool = PoolThreadInit(1, /* thread */
- 0, /* unlimited */
- stream_config.prealloc_sessions,
- sizeof(TcpSession),
- StreamTcpSessionPoolAlloc,
- StreamTcpSessionPoolInit, NULL,
- StreamTcpSessionPoolCleanup, NULL);
- }
- SCMutexUnlock(&ssn_pool_mutex);
- }
-#endif
-}
-
-void StreamTcpFreeConfig(char quiet)
-{
- StreamTcpReassembleFree(quiet);
-
- SCMutexLock(&ssn_pool_mutex);
- if (ssn_pool != NULL) {
- PoolThreadFree(ssn_pool);
- ssn_pool = NULL;
- }
- SCMutexUnlock(&ssn_pool_mutex);
- SCMutexDestroy(&ssn_pool_mutex);
-
- SCLogDebug("ssn_pool_cnt %"PRIu64"", ssn_pool_cnt);
-}
-
-/** \brief The function is used to to fetch a TCP session from the
- * ssn_pool, when a TCP SYN is received.
- *
- * \param quiet Packet P, which has been recieved for the new TCP session.
- *
- * \retval TcpSession A new TCP session with field initilaized to 0/NULL.
- */
-TcpSession *StreamTcpNewSession (Packet *p, int id)
-{
- TcpSession *ssn = (TcpSession *)p->flow->protoctx;
-
- if (ssn == NULL) {
- p->flow->protoctx = PoolThreadGetById(ssn_pool, id);
-#ifdef DEBUG
- SCMutexLock(&ssn_pool_mutex);
- if (p->flow->protoctx != NULL)
- ssn_pool_cnt++;
- SCMutexUnlock(&ssn_pool_mutex);
-#endif
-
- ssn = (TcpSession *)p->flow->protoctx;
- if (ssn == NULL) {
- SCLogDebug("ssn_pool is empty");
- return NULL;
- }
-
- ssn->state = TCP_NONE;
- ssn->flags = stream_config.ssn_init_flags;
- ssn->tcp_packet_flags = p->tcph ? p->tcph->th_flags : 0;
-
- if (PKT_IS_TOSERVER(p)) {
- ssn->client.tcp_flags = p->tcph ? p->tcph->th_flags : 0;
- ssn->server.tcp_flags = 0;
- } else if (PKT_IS_TOCLIENT(p)) {
- ssn->server.tcp_flags = p->tcph ? p->tcph->th_flags : 0;
- ssn->client.tcp_flags = 0;
- }
- }
-
- return ssn;
-}
-
-static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn,
- uint8_t state)
-{
- if (state == ssn->state || PKT_IS_PSEUDOPKT(p))
- return;
-
- ssn->state = state;
-
- /* update the flow state */
- switch(ssn->state) {
- case TCP_ESTABLISHED:
- case TCP_FIN_WAIT1:
- case TCP_FIN_WAIT2:
- case TCP_CLOSING:
- case TCP_CLOSE_WAIT:
- SC_ATOMIC_SET(p->flow->flow_state, FLOW_STATE_ESTABLISHED);
- break;
- case TCP_LAST_ACK:
- case TCP_TIME_WAIT:
- case TCP_CLOSED:
- SC_ATOMIC_SET(p->flow->flow_state, FLOW_STATE_CLOSED);
- break;
- }
-}
-
-/**
- * \brief Function to set the OS policy for the given stream based on the
- * destination of the received packet.
- *
- * \param stream TcpStream of which os_policy needs to set
- * \param p Packet which is used to set the os policy
- */
-void StreamTcpSetOSPolicy(TcpStream *stream, Packet *p)
-{
- int ret = 0;
-
- if (PKT_IS_IPV4(p)) {
- /* Get the OS policy based on destination IP address, as destination
- OS will decide how to react on the anomalies of newly received
- packets */
- ret = SCHInfoGetIPv4HostOSFlavour((uint8_t *)GET_IPV4_DST_ADDR_PTR(p));
- if (ret > 0)
- stream->os_policy = ret;
- else
- stream->os_policy = OS_POLICY_DEFAULT;
-
- } else if (PKT_IS_IPV6(p)) {
- /* Get the OS policy based on destination IP address, as destination
- OS will decide how to react on the anomalies of newly received
- packets */
- ret = SCHInfoGetIPv6HostOSFlavour((uint8_t *)GET_IPV6_DST_ADDR(p));
- if (ret > 0)
- stream->os_policy = ret;
- else
- stream->os_policy = OS_POLICY_DEFAULT;
- }
-
- if (stream->os_policy == OS_POLICY_BSD_RIGHT)
- stream->os_policy = OS_POLICY_BSD;
- else if (stream->os_policy == OS_POLICY_OLD_SOLARIS)
- stream->os_policy = OS_POLICY_SOLARIS;
-
- SCLogDebug("Policy is %"PRIu8"", stream->os_policy);
-
-}
-
-/**
- * \brief get the size of a stream
- *
- * \note this just calculates the diff between isn and last_ack
- * and will not consider sequence wrap arounds (streams
- * bigger than 4gb).
- *
- * \retval size stream size
- */
-uint32_t StreamTcpGetStreamSize(TcpStream *stream)
-{
- return (stream->last_ack - stream->isn - 1);
-}
-
-/**
- * \brief macro to update last_ack only if the new value is higher
- *
- * \param ssn session
- * \param stream stream to update
- * \param ack ACK value to test and set
- */
-#define StreamTcpUpdateLastAck(ssn, stream, ack) { \
- if (SEQ_GT((ack), (stream)->last_ack)) \
- { \
- SCLogDebug("ssn %p: last_ack set to %"PRIu32", moved %u forward", (ssn), (ack), (ack) - (stream)->last_ack); \
- if ((SEQ_LEQ((stream)->last_ack, (stream)->next_seq) && SEQ_GT((ack),(stream)->next_seq))) { \
- SCLogDebug("last_ack just passed next_seq: %u (was %u) > %u", (ack), (stream)->last_ack, (stream)->next_seq); \
- } else { \
- SCLogDebug("next_seq (%u) <> last_ack now %d", (stream)->next_seq, (int)(stream)->next_seq - (ack)); \
- }\
- (stream)->last_ack = (ack); \
- StreamTcpSackPruneList((stream)); \
- } else { \
- SCLogDebug("ssn %p: no update: ack %u, last_ack %"PRIu32", next_seq %u (state %u)", \
- (ssn), (ack), (stream)->last_ack, (stream)->next_seq, (ssn)->state); \
- }\
-}
-
-/**
- * \brief macro to update next_win only if the new value is higher
- *
- * \param ssn session
- * \param stream stream to update
- * \param win window value to test and set
- */
-#define StreamTcpUpdateNextWin(ssn, stream, win) { \
- uint32_t sacked_size__ = StreamTcpSackedSize((stream)); \
- if (SEQ_GT(((win) + sacked_size__), (stream)->next_win)) { \
- (stream)->next_win = ((win) + sacked_size__); \
- SCLogDebug("ssn %p: next_win set to %"PRIu32, (ssn), (stream)->next_win); \
- } \
-}
-
-static int StreamTcpPacketIsRetransmission(TcpStream *stream, Packet *p)
-{
- if (p->payload_len == 0)
- SCReturnInt(0);
-
- /* retransmission of already partially ack'd data */
- if (SEQ_LT(TCP_GET_SEQ(p), stream->last_ack) && SEQ_GT((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack))
- {
- StreamTcpSetEvent(p, STREAM_PKT_RETRANSMISSION);
- SCReturnInt(1);
- }
-
- /* retransmission of already ack'd data */
- if (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), stream->last_ack)) {
- StreamTcpSetEvent(p, STREAM_PKT_RETRANSMISSION);
- SCReturnInt(1);
- }
-
- /* retransmission of in flight data */
- if (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), stream->next_seq)) {
- StreamTcpSetEvent(p, STREAM_PKT_RETRANSMISSION);
- SCReturnInt(2);
- }
-
- SCLogDebug("seq %u payload_len %u => %u, last_ack %u, next_seq %u", TCP_GET_SEQ(p),
- p->payload_len, (TCP_GET_SEQ(p) + p->payload_len), stream->last_ack, stream->next_seq);
- SCReturnInt(0);
-}
-
-/**
- * \internal
- * \brief Function to handle the TCP_CLOSED or NONE state. The function handles
- * packets while the session state is None which means a newly
- * initialized structure, or a fully closed session.
- *
- * \param tv Thread Variable containig input/output queue, cpu affinity
- * \param p Packet which has to be handled in this TCP state.
- * \param stt Strean Thread module registered to handle the stream handling
- *
- * \retval 0 ok
- * \retval -1 error
- */
-static int StreamTcpPacketStateNone(ThreadVars *tv, Packet *p,
- StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
-{
- if (p->tcph->th_flags & TH_RST) {
- StreamTcpSetEvent(p, STREAM_RST_BUT_NO_SESSION);
- SCLogDebug("RST packet received, no session setup");
- return -1;
-
- } else if (p->tcph->th_flags & TH_FIN) {
- StreamTcpSetEvent(p, STREAM_FIN_BUT_NO_SESSION);
- SCLogDebug("FIN packet received, no session setup");
- return -1;
-
- /* SYN/ACK */
- } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
- if (stream_config.midstream == FALSE &&
- stream_config.async_oneside == FALSE)
- return 0;
-
- if (ssn == NULL) {
- ssn = StreamTcpNewSession(p, stt->ssn_pool_id);
- if (ssn == NULL) {
- StatsIncr(tv, stt->counter_tcp_ssn_memcap);
- return -1;
- }
- StatsIncr(tv, stt->counter_tcp_sessions);
- }
- /* set the state */
- StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
- SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
- "TCP_SYN_RECV", ssn);
- ssn->flags |= STREAMTCP_FLAG_MIDSTREAM;
- /* Flag used to change the direct in the later stage in the session */
- ssn->flags |= STREAMTCP_FLAG_MIDSTREAM_SYNACK;
-
- /* sequence number & window */
- ssn->server.isn = TCP_GET_SEQ(p);
- STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn);
- ssn->server.next_seq = ssn->server.isn + 1;
- ssn->server.window = TCP_GET_WINDOW(p);
- SCLogDebug("ssn %p: server window %u", ssn, ssn->server.window);
-
- ssn->client.isn = TCP_GET_ACK(p) - 1;
- STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn);
- ssn->client.next_seq = ssn->client.isn + 1;
-
- ssn->client.last_ack = TCP_GET_ACK(p);
- ssn->server.last_ack = TCP_GET_SEQ(p);
-
- ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
-
- /** If the client has a wscale option the server had it too,
- * so set the wscale for the server to max. Otherwise none
- * will have the wscale opt just like it should. */
- if (p->tcpvars.ws != NULL) {
- ssn->client.wscale = TCP_GET_WSCALE(p);
- ssn->server.wscale = TCP_WSCALE_MAX;
- }
-
- SCLogDebug("ssn %p: ssn->client.isn %"PRIu32", ssn->client.next_seq"
- " %"PRIu32", ssn->client.last_ack %"PRIu32"", ssn,
- ssn->client.isn, ssn->client.next_seq,
- ssn->client.last_ack);
- SCLogDebug("ssn %p: ssn->server.isn %"PRIu32", ssn->server.next_seq"
- " %"PRIu32", ssn->server.last_ack %"PRIu32"", ssn,
- ssn->server.isn, ssn->server.next_seq,
- ssn->server.last_ack);
-
- /* Set the timestamp value for both streams, if packet has timestamp
- * option enabled.*/
- if (p->tcpvars.ts != NULL) {
- ssn->server.last_ts = TCP_GET_TSVAL(p);
- ssn->client.last_ts = TCP_GET_TSECR(p);
- SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
- "ssn->client.last_ts %" PRIu32"", ssn,
- ssn->server.last_ts, ssn->client.last_ts);
-
- ssn->flags |= STREAMTCP_FLAG_TIMESTAMP;
-
- ssn->server.last_pkt_ts = p->ts.tv_sec;
- if (ssn->server.last_ts == 0)
- ssn->server.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
- if (ssn->client.last_ts == 0)
- ssn->client.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
-
- } else {
- ssn->server.last_ts = 0;
- ssn->client.last_ts = 0;
- }
-
- if (TCP_GET_SACKOK(p) == 1) {
- ssn->flags |= STREAMTCP_FLAG_SACKOK;
- SCLogDebug("ssn %p: SYN/ACK with SACK permitted, assuming "
- "SACK permitted for both sides", ssn);
- }
-
- /* packet thinks it is in the wrong direction, flip it */
- StreamTcpPacketSwitchDir(ssn, p);
-
- } else if (p->tcph->th_flags & TH_SYN) {
- if (ssn == NULL) {
- ssn = StreamTcpNewSession(p, stt->ssn_pool_id);
- if (ssn == NULL) {
- StatsIncr(tv, stt->counter_tcp_ssn_memcap);
- return -1;
- }
-
- StatsIncr(tv, stt->counter_tcp_sessions);
- }
-
- /* set the state */
- StreamTcpPacketSetState(p, ssn, TCP_SYN_SENT);
- SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_SENT", ssn);
-
- /* set the sequence numbers and window */
- ssn->client.isn = TCP_GET_SEQ(p);
- STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn);
- ssn->client.next_seq = ssn->client.isn + 1;
-
- /* Set the stream timestamp value, if packet has timestamp option
- * enabled. */
- if (p->tcpvars.ts != NULL) {
- ssn->client.last_ts = TCP_GET_TSVAL(p);
- SCLogDebug("ssn %p: p->tcpvars.ts %p, %02x", ssn, p->tcpvars.ts,
- ssn->client.last_ts);
-
- if (ssn->client.last_ts == 0)
- ssn->client.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
-
- ssn->client.last_pkt_ts = p->ts.tv_sec;
- ssn->client.flags |= STREAMTCP_STREAM_FLAG_TIMESTAMP;
- }
-
- ssn->server.window = TCP_GET_WINDOW(p);
- if (p->tcpvars.ws != NULL) {
- ssn->flags |= STREAMTCP_FLAG_SERVER_WSCALE;
- ssn->server.wscale = TCP_GET_WSCALE(p);
- }
-
- if (TCP_GET_SACKOK(p) == 1) {
- ssn->flags |= STREAMTCP_FLAG_CLIENT_SACKOK;
- SCLogDebug("ssn %p: SACK permited on SYN packet", ssn);
- }
-
- SCLogDebug("ssn %p: ssn->client.isn %" PRIu32 ", "
- "ssn->client.next_seq %" PRIu32 ", ssn->client.last_ack "
- "%"PRIu32"", ssn, ssn->client.isn, ssn->client.next_seq,
- ssn->client.last_ack);
-
- } else if (p->tcph->th_flags & TH_ACK) {
- if (stream_config.midstream == FALSE)
- return 0;
-
- if (ssn == NULL) {
- ssn = StreamTcpNewSession(p, stt->ssn_pool_id);
- if (ssn == NULL) {
- StatsIncr(tv, stt->counter_tcp_ssn_memcap);
- return -1;
- }
- StatsIncr(tv, stt->counter_tcp_sessions);
- }
- /* set the state */
- StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
- SCLogDebug("ssn %p: =~ midstream picked ssn state is now "
- "TCP_ESTABLISHED", ssn);
-
- ssn->flags = STREAMTCP_FLAG_MIDSTREAM;
- ssn->flags |= STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED;
-
- /** window scaling for midstream pickups, we can't do much other
- * than assume that it's set to the max value: 14 */
- ssn->client.wscale = TCP_WSCALE_MAX;
- ssn->server.wscale = TCP_WSCALE_MAX;
-
- /* set the sequence numbers and window */
- ssn->client.isn = TCP_GET_SEQ(p) - 1;
- STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn);
- ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- ssn->client.last_ack = TCP_GET_SEQ(p);
- ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
- SCLogDebug("ssn %p: ssn->client.isn %u, ssn->client.next_seq %u",
- ssn, ssn->client.isn, ssn->client.next_seq);
-
- ssn->server.isn = TCP_GET_ACK(p) - 1;
- STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn);
- ssn->server.next_seq = ssn->server.isn + 1;
- ssn->server.last_ack = TCP_GET_ACK(p);
- ssn->server.next_win = ssn->server.last_ack;
-
- SCLogDebug("ssn %p: ssn->client.next_win %"PRIu32", "
- "ssn->server.next_win %"PRIu32"", ssn,
- ssn->client.next_win, ssn->server.next_win);
- SCLogDebug("ssn %p: ssn->client.last_ack %"PRIu32", "
- "ssn->server.last_ack %"PRIu32"", ssn,
- ssn->client.last_ack, ssn->server.last_ack);
-
- /* Set the timestamp value for both streams, if packet has timestamp
- * option enabled.*/
- if (p->tcpvars.ts != NULL) {
- ssn->client.last_ts = TCP_GET_TSVAL(p);
- ssn->server.last_ts = TCP_GET_TSECR(p);
- SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
- "ssn->client.last_ts %" PRIu32"", ssn,
- ssn->server.last_ts, ssn->client.last_ts);
-
- ssn->flags |= STREAMTCP_FLAG_TIMESTAMP;
-
- ssn->client.last_pkt_ts = p->ts.tv_sec;
- if (ssn->server.last_ts == 0)
- ssn->server.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
- if (ssn->client.last_ts == 0)
- ssn->client.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
-
- } else {
- ssn->server.last_ts = 0;
- ssn->client.last_ts = 0;
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
-
- ssn->flags |= STREAMTCP_FLAG_SACKOK;
- SCLogDebug("ssn %p: assuming SACK permitted for both sides", ssn);
-
- } else {
- SCLogDebug("default case");
- }
-
- return 0;
-}
-
-/** \internal
- * \brief Setup TcpStateQueue based on SYN/ACK packet
- */
-static inline void StreamTcp3whsSynAckToStateQueue(Packet *p, TcpStateQueue *q)
-{
- q->flags = 0;
- q->wscale = 0;
- q->ts = 0;
- q->win = TCP_GET_WINDOW(p);
- q->seq = TCP_GET_SEQ(p);
- q->ack = TCP_GET_ACK(p);
- q->pkt_ts = p->ts.tv_sec;
-
- if (TCP_GET_SACKOK(p) == 1)
- q->flags |= STREAMTCP_QUEUE_FLAG_SACK;
-
- if (p->tcpvars.ws != NULL) {
- q->flags |= STREAMTCP_QUEUE_FLAG_WS;
- q->wscale = TCP_GET_WSCALE(p);
- }
- if (p->tcpvars.ts != NULL) {
- q->flags |= STREAMTCP_QUEUE_FLAG_TS;
- q->ts = TCP_GET_TSVAL(p);
- }
-}
-
-/** \internal
- * \brief Find the Queued SYN/ACK that is the same as this SYN/ACK
- * \retval q or NULL */
-TcpStateQueue *StreamTcp3whsFindSynAckBySynAck(TcpSession *ssn, Packet *p)
-{
- TcpStateQueue *q = ssn->queue;
- TcpStateQueue search;
-
- StreamTcp3whsSynAckToStateQueue(p, &search);
-
- while (q != NULL) {
- if (search.flags == q->flags &&
- search.wscale == q->wscale &&
- search.win == q->win &&
- search.seq == q->seq &&
- search.ack == q->ack &&
- search.ts == q->ts) {
- return q;
- }
-
- q = q->next;
- }
-
- return q;
-}
-
-int StreamTcp3whsQueueSynAck(TcpSession *ssn, Packet *p)
-{
- /* first see if this is already in our list */
- if (StreamTcp3whsFindSynAckBySynAck(ssn, p) != NULL)
- return 0;
-
- if (ssn->queue_len == stream_config.max_synack_queued) {
- SCLogDebug("ssn %p: =~ SYN/ACK queue limit reached", ssn);
- StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_FLOOD);
- return -1;
- }
-
- if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpStateQueue)) == 0) {
- SCLogDebug("ssn %p: =~ SYN/ACK queue failed: stream memcap reached", ssn);
- return -1;
- }
-
- TcpStateQueue *q = SCMalloc(sizeof(*q));
- if (unlikely(q == NULL)) {
- SCLogDebug("ssn %p: =~ SYN/ACK queue failed: alloc failed", ssn);
- return -1;
- }
- memset(q, 0x00, sizeof(*q));
- StreamTcpIncrMemuse((uint64_t)sizeof(TcpStateQueue));
-
- StreamTcp3whsSynAckToStateQueue(p, q);
-
- /* put in list */
- q->next = ssn->queue;
- ssn->queue = q;
- ssn->queue_len++;
- return 0;
-}
-
-/** \internal
- * \brief Find the Queued SYN/ACK that goes with this ACK
- * \retval q or NULL */
-TcpStateQueue *StreamTcp3whsFindSynAckByAck(TcpSession *ssn, Packet *p)
-{
- uint32_t ack = TCP_GET_SEQ(p);
- uint32_t seq = TCP_GET_ACK(p) - 1;
- TcpStateQueue *q = ssn->queue;
-
- while (q != NULL) {
- if (seq == q->seq &&
- ack == q->ack) {
- return q;
- }
-
- q = q->next;
- }
-
- return NULL;
-}
-
-/** \internal
- * \brief Update SSN after receiving a valid SYN/ACK
- *
- * Normally we update the SSN from the SYN/ACK packet. But in case
- * of queued SYN/ACKs, we can use one of those.
- *
- * \param ssn TCP session
- * \param p Packet
- * \param q queued state if used, NULL otherwise
- *
- * To make sure all SYN/ACK based state updates are in one place,
- * this function can updated based on Packet or TcpStateQueue, where
- * the latter takes precedence.
- */
-static void StreamTcp3whsSynAckUpdate(TcpSession *ssn, Packet *p, TcpStateQueue *q)
-{
- TcpStateQueue update;
- if (likely(q == NULL)) {
- StreamTcp3whsSynAckToStateQueue(p, &update);
- q = &update;
- }
-
- if (ssn->state != TCP_SYN_RECV) {
- /* update state */
- StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
- SCLogDebug("ssn %p: =~ ssn state is now TCP_SYN_RECV", ssn);
- }
- /* sequence number & window */
- ssn->server.isn = q->seq;
- STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn);
- ssn->server.next_seq = ssn->server.isn + 1;
-
- ssn->client.window = q->win;
- SCLogDebug("ssn %p: window %" PRIu32 "", ssn, ssn->server.window);
-
- /* Set the timestamp values used to validate the timestamp of
- * received packets.*/
- if ((q->flags & STREAMTCP_QUEUE_FLAG_TS) &&
- (ssn->client.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP))
- {
- ssn->server.last_ts = q->ts;
- SCLogDebug("ssn %p: ssn->server.last_ts %" PRIu32" "
- "ssn->client.last_ts %" PRIu32"", ssn,
- ssn->server.last_ts, ssn->client.last_ts);
- ssn->flags |= STREAMTCP_FLAG_TIMESTAMP;
- ssn->server.last_pkt_ts = q->pkt_ts;
- if (ssn->server.last_ts == 0)
- ssn->server.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
- } else {
- ssn->client.last_ts = 0;
- ssn->server.last_ts = 0;
- ssn->client.flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
- }
-
- ssn->client.last_ack = q->ack;
- ssn->server.last_ack = ssn->server.isn + 1;
-
- /** check for the presense of the ws ptr to determine if we
- * support wscale at all */
- if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) &&
- (q->flags & STREAMTCP_QUEUE_FLAG_WS))
- {
- ssn->client.wscale = q->wscale;
- } else {
- ssn->client.wscale = 0;
- }
-
- if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) &&
- (q->flags & STREAMTCP_QUEUE_FLAG_SACK)) {
- ssn->flags |= STREAMTCP_FLAG_SACKOK;
- SCLogDebug("ssn %p: SACK permitted for session", ssn);
- } else {
- ssn->flags &= ~STREAMTCP_FLAG_SACKOK;
- }
-
- ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
- ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
- SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 "", ssn,
- ssn->server.next_win);
- SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 "", ssn,
- ssn->client.next_win);
- SCLogDebug("ssn %p: ssn->server.isn %" PRIu32 ", "
- "ssn->server.next_seq %" PRIu32 ", "
- "ssn->server.last_ack %" PRIu32 " "
- "(ssn->client.last_ack %" PRIu32 ")", ssn,
- ssn->server.isn, ssn->server.next_seq,
- ssn->server.last_ack, ssn->client.last_ack);
-
- /* unset the 4WHS flag as we received this SYN/ACK as part of a
- * (so far) valid 3WHS */
- if (ssn->flags & STREAMTCP_FLAG_4WHS)
- SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS unset, normal SYN/ACK"
- " so considering 3WHS", ssn);
-
- ssn->flags &=~ STREAMTCP_FLAG_4WHS;
-}
-
-/**
- * \brief Function to handle the TCP_SYN_SENT state. The function handles
- * SYN, SYN/ACK, RST packets and correspondingly changes the connection
- * state.
- *
- * \param tv Thread Variable containig input/output queue, cpu affinity
- * \param p Packet which has to be handled in this TCP state.
- * \param stt Strean Thread module registered to handle the stream handling
- */
-
-static int StreamTcpPacketStateSynSent(ThreadVars *tv, Packet *p,
- StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
-{
- if (ssn == NULL)
- return -1;
-
- SCLogDebug("ssn %p: pkt received: %s", ssn, PKT_IS_TOCLIENT(p) ?
- "toclient":"toserver");
-
- /* RST */
- if (p->tcph->th_flags & TH_RST) {
- if (!StreamTcpValidateRst(ssn, p))
- return -1;
-
- if (PKT_IS_TOSERVER(p)) {
- if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn) &&
- SEQ_EQ(TCP_GET_WINDOW(p), 0) &&
- SEQ_EQ(TCP_GET_ACK(p), (ssn->client.isn + 1)))
- {
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: Reset received and state changed to "
- "TCP_CLOSED", ssn);
- }
- } else {
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: Reset received and state changed to "
- "TCP_CLOSED", ssn);
- }
-
- /* FIN */
- } else if (p->tcph->th_flags & TH_FIN) {
- /** \todo */
-
- /* SYN/ACK */
- } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
- if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: SYN/ACK received on 4WHS session", ssn);
-
- /* Check if the SYN/ACK packet ack's the earlier
- * received SYN packet. */
- if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->server.isn + 1))) {
- StreamTcpSetEvent(p, STREAM_4WHS_SYNACK_WITH_WRONG_ACK);
-
- SCLogDebug("ssn %p: 4WHS ACK mismatch, packet ACK %"PRIu32""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_ACK(p), ssn->server.isn + 1);
- return -1;
- }
-
- /* Check if the SYN/ACK packet SEQ's the *FIRST* received SYN
- * packet. */
- if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
- StreamTcpSetEvent(p, STREAM_4WHS_SYNACK_WITH_WRONG_SYN);
-
- SCLogDebug("ssn %p: 4WHS SEQ mismatch, packet SEQ %"PRIu32""
- " != %" PRIu32 " from *first* SYN pkt", ssn,
- TCP_GET_SEQ(p), ssn->client.isn);
- return -1;
- }
-
-
- /* update state */
- StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
- SCLogDebug("ssn %p: =~ 4WHS ssn state is now TCP_SYN_RECV", ssn);
-
- /* sequence number & window */
- ssn->client.isn = TCP_GET_SEQ(p);
- STREAMTCP_SET_RA_BASE_SEQ(&ssn->client, ssn->client.isn);
- ssn->client.next_seq = ssn->client.isn + 1;
-
- ssn->server.window = TCP_GET_WINDOW(p);
- SCLogDebug("ssn %p: 4WHS window %" PRIu32 "", ssn,
- ssn->client.window);
-
- /* Set the timestamp values used to validate the timestamp of
- * received packets. */
- if ((p->tcpvars.ts != NULL) &&
- (ssn->server.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP))
- {
- ssn->client.last_ts = TCP_GET_TSVAL(p);
- SCLogDebug("ssn %p: 4WHS ssn->client.last_ts %" PRIu32" "
- "ssn->server.last_ts %" PRIu32"", ssn,
- ssn->client.last_ts, ssn->server.last_ts);
- ssn->flags |= STREAMTCP_FLAG_TIMESTAMP;
- ssn->client.last_pkt_ts = p->ts.tv_sec;
- if (ssn->client.last_ts == 0)
- ssn->client.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
- } else {
- ssn->server.last_ts = 0;
- ssn->client.last_ts = 0;
- ssn->server.flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
- }
-
- ssn->server.last_ack = TCP_GET_ACK(p);
- ssn->client.last_ack = ssn->client.isn + 1;
-
- /** check for the presense of the ws ptr to determine if we
- * support wscale at all */
- if ((ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) &&
- (p->tcpvars.ws != NULL))
- {
- ssn->server.wscale = TCP_GET_WSCALE(p);
- } else {
- ssn->server.wscale = 0;
- }
-
- if ((ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) &&
- TCP_GET_SACKOK(p) == 1) {
- ssn->flags |= STREAMTCP_FLAG_SACKOK;
- SCLogDebug("ssn %p: SACK permitted for 4WHS session", ssn);
- }
-
- ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
- ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
- SCLogDebug("ssn %p: 4WHS ssn->client.next_win %" PRIu32 "", ssn,
- ssn->client.next_win);
- SCLogDebug("ssn %p: 4WHS ssn->server.next_win %" PRIu32 "", ssn,
- ssn->server.next_win);
- SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
- "ssn->client.next_seq %" PRIu32 ", "
- "ssn->client.last_ack %" PRIu32 " "
- "(ssn->server.last_ack %" PRIu32 ")", ssn,
- ssn->client.isn, ssn->client.next_seq,
- ssn->client.last_ack, ssn->server.last_ack);
-
- /* done here */
- return 0;
- }
-
- if (PKT_IS_TOSERVER(p)) {
- StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_IN_WRONG_DIRECTION);
- SCLogDebug("ssn %p: SYN/ACK received in the wrong direction", ssn);
- return -1;
- }
-
- /* Check if the SYN/ACK packet ack's the earlier
- * received SYN packet. */
- if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.isn + 1))) {
- StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_WITH_WRONG_ACK);
- SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
- "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
- ssn->client.isn + 1);
- return -1;
- }
-
- StreamTcp3whsSynAckUpdate(ssn, p, /* no queue override */NULL);
-
- } else if (p->tcph->th_flags & TH_SYN) {
- SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent", ssn);
- if (ssn->flags & STREAMTCP_FLAG_4WHS) {
- SCLogDebug("ssn %p: SYN packet on state SYN_SENT... resent of "
- "4WHS SYN", ssn);
- }
-
- if (PKT_IS_TOCLIENT(p)) {
- /** a SYN only packet in the opposite direction could be:
- * http://www.breakingpointsystems.com/community/blog/tcp-
- * portals-the-three-way-handshake-is-a-lie
- *
- * \todo improve resetting the session */
-
- /* indicate that we're dealing with 4WHS here */
- ssn->flags |= STREAMTCP_FLAG_4WHS;
- SCLogDebug("ssn %p: STREAMTCP_FLAG_4WHS flag set", ssn);
-
- /* set the sequence numbers and window for server
- * We leave the ssn->client.isn in place as we will
- * check the SYN/ACK pkt with that.
- */
- ssn->server.isn = TCP_GET_SEQ(p);
- STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn);
- ssn->server.next_seq = ssn->server.isn + 1;
-
- /* Set the stream timestamp value, if packet has timestamp
- * option enabled. */
- if (p->tcpvars.ts != NULL) {
- ssn->server.last_ts = TCP_GET_TSVAL(p);
- SCLogDebug("ssn %p: p->tcpvars.ts %p, %02x", ssn,
- p->tcpvars.ts, ssn->server.last_ts);
-
- if (ssn->server.last_ts == 0)
- ssn->server.flags |= STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
- ssn->server.last_pkt_ts = p->ts.tv_sec;
- ssn->server.flags |= STREAMTCP_STREAM_FLAG_TIMESTAMP;
- }
-
- ssn->server.window = TCP_GET_WINDOW(p);
- if (p->tcpvars.ws != NULL) {
- ssn->flags |= STREAMTCP_FLAG_SERVER_WSCALE;
- ssn->server.wscale = TCP_GET_WSCALE(p);
- } else {
- ssn->flags &= ~STREAMTCP_FLAG_SERVER_WSCALE;
- ssn->server.wscale = 0;
- }
-
- if (TCP_GET_SACKOK(p) == 1) {
- ssn->flags |= STREAMTCP_FLAG_CLIENT_SACKOK;
- } else {
- ssn->flags &= ~STREAMTCP_FLAG_CLIENT_SACKOK;
- }
-
- SCLogDebug("ssn %p: 4WHS ssn->server.isn %" PRIu32 ", "
- "ssn->server.next_seq %" PRIu32 ", "
- "ssn->server.last_ack %"PRIu32"", ssn,
- ssn->server.isn, ssn->server.next_seq,
- ssn->server.last_ack);
- SCLogDebug("ssn %p: 4WHS ssn->client.isn %" PRIu32 ", "
- "ssn->client.next_seq %" PRIu32 ", "
- "ssn->client.last_ack %"PRIu32"", ssn,
- ssn->client.isn, ssn->client.next_seq,
- ssn->client.last_ack);
- }
-
- /** \todo check if it's correct or set event */
-
- } else if (p->tcph->th_flags & TH_ACK) {
- /* Handle the asynchronous stream, when we receive a SYN packet
- and now istead of receving a SYN/ACK we receive a ACK from the
- same host, which sent the SYN, this suggests the ASNYC streams.*/
- if (stream_config.async_oneside == FALSE)
- return 0;
-
- /* we are in AYNC (one side) mode now. */
-
- /* one side async means we won't see a SYN/ACK, so we can
- * only check the SYN. */
- if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq))) {
- StreamTcpSetEvent(p, STREAM_3WHS_ASYNC_WRONG_SEQ);
-
- SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
- "%" PRIu32 " from stream",ssn, TCP_GET_SEQ(p),
- ssn->client.next_seq);
- return -1;
- }
-
- ssn->flags |= STREAMTCP_FLAG_ASYNC;
- StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
- SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
-
- ssn->client.window = TCP_GET_WINDOW(p);
- ssn->client.last_ack = TCP_GET_SEQ(p);
- ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
-
- /* Set the server side parameters */
- ssn->server.isn = TCP_GET_ACK(p) - 1;
- STREAMTCP_SET_RA_BASE_SEQ(&ssn->server, ssn->server.isn);
- ssn->server.next_seq = ssn->server.isn + 1;
- ssn->server.last_ack = ssn->server.next_seq;
- ssn->server.next_win = ssn->server.last_ack;
-
- SCLogDebug("ssn %p: synsent => Asynchronous stream, packet SEQ"
- " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
- "ssn->client.next_seq %" PRIu32 ""
- ,ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p)
- + p->payload_len, ssn->client.next_seq);
-
- /* if SYN had wscale, assume it to be supported. Otherwise
- * we know it not to be supported. */
- if (ssn->flags & STREAMTCP_FLAG_SERVER_WSCALE) {
- ssn->client.wscale = TCP_WSCALE_MAX;
- }
-
- /* Set the timestamp values used to validate the timestamp of
- * received packets.*/
- if (p->tcpvars.ts != NULL &&
- (ssn->client.flags & STREAMTCP_STREAM_FLAG_TIMESTAMP))
- {
- ssn->flags |= STREAMTCP_FLAG_TIMESTAMP;
- ssn->client.flags &= ~STREAMTCP_STREAM_FLAG_TIMESTAMP;
- ssn->client.last_pkt_ts = p->ts.tv_sec;
- } else {
- ssn->client.last_ts = 0;
- ssn->client.flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
- }
-
- if (ssn->flags & STREAMTCP_FLAG_CLIENT_SACKOK) {
- ssn->flags |= STREAMTCP_FLAG_SACKOK;
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
-
- } else {
- SCLogDebug("ssn %p: default case", ssn);
- }
-
- return 0;
-}
-
-/**
- * \brief Function to handle the TCP_SYN_RECV state. The function handles
- * SYN, SYN/ACK, ACK, FIN, RST packets and correspondingly changes
- * the connection state.
- *
- * \param tv Thread Variable containig input/output queue, cpu affinity
- * \param p Packet which has to be handled in this TCP state.
- * \param stt Strean Thread module registered to handle the stream handling
- *
- * \retval 0 ok
- * \retval -1 error
- */
-
-static int StreamTcpPacketStateSynRecv(ThreadVars *tv, Packet *p,
- StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
-{
- if (ssn == NULL)
- return -1;
-
- if (p->tcph->th_flags & TH_RST) {
- if (!StreamTcpValidateRst(ssn, p))
- return -1;
-
- uint8_t reset = TRUE;
- /* After receiveing the RST in SYN_RECV state and if detection
- evasion flags has been set, then the following operating
- systems will not closed the connection. As they consider the
- packet as stray packet and not belonging to the current
- session, for more information check
- http://www.packetstan.com/2010/06/recently-ive-been-on-campaign-to-make.html */
- if (ssn->flags & STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT) {
- if (PKT_IS_TOSERVER(p)) {
- if ((ssn->server.os_policy == OS_POLICY_LINUX) ||
- (ssn->server.os_policy == OS_POLICY_OLD_LINUX) ||
- (ssn->server.os_policy == OS_POLICY_SOLARIS))
- {
- reset = FALSE;
- SCLogDebug("Detection evasion has been attempted, so"
- " not resetting the connection !!");
- }
- } else {
- if ((ssn->client.os_policy == OS_POLICY_LINUX) ||
- (ssn->client.os_policy == OS_POLICY_OLD_LINUX) ||
- (ssn->client.os_policy == OS_POLICY_SOLARIS))
- {
- reset = FALSE;
- SCLogDebug("Detection evasion has been attempted, so"
- " not resetting the connection !!");
- }
- }
- }
-
- if (reset == TRUE) {
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: Reset received and state changed to "
- "TCP_CLOSED", ssn);
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
- }
-
- } else if (p->tcph->th_flags & TH_FIN) {
- /* FIN is handled in the same way as in TCP_ESTABLISHED case */;
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p))
- return -1;
- }
-
- if ((StreamTcpHandleFin(tv, stt, ssn, p, pq)) == -1)
- return -1;
-
- /* SYN/ACK */
- } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
- SCLogDebug("ssn %p: SYN/ACK packet on state SYN_RECV. resent", ssn);
-
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: SYN/ACK-pkt to server in SYN_RECV state", ssn);
-
- StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_TOSERVER_ON_SYN_RECV);
- return -1;
- }
-
- /* Check if the SYN/ACK packets ACK matches the earlier
- * received SYN/ACK packet. */
- if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) {
- SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
- "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
- ssn->client.isn + 1);
-
- StreamTcpSetEvent(p, STREAM_3WHS_SYNACK_RESEND_WITH_DIFFERENT_ACK);
- return -1;
- }
-
- /* Check if the SYN/ACK packet SEQ the earlier
- * received SYN/ACK packet, server resend with different ISN. */
- if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) {
- SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
- "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p),
- ssn->client.isn);
-
- if (StreamTcp3whsQueueSynAck(ssn, p) == -1)
- return -1;
- SCLogDebug("ssn %p: queued different SYN/ACK", ssn);
- }
-
- } else if (p->tcph->th_flags & TH_SYN) {
- SCLogDebug("ssn %p: SYN packet on state SYN_RECV... resent", ssn);
-
- if (PKT_IS_TOCLIENT(p)) {
- SCLogDebug("ssn %p: SYN-pkt to client in SYN_RECV state", ssn);
-
- StreamTcpSetEvent(p, STREAM_3WHS_SYN_TOCLIENT_ON_SYN_RECV);
- return -1;
- }
-
- if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
- SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
-
- StreamTcpSetEvent(p, STREAM_3WHS_SYN_RESEND_DIFF_SEQ_ON_SYN_RECV);
- return -1;
- }
-
- } else if (p->tcph->th_flags & TH_ACK) {
- if (ssn->queue_len) {
- SCLogDebug("ssn %p: checking ACK against queued SYN/ACKs", ssn);
- TcpStateQueue *q = StreamTcp3whsFindSynAckByAck(ssn, p);
- if (q != NULL) {
- SCLogDebug("ssn %p: here we update state against queued SYN/ACK", ssn);
- StreamTcp3whsSynAckUpdate(ssn, p, /* using queue to update state */q);
- } else {
- SCLogDebug("ssn %p: none found, now checking ACK against original SYN/ACK (state)", ssn);
- }
- }
-
-
- /* If the timestamp option is enabled for both the streams, then
- * validate the received packet timestamp value against the
- * stream->last_ts. If the timestamp is valid then process the
- * packet normally otherwise the drop the packet (RFC 1323)*/
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!(StreamTcpValidateTimestamp(ssn, p))) {
- return -1;
- }
- }
-
- if ((ssn->flags & STREAMTCP_FLAG_4WHS) && PKT_IS_TOCLIENT(p)) {
- SCLogDebug("ssn %p: ACK received on 4WHS session",ssn);
-
- if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))) {
- SCLogDebug("ssn %p: 4WHS wrong seq nr on packet", ssn);
- StreamTcpSetEvent(p, STREAM_4WHS_WRONG_SEQ);
- return -1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
- SCLogDebug("ssn %p: 4WHS invalid ack nr on packet", ssn);
- StreamTcpSetEvent(p, STREAM_4WHS_INVALID_ACK);
- return -1;
- }
-
- SCLogDebug("4WHS normal pkt");
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
- ssn->server.next_seq += p->payload_len;
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
-
- StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
- SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
-
- SCLogDebug("ssn %p: ssn->client.next_win %" PRIu32 ", "
- "ssn->client.last_ack %"PRIu32"", ssn,
- ssn->client.next_win, ssn->client.last_ack);
- return 0;
- }
-
- /* Check if the ACK received is in right direction. But when we have
- * picked up a mid stream session after missing the initial SYN pkt,
- * in this case the ACK packet can arrive from either client (normal
- * case) or from server itself (asynchronous streams). Therefore
- * the check has been avoided in this case */
- if (PKT_IS_TOCLIENT(p)) {
- /* special case, handle 4WHS, so SYN/ACK in the opposite
- * direction */
- if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK) {
- SCLogDebug("ssn %p: ACK received on midstream SYN/ACK "
- "pickup session",ssn);
- /* fall through */
- } else {
- SCLogDebug("ssn %p: ACK received in the wrong direction",
- ssn);
-
- StreamTcpSetEvent(p, STREAM_3WHS_ACK_IN_WRONG_DIR);
- return -1;
- }
- }
-
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ""
- ", ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
- TCP_GET_ACK(p));
-
- /* Check both seq and ack number before accepting the packet and
- changing to ESTABLISHED state */
- if ((SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) &&
- SEQ_EQ(TCP_GET_ACK(p), ssn->server.next_seq)) {
- SCLogDebug("normal pkt");
-
- /* process the packet normal, No Async streams :) */
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
-
- ssn->client.next_seq += p->payload_len;
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
-
- ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
-
- if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- ssn->client.next_win = ssn->client.last_ack + ssn->client.window;
- ssn->server.next_win = ssn->server.last_ack +
- ssn->server.window;
- if (!(ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)) {
- /* window scaling for midstream pickups, we can't do much
- * other than assume that it's set to the max value: 14 */
- ssn->server.wscale = TCP_WSCALE_MAX;
- ssn->client.wscale = TCP_WSCALE_MAX;
- ssn->flags |= STREAMTCP_FLAG_SACKOK;
- }
- }
-
- StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
- SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
-
- /* If asynchronous stream handling is allowed then set the session,
- if packet's seq number is equal the expected seq no.*/
- } else if (stream_config.async_oneside == TRUE &&
- (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)))
- {
- /*set the ASYNC flag used to indicate the session as async stream
- and helps in relaxing the windows checks.*/
- ssn->flags |= STREAMTCP_FLAG_ASYNC;
- ssn->server.next_seq += p->payload_len;
- ssn->server.last_ack = TCP_GET_SEQ(p);
-
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- ssn->client.last_ack = TCP_GET_ACK(p);
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
- ssn->server.window = TCP_GET_WINDOW(p);
- ssn->client.next_win = ssn->server.last_ack +
- ssn->server.window;
- /* window scaling for midstream pickups, we can't do much
- * other than assume that it's set to the max value: 14 */
- ssn->server.wscale = TCP_WSCALE_MAX;
- ssn->client.wscale = TCP_WSCALE_MAX;
- ssn->flags |= STREAMTCP_FLAG_SACKOK;
- }
-
- SCLogDebug("ssn %p: synrecv => Asynchronous stream, packet SEQ"
- " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
- "ssn->server.next_seq %" PRIu32 "\n"
- , ssn, TCP_GET_SEQ(p), p->payload_len, TCP_GET_SEQ(p)
- + p->payload_len, ssn->server.next_seq);
-
- StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
- SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- /* Upon receiving the packet with correct seq number and wrong
- ACK number, it causes the other end to send RST. But some target
- system (Linux & solaris) does not RST the connection, so it is
- likely to avoid the detection */
- } else if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)){
- ssn->flags |= STREAMTCP_FLAG_DETECTION_EVASION_ATTEMPT;
- SCLogDebug("ssn %p: wrong ack nr on packet, possible evasion!!",
- ssn);
-
- StreamTcpSetEvent(p, STREAM_3WHS_RIGHT_SEQ_WRONG_ACK_EVASION);
- return -1;
-
- /* if we get a packet with a proper ack, but a seq that is beyond
- * next_seq but in-window, we probably missed some packets */
- } else if (SEQ_GT(TCP_GET_SEQ(p), ssn->client.next_seq) &&
- SEQ_LEQ(TCP_GET_SEQ(p),ssn->client.next_win) &&
- SEQ_EQ(TCP_GET_ACK(p), ssn->server.next_seq))
- {
- SCLogDebug("ssn %p: ACK for missing data", ssn);
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
-
- ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
- SCLogDebug("ssn %p: ACK for missing data: ssn->client.next_seq %u", ssn, ssn->client.next_seq);
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
-
- ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
-
- if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) {
- ssn->client.window = TCP_GET_WINDOW(p);
- ssn->server.next_win = ssn->server.last_ack +
- ssn->server.window;
- /* window scaling for midstream pickups, we can't do much
- * other than assume that it's set to the max value: 14 */
- ssn->server.wscale = TCP_WSCALE_MAX;
- ssn->client.wscale = TCP_WSCALE_MAX;
- ssn->flags |= STREAMTCP_FLAG_SACKOK;
- }
-
- StreamTcpPacketSetState(p, ssn, TCP_ESTABLISHED);
- SCLogDebug("ssn %p: =~ ssn state is now TCP_ESTABLISHED", ssn);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- } else {
- SCLogDebug("ssn %p: wrong seq nr on packet", ssn);
-
- StreamTcpSetEvent(p, STREAM_3WHS_WRONG_SEQ_WRONG_ACK);
- return -1;
- }
-
- SCLogDebug("ssn %p: ssn->server.next_win %" PRIu32 ", "
- "ssn->server.last_ack %"PRIu32"", ssn,
- ssn->server.next_win, ssn->server.last_ack);
- } else {
- SCLogDebug("ssn %p: default case", ssn);
- }
-
- return 0;
-}
-
-/**
- * \brief Function to handle the TCP_ESTABLISHED state packets, which are
- * sent by the client to server. The function handles
- * ACK packets and call StreamTcpReassembleHandleSegment() to handle
- * the reassembly.
- *
- * Timestamp has already been checked at this point.
- *
- * \param tv Thread Variable containig input/output queue, cpu affinity etc.
- * \param ssn Pointer to the current TCP session
- * \param p Packet which has to be handled in this TCP state.
- * \param stt Strean Thread module registered to handle the stream handling
- */
-static int HandleEstablishedPacketToServer(ThreadVars *tv, TcpSession *ssn, Packet *p,
- StreamTcpThread *stt, PacketQueue *pq)
-{
- SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
- "ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p));
-
- if (StreamTcpValidateAck(ssn, &(ssn->server), p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_EST_INVALID_ACK);
- return -1;
- }
-
- /* check for Keep Alive */
- if ((p->payload_len == 0 || p->payload_len == 1) &&
- (TCP_GET_SEQ(p) == (ssn->client.next_seq - 1))) {
- SCLogDebug("ssn %p: pkt is keep alive", ssn);
-
- /* normal pkt */
- } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->client.last_ack))) {
- if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
- SCLogDebug("ssn %p: server => Asynchrouns stream, packet SEQ"
- " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
- " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
- "%" PRIu32"(%"PRIu32")", ssn, TCP_GET_SEQ(p),
- p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
- ssn->client.last_ack, ssn->client.next_win,
- TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
-
- /* update the last_ack to current seq number as the session is
- * async and other stream is not updating it anymore :( */
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
-
- } else if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p)) &&
- (stream_config.async_oneside == TRUE) &&
- (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) {
- SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ."
- " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
- "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
- "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
- p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
- ssn->client.last_ack, ssn->client.next_win,
- TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
-
- /* it seems we missed SYN and SYN/ACK packets of this session.
- * Update the last_ack to current seq number as the session
- * is async and other stream is not updating it anymore :( */
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
- ssn->flags |= STREAMTCP_FLAG_ASYNC;
-
- } else if (SEQ_EQ(ssn->client.last_ack, (ssn->client.isn + 1)) &&
- (stream_config.async_oneside == TRUE) &&
- (ssn->flags & STREAMTCP_FLAG_MIDSTREAM)) {
- SCLogDebug("ssn %p: server => Asynchronous stream, packet SEQ"
- " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
- "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
- "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
- p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
- ssn->client.last_ack, ssn->client.next_win,
- TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
-
- /* it seems we missed SYN and SYN/ACK packets of this session.
- * Update the last_ack to current seq number as the session
- * is async and other stream is not updating it anymore :(*/
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_SEQ(p));
- ssn->flags |= STREAMTCP_FLAG_ASYNC;
-
- /* if last ack is beyond next_seq, we have accepted ack's for missing data.
- * In this case we do accept the data before last_ack if it is (partly)
- * beyond next seq */
- } else if (SEQ_GT(ssn->client.last_ack, ssn->client.next_seq) &&
- SEQ_GT((TCP_GET_SEQ(p)+p->payload_len),ssn->client.next_seq))
- {
- SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16
- " before last_ack %"PRIu32", after next_seq %"PRIu32":"
- " acked data that we haven't seen before",
- ssn, TCP_GET_SEQ(p), p->payload_len, ssn->client.last_ack, ssn->client.next_seq);
- if (SEQ_EQ(TCP_GET_SEQ(p),ssn->client.next_seq)) {
- ssn->client.next_seq += p->payload_len;
- }
- } else {
- SCLogDebug("ssn %p: server => SEQ before last_ack, packet SEQ"
- " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "), "
- "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
- "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
- p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
- ssn->client.last_ack, ssn->client.next_win,
- TCP_GET_SEQ(p) + p->payload_len - ssn->client.next_win);
-
- SCLogDebug("ssn %p: rejecting because pkt before last_ack", ssn);
- StreamTcpSetEvent(p, STREAM_EST_PKT_BEFORE_LAST_ACK);
- return -1;
- }
- }
-
- int zerowindowprobe = 0;
- /* zero window probe */
- if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->client.next_seq && ssn->client.window == 0) {
- SCLogDebug("ssn %p: zero window probe", ssn);
- zerowindowprobe = 1;
-
- /* expected packet */
- } else if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
- ssn->client.next_seq += p->payload_len;
- SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "",
- ssn, ssn->client.next_seq);
- /* not completely as expected, but valid */
- } else if (SEQ_LT(TCP_GET_SEQ(p),ssn->client.next_seq) &&
- SEQ_GT((TCP_GET_SEQ(p)+p->payload_len), ssn->client.next_seq))
- {
- ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
- SCLogDebug("ssn %p: ssn->client.next_seq %"PRIu32
- " (started before next_seq, ended after)",
- ssn, ssn->client.next_seq);
- /* if next_seq has fallen behind last_ack, we got some catching up to do */
- } else if (SEQ_LT(ssn->client.next_seq, ssn->client.last_ack)) {
- ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
- SCLogDebug("ssn %p: ssn->client.next_seq %"PRIu32
- " (next_seq had fallen behind last_ack)",
- ssn, ssn->client.next_seq);
- } else {
- SCLogDebug("ssn %p: no update to ssn->client.next_seq %"PRIu32
- " SEQ %u SEQ+ %u last_ack %u",
- ssn, ssn->client.next_seq,
- TCP_GET_SEQ(p), TCP_GET_SEQ(p)+p->payload_len, ssn->client.last_ack);
- }
-
- /* in window check */
- if (zerowindowprobe) {
- SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
- } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
- (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) ||
- (ssn->flags & STREAMTCP_FLAG_ASYNC))
- {
- SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
- "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
-
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
- SCLogDebug("ssn %p: ssn->server.window %"PRIu32"", ssn,
- ssn->server.window);
-
- /* Check if the ACK value is sane and inside the window limit */
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
- SCLogDebug("ack %u last_ack %u next_seq %u", TCP_GET_ACK(p), ssn->server.last_ack, ssn->server.next_seq);
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpSackUpdatePacket(&ssn->server, p);
-
- /* update next_win */
- StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
-
- /* handle data (if any) */
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
- } else {
- SCLogDebug("ssn %p: toserver => SEQ out of window, packet SEQ "
- "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
- "ssn->client.last_ack %" PRIu32 ", ssn->client.next_win "
- "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
- p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
- ssn->client.last_ack, ssn->client.next_win,
- (TCP_GET_SEQ(p) + p->payload_len) - ssn->client.next_win);
- SCLogDebug("ssn %p: window %u sacked %u", ssn, ssn->client.window,
- StreamTcpSackedSize(&ssn->client));
- StreamTcpSetEvent(p, STREAM_EST_PACKET_OUT_OF_WINDOW);
- return -1;
- }
- return 0;
-}
-
-/**
- * \brief Function to handle the TCP_ESTABLISHED state packets, which are
- * sent by the server to client. The function handles
- * ACK packets and call StreamTcpReassembleHandleSegment() to handle
- * the reassembly
- *
- * Timestamp has already been checked at this point.
- *
- * \param tv Thread Variable containig input/output queue, cpu affinity etc.
- * \param ssn Pointer to the current TCP session
- * \param p Packet which has to be handled in this TCP state.
- * \param stt Strean Thread module registered to handle the stream handling
- */
-static int HandleEstablishedPacketToClient(ThreadVars *tv, TcpSession *ssn, Packet *p,
- StreamTcpThread *stt, PacketQueue *pq)
-{
- SCLogDebug("ssn %p: =+ pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ","
- " ACK %" PRIu32 ", WIN %"PRIu16"", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p), TCP_GET_WINDOW(p));
-
- if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_EST_INVALID_ACK);
- return -1;
- }
-
- /* To get the server window value from the servers packet, when connection
- is picked up as midstream */
- if ((ssn->flags & STREAMTCP_FLAG_MIDSTREAM) &&
- (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED))
- {
- ssn->server.window = TCP_GET_WINDOW(p);
- ssn->server.next_win = ssn->server.last_ack + ssn->server.window;
- ssn->flags &= ~STREAMTCP_FLAG_MIDSTREAM_ESTABLISHED;
- SCLogDebug("ssn %p: adjusted midstream ssn->server.next_win to "
- "%" PRIu32 "", ssn, ssn->server.next_win);
- }
-
- /* check for Keep Alive */
- if ((p->payload_len == 0 || p->payload_len == 1) &&
- (TCP_GET_SEQ(p) == (ssn->server.next_seq - 1))) {
- SCLogDebug("ssn %p: pkt is keep alive", ssn);
-
- /* normal pkt */
- } else if (!(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len), ssn->server.last_ack))) {
- if (ssn->flags & STREAMTCP_FLAG_ASYNC) {
-
- SCLogDebug("ssn %p: client => Asynchrouns stream, packet SEQ"
- " %" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
- " ssn->client.last_ack %" PRIu32 ", ssn->client.next_win"
- " %"PRIu32"(%"PRIu32")", ssn, TCP_GET_SEQ(p),
- p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
- ssn->server.last_ack, ssn->server.next_win,
- TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win);
-
- ssn->server.last_ack = TCP_GET_SEQ(p);
-
- /* if last ack is beyond next_seq, we have accepted ack's for missing data.
- * In this case we do accept the data before last_ack if it is (partly)
- * beyond next seq */
- } else if (SEQ_GT(ssn->server.last_ack, ssn->server.next_seq) &&
- SEQ_GT((TCP_GET_SEQ(p)+p->payload_len),ssn->server.next_seq))
- {
- SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16
- " before last_ack %"PRIu32", after next_seq %"PRIu32":"
- " acked data that we haven't seen before",
- ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
- if (SEQ_EQ(TCP_GET_SEQ(p),ssn->server.next_seq)) {
- ssn->server.next_seq += p->payload_len;
- }
- } else {
- SCLogDebug("ssn %p: PKT SEQ %"PRIu32" payload_len %"PRIu16
- " before last_ack %"PRIu32". next_seq %"PRIu32,
- ssn, TCP_GET_SEQ(p), p->payload_len, ssn->server.last_ack, ssn->server.next_seq);
- StreamTcpSetEvent(p, STREAM_EST_PKT_BEFORE_LAST_ACK);
- return -1;
- }
- }
-
- int zerowindowprobe = 0;
- /* zero window probe */
- if (p->payload_len == 1 && TCP_GET_SEQ(p) == ssn->server.next_seq && ssn->server.window == 0) {
- SCLogDebug("ssn %p: zero window probe", ssn);
- zerowindowprobe = 1;
-
- /* expected packet */
- } else if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
- ssn->server.next_seq += p->payload_len;
- SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "",
- ssn, ssn->server.next_seq);
- /* not completely as expected, but valid */
- } else if (SEQ_LT(TCP_GET_SEQ(p),ssn->server.next_seq) &&
- SEQ_GT((TCP_GET_SEQ(p)+p->payload_len), ssn->server.next_seq))
- {
- ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len;
- SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32
- " (started before next_seq, ended after)",
- ssn, ssn->server.next_seq);
- /* if next_seq has fallen behind last_ack, we got some catching up to do */
- } else if (SEQ_LT(ssn->server.next_seq, ssn->server.last_ack)) {
- ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len;
- SCLogDebug("ssn %p: ssn->server.next_seq %"PRIu32
- " (next_seq had fallen behind last_ack)",
- ssn, ssn->server.next_seq);
- } else {
- SCLogDebug("ssn %p: no update to ssn->server.next_seq %"PRIu32
- " SEQ %u SEQ+ %u last_ack %u",
- ssn, ssn->server.next_seq,
- TCP_GET_SEQ(p), TCP_GET_SEQ(p)+p->payload_len, ssn->server.last_ack);
- }
-
- if (zerowindowprobe) {
- SCLogDebug("ssn %p: zero window probe, skipping oow check", ssn);
- } else if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
- (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) ||
- (ssn->flags & STREAMTCP_FLAG_ASYNC)) {
- SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
- "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- SCLogDebug("ssn %p: ssn->client.window %"PRIu32"", ssn,
- ssn->client.window);
-
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpSackUpdatePacket(&ssn->client, p);
-
- StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq);
- } else {
- SCLogDebug("ssn %p: client => SEQ out of window, packet SEQ"
- "%" PRIu32 ", payload size %" PRIu32 " (%" PRIu32 "),"
- " ssn->server.last_ack %" PRIu32 ", ssn->server.next_win "
- "%" PRIu32 "(%"PRIu32")", ssn, TCP_GET_SEQ(p),
- p->payload_len, TCP_GET_SEQ(p) + p->payload_len,
- ssn->server.last_ack, ssn->server.next_win,
- TCP_GET_SEQ(p) + p->payload_len - ssn->server.next_win);
- StreamTcpSetEvent(p, STREAM_EST_PACKET_OUT_OF_WINDOW);
- return -1;
- }
- return 0;
-}
-
-/**
- * \internal
- *
- * \brief Find the highest sequence number needed to consider all segments as ACK'd
- *
- * Used to treat all segments as ACK'd upon receiving a valid RST.
- *
- * \param stream stream to inspect the segments from
- * \param seq sequence number to check against
- *
- * \retval ack highest ack we need to set
- */
-static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq)
-{
- uint32_t ack = seq;
-
- if (stream->seg_list_tail != NULL) {
- if (SEQ_GT((stream->seg_list_tail->seq + stream->seg_list_tail->payload_len), ack))
- {
- ack = stream->seg_list_tail->seq + stream->seg_list_tail->payload_len;
- }
- }
-
- SCReturnUInt(ack);
-}
-
-/**
- * \brief Function to handle the TCP_ESTABLISHED state. The function handles
- * ACK, FIN, RST packets and correspondingly changes the connection
- * state. The function handles the data inside packets and call
- * StreamTcpReassembleHandleSegment(tv, ) to handle the reassembling.
- *
- * \param tv Thread Variable containig input/output queue, cpu affinity etc.
- * \param p Packet which has to be handled in this TCP state.
- * \param stt Strean Thread module registered to handle the stream handling
- */
-
-static int StreamTcpPacketStateEstablished(ThreadVars *tv, Packet *p,
- StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
-{
- if (ssn == NULL)
- return -1;
-
- if (p->tcph->th_flags & TH_RST) {
- if (!StreamTcpValidateRst(ssn, p))
- return -1;
-
- /* force both streams to reassemble, if necessary */
- StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq);
-
- if (PKT_IS_TOSERVER(p)) {
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: Reset received and state changed to "
- "TCP_CLOSED", ssn);
-
- ssn->server.next_seq = TCP_GET_ACK(p);
- ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
- SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
- ssn->server.next_seq);
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
-
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->client.next_seq,
- ssn->server.last_ack);
-
- /* don't return packets to pools here just yet, the pseudo
- * packet will take care, otherwise the normal session
- * cleanup. */
- } else {
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: Reset received and state changed to "
- "TCP_CLOSED", ssn);
-
- ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len + 1;
- ssn->client.next_seq = TCP_GET_ACK(p);
-
- SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
- ssn->server.next_seq);
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
-
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->server.next_seq,
- ssn->client.last_ack);
-
- /* don't return packets to pools here just yet, the pseudo
- * packet will take care, otherwise the normal session
- * cleanup. */
- }
-
- } else if (p->tcph->th_flags & TH_FIN) {
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p))
- return -1;
- }
-
- SCLogDebug("ssn (%p: FIN received SEQ"
- " %" PRIu32 ", last ACK %" PRIu32 ", next win %"PRIu32","
- " win %" PRIu32 "", ssn, ssn->server.next_seq,
- ssn->client.last_ack, ssn->server.next_win,
- ssn->server.window);
-
- if ((StreamTcpHandleFin(tv, stt, ssn, p, pq)) == -1)
- return -1;
-
- /* SYN/ACK */
- } else if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
- SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent",
- ssn);
-
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: SYN/ACK-pkt to server in ESTABLISHED state", ssn);
-
- StreamTcpSetEvent(p, STREAM_EST_SYNACK_TOSERVER);
- return -1;
- }
-
- /* Check if the SYN/ACK packets ACK matches the earlier
- * received SYN/ACK packet. */
- if (!(SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack))) {
- SCLogDebug("ssn %p: ACK mismatch, packet ACK %" PRIu32 " != "
- "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
- ssn->client.isn + 1);
-
- StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND_WITH_DIFFERENT_ACK);
- return -1;
- }
-
- /* Check if the SYN/ACK packet SEQ the earlier
- * received SYN packet. */
- if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.isn))) {
- SCLogDebug("ssn %p: SEQ mismatch, packet SEQ %" PRIu32 " != "
- "%" PRIu32 " from stream", ssn, TCP_GET_ACK(p),
- ssn->client.isn + 1);
-
- StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND_WITH_DIFF_SEQ);
- return -1;
- }
-
- if (ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED) {
- /* a resend of a SYN while we are established already -- fishy */
- StreamTcpSetEvent(p, STREAM_EST_SYNACK_RESEND);
- return -1;
- }
-
- SCLogDebug("ssn %p: SYN/ACK packet on state ESTABLISHED... resent. "
- "Likely due server not receiving final ACK in 3whs", ssn);
-
- /* resetting state to TCP_SYN_RECV as we should get another ACK now */
- StreamTcpPacketSetState(p, ssn, TCP_SYN_RECV);
- SCLogDebug("ssn %p: =~ ssn state is now reset to TCP_SYN_RECV", ssn);
- return 0;
-
- } else if (p->tcph->th_flags & TH_SYN) {
- SCLogDebug("ssn %p: SYN packet on state ESTABLISED... resent", ssn);
- if (PKT_IS_TOCLIENT(p)) {
- SCLogDebug("ssn %p: SYN-pkt to client in EST state", ssn);
-
- StreamTcpSetEvent(p, STREAM_EST_SYN_TOCLIENT);
- return -1;
- }
-
- if (!(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.isn))) {
- SCLogDebug("ssn %p: SYN with different SEQ on SYN_RECV state", ssn);
-
- StreamTcpSetEvent(p, STREAM_EST_SYN_RESEND_DIFF_SEQ);
- return -1;
- }
-
- /* a resend of a SYN while we are established already -- fishy */
- StreamTcpSetEvent(p, STREAM_EST_SYN_RESEND);
- return -1;
-
- } else if (p->tcph->th_flags & TH_ACK) {
- /* Urgent pointer size can be more than the payload size, as it tells
- * the future coming data from the sender will be handled urgently
- * until data of size equal to urgent offset has been processed
- * (RFC 2147) */
-
- /* If the timestamp option is enabled for both the streams, then
- * validate the received packet timestamp value against the
- * stream->last_ts. If the timestamp is valid then process the
- * packet normally otherwise the drop the packet (RFC 1323) */
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p))
- return -1;
- }
-
- if (PKT_IS_TOSERVER(p)) {
- /* Process the received packet to server */
- HandleEstablishedPacketToServer(tv, ssn, p, stt, pq);
-
- SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
- " next win %" PRIu32 ", win %" PRIu32 "", ssn,
- ssn->client.next_seq, ssn->server.last_ack
- ,ssn->client.next_win, ssn->client.window);
-
- } else { /* implied to client */
- if (!(ssn->flags & STREAMTCP_FLAG_3WHS_CONFIRMED)) {
- ssn->flags |= STREAMTCP_FLAG_3WHS_CONFIRMED;
- SCLogDebug("3whs is now confirmed by server");
- }
-
- /* Process the received packet to client */
- HandleEstablishedPacketToClient(tv, ssn, p, stt, pq);
-
- SCLogDebug("ssn %p: next SEQ %" PRIu32 ", last ACK %" PRIu32 ","
- " next win %" PRIu32 ", win %" PRIu32 "", ssn,
- ssn->server.next_seq, ssn->client.last_ack,
- ssn->server.next_win, ssn->server.window);
- }
- } else {
- SCLogDebug("ssn %p: default case", ssn);
- }
-
- return 0;
-}
-
-/**
- * \brief Function to handle the FIN packets for states TCP_SYN_RECV and
- * TCP_ESTABLISHED and changes to another TCP state as required.
- *
- * \param tv Thread Variable containig input/output queue, cpu affinity
- * \param p Packet which has to be handled in this TCP state.
- * \param stt Strean Thread module registered to handle the stream handling
- *
- * \retval 0 success
- * \retval -1 something wrong with the packet
- */
-
-static int StreamTcpHandleFin(ThreadVars *tv, StreamTcpThread *stt,
- TcpSession *ssn, Packet *p, PacketQueue *pq)
-{
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ %" PRIu32 ","
- " ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
- TCP_GET_ACK(p));
-
- if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_FIN_INVALID_ACK);
- return -1;
- }
-
- if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
- SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
- {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
- "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p),
- ssn->client.next_seq);
-
- StreamTcpSetEvent(p, STREAM_FIN_OUT_OF_WINDOW);
- return -1;
- }
-
- StreamTcpPacketSetState(p, ssn, TCP_CLOSE_WAIT);
- SCLogDebug("ssn %p: state changed to TCP_CLOSE_WAIT", ssn);
-
- if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq))
- ssn->client.next_seq = TCP_GET_SEQ(p) + p->payload_len;
-
- SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "", ssn,
- ssn->client.next_seq);
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
-
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client packet
- and server has already received and acked it */
- if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
- ssn->server.next_seq = TCP_GET_ACK(p);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->client, p, pq);
-
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
- ssn, ssn->client.next_seq, ssn->server.last_ack);
- } else { /* implied to client */
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ %" PRIu32 ", "
- "ACK %" PRIu32 "", ssn, p->payload_len, TCP_GET_SEQ(p),
- TCP_GET_ACK(p));
-
- if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_FIN_INVALID_ACK);
- return -1;
- }
-
- if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
- SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
- {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 " != "
- "%" PRIu32 " from stream", ssn, TCP_GET_SEQ(p),
- ssn->server.next_seq);
-
- StreamTcpSetEvent(p, STREAM_FIN_OUT_OF_WINDOW);
- return -1;
- }
-
- StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT1);
- SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT1", ssn);
-
- if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq))
- ssn->server.next_seq = TCP_GET_SEQ(p) + p->payload_len;
-
- SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "", ssn,
- ssn->server.next_seq);
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
-
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client packet
- and server has already received and acked it */
- if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
- ssn->client.next_seq = TCP_GET_ACK(p);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn, &ssn->server, p, pq);
-
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK %" PRIu32 "",
- ssn, ssn->server.next_seq, ssn->client.last_ack);
- }
-
- return 0;
-}
-
-/**
- * \brief Function to handle the TCP_FIN_WAIT1 state. The function handles
- * ACK, FIN, RST packets and correspondingly changes the connection
- * state.
- *
- * \param tv Thread Variable containig input/output queue, cpu affinity
- * \param p Packet which has to be handled in this TCP state.
- * \param stt Strean Thread module registered to handle the stream handling
- *
- * \retval 0 success
- * \retval -1 something wrong with the packet
- */
-
-static int StreamTcpPacketStateFinWait1(ThreadVars *tv, Packet *p,
- StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
-{
- if (ssn == NULL)
- return -1;
-
- if (p->tcph->th_flags & TH_RST) {
- if (!StreamTcpValidateRst(ssn, p))
- return -1;
-
- /* force both streams to reassemble, if necessary */
- StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq);
-
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
- ssn);
-
- if (PKT_IS_TOSERVER(p)) {
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- } else {
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- }
-
- } else if ((p->tcph->th_flags & (TH_FIN|TH_ACK)) == (TH_FIN|TH_ACK)) {
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p))
- return -1;
- }
-
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- int retransmission = 0;
-
- if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
-
- } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
- SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
- {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->client.next_seq);
- StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ);
- return -1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
- return -1;
- }
-
- if (!retransmission) {
- StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
- SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
-
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
- ssn->server.next_seq = TCP_GET_ACK(p);
-
- if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
- ssn->client.next_seq += p->payload_len;
- SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "",
- ssn, ssn->client.next_seq);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
-
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->client.next_seq,
- ssn->server.last_ack);
- } else { /* implied to client */
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- int retransmission = 0;
-
- if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
-
- } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
- SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
- {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->server.next_seq);
- StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ);
- return -1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
- return -1;
- }
-
- if (!retransmission) {
- StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
- SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
-
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
- ssn->client.next_seq = TCP_GET_ACK(p);
-
- if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
- ssn->server.next_seq += p->payload_len;
- SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "",
- ssn, ssn->server.next_seq);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
-
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->server.next_seq,
- ssn->client.last_ack);
- }
-
- } else if (p->tcph->th_flags & TH_FIN) {
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p))
- return -1;
- }
-
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- int retransmission = 0;
-
- if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
-
- } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
- SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
- {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->client.next_seq);
- StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ);
- return -1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
- return -1;
- }
-
- if (!retransmission) {
- StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
- SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
-
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
- ssn->server.next_seq = TCP_GET_ACK(p);
-
- if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
- ssn->client.next_seq += p->payload_len;
- SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "",
- ssn, ssn->client.next_seq);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
-
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->client.next_seq,
- ssn->server.last_ack);
- } else { /* implied to client */
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
-
- int retransmission = 0;
-
- if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
-
- } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
- SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
- {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->server.next_seq);
- StreamTcpSetEvent(p, STREAM_FIN1_FIN_WRONG_SEQ);
- return -1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
- return -1;
- }
-
- if (!retransmission) {
- StreamTcpPacketSetState(p, ssn, TCP_CLOSING);
- SCLogDebug("ssn %p: state changed to TCP_CLOSING", ssn);
-
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
- ssn->client.next_seq = TCP_GET_ACK(p);
-
- if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
- ssn->server.next_seq += p->payload_len;
- SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "",
- ssn, ssn->server.next_seq);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
-
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->server.next_seq,
- ssn->client.last_ack);
- }
- } else if (p->tcph->th_flags & TH_SYN) {
- SCLogDebug("ssn (%p): SYN pkt on FinWait1", ssn);
- StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND);
- return -1;
-
- } else if (p->tcph->th_flags & TH_ACK) {
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p))
- return -1;
- }
-
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- int retransmission = 0;
-
- if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
- return -1;
- }
-
- if (!retransmission) {
- if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
- (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) ||
- ssn->flags & STREAMTCP_FLAG_ASYNC)
- {
- SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
- "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
-
- if (TCP_GET_SEQ(p) == ssn->client.next_seq) {
- StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
- SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
- }
- } else {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->client.next_seq);
-
- StreamTcpSetEvent(p, STREAM_FIN1_ACK_WRONG_SEQ);
- return -1;
- }
-
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
- ssn->server.next_seq = TCP_GET_ACK(p);
-
- if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
- ssn->client.next_seq += p->payload_len;
- SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "",
- ssn, ssn->client.next_seq);
- }
-
- StreamTcpSackUpdatePacket(&ssn->server, p);
-
- /* update next_win */
- StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
-
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->client.next_seq,
- ssn->server.last_ack);
-
- } else { /* implied to client */
-
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
-
- int retransmission = 0;
-
- if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_FIN1_INVALID_ACK);
- return -1;
- }
-
- if (!retransmission) {
- if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
- (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) ||
- (ssn->flags & STREAMTCP_FLAG_ASYNC))
- {
- SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
- "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
-
- if (TCP_GET_SEQ(p) == ssn->server.next_seq) {
- StreamTcpPacketSetState(p, ssn, TCP_FIN_WAIT2);
- SCLogDebug("ssn %p: state changed to TCP_FIN_WAIT2", ssn);
- }
- } else {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->server.next_seq);
- StreamTcpSetEvent(p, STREAM_FIN1_ACK_WRONG_SEQ);
- return -1;
- }
-
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
- ssn->client.next_seq = TCP_GET_ACK(p);
-
- if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
- ssn->server.next_seq += p->payload_len;
- SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "",
- ssn, ssn->server.next_seq);
- }
-
- StreamTcpSackUpdatePacket(&ssn->client, p);
-
- /* update next_win */
- StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
-
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->server.next_seq,
- ssn->client.last_ack);
- }
- } else {
- SCLogDebug("ssn (%p): default case", ssn);
- }
-
- return 0;
-}
-
-/**
- * \brief Function to handle the TCP_FIN_WAIT2 state. The function handles
- * ACK, RST, FIN packets and correspondingly changes the connection
- * state.
- *
- * \param tv Thread Variable containig input/output queue, cpu affinity
- * \param p Packet which has to be handled in this TCP state.
- * \param stt Strean Thread module registered to handle the stream handling
- */
-
-static int StreamTcpPacketStateFinWait2(ThreadVars *tv, Packet *p,
- StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
-{
- if (ssn == NULL)
- return -1;
-
- if (p->tcph->th_flags & TH_RST) {
- if (!StreamTcpValidateRst(ssn, p))
- return -1;
-
- /* force both streams to reassemble, if necessary */
- StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq);
-
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
- ssn);
-
- if (PKT_IS_TOSERVER(p)) {
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- } else {
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- }
-
- } else if (p->tcph->th_flags & TH_FIN) {
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p))
- return -1;
- }
-
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- int retransmission = 0;
-
- if (SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq - 1) &&
- SEQ_EQ(TCP_GET_ACK(p), ssn->server.last_ack)) {
- SCLogDebug("ssn %p: retransmission", ssn);
- retransmission = 1;
- } else if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
-
- } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
- SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
- {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
- "%" PRIu32 " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->client.next_seq);
- StreamTcpSetEvent(p, STREAM_FIN2_FIN_WRONG_SEQ);
- return -1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_FIN2_INVALID_ACK);
- return -1;
- }
-
- if (!retransmission) {
- StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
- SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
-
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
- ssn->server.next_seq = TCP_GET_ACK(p);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
-
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->client.next_seq,
- ssn->server.last_ack);
- } else { /* implied to client */
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- int retransmission = 0;
-
- if (SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq - 1) &&
- SEQ_EQ(TCP_GET_ACK(p), ssn->client.last_ack)) {
- SCLogDebug("ssn %p: retransmission", ssn);
- retransmission = 1;
- } else if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
-
- } else if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
- SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
- {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ "
- "%" PRIu32 " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->server.next_seq);
- StreamTcpSetEvent(p, STREAM_FIN2_FIN_WRONG_SEQ);
- return -1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_FIN2_INVALID_ACK);
- return -1;
- }
-
- if (!retransmission) {
- StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
- SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
-
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
- ssn->client.next_seq = TCP_GET_ACK(p);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->server.next_seq,
- ssn->client.last_ack);
- }
-
- } else if (p->tcph->th_flags & TH_SYN) {
- SCLogDebug("ssn (%p): SYN pkt on FinWait2", ssn);
- StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND);
- return -1;
-
- } else if (p->tcph->th_flags & TH_ACK) {
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p))
- return -1;
- }
-
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- int retransmission = 0;
-
- if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_FIN2_INVALID_ACK);
- return -1;
- }
-
- if (!retransmission) {
- if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->client.next_win) ||
- (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) ||
- (ssn->flags & STREAMTCP_FLAG_ASYNC))
- {
- SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->client.next_win "
- "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->client.next_win);
-
- } else {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->client.next_seq);
- StreamTcpSetEvent(p, STREAM_FIN2_ACK_WRONG_SEQ);
- return -1;
- }
-
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- if (SEQ_EQ(ssn->client.next_seq, TCP_GET_SEQ(p))) {
- ssn->client.next_seq += p->payload_len;
- SCLogDebug("ssn %p: ssn->client.next_seq %" PRIu32 "",
- ssn, ssn->client.next_seq);
- }
-
- StreamTcpSackUpdatePacket(&ssn->server, p);
-
- /* update next_win */
- StreamTcpUpdateNextWin(ssn, &ssn->server, (ssn->server.last_ack + ssn->server.window));
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
-
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->client.next_seq,
- ssn->server.last_ack);
- } else { /* implied to client */
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- int retransmission = 0;
-
- if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_FIN2_INVALID_ACK);
- return -1;
- }
-
- if (!retransmission) {
- if (SEQ_LEQ(TCP_GET_SEQ(p) + p->payload_len, ssn->server.next_win) ||
- (ssn->flags & STREAMTCP_FLAG_MIDSTREAM) ||
- (ssn->flags & STREAMTCP_FLAG_ASYNC))
- {
- SCLogDebug("ssn %p: seq %"PRIu32" in window, ssn->server.next_win "
- "%" PRIu32 "", ssn, TCP_GET_SEQ(p), ssn->server.next_win);
- } else {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->server.next_seq);
- StreamTcpSetEvent(p, STREAM_FIN2_ACK_WRONG_SEQ);
- return -1;
- }
-
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- if (SEQ_EQ(ssn->server.next_seq, TCP_GET_SEQ(p))) {
- ssn->server.next_seq += p->payload_len;
- SCLogDebug("ssn %p: ssn->server.next_seq %" PRIu32 "",
- ssn, ssn->server.next_seq);
- }
-
- StreamTcpSackUpdatePacket(&ssn->client, p);
-
- /* update next_win */
- StreamTcpUpdateNextWin(ssn, &ssn->client, (ssn->client.last_ack + ssn->client.window));
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
-
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->server.next_seq,
- ssn->client.last_ack);
- }
- } else {
- SCLogDebug("ssn %p: default case", ssn);
- }
-
- return 0;
-}
-
-/**
- * \brief Function to handle the TCP_CLOSING state. Upon arrival of ACK
- * the connection goes to TCP_TIME_WAIT state. The state has been
- * reached as both end application has been closed.
- *
- * \param tv Thread Variable containig input/output queue, cpu affinity
- * \param p Packet which has to be handled in this TCP state.
- * \param stt Strean Thread module registered to handle the stream handling
- */
-
-static int StreamTcpPacketStateClosing(ThreadVars *tv, Packet *p,
- StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
-{
- if (ssn == NULL)
- return -1;
-
- if (p->tcph->th_flags & TH_RST) {
- if (!StreamTcpValidateRst(ssn, p))
- return -1;
-
- /* force both streams to reassemble, if necessary */
- StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq);
-
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
- ssn);
-
- if (PKT_IS_TOSERVER(p)) {
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- } else {
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- }
-
- } else if (p->tcph->th_flags & TH_SYN) {
- SCLogDebug("ssn (%p): SYN pkt on Closing", ssn);
- StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND);
- return -1;
-
- } else if (p->tcph->th_flags & TH_ACK) {
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p))
- return -1;
- }
-
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- int retransmission = 0;
- if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
- }
-
- if (TCP_GET_SEQ(p) != ssn->client.next_seq) {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->client.next_seq);
- StreamTcpSetEvent(p, STREAM_CLOSING_ACK_WRONG_SEQ);
- return -1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_CLOSING_INVALID_ACK);
- return -1;
- }
-
- if (!retransmission) {
- StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
- SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
-
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
- ssn->server.next_seq = TCP_GET_ACK(p);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->client.next_seq,
- ssn->server.last_ack);
- } else { /* implied to client */
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- int retransmission = 0;
- if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
- }
-
- if (TCP_GET_SEQ(p) != ssn->server.next_seq) {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->server.next_seq);
- StreamTcpSetEvent(p, STREAM_CLOSING_ACK_WRONG_SEQ);
- return -1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_CLOSING_INVALID_ACK);
- return -1;
- }
-
- if (!retransmission) {
- StreamTcpPacketSetState(p, ssn, TCP_TIME_WAIT);
- SCLogDebug("ssn %p: state changed to TCP_TIME_WAIT", ssn);
-
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
- ssn->client.next_seq = TCP_GET_ACK(p);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- SCLogDebug("StreamTcpPacketStateClosing (%p): =+ next SEQ "
- "%" PRIu32 ", last ACK %" PRIu32 "", ssn,
- ssn->server.next_seq, ssn->client.last_ack);
- }
- } else {
- SCLogDebug("ssn %p: default case", ssn);
- }
-
- return 0;
-}
-
-/**
- * \brief Function to handle the TCP_CLOSE_WAIT state. Upon arrival of FIN
- * packet from server the connection goes to TCP_LAST_ACK state.
- * The state is possible only for server host.
- *
- * \param tv Thread Variable containig input/output queue, cpu affinity
- * \param p Packet which has to be handled in this TCP state.
- * \param stt Strean Thread module registered to handle the stream handling
- */
-
-static int StreamTcpPacketStateCloseWait(ThreadVars *tv, Packet *p,
- StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
-{
- SCEnter();
-
- if (ssn == NULL) {
- SCReturnInt(-1);
- }
-
- if (PKT_IS_TOCLIENT(p)) {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- } else {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- }
-
- if (p->tcph->th_flags & TH_RST) {
- if (!StreamTcpValidateRst(ssn, p))
- return -1;
-
- /* force both streams to reassemble, if necessary */
- StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq);
-
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
- ssn);
-
- if (PKT_IS_TOSERVER(p)) {
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- } else {
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- }
-
- } else if (p->tcph->th_flags & TH_FIN) {
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p))
- SCReturnInt(-1);
- }
-
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
-
- int retransmission = 0;
- if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
- }
-
- if (!retransmission) {
- if (SEQ_LT(TCP_GET_SEQ(p), ssn->client.next_seq) ||
- SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
- {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->client.next_seq);
- StreamTcpSetEvent(p, STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW);
- SCReturnInt(-1);
- }
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_CLOSEWAIT_INVALID_ACK);
- SCReturnInt(-1);
- }
-
- /* don't update to LAST_ACK here as we want a toclient FIN for that */
-
- if (!retransmission)
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
-
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
- ssn->server.next_seq = TCP_GET_ACK(p);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->client.next_seq,
- ssn->server.last_ack);
- } else {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
-
- int retransmission = 0;
- if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
- }
-
- if (!retransmission) {
- if (SEQ_LT(TCP_GET_SEQ(p), ssn->server.next_seq) ||
- SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
- {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->server.next_seq);
- StreamTcpSetEvent(p, STREAM_CLOSEWAIT_FIN_OUT_OF_WINDOW);
- SCReturnInt(-1);
- }
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_CLOSEWAIT_INVALID_ACK);
- SCReturnInt(-1);
- }
-
- if (!retransmission) {
- StreamTcpPacketSetState(p, ssn, TCP_LAST_ACK);
- SCLogDebug("ssn %p: state changed to TCP_LAST_ACK", ssn);
-
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
- ssn->client.next_seq = TCP_GET_ACK(p);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->server.next_seq,
- ssn->client.last_ack);
- }
-
- } else if (p->tcph->th_flags & TH_SYN) {
- SCLogDebug("ssn (%p): SYN pkt on CloseWait", ssn);
- StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND);
- SCReturnInt(-1);
-
- } else if (p->tcph->th_flags & TH_ACK) {
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p))
- SCReturnInt(-1);
- }
-
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
-
- int retransmission = 0;
- if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
- }
-
- if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->client.last_ack))) {
- SCLogDebug("ssn %p: -> retransmission", ssn);
- StreamTcpSetEvent(p, STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK);
- SCReturnInt(-1);
-
- } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->client.last_ack + ssn->client.window)))
- {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->client.next_seq);
- StreamTcpSetEvent(p, STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW);
- SCReturnInt(-1);
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_CLOSEWAIT_INVALID_ACK);
- SCReturnInt(-1);
- }
-
- if (!retransmission) {
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
- ssn->server.next_seq = TCP_GET_ACK(p);
-
- if (SEQ_EQ(TCP_GET_SEQ(p),ssn->client.next_seq))
- ssn->client.next_seq += p->payload_len;
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->client.next_seq,
- ssn->server.last_ack);
- } else {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- int retransmission = 0;
- if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
- }
-
- if (p->payload_len > 0 && (SEQ_LEQ((TCP_GET_SEQ(p) + p->payload_len), ssn->server.last_ack))) {
- SCLogDebug("ssn %p: -> retransmission", ssn);
- StreamTcpSetEvent(p, STREAM_CLOSEWAIT_PKT_BEFORE_LAST_ACK);
- SCReturnInt(-1);
-
- } else if (SEQ_GT(TCP_GET_SEQ(p), (ssn->server.last_ack + ssn->server.window)))
- {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->server.next_seq);
- StreamTcpSetEvent(p, STREAM_CLOSEWAIT_ACK_OUT_OF_WINDOW);
- SCReturnInt(-1);
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_CLOSEWAIT_INVALID_ACK);
- SCReturnInt(-1);
- }
-
- if (!retransmission) {
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
- ssn->client.next_seq = TCP_GET_ACK(p);
-
- if (SEQ_EQ(TCP_GET_SEQ(p),ssn->server.next_seq))
- ssn->server.next_seq += p->payload_len;
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->server.next_seq,
- ssn->client.last_ack);
- }
-
- } else {
- SCLogDebug("ssn %p: default case", ssn);
- }
- SCReturnInt(0);
-}
-
-/**
- * \brief Function to handle the TCP_LAST_ACK state. Upon arrival of ACK
- * the connection goes to TCP_CLOSED state and stream memory is
- * returned back to pool. The state is possible only for server host.
- *
- * \param tv Thread Variable containig input/output queue, cpu affinity
- * \param p Packet which has to be handled in this TCP state.
- * \param stt Strean Thread module registered to handle the stream handling
- */
-
-static int StreamTcpPacketStateLastAck(ThreadVars *tv, Packet *p,
- StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
-{
- if (ssn == NULL)
- return -1;
-
- if (p->tcph->th_flags & TH_RST) {
- if (!StreamTcpValidateRst(ssn, p))
- return -1;
-
- /* force both streams to reassemble, if necessary */
- StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq);
-
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
- ssn);
-
- if (PKT_IS_TOSERVER(p)) {
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- } else {
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- }
-
- } else if (p->tcph->th_flags & TH_FIN) {
- /** \todo */
-
- } else if (p->tcph->th_flags & TH_SYN) {
- SCLogDebug("ssn (%p): SYN pkt on LastAck", ssn);
- StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND);
- return -1;
-
- } else if (p->tcph->th_flags & TH_ACK) {
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p))
- return -1;
- }
-
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
-
- int retransmission = 0;
- if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
- }
-
- if (TCP_GET_SEQ(p) != ssn->client.next_seq && TCP_GET_SEQ(p) != ssn->client.next_seq + 1) {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->client.next_seq);
- StreamTcpSetEvent(p, STREAM_LASTACK_ACK_WRONG_SEQ);
- return -1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_LASTACK_INVALID_ACK);
- SCReturnInt(-1);
- }
-
- if (!retransmission) {
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
-
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
- ssn->server.next_seq = TCP_GET_ACK(p);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->client.next_seq,
- ssn->server.last_ack);
- }
- } else {
- SCLogDebug("ssn %p: default case", ssn);
- }
-
- return 0;
-}
-
-/**
- * \brief Function to handle the TCP_TIME_WAIT state. Upon arrival of ACK
- * the connection goes to TCP_CLOSED state and stream memory is
- * returned back to pool.
- *
- * \param tv Thread Variable containig input/output queue, cpu affinity
- * \param p Packet which has to be handled in this TCP state.
- * \param stt Strean Thread module registered to handle the stream handling
- */
-
-static int StreamTcpPacketStateTimeWait(ThreadVars *tv, Packet *p,
- StreamTcpThread *stt, TcpSession *ssn, PacketQueue *pq)
-{
- if (ssn == NULL)
- return -1;
-
- if (p->tcph->th_flags & TH_RST) {
- if (!StreamTcpValidateRst(ssn, p))
- return -1;
-
- /* force both streams to reassemble, if necessary */
- StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq);
-
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: Reset received state changed to TCP_CLOSED",
- ssn);
-
- if (PKT_IS_TOSERVER(p)) {
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->server, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- } else {
- if ((p->tcph->th_flags & TH_ACK) && StreamTcpValidateAck(ssn, &ssn->client, p) == 0)
- StreamTcpUpdateLastAck(ssn, &ssn->client,
- StreamTcpResetGetMaxAck(&ssn->client, TCP_GET_ACK(p)));
-
- StreamTcpUpdateLastAck(ssn, &ssn->server,
- StreamTcpResetGetMaxAck(&ssn->server, TCP_GET_SEQ(p)));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- }
-
- } else if (p->tcph->th_flags & TH_FIN) {
- /** \todo */
-
- } else if (p->tcph->th_flags & TH_SYN) {
- SCLogDebug("ssn (%p): SYN pkt on TimeWait", ssn);
- StreamTcpSetEvent(p, STREAM_SHUTDOWN_SYN_RESEND);
- return -1;
-
- } else if (p->tcph->th_flags & TH_ACK) {
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p))
- return -1;
- }
-
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to server: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- int retransmission = 0;
- if (StreamTcpPacketIsRetransmission(&ssn->client, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
-
- } else if (TCP_GET_SEQ(p) != ssn->client.next_seq && TCP_GET_SEQ(p) != ssn->client.next_seq+1) {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->client.next_seq);
- StreamTcpSetEvent(p, STREAM_TIMEWAIT_ACK_WRONG_SEQ);
- return -1;
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_TIMEWAIT_INVALID_ACK);
- SCReturnInt(-1);
- }
-
- if (!retransmission) {
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
-
- ssn->server.window = TCP_GET_WINDOW(p) << ssn->server.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->server, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->server.next_seq, TCP_GET_ACK(p)))
- ssn->server.next_seq = TCP_GET_ACK(p);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->client.next_seq,
- ssn->server.last_ack);
-
- StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq);
- } else {
- SCLogDebug("ssn %p: pkt (%" PRIu32 ") is to client: SEQ "
- "%" PRIu32 ", ACK %" PRIu32 "", ssn, p->payload_len,
- TCP_GET_SEQ(p), TCP_GET_ACK(p));
- int retransmission = 0;
- if (StreamTcpPacketIsRetransmission(&ssn->server, p)) {
- SCLogDebug("ssn %p: packet is retransmission", ssn);
- retransmission = 1;
- } else if (TCP_GET_SEQ(p) != ssn->server.next_seq && TCP_GET_SEQ(p) != ssn->server.next_seq+1) {
- if (p->payload_len > 0 && TCP_GET_SEQ(p) == ssn->server.last_ack) {
- SCLogDebug("ssn %p: -> retransmission", ssn);
- SCReturnInt(0);
- } else {
- SCLogDebug("ssn %p: -> SEQ mismatch, packet SEQ %" PRIu32 ""
- " != %" PRIu32 " from stream", ssn,
- TCP_GET_SEQ(p), ssn->server.next_seq);
- StreamTcpSetEvent(p, STREAM_TIMEWAIT_ACK_WRONG_SEQ);
- return -1;
- }
- }
-
- if (StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_TIMEWAIT_INVALID_ACK);
- SCReturnInt(-1);
- }
-
- if (!retransmission) {
- StreamTcpPacketSetState(p, ssn, TCP_CLOSED);
- SCLogDebug("ssn %p: state changed to TCP_CLOSED", ssn);
-
- ssn->client.window = TCP_GET_WINDOW(p) << ssn->client.wscale;
- }
-
- StreamTcpUpdateLastAck(ssn, &ssn->client, TCP_GET_ACK(p));
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- StreamTcpHandleTimestamp(ssn, p);
- }
-
- /* Update the next_seq, in case if we have missed the client
- packet and server has already received and acked it */
- if (SEQ_LT(ssn->client.next_seq, TCP_GET_ACK(p)))
- ssn->client.next_seq = TCP_GET_ACK(p);
-
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- SCLogDebug("ssn %p: =+ next SEQ %" PRIu32 ", last ACK "
- "%" PRIu32 "", ssn, ssn->server.next_seq,
- ssn->client.last_ack);
-
- StreamTcpPseudoPacketCreateStreamEndPacket(tv, stt, p, ssn, pq);
- }
-
- } else {
- SCLogDebug("ssn %p: default case", ssn);
- }
-
- return 0;
-}
-
-/**
- * \retval 1 packet is a keep alive pkt
- * \retval 0 packet is not a keep alive pkt
- */
-static int StreamTcpPacketIsKeepAlive(TcpSession *ssn, Packet *p)
-{
- TcpStream *stream = NULL, *ostream = NULL;
- uint32_t seq;
- uint32_t ack;
-
- if (p->flags & PKT_PSEUDO_STREAM_END)
- return 0;
-
- /*
- rfc 1122:
- An implementation SHOULD send a keep-alive segment with no
- data; however, it MAY be configurable to send a keep-alive
- segment containing one garbage octet, for compatibility with
- erroneous TCP implementations.
- */
- if (p->payload_len > 1)
- return 0;
-
- if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0) {
- return 0;
- }
-
- if (PKT_IS_TOSERVER(p)) {
- stream = &ssn->client;
- ostream = &ssn->server;
- } else {
- stream = &ssn->server;
- ostream = &ssn->client;
- }
-
- seq = TCP_GET_SEQ(p);
- ack = TCP_GET_ACK(p);
-
- if (ack == ostream->last_ack && seq == (stream->next_seq - 1)) {
- SCLogDebug("packet is TCP keep-alive: %"PRIu64, p->pcap_cnt);
- stream->flags |= STREAMTCP_STREAM_FLAG_KEEPALIVE;
- return 1;
- }
- SCLogDebug("seq %u (%u), ack %u (%u)", seq, (stream->next_seq - 1), ack, ostream->last_ack);
- return 0;
-}
-
-/**
- * \retval 1 packet is a keep alive ACK pkt
- * \retval 0 packet is not a keep alive ACK pkt
- */
-static int StreamTcpPacketIsKeepAliveACK(TcpSession *ssn, Packet *p)
-{
- TcpStream *stream = NULL, *ostream = NULL;
- uint32_t seq;
- uint32_t ack;
- uint32_t pkt_win;
-
- if (p->flags & PKT_PSEUDO_STREAM_END)
- return 0;
- /* should get a normal ACK to a Keep Alive */
- if (p->payload_len > 0)
- return 0;
-
- if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0)
- return 0;
-
- if (TCP_GET_WINDOW(p) == 0)
- return 0;
-
- if (PKT_IS_TOSERVER(p)) {
- stream = &ssn->client;
- ostream = &ssn->server;
- } else {
- stream = &ssn->server;
- ostream = &ssn->client;
- }
-
- seq = TCP_GET_SEQ(p);
- ack = TCP_GET_ACK(p);
-
- pkt_win = TCP_GET_WINDOW(p) << ostream->wscale;
- if (pkt_win != ostream->window)
- return 0;
-
- if ((ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) && ack == ostream->last_ack && seq == stream->next_seq) {
- SCLogDebug("packet is TCP keep-aliveACK: %"PRIu64, p->pcap_cnt);
- ostream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE;
- return 1;
- }
- SCLogDebug("seq %u (%u), ack %u (%u) FLAG_KEEPALIVE: %s", seq, stream->next_seq, ack, ostream->last_ack,
- ostream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE ? "set" : "not set");
- return 0;
-}
-
-static void StreamTcpClearKeepAliveFlag(TcpSession *ssn, Packet *p)
-{
- TcpStream *stream = NULL;
-
- if (p->flags & PKT_PSEUDO_STREAM_END)
- return;
-
- if (PKT_IS_TOSERVER(p)) {
- stream = &ssn->client;
- } else {
- stream = &ssn->server;
- }
-
- if (stream->flags & STREAMTCP_STREAM_FLAG_KEEPALIVE) {
- stream->flags &= ~STREAMTCP_STREAM_FLAG_KEEPALIVE;
- SCLogDebug("FLAG_KEEPALIVE cleared");
- }
-}
-
-/**
- * \retval 1 packet is a window update pkt
- * \retval 0 packet is not a window update pkt
- */
-static int StreamTcpPacketIsWindowUpdate(TcpSession *ssn, Packet *p)
-{
- TcpStream *stream = NULL, *ostream = NULL;
- uint32_t seq;
- uint32_t ack;
- uint32_t pkt_win;
-
- if (p->flags & PKT_PSEUDO_STREAM_END)
- return 0;
-
- if (ssn->state < TCP_ESTABLISHED)
- return 0;
-
- if (p->payload_len > 0)
- return 0;
-
- if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0)
- return 0;
-
- if (TCP_GET_WINDOW(p) == 0)
- return 0;
-
- if (PKT_IS_TOSERVER(p)) {
- stream = &ssn->client;
- ostream = &ssn->server;
- } else {
- stream = &ssn->server;
- ostream = &ssn->client;
- }
-
- seq = TCP_GET_SEQ(p);
- ack = TCP_GET_ACK(p);
-
- pkt_win = TCP_GET_WINDOW(p) << ostream->wscale;
- if (pkt_win == ostream->window)
- return 0;
-
- if (ack == ostream->last_ack && seq == stream->next_seq) {
- SCLogDebug("packet is TCP window update: %"PRIu64, p->pcap_cnt);
- return 1;
- }
- SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
- return 0;
-}
-
-/**
- * Try to detect whether a packet is a valid FIN 4whs final ack.
- *
- */
-static int StreamTcpPacketIsFinShutdownAck(TcpSession *ssn, Packet *p)
-{
- TcpStream *stream = NULL, *ostream = NULL;
- uint32_t seq;
- uint32_t ack;
-
- if (p->flags & PKT_PSEUDO_STREAM_END)
- return 0;
- if (!(ssn->state == TCP_TIME_WAIT || ssn->state == TCP_CLOSE_WAIT || ssn->state == TCP_LAST_ACK))
- return 0;
- if (p->tcph->th_flags != TH_ACK)
- return 0;
- if (p->payload_len != 0)
- return 0;
-
- if (PKT_IS_TOSERVER(p)) {
- stream = &ssn->client;
- ostream = &ssn->server;
- } else {
- stream = &ssn->server;
- ostream = &ssn->client;
- }
-
- seq = TCP_GET_SEQ(p);
- ack = TCP_GET_ACK(p);
-
- SCLogDebug("%"PRIu64", seq %u ack %u stream->next_seq %u ostream->next_seq %u",
- p->pcap_cnt, seq, ack, stream->next_seq, ostream->next_seq);
-
- if (SEQ_EQ(stream->next_seq + 1, seq) && SEQ_EQ(ack, ostream->next_seq + 1)) {
- return 1;
- }
- return 0;
-}
-
-/**
- * Try to detect packets doing bad window updates
- *
- * See bug 1238.
- *
- * Find packets that are unexpected, and shrink the window to the point
- * where the packets we do expect are rejected for being out of window.
- *
- * The logic we use here is:
- * - packet seq > next_seq
- * - packet ack > next_seq (packet acks unseen data)
- * - packet shrinks window more than it's own data size
- * - packet shrinks window more than the diff between it's ack and the
- * last_ack value
- *
- * Packets coming in after packet loss can look quite a bit like this.
- */
-static int StreamTcpPacketIsBadWindowUpdate(TcpSession *ssn, Packet *p)
-{
- TcpStream *stream = NULL, *ostream = NULL;
- uint32_t seq;
- uint32_t ack;
- uint32_t pkt_win;
-
- if (p->flags & PKT_PSEUDO_STREAM_END)
- return 0;
-
- if (ssn->state < TCP_ESTABLISHED || ssn->state == TCP_CLOSED)
- return 0;
-
- if ((p->tcph->th_flags & (TH_SYN|TH_FIN|TH_RST)) != 0)
- return 0;
-
- if (PKT_IS_TOSERVER(p)) {
- stream = &ssn->client;
- ostream = &ssn->server;
- } else {
- stream = &ssn->server;
- ostream = &ssn->client;
- }
-
- seq = TCP_GET_SEQ(p);
- ack = TCP_GET_ACK(p);
-
- pkt_win = TCP_GET_WINDOW(p) << ostream->wscale;
-
- if (pkt_win < ostream->window) {
- uint32_t diff = ostream->window - pkt_win;
- if (diff > p->payload_len &&
- SEQ_GT(ack, ostream->next_seq) &&
- SEQ_GT(seq, stream->next_seq))
- {
- SCLogDebug("%"PRIu64", pkt_win %u, stream win %u, diff %u, dsize %u",
- p->pcap_cnt, pkt_win, ostream->window, diff, p->payload_len);
- SCLogDebug("%"PRIu64", pkt_win %u, stream win %u",
- p->pcap_cnt, pkt_win, ostream->window);
- SCLogDebug("%"PRIu64", seq %u ack %u ostream->next_seq %u ostream->last_ack %u, ostream->next_win %u, diff %u (%u)",
- p->pcap_cnt, seq, ack, ostream->next_seq, ostream->last_ack, ostream->next_win,
- ostream->next_seq - ostream->last_ack, stream->next_seq - stream->last_ack);
-
- /* get the expected window shrinking from looking at ack vs last_ack.
- * Observed a lot of just a little overrunning that value. So added some
- * margin that is still ok. To make sure this isn't a loophole to still
- * close the window, this is limited to windows above 1024. Both values
- * are rather arbitrary. */
- uint32_t adiff = ack - ostream->last_ack;
- if (((pkt_win > 1024) && (diff > (adiff + 32))) ||
- ((pkt_win <= 1024) && (diff > adiff)))
- {
- SCLogDebug("pkt ACK %u is %u bytes beyond last_ack %u, shrinks window by %u "
- "(allowing 32 bytes extra): pkt WIN %u", ack, adiff, ostream->last_ack, diff, pkt_win);
- SCLogDebug("%u - %u = %u (state %u)", diff, adiff, diff - adiff, ssn->state);
- StreamTcpSetEvent(p, STREAM_PKT_BAD_WINDOW_UPDATE);
- return 1;
- }
- }
-
- }
- SCLogDebug("seq %u (%u), ack %u (%u)", seq, stream->next_seq, ack, ostream->last_ack);
- return 0;
-}
-
-/* flow is and stays locked */
-int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt,
- PacketQueue *pq)
-{
- SCEnter();
-
- DEBUG_ASSERT_FLOW_LOCKED(p->flow);
-
- SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt);
-
- /* assign the thread id to the flow */
- if (unlikely(p->flow->thread_id == 0)) {
- p->flow->thread_id = (FlowThreadId)tv->id;
-#ifdef DEBUG
- } else if (unlikely((FlowThreadId)tv->id != p->flow->thread_id)) {
- SCLogDebug("wrong thread: flow has %u, we are %d", p->flow->thread_id, tv->id);
-#endif
- }
-
- TcpSession *ssn = (TcpSession *)p->flow->protoctx;
-
- /* track TCP flags */
- if (ssn != NULL) {
- ssn->tcp_packet_flags |= p->tcph->th_flags;
- if (PKT_IS_TOSERVER(p))
- ssn->client.tcp_flags |= p->tcph->th_flags;
- else if (PKT_IS_TOCLIENT(p))
- ssn->server.tcp_flags |= p->tcph->th_flags;
- }
-
- /* update counters */
- if ((p->tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
- StatsIncr(tv, stt->counter_tcp_synack);
- } else if (p->tcph->th_flags & (TH_SYN)) {
- StatsIncr(tv, stt->counter_tcp_syn);
- }
- if (p->tcph->th_flags & (TH_RST)) {
- StatsIncr(tv, stt->counter_tcp_rst);
- }
-
- /* broken TCP http://ask.wireshark.org/questions/3183/acknowledgment-number-broken-tcp-the-acknowledge-field-is-nonzero-while-the-ack-flag-is-not-set */
- if (!(p->tcph->th_flags & TH_ACK) && TCP_GET_ACK(p) != 0) {
- StreamTcpSetEvent(p, STREAM_PKT_BROKEN_ACK);
- }
-
- /* If we are on IPS mode, and got a drop action triggered from
- * the IP only module, or from a reassembled msg and/or from an
- * applayer detection, then drop the rest of the packets of the
- * same stream and avoid inspecting it any further */
- if (StreamTcpCheckFlowDrops(p) == 1) {
- SCLogDebug("This flow/stream triggered a drop rule");
- FlowSetNoPacketInspectionFlag(p->flow);
- DecodeSetNoPacketInspectionFlag(p);
- StreamTcpDisableAppLayer(p->flow);
- PACKET_DROP(p);
- /* return the segments to the pool */
- StreamTcpSessionPktFree(p);
- SCReturnInt(0);
- }
-
- if (ssn == NULL || ssn->state == TCP_NONE) {
- if (StreamTcpPacketStateNone(tv, p, stt, ssn, &stt->pseudo_queue) == -1) {
- goto error;
- }
-
- if (ssn != NULL)
- SCLogDebug("ssn->alproto %"PRIu16"", p->flow->alproto);
- } else {
- /* special case for PKT_PSEUDO_STREAM_END packets:
- * bypass the state handling and various packet checks,
- * we care about reassembly here. */
- if (p->flags & PKT_PSEUDO_STREAM_END) {
- if (PKT_IS_TOCLIENT(p)) {
- ssn->client.last_ack = TCP_GET_ACK(p);
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, p, pq);
- } else {
- ssn->server.last_ack = TCP_GET_ACK(p);
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, p, pq);
- }
- /* straight to 'skip' as we already handled reassembly */
- goto skip;
- }
-
- /* check if the packet is in right direction, when we missed the
- SYN packet and picked up midstream session. */
- if (ssn->flags & STREAMTCP_FLAG_MIDSTREAM_SYNACK)
- StreamTcpPacketSwitchDir(ssn, p);
-
- if (StreamTcpPacketIsKeepAlive(ssn, p) == 1) {
- goto skip;
- }
- if (StreamTcpPacketIsKeepAliveACK(ssn, p) == 1) {
- StreamTcpClearKeepAliveFlag(ssn, p);
- goto skip;
- }
- StreamTcpClearKeepAliveFlag(ssn, p);
-
- /* if packet is not a valid window update, check if it is perhaps
- * a bad window update that we should ignore (and alert on) */
- if (StreamTcpPacketIsFinShutdownAck(ssn, p) == 0)
- if (StreamTcpPacketIsWindowUpdate(ssn, p) == 0)
- if (StreamTcpPacketIsBadWindowUpdate(ssn,p))
- goto skip;
-
- switch (ssn->state) {
- case TCP_SYN_SENT:
- if(StreamTcpPacketStateSynSent(tv, p, stt, ssn, &stt->pseudo_queue)) {
- goto error;
- }
- break;
- case TCP_SYN_RECV:
- if(StreamTcpPacketStateSynRecv(tv, p, stt, ssn, &stt->pseudo_queue)) {
- goto error;
- }
- break;
- case TCP_ESTABLISHED:
- if(StreamTcpPacketStateEstablished(tv, p, stt, ssn, &stt->pseudo_queue)) {
- goto error;
- }
- break;
- case TCP_FIN_WAIT1:
- if(StreamTcpPacketStateFinWait1(tv, p, stt, ssn, &stt->pseudo_queue)) {
- goto error;
- }
- break;
- case TCP_FIN_WAIT2:
- if(StreamTcpPacketStateFinWait2(tv, p, stt, ssn, &stt->pseudo_queue)) {
- goto error;
- }
- break;
- case TCP_CLOSING:
- if(StreamTcpPacketStateClosing(tv, p, stt, ssn, &stt->pseudo_queue)) {
- goto error;
- }
- break;
- case TCP_CLOSE_WAIT:
- if(StreamTcpPacketStateCloseWait(tv, p, stt, ssn, &stt->pseudo_queue)) {
- goto error;
- }
- break;
- case TCP_LAST_ACK:
- if(StreamTcpPacketStateLastAck(tv, p, stt, ssn, &stt->pseudo_queue)) {
- goto error;
- }
- break;
- case TCP_TIME_WAIT:
- if(StreamTcpPacketStateTimeWait(tv, p, stt, ssn, &stt->pseudo_queue)) {
- goto error;
- }
- break;
- case TCP_CLOSED:
- /* TCP session memory is not returned to pool until timeout. */
- SCLogDebug("packet received on closed state");
- break;
- default:
- SCLogDebug("packet received on default state");
- break;
- }
- skip:
-
- if (ssn->state >= TCP_ESTABLISHED) {
- p->flags |= PKT_STREAM_EST;
- }
- }
-
- /* deal with a pseudo packet that is created upon receiving a RST
- * segment. To be sure we process both sides of the connection, we
- * inject a fake packet into the system, forcing reassembly of the
- * opposing direction.
- * There should be only one, but to be sure we do a while loop. */
- if (ssn != NULL) {
- while (stt->pseudo_queue.len > 0) {
- SCLogDebug("processing pseudo packet / stream end");
- Packet *np = PacketDequeue(&stt->pseudo_queue);
- if (np != NULL) {
- /* process the opposing direction of the original packet */
- if (PKT_IS_TOSERVER(np)) {
- SCLogDebug("pseudo packet is to server");
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->client, np, NULL);
- } else {
- SCLogDebug("pseudo packet is to client");
- StreamTcpReassembleHandleSegment(tv, stt->ra_ctx, ssn,
- &ssn->server, np, NULL);
- }
-
- /* enqueue this packet so we inspect it in detect etc */
- PacketEnqueue(pq, np);
- }
- SCLogDebug("processing pseudo packet / stream end done");
- }
-
- /* recalc the csum on the packet if it was modified */
- if (p->flags & PKT_STREAM_MODIFIED) {
- ReCalculateChecksum(p);
- }
-
- /* check for conditions that may make us not want to log this packet */
-
- /* streams that hit depth */
- if ((ssn->client.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) ||
- (ssn->server.flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED))
- {
- p->flags |= PKT_STREAM_NOPCAPLOG;
- }
-
- /* encrypted packets */
- if ((PKT_IS_TOSERVER(p) && (ssn->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) ||
- (PKT_IS_TOCLIENT(p) && (ssn->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)))
- {
- p->flags |= PKT_STREAM_NOPCAPLOG;
- }
- }
-
- SCReturnInt(0);
-
-error:
- /* make sure we don't leave packets in our pseudo queue */
- while (stt->pseudo_queue.len > 0) {
- Packet *np = PacketDequeue(&stt->pseudo_queue);
- if (np != NULL) {
- PacketEnqueue(pq, np);
- }
- }
-
- /* recalc the csum on the packet if it was modified */
- if (p->flags & PKT_STREAM_MODIFIED) {
- ReCalculateChecksum(p);
- }
-
- if (StreamTcpInlineMode()) {
- PACKET_DROP(p);
- }
- SCReturnInt(-1);
-}
-
-/**
- * \brief Function to validate the checksum of the received packet. If the
- * checksum is invalid, packet will be dropped, as the end system will
- * also drop the packet.
- *
- * \param p Packet of which checksum has to be validated
- * \retval 1 if the checksum is valid, otherwise 0
- */
-static inline int StreamTcpValidateChecksum(Packet *p)
-{
- int ret = 1;
-
- if (p->flags & PKT_IGNORE_CHECKSUM)
- return ret;
-
- if (p->level4_comp_csum == -1) {
- if (PKT_IS_IPV4(p)) {
- p->level4_comp_csum = TCPCalculateChecksum(p->ip4h->s_ip_addrs,
- (uint16_t *)p->tcph,
- (p->payload_len +
- TCP_GET_HLEN(p)));
- } else if (PKT_IS_IPV6(p)) {
- p->level4_comp_csum = TCPV6CalculateChecksum(p->ip6h->s_ip6_addrs,
- (uint16_t *)p->tcph,
- (p->payload_len +
- TCP_GET_HLEN(p)));
- }
- }
-
- if (p->level4_comp_csum != p->tcph->th_sum) {
- ret = 0;
- SCLogDebug("Checksum of received packet %p is invalid",p);
- if (p->livedev) {
- (void) SC_ATOMIC_ADD(p->livedev->invalid_checksums, 1);
- } else if (p->pcap_cnt) {
- PcapIncreaseInvalidChecksum();
- }
- }
-
- return ret;
-}
-
-/** \internal
- * \brief check if a packet is a valid stream started
- * \retval bool true/false */
-static int TcpSessionPacketIsStreamStarter(const Packet *p)
-{
- if (p->tcph->th_flags == TH_SYN) {
- SCLogDebug("packet %"PRIu64" is a stream starter: %02x", p->pcap_cnt, p->tcph->th_flags);
- return 1;
- }
-
- if (stream_config.midstream == TRUE || stream_config.async_oneside == TRUE) {
- if (p->tcph->th_flags == (TH_SYN|TH_ACK)) {
- SCLogDebug("packet %"PRIu64" is a midstream stream starter: %02x", p->pcap_cnt, p->tcph->th_flags);
- return 1;
- }
- }
- return 0;
-}
-
-/** \internal
- * \brief Check if Flow and TCP SSN allow this flow/tuple to be reused
- * \retval bool true yes reuse, false no keep tracking old ssn */
-static int TcpSessionReuseDoneEnoughSyn(const Packet *p, const Flow *f, const TcpSession *ssn)
-{
- if (FlowGetPacketDirection(f, p) == TOSERVER) {
- if (ssn == NULL) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn);
- return 0;
- }
- if (SEQ_EQ(ssn->client.isn, TCP_GET_SEQ(p))) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
- return 0;
- }
- if (ssn->state >= TCP_LAST_ACK) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
- return 1;
- }
- if (ssn->state == TCP_NONE) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
- return 1;
- }
- if (ssn->state < TCP_LAST_ACK) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
- return 0;
- }
-
- } else {
- if (ssn == NULL) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
- return 1;
- }
- if (ssn->state >= TCP_LAST_ACK) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
- return 1;
- }
- if (ssn->state == TCP_NONE) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
- return 1;
- }
- if (ssn->state < TCP_LAST_ACK) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
- return 0;
- }
- }
-
- SCLogDebug("default: how did we get here?");
- return 0;
-}
-
-/** \internal
- * \brief check if ssn is done enough for reuse by syn/ack
- * \note should only be called if midstream is enabled
- */
-static int TcpSessionReuseDoneEnoughSynAck(const Packet *p, const Flow *f, const TcpSession *ssn)
-{
- if (FlowGetPacketDirection(f, p) == TOCLIENT) {
- if (ssn == NULL) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p null. No reuse.", p->pcap_cnt, ssn);
- return 0;
- }
- if (SEQ_EQ(ssn->server.isn, TCP_GET_SEQ(p))) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p. Packet SEQ == Stream ISN. Retransmission. Don't reuse.", p->pcap_cnt, ssn);
- return 0;
- }
- if (ssn->state >= TCP_LAST_ACK) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
- return 1;
- }
- if (ssn->state == TCP_NONE) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
- return 1;
- }
- if (ssn->state < TCP_LAST_ACK) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
- return 0;
- }
-
- } else {
- if (ssn == NULL) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p null. Reuse.", p->pcap_cnt, ssn);
- return 1;
- }
- if (ssn->state >= TCP_LAST_ACK) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p state >= TCP_LAST_ACK (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
- return 1;
- }
- if (ssn->state == TCP_NONE) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p state == TCP_NONE (%u). Reuse.", p->pcap_cnt, ssn, ssn->state);
- return 1;
- }
- if (ssn->state < TCP_LAST_ACK) {
- SCLogDebug("steam starter packet %"PRIu64", ssn %p state < TCP_LAST_ACK (%u). Don't reuse.", p->pcap_cnt, ssn, ssn->state);
- return 0;
- }
- }
-
- SCLogDebug("default: how did we get here?");
- return 0;
-}
-
-/** \brief Check if SSN is done enough for reuse
- *
- * Reuse means a new TCP session reuses the tuple (flow in suri)
- *
- * \retval bool true if ssn can be reused, false if not */
-int TcpSessionReuseDoneEnough(const Packet *p, const Flow *f, const TcpSession *ssn)
-{
- if (p->tcph->th_flags == TH_SYN) {
- return TcpSessionReuseDoneEnoughSyn(p, f, ssn);
- }
-
- if (stream_config.midstream == TRUE || stream_config.async_oneside == TRUE) {
- if (p->tcph->th_flags == (TH_SYN|TH_ACK)) {
- return TcpSessionReuseDoneEnoughSynAck(p, f, ssn);
- }
- }
-
- return 0;
-}
-
-int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
-{
- if (p->proto == IPPROTO_TCP && p->tcph != NULL) {
- if (TcpSessionPacketIsStreamStarter(p) == 1) {
- if (TcpSessionReuseDoneEnough(p, f, tcp_ssn) == 1) {
- return 1;
- }
- }
- }
- return 0;
-}
-
-/** \brief Handle TCP reuse of tuple
- *
- * Logic:
- * 1. see if packet could trigger a new session
- * 2. see if the flow/ssn is in a state where we want to support the reuse
- * 3. disconnect packet from the old flow
- * -> at this point new packets can still find the old flow
- * -> as the flow's reference count != 0, it can't disappear
- * 4. setup a new flow unconditionally
- * 5. attach packet to new flow
- * 6. tag old flow as FLOW_TCP_REUSED
- * -> NEW packets won't find it
- * -> existing packets in our queues may still reference it
- * 7. dereference the old flow (reference cnt *may* now be 0,
- * if no other packets reference it)
- *
- * The packets that still hold a reference to the old flow are updated
- * by HandleFlowReuseApplyToPacket()
- */
-static void TcpSessionReuseHandle(Packet *p) {
- if (likely(TcpSessionPacketIsStreamStarter(p) == 0))
- return;
-
- int reuse = 0;
- FLOWLOCK_RDLOCK(p->flow);
- reuse = TcpSessionReuseDoneEnough(p, p->flow, p->flow->protoctx);
- if (!reuse) {
- SCLogDebug("steam starter packet %"PRIu64", but state not "
- "ready to be reused", p->pcap_cnt);
- FLOWLOCK_UNLOCK(p->flow);
- return;
- }
-
- SCLogDebug("steam starter packet %"PRIu64", and state "
- "ready to be reused", p->pcap_cnt);
-
- /* ok, this packet needs a new flow */
-
- /* first, get a reference to the old flow */
- Flow *old_f = NULL;
- FlowReference(&old_f, p->flow);
-
- /* get some settings that we move over to the new flow */
- FlowThreadId thread_id = old_f->thread_id;
- int autofp_tmqh_flow_qid = SC_ATOMIC_GET(old_f->autofp_tmqh_flow_qid);
-
- /* disconnect the packet from the old flow */
- FlowHandlePacketUpdateRemove(p->flow, p);
- FLOWLOCK_UNLOCK(p->flow);
- FlowDeReference(&p->flow); // < can't disappear while usecnt >0
-
- /* Can't tag flow as reused yet, would be a race condition:
- * new packets will not get old flow because of FLOW_TCP_REUSED,
- * so new flow may be created. This new flow could be handled in
- * a different thread. */
-
- /* Get a flow. It will be either a locked flow or NULL */
- Flow *new_f = FlowGetFlowFromHashByPacket(p);
- if (new_f == NULL) {
- FlowDeReference(&old_f); // < can't disappear while usecnt >0
- return;
- }
-
- /* update flow and packet */
- FlowHandlePacketUpdate(new_f, p);
- BUG_ON(new_f != p->flow);
-
- /* copy flow balancing settings */
- new_f->thread_id = thread_id;
- SC_ATOMIC_SET(new_f->autofp_tmqh_flow_qid, autofp_tmqh_flow_qid);
-
- FLOWLOCK_UNLOCK(new_f);
-
- /* tag original flow that it's now unused */
- FLOWLOCK_WRLOCK(old_f);
- SCLogDebug("old flow %p tagged with FLOW_TCP_REUSED by packet %"PRIu64"!", old_f, p->pcap_cnt);
- old_f->flags |= FLOW_TCP_REUSED;
- FLOWLOCK_UNLOCK(old_f);
- FlowDeReference(&old_f); // < can't disappear while usecnt >0
-
- SCLogDebug("new flow %p set up for packet %"PRIu64"!", p->flow, p->pcap_cnt);
-}
-
-/** \brief Handle packets that reference the wrong flow because of TCP reuse
- *
- * In the case of TCP reuse we can have many packets that were assigned
- * a flow by the capture/decode threads before the stream engine decided
- * that a new flow was needed for these packets.
- * When HandleFlowReuse creates a new flow, the packets already processed
- * by the flow engine will still reference the old flow.
- *
- * This function detects this case and replaces the flow for those packets.
- * It's a fairly expensive operation, but it should be rare as it's only
- * done for packets that were already in the engine when the TCP reuse
- * case was handled. New packets are assigned the correct flow by the
- * flow engine.
- */
-static void TcpSessionReuseHandleApplyToPacket(Packet *p)
-{
- int need_flow_replace = 0;
-
- FLOWLOCK_WRLOCK(p->flow);
- if (p->flow->flags & FLOW_TCP_REUSED) {
- SCLogDebug("packet %"PRIu64" attached to outdated flow and ssn", p->pcap_cnt);
- need_flow_replace = 1;
- }
-
- if (likely(need_flow_replace == 0)) {
- /* Work around a race condition: if HandleFlowReuse has inserted a new flow,
- * it will not have seen both sides of the session yet. The packet we have here
- * may be the first that got the flow directly from the hash right after the
- * flow was added. In this case it won't have FLOW_PKT_ESTABLISHED flag set. */
- if ((p->flow->flags & FLOW_TO_DST_SEEN) && (p->flow->flags & FLOW_TO_SRC_SEEN)) {
- p->flowflags |= FLOW_PKT_ESTABLISHED;
- SCLogDebug("packet %"PRIu64" / flow %p: p->flowflags |= FLOW_PKT_ESTABLISHED (%u/%u)", p->pcap_cnt, p->flow, p->flow->todstpktcnt, p->flow->tosrcpktcnt);
- } else {
- SCLogDebug("packet %"PRIu64" / flow %p: p->flowflags NOT FLOW_PKT_ESTABLISHED (%u/%u)", p->pcap_cnt, p->flow, p->flow->todstpktcnt, p->flow->tosrcpktcnt);
- }
- SCLogDebug("packet %"PRIu64" attached to regular flow %p and ssn", p->pcap_cnt, p->flow);
- FLOWLOCK_UNLOCK(p->flow);
- return;
- }
-
- /* disconnect packet from old flow */
- FlowHandlePacketUpdateRemove(p->flow, p);
- FLOWLOCK_UNLOCK(p->flow);
- FlowDeReference(&p->flow); // < can't disappear while usecnt >0
-
- /* find the new flow that does belong to this packet */
- Flow *new_f = FlowLookupFlowFromHash(p);
- if (new_f == NULL) {
- // TODO reset packet flag wrt flow: direction, HAS_FLOW etc
- p->flags &= ~PKT_HAS_FLOW;
- return;
- }
- FlowHandlePacketUpdate(new_f, p);
- BUG_ON(new_f != p->flow);
- FLOWLOCK_UNLOCK(new_f);
- SCLogDebug("packet %"PRIu64" switched over to new flow %p!", p->pcap_cnt, p->flow);
-}
-
-TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq)
-{
- StreamTcpThread *stt = (StreamTcpThread *)data;
- TmEcode ret = TM_ECODE_OK;
-
- if (!(PKT_IS_TCP(p)))
- return TM_ECODE_OK;
-
- if (p->flow == NULL) {
- StatsIncr(tv, stt->counter_tcp_no_flow);
- return TM_ECODE_OK;
- }
-
- if (stream_config.flags & STREAMTCP_INIT_FLAG_CHECKSUM_VALIDATION) {
- if (StreamTcpValidateChecksum(p) == 0) {
- StatsIncr(tv, stt->counter_tcp_invalid_checksum);
- return TM_ECODE_OK;
- }
- } else {
- p->flags |= PKT_IGNORE_CHECKSUM;
- }
-
- if (stt->runmode_flow_stream_async) {
- /* "autofp" handling of TCP session/flow reuse */
- if (!(p->flags & PKT_PSEUDO_STREAM_END)) {
- /* apply previous reuses to this packet */
- TcpSessionReuseHandleApplyToPacket(p);
- if (p->flow == NULL)
- return ret;
-
- if (!(p->flowflags & FLOW_PKT_TOSERVER_FIRST)) {
- /* after that, check for 'new' reuse */
- TcpSessionReuseHandle(p);
- if (p->flow == NULL)
- return ret;
- }
- }
- }
- AppLayerProfilingReset(stt->ra_ctx->app_tctx);
-
- FLOWLOCK_WRLOCK(p->flow);
- ret = StreamTcpPacket(tv, p, stt, pq);
- FLOWLOCK_UNLOCK(p->flow);
-
- //if (ret)
- // return TM_ECODE_FAILED;
-
- stt->pkts++;
- return ret;
-}
-
-TmEcode StreamTcpThreadInit(ThreadVars *tv, void *initdata, void **data)
-{
- SCEnter();
- StreamTcpThread *stt = SCMalloc(sizeof(StreamTcpThread));
- if (unlikely(stt == NULL))
- SCReturnInt(TM_ECODE_FAILED);
- memset(stt, 0, sizeof(StreamTcpThread));
- stt->ssn_pool_id = -1;
-
- *data = (void *)stt;
-
- stt->counter_tcp_sessions = StatsRegisterCounter("tcp.sessions", tv);
- stt->counter_tcp_ssn_memcap = StatsRegisterCounter("tcp.ssn_memcap_drop", tv);
- stt->counter_tcp_pseudo = StatsRegisterCounter("tcp.pseudo", tv);
- stt->counter_tcp_pseudo_failed = StatsRegisterCounter("tcp.pseudo_failed", tv);
- stt->counter_tcp_invalid_checksum = StatsRegisterCounter("tcp.invalid_checksum", tv);
- stt->counter_tcp_no_flow = StatsRegisterCounter("tcp.no_flow", tv);
- stt->counter_tcp_syn = StatsRegisterCounter("tcp.syn", tv);
- stt->counter_tcp_synack = StatsRegisterCounter("tcp.synack", tv);
- stt->counter_tcp_rst = StatsRegisterCounter("tcp.rst", tv);
-
- /* init reassembly ctx */
- stt->ra_ctx = StreamTcpReassembleInitThreadCtx(tv);
- if (stt->ra_ctx == NULL)
- SCReturnInt(TM_ECODE_FAILED);
-
- stt->ra_ctx->counter_tcp_segment_memcap = StatsRegisterCounter("tcp.segment_memcap_drop", tv);
- stt->ra_ctx->counter_tcp_stream_depth = StatsRegisterCounter("tcp.stream_depth_reached", tv);
- stt->ra_ctx->counter_tcp_reass_gap = StatsRegisterCounter("tcp.reassembly_gap", tv);
-
- SCLogDebug("StreamTcp thread specific ctx online at %p, reassembly ctx %p",
- stt, stt->ra_ctx);
-
- SCMutexLock(&ssn_pool_mutex);
- if (ssn_pool == NULL) {
- ssn_pool = PoolThreadInit(1, /* thread */
- 0, /* unlimited */
- stream_config.prealloc_sessions,
- sizeof(TcpSession),
- StreamTcpSessionPoolAlloc,
- StreamTcpSessionPoolInit, NULL,
- StreamTcpSessionPoolCleanup, NULL);
- stt->ssn_pool_id = 0;
- SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
- } else {
- /* grow ssn_pool until we have a element for our thread id */
- stt->ssn_pool_id = PoolThreadGrow(ssn_pool,
- 0, /* unlimited */
- stream_config.prealloc_sessions,
- sizeof(TcpSession),
- StreamTcpSessionPoolAlloc,
- StreamTcpSessionPoolInit, NULL,
- StreamTcpSessionPoolCleanup, NULL);
- SCLogDebug("pool size %d, thread ssn_pool_id %d", PoolThreadSize(ssn_pool), stt->ssn_pool_id);
- }
- SCMutexUnlock(&ssn_pool_mutex);
- if (stt->ssn_pool_id < 0 || ssn_pool == NULL)
- SCReturnInt(TM_ECODE_FAILED);
-
- /* see if need to enable the TCP reuse handling in the stream engine */
- stt->runmode_flow_stream_async = RunmodeGetFlowStreamAsync();
- SCLogDebug("Flow and Stream engine run %s",
- stt->runmode_flow_stream_async ? "asynchronous" : "synchronous");
-
- SCReturnInt(TM_ECODE_OK);
-}
-
-TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data)
-{
- SCEnter();
- StreamTcpThread *stt = (StreamTcpThread *)data;
- if (stt == NULL) {
- return TM_ECODE_OK;
- }
-
- /* XXX */
-
- /* free reassembly ctx */
- StreamTcpReassembleFreeThreadCtx(stt->ra_ctx);
-
- /* clear memory */
- memset(stt, 0, sizeof(StreamTcpThread));
-
- SCFree(stt);
- SCReturnInt(TM_ECODE_OK);
-}
-
-void StreamTcpExitPrintStats(ThreadVars *tv, void *data)
-{
- StreamTcpThread *stt = (StreamTcpThread *)data;
- if (stt == NULL) {
- return;
- }
-
- SCLogInfo("Stream TCP processed %" PRIu64 " TCP packets", stt->pkts);
-}
-
-/**
- * \brief Function to check the validity of the RST packets based on the
- * target OS of the given packet.
- *
- * \param ssn TCP session to which the given packet belongs
- * \param p Packet which has to be checked for its validity
- *
- * \retval 0 unacceptable RST
- * \retval 1 acceptable RST
- *
- * WebSense sends RST packets that are:
- * - RST flag, win 0, ack 0, seq = nextseq
- *
- */
-
-static int StreamTcpValidateRst(TcpSession *ssn, Packet *p)
-{
-
- uint8_t os_policy;
-
- if (ssn->flags & STREAMTCP_FLAG_TIMESTAMP) {
- if (!StreamTcpValidateTimestamp(ssn, p)) {
- SCReturnInt(0);
- }
- }
-
- /* Set up the os_policy to be used in validating the RST packets based on
- target system */
- if (PKT_IS_TOSERVER(p)) {
- if (ssn->server.os_policy == 0)
- StreamTcpSetOSPolicy(&ssn->server, p);
-
- os_policy = ssn->server.os_policy;
-
- if (p->tcph->th_flags & TH_ACK &&
- TCP_GET_ACK(p) && StreamTcpValidateAck(ssn, &ssn->server, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_RST_INVALID_ACK);
- SCReturnInt(0);
- }
-
- } else {
- if (ssn->client.os_policy == 0)
- StreamTcpSetOSPolicy(&ssn->client, p);
-
- os_policy = ssn->client.os_policy;
-
- if (p->tcph->th_flags & TH_ACK &&
- TCP_GET_ACK(p) && StreamTcpValidateAck(ssn, &ssn->client, p) == -1) {
- SCLogDebug("ssn %p: rejecting because of invalid ack value", ssn);
- StreamTcpSetEvent(p, STREAM_RST_INVALID_ACK);
- SCReturnInt(0);
- }
- }
-
- switch (os_policy) {
- case OS_POLICY_HPUX11:
- if(PKT_IS_TOSERVER(p)){
- if(SEQ_GEQ(TCP_GET_SEQ(p), ssn->client.next_seq)) {
- SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "",
- TCP_GET_SEQ(p));
- return 1;
- } else {
- SCLogDebug("reset is not Valid! Packet SEQ: %" PRIu32 " "
- "and server SEQ: %" PRIu32 "", TCP_GET_SEQ(p),
- ssn->client.next_seq);
- return 0;
- }
- } else { /* implied to client */
- if(SEQ_GEQ(TCP_GET_SEQ(p), ssn->server.next_seq)) {
- SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "",
- TCP_GET_SEQ(p));
- return 1;
- } else {
- SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
- "and client SEQ: %" PRIu32 "", TCP_GET_SEQ(p),
- ssn->server.next_seq);
- return 0;
- }
- }
- break;
- case OS_POLICY_OLD_LINUX:
- case OS_POLICY_LINUX:
- case OS_POLICY_SOLARIS:
- if(PKT_IS_TOSERVER(p)){
- if(SEQ_GEQ((TCP_GET_SEQ(p)+p->payload_len),
- ssn->client.last_ack))
- { /*window base is needed !!*/
- if(SEQ_LT(TCP_GET_SEQ(p),
- (ssn->client.next_seq + ssn->client.window)))
- {
- SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "",
- TCP_GET_SEQ(p));
- return 1;
- }
- } else {
- SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
- " server SEQ: %" PRIu32 "", TCP_GET_SEQ(p),
- ssn->client.next_seq);
- return 0;
- }
- } else { /* implied to client */
- if(SEQ_GEQ((TCP_GET_SEQ(p) + p->payload_len),
- ssn->server.last_ack))
- { /*window base is needed !!*/
- if(SEQ_LT(TCP_GET_SEQ(p),
- (ssn->server.next_seq + ssn->server.window)))
- {
- SCLogDebug("reset is Valid! Packet SEQ: %" PRIu32 "",
- TCP_GET_SEQ(p));
- return 1;
- }
- } else {
- SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
- " client SEQ: %" PRIu32 "", TCP_GET_SEQ(p),
- ssn->server.next_seq);
- return 0;
- }
- }
- break;
- default:
- case OS_POLICY_BSD:
- case OS_POLICY_FIRST:
- case OS_POLICY_HPUX10:
- case OS_POLICY_IRIX:
- case OS_POLICY_MACOS:
- case OS_POLICY_LAST:
- case OS_POLICY_WINDOWS:
- case OS_POLICY_WINDOWS2K3:
- case OS_POLICY_VISTA:
- if(PKT_IS_TOSERVER(p)) {
- if(SEQ_EQ(TCP_GET_SEQ(p), ssn->client.next_seq)) {
- SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "",
- TCP_GET_SEQ(p));
- return 1;
- } else {
- SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " "
- "and server SEQ: %" PRIu32 "", TCP_GET_SEQ(p),
- ssn->client.next_seq);
- return 0;
- }
- } else { /* implied to client */
- if(SEQ_EQ(TCP_GET_SEQ(p), ssn->server.next_seq)) {
- SCLogDebug("reset is valid! Packet SEQ: %" PRIu32 "",
- TCP_GET_SEQ(p));
- return 1;
- } else {
- SCLogDebug("reset is not valid! Packet SEQ: %" PRIu32 " and"
- " client SEQ: %" PRIu32 "", TCP_GET_SEQ(p),
- ssn->server.next_seq);
- return 0;
- }
- }
- break;
- }
- return 0;
-}
-
-/**
- * \brief Function to check the validity of the received timestamp based on
- * the target OS of the given stream.
- *
- * It's passive except for:
- * 1. it sets the os policy on the stream if necessary
- * 2. it sets an event in the packet if necessary
- *
- * \param ssn TCP session to which the given packet belongs
- * \param p Packet which has to be checked for its validity
- *
- * \retval 1 if the timestamp is valid
- * \retval 0 if the timestamp is invalid
- */
-static int StreamTcpValidateTimestamp (TcpSession *ssn, Packet *p)
-{
- SCEnter();
-
- TcpStream *sender_stream;
- TcpStream *receiver_stream;
- uint8_t ret = 1;
- uint8_t check_ts = 1;
-
- if (PKT_IS_TOSERVER(p)) {
- sender_stream = &ssn->client;
- receiver_stream = &ssn->server;
- } else {
- sender_stream = &ssn->server;
- receiver_stream = &ssn->client;
- }
-
- /* Set up the os_policy to be used in validating the timestamps based on
- the target system */
- if (receiver_stream->os_policy == 0) {
- StreamTcpSetOSPolicy(receiver_stream, p);
- }
-
- if (p->tcpvars.ts != NULL) {
- uint32_t ts = TCP_GET_TSVAL(p);
- uint32_t last_pkt_ts = sender_stream->last_pkt_ts;
- uint32_t last_ts = sender_stream->last_ts;
-
- if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
- /* The 3whs used the timestamp with 0 value. */
- switch (receiver_stream->os_policy) {
- case OS_POLICY_LINUX:
- case OS_POLICY_WINDOWS2K3:
- /* Linux and windows 2003 does not allow the use of 0 as
- * timestamp in the 3whs. */
- check_ts = 0;
- break;
-
- case OS_POLICY_OLD_LINUX:
- case OS_POLICY_WINDOWS:
- case OS_POLICY_VISTA:
- if (SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) {
- last_ts = ts;
- check_ts = 0; /*next packet will be checked for validity
- and stream TS has been updated with this
- one.*/
- }
- break;
- }
- }
-
- if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
- /* HPUX11 igoners the timestamp of out of order packets */
- if (!SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p)))
- check_ts = 0;
- }
-
- if (ts == 0) {
- switch (receiver_stream->os_policy) {
- case OS_POLICY_OLD_LINUX:
- case OS_POLICY_WINDOWS:
- case OS_POLICY_WINDOWS2K3:
- case OS_POLICY_VISTA:
- case OS_POLICY_SOLARIS:
- /* Old Linux and windows allowed packet with 0 timestamp. */
- break;
- default:
- /* other OS simply drop the pakcet with 0 timestamp, when
- * 3whs has valid timestamp*/
- goto invalid;
- }
- }
-
- if (check_ts) {
- int32_t result = 0;
-
- SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, last_ts);
-
- if (receiver_stream->os_policy == OS_POLICY_LINUX) {
- /* Linux accepts TS which are off by one.*/
- result = (int32_t) ((ts - last_ts) + 1);
- } else {
- result = (int32_t) (ts - last_ts);
- }
-
- SCLogDebug("result %"PRIi32", p->ts.tv_sec %"PRIuMAX"", result, (uintmax_t)p->ts.tv_sec);
-
- if (last_pkt_ts == 0 &&
- (ssn->flags & STREAMTCP_FLAG_MIDSTREAM))
- {
- last_pkt_ts = p->ts.tv_sec;
- }
-
- if (result < 0) {
- SCLogDebug("timestamp is not valid last_ts "
- "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
- "%" PRId32 "", last_ts, ts, result);
- /* candidate for rejection */
- ret = 0;
- } else if ((sender_stream->last_ts != 0) &&
- (((uint32_t) p->ts.tv_sec) >
- last_pkt_ts + PAWS_24DAYS))
- {
- SCLogDebug("packet is not valid last_pkt_ts "
- "%" PRIu32 " p->ts.tv_sec %" PRIu32 "",
- last_pkt_ts, (uint32_t) p->ts.tv_sec);
- /* candidate for rejection */
- ret = 0;
- }
-
- if (ret == 0) {
- /* if the timestamp of packet is not valid then, check if the
- * current stream timestamp is not so old. if so then we need to
- * accept the packet and update the stream->last_ts (RFC 1323)*/
- if ((SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) &&
- (((uint32_t) p->ts.tv_sec > (last_pkt_ts + PAWS_24DAYS))))
- {
- SCLogDebug("timestamp considered valid anyway");
- } else {
- goto invalid;
- }
- }
- }
- }
-
- SCReturnInt(1);
-
-invalid:
- StreamTcpSetEvent(p, STREAM_PKT_INVALID_TIMESTAMP);
- SCReturnInt(0);
-}
-
-/**
- * \brief Function to check the validity of the received timestamp based on
- * the target OS of the given stream and update the session.
- *
- * \param ssn TCP session to which the given packet belongs
- * \param p Packet which has to be checked for its validity
- *
- * \retval 1 if the timestamp is valid
- * \retval 0 if the timestamp is invalid
- */
-static int StreamTcpHandleTimestamp (TcpSession *ssn, Packet *p)
-{
- SCEnter();
-
- TcpStream *sender_stream;
- TcpStream *receiver_stream;
- uint8_t ret = 1;
- uint8_t check_ts = 1;
-
- if (PKT_IS_TOSERVER(p)) {
- sender_stream = &ssn->client;
- receiver_stream = &ssn->server;
- } else {
- sender_stream = &ssn->server;
- receiver_stream = &ssn->client;
- }
-
- /* Set up the os_policy to be used in validating the timestamps based on
- the target system */
- if (receiver_stream->os_policy == 0) {
- StreamTcpSetOSPolicy(receiver_stream, p);
- }
-
- if (p->tcpvars.ts != NULL) {
- uint32_t ts = TCP_GET_TSVAL(p);
-
- if (sender_stream->flags & STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP) {
- /* The 3whs used the timestamp with 0 value. */
- switch (receiver_stream->os_policy) {
- case OS_POLICY_LINUX:
- case OS_POLICY_WINDOWS2K3:
- /* Linux and windows 2003 does not allow the use of 0 as
- * timestamp in the 3whs. */
- ssn->flags &= ~STREAMTCP_FLAG_TIMESTAMP;
- check_ts = 0;
- break;
-
- case OS_POLICY_OLD_LINUX:
- case OS_POLICY_WINDOWS:
- case OS_POLICY_VISTA:
- sender_stream->flags &= ~STREAMTCP_STREAM_FLAG_ZERO_TIMESTAMP;
- if (SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) {
- sender_stream->last_ts = ts;
- check_ts = 0; /*next packet will be checked for validity
- and stream TS has been updated with this
- one.*/
- }
- break;
- default:
- break;
- }
- }
-
- if (receiver_stream->os_policy == OS_POLICY_HPUX11) {
- /*HPUX11 igoners the timestamp of out of order packets*/
- if (!SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p)))
- check_ts = 0;
- }
-
- if (ts == 0) {
- switch (receiver_stream->os_policy) {
- case OS_POLICY_OLD_LINUX:
- case OS_POLICY_WINDOWS:
- case OS_POLICY_WINDOWS2K3:
- case OS_POLICY_VISTA:
- case OS_POLICY_SOLARIS:
- /* Old Linux and windows allowed packet with 0 timestamp. */
- break;
- default:
- /* other OS simply drop the pakcet with 0 timestamp, when
- * 3whs has valid timestamp*/
- goto invalid;
- }
- }
-
- if (check_ts) {
- int32_t result = 0;
-
- SCLogDebug("ts %"PRIu32", last_ts %"PRIu32"", ts, sender_stream->last_ts);
-
- if (receiver_stream->os_policy == OS_POLICY_LINUX) {
- /* Linux accepts TS which are off by one.*/
- result = (int32_t) ((ts - sender_stream->last_ts) + 1);
- } else {
- result = (int32_t) (ts - sender_stream->last_ts);
- }
-
- SCLogDebug("result %"PRIi32", p->ts.tv_sec %"PRIuMAX"", result, (uintmax_t)p->ts.tv_sec);
-
- if (sender_stream->last_pkt_ts == 0 &&
- (ssn->flags & STREAMTCP_FLAG_MIDSTREAM))
- {
- sender_stream->last_pkt_ts = p->ts.tv_sec;
- }
-
- if (result < 0) {
- SCLogDebug("timestamp is not valid sender_stream->last_ts "
- "%" PRIu32 " p->tcpvars->ts %" PRIu32 " result "
- "%" PRId32 "", sender_stream->last_ts, ts, result);
- /* candidate for rejection */
- ret = 0;
- } else if ((sender_stream->last_ts != 0) &&
- (((uint32_t) p->ts.tv_sec) >
- sender_stream->last_pkt_ts + PAWS_24DAYS))
- {
- SCLogDebug("packet is not valid sender_stream->last_pkt_ts "
- "%" PRIu32 " p->ts.tv_sec %" PRIu32 "",
- sender_stream->last_pkt_ts, (uint32_t) p->ts.tv_sec);
- /* candidate for rejection */
- ret = 0;
- }
-
- if (ret == 1) {
- /* Update the timestamp and last seen packet time for this
- * stream */
- if (SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p)))
- sender_stream->last_ts = ts;
-
- sender_stream->last_pkt_ts = p->ts.tv_sec;
-
- } else if (ret == 0) {
- /* if the timestamp of packet is not valid then, check if the
- * current stream timestamp is not so old. if so then we need to
- * accept the packet and update the stream->last_ts (RFC 1323)*/
- if ((SEQ_EQ(sender_stream->next_seq, TCP_GET_SEQ(p))) &&
- (((uint32_t) p->ts.tv_sec > (sender_stream->last_pkt_ts + PAWS_24DAYS))))
- {
- sender_stream->last_ts = ts;
- sender_stream->last_pkt_ts = p->ts.tv_sec;
-
- SCLogDebug("timestamp considered valid anyway");
- } else {
- goto invalid;
- }
- }
- }
- } else {
- /* Solaris stops using timestamps if a packet is received
- without a timestamp and timestamps were used on that stream. */
- if (receiver_stream->os_policy == OS_POLICY_SOLARIS)
- ssn->flags &= ~STREAMTCP_FLAG_TIMESTAMP;
- }
-
- SCReturnInt(1);
-
-invalid:
- StreamTcpSetEvent(p, STREAM_PKT_INVALID_TIMESTAMP);
- SCReturnInt(0);
-}
-
-/**
- * \brief Function to test the received ACK values against the stream window
- * and previous ack value. ACK values should be higher than previous
- * ACK value and less than the next_win value.
- *
- * \param ssn TcpSession for state access
- * \param stream TcpStream of which last_ack needs to be tested
- * \param p Packet which is used to test the last_ack
- *
- * \retval 0 ACK is valid, last_ack is updated if ACK was higher
- * \retval -1 ACK is invalid
- */
-static inline int StreamTcpValidateAck(TcpSession *ssn, TcpStream *stream, Packet *p)
-{
- SCEnter();
-
- uint32_t ack = TCP_GET_ACK(p);
-
- /* fast track */
- if (SEQ_GT(ack, stream->last_ack) && SEQ_LEQ(ack, stream->next_win))
- {
- SCLogDebug("ACK in bounds");
- SCReturnInt(0);
- }
- /* fast track */
- else if (SEQ_EQ(ack, stream->last_ack)) {
- SCLogDebug("pkt ACK %"PRIu32" == stream last ACK %"PRIu32, TCP_GET_ACK(p), stream->last_ack);
- SCReturnInt(0);
- }
-
- /* exception handling */
- if (SEQ_LT(ack, stream->last_ack)) {
- SCLogDebug("pkt ACK %"PRIu32" < stream last ACK %"PRIu32, TCP_GET_ACK(p), stream->last_ack);
-
- /* This is an attempt to get a 'left edge' value that we can check against.
- * It doesn't work when the window is 0, need to think of a better way. */
-
- if (stream->window != 0 && SEQ_LT(ack, (stream->last_ack - stream->window))) {
- SCLogDebug("ACK %"PRIu32" is before last_ack %"PRIu32" - window "
- "%"PRIu32" = %"PRIu32, ack, stream->last_ack,
- stream->window, stream->last_ack - stream->window);
- goto invalid;
- }
-
- SCReturnInt(0);
- }
-
- if (ssn->state > TCP_SYN_SENT && SEQ_GT(ack, stream->next_win)) {
- SCLogDebug("ACK %"PRIu32" is after next_win %"PRIu32, ack, stream->next_win);
- goto invalid;
- /* a toclient RST as a reponse to SYN, next_win is 0, ack will be isn+1, just like
- * the syn ack */
- } else if (ssn->state == TCP_SYN_SENT && PKT_IS_TOCLIENT(p) &&
- p->tcph->th_flags & TH_RST &&
- SEQ_EQ(ack, stream->isn + 1)) {
- SCReturnInt(0);
- }
-
- SCLogDebug("default path leading to invalid: ACK %"PRIu32", last_ack %"PRIu32
- " next_win %"PRIu32, ack, stream->last_ack, stream->next_win);
-invalid:
- StreamTcpSetEvent(p, STREAM_PKT_INVALID_ACK);
- SCReturnInt(-1);
-}
-
-/** \brief Set the No reassembly flag for the given direction in given TCP
- * session.
- *
- * \param ssn TCP Session to set the flag in
- * \param direction direction to set the flag in: 0 toserver, 1 toclient
- */
-void StreamTcpSetSessionNoReassemblyFlag (TcpSession *ssn, char direction)
-{
- direction ? (ssn->server.flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY) :
- (ssn->client.flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY);
-}
-
-/** \brief Set the No reassembly flag for the given direction in given TCP
- * session.
- *
- * \param ssn TCP Session to set the flag in
- * \param direction direction to set the flag in: 0 toserver, 1 toclient
- */
-void StreamTcpSetDisableRawReassemblyFlag (TcpSession *ssn, char direction)
-{
- direction ? (ssn->server.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) :
- (ssn->client.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED);
-}
-
-#define PSEUDO_PKT_SET_IPV4HDR(nipv4h,ipv4h) do { \
- IPV4_SET_RAW_VER(nipv4h, IPV4_GET_RAW_VER(ipv4h)); \
- IPV4_SET_RAW_HLEN(nipv4h, IPV4_GET_RAW_HLEN(ipv4h)); \
- IPV4_SET_RAW_IPLEN(nipv4h, IPV4_GET_RAW_IPLEN(ipv4h)); \
- IPV4_SET_RAW_IPTOS(nipv4h, IPV4_GET_RAW_IPTOS(ipv4h)); \
- IPV4_SET_RAW_IPPROTO(nipv4h, IPV4_GET_RAW_IPPROTO(ipv4h)); \
- (nipv4h)->s_ip_src = IPV4_GET_RAW_IPDST(ipv4h); \
- (nipv4h)->s_ip_dst = IPV4_GET_RAW_IPSRC(ipv4h); \
- } while (0)
-
-#define PSEUDO_PKT_SET_IPV6HDR(nipv6h,ipv6h) do { \
- (nipv6h)->s_ip6_src[0] = (ipv6h)->s_ip6_dst[0]; \
- (nipv6h)->s_ip6_src[1] = (ipv6h)->s_ip6_dst[1]; \
- (nipv6h)->s_ip6_src[2] = (ipv6h)->s_ip6_dst[2]; \
- (nipv6h)->s_ip6_src[3] = (ipv6h)->s_ip6_dst[3]; \
- (nipv6h)->s_ip6_dst[0] = (ipv6h)->s_ip6_src[0]; \
- (nipv6h)->s_ip6_dst[1] = (ipv6h)->s_ip6_src[1]; \
- (nipv6h)->s_ip6_dst[2] = (ipv6h)->s_ip6_src[2]; \
- (nipv6h)->s_ip6_dst[3] = (ipv6h)->s_ip6_src[3]; \
- IPV6_SET_RAW_NH(nipv6h, IPV6_GET_RAW_NH(ipv6h)); \
- } while (0)
-
-#define PSEUDO_PKT_SET_TCPHDR(ntcph,tcph) do { \
- COPY_PORT((tcph)->th_dport, (ntcph)->th_sport); \
- COPY_PORT((tcph)->th_sport, (ntcph)->th_dport); \
- (ntcph)->th_seq = (tcph)->th_ack; \
- (ntcph)->th_ack = (tcph)->th_seq; \
- } while (0)
-
-/**
- * \brief Function to fetch a packet from the packet allocation queue for
- * creation of the pseudo packet from the reassembled stream.
- *
- * @param parent Pointer to the parent of the pseudo packet
- * @param pkt pointer to the raw packet of the parent
- * @param len length of the packet
- * @return upon success returns the pointer to the new pseudo packet
- * otherwise NULL
- */
-Packet *StreamTcpPseudoSetup(Packet *parent, uint8_t *pkt, uint32_t len)
-{
- SCEnter();
-
- if (len == 0) {
- SCReturnPtr(NULL, "Packet");
- }
-
- Packet *p = PacketGetFromQueueOrAlloc();
- if (p == NULL) {
- SCReturnPtr(NULL, "Packet");
- }
-
- /* set the root ptr to the lowest layer */
- if (parent->root != NULL)
- p->root = parent->root;
- else
- p->root = parent;
-
- /* copy packet and set lenght, proto */
- p->proto = parent->proto;
- p->datalink = parent->datalink;
-
- PacketCopyData(p, pkt, len);
- p->recursion_level = parent->recursion_level + 1;
- p->ts.tv_sec = parent->ts.tv_sec;
- p->ts.tv_usec = parent->ts.tv_usec;
-
- FlowReference(&p->flow, parent->flow);
- /* set tunnel flags */
-
- /* tell new packet it's part of a tunnel */
- SET_TUNNEL_PKT(p);
- /* tell parent packet it's part of a tunnel */
- SET_TUNNEL_PKT(parent);
-
- /* increment tunnel packet refcnt in the root packet */
- TUNNEL_INCR_PKT_TPR(p);
-
- return p;
-}
-
-/**
- * \brief Function to setup the IP and TCP header of the pseudo packet from
- * the newly copied raw packet contents of the parent.
- *
- * @param np pointer to the pseudo packet
- * @param p pointer to the original packet
- */
-static void StreamTcpPseudoPacketSetupHeader(Packet *np, Packet *p)
-{
- /* Setup the IP header */
- if (PKT_IS_IPV4(p)) {
- np->ip4h = (IPV4Hdr *)((uint8_t *)GET_PKT_DATA(np) + (GET_PKT_LEN(np) - IPV4_GET_IPLEN(p)));
- PSEUDO_PKT_SET_IPV4HDR(np->ip4h, p->ip4h);
-
- /* Similarly setup the TCP header with ports in opposite direction */
- np->tcph = (TCPHdr *)((uint8_t *)np->ip4h + IPV4_GET_HLEN(np));
-
- PSEUDO_PKT_SET_TCPHDR(np->tcph, p->tcph);
-
- /* Setup the adress and port details */
- SET_IPV4_SRC_ADDR(p, &np->dst);
- SET_IPV4_DST_ADDR(p, &np->src);
- SET_TCP_SRC_PORT(p, &np->dp);
- SET_TCP_DST_PORT(p, &np->sp);
-
- } else if (PKT_IS_IPV6(p)) {
- np->ip6h = (IPV6Hdr *)((uint8_t *)GET_PKT_DATA(np) + (GET_PKT_LEN(np) - IPV6_GET_PLEN(p) - IPV6_HEADER_LEN));
- PSEUDO_PKT_SET_IPV6HDR(np->ip6h, p->ip6h);
-
- /* Similarly setup the TCP header with ports in opposite direction */
- np->tcph = (TCPHdr *)((uint8_t *)np->ip6h + IPV6_HEADER_LEN);
- PSEUDO_PKT_SET_TCPHDR(np->tcph, p->tcph);
-
- /* Setup the adress and port details */
- SET_IPV6_SRC_ADDR(p, &np->dst);
- SET_IPV6_DST_ADDR(p, &np->src);
- SET_TCP_SRC_PORT(p, &np->dp);
- SET_TCP_DST_PORT(p, &np->sp);
- }
-
- /* we don't need a payload (if any) */
- np->payload = NULL;
- np->payload_len = 0;
-}
-
-/** \brief Create a pseudo packet injected into the engine to signal the
- * opposing direction of this stream to wrap up stream reassembly.
- *
- * \param p real packet
- * \param pq packet queue to store the new pseudo packet in
- */
-void StreamTcpPseudoPacketCreateStreamEndPacket(ThreadVars *tv, StreamTcpThread *stt, Packet *p, TcpSession *ssn, PacketQueue *pq)
-{
- SCEnter();
-
- if (p->flags & PKT_PSEUDO_STREAM_END) {
- SCReturn;
- }
-
- /* no need for a pseudo packet if there is nothing left to reassemble */
- if (ssn->server.seg_list == NULL && ssn->client.seg_list == NULL) {
- SCReturn;
- }
-
- Packet *np = StreamTcpPseudoSetup(p, GET_PKT_DATA(p), GET_PKT_LEN(p));
- if (np == NULL) {
- SCLogDebug("The packet received from packet allocation is NULL");
- StatsIncr(tv, stt->counter_tcp_pseudo_failed);
- SCReturn;
- }
- PKT_SET_SRC(np, PKT_SRC_STREAM_TCP_STREAM_END_PSEUDO);
-
- /* Setup the IP and TCP headers */
- StreamTcpPseudoPacketSetupHeader(np,p);
-
- np->tenant_id = p->flow->tenant_id;
-
- np->flowflags = p->flowflags;
-
- np->flags |= PKT_STREAM_EST;
- np->flags |= PKT_STREAM_EOF;
- np->flags |= PKT_HAS_FLOW;
- np->flags |= PKT_PSEUDO_STREAM_END;
-
- if (p->flags & PKT_NOPACKET_INSPECTION) {
- DecodeSetNoPacketInspectionFlag(np);
- }
- if (p->flags & PKT_NOPAYLOAD_INSPECTION) {
- DecodeSetNoPayloadInspectionFlag(np);
- }
-
- if (PKT_IS_TOSERVER(p)) {
- SCLogDebug("original is to_server, so pseudo is to_client");
- np->flowflags &= ~FLOW_PKT_TOSERVER;
- np->flowflags |= FLOW_PKT_TOCLIENT;
-#ifdef DEBUG
- BUG_ON(!(PKT_IS_TOCLIENT(np)));
- BUG_ON((PKT_IS_TOSERVER(np)));
-#endif
- } else if (PKT_IS_TOCLIENT(p)) {
- SCLogDebug("original is to_client, so pseudo is to_server");
- np->flowflags &= ~FLOW_PKT_TOCLIENT;
- np->flowflags |= FLOW_PKT_TOSERVER;
-#ifdef DEBUG
- BUG_ON(!(PKT_IS_TOSERVER(np)));
- BUG_ON((PKT_IS_TOCLIENT(np)));
-#endif
- }
-
- PacketEnqueue(pq, np);
-
- StatsIncr(tv, stt->counter_tcp_pseudo);
- SCReturn;
-}
-
-/**
- * \brief Run callback function on each TCP segment
- *
- * This function is used by StreamMsgForEach() which
- * should be used directly.
- *
- * \return -1 in case of error, the number of segment in case of success
- *
- */
-int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback CallbackFunc, void *data)
-{
- TcpSession *ssn = NULL;
- TcpStream *stream = NULL;
- int ret = 0;
- int cnt = 0;
-
- if (p->flow == NULL)
- return 0;
-
- FLOWLOCK_RDLOCK(p->flow);
- ssn = (TcpSession *)p->flow->protoctx;
-
- if (ssn == NULL) {
- FLOWLOCK_UNLOCK(p->flow);
- return 0;
- }
-
- if (flag & FLOW_PKT_TOSERVER) {
- stream = &(ssn->server);
- } else {
- stream = &(ssn->client);
- }
- TcpSegment *seg = stream->seg_list;
- for (; seg != NULL && SEQ_LT(seg->seq, stream->last_ack);) {
- ret = CallbackFunc(p, data, seg->payload, seg->payload_len);
- if (ret != 1) {
- SCLogDebug("Callback function has failed");
- FLOWLOCK_UNLOCK(p->flow);
- return -1;
- }
- seg = seg->next;
- cnt++;
- }
- FLOWLOCK_UNLOCK(p->flow);
- return cnt;
-}
-
-#ifdef UNITTESTS
-
-/**
- * \test Test the allocation of TCP session for a given packet from the
- * ssn_pool.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest01 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- memset(p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
- int ret = 0;
-
- StreamTcpInitConfig(TRUE);
-
- TcpSession *ssn = StreamTcpNewSession(p, 0);
- if (ssn == NULL) {
- printf("Session can not be allocated: ");
- goto end;
- }
- f.protoctx = ssn;
-
- if (f.alparser != NULL) {
- printf("AppLayer field not set to NULL: ");
- goto end;
- }
- if (ssn->state != 0) {
- printf("TCP state field not set to 0: ");
- goto end;
- }
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the deallocation of TCP session for a given packet and return
- * the memory back to ssn_pool and corresponding segments to segment
- * pool.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest02 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- uint8_t payload[4];
- TCPHdr tcph;
- TcpReassemblyThreadCtx ra_ctx;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx));
- memset(p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
- tcph.th_win = htons(5480);
- tcph.th_flags = TH_SYN;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
- int ret = 0;
- stt.ra_ctx = &ra_ctx;
-
- StreamTcpInitConfig(TRUE);
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- goto end;
- }
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(1);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(2);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->flowflags = FLOW_PKT_TOCLIENT;
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(6);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->flowflags = FLOW_PKT_TOCLIENT;
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the setting up a TCP session when we missed the intial
- * SYN packet of the session. The session is setup only if midstream
- * sessions are allowed to setup.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest03 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- memset(p, 0, SIZE_OF_PACKET);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
-
- StreamTcpInitConfig(TRUE);
-
- tcph.th_win = htons(5480);
- tcph.th_seq = htonl(10);
- tcph.th_ack = htonl(20);
- tcph.th_flags = TH_SYN|TH_ACK;
- p->tcph = &tcph;
- int ret = 0;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(20);
- p->tcph->th_ack = htonl(11);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(19);
- p->tcph->th_ack = htonl(11);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (stream_config.midstream != TRUE) {
- ret = 1;
- goto end;
- }
- if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
- goto end;
-
- if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 20 &&
- ((TcpSession *)(p->flow->protoctx))->server.next_seq != 11)
- goto end;
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the setting up a TCP session when we missed the intial
- * SYN/ACK packet of the session. The session is setup only if
- * midstream sessions are allowed to setup.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest04 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- memset(p, 0, SIZE_OF_PACKET);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
-
- StreamTcpInitConfig(TRUE);
-
- tcph.th_win = htons(5480);
- tcph.th_seq = htonl(10);
- tcph.th_ack = htonl(20);
- tcph.th_flags = TH_ACK;
- p->tcph = &tcph;
-
- int ret = 0;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(9);
- p->tcph->th_ack = htonl(19);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (stream_config.midstream != TRUE) {
- ret = 1;
- goto end;
- }
- if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
- goto end;
-
- if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 10 &&
- ((TcpSession *)(p->flow->protoctx))->server.next_seq != 20)
- goto end;
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the setting up a TCP session when we missed the intial
- * 3WHS packet of the session. The session is setup only if
- * midstream sessions are allowed to setup.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest05 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- uint8_t payload[4];
- memset(p, 0, SIZE_OF_PACKET);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
- int ret = 0;
-
- StreamTcpInitConfig(TRUE);
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- 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;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(20);
- p->tcph->th_ack = htonl(13);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(13);
- p->tcph->th_ack = htonl(23);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x43, 3, 4); /*CCC*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(19);
- p->tcph->th_ack = htonl(16);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x44, 3, 4); /*DDD*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (stream_config.midstream != TRUE) {
- ret = 1;
- goto end;
- }
- if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
- goto end;
-
- if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 16 &&
- ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23)
- goto end;
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the setting up a TCP session when we have seen only the
- * FIN, RST packets packet of the session. The session is setup only if
- * midstream sessions are allowed to setup.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest06 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- TcpSession ssn;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- memset(p, 0, SIZE_OF_PACKET);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&ssn, 0, sizeof (TcpSession));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
- int ret = 0;
-
- StreamTcpInitConfig(TRUE);
-
- tcph.th_flags = TH_FIN;
- p->tcph = &tcph;
-
- SCMutexLock(&f.m);
- /* StreamTcpPacket returns -1 on unsolicited FIN */
- if (StreamTcpPacket(&tv, p, &stt, &pq) != -1) {
- printf("StreamTcpPacket failed: ");
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx)) != NULL) {
- printf("we have a ssn while we shouldn't: ");
- goto end;
- }
-
- p->tcph->th_flags = TH_RST;
- /* StreamTcpPacket returns -1 on unsolicited RST */
- if (StreamTcpPacket(&tv, p, &stt, &pq) != -1) {
- printf("StreamTcpPacket failed (2): ");
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx)) != NULL) {
- printf("we have a ssn while we shouldn't (2): ");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the working on PAWS. The packet will be dropped by stream, as
- * its timestamp is old, although the segment is in the window.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest07 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- uint8_t payload[1] = {0x42};
- TCPVars tcpvars;
- TCPOpt ts;
- uint32_t data[2];
- PacketQueue pq;
-
- memset(p, 0, SIZE_OF_PACKET);
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof(StreamTcpThread));
- memset(&tcph, 0, sizeof(TCPHdr));
- memset(&tcpvars, 0, sizeof(TCPVars));
- memset(&ts, 0, sizeof(TCPOpt));
-
- FLOW_INITIALIZE(&f);
- p->flow = &f;
- int ret = 0;
-
- StreamTcpInitConfig(TRUE);
- stream_config.midstream = TRUE;
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- 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;
-
- data[0] = htonl(10);
- data[1] = htonl(11);
-
- ts.type = TCP_OPT_TS;
- ts.len = 10;
- ts.data = (uint8_t *)data;
- tcpvars.ts = &ts;
- p->tcpvars = tcpvars;
-
- p->payload = payload;
- p->payload_len = 1;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(11);
- p->tcph->th_ack = htonl(23);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- data[0] = htonl(2);
- p->tcpvars.ts->data = (uint8_t *)data;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- if (((TcpSession *) (p->flow->protoctx))->client.next_seq != 11) {
- printf("the timestamp values are client %"PRIu32" server %" PRIu32""
- " seq %" PRIu32 "\n", TCP_GET_TSVAL(p), TCP_GET_TSECR(p),
- ((TcpSession *) (p->flow->protoctx))->client.next_seq);
- goto end;
- }
-
- StreamTcpSessionClear(p->flow->protoctx);
- ret = 1;
- }
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the working on PAWS. The packet will be accpeted by engine as
- * the timestamp is valid and it is in window.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest08 (void)
-{
-
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- uint8_t payload[1] = {0x42};
- TCPVars tcpvars;
- TCPOpt ts;
- uint32_t data[2];
-
- memset(p, 0, SIZE_OF_PACKET);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof(StreamTcpThread));
- memset(&tcph, 0, sizeof(TCPHdr));
- memset(&tcpvars, 0, sizeof(TCPVars));
- memset(&ts, 0, sizeof(TCPOpt));
-
- FLOW_INITIALIZE(&f);
- p->flow = &f;
- int ret = 0;
-
- StreamTcpInitConfig(TRUE);
- stream_config.midstream = TRUE;
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- 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;
-
- data[0] = htonl(10);
- data[1] = htonl(11);
-
- ts.type = TCP_OPT_TS;
- ts.len = 10;
- ts.data = (uint8_t *)data;
- tcpvars.ts = &ts;
- p->tcpvars = tcpvars;
-
- p->payload = payload;
- p->payload_len = 1;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(11);
- p->tcph->th_ack = htonl(20);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- data[0] = htonl(12);
- p->tcpvars.ts->data = (uint8_t *)data;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (((TcpSession *) (p->flow->protoctx))->client.next_seq != 12) {
- printf("the timestamp values are client %"PRIu32" server %" PRIu32 " "
- "seq %" PRIu32 "\n", TCP_GET_TSVAL(p), TCP_GET_TSECR(p),
- ((TcpSession *) (p->flow->protoctx))->client.next_seq);
- goto end;
- }
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the working of No stream reassembly flag. The stream will not
- * reassemble the segment if the flag is set.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest09 (void)
-{
-
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- uint8_t payload[1] = {0x42};
-
- memset(p, 0, SIZE_OF_PACKET);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof(StreamTcpThread));
- memset(&tcph, 0, sizeof(TCPHdr));
-
- FLOW_INITIALIZE(&f);
- p->flow = &f;
- int ret = 0;
-
- StreamTcpInitConfig(TRUE);
- stream_config.midstream = TRUE;
-
- //prevent L7 from kicking in
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- 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->payload = payload;
- p->payload_len = 1;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(12);
- p->tcph->th_ack = htonl(23);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpSetSessionNoReassemblyFlag(((TcpSession *)(p->flow->protoctx)), 0);
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(11);
- p->tcph->th_ack = htonl(23);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (((TcpSession *) (p->flow->protoctx))->client.seg_list->next == NULL)
- ret = 1;
-
- StreamTcpSessionClear(p->flow->protoctx);
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the setting up a TCP session when we are seeing asynchronous
- * stream, while we see all the packets in that stream from start.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest10 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- uint8_t payload[4];
- memset(p, 0, SIZE_OF_PACKET);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
-
- StreamTcpInitConfig(TRUE);
-
- tcph.th_win = htons(5480);
- tcph.th_seq = htonl(10);
- tcph.th_ack = htonl(11);
- tcph.th_flags = TH_SYN;
- p->tcph = &tcph;
- int ret = 0;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(11);
- p->tcph->th_ack = htonl(11);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(11);
- p->tcph->th_ack = htonl(11);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(6);
- p->tcph->th_ack = htonl(11);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (stream_config.async_oneside != TRUE) {
- ret = 1;
- goto end;
- }
- if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) {
- printf("failed in setting state\n");
- goto end;
- }
-
- if (! (((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_ASYNC)) {
- printf("failed in setting asynchronous session\n");
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx))->client.last_ack != 6 &&
- ((TcpSession *)(p->flow->protoctx))->server.next_seq != 11) {
- printf("failed in seq %"PRIu32" match\n",
- ((TcpSession *)(p->flow->protoctx))->client.last_ack);
- goto end;
- }
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the setting up a TCP session when we are seeing asynchronous
- * stream, while we missed the SYN packet of that stream.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest11 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- uint8_t payload[4];
- memset(p, 0, SIZE_OF_PACKET);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
-
- StreamTcpInitConfig(TRUE);
-
- tcph.th_win = htons(5480);
- tcph.th_seq = htonl(10);
- tcph.th_ack = htonl(1);
- tcph.th_flags = TH_SYN|TH_ACK;
- p->tcph = &tcph;
- int ret = 0;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(11);
- p->tcph->th_ack = htonl(1);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(11);
- p->tcph->th_ack = htonl(1);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(2);
- p->tcph->th_ack = htonl(1);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (stream_config.async_oneside != TRUE) {
- ret = 1;
- goto end;
- }
-
- if (! (((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_ASYNC)) {
- printf("failed in setting asynchronous session\n");
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) {
- printf("failed in setting state\n");
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 2 &&
- ((TcpSession *)(p->flow->protoctx))->client.next_seq != 1) {
- printf("failed in seq %"PRIu32" match\n",
- ((TcpSession *)(p->flow->protoctx))->server.last_ack);
- goto end;
- }
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the setting up a TCP session when we are seeing asynchronous
- * stream, while we missed the SYN and SYN/ACK packets in that stream.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest12 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- uint8_t payload[4];
- memset(p, 0, SIZE_OF_PACKET);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
-
- StreamTcpInitConfig(TRUE);
-
- tcph.th_win = htons(5480);
- tcph.th_seq = htonl(10);
- tcph.th_ack = htonl(11);
- tcph.th_flags = TH_ACK;
- p->tcph = &tcph;
- int ret = 0;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(10);
- p->tcph->th_ack = htonl(11);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(6);
- p->tcph->th_ack = htonl(11);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (stream_config.async_oneside != TRUE) {
- ret = 1;
- goto end;
- }
-
- if (! (((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_ASYNC)) {
- printf("failed in setting asynchronous session\n");
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) {
- printf("failed in setting state\n");
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx))->client.last_ack != 6 &&
- ((TcpSession *)(p->flow->protoctx))->server.next_seq != 11) {
- printf("failed in seq %"PRIu32" match\n",
- ((TcpSession *)(p->flow->protoctx))->client.last_ack);
- goto end;
- }
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the setting up a TCP session when we are seeing asynchronous
- * stream, while we missed the SYN and SYN/ACK packets in that stream.
- * Later, we start to receive the packet from other end stream too.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest13 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- uint8_t payload[4];
- memset(p, 0, SIZE_OF_PACKET);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
-
- StreamTcpInitConfig(TRUE);
-
- tcph.th_win = htons(5480);
- tcph.th_seq = htonl(10);
- tcph.th_ack = htonl(11);
- tcph.th_flags = TH_ACK;
- p->tcph = &tcph;
- int ret = 0;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(10);
- p->tcph->th_ack = htonl(11);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(6);
- p->tcph->th_ack = htonl(11);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (stream_config.async_oneside != TRUE) {
- ret = 1;
- goto end;
- }
-
- if (! (((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_ASYNC)) {
- printf("failed in setting asynchronous session\n");
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) {
- printf("failed in setting state\n");
- goto end;
- }
-
- p->tcph->th_seq = htonl(11);
- p->tcph->th_ack = htonl(9);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (((TcpSession *)(p->flow->protoctx))->client.last_ack != 9 &&
- ((TcpSession *)(p->flow->protoctx))->server.next_seq != 14) {
- printf("failed in seq %"PRIu32" match\n",
- ((TcpSession *)(p->flow->protoctx))->client.last_ack);
- goto end;
- }
-
- StreamTcpSessionPktFree(p);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/* Dummy conf string to setup the OS policy for unit testing */
-static const char *dummy_conf_string =
- "%YAML 1.1\n"
- "---\n"
- "\n"
- "default-log-dir: /var/log/eidps\n"
- "\n"
- "logging:\n"
- "\n"
- " default-log-level: debug\n"
- "\n"
- " default-format: \"<%t> - <%l>\"\n"
- "\n"
- " default-startup-message: Your IDS has started.\n"
- "\n"
- " default-output-filter:\n"
- "\n"
- "host-os-policy:\n"
- "\n"
- " windows: 192.168.0.1\n"
- "\n"
- " linux: 192.168.0.2\n"
- "\n";
-/* Dummy conf string to setup the OS policy for unit testing */
-static const char *dummy_conf_string1 =
- "%YAML 1.1\n"
- "---\n"
- "\n"
- "default-log-dir: /var/log/eidps\n"
- "\n"
- "logging:\n"
- "\n"
- " default-log-level: debug\n"
- "\n"
- " default-format: \"<%t> - <%l>\"\n"
- "\n"
- " default-startup-message: Your IDS has started.\n"
- "\n"
- " default-output-filter:\n"
- "\n"
- "host-os-policy:\n"
- "\n"
- " windows: 192.168.0.0/24," "192.168.1.1\n"
- "\n"
- " linux: 192.168.1.0/24," "192.168.0.1\n"
- "\n";
-
-/**
- * \brief Function to parse the dummy conf string and get the value of IP
- * address for the corresponding OS policy type.
- *
- * \param conf_val_name Name of the OS policy type
- * \retval returns IP address as string on success and NULL on failure
- */
-char *StreamTcpParseOSPolicy (char *conf_var_name)
-{
- SCEnter();
- char conf_var_type_name[15] = "host-os-policy";
- char *conf_var_full_name = NULL;
- char *conf_var_value = NULL;
-
- if (conf_var_name == NULL)
- goto end;
-
- /* the + 2 is for the '.' and the string termination character '\0' */
- conf_var_full_name = (char *)SCMalloc(strlen(conf_var_type_name) +
- strlen(conf_var_name) + 2);
- if (conf_var_full_name == NULL)
- goto end;
-
- if (snprintf(conf_var_full_name,
- strlen(conf_var_type_name) + strlen(conf_var_name) + 2, "%s.%s",
- conf_var_type_name, conf_var_name) < 0) {
- SCLogError(SC_ERR_INVALID_VALUE, "Error in making the conf full name");
- goto end;
- }
-
- if (ConfGet(conf_var_full_name, &conf_var_value) != 1) {
- SCLogError(SC_ERR_UNKNOWN_VALUE, "Error in getting conf value for conf name %s",
- conf_var_full_name);
- goto end;
- }
-
- SCLogDebug("Value obtained from the yaml conf file, for the var "
- "\"%s\" is \"%s\"", conf_var_name, conf_var_value);
-
- end:
- if (conf_var_full_name != NULL)
- SCFree(conf_var_full_name);
- SCReturnCharPtr(conf_var_value);
-
-
-}
-/**
- * \test Test the setting up a OS policy. Te OS policy values are defined in
- * the config string "dummy_conf_string"
- *
- * \retval On success it returns 1 and on failure 0
- */
-
-static int StreamTcpTest14 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- uint8_t payload[4];
- struct in_addr addr;
- IPV4Hdr ipv4h;
- char os_policy_name[10] = "windows";
- char *ip_addr;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- memset(p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- memset(&addr, 0, sizeof(addr));
- memset(&ipv4h, 0, sizeof(ipv4h));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
- int ret = 0;
-
- StreamTcpInitConfig(TRUE);
-
- /* Load the config string in to parser */
- ConfCreateContextBackup();
- ConfInit();
- ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string));
-
- /* Get the IP address as string and add it to Host info tree for lookups */
- ip_addr = StreamTcpParseOSPolicy(os_policy_name);
- SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
- strlcpy(os_policy_name, "linux\0", sizeof(os_policy_name));
- ip_addr = StreamTcpParseOSPolicy(os_policy_name);
- SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- addr.s_addr = inet_addr("192.168.0.1");
- 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->dst.family = AF_INET;
- p->dst.address.address_un_data32[0] = addr.s_addr;
- p->ip4h = &ipv4h;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, sizeof(payload)); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(20);
- p->tcph->th_ack = htonl(13);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, sizeof(payload)); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(15);
- p->tcph->th_ack = htonl(23);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(14);
- p->tcph->th_ack = htonl(23);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- addr.s_addr = inet_addr("192.168.0.2");
- p->tcph->th_seq = htonl(25);
- p->tcph->th_ack = htonl(13);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
- p->dst.address.address_un_data32[0] = addr.s_addr;
-
- StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(24);
- p->tcph->th_ack = htonl(13);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (stream_config.midstream != TRUE) {
- ret = 1;
- goto end;
- }
- if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
- goto end;
-
- if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 13 &&
- ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23) {
- printf("failed in next_seq match client.next_seq %"PRIu32""
- " server.next_seq %"PRIu32"\n",
- ((TcpSession *)(p->flow->protoctx))->client.next_seq,
- ((TcpSession *)(p->flow->protoctx))->server.next_seq);
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx))->client.os_policy !=
- OS_POLICY_WINDOWS && ((TcpSession *)
- (p->flow->protoctx))->server.os_policy != OS_POLICY_LINUX)
- {
- printf("failed in setting up OS policy, client.os_policy: %"PRIu8""
- " should be %"PRIu8" and server.os_policy: %"PRIu8""
- " should be %"PRIu8"\n", ((TcpSession *)
- (p->flow->protoctx))->client.os_policy, OS_POLICY_WINDOWS,
- ((TcpSession *)(p->flow->protoctx))->server.os_policy,
- OS_POLICY_LINUX);
- goto end;
- }
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- ConfDeInit();
- ConfRestoreContextBackup();
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the setting up a TCP session using the 4WHS:
- * SYN, SYN, SYN/ACK, ACK
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcp4WHSTest01 (void)
-{
- int ret = 0;
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- memset(p, 0, SIZE_OF_PACKET);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
-
- StreamTcpInitConfig(TRUE);
-
- tcph.th_win = htons(5480);
- tcph.th_seq = htonl(10);
- tcph.th_ack = 0;
- tcph.th_flags = TH_SYN;
- p->tcph = &tcph;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(20);
- p->tcph->th_ack = 0;
- p->tcph->th_flags = TH_SYN;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if ((!(((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_4WHS))) {
- printf("STREAMTCP_FLAG_4WHS flag not set: ");
- goto end;
- }
-
- p->tcph->th_seq = htonl(10);
- p->tcph->th_ack = htonl(21); /* the SYN/ACK uses the SEQ from the first SYN pkt */
- p->tcph->th_flags = TH_SYN|TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(21);
- p->tcph->th_ack = htonl(10);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) {
- printf("state is not ESTABLISHED: ");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpSessionClear(p->flow->protoctx);
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test set up a TCP session using the 4WHS:
- * SYN, SYN, SYN/ACK, ACK, but the SYN/ACK does
- * not have the right SEQ
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcp4WHSTest02 (void)
-{
- int ret = 0;
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- memset(p, 0, SIZE_OF_PACKET);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
-
- StreamTcpInitConfig(TRUE);
-
- tcph.th_win = htons(5480);
- tcph.th_seq = htonl(10);
- tcph.th_ack = 0;
- tcph.th_flags = TH_SYN;
- p->tcph = &tcph;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(20);
- p->tcph->th_ack = 0;
- p->tcph->th_flags = TH_SYN;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if ((!(((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_4WHS))) {
- printf("STREAMTCP_FLAG_4WHS flag not set: ");
- goto end;
- }
-
- p->tcph->th_seq = htonl(30);
- p->tcph->th_ack = htonl(21); /* the SYN/ACK uses the SEQ from the first SYN pkt */
- p->tcph->th_flags = TH_SYN|TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) != -1) {
- printf("SYN/ACK pkt not rejected but it should have: ");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpSessionClear(p->flow->protoctx);
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test set up a TCP session using the 4WHS:
- * SYN, SYN, SYN/ACK, ACK: however the SYN/ACK and ACK
- * are part of a normal 3WHS
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcp4WHSTest03 (void)
-{
- int ret = 0;
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- memset(p, 0, SIZE_OF_PACKET);
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
-
- StreamTcpInitConfig(TRUE);
-
- tcph.th_win = htons(5480);
- tcph.th_seq = htonl(10);
- tcph.th_ack = 0;
- tcph.th_flags = TH_SYN;
- p->tcph = &tcph;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(20);
- p->tcph->th_ack = 0;
- p->tcph->th_flags = TH_SYN;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if ((!(((TcpSession *)(p->flow->protoctx))->flags & STREAMTCP_FLAG_4WHS))) {
- printf("STREAMTCP_FLAG_4WHS flag not set: ");
- goto end;
- }
-
- p->tcph->th_seq = htonl(30);
- p->tcph->th_ack = htonl(11);
- p->tcph->th_flags = TH_SYN|TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(11);
- p->tcph->th_ack = htonl(31);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED) {
- printf("state is not ESTABLISHED: ");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpSessionClear(p->flow->protoctx);
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the setting up a OS policy. Te OS policy values are defined in
- * the config string "dummy_conf_string1"
- *
- * \retval On success it returns 1 and on failure 0
- */
-
-static int StreamTcpTest15 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- uint8_t payload[4];
- struct in_addr addr;
- IPV4Hdr ipv4h;
- char os_policy_name[10] = "windows";
- char *ip_addr;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- memset(p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- memset(&addr, 0, sizeof(addr));
- memset(&ipv4h, 0, sizeof(ipv4h));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
- int ret = 0;
-
- StreamTcpInitConfig(TRUE);
-
- /* Load the config string in to parser */
- ConfCreateContextBackup();
- ConfInit();
- ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
-
- /* Get the IP address as string and add it to Host info tree for lookups */
- ip_addr = StreamTcpParseOSPolicy(os_policy_name);
- SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
- strlcpy(os_policy_name, "linux\0", sizeof(os_policy_name));
- ip_addr = StreamTcpParseOSPolicy(os_policy_name);
- SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- addr.s_addr = inet_addr("192.168.0.20");
- 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->dst.family = AF_INET;
- p->dst.address.address_un_data32[0] = addr.s_addr;
- p->ip4h = &ipv4h;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, sizeof(payload)); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(20);
- p->tcph->th_ack = htonl(13);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, sizeof(payload)); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(15);
- p->tcph->th_ack = htonl(23);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(14);
- p->tcph->th_ack = htonl(23);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- addr.s_addr = inet_addr("192.168.1.20");
- p->tcph->th_seq = htonl(25);
- p->tcph->th_ack = htonl(13);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
- p->dst.address.address_un_data32[0] = addr.s_addr;
-
- StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(24);
- p->tcph->th_ack = htonl(13);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (stream_config.midstream != TRUE) {
- ret = 1;
- goto end;
- }
- if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
- goto end;
-
- if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 13 &&
- ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23) {
- printf("failed in next_seq match client.next_seq %"PRIu32""
- " server.next_seq %"PRIu32"\n",
- ((TcpSession *)(p->flow->protoctx))->client.next_seq,
- ((TcpSession *)(p->flow->protoctx))->server.next_seq);
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx))->client.os_policy !=
- OS_POLICY_WINDOWS && ((TcpSession *)
- (p->flow->protoctx))->server.os_policy != OS_POLICY_LINUX)
- {
- printf("failed in setting up OS policy, client.os_policy: %"PRIu8""
- " should be %"PRIu8" and server.os_policy: %"PRIu8""
- " should be %"PRIu8"\n", ((TcpSession *)
- (p->flow->protoctx))->client.os_policy, OS_POLICY_WINDOWS,
- ((TcpSession *)(p->flow->protoctx))->server.os_policy,
- OS_POLICY_LINUX);
- goto end;
- }
- StreamTcpSessionPktFree(p);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- ConfDeInit();
- ConfRestoreContextBackup();
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the setting up a OS policy. Te OS policy values are defined in
- * the config string "dummy_conf_string1"
- *
- * \retval On success it returns 1 and on failure 0
- */
-
-static int StreamTcpTest16 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- uint8_t payload[4];
- struct in_addr addr;
- IPV4Hdr ipv4h;
- char os_policy_name[10] = "windows";
- char *ip_addr;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- memset(p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- memset(&addr, 0, sizeof(addr));
- memset(&ipv4h, 0, sizeof(ipv4h));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
- int ret = 0;
-
- StreamTcpInitConfig(TRUE);
-
- /* Load the config string in to parser */
- ConfCreateContextBackup();
- ConfInit();
- ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
-
- /* Get the IP address as string and add it to Host info tree for lookups */
- ip_addr = StreamTcpParseOSPolicy(os_policy_name);
- SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
- strlcpy(os_policy_name, "linux\0", sizeof(os_policy_name));
- ip_addr = StreamTcpParseOSPolicy(os_policy_name);
- SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- addr.s_addr = inet_addr("192.168.0.1");
- 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->dst.family = AF_INET;
- p->dst.address.address_un_data32[0] = addr.s_addr;
- p->ip4h = &ipv4h;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, sizeof(payload)); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(20);
- p->tcph->th_ack = htonl(13);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, sizeof(payload)); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(15);
- p->tcph->th_ack = htonl(23);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(14);
- p->tcph->th_ack = htonl(23);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- addr.s_addr = inet_addr("192.168.1.1");
- p->tcph->th_seq = htonl(25);
- p->tcph->th_ack = htonl(13);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
- p->dst.address.address_un_data32[0] = addr.s_addr;
-
- StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(24);
- p->tcph->th_ack = htonl(13);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (stream_config.midstream != TRUE) {
- ret = 1;
- goto end;
- }
- if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
- goto end;
-
- if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 13 &&
- ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23) {
- printf("failed in next_seq match client.next_seq %"PRIu32""
- " server.next_seq %"PRIu32"\n",
- ((TcpSession *)(p->flow->protoctx))->client.next_seq,
- ((TcpSession *)(p->flow->protoctx))->server.next_seq);
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx))->client.os_policy !=
- OS_POLICY_LINUX && ((TcpSession *)
- (p->flow->protoctx))->server.os_policy != OS_POLICY_WINDOWS)
- {
- printf("failed in setting up OS policy, client.os_policy: %"PRIu8""
- " should be %"PRIu8" and server.os_policy: %"PRIu8""
- " should be %"PRIu8"\n", ((TcpSession *)
- (p->flow->protoctx))->client.os_policy, OS_POLICY_LINUX,
- ((TcpSession *)(p->flow->protoctx))->server.os_policy,
- OS_POLICY_WINDOWS);
- goto end;
- }
- StreamTcpSessionPktFree(p);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- ConfDeInit();
- ConfRestoreContextBackup();
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the setting up a OS policy. Te OS policy values are defined in
- * the config string "dummy_conf_string1". To check the setting of
- * Default os policy
- *
- * \retval On success it returns 1 and on failure 0
- */
-
-static int StreamTcpTest17 (void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- uint8_t payload[4];
- struct in_addr addr;
- IPV4Hdr ipv4h;
- char os_policy_name[10] = "windows";
- char *ip_addr;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- memset(p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- memset(&addr, 0, sizeof(addr));
- memset(&ipv4h, 0, sizeof(ipv4h));
- FLOW_INITIALIZE(&f);
- p->flow = &f;
- int ret = 0;
-
- StreamTcpInitConfig(TRUE);
-
- /* Load the config string in to parser */
- ConfCreateContextBackup();
- ConfInit();
- ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
-
- /* Get the IP address as string and add it to Host info tree for lookups */
- ip_addr = StreamTcpParseOSPolicy(os_policy_name);
- SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
- strlcpy(os_policy_name, "linux\0", sizeof(os_policy_name));
- ip_addr = StreamTcpParseOSPolicy(os_policy_name);
- SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- addr.s_addr = inet_addr("192.168.0.1");
- 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->dst.family = AF_INET;
- p->dst.address.address_un_data32[0] = addr.s_addr;
- p->ip4h = &ipv4h;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, sizeof(payload)); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(20);
- p->tcph->th_ack = htonl(13);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, sizeof(payload)); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(15);
- p->tcph->th_ack = htonl(23);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(14);
- p->tcph->th_ack = htonl(23);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x43, 3, sizeof(payload)); /*CCC*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- addr.s_addr = inet_addr("10.1.1.1");
- p->tcph->th_seq = htonl(25);
- p->tcph->th_ack = htonl(13);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
- p->dst.address.address_un_data32[0] = addr.s_addr;
-
- StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_seq = htonl(24);
- p->tcph->th_ack = htonl(13);
- p->tcph->th_flags = TH_ACK|TH_PUSH;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x44, 3, sizeof(payload)); /*DDD*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- if (stream_config.midstream != TRUE) {
- ret = 1;
- goto end;
- }
- if (((TcpSession *)(p->flow->protoctx))->state != TCP_ESTABLISHED)
- goto end;
-
- if (((TcpSession *)(p->flow->protoctx))->client.next_seq != 13 &&
- ((TcpSession *)(p->flow->protoctx))->server.next_seq != 23) {
- printf("failed in next_seq match client.next_seq %"PRIu32""
- " server.next_seq %"PRIu32"\n",
- ((TcpSession *)(p->flow->protoctx))->client.next_seq,
- ((TcpSession *)(p->flow->protoctx))->server.next_seq);
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx))->client.os_policy !=
- OS_POLICY_LINUX && ((TcpSession *)
- (p->flow->protoctx))->server.os_policy != OS_POLICY_DEFAULT)
- {
- printf("failed in setting up OS policy, client.os_policy: %"PRIu8""
- " should be %"PRIu8" and server.os_policy: %"PRIu8""
- " should be %"PRIu8"\n", ((TcpSession *)
- (p->flow->protoctx))->client.os_policy, OS_POLICY_LINUX,
- ((TcpSession *)(p->flow->protoctx))->server.os_policy,
- OS_POLICY_DEFAULT);
- goto end;
- }
- StreamTcpSessionPktFree(p);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- ConfDeInit();
- ConfRestoreContextBackup();
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/** \test Test the various OS policies based on different IP addresses from
- confuguration defined in 'dummy_conf_string1' */
-static int StreamTcpTest18 (void)
-{
-
- struct in_addr addr;
- char os_policy_name[10] = "windows";
- char *ip_addr;
- TcpStream stream;
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- IPV4Hdr ipv4h;
- int ret = 0;
-
- memset(&addr, 0, sizeof(addr));
- memset(&stream, 0, sizeof(stream));
- memset(p, 0, SIZE_OF_PACKET);
- memset(&ipv4h, 0, sizeof(ipv4h));
-
- StreamTcpInitConfig(TRUE);
- SCHInfoCleanResources();
-
- /* Load the config string in to parser */
- ConfCreateContextBackup();
- ConfInit();
- ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
-
- /* Get the IP address as string and add it to Host info tree for lookups */
- ip_addr = StreamTcpParseOSPolicy(os_policy_name);
- SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
-
- p->dst.family = AF_INET;
- p->ip4h = &ipv4h;
- addr.s_addr = inet_addr("192.168.1.1");
- p->dst.address.address_un_data32[0] = addr.s_addr;
- StreamTcpSetOSPolicy(&stream, p);
-
- if (stream.os_policy != OS_POLICY_WINDOWS)
- goto end;
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- ConfDeInit();
- ConfRestoreContextBackup();
- SCFree(p);
- return ret;
-}
-/** \test Test the various OS policies based on different IP addresses from
- confuguration defined in 'dummy_conf_string1' */
-static int StreamTcpTest19 (void)
-{
-
- struct in_addr addr;
- char os_policy_name[10] = "windows";
- char *ip_addr;
- TcpStream stream;
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- IPV4Hdr ipv4h;
- int ret = 0;
-
- memset(&addr, 0, sizeof(addr));
- memset(&stream, 0, sizeof(stream));
- memset(p, 0, SIZE_OF_PACKET);
- memset(&ipv4h, 0, sizeof(ipv4h));
-
- StreamTcpInitConfig(TRUE);
- SCHInfoCleanResources();
-
- /* Load the config string in to parser */
- ConfCreateContextBackup();
- ConfInit();
- ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
-
- /* Get the IP address as string and add it to Host info tree for lookups */
- ip_addr = StreamTcpParseOSPolicy(os_policy_name);
- SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
-
- p->dst.family = AF_INET;
- p->ip4h = &ipv4h;
- addr.s_addr = inet_addr("192.168.0.30");
- p->dst.address.address_un_data32[0] = addr.s_addr;
- StreamTcpSetOSPolicy(&stream, p);
-
- if (stream.os_policy != OS_POLICY_WINDOWS) {
- printf("expected os_policy: %"PRIu8" but received %"PRIu8": ",
- OS_POLICY_WINDOWS, stream.os_policy);
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- ConfDeInit();
- ConfRestoreContextBackup();
- SCFree(p);
- return ret;
-}
-/** \test Test the various OS policies based on different IP addresses from
- confuguration defined in 'dummy_conf_string1' */
-static int StreamTcpTest20 (void)
-{
-
- struct in_addr addr;
- char os_policy_name[10] = "linux";
- char *ip_addr;
- TcpStream stream;
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- IPV4Hdr ipv4h;
- int ret = 0;
-
- memset(&addr, 0, sizeof(addr));
- memset(&stream, 0, sizeof(stream));
- memset(p, 0, SIZE_OF_PACKET);
- memset(&ipv4h, 0, sizeof(ipv4h));
-
- StreamTcpInitConfig(TRUE);
- SCHInfoCleanResources();
-
- /* Load the config string in to parser */
- ConfCreateContextBackup();
- ConfInit();
- ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
-
- /* Get the IP address as string and add it to Host info tree for lookups */
- ip_addr = StreamTcpParseOSPolicy(os_policy_name);
- SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
-
- p->dst.family = AF_INET;
- p->ip4h = &ipv4h;
- addr.s_addr = inet_addr("192.168.0.1");
- p->dst.address.address_un_data32[0] = addr.s_addr;
- StreamTcpSetOSPolicy(&stream, p);
-
- if (stream.os_policy != OS_POLICY_LINUX) {
- printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n",
- OS_POLICY_LINUX, stream.os_policy);
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- ConfDeInit();
- ConfRestoreContextBackup();
- SCFree(p);
- return ret;
-}
-/** \test Test the various OS policies based on different IP addresses from
- confuguration defined in 'dummy_conf_string1' */
-static int StreamTcpTest21 (void)
-{
-
- struct in_addr addr;
- char os_policy_name[10] = "linux";
- char *ip_addr;
- TcpStream stream;
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- IPV4Hdr ipv4h;
- int ret = 0;
-
- memset(&addr, 0, sizeof(addr));
- memset(&stream, 0, sizeof(stream));
- memset(p, 0, SIZE_OF_PACKET);
- memset(&ipv4h, 0, sizeof(ipv4h));
-
- StreamTcpInitConfig(TRUE);
- SCHInfoCleanResources();
-
- /* Load the config string in to parser */
- ConfCreateContextBackup();
- ConfInit();
- ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
-
- /* Get the IP address as string and add it to Host info tree for lookups */
- ip_addr = StreamTcpParseOSPolicy(os_policy_name);
- SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
-
- p->dst.family = AF_INET;
- p->ip4h = &ipv4h;
- addr.s_addr = inet_addr("192.168.1.30");
- p->dst.address.address_un_data32[0] = addr.s_addr;
- StreamTcpSetOSPolicy(&stream, p);
-
- if (stream.os_policy != OS_POLICY_LINUX) {
- printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n",
- OS_POLICY_LINUX, stream.os_policy);
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- ConfDeInit();
- ConfRestoreContextBackup();
- SCFree(p);
- return ret;
-}
-/** \test Test the various OS policies based on different IP addresses from
- confuguration defined in 'dummy_conf_string1' */
-static int StreamTcpTest22 (void)
-{
-
- struct in_addr addr;
- char os_policy_name[10] = "windows";
- char *ip_addr;
- TcpStream stream;
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- IPV4Hdr ipv4h;
- int ret = 0;
-
- memset(&addr, 0, sizeof(addr));
- memset(&stream, 0, sizeof(stream));
- memset(p, 0, SIZE_OF_PACKET);
- memset(&ipv4h, 0, sizeof(ipv4h));
-
- StreamTcpInitConfig(TRUE);
- SCHInfoCleanResources();
-
- /* Load the config string in to parser */
- ConfCreateContextBackup();
- ConfInit();
- ConfYamlLoadString(dummy_conf_string1, strlen(dummy_conf_string1));
-
- /* Get the IP address as string and add it to Host info tree for lookups */
- ip_addr = StreamTcpParseOSPolicy(os_policy_name);
- SCHInfoAddHostOSInfo(os_policy_name, ip_addr, -1);
-
- p->dst.family = AF_INET;
- p->ip4h = &ipv4h;
- addr.s_addr = inet_addr("123.231.2.1");
- p->dst.address.address_un_data32[0] = addr.s_addr;
- StreamTcpSetOSPolicy(&stream, p);
-
- if (stream.os_policy != OS_POLICY_DEFAULT) {
- printf("expected os_policy: %"PRIu8" but received %"PRIu8"\n",
- OS_POLICY_DEFAULT, stream.os_policy);
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- ConfDeInit();
- ConfRestoreContextBackup();
- SCFree(p);
- return ret;
-}
-
-/** \test Test the stream mem leaks conditions. */
-static int StreamTcpTest23(void)
-{
- TcpSession ssn;
- Flow f;
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- uint8_t packet[1460] = "";
- ThreadVars tv;
- int result = 1;
- PacketQueue pq;
-
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
-
- memset(&pq,0,sizeof(PacketQueue));
- memset(&ssn, 0, sizeof (TcpSession));
- memset(p, 0, SIZE_OF_PACKET);
- memset(&f, 0, sizeof (Flow));
- memset(&tcph, 0, sizeof (TCPHdr));
- memset(&tv, 0, sizeof (ThreadVars));
-
- StreamTcpInitConfig(TRUE);
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- FLOW_INITIALIZE(&f);
- ssn.client.os_policy = OS_POLICY_BSD;
- f.protoctx = &ssn;
- 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;
- ssn.client.ra_app_base_seq = ssn.client.ra_raw_base_seq = ssn.client.last_ack = 3184324453UL;
-
- p->tcph->th_seq = htonl(3184324453UL);
- p->tcph->th_ack = htonl(3373419609UL);
- p->payload_len = 2;
-
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
- printf("failed in segment reassmebling: ");
- result &= 0;
- goto end;
- }
-
- p->tcph->th_seq = htonl(3184324455UL);
- p->tcph->th_ack = htonl(3373419621UL);
- p->payload_len = 2;
-
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
- printf("failed in segment reassmebling: ");
- result &= 0;
- goto end;
- }
-
- p->tcph->th_seq = htonl(3184324453UL);
- p->tcph->th_ack = htonl(3373419621UL);
- p->payload_len = 6;
-
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
- printf("failed in segment reassmebling: ");
- result &= 0;
-// goto end;
- }
-
- if(ssn.client.seg_list_tail != NULL && ssn.client.seg_list_tail->payload_len != 4) {
- printf("failed in segment reassmebling: ");
- result &= 0;
- }
-
-end:
- StreamTcpReturnStreamSegments(&ssn.client);
- StreamTcpFreeConfig(TRUE);
- if (SC_ATOMIC_GET(st_memuse) == 0) {
- result &= 1;
- } else {
- printf("smemuse.stream_memuse %"PRIu64"\n", SC_ATOMIC_GET(st_memuse));
- }
- SCFree(p);
- FLOW_DESTROY(&f);
- return result;
-}
-
-/** \test Test the stream mem leaks conditions. */
-static int StreamTcpTest24(void)
-{
- TcpSession ssn;
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- uint8_t packet[1460] = "";
- ThreadVars tv;
- int result = 1;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- StreamTcpInitConfig(TRUE);
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- memset(&ssn, 0, sizeof (TcpSession));
- memset(p, 0, SIZE_OF_PACKET);
- memset(&f, 0, sizeof (Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&tcph, 0, sizeof (TCPHdr));
- FLOW_INITIALIZE(&f);
- ssn.client.os_policy = OS_POLICY_BSD;
- f.protoctx = &ssn;
- 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;
- ssn.client.ra_app_base_seq = ssn.client.ra_raw_base_seq = ssn.client.last_ack = 3184324453UL;
-
- p->tcph->th_seq = htonl(3184324455UL);
- p->tcph->th_ack = htonl(3373419621UL);
- p->payload_len = 4;
-
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- goto end;
- }
-
- p->tcph->th_seq = htonl(3184324459UL);
- p->tcph->th_ack = htonl(3373419633UL);
- p->payload_len = 2;
-
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- goto end;
- }
-
- p->tcph->th_seq = htonl(3184324459UL);
- p->tcph->th_ack = htonl(3373419657UL);
- p->payload_len = 4;
-
- if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- goto end;
- }
-
- if(ssn.client.seg_list_tail != NULL && ssn.client.seg_list_tail->payload_len != 2) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- }
-
-end:
- StreamTcpReturnStreamSegments(&ssn.client);
- StreamTcpFreeConfig(TRUE);
- if (SC_ATOMIC_GET(st_memuse) == 0) {
- result &= 1;
- } else {
- printf("smemuse.stream_memuse %"PRIu64"\n", SC_ATOMIC_GET(st_memuse));
- }
- SCFree(p);
- FLOW_DESTROY(&f);
- return result;
-}
-
-/**
- * \test Test the initialization of tcp streams with congestion flags
- *
- * \retval On success it returns 1 and on failure 0.
- */
-static int StreamTcpTest25(void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- uint8_t payload[4];
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- int ret = 0;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- memset(p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- FLOW_INITIALIZE(&f);
- stt.ra_ctx = ra_ctx;
- p->flow = &f;
- tcph.th_win = htons(5480);
- tcph.th_flags = TH_SYN | TH_CWR;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- /* prevent L7 from kicking in */
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOSERVER, 4096);
- StreamMsgQueueSetMinChunkLen(FLOW_PKT_TOCLIENT, 4096);
-
- StreamTcpInitConfig(TRUE);
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(1);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(2);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->flowflags = FLOW_PKT_TOCLIENT;
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(6);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->flowflags = FLOW_PKT_TOCLIENT;
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the initialization of tcp streams with congestion flags
- *
- * \retval On success it returns 1 and on failure 0.
- */
-static int StreamTcpTest26(void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- uint8_t payload[4];
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- int ret = 0;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- memset(p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- FLOW_INITIALIZE(&f);
- stt.ra_ctx = ra_ctx;
- p->flow = &f;
- tcph.th_win = htons(5480);
- tcph.th_flags = TH_SYN | TH_ECN;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpInitConfig(TRUE);
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(1);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(2);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->flowflags = FLOW_PKT_TOCLIENT;
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(6);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->flowflags = FLOW_PKT_TOCLIENT;
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the initialization of tcp streams with congestion flags
- *
- * \retval On success it returns 1 and on failure 0.
- */
-static int StreamTcpTest27(void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- uint8_t payload[4];
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- int ret = 0;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- memset(p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- FLOW_INITIALIZE(&f);
- stt.ra_ctx = ra_ctx;
- p->flow = &f;
- tcph.th_win = htons(5480);
- tcph.th_flags = TH_SYN | TH_CWR | TH_ECN;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpInitConfig(TRUE);
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(1);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(2);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->flowflags = FLOW_PKT_TOCLIENT;
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(6);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x42, 3, 4); /*BBB*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- p->flowflags = FLOW_PKT_TOCLIENT;
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL)
- goto end;
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/** \test Test the memcap incrementing/decrementing and memcap check */
-static int StreamTcpTest28(void)
-{
- uint8_t ret = 0;
- StreamTcpInitConfig(TRUE);
- uint32_t memuse = SC_ATOMIC_GET(st_memuse);
-
- StreamTcpIncrMemuse(500);
- if (SC_ATOMIC_GET(st_memuse) != (memuse+500)) {
- printf("failed in incrementing the memory");
- goto end;
- }
-
- StreamTcpDecrMemuse(500);
- if (SC_ATOMIC_GET(st_memuse) != memuse) {
- printf("failed in decrementing the memory");
- goto end;
- }
-
- if (StreamTcpCheckMemcap(500) != 1) {
- printf("failed in validating the memcap");
- goto end;
- }
-
- if (StreamTcpCheckMemcap((memuse + stream_config.memcap)) != 0) {
- printf("failed in validating the overflowed memcap");
- goto end;
- }
-
- StreamTcpFreeConfig(TRUE);
-
- if (SC_ATOMIC_GET(st_memuse) != 0) {
- printf("failed in clearing the memory");
- goto end;
- }
-
- ret = 1;
- return ret;
-end:
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-#if 0
-/**
- * \test Test the resetting of the sesison with bad checksum packet and later
- * send the malicious contents on the session. Engine should drop the
- * packet with the bad checksum.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-static int StreamTcpTest29(void)
-{
- Packet p;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- TcpSession ssn;
- IPV4Hdr ipv4h;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- struct in_addr addr;
- struct in_addr addr1;
- TCPCache tcpc;
- TCPVars tcpvars;
- TcpStream server;
- TcpStream client;
-
- memset (&p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- memset (&ipv4h, 0, sizeof(IPV4Hdr));
- memset (&addr, 0, sizeof(addr));
- memset (&addr1, 0, sizeof(addr1));
- memset (&tcpc, 0, sizeof(tcpc));
- memset (&tcpvars, 0, sizeof(tcpvars));
- memset(&ssn, 0, sizeof (TcpSession));
- memset(&server, 0, sizeof (TcpStream));
- memset(&client, 0, sizeof (TcpStream));
- uint8_t packet[1460] = "";
- int result = 1;
-
- FLOW_INITIALIZE(&f);
- StreamTcpInitConfig(TRUE);
-
- /* prevent L7 from kicking in */
-
- ssn.client.os_policy = OS_POLICY_BSD;
- p.src.family = AF_INET;
- p.dst.family = AF_INET;
- p.proto = IPPROTO_TCP;
- p.flow = &f;
- tcph.th_win = 5480;
- p.tcph = &tcph;
- p.payload = packet;
- p.ip4h = &ipv4h;
- p.tcpc = tcpc;
- p.tcpc.level4_comp_csum = -1;
- tcpvars.hlen = 20;
- p.tcpvars = tcpvars;
- ssn.state = TCP_ESTABLISHED;
- addr.s_addr = inet_addr("10.1.3.53");
- p.dst.address.address_un_data32[0] = addr.s_addr;
- addr1.s_addr = inet_addr("10.1.3.7");
- p.src.address.address_un_data32[0] = addr1.s_addr;
- f.protoctx = &ssn;
- stt.ra_ctx = ra_ctx;
- ssn.server = server;
- ssn.client = client;
- ssn.client.isn = 10;
- ssn.client.window = 5184;
- ssn.client.last_ack = 10;
- ssn.client.ra_base_seq = 10;
- ssn.client.next_win = 5184;
- ssn.server.isn = 119197101;
- ssn.server.window = 5184;
- ssn.server.next_win = 5184;
- ssn.server.last_ack = 119197101;
- ssn.server.ra_base_seq = 119197101;
-
- tcph.th_flags = TH_PUSH | TH_ACK;
- p.flowflags = FLOW_PKT_TOSERVER;
- p.tcph->th_seq = htonl(11);
- p.tcph->th_ack = htonl(119197102);
- p.payload_len = 4;
- p.ip4h->ip_src = addr1;
- p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
- (uint16_t *)p.tcph,
- (p.payload_len +
- p.tcpvars.hlen) );
-
- if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- goto end;
- }
-
- tcph.th_flags = TH_ACK;
- p.flowflags = FLOW_PKT_TOCLIENT;
- p.tcph->th_seq = htonl(119197102);
- p.tcph->th_ack = htonl(15);
- p.payload_len = 0;
- p.ip4h->ip_src = addr;
- p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
- (uint16_t *)p.tcph,
- (p.payload_len +
- p.tcpvars.hlen) );
-
- if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- goto end;
- }
-
- tcph.th_flags = TH_RST | TH_ACK;
- p.flowflags = FLOW_PKT_TOSERVER;
- p.tcph->th_seq = htonl(15);
- p.tcph->th_ack = htonl(119197102);
- p.payload_len = 0;
- p.ip4h->ip_src = addr1;
- p.tcph->th_sum = 12345;
-
- if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- goto end;
- }
-
- if (ssn.state != TCP_ESTABLISHED) {
- printf("the ssn.state should be TCP_ESTABLISHED(%"PRIu8"), not %"PRIu8""
- "\n", TCP_ESTABLISHED, ssn.state);
- result &= 0;
- goto end;
- }
-
-end:
- StreamTcpReturnStreamSegments(&ssn.client);
- StreamTcpFreeConfig(TRUE);
- return result;
-}
-
-/**
- * \test Test the overlapping of the packet with bad checksum packet and later
- * send the malicious contents on the session. Engine should drop the
- * packet with the bad checksum.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-static int StreamTcpTest30(void)
-{
- Packet p;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- TcpSession ssn;
- IPV4Hdr ipv4h;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- struct in_addr addr;
- struct in_addr addr1;
- TCPCache tcpc;
- TCPVars tcpvars;
- TcpStream server;
- TcpStream client;
-
- memset (&p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- memset (&ipv4h, 0, sizeof(IPV4Hdr));
- memset (&addr, 0, sizeof(addr));
- memset (&addr1, 0, sizeof(addr1));
- memset (&tcpc, 0, sizeof(tcpc));
- memset (&tcpvars, 0, sizeof(tcpvars));
- memset(&ssn, 0, sizeof (TcpSession));
- memset(&server, 0, sizeof (TcpStream));
- memset(&client, 0, sizeof (TcpStream));
- uint8_t payload[9] = "AAAAAAAAA";
- uint8_t payload1[9] = "GET /EVIL";
- uint8_t expected_content[9] = { 0x47, 0x45, 0x54, 0x20, 0x2f, 0x45, 0x56,
- 0x49, 0x4c };
- int result = 1;
-
- FLOW_INITIALIZE(&f);
- StreamTcpInitConfig(TRUE);
-
- /* prevent L7 from kicking in */
-
- ssn.client.os_policy = OS_POLICY_BSD;
- p.src.family = AF_INET;
- p.dst.family = AF_INET;
- p.proto = IPPROTO_TCP;
- p.flow = &f;
- tcph.th_win = 5480;
- p.tcph = &tcph;
- p.payload = payload;
- p.ip4h = &ipv4h;
- p.tcpc = tcpc;
- p.tcpc.level4_comp_csum = -1;
- p.tcpvars = tcpvars;
- ssn.state = TCP_ESTABLISHED;
- addr.s_addr = inet_addr("10.1.3.53");
- p.dst.address.address_un_data32[0] = addr.s_addr;
- addr1.s_addr = inet_addr("10.1.3.7");
- p.src.address.address_un_data32[0] = addr1.s_addr;
- f.protoctx = &ssn;
- stt.ra_ctx = ra_ctx;
- ssn.server = server;
- ssn.client = client;
- ssn.client.isn = 10;
- ssn.client.window = 5184;
- ssn.client.last_ack = 10;
- ssn.client.ra_base_seq = 10;
- ssn.client.next_win = 5184;
- ssn.server.isn = 1351079940;
- ssn.server.window = 5184;
- ssn.server.next_win = 1351088132;
- ssn.server.last_ack = 1351079940;
- ssn.server.ra_base_seq = 1351079940;
-
- tcph.th_flags = TH_PUSH | TH_ACK;
- p.flowflags = FLOW_PKT_TOSERVER;
- p.tcph->th_seq = htonl(11);
- p.tcph->th_ack = htonl(1351079940);
- p.payload_len = 9;
- p.ip4h->ip_src = addr1;
- p.tcph->th_sum = 12345;
-
- if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- goto end;
- }
-
- tcph.th_flags = TH_PUSH | TH_ACK;
- p.flowflags = FLOW_PKT_TOSERVER;
- p.tcph->th_seq = htonl(11);
- p.tcph->th_ack = htonl(1351079940);
- p.payload = payload1;
- p.payload_len = 9;
- p.ip4h->ip_src = addr1;
- p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
- (uint16_t *)p.tcph,
- (p.payload_len +
- p.tcpvars.hlen) );
-
- if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- goto end;
- }
-
- tcph.th_flags = TH_ACK;
- p.flowflags = FLOW_PKT_TOCLIENT;
- p.tcph->th_seq = htonl(1351079940);
- p.tcph->th_ack = htonl(20);
- p.payload_len = 0;
- p.ip4h->ip_src = addr;
- p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
- (uint16_t *)p.tcph,
- (p.payload_len +
- p.tcpvars.hlen) );
-
- if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- goto end;
- }
-
- if (StreamTcpCheckStreamContents(expected_content, 9, &ssn.client) != 1) {
- printf("the contents are not as expected(GET /EVIL), contents are: ");
- PrintRawDataFp(stdout, ssn.client.seg_list->payload, 9);
- result &= 0;
- goto end;
- }
-
-end:
- StreamTcpReturnStreamSegments(&ssn.client);
- StreamTcpFreeConfig(TRUE);
- return result;
-}
-
-/**
- * \test Test the multiple SYN packet handling with bad checksum and timestamp
- * value. Engine should drop the bad checksum packet and establish
- * TCP session correctly.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-static int StreamTcpTest31(void)
-{
- Packet p;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- TcpSession ssn;
- IPV4Hdr ipv4h;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- struct in_addr addr;
- struct in_addr addr1;
- TCPCache tcpc;
- TCPVars tcpvars;
- TcpStream server;
- TcpStream client;
- TCPOpt tcpopt;
-
- memset (&p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- memset (&ipv4h, 0, sizeof(IPV4Hdr));
- memset (&addr, 0, sizeof(addr));
- memset (&addr1, 0, sizeof(addr1));
- memset (&tcpc, 0, sizeof(tcpc));
- memset (&tcpvars, 0, sizeof(tcpvars));
- memset(&ssn, 0, sizeof (TcpSession));
- memset(&server, 0, sizeof (TcpStream));
- memset(&client, 0, sizeof (TcpStream));
- memset(&tcpopt, 0, sizeof (TCPOpt));
- int result = 1;
-
- StreamTcpInitConfig(TRUE);
-
- FLOW_INITIALIZE(&f);
- /* prevent L7 from kicking in */
-
- ssn.client.os_policy = OS_POLICY_LINUX;
- p.src.family = AF_INET;
- p.dst.family = AF_INET;
- p.proto = IPPROTO_TCP;
- p.flow = &f;
- tcph.th_win = 5480;
- p.tcph = &tcph;
- p.ip4h = &ipv4h;
- p.tcpc = tcpc;
- p.tcpc.level4_comp_csum = -1;
- p.tcpvars = tcpvars;
- p.tcpvars.ts = &tcpopt;
- addr.s_addr = inet_addr("10.1.3.53");
- p.dst.address.address_un_data32[0] = addr.s_addr;
- addr1.s_addr = inet_addr("10.1.3.7");
- p.src.address.address_un_data32[0] = addr1.s_addr;
- f.protoctx = &ssn;
- stt.ra_ctx = ra_ctx;
- ssn.server = server;
- ssn.client = client;
- ssn.client.isn = 10;
- ssn.client.window = 5184;
- ssn.client.last_ack = 10;
- ssn.client.ra_base_seq = 10;
- ssn.client.next_win = 5184;
- ssn.server.isn = 1351079940;
- ssn.server.window = 5184;
- ssn.server.next_win = 1351088132;
- ssn.server.last_ack = 1351079940;
- ssn.server.ra_base_seq = 1351079940;
-
- tcph.th_flags = TH_SYN;
- p.flowflags = FLOW_PKT_TOSERVER;
- p.tcph->th_seq = htonl(10);
- p.payload_len = 0;
- p.ip4h->ip_src = addr1;
- p.tcpc.ts1 = 100;
- p.tcph->th_sum = 12345;
-
- if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- goto end;
- }
-
- tcph.th_flags = TH_SYN;
- p.flowflags = FLOW_PKT_TOSERVER;
- p.tcph->th_seq = htonl(10);
- p.payload_len = 0;
- p.ip4h->ip_src = addr1;
- p.tcpc.ts1 = 10;
- p.tcpc.level4_comp_csum = -1;
- p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
- (uint16_t *)p.tcph,
- (p.payload_len +
- p.tcpvars.hlen) );
-
- if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- goto end;
- }
-
- ssn.flags |= STREAMTCP_FLAG_TIMESTAMP;
- tcph.th_flags = TH_SYN | TH_ACK;
- p.flowflags = FLOW_PKT_TOCLIENT;
- p.tcph->th_seq = htonl(1351079940);
- p.tcph->th_ack = htonl(11);
- p.payload_len = 0;
- p.tcpc.ts1 = 10;
- p.ip4h->ip_src = addr;
- p.tcpc.level4_comp_csum = -1;
- p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
- (uint16_t *)p.tcph,
- (p.payload_len +
- p.tcpvars.hlen) );
-
- if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- goto end;
- }
-
- tcph.th_flags = TH_ACK;
- p.flowflags = FLOW_PKT_TOSERVER;
- p.tcph->th_seq = htonl(11);
- p.tcph->th_ack = htonl(1351079941);
- p.payload_len = 0;
- p.tcpc.ts1 = 10;
- p.ip4h->ip_src = addr1;
- p.tcpc.level4_comp_csum = -1;
- p.tcph->th_sum = TCPCalculateChecksum((uint16_t *)&(p.ip4h->ip_src),
- (uint16_t *)p.tcph,
- (p.payload_len +
- p.tcpvars.hlen) );
-
- if (StreamTcp(&tv, &p, (void *)&stt, NULL, NULL) != TM_ECODE_OK) {
- printf("failed in segment reassmebling\n");
- result &= 0;
- goto end;
- }
-
- if (ssn.state != TCP_ESTABLISHED) {
- printf("the should have been changed to TCP_ESTABLISHED!!\n ");
- result &= 0;
- goto end;
- }
-
-end:
- StreamTcpReturnStreamSegments(&ssn.client);
- StreamTcpFreeConfig(TRUE);
- return result;
-}
-
-/**
- * \test Test the initialization of tcp streams with ECN & CWR flags
- *
- * \retval On success it returns 1 and on failure 0.
- */
-static int StreamTcpTest32(void)
-{
- Packet p;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- uint8_t payload[4];
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- int ret = 0;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- memset (&p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- FLOW_INITIALIZE(&f);
- stt.ra_ctx = ra_ctx;
- p.flow = &f;
- tcph.th_win = htons(5480);
- tcph.th_flags = TH_SYN | TH_CWR | TH_ECN;
- p.tcph = &tcph;
- p.flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpInitConfig(TRUE);
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- p.tcph->th_ack = htonl(1);
- p.tcph->th_flags = TH_SYN | TH_ACK | TH_ECN;
- p.flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- p.tcph->th_ack = htonl(1);
- p.tcph->th_seq = htonl(1);
- p.tcph->th_flags = TH_ACK | TH_ECN | TH_CWR;
- p.flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- p.tcph->th_ack = htonl(1);
- p.tcph->th_seq = htonl(2);
- p.tcph->th_flags = TH_PUSH | TH_ACK | TH_ECN | TH_CWR;
- p.flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p.payload = payload;
- p.payload_len = 3;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- p.flowflags = FLOW_PKT_TOCLIENT;
- p.tcph->th_flags = TH_ACK;
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- if (((TcpSession *)p.flow->protoctx)->state != TCP_ESTABLISHED) {
- printf("the TCP state should be TCP_ESTABLISEHD\n");
- goto end;
- }
- StreamTcpSessionClear(p.flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-/**
- * \test Test the allocation of TCP session for a given packet when the same
- * ports have been used to start the new session after resetting the
- * previous session.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest33 (void)
-{
- Packet p;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- TcpReassemblyThreadCtx ra_ctx;
- StreamMsgQueue stream_q;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset(&stream_q, 0, sizeof(StreamMsgQueue));
- memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx));
- memset (&p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- FLOW_INITIALIZE(&f);
- p.flow = &f;
- tcph.th_win = htons(5480);
- tcph.th_flags = TH_SYN;
- p.tcph = &tcph;
- p.flowflags = FLOW_PKT_TOSERVER;
- int ret = 0;
- ra_ctx.stream_q = &stream_q;
- stt.ra_ctx = &ra_ctx;
-
- StreamTcpInitConfig(TRUE);
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- p.tcph->th_ack = htonl(1);
- p.tcph->th_flags = TH_SYN | TH_ACK;
- p.flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- p.tcph->th_ack = htonl(1);
- p.tcph->th_seq = htonl(1);
- p.tcph->th_flags = TH_ACK;
- p.flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- p.tcph->th_ack = htonl(1);
- p.tcph->th_seq = htonl(1);
- p.tcph->th_flags = TH_RST | TH_ACK;
- p.flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- if (((TcpSession *)(p.flow->protoctx))->state != TCP_CLOSED) {
- printf("Tcp session should have been closed\n");
- goto end;
- }
-
- p.tcph->th_seq = htonl(1);
- p.tcph->th_flags = TH_SYN;
- p.flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- p.tcph->th_seq = htonl(1);
- p.tcph->th_ack = htonl(2);
- p.tcph->th_flags = TH_SYN | TH_ACK;
- p.flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- p.tcph->th_ack = htonl(2);
- p.tcph->th_seq = htonl(2);
- p.tcph->th_flags = TH_ACK;
- p.flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- if (((TcpSession *)(p.flow->protoctx))->state != TCP_ESTABLISHED) {
- printf("Tcp session should have been ESTABLISHED\n");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpSessionClear(p.flow->protoctx);
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-/**
- * \test Test the allocation of TCP session for a given packet when the SYN
- * packet is sent with the PUSH flag set.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest34 (void)
-{
- Packet p;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- TcpReassemblyThreadCtx ra_ctx;
- StreamMsgQueue stream_q;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset(&stream_q, 0, sizeof(StreamMsgQueue));
- memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx));
- memset (&p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- FLOW_INITIALIZE(&f);
- p.flow = &f;
- tcph.th_win = htons(5480);
- tcph.th_flags = TH_SYN|TH_PUSH;
- p.tcph = &tcph;
- p.flowflags = FLOW_PKT_TOSERVER;
- int ret = 0;
- ra_ctx.stream_q = &stream_q;
- stt.ra_ctx = &ra_ctx;
-
- StreamTcpInitConfig(TRUE);
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- p.tcph->th_ack = htonl(1);
- p.tcph->th_flags = TH_SYN | TH_ACK;
- p.flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- p.tcph->th_ack = htonl(1);
- p.tcph->th_seq = htonl(1);
- p.tcph->th_flags = TH_ACK;
- p.flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- if (((TcpSession *)(p.flow->protoctx))->state != TCP_ESTABLISHED) {
- printf("Tcp session should have been establisehd\n");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpSessionClear(p.flow->protoctx);
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-/**
- * \test Test the allocation of TCP session for a given packet when the SYN
- * packet is sent with the URG flag set.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest35 (void)
-{
- Packet p;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- TcpReassemblyThreadCtx ra_ctx;
- StreamMsgQueue stream_q;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
- memset(&stream_q, 0, sizeof(StreamMsgQueue));
- memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx));
- memset (&p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- FLOW_INITIALIZE(&f);
- p.flow = &f;
- tcph.th_win = htons(5480);
- tcph.th_flags = TH_SYN|TH_URG;
- p.tcph = &tcph;
- p.flowflags = FLOW_PKT_TOSERVER;
- int ret = 0;
- ra_ctx.stream_q = &stream_q;
- stt.ra_ctx = &ra_ctx;
-
- StreamTcpInitConfig(TRUE);
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- p.tcph->th_ack = htonl(1);
- p.tcph->th_flags = TH_SYN | TH_ACK;
- p.flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- p.tcph->th_ack = htonl(1);
- p.tcph->th_seq = htonl(1);
- p.tcph->th_flags = TH_ACK;
- p.flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1)
- goto end;
-
- if (((TcpSession *)(p.flow->protoctx))->state != TCP_ESTABLISHED) {
- printf("Tcp session should have been establisehd\n");
- goto end;
- }
-
- ret = 1;
-end:
- StreamTcpSessionClear(p.flow->protoctx);
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-
-/**
- * \test Test the processing of PSH and URG flag in tcp session.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-static int StreamTcpTest36(void)
-{
- Packet p;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- uint8_t payload[4];
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- int ret = 0;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- memset (&p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- FLOW_INITIALIZE(&f);
- stt.ra_ctx = ra_ctx;
- p.flow = &f;
- tcph.th_win = htons(5480);
- tcph.th_flags = TH_SYN;
- p.tcph = &tcph;
- p.flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpInitConfig(TRUE);
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- p.tcph->th_ack = htonl(1);
- p.tcph->th_flags = TH_SYN | TH_ACK;
- p.flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- p.tcph->th_ack = htonl(1);
- p.tcph->th_seq = htonl(1);
- p.tcph->th_flags = TH_ACK;
- p.flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- if (((TcpSession *)p.flow->protoctx)->state != TCP_ESTABLISHED) {
- printf("the TCP state should be TCP_ESTABLISEHD\n");
- goto end;
- }
-
- p.tcph->th_ack = htonl(2);
- p.tcph->th_seq = htonl(1);
- p.tcph->th_flags = TH_PUSH | TH_ACK | TH_URG;
- p.flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p.payload = payload;
- p.payload_len = 3;
-
- if (StreamTcpPacket(&tv, &p, &stt, &pq) == -1 || (TcpSession *)p.flow->protoctx == NULL) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- if (((TcpSession *)p.flow->protoctx)->client.next_seq != 4) {
- printf("the ssn->client.next_seq should be 4, but it is %"PRIu32"\n",
- ((TcpSession *)p.flow->protoctx)->client.next_seq);
- goto end;
- }
-
- StreamTcpSessionClear(p.flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- return ret;
-}
-#endif
-
-/**
- * \test Test the processing of out of order FIN packets in tcp session.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-static int StreamTcpTest37(void)
-{
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- uint8_t payload[4];
- TCPHdr tcph;
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- int ret = 0;
- PacketQueue pq;
- memset(&pq,0,sizeof(PacketQueue));
-
- memset(p, 0, SIZE_OF_PACKET);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- FLOW_INITIALIZE(&f);
-
- stt.ra_ctx = ra_ctx;
- p->flow = &f;
- tcph.th_win = htons(5480);
- tcph.th_flags = TH_SYN;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpInitConfig(TRUE);
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(1);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- if (((TcpSession *)p->flow->protoctx)->state != TCP_ESTABLISHED) {
- printf("the TCP state should be TCP_ESTABLISEHD\n");
- goto end;
- }
-
- p->tcph->th_ack = htonl(2);
- p->tcph->th_seq = htonl(4);
- p->tcph->th_flags = TH_ACK|TH_FIN;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- if (((TcpSession *)p->flow->protoctx)->state != TCP_CLOSE_WAIT) {
- printf("the TCP state should be TCP_CLOSE_WAIT\n");
- goto end;
- }
-
- 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;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- p->tcph->th_ack = htonl(4);
- p->tcph->th_seq = htonl(2);
- p->tcph->th_flags = TH_ACK;
- p->payload_len = 0;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1 || (TcpSession *)p->flow->protoctx == NULL) {
- printf("failed in processing packet\n");
- goto end;
- }
-
- if (((TcpSession *)p->flow->protoctx)->client.ra_raw_base_seq != 3) {
- printf("the ssn->client.next_seq should be 3, but it is %"PRIu32"\n",
- ((TcpSession *)p->flow->protoctx)->client.ra_raw_base_seq);
- goto end;
- }
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/**
- * \test Test the validation of the ACK number before setting up the
- * stream.last_ack.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest38 (void)
-{
- int ret = 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- uint8_t payload[128];
- TCPHdr tcph;
- PacketQueue pq;
-
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- memset(&pq,0,sizeof(PacketQueue));
-
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- memset(p, 0, SIZE_OF_PACKET);
-
- FLOW_INITIALIZE(&f);
- p->flow = &f;
- tcph.th_win = htons(5480);
- tcph.th_flags = TH_SYN;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
- stt.ra_ctx = ra_ctx;
-
- StreamTcpInitConfig(TRUE);
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet in StreamTcpPacket\n");
- goto end;
- }
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet in StreamTcpPacket\n");
- goto end;
- }
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(1);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet in StreamTcpPacket\n");
- goto end;
- }
-
- p->tcph->th_ack = htonl(29847);
- p->tcph->th_seq = htonl(2);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet in StreamTcpPacket\n");
- goto end;
- }
-
- /* last_ack value should be 1 as the previous sent ACK value is out of
- window */
- if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 1) {
- printf("the server.last_ack should be 1, but it is %"PRIu32"\n",
- ((TcpSession *)(p->flow->protoctx))->server.last_ack);
- goto end;
- }
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(1);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x41, 127, 128); /*AAA*/
- p->payload = payload;
- p->payload_len = 127;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet in StreamTcpPacket\n");
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 128) {
- printf("the server.next_seq should be 128, but it is %"PRIu32"\n",
- ((TcpSession *)(p->flow->protoctx))->server.next_seq);
- goto end;
- }
-
- p->tcph->th_ack = htonl(256); // in window, but beyond next_seq
- p->tcph->th_seq = htonl(5);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet in StreamTcpPacket\n");
- goto end;
- }
-
- /* last_ack value should be 256, as the previous sent ACK value
- is inside window */
- if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 256) {
- printf("the server.last_ack should be 1, but it is %"PRIu32"\n",
- ((TcpSession *)(p->flow->protoctx))->server.last_ack);
- goto end;
- }
-
- p->tcph->th_ack = htonl(128);
- p->tcph->th_seq = htonl(8);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet in StreamTcpPacket\n");
- goto end;
- }
-
- /* last_ack value should be 256 as the previous sent ACK value is inside
- window */
- if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 256) {
- printf("the server.last_ack should be 256, but it is %"PRIu32"\n",
- ((TcpSession *)(p->flow->protoctx))->server.last_ack);
- goto end;
- }
-
- ret = 1;
-
-end:
- StreamTcpSessionClear(p->flow->protoctx);
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- if (stt.ra_ctx != NULL)
- StreamTcpReassembleFreeThreadCtx(stt.ra_ctx);
- return ret;
-}
-
-/**
- * \test Test the validation of the ACK number before setting up the
- * stream.last_ack and update the next_seq after loosing the .
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int StreamTcpTest39 (void)
-{
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- uint8_t payload[4];
- TCPHdr tcph;
- PacketQueue pq;
-
- TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
- memset(&pq,0,sizeof(PacketQueue));
-
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- memset(p, 0, SIZE_OF_PACKET);
-
- FLOW_INITIALIZE(&f);
- p->flow = &f;
- tcph.th_win = htons(5480);
- tcph.th_flags = TH_SYN;
- p->tcph = &tcph;
- p->flowflags = FLOW_PKT_TOSERVER;
- int ret = 0;
- stt.ra_ctx = ra_ctx;
-
- StreamTcpInitConfig(TRUE);
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet in StreamTcpPacket\n");
- goto end;
- }
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet in StreamTcpPacket\n");
- goto end;
- }
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(1);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet in StreamTcpPacket\n");
- goto end;
- }
-
- p->tcph->th_ack = htonl(1);
- p->tcph->th_seq = htonl(1);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet in StreamTcpPacket\n");
- goto end;
- }
-
- if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 4) {
- printf("the server.next_seq should be 4, but it is %"PRIu32"\n",
- ((TcpSession *)(p->flow->protoctx))->server.next_seq);
- goto end;
- }
-
- p->tcph->th_ack = htonl(4);
- p->tcph->th_seq = htonl(2);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet in StreamTcpPacket\n");
- goto end;
- }
-
- /* last_ack value should be 4 as the previous sent ACK value is inside
- window */
- if (((TcpSession *)(p->flow->protoctx))->server.last_ack != 4) {
- printf("the server.last_ack should be 4, but it is %"PRIu32"\n",
- ((TcpSession *)(p->flow->protoctx))->server.last_ack);
- goto end;
- }
-
- p->tcph->th_seq = htonl(4);
- p->tcph->th_ack = htonl(5);
- p->tcph->th_flags = TH_PUSH | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- StreamTcpCreateTestPacket(payload, 0x41, 3, 4); /*AAA*/
- p->payload = payload;
- p->payload_len = 3;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1) {
- printf("failed in processing packet in StreamTcpPacket\n");
- goto end;
- }
-
- /* next_seq value should be 2987 as the previous sent ACK value is inside
- window */
- if (((TcpSession *)(p->flow->protoctx))->server.next_seq != 7) {
- printf("the server.next_seq should be 7, but it is %"PRIu32"\n",
- ((TcpSession *)(p->flow->protoctx))->server.next_seq);
- goto end;
- }
-
- ret = 1;
-
-end:
- StreamTcpSessionClear(p->flow->protoctx);
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- if (stt.ra_ctx != NULL)
- StreamTcpReassembleFreeThreadCtx(stt.ra_ctx);
- return ret;
-}
-
-static int StreamTcpTest40(void)
-{
- uint8_t raw_vlan[] = {
- 0x00, 0x20, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34,
- 0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9,
- 0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15,
- 0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55,
- 0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50,
- 0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a,
- 0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3
- };
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- ThreadVars tv;
- DecodeThreadVars dtv;
-
- memset(&tv, 0, sizeof(ThreadVars));
- memset(p, 0, SIZE_OF_PACKET);
- PACKET_INITIALIZE(p);
-
- SET_PKT_LEN(p, sizeof(raw_vlan));
- memcpy(GET_PKT_DATA(p), raw_vlan, sizeof(raw_vlan));
- memset(&dtv, 0, sizeof(DecodeThreadVars));
-
- FlowInitConfig(FLOW_QUIET);
-
- DecodeVLAN(&tv, &dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), NULL);
-
- if(p->vlanh == NULL) {
- SCFree(p);
- return 0;
- }
-
- if(p->tcph == NULL) {
- SCFree(p);
- return 0;
- }
-
- Packet *np = StreamTcpPseudoSetup(p, GET_PKT_DATA(p), GET_PKT_LEN(p));
- if (np == NULL) {
- printf("the packet received from packet allocation is NULL: ");
- return 0;
- }
-
- StreamTcpPseudoPacketSetupHeader(np,p);
-
- if (((uint8_t *)p->tcph - (uint8_t *)p->ip4h) != ((uint8_t *)np->tcph - (uint8_t *)np->ip4h)) {
- return 0;
- }
-
- PACKET_RECYCLE(np);
- PACKET_RECYCLE(p);
- FlowShutdown();
-
- return 1;
-}
-
-static int StreamTcpTest41(void)
-{
- /* IPV6/TCP/no eth header */
- uint8_t raw_ip[] = {
- 0x60, 0x00, 0x00, 0x00, 0x00, 0x28, 0x06, 0x40,
- 0x20, 0x01, 0x06, 0x18, 0x04, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x51, 0x99, 0xcc, 0x70,
- 0x20, 0x01, 0x06, 0x18, 0x00, 0x01, 0x80, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
- 0x8c, 0x9b, 0x00, 0x50, 0x6a, 0xe7, 0x07, 0x36,
- 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x16, 0x30,
- 0x29, 0x9c, 0x00, 0x00, 0x02, 0x04, 0x05, 0x8c,
- 0x04, 0x02, 0x08, 0x0a, 0x00, 0xdd, 0x1a, 0x39,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02 };
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- if (unlikely(p == NULL))
- return 0;
- ThreadVars tv;
- DecodeThreadVars dtv;
-
- memset(&dtv, 0, sizeof(DecodeThreadVars));
- memset(&tv, 0, sizeof(ThreadVars));
- memset(p, 0, SIZE_OF_PACKET);
- PACKET_INITIALIZE(p);
-
- if (PacketCopyData(p, raw_ip, sizeof(raw_ip)) == -1) {
- PacketFree(p);
- return 1;
- }
-
- FlowInitConfig(FLOW_QUIET);
-
- DecodeRaw(&tv, &dtv, p, raw_ip, GET_PKT_LEN(p), NULL);
-
- if (p->ip6h == NULL) {
- printf("expected a valid ipv6 header but it was NULL: ");
- FlowShutdown();
- SCFree(p);
- return 1;
- }
-
- if(p->tcph == NULL) {
- SCFree(p);
- return 0;
- }
-
- Packet *np = StreamTcpPseudoSetup(p, GET_PKT_DATA(p), GET_PKT_LEN(p));
- if (np == NULL) {
- printf("the packet received from packet allocation is NULL: ");
- return 0;
- }
-
- StreamTcpPseudoPacketSetupHeader(np,p);
-
- if (((uint8_t *)p->tcph - (uint8_t *)p->ip6h) != ((uint8_t *)np->tcph - (uint8_t *)np->ip6h)) {
- return 0;
- }
-
- PACKET_RECYCLE(np);
- PACKET_RECYCLE(p);
- SCFree(p);
- FlowShutdown();
-
- return 1;
-}
-
-/** \test multiple different SYN/ACK, pick first */
-static int StreamTcpTest42 (void)
-{
- int ret = 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- PacketQueue pq;
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- TcpSession *ssn;
-
- if (unlikely(p == NULL))
- return 0;
- memset(p, 0, SIZE_OF_PACKET);
-
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- StreamTcpInitConfig(TRUE);
-
- FLOW_INITIALIZE(&f);
- p->tcph = &tcph;
- tcph.th_win = htons(5480);
- p->flow = &f;
-
- /* SYN pkt */
- tcph.th_flags = TH_SYN;
- tcph.th_seq = htonl(100);
- p->flowflags = FLOW_PKT_TOSERVER;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- /* SYN/ACK */
- p->tcph->th_seq = htonl(500);
- p->tcph->th_ack = htonl(101);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- /* SYN/ACK */
- p->tcph->th_seq = htonl(1000);
- p->tcph->th_ack = htonl(101);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- /* ACK */
- p->tcph->th_ack = htonl(501);
- p->tcph->th_seq = htonl(101);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- ssn = p->flow->protoctx;
-
- if (ssn->state != TCP_ESTABLISHED) {
- printf("state not TCP_ESTABLISHED: ");
- goto end;
- }
-
- if (ssn->server.isn != 500) {
- SCLogDebug("ssn->server.isn %"PRIu32" != %"PRIu32"",
- ssn->server.isn, 500);
- goto end;
- }
- if (ssn->client.isn != 100) {
- SCLogDebug("ssn->client.isn %"PRIu32" != %"PRIu32"",
- ssn->client.isn, 100);
- goto end;
- }
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/** \test multiple different SYN/ACK, pick second */
-static int StreamTcpTest43 (void)
-{
- int ret = 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- PacketQueue pq;
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- TcpSession *ssn;
-
- if (unlikely(p == NULL))
- return 0;
- memset(p, 0, SIZE_OF_PACKET);
-
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- StreamTcpInitConfig(TRUE);
-
- FLOW_INITIALIZE(&f);
- p->tcph = &tcph;
- tcph.th_win = htons(5480);
- p->flow = &f;
-
- /* SYN pkt */
- tcph.th_flags = TH_SYN;
- tcph.th_seq = htonl(100);
- p->flowflags = FLOW_PKT_TOSERVER;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- /* SYN/ACK */
- p->tcph->th_seq = htonl(500);
- p->tcph->th_ack = htonl(101);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- /* SYN/ACK */
- p->tcph->th_seq = htonl(1000);
- p->tcph->th_ack = htonl(101);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- /* ACK */
- p->tcph->th_ack = htonl(1001);
- p->tcph->th_seq = htonl(101);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- ssn = p->flow->protoctx;
-
- if (ssn->state != TCP_ESTABLISHED) {
- printf("state not TCP_ESTABLISHED: ");
- goto end;
- }
-
- if (ssn->server.isn != 1000) {
- SCLogDebug("ssn->server.isn %"PRIu32" != %"PRIu32"",
- ssn->server.isn, 1000);
- goto end;
- }
- if (ssn->client.isn != 100) {
- SCLogDebug("ssn->client.isn %"PRIu32" != %"PRIu32"",
- ssn->client.isn, 100);
- goto end;
- }
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/** \test multiple different SYN/ACK, pick neither */
-static int StreamTcpTest44 (void)
-{
- int ret = 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- PacketQueue pq;
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- TcpSession *ssn;
-
- if (unlikely(p == NULL))
- return 0;
- memset(p, 0, SIZE_OF_PACKET);
-
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- StreamTcpInitConfig(TRUE);
-
- FLOW_INITIALIZE(&f);
- p->tcph = &tcph;
- tcph.th_win = htons(5480);
- p->flow = &f;
-
- /* SYN pkt */
- tcph.th_flags = TH_SYN;
- tcph.th_seq = htonl(100);
- p->flowflags = FLOW_PKT_TOSERVER;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- /* SYN/ACK */
- p->tcph->th_seq = htonl(500);
- p->tcph->th_ack = htonl(101);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- /* SYN/ACK */
- p->tcph->th_seq = htonl(1000);
- p->tcph->th_ack = htonl(101);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- /* ACK */
- p->tcph->th_ack = htonl(3001);
- p->tcph->th_seq = htonl(101);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) != -1)
- goto end;
-
- ssn = p->flow->protoctx;
-
- if (ssn->state != TCP_SYN_RECV) {
- SCLogDebug("state not TCP_SYN_RECV");
- goto end;
- }
-
- if (ssn->client.isn != 100) {
- SCLogDebug("ssn->client.isn %"PRIu32" != %"PRIu32"",
- ssn->client.isn, 100);
- goto end;
- }
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- FLOW_DESTROY(&f);
- return ret;
-}
-
-/** \test multiple different SYN/ACK, over the limit */
-static int StreamTcpTest45 (void)
-{
- int ret = 0;
- Flow f;
- ThreadVars tv;
- StreamTcpThread stt;
- TCPHdr tcph;
- PacketQueue pq;
- Packet *p = SCMalloc(SIZE_OF_PACKET);
- TcpSession *ssn;
-
- if (unlikely(p == NULL))
- return 0;
- memset(p, 0, SIZE_OF_PACKET);
-
- memset(&pq,0,sizeof(PacketQueue));
- memset (&f, 0, sizeof(Flow));
- memset(&tv, 0, sizeof (ThreadVars));
- memset(&stt, 0, sizeof (StreamTcpThread));
- memset(&tcph, 0, sizeof (TCPHdr));
-
- StreamTcpInitConfig(TRUE);
- stream_config.max_synack_queued = 2;
-
- FLOW_INITIALIZE(&f);
- p->tcph = &tcph;
- tcph.th_win = htons(5480);
- p->flow = &f;
-
- /* SYN pkt */
- tcph.th_flags = TH_SYN;
- tcph.th_seq = htonl(100);
- p->flowflags = FLOW_PKT_TOSERVER;
-
- SCMutexLock(&f.m);
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- /* SYN/ACK */
- p->tcph->th_seq = htonl(500);
- p->tcph->th_ack = htonl(101);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- /* SYN/ACK */
- p->tcph->th_seq = htonl(1000);
- p->tcph->th_ack = htonl(101);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- /* SYN/ACK */
- p->tcph->th_seq = htonl(2000);
- p->tcph->th_ack = htonl(101);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- /* SYN/ACK */
- p->tcph->th_seq = htonl(3000);
- p->tcph->th_ack = htonl(101);
- p->tcph->th_flags = TH_SYN | TH_ACK;
- p->flowflags = FLOW_PKT_TOCLIENT;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) != -1)
- goto end;
-
- /* ACK */
- p->tcph->th_ack = htonl(1001);
- p->tcph->th_seq = htonl(101);
- p->tcph->th_flags = TH_ACK;
- p->flowflags = FLOW_PKT_TOSERVER;
-
- if (StreamTcpPacket(&tv, p, &stt, &pq) == -1)
- goto end;
-
- ssn = p->flow->protoctx;
-
- if (ssn->state != TCP_ESTABLISHED) {
- printf("state not TCP_ESTABLISHED: ");
- goto end;
- }
-
- if (ssn->server.isn != 1000) {
- SCLogDebug("ssn->server.isn %"PRIu32" != %"PRIu32"",
- ssn->server.isn, 1000);
- goto end;
- }
- if (ssn->client.isn != 100) {
- SCLogDebug("ssn->client.isn %"PRIu32" != %"PRIu32"",
- ssn->client.isn, 100);
- goto end;
- }
-
- StreamTcpSessionClear(p->flow->protoctx);
-
- ret = 1;
-end:
- StreamTcpFreeConfig(TRUE);
- SCMutexUnlock(&f.m);
- SCFree(p);
- return ret;
-}
-
-#endif /* UNITTESTS */
-
-void StreamTcpRegisterTests (void)
-{
-#ifdef UNITTESTS
- UtRegisterTest("StreamTcpTest01 -- TCP session allocation",
- StreamTcpTest01, 1);
- UtRegisterTest("StreamTcpTest02 -- TCP session deallocation",
- StreamTcpTest02, 1);
- UtRegisterTest("StreamTcpTest03 -- SYN missed MidStream session",
- StreamTcpTest03, 1);
- UtRegisterTest("StreamTcpTest04 -- SYN/ACK missed MidStream session",
- StreamTcpTest04, 1);
- UtRegisterTest("StreamTcpTest05 -- 3WHS missed MidStream session",
- StreamTcpTest05, 1);
- UtRegisterTest("StreamTcpTest06 -- FIN, RST message MidStream session",
- StreamTcpTest06, 1);
- UtRegisterTest("StreamTcpTest07 -- PAWS invalid timestamp",
- StreamTcpTest07, 1);
- UtRegisterTest("StreamTcpTest08 -- PAWS valid timestamp",
- StreamTcpTest08, 1);
- UtRegisterTest("StreamTcpTest09 -- No Client Reassembly",
- StreamTcpTest09, 1);
- UtRegisterTest("StreamTcpTest10 -- No missed packet Async stream",
- StreamTcpTest10, 1);
- UtRegisterTest("StreamTcpTest11 -- SYN missed Async stream",
- StreamTcpTest11, 1);
- UtRegisterTest("StreamTcpTest12 -- SYN/ACK missed Async stream",
- StreamTcpTest12, 1);
- UtRegisterTest("StreamTcpTest13 -- opposite stream packets for Async "
- "stream", StreamTcpTest13, 1);
- UtRegisterTest("StreamTcp4WHSTest01", StreamTcp4WHSTest01, 1);
- UtRegisterTest("StreamTcp4WHSTest02", StreamTcp4WHSTest02, 1);
- UtRegisterTest("StreamTcp4WHSTest03", StreamTcp4WHSTest03, 1);
- UtRegisterTest("StreamTcpTest14 -- setup OS policy", StreamTcpTest14, 1);
- UtRegisterTest("StreamTcpTest15 -- setup OS policy", StreamTcpTest15, 1);
- UtRegisterTest("StreamTcpTest16 -- setup OS policy", StreamTcpTest16, 1);
- UtRegisterTest("StreamTcpTest17 -- setup OS policy", StreamTcpTest17, 1);
- UtRegisterTest("StreamTcpTest18 -- setup OS policy", StreamTcpTest18, 1);
- UtRegisterTest("StreamTcpTest19 -- setup OS policy", StreamTcpTest19, 1);
- UtRegisterTest("StreamTcpTest20 -- setup OS policy", StreamTcpTest20, 1);
- UtRegisterTest("StreamTcpTest21 -- setup OS policy", StreamTcpTest21, 1);
- UtRegisterTest("StreamTcpTest22 -- setup OS policy", StreamTcpTest22, 1);
- UtRegisterTest("StreamTcpTest23 -- stream memory leaks", StreamTcpTest23, 1);
- UtRegisterTest("StreamTcpTest24 -- stream memory leaks", StreamTcpTest24, 1);
- UtRegisterTest("StreamTcpTest25 -- test ecn/cwr sessions",
- StreamTcpTest25, 1);
- UtRegisterTest("StreamTcpTest26 -- test ecn/cwr sessions",
- StreamTcpTest26, 1);
- UtRegisterTest("StreamTcpTest27 -- test ecn/cwr sessions",
- StreamTcpTest27, 1);
- UtRegisterTest("StreamTcpTest28 -- Memcap Test", StreamTcpTest28, 1);
-
-#if 0 /* VJ 2010/09/01 disabled since they blow up on Fedora and Fedora is
- * right about blowing up. The checksum functions are not used properly
- * in the tests. */
- UtRegisterTest("StreamTcpTest29 -- Badchecksum Reset Test", StreamTcpTest29, 1);
- UtRegisterTest("StreamTcpTest30 -- Badchecksum Overlap Test", StreamTcpTest30, 1);
- UtRegisterTest("StreamTcpTest31 -- MultipleSyns Test", StreamTcpTest31, 1);
- UtRegisterTest("StreamTcpTest32 -- Bogus CWR Test", StreamTcpTest32, 1);
- UtRegisterTest("StreamTcpTest33 -- RST-SYN Again Test", StreamTcpTest33, 1);
- UtRegisterTest("StreamTcpTest34 -- SYN-PUSH Test", StreamTcpTest34, 1);
- UtRegisterTest("StreamTcpTest35 -- SYN-URG Test", StreamTcpTest35, 1);
- UtRegisterTest("StreamTcpTest36 -- PUSH-URG Test", StreamTcpTest36, 1);
-#endif
- UtRegisterTest("StreamTcpTest37 -- Out of order FIN Test", StreamTcpTest37, 1);
-
- UtRegisterTest("StreamTcpTest38 -- validate ACK", StreamTcpTest38, 1);
- UtRegisterTest("StreamTcpTest39 -- update next_seq", StreamTcpTest39, 1);
-
- UtRegisterTest("StreamTcpTest40 -- pseudo setup", StreamTcpTest40, 1);
- UtRegisterTest("StreamTcpTest41 -- pseudo setup", StreamTcpTest41, 1);
-
- UtRegisterTest("StreamTcpTest42 -- SYN/ACK queue", StreamTcpTest42, 1);
- UtRegisterTest("StreamTcpTest43 -- SYN/ACK queue", StreamTcpTest43, 1);
- UtRegisterTest("StreamTcpTest44 -- SYN/ACK queue", StreamTcpTest44, 1);
- UtRegisterTest("StreamTcpTest45 -- SYN/ACK queue", StreamTcpTest45, 1);
-
- /* set up the reassembly tests as well */
- StreamTcpReassembleRegisterTests();
-
- StreamTcpSackRegisterTests ();
-#endif /* UNITTESTS */
-}
-