suricata
detect-flowbits.c
Go to the documentation of this file.
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 
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 
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";
68  sigmatch_table[DETECT_FLOWBITS].Setup = DetectFlowbitSetup;
70 #ifdef UNITTESTS
72 #endif
73  /* this is compatible to ip-only signatures */
75 
76  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
77 }
78 
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);
119  }
120 
121  return 1;
122 }
123 
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 
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 
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 
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 
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 
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) {
198  return DetectFlowbitMatchIsset(p,fd);
200  return DetectFlowbitMatchIsnotset(p,fd);
202  return DetectFlowbitMatchSet(p,fd);
204  return DetectFlowbitMatchUnset(p,fd);
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 
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) {
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])) {
253  "spaces not allowed in flowbit names");
254  return 0;
255  }
256  }
257  }
258  }
259 
260  return 1;
261 }
262 
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) {
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) {
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) {
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) {
294  if (strlen(fb_name) != 0)
295  goto error;
296  s->flags |= SIG_FLAG_NOALERT;
297  return 0;
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 {
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 
341  /* checks, so packet list */
343  break;
344 
348  /* modifiers, only run when entire sig has matched */
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)
363  if (sm != NULL)
364  SCFree(sm);
365  return -1;
366 }
367 
369 {
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 {
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;
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;
401 };
402 #ifdef PROFILING
403 static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
404  struct FBAnalyze *array, uint32_t elements);
405 #endif
406 
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 &&
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,
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,
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) {
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 #ifdef PROFILING
633  DetectFlowbitsAnalyzeDump(de_ctx, array, array_size);
634 #endif
635 
636 end:
637  for (uint32_t i = 0; i < array_size; i++) {
638  SCFree(array[i].set_sids);
639  SCFree(array[i].unset_sids);
640  SCFree(array[i].isset_sids);
641  SCFree(array[i].isnotset_sids);
642  SCFree(array[i].toggle_sids);
643  }
644  SCFree(array);
645 
646  return 0;
647 }
648 
649 #ifdef PROFILING
650 #include "output-json.h"
651 #include "util-buffer.h"
653 static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
654  struct FBAnalyze *array, uint32_t elements)
655 {
656  json_t *js = json_object();
657  if (js == NULL)
658  return;
659 
660  json_t *js_array = json_array();
661  uint32_t x;
662  for (x = 0; x < elements; x++)
663  {
664  char *varname = VarNameStoreSetupLookup(x, VAR_TYPE_FLOW_BIT);
665  if (varname == NULL)
666  continue;
667 
668  const struct FBAnalyze *e = &array[x];
669 
670  json_t *js_fb = json_object();
671  if (unlikely(js_fb != NULL)) {
672  json_object_set_new(js_fb, "name", json_string(varname));
673  json_object_set_new(js_fb, "internal_id", json_integer(x));
674  json_object_set_new(js_fb, "set_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_SET]));
675  json_object_set_new(js_fb, "unset_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_UNSET]));
676  json_object_set_new(js_fb, "toggle_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_TOGGLE]));
677  json_object_set_new(js_fb, "isset_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_ISSET]));
678  json_object_set_new(js_fb, "isnotset_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_ISNOTSET]));
679 
680  // sets
681  if (e->cnts[DETECT_FLOWBITS_CMD_SET]) {
682  json_t *js_set_array = json_array();
683  if (js_set_array) {
684  for(uint32_t i = 0; i < e->set_sids_idx; i++) {
685  const Signature *s = de_ctx->sig_array[e->set_sids[i]];
686  json_array_append_new(js_set_array, json_integer(s->id));
687  }
688  json_object_set_new(js_fb, "sets", js_set_array);
689  }
690  }
691  // gets
693  json_t *js_isset_array = json_array();
694  if (js_isset_array) {
695  for(uint32_t i = 0; i < e->isset_sids_idx; i++) {
696  const Signature *s = de_ctx->sig_array[e->isset_sids[i]];
697  json_array_append_new(js_isset_array, json_integer(s->id));
698  }
699  json_object_set_new(js_fb, "isset", js_isset_array);
700  }
701  }
702  // isnotset
704  json_t *js_isnotset_array = json_array();
705  if (js_isnotset_array) {
706  for(uint32_t i = 0; i < e->isnotset_sids_idx; i++) {
707  const Signature *s = de_ctx->sig_array[e->isnotset_sids[i]];
708  json_array_append_new(js_isnotset_array, json_integer(s->id));
709  }
710  json_object_set_new(js_fb, "isnotset", js_isnotset_array);
711  }
712  }
713  // unset
715  json_t *js_unset_array = json_array();
716  if (js_unset_array) {
717  for(uint32_t i = 0; i < e->unset_sids_idx; i++) {
718  const Signature *s = de_ctx->sig_array[e->unset_sids[i]];
719  json_array_append_new(js_unset_array, json_integer(s->id));
720  }
721  json_object_set_new(js_fb, "unset", js_unset_array);
722  }
723  }
724  // toggle
726  json_t *js_toggle_array = json_array();
727  if (js_toggle_array) {
728  for(uint32_t i = 0; i < e->toggle_sids_idx; i++) {
729  const Signature *s = de_ctx->sig_array[e->toggle_sids[i]];
730  json_array_append_new(js_toggle_array, json_integer(s->id));
731  }
732  json_object_set_new(js_fb, "toggle", js_toggle_array);
733  }
734  }
735 
736  json_array_append_new(js_array, js_fb);
737  }
738  SCFree(varname);
739  }
740 
741  json_object_set_new(js, "flowbits", js_array);
742 
743  const char *filename = "flowbits.json";
744  const char *log_dir = ConfigGetLogDirectory();
745  char log_path[PATH_MAX] = "";
746  snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, filename);
747 
748  MemBuffer *mbuf = NULL;
749  mbuf = MemBufferCreateNew(4096);
750  BUG_ON(mbuf == NULL);
751 
752  OutputJSONMemBufferWrapper wrapper = {
753  .buffer = &mbuf,
754  .expand_by = 4096,
755  };
756 
757  int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper,
758  JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
760  if (r != 0) {
761  SCLogWarning(SC_ERR_SOCKET, "unable to serialize JSON object");
762  } else {
763  MemBufferWriteString(mbuf, "\n");
765  FILE *fp = fopen(log_path, "w");
766  if (fp != NULL) {
767  MemBufferPrintToFPAsString(mbuf, fp);
768  fclose(fp);
769  }
771  }
772 
773  MemBufferFree(mbuf);
774  json_object_clear(js);
775  json_decref(js);
776 }
777 #endif /* PROFILING */
778 
779 #ifdef UNITTESTS
780 
781 static int FlowBitsTestParse01(void)
782 {
783  char command[16] = "", name[16] = "";
784 
785  /* Single argument version. */
786  FAIL_IF(!DetectFlowbitParse("noalert", command, sizeof(command), name,
787  sizeof(name)));
788  FAIL_IF(strcmp(command, "noalert") != 0);
789 
790  /* No leading or trailing spaces. */
791  FAIL_IF(!DetectFlowbitParse("set,flowbit", command, sizeof(command), name,
792  sizeof(name)));
793  FAIL_IF(strcmp(command, "set") != 0);
794  FAIL_IF(strcmp(name, "flowbit") != 0);
795 
796  /* Leading space. */
797  FAIL_IF(!DetectFlowbitParse("set, flowbit", command, sizeof(command), name,
798  sizeof(name)));
799  FAIL_IF(strcmp(command, "set") != 0);
800  FAIL_IF(strcmp(name, "flowbit") != 0);
801 
802  /* Trailing space. */
803  FAIL_IF(!DetectFlowbitParse("set,flowbit ", command, sizeof(command), name,
804  sizeof(name)));
805  FAIL_IF(strcmp(command, "set") != 0);
806  FAIL_IF(strcmp(name, "flowbit") != 0);
807 
808  /* Leading and trailing space. */
809  FAIL_IF(!DetectFlowbitParse("set, flowbit ", command, sizeof(command), name,
810  sizeof(name)));
811  FAIL_IF(strcmp(command, "set") != 0);
812  FAIL_IF(strcmp(name, "flowbit") != 0);
813 
814  /* Spaces are not allowed in the name. */
815  FAIL_IF(DetectFlowbitParse("set,namewith space", command, sizeof(command),
816  name, sizeof(name)));
817 
818  PASS;
819 }
820 
821 /**
822  * \test FlowBitsTestSig01 is a test for a valid noalert flowbits option
823  *
824  * \retval 1 on succces
825  * \retval 0 on failure
826  */
827 
828 static int FlowBitsTestSig01(void)
829 {
830  Signature *s = NULL;
831  DetectEngineCtx *de_ctx = NULL;
832 
835 
836  de_ctx->flags |= DE_QUIET;
837 
838  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)");
839  FAIL_IF_NOT_NULL(s);
840 
843  PASS;
844 }
845 
846 /**
847  * \test FlowBitsTestSig02 is a test for a valid isset,set,isnotset,unset,toggle flowbits options
848  *
849  * \retval 1 on succces
850  * \retval 0 on failure
851  */
852 
853 static int FlowBitsTestSig02(void)
854 {
855  Signature *s = NULL;
856  ThreadVars th_v;
857  DetectEngineCtx *de_ctx = NULL;
858 
859  memset(&th_v, 0, sizeof(th_v));
860 
863 
864  de_ctx->flags |= DE_QUIET;
865 
866  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;)");
867  FAIL_IF_NOT_NULL(s);
868 
869  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;)");
870  FAIL_IF_NOT_NULL(s);
871 
872  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;)");
873  FAIL_IF_NOT_NULL(s);
874 
875  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;)");
876  FAIL_IF_NOT_NULL(s);
877 
878  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;)");
879  FAIL_IF_NOT_NULL(s);
880 
881  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;)");
882  FAIL_IF_NOT_NULL(s);
883 
886 
887  PASS;
888 }
889 
890 /**
891  * \test FlowBitsTestSig03 is a test for a invalid flowbits option
892  *
893  * \retval 1 on succces
894  * \retval 0 on failure
895  */
896 
897 static int FlowBitsTestSig03(void)
898 {
899  Signature *s = NULL;
900  DetectEngineCtx *de_ctx = NULL;
901 
904 
905  de_ctx->flags |= DE_QUIET;
906 
907  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)");
908  FAIL_IF_NOT_NULL(s);
909 
912  PASS;
913 }
914 
915 /**
916  * \test FlowBitsTestSig04 is a test check idx value
917  *
918  * \retval 1 on succces
919  * \retval 0 on failure
920  */
921 
922 static int FlowBitsTestSig04(void)
923 {
924  Signature *s = NULL;
925  DetectEngineCtx *de_ctx = NULL;
926  int idx = 0;
929 
930  de_ctx->flags |= DE_QUIET;
931 
932  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)");
933  FAIL_IF_NULL(s);
934 
936  FAIL_IF(idx != 1);
937 
940  PASS;
941 }
942 
943 /**
944  * \test FlowBitsTestSig05 is a test check noalert flag
945  *
946  * \retval 1 on succces
947  * \retval 0 on failure
948  */
949 
950 static int FlowBitsTestSig05(void)
951 {
952  Signature *s = NULL;
953  DetectEngineCtx *de_ctx = NULL;
954 
957 
958  de_ctx->flags |= DE_QUIET;
959 
960  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)");
961  FAIL_IF_NULL(s);
963 
966  PASS;
967 }
968 
969 /**
970  * \test FlowBitsTestSig06 is a test set flowbits option
971  *
972  * \retval 1 on succces
973  * \retval 0 on failure
974  */
975 
976 static int FlowBitsTestSig06(void)
977 {
978  uint8_t *buf = (uint8_t *)
979  "GET /one/ HTTP/1.1\r\n"
980  "Host: one.example.org\r\n"
981  "\r\n";
982  uint16_t buflen = strlen((char *)buf);
984  FAIL_IF_NULL(p);
985  Signature *s = NULL;
986  ThreadVars th_v;
987  DetectEngineThreadCtx *det_ctx = NULL;
988  DetectEngineCtx *de_ctx = NULL;
989  Flow f;
990  GenericVar flowvar, *gv = NULL;
991  int result = 0;
992  uint32_t idx = 0;
993 
994  memset(p, 0, SIZE_OF_PACKET);
995  memset(&th_v, 0, sizeof(th_v));
996  memset(&f, 0, sizeof(Flow));
997  memset(&flowvar, 0, sizeof(GenericVar));
998 
999  FLOW_INITIALIZE(&f);
1000  p->flow = &f;
1001  p->flow->flowvar = &flowvar;
1002 
1003  p->src.family = AF_INET;
1004  p->dst.family = AF_INET;
1005  p->payload = buf;
1006  p->payload_len = buflen;
1007  p->proto = IPPROTO_TCP;
1008  p->flags |= PKT_HAS_FLOW;
1010 
1013 
1014  de_ctx->flags |= DE_QUIET;
1015 
1016  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)");
1017  FAIL_IF_NULL(s);
1018 
1019  idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
1021  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1022 
1023  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1024 
1025  gv = p->flow->flowvar;
1026  FAIL_IF_NULL(gv);
1027  for ( ; gv != NULL; gv = gv->next) {
1028  if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1029  result = 1;
1030  }
1031  }
1032  FAIL_IF_NOT(result);
1033 
1034  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1036 
1037  FLOW_DESTROY(&f);
1038 
1039  SCFree(p);
1040  PASS;
1041 }
1042 
1043 /**
1044  * \test FlowBitsTestSig07 is a test unset flowbits option
1045  *
1046  * \retval 1 on succces
1047  * \retval 0 on failure
1048  */
1049 
1050 static int FlowBitsTestSig07(void)
1051 {
1052  uint8_t *buf = (uint8_t *)
1053  "GET /one/ HTTP/1.1\r\n"
1054  "Host: one.example.org\r\n"
1055  "\r\n";
1056  uint16_t buflen = strlen((char *)buf);
1058  FAIL_IF_NULL(p);
1059  Signature *s = NULL;
1060  ThreadVars th_v;
1061  DetectEngineThreadCtx *det_ctx = NULL;
1062  DetectEngineCtx *de_ctx = NULL;
1063  Flow f;
1064  GenericVar flowvar, *gv = NULL;
1065  int result = 0;
1066  uint32_t idx = 0;
1067 
1068  memset(p, 0, SIZE_OF_PACKET);
1069  memset(&th_v, 0, sizeof(th_v));
1070  memset(&f, 0, sizeof(Flow));
1071  memset(&flowvar, 0, sizeof(GenericVar));
1072 
1073  FLOW_INITIALIZE(&f);
1074  p->flow = &f;
1075  p->flow->flowvar = &flowvar;
1076 
1077  p->src.family = AF_INET;
1078  p->dst.family = AF_INET;
1079  p->payload = buf;
1080  p->payload_len = buflen;
1081  p->proto = IPPROTO_TCP;
1082 
1085 
1086  de_ctx->flags |= DE_QUIET;
1087 
1088  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)");
1089  FAIL_IF_NULL(s);
1090 
1091  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)");
1092  FAIL_IF_NULL(s);
1093 
1094  idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
1096  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1097 
1098  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1099 
1100  gv = p->flow->flowvar;
1101  FAIL_IF_NULL(gv);
1102 
1103  for ( ; gv != NULL; gv = gv->next) {
1104  if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1105  result = 1;
1106  }
1107  }
1108  FAIL_IF(result);
1109 
1110  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1112 
1113  FLOW_DESTROY(&f);
1114 
1115  SCFree(p);
1116  PASS;
1117 }
1118 
1119 /**
1120  * \test FlowBitsTestSig08 is a test toogle flowbits option
1121  *
1122  * \retval 1 on succces
1123  * \retval 0 on failure
1124  */
1125 
1126 static int FlowBitsTestSig08(void)
1127 {
1128  uint8_t *buf = (uint8_t *)
1129  "GET /one/ HTTP/1.1\r\n"
1130  "Host: one.example.org\r\n"
1131  "\r\n";
1132  uint16_t buflen = strlen((char *)buf);
1134  if (unlikely(p == NULL))
1135  return 0;
1136  Signature *s = NULL;
1137  ThreadVars th_v;
1138  DetectEngineThreadCtx *det_ctx = NULL;
1139  DetectEngineCtx *de_ctx = NULL;
1140  Flow f;
1141  GenericVar flowvar, *gv = NULL;
1142  int result = 0;
1143  uint32_t idx = 0;
1144 
1145  memset(p, 0, SIZE_OF_PACKET);
1146  memset(&th_v, 0, sizeof(th_v));
1147  memset(&f, 0, sizeof(Flow));
1148  memset(&flowvar, 0, sizeof(GenericVar));
1149 
1150  FLOW_INITIALIZE(&f);
1151  p->flow = &f;
1152  p->flow->flowvar = &flowvar;
1153 
1154  p->src.family = AF_INET;
1155  p->dst.family = AF_INET;
1156  p->payload = buf;
1157  p->payload_len = buflen;
1158  p->proto = IPPROTO_TCP;
1159 
1162 
1163  de_ctx->flags |= DE_QUIET;
1164 
1165  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)");
1166  FAIL_IF_NULL(s);
1167 
1168  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:toggle,myflow2; sid:11;)");
1169  FAIL_IF_NULL(s);
1170 
1171  idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
1173  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1174 
1175  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1176 
1177  gv = p->flow->flowvar;
1178  FAIL_IF_NULL(gv);
1179 
1180  for ( ; gv != NULL; gv = gv->next) {
1181  if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1182  result = 1;
1183  }
1184  }
1185  FAIL_IF(result);
1186 
1187  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1189 
1190  FLOW_DESTROY(&f);
1191 
1192  SCFree(p);
1193  PASS;
1194 }
1195 
1196 /**
1197  * \test FlowBitsTestSig09 is to test isset flowbits option with oring
1198  *
1199  * \retval 1 on success
1200  * \retval 0 on failure
1201  */
1202 
1203 static int FlowBitsTestSig09(void)
1204 {
1205  uint8_t *buf = (uint8_t *)
1206  "GET /one/ HTTP/1.1\r\n"
1207  "Host: one.example.org\r\n"
1208  "\r\n";
1209  uint16_t buflen = strlen((char *)buf);
1211  FAIL_IF_NULL(p);
1212  Signature *s = NULL;
1213  ThreadVars th_v;
1214  DetectEngineThreadCtx *det_ctx = NULL;
1215  DetectEngineCtx *de_ctx = NULL;
1216  Flow f;
1217 
1218  memset(p, 0, SIZE_OF_PACKET);
1219  memset(&th_v, 0, sizeof(th_v));
1220  memset(&f, 0, sizeof(Flow));
1221 
1222  FLOW_INITIALIZE(&f);
1223  p->flow = &f;
1224 
1225  p->src.family = AF_INET;
1226  p->dst.family = AF_INET;
1227  p->payload = buf;
1228  p->payload_len = buflen;
1229  p->proto = IPPROTO_TCP;
1230  p->flags |= PKT_HAS_FLOW;
1232 
1235 
1236  de_ctx->flags |= DE_QUIET;
1237 
1238  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb1; sid:1;)");
1239  FAIL_IF_NULL(s);
1240  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb2; sid:2;)");
1241  FAIL_IF_NULL(s);
1242  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit isset ored flowbits\"; flowbits:isset,fb3|fb4; sid:3;)");
1243  FAIL_IF_NULL(s);
1244 
1246  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1247 
1248  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1249 
1252  FAIL_IF(PacketAlertCheck(p, 3));
1253 
1254  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1256 
1257  FLOW_DESTROY(&f);
1258 
1259  SCFree(p);
1260  PASS;
1261 }
1262 
1263 /**
1264  * \test FlowBitsTestSig10 is to test isset flowbits option with oring
1265  *
1266  * \retval 1 on success
1267  * \retval 0 on failure
1268  */
1269 
1270 static int FlowBitsTestSig10(void)
1271 {
1272  uint8_t *buf = (uint8_t *)
1273  "GET /one/ HTTP/1.1\r\n"
1274  "Host: one.example.org\r\n"
1275  "\r\n";
1276  uint16_t buflen = strlen((char *)buf);
1278  FAIL_IF_NULL(p);
1279  Signature *s = NULL;
1280  ThreadVars th_v;
1281  DetectEngineThreadCtx *det_ctx = NULL;
1282  DetectEngineCtx *de_ctx = NULL;
1283  Flow f;
1284 
1285  memset(p, 0, SIZE_OF_PACKET);
1286  memset(&th_v, 0, sizeof(th_v));
1287  memset(&f, 0, sizeof(Flow));
1288 
1289  FLOW_INITIALIZE(&f);
1290  p->flow = &f;
1291 
1292  p->src.family = AF_INET;
1293  p->dst.family = AF_INET;
1294  p->payload = buf;
1295  p->payload_len = buflen;
1296  p->proto = IPPROTO_TCP;
1297  p->flags |= PKT_HAS_FLOW;
1299 
1302 
1303  de_ctx->flags |= DE_QUIET;
1304 
1305  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb1; sid:1;)");
1306  FAIL_IF_NULL(s);
1307  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb2; sid:2;)");
1308  FAIL_IF_NULL(s);
1309  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb3; sid:3;)");
1310  FAIL_IF_NULL(s);
1311  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit isset ored flowbits\"; flowbits:isset,fb3|fb4; sid:4;)");
1312  FAIL_IF_NULL(s);
1313 
1315  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1316 
1317  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1318 
1323 
1324  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1326 
1327  FLOW_DESTROY(&f);
1328 
1329  SCFree(p);
1330  PASS;
1331 }
1332 
1333 /**
1334  * \test FlowBitsTestSig11 is to test isnotset flowbits option with oring
1335  *
1336  * \retval 1 on success
1337  * \retval 0 on failure
1338  */
1339 
1340 static int FlowBitsTestSig11(void)
1341 {
1342  uint8_t *buf = (uint8_t *)
1343  "GET /one/ HTTP/1.1\r\n"
1344  "Host: one.example.org\r\n"
1345  "\r\n";
1346  uint16_t buflen = strlen((char *)buf);
1348  FAIL_IF_NULL(p);
1349  Signature *s = NULL;
1350  ThreadVars th_v;
1351  DetectEngineThreadCtx *det_ctx = NULL;
1352  DetectEngineCtx *de_ctx = NULL;
1353  Flow f;
1354 
1355  memset(p, 0, SIZE_OF_PACKET);
1356  memset(&th_v, 0, sizeof(th_v));
1357  memset(&f, 0, sizeof(Flow));
1358 
1359  FLOW_INITIALIZE(&f);
1360  p->flow = &f;
1361 
1362  p->src.family = AF_INET;
1363  p->dst.family = AF_INET;
1364  p->payload = buf;
1365  p->payload_len = buflen;
1366  p->proto = IPPROTO_TCP;
1367  p->flags |= PKT_HAS_FLOW;
1369 
1372 
1373  de_ctx->flags |= DE_QUIET;
1374 
1375  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb1; sid:1;)");
1376  FAIL_IF_NULL(s);
1377  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb2; sid:2;)");
1378  FAIL_IF_NULL(s);
1379  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb3; sid:3;)");
1380  FAIL_IF_NULL(s);
1381  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit isnotset ored flowbits\"; flowbits:isnotset, fb1 | fb2 ; sid:4;)");
1382  FAIL_IF_NULL(s);
1383 
1385  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1386 
1387  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1388 
1392  FAIL_IF(PacketAlertCheck(p, 4));
1393 
1394  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1396 
1397  FLOW_DESTROY(&f);
1398 
1399  SCFree(p);
1400  PASS;
1401 }
1402 
1403 /**
1404  * \brief this function registers unit tests for FlowBits
1405  */
1407 {
1408  UtRegisterTest("FlowBitsTestParse01", FlowBitsTestParse01);
1409  UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01);
1410  UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02);
1411  UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03);
1412  UtRegisterTest("FlowBitsTestSig04", FlowBitsTestSig04);
1413  UtRegisterTest("FlowBitsTestSig05", FlowBitsTestSig05);
1414  UtRegisterTest("FlowBitsTestSig06", FlowBitsTestSig06);
1415  UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07);
1416  UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08);
1417  UtRegisterTest("FlowBitsTestSig09", FlowBitsTestSig09);
1418  UtRegisterTest("FlowBitsTestSig10", FlowBitsTestSig10);
1419  UtRegisterTest("FlowBitsTestSig11", FlowBitsTestSig11);
1420 }
1421 #endif /* UNITTESTS */
FBAnalyze::cnts
uint16_t cnts[DETECT_FLOWBITS_CMD_MAX]
Definition: detect-flowbits.c:379
GenericVar_::type
uint8_t type
Definition: util-var.h:49
FBAnalyze::isset_sids
uint32_t * isset_sids
Definition: detect-flowbits.c:386
SigTableElmt_::url
const char * url
Definition: detect.h:1213
Packet_::proto
uint8_t proto
Definition: decode.h:434
FBAnalyze::isnotset_sids_idx
uint32_t isnotset_sids_idx
Definition: detect-flowbits.c:391
g_flowbits_dump_write_m
SCMutex g_flowbits_dump_write_m
Definition: detect-flowbits.c:652
DetectFlowbitsData_::or_list_size
uint8_t or_list_size
Definition: detect-flowbits.h:39
detect-engine.h
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
DETECT_FLOWBITS_CMD_MAX
#define DETECT_FLOWBITS_CMD_MAX
Definition: detect-flowbits.h:34
SigTableElmt_::desc
const char * desc
Definition: detect.h:1212
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1104
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1200
flow-util.h
SC_ERR_SOCKET
@ SC_ERR_SOCKET
Definition: util-error.h:232
SigTableElmt_::name
const char * name
Definition: detect.h:1210
Signature_::num
SigIntId num
Definition: detect.h:537
FBAnalyze::isnotset_sids
uint32_t * isnotset_sids
Definition: detect-flowbits.c:390
FlowBitsRegisterTests
void FlowBitsRegisterTests(void)
this function registers unit tests for FlowBits
Definition: detect-flowbits.c:1406
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
MAX_SIDS
#define MAX_SIDS
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
FBAnalyze::unset_sids_size
uint32_t unset_sids_size
Definition: detect-flowbits.c:396
MAX_TOKENS
#define MAX_TOKENS
Definition: detect-flowbits.c:51
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
DETECT_SM_LIST_DYNAMIC_START
@ DETECT_SM_LIST_DYNAMIC_START
Definition: detect.h:109
DETECT_FLOWBITS_CMD_ISNOTSET
#define DETECT_FLOWBITS_CMD_ISNOTSET
Definition: detect-flowbits.h:31
Packet_::payload
uint8_t * payload
Definition: decode.h:547
PacketAlertCheck
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
Definition: detect-engine-alert.c:138
Packet_::flags
uint32_t flags
Definition: decode.h:447
threads.h
Flow_
Flow data structure.
Definition: flow.h:347
SigInit
Signature * SigInit(DetectEngineCtx *, const char *)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:2039
DetectFlowbitsAnalyze
int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx)
Definition: detect-flowbits.c:407
SigTableElmt_::flags
uint16_t flags
Definition: detect.h:1204
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:766
VarNameStoreSetupLookup
char * VarNameStoreSetupLookup(uint32_t idx, const enum VarTypes type)
Definition: util-var-name.c:332
SC_ERR_INVALID_SIGNATURE
@ SC_ERR_INVALID_SIGNATURE
Definition: util-error.h:69
DetectFlowbitsData_::cmd
uint8_t cmd
Definition: detect-flowbits.h:38
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2093
flow-bit.h
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:219
util-var-name.h
DE_QUIET
#define DE_QUIET
Definition: detect.h:293
OutputJSONMemBufferWrapper_::buffer
MemBuffer ** buffer
Definition: output-json.h:67
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
SignatureInitData_::init_flags
uint32_t init_flags
Definition: detect.h:492
JSON_ESCAPE_SLASH
#define JSON_ESCAPE_SLASH
Definition: suricata-common.h:258
DETECT_FLOWBITS_CMD_TOGGLE
#define DETECT_FLOWBITS_CMD_TOGGLE
Definition: detect-flowbits.h:29
DETECT_FLOWBITS_CMD_ISSET
#define DETECT_FLOWBITS_CMD_ISSET
Definition: detect-flowbits.h:32
SC_ERR_PCRE_GET_SUBSTRING
@ SC_ERR_PCRE_GET_SUBSTRING
Definition: util-error.h:34
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:443
MAX
#define MAX(x, y)
Definition: suricata-common.h:381
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1195
Packet_::payload_len
uint16_t payload_len
Definition: decode.h:548
util-unittest.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
Signature_::next
struct Signature_ * next
Definition: detect.h:599
FlowBitUnset
void FlowBitUnset(Flow *f, uint32_t idx)
Definition: flow-bit.c:89
DetectFlowbitsData_
Definition: detect-flowbits.h:36
DETECT_SM_LIST_POSTMATCH
@ DETECT_SM_LIST_POSTMATCH
Definition: detect.h:98
FLOW_INITIALIZE
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
decode.h
FAIL_IF_NOT_NULL
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
util-debug.h
SC_ERR_PCRE_MATCH
@ SC_ERR_PCRE_MATCH
Definition: util-error.h:32
GenericVar_::next
struct GenericVar_ * next
Definition: util-var.h:52
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
PARSE_REGEX
#define PARSE_REGEX
Definition: detect-flowbits.c:48
DetectEngineThreadCtx_
Definition: detect.h:1009
output-json.h
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
SC_ERR_UNKNOWN_VALUE
@ SC_ERR_UNKNOWN_VALUE
Definition: util-error.h:159
DetectSetupParseRegexes
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
Definition: detect-parse.c:2476
FlowBitSet
void FlowBitSet(Flow *f, uint32_t idx)
Definition: flow-bit.c:84
detect-engine-mpm.h
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
FBAnalyze::toggle_sids_idx
uint32_t toggle_sids_idx
Definition: detect-flowbits.c:399
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:323
FBAnalyze::set_sids_size
uint32_t set_sids_size
Definition: detect-flowbits.c:384
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:89
SIZE_OF_PACKET
#define SIZE_OF_PACKET
Definition: decode.h:625
app-layer-parser.h
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:322
GenericVar_::idx
uint32_t idx
Definition: util-var.h:51
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:282
FBAnalyze::unset_sids
uint32_t * unset_sids
Definition: detect-flowbits.c:394
DetectFlowbitFree
void DetectFlowbitFree(DetectEngineCtx *, void *)
Definition: detect-flowbits.c:368
SigMatchSignatures
void SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1688
DetectFlowbitsRegister
void DetectFlowbitsRegister(void)
Definition: detect-flowbits.c:62
Signature_::flags
uint32_t flags
Definition: detect.h:528
FBAnalyze::set_sids
uint32_t * set_sids
Definition: detect-flowbits.c:382
DetectEngineCtx_::max_fb_id
uint32_t max_fb_id
Definition: detect.h:831
MemBufferPrintToFPAsString
#define MemBufferPrintToFPAsString(mem_buffer, fp)
Write a buffer to the file pointer as a printable char string.
Definition: util-buffer.h:93
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, const char *str, int start_offset, int options, int *ovector, int ovector_size)
Definition: detect-parse.c:2406
Packet_
Definition: decode.h:412
OutputJSONMemBufferWrapper_
Definition: output-json.h:66
DetectFlowbitsData_::idx
uint32_t idx
Definition: detect-flowbits.h:37
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:596
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1178
FBAnalyze::toggle_sids
uint32_t * toggle_sids
Definition: detect-flowbits.c:398
SignatureInitData_::smlists
struct SigMatch_ ** smlists
Definition: detect.h:521
SC_WARN_FLOWBIT
@ SC_WARN_FLOWBIT
Definition: util-error.h:339
FBAnalyze::isset_sids_idx
uint32_t isset_sids_idx
Definition: detect-flowbits.c:387
MemBuffer_
Definition: util-buffer.h:27
detect-flowbits.h
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:235
FlowBitToggle
void FlowBitToggle(Flow *f, uint32_t idx)
Definition: flow-bit.c:94
Flow_::flowvar
GenericVar * flowvar
Definition: flow.h:486
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:1878
SigMatch_::type
uint8_t type
Definition: detect.h:320
FBAnalyze::unset_sids_idx
uint32_t unset_sids_idx
Definition: detect-flowbits.c:395
FBAnalyze::toggle_sids_size
uint32_t toggle_sids_size
Definition: detect-flowbits.c:400
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
SIG_FLAG_INIT_STATE_MATCH
#define SIG_FLAG_INIT_STATE_MATCH
Definition: detect.h:262
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:314
Packet_::flow
struct Flow_ * flow
Definition: decode.h:449
DETECT_FLOWBITS_CMD_NOALERT
#define DETECT_FLOWBITS_CMD_NOALERT
Definition: detect-flowbits.h:33
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
Definition: detect-engine.c:2797
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
VAR_TYPE_FLOW_BIT
@ VAR_TYPE_FLOW_BIT
Definition: util-var.h:35
FBAnalyze::state_cnts
uint16_t state_cnts[DETECT_FLOWBITS_CMD_MAX]
Definition: detect-flowbits.c:380
suricata-common.h
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
Definition: detect-engine.c:3005
GenericVar_
Definition: util-var.h:48
MemBufferFree
void MemBufferFree(MemBuffer *buffer)
Definition: util-buffer.c:82
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:73
DetectParseRegex_
Definition: detect-parse.h:42
util-spm.h
MemBufferWriteString
#define MemBufferWriteString(dst,...)
Write a string buffer to the Membuffer dst.
Definition: util-buffer.h:162
VarNameStoreSetupAdd
uint32_t VarNameStoreSetupAdd(const char *name, const enum VarTypes type)
add to staging or return existing id if already in there
Definition: util-var-name.c:323
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
FBAnalyze::set_sids_idx
uint32_t set_sids_idx
Definition: detect-flowbits.c:383
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:772
SIG_FLAG_NOALERT
#define SIG_FLAG_NOALERT
Definition: detect.h:216
DETECT_FLOWBITS
@ DETECT_FLOWBITS
Definition: detect-engine-register.h:87
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
FlowBitIsset
int FlowBitIsset(Flow *f, uint32_t idx)
Definition: flow-bit.c:104
str
#define str(s)
Definition: suricata-common.h:273
FBAnalyze::isset_sids_size
uint32_t isset_sids_size
Definition: detect-flowbits.c:388
ConfigGetLogDirectory
const char * ConfigGetLogDirectory()
Definition: util-conf.c:35
SCLogWarning
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:244
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DetectFlowbitsData_::or_list
uint32_t * or_list
Definition: detect-flowbits.h:40
Signature_::id
uint32_t id
Definition: detect.h:560
DETECT_FLOWBITS_CMD_UNSET
#define DETECT_FLOWBITS_CMD_UNSET
Definition: detect-flowbits.h:30
detect-parse.h
util-buffer.h
Signature_
Signature container.
Definition: detect.h:527
SigMatch_
a single match condition for a signature
Definition: detect.h:319
FBAnalyze::isnotset_sids_size
uint32_t isnotset_sids_size
Definition: detect-flowbits.c:392
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2048
OutputJSONMemBufferCallback
int OutputJSONMemBufferCallback(const char *str, size_t size, void *data)
Definition: output-json.c:936
DetectFlowbitMatch
int DetectFlowbitMatch(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect-flowbits.c:189
SC_ERR_MEM_ALLOC
@ SC_ERR_MEM_ALLOC
Definition: util-error.h:31
DetectEngineCtx_::sig_array
Signature ** sig_array
Definition: detect.h:781
Address_::family
char family
Definition: decode.h:115
Packet_::dst
Address dst
Definition: decode.h:417
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:767
flow.h
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
DetectEngineCtx_::sig_array_len
uint32_t sig_array_len
Definition: detect.h:783
FBAnalyze
Definition: detect-flowbits.c:378
SIGMATCH_IPONLY_COMPAT
#define SIGMATCH_IPONLY_COMPAT
Definition: detect.h:1381
SCMutex
#define SCMutex
Definition: threads-debug.h:114
SigMatchAppendSMToList
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:349
FLOW_DESTROY
#define FLOW_DESTROY(f)
Definition: flow-util.h:130
Packet_::src
Address src
Definition: decode.h:416
MemBufferCreateNew
MemBuffer * MemBufferCreateNew(uint32_t size)
Definition: util-buffer.c:32
FlowBitIsnotset
int FlowBitIsnotset(Flow *f, uint32_t idx)
Definition: flow-bit.c:116
DETECT_FLOWBITS_CMD_SET
#define DETECT_FLOWBITS_CMD_SET
Definition: detect-flowbits.h:28
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1202
SignatureInitData_::smlists_array_size
uint32_t smlists_array_size
Definition: detect.h:519