]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1545 in SNORT/snort3 from ~CWAXMAN/snort3:rule_state to master
authorMichael Altizer (mialtize) <mialtize@cisco.com>
Fri, 29 Mar 2019 15:32:49 +0000 (11:32 -0400)
committerMichael Altizer (mialtize) <mialtize@cisco.com>
Fri, 29 Mar 2019 15:32:49 +0000 (11:32 -0400)
Squashed commit of the following:

commit 323e859c920a3edbb522200a408a47aaabb74e34
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Tue Mar 12 15:21:40 2019 -0400

    detection, snort2lua: added global rule state options for legacy conversions

commit b5cb6f3f9a17fb2df26c86475e305946edaaef5c
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Fri Mar 8 15:36:25 2019 -0500

    detection: fixed incorrect log messages

commit eb438448160d41867d5e68a890cea627a04c88fb
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Tue Feb 26 08:28:52 2019 -0500

    rule_state: added default rule state to ips policy

commit 6eec505eb1af7357584eb7a18a49fde409b5e1a3
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Mon Feb 25 15:41:08 2019 -0500

    rule_state: add rtn but disable if block is set on non-inline deployment

commit 52b20be073639ba0f1b75a0943c6b595f81b7318
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Mon Feb 18 12:27:48 2019 -0500

    rule_state: added per-ips-policy rule states

29 files changed:
src/actions/actions.h
src/detection/CMakeLists.txt
src/detection/fp_create.cc
src/detection/fp_detect.cc
src/detection/rtn_checks.cc
src/detection/rules.cc [new file with mode: 0644]
src/detection/rules.h
src/detection/service_map.cc
src/detection/signature.cc
src/detection/signature.h
src/detection/treenodes.h
src/framework/parameter.h
src/ips_options/ips_flow.cc
src/main/modules.cc
src/main/policy.h
src/main/snort_config.cc
src/main/snort_config.h
src/managers/module_manager.cc
src/parser/parse_conf.cc
src/parser/parse_conf.h
src/parser/parse_rule.cc
src/parser/parser.cc
tools/snort2lua/config_states/config_default_rule_state.cc
tools/snort2lua/data/data_types/dt_table.cc
tools/snort2lua/data/data_types/dt_table.h
tools/snort2lua/data/dt_table_api.cc
tools/snort2lua/data/dt_table_api.h
tools/snort2lua/helpers/converter.cc
tools/snort2lua/keyword_states/kws_rule_state.cc

index 75ea1ce0296743dd81182b936edfe1519a510b2a..8d8b89625ac56e400e20519ad9f2544b655fa84c 100644 (file)
@@ -35,7 +35,7 @@ class SO_PUBLIC Actions
 {
 public:
     // FIXIT-L if Type is changed, RateFilterModule and type in actions.cc must be updated
-    enum Type
+    enum Type : uint8_t
     { NONE = 0, LOG, PASS, ALERT, DROP, BLOCK, RESET, MAX };
 
     static const char* get_string(Type);
index 4620d7e847d80f23a6a4e45d4b0669fbd9e5bbef..a6d88da14406f3bbe16f86916b0ad85b352f6aec 100644 (file)
@@ -42,6 +42,7 @@ add_library (detection OBJECT
     regex_offload.cc
     rtn_checks.cc
     rtn_checks.h
+    rules.cc
     service_map.cc
     service_map.h
     sfrim.cc
index b3c5e4a2a28c55057d59144a183109ca44fd625c..c753201081ed5ca41def2ce0006c7af0ae34ce96 100644 (file)
@@ -522,8 +522,7 @@ static int fpAddPortGroupRule(
     if ( otn->sigInfo.builtin )
         return -1;
 
-    /* Rule not enabled */
-    if ( !otn->enabled )
+    if ( !otn->enabled_somewhere() )
         return -1;
 
     search_api = fp->get_search_api();
@@ -1294,7 +1293,7 @@ static int fpCreatePortGroups(SnortConfig* sc, RulePortTables* p)
 
     if (fpCreatePortTablePortGroups(sc, p->udp.dst, add_any_any))
     {
-        LogMessage("fpCreatePorTablePortGroups failed-udp.src\n");
+        LogMessage("fpCreatePorTablePortGroups failed-udp.dst\n");
         return -1;
     }
 
@@ -1303,7 +1302,7 @@ static int fpCreatePortGroups(SnortConfig* sc, RulePortTables* p)
 
     if (fpCreatePortObject2PortGroup(sc, po2, nullptr))
     {
-        LogMessage("fpCreatePorTablePortGroups failed-udp.src\n");
+        LogMessage("fpCreatePorTablePortGroups failed-udp.any\n");
         return -1;
     }
 
@@ -1773,13 +1772,13 @@ void fpDeleteFastPacketDetection(SnortConfig* sc)
 
 static void print_nfp_info(const char* group, OptTreeNode* otn)
 {
-    if ( otn->warned_fp )
+    if ( otn->warned_fp() )
         return;
 
     ParseWarning(WARN_RULES, "%s rule %u:%u:%u has no fast pattern",
         group, otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev);
 
-    otn->warned_fp = true;
+    otn->set_warned_fp();
 }
 
 void get_pattern_info(const PatternMatchData* pmd,
index 672faa23e1b3e9ada5bccede9786ef54fe8dfb4a..5fd380f4f89cbdca20311587f958ef4d187e3e90 100644 (file)
@@ -139,10 +139,10 @@ int fpLogEvent(const RuleTreeNode* rtn, const OptTreeNode* otn, Packet* p)
     int action = -1, rateAction = -1;
     int override, filterEvent = 0;
 
-    if ( Actions::is_pass(rtn->type) )
+    if ( Actions::is_pass(rtn->action) )
         p->packet_flags |= PKT_PASS_RULE;
 
-    if ( otn->stateless )
+    if ( otn->stateless() )
     {
         /* Stateless rule, set the stateless bit */
         p->packet_flags |= PKT_STATELESS;
@@ -158,12 +158,12 @@ int fpLogEvent(const RuleTreeNode* rtn, const OptTreeNode* otn, Packet* p)
     if ((p->packet_flags & PKT_STREAM_UNEST_UNI) &&
         SnortConfig::assure_established() &&
         (!(p->packet_flags & PKT_REBUILT_STREAM)) &&
-        (otn->stateless == 0))
+        !otn->stateless() )
     {
         // We still want to drop packets that are drop rules.
         // We just don't want to see the alert.
-        Actions::apply(rtn->type, p);
-        fpLogOther(p, rtn, otn, rtn->type);
+        Actions::apply(rtn->action, p);
+        fpLogOther(p, rtn, otn, rtn->action);
         return 1;
     }
 
@@ -178,7 +178,7 @@ int fpLogEvent(const RuleTreeNode* rtn, const OptTreeNode* otn, Packet* p)
     {
         return 1;
     }
-    action = (rateAction < 0) ? (int)rtn->type : rateAction;
+    action = (rateAction < 0) ? (int)rtn->action : rateAction;
 
     // When rate filters kick in, event filters are still processed.
     // perform event filtering tests - impacts logging
@@ -216,9 +216,9 @@ int fpLogEvent(const RuleTreeNode* rtn, const OptTreeNode* otn, Packet* p)
      * If its order is lower than 'pass', it should have been passed.
      * This is consistent with other detection rules */
     if ( (p->packet_flags & PKT_PASS_RULE)
-        &&(SnortConfig::get_eval_index(rtn->type) > SnortConfig::get_eval_index(Actions::PASS)))
+        &&(SnortConfig::get_eval_index(rtn->action) > SnortConfig::get_eval_index(Actions::PASS)))
     {
-        fpLogOther(p, rtn, otn, rtn->type);
+        fpLogOther(p, rtn, otn, rtn->action);
         return 1;
     }
 
@@ -677,7 +677,7 @@ static inline int fpFinalSelectEvent(OtnxMatchData* o, Packet* p)
                 otn = o->matchInfo[i].MatchArray[j];
                 rtn = getRtnFromOtn(otn);
 
-                if (otn && rtn && Actions::is_pass(rtn->type))
+                if (otn && rtn && Actions::is_pass(rtn->action))
                 {
                     /* Already acted on rules, so just don't act on anymore */
                     if ( tcnt > 0 )
@@ -718,7 +718,7 @@ static inline int fpFinalSelectEvent(OtnxMatchData* o, Packet* p)
                 }
 
                 /* only log/count one pass */
-                if ( otn && rtn && Actions::is_pass(rtn->type))
+                if ( otn && rtn && Actions::is_pass(rtn->action))
                 {
                     p->packet_flags |= PKT_PASS_RULE;
                     return 1;
index 04c393ac8203afdc1c85dad5cd69751a6bc39b7a..ca9c54bc28363b6fae8597c706365aa1dbb7ae21 100644 (file)
@@ -61,9 +61,9 @@ static int CheckAddrPort(sfip_var_t* rule_addr, PortObject* po, Packet* p,
         pkt_port = p->ptrs.sp;
 
         if (mode & INVERSE)
-            any_port_flag = flags & ANY_DST_PORT;
+            any_port_flag = flags & RuleTreeNode::ANY_DST_PORT;
         else
-            any_port_flag = flags & ANY_SRC_PORT;
+            any_port_flag = flags & RuleTreeNode::ANY_SRC_PORT;
     }
     else
     {
@@ -71,9 +71,9 @@ static int CheckAddrPort(sfip_var_t* rule_addr, PortObject* po, Packet* p,
         pkt_port = p->ptrs.dp;
 
         if (mode & INVERSE)
-            any_port_flag = flags & ANY_SRC_PORT;
+            any_port_flag = flags & RuleTreeNode::ANY_SRC_PORT;
         else
-            any_port_flag = flags & ANY_DST_PORT;
+            any_port_flag = flags & RuleTreeNode::ANY_DST_PORT;
     }
 
     if (!rule_addr)
diff --git a/src/detection/rules.cc b/src/detection/rules.cc
new file mode 100644 (file)
index 0000000..241e031
--- /dev/null
@@ -0,0 +1,172 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 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.
+//--------------------------------------------------------------------------
+
+// rules.cc author Carter Waxman <cwaxman@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rules.h"
+
+#include "log/messages.h"
+#include "hash/xhash.h"
+#include "main/policy.h"
+#include "main/snort_config.h"
+#include "parser/parser.h"
+#include "sfip/sf_ipvar.h"
+#include "sfip/sf_vartable.h"
+
+#include "treenodes.h"
+
+#ifdef REG_TEST
+#define ParseError(...) ParseWarning(WARN_RULES, __VA_ARGS__)
+#endif
+
+using namespace snort;
+
+void RuleState::apply(SnortConfig* sc)
+{
+    OptTreeNode* otn = OtnLookup(sc->otn_map, gid, sid);
+
+    if ( otn == nullptr )
+        ParseError("Rule state specified for invalid SID: %u GID: %u", sid, gid);
+    else
+    {
+        if ( sc->global_rule_state )
+        {
+            for ( unsigned i = 0; i < sc->policy_map->ips_policy_count(); i++ )
+            {
+                if ( sc->policy_map->get_ips_policy(i) )
+                    apply(sc, otn, i);
+            }
+        }
+        else
+            apply(sc, otn, policy);
+    }
+}
+
+void RuleState::apply(SnortConfig* sc, OptTreeNode* otn, unsigned ips_num)
+{
+    RuleTreeNode* rtn = getRtnFromOtn(otn, ips_num);
+    
+    if ( !rtn )
+        return;
+
+    if ( rtn->otnRefCount > 1 )
+    {
+        // duplicate to avoid blanket setting behavior of multiple OTNs
+        rtn = find_updated_rtn(rtn, sc, ips_num);
+        if ( !rtn )
+        {
+            rtn = dup_rtn(otn, sc, ips_num);
+            replace_rtn(otn, rtn, sc, ips_num);
+        }
+
+        else if ( rtn != getRtnFromOtn(otn, ips_num) )
+            replace_rtn(otn, rtn, sc, ips_num);
+
+        update_rtn(getRtnFromOtn(otn, ips_num));
+    }
+    else
+    {
+        RuleTreeNode* existing_rtn = find_updated_rtn(rtn, sc, ips_num);
+
+        // dedup to avoid wasting memory when transitioning RTN to behavior of existing one
+        if ( existing_rtn )
+            replace_rtn(otn, existing_rtn, sc, ips_num);
+        else
+            update_rtn(getRtnFromOtn(otn, ips_num));
+    }
+}
+
+RuleTreeNode* RuleState::find_updated_rtn(RuleTreeNode* rtn, SnortConfig* sc, unsigned ips_num)
+{
+    RuleTreeNode test_rtn(*rtn);
+    update_rtn(&test_rtn);
+
+    RuleTreeNodeKey key { &test_rtn, ips_num };
+    return (RuleTreeNode*)xhash_find(sc->rtn_hash_table, &key);
+}
+
+void RuleState::replace_rtn(OptTreeNode* otn, RuleTreeNode* replacement, SnortConfig* sc, unsigned ips_num)
+{
+    RuleTreeNode* rtn = getRtnFromOtn(otn, ips_num);
+    rtn->otnRefCount--;
+
+    deleteRtnFromOtn(otn, ips_num, sc, rtn->otnRefCount == 0);
+    addRtnToOtn(snort::SnortConfig::get_conf(), otn, replacement, ips_num);
+}
+
+RuleTreeNode* RuleState::dup_rtn(OptTreeNode* otn, SnortConfig* sc, unsigned ips_num)
+{
+    RuleTreeNode* rtn = getRtnFromOtn(otn, ips_num);
+    RuleTreeNode* ret = new RuleTreeNode(*rtn);
+    ret->otnRefCount = 1;
+    
+    auto ip_vartable = sc->policy_map->get_ips_policy(ips_num)->ip_vartable;
+
+    if ( rtn->sip )
+        ret->sip = sfvt_lookup_var(ip_vartable, rtn->sip->name);
+
+    if ( rtn->dip )
+        ret->dip = sfvt_lookup_var(ip_vartable, rtn->dip->name);
+
+    RuleFpList* from = rtn->rule_func;
+
+    if ( from )
+    {
+        RuleFpList* to = new RuleFpList(*from);
+        to->next = nullptr;
+        ret->rule_func = to;
+
+        for ( from = from->next; from; from = from->next )
+        {
+            to->next = new RuleFpList(*from);
+            to = to->next;
+            to->next = nullptr;
+        }
+    }
+
+    return ret;
+}
+
+void RuleStateAction::update_rtn(RuleTreeNode* rtn)
+{
+    switch ( action )
+    {
+        case IpsPolicy::LOG: rtn->action = snort::Actions::Type::LOG; break;
+        case IpsPolicy::PASS: rtn->action = snort::Actions::Type::PASS; break;
+        case IpsPolicy::ALERT: rtn->action = snort::Actions::Type::ALERT; break;
+        case IpsPolicy::DROP: rtn->action = snort::Actions::Type::DROP; break;
+        case IpsPolicy::BLOCK: rtn->action = snort::Actions::Type::BLOCK; break;
+        case IpsPolicy::RESET: rtn->action = snort::Actions::Type::RESET; break;
+        case IpsPolicy::INHERIT_ACTION: break;
+    }
+}
+
+void RuleStateEnable::update_rtn(RuleTreeNode* rtn)
+{
+    switch( enable )
+    {
+        case IpsPolicy::FALSE: rtn->clear_enabled(); break;
+        case IpsPolicy::TRUE: rtn->set_enabled(); break;
+        case IpsPolicy::INHERIT_ENABLE: break;
+    }
+}
+
index 9cd60a9f4701830535acc3a3940840555c91eb00..83687b0fdb6ec825100527dd389943159e7cb87b 100644 (file)
 // FIXIT-L refactor this header
 
 #include "actions/actions.h"
-
-#define ANY_SRC_PORT    0x01
-#define ANY_DST_PORT    0x02
-#define ANY_FLAGS       0x04
-#define BIDIRECTIONAL   0x08
-#define ANY_SRC_IP      0x10
-#define ANY_DST_IP      0x20
+#include "main/policy.h"
 
 #define GID_DEFAULT          1
 #define GID_SESSION        135
 namespace snort
 {
     class IpsAction;
+    struct SnortConfig;
 }
 struct OutputSet;
+struct RuleTreeNode;
 
 struct ListHead
 {
@@ -67,12 +63,47 @@ struct RuleListNode
 };
 
 // for separately overriding rule type
-struct RuleState
+class RuleState
 {
-    uint32_t sid;
-    uint32_t gid;
-    int state;
-    RuleState* next;
+public:
+    RuleState(unsigned g, unsigned s) : gid(g), sid(s)
+    { policy = snort::get_ips_policy()->policy_id; }
+
+    virtual ~RuleState() = default;
+
+    void apply(snort::SnortConfig*);
+    virtual void update_rtn(RuleTreeNode*) = 0;
+
+private:
+    unsigned gid;
+    unsigned sid;
+    unsigned policy;
+
+    void apply(snort::SnortConfig*, OptTreeNode* otn, unsigned ips_num);
+    RuleTreeNode* find_updated_rtn(RuleTreeNode*, snort::SnortConfig*, unsigned ips_num);
+    void replace_rtn(OptTreeNode*, RuleTreeNode*, snort::SnortConfig*, unsigned ips_num);
+    RuleTreeNode* dup_rtn(OptTreeNode*, snort::SnortConfig*, unsigned ips_num);
+};
+
+class RuleStateAction : public RuleState
+{
+public:
+    RuleStateAction(unsigned g, unsigned s, IpsPolicy::Action a) : RuleState(g, s), action(a) { }
+    virtual void update_rtn(RuleTreeNode*) override;
+
+private:
+    IpsPolicy::Action action;
+    
+};
+
+class RuleStateEnable : public RuleState
+{
+public:
+    RuleStateEnable(unsigned g, unsigned s, IpsPolicy::Enable e) : RuleState(g, s), enable(e) { }
+    virtual void update_rtn(RuleTreeNode*) override;
+
+private:
+    IpsPolicy::Enable enable;
 };
 
 #endif
index 0479e64b889734adc9d43c3d768d3ebf99200754..eaeb66aa08364e1abab0ce5f3ad80afef2a1ff9b 100644 (file)
@@ -258,7 +258,7 @@ int fpCreateServiceMaps(SnortConfig* sc)
                     continue;
 
                 /* Not enabled, don't do the FP content */
-                if ( !otn->enabled )
+                if ( !rtn->enabled() )
                     continue;
 
                 for (svc_idx = 0; svc_idx < otn->sigInfo.num_services; svc_idx++)
index 3edc2bbeeff3eeac1b369c146105692d43bc3298..a7dc523a93a0d12564078f11c5c596761d3782e8 100644 (file)
@@ -177,12 +177,12 @@ void OtnFree(void* data)
     {
         OptFpList* tmp = opt_func;
         opt_func = opt_func->next;
-        snort_free(tmp);
+        snort_free(tmp); // FIXIT-L use c++ operators for all of this
     }
 
     if ( otn->sigInfo.message )
     {
-        if (!otn->generated)
+        if ( !otn->generated() )
             snort_free(otn->sigInfo.message);
     }
     for (unsigned svc_idx = 0; svc_idx < otn->sigInfo.num_services; svc_idx++)
@@ -211,14 +211,14 @@ void OtnFree(void* data)
 
     /* RTN was generated on the fly.  Don't necessarily know which policy
      * at this point so go through all RTNs and delete them */
-    if (otn->generated)
+    if ( otn->generated() )
     {
         for (int i = 0; i < otn->proto_node_num; i++)
         {
             RuleTreeNode* rtn = deleteRtnFromOtn(otn, i);
 
             if ( rtn )
-                snort_free(rtn);
+                delete rtn;
         }
     }
 
@@ -228,8 +228,8 @@ void OtnFree(void* data)
     if (otn->detection_filter)
         snort_free(otn->detection_filter);
 
-    snort_free(otn->state);
-    snort_free(otn);
+    delete[] otn->state;
+    delete otn;
 }
 
 GHash* OtnLookupNew()
index ace5d9f80f6648c6db1c94397405177bf9efe8b2..4a278abb875c4493f3547103f527f90ebbdeabba 100644 (file)
@@ -89,21 +89,21 @@ enum Target
 
 struct SigInfo
 {
-    char* message;
-    ClassType* class_type;
-    ReferenceNode* refs;
-    SignatureServiceInfo* services;
+    char* message = nullptr;
+    ClassType* class_type = nullptr;
+    ReferenceNode* refs = nullptr;
+    SignatureServiceInfo* services = nullptr;
 
-    uint32_t gid;
-    uint32_t sid;
-    uint32_t rev;
+    uint32_t gid = 0;
+    uint32_t sid = 0;
+    uint32_t rev = 0;
 
-    uint32_t class_id;
-    uint32_t priority;
-    uint32_t num_services;
+    uint32_t class_id = 0;
+    uint32_t priority = 0;
+    uint32_t num_services = 0;
 
-    bool builtin;
-    Target target;
+    bool builtin = false;
+    Target target = TARGET_NONE;
 };
 
 snort::GHash* OtnLookupNew();
index db3bae8843f67e7aa5c4599cd26da517a0d59981..1618f9a54b9e0f7459b9bcc68b78a574731c64ef 100644 (file)
@@ -72,91 +72,148 @@ struct OtnState
     { return elapsed > 0_ticks || checks > 0; }
 };
 
+/* function pointer list for rule head nodes */
+// FIXIT-L use bit mask to determine what header checks to do
+// cheaper than traversing a list and uses much less memory
+struct RuleFpList
+{
+    /* context data for this test */
+    void* context = nullptr;
+
+    /* rule check function pointer */
+    int (* RuleHeadFunc)(snort::Packet*, RuleTreeNode*, RuleFpList*, int) = nullptr;
+
+    /* pointer to the next rule function node */
+    RuleFpList* next = nullptr;
+};
+
+// one of these per rule per policy
+// represents head part of rule
+struct RuleTreeNode
+{
+    using Flag = uint8_t;
+    static constexpr Flag ENABLED       = 0x01;
+    static constexpr Flag ANY_SRC_PORT  = 0x02;
+    static constexpr Flag ANY_DST_PORT  = 0x04;
+    static constexpr Flag ANY_FLAGS     = 0x08;
+    static constexpr Flag BIDIRECTIONAL = 0x10;
+    static constexpr Flag ANY_SRC_IP    = 0x20;
+    static constexpr Flag ANY_DST_IP    = 0x40;
+
+    RuleFpList* rule_func = nullptr; /* match functions.. (Bidirectional etc.. ) */
+
+    sfip_var_t* sip = nullptr;
+    sfip_var_t* dip = nullptr;
+
+    PortObject* src_portobject = nullptr;
+    PortObject* dst_portobject = nullptr;
+
+    struct ListHead* listhead = nullptr;
+
+    SnortProtocolId snort_protocol_id = 0;
+
+    // reference count from otn.
+    // 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;
+
+    uint8_t flags = 0;
+
+    void set_enabled()
+    { flags |= ENABLED; }
+
+    void clear_enabled()
+    { flags &= (~ENABLED); }
+
+    bool enabled() const
+    { return flags & ENABLED; }
+};
+
 // one of these for each rule
 // represents body part of rule
 struct OptTreeNode
 {
-    /* plugin/detection functions go here */
-    OptFpList* opt_func;
-    OutputSet* outputFuncs; /* per sid enabled output functions */
-    snort::IpsOption* agent;
+    using Flag = uint8_t;
+    static constexpr Flag GENERATED     = 0x01;
+    static constexpr Flag WARNED_FP     = 0x02;
+    static constexpr Flag ESTABLISHED   = 0x04;
+    static constexpr Flag UNESTABLISHED = 0x08;
+    static constexpr Flag STATELESS     = 0x10;
 
     /* metadata about signature */
     SigInfo sigInfo;
-    char* soid;
+    char* soid = nullptr;
 
-    struct THD_NODE* detection_filter; /* if present, evaluated last, after header checks */
-    TagData* tag;
+    /* plugin/detection functions go here */
+    OptFpList* opt_func = nullptr;
+    OutputSet* outputFuncs = nullptr; /* per sid enabled output functions */
+    snort::IpsOption* agent = nullptr;
 
-    // ptr to list of RTNs (head part); indexed by policyId
-    RuleTreeNode** proto_nodes;
+    struct THD_NODE* detection_filter = nullptr; /* if present, evaluated last, after header checks */
+    TagData* tag = nullptr;
 
-    OtnState* state;
+    // ptr to list of RTNs (head part); indexed by policyId
+    RuleTreeNode** proto_nodes = nullptr;
 
-    int chain_node_number;
-    int evalIndex;       /* where this rule sits in the evaluation sets */
+    OtnState* state = nullptr;
 
-    // Added for integrity checks during rule parsing.
-    SnortProtocolId snort_protocol_id;
+    int chain_node_number = 0;
+    int evalIndex = 0;       /* where this rule sits in the evaluation sets */
 
-    unsigned ruleIndex; // unique index
+    unsigned ruleIndex = 0; // unique index
 
-    bool warned_fp;
-    bool enabled;
+    uint32_t num_detection_opts = 0;
+    uint32_t plugins = 0;
 
-    uint32_t num_detection_opts;
-    uint32_t plugins;
+    // Added for integrity checks during rule parsing.
+    SnortProtocolId snort_protocol_id = 0;
 
     /**number of proto_nodes. */
-    unsigned short proto_node_num;
+    unsigned short proto_node_num = 0;
 
-    uint16_t longestPatternLen;
+    uint16_t longestPatternLen = 0;
 
-    uint8_t stateless;  /* this rule can fire regardless of session state */
-    uint8_t established; /* this rule can only fire if it is established */
-    uint8_t unestablished;
+    Flag flags = 0;
 
-    char generated;
-};
+    void set_generated()
+    { flags |= GENERATED; }
 
-/* function pointer list for rule head nodes */
-// FIXIT-L use bit mask to determine what header checks to do
-// cheaper than traversing a list and uses much less memory
-struct RuleFpList
-{
-    /* context data for this test */
-    void* context;
+    bool generated() const
+    { return flags & GENERATED; }
 
-    /* rule check function pointer */
-    int (* RuleHeadFunc)(snort::Packet*, RuleTreeNode*, RuleFpList*, int);
+    void set_warned_fp()
+    { flags |= WARNED_FP; }
 
-    /* pointer to the next rule function node */
-    RuleFpList* next;
-};
+    bool warned_fp() const
+    { return flags & WARNED_FP; }
 
-// one of these per rule per policy
-// represents head part of rule
-struct RuleTreeNode
-{
-    RuleFpList* rule_func; /* match functions.. (Bidirectional etc.. ) */
+    void set_established()
+    { flags |= ESTABLISHED; }
 
-    sfip_var_t* sip;
-    sfip_var_t* dip;
+    void set_unestablished()
+    { flags |= UNESTABLISHED; }
 
-    PortObject* src_portobject;
-    PortObject* dst_portobject;
+    void set_stateless()
+    { flags |= STATELESS; }
 
-    struct ListHead* listhead;
+    bool established() const
+    { return flags & ESTABLISHED; }
 
-    SnortProtocolId snort_protocol_id;
+    bool unestablished() const
+    { return flags & UNESTABLISHED; }
 
-    uint32_t flags;     /* control flags */
+    bool stateless() const
+    { return flags & STATELESS; }
 
-    snort::Actions::Type type;
+    bool enabled_somewhere() const
+    {
+        for ( unsigned i = 0; i < proto_node_num; i++ )
+            if ( proto_nodes[i] and proto_nodes[i]->enabled() )
+                return true;
 
-    // reference count from otn.
-    // Multiple OTNs can reference this RTN with the same policy.
-    unsigned int otnRefCount;
+        return false;
+    }
 };
 
 typedef int (* RuleOptEvalFunc)(void*, Cursor&, snort::Packet*);
index 28e354241aef67e0958fb80190a73b11b1e603f3..2b0327801d10d6da7b18725a604ea451dd80f357 100644 (file)
@@ -67,6 +67,13 @@ struct SO_PUBLIC Parameter
     const void* range;  // nullptr|const char*|RangeQuery*|const Parameter*
     const char* deflt;
     const char* help;
+    bool regex = false; // for name resolution
+
+    Parameter(const char* n, Type t, const void* r, const char* d, const char* h, bool re) :
+        name(n), type(t), range(r), deflt(d), help(h), regex(re) { }
+
+    Parameter(const char* n, Type t, const void* r, const char* d, const char* h) :
+        name(n), type(t), range(r), deflt(d), help(h) { }
 
     const char* get_type() const;
     const char* get_range() const;
index 858d6bf0527f12cc73e336b17c45ac6548c4d042..a4c4927523584bb5b42da8209c55e8d01614a882 100644 (file)
@@ -410,13 +410,13 @@ static IpsOption* flow_ctor(Module* p, OptTreeNode* otn)
     FlowModule* m = (FlowModule*)p;
 
     if ( m->data.stateless )
-        otn->stateless = 1;
+        otn->set_stateless();
 
     if ( m->data.established )
-        otn->established = 1;
+        otn->set_established();
 
     if ( m->data.unestablished )
-        otn->unestablished = 1;
+        otn->set_unestablished();
 
     if (otn->snort_protocol_id == SNORT_PROTO_ICMP)
     {
index a0f11bfc8f4586221656940f8a9ca78ec9a6a174..db95f977a83b1216905b89bb1e21ffcab69aa02b 100755 (executable)
@@ -24,6 +24,8 @@
 
 #include "modules.h"
 
+#include <regex>
+
 #include "codecs/codec_module.h"
 #include "detection/fp_config.h"
 #include "filters/detection_filter.h"
@@ -72,6 +74,12 @@ static const Parameter detection_params[] =
     { "asn1", Parameter::PT_INT, "0:65535", "0",
       "maximum decode nodes" },
 
+    { "global_default_rule_state", Parameter::PT_BOOL, nullptr, "true",
+      "enable or disable rules by default (overridden by ips policy settings)" },
+
+    { "global_rule_state", Parameter::PT_BOOL, nullptr, "false",
+      "apply rule_state against all policies" },
+
     { "offload_limit", Parameter::PT_INT, "0:max32", "99999",
       "minimum sizeof PDU to offload fast pattern search (defaults to disabled)" },
 
@@ -119,6 +127,12 @@ bool DetectionModule::set(const char* fqn, Value& v, SnortConfig* sc)
     if ( v.is("asn1") )
         sc->asn1_mem = v.get_uint16();
 
+    else if ( v.is("global_default_rule_state") )
+        sc->global_default_rule_state = v.get_bool();
+
+    else if ( v.is("global_rule_state") )
+        sc->global_rule_state = v.get_bool();
+
     else if ( v.is("offload_limit") )
         sc->offload_limit = v.get_uint32();
 
@@ -664,9 +678,6 @@ static const Parameter alerts_params[] =
     { "alert_with_interface_name", Parameter::PT_BOOL, nullptr, "false",
       "include interface in alert info (fast, full, or syslog only)" },
 
-    { "default_rule_state", Parameter::PT_BOOL, nullptr, "true",
-      "enable or disable ips rules" },
-
     { "detection_filter_memcap", Parameter::PT_INT, "0:max32", "1048576",
       "set available MB of memory for detection_filters" },
 
@@ -713,9 +724,6 @@ bool AlertsModule::set(const char*, Value& v, SnortConfig* sc)
     if ( v.is("alert_with_interface_name") )
         v.update_mask(sc->output_flags, OUTPUT_FLAG__ALERT_IFACE);
 
-    else if ( v.is("default_rule_state") )
-        sc->default_rule_state = v.get_bool();
-
     else if ( v.is("detection_filter_memcap") )
         sc->detection_filter_config->memcap = v.get_uint32();
 
@@ -1210,6 +1218,9 @@ bool InspectionModule::set(const char*, Value& v, SnortConfig* sc)
 
 static const Parameter ips_params[] =
 {
+    { "default_rule_state", Parameter::PT_ENUM, "false | true | inherit", "inherit",
+      "enable or disable ips rules" },
+
     { "enable_builtin_rules", Parameter::PT_BOOL, nullptr, "false",
       "enable events from builtin rules w/o stubs" },
 
@@ -1254,7 +1265,10 @@ bool IpsModule::set(const char*, Value& v, SnortConfig* sc)
 {
     IpsPolicy* p = get_ips_policy();
 
-    if ( v.is("enable_builtin_rules") )
+    if ( v.is("default_rule_state") )
+        p->default_rule_state = (IpsPolicy::Enable)v.get_uint8();
+
+    else if ( v.is("enable_builtin_rules") )
         p->enable_builtin_rules = v.get_bool();
 
     else if ( v.is("id") )
@@ -1711,68 +1725,73 @@ bool RateFilterModule::end(const char*, int idx, SnortConfig* sc)
 // rule_state module
 //-------------------------------------------------------------------------
 
-static const Parameter rule_state_params[] =
+static const Parameter single_rule_state_params[] =
 {
-    { "gid", Parameter::PT_INT, "0:max32", "0",
-      "rule generator ID" },
+    { "action", Parameter::PT_ENUM, "log | pass | alert | drop | block | reset | inherit", "inherit",
+      "apply action if rule matches or inherit from rule definition" },
 
-    { "sid", Parameter::PT_INT, "0:max32", "0",
-      "rule signature ID" },
+    { "enable", Parameter::PT_ENUM, "false | true | inherit", "inherit",
+      "enable or disable rule in current ips policy or use default defined by ips policy" },
 
-    { "enable", Parameter::PT_BOOL, nullptr, "true",
-      "enable or disable rule in all policies" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static const char* rule_state_gid_sid_regex = "([0-9]+):([0-9]+)";
+static const Parameter rule_state_params[] =
+{
+    { rule_state_gid_sid_regex, Parameter::PT_TABLE, single_rule_state_params, nullptr,
+      "defines rule state parameters for gid:sid", true },
 
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 
 #define rule_state_help \
-    "enable/disable specific IPS rules"
+    "enable/disable and set actions for specific IPS rules"
 
 class RuleStateModule : public Module
 {
 public:
-    RuleStateModule() : Module("rule_state", rule_state_help, rule_state_params, true) { }
+    RuleStateModule() : Module("rule_state", rule_state_help, rule_state_params, false) { }
     bool set(const char*, Value&, SnortConfig*) override;
-    bool begin(const char*, int, SnortConfig*) override;
-    bool end(const char*, int, SnortConfig*) override;
 
     Usage get_usage() const override
     { return DETECT; }
-
-private:
-    RuleState state;
 };
 
-bool RuleStateModule::set(const char*, Value& v, SnortConfig*)
+bool RuleStateModule::set(const char* fqn, Value& v, SnortConfig* sc)
 {
-    if ( v.is("gid") )
-        state.gid = v.get_uint32();
+    static regex gid_sid(rule_state_gid_sid_regex);
 
-    else if ( v.is("sid") )
-        state.sid = v.get_uint32();
+    // the regex itself is passed as the fqn when declaring rule_state = { }
+    if ( strstr(fqn, rule_state_gid_sid_regex) )
+        return true;
+
+    cmatch match;
 
-    else if ( v.is("enable") )
-        state.state = v.get_bool();
+    if ( regex_search(fqn, match, gid_sid) )
+    {
+        unsigned gid = strtoul(match[1].str().c_str(), nullptr, 10);
+        unsigned sid = strtoul(match[2].str().c_str(), nullptr, 10);
 
+        if ( v.is("action") )
+        {
+            sc->rule_states.emplace_back(
+                new RuleStateAction(gid, sid, IpsPolicy::Action(v.get_uint8())));
+        }
+        else if ( v.is("enable") )
+        {
+            sc->rule_states.emplace_back(
+                new RuleStateEnable(gid, sid, IpsPolicy::Enable(v.get_uint8())));
+        }
+        else
+            return false;
+    }
     else
         return false;
 
     return true;
 }
 
-bool RuleStateModule::begin(const char*, int, SnortConfig*)
-{
-    memset(&state, 0, sizeof(state));
-    return true;
-}
-
-bool RuleStateModule::end(const char*, int idx, SnortConfig* sc)
-{
-    if ( idx )
-        AddRuleState(sc, state);
-    return true;
-}
-
 //-------------------------------------------------------------------------
 // hosts module
 //-------------------------------------------------------------------------
index 9b47dcc1c5a5d57ff9e791b006c18507349195da..ec67d24644a7c371dff48d41c91dc61f0b64da68 100644 (file)
@@ -136,6 +136,9 @@ private:
 struct IpsPolicy
 {
 public:
+    enum Action : uint8_t { LOG, PASS, ALERT, DROP, BLOCK, RESET, INHERIT_ACTION };
+    enum Enable : uint8_t { FALSE, TRUE, INHERIT_ENABLE };
+
     IpsPolicy(PolicyId = 0);
     ~IpsPolicy();
 
@@ -159,6 +162,8 @@ public:
     PortVarTable* portVarTable;     /* named entries, uses a hash table */
     PortTable* nonamePortVarTable;  /* un-named entries */
 
+    Enable default_rule_state = INHERIT_ENABLE;
+
     bool obfuscate_pii;
 };
 
index d71668be651523e8ce7369fc441f8fe2086a976e..d632719c3f95ce777024bfc955403519c37c5fa9 100644 (file)
@@ -245,7 +245,6 @@ SnortConfig::~SnortConfig()
         return;
     }
 
-    free_rule_state_list();
     FreeClassifications(classifications);
     FreeReferences(references);
 
@@ -330,7 +329,8 @@ void SnortConfig::setup()
     //print_thresholding(threshold_config, 0);
     //PrintRuleOrder(rule_lists);
 
-    SetRuleStates(this);
+    for ( auto& state : rule_states )
+        state->apply(this);
 
     /* Need to do this after dynamic detection stuff is initialized, too */
     IpsManager::verify(this);
@@ -1050,19 +1050,6 @@ void SnortConfig::enable_syslog()
     syslog_configured = true;
 }
 
-void SnortConfig::free_rule_state_list()
-{
-    RuleState* head = rule_state_list;
-
-    while ( head )
-    {
-        RuleState* tmp = head;
-        head = head->next;
-        snort_free(tmp);
-    }
-    rule_state_list = nullptr;
-}
-
 bool SnortConfig::tunnel_bypass_enabled(uint8_t proto)
 {
     return (!((get_conf()->tunnel_mask & proto) or SFDAQ::get_tunnel_bypass(proto)));
index e95f3fc1489064b89db747b90f2e93fb232a6c02..3bae004fc88ae9b966005342d50a094220262755 100644 (file)
@@ -125,7 +125,7 @@ struct LatencyConfig;
 struct PORT_RULE_MAP;
 struct RuleListNode;
 struct RulePortTables;
-struct RuleState;
+class RuleState;
 struct DetectionFilterConfig;
 struct EventQueueConfig;
 struct IpsActionsConfig;
@@ -179,7 +179,6 @@ public:
     //------------------------------------------------------
     // alert module stuff
     std::string rule_order;
-    bool default_rule_state = true;
 
     SfCidr homenet;
 
@@ -216,6 +215,9 @@ public:
     unsigned offload_limit = 99999;  // disabled
     unsigned offload_threads = 0;    // disabled
 
+    bool global_rule_state = false;
+    bool global_default_rule_state = true;
+
     //------------------------------------------------------
     // process stuff
 
@@ -306,7 +308,7 @@ public:
 
     int thiszone = 0;
 
-    RuleState* rule_state_list = nullptr;
+    std::vector<RuleState*> rule_states;
     ClassType* classifications = nullptr;
     ReferenceSystemNode* references = nullptr;
     GHash* otn_map = nullptr;
@@ -422,7 +424,6 @@ public:
     void set_umask(uint32_t);
     void set_utc(bool);
     void set_verbose(bool);
-    void free_rule_state_list();
 
     //------------------------------------------------------
     // Static convenience accessor methods
@@ -499,8 +500,21 @@ public:
     static int get_eval_index(Actions::Type type)
     { return get_conf()->evalOrder[type]; }
 
-    static int get_default_rule_state()
-    { return get_conf()->default_rule_state; }
+    static bool get_default_rule_state()
+    {
+        switch ( get_ips_policy()->default_rule_state )
+        {
+            case IpsPolicy::INHERIT_ENABLE:
+                return get_conf()->global_default_rule_state;
+
+            case IpsPolicy::TRUE:
+                return true;
+
+            case IpsPolicy::FALSE:
+                return false;
+        }
+        return true;
+    }
 
     SO_PUBLIC static bool tunnel_bypass_enabled(uint8_t proto);
 
index 166d316971c8ccabd2a36d3a87abe381b9aa5f2b..60809a08bb274933397374574161b21c842c625f 100644 (file)
@@ -29,6 +29,7 @@
 #include <cassert>
 #include <iostream>
 #include <mutex>
+#include <regex>
 #include <stack>
 #include <string>
 
@@ -346,8 +347,16 @@ static const Parameter* get_params(
     }
 
     string name = new_fqn.substr(0, new_fqn.find_first_of('.'));
-    while ( p->name && name != p->name )
+    while ( p->name )
+    {
+        if ( p->regex && regex_match(name, regex(p->name)) )
+            break;
+
+        else if ( name == p->name )
+            break;
+
         ++p;
+    }
 
     if ( !p->name )
         return nullptr;
index 35a4faea3eea866749ed261f733fcf4677dca5bf..ee22c790568d1f4ff7dc0f359a0fe40247f84bfc 100644 (file)
@@ -232,25 +232,6 @@ ListHead* get_rule_list(SnortConfig* sc, const char* s)
     return p ? p->RuleList : nullptr;
 }
 
-void AddRuleState(SnortConfig* sc, const RuleState& rs)  // FIXIT-L move to snort config
-{
-    if (sc == nullptr)
-        return;
-
-    RuleState* state = (RuleState*)snort_calloc(sizeof(RuleState));
-    *state = rs;
-
-    if ( !sc->rule_state_list )
-    {
-        sc->rule_state_list = state;
-    }
-    else
-    {
-        state->next = sc->rule_state_list;
-        sc->rule_state_list = state;
-    }
-}
-
 void ParseConfigFile(SnortConfig* sc, const char* fname)
 {
     if ( !fname )
index aa0adb01c5629334160ec05dd79fc31cf13b1e34..e28e4f21a9edf7d6e3a49064fdede81840c809e3 100644 (file)
@@ -37,7 +37,6 @@ void ParseConfigString(snort::SnortConfig*, const char* str);
 void ParseIpVar(snort::SnortConfig*, const char* name, const char* s);
 void parse_include(snort::SnortConfig*, const char*);
 
-void AddRuleState(snort::SnortConfig*, const RuleState&);
 void add_service_to_otn(snort::SnortConfig*, OptTreeNode*, const char*);
 
 snort::Actions::Type get_rule_type(const char*);
index 605b0d9ceb47971d7e724ceafd3db8971fec8a18..5badae03e33b2763b5168d93d61d2042214054db 100644 (file)
@@ -142,14 +142,14 @@ static int FinishPortListRule(
         break;
 
     default:
-        rtn->flags |= ANY_SRC_PORT|ANY_DST_PORT;
+        rtn->flags |= RuleTreeNode::ANY_SRC_PORT|RuleTreeNode::ANY_DST_PORT;
         dstTable = srcTable = nullptr;
         aaObject = port_tables->svc_any;
         prc = &svcCnt;
     }
 
     /* Count rules with both src and dst specific ports */
-    if (!(rtn->flags & ANY_DST_PORT) && !(rtn->flags & ANY_SRC_PORT))
+    if (!(rtn->flags & RuleTreeNode::ANY_DST_PORT) && !(rtn->flags & RuleTreeNode::ANY_SRC_PORT))
     {
         prc->both++;
     }
@@ -157,19 +157,19 @@ static int FinishPortListRule(
     /* If not an any-any rule test for port bleedover, if we are using a
      * single rule group, don't bother */
     if (!fp->get_single_rule_group() &&
-        (rtn->flags & (ANY_DST_PORT|ANY_SRC_PORT)) != (ANY_DST_PORT|ANY_SRC_PORT))
+        (rtn->flags & (RuleTreeNode::ANY_DST_PORT|RuleTreeNode::ANY_SRC_PORT)) != (RuleTreeNode::ANY_DST_PORT|RuleTreeNode::ANY_SRC_PORT))
     {
         int dst_cnt = 0;
         int src_cnt = 0;
 
-        if (!(rtn->flags & ANY_SRC_PORT))
+        if (!(rtn->flags & RuleTreeNode::ANY_SRC_PORT))
         {
             src_cnt = PortObjectPortCount(rtn->src_portobject);
             if (src_cnt >= fp->get_bleed_over_port_limit())
                 large_port_group = 1;
         }
 
-        if (!(rtn->flags & ANY_DST_PORT))
+        if (!(rtn->flags & RuleTreeNode::ANY_DST_PORT))
         {
             dst_cnt = PortObjectPortCount(rtn->dst_portobject);
             if (dst_cnt >= fp->get_bleed_over_port_limit())
@@ -198,7 +198,7 @@ static int FinishPortListRule(
      * any-any port rules...
      * If we have an any-any rule or a large port group or
      * were using a single rule group we make it an any-any rule. */
-    if (((rtn->flags & (ANY_DST_PORT|ANY_SRC_PORT)) == (ANY_DST_PORT|ANY_SRC_PORT)) ||
+    if (((rtn->flags & (RuleTreeNode::ANY_DST_PORT|RuleTreeNode::ANY_SRC_PORT)) == (RuleTreeNode::ANY_DST_PORT|RuleTreeNode::ANY_SRC_PORT)) ||
         large_port_group || fp->get_single_rule_group())
     {
         if (snort_protocol_id == SNORT_PROTO_IP)
@@ -247,7 +247,7 @@ static int FinishPortListRule(
     }
 
     /* add rule index to dst table if we have a specific dst port or port list */
-    if (!(rtn->flags & ANY_DST_PORT))
+    if (!(rtn->flags & RuleTreeNode::ANY_DST_PORT))
     {
         prc->dst++;
 
@@ -270,7 +270,7 @@ static int FinishPortListRule(
         PortObjectAddRule(pox, otn->ruleIndex);
 
         /* if bidir, add this rule and port group to the src table */
-        if (rtn->flags & BIDIRECTIONAL)
+        if (rtn->flags & RuleTreeNode::BIDIRECTIONAL)
         {
             pox = PortTableFindInputPortObjectPorts(srcTable, rtn->dst_portobject);
             if ( !pox )
@@ -290,7 +290,7 @@ static int FinishPortListRule(
     }
 
     /* add rule index to src table if we have a specific src port or port list */
-    if (!(rtn->flags & ANY_SRC_PORT))
+    if (!(rtn->flags & RuleTreeNode::ANY_SRC_PORT))
     {
         prc->src++;
         PortObject* pox = PortTableFindInputPortObjectPorts(srcTable, rtn->src_portobject);
@@ -309,7 +309,7 @@ static int FinishPortListRule(
         PortObjectAddRule(pox, otn->ruleIndex);
 
         /* if bidir, add this rule and port group to the dst table */
-        if (rtn->flags & BIDIRECTIONAL)
+        if (rtn->flags & RuleTreeNode::BIDIRECTIONAL)
         {
             pox = PortTableFindInputPortObjectPorts(dstTable, rtn->src_portobject);
             if ( !pox )
@@ -401,7 +401,7 @@ static int ProcessIP(SnortConfig*, const char* addr, RuleTreeNode* rtn, int mode
 
         if (rtn->sip->head && rtn->sip->head->flags & SFIP_ANY)
         {
-            rtn->flags |= ANY_SRC_IP;
+            rtn->flags |= RuleTreeNode::ANY_SRC_IP;
         }
     }
     /* mode == DST */
@@ -456,7 +456,7 @@ static int ProcessIP(SnortConfig*, const char* addr, RuleTreeNode* rtn, int mode
 
         if (rtn->dip->head && rtn->dip->head->flags & SFIP_ANY)
         {
-            rtn->flags |= ANY_DST_IP;
+            rtn->flags |= RuleTreeNode::ANY_DST_IP;
         }
     }
 
@@ -589,9 +589,9 @@ static int ParsePortList(
     if ( PortObjectHasAny(portobject) )
     {
         if ( dst_flag )
-            rtn->flags |= ANY_DST_PORT;
+            rtn->flags |= RuleTreeNode::ANY_DST_PORT;
         else
-            rtn->flags |= ANY_SRC_PORT;
+            rtn->flags |= RuleTreeNode::ANY_SRC_PORT;
     }
 
     /* check for a pure not rule - fatal if we find one */
@@ -619,7 +619,7 @@ bool same_headers(RuleTreeNode* rule, RuleTreeNode* rtn)
     if ( !rule or !rtn )
         return false;
 
-    if (rule->type != rtn->type)
+    if (rule->action != rtn->action)
         return false;
 
     if (rule->snort_protocol_id != rtn->snort_protocol_id)
@@ -666,7 +666,7 @@ static RuleTreeNode* findHeadNode(
 static void XferHeader(RuleTreeNode* from, RuleTreeNode* to)
 {
     to->flags = from->flags;
-    to->type = from->type;
+    to->action = from->action;
     to->sip = from->sip;
     to->dip = from->dip;
 
@@ -691,7 +691,7 @@ static void AddRuleFuncToList(
 
     if ( !idx )
     {
-        rtn->rule_func = (RuleFpList*)snort_calloc(sizeof(RuleFpList));
+        rtn->rule_func = new RuleFpList;
         rtn->rule_func->RuleHeadFunc = rfunc;
     }
     else
@@ -699,7 +699,7 @@ static void AddRuleFuncToList(
         while ( idx->next )
             idx = idx->next;
 
-        idx->next = (RuleFpList*)snort_calloc(sizeof(RuleFpList));
+        idx->next = new RuleFpList;
         idx = idx->next;
         idx->RuleHeadFunc = rfunc;
     }
@@ -722,14 +722,14 @@ static void AddrToFunc(RuleTreeNode* rtn, int mode)
     switch (mode)
     {
     case SRC:
-        if ((rtn->flags & ANY_SRC_IP) == 0)
+        if ((rtn->flags & RuleTreeNode::ANY_SRC_IP) == 0)
         {
             AddRuleFuncToList(CheckSrcIP, rtn);
         }
         break;
 
     case DST:
-        if ((rtn->flags & ANY_DST_IP) == 0)
+        if ((rtn->flags & RuleTreeNode::ANY_DST_IP) == 0)
         {
             AddRuleFuncToList(CheckDstIP, rtn);
         }
@@ -788,14 +788,14 @@ static void PortToFunc(RuleTreeNode* rtn, int any_flag, int except_flag, int mod
 // functions (addrs and ports)
 static void SetupRTNFuncList(RuleTreeNode* rtn)
 {
-    if (rtn->flags & BIDIRECTIONAL)
+    if (rtn->flags & RuleTreeNode::BIDIRECTIONAL)
     {
         AddRuleFuncToList(CheckBidirectional, rtn);
     }
     else
     {
-        PortToFunc(rtn, (rtn->flags & ANY_DST_PORT) ? 1 : 0, 0, DST);
-        PortToFunc(rtn, (rtn->flags & ANY_SRC_PORT) ? 1 : 0, 0, SRC);
+        PortToFunc(rtn, (rtn->flags & RuleTreeNode::ANY_DST_PORT) ? 1 : 0, 0, DST);
+        PortToFunc(rtn, (rtn->flags & RuleTreeNode::ANY_SRC_PORT) ? 1 : 0, 0, SRC);
 
         AddrToFunc(rtn, SRC);
         AddrToFunc(rtn, DST);
@@ -817,7 +817,7 @@ static RuleTreeNode* ProcessHeadNode(
     {
         head_count++;
 
-        rtn = (RuleTreeNode*)snort_calloc(sizeof(RuleTreeNode));
+        rtn = new RuleTreeNode;
         rtn->otnRefCount++;
 
         /* copy the prototype header info into the new header block */
@@ -854,7 +854,7 @@ static int mergeDuplicateOtn(
 
     RuleTreeNode* rtn_cur = getRtnFromOtn(otn_cur);
 
-    if ( rtn_cur and rtn_cur->type != rtn_new->type )
+    if ( rtn_cur and rtn_cur->action != rtn_new->action )
     {
         ParseError("GID %u SID %u in rule duplicates previous rule, with different type.",
             otn_new->sigInfo.gid, otn_new->sigInfo.sid);
@@ -988,10 +988,10 @@ void parse_rule_print()
 
 void parse_rule_type(SnortConfig* sc, const char* s, RuleTreeNode& rtn)
 {
-    memset(&rtn, 0, sizeof(rtn));
-    rtn.type = get_rule_type(s);
+    rtn = RuleTreeNode();
+    rtn.action = get_rule_type(s);
 
-    if ( rtn.type == Actions::NONE )
+    if ( rtn.action == Actions::NONE )
     {
         s_ignore = true;
         return;
@@ -1002,9 +1002,11 @@ void parse_rule_type(SnortConfig* sc, const char* s, RuleTreeNode& rtn)
 
         if ( !rtn.listhead )
         {
-            CreateRuleType(sc, s, rtn.type);
+            CreateRuleType(sc, s, rtn.action);
             rtn.listhead = get_rule_list(sc, s);
         }
+        if ( SnortConfig::get_default_rule_state() )
+            rtn.set_enabled();
     }
 
     if ( !rtn.listhead )
@@ -1070,7 +1072,7 @@ void parse_rule_dir(SnortConfig*, const char* s, RuleTreeNode& rtn)
         return;
 
     if (strcmp(s, "<>") == 0)
-        rtn.flags |= BIDIRECTIONAL;
+        rtn.flags |= RuleTreeNode::BIDIRECTIONAL;
 
     else if ( strcmp(s, "->") )
         ParseError("illegal direction specifier: %s", s);
@@ -1119,15 +1121,17 @@ OptTreeNode* parse_rule_open(SnortConfig* sc, RuleTreeNode& rtn, bool stub)
         parse_rule_nets(sc, "any", false, rtn);
         parse_rule_ports(sc, "any", false, rtn);
     }
-    OptTreeNode* otn = (OptTreeNode*)snort_calloc(sizeof(OptTreeNode));
-    otn->state = (OtnState*)snort_calloc(ThreadConfig::get_instance_max(), sizeof(OtnState));
+    OptTreeNode* otn = new OptTreeNode;
+    otn->state = new OtnState[ThreadConfig::get_instance_max()];
 
     if ( !stub )
         otn->sigInfo.gid = GID_DEFAULT;
 
     otn->chain_node_number = otn_count;
     otn->snort_protocol_id = rtn.snort_protocol_id;
-    otn->enabled = SnortConfig::get_default_rule_state();
+
+    if ( SnortConfig::get_default_rule_state() )
+        rtn.set_enabled();
 
     IpsManager::reset_options();
 
index 11e28ddcf9907c03df3ec00b329d9af720834df4..2967fd8b8817e5c1ecb9cb44c5bb2af44b6f9cfb 100644 (file)
@@ -85,7 +85,7 @@ static void FreeRuleTreeNodes(SnortConfig* sc)
 
         /* Autogenerated OTNs along with their respective pseudo RTN
          * will get cleaned up when the OTN is freed */
-        if (otn->generated)
+        if ( otn->generated() )
             continue;
 
         for (policyId = 0;
@@ -277,7 +277,10 @@ void parser_term(SnortConfig* sc)
     parse_rule_term();
     RuleIndexMapFree(ruleIndexMap);
     ruleIndexMap = nullptr;
-    sc->free_rule_state_list();
+
+    for ( auto& r : sc->rule_states )
+        delete r;
+    sc->rule_states.clear();
 }
 
 SnortConfig* ParseSnortConf(const SnortConfig* boot_conf, const char* fname, bool is_fatal)
@@ -361,7 +364,7 @@ void FreeRuleTreeNode(RuleTreeNode* rtn)
     {
         RuleFpList* tmp = idx;
         idx = idx->next;
-        snort_free(tmp);
+        delete tmp;
     }
 }
 
@@ -376,36 +379,7 @@ void DestroyRuleTreeNode(RuleTreeNode* rtn)
 
     FreeRuleTreeNode(rtn);
 
-    snort_free(rtn);
-}
-
-/****************************************************************************
- * Purpose: Adjust the information for a given rule
- *          relative to the Rule State list
- *****************************************************************************/
-void SetRuleStates(SnortConfig* sc)
-{
-    RuleState* rule_state;
-
-    if (sc == nullptr)
-        return;
-
-    /* First, cycle through the rule state list and update the
-     * rule state for each one we find. */
-    for (rule_state = sc->rule_state_list; rule_state != nullptr; rule_state = rule_state->next)
-    {
-        /* Lookup the OTN by ruleState->sid, ruleState->gid */
-        OptTreeNode* otn = OtnLookup(sc->otn_map, rule_state->gid, rule_state->sid);
-
-        if (otn == nullptr)
-        {
-            ParseError("Rule state specified for invalid SID: %u GID: %u",
-                rule_state->sid, rule_state->gid);
-            return;
-        }
-
-        otn->enabled = rule_state->state;
-    }
+    delete rtn;
 }
 
 void ParseRules(SnortConfig* sc)
@@ -637,7 +611,7 @@ static uint32_t rtn_hash_func(HashFnc*, const unsigned char* k, int)
     const RuleTreeNodeKey* rtnk = (const RuleTreeNodeKey*)k;
     RuleTreeNode* rtn = rtnk->rtn;
 
-    a = rtn->type;
+    a = rtn->action;
     b = rtn->flags;
     c = (uint32_t)(uintptr_t)rtn->listhead;
 
index f435d10be6e81c4985f3626a773f1844712f1fb8..81b1b3e039d2806e46526efdff811513dc1e9a34 100644 (file)
@@ -41,16 +41,16 @@ bool DefaultRuleState::convert(std::istringstream& data_stream)
     bool retval = true;
     std::string val;
 
-    table_api.open_table("alerts");
+    table_api.open_table("detection");
 
     if (data_stream >> val &&
         util::case_compare(val, "disabled"))
     {
-        table_api.add_option("default_rule_state", false);
+        table_api.add_option("global_default_rule_state", false);
     }
     else
     {
-        table_api.add_option("default_rule_state", true);
+        table_api.add_option("global_default_rule_state", true);
     }
 
     table_api.close_table();
index d0874ec4a42be6519a2a3f23509a13adc5551991..bb25e76fb112244208f581cd59207ed1e59bfe86 100644 (file)
@@ -51,6 +51,15 @@ Table::Table(const std::string& table_name, int d)
         Comments::CommentType::SINGLE_LINE);
 }
 
+Table::Table(const std::string& table_name, const std::string& key, int d)
+{
+    this->name = table_name;
+    this->key = key;
+    this->depth = d;
+    this->comments = new Comments(d + 1,
+        Comments::CommentType::SINGLE_LINE);
+}
+
 Table::~Table()
 {
     for ( Table* t : tables)
@@ -254,7 +263,12 @@ std::ostream& operator<<(std::ostream& out, const Table& t)
         if ( t.print_whitespace )
             out << whitespace;
 
-        out << t.name << (t.one_line ? " = " : " =\n");
+        out << t.name;
+
+        if ( !t.key.empty() )
+            out << "[\"" << t.key << "\"]";
+        
+        out << (t.one_line ? " = " : " =\n");
     }
 
     out << (t.print_whitespace ? whitespace : "")
index 7e7fdf24c28f748b3506190d76074190be8f7ef8..c0d9f8bdfc6b1e05d0064a0de81275d272c5dc8c 100644 (file)
@@ -33,6 +33,7 @@ class Table
 public:
     Table(int depth);
     Table(const std::string& name, int depth);
+    Table(const std::string& name, const std::string& key, int depth);
     virtual ~Table();
 
     inline const std::string& get_name() { return name; }
@@ -61,6 +62,7 @@ public:
 
 private:
     std::string name;
+    std::string key;
     bool one_line = false;
     bool print_whitespace = true;
 
index 40edcc4a89e5ca71cb4a9e156d73529438b266fa..10c6f3cbffa787b86d3958c48cdaadde0381f7c0 100644 (file)
@@ -148,6 +148,20 @@ void TableApi::open_table(bool one_line)
     }
 }
 
+void TableApi::open_associative_table(const char* name, const char* key)
+{
+    if ( should_delegate(name) )
+    {
+        delegate->open_associative_table(name, key);
+        delegating++;
+        return;
+    }
+
+    Table* t = new Table(name, key, 0);
+    tables.push_back(t);
+    open_tables.push(t);
+}
+
 void TableApi::close_table()
 {
     if ( should_delegate() )
index 6fc745561b2470f97fdd546c850da5f969184f64..a7c6dbe716a4f02c6a92a3439e614246157a9688 100644 (file)
@@ -87,6 +87,9 @@ public:
 // open a nested table that does not contain a name --> {...})
     void open_table(bool one_line = false);
 
+// open a table using the syntax name["key"] = {...}
+    void open_associative_table(const char* name, const char* key);
+
 // close the nested table.  go to previous table level
     void close_table();
 
index 07064dfdd970c6833a22b9094e9fe2d36633eed0..67b4c51c310801cc3988690bb57023cb756bd176 100644 (file)
@@ -46,8 +46,9 @@ TableDelegation table_delegation =
     { "ips", true },
     { "network", true },
     { "normalizer", true },
-    { "stream_tcp", true},
-    { "suppress", true},
+    { "rule_state", true },
+    { "stream_tcp", true },
+    { "suppress", true },
 };
 
 std::string Converter::ips_pattern;
index 44a7948265b232f9610dd592668c4d96258c517a..6519fa1c34533ca15072f8889f27548fab945c0a 100644 (file)
@@ -36,38 +36,48 @@ public:
 };
 } // namespace
 
+using namespace std;
+
 bool RuleState::convert(std::istringstream& data_stream)
 {
+    static bool did_preamble = false;
+
     std::string arg;
     bool retval = true;
     int count = 0;
 
-    table_api.open_table("rule_state");
-    table_api.open_table();
+    if ( !did_preamble )
+    {
+        did_preamble = true;
+        table_api.open_table("detection");
+        table_api.add_option("global_rule_state", true);
+        table_api.close_table();
+        table_api.open_table("rule_state");
+        table_api.close_table();
+    }
+
+    string gid;
+    string sid;
+    string enable;
+    string action;
 
     while (util::get_string(data_stream, arg, ", "))
     {
         switch (count)
         {
         case 0:
-            table_api.add_option("sid", std::stoi(arg));
+            sid = arg;
             count++;
             break;
         case 1:
-            table_api.add_option("gid", std::stoi(arg));
+            gid = arg;
             count++;
             break;
         case 2:
             if (arg == "enabled")
-            {
-                table_api.add_diff_option_comment("enabled", "enable");
-                table_api.add_option("enable", true);
-            }
+                enable = "true";
             else if (arg == "disabled")
-            {
-                table_api.add_diff_option_comment("disabled", "enable");
-                table_api.add_option("enable", false);
-            }
+                enable = "false";
             else
             {
                 data_api.failed_conversion(data_stream, "third option must be {enabled|disabled|");
@@ -77,7 +87,7 @@ bool RuleState::convert(std::istringstream& data_stream)
             count++;
             break;
         case 3:
-            table_api.add_deleted_comment("action");
+            action = arg;
             count++;
             break;
         default:
@@ -86,8 +96,37 @@ bool RuleState::convert(std::istringstream& data_stream)
         }
     }
 
-    table_api.close_table();
-    table_api.close_table();
+    if ( count < 2 )
+    {
+        data_api.failed_conversion(data_stream, "must set a gid and sid for rule state" + arg);
+        retval = false;
+    }
+
+    if ( retval )
+    {
+        string key = gid + ":" + sid;
+        table_api.open_associative_table("rule_state", key.c_str());
+
+        if ( !enable.empty() )
+        {
+            table_api.add_diff_option_comment("enabled/disabled", "enable");
+            table_api.add_option("enable", enable);
+        }
+
+        if ( !action.empty() )
+        {
+            if ( action == "sdrop" )
+            {
+                action = "drop";
+                table_api.add_diff_option_comment("sdrop", "drop");
+            }
+
+            table_api.add_option("action", action);
+        }
+
+        table_api.close_table();
+    }
+
     return retval;
 }