From d241e51b323d6b9bf14e211aac1b969c66301476 Mon Sep 17 00:00:00 2001 From: Anoop Saldanha Date: Sat, 11 Dec 2010 18:26:02 +0530 Subject: [PATCH] adapt fast pattern engine analysis to reflect the new changes made to your mpm design --- src/detect-engine-mpm.h | 4 + src/detect.c | 172 ++++++++++++++++++++++++++++++++-------- src/suricata.c | 2 +- 3 files changed, 146 insertions(+), 32 deletions(-) diff --git a/src/detect-engine-mpm.h b/src/detect-engine-mpm.h index f272654e9d..adfcfc3350 100644 --- a/src/detect-engine-mpm.h +++ b/src/detect-engine-mpm.h @@ -33,6 +33,7 @@ uint16_t PatternMatchDefaultMatcher(void); +uint32_t PatternStrength(uint8_t *, uint16_t); uint32_t PacketPatternSearch(DetectEngineThreadCtx *, Packet *); uint32_t UriPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint16_t); uint32_t StreamPatternSearch(DetectEngineThreadCtx *, Packet *, StreamMsg *, uint8_t); @@ -66,5 +67,8 @@ uint32_t DetectContentGetId(MpmPatternIdStore *, DetectContentData *); uint32_t DetectUricontentGetId(MpmPatternIdStore *, DetectContentData *); uint32_t DetectPatternGetId(MpmPatternIdStore *, void *, uint8_t); +int SignatureHasPacketContent(Signature *); +int SignatureHasStreamContent(Signature *); + #endif /* __DETECT_ENGINE_MPM_H__ */ diff --git a/src/detect.c b/src/detect.c index 3cf2d0dec4..cc0498f2b5 100644 --- a/src/detect.c +++ b/src/detect.c @@ -253,43 +253,23 @@ char *DetectLoadCompleteSigPath(char *sig_file) return path; } -/** - * \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) +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; - int content_maxlen = 0; - DetectContentData *cd = NULL; DetectContentData *fp_cd = NULL; - SigMatch *sm = NULL; - - for (sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - cd = (DetectContentData *)sm->ctx; - if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { + if (mpm_sm != NULL) { + fp_cd = (DetectContentData *)mpm_sm->ctx; + if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN) { fast_pattern_set = 1; - if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { fast_pattern_only_set = 1; - } else if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { + } else if (fp_cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { fast_pattern_chop_set = 1; } - fp_cd = cd; - break; - } else if (cd->content_len <= content_maxlen) { - continue; } - - fp_cd = cd; } if (fp_cd == NULL) { @@ -299,7 +279,17 @@ void EngineAnalysisFastPattern(Signature *s) } fprintf(fp_engine_analysis_FD, "== Sid: %u ==\n", s->id); - fprintf(fp_engine_analysis_FD, " Fast pattern matcher: content\n"); + fprintf(fp_engine_analysis_FD, " Fast pattern matcher: "); + if (mpm_sm->type == DETECT_CONTENT) + fprintf(fp_engine_analysis_FD, "content\n"); + else if (mpm_sm->type == DETECT_URICONTENT) + fprintf(fp_engine_analysis_FD, "uricontent\n"); + else if (mpm_sm->type == DETECT_AL_HTTP_CLIENT_BODY) + fprintf(fp_engine_analysis_FD, "http_client_body\n"); + else if (mpm_sm->type == DETECT_AL_HTTP_HEADER) + fprintf(fp_engine_analysis_FD, "http_header\n"); + else if (mpm_sm->type == DETECT_AL_HTTP_RAW_HEADER) + fprintf(fp_engine_analysis_FD, "http_raw_header\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"); @@ -318,8 +308,8 @@ void EngineAnalysisFastPattern(Signature *s) SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - memcpy(pat, cd->content, cd->content_len); - pat[cd->content_len] = '\0'; + 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"); @@ -332,7 +322,7 @@ void EngineAnalysisFastPattern(Signature *s) SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); exit(EXIT_FAILURE); } - memcpy(pat, cd->content + fp_cd->fp_chop_offset, fp_cd->fp_chop_len); + 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); @@ -347,6 +337,126 @@ void EngineAnalysisFastPattern(Signature *s) 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 sig_has_no_pkt_and_stream_content = 0; + int list_id = 0; + + if (!SignatureHasPacketContent(s) && !SignatureHasStreamContent(s)) { + sig_has_no_pkt_and_stream_content = 1; + } + + 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 (!FastPatternSupportEnabledForSigMatchType(sm->type)) + 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; + /* 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 (!FastPatternSupportEnabledForSigMatchType(sm->type)) + continue; + + DetectContentData *cd = (DetectContentData *)sm->ctx; + if (max_len < cd->content_len) + max_len = cd->content_len; + } + } + } + + 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 (!FastPatternSupportEnabledForSigMatchType(sm->type)) + 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->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 @@ -432,7 +542,7 @@ int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *sigs_tot) { * \param sig_file Filename holding signatures * \retval -1 on error */ -int SigLoadSignatures (DetectEngineCtx *de_ctx, char *sig_file) +int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file) { SCEnter(); diff --git a/src/suricata.c b/src/suricata.c index 36af1ddf57..eb92e0739a 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -753,6 +753,7 @@ int main(int argc, char **argv) /* Initializations for global vars, queues, etc (memsets, mutex init..) */ GlobalInits(); TimeInit(); + SupportFastPatternForSigMatchTypes(); /* Load yaml configuration file if provided. */ if (conf_filename != NULL) { @@ -834,7 +835,6 @@ int main(int argc, char **argv) SigTableSetup(); /* load the rule keywords */ TmqhSetup(); - SupportFastPatternForSigMatchTypes(); CIDRInit(); SigParsePrepare(); //PatternMatchPrepare(mpm_ctx, MPM_B2G);