summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extensions/libct_proto_udp.c54
-rw-r--r--include/cache.h1
-rw-r--r--include/conntrackd.h4
-rw-r--r--include/debug.h4
-rw-r--r--src/cache.c9
-rw-r--r--src/cache_iterators.c6
-rw-r--r--src/netlink.c73
-rw-r--r--src/run.c11
-rw-r--r--src/stats-mode.c48
-rw-r--r--src/sync-mode.c85
10 files changed, 190 insertions, 105 deletions
diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c
index 6e8d13c..bae9bf8 100644
--- a/extensions/libct_proto_udp.c
+++ b/extensions/libct_proto_udp.c
@@ -43,12 +43,10 @@ static void help()
static int parse_options(char c, char *argv[],
struct nf_conntrack *ct,
- struct nfct_tuple *exptuple,
- struct nfct_tuple *mask,
+ struct nf_conntrack *exptuple,
+ struct nf_conntrack *mask,
unsigned int *flags)
{
- int i;
-
switch(c) {
case '1':
if (!optarg)
@@ -91,28 +89,44 @@ static int parse_options(char c, char *argv[],
*flags |= UDP_REPL_DPORT;
break;
case '5':
- if (optarg) {
- mask->l4src.udp.port = htons(atoi(optarg));
- *flags |= UDP_MASK_SPORT;
- }
+ if (!optarg)
+ break;
+
+ nfct_set_attr_u16(mask,
+ ATTR_ORIG_PORT_SRC,
+ htons(atoi(optarg)));
+
+ *flags |= UDP_MASK_SPORT;
break;
case '6':
- if (optarg) {
- mask->l4dst.udp.port = htons(atoi(optarg));
- *flags |= UDP_MASK_DPORT;
- }
+ if (!optarg)
+ break;
+
+ nfct_set_attr_u16(mask,
+ ATTR_ORIG_PORT_DST,
+ htons(atoi(optarg)));
+
+ *flags |= UDP_MASK_DPORT;
break;
case '7':
- if (optarg) {
- exptuple->l4src.udp.port = htons(atoi(optarg));
- *flags |= UDP_EXPTUPLE_SPORT;
- }
+ if (!optarg)
+ break;
+
+ nfct_set_attr_u16(exptuple,
+ ATTR_ORIG_PORT_SRC,
+ htons(atoi(optarg)));
+
+ *flags |= UDP_EXPTUPLE_SPORT;
break;
case '8':
- if (optarg) {
- exptuple->l4dst.udp.port = htons(atoi(optarg));
- *flags |= UDP_EXPTUPLE_DPORT;
- }
+ if (!optarg)
+ break;
+
+ nfct_set_attr_u16(exptuple,
+ ATTR_ORIG_PORT_DST,
+ htons(atoi(optarg)));
+
+ *flags |= UDP_EXPTUPLE_DPORT;
break;
}
return 1;
diff --git a/include/cache.h b/include/cache.h
index 7d9559a..e755dbe 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -82,6 +82,7 @@ int cache_test(struct cache *c, struct nf_conntrack *ct);
void cache_stats(struct cache *c, int fd);
struct us_conntrack *cache_get_conntrack(struct cache *, void *);
void *cache_get_extra(struct cache *, void *);
+void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2));
/* iterators */
void cache_dump(struct cache *c, int fd, int type);
diff --git a/include/conntrackd.h b/include/conntrackd.h
index a5f7a3a..76b9747 100644
--- a/include/conntrackd.h
+++ b/include/conntrackd.h
@@ -102,11 +102,9 @@ struct ct_general_state {
struct ignore_pool *ignore_pool;
struct nfnl_handle *event; /* event handler */
- struct nfnl_handle *sync; /* sync handler */
struct nfnl_handle *dump; /* dump handler */
struct nfnl_subsys_handle *subsys_event; /* events */
- struct nfnl_subsys_handle *subsys_sync; /* resync */
struct nfnl_subsys_handle *subsys_dump; /* dump */
/* statistics */
@@ -159,7 +157,7 @@ struct ct_mode {
int (*local)(int fd, int type, void *data);
void (*kill)(void);
void (*dump)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
- void (*overrun)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
+ void (*overrun)(void);
void (*event_new)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
void (*event_upd)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
int (*event_dst)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
diff --git a/include/debug.h b/include/debug.h
index 67f2c71..4d1f44f 100644
--- a/include/debug.h
+++ b/include/debug.h
@@ -11,8 +11,11 @@
#include <netinet/in.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#undef DEBUG_CT
+
static inline void debug_ct(struct nf_conntrack *ct, char *msg)
{
+#ifdef DEBUG_CT
struct in_addr addr, addr2, addr3, addr4;
debug("----%s (%p) ----\n", msg, ct);
@@ -48,6 +51,7 @@ static inline void debug_ct(struct nf_conntrack *ct, char *msg)
inet_ntoa(addr4),
ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)));
debug("-------------------------\n");
+#endif
}
#endif
diff --git a/src/cache.c b/src/cache.c
index 32caee5..1b130c8 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -445,3 +445,12 @@ void cache_stats(struct cache *c, int fd)
unlock();
send(fd, buf, size, 0);
}
+
+void cache_iterate(struct cache *c,
+ void *data,
+ int (*iterate)(void *data1, void *data2))
+{
+ lock();
+ hashtable_iterate(c->h, data, iterate);
+ unlock();
+}
diff --git a/src/cache_iterators.c b/src/cache_iterators.c
index e1f3798..1c03fef 100644
--- a/src/cache_iterators.c
+++ b/src/cache_iterators.c
@@ -111,7 +111,7 @@ static int do_commit(void *data1, void *data2)
*/
nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout));
- ret = nfct_build_query(STATE(subsys_sync),
+ ret = nfct_build_query(STATE(subsys_dump),
NFCT_Q_CREATE,
ct,
nlh,
@@ -125,7 +125,7 @@ static int do_commit(void *data1, void *data2)
return 0;
}
- ret = nfnl_query(STATE(sync), nlh);
+ ret = nfnl_query(STATE(dump), nlh);
if (ret == -1) {
switch(errno) {
case EEXIST:
@@ -211,7 +211,7 @@ static int do_bulk(void *data1, void *data2)
struct nlnetwork *net = (struct nlnetwork *) buf;
ret = build_network_msg(NFCT_Q_UPDATE,
- STATE(subsys_sync),
+ STATE(subsys_dump),
u->ct,
buf,
sizeof(buf));
diff --git a/src/netlink.c b/src/netlink.c
index 0bde632..94200b9 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -207,66 +207,6 @@ int nl_init_dump_handler(void)
return 0;
}
-static int nl_overrun_handler(struct nlmsghdr *nlh,
- struct nfattr *nfa[],
- void *data)
-{
- char buf[1024];
- struct nf_conntrack *ct = (struct nf_conntrack *) buf;
- int type;
-
- memset(buf, 0, sizeof(buf));
-
- if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR)
- return NFCT_CB_CONTINUE;
-
- /*
- * Ignore this conntrack: it talks about a
- * connection that is not interesting for us.
- */
- if (ignore_conntrack(ct))
- return NFCT_CB_CONTINUE;
-
- switch(type) {
- case NFCT_T_UPDATE:
- if (STATE(mode)->overrun)
- STATE(mode)->overrun(ct, nlh);
- break;
- default:
- dlog(STATE(log), "received unknown msg from ctnetlink");
- break;
- }
- return NFCT_CB_CONTINUE;
-}
-
-int nl_init_overrun_handler(void)
-{
- struct nfnl_callback cb_sync = {
- .call = nl_overrun_handler,
- .attr_count = CTA_MAX
- };
-
- /* open sync netlink socket */
- STATE(sync) = nfnl_open();
- if (!STATE(sync))
- return -1;
-
- /* open synchronizer subsystem */
- STATE(subsys_sync) = nfnl_subsys_open(STATE(sync),
- NFNL_SUBSYS_CTNETLINK,
- IPCTNL_MSG_MAX,
- 0);
- if (STATE(subsys_sync) == NULL)
- return -1;
-
- /* register callback for dumped entries */
- nfnl_callback_register(STATE(subsys_sync),
- IPCTNL_MSG_CT_NEW,
- &cb_sync);
-
- return 0;
-}
-
static int warned = 0;
void nl_resize_socket_buffer(struct nfnl_handle *h)
@@ -278,7 +218,14 @@ void nl_resize_socket_buffer(struct nfnl_handle *h)
return;
if (s > CONFIG(netlink_buffer_size_max_grown)) {
- dlog(STATE(log), "maximum netlink socket buffer size reached");
+ dlog(STATE(log), "WARNING: maximum netlink socket buffer "
+ "size has been reached. We are likely to "
+ "be losing events, this may lead to "
+ "unsynchronized replicas. Please, consider "
+ "increasing netlink socket buffer size via "
+ "SocketBufferSize and "
+ "SocketBufferSizeMaxGrown clauses in "
+ "conntrackd.conf");
s = CONFIG(netlink_buffer_size_max_grown);
warned = 1;
}
@@ -313,13 +260,13 @@ int nl_flush_master_conntrack_table(void)
struct nfnlhdr req;
memset(&req, 0, sizeof(req));
- nfct_build_query(STATE(subsys_sync),
+ nfct_build_query(STATE(subsys_dump),
NFCT_Q_FLUSH,
&CONFIG(family),
&req,
sizeof(req));
- if (nfnl_query(STATE(sync), &req.nlh) == -1)
+ if (nfnl_query(STATE(dump), &req.nlh) == -1)
return -1;
return 0;
diff --git a/src/run.c b/src/run.c
index 67437d8..b7dc543 100644
--- a/src/run.c
+++ b/src/run.c
@@ -32,10 +32,8 @@ void killer(int foo)
nfnl_subsys_close(STATE(subsys_event));
nfnl_subsys_close(STATE(subsys_dump));
- nfnl_subsys_close(STATE(subsys_sync));
nfnl_close(STATE(event));
nfnl_close(STATE(dump));
- nfnl_close(STATE(sync));
ignore_pool_destroy(STATE(ignore_pool));
local_server_destroy(STATE(local));
@@ -120,12 +118,6 @@ int init(int mode)
return -1;
}
- if (nl_init_overrun_handler() == -1) {
- dlog(STATE(log), "[FAIL] can't open netlink handler! "
- "no ctnetlink kernel support?");
- return -1;
- }
-
/* Signals handling */
sigemptyset(&STATE(block));
sigaddset(&STATE(block), SIGTERM);
@@ -196,8 +188,7 @@ static void __run(void)
* size and resync with master conntrack table.
*/
nl_resize_socket_buffer(STATE(event));
- nl_dump_conntrack_table(STATE(sync),
- STATE(subsys_sync));
+ STATE(mode)->overrun();
break;
case ENOENT:
/*
diff --git a/src/stats-mode.c b/src/stats-mode.c
index 9647bbf..581c07d 100644
--- a/src/stats-mode.c
+++ b/src/stats-mode.c
@@ -1,5 +1,5 @@
/*
- * (C) 2006 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2006-2007 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* 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
@@ -65,7 +65,7 @@ static int local_handler_stats(int fd, int type, void *data)
cache_dump(STATE_STATS(cache), fd, NFCT_O_PLAIN);
break;
case DUMP_INT_XML:
- cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML);
+ cache_dump(STATE_STATS(cache), fd, NFCT_O_XML);
break;
case FLUSH_CACHE:
dlog(STATE(log), "[REQ] flushing caches");
@@ -92,6 +92,48 @@ static void dump_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
debug_ct(ct, "resync entry");
}
+static int overrun_cb(enum nf_conntrack_msg_type type,
+ struct nf_conntrack *ct,
+ void *data)
+{
+ /* This is required by kernels < 2.6.20 */
+ nfct_attr_unset(ct, ATTR_TIMEOUT);
+ nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES);
+ nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS);
+ nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES);
+ nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS);
+ nfct_attr_unset(ct, ATTR_USE);
+
+ if (!cache_test(STATE_STATS(cache), ct))
+ if (!cache_update_force(STATE_STATS(cache), ct))
+ debug_ct(ct, "overrun stats resync");
+
+ return NFCT_CB_CONTINUE;
+}
+
+static void overrun_stats()
+{
+ int ret;
+ struct nfct_handle *h;
+ int family = CONFIG(family);
+
+ h = nfct_open(CONNTRACK, 0);
+ if (!h) {
+ dlog(STATE(log), "can't open overrun handler");
+ return;
+ }
+
+ nfct_callback_register(h, NFCT_T_ALL, overrun_cb, NULL);
+
+ cache_flush(STATE_STATS(cache));
+
+ ret = nfct_query(h, NFCT_Q_DUMP, &family);
+ if (ret == -1)
+ dlog(STATE(log), "overrun query error %s", strerror(errno));
+
+ nfct_close(h);
+}
+
static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
{
debug_ct(ct, "debug event");
@@ -144,7 +186,7 @@ struct ct_mode stats_mode = {
.local = local_handler_stats,
.kill = kill_stats,
.dump = dump_stats,
- .overrun = dump_stats,
+ .overrun = overrun_stats,
.event_new = event_new_stats,
.event_upd = event_update_stats,
.event_dst = event_destroy_stats
diff --git a/src/sync-mode.c b/src/sync-mode.c
index 0a195d7..65a3c5b 100644
--- a/src/sync-mode.c
+++ b/src/sync-mode.c
@@ -1,5 +1,5 @@
/*
- * (C) 2006 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2006-2007 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* 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
@@ -293,7 +293,9 @@ static void mcast_send_sync(struct nlmsghdr *nlh,
STATE_SYNC(mcast_sync)->post_send(type, net, u);
}
-static void overrun_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+static int overrun_cb(enum nf_conntrack_msg_type type,
+ struct nf_conntrack *ct,
+ void *data)
{
struct us_conntrack *u;
@@ -307,10 +309,87 @@ static void overrun_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
if (!cache_test(STATE_SYNC(internal), ct)) {
if ((u = cache_update_force(STATE_SYNC(internal), ct))) {
- debug_ct(ct, "overrun resync");
+ int ret;
+ char buf[4096];
+ struct nlnetwork *net = (struct nlnetwork *) buf;
+ unsigned int size = sizeof(struct nlnetwork);
+ struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size);
+
+ debug_ct(u->ct, "overrun resync");
+
+ ret = build_network_msg(NFCT_Q_UPDATE,
+ STATE(subsys_dump),
+ u->ct,
+ buf,
+ sizeof(buf));
+
+ if (ret == -1) {
+ dlog(STATE(log), "can't build overrun");
+ return NFCT_CB_CONTINUE;
+ }
+
mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE);
}
}
+
+ return NFCT_CB_CONTINUE;
+}
+
+static int overrun_purge_step(void *data1, void *data2)
+{
+ int ret;
+ struct nfct_handle *h = data1;
+ struct us_conntrack *u = data2;
+
+ ret = nfct_query(h, NFCT_Q_GET, u->ct);
+ if (ret == -1 && errno == ENOENT) {
+ char buf[4096];
+ struct nlnetwork *net = (struct nlnetwork *) buf;
+ unsigned int size = sizeof(struct nlnetwork);
+ struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size);
+
+ debug_ct(u->ct, "overrun purge resync");
+
+ ret = build_network_msg(NFCT_Q_DESTROY,
+ STATE(subsys_dump),
+ u->ct,
+ buf,
+ sizeof(buf));
+
+ if (ret == -1)
+ dlog(STATE(log), "failed to build network message");
+
+ mcast_send_sync(nlh, NULL, u->ct, NFCT_T_DESTROY);
+ __cache_del(STATE_SYNC(internal), u->ct);
+ }
+
+ return 0;
+}
+
+/* it's likely that we're losing events, just try to do our best here */
+static void overrun_sync()
+{
+ int ret;
+ struct nfct_handle *h;
+ int family = CONFIG(family);
+
+ h = nfct_open(CONNTRACK, 0);
+ if (!h) {
+ dlog(STATE(log), "can't open overrun handler");
+ return;
+ }
+
+ nfct_callback_register(h, NFCT_T_ALL, overrun_cb, NULL);
+
+ ret = nfct_query(h, NFCT_Q_DUMP, &family);
+ if (ret == -1)
+ dlog(STATE(log), "overrun query error %s", strerror(errno));
+
+ nfct_callback_unregister(h);
+
+ cache_iterate(STATE_SYNC(internal), h, overrun_purge_step);
+
+ nfct_close(h);
}
static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)