diff --git a/src/Makefile.am b/src/Makefile.am index b069823974..ee00e8bcf2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -58,6 +58,7 @@ detect-metadata.c detect-metadata.h \ detect-msg.c detect-msg.h \ detect-flow.c detect-flow.h \ detect-dsize.c detect-dsize.h \ +detect-decode-event.c detect-decode-event.h \ detect-noalert.c detect-noalert.h \ util-print.c util-print.h \ util-mpm.c util-mpm.h \ diff --git a/src/detect-decode-event.c b/src/detect-decode-event.c new file mode 100644 index 0000000000..66334aec87 --- /dev/null +++ b/src/detect-decode-event.c @@ -0,0 +1,309 @@ +/** Copyright (c) 2009 Open Information Security Foundation + * + * \author Breno Silva + */ + +#include "decode.h" +#include "detect.h" +#include "flow-var.h" + +#include "eidps.h" + +#include "decode-events.h" +#include "detect-decode-event.h" + +#include "util-unittest.h" + +#include +#include + +#define PARSE_REGEX "\\S[0-9A-z_]+[.][A-z+]+$" + +static pcre *parse_regex; +static pcre_extra *parse_regex_study; + +int DetectDecodeEventMatch (ThreadVars *, PatternMatcherThread *, Packet *, Signature *, SigMatch *); +int DetectDecodeEventSetup (DetectEngineCtx *, Signature *s, SigMatch *m, char *str); +void DecodeEventRegisterTests(void); + + +/** + * \brief Registration function for decode-event: keyword + */ +void DetectDecodeEventRegister (void) { + sigmatch_table[DETECT_DECODE_EVENT].name = "decode-event"; + sigmatch_table[DETECT_DECODE_EVENT].Match = DetectDecodeEventMatch; + sigmatch_table[DETECT_DECODE_EVENT].Setup = DetectDecodeEventSetup; + sigmatch_table[DETECT_DECODE_EVENT].Free = NULL; + sigmatch_table[DETECT_DECODE_EVENT].RegisterTests = DecodeEventRegisterTests; + + const char *eb; + int eo; + int opts = 0; + + parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); + if(parse_regex == NULL) + { + printf("pcre compile of \"%s\" failed at offset %d: %s\n", PARSE_REGEX, eo, eb); + goto error; + } + + parse_regex_study = pcre_study(parse_regex, 0, &eb); + if(eb != NULL) + { + printf("pcre study failed: %s\n", eb); + goto error; + } + return; + +error: + return; + +} + +/** + * \brief This function is used to match decoder event flags set on a packet with those passed via decode-event: + * + * \param t pointer to thread vars + * \param pmt pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param s pointer to the Signature + * \param m pointer to the sigmatch + * + * \retval 0 no match + * \retval 1 match + */ +int DetectDecodeEventMatch (ThreadVars *t, PatternMatcherThread *pmt, Packet *p, Signature *s, SigMatch *m) +{ + int ret = 0; + DetectDecodeEventData *de = (DetectDecodeEventData *)m->ctx; + + if(de && DECODER_ISSET_EVENT(p, de->event)) + return 1; + + return ret; +} + +/** + * \brief This function is used to parse decoder events options passed via decode-event: keyword + * + * \param rawstr Pointer to the user provided decode-event options + * + * \retval de pointer to DetectFlowData on success + * \retval NULL on failure + */ +DetectDecodeEventData *DetectDecodeEventParse (char *rawstr) +{ + int i; + DetectDecodeEventData *de = NULL; +#define MAX_SUBSTRINGS 30 + int ret = 0, res = 0, found = 0; + int ov[MAX_SUBSTRINGS]; + + ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); + if (ret < 1) { + goto error; + } + + const char *str_ptr; + res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 0, &str_ptr); + + if (res < 0) { + goto error; + } + + for(i = 0; DEvents[i].event_name != NULL; i++) { + if((strncasecmp(DEvents[i].event_name,str_ptr,strlen(DEvents[i].event_name))) == 0) { + found = 1; + break; + } + } + + if(found == 0) + goto error; + + de = malloc(sizeof(DetectDecodeEventData)); + if (de == NULL) { + printf("DetectDecodeEventSetup malloc failed\n"); + goto error; + } + + de->event = DEvents[i].code; + return de; + +error: + if (de) free(de); + return NULL; +} + +/** + * \brief this function is used to add the parsed decode-event into the current signature + * + * \param de_ctx pointer to the Detection Engine Context + * \param s pointer to the Current Signature + * \param m pointer to the Current SigMatch + * \param rawstr pointer to the user provided decode-event options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +int DetectDecodeEventSetup (DetectEngineCtx *de_ctx, Signature *s, SigMatch *m, char *rawstr) +{ + DetectDecodeEventData *de = NULL; + SigMatch *sm = NULL; + + de = DetectDecodeEventParse(rawstr); + if (de == NULL) + goto error; + + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_DECODE_EVENT; + sm->ctx = (void *)de; + + SigMatchAppend(s,m,sm); + return 0; + +error: + if (de) free(de); + if (sm) free(sm); + return -1; +} + +/** + * \brief this function will free memory associated with DetectDecodeEventData + * + * \param de pointer to DetectDecodeEventData + */ +void DetectDecodeEventFree(DetectDecodeEventData *de) { + if(de) free(de); +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ + +/** + * \test DecodeEventTestParse01 is a test for a valid decode-event value + */ +int DecodeEventTestParse01 (void) { + DetectDecodeEventData *de = NULL; + de = DetectDecodeEventParse("ipv4.pkt_too_small"); + if (de) { + DetectDecodeEventFree(de); + return 1; + } + + return 0; +} + + +/** + * \test DecodeEventTestParse02 is a test for a valid upper + lower case decode-event value + */ +int DecodeEventTestParse02 (void) { + DetectDecodeEventData *de = NULL; + de = DetectDecodeEventParse("PPP.pkt_too_small"); + if (de) { + DetectDecodeEventFree(de); + return 1; + } + + return 0; +} + +/** + * \test DecodeEventTestParse03 is a test for a valid upper case decode-event value + */ +int DecodeEventTestParse03 (void) { + DetectDecodeEventData *de = NULL; + de = DetectDecodeEventParse("IPV6.PKT_TOO_SMALL"); + if (de) { + DetectDecodeEventFree(de); + return 1; + } + + return 0; +} + +/** + * \test DecodeEventTestParse04 is a test for an invalid upper case decode-event value + */ +int DecodeEventTestParse04 (void) { + DetectDecodeEventData *de = NULL; + de = DetectDecodeEventParse("IPV6.INVALID_EVENT"); + if (de) { + DetectDecodeEventFree(de); + return 1; + } + + return 0; +} + +/** + * \test DecodeEventTestParse05 is a test for an invalid char into the decode-event value + */ +int DecodeEventTestParse05 (void) { + DetectDecodeEventData *de = NULL; + de = DetectDecodeEventParse("IPV-6,INVALID_CHAR"); + if (de) { + DetectDecodeEventFree(de); + return 1; + } + + return 0; +} + +/** + * \test DecodeEventTestParse06 is a test for match function with valid decode-event value + */ +int DecodeEventTestParse06 (void) { + Packet p; + ThreadVars tv; + int ret = 0; + DetectDecodeEventData *de = NULL; + SigMatch *sm = NULL; + + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&p, 0, sizeof(Packet)); + + DECODER_SET_EVENT(&p,PPP_PKT_TOO_SMALL); + + de = DetectDecodeEventParse("ppp.pkt_too_small"); + if (de == NULL) + goto error; + + de->event = PPP_PKT_TOO_SMALL; + + sm = SigMatchAlloc(); + if (sm == NULL) + goto error; + + sm->type = DETECT_DECODE_EVENT; + sm->ctx = (void *)de; + + ret = DetectDecodeEventMatch(&tv,NULL,&p,NULL,sm); + + if(ret) + return 1; + +error: + if (de) free(de); + if (sm) free(sm); + return 0; +} + +/** + * \brief this function registers unit tests for DecodeEvent + */ +void DecodeEventRegisterTests(void) { + UtRegisterTest("DecodeEventTestParse01", DecodeEventTestParse01, 1); + UtRegisterTest("DecodeEventTestParse02", DecodeEventTestParse02, 1); + UtRegisterTest("DecodeEventTestParse03", DecodeEventTestParse03, 1); + UtRegisterTest("DecodeEventTestParse04", DecodeEventTestParse04, 0); + UtRegisterTest("DecodeEventTestParse05", DecodeEventTestParse05, 0); + UtRegisterTest("DecodeEventTestParse06", DecodeEventTestParse06, 1); +} diff --git a/src/detect-decode-event.h b/src/detect-decode-event.h new file mode 100644 index 0000000000..67f0a69d50 --- /dev/null +++ b/src/detect-decode-event.h @@ -0,0 +1,55 @@ +/** Copyright (c) 2009 Open Information Security Foundation + * + * \author Breno Silva + */ + +#ifndef __DETECT_DECODE_EVENT_H__ +#define __DETECT_DECODE_EVENT_H__ + + +typedef struct DetectDecodeEventData_ { + u_int8_t event; +} DetectDecodeEventData; + +/* prototypes */ +void DetectDecodeEventRegister (void); + +/* suppoted decoder events */ + +struct DetectDecodeEvents_ { + char *event_name; + u_int8_t code; +} DEvents[] = { + { "ipv4.pkt_too_small", IPV4_PKT_TOO_SMALL, }, + { "ipv4.hlen_too_small", IPV4_HLEN_TOO_SMALL, }, + { "ipv4.iplen_smaller_than_hlen", IPV4_IPLEN_SMALLER_THAN_HLEN, }, + { "ipv6.pkt_too_small", IPV6_PKT_TOO_SMALL, }, + { "ipv6.trunc_exthdr", IPV6_TRUNC_EXTHDR, }, + { "ipv6.exthdr_dupl_fh", IPV6_EXTHDR_DUPL_FH, }, + { "ipv6.exthdr_dupl_rh", IPV6_EXTHDR_DUPL_RH, }, + { "ipv6.exthdr_dupl_hh", IPV6_EXTHDR_DUPL_HH, }, + { "ipv6.exthdr_dupl_dh", IPV6_EXTHDR_DUPL_DH, }, + { "ipv6.exthdr_dupl_ah", IPV6_EXTHDR_DUPL_AH, }, + { "ipv6.exthdr_dupl_eh", IPV6_EXTHDR_DUPL_EH, }, + { "ipv6.exthdr_invalid_optlen", IPV6_EXTHDR_INVALID_OPTLEN, }, + { "tcp.pkt_too_small", TCP_PKT_TOO_SMALL, }, + { "tcp.hlen_too_small", TCP_HLEN_TOO_SMALL, }, + { "tcp.invalid_optlen", TCP_INVALID_OPTLEN, }, + { "tcp.opt_invalid_len", TCP_OPT_INVALID_LEN, }, + { "tcp.opt_duplicate", TCP_OPT_DUPLICATE, }, + { "udp.pkt_too_small", UDP_PKT_TOO_SMALL, }, + { "udp.hlen_too_small", UDP_HLEN_TOO_SMALL, }, + { "udp.hlen_invalid", UDP_HLEN_INVALID, }, + { "sll.pkt_too_small", SLL_PKT_TOO_SMALL, }, + { "ethernet.pkt_too_small", ETHERNET_PKT_TOO_SMALL, }, + { "ppp.pkt_too_small", PPP_PKT_TOO_SMALL, }, + { "ppp.ju_pkt_too_small", PPPVJU_PKT_TOO_SMALL, }, + { "ppp.ip4_pkt_too_small", PPPIPV4_PKT_TOO_SMALL, }, + { "ppp.ip6_pkt_too_small", PPPIPV6_PKT_TOO_SMALL, }, + { "ppp.wrong_type", PPP_WRONG_TYPE, }, + { NULL, 0 }, +}; + + +#endif /*__DETECT_DECODE_EVENT_H__ */ + diff --git a/src/detect-parse.c b/src/detect-parse.c index 0b145fbe94..b3f66f9ea9 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -37,10 +37,10 @@ static u_int32_t dbg_dstportany_cnt = 0; #define CONFIG_OPTS 7 // action protocol src sp dir dst dp options -#define CONFIG_PCRE "^([A-z]+)\\s+([A-z0-9]+)\\s+([\\[\\]A-z0-9\\.\\:_\\$\\!\\-,\\/]+)\\s+([\\:A-z0-9_\\$\\!,]+)\\s+(\\<-|-\\>|\\<\\>)\\s+([\\[\\]A-z0-9\\.\\:_\\$\\!\\-,/]+)\\s+([\\:A-z0-9_\\$\\!,]+)(?:\\s+\\((.*)?(?:\\s*)\\))?(?:(?:\\s*)\\n)?$" -#define OPTION_PARTS 3 -#define OPTION_PCRE "^\\s*([A-z_0-9]+)(?:\\s*\\:\\s*(.*)(?|\\<\\>)\\s+([\\[\\]A-z0-9\\.\\:_\\$\\!\\-,/]+)\\s+([\\:A-z0-9_\\$\\!]+)(?:\\s+\\((.*)?(?:\\s*)\\))?(?:(?:\\s*)\\n)?$" +#define OPTION_PARTS 3 +#define OPTION_PCRE "^\\s*([A-z_0-9-]+)(?:\\s*\\:\\s*(.*)(?next = sig; prevsig = sig; + sig = SigInit(g_de_ctx, "alert tcp any any -> any any (msg:\"ipv4 pkt too small\"; decode-event:ipv4.pkt_too_small; sid:5;)"); + if (sig == NULL) + return; + prevsig->next = sig; + prevsig = sig; /* sig = SigInit(g_de_ctx,"alert udp any any -> any any (msg:\"ViCtOr nocase test\"; sid:4; rev:13; content:\"ViCtOr!!\"; offset:100; depth:150; nocase; content:\"ViCtOr!!\"; nocase; offset:99; depth:150;)"); if (sig == NULL) @@ -658,6 +663,8 @@ static int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s) { return 0; } else if (sm->type == DETECT_DSIZE) { return 0; + } else if (sm->type == DETECT_DECODE_EVENT) { + return 0; } } @@ -2592,6 +2599,7 @@ void SigTableSetup(void) { DetectPktvarRegister(); DetectNoalertRegister(); DetectFlowbitsRegister(); + DetectDecodeEventRegister(); u_int8_t i = 0; for (i = 0; i < DETECT_TBLSIZE; i++) { diff --git a/src/detect.h b/src/detect.h index 8d9a8cd575..d0bea15f76 100644 --- a/src/detect.h +++ b/src/detect.h @@ -382,7 +382,7 @@ enum { DETECT_ADDRESS, DETECT_PROTO, DETECT_PORT, - + DETECT_DECODE_EVENT, /* make sure this stays last */ DETECT_TBLSIZE, };