summaryrefslogtreecommitdiffstats
path: root/ulogd.c
diff options
context:
space:
mode:
Diffstat (limited to 'ulogd.c')
-rw-r--r--ulogd.c257
1 files changed, 169 insertions, 88 deletions
diff --git a/ulogd.c b/ulogd.c
index a60cf5f..55ed931 100644
--- a/ulogd.c
+++ b/ulogd.c
@@ -1,13 +1,13 @@
-/* ulogd, Version $Revision: 1.11 $
+/* ulogd, Version $Revision: 1.12 $
*
- * first try of a logging daemon for my netfilter ULOG target
- * for the linux 2.4 netfilter subsystem.
+ * userspace logging daemon for the netfilter ULOG target
+ * of the linux 2.4 netfilter subsystem.
*
- * (C) 2000 by Harald Welte <laforge@sunbeam.franken.de>
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
*
* this code is released under the terms of GNU GPL
*
- * $Id: ulogd.c,v 1.11 2000/11/16 17:20:52 laforge Exp $
+ * $Id: ulogd.c,v 1.12 2000/11/16 21:15:30 laforge Exp $
*/
#include <stdio.h>
@@ -22,6 +22,7 @@
#include "conffile.h"
#include "ulogd.h"
+/* Size of the netlink receive buffer */
#define MYBUFSIZ 2048
#ifdef DEBUG
@@ -31,9 +32,6 @@
#endif
/* default config parameters, if not changed in configfile */
-#ifndef ULOGD_PLUGINDIR_DEFAULT
-#define ULOGD_PLUGINDIR_DEFAULT "/usr/local/lib/ulogd"
-#endif
#ifndef ULOGD_LOGFILE_DEFAULT
#define ULOGD_LOGFILE_DEFAULT "/var/log/ulogd.log"
#endif
@@ -48,6 +46,8 @@
FILE *logfile = NULL;
+int loglevel = 1;
+
/* linked list for all registered interpreters */
static ulog_interpreter_t *ulogd_interpreters;
@@ -55,11 +55,26 @@ static ulog_interpreter_t *ulogd_interpreters;
static ulog_output_t *ulogd_outputs;
/***********************************************************************
- * INTERPRETER AND KEY HASH FUNCTIONS
+ * INTERPRETER AND KEY HASH FUNCTIONS (new in 0.9)
***********************************************************************/
+/* We keep hashtables of interpreters and registered keys. The hash-tables
+ * are allocated dynamically at program load time. You may control the
+ * allocation granularity of both hashes (i.e. the amount of hashtable
+ * entries are allocated at one time) through modification of the constants
+ * INTERH_ALLOC_GRAN and KEYH_ALLOC_GRAN
+ */
+
+/* allocation granularith */
+#define INTERH_ALLOC_GRAN 5
+
/* hashtable for all registered interpreters */
-static ulog_interpreter_t *ulogd_interh[100];
+static ulog_interpreter_t **ulogd_interh;
+
+/* current hashtable size */
+static unsigned int ulogd_interh_ids_alloc;
+
+/* total number of registered ids */
static unsigned int ulogd_interh_ids;
/* allocate a new interpreter id and write it into the interpreter struct */
@@ -68,12 +83,28 @@ static unsigned int interh_allocid(ulog_interpreter_t *ip)
unsigned int id;
id = ++ulogd_interh_ids;
+
+ if (id >= ulogd_interh_ids_alloc) {
+ if (!ulogd_interh)
+ ulogd_interh = (ulog_interpreter_t **)
+ malloc(INTERH_ALLOC_GRAN *
+ sizeof(ulog_interpreter_t));
+ else
+ ulogd_interh = (ulog_interpreter_t **)
+ realloc(ulogd_interh,
+ (INTERH_ALLOC_GRAN +
+ ulogd_interh_ids_alloc) *
+ sizeof(ulog_interpreter_t));
+
+ ulogd_interh_ids_alloc += INTERH_ALLOC_GRAN;
+ }
+
ip->id = id;
ulogd_interh[id] = ip;
return id;
}
-/* get interpreter d by name */
+/* get interpreter id by name */
unsigned int interh_getid(const char *name)
{
int i;
@@ -90,11 +121,21 @@ static void interh_dump(void)
int i;
for (i = 1; i <= ulogd_interh_ids; i++)
- printf("ulogd_interh[%d] = %s\n", i, (ulogd_interh[i])->name);
+ ulogd_log(ULOGD_DEBUG, "ulogd_interh[%d] = %s\n",
+ i, (ulogd_interh[i])->name);
}
-struct ulogd_keyh_entry ulogd_keyh[100];
+/* key hash allocation granularity */
+#define KEYH_ALLOC_GRAN 20
+
+/* hash table for key ids */
+struct ulogd_keyh_entry *ulogd_keyh;
+
+/* current size of the hashtable */
+static unsigned int ulogd_keyh_ids_alloc;
+
+/* total number of registered keys */
static unsigned int ulogd_keyh_ids;
/* allocate a new key_id */
@@ -105,6 +146,30 @@ static unsigned int keyh_allocid(ulog_interpreter_t *ip, unsigned int offset,
id = ++ulogd_keyh_ids;
+ if (id >= ulogd_keyh_ids_alloc) {
+ if (!ulogd_keyh) {
+ ulogd_keyh = (struct ulogd_keyh_entry *)
+ malloc(KEYH_ALLOC_GRAN *
+ sizeof(struct ulogd_keyh_entry));
+ if (!ulogd_keyh) {
+ ulogd_log(ULOGD_ERROR, "OOM!\n");
+ return 0;
+ }
+ } else {
+ ulogd_keyh = (struct ulogd_keyh_entry *)
+ realloc(ulogd_keyh, (KEYH_ALLOC_GRAN
+ +ulogd_keyh_ids_alloc) *
+ sizeof(struct ulogd_keyh_entry));
+
+ if (!ulogd_keyh) {
+ ulogd_log(ULOGD_ERROR, "OOM!\n");
+ return 0;
+ }
+ }
+
+ ulogd_keyh_ids_alloc += KEYH_ALLOC_GRAN;
+ }
+
ulogd_keyh[id].interp = ip;
ulogd_keyh[id].offset = offset;
ulogd_keyh[id].name = name;
@@ -112,6 +177,7 @@ static unsigned int keyh_allocid(ulog_interpreter_t *ip, unsigned int offset,
return id;
}
+/* dump the keyhash to standard output */
static void keyh_dump(void)
{
int i;
@@ -120,7 +186,6 @@ static void keyh_dump(void)
for (i = 1; i <= ulogd_keyh_ids; i++)
printf("ulogd_keyh[%d] = %s:%d\n", i, ulogd_keyh[i].interp->name,
ulogd_keyh[i].offset);
-
}
/* get keyid by name */
@@ -135,23 +200,37 @@ unsigned int keyh_getid(const char *name)
}
/* get key name by keyid */
-inline char *keyh_getname(unsigned int id)
+char *keyh_getname(unsigned int id)
{
+ if (id > ulogd_keyh_ids) {
+ ulogd_log(ULOGD_NOTICE,
+ "keyh_getname called with invalid id%u\n", id);
+ return NULL;
+ }
+
return ulogd_keyh[id].interp->name;
}
+/* get result for given key id. does not check if result valid */
ulog_iret_t *keyh_getres(unsigned int id)
{
ulog_iret_t *ret;
- ret = &ulogd_keyh[id].interp->result[ulogd_keyh[id].offset];
+ if (id > ulogd_keyh_ids) {
+ ulogd_log(ULOGD_NOTICE,
+ "keyh_getres called with invalid id %d\n", id);
+ return NULL;
+ }
- if (ret->flags & ULOGD_RETF_VALID)
- return ret;
+ ret = &ulogd_keyh[id].interp->result[ulogd_keyh[id].offset];
- return NULL;
+ return ret;
}
+/***********************************************************************
+ * INTERPRETER MANAGEMENT
+ ***********************************************************************
+
/* try to lookup a registered interpreter for a given name */
static ulog_interpreter_t *find_interpreter(const char *name)
{
@@ -172,32 +251,44 @@ void register_interpreter(ulog_interpreter_t *me)
/* check if we already have an interpreter with this name */
if (find_interpreter(me->name)) {
- ulogd_error("interpreter `%s' already registered\n",
- me->name);
- exit(1);
+ ulogd_log(ULOGD_NOTICE,
+ "interpreter `%s' already registered\n", me->name);
+ return;
}
- ulogd_log(ULOGD_NOTICE, "registering interpreter `%s'\n", me->name);
+ ulogd_log(ULOGD_INFO, "registering interpreter `%s'\n", me->name);
/* allocate a new interpreter id for it */
- interh_allocid(me);
+ if (!interh_allocid(me)) {
+ ulogd_log(ULOGD_ERROR, "unable to obtain interh_id for "
+ "interpreter '%s'\n", me->name);
+ return;
+ }
/* - allocate one keyh_id for each result of this interpreter
* - link the elements to each other */
for (i = 0; i < me->key_num; i++) {
- keyh_allocid(me, i, me->result[i].key);
+ if (!keyh_allocid(me, i, me->result[i].key)) {
+ ulogd_log(ULOGD_ERROR, "unable to obtain keyh_id "
+ "for interpreter %s, key %d", me->name,
+ me->result[i].key);
+ continue;
+ }
if (i != me->key_num - 1)
me->result[i].next = &me->result[i+1];
}
+ /* all work done, we can prepend the new interpreter to the list */
if (ulogd_interpreters)
me->result[me->key_num - 1].next = &ulogd_interpreters->result[0];
-
- /* all work done, we can prepend the new interpreter to the list */
me->next = ulogd_interpreters;
ulogd_interpreters = me;
}
+/***********************************************************************
+ * OUTPUT MANAGEMENT
+ ***********************************************************************
+
/* try to lookup a registered output plugin for a given name */
static ulog_output_t *find_output(const char *name)
{
@@ -215,7 +306,7 @@ static ulog_output_t *find_output(const char *name)
void register_output(ulog_output_t *me)
{
if (find_output(me->name)) {
- ulogd_error("output `%s' already registered\n",
+ ulogd_log(ULOGD_NOTICE, "output `%s' already registered\n",
me->name);
exit(1);
}
@@ -224,18 +315,9 @@ void register_output(ulog_output_t *me)
ulogd_outputs = me;
}
-/* allocate a new ulog_iret_t. Called by interpreter plugins */
-ulog_iret_t *alloc_ret(const u_int16_t type, const char* key)
-{
- ulog_iret_t *ptr = NULL;
-
- ptr = (ulog_iret_t *) malloc(sizeof(ulog_iret_t));
- memset(ptr, 0, sizeof(ulog_iret_t));
- strcpy(ptr->key, key);
- ptr->type = type;
-
- return ptr;
-}
+/***********************************************************************
+ * MAIN PROGRAM
+ ***********************************************************************
/* log message to the logfile */
void ulogd_log(int level, const char *format, ...)
@@ -245,6 +327,10 @@ void ulogd_log(int level, const char *format, ...)
time_t tm;
FILE *outfd;
+ /* log only messages which have level at least as high as loglevel */
+ if (level < loglevel)
+ return;
+
if (logfile)
outfd = logfile;
else
@@ -255,13 +341,13 @@ void ulogd_log(int level, const char *format, ...)
tm = time(NULL);
timestr = ctime(&tm);
timestr[strlen(timestr)-1] = '\0';
- fprintf(outfd, "%s <%1.1d>", timestr, level);
+ fprintf(outfd, "%s <%1.1d> %s:%d ", timestr, level, __FILE__, __LINE__);
vfprintf(outfd, format, ap);
va_end(ap);
}
-/* this should pass the result(s) to one or more registered output plugins,
- * but is currently only printing them out */
+
+/* propagate results to all registered output plugins */
static void propagate_results(ulog_iret_t *ret)
{
ulog_output_t *p;
@@ -284,8 +370,6 @@ static void clean_results(ulog_iret_t *ret)
}
}
-#define IS_VALID(x) (x.flags & ULOGD_RETF_VALID)
-
/* call all registered interpreters and hand the results over to
* propagate_results */
static void handle_packet(ulog_packet_msg_t *pkt)
@@ -299,7 +383,7 @@ static void handle_packet(ulog_packet_msg_t *pkt)
for (i = 1; i <= ulogd_interh_ids; i++) {
ip = ulogd_interh[i];
/* call interpreter */
- if (ret = ((ip)->interp)(ip, pkt)) {
+ if ((ret = ((ip)->interp)(ip, pkt))) {
/* create references for result linked-list */
for (j = 0; j < ip->key_num; j++) {
if (IS_VALID(ip->result[j])) {
@@ -313,34 +397,17 @@ static void handle_packet(ulog_packet_msg_t *pkt)
clean_results(ulogd_interpreters->result);
}
-/* silly plugin loader to dlopen() all available plugins */
-static void load_plugins(char *dir)
+/* plugin loader to dlopen() a plugins */
+static int load_plugin(char *file)
{
- DIR *ldir;
- struct dirent *dent;
- char *fname;
-
- ldir = opendir(dir);
- if (ldir) {
- fname = (char *) malloc(NAME_MAX + strlen(dir)
- + 3);
- for (dent = readdir(ldir); dent; dent = readdir(ldir)) {
- if (strncmp(dent->d_name,"ulogd", 5) == 0) {
- DEBUGP("load_plugins: %s\n", dent->d_name);
- sprintf(fname, "%s/%s", dir, dent->d_name);
- if (!dlopen(fname, RTLD_NOW))
- ulogd_error("load_plugins: %s\n", dlerror());
- }
- }
- free(fname);
- } else
- ulogd_error("No plugin directory: %s\n", dir);
-
- interh_dump();
- keyh_dump();
-
+ if (!dlopen(file, RTLD_NOW)) {
+ ulogd_log(ULOGD_ERROR, "load_plugins: %s\n", dlerror());
+ return 1;
+ }
+ return 0;
}
+/* open the logfile */
static int logfile_open(const char *name)
{
logfile = fopen(name, "a");
@@ -352,6 +419,7 @@ static int logfile_open(const char *name)
return 0;
}
+/* wrapper to handle conffile error codes */
static int parse_conffile(int final)
{
int err;
@@ -363,17 +431,21 @@ static int parse_conffile(int final)
return 0;
break;
case -ERROPEN:
- ulogd_error("ERROR: unable to open configfile: %s\n",
- ULOGD_CONFIGFILE);
+ ulogd_log(ULOGD_ERROR,
+ "unable to open configfile: %s\n",
+ ULOGD_CONFIGFILE);
break;
case -ERRMAND:
- ulogd_error("ERROR: mandatory option not found\n");
+ ulogd_log(ULOGD_ERROR,
+ "mandatory option not found\n");
break;
case -ERRMULT:
- ulogd_error("ERROR: option occurred more than once\n");
+ ulogd_log(ULOGD_ERROR,
+ "option occurred more than once\n");
break;
case -ERRUNKN:
- ulogd_error("ERROR: unknown config key\n");
+ ulogd_log(ULOGD_ERROR,
+ "unknown config key\n");
/* config_errce->key); */
break;
}
@@ -381,27 +453,29 @@ static int parse_conffile(int final)
}
+/* configuration directives of the main program */
static config_entry_t logf_ce = { NULL, "logfile", CONFIG_TYPE_STRING,
CONFIG_OPT_NONE, 0,
{ string: ULOGD_LOGFILE_DEFAULT } };
-
-static config_entry_t pldir_ce = { NULL, "plugindir", CONFIG_TYPE_STRING,
- CONFIG_OPT_NONE, 0,
- { string: ULOGD_PLUGINDIR_DEFAULT } };
-static config_entry_t nlgroup_ce = { NULL, "nlgroup", CONFIG_TYPE_INT,
+static config_entry_t plugin_ce = { &logf_ce, "plugin", CONFIG_TYPE_CALLBACK,
+ CONFIG_OPT_MULTI, 0,
+ { parser: &load_plugin } };
+
+static config_entry_t nlgroup_ce = { &plugin_ce, "nlgroup", CONFIG_TYPE_INT,
CONFIG_OPT_NONE, 0,
{ value: ULOGD_NLGROUP_DEFAULT } };
+
+static config_entry_t loglevel_ce = { &nlgroup_ce, "loglevel", CONFIG_TYPE_INT,
+ CONFIG_OPT_NONE, 0,
+ { value: 1 } };
+
static int init_conffile(char *file)
{
if (config_register_file(file))
return 1;
- /* link them together */
- logf_ce.next = &pldir_ce;
- pldir_ce.next = &nlgroup_ce;
-
- config_register_key(&logf_ce);
+ config_register_key(&loglevel_ce);
/* parse config file the first time (for logfile name, ...) */
return parse_conffile(0);
@@ -415,18 +489,24 @@ int main(int argc, char* argv[])
ulog_packet_msg_t *upkt;
if (init_conffile(ULOGD_CONFIGFILE)) {
+ ulogd_log(ULOGD_FATAL, "parse_conffile error\n");
exit(1);
}
logfile_open(logf_ce.u.string);
- load_plugins(pldir_ce.u.string);
/* parse config file the second time (for plugin options) */
if (parse_conffile(1)) {
- ulogd_error("ERROR during second parse_conffile\n");
+ ulogd_log(ULOGD_FATAL, "parse_conffile\n");
exit(1);
}
+#ifdef DEBUG
+ /* dump key and interpreter hash */
+ interh_dump();
+ keyh_dump();
+#endif
+
/* allocate a receive buffer */
buf = (unsigned char *) malloc(MYBUFSIZ);
@@ -434,6 +514,7 @@ int main(int argc, char* argv[])
h = ipulog_create_handle(ipulog_group2gmask(nlgroup_ce.u.value));
if (!h) {
/* if some error occurrs, print it to stderr */
+ ulogd_log(ULOGD_FATAL, "unable to create ipulogd handle\n");
ipulog_perror(NULL);
exit(1);
}