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