#include "protocols/packet.h"
#include "protocols/tcp.h"
#include "stream/flush_bucket.h"
+#include "stream/tcp/tcp_stream_tracker.h"
#include "stream_ha.h"
#include "stream_module.h"
if ( config.flow_cache_cfg.max_flows > 0 )
flow_con->init_exp(config.flow_cache_cfg.max_flows);
+ TcpStreamTracker::set_held_packet_timeout(config.held_packet_timeout);
+
#ifdef REG_TEST
FlushBucket::set(config.footprint);
#else
delete p;
}
+static void base_tinit()
+{
+ TcpStreamTracker::thread_init();
+}
+
static void base_tterm()
{
// this can't happen sooner because the counts haven't been harvested yet
delete flow_con;
flow_con = nullptr;
+ TcpStreamTracker::thread_term();
}
static const InspectApi base_api =
nullptr, // service
nullptr, // init
nullptr, // term
- nullptr, // tinit
+ base_tinit,
base_tterm,
base_ctor,
base_dtor,
#include "main/snort.h"
#include "main/snort_config.h"
#include "stream/flush_bucket.h"
+#include "stream/tcp/tcp_stream_tracker.h"
+#include "time/packet_time.h"
#include "trace/trace.h"
using namespace snort;
{ "pruning_timeout", Parameter::PT_INT, "1:max32", "30",
"minimum inactive time before being eligible for pruning" },
+ { "held_packet_timeout", Parameter::PT_INT, "1:max32", "1000",
+ "timeout in milliseconds for held packets" },
+
FLOW_TYPE_TABLE("ip_cache", "ip", ip_params),
FLOW_TYPE_TABLE("icmp_cache", "icmp", icmp_params),
FLOW_TYPE_TABLE("tcp_cache", "tcp", tcp_params),
config.flow_cache_cfg.pruning_timeout = v.get_uint32();
return true;
}
+ else if ( v.is("held_packet_timeout") )
+ {
+ config.held_packet_timeout = v.get_uint32();
+ return true;
+ }
else if ( strstr(fqn, "ip_cache") )
type = PktType::IP;
else if ( strstr(fqn, "icmp_cache") )
if ( reload_resource_manager.initialize(config) )
sc->register_reload_resource_tuner(reload_resource_manager);
+ if ( hpq_rrt.initialize(config.held_packet_timeout) )
+ sc->register_reload_resource_tuner(hpq_rrt);
+
return true;
}
{
int max_flows_change =
config.flow_cache_cfg.max_flows - flow_con->get_flow_cache_config().max_flows;
+
if ( max_flows_change )
{
if ( max_flows_change < 0 )
ConfigLogger::log_value(flow_type_names[i], tmp.c_str());
}
}
+
+bool HPQReloadTuner::initialize(uint32_t new_timeout_ms)
+{
+ held_packet_timeout = new_timeout_ms;
+ return Snort::is_reloading();
+}
+
+bool HPQReloadTuner::tinit()
+{
+ packet_gettimeofday(&reload_time);
+ return TcpStreamTracker::adjust_expiration(held_packet_timeout, reload_time);
+}
+
+bool HPQReloadTuner::tune_packet_context()
+{
+ return !TcpStreamTracker::release_held_packets(reload_time, max_work);
+}
+
+bool HPQReloadTuner::tune_idle_context()
+{
+ return !TcpStreamTracker::release_held_packets(reload_time, max_work_idle);
+}
#ifdef REG_TEST
unsigned footprint = 0;
#endif
+ uint32_t held_packet_timeout = 1000; // in milliseconds
void show() const;
};
StreamModuleConfig config;
};
+class HPQReloadTuner : public snort::ReloadResourceTuner
+{
+public:
+ HPQReloadTuner() = default;
+
+ bool tinit() override;
+ bool tune_packet_context() override;
+ bool tune_idle_context() override;
+ bool initialize(uint32_t new_timeout_ms);
+
+private:
+ uint32_t held_packet_timeout;
+ timeval reload_time;
+};
+
class StreamModule : public snort::Module
{
public:
private:
StreamModuleConfig config;
StreamReloadResourceManager reload_resource_manager;
+ HPQReloadTuner hpq_rrt;
};
extern void base_prep();
using namespace snort;
+void HeldPacket::adjust_expiration(const timeval& delta, bool up)
+{
+ timeval new_expiration;
+ if ( up )
+ timeradd(&expiration, &delta, &new_expiration);
+ else
+ timersub(&expiration, &delta, &new_expiration);
+ expiration = new_expiration;
+}
+
HeldPacket::HeldPacket(DAQ_Msg_h msg, uint32_t seq, const timeval& exp, TcpStreamTracker& trk)
: daq_msg(msg), seq_num(seq), expiration(exp), tracker(trk), expired(false)
{
q.erase(it);
}
-void HeldPacketQueue::execute(const timeval& cur_time, int max_remove)
+bool HeldPacketQueue::execute(const timeval& cur_time, int max_remove)
{
while ( !q.empty() && (max_remove < 0 || max_remove--) )
{
else
break;
}
+
+ return !q.empty() && q.front().has_expired(cur_time);
+}
+
+bool HeldPacketQueue::adjust_expiration(uint32_t new_timeout, const timeval& now)
+{
+ if ( q.empty() )
+ return false;
+
+ uint32_t ms;
+ bool up;
+
+ uint32_t old_timeout = get_timeout();
+ set_timeout(new_timeout);
+
+ if ( new_timeout < old_timeout )
+ {
+ ms = old_timeout - new_timeout;
+ up = false;
+ }
+ else if ( new_timeout > old_timeout )
+ {
+ ms = new_timeout - old_timeout;
+ up = true;
+ }
+ else
+ return false;
+
+ timeval delta = { static_cast<time_t>(ms) / 1000, static_cast<suseconds_t>((ms % 1000) * 1000) };
+
+ for ( auto& hp : q )
+ hp.adjust_expiration(delta, up);
+
+ return q.front().has_expired(now);
}
TcpStreamTracker& get_tracker() const { return tracker; }
DAQ_Msg_h get_daq_msg() const { return daq_msg; }
uint32_t get_seq_num() const { return seq_num; }
+ void adjust_expiration(const timeval& delta, bool up);
private:
DAQ_Msg_h daq_msg;
iter_t append(DAQ_Msg_h msg, uint32_t seq, TcpStreamTracker& trk);
void erase(iter_t it);
- void execute(const timeval& cur_time, int max_remove);
+
+ // Return whether there still are expired packets in the queue.
+ bool execute(const timeval& cur_time, int max_remove);
void set_timeout(uint32_t ms)
{
- timeout.tv_sec = ms / 1000;
- timeout.tv_usec = static_cast<suseconds_t>((ms % 1000) * 1000);
+ timeout = { static_cast<time_t>(ms) / 1000, static_cast<suseconds_t>((ms % 1000) * 1000) };
+ }
+
+ // Return the timeout in milliseconds.
+ uint32_t get_timeout() const
+ {
+ return timeout.tv_sec * 1000 + timeout.tv_usec / 1000;
}
+
bool empty() const { return q.empty(); }
+ // This must be called at reload time only, with now = reload time.
+ // Return true if, upon exit, there are expired packets in the queue.
+ bool adjust_expiration(uint32_t new_timeout_ms, const timeval& now);
+
private:
timeval timeout = {1, 0};
list_t q;
#include "tcp_session.h"
#include "tcp_reassemblers.h"
#include "tcp_state_machine.h"
-#include "tcp_stream_tracker.h"
using namespace snort;
void StreamTcp::tinit()
{
- TcpStreamTracker::set_held_packet_timeout(config->held_packet_timeout);
TcpHAManager::tinit();
TcpSession::sinit();
}
static void tcp_dtor(Inspector* p)
{ delete p; }
-static void stream_tcp_tinit()
-{
- TcpStreamTracker::thread_init();
-}
-
-static void stream_tcp_tterm()
-{
- TcpStreamTracker::thread_term();
-}
-
static void stream_tcp_pinit()
{
TcpStateMachine::initialize();
nullptr, // service
stream_tcp_pinit, // pinit
stream_tcp_pterm, // pterm
- stream_tcp_tinit, // tinit,
- stream_tcp_tterm, // tterm,
+ nullptr, // tinit,
+ nullptr, // tterm,
tcp_ctor,
tcp_dtor,
tcp_ssn,
{ "track_only", Parameter::PT_BOOL, nullptr, "false",
"disable reassembly if true" },
- { "held_packet_timeout", Parameter::PT_INT, "1:max32", "1000",
- "timeout in milliseconds for held packets" },
-
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
else
config->flags &= ~STREAM_CONFIG_NO_REASSEMBLY;
}
- else if ( v.is("held_packet_timeout") )
- {
- config->held_packet_timeout = v.get_uint32();
- }
else
return false;
int hs_timeout = -1;
bool no_ack;
-
- uint32_t held_packet_timeout = 1000; // in milliseconds
};
#endif
}
}
-void TcpStreamTracker::release_held_packets(const timeval& cur_time, int max_remove)
+bool TcpStreamTracker::release_held_packets(const timeval& cur_time, int max_remove)
{
+ bool is_front_expired = false;
if ( hpq )
- hpq->execute(cur_time, max_remove);
+ is_front_expired = hpq->execute(cur_time, max_remove);
+ return is_front_expired;
}
void TcpStreamTracker::set_held_packet_timeout(const uint32_t ms)
hpq->set_timeout(ms);
}
+bool TcpStreamTracker::adjust_expiration(uint32_t new_timeout_ms, const timeval& now)
+{
+ assert(hpq);
+ return hpq->adjust_expiration(new_timeout_ms, now);
+}
+
void TcpStreamTracker::thread_init()
{
assert(!hpq);
void finalize_held_packet(snort::Flow*);
uint32_t perform_partial_flush();
- // max_remove < 0 means time out all eligible packets
- static void release_held_packets(const timeval& cur_time, int max_remove);
+ // max_remove < 0 means time out all eligible packets.
+ // Return whether there are more packets that need to be released.
+ static bool release_held_packets(const timeval& cur_time, int max_remove);
static void set_held_packet_timeout(const uint32_t ms);
+ static bool adjust_expiration(uint32_t new_timeout_ms, const timeval& now);
static void thread_init();
static void thread_term();