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