From: Russ Combs (rucombs) Date: Tue, 2 Apr 2019 02:08:25 +0000 (-0400) Subject: Merge pull request #1520 in SNORT/snort3 from ~RUCOMBS/snort3:so_rulez to master X-Git-Tag: 3.0.0-252~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=36dff7726076bb212a720c92b2c943125408cf8a;p=thirdparty%2Fsnort3.git Merge pull request #1520 in SNORT/snort3 from ~RUCOMBS/snort3:so_rulez to master Squashed commit of the following: commit f07cb92074a0874b6f64008dcafd3ba716de877a Author: russ Date: Sat Mar 30 14:03:48 2019 -0400 so rules: fixup shutdown sequencing commit 01db8beda055da0ac1f936d4252670cd185a6ec3 Author: russ Date: Sun Feb 17 13:06:34 2019 -0500 so rules: use stub strictly as a key commit 498dec668e51bdeaf9ddcb91767099f2e79b3ff8 Author: russ Date: Sat Feb 16 11:53:51 2019 -0500 so rules: make plain stubs same as protected --- diff --git a/src/main/snort_config.cc b/src/main/snort_config.cc index d632719c3..f1fd4a1e3 100644 --- a/src/main/snort_config.cc +++ b/src/main/snort_config.cc @@ -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); diff --git a/src/managers/so_manager.cc b/src/managers/so_manager.cc index 847ced4b6..5ee4ae5aa 100644 --- a/src/managers/so_manager.cc +++ b/src/managers/so_manager.cc @@ -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; diff --git a/src/managers/so_manager.h b/src/managers/so_manager.h index f05fdc8d0..03db28480 100644 --- a/src/managers/so_manager.h +++ b/src/managers/so_manager.h @@ -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*); diff --git a/src/parser/parse_rule.cc b/src/parser/parse_rule.cc index 5badae03e..91587bed1 100644 --- a/src/parser/parse_rule.cc +++ b/src/parser/parse_rule.cc @@ -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; } diff --git a/src/parser/parse_rule.h b/src/parser/parse_rule.h index 39be9052e..28023afdf 100644 --- a/src/parser/parse_rule.h +++ b/src/parser/parse_rule.h @@ -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(); diff --git a/src/parser/parse_so_rule.cc b/src/parser/parse_so_rule.cc index b7b7c55a8..8cf7a16c0 100644 --- a/src/parser/parse_so_rule.cc +++ b/src/parser/parse_so_rule.cc @@ -32,37 +32,18 @@ #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 stub_opts = { "classtype", "flowbits", "gid", "metadata", "msg", "priority", @@ -71,193 +52,199 @@ static std::set 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 diff --git a/src/parser/parse_so_rule.h b/src/parser/parse_so_rule.h index a44ece2df..432c02619 100644 --- a/src/parser/parse_so_rule.h +++ b/src/parser/parse_so_rule.h @@ -19,10 +19,21 @@ #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 -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 diff --git a/src/parser/parse_stream.cc b/src/parser/parse_stream.cc index 3c1a25dcf..ebf82e0c0 100644 --- a/src/parser/parse_stream.cc +++ b/src/parser/parse_stream.cc @@ -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;