diff options
Diffstat (limited to 'ulogd.c')
-rw-r--r-- | ulogd.c | 257 |
1 files changed, 169 insertions, 88 deletions
@@ -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); } |