Support for Classtype keyword and Classification Config file

remotes/origin/master-1.0.x
Anoop Saldanha 15 years ago committed by Victor Julien
parent f0be69dcd0
commit bc4df59414

@ -119,6 +119,7 @@ util-rule-vars.c util-rule-vars.h \
util-fix_checksum.c util-fix_checksum.h \
util-daemon.c util-daemon.h \
util-random.c util-random.h \
util-classification-config.c util-classification-config.h \
tm-modules.c tm-modules.h \
tm-queues.c tm-queues.h \
tm-queuehandlers.c tm-queuehandlers.h \

@ -24,6 +24,12 @@
#include "util-debug.h"
#include "util-unittest.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-mpm.h"
#include "util-classification-config.h"
#define DEFAULT_LOG_FILENAME "fast.log"
TmEcode AlertFastlog (ThreadVars *, Packet *, void *, PacketQueue *);
@ -33,6 +39,7 @@ TmEcode AlertFastlogThreadInit(ThreadVars *, void *, void **);
TmEcode AlertFastlogThreadDeinit(ThreadVars *, void *);
void AlertFastlogExitPrintStats(ThreadVars *, void *);
int AlertFastlogOpenFileCtx(LogFileCtx *, char *);
void AlertFastLogRegisterTests(void);
void TmModuleAlertFastlogRegister (void) {
tmm_modules[TMM_ALERTFASTLOG].name = "AlertFastlog";
@ -40,7 +47,7 @@ void TmModuleAlertFastlogRegister (void) {
tmm_modules[TMM_ALERTFASTLOG].Func = AlertFastlog;
tmm_modules[TMM_ALERTFASTLOG].ThreadExitPrintStats = AlertFastlogExitPrintStats;
tmm_modules[TMM_ALERTFASTLOG].ThreadDeinit = AlertFastlogThreadDeinit;
tmm_modules[TMM_ALERTFASTLOG].RegisterTests = NULL;
tmm_modules[TMM_ALERTFASTLOG].RegisterTests = AlertFastLogRegisterTests;
}
void TmModuleAlertFastlogIPv4Register (void) {
@ -131,8 +138,8 @@ 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: fixme] [Priority: %" PRIu32 "] {%" PRIu32 "} %s:%" PRIu32 " -> %s:%" PRIu32 "\n",
timebuf, pa->gid, pa->sid, pa->rev, pa->msg, pa->prio, IPV6_GET_L4PROTO(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 "\n",
timebuf, pa->gid, pa->sid, pa->rev, pa->msg, pa->class_msg, pa->prio, IPV6_GET_L4PROTO(p), srcip, p->sp, dstip, p->dp);
fflush(aft->file_ctx->fp);
}
@ -256,3 +263,133 @@ int AlertFastlogOpenFileCtx(LogFileCtx *file_ctx, char *config_file)
}
/*------------------------------Unittests-------------------------------------*/
#ifdef UNITTESTS
int AlertFastLogTest01()
{
int result = 0;
uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n"
"Host: one.example.org\r\n";
uint16_t buflen = strlen((char *)buf);
Packet p;
ThreadVars th_v;
DetectEngineThreadCtx *det_ctx;
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) {
return result;
}
de_ctx->flags |= DE_QUIET;
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Fastlog test\"; content:GET; "
"Classtype:unknown; sid:1;)");
result = (de_ctx->sig_list != NULL);
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 (p.alerts.cnt == 1)
result = (strcmp(p.alerts.alerts[0].class_msg, "Unknown Traffic") == 0);
else
result = 0;
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
//PatternMatchDestroy(mpm_ctx);
DetectEngineCtxFree(de_ctx);
return result;
}
int AlertFastLogTest02()
{
int result = 0;
uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n"
"Host: one.example.org\r\n";
uint16_t buflen = strlen((char *)buf);
Packet p;
ThreadVars th_v;
DetectEngineThreadCtx *det_ctx;
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) {
return result;
}
de_ctx->flags |= DE_QUIET;
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Fastlog test\"; content:GET; "
"Classtype:attempted-admin; sid:1;)");
result = (de_ctx->sig_list != NULL);
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 (p.alerts.cnt == 1) {
result = (strcmp(p.alerts.alerts[0].class_msg, "Unknown Traffic") != 0);
result = (strcmp(p.alerts.alerts[0].class_msg,
"Attempted Administrator Privilege Gain") == 0);
} else {
result = 0;
}
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
//PatternMatchDestroy(mpm_ctx);
DetectEngineCtxFree(de_ctx);
return result;
}
#endif /* UNITTESTS */
/**
* \brief This function registers unit tests for AlertFastLog API.
*/
void AlertFastLogRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("AlertFastLogTest01", AlertFastLogTest01, 1);
UtRegisterTest("AlertFastLogTest02", AlertFastLogTest02, 1);
#endif /* UNITTESTS */
}

@ -147,7 +147,8 @@ typedef struct PacketAlert_ {
uint8_t rev;
uint8_t class;
uint8_t prio;
char *msg;
char *msg;
char *class_msg;
} PacketAlert;
#define PACKET_ALERT_MAX 256
@ -277,7 +278,7 @@ typedef struct Packet_
uint16_t payload_len;
/* decoder events: review how many events we have */
uint8_t events[65535/8];
uint8_t events[65535 / 8];
HttpUri http_uri;

@ -1,35 +1,354 @@
/* CLASSTYPE part of the detection engine. */
/** Copyright (c) 2009 Open Information Security Foundation.
* \author Anoop Saldanha <poonaatsoc@gmail.com>
*/
#include "suricata-common.h"
#include "decode.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-mpm.h"
#include "detect-classtype.h"
#include "flow-var.h"
#include "util-classification-config.h"
#include "util-error.h"
#include "util-debug.h"
#include "util-unittest.h"
#define DETECT_CLASSTYPE_REGEX "^\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s*$"
static pcre *regex = NULL;
static pcre_extra *regex_study = NULL;
int DetectClasstypeSetup(DetectEngineCtx *, Signature *, SigMatch *, char *);
void DetectClasstypeRegisterTests(void);
/**
* \brief Registers the handler functions for the "Classtype" keyword.
*/
void DetectClasstypeRegister(void)
{
const char *eb = NULL;
int eo;
int opts = 0;
int DetectClasstypeSetup (DetectEngineCtx *, Signature *s, SigMatch *m, char *str);
SCLogDebug("Registering the Classtype keyword handler");
void DetectClasstypeRegister (void) {
sigmatch_table[DETECT_CLASSTYPE].name = "classtype";
sigmatch_table[DETECT_CLASSTYPE].Match = NULL;
sigmatch_table[DETECT_CLASSTYPE].Setup = DetectClasstypeSetup;
sigmatch_table[DETECT_CLASSTYPE].Free = NULL;
sigmatch_table[DETECT_CLASSTYPE].RegisterTests = NULL;
sigmatch_table[DETECT_CLASSTYPE].RegisterTests = DetectClasstypeRegisterTests;
regex = pcre_compile(DETECT_CLASSTYPE_REGEX, opts, &eb, &eo, NULL);
if (regex == NULL) {
SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s",
DETECT_CLASSTYPE_REGEX, eo, eb);
goto end;
}
regex_study = pcre_study(regex, 0, &eb);
if (eb != NULL) {
SCLogDebug("pcre study failed: %s", eb);
goto end;
}
end:
return;
}
/**
* \brief Parses the raw string supplied with the "Classtype" keyword.
*
* \param Pointer to the string to be parsed.
*
* \retval ct_name Pointer to the parsed string on Success; NULL on failure.
*/
static inline const char *DetectClasstypeParseRawString(char *rawstr)
{
const char *ct_name = NULL;
#define MAX_SUBSTRINGS 30
int ret = 0;
int ov[MAX_SUBSTRINGS];
/* get rid of the double quotes if present */
if (rawstr[0] == '\"' && rawstr[strlen(rawstr) - 1] == '\"') {
if ( (rawstr = strdup(rawstr + 1)) == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
exit(EXIT_FAILURE);
}
rawstr[strlen(rawstr) - 1] = '\0';
}
ret = pcre_exec(regex, regex_study, rawstr, strlen(rawstr), 0, 0, ov, 30);
if (ret < 0) {
SCLogWarning(SC_ERR_INVALID_SIGNATURE, "Invalid Classtype in Signature");
goto end;
}
ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &ct_name);
if (ret < 0) {
SCLogInfo("pcre_get_substring() failed");
goto end;
}
end:
return ct_name;
}
/**
* \brief Gets the classtype from the corresponding hash table stored
* in the Detection Engine Context, given the classtype name.
*
* \param ct_name Pointer to the classtype name that has to be looked up.
* \param de_ctx Pointer to the Detection Engine Context.
*
* \retval lookup_ct_info Pointer to the SCClassConfClasstype instance from
* the hash table on success; NULL on failure.
*/
static inline SCClassConfClasstype *DetectClasstypeGetClasstypeInfo(const char *ct_name,
DetectEngineCtx *de_ctx)
{
SCClassConfClasstype *ct_info = SCClassConfAllocClasstype(ct_name, NULL,
0);
SCClassConfClasstype *lookup_ct_info = HashTableLookup(de_ctx->class_conf_ht,
ct_info, 0);
SCClassConfDeAllocClasstype(ct_info);
return lookup_ct_info;
}
int DetectClasstypeSetup (DetectEngineCtx *de_ctx, Signature *s, SigMatch *m, char *rawstr)
/**
* \brief The setup function that would be called when the Signature parsing
* module encounters the "Classtype" keyword.
*
* \param de_ctx Pointer to the Detection Engine Context.
* \param s Pointer the current Signature instance that is being parsed.
* \param m Pointer to the previous SigMatch.
* \param rawstr Pointer to the argument supplied to the classtype keyword.
*
* \retval 0 On success
* \retval -1 On failure
*/
int DetectClasstypeSetup(DetectEngineCtx *de_ctx, Signature *s, SigMatch *m,
char *rawstr)
{
char *str = rawstr;
char dubbed = 0;
const char *parsed_ct_name = NULL;
SCClassConfClasstype *ct = NULL;
if ( (parsed_ct_name = DetectClasstypeParseRawString(rawstr)) == NULL) {
SCLogDebug("Error parsing classtype argument supplied with the "
"classtype keyword");
goto error;
}
/* strip "'s */
if (rawstr[0] == '\"' && rawstr[strlen(rawstr)-1] == '\"') {
str = strdup(rawstr+1);
str[strlen(rawstr)-2] = '\0';
dubbed = 1;
ct = DetectClasstypeGetClasstypeInfo(parsed_ct_name, de_ctx);
if (ct == NULL) {
SCLogDebug("Unknown Classtype: \"%s\". Invalidating the Signature",
parsed_ct_name);
goto error;
}
/* XXX */
/* if we have retrieved the classtype, assign the message to be displayed
* for this Signature by fast.log, if a Packet matches this Signature */
s->class_msg = ct->classtype_desc;
/* if a priority keyword has appeared before the classtype, s->prio would
* hold a value which is != -1, in which case we don't overwrite the value.
* Otherwise, overwrite the value */
if (s->prio == -1)
s->prio = ct->priority;
if (dubbed) free(str);
return 0;
error:
return -1;
}
/*------------------------------Unittests-------------------------------------*/
#ifdef UNITTESTS
/**
* \test Check that supplying an invalid classtype in the rule, results in the
* rule being invalidated.
*/
int DetectClasstypeTest01()
{
int result = 0;
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Classtype test\"; "
"Classtype:not_available; sid:1;)");
if (de_ctx->sig_list == NULL)
result = 1;
DetectEngineCtxFree(de_ctx);
end:
return result;
}
/**
* \test Check that both valid and invalid classtypes in a rule are handled
* properly, with rules containing invalid classtypes being rejected
* and the ones containing valid classtypes parsed and returned.
*/
int DetectClasstypeTest02()
{
int result = 0;
Signature *last = NULL;
Signature *sig = NULL;
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Classtype test\"; Classtype:unknown; sid:1;)");
de_ctx->sig_list = last = sig;
result = (sig != NULL);
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Classtype test\"; Classtype:not-there; sid:1;)");
last->next = sig;
result &= (sig == NULL);
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Classtype test\"; Classtype:atteMPted-dos; sid:1;)");
last->next = sig;
last = sig;
result &= (sig != NULL);
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Classtype test\"; Classtype:attempted-dos; sid:1;)");
last->next = sig;
last = sig;
result &= (sig != NULL);
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Classtype test\"; Classtype:attempted_dos; sid:1;)");
last->next = sig;
result &= (sig == NULL);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
end:
return result;
}
/**
* \test Check that the signatures are assigned priority based on classtype they
* are given.
*/
int DetectClasstypeTest03()
{
int result = 0;
Signature *last = NULL;
Signature *sig = NULL;
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Classtype test\"; Classtype:bad-unknown; priority:1; sid:1;)");
de_ctx->sig_list = last = sig;
result = (sig != NULL);
result &= (sig->prio == 1);
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Classtype test\"; Classtype:atteMPted-dos; "
"priority:3; sid:1;)");
last->next = sig;
last = sig;
result &= (sig != NULL);
result &= (sig->prio == 3);
sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Classtype test\"; "
"Classtype:attempted-dos; priority:1; sid:1;)");
last->next = sig;
last = sig;
result &= (sig != NULL);
result &= (sig->prio == 1);
sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Classtype test\"; "
"priority:1; Classtype:unknown; sid:1;)");
last->next = sig;
last = sig;
result &= (sig != NULL);
result &= (sig->prio == 1);
sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Classtype test\"; "
"priority:2; Classtype:unknown; sid:1;)");
last->next = sig;
last = sig;
result &= (sig != NULL);
result &= (sig->prio == 2);
sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Classtype test\"; "
"sid:1;)");
last->next = sig;
last = sig;
result &= (sig != NULL);
result &= (sig->prio == 3);
sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Classtype test\"; "
"Classtype:unknown; sid:1;)");
last->next = sig;
last = sig;
result &= (sig != NULL);
result &= (sig->prio == 3);
sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"Classtype test\"; "
"Classtype:bad-unknown; sid:1;)");
last->next = sig;
last = sig;
result &= (sig != NULL);
result &= (sig->prio == 2);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
end:
return result;
}
#endif /* UNITTESTS */
/**
* \brief This function registers unit tests for Classification Config API.
*/
void DetectClasstypeRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("DetectClasstypeTest01", DetectClasstypeTest01, 1);
UtRegisterTest("DetectClasstypeTest02", DetectClasstypeTest02, 1);
UtRegisterTest("DetectClasstypeTest03", DetectClasstypeTest03, 1);
#endif /* UNITTESTS */
}

@ -1,8 +1,12 @@
/** Copyright (c) 2009 Open Information Security Foundation.
* \author Anoop Saldanha <poonaatsoc@gmail.com>
*/
#ifndef __DETECT_CLASSTYPE_H__
#define __DETECT_CLASSTYPE_H__
/* prototypes */
void DetectClasstypeRegister (void);
void DetectClasstypeRegister(void);
#endif /* __DETECT_CLASSTYPE_H__ */

@ -24,8 +24,8 @@
#include "detect-engine-mpm.h"
#include "detect-engine-threshold.h"
#include "detect-threshold.h"
#include "util-classification-config.h"
#include "util-debug.h"
#include "util-unittest.h"
@ -377,9 +377,7 @@ void IPOnlyMatchPacket(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx,
continue;
}
if (!(s->flags & SIG_FLAG_NOALERT)) {
PacketAlertHandle(de_ctx,s,p);
/* set verdict on packet */
p->action = s->action;
@ -499,7 +497,13 @@ void IPOnlyAddSignature(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx,
static int IPOnlyTestSig01(void) {
int result = 0;
DetectEngineCtx de_ctx;
memset (&de_ctx, 0, sizeof(DetectEngineCtx));
memset(&de_ctx, 0, sizeof(DetectEngineCtx));
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(&de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
de_ctx.flags |= DE_QUIET;
Signature *s = SigInit(&de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-01 sig is IPOnly \"; classtype:misc-activity; sid:400001; rev:1;)");
@ -526,6 +530,12 @@ static int IPOnlyTestSig02 (void) {
DetectEngineCtx de_ctx;
memset (&de_ctx, 0, sizeof(DetectEngineCtx));
memset(&de_ctx, 0, sizeof(DetectEngineCtx));
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(&de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
de_ctx.flags |= DE_QUIET;
Signature *s = SigInit(&de_ctx,"alert tcp any any -> any 80 (msg:\"SigTest40-02 sig is not IPOnly \"; classtype:misc-activity; sid:400001; rev:1;)");

@ -53,7 +53,7 @@ void PacketAlertHandle(DetectEngineCtx *de_ctx, Signature *sig, Packet *p)
/* if have none just alert, otherwise handle thresholding */
if (td == NULL) {
PacketAlertAppend(p, sig->gid, sig->id, sig->rev, sig->prio, sig->msg);
PacketAlertAppend(p, sig->gid, sig->id, sig->rev, sig->prio, sig->msg, sig->class_msg);
} else {
PacketAlertThreshold(de_ctx, td, p, sig);
}
@ -277,20 +277,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);
PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg);
}
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);
PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg);
}
} else {
ste->tv_sec1 = ts.tv_sec;
ste->current_count = 1;
PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg);
PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg);
ThresholdHashAdd(de_ctx, ste, p);
ste = NULL;
@ -307,7 +307,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);
PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg);
lookup_tsh->current_count = 0;
}
} else {
@ -319,7 +319,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);
PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg);
ste->current_count = 0;
} else {
ThresholdHashAdd(de_ctx,ste,p);
@ -337,7 +337,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);
PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg);
}
} else {
lookup_tsh->tv_sec1 = ts.tv_sec;
@ -348,7 +348,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);
PacketAlertAppend(p, s->gid, s->id, s->rev, s->prio, s->msg, s->class_msg);
ste->current_count = 0;
} else {
ThresholdHashAdd(de_ctx,ste,p);

@ -2,6 +2,7 @@
#include "suricata-common.h"
#include "detect.h"
#include "util-classification-config.h"
#include "util-debug.h"
#include "util-unittest.h"
@ -118,6 +119,10 @@ static int DetectMsgParseTest01(void)
if (de_ctx == NULL)
goto end;
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"flow stateless to_server\"; flow:stateless,to_server; content:\"flowstatelesscheck\"; classtype:bad-unknown; sid: 40000002; rev: 1;)");
if(sig == NULL)
goto end;

@ -21,6 +21,7 @@
#include "app-layer-protos.h"
#include "app-layer-parser.h"
#include "util-classification-config.h"
#include "util-unittest.h"
#include "util-debug.h"
#include "string.h"
@ -558,6 +559,11 @@ Signature *SigAlloc (void) {
return NULL;
memset(sig, 0, sizeof(Signature));
/* assign it to -1, so that we can later check if the value has been
* overwritten after the Signature has been parsed, and if it hasn't been
* overwritten, we can then assign the default value of 3 */
sig->prio = -1;
return sig;
}
@ -603,13 +609,13 @@ Signature *SigInit(DetectEngineCtx *de_ctx, char *sigstr) {
if (sig == NULL)
goto error;
/* XXX one day we will support this the way Snort does,
* through classifications.config */
sig->prio = 3;
if (SigParse(de_ctx, sig, sigstr, SIG_DIREC_NORMAL) < 0)
goto error;
/* signature priority hasn't been overwritten. Using default priority */
if (sig->prio == -1)
sig->prio = 3;
sig->num = de_ctx->signum;
de_ctx->signum++;
@ -883,10 +889,16 @@ int SigParseTest02 (void) {
int result = 0;
Signature *sig = NULL;
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL)
goto end;
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; classtype:non-standard-protocol; sid:2003055; rev:4;)");
if (sig == NULL) {
goto end;
@ -1755,7 +1767,7 @@ static int SigParseTestAppLayerTLS01(void) {
goto end;
de_ctx->flags |= DE_QUIET;
s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; classtype:misc-activity; sid:410006; rev:1;)");
s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
if (s == NULL) {
printf("parsing sig failed: ");
goto end;
@ -1789,7 +1801,7 @@ static int SigParseTestAppLayerTLS02(void) {
goto end;
de_ctx->flags |= DE_QUIET;
s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; classtype:misc-activity; sid:410006; rev:1;)");
s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
if (s == NULL) {
printf("parsing sig failed: ");
goto end;

@ -1,33 +1,178 @@
/* PRIORITY part of the detection engine. */
/** Copyright (c) 2009 Open Information Security Foundation.
* \author Victor Julien <victor@inliniac.net>
* \author Anoop Saldanha <poonaatsoc@gmail.com>
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-mpm.h"
#include "util-error.h"
#include "util-debug.h"
#include "util-unittest.h"
#define DETECT_PRIORITY_REGEX "^\\s*(\\d+|\"\\d+\")\\s*$"
static pcre *regex = NULL;
static pcre_extra *regex_study = NULL;
int DetectPrioritySetup (DetectEngineCtx *, Signature *s, SigMatch *m, char *sidstr);
void SCPriorityRegisterTests(void);
/**
* \brief Registers the handler functions for the "priority" keyword
*/
void DetectPriorityRegister (void)
{
const char *eb = NULL;
int eo;
int opts = 0;
void DetectPriorityRegister (void) {
sigmatch_table[DETECT_PRIORITY].name = "priority";
sigmatch_table[DETECT_PRIORITY].Match = NULL;
sigmatch_table[DETECT_PRIORITY].Setup = DetectPrioritySetup;
sigmatch_table[DETECT_PRIORITY].Free = NULL;
sigmatch_table[DETECT_PRIORITY].RegisterTests = NULL;
sigmatch_table[DETECT_PRIORITY].RegisterTests = SCPriorityRegisterTests;
regex = pcre_compile(DETECT_PRIORITY_REGEX, opts, &eb, &eo, NULL);
if (regex == NULL) {
SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s",
DETECT_PRIORITY_REGEX, eo, eb);
goto end;
}
regex_study = pcre_study(regex, 0, &eb);
if (eb != NULL) {
SCLogDebug("pcre study failed: %s", eb);
goto end;
}
end:
return;
}
int DetectPrioritySetup (DetectEngineCtx *de_ctx, Signature *s, SigMatch *m, char *rawstr)
{
char *str = rawstr;
char dubbed = 0;
/* strip "'s */
if (rawstr[0] == '\"' && rawstr[strlen(rawstr)-1] == '\"') {
str = strdup(rawstr+1);
str[strlen(rawstr)-2] = '\0';
dubbed = 1;
const char *prio_str = 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_INVALID_SIGNATURE, "Invalid Priority in Signature "
"- %s", rawstr);
return -1;
}
s->prio = (uint32_t)atoi(str);
ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &prio_str);
if (ret < 0) {
SCLogInfo("pcre_get_substring() failed");
return -1;
}
/* if we have reached here, we have had a valid priority. Assign it */
s->prio = atoi(prio_str);
if (dubbed) free(str);
return 0;
}
/*------------------------------Unittests-------------------------------------*/
#ifdef UNITTESTS
int DetectPriorityTest01()
{
int result = 0;
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Priority test\"; priority:2; sid:1;)");
if (de_ctx->sig_list != NULL)
result = 1;
DetectEngineCtxFree(de_ctx);
end:
return result;
}
int DetectPriorityTest02()
{
int result = 0;
Signature *last = NULL;
Signature *sig = NULL;
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Priority test\"; priority:1; sid:1;)");
de_ctx->sig_list = last = sig;
result = (sig != NULL);
result &= (sig->prio == 1);
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Priority test\"; priority:boo; sid:1;)");
last->next = sig;
result &= (sig == NULL);
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Priority test\"; priority:10boo; sid:1;)");
last->next = sig;
result &= (sig == NULL);
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Priority test\"; priority:b10oo; sid:1;)");
last->next = sig;
result &= (sig == NULL);
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Priority test\"; priority:boo10; sid:1;)");
last->next = sig;
result &= (sig == NULL);
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Priority test\"; priority:-1; sid:1;)");
last->next = sig;
result &= (sig == NULL);
sig = SigInit(de_ctx, "alert tcp any any -> any any "
"(msg:\"Priority test\"; sid:1;)");
last->next = sig;
last = sig;
result &= (sig != NULL);
result &= (sig->prio == 3);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
end:
return result;
}
#endif /* UNITTESTS */
/**
* \brief This function registers unit tests for Classification Config API.
*/
void SCPriorityRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("DetectPriorityTest01", DetectPriorityTest01, 1);
UtRegisterTest("DetectPriorityTest02", DetectPriorityTest02, 1);
#endif /* UNITTESTS */
}

@ -1,3 +1,8 @@
/** Copyright (c) 2009 Open Information Security Foundation.
* \author Victor Julien <victor@inliniac.net>
* \author Anoop Saldanha <poonaatsoc@gmail.com>
*/
#ifndef __DETECT_PRIORITY_H__
#define __DETECT_PRIORITY_H__

@ -84,7 +84,8 @@
#include "conf.h"
#include "conf-yaml-loader.h"
#include <yaml.h>
#include "util-classification-config.h"
#include "util-print.h"
#include "util-unittest.h"
#include "util-debug.h"
@ -404,7 +405,8 @@ 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)
int PacketAlertAppend(Packet *p, uint32_t gid, uint32_t sid, uint8_t rev,
uint8_t prio, char *msg, char *class_msg)
{
/* XXX overflow check? */
@ -419,6 +421,7 @@ int PacketAlertAppend(Packet *p, uint32_t gid, uint32_t sid, uint8_t rev, uint8_
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.cnt++;
return 0;
@ -579,7 +582,6 @@ static int SigMatchSignaturesAppLayer(ThreadVars *th_v, DetectEngineCtx *de_ctx,
if (s->match == NULL) {
fmatch = 1;
if (!(s->flags & SIG_FLAG_NOALERT)) {
PacketAlertHandle(de_ctx,s,p);
/* set verdict on packet */
@ -797,7 +799,6 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
fmatch = 1;
if (!(s->flags & SIG_FLAG_NOALERT)) {
PacketAlertHandle(de_ctx,s,p);
/* set verdict on packet */
p->action = s->action;
@ -832,7 +833,6 @@ 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);
/* set verdict on packet */
p->action = s->action;
@ -4040,6 +4040,11 @@ static int SigTest15Real (int mpm_type) {
}
de_ctx->mpm_matcher = mpm_type;
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; content:\" HTTP/1.\"; nocase; within:1000; classtype:misc-activity; sid:2008284; rev:2;)");
@ -4105,6 +4110,11 @@ static int SigTest16Real (int mpm_type) {
}
de_ctx->mpm_matcher = mpm_type;
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any !$HTTP_PORTS (msg:\"ET POLICY Inbound HTTP CONNECT Attempt on Off-Port\"; content:\"CONNECT \"; nocase; depth:8; content:\" HTTP/1.\"; nocase; within:1000; classtype:misc-activity; sid:2008284; rev:2;)");
@ -4244,6 +4254,11 @@ static int SigTest18Real (int mpm_type) {
}
de_ctx->mpm_matcher = mpm_type;
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx,"alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; classtype:non-standard-protocol; sid:2003055; rev:4;)");

@ -150,7 +150,7 @@ typedef struct Signature_ {
uint16_t flags;
uint8_t rev;
uint8_t prio;
int prio;
uint32_t gid; /**< generator id */
SigIntId num; /**< signature number, internal id */
@ -158,6 +158,9 @@ typedef struct Signature_ {
uint8_t nchunk_groups; /**< Internal chunk grp id (for splitted patterns) */
char *msg;
/* classification message */
char *class_msg;
/** addresses, ports and proto this sig matches on */
DetectAddressHead src, dst;
DetectProto proto;
@ -250,15 +253,18 @@ typedef struct DetectEngineCtx_ {
struct SCSigOrderFunc_ *sc_sig_order_funcs;
struct SCSigSignatureWrapper_ *sc_sig_sig_wrapper;
/* hash table used for holding the classification config info */
HashTable *class_conf_ht;
/* main sigs */
DetectEngineLookupDsize dsize_gh[DSIZE_STATES];
uint32_t mpm_unique, mpm_reuse, mpm_none,
mpm_uri_unique, mpm_uri_reuse, mpm_uri_none;
mpm_uri_unique, mpm_uri_reuse, mpm_uri_none;
uint32_t gh_unique, gh_reuse;
uint32_t mpm_max_patcnt, mpm_min_patcnt, mpm_tot_patcnt,
mpm_uri_max_patcnt, mpm_uri_min_patcnt, mpm_uri_tot_patcnt;
mpm_uri_max_patcnt, mpm_uri_min_patcnt, mpm_uri_tot_patcnt;
/* content and uricontent vars */
uint32_t content_max_id;
@ -512,15 +518,18 @@ int SigGroupBuild(DetectEngineCtx *);
int SigGroupCleanup();
void SigAddressPrepareBidirectionals (DetectEngineCtx *);
int PacketAlertAppend(Packet *, uint32_t, uint32_t, uint8_t, uint8_t, char *);
int PacketAlertAppend(Packet *, uint32_t, uint32_t, uint8_t, uint8_t, char *,
char *);
int SigLoadSignatures (DetectEngineCtx *, char *);
void SigTableSetup(void);
int PacketAlertCheck(Packet *p, uint32_t sid);
int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p);
int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx,
DetectEngineThreadCtx *det_ctx, Packet *p);
int PacketAlertCheck(Packet *p, uint32_t sid);
int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p);
int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx,
DetectEngineThreadCtx *det_ctx, Packet *p);
int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s);
#endif /* __DETECT_H__ */

@ -74,6 +74,7 @@
#include "util-unittest.h"
#include "util-time.h"
#include "util-rule-vars.h"
#include "util-classification-config.h"
#include "conf.h"
#include "conf-yaml-loader.h"
@ -555,7 +556,7 @@ int main(int argc, char **argv)
SCRuleVarsRegisterTests();
AppLayerParserRegisterTests();
ThreadMacrosRegisterTests();
SCClassConfRegisterTests();
if (list_unittests) {
UtListTests(regex_arg);
}
@ -599,6 +600,8 @@ int main(int argc, char **argv)
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
SCClassConfLoadClassficationConfigFile(de_ctx);
/** Create file contexts for output modules */
/* ascii */
LogFileCtx *af_logfile_ctx = AlertFastlogInitCtx(NULL);

@ -0,0 +1,853 @@
/** Copyright (c) 2009 Open Information Security Foundation.
* \author Anoop Saldanha <poonaatsoc@gmail.com>
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-engine.h"
#include "util-hash.h"
#include "conf.h"
#include "util-classification-config.h"
#include "util-unittest.h"
#include "util-error.h"
#include "util-debug.h"
/* Regex to parse the classtype argument from a Signature. The first substring
* holds the classtype name, the second substring holds the classtype the
* classtype description, and the third argument holds the priority */
#define DETECT_CLASSCONFIG_REGEX "^\\s*config\\s*classification\\s*:\\s*([a-zA-Z][a-zA-Z0-9-_]*)\\s*,\\s*(.+)\\s*,\\s*(\\d+)\\s*$"
/* Default path for the classification.config file */
#define SC_CLASS_CONF_DEF_CONF_FILEPATH "/root/classification.config1"
/* Holds a pointer to the default path for the classification.config file */
static const char *default_file_path = SC_CLASS_CONF_DEF_CONF_FILEPATH;
static FILE *fd = NULL;
static pcre *regex = NULL;
static pcre_extra *regex_study = NULL;
uint32_t SCClassConfClasstypeHashFunc(HashTable *ht, void *data, uint16_t datalen);
char SCClassConfClasstypeHashCompareFunc(void *data1, uint16_t datalen1,
void *data2, uint16_t datalen2);
void SCClassConfClasstypeHashFree(void *ch);
/**
* \brief Returns the path for the Classification 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 classification file which is
* "./classification.config".
*
* \retval log_filename Pointer to a string containing the path for the
* Classification Config file.
*/
static char *SCClassConfGetConfFilename(void)
{
char *log_filename = (char *)default_file_path;
ConfGet("classification-file", &log_filename);
return log_filename;
}
/**
* \brief Inits the context to be used by the Classification Config parsing API.
*
* This function initializes the hash table to be used by the Detection
* Engine Context to hold the data from the classification.config file,
* obtains the file desc to parse the classification.config file, and
* inits the regex used to parse the lines from classification.config
* file.
*
* \param de_ctx Pointer to the Detection Engine Context.
*
* \retval 0 On success.
* \retval -1 On failure.
*/
static inline int SCClassConfInitContext(DetectEngineCtx *de_ctx)
{
char *filename = NULL;
const char *eb = NULL;
int eo;
int opts = 0;
/* init the hash table to be used by the classification config Classtypes */
de_ctx->class_conf_ht = HashTableInit(4096, SCClassConfClasstypeHashFunc,
SCClassConfClasstypeHashCompareFunc,
SCClassConfClasstypeHashFree);
if (de_ctx->class_conf_ht == NULL) {
SCLogError(SC_ERR_HASH_TABLE_INIT_FAILED, "Error initializing the hash "
"table");
return -1;
}
filename = SCClassConfGetConfFilename();
if ( (fd = fopen(filename, "r")) == NULL) {
SCLogError(SC_ERR_FOPEN_ERROR, "Error opening file: \"%s\"", filename);
goto error;
}
regex = pcre_compile(DETECT_CLASSCONFIG_REGEX, opts, &eb, &eo, NULL);
if (regex == NULL) {
SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s",
DETECT_CLASSCONFIG_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->class_conf_ht != NULL) {
HashTableFree(de_ctx->class_conf_ht);
de_ctx->class_conf_ht = NULL;
}
if (fd != NULL)
fclose(fd);
return -1;
}
/**
* \brief Releases resources used by the Classification Config API.
*/
static void SCClassConfDeInitContext(void)
{
fclose(fd);
default_file_path = SC_CLASS_CONF_DEF_CONF_FILEPATH;
return;
}
/**
* \brief Converts a string to lowercase.
*
* \param str Pointer to the string to be converted.
*/
static char *SCClassConfStringToLowercase(const char *str)
{
char *new_str = NULL;
char *temp_str = NULL;
if ( (new_str = strdup(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 classification file and adds it to Classtype
* hash table in DetectEngineCtx, i.e. DetectEngineCtx->class_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 inline int SCClassConfAddClasstype(char *rawstr, DetectEngineCtx *de_ctx)
{
const char *ct_name = NULL;
const char *ct_desc = NULL;
const char *ct_priority_str = NULL;
int ct_priority = 0;
SCClassConfClasstype *ct_new = NULL;
SCClassConfClasstype *ct_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_INVALID_SIGNATURE, "Invalid Classtype in "
"classification.config file");
goto error;
}
/* retrieve the classtype name */
ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &ct_name);
if (ret < 0) {
SCLogInfo("pcre_get_substring() failed");
goto error;
}
/* retrieve the classtype description */
ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &ct_desc);
if (ret < 0) {
SCLogInfo("pcre_get_substring() failed");
goto error;
}
/* retrieve the classtype priority */
ret = pcre_get_substring((char *)rawstr, ov, 30, 3, &ct_priority_str);
if (ret < 0) {
SCLogInfo("pcre_get_substring() failed");
goto error;
}
ct_priority = atoi(ct_priority_str);
/* Create a new instance of the parsed Classtype string */
ct_new = SCClassConfAllocClasstype(ct_name, ct_desc, ct_priority);
if (ct_new == NULL)
goto error;
/* Check if the Classtype is present in the HashTable. In case it's present
* ignore it, as it is a duplicate. If not present, add it to the table */
ct_lookup = HashTableLookup(de_ctx->class_conf_ht, ct_new, 0);
if (ct_lookup == NULL) {
if (HashTableAdd(de_ctx->class_conf_ht, ct_new, 0) < 0)
SCLogDebug("HashTable Add failed");
} else {
SCLogDebug("Duplicate classtype found inside classification.config");
}
return 0;
error:
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 SCClassConfIsLineBlankOrComment(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 Classification Config file and updates the
* DetectionEngineCtx->class_conf_ht with the Classtype information.
*
* \param de_ctx Pointer to the Detection Engine Context.
*/
static inline void SCClassConfParseFile(DetectEngineCtx *de_ctx)
{
char line[1024];
while (fgets(line, sizeof(line), fd) != NULL) {
if (SCClassConfIsLineBlankOrComment(line))
continue;
SCClassConfAddClasstype(line, de_ctx);
}
SCLogInfo("Added \"%d\" classification types from the classification file",
de_ctx->class_conf_ht->count);
return;
}
/**
* \brief Returns a new SCClassConfClasstype instance. The classtype string
* is converted into lowercase, before being assigned to the instance.
*
* \param classtype Pointer to the classification type.
* \param classtype_desc Pointer to the classification type description.
* \param priority Holds the priority for the classification type.
*
* \retval ct Pointer to the new instance of SCClassConfClasstype on success;
* NULL on failure.
*/
SCClassConfClasstype *SCClassConfAllocClasstype(const char *classtype,
const char *classtype_desc,
int priority)
{
SCClassConfClasstype *ct = NULL;
if (classtype == NULL)
return NULL;
if ( (ct = malloc(sizeof(SCClassConfClasstype))) == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
exit(EXIT_FAILURE);
}
memset(ct, 0, sizeof(SCClassConfClasstype));
if ( (ct->classtype = SCClassConfStringToLowercase(classtype)) == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
exit(EXIT_FAILURE);
}
if (classtype_desc != NULL &&
(ct->classtype_desc = strdup(classtype_desc)) == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
exit(EXIT_FAILURE);
}
ct->priority = priority;
return ct;
}
/**
* \brief Frees a SCClassConfClasstype instance
*
* \param Pointer to the SCClassConfClasstype instance that has to be freed
*/
void SCClassConfDeAllocClasstype(SCClassConfClasstype *ct)
{
if (ct != NULL) {
if (ct->classtype != NULL)
free(ct->classtype);
if (ct->classtype_desc != NULL)
free(ct->classtype_desc);
free(ct);
}
return;
}
/**
* \brief Hashing function to be used to hash the Classtype name. Would be
* supplied as an argument to the HashTableInit function for
* DetectEngineCtx->class_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 SCClassConfClasstype instance.
* \param datalen Not used by this function.
*/
uint32_t SCClassConfClasstypeHashFunc(HashTable *ht, void *data, uint16_t datalen)
{
SCClassConfClasstype *ct = (SCClassConfClasstype *)data;
uint32_t hash = 0;
int i = 0;
int len = strlen(ct->classtype);
for (i = 0; i < len; i++)
hash += tolower((ct->classtype)[i]);
hash = hash % ht->array_size;
return hash;
}
/**
* \brief Used to compare two Classtypes that have been stored in the HashTable.
* This function is supplied as an argument to the HashTableInit function
* for DetectionEngineCtx->class_conf_ct.
*
* \param data1 Pointer to the first SCClassConfClasstype to be compared.
* \param len1 Not used by this function.
* \param data2 Pointer to the second SCClassConfClasstype 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 SCClassConfClasstypeHashCompareFunc(void *data1, uint16_t datalen1,
void *data2, uint16_t datalen2)
{
SCClassConfClasstype *ct1 = (SCClassConfClasstype *)data1;
SCClassConfClasstype *ct2 = (SCClassConfClasstype *)data2;
int len1 = 0;
int len2 = 0;
if (ct1 == NULL || ct2 == NULL)
return 0;
if (ct1->classtype == NULL || ct2->classtype == NULL)
return 0;
len1 = strlen(ct1->classtype);
len2 = strlen(ct2->classtype);
if (len1 == len2 && memcmp(ct1->classtype, ct2->classtype, len1) == 0) {
SCLogDebug("Match found inside Classification-Config hash function");
return 1;
}
return 0;
}
/**
* \brief Used to free the Classification Config Hash Data that was stored in
* DetectEngineCtx->class_conf_ht Hashtable.
*
* \param ch Pointer to the data that has to be freed.
*/
void SCClassConfClasstypeHashFree(void *ch)
{
SCClassConfDeAllocClasstype(ch);
return;
}
/**
* \brief Loads the Classtype info from the classification.config file.
*
* The classification.config file contains the different classtypes,
* that can be used to label Signatures. Each line of the file should
* have the following format -
* classtype_name, classtype_description, priority
* None of the above parameters should hold a quote inside the file.
*
* \param de_ctx Pointer to the Detection Engine Context that should be updated
* with Classtype information.
*/
void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *de_ctx)
{
if (SCClassConfInitContext(de_ctx) == -1) {
SCLogDebug("Error initializing classification config API");
return;
}
SCClassConfParseFile(de_ctx);
SCClassConfDeInitContext();
return;
}
/*----------------------------------Unittests---------------------------------*/
#ifdef UNITTESTS
/**
* \brief Creates a dummy classification file, with all valid Classtypes, for
* testing purposes.
*
* \file_path Pointer to the file_path for the dummy classification file.
*/
void SCClassConfGenerateValidDummyClassConfigFile01(const char *file_path)
{
FILE *fd = NULL;
default_file_path = file_path;
if ( (fd = fopen(default_file_path, "w+")) == NULL) {
SCLogError(SC_ERR_FOPEN_ERROR, "Error opening file: \"%s\"", file_path);
return;
}
fputs("config classification: not-suspicious,Not Suspicious Traffic,3\n", fd);
fputs("config classification: unknown,Unknown Traffic,3\n", fd);
fputs("config classification: bad-unknown,Potentially Bad Traffic, 2\n", fd);
fputs("config classification: attempted-recon,Attempted Information "
"Leak,2\n", fd);
fputs("config classification: successful-recon-limited,Information "
"Leak,2\n", fd);
fputs("config classification: successful-recon-largescale,Large Scale "
"Information Leak,2\n", fd);
fputs("config classification: attempted-dos,Attempted Denial of "
"Service,2\n", fd);
fputs("config classification: successful-dos,Denial of Service,2\n", fd);
fputs("config classification: attempted-user,Attempted User Privilege "
"Gain,1\n", fd);
fputs("config classification: unsuccessful-user,Unsuccessful User "
"Privilege Gain,1\n", fd);
fputs("config classification: successful-user,Successful User Privilege "
"Gain,1\n", fd);
fputs("config classification: attempted-admin,Attempted Administrator "
"Privilege Gain,1\n", fd);
fputs("config classification: successful-admin,Successful Administrator "
"Privilege Gain,1\n", fd);
fputs("config classification: rpc-portmap-decode,Decode of an RPC "
"Query,2\n", fd);
fputs("config classification: shellcode-detect,Executable code was "
"detected,1\n", fd);
fputs("config classification: string-detect,A suspicious string was "
"detected,3\n", fd);
fputs("config classification: suspicious-filename-detect,A suspicious "
"filename was detected,2\n", fd);
fputs("config classification: suspicious-login,An attempted login using "
"a suspicious username was detected,2\n", fd);
fputs("config classification: system-call-detect,A system call was "
"detected,2\n", fd);
fputs("config classification: tcp-connection,A TCP connection was "
"detected,4\n", fd);
fputs("config classification: trojan-activity,A Network Trojan was "
"detected, 1\n", fd);
fputs("config classification: unusual-client-port-connection,A client "
"was using an unusual port,2\n", fd);
fputs("config classification: network-scan,Detection of a Network "
"Scan,3\n", fd);
fputs("config classification: denial-of-service,Detection of a Denial "
"of Service Attack,2\n", fd);
fputs("config classification: non-standard-protocol,Detection of a "
"non-standard protocol or event,2\n", fd);
fputs("config classification: protocol-command-decode,Generic Protocol "
"Command Decode,3\n", fd);
fputs("config classification: web-application-activity,access to a "
"potentially vulnerable web application,2\n", fd);
fputs("config classification: web-application-attack,Web Application "
"Attack,1\n", fd);
fputs("config classification: misc-activity,Misc activity,3\n", fd);
fputs("config classification: misc-attack,Misc Attack,2\n", fd);
fputs("config classification: icmp-event,Generic ICMP event,3\n", fd);
fputs("config classification: kickass-porn,SCORE! Get the lotion!,1\n", fd);
fputs("config classification: policy-violation,Potential Corporate "
"Privacy Violation,1\n", fd);
fputs("config classification: default-login-attempt,Attempt to login by "
"a default username and password,2\n", fd);
fclose(fd);
}
/**
* \brief Creates a dummy classification file, with some valid Classtypes and a
* couple of invalid Classtypes, for testing purposes.
*
* \file_path Pointer to the file_path for the dummy classification file.
*/
void SCClassConfGenerateInValidDummyClassConfigFile02(const char *file_path)
{
FILE *fd = NULL;
default_file_path = file_path;
if ( (fd = fopen(default_file_path, "w+")) == NULL) {
SCLogError(SC_ERR_FOPEN_ERROR, "Error opening file: \"%s\"", file_path);
return;
}
fputs("config classification: not-suspicious,Not Suspicious Traffic,3\n", fd);
fputs("onfig classification: unknown,Unknown Traffic,3\n", fd);
fputs("config classification: _badunknown,Potentially Bad Traffic, 2\n", fd);
fputs("config classification: bamboola1,Unknown Traffic,3\n", fd);
fputs("config classification: misc-activity,Misc activity,-1\n", fd);
fputs("config classification: policy-violation,Potential Corporate ", fd);
fputs("config classification: bamboola,Unknown Traffic,3\n", fd);
fclose(fd);
}
/**
* \brief Creates a dummy classification file, with all invalid Classtypes, for
* testing purposes.
*
* \file_path Pointer to the file_path for the dummy classification file.
*/
void SCClassConfGenerateInValidDummyClassConfigFile03(const char *file_path)
{
FILE *fd = NULL;
default_file_path = file_path;
if ( (fd = fopen(default_file_path, "w+")) == NULL) {
SCLogError(SC_ERR_FOPEN_ERROR, "Error opening file: \"%s\"", file_path);
return;
}
fputs("conig classification: not-suspicious,Not Suspicious Traffic,3\n", fd);
fputs("onfig classification: unknown,Unknown Traffic,3\n", fd);
fputs("config classification: _badunknown,Potentially Bad Traffic, 2\n", fd);
fputs("config classification: misc-activity,Misc activity,-1\n", fd);
fclose(fd);
}
/**
* \brief Deletes a file, whose path is specified as the argument.
*
* \file_path Pointer to the file_path that has to be deleted.
*/
void SCClassConfDeleteDummyClassificationConfigFile(const char *file_path)
{
remove(file_path);
return;
}
/**
* \test Check that the classification file is loaded and the detection engine
* content class_conf_hash_table loaded with the classtype data.
*/
int SCClassConfTest01(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
int result = 0;
if (de_ctx == NULL)
return result;
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
if (de_ctx->class_conf_ht == NULL)
return result;
result = (de_ctx->class_conf_ht->count == 34);
DetectEngineCtxFree(de_ctx);
free(de_ctx->class_conf_ht);
return result;
}
/**
* \test Check that invalid classtypes present in the classification config file
* aren't loaded.
*/
int SCClassConfTest02(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
int result = 0;
if (de_ctx == NULL)
return result;
SCClassConfGenerateInValidDummyClassConfigFile03("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
if (de_ctx->class_conf_ht == NULL)
return result;
result = (de_ctx->class_conf_ht->count == 0);
DetectEngineCtxFree(de_ctx);
free(de_ctx->class_conf_ht);
return result;
}
/**
* \test Check that only valid classtypes are loaded into the hash table from
* the classfication.config file.
*/
int SCClassConfTest03(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
int result = 0;
if (de_ctx == NULL)
return result;
SCClassConfGenerateInValidDummyClassConfigFile02("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
if (de_ctx->class_conf_ht == NULL)
return result;
result = (de_ctx->class_conf_ht->count == 3);
DetectEngineCtxFree(de_ctx);
free(de_ctx->class_conf_ht);
return result;
}
/**
* \test Check if the classtype info from the classification.config file have
* been loaded into the hash table.
*/
int SCClassConfTest04(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
SCClassConfClasstype *ct = NULL;
int result = 1;
if (de_ctx == NULL)
return 0;
SCClassConfGenerateValidDummyClassConfigFile01("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
if (de_ctx->class_conf_ht == NULL)
return 0;
result = (de_ctx->class_conf_ht->count == 34);
ct = SCClassConfAllocClasstype("unknown", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) != NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("unKnoWn", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) != NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("bamboo", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) == NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("bad-unknown", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) != NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("BAD-UNKnOWN", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) != NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("bed-unknown", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) == NULL);
SCClassConfDeAllocClasstype(ct);
DetectEngineCtxFree(de_ctx);
free(de_ctx->class_conf_ht);
return result;
}
/**
* \test Check if the classtype info from the invalid classification.config file
* have not been loaded into the hash table, and cross verify to check
* that the hash table contains no classtype data.
*/
int SCClassConfTest05(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
SCClassConfClasstype *ct = NULL;
int result = 1;
if (de_ctx == NULL)
return 0;
SCClassConfGenerateInValidDummyClassConfigFile03("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
if (de_ctx->class_conf_ht == NULL)
return 0;
result = (de_ctx->class_conf_ht->count == 0);
ct = SCClassConfAllocClasstype("unknown", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) == NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("unKnoWn", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) == NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("bamboo", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) == NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("bad-unknown", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) == NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("BAD-UNKnOWN", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) == NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("bed-unknown", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) == NULL);
SCClassConfDeAllocClasstype(ct);
DetectEngineCtxFree(de_ctx);
free(de_ctx->class_conf_ht);
return result;
}
/**
* \test Check if the classtype info from the classification.config file have
* been loaded into the hash table.
*/
int SCClassConfTest06(void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
SCClassConfClasstype *ct = NULL;
int result = 1;
if (de_ctx == NULL)
return 0;
SCClassConfGenerateInValidDummyClassConfigFile02("/var/log/eidps/classification.config");
SCClassConfLoadClassficationConfigFile(de_ctx);
SCClassConfDeleteDummyClassificationConfigFile("/var/log/eidps/classification.config");
if (de_ctx->class_conf_ht == NULL)
return 0;
result = (de_ctx->class_conf_ht->count == 3);
ct = SCClassConfAllocClasstype("unknown", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) == NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("not-suspicious", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) != NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("bamboola1", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) != NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("bamboola1", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) != NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("BAMBOolA1", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) != NULL);
SCClassConfDeAllocClasstype(ct);
ct = SCClassConfAllocClasstype("unkNOwn", NULL, 0);
result &= (HashTableLookup(de_ctx->class_conf_ht, ct, 0) == NULL);
SCClassConfDeAllocClasstype(ct);
DetectEngineCtxFree(de_ctx);
free(de_ctx->class_conf_ht);
return result;
}
#endif /* UNITTESTS */
/**
* \brief This function registers unit tests for Classification Config API.
*/
void SCClassConfRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("SCClassConfTest01", SCClassConfTest01, 1);
UtRegisterTest("SCClassConfTest02", SCClassConfTest02, 1);
UtRegisterTest("SCClassConfTest03", SCClassConfTest03, 1);
UtRegisterTest("SCClassConfTest04", SCClassConfTest04, 1);
UtRegisterTest("SCClassConfTest05", SCClassConfTest05, 1);
UtRegisterTest("SCClassConfTest06", SCClassConfTest06, 1);
#endif /* UNITTESTS */
}

@ -0,0 +1,34 @@
/** Copyright (c) 2009 Open Information Security Foundation.
* \author Anoop Saldanha <poonaatsoc@gmail.com>
*/
#ifndef __UTIL_CLASSIFICATION_CONFIG_H__
#define __UTIL_CLASSIFICATION_CONFIG_H__
/**
* \brief Container for a Classtype from the Classification.config file.
*/
typedef struct SCClassConfClasstype_ {
/* The classtype name. This is the primary key for a Classification. */
char *classtype;
/* Description for a classification. Would be used while printing out
* the classification info for a Signature, by the fast-log module. */
char *classtype_desc;
/* The priority this classification type carries */
int priority;
} SCClassConfClasstype;
SCClassConfClasstype *SCClassConfAllocClasstype(const char *, const char *,
int);
void SCClassConfDeAllocClasstype(SCClassConfClasstype *);
void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *);
void SCClassConfRegisterTests(void);
void SCClassConfGenerateValidDummyClassConfigFile01(const char *);
void SCClassConfGenerateInValidDummyClassConfigFile02(const char *);
void SCClassConfGenerateInValidDummyClassConfigFile03(const char *);
void SCClassConfDeleteDummyClassificationConfigFile(const char *);
#endif /* __UTIL_CLASSIFICATION_CONFIG_H__ */

@ -82,6 +82,8 @@ typedef enum {
SC_ERR_OFFSET_MISSING_CONTENT,
SC_ERR_DEPTH_MISSING_CONTENT,
SC_ERR_NO_URICONTENT_NEGATION,
SC_ERR_FOPEN_ERROR,
SC_ERR_HASH_TABLE_INIT_FAILED,
} SCError;
const char *SCErrorToString(SCError);

@ -108,6 +108,8 @@ int HashTableAdd(HashTable *ht, void *data, uint16_t datalen) {
ht->array[hash] = hb;
}
ht->count++;
return 0;
error:
@ -155,14 +157,19 @@ int HashTableRemove(HashTable *ht, void *data, uint16_t datalen) {
}
void *HashTableLookup(HashTable *ht, void *data, uint16_t datalen) {
uint32_t hash = ht->Hash(ht, data, datalen);
uint32_t hash = 0;
if (ht == NULL)
return NULL;
hash = ht->Hash(ht, data, datalen);
if (ht->array[hash] == NULL)
return NULL;
HashTableBucket *hashbucket = ht->array[hash];
do {
if (ht->Compare(hashbucket->data,hashbucket->size,data,datalen) == 1)
if (ht->Compare(hashbucket->data, hashbucket->size, data, datalen) == 1)
return hashbucket->data;
hashbucket = hashbucket->next;

@ -14,6 +14,7 @@ typedef struct HashTableBucket_ {
typedef struct HashTable_ {
HashTableBucket **array;
uint32_t array_size;
uint32_t count;
uint32_t (*Hash)(struct HashTable_ *, void *, uint16_t);
char (*Compare)(void *, uint16_t, void *, uint16_t);
void (*Free)(void *);

Loading…
Cancel
Save