]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2115 in SNORT/snort3 from ~RUCOMBS/snort3:rule_meta to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Tue, 7 Apr 2020 13:11:54 +0000 (13:11 +0000)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Tue, 7 Apr 2020 13:11:54 +0000 (13:11 +0000)
Squashed commit of the following:

commit 9f06fc29f374152d9258636b16e37f966753f6f6
Author: russ <rucombs@cisco.com>
Date:   Sun Apr 5 11:25:48 2020 -0400

    flowbits: relocate bitop.h to helpers

commit 28c62396337cab09d8762e2299043fc0dd75a60f
Author: russ <rucombs@cisco.com>
Date:   Sun Apr 5 00:13:29 2020 -0400

    flowbits: fix reload mapping

commit 6637ad94652470fbff956e90a33760d92f56937e
Author: russ <rucombs@cisco.com>
Date:   Sun Mar 29 20:54:58 2020 -0400

    ips: fix rule state mapping and policy lookup

commit b12fae905f4d3e2fa845572cf9d51da42b21fde8
Author: russ <rucombs@cisco.com>
Date:   Sun Mar 29 15:12:52 2020 -0400

    src: remove extraneous trailing spaces

commit bcab016e2dafb240316bfccaf728bb36dfb291e6
Author: russ <rucombs@cisco.com>
Date:   Sun Mar 29 10:31:55 2020 -0400

    so rules: allow stub gid:sid:rev to override so

commit 6e8e8a7e39df9030c0b679aaec1688eb602b1325
Author: russ <rucombs@cisco.com>
Date:   Sat Mar 28 17:23:49 2020 -0400

    metadata-filter: apply to so rule stubs

commit 2ba460819894571742f16166286b597963d08652
Author: russ <rucombs@cisco.com>
Date:   Sat Mar 28 16:04:57 2020 -0400

    so rules: allow stub header to override so header

commit 9a40462e5b02191f2bd44abd98d40876d87af233
Author: russ <rucombs@cisco.com>
Date:   Sat Mar 28 10:40:41 2020 -0400

    snort: add --dump-rule-state

commit 7aa13768693d7037a0525d90bef053866203bad8
Author: russ <rucombs@cisco.com>
Date:   Sat Mar 28 09:47:31 2020 -0400

    snort: add --dump-rule-deps

commit 3975f00f8476bccacb4047cd4488555d513d3b22
Author: russ <rucombs@cisco.com>
Date:   Sat Mar 28 09:11:08 2020 -0400

    snort: add rule text to --dump-rule-meta

commit 17eff18a925a8fc728fbe1821f2c390b05fac49b
Author: russ <rucombs@cisco.com>
Date:   Mon Mar 23 22:15:30 2020 -0400

    snort: enable --dump-rule-meta to work without a conf

commit 634dc34e894e0e6dd05568eb6a1184312da5011a
Author: russ <rucombs@cisco.com>
Date:   Sat Mar 14 22:11:23 2020 -0400

    snort: add flowbits set and checked to --dump-rule-meta

commit dfecdf639ac3027e6fdb0ee9945f59c01490b166
Author: russ <rucombs@cisco.com>
Date:   Fri Mar 13 19:45:35 2020 -0400

    snort: initial implementation of --dump-rule-meta

commit b969f1b1b19c9ecdf546828bfd73d80d02d01813
Author: russ <rucombs@cisco.com>
Date:   Thu Mar 26 11:26:39 2020 -0400

    stream_tcp: remove unused session printing cruft

commit c9c7b527debe3c6689ffce4e4be5d1caa7b476e2
Author: russ <rucombs@cisco.com>
Date:   Thu Mar 26 11:15:48 2020 -0400

    hyperscan: simplify scratch memory initialization

commit 3be58eed3d48ede7c5bd6ae949c25d9f8825e9b2
Author: russ <rucombs@cisco.com>
Date:   Tue Mar 24 08:49:17 2020 -0400

    output: allow error messages in quiet mode

commit c63c2cee10e3e924b27719770776b67e31339ad5
Author: russ <rucombs@cisco.com>
Date:   Mon Mar 23 08:29:27 2020 -0400

    session: remove unused IPS option

commit d52b37a58007a4e1f8e9f191c96a48529a3aa8d0
Author: russ <rucombs@cisco.com>
Date:   Sun Mar 22 20:44:10 2020 -0400

    snort: remove unused --pcap-reload option

commit 616ac76d41aade222a16cf19a7f4634e6f92be9a
Author: russ <rucombs@cisco.com>
Date:   Sun Mar 22 20:22:12 2020 -0400

    snort: remove inappropriate fatal errors

commit 57ab3b040ba3735eb2f62f442641f49b6ee31ee1
Author: russ <rucombs@cisco.com>
Date:   Sat Mar 14 12:10:39 2020 -0400

    flowbits: refactor implementation

... and 4 more commits

49 files changed:
src/codecs/ip/cd_udp.cc
src/detection/detection_options.cc
src/detection/fp_detect.cc
src/detection/fp_detect.h
src/detection/rules.cc
src/detection/rules.h
src/detection/signature.cc
src/detection/signature.h
src/detection/treenodes.h
src/flow/flow.cc
src/flow/flow_data.cc
src/helpers/CMakeLists.txt
src/helpers/bitop.h [moved from src/utils/bitop.h with 58% similarity]
src/helpers/test/CMakeLists.txt
src/helpers/test/bitop_test.cc [moved from src/utils/test/bitop_test.cc with 54% similarity]
src/ips_options/CMakeLists.txt
src/ips_options/ips_classtype.cc
src/ips_options/ips_flowbits.cc
src/ips_options/ips_flowbits.h
src/ips_options/ips_options.cc
src/ips_options/ips_session.cc [deleted file]
src/log/messages.cc
src/main.cc
src/main/modules.cc
src/main/policy.cc
src/main/policy.h
src/main/snort_config.cc
src/main/snort_config.h
src/main/snort_debug.cc
src/main/snort_module.cc
src/managers/inspector_manager.cc
src/managers/inspector_manager.h
src/managers/ips_manager.cc
src/network_inspectors/binder/bind_module.cc
src/parser/cmd_line.cc
src/parser/parse_rule.cc
src/parser/parse_stream.cc
src/parser/parser.cc
src/ports/port_table.cc
src/ports/port_var_table.cc
src/search_engines/hyperscan.cc
src/service_inspectors/http2_inspect/http2_stream.h
src/service_inspectors/http_inspect/http_cutter.cc
src/stream/tcp/tcp_stream_session.cc
src/stream/tcp/tcp_stream_session.h
src/stream/tcp/tcp_stream_tracker.cc
src/stream/tcp/tcp_stream_tracker.h
src/utils/CMakeLists.txt
src/utils/test/CMakeLists.txt

index 727c98d11c2d4fb39e8662cae18d0c1f3b83643b..333051de3dd3251d640252850feec060d3353604 100644 (file)
@@ -141,7 +141,7 @@ class UdpModule : public CodecModule
 {
 public:
     UdpModule() : CodecModule(CD_UDP_NAME, CD_UDP_HELP, udp_params)
-    { 
+    {
         config = nullptr;
     }
 
@@ -583,7 +583,7 @@ static void mod_dtor(Module* m)
 { delete m; }
 
 static Codec* ctor(Module* m)
-{ 
+{
     UdpModule* mod = (UdpModule*)m;
     // Codecs can be instantiated without modules. In which case use
     // the snort defaults for config.
index c948b7c3fdd62dff164e7f38b89b81ad657c5921..5c8dd15d157fa72a1454bc6c7d4a55820ac6d042 100644 (file)
@@ -360,7 +360,7 @@ int detection_option_node_evaluate(
     char tmp_noalert_flag = 0;
     Cursor cursor = orig_cursor;
     bool continue_loop = true;
-    char flowbits_setoperation = 0;
+    bool flowbits_setoperation = false;
     int loop_count = 0;
     uint32_t tmp_byte_extract_vars[NUM_IPS_OPTIONS_VARS];
     uint64_t cur_eval_context_num = eval_data.p->context->context_num;
@@ -443,12 +443,12 @@ int detection_option_node_evaluate(
                 }
             }
 
-            int eval_rtn_result = 0;
+            bool eval_rtn_result;
 
             // Don't include RTN time
             {
                 RulePause pause(profile);
-                eval_rtn_result = fpEvalRTN(getRuntimeRtnFromOtn(otn), p, check_ports);
+                eval_rtn_result = fp_eval_rtn(getRuntimeRtnFromOtn(otn), p, check_ports);
             }
 
             if ( eval_rtn_result )
@@ -515,7 +515,7 @@ int detection_option_node_evaluate(
         case RULE_OPTION_TYPE_FLOWBIT:
             if ( node->evaluate )
             {
-                flowbits_setoperation = FlowBits_SetOperation(node->option_data);
+                flowbits_setoperation = flowbits_setter(node->option_data);
 
                 if ( flowbits_setoperation )
                     // set to match so we don't bail early
index 95676a004c6ab9da966e305de8ebe0499dd39f23..f9b42af21acc9122e4ce66061ba628746f2430cd 100644 (file)
@@ -293,37 +293,18 @@ int fpAddMatch(OtnxMatchData* omd, const OptTreeNode* otn)
     return 0;
 }
 
-/*
-**  DESCRIPTION
-**    Evaluates an RTN against a packet.  We can probably get rid of
-**    the check_ports variable, but it's in there for good luck.  :)
-**
-**  FORMAL INPUTS
-**    RuleTreeNode * - RTN to check packet against.
-**    Packet       * - Packet to evaluate
-**    int            - whether to do a quick enhancement against ports.
-**
-**  FORMAL OUTPUT
-**    int - 1 if match, 0 if match failed.
-*/
-int fpEvalRTN(RuleTreeNode* rtn, Packet* p, int check_ports)
+bool fp_eval_rtn(RuleTreeNode* rtn, Packet* p, int check_ports)
 {
-    if ( !rtn )
-        return 0;
+    if ( !rtn or !rtn->enabled() )
+        return false;
 
     if ( rtn->user_mode() )
         check_ports = 1;
 
     if (!rtn->rule_func->RuleHeadFunc(p, rtn, rtn->rule_func, check_ports))
-    {
-        return 0;
-    }
+        return false;
 
-    /*
-    **  Return that there is a rule match and log the event outside
-    **  of this routine.
-    */
-    return 1;
+    return true;
 }
 
 int fp_eval_option(void* v, Cursor& c, Packet* p)
index 4efde0dc3f531cd1a9498f13b6b3d962d2691db6..4148c29bec52af83f0689dd29b12c246975bbae8 100644 (file)
@@ -50,7 +50,7 @@ extern THREAD_LOCAL snort::ProfileStats rulePerfStats;
 
 struct RuleTreeNode;
 int fpLogEvent(const RuleTreeNode*, const OptTreeNode*, snort::Packet*);
-int fpEvalRTN(RuleTreeNode*, snort::Packet*, int check_ports);
+bool fp_eval_rtn(RuleTreeNode*, snort::Packet*, int check_ports);
 int fp_eval_option(void*, Cursor&, snort::Packet*);
 
 #define MAX_NUM_RULE_TYPES 16   // max number of allowed rule types
index aca3f338ae2a665cdcb7aeb494a45476ca064ed3..1c39b1a66375aad7f33dabf636550f6a90278380 100644 (file)
 
 using namespace snort;
 
+bool operator< (const RuleKey& lhs, const RuleKey& rhs)
+{
+    if ( lhs.policy_id < rhs.policy_id )
+        return true;
+
+    if ( lhs.policy_id == rhs.policy_id )
+    {
+        if ( lhs.gid < rhs.gid )
+            return true;
+
+        if ( lhs.gid == rhs.gid and lhs.sid < rhs.sid )
+            return true;
+    }
+    return false;
+}
+
 void RuleStateMap::apply(SnortConfig* sc)
 {
     for ( auto it : map )
@@ -58,7 +74,7 @@ void RuleStateMap::apply(SnortConfig* sc)
                 }
             }
             else
-                apply(sc, otn, it.second.policy_id, it.second);
+                apply(sc, otn, it.first.policy_id, it.second);
         }
     }
 }
index b31436bf3da02423be4bb88289f6b896812c50ea..33e4ce618f059f1f2123356c7e25e4d3e256db0b 100644 (file)
@@ -72,16 +72,15 @@ struct RuleListNode
 
 struct RuleKey
 {
+    unsigned policy_id;
     unsigned gid;
     unsigned sid;
 
-    friend bool operator< (const RuleKey& lhs, const RuleKey& rhs)
-    { return lhs.gid < rhs.gid ? true : (lhs.gid > rhs.gid ? false : (lhs.sid < rhs.sid)); }
+    friend bool operator< (const RuleKey&, const RuleKey&);
 };
 
 struct RuleState
 {
-    unsigned policy_id;
     snort::Actions::Type action;
     IpsPolicy::Enable enable;
 };
index f8d5ef51addb8796112a6b3e459e65d664ff3982..62ffe74f051d3278b184197d0f0cf31172536d10 100644 (file)
 
 #include <cassert>
 #include <iostream>
+#include <unordered_map>
 
 #include "signature.h"
 
+#include "framework/decode_data.h"
 #include "hash/hash_defs.h"
 #include "hash/ghash.h"
+#include "ips_options/ips_flowbits.h"
 #include "log/messages.h"
 #include "main/snort_config.h"
+#include "main/policy.h"
+#include "managers/inspector_manager.h"
 #include "parser/parser.h"
 #include "utils/util.h"
 #include "utils/util_cstring.h"
@@ -157,6 +162,7 @@ OptTreeNode::~OptTreeNode()
     if (detection_filter)
         snort_free(detection_filter);
 
+    delete sigInfo.body;
     delete[] state;
 }
 
@@ -223,7 +229,7 @@ void OtnLookupFree(GHash* otn_map)
         delete otn_map;
 }
 
-void dump_msg_map(SnortConfig* sc)
+void dump_msg_map(const SnortConfig* sc)
 {
     GHashNode* ghn = sc->otn_map->find_first();
 
@@ -245,3 +251,176 @@ void dump_msg_map(SnortConfig* sc)
     }
 }
 
+static void get_flow_bits(
+    const OptTreeNode* otn, std::vector<std::string>& setters, std::vector<std::string>& checkers)
+{
+    OptFpList* p = otn->opt_func;
+
+    while ( p )
+    {
+        if ( p->type == RULE_OPTION_TYPE_FLOWBIT )
+        {
+            bool set;
+            std::vector<std::string> bits;
+            get_flowbits_dependencies(p->ips_opt, set, bits);
+
+            if ( !bits.empty() )
+            {
+                if ( set )
+                    setters.insert(setters.end(), bits.begin(), bits.end());
+                else
+                    checkers.insert(checkers.end(), bits.begin(), bits.end());
+            }
+        }
+        p = p->next;
+    }
+}
+
+static void dump_field(const char* key, long val, bool sep = true)
+{ if ( sep ) std::cout << ", "; std::cout << key << ": " << val; }
+
+static void dump_field(const char* key, const std::string& val, bool sep = true)
+{ if ( sep ) std::cout << ", "; std::cout << key << ": " << val; }
+
+static void dump_opt(const char* key, const std::string& val, bool sep = true)
+{
+    if ( val.empty() )
+        return;
+
+    if ( sep )
+        std::cout << ", ";
+
+    std::cout << key << ": " << val;
+}
+
+static void dump_info(const SigInfo& si)
+{
+    dump_field("gid", si.gid, false);
+    dump_field("sid", si.sid);
+    dump_field("rev", si.rev);
+}
+
+static void dump_header(const RuleHeader* h)
+{
+    assert(h);
+    dump_opt("action", h->action);
+    dump_opt("src_nets", h->src_nets);
+    dump_opt("src_ports", h->src_ports);
+    dump_opt("direction", h->dir);
+    dump_opt("dst_nets", h->dst_nets);
+    dump_opt("dst_ports", h->dst_ports);
+}
+
+void dump_rule_meta(const SnortConfig* sc)
+{
+    GHashNode* ghn = sc->otn_map->find_first();
+
+    while ( ghn )
+    {
+        const OptTreeNode* otn = (OptTreeNode*)ghn->data;
+        const SigInfo& si = otn->sigInfo;
+
+        dump_info(si);
+
+        const RuleTreeNode* rtn = otn->proto_nodes[0];
+        dump_header(rtn->header);
+
+        dump_field("msg", si.message);
+
+        for ( const auto& svc : si.services )
+            dump_field("service", svc.service);
+
+        std::vector<std::string> setters;
+        std::vector<std::string> checkers;
+        get_flow_bits(otn, setters, checkers);
+
+        for ( const auto& s : setters )
+            dump_field("sets", s);
+
+        for ( const auto& s : checkers )
+            dump_field("checks", s);
+
+        dump_field("body", *si.body);
+
+        std::cout << std::endl;
+        ghn = sc->otn_map->find_next();
+    }
+}
+
+void dump_rule_state(const SnortConfig* sc)
+{
+    GHashNode* ghn = sc->otn_map->find_first();
+
+    while ( ghn )
+    {
+        const OptTreeNode* otn = (OptTreeNode*)ghn->data;
+        const SigInfo& si = otn->sigInfo;
+
+        dump_field("gid", si.gid, false);
+        dump_field("sid", si.sid);
+        dump_field("rev", si.rev);
+
+        for ( unsigned i = 0; i < otn->proto_node_num; ++i )
+        {
+            const RuleTreeNode* rtn = otn->proto_nodes[i];
+
+            if ( !rtn )
+                continue;
+
+            auto pid = snort::get_ips_policy(sc, i)->user_policy_id;
+            dump_field("policy", pid);
+
+            const char* s = Actions::get_string(rtn->action);
+            dump_field("action", s);
+
+            s = rtn->enabled() ? "enabled" : "disabled";
+            dump_field("state", s);
+        }
+        std::cout << std::endl;
+        ghn = sc->otn_map->find_next();
+    }
+}
+
+using SvcMap = std::unordered_map<std::string, std::vector<std::string>>;
+
+static SvcMap get_dependencies()
+{
+    SvcMap map;
+    std::vector<const InspectApi*> apis = InspectorManager::get_apis();
+
+    for ( const auto* p : apis )
+    {
+        if ( !p->service )
+            continue;
+
+        std::vector<std::string>& v = map[p->service];
+        v.emplace_back(p->base.name);
+
+        // FIXIT-L need NHI to advertise dependency on H2I
+        if ( !strcmp(p->base.name, "http2_inspect") )
+            v.emplace_back("http_inspect");
+
+        if ( p->proto_bits & (PROTO_BIT__TCP|PROTO_BIT__PDU) )
+            v.emplace_back("stream_tcp");
+
+        if ( p->proto_bits & PROTO_BIT__UDP )
+            v.emplace_back("stream_udp");
+    }
+    return map;
+}
+
+void dump_rule_deps(const SnortConfig*)
+{
+    SvcMap map = get_dependencies();
+
+    for ( const auto& it : map )
+    {
+        dump_field("service", it.first, false);
+
+        for ( const auto& s : it.second )
+            dump_field("requires", s);
+
+        std::cout << std::endl;
+    }
+}
+
index e2bc047c90e77d7000d6ffd02e86faa48b3de0b1..1c56ccf795b83f4156a00ee444fc57d62abc1dfe 100644 (file)
@@ -91,6 +91,8 @@ enum Target
 struct SigInfo
 {
     std::string message;
+    std::string* body = nullptr;
+
     std::vector<const ReferenceNode*> refs;
     std::vector<SignatureServiceInfo> services;
 
@@ -115,7 +117,10 @@ void OtnRemove(snort::GHash*, OptTreeNode*);
 
 OptTreeNode* GetOTN(uint32_t gid, uint32_t sid);
 
-void dump_msg_map(snort::SnortConfig*);
+void dump_msg_map(const snort::SnortConfig*);
+void dump_rule_deps(const snort::SnortConfig*);
+void dump_rule_meta(const snort::SnortConfig*);
+void dump_rule_state(const snort::SnortConfig*);
 
 #endif
 
index 7449124f9124761bb16b02b4aa716e9a55d4629d..8451484c9f2b91d0527a59ffc85cba926173eb1d 100644 (file)
@@ -88,6 +88,19 @@ struct RuleFpList
     RuleFpList* next = nullptr;
 };
 
+struct RuleHeader
+{
+    RuleHeader(const char* s) : action(s) { }
+
+    std::string action;
+    std::string proto;
+    std::string src_nets;
+    std::string src_ports;
+    std::string dir;
+    std::string dst_nets;
+    std::string dst_ports;
+};
+
 // one of these per rule per policy
 // represents head part of rule
 struct RuleTreeNode
@@ -103,6 +116,7 @@ struct RuleTreeNode
     static constexpr Flag USER_MODE     = 0x80;
 
     RuleFpList* rule_func = nullptr; /* match functions.. (Bidirectional etc.. ) */
+    RuleHeader* header = nullptr;
 
     sfip_var_t* sip = nullptr;
     sfip_var_t* dip = nullptr;
@@ -175,7 +189,6 @@ struct OptTreeNode
     unsigned evalIndex = 0;       /* where this rule sits in the evaluation sets */
     unsigned ruleIndex = 0; // unique index
     uint32_t num_detection_opts = 0;
-    uint32_t plugins = 0;
     SnortProtocolId snort_protocol_id = 0;    // Added for integrity checks during rule parsing.
     unsigned short proto_node_num = 0;
     uint16_t longestPatternLen = 0;
@@ -226,12 +239,6 @@ namespace snort
 SO_PUBLIC bool otn_has_plugin(OptTreeNode* otn, const char* name);
 }
 
-inline bool otn_has_plugin(OptTreeNode* otn, int id)
-{ return (otn->plugins & (0x1 << id)) != 0; }
-
-inline void otn_set_plugin(OptTreeNode* otn, int id)
-{ otn->plugins |= (0x1 << id); }
-
 bool otn_set_agent(OptTreeNode*, snort::IpsOption*);
 
 void otn_trigger_actions(const OptTreeNode*, snort::Packet*);
index ffac79d048f6a90c226de4a015acd9b408563bb2..d7ea28f06b6fcfa520cad49d6e841f027b88dc77 100644 (file)
 #include "flow/ha.h"
 #include "flow/session.h"
 #include "framework/data_bus.h"
+#include "helpers/bitop.h"
 #include "ips_options/ips_flowbits.h"
 #include "protocols/packet.h"
 #include "sfip/sf_ip.h"
-#include "utils/bitop.h"
 #include "utils/stats.h"
 #include "utils/util.h"
 
index af6f9b01715ec7d2564ca629eb84efebb4085a8a..470675aed62d4c0aafff2a4815305774c0c4c06c 100644 (file)
@@ -66,6 +66,7 @@ void FlowData::update_deallocations(size_t n)
     mem_in_use -= n;
 }
 
-RuleFlowData::RuleFlowData(unsigned u) : FlowData(u, 
-    SnortConfig::get_conf()->so_rules->proxy) { }
+RuleFlowData::RuleFlowData(unsigned u) :
+    FlowData(u, SnortConfig::get_conf()->so_rules->proxy)
+{ }
 
index 0503609d4f488079c5f6c36cd7cba149a7ac0ea9..754a9257bf6ac6e58fd5251a74f9fe8429a36c9c 100644 (file)
@@ -22,6 +22,7 @@ add_library (helpers OBJECT
     ${HELPERS_INCLUDES}
     ${HYPER_SOURCES}
     base64_encoder.cc
+    bitop.h
     boyer_moore_search.cc
     chunk.cc
     chunk.h
similarity index 58%
rename from src/utils/bitop.h
rename to src/helpers/bitop.h
index d175d28b559bdaa8aee3e3c405ca78fc7b88085b..d485f2d57fc03998a7c0b61e258138ab8f686cb9 100644 (file)
 
 // A simple, dynamically sized bit vector implementation
 
-#include <cassert>
 #include <cstdint>
-#include <cstring>
+#include <vector>
 
 class BitOp
 {
 public:
-    BitOp(size_t);
-    ~BitOp();
+    BitOp(size_t bit)
+    { bit_buf.resize(index(bit) + 1); }
+
+    ~BitOp() = default;
 
     BitOp(const BitOp&) = delete;
     BitOp& operator=(const BitOp&) = delete;
 
-    void reset();
     void set(unsigned int bit);
     bool is_set(unsigned int bit) const;
     void clear(unsigned int bit);
 
-    size_t size() const;
+private:
+    size_t size() const
+    { return bit_buf.size(); }
+
+    size_t index(size_t bit) const
+    { return (bit + 7) >> 3; }
 
-    // FIXIT-L add operator overloads for [], &=, |=, etc
-    size_t get_buf_size() const;
-    uint8_t& get_buf_element(size_t);
-    const uint8_t& get_buf_element(size_t) const;
+    uint8_t& byte(size_t bit)
+    { return bit_buf[index(bit)]; }
 
-private:
-    uint8_t mask(size_t bit) const;
+    uint8_t mask(size_t bit) const
+    { return (uint8_t)(0x80 >> (bit & 7)); }
 
-    uint8_t* bit_buf;
-    const size_t buf_size;
+    std::vector<uint8_t> bit_buf;
 };
 
 // -----------------------------------------------------------------------------
 // implementation
 // -----------------------------------------------------------------------------
 
-inline BitOp::BitOp(size_t len) :
-    buf_size(len ? (len + 7) >> 3 : 1)
-{
-    bit_buf = new uint8_t[len]();
-}
-
-inline BitOp::~BitOp()
-{ delete[] bit_buf; }
-
-inline uint8_t BitOp::mask(size_t bit) const
-{ return (uint8_t)(0x80 >> (bit & 7)); }
-
-// Reset the bit buffer so that it can be reused
-inline void BitOp::reset()
-{ memset(bit_buf, 0, buf_size); }
-
-// Set the bit in the specified position within the bit buffer.
 inline void BitOp::set(unsigned int bit)
 {
-    assert(size() > bit);
-    bit_buf[bit >> 3] |= mask(bit);
+    if ( index(bit) >= size() )
+        bit_buf.resize(index(bit) + 1);
+    byte(bit) |= mask(bit);
 }
 
-// Checks if the bit at the specified position is set
 inline bool BitOp::is_set(unsigned int bit) const
 {
-    assert(size() > bit);
-    return mask(bit) & bit_buf[bit >> 3];
+    if ( index(bit) >= size() )
+        return false;
+    return bit_buf[index(bit)] & mask(bit);
 }
 
-// Clear the bit in the specified position within the bit buffer.
 inline void BitOp::clear(unsigned int bit)
 {
-    assert(size() > bit);
-    bit_buf[bit >> 3] &= ~mask(bit);
+    if ( index(bit) >= size() )
+        return;
+    byte(bit) &= ~mask(bit);
 }
 
-inline size_t BitOp::size() const
-{ return buf_size << 3; }
-
-inline size_t BitOp::get_buf_size() const
-{ return buf_size; }
-
-inline uint8_t& BitOp::get_buf_element(size_t i)
-{ return bit_buf[i]; }
-
-inline const uint8_t& BitOp::get_buf_element(size_t i) const
-{ return bit_buf[i]; }
-
 #endif
 
index 07e1b103db1e9dc389f8f0120370f3367acc4398..9b989cb6d7b67a8512b0fe90b37af46aa2c9d08b 100644 (file)
@@ -14,3 +14,5 @@ if ( HAVE_HYPERSCAN )
     )
 endif()
 
+add_catch_test( bitop_test )
+
similarity index 54%
rename from src/utils/test/bitop_test.cc
rename to src/helpers/test/bitop_test.cc
index 7f1c7efa3606d00da467354b0cf38cb41f084eab..b8acf7be106b020008ad1f1d7a4089c8f60b1e70 100644 (file)
 
 #include "../bitop.h"
 
-static bool t_bitop_buffer_zero(BitOp& bitop)
+static unsigned num_set(BitOp& bitop, size_t max)
 {
-    for ( size_t i = 0; i < bitop.get_buf_size(); ++i )
-        if ( bitop.get_buf_element(i) )
-            return false;
+    unsigned c = 0;
 
-    return true;
+    for ( size_t i = 0; i < max; ++i )
+    {
+        if ( bitop.is_set(i) )
+            c++;
+    }
+    return c;
 }
 
+static bool is_clear(BitOp& bitop, size_t max)
+{ return num_set(bitop, max) == 0; }
+
 TEST_CASE( "bitop", "[bitop]" )
 {
-    BitOp bitop(24);
+    const size_t max = 16;
+    BitOp bitop(max);
 
     SECTION( "zero-initialized" )
     {
-        CHECK( (t_bitop_buffer_zero(bitop) == true) );
+        CHECK( (is_clear(bitop, max) == true) );
     }
 
-    SECTION( "reset" )
+    SECTION( "toggle" )
     {
-        bitop.get_buf_element(0) = 0xff;
-        bitop.reset();
+        const size_t bit = 7;
+
+        bitop.set(bit);
+        CHECK(bitop.is_set(bit));
+
+        CHECK(num_set(bitop, max) == 1);
+
+        bitop.clear(bit);
+        CHECK(!bitop.is_set(bit));
 
-        CHECK( (t_bitop_buffer_zero(bitop) == true) );
+        CHECK( (is_clear(bitop, max) == true) );
     }
 
-    SECTION( "set/is_set/clear" )
+    SECTION( "over size" )
     {
-        bitop.set(6);
+        const size_t j = max / 2;
+        const size_t k = max + 2;
 
-        CHECK( (bitop.get_buf_element(0) == 0x02) );
+        bitop.set(j);
+        CHECK(bitop.is_set(j));
 
-        CHECK( bitop.is_set(6) );
-        CHECK_FALSE( bitop.is_set(7) );
+        CHECK(!bitop.is_set(k));
 
-        bitop.set(7);
-        bitop.clear(6);
+        bitop.set(k);
+        CHECK(bitop.is_set(k));
 
-        CHECK( bitop.get_buf_element(0) == 0x01 );
-    }
+        CHECK(num_set(bitop, k + 2) == 2);
+        CHECK(bitop.is_set(j));
 
-    SECTION( "size" )
-    {
-        CHECK( (bitop.size() == 24) );
+        bitop.clear(k);
+        CHECK(!bitop.is_set(k));
+
+        CHECK(bitop.is_set(j));
+        bitop.clear(j);
+
+        CHECK( (is_clear(bitop, k + 2) == true) );
     }
 }
+
index a1d56704f6ccfa9fc9c805402e155fc17d54b44b..65a0af88c66b919e0f35d29bfa11d5570b477220 100644 (file)
@@ -37,7 +37,6 @@ SET( PLUGIN_LIST
     ips_rev.cc
     ips_rpc.cc
     ips_seq.cc
-    ips_session.cc
     ips_sid.cc
     ips_soid.cc
     ips_tag.cc
@@ -129,7 +128,6 @@ else (STATIC_IPS_OPTIONS)
     add_dynamic_module(ips_rpc ips_options ips_rpc.cc)
     add_dynamic_module(ips_sid ips_options ips_sid.cc)
     add_dynamic_module(ips_seq ips_options ips_seq.cc)
-    add_dynamic_module(ips_session ips_options ips_session.cc)
     add_dynamic_module(ips_soid ips_options ips_soid.cc)
     add_dynamic_module(ips_tag ips_options ips_tag.cc)
     add_dynamic_module(ips_target ips_options ips_target.cc)
index 4c03736d95979a232a4c932e9feeebf231e0d69f..70f842ba8bafed4518a177d22fe6421e529b28dd 100644 (file)
@@ -25,6 +25,7 @@
 #include "framework/decode_data.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
+#include "main/snort_config.h"
 
 using namespace snort;
 
@@ -65,6 +66,12 @@ bool ClassTypeModule::set(const char*, Value& v, SnortConfig* sc)
 
     type = get_classification(sc, v.get_string());
 
+    if ( !type and sc->dump_rule_info() )
+    {
+        const char* s = v.get_string();
+        add_classification(sc, s, s, 1);
+        type = get_classification(sc, s);
+    }
     return type != nullptr;
 }
 
index 7078efd78581541e918b6f16cdb20b95eabf4db0..80e8f63257679df87b030a0fb847c220562419f4 100644 (file)
@@ -1,6 +1,5 @@
 //--------------------------------------------------------------------------
 // Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2003-2013 Sourcefire, Inc.
 //
 // 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
 
 #include "ips_flowbits.h"
 
-#include <forward_list>
-#include <sstream>
-#include <string>
+#include <unordered_map>
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/ghash.h"
 #include "hash/hash_defs.h"
 #include "hash/hash_key_operations.h"
+#include "helpers/bitop.h"
 #include "log/messages.h"
 #include "protocols/packet.h"
 #include "profiler/profiler.h"
-#include "utils/bitop.h"
 #include "utils/sflsq.h"
 #include "utils/util.h"
 
@@ -45,97 +41,104 @@ using namespace snort;
 
 #define s_name "flowbits"
 
-static THREAD_LOCAL ProfileStats flowBitsPerfStats;
-
-#define ALLOWED_SPECIAL_CHARS       ".-_"
-
-#define FLOWBITS_SET       0x01
-#define FLOWBITS_UNSET     0x02
-#define FLOWBITS_TOGGLE    0x04
-#define FLOWBITS_ISSET     0x08
-#define FLOWBITS_ISNOTSET  0x10
-#define FLOWBITS_RESET     0x20
-#define FLOWBITS_NOALERT   0x40
-#define FLOWBITS_SETX      0x80
-
-/**
-**  The FLOWBITS_OBJECT is used to track the different
-**  flowbit names that set/unset/etc. bits.  We use these
-**  so that we can verify that the rules that use flowbits
-**  make sense.
-**
-**  The types element tracks all the different operations that
-**  may occur for a given object.  This is different from how
-**  the type element is used from the FLOWBITS_OP structure.
-*/
-struct FLOWBITS_OBJECT
+struct FlowBit
 {
-    uint16_t id = 0;
-    uint8_t types = 0;
-    int toggle = 0;
-    int set = 0;
-    int isset = 0;
+    uint16_t id = 65535;
+    uint16_t sets = 0;
+    uint16_t checks = 0;
+
+    bool is_new()
+    { return id == 65535; }
 };
 
-typedef enum
-{
-    FLOWBITS_AND,
-    FLOWBITS_OR,
-    FLOWBITS_ANY,
-    FLOWBITS_ALL
-}Flowbits_eval;
-
-/**
-**  This class is the context ptr for each detection option
-**  on a rule.  The id is associated with a FLOWBITS_OBJECT id.
-**
-**  The type element track only one operation.
-*/
-class FLOWBITS_OP
+static std::vector<std::string> bit_keys;
+static std::unordered_map<std::string, FlowBit> bit_map;
+static THREAD_LOCAL ProfileStats flowbits_profile;
+
+//--------------------------------------------------------------------------
+// flowbits option config
+//--------------------------------------------------------------------------
+
+struct FlowBitCheck
 {
-public:
-    std::string name;
-    std::string group;
+    enum Op { SET, UNSET, IS_SET, IS_NOT_SET, NO_ALERT };
 
-    std::vector<uint16_t> ids;
-    Flowbits_eval eval = FLOWBITS_AND;
+    FlowBitCheck(Op t) : type(t) { }
+    bool validate();
 
-    uint32_t group_id = 0;
-    uint8_t type = 0;         /* Set, Unset, Invert, IsSet, IsNotSet, Reset  */
-};
+    bool is_setter()
+    { return type == SET or type == UNSET; }
 
-struct FLOWBITS_GRP
-{
-    std::string name;
-    BitOp* GrpBitOp = nullptr;
+    bool is_checker()
+    { return type == IS_SET or type == IS_NOT_SET; }
 
-    uint32_t group_id = 0;
+    void add(uint16_t);
 
-    uint16_t count = 0;
-    uint16_t max_id = 0;
+    std::vector<uint16_t> ids;
+    uint16_t max = 0;
+    bool or_bits = false;
+    Op type;
 };
 
-struct FlowBitState
+void FlowBitCheck::add(uint16_t id)
 {
-    std::forward_list<const FLOWBITS_OP*> op_list;
-    GHash* flowbits_hash = nullptr;
-    GHash* flowbits_grp_hash = nullptr;
-    SF_QUEUE* flowbits_bit_queue = nullptr;
-    unsigned flowbits_count = 0;
-    unsigned flowbits_grp_count = 0;
-    int flowbits_toggle = 1;
-};
+    ids.push_back(id);
+    if ( id > max )
+        max = id;
+}
+
+bool FlowBitCheck::validate()
+{
+    switch ( type )
+    {
+    case SET:
+        if ( !or_bits and !ids.empty() )
+            return true;
+
+        ParseError("%s: set uses syntax: flowbits:set,bit[&bit].", s_name);
+        break;
+
+    case UNSET:
+        if ( !or_bits and !ids.empty() )
+            return true;
+
+        ParseError("%s: unset uses syntax: flowbits:unset,bit[&bit].", s_name);
+        break;
+
+    case IS_SET:
+        if ( !ids.empty() )
+            return true;
 
-// Forward declarations
-static void free_item(void*);
-static void free_group(void*);
+        ParseError("%s: isset uses syntax: flowbits:isset,bit[&bit] OR "
+            "flowbits:isset,bit[|bit].", s_name);
+        break;
+
+    case IS_NOT_SET:
+        if ( !ids.empty() )
+            return true;
+
+        ParseError("%s: isnotset uses syntax: flowbits:isnotset,bit[&bit] OR "
+            "flowbits:isnotset,bit[|bit]", s_name);
+        break;
 
-static IpsOption::EvalStatus check_flowbits(FLOWBITS_OP*, Packet*);
+    case NO_ALERT:
+        if ( ids.empty() )
+            return true;
+
+        ParseError("%s: noalert uses syntax: flowbits:noalert.", s_name);
+        break;
+    }
+    return false;
+}
+
+//--------------------------------------------------------------------------
+// flowbits option config
+//--------------------------------------------------------------------------
 
 class FlowBitsOption : public IpsOption
 {
 public:
-    FlowBitsOption(FLOWBITS_OP* c) :
+    FlowBitsOption(FlowBitCheck* c) :
         IpsOption(s_name, RULE_OPTION_TYPE_FLOWBIT), config(c)
     { }
 
@@ -146,11 +149,16 @@ public:
 
     EvalStatus eval(Cursor&, Packet*) override;
 
-    bool is_set(uint8_t bits)
-    { return (config->type & bits) != 0; }
+    bool is_setter()
+    { return config->is_setter(); }
+
+    void get_dependencies(bool& set, std::vector<std::string>& bits);
 
 private:
-    FLOWBITS_OP* config;
+    bool is_set(BitOp*);
+
+private:
+    FlowBitCheck* config;
 };
 
 //-------------------------------------------------------------------------
@@ -165,11 +173,11 @@ FlowBitsOption::~FlowBitsOption()
 uint32_t FlowBitsOption::hash() const
 {
     uint32_t a,b,c;
-    const FLOWBITS_OP* data = config;
+    const FlowBitCheck* data = config;
     unsigned i;
     unsigned j = 0;
 
-    a = data->eval;
+    a = data->or_bits ? 1 : 0;
     b = data->type;
     c = 0;
 
@@ -198,8 +206,6 @@ uint32_t FlowBitsOption::hash() const
         b += data->ids[data->ids.size() - 1]|data->ids.size() << 16;
     }
 
-    c += data->group_id;
-
     finalize(a,b,c);
 
     return c;
@@ -213,9 +219,8 @@ bool FlowBitsOption::operator==(const IpsOption& ips) const
     const FlowBitsOption& rhs = (const FlowBitsOption&)ips;
 
     if ( (config->ids.size() != rhs.config->ids.size()) or
-            (config->eval != rhs.config->eval) or
-            (config->type != rhs.config->type) or
-            (config->group_id != rhs.config->group_id) )
+            (config->or_bits != rhs.config->or_bits) or
+            (config->type != rhs.config->type) )
         return false;
 
     for ( unsigned i = 0; i < config->ids.size(); i++ )
@@ -229,375 +234,138 @@ bool FlowBitsOption::operator==(const IpsOption& ips) const
 
 IpsOption::EvalStatus FlowBitsOption::eval(Cursor&, Packet* p)
 {
-    RuleProfile profile(flowBitsPerfStats);
-    return check_flowbits(config, p);
-}
-
-//-------------------------------------------------------------------------
-// helper methods
-//-------------------------------------------------------------------------
-
-static inline BitOp* get_flow_bitop(const Packet* p, FlowBitState* flowbit_state)
-{
-    Flow* flow = p->flow;
-
-    if (!flow)
-        return nullptr;
-
-    if ( !flow->bitop )
-        flow->bitop = new BitOp(flowbit_state->flowbits_count);
-
-    return flow->bitop;
-}
-
-static inline int clear_group_bit(
-    BitOp* bitop, const std::string& group, FlowBitState* flowbit_state)
-{
-    if ( group.empty() )
-        return 0;
-
-    // FIXIT-M why is the hash lookup done at runtime for flowbits groups?
-    // a pointer to flowbits_grp should be in flowbits config data
-    // this *should* be safe but iff splay mode is disabled
-    auto flowbits_grp = (FLOWBITS_GRP*)flowbit_state->flowbits_grp_hash->find(group.c_str());
-
-    if ( !flowbits_grp )
-        return 0;
+    RuleProfile profile(flowbits_profile);
 
-    if ( !bitop or (bitop->size() <= flowbits_grp->max_id) or !flowbits_grp->count )
-        return 0;
+    if ( !p->flow )
+        return IpsOption::NO_MATCH;
 
-    auto GrpBitOp = flowbits_grp->GrpBitOp;
+    BitOp* bitop = p->flow->bitop;
 
-    /* note, max_id is an index, not a count.
-     * Calculate max_bytes by adding 8 to max_id, then dividing by 8.  */
-    unsigned int max_bytes = (flowbits_grp->max_id + 8) >> 3;
+    // do ops that don't require a bit
+    switch ( config->type )
+    {
+    case FlowBitCheck::SET:
+        break;
 
-    for ( unsigned int i = 0; i < max_bytes; i++ )
-        bitop->get_buf_element(i) &= ~GrpBitOp->get_buf_element(i);
+    case FlowBitCheck::UNSET:
+        if ( !bitop )
+            return IpsOption::MATCH;
 
-    return 1;
-}
+        for ( auto id : config->ids )
+            bitop->clear(id);
 
-static inline int toggle_group_bit(
-    BitOp* bitop, const std::string& group, FlowBitState* flowbit_state)
-{
-    if ( group.empty() )
-        return 0;
+        return IpsOption::MATCH;
 
-    auto flowbits_grp = (FLOWBITS_GRP*)flowbit_state->flowbits_grp_hash->find(group.c_str());
+    case FlowBitCheck::IS_SET:
+        if ( !bitop )
+            return IpsOption::FAILED_BIT;
 
-    if ( !flowbits_grp )
-        return 0;
+        if ( is_set(bitop) )
+            return IpsOption::MATCH;
 
-    if ( !bitop or  (bitop->size() <= flowbits_grp->max_id) or  !flowbits_grp->count )
-        return 0;
+        return IpsOption::FAILED_BIT;
 
-    auto GrpBitOp = flowbits_grp->GrpBitOp;
+    case FlowBitCheck::IS_NOT_SET:
+        if ( !bitop or !is_set(bitop) )
+            return IpsOption::MATCH;
 
-    /* note, max_id is an index, not a count.
-     * Calculate max_bytes by adding 8 to max_id, then dividing by 8.  */
-    unsigned int max_bytes = (flowbits_grp->max_id + 8) >> 3;
-    for ( unsigned int i = 0; i < max_bytes; i++ )
-        bitop->get_buf_element(i) ^= GrpBitOp->get_buf_element(i);
+        return IpsOption::FAILED_BIT;
 
-    return 1;
-}
+    case FlowBitCheck::NO_ALERT:
+        return IpsOption::NO_ALERT;
+    }
 
-static inline int set_xbits_to_group(
-    BitOp* bitop, FLOWBITS_OP* fb, FlowBitState* flowbit_state)
-{
-    if ( !clear_group_bit(bitop, fb->group, flowbit_state) )
-        return 0;
+    // do ops that require a bit (set)
+    if ( !bitop )
+        bitop = p->flow->bitop = new BitOp(config->max);
 
-    for ( auto id : fb->ids )
+    for ( auto id : config->ids )
         bitop->set(id);
 
-    return 1;
+    return IpsOption::MATCH;
 }
 
-static inline int is_set_flowbits(
-    BitOp* bitop, FLOWBITS_OP* fb, FlowBitState* flowbit_state)
+bool FlowBitsOption::is_set(BitOp* bitop)
 {
-    FLOWBITS_GRP* flowbits_grp;
-
-    switch ( fb->eval )
+    if ( !config->or_bits )
     {
-    case FLOWBITS_AND:
-        for ( auto id : fb->ids )
+        for ( auto id : config->ids )
         {
             if ( !bitop->is_set(id) )
-                return 0;
-        }
-        return 1;
-
-    case FLOWBITS_OR:
-        for ( auto id : fb->ids )
-        {
-            if ( bitop->is_set(id) )
-                return 1;
-        }
-        return 0;
-
-    case FLOWBITS_ALL:
-        flowbits_grp = (FLOWBITS_GRP*)flowbit_state->flowbits_grp_hash->find(fb->group.c_str());
-
-        if ( !flowbits_grp )
-            return 0;
-
-        for ( unsigned i = 0; i <= (unsigned int)(flowbits_grp->max_id >>3); i++ )
-        {
-            uint8_t val = bitop->get_buf_element(i) & flowbits_grp->GrpBitOp->get_buf_element(i);
-
-            if ( val != flowbits_grp->GrpBitOp->get_buf_element(i) )
-                return 0;
-        }
-        return 1;
-
-    case FLOWBITS_ANY:
-        flowbits_grp = (FLOWBITS_GRP*)flowbit_state->flowbits_grp_hash->find(fb->group.c_str());
-
-        if ( !flowbits_grp )
-            return 0;
-
-        for ( unsigned i = 0; i <= (unsigned int)(flowbits_grp->max_id >>3); i++ )
-        {
-            uint8_t val = bitop->get_buf_element(i) & flowbits_grp->GrpBitOp->get_buf_element(i);
-            if ( val )
-                return 1;
+                return false;
         }
-        return 0;
-
-    default:
-        return 0;
+        return true;
+    }
+    for ( auto id : config->ids )
+    {
+        if ( bitop->is_set(id) )
+            return true;
     }
+    return false;
 }
 
-static IpsOption::EvalStatus check_flowbits(FLOWBITS_OP* fb, Packet* p)
+void FlowBitsOption::get_dependencies(bool& set, std::vector<std::string>& bits)
 {
-    int result = 0;
-
-    FlowBitState* flowbit_state = SnortConfig::get_conf()->flowbit_state;
-    assert(flowbit_state != nullptr);
+    set = config->is_setter();
 
-    BitOp* bitop = get_flow_bitop(p, flowbit_state);
-    if (!bitop)
-        return IpsOption::NO_MATCH;
-
-    switch (fb->type)
+    for ( auto id : config->ids )
     {
-    case FLOWBITS_SET:
-        for ( auto id : fb->ids )
-            bitop->set(id);
-        result = 1;
-        break;
-
-    case FLOWBITS_SETX:
-        result = set_xbits_to_group(bitop, fb, flowbit_state);
-        break;
-
-    case FLOWBITS_UNSET:
-        if (fb->eval == FLOWBITS_ALL )
-            clear_group_bit(bitop, fb->group, flowbit_state);
-        else
-        {
-            for ( auto id : fb->ids )
-                bitop->clear(id);
-        }
-        result = 1;
-        break;
-
-    case FLOWBITS_RESET:
-        if ( fb->group.empty() )
-            bitop->reset();
-        else
-            clear_group_bit(bitop, fb->group, flowbit_state);
-
-        result = 1;
-        break;
-
-    case FLOWBITS_ISSET:
-        if ( is_set_flowbits(bitop, fb, flowbit_state) )
-            result = 1;
-        else
-            return IpsOption::FAILED_BIT;
-        break;
-
-    case FLOWBITS_ISNOTSET:
-        if ( !is_set_flowbits(bitop, fb, flowbit_state) )
-            result = 1;
-        else
-            return IpsOption::FAILED_BIT;
-        break;
-
-    case FLOWBITS_TOGGLE:
-        if ( !fb->group.empty() )
-            toggle_group_bit(bitop, fb->group, flowbit_state);
-
-        else for ( auto id : fb->ids )
-        {
-            if (bitop->is_set(id))
-                bitop->clear(id);
-            else
-                bitop->set(id);
-        }
-        result = 1;
-
-        break;
-
-    case FLOWBITS_NOALERT:
-        /*
-         **  This logic allows us to put flowbits: noalert any where
-         **  in the detection chain, and still do bit ops after this
-         **  option.
-         */
-        return IpsOption::NO_ALERT;
-
-    default:
-        return IpsOption::NO_MATCH;
+        assert(id < bit_keys.size());
+        bits.emplace_back(bit_keys[id]);
     }
-
-    if (result == 1)
-        return IpsOption::MATCH;
-
-    return IpsOption::NO_MATCH;
 }
 
 //-------------------------------------------------------------------------
 // public methods
 //-------------------------------------------------------------------------
-void flowbits_ginit(SnortConfig* sc)
-{
-    sc->flowbit_state = new FlowBitState;
-    sc->flowbit_state->flowbits_hash = new GHash(10000, 0, 0, free_item);
-
-    // this is used during parse time and runtime so do NOT
-    // enable splay mode (which is NOT useful here anyway)
-    sc->flowbit_state->flowbits_grp_hash = new GHash(10000, 0, 0, free_group);
-    sc->flowbit_state->flowbits_bit_queue = sfqueue_new();
-}
 
-void flowbits_gterm(SnortConfig* sc)
+bool flowbits_setter(void* option_data)
 {
-    FlowBitState* flowbit_state = sc->flowbit_state;
-    if (flowbit_state == nullptr)
-        return;
-
-    if ( flowbit_state->flowbits_hash )
-        delete flowbit_state->flowbits_hash;
-
-    if ( flowbit_state->flowbits_grp_hash )
-        delete flowbit_state->flowbits_grp_hash;
-
-    if ( flowbit_state->flowbits_bit_queue )
-        sfqueue_free_all(flowbit_state->flowbits_bit_queue, nullptr);
-
-    delete flowbit_state;
-    flowbit_state = nullptr;
+    FlowBitsOption* p = (FlowBitsOption*)option_data;
+    return p->is_setter();
 }
 
-int FlowBits_SetOperation(void* option_data)
+void get_flowbits_dependencies(void* option_data, bool& set, std::vector<std::string>& bits)
 {
     FlowBitsOption* p = (FlowBitsOption*)option_data;
-
-    if (p->is_set(FLOWBITS_SET | FLOWBITS_SETX |FLOWBITS_UNSET | FLOWBITS_TOGGLE |
-        FLOWBITS_RESET))
-    {
-        return 1;
-    }
-    return 0;
+    p->get_dependencies(set, bits);
 }
 
 //-------------------------------------------------------------------------
 // parsing methods
 //-------------------------------------------------------------------------
 
-static bool validate_name(const char* name)
+static FlowBit* get_bit(
+    const char* bit, FlowBitCheck* check)
 {
-    assert(name);
+    FlowBit& flow_bit = bit_map[bit];
 
-    for ( unsigned i=0; i<strlen(name); i++ )
+    if ( flow_bit.is_new() )
     {
-        if (!isalnum(name[i]) and (nullptr == strchr(ALLOWED_SPECIAL_CHARS,name[i])))
-            return false;
+        flow_bit.id = bit_map.size() - 1;
+        bit_keys.emplace_back(bit);
     }
-    return true;
-}
-
-static FLOWBITS_OBJECT* get_item(
-    const char* bit, FLOWBITS_OP* flowbits, FlowBitState* flowbit_state)
-{
-    if ( !validate_name(bit) )
-    {
-        ParseAbort("%s: name is limited to any alphanumeric string including %s",
-            s_name, ALLOWED_SPECIAL_CHARS);
-    }
-
-    FLOWBITS_OBJECT* flowbits_item = (FLOWBITS_OBJECT*)flowbit_state->flowbits_hash->find(bit);
-
-    if ( !flowbits_item )
-    {
-        flowbits_item = new FLOWBITS_OBJECT;
-
-        if (sfqueue_count(flowbit_state->flowbits_bit_queue) > 0)
-        {
-            flowbits_item->id = (uint16_t)(uintptr_t)sfqueue_remove(
-                flowbit_state->flowbits_bit_queue);
-        }
-        else
-        {
-            flowbits_item->id = flowbit_state->flowbits_count++;
-
-            if ( !flowbit_state->flowbits_count )
-            {
-                ParseError("The number of flowbit IDs in the current ruleset exceeds "
-                    "the maximum number of IDs that are allowed (%u).",
-                    flowbit_state->flowbits_count-1);
-            }
-        }
 
-        int hstatus = flowbit_state->flowbits_hash->insert(bit, flowbits_item);
+    if ( check->is_setter() )
+        flow_bit.sets++;
 
-        if (hstatus != HASH_OK)
-            ParseError("Could not add flowbits key (%s) to hash.", bit);
-    }
-    flowbits_item->toggle = flowbit_state->flowbits_toggle;
-    flowbits_item->types |= flowbits->type;
+    else if ( check->is_checker() )
+        flow_bit.checks++;
 
-    switch (flowbits->type)
-    {
-    case FLOWBITS_SET:
-    case FLOWBITS_SETX:
-    case FLOWBITS_UNSET:
-    case FLOWBITS_TOGGLE:
-    case FLOWBITS_RESET:
-        flowbits_item->set++;
-        break;
-    case FLOWBITS_ISSET:
-    case FLOWBITS_ISNOTSET:
-        flowbits_item->isset++;
-        break;
-    default:
-        break;
-    }
-
-    return flowbits_item;
+    return &flow_bit;
 }
 
-static void parse_flowbits(
-    const char* flowbits_names, FLOWBITS_OP* flowbits, FlowBitState* flowbit_state)
+static bool parse_flowbits(const char* flowbits_names, FlowBitCheck* check)
 {
-    FLOWBITS_OBJECT* flowbits_item;
-
-    if ( !flowbits_names or  ((*flowbits_names) == 0) )
-        return;
+    assert(flowbits_names);
+    FlowBit* flow_bit;
 
     if ( strchr(flowbits_names, '|') )
     {
         if ( strchr(flowbits_names, '&') )
         {
             ParseError("%s: tag id opcode '|' and '&' are used together.", s_name);
-            return;
+            return false;
         }
         std::string bits = flowbits_names;
         std::replace(bits.begin(), bits.end(), '|', ' ');
@@ -606,10 +374,10 @@ static void parse_flowbits(
 
         while ( ss >> tok )
         {
-            flowbits_item = get_item(tok.c_str(), flowbits, flowbit_state);
-            flowbits->ids.push_back(flowbits_item->id);
+            flow_bit = get_bit(tok.c_str(), check);
+            check->add(flow_bit->id);
         }
-        flowbits->eval = FLOWBITS_OR;
+        check->or_bits = true;
     }
     else if ( strchr(flowbits_names, '&') )
     {
@@ -620,339 +388,59 @@ static void parse_flowbits(
 
         while ( ss >> tok )
         {
-            flowbits_item = get_item(tok.c_str(), flowbits, flowbit_state);
-            flowbits->ids.push_back(flowbits_item->id);
-        }
-        flowbits->eval = FLOWBITS_AND;
-    }
-    else if ( !strcasecmp(flowbits_names, "all") )
-    {
-        flowbits->eval = FLOWBITS_ALL;
-    }
-    else if ( !strcasecmp(flowbits_names, "any") )
-    {
-        flowbits->eval = FLOWBITS_ANY;
-    }
-    else
-    {
-        flowbits_item = get_item(flowbits_names, flowbits, flowbit_state);
-        flowbits->ids.push_back(flowbits_item->id);
-    }
-}
-
-static void validateFlowbitsSyntax(FLOWBITS_OP* flowbits)
-{
-    switch (flowbits->type)
-    {
-    case FLOWBITS_SET:
-        if ( (flowbits->eval == FLOWBITS_AND) and !flowbits->ids.empty() )
-            break;
-
-        ParseError("%s: operation set uses syntax: flowbits:set,bit[&bit],[group].", s_name);
-        return;
-
-    case FLOWBITS_SETX:
-        if ( (flowbits->eval == FLOWBITS_AND) and !flowbits->group.empty() and
-            !flowbits->ids.empty() )
-            break;
-
-        ParseError("%s: operation setx uses syntax: flowbits:setx,bit[&bit],group.", s_name);
-        return;
-
-    case FLOWBITS_UNSET:
-        if (((flowbits->eval == FLOWBITS_AND) and flowbits->group.empty() and !flowbits->ids.empty())
-            or ((flowbits->eval == FLOWBITS_ALL) and !flowbits->group.empty()))
-            break;
-
-        ParseError("%s: operation unset uses syntax: flowbits:unset,bit[&bit] OR"
-            " flowbits:unset, all, group.", s_name);
-        return;
-
-    case FLOWBITS_TOGGLE:
-        if (((flowbits->eval == FLOWBITS_AND) and flowbits->group.empty() and !flowbits->ids.empty())
-            or ((flowbits->eval == FLOWBITS_ALL) and !flowbits->group.empty()))
-            break;
-
-        ParseError("%s: operation toggle uses syntax: flowbits:toggle,bit[&bit] OR"
-            " flowbits:toggle,all,group.", s_name);
-        return;
-
-    case FLOWBITS_ISSET:
-        if ((((flowbits->eval == FLOWBITS_AND) or (flowbits->eval == FLOWBITS_OR)) and
-            flowbits->group.empty() and !flowbits->ids.empty())
-            or (((flowbits->eval == FLOWBITS_ANY) or (flowbits->eval == FLOWBITS_ALL)) and
-            !flowbits->group.empty()))
-            break;
-
-        ParseError("%s: operation isset uses syntax: flowbits:isset,bit[&bit] OR "
-            "flowbits:isset,bit[|bit] OR flowbits:isset,all,group OR flowbits:isset,any,group.",
-            s_name);
-        return;
-
-    case FLOWBITS_ISNOTSET:
-        if ((((flowbits->eval == FLOWBITS_AND) or  (flowbits->eval == FLOWBITS_OR)) and
-            flowbits->group.empty() and !flowbits->ids.empty())
-            or ((((flowbits->eval == FLOWBITS_ANY)) or (flowbits->eval == FLOWBITS_ALL)) and
-            !flowbits->group.empty()))
-            break;
-
-        ParseError("%s: operation isnotset uses syntax: flowbits:isnotset,bit[&bit] OR "
-            "flowbits:isnotset,bit[|bit] OR flowbits:isnotset,all,group OR "
-            "flowbits:isnotset,any,group.", s_name);
-        return;
-
-    case FLOWBITS_RESET:
-        if ( flowbits->ids.empty() )
-            break;
-
-        ParseError(
-            "%s: operation unset uses syntax: flowbits:reset OR flowbits:reset, group.", s_name);
-        return;
-
-    case FLOWBITS_NOALERT:
-        if ( flowbits->ids.empty() and flowbits->group.empty() )
-            break;
-
-        ParseError("%s: operation noalert uses syntax: flowbits:noalert.", s_name);
-        return;
-
-    default:
-        ParseError("%s: unknown opcode.", s_name);
-        return;
-    }
-}
-
-static FLOWBITS_GRP* get_group(const char* group, FlowBitState* flowbit_state)
-{
-    if (!validate_name(group))
-    {
-        ParseAbort(
-            "%s: flowbits group name is limited to any alphanumeric string including %s",
-            s_name, ALLOWED_SPECIAL_CHARS);
-    }
-
-    FLOWBITS_GRP* flowbits_grp = (FLOWBITS_GRP*)flowbit_state->flowbits_grp_hash->find(group);
-
-    if ( !flowbits_grp )
-    {
-        // new group defined, add (bitop set later once we know size)
-        flowbits_grp = new FLOWBITS_GRP;
-        flowbit_state->flowbits_grp_hash->insert(group, flowbits_grp);
-        flowbit_state->flowbits_grp_count++;
-        flowbits_grp->group_id = flowbit_state->flowbits_grp_count;
-        flowbits_grp->name = group;
-    }
-
-    return flowbits_grp;
-}
-
-static void parse_flowbits_with_group(
-    const char* bits, const char* group, FLOWBITS_OP* flowbits, FlowBitState* flowbit_state)
-{
-    parse_flowbits(bits, flowbits, flowbit_state);
-
-    if ( group and flowbits->group.empty() )
-    {
-        flowbits->group = group;
-        FLOWBITS_GRP* flowbits_grp = get_group(group, flowbit_state);
-        flowbits->group_id = flowbits_grp->group_id;
-    }
-    validateFlowbitsSyntax(flowbits);
-
-    if ( !flowbits->group.empty() )
-        flowbit_state->op_list.push_front(flowbits);
-}
-
-static FLOWBITS_OP* flowbits_parse(
-    std::string& op, std::string& bits, std::string& group, SnortConfig* sc)
-{
-    FlowBitState* flowbit_state = sc->flowbit_state;
-    assert(flowbit_state != nullptr);
-
-    FLOWBITS_OP* flowbits = new FLOWBITS_OP;
-    flowbits->name = op;
-
-    if ( op == "set" )
-        flowbits->type = FLOWBITS_SET;
-
-    else if ( op == "setx" )
-        flowbits->type = FLOWBITS_SETX;
-
-    else if ( op == "unset" )
-        flowbits->type = FLOWBITS_UNSET;
-
-    else if ( op == "toggle" )
-        flowbits->type = FLOWBITS_TOGGLE;
-
-    else if ( op == "isset" )
-        flowbits->type = FLOWBITS_ISSET;
-
-    else if ( op == "isnotset" )
-        flowbits->type = FLOWBITS_ISNOTSET;
-
-    else if ( op == "noalert" )
-    {
-        if ( !bits.empty() )
-        {
-            ParseError("%s: invalid configuration.", s_name);
-            delete flowbits;
-            return nullptr;
-        }
-
-        flowbits->type = FLOWBITS_NOALERT;
-        return flowbits;
-    }
-    else if ( op == "reset" )
-    {
-        if ( !group.empty() )
-        {
-            ParseError("%s: invalid configuration.", s_name);
-            delete flowbits;
-            return nullptr;
+            flow_bit = get_bit(tok.c_str(), check);
+            check->add(flow_bit->id);
         }
-        if ( !bits.empty() )
-        {
-            group = bits;
-            FLOWBITS_GRP* flowbits_grp = get_group(group.c_str(), flowbit_state);
-            flowbits->group = group;
-            flowbits->group_id = flowbits_grp->group_id;
-        }
-        flowbits->type = FLOWBITS_RESET;
-        return flowbits;
+        check->or_bits = false;
     }
     else
     {
-        ParseError("%s: invalid configuration.", s_name);
-        delete flowbits;
-        return nullptr;
-    }
-
-    parse_flowbits_with_group(bits.c_str(), group.c_str(), flowbits, flowbit_state);
-    return flowbits;
-}
-
-static void update_group(FLOWBITS_GRP* flowbits_grp, int id)
-{
-    flowbits_grp->count++;
-
-    if ( flowbits_grp->max_id < id )
-        flowbits_grp->max_id = id;
-
-    flowbits_grp->GrpBitOp->set(id);
-}
-
-static void init_groups(FlowBitState* flowbit_state)
-{
-    if ( !flowbit_state->flowbits_hash or !flowbit_state->flowbits_grp_hash )
-        return;
-
-    for (GHashNode* n = flowbit_state->flowbits_grp_hash->find_first();
-         n != nullptr;
-         n= flowbit_state->flowbits_grp_hash->find_next())
-    {
-        FLOWBITS_GRP* fbg = (FLOWBITS_GRP*)n->data;
-        fbg->GrpBitOp = new BitOp(flowbit_state->flowbits_count);
-        fbg->GrpBitOp->reset();
-    }
-
-    while ( !flowbit_state->op_list.empty() )
-    {
-        const FLOWBITS_OP* fbop = flowbit_state->op_list.front();
-        FLOWBITS_GRP* fbg =
-            (FLOWBITS_GRP*)flowbit_state->flowbits_grp_hash->find(fbop->group.c_str());
-        assert(fbg);
-
-        for ( unsigned i = 0; i < fbop->ids.size(); ++i )
-            update_group(fbg, fbop->ids[i]);
-
-        flowbit_state->op_list.pop_front();
+        flow_bit = get_bit(flowbits_names, check);
+        check->add(flow_bit->id);
     }
+    return true;
 }
 
-static void flowbits_verify(FlowBitState* flowbit_state)
+static void flowbits_verify()
 {
-    GHashNode* n;
-    unsigned num_flowbits = 0;
     unsigned unchecked = 0, unset = 0;
 
-    if (flowbit_state->flowbits_hash == nullptr)
-        return;
-
-    for (n = flowbit_state->flowbits_hash->find_first();
-         n != nullptr;
-         n = flowbit_state->flowbits_hash->find_next())
+    for ( const auto& it : bit_map )
     {
-        FLOWBITS_OBJECT* fb = (FLOWBITS_OBJECT*)n->data;
-
-        if (fb->toggle != flowbit_state->flowbits_toggle)
-        {
-            sfqueue_add(flowbit_state->flowbits_bit_queue, (NODE_DATA)(uintptr_t)fb->id);
-            flowbit_state->flowbits_hash->remove(n->key);
-            continue;
-        }
-
-        if ((fb->set > 0) and (fb->isset == 0))
+        if ((it.second.sets > 0) and (it.second.checks == 0))
         {
             ParseWarning(WARN_FLOWBITS, "%s key '%s' is set but not checked.",
-                s_name, (const char*)n->key);
+                s_name, it.first.c_str());
             unchecked++;
         }
-        else if ((fb->isset > 0) and (fb->set == 0))
+        else if ((it.second.checks > 0) and (it.second.sets == 0))
         {
-            ParseWarning(WARN_FLOWBITS, "%s key '%s' is checked but not ever set.",
-                s_name, (const char*)n->key);
+            ParseWarning(WARN_FLOWBITS, "%s key '%s' is checked but not set.",
+                s_name, it.first.c_str());
             unset++;
         }
-        else if ((fb->set == 0) and (fb->isset == 0))
-        {
-            continue; /* don't count this bit as used */
-        }
-
-        num_flowbits++;
     }
-    assert(num_flowbits == flowbit_state->flowbits_count);
 
-    flowbit_state->flowbits_toggle ^= 1;
-
-    if ( !num_flowbits )
+    if ( !bit_map.size() )
         return;
 
     LogLabel(s_name);
-    LogCount("defined", num_flowbits);
+    LogCount("defined", bit_map.size());
     LogCount("not checked", unchecked);
     LogCount("not set", unset);
 }
 
-static void free_item(void* d)
-{
-    FLOWBITS_OBJECT* data = (FLOWBITS_OBJECT*)d;
-    delete data;
-}
-
-static void free_group(void* d)
-{
-    FLOWBITS_GRP* data = (FLOWBITS_GRP*)d;
-
-    if (data->GrpBitOp)
-        delete data->GrpBitOp;
-
-    delete data;
-}
-
 //-------------------------------------------------------------------------
 // module
 //-------------------------------------------------------------------------
 
 static const Parameter s_params[] =
 {
-    { "~op", Parameter::PT_STRING, nullptr, nullptr,
-      "set|reset|isset|etc." },  // FIXIT-L replace this legacy flowbits parsing with PT_SELECT
+    { "~op", Parameter::PT_ENUM, "set | unset | isset | isnotset | noalert", nullptr,
+      "bit operation or noalert (no bits)" },
 
     { "~bits", Parameter::PT_STRING, nullptr, nullptr,
-      "bits or group" },
-
-    { "~group", Parameter::PT_STRING, nullptr, nullptr,
-      "group if arg1 is bits" },
+      "bit [|bit]* or bit [&bit]*" },
 
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
@@ -964,64 +452,63 @@ class FlowbitsModule : public Module
 {
 public:
     FlowbitsModule() : Module(s_name, s_help, s_params) { }
+    ~FlowbitsModule() { delete fbc; }
 
     bool begin(const char*, int, SnortConfig*) override;
     bool set(const char*, Value&, SnortConfig*) override;
     bool end(const char*, int, SnortConfig*) override;
 
     ProfileStats* get_profile() const override
-    { return &flowBitsPerfStats; }
+    { return &flowbits_profile; }
 
     Usage get_usage() const override
     { return DETECT; }
 
-    FLOWBITS_OP* get_data();
+    FlowBitCheck* get_data();
 
 public:
-    std::string op;
+    FlowBitCheck::Op op;
     std::string bits;
-    std::string group;
-    FLOWBITS_OP* fbop = nullptr;
+    FlowBitCheck* fbc = nullptr;
 };
 
 bool FlowbitsModule::begin(const char*, int, SnortConfig*)
 {
-    op.clear();
+    delete fbc;
     bits.clear();
-    group.clear();
     return true;
 }
 
 bool FlowbitsModule::set(const char*, Value& v, SnortConfig*)
 {
     if ( v.is("~op") )
-        op = v.get_string();
+        op = static_cast<FlowBitCheck::Op>(v.get_uint8());
 
     else if ( v.is("~bits") )
         bits = v.get_string();
 
-    else if ( v.is("~group") )
-        group = v.get_string();
-
     else
         return false;
 
     return true;
 }
 
-bool FlowbitsModule::end(const char*, int, SnortConfig* sc)
+bool FlowbitsModule::end(const char*, int, SnortConfig*)
 {
-    if ( op.empty() )
-        return false;
+    fbc = new FlowBitCheck(op);
+    bool ok = true;
+
+    if ( fbc->is_setter() or fbc->is_checker() )
+        ok = parse_flowbits(bits.c_str(), fbc);
 
-    fbop = flowbits_parse(op, bits, group, sc);
-    return fbop != nullptr;
+    ok = ok and fbc->validate();
+    return ok;
 }
 
-FLOWBITS_OP* FlowbitsModule::get_data()
+FlowBitCheck* FlowbitsModule::get_data()
 {
-    FLOWBITS_OP* tmp = fbop;
-    fbop = nullptr;
+    FlowBitCheck* tmp = fbc;
+    fbc = nullptr;
     return tmp;
 }
 
@@ -1037,17 +524,14 @@ static Module* mod_ctor()
 static void mod_dtor(Module* m)
 {
     FlowbitsModule* fb = (FlowbitsModule*)m;
-    if (fb->fbop)
-        delete fb->fbop;
-
     delete fb;
 }
 
 static IpsOption* flowbits_ctor(Module* p, OptTreeNode*)
 {
     FlowbitsModule* m = (FlowbitsModule*)p;
-    FLOWBITS_OP* fbop = m->get_data();
-    return new FlowBitsOption(fbop);
+    FlowBitCheck* fbc = m->get_data();
+    return new FlowBitsOption(fbc);
 }
 
 static void flowbits_dtor(IpsOption* p)
@@ -1055,27 +539,10 @@ static void flowbits_dtor(IpsOption* p)
     delete p;
 }
 
-static void flowbits_verify(SnortConfig* sc)
-{
-    FlowBitState* flowbit_state = sc->flowbit_state;
-    init_groups(flowbit_state);
-    flowbits_verify(flowbit_state);
-}
-
-#if 0
-// FIXIT-M if add_detection_option() finds a dup, then
-// we can leak the original group name if same as current
-// also, why use new group name instead of original?
-char* group_name =  ((FLOWBITS_OP*)idx_dup)->group;
-
-if (flowbits->group)
+static void flowbits_verify(SnortConfig*)
 {
-    if (group_name and strcmp(group_name, flowbits->group))
-        snort_free(group_name);
-    ((FLOWBITS_OP*)idx_dup)->group = snort_strdup(flowbits->group);
+    flowbits_verify();
 }
-// ... then delete current and use original
-#endif
 
 static const IpsApi flowbits_api =
 {
index ca289551ae527e0fbd3b6b1a0a157ea0ac0b4131..08684ea527234c85c2fa1e02b0e85940f667ae68 100644 (file)
@@ -1,6 +1,5 @@
 //--------------------------------------------------------------------------
 // Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2004-2013 Sourcefire, Inc.
 //
 // 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
 #ifndef IPS_FLOWBITS_H
 #define IPS_FLOWBITS_H
 
-#include "main/snort_config.h"
-namespace snort
-{
-struct SnortConfig;
-}
+#include <string>
+#include <vector>
 
-void flowbits_ginit(snort::SnortConfig*);
-void flowbits_gterm(snort::SnortConfig*);
-int FlowBits_SetOperation(void*);
+bool flowbits_setter(void*);
+void get_flowbits_dependencies(void*, bool& set, std::vector<std::string>& bits);
 
 #endif
 
index 275ec03bd8f312651d0705938fb67b2b845d1513..6de8f3ff54cfeafad4eae4b2a380593992e55216 100644 (file)
@@ -77,7 +77,6 @@ extern const BaseApi* ips_rem[];
 extern const BaseApi* ips_rev[];
 extern const BaseApi* ips_rpc[];
 extern const BaseApi* ips_seq[];
-extern const BaseApi* ips_session[];
 extern const BaseApi* ips_sid[];
 extern const BaseApi* ips_soid[];
 extern const BaseApi* ips_target[];
@@ -150,7 +149,6 @@ void load_ips_options()
     PluginManager::load_plugins(ips_rev);
     PluginManager::load_plugins(ips_rpc);
     PluginManager::load_plugins(ips_seq);
-    PluginManager::load_plugins(ips_session);
     PluginManager::load_plugins(ips_sid);
     PluginManager::load_plugins(ips_soid);
     PluginManager::load_plugins(ips_target);
diff --git a/src/ips_options/ips_session.cc b/src/ips_options/ips_session.cc
deleted file mode 100644 (file)
index 598edbe..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2002-2013 Sourcefire, Inc.
-// Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
-//
-// 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.
-//--------------------------------------------------------------------------
-
-/* Snort Session Logging Plugin */
-
-/* sp_session
- *
- * Purpose:
- *
- * Drops data (printable or otherwise) into a SESSION file.  Useful for
- * logging user sessions (telnet, http, ftp, etc).
- *
- * Arguments:
- *
- * This plugin can take two arguments:
- *    printable => only log the "printable" ASCII characters.
- *    all       => log all traffic in the session, logging non-printable
- *                 chars in "\xNN" hexadecimal format
- *
- * Effect:
- *
- * Warning, this plugin may slow Snort *way* down!
- *
- */
-// FIXIT-L delete this (sp_session) and use session tag instead
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <sys/stat.h>
-
-#include "framework/ips_option.h"
-#include "framework/module.h"
-#include "hash/hash_key_operations.h"
-#include "log/messages.h"
-#include "main/snort_config.h"
-#include "profiler/profiler.h"
-#include "protocols/packet.h"
-#include "utils/util.h"
-#include "utils/util_cstring.h"
-
-using namespace snort;
-
-#define s_name "session"
-
-static THREAD_LOCAL ProfileStats sessionPerfStats;
-
-#define SESSION_PRINTABLE   1
-#define SESSION_BINARY      2
-#define SESSION_ALL         3
-
-struct SessionData
-{
-    int session_flag;
-};
-
-class SessionOption : public IpsOption
-{
-public:
-    SessionOption(const SessionData& c) :
-        IpsOption(s_name)
-    { config = c; }
-
-    uint32_t hash() const override;
-    bool operator==(const IpsOption&) const override;
-
-    EvalStatus eval(Cursor&, Packet*) override;
-
-private:
-    SessionData config;
-};
-
-static FILE* OpenSessionFile(Packet*);
-static void DumpSessionData(FILE*, Packet*, SessionData*);
-
-//-------------------------------------------------------------------------
-// class methods
-//-------------------------------------------------------------------------
-
-uint32_t SessionOption::hash() const
-{
-    uint32_t a,b,c;
-    const SessionData* data = &config;
-
-    a = data->session_flag;
-    b = 0;
-    c = 0;
-
-    mix_str(a,b,c,get_name());
-    finalize(a,b,c);
-
-    return c;
-}
-
-bool SessionOption::operator==(const IpsOption& ips) const
-{
-    if ( strcmp(get_name(), ips.get_name()) )
-        return false;
-
-    const SessionOption& rhs = (const SessionOption&)ips;
-    const SessionData* left = &config;
-    const SessionData* right = &rhs.config;
-
-    if (left->session_flag == right->session_flag)
-    {
-        return true;
-    }
-
-    return false;
-}
-
-IpsOption::EvalStatus SessionOption::eval(Cursor&, Packet* p)
-{
-    RuleProfile profile(sessionPerfStats);
-
-    if ( !p->dsize || !p->data )
-        return MATCH;
-
-    if ( p->is_fragment() )
-        return MATCH;
-
-    // FIXIT-L should wrap file open/close in a class to ensure cleanup
-    {
-        FILE* session = OpenSessionFile(p);
-
-        if ( !session )
-            return MATCH;
-
-        DumpSessionData(session, p, &config);
-        fclose(session);
-    }
-
-    return MATCH;
-}
-
-//-------------------------------------------------------------------------
-// implementation methods
-//-------------------------------------------------------------------------
-
-static FILE* OpenSessionFile(Packet* p)
-{
-    char filename[STD_BUF];
-    char session_file[STD_BUF]; /* name of session file */
-    const SfIp* dst, * src;
-
-    FILE* ret;
-
-    if (p->ptrs.decode_flags & DECODE_FRAG)
-    {
-        return nullptr;
-    }
-
-    memset((char*)session_file, 0, STD_BUF);
-
-    /* figure out which way this packet is headed in relation to the homenet */
-    dst = p->ptrs.ip_api.get_dst();
-    src = p->ptrs.ip_api.get_src();
-
-    SfIpString addr;
-
-    if (SnortConfig::get_conf()->homenet.contains(dst) == SFIP_CONTAINS)
-    {
-        if (SnortConfig::get_conf()->homenet.contains(src) == SFIP_NOT_CONTAINS)
-        {
-            p->ptrs.ip_api.get_src()->ntop(addr);
-        }
-        else
-        {
-            if (p->ptrs.sp >= p->ptrs.dp)
-            {
-                p->ptrs.ip_api.get_src()->ntop(addr);
-            }
-            else
-            {
-                p->ptrs.ip_api.get_dst()->ntop(addr);
-            }
-        }
-    }
-    else
-    {
-        if (SnortConfig::get_conf()->homenet.contains(src) == SFIP_CONTAINS)
-        {
-            p->ptrs.ip_api.get_dst()->ntop(addr);
-        }
-        else
-        {
-            if (p->ptrs.sp >= p->ptrs.dp)
-            {
-                p->ptrs.ip_api.get_src()->ntop(addr);
-            }
-            else
-            {
-                p->ptrs.ip_api.get_dst()->ntop(addr);
-            }
-        }
-    }
-    std::string name;
-    const char* log_path = get_instance_file(name, addr);
-
-    /* build the log directory */
-    if (mkdir(log_path,S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH))
-    {
-        if (errno != EEXIST)
-        {
-            FatalError("Problem creating directory %s: %s\n",
-                log_path, get_error(errno));
-        }
-    }
-
-    if (p->ptrs.sp >= p->ptrs.dp)
-        SnortSnprintf(session_file, STD_BUF, "%s/SESSION:%d-%d", log_path, p->ptrs.sp, p->ptrs.dp);
-    else
-        SnortSnprintf(session_file, STD_BUF, "%s/SESSION:%d-%d", log_path, p->ptrs.dp, p->ptrs.sp);
-
-
-    strncpy(filename, session_file, STD_BUF - 1);
-    filename[STD_BUF - 1] = '\0';
-
-    ret = fopen(session_file, "a");
-
-    if (ret == nullptr)
-    {
-        FatalError("OpenSessionFile() => fopen(%s) session file: %s\n",
-            session_file, get_error(errno));
-    }
-
-    return ret;
-}
-
-static void DumpSessionData(FILE* fp, Packet* p, SessionData* sessionData)
-{
-    const uint8_t* idx;
-    const uint8_t* end;
-    char conv[] = "0123456789ABCDEF"; /* xlation lookup table */
-
-    if (p->dsize == 0 || p->data == nullptr || (p->ptrs.decode_flags & DECODE_FRAG))
-        return;
-
-    idx = p->data;
-    end = idx + p->dsize;
-
-    if (sessionData->session_flag == SESSION_PRINTABLE)
-    {
-        while (idx != end)
-        {
-            if ((*idx > 0x1f && *idx < 0x7f) || *idx == 0x0a || *idx == 0x0d)
-            {
-                fputc(*idx, fp);
-            }
-            idx++;
-        }
-    }
-    else if (sessionData->session_flag == SESSION_BINARY)
-    {
-        fwrite(p->data, p->dsize, sizeof(char), fp);
-    }
-    else
-    {
-        while (idx != end)
-        {
-            if ((*idx > 0x1f && *idx < 0x7f) || *idx == 0x0a || *idx == 0x0d)
-            {
-                /* Escape all occurrences of '\' */
-                if (*idx == '\\')
-                    fputc('\\', fp);
-                fputc(*idx, fp);
-            }
-            else
-            {
-                fputc('\\', fp);
-                fputc(conv[((*idx&0xFF) >> 4)], fp);
-                fputc(conv[((*idx&0xFF)&0x0F)], fp);
-            }
-
-            idx++;
-        }
-    }
-}
-
-//-------------------------------------------------------------------------
-// module
-//-------------------------------------------------------------------------
-
-static const Parameter s_params[] =
-{
-    { "~mode", Parameter::PT_ENUM, "printable|binary|all", nullptr,
-      "output format" },
-
-    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
-};
-
-#define s_help \
-    "rule option to check user data from TCP sessions"
-
-class SsnModule : public Module
-{
-public:
-    SsnModule() : Module(s_name, s_help, s_params) { }
-
-    bool begin(const char*, int, SnortConfig*) override;
-    bool set(const char*, Value&, SnortConfig*) override;
-
-    ProfileStats* get_profile() const override
-    { return &sessionPerfStats; }
-
-    Usage get_usage() const override
-    { return DETECT; }
-
-public:
-    SessionData data;
-};
-
-bool SsnModule::begin(const char*, int, SnortConfig*)
-{
-    memset(&data, 0, sizeof(data));
-    return true;
-}
-
-bool SsnModule::set(const char*, Value& v, SnortConfig*)
-{
-    if ( v.is("~mode") )
-        data.session_flag = v.get_uint8() + 1;
-
-    else
-        return false;
-
-    return true;
-}
-
-//-------------------------------------------------------------------------
-// api methods
-//-------------------------------------------------------------------------
-
-static Module* mod_ctor()
-{
-    return new SsnModule;
-}
-
-static void mod_dtor(Module* m)
-{
-    delete m;
-}
-
-static IpsOption* session_ctor(Module* p, OptTreeNode*)
-{
-    SsnModule* m = (SsnModule*)p;
-    return new SessionOption(m->data);
-}
-
-static void session_dtor(IpsOption* p)
-{
-    delete p;
-}
-
-static const IpsApi session_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        0,
-        API_RESERVED,
-        API_OPTIONS,
-        s_name,
-        s_help,
-        mod_ctor,
-        mod_dtor
-    },
-    OPT_TYPE_LOGGING,
-    /*
-     * Theoretically we should only allow this plugin to be used when
-     * there's a possibility of a session happening (i.e. TCP), but I get
-     * enough requests that I'm going to pull the verifier so that things
-     * should work for everyone
-     */
-    1, /*PROTO_BIT__TCP*/ 0,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    session_ctor,
-    session_dtor,
-    nullptr
-};
-
-#ifdef BUILDING_SO
-SO_PUBLIC const BaseApi* snort_plugins[] =
-#else
-const BaseApi* ips_session[] =
-#endif
-{
-    &session_api.base,
-    nullptr
-};
-
index 75bf2fefe57ffc8cebe8a479ca9557e7e3e6e9d5..c6388cd15d3d8f00a4e290f08a77615fabd88016 100644 (file)
@@ -180,9 +180,6 @@ static void WriteLogMessage(FILE* fh, bool prefer_fh, const char* format, va_lis
 {
     if ( SnortConfig::get_conf() && !prefer_fh )
     {
-        if ( SnortConfig::log_quiet() )
-            return;
-
         if ( SnortConfig::log_syslog() )
         {
             char buf[STD_BUF+1];
@@ -207,6 +204,9 @@ static void WriteLogMessage(FILE* fh, bool prefer_fh, const char* format, va_lis
  */
 void LogMessage(const char* format,...)
 {
+    if ( SnortConfig::get_conf() and SnortConfig::log_quiet() )
+        return;
+
     va_list ap;
     va_start(ap, format);
 
@@ -217,6 +217,9 @@ void LogMessage(const char* format,...)
 
 void LogMessage(FILE* fh, const char* format,...)
 {
+    if ( fh == stdout and SnortConfig::get_conf() and SnortConfig::log_quiet() )
+        return;
+
     va_list ap;
     va_start(ap, format);
 
@@ -239,9 +242,6 @@ void WarningMessage(const char* format,...)
 {
     va_list ap;
 
-    if ( SnortConfig::get_conf() and SnortConfig::log_quiet() )
-        return;
-
     va_start(ap, format);
 
     if ( SnortConfig::get_conf() and SnortConfig::log_syslog() )
index 24665ae49188749aea48b78dadc623d5f3e9b960..ef7309f3647cf839ad67eafbbacb842891acf7e3 100644 (file)
@@ -796,6 +796,24 @@ static bool set_mode()
         return false;
     }
 
+    if ( SnortConfig::dump_rule_deps() )
+    {
+        dump_rule_deps(SnortConfig::get_conf());
+        return false;
+    }
+
+    if ( SnortConfig::dump_rule_meta() )
+    {
+        dump_rule_meta(SnortConfig::get_conf());
+        return false;
+    }
+
+    if ( SnortConfig::dump_rule_state() )
+    {
+        dump_rule_state(SnortConfig::get_conf());
+        return false;
+    }
+
     if ( just_validate() )
     {
         LogMessage("\nSnort successfully validated the configuration (with %u warnings).\n",
index 870b8e3aad35655eab9d4c18afeec3398cfb65bb..8b9ce42ea3b8e667a2177eb36c1004f7beee3c16 100644 (file)
@@ -717,7 +717,7 @@ static const Parameter output_params[] =
       "" },
 
     { "quiet", Parameter::PT_BOOL, nullptr, "false",
-      "suppress non-fatal information (still show alerts, same as -q)" },
+      "suppress normal logging on stdout (same as -q)" },
 
     { "logdir", Parameter::PT_STRING, nullptr, ".",
       "where to put log files (same as -l)" },
@@ -1801,7 +1801,7 @@ bool RuleStateModule::begin(const char*, int, SnortConfig* sc)
 
     else
     {
-        key = { 0, 0 };
+        key = { 0, 0, 0 };
         state.action = snort::Actions::Type::ALERT;
         state.enable = IpsPolicy::Enable::INHERIT_ENABLE;
     }
@@ -1816,7 +1816,7 @@ bool RuleStateModule::end(const char* fqn, int, SnortConfig* sc)
     if ( !key.gid or !key.sid )
         return false;
 
-    state.policy_id = snort::get_ips_policy()->policy_id;
+    key.policy_id = snort::get_ips_policy()->policy_id;
     sc->rule_states->add(key, state);
 
     return true;
index cc65d39ebab0329184b9a99f61de643dc01b97c3..2cefa79835320d17c30b25d8a79b8de32b540193 100644 (file)
@@ -297,10 +297,10 @@ InspectionPolicy* get_inspection_policy()
 IpsPolicy* get_ips_policy()
 { return s_detection_policy; }
 
-IpsPolicy* get_ips_policy(SnortConfig* sc, unsigned i)
+IpsPolicy* get_ips_policy(const SnortConfig* sc, unsigned i)
 {
     return sc && i < sc->policy_map->ips_policy_count() ?
-        sc->policy_map->get_ips_policy(0) : nullptr;
+        sc->policy_map->get_ips_policy(i) : nullptr;
 }
 
 InspectionPolicy* get_default_inspection_policy(SnortConfig* sc)
index 4821aa67496fe27461568f428e8446e2158da4c1..afc0b7edfb86e29e84056cd2a10bf14c7ef0c889 100644 (file)
@@ -278,7 +278,7 @@ namespace snort
 SO_PUBLIC NetworkPolicy* get_network_policy();
 SO_PUBLIC InspectionPolicy* get_inspection_policy();
 SO_PUBLIC IpsPolicy* get_ips_policy();
-SO_PUBLIC IpsPolicy* get_ips_policy(snort::SnortConfig*, unsigned i = 0);
+SO_PUBLIC IpsPolicy* get_ips_policy(const snort::SnortConfig*, unsigned i = 0);
 SO_PUBLIC InspectionPolicy* get_default_inspection_policy(snort::SnortConfig*);
 SO_PUBLIC void set_ips_policy(IpsPolicy* p);
 SO_PUBLIC void set_network_policy(NetworkPolicy* p);
index 89d7ea44174d77cba90fe4b4379fe56618cafc7c..935a8fad649fbf2dd8c8ab0ffd5a3f18feb70430 100644 (file)
@@ -38,7 +38,6 @@
 #include "flow/ha_module.h"
 #include "hash/xhash.h"
 #include "helpers/process.h"
-#include "ips_options/ips_flowbits.h"
 #include "latency/latency_config.h"
 #include "log/messages.h"
 #include "managers/action_manager.h"
@@ -176,7 +175,6 @@ void SnortConfig::init(const SnortConfig* const other_conf, ProtocolReference* p
 
         memset(evalOrder, 0, sizeof(evalOrder));
         proto_ref = new ProtocolReference(protocol_reference);
-        flowbits_ginit(this);
         so_rules = new SoRules;
     }
     else
@@ -257,8 +255,6 @@ SnortConfig::~SnortConfig()
     }
     delete fast_pattern_config;
 
-    flowbits_gterm(this);
-
     delete policy_map;
     InspectorManager::delete_config(this);
     ActionManager::delete_config(this);
index f69d1e0d5e8a2b849f38a7f52a31f9d985da574e..5c2c18bdde91ec77cce488f6e5a63a25444cf420 100644 (file)
@@ -43,7 +43,7 @@ enum RunFlag
     RUN_FLAG__READ                = 0x00000001,
     RUN_FLAG__DAEMON              = 0x00000002,
     RUN_FLAG__DUMP_MSG_MAP        = 0x00000004,
-    // unused                     = 0x00000008,
+    RUN_FLAG__DUMP_RULE_META      = 0x00000008,
 
     RUN_FLAG__INLINE              = 0x00000010,
     RUN_FLAG__STATIC_HASH         = 0x00000020,
@@ -68,7 +68,7 @@ enum RunFlag
     RUN_FLAG__ASSURE_EST          = 0x00080000,
 
     RUN_FLAG__TREAT_DROP_AS_IGNORE= 0x00100000,
-    RUN_FLAG__PCAP_RELOAD         = 0x00200000,
+    RUN_FLAG__DUMP_RULE_DEPS      = 0x00200000,
     RUN_FLAG__TEST                = 0x00400000,
 #ifdef SHELL
     RUN_FLAG__SHELL               = 0x00800000,
@@ -79,6 +79,8 @@ enum RunFlag
     RUN_FLAG__MEM_CHECK           = 0x02000000,
     RUN_FLAG__TRACK_ON_SYN        = 0x04000000,
     RUN_FLAG__IP_FRAGS_ONLY       = 0x08000000,
+
+    RUN_FLAG__DUMP_RULE_STATE     = 0x10000000,
 };
 
 enum OutputFlag
@@ -132,7 +134,6 @@ struct sopg_table_t;
 struct ClassType;
 struct DetectionFilterConfig;
 struct EventQueueConfig;
-struct FlowBitState;
 struct FrameworkConfig;
 struct HighAvailabilityConfig;
 struct IpsActionsConfig;
@@ -319,7 +320,6 @@ public:
     ThresholdConfig* threshold_config = nullptr;
     RateFilterConfig* rate_filter_config = nullptr;
     DetectionFilterConfig* detection_filter_config = nullptr;
-    FlowBitState* flowbit_state = nullptr;
 
     //------------------------------------------------------
     // FIXIT-L command line only stuff, add to conf / module
@@ -496,6 +496,22 @@ public:
     static bool dump_msg_map()
     { return get_conf()->run_flags & RUN_FLAG__DUMP_MSG_MAP; }
 
+    static bool dump_rule_meta()
+    { return get_conf()->run_flags & RUN_FLAG__DUMP_RULE_META; }
+
+    static bool dump_rule_state()
+    { return get_conf()->run_flags & RUN_FLAG__DUMP_RULE_STATE; }
+
+    static bool dump_rule_deps()
+    { return get_conf()->run_flags & RUN_FLAG__DUMP_RULE_DEPS; }
+
+    static bool dump_rule_info()
+    {
+        const SnortConfig* sc = get_conf();
+        return sc->dump_msg_map() or sc->dump_rule_meta() or
+            sc->dump_rule_deps() or sc->dump_rule_state();
+    }
+
     static bool test_mode()
     { return get_conf()->run_flags & RUN_FLAG__TEST; }
 
index e3ff27705bdeeeac2b4a2a2ef464a50a1ff893fe..57b03e8fa2bd2eae36133bb7b527837f42a88b8d 100644 (file)
@@ -163,7 +163,7 @@ TEST_CASE("trace all=0", "[trace]")
     test.set(trace_val);
 
     testing_dump[0] = '\0';
-    debug_log(test, "my message"); 
+    debug_log(test, "my message");
     CHECK( testing_dump[0] == '\0' );
 }
 
@@ -178,7 +178,7 @@ TEST_CASE("debug_log", "[trace]")
     test.set(trace_val);
 
     testing_dump[0] = '\0';
-    debug_log(test, "my message"); 
+    debug_log(test, "my message");
     CHECK( !strcmp(testing_dump, "test:all:1: my message") );
 
     Parameter p_all("all", Parameter::PT_INT, "0:255", "0", "p_all");
@@ -223,7 +223,7 @@ TEST_CASE("debug_log", "[trace]")
     testing_dump[0] = '\0';
     debug_log(3, testing_opt, TEST_TRACE_OPTION3, "log option3 message");
     CHECK( !strcmp(testing_dump, "testing_opt:option3:3: log option3 message") );
-    
+
     testing_dump[0] = '\0';
     debug_log(2, testing_opt, TEST_TRACE_OPTION4, "log option4 message");
     CHECK( !strcmp(testing_dump, "testing_opt:option4:2: log option4 message") );
@@ -288,7 +288,7 @@ TEST_CASE("debug_logf", "[trace]")
     testing_dump[0] = '\0';
     debug_logf(6, testing_opt, TEST_TRACE_OPTION3, "%s %s %s", "log", "option3", "message");
     CHECK( testing_dump[0] == '\0' );
-    
+
     testing_dump[0] = '\0';
     debug_logf(2, testing_opt, TEST_TRACE_OPTION4, "%s %s %s", "log", "option4", "message");
     CHECK( !strcmp(testing_dump, "testing_opt:option4:2: log option4 message") );
index b7f55bdc401ae24c17cd1923b2bd1f3b61bb40a1..9163fc6f4b6a094d1b742484566bf322e3c018ee 100644 (file)
@@ -250,7 +250,7 @@ static const Parameter s_params[] =
       "enable inline mode operation" },
 
     { "-q", Parameter::PT_IMPLIED, nullptr, nullptr,
-      "quiet mode - Don't show banner and status report" },
+      "quiet mode - suppress normal logging on stdout" },
 
     { "-R", Parameter::PT_STRING, nullptr, nullptr,
       "<rules> include this rules file in the default policy" },
@@ -345,6 +345,15 @@ static const Parameter s_params[] =
     { "--dump-defaults", Parameter::PT_STRING, "(optional)", nullptr,
       "[<module prefix>] output module defaults in Lua format" },
 
+    { "--dump-rule-deps", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "dump rule dependencies in json format for use by other tools" },
+
+    { "--dump-rule-meta", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "dump configured rule info in json format for use by other tools" },
+
+    { "--dump-rule-state", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "dump configured rule state in json format for use by other tools" },
+
     { "--dump-version", Parameter::PT_IMPLIED, nullptr, nullptr,
       "output the version, the whole version, and only the version" },
 
@@ -462,9 +471,6 @@ static const Parameter s_params[] =
     { "--pcap-no-filter", Parameter::PT_IMPLIED, nullptr, nullptr,
       "reset to use no filter when getting pcaps from file or directory" },
 
-    { "--pcap-reload", Parameter::PT_IMPLIED, nullptr, nullptr,
-      "if reading multiple pcaps, reload snort config between pcaps" },
-
     { "--pcap-show", Parameter::PT_IMPLIED, nullptr, nullptr,
       "print a line saying what pcap is currently being read" },
 
@@ -840,6 +846,22 @@ bool SnortModule::set(const char*, Value& v, SnortConfig* sc)
     else if ( v.is("--dump-defaults") )
         dump_defaults(sc, v.get_string());
 
+    else if ( v.is("--dump-rule-deps") )
+    {
+        sc->run_flags |= (RUN_FLAG__DUMP_RULE_DEPS | RUN_FLAG__TEST);
+        sc->set_quiet(true);
+    }
+    else if ( v.is("--dump-rule-meta") )
+    {
+        sc->run_flags |= (RUN_FLAG__DUMP_RULE_META | RUN_FLAG__TEST);
+        sc->output_flags |= OUTPUT_FLAG__ALERT_REFS;
+        sc->set_quiet(true);
+    }
+    else if ( v.is("--dump-rule-state") )
+    {
+        sc->run_flags |= (RUN_FLAG__DUMP_RULE_STATE | RUN_FLAG__TEST);
+        sc->set_quiet(true);
+    }
     else if ( v.is("--dump-version") )
         dump_version(sc);
 
@@ -954,9 +976,6 @@ bool SnortModule::set(const char*, Value& v, SnortConfig* sc)
     else if ( v.is("--pcap-no-filter") )
         Trough::set_filter(nullptr);
 
-    else if ( v.is("--pcap-reload") )
-        sc->run_flags |= RUN_FLAG__PCAP_RELOAD;
-
     else if ( v.is("--pcap-show") )
         sc->run_flags |= RUN_FLAG__PCAP_SHOW;
 
index 68e804d5278591c4db65ec9d0b6aee227aca9f6f..39dea1609de46625e2822de22104444db86350bd 100644 (file)
@@ -289,6 +289,16 @@ void FrameworkPolicy::vectorize(SnortConfig* sc)
 // global stuff
 //-------------------------------------------------------------------------
 
+std::vector<const InspectApi*> InspectorManager::get_apis()
+{
+    std::vector<const InspectApi*> v;
+
+    for ( const auto* p : s_handlers )
+        v.emplace_back(&p->api);
+
+    return v;
+}
+
 void InspectorManager::add_plugin(const InspectApi* api)
 {
     PHGlobal* g = new PHGlobal(*api);
index d2248aa940e34005bc19adf9e2ee9d84da38e8e4..e71850039b97e8fbd0cfc7b0397e4113f7bcf86b 100644 (file)
@@ -44,6 +44,8 @@ public:
     static void dump_buffers();
     static void release_plugins();
 
+    static std::vector<const InspectApi*> get_apis();
+
     static void new_policy(InspectionPolicy*, InspectionPolicy*);
     static void delete_policy(InspectionPolicy*, bool cloned);
     static void update_policy(SnortConfig* sc);
index c69c62ae4839ac1dc2f6e0915db99d3ff7687751..5297a3f5e0702dfd72747bbf84187774cc59c9ab 100644 (file)
@@ -320,8 +320,6 @@ bool IpsManager::option_end(
     if ( ips->is_relative() )
         fpl->isRelative = 1;
 
-    otn_set_plugin(otn, ips->get_type());
-
     if ( ips->is_agent() and !otn_set_agent(otn, ips) )
     {
         // FIXIT-L support multiple actions (eg replaces) per rule
index ab731ab0735060cc8b51b7dd59c661c3829524b0..233bee4cbacaffcf0d26ae45ea9e19af84e854d1 100644 (file)
@@ -326,8 +326,8 @@ bool BinderModule::end(const char* fqn, int idx, SnortConfig* sc)
             return true;
         }
 
-        // FIXIT-D: remove this when network_policy binding is deleted from    
-        // the binder's options  
+        // FIXIT-D: remove this when network_policy binding is deleted from
+        // the binder's options
         if ( work->use.type == NETWORK_KEY )
         {
             delete work;
index 938812dcba1e02b8831a088afac0ecc96c37ac9d..bac02b189f3af629d655f3111eac015a70f3d1c6 100644 (file)
@@ -42,20 +42,13 @@ static void check_flags(SnortConfig* sc)
     if ((sc->run_flags & RUN_FLAG__INLINE) &&
         (sc->run_flags & RUN_FLAG__INLINE_TEST))
     {
-        FatalError("Cannot use inline adapter mode and inline test "
+        ParseError("Cannot use inline adapter mode and inline test "
             "mode together. \n");
     }
 
     if (Trough::get_loop_count() && !(sc->run_flags & RUN_FLAG__READ))
     {
-        FatalError("--pcap-loop can only be used in combination with pcaps "
-            "on the command line.\n");
-    }
-
-    if ((sc->run_flags & RUN_FLAG__PCAP_RELOAD) &&
-        !(sc->run_flags & RUN_FLAG__READ))
-    {
-        FatalError("--pcap-reload can only be used in combination with pcaps "
+        ParseError("--pcap-loop can only be used in combination with pcaps "
             "on the command line.\n");
     }
 }
index 011afb993652ac4d0c7d9a64fdedfee6efa4eb62..84beb206262c8257eb6559a6fe54b8de8ff1bc90 100644 (file)
@@ -84,6 +84,22 @@ static rule_count_t ipCnt;
 static rule_count_t svcCnt;  // dummy for now
 
 static bool s_ignore = false;  // for skipping drop rules when not inline, etc.
+static bool s_capture = false;
+
+static std::string s_body;
+
+struct SoRule
+{
+    SoRule(RuleTreeNode* rtn, const OptTreeNode* otn) :
+        rtn(rtn), gid(otn->sigInfo.gid), sid(otn->sigInfo.sid), rev(otn->sigInfo.rev) { }
+
+    RuleTreeNode* rtn;
+    uint32_t gid;
+    uint32_t sid;
+    uint32_t rev;
+};
+
+static SoRule* s_so_rule = nullptr;
 
 /*
  * Finish adding the rule to the port tables
@@ -99,8 +115,7 @@ static bool s_ignore = false;  // for skipping drop rules when not inline, etc.
  *    c)if the rule is bidir add the rule and port-object to both src and dst tables
  */
 static int FinishPortListRule(
-    RulePortTables* port_tables, RuleTreeNode* rtn, OptTreeNode* otn,
-    SnortProtocolId snort_protocol_id, FastPatternConfig* fp)
+    RulePortTables* port_tables, RuleTreeNode* rtn, OptTreeNode* otn, FastPatternConfig* fp)
 {
     int large_port_group = 0;
     PortTable* dstTable;
@@ -109,11 +124,9 @@ static int FinishPortListRule(
     rule_count_t* prc;
     uint32_t orig_flags = rtn->flags;
 
-    assert(otn->snort_protocol_id == snort_protocol_id);
-
     /* Select the Target PortTable for this rule, based on protocol, src/dst
      * dir, and if there is rule content */
-    switch ( snort_protocol_id )
+    switch ( otn->snort_protocol_id )
     {
     case SNORT_PROTO_IP:
         dstTable = port_tables->ip.dst;
@@ -198,7 +211,7 @@ static int FinishPortListRule(
      * were using a single rule group we make it an any-any rule. */
     if ( rtn->any_any_port() or large_port_group or fp->get_single_rule_group() )
     {
-        if (snort_protocol_id == SNORT_PROTO_IP)
+        if (otn->snort_protocol_id == SNORT_PROTO_IP)
         {
             PortObjectAddRule(port_tables->icmp.any, otn->ruleIndex);
             icmpCnt.any++;
@@ -285,7 +298,7 @@ static int ValidateIPList(sfip_var_t* addrset, const char* token)
     return 0;
 }
 
-static int ProcessIP(SnortConfig*, const char* addr, RuleTreeNode* rtn, int mode, int)
+static int ProcessIP(SnortConfig* sc, const char* addr, RuleTreeNode* rtn, int mode, int)
 {
     vartable_t* ip_vartable = get_ips_policy()->ip_vartable;
 
@@ -318,6 +331,9 @@ static int ProcessIP(SnortConfig*, const char* addr, RuleTreeNode* rtn, int mode
         }
 
         /* The function sfvt_add_to_var adds 'addr' to the variable 'rtn->sip' */
+        if ( ret == SFIP_LOOKUP_FAILURE and sc->dump_rule_info() )
+            ret = sfvt_add_to_var(ip_vartable, rtn->sip, "any");
+
         if (ret != SFIP_SUCCESS)
         {
             if (ret == SFIP_LOOKUP_FAILURE)
@@ -373,7 +389,10 @@ static int ProcessIP(SnortConfig*, const char* addr, RuleTreeNode* rtn, int mode
             ret = sfvt_add_to_var(ip_vartable, rtn->dip, addr);
         }
 
-        if (ret != SFIP_SUCCESS)
+        if ( ret == SFIP_LOOKUP_FAILURE and sc->dump_rule_info() )
+            ret = sfvt_add_to_var(ip_vartable, rtn->dip, "any");
+
+        if ( ret != SFIP_SUCCESS )
         {
             if (ret == SFIP_LOOKUP_FAILURE)
             {
@@ -615,10 +634,13 @@ static void XferHeader(RuleTreeNode* from, RuleTreeNode* to)
     to->sip = from->sip;
     to->dip = from->dip;
 
+    to->listhead = from->listhead;
     to->snort_protocol_id = from->snort_protocol_id;
 
     to->src_portobject = from->src_portobject;
     to->dst_portobject = from->dst_portobject;
+
+    to->header = from->header;
 }
 
 /****************************************************************************
@@ -753,26 +775,22 @@ static void SetupRTNFuncList(RuleTreeNode* rtn)
     AddRuleFuncToList(RuleListEnd, rtn);
 }
 
-// Process the header block info and add to the block list if necessary
-static RuleTreeNode* ProcessHeadNode(
-    SnortConfig* sc, RuleTreeNode* test_node, ListHead* list)
+// if it doesn't match any of the existing nodes, make a new node and
+// stick it at the end of the list
+static RuleTreeNode* ProcessHeadNode(SnortConfig* sc, RuleTreeNode* test_node)
 {
     RuleTreeNode* rtn = findHeadNode(
         sc, test_node, get_ips_policy()->policy_id);
 
-    /* if it doesn't match any of the existing nodes, make a new node and
-     * stick it at the end of the list */
-    if ( !rtn )
+    if ( rtn )
+        FreeRuleTreeNode(test_node);
+
+    else
     {
         head_count++;
         rtn = new RuleTreeNode;
         XferHeader(test_node, rtn);
         SetupRTNFuncList(rtn);
-        rtn->listhead = list;
-    }
-    else
-    {
-        FreeRuleTreeNode(test_node);
     }
 
     return rtn;
@@ -918,6 +936,10 @@ void parse_rule_print()
 void parse_rule_type(SnortConfig* sc, const char* s, RuleTreeNode& rtn)
 {
     rtn = RuleTreeNode();
+
+    if ( s_so_rule )
+        return;
+
     rtn.action = get_rule_type(s);
 
     if ( rtn.action == Actions::NONE )
@@ -925,18 +947,18 @@ void parse_rule_type(SnortConfig* sc, const char* s, RuleTreeNode& rtn)
         s_ignore = true;
         return;
     }
-    else
+    if ( sc->dump_rule_meta() )
+        rtn.header = new RuleHeader(s);
+
+    rtn.listhead = get_rule_list(sc, s);
+
+    if ( !rtn.listhead )
     {
+        CreateRuleType(sc, s, rtn.action);
         rtn.listhead = get_rule_list(sc, s);
-
-        if ( !rtn.listhead )
-        {
-            CreateRuleType(sc, s, rtn.action);
-            rtn.listhead = get_rule_list(sc, s);
-        }
-        if ( SnortConfig::get_default_rule_state() )
-            rtn.set_enabled();
     }
+    if ( SnortConfig::get_default_rule_state() )
+        rtn.set_enabled();
 
     if ( !rtn.listhead )
         ParseError("unconfigured rule action '%s'", s);
@@ -947,6 +969,9 @@ void parse_rule_proto(SnortConfig* sc, const char* s, RuleTreeNode& rtn)
     if ( s_ignore )
         return;
 
+    if ( !s_so_rule and rtn.header )
+        rtn.header->proto = s;
+
     if ( !strcmp(s, "tcp") )
         rule_proto = PROTO_BIT__TCP;
 
@@ -970,36 +995,63 @@ void parse_rule_proto(SnortConfig* sc, const char* s, RuleTreeNode& rtn)
         ParseError("bad protocol: %s", s);
         rule_proto = 0;
     }
+    else if ( s_so_rule and s_so_rule->rtn->snort_protocol_id != rtn.snort_protocol_id )
+        ParseWarning(WARN_RULES, "so rule proto can not be changed");
 }
 
 void parse_rule_nets(
     SnortConfig* sc, const char* s, bool src, RuleTreeNode& rtn)
 {
+    if ( s_so_rule )
+        return;
+
     if ( s_ignore )
         return;
 
+    if ( rtn.header )
+    {
+        if ( src )
+            rtn.header->src_nets = s;
+        else
+            rtn.header->dst_nets = s;
+    }
     ProcessIP(sc, s, &rtn, src ? SRC : DST, 0);
 }
 
 void parse_rule_ports(
     SnortConfig*, const char* s, bool src, RuleTreeNode& rtn)
 {
+    if ( s_so_rule )
+        return;
+
     if ( s_ignore )
         return;
 
+    if ( rtn.header )
+    {
+        if ( src )
+            rtn.header->src_ports = s;
+        else
+            rtn.header->dst_ports = s;
+    }
+
     IpsPolicy* p = get_ips_policy();
 
     if ( ParsePortList(&rtn, p->portVarTable, p->nonamePortVarTable, s, src ? SRC : DST) )
-    {
         ParseError("bad ports: '%s'", s);
-    }
 }
 
 void parse_rule_dir(SnortConfig*, const char* s, RuleTreeNode& rtn)
 {
+    if ( s_so_rule )
+        return;
+
     if ( s_ignore )
         return;
 
+    if ( rtn.header )
+        rtn.header->dir = s;
+
     if (strcmp(s, "<>") == 0)
         rtn.flags |= RuleTreeNode::BIDIRECTIONAL;
 
@@ -1012,6 +1064,12 @@ void parse_rule_opt_begin(SnortConfig* sc, const char* key)
     if ( s_ignore )
         return;
 
+    if ( s_capture )
+    {
+        s_body += " ";
+        s_body += key;
+        s_body += ":";
+    }
     IpsManager::option_begin(sc, key, rule_proto);
 }
 
@@ -1021,6 +1079,16 @@ void parse_rule_opt_set(
     if ( s_ignore )
         return;
 
+    if ( s_capture )
+    {
+        s_body += opt;
+        if ( val and *val )
+        {
+            s_body += " ";
+            s_body += val;
+        }
+        s_body += ",";
+    }
     IpsManager::option_set(sc, key, opt, val);
 }
 
@@ -1029,6 +1097,11 @@ void parse_rule_opt_end(SnortConfig* sc, const char* key, OptTreeNode* otn)
     if ( s_ignore )
         return;
 
+    if ( s_capture )
+    {
+        s_body.erase(s_body.length()-1, 1);
+        s_body += ";";
+    }
     RuleOptType type = OPT_TYPE_MAX;
     IpsManager::option_end(sc, otn, otn->snort_protocol_id, key, type);
 
@@ -1063,9 +1136,13 @@ OptTreeNode* parse_rule_open(SnortConfig* sc, RuleTreeNode& rtn, bool stub)
 
     IpsManager::reset_options();
 
+    s_capture = sc->dump_rule_meta();
+    s_body = "(";
+
     return otn;
 }
 
+// FIXIT-H parse_rule_state needs parsing policy for reload
 static void parse_rule_state(SnortConfig* sc, const RuleTreeNode& rtn, OptTreeNode* otn)
 {
     if ( !otn->sigInfo.gid )
@@ -1076,11 +1153,14 @@ static void parse_rule_state(SnortConfig* sc, const RuleTreeNode& rtn, OptTreeNo
         ParseError("%u:%u rule state stubs do not support detection options",
             otn->sigInfo.gid, otn->sigInfo.sid);
     }
-    RuleKey key = { otn->sigInfo.gid, otn->sigInfo.sid };
-    RuleState state =
+    RuleKey key =
     {
-        // FIXIT-H parse_rule_state needs parsing policy for reload
         snort::get_ips_policy()->policy_id,
+        otn->sigInfo.gid,
+        otn->sigInfo.sid
+    };
+    RuleState state =
+    {
         rtn.action,
         otn->enable
     };
@@ -1120,24 +1200,31 @@ void parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* otn)
     if ( otn->is_rule_state_stub() )
     {
         parse_rule_state(sc, rtn, otn);
+        delete rtn.header;
+        rtn.header = nullptr;
         return;
     }
 
-    static bool entered = false;
-
-    if ( entered )
-        entered = false;
+    if ( !s_so_rule and !sc->metadata_filter.empty() and !otn->metadata_matched() )
+    {
+        delete otn;
+        FreeRuleTreeNode(&rtn);
+        ClearIpsOptionsVars();
+        skip_count++;
+        return;
+    }
 
+    if ( s_so_rule )
+    {
+        otn->sigInfo.gid = s_so_rule->gid;
+        otn->sigInfo.sid = s_so_rule->sid;
+        otn->sigInfo.rev = s_so_rule->rev;
+    }
     else if ( otn->soid )
     {
         // for so rules, delete the otn and parse the actual rule
-        // but if already entered, don't recurse again
-
-        // FIXIT-L RTN should be a proper object with better encapsulation
-        if ( rtn.sip )
-            sfvar_free(rtn.sip);
-        if ( rtn.dip )
-            sfvar_free(rtn.dip);
+        // keep the stub's rtn to allow user tuning of nets and ports
+        // if already entered, don't recurse again
 
         const char* rule = SoManager::get_so_rule(otn->soid, sc);
         IpsManager::reset_options();
@@ -1146,26 +1233,20 @@ void parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* otn)
             ParseError("SO rule %s not loaded.", otn->soid);
         else
         {
-            entered = true;
+            SoRule so_rule(&rtn, otn);
+            s_so_rule = &so_rule;
             parse_rules_string(sc, rule);
+            s_so_rule = nullptr;
         }
         delete otn;
         return;
     }
 
-    if ( !sc->metadata_filter.empty() and !otn->metadata_matched() )
-    {
-        delete otn;
-        FreeRuleTreeNode(&rtn);
-        ClearIpsOptionsVars();
-        skip_count++;
-        return;
-    }
-
     /* The IPs in the test node get freed in ProcessHeadNode if there is
      * already a matching RTN.  The portobjects will get freed when the
      * port var table is freed */
-    RuleTreeNode* new_rtn = ProcessHeadNode(sc, &rtn, rtn.listhead);
+    RuleTreeNode* tmp = s_so_rule ? s_so_rule->rtn : &rtn;
+    RuleTreeNode* new_rtn = ProcessHeadNode(sc, tmp);
     addRtnToOtn(sc, otn, new_rtn);
 
     OptTreeNode* otn_dup =
@@ -1236,16 +1317,15 @@ void parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* otn)
         add_service_to_otn(sc, otn, service.c_str());
     }
 
-    /*
-     * The src/dst port parsing must be done before the Head Nodes are processed, since they must
-     * compare the ports/port_objects to find the right rtn list to add the otn rule to.
-     *
-     * After otn processing we can finalize port object processing for this rule
-     */
-    if ( FinishPortListRule(
-        sc->port_tables, new_rtn, otn, rtn.snort_protocol_id, sc->fast_pattern_config) )
+    if ( FinishPortListRule(sc->port_tables, new_rtn, otn, sc->fast_pattern_config) )
         ParseError("Failed to finish a port list rule.");
 
+    if ( s_capture )
+    {
+        s_body += " )";
+        otn->sigInfo.body = new std::string(s_body);
+    }
+
     ClearIpsOptionsVars();
 }
 
index 61c86348c0bc47af37903d09c8e234ca8e3652bf..f4bb96041f23270521089f0c3caabd5407740a4b 100644 (file)
@@ -473,16 +473,13 @@ static const State* get_state(int num, TokenType type, const string& tok)
 struct RuleParseState
 {
     RuleTreeNode rtn;
-    OptTreeNode* otn;
+    OptTreeNode* otn = nullptr;
 
     string key;
     string opt;
     string val;
 
     bool tbd;
-
-    RuleParseState()
-    { otn = nullptr; }
 };
 
 static bool exec(
index a05eb3bdaee4a4ef46c27ef0a01066cc4a643f1b..355ccf4b4e671b1308fb1fcfdfa08b5d1e18d6a0 100644 (file)
@@ -383,6 +383,7 @@ void FreeRuleTreeNode(RuleTreeNode* rtn)
         idx = idx->next;
         delete tmp;
     }
+    delete rtn->header;
 }
 
 void DestroyRuleTreeNode(RuleTreeNode* rtn)
index 26bd6a773c02ddac0885fa60a5ca7b56dc13dcc1..51dde27c4058d67ce1ddf69050615c06259d2ad7 100644 (file)
@@ -257,8 +257,7 @@ static PortObject2* _merge_N_pol(
 
     // Add the plx node to the PLX hash table
     stat = mhashx->insert(&plx_tmp, ponew);
-    if ( stat == HASH_INTABLE )
-        FatalError("Could not add merged plx to PLX HASH table-INTABLE\n");
+    assert(stat == HASH_OK);
 
     return ponew;
 }
@@ -510,9 +509,6 @@ static void PortTableCompileMergePortObjects(PortTable* p)
     {
         PortObject2* poa = (PortObject2*)node->data;
 
-        if ( !poa )
-            continue;
-
         if ( !poa->port_list )
             poa->port_list = new PortBitSet;
     }
@@ -524,11 +520,7 @@ static void PortTableCompileMergePortObjects(PortTable* p)
         if ( poa )
         {
             poa->port_cnt++;
-
-            if ( poa->port_list )
-                poa->port_list->set(i);
-            else
-                FatalError("NULL po->port_list in po on port %d\n", i);
+            poa->port_list->set(i);
         }
     }
 
@@ -564,12 +556,8 @@ static void PortTableCompileMergePortObjects(PortTable* p)
 }
 
 #ifdef DEBUG
-/*  Verify all rules in 'po' list are in 'po2' hash
- *
- *  return  0 - OK
- *         !0 - a rule in po is not in po2
- */
-static int _po2_include_po_rules(PortObject2* po2, PortObject* po)
+//  Verify all rules in 'po' list are in 'po2' hash
+static void _po2_include_po_rules(PortObject2* po2, PortObject* po)
 {
     SF_LNODE* rpos;
 
@@ -580,18 +568,13 @@ static int _po2_include_po_rules(PortObject2* po2, PortObject* po)
     {
         /* find it in po2 */
         int* id = (int*)po2->rule_hash->find(pid);
-
-        /* make sure it's in po2 */
-        if ( !id )
-            return 1; /* error */
+        assert(id);
     }
-
-    return 0;
 }
 
 // consistency check - part 1
 // make sure each port is only in one composite port object
-static bool PortTableConsistencyCheck(PortTable* p)
+static void PortTableConsistencyCheck(PortTable* p)
 {
     std::unique_ptr<char[]> upA(new char[SFPO_MAX_PORTS]);
     char* parray = upA.get();
@@ -603,11 +586,6 @@ static bool PortTableConsistencyCheck(PortTable* p)
     {
         PortObject2* po = (PortObject2*)node->data;
 
-        if ( !po )
-        {
-            return false;
-        }
-
         if ( !po->port_cnt ) /* port object is not used ignore it */
             continue;
 
@@ -615,15 +593,11 @@ static bool PortTableConsistencyCheck(PortTable* p)
         {
             if ( PortObjectHasPort( (PortObject*)po, i) )
             {
-                if ( parray[i] )
-                    return false;
-
+                assert(!parray[i]);
                 parray[i] = 1;
             }
         }
     }
-
-    return true;
 }
 
 // consistency check - part 2
@@ -635,7 +609,7 @@ static bool PortTableConsistencyCheck(PortTable* p)
 *    check that each port it reference has all of the rules
 *    referenced to that port in the composite object
 */
-static bool PortTableConsistencyCheck2(PortTable* p)
+static void PortTableConsistencyCheck2(PortTable* p)
 {
     SF_LNODE* pos;
     PortObject2* lastpo = nullptr;
@@ -664,17 +638,12 @@ static bool PortTableConsistencyCheck2(PortTable* p)
                 /* small optimization*/
                 if ( lastpo != p->pt_port_object[i] )
                 {
-                    if ( _po2_include_po_rules(p->pt_port_object[i], ipo) )
-                    {
-                        return false;
-                    }
+                    _po2_include_po_rules(p->pt_port_object[i], ipo);
                     lastpo = p->pt_port_object[i];
                 }
             }
         }
     }
-
-    return true;
 }
 #endif
 
@@ -784,8 +753,8 @@ int PortTableCompile(PortTable* p)
     PortTableCompileMergePortObjects(p);
 
 #ifdef DEBUG
-    assert(PortTableConsistencyCheck(p));
-    assert(PortTableConsistencyCheck2(p));
+    PortTableConsistencyCheck(p);
+    PortTableConsistencyCheck2(p);
 #endif
 
     return 0;
index 89ed38436c3536c446b049e777cc3cc5b4017b81..c7871d71c67f7fb9ac9fb9c730934ae1d473aceb 100644 (file)
@@ -25,6 +25,8 @@
 
 #include "hash/ghash.h"
 #include "hash/hash_defs.h"
+#include "main/snort_config.h"
+#include "utils/util.h"
 
 using namespace snort;
 
@@ -89,6 +91,14 @@ PortObject* PortVarTableFind(PortVarTable* h, const char* name)
     if (!h || !name)
         return nullptr;
 
-    return (PortObject*)h->find(name);
+    PortObject* po = (PortObject*)h->find(name);
+
+    if ( !po and SnortConfig::dump_rule_info() and strstr(name, "PORT") )
+    {
+        po = PortObjectNew();
+        po->name = snort_strdup(name);
+        PortVarTableAdd(h, po);
+    }
+    return po;
 }
 
index 452c422b6f33b1e708aaf0c9943c7731444b015f..712a512057ab86130faf4111c1279f3efad614f1 100644 (file)
@@ -105,7 +105,6 @@ typedef std::vector<Pattern> PatternVector;
 
 static std::vector<hs_scratch_t*> s_scratch;
 static unsigned int scratch_index;
-static bool scratch_registered = false;
 static ScratchAllocator* scratcher = nullptr;
 
 struct ScanContext
@@ -381,12 +380,9 @@ static void mod_dtor(Module* p)
 static Mpse* hs_ctor(
     SnortConfig* sc, class Module*, const MpseAgent* a)
 {
-    if ( !scratch_registered )
-    {
-        s_scratch.resize(sc->num_slots);
-        scratch_index = scratcher->get_id();
-        scratch_registered = true;
-    }
+    if ( s_scratch.empty() )
+        s_scratch.resize(sc->num_slots, nullptr);
+
     return new HyperscanMpse(sc, a);
 }
 
index 3d635f3d3482f53b70d9ff2c1ae83e7b5c8186fe..a409772a0a288aaab6f050f5ebb3bd7426700f9c 100644 (file)
@@ -48,7 +48,7 @@ public:
     uint32_t get_xtradata_mask() { return (current_frame != nullptr) ?
         current_frame->get_xtradata_mask() : 0; }
     Http2Frame *get_current_frame() { return current_frame; }
-    
+
     Http2DataCutter* get_data_cutter(HttpCommon::SourceId source_id);
     void set_data_cutter(Http2DataCutter* cutter, HttpCommon::SourceId source_id)
         { data_cutter[source_id] = cutter; }
index 0c4f0069d55159d3e7b0586341179efdb786c551..5898cb01f06b1b8661138602e71c39faa22188be 100644 (file)
@@ -779,7 +779,7 @@ bool HttpBodyCutter::dangerous(const uint8_t* data, uint32_t length)
     uint8_t* decomp_output = nullptr;
 
     // Zipped flows must be decompressed before we can check them. Unzipping for detained
-    // inspection is completely separate from the unzipping done later in reassemble(). 
+    // inspection is completely separate from the unzipping done later in reassemble().
     if ((compression == CMP_GZIP) || (compression == CMP_DEFLATE))
     {
         const uint32_t decomp_buffer_size = MAX_OCTETS;
index ae76bb21c76c5905b089cf91232edcd9d584715e..ef929c9d4eb45b44fd7e1fa7892115e0faac7f1e 100644 (file)
@@ -398,25 +398,3 @@ void TcpStreamSession::start_proxy()
     config->policy = StreamPolicy::OS_PROXY;
 }
 
-//-------------------------------------------------------------------------
-// tcp module stuff
-//-------------------------------------------------------------------------
-
-void TcpStreamSession::print()
-{
-    char buf[64];
-
-    LogMessage("TcpStreamSession:\n");
-    sfip_ntop(&flow->server_ip, buf, sizeof(buf));
-    LogMessage("    server IP:          %s\n", buf);
-    sfip_ntop(&flow->client_ip, buf, sizeof(buf));
-    LogMessage("    client IP:          %s\n", buf);
-    LogMessage("    server port:        %d\n", flow->server_port);
-    LogMessage("    client port:        %d\n", flow->client_port);
-    LogMessage("    flags:              0x%X\n", flow->get_session_flags());
-    LogMessage("Client Tracker:\n");
-    client.print();
-    LogMessage("Server Tracker:\n");
-    server.print();
-}
-
index 027fcfaafcf314327576905d209c5272361a7494..eb4dc54b9607a473da0fa24eada7af47c8c4950e 100644 (file)
@@ -57,7 +57,6 @@ public:
 
     void reset();
     void start_proxy();
-    void print();
 
     void SetPacketHeaderFoo(const snort::Packet* p);
     void GetPacketHeaderFoo(DAQ_PktHdr_t* pkth, uint32_t dir);
index b3711884c2a971af63fbe5fac7e5f972c880c575..b2e078c495f1d1e88cda7080d3fe2f33a3aa13fc 100644 (file)
@@ -729,17 +729,3 @@ void TcpStreamTracker::finalize_held_packet(Flow* flow)
     }
 }
 
-void TcpStreamTracker::print()
-{
-    LogMessage(" + TcpTracker +\n");
-    LogMessage("    state:              %s\n", tcp_state_names[ tcp_state ]);
-    LogMessage("    iss:                0x%X\n", iss);
-    LogMessage("    ts_last:            %u\n", ts_last);
-    LogMessage("    wscale:             %u\n", wscale);
-    LogMessage("    mss:                0x%08X\n", mss);
-    LogMessage("    snd_una:            %X\n", snd_una);
-    LogMessage("    snd_nxt:            %X\n", snd_nxt);
-    LogMessage("    snd_win:            %u\n", snd_wnd);
-    LogMessage("    rcv_nxt:            %X\n", rcv_nxt);
-    LogMessage("    r_win_base:         %X\n", r_win_base);
-}
index bcc622a60c6cfa8c919bce6e003c0a80a2e05fec..9416277176d4ae7a72ac8f68e108c2db48d9293e 100644 (file)
@@ -257,8 +257,8 @@ public:
     { return flush_policy; }
 
     virtual void init_tcp_state();
-    virtual void print();
     virtual void init_flush_policy();
+
     virtual void set_splitter(snort::StreamSplitter* ss);
     virtual void set_splitter(const snort::Flow* flow);
 
index c06eff91e5a60659d46bf94be6ed86af29ffe492..d22b039ca054e7c3829388fb51298fb319dfe3b2 100644 (file)
@@ -1,6 +1,5 @@
 
 set( UTIL_INCLUDES
-    bitop.h
     boyer_moore.h
     cpp_macros.h
     endian.h
index 181baf831159bd0d319f7a44ded61369536e7520..9a9eb166e6010e493cfdc2abd6128a5a66f300e2 100644 (file)
@@ -5,4 +5,3 @@ add_cpputest( boyer_moore_test
 
 add_cpputest( memcap_allocator_test )
 
-add_catch_test( bitop_test )