suricata
detect-engine-analyzer.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2020 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 "detect.h"
31 #include "detect-parse.h"
32 #include "detect-engine.h"
33 #include "detect-engine-analyzer.h"
34 #include "detect-engine-mpm.h"
35 #include "conf.h"
36 #include "detect-content.h"
37 #include "detect-flow.h"
38 #include "detect-tcp-flags.h"
39 #include "feature.h"
40 #include "util-print.h"
41 
42 static int rule_warnings_only = 0;
43 static FILE *rule_engine_analysis_FD = NULL;
44 static FILE *fp_engine_analysis_FD = NULL;
45 static pcre2_code *percent_re = NULL;
46 static pcre2_match_data *percent_re_match = NULL;
47 static char log_path[PATH_MAX];
48 
49 typedef struct FpPatternStats_ {
50  uint16_t min;
51  uint16_t max;
52  uint32_t cnt;
53  uint64_t tot;
55 
56 /* Details for each buffer being tracked */
57 typedef struct DetectEngineAnalyzerItems {
58  int16_t item_id;
59  bool item_seen;
62  const char *item_name;
63  const char *display_name;
65 
66 /* Track which items require the item_seen value to be exposed */
68  const char *bufname;
70 };
71 
73  /* request keywords */
74  { 0, false, false, true, "http_uri", "http uri" },
75  { 0, false, false, false, "http_raw_uri", "http raw uri" },
76  { 0, false, true, false, "http_method", "http method" },
77  { 0, false, false, false, "http_request_line", "http request line" },
78  { 0, false, false, false, "http_client_body", "http client body" },
79  { 0, false, false, true, "http_header", "http header" },
80  { 0, false, false, false, "http_raw_header", "http raw header" },
81  { 0, false, false, true, "http_cookie", "http cookie" },
82  { 0, false, false, false, "http_user_agent", "http user agent" },
83  { 0, false, false, false, "http_host", "http host" },
84  { 0, false, false, false, "http_raw_host", "http raw host" },
85  { 0, false, false, false, "http_accept_enc", "http accept enc" },
86  { 0, false, false, false, "http_referer", "http referer" },
87  { 0, false, false, false, "http_content_type", "http content type" },
88  { 0, false, false, false, "http_header_names", "http header names" },
89 
90  /* response keywords not listed above */
91  { 0, false, false, false, "http_stat_msg", "http stat msg" },
92  { 0, false, false, false, "http_stat_code", "http stat code" },
93  { 0, false, true, false, "file_data", "http server body"},
94 
95  /* missing request keywords */
96  { 0, false, false, false, "http_request_line", "http request line" },
97  { 0, false, false, false, "http_accept", "http accept" },
98  { 0, false, false, false, "http_accept_lang", "http accept lang" },
99  { 0, false, false, false, "http_connection", "http connection" },
100  { 0, false, false, false, "http_content_len", "http content len" },
101  { 0, false, false, false, "http_protocol", "http protocol" },
102  { 0, false, false, false, "http_start", "http start" },
103 
104  /* missing response keywords; some of the missing are listed above*/
105  { 0, false, false, false, "http_response_line", "http response line" },
106  { 0, false, false, false, "http.server", "http server" },
107  { 0, false, false, false, "http.location", "http location" },
108 };
109 
110 /*
111  * This array contains the map between the `analyzer_items` array listed above and
112  * the item ids returned by DetectBufferTypeGetByName. Iterating signature's sigmatch
113  * array provides list_ids. The map converts those ids into elements of the
114  * analyzer items array.
115  *
116  * Ultimately, the g_buffer_type_hash is searched for each buffer name. The size of that
117  * hashlist is 256, so that's the value we use here.
118  */
119 int16_t analyzer_item_map[256];
120 
121 /*
122  * Certain values must be directly accessible. This array contains items that are directly
123  * accessed when checking if they've been seen or not.
124  */
126  { .bufname = "http_method"},
127  { .bufname = "file_data"}
128 };
129 
130 static FpPatternStats fp_pattern_stats[DETECT_SM_LIST_MAX];
131 
132 static void FpPatternStatsAdd(int list, uint16_t patlen)
133 {
134  if (list < 0 || list >= DETECT_SM_LIST_MAX)
135  return;
136 
137  FpPatternStats *f = &fp_pattern_stats[list];
138 
139  if (f->min == 0)
140  f->min = patlen;
141  else if (patlen < f->min)
142  f->min = patlen;
143 
144  if (patlen > f->max)
145  f->max = patlen;
146 
147  f->cnt++;
148  f->tot += patlen;
149 }
150 
151 void EngineAnalysisFP(const DetectEngineCtx *de_ctx, const Signature *s, char *line)
152 {
153  int fast_pattern_set = 0;
154  int fast_pattern_only_set = 0;
155  int fast_pattern_chop_set = 0;
156  const DetectContentData *fp_cd = NULL;
157  const SigMatch *mpm_sm = s->init_data->mpm_sm;
158  const int mpm_sm_list = s->init_data->mpm_sm_list;
159 
160  if (mpm_sm != NULL) {
161  fp_cd = (DetectContentData *)mpm_sm->ctx;
162  if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN) {
163  fast_pattern_set = 1;
165  fast_pattern_only_set = 1;
166  } else if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) {
167  fast_pattern_chop_set = 1;
168  }
169  }
170  }
171 
172  fprintf(fp_engine_analysis_FD, "== Sid: %u ==\n", s->id);
173  fprintf(fp_engine_analysis_FD, "%s\n", line);
174 
175  fprintf(fp_engine_analysis_FD, " Fast Pattern analysis:\n");
176  if (s->init_data->prefilter_sm != NULL) {
177  fprintf(fp_engine_analysis_FD, " Prefilter on: %s\n",
179  fprintf(fp_engine_analysis_FD, "\n");
180  return;
181  }
182 
183  if (fp_cd == NULL) {
184  fprintf(fp_engine_analysis_FD, " No content present\n");
185  fprintf(fp_engine_analysis_FD, "\n");
186  return;
187  }
188 
189  fprintf(fp_engine_analysis_FD, " Fast pattern matcher: ");
190  int list_type = mpm_sm_list;
191  if (list_type == DETECT_SM_LIST_PMATCH)
192  fprintf(fp_engine_analysis_FD, "content\n");
193  else {
194  const char *desc = DetectEngineBufferTypeGetDescriptionById(de_ctx, list_type);
195  const char *name = DetectEngineBufferTypeGetNameById(de_ctx, list_type);
196  if (desc && name) {
197  fprintf(fp_engine_analysis_FD, "%s (%s)\n", desc, name);
198  }
199  }
200 
201  int flags_set = 0;
202  fprintf(fp_engine_analysis_FD, " Flags:");
203  if (fp_cd->flags & DETECT_CONTENT_OFFSET) {
204  fprintf(fp_engine_analysis_FD, " Offset");
205  flags_set = 1;
206  } if (fp_cd->flags & DETECT_CONTENT_DEPTH) {
207  fprintf(fp_engine_analysis_FD, " Depth");
208  flags_set = 1;
209  }
210  if (fp_cd->flags & DETECT_CONTENT_WITHIN) {
211  fprintf(fp_engine_analysis_FD, " Within");
212  flags_set = 1;
213  }
214  if (fp_cd->flags & DETECT_CONTENT_DISTANCE) {
215  fprintf(fp_engine_analysis_FD, " Distance");
216  flags_set = 1;
217  }
218  if (fp_cd->flags & DETECT_CONTENT_NOCASE) {
219  fprintf(fp_engine_analysis_FD, " Nocase");
220  flags_set = 1;
221  }
222  if (fp_cd->flags & DETECT_CONTENT_NEGATED) {
223  fprintf(fp_engine_analysis_FD, " Negated");
224  flags_set = 1;
225  }
226  if (flags_set == 0)
227  fprintf(fp_engine_analysis_FD, " None");
228  fprintf(fp_engine_analysis_FD, "\n");
229 
230  fprintf(fp_engine_analysis_FD, " Fast pattern set: %s\n", fast_pattern_set ? "yes" : "no");
231  fprintf(fp_engine_analysis_FD, " Fast pattern only set: %s\n",
232  fast_pattern_only_set ? "yes" : "no");
233  fprintf(fp_engine_analysis_FD, " Fast pattern chop set: %s\n",
234  fast_pattern_chop_set ? "yes" : "no");
235  if (fast_pattern_chop_set) {
236  fprintf(fp_engine_analysis_FD, " Fast pattern offset, length: %u, %u\n",
237  fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
238  }
239 
240  uint16_t patlen = fp_cd->content_len;
241  uint8_t *pat = SCMalloc(fp_cd->content_len + 1);
242  if (unlikely(pat == NULL)) {
243  FatalError(SC_ERR_FATAL, "Error allocating memory");
244  }
245  memcpy(pat, fp_cd->content, fp_cd->content_len);
246  pat[fp_cd->content_len] = '\0';
247  fprintf(fp_engine_analysis_FD, " Original content: ");
248  PrintRawUriFp(fp_engine_analysis_FD, pat, patlen);
249  fprintf(fp_engine_analysis_FD, "\n");
250 
251  if (fast_pattern_chop_set) {
252  SCFree(pat);
253  patlen = fp_cd->fp_chop_len;
254  pat = SCMalloc(fp_cd->fp_chop_len + 1);
255  if (unlikely(pat == NULL)) {
256  exit(EXIT_FAILURE);
257  }
258  memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
259  pat[fp_cd->fp_chop_len] = '\0';
260  fprintf(fp_engine_analysis_FD, " Final content: ");
261  PrintRawUriFp(fp_engine_analysis_FD, pat, patlen);
262  fprintf(fp_engine_analysis_FD, "\n");
263 
264  FpPatternStatsAdd(list_type, patlen);
265  } else {
266  fprintf(fp_engine_analysis_FD, " Final content: ");
267  PrintRawUriFp(fp_engine_analysis_FD, pat, patlen);
268  fprintf(fp_engine_analysis_FD, "\n");
269 
270  FpPatternStatsAdd(list_type, patlen);
271  }
272  SCFree(pat);
273 
274  fprintf(fp_engine_analysis_FD, "\n");
275  return;
276 }
277 
278 /**
279  * \brief Sets up the fast pattern analyzer according to the config.
280  *
281  * \retval 1 If rule analyzer successfully enabled.
282  * \retval 0 If not enabled.
283  */
285 {
286  int fp_engine_analysis_set = 0;
287 
288  if ((ConfGetBool("engine-analysis.rules-fast-pattern",
289  &fp_engine_analysis_set)) == 0) {
290  return 0;
291  }
292 
293  if (fp_engine_analysis_set == 0)
294  return 0;
295 
296  const char *log_dir;
297  log_dir = ConfigGetLogDirectory();
298  snprintf(log_path, sizeof(log_path), "%s/%s", log_dir,
299  "rules_fast_pattern.txt");
300 
301  fp_engine_analysis_FD = fopen(log_path, "w");
302  if (fp_engine_analysis_FD == NULL) {
303  SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", log_path,
304  strerror(errno));
305  return 0;
306  }
307 
308  SCLogInfo("Engine-Analysis for fast_pattern printed to file - %s",
309  log_path);
310 
311  struct timeval tval;
312  struct tm *tms;
313  gettimeofday(&tval, NULL);
314  struct tm local_tm;
315  tms = SCLocalTime(tval.tv_sec, &local_tm);
316  fprintf(fp_engine_analysis_FD, "----------------------------------------------"
317  "---------------------\n");
318  fprintf(fp_engine_analysis_FD, "Date: %" PRId32 "/%" PRId32 "/%04d -- "
319  "%02d:%02d:%02d\n",
320  tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour,
321  tms->tm_min, tms->tm_sec);
322  fprintf(fp_engine_analysis_FD, "----------------------------------------------"
323  "---------------------\n");
324 
325  memset(&fp_pattern_stats, 0, sizeof(fp_pattern_stats));
326  return 1;
327 }
328 
329 /**
330  * \brief Sets up the rule analyzer according to the config
331  * \retval 1 if rule analyzer successfully enabled
332  * \retval 0 if not enabled
333  */
335 {
336  ConfNode *conf = ConfGetNode("engine-analysis");
337  int enabled = 0;
338  if (conf != NULL) {
339  const char *value = ConfNodeLookupChildValue(conf, "rules");
340  if (value && ConfValIsTrue(value)) {
341  enabled = 1;
342  } else if (value && strcasecmp(value, "warnings-only") == 0) {
343  enabled = 1;
344  rule_warnings_only = 1;
345  }
346  if (enabled) {
347  const char *log_dir;
348  log_dir = ConfigGetLogDirectory();
349  snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, "rules_analysis.txt");
350  rule_engine_analysis_FD = fopen(log_path, "w");
351  if (rule_engine_analysis_FD == NULL) {
352  SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", log_path, strerror(errno));
353  return 0;
354  }
355 
356  SCLogInfo("Engine-Analysis for rules printed to file - %s",
357  log_path);
358 
359  struct timeval tval;
360  struct tm *tms;
361  gettimeofday(&tval, NULL);
362  struct tm local_tm;
363  tms = SCLocalTime(tval.tv_sec, &local_tm);
364  fprintf(rule_engine_analysis_FD, "----------------------------------------------"
365  "---------------------\n");
366  fprintf(rule_engine_analysis_FD, "Date: %" PRId32 "/%" PRId32 "/%04d -- "
367  "%02d:%02d:%02d\n",
368  tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour,
369  tms->tm_min, tms->tm_sec);
370  fprintf(rule_engine_analysis_FD, "----------------------------------------------"
371  "---------------------\n");
372 
373  /*compile regex's for rule analysis*/
374  if (PerCentEncodingSetup()== 0) {
375  fprintf(rule_engine_analysis_FD, "Error compiling regex; can't check for percent encoding in normalized http content.\n");
376  }
377  }
378  }
379  else {
380  SCLogInfo("Conf parameter \"engine-analysis.rules\" not found. "
381  "Defaulting to not printing the rules analysis report.");
382  }
383  if (!enabled) {
384  SCLogInfo("Engine-Analysis for rules disabled in conf file.");
385  return 0;
386  }
387  return 1;
388 }
389 
391 {
392  fprintf(fp_engine_analysis_FD, "============\n"
393  "Summary:\n============\n");
394  int i;
395  for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
396  FpPatternStats *f = &fp_pattern_stats[i];
397  if (f->cnt == 0)
398  continue;
399 
400  fprintf(fp_engine_analysis_FD,
401  "%s, smallest pattern %u byte(s), longest pattern %u byte(s), number of patterns %u, avg pattern len %.2f byte(s)\n",
402  DetectSigmatchListEnumToString(i), f->min, f->max, f->cnt, (float)((double)f->tot/(float)f->cnt));
403  }
404 
405  if (fp_engine_analysis_FD != NULL) {
406  fclose(fp_engine_analysis_FD);
407  fp_engine_analysis_FD = NULL;
408  }
409 
410  return;
411 }
412 
413 
415 {
416  if (rule_engine_analysis_FD != NULL) {
417  SCLogInfo("Engine-Analysis for rules printed to file - %s", log_path);
418  fclose(rule_engine_analysis_FD);
419  rule_engine_analysis_FD = NULL;
420  }
421  if (percent_re != NULL) {
422  pcre2_code_free(percent_re);
423  }
424  pcre2_match_data_free(percent_re_match);
425 }
426 
427 /**
428  * \brief Compiles regex for rule analysis
429  * \retval 1 if successful
430  * \retval 0 if on error
431  */
433 {
434 #define DETECT_PERCENT_ENCODING_REGEX "%[0-9|a-f|A-F]{2}"
435  int en;
436  PCRE2_SIZE eo = 0;
437  int opts = 0; // PCRE2_NEWLINE_ANY??
438 
439  percent_re = pcre2_compile((PCRE2_SPTR8)DETECT_PERCENT_ENCODING_REGEX, PCRE2_ZERO_TERMINATED,
440  opts, &en, &eo, NULL);
441  if (percent_re == NULL) {
442  PCRE2_UCHAR errbuffer[256];
443  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
444  SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %d: %s",
445  DETECT_PERCENT_ENCODING_REGEX, (int)eo, errbuffer);
446  return 0;
447  }
448 
449  percent_re_match = pcre2_match_data_create_from_pattern(percent_re, NULL);
450  return 1;
451 }
452 
453 /**
454  * \brief Checks for % encoding in content.
455  * \param Pointer to content
456  * \retval number of matches if content has % encoding
457  * \retval 0 if it doesn't have % encoding
458  * \retval -1 on error
459  */
460 int PerCentEncodingMatch (uint8_t *content, uint8_t content_len)
461 {
462  int ret = 0;
463 
464  ret = pcre2_match(percent_re, (PCRE2_SPTR8)content, content_len, 0, 0, percent_re_match, NULL);
465  if (ret == -1) {
466  return 0;
467  }
468  else if (ret < -1) {
469  SCLogError(SC_ERR_PCRE_MATCH, "Error parsing content - %s; error code is %d", content, ret);
470  return -1;
471  }
472  return ret;
473 }
474 
475 static void EngineAnalysisRulesPrintFP(const DetectEngineCtx *de_ctx, const Signature *s)
476 {
477  const DetectContentData *fp_cd = NULL;
478  const SigMatch *mpm_sm = s->init_data->mpm_sm;
479  const int mpm_sm_list = s->init_data->mpm_sm_list;
480 
481  if (mpm_sm != NULL) {
482  fp_cd = (DetectContentData *)mpm_sm->ctx;
483  }
484 
485  if (fp_cd == NULL) {
486  return;
487  }
488 
489  uint16_t patlen = fp_cd->content_len;
490  uint8_t *pat = SCMalloc(fp_cd->content_len + 1);
491  if (unlikely(pat == NULL)) {
492  FatalError(SC_ERR_FATAL, "Error allocating memory");
493  }
494  memcpy(pat, fp_cd->content, fp_cd->content_len);
495  pat[fp_cd->content_len] = '\0';
496 
498  SCFree(pat);
499  patlen = fp_cd->fp_chop_len;
500  pat = SCMalloc(fp_cd->fp_chop_len + 1);
501  if (unlikely(pat == NULL)) {
502  exit(EXIT_FAILURE);
503  }
504  memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
505  pat[fp_cd->fp_chop_len] = '\0';
506  fprintf(rule_engine_analysis_FD, " Fast Pattern \"");
507  PrintRawUriFp(rule_engine_analysis_FD, pat, patlen);
508  } else {
509  fprintf(rule_engine_analysis_FD, " Fast Pattern \"");
510  PrintRawUriFp(rule_engine_analysis_FD, pat, patlen);
511  }
512  SCFree(pat);
513 
514  fprintf(rule_engine_analysis_FD, "\" on \"");
515 
516  const int list_type = mpm_sm_list;
517  if (list_type == DETECT_SM_LIST_PMATCH) {
518  int payload = 0;
519  int stream = 0;
521  payload = 1;
523  stream = 1;
524  fprintf(rule_engine_analysis_FD, "%s",
525  payload ? (stream ? "payload and reassembled stream" : "payload") : "reassembled stream");
526  }
527  else {
528  const char *desc = DetectEngineBufferTypeGetDescriptionById(de_ctx, list_type);
529  const char *name = DetectEngineBufferTypeGetNameById(de_ctx, list_type);
530  if (desc && name) {
531  fprintf(rule_engine_analysis_FD, "%s (%s)", desc, name);
532  } else if (desc || name) {
533  fprintf(rule_engine_analysis_FD, "%s", desc ? desc : name);
534  }
535 
536  }
537 
538  fprintf(rule_engine_analysis_FD, "\" ");
539  const DetectBufferType *bt = DetectEngineBufferTypeGetById(de_ctx, list_type);
540  if (bt && bt->transforms.cnt) {
541  fprintf(rule_engine_analysis_FD, "(with %d transform(s)) ", bt->transforms.cnt);
542  }
543  fprintf(rule_engine_analysis_FD, "buffer.\n");
544 
545  return;
546 }
547 
548 
549 void EngineAnalysisRulesFailure(char *line, char *file, int lineno)
550 {
551  fprintf(rule_engine_analysis_FD, "== Sid: UNKNOWN ==\n");
552  fprintf(rule_engine_analysis_FD, "%s\n", line);
553  fprintf(rule_engine_analysis_FD, " FAILURE: invalid rule.\n");
554  fprintf(rule_engine_analysis_FD, " File: %s.\n", file);
555  fprintf(rule_engine_analysis_FD, " Line: %d.\n", lineno);
556  fprintf(rule_engine_analysis_FD, "\n");
557 }
558 
559 typedef struct RuleAnalyzer {
560  JsonBuilder *js; /* document root */
561 
562  JsonBuilder *js_warnings;
563  JsonBuilder *js_notes;
565 
566 static void ATTR_FMT_PRINTF(2, 3) AnalyzerNote(RuleAnalyzer *ctx, char *fmt, ...)
567 {
568  va_list ap;
569  char str[1024];
570 
571  va_start(ap, fmt);
572  vsnprintf(str, sizeof(str), fmt, ap);
573  va_end(ap);
574 
575  if (!ctx->js_notes)
576  ctx->js_notes = jb_new_array();
577  if (ctx->js_notes)
578  jb_append_string(ctx->js_notes, str);
579 }
580 
581 static void ATTR_FMT_PRINTF(2, 3) AnalyzerWarning(RuleAnalyzer *ctx, char *fmt, ...)
582 {
583  va_list ap;
584  char str[1024];
585 
586  va_start(ap, fmt);
587  vsnprintf(str, sizeof(str), fmt, ap);
588  va_end(ap);
589 
590  if (!ctx->js_warnings)
591  ctx->js_warnings = jb_new_array();
592  if (ctx->js_warnings)
593  jb_append_string(ctx->js_warnings, str);
594 }
595 
596 #define CHECK(pat) if (strlen((pat)) <= len && memcmp((pat), buf, MIN(len, strlen((pat)))) == 0) return true;
597 
598 static bool LooksLikeHTTPMethod(const uint8_t *buf, uint16_t len)
599 {
600  CHECK("GET /");
601  CHECK("POST /");
602  CHECK("HEAD /");
603  CHECK("PUT /");
604  return false;
605 }
606 
607 static bool LooksLikeHTTPUA(const uint8_t *buf, uint16_t len)
608 {
609  CHECK("User-Agent: ");
610  CHECK("\nUser-Agent: ");
611  return false;
612 }
613 
614 static void DumpContent(JsonBuilder *js, const DetectContentData *cd)
615 {
616  char pattern_str[1024] = "";
617  DetectContentPatternPrettyPrint(cd, pattern_str, sizeof(pattern_str));
618 
619  jb_set_string(js, "pattern", pattern_str);
620  jb_set_uint(js, "length", cd->content_len);
621  jb_set_bool(js, "nocase", cd->flags & DETECT_CONTENT_NOCASE);
622  jb_set_bool(js, "negated", cd->flags & DETECT_CONTENT_NEGATED);
623  jb_set_bool(js, "starts_with", cd->flags & DETECT_CONTENT_STARTS_WITH);
624  jb_set_bool(js, "ends_with", cd->flags & DETECT_CONTENT_ENDS_WITH);
625  jb_set_bool(js, "is_mpm", cd->flags & DETECT_CONTENT_MPM);
626  jb_set_bool(js, "no_double_inspect", cd->flags & DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED);
627  if (cd->flags & DETECT_CONTENT_OFFSET) {
628  jb_set_uint(js, "offset", cd->offset);
629  }
630  if (cd->flags & DETECT_CONTENT_DEPTH) {
631  jb_set_uint(js, "depth", cd->depth);
632  }
633  if (cd->flags & DETECT_CONTENT_DISTANCE) {
634  jb_set_uint(js, "distance", cd->distance);
635  }
636  if (cd->flags & DETECT_CONTENT_WITHIN) {
637  jb_set_uint(js, "within", cd->within);
638  }
639  jb_set_bool(js, "fast_pattern", cd->flags & DETECT_CONTENT_FAST_PATTERN);
640 }
641 
642 static void DumpMatches(RuleAnalyzer *ctx, JsonBuilder *js, const SigMatchData *smd)
643 {
644  if (smd == NULL)
645  return;
646 
647  jb_open_array(js, "matches");
648  do {
649  jb_start_object(js);
650  const char *mname = sigmatch_table[smd->type].name;
651  jb_set_string(js, "name", mname);
652 
653  switch (smd->type) {
654  case DETECT_CONTENT: {
655  const DetectContentData *cd = (const DetectContentData *)smd->ctx;
656 
657  jb_open_object(js, "content");
658  DumpContent(js, cd);
660  AnalyzerNote(ctx, (char *)"'fast_pattern:only' option is silently ignored and "
661  "is interpreted as regular 'fast_pattern'");
662  }
663  if (LooksLikeHTTPMethod(cd->content, cd->content_len)) {
664  AnalyzerWarning(ctx,
665  (char *)"pattern looks like it inspects HTTP, use http.request_line or "
666  "http.method and http.uri instead for improved performance");
667  }
668  if (LooksLikeHTTPUA(cd->content, cd->content_len)) {
669  AnalyzerWarning(ctx,
670  (char *)"pattern looks like it inspects HTTP, use http.user_agent "
671  "or http.header for improved performance");
672  }
673  jb_close(js);
674  break;
675  }
676  }
677  jb_close(js);
678 
679  if (smd->is_last)
680  break;
681  smd++;
682  } while (1);
683  jb_close(js);
684 }
685 
688 {
689  SCEnter();
690 
691  RuleAnalyzer ctx = { NULL, NULL, NULL };
692 
693  ctx.js = jb_new_object();
694  if (ctx.js == NULL)
695  SCReturn;
696 
697  jb_set_string(ctx.js, "raw", s->sig_str);
698  jb_set_uint(ctx.js, "id", s->id);
699  jb_set_uint(ctx.js, "gid", s->gid);
700  jb_set_uint(ctx.js, "rev", s->rev);
701  jb_set_string(ctx.js, "msg", s->msg);
702 
703  const char *alproto = AppProtoToString(s->alproto);
704  jb_set_string(ctx.js, "app_proto", alproto);
705 
706  jb_open_array(ctx.js, "requirements");
707  if (s->mask & SIG_MASK_REQUIRE_PAYLOAD) {
708  jb_append_string(ctx.js, "payload");
709  }
711  jb_append_string(ctx.js, "no_payload");
712  }
713  if (s->mask & SIG_MASK_REQUIRE_FLOW) {
714  jb_append_string(ctx.js, "flow");
715  }
717  jb_append_string(ctx.js, "tcp_flags_init_deinit");
718  }
720  jb_append_string(ctx.js, "tcp_flags_unusual");
721  }
722  if (s->mask & SIG_MASK_REQUIRE_DCERPC) {
723  jb_append_string(ctx.js, "dcerpc");
724  }
726  jb_append_string(ctx.js, "engine_event");
727  }
728  jb_close(ctx.js);
729 
730  jb_open_array(ctx.js, "flags");
731  if (s->flags & SIG_FLAG_SRC_ANY) {
732  jb_append_string(ctx.js, "src_any");
733  }
734  if (s->flags & SIG_FLAG_DST_ANY) {
735  jb_append_string(ctx.js, "dst_any");
736  }
737  if (s->flags & SIG_FLAG_SP_ANY) {
738  jb_append_string(ctx.js, "sp_any");
739  }
740  if (s->flags & SIG_FLAG_DP_ANY) {
741  jb_append_string(ctx.js, "dp_any");
742  }
743  if (s->flags & SIG_FLAG_NOALERT) {
744  jb_append_string(ctx.js, "noalert");
745  }
746  if (s->flags & SIG_FLAG_DSIZE) {
747  jb_append_string(ctx.js, "dsize");
748  }
749  if (s->flags & SIG_FLAG_APPLAYER) {
750  jb_append_string(ctx.js, "applayer");
751  }
752  if (s->flags & SIG_FLAG_IPONLY) {
753  jb_append_string(ctx.js, "ip_only");
754  }
755  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
756  jb_append_string(ctx.js, "need_packet");
757  }
758  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
759  jb_append_string(ctx.js, "need_stream");
760  }
761  if (s->flags & SIG_FLAG_MPM_NEG) {
762  jb_append_string(ctx.js, "negated_mpm");
763  }
764  if (s->flags & SIG_FLAG_FLUSH) {
765  jb_append_string(ctx.js, "flush");
766  }
767  if (s->flags & SIG_FLAG_REQUIRE_FLOWVAR) {
768  jb_append_string(ctx.js, "need_flowvar");
769  }
770  if (s->flags & SIG_FLAG_FILESTORE) {
771  jb_append_string(ctx.js, "filestore");
772  }
773  if (s->flags & SIG_FLAG_TOSERVER) {
774  jb_append_string(ctx.js, "toserver");
775  }
776  if (s->flags & SIG_FLAG_TOCLIENT) {
777  jb_append_string(ctx.js, "toclient");
778  }
779  if (s->flags & SIG_FLAG_TLSSTORE) {
780  jb_append_string(ctx.js, "tlsstore");
781  }
782  if (s->flags & SIG_FLAG_BYPASS) {
783  jb_append_string(ctx.js, "bypass");
784  }
785  if (s->flags & SIG_FLAG_PREFILTER) {
786  jb_append_string(ctx.js, "prefilter");
787  }
788  if (s->flags & SIG_FLAG_PDONLY) {
789  jb_append_string(ctx.js, "proto_detect_only");
790  }
791  if (s->flags & SIG_FLAG_SRC_IS_TARGET) {
792  jb_append_string(ctx.js, "src_is_target");
793  }
794  if (s->flags & SIG_FLAG_DEST_IS_TARGET) {
795  jb_append_string(ctx.js, "dst_is_target");
796  }
797  jb_close(ctx.js);
798 
799  const DetectEnginePktInspectionEngine *pkt_mpm = NULL;
800  const DetectEngineAppInspectionEngine *app_mpm = NULL;
801 
802  jb_open_array(ctx.js, "pkt_engines");
804  for ( ; pkt != NULL; pkt = pkt->next) {
805  const char *name = DetectEngineBufferTypeGetNameById(de_ctx, pkt->sm_list);
806  if (name == NULL) {
807  switch (pkt->sm_list) {
809  name = "payload";
810  break;
812  name = "packet";
813  break;
814  default:
815  name = "unknown";
816  break;
817  }
818  }
819  jb_start_object(ctx.js);
820  jb_set_string(ctx.js, "name", name);
821  jb_set_bool(ctx.js, "is_mpm", pkt->mpm);
822  DumpMatches(&ctx, ctx.js, pkt->smd);
823  jb_close(ctx.js);
824  if (pkt->mpm) {
825  pkt_mpm = pkt;
826  }
827  }
828  jb_close(ctx.js);
829  jb_open_array(ctx.js, "frame_engines");
831  for (; frame != NULL; frame = frame->next) {
832  const char *name = DetectEngineBufferTypeGetNameById(de_ctx, frame->sm_list);
833  jb_start_object(ctx.js);
834  jb_set_string(ctx.js, "name", name);
835  jb_set_bool(ctx.js, "is_mpm", frame->mpm);
836  DumpMatches(&ctx, ctx.js, frame->smd);
837  jb_close(ctx.js);
838  }
839  jb_close(ctx.js);
840 
842  bool has_stream = false;
843  bool has_client_body_mpm = false;
844  bool has_file_data_mpm = false;
845 
846  jb_open_array(ctx.js, "engines");
848  for ( ; app != NULL; app = app->next) {
849  const char *name = DetectEngineBufferTypeGetNameById(de_ctx, app->sm_list);
850  if (name == NULL) {
851  switch (app->sm_list) {
853  name = "stream";
854  break;
855  default:
856  name = "unknown";
857  break;
858  }
859  }
860 
861  if (app->sm_list == DETECT_SM_LIST_PMATCH && !app->mpm) {
862  has_stream = true;
863  } else if (app->mpm && strcmp(name, "http_client_body") == 0) {
864  has_client_body_mpm = true;
865  } else if (app->mpm && strcmp(name, "file_data") == 0) {
866  has_file_data_mpm = true;
867  }
868 
869  jb_start_object(ctx.js);
870  jb_set_string(ctx.js, "name", name);
871  const char *direction = app->dir == 0 ? "toserver" : "toclient";
872  jb_set_string(ctx.js, "direction", direction);
873  jb_set_bool(ctx.js, "is_mpm", app->mpm);
874  jb_set_string(ctx.js, "app_proto", AppProtoToString(app->alproto));
875  jb_set_uint(ctx.js, "progress", app->progress);
876  DumpMatches(&ctx, ctx.js, app->smd);
877  jb_close(ctx.js);
878  if (app->mpm) {
879  app_mpm = app;
880  }
881  }
882  jb_close(ctx.js);
883 
884  if (has_stream && has_client_body_mpm)
885  AnalyzerNote(&ctx, (char *)"mpm in http_client_body combined with stream match leads to stream buffering");
886  if (has_stream && has_file_data_mpm)
887  AnalyzerNote(&ctx, (char *)"mpm in file_data combined with stream match leads to stream buffering");
888  }
889 
890  jb_open_object(ctx.js, "lists");
891  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
892  if (s->sm_arrays[i] != NULL) {
893  jb_open_object(ctx.js, DetectSigmatchListEnumToString(i));
894  DumpMatches(&ctx, ctx.js, s->sm_arrays[i]);
895  jb_close(ctx.js);
896  }
897  }
898  jb_close(ctx.js);
899 
900  if (pkt_mpm || app_mpm) {
901  jb_open_object(ctx.js, "mpm");
902 
903  int mpm_list = pkt_mpm ? DETECT_SM_LIST_PMATCH : app_mpm->sm_list;
904  const char *name;
905  if (mpm_list < DETECT_SM_LIST_DYNAMIC_START)
906  name = DetectListToHumanString(mpm_list);
907  else
908  name = DetectEngineBufferTypeGetNameById(de_ctx, mpm_list);
909  jb_set_string(ctx.js, "buffer", name);
910 
911  SigMatchData *smd = pkt_mpm ? pkt_mpm->smd : app_mpm->smd;
912  if (smd == NULL && mpm_list == DETECT_SM_LIST_PMATCH) {
913  smd = s->sm_arrays[mpm_list];
914  }
915  do {
916  switch (smd->type) {
917  case DETECT_CONTENT: {
918  const DetectContentData *cd = (const DetectContentData *)smd->ctx;
919  if (cd->flags & DETECT_CONTENT_MPM) {
920  DumpContent(ctx.js, cd);
921  }
922  break;
923  }
924  }
925 
926  if (smd->is_last)
927  break;
928  smd++;
929  } while (1);
930  jb_close(ctx.js);
931  } else if (s->init_data->prefilter_sm) {
932  jb_open_object(ctx.js, "prefilter");
933  int prefilter_list = SigMatchListSMBelongsTo(s, s->init_data->prefilter_sm);
934  const char *name;
935  if (prefilter_list < DETECT_SM_LIST_DYNAMIC_START)
936  name = DetectListToHumanString(prefilter_list);
937  else
938  name = DetectEngineBufferTypeGetNameById(de_ctx, prefilter_list);
939  jb_set_string(ctx.js, "buffer", name);
940  const char *mname = sigmatch_table[s->init_data->prefilter_sm->type].name;
941  jb_set_string(ctx.js, "name", mname);
942  jb_close(ctx.js);
943  }
944 
945  if (ctx.js_warnings) {
946  jb_close(ctx.js_warnings);
947  jb_set_object(ctx.js, "warnings", ctx.js_warnings);
948  jb_free(ctx.js_warnings);
949  ctx.js_warnings = NULL;
950  }
951  if (ctx.js_notes) {
952  jb_close(ctx.js_notes);
953  jb_set_object(ctx.js, "notes", ctx.js_notes);
954  jb_free(ctx.js_notes);
955  ctx.js_notes = NULL;
956  }
957  jb_close(ctx.js);
958 
959  const char *filename = "rules.json";
960  const char *log_dir = ConfigGetLogDirectory();
961  char json_path[PATH_MAX] = "";
962  snprintf(json_path, sizeof(json_path), "%s/%s", log_dir, filename);
963 
965  FILE *fp = fopen(json_path, "a");
966  if (fp != NULL) {
967  fwrite(jb_ptr(ctx.js), jb_len(ctx.js), 1, fp);
968  fprintf(fp, "\n");
969  fclose(fp);
970  }
972  jb_free(ctx.js);
973  SCReturn;
974 }
975 
977 {
978  if (de_ctx->pattern_hash_table == NULL)
979  return;
980 
981  JsonBuilder *root_jb = jb_new_object();
982  JsonBuilder *arrays[de_ctx->buffer_type_id];
983  memset(&arrays, 0, sizeof(JsonBuilder *) * de_ctx->buffer_type_id);
984 
985  jb_open_array(root_jb, "buffers");
986 
988  htb != NULL; htb = HashListTableGetListNext(htb)) {
989  char str[1024] = "";
992 
993  JsonBuilder *jb = arrays[p->sm_list];
994  if (arrays[p->sm_list] == NULL) {
995  jb = arrays[p->sm_list] = jb_new_object();
996  const char *name;
998  name = DetectListToHumanString(p->sm_list);
999  else
1001  jb_set_string(jb, "name", name);
1002  jb_set_uint(jb, "list_id", p->sm_list);
1003 
1004  jb_open_array(jb, "patterns");
1005  }
1006 
1007  jb_start_object(jb);
1008  jb_set_string(jb, "pattern", str);
1009  jb_set_uint(jb, "patlen", p->cd->content_len);
1010  jb_set_uint(jb, "cnt", p->cnt);
1011  jb_set_uint(jb, "mpm", p->mpm);
1012  jb_open_object(jb, "flags");
1013  jb_set_bool(jb, "nocase", p->cd->flags & DETECT_CONTENT_NOCASE);
1014  jb_set_bool(jb, "negated", p->cd->flags & DETECT_CONTENT_NEGATED);
1015  jb_set_bool(jb, "depth", p->cd->flags & DETECT_CONTENT_DEPTH);
1016  jb_set_bool(jb, "offset", p->cd->flags & DETECT_CONTENT_OFFSET);
1017  jb_set_bool(jb, "endswith", p->cd->flags & DETECT_CONTENT_ENDS_WITH);
1018  jb_close(jb);
1019  jb_close(jb);
1020  }
1021 
1022  for (uint32_t i = 0; i < de_ctx->buffer_type_id; i++) {
1023  JsonBuilder *jb = arrays[i];
1024  if (jb == NULL)
1025  continue;
1026 
1027  jb_close(jb); // array
1028  jb_close(jb); // object
1029 
1030  jb_append_object(root_jb, jb);
1031  jb_free(jb);
1032  }
1033  jb_close(root_jb);
1034  jb_close(root_jb);
1035 
1036  const char *filename = "patterns.json";
1037  const char *log_dir = ConfigGetLogDirectory();
1038  char json_path[PATH_MAX] = "";
1039  snprintf(json_path, sizeof(json_path), "%s/%s", log_dir, filename);
1040 
1042  FILE *fp = fopen(json_path, "a");
1043  if (fp != NULL) {
1044  fwrite(jb_ptr(root_jb), jb_len(root_jb), 1, fp);
1045  fprintf(fp, "\n");
1046  fclose(fp);
1047  }
1049  jb_free(root_jb);
1050 
1052  de_ctx->pattern_hash_table = NULL;
1053 }
1054 
1055 static void EngineAnalysisItemsReset(void)
1056 {
1057  for (size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) {
1058  analyzer_items[i].item_seen = false;
1059  }
1060 }
1061 
1062 static void EngineAnalysisItemsInit(void)
1063 {
1064  static bool analyzer_init = false;
1065 
1066  if (analyzer_init) {
1067  EngineAnalysisItemsReset();
1068  return;
1069  }
1070 
1071  memset(analyzer_item_map, -1, sizeof(analyzer_item_map));
1072 
1073  for (size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) {
1074  DetectEngineAnalyzerItems *analyzer_item = &analyzer_items[i];
1075 
1076  analyzer_item->item_id = DetectBufferTypeGetByName(analyzer_item->item_name);
1077  if (analyzer_item->item_id == -1) {
1078  /* Mismatch between the analyzer_items array and what's supported */
1080  "unable to initialize engine-analysis table: detect buffer \"%s\" not recognized.",
1081  analyzer_item->item_name);
1082  }
1083  analyzer_item->item_seen = false;
1084 
1085  if (analyzer_item->export_item_seen) {
1086  for (size_t k = 0; k < ARRAY_SIZE(exposed_item_seen_list); k++) {
1087  if (0 == strcmp(exposed_item_seen_list[k].bufname, analyzer_item->item_name))
1088  exposed_item_seen_list[k].item_seen_ptr = &analyzer_item->item_seen;
1089  }
1090 
1091  }
1092  analyzer_item_map[analyzer_item->item_id] = (int16_t) i;
1093  }
1094 
1095  analyzer_init = true;
1096 }
1097 
1098 /**
1099  * \brief Prints analysis of loaded rules.
1100  *
1101  * Warns if potential rule issues are detected. For example,
1102  * warns if a rule uses a construct that may perform poorly,
1103  * e.g. pcre without content or with http_method content only;
1104  * warns if a rule uses a construct that may not be consistent with intent,
1105  * e.g. client side ports only, http and content without any http_* modifiers, etc.
1106  *
1107  * \param s Pointer to the signature.
1108  */
1110  const Signature *s, const char *line)
1111 {
1112  uint32_t rule_bidirectional = 0;
1113  uint32_t rule_pcre = 0;
1114  uint32_t rule_pcre_http = 0;
1115  uint32_t rule_content = 0;
1116  uint32_t rule_flow = 0;
1117  uint32_t rule_flags = 0;
1118  uint32_t rule_flow_toserver = 0;
1119  uint32_t rule_flow_toclient = 0;
1120  uint32_t rule_flow_nostream = 0;
1121  uint32_t rule_ipv4_only = 0;
1122  uint32_t rule_ipv6_only = 0;
1123  uint32_t rule_flowbits = 0;
1124  uint32_t rule_flowint = 0;
1125  uint32_t rule_content_http = 0;
1126  uint32_t rule_content_offset_depth = 0;
1127  int32_t list_id = 0;
1128  uint32_t rule_warning = 0;
1129  uint32_t stream_buf = 0;
1130  uint32_t packet_buf = 0;
1131  uint32_t file_store = 0;
1132  uint32_t warn_pcre_no_content = 0;
1133  uint32_t warn_pcre_http_content = 0;
1134  uint32_t warn_pcre_http = 0;
1135  uint32_t warn_content_http_content = 0;
1136  uint32_t warn_content_http = 0;
1137  uint32_t warn_tcp_no_flow = 0;
1138  uint32_t warn_client_ports = 0;
1139  uint32_t warn_direction = 0;
1140  uint32_t warn_method_toclient = 0;
1141  uint32_t warn_method_serverbody = 0;
1142  uint32_t warn_pcre_method = 0;
1143  uint32_t warn_encoding_norm_http_buf = 0;
1144  uint32_t warn_file_store_not_present = 0;
1145  uint32_t warn_offset_depth_pkt_stream = 0;
1146  uint32_t warn_offset_depth_alproto = 0;
1147  uint32_t warn_non_alproto_fp_for_alproto_sig = 0;
1148  uint32_t warn_no_direction = 0;
1149  uint32_t warn_both_direction = 0;
1150 
1151  EngineAnalysisItemsInit();
1152 
1153  bool *http_method_item_seen_ptr = exposed_item_seen_list[0].item_seen_ptr;
1154  bool *http_server_body_item_seen_ptr = exposed_item_seen_list[1].item_seen_ptr;
1155 
1157  rule_bidirectional = 1;
1158  }
1159 
1160  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
1161  packet_buf += 1;
1162  }
1163  if (s->flags & SIG_FLAG_FILESTORE) {
1164  file_store += 1;
1165  }
1166  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
1167  stream_buf += 1;
1168  }
1169 
1170  if (s->proto.flags & DETECT_PROTO_IPV4) {
1171  rule_ipv4_only += 1;
1172  }
1173  if (s->proto.flags & DETECT_PROTO_IPV6) {
1174  rule_ipv6_only += 1;
1175  }
1176 
1177  for (list_id = 0; list_id < (int)s->init_data->smlists_array_size; list_id++) {
1178  SigMatch *sm = NULL;
1179  for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) {
1180  int16_t item_slot = analyzer_item_map[list_id];
1181  if (sm->type == DETECT_PCRE) {
1182  if (item_slot == -1) {
1183  rule_pcre++;
1184  continue;
1185  }
1186 
1187  rule_pcre_http++;
1188  analyzer_items[item_slot].item_seen = true;
1189  } else if (sm->type == DETECT_CONTENT) {
1190  if (item_slot == -1) {
1191  rule_content++;
1192  if (list_id == DETECT_SM_LIST_PMATCH) {
1195  rule_content_offset_depth++;
1196  }
1197  }
1198  continue;
1199  }
1200 
1201  rule_content_http++;
1202  analyzer_items[item_slot].item_seen = true;
1203 
1204  if (analyzer_items[item_slot].check_encoding_match) {
1206  if (cd != NULL && PerCentEncodingMatch(cd->content, cd->content_len) > 0) {
1207  warn_encoding_norm_http_buf += 1;
1208  }
1209  }
1210  }
1211  else if (sm->type == DETECT_FLOW) {
1212  rule_flow += 1;
1213  if ((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) {
1214  rule_flow_toserver = 1;
1215  }
1216  else if ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_TOSERVER)) {
1217  rule_flow_toclient = 1;
1218  }
1219  DetectFlowData *fd = (DetectFlowData *)sm->ctx;
1220  if (fd != NULL) {
1221  if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM)
1222  rule_flow_nostream = 1;
1223  }
1224  }
1225  else if (sm->type == DETECT_FLOWBITS) {
1226  if (list_id == DETECT_SM_LIST_MATCH) {
1227  rule_flowbits += 1;
1228  }
1229  }
1230  else if (sm->type == DETECT_FLOWINT) {
1231  if (list_id == DETECT_SM_LIST_MATCH) {
1232  rule_flowint += 1;
1233  }
1234  }
1235  else if (sm->type == DETECT_FLAGS) {
1236  DetectFlagsData *fd = (DetectFlagsData *)sm->ctx;
1237  if (fd != NULL) {
1238  rule_flags = 1;
1239  }
1240  }
1241  } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */
1242 
1243  } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */
1244 
1245 
1246  if (file_store && !RequiresFeature("output::file-store")) {
1247  rule_warning += 1;
1248  warn_file_store_not_present = 1;
1249  }
1250 
1251  if (rule_pcre > 0 && rule_content == 0 && rule_content_http == 0) {
1252  rule_warning += 1;
1253  warn_pcre_no_content = 1;
1254  }
1255 
1256  if (rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0) {
1257  rule_warning += 1;
1258  warn_pcre_http_content = 1;
1259  } else if (s->alproto == ALPROTO_HTTP1 && rule_pcre > 0 && rule_pcre_http == 0) {
1260  rule_warning += 1;
1261  warn_pcre_http = 1;
1262  }
1263 
1264  if (rule_content > 0 && rule_content_http > 0) {
1265  rule_warning += 1;
1266  warn_content_http_content = 1;
1267  }
1268  if (s->alproto == ALPROTO_HTTP1 && rule_content > 0 && rule_content_http == 0) {
1269  rule_warning += 1;
1270  warn_content_http = 1;
1271  }
1272  if (rule_content == 1) {
1273  //todo: warning if content is weak, separate warning for pcre + weak content
1274  }
1275  if (rule_flow == 0 && rule_flags == 0 && !(s->proto.flags & DETECT_PROTO_ANY) &&
1276  DetectProtoContainsProto(&s->proto, IPPROTO_TCP) &&
1277  (rule_content || rule_content_http || rule_pcre || rule_pcre_http || rule_flowbits ||
1278  rule_flowint)) {
1279  rule_warning += 1;
1280  warn_tcp_no_flow = 1;
1281  }
1282  if (rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)
1283  && !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))) {
1284  if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))
1285  || ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && (s->flags & SIG_FLAG_SP_ANY))) {
1286  rule_warning += 1;
1287  warn_client_ports = 1;
1288  }
1289  }
1290  if (rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)) {
1291  rule_warning += 1;
1292  warn_direction = 1;
1293  }
1294 
1295  if (*http_method_item_seen_ptr) {
1296  if (rule_flow && rule_flow_toclient) {
1297  rule_warning += 1;
1298  warn_method_toclient = 1;
1299  }
1300  if (*http_server_body_item_seen_ptr) {
1301  rule_warning += 1;
1302  warn_method_serverbody = 1;
1303  }
1304  if (rule_content == 0 && rule_content_http == 0 && (rule_pcre > 0 || rule_pcre_http > 0)) {
1305  rule_warning += 1;
1306  warn_pcre_method = 1;
1307  }
1308  }
1309  if (rule_content_offset_depth > 0 && stream_buf && packet_buf) {
1310  rule_warning += 1;
1311  warn_offset_depth_pkt_stream = 1;
1312  }
1313  if (rule_content_offset_depth > 0 && !stream_buf && packet_buf && s->alproto != ALPROTO_UNKNOWN) {
1314  rule_warning += 1;
1315  warn_offset_depth_alproto = 1;
1316  }
1317  if (s->init_data->mpm_sm != NULL && s->alproto == ALPROTO_HTTP1 &&
1319  rule_warning += 1;
1320  warn_non_alproto_fp_for_alproto_sig = 1;
1321  }
1322 
1323  if ((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
1324  warn_no_direction += 1;
1325  rule_warning += 1;
1326  }
1327 
1328  /* No warning about direction for ICMP protos */
1329  if (!(DetectProtoContainsProto(&s->proto, IPPROTO_ICMPV6) && DetectProtoContainsProto(&s->proto, IPPROTO_ICMP))) {
1331  warn_both_direction += 1;
1332  rule_warning += 1;
1333  }
1334  }
1335 
1336  if (!rule_warnings_only || (rule_warnings_only && rule_warning > 0)) {
1337  fprintf(rule_engine_analysis_FD, "== Sid: %u ==\n", s->id);
1338  fprintf(rule_engine_analysis_FD, "%s\n", line);
1339 
1340  if (s->flags & SIG_FLAG_IPONLY) fprintf(rule_engine_analysis_FD, " Rule is ip only.\n");
1341  if (s->flags & SIG_FLAG_PDONLY) fprintf(rule_engine_analysis_FD, " Rule is PD only.\n");
1342  if (rule_ipv6_only) fprintf(rule_engine_analysis_FD, " Rule is IPv6 only.\n");
1343  if (rule_ipv4_only) fprintf(rule_engine_analysis_FD, " Rule is IPv4 only.\n");
1344  if (packet_buf) fprintf(rule_engine_analysis_FD, " Rule matches on packets.\n");
1345  if (!rule_flow_nostream && stream_buf &&
1346  (rule_flow || rule_flowbits || rule_flowint || rule_content || rule_pcre)) {
1347  fprintf(rule_engine_analysis_FD, " Rule matches on reassembled stream.\n");
1348  }
1349  for(size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) {
1351  if (ai->item_seen) {
1352  fprintf(rule_engine_analysis_FD, " Rule matches on %s buffer.\n", ai->display_name);
1353  }
1354  }
1355  if (s->alproto != ALPROTO_UNKNOWN) {
1356  fprintf(rule_engine_analysis_FD, " App layer protocol is %s.\n", AppProtoToString(s->alproto));
1357  }
1358  if (rule_content || rule_content_http || rule_pcre || rule_pcre_http) {
1359  fprintf(rule_engine_analysis_FD,
1360  " Rule contains %u content options, %u http content options, %u pcre "
1361  "options, and %u pcre options with http modifiers.\n",
1362  rule_content, rule_content_http, rule_pcre, rule_pcre_http);
1363  }
1364 
1365  /* print fast pattern info */
1366  if (s->init_data->prefilter_sm) {
1367  fprintf(rule_engine_analysis_FD, " Prefilter on: %s.\n",
1369  } else {
1370  EngineAnalysisRulesPrintFP(de_ctx, s);
1371  }
1372 
1373  /* this is where the warnings start */
1374  if (warn_pcre_no_content /*rule_pcre > 0 && rule_content == 0 && rule_content_http == 0*/) {
1375  fprintf(rule_engine_analysis_FD, " Warning: Rule uses pcre without a content option present.\n"
1376  " -Consider adding a content to improve performance of this rule.\n");
1377  }
1378  if (warn_pcre_http_content /*rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0*/) {
1379  fprintf(rule_engine_analysis_FD, " Warning: Rule uses content options with http_* and pcre options without http modifiers.\n"
1380  " -Consider adding http pcre modifier.\n");
1381  }
1382  else if (warn_pcre_http /*s->alproto == ALPROTO_HTTP1 && rule_pcre > 0 && rule_pcre_http == 0*/) {
1383  fprintf(rule_engine_analysis_FD, " Warning: Rule app layer protocol is http, but pcre options do not have http modifiers.\n"
1384  " -Consider adding http pcre modifiers.\n");
1385  }
1386  if (warn_content_http_content /*rule_content > 0 && rule_content_http > 0*/) {
1387  fprintf(rule_engine_analysis_FD, " Warning: Rule contains content with http_* and content without http_*.\n"
1388  " -Consider adding http content modifiers.\n");
1389  }
1390  if (warn_content_http /*s->alproto == ALPROTO_HTTP1 && rule_content > 0 && rule_content_http == 0*/) {
1391  fprintf(rule_engine_analysis_FD, " Warning: Rule app layer protocol is http, but content options do not have http_* modifiers.\n"
1392  " -Consider adding http content modifiers.\n");
1393  }
1394  if (rule_content == 1) {
1395  //todo: warning if content is weak, separate warning for pcre + weak content
1396  }
1397  if (warn_encoding_norm_http_buf) {
1398  fprintf(rule_engine_analysis_FD, " Warning: Rule may contain percent encoded content for a normalized http buffer match.\n");
1399  }
1400  if (warn_tcp_no_flow /*rule_flow == 0 && rule_flags == 0
1401  && !(s->proto.flags & DETECT_PROTO_ANY) && DetectProtoContainsProto(&s->proto, IPPROTO_TCP)*/) {
1402  fprintf(rule_engine_analysis_FD, " Warning: TCP rule without a flow or flags option.\n"
1403  " -Consider adding flow or flags to improve performance of this rule.\n");
1404  }
1405  if (warn_client_ports /*rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)
1406  && !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY)))
1407  if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))
1408  || ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && (s->flags & SIG_FLAG_SP_ANY))*/) {
1409  fprintf(rule_engine_analysis_FD, " Warning: Rule contains ports or port variables only on the client side.\n"
1410  " -Flow direction possibly inconsistent with rule.\n");
1411  }
1412  if (warn_direction /*rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)*/) {
1413  fprintf(rule_engine_analysis_FD, " Warning: Rule is bidirectional and has a flow option with a specific direction.\n");
1414  }
1415  if (warn_method_toclient /*http_method_buf && rule_flow && rule_flow_toclient*/) {
1416  fprintf(rule_engine_analysis_FD, " Warning: Rule uses content or pcre for http_method with flow:to_client or from_server\n");
1417  }
1418  if (warn_method_serverbody /*http_method_buf && http_server_body_buf*/) {
1419  fprintf(rule_engine_analysis_FD, " Warning: Rule uses content or pcre for http_method with content or pcre for http_server_body.\n");
1420  }
1421  if (warn_pcre_method /*http_method_buf && rule_content == 0 && rule_content_http == 0
1422  && (rule_pcre > 0 || rule_pcre_http > 0)*/) {
1423  fprintf(rule_engine_analysis_FD, " Warning: Rule uses pcre with only a http_method content; possible performance issue.\n");
1424  }
1425  if (warn_offset_depth_pkt_stream) {
1426  fprintf(rule_engine_analysis_FD, " Warning: Rule has depth"
1427  "/offset with raw content keywords. Please note the "
1428  "offset/depth will be checked against both packet "
1429  "payloads and stream. If you meant to have the offset/"
1430  "depth checked against just the payload, you can update "
1431  "the signature as \"alert tcp-pkt...\"\n");
1432  }
1433  if (warn_offset_depth_alproto) {
1434  fprintf(rule_engine_analysis_FD, " Warning: Rule has "
1435  "offset/depth set along with a match on a specific "
1436  "app layer protocol - %d. This can lead to FNs if we "
1437  "have a offset/depth content match on a packet payload "
1438  "before we can detect the app layer protocol for the "
1439  "flow.\n", s->alproto);
1440  }
1441  if (warn_non_alproto_fp_for_alproto_sig) {
1442  fprintf(rule_engine_analysis_FD, " Warning: Rule app layer "
1443  "protocol is http, but the fast_pattern is set on the raw "
1444  "stream. Consider adding fast_pattern over a http "
1445  "buffer for increased performance.");
1446  }
1447  if (warn_no_direction) {
1448  fprintf(rule_engine_analysis_FD, " Warning: Rule has no direction indicator.\n");
1449  }
1450  if (warn_both_direction) {
1451  fprintf(rule_engine_analysis_FD, " Warning: Rule is inspecting both the request and the response.\n");
1452  }
1453  if (warn_file_store_not_present) {
1454  fprintf(rule_engine_analysis_FD, " Warning: Rule requires file-store but the output file-store is not enabled.\n");
1455  }
1456  if (rule_warning == 0) {
1457  fprintf(rule_engine_analysis_FD, " No warnings for this rule.\n");
1458  }
1459  fprintf(rule_engine_analysis_FD, "\n");
1460  }
1461  return;
1462 }
detect-tcp-flags.h
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:785
RuleAnalyzer::js
JsonBuilder * js
Definition: detect-engine-analyzer.c:560
HashListTableGetListData
#define HashListTableGetListData(hb)
Definition: util-hashlist.h:59
DetectContentData_::offset
uint16_t offset
Definition: detect-content.h:100
DetectPatternTracker
Definition: detect.h:677
DetectEngineAppInspectionEngine_
Definition: detect.h:398
DetectEngineAppInspectionEngine_::mpm
bool mpm
Definition: detect.h:402
detect-content.h
len
uint8_t len
Definition: app-layer-dnp3.h:2
SC_ERR_PCRE_COMPILE
@ SC_ERR_PCRE_COMPILE
Definition: util-error.h:35
detect-engine.h
DETECT_SM_LIST_PMATCH
@ DETECT_SM_LIST_PMATCH
Definition: detect.h:90
DETECT_CONTENT_FAST_PATTERN_CHOP
#define DETECT_CONTENT_FAST_PATTERN_CHOP
Definition: detect-content.h:36
DetectContentData_::fp_chop_len
uint16_t fp_chop_len
Definition: detect-content.h:91
Signature_::sig_str
char * sig_str
Definition: detect.h:617
DetectEnginePktInspectionEngine
Definition: detect.h:451
DetectEngineAppInspectionEngine_::next
struct DetectEngineAppInspectionEngine_ * next
Definition: detect.h:417
PerCentEncodingMatch
int PerCentEncodingMatch(uint8_t *content, uint8_t content_len)
Checks for % encoding in content.
Definition: detect-engine-analyzer.c:460
DETECT_PROTO_IPV6
#define DETECT_PROTO_IPV6
Definition: detect-engine-proto.h:34
SIG_FLAG_PDONLY
#define SIG_FLAG_PDONLY
Definition: detect.h:247
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:1267
DetectPatternTracker::mpm
uint32_t mpm
Definition: detect.h:681
ConfGetBool
int ConfGetBool(const char *name, int *val)
Retrieve a configuration value as an boolen.
Definition: conf.c:516
DetectListToHumanString
const char * DetectListToHumanString(int list)
Definition: detect-parse.c:114
DetectEngineCtx_::pattern_hash_table
HashListTable * pattern_hash_table
Definition: detect.h:853
DumpPatterns
void DumpPatterns(DetectEngineCtx *de_ctx)
Definition: detect-engine-analyzer.c:976
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
DetectContentData_::within
int32_t within
Definition: detect-content.h:102
DETECT_CONTENT
@ DETECT_CONTENT
Definition: detect-engine-register.h:60
SignatureInitData_::prefilter_sm
SigMatch * prefilter_sm
Definition: detect.h:522
DETECT_FLOW
@ DETECT_FLOW
Definition: detect-engine-register.h:52
Signature_::alproto
AppProto alproto
Definition: detect.h:552
CleanupFPAnalyzer
void CleanupFPAnalyzer(void)
Definition: detect-engine-analyzer.c:390
RuleAnalyzer::js_warnings
JsonBuilder * js_warnings
Definition: detect-engine-analyzer.c:562
g_rules_analyzer_write_m
SCMutex g_rules_analyzer_write_m
Definition: detect-engine-analyzer.c:686
DetectEngineAnalyzerItems::display_name
const char * display_name
Definition: detect-engine-analyzer.c:63
DETECT_SM_LIST_DYNAMIC_START
@ DETECT_SM_LIST_DYNAMIC_START
Definition: detect.h:109
SIG_FLAG_DEST_IS_TARGET
#define SIG_FLAG_DEST_IS_TARGET
Definition: detect.h:251
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:333
DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED
#define DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED
Definition: detect-content.h:55
ConfGetNode
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:175
AppProtoToString
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
Definition: app-layer-protos.c:30
DetectFlowData_::flags
uint16_t flags
Definition: detect-flow.h:38
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:811
DETECT_PROTO_ANY
#define DETECT_PROTO_ANY
Definition: detect-engine-proto.h:27
DetectEnginePktInspectionEngine::smd
SigMatchData * smd
Definition: detect.h:452
DetectEngineFrameInspectionEngine::mpm
bool mpm
Definition: detect.h:480
HashListTableGetListHead
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
Definition: util-hashlist.c:290
DetectEngineBufferTypeGetNameById
const char * DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1107
SIG_FLAG_DST_ANY
#define SIG_FLAG_DST_ANY
Definition: detect.h:212
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
SIG_FLAG_REQUIRE_STREAM
#define SIG_FLAG_REQUIRE_STREAM
Definition: detect.h:224
DetectPatternTracker::cnt
uint32_t cnt
Definition: detect.h:680
rust.h
DetectEngineAnalyzerItems
Definition: detect-engine-analyzer.c:57
DetectPatternTracker::cd
const struct DetectContentData_ * cd
Definition: detect.h:678
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:603
FpPatternStats_::max
uint16_t max
Definition: detect-engine-analyzer.c:51
SignatureInitData_::init_flags
uint32_t init_flags
Definition: detect.h:511
DetectBufferType_
Definition: detect.h:420
DetectContentData_
Definition: detect-content.h:86
DetectContentData_::fp_chop_offset
uint16_t fp_chop_offset
Definition: detect-content.h:93
SIG_FLAG_TOCLIENT
#define SIG_FLAG_TOCLIENT
Definition: detect.h:237
SIG_FLAG_SRC_ANY
#define SIG_FLAG_SRC_ANY
Definition: detect.h:211
SigMatchData_
Data needed for Match()
Definition: detect.h:330
SigMatchData_::type
uint16_t type
Definition: detect.h:331
Signature_::frame_inspect
DetectEngineFrameInspectionEngine * frame_inspect
Definition: detect.h:599
CleanupRuleAnalyzer
void CleanupRuleAnalyzer(void)
Definition: detect-engine-analyzer.c:414
ConfValIsTrue
int ConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:565
DETECT_PERCENT_ENCODING_REGEX
#define DETECT_PERCENT_ENCODING_REGEX
DetectEngineBufferTypeGetById
const DetectBufferType * DetectEngineBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1097
SIG_FLAG_APPLAYER
#define SIG_FLAG_APPLAYER
Definition: detect.h:218
DetectBufferTypeGetByName
int DetectBufferTypeGetByName(const char *name)
Definition: detect-engine.c:1077
analyzer_item_map
int16_t analyzer_item_map[256]
Definition: detect-engine-analyzer.c:119
Signature_::gid
uint32_t gid
Definition: detect.h:583
DetectEngineAppInspectionEngine_::sm_list
uint16_t sm_list
Definition: detect.h:404
ATTR_FMT_PRINTF
#define ATTR_FMT_PRINTF(x, y)
Definition: suricata-common.h:391
HashListTableGetListNext
#define HashListTableGetListNext(hb)
Definition: util-hashlist.h:58
DetectEngineAnalyzerItems::export_item_seen
bool export_item_seen
Definition: detect-engine-analyzer.c:60
SIG_FLAG_TOSERVER
#define SIG_FLAG_TOSERVER
Definition: detect.h:236
RequiresFeature
bool RequiresFeature(const char *feature_name)
Definition: feature.c:124
feature.h
SC_ERR_PCRE_MATCH
@ SC_ERR_PCRE_MATCH
Definition: util-error.h:32
DETECT_CONTENT_ENDS_WITH
#define DETECT_CONTENT_ENDS_WITH
Definition: detect-content.h:42
DETECT_CONTENT_DISTANCE
#define DETECT_CONTENT_DISTANCE
Definition: detect-content.h:30
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
DetectEnginePktInspectionEngine::sm_list
uint16_t sm_list
Definition: detect.h:454
SIG_FLAG_INIT_BIDIREC
#define SIG_FLAG_INIT_BIDIREC
Definition: detect.h:259
DETECT_FLOWINT
@ DETECT_FLOWINT
Definition: detect-engine-register.h:85
SIG_MASK_REQUIRE_ENGINE_EVENT
#define SIG_MASK_REQUIRE_ENGINE_EVENT
Definition: detect.h:277
SignatureInitData_::mpm_sm
SigMatch * mpm_sm
Definition: detect.h:520
DetectEngineBufferTypeGetDescriptionById
const char * DetectEngineBufferTypeGetDescriptionById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1185
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
SIG_FLAG_FLUSH
#define SIG_FLAG_FLUSH
Definition: detect.h:228
SignatureInitData_::mpm_sm_list
int mpm_sm_list
Definition: detect.h:518
SIG_MASK_REQUIRE_FLOW
#define SIG_MASK_REQUIRE_FLOW
Definition: detect.h:271
SIG_FLAG_BYPASS
#define SIG_FLAG_BYPASS
Definition: detect.h:241
DETECT_CONTENT_DEPTH
#define DETECT_CONTENT_DEPTH
Definition: detect-content.h:33
RuleAnalyzer
Definition: detect-engine-analyzer.c:559
Signature_::pkt_inspect
DetectEnginePktInspectionEngine * pkt_inspect
Definition: detect.h:598
DetectEngineAnalyzerItems
struct DetectEngineAnalyzerItems DetectEngineAnalyzerItems
util-print.h
SCEnter
#define SCEnter(...)
Definition: util-debug.h:300
detect-engine-mpm.h
detect.h
SIG_MASK_REQUIRE_FLAGS_INITDEINIT
#define SIG_MASK_REQUIRE_FLAGS_INITDEINIT
Definition: detect.h:272
DetectEngineFrameInspectionEngine::sm_list
uint16_t sm_list
Definition: detect.h:481
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:325
DetectEngineAnalyzerItems::item_seen
bool item_seen
Definition: detect-engine-analyzer.c:59
DETECT_CONTENT_NEGATED
#define DETECT_CONTENT_NEGATED
Definition: detect-content.h:40
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:89
EngineAnalysisRules
void EngineAnalysisRules(const DetectEngineCtx *de_ctx, const Signature *s, const char *line)
Prints analysis of loaded rules.
Definition: detect-engine-analyzer.c:1109
Signature_::app_inspect
DetectEngineAppInspectionEngine * app_inspect
Definition: detect.h:597
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:324
SIG_FLAG_REQUIRE_FLOWVAR
#define SIG_FLAG_REQUIRE_FLOWVAR
Definition: detect.h:232
FpPatternStats_::cnt
uint32_t cnt
Definition: detect-engine-analyzer.c:52
SCReturn
#define SCReturn
Definition: util-debug.h:302
Signature_::flags
uint32_t flags
Definition: detect.h:549
DetectContentData_::depth
uint16_t depth
Definition: detect-content.h:99
SC_ERR_FOPEN
@ SC_ERR_FOPEN
Definition: util-error.h:74
SIG_FLAG_IPONLY
#define SIG_FLAG_IPONLY
Definition: detect.h:219
SCLocalTime
struct tm * SCLocalTime(time_t timep, struct tm *result)
Definition: util-time.c:271
PerCentEncodingSetup
int PerCentEncodingSetup()
Compiles regex for rule analysis.
Definition: detect-engine-analyzer.c:432
conf.h
DetectContentData_::flags
uint32_t flags
Definition: detect-content.h:97
CHECK
#define CHECK(pat)
Definition: detect-engine-analyzer.c:596
DetectEngineFrameInspectionEngine
Definition: detect.h:476
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:619
SIG_FLAG_SRC_IS_TARGET
#define SIG_FLAG_SRC_IS_TARGET
Definition: detect.h:249
SignatureInitData_::smlists
struct SigMatch_ ** smlists
Definition: detect.h:542
DetectContentPatternPrettyPrint
void DetectContentPatternPrettyPrint(const DetectContentData *cd, char *str, size_t str_len)
Definition: detect-content.c:656
SIG_MASK_REQUIRE_PAYLOAD
#define SIG_MASK_REQUIRE_PAYLOAD
Definition: detect.h:270
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:217
DETECT_PCRE
@ DETECT_PCRE
Definition: detect-engine-register.h:62
ExposedItemSeen::bufname
const char * bufname
Definition: detect-engine-analyzer.c:68
DetectSigmatchListEnumToString
const char * DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type)
Definition: detect-engine.c:4602
DetectEngineAppInspectionEngine_::alproto
AppProto alproto
Definition: detect.h:399
SIG_FLAG_MPM_NEG
#define SIG_FLAG_MPM_NEG
Definition: detect.h:226
detect-engine-analyzer.h
SIG_FLAG_INIT_STATE_MATCH
#define SIG_FLAG_INIT_STATE_MATCH
Definition: detect.h:262
DetectEngineAnalyzerItems::item_id
int16_t item_id
Definition: detect-engine-analyzer.c:58
DetectPatternTracker::sm_list
int sm_list
Definition: detect.h:679
DetectEngineAppInspectionEngine_::smd
SigMatchData * smd
Definition: detect.h:415
EngineAnalysisRules2
void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s)
Definition: detect-engine-analyzer.c:687
ARRAY_SIZE
#define ARRAY_SIZE(arr)
Definition: suricata-common.h:535
DETECT_CONTENT_STARTS_WITH
#define DETECT_CONTENT_STARTS_WITH
Definition: detect-content.h:59
DetectProto_::flags
uint8_t flags
Definition: detect-engine-proto.h:38
DETECT_PROTO_IPV4
#define DETECT_PROTO_IPV4
Definition: detect-engine-proto.h:33
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:821
RuleAnalyzer::js_notes
JsonBuilder * js_notes
Definition: detect-engine-analyzer.c:563
EngineAnalysisFP
void EngineAnalysisFP(const DetectEngineCtx *de_ctx, const Signature *s, char *line)
Definition: detect-engine-analyzer.c:151
FpPatternStats_::min
uint16_t min
Definition: detect-engine-analyzer.c:50
Signature_::proto
DetectProto proto
Definition: detect.h:566
SigMatchData_::is_last
uint8_t is_last
Definition: detect.h:332
suricata-common.h
SIG_MASK_REQUIRE_NO_PAYLOAD
#define SIG_MASK_REQUIRE_NO_PAYLOAD
Definition: detect.h:274
SIG_FLAG_SP_ANY
#define SIG_FLAG_SP_ANY
Definition: detect.h:213
ExposedItemSeen
Definition: detect-engine-analyzer.c:67
SigMatch_::type
uint16_t type
Definition: detect.h:322
HashListTableFree
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:82
DetectEngineAnalyzerItems::check_encoding_match
bool check_encoding_match
Definition: detect-engine-analyzer.c:61
DetectContentData_::distance
int32_t distance
Definition: detect-content.h:101
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:30
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:73
DetectEngineFrameInspectionEngine::next
struct DetectEngineFrameInspectionEngine * next
Definition: detect.h:489
DetectEnginePktInspectionEngine::next
struct DetectEnginePktInspectionEngine * next
Definition: detect.h:462
DetectContentData_::content
uint8_t * content
Definition: detect-content.h:87
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
Signature_::rev
uint32_t rev
Definition: detect.h:584
SetupFPAnalyzer
int SetupFPAnalyzer(void)
Sets up the fast pattern analyzer according to the config.
Definition: detect-engine-analyzer.c:284
FatalError
#define FatalError(x,...)
Definition: util-debug.h:532
SIG_FLAG_NOALERT
#define SIG_FLAG_NOALERT
Definition: detect.h:216
SIG_MASK_REQUIRE_FLAGS_UNUSUAL
#define SIG_MASK_REQUIRE_FLAGS_UNUSUAL
Definition: detect.h:273
EngineAnalysisRulesFailure
void EngineAnalysisRulesFailure(char *line, char *file, int lineno)
Definition: detect-engine-analyzer.c:549
DETECT_FLOWBITS
@ DETECT_FLOWBITS
Definition: detect-engine-register.h:88
DetectEngineAppInspectionEngine_::progress
int16_t progress
Definition: detect.h:406
detect-flow.h
PrintRawUriFp
void PrintRawUriFp(FILE *fp, uint8_t *buf, uint32_t buflen)
Definition: util-print.c:93
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
FpPatternStats
struct FpPatternStats_ FpPatternStats
str
#define str(s)
Definition: suricata-common.h:272
ConfigGetLogDirectory
const char * ConfigGetLogDirectory()
Definition: util-conf.c:35
SigMatchListSMBelongsTo
int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
Definition: detect-parse.c:625
SCFree
#define SCFree(p)
Definition: util-mem.h:61
ConfNode_
Definition: conf.h:32
SC_ERR_FATAL
@ SC_ERR_FATAL
Definition: util-error.h:203
Signature_::id
uint32_t id
Definition: detect.h:582
DETECT_CONTENT_OFFSET
#define DETECT_CONTENT_OFFSET
Definition: detect-content.h:32
HashListTableBucket_
Definition: util-hashlist.h:28
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:431
detect-parse.h
Signature_
Signature container.
Definition: detect.h:548
SigMatch_
a single match condition for a signature
Definition: detect.h:321
DETECT_SM_LIST_MAX
@ DETECT_SM_LIST_MAX
Definition: detect.h:106
FpPatternStats_::tot
uint64_t tot
Definition: detect-engine-analyzer.c:53
DetectFlagsData_
Definition: detect-tcp-flags.h:41
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
exposed_item_seen_list
struct ExposedItemSeen exposed_item_seen_list[]
Definition: detect-engine-analyzer.c:125
DetectEngineTransforms::cnt
int cnt
Definition: detect.h:381
suricata.h
SetupRuleAnalyzer
int SetupRuleAnalyzer(void)
Sets up the rule analyzer according to the config.
Definition: detect-engine-analyzer.c:334
DetectEngineAppInspectionEngine_::dir
uint8_t dir
Definition: detect.h:400
DetectEngineAnalyzerItems::item_name
const char * item_name
Definition: detect-engine-analyzer.c:62
DetectContentData_::content_len
uint16_t content_len
Definition: detect-content.h:88
ExposedItemSeen::item_seen_ptr
bool * item_seen_ptr
Definition: detect-engine-analyzer.c:69
DetectEngineCtx_::buffer_type_id
uint32_t buffer_type_id
Definition: detect.h:973
DetectEnginePktInspectionEngine::mpm
bool mpm
Definition: detect.h:453
SC_ERR_INITIALIZATION
@ SC_ERR_INITIALIZATION
Definition: util-error.h:75
RuleAnalyzer
struct RuleAnalyzer RuleAnalyzer
SIG_FLAG_TLSSTORE
#define SIG_FLAG_TLSSTORE
Definition: detect.h:239
Signature_::msg
char * msg
Definition: detect.h:608
DETECT_CONTENT_FAST_PATTERN
#define DETECT_CONTENT_FAST_PATTERN
Definition: detect-content.h:34
DETECT_FLAGS
@ DETECT_FLAGS
Definition: detect-engine-register.h:40
FpPatternStats_
Definition: detect-engine-analyzer.c:49
analyzer_items
DetectEngineAnalyzerItems analyzer_items[]
Definition: detect-engine-analyzer.c:72
SCMutex
#define SCMutex
Definition: threads-debug.h:114
SIG_FLAG_PREFILTER
#define SIG_FLAG_PREFILTER
Definition: detect.h:243
SIG_MASK_REQUIRE_DCERPC
#define SIG_MASK_REQUIRE_DCERPC
Definition: detect.h:275
SIG_FLAG_FILESTORE
#define SIG_FLAG_FILESTORE
Definition: detect.h:234
DETECT_CONTENT_WITHIN
#define DETECT_CONTENT_WITHIN
Definition: detect-content.h:31
SIG_FLAG_DP_ANY
#define SIG_FLAG_DP_ANY
Definition: detect.h:214
SIG_FLAG_DSIZE
#define SIG_FLAG_DSIZE
Definition: detect.h:217
Signature_::mask
SignatureMask mask
Definition: detect.h:558
SignatureInitData_::smlists_array_size
uint32_t smlists_array_size
Definition: detect.h:540
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:223
DetectEngineFrameInspectionEngine::smd
SigMatchData * smd
Definition: detect.h:488
ConfNodeLookupChildValue
const char * ConfNodeLookupChildValue(const ConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:842