void DetectIsdataatRegisterTests(void);
void DetectIsdataatFree(void *);
+static int DetectEndsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr);
+
/**
* \brief Registration function for isdataat: keyword
*/
sigmatch_table[DETECT_ISDATAAT].Free = DetectIsdataatFree;
sigmatch_table[DETECT_ISDATAAT].RegisterTests = DetectIsdataatRegisterTests;
+ sigmatch_table[DETECT_ENDS_WITH].name = "endswith";
+ sigmatch_table[DETECT_ENDS_WITH].desc = "make sure the previous content matches exactly at the end of the buffer";
+ sigmatch_table[DETECT_ENDS_WITH].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#endswith";
+ sigmatch_table[DETECT_ENDS_WITH].Setup = DetectEndsWithSetup;
+ sigmatch_table[DETECT_ENDS_WITH].flags = SIGMATCH_NOOPT;
+
DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study);
}
SCFree(idad);
}
+static int DetectEndsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr)
+{
+ SigMatch *pm = NULL;
+ int ret = -1;
+
+ /* retrieve the sm to apply the depth against */
+ pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1);
+ if (pm == NULL) {
+ SCLogError(SC_ERR_DEPTH_MISSING_CONTENT, "endswith needs a "
+ "preceding content option");
+ goto end;
+ }
+
+ /* verify other conditions. */
+ DetectContentData *cd = (DetectContentData *)pm->ctx;
+
+ cd->flags |= DETECT_CONTENT_ENDS_WITH;
+
+ ret = 0;
+ end:
+ return ret;
+}
#ifdef UNITTESTS
static int g_dce_stub_data_buffer_id = 0;
TEST_FOOTER;
}
+/** \test endswith (isdataat) recursion logic
+ * based on DetectEngineContentInspectionTest06 */
+static int DetectEngineContentInspectionTest12(void) {
+ TEST_HEADER;
+ // 6 steps: (1) a, (2) 1st b, (3) c not found, (4) 2nd b, (5) c found, endswith
+ TEST_RUN("ababc", 5, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; within:1; endswith;", true, 5);
+
+ TEST_RUN("ababcabc", 8, "content:\"a\"; content:\"b\"; distance:0; within:1; content:\"c\"; distance:0; within:1; endswith;", true, 7);
+
+ TEST_RUN("abcXYZ", 6, "content:\"abc\"; content:\"XYZ\"; distance:0; within:3; endswith;", true, 2);
+ TEST_RUN("abcXYZ", 6, "content:\"XYZ\"; distance:3; within:3; endswith;", true, 1);
+ TEST_RUN("abcXYZ", 6, "content:\"cXY\"; distance:2; within:3; endswith;", false, 1);
+
+ TEST_RUN("xxxxxxxxxxxxxxxxxyYYYYYYYYYYYYYYYY", 34, "content:\"yYYYYYYYYYYYYYYYY\"; distance:9; within:29; endswith;", true, 1);
+ TEST_FOOTER;
+}
+
+static int DetectEngineContentInspectionTest13(void) {
+ TEST_HEADER;
+ TEST_RUN("ab", 2, "content:\"a\"; startswith; content:\"b\"; endswith;", true, 2);
+ TEST_RUN("ab", 2, "content:\"a\"; startswith; content:\"b\"; within:1; distance:0; endswith;", true, 2);
+ TEST_RUN("ab", 2, "content:\"ab\"; startswith; endswith;", true, 1);
+ TEST_RUN("ab", 2, "content:\"a\"; startswith; endswith;", false, 1);
+ TEST_RUN("ab", 2, "content:\"b\"; startswith;", false, 1);
+ TEST_RUN("ab", 2, "content:\"b\"; startswith; endswith;", false, 1);
+ TEST_FOOTER;
+}
+
void DetectEngineContentInspectionRegisterTests(void)
{
UtRegisterTest("DetectEngineContentInspectionTest01",
DetectEngineContentInspectionTest10);
UtRegisterTest("DetectEngineContentInspectionTest11 startswith",
DetectEngineContentInspectionTest11);
+ UtRegisterTest("DetectEngineContentInspectionTest12 endswith",
+ DetectEngineContentInspectionTest12);
+ UtRegisterTest("DetectEngineContentInspectionTest13 mix startswith/endswith",
+ DetectEngineContentInspectionTest13);
}
#undef TEST_HEADER