1 /* Copyright (C) 2007-2020 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 Victor Julien <victor@inliniac.net>
22 * \author Breno Silva <breno.silva@gmail.com>
23 *
24 * Implements the flowbits keyword
25 */
26
27 #include "suricata-common.h"
28 #include "decode.h"
29 #include "detect.h"
30 #include "threads.h"
31 #include "flow.h"
32 #include "flow-bit.h"
33 #include "flow-util.h"
34 #include "detect-flowbits.h"
35 #include "util-spm.h"
36
37 #include "app-layer-parser.h"
38
39 #include "detect-parse.h"
40 #include "detect-engine.h"
41 #include "detect-engine-mpm.h"
42 #include "detect-engine-state.h"
43
44 #include "util-var-name.h"
45 #include "util-unittest.h"
46 #include "util-debug.h"
47
48 #define PARSE_REGEX "^([a-z]+)(?:,\\s*(.*))?"
49 static DetectParseRegex parse_regex;
50
51 #define MAX_TOKENS 100
52
53 int DetectFlowbitMatch (DetectEngineThreadCtx *, Packet *,
54 const Signature *, const SigMatchCtx *);
55 static int DetectFlowbitSetup (DetectEngineCtx *, Signature *, const char *);
56 static int FlowbitOrAddData(DetectEngineCtx *, DetectFlowbitsData *, char *);
57 void DetectFlowbitFree (DetectEngineCtx *, void *);
58 #ifdef UNITTESTS
59 void FlowBitsRegisterTests(void);
60 #endif
61
DetectFlowbitsRegister(void)62 void DetectFlowbitsRegister (void)
63 {
64 sigmatch_table[DETECT_FLOWBITS].name = "flowbits";
65 sigmatch_table[DETECT_FLOWBITS].desc = "operate on flow flag";
66 sigmatch_table[DETECT_FLOWBITS].url = "/rules/flow-keywords.html#flowbits";
67 sigmatch_table[DETECT_FLOWBITS].Match = DetectFlowbitMatch;
68 sigmatch_table[DETECT_FLOWBITS].Setup = DetectFlowbitSetup;
69 sigmatch_table[DETECT_FLOWBITS].Free = DetectFlowbitFree;
70 #ifdef UNITTESTS
71 sigmatch_table[DETECT_FLOWBITS].RegisterTests = FlowBitsRegisterTests;
72 #endif
73 /* this is compatible to ip-only signatures */
74 sigmatch_table[DETECT_FLOWBITS].flags |= SIGMATCH_IPONLY_COMPAT;
75
76 DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
77 }
78
FlowbitOrAddData(DetectEngineCtx * de_ctx,DetectFlowbitsData * cd,char * arrptr)79 static int FlowbitOrAddData(DetectEngineCtx *de_ctx, DetectFlowbitsData *cd, char *arrptr)
80 {
81 char *strarr[MAX_TOKENS];
82 char *token;
83 char *saveptr = NULL;
84 uint8_t i = 0;
85
86 while ((token = strtok_r(arrptr, "|", &saveptr))) {
87 // Check for leading/trailing spaces in the token
88 while(isspace((unsigned char)*token))
89 token++;
90 if (*token == 0)
91 goto next;
92 char *end = token + strlen(token) - 1;
93 while(end > token && isspace((unsigned char)*end))
94 *(end--) = '\0';
95
96 // Check for spaces in between the flowbit names
97 if (strchr(token, ' ') != NULL) {
98 SCLogError(SC_ERR_INVALID_SIGNATURE, "Spaces are not allowed in flowbit names.");
99 return -1;
100 }
101
102 if (i == MAX_TOKENS) {
103 SCLogError(SC_ERR_INVALID_SIGNATURE, "Number of flowbits exceeds "
104 "maximum allowed: %d.", MAX_TOKENS);
105 return -1;
106 }
107 strarr[i++] = token;
108 next:
109 arrptr = NULL;
110 }
111
112 cd->or_list_size = i;
113 cd->or_list = SCCalloc(cd->or_list_size, sizeof(uint32_t));
114 if (unlikely(cd->or_list == NULL))
115 return -1;
116 for (uint8_t j = 0; j < cd->or_list_size ; j++) {
117 cd->or_list[j] = VarNameStoreSetupAdd(strarr[j], VAR_TYPE_FLOW_BIT);
118 de_ctx->max_fb_id = MAX(cd->or_list[j], de_ctx->max_fb_id);
119 }
120
121 return 1;
122 }
123
DetectFlowbitMatchToggle(Packet * p,const DetectFlowbitsData * fd)124 static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd)
125 {
126 if (p->flow == NULL)
127 return 0;
128
129 FlowBitToggle(p->flow,fd->idx);
130
131 return 1;
132 }
133
DetectFlowbitMatchUnset(Packet * p,const DetectFlowbitsData * fd)134 static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd)
135 {
136 if (p->flow == NULL)
137 return 0;
138
139 FlowBitUnset(p->flow,fd->idx);
140
141 return 1;
142 }
143
DetectFlowbitMatchSet(Packet * p,const DetectFlowbitsData * fd)144 static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd)
145 {
146 if (p->flow == NULL)
147 return 0;
148
149 FlowBitSet(p->flow,fd->idx);
150
151 return 1;
152 }
153
DetectFlowbitMatchIsset(Packet * p,const DetectFlowbitsData * fd)154 static int DetectFlowbitMatchIsset (Packet *p, const DetectFlowbitsData *fd)
155 {
156 if (p->flow == NULL)
157 return 0;
158 if (fd->or_list_size > 0) {
159 for (uint8_t i = 0; i < fd->or_list_size; i++) {
160 if (FlowBitIsset(p->flow, fd->or_list[i]) == 1)
161 return 1;
162 }
163 return 0;
164 }
165
166 return FlowBitIsset(p->flow,fd->idx);
167 }
168
DetectFlowbitMatchIsnotset(Packet * p,const DetectFlowbitsData * fd)169 static int DetectFlowbitMatchIsnotset (Packet *p, const DetectFlowbitsData *fd)
170 {
171 if (p->flow == NULL)
172 return 0;
173 if (fd->or_list_size > 0) {
174 for (uint8_t i = 0; i < fd->or_list_size; i++) {
175 if (FlowBitIsnotset(p->flow, fd->or_list[i]) == 1)
176 return 1;
177 }
178 return 0;
179 }
180 return FlowBitIsnotset(p->flow,fd->idx);
181 }
182
183 /*
184 * returns 0: no match
185 * 1: match
186 * -1: error
187 */
188
DetectFlowbitMatch(DetectEngineThreadCtx * det_ctx,Packet * p,const Signature * s,const SigMatchCtx * ctx)189 int DetectFlowbitMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
190 const Signature *s, const SigMatchCtx *ctx)
191 {
192 const DetectFlowbitsData *fd = (const DetectFlowbitsData *)ctx;
193 if (fd == NULL)
194 return 0;
195
196 switch (fd->cmd) {
197 case DETECT_FLOWBITS_CMD_ISSET:
198 return DetectFlowbitMatchIsset(p,fd);
199 case DETECT_FLOWBITS_CMD_ISNOTSET:
200 return DetectFlowbitMatchIsnotset(p,fd);
201 case DETECT_FLOWBITS_CMD_SET:
202 return DetectFlowbitMatchSet(p,fd);
203 case DETECT_FLOWBITS_CMD_UNSET:
204 return DetectFlowbitMatchUnset(p,fd);
205 case DETECT_FLOWBITS_CMD_TOGGLE:
206 return DetectFlowbitMatchToggle(p,fd);
207 default:
208 SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", fd->cmd);
209 return 0;
210 }
211
212 return 0;
213 }
214
DetectFlowbitParse(const char * str,char * cmd,int cmd_len,char * name,int name_len)215 static int DetectFlowbitParse(const char *str, char *cmd, int cmd_len, char *name,
216 int name_len)
217 {
218 const int max_substrings = 30;
219 int count, rc;
220 int ov[max_substrings];
221
222 count = DetectParsePcreExec(&parse_regex, str, 0, 0, ov, max_substrings);
223 if (count != 2 && count != 3) {
224 SCLogError(SC_ERR_PCRE_MATCH,
225 "\"%s\" is not a valid setting for flowbits.", str);
226 return 0;
227 }
228
229 rc = pcre_copy_substring((char *)str, ov, max_substrings, 1, cmd, cmd_len);
230 if (rc < 0) {
231 SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
232 return 0;
233 }
234
235 if (count == 3) {
236 rc = pcre_copy_substring((char *)str, ov, max_substrings, 2, name,
237 name_len);
238 if (rc < 0) {
239 SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
240 return 0;
241 }
242
243 /* Trim trailing whitespace. */
244 while (strlen(name) > 0 && isblank(name[strlen(name) - 1])) {
245 name[strlen(name) - 1] = '\0';
246 }
247
248 if (strchr(name, '|') == NULL) {
249 /* Validate name, spaces are not allowed. */
250 for (size_t i = 0; i < strlen(name); i++) {
251 if (isblank(name[i])) {
252 SCLogError(SC_ERR_INVALID_SIGNATURE,
253 "spaces not allowed in flowbit names");
254 return 0;
255 }
256 }
257 }
258 }
259
260 return 1;
261 }
262
DetectFlowbitSetup(DetectEngineCtx * de_ctx,Signature * s,const char * rawstr)263 int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
264 {
265 DetectFlowbitsData *cd = NULL;
266 SigMatch *sm = NULL;
267 uint8_t fb_cmd = 0;
268 char fb_cmd_str[16] = "", fb_name[256] = "";
269
270 if (!DetectFlowbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), fb_name,
271 sizeof(fb_name))) {
272 return -1;
273 }
274
275 if (strcmp(fb_cmd_str,"noalert") == 0) {
276 fb_cmd = DETECT_FLOWBITS_CMD_NOALERT;
277 } else if (strcmp(fb_cmd_str,"isset") == 0) {
278 fb_cmd = DETECT_FLOWBITS_CMD_ISSET;
279 } else if (strcmp(fb_cmd_str,"isnotset") == 0) {
280 fb_cmd = DETECT_FLOWBITS_CMD_ISNOTSET;
281 } else if (strcmp(fb_cmd_str,"set") == 0) {
282 fb_cmd = DETECT_FLOWBITS_CMD_SET;
283 } else if (strcmp(fb_cmd_str,"unset") == 0) {
284 fb_cmd = DETECT_FLOWBITS_CMD_UNSET;
285 } else if (strcmp(fb_cmd_str,"toggle") == 0) {
286 fb_cmd = DETECT_FLOWBITS_CMD_TOGGLE;
287 } else {
288 SCLogError(SC_ERR_UNKNOWN_VALUE, "ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str);
289 goto error;
290 }
291
292 switch (fb_cmd) {
293 case DETECT_FLOWBITS_CMD_NOALERT:
294 if (strlen(fb_name) != 0)
295 goto error;
296 s->flags |= SIG_FLAG_NOALERT;
297 return 0;
298 case DETECT_FLOWBITS_CMD_ISNOTSET:
299 case DETECT_FLOWBITS_CMD_ISSET:
300 case DETECT_FLOWBITS_CMD_SET:
301 case DETECT_FLOWBITS_CMD_UNSET:
302 case DETECT_FLOWBITS_CMD_TOGGLE:
303 default:
304 if (strlen(fb_name) == 0)
305 goto error;
306 break;
307 }
308
309 cd = SCCalloc(1, sizeof(DetectFlowbitsData));
310 if (unlikely(cd == NULL))
311 goto error;
312 if (strchr(fb_name, '|') != NULL) {
313 int retval = FlowbitOrAddData(de_ctx, cd, fb_name);
314 if (retval == -1) {
315 goto error;
316 }
317 cd->cmd = fb_cmd;
318 } else {
319 cd->idx = VarNameStoreSetupAdd(fb_name, VAR_TYPE_FLOW_BIT);
320 de_ctx->max_fb_id = MAX(cd->idx, de_ctx->max_fb_id);
321 cd->cmd = fb_cmd;
322 cd->or_list_size = 0;
323 cd->or_list = NULL;
324 SCLogDebug("idx %" PRIu32 ", cmd %s, name %s",
325 cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)");
326 }
327 /* Okay so far so good, lets get this into a SigMatch
328 * and put it in the Signature. */
329 sm = SigMatchAlloc();
330 if (sm == NULL)
331 goto error;
332
333 sm->type = DETECT_FLOWBITS;
334 sm->ctx = (SigMatchCtx *)cd;
335
336 switch (fb_cmd) {
337 /* case DETECT_FLOWBITS_CMD_NOALERT can't happen here */
338
339 case DETECT_FLOWBITS_CMD_ISNOTSET:
340 case DETECT_FLOWBITS_CMD_ISSET:
341 /* checks, so packet list */
342 SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH);
343 break;
344
345 case DETECT_FLOWBITS_CMD_SET:
346 case DETECT_FLOWBITS_CMD_UNSET:
347 case DETECT_FLOWBITS_CMD_TOGGLE:
348 /* modifiers, only run when entire sig has matched */
349 SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH);
350 break;
351
352 // suppress coverity warning as scan-build-7 warns w/o this.
353 // coverity[deadcode : FALSE]
354 default:
355 goto error;
356 }
357
358 return 0;
359
360 error:
361 if (cd != NULL)
362 DetectFlowbitFree(de_ctx, cd);
363 if (sm != NULL)
364 SCFree(sm);
365 return -1;
366 }
367
DetectFlowbitFree(DetectEngineCtx * de_ctx,void * ptr)368 void DetectFlowbitFree (DetectEngineCtx *de_ctx, void *ptr)
369 {
370 DetectFlowbitsData *fd = (DetectFlowbitsData *)ptr;
371 if (fd == NULL)
372 return;
373 if (fd->or_list != NULL)
374 SCFree(fd->or_list);
375 SCFree(fd);
376 }
377
378 struct FBAnalyze {
379 uint16_t cnts[DETECT_FLOWBITS_CMD_MAX];
380 uint16_t state_cnts[DETECT_FLOWBITS_CMD_MAX];
381
382 uint32_t *set_sids;
383 uint32_t set_sids_idx;
384 uint32_t set_sids_size;
385
386 uint32_t *isset_sids;
387 uint32_t isset_sids_idx;
388 uint32_t isset_sids_size;
389
390 uint32_t *isnotset_sids;
391 uint32_t isnotset_sids_idx;
392 uint32_t isnotset_sids_size;
393
394 uint32_t *unset_sids;
395 uint32_t unset_sids_idx;
396 uint32_t unset_sids_size;
397
398 uint32_t *toggle_sids;
399 uint32_t toggle_sids_idx;
400 uint32_t toggle_sids_size;
401 };
402
403 extern int rule_engine_analysis_set;
404 static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
405 struct FBAnalyze *array, uint32_t elements);
406
DetectFlowbitsAnalyze(DetectEngineCtx * de_ctx)407 int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx)
408 {
409 const uint32_t max_fb_id = de_ctx->max_fb_id;
410 if (max_fb_id == 0)
411 return 0;
412
413 #define MAX_SIDS 8
414 uint32_t array_size = max_fb_id + 1;
415 struct FBAnalyze *array = SCCalloc(array_size, sizeof(struct FBAnalyze));
416
417 if (array == NULL) {
418 SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate flowbit analyze array");
419 return -1;
420 }
421
422 SCLogDebug("fb analyzer array size: %"PRIu64,
423 (uint64_t)(array_size * sizeof(struct FBAnalyze)));
424
425 /* fill flowbit array, updating counters per sig */
426 for (uint32_t i = 0; i < de_ctx->sig_array_len; i++) {
427 const Signature *s = de_ctx->sig_array[i];
428 bool has_state = false;
429
430 /* see if the signature uses stateful matching */
431 for (uint32_t x = DETECT_SM_LIST_DYNAMIC_START; x < s->init_data->smlists_array_size; x++) {
432 if (s->init_data->smlists[x] == NULL)
433 continue;
434 has_state = true;
435 break;
436 }
437
438 for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
439 switch (sm->type) {
440 case DETECT_FLOWBITS:
441 {
442 /* figure out the flowbit action */
443 const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
444 // Handle flowbit array in case of ORed flowbits
445 for (uint8_t k = 0; k < fb->or_list_size; k++) {
446 array[fb->or_list[k]].cnts[fb->cmd]++;
447 if (has_state)
448 array[fb->or_list[k]].state_cnts[fb->cmd]++;
449 if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
450 if (array[fb->or_list[k]].isset_sids_idx >= array[fb->or_list[k]].isset_sids_size) {
451 uint32_t old_size = array[fb->or_list[k]].isset_sids_size;
452 uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
453
454 void *ptr = SCRealloc(array[fb->or_list[k]].isset_sids, new_size * sizeof(uint32_t));
455 if (ptr == NULL)
456 goto end;
457 array[fb->or_list[k]].isset_sids_size = new_size;
458 array[fb->or_list[k]].isset_sids = ptr;
459 }
460
461 array[fb->or_list[k]].isset_sids[array[fb->or_list[k]].isset_sids_idx] = s->num;
462 array[fb->or_list[k]].isset_sids_idx++;
463 } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET) {
464 if (array[fb->or_list[k]].isnotset_sids_idx >= array[fb->or_list[k]].isnotset_sids_size) {
465 uint32_t old_size = array[fb->or_list[k]].isnotset_sids_size;
466 uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
467
468 void *ptr = SCRealloc(array[fb->or_list[k]].isnotset_sids, new_size * sizeof(uint32_t));
469 if (ptr == NULL)
470 goto end;
471 array[fb->or_list[k]].isnotset_sids_size = new_size;
472 array[fb->or_list[k]].isnotset_sids = ptr;
473 }
474
475 array[fb->or_list[k]].isnotset_sids[array[fb->or_list[k]].isnotset_sids_idx] = s->num;
476 array[fb->or_list[k]].isnotset_sids_idx++;
477 }
478 }
479 if (fb->or_list_size == 0) {
480 array[fb->idx].cnts[fb->cmd]++;
481 if (has_state)
482 array[fb->idx].state_cnts[fb->cmd]++;
483 if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
484 if (array[fb->idx].isset_sids_idx >= array[fb->idx].isset_sids_size) {
485 uint32_t old_size = array[fb->idx].isset_sids_size;
486 uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
487
488 void *ptr = SCRealloc(array[fb->idx].isset_sids, new_size * sizeof(uint32_t));
489 if (ptr == NULL)
490 goto end;
491 array[fb->idx].isset_sids_size = new_size;
492 array[fb->idx].isset_sids = ptr;
493 }
494
495 array[fb->idx].isset_sids[array[fb->idx].isset_sids_idx] = s->num;
496 array[fb->idx].isset_sids_idx++;
497 } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET) {
498 if (array[fb->idx].isnotset_sids_idx >= array[fb->idx].isnotset_sids_size) {
499 uint32_t old_size = array[fb->idx].isnotset_sids_size;
500 uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
501
502 void *ptr = SCRealloc(array[fb->idx].isnotset_sids, new_size * sizeof(uint32_t));
503 if (ptr == NULL)
504 goto end;
505 array[fb->idx].isnotset_sids_size = new_size;
506 array[fb->idx].isnotset_sids = ptr;
507 }
508
509 array[fb->idx].isnotset_sids[array[fb->idx].isnotset_sids_idx] = s->num;
510 array[fb->idx].isnotset_sids_idx++;
511 }
512 }
513 }
514 }
515 }
516 for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_POSTMATCH] ; sm != NULL; sm = sm->next) {
517 switch (sm->type) {
518 case DETECT_FLOWBITS:
519 {
520 /* figure out what flowbit action */
521 const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
522 array[fb->idx].cnts[fb->cmd]++;
523 if (has_state)
524 array[fb->idx].state_cnts[fb->cmd]++;
525 if (fb->cmd == DETECT_FLOWBITS_CMD_SET) {
526 if (array[fb->idx].set_sids_idx >= array[fb->idx].set_sids_size) {
527 uint32_t old_size = array[fb->idx].set_sids_size;
528 uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
529
530 void *ptr = SCRealloc(array[fb->idx].set_sids, new_size * sizeof(uint32_t));
531 if (ptr == NULL)
532 goto end;
533 array[fb->idx].set_sids_size = new_size;
534 array[fb->idx].set_sids = ptr;
535 }
536
537 array[fb->idx].set_sids[array[fb->idx].set_sids_idx] = s->num;
538 array[fb->idx].set_sids_idx++;
539 }
540 else if (fb->cmd == DETECT_FLOWBITS_CMD_UNSET) {
541 if (array[fb->idx].unset_sids_idx >= array[fb->idx].unset_sids_size) {
542 uint32_t old_size = array[fb->idx].unset_sids_size;
543 uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
544
545 void *ptr = SCRealloc(array[fb->idx].unset_sids, new_size * sizeof(uint32_t));
546 if (ptr == NULL)
547 goto end;
548 array[fb->idx].unset_sids_size = new_size;
549 array[fb->idx].unset_sids = ptr;
550 }
551
552 array[fb->idx].unset_sids[array[fb->idx].unset_sids_idx] = s->num;
553 array[fb->idx].unset_sids_idx++;
554 }
555 else if (fb->cmd == DETECT_FLOWBITS_CMD_TOGGLE) {
556 if (array[fb->idx].toggle_sids_idx >= array[fb->idx].toggle_sids_size) {
557 uint32_t old_size = array[fb->idx].toggle_sids_size;
558 uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
559
560 void *ptr = SCRealloc(array[fb->idx].toggle_sids, new_size * sizeof(uint32_t));
561 if (ptr == NULL)
562 goto end;
563 array[fb->idx].toggle_sids_size = new_size;
564 array[fb->idx].toggle_sids = ptr;
565 }
566
567 array[fb->idx].toggle_sids[array[fb->idx].toggle_sids_idx] = s->num;
568 array[fb->idx].toggle_sids_idx++;
569 }
570 }
571 }
572 }
573 }
574
575 /* walk array to see if all bits make sense */
576 for (uint32_t i = 0; i < array_size; i++) {
577 char *varname = VarNameStoreSetupLookup(i, VAR_TYPE_FLOW_BIT);
578 if (varname == NULL)
579 continue;
580
581 bool to_state = false;
582
583 if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] &&
584 array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE] == 0 &&
585 array[i].cnts[DETECT_FLOWBITS_CMD_SET] == 0) {
586
587 const Signature *s = de_ctx->sig_array[array[i].isset_sids[0]];
588 SCLogWarning(SC_WARN_FLOWBIT, "flowbit '%s' is checked but not "
589 "set. Checked in %u and %u other sigs",
590 varname, s->id, array[i].isset_sids_idx - 1);
591 }
592 if (array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] &&
593 array[i].state_cnts[DETECT_FLOWBITS_CMD_SET] == 0)
594 {
595 SCLogDebug("flowbit %s/%u: isset in state, set not in state", varname, i);
596 }
597
598 /* if signature depends on 'stateful' flowbits, then turn the
599 * sig into a stateful sig itself */
600 if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] > 0 &&
601 array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] == 0 &&
602 array[i].state_cnts[DETECT_FLOWBITS_CMD_SET])
603 {
604 SCLogDebug("flowbit %s/%u: isset not in state, set in state", varname, i);
605 to_state = true;
606 }
607
608 SCLogDebug("ALL flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
609 array[i].cnts[DETECT_FLOWBITS_CMD_SET], array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE],
610 array[i].cnts[DETECT_FLOWBITS_CMD_UNSET], array[i].cnts[DETECT_FLOWBITS_CMD_ISNOTSET],
611 array[i].cnts[DETECT_FLOWBITS_CMD_ISSET]);
612 SCLogDebug("STATE flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
613 array[i].state_cnts[DETECT_FLOWBITS_CMD_SET], array[i].state_cnts[DETECT_FLOWBITS_CMD_TOGGLE],
614 array[i].state_cnts[DETECT_FLOWBITS_CMD_UNSET], array[i].state_cnts[DETECT_FLOWBITS_CMD_ISNOTSET],
615 array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET]);
616 for (uint32_t x = 0; x < array[i].set_sids_idx; x++) {
617 SCLogDebug("SET flowbit %s/%u: SID %u", varname, i,
618 de_ctx->sig_array[array[i].set_sids[x]]->id);
619 }
620 for (uint32_t x = 0; x < array[i].isset_sids_idx; x++) {
621 Signature *s = de_ctx->sig_array[array[i].isset_sids[x]];
622 SCLogDebug("GET flowbit %s/%u: SID %u", varname, i, s->id);
623
624 if (to_state) {
625 s->init_data->init_flags |= SIG_FLAG_INIT_STATE_MATCH;
626 SCLogDebug("made SID %u stateful because it depends on "
627 "stateful rules that set flowbit %s", s->id, varname);
628 }
629 }
630 SCFree(varname);
631 }
632
633 if (rule_engine_analysis_set) {
634 DetectFlowbitsAnalyzeDump(de_ctx, array, array_size);
635 }
636
637 end:
638 for (uint32_t i = 0; i < array_size; i++) {
639 SCFree(array[i].set_sids);
640 SCFree(array[i].unset_sids);
641 SCFree(array[i].isset_sids);
642 SCFree(array[i].isnotset_sids);
643 SCFree(array[i].toggle_sids);
644 }
645 SCFree(array);
646
647 return 0;
648 }
649
650 SCMutex g_flowbits_dump_write_m = SCMUTEX_INITIALIZER;
DetectFlowbitsAnalyzeDump(const DetectEngineCtx * de_ctx,struct FBAnalyze * array,uint32_t elements)651 static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
652 struct FBAnalyze *array, uint32_t elements)
653 {
654 JsonBuilder *js = jb_new_object();
655 if (js == NULL)
656 return;
657
658 jb_open_array(js, "flowbits");
659 for (uint32_t x = 0; x < elements; x++) {
660 char *varname = VarNameStoreSetupLookup(x, VAR_TYPE_FLOW_BIT);
661 if (varname == NULL)
662 continue;
663
664 const struct FBAnalyze *e = &array[x];
665
666 jb_start_object(js);
667 jb_set_string(js, "name", varname);
668 jb_set_uint(js, "internal_id", x);
669 jb_set_uint(js, "set_cnt", e->cnts[DETECT_FLOWBITS_CMD_SET]);
670 jb_set_uint(js, "unset_cnt", e->cnts[DETECT_FLOWBITS_CMD_UNSET]);
671 jb_set_uint(js, "toggle_cnt", e->cnts[DETECT_FLOWBITS_CMD_TOGGLE]);
672 jb_set_uint(js, "isset_cnt", e->cnts[DETECT_FLOWBITS_CMD_ISSET]);
673 jb_set_uint(js, "isnotset_cnt", e->cnts[DETECT_FLOWBITS_CMD_ISNOTSET]);
674
675 // sets
676 if (e->cnts[DETECT_FLOWBITS_CMD_SET]) {
677 jb_open_array(js, "sets");
678 for (uint32_t i = 0; i < e->set_sids_idx; i++) {
679 const Signature *s = de_ctx->sig_array[e->set_sids[i]];
680 jb_append_uint(js, s->id);
681 }
682 jb_close(js);
683 }
684 // gets
685 if (e->cnts[DETECT_FLOWBITS_CMD_ISSET]) {
686 jb_open_array(js, "isset");
687 for (uint32_t i = 0; i < e->isset_sids_idx; i++) {
688 const Signature *s = de_ctx->sig_array[e->isset_sids[i]];
689 jb_append_uint(js, s->id);
690 }
691 jb_close(js);
692 }
693 // isnotset
694 if (e->cnts[DETECT_FLOWBITS_CMD_ISNOTSET]) {
695 jb_open_array(js, "isnotset");
696 for (uint32_t i = 0; i < e->isnotset_sids_idx; i++) {
697 const Signature *s = de_ctx->sig_array[e->isnotset_sids[i]];
698 jb_append_uint(js, s->id);
699 }
700 jb_close(js);
701 }
702 // unset
703 if (e->cnts[DETECT_FLOWBITS_CMD_UNSET]) {
704 jb_open_array(js, "unset");
705 for (uint32_t i = 0; i < e->unset_sids_idx; i++) {
706 const Signature *s = de_ctx->sig_array[e->unset_sids[i]];
707 jb_append_uint(js, s->id);
708 }
709 jb_close(js);
710 }
711 // toggle
712 if (e->cnts[DETECT_FLOWBITS_CMD_TOGGLE]) {
713 jb_open_array(js, "toggle");
714 for (uint32_t i = 0; i < e->toggle_sids_idx; i++) {
715 const Signature *s = de_ctx->sig_array[e->toggle_sids[i]];
716 jb_append_uint(js, s->id);
717 }
718 jb_close(js);
719 }
720 SCFree(varname);
721 jb_close(js);
722 }
723 jb_close(js); // array
724 jb_close(js); // object
725
726 const char *filename = "flowbits.json";
727 const char *log_dir = ConfigGetLogDirectory();
728 char log_path[PATH_MAX] = "";
729 snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, filename);
730
731 SCMutexLock(&g_flowbits_dump_write_m);
732 FILE *fp = fopen(log_path, "w");
733 if (fp != NULL) {
734 fwrite(jb_ptr(js), jb_len(js), 1, fp);
735 fprintf(fp, "\n");
736 fclose(fp);
737 }
738 SCMutexUnlock(&g_flowbits_dump_write_m);
739
740 jb_free(js);
741 }
742
743 #ifdef UNITTESTS
744
FlowBitsTestParse01(void)745 static int FlowBitsTestParse01(void)
746 {
747 char command[16] = "", name[16] = "";
748
749 /* Single argument version. */
750 FAIL_IF(!DetectFlowbitParse("noalert", command, sizeof(command), name,
751 sizeof(name)));
752 FAIL_IF(strcmp(command, "noalert") != 0);
753
754 /* No leading or trailing spaces. */
755 FAIL_IF(!DetectFlowbitParse("set,flowbit", command, sizeof(command), name,
756 sizeof(name)));
757 FAIL_IF(strcmp(command, "set") != 0);
758 FAIL_IF(strcmp(name, "flowbit") != 0);
759
760 /* Leading space. */
761 FAIL_IF(!DetectFlowbitParse("set, flowbit", command, sizeof(command), name,
762 sizeof(name)));
763 FAIL_IF(strcmp(command, "set") != 0);
764 FAIL_IF(strcmp(name, "flowbit") != 0);
765
766 /* Trailing space. */
767 FAIL_IF(!DetectFlowbitParse("set,flowbit ", command, sizeof(command), name,
768 sizeof(name)));
769 FAIL_IF(strcmp(command, "set") != 0);
770 FAIL_IF(strcmp(name, "flowbit") != 0);
771
772 /* Leading and trailing space. */
773 FAIL_IF(!DetectFlowbitParse("set, flowbit ", command, sizeof(command), name,
774 sizeof(name)));
775 FAIL_IF(strcmp(command, "set") != 0);
776 FAIL_IF(strcmp(name, "flowbit") != 0);
777
778 /* Spaces are not allowed in the name. */
779 FAIL_IF(DetectFlowbitParse("set,namewith space", command, sizeof(command),
780 name, sizeof(name)));
781
782 PASS;
783 }
784
785 /**
786 * \test FlowBitsTestSig01 is a test for a valid noalert flowbits option
787 *
788 * \retval 1 on succces
789 * \retval 0 on failure
790 */
791
FlowBitsTestSig01(void)792 static int FlowBitsTestSig01(void)
793 {
794 Signature *s = NULL;
795 DetectEngineCtx *de_ctx = NULL;
796
797 de_ctx = DetectEngineCtxInit();
798 FAIL_IF_NULL(de_ctx);
799
800 de_ctx->flags |= DE_QUIET;
801
802 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)");
803 FAIL_IF_NOT_NULL(s);
804
805 SigGroupBuild(de_ctx);
806 DetectEngineCtxFree(de_ctx);
807 PASS;
808 }
809
810 /**
811 * \test FlowBitsTestSig02 is a test for a valid isset,set,isnotset,unset,toggle flowbits options
812 *
813 * \retval 1 on succces
814 * \retval 0 on failure
815 */
816
FlowBitsTestSig02(void)817 static int FlowBitsTestSig02(void)
818 {
819 Signature *s = NULL;
820 ThreadVars th_v;
821 DetectEngineCtx *de_ctx = NULL;
822
823 memset(&th_v, 0, sizeof(th_v));
824
825 de_ctx = DetectEngineCtxInit();
826 FAIL_IF_NULL(de_ctx);
827
828 de_ctx->flags |= DE_QUIET;
829
830 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset rule need an option\"; flowbits:isset; content:\"GET \"; sid:1;)");
831 FAIL_IF_NOT_NULL(s);
832
833 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isnotset rule need an option\"; flowbits:isnotset; content:\"GET \"; sid:2;)");
834 FAIL_IF_NOT_NULL(s);
835
836 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"set rule need an option\"; flowbits:set; content:\"GET \"; sid:3;)");
837 FAIL_IF_NOT_NULL(s);
838
839 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"unset rule need an option\"; flowbits:unset; content:\"GET \"; sid:4;)");
840 FAIL_IF_NOT_NULL(s);
841
842 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"toggle rule need an option\"; flowbits:toggle; content:\"GET \"; sid:5;)");
843 FAIL_IF_NOT_NULL(s);
844
845 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"!set is not an option\"; flowbits:!set,myerr; content:\"GET \"; sid:6;)");
846 FAIL_IF_NOT_NULL(s);
847
848 SigGroupBuild(de_ctx);
849 DetectEngineCtxFree(de_ctx);
850
851 PASS;
852 }
853
854 /**
855 * \test FlowBitsTestSig03 is a test for a invalid flowbits option
856 *
857 * \retval 1 on succces
858 * \retval 0 on failure
859 */
860
FlowBitsTestSig03(void)861 static int FlowBitsTestSig03(void)
862 {
863 Signature *s = NULL;
864 DetectEngineCtx *de_ctx = NULL;
865
866 de_ctx = DetectEngineCtxInit();
867 FAIL_IF_NULL(de_ctx);
868
869 de_ctx->flags |= DE_QUIET;
870
871 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)");
872 FAIL_IF_NOT_NULL(s);
873
874 SigGroupBuild(de_ctx);
875 DetectEngineCtxFree(de_ctx);
876 PASS;
877 }
878
879 /**
880 * \test FlowBitsTestSig04 is a test check idx value
881 *
882 * \retval 1 on succces
883 * \retval 0 on failure
884 */
885
FlowBitsTestSig04(void)886 static int FlowBitsTestSig04(void)
887 {
888 Signature *s = NULL;
889 DetectEngineCtx *de_ctx = NULL;
890 int idx = 0;
891 de_ctx = DetectEngineCtxInit();
892 FAIL_IF_NULL(de_ctx);
893
894 de_ctx->flags |= DE_QUIET;
895
896 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)");
897 FAIL_IF_NULL(s);
898
899 idx = VarNameStoreSetupAdd("fbt", VAR_TYPE_FLOW_BIT);
900 FAIL_IF(idx != 1);
901
902 SigGroupBuild(de_ctx);
903 DetectEngineCtxFree(de_ctx);
904 PASS;
905 }
906
907 /**
908 * \test FlowBitsTestSig05 is a test check noalert flag
909 *
910 * \retval 1 on succces
911 * \retval 0 on failure
912 */
913
FlowBitsTestSig05(void)914 static int FlowBitsTestSig05(void)
915 {
916 Signature *s = NULL;
917 DetectEngineCtx *de_ctx = NULL;
918
919 de_ctx = DetectEngineCtxInit();
920 FAIL_IF_NULL(de_ctx);
921
922 de_ctx->flags |= DE_QUIET;
923
924 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)");
925 FAIL_IF_NULL(s);
926 FAIL_IF((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT);
927
928 SigGroupBuild(de_ctx);
929 DetectEngineCtxFree(de_ctx);
930 PASS;
931 }
932
933 /**
934 * \test FlowBitsTestSig06 is a test set flowbits option
935 *
936 * \retval 1 on succces
937 * \retval 0 on failure
938 */
939
FlowBitsTestSig06(void)940 static int FlowBitsTestSig06(void)
941 {
942 uint8_t *buf = (uint8_t *)
943 "GET /one/ HTTP/1.1\r\n"
944 "Host: one.example.org\r\n"
945 "\r\n";
946 uint16_t buflen = strlen((char *)buf);
947 Packet *p = SCMalloc(SIZE_OF_PACKET);
948 FAIL_IF_NULL(p);
949 Signature *s = NULL;
950 ThreadVars th_v;
951 DetectEngineThreadCtx *det_ctx = NULL;
952 DetectEngineCtx *de_ctx = NULL;
953 Flow f;
954 GenericVar flowvar, *gv = NULL;
955 int result = 0;
956 uint32_t idx = 0;
957
958 memset(p, 0, SIZE_OF_PACKET);
959 memset(&th_v, 0, sizeof(th_v));
960 memset(&f, 0, sizeof(Flow));
961 memset(&flowvar, 0, sizeof(GenericVar));
962
963 FLOW_INITIALIZE(&f);
964 p->flow = &f;
965 p->flow->flowvar = &flowvar;
966
967 p->src.family = AF_INET;
968 p->dst.family = AF_INET;
969 p->payload = buf;
970 p->payload_len = buflen;
971 p->proto = IPPROTO_TCP;
972 p->flags |= PKT_HAS_FLOW;
973 p->flowflags |= FLOW_PKT_TOSERVER;
974
975 de_ctx = DetectEngineCtxInit();
976 FAIL_IF_NULL(de_ctx);
977
978 de_ctx->flags |= DE_QUIET;
979
980 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)");
981 FAIL_IF_NULL(s);
982
983 idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
984 SigGroupBuild(de_ctx);
985 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
986
987 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
988
989 gv = p->flow->flowvar;
990 FAIL_IF_NULL(gv);
991 for ( ; gv != NULL; gv = gv->next) {
992 if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
993 result = 1;
994 }
995 }
996 FAIL_IF_NOT(result);
997
998 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
999 DetectEngineCtxFree(de_ctx);
1000
1001 FLOW_DESTROY(&f);
1002
1003 SCFree(p);
1004 PASS;
1005 }
1006
1007 /**
1008 * \test FlowBitsTestSig07 is a test unset flowbits option
1009 *
1010 * \retval 1 on succces
1011 * \retval 0 on failure
1012 */
1013
FlowBitsTestSig07(void)1014 static int FlowBitsTestSig07(void)
1015 {
1016 uint8_t *buf = (uint8_t *)
1017 "GET /one/ HTTP/1.1\r\n"
1018 "Host: one.example.org\r\n"
1019 "\r\n";
1020 uint16_t buflen = strlen((char *)buf);
1021 Packet *p = SCMalloc(SIZE_OF_PACKET);
1022 FAIL_IF_NULL(p);
1023 Signature *s = NULL;
1024 ThreadVars th_v;
1025 DetectEngineThreadCtx *det_ctx = NULL;
1026 DetectEngineCtx *de_ctx = NULL;
1027 Flow f;
1028 GenericVar flowvar, *gv = NULL;
1029 int result = 0;
1030 uint32_t idx = 0;
1031
1032 memset(p, 0, SIZE_OF_PACKET);
1033 memset(&th_v, 0, sizeof(th_v));
1034 memset(&f, 0, sizeof(Flow));
1035 memset(&flowvar, 0, sizeof(GenericVar));
1036
1037 FLOW_INITIALIZE(&f);
1038 p->flow = &f;
1039 p->flow->flowvar = &flowvar;
1040
1041 p->src.family = AF_INET;
1042 p->dst.family = AF_INET;
1043 p->payload = buf;
1044 p->payload_len = buflen;
1045 p->proto = IPPROTO_TCP;
1046
1047 de_ctx = DetectEngineCtxInit();
1048 FAIL_IF_NULL(de_ctx);
1049
1050 de_ctx->flags |= DE_QUIET;
1051
1052 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)");
1053 FAIL_IF_NULL(s);
1054
1055 s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)");
1056 FAIL_IF_NULL(s);
1057
1058 idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
1059 SigGroupBuild(de_ctx);
1060 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1061
1062 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1063
1064 gv = p->flow->flowvar;
1065 FAIL_IF_NULL(gv);
1066
1067 for ( ; gv != NULL; gv = gv->next) {
1068 if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1069 result = 1;
1070 }
1071 }
1072 FAIL_IF(result);
1073
1074 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1075 DetectEngineCtxFree(de_ctx);
1076
1077 FLOW_DESTROY(&f);
1078
1079 SCFree(p);
1080 PASS;
1081 }
1082
1083 /**
1084 * \test FlowBitsTestSig08 is a test toogle flowbits option
1085 *
1086 * \retval 1 on succces
1087 * \retval 0 on failure
1088 */
1089
FlowBitsTestSig08(void)1090 static int FlowBitsTestSig08(void)
1091 {
1092 uint8_t *buf = (uint8_t *)
1093 "GET /one/ HTTP/1.1\r\n"
1094 "Host: one.example.org\r\n"
1095 "\r\n";
1096 uint16_t buflen = strlen((char *)buf);
1097 Packet *p = SCMalloc(SIZE_OF_PACKET);
1098 if (unlikely(p == NULL))
1099 return 0;
1100 Signature *s = NULL;
1101 ThreadVars th_v;
1102 DetectEngineThreadCtx *det_ctx = NULL;
1103 DetectEngineCtx *de_ctx = NULL;
1104 Flow f;
1105 GenericVar flowvar, *gv = NULL;
1106 int result = 0;
1107 uint32_t idx = 0;
1108
1109 memset(p, 0, SIZE_OF_PACKET);
1110 memset(&th_v, 0, sizeof(th_v));
1111 memset(&f, 0, sizeof(Flow));
1112 memset(&flowvar, 0, sizeof(GenericVar));
1113
1114 FLOW_INITIALIZE(&f);
1115 p->flow = &f;
1116 p->flow->flowvar = &flowvar;
1117
1118 p->src.family = AF_INET;
1119 p->dst.family = AF_INET;
1120 p->payload = buf;
1121 p->payload_len = buflen;
1122 p->proto = IPPROTO_TCP;
1123
1124 de_ctx = DetectEngineCtxInit();
1125 FAIL_IF_NULL(de_ctx);
1126
1127 de_ctx->flags |= DE_QUIET;
1128
1129 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)");
1130 FAIL_IF_NULL(s);
1131
1132 s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:toggle,myflow2; sid:11;)");
1133 FAIL_IF_NULL(s);
1134
1135 idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
1136 SigGroupBuild(de_ctx);
1137 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1138
1139 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1140
1141 gv = p->flow->flowvar;
1142 FAIL_IF_NULL(gv);
1143
1144 for ( ; gv != NULL; gv = gv->next) {
1145 if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1146 result = 1;
1147 }
1148 }
1149 FAIL_IF(result);
1150
1151 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1152 DetectEngineCtxFree(de_ctx);
1153
1154 FLOW_DESTROY(&f);
1155
1156 SCFree(p);
1157 PASS;
1158 }
1159
1160 /**
1161 * \test FlowBitsTestSig09 is to test isset flowbits option with oring
1162 *
1163 * \retval 1 on success
1164 * \retval 0 on failure
1165 */
1166
FlowBitsTestSig09(void)1167 static int FlowBitsTestSig09(void)
1168 {
1169 uint8_t *buf = (uint8_t *)
1170 "GET /one/ HTTP/1.1\r\n"
1171 "Host: one.example.org\r\n"
1172 "\r\n";
1173 uint16_t buflen = strlen((char *)buf);
1174 Packet *p = SCMalloc(SIZE_OF_PACKET);
1175 FAIL_IF_NULL(p);
1176 Signature *s = NULL;
1177 ThreadVars th_v;
1178 DetectEngineThreadCtx *det_ctx = NULL;
1179 DetectEngineCtx *de_ctx = NULL;
1180 Flow f;
1181
1182 memset(p, 0, SIZE_OF_PACKET);
1183 memset(&th_v, 0, sizeof(th_v));
1184 memset(&f, 0, sizeof(Flow));
1185
1186 FLOW_INITIALIZE(&f);
1187 p->flow = &f;
1188
1189 p->src.family = AF_INET;
1190 p->dst.family = AF_INET;
1191 p->payload = buf;
1192 p->payload_len = buflen;
1193 p->proto = IPPROTO_TCP;
1194 p->flags |= PKT_HAS_FLOW;
1195 p->flowflags |= FLOW_PKT_TOSERVER;
1196
1197 de_ctx = DetectEngineCtxInit();
1198 FAIL_IF_NULL(de_ctx);
1199
1200 de_ctx->flags |= DE_QUIET;
1201
1202 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb1; sid:1;)");
1203 FAIL_IF_NULL(s);
1204 s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb2; sid:2;)");
1205 FAIL_IF_NULL(s);
1206 s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit isset ored flowbits\"; flowbits:isset,fb3|fb4; sid:3;)");
1207 FAIL_IF_NULL(s);
1208
1209 SigGroupBuild(de_ctx);
1210 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1211
1212 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1213
1214 FAIL_IF_NOT(PacketAlertCheck(p, 1));
1215 FAIL_IF_NOT(PacketAlertCheck(p, 2));
1216 FAIL_IF(PacketAlertCheck(p, 3));
1217
1218 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1219 DetectEngineCtxFree(de_ctx);
1220
1221 FLOW_DESTROY(&f);
1222
1223 SCFree(p);
1224 PASS;
1225 }
1226
1227 /**
1228 * \test FlowBitsTestSig10 is to test isset flowbits option with oring
1229 *
1230 * \retval 1 on success
1231 * \retval 0 on failure
1232 */
1233
FlowBitsTestSig10(void)1234 static int FlowBitsTestSig10(void)
1235 {
1236 uint8_t *buf = (uint8_t *)
1237 "GET /one/ HTTP/1.1\r\n"
1238 "Host: one.example.org\r\n"
1239 "\r\n";
1240 uint16_t buflen = strlen((char *)buf);
1241 Packet *p = SCMalloc(SIZE_OF_PACKET);
1242 FAIL_IF_NULL(p);
1243 Signature *s = NULL;
1244 ThreadVars th_v;
1245 DetectEngineThreadCtx *det_ctx = NULL;
1246 DetectEngineCtx *de_ctx = NULL;
1247 Flow f;
1248
1249 memset(p, 0, SIZE_OF_PACKET);
1250 memset(&th_v, 0, sizeof(th_v));
1251 memset(&f, 0, sizeof(Flow));
1252
1253 FLOW_INITIALIZE(&f);
1254 p->flow = &f;
1255
1256 p->src.family = AF_INET;
1257 p->dst.family = AF_INET;
1258 p->payload = buf;
1259 p->payload_len = buflen;
1260 p->proto = IPPROTO_TCP;
1261 p->flags |= PKT_HAS_FLOW;
1262 p->flowflags |= FLOW_PKT_TOSERVER;
1263
1264 de_ctx = DetectEngineCtxInit();
1265 FAIL_IF_NULL(de_ctx);
1266
1267 de_ctx->flags |= DE_QUIET;
1268
1269 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb1; sid:1;)");
1270 FAIL_IF_NULL(s);
1271 s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb2; sid:2;)");
1272 FAIL_IF_NULL(s);
1273 s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb3; sid:3;)");
1274 FAIL_IF_NULL(s);
1275 s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit isset ored flowbits\"; flowbits:isset,fb3|fb4; sid:4;)");
1276 FAIL_IF_NULL(s);
1277
1278 SigGroupBuild(de_ctx);
1279 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1280
1281 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1282
1283 FAIL_IF_NOT(PacketAlertCheck(p, 1));
1284 FAIL_IF_NOT(PacketAlertCheck(p, 2));
1285 FAIL_IF_NOT(PacketAlertCheck(p, 3));
1286 FAIL_IF_NOT(PacketAlertCheck(p, 4));
1287
1288 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1289 DetectEngineCtxFree(de_ctx);
1290
1291 FLOW_DESTROY(&f);
1292
1293 SCFree(p);
1294 PASS;
1295 }
1296
1297 /**
1298 * \test FlowBitsTestSig11 is to test isnotset flowbits option with oring
1299 *
1300 * \retval 1 on success
1301 * \retval 0 on failure
1302 */
1303
FlowBitsTestSig11(void)1304 static int FlowBitsTestSig11(void)
1305 {
1306 uint8_t *buf = (uint8_t *)
1307 "GET /one/ HTTP/1.1\r\n"
1308 "Host: one.example.org\r\n"
1309 "\r\n";
1310 uint16_t buflen = strlen((char *)buf);
1311 Packet *p = SCMalloc(SIZE_OF_PACKET);
1312 FAIL_IF_NULL(p);
1313 Signature *s = NULL;
1314 ThreadVars th_v;
1315 DetectEngineThreadCtx *det_ctx = NULL;
1316 DetectEngineCtx *de_ctx = NULL;
1317 Flow f;
1318
1319 memset(p, 0, SIZE_OF_PACKET);
1320 memset(&th_v, 0, sizeof(th_v));
1321 memset(&f, 0, sizeof(Flow));
1322
1323 FLOW_INITIALIZE(&f);
1324 p->flow = &f;
1325
1326 p->src.family = AF_INET;
1327 p->dst.family = AF_INET;
1328 p->payload = buf;
1329 p->payload_len = buflen;
1330 p->proto = IPPROTO_TCP;
1331 p->flags |= PKT_HAS_FLOW;
1332 p->flowflags |= FLOW_PKT_TOSERVER;
1333
1334 de_ctx = DetectEngineCtxInit();
1335 FAIL_IF_NULL(de_ctx);
1336
1337 de_ctx->flags |= DE_QUIET;
1338
1339 s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb1; sid:1;)");
1340 FAIL_IF_NULL(s);
1341 s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb2; sid:2;)");
1342 FAIL_IF_NULL(s);
1343 s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb3; sid:3;)");
1344 FAIL_IF_NULL(s);
1345 s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit isnotset ored flowbits\"; flowbits:isnotset, fb1 | fb2 ; sid:4;)");
1346 FAIL_IF_NULL(s);
1347
1348 SigGroupBuild(de_ctx);
1349 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1350
1351 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1352
1353 FAIL_IF_NOT(PacketAlertCheck(p, 1));
1354 FAIL_IF_NOT(PacketAlertCheck(p, 2));
1355 FAIL_IF_NOT(PacketAlertCheck(p, 3));
1356 FAIL_IF(PacketAlertCheck(p, 4));
1357
1358 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1359 DetectEngineCtxFree(de_ctx);
1360
1361 FLOW_DESTROY(&f);
1362
1363 SCFree(p);
1364 PASS;
1365 }
1366
1367 /**
1368 * \brief this function registers unit tests for FlowBits
1369 */
FlowBitsRegisterTests(void)1370 void FlowBitsRegisterTests(void)
1371 {
1372 UtRegisterTest("FlowBitsTestParse01", FlowBitsTestParse01);
1373 UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01);
1374 UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02);
1375 UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03);
1376 UtRegisterTest("FlowBitsTestSig04", FlowBitsTestSig04);
1377 UtRegisterTest("FlowBitsTestSig05", FlowBitsTestSig05);
1378 UtRegisterTest("FlowBitsTestSig06", FlowBitsTestSig06);
1379 UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07);
1380 UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08);
1381 UtRegisterTest("FlowBitsTestSig09", FlowBitsTestSig09);
1382 UtRegisterTest("FlowBitsTestSig10", FlowBitsTestSig10);
1383 UtRegisterTest("FlowBitsTestSig11", FlowBitsTestSig11);
1384 }
1385 #endif /* UNITTESTS */
1386