]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1847 in SNORT/snort3 from ~RUCOMBS/snort3:rule_hacks to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Mon, 2 Dec 2019 22:28:25 +0000 (22:28 +0000)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Mon, 2 Dec 2019 22:28:25 +0000 (22:28 +0000)
Squashed commit of the following:

commit a273b19fd7256ab43c4639b064695a1d11f8030f
Author: russ <rucombs@cisco.com>
Date:   Fri Nov 29 08:28:33 2019 -0500

    http_inspect: implement show method for verbose config output

commit 6e1f40e01c95f0afd8ef4d0b609df25db9b757c6
Author: russ <rucombs@cisco.com>
Date:   Thu Nov 28 18:44:33 2019 -0500

    appid: format detected apps stats in columns akin to file stats

commit 4eb7cbdbfa223d6e6c998822c4db06d8c6f6a681
Author: russ <rucombs@cisco.com>
Date:   Sun Nov 24 17:58:51 2019 -0500

    profiler: fix module profile for multithreaded runs

    The checks and time(us) are aggregated from all packet threads so the total time
    can be N times greater than elapsed real time for N packet threads.  The "other"
    bucket has checks equal to the total number of packets and time equal to the sum
    of all packet thread run times less the sum of all other times accounted for.

commit 9f7e9ec1fec03fc8681438a89f680d7b248f2326
Author: russ <rucombs@cisco.com>
Date:   Wed Nov 27 13:42:13 2019 -0500

    search_engine: raise an error if any MPSE compilation fails

commit 75bd85542994fb88da80754668679b46cfb3caca
Author: russ <rucombs@cisco.com>
Date:   Wed Nov 27 09:08:10 2019 -0500

    search_engine: process intermediate fast-pattern matches in batches of 32 same as Snort 2

commit b76f0fc78432d4056e9b940441fd8803d7a5035b
Author: russ <rucombs@cisco.com>
Date:   Sun Nov 24 18:01:12 2019 -0500

    ips: support 2 rule vars same as Snort 2

commit 67ee953c4c7c9d13e4f95a4e527d87cb8a365b44
Author: russ <rucombs@cisco.com>
Date:   Fri Nov 22 16:30:41 2019 -0500

    appid: minor cleanup

commit 6b66d0839ca6cb14e8dd37010d69a47f97c6c5b6
Author: russ <rucombs@cisco.com>
Date:   Fri Nov 22 16:24:56 2019 -0500

    search_engine: ensure configured search_method is applied to search tools

commit 039f452cea4f183a469aa555275c7f47d37cd14d
Author: russ <rucombs@cisco.com>
Date:   Mon Nov 18 18:14:14 2019 -0500

    ips: only use multiple threads for rule group compilation at startup

    A typical deployment will have N packet threads, each pinned to a separate core.
    N threads can be used to speed up startup but shouldn't be used during reload
    since that could impact detection.  Reload is also not as time critical as
    startup.

commit a23500a9baf5773592653648d1a2cf32cfb22487
Author: russ <rucombs@cisco.com>
Date:   Fri Nov 15 13:59:18 2019 -0500

    hyperscan: select max scratch from among all compiler threads

commit 5b918976e0fad0f706675635852c74870175b4ad
Author: russ <rucombs@cisco.com>
Date:   Thu Nov 14 16:45:34 2019 -0500

    mpse: only hyperscan currently supports parallel compilation

commit 5ceb74b43af4b3bd7fafe61da7c53f2900b6b3cd
Author: russ <rucombs@cisco.com>
Date:   Thu Nov 14 15:52:41 2019 -0500

    ips: add support for parallel fast-pattern MPSE FSM compilation

36 files changed:
src/detection/detection_options.cc
src/detection/fp_create.cc
src/detection/fp_detect.cc
src/detection/fp_utils.cc
src/detection/fp_utils.h
src/framework/mpse.h
src/framework/mpse_batch.cc
src/framework/mpse_batch.h
src/ips_options/extract.cc
src/ips_options/extract.h
src/ips_options/ips_byte_math.cc
src/main.cc
src/main/analyzer.cc
src/main/snort_config.cc
src/main/snort_config.h
src/managers/mpse_manager.cc
src/managers/mpse_manager.h
src/mime/file_mime_process.cc
src/network_inspectors/appid/appid_peg_counts.cc
src/network_inspectors/appid/appid_peg_counts.h
src/network_inspectors/appid/detector_plugins/http_url_patterns.cc
src/network_inspectors/appid/detector_plugins/http_url_patterns.h
src/network_inspectors/appid/test/appid_http_session_test.cc
src/parser/parser.cc
src/profiler/profiler.cc
src/profiler/profiler.h
src/profiler/profiler_defs.h
src/profiler/profiler_nodes.cc
src/profiler/profiler_nodes.h
src/search_engines/hyperscan.cc
src/search_engines/search_tool.cc
src/search_engines/test/hyperscan_test.cc
src/search_engines/test/search_tool_test.cc
src/service_inspectors/http_inspect/http_inspect.cc
src/service_inspectors/http_inspect/http_inspect.h
src/utils/stats.cc

index 883aa8dbea8131a4f01b994f33f7cc7bee0852b5..bf374e465b4435dec2d021cacb65d6c9a5c69cd9 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "detection_options.h"
 
+#include <mutex>
 #include <string>
 
 #include "filters/detection_filter.h"
@@ -327,6 +328,9 @@ void print_option_tree(detection_option_tree_node_t* node, int level)
 
 void* add_detection_option_tree(SnortConfig* sc, detection_option_tree_node_t* option_tree)
 {
+    static std::mutex build_mutex;
+    std::lock_guard<std::mutex> lock(build_mutex);
+
     if ( !sc->detection_option_tree_hash_table )
         sc->detection_option_tree_hash_table = DetectionTreeHashTableNew();
 
index bcce9ad5e8a772f3bc369179f00ecd9833e214fc..2914a4b23623ec4fb17d75df7f484a893e75e826 100644 (file)
@@ -38,7 +38,9 @@
 #include "framework/mpse_batch.h"
 #include "hash/ghash.h"
 #include "log/messages.h"
+#include "main/snort.h"
 #include "main/snort_config.h"
+#include "main/thread_config.h"
 #include "managers/mpse_manager.h"
 #include "parser/parse_rule.h"
 #include "parser/parser.h"
@@ -428,15 +430,11 @@ static int fpFinishPortGroup(
             {
                 if (pg->mpsegrp[i]->normal_mpse->get_pattern_count() != 0)
                 {
-                    if ( !sc->test_mode() or sc->mem_check() )
-                    {
-                        if ( pg->mpsegrp[i]->normal_mpse->prep_patterns(sc) != 0 )
-                            FatalError("Failed to compile port group patterns for normal "
-                                    "search engine.\n");
-                    }
+                    queue_mpse(pg->mpsegrp[i]->normal_mpse);
 
                     if (fp->get_debug_mode())
                         pg->mpsegrp[i]->normal_mpse->print_info();
+
                     rules = 1;
                 }
                 else
@@ -449,15 +447,11 @@ static int fpFinishPortGroup(
             {
                 if (pg->mpsegrp[i]->offload_mpse->get_pattern_count() != 0)
                 {
-                    if ( !sc->test_mode() or sc->mem_check() )
-                    {
-                        if ( pg->mpsegrp[i]->offload_mpse->prep_patterns(sc) != 0 )
-                            FatalError("Failed to compile port group patterns for offload "
-                                    "search engine.\n");
-                    }
+                    queue_mpse(pg->mpsegrp[i]->offload_mpse);
 
                     if (fp->get_debug_mode())
                         pg->mpsegrp[i]->offload_mpse->print_info();
+
                     rules = 1;
                 }
                 else
@@ -1649,6 +1643,25 @@ static int fpCreateServicePortGroups(SnortConfig* sc)
     return 0;
 }
 
+static unsigned can_build_mt(FastPatternConfig* fp)
+{
+    if ( Snort::is_reloading() )
+        return false;
+
+    const MpseApi* search_api = fp->get_search_api();
+    assert(search_api);
+
+    if ( !MpseManager::parallel_compiles(search_api) )
+        return false;
+
+    const MpseApi* offload_search_api = fp->get_offload_search_api();
+
+    if ( offload_search_api and !MpseManager::parallel_compiles(offload_search_api) )
+        return false;
+
+    return true;
+}
+
 /*
 *  Port list version
 *
@@ -1712,6 +1725,14 @@ int fpCreateFastPacketDetection(SnortConfig* sc)
     if (fp->get_debug_print_rule_group_build_details())
         LogMessage("Service Based Rule Maps Done....\n");
 
+    if ( !sc->test_mode() or sc->mem_check() )
+    {
+        unsigned c = compile_mpses(sc, can_build_mt(fp));
+
+        if ( c != mpse_count )
+            ParseError("Failed to compile %u search engines", mpse_count - c);
+    }
+
     fp_print_port_groups(port_tables);
     fp_print_service_groups(sc->spgmmTable);
 
index 1aa2ce4fa2a32b8b4bf717ef522072ad832cf3a1..7985f9254040353fb4416fd41b743f739ad85203 100644 (file)
@@ -761,6 +761,13 @@ private:
     unsigned count;
     unsigned max;
     std::vector<Node> queue;
+
+    // perf trade-off, same as Snort 2
+    // queue to keep mpse search cache warm
+    // but limit to avoid the O(n**2) effect of inserts
+    // and to get any rule hits before exhaustive searching
+    // consider a map in lieu of vector
+    const unsigned queue_limit = 32;
 };
 
 // uniquely insert into q, should splay elements for performance
@@ -780,21 +787,21 @@ bool MpseStash::push(void* user, void* tree, int index, void* list)
     if ( max and ( count == max ) )
     {
         pmqs.tot_inq_overruns++;
-        return true;
+        return false;
     }
 
-    if ( !max or ( count < max ) )
-    {
-        Node node;
-        node.user = user;
-        node.tree = tree;
-        node.index = index;
-        node.list = list;
-        queue.push_back(node);
-        pmqs.tot_inq_uinserts++;
-        pmqs.tot_inq_inserts++;
-        count++;
-    }
+    Node node;
+    node.user = user;
+    node.tree = tree;
+    node.index = index;
+    node.list = list;
+    queue.push_back(node);
+    pmqs.tot_inq_uinserts++;
+    pmqs.tot_inq_inserts++;
+    count++;
+
+    if ( queue.size() == queue_limit )
+        return true;  // process now
 
     return false;
 }
@@ -824,14 +831,12 @@ bool MpseStash::process(MpseMatch match, void* context)
         if ( res > 0 )
         {
             /* terminate matching */
-            pmqs.tot_inq_flush += count;
-            count = 0;
+            pmqs.tot_inq_flush += i;
             queue.clear();
             return true;
         }
     }
-    pmqs.tot_inq_flush += count;
-    count = 0;
+    pmqs.tot_inq_flush += i;
     queue.clear();
     return false;
 }
@@ -858,7 +863,12 @@ static int rule_tree_queue(
 {
     MpseStash* stash = ((IpsContext*)context)->stash;
 
-    return stash->push(user, tree, index, list) ? 1 : 0;
+    if ( stash->push(user, tree, index, list) )
+    {
+        if ( stash->process(rule_tree_match, context) )
+            return 1;
+    }
+    return 0;
 }
 
 static inline int batch_search(
index 5fee5d735f8248cfc4bece1719fd71bf6e60b178..6a238ff563f23160548abdc094d49b9a73943f1a 100644 (file)
 
 #include <cassert>
 #include <cstring>
+#include <list>
+#include <mutex>
+#include <thread>
 
 #include "ips_options/ips_flow.h"
 #include "log/messages.h"
+#include "main/snort_config.h"
 #include "main/thread_config.h"
+#include "pattern_match_data.h"
 #include "ports/port_group.h"
 #include "target_based/snort_protocols.h"
+#include "treenodes.h"
 #include "utils/util.h"
 
 #ifdef UNIT_TEST
 #include "catch/snort_catch.h"
 #endif
 
-#include "pattern_match_data.h"
-#include "treenodes.h"
-
 using namespace snort;
 
 //--------------------------------------------------------------------------
@@ -368,6 +371,68 @@ PatternMatchVector get_fp_content(
     return pmds;
 }
 
+//--------------------------------------------------------------------------
+// mpse compile threads
+//--------------------------------------------------------------------------
+
+static std::list<Mpse*> s_tbd;
+static std::mutex s_mutex;
+
+static Mpse* get_mpse()
+{
+    std::lock_guard<std::mutex> lock(s_mutex);
+
+    if ( s_tbd.empty() )
+        return nullptr;
+
+    Mpse* m = s_tbd.front();
+    s_tbd.pop_front();
+
+    return m;
+}
+
+static void compile_mpse(SnortConfig* sc, unsigned id, unsigned* count)
+{
+    set_instance_id(id);
+    unsigned c = 0;
+
+    while ( Mpse* m = get_mpse() )
+    {
+        if ( !m->prep_patterns(sc) )
+            c++;
+    }
+    std::lock_guard<std::mutex> lock(s_mutex);
+    *count += c;
+}
+
+void queue_mpse(Mpse* m)
+{
+    s_tbd.push_back(m);
+}
+
+unsigned compile_mpses(struct SnortConfig* sc, bool parallel)
+{
+    std::list<std::thread*> workers;
+    unsigned max = parallel ? sc->num_slots : 1;
+    unsigned count = 0;
+
+    if ( max == 1 )
+    {
+        compile_mpse(sc, get_instance_id(), &count);
+        return count;
+    }
+
+    for ( unsigned i = 0; i < max; ++i )
+        workers.push_back(new std::thread(compile_mpse, sc, i, &count));
+
+    for ( auto* w : workers )
+    {
+        w->join();
+        delete w;
+    }
+    return count;
+}
+
 //--------------------------------------------------------------------------
 // unit tests
 //--------------------------------------------------------------------------
index 5e0ac19e3e4801e1cca412afca3bfc4700a49743..5341ef4dfe70f65de6a71a8bdc034bf61ffa2991 100644 (file)
@@ -40,5 +40,8 @@ bool set_fp_content(OptTreeNode*);
 std::vector <PatternMatchData*> get_fp_content(
     OptTreeNode*, OptFpList*&, bool srvc, bool only_literals, bool& exclude);
 
+void queue_mpse(snort::Mpse*);
+unsigned compile_mpses(struct snort::SnortConfig*, bool parallel = false);
+
 #endif
 
index d6fabc0a457ebd5956a508783996c4a35153b9c0..e2a86117a7fafc94764c8aca71ecd604f78a95b5 100644 (file)
@@ -129,10 +129,11 @@ typedef void (* MpseDelFunc)(Mpse*);
 
 typedef Mpse::MpseRespType (* MpsePollFunc)(MpseBatch*&, Mpse::MpseType);
 
-#define MPSE_BASE   0x00
-#define MPSE_TRIM   0x01
-#define MPSE_REGEX  0x02
-#define MPSE_ASYNC  0x04
+#define MPSE_BASE   0x00  // no optional features
+#define MPSE_TRIM   0x01  // should trim leading zero bytes from patterns
+#define MPSE_REGEX  0x02  // supports regex patterns
+#define MPSE_ASYNC  0x04  // does asynchronous (lookaside) searches
+#define MPSE_MTBLD  0x08  // support multithreaded / parallel compilation
 
 struct MpseApi
 {
index 84a8c4737cdf63d3e53ef63fb8f4342179b8e432..9758be3d46319c4703453435dbac62bdc3e024a8 100644 (file)
@@ -102,10 +102,10 @@ bool MpseGroup::create_normal_mpse(SnortConfig* sc, const MpseAgent* agent)
     }
 }
 
-bool MpseGroup::create_normal_mpse(const char* type)
+bool MpseGroup::create_normal_mpse(SnortConfig* sc, const char* type)
 {
-    if ( !type and SnortConfig::get_conf()->fast_pattern_config )
-        type = SnortConfig::get_conf()->fast_pattern_config->get_search_method();
+    if ( !type and sc->fast_pattern_config )
+        type = sc->fast_pattern_config->get_search_method();
 
     if ( !type )
         type = "ac_bnfa";
@@ -115,7 +115,7 @@ bool MpseGroup::create_normal_mpse(const char* type)
     if (search_api)
     {
         Module* mod = ModuleManager::get_module(search_api->base.name);
-        normal_mpse = search_api->ctor(nullptr, mod, nullptr);
+        normal_mpse = search_api->ctor(sc, mod, nullptr);
         normal_mpse->set_api(search_api);
         return true;
     }
@@ -150,21 +150,21 @@ bool MpseGroup::create_offload_mpse(SnortConfig* sc, const MpseAgent* agent)
     }
 }
 
-bool MpseGroup::create_offload_mpse()
+bool MpseGroup::create_offload_mpse(SnortConfig* sc)
 {
     const MpseApi* search_api = nullptr;
     const MpseApi* offload_search_api = nullptr;
 
-    if (SnortConfig::get_conf()->fast_pattern_config )
+    if (sc->fast_pattern_config )
     {
-        search_api = SnortConfig::get_conf()->fast_pattern_config->get_search_api();
-        offload_search_api = SnortConfig::get_conf()->fast_pattern_config->get_offload_search_api();
+        search_api = sc->fast_pattern_config->get_search_api();
+        offload_search_api = sc->fast_pattern_config->get_offload_search_api();
     }
 
     if (offload_search_api and (offload_search_api != search_api))
     {
         Module* mod = ModuleManager::get_module(offload_search_api->base.name);
-        offload_mpse = offload_search_api->ctor(nullptr, mod, nullptr);
+        offload_mpse = offload_search_api->ctor(sc, mod, nullptr);
         offload_mpse->set_api(offload_search_api);
         return true;
     }
index d09e0ad3761fcb14ba1b1de18c217ba9583aed50..bd91a5c75c67c687b976caa4a6dfc453f3b08b43 100644 (file)
@@ -48,10 +48,10 @@ public:
     { return offload_mpse ? offload_mpse : normal_mpse; }
 
     bool create_normal_mpse(SnortConfig*, const MpseAgent* agent);
-    bool create_normal_mpse(const char*);
+    bool create_normal_mpse(SnortConfig*, const char*);
 
     bool create_offload_mpse(SnortConfig*, const MpseAgent* agent);
-    bool create_offload_mpse();
+    bool create_offload_mpse(SnortConfig*);
 
     inline bool can_fallback() const
     { return get_offload_mpse() != normal_mpse; }
index dd7e2001b5e5da20b554cc47fdacd62223553eb3..14da848420955837bceabb04e2c63d0f1155d30c 100644 (file)
@@ -329,7 +329,7 @@ TEST_CASE("ips options vars")
     int8_t ind2 = AddVarNameToList("VALUE");
     REQUIRE((ind2 == 1));
     int8_t ind3 = AddVarNameToList("VAR3");
-    REQUIRE((ind3 == 2));
+    REQUIRE((ind3 == IPS_OPTIONS_NO_VAR));
 
     // Insert same name twice
     REQUIRE((AddVarNameToList("VALUE") == 1));
index 31397f2f50e8b602d6d65dc0368255326ba384e3..0a177a8282cc80a7eb6ccc73f8b1fa735d83491a 100644 (file)
@@ -30,7 +30,7 @@
 #define PARSELEN      10
 #define MAX_BYTES_TO_GRAB 4
 
-#define NUM_IPS_OPTIONS_VARS 3
+#define NUM_IPS_OPTIONS_VARS 2
 #define IPS_OPTIONS_NO_VAR (-1)
 #define INVALID_VAR_ERR_STR "%s uses an undefined rule option variable (%s)"
 
index 1f4dd1b6c7f306bff42e616139830bdfeb53c056..a56426826ea2b9e83fcddcf7877bf1b7f99682b0 100644 (file)
@@ -518,8 +518,7 @@ static IpsOption* byte_math_ctor(Module* p, OptTreeNode*)
     data.result_var = AddVarNameToList(data.result_name);
     if (data.result_var == IPS_OPTIONS_NO_VAR)
     {
-        ParseError("Rule has more than %d variables.",
-            NUM_IPS_OPTIONS_VARS);
+        ParseError("Rule has more than %d variables.", NUM_IPS_OPTIONS_VARS);
         return nullptr;
     }
     return new ByteMathOption(m->data);
index c16b8a546f04bde1514a25ca28a418fc6824629b..717d426c256b9cef1eed678fca5510b8f04807eb 100644 (file)
@@ -346,6 +346,8 @@ int main_reload_config(lua_State* L)
          current_request->respond("== reload failed - restart required\n");
         else
           current_request->respond("== reload failed - bad config\n");
+
+        SnortConfig::set_parser_conf(nullptr);
         return 0;
     }
 
@@ -355,6 +357,7 @@ int main_reload_config(lua_State* L)
     if ( !tc )
     {
         current_request->respond("== reload failed - bad config\n");
+        SnortConfig::set_parser_conf(nullptr);
         return 0;
     }
     SnortConfig::set_conf(sc);
@@ -364,6 +367,7 @@ int main_reload_config(lua_State* L)
     current_request->respond(".. swapping configuration\n", from_shell);
     main_broadcast_command(new ACSwap(new Swapper(old, sc, old_tc, tc), current_request, from_shell), from_shell);
 
+    SnortConfig::set_parser_conf(nullptr);
     return 0;
 }
 
index 350b95c19f1ea217e7df2af95eefba8ef1536f6f..91c6f4715be3963568b830f12af74dc757f6c8be 100644 (file)
@@ -661,9 +661,12 @@ void Analyzer::operator()(Swapper* ps, uint16_t run_num)
     SFDAQ::set_local_instance(daq_instance);
     set_state(State::INITIALIZED);
 
+    Profiler::start();
+
     // Start the main loop
     analyze();
 
+    Profiler::stop(pc.analyzed_pkts);
     term();
 
     set_state(State::STOPPED);
index f72881101eafcb5a1169e48c19a88f50f5d1e3ba..7df8c0e32439fb85f4ba1d19856dd14a8dc9c10d 100644 (file)
@@ -81,6 +81,7 @@ using namespace snort;
 #define OUTPUT_U2   "unified2"
 #define OUTPUT_FAST "alert_fast"
 
+SnortConfig* parser_conf = nullptr;
 THREAD_LOCAL SnortConfig* snort_conf = nullptr;
 
 uint32_t SnortConfig::warning_flags = 0;
@@ -1080,6 +1081,12 @@ SO_PUBLIC int SnortConfig::request_scratch(ScScratchFunc setup, ScScratchFunc cl
     return scratch_handlers.size() - 1;
 }
 
+SO_PUBLIC SnortConfig* SnortConfig::get_parser_conf()
+{ return parser_conf; }
+
+void SnortConfig::set_parser_conf(SnortConfig* sc)
+{ parser_conf = sc; }
+
 SO_PUBLIC SnortConfig* SnortConfig::get_conf()
 { return snort_conf; }
 
index d51864526994f6cc24623ded233d22f78640b4ee..9347f9f5d6dc157587fbaad0b5a39cacd936b908 100644 (file)
@@ -714,8 +714,10 @@ public:
 
     // Use this to access current thread's conf from other units
     static void set_conf(SnortConfig*);
+    static void set_parser_conf(SnortConfig*);
 
     SO_PUBLIC static SnortConfig* get_conf();
+    SO_PUBLIC static SnortConfig* get_parser_conf();  // main thread only!
 
     SO_PUBLIC void register_reload_resource_tuner(ReloadResourceTuner& rrt)
     { reload_tuners.push_back(&rrt); }
index 2e851fcf45eb93d1ce13aac11c20f6698cb18b1e..d0046854d222575e536d7bd3a3a46fc8bef8e9ac 100644 (file)
@@ -190,6 +190,12 @@ bool MpseManager::is_poll_capable(const MpseApi* api)
     return (api->poll);
 }
 
+bool MpseManager::parallel_compiles(const MpseApi* api)
+{
+    assert(api);
+    return (api->flags & MPSE_MTBLD) != 0;
+}
+
 // was called during drop stats but actually commented out
 // FIXIT-M this one has to accumulate across threads
 #if 0
index 806947f660d74054f808452836cd3274e34354a0..ccbf0802f344897108abfa481d1ece224270918b 100644 (file)
@@ -78,6 +78,7 @@ public:
     static bool search_engine_trim(const snort::MpseApi*);
     static bool is_async_capable(const snort::MpseApi*);
     static bool is_regex_capable(const snort::MpseApi*);
+    static bool parallel_compiles(const snort::MpseApi*);
     static bool is_poll_capable(const snort::MpseApi* api);
     static void print_mpse_summary(const snort::MpseApi*);
     static void print_search_engine_stats();
index f43e71c05bd7c016481353545420c8484ad21ff7..2281877a0e9fe813bac249e7fcbaba716d5a0338 100644 (file)
@@ -778,14 +778,10 @@ void MimeSession::init()
 
     MimeDecode::init();
 
-    /* Header search */
     mime_hdr_search_mpse = new SearchTool;
+
     if (mime_hdr_search_mpse == nullptr)
-    {
-        // FIXIT-M make configurable or at least fall back to any
-        // available search engine
-        FatalError("Could not instantiate ac_bnfa search engine.\n");
-    }
+        FatalError("Could not instantiate search engine.\n");
 
     for (tmp = &mime_hdrs[0]; tmp->name != nullptr; tmp++)
     {
index bcfa62b5a2ba004f8e3ed72e3b649e0cf63b29ca..a1173b1f3870359b1eea3d021afe819ca31df99c 100644 (file)
@@ -135,7 +135,11 @@ void AppIdPegCounts::print()
     if (!print && unknown_pegs->all_zeros())
         return;
 
-    LogLabel("Appid dynamic stats:");
+    LogLabel("Appid Statistics");
+    LogLabel("detected apps and services");
+
+    LogMessage("%25.25s: %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n",
+        "Application", "Flows", "Clients", "Users", "Payloads", "Misc", "Incompat.", "Failed");
 
     for (unsigned i = 0; i < app_num; i++)
     {
@@ -144,17 +148,14 @@ void AppIdPegCounts::print()
             continue;
 
         std::string app_name = AppIdPegCounts::appid_detectors_info[i];
-        LogMessage("%s: ", app_name.c_str());
+        LogMessage("%25.25s:", app_name.c_str());
         pegs->print();
     }
 
-    // Print unknown app stats
     if (!unknown_pegs->all_zeros())
     {
-        LogMessage("unknown_app: flows: %" PRIu64 ", clients: %" PRIu64 ", users: %" PRIu64 ", payloads %"
-            PRIu64 ", misc: %" PRIu64 "\n",
-            unknown_pegs->stats[0], unknown_pegs->stats[1], unknown_pegs->stats[2],
-            unknown_pegs->stats[3], unknown_pegs->stats[4]);
+        LogMessage("%25.25s:", "unknown");
+        unknown_pegs->print();
     }
 }
 
index 1431e6a85735ded5a3e4fa973c1a52d99776233a..ed9c2affb350a735111620cccf158f5ffb889f5d 100644 (file)
@@ -70,8 +70,8 @@ public:
 
         void print()
         {
-            snort::LogMessage("flows: %" PRIu64 ", clients: %" PRIu64 ", users: %" PRIu64 ", payloads %" PRIu64
-                ", misc: %" PRIu64 ", incompatible: %" PRIu64 ", failed: %" PRIu64 "\n",
+            snort::LogMessage(" " FMTu64("-10") " " FMTu64("-10") " " FMTu64("-10") " " FMTu64("-10")
+                " " FMTu64("-10") " " FMTu64("-10") " " FMTu64("-10")"\n",
                 stats[0], stats[1], stats[2], stats[3], stats[4], stats[5], stats[6]);
         }
     };
index 547e290e32e708fac692a91cdb10476b675d39f1..07c2b9fe1f1cdf37aa70f8f2e8c05f6959a5d545 100644 (file)
@@ -652,7 +652,7 @@ static int http_pattern_match(void* id, void*, int match_end_pos, void* data, vo
         return 0;
 }
 
-int HttpPatternMatchers::process_host_patterns(DetectorHTTPPatterns patterns)
+int HttpPatternMatchers::process_host_patterns(DetectorHTTPPatterns& patterns)
 {
     if (!host_url_matcher)
         host_url_matcher = mlmpCreate();
index 9cd7043f19df152350c691200790f0284b47e7ed..dac7ac1559b4d6e8d8cafd78e1b3c2233150c234 100644 (file)
@@ -297,7 +297,7 @@ public:
     void insert_rtmp_url_pattern(DetectorAppUrlPattern*);
     void insert_app_url_pattern(DetectorAppUrlPattern*);
     int process_chp_list(CHPListElement*);
-    int process_host_patterns(DetectorHTTPPatterns);
+    int process_host_patterns(DetectorHTTPPatterns&);
     int process_mlmp_patterns();
 
     void scan_key_chp(ChpMatchDescriptor&);
index 910119285d3bfc73e1750ed1eddb653eaecf10cf..cb2e4c8965055cc3ab6dfea26f0279609d86628f 100644 (file)
@@ -155,33 +155,14 @@ void AppIdDebug::set_constraints(const char*, const AppIdDebugSessionConstraints
 }
 
 // Profiler mock functions
-void Profiler::register_module(Module*)
-{
-}
-
-void Profiler::register_module(const char*, const char*, Module*)
-{
-}
-
-void Profiler::consolidate_stats(uint64_t, uint64_t)
-{
-}
-
-void Profiler::reset_stats()
-{
-}
-
-void Profiler::show_stats()
-{
-}
-
-MemoryContext::MemoryContext(MemoryTracker&)
-{
-}
-
-MemoryContext::~MemoryContext()
-{
-}
+void Profiler::register_module(Module*) { }
+void Profiler::register_module(const char*, const char*, Module*) { }
+void Profiler::consolidate_stats() { }
+void Profiler::reset_stats() { }
+void Profiler::show_stats() { }
+
+MemoryContext::MemoryContext(MemoryTracker&) { }
+MemoryContext::~MemoryContext() { }
 
 unsigned AppIdSession::inspector_id = 0;
 THREAD_LOCAL AppIdDebug* appidDebug = nullptr;
index 30c58d1f856209c6d0b65606e69e5352c2c59b9b..c5b06f85e14f0bd96ca0402f00fa93d199e49733 100644 (file)
@@ -253,6 +253,7 @@ void parser_term(SnortConfig*)
 SnortConfig* ParseSnortConf(const SnortConfig* boot_conf, const char* fname, bool is_fatal)
 {
     SnortConfig* sc = new SnortConfig(SnortConfig::get_conf()->proto_ref);
+    SnortConfig::set_parser_conf(sc);
 
     sc->logging_flags = boot_conf->logging_flags;
     sc->tweaks = boot_conf->tweaks;
index 1fc6646547c82059b3a41d2e4e0858d1f070d4a7..632c05e39f934090eea8ab32dd56b1b031b201de 100644 (file)
@@ -28,6 +28,8 @@
 
 #include "framework/module.h"
 #include "main/snort_config.h"
+#include "main/thread_config.h"
+#include "time/stopwatch.h"
 
 #include "memory_context.h"
 #include "memory_profiler.h"
@@ -45,6 +47,7 @@ THREAD_LOCAL ProfileStats totalPerfStats;
 THREAD_LOCAL ProfileStats otherPerfStats;
 
 THREAD_LOCAL TimeContext* ProfileContext::curr_time = nullptr;
+THREAD_LOCAL Stopwatch<SnortClock>* run_timer = nullptr;
 
 static ProfilerNodeMap s_profiler_nodes;
 
@@ -70,23 +73,24 @@ void Profiler::register_module(const char* n, const char* pn, Module* m)
     s_profiler_nodes.register_node(n, pn, m);
 }
 
-void Profiler::consolidate_stats(uint64_t num_pkts, uint64_t usecs)
+void Profiler::start()
 {
-    totalPerfStats.time.checks = otherPerfStats.time.checks = num_pkts;
-
-#ifdef USE_TSC_CLOCK
-    totalPerfStats.time.elapsed = otherPerfStats.time.elapsed = clock_ticks(usecs);
-#else
-    hr_duration dt = TO_DURATION(dt, usecs);
-    totalPerfStats.time.elapsed = otherPerfStats.time.elapsed = dt;
-#endif
+    run_timer = new Stopwatch<SnortClock>;
+    run_timer->start();
+}
 
-    const ProfilerNode& root = s_profiler_nodes.get_root();
-    auto children = root.get_children();
+void Profiler::stop(uint64_t checks)
+{
+    run_timer->stop();
+    totalPerfStats.time.elapsed = run_timer->get();
+    totalPerfStats.time.checks = checks;
 
-    for ( auto pn : children )
-        otherPerfStats.time.elapsed -= pn->get_stats().time.elapsed;
+    delete run_timer;
+    run_timer = nullptr;
+}
 
+void Profiler::consolidate_stats()
+{
     s_profiler_nodes.accumulate_nodes();
     MemoryProfiler::consolidate_fallthrough_stats();
 }
@@ -99,6 +103,20 @@ void Profiler::reset_stats()
 
 void Profiler::show_stats()
 {
+    const ProfilerNode& root = s_profiler_nodes.get_root();
+    auto children = root.get_children();
+
+    hr_duration runtime = root.get_stats().time.elapsed;
+    hr_duration sum = 0_ticks;
+
+    for ( auto pn : children )
+        sum += pn->get_stats().time.elapsed;
+
+    otherPerfStats.time.checks = root.get_stats().time.checks;
+    otherPerfStats.time.elapsed = (runtime > sum) ?  (runtime - sum) : 0_ticks;
+
+    s_profiler_nodes.accumulate_flex();
+
     const auto* config = SnortConfig::get_profiler();
     assert(config);
 
index c9e049628ef73cb989b3fa0c7dd2a7755644f975..e2cf8d2f381a210b3305b06c877c02d0087d57e7 100644 (file)
@@ -35,7 +35,10 @@ public:
     static void register_module(snort::Module*);
     static void register_module(const char*, const char*, snort::Module*);
 
-    static void consolidate_stats(uint64_t pkts = 0, uint64_t usecs = 0);
+    static void start();
+    static void stop(uint64_t);
+
+    static void consolidate_stats();
 
     static void reset_stats();
     static void show_stats();
index 60cde46daafc60250ba7aadf06cfdea9c953a993..81407019cdea6307257c5cf9e18f63d497d66dd9 100644 (file)
@@ -31,6 +31,7 @@
 namespace snort
 {
 #define ROOT_NODE "total"
+#define FLEX_NODE "other"
 
 struct ProfilerConfig
 {
index 07bdfbb13a7ed7503a6b74621ed6b0f5312c1660..efb770ec941ea16f617bde942f6b59e558714350 100644 (file)
@@ -134,6 +134,14 @@ void ProfilerNodeMap::accumulate_nodes()
         it->second.accumulate();
 }
 
+void ProfilerNodeMap::accumulate_flex()
+{
+    auto it = nodes.find(FLEX_NODE);
+
+    if ( it != nodes.end() )
+        it->second.accumulate();
+}
+
 void ProfilerNodeMap::reset_nodes()
 {
     for ( auto it = nodes.begin(); it != nodes.end(); ++it )
index 727b74484184e6ecb4dbf9ed811460087de62bac..65136aed144b4b5e18bc1bfb5e2bba2bd799d9bb 100644 (file)
@@ -92,6 +92,7 @@ public:
     void register_node(const std::string&, const char*, snort::Module*);
 
     void accumulate_nodes();
+    void accumulate_flex();
     void reset_nodes();
 
     const ProfilerNode& get_root();
index a506e21935d3a6bb4f3cd31fc56818439890f2d4..63dc36c584ef34f45af2cd7865b4c670f7520430 100644 (file)
@@ -31,6 +31,7 @@
 #include "framework/mpse.h"
 #include "log/messages.h"
 #include "main/snort_config.h"
+#include "main/thread.h"
 #include "utils/stats.h"
 
 using namespace snort;
@@ -93,11 +94,11 @@ void Pattern::escape(const uint8_t* s, unsigned n, bool literal)
 
 typedef std::vector<Pattern> PatternVector;
 
-// we need to update scratch in the main thread as each pattern is processed
-// and then clone to thread specific after all rules are loaded.  s_scratch is
-// a prototype that is large enough for all uses.
+// we need to update scratch in each compiler thread as each pattern is processed
+// and then select the largest to clone to packet thread specific after all rules
+// are loaded.  s_scratch is a prototype that is large enough for all uses.
 
-static hs_scratch_t* s_scratch = nullptr;
+static std::vector<hs_scratch_t*> s_scratch;
 static unsigned int scratch_index;
 static bool scratch_registered = false;
 
@@ -243,7 +244,7 @@ int HyperscanMpse::prep_patterns(SnortConfig* sc)
         return -2;
     }
 
-    if ( hs_error_t err = hs_alloc_scratch(hs_db, &s_scratch) )
+    if ( hs_error_t err = hs_alloc_scratch(hs_db, &s_scratch[get_instance_id()]) )
     {
         ParseError("can't allocate search scratch space (%d)", err);
         return -3;
@@ -294,20 +295,46 @@ int HyperscanMpse::_search(
 
 static void scratch_setup(SnortConfig* sc)
 {
+    // find the largest scratch and clone for all slots
+    hs_scratch_t* max = nullptr;
+
     for ( unsigned i = 0; i < sc->num_slots; ++i )
     {
-        hs_scratch_t** ss = (hs_scratch_t**) &sc->state[i][scratch_index];
+        if ( !s_scratch[i] )
+            continue;
 
-        if ( s_scratch )
-            hs_clone_scratch(s_scratch, ss);
+        if ( !max )
+        {
+            max = s_scratch[i];
+            s_scratch[i] = nullptr;
+            continue;
+        }
+        size_t max_sz, idx_sz;
+        hs_scratch_size(max, &max_sz);
+        hs_scratch_size(s_scratch[i], &idx_sz);
+
+        if ( idx_sz > max_sz )
+        {
+            hs_free_scratch(max);
+            max = s_scratch[i];
+        }
         else
-            ss = nullptr;
+        {
+            hs_free_scratch(s_scratch[i]);
+        }
+        s_scratch[i] = nullptr;
     }
-    if ( s_scratch )
+    for ( unsigned i = 0; i < sc->num_slots; ++i )
     {
-        hs_free_scratch(s_scratch);
-        s_scratch = nullptr;
+        hs_scratch_t** ss = (hs_scratch_t**) &sc->state[i][scratch_index];
+
+        if ( max )
+            hs_clone_scratch(max, ss);
+        else
+            *ss = nullptr;
     }
+    if ( max )
+        hs_free_scratch(max);
 }
 
 static void scratch_cleanup(SnortConfig* sc)
@@ -319,7 +346,7 @@ static void scratch_cleanup(SnortConfig* sc)
         if ( ss )
         {
             hs_free_scratch(ss);
-            ss = nullptr;
+            sc->state[i][scratch_index] = nullptr;
         }
     }
 }
@@ -333,6 +360,7 @@ static Mpse* hs_ctor(
 {
     if ( !scratch_registered )
     {
+        s_scratch.resize(sc->num_slots);
         scratch_index = SnortConfig::request_scratch(scratch_setup, scratch_cleanup);
         scratch_registered = true;
     }
@@ -370,7 +398,7 @@ static const MpseApi hs_api =
         nullptr,
         nullptr
     },
-    MPSE_REGEX,
+    MPSE_REGEX | MPSE_MTBLD,
     nullptr,  // activate
     nullptr,  // setup
     nullptr,  // start
index 5a25d3bfb96a9c3dce907aa3227ed380ee225eae..49f1fb6259039bcd3c05dbd92480e0277e5993fd 100644 (file)
@@ -42,7 +42,10 @@ SearchTool::SearchTool(const char* method, bool dfa)
     // pattern offload search method.  If a method is passed in then an offload
     // search engine will not be created
 
-    if (mpsegrp->create_normal_mpse(method))
+    SnortConfig* sc = SnortConfig::get_parser_conf();
+    assert(sc);
+
+    if (mpsegrp->create_normal_mpse(sc, method))
     {
         if( dfa )
             mpsegrp->normal_mpse->set_opt(1);
@@ -50,7 +53,7 @@ SearchTool::SearchTool(const char* method, bool dfa)
 
     if (method == nullptr)
     {
-        if (mpsegrp->create_offload_mpse())
+        if (mpsegrp->create_offload_mpse(sc))
         {
             if ( dfa )
                 mpsegrp->offload_mpse->set_opt(1);
index 924f36ec6fee423791a83ed1c6416c8a75c684ca..2a0245248605ccdd6cff2a0093770733081a833b 100644 (file)
@@ -190,7 +190,7 @@ TEST(mpse_hs_base, base)
 TEST(mpse_hs_base, mpse)
 {
     const MpseApi* mpse_api = (MpseApi*)se_hyperscan;
-    CHECK(mpse_api->flags == MPSE_REGEX);
+    CHECK(mpse_api->flags == (MPSE_REGEX | MPSE_MTBLD));
 
     CHECK(mpse_api->ctor);
     CHECK(mpse_api->dtor);
index e28286811cd44c26cee39ad3ad2248b2d8b6c8ce..e6ffcb3e8674bec210f016f5302f14af219bc80f 100644 (file)
@@ -65,6 +65,9 @@ SnortConfig::~SnortConfig() = default;
 SnortConfig* SnortConfig::get_conf()
 { return snort_conf; }
 
+SnortConfig* SnortConfig::get_parser_conf()
+{ return snort_conf; }
+
 unsigned get_instance_id()
 { return 0; }
 
@@ -196,14 +199,14 @@ MpseGroup::~MpseGroup()
     }
 }
 
-bool MpseGroup::create_normal_mpse(const char* type)
+bool MpseGroup::create_normal_mpse(SnortConfig*, const char* type)
 {
     normal_mpse = MpseManager::get_search_engine(type);
 
     return true;
 }
 
-bool MpseGroup::create_offload_mpse()
+bool MpseGroup::create_offload_mpse(SnortConfig*)
 {
     offload_mpse = nullptr;
     return false;
index 712be4d13f285cdc6230e29c86c2c6f8cab5b769..ef1df958c50eceab84accedb8f1465994a312c5e 100644 (file)
@@ -23,6 +23,8 @@
 
 #include "http_inspect.h"
 
+#include <cassert>
+
 #include "detection/detection_engine.h"
 #include "detection/detection_util.h"
 #include "log/unified2.h"
@@ -86,6 +88,43 @@ bool HttpInspect::configure(SnortConfig* )
     return true;
 }
 
+void HttpInspect::show(snort::SnortConfig*)
+{
+    assert(params);
+    LogMessage("http_inspect\n");
+
+    if ( params->request_depth == -1 )
+        LogMessage("    request_depth: " "%s" "\n", "unlimited");
+    else
+        LogMessage("    request_depth: " STDi64 "\n", params->request_depth);
+
+    if ( params->response_depth == -1 )
+        LogMessage("    response_depth: " "%s" "\n", "unlimited");
+    else
+        LogMessage("    response_depth: " STDi64 "\n", params->response_depth);
+
+    LogMessage("    unzip: %s\n", params->unzip ? "yes" : "no");
+    LogMessage("    normalize_utf: %s\n", params->normalize_utf ? "yes" : "no");
+    LogMessage("    decompress_pdf: %s\n", params->decompress_pdf ? "yes" : "no");
+    LogMessage("    decompress_swf: %s\n", params->decompress_swf ? "yes" : "no");
+    LogMessage("    decompress_zip: %s\n", params->decompress_zip ? "yes" : "no");
+    LogMessage("    detained_inspection: %s\n", params->detained_inspection ? "yes" : "no");
+
+    LogMessage("    normalize_javascript: %s\n", params->js_norm_param.normalize_javascript ? "yes" : "no");
+    LogMessage("    max_javascript_whitespaces: %d\n", params->js_norm_param.max_javascript_whitespaces);
+
+    LogMessage("    percent_u: %s\n", params->uri_param.percent_u ? "yes" : "no");
+    LogMessage("    utf8: %s\n", params->uri_param.utf8 ? "yes" : "no");
+    LogMessage("    utf8_bare_byte: %s\n", params->uri_param.utf8_bare_byte ? "yes" : "no");
+    LogMessage("    oversize_dir_length: %d\n", params->uri_param.oversize_dir_length);
+    LogMessage("    iis_unicode: %s\n", params->uri_param.iis_unicode ? "yes" : "no");
+    LogMessage("    iis_unicode_map_file: %s\n", params->uri_param.iis_unicode_map_file.c_str());
+    LogMessage("    iis_double_decode: %s\n", params->uri_param.iis_double_decode ? "yes" : "no");
+    LogMessage("    backslash_to_slash: %s\n", params->uri_param.backslash_to_slash ? "yes" : "no");
+    LogMessage("    plus_to_space: %s\n", params->uri_param.plus_to_space ? "yes" : "no");
+    LogMessage("    simplify_path: %s\n", params->uri_param.simplify_path ? "yes" : "no");
+}
+
 InspectSection HttpInspect::get_latest_is(const Packet* p)
 {
     HttpMsgSection* current_section = HttpContextData::get_snapshot(p);
index a43e2f14451d9aa6517c0538fe1d92bd134cdc72..db64b9eb055080bca1ffbc282698fdd21bd6ebd2 100644 (file)
@@ -47,7 +47,7 @@ public:
         snort::InspectionBuffer& b);
     bool get_fp_buf(snort::InspectionBuffer::Type ibt, snort::Packet* p, snort::InspectionBuffer& b) override;
     bool configure(snort::SnortConfig*) override;
-    void show(snort::SnortConfig*) override { snort::LogMessage("HttpInspect\n"); }
+    void show(snort::SnortConfig*) override;
     void eval(snort::Packet* p) override;
     void clear(snort::Packet* p) override;
     HttpStreamSplitter* get_splitter(bool is_client_to_server) override
index 8b6d5ed0460eea688eb01541538080b8ae06c4df..f1ba9f64161c7279460c4da13e902e79ddb6a64a 100644 (file)
@@ -130,12 +130,11 @@ void TimeStop()
     gettimeofday(&endtime, nullptr);
 }
 
-static void timing_stats(uint64_t& num_pkts, uint64_t& usecs)
+static void timing_stats()
 {
     struct timeval difftime;
     TIMERSUB(&endtime, &starttime, &difftime);
 
-
     uint32_t tmp = (uint32_t)difftime.tv_sec;
     uint32_t total_secs = tmp;
     if ( total_secs < 1 )
@@ -154,8 +153,7 @@ static void timing_stats(uint64_t& num_pkts, uint64_t& usecs)
     LogMessage("%25.25s: %lu.%06lu\n", "seconds",
         (unsigned long)difftime.tv_sec, (unsigned long)difftime.tv_usec);
 
-    usecs = (uint64_t)difftime.tv_sec * 1000000 + difftime.tv_usec;
-    num_pkts = (uint64_t)ModuleManager::get_module("daq")->get_global_count("received");
+    uint64_t num_pkts = (uint64_t)ModuleManager::get_module("daq")->get_global_count("received");
 
     LogMessage("%25.25s: " STDu64 "\n", "packets", num_pkts);
 
@@ -239,10 +237,7 @@ void DropStats()
 void PrintStatistics()
 {
     DropStats();
-
-    PegCount pkts;
-    uint64_t usecs;
-    timing_stats(pkts, usecs);
+    timing_stats();
 
     // FIXIT-L can do flag saving with RAII (much cleaner)
     int save_quiet_flag = SnortConfig::get_conf()->logging_flags & LOGGING_FLAG__QUIET;
@@ -250,7 +245,8 @@ void PrintStatistics()
     SnortConfig::get_conf()->logging_flags &= ~LOGGING_FLAG__QUIET;
 
     // once more for the main thread
-    Profiler::consolidate_stats(pkts, usecs);
+    Profiler::consolidate_stats();
+
     Profiler::show_stats();
 
     SnortConfig::get_conf()->logging_flags |= save_quiet_flag;