From 75ec38edbfe6865a9cdcf308f3a68078378024d2 Mon Sep 17 00:00:00 2001 From: "Bhagya Tholpady (bbantwal)" Date: Tue, 27 Oct 2020 17:05:43 +0000 Subject: [PATCH] Merge pull request #2522 in SNORT/snort3 from ~OSERHIIE/snort3:custom_vars_wo_suffixes to master Squashed commit of the following: commit 368ff259fb2f0e37e297dd82b46ce71a2bbfc1e2 Author: Oleksandr Serhiienko Date: Thu Sep 24 19:48:37 2020 +0300 ips: move IPS variables to sub-tables which designates type * main: snort supports ips.variables.nets/.paths/.ports tables to specify custom variables regardless suffixes (_PATH, _PORT, _NET and _SERVER) * lua: update default_variables with 'nets', 'paths' and 'ports' tables in snort_defaults.lua * managers, parser, ports: rid-off obsolete code for variables parsing relying on the suffixes * snort_module: remove support for -S option * tools: snort2lua converts custom variables into ips.variables.nets/.paths/.ports tables * doc: update upgrade/differences.txt --- doc/upgrade/differences.txt | 4 +- lua/snort_defaults.lua | 52 ++-- src/main/modules.cc | 46 ++-- src/main/snort_config.cc | 7 - src/main/snort_config.h | 2 - src/main/snort_module.cc | 5 - src/managers/module_manager.cc | 1 - src/parser/parse_conf.cc | 32 +-- src/parser/parse_conf.h | 3 +- src/parser/parse_rule.cc | 2 +- src/parser/parser.cc | 10 - src/parser/vars.cc | 321 ++-------------------- src/parser/vars.h | 26 +- src/ports/port_var_table.cc | 4 +- src/ports/port_var_table.h | 2 +- tools/snort2lua/data/data_types/dt_var.cc | 14 +- tools/snort2lua/data/data_types/dt_var.h | 5 +- tools/snort2lua/data/dt_data.cc | 95 +++++-- tools/snort2lua/data/dt_data.h | 18 +- tools/snort2lua/keyword_states/kws_var.cc | 76 +++-- 20 files changed, 251 insertions(+), 474 deletions(-) diff --git a/doc/upgrade/differences.txt b/doc/upgrade/differences.txt index da955f8f4..ddafc21bd 100644 --- a/doc/upgrade/differences.txt +++ b/doc/upgrade/differences.txt @@ -141,8 +141,8 @@ Some things Snort++ can do today that Snort can not do as well: * 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, ... } } +* ips policies support snort variables configured based on type, + ips = { variables = { nets = { var1 = expr1, ... }, paths = { var2 = expr2, ... }, ports = { var3 = expr3, ... } } } === Rules diff --git a/lua/snort_defaults.lua b/lua/snort_defaults.lua index 9fffe3b7a..9afdff06a 100644 --- a/lua/snort_defaults.lua +++ b/lua/snort_defaults.lua @@ -95,30 +95,34 @@ FILE_DATA_PORTS = HTTP_PORTS .. MAIL_PORTS --------------------------------------------------------------------------- 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, + nets = { + 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, + }, + paths = { + 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, + }, + ports = { + 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, + } } --------------------------------------------------------------------------- diff --git a/src/main/modules.cc b/src/main/modules.cc index 62be9831f..306871494 100644 --- a/src/main/modules.cc +++ b/src/main/modules.cc @@ -1168,14 +1168,14 @@ bool InspectionModule::set(const char*, Value& v, SnortConfig* sc) // Ips policy module //------------------------------------------------------------------------- -static void set_var(SnortConfig* sc, const char* fqn, Value& v) +static const char* get_var_name(const char* fqn) { const char* ptr = strrchr(fqn, '.'); assert(ptr); - SetVar(sc, ptr + 1, v.get_string()); + return ptr + 1; } -static const Parameter variable_params[] = +static const Parameter var_params[] = { { "$var" , Parameter::PT_STRING, nullptr, nullptr, "IPS policy variable" }, @@ -1183,6 +1183,20 @@ static const Parameter variable_params[] = { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; +static const Parameter variable_params[] = +{ + { "nets" , Parameter::PT_TABLE, var_params, nullptr, + "net variables" }, + + { "paths" , Parameter::PT_TABLE, var_params, nullptr, + "path variables" }, + + { "ports" , Parameter::PT_TABLE, var_params, nullptr, + "port variables" }, + + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + static const Parameter ips_params[] = { { "default_rule_state", Parameter::PT_ENUM, "no | yes | inherit", "inherit", @@ -1238,19 +1252,8 @@ public: { return DETECT; } }; -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::matches(const char*, std::string&) +{ return true; } bool IpsModule::set(const char* fqn, Value& v, SnortConfig* sc) { @@ -1297,8 +1300,15 @@ bool IpsModule::set(const char* fqn, Value& v, SnortConfig* sc) } #endif - else if ( strstr(fqn, "variables") ) - set_var(sc, fqn, v); + // FIXIT-M should only need one table with dynamically typed vars + else if ( strstr(fqn, "variables.nets.") ) + ParseIpVar(get_var_name(fqn), v.get_string()); + + else if ( strstr(fqn, "variables.paths.") ) + ParsePathVar(get_var_name(fqn), v.get_string()); + + else if ( strstr(fqn, "variables.ports.") ) + ParsePortVar(get_var_name(fqn), v.get_string()); else return false; diff --git a/src/main/snort_config.cc b/src/main/snort_config.cc index aa4b9f2a8..163fd79bf 100644 --- a/src/main/snort_config.cc +++ b/src/main/snort_config.cc @@ -245,9 +245,6 @@ SnortConfig::~SnortConfig() if (eth_dst ) snort_free(eth_dst); - if ( var_list ) - FreeVarList(var_list); - if ( fast_pattern_config && (!snort_conf || this == snort_conf || (fast_pattern_config->get_search_api() != @@ -458,10 +455,6 @@ void SnortConfig::merge(SnortConfig* cmd_line) remote_control_socket = cmd_line->remote_control_socket; #endif - // config file vars are stored differently - // FIXIT-M should cmd_line use the same var list / table? - var_list = nullptr; - assert(!state); num_slots = offload_threads + ThreadConfig::get_instance_max(); state = new std::vector[num_slots]; diff --git a/src/main/snort_config.h b/src/main/snort_config.h index 3c8a85a78..46b087143 100644 --- a/src/main/snort_config.h +++ b/src/main/snort_config.h @@ -157,7 +157,6 @@ struct RulePortTables; struct SFDAQConfig; struct SoRules; struct ThresholdConfig; -struct VarNode; namespace snort { @@ -393,7 +392,6 @@ public: XHash* rtn_hash_table = nullptr; PolicyMap* policy_map = nullptr; - VarNode* var_list = nullptr; std::string tweaks; DataBus* global_dbus = nullptr; diff --git a/src/main/snort_module.cc b/src/main/snort_module.cc index 497fb306b..4ab163b63 100644 --- a/src/main/snort_module.cc +++ b/src/main/snort_module.cc @@ -267,9 +267,6 @@ static const Parameter s_params[] = { "-r", Parameter::PT_STRING, nullptr, nullptr, "... (same as --pcap-list)" }, - { "-S", Parameter::PT_STRING, nullptr, nullptr, - " set config variable x equal to value v" }, - { "-s", Parameter::PT_INT, "68:65535", "1518", " (same as --snaplen); default is 1518" }, @@ -772,8 +769,6 @@ bool SnortModule::set(const char*, Value& v, SnortConfig* sc) sc->run_flags |= RUN_FLAG__READ; Trough::add_source(Trough::SOURCE_LIST, v.get_string()); } - else if ( v.is("-S") ) - config_set_var(sc, v.get_string()); else if ( v.is("-s") or v.is("--snaplen") ) sc->daq_config->set_mru_size(v.get_uint16()); diff --git a/src/managers/module_manager.cc b/src/managers/module_manager.cc index e9d33e860..6c9175f97 100644 --- a/src/managers/module_manager.cc +++ b/src/managers/module_manager.cc @@ -44,7 +44,6 @@ #include "main/snort_config.h" #include "parser/parse_conf.h" #include "parser/parser.h" -#include "parser/vars.h" #include "profiler/profiler.h" #include "utils/util.h" diff --git a/src/parser/parse_conf.cc b/src/parser/parse_conf.cc index af7f2a041..19f5540b7 100644 --- a/src/parser/parse_conf.cc +++ b/src/parser/parse_conf.cc @@ -186,7 +186,7 @@ const char* get_config_file(const char* arg, std::string& file) void parse_include(SnortConfig* sc, const char* arg) { assert(arg); - arg = ExpandVars(sc, arg); + arg = ExpandVars(arg); std::string file = !rules_file_depth ? get_ips_policy()->includer : get_parse_file(); const char* code = get_config_file(arg, file); @@ -201,38 +201,18 @@ void parse_include(SnortConfig* sc, const char* arg) 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) +void ParseIpVar(const char* var, const char* value) { int ret; IpsPolicy* p = get_ips_policy(); // FIXIT-M double check, see below - DisallowCrossTableDuplicateVars(sc, var, VAR_TYPE__IPVAR); + DisallowCrossTableDuplicateVars(var, VAR_TYPE__IPVAR); - if ((ret = sfvt_define(p->ip_vartable, var, val)) != SFIP_SUCCESS) + if ((ret = sfvt_define(p->ip_vartable, var, value)) != SFIP_SUCCESS) { switch (ret) { case SFIP_ARG_ERR: - ParseError("the following is not allowed: %s.", val); + ParseError("the following is not allowed: %s.", value); return; case SFIP_DUPLICATE: @@ -250,7 +230,7 @@ void ParseIpVar(SnortConfig* sc, const char* var, const char* val) return; default: - ParseError("failed to parse the IP address: %s.", val); + ParseError("failed to parse the IP address: %s.", value); return; } } diff --git a/src/parser/parse_conf.h b/src/parser/parse_conf.h index 065bab0c9..7f320f1b4 100644 --- a/src/parser/parse_conf.h +++ b/src/parser/parse_conf.h @@ -41,8 +41,7 @@ const char* get_config_file(const char* arg, std::string& file); 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 ParseIpVar(const char* name, const char* value); void parse_include(snort::SnortConfig*, const char*); void add_service_to_otn(snort::SnortConfig*, OptTreeNode*, const char*); diff --git a/src/parser/parse_rule.cc b/src/parser/parse_rule.cc index 2905fcfe0..05aa3a8b6 100644 --- a/src/parser/parse_rule.cc +++ b/src/parser/parse_rule.cc @@ -464,7 +464,7 @@ static PortObject* ParsePortListTcpUdpPort( const char* name = port_str + 1; /* look it up in the port var table */ - portobject = PortVarTableFind(pvt, name); + portobject = PortVarTableFind(pvt, name, true); if ( !portobject ) ParseAbort("***PortVar Lookup failed on '%s'.", port_str); diff --git a/src/parser/parser.cc b/src/parser/parser.cc index 0d9138827..f469e4ab8 100644 --- a/src/parser/parser.cc +++ b/src/parser/parser.cc @@ -323,8 +323,6 @@ SnortConfig* ParseSnortConf(const SnortConfig* boot_conf, const char* fname, boo sc->tweaks = boot_conf->tweaks; sc->dump_config_type = boot_conf->dump_config_type; - VarNode* tmp = boot_conf->var_list; - if ( !fname ) fname = get_snort_conf(); @@ -341,14 +339,6 @@ SnortConfig* ParseSnortConf(const SnortConfig* boot_conf, const char* fname, boo sc->rate_filter_config = RateFilter_ConfigNew(); sc->detection_filter_config = DetectionFilterConfigNew(); - /* Add command line defined variables - duplicates will already - * have been resolved */ - while (tmp != nullptr) - { - AddVarToTable(sc, tmp->name, tmp->value); - tmp = tmp->next; - } - // get overrides from cmd line Shell* sh = boot_conf->policy_map->get_shell(); sc->policy_map->get_shell()->set_overrides(sh); diff --git a/src/parser/vars.cc b/src/parser/vars.cc index 131a8f47a..0b6159e45 100644 --- a/src/parser/vars.cc +++ b/src/parser/vars.cc @@ -37,105 +37,24 @@ using namespace snort; -//------------------------------------------------------------------------- -// var node stuff -//------------------------------------------------------------------------- - -void config_set_var(SnortConfig* sc, const char* val) -{ - { - const char* equal_ptr = strchr(val, '='); - VarNode* node; - - if (equal_ptr == nullptr) - { - ParseError("Format for command line variable definitions " - "is:\n -S var=value\n"); - return; - } - - /* Save these and parse when snort conf is parsed so - * they can be added to the snort conf configuration */ - node = (VarNode*)snort_calloc(sizeof(VarNode)); - - /* Make sure it's not already in the list */ - if (sc->var_list != nullptr) - { - VarNode* tmp = sc->var_list; - - while (tmp != nullptr) - { - if (strncasecmp(tmp->name, val, equal_ptr - val) == 0) - { - ParseError("Duplicate variable name: %s.", tmp->name); - snort_free(node); - return; - } - tmp = tmp->next; - } - } - - node->name = snort_strndup(val, equal_ptr - val); - node->value = snort_strdup(equal_ptr + 1); - node->line = snort_strdup(val); - node->next = sc->var_list; - sc->var_list = node; - - /* Put line in a parser parsable form - we know the - * equals is already there */ - *strchr(node->line, '=') = ' '; - } -} - -void FreeVarList(VarNode* head) -{ - while (head != nullptr) - { - VarNode* tmp = head; - - head = head->next; - - if (tmp->name != nullptr) - snort_free(tmp->name); - - if (tmp->value != nullptr) - snort_free(tmp->value); - - if (tmp->line != nullptr) - snort_free(tmp->line); - - snort_free(tmp); - } -} - //------------------------------------------------------------------------- // var table stuff //------------------------------------------------------------------------- -/* - * PortVarDefine - * - * name - portlist name, i.e. http, smtp, ... - * s - port number, port range, or a list of numbers/ranges in brackets - * - * examples: - * portvar http [80,8080,8138,8700:8800,!8711] - * portvar http $http_basic - */ -int PortVarDefine(SnortConfig* sc, const char* name, const char* s) +void ParsePortVar(const char* name, const char* value) { PortObject* po; POParser pop; int rstat; PortVarTable* portVarTable = get_ips_policy()->portVarTable; - DisallowCrossTableDuplicateVars(sc, name, VAR_TYPE__PORTVAR); + DisallowCrossTableDuplicateVars(name, VAR_TYPE__PORTVAR); - if ( SnortStrcasestr(s,strlen(s),"any") ) /* this allows 'any' or '[any]' */ + if ( SnortStrcasestr(value,strlen(value),"any") ) /* this allows 'any' or '[any]' */ { - if (strstr(s,"!")) + if (strstr(value,"!")) { - ParseError("illegal use of negation and 'any': %s.", s); + ParseError("illegal use of negation and 'any': %s.", value); } po = PortObjectNew(); @@ -145,12 +64,12 @@ int PortVarDefine(SnortConfig* sc, const char* name, const char* s) else { /* Parse the Port List info into a PortObject */ - po = PortObjectParseString(portVarTable, &pop, name, s, 0); + po = PortObjectParseString(portVarTable, &pop, name, value, 0); if (!po) { const char* errstr = PortObjectParseError(&pop); ParseAbort("PortVar Parse error: (pos=%d,error=%s)\n>>%s\n>>%*s.", - pop.pos,errstr,s,pop.pos,"^"); + pop.pos,errstr,value,pop.pos,"^"); } } @@ -166,21 +85,8 @@ int PortVarDefine(SnortConfig* sc, const char* name, const char* s) ParseWarning(WARN_VARS, "PortVar '%s', already defined.", po->name); PortObjectFree(po); } - - return 0; } -/**************************************************************************** - * - * Function: VarAlloc() - * - * Purpose: allocates memory for a variable - * - * Arguments: none - * - * Returns: pointer to new VarEntry - * - ***************************************************************************/ VarEntry* VarAlloc() { VarEntry* pve; @@ -190,19 +96,6 @@ VarEntry* VarAlloc() return( pve); } -/**************************************************************************** - * - * Function: VarIsIpAddr(char *, char *) - * - * Purpose: Checks if a var is an IP address. Necessary since moving forward - * we want all IP addresses handled by the IP variable table. - * If a list is given, this checks each value. - * - * Arguments: value => the string to check - * - * Returns: 1 if IP address, 0 otherwise - * - ***************************************************************************/ int VarIsIpAddr(vartable_t* ip_vartable, const char* value) { const char* tmp; @@ -253,18 +146,6 @@ int VarIsIpAddr(vartable_t* ip_vartable, const char* value) return 0; } -/**************************************************************************** - * - * Function: CheckBrackets(char *) - * - * Purpose: Check that the brackets match up in a string that - * represents a list. - * - * Arguments: value => the string to check - * - * Returns: 1 if the brackets match correctly, 0 otherwise - * - ***************************************************************************/ static int CheckBrackets(char* value) { int num_brackets = 0; @@ -295,17 +176,6 @@ static int CheckBrackets(char* value) return 1; } -/**************************************************************************** - * - * Function: VarIsIpList(vartable_t *, char*) - * - * Purpose: Checks if a var is a list of IP addresses. - * - * Arguments: value => the string to check - * - * Returns: 1 if each item is an IP address, 0 otherwise - * - ***************************************************************************/ int VarIsIpList(vartable_t* ip_vartable, const char* value) { char* copy, * item; @@ -338,25 +208,7 @@ int VarIsIpList(vartable_t* ip_vartable, const char* value) return item_is_ip; } -/**************************************************************************** - * - * Function: DisallowCrossTableDuplicateVars(char *, int) - * - * Purpose: ParseErrors if the a variable name is redefined across variable - * types. Enforcing this mutual exclusion prevents the - * catastrophe where the variable lookup fall-through (see VarSearch) - * finds an unintended variable from the wrong table. Note: VarSearch - * is only necessary for ExpandVars. - * - * Arguments: name => The name of the variable - * var_type => The type of the variable that is about to be defined. - * The corresponding variable table will not be searched. - * - * Returns: void function - * - ***************************************************************************/ -void DisallowCrossTableDuplicateVars( - SnortConfig*, const char* name, VarType var_type) +void DisallowCrossTableDuplicateVars(const char* name, VarType var_type) { IpsPolicy* dp = get_ips_policy(); VarEntry* var_table = dp->var_table; @@ -364,13 +216,6 @@ void DisallowCrossTableDuplicateVars( vartable_t* ip_vartable = dp->ip_vartable; VarEntry* p = var_table; - /* If this is a faked Portvar, treat as a portvar */ - if ((var_type == VAR_TYPE__DEFAULT) && - (strstr(name, "_PORT") || strstr(name, "PORT_"))) - { - var_type = VAR_TYPE__PORTVAR; - } - switch (var_type) { case VAR_TYPE__DEFAULT: @@ -434,81 +279,17 @@ void DisallowCrossTableDuplicateVars( } } -/**************************************************************************** - * - * Function: VarDefine(char *, char *) - * - * Purpose: define the contents of a variable - * - * Arguments: name => the name of the variable - * value => the contents of the variable - * - * Returns: void function - * - ***************************************************************************/ -VarEntry* VarDefine( - SnortConfig* sc, const char* name, const char* value) +void ParsePathVar(const char* name, const char* value) { - IpsPolicy* dp = get_ips_policy(); - VarEntry* var_table = dp->var_table; - vartable_t* ip_vartable = dp->ip_vartable; - VarEntry* p; - uint32_t var_id = 0; - if (value == nullptr) { ParseAbort("bad value in variable definition. Make sure you don't " "have a '$' in the var name."); } - if (VarIsIpList(ip_vartable, value)) - { - SfIpRet ret; - - if (ip_vartable == nullptr) - return nullptr; - - /* Verify a variable by this name is not already used as either a - * portvar or regular var. Enforcing this mutual exclusion prevents the - * catastrophe where the variable lookup fall-through (see VarSearch) - * finds an unintended variable from the wrong table. Note: VarSearch - * is only necessary for ExpandVars. */ - DisallowCrossTableDuplicateVars(sc, name, VAR_TYPE__IPVAR); - - if ((ret = sfvt_define(ip_vartable, name, value)) != SFIP_SUCCESS) - { - switch (ret) - { - case SFIP_ARG_ERR: - ParseAbort("the following is not allowed: %s.", value); - - case SFIP_DUPLICATE: - ParseWarning(WARN_VARS, "Var '%s' redefined.", name); - break; - - case SFIP_CONFLICT: - ParseAbort("negated IP ranges that are more general than " - "non-negated ranges are not allowed. Consider " - "inverting the logic in %s.", name); - - case SFIP_NOT_ANY: - ParseAbort("!any is not allowed in %s", name); - - default: - ParseAbort("failed to parse the IP address: %s.", value); - } - } - return nullptr; - } - /* Check if this is a variable that stores an IP */ - else if (*value == '$') - { - if ( sfvt_lookup_var(ip_vartable, value) ) - { - sfvt_define(ip_vartable, name, value); - return nullptr; - } - } + IpsPolicy* dp = get_ips_policy(); + VarEntry* var_table = dp->var_table; + uint32_t var_id = 0; /* Check to see if this variable is just being aliased */ if (var_table != nullptr) @@ -529,17 +310,17 @@ VarEntry* VarDefine( while (tmp != var_table); } - value = ExpandVars(sc, value); + value = ExpandVars(value); if (!value) { ParseAbort("could not expand var('%s').", name); } - DisallowCrossTableDuplicateVars(sc, name, VAR_TYPE__DEFAULT); + DisallowCrossTableDuplicateVars(name, VAR_TYPE__DEFAULT); if (var_table == nullptr) { - p = VarAlloc(); + VarEntry* p = VarAlloc(); p->name = snort_strdup(name); p->value = snort_strdup(value); @@ -550,11 +331,11 @@ VarEntry* VarDefine( p->id = dp->var_id++; - return p; + return; } /* See if an existing variable is being redefined */ - p = var_table; + VarEntry* p = var_table; do { @@ -565,7 +346,7 @@ VarEntry* VarDefine( p->value = snort_strdup(value); ParseWarning(WARN_VARS, "Var '%s' redefined\n", p->name); - return p; + return; } p = p->next; @@ -585,7 +366,7 @@ VarEntry* VarDefine( else p->id = var_id; - return p; + return; } void DeleteVars(VarEntry* var_table) @@ -610,7 +391,7 @@ void DeleteVars(VarEntry* var_table) } } -const char* VarSearch(SnortConfig* sc, const char* name) +const char* VarSearch(const char* name) { IpsPolicy* dp = get_ips_policy(); VarEntry* var_table = dp->var_table; @@ -619,7 +400,7 @@ const char* VarSearch(SnortConfig* sc, const char* name) sfip_var_t* ipvar; if ((ipvar = sfvt_lookup_var(ip_vartable, name)) != nullptr) - return ExpandVars(sc, ipvar->value); + return ExpandVars(ipvar->value); if (PortVarTableFind(portVarTable, name)) return name; @@ -641,7 +422,7 @@ const char* VarSearch(SnortConfig* sc, const char* name) // The expanded string. Note that the string is returned in a // static variable and most likely needs to be string dup'ed. -const char* ExpandVars(SnortConfig* sc, const char* string) +const char* ExpandVars(const char* string) { static char estring[ 65536 ]; // FIXIT-L convert this foo to a std::string @@ -727,7 +508,7 @@ const char* ExpandVars(SnortConfig* sc, const char* string) memset((char*)varbuffer, 0, sizeof(varbuffer)); - varcontents = VarSearch(sc, varname); + varcontents = VarSearch(varname); switch (varmodifier) { @@ -773,59 +554,3 @@ const char* ExpandVars(SnortConfig* sc, const char* string) return estring; } -void AddVarToTable(SnortConfig* sc, const char* name, const char* value) -{ - //TODO: snort.cfg and rules should use PortVar instead ...this allows compatibility for now. - if (strstr(name, "_PORT") || strstr(name, "PORT_")) - { - PortVarDefine(sc, name, value); - } - else - { - VarDefine(sc, name, value); - } -} - -//-------------------------------------------------------------------------- -// unit tests -//-------------------------------------------------------------------------- - -#ifdef UNIT_TEST -// FIXIT-L these var tests are inadequate - -TEST_CASE("config_set_var-success", "[vars]") -{ - SnortConfig sc; - sc.var_list = nullptr; - config_set_var(&sc, "A=B"); - - REQUIRE(sc.var_list->name[0] == 'A'); - REQUIRE(sc.var_list->value[0] == 'B'); -} - -TEST_CASE("config_set_var-existing-success", "[vars]") -{ - SnortConfig sc; - - config_set_var(&sc, "C=D"); - config_set_var(&sc, "A=B"); - - REQUIRE(sc.var_list->name[0] == 'A'); - REQUIRE(sc.var_list->value[0] == 'B'); -} - -// FIXIT-L missing CHECKs / REQUIREs -TEST_CASE("config_set_var-duplicate-error", "[vars]") -{ - SnortConfig sc; - config_set_var(&sc, "A=B"); -} - -TEST_CASE("config_set_var-no_equals_sign-error", "[vars]") -{ - SnortConfig sc; - config_set_var(&sc, "A"); -} - -#endif - diff --git a/src/parser/vars.h b/src/parser/vars.h index 2d125c35c..4b733f0cc 100644 --- a/src/parser/vars.h +++ b/src/parser/vars.h @@ -29,21 +29,6 @@ namespace snort struct SnortConfig; } -//------------------------------------------------------------------------- -// var node stuff -//------------------------------------------------------------------------- - -struct VarNode -{ - char* name; - char* value; - char* line; - VarNode* next; -}; - -void config_set_var(snort::SnortConfig*, const char*); -void FreeVarList(VarNode*); - //------------------------------------------------------------------------- // var table stuff //------------------------------------------------------------------------- @@ -61,12 +46,11 @@ struct VarEntry VarEntry* next; }; -VarEntry* VarDefine(snort::SnortConfig*, const char* name, const char* value); -int PortVarDefine(snort::SnortConfig*, const char* name, const char* s); +void ParsePathVar(const char* name, const char* value); +void ParsePortVar(const char* name, const char* value); VarEntry* VarAlloc(); void DeleteVars(VarEntry* var_table); -void AddVarToTable(snort::SnortConfig*, const char*, const char*); enum VarType { @@ -77,10 +61,10 @@ enum VarType int VarIsIpAddr(vartable_t* ip_vartable, const char* value); int VarIsIpList(vartable_t* ip_vartable, const char* value); -void DisallowCrossTableDuplicateVars(snort::SnortConfig*, const char* name, VarType var_type); +void DisallowCrossTableDuplicateVars(const char* name, VarType var_type); -const char* VarSearch(snort::SnortConfig*, const char* name); -const char* ExpandVars(snort::SnortConfig*, const char* string); +const char* VarSearch(const char* name); +const char* ExpandVars(const char* string); #endif diff --git a/src/ports/port_var_table.cc b/src/ports/port_var_table.cc index 06dffaa3b..848ccf589 100644 --- a/src/ports/port_var_table.cc +++ b/src/ports/port_var_table.cc @@ -86,14 +86,14 @@ int PortVarTableAdd(PortVarTable* h, PortObject* po) return -1; } -PortObject* PortVarTableFind(PortVarTable* h, const char* name) +PortObject* PortVarTableFind(PortVarTable* h, const char* name, bool add_if_not_found) { if (!h || !name) return nullptr; PortObject* po = (PortObject*)h->find(name); - if ( !po and SnortConfig::get_conf()->dump_rule_info() and strstr(name, "PORT") ) + if ( !po and SnortConfig::get_conf()->dump_rule_info() and add_if_not_found ) { po = PortObjectNew(); po->name = snort_strdup(name); diff --git a/src/ports/port_var_table.h b/src/ports/port_var_table.h index 7babca35d..a2acc1d80 100644 --- a/src/ports/port_var_table.h +++ b/src/ports/port_var_table.h @@ -41,7 +41,7 @@ typedef snort::GHash PortVarTable; PortVarTable* PortVarTableCreate(); int PortVarTableFree(PortVarTable* pvt); int PortVarTableAdd(PortVarTable* pvt, PortObject* po); -PortObject* PortVarTableFind(PortVarTable* pvt, const char* name); +PortObject* PortVarTableFind(PortVarTable* pvt, const char* name, bool add_if_not_found = false); #endif diff --git a/tools/snort2lua/data/data_types/dt_var.cc b/tools/snort2lua/data/data_types/dt_var.cc index ee880bbfc..129d29c71 100644 --- a/tools/snort2lua/data/data_types/dt_var.cc +++ b/tools/snort2lua/data/data_types/dt_var.cc @@ -140,18 +140,18 @@ static inline void print_newline(std::ostream& out, std::ostream& operator<<(std::ostream& out, const Variable& var) { - std::string whitespace; + std::string whitespace = + ( var.print_whitespace && var.depth ) ? std::string(var.depth * 4, ' ') : ""; + bool first_var = true; std::size_t count = 0; - for (int i = 0; i < var.depth; i++) - whitespace += " "; - - out << (var.print_whitespace ? whitespace : "") << var.name << " = "; + if ( !var.comment.empty() ) + out << whitespace << "-- " << var.comment << "\n"; - if ( var.print_whitespace ) - count += whitespace.size(); + out << whitespace << var.name << " = "; + count += whitespace.size(); count += var.name.size() + 3; if ( var.print_whitespace ) diff --git a/tools/snort2lua/data/data_types/dt_var.h b/tools/snort2lua/data/data_types/dt_var.h index 6c05f3e84..0915cf7b7 100644 --- a/tools/snort2lua/data/data_types/dt_var.h +++ b/tools/snort2lua/data/data_types/dt_var.h @@ -32,10 +32,12 @@ public: Variable(const std::string& name, int depth = 0); virtual ~Variable(); - inline const std::string& get_name() { return name; } + inline const std::string& get_name() const { return name; } std::string get_value(DataApi*); bool add_value(std::string); void set_value(const std::string&, bool quoted); + void set_comment(const std::string& c) + { comment = c; } void set_print_whitespace(bool w) { print_whitespace = w; } @@ -53,6 +55,7 @@ private: std::vector vars; std::string name; + std::string comment; int depth; bool print_whitespace = true; static const std::size_t max_line_length = 77; // leave room for additional text diff --git a/tools/snort2lua/data/dt_data.cc b/tools/snort2lua/data/dt_data.cc index 6818eef65..0a33a6bb2 100644 --- a/tools/snort2lua/data/dt_data.cc +++ b/tools/snort2lua/data/dt_data.cc @@ -60,9 +60,9 @@ DataApi::~DataApi() std::string DataApi::translate_variable(const std::string& var_name) { - for (auto v : vars) - if (var_name == v->get_name()) - return v->get_value(this); + auto v = find_var(var_name); + if ( v != vars.end() ) + return (*v)->get_value(this); return std::string(); } @@ -242,6 +242,12 @@ std::string DataApi::get_file_line() return error_string; } +var_it DataApi::find_var(const std::string& name) const +{ + return std::find_if(vars.begin(), vars.end(), + [&](const Variable* v){ return v->get_name() == name; }); +} + void DataApi::error(const std::string& error) { errors->add_text(error); @@ -263,32 +269,66 @@ void DataApi::failed_conversion(const std::istringstream& stream, const std::str errors->add_text("^^^^ unknown_syntax=" + unknown_option); } -static bool is_local_variable(const std::string& name) +void DataApi::set_variable(const std::string& name, const std::string& value, bool quoted) { - 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; + Variable* var = new Variable(name); + vars.push_back(var); + var->set_value(value, quoted); } -void DataApi::set_variable(const std::string& name, const std::string& value, bool quoted) +bool DataApi::add_net_variable(const std::string& name, const std::string& value) { - if (is_local_variable(name)) - local_vars.push_back(name); + auto v = find_var(name); + if ( v != vars.end() ) + return (*v)->add_value(value); + + net_vars.push_back(name); Variable* var = new Variable(name); vars.push_back(var); - var->set_value(value, quoted); + return var->add_value(value); } -bool DataApi::add_variable(const std::string& name, const std::string& value) +bool DataApi::add_path_variable(const std::string& name, const std::string& value) { - for (auto v : vars) - if (name == v->get_name()) - return v->add_value(value); + auto v = find_var(name); + if ( v != vars.end() ) + return (*v)->add_value(value); + + Variable* var = new Variable(name); + + // Since a user may specify an IP address, port or path variable with 'var' and it's valid for + // Snort2 we attempt to detect type based on the suffix + if ( name.find("PORT_") != std::string::npos || name.find("_PORT") != std::string::npos ) + { + var->set_comment("treated as portvar"); + port_vars.push_back(name); + } + else if ( name.find("NET_") != std::string::npos || name.find("_NET") != std::string::npos + || name.find("SERVER_") != std::string::npos || name.find("_SERVER") != std::string::npos ) + { + var->set_comment("treated as ipvar"); + net_vars.push_back(name); + } + else if ( name.find("PATH_") != std::string::npos || name.find("_PATH") != std::string::npos ) + { + var->set_comment("treated as path var"); + path_vars.push_back(name); + } + else + var->set_comment("treated as global var"); - if (is_local_variable(name)) - local_vars.push_back(name); + vars.push_back(var); + return var->add_value(value); +} + +bool DataApi::add_port_variable(const std::string& name, const std::string& value) +{ + auto v = find_var(name); + if ( v != vars.end() ) + return (*v)->add_value(value); + + port_vars.push_back(name); Variable* var = new Variable(name); vars.push_back(var); @@ -355,14 +395,27 @@ void DataApi::print_unsupported(std::ostream& out) const out << (*unsupported) << "\n"; } +static void print_vars(std::ostream& out, const std::string& name, + const std::vector& vars) +{ + if ( vars.empty() ) + return; + + out << " " << name << " =\n {\n"; + for ( const auto& v : vars ) + out << " " << v << " = " << v << ",\n"; + out << " },\n"; +} + void DataApi::print_local_variables(std::ostream& out) const { - if (local_vars.empty()) + if ( !has_local_vars() ) return; out << "local_variables =\n{\n"; - for (const auto& v : local_vars) - out << " " << v << " = " << v << ",\n"; + print_vars(out, "nets", net_vars); + print_vars(out, "paths", path_vars); + print_vars(out, "ports", port_vars); out << "}\n\n"; } diff --git a/tools/snort2lua/data/dt_data.h b/tools/snort2lua/data/dt_data.h index a6f3a2b0f..ca9381851 100644 --- a/tools/snort2lua/data/dt_data.h +++ b/tools/snort2lua/data/dt_data.h @@ -50,6 +50,8 @@ class Variable; class Comments; class DataApi; +using var_it = std::vector::const_iterator; + class DataApi { public: @@ -95,7 +97,7 @@ public: { return vars.empty() && includes.empty(); } bool has_local_vars() const - { return !local_vars.empty(); } + { return !net_vars.empty() or !path_vars.empty() or !port_vars.empty(); } // functions specifically useful when parsing includes. // allows for easy swapping of data. These two functions @@ -109,7 +111,9 @@ public: // add a variable to this file void set_variable(const std::string& name, const std::string& value, bool quoted); - bool add_variable(const std::string& name, const std::string& value); + bool add_net_variable(const std::string& name, const std::string& value); + bool add_path_variable(const std::string& name, const std::string& value); + bool add_port_variable(const std::string& name, const std::string& value); // add a Snort style include file bool add_include_file(const std::string& name); // add a 'comment' to the Lua file. should ONLY be used when @@ -130,6 +134,10 @@ public: void set_current_line(unsigned line) { current_line = line; } +private: + std::string get_file_line(); + var_it find_var(const std::string& name) const; + private: enum class PrintMode { @@ -145,7 +153,9 @@ private: std::vector vars; std::vector includes; - std::vector local_vars; + std::vector net_vars; + std::vector path_vars; + std::vector port_vars; Comments* comments; Comments* errors; Comments* unsupported; @@ -153,8 +163,6 @@ private: bool curr_data_bad = false; // keep track whether current 'conversion' is already bad const std::string* current_file = nullptr; unsigned current_line = 0; - - std::string get_file_line(); }; #endif diff --git a/tools/snort2lua/keyword_states/kws_var.cc b/tools/snort2lua/keyword_states/kws_var.cc index 54f4acb88..ca7b1e765 100644 --- a/tools/snort2lua/keyword_states/kws_var.cc +++ b/tools/snort2lua/keyword_states/kws_var.cc @@ -24,19 +24,8 @@ #include "helpers/converter.h" #include "helpers/s2l_util.h" -namespace keywords -{ -namespace -{ -class Var : public ConversionState -{ -public: - Var(Converter& c) : ConversionState(c) { } - bool convert(std::istringstream& data) override; -}; -} // namespace - -bool Var::convert(std::istringstream& data_stream) +static bool var_convert(std::istringstream& data_stream, DataApi& data_api, + bool (*add_var)(const std::string&, const std::string&, DataApi&)) { std::string ports; // cv.print_line(data_stream); std::string keyword; @@ -68,39 +57,86 @@ bool Var::convert(std::istringstream& data_stream) util::split(ports, ',', port_list); for (const std::string& elem : port_list) - retval = data_api.add_variable(keyword, elem) && retval; + retval = add_var(keyword, elem, data_api) && retval; return retval; } else { - return data_api.add_variable(keyword, ports); + return add_var(keyword, ports, data_api); } } +namespace keywords +{ +namespace +{ +class NetVar : public ConversionState +{ +public: + NetVar(Converter& c) : ConversionState(c) { } + bool convert(std::istringstream& data_stream) override + { + return var_convert(data_stream, data_api, + [](const std::string& name, const std::string& net, DataApi& d_api) + { return d_api.add_net_variable(name, net); }); + } +}; + +class PathVar : public ConversionState +{ +public: + PathVar(Converter& c) : ConversionState(c) { } + bool convert(std::istringstream& data_stream) override + { + return var_convert(data_stream, data_api, + [](const std::string& name, const std::string& path, DataApi& d_api) + { return d_api.add_path_variable(name, path); }); + } +}; + +class PortVar : public ConversionState +{ +public: + PortVar(Converter& c) : ConversionState(c) { } + bool convert(std::istringstream& data_stream) override + { + return var_convert(data_stream, data_api, + [](const std::string& name, const std::string& port, DataApi& d_api) + { return d_api.add_port_variable(name, port); }); + } +}; +} // namespace + /************************** ******* A P I *********** **************************/ -static ConversionState* ctor(Converter& c) -{ return new Var(c); } +static ConversionState* ctor_net_var(Converter& c) +{ return new NetVar(c); } + +static ConversionState* ctor_path_var(Converter& c) +{ return new PathVar(c); } + +static ConversionState* ctor_port_var(Converter& c) +{ return new PortVar(c); } static const ConvertMap keyword_portvar = { "portvar", - ctor, + ctor_port_var, }; static const ConvertMap keyword_ipvar = { "ipvar", - ctor, + ctor_net_var, }; static const ConvertMap keyword_var = { "var", - ctor, + ctor_path_var, }; const ConvertMap* portvar_map = &keyword_portvar; -- 2.47.3