]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect/content: implement endswith 3182/head
authorVictor Julien <victor@inliniac.net>
Tue, 19 Dec 2017 15:14:33 +0000 (16:14 +0100)
committerVictor Julien <victor@inliniac.net>
Fri, 19 Jan 2018 09:17:21 +0000 (10:17 +0100)
src/detect-engine-register.h
src/detect-isdataat.c
src/tests/detect-engine-content-inspection.c

index 4b6310d3cd0ab4966486eab9887ef57618892693..bc9673decf43cef5399ccd3bcc4a73aa69413bc3 100644 (file)
@@ -61,6 +61,7 @@ enum {
     DETECT_PCRE,
     DETECT_DEPTH,
     DETECT_STARTS_WITH,
+    DETECT_ENDS_WITH,
     DETECT_DISTANCE,
     DETECT_WITHIN,
     DETECT_OFFSET,
index 01631d8dbba658eb99654945373f10a6778ab74f..8cca5571a2e3c79c81f7b511be39f660971d8786 100644 (file)
@@ -59,6 +59,8 @@ int DetectIsdataatSetup (DetectEngineCtx *, Signature *, const char *);
 void DetectIsdataatRegisterTests(void);
 void DetectIsdataatFree(void *);
 
+static int DetectEndsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr);
+
 /**
  * \brief Registration function for isdataat: keyword
  */
@@ -73,6 +75,12 @@ void DetectIsdataatRegister(void)
     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);
 }
 
@@ -299,6 +307,28 @@ void DetectIsdataatFree(void *ptr)
     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;
index 214c5c3fa8cfc4203ab2330693b8d09e0ebd6c6a..c920657f9dc0592187e242bf6ea866eeedf791d6 100644 (file)
@@ -235,6 +235,34 @@ static int DetectEngineContentInspectionTest11(void) {
     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",
@@ -259,6 +287,10 @@ void DetectEngineContentInspectionRegisterTests(void)
                    DetectEngineContentInspectionTest10);
     UtRegisterTest("DetectEngineContentInspectionTest11 startswith",
                    DetectEngineContentInspectionTest11);
+    UtRegisterTest("DetectEngineContentInspectionTest12 endswith",
+                   DetectEngineContentInspectionTest12);
+    UtRegisterTest("DetectEngineContentInspectionTest13 mix startswith/endswith",
+                   DetectEngineContentInspectionTest13);
 }
 
 #undef TEST_HEADER