From 9f1b4b2d028129966f7e6f23cec6ac0712c2b1b6 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sun, 20 May 2007 21:13:06 +0000 Subject: - introduce cache_iterate - empty debug_ct function if DEBUG_CT is not set - revisit overrun handler: this is a hard battle, just try to do our best here, call Patrick :) - explicit warning message when netlink_buffer_max_growth is reached - fix silly bug in stats-mode when dumping in XML format - fix UDP handler for conntrack --- src/cache.c | 9 ++++++ src/cache_iterators.c | 6 ++-- src/netlink.c | 73 ++++++------------------------------------- src/run.c | 11 +------ src/stats-mode.c | 48 +++++++++++++++++++++++++++-- src/sync-mode.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 150 insertions(+), 82 deletions(-) (limited to 'src') 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 + * (C) 2006-2007 by Pablo Neira Ayuso * * 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 + * (C) 2006-2007 by Pablo Neira Ayuso * * 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) -- cgit v1.2.3