]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1520 in SNORT/snort3 from ~RUCOMBS/snort3:so_rulez to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Tue, 2 Apr 2019 02:08:25 +0000 (22:08 -0400)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Tue, 2 Apr 2019 02:08:25 +0000 (22:08 -0400)
Squashed commit of the following:

commit f07cb92074a0874b6f64008dcafd3ba716de877a
Author: russ <rucombs@cisco.com>
Date:   Sat Mar 30 14:03:48 2019 -0400

    so rules: fixup shutdown sequencing

commit 01db8beda055da0ac1f936d4252670cd185a6ec3
Author: russ <rucombs@cisco.com>
Date:   Sun Feb 17 13:06:34 2019 -0500

    so rules: use stub strictly as a key

commit 498dec668e51bdeaf9ddcb91767099f2e79b3ff8
Author: russ <rucombs@cisco.com>
Date:   Sat Feb 16 11:53:51 2019 -0500

    so rules: make plain stubs same as protected

src/main/snort_config.cc
src/managers/so_manager.cc
src/managers/so_manager.h
src/parser/parse_rule.cc
src/parser/parse_rule.h
src/parser/parse_so_rule.cc
src/parser/parse_so_rule.h
src/parser/parse_stream.cc

index d632719c3f95ce777024bfc955403519c37c5fa9..f1fd4a1e3d4cd011e269cc1e28fe67b564f1ba15 100644 (file)
@@ -260,7 +260,6 @@ SnortConfig::~SnortConfig()
     }
 
     FreeRuleLists(this);
-    OtnLookupFree(otn_map);
     PortTablesFree(port_tables);
 
     ThresholdConfigFree(threshold_config);
@@ -271,6 +270,7 @@ SnortConfig::~SnortConfig()
         EventQueueConfigFree(event_queue_config);
 
     fpDeleteFastPacketDetection(this);
+    OtnLookupFree(otn_map);
 
     if (rtn_hash_table)
         xhash_delete(rtn_hash_table);
index 847ced4b629e4eb56b93c696000cf4b4fc64241d..5ee4ae5aa113fc442f627b03b968cfad1bf090b4 100644 (file)
@@ -194,7 +194,7 @@ static const SoApi* get_so_api(const char* soid)
     return nullptr;
 }
 
-const char* SoManager::get_so_options(const char* soid)
+const char* SoManager::get_so_rule(const char* soid)
 {
     const SoApi* api = get_so_api(soid);
 
@@ -203,17 +203,7 @@ const char* SoManager::get_so_options(const char* soid)
 
     const char* rule = revert(api->rule, api->length);
 
-    if ( !rule )
-        return nullptr;
-
-    static std::string opts;
-    opts.clear();
-
-    if ( !::get_so_options(rule, !api->length, opts) )
-        return nullptr;
-
-    opts += " )";
-    return opts.c_str();
+    return rule;
 }
 
 SoEvalFunc SoManager::get_so_eval(const char* soid, const char* so, void** data)
@@ -249,7 +239,7 @@ void SoManager::dump_rule_stubs(const char*)
 
         std::string stub;
 
-        if ( !get_so_stub(rule, !p->length, stub) )
+        if ( !get_so_stub(rule, stub) )
             continue;
 
         cout << stub << endl;
index f05fdc8d01a1dae74b6e74b90780ae1bd5b4b1d9..03db28480b5c49bb0cf91e316ace838626dcdfcd 100644 (file)
@@ -43,7 +43,7 @@ public:
     static void instantiate(const SoApi*);
 
     // soid is arg to soid option, so is arg to so option
-    static const char* get_so_options(const char* soid);
+    static const char* get_so_rule(const char* soid);
     static SoEvalFunc get_so_eval(const char* soid, const char* so, void** data);
     static void delete_so_data(const char* soid, void*);
 
index 5badae03e33b2763b5168d93d61d2042214054db..91587bed149ffcc297f3e99d2c3f4e2014a7d62b 100644 (file)
@@ -1138,34 +1138,42 @@ OptTreeNode* parse_rule_open(SnortConfig* sc, RuleTreeNode& rtn, bool stub)
     return otn;
 }
 
-// return nullptr if nothing left to do
-// for so rules, return the detection options and continue parsing
-// but if already entered, don't recurse again
-const char* parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* otn)
+void parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* otn)
 {
     if ( s_ignore )
     {
         s_ignore = false;
-        return nullptr;
+        return;
     }
 
     static bool entered = false;
-    const char* so_opts = nullptr;
 
     if ( entered )
         entered = false;
 
     else if ( otn->soid )
     {
-        so_opts = SoManager::get_so_options(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);
+
+        const char* rule = SoManager::get_so_rule(otn->soid);
+        IpsManager::reset_options();
 
-        if ( !so_opts )
+        if ( !rule )
             ParseError("SO rule %s not loaded.", otn->soid);
         else
         {
             entered = true;
-            return so_opts;
+            ParseConfigString(sc, rule);
         }
+        OtnFree(otn);
+        return;
     }
 
     /* The IPs in the test node get freed in ProcessHeadNode if there is
@@ -1186,7 +1194,7 @@ const char* parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* ot
         {
             /* We are keeping the old/dup OTN and trashing the new one
              * we just created - it's freed in the remove dup function */
-            return nullptr;
+            return;
         }
     }
     otn_count++;
@@ -1243,7 +1251,5 @@ const char* parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* ot
 
     // Clear ips_option vars
     ClearIpsOptionsVars();
-
-    return nullptr;
 }
 
index 39be9052eb76a3ce4db8e088c80c713eb877fdb7..28023afdf848dd2119467721cb0a9ef27c6e7150 100644 (file)
@@ -41,11 +41,11 @@ void parse_rule_nets(snort::SnortConfig*, const char*, bool src, RuleTreeNode&);
 void parse_rule_ports(snort::SnortConfig*, const char*, bool src, RuleTreeNode&);
 void parse_rule_dir(snort::SnortConfig*, const char*, RuleTreeNode&);
 void parse_rule_opt_begin(snort::SnortConfig*, const char* key);
-void parse_rule_opt_set(
-    snort::SnortConfig*, const char* key, const char* opt, const char* val);
+void parse_rule_opt_set(snort::SnortConfig*, const char* key, const char* opt, const char* val);
 void parse_rule_opt_end(snort::SnortConfig*, const char* key, OptTreeNode*);
+
 OptTreeNode* parse_rule_open(snort::SnortConfig*, RuleTreeNode&, bool stub = false);
-const char* parse_rule_close(snort::SnortConfig*, RuleTreeNode&, OptTreeNode*);
+void parse_rule_close(snort::SnortConfig*, RuleTreeNode&, OptTreeNode*);
 
 int get_rule_count();
 
index b7b7c55a8df398a65bd044d57ce89055d4baf531..8cf7a16c02358fbf2e18be221bcdf8ae85dcb1d6 100644 (file)
 #include "catch/snort_catch.h"
 #endif
 
-// must parse out stub options for --dump-dynamic-rules
-// must parse out detection options (ie everything else) after loading stub
-//
-// for plain so rules, all options are in stub
-// for protected rules, stub options depend on the use of UNORDERED_OPTS
-//
-// assume valid rule syntax
-// handles # and /* */ comments
-// return true if parsed rule body close
-// no requirement to beautify ugly rules
-
 class SoRuleParser
 {
 public:
-    SoRuleParser(bool p)
-    { is_plain = p; }
+    SoRuleParser() { }
 
     bool parse_so_rule(const char* in, std::string& stub, std::string& opts);
 
 private:
     bool is_stub_option(std::string& opt);
-
-private:
-    bool in_stub;
-    bool is_plain;
+    void trim(std::string&);
 };
 
-//#define UNORDERED_OPTS
-#ifdef UNORDERED_OPTS
-// these options are shown in so rule stubs
-// any other option is considered a detection option
 static std::set<std::string> stub_opts =
 {
     "classtype", "flowbits", "gid", "metadata", "msg", "priority",
@@ -71,193 +52,199 @@ static std::set<std::string> stub_opts =
 
 bool SoRuleParser::is_stub_option(std::string& opt)
 {
-    if ( is_plain )
-        return true;
-
     size_t n = opt.find_first_of(" :;");
     std::string name = opt.substr(0, n);
     return stub_opts.find(name) != stub_opts.end();
 }
-#else
-// all options up to and including soid are shown in so rule stubs
-// any options following soid are considered detection options
-// this approach requires Talos to reorder rule options so is not
-// viable long-term.
-bool SoRuleParser::is_stub_option(std::string& opt)
-{
-    if ( is_plain )
-        return true;
-
-    if ( !in_stub )
-        return false;
-
-    size_t n = opt.find_first_of(" :;");
-    std::string name = opt.substr(0, n);
-
-    if  ( name == "soid" )
-    {
-        in_stub = false;
-        return true;
-    }
-    return true;
-}
-#endif
 
 // split rule into stub and detection options
+//
+// the FSM deletes duplicate spaces between options except in these cases:
+// -- start of rule:  "^ alert"
+// -- middle of rule: ";      " (indent following # comment)
+// -- end of rule:    ";     )" (multiple detection opts)
+//
+// the trim method below cleans up the start/end of rule cases
+// FIXIT-L the middle of rule case should be handled by the FSM
+
 bool SoRuleParser::parse_so_rule(const char* in, std::string& stub, std::string& opts)
 {
-    in_stub = true;
-
-    int state = 0;
-    int next = 0;
+    unsigned state = 0;
+    unsigned next = 0;
 
-    bool del_sp = false;
+    char prev = '\0';
+    bool drop = false;
 
     std::string opt;
     std::string* accum = &stub;
 
     while ( *in )
     {
+        char c = *in;
+
         switch ( state )
         {
-        case 0:
-            if ( *in == '#' )
+        case 0:  // in rule header
+            if ( c == '#' )
             {
                 state = 1;
                 next = 0;
+                drop = true;
                 break;
             }
-            else if ( *in == '(' )
+            else if ( c == '(' )
                 state = 5;
-            else if ( *in == '/' )
+            else if ( c == '/' )
             {
                 state = 2;
                 next = 0;
+                drop = true;
             }
             break;
-        case 1:
-            if ( *in == '\n' )
+        case 1:  // in bash-style comment
+            if ( c == '\n' )
+            {
                 state = next;
+                drop = false;
+                c = ' ';
+            }
             break;
-        case 2:
-            if ( *in == '*' )
+        case 2:  // in C-style comment begin
+            if ( c == '*' )
                 state = 3;
             else
             {
+                *accum += '/';
                 state = next;
+                drop = false;
                 continue; // repeat
             }
             break;
-        case 3:
-            if ( *in == '*' )
+        case 3:  // in C-style comment
+            if ( c == '*' )
                 state = 4;
             break;
-        case 4:
-            if ( *in == '/' )
+        case 4:  // in C-style comment end
+            if ( c == '/' )
+            {
                 state = next;
+                drop = false;
+                c = ' ';
+            }
             else
                 state = 3;
             break;
-        case 5:
-            if ( del_sp )
-            {
-                if ( std::isspace(*in) )
-                {
-                    opts += *in++;
-                    continue;
-                }
-                else
-                    del_sp = false;
-            }
-            if ( *in == '#' )
+        case 5:  // in rule ( body )
+            if ( c == '#' )
             {
                 state = 1;
                 next = 5;
+                drop = true;
                 break;
             }
-            else if ( *in == '/' )
+            else if ( c == '/' )
             {
                 state = 2;
                 next = 5;
+                drop = true;
             }
-            else if ( *in == ')' )
+            else if ( c == ')' )
             {
-                *accum += *in;
+                *accum += c;
+                trim(stub);
                 return true;
             }
-            else if ( !std::isspace(*in) )
+            else if ( !std::isspace(c) )
             {
                 opt.clear();
                 accum = &opt;
                 state = 6;
             }
             break;
-        case 6:
-            if ( *in == '#' )
+        case 6:  // in rule option
+            if ( c == '#' )
             {
                 state = 1;
                 next = 6;
+                drop = true;
                 break;
             }
-            else if ( *in == '/' )
+            else if ( c == '/' )
             {
                 state = 2;
                 next = 6;
+                drop = true;
             }
-            else if ( *in == '"' )
+            else if ( c == '"' )
             {
                 state = 7;
             }
-            else if ( *in == ';' )
+            else if ( c == ';' )
             {
                 accum = &stub;
                 state = 5;
-                
+
                 if ( is_stub_option(opt) )
                     stub += opt;
                 else
                 {
                     opts += opt;
                     opts += *in++;
-                    del_sp = true;
                     continue;
                 }
             }
             break;
-        case 7:
-            if ( *in == '\\' )
+        case 7:  // in "string"
+            if ( c == '\\' )
                 state = 8;
-            else if ( *in == '"' )
+            else if ( c == '"' )
                 state = 6;
             break;
-        case 8:
+        case 8:  // in escape
             state = 7;
             break;
         }
-        *accum += *in++;
+        if ( state < 7 and c == '\n' )
+            c = ' ';
+
+        if ( (!drop and (!std::isspace(c) or !std::isspace(prev))) or (state >= 6) )
+        {
+            *accum += c;
+            if ( *accum == stub )
+                prev = c;
+        }
+        ++in;
     }
 
     return false;
 }
 
+void SoRuleParser::trim(std::string& stub)
+{
+    while ( std::isspace(stub[0]) )
+        stub.erase(0, 1);
+
+    size_t n = stub.rfind(';');
+
+    if ( n != std::string::npos and ++n < stub.length() and std::isspace(stub[n]) )
+    {
+        ++n;
+        while ( n < stub.length() and std::isspace(stub[n]) )
+            stub.erase(n, 1);
+    }
+}
+
 //--------------------------------------------------------------------------
 // public methods
 //--------------------------------------------------------------------------
 
-bool get_so_stub(const char* in, bool plain, std::string& stub)
+bool get_so_stub(const char* in, std::string& stub)
 {
-    SoRuleParser sop(plain);
+    SoRuleParser sop;
     std::string opts;
     return sop.parse_so_rule(in, stub, opts);
 }
 
-bool get_so_options(const char* in, bool plain, std::string& opts)
-{
-    SoRuleParser sop(plain);
-    std::string stub;
-    return sop.parse_so_rule(in, stub, opts);
-}
-
 //--------------------------------------------------------------------------
 // test data
 //--------------------------------------------------------------------------
@@ -272,40 +259,50 @@ struct TestCase
 
 static const TestCase syntax_tests[] =
 {
-    { "alert() ", "alert()", true },
+    { "alert()", "alert()", true },
+    { " alert() ", "alert()", true },
 
-    { "alert tcp any any -> any any ( )", 
-      "alert tcp any any -> any any ( )", true },
-
-    { "alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS ( )", 
-      "alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS ( )", true },
-
-    { "#alert()", "#alert()", false },
-    { "# \nalert()", "# \nalert()", true },
-    { "alert#\n()", "alert#\n()", true },
+    { "#alert()", "", false },
+    { "# \nalert()", "alert()", true },
+    { "alert#\n()", "alert ()", true },
     { "alert() # comment", "alert()", true },
-    { "alert(#\n)", "alert(#\n)", true },
-    { "alert(#)", "alert(#)", false },
+    { "alert(#\n)", "alert( )", true },
+    { "alert(#)", "alert(", false },
+    { "alert()#", "alert()", true },
 
-    { "/*alert()*/", "/*alert()*/", false },
+    { "/*alert()*/", " ", false },
     { "/ *alert()*/", "/ *alert()", true },
-    { "/* /alert()", "/* /alert()", false },
-    { "/* *alert()", "/* *alert()", false },
-    { "/*alert(*/)", "/*alert(*/)", false },
-    { "alert(/*)", "alert(/*)", false },
-    { "alert(/*)*/", "alert(/*)*/", false },
-    { "alert(/**)/", "alert(/**)/", false },
-    { "alert/*()*/", "alert/*()*/", false },
-    { "alert/*(*/)", "alert/*(*/)", false },
-
-    { "alert(/**/) ", "alert(/**/)", true },
-    { "alert(/* sid:1; */)", "alert(/* sid:1; */)", true },
+    { "/* /alert()", "", false },
+    { "/* *alert()", "", false },
+    { "/*alert(*/)", " )", false },
+    { "alert(/*)", "alert(", false },
+    { "alert(/*)*/", "alert( ", false },
+    { "alert(/**)/", "alert(", false },
+    { "alert/*()*/", "alert ", false },
+    { "alert/*(*/)", "alert )", false },
+
+    { "alert(/**/) ", "alert( )", true },
+    { "alert( /**/) ", "alert( )", true },
+    { "alert(/**/ ) ", "alert( )", true },
+    { "alert( /**/ ) ", "alert( )", true },
+    { "alert(/* comment */)", "alert( )", true },
+
+    { nullptr, nullptr, false }
+};
 
+static const TestCase basic_tests[] =
+{
     { "alert( sid:1; )", "alert( sid:1; )", true },
 
-    { "alert( sid:1 /*comment*/; )", "alert( sid:1 /*comment*/; )", true },
-    { "alert( sid:1 # comment\n; )", "alert( sid:1 # comment\n; )", true },
-    { "alert( sid:1; /*id:0;*/ )", "alert( sid:1; /*id:0;*/ )", true },
+    { "alert( sid:1 /*comment*/; )", "alert( sid:1  ; )", true },
+    { "alert( sid:1 # comment\n; )", "alert( sid:1  ; )", true },
+    { "alert( sid:1; /*id:0;*/ )", "alert( sid:1; )", true },
+
+    { "alert tcp any any -> any any ( )",
+      "alert tcp any any -> any any ( )", true },
+
+    { "alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS ( )",
+      "alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS ( )", true },
 
     { nullptr, nullptr, false }
 };
@@ -313,10 +310,9 @@ static const TestCase syntax_tests[] =
 // __STRDUMP_DISABLE__
 static const TestCase stub_tests[] =
 {
-#ifdef UNORDERED_OPTS
     { "alert( id:0; )", "alert( )", true },
     { "alert( sid:1; id:0; )", "alert( sid:1; )", true },
-    { "alert( sid:1;id:0; )", "alert( sid:1;)", true },
+    { "alert( sid:1;id:0; )", "alert( sid:1; )", true },
     { "alert( id:0;sid:1; )", "alert( sid:1; )", true },
 
     { "alert( id:/*comment*/0; )", "alert( )", true },
@@ -327,52 +323,12 @@ static const TestCase stub_tests[] =
     { R"_(alert( content:"f\"o"; ))_", "alert( )", true },
 
     { R"_(alert( soid; rem:"soid"; /*soid*/ ))_",
-      R"_(alert( soid; rem:"soid"; /*soid*/ ))_", true },
+      R"_(alert( soid; rem:"soid"; ))_", true },
 
-    { R"_(alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS ( msg:"MALWARE-CNC Win.Trojan.Hufysk variant outbound connection"; flow:to_server,established; http_uri; content:"/j.php|3F|u|3D|", fast_pattern,nocase; content:"&v=f2&r=",depth 8,offset 41,nocase; metadata:impact_flag red,policy balanced-ips drop,policy security-ips drop; service:http; reference:url,www.virustotal.com/file/bff436d8a2ccf1cdce56faabf341e97f59285435b5e73f952187bbfaf4df3396/analysis/; classtype:trojan-activity; sid:24062; rev:7; ))_", 
-      R"_(alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS ( msg:"MALWARE-CNC Win.Trojan.Hufysk variant outbound connection"; metadata:impact_flag red,policy balanced-ips drop,policy security-ips drop; service:http; reference:url,www.virustotal.com/file/bff436d8a2ccf1cdce56faabf341e97f59285435b5e73f952187bbfaf4df3396/analysis/; classtype:trojan-activity; sid:24062; rev:7; ))_", 
+    { R"_(alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS ( msg:"MALWARE-CNC Win.Trojan.Hufysk variant outbound connection"; flow:to_server,established; http_uri; content:"/j.php|3F|u|3D|", fast_pattern,nocase; content:"&v=f2&r=",depth 8,offset 41,nocase; metadata:impact_flag red,policy balanced-ips drop,policy security-ips drop; service:http; reference:url,www.virustotal.com/file/bff436d8a2ccf1cdce56faabf341e97f59285435b5e73f952187bbfaf4df3396/analysis/; classtype:trojan-activity; sid:24062; rev:7; ))_",
+      R"_(alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS ( msg:"MALWARE-CNC Win.Trojan.Hufysk variant outbound connection"; metadata:impact_flag red,policy balanced-ips drop,policy security-ips drop; service:http; reference:url,www.virustotal.com/file/bff436d8a2ccf1cdce56faabf341e97f59285435b5e73f952187bbfaf4df3396/analysis/; classtype:trojan-activity; sid:24062; rev:7; ))_",
       true },
 
-#else
-    { "alert( soid; id:0; )", "alert( soid; )", true },
-    { "alert( sid:1; soid; id:0; )", "alert( sid:1; soid; )", true },
-    { "alert( sid:1;soid;id:0; )", "alert( sid:1;soid;)", true },
-    { "alert( soid;id:0;sid:1; )", "alert( soid;)", true },
-
-    { "alert( soid; id:/*comment*/0; )", "alert( soid; )", true },
-    { "alert( soid; id: #comment\n0; )", "alert( soid; )", true },
-
-    { R"_(alert( soid; content:"foo"; ))_", "alert( soid; )", true },
-    { R"_(alert( soid; content:"f;o"; ))_", "alert( soid; )", true },
-    { R"_(alert( soid; content:"f\"o"; ))_", "alert( soid; )", true },
-
-    { R"_(alert( rem:"soid"; /*soid*/ soid; ))_",
-      R"_(alert( rem:"soid"; /*soid*/ soid; ))_", true },
-
-    { R"_(alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS ( msg:"MALWARE-CNC Win.Trojan.Hufysk variant outbound connection"; soid:a; flow:to_server,established; http_uri; content:"/j.php|3F|u|3D|", fast_pattern,nocase; content:"&v=f2&r=",depth 8,offset 41,nocase; metadata:impact_flag red,policy balanced-ips drop,policy security-ips drop; service:http; reference:url,www.virustotal.com/file/bff436d8a2ccf1cdce56faabf341e97f59285435b5e73f952187bbfaf4df3396/analysis/; classtype:trojan-activity; sid:24062; rev:7; ))_", 
-      R"_(alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS ( msg:"MALWARE-CNC Win.Trojan.Hufysk variant outbound connection"; soid:a; ))_", 
-      true },
-
-#endif
-    { nullptr, nullptr, false }
-};
-
-static const TestCase opts_tests[] =
-{
-#ifdef UNORDERED_OPTS
-    { R"_(alert( soid; rem:"soid"; /*soid*/ ))_", R"_(alert( /*soid*/ ))_", true },
-
-    { R"_(alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS ( msg:"MALWARE-CNC Win.Trojan.Hufysk variant outbound connection"; flow:to_server,established; http_uri; content:"/j.php|3F|u|3D|", fast_pattern,nocase; content:"&v=f2&r=",depth 8,offset 41,nocase; metadata:impact_flag red,policy balanced-ips drop,policy security-ips drop; service:http; reference:url,www.virustotal.com/file/bff436d8a2ccf1cdce56faabf341e97f59285435b5e73f952187bbfaf4df3396/analysis/; classtype:trojan-activity; sid:24062; rev:7; ))_", 
-      R"_(flow:to_server,established; http_uri; content:"/j.php|3F|u|3D|", fast_pattern,nocase; content:"&v=f2&r=",depth 8,offset 41,nocase; )_", 
-      true },
-
-#else
-    { R"_(alert( rem:"soid"; /*soid*/ soid; ))_", "", true },
-
-    { R"_(alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS ( msg:"MALWARE-CNC Win.Trojan.Hufysk variant outbound connection"; metadata:impact_flag red,policy balanced-ips drop,policy security-ips drop; service:http; reference:url,www.virustotal.com/file/bff436d8a2ccf1cdce56faabf341e97f59285435b5e73f952187bbfaf4df3396/analysis/; classtype:trojan-activity; sid:24062; rev:7; soid:3_24062_7; flow:to_server,established; http_uri; content:"/j.php|3F|u|3D|", fast_pattern,nocase; content:"&v=f2&r=",depth 8,offset 41,nocase; ))_", 
-      R"_(flow:to_server,established; http_uri; content:"/j.php|3F|u|3D|", fast_pattern,nocase; content:"&v=f2&r=",depth 8,offset 41,nocase; )_", 
-      true },
-#endif
     { nullptr, nullptr, false }
 };
 // __STRDUMP_ENABLE__
@@ -381,76 +337,51 @@ static const TestCase opts_tests[] =
 // unit tests
 //--------------------------------------------------------------------------
 
-TEST_CASE("parse_so_rule", "[parser]")
+TEST_CASE("parse_so_rule.syntax", "[parser]")
 {
     const TestCase* tc = syntax_tests;
 
     while ( tc->rule )
     {
-        SoRuleParser sop(false);
+        SoRuleParser sop;
         std::string stub;
         std::string opts;
         bool parse = sop.parse_so_rule(tc->rule, stub, opts);
-        CHECK(parse == tc->result);
-        CHECK(stub == tc->expect);
+        CHECK(tc->result == parse);
+        CHECK(tc->expect == stub);
         ++tc;
     }
 }
 
-TEST_CASE("get_so_stub protected", "[parser]")
+TEST_CASE("parse_so_rule.basic", "[parser]")
 {
-    const TestCase* tc = stub_tests;
+    const TestCase* tc = basic_tests;
 
     while ( tc->rule )
     {
+        SoRuleParser sop;
         std::string stub;
-        bool get = get_so_stub(tc->rule, false, stub);
-        CHECK(get == tc->result);
-        CHECK(stub == tc->expect);
-        ++tc;
-    }
-}
-
-TEST_CASE("get_so_options protected", "[parser]")
-{
-    const TestCase* tc = opts_tests;
-
-    while ( tc->rule )
-    {
         std::string opts;
-        bool get = get_so_options(tc->rule, false, opts);
-        CHECK(get == tc->result);
-        CHECK(opts == tc->expect);
+        bool parse = sop.parse_so_rule(tc->rule, stub, opts);
+        CHECK(tc->result == parse);
+        CHECK(tc->expect == stub);
         ++tc;
     }
 }
 
-TEST_CASE("get_so_stub plain", "[parser]")
+TEST_CASE("get_so_stub", "[parser]")
 {
     const TestCase* tc = stub_tests;
 
     while ( tc->rule )
     {
         std::string stub;
-        bool get = get_so_stub(tc->rule, true, stub);
-        CHECK(get == tc->result);
-        CHECK(stub == tc->rule);
+        bool get = get_so_stub(tc->rule, stub);
+        CHECK(tc->result == get);
+        CHECK(tc->expect == stub);
         ++tc;
     }
 }
 
-TEST_CASE("get_so_options plain", "[parser]")
-{
-    const TestCase* tc = opts_tests;
-
-    while ( tc->rule )
-    {
-        std::string opts;
-        bool get = get_so_options(tc->rule, true, opts);
-        CHECK(get == tc->result);
-        CHECK(opts == "");
-        ++tc;
-    }
-}
 #endif
 
index a44ece2dfd7ab19be2ccf4c929ba9113ec7952eb..432c0261905e5a8a1c1cc45c17b10aed6d1ae6eb 100644 (file)
 #ifndef PARSE_SO_RULE_H
 #define PARSE_SO_RULE_H
 
+// must parse out stub options for --dump-dynamic-rules
+//
+// only selected options are shown in so rule stubs
+// all other options are stripped out of the stub
+//
+// assumes valid rule syntax
+// deletes all # comments
+// replaces each /* comment */ with a single space
+// replaces each newline with a single space
+// deletes more than one space between options
+// return true if parsed rule body close
+
 #include <string>
 
-bool get_so_stub(const char* in, bool plain, std::string& opts);
-bool get_so_options(const char* in, bool plain, std::string& opts);
+bool get_so_stub(const char* in, std::string& stub);
 
 #endif
 
index 3c1a25dcfa57e61904ffe1f09c73f4de927928c6..ebf82e0c01c3d3696372253593f6b0f7d6173be6 100644 (file)
@@ -485,8 +485,6 @@ struct RuleParseState
     { otn = nullptr; }
 };
 
-static void parse_body(const char*, RuleParseState&, struct snort::SnortConfig*);
-
 static bool exec(
     FsmAction act, string& tok,
     RuleParseState& rps, snort::SnortConfig* sc)
@@ -543,16 +541,9 @@ static bool exec(
         if ( rps.tbd )
             exec(FSM_END, tok, rps, sc);
 
-        if ( const char* extra = parse_rule_close(sc, rps.rtn, rps.otn) )
-        {
-            IpsManager::reset_options();
-            parse_body(extra, rps, sc);
-        }
-        else
-        {
-            rps.otn = nullptr;
-            rules++;
-        }
+        parse_rule_close(sc, rps.rtn, rps.otn);
+        rps.otn = nullptr;
+        rules++;
         break;
     }
     case FSM_KEY:
@@ -624,39 +615,6 @@ static int get_escape(const string& s)
     return 1;      // escape, option goes to "
 }
 
-// parse_body() is called at the end of a stub rule to parse the detection
-// options in an so rule.  similar to parse_stream() except we start in a
-// different state.
-static void parse_body(const char* extra, RuleParseState& rps, snort::SnortConfig* sc)
-{
-    stringstream is(extra);
-
-    string tok;
-    TokenType type;
-    int esc = 1;
-
-    int num = 8;
-    const char* punct = "(:,;)";
-
-    while ( (type = get_token(is, tok, punct, esc)) )
-    {
-        ++tokens;
-        const State* s = get_state(num, type, tok);
-
-#ifdef TRACER
-        printf("%d: %s = '%s' -> %s\n",
-            num, toks[type], tok.c_str(), acts[s->action]);
-#endif
-        exec(s->action, tok, rps, sc);
-
-        num = s->next;
-        esc = get_escape(rps.key);
-
-        if ( s->punct )
-            punct = s->punct;
-    }
-}
-
 void parse_stream(istream& is, snort::SnortConfig* sc)
 {
     string tok;