diff --git a/Makefile b/Makefile index c4c2557..7246080 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CFLAGS := -O2 -pipe -Wall -LDFLAGS := -lpthread -lnfnetlink -lnetfilter_conntrack +LDFLAGS := -lpthread -lnfnetlink -lnetfilter_conntrack -lmysqlclient OBJS := configfile.o conntrack.o database.o hashtable.o logging.o ctstats.o diff --git a/conntrack.c b/conntrack.c index 1543876..93b026b 100644 --- a/conntrack.c +++ b/conntrack.c @@ -2,6 +2,10 @@ #include #include +#include +#include +#include + #include #include @@ -10,6 +14,7 @@ #include "hashtable.h" #define DEFAULT_HASHSIZE 127 +#define DEFAULT_NETMASK "255.255.255.255" static pthread_t ct_thread; @@ -17,6 +22,7 @@ static struct nfct_handle *cth; static struct hash_table *table[2]; static int hash_select = 0; +static struct in_addr netmask; static int conntrack_event_cb(void *arg, unsigned int flags, int type, void *privdata) { @@ -31,7 +37,7 @@ static int conntrack_event_cb(void *arg, unsigned int flags, int type, void *pri return -1; } - entry->src_ip = ct->tuple[NFCT_DIR_ORIGINAL].src.v4; + entry->src_ip = (ct->tuple[NFCT_DIR_ORIGINAL].src.v4 & netmask.s_addr); entry->protonum = ct->tuple[NFCT_DIR_ORIGINAL].protonum; entry->dst_port = ct->tuple[NFCT_DIR_ORIGINAL].l4dst.tcp.port; @@ -42,7 +48,7 @@ static int conntrack_event_cb(void *arg, unsigned int flags, int type, void *pri return 0; } -int conntrack_dump_hash(void (*callback)(struct hash_entry *entry, void *privdata), void *privdata) +struct hash_table * conntrack_get_hash(void) { /* * switch hashtable @@ -52,13 +58,17 @@ int conntrack_dump_hash(void (*callback)(struct hash_entry *entry, void *privdat */ int used_hash = hash_select; hash_select ^= 0x01; - - purge_hash(table[used_hash], callback, privdata); - return 0; + return table[used_hash]; } int conntrack_init(void) { + char *mask = config_get_string("global", "netmask", DEFAULT_NETMASK); + if (inet_aton(mask, &netmask) == 0) { + log_print(LOG_ERROR, "conntrack_init: invalid netmask"); + return -1; + } + cth = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_DESTROY); if (cth == NULL) { log_print(LOG_ERROR, "conntrack_init: nfct_open()"); diff --git a/conntrack.h b/conntrack.h index 8396412..53e37e8 100644 --- a/conntrack.h +++ b/conntrack.h @@ -7,6 +7,6 @@ int conntrack_init(void); int conntrack_start_event_thread(void); int conntrack_close(void); -int conntrack_dump_hash(void (*callback)(struct hash_entry *entry, void *privdata), void *privdata); +struct hash_table * conntrack_get_hash(void); #endif // _CONNTRACK_H_ diff --git a/ctstats.c b/ctstats.c index c12b2f4..8ccaf1c 100644 --- a/ctstats.c +++ b/ctstats.c @@ -61,7 +61,7 @@ int main(int argc, char *argv[]) if (config_parse(config)) exit(1); - /* init netlink, hashtables, mutexes */ + /* init netlink & hashtables */ if (conntrack_init()) exit(1); @@ -71,13 +71,14 @@ int main(int argc, char *argv[]) exit(1); } + /* start event listener */ conntrack_start_event_thread(); int intervall = config_get_int("global", "intervall", DEFAULT_INTERVALL); while (1) { sleep(intervall); - /* fill database */ + /* parse hashes, fill database */ database_analyse(); } diff --git a/ctstats.conf b/ctstats.conf index 5789f13..f442810 100644 --- a/ctstats.conf +++ b/ctstats.conf @@ -1,10 +1,11 @@ [global] intervall 30 hashsize 127 +netmask 255.255.255.255 logfile ctstats.log [mysql] -hostname localhost +hostname cinnagar.lan username ctstats password ctstats database ctstats diff --git a/database.c b/database.c index a94baf1..3adb761 100644 --- a/database.c +++ b/database.c @@ -1,52 +1,77 @@ +#include #include #include #include +#include + +#include "configfile.h" #include "conntrack.h" #include "database.h" #include "hashtable.h" #include "logging.h" +static MYSQL *dbh; + static void purge_hash_cb(struct hash_entry *entry, void *privdata) { struct in_addr src_ip = { .s_addr = entry->src_ip }; - char *proto; + char query[256]; - switch (entry->protonum) { - case IPPROTO_TCP: - proto = "tcp "; - break; - - case IPPROTO_UDP: - proto = "udp "; - break; - - case IPPROTO_ICMP: - proto = "icmp"; - break; - - default: - proto = "unkn"; - break; - } - - log_print(LOG_DEBUG, "%4s %15s:%5d -> %8llu / %8llu (%u)", - proto, inet_ntoa(src_ip), ntohs(entry->dst_port), + int len = snprintf(query, sizeof(query), + "INSERT INTO stats SET srcip='%s', proto='%u', dport='%u', srcbytes='%llu', dstbytes='%llu', count='%u'", + inet_ntoa(src_ip), entry->protonum, ntohs(entry->dst_port), entry->src_bytes, entry->dst_bytes, entry->count); + + if (mysql_real_query(dbh, query, len +1) != 0) + log_print(LOG_WARN, "purge_hash_cb: mysql_real_query(): %s", mysql_error(dbh)); + + log_print(LOG_DEBUG, query); } int database_analyse(void) { - conntrack_dump_hash(purge_hash_cb, NULL); + struct hash_table *hash = conntrack_get_hash(); + + if (mysql_ping(dbh) != 0) { + log_print(LOG_WARN, "database_analyse: mysql_ping(): %s", mysql_error(dbh)); + purge_hash(hash, NULL, NULL); + return 0; + } + + purge_hash(hash, purge_hash_cb, NULL); return 0; } int database_init(void) { + dbh = mysql_init(NULL); + if (dbh == NULL) { + log_print(LOG_ERROR, "database_init: mysql_init(): %s", mysql_error(dbh)); + return -1; + } + + char *hostname = config_get_string("mysql", "hostname", NULL); + char *username = config_get_string("mysql", "username", NULL); + char *password = config_get_string("mysql", "password", NULL); + MYSQL *ret = mysql_real_connect(dbh, hostname, username, password, NULL, 0, NULL, 0); + if (ret != dbh) { + log_print(LOG_ERROR, "database_init: mysql_real_connect(): %s", mysql_error(dbh)); + mysql_close(dbh); + return -1; + } + + char *database = config_get_string("mysql", "database", NULL); + if (mysql_select_db(dbh, database) != 0) { + log_print(LOG_ERROR, "database_init: mysql_select_db(): %s", mysql_error(dbh)); + mysql_close(dbh); + return -1; + } return 0; } int database_close(void) { + mysql_close(dbh); return 0; }