summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ulogd/Makefile.in5
-rw-r--r--ulogd/Rules.make.in6
-rw-r--r--ulogd/configure.in73
-rw-r--r--ulogd/doc/sqlite3.table22
-rw-r--r--ulogd/sqlite3/Makefile.in29
-rw-r--r--ulogd/sqlite3/ulogd_SQLITE3.c406
-rw-r--r--ulogd/ulogd.c3
-rw-r--r--ulogd/ulogd.conf.in8
8 files changed, 549 insertions, 3 deletions
diff --git a/ulogd/Makefile.in b/ulogd/Makefile.in
index 62c8015..87f8922 100644
--- a/ulogd/Makefile.in
+++ b/ulogd/Makefile.in
@@ -24,6 +24,11 @@ endif
ULOGD_VERSION=1.10
OLD_ULOGD_VERSION=1.09
+ifeq (x@SQLITE3INCLUDES@,x)
+else
+SUBDIRS+=sqlite3
+endif
+
# Normally You should not need to change anything below
all: recurse ulogd
diff --git a/ulogd/Rules.make.in b/ulogd/Rules.make.in
index 21b05d9..cab6b7d 100644
--- a/ulogd/Rules.make.in
+++ b/ulogd/Rules.make.in
@@ -41,3 +41,9 @@ MYSQL_LDFLAGS=@DATABASE_LIB_DIR@ @MYSQL_LIB@
#ULOGD_SL+=PGSQL
PGSQL_CFLAGS=-I@PGSQLINCLUDES@ @EXTRA_PGSQL_DEF@
PGSQL_LDFLAGS=@DATABASE_LIB_DIR@ @PGSQL_LIB@
+
+# mysql output support
+#ULOGD_SL+=SQLITE3
+SQLITE3_CFLAGS=-I@SQLITE3INCLUDES@ @EXTRA_SQLITE3_DEF@
+SQLITE3_LDFLAGS=@DATABASE_LIB_DIR@ @SQLITE3_LIB@
+
diff --git a/ulogd/configure.in b/ulogd/configure.in
index 1b94de7..acf7628 100644
--- a/ulogd/configure.in
+++ b/ulogd/configure.in
@@ -195,6 +195,75 @@ AC_ARG_WITH(pgsql-log-ip-as-string,
])
+dnl
+dnl test for sqlite3
+dnl
+AC_ARG_WITH(sqlite3,
+ --with-sqlite3=<directory> sqlite3 installed in <directoty>,[
+if test $withval != yes
+then
+ dir=$withval
+else
+ dir="/usr/local"
+fi
+mysqldir=""
+AC_MSG_CHECKING(for sqlite3 files)
+for d in $dir /usr /usr/local /usr/local/sqlite3
+do
+ if test -f $d/lib/sqlite3/libsqlite3.so
+ then
+ AC_MSG_RESULT(found sqlite3 in $d)
+ sqlite3dir=$d
+ sqlite3dir_suffix=/sqlite3
+ break
+ elif test -f $d/lib/libsqlite3.so
+ then
+ AC_MSG_RESULT(found sqlite in $d)
+ sqlite3dir=$d
+ sqlite3dir_suffix=
+ break
+ fi
+done
+
+if test x$sqlite3dir = x
+then
+ AC_MSG_WARN(sqlite3 backend not used)
+else
+ AC_DEFINE(HAVE_SQLITE3)
+ SQLITE3INCLUDES=${sqlite3dir}/include${sqlite3dir_suffix}
+ SQLITE3LIBS=${sqlite3dir}/lib${sqlite3dir_suffix}
+
+ DATABASE_DIR="${DATABASE_DIR} sqlite3"
+
+ SQLITE3_LIB="${DATABASE_LIB} -lsqlite3 "
+ DATABASE_LIB_DIR="${DATABASE_LIB_DIR} -L${SQLITE3LIBS} "
+
+dnl DATABASE_DRIVERS="${DATABASE_DRIVERS} ../sqlite3/mysql_driver.o "
+
+ DB_DEF="${DB_DEF} -DHAVE_SQLITE3 "
+
+
+ AC_SUBST(SQLITE3INCLUDES)
+ AC_SUBST(SQLITE3_LIB)
+
+fi
+])
+
+
+dnl
+dnl Check whether the user wants log IP-addresses as strings rather
+dnl than as unsigned long-integers to his sqlite3-database. Since this
+dnl feature is only used in ulogd_SQLITE3.c, there are no checks in any
+dnl way.
+dnl
+
+AC_ARG_WITH(sqlite3-log-ip-as-string,
+ --with-sqlite3-log-ip-as-string log IPs as string rather than as
+ unsigned long-integer.
+,[
+ EXTRA_SQLITE3_DEF="-D${EXTRA_SQLITE3_DEF} -DIP_AS_STRING=1"
+ AC_MSG_WARN(the use of --with-sqlite3-log-ip-as-string is discouraged)
+])
AC_SUBST(DATABASE_DIR)
@@ -203,11 +272,13 @@ AC_SUBST(DATABASE_LIB_DIR)
AC_SUBST(DB_DEF)
AC_SUBST(EXTRA_MYSQL_DEF)
AC_SUBST(EXTRA_PGSQL_DEF)
+AC_SUBST(EXTRA_SQLITE3_DEF)
AC_SUBST(DATABASE_DRIVERS)
AC_SUBST(HAVE_PCAP_H)
AM_CONDITIONAL(HAVE_MYSQL, test x$mysqldir != x)
AM_CONDITIONAL(HAVE_PGSQL, test x$pgsqldir != x)
+AM_CONDITIONAL(HAVE_SQLITE3, test x$sqlite3dir != x)
-AC_OUTPUT(extensions/Makefile doc/Makefile conffile/Makefile libipulog/Makefile mysql/Makefile pgsql/Makefile pcap/Makefile Makefile Rules.make)
+AC_OUTPUT(extensions/Makefile doc/Makefile conffile/Makefile libipulog/Makefile mysql/Makefile pgsql/Makefile sqlite3/Makefile pcap/Makefile Makefile Rules.make)
diff --git a/ulogd/doc/sqlite3.table b/ulogd/doc/sqlite3.table
new file mode 100644
index 0000000..7b5e99a
--- /dev/null
+++ b/ulogd/doc/sqlite3.table
@@ -0,0 +1,22 @@
+CREATE TABLE ulog (
+ raw_mac VARCHAR(80),
+ oob_time_sec INT UNSIGNED,
+ oob_time_usec INT UNSIGNED,
+ ip_saddr INT UNSIGNED,
+ ip_daddr INT UNSIGNED,
+ ip_protocol TINYINT UNSIGNED,
+ ip_totlen SMALLINT UNSIGNED,
+ tcp_sport SMALLINT UNSIGNED,
+ tcp_dport SMALLINT UNSIGNED,
+ udp_sport SMALLINT UNSIGNED,
+ udp_dport SMALLINT UNSIGNED,
+ udp_len SMALLINT UNSIGNED,
+ icmp_type TINYINT UNSIGNED,
+ icmp_code TINYINT UNSIGNED,
+ icmp_echoid SMALLINT UNSIGNED,
+ icmp_echoseq SMALLINT UNSIGNED,
+ icmp_gateway INT UNSIGNED,
+ icmp_fragmtu SMALLINT UNSIGNED
+ );
+
+
diff --git a/ulogd/sqlite3/Makefile.in b/ulogd/sqlite3/Makefile.in
new file mode 100644
index 0000000..5c0e1f1
--- /dev/null
+++ b/ulogd/sqlite3/Makefile.in
@@ -0,0 +1,29 @@
+#
+# Normally You should not need to change anything below
+#
+include @top_srcdir@/Rules.make
+
+CFLAGS+=-I@top_srcdir@ -I@top_srcdir@/libipulog/include -I@top_srcdir@/include
+SH_CFLAGS:=$(CFLAGS) -fPIC
+
+SHARED_LIBS=ulogd_SQLITE3.so
+
+all: $(SHARED_LIBS)
+
+distrib:
+
+$(SHARED_LIBS): %.so: %_sh.o
+ $(LD) -shared $(SQLITE3_LDFLAGS) -o $@ $< -lc
+
+%_sh.o: %.c
+ $(CC) $(SQLITE3_CFLAGS) $(SH_CFLAGS) -o $@ -c $<
+
+clean:
+ $(RM) $(SHARED_LIBS) *.o
+
+distclean:
+ $(RM) Makefile
+
+install: all
+ $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH)
+ $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH)
diff --git a/ulogd/sqlite3/ulogd_SQLITE3.c b/ulogd/sqlite3/ulogd_SQLITE3.c
new file mode 100644
index 0000000..8d78f56
--- /dev/null
+++ b/ulogd/sqlite3/ulogd_SQLITE3.c
@@ -0,0 +1,406 @@
+/*
+ * ulogd output plugin for logging to a SQLITE database
+ *
+ * (C) 2005 by Ben La Monica <ben.lamonica@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This module has been adapted from the ulogd_MYSQL.c written by
+ * Harald Welte <laforge@gnumonks.org>
+ * Alex Janssen <alex@ynfonatic.de>
+ *
+ * You can see benchmarks and an explanation of the testing
+ * at http://www.pojo.us/ulogd/
+ *
+ * 2005-02-09 Harald Welte <laforge@gnumonks.org>:
+ * - port to ulogd-1.20
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ulogd/ulogd.h>
+#include <ulogd/conffile.h>
+#include <sqlite3.h>
+
+#ifdef DEBUG_SQLITE3
+#define DEBUGP(x, args...) fprintf(stderr, x, ## args)
+#else
+#define DEBUGP(x, args...)
+#endif
+
+struct _field {
+ char name[ULOGD_MAX_KEYLEN];
+ unsigned int id;
+ struct _field *next;
+};
+
+/* the database handle we are using */
+static sqlite3 *dbh;
+
+/* a linked list of the fields the table has */
+static struct _field *fields;
+
+/* buffer for our insert statement */
+static char *stmt;
+
+/* pointer to the final prepared statement */
+static sqlite3_stmt *p_stmt;
+
+/* number of statements to buffer before we commit */
+static int buffer_size;
+
+/* number of statements currently in the buffer */
+static int buffer_ctr;
+
+/* our configuration directives */
+static config_entry_t db_ce = {
+ .key = "db",
+ .type = CONFIG_TYPE_STRING,
+ .options = CONFIG_OPT_MANDATORY,
+};
+
+static config_entry_t table_ce = {
+ .next = &db_ce,
+ .key = "table",
+ .type = CONFIG_TYPE_STRING,
+ .options = CONFIG_OPT_MANDATORY,
+};
+
+static config_entry_t buffer_ce = {
+ .next = &table_ce,
+ .key = "buffer",
+ .type = CONFIG_TYPE_INT,
+ .options = CONFIG_OPT_MANDATORY,
+};
+
+/* our main output function, called by ulogd */
+static int _sqlite3_output(ulog_iret_t *result)
+{
+ struct _field *f;
+ ulog_iret_t *res;
+ int col_counter;
+ char *ipaddr;
+
+ col_counter = 0;
+ for (f = fields; f; f = f->next) {
+ res = keyh_getres(f->id);
+
+ if (!res) {
+ ulogd_log(ULOGD_NOTICE,
+ "no result for %s ?!?\n", f->name);
+ }
+
+ if (!res || !IS_VALID((*res))) {
+ /* no result, pass a null */
+ col_counter++;
+ continue;
+ }
+
+ switch (res->type) {
+ case ULOGD_RET_INT8:
+ sqlite3_bind_int(p_stmt,col_counter,res->value.i8);
+ break;
+ case ULOGD_RET_INT16:
+ sqlite3_bind_int(p_stmt,col_counter,res->value.i16);
+ break;
+ case ULOGD_RET_INT32:
+ sqlite3_bind_int(p_stmt,col_counter,res->value.i32);
+ break;
+ case ULOGD_RET_INT64:
+ sqlite3_bind_int64(p_stmt,col_counter,res->value.i64);
+ break;
+ case ULOGD_RET_UINT8:
+ sqlite3_bind_int(p_stmt,col_counter,res->value.ui8);
+ break;
+ case ULOGD_RET_UINT16:
+ sqlite3_bind_int(p_stmt,col_counter,res->value.ui8);
+ break;
+ case ULOGD_RET_IPADDR:
+#ifdef IP_AS_STRING
+ ipaddr = inet_ntoa(ntohl(res->value.ui32));
+ sqlite3_bind_text(p_stmt,col_counter,ipaddr,strlen(ipaddr),SQLITE_STATIC);
+ break;
+#endif /* IP_AS_STRING */
+ /* EVIL: fallthrough when logging IP as u_int32_t */
+ case ULOGD_RET_UINT32:
+ sqlite3_bind_int(p_stmt,col_counter,res->value.ui32);
+ break;
+ case ULOGD_RET_UINT64:
+ sqlite3_bind_int64(p_stmt,col_counter,res->value.ui64);
+ break;
+ case ULOGD_RET_BOOL:
+ sqlite3_bind_int(p_stmt,col_counter,res->value.b);
+ break;
+ case ULOGD_RET_STRING:
+ sqlite3_bind_text(p_stmt,col_counter,res->value.ptr,strlen(res->value.ptr),SQLITE_STATIC);
+ break;
+ default:
+ ulogd_log(ULOGD_NOTICE,
+ "unknown type %d for %s\n",
+ res->type, res->key);
+ break;
+ }
+
+ col_counter++;
+ }
+
+ /* now we have created our statement, insert it */
+
+ if (sqlite3_step(p_stmt) == SQLITE_DONE) {
+ sqlite3_reset(p_stmt);
+ buffer_ctr++;
+ } else {
+ ulogd_log(ULOGD_ERROR, "sql error during insert: %s\n",
+ sqlite3_errmsg(dbh));
+ return 1;
+ }
+
+ /* commit all of the inserts to the database, ie flush buffer */
+ if (buffer_ctr >= buffer_size) {
+ if (sqlite3_exec(dbh,"commit",NULL,NULL,NULL) != SQLITE_OK)
+ ulogd_log(ULOGD_ERROR,"unable to commit records to db.");
+
+ if (sqlite3_exec(dbh,"begin deferred",NULL,NULL,NULL) != SQLITE_OK)
+ ulogd_log(ULOGD_ERROR,"unable to begin a new transaction.");
+
+ buffer_ctr = 0;
+ DEBUGP("committing.\n");
+ }
+
+ return 0;
+}
+
+#define _SQLITE3_INSERTTEMPL "insert into X (Y) values (Z)"
+
+/* create the static part of our insert statement */
+static int _sqlite3_createstmt(void)
+{
+ struct _field *f;
+ unsigned int size;
+ char buf[ULOGD_MAX_KEYLEN];
+ char *underscore;
+ char *stmt_pos;
+ int col_count;
+ int i;
+
+ if (stmt) {
+ ulogd_log(ULOGD_NOTICE, "createstmt called, but stmt"
+ " already existing\n");
+ return 1;
+ }
+
+ /* caclulate the size for the insert statement */
+ size = strlen(_SQLITE3_INSERTTEMPL) + strlen(table_ce.u.string);
+
+ DEBUGP("initial size: %u\n", size);
+
+ col_count = 0;
+ for (f = fields; f; f = f->next) {
+ /* we need space for the key and a comma, and a ? */
+ size += strlen(f->name) + 3;
+ DEBUGP("size is now %u since adding %s\n",size,f->name);
+ col_count++;
+ }
+
+ DEBUGP("there were %d columns\n",col_count);
+ DEBUGP("after calc name length: %u\n",size);
+
+ ulogd_log(ULOGD_DEBUG, "allocating %u bytes for statement\n", size);
+
+ stmt = (char *) malloc(size);
+
+ if (!stmt) {
+ ulogd_log(ULOGD_ERROR, "OOM!\n");
+ return 1;
+ }
+
+ sprintf(stmt, "insert into %s (", table_ce.u.string);
+ stmt_pos = stmt + strlen(stmt);
+
+ for (f = fields; f; f = f->next) {
+ strncpy(buf, f->name, ULOGD_MAX_KEYLEN);
+ while ((underscore = strchr(buf, '.')))
+ *underscore = '_';
+ sprintf(stmt_pos, "%s,", buf);
+ stmt_pos = stmt + strlen(stmt);
+ }
+
+ *(stmt_pos - 1) = ')';
+
+ sprintf(stmt_pos, " values (");
+ stmt_pos = stmt + strlen(stmt);
+
+ for (i = 0; i < col_count - 1; i++) {
+ sprintf(stmt_pos,"?,");
+ stmt_pos += 2;
+ }
+
+ sprintf(stmt_pos, "?)");
+ ulogd_log(ULOGD_DEBUG, "stmt='%s'\n", stmt);
+
+ DEBUGP("about to prepare statement.\n");
+
+ sqlite3_prepare(dbh,stmt,-1,&p_stmt,0);
+
+ DEBUGP("statement prepared.\n");
+
+ if (!p_stmt) {
+ ulogd_log(ULOGD_ERROR,"unable to prepare statement");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* length of "select * from \0" */
+#define SQLITE_SELECT_LEN 15
+
+/* find out which columns the table has */
+static int _sqlite3_get_columns(const char *table)
+{
+ char buf[ULOGD_MAX_KEYLEN];
+ char query[SQLITE_SELECT_LEN + CONFIG_VAL_STRING_LEN] = "select * from \0";
+ char *underscore;
+ struct _field *f;
+ sqlite3_stmt *schema_stmt;
+ int column;
+ int result;
+ int id;
+
+ if (!dbh)
+ return 1;
+
+ strncat(query,table,LINE_LEN);
+
+ result = sqlite3_prepare(dbh,query,-1,&schema_stmt,0);
+
+ if (result != SQLITE_OK)
+ return 1;
+
+ for (column = 0; column < sqlite3_column_count(schema_stmt); column++) {
+ /* replace all underscores with dots */
+ strncpy(buf, sqlite3_column_name(schema_stmt,column), ULOGD_MAX_KEYLEN);
+ while ((underscore = strchr(buf, '_')))
+ *underscore = '.';
+
+ DEBUGP("field '%s' found: ", buf);
+
+ if (!(id = keyh_getid(buf))) {
+ DEBUGP(" no keyid!\n");
+ continue;
+ }
+
+ DEBUGP("keyid %u\n", id);
+
+ /* prepend it to the linked list */
+ f = (struct _field *) malloc(sizeof *f);
+ if (!f) {
+ ulogd_log(ULOGD_ERROR, "OOM!\n");
+ return 1;
+ }
+ strncpy(f->name, buf, ULOGD_MAX_KEYLEN);
+ f->id = id;
+ f->next = fields;
+ fields = f;
+ }
+
+ sqlite3_finalize(schema_stmt);
+ return 0;
+}
+
+/**
+ * make connection and select database
+ * returns 0 if database failed to open.
+ */
+static int _sqlite3_open_db(char *db_file)
+{
+ DEBUGP("opening database.\n");
+ return sqlite3_open(db_file,&dbh);
+}
+
+/* give us an opportunity to close the database down properly */
+static void _sqlite3_fini(void)
+{
+ DEBUGP("cleaning up db connection\n");
+
+ /* free up our prepared statements so we can close the db */
+ if (p_stmt) {
+ sqlite3_finalize(p_stmt);
+ DEBUGP("prepared statement finalized\n");
+ }
+
+ if (dbh) {
+ /* flush the remaining insert statements to the database. */
+ result = sqlite3_exec(dbh,"commit",NULL,NULL,NULL);
+
+ if (result != SQLITE_OK)
+ ulogd_log(ULOGD_ERROR,"unable to commit remaining records to db.");
+
+ sqlite3_close(dbh);
+ DEBUGP("database file closed\n");
+ }
+}
+
+static int _sqlite3_init(void)
+{
+ int result = 0;
+
+ /* have the opts parsed */
+ config_parse_file("SQLITE3", &buffer_ce);
+
+ if (_sqlite3_open_db(db_ce.u.string)) {
+ ulogd_log(ULOGD_ERROR, "can't open the database file\n");
+ return;
+ }
+
+ /* set the timeout so that we don't automatically fail
+ * if the table is busy. */
+ sqlite3_busy_timeout(dbh, _SQLITE3_BUSY_TIMEOUT);
+
+ /* read the fieldnames to know which values to insert */
+ if (_sqlite3_get_columns(table_ce.u.string)) {
+ ulogd_log(ULOGD_ERROR, "unable to get sqlite columns\n");
+ return;
+ }
+
+ /* initialize our buffer size and counter */
+ buffer_size = buffer_ce.u.value;
+ buffer_ctr = 0;
+
+ DEBUGP("Have a buffer size of : %d\n", buffer_size);
+
+ if (sqlite3_exec(dbh,"begin deferred",NULL,NULL,NULL) != SQLITE_OK)
+ ulogd_log(ULOGD_ERROR,"can't create a new transaction\n");
+
+ /* create and prepare the actual insert statement */
+ _sqlite3_createstmt();
+
+ register_output(&_sqlite3_plugin);
+}
+
+static ulog_output_t _sqlite3_plugin = {
+ .name = "sqlite3",
+ .output = &_sqlite3_output,
+ .init = &_sqlite3_init,
+ .fini = &sqlite3_fini,
+};
+
+#define _SQLITE3_BUSY_TIMEOUT 300
+
+void _init(void)
+{
+ register_output(&_sqlite3_plugin);
+}
+
diff --git a/ulogd/ulogd.c b/ulogd/ulogd.c
index 9367640..28ec6cc 100644
--- a/ulogd/ulogd.c
+++ b/ulogd/ulogd.c
@@ -757,7 +757,8 @@ int main(int argc, char* argv[])
setsid();
}
- signal(SIGTERM, &sigterm_handler);
+ /* send SIGINT to the term handler, since they hit CTRL-C */
+ signal(SIGINT, &sigterm_handler);
signal(SIGHUP, &sighup_handler);
ulogd_log(ULOGD_NOTICE,
diff --git a/ulogd/ulogd.conf.in b/ulogd/ulogd.conf.in
index b1bec43..6171267 100644
--- a/ulogd/ulogd.conf.in
+++ b/ulogd/ulogd.conf.in
@@ -1,5 +1,5 @@
# Example configuration for ulogd
-# $Id: ulogd.conf.in,v 1.2 2003/05/04 10:00:10 laforge Exp $
+# $Id$
#
[global]
@@ -45,6 +45,7 @@ plugin="@libdir@/ulogd_LOGEMU.so"
#plugin="@libdir@/ulogd_OPRINT.so"
#plugin="@libdir@/ulogd_MYSQL.so"
#plugin="@libdir@/ulogd_PGSQL.so"
+#plugin="@libdir@/ulogd_SQLITE3.so"
#plugin="@libdir@/ulogd_PCAP.so"
@@ -69,6 +70,11 @@ user="postgres"
db="ulogd"
host="localhost"
+[SQLITE3]
+table="ulog"
+db="/path/to/sqlite/db"
+buffer=200
+
[PCAP]
file="/var/log/ulogd.pcap"
sync=1