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