diff --git a/src/Makefile.am b/src/Makefile.am index 498fa41e3a..4de0c41571 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 0000000000..2a604f9a87 --- /dev/null +++ b/src/detect-app-layer-protocol.c @@ -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 + */ + +#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 index 0000000000..07a34e519d --- /dev/null +++ b/src/detect-app-layer-protocol.h @@ -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 + */ + +#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__ */ diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index ca58f4917d..1e6cfd5c9a 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -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; } diff --git a/src/detect-parse.c b/src/detect-parse.c index 1c6debb024..b57149cc03 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -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))) { diff --git a/src/detect.c b/src/detect.c index 5eaf4c80cf..0341de593e 100644 --- a/src/detect.c +++ b/src/detect.c @@ -151,6 +151,7 @@ #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) diff --git a/src/detect.h b/src/detect.h index 650f6be67d..169d6752d9 100644 --- a/src/detect.h +++ b/src/detect.h @@ -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,