From e3b538c7d70ac864ff8038b0e6fc4895069489c0 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 21 Aug 2009 00:15:46 -0700 Subject: [PATCH] Simple configuration API. Allow the log directory to be changed. --- src/Makefile.am | 4 +- src/alert-debuglog.c | 14 +- src/alert-fastlog.c | 14 +- src/alert-unified-alert.c | 9 +- src/alert-unified-log.c | 9 +- src/conf.c | 326 ++++++++++++++++++++++++++++++++++++++ src/conf.h | 33 ++++ src/config.c | 84 ---------- src/counters.c | 34 +++- src/eidps.c | 13 +- src/log-httplog.c | 14 +- 11 files changed, 448 insertions(+), 106 deletions(-) create mode 100644 src/conf.c create mode 100644 src/conf.h delete mode 100644 src/config.c diff --git a/src/Makefile.am b/src/Makefile.am index a0b5f3ab87..359f8f4759 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,5 @@ bin_PROGRAMS = eidps eidps_SOURCES = eidps.c eidps.h \ -config.c config.h \ packet-queue.c packet-queue.h \ threads.c threads.h \ source-nfq.c source-nfq.h \ @@ -98,7 +97,8 @@ counters.c counter.h \ app-layer-detect-proto.c app-layer-detect-proto.h \ app-layer-parser.c app-layer-parser.h \ app-layer-http.c app-layer-http.h \ -app-layer-protos.h +app-layer-protos.h \ +conf.c conf.h # set the include path found by configure INCLUDES= $(all_includes) diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index b25c1c9cf1..439637f399 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ #include "debug.h" #include "detect.h" #include "flow.h" +#include "conf.h" #include "threadvars.h" #include "tm-modules.h" @@ -33,6 +35,8 @@ #include "util-unittest.h" +#define DEFAULT_LOG_FILENAME "alert-debug.log" + int AlertDebuglog (ThreadVars *, Packet *, void *, PacketQueue *); int AlertDebuglogIPv4(ThreadVars *, Packet *, void *, PacketQueue *); int AlertDebuglogIPv6(ThreadVars *, Packet *, void *, PacketQueue *); @@ -204,11 +208,13 @@ int AlertDebuglogThreadInit(ThreadVars *t, void *initdata, void **data) } memset(aft, 0, sizeof(AlertDebuglogThread)); - /* XXX */ - char *path = "/var/log/eidps/alert-debug.log"; - aft->fp = fopen(path, "w"); + char log_path[PATH_MAX], *log_dir; + if (ConfGet("default-log-dir", &log_dir) != 1) + log_dir = DEFAULT_LOG_DIR; + snprintf(log_path, PATH_MAX, "%s/%s", log_dir, DEFAULT_LOG_FILENAME); + aft->fp = fopen(log_path, "w"); if (aft->fp == NULL) { - printf("ERROR: failed to open %s: %s\n", path, strerror(errno)); + printf("ERROR: failed to open %s: %s\n", log_path, strerror(errno)); return -1; } diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index ff2cb22860..5c2225a319 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -27,12 +28,15 @@ #include "debug.h" #include "detect.h" #include "flow.h" +#include "conf.h" #include "threadvars.h" #include "tm-modules.h" #include "util-unittest.h" +#define DEFAULT_LOG_FILENAME "fast.log" + int AlertFastlog (ThreadVars *, Packet *, void *, PacketQueue *); int AlertFastlogIPv4(ThreadVars *, Packet *, void *, PacketQueue *); int AlertFastlogIPv6(ThreadVars *, Packet *, void *, PacketQueue *); @@ -155,11 +159,13 @@ int AlertFastlogThreadInit(ThreadVars *t, void *initdata, void **data) } memset(aft, 0, sizeof(AlertFastlogThread)); - /* XXX */ - char *path = "/var/log/eidps/fast.log"; - aft->fp = fopen(path, "w"); + char log_path[PATH_MAX], *log_dir; + if (ConfGet("default-log-dir", &log_dir) != 1) + log_dir = DEFAULT_LOG_DIR; + snprintf(log_path, PATH_MAX, "%s/%s", log_dir, DEFAULT_LOG_FILENAME); + aft->fp = fopen(log_path, "w"); if (aft->fp == NULL) { - printf("ERROR: failed to open %s: %s\n", path, strerror(errno)); + printf("ERROR: failed to open %s: %s\n", log_path, strerror(errno)); return -1; } diff --git a/src/alert-unified-alert.c b/src/alert-unified-alert.c index 786dafa4bf..4403da8f9a 100644 --- a/src/alert-unified-alert.c +++ b/src/alert-unified-alert.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include "debug.h" #include "detect.h" #include "flow.h" +#include "conf.h" #include "threadvars.h" #include "tm-modules.h" @@ -86,7 +88,7 @@ typedef struct AlertUnifiedAlertPacketHeader_ { } AlertUnifiedAlertPacketHeader; int AlertUnifiedAlertCreateFile(ThreadVars *t, AlertUnifiedAlertThread *aun) { - char filename[2048]; /* XXX some sane default? */ + char filename[PATH_MAX]; int ret; /* get the time so we can have a filename with seconds since epoch @@ -98,7 +100,10 @@ int AlertUnifiedAlertCreateFile(ThreadVars *t, AlertUnifiedAlertThread *aun) { gettimeofday(&ts, NULL); /* create the filename to use */ - snprintf(filename, sizeof(filename), "%s/%s.%" PRIu32, "/var/log/eidps", "unified.alert", (uint32_t)ts.tv_sec); + char *log_dir; + if (ConfGet("default-log-dir", &log_dir) != 1) + log_dir = DEFAULT_LOG_DIR; + snprintf(filename, sizeof(filename), "%s/%s.%" PRIu32, log_dir, "unified.alert", (uint32_t)ts.tv_sec); /* XXX filename & location */ aun->fp = fopen(filename, "wb"); diff --git a/src/alert-unified-log.c b/src/alert-unified-log.c index e5c522014a..940eaa4874 100644 --- a/src/alert-unified-log.c +++ b/src/alert-unified-log.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include "debug.h" #include "detect.h" #include "flow.h" +#include "conf.h" #include "threadvars.h" #include "tm-modules.h" @@ -88,7 +90,7 @@ typedef struct AlertUnifiedLogPacketHeader_ { } AlertUnifiedLogPacketHeader; int AlertUnifiedLogCreateFile(ThreadVars *t, AlertUnifiedLogThread *aun) { - char filename[2048]; /* XXX some sane default? */ + char filename[PATH_MAX]; /* XXX some sane default? */ int ret; /* get the time so we can have a filename with seconds since epoch @@ -100,7 +102,10 @@ int AlertUnifiedLogCreateFile(ThreadVars *t, AlertUnifiedLogThread *aun) { gettimeofday(&ts, NULL); /* create the filename to use */ - snprintf(filename, sizeof(filename), "%s/%s.%" PRIu32, "/var/log/eidps", "unified.log", (uint32_t)ts.tv_sec); + char *log_dir; + if (ConfGet("default-log-dir", &log_dir) != 1) + log_dir = DEFAULT_LOG_DIR; + snprintf(filename, sizeof(filename), "%s/%s.%" PRIu32, log_dir, "unified.log", (uint32_t)ts.tv_sec); /* XXX filename & location */ aun->fp = fopen(filename, "wb"); diff --git a/src/conf.c b/src/conf.c new file mode 100644 index 0000000000..bc3bf33952 --- /dev/null +++ b/src/conf.c @@ -0,0 +1,326 @@ +/* Copyright (c) 2009 Open Information Security Foundation + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, 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 + * along with this program. If not, see . + */ + +/** + * This file provides a basic configuration system for the IDPS + * engine. + * + * NOTE: Setting values should only be done from one thread during + * engine initialization. Multiple threads should be able access read + * configuration data. Allowing run time changes to the configuration + * will require some locks. + * + * \author Endace Technology Limited + */ + +#include +#include +#include + +#include "eidps-common.h" +#include "conf.h" +#include "util-hash.h" +#include "util-unittest.h" + +#undef CONF_DEBUG +#ifdef CONF_DEBUG +#define DPRINTF(x) do { printf x ; } while (0) +#else +#define DPRINTF(x) +#endif /* CONF_DEBUG */ + +#define CONF_HASH_TBL_SIZE 1024 + +static HashTable *conf_hash = NULL; + +/** + * Structure of a configuration parameter. + */ +struct conf_node { + char *name; + char *val; + + int allow_override; +}; + +/** + * \brief Function to generate the hash of a configuration value. + * + * This is a callback function provided to HashTable for creating the + * hash key. Its a simple wrapper around the generic hash function + * the passes on the configuration parameter name. + * + * \retval The hash ID of the configuration parameters name. + */ +static uint32_t +ConfHashFunc(HashTable *ht, void *data, uint16_t len) +{ + struct conf_node *cn = (struct conf_node *)data; + uint32_t hash; + + hash = HashTableGenericHash(ht, cn->name, strlen(cn->name)); + DPRINTF(("%s: %s -> %" PRIu32 "\n", __func__, cn->name, hash)); + return hash; +} + +/** + * \brief Function to compare 2 hash nodes. + * + * This is a callback function provided to the HashTable for comparing + * 2 nodes. + * + * \retval 1 if equivalant otherwise 0. + */ +static char +ConfHashComp(void *a, uint16_t a_len, void *b, uint16_t b_len) +{ + struct conf_node *ca = (struct conf_node *)a; + struct conf_node *cb = (struct conf_node *)b; + + if (strcmp(ca->name, cb->name) == 0) + return 1; + else + return 0; +} + +/** + * \brief Callback function to free a hash node. + */ +static void ConfHashFree(void *data) +{ + struct conf_node *cn = (struct conf_node *)data; + + DPRINTF(("%s: Freeing configuration parameter '%s'\n", __func__, cn->name)); + free(cn->name); + free(cn->val); + free(cn); +} + +/** + * \brief Initialize the configuration system. + */ +void +ConfInit(void) +{ + /* Prevent double initialization. */ + if (conf_hash != NULL) { + DPRINTF(("%s: Already initialized.\n", __func__)); + return; + } + + conf_hash = HashTableInit(CONF_HASH_TBL_SIZE, ConfHashFunc, ConfHashComp, + ConfHashFree); + if (conf_hash == NULL) { + fprintf(stderr, + "ERROR: Failed to allocate memory for configuration, aborting.\n"); + exit(1); + } + DPRINTF(("%s: Configuration module initialized.\n", __func__)); +} + +/** + * \brief Set a configuration value. + * + * \param name The name of the configuration parameter to set. + * \param val The value of the configuration parameter. + * \param allow_override Can a subsequent set override this value. + * + * \retval 1 if the value was set otherwise 0. + */ +int +ConfSet(char *name, char *val, int allow_override) +{ + struct conf_node lookup_key, *conf_node; + + lookup_key.name = name; + conf_node = HashTableLookup(conf_hash, &lookup_key, sizeof(lookup_key)); + if (conf_node != NULL) { + if (!allow_override) { + return 0; + } + HashTableRemove(conf_hash, conf_node, sizeof(*conf_node)); + } + + conf_node = calloc(1, sizeof(*conf_node)); + if (conf_node == NULL) { + return 0; + } + conf_node->name = strdup(name); + conf_node->val = strdup(val); + conf_node->allow_override = allow_override; + + if (HashTableAdd(conf_hash, conf_node, sizeof(*conf_node)) != 0) { + fprintf(stderr, "ERROR: Failed to set configuration parameter %s\n", + name); + exit(1); + } + DPRINTF(("%s: Configuration parameter '%s' set.\n", __func__, name)); + + return 1; +} + +/** + * \brief Retrieve a configuration value. + * + * \param name Name of configuration parameter to get. + * \param vptr Pointer that will be set to the configuration value parameter. + * Note that this is just a reference to the actual value, not a copy. + * + * \retval 1 will be returned if the name is found, otherwise 0 will + * be returned. + */ +int +ConfGet(char *name, char **vptr) +{ + struct conf_node lookup_key; + struct conf_node *conf_node; + + lookup_key.name = name; + + conf_node = HashTableLookup(conf_hash, &lookup_key, sizeof(lookup_key)); + if (conf_node == NULL) { + DPRINTF(("%s: Failed to lookup configuration parameter '%s'\n", + __func__, name)); + return 0; + } + else { + *vptr = conf_node->val; + return 1; + } +} + +/** + * \brief Remove a configuration parameter from the configuration db. + * + * \param name The name of the configuration parameter to remove. + * + * \retval Returns 1 if the parameter was removed, otherwise 0 is returned + * most likely indicating the parameter was not set. + */ +int +ConfRemove(char *name) +{ + struct conf_node cn; + + cn.name = name; + if (HashTableRemove(conf_hash, &cn, sizeof(cn)) == 0) + return 1; + else + return 0; +} + +#ifdef UNITTESTS + +/** + * Lookup a non-existant value. + */ +static int +ConfTestGetNonExistant(void) +{ + char name[] = "non-existant-value"; + char *value; + + return !ConfGet(name, &value); +} + +/** + * Set then lookup a value. + */ +static int +ConfTestSetAndGet(void) +{ + char name[] = "some-name"; + char value[] = "some-value"; + char *value0; + + if (ConfSet(name, value, 1) != 1) + return 0; + if (ConfGet(name, &value0) != 1) + return 0; + if (strcmp(value, value0) != 0) + return 0; + + /* Cleanup. */ + ConfRemove(name); + + return 1; +} + +/** + * Test that overriding a value is allowed provided allow_override is + * true and that the config parameter gets the new value. + */ +static int +ConfTestOverrideValue1(void) +{ + char name[] = "some-name"; + char value0[] = "some-value"; + char value1[] = "new-value"; + char *val; + int rc; + + if (ConfSet(name, value0, 1) != 1) + return 0; + if (ConfSet(name, value1, 1) != 1) + return 0; + if (ConfGet(name, &val) != 1) + return 0; + + rc = !strcmp(val, value1); + + /* Cleanup. */ + ConfRemove(name); + + return rc; +} + +/** + * Test that overriding a value is not allowed provided that + * allow_override is false and make sure the value was not overrided. + */ +static int +ConfTestOverrideValue2(void) +{ + char name[] = "some-name"; + char value0[] = "some-value"; + char value1[] = "new-value"; + char *val; + int rc; + + if (ConfSet(name, value0, 0) != 1) + return 0; + if (ConfSet(name, value1, 0) != 0) + return 0; + if (ConfGet(name, &val) != 1) + return 0; + + rc = !strcmp(val, value0); + + /* Cleanup. */ + ConfRemove(name); + + return rc; +} + +void +ConfRegisterTests(void) +{ + UtRegisterTest("ConfTestGetNonExistant", ConfTestGetNonExistant, 1); + UtRegisterTest("ConfTestSetAndGet", ConfTestSetAndGet, 1); + UtRegisterTest("ConfTestOverrideValue1", ConfTestOverrideValue1, 1); + UtRegisterTest("ConfTestOverrideValue2", ConfTestOverrideValue2, 1); +} + +#endif /* UNITTESTS */ diff --git a/src/conf.h b/src/conf.h new file mode 100644 index 0000000000..60bf9800bf --- /dev/null +++ b/src/conf.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2009 Open Information Security Foundation + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, 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 + * along with this program. If not, see . + */ + +/** + * \author Endace Technology Limited + */ + +#ifndef __CONF_H__ +#define __CONF_H__ + +/** + * The default log directory. + */ +#define DEFAULT_LOG_DIR "/var/log/eidps" + +void ConfInit(void); +int ConfGet(char *name, char **vptr); +int ConfSet(char *name, char *val, int allow_override); +void ConfRegisterTests(); + +#endif /* ! __CONF_H__ */ diff --git a/src/config.c b/src/config.c deleted file mode 100644 index 520a53143d..0000000000 --- a/src/config.c +++ /dev/null @@ -1,84 +0,0 @@ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -/** \todo These are covered by HAVE_* macros */ -#include -#include -#include -#include -#include - -#include - - -#include "eidps-common.h" - -static pcre *config_pcre = NULL; -static pcre_extra *config_pcre_extra = NULL; - -#define CONFIG_PCRE "^\\s*([a-z]+)\\s*(.*)$" - - - -int LoadConfig ( void ) { - char line[8192] = ""; - char *regexstr = CONFIG_PCRE; - const char *eb; - int eo; - int opts = 0; - int ret = 0; -#define MAX_SUBSTRINGS 30 - int ov[MAX_SUBSTRINGS]; - - FILE *fp = fopen("eidps.conf", "r"); - if (fp == NULL) printf("ERROR: fopen failed %s\n", strerror(errno)); - - - //opts |= PCRE_UNGREEDY; - config_pcre = pcre_compile(regexstr, opts, &eb, &eo, NULL); - if(config_pcre == NULL) - { - printf("pcre compile of \"%s\" failed at offset %" PRId32 ": %s\n", regexstr, eo, eb); - exit(1); - } - - config_pcre_extra = pcre_study(config_pcre, 0, &eb); - if(eb != NULL) - { - printf("pcre study failed: %s\n", eb); - exit(1); - } - - - while (fgets(line,sizeof(line),fp) != NULL) { - //printf("LoadConfig: %s", line); - - ret = pcre_exec(config_pcre, config_pcre_extra, line, strlen(line), 0, 0, ov, MAX_SUBSTRINGS); - if (ret != 3) { - //printf("pcre_exec failed: ret %" PRId32 ", optstr \"%s\"\n", ret, line); - continue; - } - //printf("LoadConfig: pcre_exec returned %" PRId32 "\n", ret); - - const char *all, *name, *value; - pcre_get_substring(line, ov, MAX_SUBSTRINGS, 0, &all); - pcre_get_substring(line, ov, MAX_SUBSTRINGS, 1, &name); - pcre_get_substring(line, ov, MAX_SUBSTRINGS, 2, &value); - - printf("LoadConfig: name \"%s\" value \"%s\"\n", name, value); - } - - return 0; -/** \todo Currently unused */ -#if 0 -error: - return -1; -#endif -} - diff --git a/src/counters.c b/src/counters.c index 69dcb68ceb..65922898dc 100644 --- a/src/counters.c +++ b/src/counters.c @@ -12,12 +12,40 @@ #include "tm-modules.h" #include "tm-threads.h" #include "util-unittest.h" +#include "conf.h" -/** \todo config api */ -#define LOGPATH "/var/log/eidps/stats.log" +/** \todo Get the default log directory from some global resource. */ +#define DEFAULT_LOG_FILENAME "stats.log" static PerfOPIfaceContext *perf_op_ctx = NULL; +/** + * \brief Get the filename with path to the stats log file. + * + * This function returns a string containing the log filename. It + * uses allocated memory simply to drop into the existing code a + * little better where a strdup was used. So as before, it is up to + * the caller to free the memory. + * + * \retval An allocated string containing the log filename or NULL on + * a failure. + */ +static char * +PerfGetLogFilename(void) +{ + char *log_dir; + char *log_filename; + + if (ConfGet("default-log-dir", &log_dir) != 1) + log_dir = DEFAULT_LOG_DIR; + log_filename = malloc(PATH_MAX); + if (log_filename == NULL) + return NULL; + snprintf(log_filename, PATH_MAX, "%s/%s", log_dir, DEFAULT_LOG_FILENAME); + + return log_filename; +} + /** * \brief Initializes the perf counter api. Things are hard coded currently. * More work to be done when we implement multiple interfaces @@ -42,7 +70,7 @@ void PerfInitOPCtx(void) perf_op_ctx->iface = IFACE_FILE; - if ( (perf_op_ctx->file = strdup(LOGPATH)) == NULL) { + if ( (perf_op_ctx->file = PerfGetLogFilename()) == NULL) { printf("error allocating memory\n"); exit(0); } diff --git a/src/eidps.c b/src/eidps.c index 9eed7f76de..9509e7b230 100644 --- a/src/eidps.c +++ b/src/eidps.c @@ -830,6 +830,7 @@ void usage(const char *progname) printf("\t-r : run in pcap file/offline mode\n"); printf("\t-q : run in inline nfqueue mode\n"); printf("\t-s : path to signature file (optional)\n"); + printf("\t-l : default log directory\n"); #ifdef UNITTESTS printf("\t-u : run the unittests and exit\n"); #endif /* UNITTESTS */ @@ -853,7 +854,10 @@ int main(int argc, char **argv) setup_signal_handler(SIGHUP, handle_sighup); //pthread_sigmask(SIG_BLOCK, &set, 0); - while ((opt = getopt(argc, argv, "hi:q:r:us:")) != -1) { + /* Initialize the configuration module. */ + ConfInit(); + + while ((opt = getopt(argc, argv, "hi:l:q:r:us:")) != -1) { switch (opt) { case 'h': usage(argv[0]); @@ -863,6 +867,12 @@ int main(int argc, char **argv) mode = MODE_PCAP_DEV; pcap_dev = optarg; break; + case 'l': + if (ConfSet("default-log-dir", optarg, 0) != 1) { + fprintf(stderr, "ERROR: Failed to set log directory.\n"); + exit(1); + } + break; case 'q': mode = MODE_NFQ; nfq_id = atoi(optarg); /* strtol? */ @@ -960,6 +970,7 @@ int main(int argc, char **argv) DecodePPPoERegisterTests(); DecodeICMPV4RegisterTests(); AlpDetectRegisterTests(); + ConfRegisterTests(); UtRunTests(); UtCleanup(); exit(0); diff --git a/src/log-httplog.c b/src/log-httplog.c index 135b8382fa..204f11bb27 100644 --- a/src/log-httplog.c +++ b/src/log-httplog.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include "debug.h" #include "detect.h" #include "pkt-var.h" +#include "conf.h" #include "threadvars.h" #include "tm-modules.h" @@ -28,6 +30,8 @@ #include "util-print.h" #include "util-unittest.h" +#define DEFAULT_LOG_FILENAME "http.log" + int LogHttplog (ThreadVars *, Packet *, void *, PacketQueue *); int LogHttplogIPv4(ThreadVars *, Packet *, void *, PacketQueue *); int LogHttplogIPv6(ThreadVars *, Packet *, void *, PacketQueue *); @@ -180,11 +184,13 @@ int LogHttplogThreadInit(ThreadVars *t, void *initdata, void **data) } memset(aft, 0, sizeof(LogHttplogThread)); - /* XXX */ - char *path = "/var/log/eidps/http.log"; - aft->fp = fopen(path, "w"); + char log_path[PATH_MAX], *log_dir; + if (ConfGet("default-log-dir", &log_dir) != 1) + log_dir = DEFAULT_LOG_DIR; + snprintf(log_path, PATH_MAX, "%s/%s", log_dir, DEFAULT_LOG_FILENAME); + aft->fp = fopen(log_path, "w"); if (aft->fp == NULL) { - printf("ERROR: failed to open %s: %s\n", path, strerror(errno)); + printf("ERROR: failed to open %s: %s\n", log_path, strerror(errno)); return -1; }