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 pcre *percent_re = NULL;
46 static pcre_extra *percent_re_study = 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  DetectContentData *fp_cd = NULL;
157  SigMatch *mpm_sm = s->init_data->mpm_sm;
158 
159  if (mpm_sm != NULL) {
160  fp_cd = (DetectContentData *)mpm_sm->ctx;
161  if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN) {
162  fast_pattern_set = 1;
164  fast_pattern_only_set = 1;
165  } else if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) {
166  fast_pattern_chop_set = 1;
167  }
168  }
169  }
170 
171  fprintf(fp_engine_analysis_FD, "== Sid: %u ==\n", s->id);
172  fprintf(fp_engine_analysis_FD, "%s\n", line);
173 
174  fprintf(fp_engine_analysis_FD, " Fast Pattern analysis:\n");
175  if (s->init_data->prefilter_sm != NULL) {
176  fprintf(fp_engine_analysis_FD, " Prefilter on: %s\n",
178  fprintf(fp_engine_analysis_FD, "\n");
179  return;
180  }
181 
182  if (fp_cd == NULL) {
183  fprintf(fp_engine_analysis_FD, " No content present\n");
184  fprintf(fp_engine_analysis_FD, "\n");
185  return;
186  }
187 
188  fprintf(fp_engine_analysis_FD, " Fast pattern matcher: ");
189  int list_type = SigMatchListSMBelongsTo(s, mpm_sm);
190  if (list_type == DETECT_SM_LIST_PMATCH)
191  fprintf(fp_engine_analysis_FD, "content\n");
192  else {
193  const char *desc = DetectBufferTypeGetDescriptionById(de_ctx, list_type);
194  const char *name = DetectBufferTypeGetNameById(de_ctx, list_type);
195  if (desc && name) {
196  fprintf(fp_engine_analysis_FD, "%s (%s)\n", desc, name);
197  }
198  }
199 
200  int flags_set = 0;
201  fprintf(fp_engine_analysis_FD, " Flags:");
202  if (fp_cd->flags & DETECT_CONTENT_OFFSET) {
203  fprintf(fp_engine_analysis_FD, " Offset");
204  flags_set = 1;
205  } if (fp_cd->flags & DETECT_CONTENT_DEPTH) {
206  fprintf(fp_engine_analysis_FD, " Depth");
207  flags_set = 1;
208  }
209  if (fp_cd->flags & DETECT_CONTENT_WITHIN) {
210  fprintf(fp_engine_analysis_FD, " Within");
211  flags_set = 1;
212  }
213  if (fp_cd->flags & DETECT_CONTENT_DISTANCE) {
214  fprintf(fp_engine_analysis_FD, " Distance");
215  flags_set = 1;
216  }
217  if (fp_cd->flags & DETECT_CONTENT_NOCASE) {
218  fprintf(fp_engine_analysis_FD, " Nocase");
219  flags_set = 1;
220  }
221  if (fp_cd->flags & DETECT_CONTENT_NEGATED) {
222  fprintf(fp_engine_analysis_FD, " Negated");
223  flags_set = 1;
224  }
225  if (flags_set == 0)
226  fprintf(fp_engine_analysis_FD, " None");
227  fprintf(fp_engine_analysis_FD, "\n");
228 
229  fprintf(fp_engine_analysis_FD, " Fast pattern set: %s\n", fast_pattern_set ? "yes" : "no");
230  fprintf(fp_engine_analysis_FD, " Fast pattern only set: %s\n",
231  fast_pattern_only_set ? "yes" : "no");
232  fprintf(fp_engine_analysis_FD, " Fast pattern chop set: %s\n",
233  fast_pattern_chop_set ? "yes" : "no");
234  if (fast_pattern_chop_set) {
235  fprintf(fp_engine_analysis_FD, " Fast pattern offset, length: %u, %u\n",
236  fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
237  }
238 
239  uint16_t patlen = fp_cd->content_len;
240  uint8_t *pat = SCMalloc(fp_cd->content_len + 1);
241  if (unlikely(pat == NULL)) {
242  FatalError(SC_ERR_FATAL, "Error allocating memory");
243  }
244  memcpy(pat, fp_cd->content, fp_cd->content_len);
245  pat[fp_cd->content_len] = '\0';
246  fprintf(fp_engine_analysis_FD, " Original content: ");
247  PrintRawUriFp(fp_engine_analysis_FD, pat, patlen);
248  fprintf(fp_engine_analysis_FD, "\n");
249 
250  if (fast_pattern_chop_set) {
251  SCFree(pat);
252  patlen = fp_cd->fp_chop_len;
253  pat = SCMalloc(fp_cd->fp_chop_len + 1);
254  if (unlikely(pat == NULL)) {
255  exit(EXIT_FAILURE);
256  }
257  memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
258  pat[fp_cd->fp_chop_len] = '\0';
259  fprintf(fp_engine_analysis_FD, " Final content: ");
260  PrintRawUriFp(fp_engine_analysis_FD, pat, patlen);
261  fprintf(fp_engine_analysis_FD, "\n");
262 
263  FpPatternStatsAdd(list_type, patlen);
264  } else {
265  fprintf(fp_engine_analysis_FD, " Final content: ");
266  PrintRawUriFp(fp_engine_analysis_FD, pat, patlen);
267  fprintf(fp_engine_analysis_FD, "\n");
268 
269  FpPatternStatsAdd(list_type, patlen);
270  }
271  SCFree(pat);
272 
273  fprintf(fp_engine_analysis_FD, "\n");
274  return;
275 }
276 
277 /**
278  * \brief Sets up the fast pattern analyzer according to the config.
279  *
280  * \retval 1 If rule analyzer successfully enabled.
281  * \retval 0 If not enabled.
282  */
284 {
285  int fp_engine_analysis_set = 0;
286 
287  if ((ConfGetBool("engine-analysis.rules-fast-pattern",
288  &fp_engine_analysis_set)) == 0) {
289  return 0;
290  }
291 
292  if (fp_engine_analysis_set == 0)
293  return 0;
294 
295  const char *log_dir;
296  log_dir = ConfigGetLogDirectory();
297  snprintf(log_path, sizeof(log_path), "%s/%s", log_dir,
298  "rules_fast_pattern.txt");
299 
300  fp_engine_analysis_FD = fopen(log_path, "w");
301  if (fp_engine_analysis_FD == NULL) {
302  SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", log_path,
303  strerror(errno));
304  return 0;
305  }
306 
307  SCLogInfo("Engine-Analysis for fast_pattern printed to file - %s",
308  log_path);
309 
310  struct timeval tval;
311  struct tm *tms;
312  gettimeofday(&tval, NULL);
313  struct tm local_tm;
314  tms = SCLocalTime(tval.tv_sec, &local_tm);
315  fprintf(fp_engine_analysis_FD, "----------------------------------------------"
316  "---------------------\n");
317  fprintf(fp_engine_analysis_FD, "Date: %" PRId32 "/%" PRId32 "/%04d -- "
318  "%02d:%02d:%02d\n",
319  tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour,
320  tms->tm_min, tms->tm_sec);
321  fprintf(fp_engine_analysis_FD, "----------------------------------------------"
322  "---------------------\n");
323 
324  memset(&fp_pattern_stats, 0, sizeof(fp_pattern_stats));
325  return 1;
326 }
327 
328 /**
329  * \brief Sets up the rule analyzer according to the config
330  * \retval 1 if rule analyzer successfully enabled
331  * \retval 0 if not enabled
332  */
334 {
335  ConfNode *conf = ConfGetNode("engine-analysis");
336  int enabled = 0;
337  if (conf != NULL) {
338  const char *value = ConfNodeLookupChildValue(conf, "rules");
339  if (value && ConfValIsTrue(value)) {
340  enabled = 1;
341  } else if (value && strcasecmp(value, "warnings-only") == 0) {
342  enabled = 1;
343  rule_warnings_only = 1;
344  }
345  if (enabled) {
346  const char *log_dir;
347  log_dir = ConfigGetLogDirectory();
348  snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, "rules_analysis.txt");
349  rule_engine_analysis_FD = fopen(log_path, "w");
350  if (rule_engine_analysis_FD == NULL) {
351  SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", log_path, strerror(errno));
352  return 0;
353  }
354 
355  SCLogInfo("Engine-Analysis for rules printed to file - %s",
356  log_path);
357 
358  struct timeval tval;
359  struct tm *tms;
360  gettimeofday(&tval, NULL);
361  struct tm local_tm;
362  tms = SCLocalTime(tval.tv_sec, &local_tm);
363  fprintf(rule_engine_analysis_FD, "----------------------------------------------"
364  "---------------------\n");
365  fprintf(rule_engine_analysis_FD, "Date: %" PRId32 "/%" PRId32 "/%04d -- "
366  "%02d:%02d:%02d\n",
367  tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour,
368  tms->tm_min, tms->tm_sec);
369  fprintf(rule_engine_analysis_FD, "----------------------------------------------"
370  "---------------------\n");
371 
372  /*compile regex's for rule analysis*/
373  if (PerCentEncodingSetup()== 0) {
374  fprintf(rule_engine_analysis_FD, "Error compiling regex; can't check for percent encoding in normalized http content.\n");
375  }
376  }
377  }
378  else {
379  SCLogInfo("Conf parameter \"engine-analysis.rules\" not found. "
380  "Defaulting to not printing the rules analysis report.");
381  }
382  if (!enabled) {
383  SCLogInfo("Engine-Analysis for rules disabled in conf file.");
384  return 0;
385  }
386  return 1;
387 }
388 
390 {
391  fprintf(fp_engine_analysis_FD, "============\n"
392  "Summary:\n============\n");
393  int i;
394  for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
395  FpPatternStats *f = &fp_pattern_stats[i];
396  if (f->cnt == 0)
397  continue;
398 
399  fprintf(fp_engine_analysis_FD,
400  "%s, smallest pattern %u byte(s), longest pattern %u byte(s), number of patterns %u, avg pattern len %.2f byte(s)\n",
401  DetectSigmatchListEnumToString(i), f->min, f->max, f->cnt, (float)((double)f->tot/(float)f->cnt));
402  }
403 
404  if (fp_engine_analysis_FD != NULL) {
405  fclose(fp_engine_analysis_FD);
406  fp_engine_analysis_FD = NULL;
407  }
408 
409  return;
410 }
411 
412 
414 {
415  if (rule_engine_analysis_FD != NULL) {
416  SCLogInfo("Engine-Analysis for rules printed to file - %s", log_path);
417  fclose(rule_engine_analysis_FD);
418  rule_engine_analysis_FD = NULL;
419  }
420 }
421 
422 /**
423  * \brief Compiles regex for rule analysis
424  * \retval 1 if successful
425  * \retval 0 if on error
426  */
428 {
429 #define DETECT_PERCENT_ENCODING_REGEX "%[0-9|a-f|A-F]{2}"
430  const char *eb = NULL;
431  int eo = 0;
432  int opts = 0; //PCRE_NEWLINE_ANY??
433 
434  percent_re = pcre_compile(DETECT_PERCENT_ENCODING_REGEX, opts, &eb, &eo, NULL);
435  if (percent_re == NULL) {
436  SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s",
438  return 0;
439  }
440 
441  percent_re_study = pcre_study(percent_re, 0, &eb);
442  if (eb != NULL) {
443  SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb);
444  return 0;
445  }
446  return 1;
447 }
448 
449 /**
450  * \brief Checks for % encoding in content.
451  * \param Pointer to content
452  * \retval number of matches if content has % encoding
453  * \retval 0 if it doesn't have % encoding
454  * \retval -1 on error
455  */
456 int PerCentEncodingMatch (uint8_t *content, uint8_t content_len)
457 {
458 #define MAX_ENCODED_CHARS 240
459  int ret = 0;
460  int ov[MAX_ENCODED_CHARS];
461 
462  ret = pcre_exec(percent_re, percent_re_study, (char *)content, content_len, 0, 0, ov, MAX_ENCODED_CHARS);
463  if (ret == -1) {
464  return 0;
465  }
466  else if (ret < -1) {
467  SCLogError(SC_ERR_PCRE_MATCH, "Error parsing content - %s; error code is %d", content, ret);
468  return -1;
469  }
470  return ret;
471 }
472 
473 static void EngineAnalysisRulesPrintFP(const DetectEngineCtx *de_ctx, const Signature *s)
474 {
475  DetectContentData *fp_cd = NULL;
476  SigMatch *mpm_sm = s->init_data->mpm_sm;
477 
478  if (mpm_sm != NULL) {
479  fp_cd = (DetectContentData *)mpm_sm->ctx;
480  }
481 
482  if (fp_cd == NULL) {
483  return;
484  }
485 
486  uint16_t patlen = fp_cd->content_len;
487  uint8_t *pat = SCMalloc(fp_cd->content_len + 1);
488  if (unlikely(pat == NULL)) {
489  FatalError(SC_ERR_FATAL, "Error allocating memory");
490  }
491  memcpy(pat, fp_cd->content, fp_cd->content_len);
492  pat[fp_cd->content_len] = '\0';
493 
495  SCFree(pat);
496  patlen = fp_cd->fp_chop_len;
497  pat = SCMalloc(fp_cd->fp_chop_len + 1);
498  if (unlikely(pat == NULL)) {
499  exit(EXIT_FAILURE);
500  }
501  memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
502  pat[fp_cd->fp_chop_len] = '\0';
503  fprintf(rule_engine_analysis_FD, " Fast Pattern \"");
504  PrintRawUriFp(rule_engine_analysis_FD, pat, patlen);
505  } else {
506  fprintf(rule_engine_analysis_FD, " Fast Pattern \"");
507  PrintRawUriFp(rule_engine_analysis_FD, pat, patlen);
508  }
509  SCFree(pat);
510 
511  fprintf(rule_engine_analysis_FD, "\" on \"");
512 
513  int list_type = SigMatchListSMBelongsTo(s, mpm_sm);
514  if (list_type == DETECT_SM_LIST_PMATCH) {
515  int payload = 0;
516  int stream = 0;
518  payload = 1;
520  stream = 1;
521  fprintf(rule_engine_analysis_FD, "%s",
522  payload ? (stream ? "payload and reassembled stream" : "payload") : "reassembled stream");
523  }
524  else {
525  const char *desc = DetectBufferTypeGetDescriptionById(de_ctx, list_type);
526  const char *name = DetectBufferTypeGetNameById(de_ctx, list_type);
527  if (desc && name) {
528  fprintf(rule_engine_analysis_FD, "%s (%s)", desc, name);
529  } else if (desc || name) {
530  fprintf(rule_engine_analysis_FD, "%s", desc ? desc : name);
531  }
532 
533  }
534 
535  fprintf(rule_engine_analysis_FD, "\" ");
536  if (de_ctx->buffer_type_map[list_type] && de_ctx->buffer_type_map[list_type]->transforms.cnt) {
537  fprintf(rule_engine_analysis_FD, "(with %d transform(s)) ",
538  de_ctx->buffer_type_map[list_type]->transforms.cnt);
539  }
540  fprintf(rule_engine_analysis_FD, "buffer.\n");
541 
542  return;
543 }
544 
545 
546 void EngineAnalysisRulesFailure(char *line, char *file, int lineno)
547 {
548  fprintf(rule_engine_analysis_FD, "== Sid: UNKNOWN ==\n");
549  fprintf(rule_engine_analysis_FD, "%s\n", line);
550  fprintf(rule_engine_analysis_FD, " FAILURE: invalid rule.\n");
551  fprintf(rule_engine_analysis_FD, " File: %s.\n", file);
552  fprintf(rule_engine_analysis_FD, " Line: %d.\n", lineno);
553  fprintf(rule_engine_analysis_FD, "\n");
554 }
555 
556 typedef struct RuleAnalyzer {
557  JsonBuilder *js; /* document root */
558 
559  JsonBuilder *js_warnings;
560  JsonBuilder *js_notes;
562 
563 static void ATTR_FMT_PRINTF(2, 3) AnalyzerNote(RuleAnalyzer *ctx, char *fmt, ...)
564 {
565  va_list ap;
566  char str[1024];
567 
568  va_start(ap, fmt);
569  vsnprintf(str, sizeof(str), fmt, ap);
570  va_end(ap);
571 
572  if (!ctx->js_notes)
573  ctx->js_notes = jb_new_array();
574  if (ctx->js_notes)
575  jb_append_string(ctx->js_notes, str);
576 }
577 
578 static void ATTR_FMT_PRINTF(2, 3) AnalyzerWarning(RuleAnalyzer *ctx, char *fmt, ...)
579 {
580  va_list ap;
581  char str[1024];
582 
583  va_start(ap, fmt);
584  vsnprintf(str, sizeof(str), fmt, ap);
585  va_end(ap);
586 
587  if (!ctx->js_warnings)
588  ctx->js_warnings = jb_new_array();
589  if (ctx->js_warnings)
590  jb_append_string(ctx->js_warnings, str);
591 }
592 
593 #define CHECK(pat) if (strlen((pat)) <= len && memcmp((pat), buf, MIN(len, strlen((pat)))) == 0) return true;
594 
595 static bool LooksLikeHTTPMethod(const uint8_t *buf, uint16_t len)
596 {
597  CHECK("GET /");
598  CHECK("POST /");
599  CHECK("HEAD /");
600  CHECK("PUT /");
601  return false;
602 }
603 
604 static bool LooksLikeHTTPUA(const uint8_t *buf, uint16_t len)
605 {
606  CHECK("User-Agent: ");
607  CHECK("\nUser-Agent: ");
608  return false;
609 }
610 
611 static void DumpContent(JsonBuilder *js, const DetectContentData *cd)
612 {
613  char pattern_str[1024] = "";
614  DetectContentPatternPrettyPrint(cd, pattern_str, sizeof(pattern_str));
615 
616  jb_set_string(js, "pattern", pattern_str);
617  jb_set_uint(js, "length", cd->content_len);
618  jb_set_bool(js, "nocase", cd->flags & DETECT_CONTENT_NOCASE);
619  jb_set_bool(js, "negated", cd->flags & DETECT_CONTENT_NEGATED);
620  jb_set_bool(js, "starts_with", cd->flags & DETECT_CONTENT_STARTS_WITH);
621  jb_set_bool(js, "ends_with", cd->flags & DETECT_CONTENT_ENDS_WITH);
622  jb_set_bool(js, "is_mpm", cd->flags & DETECT_CONTENT_MPM);
623  jb_set_bool(js, "no_double_inspect", cd->flags & DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED);
624  if (cd->flags & DETECT_CONTENT_OFFSET) {
625  jb_set_uint(js, "offset", cd->offset);
626  }
627  if (cd->flags & DETECT_CONTENT_DEPTH) {
628  jb_set_uint(js, "depth", cd->depth);
629  }
630  if (cd->flags & DETECT_CONTENT_DISTANCE) {
631  jb_set_uint(js, "distance", cd->distance);
632  }
633  if (cd->flags & DETECT_CONTENT_WITHIN) {
634  jb_set_uint(js, "within", cd->within);
635  }
636  jb_set_bool(js, "fast_pattern", cd->flags & DETECT_CONTENT_FAST_PATTERN);
637 }
638 
639 static void DumpMatches(RuleAnalyzer *ctx, JsonBuilder *js, const SigMatchData *smd)
640 {
641  if (smd == NULL)
642  return;
643 
644  jb_open_array(js, "matches");
645  do {
646  jb_start_object(js);
647  const char *mname = sigmatch_table[smd->type].name;
648  jb_set_string(js, "name", mname);
649 
650  switch (smd->type) {
651  case DETECT_CONTENT: {
652  const DetectContentData *cd = (const DetectContentData *)smd->ctx;
653 
654  jb_open_object(js, "content");
655  DumpContent(js, cd);
657  AnalyzerNote(ctx, (char *)"'fast_pattern:only' option is silently ignored and "
658  "is interpreted as regular 'fast_pattern'");
659  }
660  if (LooksLikeHTTPMethod(cd->content, cd->content_len)) {
661  AnalyzerWarning(ctx,
662  (char *)"pattern looks like it inspects HTTP, use http.request_line or "
663  "http.method and http.uri instead for improved performance");
664  }
665  if (LooksLikeHTTPUA(cd->content, cd->content_len)) {
666  AnalyzerWarning(ctx,
667  (char *)"pattern looks like it inspects HTTP, use http.user_agent "
668  "or http.header for improved performance");
669  }
670  jb_close(js);
671  break;
672  }
673  }
674  jb_close(js);
675 
676  if (smd->is_last)
677  break;
678  smd++;
679  } while (1);
680  jb_close(js);
681 }
682 
683 static void EngineAnalysisRulePatterns(const DetectEngineCtx *de_ctx, const Signature *s);
684 
687 {
688  SCEnter();
689 
690  EngineAnalysisRulePatterns(de_ctx, s);
691 
692  RuleAnalyzer ctx = { NULL, NULL, NULL };
693 
694  ctx.js = jb_new_object();
695  if (ctx.js == NULL)
696  SCReturn;
697 
698  jb_set_string(ctx.js, "raw", s->sig_str);
699  jb_set_uint(ctx.js, "id", s->id);
700  jb_set_uint(ctx.js, "gid", s->gid);
701  jb_set_uint(ctx.js, "rev", s->rev);
702  jb_set_string(ctx.js, "msg", s->msg);
703 
704  const char *alproto = AppProtoToString(s->alproto);
705  jb_set_string(ctx.js, "app_proto", alproto);
706 
707  jb_open_array(ctx.js, "requirements");
708  if (s->mask & SIG_MASK_REQUIRE_PAYLOAD) {
709  jb_append_string(ctx.js, "payload");
710  }
712  jb_append_string(ctx.js, "no_payload");
713  }
714  if (s->mask & SIG_MASK_REQUIRE_FLOW) {
715  jb_append_string(ctx.js, "flow");
716  }
718  jb_append_string(ctx.js, "tcp_flags_init_deinit");
719  }
721  jb_append_string(ctx.js, "tcp_flags_unusual");
722  }
723  if (s->mask & SIG_MASK_REQUIRE_DCERPC) {
724  jb_append_string(ctx.js, "dcerpc");
725  }
727  jb_append_string(ctx.js, "engine_event");
728  }
729  jb_close(ctx.js);
730 
731  jb_open_array(ctx.js, "flags");
732  if (s->flags & SIG_FLAG_SRC_ANY) {
733  jb_append_string(ctx.js, "src_any");
734  }
735  if (s->flags & SIG_FLAG_DST_ANY) {
736  jb_append_string(ctx.js, "dst_any");
737  }
738  if (s->flags & SIG_FLAG_SP_ANY) {
739  jb_append_string(ctx.js, "sp_any");
740  }
741  if (s->flags & SIG_FLAG_DP_ANY) {
742  jb_append_string(ctx.js, "dp_any");
743  }
744  if (s->flags & SIG_FLAG_NOALERT) {
745  jb_append_string(ctx.js, "noalert");
746  }
747  if (s->flags & SIG_FLAG_DSIZE) {
748  jb_append_string(ctx.js, "dsize");
749  }
750  if (s->flags & SIG_FLAG_APPLAYER) {
751  jb_append_string(ctx.js, "applayer");
752  }
753  if (s->flags & SIG_FLAG_IPONLY) {
754  jb_append_string(ctx.js, "ip_only");
755  }
756  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
757  jb_append_string(ctx.js, "need_packet");
758  }
759  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
760  jb_append_string(ctx.js, "need_stream");
761  }
762  if (s->flags & SIG_FLAG_MPM_NEG) {
763  jb_append_string(ctx.js, "negated_mpm");
764  }
765  if (s->flags & SIG_FLAG_FLUSH) {
766  jb_append_string(ctx.js, "flush");
767  }
768  if (s->flags & SIG_FLAG_REQUIRE_FLOWVAR) {
769  jb_append_string(ctx.js, "need_flowvar");
770  }
771  if (s->flags & SIG_FLAG_FILESTORE) {
772  jb_append_string(ctx.js, "filestore");
773  }
774  if (s->flags & SIG_FLAG_TOSERVER) {
775  jb_append_string(ctx.js, "toserver");
776  }
777  if (s->flags & SIG_FLAG_TOCLIENT) {
778  jb_append_string(ctx.js, "toclient");
779  }
780  if (s->flags & SIG_FLAG_TLSSTORE) {
781  jb_append_string(ctx.js, "tlsstore");
782  }
783  if (s->flags & SIG_FLAG_BYPASS) {
784  jb_append_string(ctx.js, "bypass");
785  }
786  if (s->flags & SIG_FLAG_PREFILTER) {
787  jb_append_string(ctx.js, "prefilter");
788  }
789  if (s->flags & SIG_FLAG_PDONLY) {
790  jb_append_string(ctx.js, "proto_detect_only");
791  }
792  if (s->flags & SIG_FLAG_SRC_IS_TARGET) {
793  jb_append_string(ctx.js, "src_is_target");
794  }
795  if (s->flags & SIG_FLAG_DEST_IS_TARGET) {
796  jb_append_string(ctx.js, "dst_is_target");
797  }
798  jb_close(ctx.js);
799 
800  const DetectEnginePktInspectionEngine *pkt_mpm = NULL;
801  const DetectEngineAppInspectionEngine *app_mpm = NULL;
802 
803  jb_open_array(ctx.js, "pkt_engines");
805  for ( ; pkt != NULL; pkt = pkt->next) {
806  const char *name = DetectBufferTypeGetNameById(de_ctx, pkt->sm_list);
807  if (name == NULL) {
808  switch (pkt->sm_list) {
810  name = "payload";
811  break;
813  name = "packet";
814  break;
815  default:
816  name = "unknown";
817  break;
818  }
819  }
820  jb_start_object(ctx.js);
821  jb_set_string(ctx.js, "name", name);
822  jb_set_bool(ctx.js, "is_mpm", pkt->mpm);
823  DumpMatches(&ctx, ctx.js, pkt->smd);
824  jb_close(ctx.js);
825  if (pkt->mpm) {
826  pkt_mpm = pkt;
827  }
828  }
829  jb_close(ctx.js);
830 
832  bool has_stream = false;
833  bool has_client_body_mpm = false;
834  bool has_file_data_mpm = false;
835 
836  jb_open_array(ctx.js, "engines");
838  for ( ; app != NULL; app = app->next) {
839  const char *name = DetectBufferTypeGetNameById(de_ctx, app->sm_list);
840  if (name == NULL) {
841  switch (app->sm_list) {
843  name = "stream";
844  break;
845  default:
846  name = "unknown";
847  break;
848  }
849  }
850 
851  if (app->sm_list == DETECT_SM_LIST_PMATCH && !app->mpm) {
852  has_stream = true;
853  } else if (app->mpm && strcmp(name, "http_client_body") == 0) {
854  has_client_body_mpm = true;
855  } else if (app->mpm && strcmp(name, "file_data") == 0) {
856  has_file_data_mpm = true;
857  }
858 
859  jb_start_object(ctx.js);
860  jb_set_string(ctx.js, "name", name);
861  const char *direction = app->dir == 0 ? "toserver" : "toclient";
862  jb_set_string(ctx.js, "direction", direction);
863  jb_set_bool(ctx.js, "is_mpm", app->mpm);
864  jb_set_string(ctx.js, "app_proto", AppProtoToString(app->alproto));
865  jb_set_uint(ctx.js, "progress", app->progress);
866  DumpMatches(&ctx, ctx.js, app->smd);
867  jb_close(ctx.js);
868  if (app->mpm) {
869  app_mpm = app;
870  }
871  }
872  jb_close(ctx.js);
873 
874  if (has_stream && has_client_body_mpm)
875  AnalyzerNote(&ctx, (char *)"mpm in http_client_body combined with stream match leads to stream buffering");
876  if (has_stream && has_file_data_mpm)
877  AnalyzerNote(&ctx, (char *)"mpm in file_data combined with stream match leads to stream buffering");
878  }
879 
880  jb_open_object(ctx.js, "lists");
881  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
882  if (s->sm_arrays[i] != NULL) {
883  jb_open_object(ctx.js, DetectSigmatchListEnumToString(i));
884  DumpMatches(&ctx, ctx.js, s->sm_arrays[i]);
885  jb_close(ctx.js);
886  }
887  }
888  jb_close(ctx.js);
889 
890  if (pkt_mpm || app_mpm) {
891  jb_open_object(ctx.js, "mpm");
892 
893  int mpm_list = pkt_mpm ? DETECT_SM_LIST_PMATCH : app_mpm->sm_list;
894  const char *name;
895  if (mpm_list < DETECT_SM_LIST_DYNAMIC_START)
896  name = DetectListToHumanString(mpm_list);
897  else
898  name = DetectBufferTypeGetNameById(de_ctx, mpm_list);
899  jb_set_string(ctx.js, "buffer", name);
900 
901  SigMatchData *smd = pkt_mpm ? pkt_mpm->smd : app_mpm->smd;
902  if (smd == NULL && mpm_list == DETECT_SM_LIST_PMATCH) {
903  smd = s->sm_arrays[mpm_list];
904  }
905  do {
906  switch (smd->type) {
907  case DETECT_CONTENT: {
908  const DetectContentData *cd = (const DetectContentData *)smd->ctx;
909  if (cd->flags & DETECT_CONTENT_MPM) {
910  DumpContent(ctx.js, cd);
911  }
912  break;
913  }
914  }
915 
916  if (smd->is_last)
917  break;
918  smd++;
919  } while (1);
920  jb_close(ctx.js);
921  } else if (s->init_data->prefilter_sm) {
922  jb_open_object(ctx.js, "prefilter");
923  int prefilter_list = SigMatchListSMBelongsTo(s, s->init_data->prefilter_sm);
924  const char *name;
925  if (prefilter_list < DETECT_SM_LIST_DYNAMIC_START)
926  name = DetectListToHumanString(prefilter_list);
927  else
928  name = DetectBufferTypeGetNameById(de_ctx, prefilter_list);
929  jb_set_string(ctx.js, "buffer", name);
930  const char *mname = sigmatch_table[s->init_data->prefilter_sm->type].name;
931  jb_set_string(ctx.js, "name", mname);
932  jb_close(ctx.js);
933  }
934 
935  if (ctx.js_warnings) {
936  jb_close(ctx.js_warnings);
937  jb_set_object(ctx.js, "warnings", ctx.js_warnings);
938  jb_free(ctx.js_warnings);
939  ctx.js_warnings = NULL;
940  }
941  if (ctx.js_notes) {
942  jb_close(ctx.js_notes);
943  jb_set_object(ctx.js, "notes", ctx.js_notes);
944  jb_free(ctx.js_notes);
945  ctx.js_notes = NULL;
946  }
947  jb_close(ctx.js);
948 
949  const char *filename = "rules.json";
950  const char *log_dir = ConfigGetLogDirectory();
951  char json_path[PATH_MAX] = "";
952  snprintf(json_path, sizeof(json_path), "%s/%s", log_dir, filename);
953 
955  FILE *fp = fopen(json_path, "a");
956  if (fp != NULL) {
957  fwrite(jb_ptr(ctx.js), jb_len(ctx.js), 1, fp);
958  fprintf(fp, "\n");
959  fclose(fp);
960  }
962  jb_free(ctx.js);
963  SCReturn;
964 }
965 
966 struct PatternItem {
968  int sm_list;
969  uint32_t cnt;
970  uint32_t mpm;
971 };
972 
973 static inline uint32_t ContentFlagsForHash(const DetectContentData *cd)
974 {
977 }
978 
979 /** \internal
980  * \brief The hash function for Pattern
981  *
982  * \param ht Pointer to the hash table.
983  * \param data Pointer to the Pattern.
984  * \param datalen Not used in our case.
985  *
986  * \retval hash The generated hash value.
987  */
988 static uint32_t PatternHashFunc(HashListTable *ht, void *data, uint16_t datalen)
989 {
990  struct PatternItem *p = (struct PatternItem *)data;
991  uint32_t hash = p->sm_list + ContentFlagsForHash(p->cd);
992 
993  for (uint32_t b = 0; b < p->cd->content_len; b++)
994  hash += p->cd->content[b];
995 
996  return hash % ht->array_size;
997 }
998 
999 /**
1000  * \brief The Compare function for Pattern
1001  *
1002  * \param data1 Pointer to the first Pattern.
1003  * \param len1 Not used.
1004  * \param data2 Pointer to the second Pattern.
1005  * \param len2 Not used.
1006  *
1007  * \retval 1 If the 2 Patterns sent as args match.
1008  * \retval 0 If the 2 Patterns sent as args do not match.
1009  */
1010 static char PatternCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2)
1011 {
1012  const struct PatternItem *p1 = (struct PatternItem *)data1;
1013  const struct PatternItem *p2 = (struct PatternItem *)data2;
1014 
1015  if (p1->sm_list != p2->sm_list)
1016  return 0;
1017 
1018  if (ContentFlagsForHash(p1->cd) != ContentFlagsForHash(p2->cd))
1019  return 0;
1020 
1021  if (p1->cd->content_len != p2->cd->content_len)
1022  return 0;
1023 
1024  if (memcmp(p1->cd->content, p2->cd->content, p1->cd->content_len) != 0) {
1025  return 0;
1026  }
1027 
1028  return 1;
1029 }
1030 
1031 static void PatternFreeFunc(void *ptr)
1032 {
1033  SCFree(ptr);
1034 }
1035 
1036 /**
1037  * \brief Initializes the Pattern mpm hash table to be used by the detection
1038  * engine context.
1039  *
1040  * \param de_ctx Pointer to the detection engine context.
1041  *
1042  * \retval 0 On success.
1043  * \retval -1 On failure.
1044  */
1045 static int PatternInit(DetectEngineCtx *de_ctx)
1046 {
1048  HashListTableInit(4096, PatternHashFunc, PatternCompareFunc, PatternFreeFunc);
1049  if (de_ctx->pattern_hash_table == NULL)
1050  goto error;
1051 
1052  return 0;
1053 
1054 error:
1055  return -1;
1056 }
1057 
1059 {
1061  return;
1062 
1063  JsonBuilder *root_jb = jb_new_object();
1064  JsonBuilder *arrays[de_ctx->buffer_type_map_elements];
1065  memset(&arrays, 0, sizeof(JsonBuilder *) * de_ctx->buffer_type_map_elements);
1066 
1067  jb_open_array(root_jb, "buffers");
1068 
1070  htb != NULL; htb = HashListTableGetListNext(htb)) {
1071  char str[1024] = "";
1072  struct PatternItem *p = HashListTableGetListData(htb);
1073  DetectContentPatternPrettyPrint(p->cd, str, sizeof(str));
1074 
1075  JsonBuilder *jb = arrays[p->sm_list];
1076  if (arrays[p->sm_list] == NULL) {
1077  jb = arrays[p->sm_list] = jb_new_object();
1078  const char *name;
1080  name = DetectListToHumanString(p->sm_list);
1081  else
1083  jb_set_string(jb, "name", name);
1084  jb_set_uint(jb, "list_id", p->sm_list);
1085 
1086  jb_open_array(jb, "patterns");
1087  }
1088 
1089  jb_start_object(jb);
1090  jb_set_string(jb, "pattern", str);
1091  jb_set_uint(jb, "patlen", p->cd->content_len);
1092  jb_set_uint(jb, "cnt", p->cnt);
1093  jb_set_uint(jb, "mpm", p->mpm);
1094  jb_open_object(jb, "flags");
1095  jb_set_bool(jb, "nocase", p->cd->flags & DETECT_CONTENT_NOCASE);
1096  jb_set_bool(jb, "negated", p->cd->flags & DETECT_CONTENT_NEGATED);
1097  jb_set_bool(jb, "depth", p->cd->flags & DETECT_CONTENT_DEPTH);
1098  jb_set_bool(jb, "offset", p->cd->flags & DETECT_CONTENT_OFFSET);
1099  jb_set_bool(jb, "endswith", p->cd->flags & DETECT_CONTENT_ENDS_WITH);
1100  jb_close(jb);
1101  jb_close(jb);
1102  }
1103 
1104  for (uint32_t i = 0; i < de_ctx->buffer_type_map_elements; i++) {
1105  JsonBuilder *jb = arrays[i];
1106  if (jb == NULL)
1107  continue;
1108 
1109  jb_close(jb); // array
1110  jb_close(jb); // object
1111 
1112  jb_append_object(root_jb, jb);
1113  jb_free(jb);
1114  }
1115  jb_close(root_jb);
1116  jb_close(root_jb);
1117 
1118  const char *filename = "patterns.json";
1119  const char *log_dir = ConfigGetLogDirectory();
1120  char json_path[PATH_MAX] = "";
1121  snprintf(json_path, sizeof(json_path), "%s/%s", log_dir, filename);
1122 
1124  FILE *fp = fopen(json_path, "a");
1125  if (fp != NULL) {
1126  fwrite(jb_ptr(root_jb), jb_len(root_jb), 1, fp);
1127  fprintf(fp, "\n");
1128  fclose(fp);
1129  }
1131  jb_free(root_jb);
1132 
1134  de_ctx->pattern_hash_table = NULL;
1135 }
1136 
1137 static void EngineAnalysisRulePatterns(const DetectEngineCtx *de_ctx, const Signature *s)
1138 {
1139  SCEnter();
1140 
1141  if (de_ctx->pattern_hash_table == NULL)
1142  PatternInit((DetectEngineCtx *)de_ctx); // TODO hack const
1143 
1144  if (s->sm_arrays[DETECT_SM_LIST_PMATCH]) {
1146  do {
1147  switch (smd->type) {
1148  case DETECT_CONTENT: {
1149  const DetectContentData *cd = (const DetectContentData *)smd->ctx;
1150  struct PatternItem lookup = {
1151  .cd = cd, .sm_list = DETECT_SM_LIST_PMATCH, .cnt = 0, .mpm = 0
1152  };
1153  struct PatternItem *res =
1155  if (res) {
1156  res->cnt++;
1157  res->mpm += ((cd->flags & DETECT_CONTENT_MPM) != 0);
1158  } else {
1159  struct PatternItem *add = SCCalloc(1, sizeof(*add));
1160  BUG_ON(add == NULL);
1161  add->cd = cd;
1163  add->cnt = 1;
1164  add->mpm = ((cd->flags & DETECT_CONTENT_MPM) != 0);
1165  HashListTableAdd(de_ctx->pattern_hash_table, (void *)add, 0);
1166  }
1167  break;
1168  }
1169  }
1170  if (smd->is_last)
1171  break;
1172  smd++;
1173  } while (1);
1174  }
1175 
1177  for (; app != NULL; app = app->next) {
1178  SigMatchData *smd = app->smd;
1179  do {
1180  switch (smd->type) {
1181  case DETECT_CONTENT: {
1182  const DetectContentData *cd = (const DetectContentData *)smd->ctx;
1183 
1184  struct PatternItem lookup = {
1185  .cd = cd, .sm_list = app->sm_list, .cnt = 0, .mpm = 0
1186  };
1187  struct PatternItem *res =
1189  if (res) {
1190  res->cnt++;
1191  res->mpm += ((cd->flags & DETECT_CONTENT_MPM) != 0);
1192  } else {
1193  struct PatternItem *add = SCCalloc(1, sizeof(*add));
1194  BUG_ON(add == NULL);
1195  add->cd = cd;
1196  add->sm_list = app->sm_list;
1197  add->cnt = 1;
1198  add->mpm = ((cd->flags & DETECT_CONTENT_MPM) != 0);
1199  HashListTableAdd(de_ctx->pattern_hash_table, (void *)add, 0);
1200  }
1201  break;
1202  }
1203  }
1204  if (smd->is_last)
1205  break;
1206  smd++;
1207  } while (1);
1208  }
1210  for (; pkt != NULL; pkt = pkt->next) {
1211  SigMatchData *smd = pkt->smd;
1212  do {
1213  if (smd == NULL) {
1215  smd = s->sm_arrays[pkt->sm_list];
1216  }
1217  switch (smd->type) {
1218  case DETECT_CONTENT: {
1219  const DetectContentData *cd = (const DetectContentData *)smd->ctx;
1220 
1221  struct PatternItem lookup = {
1222  .cd = cd, .sm_list = pkt->sm_list, .cnt = 0, .mpm = 0
1223  };
1224  struct PatternItem *res =
1226  if (res) {
1227  res->cnt++;
1228  res->mpm += ((cd->flags & DETECT_CONTENT_MPM) != 0);
1229  } else {
1230  struct PatternItem *add = SCCalloc(1, sizeof(*add));
1231  BUG_ON(add == NULL);
1232  add->cd = cd;
1233  add->sm_list = pkt->sm_list;
1234  add->cnt = 1;
1235  add->mpm = ((cd->flags & DETECT_CONTENT_MPM) != 0);
1236  HashListTableAdd(de_ctx->pattern_hash_table, (void *)add, 0);
1237  }
1238  break;
1239  }
1240  }
1241  if (smd->is_last)
1242  break;
1243  smd++;
1244  } while (1);
1245  }
1246 
1247  SCReturn;
1248 }
1249 
1250 static void EngineAnalysisItemsReset(void)
1251 {
1252  for (size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) {
1253  analyzer_items[i].item_seen = false;
1254  }
1255 }
1256 
1257 static void EngineAnalysisItemsInit(void)
1258 {
1259  static bool analyzer_init = false;
1260 
1261  if (analyzer_init) {
1262  EngineAnalysisItemsReset();
1263  return;
1264  }
1265 
1266  memset(analyzer_item_map, -1, sizeof(analyzer_item_map));
1267 
1268  for (size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) {
1269  DetectEngineAnalyzerItems *analyzer_item = &analyzer_items[i];
1270 
1271  analyzer_item->item_id = DetectBufferTypeGetByName(analyzer_item->item_name);
1272  if (analyzer_item->item_id == -1) {
1273  /* Mismatch between the analyzer_items array and what's supported */
1275  "unable to initialize engine-analysis table: detect buffer \"%s\" not recognized.",
1276  analyzer_item->item_name);
1277  }
1278  analyzer_item->item_seen = false;
1279 
1280  if (analyzer_item->export_item_seen) {
1281  for (size_t k = 0; k < ARRAY_SIZE(exposed_item_seen_list); k++) {
1282  if (0 == strcmp(exposed_item_seen_list[k].bufname, analyzer_item->item_name))
1283  exposed_item_seen_list[k].item_seen_ptr = &analyzer_item->item_seen;
1284  }
1285 
1286  }
1287  analyzer_item_map[analyzer_item->item_id] = (int16_t) i;
1288  }
1289 
1290  analyzer_init = true;
1291 }
1292 
1293 /**
1294  * \brief Prints analysis of loaded rules.
1295  *
1296  * Warns if potential rule issues are detected. For example,
1297  * warns if a rule uses a construct that may perform poorly,
1298  * e.g. pcre without content or with http_method content only;
1299  * warns if a rule uses a construct that may not be consistent with intent,
1300  * e.g. client side ports only, http and content without any http_* modifiers, etc.
1301  *
1302  * \param s Pointer to the signature.
1303  */
1305  const Signature *s, const char *line)
1306 {
1307  uint32_t rule_bidirectional = 0;
1308  uint32_t rule_pcre = 0;
1309  uint32_t rule_pcre_http = 0;
1310  uint32_t rule_content = 0;
1311  uint32_t rule_flow = 0;
1312  uint32_t rule_flags = 0;
1313  uint32_t rule_flow_toserver = 0;
1314  uint32_t rule_flow_toclient = 0;
1315  uint32_t rule_flow_nostream = 0;
1316  uint32_t rule_ipv4_only = 0;
1317  uint32_t rule_ipv6_only = 0;
1318  uint32_t rule_flowbits = 0;
1319  uint32_t rule_flowint = 0;
1320  uint32_t rule_content_http = 0;
1321  uint32_t rule_content_offset_depth = 0;
1322  int32_t list_id = 0;
1323  uint32_t rule_warning = 0;
1324  uint32_t stream_buf = 0;
1325  uint32_t packet_buf = 0;
1326  uint32_t file_store = 0;
1327  uint32_t warn_pcre_no_content = 0;
1328  uint32_t warn_pcre_http_content = 0;
1329  uint32_t warn_pcre_http = 0;
1330  uint32_t warn_content_http_content = 0;
1331  uint32_t warn_content_http = 0;
1332  uint32_t warn_tcp_no_flow = 0;
1333  uint32_t warn_client_ports = 0;
1334  uint32_t warn_direction = 0;
1335  uint32_t warn_method_toclient = 0;
1336  uint32_t warn_method_serverbody = 0;
1337  uint32_t warn_pcre_method = 0;
1338  uint32_t warn_encoding_norm_http_buf = 0;
1339  uint32_t warn_file_store_not_present = 0;
1340  uint32_t warn_offset_depth_pkt_stream = 0;
1341  uint32_t warn_offset_depth_alproto = 0;
1342  uint32_t warn_non_alproto_fp_for_alproto_sig = 0;
1343  uint32_t warn_no_direction = 0;
1344  uint32_t warn_both_direction = 0;
1345 
1346  EngineAnalysisItemsInit();
1347 
1348  bool *http_method_item_seen_ptr = exposed_item_seen_list[0].item_seen_ptr;
1349  bool *http_server_body_item_seen_ptr = exposed_item_seen_list[1].item_seen_ptr;
1350 
1352  rule_bidirectional = 1;
1353  }
1354 
1355  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
1356  packet_buf += 1;
1357  }
1358  if (s->flags & SIG_FLAG_FILESTORE) {
1359  file_store += 1;
1360  }
1361  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
1362  stream_buf += 1;
1363  }
1364 
1365  if (s->proto.flags & DETECT_PROTO_IPV4) {
1366  rule_ipv4_only += 1;
1367  }
1368  if (s->proto.flags & DETECT_PROTO_IPV6) {
1369  rule_ipv6_only += 1;
1370  }
1371 
1372  for (list_id = 0; list_id < (int)s->init_data->smlists_array_size; list_id++) {
1373  SigMatch *sm = NULL;
1374  for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) {
1375  int16_t item_slot = analyzer_item_map[list_id];
1376  if (sm->type == DETECT_PCRE) {
1377  if (item_slot == -1) {
1378  rule_pcre++;
1379  continue;
1380  }
1381 
1382  rule_pcre_http++;
1383  analyzer_items[item_slot].item_seen = true;
1384  } else if (sm->type == DETECT_CONTENT) {
1385  if (item_slot == -1) {
1386  rule_content++;
1387  if (list_id == DETECT_SM_LIST_PMATCH) {
1390  rule_content_offset_depth++;
1391  }
1392  }
1393  continue;
1394  }
1395 
1396  rule_content_http++;
1397  analyzer_items[item_slot].item_seen = true;
1398 
1399  if (analyzer_items[item_slot].check_encoding_match) {
1401  if (cd != NULL && PerCentEncodingMatch(cd->content, cd->content_len) > 0) {
1402  warn_encoding_norm_http_buf += 1;
1403  }
1404  }
1405  }
1406  else if (sm->type == DETECT_FLOW) {
1407  rule_flow += 1;
1408  if ((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_TOCLIENT)) {
1409  rule_flow_toserver = 1;
1410  }
1411  else if ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_TOSERVER)) {
1412  rule_flow_toclient = 1;
1413  }
1414  DetectFlowData *fd = (DetectFlowData *)sm->ctx;
1415  if (fd != NULL) {
1416  if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM)
1417  rule_flow_nostream = 1;
1418  }
1419  }
1420  else if (sm->type == DETECT_FLOWBITS) {
1421  if (list_id == DETECT_SM_LIST_MATCH) {
1422  rule_flowbits += 1;
1423  }
1424  }
1425  else if (sm->type == DETECT_FLOWINT) {
1426  if (list_id == DETECT_SM_LIST_MATCH) {
1427  rule_flowint += 1;
1428  }
1429  }
1430  else if (sm->type == DETECT_FLAGS) {
1431  DetectFlagsData *fd = (DetectFlagsData *)sm->ctx;
1432  if (fd != NULL) {
1433  rule_flags = 1;
1434  }
1435  }
1436  } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */
1437 
1438  } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */
1439 
1440 
1441  if (file_store && !RequiresFeature("output::file-store")) {
1442  rule_warning += 1;
1443  warn_file_store_not_present = 1;
1444  }
1445 
1446  if (rule_pcre > 0 && rule_content == 0 && rule_content_http == 0) {
1447  rule_warning += 1;
1448  warn_pcre_no_content = 1;
1449  }
1450 
1451  if (rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0) {
1452  rule_warning += 1;
1453  warn_pcre_http_content = 1;
1454  } else if (s->alproto == ALPROTO_HTTP1 && rule_pcre > 0 && rule_pcre_http == 0) {
1455  rule_warning += 1;
1456  warn_pcre_http = 1;
1457  }
1458 
1459  if (rule_content > 0 && rule_content_http > 0) {
1460  rule_warning += 1;
1461  warn_content_http_content = 1;
1462  }
1463  if (s->alproto == ALPROTO_HTTP1 && rule_content > 0 && rule_content_http == 0) {
1464  rule_warning += 1;
1465  warn_content_http = 1;
1466  }
1467  if (rule_content == 1) {
1468  //todo: warning if content is weak, separate warning for pcre + weak content
1469  }
1470  if (rule_flow == 0 && rule_flags == 0
1471  && !(s->proto.flags & DETECT_PROTO_ANY) && DetectProtoContainsProto(&s->proto, IPPROTO_TCP)
1472  && (rule_content || rule_content_http || rule_pcre || rule_pcre_http || rule_flowbits)) {
1473  rule_warning += 1;
1474  warn_tcp_no_flow = 1;
1475  }
1476  if (rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)
1477  && !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))) {
1478  if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))
1479  || ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && (s->flags & SIG_FLAG_SP_ANY))) {
1480  rule_warning += 1;
1481  warn_client_ports = 1;
1482  }
1483  }
1484  if (rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)) {
1485  rule_warning += 1;
1486  warn_direction = 1;
1487  }
1488 
1489  if (*http_method_item_seen_ptr) {
1490  if (rule_flow && rule_flow_toclient) {
1491  rule_warning += 1;
1492  warn_method_toclient = 1;
1493  }
1494  if (*http_server_body_item_seen_ptr) {
1495  rule_warning += 1;
1496  warn_method_serverbody = 1;
1497  }
1498  if (rule_content == 0 && rule_content_http == 0 && (rule_pcre > 0 || rule_pcre_http > 0)) {
1499  rule_warning += 1;
1500  warn_pcre_method = 1;
1501  }
1502  }
1503  if (rule_content_offset_depth > 0 && stream_buf && packet_buf) {
1504  rule_warning += 1;
1505  warn_offset_depth_pkt_stream = 1;
1506  }
1507  if (rule_content_offset_depth > 0 && !stream_buf && packet_buf && s->alproto != ALPROTO_UNKNOWN) {
1508  rule_warning += 1;
1509  warn_offset_depth_alproto = 1;
1510  }
1511  if (s->init_data->mpm_sm != NULL && s->alproto == ALPROTO_HTTP1 &&
1513  rule_warning += 1;
1514  warn_non_alproto_fp_for_alproto_sig = 1;
1515  }
1516 
1517  if ((s->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
1518  warn_no_direction += 1;
1519  rule_warning += 1;
1520  }
1521 
1522  /* No warning about direction for ICMP protos */
1523  if (!(DetectProtoContainsProto(&s->proto, IPPROTO_ICMPV6) && DetectProtoContainsProto(&s->proto, IPPROTO_ICMP))) {
1525  warn_both_direction += 1;
1526  rule_warning += 1;
1527  }
1528  }
1529 
1530  if (!rule_warnings_only || (rule_warnings_only && rule_warning > 0)) {
1531  fprintf(rule_engine_analysis_FD, "== Sid: %u ==\n", s->id);
1532  fprintf(rule_engine_analysis_FD, "%s\n", line);
1533 
1534  if (s->flags & SIG_FLAG_IPONLY) fprintf(rule_engine_analysis_FD, " Rule is ip only.\n");
1535  if (s->flags & SIG_FLAG_PDONLY) fprintf(rule_engine_analysis_FD, " Rule is PD only.\n");
1536  if (rule_ipv6_only) fprintf(rule_engine_analysis_FD, " Rule is IPv6 only.\n");
1537  if (rule_ipv4_only) fprintf(rule_engine_analysis_FD, " Rule is IPv4 only.\n");
1538  if (packet_buf) fprintf(rule_engine_analysis_FD, " Rule matches on packets.\n");
1539  if (!rule_flow_nostream && stream_buf && (rule_flow || rule_flowbits || rule_content || rule_pcre)) {
1540  fprintf(rule_engine_analysis_FD, " Rule matches on reassembled stream.\n");
1541  }
1542  for(size_t i = 0; i < ARRAY_SIZE(analyzer_items); i++) {
1544  if (ai->item_seen) {
1545  fprintf(rule_engine_analysis_FD, " Rule matches on %s buffer.\n", ai->display_name);
1546  }
1547  }
1548  if (s->alproto != ALPROTO_UNKNOWN) {
1549  fprintf(rule_engine_analysis_FD, " App layer protocol is %s.\n", AppProtoToString(s->alproto));
1550  }
1551  if (rule_content || rule_content_http || rule_pcre || rule_pcre_http) {
1552  fprintf(rule_engine_analysis_FD, " Rule contains %d content options, %d http content options, %d pcre options, and %d pcre options with http modifiers.\n", rule_content, rule_content_http, rule_pcre, rule_pcre_http);
1553  }
1554 
1555  /* print fast pattern info */
1556  if (s->init_data->prefilter_sm) {
1557  fprintf(rule_engine_analysis_FD, " Prefilter on: %s.\n",
1559  } else {
1560  EngineAnalysisRulesPrintFP(de_ctx, s);
1561  }
1562 
1563  /* this is where the warnings start */
1564  if (warn_pcre_no_content /*rule_pcre > 0 && rule_content == 0 && rule_content_http == 0*/) {
1565  fprintf(rule_engine_analysis_FD, " Warning: Rule uses pcre without a content option present.\n"
1566  " -Consider adding a content to improve performance of this rule.\n");
1567  }
1568  if (warn_pcre_http_content /*rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0*/) {
1569  fprintf(rule_engine_analysis_FD, " Warning: Rule uses content options with http_* and pcre options without http modifiers.\n"
1570  " -Consider adding http pcre modifier.\n");
1571  }
1572  else if (warn_pcre_http /*s->alproto == ALPROTO_HTTP1 && rule_pcre > 0 && rule_pcre_http == 0*/) {
1573  fprintf(rule_engine_analysis_FD, " Warning: Rule app layer protocol is http, but pcre options do not have http modifiers.\n"
1574  " -Consider adding http pcre modifiers.\n");
1575  }
1576  if (warn_content_http_content /*rule_content > 0 && rule_content_http > 0*/) {
1577  fprintf(rule_engine_analysis_FD, " Warning: Rule contains content with http_* and content without http_*.\n"
1578  " -Consider adding http content modifiers.\n");
1579  }
1580  if (warn_content_http /*s->alproto == ALPROTO_HTTP1 && rule_content > 0 && rule_content_http == 0*/) {
1581  fprintf(rule_engine_analysis_FD, " Warning: Rule app layer protocol is http, but content options do not have http_* modifiers.\n"
1582  " -Consider adding http content modifiers.\n");
1583  }
1584  if (rule_content == 1) {
1585  //todo: warning if content is weak, separate warning for pcre + weak content
1586  }
1587  if (warn_encoding_norm_http_buf) {
1588  fprintf(rule_engine_analysis_FD, " Warning: Rule may contain percent encoded content for a normalized http buffer match.\n");
1589  }
1590  if (warn_tcp_no_flow /*rule_flow == 0 && rule_flags == 0
1591  && !(s->proto.flags & DETECT_PROTO_ANY) && DetectProtoContainsProto(&s->proto, IPPROTO_TCP)*/) {
1592  fprintf(rule_engine_analysis_FD, " Warning: TCP rule without a flow or flags option.\n"
1593  " -Consider adding flow or flags to improve performance of this rule.\n");
1594  }
1595  if (warn_client_ports /*rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)
1596  && !((s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY)))
1597  if (((s->flags & SIG_FLAG_TOSERVER) && !(s->flags & SIG_FLAG_SP_ANY) && (s->flags & SIG_FLAG_DP_ANY))
1598  || ((s->flags & SIG_FLAG_TOCLIENT) && !(s->flags & SIG_FLAG_DP_ANY) && (s->flags & SIG_FLAG_SP_ANY))*/) {
1599  fprintf(rule_engine_analysis_FD, " Warning: Rule contains ports or port variables only on the client side.\n"
1600  " -Flow direction possibly inconsistent with rule.\n");
1601  }
1602  if (warn_direction /*rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)*/) {
1603  fprintf(rule_engine_analysis_FD, " Warning: Rule is bidirectional and has a flow option with a specific direction.\n");
1604  }
1605  if (warn_method_toclient /*http_method_buf && rule_flow && rule_flow_toclient*/) {
1606  fprintf(rule_engine_analysis_FD, " Warning: Rule uses content or pcre for http_method with flow:to_client or from_server\n");
1607  }
1608  if (warn_method_serverbody /*http_method_buf && http_server_body_buf*/) {
1609  fprintf(rule_engine_analysis_FD, " Warning: Rule uses content or pcre for http_method with content or pcre for http_server_body.\n");
1610  }
1611  if (warn_pcre_method /*http_method_buf && rule_content == 0 && rule_content_http == 0
1612  && (rule_pcre > 0 || rule_pcre_http > 0)*/) {
1613  fprintf(rule_engine_analysis_FD, " Warning: Rule uses pcre with only a http_method content; possible performance issue.\n");
1614  }
1615  if (warn_offset_depth_pkt_stream) {
1616  fprintf(rule_engine_analysis_FD, " Warning: Rule has depth"
1617  "/offset with raw content keywords. Please note the "
1618  "offset/depth will be checked against both packet "
1619  "payloads and stream. If you meant to have the offset/"
1620  "depth checked against just the payload, you can update "
1621  "the signature as \"alert tcp-pkt...\"\n");
1622  }
1623  if (warn_offset_depth_alproto) {
1624  fprintf(rule_engine_analysis_FD, " Warning: Rule has "
1625  "offset/depth set along with a match on a specific "
1626  "app layer protocol - %d. This can lead to FNs if we "
1627  "have a offset/depth content match on a packet payload "
1628  "before we can detect the app layer protocol for the "
1629  "flow.\n", s->alproto);
1630  }
1631  if (warn_non_alproto_fp_for_alproto_sig) {
1632  fprintf(rule_engine_analysis_FD, " Warning: Rule app layer "
1633  "protocol is http, but the fast_pattern is set on the raw "
1634  "stream. Consider adding fast_pattern over a http "
1635  "buffer for increased performance.");
1636  }
1637  if (warn_no_direction) {
1638  fprintf(rule_engine_analysis_FD, " Warning: Rule has no direction indicator.\n");
1639  }
1640  if (warn_both_direction) {
1641  fprintf(rule_engine_analysis_FD, " Warning: Rule is inspecting both the request and the response.\n");
1642  }
1643  if (warn_file_store_not_present) {
1644  fprintf(rule_engine_analysis_FD, " Warning: Rule requires file-store but the output file-store is not enabled.\n");
1645  }
1646  if (rule_warning == 0) {
1647  fprintf(rule_engine_analysis_FD, " No warnings for this rule.\n");
1648  }
1649  fprintf(rule_engine_analysis_FD, "\n");
1650  }
1651  return;
1652 }
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:555
RuleAnalyzer::js
JsonBuilder * js
Definition: detect-engine-analyzer.c:557
HashListTableGetListData
#define HashListTableGetListData(hb)
Definition: util-hashlist.h:59
DetectContentData_::offset
uint16_t offset
Definition: detect-content.h:100
DetectEngineAppInspectionEngine_
Definition: detect.h:397
DetectEngineAppInspectionEngine_::mpm
bool mpm
Definition: detect.h:401
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:585
DetectEnginePktInspectionEngine
Definition: detect.h:449
DetectEngineAppInspectionEngine_::next
struct DetectEngineAppInspectionEngine_ * next
Definition: detect.h:416
PerCentEncodingMatch
int PerCentEncodingMatch(uint8_t *content, uint8_t content_len)
Checks for % encoding in content.
Definition: detect-engine-analyzer.c:456
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:1201
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:800
DumpPatterns
void DumpPatterns(DetectEngineCtx *de_ctx)
Definition: detect-engine-analyzer.c:1058
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:491
DETECT_FLOW
@ DETECT_FLOW
Definition: detect-engine-register.h:52
Signature_::alproto
AppProto alproto
Definition: detect.h:521
CleanupFPAnalyzer
void CleanupFPAnalyzer(void)
Definition: detect-engine-analyzer.c:389
PatternItem::mpm
uint32_t mpm
Definition: detect-engine-analyzer.c:970
RuleAnalyzer::js_warnings
JsonBuilder * js_warnings
Definition: detect-engine-analyzer.c:559
g_rules_analyzer_write_m
SCMutex g_rules_analyzer_write_m
Definition: detect-engine-analyzer.c:685
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:332
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:758
DETECT_PROTO_ANY
#define DETECT_PROTO_ANY
Definition: detect-engine-proto.h:27
DetectEnginePktInspectionEngine::smd
SigMatchData * smd
Definition: detect.h:450
HashListTableGetListHead
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
Definition: util-hashlist.c:290
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
rust.h
DetectEngineAnalyzerItems
Definition: detect-engine-analyzer.c:57
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:571
FpPatternStats_::max
uint16_t max
Definition: detect-engine-analyzer.c:51
SignatureInitData_::init_flags
uint32_t init_flags
Definition: detect.h:482
DetectContentData_
Definition: detect-content.h:86
DetectContentData_::fp_chop_offset
uint16_t fp_chop_offset
Definition: detect-content.h:93
HashListTableLookup
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:248
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:329
CleanupRuleAnalyzer
void CleanupRuleAnalyzer(void)
Definition: detect-engine-analyzer.c:413
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
SIG_FLAG_APPLAYER
#define SIG_FLAG_APPLAYER
Definition: detect.h:218
DetectBufferTypeGetByName
int DetectBufferTypeGetByName(const char *name)
Definition: detect-engine.c:832
HashListTableAdd
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:116
analyzer_item_map
int16_t analyzer_item_map[256]
Definition: detect-engine-analyzer.c:119
HashListTable_::array_size
uint32_t array_size
Definition: util-hashlist.h:41
Signature_::gid
uint32_t gid
Definition: detect.h:552
DetectEngineAppInspectionEngine_::sm_list
uint16_t sm_list
Definition: detect.h:403
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
HashListTableInit
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hashlist.c:35
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:452
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:489
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
SIG_FLAG_FLUSH
#define SIG_FLAG_FLUSH
Definition: detect.h:228
SIG_MASK_REQUIRE_FLOW
#define SIG_MASK_REQUIRE_FLOW
Definition: detect.h:271
res
PoolThreadReserved res
Definition: stream-tcp-private.h:0
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:556
Signature_::pkt_inspect
DetectEnginePktInspectionEngine * pkt_inspect
Definition: detect.h:567
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
PatternItem::cd
const DetectContentData * cd
Definition: detect-engine-analyzer.c:967
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:324
SigMatchData_::type
uint8_t type
Definition: detect.h:330
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:1304
Signature_::app_inspect
DetectEngineAppInspectionEngine * app_inspect
Definition: detect.h:566
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:323
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:277
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:518
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:270
PerCentEncodingSetup
int PerCentEncodingSetup()
Compiles regex for rule analysis.
Definition: detect-engine-analyzer.c:427
conf.h
DetectContentData_::flags
uint32_t flags
Definition: detect-content.h:97
CHECK
#define CHECK(pat)
Definition: detect-engine-analyzer.c:593
PatternItem::sm_list
int sm_list
Definition: detect-engine-analyzer.c:968
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:587
SIG_FLAG_SRC_IS_TARGET
#define SIG_FLAG_SRC_IS_TARGET
Definition: detect.h:249
SignatureInitData_::smlists
struct SigMatch_ ** smlists
Definition: detect.h:511
SC_ERR_PCRE_STUDY
@ SC_ERR_PCRE_STUDY
Definition: util-error.h:36
HashListTable_
Definition: util-hashlist.h:37
DetectContentPatternPrettyPrint
void DetectContentPatternPrettyPrint(const DetectContentData *cd, char *str, size_t str_len)
Definition: detect-content.c:650
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:4211
SigMatch_::type
uint8_t type
Definition: detect.h:321
DetectEngineAppInspectionEngine_::alproto
AppProto alproto
Definition: detect.h:398
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
MAX_ENCODED_CHARS
#define MAX_ENCODED_CHARS
DetectEngineAppInspectionEngine_::smd
SigMatchData * smd
Definition: detect.h:414
EngineAnalysisRules2
void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s)
Definition: detect-engine-analyzer.c:686
ARRAY_SIZE
#define ARRAY_SIZE(arr)
Definition: suricata-common.h:541
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:591
RuleAnalyzer::js_notes
JsonBuilder * js_notes
Definition: detect-engine-analyzer.c:560
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:535
SigMatchData_::is_last
uint8_t is_last
Definition: detect.h:331
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
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
DetectEnginePktInspectionEngine::next
struct DetectEnginePktInspectionEngine * next
Definition: detect.h:460
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:553
SetupFPAnalyzer
int SetupFPAnalyzer(void)
Sets up the fast pattern analyzer according to the config.
Definition: detect-engine-analyzer.c:283
DetectEngineCtx_::buffer_type_map
DetectBufferType ** buffer_type_map
Definition: detect.h:916
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:546
DETECT_FLOWBITS
@ DETECT_FLOWBITS
Definition: detect-engine-register.h:88
DetectEngineAppInspectionEngine_::progress
int16_t progress
Definition: detect.h:405
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:268
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:551
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:429
detect-parse.h
Signature_
Signature container.
Definition: detect.h:517
SigMatch_
a single match condition for a signature
Definition: detect.h:320
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
DetectEngineCtx_::buffer_type_map_elements
uint32_t buffer_type_map_elements
Definition: detect.h:917
exposed_item_seen_list
struct ExposedItemSeen exposed_item_seen_list[]
Definition: detect-engine-analyzer.c:125
DetectEngineTransforms::cnt
int cnt
Definition: detect.h:380
suricata.h
SetupRuleAnalyzer
int SetupRuleAnalyzer(void)
Sets up the rule analyzer according to the config.
Definition: detect-engine-analyzer.c:333
DetectBufferTypeGetDescriptionById
const char * DetectBufferTypeGetDescriptionById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:869
DetectEngineAppInspectionEngine_::dir
uint8_t dir
Definition: detect.h:399
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
DetectBufferTypeGetNameById
const char * DetectBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:841
DetectEnginePktInspectionEngine::mpm
bool mpm
Definition: detect.h:451
SC_ERR_INITIALIZATION
@ SC_ERR_INITIALIZATION
Definition: util-error.h:75
PatternItem
Definition: detect-engine-analyzer.c:966
RuleAnalyzer
struct RuleAnalyzer RuleAnalyzer
SIG_FLAG_TLSSTORE
#define SIG_FLAG_TLSSTORE
Definition: detect.h:239
Signature_::msg
char * msg
Definition: detect.h:576
PatternItem::cnt
uint32_t cnt
Definition: detect-engine-analyzer.c:969
DETECT_CONTENT_FAST_PATTERN
#define DETECT_CONTENT_FAST_PATTERN
Definition: detect-content.h:34
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
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:527
SignatureInitData_::smlists_array_size
uint32_t smlists_array_size
Definition: detect.h:509
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
ConfNodeLookupChildValue
const char * ConfNodeLookupChildValue(const ConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:842