Support for negated content

remotes/origin/master-1.0.x
Anoop Saldanha 16 years ago committed by Victor Julien
parent 6346d1ddcf
commit 1c7ac13c25

@ -103,23 +103,53 @@ static void DetectContentPrintMatches(DetectEngineThreadCtx *det_ctx, DetectCont
static inline int static inline int
TestOffsetDepth(MpmMatch *m, DetectContentData *co, uint16_t pktoff) { TestOffsetDepth(MpmMatch *m, DetectContentData *co, uint16_t pktoff) {
if (m->offset >= pktoff) { if (m->offset >= pktoff) {
if (co->offset == 0 || if (co->offset == 0 || (m->offset >= co->offset)) {
(co->offset && m->offset >= co->offset)) { if (co->depth == 0 || ((m->offset + co->content_len) <= co->depth)) {
if (co->depth == 0 || SCLogDebug("depth %" PRIu32 ", offset %" PRIu32 ", m->offset "
(co->depth && (m->offset+co->content_len) <= co->depth)) "%" PRIu32 ", return 1", co->depth, co->offset,
{ m->offset);
SCLogDebug("depth %" PRIu32 ", offset %" PRIu32 ", m->offset %" PRIu32 ", return 1",
co->depth, co->offset, m->offset); /* If we reach this point, it means we have obtained a depth and
return 1; * offset match, which indicates that we have a FAILURE if the
* content is negated, and SUCCESS if the content is not negated */
if (co->negated == 1)
return 0;
else
return 1;
} else {
/* We have success so far with offset, but a failure with
* depth. We can return a match at the bottom of this function
* for negated_content, provided offset is 0. If offset
* isn't 0 for negated_content, we have a failure and we return
* a no match here. If the content is not negated, we have a no
* match, which we return at the end of this function. */
if (co->offset && co->negated == 1)
return 0;
}
} else {
/* If offset fails, and if the content is negated, we check if depth
* succeeds. If it succeeds, we have a no match for negated content.
* Else we have a success for negated content. If the content is
* not negated, we go down till the end and return a no match. */
if (co->negated == 1 &&
(co->depth && (m->offset+co->content_len) <= co->depth)) {
return 0;
} }
} }
} }
SCLogDebug("depth %" PRIu32 ", offset %" PRIu32 ", m->offset %" PRIu32 ", return 0", SCLogDebug("depth %" PRIu32 ", offset %" PRIu32 ", m->offset %" PRIu32 ", "
co->depth, co->offset, m->offset); "return 0", co->depth, co->offset, m->offset);
return 0;
/* If we reach this point, we have a match for negated content and no match
* otherwise */
if (co->negated == 1)
return 1;
else
return 0;
} }
/** \brief test the within, distance, offset and depth of a match /**
* \brief test the within, distance, offset and depth of a match
* *
* This function is called recursively (if nescessary) to be able * This function is called recursively (if nescessary) to be able
* to determine whether or not a chain of content matches connected * to determine whether or not a chain of content matches connected
@ -145,16 +175,24 @@ TestOffsetDepth(MpmMatch *m, DetectContentData *co, uint16_t pktoff) {
* before that point + the lenght of the pattern we're checking, * before that point + the lenght of the pattern we're checking,
* nco->content_len. * nco->content_len.
* *
* \param t thread vars * \param t thread vars
* \param det_ctx thread local data of the detection engine ctx * \param det_ctx thread local data of the detection engine ctx
* \param m match we are inspecting * \param m match we are inspecting
* \param nm current sigmatch to work with * \param nm current sigmatch to work with
* \param nsm next sigmatch to work with * \param nsm next sigmatch to work with
* \param pktoff packet offset * \param pktoff packet offset
*
* \retval 1 On success.
* \retval 0 On failure because of non-negated content.
* \retval -1 On failure because of negated content.
*/ */
static inline int int TestWithinDistanceOffsetDepth(ThreadVars *t,
TestWithinDistanceOffsetDepth(ThreadVars *t, DetectEngineThreadCtx *det_ctx, MpmMatch *m, SigMatch *sm, SigMatch *nsm, uint16_t pktoff) DetectEngineThreadCtx *det_ctx,
MpmMatch *m, SigMatch *sm,
SigMatch *nsm, uint16_t pktoff)
{ {
int neg_success_flag = 0;
if (nsm == NULL) { if (nsm == NULL) {
SCLogDebug("No next sigmatch, all sigmatches matched."); SCLogDebug("No next sigmatch, all sigmatches matched.");
return 1; return 1;
@ -178,62 +216,155 @@ TestWithinDistanceOffsetDepth(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Mpm
/** list of matches of the next pattern */ /** list of matches of the next pattern */
MpmMatch *nm = det_ctx->mtc.match[nco->id].top; MpmMatch *nm = det_ctx->mtc.match[nco->id].top;
/* if we have no matches and the content is negated, we can return a success */
if (nm == NULL && nco->negated == 1)
return 1;
/* recursively check if we have a next pattern that matches */ /* recursively check if we have a next pattern that matches */
for (; nm; nm = nm->next) { for ( ; nm != NULL; nm = nm->next) {
SCLogDebug("nm->offset %" PRIu32 ", m->offset %" PRIu32 ", pktoff %" PRIu32 "", nm->offset, m->offset, pktoff); SCLogDebug("nm->offset %" PRIu32 ", m->offset %" PRIu32 ", pktoff "
SCLogDebug("nm->offset + nco->content_len = %"PRIu32" + %"PRIu32" = %"PRIu32"", "%" PRIu32 "", nm->offset, m->offset, pktoff);
nm->offset, nco->content_len, nm->offset + nco->content_len); SCLogDebug("nm->offset + nco->content_len = %"PRIu32" + %"PRIu32" = "
SCLogDebug("within (0 if disabled) = %"PRIu32" (nco->within %"PRIu32" + co->content_len %"PRIu32")", "%"PRIu32"", nm->offset, nco->content_len,
nco->flags & DETECT_CONTENT_WITHIN ? (nco->within + co->content_len) : 0, nco->within, co->content_len); nm->offset + nco->content_len);
SCLogDebug("within (0 if disabled) = %"PRIu32" (nco->within "
"%"PRIu32" + co->content_len %"PRIu32")",
(nco->flags & DETECT_CONTENT_WITHIN) ?
(nco->within + co->content_len) : 0, nco->within,
co->content_len);
if (nm->offset >= pktoff) { if (nm->offset >= pktoff) {
if ((!(nco->flags & DETECT_CONTENT_WITHIN) || if ((!(nco->flags & DETECT_CONTENT_WITHIN) ||
(nco->within > 0 && (nm->offset > m->offset) && (nco->within > 0 && (nm->offset > m->offset) &&
(((nm->offset + nco->content_len) - m->offset) <= (nco->within + co->content_len))))) (((nm->offset + nco->content_len) - m->offset) <= (nco->within + co->content_len))))) {
{
SCLogDebug("MATCH: %" PRIu32 " <= WITHIN(%" PRIu32 ")", SCLogDebug("MATCH: %" PRIu32 " <= WITHIN(%" PRIu32 ")",
(nm->offset + nco->content_len) - m->offset, (nm->offset + nco->content_len) - m->offset,
nco->within + co->content_len); nco->within + co->content_len);
if (!(nco->flags & DETECT_CONTENT_DISTANCE) || if (!(nco->flags & DETECT_CONTENT_DISTANCE) ||
((nm->offset >= (m->offset + co->content_len)) && ((nm->offset >= (m->offset + co->content_len)) &&
((nm->offset - (m->offset + co->content_len)) >= nco->distance))) ((nm->offset - (m->offset + co->content_len)) >= nco->distance))) {
{
SCLogDebug("MATCH: %" PRIu32 " >= DISTANCE(%" PRIu32 ")", SCLogDebug("MATCH: %" PRIu32 " >= DISTANCE(%" PRIu32 ")",
nm->offset - (m->offset + co->content_len), nco->distance); nm->offset - (m->offset + co->content_len), nco->distance);
if (TestOffsetDepth(nm, nco, pktoff) == 1) { if (TestOffsetDepth(nm, nco, pktoff) == 0) {
SigMatch *real_nsm_next = DetectContentFindNextApplicableSM(nsm->next); /* if the content is not negated, we have to return a 0
return TestWithinDistanceOffsetDepth(t, det_ctx, nm, nsm, real_nsm_next, pktoff); * under all circumstances, because we can't afford for
* the offset and depth match to fail. If the content
* is negated, we have 2 cases. First case is when we
* have a distance or within and TestOffsetDepth() fails.
* In this case we have to return a 0, irrespective of
* whether we have a depth or offset, because we seem to
* be having a match for within or distance. If we don't
* have distance and within, and if the depth/offset
* check failed, then we still have a failure because of
* the obvious reason that in the absence of within and
* distance, offset/depth check has to succeed. */
if (nco->negated == 1)
return -1;
else
return 0;
} else {
/* if the content is negated and we had a within or a
* distance, it indicates that we passed through the
* within/distance, which is a failure */
if (nco->negated == 1 &&
((nco->flags & DETECT_CONTENT_WITHIN) ||
(nco->flags & DETECT_CONTENT_DISTANCE))) {
return -1;
} else {
return TestWithinDistanceOffsetDepth(t, det_ctx, nm,
nsm, nsm->next,
pktoff);
}
} }
} else { } else {
SCLogDebug("NO MATCH: %" PRIu32 " < DISTANCE(%" PRIu32 ")", SCLogDebug("NO MATCH: %" PRIu32 " < DISTANCE(%" PRIu32 ")",
nm->offset - (m->offset + co->content_len), nco->distance); nm->offset - (m->offset + co->content_len),
nco->distance);
/* looks like we got through within, but failed at distance.
* An obvious failure in case of non-negated content, in which
* case we move on to the next match.
* In case of negated content, if there was a within
* previously, it indicates that we got through the within
* and we have a nomatch now with distance. If we didn't
* have within, we made it through, but we check for depth
* and offset now. If depth/offset check succeeds we have a
* temporary success and we move on to the next match. If
* it fails, we check if it failed because we didn't have
* offset and depth, in which case, it is not a failure and
* we on to the nextmatch. Otherwise it is a failure */
if (nco->negated == 1 && (nm->offset >= (m->offset + co->content_len))) {
if (nco->flags & DETECT_CONTENT_WITHIN)
return -1;
if (TestOffsetDepth(nm, nco, pktoff) == 1) {
neg_success_flag = 1;
} else {
if (nco->offset == 0 && nco->depth == 0)
neg_success_flag = 1;
else
return -1;
}
}
} }
} else { } else {
if (nm->offset <= m->offset) { /* We have failed at within. If the content is not negated we
SCLogDebug("NO MATCH: nm->offset before or on m->offset: %"PRIu32" <= %"PRIu32"", * have an obvious failure and we move on to the next match. If
nm->offset, m->offset); * the content is negated, we check if distance exists. If it
} else { * does, and if the distance check succeeds, we have a failure
SCLogDebug("NO MATCH: %" PRIu32 " > WITHIN(%" PRIu32 ")", * for negated content. If we don't have a failure or if distance
(nm->offset + nco->content_len) - m->offset, * doesn't exist, we move on to test offset/depth check. The
(nco->within + co->content_len)); * offset/depth test is the same as in the previous else. */
if (nco->negated == 1 && nm->offset > m->offset) {
if ((nco->flags & DETECT_CONTENT_DISTANCE) &&
((nm->offset - (m->offset + co->content_len)) >= nco->distance)) {
return -1;
/* distance check meets non-negated requirements. Let
* us move on and check depth/offset */
}
if (TestOffsetDepth(nm, nco, pktoff) == 1) {
/* offset, depth success for negated content. A temp
* success for us. Let us set the flag indicating
* this and move on to the next match. */
neg_success_flag = 1;
} else {
/* looks like offset/depth failed. If it failed because
* both offset and depth weren't present, then it is not
* precisely a failure, because the existance of negated
* content is governed by the presence of within/distance.
* So we set the flag and move on to the next content.
* But if offset and depth do exist, then it indicates
* that the negated content doesn't meet the requirements
* of offset/depth and we have a failure. */
if (nco->offset == 0 && nco->depth == 0)
neg_success_flag = 1;
else
return -1;
}
} }
} }
} else { } else {
SCLogDebug("pktoff %"PRIu16" > nm->offset %"PRIu32"", pktoff, nm->offset); SCLogDebug("pktoff %"PRIu16" > nm->offset %"PRIu32"", pktoff, nm->offset);
} }
} }
if (neg_success_flag == 1) {
return 1;
}
SCLogDebug("no match found, returning 0"); SCLogDebug("no match found, returning 0");
return 0; return 0;
} }
static inline int int
DoDetectContent(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm, DetectContentData *co) DoDetectContent(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *sm, DetectContentData *co)
{ {
int ret = 0; int ret = 0;
char match = 0; char match = 0;
uint16_t pkt_off = det_ctx->pkt_off; uint16_t pkt_off = det_ctx->pkt_off;
MpmMatch *temp_m = NULL;
/* Get the top match, we already know we have one. */ /* Get the top match, we already know we have one. */
MpmMatch *m = det_ctx->mtc.match[co->id].top; MpmMatch *m = det_ctx->mtc.match[co->id].top;
@ -284,6 +415,8 @@ DoDetectContent(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signat
pkt_off = det_ctx->pkt_off = m->offset; pkt_off = det_ctx->pkt_off = m->offset;
match = 1; match = 1;
break; break;
} else if (ret == -1) {
break;
} }
} else { } else {
SCLogDebug("TestOffsetDepth returned 0, for co->id %"PRIu32"", co->id); SCLogDebug("TestOffsetDepth returned 0, for co->id %"PRIu32"", co->id);
@ -310,6 +443,17 @@ DoDetectContent(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signat
* settings. If so, return a match. * settings. If so, return a match.
*/ */
} else { } else {
/* if we have no matches, we return MATCH if the content is negated, or
* NOMATCH if the content is not negated */
if (m == NULL) {
if (co->negated == 1)
match = 1;
else
match = 0;
return match;
}
/* when in recursive capture mode don't check depth and offset /* when in recursive capture mode don't check depth and offset
* after the first match */ * after the first match */
if (s->flags & SIG_FLAG_RECURSIVE && det_ctx->pkt_cnt) { if (s->flags & SIG_FLAG_RECURSIVE && det_ctx->pkt_cnt) {
@ -324,31 +468,57 @@ DoDetectContent(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signat
} }
} }
} else { } else {
temp_m = m;
for (; m != NULL; m = m->next) { for (; m != NULL; m = m->next) {
ret = TestOffsetDepth(m,co, 0); /* no offset as we inspect each /* no offset as we inspect each match on it's own */
* match on it's own */ ret = TestOffsetDepth(m, co, 0);
if (ret == 1) {
/* update pkt ptrs, this content run doesn't /* If ret is 0 and content is negated, we have a failure and we
* use this, but pcre does */ * break. If ret is 0 and content is not negated, we have a
det_ctx->pkt_ptr = p->payload + m->offset; * failure for this match, so we will continue in this loop
det_ctx->pkt_off = m->offset; * testing other matches. If ret is 1, and the content is
match = 1; * negated we have a success and we will continue along the loop
break; * to check that other matches also return 1 for TestOffsetDepth()
* with the negated content. But if ret is 1, and the content
* is not negated, we have a match, which is sufficient for us to
* return with a break, with match = 1. */
if (ret == 0) {
if (co->negated == 1) {
match = 0;
break;
}
} else {
if (co->negated == 0) {
/* update pkt ptrs, this content run doesn't
* use this, but pcre does */
det_ctx->pkt_ptr = p->payload + m->offset;
det_ctx->pkt_off = m->offset;
match = 1;
break;
}
} }
} }
/* If there were matches, with the content being negated, and all of
* them passed TestOffsetDepth(), we have a match. This is the
* reason why we continue in the else part if ret == 1, if the
* content is negated */
if (temp_m != NULL && ret == 1 && co->negated == 1)
match = 1;
} }
} }
/* If it has matched, check if it's set a "isdataat" option and process it */ /* If it has matched, check if it's set a "isdataat" option and process it */
if (match == 1 && co->flags & DETECT_CONTENT_ISDATAAT_RELATIVE) /* If it has matched, check if it's set a "isdataat" option and process it */
{ if (match == 1 && (co->flags & DETECT_CONTENT_ISDATAAT_RELATIVE) &&
co->negated == 0) {
/* if the rest of the payload (from the last match) is less than /* if the rest of the payload (from the last match) is less than
the "isdataat" there is no data where the rule expected the "isdataat" there is no data where the rule expected
so match=0 so match=0
*/ */
SCLogDebug("isdataat: payload_len: %u, used %u, rest %u, isdataat? %u", p->payload_len, (m->offset + co->content_len),p->payload_len - (m->offset + co->content_len), co->isdataat); SCLogDebug("isdataat: payload_len: %u, used %u, rest %u, isdataat? %u", p->payload_len, (m->offset + co->content_len),p->payload_len - (m->offset + co->content_len), co->isdataat);
if(!(p->payload_len - (m->offset + co->content_len) >= co->isdataat))
if ( ((p->payload_len - (m->offset + co->content_len)) < co->isdataat) )
match = 0; match = 0;
if (match) { if (match) {
@ -368,18 +538,11 @@ DoDetectContent(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signat
int DetectContentMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) int DetectContentMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m)
{ {
uint32_t len = 0;
if (p->payload_len == 0) if (p->payload_len == 0)
return 0; return 0;
DetectContentData *co = (DetectContentData *)m->ctx; DetectContentData *co = (DetectContentData *)m->ctx;
/* see if we had a match */
len = det_ctx->mtc.match[co->id].len;
if (len == 0)
return 0;
#ifdef DEBUG #ifdef DEBUG
if (SCLogDebugEnabled()) { if (SCLogDebugEnabled()) {
DetectContentPrintMatches(det_ctx, co); DetectContentPrintMatches(det_ctx, co);
@ -392,30 +555,47 @@ int DetectContentMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p
DetectContentData *DetectContentParse (char *contentstr) DetectContentData *DetectContentParse (char *contentstr)
{ {
DetectContentData *cd = NULL; DetectContentData *cd = NULL;
char *str; char *str = NULL;
char *temp = NULL;
uint16_t len; uint16_t len;
if (strlen(contentstr) == 0) if ((temp = strdup(contentstr)) == NULL)
goto error;
if (strlen(temp) == 0) {
if (temp) free(temp);
return NULL; return NULL;
}
cd = malloc(sizeof(DetectContentData));
if (cd == NULL) {
printf("DetectContentParse malloc failed\n");
goto error;
}
memset(cd, 0, sizeof(DetectContentData));
if (temp[0] == '!') {
free(temp);
if ( (temp = strdup(contentstr + 1)) == NULL)
goto error;
cd->negated = 1;
}
if (contentstr[0] == '\"' && contentstr[strlen(contentstr)-1] == '\"') { if (temp[0] == '\"' && temp[strlen(temp)-1] == '\"') {
str = strdup(contentstr+1); if ( (str = strdup(temp + 1)) == NULL)
str[strlen(contentstr)-2] = '\0'; goto error;
str[strlen(temp) - 2] = '\0';
} else { } else {
str = strdup(contentstr); if ( (str = strdup(temp)) == NULL)
goto error;
} }
free(temp);
len = strlen(str); len = strlen(str);
if (len == 0) if (len == 0)
goto error; goto error;
cd = malloc(sizeof(DetectContentData));
if (cd == NULL) {
SCLogDebug("DetectContentParse malloc failed");
goto error;
}
memset(cd,0,sizeof(DetectContentData));
//SCLogDebug("DetectContentParse: \"%s\", len %" PRIu32 "", str, len); //SCLogDebug("DetectContentParse: \"%s\", len %" PRIu32 "", str, len);
char converted = 0; char converted = 0;
@ -849,7 +1029,6 @@ int DetectContentChunksGetTotalLength(SigMatch *sm)
void DetectContentPrintAll(SigMatch *sm) void DetectContentPrintAll(SigMatch *sm)
{ {
if (SCLogDebugEnabled()) { if (SCLogDebugEnabled()) {
int i = 0;
if (sm == NULL) if (sm == NULL)
return; return;
@ -1263,6 +1442,8 @@ int DetectContentSetup (DetectEngineCtx *de_ctx, Signature *s, SigMatch *m, char
de_ctx->content_max_id++; de_ctx->content_max_id++;
s->flags |= SIG_FLAG_MPM; s->flags |= SIG_FLAG_MPM;
if (cd->negated == 1)
s->flags |= SIG_FLAG_MPM_NEGCONTENT;
//DetectContentPrint(cd); //DetectContentPrint(cd);
} }
@ -2335,13 +2516,408 @@ int DetectContentChunkMatchTest09()
return DetectContentChunkMatchTestWrp(sig, 1); return DetectContentChunkMatchTestWrp(sig, 1);
} }
int DetectContentParseTest09(void) {
int result = 0;
DetectContentData *cd = NULL;
char *teststring = "!boo";
cd = DetectContentParse(teststring);
if (cd != NULL) {
result = (cd->negated == 1);
DetectContentFree(cd);
}
return result;
}
int DetectContentParseTest10(void) {
int result = 0;
DetectContentData *cd = NULL;
char *teststring = "!\"boo\"";
cd = DetectContentParse(teststring);
if (cd != NULL) {
result = (cd->negated == 1);
DetectContentFree(cd);
}
return result;
}
int DetectContentParseNegTest11(void) {
int result = 0;
DetectContentData *cd = NULL;
char *teststring = "boo";
cd = DetectContentParse(teststring);
if (cd != NULL) {
result = (cd->negated == 0);
DetectContentFree(cd);
}
return result;
}
int DetectContentParseNegTest12(void) {
int result = 0;
DetectContentData *cd = NULL;
char *teststring = "\"boo\"";
cd = DetectContentParse(teststring);
if (cd != NULL) {
result = (cd->negated == 0);
DetectContentFree(cd);
}
return result;
}
static int SigTestPositiveTestContent(char *rule, uint8_t *buf)
{
uint16_t buflen = strlen((char *)buf);
Packet p;
ThreadVars th_v;
DetectEngineThreadCtx *det_ctx;
int result = 0;
memset(&th_v, 0, sizeof(th_v));
memset(&p, 0, sizeof(p));
p.src.family = AF_INET;
p.dst.family = AF_INET;
p.payload = buf;
p.payload_len = buflen;
p.proto = IPPROTO_TCP;
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL)
goto end;
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx, rule);
if (de_ctx->sig_list == NULL) {
result = 0;
goto end;
}
SigGroupBuild(de_ctx);
//PatternMatchPrepare(mpm_ctx, MPM_B2G);
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
SigMatchSignatures(&th_v, de_ctx, det_ctx, &p);
if (PacketAlertCheck(&p, 1) == 1) {
result = 1;
goto end;
}
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
//PatternMatchDestroy(mpm_ctx);
DetectEngineCtxFree(de_ctx);
end:
return result;
}
static int SigTestNegativeTestContent(char *rule, uint8_t *buf)
{
uint16_t buflen = strlen((char *)buf);
Packet p;
ThreadVars th_v;
DetectEngineThreadCtx *det_ctx;
int result = 0;
memset(&th_v, 0, sizeof(th_v));
memset(&p, 0, sizeof(p));
p.src.family = AF_INET;
p.dst.family = AF_INET;
p.payload = buf;
p.payload_len = buflen;
p.proto = IPPROTO_TCP;
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL)
goto end;
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx, rule);
if (de_ctx->sig_list == NULL) {
result = 0;
goto end;
}
SigGroupBuild(de_ctx);
//PatternMatchPrepare(mpm_ctx, MPM_B2G);
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
SigMatchSignatures(&th_v, de_ctx, det_ctx, &p);
if (PacketAlertCheck(&p, 1) == 0) {
result = 1;
goto end;
}
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
//PatternMatchDestroy(mpm_ctx);
DetectEngineCtxFree(de_ctx);
end:
return result;
}
/**
* \test A positive test that checks that the content string doesn't contain
* the negated content
*/
static int SigTest41TestNegatedContent(void)
{
return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:!GES; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
}
/**
* \test A positive test that checks that the content string doesn't contain
* the negated content within the specified depth
*/
static int SigTest42TestNegatedContent(void)
{
return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:!twentythree; depth:22; offset:35; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
/**
* \test A negative test that checks that the content string doesn't contain
* the negated content within the specified depth, and also after the
* specified offset. If it is present in the depth we get a failure
* anyways, and we don't do a check on the offset
*/
static int SigTest43TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:!twentythree; depth:15; offset:22; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
/**
* \test A negative test that checks that the content string doesn't contain
* the negated content after the specified offset and within the specified
* depth.
*/
static int SigTest44TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:!twentythree; offset:40; depth:35; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
/**
* \test A positive test that uses a combination of content string with negated
* content string
*/
static int SigTest45TestNegatedContent(void)
{
return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; depth:5; content:!twentythree; depth:23; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
/**
* \test A negative test that uses a combination of content string with negated
* content string, with we receiving a failure for 'onee' itself.
*/
static int SigTest46TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:onee; content:!twentythree; depth:23; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
/**
* \test A negative test that uses a combination of content string with negated
* content string, with we receiving a failure of first content's offset
* condition
*/
static int SigTest47TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; offset:5; content:!twentythree; depth:23; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
/**
* \test A positive test that checks that we don't have a negated content within
* the specified length from the previous content match.
*/
static int SigTest48TestNegatedContent(void)
{
return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:GET; content:!GES; within:26; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
}
/**
* \test A negative test that checks the combined use of content and negated
* content with the use of within
*/
static int SigTest49TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:GET; content:!Host; within:26; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
}
/**
* \test A positive test that checks the combined use of content and negated
* content with the use of distance
*/
static int SigTest50TestNegatedContent(void)
{
return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:GET; content:!GES; distance:25; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
}
/**
* \test A negative test that checks the combined use of content and negated
* content with the use of distance
*/
static int SigTest51TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:GET; content:!Host; distance:18; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
}
/**
* \test A negative test that checks the combined use of content and negated
* content, with the content not being present
*/
static int SigTest52TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:GES; content:!BOO; sid:1;)", (uint8_t *)"GET /one/ HTTP/1.1\r\n Host: one.example.org\r\n\r\n\r\nGET /two/ HTTP/1.1\r\nHost: two.example.org\r\n\r\n\r\n");
}
/**
* \test A negative test that checks the combined use of content and negated
* content, in the presence of within
*/
static int SigTest53TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; content:!fourty; within:56; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
/**
* \test A positive test that checks the combined use of content and negated
* content, in the presence of within
*/
static int SigTest54TestNegatedContent(void)
{
return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; content:!fourty; within:20; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
/**
* \test A negative test that checks the use of negated content along with
* the presence of depth
*/
static int SigTest55TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:!one; depth:5; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
/**
* \test A positive test that checks the combined use of 2 contents in the
* presence of within
*/
static int SigTest56TestNegatedContent(void)
{
return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; content:fourty; within:56; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
/**
* \test A negative test that checks the combined use of content and negated
* content, in the presence of within
*/
static int SigTest57TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; content:!fourty; within:56; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
/**
* \test A positive test that checks the combined use of content and negated
* content, in the presence of distance
*/
static int SigTest58TestNegatedContent(void)
{
return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; content:!fourty; distance:57; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
/**
* \test A negative test that checks the combined use of content and negated
* content, in the presence of distance
*/
static int SigTest59TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; content:!fourty; distance:30; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest60TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:!one; content:fourty; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest61TestNegatedContent(void)
{
return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; depth:10; content:!fourty; within:30; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest62TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; depth:10; content:!fourty; within:30; depth:56; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest63TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; depth:10; content:!fourty; within:56; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest64TestNegatedContent(void)
{
return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; depth:10; content:!fourty; within:30; depth:30; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest65TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; depth:10; content:!fourty; within:30; offset:30; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest66TestNegatedContent(void)
{
return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; depth:10; content:!fourty; within:30; offset:56; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest67TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; depth:10; content:!four; within:56; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest68TestNegatedContent(void)
{
return SigTestPositiveTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; depth:10; content:nine; offset:8; content:!fourty; within:28; content:fiftysix; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest69TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; depth:10; content:nine; offset:8; content:!fourty; within:48; content:fiftysix; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest70TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; content:!fourty; within:52; distance:45 sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest71TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; content:!fourty; within:40; distance:43; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest72TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; content:!fourty; within:52; distance:47; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
static int SigTest73TestNegatedContent(void)
{
return SigTestNegativeTestContent("alert tcp any any -> any any (msg:\"HTTP URI cap\"; content:one; depth:5; content:!twentythree; depth:35; sid:1;)", (uint8_t *)"one four nine fourteen twentythree thirtyfive fourtysix fiftysix");
}
#endif /* UNITTESTS */ #endif /* UNITTESTS */
/** /**
* \brief this function registers unit tests for DetectContent * \brief this function registers unit tests for DetectContent
*/ */
void DetectContentRegisterTests(void) { void DetectContentRegisterTests(void)
#ifdef UNITTESTS /* UNITTESTS */ {
#ifdef UNITTESTS /* UNITTESTS */
UtRegisterTest("DetectContentParseTest01", DetectContentParseTest01, 1); UtRegisterTest("DetectContentParseTest01", DetectContentParseTest01, 1);
UtRegisterTest("DetectContentParseTest02", DetectContentParseTest02, 1); UtRegisterTest("DetectContentParseTest02", DetectContentParseTest02, 1);
UtRegisterTest("DetectContentParseTest03", DetectContentParseTest03, 1); UtRegisterTest("DetectContentParseTest03", DetectContentParseTest03, 1);
@ -2350,6 +2926,11 @@ void DetectContentRegisterTests(void) {
UtRegisterTest("DetectContentParseTest06", DetectContentParseTest06, 1); UtRegisterTest("DetectContentParseTest06", DetectContentParseTest06, 1);
UtRegisterTest("DetectContentParseTest07", DetectContentParseTest07, 1); UtRegisterTest("DetectContentParseTest07", DetectContentParseTest07, 1);
UtRegisterTest("DetectContentParseTest08", DetectContentParseTest08, 1); UtRegisterTest("DetectContentParseTest08", DetectContentParseTest08, 1);
UtRegisterTest("DetectContentParseTest09", DetectContentParseTest09, 1);
UtRegisterTest("DetectContentParseTest10", DetectContentParseTest10, 1);
UtRegisterTest("DetectContentParseTest11", DetectContentParseNegTest11, 1);
UtRegisterTest("DetectContentParseTest12", DetectContentParseNegTest12, 1);
UtRegisterTest("DetectContentChunkTestB2G01 l=32", DetectContentChunkTestB2G01, 1); UtRegisterTest("DetectContentChunkTestB2G01 l=32", DetectContentChunkTestB2G01, 1);
UtRegisterTest("DetectContentChunkTestB3G01 l=32", DetectContentChunkTestB3G01, 1); UtRegisterTest("DetectContentChunkTestB3G01 l=32", DetectContentChunkTestB3G01, 1);
UtRegisterTest("DetectContentChunkTestB2G02 l=33", DetectContentChunkTestB2G02, 1); UtRegisterTest("DetectContentChunkTestB2G02 l=33", DetectContentChunkTestB2G02, 1);
@ -2358,6 +2939,7 @@ void DetectContentRegisterTests(void) {
UtRegisterTest("DetectContentChunkTestB3G03 l=100", DetectContentChunkTestB3G03, 1); UtRegisterTest("DetectContentChunkTestB3G03 l=100", DetectContentChunkTestB3G03, 1);
UtRegisterTest("DetectContentChunkModifiersTest01", DetectContentChunkModifiersTest01, 1); UtRegisterTest("DetectContentChunkModifiersTest01", DetectContentChunkModifiersTest01, 1);
UtRegisterTest("DetectContentChunkModifiersTest02", DetectContentChunkModifiersTest02, 1); UtRegisterTest("DetectContentChunkModifiersTest02", DetectContentChunkModifiersTest02, 1);
/* The reals */ /* The reals */
UtRegisterTest("DetectContentChunkMatchTest01", DetectContentChunkMatchTest01, 1); UtRegisterTest("DetectContentChunkMatchTest01", DetectContentChunkMatchTest01, 1);
UtRegisterTest("DetectContentChunkMatchTest02", DetectContentChunkMatchTest02, 1); UtRegisterTest("DetectContentChunkMatchTest02", DetectContentChunkMatchTest02, 1);
@ -2368,5 +2950,41 @@ void DetectContentRegisterTests(void) {
UtRegisterTest("DetectContentChunkMatchTest07", DetectContentChunkMatchTest07, 1); UtRegisterTest("DetectContentChunkMatchTest07", DetectContentChunkMatchTest07, 1);
UtRegisterTest("DetectContentChunkMatchTest08", DetectContentChunkMatchTest08, 1); UtRegisterTest("DetectContentChunkMatchTest08", DetectContentChunkMatchTest08, 1);
UtRegisterTest("DetectContentChunkMatchTest09", DetectContentChunkMatchTest09, 1); UtRegisterTest("DetectContentChunkMatchTest09", DetectContentChunkMatchTest09, 1);
#endif /* UNITTESTS */
/* Negated content tests */
UtRegisterTest("SigTest41TestNegatedContent", SigTest41TestNegatedContent, 1);
UtRegisterTest("SigTest42TestNegatedContent", SigTest42TestNegatedContent, 1);
UtRegisterTest("SigTest43TestNegatedContent", SigTest43TestNegatedContent, 1);
UtRegisterTest("SigTest44TestNegatedContent", SigTest44TestNegatedContent, 1);
UtRegisterTest("SigTest45TestNegatedContent", SigTest45TestNegatedContent, 1);
UtRegisterTest("SigTest46TestNegatedContent", SigTest46TestNegatedContent, 1);
UtRegisterTest("SigTest47TestNegatedContent", SigTest47TestNegatedContent, 1);
UtRegisterTest("SigTest48TestNegatedContent", SigTest48TestNegatedContent, 1);
UtRegisterTest("SigTest49TestNegatedContent", SigTest49TestNegatedContent, 1);
UtRegisterTest("SigTest50TestNegatedContent", SigTest50TestNegatedContent, 1);
UtRegisterTest("SigTest51TestNegatedContent", SigTest51TestNegatedContent, 1);
UtRegisterTest("SigTest52TestNegatedContent", SigTest52TestNegatedContent, 1);
UtRegisterTest("SigTest53TestNegatedContent", SigTest53TestNegatedContent, 1);
UtRegisterTest("SigTest54TestNegatedContent", SigTest54TestNegatedContent, 1);
UtRegisterTest("SigTest55TestNegatedContent", SigTest55TestNegatedContent, 1);
UtRegisterTest("SigTest56TestNegatedContent", SigTest56TestNegatedContent, 1);
UtRegisterTest("SigTest57TestNegatedContent", SigTest57TestNegatedContent, 1);
UtRegisterTest("SigTest58TestNegatedContent", SigTest58TestNegatedContent, 1);
UtRegisterTest("SigTest59TestNegatedContent", SigTest59TestNegatedContent, 1);
UtRegisterTest("SigTest60TestNegatedContent", SigTest60TestNegatedContent, 1);
UtRegisterTest("SigTest61TestNegatedContent", SigTest61TestNegatedContent, 1);
UtRegisterTest("SigTest62TestNegatedContent", SigTest62TestNegatedContent, 1);
UtRegisterTest("SigTest63TestNegatedContent", SigTest63TestNegatedContent, 1);
UtRegisterTest("SigTest64TestNegatedContent", SigTest64TestNegatedContent, 1);
UtRegisterTest("SigTest65TestNegatedContent", SigTest65TestNegatedContent, 1);
UtRegisterTest("SigTest66TestNegatedContent", SigTest66TestNegatedContent, 1);
UtRegisterTest("SigTest67TestNegatedContent", SigTest67TestNegatedContent, 1);
UtRegisterTest("SigTest68TestNegatedContent", SigTest68TestNegatedContent, 1);
UtRegisterTest("SigTest69TestNegatedContent", SigTest69TestNegatedContent, 1);
UtRegisterTest("SigTest70TestNegatedContent", SigTest70TestNegatedContent, 1);
UtRegisterTest("SigTest71TestNegatedContent", SigTest71TestNegatedContent, 1);
UtRegisterTest("SigTest72TestNegatedContent", SigTest72TestNegatedContent, 1);
UtRegisterTest("SigTest73TestNegatedContent", SigTest73TestNegatedContent, 1);
#endif /* UNITTESTS */
} }

@ -28,6 +28,8 @@ typedef struct DetectContentData_ {
uint8_t content_len; uint8_t content_len;
uint32_t id; uint32_t id;
uint8_t negated;
uint16_t depth; uint16_t depth;
uint16_t offset; uint16_t offset;
uint32_t isdataat; uint32_t isdataat;

@ -423,8 +423,10 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
/* filter out sigs that want pattern matches, but /* filter out sigs that want pattern matches, but
* have no matches */ * have no matches */
if (!(det_ctx->pmq.sig_bitarray[(sig / 8)] & (1<<(sig % 8))) && if (!(det_ctx->pmq.sig_bitarray[(sig / 8)] & (1<<(sig % 8))) &&
(s->flags & SIG_FLAG_MPM)) (s->flags & SIG_FLAG_MPM) &&
!(s->flags & SIG_FLAG_MPM_NEGCONTENT)) {
continue; continue;
}
//printf("idx %" PRIu32 ", det_ctx->pmq.sig_id_array_cnt %" PRIu32 ", s->id %" PRIu32 " (MPM? %s)\n", idx, det_ctx->pmq.sig_id_array_cnt, s->id, s->flags & SIG_FLAG_MPM ? "TRUE":"FALSE"); //printf("idx %" PRIu32 ", det_ctx->pmq.sig_id_array_cnt %" PRIu32 ", s->id %" PRIu32 " (MPM? %s)\n", idx, det_ctx->pmq.sig_id_array_cnt, s->id, s->flags & SIG_FLAG_MPM ? "TRUE":"FALSE");
//printf("Sig %" PRIu32 "\n", s->id); //printf("Sig %" PRIu32 "\n", s->id);

@ -126,6 +126,7 @@ typedef struct DetectPort_ {
#define SIG_FLAG_PAYLOAD 0x0200 /**< signature is inspecting the packet payload */ #define SIG_FLAG_PAYLOAD 0x0200 /**< signature is inspecting the packet payload */
#define SIG_FLAG_DSIZE 0x0400 /**< signature has a dsize setting */ #define SIG_FLAG_DSIZE 0x0400 /**< signature has a dsize setting */
#define SIG_FLAG_FLOW 0x0800 /**< signature has a flow setting */ #define SIG_FLAG_FLOW 0x0800 /**< signature has a flow setting */
#define SIG_FLAG_MPM_NEGCONTENT 0x1000 /**< sig has negative mpm portion(!content) */
/* Detection Engine flags */ /* Detection Engine flags */
#define DE_QUIET 0x01 /**< DE is quiet (esp for unittests) */ #define DE_QUIET 0x01 /**< DE is quiet (esp for unittests) */

Loading…
Cancel
Save