/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 |