if (!util::get_string(data_stream, val, ","))
return false;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bool rc = true;
do
}
// Only add to the binder once we have validated the configuration.
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto(keyword);
while (data_stream >> port)
for (int i = 0; i < o.depth; i++)
whitespace += " ";
- out << whitespace;
+ if ( o.print_whitespace )
+ out << whitespace;
+
if (o.name.size())
out << o.name << " = ";
inline std::string get_value()
{ return value; }
+ void set_print_whitespace(bool w)
+ { print_whitespace = w; }
+
// overloading operators
friend std::ostream& operator<<(std::ostream&, const Option&);
friend bool operator!=(const Option& lhs, const Option& rhs);
std::string name;
std::string value;
int depth;
+ bool print_whitespace = false;
OptionType type;
};
whitespace += " ";
if (!t.name.empty())
- out << whitespace << t.name << " =" << std::endl;
- out << whitespace << '{' << std::endl;
+ {
+ if ( t.print_whitespace )
+ out << whitespace;
- if (!t.comments->empty() && !DataApi::is_quiet_mode())
- out << (*t.comments) << std::endl;
+ out << t.name << (t.one_line ? " = " : " =\n");
+ }
+
+ out << (t.print_whitespace ? whitespace : "")
+ << (t.one_line ? "{ " : "{\n");
// if we only want differences, don't print data
if (!DataApi::is_difference_mode())
{
for (Option* o : t.options)
- out << (*o) << ",\n";
+ {
+ o->set_print_whitespace(!t.one_line);
+ out << (*o) << (t.one_line ? ", " : ",\n");
+ }
for (Variable* v : t.lists)
- out << (*v) << ",\n";
+ {
+ v->set_print_whitespace(!t.one_line);
+ out << (*v) << (t.one_line ? ", " : ",\n");
+ }
for (Table* sub_t : t.tables)
- out << (*sub_t) << ",\n";
+ {
+ //If this table is one_lined, it may still print whitespace beforehand
+ //Don't print whitespace within the table if it's one_lined
+ sub_t->set_print_whitespace(!t.one_line);
+
+ if ( t.one_line )
+ sub_t->set_one_line(true);
+
+ out << (*sub_t) << (t.one_line ? ", " : ",\n");
+ }
}
else
{
for (Table* sub_t : t.tables)
+ {
if (sub_t->has_differences())
- out << (*sub_t) << ",\n";
+ {
+ //If this table is one_lined, it may still print whitespace beforehand
+ //Don't print whitespace within the table if it's one_lined
+ sub_t->set_print_whitespace(!t.one_line);
+
+ if ( t.one_line )
+ sub_t->set_one_line(true);
+
+ out << (*sub_t) << (t.one_line ? ", " : ",\n");
+ }
+ }
+ }
+
+
+ if (!t.comments->empty() && !DataApi::is_quiet_mode())
+ {
+ // Comments need a new line regardless of one_line setting
+ // When one_line is off, this section is already starting on it's own line
+ if ( t.one_line )
+ out << "\n";
+
+ out << (*t.comments) << "\n";
}
- out << whitespace << "}";
+ if ( !t.one_line && t.print_whitespace )
+ out << whitespace;
+ out << "}";
// Now, print all options which need to be appended/overwrite earlier options
if (!t.append_options.empty())
{
- out << "\n";
+ if ( !t.one_line )
+ out << "\n";
for (Option* a : t.append_options)
- out << (*a) << "\n";
+ {
+ a->set_print_whitespace(!t.one_line);
+
+ out << (*a);
+ if ( !t.one_line )
+ out << "\n";
+ }
}
return out;
virtual ~Table();
inline std::string get_name() { return name; }
+ void set_one_line(bool o) { one_line = o; }
+ void set_print_whitespace(bool w) { print_whitespace = w; }
bool has_differences();
Table* open_table();
Table* open_table(std::string);
private:
std::string name;
+ bool one_line = false;
+ bool print_whitespace = true;
+
int depth;
Comments* comments;
std::vector<Table*> tables;
for (int i = 0; i < var.depth; i++)
whitespace += " ";
- out << whitespace << var.name << " = ";
- count += whitespace.size() + var.name.size() + 3;
- whitespace += " ";
+ out << (var.print_whitespace ? whitespace : "") << var.name << " = ";
+
+ if ( var.print_whitespace )
+ count += whitespace.size();
+
+ count += var.name.size() + 3;
+
+ if ( var.print_whitespace )
+ whitespace += " ";
for (Variable::VarData* v : var.vars)
{
first_var = false;
// print string
- if (v->type == Variable::VarType::VARIABLE)
+ if ( v->type == Variable::VarType::VARIABLE )
{
- if (v->data.size() + count > var.max_line_length)
+ if ( var.print_whitespace && v->data.size() + count > var.max_line_length )
print_newline(out, count, whitespace);
out << v->data;
count += v->data.size();
}
- else if ((count + v->data.size()) < var.max_line_length)
+ else if ( !var.print_whitespace || (count + v->data.size()) < var.max_line_length )
{
out << "'" << v->data << "'";
count += v->data.size() + 2;
inline std::string get_name() { return name; }
std::string get_value(DataApi*);
bool add_value(std::string);
+
+ void set_print_whitespace(bool w)
+ { print_whitespace = w; }
+
friend std::ostream& operator<<(std::ostream&, const Variable&);
private:
std::vector<VarData*> vars;
std::string name;
int depth;
+ bool print_whitespace = true;
static const std::size_t max_line_length = 77; // leave room for additional text
};
curr_data_bad = false;
}
-void TableApi::open_top_level_table(std::string table_name)
+void TableApi::open_top_level_table(std::string table_name, bool one_line)
{
Table* t = util::find_table(tables, table_name);
tables.push_back(t);
}
+ t->set_one_line(one_line);
open_tables.push(t);
// ignore the initial table
top_level_tables.push(open_tables.size());
}
-void TableApi::open_table(std::string table_name)
+void TableApi::open_table(std::string table_name, bool one_line)
{
Table* t;
}
}
+ t->set_one_line(one_line);
open_tables.push(t);
}
-void TableApi::open_table()
+void TableApi::open_table(bool one_line)
{
// if no open tables, create a top-level table
if (open_tables.size() == 0)
else
{
Table* t = open_tables.top()->open_table();
+ t->set_one_line(one_line);
open_tables.push(t);
}
}
*/
// open a table at the topmost layer. i.e., the table will not be nested inside any other table.
- void open_top_level_table(std::string name);
+ void open_top_level_table(const char* name, bool one_line = false)
+ { open_top_level_table(std::string(name), one_line); }
+
+ void open_top_level_table(std::string name, bool one_line = false);
+
// open a nested named table --> 'name = {...}')
- void open_table(std::string name);
+ void open_table(std::string name, bool one_line = false);
+
+ void open_table(const char* name, bool one_line = false)
+ { open_table(std::string(name), one_line); }
+
// open a nested table that does not contain a name --> {...})
- void open_table();
+ void open_table(bool one_line = false);
+
// close the nested table. go to previous table level
void close_table();
return true;
}
+Binder& Converter::make_binder(Binder& b)
+{
+ binders.push_back(std::unique_ptr<Binder>(new Binder(b)));
+ return *binders.back();
+}
+
+Binder& Converter::make_binder()
+{
+ binders.push_back(std::unique_ptr<Binder>(new Binder(table_api)));
+ return *binders.back();
+}
+
int Converter::convert(std::string input,
std::string output_file,
std::string rule_file,
rc = parse_file(input);
+ // vector::clear()'s ordering isn't deterministic but this is
+ // keep in place for stable regressions
+ while ( binders.size() )
+ binders.pop_back();
+
if (rule_file.empty())
rule_file = output_file;
#ifndef UTILS_CONVERTER_H
#define UTILS_CONVERTER_H
+#include <memory>
#include <string>
#include "conversion_defines.h"
#include "data/dt_data.h"
#include "data/dt_table_api.h"
#include "data/dt_rule_api.h"
+#include "util_binder.h"
class Converter
{
inline static void set_empty_args(bool val)
{ empty_args = val; }
+ Binder& make_binder(Binder&);
+ Binder& make_binder();
+
int convert(std::string input,
std::string output,
std::string rules, // defaults to output_file
DataApi data_api;
TableApi table_api;
RuleApi rule_api;
+ std::vector<std::unique_ptr<Binder>> binders;
// the current parsing state.
ConversionState* state;
{
printed = true;
table_api.open_top_level_table("binder");
- table_api.open_table();
+ table_api.open_table(true);
- table_api.open_table("when");
+ table_api.open_table("when", true);
if (when_policy_id >= 0)
table_api.add_option("policy_id", when_policy_id);
if (!when_proto.empty())
table_api.add_option("proto", when_proto);
- if (!when_role.empty())
+ if (!when_role.empty() && when_role != "any")
table_api.add_option("role", when_role);
for (auto p : ports)
table_api.close_table(); // "when"
- table_api.open_table("use");
+ table_api.open_table("use", true);
if (!use_policy_id.empty())
table_api.add_option("policy_id", use_policy_id);
// The Binders destructor will add the Objects configuration to the
// table_api.
+class Converter;
class Binder
{
+ //Only use Converter to instantiate Binders through make_binder()
+ //This ensures only one binder tables is created per policy
+ friend class Converter;
public:
- Binder(TableApi&);
~Binder();
// By calling add_to_configuration(), you are adding this Binder Object
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 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 keyword;
bool retval = true;
- Binder bind_tcp(table_api);
- Binder bind_smb(table_api);
- Binder bind_udp(table_api);
- Binder bind_http_proxy(table_api);
- Binder bind_http_server(table_api);
+ auto& bind_tcp = cv.make_binder();
+ auto& bind_smb = cv.make_binder();
+ auto& bind_udp = cv.make_binder();
+ auto& bind_http_proxy = cv.make_binder();
+ auto& bind_http_server = cv.make_binder();
std::map<std::string, Binder*> bind;
if (converted_args)
return;
- Binder tcp_bind(table_api);
+ auto& tcp_bind = cv.make_binder();
tcp_bind.set_when_proto("tcp");
tcp_bind.add_when_port("20000");
tcp_bind.set_use_type("dnp3");
- Binder udp_bind(table_api);
+ auto& udp_bind = cv.make_binder();
udp_bind.set_when_proto("udp");
udp_bind.add_when_port("20000");
udp_bind.set_use_type("dnp3");
std::string keyword;
bool retval = true;
bool ports_set = false;
- Binder tcp_bind(table_api);
- Binder udp_bind(table_api);
+ auto& tcp_bind = cv.make_binder();
+ auto& udp_bind = cv.make_binder();
converted_args = true;
std::string keyword;
bool retval = true;
bool ports_set = false;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("tcp");
bind.set_use_type("dns");
}
else
{
- Binder b(table_api);
+ auto& b = cv.make_binder();
b.set_when_proto("ip");
b.add_when_net(ip_list);
b.set_use_type("stream_ip");
std::string keyword;
bool retval = true;
bool ports_set = false;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_use_type("ftp_server");
bind.set_when_proto("tcp");
{
std::string keyword;
bool retval = true;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_use_type("ftp_client");
bind.set_when_proto("tcp");
std::string keyword;
bool ports_set = false;
bool retval = true;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("tcp");
bind.set_use_type("telnet");
if (converted_args)
return;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("udp");
bind.add_when_port("2123");
bind.add_when_port("3386");
std::string keyword;
bool retval = true;
bool ports_set = false;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("udp");
bind.set_use_type("gtp_inspect");
bool ports_set = false;
bool simplify = false;
bool slash_dir_set = false;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("tcp");
bind.set_use_type("http_inspect");
std::string keyword;
bool retval = true;
bool ports_set = false;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("tcp");
bind.set_use_type("imap");
if (converted_args)
return;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("tcp");
bind.add_when_port("502");
bind.set_use_type("modbus");
std::string keyword;
bool retval = true;
bool ports_set = false;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("tcp");
bind.set_use_type("modbus");
std::string keyword;
bool retval = true;
bool ports_set = false;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("tcp");
bind.set_use_type("pop");
{
if (!converted_args)
{
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("tcp");
bind.add_when_port("111");
bind.add_when_port("32271");
std::string keyword;
// adding the binder entry
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("tcp");
bind.set_use_type("rpc_decode");
std::string keyword;
bool retval = true;
bool ports_set = false;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("udp");
bind.set_use_type("sip");
std::string keyword;
bool retval = true;
bool ports_set = false;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("tcp");
bind.set_use_type("smtp");
std::string keyword;
bool retval = true;
bool ports_set = false;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("tcp");
bind.set_use_type("ssh");
std::string keyword;
bool retval = true;
bool ports_set = false;
- Binder bind(table_api);
+ auto& bind = cv.make_binder();
bind.set_when_proto("tcp");
bind.set_use_type("ssl");
std::string keyword;
bool retval = true;
- Binder client(table_api);
- Binder server(table_api);
- Binder any(table_api);
+ auto& client = cv.make_binder();
+ auto& server = cv.make_binder();
+ auto& any = cv.make_binder();
// by default, only print one binding
client.print_binding(true);
// Add the port bindings separately from the protocol bindings since
// in 2.9.x they are OR'd not AND'd. Clear the ports so they're not
// included with the protocol bindings.
- {
- Binder b = client; // Binding is added during destructor.
- client.clear_ports();
- }
+ cv.make_binder(client);
+ client.clear_ports();
- {
- Binder b = server;
- server.clear_ports();
- }
+ cv.make_binder(server);
+ server.clear_ports();
- {
- Binder b = any;
- any.clear_ports();
- }
+ cv.make_binder(any);
+ any.clear_ports();
if (!protos_set)
{
for (const std::string& s : default_protos)
{
- Binder b = *bind_default; // Binding is added during destructor.
+ auto& b = cv.make_binder(*bind_default);
b.set_when_service(s);
}
}
{
for (std::string s : client_protocols)
{
- Binder b = client;
+ auto& b = cv.make_binder(client);
b.set_when_service(s);
}
}
{
for (std::string s : server_protocols)
{
- Binder b = server;
+ auto& b = cv.make_binder(server);
b.set_when_service(s);
}
}
{
for (std::string s : any_protocols)
{
- Binder b = any;
+ auto& b = cv.make_binder(any);
b.set_when_service(s);
}
}