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