]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2334 in SNORT/snort3 from ~SVLASIUK/snort3:dump_config_text to...
authorBhagya Tholpady (bbantwal) <bbantwal@cisco.com>
Fri, 31 Jul 2020 17:40:54 +0000 (17:40 +0000)
committerBhagya Tholpady (bbantwal) <bbantwal@cisco.com>
Fri, 31 Jul 2020 17:40:54 +0000 (17:40 +0000)
Squashed commit of the following:

commit 252af2d5de8f3b68bd43e649e49d11a7c7bb742b
Author: Serhii Vlasiuk <svlasiuk@cisco.com>
Date:   Fri Jul 3 15:25:57 2020 +0300

    main: dump consolidated config in the text format

17 files changed:
src/detection/fp_create.cc
src/framework/value.cc
src/framework/value.h
src/log/messages.cc
src/log/messages.h
src/main.cc
src/main/CMakeLists.txt
src/main/config_tree.cc [new file with mode: 0644]
src/main/config_tree.h [new file with mode: 0644]
src/main/dev_notes.txt
src/main/shell.cc
src/main/shell.h
src/main/snort.cc
src/main/snort_config.h
src/main/snort_module.cc
src/managers/module_manager.cc
src/trace/trace_module.cc

index cbc8405a216c01198a6839186aa00c278bbb1941..21a0cd084ab261b6cefd4003f9912592a49960ab 100644 (file)
@@ -1613,7 +1613,7 @@ int fpCreateFastPacketDetection(SnortConfig* sc)
     if ( log_rule_group_details )
         LogMessage("Service Based Rule Maps Done....\n");
 
-    if ( !sc->test_mode() or sc->mem_check() )
+    if ( !sc->validation_mode() or sc->mem_check() )
     {
         unsigned c = compile_mpses(sc, can_build_mt(fp));
         unsigned expected = mpse_count + offload_mpse_count;
index 0cff82c9c70c813bbd08f143a74ae7f5fa010d14..82bdfec8936832be61436b31411a9974c74591ee 100644 (file)
@@ -217,6 +217,39 @@ const char* Value::get_as_string()
     return str.c_str();
 }
 
+std::string Value::get_origin_string() const
+{
+    std::string value;
+    std::string token;
+
+    stringstream ss(origin_str);
+    while ( ss >> token )
+    {
+        value += token;
+        value += " ";
+    }
+    value.erase(value.size() - 1);
+
+    if ( param && param->type != Parameter::PT_BOOL
+        && param->type != Parameter::PT_REAL
+        && param->type != Parameter::PT_INT
+        && param->type != Parameter::PT_IMPLIED )
+    {
+        value.insert(0, "'");
+        value.insert(value.length(), "'");
+    }
+
+    return value;
+}
+
+Parameter::Type Value::get_param_type() const
+{
+    if ( param )
+        return param->type;
+
+    return Parameter::PT_MAX;
+}
+
 void Value::update_mask(uint8_t& mask, uint8_t flag, bool invert)
 {
     if ( get_bool() xor invert )
index b8190bd9d306527c683ed0cea566e66f721855d4..df176085762b26916ecc0d9b51657207a7f322d9 100644 (file)
@@ -42,35 +42,72 @@ public:
     enum ValueType { VT_BOOL, VT_NUM, VT_STR };
 
     Value(bool b)
-    { set(b); init(); }
+    { set(b); set_origin(b); }
 
     Value(double d)
-    { set(d); init(); }
+    { set(d); set_origin(d); }
 
     Value(const char* s)
-    { set(s); init(); }
+    { set(s); set_origin(s); }
+
+    Value(const Value& v) :
+        type(v.type),
+        num(v.num),
+        str(v.str),
+        origin_str(v.origin_str),
+        ss(nullptr),
+        param(v.param)
+    {}
+
+    Value& operator=(const Value& v)
+    {
+        if ( this == &v )
+            return *this;
+
+        delete ss;
+        ss = nullptr;
+
+        type = v.type;
+        num = v.num;
+        str = v.str;
+        origin_str = v.origin_str;
+        param = v.param;
+
+        return *this;
+    }
 
     ValueType get_type()
     { return type; }
 
     ~Value()
-    {
-        if ( ss )
-            delete ss;
-    }
+    { delete ss; }
 
     void set(bool b)
     { type = VT_BOOL; num = b ? 1 : 0; str.clear(); }
 
+    void set_origin(bool val)
+    { origin_str = val ? "true" : "false"; }
+
     void set(double d)
     { type = VT_NUM; num = d; str.clear(); }
 
+    void set_origin(double val)
+    {
+        auto temp = new std::stringstream;
+        *temp << val;
+        origin_str = temp->str();
+        delete temp;
+    }
+
     void set(long n)
     { set((double)n); }
 
     void set(const char* s)
     { type = VT_STR; str = s; num = 0; }
 
+    void set_origin(const char* val)
+    { origin_str = val; }
+
     void set(const uint8_t* s, unsigned len)
     { type = VT_STR; str.assign((const char*)s, len); num = 0; }
 
@@ -89,6 +126,9 @@ public:
     bool is(const char* s) const
     { return param ? !strcmp(param->name, s) : false; }
 
+    bool has_default() const
+    { return param ? param->deflt != nullptr : false; }
+
     bool get_bool() const
     { return num != 0; }
 
@@ -129,6 +169,8 @@ public:
     { return str.c_str(); }
 
     const char* get_as_string();
+    Parameter::Type get_param_type() const;
+    std::string get_origin_string() const;
 
     bool strtol(long&) const;
     bool strtol(long&, const std::string&) const;
@@ -171,16 +213,13 @@ public:
     void update_mask(uint32_t& mask, uint32_t flag, bool invert = false);
     void update_mask(uint64_t& mask, uint64_t flag, bool invert = false);
 
-private:
-    void init()
-    { param = nullptr; ss = nullptr; }
-
 private:
     ValueType type;
     double num;
     std::string str;
-    std::stringstream* ss;
-    const Parameter* param;
+    std::string origin_str;
+    std::stringstream* ss = nullptr;
+    const Parameter* param = nullptr;
 };
 }
 #endif
index e805d987fa1257e909c5ee397b266e9f62d5a8b6..7c308b38b2faf8646cc5e10d1d61badab1d186fc 100644 (file)
@@ -235,6 +235,16 @@ void LogMessage(FILE* fh, const char* format,...)
     va_end(ap);
 }
 
+void LogConfig(const char* format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+
+    WriteLogMessage(stdout, false, format, ap);
+
+    va_end(ap);
+}
+
 /*
  * Function: WarningMessage(const char *, ...)
  *
index a2ab4d28290e6484adf159fb45ccdbeb7b1d0ea7..d61e2e87009caf438e69c29343f296949a2308d5 100644 (file)
@@ -61,6 +61,7 @@ SO_PUBLIC void ParseError(const char*, ...) __attribute__((format (printf, 1, 2)
 SO_PUBLIC void ReloadError(const char*, ...) __attribute__((format (printf, 1, 2)));
 [[noreturn]] SO_PUBLIC void ParseAbort(const char*, ...) __attribute__((format (printf, 1, 2)));
 
+SO_PUBLIC void LogConfig(const char*, ...) __attribute__((format (printf, 1, 2)));
 SO_PUBLIC void LogMessage(const char*, ...) __attribute__((format (printf, 1, 2)));
 SO_PUBLIC void LogMessage(FILE*, const char*, ...) __attribute__((format (printf, 2, 3)));
 SO_PUBLIC void WarningMessage(const char*, ...) __attribute__((format (printf, 1, 2)));
index fcb8696b6f3688188e41c01daabebc0e9828c7a8..42db721825a1ae2642f3d394bf37e240b08f8d26 100644 (file)
@@ -822,6 +822,9 @@ static bool set_mode()
         return false;
     }
 
+    if ( sc->dump_config() )
+        return false;
+
     if ( just_validate(sc) )
     {
         LogMessage("\nSnort successfully validated the configuration (with %u warnings).\n",
index 502e5710dc6951540aaa09681550ac78d3247e69..954e543a96dab0a3cbd0f4d2ca7393fb505c6beb 100644 (file)
@@ -21,6 +21,8 @@ add_library (main OBJECT
     analyzer.h
     analyzer_command.cc
     build.h
+    config_tree.cc
+    config_tree.h
     help.cc
     help.h
     modules.cc
diff --git a/src/main/config_tree.cc b/src/main/config_tree.cc
new file mode 100644 (file)
index 0000000..a689869
--- /dev/null
@@ -0,0 +1,103 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// config_tree.cc author Serhii Vlasiuk <svlasiuk@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "config_tree.h"
+
+#include <cassert>
+
+#include "log/messages.h"
+
+using namespace snort;
+
+void ConfigTextFormat::print(const BaseConfigNode* parent, const std::string& config_name)
+{
+    static char buf[16];
+    int list_index = 0;
+    for ( const auto node : parent->get_children() )
+    {
+        std::string full_config_name(config_name);
+        std::string node_name = node->get_name();
+
+        if ( !node_name.empty() )
+        {
+            full_config_name += ".";
+            full_config_name += node_name;
+        }
+        else
+        {
+            sprintf(buf, "%i", list_index++);
+            full_config_name += "[";
+            full_config_name += buf;
+            full_config_name += "]";
+        }
+
+        print(node, full_config_name);
+    }
+
+    std::string config_data = parent->data();
+    if ( !config_data.empty() )
+        LogConfig("%s=%s\n", config_name.c_str(), config_data.c_str());
+}
+
+BaseConfigNode::BaseConfigNode(BaseConfigNode* p) :
+    parent(p)
+{}
+
+void BaseConfigNode::add_child_node(BaseConfigNode* node)
+{
+    assert(node);
+    children.push_back(node);
+}
+
+void BaseConfigNode::clear_nodes(BaseConfigNode* node)
+{
+    for ( auto& config_node : node->children )
+        clear_nodes(config_node);
+
+    delete node;
+}
+
+TreeConfigNode::TreeConfigNode(BaseConfigNode* parent_node,
+    const std::string& node_name, const Parameter::Type node_type) :
+        BaseConfigNode(parent_node), name(node_name), type(node_type)
+{}
+
+BaseConfigNode* TreeConfigNode::get_node(const std::string& name)
+{
+    for ( auto node : children )
+    {
+        if ( node->get_name() == name )
+            return node;
+    }
+    return nullptr;
+}
+
+ValueConfigNode::ValueConfigNode(BaseConfigNode* parent_node, const Value& val) :
+    BaseConfigNode(parent_node), value(val)
+{}
+
+BaseConfigNode* ValueConfigNode::get_node(const std::string& name)
+{
+    return value.is(name.c_str()) and value.has_default() ? this : nullptr;
+}
+
diff --git a/src/main/config_tree.h b/src/main/config_tree.h
new file mode 100644 (file)
index 0000000..598dbb1
--- /dev/null
@@ -0,0 +1,109 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// config_tree.h author Serhii Vlasiuk <svlasiuk@cisco.com>
+
+#ifndef CONFIG_TREE_H
+#define CONFIG_TREE_H
+
+#include <list>
+
+#include "framework/value.h"
+
+class BaseConfigNode;
+
+using ChildrenNodes = std::list<BaseConfigNode*>;
+
+class ConfigTextFormat
+{
+public:
+    static void print(const BaseConfigNode* parent, const std::string& config_name);
+};
+
+class BaseConfigNode
+{
+public:
+    BaseConfigNode(BaseConfigNode* parent);
+    virtual ~BaseConfigNode() = default;
+
+    virtual std::string get_name() const = 0;
+    virtual snort::Parameter::Type get_type() const = 0;
+    virtual BaseConfigNode* get_node(const std::string& name) = 0;
+    virtual std::string data() const { return ""; }
+    virtual void set_value(const snort::Value&) {}
+
+    const ChildrenNodes& get_children() const
+    { return children; }
+
+    BaseConfigNode* get_parent_node() const
+    { return parent; }
+
+    void add_child_node(BaseConfigNode* node);
+
+    static void clear_nodes(BaseConfigNode* root);
+
+protected:
+    ChildrenNodes children;
+    BaseConfigNode* parent = nullptr;
+};
+
+class TreeConfigNode : public BaseConfigNode
+{
+public:
+    TreeConfigNode(BaseConfigNode* parent, const std::string& node_name,
+        const snort::Parameter::Type node_type);
+
+private:
+    virtual std::string get_name() const override
+    { return name; }
+
+    virtual snort::Parameter::Type get_type() const override
+    { return type; }
+
+    virtual BaseConfigNode* get_node(const std::string& name) override;
+
+private:
+    std::string name;
+    snort::Parameter::Type type = snort::Parameter::PT_MAX;
+};
+
+class ValueConfigNode : public BaseConfigNode
+{
+public:
+    ValueConfigNode(BaseConfigNode* parent, const snort::Value& value);
+
+private:
+    virtual std::string get_name() const override
+    { return value.get_name(); }
+
+    virtual snort::Parameter::Type get_type() const override
+    { return value.get_param_type(); }
+
+    virtual std::string data() const override
+    { return value.get_origin_string(); }
+
+    virtual void set_value(const snort::Value& v) override
+    { value = v; }
+
+    virtual BaseConfigNode* get_node(const std::string& name) override;
+
+private:
+    snort::Value value;
+};
+
+#endif // CONFIG_TREE_H
+
index aeae057fc6e62e609047389bb8452f197237c6dd..c4cae9e04c760e875992f3df9b83a559d69a6bf5 100644 (file)
@@ -62,3 +62,12 @@ platform-independent abstraction layer for CPU and memory architecture
 information and management.  Currently it is being used as a cross-platform
 mechanism for managing CPU affinity of threads, but it will be used in the
 future for NUMA (non-uniform memory access) awareness among other things.
+
+Consolidated Config output
+
+The snort config parsed is stored as an internal tree structure within the Shell.
+A unique shell is associated with every base and targeted policy file.
+Every module in a lua file is represented by the General Tree.
+The Tree node can be one of the following types: TreeConfigNode, ValueConfigNode.
+The TreeConfigNode represents a table or list.
+The ValueConfigNode represents a config value itself.
index b20f116662e94fde3a44a16ee930425b1124eb29..c8b1c9bcd260f49bc93b3407b13a878cb041d660 100644 (file)
@@ -26,9 +26,9 @@
 #include <unistd.h>
 
 #include <cassert>
-#include <cstring>
 #include <stdexcept>
 
+#include "config_tree.h"
 #include "log/messages.h"
 #include "lua/lua.h"
 #include "main/policy.h"
@@ -101,6 +101,125 @@ void Shell::whitelist_append(const char* keyword, bool is_prefix)
     sh->whitelist_update(keyword, is_prefix);
 }
 
+void Shell::config_open_table(bool is_root_node, bool is_list, int idx,
+    const std::string& table_name, const Parameter* p)
+{
+    Parameter::Type node_type = is_list ? Parameter::PT_LIST : Parameter::PT_TABLE;
+    if ( is_root_node )
+        add_config_root_node(table_name, node_type);
+    else
+    {
+        if ( p )
+            node_type = p->type;
+
+        if ( node_type == Parameter::PT_TABLE )
+            update_current_config_node(table_name);
+        else
+        {
+            if ( idx )
+                node_type = Parameter::PT_TABLE;
+
+            add_config_child_node(table_name, node_type);
+        }
+    }
+}
+
+void Shell::add_config_child_node(const std::string& node_name, snort::Parameter::Type type)
+{
+    Shell* sh = Shell::get_current_shell();
+
+    if ( !sh )
+        return;
+
+    std::string name;
+    if ( sh->s_current_node->get_name() != node_name )
+        name = node_name;
+
+    auto new_node = new TreeConfigNode(sh->s_current_node, name, type);
+    sh->s_current_node->add_child_node(new_node);
+    sh->s_current_node = new_node;
+}
+
+void Shell::add_config_root_node(const std::string& root_name, snort::Parameter::Type node_type)
+{
+    Shell* sh = Shell::get_current_shell();
+
+    if ( !sh )
+        return;
+
+    sh->s_current_node = new TreeConfigNode(nullptr, root_name, node_type);
+    sh->config_trees.push_back(sh->s_current_node);
+}
+
+void Shell::update_current_config_node(const std::string& node_name)
+{
+    Shell* sh = Shell::get_current_shell();
+
+    if ( !sh )
+        return;
+
+    if ( !sh->s_current_node )
+        return;
+
+    // node has been added during setting default options
+    if ( !node_name.empty() )
+        sh->s_current_node = sh->s_current_node->get_node(node_name);
+    else if ( sh->s_current_node->get_parent_node() and
+        sh->s_current_node->get_type() == Parameter::PT_TABLE and
+        !sh->s_current_node->get_name().empty() )
+            sh->s_current_node = sh->s_current_node->get_parent_node();
+
+    assert(sh->s_current_node);
+}
+
+void Shell::config_close_table()
+{
+    Shell* sh = Shell::get_current_shell();
+
+    if ( !sh )
+        return;
+
+    if ( !sh->s_current_node )
+        return;
+
+    sh->s_current_node = sh->s_current_node->get_parent_node();
+}
+
+void Shell::set_config_value(const snort::Value& value)
+{
+    Shell* sh = Shell::get_current_shell();
+
+    if ( !sh )
+        return;
+
+    if ( !sh->s_current_node )
+        return;
+
+    // lua interpreter does not call open_table for simple list items like (string)
+    // we have to add tree node for this item too
+    if ( sh->s_current_node->get_type() == Parameter::PT_LIST )
+    {
+        add_config_child_node("", Parameter::PT_TABLE);
+        sh->s_current_node->add_child_node(new ValueConfigNode(sh->s_current_node, value));
+        sh->s_current_node = sh->s_current_node->get_parent_node();
+
+        return;
+    }
+    
+    BaseConfigNode* child_node = nullptr;
+    for ( auto node : sh->s_current_node->get_children() )
+    {
+        child_node = node->get_node(value.get_name());
+        if ( child_node )
+            break;
+    }
+
+    if ( !child_node )
+        sh->s_current_node->add_child_node(new ValueConfigNode(sh->s_current_node, value));
+    else
+        child_node->set_value(value);
+}
+
 // FIXIT-L shell --pause should stop before loading config so Lua state
 // can be examined and modified.
 
@@ -155,7 +274,6 @@ static void load_string(lua_State* L, const char* s)
         FatalError("can't init overrides: %s\n", lua_tostring(L, -1));
 }
 
-
 //-------------------------------------------------------------------------
 // public methods
 //-------------------------------------------------------------------------
@@ -264,6 +382,14 @@ bool Shell::configure(SnortConfig* sc, bool is_fatal, bool is_root)
     load_string(lua, ModuleManager::get_lua_finalize());
 
     clear_whitelist();
+
+    if ( SnortConfig::get_conf()->dump_config() )
+    {
+        sort_config();
+        print_config_text();
+        clear_config_tree();
+    }
+
     current_shells.pop();
 
     set_default_policy(sc);
@@ -333,6 +459,29 @@ static void print_list(const Shell::Whitelist& wlist, const std::string& msg)
 //-------------------------------------------------------------------------
 // private methods
 //-------------------------------------------------------------------------
+void Shell::sort_config()
+{
+    config_trees.sort([](const BaseConfigNode* l, const BaseConfigNode* r)
+        { return l->get_name() < r->get_name(); });
+}
+
+void Shell::print_config_text() const
+{
+    std::string output("consolidated config for ");
+    output += file;
+    LogConfig("%s\n", output.c_str());
+
+    for ( const auto config_tree: config_trees )
+        ConfigTextFormat::print(config_tree, config_tree->get_name());
+}
+
+void Shell::clear_config_tree()
+{
+    for ( auto config_tree: config_trees )
+        BaseConfigNode::clear_nodes(config_tree);
+
+    config_trees.clear();
+}
 
 void Shell::print_whitelist() const
 {
index e3578105af7e32d92958d048a736c05b1d2b0ff0..ef6883d983cb6e659279d30f0d019f7e2db982d3 100644 (file)
 
 // Shell encapsulates a Lua state.  There is one for each policy file.
 
+#include <list>
 #include <set>
 #include <stack>
 #include <string>
 
+#include "framework/parameter.h"
+
 struct lua_State;
 
+class BaseConfigNode;
+
 namespace snort
 {
 struct SnortConfig;
+class Value;
 }
 
 class Shell
@@ -62,6 +68,16 @@ public:
     static bool is_whitelisted(const std::string& key);
     static void whitelist_append(const char* keyword, bool is_prefix);
 
+    static void config_open_table(bool is_root_node, bool is_list, int idx,
+        const std::string& table_name, const snort::Parameter* p);
+    static void set_config_value(const snort::Value& value);
+    static void add_config_child_node(const std::string& node_name, snort::Parameter::Type type);
+    static void update_current_config_node(const std::string& node_name = "");
+    static void config_close_table();
+
+private:
+    static void add_config_root_node(const std::string& root_name, snort::Parameter::Type type);
+
 private:
     [[noreturn]] static int panic(lua_State*);
     static Shell* get_current_shell();
@@ -90,6 +106,10 @@ private:
     void print_whitelist() const;
     void whitelist_update(const char* keyword, bool is_prefix);
 
+    void sort_config();
+    void print_config_text() const;
+    void clear_config_tree();
+
 private:
     bool loaded;
     bool bootstrapped = false;
@@ -100,6 +120,8 @@ private:
     Whitelist whitelist;
     Whitelist internal_whitelist;
     Whitelist whitelist_prefixes;
+    std::list<BaseConfigNode*> config_trees;
+    BaseConfigNode* s_current_node = nullptr;
 };
 
 #endif
index 432cbf5c510b29ceb44fe1848eba704f8808e331..28e665b4395c99da1722bcb96fe9051c14647c3e 100644 (file)
@@ -426,7 +426,7 @@ void Snort::cleanup()
     SFDAQ::term();
     FileService::close();
 
-    if ( !SnortConfig::get_conf()->test_mode() )  // FIXIT-M ideally the check is in one place
+    if ( !SnortConfig::get_conf()->validation_mode() )  // FIXIT-M ideally the check is in one place
         PrintStatistics();
 
     CloseLogger();
index 70ba985f4125250ac6b40696446b4697a0082cb1..30a7fbbec2380424c78babcb503a9db871c146e9 100644 (file)
@@ -81,6 +81,7 @@ enum RunFlag
     RUN_FLAG__IP_FRAGS_ONLY       = 0x08000000,
 
     RUN_FLAG__DUMP_RULE_STATE     = 0x10000000,
+    RUN_FLAG__DUMP_CONFIG         = 0x20000000,
 };
 
 enum OutputFlag
@@ -500,6 +501,9 @@ public:
     { return address_anomaly_check_enabled; }
 
     // mode related
+    bool dump_config() const
+    { return run_flags & RUN_FLAG__DUMP_CONFIG; }
+
     bool dump_msg_map() const
     { return run_flags & RUN_FLAG__DUMP_MSG_MAP; }
 
@@ -518,11 +522,14 @@ public:
     bool test_mode() const
     { return run_flags & RUN_FLAG__TEST; }
 
+    bool validation_mode() const
+    { return test_mode() or dump_config(); }
+
     bool mem_check() const
-    { return run_flags & RUN_FLAG__MEM_CHECK; }
+    { return (run_flags & RUN_FLAG__MEM_CHECK) and !dump_config(); }
 
     bool daemon_mode() const
-    { return run_flags & RUN_FLAG__DAEMON; }
+    { return (run_flags & RUN_FLAG__DAEMON) and !dump_config(); }
 
     bool read_mode() const
     { return run_flags & RUN_FLAG__READ; }
index e936098faa25c18e7a9b49c011a4cce0d9760e03..5de0697eeed9ad92913d33b6141d56e21c8f087c 100644 (file)
@@ -347,6 +347,9 @@ static const Parameter s_params[] =
     { "--dump-builtin-rules", Parameter::PT_STRING, "(optional)", nullptr,
       "[<module prefix>] output stub rules for selected modules" },
 
+    { "--dump-config-text", Parameter::PT_IMPLIED, nullptr, nullptr,
+      "dump config in text format" },
+
     // FIXIT-L add --list-dynamic-rules like --list-builtin-rules
     { "--dump-dynamic-rules", Parameter::PT_IMPLIED, nullptr, nullptr,
       "output stub rules for all loaded rules libraries" },
@@ -601,9 +604,6 @@ static const Parameter s_params[] =
     { "--x2s", Parameter::PT_STRING, nullptr, nullptr,
       "output ASCII string for given byte code (see also --x2c)" },
 
-    { "--trace", Parameter::PT_IMPLIED, nullptr, nullptr,
-      "turn on main loop debug trace" },
-
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 
@@ -868,6 +868,12 @@ bool SnortModule::set(const char*, Value& v, SnortConfig* sc)
     else if ( v.is("--dump-builtin-rules") )
         dump_builtin_rules(sc, v.get_string());
 
+    else if ( v.is("--dump-config-text") )
+    {
+      sc->run_flags |= RUN_FLAG__DUMP_CONFIG;
+      sc->set_quiet(true);
+    }
+
     else if ( v.is("--dump-dynamic-rules") )
         dump_dynamic_rules(sc, v.get_string());
 
index fb937126998d39c55854e24e2a076c72a0194497..b27bd269dcea3375e7b506f1900da5c513f7806e 100644 (file)
@@ -166,6 +166,14 @@ void ModHook::init()
 //-------------------------------------------------------------------------
 // helper functions
 //-------------------------------------------------------------------------
+static std::string get_sub_table(const std::string& fqn)
+{
+    auto pos = fqn.find_last_of(".");
+    if ( pos != std::string::npos )
+        return fqn.substr(pos + 1);
+    else
+        return fqn;
+}
 
 static void set_type(string& fqn)
 {
@@ -446,6 +454,9 @@ static bool set_var(const char* fqn, Value& v)
 
 static bool set_param(Module* mod, const char* fqn, Value& val)
 {
+    if ( s_config->dump_config() )
+        Shell::set_config_value(val);
+
     if ( !mod->verified_set(fqn, val, s_config) )
     {
         ParseError("%s is invalid", fqn);
@@ -583,6 +594,9 @@ static bool begin(Module* m, const Parameter* p, const char* s, int idx, int dep
             {
                 const Parameter* table_item_params = reinterpret_cast<const Parameter*>(p->range);
 
+                if ( s_config->dump_config() )
+                    Shell::add_config_child_node(get_sub_table(fqn), p->type);
+
                 if ( !begin(m, table_item_params, fqn.c_str(), idx, depth+1) )
                     return false;
             }
@@ -619,6 +633,8 @@ static bool begin(Module* m, const Parameter* p, const char* s, int idx, int dep
         }
         ++p;
     }
+    if ( s_config->dump_config() )
+        Shell::update_current_config_node();
     return true;
 }
 
@@ -747,6 +763,19 @@ SO_PUBLIC bool open_table(const char* s, int idx)
         s_current = unique_key;
     }
 
+    if ( s_config->dump_config() )
+    {
+        std::string table_name = get_sub_table(s);
+        bool is_top_level = false;
+        if ( top_level(s) && !idx )
+        {
+            table_name = s_current;
+            is_top_level = true;
+        }
+
+        Shell::config_open_table(is_top_level, m->is_list(), idx, table_name, p);
+    }
+
     if ( !begin(m, p, s, idx, 0) )
     {
         ParseError("can't open %s", m->get_name());
@@ -786,6 +815,9 @@ SO_PUBLIC void close_table(const char* s, int idx)
         s_name.clear();
         s_type.clear();
     }
+
+    if ( s_config->dump_config() )
+        Shell::config_close_table();
 }
 
 SO_PUBLIC bool set_bool(const char* fqn, bool b)
index 68f8e63684da9d8790831b3d0bf74633c3627285..6d4a0353a5a7d09f450106647ad6a0b3a808c9fd 100644 (file)
@@ -84,6 +84,9 @@ void TraceModule::generate_params()
         }
     }
 
+    std::sort(modules_params.begin(), modules_params.end(),
+        [](const Parameter& l, const Parameter& r) { return (strcmp(l.name, r.name) < 0); });
+
     modules_params.emplace_back(nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr);
 
     const static Parameter trace_constraints_params[] =
@@ -174,28 +177,34 @@ bool TraceModule::end(const char* fqn, int, SnortConfig* sc)
     if ( !strcmp(fqn, "trace") )
     {
         assert(trace_parser);
-        switch ( log_output_type )
-        {
-            case OUTPUT_TYPE_STDOUT:
-                trace_parser->get_trace_config()->logger_factory = new StdoutLoggerFactory();
-                break;
-            case OUTPUT_TYPE_SYSLOG:
-                trace_parser->get_trace_config()->logger_factory = new SyslogLoggerFactory();
-                break;
-            default:
-                break;
-        }
 
-        // "output=syslog" config override case
-        // do not closelog() here since it will be closed in Snort::clean_exit()
-        if ( !sc->log_syslog() and log_output_type == OUTPUT_TYPE_SYSLOG
-             and !local_syslog )
+        if ( sc->dump_config() )
+            trace_parser->clear_traces();
+        else
         {
-            local_syslog = true;
-            openlog("snort", LOG_PID | LOG_CONS, LOG_DAEMON);
-        }
+            switch ( log_output_type )
+            {
+                case OUTPUT_TYPE_STDOUT:
+                    trace_parser->get_trace_config()->logger_factory = new StdoutLoggerFactory();
+                    break;
+                case OUTPUT_TYPE_SYSLOG:
+                    trace_parser->get_trace_config()->logger_factory = new SyslogLoggerFactory();
+                    break;
+                default:
+                    break;
+            }
 
-        trace_parser->finalize_constraints();
+            // "output=syslog" config override case
+            // do not closelog() here since it will be closed in Snort::clean_exit()
+            if ( !sc->log_syslog() and log_output_type == OUTPUT_TYPE_SYSLOG
+                and !local_syslog )
+            {
+                local_syslog = true;
+                openlog("snort", LOG_PID | LOG_CONS, LOG_DAEMON);
+            }
+
+            trace_parser->finalize_constraints();
+        }
 
         delete trace_parser;
         trace_parser = nullptr;