set (FLOW_INCLUDES
flow.h
+ flow_config.h
flow_key.h
+ memcap.h
)
add_library (flow STATIC
x_include_HEADERS = \
flow.h \
-flow_key.h
+flow_config.h \
+flow_key.h \
+memcap.h
libflow_a_SOURCES = \
flow.cc \
#include "packet_io/active.h"
#include "packet_time.h"
#include "ips_options/ips_flowbits.h"
-#include "stream/stream.h"
#include "hash/zhash.h"
#include "main/snort_debug.h"
//-------------------------------------------------------------------------
FlowCache::FlowCache (
- int max,
- uint32_t flow_timeout_min,
- uint32_t flow_timeout_max,
- uint32_t cleanup_count,
- uint32_t cleanup_percent)
+ const FlowConfig& cfg, uint32_t cleanup_count, uint32_t cleanup_percent) :
+ config(cfg), memcap(cfg.mem_cap)
{
- timeoutAggressive = flow_timeout_min;
- timeoutNominal = flow_timeout_max;
- max_flows = max;
-
if (cleanup_percent)
- cleanup_flows = max_flows * cleanup_percent/100;
+ cleanup_flows = config.max_sessions * cleanup_percent/100;
else
cleanup_flows = cleanup_count;
if ( !cleanup_flows )
cleanup_flows = 1;
- hash_table = new ZHash(max_flows, sizeof(FlowKey));
+ hash_table = new ZHash(config.max_sessions, sizeof(FlowKey));
hash_table->set_keyops(FlowKey::hash, FlowKey::compare);
uni_head = new Flow;
hash_table->touch();
}
- else if ((flow->last_data_seen + timeoutAggressive) < thetime)
+ else if ((flow->last_data_seen + config.pruning_timeout) < thetime)
{
DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "pruning stale flow\n"); );
flow->ssn_state.session_flags |= SSNFLAG_TIMEDOUT;
{
// we may have many or few unis; need to find reasonable ratio
// FIXIT-L max_uni should be based on typical ratios seen in perfmon
- const uint32_t max_uni = (max_flows >> 2) + 1;
+ const uint32_t max_uni = (config.max_sessions >> 2) + 1;
Flow* curr = uni_tail->prev;
uint32_t pruned = 0;
* memcap or free enough flows to be able to create
* new ones.
*/
- const uint32_t max_cap = max_flows - cleanup_flows;
+ const uint32_t max_cap = config.max_sessions - cleanup_flows;
uint32_t pruned = 0;
Active::suspend();
while (
(hash_table->get_count() > 1) &&
((!memCheck && ((hash_table->get_count() > max_cap) || !pruned)) ||
- (memCheck && tcp_memcap->at_max()) )) // FIXIT-M remove explicit dependence on tcp_memcap
+ (memCheck && memcap.at_max()) ))
{
unsigned int blocks = 0;
Flow* flow = (Flow*)hash_table->first();
while ( flow && flowRetiredCount < flowCount && flowExaminedCount < flowMax )
{
- if ((time_t)(flow->last_data_seen + timeoutNominal) > cur_time)
+ if ((time_t)(flow->last_data_seen + config.nominal_timeout) > cur_time)
break;
flowExaminedCount++;
#ifndef FLOW_CACHE_H
#define FLOW_CACHE_H
+#include "flow/flow_config.h"
#include "flow/flow_key.h"
+#include "flow/memcap.h"
#include "stream/stream.h"
class FlowCache
{
public:
FlowCache(
- int max_flows,
- uint32_t flow_timeout_min,
- uint32_t flow_timeout_max,
+ const FlowConfig&,
uint32_t cleanup_flows,
uint32_t cleanup_percent);
int purge();
int get_count();
- uint32_t get_max_flows() { return max_flows; }
+ uint32_t get_max_flows() { return config.max_sessions; }
uint32_t get_prunes() { return prunes; }
void reset_prunes() { prunes = 0; }
void unlink_uni(Flow*);
+ Memcap& get_memcap() { return memcap; }
+
private:
void link_uni(Flow*);
int remove(Flow*);
private:
- uint32_t timeoutAggressive;
- uint32_t timeoutNominal;
- uint32_t max_flows;
+ const FlowConfig& config;
uint32_t cleanup_flows;
uint32_t prunes;
uint32_t uni_count;
uint32_t flags;
+ Memcap memcap;
+
class ZHash* hash_table;
Flow* uni_head, * uni_tail;
};
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// flow_config.h author Russ Combs <rucombs@cisco.com>
+
+#ifndef FLOW_CONFIG_H
+#define FLOW_CONFIG_H
+
+struct FlowConfig
+{
+ unsigned max_sessions = 0;
+ unsigned long mem_cap = 0;
+ unsigned pruning_timeout = 0;
+ unsigned nominal_timeout = 0;
+};
+
+#endif
+
cache->reset_prunes();
}
+Memcap& FlowControl::get_memcap (PktType proto)
+{
+ static Memcap dummy;
+ FlowCache* cache = get_cache(proto);
+ assert(cache); // FIXIT-L dummy is a hack
+ return cache ? cache->get_memcap() : dummy;
+}
+
//-------------------------------------------------------------------------
// cache foo
//-------------------------------------------------------------------------
if ( !fc.max_sessions || !get_ssn )
return;
- ip_cache = new FlowCache(
- fc.max_sessions, fc.cache_pruning_timeout,
- fc.cache_nominal_timeout, 5, 0);
+ ip_cache = new FlowCache(fc, 5, 0);
ip_mem = (Flow*)calloc(fc.max_sessions, sizeof(Flow));
if ( !fc.max_sessions || !get_ssn )
return;
- icmp_cache = new FlowCache(
- fc.max_sessions, fc.cache_pruning_timeout,
- fc.cache_nominal_timeout, 5, 0);
+ icmp_cache = new FlowCache(fc, 5, 0);
icmp_mem = (Flow*)calloc(fc.max_sessions, sizeof(Flow));
if ( !fc.max_sessions || !get_ssn )
return;
- tcp_cache = new FlowCache(
- fc.max_sessions, fc.cache_pruning_timeout,
- fc.cache_nominal_timeout, 5, 0);
+ tcp_cache = new FlowCache(fc, 5, 0);
tcp_mem = (Flow*)calloc(fc.max_sessions, sizeof(Flow));
if ( !fc.max_sessions || !get_ssn )
return;
- udp_cache = new FlowCache(
- fc.max_sessions, fc.cache_pruning_timeout,
- fc.cache_nominal_timeout, 5, 0);
+ udp_cache = new FlowCache(fc, 5, 0);
udp_mem = (Flow*)calloc(fc.max_sessions, sizeof(Flow));
if ( !fc.max_sessions || !get_ssn )
return;
- user_cache = new FlowCache(
- fc.max_sessions, fc.cache_pruning_timeout,
- fc.cache_nominal_timeout, 5, 0);
+ user_cache = new FlowCache(fc, 5, 0);
user_mem = (Flow*)calloc(fc.max_sessions, sizeof(Flow));
if ( !fc.max_sessions || !get_ssn )
return;
- file_cache = new FlowCache(
- fc.max_sessions, fc.cache_pruning_timeout,
- fc.cache_nominal_timeout, 5, 0);
+ file_cache = new FlowCache(fc, 5, 0);
file_mem = (Flow*)calloc(fc.max_sessions, sizeof(Flow));
#define FLOW_CONTROL_H
#include "flow/flow.h"
+#include "flow/flow_config.h"
#include "utils/stats.h"
-struct FlowConfig
-{
- uint64_t mem_cap;
- uint32_t max_sessions;
- uint16_t cache_pruning_timeout;
- uint16_t cache_nominal_timeout;
-};
-
class FlowControl
{
public:
PegCount get_flows(PktType);
void clear_counts();
+ class Memcap& get_memcap(PktType);
+
private:
class FlowCache* get_cache(PktType);
void set_key(FlowKey*, Packet*);
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// memcap.h author Russ Combs <rucombs@cisco.com>
+
+#ifndef MEMCAP_H
+#define MEMCAP_H
+
+#include <stdint.h>
+
+class Memcap
+{
+public:
+ Memcap(uint64_t u = 0) { cap = u; use = 0; }
+
+ void set_cap(uint64_t c) { cap = c; }
+ uint64_t get_cap() { return cap; }
+ bool at_max() { return cap and use >= cap; }
+ void alloc(uint64_t sz) { use += sz; }
+ void dealloc(uint64_t sz) { if ( use >= sz) use -= sz; }
+ uint64_t used() { return use; }
+
+private:
+ uint64_t cap;
+ uint64_t use;
+};
+
+#endif
+
#include "flow/flow_control.h"
#include "stream/stream_api.h"
#include "time/profiler.h"
+#include "stream/tcp/tcp_session.h"
//-------------------------------------------------------------------------
// stats
if ( config->ip_cfg.max_sessions )
{
if ( (f = InspectorManager::get_session((uint16_t)PktType::IP)) )
+ {
flow_con->init_ip(config->ip_cfg, f);
+ // FIXIT-L update stream_ip to use standard memcap
+ //IpSession::set_memcap(flow_con->get_memcap(PktType::IP));
+ }
}
if ( config->icmp_cfg.max_sessions )
{
if ( config->tcp_cfg.max_sessions )
{
if ( (f = InspectorManager::get_session((uint16_t)PktType::TCP)) )
+ {
flow_con->init_tcp(config->tcp_cfg, f);
+ TcpSession::set_memcap(flow_con->get_memcap(PktType::TCP));
+ }
}
if ( config->udp_cfg.max_sessions )
{
if ( config->user_cfg.max_sessions )
{
if ( (f = InspectorManager::get_session((uint16_t)PktType::USER)) )
+ {
flow_con->init_user(config->user_cfg, f);
+ // FIXIT-L update stream_ip to use standard memcap
+ //UserSession::set_memcap(flow_con->get_memcap(PktType::USER));
+ }
}
if ( config->file_cfg.max_sessions )
{
// stream_module.cc author Russ Combs <rucombs@cisco.com>
#include "stream_module.h"
+#include "stream/stream.h"
#include <string>
using namespace std;
-#include "stream/stream.h"
-
-static constexpr unsigned K = 1024;
-
-static StreamModuleConfig stream_cfg =
-{
- // bytes, #, sec, sec
- { 8*K, 16*K, 30, 180 }, // ip
- { 8*K, 32*K, 30, 180 }, // icmp
- { 8*K, 128*K, 30, 180 }, // tcp
- { 8*K, 64*K, 30, 180 }, // udp
- { 8*K, 8*K, 30, 180 }, // user
- { 8*K, 4*K, 30, 180 }, // file
-};
-
//-------------------------------------------------------------------------
// stream module
//-------------------------------------------------------------------------
-static const Parameter proto_params[] =
-{
- { "memcap", Parameter::PT_INT, "0:", "0",
- "maximum cache memory" },
-
- { "idle_timeout", Parameter::PT_INT, "1:", "60",
- "maximum inactive time before retiring session tracker" },
-
- { "pruning_timeout", Parameter::PT_INT, "1:", "30",
- "minimum inactive time before being eligible for pruning" },
+#define CACHE_PARAMS(name, ssn, mem, prune, idle) \
+static const Parameter name[] = \
+{ \
+ { "max_sessions", Parameter::PT_INT, "1:", ssn, \
+ "maximum simultaneous sessions tracked before pruning" }, \
+ \
+ { "memcap", Parameter::PT_INT, "0:", mem, \
+ "maximum cache memory before pruning (0 is unlimited)" }, \
+ \
+ { "pruning_timeout", Parameter::PT_INT, "1:", prune, \
+ "minimum inactive time before being eligible for pruning" }, \
+ \
+ { "idle_timeout", Parameter::PT_INT, "1:", idle, \
+ "maximum inactive time before retiring session tracker" }, \
+ \
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } \
+}
- { "max_sessions", Parameter::PT_INT, "0:", "262144",
- "maximum simultaneous tcp sessions tracked before pruning" },
+CACHE_PARAMS(ip_params, "16384", "23920640", "30", "180");
+CACHE_PARAMS(icmp_params, "32768", "1048576", "30", "180");
+CACHE_PARAMS(tcp_params, "131072", "268435456", "30", "180");
+CACHE_PARAMS(udp_params, "65536", "0", "30", "180");
+CACHE_PARAMS(user_params, "1024", "1048576", "30", "180");
+CACHE_PARAMS(file_params, " 128", "0", "30", "180");
- { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
-};
+#define CACHE_TABLE(cache, proto, params) \
+ { cache, Parameter::PT_TABLE, params, nullptr, \
+ "configure " proto " cache limits" }
static const Parameter s_params[] =
{
- { "icmp_cache", Parameter::PT_TABLE, proto_params, nullptr,
- "configure icmp cache limits" },
-
- { "ip_cache", Parameter::PT_TABLE, proto_params, nullptr,
- "configure ip cache limits" },
-
- { "tcp_cache", Parameter::PT_TABLE, proto_params, nullptr,
- "configure tcp cache limits" },
-
- { "udp_cache", Parameter::PT_TABLE, proto_params, nullptr,
- "configure udp cache limits" },
+ CACHE_TABLE("ip_cache", "ip", ip_params),
+ CACHE_TABLE("icmp_cache", "icmp", icmp_params),
+ CACHE_TABLE("tcp_cache", "tcp", tcp_params),
+ CACHE_TABLE("udp_cache", "udp", udp_params),
+ CACHE_TABLE("user_cache", "user", user_params),
+ CACHE_TABLE("file_cache", "file", file_params),
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
StreamModule::StreamModule() :
Module(MOD_NAME, MOD_HELP, s_params)
-{
- proto = &stream_cfg.ip_cfg;
-}
+{ }
const PegInfo* StreamModule::get_pegs() const
{ return base_pegs; }
const StreamModuleConfig* StreamModule::get_data()
{
- return &stream_cfg;
+ return &config;
}
-bool StreamModule::set(const char*, Value& v, SnortConfig*)
+bool StreamModule::set(const char* fqn, Value& v, SnortConfig*)
{
- if ( v.is("memcap") )
- proto->mem_cap = v.get_long();
+ FlowConfig* fc = nullptr;
- else if ( v.is("max_sessions") )
- proto->max_sessions = v.get_long();
+ if ( strstr(fqn, "ip_cache") )
+ fc = &config.ip_cfg;
- else if ( v.is("pruning_timeout") )
- proto->cache_pruning_timeout = v.get_long();
+ else if ( strstr(fqn, "icmp_cache") )
+ fc = &config.icmp_cfg;
- else if ( v.is("idle_timeout") )
- proto->cache_nominal_timeout = v.get_long();
+ else if ( strstr(fqn, "tcp_cache") )
+ fc = &config.tcp_cfg;
+
+ else if ( strstr(fqn, "udp_cache") )
+ fc = &config.udp_cfg;
+
+ else if ( strstr(fqn, "user_cache") )
+ fc = &config.user_cfg;
+
+ else if ( strstr(fqn, "file_cache") )
+ fc = &config.file_cfg;
else
return false;
- return true;
-}
-
-bool StreamModule::begin(const char* fqn, int, SnortConfig*)
-{
- if ( !strcmp(fqn, "stream.tcp_cache") )
- proto = &stream_cfg.tcp_cfg;
+ if ( v.is("memcap") )
+ fc->mem_cap = v.get_long();
- else if ( !strcmp(fqn, "stream.udp_cache") )
- proto = &stream_cfg.udp_cfg;
+ else if ( v.is("max_sessions") )
+ fc->max_sessions = v.get_long();
- else if ( !strcmp(fqn, "stream.icmp_cache") )
- proto = &stream_cfg.icmp_cfg;
+ else if ( v.is("pruning_timeout") )
+ fc->pruning_timeout = v.get_long();
- else if ( !strcmp(fqn, "stream.ip_cache") )
- proto = &stream_cfg.ip_cfg;
+ else if ( v.is("idle_timeout") )
+ fc->nominal_timeout = v.get_long();
- else if ( strcmp(fqn, "stream") )
+ else
return false;
return true;
StreamModule();
bool set(const char*, Value&, SnortConfig*) override;
- bool begin(const char*, int, SnortConfig*) override;
const PegInfo* get_pegs() const override;
ProfileStats* get_profile() const override;
void reset_stats() override;
private:
- FlowConfig* proto;
+ StreamModuleConfig config;
};
extern void base_sum();
#define FROM_CLIENT 1
#define FROM_SENDER 1
-class Memcap
-{
-public:
- Memcap(unsigned u) { cap = u; use = 0; }
-
- void set_cap(unsigned c) { cap = c; }
- unsigned get_cap() { return cap; }
- bool at_max() { return use >= cap; }
- void alloc(unsigned sz) { use += sz; }
- void dealloc(unsigned sz) { if ( use >= sz) use -= sz; }
- unsigned used() { return use; }
-
-private:
- unsigned cap;
- unsigned use;
-};
-
// FIXIT-L some of this stuff can be better encapsulated
struct StreamGlobalConfig
uint8_t service_filter[MAX_PROTOCOL_ORDINAL];
};
-#if 0
-FIXIT-M delete?
-typedef struct
-{
- PegCount filtered;
- PegCount inspected;
- PegCount session_tracked;
-} tPortFilterStats;
-#endif
-
// shared stream state
-extern THREAD_LOCAL Memcap* tcp_memcap;
extern THREAD_LOCAL class FlowControl* flow_con;
extern const PegInfo base_pegs[];
void StreamTcp::show(SnortConfig*)
{
- tcp_show(config);
+ TcpSession::show(config);
}
bool StreamTcp::configure(SnortConfig*)
void tcp_tinit()
{
- tcp_sinit();
+ TcpSession::sinit();
}
void tcp_tterm()
{
- tcp_sterm();
+ TcpSession::sterm();
FlushBucket::clear();
}
#include "protocols/eth.h"
#include "network_inspectors/normalize/normalize.h"
#include "filters/sfrf.h"
+#include "flow/memcap.h"
using namespace tcp;
#define PAWS_WINDOW 60
#define PAWS_24DAYS 2073600 /* 24 days in seconds */
-/* for state transition queuing */
-#define CHK_SEQ 0
-#define NO_CHK_SEQ 1
-
#define STREAM_UNALIGNED 0
#define STREAM_ALIGNED 1
#define STREAM_INSERT_TIMEOUT 2
#define STREAM_INSERT_FAILED 3
-#define STREAM_DEFAULT_TCP_PACKET_MEMCAP 8388608 /* 8MB */
-#define STREAM_MIN_OVERLAP_LIMIT 0
-#define STREAM_MAX_OVERLAP_LIMIT 255
-#define STREAM_MAX_FLUSH_FACTOR 2048
-
/* target-based policy types */
// changes to this enum require changes to stream_api.h::TCP_POLICIES
#define STREAM_POLICY_FIRST 1
#define REASSEMBLY_POLICY_VISTA 13
#define REASSEMBLY_POLICY_DEFAULT REASSEMBLY_POLICY_BSD
-#define STREAM_MAX_MAX_WINDOW 0x3FFFc000 /* max window allowed by TCP */
-/* 65535 << 14 (max wscale) */
-#define STREAM_MIN_MAX_WINDOW 0
-
-#define MAX_PORTS_TO_PRINT 20
-
#define STREAM_DEFAULT_MAX_QUEUED_BYTES 1048576 /* 1 MB */
-#define STREAM_MIN_MAX_QUEUED_BYTES 1024 /* Don't let this go below 1024 */
-#define STREAM_MAX_MAX_QUEUED_BYTES 0x40000000 /* 1 GB, most we could reach within
- * largest window scale */
#define AVG_PKT_SIZE 400
#define STREAM_DEFAULT_MAX_QUEUED_SEGS (STREAM_DEFAULT_MAX_QUEUED_BYTES/AVG_PKT_SIZE)
-#define STREAM_MIN_MAX_QUEUED_SEGS 2 /* Don't let this go below 2 */
-#define STREAM_MAX_MAX_QUEUED_SEGS 0x40000000 /* 1 GB worth of one-byte segments */
#define STREAM_DEFAULT_MAX_SMALL_SEG_SIZE 0 /* disabled */
-#define STREAM_MAX_MAX_SMALL_SEG_SIZE 2048 /* 2048 bytes in single packet, uh, not small */
-#define STREAM_MIN_MAX_SMALL_SEG_SIZE 0 /* 0 means disabled */
-
#define STREAM_DEFAULT_CONSEC_SMALL_SEGS 0 /* disabled */
-#define STREAM_MAX_CONSEC_SMALL_SEGS 2048 /* 2048 single byte packets without acks is alot */
-#define STREAM_MIN_CONSEC_SMALL_SEGS 0 /* 0 means disabled */
#define SUB_SYN_SENT 0x01
#define SUB_ACK_SENT 0x02
snd->l_window = tdb->win;
}
-void tcp_sinit()
-{
- s5_pkt = PacketManager::encode_new();
- tcp_memcap = new Memcap(26214400); // FIXIT-M replace with session memcap
- //AtomSplitter::init(); // FIXIT-L PAF implement
-}
-
-void tcp_sterm()
-{
- if (s5_pkt)
- {
- PacketManager::encode_delete(s5_pkt);
- s5_pkt = nullptr;
- }
-
- delete tcp_memcap;
- tcp_memcap = nullptr;
-}
-
static inline void SetupTcpDataBlock(TcpDataBlock* tdb, Packet* p)
{
tdb->seq = ntohl(p->ptrs.tcph->th_seq);
// tcp module stuff
//-------------------------------------------------------------------------
-void tcp_show(StreamTcpConfig* tcp_config)
+void TcpSession::set_memcap(Memcap& mc)
+{
+ tcp_memcap = &mc;
+}
+
+void TcpSession::sinit()
+{
+ s5_pkt = PacketManager::encode_new();
+ //AtomSplitter::init(); // FIXIT-L PAF implement
+}
+
+void TcpSession::sterm()
+{
+ if (s5_pkt)
+ {
+ PacketManager::encode_delete(s5_pkt);
+ s5_pkt = nullptr;
+ }
+}
+
+void TcpSession::show(StreamTcpConfig* tcp_config)
{
StreamPrintTcpConfig(tcp_config);
}
TcpTracker client;
TcpTracker server;
+ static void set_memcap(class Memcap&);
+
+ static void sinit();
+ static void sterm();
+
+ static void show(StreamTcpConfig*);
+
#ifdef HAVE_DAQ_ADDRESS_SPACE_ID
int32_t ingress_index; /* Index of the inbound interface. */
int32_t egress_index; /* Index of the outbound interface. */
int process_dis(Packet*);
};
-void tcp_show(StreamTcpConfig*);
-
#endif