* stream5_tcp: prune_log_max deleted; to be replaced with histogram
* stream5_tcp: max_active_responses, min_response_seconds moved to
active.max_responses, min_interval
+* ips policies support snort variables (_PATH, _PORT, _NET, _SERVER),
+ ips = { variables = { var1 = expr1, var2 = expr2, ... } }
=== Rules
-- default networks
---------------------------------------------------------------------------
--- List of DNS servers on your network
+-- List of DNS servers on your network
DNS_SERVERS = HOME_NET
-- List of ftp servers on your network
-- List of SMTP servers on your network
SMTP_SERVERS = HOME_NET
--- List of sql servers on your network
+-- List of sql servers on your network
SQL_SERVERS = HOME_NET
-- List of ssh servers on your network
3702 4343 4848 5250 6988 7000 7001 7144 7145 7510 7777 7779 8000 8008
8014 8028 8080 8085 8088 8090 8118 8123 8180 8181 8243 8280 8300 8800
8888 8899 9000 9060 9080 9090 9091 9443 9999 11371 34443 34444 41080
- 50002 55555
+ 50002 55555
]]
-- List of ports you run mail servers on
-- List of ports for file inspection
FILE_DATA_PORTS = HTTP_PORTS .. MAIL_PORTS
+---------------------------------------------------------------------------
+-- default variables
+---------------------------------------------------------------------------
+
+default_variables = {
+ RULE_PATH = RULE_PATH,
+ BUILTIN_RULE_PATH = BUILTIN_RULE_PATH,
+ PLUGIN_RULE_PATH = PLUGIN_RULE_PATH,
+ WHITE_LIST_PATH = WHITE_LIST_PATH,
+ BLACK_LIST_PATH = BLACK_LIST_PATH,
+
+ HOME_NET = HOME_NET,
+ EXTERNAL_NET = EXTERNAL_NET,
+ DNS_SERVERS = DNS_SERVERS,
+ FTP_SERVERS = FTP_SERVERS,
+ HTTP_SERVERS = HTTP_SERVERS,
+ SIP_SERVERS = SIP_SERVERS,
+ SMTP_SERVERS = SMTP_SERVERS,
+ SQL_SERVERS = SQL_SERVERS,
+ SSH_SERVERS = SSH_SERVERS,
+ TELNET_SERVERS = TELNET_SERVERS,
+
+ FTP_PORTS = FTP_PORTS,
+ HTTP_PORTS = HTTP_PORTS,
+ MAIL_PORTS = MAIL_PORTS,
+ ORACLE_PORTS = ORACLE_PORTS,
+ SIP_PORTS = SIP_PORTS,
+ SSH_PORTS = SSH_PORTS,
+ FILE_DATA_PORTS = FILE_DATA_PORTS,
+}
+
---------------------------------------------------------------------------
-- default ftp server
---------------------------------------------------------------------------
XSEM XSEN XSHA1 XSHA256
]]
-ftp_default_data_chan_cmds =
+ftp_default_data_chan_cmds =
[[
PORT PASV LPRT LPSV EPRT EPSV
]]
RETR STOR STOU APPE LIST NLST
]]
-ftp_default_file_put_cmds =
+ftp_default_file_put_cmds =
[[
STOR STOU
]]
-ftp_default_file_get_cmds =
+ftp_default_file_get_cmds =
[[
RETR
]]
-ftp_default_login_cmds =
+ftp_default_login_cmds =
[[
USER PASS
]]
-ftp_default_encr_cmds =
+ftp_default_encr_cmds =
[[
AUTH
]]
-ftp_format_commands =
-[[
+ftp_format_commands =
+[[
ACCT ADAT ALLO APPE AUTH CEL CLNT CMD CONF CWD DELE ENC EPRT EPSV ESTP
HELP LANG LIST LPRT MACB MAIL MDTM MIC MKD MLSD MLST MODE NLST OPTS
PASS PBSZ PORT PROT REST RETR RMD RNFR RNTO SDUP SITE SIZE SMNT STAT
},
hexes =
{
- { service = 'dnp3', proto = 'tcp', client_first = true,
+ { service = 'dnp3', proto = 'tcp', client_first = true,
to_server = { '|05 64|' }, to_client = { '|05 64|' } },
{ service = 'http2', proto = 'tcp', client_first = true,
ip_med_sweep ip_med_dist ip_hi_proto ip_hi_decoy ip_hi_sweep
ip_hi_dist icmp_low_sweep icmp_med_sweep icmp_hi_sweep
default_hi_port_scan default_med_port_scan default_low_port_scan
+ default_variables
]]
snort_whitelist_append(default_whitelist)
#include "parser/parse_conf.h"
#include "parser/parse_ip.h"
#include "parser/parser.h"
+#include "parser/vars.h"
#include "payload_injector/payload_injector_module.h"
#include "profiler/profiler.h"
#include "search_engines/pat_stats.h"
// Ips policy module
//-------------------------------------------------------------------------
+static void set_var(SnortConfig* sc, const char* fqn, Value& v)
+{
+ const char* ptr = strrchr(fqn, '.');
+ assert(ptr);
+ SetVar(sc, ptr + 1, v.get_string());
+}
+
+static const Parameter variable_params[] =
+{
+ { "$var" , Parameter::PT_STRING, nullptr, nullptr,
+ "IPS policy variable" },
+
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
static const Parameter ips_params[] =
{
{ "default_rule_state", Parameter::PT_ENUM, "no | yes | inherit", "inherit",
"IPS policy uuid" },
#endif
+ { "variables", Parameter::PT_TABLE, variable_params, nullptr,
+ "defines IPS policy variables" },
+
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
public:
IpsModule() : Module("ips", ips_help, ips_params) { }
bool set(const char*, Value&, SnortConfig*) override;
+ bool matches(const char*, std::string&) override;
Usage get_usage() const override
{ return DETECT; }
};
-bool IpsModule::set(const char*, Value& v, SnortConfig* sc)
+bool IpsModule::matches(const char* param, std::string& name)
+{
+ if ( strcmp(param, "$var") )
+ return false;
+
+ if ( name.find("_PATH") != string::npos or
+ name.find("_PORT") != string::npos or
+ name.find("_NET") != string::npos or
+ name.find("_SERVER") != string::npos )
+ return true;
+
+ return false;
+}
+
+bool IpsModule::set(const char* fqn, Value& v, SnortConfig* sc)
{
IpsPolicy* p = get_ips_policy();
}
#endif
+ else if ( strstr(fqn, "variables") )
+ set_var(sc, fqn, v);
+
else
return false;
fqn.erase(pos);
}
-static void trace(const char* s, const char* fqn, Value& v)
-{
-#if 1
- if ( s )
- return;
-#endif
-
- if ( v.get_type() == Value::VT_STR )
- printf("%s: %s = '%s'\n", s, fqn, v.get_string());
- else
- printf("%s: %s = " STDi64 "\n", s, fqn, v.get_int64());
-}
-
static ModHook* get_hook(const char* s)
{
auto mh = s_modules.find(s);
return get_params(new_fqn, m, p, idx);
}
-// FIXIT-M vars may have been defined on command line. that mechanism will
-// be replaced with pulling a Lua chunk from the command line and stuffing
-// into L before setting configs; that will overwrite
-//
-// FIXIT-M should only need one table with dynamically typed vars
-//
-//
-// FIXIT-M this is a hack to tell vars by naming convention; with one table
-// this is obviated but if multiple tables are kept might want to change
-// these to a module with parameters
-//
-// FIXIT-L presently no way to catch errors like EXTERNAL_NET = not HOME_NET
-// which becomes a bool var and is ignored.
-static bool set_var(const char* fqn, Value& val)
-{
- if ( val.get_type() != Value::VT_STR )
- return false;
-
- if ( get_ips_policy() == nullptr )
- return true;
-
- trace("var", fqn, val);
- const char* s = val.get_string();
-
- if ( strstr(fqn, "PATH") )
- AddVarToTable(s_config, fqn, s);
-
- else if ( strstr(fqn, "PORT") )
- PortVarDefine(s_config, fqn, s);
-
- else if ( strstr(fqn, "NET") || strstr(fqn, "SERVER") )
- ParseIpVar(s_config, fqn, s);
-
- return true;
-}
-
-static bool set_param(Module* mod, const char* fqn, Value& val)
-{
- if ( !mod->verified_set(fqn, val, s_config) )
- {
- ParseError("%s is invalid", fqn);
- ++s_errors;
- }
-
- trace("par", fqn, val);
- return true;
-}
-
static bool ignored(const char* fqn)
{
static const char* ignore = nullptr;
return true;
}
+// FIXIT-M vars may have been defined on command line. that mechanism will
+// be replaced with pulling a Lua chunk from the command line and stuffing
+// into L before setting configs; that will overwrite
+//
+// FIXIT-L presently no way to catch errors like EXTERNAL_NET = not HOME_NET
+// which becomes a bool var and is ignored.
+static bool set_var(const char* fqn, Value& v)
+{
+ bool to_be_set = v.get_type() == Value::VT_STR;
+
+ if ( to_be_set )
+ {
+ if ( get_ips_policy() != nullptr )
+ SetVar(s_config, fqn, v.get_string());
+ }
+ else
+ {
+ if ( !ignored(fqn) )
+ ParseWarning(WARN_SYMBOLS, "unknown symbol %s", fqn);
+ }
+
+ return to_be_set;
+}
+
+static bool set_param(Module* mod, const char* fqn, Value& val)
+{
+ if ( !mod->verified_set(fqn, val, s_config) )
+ {
+ ParseError("%s is invalid", fqn);
+ ++s_errors;
+ }
+
+ return true;
+}
+
static bool set_value(const char* fqn, Value& v)
{
string t = fqn;
Module* mod = ModuleManager::get_module(key.c_str());
if ( !mod )
- {
- bool found = set_var(fqn, v);
-
- if ( !found && !ignored(fqn) )
- ParseWarning(WARN_SYMBOLS, "unknown symbol %s", fqn);
- return found;
- }
+ return set_var(fqn, v);
const Parameter* p;
auto a = s_pmap.find(t);
pop_parse_location();
}
+// FIXIT-M should only need one table with dynamically typed vars
+//
+// FIXIT-M this is a hack to tell vars by naming convention; with one table
+// this is obviated but if multiple tables are kept might want to change
+// these to a module with parameters
+void SetVar(snort::SnortConfig* sc, const char* name, const char* value)
+{
+ if ( strstr(name, "_PATH") )
+ AddVarToTable(sc, name, value);
+
+ else if ( strstr(name, "_PORT") )
+ PortVarDefine(sc, name, value);
+
+ else if ( strstr(name, "_NET") )
+ ParseIpVar(sc, name, value);
+
+ else if ( strstr(name, "_SERVER") )
+ ParseIpVar(sc, name, value);
+}
+
void ParseIpVar(SnortConfig* sc, const char* var, const char* val)
{
int ret;
void parse_rules_file(snort::SnortConfig*, const char* fname);
void parse_rules_string(snort::SnortConfig*, const char* str);
+void SetVar(snort::SnortConfig*, const char* name, const char* value);
void ParseIpVar(snort::SnortConfig*, const char* name, const char* s);
void parse_include(snort::SnortConfig*, const char*);
{
sfip_var_t* ret;
int ret_code;
- vartable_t* ip_vartable = nullptr;
-
- if (get_ips_policy())
- ip_vartable = get_ips_policy()->ip_vartable;
ret = (sfip_var_t*)snort_calloc(sizeof(sfip_var_t));
- if ((ret_code = sfvt_add_to_var(ip_vartable, ret, addr)) != SFIP_SUCCESS)
+ if ((ret_code = sfvt_add_to_var(nullptr, ret, addr)) != SFIP_SUCCESS)
{
if (ret_code == SFIP_LOOKUP_FAILURE)
{
if ( rstat < 0 )
{
ParseError("PortVarTableAdd failed with '%s', exiting.", po->name);
+ PortObjectFree(po);
}
else if ( rstat > 0 )
{
ParseWarning(WARN_VARS, "PortVar '%s', already defined.", po->name);
+ PortObjectFree(po);
}
-#if 0
- LogMessage("PortVar '%s' defined : ",po->name);
- PortObjectPrintPortsRaw(po);
- LogMessage("\n");
-#endif
-
return 0;
}
else
p->id = var_id;
-#if 0
- vlen = strlen(value);
- LogMessage("Var '%s' defined, value len = %d chars", p->name, vlen);
-
- if ( vlen < 64 )
- {
- LogMessage(", value = %s\n", value);
- }
- else
- {
- LogMessage("\n");
- n = 128;
- s = value;
- while (vlen)
- {
- if ( n > vlen )
- n = vlen;
- LogMessage(" %.*s\n", n, s);
- s += n;
- vlen -= n;
- }
- }
-#endif
-
return p;
}
sfvt_free_table(table);
}
+
+ SECTION("merge without table")
+ {
+ SfIp* ip;
+
+ var2 = (sfip_var_t*)snort_calloc(sizeof(sfip_var_t));
+ table = sfvt_alloc_table();
+
+ // 'foo' variable
+ CHECK(sfvt_add_str(table, "foo 1.0.0.1", &var1) == SFIP_SUCCESS);
+
+ // no table used
+ CHECK(sfvt_add_to_var(nullptr, var2, "1.0.0.2") == SFIP_SUCCESS);
+ CHECK(sfvt_add_to_var(nullptr, var2, "$foo") == SFIP_LOOKUP_UNAVAILABLE);
+ CHECK(sfvt_add_to_var(nullptr, var2, "$moo") == SFIP_LOOKUP_UNAVAILABLE);
+
+ print_var_list(var2->head);
+ CHECK(!strcmp("1.0.0.2", sfipvar_test_buff));
+
+ ip = (SfIp *)snort_alloc(sizeof(SfIp));
+ CHECK(ip->set("1.0.0.1") == SFIP_SUCCESS);
+ CHECK((sfvar_ip_in(var2, ip) == false));
+ snort_free(ip);
+
+ ip = (SfIp *)snort_alloc(sizeof(SfIp));
+ CHECK(ip->set("1.0.0.2") == SFIP_SUCCESS);
+ CHECK((sfvar_ip_in(var2, ip) == true));
+ snort_free(ip);
+
+ // using table
+ CHECK(sfvt_add_to_var(table, var2, "$foo") == SFIP_SUCCESS);
+ CHECK(sfvt_add_to_var(table, var2, "$moo") == SFIP_LOOKUP_FAILURE);
+
+ print_var_list(var2->head);
+ CHECK(!strcmp("1.0.0.1,1.0.0.2", sfipvar_test_buff));
+
+ ip = (SfIp *)snort_alloc(sizeof(SfIp));
+ CHECK(ip->set("1.0.0.1") == SFIP_SUCCESS);
+ CHECK((sfvar_ip_in(var2, ip) == true));
+ snort_free(ip);
+
+ ip = (SfIp *)snort_alloc(sizeof(SfIp));
+ CHECK(ip->set("1.0.0.2") == SFIP_SUCCESS);
+ CHECK((sfvar_ip_in(var2, ip) == true));
+ snort_free(ip);
+
+ sfvar_free(var2);
+ sfvt_free_table(table);
+ }
}
TEST_CASE("SfIpVarCopyAddCompare", "[SfIpVar]")
errors->add_text("^^^^ unknown_syntax=" + unknown_option);
}
+static bool is_local_variable(const std::string& name)
+{
+ return name.find("_PATH") != std::string::npos
+ || name.find("_PORT") != std::string::npos
+ || name.find("_NET") != std::string::npos
+ || name.find("_SERVER") != std::string::npos;
+}
+
void DataApi::set_variable(const std::string& name, const std::string& value, bool quoted)
{
+ if (is_local_variable(name))
+ local_vars.push_back(name);
+
Variable* var = new Variable(name);
vars.push_back(var);
var->set_value(value, quoted);
if (name == v->get_name())
return v->add_value(value);
+ if (is_local_variable(name))
+ local_vars.push_back(name);
+
Variable* var = new Variable(name);
vars.push_back(var);
return var->add_value(value);
void DataApi::add_unsupported_comment(const std::string& c)
{ unsupported->add_text(c); }
-void DataApi::print_errors(std::ostream& out)
+void DataApi::print_errors(std::ostream& out) const
{
if (is_default_mode() &&
!errors->empty())
}
}
-void DataApi::print_data(std::ostream& out)
+void DataApi::print_data(std::ostream& out) const
{
for (Variable* v : vars)
out << (*v) << "\n\n";
out << (*i) << "\n\n";
}
-void DataApi::print_comments(std::ostream& out)
+void DataApi::print_comments(std::ostream& out) const
{
if (is_default_mode() && !comments->empty())
out << (*comments) << "\n";
}
-void DataApi::print_unsupported(std::ostream& out)
+void DataApi::print_unsupported(std::ostream& out) const
{
if (is_default_mode() && !unsupported->empty())
out << (*unsupported) << "\n";
}
+void DataApi::print_local_variables(std::ostream& out) const
+{
+ if (local_vars.empty())
+ return;
+
+ out << "local_variables =\n{\n";
+ for (const auto& v : local_vars)
+ out << " " << v << " = " << v << ",\n";
+ out << "}\n\n";
+}
+
void DataApi::swap_conf_data(std::vector<Variable*>& new_vars,
std::vector<Include*>& new_includes,
Comments*& new_comments, Comments*& new_unsupported)
void reset_state();
// Output Functions
- void print_errors(std::ostream&);
- void print_data(std::ostream&);
- void print_comments(std::ostream& out);
- void print_unsupported(std::ostream& out);
+ void print_errors(std::ostream&) const;
+ void print_data(std::ostream&) const;
+ void print_comments(std::ostream& out) const;
+ void print_unsupported(std::ostream& out) const;
+ void print_local_variables(std::ostream&) const;
// have there been any failed conversion?
bool failed_conversions() const;
bool empty() const
{ return vars.empty() && includes.empty(); }
+ bool has_local_vars() const
+ { return !local_vars.empty(); }
+
// functions specifically useful when parsing includes.
// allows for easy swapping of data. These two functions
// swap data which will be printed in 'print_rules()' and
std::vector<Variable*> vars;
std::vector<Include*> includes;
+ std::vector<std::string> local_vars;
Comments* comments;
Comments* errors;
Comments* unsupported;
#include "helpers/converter.h"
#include "conversion_state.h"
#include "data/data_types/dt_comment.h"
+#include "data/data_types/dt_include.h"
#include "data/data_types/dt_rule.h"
#include "data/data_types/dt_table.h"
+#include "data/data_types/dt_var.h"
#include "helpers/s2l_util.h"
#include "helpers/util_binder.h"
#include "init_state.h"
rule_api.include_rule_file(input_file + ".rules");
}
+ for (auto v : vars)
+ delete v;
+
for (auto r : rules)
delete r;
for (auto t : tables)
delete t;
+ for (auto i : includes)
+ delete i;
+
return rc;
}
if (!rule_api.empty())
{
+ data_api.print_local_variables(out);
+
if (rule_file.empty() || rule_file == output_file)
{
rule_api.print_rules(out, false);
- std::string s = std::string("$local_rules");
table_api.open_top_level_table("ips");
- table_api.add_option("rules", s);
+ table_api.add_option("rules", "$local_rules");
+ if (data_api.has_local_vars())
+ table_api.add_option("variables", "$local_variables");
table_api.close_table();
}
else
table_api.open_top_level_table("ips");
table_api.add_option("include", rule_file);
+ if (data_api.has_local_vars())
+ table_api.add_option("variables", "$local_variables");
table_api.close_table();
}
}