suricata
detect-flowbits.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2017 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 pcre *parse_regex;
50 static pcre_extra *parse_regex_study;
51 
53  const Signature *, const SigMatchCtx *);
54 static int DetectFlowbitSetup (DetectEngineCtx *, Signature *, const char *);
55 void DetectFlowbitFree (void *);
56 void FlowBitsRegisterTests(void);
57 
59 {
60  sigmatch_table[DETECT_FLOWBITS].name = "flowbits";
61  sigmatch_table[DETECT_FLOWBITS].desc = "operate on flow flag";
62  sigmatch_table[DETECT_FLOWBITS].url = DOC_URL DOC_VERSION "/rules/flow-keywords.html#flowbits";
64  sigmatch_table[DETECT_FLOWBITS].Setup = DetectFlowbitSetup;
67  /* this is compatible to ip-only signatures */
69 
70  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study);
71 }
72 
73 
74 static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd)
75 {
76  if (p->flow == NULL)
77  return 0;
78 
79  FlowBitToggle(p->flow,fd->idx);
80 
81  return 1;
82 }
83 
84 static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd)
85 {
86  if (p->flow == NULL)
87  return 0;
88 
89  FlowBitUnset(p->flow,fd->idx);
90 
91  return 1;
92 }
93 
94 static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd)
95 {
96  if (p->flow == NULL)
97  return 0;
98 
99  FlowBitSet(p->flow,fd->idx);
100 
101  return 1;
102 }
103 
104 static int DetectFlowbitMatchIsset (Packet *p, const DetectFlowbitsData *fd)
105 {
106  if (p->flow == NULL)
107  return 0;
108 
109  return FlowBitIsset(p->flow,fd->idx);
110 }
111 
112 static int DetectFlowbitMatchIsnotset (Packet *p, const DetectFlowbitsData *fd)
113 {
114  if (p->flow == NULL)
115  return 0;
116 
117  return FlowBitIsnotset(p->flow,fd->idx);
118 }
119 
120 /*
121  * returns 0: no match
122  * 1: match
123  * -1: error
124  */
125 
127  const Signature *s, const SigMatchCtx *ctx)
128 {
129  const DetectFlowbitsData *fd = (const DetectFlowbitsData *)ctx;
130  if (fd == NULL)
131  return 0;
132 
133  switch (fd->cmd) {
135  return DetectFlowbitMatchIsset(p,fd);
137  return DetectFlowbitMatchIsnotset(p,fd);
139  return DetectFlowbitMatchSet(p,fd);
141  return DetectFlowbitMatchUnset(p,fd);
143  return DetectFlowbitMatchToggle(p,fd);
144  default:
145  SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", fd->cmd);
146  return 0;
147  }
148 
149  return 0;
150 }
151 
152 static int DetectFlowbitParse(const char *str, char *cmd, int cmd_len, char *name,
153  int name_len)
154 {
155  const int max_substrings = 30;
156  int count, rc;
157  int ov[max_substrings];
158 
159  count = pcre_exec(parse_regex, parse_regex_study, str, strlen(str), 0, 0,
160  ov, max_substrings);
161  if (count != 2 && count != 3) {
163  "\"%s\" is not a valid setting for flowbits.", str);
164  return 0;
165  }
166 
167  rc = pcre_copy_substring((char *)str, ov, max_substrings, 1, cmd, cmd_len);
168  if (rc < 0) {
169  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
170  return 0;
171  }
172 
173  if (count == 3) {
174  rc = pcre_copy_substring((char *)str, ov, max_substrings, 2, name,
175  name_len);
176  if (rc < 0) {
177  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
178  return 0;
179  }
180 
181  /* Trim trailing whitespace. */
182  while (strlen(name) > 0 && isblank(name[strlen(name) - 1])) {
183  name[strlen(name) - 1] = '\0';
184  }
185 
186  /* Validate name, spaces are not allowed. */
187  for (size_t i = 0; i < strlen(name); i++) {
188  if (isblank(name[i])) {
190  "spaces not allowed in flowbit names");
191  return 0;
192  }
193  }
194  }
195 
196  return 1;
197 }
198 
199 int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
200 {
201  DetectFlowbitsData *cd = NULL;
202  SigMatch *sm = NULL;
203  uint8_t fb_cmd = 0;
204  char fb_cmd_str[16] = "", fb_name[256] = "";
205 
206  if (!DetectFlowbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), fb_name,
207  sizeof(fb_name))) {
208  return -1;
209  }
210 
211  if (strcmp(fb_cmd_str,"noalert") == 0) {
213  } else if (strcmp(fb_cmd_str,"isset") == 0) {
214  fb_cmd = DETECT_FLOWBITS_CMD_ISSET;
215  } else if (strcmp(fb_cmd_str,"isnotset") == 0) {
217  } else if (strcmp(fb_cmd_str,"set") == 0) {
218  fb_cmd = DETECT_FLOWBITS_CMD_SET;
219  } else if (strcmp(fb_cmd_str,"unset") == 0) {
220  fb_cmd = DETECT_FLOWBITS_CMD_UNSET;
221  } else if (strcmp(fb_cmd_str,"toggle") == 0) {
223  } else {
224  SCLogError(SC_ERR_UNKNOWN_VALUE, "ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str);
225  goto error;
226  }
227 
228  switch (fb_cmd) {
230  if (strlen(fb_name) != 0)
231  goto error;
232  s->flags |= SIG_FLAG_NOALERT;
233  return 0;
239  default:
240  if (strlen(fb_name) == 0)
241  goto error;
242  break;
243  }
244 
245  cd = SCMalloc(sizeof(DetectFlowbitsData));
246  if (unlikely(cd == NULL))
247  goto error;
248 
250  de_ctx->max_fb_id = MAX(cd->idx, de_ctx->max_fb_id);
251  cd->cmd = fb_cmd;
252 
253  SCLogDebug("idx %" PRIu32 ", cmd %s, name %s",
254  cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)");
255 
256  /* Okay so far so good, lets get this into a SigMatch
257  * and put it in the Signature. */
258  sm = SigMatchAlloc();
259  if (sm == NULL)
260  goto error;
261 
262  sm->type = DETECT_FLOWBITS;
263  sm->ctx = (SigMatchCtx *)cd;
264 
265  switch (fb_cmd) {
266  /* case DETECT_FLOWBITS_CMD_NOALERT can't happen here */
267 
270  /* checks, so packet list */
272  break;
273 
277  /* modifiers, only run when entire sig has matched */
279  break;
280 
281  // suppress coverity warning as scan-build-7 warns w/o this.
282  // coverity[deadcode : FALSE]
283  default:
284  goto error;
285  }
286 
287  return 0;
288 
289 error:
290  if (cd != NULL)
291  SCFree(cd);
292  if (sm != NULL)
293  SCFree(sm);
294  return -1;
295 }
296 
297 void DetectFlowbitFree (void *ptr)
298 {
300 
301  if (fd == NULL)
302  return;
303 
304  SCFree(fd);
305 }
306 
307 struct FBAnalyze {
310 
311  uint32_t *set_sids;
312  uint32_t set_sids_idx;
313  uint32_t set_sids_size;
314 
315  uint32_t *isset_sids;
316  uint32_t isset_sids_idx;
317  uint32_t isset_sids_size;
318 
319  uint32_t *isnotset_sids;
322 
323  uint32_t *unset_sids;
324  uint32_t unset_sids_idx;
325  uint32_t unset_sids_size;
326 
327  uint32_t *toggle_sids;
328  uint32_t toggle_sids_idx;
330 };
331 #ifdef PROFILING
332 static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
333  struct FBAnalyze *array, uint32_t elements);
334 #endif
335 
337 {
338  const uint32_t max_fb_id = de_ctx->max_fb_id;
339  if (max_fb_id == 0)
340  return;
341 
342 #define MAX_SIDS 8
343  uint32_t array_size = max_fb_id + 1;
344  struct FBAnalyze array[array_size];
345  memset(&array, 0, array_size * sizeof(struct FBAnalyze));
346 
347  SCLogDebug("fb analyzer array size: %"PRIu64,
348  (uint64_t)(array_size * sizeof(struct FBAnalyze)));
349 
350  /* fill flowbit array, updating counters per sig */
351  for (uint32_t i = 0; i < de_ctx->sig_array_len; i++) {
352  const Signature *s = de_ctx->sig_array[i];
353  bool has_state = false;
354 
355  /* see if the signature uses stateful matching */
356  for (uint32_t x = DETECT_SM_LIST_DYNAMIC_START; x < s->init_data->smlists_array_size; x++) {
357  if (s->init_data->smlists[x] == NULL)
358  continue;
359  has_state = true;
360  break;
361  }
362 
363  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
364  switch (sm->type) {
365  case DETECT_FLOWBITS:
366  {
367  /* figure out the flowbit action */
368  const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
369  array[fb->idx].cnts[fb->cmd]++;
370  if (has_state)
371  array[fb->idx].state_cnts[fb->cmd]++;
372  if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
373  if (array[fb->idx].isset_sids_idx >= array[fb->idx].isset_sids_size) {
374  uint32_t old_size = array[fb->idx].isset_sids_size;
375  uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
376 
377  void *ptr = SCRealloc(array[fb->idx].isset_sids, new_size * sizeof(uint32_t));
378  if (ptr == NULL)
379  goto end;
380  array[fb->idx].isset_sids_size = new_size;
381  array[fb->idx].isset_sids = ptr;
382  }
383 
384  array[fb->idx].isset_sids[array[fb->idx].isset_sids_idx] = s->num;
385  array[fb->idx].isset_sids_idx++;
386  } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET){
387  if (array[fb->idx].isnotset_sids_idx >= array[fb->idx].isnotset_sids_size) {
388  uint32_t old_size = array[fb->idx].isnotset_sids_size;
389  uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
390 
391  void *ptr = SCRealloc(array[fb->idx].isnotset_sids, new_size * sizeof(uint32_t));
392  if (ptr == NULL)
393  goto end;
394  array[fb->idx].isnotset_sids_size = new_size;
395  array[fb->idx].isnotset_sids = ptr;
396  }
397 
398  array[fb->idx].isnotset_sids[array[fb->idx].isnotset_sids_idx] = s->num;
399  array[fb->idx].isnotset_sids_idx++;
400  }
401  }
402  }
403  }
404  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_POSTMATCH] ; sm != NULL; sm = sm->next) {
405  switch (sm->type) {
406  case DETECT_FLOWBITS:
407  {
408  /* figure out what flowbit action */
409  const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
410  array[fb->idx].cnts[fb->cmd]++;
411  if (has_state)
412  array[fb->idx].state_cnts[fb->cmd]++;
413  if (fb->cmd == DETECT_FLOWBITS_CMD_SET) {
414  if (array[fb->idx].set_sids_idx >= array[fb->idx].set_sids_size) {
415  uint32_t old_size = array[fb->idx].set_sids_size;
416  uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
417 
418  void *ptr = SCRealloc(array[fb->idx].set_sids, new_size * sizeof(uint32_t));
419  if (ptr == NULL)
420  goto end;
421  array[fb->idx].set_sids_size = new_size;
422  array[fb->idx].set_sids = ptr;
423  }
424 
425  array[fb->idx].set_sids[array[fb->idx].set_sids_idx] = s->num;
426  array[fb->idx].set_sids_idx++;
427  }
428  else if (fb->cmd == DETECT_FLOWBITS_CMD_UNSET) {
429  if (array[fb->idx].unset_sids_idx >= array[fb->idx].unset_sids_size) {
430  uint32_t old_size = array[fb->idx].unset_sids_size;
431  uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
432 
433  void *ptr = SCRealloc(array[fb->idx].unset_sids, new_size * sizeof(uint32_t));
434  if (ptr == NULL)
435  goto end;
436  array[fb->idx].unset_sids_size = new_size;
437  array[fb->idx].unset_sids = ptr;
438  }
439 
440  array[fb->idx].unset_sids[array[fb->idx].unset_sids_idx] = s->num;
441  array[fb->idx].unset_sids_idx++;
442  }
443  else if (fb->cmd == DETECT_FLOWBITS_CMD_TOGGLE) {
444  if (array[fb->idx].toggle_sids_idx >= array[fb->idx].toggle_sids_size) {
445  uint32_t old_size = array[fb->idx].toggle_sids_size;
446  uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
447 
448  void *ptr = SCRealloc(array[fb->idx].toggle_sids, new_size * sizeof(uint32_t));
449  if (ptr == NULL)
450  goto end;
451  array[fb->idx].toggle_sids_size = new_size;
452  array[fb->idx].toggle_sids = ptr;
453  }
454 
455  array[fb->idx].toggle_sids[array[fb->idx].toggle_sids_idx] = s->num;
456  array[fb->idx].toggle_sids_idx++;
457  }
458  }
459  }
460  }
461  }
462 
463  /* walk array to see if all bits make sense */
464  for (uint32_t i = 0; i < array_size; i++) {
465  char *varname = VarNameStoreSetupLookup(i, VAR_TYPE_FLOW_BIT);
466  if (varname == NULL)
467  continue;
468 
469  bool to_state = false;
470 
471  if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] &&
472  array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE] == 0 &&
473  array[i].cnts[DETECT_FLOWBITS_CMD_SET] == 0) {
474 
475  const Signature *s = de_ctx->sig_array[array[i].isset_sids[0]];
476  SCLogWarning(SC_WARN_FLOWBIT, "flowbit '%s' is checked but not "
477  "set. Checked in %u and %u other sigs",
478  varname, s->id, array[i].isset_sids_idx - 1);
479  }
480  if (array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] &&
481  array[i].state_cnts[DETECT_FLOWBITS_CMD_SET] == 0)
482  {
483  SCLogDebug("flowbit %s/%u: isset in state, set not in state", varname, i);
484  }
485 
486  /* if signature depends on 'stateful' flowbits, then turn the
487  * sig into a stateful sig itself */
488  if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] > 0 &&
489  array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] == 0 &&
491  {
492  SCLogDebug("flowbit %s/%u: isset not in state, set in state", varname, i);
493  to_state = true;
494  }
495 
496  SCLogDebug("ALL flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
497  array[i].cnts[DETECT_FLOWBITS_CMD_SET], array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE],
499  array[i].cnts[DETECT_FLOWBITS_CMD_ISSET]);
500  SCLogDebug("STATE flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
501  array[i].state_cnts[DETECT_FLOWBITS_CMD_SET], array[i].state_cnts[DETECT_FLOWBITS_CMD_TOGGLE],
502  array[i].state_cnts[DETECT_FLOWBITS_CMD_UNSET], array[i].state_cnts[DETECT_FLOWBITS_CMD_ISNOTSET],
503  array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET]);
504  for (uint32_t x = 0; x < array[i].set_sids_idx; x++) {
505  SCLogDebug("SET flowbit %s/%u: SID %u", varname, i,
506  de_ctx->sig_array[array[i].set_sids[x]]->id);
507  }
508  for (uint32_t x = 0; x < array[i].isset_sids_idx; x++) {
509  Signature *s = de_ctx->sig_array[array[i].isset_sids[x]];
510  SCLogDebug("GET flowbit %s/%u: SID %u", varname, i, s->id);
511 
512  if (to_state) {
514  SCLogDebug("made SID %u stateful because it depends on "
515  "stateful rules that set flowbit %s", s->id, varname);
516  }
517  }
518  SCFree(varname);
519  }
520 #ifdef PROFILING
521  DetectFlowbitsAnalyzeDump(de_ctx, array, array_size);
522 #endif
523 
524 end:
525  for (uint32_t i = 0; i < array_size; i++) {
526  SCFree(array[i].set_sids);
527  SCFree(array[i].unset_sids);
528  SCFree(array[i].isset_sids);
529  SCFree(array[i].isnotset_sids);
530  SCFree(array[i].toggle_sids);
531  }
532 }
533 
534 #ifdef PROFILING
535 #include "output-json.h"
536 #include "util-buffer.h"
538 static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
539  struct FBAnalyze *array, uint32_t elements)
540 {
541  json_t *js = json_object();
542  if (js == NULL)
543  return;
544 
545  json_t *js_array = json_array();
546  uint32_t x;
547  for (x = 0; x < elements; x++)
548  {
549  char *varname = VarNameStoreSetupLookup(x, VAR_TYPE_FLOW_BIT);
550  if (varname == NULL)
551  continue;
552 
553  const struct FBAnalyze *e = &array[x];
554 
555  json_t *js_fb = json_object();
556  if (unlikely(js_fb != NULL)) {
557  json_object_set_new(js_fb, "name", json_string(varname));
558  json_object_set_new(js_fb, "internal_id", json_integer(x));
559  json_object_set_new(js_fb, "set_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_SET]));
560  json_object_set_new(js_fb, "unset_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_UNSET]));
561  json_object_set_new(js_fb, "toggle_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_TOGGLE]));
562  json_object_set_new(js_fb, "isset_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_ISSET]));
563  json_object_set_new(js_fb, "isnotset_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_ISNOTSET]));
564 
565  // sets
566  if (e->cnts[DETECT_FLOWBITS_CMD_SET]) {
567  json_t *js_set_array = json_array();
568  if (js_set_array) {
569  for(uint32_t i = 0; i < e->set_sids_idx; i++) {
570  const Signature *s = de_ctx->sig_array[e->set_sids[i]];
571  json_array_append_new(js_set_array, json_integer(s->id));
572  }
573  json_object_set_new(js_fb, "sets", js_set_array);
574  }
575  }
576  // gets
578  json_t *js_isset_array = json_array();
579  if (js_isset_array) {
580  for(uint32_t i = 0; i < e->isset_sids_idx; i++) {
581  const Signature *s = de_ctx->sig_array[e->isset_sids[i]];
582  json_array_append_new(js_isset_array, json_integer(s->id));
583  }
584  json_object_set_new(js_fb, "isset", js_isset_array);
585  }
586  }
587  // isnotset
589  json_t *js_isnotset_array = json_array();
590  if (js_isnotset_array) {
591  for(uint32_t i = 0; i < e->isnotset_sids_idx; i++) {
592  const Signature *s = de_ctx->sig_array[e->isnotset_sids[i]];
593  json_array_append_new(js_isnotset_array, json_integer(s->id));
594  }
595  json_object_set_new(js_fb, "isnotset", js_isnotset_array);
596  }
597  }
598  // unset
600  json_t *js_unset_array = json_array();
601  if (js_unset_array) {
602  for(uint32_t i = 0; i < e->unset_sids_idx; i++) {
603  const Signature *s = de_ctx->sig_array[e->unset_sids[i]];
604  json_array_append_new(js_unset_array, json_integer(s->id));
605  }
606  json_object_set_new(js_fb, "unset", js_unset_array);
607  }
608  }
609  // toggle
611  json_t *js_toggle_array = json_array();
612  if (js_toggle_array) {
613  for(uint32_t i = 0; i < e->toggle_sids_idx; i++) {
614  const Signature *s = de_ctx->sig_array[e->toggle_sids[i]];
615  json_array_append_new(js_toggle_array, json_integer(s->id));
616  }
617  json_object_set_new(js_fb, "toggle", js_toggle_array);
618  }
619  }
620 
621  json_array_append_new(js_array, js_fb);
622  }
623  SCFree(varname);
624  }
625 
626  json_object_set_new(js, "flowbits", js_array);
627 
628  const char *filename = "flowbits.json";
629  const char *log_dir = ConfigGetLogDirectory();
630  char log_path[PATH_MAX] = "";
631  snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, filename);
632 
633  MemBuffer *mbuf = NULL;
634  mbuf = MemBufferCreateNew(4096);
635  BUG_ON(mbuf == NULL);
636 
637  OutputJSONMemBufferWrapper wrapper = {
638  .buffer = &mbuf,
639  .expand_by = 4096,
640  };
641 
642  int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper,
643  JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
645  if (r != 0) {
646  SCLogWarning(SC_ERR_SOCKET, "unable to serialize JSON object");
647  } else {
648  MemBufferWriteString(mbuf, "\n");
650  FILE *fp = fopen(log_path, "w");
651  if (fp != NULL) {
652  MemBufferPrintToFPAsString(mbuf, fp);
653  fclose(fp);
654  }
656  }
657 
658  MemBufferFree(mbuf);
659  json_object_clear(js);
660  json_decref(js);
661 }
662 #endif /* PROFILING */
663 
664 #ifdef UNITTESTS
665 
666 static int FlowBitsTestParse01(void)
667 {
668  char command[16] = "", name[16] = "";
669 
670  /* Single argument version. */
671  FAIL_IF(!DetectFlowbitParse("noalert", command, sizeof(command), name,
672  sizeof(name)));
673  FAIL_IF(strcmp(command, "noalert") != 0);
674 
675  /* No leading or trailing spaces. */
676  FAIL_IF(!DetectFlowbitParse("set,flowbit", command, sizeof(command), name,
677  sizeof(name)));
678  FAIL_IF(strcmp(command, "set") != 0);
679  FAIL_IF(strcmp(name, "flowbit") != 0);
680 
681  /* Leading space. */
682  FAIL_IF(!DetectFlowbitParse("set, flowbit", command, sizeof(command), name,
683  sizeof(name)));
684  FAIL_IF(strcmp(command, "set") != 0);
685  FAIL_IF(strcmp(name, "flowbit") != 0);
686 
687  /* Trailing space. */
688  FAIL_IF(!DetectFlowbitParse("set,flowbit ", command, sizeof(command), name,
689  sizeof(name)));
690  FAIL_IF(strcmp(command, "set") != 0);
691  FAIL_IF(strcmp(name, "flowbit") != 0);
692 
693  /* Leading and trailing space. */
694  FAIL_IF(!DetectFlowbitParse("set, flowbit ", command, sizeof(command), name,
695  sizeof(name)));
696  FAIL_IF(strcmp(command, "set") != 0);
697  FAIL_IF(strcmp(name, "flowbit") != 0);
698 
699  /* Spaces are not allowed in the name. */
700  FAIL_IF(DetectFlowbitParse("set,namewith space", command, sizeof(command),
701  name, sizeof(name)));
702 
703  PASS;
704 }
705 
706 /**
707  * \test FlowBitsTestSig01 is a test for a valid noalert flowbits option
708  *
709  * \retval 1 on succces
710  * \retval 0 on failure
711  */
712 
713 static int FlowBitsTestSig01(void)
714 {
715  Signature *s = NULL;
716  DetectEngineCtx *de_ctx = NULL;
717 
718  de_ctx = DetectEngineCtxInit();
719  FAIL_IF_NULL(de_ctx);
720 
721  de_ctx->flags |= DE_QUIET;
722 
723  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)");
724  FAIL_IF_NOT_NULL(s);
725 
726  SigGroupBuild(de_ctx);
727  DetectEngineCtxFree(de_ctx);
728  PASS;
729 }
730 
731 /**
732  * \test FlowBitsTestSig02 is a test for a valid isset,set,isnotset,unset,toggle flowbits options
733  *
734  * \retval 1 on succces
735  * \retval 0 on failure
736  */
737 
738 static int FlowBitsTestSig02(void)
739 {
740  Signature *s = NULL;
741  ThreadVars th_v;
742  DetectEngineCtx *de_ctx = NULL;
743 
744  memset(&th_v, 0, sizeof(th_v));
745 
746  de_ctx = DetectEngineCtxInit();
747  FAIL_IF_NULL(de_ctx);
748 
749  de_ctx->flags |= DE_QUIET;
750 
751  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;)");
752  FAIL_IF_NOT_NULL(s);
753 
754  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;)");
755  FAIL_IF_NOT_NULL(s);
756 
757  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;)");
758  FAIL_IF_NOT_NULL(s);
759 
760  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;)");
761  FAIL_IF_NOT_NULL(s);
762 
763  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;)");
764  FAIL_IF_NOT_NULL(s);
765 
766  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;)");
767  FAIL_IF_NOT_NULL(s);
768 
769  SigGroupBuild(de_ctx);
770  DetectEngineCtxFree(de_ctx);
771 
772  PASS;
773 }
774 
775 /**
776  * \test FlowBitsTestSig03 is a test for a invalid flowbits option
777  *
778  * \retval 1 on succces
779  * \retval 0 on failure
780  */
781 
782 static int FlowBitsTestSig03(void)
783 {
784  Signature *s = NULL;
785  DetectEngineCtx *de_ctx = NULL;
786 
787  de_ctx = DetectEngineCtxInit();
788  FAIL_IF_NULL(de_ctx);
789 
790  de_ctx->flags |= DE_QUIET;
791 
792  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)");
793  FAIL_IF_NOT_NULL(s);
794 
795  SigGroupBuild(de_ctx);
796  DetectEngineCtxFree(de_ctx);
797  PASS;
798 }
799 
800 /**
801  * \test FlowBitsTestSig04 is a test check idx value
802  *
803  * \retval 1 on succces
804  * \retval 0 on failure
805  */
806 
807 static int FlowBitsTestSig04(void)
808 {
809  Signature *s = NULL;
810  DetectEngineCtx *de_ctx = NULL;
811  int idx = 0;
812 
813  de_ctx = DetectEngineCtxInit();
814  FAIL_IF_NULL(de_ctx);
815 
816  de_ctx->flags |= DE_QUIET;
817 
818  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)");
819  FAIL_IF_NULL(s);
820 
822  FAIL_IF(idx != 1);
823 
824  SigGroupBuild(de_ctx);
825  DetectEngineCtxFree(de_ctx);
826  PASS;
827 }
828 
829 /**
830  * \test FlowBitsTestSig05 is a test check noalert flag
831  *
832  * \retval 1 on succces
833  * \retval 0 on failure
834  */
835 
836 static int FlowBitsTestSig05(void)
837 {
838  Signature *s = NULL;
839  DetectEngineCtx *de_ctx = NULL;
840 
841  de_ctx = DetectEngineCtxInit();
842  FAIL_IF_NULL(de_ctx);
843 
844  de_ctx->flags |= DE_QUIET;
845 
846  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)");
847  FAIL_IF_NULL(s);
849 
850  SigGroupBuild(de_ctx);
851  DetectEngineCtxFree(de_ctx);
852  PASS;
853 }
854 
855 /**
856  * \test FlowBitsTestSig06 is a test set flowbits option
857  *
858  * \retval 1 on succces
859  * \retval 0 on failure
860  */
861 
862 static int FlowBitsTestSig06(void)
863 {
864  uint8_t *buf = (uint8_t *)
865  "GET /one/ HTTP/1.1\r\n"
866  "Host: one.example.org\r\n"
867  "\r\n";
868  uint16_t buflen = strlen((char *)buf);
870  FAIL_IF_NULL(p);
871  Signature *s = NULL;
872  ThreadVars th_v;
873  DetectEngineThreadCtx *det_ctx = NULL;
874  DetectEngineCtx *de_ctx = NULL;
875  Flow f;
876  GenericVar flowvar, *gv = NULL;
877  int result = 0;
878  uint32_t idx = 0;
879 
880  memset(p, 0, SIZE_OF_PACKET);
881  memset(&th_v, 0, sizeof(th_v));
882  memset(&f, 0, sizeof(Flow));
883  memset(&flowvar, 0, sizeof(GenericVar));
884 
885  FLOW_INITIALIZE(&f);
886  p->flow = &f;
887  p->flow->flowvar = &flowvar;
888 
889  p->src.family = AF_INET;
890  p->dst.family = AF_INET;
891  p->payload = buf;
892  p->payload_len = buflen;
893  p->proto = IPPROTO_TCP;
894  p->flags |= PKT_HAS_FLOW;
896 
897  de_ctx = DetectEngineCtxInit();
898  FAIL_IF_NULL(de_ctx);
899 
900  de_ctx->flags |= DE_QUIET;
901 
902  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)");
903  FAIL_IF_NULL(s);
904 
905  idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
906  SigGroupBuild(de_ctx);
907  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
908 
909  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
910 
911  gv = p->flow->flowvar;
912  FAIL_IF_NULL(gv);
913  for ( ; gv != NULL; gv = gv->next) {
914  if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
915  result = 1;
916  }
917  }
918  FAIL_IF_NOT(result);
919 
920  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
921  DetectEngineCtxFree(de_ctx);
922 
923  FLOW_DESTROY(&f);
924 
925  SCFree(p);
926  PASS;
927 }
928 
929 /**
930  * \test FlowBitsTestSig07 is a test unset flowbits option
931  *
932  * \retval 1 on succces
933  * \retval 0 on failure
934  */
935 
936 static int FlowBitsTestSig07(void)
937 {
938  uint8_t *buf = (uint8_t *)
939  "GET /one/ HTTP/1.1\r\n"
940  "Host: one.example.org\r\n"
941  "\r\n";
942  uint16_t buflen = strlen((char *)buf);
944  FAIL_IF_NULL(p);
945  Signature *s = NULL;
946  ThreadVars th_v;
947  DetectEngineThreadCtx *det_ctx = NULL;
948  DetectEngineCtx *de_ctx = NULL;
949  Flow f;
950  GenericVar flowvar, *gv = NULL;
951  int result = 0;
952  uint32_t idx = 0;
953 
954  memset(p, 0, SIZE_OF_PACKET);
955  memset(&th_v, 0, sizeof(th_v));
956  memset(&f, 0, sizeof(Flow));
957  memset(&flowvar, 0, sizeof(GenericVar));
958 
959  FLOW_INITIALIZE(&f);
960  p->flow = &f;
961  p->flow->flowvar = &flowvar;
962 
963  p->src.family = AF_INET;
964  p->dst.family = AF_INET;
965  p->payload = buf;
966  p->payload_len = buflen;
967  p->proto = IPPROTO_TCP;
968 
969  de_ctx = DetectEngineCtxInit();
970  FAIL_IF_NULL(de_ctx);
971 
972  de_ctx->flags |= DE_QUIET;
973 
974  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)");
975  FAIL_IF_NULL(s);
976 
977  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)");
978  FAIL_IF_NULL(s);
979 
980  idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
981  SigGroupBuild(de_ctx);
982  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
983 
984  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
985 
986  gv = p->flow->flowvar;
987  FAIL_IF_NULL(gv);
988 
989  for ( ; gv != NULL; gv = gv->next) {
990  if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
991  result = 1;
992  }
993  }
994  FAIL_IF(result);
995 
996  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
997  DetectEngineCtxFree(de_ctx);
998 
999  FLOW_DESTROY(&f);
1000 
1001  SCFree(p);
1002  PASS;
1003 }
1004 
1005 /**
1006  * \test FlowBitsTestSig08 is a test toogle flowbits option
1007  *
1008  * \retval 1 on succces
1009  * \retval 0 on failure
1010  */
1011 
1012 static int FlowBitsTestSig08(void)
1013 {
1014  uint8_t *buf = (uint8_t *)
1015  "GET /one/ HTTP/1.1\r\n"
1016  "Host: one.example.org\r\n"
1017  "\r\n";
1018  uint16_t buflen = strlen((char *)buf);
1020  if (unlikely(p == NULL))
1021  return 0;
1022  Signature *s = NULL;
1023  ThreadVars th_v;
1024  DetectEngineThreadCtx *det_ctx = NULL;
1025  DetectEngineCtx *de_ctx = NULL;
1026  Flow f;
1027  GenericVar flowvar, *gv = NULL;
1028  int result = 0;
1029  uint32_t idx = 0;
1030 
1031  memset(p, 0, SIZE_OF_PACKET);
1032  memset(&th_v, 0, sizeof(th_v));
1033  memset(&f, 0, sizeof(Flow));
1034  memset(&flowvar, 0, sizeof(GenericVar));
1035 
1036  FLOW_INITIALIZE(&f);
1037  p->flow = &f;
1038  p->flow->flowvar = &flowvar;
1039 
1040  p->src.family = AF_INET;
1041  p->dst.family = AF_INET;
1042  p->payload = buf;
1043  p->payload_len = buflen;
1044  p->proto = IPPROTO_TCP;
1045 
1046  de_ctx = DetectEngineCtxInit();
1047  FAIL_IF_NULL(de_ctx);
1048 
1049  de_ctx->flags |= DE_QUIET;
1050 
1051  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)");
1052  FAIL_IF_NULL(s);
1053 
1054  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:toggle,myflow2; sid:11;)");
1055  FAIL_IF_NULL(s);
1056 
1057  idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
1058  SigGroupBuild(de_ctx);
1059  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1060 
1061  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1062 
1063  gv = p->flow->flowvar;
1064  FAIL_IF_NULL(gv);
1065 
1066  for ( ; gv != NULL; gv = gv->next) {
1067  if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1068  result = 1;
1069  }
1070  }
1071  FAIL_IF(result);
1072 
1073  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1074  DetectEngineCtxFree(de_ctx);
1075 
1076  FLOW_DESTROY(&f);
1077 
1078  SCFree(p);
1079  PASS;
1080 }
1081 #endif /* UNITTESTS */
1082 
1083 /**
1084  * \brief this function registers unit tests for FlowBits
1085  */
1087 {
1088 #ifdef UNITTESTS
1089  UtRegisterTest("FlowBitsTestParse01", FlowBitsTestParse01);
1090  UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01);
1091  UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02);
1092  UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03);
1093  UtRegisterTest("FlowBitsTestSig04", FlowBitsTestSig04);
1094  UtRegisterTest("FlowBitsTestSig05", FlowBitsTestSig05);
1095  UtRegisterTest("FlowBitsTestSig06", FlowBitsTestSig06);
1096  UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07);
1097  UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08);
1098 #endif /* UNITTESTS */
1099 }
MemBuffer * MemBufferCreateNew(uint32_t size)
Definition: util-buffer.c:32
#define SCMutex
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1448
SignatureInitData * init_data
Definition: detect.h:591
#define DETECT_FLOWBITS_CMD_ISNOTSET
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1186
uint8_t type
Definition: util-var.h:49
#define SCLogDebug(...)
Definition: util-debug.h:335
#define MAX(x, y)
Signature ** sig_array
Definition: detect.h:776
struct Flow_ * flow
Definition: decode.h:445
uint32_t * set_sids
#define MemBufferWriteString(dst,...)
Write a string buffer to the Membuffer dst.
Definition: util-buffer.h:162
uint32_t sig_array_len
Definition: detect.h:778
#define BUG_ON(x)
uint32_t flags
Definition: detect.h:523
uint32_t max_fb_id
Definition: detect.h:826
uint16_t state_cnts[DETECT_FLOWBITS_CMD_MAX]
uint32_t id
Definition: detect.h:555
#define DETECT_FLOWBITS_CMD_UNSET
#define PASS
Pass the test.
#define unlikely(expr)
Definition: util-optimize.h:35
void FlowBitToggle(Flow *f, uint32_t idx)
Definition: flow-bit.c:94
Signature * SigInit(DetectEngineCtx *, const char *)
Parses a signature and adds it to the Detection Engine Context.
char * VarNameStoreSetupLookup(uint32_t idx, const enum VarTypes type)
#define DETECT_FLOWBITS_CMD_MAX
uint32_t isnotset_sids_idx
Signature * sig_list
Definition: detect.h:767
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
Address dst
Definition: decode.h:413
uint32_t toggle_sids_idx
int FlowBitIsnotset(Flow *f, uint32_t idx)
Definition: flow-bit.c:116
#define DETECT_FLOWBITS_CMD_ISSET
uint32_t * unset_sids
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
const char * name
Definition: detect.h:1200
uint32_t idx
Definition: util-var.h:51
uint32_t set_sids_idx
Signature container.
Definition: detect.h:522
#define SCMutexLock(mut)
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:313
void FlowBitSet(Flow *f, uint32_t idx)
Definition: flow-bit.c:84
SigIntId num
Definition: detect.h:532
uint32_t isset_sids_size
struct SigMatch_ * next
Definition: detect.h:322
main detection engine ctx
Definition: detect.h:761
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
struct GenericVar_ * next
Definition: util-var.h:52
int FlowBitIsset(Flow *f, uint32_t idx)
Definition: flow-bit.c:104
uint16_t cnts[DETECT_FLOWBITS_CMD_MAX]
#define DE_QUIET
Definition: detect.h:292
#define SIZE_OF_PACKET
Definition: decode.h:618
#define str(s)
#define SCMutexUnlock(mut)
void DetectFlowbitFree(void *)
#define MAX_SIDS
char family
Definition: decode.h:111
uint8_t proto
Definition: decode.h:430
uint8_t flags
Definition: detect.h:762
#define SCMUTEX_INITIALIZER
Data structures and function prototypes for keeping state for the detection engine.
void(* Free)(void *)
Definition: detect.h:1191
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
#define FLOW_DESTROY(f)
Definition: flow-util.h:121
uint32_t toggle_sids_size
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
uint32_t isnotset_sids_size
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
void SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1669
void DetectSetupParseRegexes(const char *parse_str, pcre **parse_regex, pcre_extra **parse_regex_study)
void FlowBitUnset(Flow *f, uint32_t idx)
Definition: flow-bit.c:89
#define MemBufferPrintToFPAsString(mem_buffer, fp)
Write a buffer to the file pointer as a printable char string.
Definition: util-buffer.h:93
uint8_t flowflags
Definition: decode.h:439
#define FLOW_PKT_TOSERVER
Definition: flow.h:201
SCMutex g_flowbits_dump_write_m
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1170
struct Signature_ * next
Definition: detect.h:594
uint8_t type
Definition: detect.h:319
#define SIG_FLAG_INIT_STATE_MATCH
Definition: detect.h:262
GenericVar * flowvar
Definition: flow.h:448
void FlowBitsRegisterTests(void)
this function registers unit tests for FlowBits
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:281
const char * desc
Definition: detect.h:1202
#define SCRealloc(x, a)
Definition: util-mem.h:238
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:346
struct SigMatch_ ** smlists
Definition: detect.h:516
int OutputJSONMemBufferCallback(const char *str, size_t size, void *data)
Definition: output-json.c:796
#define DETECT_FLOWBITS_CMD_NOALERT
uint32_t smlists_array_size
Definition: detect.h:514
void DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx)
SigMatchCtx * ctx
Definition: detect.h:321
const char * ConfigGetLogDirectory()
Definition: util-conf.c:36
#define SCMalloc(a)
Definition: util-mem.h:222
#define JSON_ESCAPE_SLASH
#define SCFree(a)
Definition: util-mem.h:322
#define SIG_FLAG_NOALERT
Definition: detect.h:216
int DetectFlowbitMatch(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
uint32_t init_flags
Definition: detect.h:486
uint32_t * isnotset_sids
#define DETECT_FLOWBITS_CMD_SET
uint32_t set_sids_size
uint32_t VarNameStoreSetupAdd(const char *name, const enum VarTypes type)
add to staging or return existing id if already in there
const char * url
Definition: detect.h:1203
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
#define PKT_HAS_FLOW
Definition: decode.h:1093
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
#define SIGMATCH_IPONLY_COMPAT
Definition: detect.h:1371
#define DOC_URL
Definition: suricata.h:86
uint32_t * toggle_sids
uint32_t isset_sids_idx
void DetectFlowbitsRegister(void)
uint32_t unset_sids_size
uint32_t * isset_sids
#define DETECT_FLOWBITS_CMD_TOGGLE
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:232
Per thread variable structure.
Definition: threadvars.h:57
uint32_t flags
Definition: decode.h:443
uint16_t payload_len
Definition: decode.h:541
#define DOC_VERSION
Definition: suricata.h:91
uint16_t flags
Definition: detect.h:1194
#define PARSE_REGEX
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Flow data structure.
Definition: flow.h:325
uint8_t * payload
Definition: decode.h:540
void(* RegisterTests)(void)
Definition: detect.h:1192
a single match condition for a signature
Definition: detect.h:318
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
void MemBufferFree(MemBuffer *buffer)
Definition: util-buffer.c:82
Address src
Definition: decode.h:412
uint32_t unset_sids_idx
DetectEngineCtx * DetectEngineCtxInit(void)