#ifndef LATENCY_CONFIG_H
#define LATENCY_CONFIG_H
+#include "main/snort_debug.h"
+
#include "packet_latency_config.h"
#include "rule_latency_config.h"
RuleLatencyConfig rule_latency;
};
+extern snort::Trace latency_trace;
+
#endif
#define s_help \
"packet and rule latency monitoring and control"
+Trace latency_trace(s_name);
+
static const Parameter s_packet_params[] =
{
{ "max_time", Parameter::PT_INT, "0:max53", "500",
{ "fastpath", Parameter::PT_BOOL, nullptr, "false",
"fastpath expensive packets (max_time exceeded)" },
- { "action", Parameter::PT_ENUM, "none | alert | log | alert_and_log", "none",
- "event action if packet times out and is fastpathed" },
-
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
{ "max_suspend_time", Parameter::PT_INT, "0:max32", "30000",
"set max time for suspending a rule (ms, 0 means permanently disable rule)" },
- { "action", Parameter::PT_ENUM, "none | alert | log | alert_and_log", "none",
- "event action for rule latency enable and suspend events" },
-
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
else if ( v.is("fastpath") )
config.fastpath = v.get_bool();
- else if ( v.is("action") )
- config.action =
- static_cast<decltype(config.action)>(v.get_uint8());
else
return false;
long t = clock_ticks(v.get_uint32());
config.max_suspend_time = TO_DURATION(config.max_time, t);
}
- else if ( v.is("action") )
- config.action =
- static_cast<decltype(config.action)>(v.get_uint8());
else
return false;
}
LatencyModule::LatencyModule() :
- Module(s_name, s_help, s_params)
+ Module(s_name, s_help, s_params, false, &latency_trace)
{ }
bool LatencyModule::set(const char* fqn, Value& v, SnortConfig* sc)
else if ( !strncmp(fqn, slr, strlen(slr)) )
return latency_set(v, sc->latency->rule_latency);
- return false;
+ return Module::set(fqn, v, sc);
}
const RuleMap* LatencyModule::get_rules() const
static inline std::ostream& operator<<(std::ostream& os, const Event& e)
{
- os << "latency: " << e.packet->context->packet_number << " packet";
+ os << "packet " << e.packet->context->packet_number;
if ( e.fastpathed )
os << " fastpathed: ";
class Impl
{
public:
- Impl(const ConfigWrapper&, EventHandler&, EventHandler&);
+ Impl(const ConfigWrapper&, EventHandler&);
void push();
bool pop(const Packet*);
std::vector<PacketTimer<Clock>> timers;
const ConfigWrapper& config;
EventHandler& event_handler;
- EventHandler& log_handler;
};
template<typename Clock>
-inline Impl<Clock>::Impl(const ConfigWrapper& cfg, EventHandler& eh, EventHandler& lh) :
- config(cfg), event_handler(eh), log_handler(lh)
+inline Impl<Clock>::Impl(const ConfigWrapper& cfg, EventHandler& eh) :
+ config(cfg), event_handler(eh)
{ }
template<typename Clock>
// timer.mark implies fastpath-related timeout
Event e { p, timer.marked_as_fastpathed, timer.elapsed() };
- if ( config->action & PacketLatencyConfig::LOG )
- log_handler.handle(e);
-
- if ( config->action & PacketLatencyConfig::ALERT )
- event_handler.handle(e);
+ event_handler.handle(e);
}
elapsed = clock_usecs(TO_USECS(timer.elapsed()));
} config;
static struct SnortEventHandler : public EventHandler
-{
- void handle(const Event&) override
- { DetectionEngine::queue_event(GID_LATENCY, LATENCY_EVENT_PACKET_FASTPATHED); }
-} event_handler;
-
-static struct SnortLogHandler : public EventHandler
{
void handle(const Event& e) override
{
assert(e.packet);
std::ostringstream ss;
ss << e;
- LogMessage("%s\n", ss.str().c_str());
+ debug_logf(latency_trace, "%s\n", ss.str().c_str());
+
+ DetectionEngine::queue_event(GID_LATENCY, LATENCY_EVENT_PACKET_FASTPATHED);
}
-} log_handler;
+} event_handler;
static THREAD_LOCAL Impl<>* impl = nullptr;
static inline Impl<>& get_impl()
{
if ( !impl )
- impl = new Impl<>(config, event_handler, log_handler);
+ impl = new Impl<>(config, event_handler);
return *impl;
}
MockConfigWrapper config;
EventHandlerSpy event_handler;
- EventHandlerSpy log_handler;
MockClock::reset();
- packet_latency::Impl<MockClock> impl(config, event_handler, log_handler);
+ packet_latency::Impl<MockClock> impl(config, event_handler);
config.config.max_time = 2_ticks;
- config.config.action = PacketLatencyConfig::ALERT_AND_LOG;
-
SECTION( "fastpath enabled" )
{
config.config.fastpath = true;
CHECK( impl.pop(nullptr) );
CHECK( event_handler.count == 1 );
- CHECK( log_handler.count == 1 );
}
SECTION( "no timeout" )
CHECK_FALSE( impl.pop(nullptr) );
CHECK( event_handler.count == 0 );
- CHECK( log_handler.count == 0 );
}
}
CHECK( impl.pop(nullptr) );
CHECK( event_handler.count == 1 );
- CHECK( log_handler.count == 1 );
}
SECTION( "no timeout" )
CHECK_FALSE( impl.pop(nullptr) );
CHECK( event_handler.count == 0 );
- CHECK( log_handler.count == 0 );
}
}
}
struct PacketLatencyConfig
{
- enum Action
- {
- NONE = 0x00,
- ALERT = 0x01,
- LOG = 0x02,
- ALERT_AND_LOG = ALERT | LOG
- };
-
hr_duration max_time = CLOCK_ZERO;
bool fastpath = false;
- Action action = NONE;
bool enabled() const { return max_time > CLOCK_ZERO; }
};
using std::chrono::duration_cast;
using std::chrono::microseconds;
- os << "latency: " << e.packet->context->packet_number << " rule tree ";
+ os << "packet " << e.packet->context->packet_number << " rule tree ";
switch ( e.type )
{
class Impl
{
public:
- Impl(const ConfigWrapper&, EventHandler&, EventHandler&);
+ Impl(const ConfigWrapper&, EventHandler&);
bool push(detection_option_tree_root_t*, Packet*);
bool pop();
bool suspended() const;
private:
- void handle(const Event&);
-
std::vector<RuleTimer<Clock>> timers;
const ConfigWrapper& config;
EventHandler& event_handler;
- EventHandler& log_handler;
};
template<typename Clock, typename RuleTree>
-inline Impl<Clock, RuleTree>::Impl(const ConfigWrapper& cfg, EventHandler& eh, EventHandler& lh) :
- config(cfg), event_handler(eh), log_handler(lh)
+inline Impl<Clock, RuleTree>::Impl(const ConfigWrapper& cfg, EventHandler& eh) :
+ config(cfg), event_handler(eh)
{ }
template<typename Clock, typename RuleTree>
if ( RuleTree::reenable(*root, config->max_suspend_time, Clock::now()) )
{
Event e { Event::EVENT_ENABLED, config->max_suspend_time, root, p };
- handle(e);
+ event_handler.handle(e);
return true;
}
}
timer.elapsed(), timer.root, timer.packet
};
- handle(e);
+ event_handler.handle(e);
}
}
return RuleTree::is_suspended(*timers.back().root);
}
-template<typename Clock, typename RuleTree>
-inline void Impl<Clock, RuleTree>::handle(const Event& e)
-{
- if ( config->action & RuleLatencyConfig::LOG )
- log_handler.handle(e);
-
- if ( config->action & RuleLatencyConfig::ALERT )
- event_handler.handle(e);
-}
-
// -----------------------------------------------------------------------------
// static variables
// -----------------------------------------------------------------------------
{
void handle(const Event& e) override
{
+ std::ostringstream ss;
+ ss << e;
+ debug_logf(latency_trace, "%s\n", ss.str().c_str());
+
switch ( e.type )
{
case Event::EVENT_ENABLED:
}
} event_handler;
-static struct SnortLogHandler : public EventHandler
-{
- void handle(const Event& e) override
- {
- std::ostringstream ss;
- ss << e;
- LogMessage("%s\n", ss.str().c_str());
- }
-} log_handler;
-
static THREAD_LOCAL Impl<>* impl = nullptr;
// FIXIT-L this should probably be put in a tinit
static inline Impl<>& get_impl()
{
if ( !impl )
- impl = new Impl<>(config, event_handler, log_handler);
+ impl = new Impl<>(config, event_handler);
return *impl;
}
MockConfigWrapper config;
EventHandlerSpy event_handler;
- EventHandlerSpy log_handler;
MockClock::reset();
RuleInterfaceSpy::reset();
- config.config.action = RuleLatencyConfig::ALERT_AND_LOG;
-
detection_option_tree_root_t root;
Packet pkt(false);
- rule_latency::Impl<MockClock, RuleInterfaceSpy> impl(config, event_handler, log_handler);
+ rule_latency::Impl<MockClock, RuleInterfaceSpy> impl(config, event_handler);
SECTION( "push" )
{
SECTION( "push rule" )
{
CHECK_FALSE( impl.push(&root, &pkt) );
- CHECK( log_handler.count == 0 );
CHECK( event_handler.count == 0 );
CHECK( RuleInterfaceSpy::reenable_called );
}
RuleInterfaceSpy::reenable_result = true;
CHECK( impl.push(&root, &pkt) );
- CHECK( log_handler.count == 1 );
CHECK( event_handler.count == 1 );
CHECK( RuleInterfaceSpy::reenable_called );
}
SECTION( "push rule" )
{
CHECK_FALSE( impl.push(&root, &pkt) );
- CHECK( log_handler.count == 0 );
CHECK( event_handler.count == 0 );
CHECK_FALSE( RuleInterfaceSpy::reenable_called );
}
RuleInterfaceSpy::is_suspended_result = true;
CHECK_FALSE( impl.pop() );
- CHECK( log_handler.count == 0 );
CHECK( event_handler.count == 0 );
CHECK_FALSE( RuleInterfaceSpy::timeout_and_suspend_called );
}
RuleInterfaceSpy::timeout_and_suspend_result = true;
CHECK( impl.pop() );
- CHECK( log_handler.count == 1 );
CHECK( event_handler.count == 1 );
CHECK( RuleInterfaceSpy::timeout_and_suspend_called );
}
RuleInterfaceSpy::timeout_and_suspend_result = false;
CHECK( impl.pop() );
- CHECK( log_handler.count == 1 );
CHECK( event_handler.count == 1 );
CHECK( RuleInterfaceSpy::timeout_and_suspend_called );
}
RuleInterfaceSpy::is_suspended_result = false;
CHECK_FALSE( impl.pop() );
- CHECK( log_handler.count == 0 );
CHECK( event_handler.count == 0 );
CHECK_FALSE( RuleInterfaceSpy::timeout_and_suspend_called );
}
struct RuleLatencyConfig
{
- enum Action
- {
- NONE = 0x00,
- ALERT = 0x01,
- LOG = 0x02,
- ALERT_AND_LOG = ALERT | LOG
- };
-
hr_duration max_time = 0_ticks;
bool suspend = false;
unsigned suspend_threshold = 0;
hr_duration max_suspend_time = 0_ticks;
- Action action = NONE;
bool enabled() const { return max_time > 0_ticks; }
bool allow_reenable() const { return max_suspend_time > 0_ticks; }
while (data_stream >> keyword)
{
bool tmpval = true;
- bool popped_comma;
-
+ bool popped_comma = false;
if (keyword.back() == ',')
{
keyword.pop_back();
popped_comma = true;
}
- else
- {
- popped_comma = false;
- }
if (keyword.empty())
continue;
table_api.close_table();
}
- else if (keyword == "pkt-log")
- {
- table_api.add_diff_option_comment("pkt-log", "packet.action");
- table_api.open_table("packet");
-
- std::string opt1;
- std::string opt2;
-
- if (popped_comma)
- table_api.add_option("action", "log");
-
- else if (!(data_stream >> opt1))
- table_api.add_option("action", "log");
-
- else if (opt1.back() == ',')
- {
- opt1.pop_back();
- tmpval = table_api.add_option("action", opt1);
- }
-
- else if (!(data_stream >> opt2))
- tmpval = table_api.add_option("action", opt1);
-
- else
- {
- table_api.add_diff_option_comment("'both'", "'alert_and_log'");
- tmpval = table_api.add_option("action", "alert_and_log");
- }
-
- table_api.close_table();
- }
-
- else if (keyword == "rule-log")
+ else if ((keyword == "pkt-log") or (keyword == "rule-log"))
{
- table_api.add_diff_option_comment("rule-log", "rule.action");
- table_api.open_table("rule");
-
- std::string opt1;
- std::string opt2;
-
- if (!(data_stream >> opt1))
- tmpval = false;
-
- else if (opt1.back() == ',')
+ table_api.add_deleted_comment(keyword);
+ if (!popped_comma)
{
- opt1.pop_back();
- tmpval = table_api.add_option("action", opt1);
+ while ((data_stream >> keyword) && (keyword.back() != ','));
}
-
- else if (!(data_stream >> opt2))
- tmpval = table_api.add_option("action", opt1);
-
- else
- {
- table_api.add_diff_option_comment("'both'", "'alert_and_log'");
- tmpval = table_api.add_option("action", "alert_and_log");
- }
-
- table_api.close_table();
}
-
else
tmpval = false;