suricata
detect-flowbits.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2025 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 "action-globals.h"
30 #include "detect.h"
31 #include "threads.h"
32 #include "flow.h"
33 #include "flow-bit.h"
34 #include "flow-util.h"
35 #include "detect-flowbits.h"
36 #include "util-spm.h"
37 
38 #include "app-layer-parser.h"
39 
40 #include "detect-parse.h"
41 #include "detect-engine.h"
42 #include "detect-engine-mpm.h"
43 #include "detect-engine-state.h"
44 #include "detect-engine-build.h"
46 
47 #include "tree.h"
48 
49 #include "util-var-name.h"
50 #include "util-unittest.h"
51 #include "util-debug.h"
52 #include "util-conf.h"
53 
54 #define PARSE_REGEX "^([a-z]+)(?:,\\s*(.*))?"
55 static DetectParseRegex parse_regex;
56 
57 #define MAX_TOKENS 100
58 
60  const Signature *, const SigMatchCtx *);
61 static int DetectFlowbitSetup (DetectEngineCtx *, Signature *, const char *);
62 static int FlowbitOrAddData(DetectEngineCtx *, DetectFlowbitsData *, char *);
63 void DetectFlowbitFree (DetectEngineCtx *, void *);
64 #ifdef UNITTESTS
65 void FlowBitsRegisterTests(void);
66 #endif
67 static bool PrefilterFlowbitIsPrefilterable(const Signature *s);
68 static int PrefilterSetupFlowbits(DetectEngineCtx *de_ctx, SigGroupHead *sgh);
69 
71 {
72  sigmatch_table[DETECT_FLOWBITS].name = "flowbits";
73  sigmatch_table[DETECT_FLOWBITS].desc = "operate on flow flag";
74  sigmatch_table[DETECT_FLOWBITS].url = "/rules/flow-keywords.html#flowbits";
76  sigmatch_table[DETECT_FLOWBITS].Setup = DetectFlowbitSetup;
78 #ifdef UNITTESTS
80 #endif
81  /* this is compatible to ip-only signatures */
83 
84  sigmatch_table[DETECT_FLOWBITS].SupportsPrefilter = PrefilterFlowbitIsPrefilterable;
85  sigmatch_table[DETECT_FLOWBITS].SetupPrefilter = PrefilterSetupFlowbits;
86  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
87 }
88 
89 static int FlowbitOrAddData(DetectEngineCtx *de_ctx, DetectFlowbitsData *cd, char *arrptr)
90 {
91  char *strarr[MAX_TOKENS];
92  char *token;
93  char *saveptr = NULL;
94  uint8_t i = 0;
95 
96  while ((token = strtok_r(arrptr, "|", &saveptr))) {
97  // Check for leading/trailing spaces in the token
98  while(isspace((unsigned char)*token))
99  token++;
100  if (*token == 0)
101  goto next;
102  char *end = token + strlen(token) - 1;
103  while(end > token && isspace((unsigned char)*end))
104  *(end--) = '\0';
105 
106  // Check for spaces in between the flowbit names
107  if (strchr(token, ' ') != NULL) {
108  SCLogError("Spaces are not allowed in flowbit names.");
109  return -1;
110  }
111 
112  if (i == MAX_TOKENS) {
113  SCLogError("Number of flowbits exceeds "
114  "maximum allowed: %d.",
115  MAX_TOKENS);
116  return -1;
117  }
118  strarr[i++] = token;
119  next:
120  arrptr = NULL;
121  }
122  if (i == 0) {
123  SCLogError("No valid flowbits specified");
124  return -1;
125  }
126 
127  cd->or_list_size = i;
128  cd->or_list = SCCalloc(cd->or_list_size, sizeof(uint32_t));
129  if (unlikely(cd->or_list == NULL))
130  return -1;
131  for (uint8_t j = 0; j < cd->or_list_size ; j++) {
132  cd->or_list[j] = VarNameStoreRegister(strarr[j], VAR_TYPE_FLOW_BIT);
134  }
135 
136  return 1;
137 }
138 
139 static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd)
140 {
141  if (p->flow == NULL)
142  return -1;
143 
144  return FlowBitToggle(p->flow, fd->idx);
145 }
146 
147 static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd)
148 {
149  if (p->flow == NULL)
150  return 0;
151 
152  FlowBitUnset(p->flow,fd->idx);
153 
154  return 1;
155 }
156 
157 static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd)
158 {
159  if (p->flow == NULL)
160  return -1;
161 
162  int r = FlowBitSet(p->flow, fd->idx);
163  SCLogDebug("set %u", fd->idx);
164  return r;
165 }
166 
167 static int DetectFlowbitMatchIsset (Packet *p, const DetectFlowbitsData *fd)
168 {
169  if (p->flow == NULL)
170  return 0;
171  if (fd->or_list_size > 0) {
172  for (uint8_t i = 0; i < fd->or_list_size; i++) {
173  if (FlowBitIsset(p->flow, fd->or_list[i]) == 1)
174  return 1;
175  }
176  return 0;
177  }
178 
179  return FlowBitIsset(p->flow,fd->idx);
180 }
181 
182 static int DetectFlowbitMatchIsnotset (Packet *p, const DetectFlowbitsData *fd)
183 {
184  if (p->flow == NULL)
185  return 0;
186  if (fd->or_list_size > 0) {
187  for (uint8_t i = 0; i < fd->or_list_size; i++) {
188  if (FlowBitIsnotset(p->flow, fd->or_list[i]) == 1)
189  return 1;
190  }
191  return 0;
192  }
193  return FlowBitIsnotset(p->flow,fd->idx);
194 }
195 
196 /*
197  * returns 0: no match (or error)
198  * 1: match
199  */
200 
202  const Signature *s, const SigMatchCtx *ctx)
203 {
204  const DetectFlowbitsData *fd = (const DetectFlowbitsData *)ctx;
205  if (fd == NULL)
206  return 0;
207 
208  switch (fd->cmd) {
210  return DetectFlowbitMatchIsset(p,fd);
212  return DetectFlowbitMatchIsnotset(p,fd);
214  int r = DetectFlowbitMatchSet(p, fd);
215  /* only on a new "set" invoke the prefilter */
216  if (r == 1 && fd->post_rule_match_prefilter) {
217  SCLogDebug("flowbit set, appending to work queue");
219  }
220  return (r != -1);
221  }
223  return DetectFlowbitMatchUnset(p,fd);
225  int r = DetectFlowbitMatchToggle(p, fd);
226  if (r == 1 && fd->post_rule_match_prefilter) {
227  SCLogDebug("flowbit set (by toggle), appending to work queue");
229  }
230  return (r != -1);
231  }
232  default:
233  SCLogError("unknown cmd %" PRIu32 "", fd->cmd);
234  return 0;
235  }
236 
237  return 0;
238 }
239 
240 static int DetectFlowbitParse(const char *str, char *cmd, int cmd_len, char *name,
241  int name_len)
242 {
243  int rc;
244  size_t pcre2len;
245  pcre2_match_data *match = NULL;
246 
247  int count = DetectParsePcreExec(&parse_regex, &match, str, 0, 0);
248  if (count != 2 && count != 3) {
249  SCLogError("\"%s\" is not a valid setting for flowbits.", str);
250  goto error;
251  }
252 
253  pcre2len = cmd_len;
254  rc = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)cmd, &pcre2len);
255  if (rc < 0) {
256  SCLogError("pcre2_substring_copy_bynumber failed");
257  goto error;
258  }
259 
260  if (count == 3) {
261  pcre2len = name_len;
262  rc = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)name, &pcre2len);
263  if (rc < 0) {
264  SCLogError("pcre2_substring_copy_bynumber failed");
265  goto error;
266  }
267 
268  /* Trim trailing whitespace. */
269  while (strlen(name) > 0 && isblank(name[strlen(name) - 1])) {
270  name[strlen(name) - 1] = '\0';
271  }
272 
273  if (strchr(name, '|') == NULL) {
274  /* Validate name, spaces are not allowed. */
275  for (size_t i = 0; i < strlen(name); i++) {
276  if (isblank(name[i])) {
277  SCLogError("spaces not allowed in flowbit names");
278  goto error;
279  }
280  }
281  }
282  }
283 
284  pcre2_match_data_free(match);
285  return 1;
286 
287 error:
288  if (match) {
289  pcre2_match_data_free(match);
290  }
291  return 0;
292 }
293 
294 int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
295 {
296  DetectFlowbitsData *cd = NULL;
297  uint8_t fb_cmd = 0;
298  char fb_cmd_str[16] = "", fb_name[256] = "";
299 
300  if (!DetectFlowbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), fb_name,
301  sizeof(fb_name))) {
302  return -1;
303  }
304 
305  if (strcmp(fb_cmd_str,"noalert") == 0) {
306  if (strlen(fb_name) != 0)
307  goto error;
308  s->action &= ~ACTION_ALERT;
309  return 0;
310  } else if (strcmp(fb_cmd_str,"isset") == 0) {
311  fb_cmd = DETECT_FLOWBITS_CMD_ISSET;
312  } else if (strcmp(fb_cmd_str,"isnotset") == 0) {
314  } else if (strcmp(fb_cmd_str,"set") == 0) {
315  fb_cmd = DETECT_FLOWBITS_CMD_SET;
316  } else if (strcmp(fb_cmd_str,"unset") == 0) {
317  fb_cmd = DETECT_FLOWBITS_CMD_UNSET;
318  } else if (strcmp(fb_cmd_str,"toggle") == 0) {
320  } else {
321  SCLogError("ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str);
322  goto error;
323  }
324 
325  switch (fb_cmd) {
331  default:
332  if (strlen(fb_name) == 0)
333  goto error;
334  break;
335  }
336 
337  cd = SCCalloc(1, sizeof(DetectFlowbitsData));
338  if (unlikely(cd == NULL))
339  goto error;
340  if (strchr(fb_name, '|') != NULL) {
341  int retval = FlowbitOrAddData(de_ctx, cd, fb_name);
342  if (retval == -1) {
343  goto error;
344  }
345  cd->cmd = fb_cmd;
346  } else {
349  cd->cmd = fb_cmd;
350  cd->or_list_size = 0;
351  cd->or_list = NULL;
352  SCLogDebug("idx %" PRIu32 ", cmd %s, name %s",
353  cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)");
354  }
355  /* Okay so far so good, lets get this into a SigMatch
356  * and put it in the Signature. */
357 
358  switch (fb_cmd) {
359  /* noalert can't happen here */
362  /* checks, so packet list */
364  DETECT_SM_LIST_MATCH) == NULL) {
365  goto error;
366  }
367  break;
368 
372  /* modifiers, only run when entire sig has matched */
374  DETECT_SM_LIST_POSTMATCH) == NULL) {
375  goto error;
376  }
377  break;
378 
379  // suppress coverity warning as scan-build-7 warns w/o this.
380  // coverity[deadcode : FALSE]
381  default:
382  goto error;
383  }
384 
385  return 0;
386 
387 error:
388  if (cd != NULL)
390  return -1;
391 }
392 
394 {
396  if (fd == NULL)
397  return;
399  if (fd->or_list != NULL) {
400  for (uint8_t i = 0; i < fd->or_list_size; i++) {
402  }
403  SCFree(fd->or_list);
404  }
405  SCFree(fd);
406 }
407 
408 struct FBAnalyzer {
409  struct FBAnalyze *array;
410  uint32_t array_size;
411 };
412 
413 struct FBAnalyze {
416 
417  uint32_t *set_sids;
418  uint32_t set_sids_idx;
419  uint32_t set_sids_size;
420 
421  uint32_t *isset_sids;
422  uint32_t isset_sids_idx;
423  uint32_t isset_sids_size;
424 
425  uint32_t *isnotset_sids;
428 
429  uint32_t *unset_sids;
430  uint32_t unset_sids_idx;
431  uint32_t unset_sids_size;
432 
433  uint32_t *toggle_sids;
434  uint32_t toggle_sids_idx;
436 };
437 
438 extern bool rule_engine_analysis_set;
439 static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
440  struct FBAnalyze *array, uint32_t elements);
441 
442 static void FBAnalyzerArrayFree(struct FBAnalyze *array, const uint32_t array_size)
443 {
444  if (array) {
445  for (uint32_t i = 0; i < array_size; i++) {
446  SCFree(array[i].set_sids);
447  SCFree(array[i].unset_sids);
448  SCFree(array[i].isset_sids);
449  SCFree(array[i].isnotset_sids);
450  SCFree(array[i].toggle_sids);
451  }
452  SCFree(array);
453  }
454 }
455 
456 static void FBAnalyzerFree(struct FBAnalyzer *fba)
457 {
458  if (fba && fba->array) {
459  FBAnalyzerArrayFree(fba->array, fba->array_size);
460  fba->array = NULL;
461  fba->array_size = 0;
462  }
463 }
464 
465 #define MAX_SIDS 8
466 static bool CheckExpand(const uint32_t sids_idx, uint32_t **sids, uint32_t *sids_size)
467 {
468  if (sids_idx >= *sids_size) {
469  const uint32_t old_size = *sids_size;
470  const uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
471 
472  void *ptr = SCRealloc(*sids, new_size * sizeof(uint32_t));
473  if (ptr == NULL)
474  return false;
475  *sids_size = new_size;
476  *sids = ptr;
477  }
478  return true;
479 }
480 
481 static int DetectFlowbitsAnalyzeSignature(const Signature *s, struct FBAnalyzer *fba)
482 {
483  struct FBAnalyze *array = fba->array;
484  if (array == NULL)
485  return -1;
486 
487  /* see if the signature uses stateful matching TODO is there not a flag? */
488  bool has_state = (s->init_data->buffer_index != 0);
489 
490  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
491  sm = sm->next) {
492  if (sm->type != DETECT_FLOWBITS)
493  continue;
494  /* figure out the flowbit action */
495  const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
496  // Handle flowbit array in case of ORed flowbits
497  for (uint8_t k = 0; k < fb->or_list_size; k++) {
498  struct FBAnalyze *fa = &array[fb->or_list[k]];
499  fa->cnts[fb->cmd]++;
500  fa->state_cnts[fb->cmd] += has_state;
501 
502  if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
503  if (!CheckExpand(fa->isset_sids_idx, &fa->isset_sids, &fa->isset_sids_size))
504  return -1;
505  fa->isset_sids[fa->isset_sids_idx] = s->num;
506  fa->isset_sids_idx++;
507  } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET) {
508  if (!CheckExpand(
510  return -1;
511  fa->isnotset_sids[fa->isnotset_sids_idx] = s->num;
512  fa->isnotset_sids_idx++;
513  }
514  }
515  if (fb->or_list_size == 0) {
516  struct FBAnalyze *fa = &array[fb->idx];
517  fa->cnts[fb->cmd]++;
518  fa->state_cnts[fb->cmd] += has_state;
519 
520  if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
521  if (!CheckExpand(fa->isset_sids_idx, &fa->isset_sids, &fa->isset_sids_size))
522  return -1;
523  fa->isset_sids[fa->isset_sids_idx] = s->num;
524  fa->isset_sids_idx++;
525  } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET) {
526  if (!CheckExpand(
528  return -1;
529  fa->isnotset_sids[fa->isnotset_sids_idx] = s->num;
530  fa->isnotset_sids_idx++;
531  }
532  }
533  }
534  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_POSTMATCH]; sm != NULL;
535  sm = sm->next) {
536  if (sm->type != DETECT_FLOWBITS)
537  continue;
538  /* figure out what flowbit action */
539  const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
540  struct FBAnalyze *fa = &array[fb->idx];
541  fa->cnts[fb->cmd]++;
542  fa->state_cnts[fb->cmd] += has_state;
543 
544  if (fb->cmd == DETECT_FLOWBITS_CMD_SET) {
545  if (!CheckExpand(fa->set_sids_idx, &fa->set_sids, &fa->set_sids_size))
546  return -1;
547  fa->set_sids[fa->set_sids_idx] = s->num;
548  fa->set_sids_idx++;
549  } else if (fb->cmd == DETECT_FLOWBITS_CMD_UNSET) {
550  if (!CheckExpand(fa->unset_sids_idx, &fa->unset_sids, &fa->unset_sids_size))
551  return -1;
552  fa->unset_sids[fa->unset_sids_idx] = s->num;
553  fa->unset_sids_idx++;
554  } else if (fb->cmd == DETECT_FLOWBITS_CMD_TOGGLE) {
555  if (!CheckExpand(fa->toggle_sids_idx, &fa->toggle_sids, &fa->toggle_sids_size))
556  return -1;
557  fa->toggle_sids[fa->toggle_sids_idx] = s->num;
558  fa->toggle_sids_idx++;
559  }
560  }
561  return 0;
562 }
563 
565 {
566  const uint32_t max_fb_id = de_ctx->max_fb_id;
567  if (max_fb_id == 0)
568  return 0;
569 
570  struct FBAnalyzer fba = { .array = NULL, .array_size = 0 };
571  const uint32_t array_size = max_fb_id + 1;
572  struct FBAnalyze *array = SCCalloc(array_size, sizeof(struct FBAnalyze));
573  if (array == NULL) {
574  SCLogError("Unable to allocate flowbit analyze array");
575  return -1;
576  }
577  fba.array = array;
578  fba.array_size = array_size;
579 
580  SCLogDebug("fb analyzer array size: %"PRIu64,
581  (uint64_t)(array_size * sizeof(struct FBAnalyze)));
582 
583  /* fill flowbit array, updating counters per sig */
584  for (uint32_t i = 0; i < de_ctx->sig_array_len; i++) {
585  const Signature *s = de_ctx->sig_array[i];
586 
587  int r = DetectFlowbitsAnalyzeSignature(s, &fba);
588  if (r < 0) {
589  FBAnalyzerFree(&fba);
590  return -1;
591  }
592  }
593 
594  /* walk array to see if all bits make sense */
595  for (uint32_t i = 0; i < array_size; i++) {
596  const char *varname = VarNameStoreSetupLookup(i, VAR_TYPE_FLOW_BIT);
597  if (varname == NULL)
598  continue;
599 
600  bool to_state = false;
601 
602  if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] &&
603  array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE] == 0 &&
604  array[i].cnts[DETECT_FLOWBITS_CMD_SET] == 0) {
605 
606  const Signature *s = de_ctx->sig_array[array[i].isset_sids[0]];
607  SCLogWarning("flowbit '%s' is checked but not "
608  "set. Checked in %u and %u other sigs",
609  varname, s->id, array[i].isset_sids_idx - 1);
610  }
611  if (array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] &&
612  array[i].state_cnts[DETECT_FLOWBITS_CMD_SET] == 0)
613  {
614  SCLogDebug("flowbit %s/%u: isset in state, set not in state", varname, i);
615  }
616 
617  /* if signature depends on 'stateful' flowbits, then turn the
618  * sig into a stateful sig itself */
619  if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] > 0 &&
620  array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] == 0 &&
622  {
623  SCLogDebug("flowbit %s/%u: isset not in state, set in state", varname, i);
624  to_state = true;
625  }
626 
627  SCLogDebug("ALL flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
630  array[i].cnts[DETECT_FLOWBITS_CMD_ISSET]);
631  SCLogDebug("STATE flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
635  for (uint32_t x = 0; x < array[i].set_sids_idx; x++) {
636  SCLogDebug("SET flowbit %s/%u: SID %u", varname, i,
637  de_ctx->sig_array[array[i].set_sids[x]]->id);
638  }
639  if (to_state) {
640  for (uint32_t x = 0; x < array[i].isset_sids_idx; x++) {
641  Signature *s = de_ctx->sig_array[array[i].isset_sids[x]];
642  SCLogDebug("GET flowbit %s/%u: SID %u", varname, i, s->id);
643 
646 
647  uint32_t sids_array_size = array[i].set_sids_idx;
648 
649  // save information about flowbits that affect this rule's state
650  if (s->init_data->rule_state_dependant_sids_array == NULL) {
652  SCCalloc(sids_array_size, sizeof(uint32_t));
653  if (s->init_data->rule_state_dependant_sids_array == NULL) {
654  SCLogError("Failed to allocate memory for rule_state_dependant_ids");
655  goto error;
656  }
659  SCCalloc(s->init_data->rule_state_flowbits_ids_size, sizeof(uint32_t));
660  if (s->init_data->rule_state_flowbits_ids_array == NULL) {
661  SCLogError("Failed to allocate memory for rule_state_variable_idx");
662  goto error;
663  }
664  s->init_data->rule_state_dependant_sids_size = sids_array_size;
665  SCLogDebug("alloc'ed array for rule dependency and fbs idx array, sid %u, "
666  "sizes are %u and %u",
669  } else {
670  uint32_t new_array_size =
671  s->init_data->rule_state_dependant_sids_size + sids_array_size;
673  new_array_size * sizeof(uint32_t));
674  if (tmp_ptr == NULL) {
675  SCLogError("Failed to allocate memory for rule_state_variable_idx");
676  goto error;
677  }
679  s->init_data->rule_state_dependant_sids_size = new_array_size;
680  SCLogDebug("realloc'ed array for rule dependency, sid %u, new size is %u",
682  uint32_t new_fb_array_size = s->init_data->rule_state_flowbits_ids_size + 1;
683  void *tmp_fb_ptr = SCRealloc(s->init_data->rule_state_flowbits_ids_array,
684  new_fb_array_size * sizeof(uint32_t));
685  s->init_data->rule_state_flowbits_ids_array = tmp_fb_ptr;
686  if (s->init_data->rule_state_flowbits_ids_array == NULL) {
687  SCLogError("Failed to reallocate memory for rule_state_variable_idx");
688  goto error;
689  }
690  SCLogDebug(
691  "realloc'ed array for flowbits ids, new size is %u", new_fb_array_size);
692  s->init_data->rule_state_dependant_sids_size = new_array_size;
693  s->init_data->rule_state_flowbits_ids_size = new_fb_array_size;
694  }
695  for (uint32_t idx = 0; idx < s->init_data->rule_state_dependant_sids_size; idx++) {
696  if (idx < array[i].set_sids_idx) {
699  de_ctx->sig_array[array[i].set_sids[idx]]->id;
701  }
702  }
703  s->init_data
705  1] = i;
707  // flowbit info saving for rule made stateful rule work finished
708 
709  SCLogDebug("made SID %u stateful because it depends on "
710  "stateful rules that set flowbit %s", s->id, varname);
711  }
712  }
713  }
714 
716  DetectFlowbitsAnalyzeDump(de_ctx, array, array_size);
717  }
718 
719  FBAnalyzerFree(&fba);
720  return 0;
721 error:
722  FBAnalyzerFree(&fba);
723  return -1;
724 }
725 
726 // TODO misses IPOnly rules. IPOnly flowbit rules are set only though.
727 static struct FBAnalyzer DetectFlowbitsAnalyzeForGroup(
728  const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
729 {
730  struct FBAnalyzer fba = { .array = NULL, .array_size = 0 };
731 
732  const uint32_t max_fb_id = de_ctx->max_fb_id;
733  if (max_fb_id == 0)
734  return fba;
735 
736  uint32_t array_size = max_fb_id + 1;
737  struct FBAnalyze *array = SCCalloc(array_size, sizeof(struct FBAnalyze));
738  if (array == NULL) {
739  SCLogError("Unable to allocate flowbit analyze array");
740  return fba;
741  }
742  SCLogDebug(
743  "fb analyzer array size: %" PRIu64, (uint64_t)(array_size * sizeof(struct FBAnalyze)));
744  fba.array = array;
745  fba.array_size = array_size;
746 
747  /* fill flowbit array, updating counters per sig */
748  for (uint32_t i = 0; i < sgh->init->sig_cnt; i++) {
749  const Signature *s = sgh->init->match_array[i];
750  SCLogDebug("sgh %p: s->id %u", sgh, s->id);
751 
752  int r = DetectFlowbitsAnalyzeSignature(s, &fba);
753  if (r < 0) {
754  FBAnalyzerFree(&fba);
755  return fba;
756  }
757  }
758 
759  /* walk array to see if all bits make sense */
760  for (uint32_t i = 0; i < array_size; i++) {
761  const char *varname = VarNameStoreSetupLookup(i, VAR_TYPE_FLOW_BIT);
762  if (varname == NULL)
763  continue;
764 
765  bool to_state = false;
766  if (array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] &&
767  array[i].state_cnts[DETECT_FLOWBITS_CMD_SET] == 0) {
768  SCLogDebug("flowbit %s/%u: isset in state, set not in state", varname, i);
769  }
770 
771  /* if signature depends on 'stateful' flowbits, then turn the
772  * sig into a stateful sig itself */
773  if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] > 0 &&
774  array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] == 0 &&
776  SCLogDebug("flowbit %s/%u: isset not in state, set in state", varname, i);
777  to_state = true;
778  }
779 
780  SCLogDebug("ALL flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u",
781  varname, i, array[i].cnts[DETECT_FLOWBITS_CMD_SET],
784  array[i].cnts[DETECT_FLOWBITS_CMD_ISSET]);
785  SCLogDebug("STATE flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u",
786  varname, i, array[i].state_cnts[DETECT_FLOWBITS_CMD_SET],
791  for (uint32_t x = 0; x < array[i].set_sids_idx; x++) {
792  SCLogDebug("SET flowbit %s/%u: SID %u", varname, i,
793  de_ctx->sig_array[array[i].set_sids[x]]->id);
794  }
795  for (uint32_t x = 0; x < array[i].isset_sids_idx; x++) {
796  Signature *s = de_ctx->sig_array[array[i].isset_sids[x]];
797  SCLogDebug("GET flowbit %s/%u: SID %u", varname, i, s->id);
798 
799  if (to_state) {
801  SCLogDebug("made SID %u stateful because it depends on "
802  "stateful rules that set flowbit %s",
803  s->id, varname);
804  }
805  }
806  }
807 
808  return fba;
809 }
810 
812 static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
813  struct FBAnalyze *array, uint32_t elements)
814 {
815  SCJsonBuilder *js = SCJbNewObject();
816  if (js == NULL)
817  return;
818 
819  SCJbOpenArray(js, "flowbits");
820  for (uint32_t x = 0; x < elements; x++) {
821  const char *varname = VarNameStoreSetupLookup(x, VAR_TYPE_FLOW_BIT);
822  if (varname == NULL)
823  continue;
824 
825  const struct FBAnalyze *e = &array[x];
826 
827  SCJbStartObject(js);
828  SCJbSetString(js, "name", varname);
829  SCJbSetUint(js, "internal_id", x);
830  SCJbSetUint(js, "set_cnt", e->cnts[DETECT_FLOWBITS_CMD_SET]);
831  SCJbSetUint(js, "unset_cnt", e->cnts[DETECT_FLOWBITS_CMD_UNSET]);
832  SCJbSetUint(js, "toggle_cnt", e->cnts[DETECT_FLOWBITS_CMD_TOGGLE]);
833  SCJbSetUint(js, "isset_cnt", e->cnts[DETECT_FLOWBITS_CMD_ISSET]);
834  SCJbSetUint(js, "isnotset_cnt", e->cnts[DETECT_FLOWBITS_CMD_ISNOTSET]);
835 
836  // sets
837  if (e->cnts[DETECT_FLOWBITS_CMD_SET]) {
838  SCJbOpenArray(js, "sets");
839  for (uint32_t i = 0; i < e->set_sids_idx; i++) {
840  const Signature *s = de_ctx->sig_array[e->set_sids[i]];
841  SCJbAppendUint(js, s->id);
842  }
843  SCJbClose(js);
844  }
845  // gets
847  SCJbOpenArray(js, "isset");
848  for (uint32_t i = 0; i < e->isset_sids_idx; i++) {
849  const Signature *s = de_ctx->sig_array[e->isset_sids[i]];
850  SCJbAppendUint(js, s->id);
851  }
852  SCJbClose(js);
853  }
854  // isnotset
856  SCJbOpenArray(js, "isnotset");
857  for (uint32_t i = 0; i < e->isnotset_sids_idx; i++) {
858  const Signature *s = de_ctx->sig_array[e->isnotset_sids[i]];
859  SCJbAppendUint(js, s->id);
860  }
861  SCJbClose(js);
862  }
863  // unset
865  SCJbOpenArray(js, "unset");
866  for (uint32_t i = 0; i < e->unset_sids_idx; i++) {
867  const Signature *s = de_ctx->sig_array[e->unset_sids[i]];
868  SCJbAppendUint(js, s->id);
869  }
870  SCJbClose(js);
871  }
872  // toggle
874  SCJbOpenArray(js, "toggle");
875  for (uint32_t i = 0; i < e->toggle_sids_idx; i++) {
876  const Signature *s = de_ctx->sig_array[e->toggle_sids[i]];
877  SCJbAppendUint(js, s->id);
878  }
879  SCJbClose(js);
880  }
881  SCJbClose(js);
882  }
883  SCJbClose(js); // array
884  SCJbClose(js); // object
885 
886  const char *filename = "flowbits.json";
887  const char *log_dir = SCConfigGetLogDirectory();
888  char log_path[PATH_MAX] = "";
889  snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, filename);
890 
892  FILE *fp = fopen(log_path, "w");
893  if (fp != NULL) {
894  fwrite(SCJbPtr(js), SCJbLen(js), 1, fp);
895  fprintf(fp, "\n");
896  fclose(fp);
897  }
899 
900  SCJbFree(js);
901 }
902 
903 static bool PrefilterFlowbitIsPrefilterable(const Signature *s)
904 {
905  SCLogDebug("sid:%u: checking", s->id);
906 
907  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
908  sm = sm->next) {
909  switch (sm->type) {
910  case DETECT_FLOWBITS: {
911  const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
912  if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
913  SCLogDebug("sid:%u: FLOWBITS ISSET can prefilter", s->id);
914  return true;
915  }
916  break;
917  }
918  }
919  }
920  SCLogDebug("sid:%u: no flowbit prefilter", s->id);
921  return false;
922 }
923 
924 /** core flowbit data structure: map a flowbit id to the signatures that need inspecting after it is
925  * found. Part of a rb-tree. */
926 typedef struct PrefilterFlowbit {
927  uint32_t id; /**< flowbit id */
928  uint32_t rule_id_size; /**< size in elements of `rule_id` */
929  uint32_t rule_id_cnt; /**< usage in elements of `rule_id` */
930  uint32_t *rule_id; /**< array of signature iid that are part of this prefilter */
931  RB_ENTRY(PrefilterFlowbit) __attribute__((__packed__)) rb;
932 } __attribute__((__packed__)) PrefilterFlowbit;
933 
934 static int PrefilterFlowbitCompare(const PrefilterFlowbit *a, const PrefilterFlowbit *b)
935 {
936  if (a->id > b->id)
937  return 1;
938  else if (a->id < b->id)
939  return -1;
940  else
941  return 0;
942 }
943 
944 /** red-black tree prototype for PFB (Prefilter Flow Bits) */
946 RB_PROTOTYPE(PFB, PrefilterFlowbit, rb, PrefilterFlowbitCompare);
947 RB_GENERATE(PFB, PrefilterFlowbit, rb, PrefilterFlowbitCompare);
948 
950  struct PFB fb_tree;
951 };
952 
953 static void PrefilterFlowbitFree(void *vctx)
954 {
955  struct PrefilterEngineFlowbits *ctx = vctx;
956  struct PrefilterFlowbit *rec, *safe = NULL;
957  RB_FOREACH_SAFE (rec, PFB, &ctx->fb_tree, safe) {
958  PFB_RB_REMOVE(&ctx->fb_tree, rec);
959  SCFree(rec->rule_id);
960  SCFree(rec);
961  }
962 
963  SCFree(ctx);
964 }
965 
966 static void PrefilterFlowbitMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
967 {
968  struct PrefilterEngineFlowbits *ctx = (struct PrefilterEngineFlowbits *)pectx;
969  SCLogDebug("%" PRIu64 ": ctx %p", p->pcap_cnt, ctx);
970 
971  if (p->flow == NULL) {
972  SCReturn;
973  }
974 
975  for (GenericVar *gv = p->flow->flowvar; gv != NULL; gv = gv->next) {
976  if (gv->type != DETECT_FLOWBITS)
977  continue;
978 
979  PrefilterFlowbit lookup;
980  memset(&lookup, 0, sizeof(lookup));
981  lookup.id = gv->idx;
982  SCLogDebug("flowbit %u", gv->idx);
983 
984  PrefilterFlowbit *b = PFB_RB_FIND(&ctx->fb_tree, &lookup);
985  if (b == NULL) {
986  SCLogDebug("flowbit %u not in the tree", lookup.id);
987  } else {
988  SCLogDebug("flowbit %u found in the tree: %u", lookup.id, b->id);
989 
990  PrefilterAddSids(&det_ctx->pmq, b->rule_id, b->rule_id_cnt);
991 #ifdef DEBUG
992  for (uint32_t x = 0; x < b->rule_id_cnt; x++) {
993  const Signature *s = det_ctx->de_ctx->sig_array[b->rule_id[x]];
994  SCLogDebug("flowbit %u -> sig %u", gv->idx, s->id);
995  }
996 #endif
997  }
998  }
999 }
1000 
1001 static void PrefilterFlowbitPostRuleMatch(
1002  DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f)
1003 {
1004  struct PrefilterEngineFlowbits *ctx = (struct PrefilterEngineFlowbits *)pectx;
1005  SCLogDebug("%" PRIu64 ": ctx %p", p->pcap_cnt, ctx);
1006 
1007  if (p->flow == NULL) {
1008  SCReturn;
1009  }
1010 
1011  for (uint32_t i = 0; i < det_ctx->post_rule_work_queue.len; i++) {
1012  const PostRuleMatchWorkQueueItem *w = &det_ctx->post_rule_work_queue.q[i];
1013  if (w->sm_type != DETECT_FLOWBITS)
1014  continue;
1015 
1016  PrefilterFlowbit lookup;
1017  memset(&lookup, 0, sizeof(lookup));
1018  lookup.id = w->value;
1019 
1020  PrefilterFlowbit *b = PFB_RB_FIND(&ctx->fb_tree, &lookup);
1021  if (b == NULL) {
1022  SCLogDebug("flowbit %u not in the tree", lookup.id);
1023  } else {
1024  SCLogDebug("flowbit %u found in the tree: %u. Adding %u sids", lookup.id, b->id,
1025  b->rule_id_cnt);
1026  PrefilterAddSids(&det_ctx->pmq, b->rule_id, b->rule_id_cnt);
1027 #ifdef DEBUG
1028  // SCLogDebug("b %u", b->rule_id_cnt);
1029  for (uint32_t x = 0; x < b->rule_id_cnt; x++) {
1030  Signature *s = det_ctx->de_ctx->sig_array[b->rule_id[x]];
1031  SCLogDebug("flowbit %u -> sig %u (triggered by %u)", w->value, s->id,
1032  det_ctx->de_ctx->sig_array[w->id]->id);
1033  }
1034 #endif
1035  }
1036  }
1037 }
1038 
1039 #define BLOCK_SIZE 8
1041 static int AddBitAndSid(
1042  struct PrefilterEngineFlowbits *ctx, const Signature *s, const uint32_t flowbit_id)
1043 {
1044  PrefilterFlowbit x;
1045  memset(&x, 0, sizeof(x));
1046  x.id = flowbit_id;
1047 
1048  PrefilterFlowbit *pfb = PFB_RB_FIND(&ctx->fb_tree, &x);
1049  if (pfb == NULL) {
1050  PrefilterFlowbit *add = SCCalloc(1, sizeof(*add));
1051  if (add == NULL)
1052  return -1;
1053 
1054  add->id = flowbit_id;
1055  add->rule_id = SCCalloc(1, BLOCK_SIZE * sizeof(uint32_t));
1056  if (add->rule_id == NULL) {
1057  SCFree(add);
1058  return -1;
1059  }
1060  add->rule_id_size = BLOCK_SIZE;
1061  add->rule_id_cnt = 1;
1062  add->rule_id[0] = s->num;
1063 
1064  PrefilterFlowbit *res = PFB_RB_INSERT(&ctx->fb_tree, add);
1065  SCLogDebug("not found, so added (res %p)", res);
1066  if (res != NULL) {
1067  // duplicate, shouldn't be possible after the FIND above
1068  BUG_ON(1);
1069  return -1;
1070  }
1071  } else {
1072  SCLogDebug("found! pfb %p id %u", pfb, pfb->id);
1073 
1074  if (pfb->rule_id_cnt < pfb->rule_id_size) {
1075  pfb->rule_id[pfb->rule_id_cnt++] = s->num;
1076  } else {
1077  uint32_t *ptr =
1078  SCRealloc(pfb->rule_id, (pfb->rule_id_size + BLOCK_SIZE) * sizeof(uint32_t));
1079  if (ptr == NULL) {
1080  // memory stays in the tree
1081  return -1;
1082  }
1083  pfb->rule_id = ptr;
1084  pfb->rule_id_size += BLOCK_SIZE;
1085  pfb->rule_id[pfb->rule_id_cnt++] = s->num;
1086  }
1087  }
1088  return 0;
1089 }
1090 
1091 static int AddBitsAndSid(const DetectEngineCtx *de_ctx, struct PrefilterEngineFlowbits *ctx,
1092  const DetectFlowbitsData *fb, const Signature *s)
1093 {
1094  if (fb->or_list_size == 0) {
1095  if (AddBitAndSid(ctx, s, fb->idx) < 0) {
1096  return -1;
1097  }
1098  } else {
1099  for (uint8_t i = 0; i < fb->or_list_size; i++) {
1100  SCLogDebug("flowbit OR: bit %u", fb->or_list[i]);
1101  if (AddBitAndSid(ctx, s, fb->or_list[i]) < 0) {
1102  return -1;
1103  }
1104  }
1105  }
1106  return 0;
1107 }
1108 
1109 static uint32_t NextMultiple(const uint32_t v, const uint32_t m)
1110 {
1111  return v + (m - v % m);
1112 }
1113 
1114 /** \internal
1115  * \brief adds sids for 'isset' prefilter flowbits
1116  * \retval int 1 if we added sid(s), 0 if we didn't, -1 on error */
1117 // TODO skip sids that aren't set by this sgh
1118 // TODO skip sids that doesn't have a isset in the same direction
1119 static int AddIssetSidsForBit(const DetectEngineCtx *de_ctx, const struct FBAnalyzer *fba,
1120  const DetectFlowbitsData *fb, PrefilterFlowbit *add)
1121 {
1122  int added = 0;
1123  for (uint32_t i = 0; i < fba->array[fb->idx].isset_sids_idx; i++) {
1124  const uint32_t sig_iid = fba->array[fb->idx].isset_sids[i];
1125  const Signature *s = de_ctx->sig_array[sig_iid];
1126  SCLogDebug("flowbit: %u => considering sid %u (iid:%u)", fb->idx, s->id, s->num);
1127 
1128  /* Skip sids that aren't prefilter. These would just run all the time. */
1129  if (s->init_data->prefilter_sm == NULL ||
1131 #ifdef DEBUG
1132  const char *name = s->init_data->prefilter_sm
1134  : "none";
1135  SCLogDebug("flowbit: %u => rejected sid %u (iid:%u). No prefilter or prefilter not "
1136  "flowbits (%p, %s, %d)",
1137  fb->idx, s->id, sig_iid, s->init_data->prefilter_sm, name,
1139 #endif
1140  continue;
1141  }
1142 
1143  /* only add sids that match our bit */
1144  const DetectFlowbitsData *fs_fb =
1146  if (fs_fb->idx != fb->idx) {
1147  SCLogDebug(
1148  "flowbit: %u => rejected sid %u (iid:%u). Sig prefilters on different bit %u",
1149  fb->idx, s->id, sig_iid, fs_fb->idx);
1150  continue;
1151  }
1152 
1153  bool dup = false;
1154  for (uint32_t x = 0; x < add->rule_id_cnt; x++) {
1155  if (add->rule_id[x] == sig_iid) {
1156  dup = true;
1157  }
1158  }
1159 
1160  if (!dup) {
1161  if (add->rule_id_cnt < add->rule_id_size) {
1162  add->rule_id[add->rule_id_cnt++] = sig_iid;
1163  } else {
1164  uint32_t *ptr = SCRealloc(
1165  add->rule_id, (add->rule_id_size + BLOCK_SIZE) * sizeof(uint32_t));
1166  if (ptr == NULL) {
1167  return -1;
1168  }
1169  add->rule_id = ptr;
1170  add->rule_id_size += BLOCK_SIZE;
1171  add->rule_id[add->rule_id_cnt++] = sig_iid;
1172  }
1173  added = 1;
1174  SCLogDebug("flowbit: %u => accepted sid %u (iid:%u)", fb->idx, s->id, sig_iid);
1175  }
1176  }
1177  return added;
1178 }
1179 
1180 /* TODO shouldn't add sids for which Signature::num is < our num. Is this possible after sorting? */
1181 
1182 /** \brief For set/toggle flowbits, build "set" post-rule-match engine
1183  *
1184  * For set/toggle flowbits, a special post-rule-match engine is constructed
1185  * to update the running match array during rule matching.
1186  */
1187 static int AddBitSetToggle(const DetectEngineCtx *de_ctx, struct FBAnalyzer *fba,
1188  struct PrefilterEngineFlowbits *ctx, const DetectFlowbitsData *fb, const Signature *s)
1189 {
1190  PrefilterFlowbit x;
1191  memset(&x, 0, sizeof(x));
1192  x.id = fb->idx;
1193  PrefilterFlowbit *pfb = PFB_RB_FIND(&ctx->fb_tree, &x);
1194  if (pfb == NULL) {
1195  PrefilterFlowbit *add = SCCalloc(1, sizeof(*add));
1196  if (add == NULL)
1197  return -1;
1198 
1199  add->id = fb->idx;
1200  add->rule_id_size = NextMultiple(fba->array[fb->idx].isset_sids_idx, BLOCK_SIZE);
1201  add->rule_id = SCCalloc(1, add->rule_id_size * sizeof(uint32_t));
1202  if (add->rule_id == NULL) {
1203  SCFree(add);
1204  return -1;
1205  }
1206 
1207  if (AddIssetSidsForBit(de_ctx, fba, fb, add) != 1) {
1208  SCLogDebug("no sids added");
1209  SCFree(add->rule_id);
1210  SCFree(add);
1211  return 0;
1212  }
1213  PrefilterFlowbit *res = PFB_RB_INSERT(&ctx->fb_tree, add);
1214  SCLogDebug("not found, so added (res %p)", res);
1215  BUG_ON(res != NULL); // TODO if res != NULL we have a duplicate which should be impossible
1216  } else {
1217  SCLogDebug("found! pfb %p id %u", pfb, pfb->id);
1218 
1219  int r = AddIssetSidsForBit(de_ctx, fba, fb, pfb);
1220  if (r < 0) {
1221  return -1;
1222  } else if (r == 0) {
1223  SCLogDebug("no sids added");
1224  return 0;
1225  }
1226  }
1227  return 1;
1228 }
1229 
1230 /** \brief build flowbit prefilter state(s)
1231  *
1232  * Build "set" and "isset" states.
1233  *
1234  * For each flowbit "isset" in the sgh, we need to check:
1235  * 1. is it supported
1236  * 2. is prefilter enabled
1237  * 3. does it match in the same dir or only opposing dir
1238  */
1239 static int PrefilterSetupFlowbits(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
1240 {
1241  if (sgh == NULL)
1242  return 0;
1243 
1244  SCLogDebug("sgh %p: setting up prefilter", sgh);
1245  struct PrefilterEngineFlowbits *isset_ctx = NULL;
1246  struct PrefilterEngineFlowbits *set_ctx = NULL;
1247 
1248  struct FBAnalyzer fb_analysis = DetectFlowbitsAnalyzeForGroup(de_ctx, sgh);
1249  if (fb_analysis.array == NULL)
1250  goto error;
1251 
1252  for (uint32_t i = 0; i < sgh->init->sig_cnt; i++) {
1253  Signature *s = sgh->init->match_array[i];
1254  if (s == NULL)
1255  continue;
1256 
1257  SCLogDebug("checking sid %u", s->id);
1258 
1259  /* first build the 'set' state */
1260  for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_POSTMATCH]; sm != NULL;
1261  sm = sm->next) {
1262  if (sm->type != DETECT_FLOWBITS) {
1263  SCLogDebug("skip non flowbits sm");
1264  continue;
1265  }
1266 
1267  DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
1268  if (fb->cmd == DETECT_FLOWBITS_CMD_SET) {
1269  SCLogDebug(
1270  "DETECT_SM_LIST_POSTMATCH: sid %u DETECT_FLOWBITS set %u", s->id, fb->idx);
1271  } else if (fb->cmd == DETECT_FLOWBITS_CMD_TOGGLE) {
1272  SCLogDebug("DETECT_SM_LIST_POSTMATCH: sid %u DETECT_FLOWBITS toggle %u", s->id,
1273  fb->idx);
1274  } else {
1275  SCLogDebug("unsupported flowbits setting");
1276  continue;
1277  }
1278 
1279  if (fb_analysis.array[fb->idx].isnotset_sids_idx ||
1280  fb_analysis.array[fb->idx].unset_sids_idx) {
1281  SCLogDebug("flowbit %u not supported: unset in use", fb->idx);
1282  continue;
1283  }
1284 
1285  if (set_ctx == NULL) {
1286  set_ctx = SCCalloc(1, sizeof(*set_ctx));
1287  if (set_ctx == NULL)
1288  goto error;
1289  }
1290 
1291  SCLogDebug("setting up sets/toggles for sid %u", s->id);
1292  if (AddBitSetToggle(de_ctx, &fb_analysis, set_ctx, fb, s) == 1) {
1293  // flag the set/toggle to trigger the post-rule match logic
1294  SCLogDebug("set up sets/toggles for sid %u", s->id);
1295  fb->post_rule_match_prefilter = true;
1296  }
1297 
1298  // TODO don't add for sigs that don't have isset in this sgh. Reasoning:
1299  // prefilter post match logic only makes sense in the same dir as otherwise
1300  // the regular 'isset' logic can simply run with the regular prefilters
1301  // before the rule loop
1302  }
1303 
1304  /* next, build the 'isset' state */
1305  if (s->init_data->prefilter_sm == NULL ||
1307  SCLogDebug("no prefilter or prefilter not flowbits");
1308  continue;
1309  }
1310 
1312  if (fb_analysis.array[fb->idx].isnotset_sids_idx ||
1313  fb_analysis.array[fb->idx].unset_sids_idx) {
1314  SCLogDebug("flowbit %u not supported: toggle or unset in use", fb->idx);
1315  s->init_data->prefilter_sm = NULL;
1316  s->flags &= ~SIG_FLAG_PREFILTER;
1317  continue;
1318  }
1319 
1320  SCLogDebug("isset: adding sid %u, flowbit %u", s->id, fb->idx);
1321 
1322  if (isset_ctx == NULL) {
1323  isset_ctx = SCCalloc(1, sizeof(*isset_ctx));
1324  if (isset_ctx == NULL)
1325  goto error;
1326  }
1327  if (AddBitsAndSid(de_ctx, isset_ctx, fb, s) < 0) {
1328  goto error;
1329  }
1330  }
1331 
1332  /* finally, register the states with their engines */
1333  static const char *g_prefilter_flowbits_isset = "flowbits:isset";
1334  if (isset_ctx != NULL) {
1335  enum SignatureHookPkt hook = SIGNATURE_HOOK_PKT_NOT_SET; // TODO review
1336  PrefilterAppendEngine(de_ctx, sgh, PrefilterFlowbitMatch, SIG_MASK_REQUIRE_FLOW, hook,
1337  isset_ctx, PrefilterFlowbitFree, g_prefilter_flowbits_isset);
1338  SCLogDebug("isset: added prefilter engine");
1339 
1340  if (set_ctx != NULL && !RB_EMPTY(&set_ctx->fb_tree)) {
1341  static const char *g_prefilter_flowbits_set = "flowbits:set";
1342  PrefilterAppendPostRuleEngine(de_ctx, sgh, PrefilterFlowbitPostRuleMatch, set_ctx,
1343  PrefilterFlowbitFree, g_prefilter_flowbits_set);
1344  SCLogDebug("set/toggle: added prefilter engine");
1345  } else {
1346  if (set_ctx) {
1347  PrefilterFlowbitFree(set_ctx);
1348  }
1349  SCLogDebug("set/toggle: NO prefilter engine added");
1350  }
1351  } else if (set_ctx != NULL) {
1352  PrefilterFlowbitFree(set_ctx);
1353  }
1354  FBAnalyzerFree(&fb_analysis);
1355  return 0;
1356 
1357 error:
1358  if (set_ctx) {
1359  PrefilterFlowbitFree(set_ctx);
1360  }
1361  if (isset_ctx) {
1362  PrefilterFlowbitFree(isset_ctx);
1363  }
1364  FBAnalyzerFree(&fb_analysis);
1365  return -1;
1366 }
1367 
1368 #ifdef UNITTESTS
1369 
1370 static int FlowBitsTestParse01(void)
1371 {
1372  char command[16] = "", name[16] = "";
1373 
1374  /* Single argument version. */
1375  FAIL_IF(!DetectFlowbitParse("noalert", command, sizeof(command), name,
1376  sizeof(name)));
1377  FAIL_IF(strcmp(command, "noalert") != 0);
1378 
1379  /* No leading or trailing spaces. */
1380  FAIL_IF(!DetectFlowbitParse("set,flowbit", command, sizeof(command), name,
1381  sizeof(name)));
1382  FAIL_IF(strcmp(command, "set") != 0);
1383  FAIL_IF(strcmp(name, "flowbit") != 0);
1384 
1385  /* Leading space. */
1386  FAIL_IF(!DetectFlowbitParse("set, flowbit", command, sizeof(command), name,
1387  sizeof(name)));
1388  FAIL_IF(strcmp(command, "set") != 0);
1389  FAIL_IF(strcmp(name, "flowbit") != 0);
1390 
1391  /* Trailing space. */
1392  FAIL_IF(!DetectFlowbitParse("set,flowbit ", command, sizeof(command), name,
1393  sizeof(name)));
1394  FAIL_IF(strcmp(command, "set") != 0);
1395  FAIL_IF(strcmp(name, "flowbit") != 0);
1396 
1397  /* Leading and trailing space. */
1398  FAIL_IF(!DetectFlowbitParse("set, flowbit ", command, sizeof(command), name,
1399  sizeof(name)));
1400  FAIL_IF(strcmp(command, "set") != 0);
1401  FAIL_IF(strcmp(name, "flowbit") != 0);
1402 
1403  /* Spaces are not allowed in the name. */
1404  FAIL_IF(DetectFlowbitParse("set,namewith space", command, sizeof(command),
1405  name, sizeof(name)));
1406 
1407  PASS;
1408 }
1409 
1410 /**
1411  * \test FlowBitsTestSig01 is a test for a valid noalert flowbits option
1412  *
1413  * \retval 1 on success
1414  * \retval 0 on failure
1415  */
1416 
1417 static int FlowBitsTestSig01(void)
1418 {
1419  Signature *s = NULL;
1420  DetectEngineCtx *de_ctx = NULL;
1421 
1424 
1425  de_ctx->flags |= DE_QUIET;
1426 
1427  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)");
1428  FAIL_IF_NOT_NULL(s);
1429 
1432  PASS;
1433 }
1434 
1435 /**
1436  * \test FlowBitsTestSig02 is a test for a valid isset,set,isnotset,unset,toggle flowbits options
1437  *
1438  * \retval 1 on success
1439  * \retval 0 on failure
1440  */
1441 
1442 static int FlowBitsTestSig02(void)
1443 {
1444  Signature *s = NULL;
1445  ThreadVars th_v;
1446  DetectEngineCtx *de_ctx = NULL;
1447 
1448  memset(&th_v, 0, sizeof(th_v));
1449 
1452 
1453  de_ctx->flags |= DE_QUIET;
1454 
1455  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;)");
1456  FAIL_IF_NOT_NULL(s);
1457 
1458  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;)");
1459  FAIL_IF_NOT_NULL(s);
1460 
1461  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;)");
1462  FAIL_IF_NOT_NULL(s);
1463 
1464  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;)");
1465  FAIL_IF_NOT_NULL(s);
1466 
1467  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;)");
1468  FAIL_IF_NOT_NULL(s);
1469 
1470  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;)");
1471  FAIL_IF_NOT_NULL(s);
1472 
1475 
1476  PASS;
1477 }
1478 
1479 /**
1480  * \test FlowBitsTestSig03 is a test for a invalid flowbits option
1481  *
1482  * \retval 1 on success
1483  * \retval 0 on failure
1484  */
1485 
1486 static int FlowBitsTestSig03(void)
1487 {
1488  Signature *s = NULL;
1489  DetectEngineCtx *de_ctx = NULL;
1490 
1493 
1494  de_ctx->flags |= DE_QUIET;
1495 
1496  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)");
1497  FAIL_IF_NOT_NULL(s);
1498 
1501  PASS;
1502 }
1503 
1504 /**
1505  * \test FlowBitsTestSig04 is a test check idx value
1506  *
1507  * \retval 1 on success
1508  * \retval 0 on failure
1509  */
1510 
1511 static int FlowBitsTestSig04(void)
1512 {
1513  Signature *s = NULL;
1514  DetectEngineCtx *de_ctx = NULL;
1515  int idx = 0;
1518 
1519  de_ctx->flags |= DE_QUIET;
1520 
1521  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)");
1522  FAIL_IF_NULL(s);
1523 
1525  FAIL_IF(idx == 0);
1526 
1529  PASS;
1530 }
1531 
1532 /**
1533  * \test FlowBitsTestSig05 is a test check noalert flag
1534  *
1535  * \retval 1 on success
1536  * \retval 0 on failure
1537  */
1538 
1539 static int FlowBitsTestSig05(void)
1540 {
1541  Signature *s = NULL;
1542  DetectEngineCtx *de_ctx = NULL;
1543 
1546 
1547  de_ctx->flags |= DE_QUIET;
1548 
1549  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)");
1550  FAIL_IF_NULL(s);
1551  FAIL_IF((s->action & ACTION_ALERT) != 0);
1552 
1555  PASS;
1556 }
1557 
1558 /**
1559  * \test FlowBitsTestSig06 is a test set flowbits option
1560  *
1561  * \retval 1 on success
1562  * \retval 0 on failure
1563  */
1564 
1565 static int FlowBitsTestSig06(void)
1566 {
1567  uint8_t *buf = (uint8_t *)
1568  "GET /one/ HTTP/1.1\r\n"
1569  "Host: one.example.org\r\n"
1570  "\r\n";
1571  uint16_t buflen = strlen((char *)buf);
1572  Packet *p = PacketGetFromAlloc();
1573  FAIL_IF_NULL(p);
1574  Signature *s = NULL;
1575  ThreadVars th_v;
1576  DetectEngineThreadCtx *det_ctx = NULL;
1577  DetectEngineCtx *de_ctx = NULL;
1578  Flow f;
1579  GenericVar flowvar, *gv = NULL;
1580  int result = 0;
1581  uint32_t idx = 0;
1582 
1583  memset(&th_v, 0, sizeof(th_v));
1584  memset(&f, 0, sizeof(Flow));
1585  memset(&flowvar, 0, sizeof(GenericVar));
1586 
1587  FLOW_INITIALIZE(&f);
1588  p->flow = &f;
1589  p->flow->flowvar = &flowvar;
1590 
1591  p->src.family = AF_INET;
1592  p->dst.family = AF_INET;
1593  p->payload = buf;
1594  p->payload_len = buflen;
1595  p->proto = IPPROTO_TCP;
1596  p->flags |= PKT_HAS_FLOW;
1598 
1601 
1602  de_ctx->flags |= DE_QUIET;
1603 
1604  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)");
1605  FAIL_IF_NULL(s);
1606 
1607  idx = VarNameStoreRegister("myflow", VAR_TYPE_FLOW_BIT);
1609  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1610 
1611  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1612 
1613  gv = p->flow->flowvar;
1614  FAIL_IF_NULL(gv);
1615  for ( ; gv != NULL; gv = gv->next) {
1616  if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1617  result = 1;
1618  }
1619  }
1620  FAIL_IF_NOT(result);
1621 
1622  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1624 
1625  FLOW_DESTROY(&f);
1626 
1627  SCFree(p);
1628  PASS;
1629 }
1630 
1631 /**
1632  * \test FlowBitsTestSig07 is a test unset flowbits option
1633  *
1634  * \retval 1 on success
1635  * \retval 0 on failure
1636  */
1637 
1638 static int FlowBitsTestSig07(void)
1639 {
1640  uint8_t *buf = (uint8_t *)
1641  "GET /one/ HTTP/1.1\r\n"
1642  "Host: one.example.org\r\n"
1643  "\r\n";
1644  uint16_t buflen = strlen((char *)buf);
1645  Packet *p = PacketGetFromAlloc();
1646  FAIL_IF_NULL(p);
1647  Signature *s = NULL;
1648  ThreadVars th_v;
1649  DetectEngineThreadCtx *det_ctx = NULL;
1650  DetectEngineCtx *de_ctx = NULL;
1651  Flow f;
1652  GenericVar flowvar, *gv = NULL;
1653  int result = 0;
1654  uint32_t idx = 0;
1655 
1656  memset(&th_v, 0, sizeof(th_v));
1657  memset(&f, 0, sizeof(Flow));
1658  memset(&flowvar, 0, sizeof(GenericVar));
1659 
1660  FLOW_INITIALIZE(&f);
1661  p->flow = &f;
1662  p->flow->flowvar = &flowvar;
1663 
1664  p->src.family = AF_INET;
1665  p->dst.family = AF_INET;
1666  p->payload = buf;
1667  p->payload_len = buflen;
1668  p->proto = IPPROTO_TCP;
1669 
1672 
1673  de_ctx->flags |= DE_QUIET;
1674 
1675  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)");
1676  FAIL_IF_NULL(s);
1677 
1678  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)");
1679  FAIL_IF_NULL(s);
1680 
1681  idx = VarNameStoreRegister("myflow", VAR_TYPE_FLOW_BIT);
1683  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1684 
1685  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1686 
1687  gv = p->flow->flowvar;
1688  FAIL_IF_NULL(gv);
1689 
1690  for ( ; gv != NULL; gv = gv->next) {
1691  if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1692  result = 1;
1693  }
1694  }
1695  FAIL_IF(result);
1696 
1697  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1699 
1700  FLOW_DESTROY(&f);
1701 
1702  SCFree(p);
1703  PASS;
1704 }
1705 
1706 /**
1707  * \test FlowBitsTestSig08 is a test toggle flowbits option
1708  *
1709  * \retval 1 on success
1710  * \retval 0 on failure
1711  */
1712 
1713 static int FlowBitsTestSig08(void)
1714 {
1715  uint8_t *buf = (uint8_t *)
1716  "GET /one/ HTTP/1.1\r\n"
1717  "Host: one.example.org\r\n"
1718  "\r\n";
1719  uint16_t buflen = strlen((char *)buf);
1720  Packet *p = PacketGetFromAlloc();
1721  if (unlikely(p == NULL))
1722  return 0;
1723  Signature *s = NULL;
1724  ThreadVars th_v;
1725  DetectEngineThreadCtx *det_ctx = NULL;
1726  DetectEngineCtx *de_ctx = NULL;
1727  Flow f;
1728  GenericVar flowvar, *gv = NULL;
1729  int result = 0;
1730  uint32_t idx = 0;
1731 
1732  memset(&th_v, 0, sizeof(th_v));
1733  memset(&f, 0, sizeof(Flow));
1734  memset(&flowvar, 0, sizeof(GenericVar));
1735 
1736  FLOW_INITIALIZE(&f);
1737  p->flow = &f;
1738  p->flow->flowvar = &flowvar;
1739 
1740  p->src.family = AF_INET;
1741  p->dst.family = AF_INET;
1742  p->payload = buf;
1743  p->payload_len = buflen;
1744  p->proto = IPPROTO_TCP;
1745 
1748 
1749  de_ctx->flags |= DE_QUIET;
1750 
1751  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)");
1752  FAIL_IF_NULL(s);
1753 
1754  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:toggle,myflow2; sid:11;)");
1755  FAIL_IF_NULL(s);
1756 
1757  idx = VarNameStoreRegister("myflow", VAR_TYPE_FLOW_BIT);
1759  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1760 
1761  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1762 
1763  gv = p->flow->flowvar;
1764  FAIL_IF_NULL(gv);
1765 
1766  for ( ; gv != NULL; gv = gv->next) {
1767  if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1768  result = 1;
1769  }
1770  }
1771  FAIL_IF(result);
1772 
1773  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1775 
1776  FLOW_DESTROY(&f);
1777 
1778  SCFree(p);
1779  PASS;
1780 }
1781 
1782 /**
1783  * \brief this function registers unit tests for FlowBits
1784  */
1786 {
1787  UtRegisterTest("FlowBitsTestParse01", FlowBitsTestParse01);
1788  UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01);
1789  UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02);
1790  UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03);
1791  UtRegisterTest("FlowBitsTestSig04", FlowBitsTestSig04);
1792  UtRegisterTest("FlowBitsTestSig05", FlowBitsTestSig05);
1793  UtRegisterTest("FlowBitsTestSig06", FlowBitsTestSig06);
1794  UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07);
1795  UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08);
1796 }
1797 #endif /* UNITTESTS */
FBAnalyze::cnts
uint16_t cnts[DETECT_FLOWBITS_CMD_MAX]
Definition: detect-flowbits.c:414
SignatureInitData_::rule_state_dependant_sids_idx
uint32_t rule_state_dependant_sids_idx
Definition: detect.h:660
FBAnalyze::isset_sids
uint32_t * isset_sids
Definition: detect-flowbits.c:421
SigTableElmt_::url
const char * url
Definition: detect.h:1405
Packet_::proto
uint8_t proto
Definition: decode.h:506
FBAnalyze::isnotset_sids_idx
uint32_t isnotset_sids_idx
Definition: detect-flowbits.c:426
g_flowbits_dump_write_m
SCMutex g_flowbits_dump_write_m
Definition: detect-flowbits.c:811
DetectFlowbitsData_::or_list_size
uint8_t or_list_size
Definition: detect-flowbits.h:38
detect-engine.h
PrefilterFlowbit::rule_id_cnt
uint32_t rule_id_cnt
Definition: detect-flowbits.c:929
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
SignatureInitData_::smlists
struct SigMatch_ * smlists[DETECT_SM_LIST_MAX]
Definition: detect.h:643
DETECT_FLOWBITS_CMD_MAX
#define DETECT_FLOWBITS_CMD_MAX
Definition: detect-flowbits.h:33
SigTableElmt_::desc
const char * desc
Definition: detect.h:1404
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:155
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1242
PostRuleMatchWorkQueueAppend
void PostRuleMatchWorkQueueAppend(DetectEngineThreadCtx *det_ctx, const Signature *s, const int type, const uint32_t value)
Definition: detect-engine-prefilter.c:1693
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1392
flow-util.h
DetectParseRegex
Definition: detect-parse.h:62
PostRuleMatchWorkQueue::len
uint32_t len
Definition: detect.h:1190
PostRuleMatchWorkQueueItem::sm_type
int sm_type
Definition: detect.h:1179
SigTableElmt_::name
const char * name
Definition: detect.h:1402
PrefilterFlowbit::id
uint32_t id
Definition: detect-flowbits.c:927
Signature_::num
SigIntId num
Definition: detect.h:681
SigGroupHead_
Container for matching data for a signature group.
Definition: detect.h:1570
FBAnalyze::isnotset_sids
uint32_t * isnotset_sids
Definition: detect-flowbits.c:425
FlowBitsRegisterTests
void FlowBitsRegisterTests(void)
this function registers unit tests for FlowBits
Definition: detect-flowbits.c:1785
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
PostRuleMatchWorkQueueItem
Definition: detect.h:1178
MAX_SIDS
#define MAX_SIDS
Definition: detect-flowbits.c:465
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:431
MAX_TOKENS
#define MAX_TOKENS
Definition: detect-flowbits.c:57
SignatureInitData_::prefilter_sm
SigMatch * prefilter_sm
Definition: detect.h:626
SignatureInitData_::is_rule_state_dependant
bool is_rule_state_dependant
Definition: detect.h:657
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:609
PrefilterEngineFlowbits::fb_tree
struct PFB fb_tree
Definition: detect-flowbits.c:950
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
DETECT_FLOWBITS_CMD_ISNOTSET
#define DETECT_FLOWBITS_CMD_ISNOTSET
Definition: detect-flowbits.h:31
Packet_::payload
uint8_t * payload
Definition: decode.h:588
action-globals.h
PrefilterAppendEngine
int PrefilterAppendEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterPktFn PrefilterFunc, SignatureMask mask, enum SignatureHookPkt hook, void *pectx, void(*FreeFunc)(void *pectx), const char *name)
Definition: detect-engine-prefilter.c:282
Packet_::flags
uint32_t flags
Definition: decode.h:527
threads.h
FlowBitToggle
bool FlowBitToggle(Flow *f, uint32_t idx)
Definition: flow-bit.c:107
Flow_
Flow data structure.
Definition: flow.h:356
DetectFlowbitsAnalyze
int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx)
Definition: detect-flowbits.c:564
DetectEngineThreadCtx_::pmq
PrefilterRuleStore pmq
Definition: detect.h:1298
SigTableElmt_::flags
uint16_t flags
Definition: detect.h:1396
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:920
DetectFlowbitsData_::cmd
uint8_t cmd
Definition: detect-flowbits.h:37
SIGNATURE_HOOK_PKT_NOT_SET
@ SIGNATURE_HOOK_PKT_NOT_SET
Definition: detect.h:552
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2799
flow-bit.h
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:233
util-var-name.h
DE_QUIET
#define DE_QUIET
Definition: detect.h:329
VarNameStoreSetupLookup
const char * VarNameStoreSetupLookup(const uint32_t id, const enum VarTypes type)
Definition: util-var-name.c:188
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:2319
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
SignatureInitData_::init_flags
uint32_t init_flags
Definition: detect.h:609
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
Definition: detect-parse.c:3398
m
SCMutex m
Definition: flow-hash.h:6
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
VarNameStoreRegister
uint32_t VarNameStoreRegister(const char *name, const enum VarTypes type)
Definition: util-var-name.c:155
SIGMATCH_SUPPORT_FIREWALL
#define SIGMATCH_SUPPORT_FIREWALL
Definition: detect.h:1622
__attribute__
struct PrefilterEngineFlowbits __attribute__
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:515
MAX
#define MAX(x, y)
Definition: suricata-common.h:404
RB_HEAD
RB_HEAD(PFB, PrefilterFlowbit)
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1387
Packet_::payload_len
uint16_t payload_len
Definition: decode.h:589
detect-engine-prefilter.h
util-unittest.h
FlowBitSet
int FlowBitSet(Flow *f, uint32_t idx)
add a flowbit to the flow
Definition: flow-bit.c:94
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
SigTableElmt_::SetupPrefilter
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition: detect.h:1390
Signature_::next
struct Signature_ * next
Definition: detect.h:751
FlowBitUnset
void FlowBitUnset(Flow *f, uint32_t idx)
Definition: flow-bit.c:99
DetectFlowbitsData_
Definition: detect-flowbits.h:35
DETECT_SM_LIST_POSTMATCH
@ DETECT_SM_LIST_POSTMATCH
Definition: detect.h:126
FLOW_INITIALIZE
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:38
decode.h
RB_EMPTY
#define RB_EMPTY(head)
Definition: tree.h:327
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
GenericVar_::next
struct GenericVar_ * next
Definition: util-var.h:55
SigGroupHeadInitData_::sig_cnt
SigIntId sig_cnt
Definition: detect.h:1563
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
PARSE_REGEX
#define PARSE_REGEX
Definition: detect-flowbits.c:54
DetectEngineThreadCtx_
Definition: detect.h:1197
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
SIG_MASK_REQUIRE_FLOW
#define SIG_MASK_REQUIRE_FLOW
Definition: detect.h:311
FBAnalyzer::array
struct FBAnalyze * array
Definition: detect-flowbits.c:409
DetectSetupParseRegexes
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
Definition: detect-parse.c:3524
RB_FOREACH_SAFE
#define RB_FOREACH_SAFE(x, name, head, y)
Definition: tree.h:791
detect-engine-mpm.h
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
SignatureInitData_::rule_state_flowbits_ids_size
uint32_t rule_state_flowbits_ids_size
Definition: detect.h:662
SignatureHookPkt
SignatureHookPkt
Definition: detect.h:551
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3525
VarNameStoreUnregister
void VarNameStoreUnregister(const uint32_t id, const enum VarTypes type)
Definition: util-var-name.c:201
PrefilterFlowbit::rule_id_size
uint32_t rule_id_size
Definition: detect-flowbits.c:928
PrefilterFlowbit::rule_id
uint32_t * rule_id
Definition: detect-flowbits.c:930
FBAnalyze::toggle_sids_idx
uint32_t toggle_sids_idx
Definition: detect-flowbits.c:434
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:360
FBAnalyzer
Definition: detect-flowbits.c:408
FBAnalyze::set_sids_size
uint32_t set_sids_size
Definition: detect-flowbits.c:419
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:116
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:249
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:3002
SigGroupHead_::init
SigGroupHeadInitData * init
Definition: detect.h:1587
app-layer-parser.h
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:359
GenericVar_::idx
uint32_t idx
Definition: util-var.h:54
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:309
FBAnalyze::unset_sids
uint32_t * unset_sids
Definition: detect-flowbits.c:429
DetectFlowbitFree
void DetectFlowbitFree(DetectEngineCtx *, void *)
Definition: detect-flowbits.c:393
FBAnalyzer::array_size
uint32_t array_size
Definition: detect-flowbits.c:410
Signature_::action
uint8_t action
Definition: detect.h:684
DetectFlowbitsRegister
void DetectFlowbitsRegister(void)
Definition: detect-flowbits.c:70
SCReturn
#define SCReturn
Definition: util-debug.h:273
Signature_::flags
uint32_t flags
Definition: detect.h:670
FBAnalyze::set_sids
uint32_t * set_sids
Definition: detect-flowbits.c:417
DetectEngineCtx_::max_fb_id
uint32_t max_fb_id
Definition: detect.h:982
ACTION_ALERT
#define ACTION_ALERT
Definition: action-globals.h:29
Packet_
Definition: decode.h:484
detect-engine-build.h
SCConfigGetLogDirectory
const char * SCConfigGetLogDirectory(void)
Definition: util-conf.c:38
PrefilterFlowbit
Definition: detect-flowbits.c:926
DetectFlowbitsData_::idx
uint32_t idx
Definition: detect-flowbits.h:36
RB_GENERATE
RB_GENERATE(PFB, PrefilterFlowbit, rb, PrefilterFlowbitCompare)
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:748
name
const char * name
Definition: tm-threads.c:2135
SignatureInitData_::rule_state_dependant_sids_array
uint32_t * rule_state_dependant_sids_array
Definition: detect.h:658
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:1370
FBAnalyze::toggle_sids
uint32_t * toggle_sids
Definition: detect-flowbits.c:433
SignatureInitData_::rule_state_dependant_sids_size
uint32_t rule_state_dependant_sids_size
Definition: detect.h:659
FBAnalyze::isset_sids_idx
uint32_t isset_sids_idx
Definition: detect-flowbits.c:422
detect-flowbits.h
Flow_::flowvar
GenericVar * flowvar
Definition: flow.h:489
tree.h
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2129
FBAnalyze::unset_sids_idx
uint32_t unset_sids_idx
Definition: detect-flowbits.c:430
FBAnalyze::toggle_sids_size
uint32_t toggle_sids_size
Definition: detect-flowbits.c:435
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
SIG_FLAG_INIT_STATE_MATCH
#define SIG_FLAG_INIT_STATE_MATCH
Definition: detect.h:295
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:351
util-conf.h
Packet_::flow
struct Flow_ * flow
Definition: decode.h:529
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
VAR_TYPE_FLOW_BIT
@ VAR_TYPE_FLOW_BIT
Definition: util-var.h:36
FBAnalyze::state_cnts
uint16_t state_cnts[DETECT_FLOWBITS_CMD_MAX]
Definition: detect-flowbits.c:415
suricata-common.h
SigMatch_::type
uint16_t type
Definition: detect.h:357
GenericVar_
Definition: util-var.h:51
SigGroupHeadInitData_::match_array
Signature ** match_array
Definition: detect.h:1566
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3751
util-spm.h
PostRuleMatchWorkQueue::q
PostRuleMatchWorkQueueItem * q
Definition: detect.h:1189
FBAnalyze::set_sids_idx
uint32_t set_sids_idx
Definition: detect-flowbits.c:418
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:929
DETECT_FLOWBITS
@ DETECT_FLOWBITS
Definition: detect-engine-register.h:59
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:232
PrefilterAppendPostRuleEngine
int PrefilterAppendPostRuleEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, void(*PrefilterPostRuleFunc)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f), void *pectx, void(*FreeFunc)(void *pectx), const char *name)
Definition: detect-engine-prefilter.c:424
FlowBitIsset
int FlowBitIsset(Flow *f, uint32_t idx)
Definition: flow-bit.c:119
str
#define str(s)
Definition: suricata-common.h:300
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
FBAnalyze::isset_sids_size
uint32_t isset_sids_size
Definition: detect-flowbits.c:423
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DetectFlowbitsData_::or_list
uint32_t * or_list
Definition: detect-flowbits.h:42
SigTableElmt_::SupportsPrefilter
bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1389
Signature_::id
uint32_t id
Definition: detect.h:714
DETECT_FLOWBITS_CMD_UNSET
#define DETECT_FLOWBITS_CMD_UNSET
Definition: detect-flowbits.h:30
detect-parse.h
Signature_
Signature container.
Definition: detect.h:669
SigMatch_
a single match condition for a signature
Definition: detect.h:356
FBAnalyze::isnotset_sids_size
uint32_t isnotset_sids_size
Definition: detect-flowbits.c:427
PostRuleMatchWorkQueueItem::value
uint32_t value
Definition: detect.h:1180
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2760
GenericVar_::type
uint16_t type
Definition: util-var.h:52
DetectFlowbitMatch
int DetectFlowbitMatch(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect-flowbits.c:201
PrefilterEngineFlowbits
Definition: detect-flowbits.c:949
RB_ENTRY
#define RB_ENTRY(type)
Definition: tree.h:314
DetectEngineThreadCtx_::de_ctx
DetectEngineCtx * de_ctx
Definition: detect.h:1313
DetectEngineCtx_::sig_array
Signature ** sig_array
Definition: detect.h:938
Address_::family
char family
Definition: decode.h:113
Packet_::dst
Address dst
Definition: decode.h:489
SigMatchAppendSMToList
SigMatch * SigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:464
SignatureInitData_::rule_state_flowbits_ids_array
uint32_t * rule_state_flowbits_ids_array
Definition: detect.h:661
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:922
flow.h
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
DetectEngineCtx_::sig_array_len
uint32_t sig_array_len
Definition: detect.h:939
FBAnalyze
Definition: detect-flowbits.c:413
SignatureInitData_::buffer_index
uint32_t buffer_index
Definition: detect.h:649
SIGMATCH_IPONLY_COMPAT
#define SIGMATCH_IPONLY_COMPAT
Definition: detect.h:1594
FLOW_PKT_TOSERVER_FIRST
#define FLOW_PKT_TOSERVER_FIRST
Definition: flow.h:236
SCMutex
#define SCMutex
Definition: threads-debug.h:114
rule_engine_analysis_set
bool rule_engine_analysis_set
Definition: detect-engine-loader.c:56
SIG_FLAG_PREFILTER
#define SIG_FLAG_PREFILTER
Definition: detect.h:277
FLOW_DESTROY
#define FLOW_DESTROY(f)
Definition: flow-util.h:119
Packet_::src
Address src
Definition: decode.h:488
DetectFlowbitsData_::post_rule_match_prefilter
bool post_rule_match_prefilter
Definition: detect-flowbits.h:40
BLOCK_SIZE
#define BLOCK_SIZE
Definition: detect-flowbits.c:1039
RB_PROTOTYPE
RB_PROTOTYPE(PFB, PrefilterFlowbit, rb, PrefilterFlowbitCompare)
DetectEngineThreadCtx_::post_rule_work_queue
PostRuleMatchWorkQueue post_rule_work_queue
Definition: detect.h:1296
FlowBitIsnotset
int FlowBitIsnotset(Flow *f, uint32_t idx)
Definition: flow-bit.c:131
DETECT_FLOWBITS_CMD_SET
#define DETECT_FLOWBITS_CMD_SET
Definition: detect-flowbits.h:28
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1394