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 #ifdef HAVE_LIBJANSSON
333 static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
334  struct FBAnalyze *array, uint32_t elements);
335 #endif
336 #endif
337 
339 {
340  const uint32_t max_fb_id = de_ctx->max_fb_id;
341  if (max_fb_id == 0)
342  return;
343 
344 #define MAX_SIDS 8
345  uint32_t array_size = max_fb_id + 1;
346  struct FBAnalyze array[array_size];
347  memset(&array, 0, array_size * sizeof(struct FBAnalyze));
348 
349  SCLogDebug("fb analyzer array size: %"PRIu64,
350  (uint64_t)(array_size * sizeof(struct FBAnalyze)));
351 
352  /* fill flowbit array, updating counters per sig */
353  for (uint32_t i = 0; i < de_ctx->sig_array_len; i++) {
354  const Signature *s = de_ctx->sig_array[i];
355  bool has_state = false;
356 
357  /* see if the signature uses stateful matching */
358  for (uint32_t x = DETECT_SM_LIST_DYNAMIC_START; x < s->init_data->smlists_array_size; x++) {
359  if (s->init_data->smlists[x] == NULL)
360  continue;
361  has_state = true;
362  break;
363  }
364 
365  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
366  switch (sm->type) {
367  case DETECT_FLOWBITS:
368  {
369  /* figure out the flowbit action */
370  const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
371  array[fb->idx].cnts[fb->cmd]++;
372  if (has_state)
373  array[fb->idx].state_cnts[fb->cmd]++;
374  if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
375  if (array[fb->idx].isset_sids_idx >= array[fb->idx].isset_sids_size) {
376  uint32_t old_size = array[fb->idx].isset_sids_size;
377  uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
378 
379  void *ptr = SCRealloc(array[fb->idx].isset_sids, new_size * sizeof(uint32_t));
380  if (ptr == NULL)
381  goto end;
382  array[fb->idx].isset_sids_size = new_size;
383  array[fb->idx].isset_sids = ptr;
384  }
385 
386  array[fb->idx].isset_sids[array[fb->idx].isset_sids_idx] = s->num;
387  array[fb->idx].isset_sids_idx++;
388  } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET){
389  if (array[fb->idx].isnotset_sids_idx >= array[fb->idx].isnotset_sids_size) {
390  uint32_t old_size = array[fb->idx].isnotset_sids_size;
391  uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
392 
393  void *ptr = SCRealloc(array[fb->idx].isnotset_sids, new_size * sizeof(uint32_t));
394  if (ptr == NULL)
395  goto end;
396  array[fb->idx].isnotset_sids_size = new_size;
397  array[fb->idx].isnotset_sids = ptr;
398  }
399 
400  array[fb->idx].isnotset_sids[array[fb->idx].isnotset_sids_idx] = s->num;
401  array[fb->idx].isnotset_sids_idx++;
402  }
403  }
404  }
405  }
406  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_POSTMATCH] ; sm != NULL; sm = sm->next) {
407  switch (sm->type) {
408  case DETECT_FLOWBITS:
409  {
410  /* figure out what flowbit action */
411  const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
412  array[fb->idx].cnts[fb->cmd]++;
413  if (has_state)
414  array[fb->idx].state_cnts[fb->cmd]++;
415  if (fb->cmd == DETECT_FLOWBITS_CMD_SET) {
416  if (array[fb->idx].set_sids_idx >= array[fb->idx].set_sids_size) {
417  uint32_t old_size = array[fb->idx].set_sids_size;
418  uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
419 
420  void *ptr = SCRealloc(array[fb->idx].set_sids, new_size * sizeof(uint32_t));
421  if (ptr == NULL)
422  goto end;
423  array[fb->idx].set_sids_size = new_size;
424  array[fb->idx].set_sids = ptr;
425  }
426 
427  array[fb->idx].set_sids[array[fb->idx].set_sids_idx] = s->num;
428  array[fb->idx].set_sids_idx++;
429  }
430  else if (fb->cmd == DETECT_FLOWBITS_CMD_UNSET) {
431  if (array[fb->idx].unset_sids_idx >= array[fb->idx].unset_sids_size) {
432  uint32_t old_size = array[fb->idx].unset_sids_size;
433  uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
434 
435  void *ptr = SCRealloc(array[fb->idx].unset_sids, new_size * sizeof(uint32_t));
436  if (ptr == NULL)
437  goto end;
438  array[fb->idx].unset_sids_size = new_size;
439  array[fb->idx].unset_sids = ptr;
440  }
441 
442  array[fb->idx].unset_sids[array[fb->idx].unset_sids_idx] = s->num;
443  array[fb->idx].unset_sids_idx++;
444  }
445  else if (fb->cmd == DETECT_FLOWBITS_CMD_TOGGLE) {
446  if (array[fb->idx].toggle_sids_idx >= array[fb->idx].toggle_sids_size) {
447  uint32_t old_size = array[fb->idx].toggle_sids_size;
448  uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
449 
450  void *ptr = SCRealloc(array[fb->idx].toggle_sids, new_size * sizeof(uint32_t));
451  if (ptr == NULL)
452  goto end;
453  array[fb->idx].toggle_sids_size = new_size;
454  array[fb->idx].toggle_sids = ptr;
455  }
456 
457  array[fb->idx].toggle_sids[array[fb->idx].toggle_sids_idx] = s->num;
458  array[fb->idx].toggle_sids_idx++;
459  }
460  }
461  }
462  }
463  }
464 
465  /* walk array to see if all bits make sense */
466  for (uint32_t i = 0; i < array_size; i++) {
467  char *varname = VarNameStoreSetupLookup(i, VAR_TYPE_FLOW_BIT);
468  if (varname == NULL)
469  continue;
470 
471  bool to_state = false;
472 
473  if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] &&
474  array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE] == 0 &&
475  array[i].cnts[DETECT_FLOWBITS_CMD_SET] == 0) {
476 
477  const Signature *s = de_ctx->sig_array[array[i].isset_sids[0]];
478  SCLogWarning(SC_WARN_FLOWBIT, "flowbit '%s' is checked but not "
479  "set. Checked in %u and %u other sigs",
480  varname, s->id, array[i].isset_sids_idx - 1);
481  }
482  if (array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] &&
483  array[i].state_cnts[DETECT_FLOWBITS_CMD_SET] == 0)
484  {
485  SCLogDebug("flowbit %s/%u: isset in state, set not in state", varname, i);
486  }
487 
488  /* if signature depends on 'stateful' flowbits, then turn the
489  * sig into a stateful sig itself */
490  if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] > 0 &&
491  array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] == 0 &&
493  {
494  SCLogDebug("flowbit %s/%u: isset not in state, set in state", varname, i);
495  to_state = true;
496  }
497 
498  SCLogDebug("ALL flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
499  array[i].cnts[DETECT_FLOWBITS_CMD_SET], array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE],
501  array[i].cnts[DETECT_FLOWBITS_CMD_ISSET]);
502  SCLogDebug("STATE flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
503  array[i].state_cnts[DETECT_FLOWBITS_CMD_SET], array[i].state_cnts[DETECT_FLOWBITS_CMD_TOGGLE],
504  array[i].state_cnts[DETECT_FLOWBITS_CMD_UNSET], array[i].state_cnts[DETECT_FLOWBITS_CMD_ISNOTSET],
505  array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET]);
506  for (uint32_t x = 0; x < array[i].set_sids_idx; x++) {
507  SCLogDebug("SET flowbit %s/%u: SID %u", varname, i,
508  de_ctx->sig_array[array[i].set_sids[x]]->id);
509  }
510  for (uint32_t x = 0; x < array[i].isset_sids_idx; x++) {
511  Signature *s = de_ctx->sig_array[array[i].isset_sids[x]];
512  SCLogDebug("GET flowbit %s/%u: SID %u", varname, i, s->id);
513 
514  if (to_state) {
516  SCLogDebug("made SID %u stateful because it depends on "
517  "stateful rules that set flowbit %s", s->id, varname);
518  }
519  }
520  SCFree(varname);
521  }
522 #ifdef PROFILING
523 #ifdef HAVE_LIBJANSSON
524  DetectFlowbitsAnalyzeDump(de_ctx, array, array_size);
525 #endif
526 #endif
527 
528 end:
529  for (uint32_t i = 0; i < array_size; i++) {
530  SCFree(array[i].set_sids);
531  SCFree(array[i].unset_sids);
532  SCFree(array[i].isset_sids);
533  SCFree(array[i].isnotset_sids);
534  SCFree(array[i].toggle_sids);
535  }
536 }
537 
538 #ifdef PROFILING
539 #ifdef HAVE_LIBJANSSON
540 #include "output-json.h"
541 #include "util-buffer.h"
542 SCMutex g_flowbits_dump_write_m = SCMUTEX_INITIALIZER;
543 static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
544  struct FBAnalyze *array, uint32_t elements)
545 {
546  json_t *js = json_object();
547  if (js == NULL)
548  return;
549 
550  json_t *js_array = json_array();
551  uint32_t x;
552  for (x = 0; x < elements; x++)
553  {
554  char *varname = VarNameStoreSetupLookup(x, VAR_TYPE_FLOW_BIT);
555  if (varname == NULL)
556  continue;
557 
558  const struct FBAnalyze *e = &array[x];
559 
560  json_t *js_fb = json_object();
561  if (unlikely(js_fb != NULL)) {
562  json_object_set_new(js_fb, "name", json_string(varname));
563  json_object_set_new(js_fb, "internal_id", json_integer(x));
564  json_object_set_new(js_fb, "set_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_SET]));
565  json_object_set_new(js_fb, "unset_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_UNSET]));
566  json_object_set_new(js_fb, "toggle_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_TOGGLE]));
567  json_object_set_new(js_fb, "isset_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_ISSET]));
568  json_object_set_new(js_fb, "isnotset_cnt", json_integer(e->cnts[DETECT_FLOWBITS_CMD_ISNOTSET]));
569 
570  // sets
571  if (e->cnts[DETECT_FLOWBITS_CMD_SET]) {
572  json_t *js_set_array = json_array();
573  if (js_set_array) {
574  for(uint32_t i = 0; i < e->set_sids_idx; i++) {
575  const Signature *s = de_ctx->sig_array[e->set_sids[i]];
576  json_array_append_new(js_set_array, json_integer(s->id));
577  }
578  json_object_set_new(js_fb, "sets", js_set_array);
579  }
580  }
581  // gets
583  json_t *js_isset_array = json_array();
584  if (js_isset_array) {
585  for(uint32_t i = 0; i < e->isset_sids_idx; i++) {
586  const Signature *s = de_ctx->sig_array[e->isset_sids[i]];
587  json_array_append_new(js_isset_array, json_integer(s->id));
588  }
589  json_object_set_new(js_fb, "isset", js_isset_array);
590  }
591  }
592  // isnotset
594  json_t *js_isnotset_array = json_array();
595  if (js_isnotset_array) {
596  for(uint32_t i = 0; i < e->isnotset_sids_idx; i++) {
597  const Signature *s = de_ctx->sig_array[e->isnotset_sids[i]];
598  json_array_append_new(js_isnotset_array, json_integer(s->id));
599  }
600  json_object_set_new(js_fb, "isnotset", js_isnotset_array);
601  }
602  }
603  // unset
605  json_t *js_unset_array = json_array();
606  if (js_unset_array) {
607  for(uint32_t i = 0; i < e->unset_sids_idx; i++) {
608  const Signature *s = de_ctx->sig_array[e->unset_sids[i]];
609  json_array_append_new(js_unset_array, json_integer(s->id));
610  }
611  json_object_set_new(js_fb, "unset", js_unset_array);
612  }
613  }
614  // toggle
616  json_t *js_toggle_array = json_array();
617  if (js_toggle_array) {
618  for(uint32_t i = 0; i < e->toggle_sids_idx; i++) {
619  const Signature *s = de_ctx->sig_array[e->toggle_sids[i]];
620  json_array_append_new(js_toggle_array, json_integer(s->id));
621  }
622  json_object_set_new(js_fb, "toggle", js_toggle_array);
623  }
624  }
625 
626  json_array_append_new(js_array, js_fb);
627  }
628  SCFree(varname);
629  }
630 
631  json_object_set_new(js, "flowbits", js_array);
632 
633  const char *filename = "flowbits.json";
634  const char *log_dir = ConfigGetLogDirectory();
635  char log_path[PATH_MAX] = "";
636  snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, filename);
637 
638  MemBuffer *mbuf = NULL;
639  mbuf = MemBufferCreateNew(4096);
640  BUG_ON(mbuf == NULL);
641 
642  OutputJSONMemBufferWrapper wrapper = {
643  .buffer = &mbuf,
644  .expand_by = 4096,
645  };
646 
647  int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper,
648  JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
649  JSON_ESCAPE_SLASH);
650  if (r != 0) {
651  SCLogWarning(SC_ERR_SOCKET, "unable to serialize JSON object");
652  } else {
653  MemBufferWriteString(mbuf, "\n");
654  SCMutexLock(&g_flowbits_dump_write_m);
655  FILE *fp = fopen(log_path, "w");
656  if (fp != NULL) {
657  MemBufferPrintToFPAsString(mbuf, fp);
658  fclose(fp);
659  }
660  SCMutexUnlock(&g_flowbits_dump_write_m);
661  }
662 
663  MemBufferFree(mbuf);
664  json_object_clear(js);
665  json_decref(js);
666 }
667 #endif /* HAVE_LIBJANSSON */
668 #endif /* PROFILING */
669 
670 #ifdef UNITTESTS
671 
672 static int FlowBitsTestParse01(void)
673 {
674  char command[16] = "", name[16] = "";
675 
676  /* Single argument version. */
677  FAIL_IF(!DetectFlowbitParse("noalert", command, sizeof(command), name,
678  sizeof(name)));
679  FAIL_IF(strcmp(command, "noalert") != 0);
680 
681  /* No leading or trailing spaces. */
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  /* Leading 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  /* 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  /* Leading and trailing space. */
700  FAIL_IF(!DetectFlowbitParse("set, flowbit ", command, sizeof(command), name,
701  sizeof(name)));
702  FAIL_IF(strcmp(command, "set") != 0);
703  FAIL_IF(strcmp(name, "flowbit") != 0);
704 
705  /* Spaces are not allowed in the name. */
706  FAIL_IF(DetectFlowbitParse("set,namewith space", command, sizeof(command),
707  name, sizeof(name)));
708 
709  PASS;
710 }
711 
712 /**
713  * \test FlowBitsTestSig01 is a test for a valid noalert flowbits option
714  *
715  * \retval 1 on succces
716  * \retval 0 on failure
717  */
718 
719 static int FlowBitsTestSig01(void)
720 {
721  Signature *s = NULL;
722  DetectEngineCtx *de_ctx = NULL;
723 
724  de_ctx = DetectEngineCtxInit();
725  FAIL_IF_NULL(de_ctx);
726 
727  de_ctx->flags |= DE_QUIET;
728 
729  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)");
730  FAIL_IF_NOT_NULL(s);
731 
732  SigGroupBuild(de_ctx);
733  DetectEngineCtxFree(de_ctx);
734  PASS;
735 }
736 
737 /**
738  * \test FlowBitsTestSig02 is a test for a valid isset,set,isnotset,unset,toggle flowbits options
739  *
740  * \retval 1 on succces
741  * \retval 0 on failure
742  */
743 
744 static int FlowBitsTestSig02(void)
745 {
746  Signature *s = NULL;
747  ThreadVars th_v;
748  DetectEngineCtx *de_ctx = NULL;
749 
750  memset(&th_v, 0, sizeof(th_v));
751 
752  de_ctx = DetectEngineCtxInit();
753  FAIL_IF_NULL(de_ctx);
754 
755  de_ctx->flags |= DE_QUIET;
756 
757  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;)");
758  FAIL_IF_NOT_NULL(s);
759 
760  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;)");
761  FAIL_IF_NOT_NULL(s);
762 
763  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;)");
764  FAIL_IF_NOT_NULL(s);
765 
766  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;)");
767  FAIL_IF_NOT_NULL(s);
768 
769  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;)");
770  FAIL_IF_NOT_NULL(s);
771 
772  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;)");
773  FAIL_IF_NOT_NULL(s);
774 
775  SigGroupBuild(de_ctx);
776  DetectEngineCtxFree(de_ctx);
777 
778  PASS;
779 }
780 
781 /**
782  * \test FlowBitsTestSig03 is a test for a invalid flowbits option
783  *
784  * \retval 1 on succces
785  * \retval 0 on failure
786  */
787 
788 static int FlowBitsTestSig03(void)
789 {
790  Signature *s = NULL;
791  DetectEngineCtx *de_ctx = NULL;
792 
793  de_ctx = DetectEngineCtxInit();
794  FAIL_IF_NULL(de_ctx);
795 
796  de_ctx->flags |= DE_QUIET;
797 
798  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)");
799  FAIL_IF_NOT_NULL(s);
800 
801  SigGroupBuild(de_ctx);
802  DetectEngineCtxFree(de_ctx);
803  PASS;
804 }
805 
806 /**
807  * \test FlowBitsTestSig04 is a test check idx value
808  *
809  * \retval 1 on succces
810  * \retval 0 on failure
811  */
812 
813 static int FlowBitsTestSig04(void)
814 {
815  Signature *s = NULL;
816  DetectEngineCtx *de_ctx = NULL;
817  int idx = 0;
818 
819  de_ctx = DetectEngineCtxInit();
820  FAIL_IF_NULL(de_ctx);
821 
822  de_ctx->flags |= DE_QUIET;
823 
824  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)");
825  FAIL_IF_NULL(s);
826 
828  FAIL_IF(idx != 1);
829 
830  SigGroupBuild(de_ctx);
831  DetectEngineCtxFree(de_ctx);
832  PASS;
833 }
834 
835 /**
836  * \test FlowBitsTestSig05 is a test check noalert flag
837  *
838  * \retval 1 on succces
839  * \retval 0 on failure
840  */
841 
842 static int FlowBitsTestSig05(void)
843 {
844  Signature *s = NULL;
845  DetectEngineCtx *de_ctx = NULL;
846 
847  de_ctx = DetectEngineCtxInit();
848  FAIL_IF_NULL(de_ctx);
849 
850  de_ctx->flags |= DE_QUIET;
851 
852  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)");
853  FAIL_IF_NULL(s);
855 
856  SigGroupBuild(de_ctx);
857  DetectEngineCtxFree(de_ctx);
858  PASS;
859 }
860 
861 /**
862  * \test FlowBitsTestSig06 is a test set flowbits option
863  *
864  * \retval 1 on succces
865  * \retval 0 on failure
866  */
867 
868 static int FlowBitsTestSig06(void)
869 {
870  uint8_t *buf = (uint8_t *)
871  "GET /one/ HTTP/1.1\r\n"
872  "Host: one.example.org\r\n"
873  "\r\n";
874  uint16_t buflen = strlen((char *)buf);
876  FAIL_IF_NULL(p);
877  Signature *s = NULL;
878  ThreadVars th_v;
879  DetectEngineThreadCtx *det_ctx = NULL;
880  DetectEngineCtx *de_ctx = NULL;
881  Flow f;
882  GenericVar flowvar, *gv = NULL;
883  int result = 0;
884  uint32_t idx = 0;
885 
886  memset(p, 0, SIZE_OF_PACKET);
887  memset(&th_v, 0, sizeof(th_v));
888  memset(&f, 0, sizeof(Flow));
889  memset(&flowvar, 0, sizeof(GenericVar));
890 
891  FLOW_INITIALIZE(&f);
892  p->flow = &f;
893  p->flow->flowvar = &flowvar;
894 
895  p->src.family = AF_INET;
896  p->dst.family = AF_INET;
897  p->payload = buf;
898  p->payload_len = buflen;
899  p->proto = IPPROTO_TCP;
900  p->flags |= PKT_HAS_FLOW;
902 
903  de_ctx = DetectEngineCtxInit();
904  FAIL_IF_NULL(de_ctx);
905 
906  de_ctx->flags |= DE_QUIET;
907 
908  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)");
909  FAIL_IF_NULL(s);
910 
911  idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
912  SigGroupBuild(de_ctx);
913  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
914 
915  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
916 
917  gv = p->flow->flowvar;
918  FAIL_IF_NULL(gv);
919  for ( ; gv != NULL; gv = gv->next) {
920  if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
921  result = 1;
922  }
923  }
924  FAIL_IF_NOT(result);
925 
926  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
927  DetectEngineCtxFree(de_ctx);
928 
929  FLOW_DESTROY(&f);
930 
931  SCFree(p);
932  PASS;
933 }
934 
935 /**
936  * \test FlowBitsTestSig07 is a test unset flowbits option
937  *
938  * \retval 1 on succces
939  * \retval 0 on failure
940  */
941 
942 static int FlowBitsTestSig07(void)
943 {
944  uint8_t *buf = (uint8_t *)
945  "GET /one/ HTTP/1.1\r\n"
946  "Host: one.example.org\r\n"
947  "\r\n";
948  uint16_t buflen = strlen((char *)buf);
950  FAIL_IF_NULL(p);
951  Signature *s = NULL;
952  ThreadVars th_v;
953  DetectEngineThreadCtx *det_ctx = NULL;
954  DetectEngineCtx *de_ctx = NULL;
955  Flow f;
956  GenericVar flowvar, *gv = NULL;
957  int result = 0;
958  uint32_t idx = 0;
959 
960  memset(p, 0, SIZE_OF_PACKET);
961  memset(&th_v, 0, sizeof(th_v));
962  memset(&f, 0, sizeof(Flow));
963  memset(&flowvar, 0, sizeof(GenericVar));
964 
965  FLOW_INITIALIZE(&f);
966  p->flow = &f;
967  p->flow->flowvar = &flowvar;
968 
969  p->src.family = AF_INET;
970  p->dst.family = AF_INET;
971  p->payload = buf;
972  p->payload_len = buflen;
973  p->proto = IPPROTO_TCP;
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,myflow2; sid:10;)");
981  FAIL_IF_NULL(s);
982 
983  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)");
984  FAIL_IF_NULL(s);
985 
986  idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
987  SigGroupBuild(de_ctx);
988  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
989 
990  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
991 
992  gv = p->flow->flowvar;
993  FAIL_IF_NULL(gv);
994 
995  for ( ; gv != NULL; gv = gv->next) {
996  if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
997  result = 1;
998  }
999  }
1000  FAIL_IF(result);
1001 
1002  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1003  DetectEngineCtxFree(de_ctx);
1004 
1005  FLOW_DESTROY(&f);
1006 
1007  SCFree(p);
1008  PASS;
1009 }
1010 
1011 /**
1012  * \test FlowBitsTestSig08 is a test toogle flowbits option
1013  *
1014  * \retval 1 on succces
1015  * \retval 0 on failure
1016  */
1017 
1018 static int FlowBitsTestSig08(void)
1019 {
1020  uint8_t *buf = (uint8_t *)
1021  "GET /one/ HTTP/1.1\r\n"
1022  "Host: one.example.org\r\n"
1023  "\r\n";
1024  uint16_t buflen = strlen((char *)buf);
1026  if (unlikely(p == NULL))
1027  return 0;
1028  Signature *s = NULL;
1029  ThreadVars th_v;
1030  DetectEngineThreadCtx *det_ctx = NULL;
1031  DetectEngineCtx *de_ctx = NULL;
1032  Flow f;
1033  GenericVar flowvar, *gv = NULL;
1034  int result = 0;
1035  uint32_t idx = 0;
1036 
1037  memset(p, 0, SIZE_OF_PACKET);
1038  memset(&th_v, 0, sizeof(th_v));
1039  memset(&f, 0, sizeof(Flow));
1040  memset(&flowvar, 0, sizeof(GenericVar));
1041 
1042  FLOW_INITIALIZE(&f);
1043  p->flow = &f;
1044  p->flow->flowvar = &flowvar;
1045 
1046  p->src.family = AF_INET;
1047  p->dst.family = AF_INET;
1048  p->payload = buf;
1049  p->payload_len = buflen;
1050  p->proto = IPPROTO_TCP;
1051 
1052  de_ctx = DetectEngineCtxInit();
1053  FAIL_IF_NULL(de_ctx);
1054 
1055  de_ctx->flags |= DE_QUIET;
1056 
1057  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)");
1058  FAIL_IF_NULL(s);
1059 
1060  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:toggle,myflow2; sid:11;)");
1061  FAIL_IF_NULL(s);
1062 
1063  idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
1064  SigGroupBuild(de_ctx);
1065  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1066 
1067  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1068 
1069  gv = p->flow->flowvar;
1070  FAIL_IF_NULL(gv);
1071 
1072  for ( ; gv != NULL; gv = gv->next) {
1073  if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1074  result = 1;
1075  }
1076  }
1077  FAIL_IF(result);
1078 
1079  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1080  DetectEngineCtxFree(de_ctx);
1081 
1082  FLOW_DESTROY(&f);
1083 
1084  SCFree(p);
1085  PASS;
1086 }
1087 #endif /* UNITTESTS */
1088 
1089 /**
1090  * \brief this function registers unit tests for FlowBits
1091  */
1093 {
1094 #ifdef UNITTESTS
1095  UtRegisterTest("FlowBitsTestParse01", FlowBitsTestParse01);
1096  UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01);
1097  UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02);
1098  UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03);
1099  UtRegisterTest("FlowBitsTestSig04", FlowBitsTestSig04);
1100  UtRegisterTest("FlowBitsTestSig05", FlowBitsTestSig05);
1101  UtRegisterTest("FlowBitsTestSig06", FlowBitsTestSig06);
1102  UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07);
1103  UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08);
1104 #endif /* UNITTESTS */
1105 }
MemBuffer * MemBufferCreateNew(uint32_t size)
Definition: util-buffer.c:32
#define SCMutex
int DetectFlowbitMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1406
SignatureInitData * init_data
Definition: detect.h:563
#define DETECT_FLOWBITS_CMD_ISNOTSET
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1149
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:738
struct Flow_ * flow
Definition: decode.h:443
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:740
#define BUG_ON(x)
uint32_t flags
Definition: detect.h:496
uint32_t max_fb_id
Definition: detect.h:788
uint16_t state_cnts[DETECT_FLOWBITS_CMD_MAX]
uint32_t id
Definition: detect.h:528
#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:729
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
Address dst
Definition: decode.h:411
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:1163
uint32_t idx
Definition: util-var.h:51
uint32_t set_sids_idx
Signature container.
Definition: detect.h:495
#define SCMutexLock(mut)
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:317
void FlowBitSet(Flow *f, uint32_t idx)
Definition: flow-bit.c:84
SigIntId num
Definition: detect.h:505
uint32_t isset_sids_size
struct SigMatch_ * next
Definition: detect.h:326
main detection engine ctx
Definition: detect.h:723
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:296
#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:109
uint8_t proto
Definition: decode.h:428
uint8_t flags
Definition: detect.h:724
#define SCMUTEX_INITIALIZER
Data structures and function prototypes for keeping state for the detection engine.
void(* Free)(void *)
Definition: detect.h:1154
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
#define FLOW_DESTROY(f)
Definition: flow-util.h:115
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:1743
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:437
#define FLOW_PKT_TOSERVER
Definition: flow.h:200
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
struct Signature_ * next
Definition: detect.h:566
uint8_t type
Definition: detect.h:323
#define SIG_FLAG_INIT_STATE_MATCH
Definition: detect.h:267
GenericVar * flowvar
Definition: flow.h:443
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:1165
#define SCRealloc(x, a)
Definition: util-mem.h:182
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:288
struct SigMatch_ ** smlists
Definition: detect.h:489
#define DETECT_FLOWBITS_CMD_NOALERT
uint32_t smlists_array_size
Definition: detect.h:487
void DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx)
SigMatchCtx * ctx
Definition: detect.h:325
const char * ConfigGetLogDirectory()
Definition: util-conf.c:36
#define SCMalloc(a)
Definition: util-mem.h:166
#define SCFree(a)
Definition: util-mem.h:228
#define SIG_FLAG_NOALERT
Definition: detect.h:221
uint32_t init_flags
Definition: detect.h:459
uint32_t * isnotset_sids
#define DETECT_FLOWBITS_CMD_SET
uint32_t set_sids_size
int(* Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1132
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:1166
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
#define PKT_HAS_FLOW
Definition: decode.h:1092
#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:1333
#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:441
uint16_t payload_len
Definition: decode.h:541
#define DOC_VERSION
Definition: suricata.h:91
uint16_t flags
Definition: detect.h:1157
#define PARSE_REGEX
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Flow data structure.
Definition: flow.h:324
uint8_t * payload
Definition: decode.h:540
void(* RegisterTests)(void)
Definition: detect.h:1155
a single match condition for a signature
Definition: detect.h:322
#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:410
uint32_t unset_sids_idx
DetectEngineCtx * DetectEngineCtxInit(void)