Print FP info in rule analysis + other cleanup.
pull/161/merge
Anoop Saldanha 14 years ago committed by Victor Julien
parent ac5bab8838
commit 7a7cd6999e

@ -26,18 +26,177 @@
#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
@ -66,6 +225,9 @@ int SetupRuleAnalyzer(void)
return 0;
}
SCLogInfo("Engine-Analyis for rules printed to file - %s",
log_path);
struct timeval tval;
struct tm *tms;
gettimeofday(&tval, NULL);
@ -97,6 +259,17 @@ int SetupRuleAnalyzer(void)
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);
@ -156,6 +329,86 @@ int PerCentEncodingMatch (uint8_t *content, uint8_t content_len)
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.
*
@ -214,6 +467,7 @@ void EngineAnalysisRules(Signature *s, char *line)
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;
@ -454,6 +708,11 @@ void EngineAnalysisRules(Signature *s, char *line)
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);
@ -481,6 +740,11 @@ void EngineAnalysisRules(Signature *s, char *line)
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");
@ -548,6 +812,12 @@ void EngineAnalysisRules(Signature *s, char *line)
"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");
}

@ -26,10 +26,16 @@
#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__ */

@ -1657,218 +1657,140 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx,
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;
}

@ -26,6 +26,7 @@
#include "tm-threads.h"
#include "detect.h"
#include "detect-content.h"
#include "detect-uricontent.h"
@ -78,5 +79,7 @@ uint32_t DetectPatternGetId(MpmPatternIdStore *, void *, uint8_t);
int SignatureHasPacketContent(Signature *);
int SignatureHasStreamContent(Signature *);
SigMatch *RetrieveFPForSig(Signature *s);
#endif /* __DETECT_ENGINE_MPM_H__ */

@ -194,7 +194,6 @@ extern int rule_reload;
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);
@ -268,236 +267,6 @@ char *DetectLoadCompleteSigPath(char *sig_file)
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
@ -560,11 +329,14 @@ int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *sigs_tot) {
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++;
@ -603,46 +375,8 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl
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();
}
@ -734,17 +468,12 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl
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);

Loading…
Cancel
Save