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 --- extensions/libct_proto_udp.c | 54 +++++++++++++++++----------- include/cache.h | 1 + include/conntrackd.h | 4 +-- include/debug.h | 4 +++ 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 ++++++++++++++++++++++++++++++++++++++++++-- 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 #include +#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 + * (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