Coverage Report

Created: 2026-06-30 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/util-action.c
Line
Count
Source
1
/* Copyright (C) 2007-2022 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 Pablo Rincon <pablo.rincon.crespo@gmail.com>
22
 */
23
24
#include "suricata-common.h"
25
26
#include "action-globals.h"
27
#include "conf.h"
28
#include "conf-yaml-loader.h"
29
30
#include "detect.h"
31
#include "detect-engine.h"
32
#include "detect-engine-sigorder.h"
33
34
#include "util-unittest.h"
35
#include "util-action.h"
36
#include "util-unittest-helper.h"
37
#include "util-debug.h"
38
39
/* Default order: */
40
uint8_t action_order_sigs[4] = {ACTION_PASS, ACTION_DROP, ACTION_REJECT, ACTION_ALERT};
41
/* This order can be changed from config */
42
43
/**
44
 * \brief Return the priority associated to an action (to order sigs
45
 *        as specified at config)
46
 *        action_order_sigs has this priority by index val
47
 *        so action_order_sigs[0] has to be inspected first.
48
 *        This function is called from detect-engine-sigorder
49
 * \param action can be one of ACTION_PASS, ACTION_DROP,
50
 *        ACTION_REJECT or ACTION_ALERT
51
 * \retval uint8_t the priority (order of this actions)
52
 */
53
uint8_t ActionOrderVal(uint8_t action)
54
1.25M
{
55
    /* reject_both and reject_dst have the same prio as reject */
56
1.25M
    if (action & ACTION_REJECT_ANY) {
57
0
        action = ACTION_REJECT;
58
1.25M
    } else if (action & ACTION_DROP) {
59
18.6k
        action = ACTION_DROP;
60
1.24M
    } else if (action & ACTION_PASS) {
61
57.6k
        action = ACTION_PASS;
62
1.18M
    } else if (action & ACTION_ALERT) {
63
1.16M
        action = ACTION_ALERT;
64
1.16M
    } else if (action == 0) {
65
14.9k
        action = ACTION_ALERT;
66
14.9k
    }
67
68
4.82M
    for (uint8_t i = 0; i < 4; i++) {
69
4.82M
        if (action_order_sigs[i] == action) {
70
1.25M
            return i;
71
1.25M
        }
72
4.82M
    }
73
    /* Unknown action, set just a low prio (high val) */
74
1.04k
    return 10;
75
1.25M
}
76
77
/**
78
 * \brief Return the ACTION_* bit from their ascii value
79
 * \param action can be one of "pass", "drop",
80
 *        "reject" or "alert"
81
 * \retval uint8_t can be one of ACTION_PASS, ACTION_DROP,
82
 *        ACTION_REJECT or ACTION_ALERT
83
 */
84
static uint8_t ActionAsciiToFlag(const char *action)
85
0
{
86
0
    if (strcmp(action,"pass") == 0)
87
0
        return ACTION_PASS;
88
0
    if (strcmp(action,"drop") == 0)
89
0
        return ACTION_DROP;
90
0
    if (strcmp(action,"reject") == 0)
91
0
        return ACTION_REJECT;
92
0
    if (strcmp(action,"alert") == 0)
93
0
        return ACTION_ALERT;
94
95
0
    return 0;
96
0
}
97
98
/**
99
 * \brief Load the action order from config. If none is provided,
100
 *        it will be default to ACTION_PASS, ACTION_DROP,
101
 *        ACTION_REJECT, ACTION_ALERT (pass has the highest prio)
102
 *
103
 * \retval 0 on success; -1 on fatal error;
104
 */
105
int ActionInitConfig(void)
106
145k
{
107
145k
    uint8_t actions_used = 0;
108
145k
    uint8_t action_flag = 0;
109
145k
    uint8_t actions_config[4] = {0, 0, 0, 0};
110
145k
    int order = 0;
111
112
145k
    ConfNode *action_order;
113
145k
    ConfNode *action = NULL;
114
115
    /* Let's load the order of actions from the general config */
116
145k
    action_order = ConfGetNode("action-order");
117
145k
    if (action_order == NULL) {
118
        /* No configuration, use defaults. */
119
145k
        return 0;
120
145k
    }
121
0
    else {
122
0
        TAILQ_FOREACH(action, &action_order->head, next) {
123
0
            SCLogDebug("Loading action order : %s", action->val);
124
0
            action_flag = ActionAsciiToFlag(action->val);
125
0
            if (action_flag == 0) {
126
0
                SCLogError("action-order, invalid action: \"%s\". Please, use"
127
0
                           " \"pass\",\"drop\",\"alert\",\"reject\". You have"
128
0
                           " to specify all of them, without quotes and without"
129
0
                           " capital letters",
130
0
                        action->val);
131
0
                goto error;
132
0
            }
133
134
0
            if (actions_used & action_flag) {
135
0
                SCLogError("action-order, action already set: \"%s\". Please,"
136
0
                           " use \"pass\",\"drop\",\"alert\",\"reject\". You"
137
0
                           " have to specify all of them, without quotes and"
138
0
                           " without capital letters",
139
0
                        action->val);
140
0
                goto error;
141
0
            }
142
143
0
            if (order >= 4) {
144
0
                SCLogError("action-order, you have already specified all the "
145
0
                           "possible actions plus \"%s\". Please, use \"pass\","
146
0
                           "\"drop\",\"alert\",\"reject\". You have to specify"
147
0
                           " all of them, without quotes and without capital"
148
0
                           " letters",
149
0
                        action->val);
150
0
                goto error;
151
0
            }
152
0
            actions_used |= action_flag;
153
0
            actions_config[order++] = action_flag;
154
0
        }
155
0
    }
156
0
    if (order < 4) {
157
0
        SCLogError("action-order, the config didn't specify all of the "
158
0
                   "actions. Please, use \"pass\",\"drop\",\"alert\","
159
0
                   "\"reject\". You have to specify all of them, without"
160
0
                   " quotes and without capital letters");
161
0
        goto error;
162
0
    }
163
164
    /* Now, it's a valid config. Override the default preset */
165
0
    for (order = 0; order < 4; order++) {
166
0
        action_order_sigs[order] = actions_config[order];
167
0
    }
168
169
0
    return 0;
170
171
0
 error:
172
0
    return -1;
173
0
}
174
175
#ifdef UNITTESTS
176
177
/**
178
 * \test Check that we invalidate duplicated actions
179
 *       (It should default to pass, drop, reject, alert)
180
 */
181
static int UtilActionTest01(void)
182
{
183
    char config[] = "\
184
%YAML 1.1\n\
185
---\n\
186
action-order:\n\
187
  - alert\n\
188
  - drop\n\
189
  - reject\n\
190
  - alert\n";
191
192
    ConfCreateContextBackup();
193
    ConfInit();
194
    ConfYamlLoadString(config, strlen(config));
195
196
    ActionInitConfig();
197
    FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
198
    FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
199
    FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
200
    FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT);
201
    ConfRestoreContextBackup();
202
203
    /* Restore default values */
204
    action_order_sigs[0] = ACTION_PASS;
205
    action_order_sigs[1] = ACTION_DROP;
206
    action_order_sigs[2] = ACTION_REJECT;
207
    action_order_sigs[3] = ACTION_ALERT;
208
    PASS;
209
}
210
211
/**
212
 * \test Check that we invalidate with unknown keywords
213
 *       (It should default to pass, drop, reject, alert)
214
 */
215
static int UtilActionTest02(void)
216
{
217
    char config[] = "\
218
%YAML 1.1\n\
219
---\n\
220
action-order:\n\
221
  - alert\n\
222
  - drop\n\
223
  - reject\n\
224
  - ftw\n";
225
226
    ConfCreateContextBackup();
227
    ConfInit();
228
    ConfYamlLoadString(config, strlen(config));
229
230
    ActionInitConfig();
231
    FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
232
    FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
233
    FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
234
    FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT);
235
    ConfRestoreContextBackup();
236
237
    /* Restore default values */
238
    action_order_sigs[0] = ACTION_PASS;
239
    action_order_sigs[1] = ACTION_DROP;
240
    action_order_sigs[2] = ACTION_REJECT;
241
    action_order_sigs[3] = ACTION_ALERT;
242
    PASS;
243
}
244
245
/**
246
 * \test Check that we invalidate if any action is missing
247
 *       (It should default to pass, drop, reject, alert)
248
 */
249
static int UtilActionTest03(void)
250
{
251
    char config[] = "\
252
%YAML 1.1\n\
253
---\n\
254
action-order:\n\
255
  - alert\n\
256
  - drop\n\
257
  - reject\n";
258
259
    ConfCreateContextBackup();
260
    ConfInit();
261
    ConfYamlLoadString(config, strlen(config));
262
263
    ActionInitConfig();
264
    FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
265
    FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
266
    FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
267
    FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT);
268
    ConfRestoreContextBackup();
269
270
    /* Restore default values */
271
    action_order_sigs[0] = ACTION_PASS;
272
    action_order_sigs[1] = ACTION_DROP;
273
    action_order_sigs[2] = ACTION_REJECT;
274
    action_order_sigs[3] = ACTION_ALERT;
275
    PASS;
276
}
277
278
/**
279
 * \test Check that we invalidate if any action is missing
280
 *       (It should default to pass, drop, reject, alert)
281
 */
282
static int UtilActionTest04(void)
283
{
284
    char config[] = "\
285
%YAML 1.1\n\
286
---\n\
287
action-order:\n";
288
289
    ConfCreateContextBackup();
290
    ConfInit();
291
    ConfYamlLoadString(config, strlen(config));
292
293
    ActionInitConfig();
294
    FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
295
    FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
296
    FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
297
    FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT);
298
    ConfRestoreContextBackup();
299
300
    /* Restore default values */
301
    action_order_sigs[0] = ACTION_PASS;
302
    action_order_sigs[1] = ACTION_DROP;
303
    action_order_sigs[2] = ACTION_REJECT;
304
    action_order_sigs[3] = ACTION_ALERT;
305
    PASS;
306
}
307
308
/**
309
 * \test Check that we invalidate with unknown keywords
310
 *       and/or more than the expected
311
 *       (It should default to pass, drop, reject, alert)
312
 */
313
static int UtilActionTest05(void)
314
{
315
    char config[] = "\
316
%YAML 1.1\n\
317
---\n\
318
action-order:\n\
319
  - alert\n\
320
  - drop\n\
321
  - reject\n\
322
  - pass\n\
323
  - whatever\n";
324
325
    ConfCreateContextBackup();
326
    ConfInit();
327
    ConfYamlLoadString(config, strlen(config));
328
329
    ActionInitConfig();
330
    FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
331
    FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
332
    FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
333
    FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT);
334
    ConfRestoreContextBackup();
335
336
    /* Restore default values */
337
    action_order_sigs[0] = ACTION_PASS;
338
    action_order_sigs[1] = ACTION_DROP;
339
    action_order_sigs[2] = ACTION_REJECT;
340
    action_order_sigs[3] = ACTION_ALERT;
341
    PASS;
342
}
343
344
/**
345
 * \test Check that we load a valid config
346
 */
347
static int UtilActionTest06(void)
348
{
349
    char config[] = "\
350
%YAML 1.1\n\
351
---\n\
352
action-order:\n\
353
  - alert\n\
354
  - drop\n\
355
  - reject\n\
356
  - pass\n";
357
358
    ConfCreateContextBackup();
359
    ConfInit();
360
    ConfYamlLoadString(config, strlen(config));
361
362
    ActionInitConfig();
363
    FAIL_IF_NOT(action_order_sigs[0] == ACTION_ALERT);
364
    FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
365
    FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
366
    FAIL_IF_NOT(action_order_sigs[3] == ACTION_PASS);
367
    ConfRestoreContextBackup();
368
369
    /* Restore default values */
370
    action_order_sigs[0] = ACTION_PASS;
371
    action_order_sigs[1] = ACTION_DROP;
372
    action_order_sigs[2] = ACTION_REJECT;
373
    action_order_sigs[3] = ACTION_ALERT;
374
    PASS;
375
}
376
377
/**
378
 * \test Check that we load a valid config
379
 */
380
static int UtilActionTest07(void)
381
{
382
    char config[] = "\
383
%YAML 1.1\n\
384
---\n\
385
action-order:\n\
386
  - pass\n\
387
  - alert\n\
388
  - drop\n\
389
  - reject\n";
390
391
    ConfCreateContextBackup();
392
    ConfInit();
393
    ConfYamlLoadString(config, strlen(config));
394
395
    ActionInitConfig();
396
    FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
397
    FAIL_IF_NOT(action_order_sigs[1] == ACTION_ALERT);
398
    FAIL_IF_NOT(action_order_sigs[2] == ACTION_DROP);
399
    FAIL_IF_NOT(action_order_sigs[3] == ACTION_REJECT);
400
    ConfRestoreContextBackup();
401
402
    /* Restore default values */
403
    action_order_sigs[0] = ACTION_PASS;
404
    action_order_sigs[1] = ACTION_DROP;
405
    action_order_sigs[2] = ACTION_REJECT;
406
    action_order_sigs[3] = ACTION_ALERT;
407
    PASS;
408
}
409
410
/**
411
 * \test Check that the expected defaults are loaded if the
412
 *     action-order configuration is not present.
413
 */
414
static int UtilActionTest08(void)
415
{
416
    char config[] = "%YAML 1.1\n"
417
        "---\n";
418
419
    ConfCreateContextBackup();
420
    ConfInit();
421
    ConfYamlLoadString(config, strlen(config));
422
423
    FAIL_IF_NOT(ActionInitConfig() == 0);
424
    FAIL_IF_NOT(action_order_sigs[0] == ACTION_PASS);
425
    FAIL_IF_NOT(action_order_sigs[1] == ACTION_DROP);
426
    FAIL_IF_NOT(action_order_sigs[2] == ACTION_REJECT);
427
    FAIL_IF_NOT(action_order_sigs[3] == ACTION_ALERT);
428
429
    ConfRestoreContextBackup();
430
    PASS;
431
}
432
433
/* Register unittests */
434
void UtilActionRegisterTests(void)
435
{
436
    /* Generic tests */
437
    UtRegisterTest("UtilActionTest01", UtilActionTest01);
438
    UtRegisterTest("UtilActionTest02", UtilActionTest02);
439
    UtRegisterTest("UtilActionTest02", UtilActionTest02);
440
    UtRegisterTest("UtilActionTest03", UtilActionTest03);
441
    UtRegisterTest("UtilActionTest04", UtilActionTest04);
442
    UtRegisterTest("UtilActionTest05", UtilActionTest05);
443
    UtRegisterTest("UtilActionTest06", UtilActionTest06);
444
    UtRegisterTest("UtilActionTest07", UtilActionTest07);
445
    UtRegisterTest("UtilActionTest08", UtilActionTest08);
446
}
447
#endif