mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
412 lines
14 KiB
C
412 lines
14 KiB
C
/* Copyright (C) 2007-2010 Open Information Security Foundation
|
|
*
|
|
* You can copy, redistribute or modify this Program under the terms of
|
|
* the GNU General Public License version 2 as published by the Free
|
|
* Software Foundation.
|
|
*
|
|
* 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
|
|
* version 2 along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
/**
|
|
* \file
|
|
*
|
|
* \author Anoop Saldanha <anoopsaldanha@gmail.com>
|
|
*
|
|
* Rule variable utility functions
|
|
*/
|
|
|
|
#include "suricata-common.h"
|
|
#include "conf.h"
|
|
#include "conf-yaml-loader.h"
|
|
|
|
#include "detect.h"
|
|
#include "detect-content.h"
|
|
#include "detect-parse.h"
|
|
#include "detect-engine.h"
|
|
#include "detect-engine-mpm.h"
|
|
|
|
#include "util-rule-vars.h"
|
|
#include "util-enum.h"
|
|
#include "util-debug.h"
|
|
#include "util-unittest.h"
|
|
|
|
/** An enum-string map, that maps the different vars type in the yaml conf
|
|
* type with the mapping path in the yaml conf file */
|
|
SCEnumCharMap sc_rule_vars_type_map[ ] = {
|
|
{ "vars.address-groups", SC_RULE_VARS_ADDRESS_GROUPS },
|
|
{ "vars.port-groups", SC_RULE_VARS_PORT_GROUPS }
|
|
};
|
|
|
|
/**
|
|
* \internal
|
|
* \brief Retrieves a value for a yaml mapping. The sequence from the yaml
|
|
* conf file, from which the conf value has to be retrieved can be
|
|
* specified by supplying a SCRuleVarsType enum. The string mapping
|
|
* for each of the SCRuleVarsType is present in sc_rule_vars_type_map.
|
|
*
|
|
* \param conf_var_name Pointer to a character string containing the conf var
|
|
* name, whose value has to be retrieved from the yaml
|
|
* conf file.
|
|
* \param conf_vars_type Holds an enum value that indicates the kind of yaml
|
|
* mapping that has to be retrieved. Can be one of the
|
|
* values in SCRuleVarsType.
|
|
*
|
|
* \retval conf_var_name_value Pointer to the string containing the conf value
|
|
* on success; NULL on failure.
|
|
*/
|
|
const char *SCRuleVarsGetConfVar(const DetectEngineCtx *de_ctx,
|
|
const char *conf_var_name,
|
|
SCRuleVarsType conf_vars_type)
|
|
{
|
|
SCEnter();
|
|
|
|
const char *conf_var_type_name = NULL;
|
|
char conf_var_full_name[2048];
|
|
const char *conf_var_full_name_value = NULL;
|
|
|
|
if (conf_var_name == NULL)
|
|
goto end;
|
|
|
|
while (conf_var_name[0] != '\0' && isspace((unsigned char)conf_var_name[0])) {
|
|
conf_var_name++;
|
|
}
|
|
|
|
(conf_var_name[0] == '$') ? conf_var_name++ : conf_var_name;
|
|
conf_var_type_name = SCMapEnumValueToName(conf_vars_type,
|
|
sc_rule_vars_type_map);
|
|
if (conf_var_type_name == NULL)
|
|
goto end;
|
|
|
|
if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) {
|
|
if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s.%s",
|
|
de_ctx->config_prefix, conf_var_type_name, conf_var_name) < 0) {
|
|
goto end;
|
|
}
|
|
} else {
|
|
if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s",
|
|
conf_var_type_name, conf_var_name) < 0) {
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
if (ConfGet(conf_var_full_name, &conf_var_full_name_value) != 1) {
|
|
SCLogError(SC_ERR_UNDEFINED_VAR, "Variable \"%s\" is not defined in "
|
|
"configuration file", conf_var_name);
|
|
goto end;
|
|
}
|
|
|
|
SCLogDebug("Value obtained from the yaml conf file, for the var "
|
|
"\"%s\" is \"%s\"", conf_var_name, conf_var_full_name_value);
|
|
|
|
end:
|
|
SCReturnCharPtr(conf_var_full_name_value);
|
|
}
|
|
|
|
|
|
/**********************************Unittests***********************************/
|
|
#ifdef UNITTESTS
|
|
|
|
static const char *dummy_conf_string =
|
|
"%YAML 1.1\n"
|
|
"---\n"
|
|
"\n"
|
|
"default-log-dir: /var/log/suricata\n"
|
|
"\n"
|
|
"logging:\n"
|
|
"\n"
|
|
" default-log-level: debug\n"
|
|
"\n"
|
|
" default-format: \"<%t> - <%l>\"\n"
|
|
"\n"
|
|
" default-startup-message: Your IDS has started.\n"
|
|
"\n"
|
|
" default-output-filter:\n"
|
|
"\n"
|
|
" output:\n"
|
|
"\n"
|
|
" - interface: console\n"
|
|
" log-level: info\n"
|
|
"\n"
|
|
" - interface: file\n"
|
|
" filename: /var/log/suricata.log\n"
|
|
"\n"
|
|
" - interface: syslog\n"
|
|
" facility: local5\n"
|
|
" format: \"%l\"\n"
|
|
"\n"
|
|
"pfring:\n"
|
|
"\n"
|
|
" interface: eth0\n"
|
|
"\n"
|
|
" clusterid: 99\n"
|
|
"\n"
|
|
"vars:\n"
|
|
"\n"
|
|
" address-groups:\n"
|
|
"\n"
|
|
" HOME_NET: \"[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:"
|
|
"13c5:5AFE::/64,2001:888:13c5:CAFE::/64]\"\n"
|
|
"\n"
|
|
" EXTERNAL_NET: \"[!192.168.0.0/16,2000::/3]\"\n"
|
|
"\n"
|
|
" HTTP_SERVERS: \"!192.168.0.0/16\"\n"
|
|
"\n"
|
|
" SMTP_SERVERS: \"!192.168.0.0/16\"\n"
|
|
"\n"
|
|
" SQL_SERVERS: \"!192.168.0.0/16\"\n"
|
|
"\n"
|
|
" DNS_SERVERS: any\n"
|
|
"\n"
|
|
" TELNET_SERVERS: any\n"
|
|
"\n"
|
|
" AIM_SERVERS: any\n"
|
|
"\n"
|
|
" port-groups:\n"
|
|
"\n"
|
|
" HTTP_PORTS: \"80:81,88\"\n"
|
|
"\n"
|
|
" SHELLCODE_PORTS: 80\n"
|
|
"\n"
|
|
" ORACLE_PORTS: 1521\n"
|
|
"\n"
|
|
" SSH_PORTS: 22\n"
|
|
"\n";
|
|
|
|
/**
|
|
* \test Check that valid address and port group vars are correctly retrieved
|
|
* from the configuration.
|
|
*/
|
|
static int SCRuleVarsPositiveTest01(void)
|
|
{
|
|
ConfCreateContextBackup();
|
|
ConfInit();
|
|
ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string));
|
|
|
|
/* check for address-groups */
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL, "$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS),
|
|
"[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:13c5:"
|
|
"5AFE::/64,2001:888:13c5:CAFE::/64]") == 0);
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL, "$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS),
|
|
"[!192.168.0.0/16,2000::/3]") == 0);
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL, "$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
|
|
"!192.168.0.0/16") == 0);
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL, "$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
|
|
"!192.168.0.0/16") == 0);
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL, "$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
|
|
"!192.168.0.0/16") == 0);
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL, "$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
|
|
"any") == 0);
|
|
FAIL_IF_NOT(
|
|
SCRuleVarsGetConfVar(NULL, "$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL, "$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
|
|
"any") == 0);
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL, "$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
|
|
"any") == 0);
|
|
|
|
/* Test that a leading space is stripped. */
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, " $AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL, " $AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
|
|
"any") == 0);
|
|
|
|
/* check for port-groups */
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL, "$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS),
|
|
"80:81,88") == 0);
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL, "$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS),
|
|
"80") == 0);
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL, "$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS),
|
|
"1521") == 0);
|
|
FAIL_IF_NOT(
|
|
SCRuleVarsGetConfVar(NULL, "$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL, "$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS), "22") == 0);
|
|
|
|
ConfDeInit();
|
|
ConfRestoreContextBackup();
|
|
PASS;
|
|
}
|
|
|
|
/**
|
|
* \test Check that invalid address and port groups are properly handled by the
|
|
* API.
|
|
*/
|
|
static int SCRuleVarsNegativeTest02(void)
|
|
{
|
|
ConfCreateContextBackup();
|
|
ConfInit();
|
|
ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string));
|
|
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HOME_NETW", SC_RULE_VARS_ADDRESS_GROUPS) == NULL);
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$home_net", SC_RULE_VARS_ADDRESS_GROUPS) == NULL);
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$TOMCAT_PORTSW", SC_RULE_VARS_PORT_GROUPS) == NULL);
|
|
FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$tomcat_ports", SC_RULE_VARS_PORT_GROUPS) == NULL);
|
|
|
|
ConfDeInit();
|
|
ConfRestoreContextBackup();
|
|
PASS;
|
|
}
|
|
|
|
/**
|
|
* \test Check that Signatures with valid address and port groups are parsed
|
|
* without any errors by the Signature parsing API.
|
|
*/
|
|
static int SCRuleVarsPositiveTest03(void)
|
|
{
|
|
ConfCreateContextBackup();
|
|
ConfInit();
|
|
ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string));
|
|
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
FAIL_IF_NULL(de_ctx);
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
Signature *s = DetectEngineAppendSig(de_ctx,
|
|
"alert tcp [$HTTP_SERVERS,$HOME_NET,192.168.2.5] $HTTP_PORTS -> $EXTERNAL_NET "
|
|
"[80,[!$HTTP_PORTS,$ORACLE_PORTS]] (msg:\"Rule Vars Test\"; sid:1;)");
|
|
FAIL_IF_NULL(s);
|
|
|
|
ConfDeInit();
|
|
ConfRestoreContextBackup();
|
|
DetectEngineCtxFree(de_ctx);
|
|
PASS;
|
|
}
|
|
|
|
/**
|
|
* \test Check that Signatures with invalid address and port groups, are
|
|
* are invalidated by the Singature parsing API.
|
|
*/
|
|
static int SCRuleVarsNegativeTest04(void)
|
|
{
|
|
ConfCreateContextBackup();
|
|
ConfInit();
|
|
ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string));
|
|
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
|
|
FAIL_IF_NULL(de_ctx);
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
Signature *s = DetectEngineAppendSig(
|
|
de_ctx, "alert tcp $HTTP_SERVER any -> any any (msg:\"Rule Vars Test\"; sid:1;)");
|
|
FAIL_IF_NOT_NULL(s);
|
|
s = DetectEngineAppendSig(
|
|
de_ctx, "alert tcp $http_servers any -> any any (msg:\"Rule Vars Test\"; sid:1;)");
|
|
FAIL_IF_NOT_NULL(s);
|
|
s = DetectEngineAppendSig(de_ctx,
|
|
"alert tcp $http_servers any -> any $HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)");
|
|
FAIL_IF_NOT_NULL(s);
|
|
s = DetectEngineAppendSig(de_ctx,
|
|
"alert tcp !$TELNET_SERVERS !80 -> any !$SSH_PORTS (msg:\"Rule Vars Test\"; sid:1;)");
|
|
FAIL_IF_NOT_NULL(s);
|
|
|
|
DetectEngineCtxFree(de_ctx);
|
|
ConfDeInit();
|
|
ConfRestoreContextBackup();
|
|
PASS;
|
|
}
|
|
|
|
static const char *dummy_mt_conf_string =
|
|
"%YAML 1.1\n"
|
|
"---\n"
|
|
"vars:\n"
|
|
"\n"
|
|
" address-groups:\n"
|
|
"\n"
|
|
" HOME_NET: \"[1.2.3.4]\"\n"
|
|
" port-groups:\n"
|
|
" HTTP_PORTS: \"12345\"\n"
|
|
"multi-detect:\n"
|
|
" 0:\n"
|
|
" vars:\n"
|
|
"\n"
|
|
" address-groups:\n"
|
|
"\n"
|
|
" HOME_NET: \"[8.8.8.8]\"\n"
|
|
" port-groups:\n"
|
|
" HTTP_PORTS: \"54321\"\n"
|
|
"\n";
|
|
|
|
/**
|
|
* \test Check that valid address and port group vars are correctly retrieved
|
|
* from the configuration.
|
|
*/
|
|
static int SCRuleVarsMTest01(void)
|
|
{
|
|
int result = 0;
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
|
|
ConfCreateContextBackup();
|
|
ConfInit();
|
|
ConfYamlLoadString(dummy_mt_conf_string, strlen(dummy_mt_conf_string));
|
|
|
|
if ( (de_ctx = DetectEngineCtxInit()) == NULL)
|
|
return 0;
|
|
de_ctx->flags |= DE_QUIET;
|
|
snprintf(de_ctx->config_prefix, sizeof(de_ctx->config_prefix),
|
|
"multi-detect.0");
|
|
|
|
/* check for address-groups */
|
|
result = (SCRuleVarsGetConfVar(de_ctx,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(de_ctx,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS),
|
|
"[8.8.8.8]") == 0);
|
|
if (result == 0)
|
|
goto end;
|
|
|
|
result = (SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS),
|
|
"[1.2.3.4]") == 0);
|
|
if (result == 0)
|
|
goto end;
|
|
|
|
/* check for port-groups */
|
|
result = (SCRuleVarsGetConfVar(de_ctx,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(de_ctx,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS),
|
|
"54321") == 0);
|
|
if (result == 0)
|
|
goto end;
|
|
|
|
result = (SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL &&
|
|
strcmp(SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS),
|
|
"12345") == 0);
|
|
if (result == 0)
|
|
goto end;
|
|
|
|
end:
|
|
ConfDeInit();
|
|
ConfRestoreContextBackup();
|
|
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
return result;
|
|
}
|
|
|
|
#endif /* UNITTESTS */
|
|
|
|
void SCRuleVarsRegisterTests(void)
|
|
{
|
|
#ifdef UNITTESTS
|
|
UtRegisterTest("SCRuleVarsPositiveTest01", SCRuleVarsPositiveTest01);
|
|
UtRegisterTest("SCRuleVarsNegativeTest02", SCRuleVarsNegativeTest02);
|
|
UtRegisterTest("SCRuleVarsPositiveTest03", SCRuleVarsPositiveTest03);
|
|
UtRegisterTest("SCRuleVarsNegativeTest04", SCRuleVarsNegativeTest04);
|
|
|
|
UtRegisterTest("SCRuleVarsMTest01", SCRuleVarsMTest01);
|
|
#endif
|
|
|
|
return;
|
|
}
|