Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/util-rule-vars.c
Line
Count
Source
1
/* Copyright (C) 2007-2010 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
/**
19
 * \file
20
 *
21
 *  \author Anoop Saldanha <anoopsaldanha@gmail.com>
22
 *
23
 *  Rule variable utility functions
24
 */
25
26
#include "suricata-common.h"
27
#include "conf.h"
28
#include "conf-yaml-loader.h"
29
30
#include "detect.h"
31
#include "detect-content.h"
32
#include "detect-parse.h"
33
#include "detect-engine.h"
34
#include "detect-engine-mpm.h"
35
36
#include "util-rule-vars.h"
37
#include "util-enum.h"
38
#include "util-debug.h"
39
#include "util-unittest.h"
40
41
/** An enum-string map, that maps the different vars type in the yaml conf
42
 *  type with the mapping path in the yaml conf file */
43
SCEnumCharMap sc_rule_vars_type_map[ ] = {
44
    { "vars.address-groups", SC_RULE_VARS_ADDRESS_GROUPS },
45
    { "vars.port-groups",    SC_RULE_VARS_PORT_GROUPS }
46
};
47
48
/**
49
 * \internal
50
 * \brief Retrieves a value for a yaml mapping.  The sequence from the yaml
51
 *        conf file, from which the conf value has to be retrieved can be
52
 *        specified by supplying a SCRuleVarsType enum.  The string mapping
53
 *        for each of the SCRuleVarsType is present in sc_rule_vars_type_map.
54
 *
55
 * \param conf_var_name  Pointer to a character string containing the conf var
56
 *                       name, whose value has to be retrieved from the yaml
57
 *                       conf file.
58
 * \param conf_vars_type Holds an enum value that indicates the kind of yaml
59
 *                       mapping that has to be retrieved.  Can be one of the
60
 *                       values in SCRuleVarsType.
61
 *
62
 * \retval conf_var_name_value Pointer to the string containing the conf value
63
 *                             on success; NULL on failure.
64
 */
65
const char *SCRuleVarsGetConfVar(const DetectEngineCtx *de_ctx,
66
                           const char *conf_var_name,
67
                           SCRuleVarsType conf_vars_type)
68
18.3k
{
69
18.3k
    SCEnter();
70
71
18.3k
    const char *conf_var_type_name = NULL;
72
18.3k
    char conf_var_full_name[2048];
73
18.3k
    const char *conf_var_full_name_value = NULL;
74
75
18.3k
    if (conf_var_name == NULL)
76
0
        goto end;
77
78
21.9k
    while (conf_var_name[0] != '\0' && isspace((unsigned char)conf_var_name[0])) {
79
3.55k
        conf_var_name++;
80
3.55k
    }
81
82
18.3k
    (conf_var_name[0] == '$') ? conf_var_name++ : conf_var_name;
83
18.3k
    conf_var_type_name = SCMapEnumValueToName(conf_vars_type,
84
18.3k
                                              sc_rule_vars_type_map);
85
18.3k
    if (conf_var_type_name == NULL)
86
0
        goto end;
87
88
18.3k
    if (de_ctx != NULL && strlen(de_ctx->config_prefix) > 0) {
89
0
        if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s.%s",
90
0
                    de_ctx->config_prefix, conf_var_type_name, conf_var_name) < 0) {
91
0
            goto end;
92
0
        }
93
18.3k
    } else {
94
18.3k
        if (snprintf(conf_var_full_name, sizeof(conf_var_full_name), "%s.%s",
95
18.3k
                    conf_var_type_name, conf_var_name) < 0) {
96
0
            goto end;
97
0
        }
98
18.3k
    }
99
100
18.3k
    if (ConfGet(conf_var_full_name, &conf_var_full_name_value) != 1) {
101
18.3k
        SCLogError("Variable \"%s\" is not defined in "
102
18.3k
                   "configuration file",
103
18.3k
                conf_var_name);
104
18.3k
        goto end;
105
18.3k
    }
106
107
0
    SCLogDebug("Value obtained from the yaml conf file, for the var "
108
0
               "\"%s\" is \"%s\"", conf_var_name, conf_var_full_name_value);
109
110
18.3k
 end:
111
18.3k
    SCReturnCharPtr(conf_var_full_name_value);
112
0
}
113
114
115
/**********************************Unittests***********************************/
116
#ifdef UNITTESTS
117
118
static const char *dummy_conf_string =
119
    "%YAML 1.1\n"
120
    "---\n"
121
    "\n"
122
    "default-log-dir: /var/log/suricata\n"
123
    "\n"
124
    "logging:\n"
125
    "\n"
126
    "  default-log-level: debug\n"
127
    "\n"
128
    "  default-format: \"<%t> - <%l>\"\n"
129
    "\n"
130
    "  default-startup-message: Your IDS has started.\n"
131
    "\n"
132
    "  default-output-filter:\n"
133
    "\n"
134
    "  output:\n"
135
    "\n"
136
    "  - interface: console\n"
137
    "    log-level: info\n"
138
    "\n"
139
    "  - interface: file\n"
140
    "    filename: /var/log/suricata.log\n"
141
    "\n"
142
    "  - interface: syslog\n"
143
    "    facility: local5\n"
144
    "    format: \"%l\"\n"
145
    "\n"
146
    "pfring:\n"
147
    "\n"
148
    "  interface: eth0\n"
149
    "\n"
150
    "  clusterid: 99\n"
151
    "\n"
152
    "vars:\n"
153
    "\n"
154
    "  address-groups:\n"
155
    "\n"
156
    "    HOME_NET: \"[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:"
157
    "13c5:5AFE::/64,2001:888:13c5:CAFE::/64]\"\n"
158
    "\n"
159
    "    EXTERNAL_NET: \"[!192.168.0.0/16,2000::/3]\"\n"
160
    "\n"
161
    "    HTTP_SERVERS: \"!192.168.0.0/16\"\n"
162
    "\n"
163
    "    SMTP_SERVERS: \"!192.168.0.0/16\"\n"
164
    "\n"
165
    "    SQL_SERVERS: \"!192.168.0.0/16\"\n"
166
    "\n"
167
    "    DNS_SERVERS: any\n"
168
    "\n"
169
    "    TELNET_SERVERS: any\n"
170
    "\n"
171
    "    AIM_SERVERS: any\n"
172
    "\n"
173
    "  port-groups:\n"
174
    "\n"
175
    "    HTTP_PORTS: \"80:81,88\"\n"
176
    "\n"
177
    "    SHELLCODE_PORTS: 80\n"
178
    "\n"
179
    "    ORACLE_PORTS: 1521\n"
180
    "\n"
181
    "    SSH_PORTS: 22\n"
182
    "\n";
183
184
/**
185
 * \test Check that valid address and port group vars are correctly retrieved
186
 *       from the configuration.
187
 */
188
static int SCRuleVarsPositiveTest01(void)
189
{
190
    ConfCreateContextBackup();
191
    ConfInit();
192
    ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string));
193
194
    /* check for address-groups */
195
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
196
                strcmp(SCRuleVarsGetConfVar(NULL, "$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS),
197
                        "[192.168.0.0/16,10.8.0.0/16,127.0.0.1,2001:888:13c5:"
198
                        "5AFE::/64,2001:888:13c5:CAFE::/64]") == 0);
199
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
200
                strcmp(SCRuleVarsGetConfVar(NULL, "$EXTERNAL_NET", SC_RULE_VARS_ADDRESS_GROUPS),
201
                        "[!192.168.0.0/16,2000::/3]") == 0);
202
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
203
                strcmp(SCRuleVarsGetConfVar(NULL, "$HTTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
204
                        "!192.168.0.0/16") == 0);
205
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
206
                strcmp(SCRuleVarsGetConfVar(NULL, "$SMTP_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
207
                        "!192.168.0.0/16") == 0);
208
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
209
                strcmp(SCRuleVarsGetConfVar(NULL, "$SQL_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
210
                        "!192.168.0.0/16") == 0);
211
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
212
                strcmp(SCRuleVarsGetConfVar(NULL, "$DNS_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
213
                        "any") == 0);
214
    FAIL_IF_NOT(
215
            SCRuleVarsGetConfVar(NULL, "$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
216
            strcmp(SCRuleVarsGetConfVar(NULL, "$TELNET_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
217
                    "any") == 0);
218
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
219
                strcmp(SCRuleVarsGetConfVar(NULL, "$AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
220
                        "any") == 0);
221
222
    /* Test that a leading space is stripped. */
223
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, " $AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
224
                strcmp(SCRuleVarsGetConfVar(NULL, " $AIM_SERVERS", SC_RULE_VARS_ADDRESS_GROUPS),
225
                        "any") == 0);
226
227
    /* check for port-groups */
228
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL &&
229
                strcmp(SCRuleVarsGetConfVar(NULL, "$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS),
230
                        "80:81,88") == 0);
231
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL &&
232
                strcmp(SCRuleVarsGetConfVar(NULL, "$SHELLCODE_PORTS", SC_RULE_VARS_PORT_GROUPS),
233
                        "80") == 0);
234
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL &&
235
                strcmp(SCRuleVarsGetConfVar(NULL, "$ORACLE_PORTS", SC_RULE_VARS_PORT_GROUPS),
236
                        "1521") == 0);
237
    FAIL_IF_NOT(
238
            SCRuleVarsGetConfVar(NULL, "$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL &&
239
            strcmp(SCRuleVarsGetConfVar(NULL, "$SSH_PORTS", SC_RULE_VARS_PORT_GROUPS), "22") == 0);
240
241
    ConfDeInit();
242
    ConfRestoreContextBackup();
243
    PASS;
244
}
245
246
/**
247
 * \test Check that invalid address and port groups are properly handled by the
248
 *       API.
249
 */
250
static int SCRuleVarsNegativeTest02(void)
251
{
252
    ConfCreateContextBackup();
253
    ConfInit();
254
    ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string));
255
256
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$HOME_NETW", SC_RULE_VARS_ADDRESS_GROUPS) == NULL);
257
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$home_net", SC_RULE_VARS_ADDRESS_GROUPS) == NULL);
258
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$TOMCAT_PORTSW", SC_RULE_VARS_PORT_GROUPS) == NULL);
259
    FAIL_IF_NOT(SCRuleVarsGetConfVar(NULL, "$tomcat_ports", SC_RULE_VARS_PORT_GROUPS) == NULL);
260
261
    ConfDeInit();
262
    ConfRestoreContextBackup();
263
    PASS;
264
}
265
266
/**
267
 * \test Check that Signatures with valid address and port groups are parsed
268
 *       without any errors by the Signature parsing API.
269
 */
270
static int SCRuleVarsPositiveTest03(void)
271
{
272
    ConfCreateContextBackup();
273
    ConfInit();
274
    ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string));
275
276
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
277
    FAIL_IF_NULL(de_ctx);
278
    de_ctx->flags |= DE_QUIET;
279
280
    Signature *s = DetectEngineAppendSig(de_ctx,
281
            "alert tcp [$HTTP_SERVERS,$HOME_NET,192.168.2.5] $HTTP_PORTS -> $EXTERNAL_NET "
282
            "[80,[!$HTTP_PORTS,$ORACLE_PORTS]] (msg:\"Rule Vars Test\"; sid:1;)");
283
    FAIL_IF_NULL(s);
284
285
    ConfDeInit();
286
    ConfRestoreContextBackup();
287
    DetectEngineCtxFree(de_ctx);
288
    PASS;
289
}
290
291
/**
292
 * \test Check that Signatures with invalid address and port groups, are
293
 *       are invalidated by the Signature parsing API.
294
 */
295
static int SCRuleVarsNegativeTest04(void)
296
{
297
    ConfCreateContextBackup();
298
    ConfInit();
299
    ConfYamlLoadString(dummy_conf_string, strlen(dummy_conf_string));
300
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
301
    FAIL_IF_NULL(de_ctx);
302
    de_ctx->flags |= DE_QUIET;
303
304
    Signature *s = DetectEngineAppendSig(
305
            de_ctx, "alert tcp $HTTP_SERVER any -> any any (msg:\"Rule Vars Test\"; sid:1;)");
306
    FAIL_IF_NOT_NULL(s);
307
    s = DetectEngineAppendSig(
308
            de_ctx, "alert tcp $http_servers any -> any any (msg:\"Rule Vars Test\"; sid:1;)");
309
    FAIL_IF_NOT_NULL(s);
310
    s = DetectEngineAppendSig(de_ctx,
311
            "alert tcp $http_servers any -> any $HTTP_PORTS (msg:\"Rule Vars Test\"; sid:1;)");
312
    FAIL_IF_NOT_NULL(s);
313
    s = DetectEngineAppendSig(de_ctx,
314
            "alert tcp !$TELNET_SERVERS !80 -> any !$SSH_PORTS (msg:\"Rule Vars Test\"; sid:1;)");
315
    FAIL_IF_NOT_NULL(s);
316
317
    DetectEngineCtxFree(de_ctx);
318
    ConfDeInit();
319
    ConfRestoreContextBackup();
320
    PASS;
321
}
322
323
static const char *dummy_mt_conf_string =
324
    "%YAML 1.1\n"
325
    "---\n"
326
    "vars:\n"
327
    "\n"
328
    "  address-groups:\n"
329
    "\n"
330
    "    HOME_NET: \"[1.2.3.4]\"\n"
331
    "  port-groups:\n"
332
    "    HTTP_PORTS: \"12345\"\n"
333
    "multi-detect:\n"
334
    "  0:\n"
335
    "    vars:\n"
336
    "\n"
337
    "      address-groups:\n"
338
    "\n"
339
    "        HOME_NET: \"[8.8.8.8]\"\n"
340
    "      port-groups:\n"
341
    "        HTTP_PORTS: \"54321\"\n"
342
    "\n";
343
344
/**
345
 * \test Check that valid address and port group vars are correctly retrieved
346
 *       from the configuration.
347
 */
348
static int SCRuleVarsMTest01(void)
349
{
350
    int result = 0;
351
    DetectEngineCtx *de_ctx = NULL;
352
353
    ConfCreateContextBackup();
354
    ConfInit();
355
    ConfYamlLoadString(dummy_mt_conf_string, strlen(dummy_mt_conf_string));
356
357
    if ( (de_ctx = DetectEngineCtxInit()) == NULL)
358
        return 0;
359
    de_ctx->flags |= DE_QUIET;
360
    snprintf(de_ctx->config_prefix, sizeof(de_ctx->config_prefix),
361
                "multi-detect.0");
362
363
    /* check for address-groups */
364
    result = (SCRuleVarsGetConfVar(de_ctx,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
365
               strcmp(SCRuleVarsGetConfVar(de_ctx,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS),
366
                      "[8.8.8.8]") == 0);
367
    if (result == 0)
368
        goto end;
369
370
    result = (SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS) != NULL &&
371
               strcmp(SCRuleVarsGetConfVar(NULL,"$HOME_NET", SC_RULE_VARS_ADDRESS_GROUPS),
372
                      "[1.2.3.4]") == 0);
373
    if (result == 0)
374
        goto end;
375
376
    /* check for port-groups */
377
    result = (SCRuleVarsGetConfVar(de_ctx,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL &&
378
               strcmp(SCRuleVarsGetConfVar(de_ctx,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS),
379
                      "54321") == 0);
380
    if (result == 0)
381
        goto end;
382
383
    result = (SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS) != NULL &&
384
               strcmp(SCRuleVarsGetConfVar(NULL,"$HTTP_PORTS", SC_RULE_VARS_PORT_GROUPS),
385
                      "12345") == 0);
386
    if (result == 0)
387
        goto end;
388
389
end:
390
    ConfDeInit();
391
    ConfRestoreContextBackup();
392
393
    if (de_ctx != NULL)
394
        DetectEngineCtxFree(de_ctx);
395
    return result;
396
}
397
398
#endif /* UNITTESTS */
399
400
void SCRuleVarsRegisterTests(void)
401
0
{
402
#ifdef UNITTESTS
403
    UtRegisterTest("SCRuleVarsPositiveTest01", SCRuleVarsPositiveTest01);
404
    UtRegisterTest("SCRuleVarsNegativeTest02", SCRuleVarsNegativeTest02);
405
    UtRegisterTest("SCRuleVarsPositiveTest03", SCRuleVarsPositiveTest03);
406
    UtRegisterTest("SCRuleVarsNegativeTest04", SCRuleVarsNegativeTest04);
407
408
    UtRegisterTest("SCRuleVarsMTest01", SCRuleVarsMTest01);
409
#endif
410
411
0
    return;
412
0
}