]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
feature #727 - Add support for app-layer-protocol:<protocol> keyword
authorAnoop Saldanha <anoopsaldanha@gmail.com>
Sat, 3 Aug 2013 14:16:46 +0000 (19:46 +0530)
committerAnoop Saldanha <anoopsaldanha@gmail.com>
Sun, 29 Sep 2013 17:43:07 +0000 (23:13 +0530)
src/Makefile.am
src/detect-app-layer-protocol.c [new file with mode: 0644]
src/detect-app-layer-protocol.h [new file with mode: 0644]
src/detect-engine-state.c
src/detect-parse.c
src/detect.c
src/detect.h

index 498fa41e3a7e95143f1a905b58ba13d48eaef862..4de0c4157124287fd73fc52a425794ac87c2f1f4 100644 (file)
@@ -60,6 +60,7 @@ defrag-queue.c defrag-queue.h \
 defrag-timeout.c defrag-timeout.h \
 detect-ack.c detect-ack.h \
 detect-app-layer-event.c detect-app-layer-event.h \
+detect-app-layer-protocol.c detect-app-layer-protocol.h \
 detect-asn1.c detect-asn1.h \
 detect-byte-extract.c detect-byte-extract.h \
 detect-bytejump.c detect-bytejump.h \
diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c
new file mode 100644 (file)
index 0000000..2a604f9
--- /dev/null
@@ -0,0 +1,408 @@
+/* Copyright (C) 2007-2013 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Anoop Saldanha <anoopsaldanha@gmail.com>
+ */
+
+#include "suricata-common.h"
+#include "detect-engine.h"
+#include "detect-parse.h"
+#include "detect-app-layer-protocol.h"
+#include "app-layer-parser.h"
+#include "util-debug.h"
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
+
+void DetectAppLayerProtocolRegisterTests(void);
+
+int DetectAppLayerProtocolMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx,
+                                Flow *f, uint8_t flags, void *state,
+                                Signature *s, SigMatch *m)
+{
+    int r = 0;
+    DetectAppLayerProtocolData *data = (DetectAppLayerProtocolData *)m->ctx;
+
+    FLOWLOCK_RDLOCK(f);
+    r = (data->negated) ? (f->alproto != data->alproto) :
+        (f->alproto == data->alproto);
+    FLOWLOCK_UNLOCK(f);
+
+    return r;
+}
+
+static DetectAppLayerProtocolData *DetectAppLayerProtocolParse(const char *arg)
+{
+    DetectAppLayerProtocolData *data;
+    uint16_t alproto = ALPROTO_UNKNOWN;
+    uint8_t negated = 0;
+
+    if (arg == NULL) {
+        SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-protocol keyword "
+                   "supplied with no arguments.  This keyword needs "
+                   "an argument.");
+        return NULL;
+    }
+
+    while (*arg != '\0' && isspace((unsigned char)*arg))
+        arg++;
+
+    if (arg[0] == '!') {
+        negated = 1;
+        arg++;
+    }
+
+    while (*arg != '\0' && isspace((unsigned char)*arg))
+        arg++;
+
+    alproto = AppLayerGetProtoByName(arg);
+    if (alproto == ALPROTO_UNKNOWN) {
+        SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-protocol "
+                   "keyword supplied with unknown protocol \"%s\"", arg);
+        return NULL;
+    }
+
+    data = SCMalloc(sizeof(DetectAppLayerProtocolData));
+    if (unlikely(data == NULL))
+        return NULL;
+    data->alproto = alproto;
+    data->negated = negated;
+
+    return data;
+}
+
+int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, Signature *s,
+                                char *arg)
+{
+    DetectAppLayerProtocolData *data = NULL;
+    SigMatch *sm = NULL;
+
+    if (s->alproto != ALPROTO_UNKNOWN) {
+        SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "Either we already "
+                   "have the rule match on an app layer protocol set through "
+                   "other keywords that match on this protocol, or have "
+                   "already seen a non-negated app-layer-protocol.");
+        goto error;
+    }
+
+    data = DetectAppLayerProtocolParse(arg);
+    if (data == NULL)
+        goto error;
+
+    if (!data->negated)
+        s->alproto = data->alproto;
+
+    sm = SigMatchAlloc();
+    if (sm == NULL)
+        goto error;
+
+    sm->type = DETECT_AL_APP_LAYER_PROTOCOL;
+    sm->ctx = (void *)data;
+
+    SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH);
+    s->flags |= SIG_FLAG_APPLAYER;
+
+    return 0;
+
+error:
+    if (data != NULL)
+        SCFree(data);
+    return -1;
+}
+
+void DetectAppLayerProtocolFree(void *ptr)
+{
+    SCFree(ptr);
+
+    return;
+}
+
+void DetectAppLayerProtocolRegister(void)
+{
+    sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].name = "app-layer-protocol";
+    sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Match = NULL;
+    sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].AppLayerMatch =
+        DetectAppLayerProtocolMatch;
+    sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Setup =
+        DetectAppLayerProtocolSetup;
+    sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Free =
+        DetectAppLayerProtocolFree;
+    sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].RegisterTests =
+        DetectAppLayerProtocolRegisterTests;
+
+    return;
+}
+
+/**********************************Unittests***********************************/
+
+#ifdef UNITTESTS
+
+int DetectAppLayerProtocolTest01(void)
+{
+    int result = 0;
+
+    DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("http");
+    if (data == NULL)
+        goto end;
+    if (data->alproto != ALPROTO_HTTP || data->negated) {
+        printf("test failure.  Holding wrong state\n");
+        goto end;
+    }
+
+    result = 1;
+
+ end:
+    if (data != NULL)
+        DetectAppLayerProtocolFree(data);
+    return result;
+}
+
+int DetectAppLayerProtocolTest02(void)
+{
+    int result = 0;
+
+    DetectAppLayerProtocolData *data = DetectAppLayerProtocolParse("!http");
+    if (data == NULL)
+        goto end;
+    if (data->alproto != ALPROTO_HTTP || !data->negated) {
+        printf("test failure.  Holding wrong state\n");
+        goto end;
+    }
+
+    result = 1;
+
+ end:
+    if (data != NULL)
+        DetectAppLayerProtocolFree(data);
+    return result;
+}
+
+int DetectAppLayerProtocolTest03(void)
+{
+    int result = 0;
+    Signature *s = NULL;
+    DetectAppLayerProtocolData *data = NULL;
+    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+    if (de_ctx == NULL)
+        goto end;
+    de_ctx->flags |= DE_QUIET;
+
+    s = SigInit(de_ctx, "alert tcp any any -> any any "
+                "(app-layer-protocol:http; sid:1;)");
+    if (s->alproto != ALPROTO_HTTP) {
+        printf("signature alproto should be http\n");
+        goto end;
+    }
+    data = s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx;
+    if (data->alproto != ALPROTO_HTTP || data->negated) {
+        printf("if (data->alproto != ALPROTO_HTTP || data->negated)\n");
+        goto end;
+    }
+
+    result = 1;
+
+ end:
+    SigGroupCleanup(de_ctx);
+    SigCleanSignatures(de_ctx);
+    DetectEngineCtxFree(de_ctx);
+    return result;
+}
+
+int DetectAppLayerProtocolTest04(void)
+{
+    int result = 0;
+    Signature *s = NULL;
+    DetectAppLayerProtocolData *data = NULL;
+    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+    if (de_ctx == NULL)
+        goto end;
+    de_ctx->flags |= DE_QUIET;
+
+    s = SigInit(de_ctx, "alert tcp any any -> any any "
+                "(app-layer-protocol:!http; sid:1;)");
+    if (s->alproto != ALPROTO_UNKNOWN) {
+        printf("signature alproto should be unknown\n");
+        goto end;
+    }
+    if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL) {
+        printf("if (s->sm_lists[DETECT_SM_LIST_AMATCH] == NULL)\n");
+        goto end;
+    }
+    data = s->sm_lists[DETECT_SM_LIST_AMATCH]->ctx;
+    if (data == NULL) {
+        printf("if (data == NULL)\n");
+        goto end;
+    }
+    if (data->alproto != ALPROTO_HTTP || !data->negated) {
+        printf("if (data->alproto != ALPROTO_HTTP || !data->negated)\n");
+        goto end;
+    }
+
+    result = 1;
+
+ end:
+    SigGroupCleanup(de_ctx);
+    SigCleanSignatures(de_ctx);
+    DetectEngineCtxFree(de_ctx);
+    return result;
+}
+
+int DetectAppLayerProtocolTest05(void)
+{
+    int result = 0;
+    Signature *s = NULL;
+    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+    if (de_ctx == NULL)
+        goto end;
+    de_ctx->flags |= DE_QUIET;
+
+    s = SigInit(de_ctx, "alert tcp any any -> any any "
+                "(app-layer-protocol:!http; app-layer-protocol:!smtp; sid:1;)");
+    if (s->alproto != ALPROTO_UNKNOWN) {
+        printf("signature alproto should be unknown\n");
+        goto end;
+    }
+
+    result = 1;
+
+ end:
+    SigGroupCleanup(de_ctx);
+    SigCleanSignatures(de_ctx);
+    DetectEngineCtxFree(de_ctx);
+    return result;
+}
+
+int DetectAppLayerProtocolTest06(void)
+{
+    int result = 0;
+    Signature *s = NULL;
+    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+    if (de_ctx == NULL)
+        goto end;
+    de_ctx->flags |= DE_QUIET;
+
+    s = SigInit(de_ctx, "alert http any any -> any any "
+                "(app-layer-protocol:smtp; sid:1;)");
+    if (s != NULL) {
+        printf("if (s != NULL)\n");
+        goto end;
+    }
+
+    result = 1;
+
+ end:
+    SigGroupCleanup(de_ctx);
+    SigCleanSignatures(de_ctx);
+    DetectEngineCtxFree(de_ctx);
+    return result;
+}
+
+int DetectAppLayerProtocolTest07(void)
+{
+    int result = 0;
+    Signature *s = NULL;
+    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+    if (de_ctx == NULL)
+        goto end;
+    de_ctx->flags |= DE_QUIET;
+
+    s = SigInit(de_ctx, "alert http any any -> any any "
+                "(app-layer-protocol:!smtp; sid:1;)");
+    if (s != NULL) {
+        printf("if (s != NULL)\n");
+        goto end;
+    }
+
+    result = 1;
+
+ end:
+    SigGroupCleanup(de_ctx);
+    SigCleanSignatures(de_ctx);
+    DetectEngineCtxFree(de_ctx);
+    return result;
+}
+
+int DetectAppLayerProtocolTest08(void)
+{
+    int result = 0;
+    Signature *s = NULL;
+    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+    if (de_ctx == NULL)
+        goto end;
+    de_ctx->flags |= DE_QUIET;
+
+    s = SigInit(de_ctx, "alert tcp any any -> any any "
+                "(app-layer-protocol:!smtp; app-layer-protocol:http; sid:1;)");
+    if (s != NULL) {
+        printf("if (s != NULL)\n");
+        goto end;
+    }
+
+    result = 1;
+
+ end:
+    SigGroupCleanup(de_ctx);
+    SigCleanSignatures(de_ctx);
+    DetectEngineCtxFree(de_ctx);
+    return result;
+}
+
+int DetectAppLayerProtocolTest09(void)
+{
+    int result = 0;
+    Signature *s = NULL;
+    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+    if (de_ctx == NULL)
+        goto end;
+    de_ctx->flags |= DE_QUIET;
+
+    s = SigInit(de_ctx, "alert tcp any any -> any any "
+                "(app-layer-protocol:http; app-layer-protocol:!smtp; sid:1;)");
+    if (s != NULL) {
+        printf("if (s != NULL)\n");
+        goto end;
+    }
+
+    result = 1;
+
+ end:
+    SigGroupCleanup(de_ctx);
+    SigCleanSignatures(de_ctx);
+    DetectEngineCtxFree(de_ctx);
+    return result;
+}
+
+#endif /* UNITTESTS */
+
+void DetectAppLayerProtocolRegisterTests(void)
+{
+#ifdef UNITTESTS /* UNITTESTS */
+    UtRegisterTest("DetectAppLayerProtocolTest01", DetectAppLayerProtocolTest01, 1);
+    UtRegisterTest("DetectAppLayerProtocolTest02", DetectAppLayerProtocolTest02, 1);
+    UtRegisterTest("DetectAppLayerProtocolTest03", DetectAppLayerProtocolTest03, 1);
+    UtRegisterTest("DetectAppLayerProtocolTest04", DetectAppLayerProtocolTest04, 1);
+    UtRegisterTest("DetectAppLayerProtocolTest05", DetectAppLayerProtocolTest05, 1);
+    UtRegisterTest("DetectAppLayerProtocolTest06", DetectAppLayerProtocolTest06, 1);
+    UtRegisterTest("DetectAppLayerProtocolTest07", DetectAppLayerProtocolTest07, 1);
+    UtRegisterTest("DetectAppLayerProtocolTest08", DetectAppLayerProtocolTest08, 1);
+    UtRegisterTest("DetectAppLayerProtocolTest09", DetectAppLayerProtocolTest09, 1);
+#endif /* UNITTESTS */
+
+    return;
+}
diff --git a/src/detect-app-layer-protocol.h b/src/detect-app-layer-protocol.h
new file mode 100644 (file)
index 0000000..07a34e5
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (C) 2007-2013 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Anoop Saldanha <anoopsaldanha@gmail.com>
+ */
+
+#ifndef __DETECT_APP_LAYER_PROTOCOL__H__
+#define __DETECT_APP_LAYER_PROTOCOL__H__
+
+typedef struct DetectAppLayerProtocolData_ {
+    uint16_t alproto;
+    uint8_t negated;
+} DetectAppLayerProtocolData;
+
+void DetectAppLayerProtocolRegister(void);
+
+#endif /* __DETECT_APP_LAYER_PROTOCOL__H__ */
index ca58f4917d12c1f36cae79cadd04850a657b7a4d..1e6cfd5c9a6e0ab4833d97f46ab90f7585454f58 100644 (file)
@@ -348,10 +348,9 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
     }
 
     sm = s->sm_lists[DETECT_SM_LIST_AMATCH];
-    for (; sm != NULL; sm = sm->next) {
-        if (sigmatch_table[sm->type].AppLayerMatch != NULL &&
-            (alproto == s->alproto || alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2))
-        {
+    for (match = 0; sm != NULL; sm = sm->next) {
+        match = 0;
+        if (sigmatch_table[sm->type].AppLayerMatch != NULL) {
             if (alproto == ALPROTO_SMB || alproto == ALPROTO_SMB2) {
                 smb_state = (SMBState *)alstate;
                 if (smb_state->dcerpc_present) {
@@ -365,14 +364,16 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
 
             if (match == 0)
                 break;
-            else if (match == 2)
+            if (match == 2) {
                 inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH;
+                break;
+            }
         }
     }
     if (s->sm_lists[DETECT_SM_LIST_AMATCH] != NULL) {
         store_de_state = 1;
         if (sm == NULL || inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH) {
-            if (sm == NULL)
+            if (match == 1)
                 alert_cnt = 1;
             inspect_flags |= DE_STATE_FLAG_FULL_INSPECT;
         }
index 1c6debb024fd4bf887d9b17415e06aa65c7cc0ab..b57149cc0358a56554471488f6a177c416781792 100644 (file)
@@ -38,6 +38,7 @@
 #include "detect-reference.h"
 #include "detect-ipproto.h"
 #include "detect-flow.h"
+#include "detect-app-layer-protocol.h"
 
 #include "pkt-var.h"
 #include "host.h"
@@ -1297,6 +1298,19 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s) {
         }
     }
 
+    for (sm = s->sm_lists[DETECT_SM_LIST_AMATCH]; sm != NULL; sm = sm->next) {
+        if (sm->type != DETECT_AL_APP_LAYER_PROTOCOL)
+            continue;
+        if (((DetectAppLayerProtocolData *)sm->ctx)->negated)
+            break;
+    }
+    if (sm != NULL && s->alproto != ALPROTO_UNKNOWN) {
+        SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "We can't have "
+                   "the rule match on a fixed alproto and at the same time"
+                   "have an app-layer-protocol keyword set.");
+        SCReturnInt(0);
+    }
+
     /* TCP: pkt vs stream vs depth/offset */
     if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) {
         if (!(s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM))) {
index 5eaf4c80cfe78341502d7dcc6ed6951dd29e9b02..0341de593ec015f5b52e5deec044fe7f974b324d 100644 (file)
 #include "detect-iprep.h"
 #include "detect-geoip.h"
 #include "detect-dns-query.h"
+#include "detect-app-layer-protocol.h"
 
 #include "util-rule-vars.h"
 
@@ -4756,6 +4757,7 @@ void SigTableSetup(void) {
     DetectLuajitRegister();
     DetectIPRepRegister();
     DetectDnsQueryRegister();
+    DetectAppLayerProtocolRegister();
 }
 
 void SigTableRegisterTests(void)
index 650f6be67d69950af7d616f25e3be2641e92c983..169d6752d9643100bcf45d963c2f901eef941809 100644 (file)
@@ -1104,6 +1104,7 @@ enum {
     DETECT_FILE_DATA,
     DETECT_PKT_DATA,
     DETECT_AL_APP_LAYER_EVENT,
+    DETECT_AL_APP_LAYER_PROTOCOL,
 
     DETECT_DCE_IFACE,
     DETECT_DCE_OPNUM,