]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
adding support for 'ruletype' keyword and its associated rules
authorJosh <jrosenba@cisco.com>
Tue, 2 Dec 2014 15:24:05 +0000 (09:24 -0600)
committerJosh <jrosenba@cisco.com>
Tue, 2 Dec 2014 15:29:52 +0000 (09:29 -0600)
12 files changed:
doc/snort2lua.txt
tools/snort2lua/helpers/converter.cc
tools/snort2lua/helpers/converter.h
tools/snort2lua/helpers/s2l_util.cc
tools/snort2lua/helpers/s2l_util.h
tools/snort2lua/init_state.cc
tools/snort2lua/keyword_states/CMakeLists.txt
tools/snort2lua/keyword_states/Makefile.am
tools/snort2lua/keyword_states/keywords_api.cc
tools/snort2lua/keyword_states/keywords_api.h
tools/snort2lua/keyword_states/kws_ruletype.cc
tools/snort2lua/tests/snort.conf.in

index 20aaf81891c2435732343c1e9d8a72aeeb853a2a..7e606ec61a759dafa61c4f8e1db4240fa801f6f0 100644 (file)
@@ -57,7 +57,6 @@ output a valid Snort++ configuration.  Instead, you can see the exact
 options from the input configuration that have changed.
 
 
-// FIXIT-J L include Snort2Lua commands
 :leveloffset: 1
 include::snort2lua_cmds.txt[]
 :leveloffset: 0
@@ -79,3 +78,7 @@ configuration will automatically be combined into the same file.  Also, the
 new files name will automatically become the old file’s name with a .lua
 extension.  There is currently no way to specify or change that files name.
 
+*  If a rule's action is a custom ruletype, that rule will silently be
+converted to the rultype's 'type'. No warnings or errors are currently
+emmitted. Additionally, the custom ruletypes outputs will be silently
+discarded.
index 50da443f9b84fdc20cbbcc6bf7e916b6dd7e30e4..d36c7d5309999ba24120d243918cf1364c85a0f3 100644 (file)
@@ -35,7 +35,8 @@ bool Converter::convert_conf_mult_files = true;
 
 Converter::Converter()
     :   state(nullptr),
-        error(false)
+        error(false),
+        multiline_state(false)
 {
 }
 
@@ -212,7 +213,9 @@ int Converter::parse_file(std::string input_file)
             }
 
             orig_text.clear();
-            reset_state();
+
+            if ( !multiline_state )
+                reset_state();
         }
     }
 
index 57f300842db11d787ee3a1b1f5e7a24dd2e445c3..30015fe8ed6313f4591e5f4546969ca3539ee00f 100644 (file)
@@ -45,6 +45,7 @@ public:
     // tells this class whether to convert a file inline or pull all data into one file.
     inline static void create_mult_rule_files(bool var)
     { convert_rules_mult_files = var; }
+
     inline static bool include_create_rule()
     { return convert_rules_mult_files; }
 
@@ -76,6 +77,12 @@ public:
     { return data_api.failed_conversions() || rule_api.failed_conversions(); }
 
 
+    inline void start_multiline_parsing()
+    { multiline_state = true; }
+
+    inline void end_multiline_parsing()
+    { multiline_state = false; }
+
     inline DataApi& get_data_api()
     { return data_api; }
 
@@ -98,6 +105,7 @@ private:
     // the current parsing state.
     ConversionState* state;
     bool error;
+    bool multiline_state;
 
 
     // initialize data class
index 1d0a0d1d36f672f050cc8131431e05f237b0de58..339f25a3d15c5c1db4559ccf096ff9869cd2cbae 100644 (file)
@@ -53,7 +53,9 @@ std::vector<std::string> &split(const std::string &s,
     return elems;
 }
 
-const ConvertMap* find_map(const std::vector<const ConvertMap*> map, std::string keyword)
+const ConvertMap* find_map(
+    const std::vector<const ConvertMap*>& map,
+    const std::string& keyword)
 {
     for (const ConvertMap *p : map)
         if (p->keyword.compare(0, p->keyword.size(), keyword) == 0)
@@ -62,7 +64,20 @@ const ConvertMap* find_map(const std::vector<const ConvertMap*> map, std::string
     return nullptr;
 }
 
-Table* find_table(std::vector<Table*> vec, std::string name)
+const std::unique_ptr<const ConvertMap>& find_map(
+    const std::vector<std::unique_ptr<const ConvertMap> >& map,
+    const std::string& keyword)
+{
+    for (auto& p : map)
+        if (p->keyword.compare(0, p->keyword.size(), keyword) == 0)
+            return p;
+
+    static std::unique_ptr<const ConvertMap> np(nullptr);
+    return np;
+}
+
+
+Table* find_table(const std::vector<Table*>& vec, const std::string& name)
 {
     if(name.empty())
         return nullptr;
index 693e9c3dfaea109c9aae819334760fa7a01aaa58..7b9dc3521a15dbb2ea57907b448b712d26fe14a7 100644 (file)
@@ -29,6 +29,7 @@
 #include <cctype>
 #include <locale>
 #include <sstream>
+#include <memory>
 
 struct ConvertMap;
 class Table;
@@ -39,8 +40,11 @@ namespace util
 std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems);
 
 // Search through the vector for the map which matches keyword
-const ConvertMap* find_map(const std::vector<const ConvertMap*>, std::string keyword);
-Table* find_table(std::vector<Table*> vec, std::string name);
+
+Table* find_table(const std::vector<Table*>& vec, const std::string& name);
+const ConvertMap* find_map(const std::vector<const ConvertMap*>&, const std::string& keyword);
+const std::unique_ptr<const ConvertMap>& find_map(
+    const std::vector<std::unique_ptr<const ConvertMap> >&, const std::string& keyword);
 
 // trim from begining
 std::string &ltrim(std::string &s);
index f0c1b68d4465420a2e890c677e5886ec2d863820..ffc823d8a0756de9d1d3699e8427843386952193 100644 (file)
@@ -44,6 +44,14 @@ bool InitState::convert(std::istringstream& data_stream)
             return true;
         }
 
+        const std::unique_ptr<const ConvertMap>& ruletype =
+            util::find_map(keywords::ruletype_api, keyword);
+        if ( ruletype != nullptr )
+        {
+            cv.set_state(ruletype->ctor(cv));
+            return true;
+        }
+
         data_api.failed_conversion(data_stream, keyword);
     }
     else
index 02b110e0cd07f377b9d22b1917340d5f906c120e..27c715c83a92063957f655fb77398a48fcd95a4a 100644 (file)
@@ -8,9 +8,10 @@ add_library( keyword_states
     kws_output.cc
     kws_paths.cc
     kws_preprocessor.cc
+    kws_rate_filter.cc
     kws_rule.cc
     kws_rule_state.cc
-    kws_rate_filter.cc
+    kws_ruletype.cc
     kws_var.cc
     kws_suppress.cc
     keywords_api.h
index e748ea4c10d44c543ba90d6e2aa8b8b0aeadf42a..a5e823888461e4c634adc7beebf1e9b64e1bbf23 100644 (file)
@@ -14,6 +14,7 @@ kws_paths.cc \
 kws_preprocessor.cc \
 kws_rule.cc \
 kws_rule_state.cc \
+kws_ruletype.cc \
 kws_rate_filter.cc \
 kws_var.cc \
 kws_suppress.cc \
index abd86f20ad319ea5a8b1545e2b4ee2be9792dae5..d4983f3be5cd38b1f3db37373771f72f44043c96 100644 (file)
@@ -47,6 +47,7 @@ extern const ConvertMap* preprocessor_map;
 extern const ConvertMap* rate_filter_map;
 extern const ConvertMap* reject_map;
 extern const ConvertMap* rule_state_map;
+extern const ConvertMap* ruletype_map;
 extern const ConvertMap* sblock_map;
 extern const ConvertMap* sdrop_map;
 extern const ConvertMap* suppress_map;
@@ -79,6 +80,7 @@ const std::vector<const ConvertMap*> keywords_api =
     rate_filter_map,
     reject_map,
     rule_state_map,
+    ruletype_map,
     sblock_map,
     sdrop_map,
     suppress_map,
index 298d0130d2098f21ef3b2dcfcddf916f02eb690a..1776e36241f4668fc0454067bc71d5fe4513829f 100644 (file)
@@ -22,6 +22,7 @@
 #define KEYWORD_STATES_KEYWORDS_API_H
 
 #include <vector>
+#include <memory>
 #include "conversion_defines.h"
 
 
@@ -30,6 +31,9 @@ namespace keywords
 
 extern const std::vector<const ConvertMap*> keywords_api;
 
+// instantiated in kws_ruletype.cc
+extern const std::vector<std::unique_ptr<const ConvertMap> > ruletype_api;
+
 
 }  // namespace keywords
 
index 04f8d9902d901d5ac1ea6f11233583c4c4c6ad13..122a9c60b2727c931d061185a0c62a556408cdab 100644 (file)
 #include "conversion_state.h"
 #include "helpers/converter.h"
 #include "config_states/config_api.h"
+#include "keyword_states/keywords_api.h"
 
 
 namespace keywords
 {
 
+const std::vector<std::unique_ptr<const ConvertMap> > ruletype_api;
+
 namespace {
 
+enum class ParseState
+{
+    NAME,
+    OPEN_BRACKET,
+    TYPE_KEYWORD,
+    TYPE_NAME,
+    OUTPUT_OR_BRACKET,
+    OUTPUT_ARGS
+};
+
 class RuleType : public ConversionState
 {
 public:
-    RuleType(Converter& c) : ConversionState(c) {};
+    RuleType(Converter& c) : ConversionState(c),
+                             state(ParseState::NAME),
+                             entire_line("ruletype")
+    {}
+
     virtual ~RuleType() {};
     virtual bool convert(std::istringstream& data);
+
+private:
+    ParseState state;
+    std::string name;
+    std::string type;
+    std::string entire_line;
 };
 
 } // namespace
 
 
-bool RuleType::convert(std::istringstream& data_stream)
+bool RuleType::convert(std::istringstream& stream)
 {
-    std::string keyword;
-#if 0
-    if(data_stream >> keyword)
-    {
+    std::string val;
 
-        if(keyword.back() == ':')
-            keyword.pop_back();
+    if ( !entire_line.empty() )
+        entire_line += "\n";
 
-        const ConvertMap* map = util::find_map(rules::rule_api, keyword);
-        if (map)
+    while ( stream >> val)
+    {
+        entire_line += " " + val;
+
+        switch (state)
         {
-            cv.set_state(map->ctor());
-            return true;
-        }
+        case ParseState::NAME:
+            cv.start_multiline_parsing();
+            name = val;
+            state = ParseState::OPEN_BRACKET;
+            break;
+
+        case ParseState::OPEN_BRACKET:
+            if ( val.compare("{") )
+            {
+                std::istringstream tmp(entire_line);
+                data_api.failed_conversion(tmp, val);
+                return false;   
+            }
+            state = ParseState::TYPE_KEYWORD;
+            break;
+
+        case ParseState::TYPE_KEYWORD:
+            if ( val.compare("type") )
+            {
+                std::istringstream tmp(entire_line);
+                data_api.failed_conversion(tmp, val);
+                return false;   
+            }
+            state = ParseState::TYPE_NAME;
+            break;
+
+        case ParseState::TYPE_NAME:
+            type = val;
+            state = ParseState::OUTPUT_OR_BRACKET;
+            break;
+
+        case ParseState::OUTPUT_OR_BRACKET:
+            if ( !val.compare("}") )
+            {
+                cv.end_multiline_parsing();
+
+                if ( util::find_map(ruletype_api, name) != nullptr )
+                {
+                    std::istringstream tmp(entire_line);
+                    data_api.failed_conversion(tmp, name + " -- defined multiple times in configuration file");
+                    return false;
+                }
+
+                const ConvertMap* map = util::find_map(keywords_api, type);
+
+                if (map)
+                {
+
+                    // using smart pointer to gaurantee new Map is deleted
+                    const std::vector<std::unique_ptr<const ConvertMap> >& ruletype_map = ruletype_api;
+                    std::unique_ptr<ConvertMap> new_map(new ConvertMap());
+                    new_map->keyword = name;
+                    new_map->ctor = map->ctor;
+                    const_cast<std::vector<std::unique_ptr<const ConvertMap> >&>(
+                        ruletype_map).push_back(std::move(new_map));
+                    return true;
+                }
+                else
+                {
+                    std::istringstream tmp(entire_line);
+                    data_api.failed_conversion(tmp, "type " + type);
+                    return false;
+                }
+            }
+            else if (!val.compare("output") )
+            {
+                state = ParseState::OUTPUT_ARGS;
+            }
+            else
+            {
+                std::istringstream tmp(entire_line);
+                data_api.failed_conversion(tmp, "type " + type);
+                return false;
+            }
+
+            break;
+
+        case ParseState::OUTPUT_ARGS:
+            // eat this argument.  Do nothing.
+            break;
+        }   
     }
-#endif
-    return false;
+
+
+    // OUTPUT_ARGS ate up the rest of the line.
+    // Now, start a new line.
+    if ( state == ParseState::OUTPUT_ARGS )
+        state = ParseState::OUTPUT_OR_BRACKET;
+
+    else if ( state == ParseState::TYPE_NAME )
+        return false;
+
+    return true;
 }
 
 /**************************
@@ -68,7 +178,7 @@ bool RuleType::convert(std::istringstream& data_stream)
  **************************/
 
 static ConversionState* ctor(Converter& c)
-{ return new RuleType(); }
+{ return new RuleType(c); }
 
 static const ConvertMap keyword_ruletype = 
 {
index b44ddb37746bdb5440b56ae4f1964ac69b4d1b01..2a64e114b8c113acde9814b23e9a1116f0cfda70 100644 (file)
@@ -1335,3 +1335,24 @@ alert ip any any -> any any (msg:"TTL RULE OPTION"; ttl:5-6; sid:11111113;)
 alert ip any any -> any any (msg:"TTL RULE OPTION"; ttl:7-; sid:11111114;)
 
 alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (content:"fe, fe, fe, fe, fe, fe, fe,"; msg:"BROWSER-FIREFOX Mozilla Firefox Javascript engine function arguments memory corruption attempt"; flow:to_client,established; file_data; content:"|3B|i<25|3B|i++|29| fe += fe|3B|"; fast_pattern:only; content:"fu=new Function|28 0A|"; content:"fe, fe, fe, fe, fe, fe, fe,"; within:30; metadata:policy balanced-ips drop, policy security-ips drop, service http; reference:bugtraq,19181; reference:cve,2006-3806; classtype:attempted-user; sid:18262; rev:3;)
+
+
+ruletype suspicious
+{
+    type log
+}
+ruletype suspicious1
+{
+    type log
+    output log_tcpdump: suspicious.log
+}
+ruletype suspicious2
+{
+    type log
+    output log_tcpdump: suspicious.log
+    output unified2: filename merged.log
+}
+
+suspicious tcp any any -> any any (msg:"SUSPICIOUS ruletype"; sid:11111115;)
+suspicious1 tcp any any -> any any (msg:"SUSPICIOUS ruletype"; sid:11111116;)
+suspicious2 tcp any any -> any any (msg:"SUSPICIOUS ruletype"; sid:111111167;)
\ No newline at end of file