#include "helpers/converter.h"
#include "helpers/s2l_util.h"
#include "helpers/s2l_markup.h"
+#include "helpers/util_binder.h"
namespace parser
{
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 <snort_conf> ...\n";
{ "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 <out_file>" },
//--------------------------------------------------------------------------
// pps_binder.cc author Josh Rosenbaum <jrosenba@cisco.com>
+#include <algorithm>
+
#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)
Binder::~Binder()
{
- if (!printed)
+ if ( !printed )
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"
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<Binder> left, const shared_ptr<Binder> 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 <iostream>
+
+void print_binder_priorities()
+{
+ static unsigned const num_combos = 2 * 2 * 2 * 2 * 2 * 2 * 2;
+ vector<shared_ptr<Binder>> binders;
+ TableApi t;
+
+ for ( unsigned i = 0; i < num_combos; i++ )
+ {
+ binders.push_back(shared_ptr<Binder>(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
#ifndef HELPERS_PPS_BINDER_H
#define HELPERS_PPS_BINDER_H
+#include <memory>
#include <string>
#include <vector>
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<Binder>, const std::shared_ptr<Binder>);
+
+ 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);
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);
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
std::string use_file;
std::string use_service;
std::string use_action;
+
+ void add_to_configuration();
};
+bool operator<(const std::shared_ptr<Binder>, const std::shared_ptr<Binder>);
+
typedef void (Binder::* binder_func)(std::string);
+#ifdef REG_TEST
+void print_binder_priorities();
+#endif
+
#endif