diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index 11fd8e612a..418b4a910c 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -29,6 +29,7 @@ #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" +#include "detect-reference.h" #include "util-classification-config.h" #include "output.h" @@ -91,15 +92,16 @@ static void CreateTimeString (const struct timeval *ts, char *str, size_t size) uint32_t sec = ts->tv_sec % 86400; snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", - t->tm_mon + 1, t->tm_mday, t->tm_year - 100, - sec / 3600, (sec % 3600) / 60, sec % 60, - (uint32_t) ts->tv_usec); + t->tm_mon + 1, t->tm_mday, t->tm_year - 100, + sec / 3600, (sec % 3600) / 60, sec % 60, + (uint32_t) ts->tv_usec); } TmEcode AlertFastLogIPv4(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq) { AlertFastLogThread *aft = (AlertFastLogThread *)data; int i; + Reference *ref = NULL; char timebuf[64]; if (p->alerts.cnt == 0) @@ -119,8 +121,17 @@ TmEcode AlertFastLogIPv4(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq) inet_ntop(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); inet_ntop(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); - fprintf(aft->file_ctx->fp, "%s [**] [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [**] [Classification: %s] [Priority: %" PRIu32 "] {%" PRIu32 "} %s:%" PRIu32 " -> %s:%" PRIu32 "\n", - timebuf, pa->gid, pa->sid, pa->rev, pa->msg, pa->class_msg, pa->prio, IPV4_GET_IPPROTO(p), srcip, p->sp, dstip, p->dp); + fprintf(aft->file_ctx->fp, "%s [**] [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [**] [Classification: %s] [Priority: %" PRIu32 "] {%" PRIu32 "} %s:%" PRIu32 " -> %s:%" PRIu32 " ", + timebuf, pa->gid, pa->sid, pa->rev, pa->msg, pa->class_msg, pa->prio, IPV4_GET_IPPROTO(p), srcip, p->sp, dstip, p->dp); + + if(pa->references != NULL) { + for (ref = pa->references; ref != NULL; ref = ref->next) { + fprintf(aft->file_ctx->fp,"[Xref => %s%s]", ref->key, ref->reference); + } + } + + fprintf(aft->file_ctx->fp,"\n"); + fflush(aft->file_ctx->fp); } SCMutexUnlock(&aft->file_ctx->fp_mutex); @@ -132,6 +143,7 @@ TmEcode AlertFastLogIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq) { AlertFastLogThread *aft = (AlertFastLogThread *)data; int i; + Reference *ref = NULL; char timebuf[64]; if (p->alerts.cnt == 0) @@ -150,10 +162,19 @@ TmEcode AlertFastLogIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq) inet_ntop(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); inet_ntop(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); - fprintf(aft->file_ctx->fp, "%s [**] [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [**] [Classification: %s] [Priority: %" PRIu32 "] {%" PRIu32 "} %s:%" PRIu32 " -> %s:%" PRIu32 "\n", + fprintf(aft->file_ctx->fp, "%s [**] [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [**] [Classification: %s] [Priority: %" PRIu32 "] {%" PRIu32 "} %s:%" PRIu32 " -> %s:%" PRIu32 " ", timebuf, pa->gid, pa->sid, pa->rev, pa->msg, pa->class_msg, pa->prio, IPV6_GET_L4PROTO(p), srcip, p->sp, dstip, p->dp); + + if(pa->references != NULL) { + for (ref = pa->references; ref != NULL; ref = ref->next) { + fprintf(aft->file_ctx->fp,"[Xref => %s%s]", ref->key, ref->reference); + } + } + + fprintf(aft->file_ctx->fp,"\n"); + + fflush(aft->file_ctx->fp); } - fflush(aft->file_ctx->fp); SCMutexUnlock(&aft->file_ctx->fp_mutex); return TM_ECODE_OK; @@ -237,7 +258,7 @@ OutputCtx *AlertFastLogInitCtx(ConfNode *conf) OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (output_ctx == NULL) { SCLogError(SC_ERR_MEM_ALLOC, - "Failed to allocated memory for OutputCtx"); + "Failed to allocated memory for OutputCtx"); exit(EXIT_FAILURE); } output_ctx->data = logfile_ctx; @@ -271,7 +292,7 @@ static int AlertFastLogOpenFileCtx(LogFileCtx *file_ctx, const char *filename) if (file_ctx->fp == NULL) { SCLogError(SC_ERR_FOPEN, "ERROR: failed to open %s: %s", log_path, - strerror(errno)); + strerror(errno)); return -1; } @@ -314,8 +335,8 @@ int AlertFastLogTest01() SCClassConfDeleteDummyClassificationConfigFD(); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"FastLog test\"; content:GET; " - "Classtype:unknown; sid:1;)"); + "(msg:\"FastLog test\"; content:GET; " + "Classtype:unknown; sid:1;)"); result = (de_ctx->sig_list != NULL); SigGroupBuild(de_ctx); @@ -375,8 +396,8 @@ int AlertFastLogTest02() SCClassConfDeleteDummyClassificationConfigFD(); de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any " - "(msg:\"FastLog test\"; content:GET; " - "Classtype:unknown; sid:1;)"); + "(msg:\"FastLog test\"; content:GET; " + "Classtype:unknown; sid:1;)"); result = (de_ctx->sig_list != NULL); if (result == 0) printf("sig parse failed: "); @@ -389,7 +410,7 @@ int AlertFastLogTest02() result = (strcmp(p.alerts.alerts[0].class_msg, "Unknown Traffic") != 0); if (result == 0) printf("p.alerts.alerts[0].class_msg %s: ", p.alerts.alerts[0].class_msg); result = (strcmp(p.alerts.alerts[0].class_msg, - "Unknown are we") == 0); + "Unknown are we") == 0); if (result == 0) printf("p.alerts.alerts[0].class_msg %s: ", p.alerts.alerts[0].class_msg); } else { result = 0; @@ -424,7 +445,7 @@ void AlertFastLogRegisterTests(void) #ifdef __SC_CUDA_SUPPORT__ UtRegisterTest("AlertFastLogCudaContextInit", - SCCudaHlTestEnvCudaContextInit, 1); + SCCudaHlTestEnvCudaContextInit, 1); #endif UtRegisterTest("AlertFastLogTest01", AlertFastLogTest01, 1); @@ -432,7 +453,7 @@ void AlertFastLogRegisterTests(void) #ifdef __SC_CUDA_SUPPORT__ UtRegisterTest("AlertFastLogCudaContextDeInit", - SCCudaHlTestEnvCudaContextDeInit, 1); + SCCudaHlTestEnvCudaContextDeInit, 1); #endif #endif /* UNITTESTS */ diff --git a/src/counters.c b/src/counters.c index 5fb41f77f3..665255782f 100644 --- a/src/counters.c +++ b/src/counters.c @@ -1536,6 +1536,42 @@ int SCPerfUpdateCounterArray(SCPerfCounterArray *pca, SCPerfContext *pctx, return 1; } +/* + * \brief Get the value of the local copy of the counter that hold this id. + * + * \param id The counter id. + * \param pca Pointer to the SCPerfCounterArray. + * + * \retval 0 on success. + * \retval -1 on error. + */ +double SCPerfGetLocalCounterValue(uint16_t id, SCPerfCounterArray *pca) +{ + if (pca == NULL) { + SCLogDebug("pca NULL inside SCPerfUpdateCounterArray"); + return -1; + } + + if ((id < 1) || (id > pca->size)) { + SCLogDebug("counter doesn't exist"); + return -1; + } + + /* we check the type of the counter. Whether it's a counter that holds an + * unsigned_int_64 value or double value */ + switch (pca->head[id].pc->value->type) { + /* the counter holds an unsigned_int_64 value */ + case SC_PERF_TYPE_UINT64: + return pca->head[id].ui64_cnt; + /* the counter holds a double */ + case SC_PERF_TYPE_DOUBLE: + return pca->head[id].d_cnt; + default: + /* this can never happen */ + return -1; + } +} + /** * \brief The output interface dispatcher for the counter api */ diff --git a/src/counters.h b/src/counters.h index ee6a90886f..ff44a96ee8 100644 --- a/src/counters.h +++ b/src/counters.h @@ -229,6 +229,7 @@ inline void SCPerfCounterSetUI64(uint16_t, SCPerfCounterArray *, uint64_t); inline void SCPerfCounterSetDouble(uint16_t, SCPerfCounterArray *, double); int SCPerfUpdateCounterArray(SCPerfCounterArray *, SCPerfContext *, int); +double SCPerfGetLocalCounterValue(uint16_t, SCPerfCounterArray *); void SCPerfOutputCounters(void); diff --git a/src/decode.h b/src/decode.h index e3e05e3e60..d3f672a142 100644 --- a/src/decode.h +++ b/src/decode.h @@ -34,6 +34,8 @@ #include "decode-raw.h" #include "decode-vlan.h" +#include "detect-reference.h" + /* forward declaration */ struct DetectionEngineThreadCtx_; @@ -170,6 +172,7 @@ typedef struct PacketAlert_ { uint8_t prio; char *msg; char *class_msg; + Reference *references; } PacketAlert; #define PACKET_ALERT_MAX 256 diff --git a/src/detect-engine-iponly.c b/src/detect-engine-iponly.c index 6cb04918c4..9c188403c7 100644 --- a/src/detect-engine-iponly.c +++ b/src/detect-engine-iponly.c @@ -859,7 +859,9 @@ void DetectEngineIPOnlyThreadDeinit(DetectEngineIPOnlyThreadCtx *io_tctx) { * \param io_ctx Pointer to the current ip only thread detection engine * \param p Pointer to the Packet to match against */ -void IPOnlyMatchPacket(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx, +void IPOnlyMatchPacket(DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + DetectEngineIPOnlyCtx *io_ctx, DetectEngineIPOnlyThreadCtx *io_tctx, Packet *p) { SCRadixNode *srcnode = NULL, *dstnode = NULL; @@ -933,7 +935,7 @@ void IPOnlyMatchPacket(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx, u * 8 + i, s->id, s->msg); if (!(s->flags & SIG_FLAG_NOALERT)) { - PacketAlertHandle(de_ctx,s,p); + PacketAlertHandle(de_ctx, det_ctx, s, p); /* set verdict on packet */ p->action |= s->action; diff --git a/src/detect-engine-iponly.h b/src/detect-engine-iponly.h index 9704572987..be8086d05c 100644 --- a/src/detect-engine-iponly.h +++ b/src/detect-engine-iponly.h @@ -28,7 +28,9 @@ int IPOnlyCIDRItemParseSingle(IPOnlyCIDRItem *dd, char *str); int IPOnlyCIDRItemSetup(IPOnlyCIDRItem *gh, char *s); void IPOnlyCIDRListPrint(IPOnlyCIDRItem *); -void IPOnlyMatchPacket(DetectEngineCtx *, DetectEngineIPOnlyCtx *, DetectEngineIPOnlyThreadCtx *, Packet *); +void IPOnlyMatchPacket(DetectEngineCtx *, DetectEngineThreadCtx *, + DetectEngineIPOnlyCtx *, DetectEngineIPOnlyThreadCtx *, + Packet *); void IPOnlyInit(DetectEngineCtx *, DetectEngineIPOnlyCtx *); void IPOnlyPrint(DetectEngineCtx *, DetectEngineIPOnlyCtx *); void IPOnlyDeinit(DetectEngineCtx *, DetectEngineIPOnlyCtx *); diff --git a/src/detect-engine-threshold.c b/src/detect-engine-threshold.c index f376d58015..30d79fb538 100644 --- a/src/detect-engine-threshold.c +++ b/src/detect-engine-threshold.c @@ -42,20 +42,21 @@ * \param p Packet structure * */ -void PacketAlertHandle(DetectEngineCtx *de_ctx, Signature *sig, Packet *p) +void PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Signature *s, Packet *p) { SCEnter(); /* retrieve the sig match data */ - DetectThresholdData *td = SigGetThresholdType(sig,p); + DetectThresholdData *td = SigGetThresholdType(s,p); SCLogDebug("td %p", td); /* if have none just alert, otherwise handle thresholding */ if (td == NULL) { - PacketAlertAppend(p, sig->gid, sig->id, sig->rev, sig->prio, sig->msg, sig->class_msg); + PacketAlertAppend(det_ctx, s, p); } else { - PacketAlertThreshold(de_ctx, td, p, sig); + PacketAlertThreshold(de_ctx, det_ctx, td, p, s); } SCReturn; @@ -224,7 +225,8 @@ void ThresholdHashAdd(DetectEngineCtx *de_ctx, DetectThresholdEntry *tsh_ptr, Pa * \param s Signature structure * */ -void PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectThresholdData *td, Packet *p, Signature *s) +void PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + DetectThresholdData *td, Packet *p, Signature *s) { SCEnter(); @@ -277,20 +279,20 @@ void PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectThresholdData *td, Pack if (lookup_tsh != NULL) { if ((ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { if (lookup_tsh->current_count < td->count) { - PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg); + PacketAlertAppend(det_ctx, s, p); } lookup_tsh->current_count++; } else { lookup_tsh->tv_sec1 = ts.tv_sec; lookup_tsh->current_count = 1; - PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg); + PacketAlertAppend(det_ctx, s, p); } } else { ste->tv_sec1 = ts.tv_sec; ste->current_count = 1; - PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg); + PacketAlertAppend(det_ctx, s, p); ThresholdHashAdd(de_ctx, ste, p); ste = NULL; @@ -307,7 +309,7 @@ void PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectThresholdData *td, Pack lookup_tsh->current_count++; if (lookup_tsh->current_count >= td->count) { - PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg); + PacketAlertAppend(det_ctx, s, p); lookup_tsh->current_count = 0; } } else { @@ -319,7 +321,7 @@ void PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectThresholdData *td, Pack ste->tv_sec1 = ts.tv_sec; if (td->count == 1) { - PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg); + PacketAlertAppend(det_ctx, s, p); ste->current_count = 0; } else { ThresholdHashAdd(de_ctx,ste,p); @@ -337,7 +339,7 @@ void PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectThresholdData *td, Pack if ((ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { lookup_tsh->current_count++; if (lookup_tsh->current_count == td->count) { - PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg); + PacketAlertAppend(det_ctx, s, p); } } else { lookup_tsh->tv_sec1 = ts.tv_sec; @@ -348,7 +350,7 @@ void PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectThresholdData *td, Pack ste->tv_sec1 = ts.tv_sec; if (td->count == 1) { - PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg); + PacketAlertAppend(det_ctx, s, p); ste->current_count = 0; } else { ThresholdHashAdd(de_ctx,ste,p); @@ -367,7 +369,7 @@ void PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectThresholdData *td, Pack if ((ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { lookup_tsh->current_count++; if (lookup_tsh->current_count >= td->count) { - PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg); + PacketAlertAppend(det_ctx, s, p); } } else { lookup_tsh->tv_sec1 = ts.tv_sec; @@ -378,7 +380,7 @@ void PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectThresholdData *td, Pack ste->tv_sec1 = ts.tv_sec; if (td->count == 1) { - PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg); + PacketAlertAppend(det_ctx, s, p); } ThresholdHashAdd(de_ctx, ste, p); ste = NULL; diff --git a/src/detect-engine-threshold.h b/src/detect-engine-threshold.h index 6fcf013acc..1e72e051d7 100644 --- a/src/detect-engine-threshold.h +++ b/src/detect-engine-threshold.h @@ -12,9 +12,11 @@ #define THRESHOLD_HASH_SIZE 0xffff -void PacketAlertHandle(DetectEngineCtx *de_ctx, Signature *sig, Packet *p); +void PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *, + Signature *sig, Packet *p); DetectThresholdData *SigGetThresholdType(Signature *, Packet *); -void PacketAlertThreshold(DetectEngineCtx *,DetectThresholdData *, Packet *, Signature *); +void PacketAlertThreshold(DetectEngineCtx *, DetectEngineThreadCtx *, + DetectThresholdData *, Packet *, Signature *); void ThresholdFreeFunc(void *data); char ThresholdCompareFunc(void *data1, uint16_t len1, void *data2,uint16_t len2); uint32_t ThresholdHashFunc(HashListTable *ht, void *data, uint16_t datalen); diff --git a/src/detect-engine.c b/src/detect-engine.c index c0c3b6f6a5..1785f655a2 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -437,6 +437,9 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) { tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx); SCPerfAddToClubbedTMTable(tv->name, &tv->sc_perf_pctx); + /* this detection engine context belongs to this thread instance */ + det_ctx->tv = tv; + *data = (void *)det_ctx; #ifdef __SC_CUDA_SUPPORT__ diff --git a/src/detect-parse.c b/src/detect-parse.c index 1c374770db..66d0757677 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -11,6 +11,7 @@ #include "detect-content.h" #include "detect-uricontent.h" +#include "detect-reference.h" #include "flow.h" @@ -683,6 +684,35 @@ Signature *SigAlloc (void) { return sig; } +/** + * \internal + * \brief Free Reference list + * + * \param s Pointer to the signature + */ +static void SigRefFree (Signature *s) { + SCEnter(); + + Reference *ref = NULL; + Reference *next_ref = NULL; + + if (s == NULL) { + SCReturn; + } + + SCLogDebug("s %p, s->references %p", s, s->references); + + for (ref = s->references; ref != NULL;) { + next_ref = ref->next; + DetectReferenceFree(ref); + ref = next_ref; + } + + s->references = NULL; + + SCReturn; +} + void SigFree(Signature *s) { if (s == NULL) return; @@ -710,7 +740,10 @@ void SigFree(Signature *s) { DetectPortCleanupList(s->dp); } - if (s->msg != NULL) SCFree(s->msg); + if (s->msg != NULL) + SCFree(s->msg); + + SigRefFree(s); SCFree(s); } diff --git a/src/detect-reference.c b/src/detect-reference.c index 06488226e9..55b873b13b 100644 --- a/src/detect-reference.c +++ b/src/detect-reference.c @@ -1,33 +1,383 @@ -/* REFERENCE part of the detection engine. */ +/* Copyright (c) 2009, 2010 Open Information Security Foundation */ + +/** + * \file + * \author Breno Silva + */ #include "suricata-common.h" +#include "suricata.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" + +#include "decode.h" #include "detect.h" +#include "flow-var.h" +#include "decode-events.h" +#include "stream-tcp.h" + +#include "detect-reference.h" + +#include "util-unittest.h" +#include "util-byte.h" +#include "util-debug.h" + +#define PARSE_REGEX "^\\s*(cve|nessus|url|mcafee|bugtraq|arachnids)\\s*,\"?\\s*\"?\\s*([a-zA-Z0-9\\-_\\.\\/\\?\\=]+)\"?\\s*\"?" + +/* Static prefix for references - Maybe we should move them to reference.config in the future */ +char REFERENCE_BUGTRAQ[] = "http://www.securityfocus.com/bid/"; +char REFERENCE_CVE[] = "http://cve.mitre.org/cgi-bin/cvename.cgi?name="; +char REFERENCE_NESSUS[] = "http://cgi.nessus.org/plugins/dump.php3?id="; +char REFERENCE_ARACHNIDS[] = "http://www.whitehats.com/info/IDS"; +char REFERENCE_MCAFEE[] = "http://vil.nai.com/vil/dispVirus.asp?virus_k="; +char REFERENCE_URL[] = "http://"; -static int DetectReferenceSetup (DetectEngineCtx *, Signature *, char *); +static pcre *parse_regex; +static pcre_extra *parse_regex_study; + +static int DetectReferenceSetup (DetectEngineCtx *, Signature *s, char *str); + +/** + * \brief Registration function for reference: keyword + */ void DetectReferenceRegister (void) { sigmatch_table[DETECT_REFERENCE].name = "reference"; sigmatch_table[DETECT_REFERENCE].Match = NULL; sigmatch_table[DETECT_REFERENCE].Setup = DetectReferenceSetup; sigmatch_table[DETECT_REFERENCE].Free = NULL; - sigmatch_table[DETECT_REFERENCE].RegisterTests = NULL; + sigmatch_table[DETECT_REFERENCE].RegisterTests = ReferenceRegisterTests; + + const char *eb; + int opts = 0; + int eo; + + opts |= PCRE_CASELESS; + + parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL); + if (parse_regex == NULL) + { + SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at offset %" PRId32 ": %s", PARSE_REGEX, eo, eb); + goto error; + } + + parse_regex_study = pcre_study(parse_regex, 0, &eb); + if (eb != NULL) + { + SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); + goto error; + } + +error: + return; + +} + +/** + * \brief Free a Reference object + */ +void DetectReferenceFree(Reference *ref) { + SCEnter(); + + if (ref->reference != NULL) { + SCFree(ref->reference); + } + SCFree(ref); + + SCReturn; +} + +/** + * \internal + * \brief This function is used to parse reference options passed via reference: keyword + * + * \param rawstr Pointer to the user provided reference options + * + * \retval ref pointer to signature reference on success + * \retval NULL on failure + */ +static Reference *DetectReferenceParse (char *rawstr) +{ + SCEnter(); + + Reference *ref = NULL; + char *str = NULL; +#define MAX_SUBSTRINGS 30 + int ret = 0, res = 0; + int ov[MAX_SUBSTRINGS]; + const char *ref_key = NULL; + const char *ref_content = NULL; + + ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); + if (ret < 2) { + SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); + goto error; + } + + ref = SCMalloc(sizeof(Reference)); + if (ref == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "malloc failed: %s", strerror(errno)); + goto error; + } + memset(ref, 0, sizeof(Reference)); + + res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS,1, &ref_key); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS,2, &ref_content); + if (res < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + if (ref_key == NULL || ref_content == NULL) + goto error; + + if (strcasecmp(ref_key,"cve") == 0) { + ref->key = REFERENCE_CVE; + } else if (strcasecmp(ref_key,"bugtraq") == 0) { + ref->key = REFERENCE_BUGTRAQ; + } else if (strcasecmp(ref_key,"nessus") == 0) { + ref->key = REFERENCE_NESSUS; + } else if (strcasecmp(ref_key,"url") == 0) { + ref->key = REFERENCE_URL; + } else if (strcasecmp(ref_key,"mcafee") == 0) { + ref->key = REFERENCE_MCAFEE; + } else if (strcasecmp(ref_key,"arachnids") == 0) { + ref->key = REFERENCE_ARACHNIDS; + } else { + SCLogError(SC_ERR_REFERENCE_UNKNOWN, "unknown reference key \"%s\". " + "Supported keys are cve, bugtraq, nessus, url, mcafee, " + "arachnids.", ref_key); + goto error; + } + + /* make a copy so we can free pcre's substring */ + str = SCStrdup((char *)ref_content); + if (str == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "strdup failed: %s", strerror(errno)); + goto error; + } + + ref->reference = str; + + /* free the substrings */ + pcre_free_substring(ref_key); + pcre_free_substring(ref_content); + + SCReturnPtr(ref, "Reference"); + +error: + if (ref_key != NULL) { + pcre_free_substring(ref_key); + } + if (ref_content != NULL) { + pcre_free_substring(ref_content); + } + + if (ref != NULL) { + DetectReferenceFree(ref); + } + + SCReturnPtr(NULL, "Reference"); +} + +/** + * \internal + * \brief this function is used to add the parsed reference 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 reference options + * + * \retval 0 on Success + * \retval -1 on Failure + */ +static int DetectReferenceSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +{ + SCEnter(); + + Reference *ref = NULL; + Reference *actual_reference = NULL; + + ref = DetectReferenceParse(rawstr); + if (ref == NULL) + goto error; + + SCLogDebug("ref %s %s", ref->key, ref->reference); + + if (s->references == NULL) { + s->references = ref; + ref->next = NULL; + } else { + actual_reference = s->references; + + while (actual_reference->next != NULL) { + actual_reference = actual_reference->next; + } + + actual_reference->next = ref; + ref->next = NULL; + } + + SCLogDebug("s->references %p", s->references); + SCReturnInt(0); + +error: + if (ref != NULL) { + DetectReferenceFree(ref); + } + + SCReturnInt(-1); +} + +/* + * ONLY TESTS BELOW THIS COMMENT + */ +#ifdef UNITTESTS + +/** + * \test one valid reference. + * + * \retval 1 on succces + * \retval 0 on failure + */ +static int DetectReferenceParseTest01(void) +{ + int result = 0; + Signature *s = NULL; + Reference *ref = NULL; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto cleanup; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any (msg:\"One reference\"; reference:cve,001-2010; sid:2;)"); + + if (s == NULL) { + goto cleanup; + } + + if (s->references == NULL) { + goto cleanup; + } + + ref = s->references; + if (strcmp(ref->key,"http://cve.mitre.org/cgi-bin/cvename.cgi?name=") != 0 || + strcmp(ref->reference,"001-2010") != 0) { + goto cleanup; + } + + result = 1; + +cleanup: + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + return result; + +} + +/** + * \test for two valid references. + * + * \retval 1 on succces + * \retval 0 on failure + */ +static int DetectReferenceParseTest02(void) +{ + int result = 0; + Signature *s = NULL; + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto cleanup; + } + + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any (msg:\"Two references\"; reference:url,www.openinfosecfoundation.org; reference:cve,001-2010; sid:2;)"); + if (s == NULL) { + printf("sig parse failed: "); + goto cleanup; + } + + if (s->references == NULL || s->references->next == NULL) { + printf("no ref or not enough refs: "); + goto cleanup; + } + + if (strcmp(s->references->key, "http://") != 0 || + strcmp(s->references->reference, "www.openinfosecfoundation.org") != 0) { + printf("first ref failed: "); + goto cleanup; + + } + + if (strcmp(s->references->next->key, + "http://cve.mitre.org/cgi-bin/cvename.cgi?name=") != 0 || + strcmp(s->references->next->reference, "001-2010") != 0) { + printf("second ref failed: "); + goto cleanup; + + } + + result = 1; + +cleanup: + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } + return result; + } -int DetectReferenceSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr) +/** + * \test parsing: invalid reference + * + * \retval 1 on succces + * \retval 0 on failure + */ +static int DetectReferenceParseTest03(void) { - char *str = rawstr; - char dubbed = 0; + int result = 0; + Signature *s = NULL; + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto cleanup; + } - /* strip "'s */ - if (rawstr[0] == '\"' && rawstr[strlen(rawstr)-1] == '\"') { - str = SCStrdup(rawstr+1); - str[strlen(rawstr)-2] = '\0'; - dubbed = 1; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any (msg:\"invalid ref\"; reference:unknownkey,001-2010; sid:2;)"); + if (s != NULL) { + printf("sig parsed even though it's invalid: "); + goto cleanup; } - /* XXX */ + result = 1; +cleanup: + if (de_ctx != NULL) { + DetectEngineCtxFree(de_ctx); + } - if (dubbed) SCFree(str); - return 0; + return result; } +#endif /* UNITTESTS */ +void ReferenceRegisterTests(void) { +#ifdef UNITTESTS + UtRegisterTest("DetectReferenceParseTest01", DetectReferenceParseTest01, 1); + UtRegisterTest("DetectReferenceParseTest02", DetectReferenceParseTest02, 1); + UtRegisterTest("DetectReferenceParseTest03", DetectReferenceParseTest03, 1); +#endif /* UNITTESTS */ +} diff --git a/src/detect-reference.h b/src/detect-reference.h index 61c6deac77..21bc79d07c 100644 --- a/src/detect-reference.h +++ b/src/detect-reference.h @@ -1,8 +1,38 @@ +/* Copyright (c) 2009, 2010 Open Information Security Foundation */ + +/** + * \file + * \author Breno Silva + */ + #ifndef __DETECT_REFERENCE_H__ #define __DETECT_REFERENCE_H__ -/* prototypes */ +#include "decode-events.h" +#include "decode-ipv4.h" +#include "decode-tcp.h" + +/** Signature reference list */ +typedef struct Reference_ { + char *key; /**< pointer to key */ + char *reference; /**< reference data */ + struct Reference_ *next; /**< next reference in the signature */ +} Reference; + +/** + * Registration function for reference: keyword + */ void DetectReferenceRegister (void); -#endif /* __DETECT_REFERENCE_H__ */ +/** + * This function registers unit tests for Reference + */ +void ReferenceRegisterTests(void); + +/** + * Free function for a Reference object + */ +void DetectReferenceFree(Reference *); + +#endif /*__DETECT_REFERENCE_H__ */ diff --git a/src/detect.c b/src/detect.c index 07818771a5..2e933dddfd 100644 --- a/src/detect.c +++ b/src/detect.c @@ -388,26 +388,28 @@ int PacketAlertCheck(Packet *p, uint32_t sid) return match; } -int PacketAlertAppend(Packet *p, uint32_t gid, uint32_t sid, uint8_t rev, - uint8_t prio, char *msg, char *class_msg) +int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p) { if (p->alerts.cnt == PACKET_ALERT_MAX) return 0; - SCLogDebug("sid %"PRIu32"", sid); + SCLogDebug("sid %"PRIu32"", s->id); - if (gid > 1) - p->alerts.alerts[p->alerts.cnt].gid = gid; + if (s->gid > 1) + p->alerts.alerts[p->alerts.cnt].gid = s->gid; else p->alerts.alerts[p->alerts.cnt].gid = 1; - p->alerts.alerts[p->alerts.cnt].sid = sid; - p->alerts.alerts[p->alerts.cnt].rev = rev; - p->alerts.alerts[p->alerts.cnt].prio = prio; - p->alerts.alerts[p->alerts.cnt].msg = msg; - p->alerts.alerts[p->alerts.cnt].class_msg = class_msg; + p->alerts.alerts[p->alerts.cnt].sid = s->id; + p->alerts.alerts[p->alerts.cnt].rev = s->rev; + p->alerts.alerts[p->alerts.cnt].prio = s->prio; + p->alerts.alerts[p->alerts.cnt].msg = s->msg; + p->alerts.alerts[p->alerts.cnt].class_msg = s->class_msg; + p->alerts.alerts[p->alerts.cnt].references = s->references; p->alerts.cnt++; + SCPerfCounterIncr(det_ctx->counter_alerts, det_ctx->tv->sc_perf_pca); + return 0; } @@ -506,7 +508,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh (p->flowflags & FLOW_PKT_TOCLIENT && !(p->flowflags & FLOW_PKT_TOCLIENT_IPONLY_SET))) { SCLogDebug("testing against \"ip-only\" signatures"); - IPOnlyMatchPacket(de_ctx, &de_ctx->io_ctx, &det_ctx->io_ctx, p); + IPOnlyMatchPacket(de_ctx, det_ctx, &de_ctx->io_ctx, &det_ctx->io_ctx, p); /* save in the flow that we scanned this direction... locking is * done in the FlowSetIPOnlyFlag function. */ if (p->flow != NULL) { @@ -520,7 +522,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh if (p->flow->flags & FLOW_ACTION_DROP) p->action |= ACTION_DROP; } else { /* Even without flow we should match the packet src/dst */ - IPOnlyMatchPacket(de_ctx, &de_ctx->io_ctx, &det_ctx->io_ctx, p); + IPOnlyMatchPacket(de_ctx, det_ctx, &de_ctx->io_ctx, &det_ctx->io_ctx, p); } /* we assume we have an uri when we start inspection */ @@ -680,7 +682,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh fmatch = 1; if (!(s->flags & SIG_FLAG_NOALERT)) { - PacketAlertHandle(de_ctx,s,p); + PacketAlertHandle(de_ctx, det_ctx, s, p); /* set verdict on packet */ p->action |= s->action; } @@ -718,7 +720,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh if (!(s->flags & SIG_FLAG_NOALERT)) { /* only add once */ if (rmatch == 0) { - PacketAlertHandle(de_ctx,s,p); + PacketAlertHandle(de_ctx, det_ctx, s, p); /* set verdict on packet */ p->action |= s->action; } @@ -764,7 +766,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh if (!(s->flags & SIG_FLAG_NOALERT)) { /* set flowbit for this match */ - PacketAlertHandle(de_ctx,s,p); + PacketAlertHandle(de_ctx, det_ctx, s, p); /* set verdict on packet */ p->action |= s->action; @@ -8462,6 +8464,62 @@ static int SigTestDepthOffset01Wm (void) { return SigTestDepthOffset01Real(MPM_WUMANBER); } +static int SigTestDetectAlertCounter(void) +{ + Packet p; + ThreadVars tv; + DetectEngineThreadCtx *det_ctx = NULL; + int result = 0; + + memset(&tv, 0, sizeof(tv)); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Test counter\"; " + "content:\"boo\"; sid:1;)"); + if (de_ctx->sig_list == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + tv.name = "detect_test"; + DetectEngineThreadCtxInit(&tv, de_ctx, (void *)&det_ctx); + + memset(&p, 0, sizeof(p)); + p.src.family = AF_INET; + p.dst.family = AF_INET; + p.payload = (uint8_t *)"boo"; + p.payload_len = strlen((char *)p.payload); + p.proto = IPPROTO_TCP; + Detect(&tv, &p, det_ctx, NULL); + result = (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 1); + + Detect(&tv, &p, det_ctx, NULL); + result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 2); + + p.payload = (uint8_t *)"roo"; + p.payload_len = strlen((char *)p.payload); + Detect(&tv, &p, det_ctx, NULL); + result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 2); + + p.payload = (uint8_t *)"laboosa"; + p.payload_len = strlen((char *)p.payload); + Detect(&tv, &p, det_ctx, NULL); + result &= (SCPerfGetLocalCounterValue(det_ctx->counter_alerts, tv.sc_perf_pca) == 3); + +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} #endif /* UNITTESTS */ @@ -8663,6 +8721,8 @@ void SigRegisterTests(void) { UtRegisterTest("SigTestDepthOffset01B3g", SigTestDepthOffset01B3g, 1); UtRegisterTest("SigTestDepthOffset01Wm", SigTestDepthOffset01Wm, 1); + UtRegisterTest("SigTestDetectAlertCounter", SigTestDetectAlertCounter, 1); + #endif /* UNITTESTS */ } diff --git a/src/detect.h b/src/detect.h index 6fb5394e79..006a7fde87 100644 --- a/src/detect.h +++ b/src/detect.h @@ -6,6 +6,7 @@ #include "flow.h" #include "detect-engine-proto.h" +#include "detect-reference.h" #include "packet-queue.h" #include "util-mpm.h" @@ -208,6 +209,9 @@ typedef struct Signature_ { /** classification message */ char *class_msg; + /** Reference */ + Reference *references; + /** addresses, ports and proto this sig matches on */ DetectAddressHead src, dst; DetectProto proto; @@ -411,6 +415,9 @@ enum { * Detection engine thread data. */ typedef struct DetectionEngineThreadCtx_ { + /* the thread to which this detection engine thread belongs */ + ThreadVars *tv; + /* detection engine variables */ /** offset into the payload of the last match by: @@ -659,8 +666,7 @@ int SigGroupBuild(DetectEngineCtx *); int SigGroupCleanup(); void SigAddressPrepareBidirectionals (DetectEngineCtx *); -int PacketAlertAppend(Packet *, uint32_t, uint32_t, uint8_t, uint8_t, char *, - char *); +int PacketAlertAppend(DetectEngineThreadCtx *, Signature *s, Packet *); int SigLoadSignatures (DetectEngineCtx *, char *); void SigTableSetup(void); diff --git a/src/util-error.c b/src/util-error.c index 80ac78c7cb..6d65d1a62a 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -138,6 +138,7 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_LIBNET_WRITE_FAILED); CASE_CODE (SC_ERR_LIBNET_NOT_ENABLED); CASE_CODE (SC_ERR_UNIFIED_LOG_FILE_HEADER); + CASE_CODE (SC_ERR_REFERENCE_UNKNOWN); default: return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index 7d392417ef..cc32e86c78 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -156,6 +156,7 @@ typedef enum { SC_ERR_UNIFIED_LOG_FILE_HEADER, /**< Error to indicate the unified file header writing function has been failed */ + SC_ERR_REFERENCE_UNKNOWN, /**< unknown reference key (cve, url, etc) */ } SCError;