suricata
detect-engine-analyzer.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 Eileen Donlon <emdonlo@gmail.com>
22  * \author Victor Julien <victor@inliniac.net>
23  *
24  * Rule analyzers for the detection engine
25  */
26 
27 #include "suricata-common.h"
28 #include "suricata.h"
29 #include "rust.h"
30 #include "action-globals.h"
31 #include "detect.h"
32 #include "detect-parse.h"
33 #include "detect-engine.h"
34 #include "detect-engine-analyzer.h"
35 #include "detect-engine-mpm.h"
36 #include "detect-engine-uint.h"
37 #include "conf.h"
38 #include "detect-content.h"
39 #include "detect-pcre.h"
40 #include "detect-bytejump.h"
41 #include "detect-bytetest.h"
42 #include "detect-isdataat.h"
43 #include "detect-flow.h"
44 #include "detect-ttl.h"
45 #include "detect-tcp-flags.h"
46 #include "detect-tcp-ack.h"
47 #include "detect-ipopts.h"
48 #include "detect-tcp-seq.h"
49 #include "feature.h"
50 #include "util-print.h"
51 #include "util-time.h"
52 #include "util-validate.h"
53 #include "util-conf.h"
54 #include "detect-flowbits.h"
55 #include "detect-flowint.h"
56 #include "util-var-name.h"
57 #include "detect-icmp-id.h"
58 #include "detect-tcp-window.h"
59 
60 static int rule_warnings_only = 0;
61 
62 /* Details for each buffer being tracked */
63 typedef struct DetectEngineAnalyzerItems {
64  int16_t item_id;
65  bool item_seen;
68  const char *item_name;
69  const char *display_name;
71 
72 typedef struct FpPatternStats_ {
73  uint16_t min;
74  uint16_t max;
75  uint32_t cnt;
76  uint64_t tot;
78 
79 /* Track which items require the item_seen value to be exposed */
81  const char *bufname;
83 };
84 
85 typedef struct EngineAnalysisCtx_ {
86 
89 
91  char *file_prefix;
92  pcre2_code *percent_re;
93 
94  /*
95  * This array contains the map between the `analyzer_items` array listed above and
96  * the item ids returned by DetectBufferTypeGetByName. Iterating signature's sigmatch
97  * array provides list_ids. The map converts those ids into elements of the
98  * analyzer items array.
99  *
100  * Ultimately, the g_buffer_type_hash is searched for each buffer name. The size of that
101  * hashlist is 256, so that's the value we use here.
102  */
103  int16_t analyzer_item_map[256];
105  /*
106  * Certain values must be directly accessible. This array contains items that are directly
107  * accessed when checking if they've been seen or not.
108  */
110 
113 
115  /* request keywords */
116  { 0, false, false, true, "http_uri", "http uri" },
117  { 0, false, false, false, "http_raw_uri", "http raw uri" },
118  { 0, false, true, false, "http_method", "http method" },
119  { 0, false, false, false, "http_request_line", "http request line" },
120  { 0, false, false, false, "http_client_body", "http client body" },
121  { 0, false, false, true, "http_header", "http header" },
122  { 0, false, false, false, "http_raw_header", "http raw header" },
123  { 0, false, false, true, "http_cookie", "http cookie" },
124  { 0, false, false, false, "http_user_agent", "http user agent" },
125  { 0, false, false, false, "http_host", "http host" },
126  { 0, false, false, false, "http_raw_host", "http raw host" },
127  { 0, false, false, false, "http_accept_enc", "http accept enc" },
128  { 0, false, false, false, "http_referer", "http referer" },
129  { 0, false, false, false, "http_content_type", "http content type" },
130  { 0, false, false, false, "http_header_names", "http header names" },
131 
132  /* response keywords not listed above */
133  { 0, false, false, false, "http_stat_msg", "http stat msg" },
134  { 0, false, false, false, "http_stat_code", "http stat code" },
135  { 0, false, true, false, "file_data", "http server body" },
136 
137  /* missing request keywords */
138  { 0, false, false, false, "http_request_line", "http request line" },
139  { 0, false, false, false, "http_accept", "http accept" },
140  { 0, false, false, false, "http_accept_lang", "http accept lang" },
141  { 0, false, false, false, "http_connection", "http connection" },
142  { 0, false, false, false, "http_content_len", "http content len" },
143  { 0, false, false, false, "http_protocol", "http protocol" },
144  { 0, false, false, false, "http_start", "http start" },
145 
146  /* missing response keywords; some of the missing are listed above*/
147  { 0, false, false, false, "http_response_line", "http response line" },
148  { 0, false, false, false, "http.server", "http server" },
149  { 0, false, false, false, "http.location", "http location" },
150 };
151 
152 static void FpPatternStatsAdd(FpPatternStats *fp, int list, uint16_t patlen)
153 {
154  if (list < 0 || list >= DETECT_SM_LIST_MAX)
155  return;
156 
157  FpPatternStats *f = &fp[list];
158 
159  if (f->min == 0)
160  f->min = patlen;
161  else if (patlen < f->min)
162  f->min = patlen;
163 
164  if (patlen > f->max)
165  f->max = patlen;
166 
167  f->cnt++;
168  f->tot += patlen;
169 }
170 
171 void EngineAnalysisFP(const DetectEngineCtx *de_ctx, const Signature *s, const char *line)
172 {
173  int fast_pattern_set = 0;
174  int fast_pattern_only_set = 0;
175  int fast_pattern_chop_set = 0;
176  const DetectContentData *fp_cd = NULL;
177  const SigMatch *mpm_sm = s->init_data->mpm_sm;
178  const int mpm_sm_list = s->init_data->mpm_sm_list;
179 
180  if (mpm_sm != NULL) {
181  fp_cd = (DetectContentData *)mpm_sm->ctx;
182  if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN) {
183  fast_pattern_set = 1;
185  fast_pattern_only_set = 1;
186  } else if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) {
187  fast_pattern_chop_set = 1;
188  }
189  }
190  }
191 
192  FILE *fp = de_ctx->ea->rule_engine_analysis_fp;
193  fprintf(fp, "== Sid: %u ==\n", s->id);
194  fprintf(fp, "%s\n", line);
195 
196  fprintf(fp, " Fast Pattern analysis:\n");
197  if (s->init_data->prefilter_sm != NULL) {
198  fprintf(fp, " Prefilter on: %s\n",
200  fprintf(fp, "\n");
201  return;
202  }
203 
204  if (fp_cd == NULL) {
205  fprintf(fp, " No content present\n");
206  fprintf(fp, "\n");
207  return;
208  }
209 
210  fprintf(fp, " Fast pattern matcher: ");
211  int list_type = mpm_sm_list;
212  if (list_type == DETECT_SM_LIST_PMATCH)
213  fprintf(fp, "content\n");
214  else {
215  const char *desc = DetectEngineBufferTypeGetDescriptionById(de_ctx, list_type);
216  const char *name = DetectEngineBufferTypeGetNameById(de_ctx, list_type);
217  if (desc && name) {
218  fprintf(fp, "%s (%s)\n", desc, name);
219  }
220  }
221 
222  int flags_set = 0;
223  fprintf(fp, " Flags:");
224  if (fp_cd->flags & DETECT_CONTENT_OFFSET) {
225  fprintf(fp, " Offset");
226  flags_set = 1;
227  } if (fp_cd->flags & DETECT_CONTENT_DEPTH) {
228  fprintf(fp, " Depth");
229  flags_set = 1;
230  }
231  if (fp_cd->flags & DETECT_CONTENT_WITHIN) {
232  fprintf(fp, " Within");
233  flags_set = 1;
234  }
235  if (fp_cd->flags & DETECT_CONTENT_DISTANCE) {
236  fprintf(fp, " Distance");
237  flags_set = 1;
238  }
239  if (fp_cd->flags & DETECT_CONTENT_NOCASE) {
240  fprintf(fp, " Nocase");
241  flags_set = 1;
242  }
243  if (fp_cd->flags & DETECT_CONTENT_NEGATED) {
244  fprintf(fp, " Negated");
245  flags_set = 1;
246  }
247  if (flags_set == 0)
248  fprintf(fp, " None");
249  fprintf(fp, "\n");
250 
251  fprintf(fp, " Fast pattern set: %s\n", fast_pattern_set ? "yes" : "no");
252  fprintf(fp, " Fast pattern only set: %s\n", fast_pattern_only_set ? "yes" : "no");
253  fprintf(fp, " Fast pattern chop set: %s\n", fast_pattern_chop_set ? "yes" : "no");
254  if (fast_pattern_chop_set) {
255  fprintf(fp, " Fast pattern offset, length: %u, %u\n", fp_cd->fp_chop_offset,
256  fp_cd->fp_chop_len);
257  }
258 
259  uint16_t patlen = fp_cd->content_len;
260  uint8_t *pat = SCMalloc(fp_cd->content_len + 1);
261  if (unlikely(pat == NULL)) {
262  FatalError("Error allocating memory");
263  }
264  memcpy(pat, fp_cd->content, fp_cd->content_len);
265  pat[fp_cd->content_len] = '\0';
266  fprintf(fp, " Original content: ");
267  PrintRawUriFp(fp, pat, patlen);
268  fprintf(fp, "\n");
269 
270  if (fast_pattern_chop_set) {
271  SCFree(pat);
272  patlen = fp_cd->fp_chop_len;
273  pat = SCMalloc(fp_cd->fp_chop_len + 1);
274  if (unlikely(pat == NULL)) {
275  exit(EXIT_FAILURE);
276  }
277  memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
278  pat[fp_cd->fp_chop_len] = '\0';
279  fprintf(fp, " Final content: ");
280  PrintRawUriFp(fp, pat, patlen);
281  fprintf(fp, "\n");
282 
283  FpPatternStatsAdd(&de_ctx->ea->fp_pattern_stats[0], list_type, patlen);
284  } else {
285  fprintf(fp, " Final content: ");
286  PrintRawUriFp(fp, pat, patlen);
287  fprintf(fp, "\n");
288 
289  FpPatternStatsAdd(&de_ctx->ea->fp_pattern_stats[0], list_type, patlen);
290  }
291  SCFree(pat);
292 
293  fprintf(fp, "\n");
294 }
295 
296 /**
297  * \brief Sets up the fast pattern analyzer according to the config.
298  *
299  * \retval 1 If rule analyzer successfully enabled.
300  * \retval 0 If not enabled.
301  */
302 static int SetupFPAnalyzer(DetectEngineCtx *de_ctx)
303 {
304  int fp_engine_analysis_set = 0;
305 
306  if ((SCConfGetBool("engine-analysis.rules-fast-pattern", &fp_engine_analysis_set)) == 0) {
307  return false;
308  }
309 
310  if (fp_engine_analysis_set == 0)
311  return false;
312 
313  const char *log_dir = SCConfigGetLogDirectory();
314  char *log_path = SCMalloc(PATH_MAX);
315  if (log_path == NULL) {
316  FatalError("Unable to allocate scratch memory for rule filename");
317  }
318  snprintf(log_path, PATH_MAX, "%s/%s%s", log_dir,
319  de_ctx->ea->file_prefix ? de_ctx->ea->file_prefix : "", "rules_fast_pattern.txt");
320 
321  FILE *fp = fopen(log_path, "w");
322  if (fp == NULL) {
323  SCLogError("failed to open %s: %s", log_path, strerror(errno));
324  SCFree(log_path);
325  return false;
326  }
327 
329 
330  SCLogInfo("Engine-Analysis for fast_pattern printed to file - %s",
331  log_path);
332  SCFree(log_path);
333 
334  struct timeval tval;
335  gettimeofday(&tval, NULL);
336  struct tm local_tm;
337  struct tm *tms = SCLocalTime(tval.tv_sec, &local_tm);
338  fprintf(fp, "----------------------------------------------"
339  "---------------------\n");
340  fprintf(fp,
341  "Date: %" PRId32 "/%" PRId32 "/%04d -- "
342  "%02d:%02d:%02d\n",
343  tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
344  tms->tm_sec);
345  fprintf(fp, "----------------------------------------------"
346  "---------------------\n");
347 
348  memset(&de_ctx->ea->fp_pattern_stats[0], 0, sizeof(de_ctx->ea->fp_pattern_stats));
349  return true;
350 }
351 
352 /**
353  * \brief Compiles regex for rule analysis
354  * \retval 1 if successful
355  * \retval 0 if on error
356  */
357 static bool PerCentEncodingSetup(EngineAnalysisCtx *ea_ctx)
358 {
359 #define DETECT_PERCENT_ENCODING_REGEX "%[0-9|a-f|A-F]{2}"
360  int en;
361  PCRE2_SIZE eo = 0;
362  int opts = 0; // PCRE2_NEWLINE_ANY??
363 
364  ea_ctx->percent_re = pcre2_compile((PCRE2_SPTR8)DETECT_PERCENT_ENCODING_REGEX,
365  PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
366  if (ea_ctx->percent_re == NULL) {
367  PCRE2_UCHAR errbuffer[256];
368  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
369  SCLogError("Compile of \"%s\" failed at offset %d: %s", DETECT_PERCENT_ENCODING_REGEX,
370  (int)eo, errbuffer);
371  return false;
372  }
373 
374  return true;
375 }
376 /**
377  * \brief Sets up the rule analyzer according to the config
378  * \retval 1 if rule analyzer successfully enabled
379  * \retval 0 if not enabled
380  */
381 static int SetupRuleAnalyzer(DetectEngineCtx *de_ctx)
382 {
383  SCConfNode *conf = SCConfGetNode("engine-analysis");
384  int enabled = 0;
385  if (conf != NULL) {
386  const char *value = SCConfNodeLookupChildValue(conf, "rules");
387  if (value && SCConfValIsTrue(value)) {
388  enabled = 1;
389  } else if (value && strcasecmp(value, "warnings-only") == 0) {
390  enabled = 1;
391  rule_warnings_only = 1;
392  }
393  if (enabled) {
394  const char *log_dir;
395  log_dir = SCConfigGetLogDirectory();
396  char log_path[PATH_MAX];
397  snprintf(log_path, sizeof(log_path), "%s/%s%s", log_dir,
398  de_ctx->ea->file_prefix ? de_ctx->ea->file_prefix : "", "rules_analysis.txt");
399  de_ctx->ea->rule_engine_analysis_fp = fopen(log_path, "w");
400  if (de_ctx->ea->rule_engine_analysis_fp == NULL) {
401  SCLogError("failed to open %s: %s", log_path, strerror(errno));
402  return 0;
403  }
404 
405  SCLogInfo("Engine-Analysis for rules printed to file - %s",
406  log_path);
407 
408  struct timeval tval;
409  gettimeofday(&tval, NULL);
410  struct tm local_tm;
411  struct tm *tms = SCLocalTime(tval.tv_sec, &local_tm);
413  "----------------------------------------------"
414  "---------------------\n");
416  "Date: %" PRId32 "/%" PRId32 "/%04d -- "
417  "%02d:%02d:%02d\n",
418  tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
419  tms->tm_sec);
421  "----------------------------------------------"
422  "---------------------\n");
423 
424  /*compile regex's for rule analysis*/
425  if (!PerCentEncodingSetup(de_ctx->ea)) {
427  "Error compiling regex; can't check for percent encoding in normalized "
428  "http content.\n");
429  }
430  }
431  }
432  else {
433  SCLogInfo("Conf parameter \"engine-analysis.rules\" not found. "
434  "Defaulting to not printing the rules analysis report.");
435  }
436  if (!enabled) {
437  SCLogInfo("Engine-Analysis for rules disabled in conf file.");
438  return 0;
439  }
440  return 1;
441 }
442 
443 static void CleanupFPAnalyzer(DetectEngineCtx *de_ctx)
444 {
445  FILE *fp = de_ctx->ea->rule_engine_analysis_fp;
446  fprintf(fp, "============\n"
447  "Summary:\n============\n");
448 
449  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
451  if (f->cnt == 0)
452  continue;
453 
454  fprintf(fp,
455  "%s, smallest pattern %u byte(s), longest pattern %u byte(s), number of patterns "
456  "%u, avg pattern len %.2f byte(s)\n",
457  DetectSigmatchListEnumToString(i), f->min, f->max, f->cnt,
458  (float)((double)f->tot / (float)f->cnt));
459  }
460 
463 }
464 
465 static void CleanupRuleAnalyzer(DetectEngineCtx *de_ctx)
466 {
467  if (de_ctx->ea->fp_engine_analysis_fp != NULL) {
468  fclose(de_ctx->ea->fp_engine_analysis_fp);
470  }
471  if (de_ctx->ea->percent_re != NULL) {
472  pcre2_code_free(de_ctx->ea->percent_re);
473  }
474 }
475 
476 void SetupEngineAnalysis(DetectEngineCtx *de_ctx, bool *fp_analysis, bool *rule_analysis)
477 {
478  *fp_analysis = false;
479  *rule_analysis = false;
480 
481  EngineAnalysisCtx *ea = SCCalloc(1, sizeof(EngineAnalysisCtx));
482  if (ea == NULL) {
483  FatalError("Unable to allocate per-engine analysis context");
484  }
485 
486  ea->file_prefix = NULL;
487  size_t cfg_prefix_len = strlen(de_ctx->config_prefix);
488  if (cfg_prefix_len > 0) {
489  char prefix[sizeof(de_ctx->config_prefix) + 1];
490  snprintf(prefix, sizeof(prefix), "%s.", de_ctx->config_prefix);
491  ea->file_prefix = SCStrdup(prefix);
492  if (ea->file_prefix == NULL) {
493  FatalError("Unable to allocate per-engine analysis context name buffer");
494  }
495  }
496 
497  de_ctx->ea = ea;
498 
499  *fp_analysis = SetupFPAnalyzer(de_ctx);
500  *rule_analysis = SetupRuleAnalyzer(de_ctx);
501 
502  if (!(*fp_analysis || *rule_analysis)) {
503  if (ea->file_prefix)
504  SCFree(ea->file_prefix);
505  if (ea->analyzer_items)
506  SCFree(ea->analyzer_items);
507  SCFree(ea);
508  }
509 }
510 
512 {
513  if (de_ctx->ea) {
514  CleanupRuleAnalyzer(de_ctx);
515  CleanupFPAnalyzer(de_ctx);
516  if (de_ctx->ea->file_prefix)
518  if (de_ctx->ea->analyzer_items)
520  SCFree(de_ctx->ea);
521  de_ctx->ea = NULL;
522  }
523 }
524 
525 /**
526  * \brief Checks for % encoding in content.
527  * \param Pointer to content
528  * \retval number of matches if content has % encoding
529  * \retval 0 if it doesn't have % encoding
530  * \retval -1 on error
531  */
532 static int PerCentEncodingMatch(EngineAnalysisCtx *ea_ctx, uint8_t *content, uint16_t content_len)
533 {
534  int ret = 0;
535 
536  pcre2_match_data *match = pcre2_match_data_create_from_pattern(ea_ctx->percent_re, NULL);
537  ret = pcre2_match(ea_ctx->percent_re, (PCRE2_SPTR8)content, content_len, 0, 0, match, NULL);
538  if (ret == -1) {
539  return 0;
540  } else if (ret < -1) {
541  SCLogError("Error parsing content - %s; error code is %d", content, ret);
542  ret = -1;
543  }
544  pcre2_match_data_free(match);
545  return ret;
546 }
547 
548 static void EngineAnalysisRulesPrintFP(const DetectEngineCtx *de_ctx, const Signature *s)
549 {
550  const DetectContentData *fp_cd = NULL;
551  const SigMatch *mpm_sm = s->init_data->mpm_sm;
552  const int mpm_sm_list = s->init_data->mpm_sm_list;
553 
554  if (mpm_sm != NULL) {
555  fp_cd = (DetectContentData *)mpm_sm->ctx;
556  }
557 
558  if (fp_cd == NULL) {
559  return;
560  }
561 
562  uint16_t patlen = fp_cd->content_len;
563  uint8_t *pat = SCMalloc(fp_cd->content_len + 1);
564  if (unlikely(pat == NULL)) {
565  FatalError("Error allocating memory");
566  }
567 
568  EngineAnalysisCtx *ea_ctx = de_ctx->ea;
569 
570  memcpy(pat, fp_cd->content, fp_cd->content_len);
571  pat[fp_cd->content_len] = '\0';
572 
574  SCFree(pat);
575  patlen = fp_cd->fp_chop_len;
576  pat = SCMalloc(fp_cd->fp_chop_len + 1);
577  if (unlikely(pat == NULL)) {
578  exit(EXIT_FAILURE);
579  }
580  memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
581  pat[fp_cd->fp_chop_len] = '\0';
582  fprintf(ea_ctx->rule_engine_analysis_fp, " Fast Pattern \"");
583  PrintRawUriFp(ea_ctx->rule_engine_analysis_fp, pat, patlen);
584  } else {
585  fprintf(ea_ctx->rule_engine_analysis_fp, " Fast Pattern \"");
586  PrintRawUriFp(ea_ctx->rule_engine_analysis_fp, pat, patlen);
587  }
588  SCFree(pat);
589 
590  fprintf(ea_ctx->rule_engine_analysis_fp, "\" on \"");
591 
592  const int list_type = mpm_sm_list;
593  if (list_type == DETECT_SM_LIST_PMATCH) {
594  int payload = 0;
595  int stream = 0;
597  payload = 1;
599  stream = 1;
600  fprintf(ea_ctx->rule_engine_analysis_fp, "%s",
601  payload ? (stream ? "payload and reassembled stream" : "payload")
602  : "reassembled stream");
603  }
604  else {
605  const char *desc = DetectEngineBufferTypeGetDescriptionById(de_ctx, list_type);
606  const char *name = DetectEngineBufferTypeGetNameById(de_ctx, list_type);
607  if (desc && name) {
608  fprintf(ea_ctx->rule_engine_analysis_fp, "%s (%s)", desc, name);
609  } else if (desc || name) {
610  fprintf(ea_ctx->rule_engine_analysis_fp, "%s", desc ? desc : name);
611  }
612 
613  }
614 
615  fprintf(ea_ctx->rule_engine_analysis_fp, "\" ");
616  const DetectBufferType *bt = DetectEngineBufferTypeGetById(de_ctx, list_type);
617  if (bt && bt->transforms.cnt) {
618  fprintf(ea_ctx->rule_engine_analysis_fp, "(with %d transform(s)) ", bt->transforms.cnt);
619  }
620  fprintf(ea_ctx->rule_engine_analysis_fp, "buffer.\n");
621 }
622 
624  const DetectEngineCtx *de_ctx, const char *line, const char *file, int lineno)
625 {
628  if (tmp_fp) {
629  fprintf(tmp_fp, "== Sid: UNKNOWN ==\n");
630  fprintf(tmp_fp, "%s\n", line);
631  fprintf(tmp_fp, " FAILURE: invalid rule.\n");
632  fprintf(tmp_fp, " File: %s.\n", file);
633  fprintf(tmp_fp, " Line: %d.\n", lineno);
634  fprintf(tmp_fp, "\n");
635  }
636 }
637 
638 typedef struct RuleAnalyzer {
639  SCJsonBuilder *js; /* document root */
640 
641  SCJsonBuilder *js_warnings;
642  SCJsonBuilder *js_notes;
644 
645 static void ATTR_FMT_PRINTF(2, 3) AnalyzerNote(RuleAnalyzer *ctx, char *fmt, ...)
646 {
647  va_list ap;
648  char str[1024];
649 
650  va_start(ap, fmt);
651  vsnprintf(str, sizeof(str), fmt, ap);
652  va_end(ap);
653 
654  if (!ctx->js_notes)
655  ctx->js_notes = SCJbNewArray();
656  if (ctx->js_notes)
657  SCJbAppendString(ctx->js_notes, str);
658 }
659 
660 static void ATTR_FMT_PRINTF(2, 3) AnalyzerWarning(RuleAnalyzer *ctx, char *fmt, ...)
661 {
662  va_list ap;
663  char str[1024];
664 
665  va_start(ap, fmt);
666  vsnprintf(str, sizeof(str), fmt, ap);
667  va_end(ap);
668 
669  if (!ctx->js_warnings)
670  ctx->js_warnings = SCJbNewArray();
671  if (ctx->js_warnings)
672  SCJbAppendString(ctx->js_warnings, str);
673 }
674 
675 #define CHECK(pat) if (strlen((pat)) <= len && memcmp((pat), buf, MIN(len, strlen((pat)))) == 0) return true;
676 
677 static bool LooksLikeHTTPMethod(const uint8_t *buf, uint16_t len)
678 {
679  CHECK("GET /");
680  CHECK("POST /");
681  CHECK("HEAD /");
682  CHECK("PUT /");
683  return false;
684 }
685 
686 static bool LooksLikeHTTPUA(const uint8_t *buf, uint16_t len)
687 {
688  CHECK("User-Agent: ");
689  CHECK("\nUser-Agent: ");
690  return false;
691 }
692 
693 static void DumpContent(SCJsonBuilder *js, const DetectContentData *cd)
694 {
695  char pattern_str[1024] = "";
696  DetectContentPatternPrettyPrint(cd, pattern_str, sizeof(pattern_str));
697 
698  SCJbSetString(js, "pattern", pattern_str);
699  SCJbSetUint(js, "length", cd->content_len);
700  SCJbSetBool(js, "nocase", cd->flags & DETECT_CONTENT_NOCASE);
701  SCJbSetBool(js, "negated", cd->flags & DETECT_CONTENT_NEGATED);
702  SCJbSetBool(js, "starts_with", cd->flags & DETECT_CONTENT_STARTS_WITH);
703  SCJbSetBool(js, "ends_with", cd->flags & DETECT_CONTENT_ENDS_WITH);
704  SCJbSetBool(js, "is_mpm", cd->flags & DETECT_CONTENT_MPM);
705  SCJbSetBool(js, "no_double_inspect", cd->flags & DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED);
706  if (cd->flags & DETECT_CONTENT_OFFSET) {
707  SCJbSetUint(js, "offset", cd->offset);
708  }
709  if (cd->flags & DETECT_CONTENT_DEPTH) {
710  SCJbSetUint(js, "depth", cd->depth);
711  }
712  if (cd->flags & DETECT_CONTENT_DISTANCE) {
713  SCJbSetInt(js, "distance", cd->distance);
714  }
715  if (cd->flags & DETECT_CONTENT_WITHIN) {
716  SCJbSetInt(js, "within", cd->within);
717  }
718  SCJbSetBool(js, "fast_pattern", cd->flags & DETECT_CONTENT_FAST_PATTERN);
719  SCJbSetBool(js, "relative_next", cd->flags & DETECT_CONTENT_RELATIVE_NEXT);
720 }
721 
722 static void DumpPcre(SCJsonBuilder *js, const DetectPcreData *cd)
723 {
724  SCJbSetBool(js, "relative", cd->flags & DETECT_PCRE_RELATIVE);
725  SCJbSetBool(js, "relative_next", cd->flags & DETECT_PCRE_RELATIVE_NEXT);
726  SCJbSetBool(js, "nocase", cd->flags & DETECT_PCRE_CASELESS);
727  SCJbSetBool(js, "negated", cd->flags & DETECT_PCRE_NEGATE);
728 }
729 
730 static void DumpMatches(RuleAnalyzer *ctx, SCJsonBuilder *js, const SigMatchData *smd)
731 {
732  if (smd == NULL)
733  return;
734 
735  SCJbOpenArray(js, "matches");
736  do {
737  SCJbStartObject(js);
738  const char *mname = sigmatch_table[smd->type].name;
739  SCJbSetString(js, "name", mname);
740 
741  switch (smd->type) {
742  case DETECT_CONTENT: {
743  const DetectContentData *cd = (const DetectContentData *)smd->ctx;
744 
745  SCJbOpenObject(js, "content");
746  DumpContent(js, cd);
748  AnalyzerNote(ctx, (char *)"'fast_pattern:only' option is silently ignored and "
749  "is interpreted as regular 'fast_pattern'");
750  }
751  if (LooksLikeHTTPMethod(cd->content, cd->content_len)) {
752  AnalyzerNote(ctx,
753  (char *)"pattern looks like it inspects HTTP, use http.request_line or "
754  "http.method and http.uri instead for improved performance");
755  }
756  if (LooksLikeHTTPUA(cd->content, cd->content_len)) {
757  AnalyzerNote(ctx,
758  (char *)"pattern looks like it inspects HTTP, use http.user_agent "
759  "or http.header for improved performance");
760  }
762  AnalyzerNote(ctx, (char *)"'within' option for pattern w/o previous content "
763  "was converted to 'depth'");
764  }
766  AnalyzerNote(ctx, (char *)"'distance' option for pattern w/o previous content "
767  "was converted to 'offset'");
768  }
769  SCJbClose(js);
770  break;
771  }
772  case DETECT_PCRE: {
773  const DetectPcreData *cd = (const DetectPcreData *)smd->ctx;
774 
775  SCJbOpenObject(js, "pcre");
776  DumpPcre(js, cd);
777  SCJbClose(js);
778  if (cd->flags & DETECT_PCRE_RAWBYTES) {
779  AnalyzerNote(ctx,
780  (char *)"'/B' (rawbytes) option is a no-op and is silently ignored");
781  }
782  break;
783  }
784  case DETECT_BYTEJUMP: {
785  const DetectBytejumpData *cd = (const DetectBytejumpData *)smd->ctx;
786 
787  SCJbOpenObject(js, "byte_jump");
788  SCJbSetUint(js, "nbytes", cd->nbytes);
789  SCJbSetInt(js, "offset", cd->offset);
790  SCJbSetUint(js, "multiplier", cd->multiplier);
791  SCJbSetInt(js, "post_offset", cd->post_offset);
792  switch (cd->base) {
794  SCJbSetString(js, "base", "unset");
795  break;
797  SCJbSetString(js, "base", "oct");
798  break;
800  SCJbSetString(js, "base", "dec");
801  break;
803  SCJbSetString(js, "base", "hex");
804  break;
805  }
806  SCJbOpenArray(js, "flags");
807  if (cd->flags & DETECT_BYTEJUMP_BEGIN)
808  SCJbAppendString(js, "from_beginning");
809  if (cd->flags & DETECT_BYTEJUMP_LITTLE)
810  SCJbAppendString(js, "little_endian");
811  if (cd->flags & DETECT_BYTEJUMP_BIG)
812  SCJbAppendString(js, "big_endian");
813  if (cd->flags & DETECT_BYTEJUMP_STRING)
814  SCJbAppendString(js, "string");
816  SCJbAppendString(js, "relative");
817  if (cd->flags & DETECT_BYTEJUMP_ALIGN)
818  SCJbAppendString(js, "align");
819  if (cd->flags & DETECT_BYTEJUMP_DCE)
820  SCJbAppendString(js, "dce");
822  SCJbAppendString(js, "offset_be");
823  if (cd->flags & DETECT_BYTEJUMP_END)
824  SCJbAppendString(js, "from_end");
825  SCJbClose(js);
826  SCJbClose(js);
827  break;
828  }
829  case DETECT_BYTETEST: {
830  const DetectBytetestData *cd = (const DetectBytetestData *)smd->ctx;
831 
832  SCJbOpenObject(js, "byte_test");
833  SCJbSetUint(js, "nbytes", cd->nbytes);
834  SCJbSetInt(js, "offset", cd->offset);
835  switch (cd->base) {
837  SCJbSetString(js, "base", "unset");
838  break;
840  SCJbSetString(js, "base", "oct");
841  break;
843  SCJbSetString(js, "base", "dec");
844  break;
846  SCJbSetString(js, "base", "hex");
847  break;
848  }
849  SCJbOpenArray(js, "flags");
850  if (cd->flags & DETECT_BYTETEST_LITTLE)
851  SCJbAppendString(js, "little_endian");
852  if (cd->flags & DETECT_BYTETEST_BIG)
853  SCJbAppendString(js, "big_endian");
854  if (cd->flags & DETECT_BYTETEST_STRING)
855  SCJbAppendString(js, "string");
857  SCJbAppendString(js, "relative");
858  if (cd->flags & DETECT_BYTETEST_DCE)
859  SCJbAppendString(js, "dce");
860  SCJbClose(js);
861  SCJbClose(js);
862  break;
863  }
864  case DETECT_ABSENT: {
865  const DetectAbsentData *dad = (const DetectAbsentData *)smd->ctx;
866  SCJbOpenObject(js, "absent");
867  SCJbSetBool(js, "or_else", dad->or_else);
868  SCJbClose(js);
869  break;
870  }
871 
872  case DETECT_IPOPTS: {
873  const DetectIpOptsData *cd = (const DetectIpOptsData *)smd->ctx;
874 
875  SCJbOpenObject(js, "ipopts");
876  const char *flag = IpOptsFlagToString(cd->ipopt);
877  SCJbSetString(js, "option", flag);
878  SCJbClose(js);
879  break;
880  }
881  case DETECT_FLOWBITS: {
882  const DetectFlowbitsData *cd = (const DetectFlowbitsData *)smd->ctx;
883 
884  SCJbOpenObject(js, "flowbits");
885  switch (cd->cmd) {
887  SCJbSetString(js, "cmd", "isset");
888  break;
890  SCJbSetString(js, "cmd", "isnotset");
891  break;
893  SCJbSetString(js, "cmd", "set");
894  break;
896  SCJbSetString(js, "cmd", "unset");
897  break;
899  SCJbSetString(js, "cmd", "toggle");
900  break;
901  }
902  bool is_or = false;
903  SCJbOpenArray(js, "names");
904  if (cd->or_list_size == 0) {
905  SCJbAppendString(js, VarNameStoreSetupLookup(cd->idx, VAR_TYPE_FLOW_BIT));
906  } else if (cd->or_list_size > 0) {
907  is_or = true;
908  for (uint8_t i = 0; i < cd->or_list_size; i++) {
909  const char *varname =
911  SCJbAppendString(js, varname);
912  }
913  }
914  SCJbClose(js); // array
915  if (is_or) {
916  SCJbSetString(js, "operator", "or");
917  }
918  SCJbClose(js); // object
919  break;
920  }
921  case DETECT_FLOWINT: {
922  const DetectFlowintData *cd = (const DetectFlowintData *)smd->ctx;
923 
924  SCJbOpenObject(js, "flowint");
925  switch (cd->modifier) {
927  SCJbSetString(js, "cmd", "set");
928  break;
930  SCJbSetString(js, "cmd", "add");
931  break;
933  SCJbSetString(js, "cmd", "sub");
934  break;
935  case FLOWINT_MODIFIER_LT:
936  SCJbSetString(js, "cmd", "lt");
937  break;
938  case FLOWINT_MODIFIER_LE:
939  SCJbSetString(js, "cmd", "lte");
940  break;
941  case FLOWINT_MODIFIER_EQ:
942  SCJbSetString(js, "cmd", "eq");
943  break;
944  case FLOWINT_MODIFIER_NE:
945  SCJbSetString(js, "cmd", "ne");
946  break;
947  case FLOWINT_MODIFIER_GE:
948  SCJbSetString(js, "cmd", "gte");
949  break;
950  case FLOWINT_MODIFIER_GT:
951  SCJbSetString(js, "cmd", "gt");
952  break;
954  SCJbSetString(js, "cmd", "isset");
955  break;
957  SCJbSetString(js, "cmd", "isnotset");
958  break;
959  }
960  const char *varname = VarNameStoreSetupLookup(cd->idx, VAR_TYPE_FLOW_INT);
961  if (varname != NULL) {
962  SCJbSetString(js, "var", varname);
963  }
964  if (cd->targettype == FLOWINT_TARGET_VAL) {
965  SCJbSetUint(js, "value", cd->target.value);
966  } else if (cd->targettype == FLOWINT_TARGET_VAR) {
967  if (cd->target.tvar.name != NULL) {
968  SCJbSetString(js, "target", cd->target.tvar.name);
969  }
970  }
971  SCJbClose(js);
972  break;
973  }
974  case DETECT_ACK: {
975  const DetectU32Data *cd = (const DetectU32Data *)smd->ctx;
976  SCJbOpenObject(js, "ack");
977  SCDetectU32ToJson(js, cd);
978  SCJbClose(js);
979  break;
980  }
981  case DETECT_SEQ: {
982  const DetectU32Data *cd = (const DetectU32Data *)smd->ctx;
983  SCJbOpenObject(js, "seq");
984  SCDetectU32ToJson(js, cd);
985  SCJbClose(js);
986  break;
987  }
988  case DETECT_TCPMSS: {
989  const DetectU16Data *cd = (const DetectU16Data *)smd->ctx;
990  SCJbOpenObject(js, "tcp_mss");
991  SCDetectU16ToJson(js, cd);
992  SCJbClose(js);
993  break;
994  }
995  case DETECT_DSIZE: {
996  const DetectU16Data *cd = (const DetectU16Data *)smd->ctx;
997  SCJbOpenObject(js, "dsize");
998  SCDetectU16ToJson(js, cd);
999  SCJbClose(js);
1000  break;
1001  }
1002  case DETECT_ICODE: {
1003  const DetectU8Data *cd = (const DetectU8Data *)smd->ctx;
1004  SCJbOpenObject(js, "code");
1005  SCDetectU8ToJson(js, cd);
1006  SCJbClose(js);
1007  break;
1008  }
1009  case DETECT_TTL: {
1010  const DetectU8Data *cd = (const DetectU8Data *)smd->ctx;
1011  SCJbOpenObject(js, "ttl");
1012  SCDetectU8ToJson(js, cd);
1013  SCJbClose(js);
1014  break;
1015  }
1016  case DETECT_ICMP_ID: {
1017  const DetectU16Data *cd = (const DetectU16Data *)smd->ctx;
1018  SCJbOpenObject(js, "id");
1019  SCDetectU16ToJson(js, cd);
1020  SCJbClose(js);
1021  break;
1022  }
1023  case DETECT_WINDOW: {
1024  const DetectU16Data *cd = (const DetectU16Data *)smd->ctx;
1025  SCJbOpenObject(js, "window");
1026  SCDetectU16ToJson(js, cd);
1027  SCJbClose(js);
1028  break;
1029  }
1030  case DETECT_FLOW_AGE: {
1031  const DetectU32Data *cd = (const DetectU32Data *)smd->ctx;
1032  SCJbOpenObject(js, "flow_age");
1033  SCDetectU32ToJson(js, cd);
1034  SCJbClose(js);
1035  break;
1036  }
1037  }
1038  SCJbClose(js);
1039 
1040  if (smd->is_last)
1041  break;
1042  smd++;
1043  } while (1);
1044  SCJbClose(js);
1045 }
1046 
1049 {
1050  SCEnter();
1051 
1052  RuleAnalyzer ctx = { NULL, NULL, NULL };
1053 
1054  ctx.js = SCJbNewObject();
1055  if (ctx.js == NULL)
1056  SCReturn;
1057 
1058  if (s->init_data->firewall_rule) {
1059  JB_SET_STRING(ctx.js, "class", "firewall");
1060  } else {
1061  JB_SET_STRING(ctx.js, "class", "threat detection");
1062  }
1063 
1064  SCJbSetString(ctx.js, "raw", s->sig_str);
1065  SCJbSetUint(ctx.js, "id", s->id);
1066  SCJbSetUint(ctx.js, "gid", s->gid);
1067  SCJbSetUint(ctx.js, "rev", s->rev);
1068  SCJbSetString(ctx.js, "msg", s->msg);
1069 
1070  const char *alproto = AppProtoToString(s->alproto);
1071  SCJbSetString(ctx.js, "app_proto", alproto);
1072 
1073  SCJbOpenArray(ctx.js, "requirements");
1074  if (s->mask & SIG_MASK_REQUIRE_PAYLOAD) {
1075  SCJbAppendString(ctx.js, "payload");
1076  }
1077  if (s->mask & SIG_MASK_REQUIRE_NO_PAYLOAD) {
1078  SCJbAppendString(ctx.js, "no_payload");
1079  }
1080  if (s->mask & SIG_MASK_REQUIRE_FLOW) {
1081  SCJbAppendString(ctx.js, "flow");
1082  }
1084  SCJbAppendString(ctx.js, "tcp_flags_init_deinit");
1085  }
1087  SCJbAppendString(ctx.js, "tcp_flags_unusual");
1088  }
1090  SCJbAppendString(ctx.js, "engine_event");
1091  }
1092  if (s->mask & SIG_MASK_REQUIRE_REAL_PKT) {
1093  SCJbAppendString(ctx.js, "real_pkt");
1094  }
1095  SCJbClose(ctx.js);
1096 
1097  SCJbOpenObject(ctx.js, "match_policy");
1098  SCJbOpenArray(ctx.js, "actions");
1099  if (s->action & ACTION_ALERT) {
1100  SCJbAppendString(ctx.js, "alert");
1101  }
1102  if (s->action & ACTION_DROP) {
1103  SCJbAppendString(ctx.js, "drop");
1104  }
1105  if (s->action & ACTION_REJECT) {
1106  SCJbAppendString(ctx.js, "reject");
1107  }
1108  if (s->action & ACTION_REJECT_DST) {
1109  SCJbAppendString(ctx.js, "reject_dst");
1110  }
1111  if (s->action & ACTION_REJECT_BOTH) {
1112  SCJbAppendString(ctx.js, "reject_both");
1113  }
1114  if (s->action & ACTION_CONFIG) {
1115  SCJbAppendString(ctx.js, "config");
1116  }
1117  if (s->action & ACTION_PASS) {
1118  SCJbAppendString(ctx.js, "pass");
1119  }
1120  if (s->action & ACTION_ACCEPT) {
1121  SCJbAppendString(ctx.js, "accept");
1122  }
1123  SCJbClose(ctx.js);
1124 
1125  if (s->action_scope == ACTION_SCOPE_AUTO) {
1127  switch (flow_action) {
1129  SCJbSetString(ctx.js, "scope", "packet");
1130  break;
1132  SCJbSetString(ctx.js, "scope", "flow");
1133  break;
1135  SCJbSetString(ctx.js, "scope", "flow_if_stateful");
1136  break;
1137  }
1138  } else {
1139  enum ActionScope as = s->action_scope;
1140  switch (as) {
1141  case ACTION_SCOPE_PACKET:
1142  SCJbSetString(ctx.js, "scope", "packet");
1143  break;
1144  case ACTION_SCOPE_FLOW:
1145  SCJbSetString(ctx.js, "scope", "flow");
1146  break;
1147  case ACTION_SCOPE_HOOK:
1148  SCJbSetString(ctx.js, "scope", "hook");
1149  break;
1150  case ACTION_SCOPE_TX:
1151  SCJbSetString(ctx.js, "scope", "tx");
1152  break;
1153  case ACTION_SCOPE_AUTO: /* should be unreachable */
1154  break;
1155  }
1156  }
1157  SCJbClose(ctx.js);
1158 
1159  switch (s->type) {
1160  case SIG_TYPE_NOT_SET:
1161  SCJbSetString(ctx.js, "type", "unset");
1162  break;
1163  case SIG_TYPE_IPONLY:
1164  SCJbSetString(ctx.js, "type", "ip_only");
1165  break;
1166  case SIG_TYPE_LIKE_IPONLY:
1167  SCJbSetString(ctx.js, "type", "like_ip_only");
1168  break;
1169  case SIG_TYPE_PDONLY:
1170  SCJbSetString(ctx.js, "type", "pd_only");
1171  break;
1172  case SIG_TYPE_DEONLY:
1173  SCJbSetString(ctx.js, "type", "de_only");
1174  break;
1175  case SIG_TYPE_PKT:
1176  SCJbSetString(ctx.js, "type", "pkt");
1177  break;
1178  case SIG_TYPE_PKT_STREAM:
1179  SCJbSetString(ctx.js, "type", "pkt_stream");
1180  break;
1181  case SIG_TYPE_STREAM:
1182  SCJbSetString(ctx.js, "type", "stream");
1183  break;
1184  case SIG_TYPE_APPLAYER:
1185  SCJbSetString(ctx.js, "type", "app_layer");
1186  break;
1187  case SIG_TYPE_APP_TX:
1188  SCJbSetString(ctx.js, "type", "app_tx");
1189  break;
1190  case SIG_TYPE_MAX:
1191  SCJbSetString(ctx.js, "type", "error");
1192  break;
1193  }
1194 
1195  // dependencies object and its subfields only logged if we have values
1197  SCJbOpenObject(ctx.js, "dependencies");
1198  SCJbOpenObject(ctx.js, "flowbits");
1199  SCJbOpenObject(ctx.js, "upstream");
1201  SCJbOpenObject(ctx.js, "state_modifying_rules");
1202  SCJbOpenArray(ctx.js, "sids");
1203  for (uint32_t i = 0; i < s->init_data->rule_state_dependant_sids_idx; i++) {
1204  SCJbAppendUint(ctx.js, s->init_data->rule_state_dependant_sids_array[i]);
1205  }
1206  SCJbClose(ctx.js); // sids
1207  SCJbOpenArray(ctx.js, "names");
1208  for (uint32_t i = 0; i < s->init_data->rule_state_flowbits_ids_size - 1; i++) {
1209  if (s->init_data->rule_state_flowbits_ids_array[i] != 0) {
1210  SCJbAppendString(ctx.js,
1213  }
1214  }
1215  SCJbClose(ctx.js); // names
1216  SCJbClose(ctx.js); // state_modifying_rules
1217  }
1218  SCJbClose(ctx.js); // upstream
1219  SCJbClose(ctx.js); // flowbits
1220  SCJbClose(ctx.js); // dependencies
1221  }
1222 
1223  SCJbOpenArray(ctx.js, "flags");
1224  if (s->flags & SIG_FLAG_SRC_ANY) {
1225  SCJbAppendString(ctx.js, "src_any");
1226  }
1227  if (s->flags & SIG_FLAG_DST_ANY) {
1228  SCJbAppendString(ctx.js, "dst_any");
1229  }
1230  if (s->flags & SIG_FLAG_SP_ANY) {
1231  SCJbAppendString(ctx.js, "sp_any");
1232  }
1233  if (s->flags & SIG_FLAG_DP_ANY) {
1234  SCJbAppendString(ctx.js, "dp_any");
1235  }
1236  if ((s->action & ACTION_ALERT) == 0) {
1237  SCJbAppendString(ctx.js, "noalert");
1238  }
1239  if (s->flags & SIG_FLAG_DSIZE) {
1240  SCJbAppendString(ctx.js, "dsize");
1241  }
1242  if (s->flags & SIG_FLAG_APPLAYER) {
1243  SCJbAppendString(ctx.js, "applayer");
1244  }
1245  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
1246  SCJbAppendString(ctx.js, "need_packet");
1247  }
1248  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
1249  SCJbAppendString(ctx.js, "need_stream");
1250  }
1251  if (s->flags & SIG_FLAG_MPM_NEG) {
1252  SCJbAppendString(ctx.js, "negated_mpm");
1253  }
1254  if (s->flags & SIG_FLAG_FLUSH) {
1255  SCJbAppendString(ctx.js, "flush");
1256  }
1257  if (s->flags & SIG_FLAG_REQUIRE_FLOWVAR) {
1258  SCJbAppendString(ctx.js, "need_flowvar");
1259  }
1260  if (s->flags & SIG_FLAG_FILESTORE) {
1261  SCJbAppendString(ctx.js, "filestore");
1262  }
1263  if (s->flags & SIG_FLAG_TOSERVER) {
1264  SCJbAppendString(ctx.js, "toserver");
1265  }
1266  if (s->flags & SIG_FLAG_TOCLIENT) {
1267  SCJbAppendString(ctx.js, "toclient");
1268  }
1269  if (s->flags & SIG_FLAG_TLSSTORE) {
1270  SCJbAppendString(ctx.js, "tlsstore");
1271  }
1272  if (s->flags & SIG_FLAG_BYPASS) {
1273  SCJbAppendString(ctx.js, "bypass");
1274  }
1275  if (s->flags & SIG_FLAG_PREFILTER) {
1276  SCJbAppendString(ctx.js, "prefilter");
1277  }
1278  if (s->flags & SIG_FLAG_SRC_IS_TARGET) {
1279  SCJbAppendString(ctx.js, "src_is_target");
1280  }
1281  if (s->flags & SIG_FLAG_DEST_IS_TARGET) {
1282  SCJbAppendString(ctx.js, "dst_is_target");
1283  }
1284  SCJbClose(ctx.js);
1285 
1286  const DetectEnginePktInspectionEngine *pkt_mpm = NULL;
1287  const DetectEngineAppInspectionEngine *app_mpm = NULL;
1288 
1289  SCJbOpenArray(ctx.js, "pkt_engines");
1291  for ( ; pkt != NULL; pkt = pkt->next) {
1293  if (name == NULL) {
1294  switch (pkt->sm_list) {
1295  case DETECT_SM_LIST_PMATCH:
1296  name = "payload";
1297  break;
1298  case DETECT_SM_LIST_MATCH:
1299  name = "packet";
1300  break;
1301  default:
1302  name = "unknown";
1303  break;
1304  }
1305  }
1306  SCJbStartObject(ctx.js);
1307  SCJbSetString(ctx.js, "name", name);
1308  SCJbSetBool(ctx.js, "is_mpm", pkt->mpm);
1309  if (pkt->v1.transforms != NULL) {
1310  SCJbOpenArray(ctx.js, "transforms");
1311  for (int t = 0; t < pkt->v1.transforms->cnt; t++) {
1312  SCJbStartObject(ctx.js);
1313  SCJbSetString(ctx.js, "name",
1315  SCJbClose(ctx.js);
1316  }
1317  SCJbClose(ctx.js);
1318  }
1319  DumpMatches(&ctx, ctx.js, pkt->smd);
1320  SCJbClose(ctx.js);
1321  if (pkt->mpm) {
1322  pkt_mpm = pkt;
1323  }
1324  }
1325  SCJbClose(ctx.js);
1326  SCJbOpenArray(ctx.js, "frame_engines");
1328  for (; frame != NULL; frame = frame->next) {
1329  const char *name = DetectEngineBufferTypeGetNameById(de_ctx, frame->sm_list);
1330  SCJbStartObject(ctx.js);
1331  SCJbSetString(ctx.js, "name", name);
1332  SCJbSetBool(ctx.js, "is_mpm", frame->mpm);
1333  if (frame->v1.transforms != NULL) {
1334  SCJbOpenArray(ctx.js, "transforms");
1335  for (int t = 0; t < frame->v1.transforms->cnt; t++) {
1336  SCJbStartObject(ctx.js);
1337  SCJbSetString(ctx.js, "name",
1339  SCJbClose(ctx.js);
1340  }
1341  SCJbClose(ctx.js);
1342  }
1343  DumpMatches(&ctx, ctx.js, frame->smd);
1344  SCJbClose(ctx.js);
1345  }
1346  SCJbClose(ctx.js);
1347 
1349  bool has_stream = false;
1350  bool has_client_body_mpm = false;
1351  bool has_file_data_mpm = false;
1352 
1353  SCJbOpenArray(ctx.js, "engines");
1355  for ( ; app != NULL; app = app->next) {
1357  if (name == NULL) {
1358  switch (app->sm_list) {
1359  case DETECT_SM_LIST_PMATCH:
1360  name = "stream";
1361  break;
1362  default:
1363  name = "unknown";
1364  break;
1365  }
1366  }
1367 
1368  if (app->sm_list == DETECT_SM_LIST_PMATCH && !app->mpm) {
1369  has_stream = true;
1370  } else if (app->mpm && strcmp(name, "http_client_body") == 0) {
1371  has_client_body_mpm = true;
1372  } else if (app->mpm && strcmp(name, "file_data") == 0) {
1373  has_file_data_mpm = true;
1374  }
1375 
1376  SCJbStartObject(ctx.js);
1377  SCJbSetString(ctx.js, "name", name);
1378  const char *direction = app->dir == 0 ? "toserver" : "toclient";
1379  SCJbSetString(ctx.js, "direction", direction);
1380  SCJbSetBool(ctx.js, "is_mpm", app->mpm);
1381  SCJbSetString(ctx.js, "app_proto", AppProtoToString(app->alproto));
1382  SCJbSetUint(ctx.js, "progress", app->progress);
1383 
1384  if (app->v2.transforms != NULL) {
1385  SCJbOpenArray(ctx.js, "transforms");
1386  for (int t = 0; t < app->v2.transforms->cnt; t++) {
1387  SCJbStartObject(ctx.js);
1388  SCJbSetString(ctx.js, "name",
1390  SCJbClose(ctx.js);
1391  }
1392  SCJbClose(ctx.js);
1393  }
1394  DumpMatches(&ctx, ctx.js, app->smd);
1395  SCJbClose(ctx.js);
1396  if (app->mpm) {
1397  app_mpm = app;
1398  }
1399  }
1400  SCJbClose(ctx.js);
1401 
1402  if (has_stream && has_client_body_mpm)
1403  AnalyzerNote(&ctx, (char *)"mpm in http_client_body combined with stream match leads to stream buffering");
1404  if (has_stream && has_file_data_mpm)
1405  AnalyzerNote(&ctx, (char *)"mpm in file_data combined with stream match leads to stream buffering");
1406  }
1407 
1408  SCJbOpenObject(ctx.js, "lists");
1409  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
1410  if (s->sm_arrays[i] != NULL) {
1411  SCJbOpenObject(ctx.js, DetectListToHumanString(i));
1412  DumpMatches(&ctx, ctx.js, s->sm_arrays[i]);
1413  SCJbClose(ctx.js);
1414  }
1415  }
1416  SCJbClose(ctx.js);
1417 
1418  if (pkt_mpm || app_mpm) {
1419  SCJbOpenObject(ctx.js, "mpm");
1420 
1421  int mpm_list = pkt_mpm ? DETECT_SM_LIST_PMATCH : app_mpm->sm_list;
1422  const char *name;
1423  if (mpm_list < DETECT_SM_LIST_DYNAMIC_START)
1424  name = DetectListToHumanString(mpm_list);
1425  else
1427  SCJbSetString(ctx.js, "buffer", name);
1428 
1429  SigMatchData *smd = pkt_mpm ? pkt_mpm->smd : app_mpm->smd;
1430  if (smd == NULL && mpm_list == DETECT_SM_LIST_PMATCH) {
1431  smd = s->sm_arrays[mpm_list];
1432  }
1433  do {
1434  switch (smd->type) {
1435  case DETECT_CONTENT: {
1436  const DetectContentData *cd = (const DetectContentData *)smd->ctx;
1437  if (cd->flags & DETECT_CONTENT_MPM) {
1438  DumpContent(ctx.js, cd);
1439  }
1440  break;
1441  }
1442  }
1443 
1444  if (smd->is_last)
1445  break;
1446  smd++;
1447  } while (1);
1448  SCJbClose(ctx.js);
1449  } else if (s->init_data->prefilter_sm) {
1450  SCJbOpenObject(ctx.js, "prefilter");
1451  int prefilter_list = SigMatchListSMBelongsTo(s, s->init_data->prefilter_sm);
1452  const char *name;
1453  if (prefilter_list < DETECT_SM_LIST_DYNAMIC_START)
1454  name = DetectListToHumanString(prefilter_list);
1455  else
1456  name = DetectEngineBufferTypeGetNameById(de_ctx, prefilter_list);
1457  SCJbSetString(ctx.js, "buffer", name);
1458  const char *mname = sigmatch_table[s->init_data->prefilter_sm->type].name;
1459  SCJbSetString(ctx.js, "name", mname);
1460  SCJbClose(ctx.js);
1461  }
1462 
1463  if (ctx.js_warnings) {
1464  SCJbClose(ctx.js_warnings);
1465  SCJbSetObject(ctx.js, "warnings", ctx.js_warnings);
1466  SCJbFree(ctx.js_warnings);
1467  ctx.js_warnings = NULL;
1468  }
1469  if (ctx.js_notes) {
1470  SCJbClose(ctx.js_notes);
1471  SCJbSetObject(ctx.js, "notes", ctx.js_notes);
1472  SCJbFree(ctx.js_notes);
1473  ctx.js_notes = NULL;
1474  }
1475  SCJbClose(ctx.js);
1476 
1477  const char *filename = "rules.json";
1478  const char *log_dir = SCConfigGetLogDirectory();
1479  char json_path[PATH_MAX] = "";
1480  snprintf(json_path, sizeof(json_path), "%s/%s%s", log_dir,
1481  de_ctx->ea->file_prefix ? de_ctx->ea->file_prefix : "", filename);
1482 
1484  FILE *fp = fopen(json_path, "a");
1485  if (fp != NULL) {
1486  fwrite(SCJbPtr(ctx.js), SCJbLen(ctx.js), 1, fp);
1487  fprintf(fp, "\n");
1488  fclose(fp);
1489  }
1491  SCJbFree(ctx.js);
1492  SCReturn;
1493 }
1494 
1496 {
1497  if (de_ctx->pattern_hash_table == NULL)
1498  return;
1499 
1500  SCJsonBuilder *root_jb = SCJbNewObject();
1501  SCJsonBuilder *arrays[de_ctx->buffer_type_id];
1502  memset(&arrays, 0, sizeof(SCJsonBuilder *) * de_ctx->buffer_type_id);
1503 
1504  SCJbOpenArray(root_jb, "buffers");
1505 
1507  htb != NULL; htb = HashListTableGetListNext(htb)) {
1508  char str[1024] = "";
1510  DetectContentPatternPrettyPrint(p->cd, str, sizeof(str));
1511 
1512  SCJsonBuilder *jb = arrays[p->sm_list];
1513  if (arrays[p->sm_list] == NULL) {
1514  jb = arrays[p->sm_list] = SCJbNewObject();
1515  const char *name;
1518  else
1520  SCJbSetString(jb, "name", name);
1521  SCJbSetUint(jb, "list_id", p->sm_list);
1522 
1523  SCJbOpenArray(jb, "patterns");
1524  }
1525 
1526  SCJbStartObject(jb);
1527  SCJbSetString(jb, "pattern", str);
1528  SCJbSetUint(jb, "patlen", p->cd->content_len);
1529  SCJbSetUint(jb, "cnt", p->cnt);
1530  SCJbSetUint(jb, "mpm", p->mpm);
1531  SCJbOpenObject(jb, "flags");
1532  SCJbSetBool(jb, "nocase", p->cd->flags & DETECT_CONTENT_NOCASE);
1533  SCJbSetBool(jb, "negated", p->cd->flags & DETECT_CONTENT_NEGATED);
1534  SCJbSetBool(jb, "depth", p->cd->flags & DETECT_CONTENT_DEPTH);
1535  SCJbSetBool(jb, "offset", p->cd->flags & DETECT_CONTENT_OFFSET);
1536  SCJbSetBool(jb, "endswith", p->cd->flags & DETECT_CONTENT_ENDS_WITH);
1537  SCJbClose(jb);
1538  SCJbClose(jb);
1539  }
1540 
1541  for (uint32_t i = 0; i < de_ctx->buffer_type_id; i++) {
1542  SCJsonBuilder *jb = arrays[i];
1543  if (jb == NULL)
1544  continue;
1545 
1546  SCJbClose(jb); // array
1547  SCJbClose(jb); // object
1548 
1549  SCJbAppendObject(root_jb, jb);
1550  SCJbFree(jb);
1551  }
1552  SCJbClose(root_jb);
1553  SCJbClose(root_jb);
1554 
1555  const char *filename = "patterns.json";
1556  const char *log_dir = SCConfigGetLogDirectory();
1557  char json_path[PATH_MAX] = "";
1558  snprintf(json_path, sizeof(json_path), "%s/%s%s", log_dir,
1559  de_ctx->ea->file_prefix ? de_ctx->ea->file_prefix : "", filename);
1560 
1562  FILE *fp = fopen(json_path, "a");
1563  if (fp != NULL) {
1564  fwrite(SCJbPtr(root_jb), SCJbLen(root_jb), 1, fp);
1565  fprintf(fp, "\n");
1566  fclose(fp);
1567  }
1569  SCJbFree(root_jb);
1570 
1572  de_ctx->pattern_hash_table = NULL;
1573 }
1574 
1575 static void EngineAnalysisItemsReset(EngineAnalysisCtx *ea_ctx)
1576 {
1577  for (size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) {
1578  ea_ctx->analyzer_items[i].item_seen = false;
1579  }
1580 }
1581 
1582 static void EngineAnalysisItemsInit(EngineAnalysisCtx *ea_ctx)
1583 {
1584  if (ea_ctx->analyzer_initialized) {
1585  EngineAnalysisItemsReset(ea_ctx);
1586  return;
1587  }
1588 
1589  ea_ctx->exposed_item_seen_list[0].bufname = "http_method";
1590  ea_ctx->exposed_item_seen_list[1].bufname = "file_data";
1591  ea_ctx->analyzer_items = SCCalloc(1, sizeof(analyzer_items));
1592  if (!ea_ctx->analyzer_items) {
1593  FatalError("Unable to allocate analysis scratch pad");
1594  }
1595  memset(ea_ctx->analyzer_item_map, -1, sizeof(ea_ctx->analyzer_item_map));
1596 
1597  for (size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) {
1598  ea_ctx->analyzer_items[i] = analyzer_items[i];
1599  DetectEngineAnalyzerItems *analyzer_item = &ea_ctx->analyzer_items[i];
1600 
1601  int item_id = DetectBufferTypeGetByName(analyzer_item->item_name);
1602  DEBUG_VALIDATE_BUG_ON(item_id < 0 || item_id > UINT16_MAX);
1603  analyzer_item->item_id = (uint16_t)item_id;
1604  if (analyzer_item->item_id == -1) {
1605  /* Mismatch between the analyzer_items array and what's supported */
1606  FatalError("unable to initialize engine-analysis table: detect buffer \"%s\" not "
1607  "recognized.",
1608  analyzer_item->item_name);
1609  }
1610  analyzer_item->item_seen = false;
1611 
1612  if (analyzer_item->export_item_seen) {
1613  for (size_t k = 0; k < ARRAY_SIZE(ea_ctx->exposed_item_seen_list); k++) {
1614  if (0 ==
1615  strcmp(ea_ctx->exposed_item_seen_list[k].bufname, analyzer_item->item_name))
1616  ea_ctx->exposed_item_seen_list[k].item_seen_ptr = &analyzer_item->item_seen;
1617  }
1618  }
1619  ea_ctx->analyzer_item_map[analyzer_item->item_id] = (int16_t)i;
1620  }
1621 
1622  ea_ctx->analyzer_initialized = true;
1623 }
1624 
1625 /**
1626  * \brief Prints analysis of loaded rules.
1627  *
1628  * Warns if potential rule issues are detected. For example,
1629  * warns if a rule uses a construct that may perform poorly,
1630  * e.g. pcre without content or with http_method content only;
1631  * warns if a rule uses a construct that may not be consistent with intent,
1632  * e.g. client side ports only, http and content without any http_* modifiers, etc.
1633  *
1634  * \param s Pointer to the signature.
1635  */
1637  const Signature *s, const char *line)
1638 {
1639  uint32_t rule_bidirectional = 0;
1640  uint32_t rule_pcre = 0;
1641  uint32_t rule_pcre_http = 0;
1642  uint32_t rule_content = 0;
1643  uint32_t rule_flow = 0;
1644  uint32_t rule_flags = 0;
1645  uint32_t rule_flow_toserver = 0;
1646  uint32_t rule_flow_toclient = 0;
1647  uint32_t rule_flow_nostream = 0;
1648  uint32_t rule_ipv4_only = 0;
1649  uint32_t rule_ipv6_only = 0;
1650  uint32_t rule_flowbits = 0;
1651  uint32_t rule_flowint = 0;
1652  uint32_t rule_content_http = 0;
1653  uint32_t rule_content_offset_depth = 0;
1654  int32_t list_id = 0;
1655  uint32_t rule_warning = 0;
1656  uint32_t stream_buf = 0;
1657  uint32_t packet_buf = 0;
1658  uint32_t file_store = 0;
1659  uint32_t warn_pcre_no_content = 0;
1660  uint32_t warn_pcre_http_content = 0;
1661  uint32_t warn_pcre_http = 0;
1662  uint32_t warn_content_http_content = 0;
1663  uint32_t warn_content_http = 0;
1664  uint32_t warn_tcp_no_flow = 0;
1665  uint32_t warn_client_ports = 0;
1666  uint32_t warn_direction = 0;
1667  uint32_t warn_method_toclient = 0;
1668  uint32_t warn_method_serverbody = 0;
1669  uint32_t warn_pcre_method = 0;
1670  uint32_t warn_encoding_norm_http_buf = 0;
1671  uint32_t warn_file_store_not_present = 0;
1672  uint32_t warn_offset_depth_pkt_stream = 0;
1673  uint32_t warn_offset_depth_alproto = 0;
1674  uint32_t warn_non_alproto_fp_for_alproto_sig = 0;
1675  uint32_t warn_no_direction = 0;
1676  uint32_t warn_both_direction = 0;
1677 
1678  EngineAnalysisItemsInit(de_ctx->ea);
1679 
1680  bool *http_method_item_seen_ptr = de_ctx->ea->exposed_item_seen_list[0].item_seen_ptr;
1681  bool *http_server_body_item_seen_ptr = de_ctx->ea->exposed_item_seen_list[1].item_seen_ptr;
1682 
1684  rule_bidirectional = 1;
1685  }
1686 
1687  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
1688  packet_buf += 1;
1689  }
1690  if (s->flags & SIG_FLAG_FILESTORE) {
1691  file_store += 1;
1692  }
1693  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
1694  stream_buf += 1;
1695  }
1696 
1697  if (s->proto.flags & DETECT_PROTO_IPV4) {
1698  rule_ipv4_only += 1;
1699  }
1700  if (s->proto.flags & DETECT_PROTO_IPV6) {
1701  rule_ipv6_only += 1;
1702  }
1703 
1704  for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) {
1705  SigMatch *sm = NULL;
1706  for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) {
1707  int16_t item_slot = de_ctx->ea->analyzer_item_map[list_id];
1708  if (sm->type == DETECT_PCRE) {
1709  if (item_slot == -1) {
1710  rule_pcre++;
1711  continue;
1712  }
1713 
1714  rule_pcre_http++;
1715  de_ctx->ea->analyzer_items[item_slot].item_seen = true;
1716  } else if (sm->type == DETECT_CONTENT) {
1717  if (item_slot == -1) {
1718  rule_content++;
1719  if (list_id == DETECT_SM_LIST_PMATCH) {
1722  rule_content_offset_depth++;
1723  }
1724  }
1725  continue;
1726  }
1727 
1728  rule_content_http++;
1729  de_ctx->ea->analyzer_items[item_slot].item_seen = true;
1730 
1731  if (de_ctx->ea->analyzer_items[item_slot].check_encoding_match) {
1733  if (cd != NULL &&
1734  PerCentEncodingMatch(de_ctx->ea, cd->content, cd->content_len) > 0) {
1735  warn_encoding_norm_http_buf += 1;
1736  }
1737  }
1738  }
1739  else if (sm->type == DETECT_FLOW) {
1740  rule_flow += 1;
1741  if ((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) {
1742  rule_flow_toserver = 1;
1743  }
1744  else if ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_TOSERVER)) {
1745  rule_flow_toclient = 1;
1746  }
1747  DetectFlowData *fd = (DetectFlowData *)sm->ctx;
1748  if (fd != NULL) {
1749  if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM)
1750  rule_flow_nostream = 1;
1751  }
1752  }
1753  else if (sm->type == DETECT_FLOWBITS) {
1754  if (list_id == DETECT_SM_LIST_MATCH) {
1755  rule_flowbits += 1;
1756  }
1757  }
1758  else if (sm->type == DETECT_FLOWINT) {
1759  if (list_id == DETECT_SM_LIST_MATCH) {
1760  rule_flowint += 1;
1761  }
1762  }
1763  else if (sm->type == DETECT_FLAGS) {
1764  if (sm->ctx != NULL) {
1765  rule_flags = 1;
1766  }
1767  }
1768  } /* for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) */
1769 
1770  } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */
1771 
1772  if (file_store && !SCRequiresFeature("output::file-store")) {
1773  rule_warning += 1;
1774  warn_file_store_not_present = 1;
1775  }
1776 
1777  if (rule_pcre > 0 && rule_content == 0 && rule_content_http == 0) {
1778  rule_warning += 1;
1779  warn_pcre_no_content = 1;
1780  }
1781 
1782  if (rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0) {
1783  rule_warning += 1;
1784  warn_pcre_http_content = 1;
1785  } else if (s->alproto == ALPROTO_HTTP1 && rule_pcre > 0 && rule_pcre_http == 0) {
1786  rule_warning += 1;
1787  warn_pcre_http = 1;
1788  }
1789 
1790  if (rule_content > 0 && rule_content_http > 0) {
1791  rule_warning += 1;
1792  warn_content_http_content = 1;
1793  }
1794  if (s->alproto == ALPROTO_HTTP1 && rule_content > 0 && rule_content_http == 0) {
1795  rule_warning += 1;
1796  warn_content_http = 1;
1797  }
1798  if (rule_content == 1) {
1799  //todo: warning if content is weak, separate warning for pcre + weak content
1800  }
1801  if (rule_flow == 0 && rule_flags == 0 && !(s->proto.flags & DETECT_PROTO_ANY) &&
1802  DetectProtoContainsProto(&s->proto, IPPROTO_TCP) &&
1803  (rule_content || rule_content_http || rule_pcre || rule_pcre_http || rule_flowbits ||
1804  rule_flowint)) {
1805  rule_warning += 1;
1806  warn_tcp_no_flow = 1;
1807  }
1808  if (rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)
1809  && !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))) {
1810  if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))
1811  || ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && (s->flags & SIG_FLAG_SP_ANY))) {
1812  rule_warning += 1;
1813  warn_client_ports = 1;
1814  }
1815  }
1816  if (rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)) {
1817  rule_warning += 1;
1818  warn_direction = 1;
1819  }
1820 
1821  if (*http_method_item_seen_ptr) {
1822  if (rule_flow && rule_flow_toclient) {
1823  rule_warning += 1;
1824  warn_method_toclient = 1;
1825  }
1826  if (*http_server_body_item_seen_ptr) {
1827  rule_warning += 1;
1828  warn_method_serverbody = 1;
1829  }
1830  if (rule_content == 0 && rule_content_http == 0 && (rule_pcre > 0 || rule_pcre_http > 0)) {
1831  rule_warning += 1;
1832  warn_pcre_method = 1;
1833  }
1834  }
1835  if (rule_content_offset_depth > 0 && stream_buf && packet_buf) {
1836  rule_warning += 1;
1837  warn_offset_depth_pkt_stream = 1;
1838  }
1839  if (rule_content_offset_depth > 0 && !stream_buf && packet_buf && s->alproto != ALPROTO_UNKNOWN) {
1840  rule_warning += 1;
1841  warn_offset_depth_alproto = 1;
1842  }
1843  if (s->init_data->mpm_sm != NULL && s->alproto == ALPROTO_HTTP1 &&
1845  rule_warning += 1;
1846  warn_non_alproto_fp_for_alproto_sig = 1;
1847  }
1848 
1849  if ((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
1850  warn_no_direction += 1;
1851  rule_warning += 1;
1852  }
1853 
1854  /* No warning about direction for ICMP protos */
1855  if (!(DetectProtoContainsProto(&s->proto, IPPROTO_ICMPV6) && DetectProtoContainsProto(&s->proto, IPPROTO_ICMP))) {
1857  warn_both_direction += 1;
1858  rule_warning += 1;
1859  }
1860  }
1861 
1862  if (!rule_warnings_only || (rule_warnings_only && rule_warning > 0)) {
1863  FILE *fp = de_ctx->ea->rule_engine_analysis_fp;
1864  fprintf(fp, "== Sid: %u ==\n", s->id);
1865  fprintf(fp, "%s\n", line);
1866 
1867  switch (s->type) {
1868  case SIG_TYPE_NOT_SET:
1869  break;
1870  case SIG_TYPE_IPONLY:
1871  fprintf(fp, " Rule is ip only.\n");
1872  break;
1873  case SIG_TYPE_LIKE_IPONLY:
1874  fprintf(fp, " Rule is like ip only.\n");
1875  break;
1876  case SIG_TYPE_PDONLY:
1877  fprintf(fp, " Rule is PD only.\n");
1878  break;
1879  case SIG_TYPE_DEONLY:
1880  fprintf(fp, " Rule is DE only.\n");
1881  break;
1882  case SIG_TYPE_PKT:
1883  fprintf(fp, " Rule is packet inspecting.\n");
1884  break;
1885  case SIG_TYPE_PKT_STREAM:
1886  fprintf(fp, " Rule is packet and stream inspecting.\n");
1887  break;
1888  case SIG_TYPE_STREAM:
1889  fprintf(fp, " Rule is stream inspecting.\n");
1890  break;
1891  case SIG_TYPE_APPLAYER:
1892  fprintf(fp, " Rule is app-layer inspecting.\n");
1893  break;
1894  case SIG_TYPE_APP_TX:
1895  fprintf(fp, " Rule is App-layer TX inspecting.\n");
1896  break;
1897  case SIG_TYPE_MAX:
1898  break;
1899  }
1900  if (rule_ipv6_only)
1901  fprintf(fp, " Rule is IPv6 only.\n");
1902  if (rule_ipv4_only)
1903  fprintf(fp, " Rule is IPv4 only.\n");
1904  if (packet_buf)
1905  fprintf(fp, " Rule matches on packets.\n");
1906  if (!rule_flow_nostream && stream_buf &&
1907  (rule_flow || rule_flowbits || rule_flowint || rule_content || rule_pcre)) {
1908  fprintf(fp, " Rule matches on reassembled stream.\n");
1909  }
1910  for(size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) {
1912  if (ai->item_seen) {
1913  fprintf(fp, " Rule matches on %s buffer.\n", ai->display_name);
1914  }
1915  }
1916  if (s->alproto != ALPROTO_UNKNOWN) {
1917  fprintf(fp, " App layer protocol is %s.\n", AppProtoToString(s->alproto));
1918  }
1919  if (rule_content || rule_content_http || rule_pcre || rule_pcre_http) {
1920  fprintf(fp,
1921  " Rule contains %u content options, %u http content options, %u pcre "
1922  "options, and %u pcre options with http modifiers.\n",
1923  rule_content, rule_content_http, rule_pcre, rule_pcre_http);
1924  }
1925 
1926  /* print fast pattern info */
1927  if (s->init_data->prefilter_sm) {
1928  fprintf(fp, " Prefilter on: %s.\n",
1930  } else {
1931  EngineAnalysisRulesPrintFP(de_ctx, s);
1932  }
1933 
1934  /* this is where the warnings start */
1935  if (warn_pcre_no_content /*rule_pcre > 0 && rule_content == 0 && rule_content_http == 0*/) {
1936  fprintf(fp, " Warning: Rule uses pcre without a content option present.\n"
1937  " -Consider adding a content to improve performance of this "
1938  "rule.\n");
1939  }
1940  if (warn_pcre_http_content /*rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0*/) {
1941  fprintf(fp, " Warning: Rule uses content options with http_* and pcre options "
1942  "without http modifiers.\n"
1943  " -Consider adding http pcre modifier.\n");
1944  }
1945  else if (warn_pcre_http /*s->alproto == ALPROTO_HTTP1 && rule_pcre > 0 && rule_pcre_http == 0*/) {
1946  fprintf(fp, " Warning: Rule app layer protocol is http, but pcre options do not "
1947  "have http modifiers.\n"
1948  " -Consider adding http pcre modifiers.\n");
1949  }
1950  if (warn_content_http_content /*rule_content > 0 && rule_content_http > 0*/) {
1951  fprintf(fp,
1952  " Warning: Rule contains content with http_* and content without http_*.\n"
1953  " -Consider adding http content modifiers.\n");
1954  }
1955  if (warn_content_http /*s->alproto == ALPROTO_HTTP1 && rule_content > 0 && rule_content_http == 0*/) {
1956  fprintf(fp, " Warning: Rule app layer protocol is http, but content options do not "
1957  "have http_* modifiers.\n"
1958  " -Consider adding http content modifiers.\n");
1959  }
1960  if (rule_content == 1) {
1961  //todo: warning if content is weak, separate warning for pcre + weak content
1962  }
1963  if (warn_encoding_norm_http_buf) {
1964  fprintf(fp, " Warning: Rule may contain percent encoded content for a normalized "
1965  "http buffer match.\n");
1966  }
1967  if (warn_tcp_no_flow /*rule_flow == 0 && rule_flags == 0
1968  && !(s->proto.flags & DETECT_PROTO_ANY) && DetectProtoContainsProto(&s->proto, IPPROTO_TCP)*/) {
1969  fprintf(fp, " Warning: TCP rule without a flow or flags option.\n"
1970  " -Consider adding flow or flags to improve performance of "
1971  "this rule.\n");
1972  }
1973  if (warn_client_ports /*rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)
1974  && !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY)))
1975  if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))
1976  || ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && (s->flags & SIG_FLAG_SP_ANY))*/) {
1977  fprintf(fp,
1978  " Warning: Rule contains ports or port variables only on the client side.\n"
1979  " -Flow direction possibly inconsistent with rule.\n");
1980  }
1981  if (warn_direction /*rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)*/) {
1982  fprintf(fp, " Warning: Rule is bidirectional and has a flow option with a specific "
1983  "direction.\n");
1984  }
1985  if (warn_method_toclient /*http_method_buf && rule_flow && rule_flow_toclient*/) {
1986  fprintf(fp, " Warning: Rule uses content or pcre for http_method with "
1987  "flow:to_client or from_server\n");
1988  }
1989  if (warn_method_serverbody /*http_method_buf && http_server_body_buf*/) {
1990  fprintf(fp, " Warning: Rule uses content or pcre for http_method with content or "
1991  "pcre for http_server_body.\n");
1992  }
1993  if (warn_pcre_method /*http_method_buf && rule_content == 0 && rule_content_http == 0
1994  && (rule_pcre > 0 || rule_pcre_http > 0)*/) {
1995  fprintf(fp, " Warning: Rule uses pcre with only a http_method content; possible "
1996  "performance issue.\n");
1997  }
1998  if (warn_offset_depth_pkt_stream) {
1999  fprintf(fp, " Warning: Rule has depth"
2000  "/offset with raw content keywords. Please note the "
2001  "offset/depth will be checked against both packet "
2002  "payloads and stream. If you meant to have the offset/"
2003  "depth checked against just the payload, you can update "
2004  "the signature as \"alert tcp-pkt...\"\n");
2005  }
2006  if (warn_offset_depth_alproto) {
2007  fprintf(fp,
2008  " Warning: Rule has "
2009  "offset/depth set along with a match on a specific "
2010  "app layer protocol - %d. This can lead to FNs if we "
2011  "have a offset/depth content match on a packet payload "
2012  "before we can detect the app layer protocol for the "
2013  "flow.\n",
2014  s->alproto);
2015  }
2016  if (warn_non_alproto_fp_for_alproto_sig) {
2017  fprintf(fp, " Warning: Rule app layer "
2018  "protocol is http, but the fast_pattern is set on the raw "
2019  "stream. Consider adding fast_pattern over a http "
2020  "buffer for increased performance.");
2021  }
2022  if (warn_no_direction) {
2023  fprintf(fp, " Warning: Rule has no direction indicator.\n");
2024  }
2025  if (warn_both_direction) {
2026  fprintf(fp, " Warning: Rule is inspecting both the request and the response.\n");
2027  }
2028  if (warn_file_store_not_present) {
2029  fprintf(fp, " Warning: Rule requires file-store but the output file-store is not "
2030  "enabled.\n");
2031  }
2032  if (rule_warning == 0) {
2033  fprintf(fp, " No warnings for this rule.\n");
2034  }
2035  fprintf(fp, "\n");
2036  }
2037 }
2038 
2039 #include "app-layer-parser.h"
2040 
2041 static void FirewallAddRulesForState(const DetectEngineCtx *de_ctx, const AppProto a,
2042  const uint8_t state, const uint8_t direction, RuleAnalyzer *ctx)
2043 {
2044  uint32_t accept_rules = 0;
2045  SCJbSetString(ctx->js, "policy", "drop:flow");
2046  SCJbOpenArray(ctx->js, "rules");
2047  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
2048  if ((s->flags & SIG_FLAG_FIREWALL) == 0)
2049  break;
2050  if (s->type != SIG_TYPE_APP_TX)
2051  continue;
2052  if (s->alproto != a)
2053  continue;
2054 
2055  if (direction == STREAM_TOSERVER) {
2056  if (s->flags & SIG_FLAG_TOCLIENT) {
2057  continue;
2058  }
2059  } else {
2060  if (s->flags & SIG_FLAG_TOSERVER) {
2061  continue;
2062  }
2063  }
2064 
2065  if (s->app_progress_hook == state) {
2066  SCJbAppendString(ctx->js, s->sig_str);
2067  accept_rules += ((s->action & ACTION_ACCEPT) != 0);
2068  }
2069  }
2070  SCJbClose(ctx->js);
2071 
2072  if (accept_rules == 0) {
2073  AnalyzerWarning(ctx, (char *)"no accept rules for state, default policy will be applied");
2074  }
2075 }
2076 
2078 {
2079  RuleAnalyzer ctx = { NULL, NULL, NULL };
2080  ctx.js = SCJbNewObject();
2081  if (ctx.js == NULL)
2082  return -1;
2083 
2084  SCJbOpenObject(ctx.js, "tables");
2085  SCJbOpenObject(ctx.js, "packet:filter");
2086  SCJbSetString(ctx.js, "policy", "drop:packet");
2087  SCJbOpenArray(ctx.js, "rules");
2088  uint32_t accept_rules = 0;
2089  uint32_t last_sid = 0;
2090  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
2091  if ((s->flags & SIG_FLAG_FIREWALL) == 0)
2092  break;
2093  if (s->type != SIG_TYPE_PKT)
2094  continue;
2095  /* don't double list <> sigs */
2096  if (last_sid == s->id)
2097  continue;
2098  last_sid = s->id;
2099  SCJbAppendString(ctx.js, s->sig_str);
2100  accept_rules += ((s->action & ACTION_ACCEPT) != 0);
2101  }
2102  SCJbClose(ctx.js);
2103  if (accept_rules == 0) {
2104  AnalyzerWarning(&ctx,
2105  (char *)"no accept rules for \'packet:filter\', default policy will be applied");
2106  }
2107  if (ctx.js_warnings) {
2108  SCJbClose(ctx.js_warnings);
2109  SCJbSetObject(ctx.js, "warnings", ctx.js_warnings);
2110  SCJbFree(ctx.js_warnings);
2111  ctx.js_warnings = NULL;
2112  }
2113  SCJbClose(ctx.js); // packet_filter
2114 
2115  for (AppProto a = 0; a < g_alproto_max; a++) {
2116  if (!AppProtoIsValid(a))
2117  continue;
2118 
2119  // HACK not all protocols have named states yet
2120  const char *hack = AppLayerParserGetStateNameById(IPPROTO_TCP, a, 0, STREAM_TOSERVER);
2121  if (!hack)
2122  continue;
2123 
2124  SCJbOpenObject(ctx.js, AppProtoToString(a));
2125  const uint8_t complete_state_ts =
2126  (const uint8_t)AppLayerParserGetStateProgressCompletionStatus(a, STREAM_TOSERVER);
2127  for (uint8_t state = 0; state < complete_state_ts; state++) {
2128  const char *name =
2129  AppLayerParserGetStateNameById(IPPROTO_TCP, a, state, STREAM_TOSERVER);
2130  char table_name[128];
2131  snprintf(table_name, sizeof(table_name), "app:%s:%s", AppProtoToString(a), name);
2132  SCJbOpenObject(ctx.js, table_name);
2133  FirewallAddRulesForState(de_ctx, a, state, STREAM_TOSERVER, &ctx);
2134  if (ctx.js_warnings) {
2135  SCJbClose(ctx.js_warnings);
2136  SCJbSetObject(ctx.js, "warnings", ctx.js_warnings);
2137  SCJbFree(ctx.js_warnings);
2138  ctx.js_warnings = NULL;
2139  }
2140  SCJbClose(ctx.js);
2141  }
2142  const uint8_t complete_state_tc =
2143  (const uint8_t)AppLayerParserGetStateProgressCompletionStatus(a, STREAM_TOCLIENT);
2144  for (uint8_t state = 0; state < complete_state_tc; state++) {
2145  const char *name =
2146  AppLayerParserGetStateNameById(IPPROTO_TCP, a, state, STREAM_TOCLIENT);
2147  char table_name[128];
2148  snprintf(table_name, sizeof(table_name), "app:%s:%s", AppProtoToString(a), name);
2149  SCJbOpenObject(ctx.js, table_name);
2150  FirewallAddRulesForState(de_ctx, a, state, STREAM_TOCLIENT, &ctx);
2151  if (ctx.js_warnings) {
2152  SCJbClose(ctx.js_warnings);
2153  SCJbSetObject(ctx.js, "warnings", ctx.js_warnings);
2154  SCJbFree(ctx.js_warnings);
2155  ctx.js_warnings = NULL;
2156  }
2157  SCJbClose(ctx.js);
2158  }
2159  SCJbClose(ctx.js); // app layer
2160  }
2161  SCJbOpenObject(ctx.js, "packet:td");
2162  SCJbSetString(ctx.js, "policy", "accept:hook");
2163  last_sid = 0;
2164  SCJbOpenArray(ctx.js, "rules");
2165  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
2166  if ((s->flags & SIG_FLAG_FIREWALL) != 0)
2167  continue;
2168  if (s->type == SIG_TYPE_APP_TX)
2169  continue;
2170  if (last_sid == s->id)
2171  continue;
2172  last_sid = s->id;
2173  SCJbAppendString(ctx.js, s->sig_str);
2174  }
2175  SCJbClose(ctx.js); // rules
2176  SCJbClose(ctx.js); // packet:td
2177  SCJbOpenObject(ctx.js, "app:td");
2178  SCJbSetString(ctx.js, "policy", "accept:hook");
2179  last_sid = 0;
2180  SCJbOpenArray(ctx.js, "rules");
2181  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
2182  if ((s->flags & SIG_FLAG_FIREWALL) != 0)
2183  continue;
2184  if (s->type != SIG_TYPE_APP_TX)
2185  continue;
2186  if (last_sid == s->id)
2187  continue;
2188  last_sid = s->id;
2189  SCJbAppendString(ctx.js, s->sig_str);
2190  }
2191  SCJbClose(ctx.js); // rules
2192  SCJbClose(ctx.js); // app:td
2193  SCJbClose(ctx.js); // tables
2194 
2195  SCJbOpenObject(ctx.js, "lists");
2196  SCJbOpenObject(ctx.js, "firewall");
2197  last_sid = 0;
2198  SCJbOpenArray(ctx.js, "rules");
2199  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
2200  if ((s->flags & SIG_FLAG_FIREWALL) == 0)
2201  continue;
2202  if (last_sid == s->id)
2203  continue;
2204  last_sid = s->id;
2205  SCJbAppendString(ctx.js, s->sig_str);
2206  }
2207  SCJbClose(ctx.js); // rules
2208  SCJbClose(ctx.js); // firewall
2209 
2210  SCJbOpenObject(ctx.js, "td");
2211  last_sid = 0;
2212  SCJbOpenArray(ctx.js, "rules");
2213  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
2214  if ((s->flags & SIG_FLAG_FIREWALL) != 0)
2215  continue;
2216  if (last_sid == s->id)
2217  continue;
2218  last_sid = s->id;
2219  SCJbAppendString(ctx.js, s->sig_str);
2220  }
2221  SCJbClose(ctx.js); // rules
2222  SCJbClose(ctx.js); // td
2223 
2224  SCJbOpenObject(ctx.js, "all");
2225  last_sid = 0;
2226  SCJbOpenArray(ctx.js, "rules");
2227  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
2228  if (last_sid == s->id)
2229  continue;
2230  last_sid = s->id;
2231  SCJbAppendString(ctx.js, s->sig_str);
2232  }
2233  SCJbClose(ctx.js); // rules
2234  SCJbClose(ctx.js); // all
2235 
2236  SCJbClose(ctx.js); // lists
2237 
2238  SCJbClose(ctx.js); // top level object
2239 
2240  const char *filename = "firewall.json";
2241  const char *log_dir = SCConfigGetLogDirectory();
2242  char json_path[PATH_MAX] = "";
2243  snprintf(json_path, sizeof(json_path), "%s/%s", log_dir, filename);
2244 
2246  FILE *fp = fopen(json_path, "w");
2247  if (fp != NULL) {
2248  fwrite(SCJbPtr(ctx.js), SCJbLen(ctx.js), 1, fp);
2249  fprintf(fp, "\n");
2250  fclose(fp);
2251  }
2253  SCJbFree(ctx.js);
2254  return 0;
2255 }
detect-tcp-flags.h
DETECT_PCRE_CASELESS
#define DETECT_PCRE_CASELESS
Definition: detect-pcre.h:32
DETECT_CONTENT_NOCASE
#define DETECT_CONTENT_NOCASE
Definition: detect-content.h:29
SignatureHasPacketContent
int SignatureHasPacketContent(const Signature *s)
check if a signature has patterns that are to be inspected against a packets payload (as opposed to t...
Definition: detect-engine-mpm.c:853
DetectBytejumpData_::post_offset
int32_t post_offset
Definition: detect-bytejump.h:51
HashListTableGetListData
#define HashListTableGetListData(hb)
Definition: util-hashlist.h:56
SIG_TYPE_STREAM
@ SIG_TYPE_STREAM
Definition: detect.h:74
DetectContentData_::offset
uint16_t offset
Definition: detect-content.h:107
DetectBytetestData_::flags
uint16_t flags
Definition: detect-bytetest.h:58
detect-engine-uint.h
DetectPatternTracker
Definition: detect.h:809
SignatureInitData_::rule_state_dependant_sids_idx
uint32_t rule_state_dependant_sids_idx
Definition: detect.h:659
DetectEngineAppInspectionEngine_
Definition: detect.h:416
DETECT_CONTENT_RELATIVE_NEXT
#define DETECT_CONTENT_RELATIVE_NEXT
Definition: detect-content.h:66
DetectEngineAppInspectionEngine_::mpm
bool mpm
Definition: detect.h:420
DETECT_TTL
@ DETECT_TTL
Definition: detect-engine-register.h:45
detect-content.h
DetectFlowbitsData_::or_list_size
uint8_t or_list_size
Definition: detect-flowbits.h:38
len
uint8_t len
Definition: app-layer-dnp3.h:2
DetectEngineAppInspectionEngine_::v2
struct DetectEngineAppInspectionEngine_::@82 v2
SCConfValIsTrue
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:551
detect-engine.h
DETECT_SM_LIST_PMATCH
@ DETECT_SM_LIST_PMATCH
Definition: detect.h:119
SIG_MASK_REQUIRE_REAL_PKT
#define SIG_MASK_REQUIRE_REAL_PKT
Definition: detect.h:316
DETECT_CONTENT_FAST_PATTERN_CHOP
#define DETECT_CONTENT_FAST_PATTERN_CHOP
Definition: detect-content.h:36
SignatureInitData_::smlists
struct SigMatch_ * smlists[DETECT_SM_LIST_MAX]
Definition: detect.h:642
DetectContentData_::fp_chop_len
uint16_t fp_chop_len
Definition: detect-content.h:98
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
Signature_::sig_str
char * sig_str
Definition: detect.h:745
SIG_TYPE_APP_TX
@ SIG_TYPE_APP_TX
Definition: detect.h:77
AppLayerParserGetStateNameById
const char * AppLayerParserGetStateNameById(uint8_t ipproto, AppProto alproto, const int id, const uint8_t direction)
Definition: app-layer-parser.c:1603
DetectEnginePktInspectionEngine
Definition: detect.h:483
DetectEngineAppInspectionEngine_::next
struct DetectEngineAppInspectionEngine_ * next
Definition: detect.h:441
DETECT_PROTO_IPV6
#define DETECT_PROTO_IPV6
Definition: detect-engine-proto.h:32
DetectFlowData_
Definition: detect-flow.h:37
DETECT_FLOW_FLAG_NOSTREAM
#define DETECT_FLOW_FLAG_NOSTREAM
Definition: detect-flow.h:33
SigTableElmt_::name
const char * name
Definition: detect.h:1458
DETECT_BYTEJUMP
@ DETECT_BYTEJUMP
Definition: detect-engine-register.h:83
DetectPatternTracker::mpm
uint32_t mpm
Definition: detect.h:813
DETECT_ABSENT
@ DETECT_ABSENT
Definition: detect-engine-register.h:95
DetectListToHumanString
const char * DetectListToHumanString(int list)
Definition: detect-parse.c:112
DetectEngineCtx_::pattern_hash_table
HashListTable * pattern_hash_table
Definition: detect.h:966
DumpPatterns
void DumpPatterns(DetectEngineCtx *de_ctx)
Definition: detect-engine-analyzer.c:1495
FLOWINT_MODIFIER_ADD
@ FLOWINT_MODIFIER_ADD
Definition: detect-flowint.h:31
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
DetectContentData_::within
int32_t within
Definition: detect-content.h:109
ACTION_PASS
#define ACTION_PASS
Definition: action-globals.h:34
ACTION_REJECT
#define ACTION_REJECT
Definition: action-globals.h:31
DETECT_BYTEJUMP_LITTLE
#define DETECT_BYTEJUMP_LITTLE
Definition: detect-bytejump.h:35
SetupEngineAnalysis
void SetupEngineAnalysis(DetectEngineCtx *de_ctx, bool *fp_analysis, bool *rule_analysis)
Definition: detect-engine-analyzer.c:476
Signature_::app_progress_hook
uint8_t app_progress_hook
Definition: detect.h:705
DETECT_CONTENT
@ DETECT_CONTENT
Definition: detect-engine-register.h:69
SignatureInitData_::prefilter_sm
SigMatch * prefilter_sm
Definition: detect.h:625
EngineAnalysisCtx_::rule_engine_analysis_fp
FILE * rule_engine_analysis_fp
Definition: detect-engine-analyzer.c:87
DETECT_FLOW
@ DETECT_FLOW
Definition: detect-engine-register.h:54
Signature_::alproto
AppProto alproto
Definition: detect.h:673
SignatureInitData_::is_rule_state_dependant
bool is_rule_state_dependant
Definition: detect.h:656
detect-isdataat.h
FLOWINT_MODIFIER_NE
@ FLOWINT_MODIFIER_NE
Definition: detect-flowint.h:38
DETECT_BYTETEST_BASE_HEX
#define DETECT_BYTETEST_BASE_HEX
Definition: detect-bytetest.h:40
SigMatchData_::is_last
bool is_last
Definition: detect.h:367
g_rules_analyzer_write_m
SCMutex g_rules_analyzer_write_m
Definition: detect-engine-analyzer.c:1047
DetectEngineAnalyzerItems::display_name
const char * display_name
Definition: detect-engine-analyzer.c:69
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:86
DETECT_CONTENT_WITHIN2DEPTH
#define DETECT_CONTENT_WITHIN2DEPTH
Definition: detect-content.h:62
EngineAnalysisCtx_::percent_re
pcre2_code * percent_re
Definition: detect-engine-analyzer.c:92
DETECT_SM_LIST_DYNAMIC_START
@ DETECT_SM_LIST_DYNAMIC_START
Definition: detect.h:138
DETECT_FLOWBITS_CMD_ISNOTSET
#define DETECT_FLOWBITS_CMD_ISNOTSET
Definition: detect-flowbits.h:31
SIG_FLAG_DEST_IS_TARGET
#define SIG_FLAG_DEST_IS_TARGET
Definition: detect.h:285
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:368
DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED
#define DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED
Definition: detect-content.h:55
DetectFlowintData_::targettype
uint8_t targettype
Definition: detect-flowint.h:71
action-globals.h
EngineAnalysisCtx_
Definition: detect-engine-analyzer.c:85
DETECT_IPOPTS
@ DETECT_IPOPTS
Definition: detect-engine-register.h:39
AppProtoToString
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
Definition: app-layer-protos.c:41
ctx
struct Thresholds ctx
DETECT_BYTEJUMP_BASE_OCT
#define DETECT_BYTEJUMP_BASE_OCT
Definition: detect-bytejump.h:29
DetectEngineFrameInspectionEngine::transforms
const DetectEngineTransforms * transforms
Definition: detect.h:518
DetectFlowData_::flags
uint16_t flags
Definition: detect-flow.h:38
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:933
DETECT_PROTO_ANY
#define DETECT_PROTO_ANY
Definition: detect-engine-proto.h:28
DetectFlowintData_
Definition: detect-flowint.h:61
DetectEnginePktInspectionEngine::smd
SigMatchData * smd
Definition: detect.h:484
AppLayerParserGetStateProgressCompletionStatus
int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, uint8_t direction)
Definition: app-layer-parser.c:1102
SIG_TYPE_PKT_STREAM
@ SIG_TYPE_PKT_STREAM
Definition: detect.h:73
DetectFlowbitsData_::cmd
uint8_t cmd
Definition: detect-flowbits.h:37
DetectEngineFrameInspectionEngine::mpm
bool mpm
Definition: detect.h:512
DETECT_BYTETEST_DCE
#define DETECT_BYTETEST_DCE
Definition: detect-bytetest.h:47
HashListTableGetListHead
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
Definition: util-hashlist.c:287
detect-tcp-seq.h
EngineAnalysisCtx_::fp_pattern_stats
FpPatternStats fp_pattern_stats[DETECT_SM_LIST_MAX]
Definition: detect-engine-analyzer.c:104
detect-flowint.h
DetectEngineBufferTypeGetNameById
const char * DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1308
SIG_FLAG_DST_ANY
#define SIG_FLAG_DST_ANY
Definition: detect.h:242
ACTION_SCOPE_FLOW
@ ACTION_SCOPE_FLOW
Definition: action-globals.h:45
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
util-var-name.h
SIG_FLAG_REQUIRE_STREAM
#define SIG_FLAG_REQUIRE_STREAM
Definition: detect.h:255
DetectPatternTracker::cnt
uint32_t cnt
Definition: detect.h:812
rust.h
EngineAnalysisCtx_::fp_engine_analysis_fp
FILE * fp_engine_analysis_fp
Definition: detect-engine-analyzer.c:88
SCConfGetBool
int SCConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
Definition: conf.c:497
EngineAnalysisCtx_::analyzer_initialized
bool analyzer_initialized
Definition: detect-engine-analyzer.c:111
DetectEngineAnalyzerItems
Definition: detect-engine-analyzer.c:63
DETECT_BYTEJUMP_DCE
#define DETECT_BYTEJUMP_DCE
Definition: detect-bytejump.h:40
DetectPatternTracker::cd
const struct DetectContentData_ * cd
Definition: detect.h:810
VarNameStoreSetupLookup
const char * VarNameStoreSetupLookup(const uint32_t id, const enum VarTypes type)
Definition: util-var-name.c:191
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:122
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:731
FpPatternStats_::max
uint16_t max
Definition: detect-engine-analyzer.c:74
SignatureInitData_::init_flags
uint32_t init_flags
Definition: detect.h:608
DetectBufferType_
Definition: detect.h:449
DETECT_FLOWBITS_CMD_TOGGLE
#define DETECT_FLOWBITS_CMD_TOGGLE
Definition: detect-flowbits.h:29
DetectContentData_
Definition: detect-content.h:93
DETECT_FLOWBITS_CMD_ISSET
#define DETECT_FLOWBITS_CMD_ISSET
Definition: detect-flowbits.h:32
DetectPcreData_::flags
uint16_t flags
Definition: detect-pcre.h:51
SCConfNodeLookupChildValue
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:824
DetectContentData_::fp_chop_offset
uint16_t fp_chop_offset
Definition: detect-content.h:100
DetectBytetestData_::nbytes
uint8_t nbytes
Definition: detect-bytetest.h:54
DetectBytetestData_
Definition: detect-bytetest.h:53
EngineAnalysisCtx_::analyzer_item_map
int16_t analyzer_item_map[256]
Definition: detect-engine-analyzer.c:103
SIG_FLAG_TOCLIENT
#define SIG_FLAG_TOCLIENT
Definition: detect.h:272
DETECT_BYTEJUMP_BIG
#define DETECT_BYTEJUMP_BIG
Definition: detect-bytejump.h:36
SIG_FLAG_SRC_ANY
#define SIG_FLAG_SRC_ANY
Definition: detect.h:241
EngineAnalysisRulesFailure
void EngineAnalysisRulesFailure(const DetectEngineCtx *de_ctx, const char *line, const char *file, int lineno)
Definition: detect-engine-analyzer.c:623
SigMatchData_
Data needed for Match()
Definition: detect.h:365
DetectBytejumpData_::base
uint8_t base
Definition: detect-bytejump.h:48
detect-pcre.h
SIG_TYPE_APPLAYER
@ SIG_TYPE_APPLAYER
Definition: detect.h:76
SigMatchData_::type
uint16_t type
Definition: detect.h:366
DetectBytejumpData_
Definition: detect-bytejump.h:46
Signature_::frame_inspect
DetectEngineFrameInspectionEngine * frame_inspect
Definition: detect.h:727
DetectBytejumpData_::offset
int32_t offset
Definition: detect-bytejump.h:50
DetectEnginePktInspectionEngine::transforms
const DetectEngineTransforms * transforms
Definition: detect.h:492
EngineAnalysisCtx_::analyzer_items
DetectEngineAnalyzerItems * analyzer_items
Definition: detect-engine-analyzer.c:90
DETECT_PERCENT_ENCODING_REGEX
#define DETECT_PERCENT_ENCODING_REGEX
FirewallAnalyzer
int FirewallAnalyzer(const DetectEngineCtx *de_ctx)
Definition: detect-engine-analyzer.c:2077
DetectBytejumpData_::multiplier
uint16_t multiplier
Definition: detect-bytejump.h:52
SIG_FLAG_APPLAYER
#define SIG_FLAG_APPLAYER
Definition: detect.h:249
DetectBufferTypeGetByName
int DetectBufferTypeGetByName(const char *name)
Definition: detect-engine.c:1278
SIG_FLAG_FIREWALL
#define SIG_FLAG_FIREWALL
Definition: detect.h:246
Signature_::gid
uint32_t gid
Definition: detect.h:714
DetectFlowintData_::idx
uint32_t idx
Definition: detect-flowint.h:66
Signature_::next
struct Signature_ * next
Definition: detect.h:750
ACTION_REJECT_DST
#define ACTION_REJECT_DST
Definition: action-globals.h:32
DetectEngineAppInspectionEngine_::sm_list
uint16_t sm_list
Definition: detect.h:424
ATTR_FMT_PRINTF
#define ATTR_FMT_PRINTF(x, y)
Definition: suricata-common.h:427
DetectFlowbitsData_
Definition: detect-flowbits.h:35
HashListTableGetListNext
#define HashListTableGetListNext(hb)
Definition: util-hashlist.h:55
DetectEngineAnalyzerItems::export_item_seen
bool export_item_seen
Definition: detect-engine-analyzer.c:66
SignaturePropertyFlowAction
SignaturePropertyFlowAction
Definition: detect.h:83
SIG_FLAG_TOSERVER
#define SIG_FLAG_TOSERVER
Definition: detect.h:271
DETECT_BYTETEST_RELATIVE
#define DETECT_BYTETEST_RELATIVE
Definition: detect-bytetest.h:46
SIG_TYPE_PKT
@ SIG_TYPE_PKT
Definition: detect.h:72
feature.h
RuleAnalyzer::js
SCJsonBuilder * js
Definition: detect-engine-analyzer.c:639
IpOptsFlagToString
const char * IpOptsFlagToString(uint16_t flag)
Return human readable value for ipopts flag.
Definition: detect-ipopts.c:117
JB_SET_STRING
#define JB_SET_STRING(jb, key, val)
Definition: rust.h:32
EngineAnalysisCtx
struct EngineAnalysisCtx_ EngineAnalysisCtx
DETECT_CONTENT_ENDS_WITH
#define DETECT_CONTENT_ENDS_WITH
Definition: detect-content.h:42
DETECT_PCRE_RAWBYTES
#define DETECT_PCRE_RAWBYTES
Definition: detect-pcre.h:31
DETECT_CONTENT_DISTANCE
#define DETECT_CONTENT_DISTANCE
Definition: detect-content.h:30
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
DetectEnginePktInspectionEngine::sm_list
uint16_t sm_list
Definition: detect.h:486
SIG_FLAG_INIT_BIDIREC
#define SIG_FLAG_INIT_BIDIREC
Definition: detect.h:293
g_alproto_max
AppProto g_alproto_max
Definition: app-layer-protos.c:30
DETECT_FLOWINT
@ DETECT_FLOWINT
Definition: detect-engine-register.h:62
SIG_MASK_REQUIRE_ENGINE_EVENT
#define SIG_MASK_REQUIRE_ENGINE_EVENT
Definition: detect.h:318
DETECT_ICODE
@ DETECT_ICODE
Definition: detect-engine-register.h:48
DETECT_FLOW_AGE
@ DETECT_FLOW_AGE
Definition: detect-engine-register.h:128
DETECT_BYTETEST_BASE_UNSET
#define DETECT_BYTETEST_BASE_UNSET
Definition: detect-bytetest.h:37
SIG_TYPE_IPONLY
@ SIG_TYPE_IPONLY
Definition: detect.h:66
FLOWINT_TARGET_VAL
@ FLOWINT_TARGET_VAL
Definition: detect-flowint.h:50
DETECT_BYTEJUMP_ALIGN
#define DETECT_BYTEJUMP_ALIGN
Definition: detect-bytejump.h:39
SignatureInitData_::mpm_sm
SigMatch * mpm_sm
Definition: detect.h:623
DetectEngineBufferTypeGetDescriptionById
const char * DetectEngineBufferTypeGetDescriptionById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1386
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:120
SIG_FLAG_FLUSH
#define SIG_FLAG_FLUSH
Definition: detect.h:259
DetectIpOptsData_::ipopt
uint16_t ipopt
Definition: detect-ipopts.h:38
SignatureInitData_::mpm_sm_list
int mpm_sm_list
Definition: detect.h:621
DETECT_BYTETEST_BASE_DEC
#define DETECT_BYTETEST_BASE_DEC
Definition: detect-bytetest.h:39
SIG_MASK_REQUIRE_FLOW
#define SIG_MASK_REQUIRE_FLOW
Definition: detect.h:312
SIG_FLAG_BYPASS
#define SIG_FLAG_BYPASS
Definition: detect.h:276
DETECT_CONTENT_DEPTH
#define DETECT_CONTENT_DEPTH
Definition: detect-content.h:33
DETECT_CONTENT_DISTANCE2OFFSET
#define DETECT_CONTENT_DISTANCE2OFFSET
Definition: detect-content.h:63
RuleAnalyzer
Definition: detect-engine-analyzer.c:638
DETECT_BYTEJUMP_END
#define DETECT_BYTEJUMP_END
Definition: detect-bytejump.h:42
Signature_::pkt_inspect
DetectEnginePktInspectionEngine * pkt_inspect
Definition: detect.h:726
DetectEngineAnalyzerItems
struct DetectEngineAnalyzerItems DetectEngineAnalyzerItems
util-print.h
SCEnter
#define SCEnter(...)
Definition: util-debug.h:281
detect-engine-mpm.h
detect.h
SIG_MASK_REQUIRE_FLAGS_INITDEINIT
#define SIG_MASK_REQUIRE_FLAGS_INITDEINIT
Definition: detect.h:313
SignatureInitData_::rule_state_flowbits_ids_size
uint32_t rule_state_flowbits_ids_size
Definition: detect.h:661
DetectEngineFrameInspectionEngine::sm_list
uint16_t sm_list
Definition: detect.h:513
detect-tcp-window.h
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:360
DetectEngineAnalyzerItems::item_seen
bool item_seen
Definition: detect-engine-analyzer.c:65
DETECT_CONTENT_NEGATED
#define DETECT_CONTENT_NEGATED
Definition: detect-content.h:40
DetectU8Data
DetectUintData_u8 DetectU8Data
Definition: detect-engine-uint.h:43
util-time.h
DETECT_ICMP_ID
@ DETECT_ICMP_ID
Definition: detect-engine-register.h:49
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:117
EngineAnalysisRules
void EngineAnalysisRules(const DetectEngineCtx *de_ctx, const Signature *s, const char *line)
Prints analysis of loaded rules.
Definition: detect-engine-analyzer.c:1636
app-layer-parser.h
Signature_::app_inspect
DetectEngineAppInspectionEngine * app_inspect
Definition: detect.h:725
DETECT_SEQ
@ DETECT_SEQ
Definition: detect-engine-register.h:37
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:359
DETECT_ACK
@ DETECT_ACK
Definition: detect-engine-register.h:36
RuleAnalyzer::js_warnings
SCJsonBuilder * js_warnings
Definition: detect-engine-analyzer.c:641
SIG_FLAG_REQUIRE_FLOWVAR
#define SIG_FLAG_REQUIRE_FLOWVAR
Definition: detect.h:267
Signature_::action
uint8_t action
Definition: detect.h:683
FpPatternStats_::cnt
uint32_t cnt
Definition: detect-engine-analyzer.c:75
SCReturn
#define SCReturn
Definition: util-debug.h:283
Signature_::flags
uint32_t flags
Definition: detect.h:669
DetectContentData_::depth
uint16_t depth
Definition: detect-content.h:106
DetectEngineFrameInspectionEngine::v1
struct DetectEngineFrameInspectionEngine::@86 v1
ACTION_ALERT
#define ACTION_ALERT
Definition: action-globals.h:29
DETECT_BYTETEST_BIG
#define DETECT_BYTETEST_BIG
Definition: detect-bytetest.h:44
FLOWINT_MODIFIER_LE
@ FLOWINT_MODIFIER_LE
Definition: detect-flowint.h:36
SCLocalTime
struct tm * SCLocalTime(time_t timep, struct tm *result)
Definition: util-time.c:267
detect-bytejump.h
ACTION_SCOPE_TX
@ ACTION_SCOPE_TX
Definition: action-globals.h:47
SCConfigGetLogDirectory
const char * SCConfigGetLogDirectory(void)
Definition: util-conf.c:38
ACTION_SCOPE_AUTO
@ ACTION_SCOPE_AUTO
Definition: action-globals.h:43
conf.h
DetectContentData_::flags
uint32_t flags
Definition: detect-content.h:104
CHECK
#define CHECK(pat)
Definition: detect-engine-analyzer.c:675
DetectEngineFrameInspectionEngine
Definition: detect.h:508
DetectFlowbitsData_::idx
uint32_t idx
Definition: detect-flowbits.h:36
DetectEngineBufferTypeGetById
const DetectBufferType * DetectEngineBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1298
DETECT_BYTEJUMP_BASE_UNSET
#define DETECT_BYTEJUMP_BASE_UNSET
Definition: detect-bytejump.h:28
name
const char * name
Definition: tm-threads.c:2163
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:747
DetectFlowintData_::modifier
uint8_t modifier
Definition: detect-flowint.h:70
SIG_FLAG_SRC_IS_TARGET
#define SIG_FLAG_SRC_IS_TARGET
Definition: detect.h:283
SignatureInitData_::rule_state_dependant_sids_array
uint32_t * rule_state_dependant_sids_array
Definition: detect.h:657
DetectContentPatternPrettyPrint
void DetectContentPatternPrettyPrint(const DetectContentData *cd, char *str, size_t str_len)
Definition: detect-content.c:743
SignatureInitData_::rule_state_dependant_sids_size
uint32_t rule_state_dependant_sids_size
Definition: detect.h:658
DetectEngineTransforms::transforms
TransformData transforms[DETECT_TRANSFORMS_MAX]
Definition: detect.h:392
DETECT_BYTEJUMP_BASE_HEX
#define DETECT_BYTEJUMP_BASE_HEX
Definition: detect-bytejump.h:31
SIG_TYPE_DEONLY
@ SIG_TYPE_DEONLY
Definition: detect.h:71
SIG_PROP_FLOW_ACTION_PACKET
@ SIG_PROP_FLOW_ACTION_PACKET
Definition: detect.h:84
signature_properties
const struct SignatureProperties signature_properties[SIG_TYPE_MAX]
Definition: detect-engine.c:116
detect-flowbits.h
SIG_MASK_REQUIRE_PAYLOAD
#define SIG_MASK_REQUIRE_PAYLOAD
Definition: detect.h:311
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:229
DETECT_PCRE
@ DETECT_PCRE
Definition: detect-engine-register.h:71
DETECT_DSIZE
@ DETECT_DSIZE
Definition: detect-engine-register.h:52
SIG_TYPE_NOT_SET
@ SIG_TYPE_NOT_SET
Definition: detect.h:65
ExposedItemSeen::bufname
const char * bufname
Definition: detect-engine-analyzer.c:81
DETECT_BYTEJUMP_OFFSET_BE
#define DETECT_BYTEJUMP_OFFSET_BE
Definition: detect-bytejump.h:41
FLOWINT_MODIFIER_GT
@ FLOWINT_MODIFIER_GT
Definition: detect-flowint.h:40
detect-ttl.h
DetectEngineCtx_::config_prefix
char config_prefix[64]
Definition: detect.h:1052
DetectSigmatchListEnumToString
const char * DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type)
Definition: detect-engine.c:4987
analyzer_items
const DetectEngineAnalyzerItems analyzer_items[]
Definition: detect-engine-analyzer.c:114
DetectEngineAppInspectionEngine_::alproto
AppProto alproto
Definition: detect.h:417
SIG_FLAG_MPM_NEG
#define SIG_FLAG_MPM_NEG
Definition: detect.h:257
detect-engine-analyzer.h
SIG_FLAG_INIT_STATE_MATCH
#define SIG_FLAG_INIT_STATE_MATCH
Definition: detect.h:296
DetectEngineAnalyzerItems::item_id
int16_t item_id
Definition: detect-engine-analyzer.c:64
DetectPatternTracker::sm_list
int sm_list
Definition: detect.h:811
DetectEngineAppInspectionEngine_::smd
SigMatchData * smd
Definition: detect.h:439
EngineAnalysisRules2
void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s)
Definition: detect-engine-analyzer.c:1048
ACTION_REJECT_BOTH
#define ACTION_REJECT_BOTH
Definition: action-globals.h:33
FLOWINT_MODIFIER_LT
@ FLOWINT_MODIFIER_LT
Definition: detect-flowint.h:35
DetectFlowintData_::target
union DetectFlowintData_::@68 target
ARRAY_SIZE
#define ARRAY_SIZE(arr)
Definition: suricata-common.h:562
DETECT_CONTENT_STARTS_WITH
#define DETECT_CONTENT_STARTS_WITH
Definition: detect-content.h:59
DetectProto_::flags
uint8_t flags
Definition: detect-engine-proto.h:37
DETECT_BYTETEST
@ DETECT_BYTETEST
Definition: detect-engine-register.h:82
DETECT_PROTO_IPV4
#define DETECT_PROTO_IPV4
Definition: detect-engine-proto.h:31
util-conf.h
SignatureHasStreamContent
int SignatureHasStreamContent(const Signature *s)
check if a signature has patterns that are to be inspected against the stream payload (as opposed to ...
Definition: detect-engine-mpm.c:883
FpPatternStats_::min
uint16_t min
Definition: detect-engine-analyzer.c:73
VAR_TYPE_FLOW_BIT
@ VAR_TYPE_FLOW_BIT
Definition: util-var.h:36
Signature_::proto
DetectProto proto
Definition: detect.h:687
FLOWINT_TARGET_VAR
@ FLOWINT_TARGET_VAR
Definition: detect-flowint.h:51
suricata-common.h
SIG_MASK_REQUIRE_NO_PAYLOAD
#define SIG_MASK_REQUIRE_NO_PAYLOAD
Definition: detect.h:315
FLOWINT_MODIFIER_SET
@ FLOWINT_MODIFIER_SET
Definition: detect-flowint.h:30
DetectEnginePktInspectionEngine::v1
struct DetectEnginePktInspectionEngine::@85 v1
SIG_FLAG_SP_ANY
#define SIG_FLAG_SP_ANY
Definition: detect.h:243
SIG_PROP_FLOW_ACTION_FLOW_IF_STATEFUL
@ SIG_PROP_FLOW_ACTION_FLOW_IF_STATEFUL
Definition: detect.h:86
ActionScope
ActionScope
Definition: action-globals.h:42
FLOWINT_MODIFIER_ISSET
@ FLOWINT_MODIFIER_ISSET
Definition: detect-flowint.h:42
DetectAbsentData_
Definition: detect-isdataat.h:37
ExposedItemSeen
Definition: detect-engine-analyzer.c:80
SigMatch_::type
uint16_t type
Definition: detect.h:357
HashListTableFree
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:88
DetectEngineAnalyzerItems::check_encoding_match
bool check_encoding_match
Definition: detect-engine-analyzer.c:67
DetectContentData_::distance
int32_t distance
Definition: detect-content.h:108
ACTION_SCOPE_HOOK
@ ACTION_SCOPE_HOOK
Definition: action-globals.h:46
CleanupEngineAnalysis
void CleanupEngineAnalysis(DetectEngineCtx *de_ctx)
Definition: detect-engine-analyzer.c:511
DetectBytejumpData_::nbytes
uint8_t nbytes
Definition: detect-bytejump.h:47
Signature_::action_scope
uint8_t action_scope
Definition: detect.h:690
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:36
DetectEngineFrameInspectionEngine::next
struct DetectEngineFrameInspectionEngine * next
Definition: detect.h:521
DetectU32Data
DetectUintData_u32 DetectU32Data
Definition: detect-engine-uint.h:41
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
DetectEnginePktInspectionEngine::next
struct DetectEnginePktInspectionEngine * next
Definition: detect.h:494
DetectContentData_::content
uint8_t * content
Definition: detect-content.h:94
Signature_::rev
uint32_t rev
Definition: detect.h:715
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
FatalError
#define FatalError(...)
Definition: util-debug.h:514
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:942
DETECT_BYTEJUMP_BASE_DEC
#define DETECT_BYTEJUMP_BASE_DEC
Definition: detect-bytejump.h:30
DetectIpOptsData_
Definition: detect-ipopts.h:37
ACTION_CONFIG
#define ACTION_CONFIG
Definition: action-globals.h:35
PrintRawUriFp
void PrintRawUriFp(FILE *fp, const uint8_t *buf, uint32_t buflen)
Definition: util-print.c:69
SIG_MASK_REQUIRE_FLAGS_UNUSUAL
#define SIG_MASK_REQUIRE_FLAGS_UNUSUAL
Definition: detect.h:314
TransformData_::transform
int transform
Definition: detect.h:387
FLOWINT_MODIFIER_ISNOTSET
@ FLOWINT_MODIFIER_ISNOTSET
Definition: detect-flowint.h:43
DETECT_FLOWBITS
@ DETECT_FLOWBITS
Definition: detect-engine-register.h:59
SIG_TYPE_MAX
@ SIG_TYPE_MAX
Definition: detect.h:79
DetectEngineCtx_::ea
struct EngineAnalysisCtx_ * ea
Definition: detect.h:1130
DetectEngineAppInspectionEngine_::progress
int16_t progress
Definition: detect.h:426
DETECT_BYTETEST_BASE_OCT
#define DETECT_BYTETEST_BASE_OCT
Definition: detect-bytetest.h:38
util-validate.h
detect-flow.h
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
EngineAnalysisFP
void EngineAnalysisFP(const DetectEngineCtx *de_ctx, const Signature *s, const char *line)
Definition: detect-engine-analyzer.c:171
SignatureInitData_::firewall_rule
bool firewall_rule
Definition: detect.h:664
FpPatternStats
struct FpPatternStats_ FpPatternStats
detect-tcp-ack.h
str
#define str(s)
Definition: suricata-common.h:308
SCConfGetNode
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition: conf.c:181
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:271
SigMatchListSMBelongsTo
int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
Definition: detect-parse.c:763
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DetectFlowbitsData_::or_list
uint32_t * or_list
Definition: detect-flowbits.h:42
Signature_::id
uint32_t id
Definition: detect.h:713
DETECT_CONTENT_OFFSET
#define DETECT_CONTENT_OFFSET
Definition: detect-content.h:32
HashListTableBucket_
Definition: util-hashlist.h:28
DETECT_FLOWBITS_CMD_UNSET
#define DETECT_FLOWBITS_CMD_UNSET
Definition: detect-flowbits.h:30
DETECT_CONTENT_FAST_PATTERN_ONLY
#define DETECT_CONTENT_FAST_PATTERN_ONLY
Definition: detect-content.h:35
DETECT_CONTENT_MPM
#define DETECT_CONTENT_MPM
Definition: detect-content.h:61
ACTION_SCOPE_PACKET
@ ACTION_SCOPE_PACKET
Definition: action-globals.h:44
DetectBufferType_::transforms
DetectEngineTransforms transforms
Definition: detect.h:462
detect-parse.h
Signature_
Signature container.
Definition: detect.h:668
SigMatch_
a single match condition for a signature
Definition: detect.h:356
DetectEngineAppInspectionEngine_::transforms
const DetectEngineTransforms * transforms
Definition: detect.h:436
DETECT_SM_LIST_MAX
@ DETECT_SM_LIST_MAX
Definition: detect.h:135
SCRequiresFeature
bool SCRequiresFeature(const char *feature_name)
Definition: feature.c:126
FpPatternStats_::tot
uint64_t tot
Definition: detect-engine-analyzer.c:76
DetectFlowintData_::tvar
TargetVar tvar
Definition: detect-flowint.h:77
DETECT_BYTETEST_STRING
#define DETECT_BYTETEST_STRING
Definition: detect-bytetest.h:45
DetectBytetestData_::offset
int32_t offset
Definition: detect-bytetest.h:60
VAR_TYPE_FLOW_INT
@ VAR_TYPE_FLOW_INT
Definition: util-var.h:37
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
DETECT_PCRE_RELATIVE_NEXT
#define DETECT_PCRE_RELATIVE_NEXT
Definition: detect-pcre.h:34
detect-icmp-id.h
ACTION_ACCEPT
#define ACTION_ACCEPT
Definition: action-globals.h:36
detect-ipopts.h
DetectEngineTransforms::cnt
int cnt
Definition: detect.h:393
suricata.h
DetectPcreData_
Definition: detect-pcre.h:47
DetectEngineAppInspectionEngine_::dir
uint8_t dir
Definition: detect.h:418
DetectEngineAnalyzerItems::item_name
const char * item_name
Definition: detect-engine-analyzer.c:68
DetectContentData_::content_len
uint16_t content_len
Definition: detect-content.h:95
ExposedItemSeen::item_seen_ptr
bool * item_seen_ptr
Definition: detect-engine-analyzer.c:82
DETECT_BYTEJUMP_STRING
#define DETECT_BYTEJUMP_STRING
Definition: detect-bytejump.h:37
DetectEngineCtx_::buffer_type_id
uint32_t buffer_type_id
Definition: detect.h:1082
EngineAnalysisCtx_::file_prefix
char * file_prefix
Definition: detect-engine-analyzer.c:91
DetectEnginePktInspectionEngine::mpm
bool mpm
Definition: detect.h:485
DETECT_BYTEJUMP_BEGIN
#define DETECT_BYTEJUMP_BEGIN
Definition: detect-bytejump.h:34
SignatureInitData_::rule_state_flowbits_ids_array
uint32_t * rule_state_flowbits_ids_array
Definition: detect.h:660
SIG_PROP_FLOW_ACTION_FLOW
@ SIG_PROP_FLOW_ACTION_FLOW
Definition: detect.h:85
DETECT_PCRE_RELATIVE
#define DETECT_PCRE_RELATIVE
Definition: detect-pcre.h:29
TargetVar_::name
char * name
Definition: detect-flowint.h:57
FLOWINT_MODIFIER_EQ
@ FLOWINT_MODIFIER_EQ
Definition: detect-flowint.h:37
RuleAnalyzer
struct RuleAnalyzer RuleAnalyzer
DETECT_WINDOW
@ DETECT_WINDOW
Definition: detect-engine-register.h:38
SIG_FLAG_TLSSTORE
#define SIG_FLAG_TLSSTORE
Definition: detect.h:274
DetectU16Data
DetectUintData_u16 DetectU16Data
Definition: detect-engine-uint.h:42
Signature_::msg
char * msg
Definition: detect.h:736
DETECT_CONTENT_FAST_PATTERN
#define DETECT_CONTENT_FAST_PATTERN
Definition: detect-content.h:34
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
DetectAbsentData_::or_else
bool or_else
Definition: detect-isdataat.h:39
RuleAnalyzer::js_notes
SCJsonBuilder * js_notes
Definition: detect-engine-analyzer.c:642
DETECT_FLAGS
@ DETECT_FLAGS
Definition: detect-engine-register.h:42
DETECT_PCRE_NEGATE
#define DETECT_PCRE_NEGATE
Definition: detect-pcre.h:35
EngineAnalysisCtx_::exposed_item_seen_list
struct ExposedItemSeen exposed_item_seen_list[2]
Definition: detect-engine-analyzer.c:109
Signature_::type
enum SignatureType type
Definition: detect.h:671
SCConfNode_
Definition: conf.h:37
FpPatternStats_
Definition: detect-engine-analyzer.c:72
DetectBytetestData_::base
uint8_t base
Definition: detect-bytetest.h:56
FLOWINT_MODIFIER_SUB
@ FLOWINT_MODIFIER_SUB
Definition: detect-flowint.h:32
DETECT_BYTETEST_LITTLE
#define DETECT_BYTETEST_LITTLE
Definition: detect-bytetest.h:43
SCMutex
#define SCMutex
Definition: threads-debug.h:114
SIG_TYPE_PDONLY
@ SIG_TYPE_PDONLY
Definition: detect.h:70
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
SIG_FLAG_PREFILTER
#define SIG_FLAG_PREFILTER
Definition: detect.h:278
SignatureProperties::flow_action
enum SignaturePropertyFlowAction flow_action
Definition: detect.h:90
DETECT_TCPMSS
@ DETECT_TCPMSS
Definition: detect-engine-register.h:289
SIG_FLAG_FILESTORE
#define SIG_FLAG_FILESTORE
Definition: detect.h:269
DETECT_CONTENT_WITHIN
#define DETECT_CONTENT_WITHIN
Definition: detect-content.h:31
DETECT_BYTEJUMP_RELATIVE
#define DETECT_BYTEJUMP_RELATIVE
Definition: detect-bytejump.h:38
SIG_FLAG_DP_ANY
#define SIG_FLAG_DP_ANY
Definition: detect.h:244
DETECT_FLOWBITS_CMD_SET
#define DETECT_FLOWBITS_CMD_SET
Definition: detect-flowbits.h:28
SIG_FLAG_DSIZE
#define SIG_FLAG_DSIZE
Definition: detect.h:248
FLOWINT_MODIFIER_GE
@ FLOWINT_MODIFIER_GE
Definition: detect-flowint.h:39
DetectBytejumpData_::flags
uint16_t flags
Definition: detect-bytejump.h:49
Signature_::mask
SignatureMask mask
Definition: detect.h:679
SIG_TYPE_LIKE_IPONLY
@ SIG_TYPE_LIKE_IPONLY
Definition: detect.h:67
detect-bytetest.h
DetectFlowintData_::value
uint32_t value
Definition: detect-flowint.h:75
DetectProtoContainsProto
int DetectProtoContainsProto(const DetectProto *dp, int proto)
see if a DetectProto contains a certain proto
Definition: detect-engine-proto.c:115
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:254
DetectEngineFrameInspectionEngine::smd
SigMatchData * smd
Definition: detect.h:520