diff --git a/src/Makefile.am b/src/Makefile.am index 0b7cacd4c6..21f68a8096 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -104,6 +104,7 @@ util-mpm-b2g.c util-mpm-b2g.h \ util-mpm-b3g.c util-mpm-b3g.h \ util-cidr.c util-cidr.h \ util-unittest.c util-unittest.h \ +util-unittest-helper.c util-unittest-helper.h \ util-hash.c util-hash.h \ util-hashlist.c util-hashlist.h \ util-bloomfilter.c util-bloomfilter.h \ diff --git a/src/detect-content.c b/src/detect-content.c index 7e9474d9f9..483a0dd704 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -532,7 +532,6 @@ DoDetectContent(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signat } } - /* 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) && co->negated == 0) { diff --git a/src/detect-engine.h b/src/detect-engine.h index 3e46dbe4ac..88d510ed9c 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -2,11 +2,14 @@ #define __DETECT_ENGINE_H__ #include "detect.h" +#include "tm-modules.h" /* prototypes */ DetectEngineCtx *DetectEngineCtxInit(void); void DetectEngineCtxFree(DetectEngineCtx *); +TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **); +TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *); //inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *); /* faster as a macro than a inline function on my box -- VJ */ #define DetectEngineGetMaxSigId(de_ctx) ((de_ctx)->signum) diff --git a/src/detect-id.c b/src/detect-id.c index b76acd2a59..1f3cf51dc6 100644 --- a/src/detect-id.c +++ b/src/detect-id.c @@ -22,6 +22,7 @@ #include "util-debug.h" #include "util-unittest.h" +#include "util-unittest-helper.h" /** * \brief Regex for parsing "id" option, matching number or "number" @@ -301,298 +302,51 @@ int DetectIdTestParse04 (void) { } /** - * \test DetectIdTestPacket01 is a test to check "id" option with constructed - * packets, expecting to match - * Parse Id Data: expecting ip_id == 41158 - * The packet has ip_id == 41158 so it must match + * \test DetectIdTestSig01 + * \brief Test to check "id" keyword with constructed packets */ -int DetectIdTestPacket01 (void) { - DetectIdData *id_d = NULL; - - id_d = DetectIdParse(" 41158"); - if (id_d == NULL) { - SCLogDebug("DetectIdTestPacket01: expected a DetectIdData pointer" - " (got NULL)\n"); - return 0; - } - /* Buid and decode the packet */ - uint8_t raw_eth [] = { - 0x00, 0x14, 0xf8, 0x50, 0xf9, 0x09, 0x00, 0x10, - 0xdc, 0x4f, 0xe6, 0x09, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0xa0, 0xc6, 0x40, 0x00, 0x40, 0x06, - 0xab, 0x46, 0xc0, 0xa8, 0x00, 0xdc, 0x4b, 0x7d, - 0xe1, 0xad, 0xbe, 0x23, 0x00, 0x50, 0xf4, 0x66, - 0x71, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, - 0x16, 0xd0, 0x45, 0xf0, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x06, 0xae, - 0xd1, 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, - 0x03, 0x06 }; - - Packet q; - ThreadVars tv; - DecodeThreadVars dtv; - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&q, 0, sizeof(Packet)); - memset(&dtv, 0, sizeof(DecodeThreadVars)); - - FlowInitConfig(FLOW_QUIET); - DecodeEthernet(&tv, &dtv, &q, raw_eth, sizeof(raw_eth), NULL); - FlowShutdown(); - - Packet *p=&q; - - if (!(PKT_IS_IPV4(p))) { - SCLogDebug("detect-id: TestPacket01: Packet is not IPV4\n"); - return 0; - } - - DetectEngineThreadCtx *det_ctx=NULL; - Signature *s=NULL; - - SigMatch m; - m.ctx=id_d; - - /* Now that we have what we need, just try to Match! */ - return DetectIdMatch (&tv, det_ctx, p, s, &m); -} - -/** - * \test DetectIdTestPacket02 is a test to check "id" option with - * constructed packets - * Parse Id Data: expecting ip_id == 41159 - * The packet has ip_id == 41158 so it must NOT match - */ -int DetectIdTestPacket02 (void) { - DetectIdData *id_d = NULL; - - id_d = DetectIdParse("41159 "); - if (id_d == NULL) { - SCLogDebug("DetectIdTestPacket01: expected a DetectIdData pointer" - " (got NULL)\n"); - return 0; - } - /* Buid and decode the packet */ - uint8_t raw_eth [] = { - 0x00, 0x14, 0xf8, 0x50, 0xf9, 0x09, 0x00, 0x10, - 0xdc, 0x4f, 0xe6, 0x09, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0xa0, 0xc6, 0x40, 0x00, 0x40, 0x06, - 0xab, 0x46, 0xc0, 0xa8, 0x00, 0xdc, 0x4b, 0x7d, - 0xe1, 0xad, 0xbe, 0x23, 0x00, 0x50, 0xf4, 0x66, - 0x71, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, - 0x16, 0xd0, 0x45, 0xf0, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x06, 0xae, - 0xd1, 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, - 0x03, 0x06 }; - - Packet q; - ThreadVars tv; - DecodeThreadVars dtv; - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&q, 0, sizeof(Packet)); - memset(&dtv, 0, sizeof(DecodeThreadVars)); - - FlowInitConfig(FLOW_QUIET); - DecodeEthernet(&tv, &dtv, &q, raw_eth, sizeof(raw_eth), NULL); - FlowShutdown(); - - Packet *p=&q; - - if (!(PKT_IS_IPV4(p))) { - SCLogDebug("detect-id: TestPacket01: Packet is not IPV4\n"); - return 0; - } - - DetectEngineThreadCtx *det_ctx=NULL; - Signature *s=NULL; - - SigMatch m; - m.ctx=id_d; - - /* Now that we have what we need, just try "not" to Match! */ - if (DetectIdMatch (&tv, det_ctx, p, s, &m)) - return 0; - else - return 1; -} - -/** - * \test SigTest41IdKeyword01Real - * \brief Test to check "id" keyword with constructed packets, - * \brief expecting to match the ip->id - */ -int DetectIdTestSig1(void) { - int result = 1; - - // Buid and decode the packet - - uint8_t raw_eth [] = { - 0x00, 0x14, 0xf8, 0x50, 0xf9, 0x09, 0x00, 0x10, - 0xdc, 0x4f, 0xe6, 0x09, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0xa0, 0xc6, 0x40, 0x00, 0x40, 0x06, - 0xab, 0x46, 0xc0, 0xa8, 0x00, 0xdc, 0x4b, 0x7d, - 0xe1, 0xad, 0xbe, 0x23, 0x00, 0x50, 0xf4, 0x66, - 0x71, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, - 0x16, 0xd0, 0x45, 0xf0, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x06, 0xae, - 0xd1, 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, - 0x03, 0x06 }; - - Packet p; - DecodeThreadVars dtv; - - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - - memset(&p, 0, sizeof(Packet)); - memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&th_v, 0, sizeof(th_v)); - - FlowInitConfig(FLOW_QUIET); - DecodeEthernet(&th_v, &dtv, &p, raw_eth, sizeof(raw_eth), NULL); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - result = 0; - goto end; - } - - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any" - " (msg:\"SigTest41IdKeyword01 match\";" - " id:41158; sid:10141;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); - if (PacketAlertCheck(&p, 10141) == 0) { - result=0; +int DetectIdTestMatch01(void) { + int result = 0; + uint8_t *buf = (uint8_t *)"Hi all!"; + uint16_t buflen = strlen((char *)buf); + Packet *p[3]; + p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_UDP); + p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP); + + if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) goto end; - } - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - FlowShutdown(); - - return result; - -end: - if (de_ctx != NULL) { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } + /* TCP IP id = 1234 */ + p[0]->ip4h->ip_id = htons(1234); - if (det_ctx != NULL) { - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - } + /* UDP IP id = 5678 */ + p[1]->ip4h->ip_id = htons(5678); - if (de_ctx != NULL) { - DetectEngineCtxFree(de_ctx); - } + /* UDP IP id = 91011 */ + p[2]->ip4h->ip_id = htons(5101); - FlowShutdown(); + char *sigs[3]; + sigs[0]= "alert ip any any -> any any (msg:\"Testing id 1\"; id:1234; sid:1;)"; + sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; id:5678; sid:2;)"; + sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; id:5101; sid:3;)"; - return result; -} + uint32_t sid[3] = {1, 2, 3}; -/** - * \test - * \brief Test to check "id" keyword with constructed packets, - * \brief not expecting to match the ip->id - */ -int DetectIdTestSig2(void) { - int result = 1; - - // Buid and decode the packet - - uint8_t raw_eth [] = { - 0x00, 0x14, 0xf8, 0x50, 0xf9, 0x09, 0x00, 0x10, - 0xdc, 0x4f, 0xe6, 0x09, 0x08, 0x00, 0x45, 0x00, - 0x00, 0x3c, 0xa0, 0xc6, 0x40, 0x00, 0x40, 0x06, - 0xab, 0x46, 0xc0, 0xa8, 0x00, 0xdc, 0x4b, 0x7d, - 0xe1, 0xad, 0xbe, 0x23, 0x00, 0x50, 0xf4, 0x66, - 0x71, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, - 0x16, 0xd0, 0x45, 0xf0, 0x00, 0x00, 0x02, 0x04, - 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x06, 0xae, - 0xd1, 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, - 0x03, 0x06 }; - - Packet p; - DecodeThreadVars dtv; - - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - - memset(&p, 0, sizeof(Packet)); - memset(&dtv, 0, sizeof(DecodeThreadVars)); - memset(&th_v, 0, sizeof(th_v)); - - FlowInitConfig(FLOW_QUIET); - DecodeEthernet(&th_v, &dtv, &p, raw_eth, sizeof(raw_eth), NULL); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - result=0; - goto end; - } + uint32_t results[3][3] = { + /* packet 0 match sid 1 but should not match sid 2 */ + {1, 0, 0}, + /* packet 1 should not match */ + {0, 1, 0}, + /* packet 2 should not match */ + {0, 0, 1} }; - de_ctx->flags |= DE_QUIET; - - de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any" - " (msg:\"SigTest42IdKeyword02" - " I should not match!\";" - " id:41159; sid:10142;)"); - if (de_ctx->sig_list == NULL) { - result = 0; - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); - if (PacketAlertCheck(&p, 10142) == 1) { - result = 0; - goto end; - } - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - FlowShutdown(); - - return result; + result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 3); + UTHFreePackets(p, 3); end: - if (de_ctx) - { - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - } - - if (det_ctx) - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - - if (de_ctx) - DetectEngineCtxFree(de_ctx); - - FlowShutdown(); - return result; } - #endif /* UNITTESTS */ /** @@ -604,10 +358,7 @@ void DetectIdRegisterTests(void) { UtRegisterTest("DetectIdTestParse02", DetectIdTestParse02, 1); UtRegisterTest("DetectIdTestParse03", DetectIdTestParse03, 1); UtRegisterTest("DetectIdTestParse04", DetectIdTestParse04, 1); - UtRegisterTest("DetectIdTestPacket01", DetectIdTestPacket01 , 1); - UtRegisterTest("DetectIdTestPacket02", DetectIdTestPacket02 , 1); - UtRegisterTest("DetectIdTestSig1", DetectIdTestSig1, 1); - UtRegisterTest("DetectIdTestSig2", DetectIdTestSig2, 1); + UtRegisterTest("DetectIdTestMatch01", DetectIdTestMatch01, 1); #endif /* UNITTESTS */ } diff --git a/src/detect-ipproto.c b/src/detect-ipproto.c index f4afa1e7f7..0b37c3c8fa 100644 --- a/src/detect-ipproto.c +++ b/src/detect-ipproto.c @@ -23,6 +23,7 @@ #include "util-byte.h" #include "util-unittest.h" +#include "util-unittest-helper.h" #include "util-debug.h" @@ -521,83 +522,40 @@ end: } static int DetectIPProtoTestSig1(void) { + int result = 0; uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" "Host: one.example.org\r\n" "\r\n"; uint16_t buflen = strlen((char *)buf); - Packet p; - Signature *s = NULL; - 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; - - s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Not tcp\"; ip_proto:!tcp; content:\"GET \"; sid:1;)"); - if (s == NULL) { - goto end; - } - - s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Less than 7\"; content:\"GET \"; ip_proto:<7; sid:2;)"); - if (s == NULL) { - goto end; - } - - s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Greater than 5\"; content:\"GET \"; ip_proto:>5; sid:3;)"); - if (s == NULL) { + Packet *p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + if (p == NULL) goto end; - } - - s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Equals tcp\"; content:\"GET \"; ip_proto:tcp; sid:4;)"); - if (s == NULL) { - goto end; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, &p); - if (PacketAlertCheck(&p, 1)) { - printf("sid 1 alerted, but should not have: "); - goto cleanup; - } else if (PacketAlertCheck(&p, 2) == 0) { - printf("sid 2 did not alert, but should have: "); - goto cleanup; - } else if (PacketAlertCheck(&p, 3) == 0) { - printf("sid 3 did not alert, but should have: "); - goto cleanup; - } else if (PacketAlertCheck(&p, 4) == 0) { - printf("sid 4 did not alert, but should have: "); - goto cleanup; - } - - result = 1; - -cleanup: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); + char *sigs[4]; + sigs[0] = "alert ip any any -> any any (msg:\"Not tcp\"; ip_proto:!tcp; content:\"GET \"; sid:1;)"; + sigs[1] = "alert ip any any -> any any (msg:\"Less than 7\"; content:\"GET \"; ip_proto:<7; sid:2;)"; + sigs[2] = "alert ip any any -> any any (msg:\"Greater than 5\"; content:\"GET \"; ip_proto:>5; sid:3;)"; + sigs[3] = "alert ip any any -> any any (msg:\"Equals tcp\"; content:\"GET \"; ip_proto:tcp; sid:4;)"; + + /* sids to match */ + uint32_t sid[4] = {1, 2, 3, 4}; + /* expected matches for each sid within this packet we are testing */ + uint32_t results[4] = {0, 1, 1, 1}; + + /* remember that UTHGenericTest expect the first parameter + * as an array of packet pointers. And also a bidimensional array of results + * For example: + * results[numpacket][position] should hold the number of times + * that the sid at sid[position] matched that packet (should be always 1..) + * But here we built it as unidimensional array + */ + result = UTHGenericTest(&p, 1, sigs, sid, results, 4); + + UTHFreePacket(p); +end: DetectSigGroupPrintMemory(); DetectAddressPrintMemory(); - -end: return result; } diff --git a/src/detect-isdataat.c b/src/detect-isdataat.c index f9b9882705..76700c6722 100644 --- a/src/detect-isdataat.c +++ b/src/detect-isdataat.c @@ -2,7 +2,7 @@ * \file * \author Pablo Rincon * - * ISDATAAT part of the detection engine. + * Isdataat: part of the detection engine. */ #include "suricata-common.h" @@ -11,6 +11,7 @@ #include "detect.h" #include "util-unittest.h" +#include "util-unittest-helper.h" #include "detect-isdataat.h" #include "detect-content.h" @@ -83,18 +84,20 @@ error: int DetectIsdataatMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectIsdataatData *idad = (DetectIsdataatData *)m->ctx; - int ret=0; SCLogDebug("payload_len: %u , dataat? %u ; relative? %u...", p->payload_len,idad->dataat,idad->flags &ISDATAAT_RELATIVE); - /* Relative to the last matched content is not performed here */ - if(!(idad->flags & ISDATAAT_RELATIVE) && p->payload_len >= idad->dataat) { - ret = 1; /* its not relative and we have more data in the packet than the offset of isdataat */ + /* Relative to the last matched content is not performed here, returning match (content should take care of this)*/ + if (idad->flags & ISDATAAT_RELATIVE) + return 1; + /* its not relative and we have more data in the packet than the offset of isdataat */ + if (p->payload_len >= idad->dataat) { SCLogDebug("matched with payload_len: %u , dataat? %u ; relative? %u...", p->payload_len,idad->dataat,idad->flags &ISDATAAT_RELATIVE); + return 1; } - return ret; + return 0; } /** @@ -328,192 +331,44 @@ int DetectIsdataatTestParse03 (void) { } /** - * \test DetectIsdataatTestPacket01 is a test to check if the packet has data at 50 bytes offset non relative - * + * \test DetectIsdataatTestPacket01 is a test to check matches of + * isdataat, and isdataat relative */ - int DetectIsdataatTestPacket01 (void) { int result = 0; - DetectIsdataatData *idad = NULL; - - /// Parse Isdataat Data: if packet data len is greater or equal than 50 byte it should match - /// The packet has 190 bytes of data so it must match - idad = DetectIsdataatParse("50"); - if (idad == NULL) { - printf("DetectIsdataatTestPacket01: expected a DetectIsdataatData pointer (got NULL)\n"); - return 0; - } - /* Buid and decode the packet */ - uint8_t raw_eth [] = { - 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 - ,0x01,0xcc,0xcb,0x91,0x00,0x00,0x34,0x06,0xdf,0xa8,0xd1,0x55,0xe3,0x67,0xc0,0xa8 - ,0x64,0x8c,0x00,0x50,0xc0,0xb7,0xd1,0x11,0xed,0x63,0x81,0xa9,0x9a,0x05,0x80,0x18 - ,0x00,0x75,0x0a,0xdd,0x00,0x00,0x01,0x01,0x08,0x0a,0x09,0x8a,0x06,0xd0,0x12,0x21 - ,0x2a,0x3b,0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x33,0x30,0x32,0x20,0x46 - ,0x6f,0x75,0x6e,0x64,0x0d,0x0a,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x20 - ,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c - ,0x65,0x2e,0x65,0x73,0x2f,0x0d,0x0a,0x43,0x61,0x63,0x68,0x65,0x2d,0x43,0x6f,0x6e - ,0x74,0x72,0x6f,0x6c,0x3a,0x20,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x0d,0x0a,0x43 - ,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78 - ,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d - ,0x55,0x54,0x46,0x2d,0x38,0x0d,0x0a,0x44,0x61,0x74,0x65,0x3a,0x20,0x4d,0x6f,0x6e - ,0x2c,0x20,0x31,0x34,0x20,0x53,0x65,0x70,0x20,0x32,0x30,0x30,0x39,0x20,0x30,0x38 - ,0x3a,0x34,0x38,0x3a,0x33,0x31,0x20,0x47,0x4d,0x54,0x0d,0x0a,0x53,0x65,0x72,0x76 - ,0x65,0x72,0x3a,0x20,0x67,0x77,0x73,0x0d,0x0a,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74 - ,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x32,0x31,0x38,0x0d,0x0a,0x0d,0x0a - ,0x3c,0x48,0x54,0x4d,0x4c,0x3e,0x3c,0x48,0x45,0x41,0x44,0x3e,0x3c,0x6d,0x65,0x74 - ,0x61,0x20,0x68,0x74,0x74,0x70,0x2d,0x65,0x71,0x75,0x69,0x76,0x3d,0x22,0x63,0x6f - ,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x22,0x20,0x63,0x6f,0x6e,0x74 - ,0x65,0x6e,0x74,0x3d,0x22,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x63 - ,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x22,0x3e,0x0a,0x3c - ,0x54,0x49,0x54,0x4c,0x45,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76,0x65,0x64,0x3c - ,0x2f,0x54,0x49,0x54,0x4c,0x45,0x3e,0x3c,0x2f,0x48,0x45,0x41,0x44,0x3e,0x3c,0x42 - ,0x4f,0x44,0x59,0x3e,0x0a,0x3c,0x48,0x31,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76 - ,0x65,0x64,0x3c,0x2f,0x48,0x31,0x3e,0x0a,0x54,0x68,0x65,0x20,0x64,0x6f,0x63,0x75 - ,0x6d,0x65,0x6e,0x74,0x20,0x68,0x61,0x73,0x20,0x6d,0x6f,0x76,0x65,0x64,0x0a,0x3c - ,0x41,0x20,0x48,0x52,0x45,0x46,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77 - ,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x65,0x73,0x2f,0x22,0x3e,0x68 - ,0x65,0x72,0x65,0x3c,0x2f,0x41,0x3e,0x2e,0x0d,0x0a,0x3c,0x2f,0x42,0x4f,0x44,0x59 - ,0x3e,0x3c,0x2f,0x48,0x54,0x4d,0x4c,0x3e,0x0d,0x0a }; - - Packet q; - ThreadVars tv; - DecodeThreadVars dtv; - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&q, 0, sizeof(Packet)); - memset(&dtv, 0, sizeof(DecodeThreadVars)); - - FlowInitConfig(FLOW_QUIET); - DecodeEthernet(&tv, &dtv, &q, raw_eth, sizeof(raw_eth), NULL); - FlowShutdown(); - - Packet *p=&q; - - if (!(PKT_IS_TCP(p))) { - printf("detect-window: TestPacket01: Packet is not TCP\n"); - return 0; - } - - - /* We dont need DetectEngineThreadCtx inside DetectIsdataatMatch, its just to pass it to - the function, since this is a test for this option - Also a Signature is not really needed - */ - - DetectEngineThreadCtx *det_ctx=NULL; - Signature *s=NULL; - - /* The data of DetectIsdataatData is retrieved inside DetectIsdataatMatch - from a SigMatch struct, so creating a temporal SigMatch - */ - SigMatch m; - m.ctx=idad; - - /* Now that we have what we need, just try to Match! */ - result=DetectIsdataatMatch (&tv, det_ctx, p, s, &m); - - return result; -} - - -/** - * \test DetectIsdataatTestPacket02 is a test to check if the packet match 6000 bytes offset non relative (it wont) - * - */ - -int DetectIsdataatTestPacket02 (void) { - int result = 0; - DetectIsdataatData *idad = NULL; - - /// Parse Isdataat Data: if packet data len is greater or equal than 6000 byte it should match - /// The packet has 190 bytes of data so it must not match - idad = DetectIsdataatParse("6000"); - if (idad == NULL) - { - printf("DetectIsdataatTestPacket01: expected a DetectIsdataatData pointer (got NULL)\n"); - return 0; - } - /* Buid and decode the packet */ - uint8_t raw_eth [] = { - 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 - ,0x01,0xcc,0xcb,0x91,0x00,0x00,0x34,0x06,0xdf,0xa8,0xd1,0x55,0xe3,0x67,0xc0,0xa8 - ,0x64,0x8c,0x00,0x50,0xc0,0xb7,0xd1,0x11,0xed,0x63,0x81,0xa9,0x9a,0x05,0x80,0x18 - ,0x00,0x75,0x0a,0xdd,0x00,0x00,0x01,0x01,0x08,0x0a,0x09,0x8a,0x06,0xd0,0x12,0x21 - ,0x2a,0x3b,0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x33,0x30,0x32,0x20,0x46 - ,0x6f,0x75,0x6e,0x64,0x0d,0x0a,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x20 - ,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c - ,0x65,0x2e,0x65,0x73,0x2f,0x0d,0x0a,0x43,0x61,0x63,0x68,0x65,0x2d,0x43,0x6f,0x6e - ,0x74,0x72,0x6f,0x6c,0x3a,0x20,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x0d,0x0a,0x43 - ,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78 - ,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d - ,0x55,0x54,0x46,0x2d,0x38,0x0d,0x0a,0x44,0x61,0x74,0x65,0x3a,0x20,0x4d,0x6f,0x6e - ,0x2c,0x20,0x31,0x34,0x20,0x53,0x65,0x70,0x20,0x32,0x30,0x30,0x39,0x20,0x30,0x38 - ,0x3a,0x34,0x38,0x3a,0x33,0x31,0x20,0x47,0x4d,0x54,0x0d,0x0a,0x53,0x65,0x72,0x76 - ,0x65,0x72,0x3a,0x20,0x67,0x77,0x73,0x0d,0x0a,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74 - ,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x32,0x31,0x38,0x0d,0x0a,0x0d,0x0a - ,0x3c,0x48,0x54,0x4d,0x4c,0x3e,0x3c,0x48,0x45,0x41,0x44,0x3e,0x3c,0x6d,0x65,0x74 - ,0x61,0x20,0x68,0x74,0x74,0x70,0x2d,0x65,0x71,0x75,0x69,0x76,0x3d,0x22,0x63,0x6f - ,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x22,0x20,0x63,0x6f,0x6e,0x74 - ,0x65,0x6e,0x74,0x3d,0x22,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x63 - ,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x22,0x3e,0x0a,0x3c - ,0x54,0x49,0x54,0x4c,0x45,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76,0x65,0x64,0x3c - ,0x2f,0x54,0x49,0x54,0x4c,0x45,0x3e,0x3c,0x2f,0x48,0x45,0x41,0x44,0x3e,0x3c,0x42 - ,0x4f,0x44,0x59,0x3e,0x0a,0x3c,0x48,0x31,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76 - ,0x65,0x64,0x3c,0x2f,0x48,0x31,0x3e,0x0a,0x54,0x68,0x65,0x20,0x64,0x6f,0x63,0x75 - ,0x6d,0x65,0x6e,0x74,0x20,0x68,0x61,0x73,0x20,0x6d,0x6f,0x76,0x65,0x64,0x0a,0x3c - ,0x41,0x20,0x48,0x52,0x45,0x46,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77 - ,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x65,0x73,0x2f,0x22,0x3e,0x68 - ,0x65,0x72,0x65,0x3c,0x2f,0x41,0x3e,0x2e,0x0d,0x0a,0x3c,0x2f,0x42,0x4f,0x44,0x59 - ,0x3e,0x3c,0x2f,0x48,0x54,0x4d,0x4c,0x3e,0x0d,0x0a }; - - Packet q; - ThreadVars tv; - DecodeThreadVars dtv; - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&q, 0, sizeof(Packet)); - memset(&dtv, 0, sizeof(DecodeThreadVars)); - - FlowInitConfig(FLOW_QUIET); - DecodeEthernet(&tv, &dtv, &q, raw_eth, sizeof(raw_eth), NULL); - FlowShutdown(); - - Packet *p=&q; - - if (!(PKT_IS_TCP(p))) { - printf("detect-window: TestPacket02: Packet is not TCP\n"); - return 0; - } - - - /* We dont need DetectEngineThreadCtx inside DetectIsdataatMatch, its just to pass it to - the function, since this is a test for this option - Also a Signature is not really needed - */ - - DetectEngineThreadCtx *det_ctx=NULL; - Signature *s=NULL; - - /* The data of DetectIsdataatData is retrieved inside DetectIsdataatMatch - from a SigMatch struct, so creating a temporal SigMatch - */ - - SigMatch m; - - m.ctx=idad; - - /* Now that we have what we need, just try to Match! */ - result=DetectIsdataatMatch (&tv, det_ctx, p, s, &m); - - /* Invert it, we dont want this packet to match */ - result=!result; - if(result==0) - printf("detect-isdataat: It has matched with isdataat 6000, expecting not to match\n"); - + uint8_t *buf = (uint8_t *)"Hi all!"; + uint16_t buflen = strlen((char *)buf); + Packet *p[3]; + p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_UDP); + p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP); + + if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) + goto end; + + char *sigs[5]; + sigs[0]= "alert ip any any -> any any (msg:\"Testing window 1\"; isdataat:6; sid:1;)"; + sigs[1]= "alert ip any any -> any any (msg:\"Testing window 2\"; content:\"all\"; isdataat:1, relative; isdataat:7; sid:2;)"; + sigs[2]= "alert ip any any -> any any (msg:\"Testing window 3\"; isdataat:8; sid:3;)"; + sigs[3]= "alert ip any any -> any any (msg:\"Testing window 4\"; content:\"Hi\"; isdataat:5, relative; sid:4;)"; + sigs[4]= "alert ip any any -> any any (msg:\"Testing window 4\"; content:\"Hi\"; isdataat:6, relative; sid:5;)"; + + uint32_t sid[5] = {1, 2, 3, 4, 5}; + + uint32_t results[3][5] = { + /* packet 0 match sid 1 but should not match sid 2 */ + {1, 1, 0, 1, 0}, + /* packet 1 should not match */ + {1, 1, 0, 1, 0}, + /* packet 2 should not match */ + {1, 1, 0, 1, 0} }; + + result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 5); + + UTHFreePackets(p, 3); +end: return result; } - #endif /** @@ -525,6 +380,5 @@ void DetectIsdataatRegisterTests(void) { UtRegisterTest("DetectIsdataatTestParse02", DetectIsdataatTestParse02, 1); UtRegisterTest("DetectIsdataatTestParse03", DetectIsdataatTestParse03, 1); UtRegisterTest("DetectIsdataatTestPacket01", DetectIsdataatTestPacket01, 1); - UtRegisterTest("DetectIsdataatTestPacket02", DetectIsdataatTestPacket02, 1); #endif } diff --git a/src/detect-parse.c b/src/detect-parse.c index b07b3fb6dc..85a5e2bd22 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -541,10 +541,10 @@ int SigParse(DetectEngineCtx *de_ctx, Signature *s, char *sigstr, uint8_t addrs_ if (basics != NULL) { int i = 0; while (basics[i] != NULL) { - free(basics[i]); + //free(basics[i]); i++; } - free(basics); + //free(basics); } SCReturnInt(ret); @@ -825,14 +825,16 @@ error: Signature *DetectEngineAppendSig(DetectEngineCtx *de_ctx, char *sigstr) { Signature *sig = SigInitReal(de_ctx, sigstr); if (sig == NULL) - goto error; + return NULL; if (sig->flags & SIG_FLAG_BIDIREC) { - if (sig->next != NULL) + if (sig->next != NULL) { sig->next->next = de_ctx->sig_list; - else + } else { goto error; - } else { + } + } + else { /* if this sig is the first one, sig_list should be null */ sig->next = de_ctx->sig_list; } diff --git a/src/detect-seq.c b/src/detect-seq.c index 64e70b9e8e..519b11e5b8 100644 --- a/src/detect-seq.c +++ b/src/detect-seq.c @@ -20,6 +20,7 @@ #include "util-byte.h" #include "util-unittest.h" +#include "util-unittest-helper.h" static int DetectSeqSetup(DetectEngineCtx *, Signature *s, SigMatch *m, char *sidstr); @@ -124,70 +125,16 @@ static void DetectSeqFree(void *ptr) #ifdef UNITTESTS + /** - * \internal - * \brief This test tests sameip success and failure. + * \test DetectSeqSigTest01 tests parses */ -static int DetectSeqSigTest01Real(int mpm_type) +static int DetectSeqSigTest01(void) { - uint8_t *buf = (uint8_t *)""; - uint16_t buflen = strlen((char *)buf); - Packet p[3]; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx; int result = 0; - uint8_t tcp_hdr0[] = { - 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, - 0xcf, 0x0d, 0x21, 0x80, 0xa0, 0x12, 0x16, 0xa0, - 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, - 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, - 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x02 - }; - uint8_t tcp_hdr1[] = { - 0x00, 0x50, 0x8e, 0x16, 0x0d, 0x59, 0xcd, 0x3c, - 0xcf, 0x0d, 0x21, 0x80, 0xa0, 0x12, 0x16, 0xa0, - 0xfa, 0x03, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, - 0x04, 0x02, 0x08, 0x0a, 0x6e, 0x18, 0x78, 0x73, - 0x01, 0x71, 0x74, 0xde, 0x01, 0x03, 0x03, 0x02 - }; - - memset(&th_v, 0, sizeof(th_v)); - - /* TCP w/seq=42 */ - memset(&p[0], 0, sizeof(p[0])); - p[0].src.family = AF_INET; - p[0].dst.family = AF_INET; - p[0].payload = buf; - p[0].payload_len = buflen; - p[0].proto = IPPROTO_TCP; - p[0].tcph = (TCPHdr *)tcp_hdr0; - p[0].tcph->th_seq = htonl(42); - - /* TCP w/seq=100 */ - memset(&p[1], 0, sizeof(p[1])); - p[1].src.family = AF_INET; - p[1].dst.family = AF_INET; - p[1].payload = buf; - p[1].payload_len = buflen; - p[1].proto = IPPROTO_TCP; - p[1].tcph = (TCPHdr *)tcp_hdr1; - p[1].tcph->th_seq = htonl(100); - - /* ICMP */ - memset(&p[2], 0, sizeof(p[2])); - p[2].src.family = AF_INET; - p[2].dst.family = AF_INET; - p[2].payload = buf; - p[2].payload_len = buflen; - p[2].proto = IPPROTO_ICMP; - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { + if (de_ctx == NULL) goto end; - } - - de_ctx->mpm_matcher = mpm_type; - de_ctx->flags |= DE_QUIET; /* These three are crammed in here as there is no Parse */ if (SigInit(de_ctx, @@ -195,107 +142,73 @@ static int DetectSeqSigTest01Real(int mpm_type) "(msg:\"Testing seq\";seq:foo;sid:1;)") != NULL) { printf("invalid seq accepted: "); - goto cleanup_engine; + goto cleanup; } if (SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing seq\";seq:9999999999;sid:1;)") != NULL) { printf("overflowing seq accepted: "); - goto cleanup_engine; + goto cleanup; } if (SigInit(de_ctx, "alert tcp any any -> any any " "(msg:\"Testing seq\";seq:-100;sid:1;)") != NULL) { printf("negative seq accepted: "); - goto cleanup_engine; - } - - de_ctx->sig_list = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing seq\";seq:41;sid:1;)"); - if (de_ctx->sig_list == NULL) { - goto cleanup_engine; - } - - de_ctx->sig_list->next = SigInit(de_ctx, - "alert tcp any any -> any any " - "(msg:\"Testing seq\";seq:42;sid:2;)"); - if (de_ctx->sig_list->next == NULL) { - goto cleanup_engine; - } - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - - SigMatchSignatures(&th_v, de_ctx, det_ctx, &p[0]); - if (PacketAlertCheck(&p[0], 1) != 0) { - printf("sid 1 alerted, but should not have: "); - goto cleanup; - } - if (PacketAlertCheck(&p[0], 2) == 0) { - printf("sid 2 did not alert, but should have: "); goto cleanup; } - - SigMatchSignatures(&th_v, de_ctx, det_ctx, &p[1]); - if (PacketAlertCheck(&p[1], 1) != 0) { - printf("sid 1 alerted, but should not have: "); - goto cleanup; - } - if (PacketAlertCheck(&p[1], 2) != 0) { - printf("sid 2 alerted, but should not have: "); - goto cleanup; - } - - SigMatchSignatures(&th_v, de_ctx, det_ctx, &p[1]); - if (PacketAlertCheck(&p[2], 1) != 0) { - printf("sid 1 alerted, but should not have: "); - goto cleanup; - } - if (PacketAlertCheck(&p[2], 2) != 0) { - printf("sid 2 alerted, but should not have: "); - goto cleanup; - } - result = 1; cleanup: - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); - - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - -cleanup_engine: - DetectEngineCtxFree(de_ctx); - + if (de_ctx) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } end: return result; } /** - * \test DetectSeqSigTest01B2g tests sameip under B2g MPM + * \test DetectSeqSigTest02 tests seq keyword */ -static int DetectSeqSigTest01B2g(void) +static int DetectSeqSigTest02(void) { - return DetectSeqSigTest01Real(MPM_B2G); -} + int result = 0; + uint8_t *buf = (uint8_t *)"Hi all!"; + uint16_t buflen = strlen((char *)buf); + Packet *p[3]; + p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP); + if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) + goto end; -/** - * \test DetectSeqSigTest01B2g tests sameip under B3g MPM - */ -static int DetectSeqSigTest01B3g(void) -{ - return DetectSeqSigTest01Real(MPM_B3G); -} + /* TCP w/seq=42 */ + p[0]->tcph->th_seq = htonl(42); -/** - * \test DetectSeqSigTest01B2g tests sameip under WuManber MPM - */ -static int DetectSeqSigTest01Wm(void) -{ - return DetectSeqSigTest01Real(MPM_WUMANBER); + /* TCP w/seq=100 */ + p[1]->tcph->th_seq = htonl(100); + + char *sigs[2]; + sigs[0]= "alert tcp any any -> any any (msg:\"Testing seq\"; seq:41; sid:1;)"; + sigs[1]= "alert tcp any any -> any any (msg:\"Testing seq\"; seq:42; sid:2;)"; + + uint32_t sid[2] = {1, 2}; + + uint32_t results[3][2] = { + /* packet 0 match sid 1 but should not match sid 2 */ + {0, 1}, + /* packet 1 should not match */ + {0, 0}, + /* packet 2 should not match */ + {0, 0} }; + + result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 2); + UTHFreePackets(p, 3); +end: + return result; } #endif /* UNITTESTS */ @@ -307,9 +220,8 @@ static int DetectSeqSigTest01Wm(void) static void DetectSeqRegisterTests(void) { #ifdef UNITTESTS - UtRegisterTest("DetectSeqSigTest01B2g", DetectSeqSigTest01B2g, 1); - UtRegisterTest("DetectSeqSigTest01B3g", DetectSeqSigTest01B3g, 1); - UtRegisterTest("DetectSeqSigTest01Wm", DetectSeqSigTest01Wm, 1); + UtRegisterTest("DetectSeqSigTest01", DetectSeqSigTest01, 1); + UtRegisterTest("DetectSeqSigTest02", DetectSeqSigTest02, 1); #endif /* UNITTESTS */ } diff --git a/src/detect-window.c b/src/detect-window.c index da7e4fc1ad..42f08cba83 100644 --- a/src/detect-window.c +++ b/src/detect-window.c @@ -14,7 +14,10 @@ #include "flow.h" #include "flow-var.h" +#include "util-debug.h" #include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-byte.h" /** * \brief Regex for parsing our window option @@ -24,8 +27,8 @@ static pcre *parse_regex; static pcre_extra *parse_regex_study; -int DetectWindowMatch (ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); -int DetectWindowSetup (DetectEngineCtx *, Signature *, SigMatch *, char *); +int DetectWindowMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *); +int DetectWindowSetup(DetectEngineCtx *, Signature *, SigMatch *, char *); void DetectWindowRegisterTests(void); void DetectWindowFree(void *); @@ -78,32 +81,17 @@ error: * \retval 0 no match * \retval 1 match */ -int DetectWindowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) -{ - int ret=0; +int DetectWindowMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, SigMatch *m) { DetectWindowData *wd = (DetectWindowData *)m->ctx; + if ( !(PKT_IS_TCP(p)) || wd == NULL) { + return 0; + } - if(wd != NULL) - { - - /** - * To match a packet with a widow size rule, we need a TCP packet, - * and we must look if the size is negated or not - */ - if (!(PKT_IS_TCP(p))) { - return 0; - } - - if((!wd->negated && wd->size==TCP_GET_WINDOW(p)) || (wd->negated && wd->size!=TCP_GET_WINDOW(p))) - { - #ifdef WINDOW_DEBUG - printf("detect-window: packet is TCP Proto and matched with packet window size %d and rule option size %d negated: %d!!!\n", TCP_GET_WINDOW(p), wd->size, wd->negated); - #endif - ret=1; - } + if ( (!wd->negated && wd->size == TCP_GET_WINDOW(p)) || (wd->negated && wd->size != TCP_GET_WINDOW(p))) { + return 1; } - return ret; + return 0; } /** @@ -114,8 +102,7 @@ int DetectWindowMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, * \retval wd pointer to DetectWindowData on success * \retval NULL on failure */ -DetectWindowData *DetectWindowParse (char *windowstr) -{ +DetectWindowData *DetectWindowParse(char *windowstr) { DetectWindowData *wd = NULL; char *args[3] = {NULL,NULL,NULL}; /* PR: Why PCRE MAX_SUBSTRING must be multiple of 3? */ #define MAX_SUBSTRINGS 30 @@ -145,16 +132,11 @@ DetectWindowData *DetectWindowParse (char *windowstr) goto error; } args[0] = (char *)str_ptr; - // Detect if it's negated - if(args[0][0]=='!') - wd->negated=1; + /* Detect if it's negated */ + if (args[0][0] == '!') + wd->negated = 1; else - wd->negated=0; - -#ifdef WINDOW_DEBUG - if(wd->negated) - printf("detect-window: Negation: %s\n", windowstr); -#endif + wd->negated = 0; if (ret > 2) { res = pcre_get_substring((char *)windowstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); @@ -162,21 +144,20 @@ DetectWindowData *DetectWindowParse (char *windowstr) printf("DetectWindowParse: pcre_get_substring failed\n"); goto error; } - wd->size = atoi((char *)str_ptr); - // Get the window size if it's a valid value (in packets, we should alert if this doesn't happend from decode) - if(wd->size > MAX_WINDOW_VALUE) - { + /* Get the window size if it's a valid value (in packets, we should alert if this doesn't happend from decode) */ + if (-1 == ByteExtractStringUint16(&wd->size, 10, 0, str_ptr)) { goto error; } -#ifdef WINDOW_DEBUG - printf("detect-window: window size-> %u\n", wd->size); -#endif + /* If greater than 1GB window */ + if (wd->size < MIN_WINDOW_VALUE || wd->size > MAX_WINDOW_VALUE) { + goto error; + } } } - int i=0; + int i = 0; for (i = 0; i < (ret -1); i++){ if (args[i] != NULL) free(args[i]); } @@ -310,172 +291,44 @@ int DetectWindowTestParse04 (void) { return result; } - /** - * \test DetectWindowTestPacket01 is a test to check window with constructed packets, expecting to match a negated size - * Parse Window Data: if th_win is not 55455 it should Match! - * The packet is less than 55455 so it must match + * \test DetectWindowTestPacket01 is a test to check window with constructed packets */ - int DetectWindowTestPacket01 (void) { int result = 0; - DetectWindowData *wd = NULL; - - - wd = DetectWindowParse("!55455"); - if (wd == NULL) - { - printf("DetectWindowTestPacket01: expected a DetectWindowData pointer (got NULL)\n"); - return 0; - } - /* Buid and decode the packet */ - uint8_t raw_eth [] = { - 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 - ,0x01,0xcc,0xcb,0x91,0x00,0x00,0x34,0x06,0xdf,0xa8,0xd1,0x55,0xe3,0x67,0xc0,0xa8 - ,0x64,0x8c,0x00,0x50,0xc0,0xb7,0xd1,0x11,0xed,0x63,0x81,0xa9,0x9a,0x05,0x80,0x18 - ,0x00,0x75,0x0a,0xdd,0x00,0x00,0x01,0x01,0x08,0x0a,0x09,0x8a,0x06,0xd0,0x12,0x21 - ,0x2a,0x3b,0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x33,0x30,0x32,0x20,0x46 - ,0x6f,0x75,0x6e,0x64,0x0d,0x0a,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x20 - ,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c - ,0x65,0x2e,0x65,0x73,0x2f,0x0d,0x0a,0x43,0x61,0x63,0x68,0x65,0x2d,0x43,0x6f,0x6e - ,0x74,0x72,0x6f,0x6c,0x3a,0x20,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x0d,0x0a,0x43 - ,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78 - ,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d - ,0x55,0x54,0x46,0x2d,0x38,0x0d,0x0a,0x44,0x61,0x74,0x65,0x3a,0x20,0x4d,0x6f,0x6e - ,0x2c,0x20,0x31,0x34,0x20,0x53,0x65,0x70,0x20,0x32,0x30,0x30,0x39,0x20,0x30,0x38 - ,0x3a,0x34,0x38,0x3a,0x33,0x31,0x20,0x47,0x4d,0x54,0x0d,0x0a,0x53,0x65,0x72,0x76 - ,0x65,0x72,0x3a,0x20,0x67,0x77,0x73,0x0d,0x0a,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74 - ,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x32,0x31,0x38,0x0d,0x0a,0x0d,0x0a - ,0x3c,0x48,0x54,0x4d,0x4c,0x3e,0x3c,0x48,0x45,0x41,0x44,0x3e,0x3c,0x6d,0x65,0x74 - ,0x61,0x20,0x68,0x74,0x74,0x70,0x2d,0x65,0x71,0x75,0x69,0x76,0x3d,0x22,0x63,0x6f - ,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x22,0x20,0x63,0x6f,0x6e,0x74 - ,0x65,0x6e,0x74,0x3d,0x22,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x63 - ,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x22,0x3e,0x0a,0x3c - ,0x54,0x49,0x54,0x4c,0x45,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76,0x65,0x64,0x3c - ,0x2f,0x54,0x49,0x54,0x4c,0x45,0x3e,0x3c,0x2f,0x48,0x45,0x41,0x44,0x3e,0x3c,0x42 - ,0x4f,0x44,0x59,0x3e,0x0a,0x3c,0x48,0x31,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76 - ,0x65,0x64,0x3c,0x2f,0x48,0x31,0x3e,0x0a,0x54,0x68,0x65,0x20,0x64,0x6f,0x63,0x75 - ,0x6d,0x65,0x6e,0x74,0x20,0x68,0x61,0x73,0x20,0x6d,0x6f,0x76,0x65,0x64,0x0a,0x3c - ,0x41,0x20,0x48,0x52,0x45,0x46,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77 - ,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x65,0x73,0x2f,0x22,0x3e,0x68 - ,0x65,0x72,0x65,0x3c,0x2f,0x41,0x3e,0x2e,0x0d,0x0a,0x3c,0x2f,0x42,0x4f,0x44,0x59 - ,0x3e,0x3c,0x2f,0x48,0x54,0x4d,0x4c,0x3e,0x0d,0x0a }; - - Packet q; - ThreadVars tv; - DecodeThreadVars dtv; - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&q, 0, sizeof(Packet)); - memset(&dtv, 0, sizeof(DecodeThreadVars)); - - FlowInitConfig(FLOW_QUIET); - DecodeEthernet(&tv, &dtv, &q, raw_eth, sizeof(raw_eth), NULL); - FlowShutdown(); - - Packet *p=&q; - - if (!(PKT_IS_TCP(p))) { - printf("detect-window: TestPacket01: Packet is not TCP\n"); - return 0; - } - - - /* We dont need DetectEngineThreadCtx inside DetectWindowMatch, its just to pass it to - the function, since this is a test for this option - Also a Signature is not really needed - */ - - DetectEngineThreadCtx *det_ctx=NULL; - Signature *s=NULL; - - SigMatch m; - m.ctx=wd; - - /* Now that we have what we need, just try to Match! */ - result=DetectWindowMatch (&tv, det_ctx, p, s, &m); - - return result; -} - - -/** - * \test DetectWindowTestPacket02 is a test to check window with constructed packets, expecting to match a size - * Parse Window Data: if th_win is 190 it should Match! - * The packet tcp window is 190 so it must match - */ - -int DetectWindowTestPacket02 (void) { - int result = 0; - DetectWindowData *wd = NULL; - - wd = DetectWindowParse("117"); - if (wd == NULL) - { - printf("DetectWindowTestPacket02: expected a DetectWindowData pointer (got NULL)\n"); - return 0; - } - - uint8_t raw_eth [] = { - 0x00,0x25,0x00,0x9e,0xfa,0xfe,0x00,0x02,0xcf,0x74,0xfe,0xe1,0x08,0x00,0x45,0x00 - ,0x01,0xcc,0xcb,0x91,0x00,0x00,0x34,0x06,0xdf,0xa8,0xd1,0x55,0xe3,0x67,0xc0,0xa8 - ,0x64,0x8c,0x00,0x50,0xc0,0xb7,0xd1,0x11,0xed,0x63,0x81,0xa9,0x9a,0x05,0x80,0x18 - ,0x00,0x75,0x0a,0xdd,0x00,0x00,0x01,0x01,0x08,0x0a,0x09,0x8a,0x06,0xd0,0x12,0x21 - ,0x2a,0x3b,0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x31,0x20,0x33,0x30,0x32,0x20,0x46 - ,0x6f,0x75,0x6e,0x64,0x0d,0x0a,0x4c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x3a,0x20 - ,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c - ,0x65,0x2e,0x65,0x73,0x2f,0x0d,0x0a,0x43,0x61,0x63,0x68,0x65,0x2d,0x43,0x6f,0x6e - ,0x74,0x72,0x6f,0x6c,0x3a,0x20,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x0d,0x0a,0x43 - ,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x54,0x79,0x70,0x65,0x3a,0x20,0x74,0x65,0x78 - ,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x20,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x3d - ,0x55,0x54,0x46,0x2d,0x38,0x0d,0x0a,0x44,0x61,0x74,0x65,0x3a,0x20,0x4d,0x6f,0x6e - ,0x2c,0x20,0x31,0x34,0x20,0x53,0x65,0x70,0x20,0x32,0x30,0x30,0x39,0x20,0x30,0x38 - ,0x3a,0x34,0x38,0x3a,0x33,0x31,0x20,0x47,0x4d,0x54,0x0d,0x0a,0x53,0x65,0x72,0x76 - ,0x65,0x72,0x3a,0x20,0x67,0x77,0x73,0x0d,0x0a,0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74 - ,0x2d,0x4c,0x65,0x6e,0x67,0x74,0x68,0x3a,0x20,0x32,0x31,0x38,0x0d,0x0a,0x0d,0x0a - ,0x3c,0x48,0x54,0x4d,0x4c,0x3e,0x3c,0x48,0x45,0x41,0x44,0x3e,0x3c,0x6d,0x65,0x74 - ,0x61,0x20,0x68,0x74,0x74,0x70,0x2d,0x65,0x71,0x75,0x69,0x76,0x3d,0x22,0x63,0x6f - ,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x22,0x20,0x63,0x6f,0x6e,0x74 - ,0x65,0x6e,0x74,0x3d,0x22,0x74,0x65,0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x3b,0x63 - ,0x68,0x61,0x72,0x73,0x65,0x74,0x3d,0x75,0x74,0x66,0x2d,0x38,0x22,0x3e,0x0a,0x3c - ,0x54,0x49,0x54,0x4c,0x45,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76,0x65,0x64,0x3c - ,0x2f,0x54,0x49,0x54,0x4c,0x45,0x3e,0x3c,0x2f,0x48,0x45,0x41,0x44,0x3e,0x3c,0x42 - ,0x4f,0x44,0x59,0x3e,0x0a,0x3c,0x48,0x31,0x3e,0x33,0x30,0x32,0x20,0x4d,0x6f,0x76 - ,0x65,0x64,0x3c,0x2f,0x48,0x31,0x3e,0x0a,0x54,0x68,0x65,0x20,0x64,0x6f,0x63,0x75 - ,0x6d,0x65,0x6e,0x74,0x20,0x68,0x61,0x73,0x20,0x6d,0x6f,0x76,0x65,0x64,0x0a,0x3c - ,0x41,0x20,0x48,0x52,0x45,0x46,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77 - ,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x65,0x73,0x2f,0x22,0x3e,0x68 - ,0x65,0x72,0x65,0x3c,0x2f,0x41,0x3e,0x2e,0x0d,0x0a,0x3c,0x2f,0x42,0x4f,0x44,0x59 - ,0x3e,0x3c,0x2f,0x48,0x54,0x4d,0x4c,0x3e,0x0d,0x0a }; - - Packet q; - ThreadVars tv; - DecodeThreadVars dtv; - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&q, 0, sizeof(Packet)); - memset(&dtv, 0, sizeof(DecodeThreadVars)); - - FlowInitConfig(FLOW_QUIET); - DecodeEthernet(&tv, &dtv, &q, raw_eth, sizeof(raw_eth), NULL); - FlowShutdown(); - - Packet *p=&q; - - if (!(PKT_IS_TCP(p))) { - printf("DetectWindowTestPacket02: TestPacket01: Packet is not TCP\n"); - return 0; - } - - - DetectEngineThreadCtx *det_ctx=NULL; - Signature *s=NULL; - SigMatch m; - m.ctx=wd; - - /* Now that we have what we need, just try to Match! */ - result=DetectWindowMatch (&tv, det_ctx, p, s, &m); - + uint8_t *buf = (uint8_t *)"Hi all!"; + uint16_t buflen = strlen((char *)buf); + Packet *p[3]; + p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); + p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP); + + if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) + goto end; + + /* TCP wwindow = 40 */ + p[0]->tcph->th_win = htons(40); + + /* TCP window = 41 */ + p[1]->tcph->th_win = htons(41); + + char *sigs[2]; + sigs[0]= "alert tcp any any -> any any (msg:\"Testing window 1\"; window:40; sid:1;)"; + sigs[1]= "alert tcp any any -> any any (msg:\"Testing window 2\"; window:41; sid:2;)"; + + uint32_t sid[2] = {1, 2}; + + uint32_t results[3][2] = { + /* packet 0 match sid 1 but should not match sid 2 */ + {1, 0}, + /* packet 1 should not match */ + {0, 1}, + /* packet 2 should not match */ + {0, 0} }; + result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 2); + + UTHFreePackets(p, 3); +end: return result; } @@ -491,6 +344,5 @@ void DetectWindowRegisterTests(void) { UtRegisterTest("DetectWindowTestParse03", DetectWindowTestParse03, 1); UtRegisterTest("DetectWindowTestParse04", DetectWindowTestParse04, 1); UtRegisterTest("DetectWindowTestPacket01" , DetectWindowTestPacket01 , 1); - UtRegisterTest("DetectWindowTestPacket02" , DetectWindowTestPacket02 , 1); #endif /* UNITTESTS */ } diff --git a/src/detect-window.h b/src/detect-window.h index a5f985976c..68c2431b53 100644 --- a/src/detect-window.h +++ b/src/detect-window.h @@ -6,7 +6,7 @@ typedef struct DetectWindowData_ { uint8_t negated; /** negated? 1=True : 0=False */ - uint32_t size; /** window size to match */ + uint16_t size; /** window size to match */ } DetectWindowData; /* prototypes */ diff --git a/src/detect.c b/src/detect.c index a4dc9c896f..7af86fb86e 100644 --- a/src/detect.c +++ b/src/detect.c @@ -2610,7 +2610,6 @@ int SigAddressCleanupStage1(DetectEngineCtx *de_ctx) { void DbgPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh) { if (sgh == NULL) { printf("\n"); - return; } uint32_t sig; diff --git a/src/suricata.c b/src/suricata.c index 15f0b3a498..a94038a822 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -75,6 +75,7 @@ #include "util-host-os-info.h" #include "util-cidr.h" #include "util-unittest.h" +#include "util-unittest-helper.h" #include "util-time.h" #include "util-rule-vars.h" #include "util-classification-config.h" @@ -548,6 +549,7 @@ int main(int argc, char **argv) UtRunSelftest(regex_arg); /* inits and cleans up again */ } UtInitialize(); + UTHRegisterTests(); TmModuleRegisterTests(); SigTableRegisterTests(); HashTableRegisterTests(); diff --git a/src/util-unittest-helper.c b/src/util-unittest-helper.c new file mode 100644 index 0000000000..0237e6a861 --- /dev/null +++ b/src/util-unittest-helper.c @@ -0,0 +1,639 @@ +/** Copyright (c) 2009 Open Information Security Foundation + * + * \author Pablo Rincon Crespo + * + * This file provide a set of helper functions for reducing the complexity + * when constructing unittests + */ + +#include "suricata-common.h" +#include "decode.h" +#include "detect.h" +#include "detect-parse.h" +#include "util-debug.h" +#include "util-error.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include +#include "detect-engine.h" + +/** + * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests + * specifying ip and port sources and destinations + * + * \param payload pointer to the payloadd buffer + * \param payload_len pointer to the length of the payload + * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP + * \param src pointer to a string containing the ip source + * \param dst pointer to a string containing the ip destination + * \param sport pointer to a string containing the port source + * \param dport pointer to a string containing the port destination + * + * \retval Packet pointer to the built in packet + */ +Packet *UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len, + uint16_t ipproto, char *src, char *dst, + uint16_t sport, uint16_t dport) { + struct in_addr in; + + Packet *p = malloc(sizeof(Packet)); + if (p == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating packet"); + exit(EXIT_FAILURE); + } + memset(p, 0, sizeof(Packet)); + + p->src.family = AF_INET; + p->dst.family = AF_INET; + p->payload = payload; + p->payload_len = payload_len; + p->proto = ipproto; + + inet_pton(AF_INET, src, &in); + p->src.addr_data32[0] = in.s_addr; + p->sp = sport; + + inet_pton(AF_INET, dst, &in); + p->dst.addr_data32[0] = in.s_addr; + p->dp = dport; + + switch(ipproto) { + case IPPROTO_UDP: + p->ip4h = malloc(sizeof(IPV4Hdr)); + if (p->ip4h == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating packet ip4h"); + exit(EXIT_FAILURE); + } + p->udph = malloc(sizeof(UDPHdr)); + if (p->udph == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating packet udph"); + exit(EXIT_FAILURE); + } + p->udph->uh_sport = sport; + p->udph->uh_dport = dport; + break; + case IPPROTO_TCP: + p->ip4h = malloc(sizeof(IPV4Hdr)); + if (p->ip4h == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating packet ip4h"); + exit(EXIT_FAILURE); + } + p->tcph = malloc(sizeof(TCPHdr)); + if (p->tcph == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating packet tcph"); + exit(EXIT_FAILURE); + } + p->tcph->th_sport = sport; + p->tcph->th_dport = dport; + break; + case IPPROTO_ICMP: + p->ip4h = malloc(sizeof(IPV4Hdr)); + if (p->ip4h == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating packet ip4h"); + exit(EXIT_FAILURE); + } + break; + /* TODO: Add more protocols */ + } + return p; +} + +/** + * \brief UTHBuildPacket is a wrapper that build packets with default ip + * and port fields + * + * \param payload pointer to the payloadd buffer + * \param payload_len pointer to the length of the payload + * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP + * + * \retval Packet pointer to the built in packet + */ +Packet *UTHBuildPacket(uint8_t *payload, uint16_t payload_len, + uint16_t ipproto) { + return UTHBuildPacketReal(payload, payload_len, ipproto, + "192.168.1.5", "192.168.1.1", + 41424, 80); +} + +/** + * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs + * and defaulting ports + * + * \param payload pointer to the payloadd buffer + * \param payload_len pointer to the length of the payload + * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP + * + * \retval Packet pointer to the built in packet + */ +Packet *UTHBuildPacketSrcDst(uint8_t *payload, uint16_t payload_len, + uint16_t ipproto, char *src, char *dst) { + return UTHBuildPacketReal(payload, payload_len, ipproto, + src, dst, + 41424, 80); +} + +/** + * \brief UTHBuildPacketSrcDstPorts is a wrapper that build packets specifying + * src and dst ports and defaulting IPs + * + * \param payload pointer to the payloadd buffer + * \param payload_len pointer to the length of the payload + * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP + * + * \retval Packet pointer to the built in packet + */ +Packet *UTHBuildPacketSrcDstPorts(uint8_t *payload, uint16_t payload_len, + uint16_t ipproto, uint16_t sport, uint16_t dport) { + return UTHBuildPacketReal(payload, payload_len, ipproto, + "192.168.1.5", "192.168.1.1", + sport, dport); +} + +/** + * \brief UTHFreePackets: function to release the allocated data + * from UTHBuildPacket and the packet itself + * + * \param p pointer to the Packet + */ +void UTHFreePackets(Packet **p, int numpkts) { + if (p == NULL) + return; + + int i = 0; + for (; i < numpkts; i++) { + UTHFreePacket(p[i]); + } +} + +/** + * \brief UTHFreePacket: function to release the allocated data + * from UTHBuildPacket and the packet itself + * + * \param p pointer to the Packet + */ +void UTHFreePacket(Packet *p) { + if (p == NULL) + return; + + switch(p->proto) { + case IPPROTO_UDP: + if (p->udph != NULL) + free(p->udph); + if (p->ip4h != NULL) + free(p->ip4h); + break; + case IPPROTO_TCP: + if (p->tcph != NULL) + free(p->tcph); + if (p->ip4h != NULL) + free(p->ip4h); + break; + case IPPROTO_ICMP: + if (p->ip4h != NULL) + free(p->ip4h); + break; + /* TODO: Add more protocols */ + } + free(p); +} + +/** + * \brief UTHGenericTest: function that perfom a generic check taking care of + * as maximum common unittest elements as possible. + * It will create a detection engine, append an array + * of signatures an check the spected results for each + * of them, it check matches for an array of packets + * + * \param pkt pointer to the array of packets + * \param numpkts number of packets to match + * \param sigs array of char* pointing to signatures to load + * \param numsigs number of signatures to load and check + * \param results pointer to arrays of numbers, each of them foreach packet + * to check if sids matches that packet as espected with + * that number of times or not. The size of results should be + * numpkts * numsigs * sizeof(uint16_t *) + * + * Example: + * result[1][3] would mean the number of times the pkt[1] + * match the sid[3] + * + * \retval int 1 if the match of all the sids is the specified has the + * specified results; 0 if not + */ +int UTHGenericTest(Packet **pkt, int numpkts, char *sigs[], uint32_t sids[], uint32_t *results, int numsigs) { + + int result = 0; + if (pkt == NULL || sigs == NULL || numpkts == 0 + || sids == NULL || results == NULL || numsigs == 0) { + SCLogError(SC_INVALID_ARGUMENT, "Arguments invalid, that the pointer/arrays are not NULL, and the number of signatures and packets is > 0"); + goto end; + } + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0) + goto cleanup; + + result = UTHMatchPacketsWithResults(de_ctx, pkt, numpkts, sids, results, numsigs); + +cleanup: + if (de_ctx != NULL) { + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + } +end: + return result; +} + +/** + * \brief UTHCheckPacketMatches: function to check if a packet some sids + * + * + * \param p pointer to the Packet + * \param sigs array of char* pointing to signatures to load + * \param numsigs number of signatures to load from the array + * \param results pointer to an array of numbers to check if sids matches + * that number of times or not. + * + * \retval int 1 if the match of all the sids is the specified has the + * specified results; 0 if not + */ +int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[], uint32_t results[], int numsids) { + if (p == NULL || sids == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Arguments invalid, check if the packet is NULL, and if the array contain sids is set"); + return 0; + } + int i = 0; + int res = 1; + for (; i < numsids; i++) { + uint16_t r = PacketAlertCheck(p, sids[i]); + if (r != results[i]) { + SCLogInfo("Sid %"PRIu32" matched %"PRIu16" times, and not %"PRIu16" as espected", sids[i], r, results[i]); + res = 0; + } else { + SCLogInfo("Sid %"PRIu32" matched %"PRIu16" times, as expected", sids[i], r); + } + } + return res; +} + +/** + * \brief UTHAppendSigs: Add sigs to the detection_engine checking for errors + * + * \param de_ctx pointer to the DetectEngineCtx used + * \param sigs array of char* pointing to signatures to load + * \param numsigs number of signatures to load from the array + * (size of the array) + * + * \retval int 0 if we have errors; 1 if all the signatures loaded succesfuly + */ +int UTHAppendSigs(DetectEngineCtx *de_ctx, char *sigs[], int numsigs) { + if (de_ctx == NULL || numsigs <= 0 || sigs == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Arguments invalid, check if sigs or de_ctx are NULL, and if the array contain sigs"); + return 0; + } + //SCLogDebug("Adding %d signatures for the current unittest", numsigs); + + Signature *s; + int i = 0; + + for ( ; i < numsigs; i++) { + if (sigs[i] == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Check the signature" + " at position %d", i); + return 0; + } + s = DetectEngineAppendSig(de_ctx, sigs[i]); + if (s == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "Check the signature at" + " position %d (%s)", i, sigs[i]); + return 0; + } + } + //SCLogDebug("Added %d signatures to the de_ctx of the unittest", i); + return 1; +} + +/** + * \test UTHMatchPacketsWithResults Match a packet or a array of packets against sigs + * of a de_ctx, checking that each signature match match X times for certain packets + * + * \param de_ctx pointer with the signatures loaded + * \param p pointer to the array of packets + * \param num_packets number of packets in the array + * + * \retval return 1 if all goes well + * \retval return 0 if something fail + */ +int UTHMatchPacketsWithResults(DetectEngineCtx *de_ctx, Packet **p, int num_packets, uint32_t sids[], uint32_t *results, int numsigs) { + int result = 0; + + if (de_ctx == NULL || p == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "packet or de_ctx was null"); + result = 0; + goto end; + } + + DecodeThreadVars dtv; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + memset(&dtv, 0, sizeof(DecodeThreadVars)); + memset(&th_v, 0, sizeof(th_v)); + + //de_ctx->flags |= DE_QUIET; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int i = 0; + for (; i < num_packets; i++) { + SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]); + if (UTHCheckPacketMatchResults(p[i], sids, &results[(i * numsigs)], numsigs) == 0) + goto cleanup; + } + + /* so far, so good ;) */ + result = 1; + +cleanup: + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); +end: + return result; +} + +/** + * \test UTHMatchPackets Match a packet or a array of packets against sigs + * of a de_ctx, but note that the return value doesn't mean that we have a + * match, we have to check it later with PacketAlertCheck() + * + * \param de_ctx pointer with the signatures loaded + * \param p pointer to the array of packets + * \param num_packets number of packets in the array + * + * \retval return 1 if all goes well + * \retval return 0 if something fail + */ +int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets) { + int result = 1; + + if (de_ctx == NULL || p == NULL) { + SCLogError(SC_INVALID_ARGUMENT, "packet or de_ctx was null"); + result = 0; + goto end; + } + + DecodeThreadVars dtv; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + memset(&dtv, 0, sizeof(DecodeThreadVars)); + memset(&th_v, 0, sizeof(th_v)); + + //de_ctx->flags |= DE_QUIET; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + int i = 0; + for (; i < num_packets; i++) + SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]); + + /* Here we don't check if the packet matched or not, because + * the de_ctx can have multiple signatures, and some of them may match + * and others may not. That check will be outside + */ +end: + if (det_ctx != NULL) { + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + } + + return result; +} + +/** + * \test Test if a packet match a signature given as string + * Useful for unittests with only one packet and one signature + * + * \param sig pointer to the string signature to test + * \param sid sid number of the signature + * + * \retval return 1 if match + * \retval return 0 if not + */ +int UTHPacketMatchSig(Packet *p, char *sig) { + int result = 1; + + DecodeThreadVars dtv; + + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx = NULL; + + memset(&dtv, 0, sizeof(DecodeThreadVars)); + memset(&th_v, 0, sizeof(th_v)); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + result=0; + goto end; + } + + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, sig); + 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, de_ctx->sig_list->id) != 1) { + result = 0; + goto end; + } + +end: + if (det_ctx != NULL) + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + if (de_ctx != NULL) + DetectEngineCtxFree(de_ctx); + + return result; +} + +/* +static int UTHBuildStream(Signature *s, uint8_t *payload, uint16_t payload_len, Proto tcp/udp) { +} +static int UTHInitFlow(Signature *s, uint8_t *payload, uint16_t payload_len, Proto tcp/udp) { +} +static int UTHInitConfigApi(Signature *s, uint8_t *payload, uint16_t payload_len, Proto tcp/udp) { +} +static int UTHInitDeCtx(Signature *s, uint8_t *payload, uint16_t payload_len, Proto tcp/udp) { +} +*/ + + +#ifdef UNITTESTS +/** + * \brief CheckUTHTestPacket wrapper to check packets for unittests + */ +int CheckUTHTestPacket(Packet *p, uint16_t ipproto) { + uint16_t sport = 41424; + uint16_t dport = 80; + uint8_t payload[] = "Payload"; + + uint8_t len = sizeof(payload); + + if (p == NULL) + return 0; + + if (p->payload_len != len) + return 0; + + if (strncmp((char *)payload, (char *)p->payload, len) != 0) + return 0; + + if (p->src.family != AF_INET) + return 0; + if (p->dst.family != AF_INET) + return 0; + if (p->proto != ipproto) + return 0; + + switch(ipproto) { + case IPPROTO_UDP: + if (p->udph == NULL) + return 0; + if (p->udph->uh_sport != sport) + return 0; + if (p->udph->uh_dport != dport) + return 0; + break; + case IPPROTO_TCP: + if (p->tcph == NULL) + return 0; + if (p->tcph->th_sport != sport) + return 0; + if (p->tcph->th_dport != dport) + return 0; + break; + } + return 1; +} + +/** + * \brief UTHBuildPacketRealTest01 wrapper to check packets for unittests + */ +int UTHBuildPacketRealTest01(void) { + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1", 41424, 80); + + return CheckUTHTestPacket(p, IPPROTO_TCP); +} + +/** + * \brief UTHBuildPacketRealTest02 wrapper to check packets for unittests + */ +int UTHBuildPacketRealTest02(void) { + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_UDP, + "192.168.1.5", "192.168.1.1", 41424, 80); + + return CheckUTHTestPacket(p, IPPROTO_UDP); +} + +/** + * \brief UTHBuildPacketTest01 wrapper to check packets for unittests + */ +int UTHBuildPacketTest01(void) { + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP); + + return CheckUTHTestPacket(p, IPPROTO_TCP); +} + +/** + * \brief UTHBuildPacketTest02 wrapper to check packets for unittests + */ +int UTHBuildPacketTest02(void) { + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_UDP); + + return CheckUTHTestPacket(p, IPPROTO_UDP); +} + +/** + * \brief UTHBuildPacketSrcDstTest01 wrapper to check packets for unittests + */ +int UTHBuildPacketSrcDstTest01(void) { + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_TCP, + "192.168.1.5", "192.168.1.1"); + + return CheckUTHTestPacket(p, IPPROTO_TCP); +} + +/** + * \brief UTHBuildPacketSrcDstTest02 wrapper to check packets for unittests + */ +int UTHBuildPacketSrcDstTest02(void) { + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_UDP, + "192.168.1.5", "192.168.1.1"); + + return CheckUTHTestPacket(p, IPPROTO_UDP); +} + +/** + * \brief UTHBuildPacketSrcDstPortsTest01 wrapper to check packets for unittests + */ +int UTHBuildPacketSrcDstPortsTest01(void) { + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_TCP, + 41424, 80); + + return CheckUTHTestPacket(p, IPPROTO_TCP); +} + +/** + * \brief UTHBuildPacketSrcDstPortsTest02 wrapper to check packets for unittests + */ +int UTHBuildPacketSrcDstPortsTest02(void) { + uint8_t payload[] = "Payload"; + + Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_UDP, + 41424, 80); + + return CheckUTHTestPacket(p, IPPROTO_UDP); +} + +#endif /* UNITTESTS */ + +void UTHRegisterTests(void) { +#ifdef UNITTESTS + UtRegisterTest("UTHBuildPacketRealTest01", UTHBuildPacketRealTest01, 1); + UtRegisterTest("UTHBuildPacketRealTest02", UTHBuildPacketRealTest02, 1); + UtRegisterTest("UTHBuildPacketTest01", UTHBuildPacketTest01, 1); + UtRegisterTest("UTHBuildPacketTest02", UTHBuildPacketTest02, 1); + UtRegisterTest("UTHBuildPacketSrcDstTest01", UTHBuildPacketSrcDstTest01, 1); + UtRegisterTest("UTHBuildPacketSrcDstTest02", UTHBuildPacketSrcDstTest02, 1); + UtRegisterTest("UTHBuildPacketSrcDstPortsTest01", UTHBuildPacketSrcDstPortsTest01, 1); + UtRegisterTest("UTHBuildPacketSrcDstPortsTest02", UTHBuildPacketSrcDstPortsTest02, 1); + +#endif /* UNITTESTS */ +} + diff --git a/src/util-unittest-helper.h b/src/util-unittest-helper.h new file mode 100644 index 0000000000..45b4726d07 --- /dev/null +++ b/src/util-unittest-helper.h @@ -0,0 +1,21 @@ +#ifndef __UTIL_UNITTEST_HELPER__ +#define __UTIL_UNITTEST_HELPER__ + +Packet *UTHBuildPacketReal(uint8_t *, uint16_t, uint16_t, char *, char *, uint16_t, uint16_t); +Packet *UTHBuildPacket(uint8_t *, uint16_t, uint16_t); +Packet *UTHBuildPacketSrcDst(uint8_t *, uint16_t, uint16_t, char *, char *); +Packet *UTHBuildPacketSrcDstPorts(uint8_t *, uint16_t, uint16_t, uint16_t, uint16_t); +void UTHFreePacket(Packet *); +void UTHFreePackets(Packet **, int); + +int UTHAppendSigs(DetectEngineCtx *, char **, int); +int UTHMatchPackets(DetectEngineCtx *, Packet **, int); +int UTHPacketMatchSig(Packet *p, char *); +int UTHCheckPacketMatch(Packet *, uint32_t *, uint32_t *, int); + +int UTHMatchPacketsWithResults(DetectEngineCtx *, Packet **, int, uint32_t *, uint32_t *, int); +int UTHGenericTest(Packet **, int, char **, uint32_t *, uint32_t *, int); + +void UTHRegisterTests(void); + +#endif /* __UTIL_UNITTEST_HELPER__ */