ctstats/conntrack.c

128 lines
2.9 KiB
C

#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
#include "configfile.h"
#include "logging.h"
#include "hashtable.h"
#define DEFAULT_HASHSIZE 127
#define DEFAULT_NETMASK "255.255.255.255"
static pthread_t ct_thread;
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)
{
struct nfct_conntrack *ct = (struct nfct_conntrack *)arg;
if (ct->tuple[NFCT_DIR_ORIGINAL].l3protonum != AF_INET)
return 0;
struct hash_entry *entry = malloc(sizeof(struct hash_entry));
if (entry == NULL) {
log_print(LOG_WARN, "conntrack_event_cb: out of memory");
return -1;
}
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;
entry->src_bytes = ct->counters[NFCT_DIR_ORIGINAL].bytes;
entry->dst_bytes = ct->counters[NFCT_DIR_REPLY].bytes;
hash_add(table[hash_select], entry);
return 0;
}
struct hash_table * conntrack_get_hash(void)
{
/*
* switch hashtable
* -> conntrack_event_cb will use the empty hash next time, and we dump now the full one
* -> if conntrack_event_cb is running *now* (on the full hash), we have to wait a bit
* -> but since we are faster than dump intervall, conntrack_event_cb never waits
*/
int used_hash = hash_select;
hash_select ^= 0x01;
return table[used_hash];
}
int conntrack_init(void)
{
const 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()");
return -1;
}
int size = config_get_int("global", "hashsize", DEFAULT_HASHSIZE);
table[0] = create_hash(size);
if (table[0] == NULL) {
log_print(LOG_ERROR, "conntrack_init: create_hash(0)");
nfct_close(cth);
return -1;
}
table[1] = create_hash(size);
if (table[1] == NULL) {
log_print(LOG_ERROR, "conntrack_init: create_hash(1)");
destroy_hash(table[0]);
nfct_close(cth);
return -1;
}
nfct_register_callback(cth, conntrack_event_cb, NULL);
return 0;
}
static int event_thread(void *arg)
{
nfct_event_conntrack(cth);
return 0;
}
int conntrack_start_event_thread(void)
{
/* startup conntrack event listener */
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 65536);
pthread_create(&ct_thread, &attr, (void *)&event_thread, NULL);
return 0;
}
int conntrack_close(void)
{
if (ct_thread)
pthread_cancel(ct_thread);
destroy_hash(table[1]);
destroy_hash(table[0]);
nfct_close(cth);
return 0;
}