/*************************************************************************** * Copyright (C) 07/2007 by Olaf Rempel * * razzor@kopf-tisch.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License * * * * 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. * ***************************************************************************/ #include #include #include #include #include #include #include #include #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->flags = ct->status & (IPS_EXPECTED || IPS_SEEN_REPLY || IPS_ASSURED || IPS_CONFIRMED); 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; }