#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"
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;
}
cmd_line.h
config_file.cc
config_file.h
+ var_dependency.cc
+ var_dependency.h
vars.cc
vars.h
)
#include "config_file.h"
#include "parser.h"
#include "parse_stream.h"
+#include "var_dependency.h"
#include "vars.h"
using namespace snort;
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();
{
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);
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)
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*);
--- /dev/null
+//--------------------------------------------------------------------------
+// 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);
+}
--- /dev/null
+//--------------------------------------------------------------------------
+// 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
#include "utils/util_cstring.h"
#include "parse_ports.h"
+#include "var_dependency.h"
#ifdef UNIT_TEST
#include "catch/snort_catch.h"
// var table stuff
//-------------------------------------------------------------------------
-void ParsePortVar(const char* name, const char* value)
+bool ParsePortVar(const char* name, const char* value)
{
PortObject* po;
POParser pop;
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;
}
}
ParseWarning(WARN_VARS, "PortVar '%s', already defined.", po->name);
PortObjectFree(po);
}
+
+ return true;
}
VarEntry* VarAlloc()
};
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);
/* 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;