]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4125: main: fix inconsistent lua variables assignment
authorYurii Chalov -X (ychalov - SOFTSERVE INC at Cisco) <ychalov@cisco.com>
Fri, 22 Dec 2023 18:18:39 +0000 (18:18 +0000)
committerOleksii. Shumeiko -X (oshumeik - SOFTSERVE INC at Cisco) <oshumeik@cisco.com>
Fri, 22 Dec 2023 18:18:39 +0000 (18:18 +0000)
Merge in SNORT/snort3 from ~YCHALOV/snort3:lua_variable_fix to master

Squashed commit of the following:

commit d05cfa28ecd64935bfb573312eba89bf96b2ca8d
Author: Yurii Chalov <ychalov@cisco.com>
Date:   Mon Dec 4 11:05:35 2023 +0100

    main: fix inconsistent lua variables assignment

src/main/modules.cc
src/parser/CMakeLists.txt
src/parser/parse_conf.cc
src/parser/parse_conf.h
src/parser/var_dependency.cc [new file with mode: 0644]
src/parser/var_dependency.h [new file with mode: 0644]
src/parser/vars.cc
src/parser/vars.h
src/sfip/sf_vartable.cc

index 422ea86c42871627a857552a365ad0f715e408e8..0d047a2fafc303d2c5cbf2f642c2889eeb605f81 100644 (file)
@@ -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;
 }
 
index c3658eaa66fb5e609e7ab122245cc2aa4fda81d2..aa2eb29043d55d6ac27c5700545e1a2dbbf86f4a 100644 (file)
@@ -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
 )
index f10dbac38888dffea9b874eef1ca2df5e979537f..0a712b7ae6c566c22c8b5d08a8402c3cfe1b5b32 100644 (file)
@@ -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)
index 56cc2116fd50bfcb2f6c171737c26a733fe92540..89edb62bb19870b17732385dd2fd7af5002b70c5 100644 (file)
@@ -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 (file)
index 0000000..435a0b7
--- /dev/null
@@ -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 <ychalov@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "var_dependency.h"
+
+#include <list>
+#include <string>
+
+#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<WeakVariable*> weak_nets, weak_ports;
+
+static bool resolving_nets = false;
+static bool resolving_ports = false;
+
+static std::list<std::string> extract_variable_names(const char* input)
+{
+    std::list<std::string> 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<WeakVariable*> find_over_table(WeakVariable* var, const std::list<WeakVariable*>& vars)
+{
+    std::list<WeakVariable*> res;
+    std::list<std::string> 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<WeakVariable*>& vars, parse_callback parse_variable)
+{
+    std::list<WeakVariable*> 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<WeakVariable*>& 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<WeakVariable*>& 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<WeakVariable*>& 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 (file)
index 0000000..eb4f874
--- /dev/null
@@ -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 <ychalov@cisco.com>
+
+#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
index a8f2a35d07abf4af8ac250bdb2ef8e46d5625500..e130851cd4dfeb72c2db2c731706534b968411f8 100644 (file)
@@ -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()
index 60883ca42707851c96f922b8b5e73401cfe701dd..ae234847e9b0dd1d1995bdd96894f63014f47bbc 100644 (file)
@@ -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);
index d67a4263e485f8487b73c4f4652ffbbd71ca08ec..efc6821d1bddda137dd679f00b7dffbae85ea1ea 100644 (file)
@@ -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;