diff --git a/src/detect-content.h b/src/detect-content.h index 4c99670be0..11ea1b393e 100644 --- a/src/detect-content.h +++ b/src/detect-content.h @@ -26,17 +26,21 @@ /* Flags affecting this content */ -#define DETECT_CONTENT_NOCASE 0x01 -#define DETECT_CONTENT_DISTANCE 0x02 -#define DETECT_CONTENT_WITHIN 0x04 -#define DETECT_CONTENT_FAST_PATTERN 0x08 +#define DETECT_CONTENT_NOCASE 0x0001 +#define DETECT_CONTENT_DISTANCE 0x0002 +#define DETECT_CONTENT_WITHIN 0x0004 +#define DETECT_CONTENT_OFFSET 0x0008 +#define DETECT_CONTENT_DEPTH 0x0010 +#define DETECT_CONTENT_FAST_PATTERN 0x0020 +#define DETECT_CONTENT_FAST_PATTERN_ONLY 0x0040 +#define DETECT_CONTENT_FAST_PATTERN_CHOP 0x0080 /** content applies to a "raw"/undecoded field if applicable */ -#define DETECT_CONTENT_RAWBYTES 0x10 +#define DETECT_CONTENT_RAWBYTES 0x0100 /** content is negated */ -#define DETECT_CONTENT_NEGATED 0x20 +#define DETECT_CONTENT_NEGATED 0x0200 /** a relative match to this content is next, used in matching phase */ -#define DETECT_CONTENT_RELATIVE_NEXT 0x40 +#define DETECT_CONTENT_RELATIVE_NEXT 0x0400 #define DETECT_CONTENT_IS_SINGLE(c) (!((c)->flags & DETECT_CONTENT_DISTANCE || \ (c)->flags & DETECT_CONTENT_WITHIN || \ @@ -49,7 +53,7 @@ typedef struct DetectContentData_ { uint8_t *content; /**< ptr to chunk of memory containing the pattern */ uint8_t content_len;/**< length of the pattern (and size of the memory) */ - uint8_t flags; + uint16_t flags; PatIntId id; /**< unique pattern id */ uint16_t depth; uint16_t offset; @@ -58,7 +62,13 @@ typedef struct DetectContentData_ { int32_t distance; int32_t within; BmCtx *bm_ctx; /**< Boyer Moore context (for spm search) */ - + /* if someone wants to add an extra var to this structutre of size 1 byte + * you can reduce the below var to uint8_t. No problemo */ + uint16_t avoid_double_check; + /* for chopped fast pattern, the offset */ + uint16_t fp_chop_offset; + /* for chopped fast pattern, the length */ + uint16_t fp_chop_len; } DetectContentData; /* prototypes */ diff --git a/src/detect-depth.c b/src/detect-depth.c index b967e28fdf..23955dc9da 100644 --- a/src/detect-depth.c +++ b/src/detect-depth.c @@ -55,6 +55,7 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths char *str = depthstr; char dubbed = 0; SigMatch *pm = NULL; + DetectContentData *cd = NULL; /* strip "'s */ if (depthstr[0] == '\"' && depthstr[strlen(depthstr)-1] == '\"') { @@ -115,13 +116,28 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths break; case DETECT_CONTENT: - { - DetectContentData *cd = (DetectContentData *)pm->ctx; + + cd = (DetectContentData *)pm->ctx; if (cd == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument"); if (dubbed) SCFree(str); return -1; } + + if (cd->flags & DETECT_CONTENT_NEGATED) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "negated keyword set along with a fast_pattern"); + goto error; + } + } else { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "keyword set along with a fast_pattern:only;"); + goto error; + } + } + cd->depth = (uint32_t)atoi(str); if (cd->depth < cd->content_len) { cd->depth = cd->content_len; @@ -130,8 +146,9 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths } /* Now update the real limit, as depth is relative to the offset */ cd->depth += cd->offset; - } - break; + cd->flags |= DETECT_CONTENT_DEPTH; + + break; default: SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "depth needs a preceeding " @@ -141,6 +158,12 @@ static int DetectDepthSetup (DetectEngineCtx *de_ctx, Signature *s, char *depths break; } - if (dubbed) SCFree(str); + if (dubbed) + SCFree(str); return 0; + +error: + if (dubbed) + SCFree(str); + return -1; } diff --git a/src/detect-distance.c b/src/detect-distance.c index 6b5cfb045e..8c40d99e5c 100644 --- a/src/detect-distance.c +++ b/src/detect-distance.c @@ -250,6 +250,20 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, goto error; } + if (cd->flags & DETECT_CONTENT_NEGATED) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "negated keyword set along with a fast_pattern"); + goto error; + } + } else { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "keyword set along with a fast_pattern:only;"); + goto error; + } + } + cd->distance = strtol(str, NULL, 10); cd->flags |= DETECT_CONTENT_DISTANCE; if (cd->flags & DETECT_CONTENT_WITHIN) { @@ -284,6 +298,14 @@ static int DetectDistanceSetup (DetectEngineCtx *de_ctx, Signature *s, } cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Previous keyword " + "has a fast_pattern:only; set. You can't " + "have relative keywords around a fast_pattern " + "only content"); + goto error; + } + break; case DETECT_PCRE: diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 922238d3be..d261d076ce 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -34,6 +34,7 @@ #include "detect-engine-siggroup.h" #include "detect-engine-mpm.h" #include "detect-engine-iponly.h" +#include "detect-parse.h" #include "util-mpm.h" #include "conf.h" @@ -729,16 +730,62 @@ static int PatternMatchPreprarePopulateMpm(DetectEngineCtx *de_ctx, SigGroupHead } } - /* add the content to the "packet" mpm */ - if (co->flags & DETECT_CONTENT_NOCASE) { - mpm_table[sgh->mpm_ctx->mpm_type].AddPatternNocase(sgh->mpm_ctx, - co->content, co->content_len, offset, depth, co->id, - s->num, flags); + if (co->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) { + /* add the content to the "packet" mpm */ + if (co->flags & DETECT_CONTENT_NOCASE) { + mpm_table[sgh->mpm_ctx->mpm_type]. + AddPatternNocase(sgh->mpm_ctx, + co->content + co->fp_chop_offset, + co->fp_chop_len, + 0, 0, co->id, s->num, flags); + } else { + mpm_table[sgh->mpm_ctx->mpm_type]. + AddPattern(sgh->mpm_ctx, + co->content + co->fp_chop_offset, + co->fp_chop_len, + 0, 0, co->id, s->num, flags); + } } else { - mpm_table[sgh->mpm_ctx->mpm_type].AddPattern(sgh->mpm_ctx, - co->content, co->content_len, offset, depth, co->id, - s->num, flags); - } + if (co->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + co->avoid_double_check = 1; + } else { + if (!(co->flags & DETECT_CONTENT_RELATIVE_NEXT)) { + SigMatch *tmp_sm = s->pmatch; + for ( ; tmp_sm != NULL; tmp_sm = tmp_sm->next) { + if (tmp_sm->type != DETECT_CONTENT) + continue; + + DetectContentData *tmp_co = (DetectContentData *)tmpsm->ctx; + if (tmp_co == NULL) + continue; + + if (co->id == tmp_co->id) + break; + } + + SigMatch *prev_sm = SigMatchGetLastSMFromLists(s, 2, + DETECT_CONTENT, tmp_sm->prev); + if (prev_sm != NULL) { + DetectContentData *prev_co = (DetectContentData *)prev_sm->ctx; + if (!(prev_co->flags & DETECT_CONTENT_RELATIVE_NEXT)) + co->avoid_double_check = 1; + } + } + } /* else - if (co->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) */ + + /* add the content to the "packet" mpm */ + if (co->flags & DETECT_CONTENT_NOCASE) { + mpm_table[sgh->mpm_ctx->mpm_type]. + AddPatternNocase(sgh->mpm_ctx, + co->content, co->content_len, + offset, depth, co->id, s->num, flags); + } else { + mpm_table[sgh->mpm_ctx->mpm_type]. + AddPattern(sgh->mpm_ctx, + co->content, co->content_len, + offset, depth, co->id, s->num, flags); + } + } /* else - if (co->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) */ /* tell matcher we are inspecting packet */ s->flags |= SIG_FLAG_MPM_PACKET; diff --git a/src/detect-engine-payload.c b/src/detect-engine-payload.c index fade78a0cf..c4e247e52a 100644 --- a/src/detect-engine-payload.c +++ b/src/detect-engine-payload.c @@ -81,10 +81,15 @@ static int DoInspectPacketPayload(DetectEngineCtx *de_ctx, switch(sm->type) { case DETECT_CONTENT: { - DetectContentData *cd = NULL; - cd = (DetectContentData *)sm->ctx; + DetectContentData *cd = (DetectContentData *)sm->ctx; SCLogDebug("inspecting content %"PRIu32" payload_len %"PRIu32, cd->id, payload_len); + /* we might have already have this content matched by the mpm. + * (if there is any other reason why we'd want to avoid checking + * it here, please fill it in) */ + if (cd->avoid_double_check) + goto match; + /* rule parsers should take care of this */ BUG_ON(cd->depth != 0 && cd->depth <= cd->offset); diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c index 4132d16af3..7cc690ece2 100644 --- a/src/detect-fast-pattern.c +++ b/src/detect-fast-pattern.c @@ -37,6 +37,11 @@ #include "util-unittest.h" #include "util-unittest-helper.h" +#define DETECT_FAST_PATTERN_REGEX "^(\\s*only\\s*)|\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*$" + +static pcre *parse_regex = NULL; +static pcre_extra *parse_regex_study = NULL; + static int DetectFastPatternSetup(DetectEngineCtx *, Signature *, char *); void DetectFastPatternRegisterTests(void); @@ -52,32 +57,58 @@ void DetectFastPatternRegister(void) sigmatch_table[DETECT_FAST_PATTERN].RegisterTests = DetectFastPatternRegisterTests; sigmatch_table[DETECT_FAST_PATTERN].flags |= SIGMATCH_PAYLOAD; + + const char *eb; + int eo; + int opts = 0; + + parse_regex = pcre_compile(DETECT_FAST_PATTERN_REGEX, opts, &eb, &eo, NULL); + if(parse_regex == NULL) + { + SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at " + "offset %" PRId32 ": %s", DETECT_FAST_PATTERN_REGEX, eo, eb); + goto error; + } + + parse_regex_study = pcre_study(parse_regex, 0, &eb); + if(eb != NULL) + { + SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); + goto error; + } + + return; + + error: + /* get some way to return an error code! */ + return; } +//static int DetectFastPatternParseArg( + /** * \brief Configures the previous content context for a fast_pattern modifier - * keyword used in the rule + * keyword used in the rule. * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param m Pointer to the SigMatch - * \param null_str Should hold an empty string always + * \param de_ctx Pointer to the Detection Engine Context. + * \param s Pointer to the Signature to which the current keyword belongs. + * \param m Pointer to the SigMatch. + * \param null_str Should hold an empty string always. * - * \retval 0 On success - * \retval -1 On failure + * \retval 0 On success. + * \retval -1 On failure. */ -static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *null_str) +static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) { - if (null_str != NULL && strcmp(null_str, "") != 0) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "DetectFastPatternSetup: fast_pattern " - "shouldn't be supplied with a value"); - return -1; - } +#define MAX_SUBSTRINGS 30 + int ret = 0, res = 0; + int ov[MAX_SUBSTRINGS]; + const char *arg_substr = NULL; if (s->pmatch_tail == NULL) { - SCLogWarning(SC_WARN_COMPATIBILITY, " a fast_pattern found inside the " - "rule, is not preceding a keyword that support (currently)" - " this optimization. At least, the engine support " + SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the " + "rule, without a preceding keyword that supports (currently) " + "this optimization. At least, the engine support " "fast_pattern for content (not for uricontent yet). " "The signature is being loaded anyway ==> %s", s->sig_str); @@ -87,14 +118,110 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *n SigMatch *pm = DetectContentGetLastPattern(s->pmatch_tail); if (pm == NULL) { SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside " - "the rule, without a content context. Please use a " - "content keyword before using fast pattern"); + "the rule, without a content context. Please use a " + "content keyword before using fast_pattern"); return -1; } + if (arg == NULL|| strcmp(arg, "") == 0) { + ((DetectContentData *)pm->ctx)->flags |= DETECT_CONTENT_FAST_PATTERN; + return 0; + } + + DetectContentData *cd = pm->ctx; + if (cd->flags & DETECT_CONTENT_NEGATED && + (cd->flags & DETECT_CONTENT_DISTANCE || + cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_OFFSET || + cd->flags & DETECT_CONTENT_DEPTH)) { + /* we can't have any of these if we are having "only" */ + SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern; cannot be " + "used with negated content, along with relative modifiers."); + goto error; + } + + + /* Execute the regex and populate args with captures. */ + ret = pcre_exec(parse_regex, parse_regex_study, arg, + strlen(arg), 0, 0, ov, MAX_SUBSTRINGS); + if (ret == 2) { + if (cd->flags & DETECT_CONTENT_NEGATED || + cd->flags & DETECT_CONTENT_DISTANCE || + cd->flags & DETECT_CONTENT_WITHIN || + cd->flags & DETECT_CONTENT_OFFSET || + cd->flags & DETECT_CONTENT_DEPTH) { + /* we can't have any of these if we are having "only" */ + SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern: only; cannot be " + "used with negated content"); + goto error; + } + + cd->flags |= DETECT_CONTENT_FAST_PATTERN_ONLY; + } else if (ret == 4) { + res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, + 2, &arg_substr); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " + "for fast_pattern offset"); + goto error; + } + int offset = atoi(arg_substr); + if (offset > 65535) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Fast pattern offset exceeds " + "limit"); + goto error; + } + + res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, + 3, &arg_substr); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " + "for fast_pattern offset"); + goto error; + } + int length = atoi(arg_substr); + if (offset > 65535) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Fast pattern length exceeds " + "limit"); + goto error; + } + + if (offset + length > 65535) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Fast pattern (length + offset) " + "exceeds limit pattern length limit"); + goto error; + } + + cd->fp_chop_offset = offset; + cd->fp_chop_len = length; + + cd->flags |= DETECT_CONTENT_FAST_PATTERN_CHOP; + } else { + SCLogError(SC_ERR_PCRE_PARSE, "parse error, ret %" PRId32 + ", string %s", ret, arg); + goto error; + } + + //int args; + //args = 0; + //printf("ret-%d\n", ret); + //for (args = 0; args < ret; args++) { + // res = pcre_get_substring((char *)arg, ov, MAX_SUBSTRINGS, + // args, &arg_substr); + // if (res < 0) { + // SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed " + // "for arg 1"); + // goto error; + // } + // printf("%d-%s\n", args, arg_substr); + //} + ((DetectContentData *)pm->ctx)->flags |= DETECT_CONTENT_FAST_PATTERN; return 0; + + error: + return -1; } /*----------------------------------Unittests---------------------------------*/ @@ -798,26 +925,1151 @@ end: #endif -void DetectFastPatternRegisterTests(void) +/** + * \test Checks if a fast_pattern is registered in a Signature + */ +int DetectFastPatternTest15(void) { + SigMatch *sm = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; -#ifdef UNITTESTS + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; - UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01, 1); - UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02, 1); - UtRegisterTest("DetectFastPatternTest03", DetectFastPatternTest03, 1); - UtRegisterTest("DetectFastPatternTest04", DetectFastPatternTest04, 1); - UtRegisterTest("DetectFastPatternTest05", DetectFastPatternTest05, 1); - UtRegisterTest("DetectFastPatternTest06", DetectFastPatternTest06, 1); - UtRegisterTest("DetectFastPatternTest07", DetectFastPatternTest07, 1); - UtRegisterTest("DetectFastPatternTest08", DetectFastPatternTest08, 1); - UtRegisterTest("DetectFastPatternTest09", DetectFastPatternTest09, 1); - UtRegisterTest("DetectFastPatternTest10", DetectFastPatternTest10, 1); - UtRegisterTest("DetectFastPatternTest11", DetectFastPatternTest11, 1); - UtRegisterTest("DetectFastPatternTest12", DetectFastPatternTest12, 1); - UtRegisterTest("DetectFastPatternTest13", DetectFastPatternTest13, 1); - UtRegisterTest("DetectFastPatternTest14", DetectFastPatternTest14, 1); + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:\"/one/\"; fast_pattern:only; " + "msg:\"Testing fast_pattern\"; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + result = 0; + sm = de_ctx->sig_list->pmatch; + while (sm != NULL) { + if (sm->type == DETECT_CONTENT) { + if ( ((DetectContentData *)sm->ctx)->flags & + DETECT_CONTENT_FAST_PATTERN) { + result = 1; + break; + } else { + result = 0; + break; + } + } + sm = sm->next; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +/** + * \test Checks if a fast_pattern is registered in a Signature + */ +int DetectFastPatternTest16(void) +{ + SigMatch *sm = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:\"/one/\"; fast_pattern:3,4; " + "msg:\"Testing fast_pattern\"; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + result = 0; + sm = de_ctx->sig_list->pmatch; + while (sm != NULL) { + if (sm->type == DETECT_CONTENT) { + if ( ((DetectContentData *)sm->ctx)->flags & + DETECT_CONTENT_FAST_PATTERN) { + result = 1; + break; + } else { + result = 0; + break; + } + } + sm = sm->next; + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest17(void) +{ + SigMatch *sm = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; fast_pattern:only; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + result = 0; + sm = de_ctx->sig_list->pmatch; + DetectContentData *cd = sm->ctx; + if (sm != NULL && sm->type == DETECT_CONTENT) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && + !(cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && + cd->fp_chop_offset == 0 && + cd->fp_chop_len == 0) { + result = 1; + } else { + result = 0; + } + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest18(void) +{ + SigMatch *sm = NULL; + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; fast_pattern:3,4; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + result = 0; + sm = de_ctx->sig_list->pmatch; + DetectContentData *cd = sm->ctx; + if (sm != NULL && sm->type == DETECT_CONTENT) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + cd->fp_chop_offset == 3 && + cd->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + } + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest19(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; fast_pattern:only; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest20(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; distance:10; fast_pattern:only; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest21(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; fast_pattern:only; within:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest22(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; within:10; fast_pattern:only; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest23(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; fast_pattern:only; offset:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest24(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; offset:10; fast_pattern:only; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest25(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; fast_pattern:only; depth:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest26(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; depth:10; fast_pattern:only; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest27(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:!two; fast_pattern:only; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest28(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content: one; content:two; distance:30; content:two; fast_pattern:only; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->prev->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && + !(cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && + cd->fp_chop_offset == 0 && + cd->fp_chop_len == 0) { + result = 1; + } else { + result = 0; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest29(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; within:30; content:two; fast_pattern:only; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->prev->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && + !(cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && + cd->fp_chop_offset == 0 && + cd->fp_chop_len == 0) { + result = 1; + } else { + result = 0; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest30(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; offset:30; content:two; fast_pattern:only; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->prev->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && + !(cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && + cd->fp_chop_offset == 0 && + cd->fp_chop_len == 0) { + result = 1; + } else { + result = 0; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest31(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; depth:30; content:two; fast_pattern:only; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->prev->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY && + !(cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && + cd->fp_chop_offset == 0 && + cd->fp_chop_len == 0) { + result = 1; + } else { + result = 0; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest32(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:!one; fast_pattern; content:two; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->prev->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + cd->flags & DETECT_CONTENT_NEGATED && + !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + !(cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) && + cd->fp_chop_offset == 0 && + cd->fp_chop_len == 0) { + result = 1; + } else { + result = 0; + } + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest33(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:two; content:!one; fast_pattern; distance:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest34(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:two; content:!one; fast_pattern; within:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest35(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:two; content:!one; fast_pattern; offset:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest36(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:two; content:!one; fast_pattern; depth:20; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest37(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; fast_pattern:3,4; content:three; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->prev->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + cd->fp_chop_offset == 3 && + cd->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest38(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; fast_pattern:3,4; content:three; distance:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->prev->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + cd->fp_chop_offset == 3 && + cd->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest39(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; fast_pattern:3,4; content:three; within:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->prev->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + cd->fp_chop_offset == 3 && + cd->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest40(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; fast_pattern:3,4; content:three; offset:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->prev->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + cd->fp_chop_offset == 3 && + cd->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest41(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; fast_pattern:3,4; content:three; depth:30; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->prev->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + cd->fp_chop_offset == 3 && + cd->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest42(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; distance:10; content:three; fast_pattern:3,4; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + cd->fp_chop_offset == 3 && + cd->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest43(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; within:10; content:three; fast_pattern:3,4; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + cd->fp_chop_offset == 3 && + cd->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest44(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; offset:10; content:three; fast_pattern:3,4; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + cd->fp_chop_offset == 3 && + cd->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest45(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; depth:10; content:three; fast_pattern:3,4; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + cd->fp_chop_offset == 3 && + cd->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest46(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; fast_pattern:65977,4; content:three; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest47(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; fast_pattern:3,65977; content:three; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest48(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:two; fast_pattern:65534,4; content:three; distance:10; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest49(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:!two; fast_pattern:3,4; content:three; sid:1;)"); + if (de_ctx->sig_list == NULL) + goto end; + DetectContentData *cd = de_ctx->sig_list->pmatch_tail->prev->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN && + cd->flags & DETECT_CONTENT_NEGATED && + !(cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) && + cd->flags & cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP && + cd->fp_chop_offset == 3 && + cd->fp_chop_len == 4) { + result = 1; + } else { + result = 0; + } + + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest50(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:!two; fast_pattern:3,4; distance:10; content:three; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest51(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:!two; fast_pattern:3,4; within:10; content:three; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest52(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:!two; fast_pattern:3,4; offset:10; content:three; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +int DetectFastPatternTest53(void) +{ + DetectEngineCtx *de_ctx = NULL; + int result = 0; + + if ( (de_ctx = DetectEngineCtxInit()) == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " + "(content:one; content:!two; fast_pattern:3,4; depth:10; content:three; sid:1;)"); + if (de_ctx->sig_list != NULL) + goto end; + + result = 1; + + end: + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +void DetectFastPatternRegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01, 1); + UtRegisterTest("DetectFastPatternTest02", DetectFastPatternTest02, 1); + UtRegisterTest("DetectFastPatternTest03", DetectFastPatternTest03, 1); + UtRegisterTest("DetectFastPatternTest04", DetectFastPatternTest04, 1); + UtRegisterTest("DetectFastPatternTest05", DetectFastPatternTest05, 1); + UtRegisterTest("DetectFastPatternTest06", DetectFastPatternTest06, 1); + UtRegisterTest("DetectFastPatternTest07", DetectFastPatternTest07, 1); + UtRegisterTest("DetectFastPatternTest08", DetectFastPatternTest08, 1); + UtRegisterTest("DetectFastPatternTest09", DetectFastPatternTest09, 1); + UtRegisterTest("DetectFastPatternTest10", DetectFastPatternTest10, 1); + UtRegisterTest("DetectFastPatternTest11", DetectFastPatternTest11, 1); + UtRegisterTest("DetectFastPatternTest12", DetectFastPatternTest12, 1); + UtRegisterTest("DetectFastPatternTest13", DetectFastPatternTest13, 1); + UtRegisterTest("DetectFastPatternTest14", DetectFastPatternTest14, 1); + UtRegisterTest("DetectFastPatternTest15", DetectFastPatternTest15, 1); + UtRegisterTest("DetectFastPatternTest16", DetectFastPatternTest16, 1); + UtRegisterTest("DetectFastPatternTest17", DetectFastPatternTest17, 1); + UtRegisterTest("DetectFastPatternTest18", DetectFastPatternTest18, 1); + UtRegisterTest("DetectFastPatternTest19", DetectFastPatternTest19, 1); + UtRegisterTest("DetectFastPatternTest20", DetectFastPatternTest20, 1); + UtRegisterTest("DetectFastPatternTest21", DetectFastPatternTest21, 1); + UtRegisterTest("DetectFastPatternTest22", DetectFastPatternTest22, 1); + UtRegisterTest("DetectFastPatternTest23", DetectFastPatternTest23, 1); + UtRegisterTest("DetectFastPatternTest24", DetectFastPatternTest24, 1); + UtRegisterTest("DetectFastPatternTest25", DetectFastPatternTest25, 1); + UtRegisterTest("DetectFastPatternTest26", DetectFastPatternTest26, 1); + UtRegisterTest("DetectFastPatternTest27", DetectFastPatternTest27, 1); + UtRegisterTest("DetectFastPatternTest28", DetectFastPatternTest28, 1); + UtRegisterTest("DetectFastPatternTest29", DetectFastPatternTest29, 1); + UtRegisterTest("DetectFastPatternTest30", DetectFastPatternTest30, 1); + UtRegisterTest("DetectFastPatternTest31", DetectFastPatternTest31, 1); + UtRegisterTest("DetectFastPatternTest32", DetectFastPatternTest32, 1); + UtRegisterTest("DetectFastPatternTest33", DetectFastPatternTest33, 1); + UtRegisterTest("DetectFastPatternTest34", DetectFastPatternTest34, 1); + UtRegisterTest("DetectFastPatternTest35", DetectFastPatternTest35, 1); + UtRegisterTest("DetectFastPatternTest36", DetectFastPatternTest36, 1); + UtRegisterTest("DetectFastPatternTest37", DetectFastPatternTest37, 1); + UtRegisterTest("DetectFastPatternTest38", DetectFastPatternTest38, 1); + UtRegisterTest("DetectFastPatternTest39", DetectFastPatternTest39, 1); + UtRegisterTest("DetectFastPatternTest40", DetectFastPatternTest40, 1); + UtRegisterTest("DetectFastPatternTest41", DetectFastPatternTest41, 1); + UtRegisterTest("DetectFastPatternTest42", DetectFastPatternTest42, 1); + UtRegisterTest("DetectFastPatternTest43", DetectFastPatternTest43, 1); + UtRegisterTest("DetectFastPatternTest44", DetectFastPatternTest44, 1); + UtRegisterTest("DetectFastPatternTest45", DetectFastPatternTest45, 1); + UtRegisterTest("DetectFastPatternTest46", DetectFastPatternTest46, 1); + UtRegisterTest("DetectFastPatternTest47", DetectFastPatternTest47, 1); + UtRegisterTest("DetectFastPatternTest48", DetectFastPatternTest48, 1); + UtRegisterTest("DetectFastPatternTest49", DetectFastPatternTest49, 1); + UtRegisterTest("DetectFastPatternTest50", DetectFastPatternTest50, 1); + UtRegisterTest("DetectFastPatternTest51", DetectFastPatternTest51, 1); + UtRegisterTest("DetectFastPatternTest52", DetectFastPatternTest52, 1); + UtRegisterTest("DetectFastPatternTest53", DetectFastPatternTest53, 1); #endif + return; } diff --git a/src/detect-offset.c b/src/detect-offset.c index ab20207a1a..f41c33ada0 100644 --- a/src/detect-offset.c +++ b/src/detect-offset.c @@ -122,6 +122,21 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) if (dubbed) SCFree(str); return -1; } + + if (cd->flags & DETECT_CONTENT_NEGATED) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "negated keyword set along with a fast_pattern"); + goto error; + } + } else { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "keyword set along with a fast_pattern:only;"); + goto error; + } + } + cd->offset = (uint32_t)atoi(str); if (cd->depth != 0) { if (cd->depth < cd->content_len) { @@ -132,6 +147,9 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) /* Updating the depth as is relative to the offset */ cd->depth += cd->offset; } + + cd->flags |= DETECT_CONTENT_OFFSET; + break; default: @@ -146,5 +164,10 @@ int DetectOffsetSetup (DetectEngineCtx *de_ctx, Signature *s, char *offsetstr) if (dubbed) SCFree(str); return 0; + +error: + if (dubbed) + SCFree(str); + return -1; } diff --git a/src/detect-uricontent.c b/src/detect-uricontent.c index 60ee2eb658..8b4d0a4150 100644 --- a/src/detect-uricontent.c +++ b/src/detect-uricontent.c @@ -1196,7 +1196,7 @@ static int DetectUriSigTest04(void) { s->pmatch == NULL || ((DetectContentData*) s->pmatch->ctx)->depth != 15 || ((DetectContentData*) s->pmatch->ctx)->offset != 5 || - ((DetectContentData*) s->umatch_tail->ctx)->distance != 30 || + ((DetectUricontentData*) s->umatch_tail->ctx)->distance != 30 || s->match != NULL) { printf("sig 10 failed to parse: "); diff --git a/src/detect-within.c b/src/detect-within.c index ec6b7d6caa..81ea4b7e71 100644 --- a/src/detect-within.c +++ b/src/detect-within.c @@ -261,6 +261,20 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi goto error; } + if (cd->flags & DETECT_CONTENT_NEGATED) { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "negated keyword set along with a fast_pattern"); + goto error; + } + } else { + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "You can't have a relative " + "keyword set along with a fast_pattern:only;"); + goto error; + } + } + cd->within = strtol(str, NULL, 10); if (cd->within < (int32_t)cd->content_len) { SCLogError(SC_ERR_WITHIN_INVALID, "within argument \"%"PRIi32"\" is " @@ -304,6 +318,14 @@ static int DetectWithinSetup (DetectEngineCtx *de_ctx, Signature *s, char *withi } cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "Previous keyword " + "has a fast_pattern:only; set. You can't " + "have relative keywords around a fast_pattern " + "only content"); + goto error; + } + break; case DETECT_PCRE: diff --git a/src/detect.c b/src/detect.c index 409a73179d..f07fc7ba7c 100644 --- a/src/detect.c +++ b/src/detect.c @@ -151,6 +151,10 @@ extern uint8_t engine_mode; +extern int engine_analysis; +static int fp_engine_analysis_set = 0; +static FILE *fp_engine_analysis_FD = NULL; + SigMatch *SigMatchAlloc(void); void DetectExitPrintStats(ThreadVars *tv, void *data); @@ -243,6 +247,90 @@ 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) +{ + 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->pmatch; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT) + continue; + + cd = (DetectContentData *)sm->ctx; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { + fast_pattern_set = 1; + if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) { + fast_pattern_only_set = 1; + } else if (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) { + 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: 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"); + + uint8_t *pat = malloc(fp_cd->content_len + 1); + if (pat == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + exit(EXIT_FAILURE); + } + memcpy(pat, cd->content, cd->content_len); + pat[cd->content_len] = '\0'; + fprintf(fp_engine_analysis_FD, " Original content: %s\n", pat); + + if (fast_pattern_chop_set) { + uint8_t *pat = malloc(fp_cd->fp_chop_len + 1); + if (pat == NULL) { + 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); + pat[fp_cd->fp_chop_len] = '\0'; + fprintf(fp_engine_analysis_FD, " Final content: %s\n", pat); + } else { + fprintf(fp_engine_analysis_FD, " Final content: %s\n", pat); + } + + return; +} + /** * \brief Load a file with signatures * \param de_ctx Pointer to the detection engine context @@ -302,6 +390,9 @@ 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); + } SCLogDebug("signature %"PRIu32" loaded", sig->id); good++; } else { @@ -338,6 +429,40 @@ int SigLoadSignatures (DetectEngineCtx *de_ctx, char *sig_file) int sigtotal = 0; char *sfile = NULL; + if (engine_analysis) { + if ((ConfGetBool("engine-analysis.rules-fast-pattern", + &fp_engine_analysis_set)) == 0) { + fp_engine_analysis_set = 0; + } + + if (fp_engine_analysis_set) { + char log_path[256], *log_dir; + if (ConfGet("default-log-dir", &log_dir) != 1) + log_dir = DEFAULT_LOG_DIR; + snprintf(log_path, 256, "%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, "ERROR: 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 *)localtime_r(&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"); + } + } + /* ok, let's load signature files from the general config */ rule_files = ConfGetNode("rule-files"); if (rule_files != NULL) { @@ -418,6 +543,15 @@ int SigLoadSignatures (DetectEngineCtx *de_ctx, char *sig_file) ret = 0; end: + if (engine_analysis) { + if (fp_engine_analysis_set) { + if (fp_engine_analysis_FD != NULL) { + fclose(fp_engine_analysis_FD); + fp_engine_analysis_FD = NULL; + } + } + } + DetectParseDupSigHashFree(de_ctx); SCReturnInt(ret); } diff --git a/src/suricata.c b/src/suricata.c index 0dbce74adc..8f793d85e7 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -170,6 +170,10 @@ uint8_t suricata_ctl_flags = 0; /** Run mode selected */ int run_mode = MODE_UNKNOWN; +/** engine_analysis. disabled(0) by default, unless enabled by the user by + * running the engine with --engine-analysis */ +int engine_analysis = 0; + /** Engine mode: inline (ENGINE_MODE_IPS) or just * detection mode (ENGINE_MODE_IDS by default) */ uint8_t engine_mode = ENGINE_MODE_IDS; @@ -330,6 +334,12 @@ void usage(const char *progname) printf("\t--list-unittests : list unit tests\n"); printf("\t--fatal-unittests : enable fatal failure on unittest error\n"); #endif /* UNITTESTS */ +#ifdef __SC_CUDA_SUPPORT__ + printf("\t--list-cuda-cards : list cuda supported cards\n"); +#endif + printf("\t--engine-analysis : print reports on analysis of different sections in the engine and exit.\n" + "\t Please have a look at the conf parameter engine-analysis on what reports\n" + "\t can be printed\n"); printf("\t--pidfile : write pid to this file (only for daemon mode)\n"); printf("\t--init-errors-fatal : enable fatal failure on signature init error\n"); printf("\t--dump-config : show the running configuration\n"); @@ -436,6 +446,7 @@ int main(int argc, char **argv) {"unittest-filter", required_argument, 0, 'U'}, {"list-unittests", 0, &list_unittests, 1}, {"list-cuda-cards", 0, &list_cuda_cards, 1}, + {"engine-analysis", 0, &engine_analysis, 1}, #ifdef OS_WIN32 {"service-install", 0, 0, 0}, {"service-remove", 0, 0, 0}, @@ -513,6 +524,8 @@ int main(int argc, char **argv) "--enable-cuda to configure when building.\n"); exit(EXIT_FAILURE); #endif /* UNITTESTS */ + } else if(strcmp((long_opts[option_index]).name, "engine-analysis") == 0) { + printf("==Carrying out engine analyis==\n"); } #ifdef OS_WIN32 else if(strcmp((long_opts[option_index]).name, "service-install") == 0) { @@ -778,8 +791,10 @@ int main(int argc, char **argv) SCHInfoLoadFromConfig(); if (run_mode == MODE_UNKNOWN) { - usage(argv[0]); - exit(EXIT_FAILURE); + if (!engine_analysis) { + usage(argv[0]); + exit(EXIT_FAILURE); + } } /* create table for O(1) lowercase conversion lookup */ @@ -1046,6 +1061,9 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + if (engine_analysis) { + exit(EXIT_SUCCESS); + } #ifdef PROFILING SCProfilingInitRuleCounters(de_ctx); diff --git a/suricata.yaml b/suricata.yaml index 46aac3209c..c9f3fcccf1 100644 --- a/suricata.yaml +++ b/suricata.yaml @@ -78,6 +78,15 @@ defrag: prealloc: yes timeout: 60 +# When run with the option --engine-analysis, the engine will read each of +# the parameters below, and print reports for each of the enabled sections +# and exit. The reports are printed to a file in the default log dir +# given by the parameter "default-log-dir", with engine reporting +# subsection below printing reports in its own report file. +engine-analysis: + # enables printing reports for fast-pattern for every rule. + rules-fast-pattern: yes + # You can specify a threshold config file by setting "threshold-file" # to the path of the threshold config file: # threshold-file: /etc/suricata/threshold.config