react = { }
reject = { }
- rewrite = { }
+
+When these active responses are not configured the default configuration
+is used.
Active responses will be performed for reject, react or rewrite IPS rule
actions, and response packets are encoded based on the triggering packet.
For example:
- rewrite = { }
local_rules =
[[
rewrite tcp 10.1.1.87 any -> 10.1.1.0/24 80
this rule replaces "index.php" with "indax.php", and rewrite action
updates that packet.
-
-to enable rewrite action:
-
- rewrite = { }
-
-the replace operation can be disabled by changing the configuration:
-
- rewrite = { disable_replace = true }
-
variables = default_variables
}
-rewrite = { }
-
-- use these to configure additional rule actions
-- react = { }
-- reject = { }
actions.cc
ips_actions.cc
ips_actions.h
+ act_alert.cc
+ act_block.cc
+ act_drop.cc
+ act_log.cc
+ act_pass.cc
+ act_reject.cc
act_replace.cc
)
set( PLUGIN_LIST
act_react.cc
- act_reject.cc
)
if (STATIC_IPS_ACTIONS)
)
add_dynamic_module(act_react ips_actions act_react.cc)
- add_dynamic_module(act_reject ips_actions act_reject.cc)
endif (STATIC_IPS_ACTIONS)
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2021-2021 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.
+//--------------------------------------------------------------------------
+// act_alert.cc author Bhagya Tholpady <bbantwal@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "framework/ips_action.h"
+#include "framework/module.h"
+#include "protocols/packet.h"
+
+#include "actions.h"
+
+using namespace snort;
+
+#define s_name "alert"
+
+#define s_help \
+ "generate alert on the current packet"
+
+//-------------------------------------------------------------------------
+class AlertAction : public IpsAction
+{
+public:
+ AlertAction() : IpsAction(s_name, nullptr) { }
+
+ void exec(Packet*, const OptTreeNode* otn) override;
+};
+
+void AlertAction::exec(Packet* p, const OptTreeNode* otn)
+{
+ if ( otn )
+ Actions::alert(p, otn);
+}
+
+//-------------------------------------------------------------------------
+
+static IpsAction* alert_ctor(Module*)
+{ return new AlertAction; }
+
+static void alert_dtor(IpsAction* p)
+{ delete p; }
+
+static ActionApi alert_api
+{
+ {
+ PT_IPS_ACTION,
+ sizeof(ActionApi),
+ ACTAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ s_name,
+ s_help,
+ nullptr, // mod_ctor
+ nullptr, // mod_dtor
+ },
+ IpsAction::IAP_ALERT,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ alert_ctor,
+ alert_dtor
+};
+
+const BaseApi* act_alert[] =
+{
+ &alert_api.base,
+ nullptr
+};
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2021-2021 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.
+//--------------------------------------------------------------------------
+// act_block.cc author Bhagya Tholpady <bbantwal@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "framework/ips_action.h"
+#include "framework/module.h"
+#include "packet_io/active.h"
+#include "protocols/packet.h"
+
+#include "actions.h"
+
+using namespace snort;
+
+#define s_name "block"
+
+#define s_help \
+ "block current packet and all the subsequent packets in this flow"
+
+//-------------------------------------------------------------------------
+class BlockAction : public IpsAction
+{
+public:
+ BlockAction() : IpsAction(s_name, nullptr) { }
+
+ void exec(Packet*, const OptTreeNode* otn) override;
+ bool drops_traffic() override { return true; }
+};
+
+void BlockAction::exec(Packet* p, const OptTreeNode* otn)
+{
+ p->active->block_session(p);
+ p->active->set_drop_reason("ips");
+ if ( otn )
+ Actions::alert(p, otn);
+}
+
+//-------------------------------------------------------------------------
+
+static IpsAction* block_ctor(Module*)
+{ return new BlockAction; }
+
+static void block_dtor(IpsAction* p)
+{ delete p; }
+
+static ActionApi block_api
+{
+ {
+ PT_IPS_ACTION,
+ sizeof(ActionApi),
+ ACTAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ s_name,
+ s_help,
+ nullptr, // mod_ctor
+ nullptr, // mod_dtor
+ },
+ IpsAction::IAP_BLOCK,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ block_ctor,
+ block_dtor
+};
+
+const BaseApi* act_block[] =
+{
+ &block_api.base,
+ nullptr
+};
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2021-2021 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.
+//--------------------------------------------------------------------------
+// act_drop.cc author Bhagya Tholpady <bbantwal@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "framework/ips_action.h"
+#include "framework/module.h"
+#include "packet_io/active.h"
+#include "protocols/packet.h"
+
+#include "actions.h"
+
+using namespace snort;
+
+#define s_name "drop"
+
+#define s_help \
+ "drop the current packet"
+
+//-------------------------------------------------------------------------
+class DropAction : public IpsAction
+{
+public:
+ DropAction() : IpsAction(s_name, nullptr) { }
+
+ void exec(Packet*, const OptTreeNode* otn) override;
+ bool drops_traffic() override { return true; }
+};
+
+void DropAction::exec(Packet* p, const OptTreeNode* otn)
+{
+ p->active->drop_packet(p);
+ p->active->set_drop_reason("ips");
+ if ( otn )
+ Actions::alert(p, otn);
+}
+
+//-------------------------------------------------------------------------
+
+static IpsAction* drop_ctor(Module*)
+{ return new DropAction; }
+
+static void drop_dtor(IpsAction* p)
+{ delete p; }
+
+static ActionApi drop_api
+{
+ {
+ PT_IPS_ACTION,
+ sizeof(ActionApi),
+ ACTAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ s_name,
+ s_help,
+ nullptr, // mod_ctor
+ nullptr, // mod_dtor
+ },
+ IpsAction::IAP_DROP,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ drop_ctor,
+ drop_dtor
+};
+
+const BaseApi* act_drop[] =
+{
+ &drop_api.base,
+ nullptr
+};
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2021-2021 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.
+//--------------------------------------------------------------------------
+// act_log.cc author Bhagya Tholpady <bbantwal@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "framework/ips_action.h"
+#include "framework/module.h"
+#include "protocols/packet.h"
+
+#include "actions.h"
+
+using namespace snort;
+
+#define s_name "log"
+
+#define s_help \
+ "log the current packet"
+
+//-------------------------------------------------------------------------
+class LogAction : public IpsAction
+{
+public:
+ LogAction() : IpsAction(s_name, nullptr) { }
+
+ void exec(Packet*, const OptTreeNode* otn) override;
+};
+
+void LogAction::exec(Packet* p, const OptTreeNode* otn)
+{
+ if ( otn )
+ Actions::log(p, otn);
+}
+
+//-------------------------------------------------------------------------
+
+static IpsAction* log_ctor(Module*)
+{ return new LogAction; }
+
+static void log_dtor(IpsAction* p)
+{ delete p; }
+
+static ActionApi log_api
+{
+ {
+ PT_IPS_ACTION,
+ sizeof(ActionApi),
+ ACTAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ s_name,
+ s_help,
+ nullptr, // mod_ctor
+ nullptr, // mod_dtor
+ },
+ IpsAction::IAP_LOG,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ log_ctor,
+ log_dtor
+};
+
+const BaseApi* act_log[] =
+{
+ &log_api.base,
+ nullptr
+};
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2021-2021 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.
+//--------------------------------------------------------------------------
+// act_pass.cc author Bhagya Tholpady <bbantwal@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "framework/ips_action.h"
+#include "framework/module.h"
+#include "protocols/packet.h"
+
+#include "actions.h"
+
+using namespace snort;
+
+#define s_name "pass"
+
+#define s_help \
+ "mark the current packet as passed"
+
+//-------------------------------------------------------------------------
+class PassAction : public IpsAction
+{
+public:
+ PassAction() : IpsAction(s_name, nullptr) { }
+
+ void exec(Packet*, const OptTreeNode*) override;
+};
+
+void PassAction::exec(Packet* p, const OptTreeNode* otn)
+{
+ if ( otn )
+ {
+ Actions::pass();
+ p->packet_flags |= PKT_PASS_RULE;
+ }
+}
+
+//-------------------------------------------------------------------------
+
+static IpsAction* pass_ctor(Module*)
+{ return new PassAction; }
+
+static void pass_dtor(IpsAction* p)
+{ delete p; }
+
+static ActionApi pass_api
+{
+ {
+ PT_IPS_ACTION,
+ sizeof(ActionApi),
+ ACTAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ s_name,
+ s_help,
+ nullptr, // mod_ctor
+ nullptr, // mod_dtor
+ },
+ IpsAction::IAP_PASS,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ pass_ctor,
+ pass_dtor
+};
+
+const BaseApi* act_pass[] =
+{
+ &pass_api.base,
+ nullptr
+};
+
#include "utils/util.h"
#include "utils/util_cstring.h"
+#include "actions.h"
+
using namespace snort;
using namespace HttpCommon;
using namespace Http2Enums;
"</body>\r\n" \
"</html>\r\n"
-THREAD_LOCAL const snort::Trace* react_trace = nullptr;
+THREAD_LOCAL const Trace* react_trace = nullptr;
class ReactData
{
std::string resp_buf; // response to send
};
-class ReactAction : public snort::IpsAction
+//-------------------------------------------------------------------------
+// active action
+//-------------------------------------------------------------------------
+
+class ReactActiveAction : public ActiveAction
{
public:
- ReactAction(ReactData* c)
- : IpsAction(s_name, ActionType::ACT_PROXY), config(c)
+ ReactActiveAction(ReactData* c)
+ : ActiveAction( ActionPriority::AP_PROXY ), config(c)
{ }
- ~ReactAction() override
- { delete config; }
+ void delayed_exec(Packet* p) override;
- void exec(snort::Packet* p) override
- {
- Profile profile(reactPerfStats);
+private:
+ void send(Packet* p);
+ ReactData* config;
+};
- if ( p->active->is_reset_candidate(p) )
- send(p);
- }
+void ReactActiveAction::delayed_exec(Packet* p)
+{
+ Profile profile(reactPerfStats);
-private:
- void send(snort::Packet* p)
+ if ( p->active->is_reset_candidate(p) )
+ send(p);
+}
+
+void ReactActiveAction::send(Packet* p)
+{
+ InjectionControl control;
+ control.http_page = (const uint8_t*)config->get_resp_buf();
+ control.http_page_len = config->get_buf_len();
+ if (p->flow && p->flow->gadget &&
+ (strcmp(p->flow->gadget->get_name(), "http2_inspect") == 0))
{
- InjectionControl control;
- control.http_page = (const uint8_t*)config->get_resp_buf();
- control.http_page_len = config->get_buf_len();
- if (p->flow && p->flow->gadget &&
- (strcmp(p->flow->gadget->get_name(), "http2_inspect") == 0))
+ Http2FlowData* const session_data =
+ (Http2FlowData*)p->flow->get_flow_data(Http2FlowData::inspector_id);
+ assert(session_data != nullptr);
+ const SourceId source_id = p->is_from_client() ? SRC_CLIENT : SRC_SERVER;
+ if (session_data != nullptr)
{
- Http2FlowData* const session_data =
- (Http2FlowData*)p->flow->get_flow_data(Http2FlowData::inspector_id);
- assert(session_data != nullptr);
- const SourceId source_id = p->is_from_client() ? SRC_CLIENT : SRC_SERVER;
- if (session_data != nullptr)
- {
- control.stream_id = session_data->get_current_stream_id(source_id);
- assert(control.stream_id != NO_STREAM_ID);
- }
+ control.stream_id = session_data->get_current_stream_id(source_id);
+ assert(control.stream_id != NO_STREAM_ID);
}
- InjectionReturnStatus status = PayloadInjector::inject_http_payload(p, control);
+ }
+ InjectionReturnStatus status = PayloadInjector::inject_http_payload(p, control);
#ifdef DEBUG_MSGS
- if (status != INJECTION_SUCCESS)
- debug_logf(react_trace, p, "Injection error: %s\n",
- PayloadInjector::get_err_string(status));
+ if (status != INJECTION_SUCCESS)
+ debug_logf(react_trace, p, "Injection error: %s\n",
+ PayloadInjector::get_err_string(status));
#else
- UNUSED(status);
+ UNUSED(status);
#endif
- }
+}
+
+//-------------------------------------------------------------------------
+// ips action
+//-------------------------------------------------------------------------
+
+class ReactAction : public IpsAction
+{
+public:
+ ReactAction(ReactData* c)
+ : IpsAction(s_name, &react_act_action), config(c), react_act_action(c)
+ { }
+
+ ~ReactAction() override
+ { delete config; }
+
+ void exec(Packet*, const OptTreeNode* otn) override;
+ bool drops_traffic() override { return true; }
private:
ReactData* config;
+ ReactActiveAction react_act_action;
};
+void ReactAction::exec(Packet* p, const OptTreeNode* otn)
+{
+ p->active->drop_packet(p);
+ p->active->set_drop_reason("ips");
+ if ( otn )
+ Actions::alert(p, otn);
+}
+
//-------------------------------------------------------------------------
// module
//-------------------------------------------------------------------------
Usage get_usage() const override
{ return DETECT; }
- void set_trace(const snort::Trace* trace) const override
+ void set_trace(const Trace* trace) const override
{ react_trace = trace; }
- const snort::TraceOption* get_trace_options() const override
+ const TraceOption* get_trace_options() const override
{
static const TraceOption react_trace_options(nullptr, 0, nullptr);
return &react_trace_options;
}
-public:
- std::string page;
+ std::string get_data();
private:
+ std::string page;
bool getpage(const char* file);
};
return true;
}
-bool ReactModule::begin(const char*, int, SnortConfig* sc)
+bool ReactModule::begin(const char*, int, SnortConfig*)
{
page.clear();
- sc->set_active_enabled();
return true;
}
return true;
}
+std::string ReactModule::get_data()
+{
+ std::string tmp = page;
+ page.clear();
+ return tmp;
+}
+
//-------------------------------------------------------------------------
// api methods
//-------------------------------------------------------------------------
static IpsAction* react_ctor(Module* p)
{
- ReactModule* m = (ReactModule*)p;
- ReactData* rd = new ReactData(m->page);
+ std::string react_page;
+ if ( p )
+ {
+ ReactModule* m = (ReactModule*)p;
+ react_page = m->get_data();
+ }
- return new ReactAction(rd);
+ return new ReactAction(new ReactData(react_page));
}
static void react_dtor(IpsAction* p)
mod_ctor,
mod_dtor
},
- Actions::DROP,
+ IpsAction::IpsActionPriority(IpsAction::IAP_DROP + 1),
nullptr, // pinit
nullptr, // pterm
nullptr, // tinit
#include "packet_io/active.h"
#include "profiler/profiler.h"
+#include "actions.h"
+
using namespace snort;
#define s_name "reject"
THREAD_LOCAL ProfileStats rejPerfStats;
-class RejectAction : public snort::IpsAction
+//-------------------------------------------------------------------------
+// active action
+//-------------------------------------------------------------------------
+
+class RejectActiveAction : public ActiveAction
{
public:
- RejectAction(uint32_t f);
- void exec(snort::Packet*) override;
+ RejectActiveAction(uint32_t f) : ActiveAction (ActionPriority::AP_RESET) , mask(f) { }
+ void delayed_exec(Packet*) override;
private:
uint32_t mask;
};
-//-------------------------------------------------------------------------
-// class methods
-//-------------------------------------------------------------------------
-
-RejectAction::RejectAction(uint32_t f) : IpsAction(s_name, ActionType::ACT_RESET), mask(f)
-{ }
-
-
-void RejectAction::exec(Packet* p)
+void RejectActiveAction::delayed_exec(Packet* p)
{
if ( !p->ptrs.ip_api.is_ip() )
return;
act->send_unreach(p, UnreachResponse::PORT);
}
+//-------------------------------------------------------------------------
+// ips action
+//-------------------------------------------------------------------------
+
+class RejectAction : public IpsAction
+{
+public:
+ RejectAction(uint32_t f = REJ_RST_BOTH);
+
+ void exec(Packet*, const OptTreeNode* otn) override;
+
+private:
+ RejectActiveAction rej_act_action;
+};
+
+//-------------------------------------------------------------------------
+// class methods
+//-------------------------------------------------------------------------
+
+RejectAction::RejectAction(uint32_t f) : IpsAction(s_name, &rej_act_action) , rej_act_action(f)
+{ }
+
+void RejectAction::exec(Packet* p, const OptTreeNode* otn)
+{
+ p->active->reset_session(p, get_active_action());
+ if ( otn )
+ Actions::alert(p, otn);
+}
+
//-------------------------------------------------------------------------
// module
//-------------------------------------------------------------------------
Usage get_usage() const override
{ return DETECT; }
-public:
+ uint32_t get_data();
+
+private:
uint32_t flags;
};
-bool RejectModule::begin(const char*, int, SnortConfig* sc)
+bool RejectModule::begin(const char*, int, SnortConfig*)
{
flags = 0;
- sc->set_active_enabled();
return true;
}
return true;
}
+uint32_t RejectModule::get_data()
+{
+ return flags;
+}
+
//-------------------------------------------------------------------------
// api methods
//-------------------------------------------------------------------------
static IpsAction* rej_ctor(Module* p)
{
- RejectModule* m = (RejectModule*)p;
- return new RejectAction(m->flags);
+ if ( p )
+ {
+ RejectModule* m = (RejectModule*)p;
+ return new RejectAction(m->get_data());
+ }
+ else
+ return new RejectAction();
}
static void rej_dtor(IpsAction* p)
mod_ctor,
mod_dtor
},
- Actions::RESET,
+ IpsAction::IAP_REJECT,
nullptr,
nullptr,
nullptr,
rej_dtor
};
-#ifdef BUILDING_SO
-SO_PUBLIC const BaseApi* snort_plugins[] =
-#else
const BaseApi* act_reject[] =
-#endif
{
&rej_api.base,
nullptr
#include "detection/detection_engine.h"
#include "framework/ips_action.h"
#include "framework/module.h"
-#include "main/snort_config.h"
#include "packet_io/active.h"
#include "protocols/packet.h"
+#include "actions.h"
+
using namespace snort;
#define s_name "rewrite"
}
//-------------------------------------------------------------------------
-// replace module
+// active action
//-------------------------------------------------------------------------
-
-static const Parameter s_params[] =
-{
- { "disable_replace", Parameter::PT_BOOL, nullptr, "false",
- "disable replace of packet contents with rewrite rules" },
-
- { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
-};
-
-class ReplaceModule : public Module
+class ReplaceActiveAction : public ActiveAction
{
public:
- ReplaceModule() : Module(s_name, s_help, s_params) { }
- bool set(const char*, Value&, SnortConfig*) override;
- bool begin(const char*, int, SnortConfig*) override;
-
- Usage get_usage() const override
- { return DETECT; }
-
-public:
- bool disable_replace;
+ ReplaceActiveAction() : ActiveAction(ActionPriority::AP_MODIFY) { }
+ void delayed_exec(Packet*) override;
};
-bool ReplaceModule::set(const char*, Value& v, SnortConfig*)
+void ReplaceActiveAction::delayed_exec(Packet* p)
{
- if ( v.is("disable_replace") )
- disable_replace = v.get_bool();
- else
- return false;
-
- return true;
-}
+ if ( p->is_rebuilt() )
+ return;
-bool ReplaceModule::begin(const char*, int, SnortConfig* sc)
-{
- disable_replace = false;
- sc->set_active_enabled();
- return true;
+ Replace_ModifyPacket(p);
}
//-------------------------------------------------------------------------
-class ReplaceAction : public snort::IpsAction
+// ips action
+//-------------------------------------------------------------------------
+class ReplaceAction : public IpsAction
{
public:
- ReplaceAction(bool disable_replace);
+ ReplaceAction() : IpsAction(s_name, &rep_act_action) { }
+
+ void exec(Packet*, const OptTreeNode* otn) override;
- void exec(snort::Packet*) override;
private:
- bool disable_replace = false;
+ ReplaceActiveAction rep_act_action;
};
-ReplaceAction::ReplaceAction(bool dr) :
- IpsAction(s_name, ACT_RESET)
+void ReplaceAction::exec(Packet* p, const OptTreeNode* otn)
{
- disable_replace = dr;
-}
-
-void ReplaceAction::exec(Packet* p)
-{
- if ( p->is_rebuilt() || disable_replace )
- return;
-
- Replace_ModifyPacket(p);
+ Actions::alert(p, otn);
}
//-------------------------------------------------------------------------
-static Module* mod_ctor()
-{ return new ReplaceModule; }
-
-static void mod_dtor(Module* m)
-{ delete m; }
-
-static IpsAction* rep_ctor(Module* m)
-{ return new ReplaceAction( ((ReplaceModule*)m)->disable_replace); }
+static IpsAction* rep_ctor(Module*)
+{ return new ReplaceAction; }
static void rep_dtor(IpsAction* p)
{ delete p; }
API_OPTIONS,
s_name,
s_help,
- mod_ctor,
- mod_dtor
+ nullptr, // mod_ctor
+ nullptr, // mod_dtor
},
- Actions::ALERT,
+ IpsAction::IAP_REWRITE,
nullptr,
nullptr,
nullptr,
rep_dtor
};
-#ifdef BUILDING_SO
-SO_PUBLIC const BaseApi* snort_plugins[] =
-#else
const BaseApi* act_replace[] =
-#endif
{
&rep_api.base,
nullptr
#include "actions.h"
#include "detection/detect.h"
-#include "detection/tag.h"
-#include "packet_io/active.h"
-#include "packet_io/active_action.h"
+#include "managers/action_manager.h"
#include "parser/parser.h"
#include "utils/stats.h"
using namespace snort;
-static void pass()
+void Actions::pass()
{
pc.pass_pkts++;
}
-static void log(Packet* p, const OptTreeNode* otn)
+void Actions::log(Packet* p, const OptTreeNode* otn)
{
RuleTreeNode* rtn = getRuntimeRtnFromOtn(otn);
CallLogFuncs(p, otn, rtn->listhead);
}
-static void alert(Packet* p, const OptTreeNode* otn)
+void Actions::alert(Packet* p, const OptTreeNode* otn)
{
RuleTreeNode* rtn = getRuntimeRtnFromOtn(otn);
CallLogFuncs(p, otn, rtn->listhead);
}
-static const char* const type[Actions::MAX] =
+std::string Actions::get_string(Actions::Type action)
{
- "none", "log", "pass", "alert", "drop", "block", "reset"
-};
-
-const char* Actions::get_string(Actions::Type action)
-{
- if ( action < Actions::MAX )
- return type[action];
-
- return "ERROR";
+ return ActionManager::get_action_string(action);
}
Actions::Type Actions::get_type(const char* s)
{
- if ( !s )
- return Actions::NONE;
-
- else if ( !strcasecmp(s, Actions::get_string(Actions::LOG)) )
- return Actions::LOG;
-
- else if ( !strcasecmp(s, Actions::get_string(Actions::PASS)) )
- return Actions::PASS;
-
- else if ( !strcasecmp(s, Actions::get_string(Actions::ALERT)) )
- return Actions::ALERT;
-
- else if ( !strcasecmp(s, Actions::get_string(Actions::DROP)) )
- return Actions::DROP;
-
- else if ( !strcasecmp(s, Actions::get_string(Actions::BLOCK)) )
- return Actions::BLOCK;
-
- else if ( !strcasecmp(s, Actions::get_string(Actions::RESET)) )
- return Actions::RESET;
-
- return Actions::NONE;
+ return ActionManager::get_action_type(s);
}
-void Actions::execute(Actions::Type action, Packet* p, const OptTreeNode* otn,
- uint16_t event_id)
+Actions::Type Actions::get_max_types()
{
- switch (action)
- {
- case Actions::PASS:
- pass();
- SetTags(p, otn, event_id);
- break;
-
- case Actions::ALERT:
- alert(p, otn);
- SetTags(p, otn, event_id);
- break;
-
- case Actions::LOG:
- log(p, otn);
- SetTags(p, otn, event_id);
- break;
-
- case Actions::DROP:
- p->active->drop_packet(p);
- p->active->set_drop_reason("ips");
- alert(p, otn);
- SetTags(p, otn, event_id);
- break;
-
- case Actions::BLOCK:
- p->active->block_session(p);
- p->active->set_drop_reason("ips");
- alert(p, otn);
- SetTags(p, otn, event_id);
- break;
-
- case Actions::RESET:
- p->active->reset_session(p, get_ips_policy()->action[action]);
- alert(p, otn);
- SetTags(p, otn, event_id);
- break;
-
- default:
- break;
- }
+ return ActionManager::get_max_action_types();
}
-void Actions::apply(Actions::Type action, Packet* p)
+bool Actions::is_valid_action(Actions::Type action)
{
- switch ( action )
- {
- case Actions::DROP:
- p->active->drop_packet(p);
- break;
-
- case Actions::BLOCK:
- p->active->block_session(p);
- break;
-
- case Actions::RESET:
- p->active->reset_session(p, get_ips_policy()->action[action]);
- break;
+ if ( action < get_max_types() )
+ return true;
- default:
- break;
- }
+ return false;
}
+std::string Actions::get_default_priorities(bool alert_before_pass)
+{
+ return ActionManager::get_action_priorities(alert_before_pass);
+}
// Define action types and provide hooks to apply a given action to a packet
#include <cstdint>
+#include <string>
#include "main/snort_types.h"
namespace snort
{
struct Packet;
+}
class SO_PUBLIC Actions
{
public:
- // FIXIT-L if Type is changed, RateFilterModule and type in actions.cc must be updated
- enum Type : uint8_t
- { NONE = 0, LOG, PASS, ALERT, DROP, BLOCK, RESET, MAX };
-
- static const char* get_string(Type);
+ using Type = uint8_t;
+public:
+ static std::string get_string(Type);
static Type get_type(const char*);
+ static Type get_max_types();
+ static bool is_valid_action(Type);
+ static std::string get_default_priorities(bool alert_before_pass = false);
- static void execute(Type, struct Packet*, const struct OptTreeNode*,
- uint16_t event_id);
-
- static void apply(Type, struct Packet*);
-
- static inline bool is_pass(Type a)
- { return ( a == PASS ); }
+ static void pass();
+ static void log(snort::Packet*, const OptTreeNode*);
+ static void alert(snort::Packet*, const OptTreeNode*);
};
-}
#endif
-IPS actions allow you to execute custom responses to events.
-Unlike loggers, these are invoked before thresholding and can be used to
-control external agents (including loggers).
+IPS actions allow you to execute custom responses to events. Unlike loggers,
+these are invoked before thresholding and can be used to control external agents
+(including loggers).
IPS rules have an associated type that determines what kind of action they
trigger. The rule types defined in this module are:
-* log
-* pass
-* alert
-* drop
-* block
-* reset
-
-There is also a "none" rule type, which is a no-op.
+* log pass alert drop block
It also defines 3 active responses:
-* react
-* reject
-* rewrite
+* react reject rewrite
+
+Reject performs active response to shutdown hostile network session by injecting
+TCP resets (TCP connections) or ICMP unreachable packets.
+
+React sends an HTML page to the client, a RST to the server and blocks the flow.
+It is using payload_injector utilty. payload_injector should be configured when
+react is used.
+
+Rewrite enables overwrite packet contents based on "replace" option in the
+rules.
-Reject performs active response to shutdown hostile network
-session by injecting TCP resets (TCP connections) or ICMP unreachable
-packets.
+Ips actions are all pluggable and implemented as subclasses of IpsAction action.
+Each ips action instance has an instance of the active action that is used to
+perform the active response.
-React sends an HTML page to the client, a RST to the server
-and blocks the flow. It is using payload_injector utilty.
-payload_injector should be configured when react is used.
+IpsAction::exec represents the action taken by the ips actions after rule
+evaluation during packet processing. This may include logging, alerting marking
+the packet as passed, etc. IpsActions::exec when called without the otn will do
+the active action such as drop/block/reset without alerting/logging or marking
+the packet as passed.
-Rewrite enables overwrite packet contents based on "replace"
-option in the rules.
+ActiveAction::delayed_exec is called during the post processing of a packet to
+send active responses.
#ifdef STATIC_IPS_ACTIONS
extern const BaseApi* act_react[];
-extern const BaseApi* act_reject[];
#endif
+extern const BaseApi* act_alert[];
+extern const BaseApi* act_block[];
+extern const BaseApi* act_drop[];
+extern const BaseApi* act_log[];
+extern const BaseApi* act_pass[];
+extern const BaseApi* act_reject[];
extern const BaseApi* act_replace[];
void load_actions()
{
#ifdef STATIC_IPS_ACTIONS
PluginManager::load_plugins(act_react);
- PluginManager::load_plugins(act_reject);
#endif
+ PluginManager::load_plugins(act_alert);
+ PluginManager::load_plugins(act_block);
+ PluginManager::load_plugins(act_drop);
+ PluginManager::load_plugins(act_log);
+ PluginManager::load_plugins(act_pass);
+ PluginManager::load_plugins(act_reject);
PluginManager::load_plugins(act_replace);
}
return 0;
}
-int DetectionEngine::queue_event(unsigned gid, unsigned sid, Actions::Type type)
+int DetectionEngine::queue_event(unsigned gid, unsigned sid)
{
OptTreeNode* otn = GetOTN(gid, sid);
en->otn = otn;
en->rtn = nullptr; // lookup later after ips policy selection
- en->type = type;
if ( sfeventq_add(pq, en) )
return -1;
// packet (PDU), first call set_next_packet(). If rebuild is successful,
// then instantiate a new DetectionEngine to detect that packet.
-#include "actions/actions.h"
#include "detection/detection_util.h"
#include "detection/ips_context.h"
#include "main/snort_types.h"
static bool inspect(Packet*);
static int queue_event(const struct OptTreeNode*);
- static int queue_event(unsigned gid, unsigned sid, Actions::Type = Actions::NONE);
+ static int queue_event(unsigned gid, unsigned sid);
static void disable_all(Packet*);
static bool all_disabled(Packet*);
#include "detection_util.h"
+#include "actions/actions.h"
#include "events/event.h"
#include "log/text_log.h"
#include "protocols/packet.h"
}
}
-void EventTrace_Log(const Packet* p, const OptTreeNode* otn, int action)
+void EventTrace_Log(const Packet* p, const OptTreeNode* otn, Actions::Type action)
{
- const char* acts = Actions::get_string((Actions::Type)action);
+ std::string acts = Actions::get_string(action);
if ( !tlog )
return;
TextLog_Print(tlog,
"\nEvt=%u, Gid=%u, Sid=%u, Rev=%u, Act=%s\n",
- event_id, otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev, acts);
+ event_id, otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev, acts.c_str());
TextLog_Print(tlog,
"Pkt=" STDu64 ", Sec=%lu.%6lu, Len=%u, Cap=%u\n",
// this is a legacy junk-drawer file that needs to be refactored
// it provides file and alt data and event trace foo.
+#include "actions/actions.h"
#include "main/snort_config.h"
#define DECODE_BLEN 65535
void EventTrace_Init();
void EventTrace_Term();
-void EventTrace_Log(const snort::Packet*, const OptTreeNode*, int action);
+void EventTrace_Log(const snort::Packet*, const OptTreeNode*, Actions::Type action);
inline int EventTrace_IsEnabled(const snort::SnortConfig* sc)
{
#include <vector>
+#include "actions/actions.h"
#include "events/event.h"
#include "filters/rate_filter.h"
#include "filters/sfthreshold.h"
// called by fpLogEvent(), which does the filtering etc.
// this handles the non-rule-actions (responses).
static inline void fpLogOther(
- Packet* p, const RuleTreeNode* rtn, const OptTreeNode* otn, int action)
+ Packet* p, const RuleTreeNode* rtn, const OptTreeNode* otn, Actions::Type action)
{
if ( EventTrace_IsEnabled(p->context->conf) )
EventTrace_Log(p, otn, action);
if ( PacketTracer::is_active() )
{
+ std::string act = Actions::get_string(action);
PacketTracer::log("Event: %u:%u:%u, Action %s\n",
otn->sigInfo.gid, otn->sigInfo.sid,
- otn->sigInfo.rev, Actions::get_string((Actions::Type)action));
+ otn->sigInfo.rev, act.c_str());
}
// rule option actions are queued here (eg replace)
otn_trigger_actions(otn, p);
- // rule actions are queued here (eg reject)
- if ( rtn->listhead->is_plugin_action )
- {
- Actions::Type idx = rtn->listhead->ruleListNode->mode;
- ActiveAction * act = get_ips_policy()->action[idx];
- if ( act )
- Active::queue(act, p);
- }
+ IpsAction* act = get_ips_policy()->action[rtn->action];
+ ActiveAction* active_act = act->get_active_action();
+ if ( active_act )
+ Active::queue(act->get_active_action(), p);
}
/*
int action = -1, rateAction = -1;
int override, filterEvent = 0;
- if ( Actions::is_pass(rtn->action) )
- p->packet_flags |= PKT_PASS_RULE;
-
if ( otn->stateless() )
{
/* Stateless rule, set the stateless bit */
{
// We still want to drop packets that are drop rules.
// We just don't want to see the alert.
- Actions::apply(rtn->action, p);
+ IpsAction * act = get_ips_policy()->action[rtn->action];
+ act->exec(p);
fpLogOther(p, rtn, otn, rtn->action);
return 1;
}
// perform rate filtering tests - impacts action taken
rateAction = RateFilter_Test(otn, p);
- override = ( rateAction >= Actions::MAX );
+ override = ( rateAction >= Actions::get_max_types() );
if ( override )
- rateAction -= Actions::MAX;
+ rateAction -= Actions::get_max_types();
// internal events are no-ops
if ( (rateAction < 0) && EventIsInternal(otn->sigInfo.gid) )
** If InlineMode is on, then we still want to drop packets
** that are drop rules. We just don't want to see the alert.
*/
- Actions::apply((Actions::Type)action, p);
+ IpsAction * act = get_ips_policy()->action[action];
+ act->exec(p);
fpLogOther(p, rtn, otn, action);
pc.event_limit++;
return 1;
const SnortConfig* sc = p->context->conf;
if ( (p->packet_flags & PKT_PASS_RULE) &&
- (sc->get_eval_index(rtn->action) > sc->get_eval_index(Actions::PASS)) )
+ (sc->get_eval_index(rtn->action) > sc->get_eval_index(Actions::get_type("pass"))) )
{
fpLogOther(p, rtn, otn, rtn->action);
return 1;
otn->state[get_instance_id()].alerts++;
event_id++;
- Actions::execute((Actions::Type)action, p, otn, event_id);
+
+ IpsAction * act = get_ips_policy()->action[action];
+ act->exec(p, otn);
+ SetTags(p, otn, event_id);
+
fpLogOther(p, rtn, otn, action);
return 0;
const OptTreeNode* otn = omd->matchInfo[i].MatchArray[j];
RuleTreeNode* rtn = getRtnFromOtn(otn);
- if ( otn && rtn && Actions::is_pass(rtn->action) )
+ if ( otn && rtn && ( p->packet_flags & PKT_PASS_RULE ) )
{
/* Already acted on rules, so just don't act on anymore */
if ( tcnt > 0 )
}
/* only log/count one pass */
- if ( otn && rtn && Actions::is_pass(rtn->action) )
- {
- p->packet_flags |= PKT_PASS_RULE;
+ if ( otn && rtn && ( p->packet_flags & PKT_PASS_RULE ) )
return 1;
- }
}
}
}
policy->rules_shared++;
RuleTreeNode* t_rtn = dup_rtn(sc, otn, b_rtn, policy);
- update_rtn(t_rtn, s);
+ update_rtn(sc, t_rtn, s);
+
addRtnToOtn(sc, otn, t_rtn, ips_num);
}
return ret;
}
-void RuleStateMap::update_rtn(RuleTreeNode* rtn, const RuleState& s)
+void RuleStateMap::update_rtn(SnortConfig* sc, RuleTreeNode* rtn, const RuleState& s)
{
switch ( s.enable )
{
case IpsPolicy::ENABLED: rtn->set_enabled(); break;
case IpsPolicy::INHERIT_ENABLE: break;
}
+
+ ListHead* new_listhead = get_rule_list(sc, s.rule_action.c_str());
+
+ if ( new_listhead and ( rtn->listhead != new_listhead ) )
+ rtn->listhead = new_listhead;
+
rtn->action = s.action;
if ( rtn->header )
OutputSet* LogList;
OutputSet* AlertList;
struct RuleListNode* ruleListNode;
- bool is_plugin_action = false;
};
// for top-level rule lists by type (alert, drop, etc.)
struct RuleListNode
{
ListHead* RuleList; /* The rule list associated with this node */
- snort::Actions::Type mode; /* the rule mode */
+ Actions::Type mode; /* the rule mode */
unsigned evalIndex; /* eval index for this rule set */
char* name; /* name of this rule list */
RuleListNode* next; /* the next RuleListNode */
struct RuleState
{
std::string rule_action;
- snort::Actions::Type action;
+ uint8_t action;
IpsPolicy::Enable enable;
};
private:
RuleTreeNode* dup_rtn(snort::SnortConfig*, OptTreeNode*, RuleTreeNode*, IpsPolicy*);
- void update_rtn(RuleTreeNode*, const RuleState&);
+ void update_rtn(snort::SnortConfig*, RuleTreeNode*, const RuleState&);
void apply(snort::SnortConfig*, OptTreeNode*, unsigned ips_num, const RuleState&);
private:
#include "signature.h"
+#include "actions/actions.h"
#include "framework/decode_data.h"
#include "hash/hash_defs.h"
#include "hash/ghash.h"
auto pid = snort::get_ips_policy(sc, i)->user_policy_id;
json.put("policy", pid);
- const char* s = Actions::get_string(rtn->action);
- json.put("action", s);
+ std::string action = Actions::get_string(rtn->action);
+ json.put("action", action.c_str());
- s = rtn->enabled() ? "enabled" : "disabled";
+ const char* s = rtn->enabled() ? "enabled" : "disabled";
json.put("state", s);
json.close();
// Multiple OTNs can reference this RTN with the same policy.
unsigned int otnRefCount = 0; // FIXIT-L shared_ptr?
- snort::Actions::Type action = snort::Actions::Type::NONE;
+ Actions::Type action = 0;
uint8_t flags = 0;
#ifndef EVENT_QUEUE_H
#define EVENT_QUEUE_H
-#include "actions/actions.h"
#include "main/snort_types.h"
#define SNORT_EVENTQ_PRIORITY 1
{
const struct OptTreeNode* otn;
const struct RuleTreeNode* rtn;
- snort::Actions::Type type;
};
EventQueueConfig* EventQueueConfigNew();
return true;
}
-bool FileIdModule::end(const char* fqn, int idx, SnortConfig* sc)
+bool FileIdModule::end(const char* fqn, int idx, SnortConfig*)
{
if (!idx)
- {
- if ( need_active )
- sc->set_active_enabled();
return true;
- }
if ( !strcmp(fqn, "file_id.file_rules") )
{
#include "main/thread.h"
#include "detection/rules.h"
+#include "framework/ips_action.h"
#include "hash/ghash.h"
#include "hash/hash_defs.h"
#include "hash/xhash.h"
// but the decrement will never come so we "fix" it here
// if the count were not incremented in such cases, the
// threshold would never be exceeded.
- if ( !cfgNode->seconds && dynNode->count > cfgNode->count )
- if ( cfgNode->newAction == Actions::DROP )
+ if ( !cfgNode->seconds && (dynNode->count > cfgNode->count)
+ && Actions::is_valid_action(cfgNode->newAction) )
+ {
+ IpsAction* act = get_ips_policy()->action[cfgNode->newAction];
+ if ( act->drops_traffic() )
dynNode->count--;
+ }
#ifdef SFRF_DEBUG
printf("--SFRF_DEBUG: %d-%u-%u: %u Packet IP %s, op: %d, count %u, action %d\n",
fflush(stdout);
#endif
- return Actions::MAX + cfgNode->newAction;
+ return Actions::get_max_types() + cfgNode->newAction;
}
static void _updateDependentThresholds(
unsigned seconds;
// Action that replaces original rule action on reaching threshold
- snort::Actions::Type newAction;
+ Actions::Type newAction;
// Threshold action duration in seconds before reverting to original rule action
unsigned timeout;
status = SFRF_TestThreshold(
rfc, p->gid, p->sid, &sip, &dip, curtime, op);
- if ( status >= Actions::MAX )
- status -= Actions::MAX;
+ if ( status >= Actions::get_max_types() )
+ status -= Actions::get_max_types();
return status;
}
// These can be used to execute external controls like updating an external
// firewall.
-#include "actions/actions.h"
#include "framework/base_api.h"
#include "main/snort_types.h"
#include "packet_io/active_action.h"
// this is the current version of the api
-#define ACTAPI_VERSION ((BASE_API_VERSION << 16) | 0)
+#define ACTAPI_VERSION ((BASE_API_VERSION << 16) | 1)
//-------------------------------------------------------------------------
// api for class
//-------------------------------------------------------------------------
+struct OptTreeNode;
namespace snort
{
struct Packet;
-class SO_PUBLIC IpsAction : public ActiveAction
+class SO_PUBLIC IpsAction
{
public:
- void exec(Packet*) override = 0;
+ enum IpsActionPriority : uint16_t
+ {
+ IAP_LOG = 10,
+ IAP_ALERT = 20,
+ IAP_REWRITE = 30,
+ IAP_DROP = 40,
+ IAP_BLOCK = 50,
+ IAP_REJECT = 60,
+ IAP_PASS = 70,
+ IAP_MAX = IAP_PASS
+ };
+
+public:
+ virtual ~IpsAction() = default;
const char* get_name() const { return name; }
+ ActiveAction* get_active_action() const { return active_action; }
+
+ virtual void exec(Packet*, const OptTreeNode* otn = nullptr) = 0;
+ virtual bool drops_traffic() { return false; }
protected:
- IpsAction(const char* s, ActionType a) : ActiveAction(a)
- { name = s; }
+ IpsAction(const char* s, ActiveAction* a)
+ {
+ active_action = a;
+ name = s;
+ }
private:
const char* name;
+ ActiveAction* active_action;
};
typedef void (* IpsActFunc)();
struct ActionApi
{
BaseApi base;
- Actions::Type type;
+
+ IpsAction::IpsActionPriority priority;
IpsActFunc pinit;
IpsActFunc pterm;
//-------------------------------------------------------------------------
// alerts module
//-------------------------------------------------------------------------
-
static const Parameter alerts_params[] =
{
{ "alert_with_interface_name", Parameter::PT_BOOL, nullptr, "false",
{ "log_references", Parameter::PT_BOOL, nullptr, "false",
"include rule references in alert info (full only)" },
- { "order", Parameter::PT_STRING, nullptr, "pass reset block drop alert log",
+ { "order", Parameter::PT_STRING, nullptr, nullptr,
"change the order of rule action application" },
{ "rate_filter_memcap", Parameter::PT_INT, "0:max32", "1048576",
sc->set_dst_mac(v.get_string());
else if ( v.is("max_responses") )
- {
sc->max_responses = v.get_uint8();
- if ( sc->max_responses )
- sc->set_active_enabled();
- }
-
else if ( v.is("min_interval") )
sc->min_interval = v.get_uint8();
// rate_filter module
//-------------------------------------------------------------------------
+function<const char*()> get_action_types = []()
+{ return PluginManager::get_available_plugins(PT_IPS_ACTION); };
+
static const Parameter rate_filter_params[] =
{
{ "gid", Parameter::PT_INT, "0:max32", "1",
{ "seconds", Parameter::PT_INT, "0:max32", "1",
"count interval" },
- { "new_action", Parameter::PT_ENUM,
- // FIXIT-L new_action options must match Actions::Type and
- // should include pluggable actions as well
- "log | pass | alert | drop | block | reset", "alert",
+ { "new_action", Parameter::PT_DYNAMIC, (void*)&get_action_types, "alert",
"take this action on future hits until timeout" },
{ "timeout", Parameter::PT_INT, "0:max32", "1",
thdx.applyTo = sfip_var_from_string(v.get_string(), "rate_filter");
else if ( v.is("new_action") )
- thdx.newAction = (Actions::Type)(v.get_uint8() + 1);
+ {
+ thdx.newAction = Actions::get_type(v.get_string());
+
+ if ( !Actions::is_valid_action(thdx.newAction) )
+ ParseError("unknown new_action type rate_filter configuration %s",
+ v.get_string());
+ }
else
return false;
// detection policy
//-------------------------------------------------------------------------
-IpsPolicy::IpsPolicy(PolicyId id) : action(Actions::Type::MAX, nullptr)
+IpsPolicy::IpsPolicy(PolicyId id) : action(Actions::get_max_types(), nullptr)
{
policy_id = id;
user_policy_id = 0;
{
class GHash;
struct SnortConfig;
-class ActiveAction;
+class IpsAction;
}
struct PortTable;
bool obfuscate_pii;
- // Holds plugin actions associated with this policy (e.g. reject, react, etc.)
- // Indexed by Actions::Type.
- std::vector<snort::ActiveAction*> action;
+ // Holds all plugin actions associated with this policy
+ std::vector<snort::IpsAction*> action;
};
//-------------------------------------------------------------------------
ModuleManager::reset_stats(sc);
if (sc->alert_before_pass())
- sc->rule_order = "reset block drop alert pass log";
+ sc->rule_order = Actions::get_default_priorities(true);
sc->setup();
#include <pwd.h>
#include <syslog.h>
+#include "actions/ips_actions.h"
#include "detection/detect.h"
#include "detection/detection_engine.h"
#include "detection/fp_config.h"
thread_config = new ThreadConfig();
global_dbus = new DataBus();
- memset(evalOrder, 0, sizeof(evalOrder));
proto_ref = new ProtocolReference(protocol_reference);
so_rules = new SoRules;
trace_config = new TraceConfig;
delete memory;
delete daq_config;
delete proto_ref;
+ delete[] evalOrder;
delete so_rules;
if ( plugins )
delete plugins;
init_policies(this);
ParseRules(this);
+
+ // Allocate evalOrder before calling the OrderRuleLists
+ evalOrder = new int[Actions::get_max_types()]();
+
OrderRuleLists(this);
if ( rule_states )
#include <unordered_map>
#include <vector>
+#include "actions/actions.h"
#include "events/event_queue.h"
#include "framework/bits.h"
#include "helpers/scratch_allocator.h"
unsigned num_rule_types = 0;
RuleListNode* rule_lists = nullptr;
- int evalOrder[Actions::MAX + 1];
+ int* evalOrder = nullptr;
IpsActionsConfig* ips_actions_config = nullptr;
FrameworkConfig* framework_config = nullptr;
DumpConfigType dump_config_type = DUMP_CONFIG_NONE;
private:
- bool active_enabled = false;
std::list<ReloadResourceTuner*> reload_tuners;
public:
bool assure_established() const
{ return run_flags & RUN_FLAG__ASSURE_EST; }
- // active stuff
- void set_active_enabled()
- { active_enabled = true; }
-
- bool is_active_enabled() const
- { return active_enabled; }
-
// other stuff
uint8_t min_ttl() const
{ return get_network_policy()->min_ttl; }
#include "log/messages.h"
#include "main/snort_config.h"
+#include "managers/module_manager.h"
+#include "managers/plugin_manager.h"
#include "packet_io/active.h"
#include "parser/parser.h"
};
using ACList = vector<ActionClass>;
+using ACTypeList = unordered_map<string, Actions::Type>;
+using ACPriorityList = map<IpsAction::IpsActionPriority, string, std::greater<int>>;
static ACList s_actors;
+static ACTypeList s_act_types;
+static ACPriorityList s_act_priorities;
+static Actions::Type s_act_index = 0;
static THREAD_LOCAL ACList* s_tl_actors = nullptr;
void ActionManager::add_plugin(const ActionApi* api)
{
s_actors.emplace_back(api);
+ s_act_types.emplace(api->base.name, s_act_index++);
+ s_act_priorities.emplace(api->priority, api->base.name);
+}
+
+std::string ActionManager::get_action_string(Actions::Type action)
+{
+ if ( action < s_act_index )
+ {
+ for ( const auto& type : s_act_types )
+ {
+ if ( type.second == action )
+ return type.first;
+ }
+ }
+
+ return "ERROR";
}
Actions::Type ActionManager::get_action_type(const char* s)
{
- for ( auto& p : s_actors )
+ auto type = s_act_types.find(s);
+
+ if (type != s_act_types.end())
+ return type->second;
+
+ return get_max_action_types();
+}
+
+Actions::Type ActionManager::get_max_action_types()
+{
+ return s_act_index;
+}
+
+std::string ActionManager::get_action_priorities(bool alert_before_pass)
+{
+ std::string priorities;
+
+ for (auto iter = s_act_priorities.begin(); iter != s_act_priorities.end(); )
{
- if ( !strcmp(p.api->base.name, s) )
- return p.api->type;
+ if ( alert_before_pass )
+ {
+ if ( iter->second == "pass" )
+ {
+ iter++;
+ continue;
+ }
+ else if ( iter->second == "alert" )
+ {
+ priorities += "alert pass ";
+ iter++;
+ continue;
+ }
+ }
+
+ priorities += iter->second;
+
+ if ( ++iter != s_act_priorities.end() )
+ priorities += " ";
}
- return Actions::NONE;
+
+ return priorities;
}
void ActionManager::dump_plugins()
sc->ips_actions_config = nullptr;
}
-void ActionManager::instantiate(const ActionApi* api, Module* mod, SnortConfig* sc)
+void ActionManager::instantiate(const ActionApi* api, Module* mod, SnortConfig* sc, IpsPolicy* ips)
{
ActionClass* cls = get_action_class(api, sc->ips_actions_config);
+
assert(cls != nullptr);
IpsAction* act = cls->api->ctor(mod);
if ( act )
{
- // Add this instance to the list of those created for this config
- sc->ips_actions_config->clist.emplace_back(*cls, act);
- RuleListNode* rln = CreateRuleType(sc, api->base.name, api->type, true);
+ RuleListNode* rln = CreateRuleType(sc, api->base.name, get_action_type(api->base.name));
// The plugin actions (e.g. reject, react, etc.) are per policy, per mode.
// At logging time, they have to be retrieved the way we store them here.
- IpsPolicy* ips = get_ips_policy();
+ if ( !ips )
+ ips = get_ips_policy();
+
Actions::Type idx = rln->mode;
- assert(ips->action[idx] == nullptr);
- ips->action[idx] = act;
+ if (ips->action[idx] == nullptr)
+ {
+ ips->action[idx] = act;
+ // Add this instance to the list of those created for this config
+ sc->ips_actions_config->clist.emplace_back(*cls, act);
+ }
+ else
+ {
+ cls->api->dtor(act);
+ }
+ }
+}
+
+void ActionManager::initialize_policies(SnortConfig* sc)
+{
+ for (unsigned i = 0; i < sc->policy_map->ips_policy_count(); i++)
+ {
+ auto policy = sc->policy_map->get_ips_policy(i);
+
+ if ( !policy )
+ continue;
+
+ for ( auto actor : s_actors )
+ ActionManager::instantiate(actor.api, nullptr, sc, policy);
}
}
struct Packet;
}
+struct IpsPolicy;
+
//-------------------------------------------------------------------------
#ifdef PIGLET
static void dump_plugins();
static void new_config(snort::SnortConfig*);
- static snort::Actions::Type get_action_type(const char*);
static void delete_config(snort::SnortConfig*);
- static void instantiate(const snort::ActionApi*, snort::Module*, snort::SnortConfig*);
+ static void instantiate(const snort::ActionApi*, snort::Module*,
+ snort::SnortConfig*, IpsPolicy* ips = nullptr );
+ static void initialize_policies(snort::SnortConfig*);
+
+ static std::string get_action_string(Actions::Type);
+ static Actions::Type get_action_type(const char*);
+ static Actions::Type get_max_action_types(void);
+ static std::string get_action_priorities(bool);
static void thread_init(const snort::SnortConfig*);
static void thread_reinit(const snort::SnortConfig*);
class ResetAction : public snort::ActiveAction
{
public:
- ResetAction() : ActiveAction(ActionType::ACT_RESET) { }
+ ResetAction() : ActiveAction(ActionPriority::AP_RESET) { }
- void exec(snort::Packet* p) override
+ void delayed_exec(snort::Packet* p) override
{
p->active->kill_session(p, ENC_FLAG_FWD);
}
if ( s_attempts > MAX_ATTEMPTS )
s_attempts = MAX_ATTEMPTS;
- if ( sc->is_active_enabled() && !s_attempts )
+ if ( !s_attempts )
s_attempts = 1;
- if ( sc->is_active_enabled() && (!SFDAQ::can_inject() || !sc->respond_device.empty()) )
+ if ( !SFDAQ::can_inject() || !sc->respond_device.empty() )
{
if ( sc->read_mode() ||
!open(sc->respond_device.empty() ? nullptr : sc->respond_device.c_str()) )
if ( force or (p->context->conf->inline_mode() and SFDAQ::forwarding_packet(p->pkth)))
Stream::drop_flow(p);
- if ( p->context->conf->is_active_enabled() )
- {
- if (reject)
- Active::queue(reject, p);
+ if (reject)
+ Active::queue(reject, p);
- if ( p->flow )
- {
- Stream::init_active_response(p, p->flow);
- p->flow->set_state(Flow::FlowState::RESET);
- }
+ if ( p->flow )
+ {
+ Stream::init_active_response(p, p->flow);
+ p->flow->set_state(Flow::FlowState::RESET);
}
p->disable_inspect = true;
{
if ( *p->action )
{
- (*p->action)->exec(p);
+ (*p->action)->delayed_exec(p);
*p->action = nullptr;
}
{
struct Packet;
-enum ActionType
+enum ActionPriority
{
- ACT_LOCAL,
- ACT_MODIFY,
- ACT_PROXY,
- ACT_RESET,
- ACT_REMOTE,
- ACT_MAX
+ AP_LOCAL,
+ AP_MODIFY,
+ AP_PROXY,
+ AP_RESET,
+ AP_REMOTE,
+ AP_MAX
};
// These are injection actions (e.g. send a RST packet, or respond to a query
class SO_PUBLIC ActiveAction
{
public:
- ActiveAction(ActionType a = ActionType::ACT_MAX) : action(a) {}
+ ActiveAction(ActionPriority a = ActionPriority::AP_MAX) : action(a) {}
virtual ~ActiveAction() = default;
- virtual void exec(Packet*) = 0;
+ virtual void delayed_exec(Packet* ) { }
- ActionType get_action() const { return action; }
+ ActionPriority get_action() const { return action; }
protected:
- ActionType action;
+ ActionPriority action;
};
#include <sys/stat.h>
#include <unistd.h>
+#include <cassert>
#include <climits>
#include <fstream>
#include <stack>
#include "log/messages.h"
#include "main/snort_config.h"
-#include "managers/action_manager.h"
#include "managers/module_manager.h"
#include "sfip/sf_vartable.h"
#include "target_based/snort_protocols.h"
otn->sigInfo.services.emplace_back(si);
}
-Actions::Type get_rule_type(const char* s)
-{
- Actions::Type rt = Actions::get_type(s);
-
- if ( rt == Actions::NONE )
- rt = ActionManager::get_action_type(s);
-
- switch ( rt )
- {
- case Actions::DROP:
- case Actions::BLOCK:
- case Actions::RESET:
- return rt;
-
- case Actions::NONE:
- ParseError("unknown rule type '%s'", s);
- break;
-
- default:
- break;
- }
- return rt;
-}
-
ListHead* get_rule_list(SnortConfig* sc, const char* s)
{
const RuleListNode* p = sc->rule_lists;
void add_service_to_otn(snort::SnortConfig*, OptTreeNode*, const char*);
-snort::Actions::Type get_rule_type(const char*);
ListHead* get_rule_list(snort::SnortConfig*, const char*);
#endif
#include "parse_rule.h"
+#include "actions/actions.h"
#include "detection/detect.h"
#include "detection/fp_config.h"
#include "detection/fp_utils.h"
if ( s_so_rule )
return;
- rtn.action = get_rule_type(s);
+ assert(s);
- if ( rtn.action == Actions::NONE )
+ rtn.action = Actions::get_type(s);
+
+ if ( !Actions::is_valid_action(rtn.action) )
{
s_ignore = true;
+ ParseError("unknown rule action '%s'", s);
return;
}
+
if ( sc->dump_rule_meta() )
rtn.header = new RuleHeader(s);
CreateRuleType(sc, s, rtn.action);
rtn.listhead = get_rule_list(sc, s);
}
+
if ( sc->get_default_rule_state() )
rtn.set_enabled();
-
- if ( !rtn.listhead )
- ParseError("unconfigured rule action '%s'", s);
}
void parse_rule_proto(SnortConfig* sc, const char* s, RuleTreeNode& rtn, bool elided)
#include "main/modules.h"
#include "main/shell.h"
#include "main/snort_config.h"
+#include "managers/action_manager.h"
#include "managers/event_manager.h"
#include "managers/module_manager.h"
#include "ports/port_object.h"
return false;
bool success = sh->configure(sc, is_fatal, is_root);
+
return success;
}
// Merge in any overrides from the command line
sc->merge(cmd_line_conf);
+ ActionManager::initialize_policies(sc);
+
return sc;
}
* Returns: the ListHead for the rule type
*
***************************************************************************/
-RuleListNode* CreateRuleType(SnortConfig* sc, const char* name, Actions::Type mode, bool is_plugin_action)
+RuleListNode* CreateRuleType(SnortConfig* sc, const char* name, Actions::Type mode)
{
RuleListNode* node;
- unsigned evalIndex = 0;
if (sc == nullptr)
return nullptr;
return tmp;
}
- evalIndex++;
last = tmp;
tmp = tmp->next;
}
node->RuleList = (ListHead*)snort_calloc(sizeof(ListHead));
node->RuleList->ruleListNode = node;
- node->RuleList->is_plugin_action = is_plugin_action;
node->mode = mode;
node->name = snort_strdup(name);
- node->evalIndex = evalIndex;
- sc->evalOrder[node->mode] = evalIndex;
sc->num_rule_types++;
return node;
{
int evalIndex = 0;
RuleListNode* ordered_list = nullptr;
+ std::string default_priorities;
const char* order = sc->rule_order.c_str();
if ( !*order )
- order = "pass drop alert log"; // FIXIT-M apply builtin module defaults
+ {
+ default_priorities = Actions::get_default_priorities(); // FIXIT-M apply builtin module defaults
+ order = default_priorities.c_str();
+ }
std::stringstream ss(order);
std::string tok;
RuleListNode* node = sc->rule_lists;
sc->rule_lists = node->next;
ordered_list = addNodeToOrderedList(ordered_list, node, evalIndex++);
- sc->evalOrder[node->mode] = evalIndex;
+ sc->evalOrder[node->mode] = evalIndex;
}
sc->rule_lists = ordered_list;
return getRtnFromOtn(otn);
}
-RuleListNode* CreateRuleType(snort::SnortConfig* sc, const char* name,
- snort::Actions::Type, bool is_plugin_action = false);
+RuleListNode* CreateRuleType(snort::SnortConfig* sc, const char* name, Actions::Type action_type);
void FreeRuleTreeNode(RuleTreeNode*);
void DestroyRuleTreeNode(RuleTreeNode*);
static void set_configured() { conf.payload_injector_config = &pi_conf; }
Packet::~Packet() = default;
-int DetectionEngine::queue_event(unsigned int, unsigned int, snort::Actions::Type) { return 0; }
+int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; }
FlowData::~FlowData() = default;
FlowData::FlowData(unsigned int, snort::Inspector*) { }
// FIXIT-M needs to be updated for addition of get_fp_buf()
template<typename T>
static inline bool get_buf(
- Inspector& i, T v, Packet& p, std::string& rb)
+ Inspector& i, T v, snort::Packet& p, std::string& rb)
{
struct InspectionBuffer ib;
bool result = i.get_buf(v, &p, ib);
auto& p = PacketIface.get(L);
auto& self = IpsActionIface.get(L);
- self.exec(&p);
+ self.exec(&p, nullptr);
return 0;
}
namespace snort
{
// Stubs whose sole purpose is to make the test code link
-int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; }
+int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; }
}
using namespace Http2Enums;
namespace snort
{
// Stubs whose sole purpose is to make the test code link
-int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; }
+int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; }
}
using namespace Http2Enums;
void Value::set_first_token() {}
bool Value::get_next_token(std::string& ) { return false; }
-int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; }
+int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; }
LiteralSearch::Handle* LiteralSearch::setup() { return nullptr; }
void LiteralSearch::cleanup(LiteralSearch::Handle*) {}
LiteralSearch* LiteralSearch::instantiate(LiteralSearch::Handle*, const uint8_t*, unsigned, bool,
unsigned FlowData::flow_data_id = 0;
FlowData::FlowData(unsigned, Inspector*) {}
FlowData::~FlowData() = default;
-int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; }
+int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; }
fd_status_t File_Decomp_StopFree(fd_session_t*) { return File_Decomp_OK; }
uint32_t str_to_hash(const uint8_t *, size_t) { return 0; }
void FlowData::update_allocations(size_t) {}
void Value::get_bits(std::bitset<256ul>&) const {}
void Value::set_first_token() {}
bool Value::get_next_token(std::string& ) { return false; }
-int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; }
+int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; }
LiteralSearch::Handle* LiteralSearch::setup() { return nullptr; }
void LiteralSearch::cleanup(LiteralSearch::Handle*) {}
LiteralSearch* LiteralSearch::instantiate(LiteralSearch::Handle*, const uint8_t*, unsigned, bool,
return true;
}
-bool SmtpModule::end(const char* fqn, int idx, SnortConfig* sc)
+bool SmtpModule::end(const char* fqn, int idx, SnortConfig*)
{
- if ( !strcmp(fqn, "smtp") and config->xlink2state )
- sc->set_active_enabled();
-
if ( !idx )
return true;
const ConvertMap* disable_ipopt_drops_map = &disable_ipopt_drops_api;
+/*************************************************
+ **************** disable_replace ***************
+ *************************************************/
+
+static const std::string disable_replace = "disable_replace";
+static const ConvertMap disable_replace_api =
+{
+ disable_replace,
+ deleted_ctor<& disable_replace>,
+};
+
+const ConvertMap* disable_replace_map = &disable_replace_api;
+
+
/*************************************************
************ disable_tcpopt_alerts ************
*************************************************/
static const std::string packets = "packets";
static const std::string process = "process";
static const std::string output = "output";
-static const std::string rewrite = "rewrite";
/*************************************************
********** addressspace_agnostic **********
const ConvertMap* dirty_pig_map = &dirty_pig_api;
-/*************************************************
- ***** disable rewrite rules with replace *******
- *************************************************/
-
-static const std::string disable_replace = "disable_replace";
-static const ConvertMap disable_replace_api =
-{
- disable_replace,
- config_true_no_opt_ctor<& disable_replace, & rewrite>,
-};
-
-const ConvertMap* disable_replace_map = &disable_replace_api;
-
/*************************************************
*************** dump_chars_only ***************
*************************************************/
"Changing ruletype '" + old_action + "' to 'rewrite' "
"because the rule has 'replace' option.");
- // include a rewrite plugin
- c.get_table_api().open_table("rewrite");
- c.get_table_api().close_table();
-
// update the rule type
c.get_rule_api().update_rule_action("rewrite");