From: Michael Altizer (mialtize) Date: Fri, 18 Aug 2017 20:47:49 +0000 (-0400) Subject: Merge pull request #991 in SNORT/snort3 from binder_order to master X-Git-Tag: 3.0.0-240~62 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2be138622209b360eff2bd71b059e1d6bdf140ef;p=thirdparty%2Fsnort3.git Merge pull request #991 in SNORT/snort3 from binder_order to master Squashed commit of the following: commit 0a44cace2f0cb9798caf59a9f6aba64f21c73de3 Author: Carter Waxman Date: Mon Aug 14 12:19:28 2017 -0400 snort2lua: enforced ordering to bindings in binder table commit 4d9a66aefe11ea13f20d2468fccfd140cb18df09 Author: Carter Waxman Date: Thu Aug 10 17:56:35 2017 -0400 snort2lua: removed dead code --- diff --git a/tools/snort2lua/helpers/converter.cc b/tools/snort2lua/helpers/converter.cc index a8de1ce55..2c25b8638 100644 --- a/tools/snort2lua/helpers/converter.cc +++ b/tools/snort2lua/helpers/converter.cc @@ -17,6 +17,7 @@ //-------------------------------------------------------------------------- // converter.cc author Josh Rosenbaum +#include #include #include "helpers/converter.h" @@ -258,13 +259,13 @@ bool Converter::initialize() Binder& Converter::make_binder(Binder& b) { - binders.push_back(std::unique_ptr(new Binder(b))); + binders.push_back(std::shared_ptr(new Binder(b))); return *binders.back(); } Binder& Converter::make_binder() { - binders.push_back(std::unique_ptr(new Binder(table_api))); + binders.push_back(std::shared_ptr(new Binder(table_api))); return *binders.back(); } @@ -280,6 +281,7 @@ int Converter::convert(std::string input, // vector::clear()'s ordering isn't deterministic but this is // keep in place for stable regressions + std::stable_sort(binders.rbegin(), binders.rend()); while ( binders.size() ) binders.pop_back(); diff --git a/tools/snort2lua/helpers/converter.h b/tools/snort2lua/helpers/converter.h index 489e5a72b..19fecca1c 100644 --- a/tools/snort2lua/helpers/converter.h +++ b/tools/snort2lua/helpers/converter.h @@ -103,7 +103,7 @@ private: DataApi data_api; TableApi table_api; RuleApi rule_api; - std::vector> binders; + std::vector> binders; // the current parsing state. ConversionState* state; diff --git a/tools/snort2lua/helpers/parse_cmd_line.cc b/tools/snort2lua/helpers/parse_cmd_line.cc index 373696984..216c47fb2 100644 --- a/tools/snort2lua/helpers/parse_cmd_line.cc +++ b/tools/snort2lua/helpers/parse_cmd_line.cc @@ -31,6 +31,7 @@ #include "helpers/converter.h" #include "helpers/s2l_util.h" #include "helpers/s2l_markup.h" +#include "helpers/util_binder.h" namespace parser { @@ -281,6 +282,12 @@ static void print_version(const char* /*key*/, const char* /*val*/) std::cout << "Snort2Lua\t0.2.0"; } +static void print_binder_order(const char* /*key*/, const char* /*val*/) +{ + print_binder_priorities(); + exit(0); +} + static void help(const char* key, const char* val) { std::cout << Markup::head(3) << "Usage: snort2lua [OPTIONS]... -c ...\n"; @@ -386,6 +393,11 @@ static ConfigFunc basic_opts[] = { "print-all", print_all, "", "Same as '-a'. default option. print all data" }, +#ifdef REG_TEST + { "print-binding-order", print_binder_order, "" + "Print sorting priority used when generating binder table" }, +#endif + { "print-differences", print_differences, "", "Same as '-d'. output the differences, and only the differences, " "between the Snort and Snort++ configurations to the " }, diff --git a/tools/snort2lua/helpers/util_binder.cc b/tools/snort2lua/helpers/util_binder.cc index 1973832e4..56d087fd6 100644 --- a/tools/snort2lua/helpers/util_binder.cc +++ b/tools/snort2lua/helpers/util_binder.cc @@ -17,9 +17,13 @@ //-------------------------------------------------------------------------- // pps_binder.cc author Josh Rosenbaum +#include + #include "helpers/util_binder.h" #include "data/dt_table_api.h" +using namespace std; + Binder::Binder(TableApi& t) : table_api(t), printed(false), when_policy_id(-1) @@ -27,7 +31,7 @@ Binder::Binder(TableApi& t) : table_api(t), Binder::~Binder() { - if (!printed) + if ( !printed ) add_to_configuration(); } @@ -39,26 +43,26 @@ void Binder::add_to_configuration() table_api.open_table("when", true); - if (when_policy_id >= 0) + if ( has_policy_id() ) table_api.add_option("policy_id", when_policy_id); - if (!when_service.empty()) - table_api.add_option("service", when_service); + for ( auto s : vlans ) + table_api.add_list("vlans", s); - if (!when_proto.empty()) - table_api.add_option("proto", when_proto); + if ( has_service() ) + table_api.add_option("service", when_service); - if (!when_role.empty() && when_role != "any") - table_api.add_option("role", when_role); + for ( auto n : nets ) + table_api.add_list("nets", n); - for (auto p : ports) + for ( auto p : ports ) table_api.add_list("ports", p); - for (auto s : vlans) - table_api.add_list("vlans", s); + if ( has_proto() ) + table_api.add_option("proto", when_proto); - for (auto n : nets) - table_api.add_list("nets", n); + if ( has_role() ) + table_api.add_option("role", when_role); table_api.close_table(); // "when" @@ -130,3 +134,139 @@ void Binder::set_use_action(std::string action) void Binder::set_use_policy_id(std::string id) { use_policy_id = std::string(id); } +/* This operator is provided for STL compatible sorting. A Binder is considered + less than another Binder if it should be printed first in the binder table, + thus giving it higher priority. This is determined by checking for presence + of when options and assigning them priority. If multiple options exist, + the highest-priority non-match is used to determine order. + + Example of ordering: + policy_id vlan net + policy_id vlan + policy_id net + policy_id + vlan net + vlan + net + +*/ +bool operator<(const shared_ptr left, const shared_ptr right) +{ + #define TRISTATE(v) \ + { \ + if ( (v) < 0 ) return true; \ + if ( (v) > 0 ) return false; \ + } + + #define FIRST_IF_LT(left, right) \ + { \ + if ( (left) < (right) ) return true; \ + if ( (left) > (right) ) return false; \ + } + + #define FIRST_IF_GT(left, right) \ + { \ + if ( (left) < (right) ) return false; \ + if ( (left) > (right) ) return true; \ + } + + //By priorities of options + FIRST_IF_GT(left->has_policy_id(), right->has_policy_id()) + FIRST_IF_GT(left->has_vlans(), right->has_vlans()) + FIRST_IF_GT(left->has_service(), right->has_service()) + FIRST_IF_GT(left->has_nets(), right->has_nets()) + FIRST_IF_GT(left->has_ports(), right->has_ports()) + FIRST_IF_GT(left->has_proto(), right->has_proto()) + FIRST_IF_GT(left->has_role(), right->has_role()) + + //By values of options. Fewer specs = more specific. + if ( left->has_vlans() && right->has_vlans() ) + FIRST_IF_LT(left->vlans.size(), right->vlans.size()) + + if ( left->has_nets() && right->has_nets() ) + FIRST_IF_LT(left->nets.size(), right->nets.size()) + + if ( left->has_ports() && right->has_ports() ) + FIRST_IF_LT(left->ports.size(), right->ports.size()) + + //Sorted by value for readability if all else is equal + if ( left->has_policy_id() && right->has_policy_id() ) + FIRST_IF_LT(left->when_policy_id, right->when_policy_id) + + if ( left->has_service() && right->has_service() ) + TRISTATE(left->when_service.compare(right->when_service)) + + if ( left->has_proto() && right->has_proto() ) + TRISTATE(left->when_proto.compare(right->when_proto)) + + if ( left->has_role() && right->has_role() ) + TRISTATE(left->when_role.compare(right->when_role)) + + return false; //if here, l == r +} + +#ifdef REG_TEST +#include + +void print_binder_priorities() +{ + static unsigned const num_combos = 2 * 2 * 2 * 2 * 2 * 2 * 2; + vector> binders; + TableApi t; + + for ( unsigned i = 0; i < num_combos; i++ ) + { + binders.push_back(shared_ptr(new Binder(t))); + binders.back()->print_binding(false); + + if ( i & (1 << 0) ) + binders.back()->set_when_policy_id(1); + + if ( i & (1 << 1) ) + binders.back()->add_when_vlan("a"); + + if ( i & (1 << 2) ) + binders.back()->set_when_service("a"); + + if ( i & (1 << 3) ) + binders.back()->add_when_net("a"); + + if ( i & (1 << 4) ) + binders.back()->add_when_port("a"); + + if ( i & (1 << 5) ) + binders.back()->set_when_proto("a"); + + if ( i & (1 << 6) ) + binders.back()->set_when_role("a"); + } + + sort(binders.begin(), binders.end()); + + for ( auto& b : binders ) + { + if ( b->has_policy_id() ) + cout << "policy_id "; + + if ( b->has_vlans() ) + cout << "vlan "; + + if ( b->has_service() ) + cout << "service "; + + if ( b->has_nets() ) + cout << "net "; + + if ( b->has_ports() ) + cout << "port "; + + if ( b->has_proto() ) + cout << "proto "; + + if ( b->has_role() ) + cout << "role "; + + cout << endl; + } +} +#endif diff --git a/tools/snort2lua/helpers/util_binder.h b/tools/snort2lua/helpers/util_binder.h index 5bc8a175e..357ce8e6a 100644 --- a/tools/snort2lua/helpers/util_binder.h +++ b/tools/snort2lua/helpers/util_binder.h @@ -20,6 +20,7 @@ #ifndef HELPERS_PPS_BINDER_H #define HELPERS_PPS_BINDER_H +#include #include #include @@ -30,23 +31,20 @@ class TableApi; class Converter; class Binder { +public: //Only use Converter to instantiate Binders through make_binder() //This ensures only one binder tables is created per policy friend class Converter; -public: + + //Binding order matters. This allows STL compatible sorting. + friend bool operator<(const std::shared_ptr, const std::shared_ptr); + + Binder(TableApi&); ~Binder(); - // By calling add_to_configuration(), you are adding this Binder Object - // "as is" to the table_api. Additionally, after calling - // add_to_configuration(), the destructor will NOT add the object to the - // table_api unless 'print_binding(true)' is called. - void add_to_configuration(); void print_binding(bool should_print) { printed = !should_print; } - bool will_print() - { return !printed; } - void set_when_policy_id(int id); void set_when_service(std::string service); void set_when_role(std::string role); @@ -56,6 +54,27 @@ public: void add_when_port(std::string port); void clear_ports(); + bool has_policy_id() const + { return when_policy_id >= 0; } + + bool has_service() const + { return !when_service.empty(); } + + bool has_proto() const + { return !when_proto.empty(); } + + bool has_role() const + { return !when_role.empty() && when_role != "any"; } + + bool has_vlans() const + { return !vlans.empty(); } + + bool has_nets() const + { return !nets.empty(); } + + bool has_ports() const + { return !ports.empty(); } + void set_use_type(std::string module_name); void set_use_name(std::string struct_name); void set_use_file(std::string file_name); @@ -64,8 +83,6 @@ public: void set_use_policy_id(std::string id); private: - Binder(TableApi&); - TableApi& table_api; bool printed; // ensures that the binding is added once, // by either the destructor or user @@ -84,9 +101,17 @@ private: std::string use_file; std::string use_service; std::string use_action; + + void add_to_configuration(); }; +bool operator<(const std::shared_ptr, const std::shared_ptr); + typedef void (Binder::* binder_func)(std::string); +#ifdef REG_TEST +void print_binder_priorities(); +#endif + #endif