Print FP info in rule analysis + other cleanup.
#include "suricata-common.h"
#include "suricata.h"
#include "detect.h"
+#include "detect-parse.h"
#include "detect-engine-analyzer.h"
+#include "detect-engine-mpm.h"
#include "conf.h"
#include "detect-content.h"
#include "detect-flow.h"
#include "detect-flags.h"
+#include "util-print.h"
static int rule_warnings_only = 0;
static FILE *rule_engine_analysis_FD = NULL;
+static FILE *fp_engine_analysis_FD = NULL;
static pcre *percent_re = NULL;
static pcre_extra *percent_re_study = NULL;
static char log_path[PATH_MAX];
+void EngineAnalysisFP(Signature *s, char *line)
+{
+ int fast_pattern_set = 0;
+ int fast_pattern_only_set = 0;
+ int fast_pattern_chop_set = 0;
+ DetectContentData *fp_cd = NULL;
+ SigMatch *mpm_sm = s->mpm_sm;
+
+ if (mpm_sm != NULL) {
+ fp_cd = (DetectContentData *)mpm_sm->ctx;
+ if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN) {
+ fast_pattern_set = 1;
+ if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) {
+ fast_pattern_only_set = 1;
+ } else if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) {
+ fast_pattern_chop_set = 1;
+ }
+ }
+ }
+
+ fprintf(fp_engine_analysis_FD, "== Sid: %u ==\n", s->id);
+ fprintf(fp_engine_analysis_FD, "%s\n", line);
+
+ fprintf(fp_engine_analysis_FD, " Fast Pattern analysis:\n");
+ if (fp_cd == NULL) {
+ fprintf(fp_engine_analysis_FD, " No content present\n");
+ fprintf(fp_engine_analysis_FD, "\n");
+ return;
+ }
+
+ fprintf(fp_engine_analysis_FD, " Fast pattern matcher: ");
+ int list_type = SigMatchListSMBelongsTo(s, mpm_sm);
+ if (list_type == DETECT_SM_LIST_PMATCH)
+ fprintf(fp_engine_analysis_FD, "content\n");
+ else if (list_type == DETECT_SM_LIST_UMATCH)
+ fprintf(fp_engine_analysis_FD, "http uri content\n");
+ else if (list_type == DETECT_SM_LIST_HRUDMATCH)
+ fprintf(fp_engine_analysis_FD, "http raw uri content\n");
+ else if (list_type == DETECT_SM_LIST_HHDMATCH)
+ fprintf(fp_engine_analysis_FD, "http header content\n");
+ else if (list_type == DETECT_SM_LIST_HRHDMATCH)
+ fprintf(fp_engine_analysis_FD, "http raw header content\n");
+ else if (list_type == DETECT_SM_LIST_HMDMATCH)
+ fprintf(fp_engine_analysis_FD, "http method content\n");
+ else if (list_type == DETECT_SM_LIST_HCDMATCH)
+ fprintf(fp_engine_analysis_FD, "http cookie content\n");
+ else if (list_type == DETECT_SM_LIST_HCBDMATCH)
+ fprintf(fp_engine_analysis_FD, "http client body content\n");
+ else if (list_type == DETECT_SM_LIST_HSBDMATCH)
+ fprintf(fp_engine_analysis_FD, "http server body content\n");
+ else if (list_type == DETECT_SM_LIST_HSCDMATCH)
+ fprintf(fp_engine_analysis_FD, "http stat code content\n");
+ else if (list_type == DETECT_SM_LIST_HSMDMATCH)
+ fprintf(fp_engine_analysis_FD, "http stat msg content\n");
+ else if (list_type == DETECT_SM_LIST_HUADMATCH)
+ fprintf(fp_engine_analysis_FD, "http user agent content\n");
+
+ fprintf(fp_engine_analysis_FD, " Fast pattern set: %s\n", fast_pattern_set ? "yes" : "no");
+ fprintf(fp_engine_analysis_FD, " Fast pattern only set: %s\n",
+ fast_pattern_only_set ? "yes" : "no");
+ fprintf(fp_engine_analysis_FD, " Fast pattern chop set: %s\n",
+ fast_pattern_chop_set ? "yes" : "no");
+ if (fast_pattern_chop_set) {
+ fprintf(fp_engine_analysis_FD, " Fast pattern offset, length: %u, %u\n",
+ fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
+ }
+ fprintf(fp_engine_analysis_FD, " Content negated: %s\n",
+ (fp_cd->flags & DETECT_CONTENT_NEGATED) ? "yes" : "no");
+
+ uint16_t patlen = fp_cd->content_len;
+ uint8_t *pat = SCMalloc(fp_cd->content_len + 1);
+ if (unlikely(pat == NULL)) {
+ SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
+ exit(EXIT_FAILURE);
+ }
+ memcpy(pat, fp_cd->content, fp_cd->content_len);
+ pat[fp_cd->content_len] = '\0';
+ fprintf(fp_engine_analysis_FD, " Original content: ");
+ PrintRawUriFp(fp_engine_analysis_FD, pat, patlen);
+ fprintf(fp_engine_analysis_FD, "\n");
+
+ if (fast_pattern_chop_set) {
+ SCFree(pat);
+ patlen = fp_cd->fp_chop_len;
+ pat = SCMalloc(fp_cd->fp_chop_len + 1);
+ if (unlikely(pat == NULL)) {
+ exit(EXIT_FAILURE);
+ }
+ memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
+ pat[fp_cd->fp_chop_len] = '\0';
+ fprintf(fp_engine_analysis_FD, " Final content: ");
+ PrintRawUriFp(fp_engine_analysis_FD, pat, patlen);
+ fprintf(fp_engine_analysis_FD, "\n");
+ } else {
+ fprintf(fp_engine_analysis_FD, " Final content: ");
+ PrintRawUriFp(fp_engine_analysis_FD, pat, patlen);
+ fprintf(fp_engine_analysis_FD, "\n");
+ }
+ SCFree(pat);
+
+ fprintf(fp_engine_analysis_FD, "\n");
+ return;
+}
+
+/**
+ * \brief Sets up the fast pattern analyzer according to the config.
+ *
+ * \retval 1 If rule analyzer successfully enabled.
+ * \retval 0 If not enabled.
+ */
+int SetupFPAnalyzer(void)
+{
+ int fp_engine_analysis_set = 0;
+
+ if ((ConfGetBool("engine-analysis.rules-fast-pattern",
+ &fp_engine_analysis_set)) == 0) {
+ return 0;
+ }
+
+ if (fp_engine_analysis_set == 0)
+ return 0;
+
+ char *log_dir;
+ if (ConfGet("default-log-dir", &log_dir) != 1)
+ log_dir = DEFAULT_LOG_DIR;
+ snprintf(log_path, sizeof(log_path), "%s/%s", log_dir,
+ "rules_fast_pattern.txt");
+
+ fp_engine_analysis_FD = fopen(log_path, "w");
+ if (fp_engine_analysis_FD == NULL) {
+ SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", log_path,
+ strerror(errno));
+ return 0;
+ }
+
+ SCLogInfo("Engine-Analyis for fast_pattern printed to file - %s",
+ log_path);
+
+ struct timeval tval;
+ struct tm *tms;
+ gettimeofday(&tval, NULL);
+ struct tm local_tm;
+ tms = (struct tm *)SCLocalTime(tval.tv_sec, &local_tm);
+ fprintf(fp_engine_analysis_FD, "----------------------------------------------"
+ "---------------------\n");
+ fprintf(fp_engine_analysis_FD, "Date: %" PRId32 "/%" PRId32 "/%04d -- "
+ "%02d:%02d:%02d\n",
+ tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour,
+ tms->tm_min, tms->tm_sec);
+ fprintf(fp_engine_analysis_FD, "----------------------------------------------"
+ "---------------------\n");
+
+ return 1;
+}
+
/**
* \brief Sets up the rule analyzer according to the config
* \retval 1 if rule analyzer successfully enabled
return 0;
}
+ SCLogInfo("Engine-Analyis for rules printed to file - %s",
+ log_path);
+
struct timeval tval;
struct tm *tms;
gettimeofday(&tval, NULL);
return 1;
}
+void CleanupFPAnalyzer(void)
+{
+ if (fp_engine_analysis_FD != NULL) {
+ fclose(fp_engine_analysis_FD);
+ fp_engine_analysis_FD = NULL;
+ }
+
+ return;
+}
+
+
void CleanupRuleAnalyzer(void) {
if (rule_engine_analysis_FD != NULL) {
SCLogInfo("Engine-Analyis for rules printed to file - %s", log_path);
return ret;
}
+static void EngineAnalysisRulesPrintFP(Signature *s)
+{
+ DetectContentData *fp_cd = NULL;
+ SigMatch *mpm_sm = s->mpm_sm;
+
+ if (mpm_sm != NULL) {
+ fp_cd = (DetectContentData *)mpm_sm->ctx;
+ }
+
+ if (fp_cd == NULL) {
+ return;
+ }
+
+ uint16_t patlen = fp_cd->content_len;
+ uint8_t *pat = SCMalloc(fp_cd->content_len + 1);
+ if (unlikely(pat == NULL)) {
+ SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
+ exit(EXIT_FAILURE);
+ }
+ memcpy(pat, fp_cd->content, fp_cd->content_len);
+ pat[fp_cd->content_len] = '\0';
+
+ if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) {
+ SCFree(pat);
+ patlen = fp_cd->fp_chop_len;
+ pat = SCMalloc(fp_cd->fp_chop_len + 1);
+ if (unlikely(pat == NULL)) {
+ exit(EXIT_FAILURE);
+ }
+ memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
+ pat[fp_cd->fp_chop_len] = '\0';
+ fprintf(rule_engine_analysis_FD, " Fast Pattern \"");
+ PrintRawUriFp(rule_engine_analysis_FD, pat, patlen);
+ } else {
+ fprintf(rule_engine_analysis_FD, " Fast Pattern \"");
+ PrintRawUriFp(rule_engine_analysis_FD, pat, patlen);
+ }
+ SCFree(pat);
+
+ fprintf(rule_engine_analysis_FD, "\" on \"");
+
+ int list_type = SigMatchListSMBelongsTo(s, mpm_sm);
+ if (list_type == DETECT_SM_LIST_PMATCH) {
+ int payload = 0;
+ int stream = 0;
+ if (SignatureHasPacketContent(s))
+ payload = 1;
+ if (SignatureHasStreamContent(s))
+ stream = 1;
+ fprintf(rule_engine_analysis_FD, "%s",
+ payload ? (stream ? "payload and reassembled stream" : "payload") : "reassembled stream");
+ }
+ else if (list_type == DETECT_SM_LIST_UMATCH)
+ fprintf(rule_engine_analysis_FD, "http uri content");
+ else if (list_type == DETECT_SM_LIST_HRUDMATCH)
+ fprintf(rule_engine_analysis_FD, "http raw uri content");
+ else if (list_type == DETECT_SM_LIST_HHDMATCH)
+ fprintf(rule_engine_analysis_FD, "http header content");
+ else if (list_type == DETECT_SM_LIST_HRHDMATCH)
+ fprintf(rule_engine_analysis_FD, "http raw header content");
+ else if (list_type == DETECT_SM_LIST_HMDMATCH)
+ fprintf(rule_engine_analysis_FD, "http method content");
+ else if (list_type == DETECT_SM_LIST_HCDMATCH)
+ fprintf(rule_engine_analysis_FD, "http cookie content");
+ else if (list_type == DETECT_SM_LIST_HCBDMATCH)
+ fprintf(rule_engine_analysis_FD, "http client body content");
+ else if (list_type == DETECT_SM_LIST_HSBDMATCH)
+ fprintf(rule_engine_analysis_FD, "http server body content");
+ else if (list_type == DETECT_SM_LIST_HSCDMATCH)
+ fprintf(rule_engine_analysis_FD, "http stat code content");
+ else if (list_type == DETECT_SM_LIST_HSMDMATCH)
+ fprintf(rule_engine_analysis_FD, "http stat msg content");
+ else if (list_type == DETECT_SM_LIST_HUADMATCH)
+ fprintf(rule_engine_analysis_FD, "http user agent content");
+
+ fprintf(rule_engine_analysis_FD, "\" buffer.\n");
+
+ return;
+}
+
/**
* \brief Prints analysis of loaded rules.
*
uint32_t warn_encoding_norm_http_buf = 0;
uint32_t warn_offset_depth_pkt_stream = 0;
uint32_t warn_offset_depth_alproto = 0;
+ uint32_t warn_non_alproto_fp_for_alproto_sig = 0;
if (s->init_flags & SIG_FLAG_INIT_BIDIREC) {
rule_bidirectional = 1;
rule_warning += 1;
warn_offset_depth_alproto = 1;
}
+ if (s->mpm_sm != NULL && s->alproto == ALPROTO_HTTP &&
+ SigMatchListSMBelongsTo(s, s->mpm_sm) == DETECT_SM_LIST_PMATCH) {
+ rule_warning += 1;
+ warn_non_alproto_fp_for_alproto_sig = 1;
+ }
if (!rule_warnings_only || (rule_warnings_only && rule_warning > 0)) {
fprintf(rule_engine_analysis_FD, "== Sid: %u ==\n", s->id);
if (rule_content || rule_content_http || rule_pcre || rule_pcre_http) {
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);
}
+
+ /* print fast pattern info */
+ EngineAnalysisRulesPrintFP(s);
+
+ /* this is where the warnings start */
if (warn_pcre_no_content /*rule_pcre > 0 && rule_content == 0 && rule_content_http == 0*/) {
fprintf(rule_engine_analysis_FD, " Warning: Rule uses pcre without a content option present.\n"
" -Consider adding a content to improve performance of this rule.\n");
"before we can detect the app layer protocol for the "
"flow.\n", s->alproto);
}
+ if (warn_non_alproto_fp_for_alproto_sig) {
+ fprintf(rule_engine_analysis_FD, " Warning: Rule app layer "
+ "protocol is http, but the fast_pattern is set on the raw "
+ "stream. Consider adding fast_pattern over a http "
+ "buffer for increased performance.");
+ }
if (rule_warning == 0) {
fprintf(rule_engine_analysis_FD, " No warnings for this rule.\n");
}
#include <stdint.h>
+int SetupFPAnalyzer(void);
+void CleanupFPAnalyzer(void);
+
int SetupRuleAnalyzer(void);
void CleanupRuleAnalyzer (void);
+
int PerCentEncodingSetup ();
int PerCentEncodingMatch (uint8_t *content, uint8_t content_len);
+
+void EngineAnalysisFP(Signature *s, char *line);
void EngineAnalysisRules(Signature *s, char *line);
#endif /* __DETECT_ENGINE_ANALYZER_H__ */
return;
}
-/**
- * \internal
- * \brief Setup the mpm content.
- *
- * \param de_ctx Pointer to the detect engine context.
- * \param sgh Pointer to the signature group head against which we are
- * adding patterns to the mpm ctx.
- *
- * \retval 0 Always.
- */
-static int PatternMatchPreparePopulateMpm(DetectEngineCtx *de_ctx,
- SigGroupHead *sgh)
+SigMatch *RetrieveFPForSig(Signature *s)
{
- uint32_t sig;
- uint8_t *fast_pattern = NULL;
- uint8_t *has_non_negated_non_stream_pattern = NULL;
-
- fast_pattern = (uint8_t *)SCMalloc(sgh->sig_cnt * sizeof(uint8_t));
- if (fast_pattern == NULL) {
- SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
- exit(EXIT_FAILURE);
- }
- memset(fast_pattern, 0, sgh->sig_cnt * sizeof(uint8_t));
- has_non_negated_non_stream_pattern = (uint8_t *)SCMalloc(sgh->sig_cnt * sizeof(uint8_t));
- if (has_non_negated_non_stream_pattern == NULL) {
- SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
- exit(EXIT_FAILURE);
- }
- memset(has_non_negated_non_stream_pattern, 0, sgh->sig_cnt * sizeof(uint8_t));
+ SigMatch *mpm_sm = NULL;
+ uint8_t has_non_negated_non_stream_pattern = 0;
- /* add all mpm candidates to a hash */
- for (sig = 0; sig < sgh->sig_cnt; sig++) {
- Signature *s = sgh->match_array[sig];
- if (s == NULL)
- continue;
+ if (s->mpm_sm != NULL)
+ return s->mpm_sm;
- /* we already have a sm set as fp for this sig. Add it to the current
- * mpm context */
- if (s->mpm_sm != NULL) {
- PopulateMpmAddPatternToMpm(de_ctx, sgh, s, s->mpm_sm);
+ for (int list_id = 0 ; list_id < DETECT_SM_LIST_MAX; list_id++) {
+ /* we have no keywords that support fp in this Signature sm list */
+ if (!FastPatternSupportEnabledForSigMatchList(list_id))
continue;
- }
- int list_id = 0;
- for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) {
- /* we have no keywords that support fp in this Signature sm list */
- if (!FastPatternSupportEnabledForSigMatchList(list_id))
+ for (SigMatch *sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) {
+ /* this keyword isn't registered for fp support */
+ if (sm->type != DETECT_CONTENT)
continue;
- SigMatch *sm = NULL;
- /* get the total no of patterns in this Signature, as well as find out
- * if we have a fast_pattern set in this Signature */
- for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) {
- /* this keyword isn't registered for fp support */
- if (sm->type != DETECT_CONTENT)
- continue;
-
- //if (PopulateMpmSkipContent(sgh, s, sm)) {
- // continue;
- //}
-
- DetectContentData *cd = (DetectContentData *)sm->ctx;
- if (!(cd->flags & DETECT_CONTENT_NEGATED) &&
- list_id != DETECT_SM_LIST_PMATCH &&
- /* don't consider http_method, http_stat_msg, http_stat_code
- * to automatically override longest stream match */
- list_id != DETECT_SM_LIST_HMDMATCH &&
- list_id != DETECT_SM_LIST_HSMDMATCH &&
- list_id != DETECT_SM_LIST_HSCDMATCH) {
- has_non_negated_non_stream_pattern[sig] = 1;
- }
-
- if (cd->flags & DETECT_CONTENT_FAST_PATTERN) {
- fast_pattern[sig] = 1;
- break;
- }
- } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */
-
- /* found a fast pattern for the sig. Let's get outta here */
- if (fast_pattern[sig])
- break;
- } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */
- } /* for (sig = 0; sig < sgh->sig_cnt; sig++) { */
+ DetectContentData *cd = (DetectContentData *)sm->ctx;
+ if (cd->flags & DETECT_CONTENT_FAST_PATTERN)
+ return sm;
+ if (!(cd->flags & DETECT_CONTENT_NEGATED) &&
+ (list_id != DETECT_SM_LIST_PMATCH) &&
+ (list_id != DETECT_SM_LIST_HMDMATCH) &&
+ (list_id != DETECT_SM_LIST_HSMDMATCH) &&
+ (list_id != DETECT_SM_LIST_HSCDMATCH)) {
+ has_non_negated_non_stream_pattern = 1;
+ }
+ }
+ }
- /* now determine which one to add to the mpm phase */
- for (sig = 0; sig < sgh->sig_cnt; sig++) {
- Signature *s = sgh->match_array[sig];
- if (s == NULL)
+ int max_len = 0;
+ int max_len_negated = 0;
+ int max_len_non_negated = 0;
+ for (int list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) {
+ if (!FastPatternSupportEnabledForSigMatchList(list_id))
continue;
- /* have taken care of this in the previous loop. move on to the next sig */
- if (s->mpm_sm != NULL) {
+
+ if (has_non_negated_non_stream_pattern &&
+ ((list_id == DETECT_SM_LIST_PMATCH) ||
+ (list_id == DETECT_SM_LIST_HMDMATCH) ||
+ (list_id == DETECT_SM_LIST_HSMDMATCH) ||
+ (list_id == DETECT_SM_LIST_HSCDMATCH))) {
continue;
}
- int max_len = 0;
- int max_len_negated = 0;
- int max_len_non_negated = 0;
- /* get the longest pattern in the sig */
- if (!fast_pattern[sig]) {
- SigMatch *sm = NULL;
- int list_id = 0;
- for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) {
- if (!FastPatternSupportEnabledForSigMatchList(list_id))
- continue;
+ for (SigMatch *sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) {
+ if (sm->type != DETECT_CONTENT)
+ continue;
- if (list_id == DETECT_SM_LIST_PMATCH &&
- !fast_pattern[sig] &&
- has_non_negated_non_stream_pattern[sig]) {
- continue;
- }
+ DetectContentData *cd = (DetectContentData *)sm->ctx;
+ if (cd->flags & DETECT_CONTENT_NEGATED) {
+ if (max_len_negated < cd->content_len)
+ max_len_negated = cd->content_len;
+ } else {
+ if (max_len_non_negated < cd->content_len)
+ max_len_non_negated = cd->content_len;
+ }
+ }
+ }
- for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) {
- if (sm->type != DETECT_CONTENT)
- continue;
+ int skip_negated_content = 0;
+ if (max_len_non_negated == 0) {
+ max_len = max_len_negated;
+ skip_negated_content = 0;
+ } else {
+ max_len = max_len_non_negated;
+ skip_negated_content = 1;
+ }
- //if (PopulateMpmSkipContent(sgh, s, sm)) {
- // continue;
- //}
+ for (int list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) {
+ if (!FastPatternSupportEnabledForSigMatchList(list_id))
+ continue;
- DetectContentData *cd = (DetectContentData *)sm->ctx;
- if (cd->flags & DETECT_CONTENT_NEGATED) {
- if (max_len_negated < cd->content_len)
- max_len_negated = cd->content_len;
- } else {
- if (max_len_non_negated < cd->content_len)
- max_len_non_negated = cd->content_len;
- }
- } /* for ( ; list_id.. */
- } /* for (sm = s->sm_lists.. */
- } /* if */
-
- int skip_negated_content = 0;
- if (max_len_non_negated == 0) {
- max_len = max_len_negated;
- skip_negated_content = 0;
- } else {
- max_len = max_len_non_negated;
- skip_negated_content = 1;
+ if (has_non_negated_non_stream_pattern &&
+ ((list_id == DETECT_SM_LIST_PMATCH) ||
+ (list_id == DETECT_SM_LIST_HMDMATCH) ||
+ (list_id == DETECT_SM_LIST_HSMDMATCH) ||
+ (list_id == DETECT_SM_LIST_HSCDMATCH))) {
+ continue;
}
- SigMatch *mpm_sm = NULL;
- SigMatch *sm = NULL;
- int list_id = 0;
- for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) {
- if (!FastPatternSupportEnabledForSigMatchList(list_id))
+ for (SigMatch *sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) {
+ if (sm->type != DETECT_CONTENT)
continue;
- if (list_id == DETECT_SM_LIST_PMATCH &&
- !fast_pattern[sig] &&
- has_non_negated_non_stream_pattern[sig]) {
+ DetectContentData *cd = (DetectContentData *)sm->ctx;
+ if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
+ continue;
+ if (cd->content_len < max_len)
continue;
- }
-
- for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) {
- if (sm->type != DETECT_CONTENT)
- continue;
-
- /* skip in case of:
- * 1. we expect a fastpattern but this isn't it */
- if (fast_pattern[sig]) {
- /* can be any content based keyword since all of them
- * now use a unified structure - DetectContentData */
- DetectContentData *cd = (DetectContentData *)sm->ctx;
- if (!(cd->flags & DETECT_CONTENT_FAST_PATTERN)) {
- SCLogDebug("not a fast pattern %"PRIu32"", cd->id);
- continue;
- }
- SCLogDebug("fast pattern %"PRIu32"", cd->id);
- } else {
- //if (PopulateMpmSkipContent(sgh, s, sm)) {
- // continue;
- //}
-
- DetectContentData *cd = (DetectContentData *)sm->ctx;
- if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
- continue;
- if (cd->content_len < max_len)
- continue;
-
- } /* else - if (fast_pattern[sig] == 1) */
- if (mpm_sm == NULL) {
+ if (mpm_sm == NULL) {
+ mpm_sm = sm;
+ } else {
+ DetectContentData *data1 = (DetectContentData *)sm->ctx;
+ DetectContentData *data2 = (DetectContentData *)mpm_sm->ctx;
+ uint32_t ls = PatternStrength(data1->content, data1->content_len);
+ uint32_t ss = PatternStrength(data2->content, data2->content_len);
+ if (ls > ss) {
mpm_sm = sm;
- if (fast_pattern[sig])
- break;
- } else {
- DetectContentData *data1 = (DetectContentData *)sm->ctx;
- DetectContentData *data2 = (DetectContentData *)mpm_sm->ctx;
- uint32_t ls = PatternStrength(data1->content, data1->content_len);
- uint32_t ss = PatternStrength(data2->content, data2->content_len);
- if (ls > ss) {
+ } else if (ls == ss) {
+ /* if 2 patterns are of equal strength, we pick the longest */
+ if (data1->content_len > data2->content_len)
mpm_sm = sm;
- } else if (ls == ss) {
- /* if 2 patterns are of equal strength, we pick the longest */
- if (data1->content_len > data2->content_len)
- mpm_sm = sm;
- } else {
- SCLogDebug("sticking with mpm_sm");
- }
- } /* else - if (mpm == NULL) */
- } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */
- if (mpm_sm != NULL && fast_pattern[sig])
- break;
- } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */
+ } else {
+ SCLogDebug("sticking with mpm_sm");
+ }
+ } /* else - if (mpm == NULL) */
+ } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */
+ } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */
- PopulateMpmAddPatternToMpm(de_ctx, sgh, s, mpm_sm);
- } /* for (sig = 0; sig < sgh->sig_cnt; sig++) */
+ return mpm_sm;
+}
- if (fast_pattern != NULL)
- SCFree(fast_pattern);
- if (has_non_negated_non_stream_pattern != NULL)
- SCFree(has_non_negated_non_stream_pattern);
+/**
+ * \internal
+ * \brief Setup the mpm content.
+ *
+ * \param de_ctx Pointer to the detect engine context.
+ * \param sgh Pointer to the signature group head against which we are
+ * adding patterns to the mpm ctx.
+ *
+ * \retval 0 Always.
+ */
+static int PatternMatchPreparePopulateMpm(DetectEngineCtx *de_ctx,
+ SigGroupHead *sgh)
+{
+ for (uint32_t sig = 0; sig < sgh->sig_cnt; sig++) {
+ Signature *s = sgh->match_array[sig];
+ if (s == NULL)
+ continue;
+ PopulateMpmAddPatternToMpm(de_ctx, sgh, s, RetrieveFPForSig(s));
+ } /* for (sig = 0; sig < sgh->sig_cnt; sig++) */
return 0;
}
#include "tm-threads.h"
+#include "detect.h"
#include "detect-content.h"
#include "detect-uricontent.h"
int SignatureHasPacketContent(Signature *);
int SignatureHasStreamContent(Signature *);
+SigMatch *RetrieveFPForSig(Signature *s);
+
#endif /* __DETECT_ENGINE_MPM_H__ */
extern int engine_analysis;
static int fp_engine_analysis_set = 0;
static int rule_engine_analysis_set = 0;
-static FILE *fp_engine_analysis_FD = NULL;
SigMatch *SigMatchAlloc(void);
void DetectExitPrintStats(ThreadVars *tv, void *data);
return path;
}
-static inline void EngineAnalysisWriteFastPattern(Signature *s, SigMatch *mpm_sm)
-{
- int fast_pattern_set = 0;
- int fast_pattern_only_set = 0;
- int fast_pattern_chop_set = 0;
- DetectContentData *fp_cd = NULL;
-
- if (mpm_sm != NULL) {
- fp_cd = (DetectContentData *)mpm_sm->ctx;
- if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN) {
- fast_pattern_set = 1;
- if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) {
- fast_pattern_only_set = 1;
- } else if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) {
- fast_pattern_chop_set = 1;
- }
- }
- }
-
- if (fp_cd == NULL) {
- fprintf(fp_engine_analysis_FD, "== Sid: %u ==\n", s->id);
- fprintf(fp_engine_analysis_FD, " No content present\n");
- return;
- }
-
- fprintf(fp_engine_analysis_FD, "== Sid: %u ==\n", s->id);
- fprintf(fp_engine_analysis_FD, " Fast pattern matcher: ");
- int list_type = SigMatchListSMBelongsTo(s, mpm_sm);
- if (list_type == DETECT_SM_LIST_PMATCH)
- fprintf(fp_engine_analysis_FD, "content\n");
- else if (list_type == DETECT_SM_LIST_UMATCH)
- fprintf(fp_engine_analysis_FD, "http uri content\n");
- else if (list_type == DETECT_SM_LIST_HRUDMATCH)
- fprintf(fp_engine_analysis_FD, "http raw uri content\n");
- else if (list_type == DETECT_SM_LIST_HHDMATCH)
- fprintf(fp_engine_analysis_FD, "http header content\n");
- else if (list_type == DETECT_SM_LIST_HRHDMATCH)
- fprintf(fp_engine_analysis_FD, "http raw header content\n");
- else if (list_type == DETECT_SM_LIST_HMDMATCH)
- fprintf(fp_engine_analysis_FD, "http method content\n");
- else if (list_type == DETECT_SM_LIST_HCDMATCH)
- fprintf(fp_engine_analysis_FD, "http cookie content\n");
- else if (list_type == DETECT_SM_LIST_HCBDMATCH)
- fprintf(fp_engine_analysis_FD, "http client body content\n");
- else if (list_type == DETECT_SM_LIST_HSBDMATCH)
- fprintf(fp_engine_analysis_FD, "http server body content\n");
- else if (list_type == DETECT_SM_LIST_HSCDMATCH)
- fprintf(fp_engine_analysis_FD, "http stat code content\n");
- else if (list_type == DETECT_SM_LIST_HSMDMATCH)
- fprintf(fp_engine_analysis_FD, "http stat msg content\n");
-
- fprintf(fp_engine_analysis_FD, " Fast pattern set: %s\n", fast_pattern_set ? "yes" : "no");
- fprintf(fp_engine_analysis_FD, " Fast pattern only set: %s\n",
- fast_pattern_only_set ? "yes" : "no");
- fprintf(fp_engine_analysis_FD, " Fast pattern chop set: %s\n",
- fast_pattern_chop_set ? "yes" : "no");
- if (fast_pattern_chop_set) {
- fprintf(fp_engine_analysis_FD, " Fast pattern offset, length: %u, %u\n",
- fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
- }
- fprintf(fp_engine_analysis_FD, " Content negated: %s\n",
- (fp_cd->flags & DETECT_CONTENT_NEGATED) ? "yes" : "no");
-
- uint16_t patlen = fp_cd->content_len;
- uint8_t *pat = SCMalloc(fp_cd->content_len + 1);
- if (unlikely(pat == NULL)) {
- SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
- exit(EXIT_FAILURE);
- }
- memcpy(pat, fp_cd->content, fp_cd->content_len);
- pat[fp_cd->content_len] = '\0';
- fprintf(fp_engine_analysis_FD, " Original content: ");
- PrintRawUriFp(fp_engine_analysis_FD, pat, patlen);
- fprintf(fp_engine_analysis_FD, "\n");
-
- if (fast_pattern_chop_set) {
- SCFree(pat);
- patlen = fp_cd->fp_chop_len;
- pat = SCMalloc(fp_cd->fp_chop_len + 1);
- if (unlikely(pat == NULL)) {
- exit(EXIT_FAILURE);
- }
- memcpy(pat, fp_cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len);
- pat[fp_cd->fp_chop_len] = '\0';
- fprintf(fp_engine_analysis_FD, " Final content: ");
- PrintRawUriFp(fp_engine_analysis_FD, pat, patlen);
- fprintf(fp_engine_analysis_FD, "\n");
- } else {
- fprintf(fp_engine_analysis_FD, " Final content: ");
- PrintRawUriFp(fp_engine_analysis_FD, pat, patlen);
- fprintf(fp_engine_analysis_FD, "\n");
- }
- SCFree(pat);
-
- return;
-}
-
-/**
- * \brief Prints analysis of fast pattern for a signature.
- *
- * The code here mimics the logic to select fast_pattern from staging.
- * If any changes are made to the staging logic, this should follow suit.
- *
- * \param s Pointer to the signature.
- */
-void EngineAnalysisFastPattern(Signature *s)
-{
- SigMatch *mpm_sm = NULL;
- uint32_t fast_pattern = 0;
- int list_id = 0;
-
- for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) {
- /* we have no keywords that support fp in this Signature sm list */
- if (!FastPatternSupportEnabledForSigMatchList(list_id))
- continue;
-
- SigMatch *sm = NULL;
- /* get the total no of patterns in this Signature, as well as find out
- * if we have a fast_pattern set in this Signature */
- for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) {
- /* this keyword isn't registered for fp support */
- if (sm->type != DETECT_CONTENT)
- continue;
-
- DetectContentData *cd = (DetectContentData *)sm->ctx;
- if (cd->flags & DETECT_CONTENT_FAST_PATTERN) {
- fast_pattern = 1;
- break;
- }
- } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */
-
- /* found a fast pattern for the sig. Let's get outta here */
- if (fast_pattern)
- break;
- } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */
-
- int max_len = 0;
- int max_len_negated = 0;
- int max_len_non_negated = 0;
- /* get the longest pattern in the sig */
- if (!fast_pattern) {
- SigMatch *sm = NULL;
- for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) {
- if (!FastPatternSupportEnabledForSigMatchList(list_id))
- continue;
-
- for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) {
- if (sm->type != DETECT_CONTENT)
- continue;
-
- DetectContentData *cd = (DetectContentData *)sm->ctx;
- if (cd->flags & DETECT_CONTENT_NEGATED) {
- if (max_len_negated < cd->content_len)
- max_len_negated = cd->content_len;
- } else {
- if (max_len_non_negated < cd->content_len)
- max_len_non_negated = cd->content_len;
- }
- }
- }
- }
-
- int skip_negated_content = 0;
- if (max_len_non_negated == 0) {
- max_len = max_len_negated;
- skip_negated_content = 0;
- } else {
- max_len = max_len_non_negated;
- skip_negated_content = 1;
- }
-
- SigMatch *sm = NULL;
- for (list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) {
- if (!FastPatternSupportEnabledForSigMatchList(list_id))
- continue;
-
- for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) {
- if (sm->type != DETECT_CONTENT)
- continue;
-
- /* skip in case of:
- * 1. we expect a fastpattern but this isn't it */
- if (fast_pattern) {
- /* can be any content based keyword since all of them
- * now use a unified structure - DetectContentData */
- DetectContentData *cd = (DetectContentData *)sm->ctx;
- if (!(cd->flags & DETECT_CONTENT_FAST_PATTERN)) {
- SCLogDebug("not a fast pattern %"PRIu32"", cd->id);
- continue;
- }
- SCLogDebug("fast pattern %"PRIu32"", cd->id);
- } else {
- DetectContentData *cd = (DetectContentData *)sm->ctx;
- if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
- continue;
- if (cd->content_len < max_len)
- continue;
-
- } /* else - if (fast_pattern[sig] == 1) */
-
- if (mpm_sm == NULL) {
- mpm_sm = sm;
- if (fast_pattern)
- break;
- } else {
- DetectContentData *data1 = (DetectContentData *)sm->ctx;
- DetectContentData *data2 = (DetectContentData *)mpm_sm->ctx;
- uint32_t ls = PatternStrength(data1->content, data1->content_len);
- uint32_t ss = PatternStrength(data2->content, data2->content_len);
- if (ls > ss) {
- mpm_sm = sm;
- } else if (ls == ss) {
- /* if 2 patterns are of equal strength, we pick the longest */
- if (data1->content_len > data2->content_len)
- mpm_sm = sm;
- } else {
- SCLogDebug("sticking with mpm_sm");
- }
- } /* else - if (mpm == NULL) */
- } /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */
- if (mpm_sm != NULL && fast_pattern)
- break;
- } /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */
-
- /* output result to file */
- EngineAnalysisWriteFastPattern(s, mpm_sm);
-
- return;
-}
-
/**
* \brief Load a file with signatures
* \param de_ctx Pointer to the detection engine context
sig = DetectEngineAppendSig(de_ctx, line);
(*sigs_tot)++;
if (sig != NULL) {
- if (fp_engine_analysis_set) {
- EngineAnalysisFastPattern(sig);
- }
- if (rule_engine_analysis_set) {
- EngineAnalysisRules(sig, line);
+ if (rule_engine_analysis_set || fp_engine_analysis_set) {
+ sig->mpm_sm = RetrieveFPForSig(sig);
+ if (fp_engine_analysis_set) {
+ EngineAnalysisFP(sig, line);
+ }
+ if (rule_engine_analysis_set) {
+ EngineAnalysisRules(sig, line);
+ }
}
SCLogDebug("signature %"PRIu32" loaded", sig->id);
good++;
int sigtotal = 0;
char *sfile = NULL;
- /* needed by engine_analysis */
- char log_path[PATH_MAX];
-
if (engine_analysis) {
- if ((ConfGetBool("engine-analysis.rules-fast-pattern",
- &fp_engine_analysis_set)) == 0) {
- SCLogInfo("Conf parameter \"engine-analysis.rules-fast-pattern\" not "
- "found. Defaulting to not printing the fast_pattern "
- "report.");
- fp_engine_analysis_set = 0;
- }
- if (fp_engine_analysis_set) {
- char *log_dir;
- if (ConfGet("default-log-dir", &log_dir) != 1)
- log_dir = DEFAULT_LOG_DIR;
- snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, "rules_fast_pattern.txt");
-
- fp_engine_analysis_FD = fopen(log_path, "w");
- if (fp_engine_analysis_FD == NULL) {
- SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", log_path,
- strerror(errno));
- return -1;
- }
- struct timeval tval;
- struct tm *tms;
- gettimeofday(&tval, NULL);
- struct tm local_tm;
- tms = (struct tm *)SCLocalTime(tval.tv_sec, &local_tm);
- fprintf(fp_engine_analysis_FD, "----------------------------------------------"
- "---------------------\n");
- fprintf(fp_engine_analysis_FD, "Date: %" PRId32 "/%" PRId32 "/%04d -- "
- "%02d:%02d:%02d\n",
- tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour,
- tms->tm_min, tms->tm_sec);
- fprintf(fp_engine_analysis_FD, "----------------------------------------------"
- "---------------------\n");
- }
- else {
- SCLogInfo("Engine-Analysis for fast_pattern disabled in conf file.");
- }
+ fp_engine_analysis_set = SetupFPAnalyzer();
rule_engine_analysis_set = SetupRuleAnalyzer();
}
end:
if (engine_analysis) {
- if (fp_engine_analysis_set) {
- if (fp_engine_analysis_FD != NULL) {
- SCLogInfo("Engine-Analyis for fast_pattern printed to file - %s",
- log_path);
- fclose(fp_engine_analysis_FD);
- fp_engine_analysis_FD = NULL;
- }
- }
if (rule_engine_analysis_set) {
CleanupRuleAnalyzer();
}
+ if (fp_engine_analysis_set) {
+ CleanupFPAnalyzer();
+ }
}
DetectParseDupSigHashFree(de_ctx);