From: Yurii Chalov -X (ychalov - SOFTSERVE INC at Cisco) Date: Fri, 22 Dec 2023 18:18:39 +0000 (+0000) Subject: Pull request #4125: main: fix inconsistent lua variables assignment X-Git-Tag: 3.1.78.0~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=40813cb26e366ba80083f358a5b48daf27d7e712;p=thirdparty%2Fsnort3.git Pull request #4125: main: fix inconsistent lua variables assignment Merge in SNORT/snort3 from ~YCHALOV/snort3:lua_variable_fix to master Squashed commit of the following: commit d05cfa28ecd64935bfb573312eba89bf96b2ca8d Author: Yurii Chalov Date: Mon Dec 4 11:05:35 2023 +0100 main: fix inconsistent lua variables assignment --- diff --git a/src/main/modules.cc b/src/main/modules.cc index 422ea86c4..0d047a2fa 100644 --- a/src/main/modules.cc +++ b/src/main/modules.cc @@ -55,6 +55,7 @@ #include "parser/parse_conf.h" #include "parser/parse_ip.h" #include "parser/parser.h" +#include "parser/var_dependency.h" #include "parser/vars.h" #include "payload_injector/payload_injector_module.h" #include "profiler/profiler_module.h" @@ -1128,6 +1129,11 @@ bool IpsModule::end(const char* fqn, int idx, SnortConfig* sc) p->includer = ModuleManager::get_includer("ips"); sc->policy_map->set_user_ips(p); } + else if (!idx and !strcmp(fqn, "ips.variables.nets")) + resolve_nets(); + else if (!idx and !strcmp(fqn, "ips.variables.ports")) + resolve_ports(); + return true; } diff --git a/src/parser/CMakeLists.txt b/src/parser/CMakeLists.txt index c3658eaa6..aa2eb2904 100644 --- a/src/parser/CMakeLists.txt +++ b/src/parser/CMakeLists.txt @@ -22,6 +22,8 @@ add_library (parser OBJECT cmd_line.h config_file.cc config_file.h + var_dependency.cc + var_dependency.h vars.cc vars.h ) diff --git a/src/parser/parse_conf.cc b/src/parser/parse_conf.cc index f10dbac38..0a712b7ae 100644 --- a/src/parser/parse_conf.cc +++ b/src/parser/parse_conf.cc @@ -44,6 +44,7 @@ #include "config_file.h" #include "parser.h" #include "parse_stream.h" +#include "var_dependency.h" #include "vars.h" using namespace snort; @@ -223,7 +224,7 @@ void parse_include(SnortConfig* sc, const char* arg) pop_parse_location(); } -void ParseIpVar(const char* var, const char* value) +bool ParseIpVar(const char* var, const char* value) { int ret; IpsPolicy* p = get_ips_policy(); @@ -236,7 +237,7 @@ void ParseIpVar(const char* var, const char* value) { case SFIP_ARG_ERR: ParseError("the following is not allowed: %s.", value); - return; + return false; case SFIP_DUPLICATE: ParseWarning(WARN_VARS, "Var '%s' redefined.", var); @@ -246,17 +247,26 @@ void ParseIpVar(const char* var, const char* value) ParseError("negated IP ranges that are more general than " "non-negated ranges are not allowed. Consider " "inverting the logic in %s.", var); - return; + return false; case SFIP_NOT_ANY: ParseError("!any is not allowed in %s.", var); - return; + return false; + + case SFIP_LOOKUP_FAILURE: + if (is_resolving_nets()) + ParseError("failed to parse the IP address: %s.", value); + else + push_to_weak_nets(var, value); + return false; default: ParseError("failed to parse the IP address: %s.", value); - return; + return false; } } + + return true; } static void add_service_to_otn_helper(SnortConfig* sc, OptTreeNode* otn, const char* svc_name) diff --git a/src/parser/parse_conf.h b/src/parser/parse_conf.h index 56cc2116f..89edb62bb 100644 --- a/src/parser/parse_conf.h +++ b/src/parser/parse_conf.h @@ -41,7 +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, bool ips_policy = true); -void ParseIpVar(const char* name, const char* value); +bool 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/var_dependency.cc b/src/parser/var_dependency.cc new file mode 100644 index 000000000..435a0b7c9 --- /dev/null +++ b/src/parser/var_dependency.cc @@ -0,0 +1,160 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2023-2023 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// var_dependency.cc author Yurii Chalov + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "var_dependency.h" + +#include +#include + +#include "parser/parse_conf.h" +#include "parser/vars.h" + +struct WeakVariable +{ + std::string var_name; + std::string value; + bool is_resolved; + bool is_visited; + + WeakVariable(const char* _var_name, const char* _value) + : var_name(_var_name), value(_value), is_resolved(false), is_visited(false) {} +}; + +typedef bool (*parse_callback)(const char*, const char*); + +static std::list weak_nets, weak_ports; + +static bool resolving_nets = false; +static bool resolving_ports = false; + +static std::list extract_variable_names(const char* input) +{ + std::list variable_names; + + for (size_t begin = 0; input[begin] != '\0'; begin++) + { + if (input[begin] != '$') + continue; + + size_t end = 0; + for (end = begin + 1; input[end] != '\0' and (isalnum(input[end]) or input[end] == '_'); end++) + ; + + std::string variable(input + begin + 1, end - begin - 1); + variable_names.push_back(variable); + begin = end - 1; + } + + return variable_names; +} + +static std::list find_over_table(WeakVariable* var, const std::list& vars) +{ + std::list res; + std::list names = extract_variable_names(var->value.c_str()); + + for (const auto& name : names) + { + for (auto v : vars) + { + if (!v->is_visited and (v->var_name == name)) + { + res.push_back(v); + break; + } + } + } + + return res; +} + +static bool set_variable(WeakVariable* var, std::list& vars, parse_callback parse_variable) +{ + std::list found_vars; + + found_vars = find_over_table(var, vars); + for (auto found_var : found_vars) + { + found_var->is_visited = true; + set_variable(found_var, vars, parse_variable); + } + + if (var->is_resolved) + return true; + + var->is_resolved = true; + + return parse_variable(var->var_name.c_str(), var->value.c_str()); +} + +static void resolve(std::list& vars, parse_callback parse_variable) +{ + for (auto var : vars) + { + if (!var->is_resolved and !set_variable(var, vars, parse_variable)) + return; + } +} + +static void clear_list(std::list& vars) +{ + for (auto& item : vars) + delete item; + + vars.clear(); +} + +void resolve_nets() +{ + resolving_nets = true; + resolve(weak_nets, ParseIpVar); + resolving_nets = false; + clear_list(weak_nets); +} + +void resolve_ports() +{ + resolving_ports = true; + resolve(weak_ports, ParsePortVar); + resolving_ports = false; + clear_list(weak_ports); +} + +bool is_resolving_nets() { return resolving_nets; } +bool is_resolving_ports() { return resolving_ports; } + +static void push_to_list(std::list& vars, const char* var_name, const char* val) +{ + vars.push_back(new WeakVariable(var_name, val)); +} + +void push_to_weak_nets(const char* var_name, const char* val) +{ + push_to_list(weak_nets, var_name, val); +} + +void push_to_weak_ports(const char* var_name, const char* val) +{ + push_to_list(weak_ports, var_name, val); +} diff --git a/src/parser/var_dependency.h b/src/parser/var_dependency.h new file mode 100644 index 000000000..eb4f87402 --- /dev/null +++ b/src/parser/var_dependency.h @@ -0,0 +1,33 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2023-2023 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// var_dependency.h author Yurii Chalov + +#ifndef VAR_DEPENDENCY_H +#define VAR_DEPENDENCY_H + +void resolve_nets(); +void resolve_ports(); + +bool is_resolving_nets(); +bool is_resolving_ports(); + +void push_to_weak_nets(const char* var_name, const char* val); +void push_to_weak_ports(const char* var_name, const char* val); + +#endif diff --git a/src/parser/vars.cc b/src/parser/vars.cc index a8f2a35d0..e130851cd 100644 --- a/src/parser/vars.cc +++ b/src/parser/vars.cc @@ -30,6 +30,7 @@ #include "utils/util_cstring.h" #include "parse_ports.h" +#include "var_dependency.h" #ifdef UNIT_TEST #include "catch/snort_catch.h" @@ -41,7 +42,7 @@ using namespace snort; // var table stuff //------------------------------------------------------------------------- -void ParsePortVar(const char* name, const char* value) +bool ParsePortVar(const char* name, const char* value) { PortObject* po; POParser pop; @@ -67,9 +68,16 @@ void ParsePortVar(const char* name, const char* value) 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,value,pop.pos,"^"); + if (is_resolving_ports()) + { + const char* errstr = PortObjectParseError(&pop); + ParseAbort("PortVar Parse error: (pos=%d,error=%s)\n>>%s\n>>%*s.", + pop.pos,errstr,value,pop.pos,"^"); + } + else + push_to_weak_ports(name, value); + + return false; } } @@ -85,6 +93,8 @@ void ParsePortVar(const char* name, const char* value) ParseWarning(WARN_VARS, "PortVar '%s', already defined.", po->name); PortObjectFree(po); } + + return true; } VarEntry* VarAlloc() diff --git a/src/parser/vars.h b/src/parser/vars.h index 60883ca42..ae234847e 100644 --- a/src/parser/vars.h +++ b/src/parser/vars.h @@ -48,7 +48,7 @@ struct VarEntry }; void ParsePathVar(const char* name, const char* value); -void ParsePortVar(const char* name, const char* value); +bool ParsePortVar(const char* name, const char* value); VarEntry* VarAlloc(); void DeleteVars(VarEntry* var_table); diff --git a/src/sfip/sf_vartable.cc b/src/sfip/sf_vartable.cc index d67a4263e..efc6821d1 100644 --- a/src/sfip/sf_vartable.cc +++ b/src/sfip/sf_vartable.cc @@ -218,6 +218,11 @@ SfIpRet sfvt_add_str(vartable_t* table, const char* str, sfip_var_t** ipret) /* Creates the variable */ var = sfvar_alloc(table, str, &status); + + // If the alias is not available, return SFIP_LOOKUP_FAILURE to resolve the variable later + if (status == SFIP_LOOKUP_FAILURE) + return status; + if ( var == nullptr ) { return SFIP_FAILURE;