Support for reference.config file

remotes/origin/master-1.1.x
Anoop Saldanha 16 years ago committed by Victor Julien
parent f5a02833dd
commit 88d94b136d

@ -168,6 +168,7 @@ util-daemon.c util-daemon.h \
util-random.c util-random.h \ util-random.c util-random.h \
util-classification-config.c util-classification-config.h \ util-classification-config.c util-classification-config.h \
util-threshold-config.c util-threshold-config.h \ util-threshold-config.c util-threshold-config.h \
util-reference-config.c util-reference-config.h \
util-strlcatu.c \ util-strlcatu.c \
util-strlcpyu.c \ util-strlcpyu.c \
util-cuda.c util-cuda.h \ util-cuda.c util-cuda.h \

@ -208,7 +208,7 @@ typedef struct PacketAlert_ {
uint32_t sid; uint32_t sid;
char *msg; char *msg;
char *class_msg; char *class_msg;
Reference *references; DetectReference *references;
uint8_t flags; uint8_t flags;
} PacketAlert; } PacketAlert;

@ -2221,7 +2221,7 @@ static int UriTestSig16(void)
de_ctx->mpm_matcher = MPM_B2G; de_ctx->mpm_matcher = MPM_B2G;
de_ctx->flags |= DE_QUIET; de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any (msg:\"ET TROJAN Downadup/Conficker A or B Worm reporting\"; flow:to_server,established; uricontent:\"/search?q=\"; pcre:\"/^\\/search\\?q=[0-9]{1,3}(&aq=7(\\?[0-9a-f]{8})?)?/U\"; pcre:\"/\\x0d\\x0aHost\\: \\d+\\.\\d+\\.\\d+\\.\\d+\\x0d\\x0a/\"; reference:url,www.f-secure.com/weblog/archives/00001584.html; reference:url,doc.emergingthreats.net/bin/view/Main/2009024; reference:url,www.emergingthreats.net/cgi-bin/cvsweb.cgi/sigs/VIRUS/TROJAN_Conficker; sid:2009024; rev:9;)"); s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any (msg:\"ET TROJAN Downadup/Conficker A or B Worm reporting\"; flow:to_server,established; uricontent:\"/search?q=\"; pcre:\"/^\\/search\\?q=[0-9]{1,3}(&aq=7(\\?[0-9a-f]{8})?)?/U\"; pcre:\"/\\x0d\\x0aHost\\: \\d+\\.\\d+\\.\\d+\\.\\d+\\x0d\\x0a/\"; sid:2009024; rev:9;)");
if (s == NULL) { if (s == NULL) {
goto end; goto end;
} }

@ -992,8 +992,8 @@ Signature *SigAlloc (void) {
static void SigRefFree (Signature *s) { static void SigRefFree (Signature *s) {
SCEnter(); SCEnter();
Reference *ref = NULL; DetectReference *ref = NULL;
Reference *next_ref = NULL; DetectReference *next_ref = NULL;
if (s == NULL) { if (s == NULL) {
SCReturn; SCReturn;

@ -19,6 +19,7 @@
* \file * \file
* *
* \author Breno Silva <breno.silva@gmail.com> * \author Breno Silva <breno.silva@gmail.com>
* \author Anoop Saldanha <poonaatsoc@gmail.com>
* *
* Implements the reference keyword support * Implements the reference keyword support
*/ */
@ -35,6 +36,7 @@
#include "decode-events.h" #include "decode-events.h"
#include "stream-tcp.h" #include "stream-tcp.h"
#include "util-reference-config.h"
#include "detect-reference.h" #include "detect-reference.h"
#include "util-unittest.h" #include "util-unittest.h"
@ -43,24 +45,13 @@
#define PARSE_REGEX "^\\s*([A-Za-z]+)\\s*,\"?\\s*\"?\\s*([a-zA-Z0-9\\-_\\.\\/\\?\\=]+)\"?\\s*\"?" #define PARSE_REGEX "^\\s*([A-Za-z]+)\\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://";
char REFERENCE_TELUS[] = "http://";
char REFERENCE_BID[] = "http://";
char REFERENCE_SECUNIA[] = "http://";
static pcre *parse_regex; static pcre *parse_regex;
static pcre_extra *parse_regex_study; static pcre_extra *parse_regex_study;
static int DetectReferenceSetup(DetectEngineCtx *, Signature *s, char *str); static int DetectReferenceSetup(DetectEngineCtx *, Signature *s, char *str);
/** /**
* \brief Registration function for reference: keyword * \brief Registration function for the reference: keyword
*/ */
void DetectReferenceRegister(void) void DetectReferenceRegister(void)
{ {
@ -96,7 +87,7 @@ error:
/** /**
* \brief Free a Reference object * \brief Free a Reference object
*/ */
void DetectReferenceFree(Reference *ref) void DetectReferenceFree(DetectReference *ref)
{ {
SCEnter(); SCEnter();
@ -112,22 +103,21 @@ void DetectReferenceFree(Reference *ref)
* \internal * \internal
* \brief This function is used to parse reference options passed via reference: keyword * \brief This function is used to parse reference options passed via reference: keyword
* *
* \param rawstr Pointer to the user provided reference options * \param rawstr Pointer to the user provided reference options.
* *
* \retval ref Pointer to signature reference on success. * \retval ref Pointer to signature reference on success.
* \retval NULL On failure. * \retval NULL On failure.
*/ */
static Reference *DetectReferenceParse(char *rawstr) static DetectReference *DetectReferenceParse(char *rawstr, DetectEngineCtx *de_ctx)
{ {
SCEnter(); SCEnter();
Reference *ref = NULL; DetectReference *ref = NULL;
char *str = NULL;
#define MAX_SUBSTRINGS 30 #define MAX_SUBSTRINGS 30
int ret = 0, res = 0; int ret = 0, res = 0;
int ov[MAX_SUBSTRINGS]; int ov[MAX_SUBSTRINGS];
const char *ref_key = NULL; const char *key = NULL;
const char *ref_content = NULL; const char *content = NULL;
ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr),
0, 0, ov, MAX_SUBSTRINGS); 0, 0, ov, MAX_SUBSTRINGS);
@ -137,79 +127,60 @@ static Reference *DetectReferenceParse(char *rawstr)
goto error; goto error;
} }
ref = SCMalloc(sizeof(Reference)); ref = SCMalloc(sizeof(DetectReference));
if (ref == NULL) { if (ref == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "malloc failed: %s", strerror(errno)); SCLogError(SC_ERR_MEM_ALLOC, "malloc failed: %s", strerror(errno));
goto error; goto error;
} }
memset(ref, 0, sizeof(Reference)); memset(ref, 0, sizeof(DetectReference));
res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &ref_key); res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &key);
if (res < 0) { if (res < 0) {
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
goto error; goto error;
} }
res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &ref_content); res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &content);
if (res < 0) { if (res < 0) {
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
goto error; goto error;
} }
if (ref_key == NULL || ref_content == NULL) if (key == NULL || content == NULL)
goto error; goto error;
if (strcasecmp(ref_key,"cve") == 0) { SCRConfReference *ref_conf = SCRConfAllocSCRConfReference(key, NULL);
ref->key = REFERENCE_CVE; SCRConfReference *lookup_ref_conf = HashTableLookup(de_ctx->reference_conf_ht,
} else if (strcasecmp(ref_key,"bugtraq") == 0) { ref_conf, 0);
ref->key = REFERENCE_BUGTRAQ; if (lookup_ref_conf != NULL) {
} else if (strcasecmp(ref_key,"nessus") == 0) { ref->key = lookup_ref_conf->url;
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 if (strcasecmp(ref_key,"telus") == 0) {
ref->key = REFERENCE_ARACHNIDS;
} else if (strcasecmp(ref_key,"bid") == 0) {
ref->key = REFERENCE_ARACHNIDS;
} else if (strcasecmp(ref_key,"secunia") == 0) {
ref->key = REFERENCE_SECUNIA;
} else { } else {
SCLogError(SC_ERR_REFERENCE_UNKNOWN, "unknown reference key \"%s\". " SCLogError(SC_ERR_REFERENCE_UNKNOWN, "unknown reference key \"%s\". "
"Supported keys are cve, bugtraq, nessus, url, mcafee, " "Supported keys are defined in reference.config file. Please "
"arachnids.", ref_key); "have a look at the conf param \"reference-config-file\"", key);
goto error; goto error;
} }
SCRConfDeAllocSCRConfReference(ref_conf);
/* make a copy so we can free pcre's substring */ /* make a copy so we can free pcre's substring */
str = SCStrdup((char *)ref_content); ref->reference = SCStrdup((char *)content);
if (str == NULL) { if (ref->reference == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "strdup failed: %s", strerror(errno)); SCLogError(SC_ERR_MEM_ALLOC, "strdup failed: %s", strerror(errno));
goto error; goto error;
} }
ref->reference = str;
/* free the substrings */ /* free the substrings */
pcre_free_substring(ref_key); pcre_free_substring(key);
pcre_free_substring(ref_content); pcre_free_substring(content);
SCReturnPtr(ref, "Reference"); SCReturnPtr(ref, "Reference");
error: error:
if (ref_key != NULL) { if (key != NULL)
pcre_free_substring(ref_key); pcre_free_substring(key);
} if (content != NULL)
if (ref_content != NULL) { pcre_free_substring(content);
pcre_free_substring(ref_content); if (ref != NULL)
}
if (ref != NULL) {
DetectReferenceFree(ref); DetectReferenceFree(ref);
}
SCReturnPtr(NULL, "Reference"); SCReturnPtr(NULL, "Reference");
} }
@ -226,15 +197,15 @@ error:
* \retval 0 On Success. * \retval 0 On Success.
* \retval -1 On Failure. * \retval -1 On Failure.
*/ */
static int DetectReferenceSetup (DetectEngineCtx *de_ctx, Signature *s, static int DetectReferenceSetup(DetectEngineCtx *de_ctx, Signature *s,
char *rawstr) char *rawstr)
{ {
SCEnter(); SCEnter();
Reference *ref = NULL; DetectReference *ref = NULL;
Reference *actual_reference = NULL; DetectReference *sig_refs = NULL;
ref = DetectReferenceParse(rawstr); ref = DetectReferenceParse(rawstr, de_ctx);
if (ref == NULL) if (ref == NULL)
goto error; goto error;
@ -242,19 +213,15 @@ static int DetectReferenceSetup (DetectEngineCtx *de_ctx, Signature *s,
if (s->references == NULL) { if (s->references == NULL) {
s->references = ref; s->references = ref;
ref->next = NULL;
} else { } else {
actual_reference = s->references; sig_refs = s->references;
while (sig_refs->next != NULL) {
while (actual_reference->next != NULL) { sig_refs = sig_refs->next;
actual_reference = actual_reference->next;
} }
sig_refs->next = ref;
actual_reference->next = ref;
ref->next = NULL; ref->next = NULL;
} }
SCLogDebug("s->references %p", s->references);
SCReturnInt(0); SCReturnInt(0);
error: error:
@ -265,30 +232,34 @@ error:
SCReturnInt(-1); SCReturnInt(-1);
} }
/***************************************Unittests******************************/
#ifdef UNITTESTS #ifdef UNITTESTS
/** /**
* \test one valid reference. * \test one valid reference.
* *
* \retval 1 on succces * \retval 1 on succces.
* \retval 0 on failure * \retval 0 on failure.
*/ */
static int DetectReferenceParseTest01(void) static int DetectReferenceParseTest01(void)
{ {
int result = 0; int result = 0;
Signature *s = NULL; Signature *s = NULL;
Reference *ref = NULL; DetectReference *ref = NULL;
DetectEngineCtx *de_ctx = DetectEngineCtxInit(); DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) { if (de_ctx == NULL) {
goto cleanup; goto cleanup;
} }
de_ctx->flags |= DE_QUIET; de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " SCRConfGenerateValidDummyReferenceConfigFD01();
"(msg:\"One reference\"; reference:cve,001-2010; sid:2;)"); SCRConfLoadReferenceConfigFile(de_ctx);
SCRConfDeleteDummyReferenceConfigFD();
s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any "
"(msg:\"One reference\"; reference:one,001-2010; sid:2;)");
if (s == NULL) { if (s == NULL) {
goto cleanup; goto cleanup;
} }
@ -298,8 +269,8 @@ static int DetectReferenceParseTest01(void)
} }
ref = s->references; ref = s->references;
if (strcmp(ref->key,"http://cve.mitre.org/cgi-bin/cvename.cgi?name=") != 0 || if (strcmp(ref->key, "http://www.one.com") != 0 ||
strcmp(ref->reference,"001-2010") != 0) { strcmp(ref->reference, "001-2010") != 0) {
goto cleanup; goto cleanup;
} }
@ -316,8 +287,8 @@ cleanup:
/** /**
* \test for two valid references. * \test for two valid references.
* *
* \retval 1 on succces * \retval 1 on succces.
* \retval 0 on failure * \retval 0 on failure.
*/ */
static int DetectReferenceParseTest02(void) static int DetectReferenceParseTest02(void)
{ {
@ -328,13 +299,16 @@ static int DetectReferenceParseTest02(void)
if (de_ctx == NULL) { if (de_ctx == NULL) {
goto cleanup; goto cleanup;
} }
de_ctx->flags |= DE_QUIET; de_ctx->flags |= DE_QUIET;
SCRConfGenerateValidDummyReferenceConfigFD01();
SCRConfLoadReferenceConfigFile(de_ctx);
SCRConfDeleteDummyReferenceConfigFD();
s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any "
"(msg:\"Two references\"; " "(msg:\"Two references\"; "
"reference:url,www.openinfosecfoundation.org; " "reference:one,openinfosecdoundation.txt; "
"reference:cve,001-2010; sid:2;)"); "reference:two,001-2010; sid:2;)");
if (s == NULL) { if (s == NULL) {
printf("sig parse failed: "); printf("sig parse failed: ");
goto cleanup; goto cleanup;
@ -345,14 +319,13 @@ static int DetectReferenceParseTest02(void)
goto cleanup; goto cleanup;
} }
if (strcmp(s->references->key, "http://") != 0 || if (strcmp(s->references->key, "http://www.one.com") != 0 ||
strcmp(s->references->reference, "www.openinfosecfoundation.org") != 0) { strcmp(s->references->reference, "openinfosecdoundation.txt") != 0) {
printf("first ref failed: "); printf("first ref failed: ");
goto cleanup; goto cleanup;
} }
if (strcmp(s->references->next->key, if (strcmp(s->references->next->key, "http://www.two.com") != 0 ||
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=") != 0 ||
strcmp(s->references->next->reference, "001-2010") != 0) { strcmp(s->references->next->reference, "001-2010") != 0) {
printf("second ref failed: "); printf("second ref failed: ");
goto cleanup; goto cleanup;
@ -368,10 +341,10 @@ cleanup:
} }
/** /**
* \test parsing: invalid reference * \test parsing: invalid reference.
* *
* \retval 1 on succces * \retval 1 on succces.
* \retval 0 on failure * \retval 0 on failure.
*/ */
static int DetectReferenceParseTest03(void) static int DetectReferenceParseTest03(void)
{ {
@ -381,9 +354,12 @@ static int DetectReferenceParseTest03(void)
if (de_ctx == NULL) { if (de_ctx == NULL) {
goto cleanup; goto cleanup;
} }
de_ctx->flags |= DE_QUIET; de_ctx->flags |= DE_QUIET;
SCRConfGenerateValidDummyReferenceConfigFD01();
SCRConfLoadReferenceConfigFile(de_ctx);
SCRConfDeleteDummyReferenceConfigFD();
s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any " s = de_ctx->sig_list = SigInit(de_ctx, "alert icmp any any -> any any "
"(msg:\"invalid ref\"; " "(msg:\"invalid ref\"; "
"reference:unknownkey,001-2010; sid:2;)"); "reference:unknownkey,001-2010; sid:2;)");

@ -28,27 +28,31 @@
#include "decode-ipv4.h" #include "decode-ipv4.h"
#include "decode-tcp.h" #include "decode-tcp.h"
/** Signature reference list */ /**
typedef struct Reference_ { * \brief Signature reference list.
char *key; /**< pointer to key */ */
char *reference; /**< reference data */ typedef struct DetectReference_ {
struct Reference_ *next; /**< next reference in the signature */ /* pointer to key */
} Reference; char *key;
/* reference data */
char *reference;
/* next reference in the signature */
struct DetectReference_ *next;
} DetectReference;
/** /**
* Registration function for reference: keyword * Registration function for Reference keyword
*/ */
void DetectReferenceRegister (void); void DetectReferenceRegister(void);
/** /**
* This function registers unit tests for Reference * This function registers unit tests for Reference keyword.
*/ */
void ReferenceRegisterTests(void); void ReferenceRegisterTests(void);
/** /**
* Free function for a Reference object * Free function for a Reference object
*/ */
void DetectReferenceFree(Reference *); void DetectReferenceFree(DetectReference *);
#endif /*__DETECT_REFERENCE_H__ */ #endif /*__DETECT_REFERENCE_H__ */

@ -382,7 +382,7 @@ typedef struct Signature_ {
char *class_msg; char *class_msg;
/** Reference */ /** Reference */
Reference *references; DetectReference *references;
/* Be careful, this pointer is only valid while parsing the sig, /* Be careful, this pointer is only valid while parsing the sig,
* to warn the user about any possible problem */ * to warn the user about any possible problem */
@ -503,6 +503,8 @@ typedef struct DetectEngineCtx_ {
/* hash table used for holding the classification config info */ /* hash table used for holding the classification config info */
HashTable *class_conf_ht; HashTable *class_conf_ht;
/* hash table used for holding the reference config info */
HashTable *reference_conf_ht;
/* main sigs */ /* main sigs */
DetectEngineLookupFlow flow_gh[FLOW_STATES]; DetectEngineLookupFlow flow_gh[FLOW_STATES];

@ -118,6 +118,7 @@
#include "util-rule-vars.h" #include "util-rule-vars.h"
#include "util-classification-config.h" #include "util-classification-config.h"
#include "util-threshold-config.h" #include "util-threshold-config.h"
#include "util-reference-config.h"
#include "util-profiling.h" #include "util-profiling.h"
#include "defrag.h" #include "defrag.h"
@ -951,6 +952,7 @@ int main(int argc, char **argv)
UtilActionRegisterTests(); UtilActionRegisterTests();
SCClassConfRegisterTests(); SCClassConfRegisterTests();
SCThresholdConfRegisterTests(); SCThresholdConfRegisterTests();
SCRConfRegisterTests();
SSLParserRegisterTests(); SSLParserRegisterTests();
#ifdef __SC_CUDA_SUPPORT__ #ifdef __SC_CUDA_SUPPORT__
SCCudaRegisterTests(); SCCudaRegisterTests();
@ -1059,6 +1061,12 @@ int main(int argc, char **argv)
DetectEngineCtx *de_ctx = DetectEngineCtxInit(); DetectEngineCtx *de_ctx = DetectEngineCtxInit();
SCClassConfLoadClassficationConfigFile(de_ctx); SCClassConfLoadClassficationConfigFile(de_ctx);
if (SCRConfLoadReferenceConfigFile(de_ctx) == -1) {
SCLogInfo("Having trouble loading references from reference.config");
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
ActionInitConfig(); ActionInitConfig();

@ -191,6 +191,7 @@ const char * SCErrorToString(SCError err)
CASE_CODE (SC_WARN_COMPATIBILITY); CASE_CODE (SC_WARN_COMPATIBILITY);
CASE_CODE (SC_ERR_DCERPC); CASE_CODE (SC_ERR_DCERPC);
CASE_CODE (SC_ERR_AHO_CORASICK); CASE_CODE (SC_ERR_AHO_CORASICK);
CASE_CODE (SC_ERR_REFERENCE_CONFIG);
default: default:
return "UNKNOWN_ERROR"; return "UNKNOWN_ERROR";

@ -202,6 +202,7 @@ typedef enum {
SC_ERR_DCERPC, SC_ERR_DCERPC,
SC_ERR_DETECT_PREPARE, /**< preparing the detection engine failed */ SC_ERR_DETECT_PREPARE, /**< preparing the detection engine failed */
SC_ERR_AHO_CORASICK, SC_ERR_AHO_CORASICK,
SC_ERR_REFERENCE_CONFIG,
} SCError; } SCError;
const char *SCErrorToString(SCError); const char *SCErrorToString(SCError);

@ -0,0 +1,794 @@
/* Copyright (C) 2007-2010 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Anoop Saldanha <poonaatsoc@gmail.com>
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-engine.h"
#include "util-hash.h"
#include "util-reference-config.h"
#include "conf.h"
#include "util-unittest.h"
#include "util-error.h"
#include "util-debug.h"
#include "util-fmemopen.h"
/* Regex to parse each line from reference.config file. The first substring
* is for the system name and the second for the url */
/*-----------------------------------------------------------system-------------------url----*/
#define SC_RCONF_REGEX "^\\s*config\\s+reference\\s*:\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s+(.+)\\s*$"
/* Default path for the reference.conf file */
#define SC_RCONF_DEFAULT_FILE_PATH "reference.config"
/* Holds a pointer to the default path for the reference.config file */
static const char *file_path = SC_RCONF_DEFAULT_FILE_PATH;
static FILE *fd = NULL;
static pcre *regex = NULL;
static pcre_extra *regex_study = NULL;
/* the hash functions */
uint32_t SCRConfReferenceHashFunc(HashTable *ht, void *data, uint16_t datalen);
char SCRConfReferenceHashCompareFunc(void *data1, uint16_t datalen1,
void *data2, uint16_t datalen2);
void SCRConfReferenceHashFree(void *ch);
/* used to get the reference.config file path */
static char *SCRConfGetConfFilename(void);
/**
* \brief Inits the context to be used by the Reference Config parsing API.
*
* This function initializes the hash table to be used by the Detection
* Engine Context to hold the data from reference.config file,
* obtains the file descriptor to parse the reference.config file, and
* inits the regex used to parse the lines from reference.config file.
*
* \param de_ctx Pointer to the Detection Engine Context.
*
* \retval 0 On success.
* \retval -1 On failure.
*/
static int SCRConfInitContext(DetectEngineCtx *de_ctx)
{
char *filename = NULL;
const char *eb = NULL;
int eo;
int opts = 0;
/* init the hash table to be used by the reference config references */
de_ctx->reference_conf_ht = HashTableInit(4096, SCRConfReferenceHashFunc,
SCRConfReferenceHashCompareFunc,
SCRConfReferenceHashFree);
if (de_ctx->reference_conf_ht == NULL) {
SCLogError(SC_ERR_HASH_TABLE_INIT, "Error initializing the hash "
"table");
return -1;
}
/* if it is not NULL, use the file descriptor. The hack so that we can
* avoid using a dummy reference file for testing purposes and
* instead use an input stream against a buffer containing the
* reference strings */
if (fd == NULL) {
filename = SCRConfGetConfFilename();
if ((fd = fopen(filename, "r")) == NULL) {
SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename,
strerror(errno));
goto error;
}
}
regex = pcre_compile(SC_RCONF_REGEX, opts, &eb, &eo, NULL);
if (regex == NULL) {
SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s",
SC_RCONF_REGEX, eo, eb);
goto error;
}
regex_study = pcre_study(regex, 0, &eb);
if (eb != NULL) {
SCLogDebug("pcre study failed: %s", eb);
goto error;
}
return 0;
error:
if (de_ctx->reference_conf_ht != NULL) {
HashTableFree(de_ctx->reference_conf_ht);
de_ctx->reference_conf_ht = NULL;
}
if (fd != NULL) {
fclose(fd);
fd = NULL;
}
return -1;
}
/**
* \brief Returns the path for the Reference Config file. We check if we
* can retrieve the path from the yaml conf file. If it is not present,
* return the default path for the reference.config file which is
* "./reference.config".
*
* \retval log_filename Pointer to a string containing the path for the
* reference.config file.
*/
static char *SCRConfGetConfFilename(void)
{
char *path = (char *)file_path;
ConfGet("reference-config-file", &path);
return path;
}
/**
* \brief Releases resources used by the Reference Config API.
*/
static void SCRConfDeInitContext(DetectEngineCtx *de_ctx)
{
if (fd != NULL)
fclose(fd);
file_path = SC_RCONF_DEFAULT_FILE_PATH;
fd = NULL;
return;
}
/**
* \brief Converts a string to lowercase.
*
* \param str Pointer to the string to be converted.
*/
static char *SCRConfStringToLowercase(const char *str)
{
char *new_str = NULL;
char *temp_str = NULL;
if ( (new_str = SCStrdup(str)) == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
exit(EXIT_FAILURE);
}
temp_str = new_str;
while (*temp_str != '\0') {
*temp_str = tolower(*temp_str);
temp_str++;
}
return new_str;
}
/**
* \brief Parses a line from the reference config file and adds it to Reference
* Config hash table DetectEngineCtx->reference_conf_ht.
*
* \param rawstr Pointer to the string to be parsed.
* \param de_ctx Pointer to the Detection Engine Context.
*
* \retval 0 On success.
* \retval -1 On failure.
*/
static int SCRConfAddReference(char *rawstr, DetectEngineCtx *de_ctx)
{
const char *system = NULL;
const char *url = NULL;
SCRConfReference *ref_new = NULL;
SCRConfReference *ref_lookup = NULL;
#define MAX_SUBSTRINGS 30
int ret = 0;
int ov[MAX_SUBSTRINGS];
ret = pcre_exec(regex, regex_study, rawstr, strlen(rawstr), 0, 0, ov, 30);
if (ret < 0) {
SCLogError(SC_ERR_REFERENCE_CONFIG, "Invalid Reference Config in "
"reference.config file");
goto error;
}
/* retrieve the reference system */
ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &system);
if (ret < 0) {
SCLogInfo("pcre_get_substring() failed");
goto error;
}
/* retrieve the reference url */
ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &url);
if (ret < 0) {
SCLogInfo("pcre_get_substring() failed");
goto error;
}
/* Create a new instance of the parsed Reference string */
ref_new = SCRConfAllocSCRConfReference(system, url);
/* Check if the Reference is present in the HashTable. In case it's present
* ignore it, as it's a duplicate. If not present, add it to the table */
ref_lookup = HashTableLookup(de_ctx->reference_conf_ht, ref_new, 0);
if (ref_lookup == NULL) {
if (HashTableAdd(de_ctx->reference_conf_ht, ref_new, 0) < 0) {
SCLogDebug("HashTable Add failed");
}
} else {
SCLogDebug("Duplicate reference found inside reference.config");
SCRConfDeAllocSCRConfReference(ref_new);
}
/* free the substrings */
pcre_free_substring(system);
pcre_free_substring(url);
return 0;
error:
if (system)
pcre_free_substring(system);
if (url)
pcre_free_substring(url);
return -1;
}
/**
* \brief Checks if a string is a comment or a blank line.
*
* Comments lines are lines of the following format -
* "# This is a comment string" or
* " # This is a comment string".
*
* \param line String that has to be checked.
*
* \retval 1 On the argument string being a comment or blank line.
* \retval 0 Otherwise.
*/
static int SCRConfIsLineBlankOrComment(char *line)
{
while (*line != '\0') {
/* we have a comment */
if (*line == '#')
return 1;
/* this line is neither a comment line, nor a blank line */
if (!isspace(*line))
return 0;
line++;
}
/* we have a blank line */
return 1;
}
/**
* \brief Parses the Reference Config file and updates the
* DetectionEngineCtx->reference_conf_ht with the Reference information.
*
* \param de_ctx Pointer to the Detection Engine Context.
*/
static void SCRConfParseFile(DetectEngineCtx *de_ctx)
{
char line[1024];
uint8_t i = 1;
while (fgets(line, sizeof(line), fd) != NULL) {
if (SCRConfIsLineBlankOrComment(line))
continue;
SCRConfAddReference(line, de_ctx);
i++;
}
SCLogInfo("Added \"%d\" reference types from the reference.config file",
de_ctx->reference_conf_ht->count);
return;
}
/**
* \brief Returns a new SCRConfReference instance. The reference string
* is converted into lowercase, before being assigned to the instance.
*
* \param system Pointer to the system.
* \param url Pointer to the reference url.
*
* \retval ref Pointer to the new instance of SCRConfReference.
*/
SCRConfReference *SCRConfAllocSCRConfReference(const char *system,
const char *url)
{
SCRConfReference *ref = NULL;
if (system == NULL) {
SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid arguments. system NULL");
return NULL;
}
if ((ref = SCMalloc(sizeof(SCRConfReference))) == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
exit(EXIT_FAILURE);
}
memset(ref, 0, sizeof(SCRConfReference));
if ((ref->system = SCRConfStringToLowercase(system)) == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
exit(EXIT_FAILURE);
}
if (url != NULL && (ref->url = SCStrdup(url)) == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
exit(EXIT_FAILURE);
}
return ref;
}
/**
* \brief Frees a SCRConfReference instance.
*
* \param Pointer to the SCRConfReference instance that has to be freed.
*/
void SCRConfDeAllocSCRConfReference(SCRConfReference *ref)
{
if (ref != NULL) {
if (ref->system != NULL)
SCFree(ref->system);
if (ref->url != NULL)
SCFree(ref->url);
SCFree(ref);
}
return;
}
/**
* \brief Hashing function to be used to hash the Reference name. Would be
* supplied as an argument to the HashTableInit function for
* DetectEngineCtx->reference_conf_ht.
*
* \param ht Pointer to the HashTable.
* \param data Pointer to the data to be hashed. In this case, the data
* would be a pointer to a SCRConfReference instance.
* \param datalen Not used by this function.
*/
uint32_t SCRConfReferenceHashFunc(HashTable *ht, void *data, uint16_t datalen)
{
SCRConfReference *ref = (SCRConfReference *)data;
uint32_t hash = 0;
int i = 0;
int len = strlen(ref->system);
for (i = 0; i < len; i++)
hash += tolower(ref->system[i]);
hash = hash % ht->array_size;
return hash;
}
/**
* \brief Used to compare two References that have been stored in the HashTable.
* This function is supplied as an argument to the HashTableInit function
* for DetectionEngineCtx->reference_conf_ct.
*
* \param data1 Pointer to the first SCRConfReference to be compared.
* \param len1 Not used by this function.
* \param data2 Pointer to the second SCRConfReference to be compared.
* \param len2 Not used by this function.
*
* \retval 1 On data1 and data2 being equal.
* \retval 0 On data1 and data2 not being equal.
*/
char SCRConfReferenceHashCompareFunc(void *data1, uint16_t datalen1,
void *data2, uint16_t datalen2)
{
SCRConfReference *ref1 = (SCRConfReference *)data1;
SCRConfReference *ref2 = (SCRConfReference *)data2;
int len1 = 0;
int len2 = 0;
if (ref1 == NULL || ref2 == NULL)
return 0;
if (ref1->system == NULL || ref2->system == NULL)
return 0;
len1 = strlen(ref1->system);
len2 = strlen(ref2->system);
if (len1 == len2 && memcmp(ref1->system, ref2->system, len1) == 0) {
SCLogDebug("Match found inside Reference-Config hash function");
return 1;
}
return 0;
}
/**
* \brief Used to free the Reference Config Hash Data that was stored in
* DetectEngineCtx->reference_conf_ht Hashtable.
*
* \param data Pointer to the data that has to be freed.
*/
void SCRConfReferenceHashFree(void *data)
{
SCRConfDeAllocSCRConfReference(data);
return;
}
/**
* \brief Loads the Reference info from the reference.config file.
*
* The reference.config file contains references that can be used in
* Signatures. Each line of the file should have the following format -
* config reference: system_name, reference_url.
*
* \param de_ctx Pointer to the Detection Engine Context that should be updated
* with reference information.
*
* \retval 0 On success.
* \retval -1 On failure.
*/
int SCRConfLoadReferenceConfigFile(DetectEngineCtx *de_ctx)
{
if (SCRConfInitContext(de_ctx) == -1) {
SCLogError(SC_ERR_REFERENCE_CONFIG, "Error initializing reference "
"config API");
return -1;
}
SCRConfParseFile(de_ctx);
SCRConfDeInitContext(de_ctx);
return 0;
}
/*----------------------------------Unittests---------------------------------*/
#ifdef UNITTESTS
/**
* \brief Creates a dummy reference config, with all valid references, for
* testing purposes.
*/
void SCRConfGenerateValidDummyReferenceConfigFD01(void)
{
const char *buffer =
"config reference: one http://www.one.com\n"
"config reference: two http://www.two.com\n"
"config reference: three http://www.three.com\n"
"config reference: one http://www.one.com\n"
"config reference: three http://www.three.com\n";
fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
if (fd == NULL)
SCLogDebug("Error with SCFmemopen() called by Reference Config test code");
return;
}
/**
* \brief Creates a dummy reference config, with some valid references and a
* couple of invalid references, for testing purposes.
*/
void SCRConfGenerateInValidDummyReferenceConfigFD02(void)
{
const char *buffer =
"config reference: one http://www.one.com\n"
"config_ reference: two http://www.two.com\n"
"config reference_: three http://www.three.com\n"
"config reference: four\n"
"config reference five http://www.five.com\n";
fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
if (fd == NULL)
SCLogDebug("Error with SCFmemopen() called by Reference Config test code");
return;
}
/**
* \brief Creates a dummy reference config, with all invalid references, for
* testing purposes.
*/
void SCRConfGenerateInValidDummyReferenceConfigFD03(void)
{
const char *buffer =
"config reference one http://www.one.com\n"
"config_ reference: two http://www.two.com\n"
"config reference_: three http://www.three.com\n"
"config reference: four\n";
fd = SCFmemopen((void *)buffer, strlen(buffer), "r");
if (fd == NULL)
SCLogDebug("Error with SCFmemopen() called by Reference Config test code");
return;
}
/**
* \brief Deletes the FD, if set by the other testing functions.
*/
void SCRConfDeleteDummyReferenceConfigFD(void)
{
if (fd != NULL) {
fclose(fd);
fd = NULL;
}
return;
}
/**
* \test Check that the reference file is loaded and the detection engine
* content reference_conf_ht loaded with the reference data.
*/
int SCRConfTest01(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
int result = 0;
if (de_ctx == NULL)
return result;
SCRConfGenerateValidDummyReferenceConfigFD01();
SCRConfLoadReferenceConfigFile(de_ctx);
SCRConfDeleteDummyReferenceConfigFD();
if (de_ctx->reference_conf_ht == NULL)
goto end;
result = (de_ctx->reference_conf_ht->count == 3);
if (result == 0)
printf("FAILED: de_ctx->reference_conf_ht->count %u: ", de_ctx->reference_conf_ht->count);
end:
if (de_ctx != NULL)
DetectEngineCtxFree(de_ctx);
return result;
}
/**
* \test Check that invalid references present in the reference.config file
* aren't loaded.
*/
int SCRConfTest02(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
int result = 0;
if (de_ctx == NULL)
return result;
SCRConfGenerateInValidDummyReferenceConfigFD03();
SCRConfLoadReferenceConfigFile(de_ctx);
SCRConfDeleteDummyReferenceConfigFD();
if (de_ctx->reference_conf_ht == NULL)
goto end;
result = (de_ctx->reference_conf_ht->count == 0);
end:
if (de_ctx != NULL)
DetectEngineCtxFree(de_ctx);
return result;
}
/**
* \test Check that only valid references are loaded into the hash table from
* the reference.config file.
*/
int SCRConfTest03(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
int result = 0;
if (de_ctx == NULL)
return result;
SCRConfGenerateInValidDummyReferenceConfigFD02();
SCRConfLoadReferenceConfigFile(de_ctx);
SCRConfDeleteDummyReferenceConfigFD();
if (de_ctx->reference_conf_ht == NULL)
goto end;
result = (de_ctx->reference_conf_ht->count == 1);
end:
if (de_ctx != NULL)
DetectEngineCtxFree(de_ctx);
return result;
}
/**
* \test Check if the reference info from the reference.config file have
* been loaded into the hash table.
*/
int SCRConfTest04(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
SCRConfReference *ref = NULL;
int result = 1;
if (de_ctx == NULL)
return 0;
SCRConfGenerateValidDummyReferenceConfigFD01();
SCRConfLoadReferenceConfigFile(de_ctx);
SCRConfDeleteDummyReferenceConfigFD();
if (de_ctx->reference_conf_ht == NULL)
goto end;
result = (de_ctx->reference_conf_ht->count == 3);
ref = SCRConfAllocSCRConfReference("one", "http://www.one.com");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) != NULL);
SCRConfDeAllocSCRConfReference(ref);
ref = SCRConfAllocSCRConfReference("two", "http://www.two.com");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) != NULL);
SCRConfDeAllocSCRConfReference(ref);
ref = SCRConfAllocSCRConfReference("three", "http://www.three.com");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) != NULL);
SCRConfDeAllocSCRConfReference(ref);
ref = SCRConfAllocSCRConfReference("four", "http://www.four.com");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) == NULL);
SCRConfDeAllocSCRConfReference(ref);
end:
if (de_ctx != NULL)
DetectEngineCtxFree(de_ctx);
return result;
}
/**
* \test Check if the reference info from the invalid reference.config file
* have not been loaded into the hash table, and cross verify to check
* that the hash table contains no reference data.
*/
int SCRConfTest05(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
SCRConfReference *ref = NULL;
int result = 1;
if (de_ctx == NULL)
return 0;
SCRConfGenerateInValidDummyReferenceConfigFD03();
SCRConfLoadReferenceConfigFile(de_ctx);
SCRConfDeleteDummyReferenceConfigFD();
if (de_ctx->reference_conf_ht == NULL)
goto end;
result = (de_ctx->reference_conf_ht->count == 0);
ref = SCRConfAllocSCRConfReference("one", "one");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) == NULL);
SCRConfDeAllocSCRConfReference(ref);
ref = SCRConfAllocSCRConfReference("two", "two");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) == NULL);
SCRConfDeAllocSCRConfReference(ref);
ref = SCRConfAllocSCRConfReference("three", "three");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) == NULL);
SCRConfDeAllocSCRConfReference(ref);
ref = SCRConfAllocSCRConfReference("four", "four");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) == NULL);
SCRConfDeAllocSCRConfReference(ref);
ref = SCRConfAllocSCRConfReference("five", "five");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) == NULL);
SCRConfDeAllocSCRConfReference(ref);
end:
if (de_ctx != NULL)
DetectEngineCtxFree(de_ctx);
return result;
}
/**
* \test Check if the reference info from the reference.config file have
* been loaded into the hash table.
*/
int SCRConfTest06(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
SCRConfReference *ref = NULL;
int result = 1;
if (de_ctx == NULL)
return 0;
SCRConfGenerateInValidDummyReferenceConfigFD02();
SCRConfLoadReferenceConfigFile(de_ctx);
SCRConfDeleteDummyReferenceConfigFD();
if (de_ctx->reference_conf_ht == NULL)
goto end;
result = (de_ctx->reference_conf_ht->count == 1);
ref = SCRConfAllocSCRConfReference("one", "one");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) != NULL);
SCRConfDeAllocSCRConfReference(ref);
ref = SCRConfAllocSCRConfReference("two", "two");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) == NULL);
SCRConfDeAllocSCRConfReference(ref);
ref = SCRConfAllocSCRConfReference("three", "three");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) == NULL);
SCRConfDeAllocSCRConfReference(ref);
ref = SCRConfAllocSCRConfReference("four", "four");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) == NULL);
SCRConfDeAllocSCRConfReference(ref);
ref = SCRConfAllocSCRConfReference("five", "five");
result &= (HashTableLookup(de_ctx->reference_conf_ht, ref, 0) == NULL);
SCRConfDeAllocSCRConfReference(ref);
end:
if (de_ctx != NULL)
DetectEngineCtxFree(de_ctx);
return result;
}
#endif /* UNITTESTS */
/**
* \brief This function registers unit tests for Reference Config API.
*/
void SCRConfRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("SCRConfTest01", SCRConfTest01, 1);
UtRegisterTest("SCRConfTest02", SCRConfTest02, 1);
UtRegisterTest("SCRConfTest03", SCRConfTest03, 1);
UtRegisterTest("SCRConfTest04", SCRConfTest04, 1);
UtRegisterTest("SCRConfTest05", SCRConfTest05, 1);
UtRegisterTest("SCRConfTest06", SCRConfTest06, 1);
#endif /* UNITTESTS */
return;
}

@ -0,0 +1,48 @@
/* Copyright (C) 2007-2010 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Anoop Saldanha <poonaatsoc@gmail.com>
*/
#ifndef __UTIL_REFERENCE_CONFIG_H__
#define __UTIL_REFERENCE_CONFIG_H__
/**
* \brief Holds a reference from the file - reference.config.
*/
typedef struct SCRConfReference_ {
/* The system name. This is the primary key for a reference. */
char *system;
/* The url for the above reference */
char *url;
} SCRConfReference;
SCRConfReference *SCRConfAllocSCRConfReference(const char *, const char *);
void SCRConfDeAllocSCRConfReference(SCRConfReference *);
int SCRConfLoadReferenceConfigFile(DetectEngineCtx *);
void SCRConfRegisterTests(void);
/* these below functions are only used by unittests */
void SCRConfGenerateValidDummyReferenceConfigFD01(void);
void SCRConfGenerateInValidDummyReferenceConfigFD02(void);
void SCRConfGenerateInValidDummyReferenceConfigFD03(void);
void SCRConfDeleteDummyReferenceConfigFD(void);
#endif /* __UTIL_REFERENCE_CONFIG_H__ */

@ -443,6 +443,7 @@ rule-files:
- emerging-current_events.rules - emerging-current_events.rules
classification-file: /etc/suricata/classification.config classification-file: /etc/suricata/classification.config
reference-config-file: /etc/suricata/reference.config
# Holds variables that would be used by the engine. # Holds variables that would be used by the engine.
vars: vars:

Loading…
Cancel
Save