aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/flow.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src/flow.c')
-rw-r--r--framework/src/suricata/src/flow.c1147
1 files changed, 0 insertions, 1147 deletions
diff --git a/framework/src/suricata/src/flow.c b/framework/src/suricata/src/flow.c
deleted file mode 100644
index abd9e7e5..00000000
--- a/framework/src/suricata/src/flow.c
+++ /dev/null
@@ -1,1147 +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>
- *
- * Flow implementation.
- */
-
-#include "suricata-common.h"
-#include "suricata.h"
-#include "decode.h"
-#include "conf.h"
-#include "threadvars.h"
-#include "tm-threads.h"
-#include "runmodes.h"
-
-#include "util-random.h"
-#include "util-time.h"
-
-#include "flow.h"
-#include "flow-queue.h"
-#include "flow-hash.h"
-#include "flow-util.h"
-#include "flow-var.h"
-#include "flow-private.h"
-#include "flow-timeout.h"
-#include "flow-manager.h"
-#include "flow-storage.h"
-
-#include "stream-tcp-private.h"
-#include "stream-tcp-reassemble.h"
-#include "stream-tcp.h"
-
-#include "util-unittest.h"
-#include "util-unittest-helper.h"
-#include "util-byte.h"
-#include "util-misc.h"
-
-#include "util-debug.h"
-#include "util-privs.h"
-
-#include "detect.h"
-#include "detect-engine-state.h"
-#include "stream.h"
-
-#include "app-layer-parser.h"
-
-#define FLOW_DEFAULT_EMERGENCY_RECOVERY 30
-
-//#define FLOW_DEFAULT_HASHSIZE 262144
-#define FLOW_DEFAULT_HASHSIZE 65536
-//#define FLOW_DEFAULT_MEMCAP 128 * 1024 * 1024 /* 128 MB */
-#define FLOW_DEFAULT_MEMCAP (32 * 1024 * 1024) /* 32 MB */
-
-#define FLOW_DEFAULT_PREALLOC 10000
-
-/** atomic int that is used when freeing a flow from the hash. In this
- * case we walk the hash to find a flow to free. This var records where
- * we left off in the hash. Without this only the top rows of the hash
- * are freed. This isn't just about fairness. Under severe presure, the
- * hash rows on top would be all freed and the time to find a flow to
- * free increased with every run. */
-SC_ATOMIC_DECLARE(unsigned int, flow_prune_idx);
-
-/** atomic flags */
-SC_ATOMIC_DECLARE(unsigned int, flow_flags);
-
-void FlowRegisterTests(void);
-void FlowInitFlowProto();
-int FlowSetProtoTimeout(uint8_t , uint32_t ,uint32_t ,uint32_t);
-int FlowSetProtoEmergencyTimeout(uint8_t , uint32_t ,uint32_t ,uint32_t);
-int FlowSetProtoFreeFunc(uint8_t, void (*Free)(void *));
-
-/* Run mode selected at suricata.c */
-extern int run_mode;
-
-void FlowCleanupAppLayer(Flow *f)
-{
- if (f == NULL || f->proto == 0)
- return;
-
- AppLayerParserStateCleanup(f->proto, f->alproto, f->alstate, f->alparser);
- f->alstate = NULL;
- f->alparser = NULL;
- return;
-}
-
-/** \brief Make sure we have enough spare flows.
- *
- * Enforce the prealloc parameter, so keep at least prealloc flows in the
- * spare queue and free flows going over the limit.
- *
- * \retval 1 if the queue was properly updated (or if it already was in good shape)
- * \retval 0 otherwise.
- */
-int FlowUpdateSpareFlows(void)
-{
- SCEnter();
- uint32_t toalloc = 0, tofree = 0, len;
-
- FQLOCK_LOCK(&flow_spare_q);
- len = flow_spare_q.len;
- FQLOCK_UNLOCK(&flow_spare_q);
-
- if (len < flow_config.prealloc) {
- toalloc = flow_config.prealloc - len;
-
- uint32_t i;
- for (i = 0; i < toalloc; i++) {
- Flow *f = FlowAlloc();
- if (f == NULL)
- return 0;
-
- FlowEnqueue(&flow_spare_q,f);
- }
- } else if (len > flow_config.prealloc) {
- tofree = len - flow_config.prealloc;
-
- uint32_t i;
- for (i = 0; i < tofree; i++) {
- /* FlowDequeue locks the queue */
- Flow *f = FlowDequeue(&flow_spare_q);
- if (f == NULL)
- return 1;
-
- FlowFree(f);
- }
- }
-
- return 1;
-}
-
-/** \brief Set the IPOnly scanned flag for 'direction'. This function
- * handles the locking too.
- * \param f Flow to set the flag in
- * \param direction direction to set the flag in
- */
-void FlowSetIPOnlyFlag(Flow *f, char direction)
-{
- FLOWLOCK_WRLOCK(f);
- direction ? (f->flags |= FLOW_TOSERVER_IPONLY_SET) :
- (f->flags |= FLOW_TOCLIENT_IPONLY_SET);
- FLOWLOCK_UNLOCK(f);
- return;
-}
-
-/** \brief Set the IPOnly scanned flag for 'direction'.
- *
- * \param f Flow to set the flag in
- * \param direction direction to set the flag in
- */
-void FlowSetIPOnlyFlagNoLock(Flow *f, char direction)
-{
- direction ? (f->flags |= FLOW_TOSERVER_IPONLY_SET) :
- (f->flags |= FLOW_TOCLIENT_IPONLY_SET);
- return;
-}
-
-/**
- * \brief determine the direction of the packet compared to the flow
- * \retval 0 to_server
- * \retval 1 to_client
- */
-int FlowGetPacketDirection(const Flow *f, const Packet *p)
-{
- if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP || p->proto == IPPROTO_SCTP) {
- if (!(CMP_PORT(p->sp,p->dp))) {
- /* update flags and counters */
- if (CMP_PORT(f->sp,p->sp)) {
- return TOSERVER;
- } else {
- return TOCLIENT;
- }
- } else {
- if (CMP_ADDR(&f->src,&p->src)) {
- return TOSERVER;
- } else {
- return TOCLIENT;
- }
- }
- } else if (p->proto == IPPROTO_ICMP || p->proto == IPPROTO_ICMPV6) {
- if (CMP_ADDR(&f->src,&p->src)) {
- return TOSERVER;
- } else {
- return TOCLIENT;
- }
- }
-
- /* default to toserver */
- return TOSERVER;
-}
-
-/**
- * \brief Check to update "seen" flags
- *
- * \param p packet
- *
- * \retval 1 true
- * \retval 0 false
- */
-static inline int FlowUpdateSeenFlag(const Packet *p)
-{
- if (PKT_IS_ICMPV4(p)) {
- if (ICMPV4_IS_ERROR_MSG(p)) {
- return 0;
- }
- }
-
- return 1;
-}
-
-/**
- *
- * Remove packet from flow. This assumes this happens *before* the packet
- * is added to the stream engine and other higher state.
- *
- * \todo we can't restore the lastts
- */
-void FlowHandlePacketUpdateRemove(Flow *f, Packet *p)
-{
- if (p->flowflags & FLOW_PKT_TOSERVER) {
- f->todstpktcnt--;
- f->todstbytecnt -= GET_PKT_LEN(p);
- p->flowflags &= ~(FLOW_PKT_TOSERVER|FLOW_PKT_TOSERVER_FIRST);
- } else {
- f->tosrcpktcnt--;
- f->tosrcbytecnt -= GET_PKT_LEN(p);
- p->flowflags &= ~(FLOW_PKT_TOCLIENT|FLOW_PKT_TOCLIENT_FIRST);
- }
- p->flowflags &= ~FLOW_PKT_ESTABLISHED;
-
- /*set the detection bypass flags*/
- if (f->flags & FLOW_NOPACKET_INSPECTION) {
- SCLogDebug("unsetting FLOW_NOPACKET_INSPECTION flag on flow %p", f);
- DecodeUnsetNoPacketInspectionFlag(p);
- }
- if (f->flags & FLOW_NOPAYLOAD_INSPECTION) {
- SCLogDebug("unsetting FLOW_NOPAYLOAD_INSPECTION flag on flow %p", f);
- DecodeUnsetNoPayloadInspectionFlag(p);
- }
-}
-
-/** \brief Update Packet and Flow
- *
- * Updates packet and flow based on the new packet.
- *
- * \param f locked flow
- * \param p packet
- *
- * \note overwrites p::flowflags
- */
-void FlowHandlePacketUpdate(Flow *f, Packet *p)
-{
- SCLogDebug("packet %"PRIu64" -- flow %p", p->pcap_cnt, f);
-
- /* Point the Packet at the Flow */
- FlowReference(&p->flow, f);
-
- /* update flags and counters */
- if (FlowGetPacketDirection(f, p) == TOSERVER) {
- f->todstpktcnt++;
- f->todstbytecnt += GET_PKT_LEN(p);
- p->flowflags = FLOW_PKT_TOSERVER;
- if (!(f->flags & FLOW_TO_DST_SEEN)) {
- if (FlowUpdateSeenFlag(p)) {
- f->flags |= FLOW_TO_DST_SEEN;
- p->flowflags |= FLOW_PKT_TOSERVER_FIRST;
- }
- }
- } else {
- f->tosrcpktcnt++;
- f->tosrcbytecnt += GET_PKT_LEN(p);
- p->flowflags = FLOW_PKT_TOCLIENT;
- if (!(f->flags & FLOW_TO_SRC_SEEN)) {
- if (FlowUpdateSeenFlag(p)) {
- f->flags |= FLOW_TO_SRC_SEEN;
- p->flowflags |= FLOW_PKT_TOCLIENT_FIRST;
- }
- }
- }
-
- if ((f->flags & (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) == (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) {
- SCLogDebug("pkt %p FLOW_PKT_ESTABLISHED", p);
- p->flowflags |= FLOW_PKT_ESTABLISHED;
-
- if (f->proto != IPPROTO_TCP) {
- SC_ATOMIC_SET(f->flow_state, FLOW_STATE_ESTABLISHED);
- }
- }
-
- /*set the detection bypass flags*/
- if (f->flags & FLOW_NOPACKET_INSPECTION) {
- SCLogDebug("setting FLOW_NOPACKET_INSPECTION flag on flow %p", f);
- DecodeSetNoPacketInspectionFlag(p);
- }
- if (f->flags & FLOW_NOPAYLOAD_INSPECTION) {
- SCLogDebug("setting FLOW_NOPAYLOAD_INSPECTION flag on flow %p", f);
- DecodeSetNoPayloadInspectionFlag(p);
- }
-}
-
-/** \brief Entry point for packet flow handling
- *
- * This is called for every packet.
- *
- * \param tv threadvars
- * \param dtv decode thread vars (for flow output api thread data)
- * \param p packet to handle flow for
- */
-void FlowHandlePacket(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
-{
- /* Get this packet's flow from the hash. FlowHandlePacket() will setup
- * a new flow if nescesary. If we get NULL, we're out of flow memory.
- * The returned flow is locked. */
- Flow *f = FlowGetFlowFromHash(tv, dtv, p);
- if (f == NULL)
- return;
-
- FlowHandlePacketUpdate(f, p);
-
- FLOWLOCK_UNLOCK(f);
-
- /* set the flow in the packet */
- p->flags |= PKT_HAS_FLOW;
- return;
-}
-
-/** \brief initialize the configuration
- * \warning Not thread safe */
-void FlowInitConfig(char quiet)
-{
- SCLogDebug("initializing flow engine...");
-
- memset(&flow_config, 0, sizeof(flow_config));
- SC_ATOMIC_INIT(flow_flags);
- SC_ATOMIC_INIT(flow_memuse);
- SC_ATOMIC_INIT(flow_prune_idx);
- FlowQueueInit(&flow_spare_q);
- FlowQueueInit(&flow_recycle_q);
-
- unsigned int seed = RandomTimePreseed();
- /* set defaults */
- flow_config.hash_rand = (int)( FLOW_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0));
-
- flow_config.hash_size = FLOW_DEFAULT_HASHSIZE;
- flow_config.memcap = FLOW_DEFAULT_MEMCAP;
- flow_config.prealloc = FLOW_DEFAULT_PREALLOC;
-
- /* If we have specific config, overwrite the defaults with them,
- * otherwise, leave the default values */
- intmax_t val = 0;
- if (ConfGetInt("flow.emergency-recovery", &val) == 1) {
- if (val <= 100 && val >= 1) {
- flow_config.emergency_recovery = (uint8_t)val;
- } else {
- SCLogError(SC_ERR_INVALID_VALUE, "flow.emergency-recovery must be in the range of 1 and 100 (as percentage)");
- flow_config.emergency_recovery = FLOW_DEFAULT_EMERGENCY_RECOVERY;
- }
- } else {
- SCLogDebug("flow.emergency-recovery, using default value");
- flow_config.emergency_recovery = FLOW_DEFAULT_EMERGENCY_RECOVERY;
- }
-
- /* Check if we have memcap and hash_size defined at config */
- char *conf_val;
- uint32_t configval = 0;
-
- /** set config values for memcap, prealloc and hash_size */
- if ((ConfGet("flow.memcap", &conf_val)) == 1)
- {
- if (ParseSizeStringU64(conf_val, &flow_config.memcap) < 0) {
- SCLogError(SC_ERR_SIZE_PARSE, "Error parsing flow.memcap "
- "from conf file - %s. Killing engine",
- conf_val);
- exit(EXIT_FAILURE);
- }
- }
- if ((ConfGet("flow.hash-size", &conf_val)) == 1)
- {
- if (ByteExtractStringUint32(&configval, 10, strlen(conf_val),
- conf_val) > 0) {
- flow_config.hash_size = configval;
- }
- }
- if ((ConfGet("flow.prealloc", &conf_val)) == 1)
- {
- if (ByteExtractStringUint32(&configval, 10, strlen(conf_val),
- conf_val) > 0) {
- flow_config.prealloc = configval;
- }
- }
- SCLogDebug("Flow config from suricata.yaml: memcap: %"PRIu64", hash-size: "
- "%"PRIu32", prealloc: %"PRIu32, flow_config.memcap,
- flow_config.hash_size, flow_config.prealloc);
-
- /* alloc hash memory */
- uint64_t hash_size = flow_config.hash_size * sizeof(FlowBucket);
- if (!(FLOW_CHECK_MEMCAP(hash_size))) {
- SCLogError(SC_ERR_FLOW_INIT, "allocating flow hash failed: "
- "max flow memcap is smaller than projected hash size. "
- "Memcap: %"PRIu64", Hash table size %"PRIu64". Calculate "
- "total hash size by multiplying \"flow.hash-size\" with %"PRIuMAX", "
- "which is the hash bucket size.", flow_config.memcap, hash_size,
- (uintmax_t)sizeof(FlowBucket));
- exit(EXIT_FAILURE);
- }
- flow_hash = SCCalloc(flow_config.hash_size, sizeof(FlowBucket));
- if (unlikely(flow_hash == NULL)) {
- SCLogError(SC_ERR_FATAL, "Fatal error encountered in FlowInitConfig. Exiting...");
- exit(EXIT_FAILURE);
- }
- memset(flow_hash, 0, flow_config.hash_size * sizeof(FlowBucket));
-
- uint32_t i = 0;
- for (i = 0; i < flow_config.hash_size; i++) {
- FBLOCK_INIT(&flow_hash[i]);
- }
- (void) SC_ATOMIC_ADD(flow_memuse, (flow_config.hash_size * sizeof(FlowBucket)));
-
- if (quiet == FALSE) {
- SCLogInfo("allocated %llu bytes of memory for the flow hash... "
- "%" PRIu32 " buckets of size %" PRIuMAX "",
- SC_ATOMIC_GET(flow_memuse), flow_config.hash_size,
- (uintmax_t)sizeof(FlowBucket));
- }
-
- /* pre allocate flows */
- for (i = 0; i < flow_config.prealloc; i++) {
- if (!(FLOW_CHECK_MEMCAP(sizeof(Flow) + FlowStorageSize()))) {
- SCLogError(SC_ERR_FLOW_INIT, "preallocating flows failed: "
- "max flow memcap reached. Memcap %"PRIu64", "
- "Memuse %"PRIu64".", flow_config.memcap,
- ((uint64_t)SC_ATOMIC_GET(flow_memuse) + (uint64_t)sizeof(Flow)));
- exit(EXIT_FAILURE);
- }
-
- Flow *f = FlowAlloc();
- if (f == NULL) {
- SCLogError(SC_ERR_FLOW_INIT, "preallocating flow failed: %s", strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- FlowEnqueue(&flow_spare_q,f);
- }
-
- if (quiet == FALSE) {
- SCLogInfo("preallocated %" PRIu32 " flows of size %" PRIuMAX "",
- flow_spare_q.len, (uintmax_t)(sizeof(Flow) + + FlowStorageSize()));
- SCLogInfo("flow memory usage: %llu bytes, maximum: %"PRIu64,
- SC_ATOMIC_GET(flow_memuse), flow_config.memcap);
- }
-
- FlowInitFlowProto();
-
- return;
-}
-
-/** \brief print some flow stats
- * \warning Not thread safe */
-static void FlowPrintStats (void)
-{
-#ifdef FLOWBITS_STATS
- SCLogInfo("flowbits added: %" PRIu32 ", removed: %" PRIu32 ", max memory usage: %" PRIu32 "",
- flowbits_added, flowbits_removed, flowbits_memuse_max);
-#endif /* FLOWBITS_STATS */
- return;
-}
-
-/** \brief shutdown the flow engine
- * \warning Not thread safe */
-void FlowShutdown(void)
-{
- Flow *f;
- uint32_t u;
-
- FlowPrintStats();
-
- /* free queues */
- while((f = FlowDequeue(&flow_spare_q))) {
- FlowFree(f);
- }
- while((f = FlowDequeue(&flow_recycle_q))) {
- FlowFree(f);
- }
-
- /* clear and free the hash */
- if (flow_hash != NULL) {
- /* clean up flow mutexes */
- for (u = 0; u < flow_config.hash_size; u++) {
- Flow *f = flow_hash[u].head;
- while (f) {
-#ifdef DEBUG_VALIDATION
- BUG_ON(SC_ATOMIC_GET(f->use_cnt) != 0);
-#endif
- Flow *n = f->hnext;
- uint8_t proto_map = FlowGetProtoMapping(f->proto);
- FlowClearMemory(f, proto_map);
- FlowFree(f);
- f = n;
- }
-
- FBLOCK_DESTROY(&flow_hash[u]);
- }
- SCFree(flow_hash);
- flow_hash = NULL;
- }
- (void) SC_ATOMIC_SUB(flow_memuse, flow_config.hash_size * sizeof(FlowBucket));
- FlowQueueDestroy(&flow_spare_q);
- FlowQueueDestroy(&flow_recycle_q);
-
- SC_ATOMIC_DESTROY(flow_prune_idx);
- SC_ATOMIC_DESTROY(flow_memuse);
- SC_ATOMIC_DESTROY(flow_flags);
- return;
-}
-
-/**
- * \brief Function to set the default timeout, free function and flow state
- * function for all supported flow_proto.
- */
-
-void FlowInitFlowProto(void)
-{
- /*Default*/
- flow_proto[FLOW_PROTO_DEFAULT].new_timeout = FLOW_DEFAULT_NEW_TIMEOUT;
- flow_proto[FLOW_PROTO_DEFAULT].est_timeout = FLOW_DEFAULT_EST_TIMEOUT;
- flow_proto[FLOW_PROTO_DEFAULT].closed_timeout =
- FLOW_DEFAULT_CLOSED_TIMEOUT;
- flow_proto[FLOW_PROTO_DEFAULT].emerg_new_timeout =
- FLOW_DEFAULT_EMERG_NEW_TIMEOUT;
- flow_proto[FLOW_PROTO_DEFAULT].emerg_est_timeout =
- FLOW_DEFAULT_EMERG_EST_TIMEOUT;
- flow_proto[FLOW_PROTO_DEFAULT].emerg_closed_timeout =
- FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT;
- flow_proto[FLOW_PROTO_DEFAULT].Freefunc = NULL;
- /*TCP*/
- flow_proto[FLOW_PROTO_TCP].new_timeout = FLOW_IPPROTO_TCP_NEW_TIMEOUT;
- flow_proto[FLOW_PROTO_TCP].est_timeout = FLOW_IPPROTO_TCP_EST_TIMEOUT;
- flow_proto[FLOW_PROTO_TCP].closed_timeout = FLOW_DEFAULT_CLOSED_TIMEOUT;
- flow_proto[FLOW_PROTO_TCP].emerg_new_timeout =
- FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT;
- flow_proto[FLOW_PROTO_TCP].emerg_est_timeout =
- FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT;
- flow_proto[FLOW_PROTO_TCP].emerg_closed_timeout =
- FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT;
- flow_proto[FLOW_PROTO_TCP].Freefunc = NULL;
- /*UDP*/
- flow_proto[FLOW_PROTO_UDP].new_timeout = FLOW_IPPROTO_UDP_NEW_TIMEOUT;
- flow_proto[FLOW_PROTO_UDP].est_timeout = FLOW_IPPROTO_UDP_EST_TIMEOUT;
- flow_proto[FLOW_PROTO_UDP].closed_timeout = FLOW_DEFAULT_CLOSED_TIMEOUT;
- flow_proto[FLOW_PROTO_UDP].emerg_new_timeout =
- FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT;
- flow_proto[FLOW_PROTO_UDP].emerg_est_timeout =
- FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT;
- flow_proto[FLOW_PROTO_UDP].emerg_closed_timeout =
- FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT;
- flow_proto[FLOW_PROTO_UDP].Freefunc = NULL;
- /*ICMP*/
- flow_proto[FLOW_PROTO_ICMP].new_timeout = FLOW_IPPROTO_ICMP_NEW_TIMEOUT;
- flow_proto[FLOW_PROTO_ICMP].est_timeout = FLOW_IPPROTO_ICMP_EST_TIMEOUT;
- flow_proto[FLOW_PROTO_ICMP].closed_timeout = FLOW_DEFAULT_CLOSED_TIMEOUT;
- flow_proto[FLOW_PROTO_ICMP].emerg_new_timeout =
- FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT;
- flow_proto[FLOW_PROTO_ICMP].emerg_est_timeout =
- FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT;
- flow_proto[FLOW_PROTO_ICMP].emerg_closed_timeout =
- FLOW_DEFAULT_EMERG_CLOSED_TIMEOUT;
- flow_proto[FLOW_PROTO_ICMP].Freefunc = NULL;
-
- /* Let's see if we have custom timeouts defined from config */
- const char *new = NULL;
- const char *established = NULL;
- const char *closed = NULL;
- const char *emergency_new = NULL;
- const char *emergency_established = NULL;
- const char *emergency_closed = NULL;
-
- ConfNode *flow_timeouts = ConfGetNode("flow-timeouts");
- if (flow_timeouts != NULL) {
- ConfNode *proto = NULL;
- uint32_t configval = 0;
-
- /* Defaults. */
- proto = ConfNodeLookupChild(flow_timeouts, "default");
- if (proto != NULL) {
- new = ConfNodeLookupChildValue(proto, "new");
- established = ConfNodeLookupChildValue(proto, "established");
- closed = ConfNodeLookupChildValue(proto, "closed");
- emergency_new = ConfNodeLookupChildValue(proto, "emergency-new");
- emergency_established = ConfNodeLookupChildValue(proto,
- "emergency-established");
- emergency_closed = ConfNodeLookupChildValue(proto,
- "emergency-closed");
-
- if (new != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) {
-
- flow_proto[FLOW_PROTO_DEFAULT].new_timeout = configval;
- }
- if (established != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(established),
- established) > 0) {
-
- flow_proto[FLOW_PROTO_DEFAULT].est_timeout = configval;
- }
- if (closed != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(closed),
- closed) > 0) {
-
- flow_proto[FLOW_PROTO_DEFAULT].closed_timeout = configval;
- }
- if (emergency_new != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(emergency_new),
- emergency_new) > 0) {
-
- flow_proto[FLOW_PROTO_DEFAULT].emerg_new_timeout = configval;
- }
- if (emergency_established != NULL &&
- ByteExtractStringUint32(&configval, 10,
- strlen(emergency_established),
- emergency_established) > 0) {
-
- flow_proto[FLOW_PROTO_DEFAULT].emerg_est_timeout= configval;
- }
- if (emergency_closed != NULL &&
- ByteExtractStringUint32(&configval, 10,
- strlen(emergency_closed),
- emergency_closed) > 0) {
-
- flow_proto[FLOW_PROTO_DEFAULT].emerg_closed_timeout = configval;
- }
- }
-
- /* TCP. */
- proto = ConfNodeLookupChild(flow_timeouts, "tcp");
- if (proto != NULL) {
- new = ConfNodeLookupChildValue(proto, "new");
- established = ConfNodeLookupChildValue(proto, "established");
- closed = ConfNodeLookupChildValue(proto, "closed");
- emergency_new = ConfNodeLookupChildValue(proto, "emergency-new");
- emergency_established = ConfNodeLookupChildValue(proto,
- "emergency-established");
- emergency_closed = ConfNodeLookupChildValue(proto,
- "emergency-closed");
-
- if (new != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) {
-
- flow_proto[FLOW_PROTO_TCP].new_timeout = configval;
- }
- if (established != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(established),
- established) > 0) {
-
- flow_proto[FLOW_PROTO_TCP].est_timeout = configval;
- }
- if (closed != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(closed),
- closed) > 0) {
-
- flow_proto[FLOW_PROTO_TCP].closed_timeout = configval;
- }
- if (emergency_new != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(emergency_new),
- emergency_new) > 0) {
-
- flow_proto[FLOW_PROTO_TCP].emerg_new_timeout = configval;
- }
- if (emergency_established != NULL &&
- ByteExtractStringUint32(&configval, 10,
- strlen(emergency_established),
- emergency_established) > 0) {
-
- flow_proto[FLOW_PROTO_TCP].emerg_est_timeout = configval;
- }
- if (emergency_closed != NULL &&
- ByteExtractStringUint32(&configval, 10,
- strlen(emergency_closed),
- emergency_closed) > 0) {
-
- flow_proto[FLOW_PROTO_TCP].emerg_closed_timeout = configval;
- }
- }
-
- /* UDP. */
- proto = ConfNodeLookupChild(flow_timeouts, "udp");
- if (proto != NULL) {
- new = ConfNodeLookupChildValue(proto, "new");
- established = ConfNodeLookupChildValue(proto, "established");
- emergency_new = ConfNodeLookupChildValue(proto, "emergency-new");
- emergency_established = ConfNodeLookupChildValue(proto,
- "emergency-established");
- if (new != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) {
-
- flow_proto[FLOW_PROTO_UDP].new_timeout = configval;
- }
- if (established != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(established),
- established) > 0) {
-
- flow_proto[FLOW_PROTO_UDP].est_timeout = configval;
- }
- if (emergency_new != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(emergency_new),
- emergency_new) > 0) {
-
- flow_proto[FLOW_PROTO_UDP].emerg_new_timeout = configval;
- }
- if (emergency_established != NULL &&
- ByteExtractStringUint32(&configval, 10,
- strlen(emergency_established),
- emergency_established) > 0) {
-
- flow_proto[FLOW_PROTO_UDP].emerg_est_timeout = configval;
- }
- }
-
- /* ICMP. */
- proto = ConfNodeLookupChild(flow_timeouts, "icmp");
- if (proto != NULL) {
- new = ConfNodeLookupChildValue(proto, "new");
- established = ConfNodeLookupChildValue(proto, "established");
- emergency_new = ConfNodeLookupChildValue(proto, "emergency-new");
- emergency_established = ConfNodeLookupChildValue(proto,
- "emergency-established");
-
- if (new != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(new), new) > 0) {
-
- flow_proto[FLOW_PROTO_ICMP].new_timeout = configval;
- }
- if (established != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(established),
- established) > 0) {
-
- flow_proto[FLOW_PROTO_ICMP].est_timeout = configval;
- }
- if (emergency_new != NULL &&
- ByteExtractStringUint32(&configval, 10, strlen(emergency_new),
- emergency_new) > 0) {
-
- flow_proto[FLOW_PROTO_ICMP].emerg_new_timeout = configval;
- }
- if (emergency_established != NULL &&
- ByteExtractStringUint32(&configval, 10,
- strlen(emergency_established),
- emergency_established) > 0) {
-
- flow_proto[FLOW_PROTO_ICMP].emerg_est_timeout = configval;
- }
- }
- }
-
- return;
-}
-
-/**
- * \brief Function clear the flow memory before queueing it to spare flow
- * queue.
- *
- * \param f pointer to the flow needed to be cleared.
- * \param proto_map mapped value of the protocol to FLOW_PROTO's.
- */
-
-int FlowClearMemory(Flow* f, uint8_t proto_map)
-{
- SCEnter();
-
- /* call the protocol specific free function if we have one */
- if (flow_proto[proto_map].Freefunc != NULL) {
- flow_proto[proto_map].Freefunc(f->protoctx);
- }
-
- FlowFreeStorage(f);
-
- FLOW_RECYCLE(f);
-
- SCReturnInt(1);
-}
-
-/**
- * \brief Function to set the function to get protocol specific flow state.
- *
- * \param proto protocol of which function is needed to be set.
- * \param Free Function pointer which will be called to free the protocol
- * specific memory.
- */
-
-int FlowSetProtoFreeFunc (uint8_t proto, void (*Free)(void *))
-{
- uint8_t proto_map;
- proto_map = FlowGetProtoMapping(proto);
-
- flow_proto[proto_map].Freefunc = Free;
- return 1;
-}
-
-/**
- * \brief Function to set the timeout values for the specified protocol.
- *
- * \param proto protocol of which timeout value is needed to be set.
- * \param new_timeout timeout value for the new flows.
- * \param est_timeout timeout value for the established flows.
- * \param closed_timeout timeout value for the closed flows.
- */
-
-int FlowSetProtoTimeout(uint8_t proto, uint32_t new_timeout,
- uint32_t est_timeout, uint32_t closed_timeout)
-{
- uint8_t proto_map;
- proto_map = FlowGetProtoMapping(proto);
-
- flow_proto[proto_map].new_timeout = new_timeout;
- flow_proto[proto_map].est_timeout = est_timeout;
- flow_proto[proto_map].closed_timeout = closed_timeout;
-
- return 1;
-}
-
-/**
- * \brief Function to set the emergency timeout values for the specified
- * protocol.
- *
- * \param proto protocol of which timeout value is needed to be set.
- * \param emerg_new_timeout timeout value for the new flows.
- * \param emerg_est_timeout timeout value for the established flows.
- * \param emerg_closed_timeout timeout value for the closed flows.
- */
-
-int FlowSetProtoEmergencyTimeout(uint8_t proto, uint32_t emerg_new_timeout,
- uint32_t emerg_est_timeout,
- uint32_t emerg_closed_timeout)
-{
-
- uint8_t proto_map;
- proto_map = FlowGetProtoMapping(proto);
-
- flow_proto[proto_map].emerg_new_timeout = emerg_new_timeout;
- flow_proto[proto_map].emerg_est_timeout = emerg_est_timeout;
- flow_proto[proto_map].emerg_closed_timeout = emerg_closed_timeout;
-
- return 1;
-}
-
-AppProto FlowGetAppProtocol(const Flow *f)
-{
- return f->alproto;
-}
-
-void *FlowGetAppState(const Flow *f)
-{
- return f->alstate;
-}
-
-/**
- * \brief get 'disruption' flags: GAP/DEPTH/PASS
- * \param f locked flow
- * \param flags existing flags to be ammended
- * \retval flags original flags + disrupt flags (if any)
- * \TODO handle UDP
- */
-uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags)
-{
- if (f->proto != IPPROTO_TCP) {
- return flags;
- }
- if (f->protoctx == NULL) {
- return flags;
- }
-
- uint8_t newflags = flags;
- TcpSession *ssn = f->protoctx;
- TcpStream *stream = flags & STREAM_TOSERVER ? &ssn->client : &ssn->server;
-
- if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
- newflags |= STREAM_DEPTH;
- }
- if (stream->flags & STREAMTCP_STREAM_FLAG_GAP) {
- newflags |= STREAM_GAP;
- }
- /* todo: handle pass case (also for UDP!) */
-
- return newflags;
-}
-
-/************************************Unittests*******************************/
-
-#ifdef UNITTESTS
-#include "stream-tcp-private.h"
-#include "threads.h"
-
-/**
- * \test Test the setting of the per protocol timeouts.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int FlowTest01 (void)
-{
- uint8_t proto_map;
-
- FlowInitFlowProto();
- proto_map = FlowGetProtoMapping(IPPROTO_TCP);
-
- if ((flow_proto[proto_map].new_timeout != FLOW_IPPROTO_TCP_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_IPPROTO_TCP_EST_TIMEOUT)
- && (flow_proto[proto_map].emerg_new_timeout != FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT)){
- printf ("failed in setting TCP flow timeout");
- return 0;
- }
-
- proto_map = FlowGetProtoMapping(IPPROTO_UDP);
- if ((flow_proto[proto_map].new_timeout != FLOW_IPPROTO_UDP_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_IPPROTO_UDP_EST_TIMEOUT)
- && (flow_proto[proto_map].emerg_new_timeout != FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT)){
- printf ("failed in setting UDP flow timeout");
- return 0;
- }
-
- proto_map = FlowGetProtoMapping(IPPROTO_ICMP);
- if ((flow_proto[proto_map].new_timeout != FLOW_IPPROTO_ICMP_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_IPPROTO_ICMP_EST_TIMEOUT)
- && (flow_proto[proto_map].emerg_new_timeout != FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT)){
- printf ("failed in setting ICMP flow timeout");
- return 0;
- }
-
- proto_map = FlowGetProtoMapping(IPPROTO_DCCP);
- if ((flow_proto[proto_map].new_timeout != FLOW_DEFAULT_NEW_TIMEOUT) && (flow_proto[proto_map].est_timeout != FLOW_DEFAULT_EST_TIMEOUT)
- && (flow_proto[proto_map].emerg_new_timeout != FLOW_DEFAULT_EMERG_NEW_TIMEOUT) && (flow_proto[proto_map].emerg_est_timeout != FLOW_DEFAULT_EMERG_EST_TIMEOUT)){
- printf ("failed in setting default flow timeout");
- return 0;
- }
-
- return 1;
-}
-
-/*Test function for the unit test FlowTest02*/
-
-void test(void *f) {}
-
-/**
- * \test Test the setting of the per protocol free function to free the
- * protocol specific memory.
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int FlowTest02 (void)
-{
- FlowSetProtoFreeFunc(IPPROTO_DCCP, test);
- FlowSetProtoFreeFunc(IPPROTO_TCP, test);
- FlowSetProtoFreeFunc(IPPROTO_UDP, test);
- FlowSetProtoFreeFunc(IPPROTO_ICMP, test);
-
- if (flow_proto[FLOW_PROTO_DEFAULT].Freefunc != test) {
- printf("Failed in setting default free function\n");
- return 0;
- }
- if (flow_proto[FLOW_PROTO_TCP].Freefunc != test) {
- printf("Failed in setting TCP free function\n");
- return 0;
- }
- if (flow_proto[FLOW_PROTO_UDP].Freefunc != test) {
- printf("Failed in setting UDP free function\n");
- return 0;
- }
- if (flow_proto[FLOW_PROTO_ICMP].Freefunc != test) {
- printf("Failed in setting ICMP free function\n");
- return 0;
- }
- return 1;
-}
-
-/**
- * \test Test flow allocations when it reach memcap
- *
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int FlowTest07 (void)
-{
- int result = 0;
-
- FlowInitConfig(FLOW_QUIET);
- FlowConfig backup;
- memcpy(&backup, &flow_config, sizeof(FlowConfig));
-
- uint32_t ini = 0;
- uint32_t end = flow_spare_q.len;
- flow_config.memcap = 10000;
- flow_config.prealloc = 100;
-
- /* Let's get the flow_spare_q empty */
- UTHBuildPacketOfFlows(ini, end, 0);
-
- /* And now let's try to reach the memcap val */
- while (FLOW_CHECK_MEMCAP(sizeof(Flow))) {
- ini = end + 1;
- end = end + 2;
- UTHBuildPacketOfFlows(ini, end, 0);
- }
-
- /* should time out normal */
- TimeSetIncrementTime(2000);
- ini = end + 1;
- end = end + 2;;
- UTHBuildPacketOfFlows(ini, end, 0);
-
- /* This means that the engine entered emerg mode: should happen as easy
- * with flow mgr activated */
- if (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)
- result = 1;
-
- memcpy(&flow_config, &backup, sizeof(FlowConfig));
- FlowShutdown();
-
- return result;
-}
-
-/**
- * \test Test flow allocations when it reach memcap
- *
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int FlowTest08 (void)
-{
- int result = 0;
-
- FlowInitConfig(FLOW_QUIET);
- FlowConfig backup;
- memcpy(&backup, &flow_config, sizeof(FlowConfig));
-
- uint32_t ini = 0;
- uint32_t end = flow_spare_q.len;
- flow_config.memcap = 10000;
- flow_config.prealloc = 100;
-
- /* Let's get the flow_spare_q empty */
- UTHBuildPacketOfFlows(ini, end, 0);
-
- /* And now let's try to reach the memcap val */
- while (FLOW_CHECK_MEMCAP(sizeof(Flow))) {
- ini = end + 1;
- end = end + 2;
- UTHBuildPacketOfFlows(ini, end, 0);
- }
-
- /* By default we use 30 for timing out new flows. This means
- * that the Emergency mode should be set */
- TimeSetIncrementTime(20);
- ini = end + 1;
- end = end + 2;
- UTHBuildPacketOfFlows(ini, end, 0);
-
- /* This means that the engine released 5 flows by emergency timeout */
- if (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)
- result = 1;
-
- memcpy(&flow_config, &backup, sizeof(FlowConfig));
- FlowShutdown();
-
- return result;
-}
-
-/**
- * \test Test flow allocations when it reach memcap
- *
- *
- * \retval On success it returns 1 and on failure 0.
- */
-
-static int FlowTest09 (void)
-{
- int result = 0;
-
- FlowInitConfig(FLOW_QUIET);
- FlowConfig backup;
- memcpy(&backup, &flow_config, sizeof(FlowConfig));
-
- uint32_t ini = 0;
- uint32_t end = flow_spare_q.len;
- flow_config.memcap = 10000;
- flow_config.prealloc = 100;
-
- /* Let's get the flow_spare_q empty */
- UTHBuildPacketOfFlows(ini, end, 0);
-
- /* And now let's try to reach the memcap val */
- while (FLOW_CHECK_MEMCAP(sizeof(Flow))) {
- ini = end + 1;
- end = end + 2;
- UTHBuildPacketOfFlows(ini, end, 0);
- }
-
- /* No timeout will work */
- TimeSetIncrementTime(5);
- ini = end + 1;
- end = end + 2;
- UTHBuildPacketOfFlows(ini, end, 0);
-
- /* engine in emerg mode */
- if (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)
- result = 1;
-
- memcpy(&flow_config, &backup, sizeof(FlowConfig));
- FlowShutdown();
-
- return result;
-}
-
-#endif /* UNITTESTS */
-
-/**
- * \brief Function to register the Flow Unitests.
- */
-void FlowRegisterTests (void)
-{
-#ifdef UNITTESTS
- UtRegisterTest("FlowTest01 -- Protocol Specific Timeouts", FlowTest01, 1);
- UtRegisterTest("FlowTest02 -- Setting Protocol Specific Free Function", FlowTest02, 1);
- UtRegisterTest("FlowTest07 -- Test flow Allocations when it reach memcap", FlowTest07, 1);
- UtRegisterTest("FlowTest08 -- Test flow Allocations when it reach memcap", FlowTest08, 1);
- UtRegisterTest("FlowTest09 -- Test flow Allocations when it reach memcap", FlowTest09, 1);
-
- FlowMgrRegisterTests();
- RegisterFlowStorageTests();
-#endif /* UNITTESTS */
-}