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