suricata
detect-engine-analyzer.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2023 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-tcp-flags.h"
45 #include "detect-tcp-ack.h"
46 #include "detect-ipopts.h"
47 #include "detect-tcp-seq.h"
48 #include "feature.h"
49 #include "util-print.h"
50 #include "util-time.h"
51 #include "util-validate.h"
52 #include "util-conf.h"
53 #include "detect-flowbits.h"
54 #include "util-var-name.h"
55 #include "detect-icmp-id.h"
56 #include "detect-tcp-window.h"
57 
58 static int rule_warnings_only = 0;
59 
60 /* Details for each buffer being tracked */
61 typedef struct DetectEngineAnalyzerItems {
62  int16_t item_id;
63  bool item_seen;
66  const char *item_name;
67  const char *display_name;
69 
70 typedef struct FpPatternStats_ {
71  uint16_t min;
72  uint16_t max;
73  uint32_t cnt;
74  uint64_t tot;
76 
77 /* Track which items require the item_seen value to be exposed */
79  const char *bufname;
81 };
82 
83 typedef struct EngineAnalysisCtx_ {
84 
87 
89  char *file_prefix;
90  pcre2_code *percent_re;
91 
92  /*
93  * This array contains the map between the `analyzer_items` array listed above and
94  * the item ids returned by DetectBufferTypeGetByName. Iterating signature's sigmatch
95  * array provides list_ids. The map converts those ids into elements of the
96  * analyzer items array.
97  *
98  * Ultimately, the g_buffer_type_hash is searched for each buffer name. The size of that
99  * hashlist is 256, so that's the value we use here.
100  */
101  int16_t analyzer_item_map[256];
103  /*
104  * Certain values must be directly accessible. This array contains items that are directly
105  * accessed when checking if they've been seen or not.
106  */
108 
111 
113  /* request keywords */
114  { 0, false, false, true, "http_uri", "http uri" },
115  { 0, false, false, false, "http_raw_uri", "http raw uri" },
116  { 0, false, true, false, "http_method", "http method" },
117  { 0, false, false, false, "http_request_line", "http request line" },
118  { 0, false, false, false, "http_client_body", "http client body" },
119  { 0, false, false, true, "http_header", "http header" },
120  { 0, false, false, false, "http_raw_header", "http raw header" },
121  { 0, false, false, true, "http_cookie", "http cookie" },
122  { 0, false, false, false, "http_user_agent", "http user agent" },
123  { 0, false, false, false, "http_host", "http host" },
124  { 0, false, false, false, "http_raw_host", "http raw host" },
125  { 0, false, false, false, "http_accept_enc", "http accept enc" },
126  { 0, false, false, false, "http_referer", "http referer" },
127  { 0, false, false, false, "http_content_type", "http content type" },
128  { 0, false, false, false, "http_header_names", "http header names" },
129 
130  /* response keywords not listed above */
131  { 0, false, false, false, "http_stat_msg", "http stat msg" },
132  { 0, false, false, false, "http_stat_code", "http stat code" },
133  { 0, false, true, false, "file_data", "http server body" },
134 
135  /* missing request keywords */
136  { 0, false, false, false, "http_request_line", "http request line" },
137  { 0, false, false, false, "http_accept", "http accept" },
138  { 0, false, false, false, "http_accept_lang", "http accept lang" },
139  { 0, false, false, false, "http_connection", "http connection" },
140  { 0, false, false, false, "http_content_len", "http content len" },
141  { 0, false, false, false, "http_protocol", "http protocol" },
142  { 0, false, false, false, "http_start", "http start" },
143 
144  /* missing response keywords; some of the missing are listed above*/
145  { 0, false, false, false, "http_response_line", "http response line" },
146  { 0, false, false, false, "http.server", "http server" },
147  { 0, false, false, false, "http.location", "http location" },
148 };
149 
150 static void FpPatternStatsAdd(FpPatternStats *fp, int list, uint16_t patlen)
151 {
152  if (list < 0 || list >= DETECT_SM_LIST_MAX)
153  return;
154 
155  FpPatternStats *f = &fp[list];
156 
157  if (f->min == 0)
158  f->min = patlen;
159  else if (patlen < f->min)
160  f->min = patlen;
161 
162  if (patlen > f->max)
163  f->max = patlen;
164 
165  f->cnt++;
166  f->tot += patlen;
167 }
168 
169 void EngineAnalysisFP(const DetectEngineCtx *de_ctx, const Signature *s, char *line)
170 {
171  int fast_pattern_set = 0;
172  int fast_pattern_only_set = 0;
173  int fast_pattern_chop_set = 0;
174  const DetectContentData *fp_cd = NULL;
175  const SigMatch *mpm_sm = s->init_data->mpm_sm;
176  const int mpm_sm_list = s->init_data->mpm_sm_list;
177 
178  if (mpm_sm != NULL) {
179  fp_cd = (DetectContentData *)mpm_sm->ctx;
180  if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN) {
181  fast_pattern_set = 1;
183  fast_pattern_only_set = 1;
184  } else if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) {
185  fast_pattern_chop_set = 1;
186  }
187  }
188  }
189 
190  FILE *fp = de_ctx->ea->rule_engine_analysis_fp;
191  fprintf(fp, "== Sid: %u ==\n", s->id);
192  fprintf(fp, "%s\n", line);
193 
194  fprintf(fp, " Fast Pattern analysis:\n");
195  if (s->init_data->prefilter_sm != NULL) {
196  fprintf(fp, " Prefilter on: %s\n",
198  fprintf(fp, "\n");
199  return;
200  }
201 
202  if (fp_cd == NULL) {
203  fprintf(fp, " No content present\n");
204  fprintf(fp, "\n");
205  return;
206  }
207 
208  fprintf(fp, " Fast pattern matcher: ");
209  int list_type = mpm_sm_list;
210  if (list_type == DETECT_SM_LIST_PMATCH)
211  fprintf(fp, "content\n");
212  else {
213  const char *desc = DetectEngineBufferTypeGetDescriptionById(de_ctx, list_type);
214  const char *name = DetectEngineBufferTypeGetNameById(de_ctx, list_type);
215  if (desc && name) {
216  fprintf(fp, "%s (%s)\n", desc, name);
217  }
218  }
219 
220  int flags_set = 0;
221  fprintf(fp, " Flags:");
222  if (fp_cd->flags & DETECT_CONTENT_OFFSET) {
223  fprintf(fp, " Offset");
224  flags_set = 1;
225  } if (fp_cd->flags & DETECT_CONTENT_DEPTH) {
226  fprintf(fp, " Depth");
227  flags_set = 1;
228  }
229  if (fp_cd->flags & DETECT_CONTENT_WITHIN) {
230  fprintf(fp, " Within");
231  flags_set = 1;
232  }
233  if (fp_cd->flags & DETECT_CONTENT_DISTANCE) {
234  fprintf(fp, " Distance");
235  flags_set = 1;
236  }
237  if (fp_cd->flags & DETECT_CONTENT_NOCASE) {
238  fprintf(fp, " Nocase");
239  flags_set = 1;
240  }
241  if (fp_cd->flags & DETECT_CONTENT_NEGATED) {
242  fprintf(fp, " Negated");
243  flags_set = 1;
244  }
245  if (flags_set == 0)
246  fprintf(fp, " None");
247  fprintf(fp, "\n");
248 
249  fprintf(fp, " Fast pattern set: %s\n", fast_pattern_set ? "yes" : "no");
250  fprintf(fp, " Fast pattern only set: %s\n", fast_pattern_only_set ? "yes" : "no");
251  fprintf(fp, " Fast pattern chop set: %s\n", fast_pattern_chop_set ? "yes" : "no");
252  if (fast_pattern_chop_set) {
253  fprintf(fp, " Fast pattern offset, length: %u, %u\n", fp_cd->fp_chop_offset,
254  fp_cd->fp_chop_len);
255  }
256 
257  uint16_t patlen = fp_cd->content_len;
258  uint8_t *pat = SCMalloc(fp_cd->content_len + 1);
259  if (unlikely(pat == NULL)) {
260  FatalError("Error allocating memory");
261  }
262  memcpy(pat, fp_cd->content, fp_cd->content_len);
263  pat[fp_cd->content_len] = '\0';
264  fprintf(fp, " Original content: ");
265  PrintRawUriFp(fp, pat, patlen);
266  fprintf(fp, "\n");
267 
268  if (fast_pattern_chop_set) {
269  SCFree(pat);
270  patlen = fp_cd->fp_chop_len;
271  pat = SCMalloc(fp_cd->fp_chop_len + 1);
272  if (unlikely(pat == NULL)) {
273  exit(EXIT_FAILURE);
274  }
275  memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
276  pat[fp_cd->fp_chop_len] = '\0';
277  fprintf(fp, " Final content: ");
278  PrintRawUriFp(fp, pat, patlen);
279  fprintf(fp, "\n");
280 
281  FpPatternStatsAdd(&de_ctx->ea->fp_pattern_stats[0], list_type, patlen);
282  } else {
283  fprintf(fp, " Final content: ");
284  PrintRawUriFp(fp, pat, patlen);
285  fprintf(fp, "\n");
286 
287  FpPatternStatsAdd(&de_ctx->ea->fp_pattern_stats[0], list_type, patlen);
288  }
289  SCFree(pat);
290 
291  fprintf(fp, "\n");
292 }
293 
294 /**
295  * \brief Sets up the fast pattern analyzer according to the config.
296  *
297  * \retval 1 If rule analyzer successfully enabled.
298  * \retval 0 If not enabled.
299  */
300 static int SetupFPAnalyzer(DetectEngineCtx *de_ctx)
301 {
302  int fp_engine_analysis_set = 0;
303 
304  if ((ConfGetBool("engine-analysis.rules-fast-pattern",
305  &fp_engine_analysis_set)) == 0) {
306  return false;
307  }
308 
309  if (fp_engine_analysis_set == 0)
310  return false;
311 
312  const char *log_dir = ConfigGetLogDirectory();
313  char *log_path = SCMalloc(PATH_MAX);
314  if (log_path == NULL) {
315  FatalError("Unable to allocate scratch memory for rule filename");
316  }
317  snprintf(log_path, PATH_MAX, "%s/%s%s", log_dir,
318  de_ctx->ea->file_prefix ? de_ctx->ea->file_prefix : "", "rules_fast_pattern.txt");
319 
320  FILE *fp = fopen(log_path, "w");
321  if (fp == NULL) {
322  SCLogError("failed to open %s: %s", log_path, strerror(errno));
323  SCFree(log_path);
324  return false;
325  }
326 
328 
329  SCLogInfo("Engine-Analysis for fast_pattern printed to file - %s",
330  log_path);
331  SCFree(log_path);
332 
333  struct timeval tval;
334  gettimeofday(&tval, NULL);
335  struct tm local_tm;
336  struct tm *tms = SCLocalTime(tval.tv_sec, &local_tm);
337  fprintf(fp, "----------------------------------------------"
338  "---------------------\n");
339  fprintf(fp,
340  "Date: %" PRId32 "/%" PRId32 "/%04d -- "
341  "%02d:%02d:%02d\n",
342  tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
343  tms->tm_sec);
344  fprintf(fp, "----------------------------------------------"
345  "---------------------\n");
346 
347  memset(&de_ctx->ea->fp_pattern_stats[0], 0, sizeof(de_ctx->ea->fp_pattern_stats));
348  return true;
349 }
350 
351 /**
352  * \brief Compiles regex for rule analysis
353  * \retval 1 if successful
354  * \retval 0 if on error
355  */
356 static bool PerCentEncodingSetup(EngineAnalysisCtx *ea_ctx)
357 {
358 #define DETECT_PERCENT_ENCODING_REGEX "%[0-9|a-f|A-F]{2}"
359  int en;
360  PCRE2_SIZE eo = 0;
361  int opts = 0; // PCRE2_NEWLINE_ANY??
362 
363  ea_ctx->percent_re = pcre2_compile((PCRE2_SPTR8)DETECT_PERCENT_ENCODING_REGEX,
364  PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
365  if (ea_ctx->percent_re == NULL) {
366  PCRE2_UCHAR errbuffer[256];
367  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
368  SCLogError("Compile of \"%s\" failed at offset %d: %s", DETECT_PERCENT_ENCODING_REGEX,
369  (int)eo, errbuffer);
370  return false;
371  }
372 
373  return true;
374 }
375 /**
376  * \brief Sets up the rule analyzer according to the config
377  * \retval 1 if rule analyzer successfully enabled
378  * \retval 0 if not enabled
379  */
380 static int SetupRuleAnalyzer(DetectEngineCtx *de_ctx)
381 {
382  ConfNode *conf = ConfGetNode("engine-analysis");
383  int enabled = 0;
384  if (conf != NULL) {
385  const char *value = ConfNodeLookupChildValue(conf, "rules");
386  if (value && ConfValIsTrue(value)) {
387  enabled = 1;
388  } else if (value && strcasecmp(value, "warnings-only") == 0) {
389  enabled = 1;
390  rule_warnings_only = 1;
391  }
392  if (enabled) {
393  const char *log_dir;
394  log_dir = ConfigGetLogDirectory();
395  char log_path[PATH_MAX];
396  snprintf(log_path, sizeof(log_path), "%s/%s%s", log_dir,
397  de_ctx->ea->file_prefix ? de_ctx->ea->file_prefix : "", "rules_analysis.txt");
398  de_ctx->ea->rule_engine_analysis_fp = fopen(log_path, "w");
399  if (de_ctx->ea->rule_engine_analysis_fp == NULL) {
400  SCLogError("failed to open %s: %s", log_path, strerror(errno));
401  return 0;
402  }
403 
404  SCLogInfo("Engine-Analysis for rules printed to file - %s",
405  log_path);
406 
407  struct timeval tval;
408  gettimeofday(&tval, NULL);
409  struct tm local_tm;
410  struct tm *tms = SCLocalTime(tval.tv_sec, &local_tm);
412  "----------------------------------------------"
413  "---------------------\n");
415  "Date: %" PRId32 "/%" PRId32 "/%04d -- "
416  "%02d:%02d:%02d\n",
417  tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
418  tms->tm_sec);
420  "----------------------------------------------"
421  "---------------------\n");
422 
423  /*compile regex's for rule analysis*/
424  if (!PerCentEncodingSetup(de_ctx->ea)) {
426  "Error compiling regex; can't check for percent encoding in normalized "
427  "http content.\n");
428  }
429  }
430  }
431  else {
432  SCLogInfo("Conf parameter \"engine-analysis.rules\" not found. "
433  "Defaulting to not printing the rules analysis report.");
434  }
435  if (!enabled) {
436  SCLogInfo("Engine-Analysis for rules disabled in conf file.");
437  return 0;
438  }
439  return 1;
440 }
441 
442 static void CleanupFPAnalyzer(DetectEngineCtx *de_ctx)
443 {
444  FILE *fp = de_ctx->ea->rule_engine_analysis_fp;
445  fprintf(fp, "============\n"
446  "Summary:\n============\n");
447 
448  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
450  if (f->cnt == 0)
451  continue;
452 
453  fprintf(fp,
454  "%s, smallest pattern %u byte(s), longest pattern %u byte(s), number of patterns "
455  "%u, avg pattern len %.2f byte(s)\n",
456  DetectSigmatchListEnumToString(i), f->min, f->max, f->cnt,
457  (float)((double)f->tot / (float)f->cnt));
458  }
459 
462 }
463 
464 static void CleanupRuleAnalyzer(DetectEngineCtx *de_ctx)
465 {
466  if (de_ctx->ea->fp_engine_analysis_fp != NULL) {
467  fclose(de_ctx->ea->fp_engine_analysis_fp);
469  }
470  if (de_ctx->ea->percent_re != NULL) {
471  pcre2_code_free(de_ctx->ea->percent_re);
472  }
473 }
474 
475 void SetupEngineAnalysis(DetectEngineCtx *de_ctx, bool *fp_analysis, bool *rule_analysis)
476 {
477  *fp_analysis = false;
478  *rule_analysis = false;
479 
480  EngineAnalysisCtx *ea = SCCalloc(1, sizeof(EngineAnalysisCtx));
481  if (ea == NULL) {
482  FatalError("Unable to allocate per-engine analysis context");
483  }
484 
485  ea->file_prefix = NULL;
486  int cfg_prefix_len = strlen(de_ctx->config_prefix);
487  if (cfg_prefix_len > 0) {
488  /* length of prefix + NULL + "." */
489  ea->file_prefix = SCCalloc(1, cfg_prefix_len + 1 + 1);
490  if (ea->file_prefix == NULL) {
491  FatalError("Unable to allocate per-engine analysis context name buffer");
492  }
493 
494  snprintf(ea->file_prefix, cfg_prefix_len + 1 + 1, "%s.", de_ctx->config_prefix);
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 
623 void EngineAnalysisRulesFailure(const DetectEngineCtx *de_ctx, char *line, char *file, int lineno)
624 {
625  fprintf(de_ctx->ea->fp_engine_analysis_fp, "== Sid: UNKNOWN ==\n");
626  fprintf(de_ctx->ea->fp_engine_analysis_fp, "%s\n", line);
627  fprintf(de_ctx->ea->fp_engine_analysis_fp, " FAILURE: invalid rule.\n");
628  fprintf(de_ctx->ea->fp_engine_analysis_fp, " File: %s.\n", file);
629  fprintf(de_ctx->ea->fp_engine_analysis_fp, " Line: %d.\n", lineno);
630  fprintf(de_ctx->ea->fp_engine_analysis_fp, "\n");
631 }
632 
633 typedef struct RuleAnalyzer {
634  JsonBuilder *js; /* document root */
635 
636  JsonBuilder *js_warnings;
637  JsonBuilder *js_notes;
639 
640 static void ATTR_FMT_PRINTF(2, 3) AnalyzerNote(RuleAnalyzer *ctx, char *fmt, ...)
641 {
642  va_list ap;
643  char str[1024];
644 
645  va_start(ap, fmt);
646  vsnprintf(str, sizeof(str), fmt, ap);
647  va_end(ap);
648 
649  if (!ctx->js_notes)
650  ctx->js_notes = jb_new_array();
651  if (ctx->js_notes)
652  jb_append_string(ctx->js_notes, str);
653 }
654 
655 static void ATTR_FMT_PRINTF(2, 3) AnalyzerWarning(RuleAnalyzer *ctx, char *fmt, ...)
656 {
657  va_list ap;
658  char str[1024];
659 
660  va_start(ap, fmt);
661  vsnprintf(str, sizeof(str), fmt, ap);
662  va_end(ap);
663 
664  if (!ctx->js_warnings)
665  ctx->js_warnings = jb_new_array();
666  if (ctx->js_warnings)
667  jb_append_string(ctx->js_warnings, str);
668 }
669 
670 #define CHECK(pat) if (strlen((pat)) <= len && memcmp((pat), buf, MIN(len, strlen((pat)))) == 0) return true;
671 
672 static bool LooksLikeHTTPMethod(const uint8_t *buf, uint16_t len)
673 {
674  CHECK("GET /");
675  CHECK("POST /");
676  CHECK("HEAD /");
677  CHECK("PUT /");
678  return false;
679 }
680 
681 static bool LooksLikeHTTPUA(const uint8_t *buf, uint16_t len)
682 {
683  CHECK("User-Agent: ");
684  CHECK("\nUser-Agent: ");
685  return false;
686 }
687 
688 static void DumpContent(JsonBuilder *js, const DetectContentData *cd)
689 {
690  char pattern_str[1024] = "";
691  DetectContentPatternPrettyPrint(cd, pattern_str, sizeof(pattern_str));
692 
693  jb_set_string(js, "pattern", pattern_str);
694  jb_set_uint(js, "length", cd->content_len);
695  jb_set_bool(js, "nocase", cd->flags & DETECT_CONTENT_NOCASE);
696  jb_set_bool(js, "negated", cd->flags & DETECT_CONTENT_NEGATED);
697  jb_set_bool(js, "starts_with", cd->flags & DETECT_CONTENT_STARTS_WITH);
698  jb_set_bool(js, "ends_with", cd->flags & DETECT_CONTENT_ENDS_WITH);
699  jb_set_bool(js, "is_mpm", cd->flags & DETECT_CONTENT_MPM);
700  jb_set_bool(js, "no_double_inspect", cd->flags & DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED);
701  if (cd->flags & DETECT_CONTENT_OFFSET) {
702  jb_set_uint(js, "offset", cd->offset);
703  }
704  if (cd->flags & DETECT_CONTENT_DEPTH) {
705  jb_set_uint(js, "depth", cd->depth);
706  }
707  if (cd->flags & DETECT_CONTENT_DISTANCE) {
708  jb_set_int(js, "distance", cd->distance);
709  }
710  if (cd->flags & DETECT_CONTENT_WITHIN) {
711  jb_set_int(js, "within", cd->within);
712  }
713  jb_set_bool(js, "fast_pattern", cd->flags & DETECT_CONTENT_FAST_PATTERN);
714  jb_set_bool(js, "relative_next", cd->flags & DETECT_CONTENT_RELATIVE_NEXT);
715 }
716 
717 static void DumpPcre(JsonBuilder *js, const DetectPcreData *cd)
718 {
719  jb_set_bool(js, "relative", cd->flags & DETECT_PCRE_RELATIVE);
720  jb_set_bool(js, "relative_next", cd->flags & DETECT_PCRE_RELATIVE_NEXT);
721  jb_set_bool(js, "nocase", cd->flags & DETECT_PCRE_CASELESS);
722  jb_set_bool(js, "negated", cd->flags & DETECT_PCRE_NEGATE);
723 }
724 
725 static void DumpMatches(RuleAnalyzer *ctx, JsonBuilder *js, const SigMatchData *smd)
726 {
727  if (smd == NULL)
728  return;
729 
730  jb_open_array(js, "matches");
731  do {
732  jb_start_object(js);
733  const char *mname = sigmatch_table[smd->type].name;
734  jb_set_string(js, "name", mname);
735 
736  switch (smd->type) {
737  case DETECT_CONTENT: {
738  const DetectContentData *cd = (const DetectContentData *)smd->ctx;
739 
740  jb_open_object(js, "content");
741  DumpContent(js, cd);
743  AnalyzerNote(ctx, (char *)"'fast_pattern:only' option is silently ignored and "
744  "is interpreted as regular 'fast_pattern'");
745  }
746  if (LooksLikeHTTPMethod(cd->content, cd->content_len)) {
747  AnalyzerWarning(ctx,
748  (char *)"pattern looks like it inspects HTTP, use http.request_line or "
749  "http.method and http.uri instead for improved performance");
750  }
751  if (LooksLikeHTTPUA(cd->content, cd->content_len)) {
752  AnalyzerWarning(ctx,
753  (char *)"pattern looks like it inspects HTTP, use http.user_agent "
754  "or http.header for improved performance");
755  }
757  AnalyzerNote(ctx, (char *)"'within' option for pattern w/o previous content "
758  "was converted to 'depth'");
759  }
761  AnalyzerNote(ctx, (char *)"'distance' option for pattern w/o previous content "
762  "was converted to 'offset'");
763  }
764  jb_close(js);
765  break;
766  }
767  case DETECT_PCRE: {
768  const DetectPcreData *cd = (const DetectPcreData *)smd->ctx;
769 
770  jb_open_object(js, "pcre");
771  DumpPcre(js, cd);
772  jb_close(js);
773  if (cd->flags & DETECT_PCRE_RAWBYTES) {
774  AnalyzerNote(ctx,
775  (char *)"'/B' (rawbytes) option is a no-op and is silently ignored");
776  }
777  break;
778  }
779  case DETECT_BYTEJUMP: {
780  const DetectBytejumpData *cd = (const DetectBytejumpData *)smd->ctx;
781 
782  jb_open_object(js, "byte_jump");
783  jb_set_uint(js, "nbytes", cd->nbytes);
784  jb_set_int(js, "offset", cd->offset);
785  jb_set_uint(js, "multiplier", cd->multiplier);
786  jb_set_int(js, "post_offset", cd->post_offset);
787  switch (cd->base) {
789  jb_set_string(js, "base", "unset");
790  break;
792  jb_set_string(js, "base", "oct");
793  break;
795  jb_set_string(js, "base", "dec");
796  break;
798  jb_set_string(js, "base", "hex");
799  break;
800  }
801  jb_open_array(js, "flags");
802  if (cd->flags & DETECT_BYTEJUMP_BEGIN)
803  jb_append_string(js, "from_beginning");
804  if (cd->flags & DETECT_BYTEJUMP_LITTLE)
805  jb_append_string(js, "little_endian");
806  if (cd->flags & DETECT_BYTEJUMP_BIG)
807  jb_append_string(js, "big_endian");
808  if (cd->flags & DETECT_BYTEJUMP_STRING)
809  jb_append_string(js, "string");
811  jb_append_string(js, "relative");
812  if (cd->flags & DETECT_BYTEJUMP_ALIGN)
813  jb_append_string(js, "align");
814  if (cd->flags & DETECT_BYTEJUMP_DCE)
815  jb_append_string(js, "dce");
817  jb_append_string(js, "offset_be");
818  if (cd->flags & DETECT_BYTEJUMP_END)
819  jb_append_string(js, "from_end");
820  jb_close(js);
821  jb_close(js);
822  break;
823  }
824  case DETECT_BYTETEST: {
825  const DetectBytetestData *cd = (const DetectBytetestData *)smd->ctx;
826 
827  jb_open_object(js, "byte_test");
828  jb_set_uint(js, "nbytes", cd->nbytes);
829  jb_set_int(js, "offset", cd->offset);
830  switch (cd->base) {
832  jb_set_string(js, "base", "unset");
833  break;
835  jb_set_string(js, "base", "oct");
836  break;
838  jb_set_string(js, "base", "dec");
839  break;
841  jb_set_string(js, "base", "hex");
842  break;
843  }
844  jb_open_array(js, "flags");
845  if (cd->flags & DETECT_BYTETEST_LITTLE)
846  jb_append_string(js, "little_endian");
847  if (cd->flags & DETECT_BYTETEST_BIG)
848  jb_append_string(js, "big_endian");
849  if (cd->flags & DETECT_BYTETEST_STRING)
850  jb_append_string(js, "string");
852  jb_append_string(js, "relative");
853  if (cd->flags & DETECT_BYTETEST_DCE)
854  jb_append_string(js, "dce");
855  jb_close(js);
856  jb_close(js);
857  break;
858  }
859  case DETECT_ABSENT: {
860  const DetectAbsentData *dad = (const DetectAbsentData *)smd->ctx;
861  jb_open_object(js, "absent");
862  jb_set_bool(js, "or_else", dad->or_else);
863  jb_close(js);
864  break;
865  }
866 
867  case DETECT_IPOPTS: {
868  const DetectIpOptsData *cd = (const DetectIpOptsData *)smd->ctx;
869 
870  jb_open_object(js, "ipopts");
871  const char *flag = IpOptsFlagToString(cd->ipopt);
872  jb_set_string(js, "option", flag);
873  jb_close(js);
874  break;
875  }
876  case DETECT_FLOWBITS: {
877  const DetectFlowbitsData *cd = (const DetectFlowbitsData *)smd->ctx;
878 
879  jb_open_object(js, "flowbits");
880  switch (cd->cmd) {
882  jb_set_string(js, "cmd", "isset");
883  break;
885  jb_set_string(js, "cmd", "isnotset");
886  break;
888  jb_set_string(js, "cmd", "set");
889  break;
891  jb_set_string(js, "cmd", "unset");
892  break;
894  jb_set_string(js, "cmd", "toggle");
895  break;
896  }
897  bool is_or = false;
898  jb_open_array(js, "names");
899  if (cd->or_list_size == 0) {
900  jb_append_string(js, VarNameStoreSetupLookup(cd->idx, VAR_TYPE_FLOW_BIT));
901  } else if (cd->or_list_size > 0) {
902  is_or = true;
903  for (uint8_t i = 0; i < cd->or_list_size; i++) {
904  const char *varname =
906  jb_append_string(js, varname);
907  }
908  }
909  jb_close(js); // array
910  if (is_or) {
911  jb_set_string(js, "operator", "or");
912  }
913  jb_close(js); // object
914  break;
915  }
916  case DETECT_ACK: {
917  const DetectAckData *cd = (const DetectAckData *)smd->ctx;
918 
919  jb_open_object(js, "ack");
920  jb_set_uint(js, "number", cd->ack);
921  jb_close(js);
922  break;
923  }
924  case DETECT_SEQ: {
925  const DetectSeqData *cd = (const DetectSeqData *)smd->ctx;
926  jb_open_object(js, "seq");
927  jb_set_uint(js, "number", cd->seq);
928  jb_close(js);
929  break;
930  }
931  case DETECT_TCPMSS: {
932  const DetectU16Data *cd = (const DetectU16Data *)smd->ctx;
933  jb_open_object(js, "tcp_mss");
934  SCDetectU16ToJson(js, cd);
935  jb_close(js);
936  break;
937  }
938  case DETECT_ICMP_ID: {
939  const DetectIcmpIdData *cd = (const DetectIcmpIdData *)smd->ctx;
940  jb_open_object(js, "id");
941  jb_set_uint(js, "number", SCNtohs(cd->id));
942  jb_close(js);
943  break;
944  }
945  case DETECT_WINDOW: {
946  const DetectWindowData *wd = (const DetectWindowData *)smd->ctx;
947  jb_open_object(js, "window");
948  jb_set_uint(js, "size", wd->size);
949  jb_set_bool(js, "negated", wd->negated);
950  jb_close(js);
951  break;
952  }
953  case DETECT_FLOW_AGE: {
954  const DetectU32Data *cd = (const DetectU32Data *)smd->ctx;
955  jb_open_object(js, "flow_age");
956  SCDetectU32ToJson(js, cd);
957  jb_close(js);
958  break;
959  }
960  }
961  jb_close(js);
962 
963  if (smd->is_last)
964  break;
965  smd++;
966  } while (1);
967  jb_close(js);
968 }
969 
972 {
973  SCEnter();
974 
975  RuleAnalyzer ctx = { NULL, NULL, NULL };
976 
977  ctx.js = jb_new_object();
978  if (ctx.js == NULL)
979  SCReturn;
980 
981  jb_set_string(ctx.js, "raw", s->sig_str);
982  jb_set_uint(ctx.js, "id", s->id);
983  jb_set_uint(ctx.js, "gid", s->gid);
984  jb_set_uint(ctx.js, "rev", s->rev);
985  jb_set_string(ctx.js, "msg", s->msg);
986 
987  const char *alproto = AppProtoToString(s->alproto);
988  jb_set_string(ctx.js, "app_proto", alproto);
989 
990  jb_open_array(ctx.js, "requirements");
991  if (s->mask & SIG_MASK_REQUIRE_PAYLOAD) {
992  jb_append_string(ctx.js, "payload");
993  }
995  jb_append_string(ctx.js, "no_payload");
996  }
997  if (s->mask & SIG_MASK_REQUIRE_FLOW) {
998  jb_append_string(ctx.js, "flow");
999  }
1001  jb_append_string(ctx.js, "tcp_flags_init_deinit");
1002  }
1004  jb_append_string(ctx.js, "tcp_flags_unusual");
1005  }
1007  jb_append_string(ctx.js, "engine_event");
1008  }
1009  if (s->mask & SIG_MASK_REQUIRE_REAL_PKT) {
1010  jb_append_string(ctx.js, "real_pkt");
1011  }
1012  jb_close(ctx.js);
1013 
1014  switch (s->type) {
1015  case SIG_TYPE_NOT_SET:
1016  jb_set_string(ctx.js, "type", "unset");
1017  break;
1018  case SIG_TYPE_IPONLY:
1019  jb_set_string(ctx.js, "type", "ip_only");
1020  break;
1021  case SIG_TYPE_LIKE_IPONLY:
1022  jb_set_string(ctx.js, "type", "like_ip_only");
1023  break;
1024  case SIG_TYPE_PDONLY:
1025  jb_set_string(ctx.js, "type", "pd_only");
1026  break;
1027  case SIG_TYPE_DEONLY:
1028  jb_set_string(ctx.js, "type", "de_only");
1029  break;
1030  case SIG_TYPE_PKT:
1031  jb_set_string(ctx.js, "type", "pkt");
1032  break;
1033  case SIG_TYPE_PKT_STREAM:
1034  jb_set_string(ctx.js, "type", "pkt_stream");
1035  break;
1036  case SIG_TYPE_STREAM:
1037  jb_set_string(ctx.js, "type", "stream");
1038  break;
1039  case SIG_TYPE_APPLAYER:
1040  jb_set_string(ctx.js, "type", "app_layer");
1041  break;
1042  case SIG_TYPE_APP_TX:
1043  jb_set_string(ctx.js, "type", "app_tx");
1044  break;
1045  case SIG_TYPE_MAX:
1046  jb_set_string(ctx.js, "type", "error");
1047  break;
1048  }
1049 
1050  jb_open_array(ctx.js, "flags");
1051  if (s->flags & SIG_FLAG_SRC_ANY) {
1052  jb_append_string(ctx.js, "src_any");
1053  }
1054  if (s->flags & SIG_FLAG_DST_ANY) {
1055  jb_append_string(ctx.js, "dst_any");
1056  }
1057  if (s->flags & SIG_FLAG_SP_ANY) {
1058  jb_append_string(ctx.js, "sp_any");
1059  }
1060  if (s->flags & SIG_FLAG_DP_ANY) {
1061  jb_append_string(ctx.js, "dp_any");
1062  }
1063  if ((s->action & ACTION_ALERT) == 0) {
1064  jb_append_string(ctx.js, "noalert");
1065  }
1066  if (s->flags & SIG_FLAG_DSIZE) {
1067  jb_append_string(ctx.js, "dsize");
1068  }
1069  if (s->flags & SIG_FLAG_APPLAYER) {
1070  jb_append_string(ctx.js, "applayer");
1071  }
1072  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
1073  jb_append_string(ctx.js, "need_packet");
1074  }
1075  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
1076  jb_append_string(ctx.js, "need_stream");
1077  }
1078  if (s->flags & SIG_FLAG_MPM_NEG) {
1079  jb_append_string(ctx.js, "negated_mpm");
1080  }
1081  if (s->flags & SIG_FLAG_FLUSH) {
1082  jb_append_string(ctx.js, "flush");
1083  }
1084  if (s->flags & SIG_FLAG_REQUIRE_FLOWVAR) {
1085  jb_append_string(ctx.js, "need_flowvar");
1086  }
1087  if (s->flags & SIG_FLAG_FILESTORE) {
1088  jb_append_string(ctx.js, "filestore");
1089  }
1090  if (s->flags & SIG_FLAG_TOSERVER) {
1091  jb_append_string(ctx.js, "toserver");
1092  }
1093  if (s->flags & SIG_FLAG_TOCLIENT) {
1094  jb_append_string(ctx.js, "toclient");
1095  }
1096  if (s->flags & SIG_FLAG_TLSSTORE) {
1097  jb_append_string(ctx.js, "tlsstore");
1098  }
1099  if (s->flags & SIG_FLAG_BYPASS) {
1100  jb_append_string(ctx.js, "bypass");
1101  }
1102  if (s->flags & SIG_FLAG_PREFILTER) {
1103  jb_append_string(ctx.js, "prefilter");
1104  }
1105  if (s->flags & SIG_FLAG_SRC_IS_TARGET) {
1106  jb_append_string(ctx.js, "src_is_target");
1107  }
1108  if (s->flags & SIG_FLAG_DEST_IS_TARGET) {
1109  jb_append_string(ctx.js, "dst_is_target");
1110  }
1111  jb_close(ctx.js);
1112 
1113  const DetectEnginePktInspectionEngine *pkt_mpm = NULL;
1114  const DetectEngineAppInspectionEngine *app_mpm = NULL;
1115 
1116  jb_open_array(ctx.js, "pkt_engines");
1118  for ( ; pkt != NULL; pkt = pkt->next) {
1120  if (name == NULL) {
1121  switch (pkt->sm_list) {
1122  case DETECT_SM_LIST_PMATCH:
1123  name = "payload";
1124  break;
1125  case DETECT_SM_LIST_MATCH:
1126  name = "packet";
1127  break;
1128  default:
1129  name = "unknown";
1130  break;
1131  }
1132  }
1133  jb_start_object(ctx.js);
1134  jb_set_string(ctx.js, "name", name);
1135  jb_set_bool(ctx.js, "is_mpm", pkt->mpm);
1136  if (pkt->v1.transforms != NULL) {
1137  jb_open_array(ctx.js, "transforms");
1138  for (int t = 0; t < pkt->v1.transforms->cnt; t++) {
1139  jb_start_object(ctx.js);
1140  jb_set_string(ctx.js, "name",
1142  jb_close(ctx.js);
1143  }
1144  jb_close(ctx.js);
1145  }
1146  DumpMatches(&ctx, ctx.js, pkt->smd);
1147  jb_close(ctx.js);
1148  if (pkt->mpm) {
1149  pkt_mpm = pkt;
1150  }
1151  }
1152  jb_close(ctx.js);
1153  jb_open_array(ctx.js, "frame_engines");
1155  for (; frame != NULL; frame = frame->next) {
1156  const char *name = DetectEngineBufferTypeGetNameById(de_ctx, frame->sm_list);
1157  jb_start_object(ctx.js);
1158  jb_set_string(ctx.js, "name", name);
1159  jb_set_bool(ctx.js, "is_mpm", frame->mpm);
1160  if (frame->v1.transforms != NULL) {
1161  jb_open_array(ctx.js, "transforms");
1162  for (int t = 0; t < frame->v1.transforms->cnt; t++) {
1163  jb_start_object(ctx.js);
1164  jb_set_string(ctx.js, "name",
1166  jb_close(ctx.js);
1167  }
1168  jb_close(ctx.js);
1169  }
1170  DumpMatches(&ctx, ctx.js, frame->smd);
1171  jb_close(ctx.js);
1172  }
1173  jb_close(ctx.js);
1174 
1176  bool has_stream = false;
1177  bool has_client_body_mpm = false;
1178  bool has_file_data_mpm = false;
1179 
1180  jb_open_array(ctx.js, "engines");
1182  for ( ; app != NULL; app = app->next) {
1184  if (name == NULL) {
1185  switch (app->sm_list) {
1186  case DETECT_SM_LIST_PMATCH:
1187  name = "stream";
1188  break;
1189  default:
1190  name = "unknown";
1191  break;
1192  }
1193  }
1194 
1195  if (app->sm_list == DETECT_SM_LIST_PMATCH && !app->mpm) {
1196  has_stream = true;
1197  } else if (app->mpm && strcmp(name, "http_client_body") == 0) {
1198  has_client_body_mpm = true;
1199  } else if (app->mpm && strcmp(name, "file_data") == 0) {
1200  has_file_data_mpm = true;
1201  }
1202 
1203  jb_start_object(ctx.js);
1204  jb_set_string(ctx.js, "name", name);
1205  const char *direction = app->dir == 0 ? "toserver" : "toclient";
1206  jb_set_string(ctx.js, "direction", direction);
1207  jb_set_bool(ctx.js, "is_mpm", app->mpm);
1208  jb_set_string(ctx.js, "app_proto", AppProtoToString(app->alproto));
1209  jb_set_uint(ctx.js, "progress", app->progress);
1210 
1211  if (app->v2.transforms != NULL) {
1212  jb_open_array(ctx.js, "transforms");
1213  for (int t = 0; t < app->v2.transforms->cnt; t++) {
1214  jb_start_object(ctx.js);
1215  jb_set_string(ctx.js, "name",
1217  jb_close(ctx.js);
1218  }
1219  jb_close(ctx.js);
1220  }
1221  DumpMatches(&ctx, ctx.js, app->smd);
1222  jb_close(ctx.js);
1223  if (app->mpm) {
1224  app_mpm = app;
1225  }
1226  }
1227  jb_close(ctx.js);
1228 
1229  if (has_stream && has_client_body_mpm)
1230  AnalyzerNote(&ctx, (char *)"mpm in http_client_body combined with stream match leads to stream buffering");
1231  if (has_stream && has_file_data_mpm)
1232  AnalyzerNote(&ctx, (char *)"mpm in file_data combined with stream match leads to stream buffering");
1233  }
1234 
1235  jb_open_object(ctx.js, "lists");
1236  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
1237  if (s->sm_arrays[i] != NULL) {
1238  jb_open_object(ctx.js, DetectListToHumanString(i));
1239  DumpMatches(&ctx, ctx.js, s->sm_arrays[i]);
1240  jb_close(ctx.js);
1241  }
1242  }
1243  jb_close(ctx.js);
1244 
1245  if (pkt_mpm || app_mpm) {
1246  jb_open_object(ctx.js, "mpm");
1247 
1248  int mpm_list = pkt_mpm ? DETECT_SM_LIST_PMATCH : app_mpm->sm_list;
1249  const char *name;
1250  if (mpm_list < DETECT_SM_LIST_DYNAMIC_START)
1251  name = DetectListToHumanString(mpm_list);
1252  else
1254  jb_set_string(ctx.js, "buffer", name);
1255 
1256  SigMatchData *smd = pkt_mpm ? pkt_mpm->smd : app_mpm->smd;
1257  if (smd == NULL && mpm_list == DETECT_SM_LIST_PMATCH) {
1258  smd = s->sm_arrays[mpm_list];
1259  }
1260  do {
1261  switch (smd->type) {
1262  case DETECT_CONTENT: {
1263  const DetectContentData *cd = (const DetectContentData *)smd->ctx;
1264  if (cd->flags & DETECT_CONTENT_MPM) {
1265  DumpContent(ctx.js, cd);
1266  }
1267  break;
1268  }
1269  }
1270 
1271  if (smd->is_last)
1272  break;
1273  smd++;
1274  } while (1);
1275  jb_close(ctx.js);
1276  } else if (s->init_data->prefilter_sm) {
1277  jb_open_object(ctx.js, "prefilter");
1278  int prefilter_list = SigMatchListSMBelongsTo(s, s->init_data->prefilter_sm);
1279  const char *name;
1280  if (prefilter_list < DETECT_SM_LIST_DYNAMIC_START)
1281  name = DetectListToHumanString(prefilter_list);
1282  else
1283  name = DetectEngineBufferTypeGetNameById(de_ctx, prefilter_list);
1284  jb_set_string(ctx.js, "buffer", name);
1285  const char *mname = sigmatch_table[s->init_data->prefilter_sm->type].name;
1286  jb_set_string(ctx.js, "name", mname);
1287  jb_close(ctx.js);
1288  }
1289 
1290  if (ctx.js_warnings) {
1291  jb_close(ctx.js_warnings);
1292  jb_set_object(ctx.js, "warnings", ctx.js_warnings);
1293  jb_free(ctx.js_warnings);
1294  ctx.js_warnings = NULL;
1295  }
1296  if (ctx.js_notes) {
1297  jb_close(ctx.js_notes);
1298  jb_set_object(ctx.js, "notes", ctx.js_notes);
1299  jb_free(ctx.js_notes);
1300  ctx.js_notes = NULL;
1301  }
1302  jb_close(ctx.js);
1303 
1304  const char *filename = "rules.json";
1305  const char *log_dir = ConfigGetLogDirectory();
1306  char json_path[PATH_MAX] = "";
1307  snprintf(json_path, sizeof(json_path), "%s/%s%s", log_dir,
1308  de_ctx->ea->file_prefix ? de_ctx->ea->file_prefix : "", filename);
1309 
1311  FILE *fp = fopen(json_path, "a");
1312  if (fp != NULL) {
1313  fwrite(jb_ptr(ctx.js), jb_len(ctx.js), 1, fp);
1314  fprintf(fp, "\n");
1315  fclose(fp);
1316  }
1318  jb_free(ctx.js);
1319  SCReturn;
1320 }
1321 
1323 {
1324  if (de_ctx->pattern_hash_table == NULL)
1325  return;
1326 
1327  JsonBuilder *root_jb = jb_new_object();
1328  JsonBuilder *arrays[de_ctx->buffer_type_id];
1329  memset(&arrays, 0, sizeof(JsonBuilder *) * de_ctx->buffer_type_id);
1330 
1331  jb_open_array(root_jb, "buffers");
1332 
1334  htb != NULL; htb = HashListTableGetListNext(htb)) {
1335  char str[1024] = "";
1337  DetectContentPatternPrettyPrint(p->cd, str, sizeof(str));
1338 
1339  JsonBuilder *jb = arrays[p->sm_list];
1340  if (arrays[p->sm_list] == NULL) {
1341  jb = arrays[p->sm_list] = jb_new_object();
1342  const char *name;
1345  else
1347  jb_set_string(jb, "name", name);
1348  jb_set_uint(jb, "list_id", p->sm_list);
1349 
1350  jb_open_array(jb, "patterns");
1351  }
1352 
1353  jb_start_object(jb);
1354  jb_set_string(jb, "pattern", str);
1355  jb_set_uint(jb, "patlen", p->cd->content_len);
1356  jb_set_uint(jb, "cnt", p->cnt);
1357  jb_set_uint(jb, "mpm", p->mpm);
1358  jb_open_object(jb, "flags");
1359  jb_set_bool(jb, "nocase", p->cd->flags & DETECT_CONTENT_NOCASE);
1360  jb_set_bool(jb, "negated", p->cd->flags & DETECT_CONTENT_NEGATED);
1361  jb_set_bool(jb, "depth", p->cd->flags & DETECT_CONTENT_DEPTH);
1362  jb_set_bool(jb, "offset", p->cd->flags & DETECT_CONTENT_OFFSET);
1363  jb_set_bool(jb, "endswith", p->cd->flags & DETECT_CONTENT_ENDS_WITH);
1364  jb_close(jb);
1365  jb_close(jb);
1366  }
1367 
1368  for (uint32_t i = 0; i < de_ctx->buffer_type_id; i++) {
1369  JsonBuilder *jb = arrays[i];
1370  if (jb == NULL)
1371  continue;
1372 
1373  jb_close(jb); // array
1374  jb_close(jb); // object
1375 
1376  jb_append_object(root_jb, jb);
1377  jb_free(jb);
1378  }
1379  jb_close(root_jb);
1380  jb_close(root_jb);
1381 
1382  const char *filename = "patterns.json";
1383  const char *log_dir = ConfigGetLogDirectory();
1384  char json_path[PATH_MAX] = "";
1385  snprintf(json_path, sizeof(json_path), "%s/%s%s", log_dir,
1386  de_ctx->ea->file_prefix ? de_ctx->ea->file_prefix : "", filename);
1387 
1389  FILE *fp = fopen(json_path, "a");
1390  if (fp != NULL) {
1391  fwrite(jb_ptr(root_jb), jb_len(root_jb), 1, fp);
1392  fprintf(fp, "\n");
1393  fclose(fp);
1394  }
1396  jb_free(root_jb);
1397 
1399  de_ctx->pattern_hash_table = NULL;
1400 }
1401 
1402 static void EngineAnalysisItemsReset(EngineAnalysisCtx *ea_ctx)
1403 {
1404  for (size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) {
1405  ea_ctx->analyzer_items[i].item_seen = false;
1406  }
1407 }
1408 
1409 static void EngineAnalysisItemsInit(EngineAnalysisCtx *ea_ctx)
1410 {
1411  if (ea_ctx->analyzer_initialized) {
1412  EngineAnalysisItemsReset(ea_ctx);
1413  return;
1414  }
1415 
1416  ea_ctx->exposed_item_seen_list[0].bufname = "http_method";
1417  ea_ctx->exposed_item_seen_list[1].bufname = "file_data";
1418  ea_ctx->analyzer_items = SCCalloc(1, sizeof(analyzer_items));
1419  if (!ea_ctx->analyzer_items) {
1420  FatalError("Unable to allocate analysis scratch pad");
1421  }
1422  memset(ea_ctx->analyzer_item_map, -1, sizeof(ea_ctx->analyzer_item_map));
1423 
1424  for (size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) {
1425  ea_ctx->analyzer_items[i] = analyzer_items[i];
1426  DetectEngineAnalyzerItems *analyzer_item = &ea_ctx->analyzer_items[i];
1427 
1428  int item_id = DetectBufferTypeGetByName(analyzer_item->item_name);
1429  DEBUG_VALIDATE_BUG_ON(item_id < 0 || item_id > UINT16_MAX);
1430  analyzer_item->item_id = (uint16_t)item_id;
1431  if (analyzer_item->item_id == -1) {
1432  /* Mismatch between the analyzer_items array and what's supported */
1433  FatalError("unable to initialize engine-analysis table: detect buffer \"%s\" not "
1434  "recognized.",
1435  analyzer_item->item_name);
1436  }
1437  analyzer_item->item_seen = false;
1438 
1439  if (analyzer_item->export_item_seen) {
1440  for (size_t k = 0; k < ARRAY_SIZE(ea_ctx->exposed_item_seen_list); k++) {
1441  if (0 ==
1442  strcmp(ea_ctx->exposed_item_seen_list[k].bufname, analyzer_item->item_name))
1443  ea_ctx->exposed_item_seen_list[k].item_seen_ptr = &analyzer_item->item_seen;
1444  }
1445  }
1446  ea_ctx->analyzer_item_map[analyzer_item->item_id] = (int16_t)i;
1447  }
1448 
1449  ea_ctx->analyzer_initialized = true;
1450 }
1451 
1452 /**
1453  * \brief Prints analysis of loaded rules.
1454  *
1455  * Warns if potential rule issues are detected. For example,
1456  * warns if a rule uses a construct that may perform poorly,
1457  * e.g. pcre without content or with http_method content only;
1458  * warns if a rule uses a construct that may not be consistent with intent,
1459  * e.g. client side ports only, http and content without any http_* modifiers, etc.
1460  *
1461  * \param s Pointer to the signature.
1462  */
1464  const Signature *s, const char *line)
1465 {
1466  uint32_t rule_bidirectional = 0;
1467  uint32_t rule_pcre = 0;
1468  uint32_t rule_pcre_http = 0;
1469  uint32_t rule_content = 0;
1470  uint32_t rule_flow = 0;
1471  uint32_t rule_flags = 0;
1472  uint32_t rule_flow_toserver = 0;
1473  uint32_t rule_flow_toclient = 0;
1474  uint32_t rule_flow_nostream = 0;
1475  uint32_t rule_ipv4_only = 0;
1476  uint32_t rule_ipv6_only = 0;
1477  uint32_t rule_flowbits = 0;
1478  uint32_t rule_flowint = 0;
1479  uint32_t rule_content_http = 0;
1480  uint32_t rule_content_offset_depth = 0;
1481  int32_t list_id = 0;
1482  uint32_t rule_warning = 0;
1483  uint32_t stream_buf = 0;
1484  uint32_t packet_buf = 0;
1485  uint32_t file_store = 0;
1486  uint32_t warn_pcre_no_content = 0;
1487  uint32_t warn_pcre_http_content = 0;
1488  uint32_t warn_pcre_http = 0;
1489  uint32_t warn_content_http_content = 0;
1490  uint32_t warn_content_http = 0;
1491  uint32_t warn_tcp_no_flow = 0;
1492  uint32_t warn_client_ports = 0;
1493  uint32_t warn_direction = 0;
1494  uint32_t warn_method_toclient = 0;
1495  uint32_t warn_method_serverbody = 0;
1496  uint32_t warn_pcre_method = 0;
1497  uint32_t warn_encoding_norm_http_buf = 0;
1498  uint32_t warn_file_store_not_present = 0;
1499  uint32_t warn_offset_depth_pkt_stream = 0;
1500  uint32_t warn_offset_depth_alproto = 0;
1501  uint32_t warn_non_alproto_fp_for_alproto_sig = 0;
1502  uint32_t warn_no_direction = 0;
1503  uint32_t warn_both_direction = 0;
1504 
1505  EngineAnalysisItemsInit(de_ctx->ea);
1506 
1507  bool *http_method_item_seen_ptr = de_ctx->ea->exposed_item_seen_list[0].item_seen_ptr;
1508  bool *http_server_body_item_seen_ptr = de_ctx->ea->exposed_item_seen_list[1].item_seen_ptr;
1509 
1511  rule_bidirectional = 1;
1512  }
1513 
1514  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
1515  packet_buf += 1;
1516  }
1517  if (s->flags & SIG_FLAG_FILESTORE) {
1518  file_store += 1;
1519  }
1520  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
1521  stream_buf += 1;
1522  }
1523 
1524  if (s->proto.flags & DETECT_PROTO_IPV4) {
1525  rule_ipv4_only += 1;
1526  }
1527  if (s->proto.flags & DETECT_PROTO_IPV6) {
1528  rule_ipv6_only += 1;
1529  }
1530 
1531  for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) {
1532  SigMatch *sm = NULL;
1533  for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) {
1534  int16_t item_slot = de_ctx->ea->analyzer_item_map[list_id];
1535  if (sm->type == DETECT_PCRE) {
1536  if (item_slot == -1) {
1537  rule_pcre++;
1538  continue;
1539  }
1540 
1541  rule_pcre_http++;
1542  de_ctx->ea->analyzer_items[item_slot].item_seen = true;
1543  } else if (sm->type == DETECT_CONTENT) {
1544  if (item_slot == -1) {
1545  rule_content++;
1546  if (list_id == DETECT_SM_LIST_PMATCH) {
1549  rule_content_offset_depth++;
1550  }
1551  }
1552  continue;
1553  }
1554 
1555  rule_content_http++;
1556  de_ctx->ea->analyzer_items[item_slot].item_seen = true;
1557 
1558  if (de_ctx->ea->analyzer_items[item_slot].check_encoding_match) {
1560  if (cd != NULL &&
1561  PerCentEncodingMatch(de_ctx->ea, cd->content, cd->content_len) > 0) {
1562  warn_encoding_norm_http_buf += 1;
1563  }
1564  }
1565  }
1566  else if (sm->type == DETECT_FLOW) {
1567  rule_flow += 1;
1568  if ((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) {
1569  rule_flow_toserver = 1;
1570  }
1571  else if ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_TOSERVER)) {
1572  rule_flow_toclient = 1;
1573  }
1574  DetectFlowData *fd = (DetectFlowData *)sm->ctx;
1575  if (fd != NULL) {
1576  if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM)
1577  rule_flow_nostream = 1;
1578  }
1579  }
1580  else if (sm->type == DETECT_FLOWBITS) {
1581  if (list_id == DETECT_SM_LIST_MATCH) {
1582  rule_flowbits += 1;
1583  }
1584  }
1585  else if (sm->type == DETECT_FLOWINT) {
1586  if (list_id == DETECT_SM_LIST_MATCH) {
1587  rule_flowint += 1;
1588  }
1589  }
1590  else if (sm->type == DETECT_FLAGS) {
1591  DetectFlagsData *fd = (DetectFlagsData *)sm->ctx;
1592  if (fd != NULL) {
1593  rule_flags = 1;
1594  }
1595  }
1596  } /* for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) */
1597 
1598  } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */
1599 
1600  if (file_store && !RequiresFeature("output::file-store")) {
1601  rule_warning += 1;
1602  warn_file_store_not_present = 1;
1603  }
1604 
1605  if (rule_pcre > 0 && rule_content == 0 && rule_content_http == 0) {
1606  rule_warning += 1;
1607  warn_pcre_no_content = 1;
1608  }
1609 
1610  if (rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0) {
1611  rule_warning += 1;
1612  warn_pcre_http_content = 1;
1613  } else if (s->alproto == ALPROTO_HTTP1 && rule_pcre > 0 && rule_pcre_http == 0) {
1614  rule_warning += 1;
1615  warn_pcre_http = 1;
1616  }
1617 
1618  if (rule_content > 0 && rule_content_http > 0) {
1619  rule_warning += 1;
1620  warn_content_http_content = 1;
1621  }
1622  if (s->alproto == ALPROTO_HTTP1 && rule_content > 0 && rule_content_http == 0) {
1623  rule_warning += 1;
1624  warn_content_http = 1;
1625  }
1626  if (rule_content == 1) {
1627  //todo: warning if content is weak, separate warning for pcre + weak content
1628  }
1629  if (rule_flow == 0 && rule_flags == 0 && !(s->proto.flags & DETECT_PROTO_ANY) &&
1630  DetectProtoContainsProto(&s->proto, IPPROTO_TCP) &&
1631  (rule_content || rule_content_http || rule_pcre || rule_pcre_http || rule_flowbits ||
1632  rule_flowint)) {
1633  rule_warning += 1;
1634  warn_tcp_no_flow = 1;
1635  }
1636  if (rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)
1637  && !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))) {
1638  if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))
1639  || ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && (s->flags & SIG_FLAG_SP_ANY))) {
1640  rule_warning += 1;
1641  warn_client_ports = 1;
1642  }
1643  }
1644  if (rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)) {
1645  rule_warning += 1;
1646  warn_direction = 1;
1647  }
1648 
1649  if (*http_method_item_seen_ptr) {
1650  if (rule_flow && rule_flow_toclient) {
1651  rule_warning += 1;
1652  warn_method_toclient = 1;
1653  }
1654  if (*http_server_body_item_seen_ptr) {
1655  rule_warning += 1;
1656  warn_method_serverbody = 1;
1657  }
1658  if (rule_content == 0 && rule_content_http == 0 && (rule_pcre > 0 || rule_pcre_http > 0)) {
1659  rule_warning += 1;
1660  warn_pcre_method = 1;
1661  }
1662  }
1663  if (rule_content_offset_depth > 0 && stream_buf && packet_buf) {
1664  rule_warning += 1;
1665  warn_offset_depth_pkt_stream = 1;
1666  }
1667  if (rule_content_offset_depth > 0 && !stream_buf && packet_buf && s->alproto != ALPROTO_UNKNOWN) {
1668  rule_warning += 1;
1669  warn_offset_depth_alproto = 1;
1670  }
1671  if (s->init_data->mpm_sm != NULL && s->alproto == ALPROTO_HTTP1 &&
1673  rule_warning += 1;
1674  warn_non_alproto_fp_for_alproto_sig = 1;
1675  }
1676 
1677  if ((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
1678  warn_no_direction += 1;
1679  rule_warning += 1;
1680  }
1681 
1682  /* No warning about direction for ICMP protos */
1683  if (!(DetectProtoContainsProto(&s->proto, IPPROTO_ICMPV6) && DetectProtoContainsProto(&s->proto, IPPROTO_ICMP))) {
1685  warn_both_direction += 1;
1686  rule_warning += 1;
1687  }
1688  }
1689 
1690  if (!rule_warnings_only || (rule_warnings_only && rule_warning > 0)) {
1691  FILE *fp = de_ctx->ea->rule_engine_analysis_fp;
1692  fprintf(fp, "== Sid: %u ==\n", s->id);
1693  fprintf(fp, "%s\n", line);
1694 
1695  switch (s->type) {
1696  case SIG_TYPE_NOT_SET:
1697  break;
1698  case SIG_TYPE_IPONLY:
1699  fprintf(fp, " Rule is ip only.\n");
1700  break;
1701  case SIG_TYPE_LIKE_IPONLY:
1702  fprintf(fp, " Rule is like ip only.\n");
1703  break;
1704  case SIG_TYPE_PDONLY:
1705  fprintf(fp, " Rule is PD only.\n");
1706  break;
1707  case SIG_TYPE_DEONLY:
1708  fprintf(fp, " Rule is DE only.\n");
1709  break;
1710  case SIG_TYPE_PKT:
1711  fprintf(fp, " Rule is packet inspecting.\n");
1712  break;
1713  case SIG_TYPE_PKT_STREAM:
1714  fprintf(fp, " Rule is packet and stream inspecting.\n");
1715  break;
1716  case SIG_TYPE_STREAM:
1717  fprintf(fp, " Rule is stream inspecting.\n");
1718  break;
1719  case SIG_TYPE_APPLAYER:
1720  fprintf(fp, " Rule is app-layer inspecting.\n");
1721  break;
1722  case SIG_TYPE_APP_TX:
1723  fprintf(fp, " Rule is App-layer TX inspecting.\n");
1724  break;
1725  case SIG_TYPE_MAX:
1726  break;
1727  }
1728  if (rule_ipv6_only)
1729  fprintf(fp, " Rule is IPv6 only.\n");
1730  if (rule_ipv4_only)
1731  fprintf(fp, " Rule is IPv4 only.\n");
1732  if (packet_buf)
1733  fprintf(fp, " Rule matches on packets.\n");
1734  if (!rule_flow_nostream && stream_buf &&
1735  (rule_flow || rule_flowbits || rule_flowint || rule_content || rule_pcre)) {
1736  fprintf(fp, " Rule matches on reassembled stream.\n");
1737  }
1738  for(size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) {
1740  if (ai->item_seen) {
1741  fprintf(fp, " Rule matches on %s buffer.\n", ai->display_name);
1742  }
1743  }
1744  if (s->alproto != ALPROTO_UNKNOWN) {
1745  fprintf(fp, " App layer protocol is %s.\n", AppProtoToString(s->alproto));
1746  }
1747  if (rule_content || rule_content_http || rule_pcre || rule_pcre_http) {
1748  fprintf(fp,
1749  " Rule contains %u content options, %u http content options, %u pcre "
1750  "options, and %u pcre options with http modifiers.\n",
1751  rule_content, rule_content_http, rule_pcre, rule_pcre_http);
1752  }
1753 
1754  /* print fast pattern info */
1755  if (s->init_data->prefilter_sm) {
1756  fprintf(fp, " Prefilter on: %s.\n",
1758  } else {
1759  EngineAnalysisRulesPrintFP(de_ctx, s);
1760  }
1761 
1762  /* this is where the warnings start */
1763  if (warn_pcre_no_content /*rule_pcre > 0 && rule_content == 0 && rule_content_http == 0*/) {
1764  fprintf(fp, " Warning: Rule uses pcre without a content option present.\n"
1765  " -Consider adding a content to improve performance of this "
1766  "rule.\n");
1767  }
1768  if (warn_pcre_http_content /*rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0*/) {
1769  fprintf(fp, " Warning: Rule uses content options with http_* and pcre options "
1770  "without http modifiers.\n"
1771  " -Consider adding http pcre modifier.\n");
1772  }
1773  else if (warn_pcre_http /*s->alproto == ALPROTO_HTTP1 && rule_pcre > 0 && rule_pcre_http == 0*/) {
1774  fprintf(fp, " Warning: Rule app layer protocol is http, but pcre options do not "
1775  "have http modifiers.\n"
1776  " -Consider adding http pcre modifiers.\n");
1777  }
1778  if (warn_content_http_content /*rule_content > 0 && rule_content_http > 0*/) {
1779  fprintf(fp,
1780  " Warning: Rule contains content with http_* and content without http_*.\n"
1781  " -Consider adding http content modifiers.\n");
1782  }
1783  if (warn_content_http /*s->alproto == ALPROTO_HTTP1 && rule_content > 0 && rule_content_http == 0*/) {
1784  fprintf(fp, " Warning: Rule app layer protocol is http, but content options do not "
1785  "have http_* modifiers.\n"
1786  " -Consider adding http content modifiers.\n");
1787  }
1788  if (rule_content == 1) {
1789  //todo: warning if content is weak, separate warning for pcre + weak content
1790  }
1791  if (warn_encoding_norm_http_buf) {
1792  fprintf(fp, " Warning: Rule may contain percent encoded content for a normalized "
1793  "http buffer match.\n");
1794  }
1795  if (warn_tcp_no_flow /*rule_flow == 0 && rule_flags == 0
1796  && !(s->proto.flags & DETECT_PROTO_ANY) && DetectProtoContainsProto(&s->proto, IPPROTO_TCP)*/) {
1797  fprintf(fp, " Warning: TCP rule without a flow or flags option.\n"
1798  " -Consider adding flow or flags to improve performance of "
1799  "this rule.\n");
1800  }
1801  if (warn_client_ports /*rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)
1802  && !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY)))
1803  if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))
1804  || ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && (s->flags & SIG_FLAG_SP_ANY))*/) {
1805  fprintf(fp,
1806  " Warning: Rule contains ports or port variables only on the client side.\n"
1807  " -Flow direction possibly inconsistent with rule.\n");
1808  }
1809  if (warn_direction /*rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)*/) {
1810  fprintf(fp, " Warning: Rule is bidirectional and has a flow option with a specific "
1811  "direction.\n");
1812  }
1813  if (warn_method_toclient /*http_method_buf && rule_flow && rule_flow_toclient*/) {
1814  fprintf(fp, " Warning: Rule uses content or pcre for http_method with "
1815  "flow:to_client or from_server\n");
1816  }
1817  if (warn_method_serverbody /*http_method_buf && http_server_body_buf*/) {
1818  fprintf(fp, " Warning: Rule uses content or pcre for http_method with content or "
1819  "pcre for http_server_body.\n");
1820  }
1821  if (warn_pcre_method /*http_method_buf && rule_content == 0 && rule_content_http == 0
1822  && (rule_pcre > 0 || rule_pcre_http > 0)*/) {
1823  fprintf(fp, " Warning: Rule uses pcre with only a http_method content; possible "
1824  "performance issue.\n");
1825  }
1826  if (warn_offset_depth_pkt_stream) {
1827  fprintf(fp, " Warning: Rule has depth"
1828  "/offset with raw content keywords. Please note the "
1829  "offset/depth will be checked against both packet "
1830  "payloads and stream. If you meant to have the offset/"
1831  "depth checked against just the payload, you can update "
1832  "the signature as \"alert tcp-pkt...\"\n");
1833  }
1834  if (warn_offset_depth_alproto) {
1835  fprintf(fp,
1836  " Warning: Rule has "
1837  "offset/depth set along with a match on a specific "
1838  "app layer protocol - %d. This can lead to FNs if we "
1839  "have a offset/depth content match on a packet payload "
1840  "before we can detect the app layer protocol for the "
1841  "flow.\n",
1842  s->alproto);
1843  }
1844  if (warn_non_alproto_fp_for_alproto_sig) {
1845  fprintf(fp, " Warning: Rule app layer "
1846  "protocol is http, but the fast_pattern is set on the raw "
1847  "stream. Consider adding fast_pattern over a http "
1848  "buffer for increased performance.");
1849  }
1850  if (warn_no_direction) {
1851  fprintf(fp, " Warning: Rule has no direction indicator.\n");
1852  }
1853  if (warn_both_direction) {
1854  fprintf(fp, " Warning: Rule is inspecting both the request and the response.\n");
1855  }
1856  if (warn_file_store_not_present) {
1857  fprintf(fp, " Warning: Rule requires file-store but the output file-store is not "
1858  "enabled.\n");
1859  }
1860  if (rule_warning == 0) {
1861  fprintf(fp, " No warnings for this rule.\n");
1862  }
1863  fprintf(fp, "\n");
1864  }
1865 }
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:796
RuleAnalyzer::js
JsonBuilder * js
Definition: detect-engine-analyzer.c:634
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:73
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:737
DetectEngineAppInspectionEngine_
Definition: detect.h:431
DETECT_CONTENT_RELATIVE_NEXT
#define DETECT_CONTENT_RELATIVE_NEXT
Definition: detect-content.h:66
DetectEngineAppInspectionEngine_::mpm
bool mpm
Definition: detect.h:435
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
detect-engine.h
DETECT_SM_LIST_PMATCH
@ DETECT_SM_LIST_PMATCH
Definition: detect.h:118
SIG_MASK_REQUIRE_REAL_PKT
#define SIG_MASK_REQUIRE_REAL_PKT
Definition: detect.h:308
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:593
DetectContentData_::fp_chop_len
uint16_t fp_chop_len
Definition: detect-content.h:98
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:153
Signature_::sig_str
char * sig_str
Definition: detect.h:675
SIG_TYPE_APP_TX
@ SIG_TYPE_APP_TX
Definition: detect.h:76
DetectSeqData_::seq
uint32_t seq
Definition: detect-tcp-seq.h:31
DetectIcmpIdData_
Definition: detect-icmp-id.h:27
DetectEnginePktInspectionEngine
Definition: detect.h:490
DetectEngineAppInspectionEngine_::next
struct DetectEngineAppInspectionEngine_ * next
Definition: detect.h:455
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:1313
DETECT_BYTEJUMP
@ DETECT_BYTEJUMP
Definition: detect-engine-register.h:86
DetectPatternTracker::mpm
uint32_t mpm
Definition: detect.h:741
ConfGetBool
int ConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
Definition: conf.c:482
DETECT_ABSENT
@ DETECT_ABSENT
Definition: detect-engine-register.h:98
DetectListToHumanString
const char * DetectListToHumanString(int list)
Definition: detect-parse.c:186
DetectEngineCtx_::pattern_hash_table
HashListTable * pattern_hash_table
Definition: detect.h:884
DumpPatterns
void DumpPatterns(DetectEngineCtx *de_ctx)
Definition: detect-engine-analyzer.c:1322
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
DetectContentData_::within
int32_t within
Definition: detect-content.h:109
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:475
DETECT_CONTENT
@ DETECT_CONTENT
Definition: detect-engine-register.h:72
SignatureInitData_::prefilter_sm
SigMatch * prefilter_sm
Definition: detect.h:574
EngineAnalysisCtx_::rule_engine_analysis_fp
FILE * rule_engine_analysis_fp
Definition: detect-engine-analyzer.c:85
DETECT_FLOW
@ DETECT_FLOW
Definition: detect-engine-register.h:56
Signature_::alproto
AppProto alproto
Definition: detect.h:613
detect-isdataat.h
RuleAnalyzer::js_warnings
JsonBuilder * js_warnings
Definition: detect-engine-analyzer.c:636
DETECT_BYTETEST_BASE_HEX
#define DETECT_BYTETEST_BASE_HEX
Definition: detect-bytetest.h:40
SigMatchData_::is_last
bool is_last
Definition: detect.h:362
g_rules_analyzer_write_m
SCMutex g_rules_analyzer_write_m
Definition: detect-engine-analyzer.c:970
DetectEngineAnalyzerItems::display_name
const char * display_name
Definition: detect-engine-analyzer.c:67
DETECT_CONTENT_WITHIN2DEPTH
#define DETECT_CONTENT_WITHIN2DEPTH
Definition: detect-content.h:62
EngineAnalysisCtx_::percent_re
pcre2_code * percent_re
Definition: detect-engine-analyzer.c:90
DETECT_SM_LIST_DYNAMIC_START
@ DETECT_SM_LIST_DYNAMIC_START
Definition: detect.h:137
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:283
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:363
DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED
#define DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED
Definition: detect-content.h:55
action-globals.h
ConfGetNode
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:181
EngineAnalysisCtx_
Definition: detect-engine-analyzer.c:83
DETECT_IPOPTS
@ DETECT_IPOPTS
Definition: detect-engine-register.h:41
AppProtoToString
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
Definition: app-layer-protos.c:40
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:525
DetectFlowData_::flags
uint16_t flags
Definition: detect-flow.h:38
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:848
DETECT_PROTO_ANY
#define DETECT_PROTO_ANY
Definition: detect-engine-proto.h:28
DetectEnginePktInspectionEngine::smd
SigMatchData * smd
Definition: detect.h:491
SIG_TYPE_PKT_STREAM
@ SIG_TYPE_PKT_STREAM
Definition: detect.h:72
DetectFlowbitsData_::cmd
uint8_t cmd
Definition: detect-flowbits.h:37
DetectEngineFrameInspectionEngine::mpm
bool mpm
Definition: detect.h:519
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
DetectEngineAppInspectionEngine_::v2
struct DetectEngineAppInspectionEngine_::@79 v2
EngineAnalysisCtx_::fp_pattern_stats
FpPatternStats fp_pattern_stats[DETECT_SM_LIST_MAX]
Definition: detect-engine-analyzer.c:102
DetectEngineBufferTypeGetNameById
const char * DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1126
SIG_FLAG_DST_ANY
#define SIG_FLAG_DST_ANY
Definition: detect.h:241
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:253
DetectPatternTracker::cnt
uint32_t cnt
Definition: detect.h:740
rust.h
EngineAnalysisCtx_::fp_engine_analysis_fp
FILE * fp_engine_analysis_fp
Definition: detect-engine-analyzer.c:86
EngineAnalysisCtx_::analyzer_initialized
bool analyzer_initialized
Definition: detect-engine-analyzer.c:109
DetectEngineAnalyzerItems
Definition: detect-engine-analyzer.c:61
DETECT_BYTEJUMP_DCE
#define DETECT_BYTEJUMP_DCE
Definition: detect-bytejump.h:40
DetectPatternTracker::cd
const struct DetectContentData_ * cd
Definition: detect.h:738
VarNameStoreSetupLookup
const char * VarNameStoreSetupLookup(const uint32_t id, const enum VarTypes type)
Definition: util-var-name.c:188
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:661
FpPatternStats_::max
uint16_t max
Definition: detect-engine-analyzer.c:72
SignatureInitData_::init_flags
uint32_t init_flags
Definition: detect.h:560
DetectBufferType_
Definition: detect.h:458
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
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:101
DetectWindowData_
Definition: detect-tcp-window.h:21
SIG_FLAG_TOCLIENT
#define SIG_FLAG_TOCLIENT
Definition: detect.h:270
DETECT_BYTEJUMP_BIG
#define DETECT_BYTEJUMP_BIG
Definition: detect-bytejump.h:36
SIG_FLAG_SRC_ANY
#define SIG_FLAG_SRC_ANY
Definition: detect.h:240
SigMatchData_
Data needed for Match()
Definition: detect.h:360
DetectBytejumpData_::base
uint8_t base
Definition: detect-bytejump.h:48
detect-pcre.h
SIG_TYPE_APPLAYER
@ SIG_TYPE_APPLAYER
Definition: detect.h:75
SigMatchData_::type
uint16_t type
Definition: detect.h:361
DetectBytejumpData_
Definition: detect-bytejump.h:46
Signature_::frame_inspect
DetectEngineFrameInspectionEngine * frame_inspect
Definition: detect.h:657
DetectBytejumpData_::offset
int32_t offset
Definition: detect-bytejump.h:50
DetectEnginePktInspectionEngine::transforms
const DetectEngineTransforms * transforms
Definition: detect.h:499
ConfValIsTrue
int ConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:536
EngineAnalysisCtx_::analyzer_items
DetectEngineAnalyzerItems * analyzer_items
Definition: detect-engine-analyzer.c:88
DETECT_PERCENT_ENCODING_REGEX
#define DETECT_PERCENT_ENCODING_REGEX
DetectBytejumpData_::multiplier
uint16_t multiplier
Definition: detect-bytejump.h:52
SIG_FLAG_APPLAYER
#define SIG_FLAG_APPLAYER
Definition: detect.h:248
DetectBufferTypeGetByName
int DetectBufferTypeGetByName(const char *name)
Definition: detect-engine.c:1096
Signature_::gid
uint32_t gid
Definition: detect.h:644
DetectEngineAppInspectionEngine_::sm_list
uint16_t sm_list
Definition: detect.h:439
ATTR_FMT_PRINTF
#define ATTR_FMT_PRINTF(x, y)
Definition: suricata-common.h:410
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:64
SIG_FLAG_TOSERVER
#define SIG_FLAG_TOSERVER
Definition: detect.h:269
RequiresFeature
bool RequiresFeature(const char *feature_name)
Definition: feature.c:126
DETECT_BYTETEST_RELATIVE
#define DETECT_BYTETEST_RELATIVE
Definition: detect-bytetest.h:46
SIG_TYPE_PKT
@ SIG_TYPE_PKT
Definition: detect.h:71
DetectSeqData_
seq data
Definition: detect-tcp-seq.h:30
feature.h
IpOptsFlagToString
const char * IpOptsFlagToString(uint16_t flag)
Return human readable value for ipopts flag.
Definition: detect-ipopts.c:117
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:493
SIG_FLAG_INIT_BIDIREC
#define SIG_FLAG_INIT_BIDIREC
Definition: detect.h:291
DETECT_FLOWINT
@ DETECT_FLOWINT
Definition: detect-engine-register.h:65
SIG_MASK_REQUIRE_ENGINE_EVENT
#define SIG_MASK_REQUIRE_ENGINE_EVENT
Definition: detect.h:310
DETECT_FLOW_AGE
@ DETECT_FLOW_AGE
Definition: detect-engine-register.h:129
DETECT_BYTETEST_BASE_UNSET
#define DETECT_BYTETEST_BASE_UNSET
Definition: detect-bytetest.h:37
SIG_TYPE_IPONLY
@ SIG_TYPE_IPONLY
Definition: detect.h:65
DETECT_BYTEJUMP_ALIGN
#define DETECT_BYTEJUMP_ALIGN
Definition: detect-bytejump.h:39
SignatureInitData_::mpm_sm
SigMatch * mpm_sm
Definition: detect.h:572
DetectEngineBufferTypeGetDescriptionById
const char * DetectEngineBufferTypeGetDescriptionById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1204
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
SIG_FLAG_FLUSH
#define SIG_FLAG_FLUSH
Definition: detect.h:257
DetectIpOptsData_::ipopt
uint16_t ipopt
Definition: detect-ipopts.h:38
SignatureInitData_::mpm_sm_list
int mpm_sm_list
Definition: detect.h:570
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:304
SIG_FLAG_BYPASS
#define SIG_FLAG_BYPASS
Definition: detect.h:274
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:633
DETECT_BYTEJUMP_END
#define DETECT_BYTEJUMP_END
Definition: detect-bytejump.h:42
Signature_::pkt_inspect
DetectEnginePktInspectionEngine * pkt_inspect
Definition: detect.h:656
DetectEngineAnalyzerItems
struct DetectEngineAnalyzerItems DetectEngineAnalyzerItems
util-print.h
DetectWindowData_::negated
uint8_t negated
Definition: detect-tcp-window.h:22
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
detect-engine-mpm.h
detect.h
SIG_MASK_REQUIRE_FLAGS_INITDEINIT
#define SIG_MASK_REQUIRE_FLAGS_INITDEINIT
Definition: detect.h:305
DetectEngineFrameInspectionEngine::sm_list
uint16_t sm_list
Definition: detect.h:520
detect-tcp-window.h
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:355
DetectEngineAnalyzerItems::item_seen
bool item_seen
Definition: detect-engine-analyzer.c:63
DETECT_CONTENT_NEGATED
#define DETECT_CONTENT_NEGATED
Definition: detect-content.h:40
util-time.h
DETECT_ICMP_ID
@ DETECT_ICMP_ID
Definition: detect-engine-register.h:51
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:116
DetectAckData_::ack
uint32_t ack
Definition: detect-tcp-ack.h:31
EngineAnalysisRules
void EngineAnalysisRules(const DetectEngineCtx *de_ctx, const Signature *s, const char *line)
Prints analysis of loaded rules.
Definition: detect-engine-analyzer.c:1463
Signature_::app_inspect
DetectEngineAppInspectionEngine * app_inspect
Definition: detect.h:655
DETECT_SEQ
@ DETECT_SEQ
Definition: detect-engine-register.h:39
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:354
DETECT_ACK
@ DETECT_ACK
Definition: detect-engine-register.h:38
SIG_FLAG_REQUIRE_FLOWVAR
#define SIG_FLAG_REQUIRE_FLOWVAR
Definition: detect.h:265
Signature_::action
uint8_t action
Definition: detect.h:623
FpPatternStats_::cnt
uint32_t cnt
Definition: detect-engine-analyzer.c:73
SCReturn
#define SCReturn
Definition: util-debug.h:273
Signature_::flags
uint32_t flags
Definition: detect.h:609
DetectContentData_::depth
uint16_t depth
Definition: detect-content.h:106
ACTION_ALERT
#define ACTION_ALERT
Definition: action-globals.h:29
DETECT_BYTETEST_BIG
#define DETECT_BYTETEST_BIG
Definition: detect-bytetest.h:44
SCLocalTime
struct tm * SCLocalTime(time_t timep, struct tm *result)
Definition: util-time.c:267
detect-bytejump.h
conf.h
DetectContentData_::flags
uint32_t flags
Definition: detect-content.h:104
CHECK
#define CHECK(pat)
Definition: detect-engine-analyzer.c:670
DetectEngineFrameInspectionEngine
Definition: detect.h:515
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:1116
DETECT_BYTEJUMP_BASE_UNSET
#define DETECT_BYTEJUMP_BASE_UNSET
Definition: detect-bytejump.h:28
name
const char * name
Definition: tm-threads.c:2081
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:677
SIG_FLAG_SRC_IS_TARGET
#define SIG_FLAG_SRC_IS_TARGET
Definition: detect.h:281
DetectContentPatternPrettyPrint
void DetectContentPatternPrettyPrint(const DetectContentData *cd, char *str, size_t str_len)
Definition: detect-content.c:744
DetectIcmpIdData_::id
uint16_t id
Definition: detect-icmp-id.h:28
DetectEngineTransforms::transforms
TransformData transforms[DETECT_TRANSFORMS_MAX]
Definition: detect.h:411
DETECT_BYTEJUMP_BASE_HEX
#define DETECT_BYTEJUMP_BASE_HEX
Definition: detect-bytejump.h:31
SIG_TYPE_DEONLY
@ SIG_TYPE_DEONLY
Definition: detect.h:70
detect-flowbits.h
SIG_MASK_REQUIRE_PAYLOAD
#define SIG_MASK_REQUIRE_PAYLOAD
Definition: detect.h:303
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:224
DETECT_PCRE
@ DETECT_PCRE
Definition: detect-engine-register.h:74
DetectWindowData_::size
uint16_t size
Definition: detect-tcp-window.h:23
SIG_TYPE_NOT_SET
@ SIG_TYPE_NOT_SET
Definition: detect.h:64
ExposedItemSeen::bufname
const char * bufname
Definition: detect-engine-analyzer.c:79
EngineAnalysisRulesFailure
void EngineAnalysisRulesFailure(const DetectEngineCtx *de_ctx, char *line, char *file, int lineno)
Definition: detect-engine-analyzer.c:623
DETECT_BYTEJUMP_OFFSET_BE
#define DETECT_BYTEJUMP_OFFSET_BE
Definition: detect-bytejump.h:41
DetectEngineCtx_::config_prefix
char config_prefix[64]
Definition: detect.h:970
DetectSigmatchListEnumToString
const char * DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type)
Definition: detect-engine.c:4963
analyzer_items
const DetectEngineAnalyzerItems analyzer_items[]
Definition: detect-engine-analyzer.c:112
DetectEngineAppInspectionEngine_::alproto
AppProto alproto
Definition: detect.h:432
SIG_FLAG_MPM_NEG
#define SIG_FLAG_MPM_NEG
Definition: detect.h:255
detect-engine-analyzer.h
SIG_FLAG_INIT_STATE_MATCH
#define SIG_FLAG_INIT_STATE_MATCH
Definition: detect.h:294
DetectEngineAnalyzerItems::item_id
int16_t item_id
Definition: detect-engine-analyzer.c:62
DetectPatternTracker::sm_list
int sm_list
Definition: detect.h:739
DetectEngineAppInspectionEngine_::smd
SigMatchData * smd
Definition: detect.h:453
EngineAnalysisRules2
void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s)
Definition: detect-engine-analyzer.c:971
ARRAY_SIZE
#define ARRAY_SIZE(arr)
Definition: suricata-common.h:545
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:85
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:826
RuleAnalyzer::js_notes
JsonBuilder * js_notes
Definition: detect-engine-analyzer.c:637
EngineAnalysisFP
void EngineAnalysisFP(const DetectEngineCtx *de_ctx, const Signature *s, char *line)
Definition: detect-engine-analyzer.c:169
FpPatternStats_::min
uint16_t min
Definition: detect-engine-analyzer.c:71
VAR_TYPE_FLOW_BIT
@ VAR_TYPE_FLOW_BIT
Definition: util-var.h:36
Signature_::proto
DetectProto proto
Definition: detect.h:627
SCNtohs
#define SCNtohs(x)
Definition: suricata-common.h:414
suricata-common.h
SIG_MASK_REQUIRE_NO_PAYLOAD
#define SIG_MASK_REQUIRE_NO_PAYLOAD
Definition: detect.h:307
SIG_FLAG_SP_ANY
#define SIG_FLAG_SP_ANY
Definition: detect.h:242
DetectAbsentData_
Definition: detect-isdataat.h:37
ExposedItemSeen
Definition: detect-engine-analyzer.c:78
SigMatch_::type
uint16_t type
Definition: detect.h:352
HashListTableFree
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:88
DetectEngineAnalyzerItems::check_encoding_match
bool check_encoding_match
Definition: detect-engine-analyzer.c:65
DetectContentData_::distance
int32_t distance
Definition: detect-content.h:108
CleanupEngineAnalysis
void CleanupEngineAnalysis(DetectEngineCtx *de_ctx)
Definition: detect-engine-analyzer.c:511
DetectBytejumpData_::nbytes
uint8_t nbytes
Definition: detect-bytejump.h:47
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:36
DetectEngineFrameInspectionEngine::next
struct DetectEngineFrameInspectionEngine * next
Definition: detect.h:528
DetectU32Data
DetectUintData_u32 DetectU32Data
Definition: detect-engine-uint.h:41
DetectEnginePktInspectionEngine::next
struct DetectEnginePktInspectionEngine * next
Definition: detect.h:501
DetectContentData_::content
uint8_t * content
Definition: detect-content.h:94
Signature_::rev
uint32_t rev
Definition: detect.h:645
DetectEngineFrameInspectionEngine::v1
struct DetectEngineFrameInspectionEngine::@83 v1
FatalError
#define FatalError(...)
Definition: util-debug.h:502
DETECT_BYTEJUMP_BASE_DEC
#define DETECT_BYTEJUMP_BASE_DEC
Definition: detect-bytejump.h:30
DetectIpOptsData_
Definition: detect-ipopts.h:37
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:306
TransformData_::transform
int transform
Definition: detect.h:406
DETECT_FLOWBITS
@ DETECT_FLOWBITS
Definition: detect-engine-register.h:62
SIG_TYPE_MAX
@ SIG_TYPE_MAX
Definition: detect.h:78
DetectEngineCtx_::ea
struct EngineAnalysisCtx_ * ea
Definition: detect.h:1048
DetectEngineAppInspectionEngine_::progress
int16_t progress
Definition: detect.h:441
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
ConfigGetLogDirectory
const char * ConfigGetLogDirectory(void)
Definition: util-conf.c:38
FpPatternStats
struct FpPatternStats_ FpPatternStats
detect-tcp-ack.h
str
#define str(s)
Definition: suricata-common.h:291
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SigMatchListSMBelongsTo
int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
Definition: detect-parse.c:831
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DetectFlowbitsData_::or_list
uint32_t * or_list
Definition: detect-flowbits.h:39
ConfNode_
Definition: conf.h:32
Signature_::id
uint32_t id
Definition: detect.h:643
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
DetectBufferType_::transforms
DetectEngineTransforms transforms
Definition: detect.h:470
DetectEnginePktInspectionEngine::v1
struct DetectEnginePktInspectionEngine::@82 v1
detect-parse.h
Signature_
Signature container.
Definition: detect.h:608
SigMatch_
a single match condition for a signature
Definition: detect.h:351
DetectEngineAppInspectionEngine_::transforms
const DetectEngineTransforms * transforms
Definition: detect.h:450
DETECT_SM_LIST_MAX
@ DETECT_SM_LIST_MAX
Definition: detect.h:134
FpPatternStats_::tot
uint64_t tot
Definition: detect-engine-analyzer.c:74
DETECT_BYTETEST_STRING
#define DETECT_BYTETEST_STRING
Definition: detect-bytetest.h:45
DetectBytetestData_::offset
int32_t offset
Definition: detect-bytetest.h:60
DetectFlagsData_
Definition: detect-tcp-flags.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
detect-ipopts.h
DetectEngineTransforms::cnt
int cnt
Definition: detect.h:412
suricata.h
DetectPcreData_
Definition: detect-pcre.h:47
DetectEngineAppInspectionEngine_::dir
uint8_t dir
Definition: detect.h:433
DetectEngineAnalyzerItems::item_name
const char * item_name
Definition: detect-engine-analyzer.c:66
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:80
DETECT_BYTEJUMP_STRING
#define DETECT_BYTEJUMP_STRING
Definition: detect-bytejump.h:37
DetectEngineCtx_::buffer_type_id
uint32_t buffer_type_id
Definition: detect.h:1000
EngineAnalysisCtx_::file_prefix
char * file_prefix
Definition: detect-engine-analyzer.c:89
DetectEnginePktInspectionEngine::mpm
bool mpm
Definition: detect.h:492
DETECT_BYTEJUMP_BEGIN
#define DETECT_BYTEJUMP_BEGIN
Definition: detect-bytejump.h:34
DETECT_PCRE_RELATIVE
#define DETECT_PCRE_RELATIVE
Definition: detect-pcre.h:29
RuleAnalyzer
struct RuleAnalyzer RuleAnalyzer
DETECT_WINDOW
@ DETECT_WINDOW
Definition: detect-engine-register.h:40
SIG_FLAG_TLSSTORE
#define SIG_FLAG_TLSSTORE
Definition: detect.h:272
DetectU16Data
DetectUintData_u16 DetectU16Data
Definition: detect-engine-uint.h:42
Signature_::msg
char * msg
Definition: detect.h:666
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
DETECT_FLAGS
@ DETECT_FLAGS
Definition: detect-engine-register.h:44
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:107
Signature_::type
enum SignatureType type
Definition: detect.h:611
FpPatternStats_
Definition: detect-engine-analyzer.c:70
DetectBytetestData_::base
uint8_t base
Definition: detect-bytetest.h:56
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:69
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:276
DETECT_TCPMSS
@ DETECT_TCPMSS
Definition: detect-engine-register.h:296
DetectAckData_
ack data
Definition: detect-tcp-ack.h:30
SIG_FLAG_FILESTORE
#define SIG_FLAG_FILESTORE
Definition: detect.h:267
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:243
DETECT_FLOWBITS_CMD_SET
#define DETECT_FLOWBITS_CMD_SET
Definition: detect-flowbits.h:28
SIG_FLAG_DSIZE
#define SIG_FLAG_DSIZE
Definition: detect.h:247
DetectBytejumpData_::flags
uint16_t flags
Definition: detect-bytejump.h:49
Signature_::mask
SignatureMask mask
Definition: detect.h:619
SIG_TYPE_LIKE_IPONLY
@ SIG_TYPE_LIKE_IPONLY
Definition: detect.h:66
detect-bytetest.h
DetectProtoContainsProto
int DetectProtoContainsProto(const DetectProto *dp, int proto)
see if a DetectProto contains a certain proto
Definition: detect-engine-proto.c:135
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:252
DetectEngineFrameInspectionEngine::smd
SigMatchData * smd
Definition: detect.h:527
ConfNodeLookupChildValue
const char * ConfNodeLookupChildValue(const ConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:809