From 5eb3bc6d5594fccfff26329a26225f999e971652 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 16 Apr 2007 19:08:42 +0000 Subject: first step forward to merge conntrackd and conntrack into the same building chain --- include/network.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 include/network.h (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h new file mode 100644 index 0000000..dab50db --- /dev/null +++ b/include/network.h @@ -0,0 +1,34 @@ +#ifndef _NETWORK_H_ +#define _NETWORK_H_ + +#include + +struct nlnetwork { + u_int16_t flags; + u_int16_t checksum; + u_int32_t seq; +}; + +struct nlnetwork_ack { + u_int16_t flags; + u_int16_t checksum; + u_int32_t seq; + u_int32_t from; + u_int32_t to; +}; + +enum { + NET_HELLO_BIT = 0, + NET_HELLO = (1 << NET_HELLO_BIT), + + NET_RESYNC_BIT = 1, + NET_RESYNC = (1 << NET_RESYNC_BIT), + + NET_NACK_BIT = 2, + NET_NACK = (1 << NET_NACK_BIT), + + NET_ACK_BIT = 3, + NET_ACK = (1 << NET_ACK_BIT), +}; + +#endif -- cgit v1.2.3 From bc91f60fc288fe1fd0729f7bafe0596837c3e675 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 24 May 2007 11:32:53 +0000 Subject: simplify checksum code: use UDP/multicast checksum facilities --- ChangeLog | 8 +++++++- include/mcast.h | 1 + include/network.h | 1 - src/Makefile.am | 2 +- src/checksum.c | 32 -------------------------------- src/mcast.c | 8 ++++++++ src/network.c | 33 --------------------------------- src/read_config_yy.y | 3 ++- 8 files changed, 19 insertions(+), 69 deletions(-) delete mode 100644 src/checksum.c (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index 370308c..9a90e3d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,10 @@ -version 0.9.3 (yet unreleased) +version 0.9.4 (yet unreleased) +------------------------------ + += conntrackd = +o simplify checksum code: use UDP/multicast checksum facilities + +version 0.9.3 (2006/05/22) ------------------------------ = conntrackd = diff --git a/include/mcast.h b/include/mcast.h index 0f3e3cd..be1d0cd 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -7,6 +7,7 @@ struct mcast_conf { int ipproto; int backlog; int reuseaddr; + int checksum; unsigned short port; union { struct in_addr inet_addr; diff --git a/include/network.h b/include/network.h index dab50db..176274e 100644 --- a/include/network.h +++ b/include/network.h @@ -5,7 +5,6 @@ struct nlnetwork { u_int16_t flags; - u_int16_t checksum; u_int32_t seq; }; diff --git a/src/Makefile.am b/src/Makefile.am index 381f8ac..a67e09a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,7 +16,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ cache_lifetime.c cache_timer.c \ sync-mode.c sync-notrack.c sync-nack.c \ traffic_stats.c stats-mode.c \ - network.c checksum.c \ + network.c \ state_helper.c state_helper_tcp.c \ read_config_yy.y read_config_lex.l diff --git a/src/checksum.c b/src/checksum.c deleted file mode 100644 index 41866ff..0000000 --- a/src/checksum.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Extracted from RFC 1071 with some minor changes to fix compilation on GCC, - * this can probably be improved - * --pablo 11/feb/07 - */ - -#include - -unsigned short do_csum(const void *addr, unsigned int count) -{ - unsigned int sum = 0; - - /* checksumming disabled, just skip */ - if (CONFIG(flags) & DONT_CHECKSUM) - return 0; - - while(count > 1) { - /* This is the inner loop */ - sum += *((unsigned short *) addr++); - count -= 2; - } - - /* Add left-over byte, if any */ - if(count > 0) - sum += *((unsigned char *) addr); - - /* Fold 32-bit sum to 16 bits */ - while (sum>>16) - sum = (sum & 0xffff) + (sum >> 16); - - return ~sum; -} diff --git a/src/mcast.c b/src/mcast.c index 9904544..85992fb 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -192,6 +192,14 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) return NULL; } + if (setsockopt(m->fd, SOL_SOCKET, SO_NO_CHECK, &conf->checksum, + sizeof(int)) == -1) { + debug("mcast_sock_client_create:setsockopt1"); + close(m->fd); + free(m); + return NULL; + } + switch(conf->ipproto) { case AF_INET: ret = __mcast_client_create_ipv4(m, conf); diff --git a/src/network.c b/src/network.c index 51e89c7..d073428 100644 --- a/src/network.c +++ b/src/network.c @@ -60,9 +60,6 @@ int mcast_send_netmsg(struct mcast_sock *m, void *data) if (nlh_host2network(nlh) == -1) return -1; - net->checksum = 0; - net->checksum = ntohs(do_csum(data, len)); - return send_netmsg(m, data, len); } @@ -87,8 +84,6 @@ int mcast_resend_netmsg(struct mcast_sock *m, void *data) net->flags = htons(net->flags); net->seq = htonl(cur_seq++); - net->checksum = 0; - net->checksum = ntohs(do_csum(data, len)); return send_netmsg(m, data, len); } @@ -113,29 +108,10 @@ int mcast_send_error(struct mcast_sock *m, void *data) net->flags = htons(net->flags); net->seq = htonl(cur_seq++); - net->checksum = 0; - net->checksum = ntohs(do_csum(data, len)); return send_netmsg(m, data, len); } -static int valid_checksum(void *data, unsigned int len) -{ - struct nlnetwork *net = data; - unsigned short checksum, tmp; - - checksum = ntohs(net->checksum); - - /* no checksum, skip */ - if (!checksum) - return 1; - - net->checksum = 0; - tmp = do_csum(data, len); - - return tmp == checksum; -} - int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) { int ret; @@ -161,9 +137,6 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) if (ret < sizeof(struct nlnetwork_ack)) return -1; - if (!valid_checksum(data, ret)) - return -1; - /* host byte order conversion */ net->flags = ntohs(net->flags); net->seq = ntohl(net->seq); @@ -176,9 +149,6 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) } if (ntohs(net->flags) & NET_RESYNC) { - if (!valid_checksum(data, ret)) - return -1; - /* host byte order conversion */ net->flags = ntohs(net->flags); net->seq = ntohl(net->seq); @@ -209,9 +179,6 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) if (nfhdr->version != NFNETLINK_V0) return -1; - if (!valid_checksum(data, ret)) - return -1; - /* host byte order conversion */ net->flags = ntohs(net->flags); net->seq = ntohl(net->seq); diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 1668919..988b540 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -104,11 +104,12 @@ timeout: T_TIMEOUT T_NUMBER checksum: T_CHECKSUM T_ON { + conf.mcast.checksum = 0; }; checksum: T_CHECKSUM T_OFF { - conf.flags |= DONT_CHECKSUM; + conf.mcast.checksum = 1; }; ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}'; -- cgit v1.2.3 From cea33148e4ccf108f587e5796c026600aba35ab1 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 4 Jun 2007 15:19:42 +0000 Subject: o remove useless backlog parameter in multicast sockets o remove reminiscents of delay destroy message and relax transitions o remove confusing StripNAT parameter: NAT support enabled by default o relax event tracking: *_update callbacks use cache_update_force o use wraparound-aware functions after/before/between o lots of cleanups --- ChangeLog | 6 ++ configure.in | 2 +- examples/sync/nack/node1/conntrackd.conf | 6 -- examples/sync/nack/node2/conntrackd.conf | 6 -- examples/sync/persistent/node1/conntrackd.conf | 6 -- examples/sync/persistent/node2/conntrackd.conf | 6 -- include/conntrackd.h | 17 +--- include/mcast.h | 1 - include/network.h | 19 +++++ include/sync.h | 8 +- src/cache_iterators.c | 3 +- src/netlink.c | 6 +- src/network.c | 27 ++----- src/read_config_yy.y | 12 ++- src/stats-mode.c | 20 +---- src/sync-mode.c | 104 +++++++++++-------------- src/sync-nack.c | 27 ++++--- src/sync-notrack.c | 44 +++-------- 18 files changed, 122 insertions(+), 198 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index 396d3a4..05348e1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,12 @@ version 0.9.4 (yet unreleased) o simplify checksum code: use UDP/multicast checksum facilities o fix silly bug in build_network_message: out of bound memset o fix error message in configure.in (Eric Leblond) +o remove useless backlog parameter in multicast sockets +o remove reminiscents of delay destroy message and relax transitions +o remove confusing StripNAT parameter: NAT support enabled by default +o relax event tracking: *_update callbacks use cache_update_force +o use wraparound-aware functions after/before/between +o lots of cleanups = conntrack = o fix segfault with conntrack --output (Krzysztof Oledzky) diff --git a/configure.in b/configure.in index 7a1445d..37e7a9c 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(conntrack-tools, 0.9.3, pablo@netfilter.org) +AC_INIT(conntrack-tools, 0.9.4, pablo@netfilter.org) AC_CANONICAL_SYSTEM diff --git a/examples/sync/nack/node1/conntrackd.conf b/examples/sync/nack/node1/conntrackd.conf index f24fa7e..edec9cf 100644 --- a/examples/sync/nack/node1/conntrackd.conf +++ b/examples/sync/nack/node1/conntrackd.conf @@ -33,7 +33,6 @@ Sync { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.100 # IP of dedicated link Group 3780 - Backlog 20 } # Enable/Disable message checksumming @@ -118,8 +117,3 @@ IgnoreProtocol { VRRP # numeric numbers also valid } - -# -# Strip NAT traffic -# -StripNAT diff --git a/examples/sync/nack/node2/conntrackd.conf b/examples/sync/nack/node2/conntrackd.conf index 4f15773..de5f4d2 100644 --- a/examples/sync/nack/node2/conntrackd.conf +++ b/examples/sync/nack/node2/conntrackd.conf @@ -32,7 +32,6 @@ Sync { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.200 # IP of dedicated link Group 3780 - Backlog 20 } # Enable/Disable message checksumming @@ -117,8 +116,3 @@ IgnoreProtocol { VRRP # numeric numbers also valid } - -# -# Strip NAT traffic -# -StripNAT diff --git a/examples/sync/persistent/node1/conntrackd.conf b/examples/sync/persistent/node1/conntrackd.conf index 90afeb7..60f264b 100644 --- a/examples/sync/persistent/node1/conntrackd.conf +++ b/examples/sync/persistent/node1/conntrackd.conf @@ -38,7 +38,6 @@ Sync { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.100 # IP of dedicated link Group 3780 - Backlog 20 } # Enable/Disable message checksumming @@ -123,8 +122,3 @@ IgnoreProtocol { VRRP # numeric numbers also valid } - -# -# Strip NAT traffic -# -StripNAT diff --git a/examples/sync/persistent/node2/conntrackd.conf b/examples/sync/persistent/node2/conntrackd.conf index aee4a29..6a1806b 100644 --- a/examples/sync/persistent/node2/conntrackd.conf +++ b/examples/sync/persistent/node2/conntrackd.conf @@ -38,7 +38,6 @@ Sync { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.200 # IP of dedicated link Group 3780 - Backlog 20 } # Enable/Disable message checksumming @@ -123,8 +122,3 @@ IgnoreProtocol { VRRP # numeric numbers also valid } - -# -# Strip NAT traffic -# -StripNAT diff --git a/include/conntrackd.h b/include/conntrackd.h index 76b9747..a620400 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -30,22 +30,13 @@ #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" enum { - STRIP_NAT_BIT = 0, - STRIP_NAT = (1 << STRIP_NAT_BIT), - - DELAY_DESTROY_MSG_BIT = 1, - DELAY_DESTROY_MSG = (1 << DELAY_DESTROY_MSG_BIT), - - RELAX_TRANSITIONS_BIT = 2, - RELAX_TRANSITIONS = (1 << RELAX_TRANSITIONS_BIT), - - SYNC_MODE_PERSISTENT_BIT = 3, + SYNC_MODE_PERSISTENT_BIT = 0, SYNC_MODE_PERSISTENT = (1 << SYNC_MODE_PERSISTENT_BIT), - SYNC_MODE_NACK_BIT = 4, + SYNC_MODE_NACK_BIT = 1, SYNC_MODE_NACK = (1 << SYNC_MODE_NACK_BIT), - DONT_CHECKSUM_BIT = 5, + DONT_CHECKSUM_BIT = 2, DONT_CHECKSUM = (1 << DONT_CHECKSUM_BIT), }; @@ -122,7 +113,7 @@ struct ct_sync_state { struct mcast_sock *mcast_server; /* multicast socket: incoming */ struct mcast_sock *mcast_client; /* multicast socket: outgoing */ - struct sync_mode *mcast_sync; + struct sync_mode *sync; /* sync mode */ struct buffer *buffer; u_int32_t last_seq_sent; /* last sequence number sent */ diff --git a/include/mcast.h b/include/mcast.h index be1d0cd..66676dc 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -5,7 +5,6 @@ struct mcast_conf { int ipproto; - int backlog; int reuseaddr; int checksum; unsigned short port; diff --git a/include/network.h b/include/network.h index 176274e..5ba808a 100644 --- a/include/network.h +++ b/include/network.h @@ -30,4 +30,23 @@ enum { NET_ACK = (1 << NET_ACK_BIT), }; +/* extracted from net/tcp.h */ + +/* + * The next routines deal with comparing 32 bit unsigned ints + * and worry about wraparound (automatic with unsigned arithmetic). + */ + +static inline int before(__u32 seq1, __u32 seq2) +{ + return (__s32)(seq1-seq2) < 0; +} +#define after(seq2, seq1) before(seq1, seq2) + +/* is s2<=s1<=s3 ? */ +static inline int between(__u32 seq1, __u32 seq2, __u32 seq3) +{ + return seq3 - seq2 >= seq1 - seq2; +} + #endif diff --git a/include/sync.h b/include/sync.h index d8f1bca..72f6313 100644 --- a/include/sync.h +++ b/include/sync.h @@ -13,10 +13,10 @@ struct sync_mode { int (*init)(void); void (*kill)(void); int (*local)(int fd, int type, void *data); - int (*pre_recv)(const struct nlnetwork *net); - void (*post_send)(int type, - const struct nlnetwork *net, - struct us_conntrack *u); + int (*recv)(const struct nlnetwork *net); /* recv callback */ + void (*send)(int type, /* send callback */ + const struct nlnetwork *net, + struct us_conntrack *u); }; extern struct sync_mode notrack; diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 1c03fef..fd6694a 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -219,7 +219,8 @@ static int do_bulk(void *data1, void *data2) debug_ct(u->ct, "failed to build"); mcast_send_netmsg(STATE_SYNC(mcast_client), net); - STATE_SYNC(mcast_sync)->post_send(NFCT_T_UPDATE, net, u); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(NFCT_T_UPDATE, net, u); /* keep iterating even if we have found errors */ return 0; diff --git a/src/netlink.c b/src/netlink.c index b1f9fd7..5f7cbeb 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -32,15 +32,13 @@ int ignore_conntrack(struct nf_conntrack *ct) return 1; /* Accept DNAT'ed traffic: not really coming to the local machine */ - if ((CONFIG(flags) & STRIP_NAT) && - nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { debug_ct(ct, "DNAT"); return 0; } /* Accept SNAT'ed traffic: not really coming to the local machine */ - if ((CONFIG(flags) & STRIP_NAT) && - nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { debug_ct(ct, "SNAT"); return 0; } diff --git a/src/network.c b/src/network.c index abd30fe..a7ce740 100644 --- a/src/network.c +++ b/src/network.c @@ -205,33 +205,16 @@ int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq) goto out; /* out of sequence: some messages got lost */ - if (seq > STATE_SYNC(last_seq_recv)+1) { + if (after(seq, STATE_SYNC(last_seq_recv)+1)) { STATE_SYNC(packets_lost) += seq-STATE_SYNC(last_seq_recv)+1; ret = 0; goto out; } - /* out of sequence: replayed or sequence wrapped around issues */ - if (seq < STATE_SYNC(last_seq_recv)+1) { - /* - * Check if the sequence has wrapped around. - * Perhaps it can be a replayed packet. - */ - if (STATE_SYNC(last_seq_recv)+1-seq > ~0U/2) { - /* - * Indeed, it is a wrapped around - */ - STATE_SYNC(packets_lost) += - ~0U-STATE_SYNC(last_seq_recv)+1+seq; - } else { - /* - * It is a delayed packet - */ - dlog(STATE(log), "delayed packet? exp=%u rcv=%u", - STATE_SYNC(last_seq_recv)+1, seq); - } - ret = 0; - } + /* out of sequence: replayed/delayed packet? */ + if (before(seq, STATE_SYNC(last_seq_recv)+1)) + dlog(STATE(log), "delayed packet? exp=%u rcv=%u", + STATE_SYNC(last_seq_recv)+1, seq); out: *exp_seq = STATE_SYNC(last_seq_recv)+1; diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 988b540..57250b4 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -84,7 +84,8 @@ lock : T_LOCK T_PATH_VAL strip_nat: T_STRIP_NAT { - conf.flags |= STRIP_NAT; + fprintf(stderr, "Notice: StripNAT clause is obsolete. " + "Please, remove it from conntrackd.conf\n"); }; refreshtime : T_REFRESH T_NUMBER @@ -228,7 +229,8 @@ multicast_option : T_IPV6_IFACE T_IP multicast_option : T_BACKLOG T_NUMBER { - conf.mcast.backlog = $2; + fprintf(stderr, "Notice: Backlog option inside Multicast clause is " + "obsolete. Please, remove it from conntrackd.conf.\n"); }; multicast_option : T_GROUP T_NUMBER @@ -354,12 +356,14 @@ window_size: T_WINDOWSIZE T_NUMBER relax_transitions: T_RELAX_TRANSITIONS { - conf.flags |= RELAX_TRANSITIONS; + fprintf(stderr, "Notice: RelaxTransitions clause is obsolete. " + "Please, remove it from conntrackd.conf\n"); }; delay_destroy_msgs: T_DELAY { - conf.flags |= DELAY_DESTROY_MSG; + fprintf(stderr, "Notice: DelayDestroyMessages clause is obsolete. " + "Please, remove it from conntrackd.conf\n"); }; listen_to: T_LISTEN_TO T_IP diff --git a/src/stats-mode.c b/src/stats-mode.c index 22474e2..f65fbdb 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -139,7 +139,6 @@ static void overrun_stats() static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) { - debug_ct(ct, "debug event"); if (cache_add(STATE_STATS(cache), ct)) { debug_ct(ct, "cache new"); } else { @@ -151,22 +150,9 @@ static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) { - debug_ct(ct, "update"); - - if (!cache_update(STATE_STATS(cache), ct)) { - /* - * Perhaps we are losing events. If we are working - * in relax mode then add a new entry to the cache. - * - * FIXME: relax transitions not implemented yet - */ - if ((CONFIG(flags) & RELAX_TRANSITIONS) - && cache_add(STATE_STATS(cache), ct)) { - debug_ct(ct, "forcing cache update"); - } else { - debug_ct(ct, "can't update"); - return; - } + if (!cache_update_force(STATE_STATS(cache), ct)) { + debug_ct(ct, "can't update"); + return; } debug_ct(ct, "update"); } diff --git a/src/sync-mode.c b/src/sync-mode.c index d7bee9d..cb95392 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -32,26 +32,25 @@ static void mcast_handler() { int ret; - char buf[4096], tmp[256]; - struct mcast_sock *m = STATE_SYNC(mcast_server); - unsigned int type; - struct nlnetwork *net = (struct nlnetwork *) buf; - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); - struct nf_conntrack *ct = (struct nf_conntrack *) tmp; + unsigned int type, size = sizeof(struct nlnetwork); + char __net[4096]; + struct nlnetwork *net = (struct nlnetwork *) __net; + struct nlmsghdr *nlh = (struct nlmsghdr *) (__net + size); + char __ct[nfct_maxsize()]; + struct nf_conntrack *ct = (struct nf_conntrack *) __ct; struct us_conntrack *u = NULL; - memset(tmp, 0, sizeof(tmp)); - - ret = mcast_recv_netmsg(m, buf, sizeof(buf)); + ret = mcast_recv_netmsg(STATE_SYNC(mcast_server), net, sizeof(__net)); if (ret <= 0) { STATE(malformed)++; return; } - if (STATE_SYNC(mcast_sync)->pre_recv(net)) + if (STATE_SYNC(sync)->recv(net)) return; + memset(ct, 0, sizeof(__ct)); + if ((type = parse_network_msg(ct, nlh)) == NFCT_T_ERROR) { STATE(malformed)++; return; @@ -111,19 +110,19 @@ static int init_sync(void) memset(state.sync, 0, sizeof(struct ct_sync_state)); if (CONFIG(flags) & SYNC_MODE_NACK) - STATE_SYNC(mcast_sync) = &nack; + STATE_SYNC(sync) = &nack; else /* default to persistent mode */ - STATE_SYNC(mcast_sync) = ¬rack; + STATE_SYNC(sync) = ¬rack; - if (STATE_SYNC(mcast_sync)->init) - STATE_SYNC(mcast_sync)->init(); + if (STATE_SYNC(sync)->init) + STATE_SYNC(sync)->init(); STATE_SYNC(internal) = cache_create("internal", - STATE_SYNC(mcast_sync)->internal_cache_flags, + STATE_SYNC(sync)->internal_cache_flags, CONFIG(family), - STATE_SYNC(mcast_sync)->internal_cache_extra); + STATE_SYNC(sync)->internal_cache_extra); if (!STATE_SYNC(internal)) { dlog(STATE(log), "[FAIL] can't allocate memory for " @@ -133,7 +132,7 @@ static int init_sync(void) STATE_SYNC(external) = cache_create("external", - STATE_SYNC(mcast_sync)->external_cache_flags, + STATE_SYNC(sync)->external_cache_flags, CONFIG(family), NULL); @@ -192,8 +191,8 @@ static void kill_sync() destroy_alarm_thread(); - if (STATE_SYNC(mcast_sync)->kill) - STATE_SYNC(mcast_sync)->kill(); + if (STATE_SYNC(sync)->kill) + STATE_SYNC(sync)->kill(); } static dump_stats_sync(int fd) @@ -253,8 +252,8 @@ static int local_handler_sync(int fd, int type, void *data) cache_bulk(STATE_SYNC(internal)); break; default: - if (STATE_SYNC(mcast_sync)->local) - ret = STATE_SYNC(mcast_sync)->local(fd, type, data); + if (STATE_SYNC(sync)->local) + ret = STATE_SYNC(sync)->local(fd, type, data); break; } @@ -280,17 +279,18 @@ static void mcast_send_sync(struct nlmsghdr *nlh, struct nf_conntrack *ct, int type) { - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; + char __net[4096]; + struct nlnetwork *net = (struct nlnetwork *) __net; - memset(buf, 0, sizeof(buf)); + memset(__net, 0, sizeof(__net)); if (!state_helper_verdict(type, ct)) return; - memcpy(buf + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); - mcast_send_netmsg(STATE_SYNC(mcast_client), net); - STATE_SYNC(mcast_sync)->post_send(type, net, u); + memcpy(__net + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); + mcast_send_netmsg(STATE_SYNC(mcast_client), net); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(type, net, u); } static int overrun_cb(enum nf_conntrack_msg_type type, @@ -313,18 +313,16 @@ static int overrun_cb(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { int ret; - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); + char __nlh[4096]; + struct nlmsghdr *nlh = (struct nlmsghdr *) __nlh; debug_ct(u->ct, "overrun resync"); - ret = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_dump), - u->ct, - buf, - sizeof(buf)); + ret = nfct_build_query(STATE(subsys_dump), + NFCT_Q_UPDATE, + u->ct, + __nlh, + sizeof(__nlh)); if (ret == -1) { dlog(STATE(log), "can't build overrun"); @@ -346,18 +344,16 @@ static int overrun_purge_step(void *data1, void *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); + char __nlh[4096]; + struct nlmsghdr *nlh = (struct nlmsghdr *) (__nlh); debug_ct(u->ct, "overrun purge resync"); - - ret = build_network_msg(NFCT_Q_DESTROY, - STATE(subsys_dump), - u->ct, - buf, - sizeof(buf)); + + ret = nfct_build_query(STATE(subsys_dump), + NFCT_Q_DESTROY, + u->ct, + __nlh, + sizeof(__nlh)); if (ret == -1) dlog(STATE(log), "failed to build network message"); @@ -411,18 +407,6 @@ retry: debug_ct(u->ct, "internal new"); } else { if (errno == EEXIST) { - char buf[4096]; - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); - - int ret = build_network_msg(NFCT_Q_DESTROY, - STATE(subsys_event), - ct, - buf, - sizeof(buf)); - if (ret == -1) - return; - cache_del(STATE_SYNC(internal), ct); mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); goto retry; @@ -440,7 +424,7 @@ static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) nfct_attr_unset(ct, ATTR_TIMEOUT); - if ((u = cache_update(STATE_SYNC(internal), ct)) == NULL) { + if ((u = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { debug_ct(ct, "can't update"); return; } diff --git a/src/sync-nack.c b/src/sync-nack.c index 73f6dc2..e435b09 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -136,7 +136,7 @@ static int buffer_compare(void *data1, void *data2) unsigned old_seq = ntohl(net->seq); - if (ntohl(net->seq) >= nack->from && ntohl(net->seq) <= nack->to) { + if (between(ntohl(net->seq), nack->from, nack->to)) { if (mcast_resend_netmsg(STATE_SYNC(mcast_client), net)) dp("resend destroy (old seq=%u) (seq=%u)\n", old_seq, ntohl(net->seq)); @@ -149,7 +149,7 @@ static int buffer_remove(void *data1, void *data2) struct nlnetwork *net = data1; struct nlnetwork_ack *h = data2; - if (ntohl(net->seq) >= h->from && ntohl(net->seq) <= h->to) { + if (between(ntohl(net->seq), h->from, h->to)) { dp("remove from buffer (seq=%u)\n", ntohl(net->seq)); __buffer_del(STATE_SYNC(buffer), data1); } @@ -169,7 +169,7 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (cn->seq >= from && cn->seq <= to) { + if (between(cn->seq, from, to)) { debug_ct(u->ct, "resend nack"); dp("resending nack'ed (oldseq=%u) ", cn->seq); @@ -186,10 +186,9 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) break; } - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - STATE_SYNC(mcast_sync)->post_send(NFCT_T_UPDATE, - net, - u); + mcast_send_netmsg(STATE_SYNC(mcast_client), buf); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(NFCT_T_UPDATE, net, u); dp("(newseq=%u)\n", *seq); } } @@ -208,7 +207,7 @@ static void queue_empty(struct cache *c, unsigned int from, unsigned int to) struct cache_nack *cn = (struct cache_nack *) n; u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (cn->seq >= from && cn->seq <= to) { + if (between(cn->seq, from, to)) { dp("remove %u\n", cn->seq); debug_ct(u->ct, "ack received: empty queue"); dp("queue: deleting from queue (seq=%u)\n", cn->seq); @@ -219,7 +218,7 @@ static void queue_empty(struct cache *c, unsigned int from, unsigned int to) unlock(); } -static int nack_pre_recv(const struct nlnetwork *net) +static int nack_recv(const struct nlnetwork *net) { static unsigned int window = 0; unsigned int exp_seq; @@ -262,9 +261,9 @@ static int nack_pre_recv(const struct nlnetwork *net) return 0; } -static void nack_post_send(int type, - const struct nlnetwork *net, - struct us_conntrack *u) +static void nack_send(int type, + const struct nlnetwork *net, + struct us_conntrack *u) { unsigned int size = sizeof(struct nlnetwork); struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); @@ -301,6 +300,6 @@ struct sync_mode nack = { .init = nack_init, .kill = nack_kill, .local = nack_local, - .pre_recv = nack_pre_recv, - .post_send = nack_post_send, + .recv = nack_recv, + .send = nack_send, }; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index cc56436..4a470f9 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -25,33 +25,18 @@ static void refresher(struct alarm_list *a, void *data) { struct us_conntrack *u = data; - char buf[8192]; + char __net[4096]; int size; - if (nfct_get_attr_u32(u->ct, ATTR_STATUS) & IPS_DYING) { - - debug_ct(u->ct, "persistence destroy"); + debug_ct(u->ct, "persistence update"); - size = build_network_msg(NFCT_Q_DESTROY, - STATE(subsys_event), - u->ct, - buf, - sizeof(buf)); - - __cache_del(u->cache, u->ct); - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - } else { - - debug_ct(u->ct, "persistence update"); - - a->expires = random() % CONFIG(refresh) + 1; - size = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_event), - u->ct, - buf, - sizeof(buf)); - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - } + a->expires = random() % CONFIG(refresh) + 1; + size = build_network_msg(NFCT_Q_UPDATE, + STATE(subsys_event), + u->ct, + __net, + sizeof(__net)); + mcast_send_netmsg(STATE_SYNC(mcast_client), __net); } static void cache_notrack_add(struct us_conntrack *u, void *data) @@ -84,7 +69,7 @@ static struct cache_extra cache_notrack_extra = { .destroy = cache_notrack_destroy }; -static int notrack_pre_recv(const struct nlnetwork *net) +static int notrack_recv(const struct nlnetwork *net) { unsigned int exp_seq; @@ -114,16 +99,9 @@ static int notrack_pre_recv(const struct nlnetwork *net) return 0; } -static void notrack_post_send(int type, - const struct nlnetwork *n, - struct us_conntrack *u) -{ -} - struct sync_mode notrack = { .internal_cache_flags = LIFETIME, .external_cache_flags = TIMER | LIFETIME, .internal_cache_extra = &cache_notrack_extra, - .pre_recv = notrack_pre_recv, - .post_send = notrack_post_send, + .recv = notrack_recv, }; -- cgit v1.2.3 From e6f0851b184123ebf04df45e2f29a59f0cb827eb Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 13 Jun 2007 19:46:11 +0000 Subject: - local requests return EXIT_FAILURE if it can't connect to the daemon - several cleanups --- ChangeLog | 1 + include/network.h | 5 +++-- src/main.c | 4 +++- src/network.c | 46 ++++++++++++---------------------------------- src/sync-nack.c | 40 ++++++++++------------------------------ 5 files changed, 29 insertions(+), 67 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index 86a9a46..f1ae81f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,7 @@ o remove confusing StripNAT parameter: NAT support enabled by default o relax event tracking: *_update callbacks use cache_update_force o use wraparound-aware functions after/before/between o commit phase: if conntrack exists, update it +o local requests return EXIT_FAILURE if it can't connect to the daemon o lots of cleanups = conntrack = diff --git a/include/network.h b/include/network.h index 5ba808a..243815a 100644 --- a/include/network.h +++ b/include/network.h @@ -4,13 +4,14 @@ #include struct nlnetwork { - u_int16_t flags; + u_int16_t flags; + u_int16_t padding; u_int32_t seq; }; struct nlnetwork_ack { u_int16_t flags; - u_int16_t checksum; + u_int16_t padding; u_int32_t seq; u_int32_t from; u_int32_t to; diff --git a/src/main.c b/src/main.c index 1c75970..a039793 100644 --- a/src/main.c +++ b/src/main.c @@ -252,9 +252,11 @@ int main(int argc, char *argv[]) } if (type == REQUEST) { - if (do_local_request(action, &conf.local, local_step) == -1) + if (do_local_request(action, &conf.local, local_step) == -1) { fprintf(stderr, "can't connect: is conntrackd " "running? appropiate permissions?\n"); + exit(EXIT_FAILURE); + } exit(EXIT_SUCCESS); } diff --git a/src/network.c b/src/network.c index a7ce740..37f437e 100644 --- a/src/network.c +++ b/src/network.c @@ -19,20 +19,25 @@ #include "conntrackd.h" #include "network.h" -#if 0 -#define _TEST_DROP -#else -#undef _TEST_DROP -#endif - -static int drop = 0; /* debugging purposes */ static unsigned int seq_set, cur_seq; static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) { struct nlnetwork *net = data; + if (!seq_set) { + seq_set = 1; + cur_seq = time(NULL); + net->flags |= NET_HELLO; + } + + net->flags = htons(net->flags); + net->seq = htonl(cur_seq++); + +#undef _TEST_DROP #ifdef _TEST_DROP + static int drop = 0; + if (++drop > 10) { drop = 0; printf("dropping resend (seq=%u)\n", ntohl(net->seq)); @@ -48,15 +53,6 @@ int mcast_send_netmsg(struct mcast_sock *m, void *data) unsigned int len = nlh->nlmsg_len + sizeof(struct nlnetwork); struct nlnetwork *net = data; - if (!seq_set) { - seq_set = 1; - cur_seq = time(NULL); - net->flags |= NET_HELLO; - } - - net->flags = htons(net->flags); - net->seq = htonl(cur_seq++); - if (nlh_host2network(nlh) == -1) return -1; @@ -71,20 +67,11 @@ int mcast_resend_netmsg(struct mcast_sock *m, void *data) net->flags = ntohs(net->flags); - if (!seq_set) { - seq_set = 1; - cur_seq = time(NULL); - net->flags |= NET_HELLO; - } - if (net->flags & NET_NACK || net->flags & NET_ACK) len = sizeof(struct nlnetwork_ack); else len = sizeof(struct nlnetwork) + ntohl(nlh->nlmsg_len); - net->flags = htons(net->flags); - net->seq = htonl(cur_seq++); - return send_netmsg(m, data, len); } @@ -93,12 +80,6 @@ int mcast_send_error(struct mcast_sock *m, void *data) struct nlnetwork *net = data; unsigned int len = sizeof(struct nlnetwork); - if (!seq_set) { - seq_set = 1; - cur_seq = time(NULL); - net->flags |= NET_HELLO; - } - if (net->flags & NET_NACK || net->flags & NET_ACK) { struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; nack->from = htonl(nack->from); @@ -106,9 +87,6 @@ int mcast_send_error(struct mcast_sock *m, void *data) len = sizeof(struct nlnetwork_ack); } - net->flags = htons(net->flags); - net->seq = htonl(cur_seq++); - return send_netmsg(m, data, len); } diff --git a/src/sync-nack.c b/src/sync-nack.c index e435b09..1f62294 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -77,47 +77,25 @@ static void nack_kill() buffer_destroy(STATE_SYNC(buffer)); } -static void mcast_send_nack(u_int32_t expt_seq, u_int32_t recv_seq) -{ - struct nlnetwork_ack nack = { - .flags = NET_NACK, - .from = expt_seq, - .to = recv_seq, - }; - - mcast_send_error(STATE_SYNC(mcast_client), &nack); - buffer_add(STATE_SYNC(buffer), &nack, sizeof(struct nlnetwork_ack)); -} - -static void mcast_send_ack(u_int32_t from, u_int32_t to) +static void mcast_send_control(u_int32_t flags, u_int32_t from, u_int32_t to) { struct nlnetwork_ack ack = { - .flags = NET_ACK, - .from = from, - .to = to, + .flags = flags, + .from = from, + .to = to, }; mcast_send_error(STATE_SYNC(mcast_client), &ack); buffer_add(STATE_SYNC(buffer), &ack, sizeof(struct nlnetwork_ack)); } -static void mcast_send_resync() -{ - struct nlnetwork net = { - .flags = NET_RESYNC, - }; - - mcast_send_error(STATE_SYNC(mcast_client), &net); - buffer_add(STATE_SYNC(buffer), &net, sizeof(struct nlnetwork)); -} - -int nack_local(int fd, int type, void *data) +static int nack_local(int fd, int type, void *data) { int ret = 1; switch(type) { case REQUEST_DUMP: - mcast_send_resync(); + mcast_send_control(NET_RESYNC, 0, 0); dlog(STATE(log), "[REQ] request resync"); break; default: @@ -228,13 +206,15 @@ static int nack_recv(const struct nlnetwork *net) if (!mcast_track_seq(net->seq, &exp_seq)) { dp("OOS: sending nack (seq=%u)\n", exp_seq); - mcast_send_nack(exp_seq, net->seq - 1); + mcast_send_control(NET_NACK, exp_seq, net->seq - 1); window = CONFIG(window_size); } else { /* received a window, send an acknowledgement */ if (--window == 0) { dp("sending ack (seq=%u)\n", net->seq); - mcast_send_ack(net->seq-CONFIG(window_size), net->seq); + mcast_send_control(NET_ACK, + net->seq - CONFIG(window_size), + net->seq); } } -- cgit v1.2.3 From 3f3a6701978df8ca16ebb5988eb7a46771deb964 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 19 Jun 2007 17:00:44 +0000 Subject: - more cleanups and code refactorization - remove several debug calls - create a child to dispatch dump requests: this will help to simplify the current locking schema. Later. --- ChangeLog | 2 ++ include/network.h | 22 +++++++------ include/sync.h | 6 ++-- src/cache.c | 1 - src/cache_iterators.c | 22 ++----------- src/ignore_pool.c | 1 - src/local.c | 19 +++-------- src/network.c | 89 ++++++++++++++++++++++++++++++++++++--------------- src/run.c | 13 ++++++-- src/stats-mode.c | 8 +++-- src/sync-mode.c | 69 ++++++++++++++++----------------------- src/sync-nack.c | 63 +++++++++++++----------------------- src/sync-notrack.c | 13 ++------ 13 files changed, 156 insertions(+), 172 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index f1ae81f..aa93d4c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,8 @@ o relax event tracking: *_update callbacks use cache_update_force o use wraparound-aware functions after/before/between o commit phase: if conntrack exists, update it o local requests return EXIT_FAILURE if it can't connect to the daemon +o remove several debug statements +o fork when internal/external dump cache requests are received o lots of cleanups = conntrack = diff --git a/include/network.h b/include/network.h index 243815a..31903a5 100644 --- a/include/network.h +++ b/include/network.h @@ -3,32 +3,34 @@ #include -struct nlnetwork { +struct nethdr { u_int16_t flags; u_int16_t padding; u_int32_t seq; }; +#define NETHDR_SIZ sizeof(struct nethdr) -struct nlnetwork_ack { +struct nethdr_ack { u_int16_t flags; u_int16_t padding; u_int32_t seq; u_int32_t from; u_int32_t to; }; +#define NETHDR_ACK_SIZ sizeof(struct nethdr_ack) enum { - NET_HELLO_BIT = 0, - NET_HELLO = (1 << NET_HELLO_BIT), + NET_F_HELLO_BIT = 0, + NET_F_HELLO = (1 << NET_F_HELLO_BIT), - NET_RESYNC_BIT = 1, - NET_RESYNC = (1 << NET_RESYNC_BIT), + NET_F_RESYNC_BIT = 1, + NET_F_RESYNC = (1 << NET_F_RESYNC_BIT), - NET_NACK_BIT = 2, - NET_NACK = (1 << NET_NACK_BIT), + NET_F_NACK_BIT = 2, + NET_F_NACK = (1 << NET_F_NACK_BIT), - NET_ACK_BIT = 3, - NET_ACK = (1 << NET_ACK_BIT), + NET_F_ACK_BIT = 3, + NET_F_ACK = (1 << NET_F_ACK_BIT), }; /* extracted from net/tcp.h */ diff --git a/include/sync.h b/include/sync.h index 72f6313..a737e81 100644 --- a/include/sync.h +++ b/include/sync.h @@ -1,7 +1,7 @@ #ifndef _SYNC_HOOKS_H_ #define _SYNC_HOOKS_H_ -struct nlnetwork; +struct nethdr; struct us_conntrack; struct sync_mode { @@ -13,9 +13,9 @@ struct sync_mode { int (*init)(void); void (*kill)(void); int (*local)(int fd, int type, void *data); - int (*recv)(const struct nlnetwork *net); /* recv callback */ + int (*recv)(const struct nethdr *net); /* recv callback */ void (*send)(int type, /* send callback */ - const struct nlnetwork *net, + const struct nethdr *net, struct us_conntrack *u); }; diff --git a/src/cache.c b/src/cache.c index 1b130c8..3bf331c 100644 --- a/src/cache.c +++ b/src/cache.c @@ -23,7 +23,6 @@ #include #include "us-conntrack.h" #include "cache.h" -#include "debug.h" static u_int32_t hash(const void *data, struct hashtable *table) { diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 279ddab..7ae25fa 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -23,7 +23,6 @@ #include #include #include "us-conntrack.h" -#include "debug.h" struct __dump_container { int fd; @@ -120,8 +119,7 @@ static int do_commit(void *data1, void *data2) free(ct); if (ret == -1) { - /* XXX: Please cleanup this debug crap, default in logfile */ - debug("--- failed to build: %s --- \n", strerror(errno)); + dlog(STATE(log), "failed to build: %s", strerror(errno)); return 0; } @@ -135,10 +133,8 @@ static int do_commit(void *data1, void *data2) c->commit_fail++; break; } - debug("--- failed to commit: %s --- \n", strerror(errno)); } else { c->commit_ok++; - debug("----- commit -----\n"); } /* keep iterating even if we have found errors */ @@ -207,20 +203,8 @@ static int do_bulk(void *data1, void *data2) { int ret; struct us_conntrack *u = data2; - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - - ret = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_dump), - u->ct, - buf, - sizeof(buf)); - if (ret == -1) - debug_ct(u->ct, "failed to build"); - - mcast_send_netmsg(STATE_SYNC(mcast_client), net); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(NFCT_T_UPDATE, net, u); + + mcast_build_send_update(u); /* keep iterating even if we have found errors */ return 0; diff --git a/src/ignore_pool.c b/src/ignore_pool.c index 5946617..d6f0e93 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -20,7 +20,6 @@ #include "hash.h" #include "conntrackd.h" #include "ignore.h" -#include "debug.h" #include #define IGNORE_POOL_SIZE 32 diff --git a/src/local.c b/src/local.c index eef70ad..be51b9e 100644 --- a/src/local.c +++ b/src/local.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 @@ -22,7 +22,6 @@ #include #include #include -#include "debug.h" #include "local.h" @@ -32,14 +31,11 @@ int local_server_create(struct local_conf *conf) int len; struct sockaddr_un local; - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - debug("local_server_create:socket"); + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) return -1; - } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &conf->reuseaddr, sizeof(conf->reuseaddr)) == -1) { - debug("local_server_create:setsockopt"); close(fd); return -1; } @@ -50,14 +46,12 @@ int local_server_create(struct local_conf *conf) unlink(conf->path); if (bind(fd, (struct sockaddr *) &local, len) == -1) { - debug("local_server_create:bind"); close(fd); return -1; } if (listen(fd, conf->backlog) == -1) { close(fd); - debug("local_server_create:listen"); return -1; } @@ -76,10 +70,8 @@ int do_local_server_step(int fd, void *data, struct sockaddr_un local; size_t sin_size = sizeof(struct sockaddr_un); - if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) { - debug("do_local_server_step:accept"); + if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) return -1; - } process(rfd, data); close(rfd); @@ -102,7 +94,6 @@ int local_client_create(struct local_conf *conf) if (connect(fd, (struct sockaddr *) &local, len) == -1) { close(fd); - debug("local_client_create: connect: "); return -1; } @@ -146,10 +137,8 @@ int do_local_request(int request, return -1; ret = send(fd, &request, sizeof(int), 0); - if (ret == -1) { - debug("send:"); + if (ret == -1) return -1; - } do_local_client_step(fd, step); diff --git a/src/network.c b/src/network.c index 37f437e..159bdf3 100644 --- a/src/network.c +++ b/src/network.c @@ -23,12 +23,12 @@ static unsigned int seq_set, cur_seq; static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) { - struct nlnetwork *net = data; + struct nethdr *net = data; if (!seq_set) { seq_set = 1; cur_seq = time(NULL); - net->flags |= NET_HELLO; + net->flags |= NET_F_HELLO; } net->flags = htons(net->flags); @@ -49,9 +49,9 @@ static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) int mcast_send_netmsg(struct mcast_sock *m, void *data) { - struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); - unsigned int len = nlh->nlmsg_len + sizeof(struct nlnetwork); - struct nlnetwork *net = data; + struct nlmsghdr *nlh = data + NETHDR_SIZ; + unsigned int len = nlh->nlmsg_len + NETHDR_SIZ; + struct nethdr *net = data; if (nlh_host2network(nlh) == -1) return -1; @@ -61,40 +61,77 @@ int mcast_send_netmsg(struct mcast_sock *m, void *data) int mcast_resend_netmsg(struct mcast_sock *m, void *data) { - struct nlnetwork *net = data; - struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); + struct nethdr *net = data; + struct nlmsghdr *nlh = data + NETHDR_SIZ; unsigned int len; net->flags = ntohs(net->flags); - if (net->flags & NET_NACK || net->flags & NET_ACK) - len = sizeof(struct nlnetwork_ack); + if (net->flags & NET_F_NACK || net->flags & NET_F_ACK) + len = NETHDR_ACK_SIZ; else - len = sizeof(struct nlnetwork) + ntohl(nlh->nlmsg_len); + len = ntohl(nlh->nlmsg_len) + NETHDR_SIZ; return send_netmsg(m, data, len); } int mcast_send_error(struct mcast_sock *m, void *data) { - struct nlnetwork *net = data; - unsigned int len = sizeof(struct nlnetwork); + struct nethdr *net = data; + unsigned int len = NETHDR_SIZ; - if (net->flags & NET_NACK || net->flags & NET_ACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + if (net->flags & NET_F_NACK || net->flags & NET_F_ACK) { + struct nethdr_ack *nack = (struct nethdr_ack *) net; nack->from = htonl(nack->from); nack->to = htonl(nack->to); - len = sizeof(struct nlnetwork_ack); + len = NETHDR_ACK_SIZ; } return send_netmsg(m, data, len); } +#include "us-conntrack.h" +#include "sync.h" + +static int __build_send(struct us_conntrack *u, int type, int query) +{ + char __net[4096]; + struct nethdr *net = (struct nethdr *) __net; + + if (!state_helper_verdict(type, u->ct)) + return 0; + + int ret = build_network_msg(query, + STATE(subsys_event), + u->ct, + __net, + sizeof(__net)); + + if (ret == -1) + return -1; + + mcast_send_netmsg(STATE_SYNC(mcast_client), __net); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(type, net, u); + + return 0; +} + +int mcast_build_send_update(struct us_conntrack *u) +{ + return __build_send(u, NFCT_T_UPDATE, NFCT_Q_UPDATE); +} + +int mcast_build_send_destroy(struct us_conntrack *u) +{ + return __build_send(u, NFCT_T_DESTROY, NFCT_Q_DESTROY); +} + int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) { int ret; - struct nlnetwork *net = data; - struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); + struct nethdr *net = data; + struct nlmsghdr *nlh = data + NETHDR_SIZ; struct nfgenmsg *nfhdr; ret = mcast_recv(m, net, len); @@ -102,17 +139,17 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) return ret; /* message too small: no room for the header */ - if (ret < sizeof(struct nlnetwork)) + if (ret < NETHDR_SIZ) return -1; - if (ntohs(net->flags) & NET_HELLO) + if (ntohs(net->flags) & NET_F_HELLO) STATE_SYNC(last_seq_recv) = ntohl(net->seq) - 1; - if (ntohs(net->flags) & NET_NACK || ntohs(net->flags) & NET_ACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + if (ntohs(net->flags) & NET_F_NACK || ntohs(net->flags) & NET_F_ACK) { + struct nethdr_ack *nack = (struct nethdr_ack *) net; /* message too small: no room for the header */ - if (ret < sizeof(struct nlnetwork_ack)) + if (ret < NETHDR_ACK_SIZ) return -1; /* host byte order conversion */ @@ -126,7 +163,7 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) return ret; } - if (ntohs(net->flags) & NET_RESYNC) { + if (ntohs(net->flags) & NET_F_RESYNC) { /* host byte order conversion */ net->flags = ntohs(net->flags); net->seq = ntohl(net->seq); @@ -139,7 +176,7 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) return -1; /* information received and message length does not match */ - if (ret != ntohl(nlh->nlmsg_len) + sizeof(struct nlnetwork)) + if (ret != ntohl(nlh->nlmsg_len) + NETHDR_SIZ) return -1; /* this message does not come from ctnetlink */ @@ -209,8 +246,8 @@ int build_network_msg(const int msg_type, unsigned int size) { memset(buffer, 0, size); - buffer += sizeof(struct nlnetwork); - size -= sizeof(struct nlnetwork); + buffer += NETHDR_SIZ; + size -= NETHDR_SIZ; return nfct_build_query(ssh, msg_type, ct, buffer, size); } diff --git a/src/run.c b/src/run.c index b7dc543..0173c9f 100644 --- a/src/run.c +++ b/src/run.c @@ -47,6 +47,11 @@ void killer(int foo) exit(0); } +static void child(int foo) +{ + while(wait(NULL) > 0); +} + void local_handler(int fd, void *data) { int ret; @@ -54,11 +59,11 @@ void local_handler(int fd, void *data) ret = read(fd, &type, sizeof(type)); if (ret == -1) { - dlog(STATE(log), "can't read from unix socket\n"); + dlog(STATE(log), "can't read from unix socket"); return; } if (ret == 0) { - debug("nothing to process\n"); + dlog(STATE(log), "local request: nothing to process?"); return; } @@ -122,6 +127,7 @@ int init(int mode) sigemptyset(&STATE(block)); sigaddset(&STATE(block), SIGTERM); sigaddset(&STATE(block), SIGINT); + sigaddset(&STATE(block), SIGCHLD); if (signal(SIGINT, killer) == SIG_ERR) return -1; @@ -133,6 +139,9 @@ int init(int mode) if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) return -1; + if (signal(SIGCHLD, child) == SIG_ERR) + return -1; + dlog(STATE(log), "[OK] initialization completed"); return 0; diff --git a/src/stats-mode.c b/src/stats-mode.c index f65fbdb..92794cd 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -142,9 +142,11 @@ static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) if (cache_add(STATE_STATS(cache), ct)) { debug_ct(ct, "cache new"); } else { - dlog(STATE(log), "can't add to cache cache: " - "%s\n", strerror(errno)); - debug_ct(ct, "can't add"); + if (errno != EEXIST) { + dlog(STATE(log), "can't add to cache cache: " + "%s\n", strerror(errno)); + debug_ct(ct, "can't add"); + } } } diff --git a/src/sync-mode.c b/src/sync-mode.c index cb95392..8433532 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -32,10 +32,10 @@ static void mcast_handler() { int ret; - unsigned int type, size = sizeof(struct nlnetwork); + unsigned int type; char __net[4096]; - struct nlnetwork *net = (struct nlnetwork *) __net; - struct nlmsghdr *nlh = (struct nlmsghdr *) (__net + size); + struct nethdr *net = (struct nethdr *) __net; + struct nlmsghdr *nlh = (struct nlmsghdr *) (__net + NETHDR_SIZ); char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *) __ct; struct us_conntrack *u = NULL; @@ -93,7 +93,7 @@ retry: debug_ct(ct, "can't destroy"); break; default: - debug("unknown type %d\n", type); + dlog(STATE(log), "mcast received unknown msg type %d\n", type); break; } } @@ -216,16 +216,32 @@ static int local_handler_sync(int fd, int type, void *data) switch(type) { case DUMP_INTERNAL: - cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN); + ret = fork(); + if (ret == 0) { + cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN); + exit(EXIT_SUCCESS); + } break; case DUMP_EXTERNAL: - cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN); + ret = fork(); + if (ret == 0) { + cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN); + exit(EXIT_SUCCESS); + } break; case DUMP_INT_XML: - cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); + ret = fork(); + if (ret == 0) { + cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); + exit(EXIT_SUCCESS); + } break; case DUMP_EXT_XML: - cache_dump(STATE_SYNC(external), fd, NFCT_O_XML); + ret = fork(); + if (ret == 0) { + cache_dump(STATE_SYNC(external), fd, NFCT_O_XML); + exit(EXIT_SUCCESS); + } break; case COMMIT: dlog(STATE(log), "[REQ] commit external cache to master table"); @@ -280,14 +296,14 @@ static void mcast_send_sync(struct nlmsghdr *nlh, int type) { char __net[4096]; - struct nlnetwork *net = (struct nlnetwork *) __net; + struct nethdr *net = (struct nethdr *) __net; memset(__net, 0, sizeof(__net)); if (!state_helper_verdict(type, ct)) return; - memcpy(__net + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); + memcpy(__net + NETHDR_SIZ, nlh, nlh->nlmsg_len); mcast_send_netmsg(STATE_SYNC(mcast_client), net); if (STATE_SYNC(sync)->send) STATE_SYNC(sync)->send(type, net, u); @@ -312,24 +328,8 @@ static int overrun_cb(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { - int ret; - char __nlh[4096]; - struct nlmsghdr *nlh = (struct nlmsghdr *) __nlh; - debug_ct(u->ct, "overrun resync"); - - ret = nfct_build_query(STATE(subsys_dump), - NFCT_Q_UPDATE, - u->ct, - __nlh, - sizeof(__nlh)); - - if (ret == -1) { - dlog(STATE(log), "can't build overrun"); - return NFCT_CB_CONTINUE; - } - - mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); + mcast_build_send_update(u); } } @@ -344,21 +344,8 @@ static int overrun_purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { - char __nlh[4096]; - struct nlmsghdr *nlh = (struct nlmsghdr *) (__nlh); - debug_ct(u->ct, "overrun purge resync"); - - ret = nfct_build_query(STATE(subsys_dump), - NFCT_Q_DESTROY, - u->ct, - __nlh, - sizeof(__nlh)); - - if (ret == -1) - dlog(STATE(log), "failed to build network message"); - - mcast_send_sync(nlh, NULL, u->ct, NFCT_T_DESTROY); + mcast_build_send_destroy(u); __cache_del(STATE_SYNC(internal), u->ct); } diff --git a/src/sync-nack.c b/src/sync-nack.c index 1f62294..20ad1f4 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -79,14 +79,14 @@ static void nack_kill() static void mcast_send_control(u_int32_t flags, u_int32_t from, u_int32_t to) { - struct nlnetwork_ack ack = { + struct nethdr_ack ack = { .flags = flags, .from = from, .to = to, }; mcast_send_error(STATE_SYNC(mcast_client), &ack); - buffer_add(STATE_SYNC(buffer), &ack, sizeof(struct nlnetwork_ack)); + buffer_add(STATE_SYNC(buffer), &ack, NETHDR_ACK_SIZ); } static int nack_local(int fd, int type, void *data) @@ -95,7 +95,7 @@ static int nack_local(int fd, int type, void *data) switch(type) { case REQUEST_DUMP: - mcast_send_control(NET_RESYNC, 0, 0); + mcast_send_control(NET_F_RESYNC, 0, 0); dlog(STATE(log), "[REQ] request resync"); break; default: @@ -108,9 +108,9 @@ static int nack_local(int fd, int type, void *data) static int buffer_compare(void *data1, void *data2) { - struct nlnetwork *net = data1; - struct nlnetwork_ack *nack = data2; - struct nlmsghdr *nlh = data1 + sizeof(struct nlnetwork); + struct nethdr *net = data1; + struct nethdr_ack *nack = data2; + struct nlmsghdr *nlh = data1 + NETHDR_SIZ; unsigned old_seq = ntohl(net->seq); @@ -124,8 +124,8 @@ static int buffer_compare(void *data1, void *data2) static int buffer_remove(void *data1, void *data2) { - struct nlnetwork *net = data1; - struct nlnetwork_ack *h = data2; + struct nethdr *net = data1; + struct nethdr_ack *h = data2; if (between(ntohl(net->seq), h->from, h->to)) { dp("remove from buffer (seq=%u)\n", ntohl(net->seq)); @@ -138,9 +138,7 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) { struct list_head *n; struct us_conntrack *u; - unsigned int *seq; - lock(); list_for_each(n, &queue) { struct cache_nack *cn = (struct cache_nack *) n; struct us_conntrack *u; @@ -151,35 +149,19 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) debug_ct(u->ct, "resend nack"); dp("resending nack'ed (oldseq=%u) ", cn->seq); - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - - int ret = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_event), - u->ct, - buf, - sizeof(buf)); - if (ret == -1) { - unlock(); - break; - } - - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(NFCT_T_UPDATE, net, u); - dp("(newseq=%u)\n", *seq); + if (mcast_build_send_update(u) == -1) + continue; + + dp("(newseq=%u)\n", cn->seq); } } - unlock(); } static void queue_empty(struct cache *c, unsigned int from, unsigned int to) { struct list_head *n, *tmp; struct us_conntrack *u; - unsigned int *seq; - lock(); dp("ACK from %u to %u\n", from, to); list_for_each_safe(n, tmp, &queue) { struct cache_nack *cn = (struct cache_nack *) n; @@ -193,10 +175,9 @@ static void queue_empty(struct cache *c, unsigned int from, unsigned int to) INIT_LIST_HEAD(&cn->head); } } - unlock(); } -static int nack_recv(const struct nlnetwork *net) +static int nack_recv(const struct nethdr *net) { static unsigned int window = 0; unsigned int exp_seq; @@ -206,31 +187,31 @@ static int nack_recv(const struct nlnetwork *net) if (!mcast_track_seq(net->seq, &exp_seq)) { dp("OOS: sending nack (seq=%u)\n", exp_seq); - mcast_send_control(NET_NACK, exp_seq, net->seq - 1); + mcast_send_control(NET_F_NACK, exp_seq, net->seq - 1); window = CONFIG(window_size); } else { /* received a window, send an acknowledgement */ if (--window == 0) { dp("sending ack (seq=%u)\n", net->seq); - mcast_send_control(NET_ACK, + mcast_send_control(NET_F_ACK, net->seq - CONFIG(window_size), net->seq); } } - if (net->flags & NET_NACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + if (net->flags & NET_F_NACK) { + struct nethdr_ack *nack = (struct nethdr_ack *) net; dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); queue_resend(STATE_SYNC(internal), nack->from, nack->to); buffer_iterate(STATE_SYNC(buffer), nack, buffer_compare); return 1; - } else if (net->flags & NET_RESYNC) { + } else if (net->flags & NET_F_RESYNC) { dp("RESYNC ALL\n"); cache_bulk(STATE_SYNC(internal)); return 1; - } else if (net->flags & NET_ACK) { - struct nlnetwork_ack *h = (struct nlnetwork_ack *) net; + } else if (net->flags & NET_F_ACK) { + struct nethdr_ack *h = (struct nethdr_ack *) net; dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); queue_empty(STATE_SYNC(internal), h->from, h->to); @@ -242,10 +223,10 @@ static int nack_recv(const struct nlnetwork *net) } static void nack_send(int type, - const struct nlnetwork *net, + const struct nethdr *net, struct us_conntrack *u) { - unsigned int size = sizeof(struct nlnetwork); + int size = NETHDR_SIZ; struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); struct cache_nack *cn; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 4a470f9..1d6eba8 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -25,18 +25,11 @@ static void refresher(struct alarm_list *a, void *data) { struct us_conntrack *u = data; - char __net[4096]; - int size; debug_ct(u->ct, "persistence update"); a->expires = random() % CONFIG(refresh) + 1; - size = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_event), - u->ct, - __net, - sizeof(__net)); - mcast_send_netmsg(STATE_SYNC(mcast_client), __net); + mcast_build_send_update(u); } static void cache_notrack_add(struct us_conntrack *u, void *data) @@ -69,7 +62,7 @@ static struct cache_extra cache_notrack_extra = { .destroy = cache_notrack_destroy }; -static int notrack_recv(const struct nlnetwork *net) +static int notrack_recv(const struct nethdr *net) { unsigned int exp_seq; @@ -78,7 +71,7 @@ static int notrack_recv(const struct nlnetwork *net) * generated in notrack mode, we don't want to crash the daemon * if someone nuts mixes nack and notrack. */ - if (net->flags & (NET_RESYNC | NET_NACK)) + if (net->flags) return 1; /* -- cgit v1.2.3 From 96084e1a1f2e0a49c961bbddb9fffd2e03bfae3f Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 9 Jul 2007 19:11:53 +0000 Subject: - conntrack-tools requires libnetfilter_conntrack >= 0.0.81 - add len field to nethdr - implement buffered send/recv to batch messages - stop using netlink format for network messages: use similar TLV-based format - reduce synchronization messages size up to 60% - introduce periodic alive messages for sync-nack protocol - timeslice alarm implementation: remove alarm pthread, remove locking - simplify debugging functions: use nfct_snprintf instead - remove major use of libnfnetlink functions: use libnetfilter_conntrack API - deprecate conntrackd -F, use conntrack -F instead - major rework of the network infrastructure: much simple, less messy --- ChangeLog | 16 ++++ configure.in | 4 +- include/Makefile.am | 2 +- include/buffer.h | 5 +- include/conntrackd.h | 21 ++-- include/debug.h | 56 ++--------- include/network.h | 106 +++++++++++++++++++- include/sync.h | 7 +- include/timer.h | 17 ++++ src/Makefile.am | 7 +- src/alarm.c | 37 ++----- src/buffer.c | 26 ++--- src/build.c | 113 ++++++++++++++++++++++ src/cache.c | 40 +------- src/cache_iterators.c | 54 +---------- src/cache_timer.c | 2 +- src/lock.c | 32 ------- src/main.c | 1 + src/mcast.c | 1 - src/netlink.c | 137 ++++++-------------------- src/network.c | 238 +++++++++++++++++---------------------------- src/parse.c | 76 +++++++++++++++ src/proxy.c | 124 ------------------------ src/run.c | 72 ++++++++++---- src/state_helper.c | 2 +- src/stats-mode.c | 10 +- src/sync-mode.c | 152 +++++++++++++++++------------ src/sync-nack.c | 260 ++++++++++++++++++++++++++++++++++---------------- src/sync-notrack.c | 6 +- src/timer.c | 75 +++++++++++++++ 30 files changed, 909 insertions(+), 790 deletions(-) create mode 100644 include/timer.h create mode 100644 src/build.c create mode 100644 src/parse.c delete mode 100644 src/proxy.c create mode 100644 src/timer.c (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index 0166c97..b65966b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +version 0.9.5 (yet unreleased) +------------------------------ + += conntrackd = +o conntrack-tools requires libnetfilter_conntrack >= 0.0.81 +o add len field to nethdr +o implement buffered send/recv to batch messages +o stop using netlink format for network messages: use similar TLV-based format +o reduce synchronization messages size up to 60% +o introduce periodic alive messages for sync-nack protocol +o timeslice alarm implementation: remove alarm pthread, remove locking +o simplify debugging functions: use nfct_snprintf instead +o remove major use of libnfnetlink functions: use libnetfilter_conntrack API +o deprecate conntrackd -F, use conntrack -F instead +o major rework of the network infrastructure: much simple, less messy + version 0.9.4 (2007/07/02) ------------------------------ diff --git a/configure.in b/configure.in index 41a001c..7e1cd20 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(conntrack-tools, 0.9.4, pablo@netfilter.org) +AC_INIT(conntrack-tools, 0.9.5, pablo@netfilter.org) AC_CANONICAL_SYSTEM @@ -18,7 +18,7 @@ esac dnl Dependencies LIBNFNETLINK_REQUIRED=0.0.25 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.80 +LIBNETFILTER_CONNTRACK_REQUIRED=0.0.81 PKG_CHECK_MODULES(LIBNFNETLINK, libnfnetlink >= $LIBNFNETLINK_REQUIRED,, AC_MSG_ERROR(Cannot find libnfnetlink >= $LIBNFNETLINK_REQUIRED)) diff --git a/include/Makefile.am b/include/Makefile.am index a7716d9..7b6bc14 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,5 +2,5 @@ noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \ sync.h conntrackd.h local.h us-conntrack.h \ debug.h log.h hash.h mcast.h buffer.h conntrack.h \ - state_helper.h network.h ignore.h + state_helper.h network.h ignore.h timer.h diff --git a/include/buffer.h b/include/buffer.h index 8d72dfb..cb42f51 100644 --- a/include/buffer.h +++ b/include/buffer.h @@ -4,13 +4,12 @@ #include #include #include -#include #include "linux_list.h" struct buffer { - pthread_mutex_t lock; size_t max_size; size_t cur_size; + unsigned int num_elems; struct list_head head; }; @@ -22,9 +21,9 @@ struct buffer_node { struct buffer *buffer_create(size_t max_size); void buffer_destroy(struct buffer *b); +unsigned int buffer_len(struct buffer *b); int buffer_add(struct buffer *b, const void *data, size_t size); void buffer_del(struct buffer *b, void *data); -void __buffer_del(struct buffer *b, void *data); void buffer_iterate(struct buffer *b, void *data, int (*iterate)(void *data1, void *data2)); diff --git a/include/conntrackd.h b/include/conntrackd.h index a620400..e89fc79 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -10,6 +10,7 @@ #include "debug.h" #include #include "state_helper.h" +#include "linux_list.h" #include /* UNIX facilities */ @@ -92,11 +93,8 @@ struct ct_general_state { struct ct_mode *mode; struct ignore_pool *ignore_pool; - struct nfnl_handle *event; /* event handler */ - struct nfnl_handle *dump; /* dump handler */ - - struct nfnl_subsys_handle *subsys_event; /* events */ - struct nfnl_subsys_handle *subsys_dump; /* dump */ + struct nfct_handle *event; /* event handler */ + struct nfct_handle *dump; /* dump handler */ /* statistics */ u_int64_t malformed; @@ -114,7 +112,6 @@ struct ct_sync_state { struct mcast_sock *mcast_client; /* multicast socket: outgoing */ struct sync_mode *sync; /* sync mode */ - struct buffer *buffer; u_int32_t last_seq_sent; /* last sequence number sent */ u_int32_t last_seq_recv; /* last sequence number recv */ @@ -141,17 +138,19 @@ extern struct ct_general_state st; #define IPPROTO_VRRP 112 #endif +#define STEPS_PER_SECONDS 5 + struct ct_mode { int (*init)(void); int (*add_fds_to_set)(fd_set *readfds); - void (*step)(fd_set *readfds); + void (*run)(fd_set *readfds, int step); int (*local)(int fd, int type, void *data); void (*kill)(void); - void (*dump)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + void (*dump)(struct nf_conntrack *ct); 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); + void (*event_new)(struct nf_conntrack *ct); + void (*event_upd)(struct nf_conntrack *ct); + int (*event_dst)(struct nf_conntrack *ct); }; /* conntrackd modes */ diff --git a/include/debug.h b/include/debug.h index 4d1f44f..1ffd9ac 100644 --- a/include/debug.h +++ b/include/debug.h @@ -1,57 +1,21 @@ #ifndef _DEBUG_H #define _DEBUG_H -#if 0 -#define debug printf -#else -#define debug -#endif - -#include -#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); - memcpy(&addr, - nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), - sizeof(u_int32_t)); - memcpy(&addr2, - nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), - sizeof(u_int32_t)); - memcpy(&addr3, - nfct_get_attr(ct, ATTR_REPL_IPV4_SRC), - sizeof(u_int32_t)); - memcpy(&addr4, - nfct_get_attr(ct, ATTR_REPL_IPV4_DST), - sizeof(u_int32_t)); - - debug("status: %x\n", nfct_get_attr_u32(ct, ATTR_STATUS)); - debug("l3:%d l4:%d ", - nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO), - nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)); - debug("%s:%hu ->", inet_ntoa(addr), - ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC))); - debug("%s:%hu\n", - inet_ntoa(addr2), - ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST))); - debug("l3:%d l4:%d ", - nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO), - nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO)); - debug("%s:%hu ->", - inet_ntoa(addr3), - ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC))); - debug("%s:%hu\n", - inet_ntoa(addr4), - ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST))); - debug("-------------------------\n"); +#define debug_ct(ct, msg) \ +({ \ + char buf[1024]; \ + nfct_snprintf(buf, 1024, ct, NFCT_T_ALL, 0, 0); \ + printf("[%s]: %s\n", msg, buf); \ +}) +#define debug printf +#else +#define debug_ct(ct, msg) +#define debug #endif -} #endif diff --git a/include/network.h b/include/network.h index 31903a5..bc9431d 100644 --- a/include/network.h +++ b/include/network.h @@ -5,14 +5,17 @@ struct nethdr { u_int16_t flags; - u_int16_t padding; + u_int16_t len; u_int32_t seq; }; #define NETHDR_SIZ sizeof(struct nethdr) +#define NETHDR_DATA(x) \ + (struct netpld *)(((char *)x) + sizeof(struct nethdr)) + struct nethdr_ack { u_int16_t flags; - u_int16_t padding; + u_int16_t len; u_int32_t seq; u_int32_t from; u_int32_t to; @@ -31,8 +34,59 @@ enum { NET_F_ACK_BIT = 3, NET_F_ACK = (1 << NET_F_ACK_BIT), + + NET_F_ALIVE_BIT = 4, + NET_F_ALIVE = (1 << NET_F_ALIVE_BIT), }; +#define BUILD_NETMSG(ct, query) \ +({ \ + char __net[4096]; \ + memset(__net, 0, sizeof(__net)); \ + build_netmsg(ct, query, (struct nethdr *) __net); \ + (struct nethdr *) __net; \ +}) + +struct us_conntrack; +struct mcast_sock; + +void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); +int prepare_send_netmsg(struct mcast_sock *m, void *data); +int mcast_send_netmsg(struct mcast_sock *m, void *data); +int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len); + +#define IS_DATA(x) ((x->flags & ~NET_F_HELLO) == 0) +#define IS_ACK(x) (x->flags & NET_F_ACK) +#define IS_NACK(x) (x->flags & NET_F_NACK) +#define IS_RESYNC(x) (x->flags & NET_F_RESYNC) +#define IS_ALIVE(x) (x->flags & NET_F_ALIVE) +#define IS_CTL(x) IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x) || IS_ALIVE(x) +#define IS_HELLO(x) (x->flags & NET_F_HELLO) + +#define HDR_NETWORK2HOST(x) \ +({ \ + x->flags = ntohs(x->flags); \ + x->len = ntohs(x->len); \ + x->seq = ntohl(x->seq); \ + if (IS_CTL(x)) { \ + struct nethdr_ack *__ack = (struct nethdr_ack *) x; \ + __ack->from = ntohl(__ack->from); \ + __ack->to = ntohl(__ack->to); \ + } \ +}) + +#define HDR_HOST2NETWORK(x) \ +({ \ + if (IS_CTL(x)) { \ + struct nethdr_ack *__ack = (struct nethdr_ack *) x; \ + __ack->from = htonl(__ack->from); \ + __ack->to = htonl(__ack->to); \ + } \ + x->flags = htons(x->flags); \ + x->len = htons(x->len); \ + x->seq = htonl(x->seq); \ +}) + /* extracted from net/tcp.h */ /* @@ -52,4 +106,52 @@ static inline int between(__u32 seq1, __u32 seq2, __u32 seq3) return seq3 - seq2 >= seq1 - seq2; } +struct netpld { + u_int16_t len; + u_int16_t query; +}; +#define NETPLD_SIZ sizeof(struct netpld) + +#define PLD_NETWORK2HOST(x) \ +({ \ + x->len = ntohs(x->len); \ + x->query = ntohs(x->query); \ +}) + +#define PLD_HOST2NETWORK(x) \ +({ \ + x->len = htons(x->len); \ + x->query = htons(x->query); \ +}) + +struct netattr { + u_int16_t nta_len; + u_int16_t nta_attr; +}; + +#define ATTR_NETWORK2HOST(x) \ +({ \ + x->nta_len = ntohs(x->nta_len); \ + x->nta_attr = ntohs(x->nta_attr); \ +}) + +#define PLD_DATA(x) \ + (struct netattr *)(((char *)x) + sizeof(struct netpld)) + +#define PLD_TAIL(x) \ + (struct netattr *)(((char *)x) + sizeof(struct netpld) + x->len) + +#define NTA_DATA(x) \ + (void *)(((char *)x) + sizeof(struct netattr)) + +#define NTA_NEXT(x, len) \ +({ \ + len -= NTA_ALIGN(NTA_LENGTH(x->nta_len)); \ + (struct netattr *)(((char *)x) + NTA_ALIGN(NTA_LENGTH(x->nta_len))); \ +}) + +#define NTA_ALIGNTO 4 +#define NTA_ALIGN(len) (((len) + NTA_ALIGNTO - 1) & ~(NTA_ALIGNTO - 1)) +#define NTA_LENGTH(len) (NTA_ALIGN(sizeof(struct netattr)) + (len)) + #endif diff --git a/include/sync.h b/include/sync.h index a737e81..6345513 100644 --- a/include/sync.h +++ b/include/sync.h @@ -13,10 +13,9 @@ struct sync_mode { int (*init)(void); void (*kill)(void); int (*local)(int fd, int type, void *data); - int (*recv)(const struct nethdr *net); /* recv callback */ - void (*send)(int type, /* send callback */ - const struct nethdr *net, - struct us_conntrack *u); + int (*recv)(const struct nethdr *net); + void (*send)(struct nethdr *net, struct us_conntrack *u); + void (*run)(int step); }; extern struct sync_mode notrack; diff --git a/include/timer.h b/include/timer.h new file mode 100644 index 0000000..37b0fc9 --- /dev/null +++ b/include/timer.h @@ -0,0 +1,17 @@ +#ifndef _TIMER_H_ +#define _TIMER_H_ + +#include + +struct timer { + long credits; + struct timeval start; + struct timeval stop; + struct timeval diff; +}; + +#define GET_CREDITS(x) x.credits +#define GET_STARTTIME(x) x.start +#define GET_STOPTIME(x) x.stop + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 8647d04..d71e23c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,7 @@ conntrack_SOURCES = conntrack.c conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ - local.c log.c mcast.c netlink.c proxy.c lock.c \ + local.c log.c mcast.c netlink.c \ ignore_pool.c \ cache.c cache_iterators.c \ cache_lifetime.c cache_timer.c \ @@ -18,9 +18,10 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ traffic_stats.c stats-mode.c \ network.c \ state_helper.c state_helper_tcp.c \ + timer.c \ + build.c parse.c \ read_config_yy.y read_config_lex.l -conntrackd_LDFLAGS = $(all_libraries) -lnfnetlink -lnetfilter_conntrack \ - -lpthread +conntrackd_LDFLAGS = $(all_libraries) -lnfnetlink -lnetfilter_conntrack EXTRA_DIST = read_config_yy.h diff --git a/src/alarm.c b/src/alarm.c index 1a465c2..b4db167 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -22,17 +22,13 @@ #include "conntrackd.h" #include "alarm.h" #include "jhash.h" -#include #include #include /* alarm cascade */ -#define ALARM_CASCADE_SIZE 10 +#define ALARM_CASCADE_SIZE STEPS_PER_SECONDS static struct list_head *alarm_cascade; -/* thread stuff */ -static pthread_t alarm_thread; - struct alarm_list *create_alarm() { return (struct alarm_list *) malloc(sizeof(struct alarm_list)); @@ -86,24 +82,11 @@ int mod_alarm(struct alarm_list *alarm, unsigned long expires) return 0; } -void __run_alarms() +void do_alarm_run(int step) { struct list_head *i, *tmp; struct alarm_list *t; - struct timespec req = {0, 1000000000 / ALARM_CASCADE_SIZE}; - struct timespec rem; - static int step = 0; - -retry: - if (nanosleep(&req, &rem) == -1) { - /* interrupted syscall: retry with remaining time */ - if (errno == EINTR) { - memcpy(&req, &rem, sizeof(struct timespec)); - goto retry; - } - } - lock(); list_for_each_safe(i, tmp, &alarm_cascade[step]) { t = (struct alarm_list *) i; @@ -111,17 +94,9 @@ retry: if (t->expires == 0) t->function(t, t->data); } - step = (step + 1) < ALARM_CASCADE_SIZE ? step + 1 : 0; - unlock(); -} - -void *run_alarms(void *foo) -{ - while(1) - __run_alarms(); } -int create_alarm_thread() +int init_alarm_scheduler() { int i; @@ -132,10 +107,10 @@ int create_alarm_thread() for (i=0; imax_size = max_size; INIT_LIST_HEAD(&b->head); - pthread_mutex_init(&b->lock, NULL); return b; } @@ -39,14 +38,12 @@ void buffer_destroy(struct buffer *b) struct list_head *i, *tmp; struct buffer_node *node; - pthread_mutex_lock(&b->lock); + /* XXX: set cur_size and num_elems */ list_for_each_safe(i, tmp, &b->head) { node = (struct buffer_node *) i; list_del(i); free(node); } - pthread_mutex_unlock(&b->lock); - pthread_mutex_destroy(&b->lock); free(b); } @@ -70,8 +67,6 @@ int buffer_add(struct buffer *b, const void *data, size_t size) int ret = 0; struct buffer_node *n; - pthread_mutex_lock(&b->lock); - /* does it fit this buffer? */ if (size > b->max_size) { errno = ENOSPC; @@ -97,28 +92,22 @@ retry: list_add(&n->head, &b->head); b->cur_size += size; + b->num_elems++; err: - pthread_mutex_unlock(&b->lock); return ret; } -void __buffer_del(struct buffer *b, void *data) +void buffer_del(struct buffer *b, void *data) { struct buffer_node *n = container_of(data, struct buffer_node, data); list_del(&n->head); b->cur_size -= n->size; + b->num_elems--; free(n); } -void buffer_del(struct buffer *b, void *data) -{ - pthread_mutex_lock(&b->lock); - buffer_del(b, data); - pthread_mutex_unlock(&b->lock); -} - void buffer_iterate(struct buffer *b, void *data, int (*iterate)(void *data1, void *data2)) @@ -126,11 +115,14 @@ void buffer_iterate(struct buffer *b, struct list_head *i, *tmp; struct buffer_node *n; - pthread_mutex_lock(&b->lock); list_for_each_safe(i, tmp, &b->head) { n = (struct buffer_node *) i; if (iterate(n->data, data)) break; } - pthread_mutex_unlock(&b->lock); +} + +unsigned int buffer_len(struct buffer *b) +{ + return b->num_elems; } diff --git a/src/build.c b/src/build.c new file mode 100644 index 0000000..b77dbc2 --- /dev/null +++ b/src/build.c @@ -0,0 +1,113 @@ +/* + * (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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "network.h" + +static void addattr(struct netpld *pld, int attr, const void *data, int len) +{ + struct netattr *nta; + int tlen = NTA_LENGTH(len); + + nta = PLD_TAIL(pld); + nta->nta_attr = htons(attr); + nta->nta_len = htons(len); + memcpy(NTA_DATA(nta), data, len); + pld->len += NTA_ALIGN(tlen); +} + +static void __build_u8(const struct nf_conntrack *ct, + struct netpld *pld, + int attr) +{ + u_int8_t data = nfct_get_attr_u8(ct, attr); + addattr(pld, attr, &data, sizeof(u_int8_t)); +} + +static void __build_u16(const struct nf_conntrack *ct, + struct netpld *pld, + int attr) +{ + u_int16_t data = nfct_get_attr_u16(ct, attr); + data = htons(data); + addattr(pld, attr, &data, sizeof(u_int16_t)); +} + +static void __build_u32(const struct nf_conntrack *ct, + struct netpld *pld, + int attr) +{ + u_int32_t data = nfct_get_attr_u32(ct, attr); + data = htonl(data); + addattr(pld, attr, &data, sizeof(u_int32_t)); +} + +/* XXX: IPv6 and ICMP not supported */ +void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) +{ + /* undo NAT */ + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_SNAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_DNAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_SPAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_DPAT); + + /* build message */ + if (nfct_attr_is_set(ct, ATTR_IPV4_SRC)) + __build_u32(ct, pld, ATTR_IPV4_SRC); + if (nfct_attr_is_set(ct, ATTR_IPV4_DST)) + __build_u32(ct, pld, ATTR_IPV4_DST); + if (nfct_attr_is_set(ct, ATTR_L3PROTO)) + __build_u8(ct, pld, ATTR_L3PROTO); + if (nfct_attr_is_set(ct, ATTR_PORT_SRC)) + __build_u16(ct, pld, ATTR_PORT_SRC); + if (nfct_attr_is_set(ct, ATTR_PORT_DST)) + __build_u16(ct, pld, ATTR_PORT_DST); + if (nfct_attr_is_set(ct, ATTR_L4PROTO)) { + u_int8_t proto; + + __build_u8(ct, pld, ATTR_L4PROTO); + proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); + if (proto == IPPROTO_TCP) { + if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) + __build_u8(ct, pld, ATTR_TCP_STATE); + } + } + if (nfct_attr_is_set(ct, ATTR_SNAT_IPV4)) + __build_u32(ct, pld, ATTR_SNAT_IPV4); + if (nfct_attr_is_set(ct, ATTR_DNAT_IPV4)) + __build_u32(ct, pld, ATTR_DNAT_IPV4); + if (nfct_attr_is_set(ct, ATTR_SNAT_PORT)) + __build_u16(ct, pld, ATTR_SNAT_PORT); + if (nfct_attr_is_set(ct, ATTR_DNAT_PORT)) + __build_u16(ct, pld, ATTR_DNAT_PORT); + if (nfct_attr_is_set(ct, ATTR_TIMEOUT)) + __build_u32(ct, pld, ATTR_TIMEOUT); + if (nfct_attr_is_set(ct, ATTR_MARK)) + __build_u32(ct, pld, ATTR_MARK); + if (nfct_attr_is_set(ct, ATTR_STATUS)) + __build_u32(ct, pld, ATTR_STATUS); + + pld->query = query; + + PLD_HOST2NETWORK(pld); +} diff --git a/src/cache.c b/src/cache.c index 3bf331c..1e20d95 100644 --- a/src/cache.c +++ b/src/cache.c @@ -193,9 +193,7 @@ struct cache *cache_create(char *name, void cache_destroy(struct cache *c) { - lock(); hashtable_destroy(c->h); - unlock(); free(c->features); free(c->feature_offset); free(c); @@ -237,7 +235,7 @@ static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) return NULL; } -struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct) +struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) { struct us_conntrack *u; @@ -252,17 +250,6 @@ struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct) return NULL; } -struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) -{ - struct us_conntrack *u; - - lock(); - u = __cache_add(c, ct); - unlock(); - - return u; -} - static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) { size_t size = c->h->datasize; @@ -317,9 +304,7 @@ struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) { struct us_conntrack *u; - lock(); u = __cache_update(c, ct); - unlock(); return u; } @@ -329,19 +314,15 @@ struct us_conntrack *cache_update_force(struct cache *c, { struct us_conntrack *u; - lock(); if ((u = __update(c, ct)) != NULL) { c->upd_ok++; - unlock(); return u; } if ((u = __add(c, ct)) != NULL) { c->add_ok++; - unlock(); return u; } c->add_fail++; - unlock(); return NULL; } @@ -354,9 +335,7 @@ int cache_test(struct cache *c, struct nf_conntrack *ct) u->ct = ct; - lock(); ret = hashtable_test(c->h, u); - unlock(); return ret != NULL; } @@ -390,7 +369,7 @@ static int __del(struct cache *c, struct nf_conntrack *ct) return 0; } -int __cache_del(struct cache *c, struct nf_conntrack *ct) +int cache_del(struct cache *c, struct nf_conntrack *ct) { if (__del(c, ct)) { c->del_ok++; @@ -401,17 +380,6 @@ int __cache_del(struct cache *c, struct nf_conntrack *ct) return 0; } -int cache_del(struct cache *c, struct nf_conntrack *ct) -{ - int ret; - - lock(); - ret = __cache_del(c, ct); - unlock(); - - return ret; -} - struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) { return data - c->extra_offset; @@ -427,7 +395,6 @@ void cache_stats(struct cache *c, int fd) char buf[512]; int size; - lock(); size = sprintf(buf, "cache %s:\n" "current active connections:\t%12u\n" "connections created:\t\t%12u\tfailed:\t%12u\n" @@ -441,7 +408,6 @@ void cache_stats(struct cache *c, int fd) c->upd_fail, c->del_ok, c->del_fail); - unlock(); send(fd, buf, size, 0); } @@ -449,7 +415,5 @@ 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 446cac8..1d1b2e8 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -71,37 +71,25 @@ void cache_dump(struct cache *c, int fd, int type) .type = type }; - /* does not require locking: called inside fork() */ hashtable_iterate(c->h, (void *) &tmp, do_dump); } +/* no need to clone, called from child process */ static int do_commit(void *data1, void *data2) { int ret; struct cache *c = data1; struct us_conntrack *u = data2; - struct nf_conntrack *ct; - char buf[4096]; - struct nlmsghdr *nlh = (struct nlmsghdr *)buf; - - ct = nfct_clone(u->ct); - if (ct == NULL) - return 0; + struct nf_conntrack *ct = u->ct; + /* XXX: related connections */ if (nfct_attr_is_set(ct, ATTR_STATUS)) { u_int32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); status &= ~IPS_EXPECTED; nfct_set_attr_u32(ct, ATTR_STATUS, status); } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_SNAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_DNAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_SPAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_DPAT); + nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); /* * Set a reduced timeout for candidate-to-be-committed @@ -109,20 +97,12 @@ static int do_commit(void *data1, void *data2) */ nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); - ret = nfct_build_query(STATE(subsys_dump), - NFCT_Q_CREATE_UPDATE, - ct, - nlh, - sizeof(buf)); - - free(ct); - if (ret == -1) { dlog(STATE(log), "failed to build: %s", strerror(errno)); return 0; } - ret = nfnl_query(STATE(dump), nlh); + ret = nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); if (ret == -1) { switch(errno) { case EEXIST: @@ -146,7 +126,6 @@ void cache_commit(struct cache *c) unsigned int commit_exist = c->commit_exist; unsigned int commit_fail = c->commit_fail; - /* does not require locking: called inside fork() */ hashtable_iterate(c->h, c, do_commit); /* calculate new entries committed */ @@ -187,30 +166,7 @@ static int do_flush(void *data1, void *data2) void cache_flush(struct cache *c) { - lock(); hashtable_iterate(c->h, c, do_flush); hashtable_flush(c->h); c->flush++; - unlock(); -} - -#include "sync.h" -#include "network.h" - -static int do_bulk(void *data1, void *data2) -{ - int ret; - struct us_conntrack *u = data2; - - mcast_build_send_update(u); - - /* keep iterating even if we have found errors */ - return 0; -} - -void cache_bulk(struct cache *c) -{ - lock(); - hashtable_iterate(c->h, NULL, do_bulk); - unlock(); } diff --git a/src/cache_timer.c b/src/cache_timer.c index 213b59a..f3940f3 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -27,7 +27,7 @@ static void timeout(struct alarm_list *a, void *data) struct us_conntrack *u = data; debug_ct(u->ct, "expired timeout"); - __cache_del(u->cache, u->ct); + cache_del(u->cache, u->ct); } static void timer_add(struct us_conntrack *u, void *data) diff --git a/src/lock.c b/src/lock.c index cd68baf..e69de29 100644 --- a/src/lock.c +++ b/src/lock.c @@ -1,32 +0,0 @@ -/* - * (C) 2006 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER; - -void lock() -{ - pthread_mutex_lock(&global_lock); -} - -void unlock() -{ - pthread_mutex_unlock(&global_lock); -} diff --git a/src/main.c b/src/main.c index a039793..007b76e 100644 --- a/src/main.c +++ b/src/main.c @@ -187,6 +187,7 @@ int main(int argc, char *argv[]) case 'F': set_operation_mode(&type, REQUEST, argv); action = FLUSH_MASTER; + break; case 'f': set_operation_mode(&type, REQUEST, argv); action = FLUSH_CACHE; diff --git a/src/mcast.c b/src/mcast.c index 85992fb..6193a59 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -87,7 +87,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return NULL; } - switch(conf->ipproto) { case AF_INET: if (setsockopt(m->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, diff --git a/src/netlink.c b/src/netlink.c index 5f7cbeb..be5f82e 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -52,19 +52,10 @@ int ignore_conntrack(struct nf_conntrack *ct) return 0; } -static int nl_event_handler(struct nlmsghdr *nlh, - struct nfattr *nfa[], - void *data) +static int event_handler(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) { - char tmp[1024]; - struct nf_conntrack *ct = (struct nf_conntrack *) tmp; - int type; - - memset(tmp, 0, sizeof(tmp)); - - if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) - return NFCT_CB_STOP; - /* * Ignore this conntrack: it talks about a * connection that is not interesting for us. @@ -74,13 +65,13 @@ static int nl_event_handler(struct nlmsghdr *nlh, switch(type) { case NFCT_T_NEW: - STATE(mode)->event_new(ct, nlh); + STATE(mode)->event_new(ct); break; case NFCT_T_UPDATE: - STATE(mode)->event_upd(ct, nlh); + STATE(mode)->event_upd(ct); break; case NFCT_T_DESTROY: - if (STATE(mode)->event_dst(ct, nlh)) + if (STATE(mode)->event_dst(ct)) update_traffic_stats(ct); break; default: @@ -88,30 +79,31 @@ static int nl_event_handler(struct nlmsghdr *nlh, break; } - return NFCT_CB_STOP; + return NFCT_CB_CONTINUE; } +#include +#include +#include + int nl_init_event_handler(void) { - struct nfnl_callback cb_events = { - .call = nl_event_handler, - .attr_count = CTA_MAX - }; - - /* open event netlink socket */ - STATE(event) = nfnl_open(); + STATE(event) = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); if (!STATE(event)) return -1; + fcntl(nfct_fd(STATE(event)), F_SETFL, O_NONBLOCK); + /* set up socket buffer size */ if (CONFIG(netlink_buffer_size)) - nfnl_rcvbufsiz(STATE(event), CONFIG(netlink_buffer_size)); + nfnl_rcvbufsiz(nfct_nfnlh(STATE(event)), + CONFIG(netlink_buffer_size)); else { socklen_t socklen = sizeof(unsigned int); unsigned int read_size; /* get current buffer size */ - getsockopt(nfnl_fd(STATE(event)), SOL_SOCKET, + getsockopt(nfct_fd(STATE(event)), SOL_SOCKET, SO_RCVBUF, &read_size, &socklen); CONFIG(netlink_buffer_size) = read_size; @@ -122,40 +114,16 @@ int nl_init_event_handler(void) CONFIG(netlink_buffer_size_max_grown) = CONFIG(netlink_buffer_size); - /* open event subsystem */ - STATE(subsys_event) = nfnl_subsys_open(STATE(event), - NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_MAX, - NFCT_ALL_CT_GROUPS); - if (STATE(subsys_event) == NULL) - return -1; - - /* register callback for new and update events */ - nfnl_callback_register(STATE(subsys_event), - IPCTNL_MSG_CT_NEW, - &cb_events); - - /* register callback for delete events */ - nfnl_callback_register(STATE(subsys_event), - IPCTNL_MSG_CT_DELETE, - &cb_events); + /* register callback for events */ + nfct_callback_register(STATE(event), NFCT_T_ALL, event_handler, NULL); return 0; } -static int nl_dump_handler(struct nlmsghdr *nlh, - struct nfattr *nfa[], - void *data) +static int dump_handler(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + 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. @@ -165,7 +133,7 @@ static int nl_dump_handler(struct nlmsghdr *nlh, switch(type) { case NFCT_T_UPDATE: - STATE(mode)->dump(ct, nlh); + STATE(mode)->dump(ct); break; default: dlog(STATE(log), "received unknown msg from ctnetlink"); @@ -176,30 +144,15 @@ static int nl_dump_handler(struct nlmsghdr *nlh, int nl_init_dump_handler(void) { - struct nfnl_callback cb_dump = { - .call = nl_dump_handler, - .attr_count = CTA_MAX - }; - /* open dump netlink socket */ - STATE(dump) = nfnl_open(); + STATE(dump) = nfct_open(CONNTRACK, 0); if (!STATE(dump)) return -1; - /* open dump subsystem */ - STATE(subsys_dump) = nfnl_subsys_open(STATE(dump), - NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_MAX, - 0); - if (STATE(subsys_dump) == NULL) - return -1; - /* register callback for dumped entries */ - nfnl_callback_register(STATE(subsys_dump), - IPCTNL_MSG_CT_NEW, - &cb_dump); + nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL); - if (nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)) == -1) + if (nl_dump_conntrack_table() == -1) return -1; return 0; @@ -207,7 +160,7 @@ int nl_init_dump_handler(void) static int warned = 0; -void nl_resize_socket_buffer(struct nfnl_handle *h) +void nl_resize_socket_buffer(struct nfct_handle *h) { unsigned int s = CONFIG(netlink_buffer_size) * 2; @@ -228,44 +181,14 @@ void nl_resize_socket_buffer(struct nfnl_handle *h) warned = 1; } - CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(h, s); + CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(nfct_nfnlh(h), s); /* notify the sysadmin */ dlog(STATE(log), "netlink socket buffer size has been set to %u bytes", CONFIG(netlink_buffer_size)); } -int nl_dump_conntrack_table(struct nfnl_handle *h, - struct nfnl_subsys_handle *subsys) +int nl_dump_conntrack_table(void) { - struct nfnlhdr req; - - memset(&req, 0, sizeof(req)); - nfct_build_query(subsys, - NFCT_Q_DUMP, - &CONFIG(family), - &req, - sizeof(req)); - - if (nfnl_query(h, &req.nlh) == -1) - return -1; - - return 0; -} - -int nl_flush_master_conntrack_table(void) -{ - struct nfnlhdr req; - - memset(&req, 0, sizeof(req)); - nfct_build_query(STATE(subsys_dump), - NFCT_Q_FLUSH, - &CONFIG(family), - &req, - sizeof(req)); - - if (nfnl_query(STATE(dump), &req.nlh) == -1) - return -1; - - return 0; + return nfct_query(STATE(dump), NFCT_Q_DUMP, &CONFIG(family)); } diff --git a/src/network.c b/src/network.c index 159bdf3..d162839 100644 --- a/src/network.c +++ b/src/network.c @@ -18,190 +18,159 @@ #include "conntrackd.h" #include "network.h" +#include "us-conntrack.h" +#include "sync.h" static unsigned int seq_set, cur_seq; -static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) +static int __do_send(struct mcast_sock *m, void *data, int len) { struct nethdr *net = data; - if (!seq_set) { - seq_set = 1; - cur_seq = time(NULL); - net->flags |= NET_F_HELLO; - } - - net->flags = htons(net->flags); - net->seq = htonl(cur_seq++); - #undef _TEST_DROP #ifdef _TEST_DROP static int drop = 0; - if (++drop > 10) { + if (++drop >= 10) { + printf("drop sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len)); drop = 0; - printf("dropping resend (seq=%u)\n", ntohl(net->seq)); return 0; } #endif + debug("send sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len)); + return mcast_send(m, net, len); } -int mcast_send_netmsg(struct mcast_sock *m, void *data) +static int __do_prepare(struct mcast_sock *m, void *data, int len) { - struct nlmsghdr *nlh = data + NETHDR_SIZ; - unsigned int len = nlh->nlmsg_len + NETHDR_SIZ; struct nethdr *net = data; - if (nlh_host2network(nlh) == -1) - return -1; + if (!seq_set) { + seq_set = 1; + cur_seq = time(NULL); + net->flags |= NET_F_HELLO; + } + net->len = len; + net->seq = cur_seq++; + HDR_HOST2NETWORK(net); - return send_netmsg(m, data, len); + return len; } -int mcast_resend_netmsg(struct mcast_sock *m, void *data) +static int __prepare_ctl(struct mcast_sock *m, void *data) { - struct nethdr *net = data; - struct nlmsghdr *nlh = data + NETHDR_SIZ; - unsigned int len; + struct nethdr_ack *nack = (struct nethdr_ack *) data; - net->flags = ntohs(net->flags); + return __do_prepare(m, data, NETHDR_ACK_SIZ); +} - if (net->flags & NET_F_NACK || net->flags & NET_F_ACK) - len = NETHDR_ACK_SIZ; - else - len = ntohl(nlh->nlmsg_len) + NETHDR_SIZ; +static int __prepare_data(struct mcast_sock *m, void *data) +{ + struct nethdr *net = (struct nethdr *) data; + struct netpld *pld = NETHDR_DATA(net); - return send_netmsg(m, data, len); + return __do_prepare(m, data, ntohs(pld->len) + NETPLD_SIZ + NETHDR_SIZ); } -int mcast_send_error(struct mcast_sock *m, void *data) +int prepare_send_netmsg(struct mcast_sock *m, void *data) { - struct nethdr *net = data; - unsigned int len = NETHDR_SIZ; + int ret = 0; + struct nethdr *net = (struct nethdr *) data; - if (net->flags & NET_F_NACK || net->flags & NET_F_ACK) { - struct nethdr_ack *nack = (struct nethdr_ack *) net; - nack->from = htonl(nack->from); - nack->to = htonl(nack->to); - len = NETHDR_ACK_SIZ; - } + if (IS_DATA(net)) + ret = __prepare_data(m, data); + else if (IS_CTL(net)) + ret = __prepare_ctl(m, data); - return send_netmsg(m, data, len); + return ret; } -#include "us-conntrack.h" -#include "sync.h" +static int tx_buflen = 0; +/* XXX: use buffer size of interface MTU */ +static char __tx_buf[1460], *tx_buf = __tx_buf; -static int __build_send(struct us_conntrack *u, int type, int query) +/* return 0 if it is not sent, otherwise return 1 */ +int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len) { - char __net[4096]; - struct nethdr *net = (struct nethdr *) __net; + int ret = 0; + struct nethdr *net = data; - if (!state_helper_verdict(type, u->ct)) - return 0; +retry: + if (tx_buflen + len < sizeof(__tx_buf)) { + memcpy(__tx_buf + tx_buflen, net, len); + tx_buflen += len; + } else { + __do_send(m, tx_buf, tx_buflen); + ret = 1; + tx_buflen = 0; + goto retry; + } - int ret = build_network_msg(query, - STATE(subsys_event), - u->ct, - __net, - sizeof(__net)); + return ret; +} - if (ret == -1) - return -1; +int mcast_buffered_pending_netmsg(struct mcast_sock *m) +{ + int ret; + + if (tx_buflen == 0) + return 0; - mcast_send_netmsg(STATE_SYNC(mcast_client), __net); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(type, net, u); + ret = __do_send(m, tx_buf, tx_buflen); + tx_buflen = 0; - return 0; + return ret; } -int mcast_build_send_update(struct us_conntrack *u) +int mcast_send_netmsg(struct mcast_sock *m, void *data) { - return __build_send(u, NFCT_T_UPDATE, NFCT_Q_UPDATE); + int ret; + int len = prepare_send_netmsg(m, data); + + ret = mcast_buffered_send_netmsg(m, data, len); + mcast_buffered_pending_netmsg(m); + + return ret; } -int mcast_build_send_destroy(struct us_conntrack *u) +void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net) { - return __build_send(u, NFCT_T_DESTROY, NFCT_Q_DESTROY); + struct netpld *pld = NETHDR_DATA(net); + + build_netpld(ct, pld, query); } -int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) +int handle_netmsg(struct nethdr *net) { int ret; - struct nethdr *net = data; - struct nlmsghdr *nlh = data + NETHDR_SIZ; - struct nfgenmsg *nfhdr; - - ret = mcast_recv(m, net, len); - if (ret <= 0) - return ret; + struct netpld *pld = NETHDR_DATA(net); /* message too small: no room for the header */ - if (ret < NETHDR_SIZ) + if (ntohs(net->len) < NETHDR_ACK_SIZ) return -1; - if (ntohs(net->flags) & NET_F_HELLO) - STATE_SYNC(last_seq_recv) = ntohl(net->seq) - 1; + HDR_NETWORK2HOST(net); - if (ntohs(net->flags) & NET_F_NACK || ntohs(net->flags) & NET_F_ACK) { - struct nethdr_ack *nack = (struct nethdr_ack *) net; + if (IS_HELLO(net)) + STATE_SYNC(last_seq_recv) = net->seq - 1; - /* message too small: no room for the header */ - if (ret < NETHDR_ACK_SIZ) - return -1; - - /* host byte order conversion */ - net->flags = ntohs(net->flags); - net->seq = ntohl(net->seq); - - /* acknowledgement conversion */ - nack->from = ntohl(nack->from); - nack->to = ntohl(nack->to); - - return ret; - } - - if (ntohs(net->flags) & NET_F_RESYNC) { - /* host byte order conversion */ - net->flags = ntohs(net->flags); - net->seq = ntohl(net->seq); - - return ret; - } + if (IS_CTL(net)) + return 0; /* information received is too small */ - if (ret < NLMSG_SPACE(sizeof(struct nfgenmsg))) - return -1; - - /* information received and message length does not match */ - if (ret != ntohl(nlh->nlmsg_len) + NETHDR_SIZ) - return -1; - - /* this message does not come from ctnetlink */ - if (NFNL_SUBSYS_ID(ntohs(nlh->nlmsg_type)) != NFNL_SUBSYS_CTNETLINK) + if (net->len < sizeof(struct netpld)) return -1; - nfhdr = NLMSG_DATA(nlh); - - /* only AF_INET and AF_INET6 are supported */ - if (nfhdr->nfgen_family != AF_INET && - nfhdr->nfgen_family != AF_INET6) - return -1; - - /* only process message coming from nfnetlink v0 */ - if (nfhdr->version != NFNETLINK_V0) - return -1; - - /* host byte order conversion */ - net->flags = ntohs(net->flags); - net->seq = ntohl(net->seq); - - if (nlh_network2host(nlh) == -1) + /* size mismatch! */ + if (net->len < ntohs(pld->len) + NETHDR_SIZ) return -1; - return ret; + return 0; } int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq) @@ -238,30 +207,3 @@ out: return ret; } - -int build_network_msg(const int msg_type, - struct nfnl_subsys_handle *ssh, - struct nf_conntrack *ct, - void *buffer, - unsigned int size) -{ - memset(buffer, 0, size); - buffer += NETHDR_SIZ; - size -= NETHDR_SIZ; - return nfct_build_query(ssh, msg_type, ct, buffer, size); -} - -unsigned int parse_network_msg(struct nf_conntrack *ct, - const struct nlmsghdr *nlh) -{ - /* - * The parsing of netlink messages going through network is - * similar to the one that is done for messages coming from - * kernel, therefore do not replicate more code and use the - * function provided in the libraries. - * - * Yup, this is a hack 8) - */ - return nfct_parse_conntrack(NFCT_T_ALL, nlh, ct); -} - diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..81b70c4 --- /dev/null +++ b/src/parse.c @@ -0,0 +1,76 @@ +/* + * (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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "network.h" + +static int parse_u8(struct nf_conntrack *ct, int attr, void *data) +{ + u_int8_t *value = (u_int8_t *) data; + nfct_set_attr_u8(ct, attr, *value); +} + +static int parse_u16(struct nf_conntrack *ct, int attr, void *data) +{ + u_int16_t *value = (u_int16_t *) data; + nfct_set_attr_u16(ct, attr, ntohs(*value)); +} + +static int parse_u32(struct nf_conntrack *ct, int attr, void *data) +{ + u_int32_t *value = (u_int32_t *) data; + nfct_set_attr_u32(ct, attr, ntohl(*value)); +} + +typedef int (*parse)(struct nf_conntrack *ct, int attr, void *data); + +parse h[ATTR_MAX] = { + [ATTR_IPV4_SRC] = parse_u32, + [ATTR_IPV4_DST] = parse_u32, + [ATTR_L3PROTO] = parse_u8, + [ATTR_PORT_SRC] = parse_u16, + [ATTR_PORT_DST] = parse_u16, + [ATTR_L4PROTO] = parse_u8, + [ATTR_TCP_STATE] = parse_u8, + [ATTR_SNAT_IPV4] = parse_u32, + [ATTR_DNAT_IPV4] = parse_u32, + [ATTR_SNAT_PORT] = parse_u16, + [ATTR_DNAT_PORT] = parse_u16, + [ATTR_TIMEOUT] = parse_u32, + [ATTR_MARK] = parse_u32, + [ATTR_STATUS] = parse_u32, +}; + +void parse_netpld(struct nf_conntrack *ct, struct netpld *pld, int *query) +{ + int len; + struct netattr *attr; + + PLD_NETWORK2HOST(pld); + len = pld->len; + attr = PLD_DATA(pld); + + while (len > 0) { + ATTR_NETWORK2HOST(attr); + h[attr->nta_attr](ct, attr->nta_attr, NTA_DATA(attr)); + attr = NTA_NEXT(attr, len); + } + + *query = pld->query; +} diff --git a/src/proxy.c b/src/proxy.c deleted file mode 100644 index b9bb04e..0000000 --- a/src/proxy.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * (C) 2006 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#if 0 -#define dprintf printf -#else -#define dprintf -#endif - -int nlh_payload_host2network(struct nfattr *nfa, int len) -{ - struct nfattr *__nfa; - - while (NFA_OK(nfa, len)) { - - dprintf("type=%d nfalen=%d len=%d [%s]\n", - nfa->nfa_type & 0x7fff, - nfa->nfa_len, len, - nfa->nfa_type & NFNL_NFA_NEST ? "NEST":""); - - if (nfa->nfa_type & NFNL_NFA_NEST) { - if (NFA_PAYLOAD(nfa) > len) - return -1; - - if (nlh_payload_host2network(NFA_DATA(nfa), - NFA_PAYLOAD(nfa)) == -1) - return -1; - } - - __nfa = NFA_NEXT(nfa, len); - - nfa->nfa_type = htons(nfa->nfa_type); - nfa->nfa_len = htons(nfa->nfa_len); - - nfa = __nfa; - } - return 0; -} - -int nlh_host2network(struct nlmsghdr *nlh) -{ - struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); - struct nfattr *cda[CTA_MAX]; - unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); - unsigned int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - - nlh->nlmsg_len = htonl(nlh->nlmsg_len); - nlh->nlmsg_type = htons(nlh->nlmsg_type); - nlh->nlmsg_flags = htons(nlh->nlmsg_flags); - nlh->nlmsg_seq = htonl(nlh->nlmsg_seq); - nlh->nlmsg_pid = htonl(nlh->nlmsg_pid); - - nfhdr->res_id = htons(nfhdr->res_id); - - return nlh_payload_host2network(NFM_NFA(NLMSG_DATA(nlh)), len); -} - -int nlh_payload_network2host(struct nfattr *nfa, int len) -{ - nfa->nfa_type = ntohs(nfa->nfa_type); - nfa->nfa_len = ntohs(nfa->nfa_len); - - while(NFA_OK(nfa, len)) { - - dprintf("type=%d nfalen=%d len=%d [%s]\n", - nfa->nfa_type & 0x7fff, - nfa->nfa_len, len, - nfa->nfa_type & NFNL_NFA_NEST ? "NEST":""); - - if (nfa->nfa_type & NFNL_NFA_NEST) { - if (NFA_PAYLOAD(nfa) > len) - return -1; - - if (nlh_payload_network2host(NFA_DATA(nfa), - NFA_PAYLOAD(nfa)) == -1) - return -1; - } - - nfa = NFA_NEXT(nfa,len); - - if (len < NFA_LENGTH(0)) - break; - - nfa->nfa_type = ntohs(nfa->nfa_type); - nfa->nfa_len = ntohs(nfa->nfa_len); - } - return 0; -} - -int nlh_network2host(struct nlmsghdr *nlh) -{ - struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); - struct nfattr *cda[CTA_MAX]; - unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); - unsigned int len = ntohl(nlh->nlmsg_len) - NLMSG_ALIGN(min_len); - - nlh->nlmsg_len = ntohl(nlh->nlmsg_len); - nlh->nlmsg_type = ntohs(nlh->nlmsg_type); - nlh->nlmsg_flags = ntohs(nlh->nlmsg_flags); - nlh->nlmsg_seq = ntohl(nlh->nlmsg_seq); - nlh->nlmsg_pid = ntohl(nlh->nlmsg_pid); - - nfhdr->res_id = ntohs(nfhdr->res_id); - - return nlh_payload_network2host(NFM_NFA(NLMSG_DATA(nlh)), len); -} diff --git a/src/run.c b/src/run.c index 0173c9f..644f82e 100644 --- a/src/run.c +++ b/src/run.c @@ -24,20 +24,21 @@ #include "us-conntrack.h" #include #include +#include +#include "timer.h" void killer(int foo) { /* no signals while handling signals */ sigprocmask(SIG_BLOCK, &STATE(block), NULL); - nfnl_subsys_close(STATE(subsys_event)); - nfnl_subsys_close(STATE(subsys_dump)); - nfnl_close(STATE(event)); - nfnl_close(STATE(dump)); + nfct_close(STATE(event)); + nfct_close(STATE(dump)); ignore_pool_destroy(STATE(ignore_pool)); local_server_destroy(STATE(local)); STATE(mode)->kill(); + destroy_alarm_scheduler(); unlink(CONFIG(lockfile)); dlog(STATE(log), "------- shutdown received ----"); close_log(STATE(log)); @@ -69,12 +70,16 @@ void local_handler(int fd, void *data) switch(type) { case FLUSH_MASTER: - dlog(STATE(log), "[REQ] flushing master table"); - nl_flush_master_conntrack_table(); + dlog(STATE(log), "[DEPRECATED] `conntrackd -F' is deprecated. " + "Use conntrack -F instead."); + if (fork() == 0) { + execlp("conntrack", "conntrack", "-F", NULL); + exit(EXIT_SUCCESS); + } return; case RESYNC_MASTER: dlog(STATE(log), "[REQ] resync with master table"); - nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)); + nl_dump_conntrack_table(); return; } @@ -104,6 +109,11 @@ int init(int mode) return -1; } + if (init_alarm_scheduler() == -1) { + dlog(STATE(log), "[FAIL] can't initialize alarm scheduler"); + return -1; + } + /* local UNIX socket */ STATE(local) = local_server_create(&CONFIG(local)); if (!STATE(local)) { @@ -147,22 +157,20 @@ int init(int mode) return 0; } -#define POLL_NSECS 1 - -static void __run(void) +static void __run(long credit, int step) { int max, ret; fd_set readfds; struct timeval tv = { - .tv_sec = POLL_NSECS, - .tv_usec = 0 + .tv_sec = 0, + .tv_usec = credit, }; FD_ZERO(&readfds); FD_SET(STATE(local), &readfds); - FD_SET(nfnl_fd(STATE(event)), &readfds); + FD_SET(nfct_fd(STATE(event)), &readfds); - max = MAX(STATE(local), nfnl_fd(STATE(event))); + max = MAX(STATE(local), nfct_fd(STATE(event))); if (STATE(mode)->add_fds_to_set) max = MAX(max, STATE(mode)->add_fds_to_set(&readfds)); @@ -185,8 +193,8 @@ static void __run(void) do_local_server_step(STATE(local), NULL, local_handler); /* conntrack event has happened */ - if (FD_ISSET(nfnl_fd(STATE(event)), &readfds)) { - ret = nfnl_catch(STATE(event)); + if (FD_ISSET(nfct_fd(STATE(event)), &readfds)) { + while ((ret = nfct_catch(STATE(event))) != -1); if (ret == -1) { switch(errno) { case ENOBUFS: @@ -197,6 +205,7 @@ static void __run(void) * size and resync with master conntrack table. */ nl_resize_socket_buffer(STATE(event)); + /* XXX: schedule overrun call via alarm */ STATE(mode)->overrun(); break; case ENOENT: @@ -206,6 +215,8 @@ static void __run(void) * interested in. Just ignore it. */ break; + case EAGAIN: + break; default: dlog(STATE(log), "event catch says: %s", strerror(errno)); @@ -214,14 +225,35 @@ static void __run(void) } } - if (STATE(mode)->step) - STATE(mode)->step(&readfds); + if (STATE(mode)->run) + STATE(mode)->run(&readfds, step); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); } void run(void) { - while(1) - __run(); + int step = 0; + struct timer timer; + + timer_init(&timer); + + while(1) { + timer_start(&timer); + __run(GET_CREDITS(timer), step); + timer_stop(&timer); + + if (timer_adjust_credit(&timer)) { + timer_start(&timer); + sigprocmask(SIG_BLOCK, &STATE(block), NULL); + do_alarm_run(step); + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); + timer_stop(&timer); + + if (timer_adjust_credit(&timer)) + dlog(STATE(log), "alarm run takes too long!"); + + step = (step + 1) < STEPS_PER_SECONDS ? step + 1 : 0; + } + } } diff --git a/src/state_helper.c b/src/state_helper.c index 81b0d09..eba9d8f 100644 --- a/src/state_helper.c +++ b/src/state_helper.c @@ -25,7 +25,7 @@ int state_helper_verdict(int type, struct nf_conntrack *ct) { u_int8_t l4proto; - if (type == NFCT_T_DESTROY) + if (type == NFCT_Q_DESTROY) return ST_H_REPLICATE; l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); diff --git a/src/stats-mode.c b/src/stats-mode.c index 92794cd..65bab1b 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -86,7 +86,7 @@ static int local_handler_stats(int fd, int type, void *data) return ret; } -static void dump_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void dump_stats(struct nf_conntrack *ct) { if (cache_update_force(STATE_STATS(cache), ct)) debug_ct(ct, "resync entry"); @@ -137,7 +137,7 @@ static void overrun_stats() nfct_close(h); } -static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void event_new_stats(struct nf_conntrack *ct) { if (cache_add(STATE_STATS(cache), ct)) { debug_ct(ct, "cache new"); @@ -150,7 +150,7 @@ static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) } } -static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void event_update_stats(struct nf_conntrack *ct) { if (!cache_update_force(STATE_STATS(cache), ct)) { debug_ct(ct, "can't update"); @@ -159,7 +159,7 @@ static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) debug_ct(ct, "update"); } -static int event_destroy_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static int event_destroy_stats(struct nf_conntrack *ct) { if (cache_del(STATE_STATS(cache), ct)) { debug_ct(ct, "cache destroy"); @@ -173,7 +173,7 @@ static int event_destroy_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) struct ct_mode stats_mode = { .init = init_stats, .add_fds_to_set = NULL, - .step = NULL, + .run = NULL, .local = local_handler_stats, .kill = kill_stats, .dump = dump_stats, diff --git a/src/sync-mode.c b/src/sync-mode.c index 38ab016..f30cb95 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -27,43 +27,27 @@ #include #include "sync.h" #include "network.h" +#include "buffer.h" +#include "debug.h" -/* handler for multicast messages received */ -static void mcast_handler() +static void do_mcast_handler_step(struct nethdr *net) { - int ret; - unsigned int type; - char __net[4096]; - struct nethdr *net = (struct nethdr *) __net; - struct nlmsghdr *nlh = (struct nlmsghdr *) (__net + NETHDR_SIZ); + unsigned int query; + struct netpld *pld = NETHDR_DATA(net); char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *) __ct; struct us_conntrack *u = NULL; - ret = mcast_recv_netmsg(STATE_SYNC(mcast_server), net, sizeof(__net)); - if (ret <= 0) { - STATE(malformed)++; - return; - } - if (STATE_SYNC(sync)->recv(net)) return; memset(ct, 0, sizeof(__ct)); - if ((type = parse_network_msg(ct, nlh)) == NFCT_T_ERROR) { - STATE(malformed)++; - return; - } + /* XXX: check for malformed */ + parse_netpld(ct, pld, &query); - 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); - - switch(type) { - case NFCT_T_NEW: + switch(query) { + case NFCT_Q_CREATE: retry: if ((u = cache_add(STATE_SYNC(external), ct))) { debug_ct(u->ct, "external new"); @@ -80,24 +64,57 @@ retry: debug_ct(ct, "can't add"); } break; - case NFCT_T_UPDATE: + case NFCT_Q_UPDATE: if ((u = cache_update_force(STATE_SYNC(external), ct))) { debug_ct(u->ct, "external update"); } else debug_ct(ct, "can't update"); break; - case NFCT_T_DESTROY: + case NFCT_Q_DESTROY: if (cache_del(STATE_SYNC(external), ct)) debug_ct(ct, "external destroy"); else debug_ct(ct, "can't destroy"); break; default: - dlog(STATE(log), "mcast received unknown msg type %d\n", type); + dlog(STATE(log), "mcast received unknown query %d\n", query); break; } } +/* handler for multicast messages received */ +static void mcast_handler() +{ + int numbytes, remain; + char __net[4096], *ptr = __net; + + numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net)); + if (numbytes <= 0) + return; + + remain = numbytes; + while (remain > 0) { + struct nethdr *net = (struct nethdr *) ptr; + + if (ntohs(net->len) > remain) { + dlog(STATE(log), "fragmented messages"); + break; + } + + debug("recv sq: %u fl:%u len:%u (rem:%d)\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len), remain); + + if (handle_netmsg(net) == -1) { + STATE(malformed)++; + return; + } + do_mcast_handler_step(net); + ptr += net->len; + remain -= net->len; + } +} + static int init_sync(void) { int ret; @@ -159,11 +176,6 @@ static int init_sync(void) /* initialization of multicast sequence generation */ STATE_SYNC(last_seq_sent) = time(NULL); - if (create_alarm_thread() == -1) { - dlog(STATE(log), "[FAIL] can't initialize alarm thread"); - return -1; - } - return 0; } @@ -174,11 +186,17 @@ static int add_fds_to_set_sync(fd_set *readfds) return STATE_SYNC(mcast_server->fd); } -static void step_sync(fd_set *readfds) +static void run_sync(fd_set *readfds, int step) { /* multicast packet has been received */ if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) mcast_handler(); + + if (STATE_SYNC(sync)->run) + STATE_SYNC(sync)->run(step); + + /* flush pending messages */ + mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); } static void kill_sync() @@ -189,8 +207,6 @@ static void kill_sync() mcast_server_destroy(STATE_SYNC(mcast_server)); mcast_client_destroy(STATE_SYNC(mcast_client)); - destroy_alarm_thread(); - if (STATE_SYNC(sync)->kill) STATE_SYNC(sync)->kill(); } @@ -267,10 +283,6 @@ static int local_handler_sync(int fd, int type, void *data) STATE_SYNC(mcast_server)); dump_stats_sync(fd); break; - case SEND_BULK: - dlog(STATE(log), "[REQ] sending bulk update"); - cache_bulk(STATE_SYNC(internal)); - break; default: if (STATE_SYNC(sync)->local) ret = STATE_SYNC(sync)->local(fd, type, data); @@ -280,7 +292,7 @@ static int local_handler_sync(int fd, int type, void *data) return ret; } -static void dump_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void dump_sync(struct nf_conntrack *ct) { /* This is required by kernels < 2.6.20 */ nfct_attr_unset(ct, ATTR_TIMEOUT); @@ -294,23 +306,21 @@ static void dump_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) debug_ct(ct, "resync"); } -static void mcast_send_sync(struct nlmsghdr *nlh, - struct us_conntrack *u, +static void mcast_send_sync(struct us_conntrack *u, struct nf_conntrack *ct, - int type) + int query) { - char __net[4096]; - struct nethdr *net = (struct nethdr *) __net; - - memset(__net, 0, sizeof(__net)); + int len; + struct nethdr *net; - if (!state_helper_verdict(type, ct)) + if (!state_helper_verdict(query, ct)) return; - memcpy(__net + NETHDR_SIZ, nlh, nlh->nlmsg_len); - mcast_send_netmsg(STATE_SYNC(mcast_client), net); + net = BUILD_NETMSG(ct, query); + len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(type, net, u); + STATE_SYNC(sync)->send(net, u); } static int overrun_cb(enum nf_conntrack_msg_type type, @@ -332,8 +342,16 @@ static int overrun_cb(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { + int len; + debug_ct(u->ct, "overrun resync"); - mcast_build_send_update(u); + + struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + len = prepare_send_netmsg(STATE_SYNC(mcast_client),net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), + net, len); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(net, u); } } @@ -348,9 +366,17 @@ static int overrun_purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { + int len; + struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_DESTROY); + debug_ct(u->ct, "overrun purge resync"); - mcast_build_send_destroy(u); - __cache_del(STATE_SYNC(internal), u->ct); + + len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(net, u); + + cache_del(STATE_SYNC(internal), u->ct); } return 0; @@ -382,7 +408,7 @@ static void overrun_sync() nfct_close(h); } -static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void event_new_sync(struct nf_conntrack *ct) { struct us_conntrack *u; @@ -394,12 +420,12 @@ static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) nfct_attr_unset(ct, ATTR_TIMEOUT); retry: if ((u = cache_add(STATE_SYNC(internal), ct))) { - mcast_send_sync(nlh, u, ct, NFCT_T_NEW); + mcast_send_sync(u, ct, NFCT_Q_CREATE); debug_ct(u->ct, "internal new"); } else { if (errno == EEXIST) { cache_del(STATE_SYNC(internal), ct); - mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); + mcast_send_sync(NULL, ct, NFCT_Q_DESTROY); goto retry; } @@ -409,7 +435,7 @@ retry: } } -static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void event_update_sync(struct nf_conntrack *ct) { struct us_conntrack *u; @@ -420,15 +446,15 @@ static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) return; } debug_ct(u->ct, "internal update"); - mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); + mcast_send_sync(u, ct, NFCT_Q_UPDATE); } -static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static int event_destroy_sync(struct nf_conntrack *ct) { nfct_attr_unset(ct, ATTR_TIMEOUT); if (cache_del(STATE_SYNC(internal), ct)) { - mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); + mcast_send_sync(NULL, ct, NFCT_Q_DESTROY); debug_ct(ct, "internal destroy"); } else debug_ct(ct, "can't destroy"); @@ -437,7 +463,7 @@ static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) struct ct_mode sync_mode = { .init = init_sync, .add_fds_to_set = add_fds_to_set_sync, - .step = step_sync, + .run = run_sync, .local = local_handler_sync, .kill = kill_sync, .dump = dump_sync, diff --git a/src/sync-nack.c b/src/sync-nack.c index 20ad1f4..dbda0a7 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -24,6 +24,7 @@ #include "buffer.h" #include "debug.h" #include "network.h" +#include "alarm.h" #include #include @@ -33,28 +34,34 @@ #define dp #endif -static LIST_HEAD(queue); +static LIST_HEAD(rs_list); +static LIST_HEAD(tx_list); +static unsigned int tx_list_len; +static struct buffer *rs_queue; +static struct buffer *tx_queue; struct cache_nack { - struct list_head head; + struct list_head rs_list; + struct list_head tx_list; u_int32_t seq; }; static void cache_nack_add(struct us_conntrack *u, void *data) { struct cache_nack *cn = data; - INIT_LIST_HEAD(&cn->head); + INIT_LIST_HEAD(&cn->rs_list); + INIT_LIST_HEAD(&cn->tx_list); } static void cache_nack_del(struct us_conntrack *u, void *data) { struct cache_nack *cn = data; - if (cn->head.next == &cn->head && - cn->head.prev == &cn->head) + if (cn->rs_list.next == &cn->rs_list && + cn->rs_list.prev == &cn->rs_list) return; - list_del(&cn->head); + list_del(&cn->rs_list); } static struct cache_extra cache_nack_extra = { @@ -65,19 +72,31 @@ static struct cache_extra cache_nack_extra = { static int nack_init() { - STATE_SYNC(buffer) = buffer_create(CONFIG(resend_buffer_size)); - if (STATE_SYNC(buffer) == NULL) + tx_queue = buffer_create(CONFIG(resend_buffer_size)); + if (tx_queue == NULL) { + dlog(STATE(log), "[FAIL] cannot create tx buffer"); return -1; + } + + rs_queue = buffer_create(CONFIG(resend_buffer_size)); + if (rs_queue == NULL) { + dlog(STATE(log), "[FAIL] cannot create rs buffer"); + return -1; + } + + INIT_LIST_HEAD(&tx_list); + INIT_LIST_HEAD(&rs_list); return 0; } static void nack_kill() { - buffer_destroy(STATE_SYNC(buffer)); + buffer_destroy(rs_queue); + buffer_destroy(tx_queue); } -static void mcast_send_control(u_int32_t flags, u_int32_t from, u_int32_t to) +static void tx_queue_add_ctlmsg(u_int32_t flags, u_int32_t from, u_int32_t to) { struct nethdr_ack ack = { .flags = flags, @@ -85,8 +104,19 @@ static void mcast_send_control(u_int32_t flags, u_int32_t from, u_int32_t to) .to = to, }; - mcast_send_error(STATE_SYNC(mcast_client), &ack); - buffer_add(STATE_SYNC(buffer), &ack, NETHDR_ACK_SIZ); + buffer_add(tx_queue, &ack, NETHDR_ACK_SIZ); +} + +static int do_cache_to_tx(void *data1, void *data2) +{ + struct us_conntrack *u = data2; + struct cache_nack *cn = cache_get_extra(STATE_SYNC(internal), u); + + /* add to tx list */ + list_add(&cn->tx_list, &tx_list); + tx_list_len++; + + return 0; } static int nack_local(int fd, int type, void *data) @@ -94,85 +124,78 @@ static int nack_local(int fd, int type, void *data) int ret = 1; switch(type) { - case REQUEST_DUMP: - mcast_send_control(NET_F_RESYNC, 0, 0); - dlog(STATE(log), "[REQ] request resync"); - break; - default: - ret = 0; - break; + case REQUEST_DUMP: + dlog(STATE(log), "[REQ] request resync"); + tx_queue_add_ctlmsg(NET_F_RESYNC, 0, 0); + break; + case SEND_BULK: + dlog(STATE(log), "[REQ] sending bulk update"); + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + break; + default: + ret = 0; + break; } return ret; } -static int buffer_compare(void *data1, void *data2) +static int rs_queue_to_tx(void *data1, void *data2) { struct nethdr *net = data1; struct nethdr_ack *nack = data2; - struct nlmsghdr *nlh = data1 + NETHDR_SIZ; - - unsigned old_seq = ntohl(net->seq); - if (between(ntohl(net->seq), nack->from, nack->to)) { - if (mcast_resend_netmsg(STATE_SYNC(mcast_client), net)) - dp("resend destroy (old seq=%u) (seq=%u)\n", - old_seq, ntohl(net->seq)); + if (between(net->seq, nack->from, nack->to)) { + dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", + net->seq, net->flags, net->len); + buffer_add(tx_queue, net, net->len); } return 0; } -static int buffer_remove(void *data1, void *data2) +static int rs_queue_empty(void *data1, void *data2) { struct nethdr *net = data1; struct nethdr_ack *h = data2; - if (between(ntohl(net->seq), h->from, h->to)) { - dp("remove from buffer (seq=%u)\n", ntohl(net->seq)); - __buffer_del(STATE_SYNC(buffer), data1); + if (between(net->seq, h->from, h->to)) { + dp("remove from buffer (seq=%u)\n", net->seq); + buffer_del(rs_queue, data1); } return 0; } -static void queue_resend(struct cache *c, unsigned int from, unsigned int to) +static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) { struct list_head *n; struct us_conntrack *u; - list_for_each(n, &queue) { + list_for_each(n, &rs_list) { struct cache_nack *cn = (struct cache_nack *) n; struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (between(cn->seq, from, to)) { - debug_ct(u->ct, "resend nack"); - dp("resending nack'ed (oldseq=%u) ", cn->seq); - - if (mcast_build_send_update(u) == -1) - continue; - - dp("(newseq=%u)\n", cn->seq); + dp("resending nack'ed (oldseq=%u)\n", cn->seq); + list_add(&cn->tx_list, &tx_list); + tx_list_len++; } } } -static void queue_empty(struct cache *c, unsigned int from, unsigned int to) +static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) { struct list_head *n, *tmp; - struct us_conntrack *u; - dp("ACK from %u to %u\n", from, to); - list_for_each_safe(n, tmp, &queue) { + list_for_each_safe(n, tmp, &rs_list) { struct cache_nack *cn = (struct cache_nack *) n; + struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); if (between(cn->seq, from, to)) { - dp("remove %u\n", cn->seq); - debug_ct(u->ct, "ack received: empty queue"); dp("queue: deleting from queue (seq=%u)\n", cn->seq); - list_del(&cn->head); - INIT_LIST_HEAD(&cn->head); + list_del(&cn->rs_list); + INIT_LIST_HEAD(&cn->rs_list); } } } @@ -187,73 +210,149 @@ static int nack_recv(const struct nethdr *net) if (!mcast_track_seq(net->seq, &exp_seq)) { dp("OOS: sending nack (seq=%u)\n", exp_seq); - mcast_send_control(NET_F_NACK, exp_seq, net->seq - 1); + tx_queue_add_ctlmsg(NET_F_NACK, exp_seq, net->seq-1); window = CONFIG(window_size); } else { /* received a window, send an acknowledgement */ if (--window == 0) { dp("sending ack (seq=%u)\n", net->seq); - mcast_send_control(NET_F_ACK, - net->seq - CONFIG(window_size), - net->seq); + tx_queue_add_ctlmsg(NET_F_ACK, + net->seq - CONFIG(window_size), + net->seq); } } - if (net->flags & NET_F_NACK) { + if (IS_NACK(net)) { struct nethdr_ack *nack = (struct nethdr_ack *) net; dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); - queue_resend(STATE_SYNC(internal), nack->from, nack->to); - buffer_iterate(STATE_SYNC(buffer), nack, buffer_compare); + rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); + buffer_iterate(rs_queue, nack, rs_queue_to_tx); return 1; - } else if (net->flags & NET_F_RESYNC) { + } else if (IS_RESYNC(net)) { dp("RESYNC ALL\n"); - cache_bulk(STATE_SYNC(internal)); + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); return 1; - } else if (net->flags & NET_F_ACK) { + } else if (IS_ACK(net)) { struct nethdr_ack *h = (struct nethdr_ack *) net; dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); - queue_empty(STATE_SYNC(internal), h->from, h->to); - buffer_iterate(STATE_SYNC(buffer), h, buffer_remove); + rs_list_empty(STATE_SYNC(internal), h->from, h->to); + buffer_iterate(rs_queue, h, rs_queue_empty); + return 1; + } else if (IS_ALIVE(net)) return 1; - } return 0; } -static void nack_send(int type, - const struct nethdr *net, - struct us_conntrack *u) +static void nack_send(struct nethdr *net, struct us_conntrack *u) { - int size = NETHDR_SIZ; - struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); + struct netpld *pld = NETHDR_DATA(net); struct cache_nack *cn; - - size += ntohl(nlh->nlmsg_len); - switch(type) { - case NFCT_T_NEW: - case NFCT_T_UPDATE: + HDR_NETWORK2HOST(net); + + switch(ntohs(pld->query)) { + case NFCT_Q_CREATE: + case NFCT_Q_UPDATE: cn = (struct cache_nack *) cache_get_extra(STATE_SYNC(internal), u); - if (cn->head.next == &cn->head && - cn->head.prev == &cn->head) + if (cn->rs_list.next == &cn->rs_list && + cn->rs_list.prev == &cn->rs_list) goto insert; - list_del(&cn->head); - INIT_LIST_HEAD(&cn->head); + list_del(&cn->rs_list); + INIT_LIST_HEAD(&cn->rs_list); insert: - cn->seq = ntohl(net->seq); - list_add(&cn->head, &queue); + cn->seq = net->seq; + list_add(&cn->rs_list, &rs_list); break; - case NFCT_T_DESTROY: - buffer_add(STATE_SYNC(buffer), net, size); + case NFCT_Q_DESTROY: + buffer_add(rs_queue, net, net->len); break; } } +static int tx_queue_xmit(void *data1, void *data2) +{ + struct nethdr *net = data1; + int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + dp("tx_queue sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); + + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + HDR_NETWORK2HOST(net); + + if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) { + dp("-> back_to_tx_queue sq: %u fl:%u len:%u\n", + net->seq, net->flags, net->len); + buffer_add(rs_queue, net, net->len); + } + buffer_del(tx_queue, net); + + return 0; +} + +static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) +{ + int ret; + struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + dp("tx_list sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len)); + + list_del(i); + INIT_LIST_HEAD(i); + tx_list_len--; + + ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(net, u); + + return ret; +} + +static struct alarm_list alive_alarm; + +static void do_alive_alarm(struct alarm_list *a, void *data) +{ + del_alarm(a); + tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); +} + +static void nack_run(int step) +{ + struct list_head *i, *tmp; + + /* send messages in the tx_queue */ + buffer_iterate(tx_queue, NULL, tx_queue_xmit); + + /* send conntracks in the tx_list */ + list_for_each_safe(i, tmp, &tx_list) { + struct cache_nack *cn; + struct us_conntrack *u; + + cn = container_of(i, struct cache_nack, tx_list); + u = cache_get_conntrack(STATE_SYNC(internal), cn); + tx_list_xmit(i, u); + } + + if (alive_alarm.expires > 0) + mod_alarm(&alive_alarm, 1); + else { + init_alarm(&alive_alarm); + /* XXX: alive message expiration configurable */ + set_alarm_expiration(&alive_alarm, 1); + set_alarm_function(&alive_alarm, do_alive_alarm); + add_alarm(&alive_alarm); + } +} + struct sync_mode nack = { .internal_cache_flags = LIFETIME, .external_cache_flags = LIFETIME, @@ -263,4 +362,5 @@ struct sync_mode nack = { .local = nack_local, .recv = nack_recv, .send = nack_send, + .run = nack_run, }; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 1d6eba8..8588ecf 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -24,12 +24,16 @@ static void refresher(struct alarm_list *a, void *data) { + int len; + struct nethdr *net; struct us_conntrack *u = data; debug_ct(u->ct, "persistence update"); a->expires = random() % CONFIG(refresh) + 1; - mcast_build_send_update(u); + net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); } static void cache_notrack_add(struct us_conntrack *u, void *data) diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 0000000..b85c286 --- /dev/null +++ b/src/timer.c @@ -0,0 +1,75 @@ +/* + * (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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "conntrackd.h" +#include "timer.h" + +#define TIMESLICE_CREDIT (1000000 / STEPS_PER_SECONDS) /* 200 ms timeslice */ + +void timer_init(struct timer *timer) +{ + memset(timer, 0, sizeof(struct timer)); + timer->credits = TIMESLICE_CREDIT; +} + +void timer_start(struct timer *timer) +{ + gettimeofday(&timer->start, NULL); +} + +static int timeval_subtract(struct timeval *diff, + struct timeval *start, + struct timeval *stop) +{ + diff->tv_sec = stop->tv_sec - start->tv_sec; + diff->tv_usec = stop->tv_usec - start->tv_usec; + + if (diff->tv_usec < 0) { + diff->tv_usec += 1000000; + diff->tv_sec--; + } + + /* Return 1 if result is negative. */ + return diff->tv_sec < 0; +} + +void timer_stop(struct timer *timer) +{ + gettimeofday(&timer->stop, NULL); + timeval_subtract(&timer->diff, &timer->start, &timer->stop); +} + +int timer_adjust_credit(struct timer *timer) +{ + if (timer->diff.tv_sec != 0) { + timer->credits = TIMESLICE_CREDIT; + return 1; + } + + timer->credits -= timer->diff.tv_usec; + + if (timer->credits < 0) { + timer->credits += TIMESLICE_CREDIT; + if (timer->credits < 0) + timer->credits = TIMESLICE_CREDIT; + return 1; + } + return 0; +} -- cgit v1.2.3 From 18bbf19becaab7dc4137406928f96ad089192f69 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 18 Jul 2007 20:04:00 +0000 Subject: conntrackd: - use buffer of MTU size conntrack: - better protocol argument checkings - fix per-protocol filtering, eg. conntrack -[L|E] -p tcp now works - show per-protocol help, ie. conntrack -h -p tcp - add alias --src for --orig-src and alias --dst for --orig-dst --- ChangeLog | 7 ++ examples/sync/nack/node1/conntrackd.conf | 1 + examples/sync/nack/node2/conntrackd.conf | 1 + examples/sync/persistent/node1/conntrackd.conf | 1 + examples/sync/persistent/node2/conntrackd.conf | 1 + extensions/libct_proto_icmp.c | 45 ++++++++--- extensions/libct_proto_tcp.c | 63 ++++++++++----- extensions/libct_proto_udp.c | 50 +++++++++--- include/conntrack.h | 28 +++++-- include/mcast.h | 3 + include/network.h | 7 ++ src/conntrack.c | 108 +++++++++++-------------- src/mcast.c | 14 ++++ src/network.c | 32 +++++++- src/read_config_lex.l | 3 +- src/read_config_yy.y | 9 ++- src/sync-mode.c | 9 ++- 17 files changed, 266 insertions(+), 116 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index b65966b..23ab6e9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,7 @@ version 0.9.5 (yet unreleased) o conntrack-tools requires libnetfilter_conntrack >= 0.0.81 o add len field to nethdr o implement buffered send/recv to batch messages +o use buffer of MTU size o stop using netlink format for network messages: use similar TLV-based format o reduce synchronization messages size up to 60% o introduce periodic alive messages for sync-nack protocol @@ -14,6 +15,12 @@ o remove major use of libnfnetlink functions: use libnetfilter_conntrack API o deprecate conntrackd -F, use conntrack -F instead o major rework of the network infrastructure: much simple, less messy += conntrack = +o better protocol argument checkings +o fix per-protocol filtering, eg. conntrack -L -p tcp +o show per-protocol help, ie. conntrack -h -p tcp +o add alias --src for --orig-src and alias --dst for --orig-dst + version 0.9.4 (2007/07/02) ------------------------------ diff --git a/examples/sync/nack/node1/conntrackd.conf b/examples/sync/nack/node1/conntrackd.conf index edec9cf..9a7d55f 100644 --- a/examples/sync/nack/node1/conntrackd.conf +++ b/examples/sync/nack/node1/conntrackd.conf @@ -32,6 +32,7 @@ Sync { Multicast { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.100 # IP of dedicated link + Interface eth2 Group 3780 } diff --git a/examples/sync/nack/node2/conntrackd.conf b/examples/sync/nack/node2/conntrackd.conf index de5f4d2..cee16c8 100644 --- a/examples/sync/nack/node2/conntrackd.conf +++ b/examples/sync/nack/node2/conntrackd.conf @@ -31,6 +31,7 @@ Sync { Multicast { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.200 # IP of dedicated link + Interface eth2 Group 3780 } diff --git a/examples/sync/persistent/node1/conntrackd.conf b/examples/sync/persistent/node1/conntrackd.conf index 60f264b..e80921b 100644 --- a/examples/sync/persistent/node1/conntrackd.conf +++ b/examples/sync/persistent/node1/conntrackd.conf @@ -37,6 +37,7 @@ Sync { Multicast { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.100 # IP of dedicated link + Interface eth2 Group 3780 } diff --git a/examples/sync/persistent/node2/conntrackd.conf b/examples/sync/persistent/node2/conntrackd.conf index 6a1806b..ad4b040 100644 --- a/examples/sync/persistent/node2/conntrackd.conf +++ b/examples/sync/persistent/node2/conntrackd.conf @@ -37,6 +37,7 @@ Sync { Multicast { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.200 # IP of dedicated link + Interface eth2 Group 3780 } diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 765ced4..09fd8da 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -24,6 +24,33 @@ static struct option opts[] = { {0, 0, 0, 0} }; +#define ICMP_NUMBER_OF_OPT 4 + +static const char *icmp_optflags[ICMP_NUMBER_OF_OPT] = { +"icmp-type", "icmp-code", "icmp-id" +}; + +static char icmp_commands_v_options[NUMBER_OF_CMD][ICMP_NUMBER_OF_OPT] = +/* Well, it's better than "Re: Maradona vs Pele" */ +{ + /* 1 2 3 */ +/*CT_LIST*/ {2,2,2}, +/*CT_CREATE*/ {1,1,2}, +/*CT_UPDATE*/ {1,1,2}, +/*CT_DELETE*/ {1,1,2}, +/*CT_GET*/ {1,1,2}, +/*CT_FLUSH*/ {0,0,0}, +/*CT_EVENT*/ {2,2,2}, +/*CT_VERSION*/ {0,0,0}, +/*CT_HELP*/ {0,0,0}, +/*EXP_LIST*/ {0,0,0}, +/*EXP_CREATE*/ {0,0,0}, +/*EXP_DELETE*/ {0,0,0}, +/*EXP_GET*/ {0,0,0}, +/*EXP_FLUSH*/ {0,0,0}, +/*EXP_EVENT*/ {0,0,0}, +}; + static void help() { fprintf(stdout, " --icmp-type\t\t\ticmp type\n"); @@ -31,7 +58,7 @@ static void help() fprintf(stdout, " --icmp-id\t\t\ticmp id\n"); } -static int parse(char c, char *argv[], +static int parse(char c, struct nf_conntrack *ct, struct nf_conntrack *exptuple, struct nf_conntrack *mask, @@ -69,16 +96,14 @@ static int parse(char c, char *argv[], return 1; } -static int final_check(unsigned int flags, - unsigned int command, - struct nf_conntrack *ct) +static void final_check(unsigned int flags, + unsigned int cmd, + struct nf_conntrack *ct) { - if (!(flags & ICMP_TYPE)) - return 0; - else if (!(flags & ICMP_CODE)) - return 0; - - return 1; + generic_opt_check(flags, + ICMP_NUMBER_OF_OPT, + icmp_commands_v_options[cmd], + icmp_optflags); } static struct ctproto_handler icmp = { diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 5a40cef..1f630b3 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -32,6 +32,34 @@ static struct option opts[] = { {0, 0, 0, 0} }; +#define TCP_NUMBER_OF_OPT 10 + +static const char *tcp_optflags[TCP_NUMBER_OF_OPT] = { +"sport", "dport", "reply-port-src", "reply-port-dst", "mask-port-src", +"mask-port-dst", "state", "tuple-port-src", "tuple-port-dst" +}; + +static char tcp_commands_v_options[NUMBER_OF_CMD][TCP_NUMBER_OF_OPT] = +/* Well, it's better than "Re: Sevilla vs Betis" */ +{ + /* 1 2 3 4 5 6 7 8 9 */ +/*CT_LIST*/ {2,2,2,2,0,0,2,0,0}, +/*CT_CREATE*/ {1,1,1,1,0,0,1,0,0}, +/*CT_UPDATE*/ {1,1,1,1,0,0,2,0,0}, +/*CT_DELETE*/ {1,1,1,1,0,0,0,0,0}, +/*CT_GET*/ {1,1,1,1,0,0,2,0,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,0,0,2,0,0}, +/*CT_VERSION*/ {0,0,0,0,0,0,0,0,0}, +/*CT_HELP*/ {0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0}, +/*EXP_CREATE*/ {1,1,1,1,1,1,0,1,1}, +/*EXP_DELETE*/ {1,1,1,1,0,0,0,0,0}, +/*EXP_GET*/ {1,1,1,1,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0}, +}; + static const char *states[] = { "NONE", "SYN_SENT", @@ -58,7 +86,7 @@ static void help() fprintf(stdout, " --state\t\t\tTCP state, fe. ESTABLISHED\n"); } -static int parse_options(char c, char *argv[], +static int parse_options(char c, struct nf_conntrack *ct, struct nf_conntrack *exptuple, struct nf_conntrack *mask, @@ -139,10 +167,9 @@ static int parse_options(char c, char *argv[], break; } } - if (i == 10) { - printf("doh?\n"); - return 0; - } + if (i == 10) + exit_error(PARAMETER_PROBLEM, + "Unknown TCP state %s\n", optarg); *flags |= TCP_STATE; break; case '8': @@ -169,12 +196,10 @@ static int parse_options(char c, char *argv[], return 1; } -static int final_check(unsigned int flags, - unsigned int command, - struct nf_conntrack *ct) +static void final_check(unsigned int flags, + unsigned int cmd, + struct nf_conntrack *ct) { - int ret = 0; - if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) && !(flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { nfct_set_attr_u16(ct, @@ -183,7 +208,8 @@ static int final_check(unsigned int flags, nfct_set_attr_u16(ct, ATTR_REPL_PORT_DST, nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC)); - ret = 1; + flags |= TCP_REPL_SPORT; + flags |= TCP_REPL_DPORT; } else if (!(flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) && (flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { nfct_set_attr_u16(ct, @@ -192,17 +218,14 @@ static int final_check(unsigned int flags, nfct_set_attr_u16(ct, ATTR_ORIG_PORT_DST, nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)); - ret = 1; + flags |= TCP_ORIG_SPORT; + flags |= TCP_ORIG_DPORT; } - if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) - && ((flags & (TCP_REPL_SPORT|TCP_REPL_DPORT)))) - ret = 1; - - /* --state is missing and we are trying to create a conntrack */ - if (ret && (command & CT_CREATE) && (!(flags & TCP_STATE))) - ret = 0; - return ret; + generic_opt_check(flags, + TCP_NUMBER_OF_OPT, + tcp_commands_v_options[cmd], + tcp_optflags); } static struct ctproto_handler tcp = { diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index cb131d6..2216b71 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -31,6 +31,13 @@ static struct option opts[] = { {0, 0, 0, 0} }; +#define UDP_NUMBER_OF_OPT 9 + +static const char *udp_optflags[UDP_NUMBER_OF_OPT] = { +"sport", "dport", "reply-port-src", "reply-port-dst", "mask-port-src", +"mask-port-dst", "tuple-port-src", "tuple-port-dst" +}; + static void help() { fprintf(stdout, " --orig-port-src\t\toriginal source port\n"); @@ -43,7 +50,28 @@ static void help() fprintf(stdout, " --tuple-port-src\t\texpectation tuple dst port\n"); } -static int parse_options(char c, char *argv[], +static char udp_commands_v_options[NUMBER_OF_CMD][UDP_NUMBER_OF_OPT] = +/* Well, it's better than "Re: Galeano vs Vargas Llosa" */ +{ + /* 1 2 3 4 5 6 7 8 */ +/*CT_LIST*/ {2,2,2,2,0,0,0,0}, +/*CT_CREATE*/ {1,1,1,1,0,0,0,0}, +/*CT_UPDATE*/ {1,1,1,1,0,0,0,0}, +/*CT_DELETE*/ {1,1,1,1,0,0,0,0}, +/*CT_GET*/ {1,1,1,1,0,0,0,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,0,0,0,0}, +/*CT_VERSION*/ {0,0,0,0,0,0,0,0}, +/*CT_HELP*/ {0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0}, +/*EXP_CREATE*/ {1,1,1,1,1,1,1,1}, +/*EXP_DELETE*/ {1,1,1,1,0,0,0,0}, +/*EXP_GET*/ {1,1,1,1,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0}, +}; + +static int parse_options(char c, struct nf_conntrack *ct, struct nf_conntrack *exptuple, struct nf_conntrack *mask, @@ -134,9 +162,9 @@ static int parse_options(char c, char *argv[], return 1; } -static int final_check(unsigned int flags, - unsigned int command, - struct nf_conntrack *ct) +static void final_check(unsigned int flags, + unsigned int cmd, + struct nf_conntrack *ct) { int ret = 0; @@ -148,7 +176,8 @@ static int final_check(unsigned int flags, nfct_set_attr_u16(ct, ATTR_REPL_PORT_DST, nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC)); - ret = 1; + flags |= UDP_REPL_SPORT; + flags |= UDP_REPL_DPORT; } else if (!(flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) && (flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { nfct_set_attr_u16(ct, @@ -157,13 +186,14 @@ static int final_check(unsigned int flags, nfct_set_attr_u16(ct, ATTR_ORIG_PORT_DST, nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)); - ret = 1; + flags |= UDP_ORIG_SPORT; + flags |= UDP_ORIG_DPORT; } - if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) - && ((flags & (UDP_REPL_SPORT|UDP_REPL_DPORT)))) - ret = 1; - return ret; + generic_opt_check(flags, + UDP_NUMBER_OF_OPT, + udp_commands_v_options[cmd], + udp_optflags); } static struct ctproto_handler udp = { diff --git a/include/conntrack.h b/include/conntrack.h index f344d72..5edc0e9 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -151,15 +151,15 @@ struct ctproto_handler { enum ctattr_protoinfo protoinfo_attr; - int (*parse_opts)(char c, char *argv[], - struct nf_conntrack *ct, - struct nf_conntrack *exptuple, - struct nf_conntrack *mask, - unsigned int *flags); + int (*parse_opts)(char c, + struct nf_conntrack *ct, + struct nf_conntrack *exptuple, + struct nf_conntrack *mask, + unsigned int *flags); - int (*final_check)(unsigned int flags, - unsigned int command, - struct nf_conntrack *ct); + void (*final_check)(unsigned int flags, + unsigned int command, + struct nf_conntrack *ct); void (*help)(); @@ -168,6 +168,18 @@ struct ctproto_handler { unsigned int option_offset; }; +enum exittype { + OTHER_PROBLEM = 1, + PARAMETER_PROBLEM, + VERSION_PROBLEM +}; + +void generic_opt_check(int options, + int nops, + char *optset, + const char *optflg[]); +void exit_error(enum exittype status, char *msg, ...); + extern void register_proto(struct ctproto_handler *h); extern void register_tcp(void); diff --git a/include/mcast.h b/include/mcast.h index 66676dc..d4fd335 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -2,6 +2,7 @@ #define _MCAST_H_ #include +#include struct mcast_conf { int ipproto; @@ -16,6 +17,8 @@ struct mcast_conf { struct in_addr interface_addr; struct in6_addr interface_addr6; } ifa; + int mtu; + char iface[IFNAMSIZ]; }; struct mcast_stats { diff --git a/include/network.h b/include/network.h index bc9431d..f8fdd0d 100644 --- a/include/network.h +++ b/include/network.h @@ -55,6 +55,13 @@ int prepare_send_netmsg(struct mcast_sock *m, void *data); int mcast_send_netmsg(struct mcast_sock *m, void *data); int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len); +struct mcast_conf; + +int mcast_buffered_init(struct mcast_conf *conf); +void mcast_buffered_destroy(); +int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len); +int mcast_buffered_pending_netmsg(struct mcast_sock *m); + #define IS_DATA(x) ((x->flags & ~NET_F_HELLO) == 0) #define IS_ACK(x) (x->flags & NET_F_ACK) #define IS_NACK(x) (x->flags & NET_F_NACK) diff --git a/src/conntrack.c b/src/conntrack.c index eece45b..165809b 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -64,8 +64,10 @@ static const char cmdflags[NUMBER_OF_CMD] static const char cmd_need_param[NUMBER_OF_CMD] = { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2 }; -static const char optflags[NUMBER_OF_OPT] -= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f','n','g','x'}; +static const char *optflags[NUMBER_OF_OPT] = { +"src","dst","reply-src","reply-dst","protonum","timeout","status","zero", +"event-mask","tuple-src","tuple-dst","mask-src","mask-dst","nat-range","mark", +"id","family","src-nat","dst-nat","output" }; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, @@ -78,7 +80,9 @@ static struct option original_opts[] = { {"version", 0, 0, 'V'}, {"help", 0, 0, 'h'}, {"orig-src", 1, 0, 's'}, + {"src", 1, 0, 's'}, {"orig-dst", 1, 0, 'd'}, + {"dst", 1, 0, 'd'}, {"reply-src", 1, 0, 'r'}, {"reply-dst", 1, 0, 'q'}, {"protonum", 1, 0, 'p'}, @@ -127,7 +131,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2}, /*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*HELP*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0}, /*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0}, /*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, @@ -172,12 +176,6 @@ static struct ctproto_handler *findproto(char *name) return handler; } -enum exittype { - OTHER_PROBLEM = 1, - PARAMETER_PROBLEM, - VERSION_PROBLEM -}; - void extension_help(struct ctproto_handler *h) { fprintf(stdout, "\n"); @@ -193,8 +191,7 @@ exit_tryhelp(int status) exit(status); } -static void -exit_error(enum exittype status, char *msg, ...) +void exit_error(enum exittype status, char *msg, ...) { va_list args; @@ -218,51 +215,43 @@ exit_error(enum exittype status, char *msg, ...) static void generic_cmd_check(int command, int options) { - int i; - - for (i = 0; i < NUMBER_OF_CMD; i++) { - if (!(command & (1< illegal, 1 => legal, 0 => undecided. */ + for (i = 0; i < NUMBER_OF_CMD; i++) + if (command & (1<parse_opts - &&!h->parse_opts(c - h->option_offset, argv, obj, + &&!h->parse_opts(c - h->option_offset, obj, exptuple, mask, &l4flags)) exit_error(PARAMETER_PROBLEM, "parse error\n"); @@ -996,16 +985,15 @@ int main(int argc, char *argv[]) if (family == AF_UNSPEC) family = AF_INET; - generic_cmd_check(command, options); - generic_opt_check(command, options); + cmd = bit2cmd(command); + generic_cmd_check(cmd, options); + generic_opt_check(options, + NUMBER_OF_OPT, + commands_v_options[cmd], + optflags); - if (!(command & CT_HELP) - && h && h->final_check - && !h->final_check(l4flags, command, obj)) { - usage(argv[0]); - extension_help(h); - exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); - } + if (!(command & CT_HELP) && h && h->final_check) + h->final_check(l4flags, cmd, obj); switch(command) { diff --git a/src/mcast.c b/src/mcast.c index 6193a59..cdaed5f 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include "mcast.h" #include "debug.h" @@ -71,6 +73,18 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return NULL; } + if(conf->iface[0]) { + struct ifreq ifr; + + strncpy(ifr.ifr_name, conf->iface, sizeof(ifr.ifr_name)); + + if (ioctl(m->fd, SIOCGIFMTU, &ifr) == -1) { + debug("ioctl"); + return NULL; + } + conf->mtu = ifr.ifr_mtu; + } + if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { debug("mcast_sock_server_create:setsockopt1"); diff --git a/src/network.c b/src/network.c index d162839..a7843dc 100644 --- a/src/network.c +++ b/src/network.c @@ -90,9 +90,33 @@ int prepare_send_netmsg(struct mcast_sock *m, void *data) return ret; } +static int tx_buflenmax; static int tx_buflen = 0; -/* XXX: use buffer size of interface MTU */ -static char __tx_buf[1460], *tx_buf = __tx_buf; +static char *tx_buf; + +#define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ + +int mcast_buffered_init(struct mcast_conf *conf) +{ + int mtu = conf->mtu - HEADERSIZ; + + /* default to Ethernet MTU 1500 bytes */ + if (mtu == 0) + mtu = 1500 - HEADERSIZ; + + tx_buf = malloc(mtu); + if (tx_buf == NULL) + return -1; + + tx_buflenmax = mtu; + + return 0; +} + +void mcast_buffered_destroy(void) +{ + free(tx_buf); +} /* return 0 if it is not sent, otherwise return 1 */ int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len) @@ -101,8 +125,8 @@ int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len) struct nethdr *net = data; retry: - if (tx_buflen + len < sizeof(__tx_buf)) { - memcpy(__tx_buf + tx_buflen, net, len); + if (tx_buflen + len < tx_buflenmax) { + memcpy(tx_buf + tx_buflen, net, len); tx_buflen += len; } else { __do_send(m, tx_buf, tx_buflen); diff --git a/src/read_config_lex.l b/src/read_config_lex.l index dee90c9..87e98d1 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -42,7 +42,7 @@ ip6_part {hex_255}":"? ip6_form1 {ip6_part}{0,16}"::"{ip6_part}{0,16} ip6_form2 ({hex_255}":"){16}{hex_255} ip6 {ip6_form1}|{ip6_form2} -string [a-zA-Z]* +string [a-zA-Z0-9]* persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] nack [N|n][A|a][C|c][K|k] @@ -52,6 +52,7 @@ nack [N|n][A|a][C|c][K|k] "IPv6_address" { return T_IPV6_ADDR; } "IPv4_interface" { return T_IPV4_IFACE; } "IPv6_interface" { return T_IPV6_IFACE; } +"Interface" { return T_IFACE; } "Port" { return T_PORT; } "Multicast" { return T_MULTICAST; } "HashSize" { return T_HASHSIZE; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 57250b4..de592d2 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -1,6 +1,6 @@ %{ /* - * (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 @@ -45,7 +45,7 @@ struct ct_conf conf; %token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY %token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE %token T_PERSISTENT T_NACK T_CHECKSUM T_WINDOWSIZE T_ON T_OFF -%token T_REPLICATE T_FOR +%token T_REPLICATE T_FOR T_IFACE %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN @@ -227,6 +227,11 @@ multicast_option : T_IPV6_IFACE T_IP conf.mcast.ipproto = AF_INET6; }; +multicast_option : T_IFACE T_STRING +{ + strncpy(conf.mcast.iface, $2, IFNAMSIZ); +}; + multicast_option : T_BACKLOG T_NUMBER { fprintf(stderr, "Notice: Backlog option inside Multicast clause is " diff --git a/src/sync-mode.c b/src/sync-mode.c index f30cb95..917a3b2 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -86,7 +86,7 @@ retry: static void mcast_handler() { int numbytes, remain; - char __net[4096], *ptr = __net; + char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net)); if (numbytes <= 0) @@ -173,6 +173,11 @@ static int init_sync(void) return -1; } + if (mcast_buffered_init(&CONFIG(mcast)) == -1) { + dlog(STATE(log), "[FAIL] can't init tx buffer!"); + return -1; + } + /* initialization of multicast sequence generation */ STATE_SYNC(last_seq_sent) = time(NULL); @@ -207,6 +212,8 @@ static void kill_sync() mcast_server_destroy(STATE_SYNC(mcast_server)); mcast_client_destroy(STATE_SYNC(mcast_client)); + mcast_buffered_destroy(); + if (STATE_SYNC(sync)->kill) STATE_SYNC(sync)->kill(); } -- cgit v1.2.3 From f2e700dd7c1eb7325d8ce51f7e35b652cceac151 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 13:37:47 +0000 Subject: Max Kellermann : use the comma operator instead of curly braces --- ChangeLog | 1 + include/network.h | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index 6f6f890..8d95e48 100644 --- a/ChangeLog +++ b/ChangeLog @@ -56,6 +56,7 @@ o remove prefetch in slist.h since it confuses gcc o fix illegal use of return in the yacc code, use break instead o fix wrong invocations after prototype cleanup o set the return type of the parse functions to "void" +o use the comma operator instead of curly braces version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/network.h b/include/network.h index f8fdd0d..e92f6c3 100644 --- a/include/network.h +++ b/include/network.h @@ -152,10 +152,10 @@ struct netattr { (void *)(((char *)x) + sizeof(struct netattr)) #define NTA_NEXT(x, len) \ -({ \ - len -= NTA_ALIGN(NTA_LENGTH(x->nta_len)); \ - (struct netattr *)(((char *)x) + NTA_ALIGN(NTA_LENGTH(x->nta_len))); \ -}) +( \ + len -= NTA_ALIGN(NTA_LENGTH(x->nta_len)), \ + (struct netattr *)(((char *)x) + NTA_ALIGN(NTA_LENGTH(x->nta_len))) \ +) #define NTA_ALIGNTO 4 #define NTA_ALIGN(len) (((len) + NTA_ALIGNTO - 1) & ~(NTA_ALIGNTO - 1)) -- cgit v1.2.3 From 4e37e2d9079b4c1890a39f26e5082d6b1e7d0024 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 13:39:46 +0000 Subject: Max Kellermann : add missing function prototypes --- ChangeLog | 1 + include/alarm.h | 17 +++++++++++++++++ include/conntrackd.h | 6 ++++++ include/ignore.h | 1 + include/network.h | 6 ++++++ src/cache_iterators.c | 1 + src/cache_wt.c | 1 + src/main.c | 4 ---- src/netlink.c | 4 ++++ src/network.c | 1 + src/run.c | 1 + src/stats-mode.c | 2 ++ src/sync-mode.c | 4 ++++ src/traffic_stats.c | 1 + 14 files changed, 46 insertions(+), 4 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index 8d95e48..d417dab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -57,6 +57,7 @@ o fix illegal use of return in the yacc code, use break instead o fix wrong invocations after prototype cleanup o set the return type of the parse functions to "void" o use the comma operator instead of curly braces +o add missing function prototypes version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/alarm.h b/include/alarm.h index fbe34f6..c68e7f4 100644 --- a/include/alarm.h +++ b/include/alarm.h @@ -17,4 +17,21 @@ set_alarm_expiration(struct alarm_list *t, long tv_sec, long tv_usec) t->tv.tv_usec = tv_usec; } +void set_alarm_function(struct alarm_list *t, + void (*fcn)(struct alarm_list *a, void *data)); + +void set_alarm_data(struct alarm_list *t, void *data); + +void init_alarm(struct alarm_list *t); + +void add_alarm(struct alarm_list *alarm); + +void del_alarm(struct alarm_list *alarm); + +void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc); + +int get_next_alarm(struct timeval *tv, struct timeval *next_alarm); + +int do_alarm_run(struct timeval *next_alarm); + #endif diff --git a/include/conntrackd.h b/include/conntrackd.h index e8b90cc..33732a4 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -175,4 +175,10 @@ extern struct ct_mode stats_mode; #define MAX(x, y) x > y ? x : y +/* These live in run.c */ +void killer(int foo); +void local_handler(int fd, void *data); +int init(void); +void run(void); + #endif diff --git a/include/ignore.h b/include/ignore.h index 40cb02d..96deb93 100644 --- a/include/ignore.h +++ b/include/ignore.h @@ -8,5 +8,6 @@ struct ignore_pool { struct ignore_pool *ignore_pool_create(u_int8_t family); void ignore_pool_destroy(struct ignore_pool *ip); int ignore_pool_add(struct ignore_pool *ip, void *data); +int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct); #endif diff --git a/include/network.h b/include/network.h index e92f6c3..88ff43b 100644 --- a/include/network.h +++ b/include/network.h @@ -54,6 +54,8 @@ void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); int prepare_send_netmsg(struct mcast_sock *m, void *data); int mcast_send_netmsg(struct mcast_sock *m, void *data); int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len); +int handle_netmsg(struct nethdr *net); +int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq); struct mcast_conf; @@ -161,4 +163,8 @@ struct netattr { #define NTA_ALIGN(len) (((len) + NTA_ALIGNTO - 1) & ~(NTA_ALIGNTO - 1)) #define NTA_LENGTH(len) (NTA_ALIGN(sizeof(struct netattr)) + (len)) +void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query); + +void parse_netpld(struct nf_conntrack *ct, struct netpld *pld, int *query); + #endif diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 85f87ab..d43ae6f 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -20,6 +20,7 @@ #include "jhash.h" #include "hash.h" #include "conntrackd.h" +#include "netlink.h" #include #include #include "us-conntrack.h" diff --git a/src/cache_wt.c b/src/cache_wt.c index 2a9d8e7..fee17e2 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -16,6 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "netlink.h" #include #include "conntrackd.h" #include "us-conntrack.h" diff --git a/src/main.c b/src/main.c index 19d999a..2497a7f 100644 --- a/src/main.c +++ b/src/main.c @@ -61,10 +61,6 @@ void show_usage(char *progname) fprintf(stdout, "%s\n", usage_options); } -/* These live in run.c */ -int init(void); -void run(void); - void set_operation_mode(int *current, int want, char *argv[]) { if (*current == NOT_SET) { diff --git a/src/netlink.c b/src/netlink.c index ab945d8..7800b10 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -16,7 +16,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "netlink.h" #include "conntrackd.h" +#include "traffic_stats.h" +#include "ignore.h" +#include "log.h" #include #include #include diff --git a/src/network.c b/src/network.c index 8f1dc94..e7ffbac 100644 --- a/src/network.c +++ b/src/network.c @@ -20,6 +20,7 @@ #include "network.h" #include "us-conntrack.h" #include "sync.h" +#include "log.h" static unsigned int seq_set, cur_seq; diff --git a/src/run.c b/src/run.c index 8919b6c..7fbeaf5 100644 --- a/src/run.c +++ b/src/run.c @@ -19,6 +19,7 @@ */ #include "conntrackd.h" +#include "netlink.h" #include #include #include "us-conntrack.h" diff --git a/src/stats-mode.c b/src/stats-mode.c index de53751..0983b97 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "netlink.h" +#include "traffic_stats.h" #include #include "cache.h" #include "log.h" diff --git a/src/sync-mode.c b/src/sync-mode.c index c3630b6..8be8c18 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -16,6 +16,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "netlink.h" +#include "traffic_stats.h" +#include "log.h" #include #include "cache.h" #include "conntrackd.h" @@ -28,6 +31,7 @@ #include "sync.h" #include "network.h" #include "debug.h" +#include static void do_mcast_handler_step(struct nethdr *net) { diff --git a/src/traffic_stats.c b/src/traffic_stats.c index b510b77..b2cdaae 100644 --- a/src/traffic_stats.c +++ b/src/traffic_stats.c @@ -16,6 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "traffic_stats.h" #include "cache.h" #include "hash.h" #include "conntrackd.h" -- cgit v1.2.3 From 82290b2b0bd2ebb5539b61b98e993ae807c2e8d7 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 14:00:14 +0000 Subject: Max Kellermann : Fix tons of gcc warnings --- ChangeLog | 3 ++- extensions/libct_proto_icmp.c | 2 +- extensions/libct_proto_tcp.c | 2 +- extensions/libct_proto_udp.c | 4 +--- include/cache.h | 2 +- include/conntrack.h | 8 ++++---- include/conntrackd.h | 4 ++++ include/debug.h | 4 ++-- include/linux_list.h | 2 +- include/log.h | 6 +++--- include/network.h | 2 +- src/alarm.c | 3 ++- src/buffer.c | 1 + src/cache.c | 28 ++++++++++++++------------- src/cache_iterators.c | 5 +++-- src/cache_lifetime.c | 2 ++ src/cache_timer.c | 2 +- src/cache_wt.c | 2 +- src/conntrack.c | 44 ++++++++++++++++++++++++++----------------- src/hash.c | 8 ++------ src/ignore_pool.c | 10 +++++++--- src/local.c | 2 +- src/log.c | 9 +++++---- src/main.c | 12 +++++++++--- src/mcast.c | 10 ++++++---- src/network.c | 5 ++--- src/read_config_yy.y | 2 +- src/run.c | 17 +++++++++++++---- src/stats-mode.c | 6 ++---- src/sync-alarm.c | 2 ++ src/sync-ftfw.c | 9 +++++---- src/sync-mode.c | 2 +- src/traffic_stats.c | 4 ++-- 33 files changed, 131 insertions(+), 93 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index 6543aaf..f42234a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -42,7 +42,6 @@ o wake up the daemon iff there are real events to handle instead of polling o add support for tagged vlan interfaces in the config file, e.g. eth0.1 o improve alarm framework based on suggestions from Max Kellerman o constify queue_iterate() -o use timeradd() since manipulating tv_sec directly Max Kellermann : @@ -63,6 +62,8 @@ o merge several *_alarm() functions into init_alarm() o use add_alarm() in mod_alarm() to avoid code duplication o import tcp_state_helper only once o add missing printf arguments +o use timeradd() since manipulating tv_sec directly +o fix lots of gcc warnings version 0.9.5 (2007/07/29) ------------------------------ diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 09fd8da..7c59072 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -51,7 +51,7 @@ static char icmp_commands_v_options[NUMBER_OF_CMD][ICMP_NUMBER_OF_OPT] = /*EXP_EVENT*/ {0,0,0}, }; -static void help() +static void help(void) { fprintf(stdout, " --icmp-type\t\t\ticmp type\n"); fprintf(stdout, " --icmp-code\t\t\ticmp code\n"); diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 1f630b3..a3b1826 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -73,7 +73,7 @@ static const char *states[] = { "LISTEN" }; -static void help() +static void help(void) { fprintf(stdout, " --orig-port-src\t\toriginal source port\n"); fprintf(stdout, " --orig-port-dst\t\toriginal destination port\n"); diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 2216b71..267e3d6 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -38,7 +38,7 @@ static const char *udp_optflags[UDP_NUMBER_OF_OPT] = { "mask-port-dst", "tuple-port-src", "tuple-port-dst" }; -static void help() +static void help(void) { fprintf(stdout, " --orig-port-src\t\toriginal source port\n"); fprintf(stdout, " --orig-port-dst\t\toriginal destination port\n"); @@ -166,8 +166,6 @@ static void final_check(unsigned int flags, unsigned int cmd, struct nf_conntrack *ct) { - int ret = 0; - if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) && !(flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { nfct_set_attr_u16(ct, diff --git a/include/cache.h b/include/cache.h index 5ca6ce4..e4fb945 100644 --- a/include/cache.h +++ b/include/cache.h @@ -75,7 +75,7 @@ struct cache_extra { struct nf_conntrack; -struct cache *cache_create(char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra); +struct cache *cache_create(const char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra); void cache_destroy(struct cache *e); struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct); diff --git a/include/conntrack.h b/include/conntrack.h index 1b2581e..8f2b6a2 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -148,9 +148,9 @@ enum { struct ctproto_handler { struct list_head head; - char *name; + const char *name; u_int16_t protonum; - char *version; + const char *version; enum ctattr_protoinfo protoinfo_attr; @@ -164,7 +164,7 @@ struct ctproto_handler { unsigned int command, struct nf_conntrack *ct); - void (*help)(); + void (*help)(void); struct option *opts; @@ -181,7 +181,7 @@ void generic_opt_check(int options, int nops, char *optset, const char *optflg[]); -void exit_error(enum exittype status, char *msg, ...); +void exit_error(enum exittype status, const char *msg, ...); extern void register_proto(struct ctproto_handler *h); diff --git a/include/conntrackd.h b/include/conntrackd.h index 33732a4..d3f66ba 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -181,4 +181,8 @@ void local_handler(int fd, void *data); int init(void); void run(void); +/* from read_config_yy.c */ +int +init_config(char *filename); + #endif diff --git a/include/debug.h b/include/debug.h index 1ffd9ac..f205983 100644 --- a/include/debug.h +++ b/include/debug.h @@ -14,8 +14,8 @@ }) #define debug printf #else -#define debug_ct(ct, msg) -#define debug +#define debug_ct(ct, msg) do {} while (0) +#define debug(...) do {} while (0) #endif #endif diff --git a/include/linux_list.h b/include/linux_list.h index 57b56d7..b84b1c4 100644 --- a/include/linux_list.h +++ b/include/linux_list.h @@ -13,7 +13,7 @@ * */ #define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) /* diff --git a/include/log.h b/include/log.h index b5bbddb..64bf1ce 100644 --- a/include/log.h +++ b/include/log.h @@ -6,10 +6,10 @@ struct buffer; struct nf_conntrack; -int init_log(); -void dlog(FILE *fd, int priority, char *format, ...); +int init_log(void); +void dlog(FILE *fd, int priority, const char *format, ...); void dlog_buffered_ct(FILE *fd, struct buffer *b, struct nf_conntrack *ct); void dlog_buffered_ct_flush(void *buffer_data, void *data); -void close_log(); +void close_log(void); #endif diff --git a/include/network.h b/include/network.h index 88ff43b..d0b639b 100644 --- a/include/network.h +++ b/include/network.h @@ -60,7 +60,7 @@ int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq); struct mcast_conf; int mcast_buffered_init(struct mcast_conf *conf); -void mcast_buffered_destroy(); +void mcast_buffered_destroy(void); int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len); int mcast_buffered_pending_netmsg(struct mcast_sock *m); diff --git a/src/alarm.c b/src/alarm.c index 3467e7b..25075ef 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -36,7 +36,8 @@ void init_alarm(struct alarm_list *t, t->function = fcn; } -void __add_alarm(struct alarm_list *alarm) +static void +__add_alarm(struct alarm_list *alarm) { struct alarm_list *t; diff --git a/src/buffer.c b/src/buffer.c index 4f60123..79266a7 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -50,6 +50,7 @@ int buffer_add(struct buffer *b, void *data, unsigned int size) memcpy(b->data + b->cur_size, data, size); b->cur_size += size; + return 0; } void buffer_flush(struct buffer *b, diff --git a/src/cache.c b/src/cache.c index a0950d5..c5afb00 100644 --- a/src/cache.c +++ b/src/cache.c @@ -23,6 +23,7 @@ #include #include "us-conntrack.h" #include "cache.h" +#include static u_int32_t hash(const void *data, struct hashtable *table) { @@ -120,7 +121,7 @@ struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { [WRITE_THROUGH_FEATURE] = &writethrough_feature, }; -struct cache *cache_create(char *name, +struct cache *cache_create(const char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra) @@ -209,7 +210,7 @@ void cache_destroy(struct cache *c) static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) { - int i; + unsigned i; size_t size = c->h->datasize; char buf[size]; struct us_conntrack *u = (struct us_conntrack *) buf; @@ -226,7 +227,7 @@ static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) u = hashtable_add(c->h, u); if (u) { - void *data = u->data; + char *data = u->data; for (i = 0; i < c->num_features; i++) { c->features[i]->add(u, data); @@ -234,7 +235,7 @@ static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) } if (c->extra && c->extra->add) - c->extra->add(u, ((void *) u) + c->extra_offset); + c->extra->add(u, ((char *) u) + c->extra_offset); return u; } @@ -268,8 +269,8 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) u = (struct us_conntrack *) hashtable_test(c->h, u); if (u) { - int i; - void *data = u->data; + unsigned i; + char *data = u->data; if (nfct_attr_is_set(ct, ATTR_STATUS)) nfct_set_attr_u32(u->ct, ATTR_STATUS, @@ -287,14 +288,15 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) } if (c->extra && c->extra->update) - c->extra->update(u, ((void *) u) + c->extra_offset); + c->extra->update(u, ((char *) u) + c->extra_offset); return u; } return NULL; } -struct us_conntrack *__cache_update(struct cache *c, struct nf_conntrack *ct) +static struct us_conntrack * +__cache_update(struct cache *c, struct nf_conntrack *ct) { struct us_conntrack *u; @@ -358,8 +360,8 @@ static int __del(struct cache *c, struct nf_conntrack *ct) u = (struct us_conntrack *) hashtable_test(c->h, u); if (u) { - int i; - void *data = u->data; + unsigned i; + char *data = u->data; struct nf_conntrack *p = u->ct; for (i = 0; i < c->num_features; i++) { @@ -368,7 +370,7 @@ static int __del(struct cache *c, struct nf_conntrack *ct) } if (c->extra && c->extra->destroy) - c->extra->destroy(u, ((void *) u) + c->extra_offset); + c->extra->destroy(u, ((char *) u) + c->extra_offset); hashtable_del(c->h, u); free(p); @@ -390,12 +392,12 @@ int cache_del(struct cache *c, struct nf_conntrack *ct) struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) { - return data - c->extra_offset; + return (struct us_conntrack *)((char*)data - c->extra_offset); } void *cache_get_extra(struct cache *c, void *data) { - return data + c->extra_offset; + return (char*)data + c->extra_offset; } void cache_stats(const struct cache *c, int fd) diff --git a/src/cache_iterators.c b/src/cache_iterators.c index d43ae6f..4fdb920 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -19,6 +19,7 @@ #include "cache.h" #include "jhash.h" #include "hash.h" +#include "log.h" #include "conntrackd.h" #include "netlink.h" #include @@ -36,8 +37,8 @@ static int do_dump(void *data1, void *data2) int size; struct __dump_container *container = data1; struct us_conntrack *u = data2; - void *data = u->data; - int i; + char *data = u->data; + unsigned i; memset(buf, 0, sizeof(buf)); size = nfct_snprintf(buf, diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c index ae54df2..26496d2 100644 --- a/src/cache_lifetime.c +++ b/src/cache_lifetime.c @@ -21,6 +21,8 @@ #include "us-conntrack.h" #include "cache.h" #include "alarm.h" +#include +#include static void lifetime_add(struct us_conntrack *u, void *data) { diff --git a/src/cache_timer.c b/src/cache_timer.c index 8b4e4ea..53ed703 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -62,7 +62,7 @@ static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type) gettimeofday(&tv, NULL); timersub(&tv, &alarm->tv, &tmp); - return sprintf(buf, " [expires in %ds]", tmp.tv_sec); + return sprintf(buf, " [expires in %lds]", tmp.tv_sec); } struct cache_feature timer_feature = { diff --git a/src/cache_wt.c b/src/cache_wt.c index fee17e2..9d0af0b 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -25,7 +25,7 @@ static void add_update(struct us_conntrack *u) { char __ct[nfct_maxsize()]; - struct nf_conntrack *ct = (struct nf_conntrack *) __ct; + struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; memcpy(ct, u->ct, nfct_maxsize()); diff --git a/src/conntrack.c b/src/conntrack.c index 28340c1..f301a82 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -45,6 +45,8 @@ #include #include #include +#include +#include #ifdef HAVE_ARPA_INET_H #include #endif @@ -175,14 +177,15 @@ static struct ctproto_handler *findproto(char *name) return handler; } -void extension_help(struct ctproto_handler *h) +static void +extension_help(struct ctproto_handler *h) { fprintf(stdout, "\n"); fprintf(stdout, "Proto `%s' help:\n", h->name); h->help(); } -void +static void __attribute__((noreturn)) exit_tryhelp(int status) { fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", @@ -190,7 +193,8 @@ exit_tryhelp(int status) exit(status); } -void exit_error(enum exittype status, char *msg, ...) +void __attribute__((noreturn)) +exit_error(enum exittype status, const char *msg, ...) { va_list args; @@ -281,7 +285,7 @@ merge_options(struct option *oldopts, const struct option *newopts, #define ENOTSUPP 524 /* Operation is not supported */ /* Translates errno numbers into more human-readable form than strerror. */ -const char * +static const char * err2str(int err, enum action command) { unsigned int i; @@ -318,7 +322,7 @@ err2str(int err, enum action command) #define PARSE_MAX 3 static struct parse_parameter { - char *parameter[6]; + const char *parameter[6]; size_t size; unsigned int value[6]; } parse_array[PARSE_MAX] = { @@ -336,7 +340,8 @@ static int do_parse_parameter(const char *str, size_t str_length, unsigned int *value, int parse_type) { - int i, ret = 0; + size_t i; + int ret = 0; struct parse_parameter *p = &parse_array[parse_type]; if (strncasecmp(str, "SRC_NAT", str_length) == 0) { @@ -384,7 +389,8 @@ add_command(unsigned int *cmd, const int newcmd, const int othercmds) *cmd |= newcmd; } -unsigned int check_type(int argc, char *argv[]) +static unsigned int +check_type(int argc, char *argv[]) { char *table = NULL; @@ -424,7 +430,8 @@ struct addr_parse { unsigned int family; }; -int parse_inetaddr(const char *cp, struct addr_parse *parse) +static int +parse_inetaddr(const char *cp, struct addr_parse *parse) { if (inet_aton(cp, &parse->addr)) return AF_INET; @@ -441,7 +448,8 @@ union ct_address { u_int32_t v6[4]; }; -int parse_addr(const char *cp, union ct_address *address) +static int +parse_addr(const char *cp, union ct_address *address) { struct addr_parse parse; int ret; @@ -458,7 +466,7 @@ int parse_addr(const char *cp, union ct_address *address) static void nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) { - char *colon, *dash, *error; + char *colon, *error; union ct_address parse; colon = strchr(arg, ':'); @@ -495,7 +503,8 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) nfct_set_attr_u32(obj, ATTR_DNAT_IPV4, parse.v4); } -static void event_sighandler(int s) +static void __attribute__((noreturn)) +event_sighandler(int s) { fprintf(stdout, "Now closing conntrack event dumping...\n"); nfct_close(cth); @@ -524,7 +533,6 @@ static const char usage_conntrack_parameters[] = " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" " -z, --zero \t\t\t\tZero counters while listing\n" " -o, --output type[,...]\t\tOutput format, eg. xml\n"; - ; static const char usage_expectation_parameters[] = "Expectation parameters and options:\n" @@ -546,7 +554,9 @@ static const char usage_parameters[] = ; -void usage(char *prog) { +static void +usage(char *prog) +{ fprintf(stdout, "Command line interface for the connection " "tracking system. Version %s\n", VERSION); fprintf(stdout, "Usage: %s [commands] [options]\n", prog); @@ -662,11 +672,11 @@ int main(int argc, char *argv[]) char __obj[nfct_maxsize()]; char __exptuple[nfct_maxsize()]; char __mask[nfct_maxsize()]; - struct nf_conntrack *obj = (struct nf_conntrack *) __obj; - struct nf_conntrack *exptuple = (struct nf_conntrack *) __exptuple; - struct nf_conntrack *mask = (struct nf_conntrack *) __mask; + struct nf_conntrack *obj = (struct nf_conntrack *)(void*) __obj; + struct nf_conntrack *exptuple = (struct nf_conntrack *)(void*) __exptuple; + struct nf_conntrack *mask = (struct nf_conntrack *)(void*) __mask; char __exp[nfexp_maxsize()]; - struct nf_expect *exp = (struct nf_expect *) __exp; + struct nf_expect *exp = (struct nf_expect *)(void*) __exp; int l3protonum; union ct_address ad; unsigned int command; diff --git a/src/hash.c b/src/hash.c index 3ed6ad2..553dd1d 100644 --- a/src/hash.c +++ b/src/hash.c @@ -53,7 +53,6 @@ hashtable_create(int hashsize, int limit, int datasize, { int i; struct hashtable *h; - struct hashtype *t; int size = sizeof(struct hashtable) + hashsize * sizeof(struct slist_head); @@ -87,7 +86,6 @@ void *hashtable_add(struct hashtable *table, void *data) struct slist_head *e; struct hashtable_node *n; u_int32_t id; - int i; /* hash table is full */ if (table->count >= table->limit) { @@ -122,7 +120,6 @@ void *hashtable_test(struct hashtable *table, const void *data) struct slist_head *e; u_int32_t id; struct hashtable_node *n; - int i; id = table->hash(data, table); @@ -141,7 +138,6 @@ int hashtable_del(struct hashtable *table, void *data) struct slist_head *e, *next, *prev; u_int32_t id; struct hashtable_node *n; - int i; id = table->hash(data, table); @@ -160,7 +156,7 @@ int hashtable_del(struct hashtable *table, void *data) int hashtable_flush(struct hashtable *table) { - int i; + u_int32_t i; struct slist_head *e, *next, *prev; struct hashtable_node *n; @@ -179,7 +175,7 @@ int hashtable_flush(struct hashtable *table) int hashtable_iterate(struct hashtable *table, void *data, int (*iterate)(void *data1, void *data2)) { - int i; + u_int32_t i; struct slist_head *e, *next, *prev; struct hashtable_node *n; diff --git a/src/ignore_pool.c b/src/ignore_pool.c index ee457ba..82afa93 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -20,8 +20,11 @@ #include "hash.h" #include "conntrackd.h" #include "ignore.h" +#include "log.h" #include +#include + /* XXX: These should be configurable */ #define IGNORE_POOL_SIZE 128 #define IGNORE_POOL_LIMIT INT_MAX @@ -53,7 +56,6 @@ static int compare6(const void *data1, const void *data2) struct ignore_pool *ignore_pool_create(u_int8_t proto) { - int i, j = 0; struct ignore_pool *ip; ip = malloc(sizeof(struct ignore_pool)); @@ -100,7 +102,8 @@ int ignore_pool_add(struct ignore_pool *ip, void *data) return 1; } -int __ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct) +static int +__ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct) { return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST)) || @@ -108,7 +111,8 @@ int __ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct) hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_DST))); } -int __ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct) +static int +__ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct) { return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) || diff --git a/src/local.c b/src/local.c index be51b9e..9ff5f82 100644 --- a/src/local.c +++ b/src/local.c @@ -68,7 +68,7 @@ int do_local_server_step(int fd, void *data, { int rfd; struct sockaddr_un local; - size_t sin_size = sizeof(struct sockaddr_un); + socklen_t sin_size = sizeof(struct sockaddr_un); if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) return -1; diff --git a/src/log.c b/src/log.c index 51109b6..b42e049 100644 --- a/src/log.c +++ b/src/log.c @@ -18,7 +18,7 @@ * Description: Logging support for the conntrack daemon */ -#include +#include "log.h" #include #include #include @@ -26,6 +26,7 @@ #include #include #include +#include #include "buffer.h" #include "conntrackd.h" @@ -78,11 +79,11 @@ int init_log(void) return 0; } -void dlog(FILE *fd, int priority, char *format, ...) +void dlog(FILE *fd, int priority, const char *format, ...) { time_t t; char *buf; - char *prio; + const char *prio; va_list args; if (fd) { @@ -125,7 +126,7 @@ void dlog_buffered_ct_flush(void *buffer_data, void *data) { FILE *fd = data; - fprintf(fd, "%s", buffer_data); + fprintf(fd, "%s", (const char*)buffer_data); fflush(fd); } diff --git a/src/main.c b/src/main.c index 2497a7f..11974ff 100644 --- a/src/main.c +++ b/src/main.c @@ -28,6 +28,9 @@ #include "hash.h" #include "jhash.h" +#undef _POSIX_SOURCE +#include + struct ct_general_state st; union ct_state state; @@ -52,7 +55,8 @@ static const char usage_options[] = "Options:\n" " -C [configfile], configuration file path\n"; -void show_usage(char *progname) +static void +show_usage(char *progname) { fprintf(stdout, "Connection tracking userspace daemon v%s\n", VERSION); fprintf(stdout, "Usage: %s [commands] [options]\n\n", progname); @@ -61,7 +65,8 @@ void show_usage(char *progname) fprintf(stdout, "%s\n", usage_options); } -void set_operation_mode(int *current, int want, char *argv[]) +static void +set_operation_mode(int *current, int want, char *argv[]) { if (*current == NOT_SET) { *current = want; @@ -109,7 +114,7 @@ static int check_capabilities(void) int main(int argc, char *argv[]) { - int ret, i, config_set = 0, action; + int ret, i, config_set = 0, action = -1; char config_file[PATH_MAX]; int type = 0; struct utsname u; @@ -305,4 +310,5 @@ int main(int argc, char *argv[]) * run main process */ run(); + return 0; } diff --git a/src/mcast.c b/src/mcast.c index cdaed5f..cf03593 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -192,7 +192,6 @@ __mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf) struct mcast_sock *mcast_client_create(struct mcast_conf *conf) { int ret = 0; - struct sockaddr_in addr; struct mcast_sock *m; m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock)); @@ -300,9 +299,12 @@ void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r) "%20llu Pckts recv\n" "%20llu Error send " "%20llu Error recv\n\n", - s->stats.bytes, r->stats.bytes, - s->stats.messages, r->stats.messages, - s->stats.error, r->stats.error); + (unsigned long long)s->stats.bytes, + (unsigned long long)r->stats.bytes, + (unsigned long long)s->stats.messages, + (unsigned long long)r->stats.messages, + (unsigned long long)s->stats.error, + (unsigned long long)r->stats.error); send(fd, buf, size, 0); } diff --git a/src/network.c b/src/network.c index e7ffbac..9d6e6e1 100644 --- a/src/network.c +++ b/src/network.c @@ -22,6 +22,8 @@ #include "sync.h" #include "log.h" +#include + static unsigned int seq_set, cur_seq; static int __do_send(struct mcast_sock *m, void *data, int len) @@ -65,8 +67,6 @@ static int __do_prepare(struct mcast_sock *m, void *data, int len) static int __prepare_ctl(struct mcast_sock *m, void *data) { - struct nethdr_ack *nack = (struct nethdr_ack *) data; - return __do_prepare(m, data, NETHDR_ACK_SIZ); } @@ -172,7 +172,6 @@ void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net) int handle_netmsg(struct nethdr *net) { - int ret; struct netpld *pld = NETHDR_DATA(net); /* message too small: no room for the header */ diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 8f8759f..82131d7 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -639,7 +639,7 @@ buffer_size: T_STAT_BUFFER_SIZE T_NUMBER %% -int +int __attribute__((noreturn)) yyerror(char *msg) { fprintf(stderr, "Error parsing config file: "); diff --git a/src/run.c b/src/run.c index 7fbeaf5..3fd98cd 100644 --- a/src/run.c +++ b/src/run.c @@ -20,12 +20,19 @@ #include "conntrackd.h" #include "netlink.h" +#include "ignore.h" +#include "log.h" +#include "alarm.h" #include #include #include "us-conntrack.h" #include #include #include +#include +#include +#include +#include void killer(int foo) { @@ -84,7 +91,8 @@ void local_handler(int fd, void *data) dlog(STATE(log), LOG_WARNING, "unknown local request %d", type); } -int init(void) +int +init(void) { if (CONFIG(flags) & CTD_STATS_MODE) STATE(mode) = &stats_mode; @@ -164,11 +172,11 @@ static int __run(struct timeval *next_alarm) if (ret == -1) { /* interrupted syscall, retry */ if (errno == EINTR) - return; + return 0; dlog(STATE(log), LOG_WARNING, "select failed: %s", strerror(errno)); - return; + return 0; } /* timeout expired, run the alarm list */ @@ -223,7 +231,8 @@ static int __run(struct timeval *next_alarm) return 0; } -void run(void) +void __attribute__((noreturn)) +run(void) { struct timeval next_alarm; struct timeval *next = &next_alarm; diff --git a/src/stats-mode.c b/src/stats-mode.c index 0983b97..563e1f6 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -31,8 +31,6 @@ static int init_stats(void) { - int ret; - state.stats = malloc(sizeof(struct ct_stats_state)); if (!state.stats) { dlog(STATE(log), LOG_ERR, "can't allocate memory for stats"); @@ -59,7 +57,7 @@ static int init_stats(void) return 0; } -static void kill_stats() +static void kill_stats(void) { cache_destroy(STATE_STATS(cache)); /* flush the buffer before exiting */ @@ -130,7 +128,7 @@ static int overrun_cb(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } -static void overrun_stats() +static void overrun_stats(void) { int ret; struct nfct_handle *h; diff --git a/src/sync-alarm.c b/src/sync-alarm.c index d9a8267..05ddf81 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -22,6 +22,8 @@ #include "us-conntrack.h" #include "alarm.h" +#include + static void refresher(struct alarm_list *a, void *data) { int len; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 63fd4b2..d881298 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -25,13 +25,14 @@ #include "debug.h" #include "network.h" #include "alarm.h" +#include "log.h" #include #include #if 0 #define dp printf #else -#define dp +#define dp(...) #endif static LIST_HEAD(rs_list); @@ -92,7 +93,7 @@ static void do_alive_alarm(struct alarm_list *a, void *data) add_alarm(&alive_alarm); } -static int ftfw_init() +static int ftfw_init(void) { tx_queue = queue_create(CONFIG(resend_queue_size)); if (tx_queue == NULL) { @@ -117,7 +118,7 @@ static int ftfw_init() return 0; } -static void ftfw_kill() +static void ftfw_kill(void) { queue_destroy(rs_queue); queue_destroy(tx_queue); @@ -330,7 +331,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) return ret; } -static void ftfw_run() +static void ftfw_run(void) { struct cache_ftfw *cn, *tmp; diff --git a/src/sync-mode.c b/src/sync-mode.c index 8be8c18..f2bfc9f 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -38,7 +38,7 @@ static void do_mcast_handler_step(struct nethdr *net) int query; struct netpld *pld = NETHDR_DATA(net); char __ct[nfct_maxsize()]; - struct nf_conntrack *ct = (struct nf_conntrack *) __ct; + struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; struct us_conntrack *u = NULL; if (STATE_SYNC(sync)->recv(net)) diff --git a/src/traffic_stats.c b/src/traffic_stats.c index b2cdaae..b6fa030 100644 --- a/src/traffic_stats.c +++ b/src/traffic_stats.c @@ -48,8 +48,8 @@ void dump_traffic_stats(int fd) STATE(packets)[NFCT_DIR_REPLY]; size = sprintf(buf, "traffic processed:\n"); - size += sprintf(buf+size, "%20llu Bytes ", bytes); - size += sprintf(buf+size, "%20llu Pckts\n\n", packets); + size += sprintf(buf+size, "%20llu Bytes ", (unsigned long long)bytes); + size += sprintf(buf+size, "%20llu Pckts\n\n", (unsigned long long)packets); send(fd, buf, size, 0); } -- cgit v1.2.3 From a8f06005be7e61f0562d8c36d953f688922edf01 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 17 Jan 2008 16:56:50 +0000 Subject: Max Kellermann : use C99 integers (uint32_t instead of u_int32_t) --- ChangeLog | 1 + include/cache.h | 5 +++-- include/conntrack.h | 3 ++- include/conntrackd.h | 21 +++++++++++---------- include/hash.h | 17 +++++++++-------- include/ignore.h | 4 +++- include/mcast.h | 7 ++++--- include/network.h | 34 +++++++++++++++++----------------- include/state_helper.h | 4 +++- src/build.c | 30 +++++++++++++++--------------- src/cache.c | 18 +++++++++--------- src/conntrack.c | 6 +++--- src/hash.c | 12 ++++++------ src/ignore_pool.c | 20 ++++++++++---------- src/mcast.c | 4 ++-- src/netlink.c | 4 ++-- src/network.c | 2 +- src/parse.c | 6 +++--- src/state_helper.c | 2 +- src/state_helper_tcp.c | 2 +- src/sync-ftfw.c | 4 ++-- src/traffic_stats.c | 4 ++-- 22 files changed, 110 insertions(+), 100 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index d6bfbf9..6425e32 100644 --- a/ChangeLog +++ b/ChangeLog @@ -51,6 +51,7 @@ Max Kellermann : o fix shadow warnings by renaming variables or making them local o remove "-g" from Makefile.am, this should be specified by the user o enable C99 mode +o use C99 integers (uint32_t instead of u_int32_t) = conntrackd = o resolve global variable "alarm" conflict with alarm() function in unistd.h. diff --git a/include/cache.h b/include/cache.h index e4fb945..0743d3f 100644 --- a/include/cache.h +++ b/include/cache.h @@ -1,7 +1,8 @@ #ifndef _CACHE_H_ #define _CACHE_H_ -#include +#include +#include #include /* cache features */ @@ -75,7 +76,7 @@ struct cache_extra { struct nf_conntrack; -struct cache *cache_create(const char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra); +struct cache *cache_create(const char *name, unsigned int features, uint8_t proto, struct cache_extra *extra); void cache_destroy(struct cache *e); struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct); diff --git a/include/conntrack.h b/include/conntrack.h index 8f2b6a2..d6b6150 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -3,6 +3,7 @@ #include "linux_list.h" #include +#include #include #define PROGNAME "conntrack" @@ -149,7 +150,7 @@ struct ctproto_handler { struct list_head head; const char *name; - u_int16_t protonum; + uint16_t protonum; const char *version; enum ctattr_protoinfo protoinfo_attr; diff --git a/include/conntrackd.h b/include/conntrackd.h index d3f66ba..418f4b7 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -4,6 +4,7 @@ #include "mcast.h" #include "local.h" +#include #include #include #include "cache.h" @@ -63,9 +64,9 @@ enum { #endif union inet_address { - u_int32_t ipv4; - u_int32_t ipv6[4]; - u_int32_t all[4]; + uint32_t ipv4; + uint32_t ipv6[4]; + uint32_t all[4]; }; #define CONFIG(x) conf.x @@ -112,9 +113,9 @@ struct ct_general_state { struct nfct_handle *dump; /* dump handler */ /* statistics */ - u_int64_t malformed; - u_int64_t bytes[NFCT_DIR_MAX]; - u_int64_t packets[NFCT_DIR_MAX]; + uint64_t malformed; + uint64_t bytes[NFCT_DIR_MAX]; + uint64_t packets[NFCT_DIR_MAX]; }; #define STATE_SYNC(x) state.sync->x @@ -128,10 +129,10 @@ struct ct_sync_state { struct sync_mode *sync; /* sync mode */ - u_int32_t last_seq_sent; /* last sequence number sent */ - u_int32_t last_seq_recv; /* last sequence number recv */ - u_int64_t packets_replayed; /* number of replayed packets */ - u_int64_t packets_lost; /* lost packets: sequence tracking */ + uint32_t last_seq_sent; /* last sequence number sent */ + uint32_t last_seq_recv; /* last sequence number recv */ + uint64_t packets_replayed; /* number of replayed packets */ + uint64_t packets_lost; /* lost packets: sequence tracking */ }; #define STATE_STATS(x) state.stats->x diff --git a/include/hash.h b/include/hash.h index c9460fa..caad412 100644 --- a/include/hash.h +++ b/include/hash.h @@ -2,21 +2,22 @@ #define _NF_SET_HASH_H_ #include -#include #include "slist.h" #include "linux_list.h" +#include + struct hashtable; struct hashtable_node; struct hashtable { - u_int32_t hashsize; - u_int32_t limit; - u_int32_t count; - u_int32_t initval; - u_int32_t datasize; + uint32_t hashsize; + uint32_t limit; + uint32_t count; + uint32_t initval; + uint32_t datasize; - u_int32_t (*hash)(const void *data, struct hashtable *table); + uint32_t (*hash)(const void *data, struct hashtable *table); int (*compare)(const void *data1, const void *data2); struct slist_head members[0]; @@ -32,7 +33,7 @@ void hashtable_destroy_node(struct hashtable_node *h); struct hashtable * hashtable_create(int hashsize, int limit, int datasize, - u_int32_t (*hash)(const void *data, struct hashtable *table), + uint32_t (*hash)(const void *data, struct hashtable *table), int (*compare)(const void *data1, const void *data2)); void hashtable_destroy(struct hashtable *h); diff --git a/include/ignore.h b/include/ignore.h index 96deb93..f1c2846 100644 --- a/include/ignore.h +++ b/include/ignore.h @@ -1,11 +1,13 @@ #ifndef _IGNORE_H_ #define _IGNORE_H_ +#include + struct ignore_pool { struct hashtable *h; }; -struct ignore_pool *ignore_pool_create(u_int8_t family); +struct ignore_pool *ignore_pool_create(uint8_t family); void ignore_pool_destroy(struct ignore_pool *ip); int ignore_pool_add(struct ignore_pool *ip, void *data); int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct); diff --git a/include/mcast.h b/include/mcast.h index d4fd335..e3cdb38 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -1,6 +1,7 @@ #ifndef _MCAST_H_ #define _MCAST_H_ +#include #include #include @@ -22,9 +23,9 @@ struct mcast_conf { }; struct mcast_stats { - u_int64_t bytes; - u_int64_t messages; - u_int64_t error; + uint64_t bytes; + uint64_t messages; + uint64_t error; }; struct mcast_sock { diff --git a/include/network.h b/include/network.h index d0b639b..f9976dd 100644 --- a/include/network.h +++ b/include/network.h @@ -1,12 +1,12 @@ #ifndef _NETWORK_H_ #define _NETWORK_H_ -#include +#include struct nethdr { - u_int16_t flags; - u_int16_t len; - u_int32_t seq; + uint16_t flags; + uint16_t len; + uint32_t seq; }; #define NETHDR_SIZ sizeof(struct nethdr) @@ -14,11 +14,11 @@ struct nethdr { (struct netpld *)(((char *)x) + sizeof(struct nethdr)) struct nethdr_ack { - u_int16_t flags; - u_int16_t len; - u_int32_t seq; - u_int32_t from; - u_int32_t to; + uint16_t flags; + uint16_t len; + uint32_t seq; + uint32_t from; + uint32_t to; }; #define NETHDR_ACK_SIZ sizeof(struct nethdr_ack) @@ -55,7 +55,7 @@ int prepare_send_netmsg(struct mcast_sock *m, void *data); int mcast_send_netmsg(struct mcast_sock *m, void *data); int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len); int handle_netmsg(struct nethdr *net); -int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq); +int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); struct mcast_conf; @@ -103,21 +103,21 @@ int mcast_buffered_pending_netmsg(struct mcast_sock *m); * and worry about wraparound (automatic with unsigned arithmetic). */ -static inline int before(__u32 seq1, __u32 seq2) +static inline int before(uint32_t seq1, uint32_t seq2) { - return (__s32)(seq1-seq2) < 0; + return (int32_t)(seq1-seq2) < 0; } #define after(seq2, seq1) before(seq1, seq2) /* is s2<=s1<=s3 ? */ -static inline int between(__u32 seq1, __u32 seq2, __u32 seq3) +static inline int between(uint32_t seq1, uint32_t seq2, uint32_t seq3) { return seq3 - seq2 >= seq1 - seq2; } struct netpld { - u_int16_t len; - u_int16_t query; + uint16_t len; + uint16_t query; }; #define NETPLD_SIZ sizeof(struct netpld) @@ -134,8 +134,8 @@ struct netpld { }) struct netattr { - u_int16_t nta_len; - u_int16_t nta_attr; + uint16_t nta_len; + uint16_t nta_attr; }; #define ATTR_NETWORK2HOST(x) \ diff --git a/include/state_helper.h b/include/state_helper.h index 1ed0b79..0015890 100644 --- a/include/state_helper.h +++ b/include/state_helper.h @@ -1,13 +1,15 @@ #ifndef _STATE_HELPER_H_ #define _STATE_HELPER_H_ +#include + enum { ST_H_SKIP, ST_H_REPLICATE }; struct state_replication_helper { - u_int8_t proto; + uint8_t proto; unsigned int state; int (*verdict)(const struct state_replication_helper *h, diff --git a/src/build.c b/src/build.c index 5fdc83f..c99990b 100644 --- a/src/build.c +++ b/src/build.c @@ -36,38 +36,38 @@ static void __build_u8(const struct nf_conntrack *ct, struct netpld *pld, int attr) { - u_int8_t data = nfct_get_attr_u8(ct, attr); - addattr(pld, attr, &data, sizeof(u_int8_t)); + uint8_t data = nfct_get_attr_u8(ct, attr); + addattr(pld, attr, &data, sizeof(uint8_t)); } static void __build_u16(const struct nf_conntrack *ct, struct netpld *pld, int attr) { - u_int16_t data = nfct_get_attr_u16(ct, attr); + uint16_t data = nfct_get_attr_u16(ct, attr); data = htons(data); - addattr(pld, attr, &data, sizeof(u_int16_t)); + addattr(pld, attr, &data, sizeof(uint16_t)); } static void __build_u32(const struct nf_conntrack *ct, struct netpld *pld, int attr) { - u_int32_t data = nfct_get_attr_u32(ct, attr); + uint32_t data = nfct_get_attr_u32(ct, attr); data = htonl(data); - addattr(pld, attr, &data, sizeof(u_int32_t)); + addattr(pld, attr, &data, sizeof(uint32_t)); } -static void __nat_build_u32(u_int32_t data, struct netpld *pld, int attr) +static void __nat_build_u32(uint32_t data, struct netpld *pld, int attr) { data = htonl(data); - addattr(pld, attr, &data, sizeof(u_int32_t)); + addattr(pld, attr, &data, sizeof(uint32_t)); } -static void __nat_build_u16(u_int16_t data, struct netpld *pld, int attr) +static void __nat_build_u16(uint16_t data, struct netpld *pld, int attr) { data = htons(data); - addattr(pld, attr, &data, sizeof(u_int16_t)); + addattr(pld, attr, &data, sizeof(uint16_t)); } /* XXX: IPv6 and ICMP not supported */ @@ -84,7 +84,7 @@ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) if (nfct_attr_is_set(ct, ATTR_PORT_DST)) __build_u16(ct, pld, ATTR_PORT_DST); if (nfct_attr_is_set(ct, ATTR_L4PROTO)) { - u_int8_t proto; + uint8_t proto; __build_u8(ct, pld, ATTR_L4PROTO); proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); @@ -118,19 +118,19 @@ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) /* NAT */ if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { - u_int32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST); + uint32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST); __nat_build_u32(data, pld, ATTR_SNAT_IPV4); } if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { - u_int32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); + uint32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); __nat_build_u32(data, pld, ATTR_DNAT_IPV4); } if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) { - u_int16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST); + uint16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST); __nat_build_u16(data, pld, ATTR_SNAT_PORT); } if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) { - u_int16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC); + uint16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC); __nat_build_u16(data, pld, ATTR_DNAT_PORT); } diff --git a/src/cache.c b/src/cache.c index c5afb00..dcb0123 100644 --- a/src/cache.c +++ b/src/cache.c @@ -25,17 +25,17 @@ #include "cache.h" #include -static u_int32_t hash(const void *data, struct hashtable *table) +static uint32_t hash(const void *data, struct hashtable *table) { unsigned int a, b; const struct us_conntrack *u = data; struct nf_conntrack *ct = u->ct; - a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), sizeof(u_int32_t), + a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), sizeof(uint32_t), ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)))); - b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), sizeof(u_int32_t), + b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), sizeof(uint32_t), ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); @@ -46,24 +46,24 @@ static u_int32_t hash(const void *data, struct hashtable *table) * but using a multiply, less expensive than a divide. See: * http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html */ - return ((u_int64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; + return ((uint64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; } -static u_int32_t hash6(const void *data, struct hashtable *table) +static uint32_t hash6(const void *data, struct hashtable *table) { unsigned int a, b; const struct us_conntrack *u = data; struct nf_conntrack *ct = u->ct; - a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(u_int32_t)*4, + a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(uint32_t)*4, ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)))); - b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_DST), sizeof(u_int32_t)*4, + b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_DST), sizeof(uint32_t)*4, ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); - return ((u_int64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; + return ((uint64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; } static int __compare(const struct nf_conntrack *ct1, @@ -123,7 +123,7 @@ struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { struct cache *cache_create(const char *name, unsigned int features, - u_int8_t proto, + uint8_t proto, struct cache_extra *extra) { size_t size = sizeof(struct us_conntrack); diff --git a/src/conntrack.c b/src/conntrack.c index 9d268c5..b8843d4 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -444,8 +444,8 @@ parse_inetaddr(const char *cp, struct addr_parse *parse) } union ct_address { - u_int32_t v4; - u_int32_t v6[4]; + uint32_t v4; + uint32_t v6[4]; }; static int @@ -472,7 +472,7 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) colon = strchr(arg, ':'); if (colon) { - u_int16_t port; + uint16_t port; if (!portok) exit_error(PARAMETER_PROBLEM, diff --git a/src/hash.c b/src/hash.c index 553dd1d..d7724c8 100644 --- a/src/hash.c +++ b/src/hash.c @@ -48,7 +48,7 @@ void hashtable_destroy_node(struct hashtable_node *h) struct hashtable * hashtable_create(int hashsize, int limit, int datasize, - u_int32_t (*hash)(const void *data, struct hashtable *table), + uint32_t (*hash)(const void *data, struct hashtable *table), int (*compare)(const void *data1, const void *data2)) { int i; @@ -85,7 +85,7 @@ void *hashtable_add(struct hashtable *table, void *data) { struct slist_head *e; struct hashtable_node *n; - u_int32_t id; + uint32_t id; /* hash table is full */ if (table->count >= table->limit) { @@ -118,7 +118,7 @@ void *hashtable_add(struct hashtable *table, void *data) void *hashtable_test(struct hashtable *table, const void *data) { struct slist_head *e; - u_int32_t id; + uint32_t id; struct hashtable_node *n; id = table->hash(data, table); @@ -136,7 +136,7 @@ void *hashtable_test(struct hashtable *table, const void *data) int hashtable_del(struct hashtable *table, void *data) { struct slist_head *e, *next, *prev; - u_int32_t id; + uint32_t id; struct hashtable_node *n; id = table->hash(data, table); @@ -156,7 +156,7 @@ int hashtable_del(struct hashtable *table, void *data) int hashtable_flush(struct hashtable *table) { - u_int32_t i; + uint32_t i; struct slist_head *e, *next, *prev; struct hashtable_node *n; @@ -175,7 +175,7 @@ int hashtable_flush(struct hashtable *table) int hashtable_iterate(struct hashtable *table, void *data, int (*iterate)(void *data1, void *data2)) { - u_int32_t i; + uint32_t i; struct slist_head *e, *next, *prev; struct hashtable_node *n; diff --git a/src/ignore_pool.c b/src/ignore_pool.c index 82afa93..5889398 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -29,32 +29,32 @@ #define IGNORE_POOL_SIZE 128 #define IGNORE_POOL_LIMIT INT_MAX -static u_int32_t hash(const void *data, struct hashtable *table) +static uint32_t hash(const void *data, struct hashtable *table) { - const u_int32_t *ip = data; + const uint32_t *ip = data; return jhash_1word(*ip, 0) % table->hashsize; } -static u_int32_t hash6(const void *data, struct hashtable *table) +static uint32_t hash6(const void *data, struct hashtable *table) { - return jhash(data, sizeof(u_int32_t)*4, 0) % table->hashsize; + return jhash(data, sizeof(uint32_t)*4, 0) % table->hashsize; } static int compare(const void *data1, const void *data2) { - const u_int32_t *ip1 = data1; - const u_int32_t *ip2 = data2; + const uint32_t *ip1 = data1; + const uint32_t *ip2 = data2; return *ip1 == *ip2; } static int compare6(const void *data1, const void *data2) { - return memcmp(data1, data2, sizeof(u_int32_t)*4) == 0; + return memcmp(data1, data2, sizeof(uint32_t)*4) == 0; } -struct ignore_pool *ignore_pool_create(u_int8_t proto) +struct ignore_pool *ignore_pool_create(uint8_t proto) { struct ignore_pool *ip; @@ -67,14 +67,14 @@ struct ignore_pool *ignore_pool_create(u_int8_t proto) case AF_INET: ip->h = hashtable_create(IGNORE_POOL_SIZE, IGNORE_POOL_LIMIT, - sizeof(u_int32_t), + sizeof(uint32_t), hash, compare); break; case AF_INET6: ip->h = hashtable_create(IGNORE_POOL_SIZE, IGNORE_POOL_LIMIT, - sizeof(u_int32_t)*4, + sizeof(uint32_t)*4, hash6, compare6); break; diff --git a/src/mcast.c b/src/mcast.c index cf03593..185a7e2 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -57,9 +57,9 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) case AF_INET6: memcpy(&mreq.ipv6.ipv6mr_multiaddr, &conf->in.inet_addr6, - sizeof(u_int32_t) * 4); + sizeof(uint32_t) * 4); memcpy(&mreq.ipv6.ipv6mr_interface, &conf->ifa.interface_addr6, - sizeof(u_int32_t) * 4); + sizeof(uint32_t) * 4); m->addr.ipv6.sin6_family = AF_INET6; m->addr.ipv6.sin6_port = htons(conf->port); diff --git a/src/netlink.c b/src/netlink.c index 7800b10..388407a 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -202,11 +202,11 @@ int nl_dump_conntrack_table(void) /* This function modifies the conntrack passed as argument! */ int nl_create_conntrack(struct nf_conntrack *ct) { - u_int8_t flags; + uint8_t flags; /* XXX: related connections */ if (nfct_attr_is_set(ct, ATTR_STATUS)) { - u_int32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); + uint32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); status &= ~IPS_EXPECTED; nfct_set_attr_u32(ct, ATTR_STATUS, status); } diff --git a/src/network.c b/src/network.c index 9d6e6e1..939e94b 100644 --- a/src/network.c +++ b/src/network.c @@ -197,7 +197,7 @@ int handle_netmsg(struct nethdr *net) return 0; } -int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq) +int mcast_track_seq(uint32_t seq, uint32_t *exp_seq) { static int local_seq_set = 0; int ret = 1; diff --git a/src/parse.c b/src/parse.c index c8a9704..a248b47 100644 --- a/src/parse.c +++ b/src/parse.c @@ -22,19 +22,19 @@ static void parse_u8(struct nf_conntrack *ct, int attr, void *data) { - u_int8_t *value = (u_int8_t *) data; + uint8_t *value = (uint8_t *) data; nfct_set_attr_u8(ct, attr, *value); } static void parse_u16(struct nf_conntrack *ct, int attr, void *data) { - u_int16_t *value = (u_int16_t *) data; + uint16_t *value = (uint16_t *) data; nfct_set_attr_u16(ct, attr, ntohs(*value)); } static void parse_u32(struct nf_conntrack *ct, int attr, void *data) { - u_int32_t *value = (u_int32_t *) data; + uint32_t *value = (uint32_t *) data; nfct_set_attr_u32(ct, attr, ntohl(*value)); } diff --git a/src/state_helper.c b/src/state_helper.c index de4cf48..9034864 100644 --- a/src/state_helper.c +++ b/src/state_helper.c @@ -23,7 +23,7 @@ static struct state_replication_helper *helper[IPPROTO_MAX]; int state_helper_verdict(int type, struct nf_conntrack *ct) { - u_int8_t l4proto; + uint8_t l4proto; if (type == NFCT_Q_DESTROY) return ST_H_REPLICATE; diff --git a/src/state_helper_tcp.c b/src/state_helper_tcp.c index e0a51ee..88af35e 100644 --- a/src/state_helper_tcp.c +++ b/src/state_helper_tcp.c @@ -22,7 +22,7 @@ static int tcp_verdict(const struct state_replication_helper *h, const struct nf_conntrack *ct) { - u_int8_t t_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE); + uint8_t t_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE); if (h->state & (1 << t_state)) return ST_H_REPLICATE; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 0943e68..f0b3262 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -44,7 +44,7 @@ static struct queue *tx_queue; struct cache_ftfw { struct list_head rs_list; struct list_head tx_list; - u_int32_t seq; + uint32_t seq; }; static void cache_ftfw_add(struct us_conntrack *u, void *data) @@ -73,7 +73,7 @@ static struct cache_extra cache_ftfw_extra = { .destroy = cache_ftfw_del }; -static void tx_queue_add_ctlmsg(u_int32_t flags, u_int32_t from, u_int32_t to) +static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) { struct nethdr_ack ack = { .flags = flags, diff --git a/src/traffic_stats.c b/src/traffic_stats.c index b6fa030..93511ce 100644 --- a/src/traffic_stats.c +++ b/src/traffic_stats.c @@ -42,9 +42,9 @@ void dump_traffic_stats(int fd) { char buf[512]; int size; - u_int64_t bytes = STATE(bytes)[NFCT_DIR_ORIGINAL] + + uint64_t bytes = STATE(bytes)[NFCT_DIR_ORIGINAL] + STATE(bytes)[NFCT_DIR_REPLY]; - u_int64_t packets = STATE(packets)[NFCT_DIR_ORIGINAL] + + uint64_t packets = STATE(packets)[NFCT_DIR_ORIGINAL] + STATE(packets)[NFCT_DIR_REPLY]; size = sprintf(buf, "traffic processed:\n"); -- cgit v1.2.3 From 001805d9998229534264758432c06295614f8e2a Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 17 Jan 2008 17:36:32 +0000 Subject: Max Kellermann : import only required C headers and put local headers on top to check --- ChangeLog | 1 + extensions/libct_proto_icmp.c | 4 +++- extensions/libct_proto_udp.c | 1 - include/alarm.h | 2 ++ include/cache.h | 1 - include/conntrack.h | 1 - include/conntrackd.h | 9 +-------- include/ignore.h | 2 ++ include/linux_list.h | 2 ++ include/local.h | 2 -- include/network.h | 2 ++ include/queue.h | 3 --- src/alarm.c | 7 ------- src/buffer.c | 4 +++- src/cache.c | 6 ++++-- src/cache_iterators.c | 5 +++-- src/cache_lifetime.c | 2 -- src/cache_timer.c | 7 ++++--- src/cache_wt.c | 6 +++--- src/conntrack.c | 12 +++--------- src/hash.c | 8 +++----- src/ignore_pool.c | 5 +++-- src/local.c | 7 ++++--- src/log.c | 8 +++----- src/main.c | 8 ++++---- src/mcast.c | 10 ++++------ src/netlink.c | 8 +------- src/network.c | 5 +++-- src/parse.c | 4 ++-- src/queue.c | 4 ++++ src/read_config_lex.l | 1 - src/read_config_yy.y | 1 + src/run.c | 7 ++----- src/stats-mode.c | 11 +++++------ src/sync-alarm.c | 3 +++ src/sync-ftfw.c | 7 +++---- src/sync-mode.c | 14 +++++++------- src/traffic_stats.c | 7 ------- 38 files changed, 85 insertions(+), 112 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index e0a0da7..f84f7aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -81,6 +81,7 @@ o fix harmless error condition o add buffer_destroy() to buffer.c o fix memory leaks in several error output paths o use size_t for buffer sizes +o import only required C headers and put local headers on top to check version 0.9.5 (2007/07/29) ------------------------------ diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 7c59072..f81c3b4 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -8,6 +8,9 @@ * (at your option) any later version. * */ + +#include "conntrack.h" + #include #include #include @@ -15,7 +18,6 @@ #include #include #include -#include "conntrack.h" static struct option opts[] = { {"icmp-type", 1, 0, '1'}, diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 267e3d6..a72f9cf 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -10,7 +10,6 @@ #include #include #include -#include #include /* For htons */ #include #include diff --git a/include/alarm.h b/include/alarm.h index 338968a..532084a 100644 --- a/include/alarm.h +++ b/include/alarm.h @@ -3,6 +3,8 @@ #include "linux_list.h" +#include + struct alarm_list { struct list_head head; struct timeval tv; diff --git a/include/cache.h b/include/cache.h index 0743d3f..a2b2005 100644 --- a/include/cache.h +++ b/include/cache.h @@ -3,7 +3,6 @@ #include #include -#include /* cache features */ enum { diff --git a/include/conntrack.h b/include/conntrack.h index d6b6150..63facf4 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -2,7 +2,6 @@ #define _CONNTRACK_H #include "linux_list.h" -#include #include #include diff --git a/include/conntrackd.h b/include/conntrackd.h index bb4b183..c16d3d7 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -6,14 +6,7 @@ #include #include -#include -#include "cache.h" -#include "buffer.h" -#include "debug.h" -#include -#include "state_helper.h" -#include "linux_list.h" -#include +#include #include /* UNIX facilities */ diff --git a/include/ignore.h b/include/ignore.h index f1c2846..efb375d 100644 --- a/include/ignore.h +++ b/include/ignore.h @@ -3,6 +3,8 @@ #include +struct nf_conntrack; + struct ignore_pool { struct hashtable *h; }; diff --git a/include/linux_list.h b/include/linux_list.h index b84b1c4..de182a4 100644 --- a/include/linux_list.h +++ b/include/linux_list.h @@ -1,6 +1,8 @@ #ifndef _LINUX_LIST_H #define _LINUX_LIST_H +#include + #undef offsetof #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) diff --git a/include/local.h b/include/local.h index aae73a7..be77d35 100644 --- a/include/local.h +++ b/include/local.h @@ -1,8 +1,6 @@ #ifndef _LOCAL_SOCKET_H_ #define _LOCAL_SOCKET_H_ -#include - #ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX 108 #endif diff --git a/include/network.h b/include/network.h index f9976dd..6dfd79d 100644 --- a/include/network.h +++ b/include/network.h @@ -3,6 +3,8 @@ #include +struct nf_conntrack; + struct nethdr { uint16_t flags; uint16_t len; diff --git a/include/queue.h b/include/queue.h index ab04d62..9a5d7b8 100644 --- a/include/queue.h +++ b/include/queue.h @@ -1,9 +1,6 @@ #ifndef _QUEUE_H_ #define _QUEUE_H_ -#include -#include -#include #include "linux_list.h" struct queue { diff --git a/src/alarm.c b/src/alarm.c index d00e281..576839a 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -16,14 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include -#include "linux_list.h" -#include "conntrackd.h" #include "alarm.h" -#include "jhash.h" -#include -#include static LIST_HEAD(alarm_list); diff --git a/src/buffer.c b/src/buffer.c index 389dd38..739174a 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -15,10 +15,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "buffer.h" + #include #include #include -#include "buffer.h" struct buffer *buffer_create(size_t size) { diff --git a/src/cache.c b/src/cache.c index dcb0123..2f0e57a 100644 --- a/src/cache.c +++ b/src/cache.c @@ -16,14 +16,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "cache.h" #include "jhash.h" #include "hash.h" +#include "us-conntrack.h" #include "conntrackd.h" + #include #include -#include "us-conntrack.h" -#include "cache.h" #include +#include static uint32_t hash(const void *data, struct hashtable *table) { diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 4fdb920..bf70dd1 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -17,14 +17,15 @@ */ #include "cache.h" -#include "jhash.h" #include "hash.h" #include "log.h" #include "conntrackd.h" #include "netlink.h" +#include "us-conntrack.h" + #include #include -#include "us-conntrack.h" +#include struct __dump_container { int fd; diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c index 26496d2..ad3416a 100644 --- a/src/cache_lifetime.c +++ b/src/cache_lifetime.c @@ -17,10 +17,8 @@ */ #include -#include "conntrackd.h" #include "us-conntrack.h" #include "cache.h" -#include "alarm.h" #include #include diff --git a/src/cache_timer.c b/src/cache_timer.c index 53ed703..0fbba14 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -16,12 +16,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include +#include "cache.h" #include "conntrackd.h" #include "us-conntrack.h" -#include "cache.h" #include "alarm.h" +#include "debug.h" + +#include static void timeout(struct alarm_list *a, void *data) { diff --git a/src/cache_wt.c b/src/cache_wt.c index 9d0af0b..8ff8fae 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -16,11 +16,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "cache.h" #include "netlink.h" -#include -#include "conntrackd.h" #include "us-conntrack.h" -#include "cache.h" + +#include static void add_update(struct us_conntrack *u) { diff --git a/src/conntrack.c b/src/conntrack.c index 7918b3f..5f0cb1a 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -33,9 +33,10 @@ * Ported to the new libnetfilter_conntrack API * */ + +#include "conntrack.h" + #include -#include -#include #include #include #include @@ -43,22 +44,15 @@ #include #include #include -#include #include #include #include #ifdef HAVE_ARPA_INET_H #include #endif -#include -#include #include #include -#include "linux_list.h" -#include "conntrack.h" #include -#include -#include static const char cmdflags[NUMBER_OF_CMD] = {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'}; diff --git a/src/hash.c b/src/hash.c index d7724c8..cf64df4 100644 --- a/src/hash.c +++ b/src/hash.c @@ -18,14 +18,12 @@ * Description: generic hash table implementation */ -#include +#include "hash.h" +#include "slist.h" + #include #include -#include #include -#include "slist.h" -#include "hash.h" - struct hashtable_node *hashtable_alloc_node(int datasize, void *data) { diff --git a/src/ignore_pool.c b/src/ignore_pool.c index 5889398..c77a55b 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -16,14 +16,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "ignore.h" #include "jhash.h" #include "hash.h" #include "conntrackd.h" -#include "ignore.h" #include "log.h" -#include +#include #include +#include /* XXX: These should be configurable */ #define IGNORE_POOL_SIZE 128 diff --git a/src/local.c b/src/local.c index d861e12..f0aba1c 100644 --- a/src/local.c +++ b/src/local.c @@ -18,12 +18,13 @@ * Description: UNIX sockets library */ +#include "local.h" + #include #include +#include #include -#include - -#include "local.h" +#include int local_server_create(struct local_conf *conf) { diff --git a/src/log.c b/src/log.c index 35ae0c3..a2d48a4 100644 --- a/src/log.c +++ b/src/log.c @@ -19,16 +19,14 @@ */ #include "log.h" -#include -#include -#include +#include "buffer.h" +#include "conntrackd.h" + #include #include #include #include #include -#include "buffer.h" -#include "conntrackd.h" int init_log(void) { diff --git a/src/main.c b/src/main.c index b860982..3d8cfe9 100644 --- a/src/main.c +++ b/src/main.c @@ -16,17 +16,17 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include "conntrackd.h" #include "log.h" + #include #include #include #include #include -#include -#include "hash.h" -#include "jhash.h" +#include +#include +#include #undef _POSIX_SOURCE #include diff --git a/src/mcast.c b/src/mcast.c index 9684b61..77aa35c 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -17,19 +17,17 @@ * * Description: multicast socket library */ + +#include "mcast.h" +#include "debug.h" + #include #include -#include #include -#include -#include -#include #include #include #include #include -#include "mcast.h" -#include "debug.h" struct mcast_sock *mcast_server_create(struct mcast_conf *conf) { diff --git a/src/netlink.c b/src/netlink.c index 388407a..0457e8a 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -21,13 +21,7 @@ #include "traffic_stats.h" #include "ignore.h" #include "log.h" -#include -#include -#include -#include "us-conntrack.h" -#include -#include -#include "network.h" +#include "debug.h" int ignore_conntrack(struct nf_conntrack *ct) { diff --git a/src/network.c b/src/network.c index 939e94b..7c7a08a 100644 --- a/src/network.c +++ b/src/network.c @@ -18,11 +18,12 @@ #include "conntrackd.h" #include "network.h" -#include "us-conntrack.h" -#include "sync.h" #include "log.h" +#include "debug.h" #include +#include +#include static unsigned int seq_set, cur_seq; diff --git a/src/parse.c b/src/parse.c index a248b47..5bc71ef 100644 --- a/src/parse.c +++ b/src/parse.c @@ -16,10 +16,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include #include "network.h" +#include + static void parse_u8(struct nf_conntrack *ct, int attr, void *data) { uint8_t *value = (uint8_t *) data; diff --git a/src/queue.c b/src/queue.c index a721760..7b20e83 100644 --- a/src/queue.c +++ b/src/queue.c @@ -18,6 +18,10 @@ #include "queue.h" +#include +#include +#include + struct queue *queue_create(size_t max_size) { struct queue *b; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 6211fee..65df1e7 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -20,7 +20,6 @@ */ #include "read_config_yy.h" -#include "conntrackd.h" %} %option yylineno diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 82131d7..531b1fe 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -26,6 +26,7 @@ #include "conntrackd.h" #include "ignore.h" #include +#include extern struct state_replication_helper tcp_state_helper; diff --git a/src/run.c b/src/run.c index cb5116d..9076028 100644 --- a/src/run.c +++ b/src/run.c @@ -23,16 +23,13 @@ #include "ignore.h" #include "log.h" #include "alarm.h" -#include + #include -#include "us-conntrack.h" #include #include #include -#include #include -#include -#include +#include void killer(int foo) { diff --git a/src/stats-mode.c b/src/stats-mode.c index 0c42d95..0ecb2b0 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -18,16 +18,15 @@ #include "netlink.h" #include "traffic_stats.h" -#include +#include "buffer.h" +#include "debug.h" #include "cache.h" #include "log.h" #include "conntrackd.h" -#include -#include + #include -#include "us-conntrack.h" -#include -#include +#include +#include static int init_stats(void) { diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 05ddf81..6ee306e 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -21,8 +21,11 @@ #include "network.h" #include "us-conntrack.h" #include "alarm.h" +#include "cache.h" +#include "debug.h" #include +#include static void refresher(struct alarm_list *a, void *data) { diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index f0b3262..f6d2ed3 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -16,18 +16,17 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include "conntrackd.h" #include "sync.h" -#include "linux_list.h" #include "us-conntrack.h" #include "queue.h" #include "debug.h" #include "network.h" #include "alarm.h" #include "log.h" -#include -#include +#include "cache.h" + +#include #if 0 #define dp printf diff --git a/src/sync-mode.c b/src/sync-mode.c index 1632019..0a0fcc2 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -16,22 +16,22 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "sync.h" #include "netlink.h" #include "traffic_stats.h" #include "log.h" -#include +#include "state_helper.h" #include "cache.h" #include "conntrackd.h" -#include -#include -#include #include "us-conntrack.h" -#include -#include -#include "sync.h" #include "network.h" #include "debug.h" + +#include #include +#include +#include +#include static void do_mcast_handler_step(struct nethdr *net) { diff --git a/src/traffic_stats.c b/src/traffic_stats.c index 93511ce..9e40d53 100644 --- a/src/traffic_stats.c +++ b/src/traffic_stats.c @@ -17,14 +17,7 @@ */ #include "traffic_stats.h" -#include "cache.h" -#include "hash.h" #include "conntrackd.h" -#include -#include -#include -#include "us-conntrack.h" -#include void update_traffic_stats(struct nf_conntrack *ct) { -- cgit v1.2.3 From 5943d1ddb9ee51b80d353ab9dd2cf80d1202e328 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 23 Jan 2008 11:13:18 +0000 Subject: Max Kellermann : remove unused prototype in network.h --- ChangeLog | 1 + include/network.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index b78f337..8205ec5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -92,6 +92,7 @@ o merge mod_alarm() into add_alarm(), remove alarm_set_expiration() o remove init_alarm() before add_alarm() o fix error checking of local_create_server() o added struct local_server, several cleanups in local socket infrastructure +o remove unused prototypes in network.h version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/network.h b/include/network.h index 6dfd79d..e3e9ce1 100644 --- a/include/network.h +++ b/include/network.h @@ -55,7 +55,6 @@ struct mcast_sock; void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); int prepare_send_netmsg(struct mcast_sock *m, void *data); int mcast_send_netmsg(struct mcast_sock *m, void *data); -int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len); int handle_netmsg(struct nethdr *net); int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); -- cgit v1.2.3 From 379125b1f618b3102015a64b1e9be0bdbe883930 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 23 Jan 2008 12:30:36 +0000 Subject: Max Kellermann : use size_t --- ChangeLog | 1 + include/mcast.h | 4 ++-- include/network.h | 7 ++++--- src/build.c | 2 +- src/local.c | 4 ++-- src/mcast.c | 8 ++++---- src/network.c | 22 +++++++++++----------- src/sync-alarm.c | 2 +- src/sync-ftfw.c | 4 ++-- src/sync-mode.c | 9 +++++---- 10 files changed, 33 insertions(+), 30 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index 5010775..4cd5eff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -95,6 +95,7 @@ o added struct local_server, several cleanups in local socket infrastructure o remove unused prototypes in network.h o check if the received packet is large enough o introduce alarm_pending() +o cleanup: use size_t instead of integer version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/mcast.h b/include/mcast.h index e3cdb38..4e89c72 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -43,8 +43,8 @@ void mcast_server_destroy(struct mcast_sock *m); struct mcast_sock *mcast_client_create(struct mcast_conf *conf); void mcast_client_destroy(struct mcast_sock *m); -int mcast_send(struct mcast_sock *m, void *data, int size); -int mcast_recv(struct mcast_sock *m, void *data, int size); +ssize_t mcast_send(struct mcast_sock *m, void *data, int size); +ssize_t mcast_recv(struct mcast_sock *m, void *data, int size); struct mcast_stats *mcast_get_stats(struct mcast_sock *m); void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r); diff --git a/include/network.h b/include/network.h index e3e9ce1..92a8490 100644 --- a/include/network.h +++ b/include/network.h @@ -2,6 +2,7 @@ #define _NETWORK_H_ #include +#include struct nf_conntrack; @@ -53,7 +54,7 @@ struct us_conntrack; struct mcast_sock; void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); -int prepare_send_netmsg(struct mcast_sock *m, void *data); +size_t prepare_send_netmsg(struct mcast_sock *m, void *data); int mcast_send_netmsg(struct mcast_sock *m, void *data); int handle_netmsg(struct nethdr *net); int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); @@ -62,8 +63,8 @@ struct mcast_conf; int mcast_buffered_init(struct mcast_conf *conf); void mcast_buffered_destroy(void); -int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len); -int mcast_buffered_pending_netmsg(struct mcast_sock *m); +int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len); +ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); #define IS_DATA(x) ((x->flags & ~NET_F_HELLO) == 0) #define IS_ACK(x) (x->flags & NET_F_ACK) diff --git a/src/build.c b/src/build.c index c99990b..3de1c25 100644 --- a/src/build.c +++ b/src/build.c @@ -20,7 +20,7 @@ #include #include "network.h" -static void addattr(struct netpld *pld, int attr, const void *data, int len) +static void addattr(struct netpld *pld, int attr, const void *data, size_t len) { struct netattr *nta; int tlen = NTA_LENGTH(len); diff --git a/src/local.c b/src/local.c index 258605f..e2c3599 100644 --- a/src/local.c +++ b/src/local.c @@ -29,7 +29,7 @@ int local_server_create(struct local_server *server, struct local_conf *conf) { int fd; - int len; + socklen_t len; struct sockaddr_un local; if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) @@ -90,7 +90,7 @@ int do_local_server_step(struct local_server *server, void *data, int local_client_create(struct local_conf *conf) { - int len; + socklen_t len; struct sockaddr_un local; int fd; diff --git a/src/mcast.c b/src/mcast.c index e977c0b..8307f26 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -238,9 +238,9 @@ void mcast_client_destroy(struct mcast_sock *m) free(m); } -int mcast_send(struct mcast_sock *m, void *data, int size) +ssize_t mcast_send(struct mcast_sock *m, void *data, int size) { - int ret; + ssize_t ret; ret = sendto(m->fd, data, @@ -260,9 +260,9 @@ int mcast_send(struct mcast_sock *m, void *data, int size) return ret; } -int mcast_recv(struct mcast_sock *m, void *data, int size) +ssize_t mcast_recv(struct mcast_sock *m, void *data, int size) { - int ret; + ssize_t ret; socklen_t sin_size = sizeof(struct sockaddr_in); ret = recvfrom(m->fd, diff --git a/src/network.c b/src/network.c index da26545..92999a1 100644 --- a/src/network.c +++ b/src/network.c @@ -27,7 +27,7 @@ static unsigned int seq_set, cur_seq; -static int __do_send(struct mcast_sock *m, void *data, int len) +static size_t __do_send(struct mcast_sock *m, void *data, size_t len) { struct nethdr *net = data; @@ -50,7 +50,7 @@ static int __do_send(struct mcast_sock *m, void *data, int len) return mcast_send(m, net, len); } -static int __do_prepare(struct mcast_sock *m, void *data, int len) +static size_t __do_prepare(struct mcast_sock *m, void *data, size_t len) { struct nethdr *net = data; @@ -66,12 +66,12 @@ static int __do_prepare(struct mcast_sock *m, void *data, int len) return len; } -static int __prepare_ctl(struct mcast_sock *m, void *data) +static size_t __prepare_ctl(struct mcast_sock *m, void *data) { return __do_prepare(m, data, NETHDR_ACK_SIZ); } -static int __prepare_data(struct mcast_sock *m, void *data) +static size_t __prepare_data(struct mcast_sock *m, void *data) { struct nethdr *net = (struct nethdr *) data; struct netpld *pld = NETHDR_DATA(net); @@ -79,7 +79,7 @@ static int __prepare_data(struct mcast_sock *m, void *data) return __do_prepare(m, data, ntohs(pld->len) + NETPLD_SIZ + NETHDR_SIZ); } -int prepare_send_netmsg(struct mcast_sock *m, void *data) +size_t prepare_send_netmsg(struct mcast_sock *m, void *data) { int ret = 0; struct nethdr *net = (struct nethdr *) data; @@ -92,8 +92,8 @@ int prepare_send_netmsg(struct mcast_sock *m, void *data) return ret; } -static int tx_buflenmax; -static int tx_buflen = 0; +static size_t tx_buflenmax; +static size_t tx_buflen = 0; static char *tx_buf; #define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ @@ -121,7 +121,7 @@ void mcast_buffered_destroy(void) } /* return 0 if it is not sent, otherwise return 1 */ -int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len) +int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len) { int ret = 0; struct nethdr *net = data; @@ -140,9 +140,9 @@ retry: return ret; } -int mcast_buffered_pending_netmsg(struct mcast_sock *m) +ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m) { - int ret; + ssize_t ret; if (tx_buflen == 0) return 0; @@ -156,7 +156,7 @@ int mcast_buffered_pending_netmsg(struct mcast_sock *m) int mcast_send_netmsg(struct mcast_sock *m, void *data) { int ret; - int len = prepare_send_netmsg(m, data); + size_t len = prepare_send_netmsg(m, data); ret = mcast_buffered_send_netmsg(m, data, len); mcast_buffered_pending_netmsg(m); diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 66727e7..c7cecc8 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -29,7 +29,7 @@ static void refresher(struct alarm_list *a, void *data) { - int len; + size_t len; struct nethdr *net; struct us_conntrack *u = data; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 1d12002..49c0b2c 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -285,7 +285,7 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) static int tx_queue_xmit(void *data1, const void *data2) { struct nethdr *net = data1; - int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); dp("tx_queue sq: %u fl:%u len:%u\n", ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); @@ -307,7 +307,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) { int ret; struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); - int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); dp("tx_list sq: %u fl:%u len:%u\n", ntohl(net->seq), ntohs(net->flags), diff --git a/src/sync-mode.c b/src/sync-mode.c index 5974474..b4972a8 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -88,7 +88,8 @@ retry: /* handler for multicast messages received */ static void mcast_handler(void) { - int numbytes, remain; + ssize_t numbytes; + ssize_t remain; char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net)); @@ -339,7 +340,7 @@ static void mcast_send_sync(struct us_conntrack *u, struct nf_conntrack *ct, int query) { - int len; + size_t len; struct nethdr *net; if (!state_helper_verdict(query, ct)) @@ -373,7 +374,7 @@ static int overrun_cb(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { - int len; + size_t len; debug_ct(u->ct, "overrun resync"); @@ -397,7 +398,7 @@ static int overrun_purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { - int len; + size_t len; struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_DESTROY); debug_ct(u->ct, "overrun purge resync"); -- cgit v1.2.3 From 46e76aff2d0fc0d88ccdbc0cef43d9e3f3c4c388 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 25 Mar 2008 14:36:14 +0000 Subject: Pablo Neira Ayuso : o remove .svn directory from make distcheck tarballs (reported by B.Benjamini) + Krzysztof Oledzki : o fix minor compilation warning --- ChangeLog | 9 +++++++++ configure.in | 2 +- include/network.h | 2 +- include/state_helper.h | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index 13ac4fe..6a33399 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +version 0.9.7 (yet unreleased) +------------------------------ + +Pablo Neira Ayuso : +o remove .svn directory from make distcheck tarballs (reported by B.Benjamini) + +Krzysztof Oledzki : +o fix minor compilation warning + version 0.9.6 (2008/03/08) ------------------------------ diff --git a/configure.in b/configure.in index 920f42f..a98a324 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(conntrack-tools, 0.9.6, pablo@netfilter.org) +AC_INIT(conntrack-tools, 0.9.7, pablo@netfilter.org) AC_CANONICAL_SYSTEM diff --git a/include/network.h b/include/network.h index 92a8490..e4ebec4 100644 --- a/include/network.h +++ b/include/network.h @@ -61,7 +61,7 @@ int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); struct mcast_conf; -int mcast_buffered_init(struct mcast_conf *conf); +int mcast_buffered_init(struct mcast_conf *mconf); void mcast_buffered_destroy(void); int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len); ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); diff --git a/include/state_helper.h b/include/state_helper.h index 0015890..1a68b04 100644 --- a/include/state_helper.h +++ b/include/state_helper.h @@ -17,6 +17,6 @@ struct state_replication_helper { }; int state_helper_verdict(int type, struct nf_conntrack *ct); -void state_helper_register(struct state_replication_helper *h, int state); +void state_helper_register(struct state_replication_helper *h, int h_state); #endif -- cgit v1.2.3 From 96213d5f0821aee2fe52459ab2cd54569e50cf85 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 26 Apr 2008 16:07:00 +0000 Subject: rework of the FT-FW approach --- ChangeLog | 1 + include/network.h | 38 +++++---- src/network.c | 43 ++++++---- src/queue.c | 2 +- src/sync-ftfw.c | 237 ++++++++++++++++++++++++++++++++++++++++++------------ src/sync-mode.c | 46 +++++------ 6 files changed, 257 insertions(+), 110 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index 045988a..db11bf3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,6 +24,7 @@ o minor cleanups o fix asymmetric path support (reported by Gary Richards) o improve netlink overrun handling o add more verbose error notification when we fail to inject a conntrack +o rework of the FT-FW approach version 0.9.6 (2008/03/08) ------------------------------ diff --git a/include/network.h b/include/network.h index e4ebec4..0fa7b71 100644 --- a/include/network.h +++ b/include/network.h @@ -26,20 +26,18 @@ struct nethdr_ack { #define NETHDR_ACK_SIZ sizeof(struct nethdr_ack) enum { - NET_F_HELLO_BIT = 0, - NET_F_HELLO = (1 << NET_F_HELLO_BIT), - - NET_F_RESYNC_BIT = 1, - NET_F_RESYNC = (1 << NET_F_RESYNC_BIT), - - NET_F_NACK_BIT = 2, - NET_F_NACK = (1 << NET_F_NACK_BIT), - - NET_F_ACK_BIT = 3, - NET_F_ACK = (1 << NET_F_ACK_BIT), + NET_F_UNUSED = (1 << 0), + NET_F_RESYNC = (1 << 1), + NET_F_NACK = (1 << 2), + NET_F_ACK = (1 << 3), + NET_F_ALIVE = (1 << 4), +}; - NET_F_ALIVE_BIT = 4, - NET_F_ALIVE = (1 << NET_F_ALIVE_BIT), +enum { + MSG_DATA, + MSG_CTL, + MSG_DROP, + MSG_BAD, }; #define BUILD_NETMSG(ct, query) \ @@ -57,7 +55,18 @@ void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); size_t prepare_send_netmsg(struct mcast_sock *m, void *data); int mcast_send_netmsg(struct mcast_sock *m, void *data); int handle_netmsg(struct nethdr *net); + +enum { + SEQ_UNKNOWN, + SEQ_UNSET, + SEQ_IN_SYNC, + SEQ_AFTER, + SEQ_BEFORE, +}; + int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); +void mcast_track_update_seq(uint32_t seq); +int mcast_track_is_seq_set(void); struct mcast_conf; @@ -66,13 +75,12 @@ void mcast_buffered_destroy(void); int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len); ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); -#define IS_DATA(x) ((x->flags & ~NET_F_HELLO) == 0) +#define IS_DATA(x) (x->flags == 0) #define IS_ACK(x) (x->flags & NET_F_ACK) #define IS_NACK(x) (x->flags & NET_F_NACK) #define IS_RESYNC(x) (x->flags & NET_F_RESYNC) #define IS_ALIVE(x) (x->flags & NET_F_ALIVE) #define IS_CTL(x) IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x) || IS_ALIVE(x) -#define IS_HELLO(x) (x->flags & NET_F_HELLO) #define HDR_NETWORK2HOST(x) \ ({ \ diff --git a/src/network.c b/src/network.c index 92999a1..d7ab415 100644 --- a/src/network.c +++ b/src/network.c @@ -33,13 +33,14 @@ static size_t __do_send(struct mcast_sock *m, void *data, size_t len) #undef _TEST_DROP #ifdef _TEST_DROP - static int drop = 0; - if (++drop >= 10) { +#define DROP_RATE .25 + + /* simulate message omission with a certain probability */ + if ((random() & 0x7FFFFFFF) < 0x80000000 * DROP_RATE) { printf("drop sq: %u fl:%u len:%u\n", ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); - drop = 0; return 0; } #endif @@ -57,7 +58,6 @@ static size_t __do_prepare(struct mcast_sock *m, void *data, size_t len) if (!seq_set) { seq_set = 1; cur_seq = time(NULL); - net->flags |= NET_F_HELLO; } net->len = len; net->seq = cur_seq++; @@ -181,9 +181,6 @@ int handle_netmsg(struct nethdr *net) HDR_NETWORK2HOST(net); - if (IS_HELLO(net)) - STATE_SYNC(last_seq_recv) = net->seq - 1; - if (IS_CTL(net)) return 0; @@ -198,37 +195,51 @@ int handle_netmsg(struct nethdr *net) return 0; } +static int local_seq_set = 0; + +/* this function only tracks, it does not update the last sequence received */ int mcast_track_seq(uint32_t seq, uint32_t *exp_seq) { - static int local_seq_set = 0; - int ret = 1; + int ret = SEQ_UNKNOWN; /* netlink sequence tracking initialization */ if (!local_seq_set) { - local_seq_set = 1; + ret = SEQ_UNSET; goto out; } /* fast path: we received the correct sequence */ - if (seq == STATE_SYNC(last_seq_recv)+1) + if (seq == STATE_SYNC(last_seq_recv)+1) { + ret = SEQ_IN_SYNC; goto out; + } /* out of sequence: some messages got lost */ if (after(seq, STATE_SYNC(last_seq_recv)+1)) { STATE_SYNC(packets_lost) += seq-STATE_SYNC(last_seq_recv)+1; - ret = 0; + ret = SEQ_AFTER; goto out; } /* out of sequence: replayed/delayed packet? */ if (before(seq, STATE_SYNC(last_seq_recv)+1)) - dlog(LOG_WARNING, "delayed packet? exp=%u rcv=%u", - STATE_SYNC(last_seq_recv)+1, seq); + ret = SEQ_BEFORE; out: *exp_seq = STATE_SYNC(last_seq_recv)+1; - /* update expected sequence */ - STATE_SYNC(last_seq_recv) = seq; return ret; } + +void mcast_track_update_seq(uint32_t seq) +{ + if (!local_seq_set) + local_seq_set = 1; + + STATE_SYNC(last_seq_recv) = seq; +} + +int mcast_track_is_seq_set() +{ + return local_seq_set; +} diff --git a/src/queue.c b/src/queue.c index 7b20e83..cdd70ae 100644 --- a/src/queue.c +++ b/src/queue.c @@ -93,7 +93,7 @@ retry: goto err; } - list_add(&n->head, &b->head); + list_add_tail(&n->head, &b->head); b->cur_size += size; b->num_elems++; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index cac25d0..0b98513 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -34,11 +34,26 @@ #define dp(...) #endif +#if 0 +#define dprint printf +#else +#define dprint(...) +#endif + static LIST_HEAD(rs_list); static LIST_HEAD(tx_list); +static unsigned int rs_list_len; static unsigned int tx_list_len; static struct queue *rs_queue; static struct queue *tx_queue; +static uint32_t exp_seq; +static uint32_t window; +static uint32_t ack_from; +static int ack_from_set = 0; +static struct alarm_block alive_alarm; + +/* XXX: alive message expiration configurable */ +#define ALIVE_INT 1 struct cache_ftfw { struct list_head rs_list; @@ -64,6 +79,7 @@ static void cache_ftfw_del(struct us_conntrack *u, void *data) /* no need for list_del_init since the entry is destroyed */ list_del(&cn->rs_list); + rs_list_len--; } static struct cache_extra cache_ftfw_extra = { @@ -83,15 +99,57 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); } -static struct alarm_block alive_alarm; +static void ftfw_run(void); +/* this function is called from the alarm framework */ static void do_alive_alarm(struct alarm_block *a, void *data) { - tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); + if (ack_from_set && mcast_track_is_seq_set()) { + /* exp_seq contains the last update received */ + dprint("send ALIVE ACK (from=%u, to=%u)\n", + ack_from, STATE_SYNC(last_seq_recv)); + tx_queue_add_ctlmsg(NET_F_ACK, + ack_from, + STATE_SYNC(last_seq_recv)); + ack_from_set = 0; + } else + tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); + + /* TODO: no need for buffered send, extracted from run_sync() */ + ftfw_run(); + mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); +} - add_alarm(&alive_alarm, 1, 0); +#undef _SIGNAL_DEBUG +#ifdef _SIGNAL_DEBUG + +static int rs_dump(void *data1, const void *data2) +{ + struct nethdr_ack *net = data1; + + dprint("in RS queue -> seq:%u flags:%u\n", net->seq, net->flags); + + return 0; } +#include + +static void my_dump(int foo) +{ + struct cache_ftfw *cn, *tmp; + + list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { + struct us_conntrack *u; + + u = cache_get_conntrack(STATE_SYNC(internal), cn); + dprint("in RS list -> seq:%u\n", cn->seq); + } + + queue_iterate(rs_queue, NULL, rs_dump); +} + +#endif + static int ftfw_init(void) { tx_queue = queue_create(CONFIG(resend_queue_size)); @@ -106,12 +164,15 @@ static int ftfw_init(void) return -1; } - INIT_LIST_HEAD(&tx_list); - INIT_LIST_HEAD(&rs_list); - - /* XXX: alive message expiration configurable */ init_alarm(&alive_alarm, NULL, do_alive_alarm); - add_alarm(&alive_alarm, 1, 0); + add_alarm(&alive_alarm, ALIVE_INT, 0); + + /* set ack window size */ + window = CONFIG(window_size); + +#ifdef _SIGNAL_DEBUG + signal(SIGUSR1, my_dump); +#endif return 0; } @@ -128,7 +189,7 @@ static int do_cache_to_tx(void *data1, void *data2) struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), u); /* add to tx list */ - list_add(&cn->tx_list, &tx_list); + list_add_tail(&cn->tx_list, &tx_list); tx_list_len++; return 0; @@ -157,13 +218,14 @@ static int ftfw_local(int fd, int type, void *data) static int rs_queue_to_tx(void *data1, const void *data2) { - struct nethdr *net = data1; + struct nethdr_ack *net = data1; const struct nethdr_ack *nack = data2; if (between(net->seq, nack->from, nack->to)) { dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", net->seq, net->flags, net->len); queue_add(tx_queue, net, net->len); + queue_del(rs_queue, net); } return 0; } @@ -182,18 +244,20 @@ static int rs_queue_empty(void *data1, const void *data2) static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) { - struct cache_ftfw *cn; + struct cache_ftfw *cn, *tmp; - list_for_each_entry(cn, &rs_list, rs_list) { + list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); if (between(cn->seq, from, to)) { dp("resending nack'ed (oldseq=%u)\n", cn->seq); - list_add(&cn->tx_list, &tx_list); + list_del_init(&cn->rs_list); + rs_list_len--; + list_add_tail(&cn->tx_list, &tx_list); tx_list_len++; - } - } + } + } } static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) @@ -207,54 +271,113 @@ static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) if (between(cn->seq, from, to)) { dp("queue: deleting from queue (seq=%u)\n", cn->seq); list_del_init(&cn->rs_list); - } + rs_list_len--; + } } } -static int ftfw_recv(const struct nethdr *net) +static int digest_msg(const struct nethdr *net) { - static unsigned int window = 0; - unsigned int exp_seq; + if (IS_DATA(net)) + return MSG_DATA; - if (window == 0) - window = CONFIG(window_size); + else if (IS_ACK(net)) { + const struct nethdr_ack *h = (const struct nethdr_ack *) net; - if (!mcast_track_seq(net->seq, &exp_seq)) { - dp("OOS: sending nack (seq=%u)\n", exp_seq); - tx_queue_add_ctlmsg(NET_F_NACK, exp_seq, net->seq-1); - window = CONFIG(window_size); - } else { - /* received a window, send an acknowledgement */ - if (--window == 0) { - dp("sending ack (seq=%u)\n", net->seq); - tx_queue_add_ctlmsg(NET_F_ACK, - net->seq - CONFIG(window_size), - net->seq); - } - } + dprint("ACK(%u): from seq=%u to seq=%u\n", + h->seq, h->from, h->to); + rs_list_empty(STATE_SYNC(internal), h->from, h->to); + queue_iterate(rs_queue, h, rs_queue_empty); + return MSG_CTL; - if (IS_NACK(net)) { + } else if (IS_NACK(net)) { const struct nethdr_ack *nack = (const struct nethdr_ack *) net; - dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); + dprint("NACK(%u): from seq=%u to seq=%u\n", + nack->seq, nack->from, nack->to); rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); queue_iterate(rs_queue, nack, rs_queue_to_tx); - return 1; + return MSG_CTL; + } else if (IS_RESYNC(net)) { dp("RESYNC ALL\n"); cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); - return 1; - } else if (IS_ACK(net)) { - const struct nethdr_ack *h = (const struct nethdr_ack *) net; + return MSG_CTL; - dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); - rs_list_empty(STATE_SYNC(internal), h->from, h->to); - queue_iterate(rs_queue, h, rs_queue_empty); - return 1; } else if (IS_ALIVE(net)) - return 1; + return MSG_CTL; - return 0; + return MSG_BAD; +} + +static int ftfw_recv(const struct nethdr *net) +{ + int ret = MSG_DATA; + + switch (mcast_track_seq(net->seq, &exp_seq)) { + case SEQ_AFTER: + ret = digest_msg(net); + if (ret == MSG_BAD) { + ret = MSG_BAD; + goto out; + } + + if (ack_from_set) { + tx_queue_add_ctlmsg(NET_F_ACK, ack_from, exp_seq-1); + dprint("OFS send half ACK: from seq=%u to seq=%u\n", + ack_from, exp_seq-1); + ack_from_set = 0; + } + + tx_queue_add_ctlmsg(NET_F_NACK, exp_seq, net->seq-1); + dprint("OFS send NACK: from seq=%u to seq=%u\n", + exp_seq, net->seq-1); + + /* count this message as part of the new window */ + window = CONFIG(window_size) - 1; + ack_from = net->seq; + ack_from_set = 1; + break; + + case SEQ_BEFORE: + /* we don't accept delayed packets */ + dlog(LOG_WARNING, "Received seq=%u before expected seq=%u", + net->seq, exp_seq); + dlog(LOG_WARNING, "Probably the other node has come back" + "to life but you forgot to add " + "conntrackd -r to your scripts"); + ret = MSG_DROP; + break; + + case SEQ_UNSET: + case SEQ_IN_SYNC: + ret = digest_msg(net); + if (ret == MSG_BAD) { + ret = MSG_BAD; + goto out; + } + + if (!ack_from_set) { + ack_from_set = 1; + ack_from = net->seq; + } + + if (--window <= 0) { + /* received a window, send an acknowledgement */ + dprint("OFS send ACK: from seq=%u to seq=%u\n", + ack_from, net->seq); + + tx_queue_add_ctlmsg(NET_F_ACK, ack_from, net->seq); + window = CONFIG(window_size); + ack_from_set = 0; + } + } + +out: + if ((ret == MSG_DATA || ret == MSG_CTL)) + mcast_track_update_seq(net->seq); + + return ret; } static void ftfw_send(struct nethdr *net, struct us_conntrack *u) @@ -270,11 +393,14 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) cn = (struct cache_ftfw *) cache_get_extra(STATE_SYNC(internal), u); - if (!list_empty(&cn->rs_list)) - list_del(&cn->rs_list); + if (!list_empty(&cn->rs_list)) { + list_del_init(&cn->rs_list); + rs_list_len--; + } cn->seq = net->seq; - list_add(&cn->rs_list, &rs_list); + list_add_tail(&cn->rs_list, &rs_list); + rs_list_len++; break; case NFCT_Q_DESTROY: queue_add(rs_queue, net, net->len); @@ -294,7 +420,7 @@ static int tx_queue_xmit(void *data1, const void *data2) HDR_NETWORK2HOST(net); if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) { - dp("-> back_to_tx_queue sq: %u fl:%u len:%u\n", + dprint("tx_queue -> to_rs_queue sq: %u fl:%u len:%u\n", net->seq, net->flags, net->len); queue_add(rs_queue, net, net->len); } @@ -317,8 +443,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) tx_list_len--; ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, u); + ftfw_send(net, u); return ret; } @@ -337,6 +462,14 @@ static void ftfw_run(void) u = cache_get_conntrack(STATE_SYNC(internal), cn); tx_list_xmit(&cn->tx_list, u); } + + /* reset alive alarm */ + add_alarm(&alive_alarm, 1, 0); + + dprint("tx_list_len:%u tx_queue_len:%u " + "rs_list_len: %u rs_queue_len:%u\n", + tx_list_len, queue_len(tx_queue), + rs_list_len, queue_len(rs_queue)); } struct sync_mode sync_ftfw = { diff --git a/src/sync-mode.c b/src/sync-mode.c index 3851e4a..cbb4769 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -42,8 +42,18 @@ static void do_mcast_handler_step(struct nethdr *net) struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; struct us_conntrack *u; - if (STATE_SYNC(sync)->recv(net)) - return; + switch (STATE_SYNC(sync)->recv(net)) { + case MSG_DATA: + break; + case MSG_DROP: + case MSG_CTL: + return; + case MSG_BAD: + STATE(malformed)++; + return; + default: + break; + } memset(ct, 0, sizeof(__ct)); @@ -211,14 +221,15 @@ static int register_fds_sync(struct fds *fds) static void run_sync(fd_set *readfds) { /* multicast packet has been received */ - if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) + if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) { mcast_handler(); - if (STATE_SYNC(sync)->run) - STATE_SYNC(sync)->run(); + if (STATE_SYNC(sync)->run) + STATE_SYNC(sync)->run(); - /* flush pending messages */ - mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); + /* flush pending messages */ + mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); + } } static void kill_sync(void) @@ -358,16 +369,8 @@ static int purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { - size_t len; - struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_DESTROY); - debug_ct(u->ct, "overrun purge resync"); - - len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, u); - + mcast_send_sync(u, u->ct, NFCT_Q_DESTROY); cache_del(STATE_SYNC(internal), u->ct); } @@ -402,16 +405,8 @@ static int overrun_sync(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { - size_t len; - debug_ct(u->ct, "overrun resync"); - - struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); - len = prepare_send_netmsg(STATE_SYNC(mcast_client),net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), - net, len); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, u); + mcast_send_sync(u, u->ct, NFCT_Q_UPDATE); } } @@ -437,7 +432,6 @@ retry: } else { if (errno == EEXIST) { cache_del(STATE_SYNC(internal), ct); - mcast_send_sync(NULL, ct, NFCT_Q_DESTROY); goto retry; } -- cgit v1.2.3 From db91cafe5b72f9f591dd8c168427005503186c01 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 18 May 2008 21:16:05 +0200 Subject: improve network message sanity checkings --- ChangeLog | 1 + include/network.h | 3 +-- include/sync.h | 1 + src/network.c | 24 ------------------------ src/parse.c | 30 +++++++++++++++++++++++++++--- src/sync-mode.c | 41 ++++++++++++++++++++++++++++++----------- 6 files changed, 60 insertions(+), 40 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index d67ad30..4458830 100644 --- a/ChangeLog +++ b/ChangeLog @@ -29,6 +29,7 @@ o minor fix of the manpage (Max Wilhelm) o remove (misleading) counters and use information from the statistics mode o use generic nfct_copy() from libnetfilter_conntrack to update objects o use generic nfct_cmp() to compare objects +o improve network message sanity checkings version 0.9.6 (2008/03/08) ------------------------------ diff --git a/include/network.h b/include/network.h index 0fa7b71..baa1eba 100644 --- a/include/network.h +++ b/include/network.h @@ -54,7 +54,6 @@ struct mcast_sock; void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); size_t prepare_send_netmsg(struct mcast_sock *m, void *data); int mcast_send_netmsg(struct mcast_sock *m, void *data); -int handle_netmsg(struct nethdr *net); enum { SEQ_UNKNOWN, @@ -175,6 +174,6 @@ struct netattr { void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query); -void parse_netpld(struct nf_conntrack *ct, struct netpld *pld, int *query); +int parse_netpld(struct nf_conntrack *ct, struct nethdr *net, int *query, size_t remain); #endif diff --git a/include/sync.h b/include/sync.h index 39e0f46..fc06c93 100644 --- a/include/sync.h +++ b/include/sync.h @@ -20,5 +20,6 @@ struct sync_mode { extern struct sync_mode sync_alarm; extern struct sync_mode sync_ftfw; +extern struct sync_mode sync_notrack; #endif diff --git a/src/network.c b/src/network.c index d7ab415..fb6ea90 100644 --- a/src/network.c +++ b/src/network.c @@ -171,30 +171,6 @@ void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net) build_netpld(ct, pld, query); } -int handle_netmsg(struct nethdr *net) -{ - struct netpld *pld = NETHDR_DATA(net); - - /* message too small: no room for the header */ - if (ntohs(net->len) < NETHDR_ACK_SIZ) - return -1; - - HDR_NETWORK2HOST(net); - - if (IS_CTL(net)) - return 0; - - /* information received is too small */ - if (net->len < sizeof(struct netpld)) - return -1; - - /* size mismatch! */ - if (net->len < ntohs(pld->len) + NETHDR_SIZ) - return -1; - - return 0; -} - static int local_seq_set = 0; /* this function only tracks, it does not update the last sequence received */ diff --git a/src/parse.c b/src/parse.c index 8ef2e8d..645420d 100644 --- a/src/parse.c +++ b/src/parse.c @@ -20,6 +20,10 @@ #include +#ifndef ssizeof +#define ssizeof(x) (int)sizeof(x) +#endif + static void parse_u8(struct nf_conntrack *ct, int attr, void *data) { uint8_t *value = (uint8_t *) data; @@ -77,20 +81,40 @@ static parse h[ATTR_MAX] = { [ATTR_REPL_NAT_SEQ_OFFSET_AFTER] = parse_u32, }; -void parse_netpld(struct nf_conntrack *ct, struct netpld *pld, int *query) +int +parse_netpld(struct nf_conntrack *ct, + struct nethdr *net, + int *query, + size_t remain) { int len; struct netattr *attr; + struct netpld *pld; + + if (remain < NETHDR_SIZ + sizeof(struct netpld)) + return -1; + + pld = NETHDR_DATA(net); + + if (remain < NETHDR_SIZ + sizeof(struct netpld) + ntohs(pld->len)) + return -1; + + if (net->len < NETHDR_SIZ + sizeof(struct netpld) + ntohs(pld->len)) + return -1; PLD_NETWORK2HOST(pld); len = pld->len; attr = PLD_DATA(pld); - while (len > 0) { + while (len > ssizeof(struct netattr)) { ATTR_NETWORK2HOST(attr); - h[attr->nta_attr](ct, attr->nta_attr, NTA_DATA(attr)); + if (attr->nta_len > len) + return -1; + if (h[attr->nta_attr]) + h[attr->nta_attr](ct, attr->nta_attr, NTA_DATA(attr)); attr = NTA_NEXT(attr, len); } *query = pld->query; + return 0; } diff --git a/src/sync-mode.c b/src/sync-mode.c index a952a5b..7d73e2f 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -34,10 +34,9 @@ #include #include -static void do_mcast_handler_step(struct nethdr *net) +static void do_mcast_handler_step(struct nethdr *net, size_t remain) { int query; - struct netpld *pld = NETHDR_DATA(net); char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; struct us_conntrack *u; @@ -57,8 +56,11 @@ static void do_mcast_handler_step(struct nethdr *net) memset(ct, 0, sizeof(__ct)); - /* XXX: check for malformed */ - parse_netpld(ct, pld, &query); + if (parse_netpld(ct, net, &query, remain) == -1) { + STATE(malformed)++; + dlog(LOG_ERR, "parsing failed: malformed message"); + return; + } switch(query) { case NFCT_Q_CREATE: @@ -91,6 +93,7 @@ retry: debug_ct(ct, "can't destroy"); break; default: + STATE(malformed)++; dlog(LOG_ERR, "mcast unknown query %d\n", query); break; } @@ -113,24 +116,40 @@ static void mcast_handler(void) if (remain < NETHDR_SIZ) { STATE(malformed)++; + dlog(LOG_WARNING, "no room for header"); break; } if (ntohs(net->len) > remain) { - dlog(LOG_ERR, "fragmented messages"); + STATE(malformed)++; + dlog(LOG_WARNING, "fragmented message"); break; } + if (IS_CTL(net)) { + if (remain < NETHDR_ACK_SIZ) { + STATE(malformed)++; + dlog(LOG_WARNING, "no room for ctl message"); + } + + if (ntohs(net->len) < NETHDR_ACK_SIZ) { + STATE(malformed)++; + dlog(LOG_WARNING, "ctl header too small"); + } + } else { + if (ntohs(net->len) < NETHDR_SIZ) { + STATE(malformed)++; + dlog(LOG_WARNING, "header too small"); + } + } + debug("recv sq: %u fl:%u len:%u (rem:%d)\n", ntohl(net->seq), ntohs(net->flags), ntohs(net->len), remain); - /* sanity check and convert nethdr to host byte order */ - if (handle_netmsg(net) == -1) { - STATE(malformed)++; - return; - } - do_mcast_handler_step(net); + HDR_NETWORK2HOST(net); + + do_mcast_handler_step(net, remain); ptr += net->len; remain -= net->len; } -- cgit v1.2.3 From e877faf2c1c557399a57a884a21133e607909b16 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 26 May 2008 02:24:03 +0200 Subject: rework the HELLO logic inside FT-FW --- ChangeLog | 1 + include/network.h | 12 +++++++++++- src/sync-ftfw.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ src/sync-mode.c | 4 +++- 4 files changed, 59 insertions(+), 8 deletions(-) (limited to 'include/network.h') diff --git a/ChangeLog b/ChangeLog index 597206a..14ba054 100644 --- a/ChangeLog +++ b/ChangeLog @@ -36,6 +36,7 @@ o add Mcast[Snd|Rcv]SocketBuffer clauses to tune multicast socket buffers o add missing string.h required by strdup in config parsing o add eventfd emulation to communicate receiver -> sender o add best effort replication protocol (aka NOTRACK) +o rework the HELLO logic inside FT-FW version 0.9.6 (2008/03/08) ------------------------------ diff --git a/include/network.h b/include/network.h index baa1eba..777be11 100644 --- a/include/network.h +++ b/include/network.h @@ -31,6 +31,8 @@ enum { NET_F_NACK = (1 << 2), NET_F_ACK = (1 << 3), NET_F_ALIVE = (1 << 4), + NET_F_HELLO = (1 << 5), + NET_F_HELLO_BACK= (1 << 6), }; enum { @@ -63,6 +65,12 @@ enum { SEQ_BEFORE, }; +enum { + SAY_HELLO, + HELLO_BACK, + HELLO_DONE, +}; + int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); void mcast_track_update_seq(uint32_t seq); int mcast_track_is_seq_set(void); @@ -74,12 +82,14 @@ void mcast_buffered_destroy(void); int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len); ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); -#define IS_DATA(x) (x->flags == 0) +#define IS_DATA(x) ((x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) #define IS_ACK(x) (x->flags & NET_F_ACK) #define IS_NACK(x) (x->flags & NET_F_NACK) #define IS_RESYNC(x) (x->flags & NET_F_RESYNC) #define IS_ALIVE(x) (x->flags & NET_F_ALIVE) #define IS_CTL(x) IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x) || IS_ALIVE(x) +#define IS_HELLO(x) (x->flags & NET_F_HELLO) +#define IS_HELLO_BACK(x)(x->flags & NET_F_HELLO_BACK) #define HDR_NETWORK2HOST(x) \ ({ \ diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index adfdda9..42005c4 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -52,6 +52,7 @@ static uint32_t window; static uint32_t ack_from; static int ack_from_set = 0; static struct alarm_block alive_alarm; +static int hello_state = SAY_HELLO; /* XXX: alive message expiration configurable */ #define ALIVE_INT 1 @@ -97,6 +98,16 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) .to = to, }; + switch(hello_state) { + case SAY_HELLO: + ack.flags |= NET_F_HELLO; + break; + case HELLO_BACK: + ack.flags |= NET_F_HELLO_BACK; + hello_state = HELLO_DONE; + break; + } + queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); write_evfd(STATE_SYNC(evfd)); } @@ -315,10 +326,29 @@ static int digest_msg(const struct nethdr *net) return MSG_BAD; } +static int digest_hello(const struct nethdr *net) +{ + int ret = 0; + + if (IS_HELLO(net)) { + dlog(LOG_NOTICE, "The other node says HELLO"); + hello_state = HELLO_BACK; + ret = 1; + } else if (IS_HELLO_BACK(net)) { + dlog(LOG_NOTICE, "The other node says HELLO BACK"); + hello_state = HELLO_DONE; + } + + return ret; +} + static int ftfw_recv(const struct nethdr *net) { int ret = MSG_DATA; + if (digest_hello(net)) + goto bypass; + switch (mcast_track_seq(net->seq, &exp_seq)) { case SEQ_AFTER: ret = digest_msg(net); @@ -348,14 +378,12 @@ static int ftfw_recv(const struct nethdr *net) /* we don't accept delayed packets */ dlog(LOG_WARNING, "Received seq=%u before expected seq=%u", net->seq, exp_seq); - dlog(LOG_WARNING, "Probably the other node has come back" - "to life but you forgot to add " - "conntrackd -r to your scripts"); ret = MSG_DROP; break; case SEQ_UNSET: case SEQ_IN_SYNC: +bypass: ret = digest_msg(net); if (ret == MSG_BAD) { ret = MSG_BAD; @@ -390,8 +418,6 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) struct netpld *pld = NETHDR_DATA(net); struct cache_ftfw *cn; - HDR_NETWORK2HOST(net); - switch(ntohs(pld->query)) { case NFCT_Q_CREATE: case NFCT_Q_UPDATE: @@ -404,7 +430,19 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) rs_list_len--; } - cn->seq = net->seq; + switch(hello_state) { + case SAY_HELLO: + net->flags = ntohs(net->flags) | NET_F_HELLO; + net->flags = htons(net->flags); + break; + case HELLO_BACK: + net->flags = ntohs(net->flags) | NET_F_HELLO_BACK; + net->flags = htons(net->flags); + hello_state = HELLO_DONE; + break; + } + + cn->seq = ntohl(net->seq); list_add_tail(&cn->rs_list, &rs_list); rs_list_len++; break; diff --git a/src/sync-mode.c b/src/sync-mode.c index 16cc70d..4b36935 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -395,9 +395,11 @@ static void mcast_send_sync(struct us_conntrack *u, int query) net = BUILD_NETMSG(u->ct, query); len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + if (STATE_SYNC(sync)->send) STATE_SYNC(sync)->send(net, u); + + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); } static int purge_step(void *data1, void *data2) -- cgit v1.2.3 From 30216bf35c8cfe078ede4c4ad7f43544b469b7d3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 25 Sep 2008 17:06:12 +0200 Subject: ftfw: fix race condition in the helloing routine This patch fixes a race condition that can prevent one node from sending the initial hello message required to reset the sequence tracking. node A node B | | start | | hello msg |----------------------->| stop | | start | | |<-----------------------| hello-back msg In the picture above, the node A never sends the hello messages. Thus, the node B drops the next messages as they are in the before boundary. This patch adds a new state to the the helloing state-machine to fix this problem. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 6 ------ src/sync-ftfw.c | 44 ++++++++++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 20 deletions(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 777be11..d2e4edd 100644 --- a/include/network.h +++ b/include/network.h @@ -65,12 +65,6 @@ enum { SEQ_BEFORE, }; -enum { - SAY_HELLO, - HELLO_BACK, - HELLO_DONE, -}; - int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); void mcast_track_update_seq(uint32_t seq); int mcast_track_is_seq_set(void); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 8dd5554..11c0638 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -46,7 +46,14 @@ static uint32_t window; static uint32_t ack_from; static int ack_from_set = 0; static struct alarm_block alive_alarm; -static int hello_state = SAY_HELLO; + +enum { + HELLO_INIT, + HELLO_SAY, + HELLO_DONE, +}; +static int hello_state = HELLO_INIT; +static int say_hello_back; /* XXX: alive message expiration configurable */ #define ALIVE_INT 1 @@ -96,13 +103,17 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) }; switch(hello_state) { - case SAY_HELLO: + case HELLO_INIT: + hello_state = HELLO_SAY; + /* fall through */ + case HELLO_SAY: ack.flags |= NET_F_HELLO; break; - case HELLO_BACK: + } + + if (say_hello_back) { ack.flags |= NET_F_HELLO_BACK; - hello_state = HELLO_DONE; - break; + say_hello_back = 0; } queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); @@ -335,12 +346,13 @@ static int digest_hello(const struct nethdr *net) int ret = 0; if (IS_HELLO(net)) { - dlog(LOG_NOTICE, "The other node says HELLO"); - hello_state = HELLO_BACK; + say_hello_back = 1; ret = 1; - } else if (IS_HELLO_BACK(net)) { - dlog(LOG_NOTICE, "The other node says HELLO BACK"); - hello_state = HELLO_DONE; + } + if (IS_HELLO_BACK(net)) { + /* this is a hello back for a requested hello */ + if (hello_state == HELLO_SAY) + hello_state = HELLO_DONE; } return ret; @@ -428,15 +440,19 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) } switch(hello_state) { - case SAY_HELLO: + case HELLO_INIT: + hello_state = HELLO_SAY; + /* fall through */ + case HELLO_SAY: net->flags = ntohs(net->flags) | NET_F_HELLO; net->flags = htons(net->flags); break; - case HELLO_BACK: + } + + if (say_hello_back) { net->flags = ntohs(net->flags) | NET_F_HELLO_BACK; net->flags = htons(net->flags); - hello_state = HELLO_DONE; - break; + say_hello_back = 0; } cn->seq = ntohl(net->seq); -- cgit v1.2.3 From 64ce47955778805afceb6ced58b63839763541ad Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 2 Nov 2008 21:29:04 +0100 Subject: network: add protocol version field (breaks backward compatibility) This patch adds the version field (8-bits long) to the nethdr structure. This fields can be used to indicate the protocol version in case that we detect an incompatibility between two conntrackd daemons working with different protocol versions. Unfortunately, this patch breaks backward compatibility, ie. conntrackd <= 0.9.8 protocol is not compatible with the upcoming conntrackd >= 0.9.9. Better do this now than later. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 10 ++++++---- src/network.c | 4 ++-- src/sync-ftfw.c | 11 ++++------- src/sync-mode.c | 8 +++++++- 4 files changed, 19 insertions(+), 14 deletions(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index d2e4edd..d2431f9 100644 --- a/include/network.h +++ b/include/network.h @@ -4,10 +4,13 @@ #include #include +#define CONNTRACKD_PROTOCOL_VERSION 0 + struct nf_conntrack; struct nethdr { - uint16_t flags; + uint8_t version; + uint8_t flags; uint16_t len; uint32_t seq; }; @@ -17,7 +20,8 @@ struct nethdr { (struct netpld *)(((char *)x) + sizeof(struct nethdr)) struct nethdr_ack { - uint16_t flags; + uint8_t version; + uint8_t flags; uint16_t len; uint32_t seq; uint32_t from; @@ -87,7 +91,6 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); #define HDR_NETWORK2HOST(x) \ ({ \ - x->flags = ntohs(x->flags); \ x->len = ntohs(x->len); \ x->seq = ntohl(x->seq); \ if (IS_CTL(x)) { \ @@ -104,7 +107,6 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); __ack->from = htonl(__ack->from); \ __ack->to = htonl(__ack->to); \ } \ - x->flags = htons(x->flags); \ x->len = htons(x->len); \ x->seq = htonl(x->seq); \ }) diff --git a/src/network.c b/src/network.c index 7d1d9fa..04c9d39 100644 --- a/src/network.c +++ b/src/network.c @@ -32,8 +32,7 @@ static size_t __do_send(struct mcast_sock *m, void *data, size_t len) struct nethdr *net = data; debug("send sq: %u fl:%u len:%u\n", - ntohl(net->seq), ntohs(net->flags), - ntohs(net->len)); + ntohl(net->seq), net->flags, ntohs(net->len)); return mcast_send(m, net, len); } @@ -46,6 +45,7 @@ static size_t __do_prepare(struct mcast_sock *m, void *data, size_t len) seq_set = 1; cur_seq = time(NULL); } + net->version = CONNTRACKD_PROTOCOL_VERSION; net->len = len; net->seq = cur_seq++; HDR_HOST2NETWORK(net); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index ed97ceb..598945f 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -477,14 +477,12 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) hello_state = HELLO_SAY; /* fall through */ case HELLO_SAY: - net->flags = ntohs(net->flags) | NET_F_HELLO; - net->flags = htons(net->flags); + net->flags |= NET_F_HELLO; break; } if (say_hello_back) { - net->flags = ntohs(net->flags) | NET_F_HELLO_BACK; - net->flags = htons(net->flags); + net->flags |= NET_F_HELLO_BACK; say_hello_back = 0; } @@ -501,7 +499,7 @@ static int tx_queue_xmit(void *data1, const void *data2) size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); dp("tx_queue sq: %u fl:%u len:%u\n", - ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); + ntohl(net->seq), net->flags, ntohs(net->len)); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); HDR_NETWORK2HOST(net); @@ -521,8 +519,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); dp("tx_list sq: %u fl:%u len:%u\n", - ntohl(net->seq), ntohs(net->flags), - ntohs(net->len)); + ntohl(net->seq), net->flags, ntohs(net->len)); list_del_init(i); tx_list_len--; diff --git a/src/sync-mode.c b/src/sync-mode.c index 4c22745..152a8e2 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -41,6 +41,12 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; struct us_conntrack *u; + if (net->version != CONNTRACKD_PROTOCOL_VERSION) { + STATE(malformed)++; + dlog(LOG_WARNING, "wrong protocol version `%u'", net->version); + return; + } + switch (STATE_SYNC(sync)->recv(net)) { case MSG_DATA: break; @@ -144,7 +150,7 @@ static void mcast_handler(void) } debug("recv sq: %u fl:%u len:%u (rem:%d)\n", - ntohl(net->seq), ntohs(net->flags), + ntohl(net->seq), net->flags, ntohs(net->len), remain); HDR_NETWORK2HOST(net); -- cgit v1.2.3 From 76ac8ebe5e49385585c8e29fe530ed4baef390bf Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 2 Nov 2008 21:35:42 +0100 Subject: network: rework TLV-based protocol This patch reworks the TLV-based protocol to reduce the overhead in the message building. The idea is to group some attributes that must be present in a consistent configuration. Putting them together help us to save some cycles in the message building. Now, oprofile reports ~15% of samples in the build path instead of ~25%. CPU consumption for 3000 HTTP GET requests per second (1000 concurrent with apache benchmark tool) is ~45% in my testbed, that is ~19% more consumption than with no replication at all. Signed-off-by: Pablo Neira Ayuso --- configure.in | 2 +- include/network.h | 29 ++++++++ src/build.c | 202 ++++++++++++++++++++++++++---------------------------- src/parse.c | 153 +++++++++++++++++++++++++++++------------ 4 files changed, 240 insertions(+), 146 deletions(-) (limited to 'include/network.h') diff --git a/configure.in b/configure.in index c66679d..0994e60 100644 --- a/configure.in +++ b/configure.in @@ -18,7 +18,7 @@ esac dnl Dependencies LIBNFNETLINK_REQUIRED=0.0.33 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.97 +LIBNETFILTER_CONNTRACK_REQUIRED=0.0.98 AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes) if test "x$HAVE_PKG_CONFIG" = "x" diff --git a/include/network.h b/include/network.h index d2431f9..2487c81 100644 --- a/include/network.h +++ b/include/network.h @@ -178,6 +178,35 @@ struct netattr { #define NTA_ALIGN(len) (((len) + NTA_ALIGNTO - 1) & ~(NTA_ALIGNTO - 1)) #define NTA_LENGTH(len) (NTA_ALIGN(sizeof(struct netattr)) + (len)) +enum nta_attr { + NTA_IPV4 = 0, /* struct nfct_attr_grp_ipv4 */ + NTA_IPV6, /* struct nfct_attr_grp_ipv6 */ + NTA_L4PROTO, /* uint8_t */ + NTA_PORT, /* struct nfct_attr_grp_port */ + NTA_STATE = 4, /* uint8_t */ + NTA_STATUS, /* uint32_t */ + NTA_TIMEOUT, /* uint32_t */ + NTA_MARK, /* uint32_t */ + NTA_MASTER_IPV4 = 8, /* struct nfct_attr_grp_ipv4 */ + NTA_MASTER_IPV6, /* struct nfct_attr_grp_ipv6 */ + NTA_MASTER_L4PROTO, /* uint8_t */ + NTA_MASTER_PORT, /* struct nfct_attr_grp_port */ + NTA_SNAT_IPV4 = 12, /* uint32_t */ + NTA_DNAT_IPV4, /* uint32_t */ + NTA_SPAT_PORT, /* uint16_t */ + NTA_DPAT_PORT, /* uint16_t */ + NTA_NAT_SEQ_ADJ = 16, /* struct nta_attr_natseqadj */ +}; + +struct nta_attr_natseqadj { + uint32_t orig_seq_correction_pos; + uint32_t orig_seq_offset_before; + uint32_t orig_seq_offset_after; + uint32_t repl_seq_correction_pos; + uint32_t repl_seq_offset_before; + uint32_t repl_seq_offset_after; +}; + void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query); int parse_netpld(struct nf_conntrack *ct, struct nethdr *net, int *query, size_t remain); diff --git a/src/build.c b/src/build.c index be33c86..5143048 100644 --- a/src/build.c +++ b/src/build.c @@ -1,5 +1,5 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2008 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 @@ -20,143 +20,139 @@ #include #include "network.h" -static void addattr(struct netpld *pld, int attr, const void *data, size_t len) +static inline void * +put_header(struct netpld *pld, int attr, size_t len) { - struct netattr *nta; - int tlen = NTA_LENGTH(len); - - nta = PLD_TAIL(pld); + struct netattr *nta = PLD_TAIL(pld); + pld->len += NTA_ALIGN(NTA_LENGTH(len)); nta->nta_attr = htons(attr); nta->nta_len = htons(len); - memcpy(NTA_DATA(nta), data, len); - pld->len += NTA_ALIGN(tlen); + return NTA_DATA(nta); } -static void __build_u8(const struct nf_conntrack *ct, - struct netpld *pld, - int attr) +static inline void +addattr(struct netpld *pld, int attr, const void *data, size_t len) { - uint8_t data = nfct_get_attr_u8(ct, attr); - addattr(pld, attr, &data, sizeof(uint8_t)); + void *ptr = put_header(pld, attr, len); + memcpy(ptr, data, len); } -static void __build_u16(const struct nf_conntrack *ct, - struct netpld *pld, - int attr) +static inline void +__build_u8(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) { - uint16_t data = nfct_get_attr_u16(ct, attr); - data = htons(data); - addattr(pld, attr, &data, sizeof(uint16_t)); + void *ptr = put_header(pld, b, sizeof(uint8_t)); + memcpy(ptr, nfct_get_attr(ct, a), sizeof(uint8_t)); } -static void __build_u32(const struct nf_conntrack *ct, - struct netpld *pld, - int attr) +static inline void +__build_u16(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) { - uint32_t data = nfct_get_attr_u32(ct, attr); - data = htonl(data); - addattr(pld, attr, &data, sizeof(uint32_t)); + uint32_t data = nfct_get_attr_u16(ct, a); + data = htons(data); + addattr(pld, b, &data, sizeof(uint16_t)); } -static void __build_pointer_be(const struct nf_conntrack *ct, - struct netpld *pld, - int attr, - size_t size) +static inline void +__build_u32(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) { - addattr(pld, attr, nfct_get_attr(ct, attr), size); + uint32_t data = nfct_get_attr_u32(ct, a); + data = htonl(data); + addattr(pld, b, &data, sizeof(uint32_t)); } -static void __nat_build_u32(uint32_t data, struct netpld *pld, int attr) +static inline void +__build_group(const struct nf_conntrack *ct, int a, struct netpld *pld, + int b, int size) { - data = htonl(data); - addattr(pld, attr, &data, sizeof(uint32_t)); + void *ptr = put_header(pld, b, size); + nfct_get_attr_grp(ct, a, ptr); } -static void __nat_build_u16(uint16_t data, struct netpld *pld, int attr) +static inline void +__build_natseqadj(const struct nf_conntrack *ct, struct netpld *pld) { - data = htons(data); - addattr(pld, attr, &data, sizeof(uint16_t)); + struct nta_attr_natseqadj data = { + .orig_seq_correction_pos = + htonl(nfct_get_attr_u32(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS)), + .orig_seq_offset_before = + htonl(nfct_get_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE)), + .orig_seq_offset_after = + htonl(nfct_get_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER)), + .repl_seq_correction_pos = + htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_CORRECTION_POS)), + .repl_seq_offset_before = + htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE)), + .repl_seq_offset_after = + htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER)) + }; + addattr(pld, NTA_NAT_SEQ_ADJ, &data, sizeof(struct nta_attr_natseqadj)); } +static enum nf_conntrack_attr nat_type[] = + { ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, + ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ATTR_REPL_NAT_SEQ_CORRECTION_POS, + ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, ATTR_REPL_NAT_SEQ_OFFSET_AFTER }; + /* XXX: ICMP not supported */ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) { - if (nfct_attr_is_set(ct, ATTR_IPV4_SRC)) - __build_pointer_be(ct, pld, ATTR_IPV4_SRC, sizeof(uint32_t)); - if (nfct_attr_is_set(ct, ATTR_IPV4_DST)) - __build_pointer_be(ct, pld, ATTR_IPV4_DST, sizeof(uint32_t)); - if (nfct_attr_is_set(ct, ATTR_IPV6_SRC)) - __build_pointer_be(ct, pld, ATTR_IPV6_SRC, sizeof(uint32_t)*4); - if (nfct_attr_is_set(ct, ATTR_IPV6_DST)) - __build_pointer_be(ct, pld, ATTR_IPV6_DST, sizeof(uint32_t)*4); - if (nfct_attr_is_set(ct, ATTR_L3PROTO)) - __build_u8(ct, pld, ATTR_L3PROTO); - if (nfct_attr_is_set(ct, ATTR_PORT_SRC)) - __build_u16(ct, pld, ATTR_PORT_SRC); - if (nfct_attr_is_set(ct, ATTR_PORT_DST)) - __build_u16(ct, pld, ATTR_PORT_DST); - if (nfct_attr_is_set(ct, ATTR_L4PROTO)) { - uint8_t proto; - - __build_u8(ct, pld, ATTR_L4PROTO); - proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); - if (proto == IPPROTO_TCP) { - if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) - __build_u8(ct, pld, ATTR_TCP_STATE); - } + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { + __build_group(ct, ATTR_GRP_ORIG_IPV4, pld, NTA_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { + __build_group(ct, ATTR_GRP_ORIG_IPV6, pld, NTA_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + } + + __build_u8(ct, ATTR_L4PROTO, pld, NTA_L4PROTO); + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_PORT)) { + __build_group(ct, ATTR_GRP_ORIG_PORT, pld, NTA_PORT, + sizeof(struct nfct_attr_grp_port)); } + + __build_u32(ct, ATTR_STATUS, pld, NTA_STATUS); + + if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) + __build_u8(ct, ATTR_TCP_STATE, pld, NTA_STATE); if (nfct_attr_is_set(ct, ATTR_TIMEOUT)) - __build_u32(ct, pld, ATTR_TIMEOUT); + __build_u32(ct, ATTR_TIMEOUT, pld, NTA_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) - __build_u32(ct, pld, ATTR_MARK); - if (nfct_attr_is_set(ct, ATTR_STATUS)) - __build_u32(ct, pld, ATTR_STATUS); + __build_u32(ct, ATTR_MARK, pld, NTA_MARK); /* setup the master conntrack */ - if (nfct_attr_is_set(ct, ATTR_MASTER_IPV4_SRC)) - __build_u32(ct, pld, ATTR_MASTER_IPV4_SRC); - if (nfct_attr_is_set(ct, ATTR_MASTER_IPV4_DST)) - __build_u32(ct, pld, ATTR_MASTER_IPV4_DST); - if (nfct_attr_is_set(ct, ATTR_MASTER_L3PROTO)) - __build_u8(ct, pld, ATTR_MASTER_L3PROTO); - if (nfct_attr_is_set(ct, ATTR_MASTER_PORT_SRC)) - __build_u16(ct, pld, ATTR_MASTER_PORT_SRC); - if (nfct_attr_is_set(ct, ATTR_MASTER_PORT_DST)) - __build_u16(ct, pld, ATTR_MASTER_PORT_DST); - if (nfct_attr_is_set(ct, ATTR_MASTER_L4PROTO)) - __build_u8(ct, pld, ATTR_MASTER_L4PROTO); + if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV4)) { + __build_group(ct, ATTR_GRP_MASTER_IPV4, pld, NTA_MASTER_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + __build_u8(ct, ATTR_MASTER_L4PROTO, pld, NTA_MASTER_L4PROTO); + if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { + __build_group(ct, ATTR_GRP_MASTER_PORT, + pld, NTA_MASTER_PORT, + sizeof(struct nfct_attr_grp_port)); + } + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV6)) { + __build_group(ct, ATTR_GRP_MASTER_IPV6, pld, NTA_MASTER_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + __build_u8(ct, ATTR_MASTER_L4PROTO, pld, NTA_MASTER_L4PROTO); + if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { + __build_group(ct, ATTR_GRP_MASTER_PORT, + pld, NTA_MASTER_PORT, + sizeof(struct nfct_attr_grp_port)); + } + } /* NAT */ - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { - uint32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST); - __nat_build_u32(data, pld, ATTR_SNAT_IPV4); - } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { - uint32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); - __nat_build_u32(data, pld, ATTR_DNAT_IPV4); - } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) { - uint16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST); - __nat_build_u16(data, pld, ATTR_SNAT_PORT); - } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) { - uint16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC); - __nat_build_u16(data, pld, ATTR_DNAT_PORT); - } + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) + __build_u32(ct, ATTR_REPL_IPV4_DST, pld, NTA_SNAT_IPV4); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + __build_u32(ct, ATTR_REPL_IPV4_SRC, pld, NTA_DNAT_IPV4); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) + __build_u16(ct, ATTR_REPL_PORT_DST, pld, NTA_SPAT_PORT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) + __build_u16(ct, ATTR_REPL_PORT_SRC, pld, NTA_DPAT_PORT); /* NAT sequence adjustment */ - if (nfct_attr_is_set(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS)) - __build_u32(ct, pld, ATTR_ORIG_NAT_SEQ_CORRECTION_POS); - if (nfct_attr_is_set(ct, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE)) - __build_u32(ct, pld, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE); - if (nfct_attr_is_set(ct, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER)) - __build_u32(ct, pld, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER); - if (nfct_attr_is_set(ct, ATTR_REPL_NAT_SEQ_CORRECTION_POS)) - __build_u32(ct, pld, ATTR_REPL_NAT_SEQ_CORRECTION_POS); - if (nfct_attr_is_set(ct, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE)) - __build_u32(ct, pld, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE); - if (nfct_attr_is_set(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER)) - __build_u32(ct, pld, ATTR_REPL_NAT_SEQ_OFFSET_AFTER); + if (nfct_attr_is_set_array(ct, nat_type, 6)) + __build_natseqadj(ct, pld); pld->query = query; diff --git a/src/parse.c b/src/parse.c index b14e487..0184c5a 100644 --- a/src/parse.c +++ b/src/parse.c @@ -24,61 +24,127 @@ #define ssizeof(x) (int)sizeof(x) #endif -static void parse_u8(struct nf_conntrack *ct, int attr, void *data) +static void parse_u8(struct nf_conntrack *ct, int attr, void *data); +static void parse_u16(struct nf_conntrack *ct, int attr, void *data); +static void parse_u32(struct nf_conntrack *ct, int attr, void *data); +static void parse_group(struct nf_conntrack *ct, int attr, void *data); +static void parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); + +struct parser { + void (*parse)(struct nf_conntrack *ct, int attr, void *data); + int attr; +}; + +static struct parser h[ATTR_MAX] = { + [NTA_IPV4] = { + .parse = parse_group, + .attr = ATTR_GRP_ORIG_IPV4, + }, + [NTA_IPV6] = { + .parse = parse_group, + .attr = ATTR_GRP_ORIG_IPV6, + }, + [NTA_PORT] = { + .parse = parse_group, + .attr = ATTR_GRP_ORIG_PORT, + }, + [NTA_L4PROTO] = { + .parse = parse_u8, + .attr = ATTR_L4PROTO, + }, + [NTA_STATE] = { + .parse = parse_u8, + .attr = ATTR_TCP_STATE, + }, + [NTA_STATUS] = { + .parse = parse_u32, + .attr = ATTR_STATUS, + }, + [NTA_MARK] = { + .parse = parse_u32, + .attr = ATTR_MARK, + }, + [NTA_TIMEOUT] = { + .parse = parse_u32, + .attr = ATTR_TIMEOUT, + }, + [NTA_MASTER_IPV4] = { + .parse = parse_group, + .attr = ATTR_GRP_MASTER_IPV4, + }, + [NTA_MASTER_IPV6] = { + .parse = parse_group, + .attr = ATTR_GRP_MASTER_IPV6, + }, + [NTA_MASTER_PORT] = { + .parse = parse_group, + .attr = ATTR_GRP_MASTER_PORT, + }, + [NTA_SNAT_IPV4] = { + .parse = parse_u32, + .attr = ATTR_SNAT_IPV4, + }, + [NTA_DNAT_IPV4] = { + .parse = parse_u32, + .attr = ATTR_DNAT_IPV4, + }, + [NTA_SPAT_PORT] = { + .parse = parse_u16, + .attr = ATTR_SNAT_PORT, + }, + [NTA_DPAT_PORT] = { + .parse = parse_u16, + .attr = ATTR_SNAT_PORT, + }, + [NTA_NAT_SEQ_ADJ] = { + .parse = parse_nat_seq_adj, + }, +}; + +static void +parse_u8(struct nf_conntrack *ct, int attr, void *data) { uint8_t *value = (uint8_t *) data; - nfct_set_attr_u8(ct, attr, *value); + nfct_set_attr_u8(ct, h[attr].attr, *value); } -static void parse_u16(struct nf_conntrack *ct, int attr, void *data) +static void +parse_u16(struct nf_conntrack *ct, int attr, void *data) { uint16_t *value = (uint16_t *) data; - nfct_set_attr_u16(ct, attr, ntohs(*value)); + nfct_set_attr_u16(ct, h[attr].attr, ntohs(*value)); } -static void parse_u32(struct nf_conntrack *ct, int attr, void *data) +static void +parse_u32(struct nf_conntrack *ct, int attr, void *data) { uint32_t *value = (uint32_t *) data; - nfct_set_attr_u32(ct, attr, ntohl(*value)); + nfct_set_attr_u32(ct, h[attr].attr, ntohl(*value)); } -static void parse_pointer_be(struct nf_conntrack *ct, int attr, void *data) +static void +parse_group(struct nf_conntrack *ct, int attr, void *data) { - nfct_set_attr(ct, attr, data); + nfct_set_attr_grp(ct, h[attr].attr, data); } -typedef void (*parse)(struct nf_conntrack *ct, int attr, void *data); - -static parse h[ATTR_MAX] = { - [ATTR_IPV4_SRC] = parse_pointer_be, - [ATTR_IPV4_DST] = parse_pointer_be, - [ATTR_IPV6_SRC] = parse_pointer_be, - [ATTR_IPV6_DST] = parse_pointer_be, - [ATTR_L3PROTO] = parse_u8, - [ATTR_PORT_SRC] = parse_u16, - [ATTR_PORT_DST] = parse_u16, - [ATTR_L4PROTO] = parse_u8, - [ATTR_TCP_STATE] = parse_u8, - [ATTR_SNAT_IPV4] = parse_u32, - [ATTR_DNAT_IPV4] = parse_u32, - [ATTR_SNAT_PORT] = parse_u16, - [ATTR_DNAT_PORT] = parse_u16, - [ATTR_TIMEOUT] = parse_u32, - [ATTR_MARK] = parse_u32, - [ATTR_STATUS] = parse_u32, - [ATTR_MASTER_IPV4_SRC] = parse_u32, - [ATTR_MASTER_IPV4_DST] = parse_u32, - [ATTR_MASTER_L3PROTO] = parse_u8, - [ATTR_MASTER_PORT_SRC] = parse_u16, - [ATTR_MASTER_PORT_DST] = parse_u16, - [ATTR_MASTER_L4PROTO] = parse_u8, - [ATTR_ORIG_NAT_SEQ_CORRECTION_POS] = parse_u32, - [ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE] = parse_u32, - [ATTR_ORIG_NAT_SEQ_OFFSET_AFTER] = parse_u32, - [ATTR_REPL_NAT_SEQ_CORRECTION_POS] = parse_u32, - [ATTR_REPL_NAT_SEQ_OFFSET_BEFORE] = parse_u32, - [ATTR_REPL_NAT_SEQ_OFFSET_AFTER] = parse_u32, -}; +static void +parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) +{ + struct nta_attr_natseqadj *this = data; + nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_CORRECTION_POS, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER, + ntohl(this->orig_seq_correction_pos)); +} int parse_netpld(struct nf_conntrack *ct, @@ -109,8 +175,11 @@ parse_netpld(struct nf_conntrack *ct, ATTR_NETWORK2HOST(attr); if (attr->nta_len > len) return -1; - if (h[attr->nta_attr]) - h[attr->nta_attr](ct, attr->nta_attr, NTA_DATA(attr)); + if (h[attr->nta_attr].parse == NULL) { + attr = NTA_NEXT(attr, len); + continue; + } + h[attr->nta_attr].parse(ct, attr->nta_attr, NTA_DATA(attr)); attr = NTA_NEXT(attr, len); } -- cgit v1.2.3 From 6262a4a7b7139fb5636228cb0f5a1e72f848d871 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 25 Nov 2008 01:56:47 +0100 Subject: build: add attribute header size to total attribute length This patch adds the size of the attribute header (4 bytes) to the length field of netattr. This fixes a possible invalid memory access in malformed messages. This change is included in the set of scheduled changes for 0.9.9 that break backward compatibility. This patch also removes a memset of 4096 by one to initialize the headers and the netattr paddings. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 6 +++--- src/build.c | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 2487c81..f24fb5f 100644 --- a/include/network.h +++ b/include/network.h @@ -49,7 +49,7 @@ enum { #define BUILD_NETMSG(ct, query) \ ({ \ char __net[4096]; \ - memset(__net, 0, sizeof(__net)); \ + memset(__net, 0, NETHDR_SIZ + NETPLD_SIZ); \ build_netmsg(ct, query, (struct nethdr *) __net); \ (struct nethdr *) __net; \ }) @@ -170,8 +170,8 @@ struct netattr { #define NTA_NEXT(x, len) \ ( \ - len -= NTA_ALIGN(NTA_LENGTH(x->nta_len)), \ - (struct netattr *)(((char *)x) + NTA_ALIGN(NTA_LENGTH(x->nta_len))) \ + len -= NTA_ALIGN(x->nta_len), \ + (struct netattr *)(((char *)x) + NTA_ALIGN(x->nta_len)) \ ) #define NTA_ALIGNTO 4 diff --git a/src/build.c b/src/build.c index 5143048..c776de8 100644 --- a/src/build.c +++ b/src/build.c @@ -24,9 +24,12 @@ static inline void * put_header(struct netpld *pld, int attr, size_t len) { struct netattr *nta = PLD_TAIL(pld); - pld->len += NTA_ALIGN(NTA_LENGTH(len)); + int total_size = NTA_ALIGN(NTA_LENGTH(len)); + int attr_size = NTA_LENGTH(len); + pld->len += total_size; nta->nta_attr = htons(attr); - nta->nta_len = htons(len); + nta->nta_len = htons(attr_size); + memset((unsigned char *)nta + attr_size, 0, total_size - attr_size); return NTA_DATA(nta); } -- cgit v1.2.3 From 67994842694e57a42f524e228ca7acc564f2104f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 30 Nov 2008 14:01:29 +0100 Subject: network: make tx buffer initialization independent of mcast config This patch changes the prototype of mcast_buffered_init() to receive as argument the MTU size instead of the multicast configuration. This decouples the initialization of the tx buffer from the multicast configuration. This patch is needed by the multi-dedicated link support. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 2 +- src/network.c | 6 +++--- src/sync-mode.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index f24fb5f..5da1db5 100644 --- a/include/network.h +++ b/include/network.h @@ -75,7 +75,7 @@ int mcast_track_is_seq_set(void); struct mcast_conf; -int mcast_buffered_init(struct mcast_conf *mconf); +int mcast_buffered_init(int mtu); void mcast_buffered_destroy(void); int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len); ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); diff --git a/src/network.c b/src/network.c index 04c9d39..78be1e2 100644 --- a/src/network.c +++ b/src/network.c @@ -85,12 +85,12 @@ static char *tx_buf; #define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ -int mcast_buffered_init(struct mcast_conf *mconf) +int mcast_buffered_init(int if_mtu) { - int mtu = mconf->mtu - HEADERSIZ; + int mtu = if_mtu - HEADERSIZ; /* default to Ethernet MTU 1500 bytes */ - if (mconf->mtu == 0) + if (if_mtu == 0) mtu = 1500 - HEADERSIZ; tx_buf = malloc(mtu); diff --git a/src/sync-mode.c b/src/sync-mode.c index e613111..98867b2 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -233,7 +233,7 @@ static int init_sync(void) dlog(LOG_NOTICE, "multicast client socket sender queue " "has been set to %d bytes", CONFIG(mcast).sndbuf); - if (mcast_buffered_init(&CONFIG(mcast)) == -1) { + if (mcast_buffered_init(CONFIG(mcast).mtu) == -1) { dlog(LOG_ERR, "can't init tx buffer!"); mcast_server_destroy(STATE_SYNC(mcast_server)); mcast_client_destroy(STATE_SYNC(mcast_client)); -- cgit v1.2.3 From 567222194512c6d42c7e253fc69c3837fe7b078c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 6 Dec 2008 21:54:24 +0100 Subject: build: do not include NTA_TIMEOUT in the replication messages With this patch, NTA_TIMEOUT is not included in the replication messages anymore. During the fail-over, we set a small timeout to purge the entries that were not recovered successfully (however, unsuccessful recovery should not happen ever). Signed-off-by: Pablo Neira Ayuso --- include/network.h | 2 +- src/build.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 5da1db5..6ab099f 100644 --- a/include/network.h +++ b/include/network.h @@ -185,7 +185,7 @@ enum nta_attr { NTA_PORT, /* struct nfct_attr_grp_port */ NTA_STATE = 4, /* uint8_t */ NTA_STATUS, /* uint32_t */ - NTA_TIMEOUT, /* uint32_t */ + NTA_TIMEOUT, /* uint32_t -- unused */ NTA_MARK, /* uint32_t */ NTA_MASTER_IPV4 = 8, /* struct nfct_attr_grp_ipv4 */ NTA_MASTER_IPV6, /* struct nfct_attr_grp_ipv6 */ diff --git a/src/build.c b/src/build.c index c776de8..84515cf 100644 --- a/src/build.c +++ b/src/build.c @@ -117,8 +117,6 @@ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) __build_u8(ct, ATTR_TCP_STATE, pld, NTA_STATE); - if (nfct_attr_is_set(ct, ATTR_TIMEOUT)) - __build_u32(ct, ATTR_TIMEOUT, pld, NTA_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) __build_u32(ct, ATTR_MARK, pld, NTA_MARK); -- cgit v1.2.3 From 6042436a188581a327580f7821c0a3b94c4ef5d7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 11:07:58 +0100 Subject: parse: fix missing master layer 4 protocol number assignation This patch fixes NTA_MASTER_L4PROTO parsing which was missing. This problem was introduced in "network: rework TLV-based protocol", commit id 76ac8ebe5e49385585c8e29fe530ed4baef390bf, ie. somewhere in the development of 0.9.9. This patch also fixes the size of parsing callback array that is NTA_MAX, not ATTR_MAX. This problem does not affect conntrack-tools <= 0.9.8. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 1 + src/parse.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 6ab099f..3f8123d 100644 --- a/include/network.h +++ b/include/network.h @@ -196,6 +196,7 @@ enum nta_attr { NTA_SPAT_PORT, /* uint16_t */ NTA_DPAT_PORT, /* uint16_t */ NTA_NAT_SEQ_ADJ = 16, /* struct nta_attr_natseqadj */ + NTA_MAX }; struct nta_attr_natseqadj { diff --git a/src/parse.c b/src/parse.c index 0184c5a..4eb74b2 100644 --- a/src/parse.c +++ b/src/parse.c @@ -35,7 +35,7 @@ struct parser { int attr; }; -static struct parser h[ATTR_MAX] = { +static struct parser h[NTA_MAX] = { [NTA_IPV4] = { .parse = parse_group, .attr = ATTR_GRP_ORIG_IPV4, @@ -76,6 +76,10 @@ static struct parser h[ATTR_MAX] = { .parse = parse_group, .attr = ATTR_GRP_MASTER_IPV6, }, + [NTA_MASTER_L4PROTO] = { + .parse = parse_u8, + .attr = ATTR_MASTER_L4PROTO, + }, [NTA_MASTER_PORT] = { .parse = parse_group, .attr = ATTR_GRP_MASTER_PORT, -- cgit v1.2.3 From 29b5df53bcbef17722ab2b389f3352c4e86b4795 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 11:08:19 +0100 Subject: network: remove unused function mcast_send_netmsg() This patch removes the unused function mcast_send_netmsg(). Signed-off-by: Pablo Neira Ayuso --- include/network.h | 1 - src/network.c | 11 ----------- 2 files changed, 12 deletions(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 3f8123d..b64753c 100644 --- a/include/network.h +++ b/include/network.h @@ -59,7 +59,6 @@ struct mcast_sock; void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); size_t prepare_send_netmsg(struct mcast_sock *m, void *data); -int mcast_send_netmsg(struct mcast_sock *m, void *data); enum { SEQ_UNKNOWN, diff --git a/src/network.c b/src/network.c index 78be1e2..2f83d3b 100644 --- a/src/network.c +++ b/src/network.c @@ -140,17 +140,6 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m) return ret; } -int mcast_send_netmsg(struct mcast_sock *m, void *data) -{ - int ret; - size_t len = prepare_send_netmsg(m, data); - - ret = mcast_buffered_send_netmsg(m, data, len); - mcast_buffered_pending_netmsg(m); - - return ret; -} - void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net) { struct netpld *pld = NETHDR_DATA(net); -- cgit v1.2.3 From bf6cfeb1dc6652eaff1b7c4edda45e15f5abf361 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 11:09:02 +0100 Subject: network: remove length parameter of mcast_buffered_send_netmsg() This patch simplifies mcast_buffered_send_netmsg() by removing the length parameter. Instead, we use the length field in the nethdr to know the message size to be sent. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 2 +- src/network.c | 5 ++--- src/sync-alarm.c | 2 +- src/sync-ftfw.c | 4 ++-- src/sync-mode.c | 2 +- src/sync-notrack.c | 4 ++-- 6 files changed, 9 insertions(+), 10 deletions(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index b64753c..1195303 100644 --- a/include/network.h +++ b/include/network.h @@ -76,7 +76,7 @@ struct mcast_conf; int mcast_buffered_init(int mtu); void mcast_buffered_destroy(void); -int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len); +int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net); ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); #define IS_DATA(x) ((x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) diff --git a/src/network.c b/src/network.c index 2f83d3b..a6ecb7e 100644 --- a/src/network.c +++ b/src/network.c @@ -108,10 +108,9 @@ void mcast_buffered_destroy(void) } /* return 0 if it is not sent, otherwise return 1 */ -int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len) +int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net) { - int ret = 0; - struct nethdr *net = data; + int ret = 0, len = ntohs(net->len); retry: if (tx_buflen + len < tx_buflenmax) { diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 4473af2..377af16 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -41,7 +41,7 @@ static void refresher(struct alarm_block *a, void *data) net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } static void cache_alarm_add(struct us_conntrack *u, void *data) diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index abba1fe..293f9ab 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -495,7 +495,7 @@ static int tx_queue_xmit(void *data1, const void *data2) dp("tx_queue sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); HDR_NETWORK2HOST(net); if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) @@ -518,7 +518,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) list_del_init(i); tx_list_len--; - ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); ftfw_send(net, u); return ret; diff --git a/src/sync-mode.c b/src/sync-mode.c index 98867b2..ac9d3f3 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -406,7 +406,7 @@ static void mcast_send_sync(struct us_conntrack *u, int query) if (STATE_SYNC(sync)->send) STATE_SYNC(sync)->send(net, u); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } static int purge_step(void *data1, void *data2) diff --git a/src/sync-notrack.c b/src/sync-notrack.c index c7ac9b5..c5ea1e6 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -157,7 +157,7 @@ static int tx_queue_xmit(void *data1, const void *data2) struct nethdr *net = data1; size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); queue_del(tx_queue, net); return 0; @@ -172,7 +172,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) list_del_init(i); tx_list_len--; - ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); return ret; } -- cgit v1.2.3 From a516e5f8e550a6073aae96491372c45ce340da88 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 11:10:47 +0100 Subject: network: remove the netpld header from the messages This patch simplifies the message format of the replication messages. As a result, we save four bytes. The netpld header was introduced in the early protocol design. Today, it does not have any reason to exist. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 47 +++++++++++++++++------------------ src/build.c | 72 ++++++++++++++++++++++++++---------------------------- src/network.c | 55 +++++++++++++++-------------------------- src/parse.c | 23 +++-------------- src/sync-alarm.c | 2 -- src/sync-ftfw.c | 8 +++--- src/sync-mode.c | 11 +++------ src/sync-notrack.c | 5 ++-- 8 files changed, 90 insertions(+), 133 deletions(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 1195303..11e65c7 100644 --- a/include/network.h +++ b/include/network.h @@ -9,25 +9,34 @@ struct nf_conntrack; struct nethdr { - uint8_t version; + uint8_t version:4, + type:4; uint8_t flags; uint16_t len; uint32_t seq; }; -#define NETHDR_SIZ sizeof(struct nethdr) +#define NETHDR_SIZ nethdr_align(sizeof(struct nethdr)) + +int nethdr_align(int len); +int nethdr_size(int len); +void nethdr_set(struct nethdr *net, int type); +void nethdr_set_ack(struct nethdr *net); #define NETHDR_DATA(x) \ - (struct netpld *)(((char *)x) + sizeof(struct nethdr)) + (struct netattr *)(((char *)x) + NETHDR_SIZ) +#define NETHDR_TAIL(x) \ + (struct netattr *)(((char *)x) + x->len) struct nethdr_ack { - uint8_t version; + uint8_t version:4, + type:4; uint8_t flags; uint16_t len; uint32_t seq; uint32_t from; uint32_t to; }; -#define NETHDR_ACK_SIZ sizeof(struct nethdr_ack) +#define NETHDR_ACK_SIZ nethdr_align(sizeof(struct nethdr_ack)) enum { NET_F_UNUSED = (1 << 0), @@ -49,17 +58,17 @@ enum { #define BUILD_NETMSG(ct, query) \ ({ \ char __net[4096]; \ - memset(__net, 0, NETHDR_SIZ + NETPLD_SIZ); \ - build_netmsg(ct, query, (struct nethdr *) __net); \ - (struct nethdr *) __net; \ + struct nethdr *__hdr = (struct nethdr *) __net; \ + memset(__hdr, 0, NETHDR_SIZ); \ + nethdr_set(__hdr, query); \ + build_payload(ct, __hdr); \ + HDR_HOST2NETWORK(__hdr); \ + __hdr; \ }) struct us_conntrack; struct mcast_sock; -void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); -size_t prepare_send_netmsg(struct mcast_sock *m, void *data); - enum { SEQ_UNKNOWN, SEQ_UNSET, @@ -129,12 +138,6 @@ static inline int between(uint32_t seq1, uint32_t seq2, uint32_t seq3) return seq3 - seq2 >= seq1 - seq2; } -struct netpld { - uint16_t len; - uint16_t query; -}; -#define NETPLD_SIZ sizeof(struct netpld) - #define PLD_NETWORK2HOST(x) \ ({ \ x->len = ntohs(x->len); \ @@ -158,12 +161,6 @@ struct netattr { x->nta_attr = ntohs(x->nta_attr); \ }) -#define PLD_DATA(x) \ - (struct netattr *)(((char *)x) + sizeof(struct netpld)) - -#define PLD_TAIL(x) \ - (struct netattr *)(((char *)x) + sizeof(struct netpld) + x->len) - #define NTA_DATA(x) \ (void *)(((char *)x) + sizeof(struct netattr)) @@ -207,8 +204,8 @@ struct nta_attr_natseqadj { uint32_t repl_seq_offset_after; }; -void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query); +void build_payload(const struct nf_conntrack *ct, struct nethdr *n); -int parse_netpld(struct nf_conntrack *ct, struct nethdr *net, int *query, size_t remain); +int parse_payload(struct nf_conntrack *ct, struct nethdr *n, size_t remain); #endif diff --git a/src/build.c b/src/build.c index 84515cf..e094aa0 100644 --- a/src/build.c +++ b/src/build.c @@ -21,12 +21,12 @@ #include "network.h" static inline void * -put_header(struct netpld *pld, int attr, size_t len) +put_header(struct nethdr *n, int attr, size_t len) { - struct netattr *nta = PLD_TAIL(pld); + struct netattr *nta = NETHDR_TAIL(n); int total_size = NTA_ALIGN(NTA_LENGTH(len)); int attr_size = NTA_LENGTH(len); - pld->len += total_size; + n->len += total_size; nta->nta_attr = htons(attr); nta->nta_len = htons(attr_size); memset((unsigned char *)nta + attr_size, 0, total_size - attr_size); @@ -34,45 +34,45 @@ put_header(struct netpld *pld, int attr, size_t len) } static inline void -addattr(struct netpld *pld, int attr, const void *data, size_t len) +addattr(struct nethdr *n, int attr, const void *data, size_t len) { - void *ptr = put_header(pld, attr, len); + void *ptr = put_header(n, attr, len); memcpy(ptr, data, len); } static inline void -__build_u8(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) +__build_u8(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { - void *ptr = put_header(pld, b, sizeof(uint8_t)); + void *ptr = put_header(n, b, sizeof(uint8_t)); memcpy(ptr, nfct_get_attr(ct, a), sizeof(uint8_t)); } static inline void -__build_u16(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) +__build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { uint32_t data = nfct_get_attr_u16(ct, a); data = htons(data); - addattr(pld, b, &data, sizeof(uint16_t)); + addattr(n, b, &data, sizeof(uint16_t)); } static inline void -__build_u32(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) +__build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { uint32_t data = nfct_get_attr_u32(ct, a); data = htonl(data); - addattr(pld, b, &data, sizeof(uint32_t)); + addattr(n, b, &data, sizeof(uint32_t)); } static inline void -__build_group(const struct nf_conntrack *ct, int a, struct netpld *pld, +__build_group(const struct nf_conntrack *ct, int a, struct nethdr *n, int b, int size) { - void *ptr = put_header(pld, b, size); + void *ptr = put_header(n, b, size); nfct_get_attr_grp(ct, a, ptr); } static inline void -__build_natseqadj(const struct nf_conntrack *ct, struct netpld *pld) +__build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n) { struct nta_attr_natseqadj data = { .orig_seq_correction_pos = @@ -88,7 +88,7 @@ __build_natseqadj(const struct nf_conntrack *ct, struct netpld *pld) .repl_seq_offset_after = htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER)) }; - addattr(pld, NTA_NAT_SEQ_ADJ, &data, sizeof(struct nta_attr_natseqadj)); + addattr(n, NTA_NAT_SEQ_ADJ, &data, sizeof(struct nta_attr_natseqadj)); } static enum nf_conntrack_attr nat_type[] = @@ -97,65 +97,61 @@ static enum nf_conntrack_attr nat_type[] = ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, ATTR_REPL_NAT_SEQ_OFFSET_AFTER }; /* XXX: ICMP not supported */ -void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) +void build_payload(const struct nf_conntrack *ct, struct nethdr *n) { if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { - __build_group(ct, ATTR_GRP_ORIG_IPV4, pld, NTA_IPV4, + __build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_IPV4, sizeof(struct nfct_attr_grp_ipv4)); } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { - __build_group(ct, ATTR_GRP_ORIG_IPV6, pld, NTA_IPV6, + __build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_IPV6, sizeof(struct nfct_attr_grp_ipv6)); } - __build_u8(ct, ATTR_L4PROTO, pld, NTA_L4PROTO); + __build_u8(ct, ATTR_L4PROTO, n, NTA_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_PORT)) { - __build_group(ct, ATTR_GRP_ORIG_PORT, pld, NTA_PORT, + __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); } - __build_u32(ct, ATTR_STATUS, pld, NTA_STATUS); + __build_u32(ct, ATTR_STATUS, n, NTA_STATUS); if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) - __build_u8(ct, ATTR_TCP_STATE, pld, NTA_STATE); + __build_u8(ct, ATTR_TCP_STATE, n, NTA_STATE); if (nfct_attr_is_set(ct, ATTR_MARK)) - __build_u32(ct, ATTR_MARK, pld, NTA_MARK); + __build_u32(ct, ATTR_MARK, n, NTA_MARK); /* setup the master conntrack */ if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV4)) { - __build_group(ct, ATTR_GRP_MASTER_IPV4, pld, NTA_MASTER_IPV4, + __build_group(ct, ATTR_GRP_MASTER_IPV4, n, NTA_MASTER_IPV4, sizeof(struct nfct_attr_grp_ipv4)); - __build_u8(ct, ATTR_MASTER_L4PROTO, pld, NTA_MASTER_L4PROTO); + __build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { __build_group(ct, ATTR_GRP_MASTER_PORT, - pld, NTA_MASTER_PORT, + n, NTA_MASTER_PORT, sizeof(struct nfct_attr_grp_port)); } } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV6)) { - __build_group(ct, ATTR_GRP_MASTER_IPV6, pld, NTA_MASTER_IPV6, + __build_group(ct, ATTR_GRP_MASTER_IPV6, n, NTA_MASTER_IPV6, sizeof(struct nfct_attr_grp_ipv6)); - __build_u8(ct, ATTR_MASTER_L4PROTO, pld, NTA_MASTER_L4PROTO); + __build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { __build_group(ct, ATTR_GRP_MASTER_PORT, - pld, NTA_MASTER_PORT, + n, NTA_MASTER_PORT, sizeof(struct nfct_attr_grp_port)); } } /* NAT */ if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - __build_u32(ct, ATTR_REPL_IPV4_DST, pld, NTA_SNAT_IPV4); + __build_u32(ct, ATTR_REPL_IPV4_DST, n, NTA_SNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - __build_u32(ct, ATTR_REPL_IPV4_SRC, pld, NTA_DNAT_IPV4); + __build_u32(ct, ATTR_REPL_IPV4_SRC, n, NTA_DNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) - __build_u16(ct, ATTR_REPL_PORT_DST, pld, NTA_SPAT_PORT); + __build_u16(ct, ATTR_REPL_PORT_DST, n, NTA_SPAT_PORT); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) - __build_u16(ct, ATTR_REPL_PORT_SRC, pld, NTA_DPAT_PORT); + __build_u16(ct, ATTR_REPL_PORT_SRC, n, NTA_DPAT_PORT); /* NAT sequence adjustment */ if (nfct_attr_is_set_array(ct, nat_type, 6)) - __build_natseqadj(ct, pld); - - pld->query = query; - - PLD_HOST2NETWORK(pld); + __build_natseqadj(ct, n); } diff --git a/src/network.c b/src/network.c index ca00881..34992ec 100644 --- a/src/network.c +++ b/src/network.c @@ -25,48 +25,40 @@ #include #include +#define NETHDR_ALIGNTO 4 + static unsigned int seq_set, cur_seq; -static size_t __do_prepare(struct mcast_sock *m, void *data, size_t len) +int nethdr_align(int value) { - struct nethdr *net = data; + return (value + NETHDR_ALIGNTO - 1) & ~(NETHDR_ALIGNTO - 1); +} +int nethdr_size(int len) +{ + return NETHDR_SIZ + len; +} + +static inline void __nethdr_set(struct nethdr *net, int len, int type) +{ if (!seq_set) { seq_set = 1; cur_seq = time(NULL); } - net->version = CONNTRACKD_PROTOCOL_VERSION; - net->len = len; - net->seq = cur_seq++; - HDR_HOST2NETWORK(net); - - return len; + net->version = CONNTRACKD_PROTOCOL_VERSION; + net->type = type; + net->len = len; + net->seq = cur_seq++; } -static size_t __prepare_ctl(struct mcast_sock *m, void *data) +void nethdr_set(struct nethdr *net, int type) { - return __do_prepare(m, data, NETHDR_ACK_SIZ); + __nethdr_set(net, NETHDR_SIZ, type); } -static size_t __prepare_data(struct mcast_sock *m, void *data) +void nethdr_set_ack(struct nethdr *net) { - struct nethdr *net = (struct nethdr *) data; - struct netpld *pld = NETHDR_DATA(net); - - return __do_prepare(m, data, ntohs(pld->len) + NETPLD_SIZ + NETHDR_SIZ); -} - -size_t prepare_send_netmsg(struct mcast_sock *m, void *data) -{ - int ret = 0; - struct nethdr *net = (struct nethdr *) data; - - if (IS_DATA(net)) - ret = __prepare_data(m, data); - else if (IS_CTL(net)) - ret = __prepare_ctl(m, data); - - return ret; + __nethdr_set(net, NETHDR_ACK_SIZ, 0); } static size_t tx_buflenmax; @@ -129,13 +121,6 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m) return ret; } -void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net) -{ - struct netpld *pld = NETHDR_DATA(net); - - build_netpld(ct, pld, query); -} - static int local_seq_set = 0; /* this function only tracks, it does not update the last sequence received */ diff --git a/src/parse.c b/src/parse.c index 4eb74b2..17a0107 100644 --- a/src/parse.c +++ b/src/parse.c @@ -150,30 +150,16 @@ parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) ntohl(this->orig_seq_correction_pos)); } -int -parse_netpld(struct nf_conntrack *ct, - struct nethdr *net, - int *query, - size_t remain) +int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) { int len; struct netattr *attr; - struct netpld *pld; - if (remain < NETHDR_SIZ + sizeof(struct netpld)) + if (remain < net->len) return -1; - pld = NETHDR_DATA(net); - - if (remain < NETHDR_SIZ + sizeof(struct netpld) + ntohs(pld->len)) - return -1; - - if (net->len < NETHDR_SIZ + sizeof(struct netpld) + ntohs(pld->len)) - return -1; - - PLD_NETWORK2HOST(pld); - len = pld->len; - attr = PLD_DATA(pld); + len = net->len - NETHDR_SIZ; + attr = NETHDR_DATA(net); while (len > ssizeof(struct netattr)) { ATTR_NETWORK2HOST(attr); @@ -187,6 +173,5 @@ parse_netpld(struct nf_conntrack *ct, attr = NTA_NEXT(attr, len); } - *query = pld->query; return 0; } diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 377af16..fe3d9af 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -29,7 +29,6 @@ static void refresher(struct alarm_block *a, void *data) { - size_t len; struct nethdr *net; struct us_conntrack *u = data; @@ -40,7 +39,6 @@ static void refresher(struct alarm_block *a, void *data) ((random() % 5 + 1) * 200000) - 1); net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); - len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 293f9ab..a4895d4 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -451,10 +451,9 @@ out: static void ftfw_send(struct nethdr *net, struct us_conntrack *u) { - struct netpld *pld = NETHDR_DATA(net); struct cache_ftfw *cn; - switch(ntohs(pld->query)) { + switch(net->type) { case NFCT_Q_CREATE: case NFCT_Q_UPDATE: case NFCT_Q_DESTROY: @@ -490,7 +489,9 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) static int tx_queue_xmit(void *data1, const void *data2) { struct nethdr *net = data1; - size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + nethdr_set_ack(net); + HDR_HOST2NETWORK(net); dp("tx_queue sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); @@ -510,7 +511,6 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) { int ret; struct nethdr *net = BUILD_NETMSG(u->ct, type); - size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); dp("tx_list sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); diff --git a/src/sync-mode.c b/src/sync-mode.c index ac9d3f3..cfed7f4 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -36,7 +36,6 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) { - int query; char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; struct us_conntrack *u; @@ -62,13 +61,13 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) memset(ct, 0, sizeof(__ct)); - if (parse_netpld(ct, net, &query, remain) == -1) { + if (parse_payload(ct, net, remain) == -1) { STATE(malformed)++; dlog(LOG_ERR, "parsing failed: malformed message"); return; } - switch(query) { + switch(net->type) { case NFCT_Q_CREATE: retry: if ((u = cache_add(STATE_SYNC(external), ct))) { @@ -100,7 +99,7 @@ retry: break; default: STATE(malformed)++; - dlog(LOG_ERR, "mcast unknown query %d\n", query); + dlog(LOG_ERR, "mcast unknown query %d\n", net->type); break; } } @@ -109,7 +108,7 @@ retry: static void mcast_handler(void) { ssize_t numbytes; - size_t remain; + ssize_t remain; char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net)); @@ -397,11 +396,9 @@ static void dump_sync(struct nf_conntrack *ct) static void mcast_send_sync(struct us_conntrack *u, int query) { - size_t len; struct nethdr *net; net = BUILD_NETMSG(u->ct, query); - len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); if (STATE_SYNC(sync)->send) STATE_SYNC(sync)->send(net, u); diff --git a/src/sync-notrack.c b/src/sync-notrack.c index c5ea1e6..fdb0c43 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -155,8 +155,8 @@ static int notrack_recv(const struct nethdr *net) static int tx_queue_xmit(void *data1, const void *data2) { struct nethdr *net = data1; - size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - + nethdr_set_ack(net); + HDR_HOST2NETWORK(net); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); queue_del(tx_queue, net); @@ -167,7 +167,6 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) { int ret; struct nethdr *net = BUILD_NETMSG(u->ct, type); - size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); list_del_init(i); tx_list_len--; -- cgit v1.2.3 From 63c3ae0f664ea7045446c4117646f767a5ccd647 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 11:20:44 +0100 Subject: network: fix data offset alignment returned by NTA_DATA macro This patch aligns the data offset that is returned by the NTA_DATA macro. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 11e65c7..96a0185 100644 --- a/include/network.h +++ b/include/network.h @@ -162,7 +162,7 @@ struct netattr { }) #define NTA_DATA(x) \ - (void *)(((char *)x) + sizeof(struct netattr)) + (void *)(((char *)x) + NTA_ALIGN(sizeof(struct netattr))) #define NTA_NEXT(x, len) \ ( \ -- cgit v1.2.3 From 1f5834262c91d835414b538857b67e058a1c1dac Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 23:58:31 +0100 Subject: parse: strict attribute size checking This patch adds strict attribute size checking. This is good to detect corrupted or malformed messages. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 2 ++ src/parse.c | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 96a0185..9098e5c 100644 --- a/include/network.h +++ b/include/network.h @@ -161,6 +161,8 @@ struct netattr { x->nta_attr = ntohs(x->nta_attr); \ }) +#define NTA_SIZE(len) NTA_ALIGN(sizeof(struct netattr)) + len + #define NTA_DATA(x) \ (void *)(((char *)x) + NTA_ALIGN(sizeof(struct netattr))) diff --git a/src/parse.c b/src/parse.c index 17a0107..75daac1 100644 --- a/src/parse.c +++ b/src/parse.c @@ -33,75 +33,93 @@ static void parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); struct parser { void (*parse)(struct nf_conntrack *ct, int attr, void *data); int attr; + int size; }; static struct parser h[NTA_MAX] = { [NTA_IPV4] = { .parse = parse_group, .attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), }, [NTA_IPV6] = { .parse = parse_group, .attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), }, [NTA_PORT] = { .parse = parse_group, .attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), }, [NTA_L4PROTO] = { .parse = parse_u8, .attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_STATE] = { .parse = parse_u8, .attr = ATTR_TCP_STATE, + .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_STATUS] = { .parse = parse_u32, .attr = ATTR_STATUS, + .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_MARK] = { .parse = parse_u32, .attr = ATTR_MARK, + .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_TIMEOUT] = { .parse = parse_u32, .attr = ATTR_TIMEOUT, + .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_MASTER_IPV4] = { .parse = parse_group, .attr = ATTR_GRP_MASTER_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), }, [NTA_MASTER_IPV6] = { .parse = parse_group, .attr = ATTR_GRP_MASTER_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), }, [NTA_MASTER_L4PROTO] = { .parse = parse_u8, .attr = ATTR_MASTER_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_MASTER_PORT] = { .parse = parse_group, .attr = ATTR_GRP_MASTER_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), }, [NTA_SNAT_IPV4] = { .parse = parse_u32, .attr = ATTR_SNAT_IPV4, + .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_DNAT_IPV4] = { .parse = parse_u32, .attr = ATTR_DNAT_IPV4, + .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_SPAT_PORT] = { .parse = parse_u16, .attr = ATTR_SNAT_PORT, + .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_DPAT_PORT] = { .parse = parse_u16, .attr = ATTR_SNAT_PORT, + .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_NAT_SEQ_ADJ] = { .parse = parse_nat_seq_adj, + .size = NTA_SIZE(sizeof(struct nta_attr_natseqadj)), }, }; @@ -165,6 +183,8 @@ int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) ATTR_NETWORK2HOST(attr); if (attr->nta_len > len) return -1; + if (attr->nta_len != h[attr->nta_attr].size) + return -1; if (h[attr->nta_attr].parse == NULL) { attr = NTA_NEXT(attr, len); continue; -- cgit v1.2.3 From 8d6efef0daed05925bf9b13c21948afa651482a5 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Dec 2008 16:15:18 +0100 Subject: network: use NET_T_* instead of NFCT_Q_* This patch replaces the use of NFCT_Q_* in the message type by specific network message type NET_T_*. The query types are reserved for libnetfilter_conntrack operations. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 7 +++++++ src/sync-alarm.c | 2 +- src/sync-ftfw.c | 10 +++++----- src/sync-mode.c | 16 ++++++++-------- src/sync-notrack.c | 2 +- 5 files changed, 22 insertions(+), 15 deletions(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 9098e5c..b6722bd 100644 --- a/include/network.h +++ b/include/network.h @@ -17,6 +17,13 @@ struct nethdr { }; #define NETHDR_SIZ nethdr_align(sizeof(struct nethdr)) +enum nethdr_type { + NET_T_STATE_NEW = 0, + NET_T_STATE_UPD, + NET_T_STATE_DEL, + NET_T_STATE_MAX = NET_T_STATE_DEL, +}; + int nethdr_align(int len); int nethdr_size(int len); void nethdr_set(struct nethdr *net, int type); diff --git a/src/sync-alarm.c b/src/sync-alarm.c index fe3d9af..d871b75 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -38,7 +38,7 @@ static void refresher(struct alarm_block *a, void *data) random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); - net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + net = BUILD_NETMSG(u->ct, NET_T_STATE_UPD); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index a4895d4..05475ab 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -454,9 +454,9 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) struct cache_ftfw *cn; switch(net->type) { - case NFCT_Q_CREATE: - case NFCT_Q_UPDATE: - case NFCT_Q_DESTROY: + case NET_T_STATE_NEW: + case NET_T_STATE_UPD: + case NET_T_STATE_DEL: cn = (struct cache_ftfw *) cache_get_extra(STATE_SYNC(internal), u); @@ -537,9 +537,9 @@ static void ftfw_run(void) u = cache_get_conntrack(STATE_SYNC(internal), cn); if (alarm_pending(&u->alarm)) - tx_list_xmit(&cn->tx_list, u, NFCT_Q_DESTROY); + tx_list_xmit(&cn->tx_list, u, NET_T_STATE_DEL); else - tx_list_xmit(&cn->tx_list, u, NFCT_Q_UPDATE); + tx_list_xmit(&cn->tx_list, u, NET_T_STATE_UPD); } /* reset alive alarm */ diff --git a/src/sync-mode.c b/src/sync-mode.c index cfed7f4..d5355a7 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -68,7 +68,7 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) } switch(net->type) { - case NFCT_Q_CREATE: + case NET_T_STATE_NEW: retry: if ((u = cache_add(STATE_SYNC(external), ct))) { debug_ct(u->ct, "external new"); @@ -85,13 +85,13 @@ retry: debug_ct(ct, "can't add"); } break; - case NFCT_Q_UPDATE: + case NET_T_STATE_UPD: if ((u = cache_update_force(STATE_SYNC(external), ct))) { debug_ct(u->ct, "external update"); } else debug_ct(ct, "can't update"); break; - case NFCT_Q_DESTROY: + case NET_T_STATE_DEL: if (cache_del(STATE_SYNC(external), ct)) debug_ct(ct, "external destroy"); else @@ -415,7 +415,7 @@ static int purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { debug_ct(u->ct, "overrun purge resync"); - mcast_send_sync(u, NFCT_Q_DESTROY); + mcast_send_sync(u, NET_T_STATE_DEL); __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); } @@ -448,7 +448,7 @@ static int overrun_sync(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { debug_ct(u->ct, "overrun resync"); - mcast_send_sync(u, NFCT_Q_UPDATE); + mcast_send_sync(u, NET_T_STATE_UPD); } } @@ -466,7 +466,7 @@ static void event_new_sync(struct nf_conntrack *ct) nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); retry: if ((u = cache_add(STATE_SYNC(internal), ct))) { - mcast_send_sync(u, NFCT_Q_CREATE); + mcast_send_sync(u, NET_T_STATE_NEW); debug_ct(u->ct, "internal new"); } else { if (errno == EEXIST) { @@ -489,7 +489,7 @@ static void event_update_sync(struct nf_conntrack *ct) return; } debug_ct(u->ct, "internal update"); - mcast_send_sync(u, NFCT_Q_UPDATE); + mcast_send_sync(u, NET_T_STATE_UPD); } static int event_destroy_sync(struct nf_conntrack *ct) @@ -502,7 +502,7 @@ static int event_destroy_sync(struct nf_conntrack *ct) return 0; } - mcast_send_sync(u, NFCT_Q_DESTROY); + mcast_send_sync(u, NET_T_STATE_DEL); __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); debug_ct(ct, "internal destroy"); return 1; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index fdb0c43..8e6601a 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -188,7 +188,7 @@ static void notrack_run(void) struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); - tx_list_xmit(&cn->tx_list, u, NFCT_Q_UPDATE); + tx_list_xmit(&cn->tx_list, u, NET_T_STATE_UPD); } } -- cgit v1.2.3 From 74455dae1d095178b09ea3f1b1e8b005076e7a94 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Dec 2008 17:24:27 +0100 Subject: network: do more strict message type checking This patch adds more strict checking in the message type. We add a new message type NET_T_CTL for control messages. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 12 +++++++----- src/network.c | 2 +- src/sync-ftfw.c | 1 + src/sync-notrack.c | 1 + 4 files changed, 10 insertions(+), 6 deletions(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index b6722bd..f9756db 100644 --- a/include/network.h +++ b/include/network.h @@ -22,6 +22,7 @@ enum nethdr_type { NET_T_STATE_UPD, NET_T_STATE_DEL, NET_T_STATE_MAX = NET_T_STATE_DEL, + NET_T_CTL = 10, }; int nethdr_align(int len); @@ -95,11 +96,12 @@ void mcast_buffered_destroy(void); int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net); ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); -#define IS_DATA(x) ((x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) -#define IS_ACK(x) (x->flags & NET_F_ACK) -#define IS_NACK(x) (x->flags & NET_F_NACK) -#define IS_RESYNC(x) (x->flags & NET_F_RESYNC) -#define IS_ALIVE(x) (x->flags & NET_F_ALIVE) +#define IS_DATA(x) (x->type <= NET_T_STATE_MAX && \ + (x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) +#define IS_ACK(x) (x->type == NET_T_CTL && x->flags & NET_F_ACK) +#define IS_NACK(x) (x->type == NET_T_CTL && x->flags & NET_F_NACK) +#define IS_RESYNC(x) (x->type == NET_T_CTL && x->flags & NET_F_RESYNC) +#define IS_ALIVE(x) (x->type == NET_T_CTL && x->flags & NET_F_ALIVE) #define IS_CTL(x) IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x) || IS_ALIVE(x) #define IS_HELLO(x) (x->flags & NET_F_HELLO) #define IS_HELLO_BACK(x)(x->flags & NET_F_HELLO_BACK) diff --git a/src/network.c b/src/network.c index 34992ec..98df5ea 100644 --- a/src/network.c +++ b/src/network.c @@ -58,7 +58,7 @@ void nethdr_set(struct nethdr *net, int type) void nethdr_set_ack(struct nethdr *net) { - __nethdr_set(net, NETHDR_ACK_SIZ, 0); + __nethdr_set(net, NETHDR_ACK_SIZ, NET_T_CTL); } static size_t tx_buflenmax; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 749ccac..014cebd 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -97,6 +97,7 @@ static struct cache_extra cache_ftfw_extra = { static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) { struct nethdr_ack ack = { + .type = NET_T_CTL, .flags = flags, .from = from, .to = to, diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 8e6601a..700e272 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -61,6 +61,7 @@ static struct cache_extra cache_notrack_extra = { static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) { struct nethdr_ack ack = { + .type = NET_T_CTL, .flags = flags, .from = from, .to = to, -- cgit v1.2.3 From 08f59121eb907802d490601f5e54dcd0fbc1d695 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Dec 2008 17:24:47 +0100 Subject: ftfw: shrink alive message size This patch reduces the size of alive messages by removing the "from" and "to" fields which are not of any help. This patch also removes the IS_CTL() macro since it does not return true for the control messages anymore but only for IS_ACK(), IS_NACK() and IS_RESYNC(). Signed-off-by: Pablo Neira Ayuso --- include/network.h | 6 +++--- src/network.c | 5 +++++ src/sync-ftfw.c | 36 ++++++++++++++++++++++++++++++++++-- src/sync-mode.c | 2 +- 4 files changed, 43 insertions(+), 6 deletions(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index f9756db..40bb2b2 100644 --- a/include/network.h +++ b/include/network.h @@ -29,6 +29,7 @@ int nethdr_align(int len); int nethdr_size(int len); void nethdr_set(struct nethdr *net, int type); void nethdr_set_ack(struct nethdr *net); +void nethdr_set_ctl(struct nethdr *net); #define NETHDR_DATA(x) \ (struct netattr *)(((char *)x) + NETHDR_SIZ) @@ -102,7 +103,6 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); #define IS_NACK(x) (x->type == NET_T_CTL && x->flags & NET_F_NACK) #define IS_RESYNC(x) (x->type == NET_T_CTL && x->flags & NET_F_RESYNC) #define IS_ALIVE(x) (x->type == NET_T_CTL && x->flags & NET_F_ALIVE) -#define IS_CTL(x) IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x) || IS_ALIVE(x) #define IS_HELLO(x) (x->flags & NET_F_HELLO) #define IS_HELLO_BACK(x)(x->flags & NET_F_HELLO_BACK) @@ -110,7 +110,7 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); ({ \ x->len = ntohs(x->len); \ x->seq = ntohl(x->seq); \ - if (IS_CTL(x)) { \ + if (IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x)) { \ struct nethdr_ack *__ack = (struct nethdr_ack *) x; \ __ack->from = ntohl(__ack->from); \ __ack->to = ntohl(__ack->to); \ @@ -119,7 +119,7 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); #define HDR_HOST2NETWORK(x) \ ({ \ - if (IS_CTL(x)) { \ + if (IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x)) { \ struct nethdr_ack *__ack = (struct nethdr_ack *) x; \ __ack->from = htonl(__ack->from); \ __ack->to = htonl(__ack->to); \ diff --git a/src/network.c b/src/network.c index 98df5ea..090dec8 100644 --- a/src/network.c +++ b/src/network.c @@ -61,6 +61,11 @@ void nethdr_set_ack(struct nethdr *net) __nethdr_set(net, NETHDR_ACK_SIZ, NET_T_CTL); } +void nethdr_set_ctl(struct nethdr *net) +{ + __nethdr_set(net, NETHDR_SIZ, NET_T_CTL); +} + static size_t tx_buflenmax; static size_t tx_buflen = 0; static char *tx_buf; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 014cebd..4758710 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -121,6 +121,31 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) write_evfd(STATE_SYNC(evfd)); } +static void tx_queue_add_ctlmsg2(uint32_t flags) +{ + struct nethdr ctl = { + .type = NET_T_CTL, + .flags = flags, + }; + + switch(hello_state) { + case HELLO_INIT: + hello_state = HELLO_SAY; + /* fall through */ + case HELLO_SAY: + ctl.flags |= NET_F_HELLO; + break; + } + + if (say_hello_back) { + ctl.flags |= NET_F_HELLO_BACK; + say_hello_back = 0; + } + + queue_add(tx_queue, &ctl, NETHDR_SIZ); + write_evfd(STATE_SYNC(evfd)); +} + /* this function is called from the alarm framework */ static void do_alive_alarm(struct alarm_block *a, void *data) { @@ -131,7 +156,7 @@ static void do_alive_alarm(struct alarm_block *a, void *data) STATE_SYNC(last_seq_recv)); ack_from_set = 0; } else - tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); + tx_queue_add_ctlmsg2(NET_F_ALIVE); } static int ftfw_init(void) @@ -491,7 +516,14 @@ static int tx_queue_xmit(void *data1, const void *data2) { struct nethdr *net = data1; - nethdr_set_ack(net); + if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { + nethdr_set_ack(net); + } else if (IS_ALIVE(net)) { + nethdr_set_ctl(net); + } else { + dlog(LOG_ERR, "sending unknown control message?"); + return 0; + } HDR_HOST2NETWORK(net); dp("tx_queue sq: %u fl:%u len:%u\n", diff --git a/src/sync-mode.c b/src/sync-mode.c index d5355a7..b2b78ad 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -131,7 +131,7 @@ static void mcast_handler(void) break; } - if (IS_CTL(net)) { + if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { if (remain < NETHDR_ACK_SIZ) { STATE(malformed)++; dlog(LOG_WARNING, "no room for ctl message"); -- cgit v1.2.3 From 50339f96638eed35dac2b673b64cc6f1eb96406c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 15 Jan 2009 23:19:57 +0100 Subject: src: rework of the hash-cache infrastructure Currently, the caching system is implemented in a two layer architecture: hashtable (inner layer) and cache (upper layer). This patch reworks the hash-cache infrastructure to solve some initial design problems to make it more flexible, the main strong points of this patch are: * Memory handling is done in the cache layer, not in the inner hashtable layer. This removes one of the main dependencies between the hashtable and the cache classes. * Remove excessive encapsulation: the former cache used to hide a lot of details of the inner hashtable implementation. * Fix over-hashing of some operations: lookup-delete-add required three hash calculations. Similarly, the update-or-add operation required two hash calculations. Now, we calculate the hash once and re-use the value how many times as we need. This patch simplifies the caching system. As a result, we save ~130 lines of code. Small code means and less complexity means less chance to have bugs. Signed-off-by: Pablo Neira Ayuso --- include/Makefile.am | 4 +- include/cache.h | 43 +++++--- include/filter.h | 11 ++ include/hash.h | 22 ++-- include/network.h | 1 - include/slist.h | 41 -------- include/sync.h | 4 +- include/us-conntrack.h | 14 --- src/cache.c | 273 +++++++++++++++++++------------------------------ src/cache_iterators.c | 65 ++++++------ src/cache_lifetime.c | 10 +- src/cache_timer.c | 36 +++---- src/cache_wt.c | 33 +++--- src/filter.c | 57 +++++++++-- src/hash.c | 136 +++++++----------------- src/stats-mode.c | 55 +++++----- src/sync-alarm.c | 27 +++-- src/sync-ftfw.c | 40 ++++---- src/sync-mode.c | 116 +++++++++++---------- src/sync-notrack.c | 19 ++-- 20 files changed, 440 insertions(+), 567 deletions(-) delete mode 100644 include/slist.h delete mode 100644 include/us-conntrack.h (limited to 'include/network.h') diff --git a/include/Makefile.am b/include/Makefile.am index 13f7e37..c3f8904 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,6 @@ -noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h linux_rbtree.h \ - sync.h conntrackd.h local.h us-conntrack.h \ +noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ + sync.h conntrackd.h local.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ traffic_stats.h netlink.h fds.h event.h bitops.h diff --git a/include/cache.h b/include/cache.h index ebed70a..dcd6bcd 100644 --- a/include/cache.h +++ b/include/cache.h @@ -3,6 +3,8 @@ #include #include +#include "hash.h" +#include "alarm.h" /* cache features */ enum { @@ -22,14 +24,20 @@ enum { #define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE struct cache; -struct us_conntrack; +struct cache_object { + struct hashtable_node hashnode; + struct nf_conntrack *ct; + struct cache *cache; + struct alarm_block alarm; + char data[0]; +}; struct cache_feature { size_t size; - void (*add)(struct us_conntrack *u, void *data); - void (*update)(struct us_conntrack *u, void *data); - void (*destroy)(struct us_conntrack *u, void *data); - int (*dump)(struct us_conntrack *u, void *data, char *buf, int type); + void (*add)(struct cache_object *obj, void *data); + void (*update)(struct cache_object *obj, void *data); + void (*destroy)(struct cache_object *obj, void *data); + int (*dump)(struct cache_object *obj, void *data, char *buf, int type); }; extern struct cache_feature lifetime_feature; @@ -48,6 +56,7 @@ struct cache { unsigned int *feature_offset; struct cache_extra *extra; unsigned int extra_offset; + size_t object_size; /* statistics */ struct { @@ -77,9 +86,9 @@ struct cache { struct cache_extra { unsigned int size; - void (*add)(struct us_conntrack *u, void *data); - void (*update)(struct us_conntrack *u, void *data); - void (*destroy)(struct us_conntrack *u, void *data); + void (*add)(struct cache_object *obj, void *data); + void (*update)(struct cache_object *obj, void *data); + void (*destroy)(struct cache_object *obj, void *data); }; struct nf_conntrack; @@ -87,16 +96,18 @@ struct nf_conntrack; struct cache *cache_create(const char *name, unsigned int features, struct cache_extra *extra); void cache_destroy(struct cache *e); -struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct); -struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct); -struct us_conntrack *cache_update_force(struct cache *c, struct nf_conntrack *ct); -int cache_del(struct cache *c, struct nf_conntrack *ct); -int __cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout); -struct us_conntrack *cache_find(struct cache *c, struct nf_conntrack *ct); -int cache_test(struct cache *c, struct nf_conntrack *ct); +struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct); +void cache_object_free(struct cache_object *obj); + +int cache_add(struct cache *c, struct cache_object *obj, int id); +void cache_update(struct cache *c, struct cache_object *obj, int id, struct nf_conntrack *ct); +struct cache_object *cache_update_force(struct cache *c, struct nf_conntrack *ct); +void cache_del(struct cache *c, struct cache_object *obj); +int cache_del_timer(struct cache *c, struct cache_object *obj, int timeout); +struct cache_object *cache_find(struct cache *c, struct nf_conntrack *ct, int *pos); void cache_stats(const struct cache *c, int fd); void cache_stats_extended(const struct cache *c, int fd); -struct us_conntrack *cache_get_conntrack(struct cache *, void *); +struct cache_object *cache_data_get_object(struct cache *c, void *data); void *cache_get_extra(struct cache *, void *); void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)); diff --git a/include/filter.h b/include/filter.h index 9c2cf66..72c2aa4 100644 --- a/include/filter.h +++ b/include/filter.h @@ -4,6 +4,7 @@ #include #include #include +#include enum ct_filter_type { CT_FILTER_L4PROTO, @@ -17,6 +18,16 @@ enum ct_filter_logic { CT_FILTER_POSITIVE = 1, }; +struct ct_filter_ipv4_hnode { + struct hashtable_node node; + uint32_t ip; +}; + +struct ct_filter_ipv6_hnode { + struct hashtable_node node; + uint32_t ipv6[4]; +}; + struct ct_filter_netmask_ipv4 { uint32_t ip; uint32_t mask; diff --git a/include/hash.h b/include/hash.h index 2fb0a27..68d618b 100644 --- a/include/hash.h +++ b/include/hash.h @@ -2,7 +2,6 @@ #define _NF_SET_HASH_H_ #include -#include "slist.h" #include "linux_list.h" #include @@ -15,35 +14,30 @@ struct hashtable { uint32_t limit; uint32_t count; uint32_t initval; - uint32_t datasize; uint32_t (*hash)(const void *data, const struct hashtable *table); int (*compare)(const void *data1, const void *data2); - struct slist_head members[0]; + struct list_head members[0]; }; struct hashtable_node { - struct slist_head head; - char data[0]; + struct list_head head; }; -struct hashtable_node *hashtable_alloc_node(int datasize, void *data); -void hashtable_destroy_node(struct hashtable_node *h); - struct hashtable * -hashtable_create(int hashsize, int limit, int datasize, +hashtable_create(int hashsize, int limit, uint32_t (*hash)(const void *data, const struct hashtable *table), int (*compare)(const void *data1, const void *data2)); void hashtable_destroy(struct hashtable *h); - -void *hashtable_add(struct hashtable *table, void *data); -void *hashtable_find(struct hashtable *table, const void *data); -int hashtable_del(struct hashtable *table, void *data); +int hashtable_hash(const struct hashtable *table, const void *data); +struct hashtable_node *hashtable_find(const struct hashtable *table, const void *data, int id); +int hashtable_add(struct hashtable *table, struct hashtable_node *n, int id); +void hashtable_del(struct hashtable *table, struct hashtable_node *node); int hashtable_flush(struct hashtable *table); int hashtable_iterate(struct hashtable *table, void *data, - int (*iterate)(void *data1, void *data2)); + int (*iterate)(void *data, struct hashtable_node *n)); unsigned int hashtable_counter(const struct hashtable *table); #endif diff --git a/include/network.h b/include/network.h index 40bb2b2..619ce3e 100644 --- a/include/network.h +++ b/include/network.h @@ -75,7 +75,6 @@ enum { __hdr; \ }) -struct us_conntrack; struct mcast_sock; enum { diff --git a/include/slist.h b/include/slist.h deleted file mode 100644 index 257b627..0000000 --- a/include/slist.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _SLIST_H_ -#define _SLIST_H_ - -#include "linux_list.h" - -#define INIT_SLIST_HEAD(ptr) ((ptr).next = NULL) - -struct slist_head { - struct slist_head *next; -}; - -static inline int slist_empty(const struct slist_head *h) -{ - return !h->next; -} - -static inline void slist_del(struct slist_head *t, struct slist_head *prev) -{ - prev->next = t->next; - t->next = LIST_POISON1; -} - -static inline void slist_add(struct slist_head *head, struct slist_head *t) -{ - struct slist_head *tmp = head->next; - head->next = t; - t->next = tmp; -} - -#define slist_entry(ptr, type, member) container_of(ptr,type,member) - -#define slist_for_each(pos, head) \ - for (pos = (head)->next; pos; \ - pos = pos->next) - -#define slist_for_each_safe(pos, prev, next, head) \ - for (pos = (head)->next, prev = (head); \ - pos && ({ next = pos->next; 1; }); \ - ({ prev = (prev->next != next) ? prev->next : prev; }), pos = next) - -#endif diff --git a/include/sync.h b/include/sync.h index fc06c93..60c9fae 100644 --- a/include/sync.h +++ b/include/sync.h @@ -2,7 +2,7 @@ #define _SYNC_HOOKS_H_ struct nethdr; -struct us_conntrack; +struct cache_object; struct sync_mode { int internal_cache_flags; @@ -14,7 +14,7 @@ struct sync_mode { void (*kill)(void); int (*local)(int fd, int type, void *data); int (*recv)(const struct nethdr *net); - void (*send)(struct nethdr *net, struct us_conntrack *u); + void (*send)(struct nethdr *net, struct cache_object *obj); void (*run)(void); }; diff --git a/include/us-conntrack.h b/include/us-conntrack.h deleted file mode 100644 index 9eafa3b..0000000 --- a/include/us-conntrack.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _US_CONNTRACK_H_ -#define _US_CONNTRACK_H_ - -#include "alarm.h" -#include - -struct us_conntrack { - struct nf_conntrack *ct; - struct cache *cache; - struct alarm_block alarm; - char data[0]; -}; - -#endif diff --git a/src/cache.c b/src/cache.c index 553dddf..621a3f4 100644 --- a/src/cache.c +++ b/src/cache.c @@ -1,5 +1,5 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2009 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 @@ -20,7 +20,6 @@ #include "jhash.h" #include "hash.h" #include "log.h" -#include "us-conntrack.h" #include "conntrackd.h" #include @@ -68,14 +67,14 @@ __hash6(const struct nf_conntrack *ct, const struct hashtable *table) static uint32_t hash(const void *data, const struct hashtable *table) { int ret = 0; - const struct us_conntrack *u = data; + const struct nf_conntrack *ct = data; - switch(nfct_get_attr_u8(u->ct, ATTR_L3PROTO)) { + switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { case AF_INET: - ret = __hash4(u->ct, table); + ret = __hash4(ct, table); break; case AF_INET6: - ret = __hash6(u->ct, table); + ret = __hash6(ct, table); break; default: dlog(LOG_ERR, "unknown layer 3 proto in hash"); @@ -87,10 +86,10 @@ static uint32_t hash(const void *data, const struct hashtable *table) static int compare(const void *data1, const void *data2) { - const struct us_conntrack *u1 = data1; - const struct us_conntrack *u2 = data2; + const struct cache_object *obj = data1; + const struct nf_conntrack *ct = data2; - return nfct_cmp(u1->ct, u2->ct, NFCT_CMP_ORIG); + return nfct_cmp(obj->ct, ct, NFCT_CMP_ORIG); } struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { @@ -103,7 +102,7 @@ struct cache *cache_create(const char *name, unsigned int features, struct cache_extra *extra) { - size_t size = sizeof(struct us_conntrack); + size_t size = sizeof(struct cache_object); int i, j = 0; struct cache *c; struct cache_feature *feature_array[CACHE_MAX_FEATURE] = {}; @@ -152,7 +151,6 @@ struct cache *cache_create(const char *name, c->h = hashtable_create(CONFIG(hashsize), CONFIG(limit), - size, hash, compare); @@ -162,6 +160,7 @@ struct cache *cache_create(const char *name, free(c); return NULL; } + c->object_size = size; return c; } @@ -177,225 +176,165 @@ void cache_destroy(struct cache *c) static void __del_timeout(struct alarm_block *a, void *data); -static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) +struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) { - unsigned i; - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - struct nf_conntrack *newct; + struct cache_object *obj; - memset(u, 0, size); + obj = calloc(c->object_size, 1); + if (obj == NULL) { + errno = ENOMEM; + c->stats.add_fail_enomem++; + return NULL; + } + obj->cache = c; + init_alarm(&obj->alarm, obj, __del_timeout); - u->cache = c; - if ((u->ct = newct = nfct_new()) == NULL) { + if ((obj->ct = nfct_new()) == NULL) { + free(obj); errno = ENOMEM; - return 0; + c->stats.add_fail_enomem++; + return NULL; } - memcpy(u->ct, ct, nfct_sizeof(ct)); + memcpy(obj->ct, ct, nfct_sizeof(ct)); - u = hashtable_add(c->h, u); - if (u) { - char *data = u->data; + return obj; +} - init_alarm(&u->alarm, u, __del_timeout); +void cache_object_free(struct cache_object *obj) +{ + nfct_destroy(obj->ct); + free(obj); +} - for (i = 0; i < c->num_features; i++) { - c->features[i]->add(u, data); - data += c->features[i]->size; - } +static int __add(struct cache *c, struct cache_object *obj, int id) +{ + int ret; + unsigned int i; + char *data = obj->data; - if (c->extra && c->extra->add) - c->extra->add(u, ((char *) u) + c->extra_offset); + ret = hashtable_add(c->h, &obj->hashnode, id); + if (ret == -1) + return -1; - c->stats.active++; - return u; + for (i = 0; i < c->num_features; i++) { + c->features[i]->add(obj, data); + data += c->features[i]->size; } - free(newct); - return NULL; + if (c->extra && c->extra->add) + c->extra->add(obj, ((char *) obj) + c->extra_offset); + + c->stats.active++; + return 0; } -struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) +int cache_add(struct cache *c, struct cache_object *obj, int id) { - struct us_conntrack *u; + int ret; - u = __add(c, ct); - if (u) { - c->stats.add_ok++; - return u; - } - if (errno != EEXIST) { + ret = __add(c, obj, id); + if (ret == -1) { c->stats.add_fail++; if (errno == ENOSPC) c->stats.add_fail_enospc++; - if (errno == ENOMEM) - c->stats.add_fail_enomem++; + return -1; } - - return NULL; + c->stats.add_ok++; + return 0; } -static void -__cache_update(struct cache *c, struct us_conntrack *u, struct nf_conntrack *ct) +void cache_update(struct cache *c, struct cache_object *obj, int id, + struct nf_conntrack *ct) { - unsigned i; - char *data = u->data; + char *data = obj->data; + unsigned int i; - nfct_copy(u->ct, ct, NFCT_CP_META); + nfct_copy(obj->ct, ct, NFCT_CP_META); for (i = 0; i < c->num_features; i++) { - c->features[i]->update(u, data); + c->features[i]->update(obj, data); data += c->features[i]->size; } if (c->extra && c->extra->update) - c->extra->update(u, ((char *) u) + c->extra_offset); -} - -static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) -{ - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - - u->ct = ct; - - u = (struct us_conntrack *) hashtable_find(c->h, u); - if (u) { - __cache_update(c, u, ct); - return u; - } - return NULL; -} + c->extra->update(obj, ((char *) obj) + c->extra_offset); -struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) -{ - struct us_conntrack *u; - - u = __update(c, ct); - if (u) { - c->stats.upd_ok++; - return u; - } - c->stats.upd_fail++; - if (errno == ENOENT) - c->stats.upd_fail_enoent++; - - return NULL; + c->stats.upd_ok++; } -static void __del(struct cache *c, struct us_conntrack *u) +static void __del(struct cache *c, struct cache_object *obj) { unsigned i; - char *data = u->data; - struct nf_conntrack *p = u->ct; + char *data = obj->data; for (i = 0; i < c->num_features; i++) { - c->features[i]->destroy(u, data); + c->features[i]->destroy(obj, data); data += c->features[i]->size; } if (c->extra && c->extra->destroy) - c->extra->destroy(u, ((char *) u) + c->extra_offset); + c->extra->destroy(obj, ((char *) obj) + c->extra_offset); - hashtable_del(c->h, u); - free(p); + hashtable_del(c->h, &obj->hashnode); } -static void __cache_del(struct cache *c, struct us_conntrack *u) +void cache_del(struct cache *c, struct cache_object *obj) { /* * Do not increase stats if we are trying to * kill an entry was previously deleted via * __cache_del_timer. */ - if (!alarm_pending(&u->alarm)) { + if (!alarm_pending(&obj->alarm)) { c->stats.del_ok++; c->stats.active--; } - del_alarm(&u->alarm); - __del(c, u); + del_alarm(&obj->alarm); + __del(c, obj); } -struct us_conntrack *cache_update_force(struct cache *c, - struct nf_conntrack *ct) +struct cache_object * +cache_update_force(struct cache *c, struct nf_conntrack *ct) { - struct us_conntrack *u; - - u = cache_find(c, ct); - if (u) { - if (!alarm_pending(&u->alarm)) { - c->stats.upd_ok++; - __cache_update(c, u, ct); - return u; + struct cache_object *obj; + int id; + + obj = cache_find(c, ct, &id); + if (obj) { + if (!alarm_pending(&obj->alarm)) { + cache_update(c, obj, id, ct); + return obj; } else { - __cache_del(c, u); + cache_del(c, obj); + cache_object_free(obj); } } - if ((u = __add(c, ct)) != NULL) { - c->stats.add_ok++; - return u; - } - c->stats.add_fail++; - if (errno == ENOSPC) - c->stats.add_fail_enospc++; - if (errno == ENOMEM) - c->stats.add_fail_enomem++; - - return NULL; -} - -int cache_test(struct cache *c, struct nf_conntrack *ct) -{ - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - void *ret; - - u->ct = ct; - - ret = hashtable_find(c->h, u); - - return ret != NULL; -} - -int cache_del(struct cache *c, struct nf_conntrack *ct) -{ - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - - u->ct = ct; + obj = cache_object_new(c, ct); + if (obj == NULL) + return NULL; - u = (struct us_conntrack *) hashtable_find(c->h, u); - if (u) { - __cache_del(c, u); - return 1; - } - c->stats.del_fail++; - if (errno == ENOENT) - c->stats.del_fail_enoent++; + if (cache_add(c, obj, id) == -1) + return NULL; - return 0; + return obj; } static void __del_timeout(struct alarm_block *a, void *data) { - struct us_conntrack *u = (struct us_conntrack *) data; - - __del(u->cache, u); + struct cache_object *obj = (struct cache_object *) data; + __del(obj->cache, obj); + cache_object_free(obj); } -int -__cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout) +int cache_del_timer(struct cache *c, struct cache_object *obj, int timeout) { if (timeout <= 0) { - __cache_del(c, u); + cache_del(c, obj); + cache_object_free(obj); return 1; } - if (!alarm_pending(&u->alarm)) { - add_alarm(&u->alarm, timeout, 0); + if (!alarm_pending(&obj->alarm)) { + add_alarm(&obj->alarm, timeout, 0); /* * increase stats even if this entry was not really * removed yet. We do not want to make people think @@ -409,20 +348,16 @@ __cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout) return 0; } -struct us_conntrack *cache_find(struct cache *c, struct nf_conntrack *ct) +struct cache_object * +cache_find(struct cache *c, struct nf_conntrack *ct, int *id) { - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - - u->ct = ct; - - return ((struct us_conntrack *) hashtable_find(c->h, u)); + *id = hashtable_hash(c->h, ct); + return ((struct cache_object *) hashtable_find(c->h, ct, *id)); } -struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) +struct cache_object *cache_data_get_object(struct cache *c, void *data) { - return (struct us_conntrack *)((char*)data - c->extra_offset); + return (struct cache_object *)((char*)data - c->extra_offset); } void *cache_get_extra(struct cache *c, void *data) diff --git a/src/cache_iterators.c b/src/cache_iterators.c index a14f428..4773889 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -21,7 +21,6 @@ #include "log.h" #include "conntrackd.h" #include "netlink.h" -#include "us-conntrack.h" #include #include @@ -33,13 +32,13 @@ struct __dump_container { int type; }; -static int do_dump(void *data1, void *data2) +static int do_dump(void *data1, struct hashtable_node *n) { char buf[1024]; int size; struct __dump_container *container = data1; - struct us_conntrack *u = data2; - char *data = u->data; + struct cache_object *obj = (struct cache_object *)n; + char *data = obj->data; unsigned i; /* @@ -52,28 +51,28 @@ static int do_dump(void *data1, void *data2) * specific and it breaks conntrackd modularity. Probably * there's a nicer way to do this but until I come up with it... */ - if (CONFIG(flags) & CTD_SYNC_FTFW && alarm_pending(&u->alarm)) + if (CONFIG(flags) & CTD_SYNC_FTFW && alarm_pending(&obj->alarm)) return 0; /* do not show cached timeout, this may confuse users */ - if (nfct_attr_is_set(u->ct, ATTR_TIMEOUT)) - nfct_attr_unset(u->ct, ATTR_TIMEOUT); + if (nfct_attr_is_set(obj->ct, ATTR_TIMEOUT)) + nfct_attr_unset(obj->ct, ATTR_TIMEOUT); memset(buf, 0, sizeof(buf)); size = nfct_snprintf(buf, sizeof(buf), - u->ct, + obj->ct, NFCT_T_UNKNOWN, container->type, 0); - for (i = 0; i < u->cache->num_features; i++) { - if (u->cache->features[i]->dump) { - size += u->cache->features[i]->dump(u, - data, - buf+size, - container->type); - data += u->cache->features[i]->size; + for (i = 0; i < obj->cache->num_features; i++) { + if (obj->cache->features[i]->dump) { + size += obj->cache->features[i]->dump(obj, + data, + buf+size, + container->type); + data += obj->cache->features[i]->size; } } size += sprintf(buf+size, "\n"); @@ -101,10 +100,10 @@ struct __commit_container { }; static void -__do_commit_step(struct __commit_container *tmp, struct us_conntrack *u) +__do_commit_step(struct __commit_container *tmp, struct cache_object *obj) { int ret, retry = 1; - struct nf_conntrack *ct = u->ct; + struct nf_conntrack *ct = obj->ct; /* * Set a reduced timeout for candidate-to-be-committed @@ -166,25 +165,25 @@ try_again: } } -static int do_commit_related(void *data1, void *data2) +static int do_commit_related(void *data, struct hashtable_node *n) { - struct us_conntrack *u = data2; + struct cache_object *obj = (struct cache_object *)n; - if (ct_is_related(u->ct)) - __do_commit_step(data1, u); + if (ct_is_related(obj->ct)) + __do_commit_step(data, obj); /* keep iterating even if we have found errors */ return 0; } -static int do_commit_master(void *data1, void *data2) +static int do_commit_master(void *data, struct hashtable_node *n) { - struct us_conntrack *u = data2; + struct cache_object *obj = (struct cache_object *)n; - if (ct_is_related(u->ct)) + if (ct_is_related(obj->ct)) return 0; - __do_commit_step(data1, u); + __do_commit_step(data, obj); return 0; } @@ -231,13 +230,13 @@ void cache_commit(struct cache *c) res.tv_sec, res.tv_usec); } -static int do_reset_timers(void *data1, void *data2) +static int do_reset_timers(void *data1, struct hashtable_node *n) { int ret; u_int32_t current_timeout; struct nfct_handle *h = data1; - struct us_conntrack *u = data2; - struct nf_conntrack *ct = u->ct; + struct cache_object *obj = (struct cache_object *)n; + struct nf_conntrack *ct = obj->ct; char __tmp[nfct_maxsize()]; struct nf_conntrack *tmp = (struct nf_conntrack *) (void *)__tmp; @@ -286,13 +285,13 @@ void cache_reset_timers(struct cache *c) nfct_close(h); } -static int do_flush(void *data1, void *data2) +static int do_flush(void *data, struct hashtable_node *n) { - struct cache *c = data1; - struct us_conntrack *u = data2; - - cache_del(c, u->ct); + struct cache *c = data; + struct cache_object *obj = (struct cache_object *)n; + cache_del(c, obj); + cache_object_free(obj); return 0; } diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c index ad3416a..639d8c1 100644 --- a/src/cache_lifetime.c +++ b/src/cache_lifetime.c @@ -17,12 +17,12 @@ */ #include -#include "us-conntrack.h" #include "cache.h" #include #include +#include -static void lifetime_add(struct us_conntrack *u, void *data) +static void lifetime_add(struct cache_object *obj, void *data) { long *lifetime = data; struct timeval tv; @@ -32,15 +32,15 @@ static void lifetime_add(struct us_conntrack *u, void *data) *lifetime = tv.tv_sec; } -static void lifetime_update(struct us_conntrack *u, void *data) +static void lifetime_update(struct cache_object *obj, void *data) { } -static void lifetime_destroy(struct us_conntrack *u, void *data) +static void lifetime_destroy(struct cache_object *obj, void *data) { } -static int lifetime_dump(struct us_conntrack *u, +static int lifetime_dump(struct cache_object *obj, void *data, char *buf, int type) diff --git a/src/cache_timer.c b/src/cache_timer.c index 44482b7..a9e3e3d 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -18,7 +18,6 @@ #include "cache.h" #include "conntrackd.h" -#include "us-conntrack.h" #include "alarm.h" #include "debug.h" @@ -26,45 +25,46 @@ static void timeout(struct alarm_block *a, void *data) { - struct us_conntrack *u = data; + struct cache_object *obj = data; - debug_ct(u->ct, "expired timeout"); - cache_del(u->cache, u->ct); + debug_ct(obj->ct, "expired timeout"); + cache_del(obj->cache, obj); + cache_object_free(obj); } -static void timer_add(struct us_conntrack *u, void *data) +static void timer_add(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; + struct alarm_block *a = data; - init_alarm(alarm, u, timeout); - add_alarm(alarm, CONFIG(cache_timeout), 0); + init_alarm(a, obj, timeout); + add_alarm(a, CONFIG(cache_timeout), 0); } -static void timer_update(struct us_conntrack *u, void *data) +static void timer_update(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; - add_alarm(alarm, CONFIG(cache_timeout), 0); + struct alarm_block *a = data; + add_alarm(a, CONFIG(cache_timeout), 0); } -static void timer_destroy(struct us_conntrack *u, void *data) +static void timer_destroy(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; - del_alarm(alarm); + struct alarm_block *a = data; + del_alarm(a); } -static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type) +static int timer_dump(struct cache_object *obj, void *data, char *buf, int type) { struct timeval tv, tmp; - struct alarm_block *alarm = data; + struct alarm_block *a = data; if (type == NFCT_O_XML) return 0; - if (!alarm_pending(alarm)) + if (!alarm_pending(a)) return 0; gettimeofday(&tv, NULL); - timersub(&alarm->tv, &tv, &tmp); + timersub(&a->tv, &tv, &tmp); return sprintf(buf, " [expires in %lds]", tmp.tv_sec); } diff --git a/src/cache_wt.c b/src/cache_wt.c index d0ae8bb..84a816f 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -19,67 +19,66 @@ #include "conntrackd.h" #include "cache.h" #include "netlink.h" -#include "us-conntrack.h" #include "log.h" #include #include -static void add_wt(struct us_conntrack *u) +static void add_wt(struct cache_object *obj) { int ret; char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - ret = nl_exist_conntrack(STATE(request), u->ct); + ret = nl_exist_conntrack(STATE(request), obj->ct); switch (ret) { case -1: dlog(LOG_ERR, "cache_wt problem: %s", strerror(errno)); - dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); break; case 0: - memcpy(ct, u->ct, nfct_maxsize()); + memcpy(ct, obj->ct, nfct_maxsize()); if (nl_create_conntrack(STATE(dump), ct) == -1) { dlog(LOG_ERR, "cache_wt create: %s", strerror(errno)); - dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } break; case 1: - memcpy(ct, u->ct, nfct_maxsize()); + memcpy(ct, obj->ct, nfct_maxsize()); if (nl_update_conntrack(STATE(dump), ct) == -1) { dlog(LOG_ERR, "cache_wt crt-upd: %s", strerror(errno)); - dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } break; } } -static void upd_wt(struct us_conntrack *u) +static void upd_wt(struct cache_object *obj) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - memcpy(ct, u->ct, nfct_maxsize()); + memcpy(ct, obj->ct, nfct_maxsize()); if (nl_update_conntrack(STATE(dump), ct) == -1) { dlog(LOG_ERR, "cache_wt update:%s", strerror(errno)); - dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } } -static void writethrough_add(struct us_conntrack *u, void *data) +static void writethrough_add(struct cache_object *obj, void *data) { - add_wt(u); + add_wt(obj); } -static void writethrough_update(struct us_conntrack *u, void *data) +static void writethrough_update(struct cache_object *obj, void *data) { - upd_wt(u); + upd_wt(obj); } -static void writethrough_destroy(struct us_conntrack *u, void *data) +static void writethrough_destroy(struct cache_object *obj, void *data) { - nl_destroy_conntrack(STATE(dump), u->ct); + nl_destroy_conntrack(STATE(dump), obj->ct); } struct cache_feature writethrough_feature = { diff --git a/src/filter.c b/src/filter.c index c6e24a9..6a09c77 100644 --- a/src/filter.c +++ b/src/filter.c @@ -58,15 +58,17 @@ static uint32_t ct_filter_hash6(const void *data, const struct hashtable *table) static int ct_filter_compare(const void *data1, const void *data2) { - const uint32_t *f1 = data1; + const struct ct_filter_ipv4_hnode *f1 = data1; const uint32_t *f2 = data2; - return *f1 == *f2; + return f1->ip == *f2; } static int ct_filter_compare6(const void *data1, const void *data2) { - return memcmp(data1, data2, sizeof(uint32_t)*4) == 0; + const struct ct_filter_ipv6_hnode *f = data1; + + return memcmp(f->ipv6, data2, sizeof(uint32_t)*4) == 0; } struct ct_filter *ct_filter_create(void) @@ -80,7 +82,6 @@ struct ct_filter *ct_filter_create(void) filter->h = hashtable_create(FILTER_POOL_SIZE, FILTER_POOL_LIMIT, - sizeof(uint32_t), ct_filter_hash, ct_filter_compare); if (!filter->h) { @@ -90,7 +91,6 @@ struct ct_filter *ct_filter_create(void) filter->h6 = hashtable_create(FILTER_POOL_SIZE, FILTER_POOL_LIMIT, - sizeof(uint32_t)*4, ct_filter_hash6, ct_filter_compare6); if (!filter->h6) { @@ -155,16 +155,33 @@ void ct_filter_set_logic(struct ct_filter *filter, int ct_filter_add_ip(struct ct_filter *filter, void *data, uint8_t family) { + int id; filter = __filter_alloc(filter); switch(family) { case AF_INET: - if (!hashtable_add(filter->h, data)) + id = hashtable_hash(filter->h, data); + if (!hashtable_find(filter->h, data, id)) { + struct ct_filter_ipv4_hnode *n; + n = malloc(sizeof(struct ct_filter_ipv4_hnode)); + if (n == NULL) + return 0; + memcpy(&n->ip, data, sizeof(uint32_t)); + hashtable_add(filter->h, &n->node, id); return 0; + } break; case AF_INET6: - if (!hashtable_add(filter->h6, data)) + id = hashtable_hash(filter->h6, data); + if (!hashtable_find(filter->h6, data, id)) { + struct ct_filter_ipv6_hnode *n; + n = malloc(sizeof(struct ct_filter_ipv6_hnode)); + if (n == NULL) + return 0; + memcpy(n->ipv6, data, sizeof(uint32_t)*4); + hashtable_add(filter->h6, &n->node, id); return 0; + } break; } return 1; @@ -220,16 +237,34 @@ void ct_filter_add_state(struct ct_filter *f, int protonum, int val) static inline int __ct_filter_test_ipv4(struct ct_filter *f, struct nf_conntrack *ct) { + int id_src, id_dst; + uint32_t src, dst; + /* we only use the real source and destination address */ - return (hashtable_find(f->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || - hashtable_find(f->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC))); + src = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC); + dst = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); + + id_src = hashtable_hash(f->h, &src); + id_dst = hashtable_hash(f->h, &dst); + + return hashtable_find(f->h, &src, id_src) || + hashtable_find(f->h, &dst, id_dst); } static inline int __ct_filter_test_ipv6(struct ct_filter *f, struct nf_conntrack *ct) { - return (hashtable_find(f->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || - hashtable_find(f->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC))); + int id_src, id_dst; + const uint32_t *src, *dst; + + src = nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC); + dst = nfct_get_attr(ct, ATTR_REPL_IPV6_SRC); + + id_src = hashtable_hash(f->h6, src); + id_dst = hashtable_hash(f->h6, dst); + + return hashtable_find(f->h6, src, id_src) || + hashtable_find(f->h6, dst, id_dst); } static int diff --git a/src/hash.c b/src/hash.c index 1edb977..9c9ea5b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1,5 +1,5 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2009 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 @@ -19,32 +19,13 @@ */ #include "hash.h" -#include "slist.h" #include #include #include -struct hashtable_node *hashtable_alloc_node(int datasize, void *data) -{ - struct hashtable_node *n; - int size = sizeof(struct hashtable_node) + datasize; - - n = calloc(size, 1); - if (n == NULL) - return NULL; - memcpy(n->data, data, datasize); - - return n; -} - -void hashtable_destroy_node(struct hashtable_node *h) -{ - free(h); -} - struct hashtable * -hashtable_create(int hashsize, int limit, int datasize, +hashtable_create(int hashsize, int limit, uint32_t (*hash)(const void *data, const struct hashtable *table), int (*compare)(const void *data1, const void *data2)) @@ -52,7 +33,7 @@ hashtable_create(int hashsize, int limit, int datasize, int i; struct hashtable *h; int size = sizeof(struct hashtable) - + hashsize * sizeof(struct slist_head); + + hashsize * sizeof(struct list_head); h = (struct hashtable *) calloc(size, 1); if (h == NULL) { @@ -61,11 +42,10 @@ hashtable_create(int hashsize, int limit, int datasize, } for (i=0; imembers[i]); + INIT_LIST_HEAD(&h->members[i]); h->hashsize = hashsize; h->limit = limit; - h->datasize = datasize; h->hash = hash; h->compare = compare; @@ -74,112 +54,74 @@ hashtable_create(int hashsize, int limit, int datasize, void hashtable_destroy(struct hashtable *h) { - hashtable_flush(h); free(h); } -void *hashtable_add(struct hashtable *table, void *data) +int hashtable_hash(const struct hashtable *table, const void *data) { - struct slist_head *e; - struct hashtable_node *n; - uint32_t id; - - /* hash table is full */ - if (table->count >= table->limit) { - errno = ENOSPC; - return NULL; - } - - id = table->hash(data, table); - - slist_for_each(e, &table->members[id]) { - n = slist_entry(e, struct hashtable_node, head); - if (table->compare(n->data, data)) { - errno = EEXIST; - return NULL; - } - } - - n = hashtable_alloc_node(table->datasize, data); - if (n == NULL) { - errno = ENOMEM; - return NULL; - } - - slist_add(&table->members[id], &n->head); - table->count++; - - return n->data; + return table->hash(data, table); } -void *hashtable_find(struct hashtable *table, const void *data) +struct hashtable_node * +hashtable_find(const struct hashtable *table, const void *data, int id) { - struct slist_head *e; - uint32_t id; + struct list_head *e; struct hashtable_node *n; - id = table->hash(data, table); - - slist_for_each(e, &table->members[id]) { - n = slist_entry(e, struct hashtable_node, head); - if (table->compare(n->data, data)) - return n->data; + list_for_each(e, &table->members[id]) { + n = list_entry(e, struct hashtable_node, head); + if (table->compare(n, data)) { + return n; + } } - errno = ENOENT; return NULL; } -int hashtable_del(struct hashtable *table, void *data) +int hashtable_add(struct hashtable *table, struct hashtable_node *n, int id) { - struct slist_head *e, *next, *prev; - uint32_t id; - struct hashtable_node *n; - - id = table->hash(data, table); - - slist_for_each_safe(e, prev, next, &table->members[id]) { - n = slist_entry(e, struct hashtable_node, head); - if (table->compare(n->data, data)) { - slist_del(e, prev); - hashtable_destroy_node(n); - table->count--; - return 0; - } + /* hash table is full */ + if (table->count >= table->limit) { + errno = ENOSPC; + return -1; } - errno = ENOENT; - return -1; + list_add(&n->head, &table->members[id]); + table->count++; + return 0; +} + +void hashtable_del(struct hashtable *table, struct hashtable_node *n) +{ + list_del(&n->head); + table->count--; } int hashtable_flush(struct hashtable *table) { uint32_t i; - struct slist_head *e, *next, *prev; + struct list_head *e, *tmp; struct hashtable_node *n; - for (i=0; i < table->hashsize; i++) - slist_for_each_safe(e, prev, next, &table->members[i]) { - n = slist_entry(e, struct hashtable_node, head); - slist_del(e, prev); - hashtable_destroy_node(n); + for (i=0; i < table->hashsize; i++) { + list_for_each_safe(e, tmp, &table->members[i]) { + n = list_entry(e, struct hashtable_node, head); + free(n); } - - table->count = 0; - + } return 0; } int hashtable_iterate(struct hashtable *table, void *data, - int (*iterate)(void *data1, void *data2)) + int (*iterate)(void *data1, struct hashtable_node *n)) { uint32_t i; - struct slist_head *e, *next, *prev; + struct list_head *e, *tmp; struct hashtable_node *n; for (i=0; i < table->hashsize; i++) { - slist_for_each_safe(e, prev, next, &table->members[i]) { - n = slist_entry(e, struct hashtable_node, head); - if (iterate(data, n->data) == -1) + list_for_each_safe(e, tmp, &table->members[i]) { + n = list_entry(e, struct hashtable_node, head); + if (iterate(data, n) == -1) return -1; } } diff --git a/src/stats-mode.c b/src/stats-mode.c index d340b0d..679a50c 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -22,7 +22,6 @@ #include "cache.h" #include "log.h" #include "conntrackd.h" -#include "us-conntrack.h" #include #include @@ -118,9 +117,8 @@ static int overrun_stats(enum nf_conntrack_msg_type type, 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"); + if (!cache_update_force(STATE_STATS(cache), ct)) + debug_ct(ct, "overrun stats resync"); return NFCT_CB_CONTINUE; } @@ -128,12 +126,13 @@ static int overrun_stats(enum nf_conntrack_msg_type type, static int purge_step(void *data1, void *data2) { int ret; - struct us_conntrack *u = data2; + struct cache_object *obj = data2; - ret = nfct_query(STATE(dump), NFCT_Q_GET, u->ct); + ret = nfct_query(STATE(dump), NFCT_Q_GET, obj->ct); if (ret == -1 && errno == ENOENT) { - debug_ct(u->ct, "overrun purge stats"); - cache_del(STATE_STATS(cache), u->ct); + debug_ct(obj->ct, "overrun purge stats"); + cache_del(STATE_STATS(cache), obj); + cache_object_free(obj); } return 0; @@ -148,42 +147,46 @@ static int purge_stats(void) static void event_new_stats(struct nf_conntrack *ct) { + int id; + struct cache_object *obj; + nfct_attr_unset(ct, ATTR_TIMEOUT); - if (cache_add(STATE_STATS(cache), ct)) { - debug_ct(ct, "cache new"); - } else { - if (errno != EEXIST) { - dlog(LOG_ERR, - "can't add to cache cache: %s\n", strerror(errno)); - debug_ct(ct, "can't add"); + obj = cache_find(STATE_STATS(cache), ct, &id); + if (obj == NULL) { + obj = cache_object_new(STATE_STATS(cache), ct); + if (obj == NULL) + return; + + if (cache_add(STATE_STATS(cache), obj, id) == -1) { + cache_object_free(obj); + return; } } + return; } static void event_update_stats(struct nf_conntrack *ct) { nfct_attr_unset(ct, ATTR_TIMEOUT); - - if (!cache_update_force(STATE_STATS(cache), ct)) { - debug_ct(ct, "can't update"); - return; - } - debug_ct(ct, "update"); + cache_update_force(STATE_STATS(cache), ct); } static int event_destroy_stats(struct nf_conntrack *ct) { + int id; + struct cache_object *obj; + nfct_attr_unset(ct, ATTR_TIMEOUT); - if (cache_del(STATE_STATS(cache), ct)) { - debug_ct(ct, "cache destroy"); + obj = cache_find(STATE_STATS(cache), ct, &id); + if (obj) { + cache_del(STATE_STATS(cache), obj); dlog_ct(STATE(stats_log), ct, NFCT_O_PLAIN); + cache_object_free(obj); return 1; - } else { - debug_ct(ct, "can't destroy!"); - return 0; } + return 0; } struct ct_mode stats_mode = { diff --git a/src/sync-alarm.c b/src/sync-alarm.c index d871b75..34937fe 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -19,7 +19,6 @@ #include "conntrackd.h" #include "sync.h" #include "network.h" -#include "us-conntrack.h" #include "alarm.h" #include "cache.h" #include "debug.h" @@ -30,40 +29,40 @@ static void refresher(struct alarm_block *a, void *data) { struct nethdr *net; - struct us_conntrack *u = data; + struct cache_object *obj = data; - debug_ct(u->ct, "persistence update"); + debug_ct(obj->ct, "persistence update"); add_alarm(a, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); - net = BUILD_NETMSG(u->ct, NET_T_STATE_UPD); + net = BUILD_NETMSG(obj->ct, NET_T_STATE_UPD); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } -static void cache_alarm_add(struct us_conntrack *u, void *data) +static void cache_alarm_add(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; + struct alarm_block *a = data; - init_alarm(alarm, u, refresher); - add_alarm(alarm, + init_alarm(a, obj, refresher); + add_alarm(a, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); } -static void cache_alarm_update(struct us_conntrack *u, void *data) +static void cache_alarm_update(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; - add_alarm(alarm, + struct alarm_block *a = data; + add_alarm(a, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); } -static void cache_alarm_destroy(struct us_conntrack *u, void *data) +static void cache_alarm_destroy(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; - del_alarm(alarm); + struct alarm_block *a = data; + del_alarm(a); } static struct cache_extra cache_alarm_extra = { diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 44e8f2f..bddc18c 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -18,7 +18,6 @@ #include "conntrackd.h" #include "sync.h" -#include "us-conntrack.h" #include "queue.h" #include "debug.h" #include "network.h" @@ -64,7 +63,7 @@ struct cache_ftfw { uint32_t seq; }; -static void cache_ftfw_add(struct us_conntrack *u, void *data) +static void cache_ftfw_add(struct cache_object *obj, void *data) { struct cache_ftfw *cn = data; /* These nodes are not inserted in the list */ @@ -72,7 +71,7 @@ static void cache_ftfw_add(struct us_conntrack *u, void *data) INIT_LIST_HEAD(&cn->tx_list); } -static void cache_ftfw_del(struct us_conntrack *u, void *data) +static void cache_ftfw_del(struct cache_object *obj, void *data) { struct cache_ftfw *cn = data; @@ -190,8 +189,8 @@ static void ftfw_kill(void) static int do_cache_to_tx(void *data1, void *data2) { - struct us_conntrack *u = data2; - struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), u); + struct cache_object *obj = data2; + struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); /* repeated request for resync? */ if (!list_empty(&cn->tx_list)) @@ -226,9 +225,6 @@ static void debug_rs_dump(int fd) size = sprintf(buf, "resent list (len=%u):\n", rs_list_len); send(fd, buf, size, 0); list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct us_conntrack *u; - - u = cache_get_conntrack(STATE_SYNC(internal), cn); size = sprintf(buf, "seq:%u\n", cn->seq); send(fd, buf, size, 0); } @@ -305,9 +301,9 @@ static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) struct cache_ftfw *cn, *tmp; list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct us_conntrack *u; + struct cache_object *obj;; - u = cache_get_conntrack(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE_SYNC(internal), cn); if (before(cn->seq, from)) continue; else if (after(cn->seq, to)) @@ -330,9 +326,9 @@ static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) struct cache_ftfw *cn, *tmp; list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct us_conntrack *u; + struct cache_object *obj; - u = cache_get_conntrack(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE_SYNC(internal), cn); if (before(cn->seq, from)) continue; else if (after(cn->seq, to)) @@ -473,7 +469,7 @@ out: return ret; } -static void ftfw_send(struct nethdr *net, struct us_conntrack *u) +static void ftfw_send(struct nethdr *net, struct cache_object *obj) { struct cache_ftfw *cn; @@ -482,7 +478,7 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) case NET_T_STATE_UPD: case NET_T_STATE_DEL: cn = (struct cache_ftfw *) - cache_get_extra(STATE_SYNC(internal), u); + cache_get_extra(STATE_SYNC(internal), obj); if (!list_empty(&cn->rs_list)) { list_del_init(&cn->rs_list); @@ -538,10 +534,10 @@ static int tx_queue_xmit(void *data1, const void *data2) return 0; } -static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) +static int tx_list_xmit(struct list_head *i, struct cache_object *obj, int type) { int ret; - struct nethdr *net = BUILD_NETMSG(u->ct, type); + struct nethdr *net = BUILD_NETMSG(obj->ct, type); dp("tx_list sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); @@ -550,7 +546,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) tx_list_len--; ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - ftfw_send(net, u); + ftfw_send(net, obj); return ret; } @@ -564,13 +560,13 @@ static void ftfw_run(void) /* send conntracks in the tx_list */ list_for_each_entry_safe(cn, tmp, &tx_list, tx_list) { - struct us_conntrack *u; + struct cache_object *obj; - u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (alarm_pending(&u->alarm)) - tx_list_xmit(&cn->tx_list, u, NET_T_STATE_DEL); + obj = cache_data_get_object(STATE_SYNC(internal), cn); + if (alarm_pending(&obj->alarm)) + tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_DEL); else - tx_list_xmit(&cn->tx_list, u, NET_T_STATE_UPD); + tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_UPD); } /* reset alive alarm */ diff --git a/src/sync-mode.c b/src/sync-mode.c index ad2e2ff..368984f 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -22,7 +22,6 @@ #include "log.h" #include "cache.h" #include "conntrackd.h" -#include "us-conntrack.h" #include "network.h" #include "fds.h" #include "event.h" @@ -38,7 +37,8 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - struct us_conntrack *u; + struct cache_object *obj; + int id; if (net->version != CONNTRACKD_PROTOCOL_VERSION) { STATE_SYNC(error).msg_rcv_malformed++; @@ -75,33 +75,32 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) switch(net->type) { case NET_T_STATE_NEW: -retry: - if ((u = cache_add(STATE_SYNC(external), ct))) { - debug_ct(u->ct, "external new"); - } else { - /* - * One certain connection A arrives to the cache but - * another existing connection B in the cache has - * the same configuration, therefore B clashes with A. - */ - if (errno == EEXIST) { - cache_del(STATE_SYNC(external), ct); - goto retry; + obj = cache_find(STATE_SYNC(external), ct, &id); + if (obj == NULL) { +retry: + obj = cache_object_new(STATE_SYNC(external), ct); + if (obj == NULL) + return; + + if (cache_add(STATE_SYNC(external), obj, id) == -1) { + cache_object_free(obj); + return; } - debug_ct(ct, "can't add"); + } else { + cache_del(STATE_SYNC(external), obj); + cache_object_free(obj); + goto retry; } break; case NET_T_STATE_UPD: - if ((u = cache_update_force(STATE_SYNC(external), ct))) { - debug_ct(u->ct, "external update"); - } else - debug_ct(ct, "can't update"); + cache_update_force(STATE_SYNC(external), ct); break; case NET_T_STATE_DEL: - if (cache_del(STATE_SYNC(external), ct)) - debug_ct(ct, "external destroy"); - else - debug_ct(ct, "can't destroy"); + obj = cache_find(STATE_SYNC(external), ct, &id); + if (obj) { + cache_del(STATE_SYNC(external), obj); + cache_object_free(obj); + } break; default: STATE_SYNC(error).msg_rcv_malformed++; @@ -441,14 +440,14 @@ static void dump_sync(struct nf_conntrack *ct) debug_ct(ct, "resync"); } -static void mcast_send_sync(struct us_conntrack *u, int query) +static void mcast_send_sync(struct cache_object *obj, int query) { struct nethdr *net; - net = BUILD_NETMSG(u->ct, query); + net = BUILD_NETMSG(obj->ct, query); if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, u); + STATE_SYNC(sync)->send(net, obj); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } @@ -457,13 +456,13 @@ static int purge_step(void *data1, void *data2) { int ret; struct nfct_handle *h = STATE(dump); - struct us_conntrack *u = data2; + struct cache_object *obj = data2; - ret = nfct_query(h, NFCT_Q_GET, u->ct); + ret = nfct_query(h, NFCT_Q_GET, obj->ct); if (ret == -1 && errno == ENOENT) { - debug_ct(u->ct, "overrun purge resync"); - mcast_send_sync(u, NET_T_STATE_DEL); - __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); + debug_ct(obj->ct, "overrun purge resync"); + mcast_send_sync(obj, NET_T_STATE_DEL); + cache_del_timer(STATE_SYNC(internal), obj, CONFIG(del_timeout)); } return 0; @@ -480,7 +479,7 @@ static int overrun_sync(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { - struct us_conntrack *u; + struct cache_object *obj; if (ct_filter_conntrack(ct, 1)) return NFCT_CB_CONTINUE; @@ -492,11 +491,9 @@ static int overrun_sync(enum nf_conntrack_msg_type type, nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - if (!cache_test(STATE_SYNC(internal), ct)) { - if ((u = cache_update_force(STATE_SYNC(internal), ct))) { - debug_ct(u->ct, "overrun resync"); - mcast_send_sync(u, NET_T_STATE_UPD); - } + if ((obj = cache_update_force(STATE_SYNC(internal), ct))) { + debug_ct(obj->ct, "overrun resync"); + mcast_send_sync(obj, NET_T_STATE_UPD); } return NFCT_CB_CONTINUE; @@ -504,50 +501,59 @@ static int overrun_sync(enum nf_conntrack_msg_type type, static void event_new_sync(struct nf_conntrack *ct) { - struct us_conntrack *u; + struct cache_object *obj; + int id; /* required by linux kernel <= 2.6.20 */ 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); + + obj = cache_find(STATE_SYNC(internal), ct, &id); + if (obj == NULL) { retry: - if ((u = cache_add(STATE_SYNC(internal), ct))) { - mcast_send_sync(u, NET_T_STATE_NEW); - debug_ct(u->ct, "internal new"); - } else { - if (errno == EEXIST) { - cache_del(STATE_SYNC(internal), ct); - goto retry; + obj = cache_object_new(STATE_SYNC(internal), ct); + if (obj == NULL) + return; + if (cache_add(STATE_SYNC(internal), obj, id) == -1) { + cache_object_free(obj); + return; } + mcast_send_sync(obj, NET_T_STATE_NEW); + debug_ct(obj->ct, "internal new"); + } else { + cache_del(STATE_SYNC(internal), obj); + cache_object_free(obj); debug_ct(ct, "can't add"); + goto retry; } } static void event_update_sync(struct nf_conntrack *ct) { - struct us_conntrack *u; + struct cache_object *obj; - if ((u = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { + if ((obj = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { debug_ct(ct, "can't update"); return; } - debug_ct(u->ct, "internal update"); - mcast_send_sync(u, NET_T_STATE_UPD); + debug_ct(obj->ct, "internal update"); + mcast_send_sync(obj, NET_T_STATE_UPD); } static int event_destroy_sync(struct nf_conntrack *ct) { - struct us_conntrack *u; + struct cache_object *obj; + int id; - u = cache_find(STATE_SYNC(internal), ct); - if (u == NULL) { + obj = cache_find(STATE_SYNC(internal), ct, &id); + if (obj == NULL) { debug_ct(ct, "can't destroy"); return 0; } - - mcast_send_sync(u, NET_T_STATE_DEL); - __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); + mcast_send_sync(obj, NET_T_STATE_DEL); + cache_del_timer(STATE_SYNC(internal), obj, CONFIG(del_timeout)); debug_ct(ct, "internal destroy"); return 1; } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 700e272..2d3783e 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -18,7 +18,6 @@ #include "conntrackd.h" #include "sync.h" -#include "us-conntrack.h" #include "queue.h" #include "debug.h" #include "network.h" @@ -36,13 +35,13 @@ struct cache_notrack { struct list_head tx_list; }; -static void cache_notrack_add(struct us_conntrack *u, void *data) +static void cache_notrack_add(struct cache_object *obj, void *data) { struct cache_notrack *cn = data; INIT_LIST_HEAD(&cn->tx_list); } -static void cache_notrack_del(struct us_conntrack *u, void *data) +static void cache_notrack_del(struct cache_object *obj, void *data) { struct cache_notrack *cn = data; @@ -89,8 +88,8 @@ static void notrack_kill(void) static int do_cache_to_tx(void *data1, void *data2) { - struct us_conntrack *u = data2; - struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), u); + struct cache_object *obj = data2; + struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); if (!list_empty(&cn->tx_list)) return 0; @@ -164,10 +163,10 @@ static int tx_queue_xmit(void *data1, const void *data2) return 0; } -static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) +static int tx_list_xmit(struct list_head *i, struct cache_object *obj, int type) { int ret; - struct nethdr *net = BUILD_NETMSG(u->ct, type); + struct nethdr *net = BUILD_NETMSG(obj->ct, type); list_del_init(i); tx_list_len--; @@ -186,10 +185,10 @@ static void notrack_run(void) /* send conntracks in the tx_list */ list_for_each_entry_safe(cn, tmp, &tx_list, tx_list) { - struct us_conntrack *u; + struct cache_object *obj; - u = cache_get_conntrack(STATE_SYNC(internal), cn); - tx_list_xmit(&cn->tx_list, u, NET_T_STATE_UPD); + obj = cache_data_get_object(STATE_SYNC(internal), cn); + tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_UPD); } } -- cgit v1.2.3 From 8dce3504fde7da933dc6e7ecfeb99b4b45125f32 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 15 Jan 2009 23:19:58 +0100 Subject: cache: add status field to store the object status This patch adds the status field to the cache object. This avoids the (ab)use of the alarm to check if an entry is active or dead. This is the first step to possibly move the alarm to the cache_extra memory space of the ftfw (which is the only use by now). Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 8 ++++++++ include/network.h | 1 + src/cache.c | 10 +++++++--- src/cache_iterators.c | 2 +- src/network.c | 13 +++++++++++++ 5 files changed, 30 insertions(+), 4 deletions(-) (limited to 'include/network.h') diff --git a/include/cache.h b/include/cache.h index dcd6bcd..fd8e05f 100644 --- a/include/cache.h +++ b/include/cache.h @@ -23,11 +23,19 @@ enum { }; #define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE +enum { + C_OBJ_NONE = 0, /* not in the cache */ + C_OBJ_NEW, /* just added to the cache */ + C_OBJ_ALIVE, /* in the cache, alive */ + C_OBJ_DEAD /* still in the cache, but dead */ +}; + struct cache; struct cache_object { struct hashtable_node hashnode; struct nf_conntrack *ct; struct cache *cache; + int status; struct alarm_block alarm; char data[0]; }; diff --git a/include/network.h b/include/network.h index 619ce3e..f02d920 100644 --- a/include/network.h +++ b/include/network.h @@ -30,6 +30,7 @@ int nethdr_size(int len); void nethdr_set(struct nethdr *net, int type); void nethdr_set_ack(struct nethdr *net); void nethdr_set_ctl(struct nethdr *net); +int object_status_to_network_type(int status); #define NETHDR_DATA(x) \ (struct netattr *)(((char *)x) + NETHDR_SIZ) diff --git a/src/cache.c b/src/cache.c index 621a3f4..c46498b 100644 --- a/src/cache.c +++ b/src/cache.c @@ -196,6 +196,7 @@ struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) return NULL; } memcpy(obj->ct, ct, nfct_sizeof(ct)); + obj->status = C_OBJ_NONE; return obj; } @@ -225,6 +226,7 @@ static int __add(struct cache *c, struct cache_object *obj, int id) c->extra->add(obj, ((char *) obj) + c->extra_offset); c->stats.active++; + obj->status = C_OBJ_NEW; return 0; } @@ -260,6 +262,7 @@ void cache_update(struct cache *c, struct cache_object *obj, int id, c->extra->update(obj, ((char *) obj) + c->extra_offset); c->stats.upd_ok++; + obj->status = C_OBJ_ALIVE; } static void __del(struct cache *c, struct cache_object *obj) @@ -285,7 +288,7 @@ void cache_del(struct cache *c, struct cache_object *obj) * kill an entry was previously deleted via * __cache_del_timer. */ - if (!alarm_pending(&obj->alarm)) { + if (obj->status != C_OBJ_DEAD) { c->stats.del_ok++; c->stats.active--; } @@ -301,7 +304,7 @@ cache_update_force(struct cache *c, struct nf_conntrack *ct) obj = cache_find(c, ct, &id); if (obj) { - if (!alarm_pending(&obj->alarm)) { + if (obj->status != C_OBJ_DEAD) { cache_update(c, obj, id, ct); return obj; } else { @@ -333,7 +336,8 @@ int cache_del_timer(struct cache *c, struct cache_object *obj, int timeout) cache_object_free(obj); return 1; } - if (!alarm_pending(&obj->alarm)) { + if (obj->status != C_OBJ_DEAD) { + obj->status = C_OBJ_DEAD; add_alarm(&obj->alarm, timeout, 0); /* * increase stats even if this entry was not really diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 4773889..ab6a461 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -51,7 +51,7 @@ static int do_dump(void *data1, struct hashtable_node *n) * specific and it breaks conntrackd modularity. Probably * there's a nicer way to do this but until I come up with it... */ - if (CONFIG(flags) & CTD_SYNC_FTFW && alarm_pending(&obj->alarm)) + if (CONFIG(flags) & CTD_SYNC_FTFW && obj->status == C_OBJ_DEAD) return 0; /* do not show cached timeout, this may confuse users */ diff --git a/src/network.c b/src/network.c index 598195f..320cdea 100644 --- a/src/network.c +++ b/src/network.c @@ -177,3 +177,16 @@ int mcast_track_is_seq_set() { return local_seq_set; } + +#include "cache.h" + +static int status2type[] = { + [C_OBJ_NEW] = NET_T_STATE_NEW, + [C_OBJ_ALIVE] = NET_T_STATE_UPD, + [C_OBJ_DEAD] = NET_T_STATE_DEL, +}; + +int object_status_to_network_type(int status) +{ + return status2type[status]; +} -- cgit v1.2.3 From 7ae054f8aae252ee9c57e26327675e466fc1d15d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 18:03:52 +0100 Subject: src: support for redundant dedicated links This patch adds support for redundant dedicated links. You can add a pool of dedicated links that can be used if the current active fails. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 19 ++++ doc/sync/ftfw/conntrackd.conf | 19 ++++ doc/sync/notrack/conntrackd.conf | 19 ++++ include/conntrackd.h | 10 +- include/mcast.h | 28 ++++- include/netlink.h | 1 + include/network.h | 6 +- src/main.c | 6 +- src/mcast.c | 231 ++++++++++++++++++++++++++++++++++++--- src/netlink.c | 16 +++ src/network.c | 9 +- src/read_config_lex.l | 1 + src/read_config_yy.y | 105 ++++++++++++------ src/sync-mode.c | 109 ++++++++++++++---- 14 files changed, 495 insertions(+), 84 deletions(-) (limited to 'include/network.h') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index f16f439..528ff8f 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -104,6 +104,25 @@ Sync { # Checksum on } + # + # You can specify more than one dedicated link. Thus, if one dedicated + # link fails, conntrackd can fail-over to another. Note that adding + # more than one dedicated link does not mean that state-updates will + # be sent to all of them. There is only one active dedicated link at + # a given moment. The `Default' keyword indicates that this interface + # will be selected as the initial dedicated link. You can have + # up to 4 redundant dedicated links. Note: Use different multicast + # groups for every redundant link. + # + # Multicast Default { + # IPv4_address 225.0.0.51 + # Group 3781 + # IPv4_interface 192.168.100.101 + # Interface eth3 + # # McastSndSocketBuffer 1249280 + # # McastRcvSocketBuffer 1249280 + # Checksum on + # } } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index d85fc28..2e60f2c 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -112,6 +112,25 @@ Sync { # Checksum on } + # + # You can specify more than one dedicated link. Thus, if one dedicated + # link fails, conntrackd can fail-over to another. Note that adding + # more than one dedicated link does not mean that state-updates will + # be sent to all of them. There is only one active dedicated link at + # a given moment. The `Default' keyword indicates that this interface + # will be selected as the initial dedicated link. You can have + # up to 4 redundant dedicated links. Note: Use different multicast + # groups for every redundant link. + # + # Multicast Default { + # IPv4_address 225.0.0.51 + # Group 3781 + # IPv4_interface 192.168.100.101 + # Interface eth3 + # # McastSndSocketBuffer 1249280 + # # McastRcvSocketBuffer 1249280 + # Checksum on + # } } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 4d03234..7f8c8a3 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -94,6 +94,25 @@ Sync { # Checksum on } + # + # You can specify more than one dedicated link. Thus, if one dedicated + # link fails, conntrackd can fail-over to another. Note that adding + # more than one dedicated link does not mean that state-updates will + # be sent to all of them. There is only one active dedicated link at + # a given moment. The `Default' keyword indicates that this interface + # will be selected as the initial dedicated link. You can have + # up to 4 redundant dedicated links. Note: Use different multicast + # groups for every redundant link. + # + # Multicast Default { + # IPv4_address 225.0.0.51 + # Group 3781 + # IPv4_interface 192.168.100.101 + # Interface eth3 + # # McastSndSocketBuffer 1249280 + # # McastRcvSocketBuffer 1249280 + # Checksum on + # } } # diff --git a/include/conntrackd.h b/include/conntrackd.h index 3637e2c..ab5d825 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -29,6 +29,7 @@ #define STATS_NETWORK 28 /* extended network stats */ #define STATS_CACHE 29 /* extended cache stats */ #define STATS_RUNTIME 30 /* extended runtime stats */ +#define STATS_MULTICAST 31 /* multicast network stats */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" @@ -66,7 +67,9 @@ struct ct_conf { int syslog_facility; char lockfile[FILENAME_MAXLEN]; int hashsize; /* hashtable size */ - struct mcast_conf mcast; /* multicast settings */ + int mcast_links; + int mcast_default_link; + struct mcast_conf mcast[MCAST_LINKS_MAX]; struct local_conf local; /* unix socket facilities */ int limit; int refresh; @@ -148,8 +151,9 @@ struct ct_sync_state { struct cache *internal; /* internal events cache (netlink) */ struct cache *external; /* external events cache (mcast) */ - struct mcast_sock *mcast_server; /* multicast socket: incoming */ - struct mcast_sock *mcast_client; /* multicast socket: outgoing */ + struct mcast_sock_multi *mcast_server; /* multicast incoming */ + struct mcast_sock_multi *mcast_client; /* multicast outgoing */ + struct nlif_handle *mcast_iface; struct queue *tx_queue; struct sync_mode *sync; /* sync mode */ diff --git a/include/mcast.h b/include/mcast.h index 7c4b1d6..623f390 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -19,6 +19,7 @@ struct mcast_conf { unsigned int interface_index6; } ifa; int mtu; + int interface_idx; int sndbuf; int rcvbuf; char iface[IFNAMSIZ]; @@ -37,19 +38,42 @@ struct mcast_sock { struct sockaddr_in6 ipv6; } addr; socklen_t sockaddr_len; + int interface_idx; struct mcast_stats stats; }; +#define MCAST_LINKS_MAX 4 + +struct mcast_sock_multi { + int num_links; + int max_mtu; + struct mcast_sock *current_link; + struct mcast_sock *multi[MCAST_LINKS_MAX]; +}; + struct mcast_sock *mcast_server_create(struct mcast_conf *conf); void mcast_server_destroy(struct mcast_sock *m); +struct mcast_sock_multi *mcast_server_create_multi(struct mcast_conf *conf, int conf_len); +void mcast_server_destroy_multi(struct mcast_sock_multi *m); struct mcast_sock *mcast_client_create(struct mcast_conf *conf); void mcast_client_destroy(struct mcast_sock *m); +struct mcast_sock_multi *mcast_client_create_multi(struct mcast_conf *conf, int conf_len); +void mcast_client_destroy_multi(struct mcast_sock_multi*m); ssize_t mcast_send(struct mcast_sock *m, void *data, int size); ssize_t mcast_recv(struct mcast_sock *m, void *data, int size); -struct mcast_stats *mcast_get_stats(struct mcast_sock *m); -void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r); +int mcast_get_fd(struct mcast_sock *m); +int mcast_get_ifidx(struct mcast_sock_multi *m, int i); +int mcast_get_current_ifidx(struct mcast_sock_multi *m); + +struct mcast_sock *mcast_get_current_link(struct mcast_sock_multi *m); +void mcast_set_current_link(struct mcast_sock_multi *m, int i); + +void mcast_dump_stats(int fd, const struct mcast_sock_multi *s, const struct mcast_sock_multi *r); + +struct nlif_handle; +void mcast_dump_stats_extended(int fd, const struct mcast_sock_multi *s, const struct mcast_sock_multi *r, const struct nlif_handle *h); #endif diff --git a/include/netlink.h b/include/netlink.h index 5feb3e9..4bc5ee4 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -10,6 +10,7 @@ struct nfct_handle *nl_init_event_handler(void); struct nfct_handle *nl_init_dump_handler(void); struct nfct_handle *nl_init_request_handler(void); struct nfct_handle *nl_init_overrun_handler(void); +struct nlif_handle *nl_init_interface_handler(void); int nl_overrun_request_resync(struct nfct_handle *h); void nl_resize_socket_buffer(struct nfct_handle *h); diff --git a/include/network.h b/include/network.h index f02d920..740e762 100644 --- a/include/network.h +++ b/include/network.h @@ -76,7 +76,7 @@ enum { __hdr; \ }) -struct mcast_sock; +struct mcast_sock_multi; enum { SEQ_UNKNOWN, @@ -94,8 +94,8 @@ struct mcast_conf; int mcast_buffered_init(int mtu); void mcast_buffered_destroy(void); -int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net); -ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); +int mcast_buffered_send_netmsg(struct mcast_sock_multi *m, const struct nethdr *net); +ssize_t mcast_buffered_pending_netmsg(struct mcast_sock_multi *m); #define IS_DATA(x) (x->type <= NET_T_STATE_MAX && \ (x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) diff --git a/src/main.c b/src/main.c index 929b5c9..061a73e 100644 --- a/src/main.c +++ b/src/main.c @@ -43,7 +43,7 @@ static const char usage_client_commands[] = " -i, display content of the internal cache\n" " -e, display the content of the external cache\n" " -k, kill conntrack daemon\n" - " -s [|network|cache|runtime], dump statistics\n" + " -s [|network|cache|runtime|multicast], dump statistics\n" " -R, resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)\n" @@ -169,6 +169,10 @@ int main(int argc, char *argv[]) strlen(argv[i+1])) == 0) { action = STATS_RUNTIME; i++; + } else if (strncmp(argv[i+1], "multicast", + strlen(argv[i+1])) == 0) { + action = STATS_MULTICAST; + i++; } else { fprintf(stderr, "ERROR: unknown " "parameter `%s' for " diff --git a/src/mcast.c b/src/mcast.c index 2bb8743..70205d8 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -1,5 +1,5 @@ /* - * (C) 2006 by Pablo Neira Ayuso + * (C) 2006-2009 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 @@ -45,6 +45,8 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return NULL; memset(m, 0, sizeof(struct mcast_sock)); + m->interface_idx = conf->interface_idx; + switch(conf->ipproto) { case AF_INET: mreq.ipv4.imr_multiaddr.s_addr = conf->in.inet_addr.s_addr; @@ -147,12 +149,52 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return m; } +struct mcast_sock_multi * +mcast_server_create_multi(struct mcast_conf *conf, int conf_len) +{ + struct mcast_sock_multi *m; + int i, j; + + if (conf_len <= 0 || conf_len > MCAST_LINKS_MAX) + return NULL; + + m = calloc(sizeof(struct mcast_sock_multi), 1); + if (m == NULL) + return NULL; + + m->max_mtu = INT_MAX; + for (i=0; imulti[i] = mcast_server_create(&conf[i]); + if (m->multi[i] == NULL) { + for (j=0; jmulti[j]); + } + free(m); + return NULL; + } + if (m->max_mtu > conf[i].mtu) + m->max_mtu = conf[i].mtu; + } + m->num_links = conf_len; + + return m; +} + void mcast_server_destroy(struct mcast_sock *m) { close(m->fd); free(m); } +void mcast_server_destroy_multi(struct mcast_sock_multi *m) +{ + int i; + + for (i=0; inum_links; i++) + mcast_server_destroy(m->multi[i]); + free(m); +} + static int __mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) { @@ -222,6 +264,8 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) return NULL; memset(m, 0, sizeof(struct mcast_sock)); + m->interface_idx = conf->interface_idx; + if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { debug("mcast_sock_client_create:socket"); free(m); @@ -275,12 +319,52 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) return m; } +struct mcast_sock_multi * +mcast_client_create_multi(struct mcast_conf *conf, int conf_len) +{ + struct mcast_sock_multi *m; + int i, j; + + if (conf_len <= 0 || conf_len > MCAST_LINKS_MAX) + return NULL; + + m = calloc(sizeof(struct mcast_sock_multi), 1); + if (m == NULL) + return NULL; + + m->max_mtu = INT_MAX; + for (i=0; imulti[i] = mcast_client_create(&conf[i]); + if (m->multi[i] == NULL) { + for (j=0; jmulti[j]); + } + free(m); + return NULL; + } + if (m->max_mtu > conf[i].mtu) + m->max_mtu = conf[i].mtu; + } + m->num_links = conf_len; + + return m; +} + void mcast_client_destroy(struct mcast_sock *m) { close(m->fd); free(m); } +void mcast_client_destroy_multi(struct mcast_sock_multi *m) +{ + int i; + + for (i=0; inum_links; i++) + mcast_client_destroy(m->multi[i]); + free(m); +} + ssize_t mcast_send(struct mcast_sock *m, void *data, int size) { ssize_t ret; @@ -326,29 +410,140 @@ ssize_t mcast_recv(struct mcast_sock *m, void *data, int size) return ret; } -struct mcast_stats *mcast_get_stats(struct mcast_sock *m) +void mcast_set_current_link(struct mcast_sock_multi *m, int i) +{ + m->current_link = m->multi[i]; +} + +struct mcast_sock *mcast_get_current_link(struct mcast_sock_multi *m) +{ + return m->current_link; +} + +int mcast_get_fd(struct mcast_sock *m) +{ + return m->fd; +} + +int mcast_get_current_ifidx(struct mcast_sock_multi *m) { - return &m->stats; + return m->current_link->interface_idx; } -void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r) +int mcast_get_ifidx(struct mcast_sock_multi *m, int i) { - char buf[512]; + return m->multi[i]->interface_idx; +} + +static int +mcast_snprintf_stats(char *buf, size_t buflen, char *ifname, + struct mcast_stats *s, struct mcast_stats *r) +{ + size_t size; + + size = snprintf(buf, buflen, "multicast traffic (active device=%s):\n" + "%20llu Bytes sent " + "%20llu Bytes recv\n" + "%20llu Pckts sent " + "%20llu Pckts recv\n" + "%20llu Error send " + "%20llu Error recv\n\n", + ifname, + (unsigned long long)s->bytes, + (unsigned long long)r->bytes, + (unsigned long long)s->messages, + (unsigned long long)r->messages, + (unsigned long long)s->error, + (unsigned long long)r->error); + return size; +} + +static int +mcast_snprintf_stats2(char *buf, size_t buflen, const char *ifname, + const char *status, int active, + struct mcast_stats *s, struct mcast_stats *r) +{ + size_t size; + + size = snprintf(buf, buflen, + "multicast traffic device=%s status=%s role=%s:\n" + "%20llu Bytes sent " + "%20llu Bytes recv\n" + "%20llu Pckts sent " + "%20llu Pckts recv\n" + "%20llu Error send " + "%20llu Error recv\n\n", + ifname, status, active ? "ACTIVE" : "BACKUP", + (unsigned long long)s->bytes, + (unsigned long long)r->bytes, + (unsigned long long)s->messages, + (unsigned long long)r->messages, + (unsigned long long)s->error, + (unsigned long long)r->error); + return size; +} + +void +mcast_dump_stats(int fd, + const struct mcast_sock_multi *s, + const struct mcast_sock_multi *r) +{ + int i; + struct mcast_stats snd = { 0, 0, 0}; + struct mcast_stats rcv = { 0, 0, 0}; + char ifname[IFNAMSIZ], buf[512]; int size; - size = sprintf(buf, "multicast traffic:\n" - "%20llu Bytes sent " - "%20llu Bytes recv\n" - "%20llu Pckts sent " - "%20llu Pckts recv\n" - "%20llu Error send " - "%20llu Error recv\n\n", - (unsigned long long)s->stats.bytes, - (unsigned long long)r->stats.bytes, - (unsigned long long)s->stats.messages, - (unsigned long long)r->stats.messages, - (unsigned long long)s->stats.error, - (unsigned long long)r->stats.error); + /* it is the same for the receiver, no need to do it twice */ + if_indextoname(s->current_link->interface_idx, ifname); + + for (i=0; inum_links && inum_links; i++) { + snd.bytes += s->multi[i]->stats.bytes; + snd.messages += s->multi[i]->stats.messages; + snd.error += s->multi[i]->stats.error; + rcv.bytes += r->multi[i]->stats.bytes; + rcv.messages += r->multi[i]->stats.messages; + rcv.error += r->multi[i]->stats.error; + } + size = mcast_snprintf_stats(buf, sizeof(buf), ifname, &snd, &rcv); + send(fd, buf, size, 0); +} +void +mcast_dump_stats_extended(int fd, + const struct mcast_sock_multi *s, + const struct mcast_sock_multi *r, + const struct nlif_handle *h) +{ + int i; + char buf[4096]; + int size = 0; + + for (i=0; inum_links && inum_links; i++) { + int idx = s->multi[i]->interface_idx, active; + unsigned int flags; + char ifname[IFNAMSIZ]; + const char *status; + + if_indextoname(idx, ifname); + nlif_get_ifflags(h, idx, &flags); + active = (s->multi[i] == s->current_link); + /* + * IFF_UP shows administrative status + * IFF_RUNNING shows carrier status + */ + if (flags & IFF_UP) { + if (!(flags & IFF_RUNNING)) + status = "NO-CARRIER"; + else + status = "RUNNING"; + } else { + status = "DOWN"; + } + size += mcast_snprintf_stats2(buf+size, sizeof(buf), + ifname, status, active, + &s->multi[i]->stats, + &r->multi[i]->stats); + } send(fd, buf, size, 0); } diff --git a/src/netlink.c b/src/netlink.c index 92fbf00..2266201 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -114,6 +114,22 @@ struct nfct_handle *nl_init_request_handler(void) return h; } +struct nlif_handle *nl_init_interface_handler(void) +{ + struct nlif_handle *h; + h = nlif_open(); + if (h == NULL) + return NULL; + + if (nlif_query(h) == -1) { + free(h); + return NULL; + } + fcntl(nlif_fd(h), F_SETFL, O_NONBLOCK); + + return h; +} + static int warned = 0; void nl_resize_socket_buffer(struct nfct_handle *h) diff --git a/src/network.c b/src/network.c index 7a106b1..f71aef0 100644 --- a/src/network.c +++ b/src/network.c @@ -95,7 +95,8 @@ void mcast_buffered_destroy(void) } /* return 0 if it is not sent, otherwise return 1 */ -int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net) +int +mcast_buffered_send_netmsg(struct mcast_sock_multi *m, const struct nethdr *net) { int ret = 0, len = ntohs(net->len); @@ -104,7 +105,7 @@ retry: memcpy(tx_buf + tx_buflen, net, len); tx_buflen += len; } else { - mcast_send(m, tx_buf, tx_buflen); + mcast_send(mcast_get_current_link(m), tx_buf, tx_buflen); ret = 1; tx_buflen = 0; goto retry; @@ -113,14 +114,14 @@ retry: return ret; } -ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m) +ssize_t mcast_buffered_pending_netmsg(struct mcast_sock_multi *m) { ssize_t ret; if (tx_buflen == 0) return 0; - ret = mcast_send(m, tx_buf, tx_buflen); + ret = mcast_send(mcast_get_current_link(m), tx_buf, tx_buflen); tx_buflen = 0; return ret; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index f8b0ba1..e9e5d43 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -118,6 +118,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "Userspace" { return T_USERSPACE; } "Kernelspace" { return T_KERNELSPACE; } "EventIterationLimit" { return T_EVENT_ITER_LIMIT; } +"Default" { return T_DEFAULT; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 274bfc3..de6cef3 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -38,6 +38,7 @@ struct ct_conf conf; static void __kernel_filter_start(void); static void __kernel_filter_add_state(int value); +static void __max_mcast_dedicated_links_reached(void); %} %union { @@ -59,7 +60,7 @@ static void __kernel_filter_add_state(int value); %token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT %token T_MCAST_RCVBUFF T_MCAST_SNDBUFF T_NOTRACK %token T_FILTER T_ADDRESS T_PROTOCOL T_STATE T_ACCEPT T_IGNORE -%token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT +%token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT %token T_IP T_PATH_VAL %token T_NUMBER @@ -174,14 +175,22 @@ checksum: T_CHECKSUM T_ON { fprintf(stderr, "WARNING: The use of `Checksum' outside the " "`Multicast' clause is ambiguous.\n"); - conf.mcast.checksum = 0; + /* + * XXX: The use of Checksum outside of the Multicast clause is broken + * if we have more than one dedicated links. + */ + conf.mcast[0].checksum = 0; }; checksum: T_CHECKSUM T_OFF { fprintf(stderr, "WARNING: The use of `Checksum' outside the " "`Multicast' clause is ambiguous.\n"); - conf.mcast.checksum = 1; + /* + * XXX: The use of Checksum outside of the Multicast clause is broken + * if we have more than one dedicated links. + */ + conf.mcast[0].checksum = 1; }; ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}' @@ -243,32 +252,45 @@ ignore_traffic_option : T_IPV6_ADDR T_IP }; -multicast_line : T_MULTICAST '{' multicast_options '}'; +multicast_line : T_MULTICAST '{' multicast_options '}' +{ + conf.mcast_links++; +}; + +multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}' +{ + conf.mcast_default_link = conf.mcast_links; + conf.mcast_links++; +}; multicast_options : | multicast_options multicast_option; multicast_option : T_IPV4_ADDR T_IP { - if (!inet_aton($2, &conf.mcast.in)) { + __max_mcast_dedicated_links_reached(); + + if (!inet_aton($2, &conf.mcast[conf.mcast_links].in)) { fprintf(stderr, "%s is not a valid IPv4 address\n", $2); break; } - if (conf.mcast.ipproto == AF_INET6) { + if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { fprintf(stderr, "Your multicast address is IPv4 but " "is binded to an IPv6 interface? Surely " "this is not what you want\n"); break; } - conf.mcast.ipproto = AF_INET; + conf.mcast[conf.mcast_links].ipproto = AF_INET; }; multicast_option : T_IPV6_ADDR T_IP { + __max_mcast_dedicated_links_reached(); + #ifdef HAVE_INET_PTON_IPV6 - if (inet_pton(AF_INET6, $2, &conf.mcast.in) <= 0) { + if (inet_pton(AF_INET6, $2, &conf.mcast[conf.mcast_links].in) <= 0) { fprintf(stderr, "%s is not a valid IPv6 address\n", $2); break; } @@ -277,16 +299,17 @@ multicast_option : T_IPV6_ADDR T_IP break; #endif - if (conf.mcast.ipproto == AF_INET) { + if (conf.mcast[conf.mcast_links].ipproto == AF_INET) { fprintf(stderr, "Your multicast address is IPv6 but " "is binded to an IPv4 interface? Surely " "this is not what you want\n"); break; } - conf.mcast.ipproto = AF_INET6; + conf.mcast[conf.mcast_links].ipproto = AF_INET6; - if (conf.mcast.iface[0] && !conf.mcast.ifa.interface_index6) { + if (conf.mcast[conf.mcast_links].iface[0] && + !conf.mcast[conf.mcast_links].ifa.interface_index6) { unsigned int idx; idx = if_nametoindex($2); @@ -295,26 +318,28 @@ multicast_option : T_IPV6_ADDR T_IP break; } - conf.mcast.ifa.interface_index6 = idx; - conf.mcast.ipproto = AF_INET6; + conf.mcast[conf.mcast_links].ifa.interface_index6 = idx; + conf.mcast[conf.mcast_links].ipproto = AF_INET6; } }; multicast_option : T_IPV4_IFACE T_IP { - if (!inet_aton($2, &conf.mcast.ifa)) { + __max_mcast_dedicated_links_reached(); + + if (!inet_aton($2, &conf.mcast[conf.mcast_links].ifa)) { fprintf(stderr, "%s is not a valid IPv4 address\n", $2); break; } - if (conf.mcast.ipproto == AF_INET6) { + if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { fprintf(stderr, "Your multicast interface is IPv4 but " "is binded to an IPv6 interface? Surely " "this is not what you want\n"); break; } - conf.mcast.ipproto = AF_INET; + conf.mcast[conf.mcast_links].ipproto = AF_INET; }; multicast_option : T_IPV6_IFACE T_IP @@ -324,19 +349,22 @@ multicast_option : T_IPV6_IFACE T_IP multicast_option : T_IFACE T_STRING { - strncpy(conf.mcast.iface, $2, IFNAMSIZ); + unsigned int idx; - if (conf.mcast.ipproto == AF_INET6) { - unsigned int idx; + __max_mcast_dedicated_links_reached(); - idx = if_nametoindex($2); - if (!idx) { - fprintf(stderr, "%s is an invalid interface.\n", $2); - break; - } + strncpy(conf.mcast[conf.mcast_links].iface, $2, IFNAMSIZ); + + idx = if_nametoindex($2); + if (!idx) { + fprintf(stderr, "%s is an invalid interface.\n", $2); + break; + } + conf.mcast[conf.mcast_links].interface_idx = idx; - conf.mcast.ifa.interface_index6 = idx; - conf.mcast.ipproto = AF_INET6; + if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { + conf.mcast[conf.mcast_links].ifa.interface_index6 = idx; + conf.mcast[conf.mcast_links].ipproto = AF_INET6; } }; @@ -348,27 +376,32 @@ multicast_option : T_BACKLOG T_NUMBER multicast_option : T_GROUP T_NUMBER { - conf.mcast.port = $2; + __max_mcast_dedicated_links_reached(); + conf.mcast[conf.mcast_links].port = $2; }; multicast_option: T_MCAST_SNDBUFF T_NUMBER { - conf.mcast.sndbuf = $2; + __max_mcast_dedicated_links_reached(); + conf.mcast[conf.mcast_links].sndbuf = $2; }; multicast_option: T_MCAST_RCVBUFF T_NUMBER { - conf.mcast.rcvbuf = $2; + __max_mcast_dedicated_links_reached(); + conf.mcast[conf.mcast_links].rcvbuf = $2; }; multicast_option: T_CHECKSUM T_ON { - conf.mcast.checksum = 0; + __max_mcast_dedicated_links_reached(); + conf.mcast[conf.mcast_links].checksum = 0; }; multicast_option: T_CHECKSUM T_OFF { - conf.mcast.checksum = 1; + __max_mcast_dedicated_links_reached(); + conf.mcast[conf.mcast_links].checksum = 1; }; hashsize : T_HASHSIZE T_NUMBER @@ -1050,6 +1083,16 @@ static void __kernel_filter_add_state(int value) &filter_proto); } +static void __max_mcast_dedicated_links_reached(void) +{ + if (conf.mcast_links >= MCAST_LINKS_MAX) { + fprintf(stderr, "ERROR: too many dedicated links in " + "the configuration file (Maximum: %d).\n", + MCAST_LINKS_MAX); + exit(EXIT_FAILURE); + } +} + int init_config(char *filename) { diff --git a/src/sync-mode.c b/src/sync-mode.c index 00e2f7b..0dbd12d 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -33,8 +33,10 @@ #include #include #include +#include -static void do_mcast_handler_step(struct nethdr *net, size_t remain) +static void +do_mcast_handler_step(int if_idx, struct nethdr *net, size_t remain) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; @@ -47,6 +49,9 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) return; } + if (if_idx != mcast_get_current_ifidx(STATE_SYNC(mcast_client))) + mcast_set_current_link(STATE_SYNC(mcast_client), if_idx); + switch (STATE_SYNC(sync)->recv(net)) { case MSG_DATA: break; @@ -111,13 +116,13 @@ retry: } /* handler for multicast messages received */ -static void mcast_handler(void) +static void mcast_handler(struct mcast_sock *m, int if_idx) { ssize_t numbytes; ssize_t remain; char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ - numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net)); + numbytes = mcast_recv(m, __net, sizeof(__net)); if (numbytes <= 0) return; @@ -160,12 +165,46 @@ static void mcast_handler(void) HDR_NETWORK2HOST(net); - do_mcast_handler_step(net, remain); + do_mcast_handler_step(if_idx, net, remain); ptr += net->len; remain -= net->len; } } +/* select a new interface candidate in a round robin basis */ +static void mcast_iface_candidate(void) +{ + int i, idx; + unsigned int flags; + char buf[IFNAMSIZ]; + + for (i=0; inum_links; i++) { + idx = mcast_get_ifidx(STATE_SYNC(mcast_client), i); + if (idx == mcast_get_current_ifidx(STATE_SYNC(mcast_client))) + continue; + nlif_get_ifflags(STATE_SYNC(mcast_iface), idx, &flags); + if (flags & (IFF_RUNNING | IFF_UP)) { + mcast_set_current_link(STATE_SYNC(mcast_client), i); + dlog(LOG_NOTICE, "device `%s' becomes multicast " + "dedicated link", + if_indextoname(idx, buf)); + return; + } + } + dlog(LOG_ERR, "no dedicated links available!"); +} + +static void mcast_iface_handler(void) +{ + int idx = mcast_get_current_ifidx(STATE_SYNC(mcast_client)); + unsigned int flags; + + nlif_catch(STATE_SYNC(mcast_iface)); + nlif_get_ifflags(STATE_SYNC(mcast_iface), idx, &flags); + if (!(flags & IFF_RUNNING) || !(flags & IFF_UP)) + mcast_iface_candidate(); +} + static int init_sync(void) { state.sync = malloc(sizeof(struct ct_sync_state)); @@ -216,30 +255,35 @@ static int init_sync(void) } /* multicast server to receive events from the wire */ - STATE_SYNC(mcast_server) = mcast_server_create(&CONFIG(mcast)); + STATE_SYNC(mcast_server) = + mcast_server_create_multi(CONFIG(mcast), CONFIG(mcast_links)); if (STATE_SYNC(mcast_server) == NULL) { dlog(LOG_ERR, "can't open multicast server!"); return -1; } - dlog(LOG_NOTICE, "multicast server socket receiver queue " - "has been set to %d bytes", CONFIG(mcast).rcvbuf); - /* multicast client to send events on the wire */ - STATE_SYNC(mcast_client) = mcast_client_create(&CONFIG(mcast)); + STATE_SYNC(mcast_client) = + mcast_client_create_multi(CONFIG(mcast), CONFIG(mcast_links)); if (STATE_SYNC(mcast_client) == NULL) { dlog(LOG_ERR, "can't open client multicast socket"); - mcast_server_destroy(STATE_SYNC(mcast_server)); + mcast_server_destroy_multi(STATE_SYNC(mcast_server)); return -1; } + /* we only use one link to send events, but all to receive them */ + mcast_set_current_link(STATE_SYNC(mcast_client), + CONFIG(mcast_default_link)); - dlog(LOG_NOTICE, "multicast client socket sender queue " - "has been set to %d bytes", CONFIG(mcast).sndbuf); - - if (mcast_buffered_init(CONFIG(mcast).mtu) == -1) { + if (mcast_buffered_init(STATE_SYNC(mcast_client)->max_mtu) == -1) { dlog(LOG_ERR, "can't init tx buffer!"); - mcast_server_destroy(STATE_SYNC(mcast_server)); - mcast_client_destroy(STATE_SYNC(mcast_client)); + mcast_server_destroy_multi(STATE_SYNC(mcast_server)); + mcast_client_destroy_multi(STATE_SYNC(mcast_client)); + return -1; + } + + STATE_SYNC(mcast_iface) = nl_init_interface_handler(); + if (!STATE_SYNC(mcast_iface)) { + dlog(LOG_ERR, "can't open interface watcher"); return -1; } @@ -257,7 +301,14 @@ static int init_sync(void) static int register_fds_sync(struct fds *fds) { - if (register_fd(STATE_SYNC(mcast_server->fd), fds) == -1) + int i; + + for (i=0; inum_links; i++) { + int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]); + if (register_fd(fd, fds) == -1) + return -1; + } + if (register_fd(nlif_fd(STATE_SYNC(mcast_iface)), fds) == -1) return -1; if (register_fd(queue_get_eventfd(STATE_SYNC(tx_queue)), fds) == -1) @@ -268,13 +319,20 @@ static int register_fds_sync(struct fds *fds) static void run_sync(fd_set *readfds) { - /* multicast packet has been received */ - if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) - mcast_handler(); + int i; + + for (i=0; inum_links; i++) { + int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]); + if (FD_ISSET(fd, readfds)) + mcast_handler(STATE_SYNC(mcast_server)->multi[i], i); + } if (FD_ISSET(queue_get_eventfd(STATE_SYNC(tx_queue)), readfds)) STATE_SYNC(sync)->xmit(); + if (FD_ISSET(nlif_fd(STATE_SYNC(mcast_iface)), readfds)) + mcast_iface_handler(); + /* flush pending messages */ mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); } @@ -284,8 +342,10 @@ static void kill_sync(void) cache_destroy(STATE_SYNC(internal)); cache_destroy(STATE_SYNC(external)); - mcast_server_destroy(STATE_SYNC(mcast_server)); - mcast_client_destroy(STATE_SYNC(mcast_client)); + mcast_server_destroy_multi(STATE_SYNC(mcast_server)); + mcast_client_destroy_multi(STATE_SYNC(mcast_client)); + + nlif_close(STATE_SYNC(mcast_iface)); mcast_buffered_destroy(); queue_destroy(STATE_SYNC(tx_queue)); @@ -418,6 +478,11 @@ static int local_handler_sync(int fd, int type, void *data) cache_stats_extended(STATE_SYNC(internal), fd); cache_stats_extended(STATE_SYNC(external), fd); break; + case STATS_MULTICAST: + mcast_dump_stats_extended(fd, STATE_SYNC(mcast_client), + STATE_SYNC(mcast_server), + STATE_SYNC(mcast_iface)); + break; default: if (STATE_SYNC(sync)->local) ret = STATE_SYNC(sync)->local(fd, type, data); -- cgit v1.2.3 From 50c09dec9ad0261d8fcc18d69b2c9ec74052955c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 Jan 2009 17:53:05 +0100 Subject: src: add support for approximate timeout calculation during commit During the commit phase, the entries in the external cache entries are inserted in the kernel conntrack table. Currently, we use a fixed timeout that is specified in the config file. With this patch, if you don't specify the fixed timeout value via CommitTimeout, the daemon calculates the real timeout value during the commit phase. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 1 + include/network.h | 2 +- src/build.c | 3 +++ src/cache.c | 3 ++- src/cache_iterators.c | 22 ++++++++++++++++++++-- src/read_config_yy.y | 4 ---- 6 files changed, 27 insertions(+), 8 deletions(-) (limited to 'include/network.h') diff --git a/include/cache.h b/include/cache.h index 1fd3881..371170d 100644 --- a/include/cache.h +++ b/include/cache.h @@ -34,6 +34,7 @@ struct cache_object { int status; int refcnt; long lifetime; + long lastupdate; char data[0]; }; diff --git a/include/network.h b/include/network.h index 740e762..7cfaf84 100644 --- a/include/network.h +++ b/include/network.h @@ -192,7 +192,7 @@ enum nta_attr { NTA_PORT, /* struct nfct_attr_grp_port */ NTA_STATE = 4, /* uint8_t */ NTA_STATUS, /* uint32_t */ - NTA_TIMEOUT, /* uint32_t -- unused */ + NTA_TIMEOUT, /* uint32_t */ NTA_MARK, /* uint32_t */ NTA_MASTER_IPV4 = 8, /* struct nfct_attr_grp_ipv4 */ NTA_MASTER_IPV6, /* struct nfct_attr_grp_ipv6 */ diff --git a/src/build.c b/src/build.c index e094aa0..63a85db 100644 --- a/src/build.c +++ b/src/build.c @@ -19,6 +19,7 @@ #include #include #include "network.h" +#include "conntrackd.h" static inline void * put_header(struct nethdr *n, int attr, size_t len) @@ -117,6 +118,8 @@ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) __build_u8(ct, ATTR_TCP_STATE, n, NTA_STATE); + if (!CONFIG(commit_timeout) && nfct_attr_is_set(ct, ATTR_TIMEOUT)) + __build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) __build_u32(ct, ATTR_MARK, n, NTA_MARK); diff --git a/src/cache.c b/src/cache.c index 71825e1..318b8ec 100644 --- a/src/cache.c +++ b/src/cache.c @@ -249,7 +249,7 @@ static int __add(struct cache *c, struct cache_object *obj, int id) c->extra->add(obj, ((char *) obj) + c->extra_offset); c->stats.active++; - obj->lifetime = time(NULL); + obj->lifetime = obj->lastupdate = time(NULL); obj->status = C_OBJ_NEW; obj->refcnt++; return 0; @@ -287,6 +287,7 @@ void cache_update(struct cache *c, struct cache_object *obj, int id, c->extra->update(obj, ((char *) obj) + c->extra_offset); c->stats.upd_ok++; + obj->lastupdate = time(NULL); obj->status = C_OBJ_ALIVE; } diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 3a1ec72..e16a621 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -108,11 +108,29 @@ struct __commit_container { static void __do_commit_step(struct __commit_container *tmp, struct cache_object *obj) { - int ret, retry = 1; + int ret, retry = 1, timeout; struct nf_conntrack *ct = obj->ct; + if (CONFIG(commit_timeout)) { + timeout = CONFIG(commit_timeout); + } else { + timeout = time(NULL) - obj->lastupdate; + if (timeout < 0) { + /* XXX: Arbitrarily set the timer to one minute, how + * can this happen? For example, an adjustment due to + * daylight-saving. Probably other situations can + * trigger this. */ + timeout = 60; + } + /* calculate an estimation of the current timeout */ + timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT) - timeout; + if (timeout < 0) { + timeout = 60; + } + } + retry: - if (nl_create_conntrack(tmp->h, ct, CONFIG(commit_timeout)) == -1) { + if (nl_create_conntrack(tmp->h, ct, timeout) == -1) { if (errno == EEXIST && retry == 1) { ret = nl_destroy_conntrack(tmp->h, ct); if (ret == 0 || (ret == -1 && errno == ENOENT)) { diff --git a/src/read_config_yy.y b/src/read_config_yy.y index d71829f..766d543 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -1141,10 +1141,6 @@ init_config(char *filename) if (CONFIG(cache_timeout) == 0) CONFIG(cache_timeout) = 180; - /* default to 180 seconds: committed entries */ - if (CONFIG(commit_timeout) == 0) - CONFIG(commit_timeout) = 180; - /* default to 15 seconds: purge kernel entries */ if (CONFIG(purge_timeout) == 0) CONFIG(purge_timeout) = 15; -- cgit v1.2.3 From e31823d42a9591021bf5bbe818b530133eb437da Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 20 Feb 2009 19:51:22 +0100 Subject: network: fix endianess issue in synchronization network header This patch fixes an endianess issue in the synchronization network header. This breaks backward compatibility if different conntrackd versions are used. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 7cfaf84..3cf2cad 100644 --- a/include/network.h +++ b/include/network.h @@ -9,8 +9,15 @@ struct nf_conntrack; struct nethdr { +#if __BYTE_ORDER == __LITTLE_ENDIAN + uint8_t type:4, + version:4; +#elif __BYTE_ORDER == __BIG_ENDIAN uint8_t version:4, type:4; +#else +#error "Unknown system endianess!" +#endif uint8_t flags; uint16_t len; uint32_t seq; -- cgit v1.2.3 From 1c8002a2de8cfc2ff9d624099d5154bcd77e2f37 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 20 Feb 2009 20:06:22 +0100 Subject: network: fix endianess issue in acknowledgment network header This patch fixes an endianess issue in the acknowledgment network header. This breaks backward compatibility if different conntrackd versions are used. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 3cf2cad..29a6113 100644 --- a/include/network.h +++ b/include/network.h @@ -45,8 +45,15 @@ int object_status_to_network_type(int status); (struct netattr *)(((char *)x) + x->len) struct nethdr_ack { +#if __BYTE_ORDER == __LITTLE_ENDIAN + uint8_t type:4, + version:4; +#elif __BYTE_ORDER == __BIG_ENDIAN uint8_t version:4, type:4; +#else +#error "Unknown system endianess!" +#endif uint8_t flags; uint16_t len; uint32_t seq; -- cgit v1.2.3 From 656d5ad7c69a5a7d356c6251743890f1eec0bb71 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 12 Mar 2009 21:09:27 +0100 Subject: sync-mode: add abstract layer to make daemon independent of multicast This patch reworks conntrackd to make it independent of the protocol used to propagate state-changes. This patch adds the channel layer abstraction, this layer allows you to add support for different protocols like unicast UDP or TIPC. Signed-off-by: Pablo Neira Ayuso --- include/Makefile.am | 2 +- include/channel.h | 95 +++++++++++++++++++++++++++ include/conntrackd.h | 10 +-- include/mcast.h | 26 ++------ include/network.h | 5 -- src/Makefile.am | 1 + src/channel.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/channel_mcast.c | 123 +++++++++++++++++++++++++++++++++++ src/mcast.c | 169 +---------------------------------------------- src/multichannel.c | 110 +++++++++++++++++++++++++++++++ src/network.c | 61 ----------------- src/read_config_yy.y | 69 +++++++++++--------- src/sync-alarm.c | 4 +- src/sync-ftfw.c | 4 +- src/sync-mode.c | 82 +++++++++-------------- src/sync-notrack.c | 4 +- 16 files changed, 596 insertions(+), 349 deletions(-) create mode 100644 include/channel.h create mode 100644 src/channel.c create mode 100644 src/channel_mcast.c create mode 100644 src/multichannel.c (limited to 'include/network.h') diff --git a/include/Makefile.am b/include/Makefile.am index c3f8904..0265620 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -3,5 +3,5 @@ noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ sync.h conntrackd.h local.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ - traffic_stats.h netlink.h fds.h event.h bitops.h + traffic_stats.h netlink.h fds.h event.h bitops.h channel.h diff --git a/include/channel.h b/include/channel.h new file mode 100644 index 0000000..ac1a93c --- /dev/null +++ b/include/channel.h @@ -0,0 +1,95 @@ +#ifndef _CHANNEL_H_ +#define _CHANNEL_H_ + +#include "mcast.h" + +struct channel; +struct nethdr; + +enum { + CHANNEL_MCAST, + CHANNEL_MAX, +}; + +struct mcast_channel { + struct mcast_sock *client; + struct mcast_sock *server; +}; + +#define CHANNEL_F_DEFAULT (1 << 0) +#define CHANNEL_F_BUFFERED (1 << 1) +#define CHANNEL_F_MAX (1 << 2) + +union channel_type_conf { + struct mcast_conf mcast; +}; + +struct channel_conf { + int channel_type; + char channel_ifname[IFNAMSIZ]; + unsigned int channel_flags; + union channel_type_conf u; +}; + +struct nlif_handle; + +struct channel_ops { + void * (*open)(void *conf); + void (*close)(void *channel); + int (*send)(void *channel, const void *data, int len); + int (*recv)(void *channel, char *buf, int len); + int (*get_fd)(void *channel); + void (*stats)(struct channel *c, int fd); + void (*stats_extended)(struct channel *c, int active, + struct nlif_handle *h, int fd); +}; + +struct channel_buffer; + +struct channel { + int channel_type; + int channel_ifindex; + int channel_ifmtu; + unsigned int channel_flags; + struct channel_buffer *buffer; + struct channel_ops *ops; + void *data; +}; + +void channel_init(void); +struct channel *channel_open(struct channel_conf *conf); +void channel_close(struct channel *c); + +int channel_send(struct channel *c, const struct nethdr *net); +int channel_send_flush(struct channel *c); +int channel_recv(struct channel *c, char *buf, int size); + +int channel_get_fd(struct channel *c); +void channel_stats(struct channel *c, int fd); +void channel_stats_extended(struct channel *c, int active, + struct nlif_handle *h, int fd); + +#define MULTICHANNEL_MAX 4 + +struct multichannel { + int channel_num; + struct channel *channel[MULTICHANNEL_MAX]; + struct channel *current; +}; + +struct multichannel *multichannel_open(struct channel_conf *conf, int len); +void multichannel_close(struct multichannel *m); + +int multichannel_send(struct multichannel *c, const struct nethdr *net); +int multichannel_send_flush(struct multichannel *c); +int multichannel_recv(struct multichannel *c, char *buf, int size); + +void multichannel_stats(struct multichannel *m, int fd); +void multichannel_stats_extended(struct multichannel *m, + struct nlif_handle *h, int fd); + +int multichannel_get_ifindex(struct multichannel *m, int i); +int multichannel_get_current_ifindex(struct multichannel *m); +void multichannel_set_current_channel(struct multichannel *m, int i); + +#endif /* _CHANNEL_H_ */ diff --git a/include/conntrackd.h b/include/conntrackd.h index 536abc9..cfb1ac5 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -5,6 +5,7 @@ #include "local.h" #include "alarm.h" #include "filter.h" +#include "channel.h" #include #include @@ -71,9 +72,9 @@ struct ct_conf { int syslog_facility; char lockfile[FILENAME_MAXLEN]; int hashsize; /* hashtable size */ - int mcast_links; - int mcast_default_link; - struct mcast_conf mcast[MCAST_LINKS_MAX]; + int channel_num; + int channel_default; + struct channel_conf channel[MULTICHANNEL_MAX]; struct local_conf local; /* unix socket facilities */ int nice; int limit; @@ -163,8 +164,7 @@ struct ct_sync_state { struct cache *internal; /* internal events cache (netlink) */ struct cache *external; /* external events cache (mcast) */ - struct mcast_sock_multi *mcast_server; /* multicast incoming */ - struct mcast_sock_multi *mcast_client; /* multicast outgoing */ + struct multichannel *channel; struct nlif_handle *interface; struct queue *tx_queue; diff --git a/include/mcast.h b/include/mcast.h index 623f390..68d18e8 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -42,38 +42,22 @@ struct mcast_sock { struct mcast_stats stats; }; -#define MCAST_LINKS_MAX 4 - -struct mcast_sock_multi { - int num_links; - int max_mtu; - struct mcast_sock *current_link; - struct mcast_sock *multi[MCAST_LINKS_MAX]; -}; - struct mcast_sock *mcast_server_create(struct mcast_conf *conf); void mcast_server_destroy(struct mcast_sock *m); -struct mcast_sock_multi *mcast_server_create_multi(struct mcast_conf *conf, int conf_len); -void mcast_server_destroy_multi(struct mcast_sock_multi *m); struct mcast_sock *mcast_client_create(struct mcast_conf *conf); void mcast_client_destroy(struct mcast_sock *m); -struct mcast_sock_multi *mcast_client_create_multi(struct mcast_conf *conf, int conf_len); -void mcast_client_destroy_multi(struct mcast_sock_multi*m); ssize_t mcast_send(struct mcast_sock *m, void *data, int size); ssize_t mcast_recv(struct mcast_sock *m, void *data, int size); int mcast_get_fd(struct mcast_sock *m); -int mcast_get_ifidx(struct mcast_sock_multi *m, int i); -int mcast_get_current_ifidx(struct mcast_sock_multi *m); - -struct mcast_sock *mcast_get_current_link(struct mcast_sock_multi *m); -void mcast_set_current_link(struct mcast_sock_multi *m, int i); -void mcast_dump_stats(int fd, const struct mcast_sock_multi *s, const struct mcast_sock_multi *r); +int mcast_snprintf_stats(char *buf, size_t buflen, char *ifname, + struct mcast_stats *s, struct mcast_stats *r); -struct nlif_handle; +int mcast_snprintf_stats2(char *buf, size_t buflen, const char *ifname, + const char *status, int active, + struct mcast_stats *s, struct mcast_stats *r); -void mcast_dump_stats_extended(int fd, const struct mcast_sock_multi *s, const struct mcast_sock_multi *r, const struct nlif_handle *h); #endif diff --git a/include/network.h b/include/network.h index 29a6113..7019d7d 100644 --- a/include/network.h +++ b/include/network.h @@ -106,11 +106,6 @@ int mcast_track_is_seq_set(void); struct mcast_conf; -int mcast_buffered_init(int mtu); -void mcast_buffered_destroy(void); -int mcast_buffered_send_netmsg(struct mcast_sock_multi *m, const struct nethdr *net); -ssize_t mcast_buffered_pending_netmsg(struct mcast_sock_multi *m); - #define IS_DATA(x) (x->type <= NET_T_STATE_MAX && \ (x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) #define IS_ACK(x) (x->type == NET_T_CTL && x->flags & NET_F_ACK) diff --git a/src/Makefile.am b/src/Makefile.am index 8ba09e1..54cfda4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,6 +19,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ traffic_stats.c stats-mode.c \ network.c cidr.c \ build.c parse.c \ + channel.c multichannel.c channel_mcast.c \ read_config_yy.y read_config_lex.l # yacc and lex generate dirty code diff --git a/src/channel.c b/src/channel.c new file mode 100644 index 0000000..733fd03 --- /dev/null +++ b/src/channel.c @@ -0,0 +1,180 @@ +/* + * (C) 2009 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include "channel.h" +#include "network.h" + +static struct channel_ops *ops[CHANNEL_MAX]; +extern struct channel_ops channel_mcast; + +void channel_init(void) +{ + ops[CHANNEL_MCAST] = &channel_mcast; +} + +#define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ + +struct channel_buffer { + char *data; + int size; + int len; +}; + +static struct channel_buffer * +channel_buffer_open(int mtu) +{ + struct channel_buffer *b; + + b = calloc(sizeof(struct channel_buffer), 1); + if (b == NULL) + return NULL; + + b->size = mtu - HEADERSIZ; + + b->data = malloc(b->size); + if (b->data == NULL) { + free(b); + return NULL; + } + return b; +} + +static void +channel_buffer_close(struct channel_buffer *b) +{ + free(b->data); + free(b); +} + +struct channel * +channel_open(struct channel_conf *conf) +{ + struct channel *c; + struct ifreq ifr; + int fd; + + if (conf->channel_type >= CHANNEL_MAX) + return NULL; + if (!conf->channel_ifname[0]) + return NULL; + if (conf->channel_flags >= CHANNEL_F_MAX) + return NULL; + + c = calloc(sizeof(struct channel), 1); + if (c == NULL) + return NULL; + + c->channel_type = conf->channel_type; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + free(c); + return NULL; + } + strncpy(ifr.ifr_name, conf->channel_ifname, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) { + free(c); + return NULL; + } + close(fd); + c->channel_ifmtu = ifr.ifr_mtu; + + c->channel_ifindex = if_nametoindex(conf->channel_ifname); + if (c->channel_ifindex == 0) { + free(c); + return NULL; + } + c->ops = ops[conf->channel_type]; + + if (conf->channel_flags & CHANNEL_F_BUFFERED) { + c->buffer = channel_buffer_open(c->channel_ifmtu); + if (c->buffer == NULL) { + free(c); + return NULL; + } + } + c->channel_flags = conf->channel_flags; + + c->data = c->ops->open(&conf->u); + if (c->data == NULL) { + channel_buffer_close(c->buffer); + free(c); + return NULL; + } + return c; +} + +void +channel_close(struct channel *c) +{ + c->ops->close(c->data); + if (c->channel_flags & CHANNEL_F_BUFFERED) + channel_buffer_close(c->buffer); + free(c); +} + +int channel_send(struct channel *c, const struct nethdr *net) +{ + int ret = 0, len = ntohs(net->len); + + if (!(c->channel_flags & CHANNEL_F_BUFFERED)) { + c->ops->send(c->data, net, len); + return 1; + } +retry: + if (c->buffer->len + len < c->buffer->size) { + memcpy(c->buffer->data + c->buffer->len, net, len); + c->buffer->len += len; + } else { + c->ops->send(c->data, c->buffer->data, c->buffer->len); + ret = 1; + c->buffer->len = 0; + goto retry; + } + return ret; +} + +int channel_send_flush(struct channel *c) +{ + if (!(c->channel_flags & CHANNEL_F_BUFFERED) || c->buffer->len == 0) + return 0; + + c->ops->send(c->data, c->buffer->data, c->buffer->len); + c->buffer->len = 0; + return 1; +} + +int channel_recv(struct channel *c, char *buf, int size) +{ + return c->ops->recv(c->data, buf, size); +} + +int channel_get_fd(struct channel *c) +{ + return c->ops->get_fd(c->data); +} + +void channel_stats(struct channel *c, int fd) +{ + return c->ops->stats(c, fd); +} + +void channel_stats_extended(struct channel *c, int active, + struct nlif_handle *h, int fd) +{ + return c->ops->stats_extended(c, active, h, fd); +} diff --git a/src/channel_mcast.c b/src/channel_mcast.c new file mode 100644 index 0000000..898b194 --- /dev/null +++ b/src/channel_mcast.c @@ -0,0 +1,123 @@ +/* + * (C) 2009 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include + +#include "channel.h" +#include "mcast.h" + +static void +*channel_mcast_open(void *conf) +{ + struct mcast_channel *m; + struct mcast_conf *c = conf; + + m = calloc(sizeof(struct mcast_channel), 1); + if (m == NULL) + return NULL; + + m->client = mcast_client_create(c); + if (m->client == NULL) { + free(m); + return NULL; + } + + m->server = mcast_server_create(c); + if (m->server == NULL) { + mcast_client_destroy(m->client); + free(m); + return NULL; + } + return m; +} + +static int +channel_mcast_send(void *channel, const void *data, int len) +{ + struct mcast_channel *m = channel; + return mcast_send(m->client, data, len); +} + +static int +channel_mcast_recv(void *channel, char *buf, int size) +{ + struct mcast_channel *m = channel; + return mcast_recv(m->server, buf, size); +} + +static void +channel_mcast_close(void *channel) +{ + struct mcast_channel *m = channel; + mcast_client_destroy(m->client); + mcast_server_destroy(m->server); + free(m); +} + +static int +channel_mcast_get_fd(void *channel) +{ + struct mcast_channel *m = channel; + return mcast_get_fd(m->server); +} + +static void +channel_mcast_stats(struct channel *c, int fd) +{ + struct mcast_channel *m = c->data; + char ifname[IFNAMSIZ], buf[512]; + int size; + + if_indextoname(c->channel_ifindex, ifname); + size = mcast_snprintf_stats(buf, sizeof(buf), ifname, + &m->client->stats, &m->server->stats); + send(fd, buf, size, 0); +} + +static void +channel_mcast_stats_extended(struct channel *c, int active, + struct nlif_handle *h, int fd) +{ + struct mcast_channel *m = c->data; + char ifname[IFNAMSIZ], buf[512]; + const char *status; + unsigned int flags; + int size; + + if_indextoname(c->channel_ifindex, ifname); + nlif_get_ifflags(h, c->channel_ifindex, &flags); + /* + * IFF_UP shows administrative status + * IFF_RUNNING shows carrier status + */ + if (flags & IFF_UP) { + if (!(flags & IFF_RUNNING)) + status = "NO-CARRIER"; + else + status = "RUNNING"; + } else { + status = "DOWN"; + } + size = mcast_snprintf_stats2(buf, sizeof(buf), + ifname, status, active, + &m->client->stats, + &m->server->stats); + send(fd, buf, size, 0); +} + +struct channel_ops channel_mcast = { + .open = channel_mcast_open, + .close = channel_mcast_close, + .send = channel_mcast_send, + .recv = channel_mcast_recv, + .get_fd = channel_mcast_get_fd, + .stats = channel_mcast_stats, + .stats_extended = channel_mcast_stats_extended, +}; diff --git a/src/mcast.c b/src/mcast.c index 8f11762..8eedd07 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -143,52 +143,12 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return m; } -struct mcast_sock_multi * -mcast_server_create_multi(struct mcast_conf *conf, int conf_len) -{ - struct mcast_sock_multi *m; - int i, j; - - if (conf_len <= 0 || conf_len > MCAST_LINKS_MAX) - return NULL; - - m = calloc(sizeof(struct mcast_sock_multi), 1); - if (m == NULL) - return NULL; - - m->max_mtu = INT_MAX; - for (i=0; imulti[i] = mcast_server_create(&conf[i]); - if (m->multi[i] == NULL) { - for (j=0; jmulti[j]); - } - free(m); - return NULL; - } - if (m->max_mtu > conf[i].mtu) - m->max_mtu = conf[i].mtu; - } - m->num_links = conf_len; - - return m; -} - void mcast_server_destroy(struct mcast_sock *m) { close(m->fd); free(m); } -void mcast_server_destroy_multi(struct mcast_sock_multi *m) -{ - int i; - - for (i=0; inum_links; i++) - mcast_server_destroy(m->multi[i]); - free(m); -} - static int __mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) { @@ -306,52 +266,12 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) return m; } -struct mcast_sock_multi * -mcast_client_create_multi(struct mcast_conf *conf, int conf_len) -{ - struct mcast_sock_multi *m; - int i, j; - - if (conf_len <= 0 || conf_len > MCAST_LINKS_MAX) - return NULL; - - m = calloc(sizeof(struct mcast_sock_multi), 1); - if (m == NULL) - return NULL; - - m->max_mtu = INT_MAX; - for (i=0; imulti[i] = mcast_client_create(&conf[i]); - if (m->multi[i] == NULL) { - for (j=0; jmulti[j]); - } - free(m); - return NULL; - } - if (m->max_mtu > conf[i].mtu) - m->max_mtu = conf[i].mtu; - } - m->num_links = conf_len; - - return m; -} - void mcast_client_destroy(struct mcast_sock *m) { close(m->fd); free(m); } -void mcast_client_destroy_multi(struct mcast_sock_multi *m) -{ - int i; - - for (i=0; inum_links; i++) - mcast_client_destroy(m->multi[i]); - free(m); -} - ssize_t mcast_send(struct mcast_sock *m, void *data, int size) { ssize_t ret; @@ -395,32 +315,12 @@ ssize_t mcast_recv(struct mcast_sock *m, void *data, int size) return ret; } -void mcast_set_current_link(struct mcast_sock_multi *m, int i) -{ - m->current_link = m->multi[i]; -} - -struct mcast_sock *mcast_get_current_link(struct mcast_sock_multi *m) -{ - return m->current_link; -} - int mcast_get_fd(struct mcast_sock *m) { return m->fd; } -int mcast_get_current_ifidx(struct mcast_sock_multi *m) -{ - return m->current_link->interface_idx; -} - -int mcast_get_ifidx(struct mcast_sock_multi *m, int i) -{ - return m->multi[i]->interface_idx; -} - -static int +int mcast_snprintf_stats(char *buf, size_t buflen, char *ifname, struct mcast_stats *s, struct mcast_stats *r) { @@ -443,7 +343,7 @@ mcast_snprintf_stats(char *buf, size_t buflen, char *ifname, return size; } -static int +int mcast_snprintf_stats2(char *buf, size_t buflen, const char *ifname, const char *status, int active, struct mcast_stats *s, struct mcast_stats *r) @@ -467,68 +367,3 @@ mcast_snprintf_stats2(char *buf, size_t buflen, const char *ifname, (unsigned long long)r->error); return size; } - -void -mcast_dump_stats(int fd, - const struct mcast_sock_multi *s, - const struct mcast_sock_multi *r) -{ - int i; - struct mcast_stats snd = { 0, 0, 0}; - struct mcast_stats rcv = { 0, 0, 0}; - char ifname[IFNAMSIZ], buf[512]; - int size; - - /* it is the same for the receiver, no need to do it twice */ - if_indextoname(s->current_link->interface_idx, ifname); - - for (i=0; inum_links && inum_links; i++) { - snd.bytes += s->multi[i]->stats.bytes; - snd.messages += s->multi[i]->stats.messages; - snd.error += s->multi[i]->stats.error; - rcv.bytes += r->multi[i]->stats.bytes; - rcv.messages += r->multi[i]->stats.messages; - rcv.error += r->multi[i]->stats.error; - } - size = mcast_snprintf_stats(buf, sizeof(buf), ifname, &snd, &rcv); - send(fd, buf, size, 0); -} - -void -mcast_dump_stats_extended(int fd, - const struct mcast_sock_multi *s, - const struct mcast_sock_multi *r, - const struct nlif_handle *h) -{ - int i; - char buf[4096]; - int size = 0; - - for (i=0; inum_links && inum_links; i++) { - int idx = s->multi[i]->interface_idx, active; - unsigned int flags; - char ifname[IFNAMSIZ]; - const char *status; - - if_indextoname(idx, ifname); - nlif_get_ifflags(h, idx, &flags); - active = (s->multi[i] == s->current_link); - /* - * IFF_UP shows administrative status - * IFF_RUNNING shows carrier status - */ - if (flags & IFF_UP) { - if (!(flags & IFF_RUNNING)) - status = "NO-CARRIER"; - else - status = "RUNNING"; - } else { - status = "DOWN"; - } - size += mcast_snprintf_stats2(buf+size, sizeof(buf), - ifname, status, active, - &s->multi[i]->stats, - &r->multi[i]->stats); - } - send(fd, buf, size, 0); -} diff --git a/src/multichannel.c b/src/multichannel.c new file mode 100644 index 0000000..ab0f04c --- /dev/null +++ b/src/multichannel.c @@ -0,0 +1,110 @@ +/* + * (C) 2009 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +#include "channel.h" +#include "network.h" + +struct multichannel * +multichannel_open(struct channel_conf *conf, int len) +{ + struct multichannel *m; + int i, set_default_channel = 0; + + if (len <= 0 || len > MULTICHANNEL_MAX) + return NULL; + + m = calloc(sizeof(struct multichannel), 1); + if (m == NULL) + return NULL; + + m->channel_num = len; + for (i = 0; i < len; i++) { + m->channel[i] = channel_open(&conf[i]); + if (m->channel[i] == NULL) { + int j; + + for (j=0; jchannel[j]); + } + free(m); + return NULL; + } + if (conf[i].channel_flags & CHANNEL_F_DEFAULT) { + m->current = m->channel[i]; + set_default_channel = 1; + } + } + if (!set_default_channel) + m->current = m->channel[0]; + + return m; +} + +int multichannel_send(struct multichannel *c, const struct nethdr *net) +{ + return channel_send(c->current, net); +} + +int multichannel_send_flush(struct multichannel *c) +{ + return channel_send_flush(c->current); +} + +int multichannel_recv(struct multichannel *c, char *buf, int size) +{ + return channel_recv(c->current, buf, size); +} + +void multichannel_close(struct multichannel *m) +{ + int i; + + for (i = 0; i < m->channel_num; i++) { + channel_close(m->channel[i]); + } + free(m); +} + +void multichannel_stats(struct multichannel *m, int fd) +{ + channel_stats(m->current, fd); +} + +void +multichannel_stats_extended(struct multichannel *m, + struct nlif_handle *h, int fd) +{ + int i, active; + + for (i = 0; i < m->channel_num; i++) { + if (m->current == m->channel[i]) { + active = 1; + } else { + active = 0; + } + channel_stats_extended(m->channel[i], active, h, fd); + } +} + +int multichannel_get_ifindex(struct multichannel *m, int i) +{ + return m->channel[i]->channel_ifindex; +} + +int multichannel_get_current_ifindex(struct multichannel *m) +{ + return m->current->channel_ifindex; +} + +void multichannel_set_current_channel(struct multichannel *m, int i) +{ + m->current = m->channel[i]; +} diff --git a/src/network.c b/src/network.c index 690b28e..bdfa10c 100644 --- a/src/network.c +++ b/src/network.c @@ -65,67 +65,6 @@ void nethdr_set_ctl(struct nethdr *net) __nethdr_set(net, NETHDR_SIZ); } -static size_t tx_buflenmax; -static size_t tx_buflen = 0; -static char *tx_buf; - -#define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ - -int mcast_buffered_init(int if_mtu) -{ - int mtu = if_mtu - HEADERSIZ; - - /* default to Ethernet MTU 1500 bytes */ - if (if_mtu == 0) - mtu = 1500 - HEADERSIZ; - - tx_buf = malloc(mtu); - if (tx_buf == NULL) - return -1; - - tx_buflenmax = mtu; - - return 0; -} - -void mcast_buffered_destroy(void) -{ - free(tx_buf); -} - -/* return 0 if it is not sent, otherwise return 1 */ -int -mcast_buffered_send_netmsg(struct mcast_sock_multi *m, const struct nethdr *net) -{ - int ret = 0, len = ntohs(net->len); - -retry: - if (tx_buflen + len < tx_buflenmax) { - memcpy(tx_buf + tx_buflen, net, len); - tx_buflen += len; - } else { - mcast_send(mcast_get_current_link(m), tx_buf, tx_buflen); - ret = 1; - tx_buflen = 0; - goto retry; - } - - return ret; -} - -ssize_t mcast_buffered_pending_netmsg(struct mcast_sock_multi *m) -{ - ssize_t ret; - - if (tx_buflen == 0) - return 0; - - ret = mcast_send(mcast_get_current_link(m), tx_buf, tx_buflen); - tx_buflen = 0; - - return ret; -} - static int local_seq_set = 0; /* this function only tracks, it does not update the last sequence received */ diff --git a/src/read_config_yy.y b/src/read_config_yy.y index b9a37f7..b3a2640 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -181,18 +181,18 @@ checksum: T_CHECKSUM T_ON * XXX: The use of Checksum outside of the Multicast clause is broken * if we have more than one dedicated links. */ - conf.mcast[0].checksum = 0; + conf.channel[0].u.mcast.checksum = 0; }; checksum: T_CHECKSUM T_OFF { fprintf(stderr, "WARNING: The use of `Checksum' outside the " "`Multicast' clause is ambiguous.\n"); - /* + /* * XXX: The use of Checksum outside of the Multicast clause is broken * if we have more than one dedicated links. */ - conf.mcast[0].checksum = 1; + conf.channel[0].u.mcast.checksum = 1; }; ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}' @@ -256,13 +256,18 @@ ignore_traffic_option : T_IPV6_ADDR T_IP multicast_line : T_MULTICAST '{' multicast_options '}' { - conf.mcast_links++; + conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST; + conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED; + conf.channel_num++; }; multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}' { - conf.mcast_default_link = conf.mcast_links; - conf.mcast_links++; + conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST; + conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT | + CHANNEL_F_BUFFERED; + conf.channel_default = conf.channel_num; + conf.channel_num++; }; multicast_options : @@ -272,19 +277,19 @@ multicast_option : T_IPV4_ADDR T_IP { __max_mcast_dedicated_links_reached(); - if (!inet_aton($2, &conf.mcast[conf.mcast_links].in)) { + if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.in)) { fprintf(stderr, "%s is not a valid IPv4 address\n", $2); break; } - if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { fprintf(stderr, "Your multicast address is IPv4 but " "is binded to an IPv6 interface? Surely " "this is not what you want\n"); break; } - conf.mcast[conf.mcast_links].ipproto = AF_INET; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET; }; multicast_option : T_IPV6_ADDR T_IP @@ -292,7 +297,8 @@ multicast_option : T_IPV6_ADDR T_IP __max_mcast_dedicated_links_reached(); #ifdef HAVE_INET_PTON_IPV6 - if (inet_pton(AF_INET6, $2, &conf.mcast[conf.mcast_links].in) <= 0) { + if (inet_pton(AF_INET6, $2, + &conf.channel[conf.channel_num].u.mcast.in) <= 0) { fprintf(stderr, "%s is not a valid IPv6 address\n", $2); break; } @@ -301,17 +307,17 @@ multicast_option : T_IPV6_ADDR T_IP break; #endif - if (conf.mcast[conf.mcast_links].ipproto == AF_INET) { + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET) { fprintf(stderr, "Your multicast address is IPv6 but " "is binded to an IPv4 interface? Surely " "this is not what you want\n"); break; } - conf.mcast[conf.mcast_links].ipproto = AF_INET6; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6; - if (conf.mcast[conf.mcast_links].iface[0] && - !conf.mcast[conf.mcast_links].ifa.interface_index6) { + if (conf.channel[conf.channel_num].u.mcast.iface[0] && + !conf.channel[conf.channel_num].u.mcast.ifa.interface_index6) { unsigned int idx; idx = if_nametoindex($2); @@ -320,8 +326,8 @@ multicast_option : T_IPV6_ADDR T_IP break; } - conf.mcast[conf.mcast_links].ifa.interface_index6 = idx; - conf.mcast[conf.mcast_links].ipproto = AF_INET6; + conf.channel[conf.channel_num].u.mcast.ifa.interface_index6 = idx; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6; } }; @@ -329,19 +335,19 @@ multicast_option : T_IPV4_IFACE T_IP { __max_mcast_dedicated_links_reached(); - if (!inet_aton($2, &conf.mcast[conf.mcast_links].ifa)) { + if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.ifa)) { fprintf(stderr, "%s is not a valid IPv4 address\n", $2); break; } - if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { fprintf(stderr, "Your multicast interface is IPv4 but " "is binded to an IPv6 interface? Surely " "this is not what you want\n"); break; } - conf.mcast[conf.mcast_links].ipproto = AF_INET; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET; }; multicast_option : T_IPV6_IFACE T_IP @@ -355,18 +361,19 @@ multicast_option : T_IFACE T_STRING __max_mcast_dedicated_links_reached(); - strncpy(conf.mcast[conf.mcast_links].iface, $2, IFNAMSIZ); + strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ); + strncpy(conf.channel[conf.channel_num].u.mcast.iface, $2, IFNAMSIZ); idx = if_nametoindex($2); if (!idx) { fprintf(stderr, "%s is an invalid interface.\n", $2); break; } - conf.mcast[conf.mcast_links].interface_idx = idx; + conf.channel[conf.channel_num].u.mcast.interface_idx = idx; - if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { - conf.mcast[conf.mcast_links].ifa.interface_index6 = idx; - conf.mcast[conf.mcast_links].ipproto = AF_INET6; + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { + conf.channel[conf.channel_num].u.mcast.ifa.interface_index6 = idx; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6; } }; @@ -379,31 +386,31 @@ multicast_option : T_BACKLOG T_NUMBER multicast_option : T_GROUP T_NUMBER { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].port = $2; + conf.channel[conf.channel_num].u.mcast.port = $2; }; multicast_option: T_MCAST_SNDBUFF T_NUMBER { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].sndbuf = $2; + conf.channel[conf.channel_num].u.mcast.sndbuf = $2; }; multicast_option: T_MCAST_RCVBUFF T_NUMBER { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].rcvbuf = $2; + conf.channel[conf.channel_num].u.mcast.rcvbuf = $2; }; multicast_option: T_CHECKSUM T_ON { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].checksum = 0; + conf.channel[conf.channel_num].u.mcast.checksum = 0; }; multicast_option: T_CHECKSUM T_OFF { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].checksum = 1; + conf.channel[conf.channel_num].u.mcast.checksum = 1; }; hashsize : T_HASHSIZE T_NUMBER @@ -1128,10 +1135,10 @@ static void __kernel_filter_add_state(int value) static void __max_mcast_dedicated_links_reached(void) { - if (conf.mcast_links >= MCAST_LINKS_MAX) { + if (conf.channel_num >= MULTICHANNEL_MAX) { fprintf(stderr, "ERROR: too many dedicated links in " "the configuration file (Maximum: %d).\n", - MCAST_LINKS_MAX); + MULTICHANNEL_MAX); exit(EXIT_FAILURE); } } diff --git a/src/sync-alarm.c b/src/sync-alarm.c index a59ae11..caa6bb2 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -125,7 +125,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) net = queue_node_data(n); nethdr_set_ctl(net); HDR_HOST2NETWORK(net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); queue_object_free((struct queue_object *)n); break; case Q_ELEM_OBJ: { @@ -137,7 +137,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) obj = cache_data_get_object(STATE_SYNC(internal), ca); type = object_status_to_network_type(obj->status); net = BUILD_NETMSG(obj->ct, type); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); cache_object_put(obj); break; } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index d608e5b..cacbb13 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -494,7 +494,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) dp("tx_queue sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); HDR_NETWORK2HOST(net); if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { @@ -523,7 +523,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) dp("tx_list sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); cn->seq = ntohl(net->seq); if (queue_add(rs_queue, &cn->qnode) < 0) { if (errno == ENOSPC) { diff --git a/src/sync-mode.c b/src/sync-mode.c index b452cba..22609df 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -38,12 +38,12 @@ static void mcast_change_current_link(int if_idx) { - if (if_idx != mcast_get_current_ifidx(STATE_SYNC(mcast_client))) - mcast_set_current_link(STATE_SYNC(mcast_client), if_idx); + if (if_idx != multichannel_get_current_ifindex(STATE_SYNC(channel))) + multichannel_set_current_channel(STATE_SYNC(channel), if_idx); } static void -do_mcast_handler_step(int if_idx, struct nethdr *net, size_t remain) +do_channel_handler_step(int if_idx, struct nethdr *net, size_t remain) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; @@ -122,14 +122,14 @@ retry: } } -/* handler for multicast messages received */ -static void mcast_handler(struct mcast_sock *m, int if_idx) +/* handler for messages received */ +static void channel_handler(struct channel *m, int if_idx) { ssize_t numbytes; ssize_t remain; char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ - numbytes = mcast_recv(m, __net, sizeof(__net)); + numbytes = channel_recv(m, __net, sizeof(__net)); if (numbytes <= 0) return; @@ -168,7 +168,7 @@ static void mcast_handler(struct mcast_sock *m, int if_idx) HDR_NETWORK2HOST(net); - do_mcast_handler_step(if_idx, net, remain); + do_channel_handler_step(if_idx, net, remain); ptr += net->len; remain -= net->len; } @@ -181,13 +181,13 @@ static void interface_candidate(void) unsigned int flags; char buf[IFNAMSIZ]; - for (i=0; inum_links; i++) { - idx = mcast_get_ifidx(STATE_SYNC(mcast_client), i); - if (idx == mcast_get_current_ifidx(STATE_SYNC(mcast_client))) + for (i=0; ichannel_num; i++) { + idx = multichannel_get_ifindex(STATE_SYNC(channel), i); + if (idx == multichannel_get_current_ifindex(STATE_SYNC(channel))) continue; nlif_get_ifflags(STATE_SYNC(interface), idx, &flags); if (flags & (IFF_RUNNING | IFF_UP)) { - mcast_set_current_link(STATE_SYNC(mcast_client), i); + multichannel_set_current_channel(STATE_SYNC(channel), i); dlog(LOG_NOTICE, "device `%s' becomes multicast " "dedicated link", if_indextoname(idx, buf)); @@ -199,7 +199,7 @@ static void interface_candidate(void) static void interface_handler(void) { - int idx = mcast_get_current_ifidx(STATE_SYNC(mcast_client)); + int idx = multichannel_get_current_ifindex(STATE_SYNC(channel)); unsigned int flags; nlif_catch(STATE_SYNC(interface)); @@ -267,38 +267,21 @@ static int init_sync(void) return -1; } - /* multicast server to receive events from the wire */ - STATE_SYNC(mcast_server) = - mcast_server_create_multi(CONFIG(mcast), CONFIG(mcast_links)); - if (STATE_SYNC(mcast_server) == NULL) { - dlog(LOG_ERR, "can't open multicast server!"); + channel_init(); + + /* channel to send events on the wire */ + STATE_SYNC(channel) = + multichannel_open(CONFIG(channel), CONFIG(channel_num)); + if (STATE_SYNC(channel) == NULL) { + dlog(LOG_ERR, "can't open channel socket"); return -1; } - for (i=0; inum_links; i++) { - int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]); + for (i=0; ichannel_num; i++) { + int fd = channel_get_fd(STATE_SYNC(channel)->channel[i]); if (register_fd(fd, STATE(fds)) == -1) return -1; } - /* multicast client to send events on the wire */ - STATE_SYNC(mcast_client) = - mcast_client_create_multi(CONFIG(mcast), CONFIG(mcast_links)); - if (STATE_SYNC(mcast_client) == NULL) { - dlog(LOG_ERR, "can't open client multicast socket"); - mcast_server_destroy_multi(STATE_SYNC(mcast_server)); - return -1; - } - /* we only use one link to send events, but all to receive them */ - mcast_set_current_link(STATE_SYNC(mcast_client), - CONFIG(mcast_default_link)); - - if (mcast_buffered_init(STATE_SYNC(mcast_client)->max_mtu) == -1) { - dlog(LOG_ERR, "can't init tx buffer!"); - mcast_server_destroy_multi(STATE_SYNC(mcast_server)); - mcast_client_destroy_multi(STATE_SYNC(mcast_client)); - return -1; - } - STATE_SYNC(interface) = nl_init_interface_handler(); if (!STATE_SYNC(interface)) { dlog(LOG_ERR, "can't open interface watcher"); @@ -328,10 +311,10 @@ static void run_sync(fd_set *readfds) { int i; - for (i=0; inum_links; i++) { - int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]); + for (i=0; ichannel_num; i++) { + int fd = channel_get_fd(STATE_SYNC(channel)->channel[i]); if (FD_ISSET(fd, readfds)) - mcast_handler(STATE_SYNC(mcast_server)->multi[i], i); + channel_handler(STATE_SYNC(channel)->channel[i], i); } if (FD_ISSET(queue_get_eventfd(STATE_SYNC(tx_queue)), readfds)) @@ -341,7 +324,7 @@ static void run_sync(fd_set *readfds) interface_handler(); /* flush pending messages */ - mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); + multichannel_send_flush(STATE_SYNC(channel)); } static void kill_sync(void) @@ -349,12 +332,10 @@ static void kill_sync(void) cache_destroy(STATE_SYNC(internal)); cache_destroy(STATE_SYNC(external)); - mcast_server_destroy_multi(STATE_SYNC(mcast_server)); - mcast_client_destroy_multi(STATE_SYNC(mcast_client)); + multichannel_close(STATE_SYNC(channel)); nlif_close(STATE_SYNC(interface)); - mcast_buffered_destroy(); queue_destroy(STATE_SYNC(tx_queue)); if (STATE_SYNC(sync)->kill) @@ -486,23 +467,20 @@ static int local_handler_sync(int fd, int type, void *data) cache_stats(STATE_SYNC(internal), fd); cache_stats(STATE_SYNC(external), fd); dump_traffic_stats(fd); - mcast_dump_stats(fd, STATE_SYNC(mcast_client), - STATE_SYNC(mcast_server)); + multichannel_stats(STATE_SYNC(channel), fd); dump_stats_sync(fd); break; case STATS_NETWORK: dump_stats_sync_extended(fd); - mcast_dump_stats(fd, STATE_SYNC(mcast_client), - STATE_SYNC(mcast_server)); + multichannel_stats(STATE_SYNC(channel), fd); break; case STATS_CACHE: cache_stats_extended(STATE_SYNC(internal), fd); cache_stats_extended(STATE_SYNC(external), fd); break; case STATS_MULTICAST: - mcast_dump_stats_extended(fd, STATE_SYNC(mcast_client), - STATE_SYNC(mcast_server), - STATE_SYNC(interface)); + multichannel_stats_extended(STATE_SYNC(channel), + STATE_SYNC(interface), fd); break; default: if (STATE_SYNC(sync)->local) diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 57c3368..737ee52 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -134,7 +134,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) else nethdr_set_ctl(net); HDR_HOST2NETWORK(net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); queue_del(n); queue_object_free((struct queue_object *)n); break; @@ -150,7 +150,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) type = object_status_to_network_type(obj->status);; net = BUILD_NETMSG(obj->ct, type); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); queue_del(n); cache_object_put(obj); break; -- cgit v1.2.3 From 338d8fc2da19f5d6a75c339d9e6ecac43b68a1e4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 12 Mar 2009 21:19:19 +0100 Subject: sync-mode: rename mcast_track_*() by nethdr_track_*() This patch is a cleanup. It renames the mcast_track_*() functions by nethdr_track_*() because this functions are related to message sequence tracking. They are not stick to multicast at all. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 6 +++--- src/network.c | 6 +++--- src/sync-alarm.c | 2 +- src/sync-ftfw.c | 6 +++--- src/sync-notrack.c | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 7019d7d..b182339 100644 --- a/include/network.h +++ b/include/network.h @@ -100,9 +100,9 @@ enum { SEQ_BEFORE, }; -int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); -void mcast_track_update_seq(uint32_t seq); -int mcast_track_is_seq_set(void); +int nethdr_track_seq(uint32_t seq, uint32_t *exp_seq); +void nethdr_track_update_seq(uint32_t seq); +int nethdr_track_is_seq_set(void); struct mcast_conf; diff --git a/src/network.c b/src/network.c index bdfa10c..6a66a2b 100644 --- a/src/network.c +++ b/src/network.c @@ -68,7 +68,7 @@ void nethdr_set_ctl(struct nethdr *net) static int local_seq_set = 0; /* this function only tracks, it does not update the last sequence received */ -int mcast_track_seq(uint32_t seq, uint32_t *exp_seq) +int nethdr_track_seq(uint32_t seq, uint32_t *exp_seq) { int ret = SEQ_UNKNOWN; @@ -104,7 +104,7 @@ out: return ret; } -void mcast_track_update_seq(uint32_t seq) +void nethdr_track_update_seq(uint32_t seq) { if (!local_seq_set) local_seq_set = 1; @@ -112,7 +112,7 @@ void mcast_track_update_seq(uint32_t seq) STATE_SYNC(last_seq_recv) = seq; } -int mcast_track_is_seq_set() +int nethdr_track_is_seq_set() { return local_seq_set; } diff --git a/src/sync-alarm.c b/src/sync-alarm.c index caa6bb2..4757026 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -102,7 +102,7 @@ static int alarm_recv(const struct nethdr *net) * just joined the cluster, instead they just get resynchronized in * RefreshTime seconds at worst case. */ - mcast_track_seq(net->seq, &exp_seq); + nethdr_track_seq(net->seq, &exp_seq); return 0; } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index cacbb13..e026b1c 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -129,7 +129,7 @@ static void tx_queue_add_ctlmsg2(uint32_t flags) /* this function is called from the alarm framework */ static void do_alive_alarm(struct alarm_block *a, void *data) { - if (ack_from_set && mcast_track_is_seq_set()) { + if (ack_from_set && nethdr_track_is_seq_set()) { /* exp_seq contains the last update received */ tx_queue_add_ctlmsg(NET_F_ACK, ack_from, @@ -396,7 +396,7 @@ static int ftfw_recv(const struct nethdr *net) goto bypass; } - switch (mcast_track_seq(net->seq, &exp_seq)) { + switch (nethdr_track_seq(net->seq, &exp_seq)) { case SEQ_AFTER: ret = digest_msg(net); if (ret == MSG_BAD) { @@ -446,7 +446,7 @@ bypass: out: if ((ret == MSG_DATA || ret == MSG_CTL)) - mcast_track_update_seq(net->seq); + nethdr_track_update_seq(net->seq); return ret; } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 737ee52..6502bcd 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -114,12 +114,12 @@ static int notrack_recv(const struct nethdr *net) int ret; unsigned int exp_seq; - mcast_track_seq(net->seq, &exp_seq); + nethdr_track_seq(net->seq, &exp_seq); ret = digest_msg(net); if (ret != MSG_BAD) - mcast_track_update_seq(net->seq); + nethdr_track_update_seq(net->seq); return ret; } -- cgit v1.2.3 From 400ae54438c4b85126f9fab0ae1dc067823b70f7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 18 Apr 2009 19:36:38 +0200 Subject: sync: add support for SCTP state replication This patch adds initial support for SCTP state replication. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 1 + doc/sync/ftfw/conntrackd.conf | 1 + doc/sync/notrack/conntrackd.conf | 1 + include/network.h | 8 +++++++- src/build.c | 16 +++++++++++++++- src/parse.c | 16 +++++++++++++++- 6 files changed, 40 insertions(+), 3 deletions(-) (limited to 'include/network.h') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 793e953..4607ad1 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -323,6 +323,7 @@ General { # Protocol Accept { TCP + SCTP } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 6eb4475..3135c6c 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -332,6 +332,7 @@ General { # Protocol Accept { TCP + SCTP } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index e2085f7..ff8a8a2 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -313,6 +313,7 @@ General { # Protocol Accept { TCP + SCTP } # diff --git a/include/network.h b/include/network.h index b182339..06c0463 100644 --- a/include/network.h +++ b/include/network.h @@ -199,7 +199,7 @@ enum nta_attr { NTA_IPV6, /* struct nfct_attr_grp_ipv6 */ NTA_L4PROTO, /* uint8_t */ NTA_PORT, /* struct nfct_attr_grp_port */ - NTA_STATE = 4, /* uint8_t */ + NTA_STATE_TCP = 4, /* uint8_t */ NTA_STATUS, /* uint32_t */ NTA_TIMEOUT, /* uint32_t */ NTA_MARK, /* uint32_t */ @@ -212,6 +212,7 @@ enum nta_attr { NTA_SPAT_PORT, /* uint16_t */ NTA_DPAT_PORT, /* uint16_t */ NTA_NAT_SEQ_ADJ = 16, /* struct nta_attr_natseqadj */ + NTA_STATE_SCTP, /* struct nta_attr_sctp */ NTA_MAX }; @@ -224,6 +225,11 @@ struct nta_attr_natseqadj { uint32_t repl_seq_offset_after; }; +struct nta_attr_sctp { + uint8_t state; + uint32_t vtag_orig, vtag_repl; +}; + void build_payload(const struct nf_conntrack *ct, struct nethdr *n); int parse_payload(struct nf_conntrack *ct, struct nethdr *n, size_t remain); diff --git a/src/build.c b/src/build.c index 63a85db..6b0fad7 100644 --- a/src/build.c +++ b/src/build.c @@ -92,6 +92,17 @@ __build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n) addattr(n, NTA_NAT_SEQ_ADJ, &data, sizeof(struct nta_attr_natseqadj)); } +static inline void +__build_sctp(const struct nf_conntrack *ct, struct nethdr *n) +{ + struct nta_attr_sctp data = { + .state = nfct_get_attr_u8(ct, ATTR_SCTP_STATE), + .vtag_orig = htonl(nfct_get_attr_u32(ct, ATTR_SCTP_VTAG_ORIG)), + .vtag_repl = htonl(nfct_get_attr_u32(ct, ATTR_SCTP_VTAG_REPL)), + }; + addattr(n, NTA_STATE_SCTP, &data, sizeof(struct nta_attr_sctp)); +} + static enum nf_conntrack_attr nat_type[] = { ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ATTR_REPL_NAT_SEQ_CORRECTION_POS, @@ -117,7 +128,10 @@ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) __build_u32(ct, ATTR_STATUS, n, NTA_STATUS); if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) - __build_u8(ct, ATTR_TCP_STATE, n, NTA_STATE); + __build_u8(ct, ATTR_TCP_STATE, n, NTA_STATE_TCP); + else if (nfct_attr_is_set(ct, ATTR_SCTP_STATE)) + __build_sctp(ct, n); + if (!CONFIG(commit_timeout) && nfct_attr_is_set(ct, ATTR_TIMEOUT)) __build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) diff --git a/src/parse.c b/src/parse.c index 76287fd..d14910a 100644 --- a/src/parse.c +++ b/src/parse.c @@ -29,6 +29,7 @@ static void parse_u16(struct nf_conntrack *ct, int attr, void *data); static void parse_u32(struct nf_conntrack *ct, int attr, void *data); static void parse_group(struct nf_conntrack *ct, int attr, void *data); static void parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); +static void parse_sctp(struct nf_conntrack *ct, int attr, void *data); struct parser { void (*parse)(struct nf_conntrack *ct, int attr, void *data); @@ -57,7 +58,7 @@ static struct parser h[NTA_MAX] = { .attr = ATTR_L4PROTO, .size = NTA_SIZE(sizeof(uint8_t)), }, - [NTA_STATE] = { + [NTA_STATE_TCP] = { .parse = parse_u8, .attr = ATTR_TCP_STATE, .size = NTA_SIZE(sizeof(uint8_t)), @@ -121,6 +122,10 @@ static struct parser h[NTA_MAX] = { .parse = parse_nat_seq_adj, .size = NTA_SIZE(sizeof(struct nta_attr_natseqadj)), }, + [NTA_STATE_SCTP] = { + .parse = parse_sctp, + .size = NTA_SIZE(sizeof(struct nta_attr_sctp)), + }, }; static void @@ -168,6 +173,15 @@ parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) ntohl(this->orig_seq_correction_pos)); } +static void +parse_sctp(struct nf_conntrack *ct, int attr, void *data) +{ + struct nta_attr_sctp *this = data; + nfct_set_attr_u8(ct, ATTR_SCTP_STATE, this->state); + nfct_set_attr_u32(ct, ATTR_SCTP_VTAG_ORIG, ntohl(this->vtag_orig)); + nfct_set_attr_u32(ct, ATTR_SCTP_VTAG_REPL, ntohl(this->vtag_repl)); +} + int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) { int len; -- cgit v1.2.3 From b808645ec71b7cc22cf5106b3d79625d07e6077c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 24 Apr 2009 12:23:03 +0200 Subject: sync: add support for DCCP state replication This patch adds initial support for DCCP state replication. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 1 + doc/sync/ftfw/conntrackd.conf | 1 + doc/sync/notrack/conntrackd.conf | 1 + include/network.h | 5 +++++ src/build.c | 12 ++++++++++++ src/parse.c | 13 +++++++++++++ 6 files changed, 33 insertions(+) (limited to 'include/network.h') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 4607ad1..a108569 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -324,6 +324,7 @@ General { Protocol Accept { TCP SCTP + DCCP } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 3135c6c..c1208f9 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -333,6 +333,7 @@ General { Protocol Accept { TCP SCTP + DCCP } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index ff8a8a2..b528fab 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -314,6 +314,7 @@ General { Protocol Accept { TCP SCTP + DCCP } # diff --git a/include/network.h b/include/network.h index 06c0463..2786585 100644 --- a/include/network.h +++ b/include/network.h @@ -213,6 +213,7 @@ enum nta_attr { NTA_DPAT_PORT, /* uint16_t */ NTA_NAT_SEQ_ADJ = 16, /* struct nta_attr_natseqadj */ NTA_STATE_SCTP, /* struct nta_attr_sctp */ + NTA_STATE_DCCP, /* struct nta_attr_dccp */ NTA_MAX }; @@ -230,6 +231,10 @@ struct nta_attr_sctp { uint32_t vtag_orig, vtag_repl; }; +struct nta_attr_dccp { + uint8_t state, role; +}; + void build_payload(const struct nf_conntrack *ct, struct nethdr *n); int parse_payload(struct nf_conntrack *ct, struct nethdr *n, size_t remain); diff --git a/src/build.c b/src/build.c index 6b0fad7..a02a912 100644 --- a/src/build.c +++ b/src/build.c @@ -103,6 +103,16 @@ __build_sctp(const struct nf_conntrack *ct, struct nethdr *n) addattr(n, NTA_STATE_SCTP, &data, sizeof(struct nta_attr_sctp)); } +static inline void +__build_dccp(const struct nf_conntrack *ct, struct nethdr *n) +{ + struct nta_attr_dccp data = { + .state = nfct_get_attr_u8(ct, ATTR_DCCP_STATE), + .role = nfct_get_attr_u8(ct, ATTR_DCCP_ROLE), + }; + addattr(n, NTA_STATE_DCCP, &data, sizeof(struct nta_attr_dccp)); +} + static enum nf_conntrack_attr nat_type[] = { ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ATTR_REPL_NAT_SEQ_CORRECTION_POS, @@ -131,6 +141,8 @@ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) __build_u8(ct, ATTR_TCP_STATE, n, NTA_STATE_TCP); else if (nfct_attr_is_set(ct, ATTR_SCTP_STATE)) __build_sctp(ct, n); + else if (nfct_attr_is_set(ct, ATTR_DCCP_STATE)) + __build_dccp(ct, n); if (!CONFIG(commit_timeout) && nfct_attr_is_set(ct, ATTR_TIMEOUT)) __build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); diff --git a/src/parse.c b/src/parse.c index d14910a..100177b 100644 --- a/src/parse.c +++ b/src/parse.c @@ -30,6 +30,7 @@ static void parse_u32(struct nf_conntrack *ct, int attr, void *data); static void parse_group(struct nf_conntrack *ct, int attr, void *data); static void parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); static void parse_sctp(struct nf_conntrack *ct, int attr, void *data); +static void parse_dccp(struct nf_conntrack *ct, int attr, void *data); struct parser { void (*parse)(struct nf_conntrack *ct, int attr, void *data); @@ -126,6 +127,10 @@ static struct parser h[NTA_MAX] = { .parse = parse_sctp, .size = NTA_SIZE(sizeof(struct nta_attr_sctp)), }, + [NTA_STATE_DCCP] = { + .parse = parse_dccp, + .size = NTA_SIZE(sizeof(struct nta_attr_dccp)), + }, }; static void @@ -182,6 +187,14 @@ parse_sctp(struct nf_conntrack *ct, int attr, void *data) nfct_set_attr_u32(ct, ATTR_SCTP_VTAG_REPL, ntohl(this->vtag_repl)); } +static void +parse_dccp(struct nf_conntrack *ct, int attr, void *data) +{ + struct nta_attr_dccp *this = data; + nfct_set_attr_u8(ct, ATTR_DCCP_STATE, this->state); + nfct_set_attr_u8(ct, ATTR_DCCP_ROLE, this->role); +} + int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) { int len; -- cgit v1.2.3 From d9c0564db6b3f3ecb196508458a91b03d45fadb2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 12 Jun 2009 18:35:11 +0200 Subject: build: use TLV format for SCTP/DCCP protocol information In 400ae54438c4b85126f9fab0ae1dc067823b70f7, we added the SCTP support by means of a structure that was encapsulated in an TLV attribute. However, this structure didn't handle alignment and endianess issues appropriately. Similar problem was introduced in b808645ec71b7cc22cf5106b3d79625d07e6077c along with the DCCP support. This patch moves every field of this structure to independent attributes. I decided not to use nesting to make building and parsing more simple. Using TLV is a good idea, specially for DCCP and SCTP that are under development and that may include new fields and obsolete them in the future. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 18 ++++++------------ src/build.c | 35 +++++++++-------------------------- src/parse.c | 50 ++++++++++++++++++++++++-------------------------- 3 files changed, 39 insertions(+), 64 deletions(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 2786585..3248245 100644 --- a/include/network.h +++ b/include/network.h @@ -199,7 +199,7 @@ enum nta_attr { NTA_IPV6, /* struct nfct_attr_grp_ipv6 */ NTA_L4PROTO, /* uint8_t */ NTA_PORT, /* struct nfct_attr_grp_port */ - NTA_STATE_TCP = 4, /* uint8_t */ + NTA_TCP_STATE = 4, /* uint8_t */ NTA_STATUS, /* uint32_t */ NTA_TIMEOUT, /* uint32_t */ NTA_MARK, /* uint32_t */ @@ -212,8 +212,11 @@ enum nta_attr { NTA_SPAT_PORT, /* uint16_t */ NTA_DPAT_PORT, /* uint16_t */ NTA_NAT_SEQ_ADJ = 16, /* struct nta_attr_natseqadj */ - NTA_STATE_SCTP, /* struct nta_attr_sctp */ - NTA_STATE_DCCP, /* struct nta_attr_dccp */ + NTA_SCTP_STATE, /* uint8_t */ + NTA_SCTP_VTAG_ORIG, /* uint32_t */ + NTA_SCTP_VTAG_REPL, /* uint32_t */ + NTA_DCCP_STATE = 20, /* uint8_t */ + NTA_DCCP_ROLE, /* uint8_t */ NTA_MAX }; @@ -226,15 +229,6 @@ struct nta_attr_natseqadj { uint32_t repl_seq_offset_after; }; -struct nta_attr_sctp { - uint8_t state; - uint32_t vtag_orig, vtag_repl; -}; - -struct nta_attr_dccp { - uint8_t state, role; -}; - void build_payload(const struct nf_conntrack *ct, struct nethdr *n); int parse_payload(struct nf_conntrack *ct, struct nethdr *n, size_t remain); diff --git a/src/build.c b/src/build.c index b2eeeee..92760f2 100644 --- a/src/build.c +++ b/src/build.c @@ -92,27 +92,6 @@ __build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n) addattr(n, NTA_NAT_SEQ_ADJ, &data, sizeof(struct nta_attr_natseqadj)); } -static inline void -__build_sctp(const struct nf_conntrack *ct, struct nethdr *n) -{ - struct nta_attr_sctp data = { - .state = nfct_get_attr_u8(ct, ATTR_SCTP_STATE), - .vtag_orig = htonl(nfct_get_attr_u32(ct, ATTR_SCTP_VTAG_ORIG)), - .vtag_repl = htonl(nfct_get_attr_u32(ct, ATTR_SCTP_VTAG_REPL)), - }; - addattr(n, NTA_STATE_SCTP, &data, sizeof(struct nta_attr_sctp)); -} - -static inline void -__build_dccp(const struct nf_conntrack *ct, struct nethdr *n) -{ - struct nta_attr_dccp data = { - .state = nfct_get_attr_u8(ct, ATTR_DCCP_STATE), - .role = nfct_get_attr_u8(ct, ATTR_DCCP_ROLE), - }; - addattr(n, NTA_STATE_DCCP, &data, sizeof(struct nta_attr_dccp)); -} - static enum nf_conntrack_attr nat_type[] = { ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ATTR_REPL_NAT_SEQ_CORRECTION_POS, @@ -138,11 +117,15 @@ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) __build_u32(ct, ATTR_STATUS, n, NTA_STATUS); if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) - __build_u8(ct, ATTR_TCP_STATE, n, NTA_STATE_TCP); - else if (nfct_attr_is_set(ct, ATTR_SCTP_STATE)) - __build_sctp(ct, n); - else if (nfct_attr_is_set(ct, ATTR_DCCP_STATE)) - __build_dccp(ct, n); + __build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE); + else if (nfct_attr_is_set(ct, ATTR_SCTP_STATE)) { + __build_u8(ct, ATTR_SCTP_STATE, n, NTA_SCTP_STATE); + __build_u32(ct, ATTR_SCTP_VTAG_ORIG, n, NTA_SCTP_VTAG_ORIG); + __build_u32(ct, ATTR_SCTP_VTAG_REPL, n, NTA_SCTP_VTAG_REPL); + } else if (nfct_attr_is_set(ct, ATTR_DCCP_STATE)) { + __build_u8(ct, ATTR_DCCP_STATE, n, NTA_DCCP_STATE); + __build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE); + } if (!CONFIG(commit_timeout) && nfct_attr_is_set(ct, ATTR_TIMEOUT)) __build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); diff --git a/src/parse.c b/src/parse.c index 100177b..1bdfcc7 100644 --- a/src/parse.c +++ b/src/parse.c @@ -29,8 +29,6 @@ static void parse_u16(struct nf_conntrack *ct, int attr, void *data); static void parse_u32(struct nf_conntrack *ct, int attr, void *data); static void parse_group(struct nf_conntrack *ct, int attr, void *data); static void parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); -static void parse_sctp(struct nf_conntrack *ct, int attr, void *data); -static void parse_dccp(struct nf_conntrack *ct, int attr, void *data); struct parser { void (*parse)(struct nf_conntrack *ct, int attr, void *data); @@ -59,7 +57,7 @@ static struct parser h[NTA_MAX] = { .attr = ATTR_L4PROTO, .size = NTA_SIZE(sizeof(uint8_t)), }, - [NTA_STATE_TCP] = { + [NTA_TCP_STATE] = { .parse = parse_u8, .attr = ATTR_TCP_STATE, .size = NTA_SIZE(sizeof(uint8_t)), @@ -123,13 +121,30 @@ static struct parser h[NTA_MAX] = { .parse = parse_nat_seq_adj, .size = NTA_SIZE(sizeof(struct nta_attr_natseqadj)), }, - [NTA_STATE_SCTP] = { - .parse = parse_sctp, - .size = NTA_SIZE(sizeof(struct nta_attr_sctp)), + [NTA_SCTP_STATE] = { + .parse = parse_u8, + .attr = ATTR_SCTP_STATE, + .size = NTA_SIZE(sizeof(uint8_t)), }, - [NTA_STATE_DCCP] = { - .parse = parse_dccp, - .size = NTA_SIZE(sizeof(struct nta_attr_dccp)), + [NTA_SCTP_VTAG_ORIG] = { + .parse = parse_u32, + .attr = ATTR_SCTP_VTAG_ORIG, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_SCTP_VTAG_REPL] = { + .parse = parse_u32, + .attr = ATTR_SCTP_VTAG_REPL, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_DCCP_STATE] = { + .parse = parse_u8, + .attr = ATTR_DCCP_STATE, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_DCCP_ROLE] = { + .parse = parse_u8, + .attr = ATTR_DCCP_ROLE, + .size = NTA_SIZE(sizeof(uint8_t)), }, }; @@ -178,23 +193,6 @@ parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) ntohl(this->orig_seq_correction_pos)); } -static void -parse_sctp(struct nf_conntrack *ct, int attr, void *data) -{ - struct nta_attr_sctp *this = data; - nfct_set_attr_u8(ct, ATTR_SCTP_STATE, this->state); - nfct_set_attr_u32(ct, ATTR_SCTP_VTAG_ORIG, ntohl(this->vtag_orig)); - nfct_set_attr_u32(ct, ATTR_SCTP_VTAG_REPL, ntohl(this->vtag_repl)); -} - -static void -parse_dccp(struct nf_conntrack *ct, int attr, void *data) -{ - struct nta_attr_dccp *this = data; - nfct_set_attr_u8(ct, ATTR_DCCP_STATE, this->state); - nfct_set_attr_u8(ct, ATTR_DCCP_ROLE, this->role); -} - int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) { int len; -- cgit v1.2.3 From 9d2c667b951fa67f70bebc863f005dd1d10de91c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 3 Sep 2009 12:18:43 +0200 Subject: conntrackd: net message memory allocation is unsafe We cannot assume that we will not write in the net message before we send it, because the memory allocated for the net message (__net) is only reserved in BUILD_NETMSG (because of the { } block in it). This patch marks the buffer as static to avoid this problem. Based on a patch from Samuel Gauthier Signed-off-by: Pablo Neira Ayuso --- include/network.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/network.h') diff --git a/include/network.h b/include/network.h index 3248245..dfc3015 100644 --- a/include/network.h +++ b/include/network.h @@ -81,7 +81,7 @@ enum { #define BUILD_NETMSG(ct, query) \ ({ \ - char __net[4096]; \ + static char __net[4096]; \ struct nethdr *__hdr = (struct nethdr *) __net; \ memset(__hdr, 0, NETHDR_SIZ); \ nethdr_set(__hdr, query); \ -- cgit v1.2.3 From 65645763ebe870fa01b5c1a5dbe810feb9397ff2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 6 Oct 2009 11:19:28 +0200 Subject: conntrackd: add ICMP support for state-synchronization This patch adds state-synchronization for ICMP. You SHOULD use a Linux kernel >= 2.6.31, otherwise this patch can result in tons of state-updates. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 1 + doc/sync/ftfw/conntrackd.conf | 1 + doc/sync/notrack/conntrackd.conf | 1 + include/network.h | 3 +++ src/build.c | 9 ++++++++- src/parse.c | 15 +++++++++++++++ 6 files changed, 29 insertions(+), 1 deletion(-) (limited to 'include/network.h') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 800012f..3424e39 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -332,6 +332,7 @@ General { TCP SCTP DCCP + # ICMP # This requires a Linux kernel >= 2.6.31 } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 81f2de1..df10aca 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -357,6 +357,7 @@ General { TCP SCTP DCCP + # ICMP # This requires a Linux kernel >= 2.6.31 } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 529fbd9..5b9ebbb 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -338,6 +338,7 @@ General { TCP SCTP DCCP + # ICMP # This requires a Linux kernel >= 2.6.31 } # diff --git a/include/network.h b/include/network.h index dfc3015..70812b1 100644 --- a/include/network.h +++ b/include/network.h @@ -217,6 +217,9 @@ enum nta_attr { NTA_SCTP_VTAG_REPL, /* uint32_t */ NTA_DCCP_STATE = 20, /* uint8_t */ NTA_DCCP_ROLE, /* uint8_t */ + NTA_ICMP_TYPE, /* uint8_t */ + NTA_ICMP_CODE, /* uint8_t */ + NTA_ICMP_ID, /* uint16_t */ NTA_MAX }; diff --git a/src/build.c b/src/build.c index defb2ec..6d8b12e 100644 --- a/src/build.c +++ b/src/build.c @@ -124,6 +124,13 @@ static void build_l4proto_dccp(const struct nf_conntrack *ct, struct nethdr *n) __build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE); } +static void build_l4proto_icmp(const struct nf_conntrack *ct, struct nethdr *n) +{ + __build_u8(ct, ATTR_ICMP_TYPE, n, NTA_ICMP_TYPE); + __build_u8(ct, ATTR_ICMP_CODE, n, NTA_ICMP_CODE); + __build_u16(ct, ATTR_ICMP_ID, n, NTA_ICMP_ID); +} + #ifndef IPPROTO_DCCP #define IPPROTO_DCCP 33 #endif @@ -134,9 +141,9 @@ static struct build_l4proto { [IPPROTO_TCP] = { .build = build_l4proto_tcp }, [IPPROTO_SCTP] = { .build = build_l4proto_sctp }, [IPPROTO_DCCP] = { .build = build_l4proto_dccp }, + [IPPROTO_ICMP] = { .build = build_l4proto_icmp }, }; -/* XXX: ICMP not supported */ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) { uint8_t l4proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); diff --git a/src/parse.c b/src/parse.c index b5f257c..e6eefe4 100644 --- a/src/parse.c +++ b/src/parse.c @@ -146,6 +146,21 @@ static struct parser h[NTA_MAX] = { .attr = ATTR_DCCP_ROLE, .size = NTA_SIZE(sizeof(uint8_t)), }, + [NTA_ICMP_TYPE] = { + .parse = parse_u8, + .attr = ATTR_ICMP_TYPE, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_ICMP_CODE] = { + .parse = parse_u8, + .attr = ATTR_ICMP_CODE, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_ICMP_ID] = { + .parse = parse_u16, + .attr = ATTR_ICMP_ID, + .size = NTA_SIZE(sizeof(uint16_t)), + }, }; static void -- cgit v1.2.3 From 56817d1c0cc30bcd65c56c2f73634b256603cc4d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 29 Dec 2009 20:02:55 +0100 Subject: conntrackd: add support for TCP window scale factor synchronization This patch adds a new option TCPWindowTracking that allows not to disable TCP window tracking as it occurs by default. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 11 +++++++++++ doc/sync/ftfw/conntrackd.conf | 10 ++++++++++ doc/sync/notrack/conntrackd.conf | 11 +++++++++++ include/conntrackd.h | 1 + include/network.h | 2 ++ src/build.c | 4 ++++ src/netlink.c | 20 ++++++++++---------- src/parse.c | 10 ++++++++++ src/read_config_lex.l | 2 ++ src/read_config_yy.y | 18 ++++++++++++++++++ 10 files changed, 79 insertions(+), 10 deletions(-) (limited to 'include/network.h') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 9b7d8c6..65c8715 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -180,6 +180,17 @@ Sync { # # Checksum on # } + + # + # Other unsorted options that are related to the synchronization. + # + # Options { + # + # TCP state-entries have window tracking disabled by default, + # you can enable it with this option. As said, default is off. + # + # TCPWindowTracking Off + # } } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 877ed68..481fe8b 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -204,6 +204,16 @@ Sync { # Checksum on # } + # + # Other unsorted options that are related to the synchronization. + # + # Options { + # + # TCP state-entries have window tracking disabled by default, + # you can enable it with this option. As said, default is off. + # + # TCPWindowTracking Off + # } } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 693209a..430ca25 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -242,6 +242,17 @@ Sync { # # Checksum on # } + + # + # Other unsorted options that are related to the synchronization. + # + # Options { + # + # TCP state-entries have window tracking disabled by default, + # you can enable it with this option. As said, default is off. + # + # TCPWindowTracking Off + # } } # diff --git a/include/conntrackd.h b/include/conntrackd.h index c7f33f0..b35c95d 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -102,6 +102,7 @@ struct ct_conf { struct { int internal_cache_disable; int external_cache_disable; + int tcp_window_tracking; } sync; struct { int events_reliable; diff --git a/include/network.h b/include/network.h index 70812b1..567317b 100644 --- a/include/network.h +++ b/include/network.h @@ -220,6 +220,8 @@ enum nta_attr { NTA_ICMP_TYPE, /* uint8_t */ NTA_ICMP_CODE, /* uint8_t */ NTA_ICMP_ID, /* uint16_t */ + NTA_TCP_WSCALE_ORIG, /* uint8_t */ + NTA_TCP_WSCALE_REPL, /* uint8_t */ NTA_MAX }; diff --git a/src/build.c b/src/build.c index 6d8b12e..0bfe8c1 100644 --- a/src/build.c +++ b/src/build.c @@ -103,6 +103,10 @@ static void build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n) return; __build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE); + if (CONFIG(sync).tcp_window_tracking) { + __build_u8(ct, ATTR_TCP_WSCALE_ORIG, n, NTA_TCP_WSCALE_ORIG); + __build_u8(ct, ATTR_TCP_WSCALE_REPL, n, NTA_TCP_WSCALE_REPL); + } } static void build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n) diff --git a/src/netlink.c b/src/netlink.c index a43f782..5b6452a 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -196,12 +196,12 @@ int nl_create_conntrack(struct nfct_handle *h, nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); - /* - * TCP flags to overpass window tracking for recovered connections - */ + /* disable TCP window tracking for recovered connections if required */ if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) { - uint8_t flags = IP_CT_TCP_FLAG_BE_LIBERAL | - IP_CT_TCP_FLAG_SACK_PERM; + uint8_t flags = IP_CT_TCP_FLAG_SACK_PERM; + + if (!CONFIG(sync).tcp_window_tracking) + flags |= IP_CT_TCP_FLAG_BE_LIBERAL; /* FIXME: workaround, we should send TCP flags in updates */ if (nfct_get_attr_u8(ct, ATTR_TCP_STATE) >= @@ -261,12 +261,12 @@ int nl_update_conntrack(struct nfct_handle *h, nfct_attr_unset(ct, ATTR_MASTER_PORT_DST); } - /* - * TCP flags to overpass window tracking for recovered connections - */ + /* disable TCP window tracking for recovered connections if required */ if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) { - uint8_t flags = IP_CT_TCP_FLAG_BE_LIBERAL | - IP_CT_TCP_FLAG_SACK_PERM; + uint8_t flags = IP_CT_TCP_FLAG_SACK_PERM; + + if (!CONFIG(sync).tcp_window_tracking) + flags |= IP_CT_TCP_FLAG_BE_LIBERAL; /* FIXME: workaround, we should send TCP flags in updates */ if (nfct_get_attr_u8(ct, ATTR_TCP_STATE) >= diff --git a/src/parse.c b/src/parse.c index e6eefe4..3eb7f44 100644 --- a/src/parse.c +++ b/src/parse.c @@ -161,6 +161,16 @@ static struct parser h[NTA_MAX] = { .attr = ATTR_ICMP_ID, .size = NTA_SIZE(sizeof(uint16_t)), }, + [NTA_TCP_WSCALE_ORIG] = { + .parse = parse_u8, + .attr = ATTR_TCP_WSCALE_ORIG, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_TCP_WSCALE_REPL] = { + .parse = parse_u8, + .attr = ATTR_TCP_WSCALE_REPL, + .size = NTA_SIZE(sizeof(uint8_t)), + }, }; static void diff --git a/src/read_config_lex.l b/src/read_config_lex.l index b2d4bdb..f005099 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -138,6 +138,8 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "NetlinkEventsReliable" { return T_NETLINK_EVENTS_RELIABLE; } "DisableInternalCache" { return T_DISABLE_INTERNAL_CACHE; } "DisableExternalCache" { return T_DISABLE_EXTERNAL_CACHE; } +"Options" { return T_OPTIONS; } +"TCPWindowTracking" { return T_TCP_WINDOW_TRACKING; } "ErrorQueueLength" { return T_ERROR_QUEUE_LENGTH; } {is_on} { return T_ON; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 5f4e6be..bc76e92 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -73,6 +73,7 @@ static void __max_dedicated_links_reached(void); %token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR %token T_SCHEDULER T_TYPE T_PRIO T_NETLINK_EVENTS_RELIABLE %token T_DISABLE_INTERNAL_CACHE T_DISABLE_EXTERNAL_CACHE T_ERROR_QUEUE_LENGTH +%token T_OPTIONS T_TCP_WINDOW_TRACKING %token T_IP T_PATH_VAL %token T_NUMBER @@ -808,8 +809,25 @@ sync_line: refreshtime | state_replication | cache_writethrough | destroy_timeout + | option_line ; +option_line: T_OPTIONS '{' options '}'; + +options: + | options option + ; + +option: T_TCP_WINDOW_TRACKING T_ON +{ + CONFIG(sync).tcp_window_tracking = 1; +}; + +option: T_TCP_WINDOW_TRACKING T_OFF +{ + CONFIG(sync).tcp_window_tracking = 0; +}; + sync_mode_alarm: T_SYNC_MODE T_ALARM '{' sync_mode_alarm_list '}' { conf.flags |= CTD_SYNC_ALARM; -- cgit v1.2.3 From 931c0eff309d8c7277ebe6d670fd72d8fbe3c674 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 4 Jan 2012 14:30:02 +0100 Subject: conntrackd: generalize/cleanup network message building/parsing This patch generalizes the network message building and parsing to prepare the upcoming expectation support. Basically, it renames: - NET_T_STATE_* by NET_T_STATE_CT_*, as I plan to add NET_T_STATE_EXP_* - BUILD_NETMSG by BUILD_NETMSG_FROM_CT, and build_payload by ct2msg. I plan to add exp2msg. - parse_payload by msg2ct, since I plan to add msg2exp. - modify object_status_to_network_type to prepare the support of expectations. - add prefix ct_ to all parsing functions in parse.c, as we will have similar functions to convert messages to expectation objects. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 3 +- include/network.h | 21 +++++++------ src/build.c | 81 ++++++++++++++++++++++++------------------------ src/internal_bypass.c | 6 ++-- src/internal_cache.c | 12 ++++---- src/network.c | 19 +++++++----- src/parse.c | 85 ++++++++++++++++++++++++++------------------------- src/sync-alarm.c | 4 +-- src/sync-ftfw.c | 2 +- src/sync-mode.c | 44 +++++++++++++++++--------- src/sync-notrack.c | 9 +++--- 11 files changed, 155 insertions(+), 131 deletions(-) (limited to 'include/network.h') diff --git a/include/cache.h b/include/cache.h index a42e395..02bb386 100644 --- a/include/cache.h +++ b/include/cache.h @@ -21,7 +21,8 @@ enum { C_OBJ_NONE = 0, /* not in the cache */ C_OBJ_NEW, /* just added to the cache */ C_OBJ_ALIVE, /* in the cache, alive */ - C_OBJ_DEAD /* still in the cache, but dead */ + C_OBJ_DEAD, /* still in the cache, but dead */ + C_OBJ_MAX }; struct cache; diff --git a/include/network.h b/include/network.h index 567317b..d0531b9 100644 --- a/include/network.h +++ b/include/network.h @@ -25,10 +25,10 @@ struct nethdr { #define NETHDR_SIZ nethdr_align(sizeof(struct nethdr)) enum nethdr_type { - NET_T_STATE_NEW = 0, - NET_T_STATE_UPD, - NET_T_STATE_DEL, - NET_T_STATE_MAX = NET_T_STATE_DEL, + NET_T_STATE_CT_NEW = 0, + NET_T_STATE_CT_UPD, + NET_T_STATE_CT_DEL, + NET_T_STATE_MAX = NET_T_STATE_CT_DEL, NET_T_CTL = 10, }; @@ -37,7 +37,9 @@ int nethdr_size(int len); void nethdr_set(struct nethdr *net, int type); void nethdr_set_ack(struct nethdr *net); void nethdr_set_ctl(struct nethdr *net); -int object_status_to_network_type(int status); + +struct cache_object; +int object_status_to_network_type(struct cache_object *obj); #define NETHDR_DATA(x) \ (struct netattr *)(((char *)x) + NETHDR_SIZ) @@ -79,13 +81,13 @@ enum { MSG_BAD, }; -#define BUILD_NETMSG(ct, query) \ +#define BUILD_NETMSG_FROM_CT(ct, query) \ ({ \ static char __net[4096]; \ struct nethdr *__hdr = (struct nethdr *) __net; \ memset(__hdr, 0, NETHDR_SIZ); \ nethdr_set(__hdr, query); \ - build_payload(ct, __hdr); \ + ct2msg(ct, __hdr); \ HDR_HOST2NETWORK(__hdr); \ __hdr; \ }) @@ -234,8 +236,7 @@ struct nta_attr_natseqadj { uint32_t repl_seq_offset_after; }; -void build_payload(const struct nf_conntrack *ct, struct nethdr *n); - -int parse_payload(struct nf_conntrack *ct, struct nethdr *n, size_t remain); +void ct2msg(const struct nf_conntrack *ct, struct nethdr *n); +int msg2ct(struct nf_conntrack *ct, struct nethdr *n, size_t remain); #endif diff --git a/src/build.c b/src/build.c index a495872..9c3687c 100644 --- a/src/build.c +++ b/src/build.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2008 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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; either version 2 of the License, or @@ -42,14 +43,14 @@ addattr(struct nethdr *n, int attr, const void *data, size_t len) } static inline void -__build_u8(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) +ct_build_u8(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { void *ptr = put_header(n, b, sizeof(uint8_t)); memcpy(ptr, nfct_get_attr(ct, a), sizeof(uint8_t)); } static inline void -__build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) +ct_build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { uint16_t data = nfct_get_attr_u16(ct, a); data = htons(data); @@ -57,7 +58,7 @@ __build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) } static inline void -__build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) +ct_build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { uint32_t data = nfct_get_attr_u32(ct, a); data = htonl(data); @@ -65,7 +66,7 @@ __build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) } static inline void -__build_group(const struct nf_conntrack *ct, int a, struct nethdr *n, +ct_build_group(const struct nf_conntrack *ct, int a, struct nethdr *n, int b, int size) { void *ptr = put_header(n, b, size); @@ -73,7 +74,7 @@ __build_group(const struct nf_conntrack *ct, int a, struct nethdr *n, } static inline void -__build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n) +ct_build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n) { struct nta_attr_natseqadj data = { .orig_seq_correction_pos = @@ -99,54 +100,54 @@ static enum nf_conntrack_attr nat_type[] = static void build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); if (!nfct_attr_is_set(ct, ATTR_TCP_STATE)) return; - __build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE); + ct_build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE); if (CONFIG(sync).tcp_window_tracking) { - __build_u8(ct, ATTR_TCP_WSCALE_ORIG, n, NTA_TCP_WSCALE_ORIG); - __build_u8(ct, ATTR_TCP_WSCALE_REPL, n, NTA_TCP_WSCALE_REPL); + ct_build_u8(ct, ATTR_TCP_WSCALE_ORIG, n, NTA_TCP_WSCALE_ORIG); + ct_build_u8(ct, ATTR_TCP_WSCALE_REPL, n, NTA_TCP_WSCALE_REPL); } } static void build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); if (!nfct_attr_is_set(ct, ATTR_SCTP_STATE)) return; - __build_u8(ct, ATTR_SCTP_STATE, n, NTA_SCTP_STATE); - __build_u32(ct, ATTR_SCTP_VTAG_ORIG, n, NTA_SCTP_VTAG_ORIG); - __build_u32(ct, ATTR_SCTP_VTAG_REPL, n, NTA_SCTP_VTAG_REPL); + ct_build_u8(ct, ATTR_SCTP_STATE, n, NTA_SCTP_STATE); + ct_build_u32(ct, ATTR_SCTP_VTAG_ORIG, n, NTA_SCTP_VTAG_ORIG); + ct_build_u32(ct, ATTR_SCTP_VTAG_REPL, n, NTA_SCTP_VTAG_REPL); } static void build_l4proto_dccp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); if (!nfct_attr_is_set(ct, ATTR_DCCP_STATE)) return; - __build_u8(ct, ATTR_DCCP_STATE, n, NTA_DCCP_STATE); - __build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE); + ct_build_u8(ct, ATTR_DCCP_STATE, n, NTA_DCCP_STATE); + ct_build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE); } static void build_l4proto_icmp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_u8(ct, ATTR_ICMP_TYPE, n, NTA_ICMP_TYPE); - __build_u8(ct, ATTR_ICMP_CODE, n, NTA_ICMP_CODE); - __build_u16(ct, ATTR_ICMP_ID, n, NTA_ICMP_ID); + ct_build_u8(ct, ATTR_ICMP_TYPE, n, NTA_ICMP_TYPE); + ct_build_u8(ct, ATTR_ICMP_CODE, n, NTA_ICMP_CODE); + ct_build_u16(ct, ATTR_ICMP_ID, n, NTA_ICMP_ID); } static void build_l4proto_udp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); } @@ -165,45 +166,45 @@ static struct build_l4proto { [IPPROTO_UDP] = { .build = build_l4proto_udp }, }; -void build_payload(const struct nf_conntrack *ct, struct nethdr *n) +void ct2msg(const struct nf_conntrack *ct, struct nethdr *n) { uint8_t l4proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { - __build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_IPV4, + ct_build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_IPV4, sizeof(struct nfct_attr_grp_ipv4)); } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { - __build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_IPV6, + ct_build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_IPV6, sizeof(struct nfct_attr_grp_ipv6)); } - __build_u32(ct, ATTR_STATUS, n, NTA_STATUS); - __build_u8(ct, ATTR_L4PROTO, n, NTA_L4PROTO); + ct_build_u32(ct, ATTR_STATUS, n, NTA_STATUS); + ct_build_u8(ct, ATTR_L4PROTO, n, NTA_L4PROTO); if (l4proto_fcn[l4proto].build) l4proto_fcn[l4proto].build(ct, n); if (!CONFIG(commit_timeout) && nfct_attr_is_set(ct, ATTR_TIMEOUT)) - __build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); + ct_build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) - __build_u32(ct, ATTR_MARK, n, NTA_MARK); + ct_build_u32(ct, ATTR_MARK, n, NTA_MARK); /* setup the master conntrack */ if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV4)) { - __build_group(ct, ATTR_GRP_MASTER_IPV4, n, NTA_MASTER_IPV4, + ct_build_group(ct, ATTR_GRP_MASTER_IPV4, n, NTA_MASTER_IPV4, sizeof(struct nfct_attr_grp_ipv4)); - __build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); + ct_build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { - __build_group(ct, ATTR_GRP_MASTER_PORT, + ct_build_group(ct, ATTR_GRP_MASTER_PORT, n, NTA_MASTER_PORT, sizeof(struct nfct_attr_grp_port)); } } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV6)) { - __build_group(ct, ATTR_GRP_MASTER_IPV6, n, NTA_MASTER_IPV6, + ct_build_group(ct, ATTR_GRP_MASTER_IPV6, n, NTA_MASTER_IPV6, sizeof(struct nfct_attr_grp_ipv6)); - __build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); + ct_build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { - __build_group(ct, ATTR_GRP_MASTER_PORT, + ct_build_group(ct, ATTR_GRP_MASTER_PORT, n, NTA_MASTER_PORT, sizeof(struct nfct_attr_grp_port)); } @@ -211,15 +212,15 @@ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) /* NAT */ if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - __build_u32(ct, ATTR_REPL_IPV4_DST, n, NTA_SNAT_IPV4); + ct_build_u32(ct, ATTR_REPL_IPV4_DST, n, NTA_SNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - __build_u32(ct, ATTR_REPL_IPV4_SRC, n, NTA_DNAT_IPV4); + ct_build_u32(ct, ATTR_REPL_IPV4_SRC, n, NTA_DNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) - __build_u16(ct, ATTR_REPL_PORT_DST, n, NTA_SPAT_PORT); + ct_build_u16(ct, ATTR_REPL_PORT_DST, n, NTA_SPAT_PORT); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) - __build_u16(ct, ATTR_REPL_PORT_SRC, n, NTA_DPAT_PORT); + ct_build_u16(ct, ATTR_REPL_PORT_SRC, n, NTA_DPAT_PORT); /* NAT sequence adjustment */ if (nfct_attr_is_set_array(ct, nat_type, 6)) - __build_natseqadj(ct, n); + ct_build_natseqadj(ct, n); } diff --git a/src/internal_bypass.c b/src/internal_bypass.c index 8ecec34..98717f3 100644 --- a/src/internal_bypass.c +++ b/src/internal_bypass.c @@ -118,7 +118,7 @@ static void internal_bypass_ct_event_new(struct nf_conntrack *ct, int origin) if (origin != CTD_ORIGIN_NOT_ME) return; - net = BUILD_NETMSG(ct, NET_T_STATE_NEW); + net = BUILD_NETMSG_FROM_CT(ct, NET_T_STATE_CT_NEW); multichannel_send(STATE_SYNC(channel), net); internal_bypass_stats.new++; } @@ -131,7 +131,7 @@ static void internal_bypass_ct_event_upd(struct nf_conntrack *ct, int origin) if (origin != CTD_ORIGIN_NOT_ME) return; - net = BUILD_NETMSG(ct, NET_T_STATE_UPD); + net = BUILD_NETMSG_FROM_CT(ct, NET_T_STATE_CT_UPD); multichannel_send(STATE_SYNC(channel), net); internal_bypass_stats.upd++; } @@ -144,7 +144,7 @@ static int internal_bypass_ct_event_del(struct nf_conntrack *ct, int origin) if (origin != CTD_ORIGIN_NOT_ME) return 1; - net = BUILD_NETMSG(ct, NET_T_STATE_DEL); + net = BUILD_NETMSG_FROM_CT(ct, NET_T_STATE_CT_DEL); multichannel_send(STATE_SYNC(channel), net); internal_bypass_stats.del++; diff --git a/src/internal_cache.c b/src/internal_cache.c index 7a698e6..952327d 100644 --- a/src/internal_cache.c +++ b/src/internal_cache.c @@ -81,7 +81,7 @@ static int internal_cache_ct_purge_step(void *data1, void *data2) if (!STATE(get_retval)) { if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); - sync_send(obj, NET_T_STATE_DEL); + sync_send(obj, NET_T_STATE_CT_DEL); cache_object_put(obj); } } @@ -117,10 +117,10 @@ internal_cache_ct_resync(enum nf_conntrack_msg_type type, switch (obj->status) { case C_OBJ_NEW: - sync_send(obj, NET_T_STATE_NEW); + sync_send(obj, NET_T_STATE_CT_NEW); break; case C_OBJ_ALIVE: - sync_send(obj, NET_T_STATE_UPD); + sync_send(obj, NET_T_STATE_CT_UPD); break; } return NFCT_CB_CONTINUE; @@ -155,7 +155,7 @@ retry: * processes or the kernel, but don't propagate events that * have been triggered by conntrackd itself, eg. commits. */ if (origin == CTD_ORIGIN_NOT_ME) - sync_send(obj, NET_T_STATE_NEW); + sync_send(obj, NET_T_STATE_CT_NEW); } else { cache_del(STATE(mode)->internal->ct.data, obj); cache_object_free(obj); @@ -176,7 +176,7 @@ static void internal_cache_ct_event_upd(struct nf_conntrack *ct, int origin) return; if (origin == CTD_ORIGIN_NOT_ME) - sync_send(obj, NET_T_STATE_UPD); + sync_send(obj, NET_T_STATE_CT_UPD); } static int internal_cache_ct_event_del(struct nf_conntrack *ct, int origin) @@ -196,7 +196,7 @@ static int internal_cache_ct_event_del(struct nf_conntrack *ct, int origin) if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); if (origin == CTD_ORIGIN_NOT_ME) { - sync_send(obj, NET_T_STATE_DEL); + sync_send(obj, NET_T_STATE_CT_DEL); } cache_object_put(obj); } diff --git a/src/network.c b/src/network.c index 6a66a2b..cadc466 100644 --- a/src/network.c +++ b/src/network.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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; either version 2 of the License, or @@ -119,13 +120,15 @@ int nethdr_track_is_seq_set() #include "cache.h" -static int status2type[] = { - [C_OBJ_NEW] = NET_T_STATE_NEW, - [C_OBJ_ALIVE] = NET_T_STATE_UPD, - [C_OBJ_DEAD] = NET_T_STATE_DEL, +static int status2type[CACHE_T_MAX][C_OBJ_MAX] = { + [CACHE_T_CT] = { + [C_OBJ_NEW] = NET_T_STATE_CT_NEW, + [C_OBJ_ALIVE] = NET_T_STATE_CT_UPD, + [C_OBJ_DEAD] = NET_T_STATE_CT_DEL, + }, }; -int object_status_to_network_type(int status) +int object_status_to_network_type(struct cache_object *obj) { - return status2type[status]; + return status2type[obj->cache->type][obj->status]; } diff --git a/src/parse.c b/src/parse.c index 7e60597..0718128 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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; either version 2 of the License, or @@ -24,184 +25,184 @@ #define ssizeof(x) (int)sizeof(x) #endif -static void parse_u8(struct nf_conntrack *ct, int attr, void *data); -static void parse_u16(struct nf_conntrack *ct, int attr, void *data); -static void parse_u32(struct nf_conntrack *ct, int attr, void *data); -static void parse_group(struct nf_conntrack *ct, int attr, void *data); -static void parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_u8(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_u16(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_u32(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_group(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); -struct parser { +struct ct_parser { void (*parse)(struct nf_conntrack *ct, int attr, void *data); int attr; int size; }; -static struct parser h[NTA_MAX] = { +static struct ct_parser h[NTA_MAX] = { [NTA_IPV4] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_ORIG_IPV4, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), }, [NTA_IPV6] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_ORIG_IPV6, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), }, [NTA_PORT] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_ORIG_PORT, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), }, [NTA_L4PROTO] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_L4PROTO, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_TCP_STATE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_TCP_STATE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_STATUS] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_STATUS, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_MARK] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_MARK, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_TIMEOUT] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_TIMEOUT, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_MASTER_IPV4] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_MASTER_IPV4, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), }, [NTA_MASTER_IPV6] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_MASTER_IPV6, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), }, [NTA_MASTER_L4PROTO] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_MASTER_L4PROTO, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_MASTER_PORT] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_MASTER_PORT, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), }, [NTA_SNAT_IPV4] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_SNAT_IPV4, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_DNAT_IPV4] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_DNAT_IPV4, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_SPAT_PORT] = { - .parse = parse_u16, + .parse = ct_parse_u16, .attr = ATTR_SNAT_PORT, .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_DPAT_PORT] = { - .parse = parse_u16, + .parse = ct_parse_u16, .attr = ATTR_DNAT_PORT, .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_NAT_SEQ_ADJ] = { - .parse = parse_nat_seq_adj, + .parse = ct_parse_nat_seq_adj, .size = NTA_SIZE(sizeof(struct nta_attr_natseqadj)), }, [NTA_SCTP_STATE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_SCTP_STATE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_SCTP_VTAG_ORIG] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_SCTP_VTAG_ORIG, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_SCTP_VTAG_REPL] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_SCTP_VTAG_REPL, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_DCCP_STATE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_DCCP_STATE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_DCCP_ROLE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_DCCP_ROLE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_ICMP_TYPE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_ICMP_TYPE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_ICMP_CODE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_ICMP_CODE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_ICMP_ID] = { - .parse = parse_u16, + .parse = ct_parse_u16, .attr = ATTR_ICMP_ID, .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_TCP_WSCALE_ORIG] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_TCP_WSCALE_ORIG, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_TCP_WSCALE_REPL] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_TCP_WSCALE_REPL, .size = NTA_SIZE(sizeof(uint8_t)), }, }; static void -parse_u8(struct nf_conntrack *ct, int attr, void *data) +ct_parse_u8(struct nf_conntrack *ct, int attr, void *data) { uint8_t *value = (uint8_t *) data; nfct_set_attr_u8(ct, h[attr].attr, *value); } static void -parse_u16(struct nf_conntrack *ct, int attr, void *data) +ct_parse_u16(struct nf_conntrack *ct, int attr, void *data) { uint16_t *value = (uint16_t *) data; nfct_set_attr_u16(ct, h[attr].attr, ntohs(*value)); } static void -parse_u32(struct nf_conntrack *ct, int attr, void *data) +ct_parse_u32(struct nf_conntrack *ct, int attr, void *data) { uint32_t *value = (uint32_t *) data; nfct_set_attr_u32(ct, h[attr].attr, ntohl(*value)); } static void -parse_group(struct nf_conntrack *ct, int attr, void *data) +ct_parse_group(struct nf_conntrack *ct, int attr, void *data) { nfct_set_attr_grp(ct, h[attr].attr, data); } static void -parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) +ct_parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) { struct nta_attr_natseqadj *this = data; nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS, @@ -218,7 +219,7 @@ parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) ntohl(this->repl_seq_offset_after)); } -int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) +int msg2ct(struct nf_conntrack *ct, struct nethdr *net, size_t remain) { int len; struct netattr *attr; diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 8d6b34d..65154a1 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -42,7 +42,7 @@ static void refresher(struct alarm_block *a, void *data) random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); - alarm_enqueue(obj, NET_T_STATE_UPD); + alarm_enqueue(obj, NET_T_STATE_CT_UPD); } static void cache_alarm_add(struct cache_object *obj, void *data) @@ -137,7 +137,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) ca = (struct cache_alarm *)n; obj = cache_data_get_object(STATE(mode)->internal->ct.data, ca); - type = object_status_to_network_type(obj->status); + type = object_status_to_network_type(obj); net = obj->cache->ops->build_msg(obj, type); multichannel_send(STATE_SYNC(channel), net); cache_object_put(obj); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 55eda0b..cff4d25 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -518,7 +518,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) cn = (struct cache_ftfw *)n; obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - type = object_status_to_network_type(obj->status); + type = object_status_to_network_type(obj); net = obj->cache->ops->build_msg(obj, type); nethdr_set_hello(net); diff --git a/src/sync-mode.c b/src/sync-mode.c index 7f019f7..17533f8 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -41,6 +41,24 @@ #include #include +static struct nf_conntrack *msg2ct_alloc(struct nethdr *net, size_t remain) +{ + struct nf_conntrack *ct; + + /* TODO: add stats on ENOMEM errors in the future. */ + ct = nfct_new(); + if (ct == NULL) + return NULL; + + if (msg2ct(ct, net, remain) == -1) { + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_payload++; + nfct_destroy(ct); + return NULL; + } + return ct; +} + static void do_channel_handler_step(int i, struct nethdr *net, size_t remain) { @@ -74,26 +92,24 @@ do_channel_handler_step(int i, struct nethdr *net, size_t remain) STATE_SYNC(error).msg_rcv_bad_type++; return; } - /* TODO: add stats on ENOMEM errors in the future. */ - ct = nfct_new(); - if (ct == NULL) - return; - - if (parse_payload(ct, net, remain) == -1) { - STATE_SYNC(error).msg_rcv_malformed++; - STATE_SYNC(error).msg_rcv_bad_payload++; - nfct_destroy(ct); - return; - } switch(net->type) { - case NET_T_STATE_NEW: + case NET_T_STATE_CT_NEW: + ct = msg2ct_alloc(net, remain); + if (ct == NULL) + return; STATE_SYNC(external)->ct.new(ct); break; - case NET_T_STATE_UPD: + case NET_T_STATE_CT_UPD: + ct = msg2ct_alloc(net, remain); + if (ct == NULL) + return; STATE_SYNC(external)->ct.upd(ct); break; - case NET_T_STATE_DEL: + case NET_T_STATE_CT_DEL: + ct = msg2ct_alloc(net, remain); + if (ct == NULL) + return; STATE_SYNC(external)->ct.del(ct); break; default: diff --git a/src/sync-notrack.c b/src/sync-notrack.c index e25cfd8..6c798ac 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -1,6 +1,7 @@ /* - * (C) 2008 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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; either version 2 of the License, or @@ -87,7 +88,7 @@ static int kernel_resync_cb(enum nf_conntrack_msg_type type, { struct nethdr *net; - net = BUILD_NETMSG(ct, NET_T_STATE_NEW); + net = BUILD_NETMSG_FROM_CT(ct, NET_T_STATE_CT_NEW); multichannel_send(STATE_SYNC(channel), net); return NFCT_CB_CONTINUE; @@ -198,7 +199,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) cn = (struct cache_ftfw *)n; obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - type = object_status_to_network_type(obj->status);; + type = object_status_to_network_type(obj);; net = obj->cache->ops->build_msg(obj, type); multichannel_send(STATE_SYNC(channel), net); -- cgit v1.2.3 From 79a777c60cfe02197c135adcc4edb2f63ae9a695 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 19 Dec 2011 17:13:25 +0100 Subject: conntrackd: support for expectation synchronization This patch adds support to synchronize expectations between firewalls. This addition aims to re-use as much as possible of the existing infrastructure for stability reasons. The expectation support has been tested with the FTP helper. This extension requires libnetfilter_conntrack 1.0.0. If this is the first time you're playing with conntrackd, I *strongly* recommend you to get working setup of conntrackd without expectation support before as described in the documentation. Then, enabling expectation support is rather easy. To know more about expectations, if you're not familiar with them, I suggest you to read: "Netfilter's Connection Tracking System" http://people.netfilter.org/pablo/docs/login.pdf Reprinted from ;login: The Magazine of USENIX, vol. 31, no. 3 (Berkeley, CA: USENIX Association, 2006, pp40-45.) In short, expectations allow one Linux firewall to filter multi-flow traffic like FTP, SIP and H.323. In my testbed, there are two firewalls in a primary-backup configuration running keepalived. The use a couple of floating cluster IP address (192.168.0.100 and 192.168.1.100) that are used by the client. These firewalls protect one FTP server (192.168.1.2) that will be accessed by one client. In ASCII art, it looks like this: 192.168.0.100 192.168.1.100 eth1 eth2 fw-1 / \ FTP -- client ------ ------ server -- 192.168.0.2 \ / 192.168.1.2 fw-2 This is the rule-set for the firewalls: -A POSTROUTING -t nat -s 192.168.0.2/32 -d 192.168.1.2/32 -j SNAT --to-source 192.168.1.100 -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT -A INPUT -m state --state INVALID -j DROP -A FORWARD -m state --state RELATED -j ACCEPT -A FORWARD -i eth2 -m state --state ESTABLISHED -j ACCEPT -A FORWARD -i eth1 -p tcp -m tcp --dport 21 --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j ACCEPT -A FORWARD -i eth1 -p tcp -m state --state ESTABLISHED -j ACCEPT -A FORWARD -m state --state INVALID -j LOG --log-prefix "invalid: " The following steps detail how to check that the expectation support works fine for conntrackd: 1) You have to enable the expectation support in the configuration file with the following option: Sync { ... Options { ExpectationSync { ftp sip h323 } } } This enables expectation synchronization for the FTP, SIP and H.323 helpers. You can alternatively use: Sync { ... Options { ExpectationSync On } } To enable expectation synchronization for all helpers. 2) Make sure you have loaded the FTP helper in both firewalls. root@fw1# modprobe nf_conntrack_ftp root@fw2# modprobe nf_conntrack_ftp 3) Switch to the client. Start one FTP control connection to one server that is protected by the firewalls, enter passive mode: (term-1) user@client$ nc 192.168.1.2 21 220 dummy FTP server USER anonymous 331 Please specify the password. PASS nothing 230 Login successful. PASV 227 Entering Passive Mode (192,168,1,2,163,11). This means that port 163*256+11=41739 will be used for the data traffic. Read this if you are not familiar with the FTP protocol: http://www.freefire.org/articles/ftpexample.php 3) Switch to fw-1 (primary) to check that the expectation is in the internal cache. root@fw1# conntrackd -i exp proto=6 src=192.168.0.2 dst=192.168.1.2 sport=0 dport=41739 mask-src=255.255.255.255 mask-dst=255.255.255.255 sport=0 dport=65535 master-src=192.168.0.2 master-dst=192.168.1.2 sport=36390 dport=21 [active since 5s] 4) Switch to fw-2 (backup) to check that the expectation has been successfully replicated. root@fw2# conntrackd -e exp proto=6 src=192.168.0.2 dst=192.168.1.2 sport=0 dport=41739 mask-src=255.255.255.255 mask-dst=255.255.255.255 sport=0 dport=65535 master-src=192.168.0.2 master-dst=192.168.1.2 sport=36390 dport=21 [active since 8s] 5) Make the primary firewall fw-1 fail. Now fw-2 becomes primary. 6) Switch to fw-2 (primary) to commit the external cache into the kernel. root@fw2# conntrackd -c exp The logs should display that the commit was successful: root@fw2# tail -100f /var/log/conntrackd.log [Wed Dec 7 22:16:31 2011] (pid=19195) [notice] committing external cache: expectations [Wed Dec 7 22:16:31 2011] (pid=19195) [notice] Committed 1 new entries [Wed Dec 7 22:16:31 2011] (pid=19195) [notice] commit has taken 0.000366 seconds 7) Switch to the client. Open a new terminal and connect to the port that has been announced by the server: (term-2) user@client$ nc -vvv 192.168.1.2 41739 (UNKNOWN) [192.168.1.2] 41739 (?) open 8) Switch to term-1 and ask for the file listing: [...] 227 Entering Passive Mode (192,168,1,2,163,11). LIST 9) Switch to term-2, it should display the listing. That means everything has worked fine. You may want to try disabling the expectation support and repeating the steps to check that *it does not work* without the state-synchronization. You can also display expectation statistics by means of: root@fwX# conntrackd -s exp This update requires no changes in the primary-backup.sh script that is used by the HA manager to interact with conntrackd. Thus, we provide a backward compatible command line interface. Regarding the Filter clause and expectations, we use the master conntrack to filter expectation events. The filtering is performed in user-space. No kernel-space filtering support for expectations yet (this support should go in libnetfilter_conntrack at some point). This patch also includes support to disable caching and to allow direct injection of expectations. Signed-off-by: Pablo Neira Ayuso --- configure.ac | 2 +- conntrackd.8 | 12 +- doc/sync/alarm/conntrackd.conf | 16 ++ doc/sync/ftfw/conntrackd.conf | 16 ++ doc/sync/notrack/conntrackd.conf | 16 ++ include/cache.h | 4 + include/conntrackd.h | 19 +++ include/external.h | 11 ++ include/filter.h | 7 + include/internal.h | 17 +++ include/log.h | 2 + include/netlink.h | 7 + include/network.h | 40 ++++- src/Makefile.am | 2 +- src/build.c | 99 +++++++++++++ src/cache-ct.c | 6 +- src/cache-exp.c | 308 +++++++++++++++++++++++++++++++++++++++ src/external_cache.c | 85 +++++++++++ src/external_inject.c | 95 +++++++++++- src/filter.c | 76 ++++++++++ src/internal_bypass.c | 146 ++++++++++++++++++- src/internal_cache.c | 173 ++++++++++++++++++++++ src/log.c | 37 +++++ src/main.c | 69 +++++++-- src/netlink.c | 63 +++++++- src/network.c | 5 + src/parse.c | 192 ++++++++++++++++++++++++ src/read_config_lex.l | 1 + src/read_config_yy.y | 50 ++++++- src/run.c | 206 +++++++++++++++++++++++--- src/sync-ftfw.c | 7 +- src/sync-mode.c | 165 ++++++++++++++++++--- src/sync-notrack.c | 6 +- 33 files changed, 1889 insertions(+), 71 deletions(-) create mode 100644 src/cache-exp.c (limited to 'include/network.h') diff --git a/configure.ac b/configure.ac index 0481e23..26a7e02 100644 --- a/configure.ac +++ b/configure.ac @@ -52,7 +52,7 @@ else fi PKG_CHECK_MODULES([LIBNFNETLINK], [libnfnetlink >= 1.0.0]) -PKG_CHECK_MODULES([LIBNETFILTER_CONNTRACK], [libnetfilter_conntrack >= 0.9.1]) +PKG_CHECK_MODULES([LIBNETFILTER_CONNTRACK], [libnetfilter_conntrack >= 1.0.0]) AC_CHECK_HEADERS([linux/capability.h],, [AC_MSG_ERROR([Cannot find linux/capabibility.h])]) diff --git a/conntrackd.8 b/conntrackd.8 index 0c9054e..f07ad7a 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -24,10 +24,10 @@ Run conntrackd in daemon mode. .B conntrackd can be used in client mode to request several information and operations to a running daemon .TP -.BI "-i " +.BI "-i "[ct|expect]" Dump the internal cache, i.e. show local states .TP -.BI "-e " +.BI "-e "[ct|expect]" Dump the external cache, i.e. show foreign states .TP .BI "-x " @@ -37,7 +37,7 @@ with "-i" and "-e" parameters. .BI "-f " "[|internal|external]" Flush the internal and/or external cache .TP -.BI "-F " +.BI "-F [ct|expect]" Flush the kernel conntrack table (if you use a Linux kernel >= 2.6.29, this option will not flush your internal and external cache). .TP @@ -48,15 +48,17 @@ ask conntrackd to send the state-entries that it owns to others. .BI "-k " Kill the daemon .TP -.BI "-s " "[|network|cache|runtime|link|rsqueue|process|queue]" +.BI "-s " "[|network|cache|runtime|link|rsqueue|process|queue|ct|expect]" Dump statistics. If no parameter is passed, it displays the general statistics. If "network" is passed as parameter it displays the networking statistics. If "cache" is passed as parameter, it shows the extended cache statistics. If "runtime" is passed as parameter, it shows the run-time statistics. If "process" is passed as parameter, it shows existing child processes (if any). If "queue" is passed as parameter, it shows queue statistics. +If "ct" is passed, it displays the general statistics. +If "expect" is passed as parameter, it shows expectation statistics. .TP -.BI "-R " +.BI "-R " "[ct|expect]" Force a resync against the kernel connection tracking table .TP .BI "-t " diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index d05b499..deed291 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -191,6 +191,22 @@ Sync { # This feature requires a Linux kernel >= 2.6.36. # # TCPWindowTracking Off + + # Set this option on if you want to enable the synchronization + # of expectations. You have to specify the list of helpers that + # you want to enable. Default is off. + # + # ExpectationSync { + # ftp + # h323 + # sip + # } + # + # You can use this alternatively: + # + # ExpectationSync On + # + # If you want to synchronize expectations of all helpers. # } } diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index c52f214..0304f0f 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -214,6 +214,22 @@ Sync { # This feature requires a Linux kernel >= 2.6.36. # # TCPWindowTracking Off + + # Set this option on if you want to enable the synchronization + # of expectations. You have to specify the list of helpers that + # you want to enable. Default is off. + # + # ExpectationSync { + # ftp + # h323 + # sip + # } + # + # You can use this alternatively: + # + # ExpectationSync On + # + # If you want to synchronize expectations of all helpers. # } } diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 4d77266..34e7b32 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -253,6 +253,22 @@ Sync { # This feature requires a Linux kernel >= 2.6.36. # # TCPWindowTracking Off + + # Set this option on if you want to enable the synchronization + # of expectations. You have to specify the list of helpers that + # you want to enable. Default is off. + # + # ExpectationSync { + # ftp + # h323 + # sip + # } + # + # You can use this alternatively: + # + # ExpectationSync On + # + # If you want to synchronize expectations of all helpers. # } } diff --git a/include/cache.h b/include/cache.h index abebb97..3af2741 100644 --- a/include/cache.h +++ b/include/cache.h @@ -52,6 +52,7 @@ extern struct cache_feature timer_feature; enum cache_type { CACHE_T_NONE = 0, CACHE_T_CT, + CACHE_T_EXP, CACHE_T_MAX }; @@ -128,6 +129,9 @@ struct cache_ops { extern struct cache_ops cache_sync_internal_ct_ops; extern struct cache_ops cache_sync_external_ct_ops; extern struct cache_ops cache_stats_ct_ops; +/* templates to configure expectation caching. */ +extern struct cache_ops cache_sync_internal_exp_ops; +extern struct cache_ops cache_sync_external_exp_ops; struct nf_conntrack; diff --git a/include/conntrackd.h b/include/conntrackd.h index 697d3d7..8baa088 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -37,6 +37,16 @@ #define CT_FLUSH_EXT_CACHE 34 /* flush external cache */ #define STATS_PROCESS 35 /* child process stats */ #define STATS_QUEUE 36 /* queue stats */ +#define EXP_STATS 37 /* dump statistics */ +#define EXP_FLUSH_MASTER 38 /* flush kernel expect table */ +#define EXP_RESYNC_MASTER 39 /* resync with kernel exp table */ +#define EXP_DUMP_INTERNAL 40 /* dump internal expect cache */ +#define EXP_DUMP_EXTERNAL 41 /* dump external expect cache */ +#define EXP_COMMIT 42 /* commit expectations */ +#define ALL_FLUSH_MASTER 43 /* flush all kernel tables */ +#define ALL_RESYNC_MASTER 44 /* resync w/all kernel tables */ +#define ALL_FLUSH_CACHE 45 /* flush all caches */ +#define ALL_COMMIT 46 /* commit all tables */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" @@ -56,6 +66,7 @@ #define CTD_SYNC_ALARM (1UL << 3) #define CTD_SYNC_NOTRACK (1UL << 4) #define CTD_POLL (1UL << 5) +#define CTD_EXPECT (1UL << 6) /* FILENAME_MAX is 4096 on my system, perhaps too much? */ #ifndef FILENAME_MAXLEN @@ -105,6 +116,8 @@ struct ct_conf { int tcp_window_tracking; } sync; struct { + int subsys_id; + int groups; int events_reliable; } netlink; struct { @@ -130,6 +143,7 @@ struct ct_general_state { struct local_server local; struct ct_mode *mode; struct ct_filter *us_filter; + struct exp_filter *exp_filter; struct nfct_handle *event; /* event handler */ struct nfct_filter *filter; /* event filter */ @@ -177,6 +191,10 @@ struct ct_general_state { } stats; }; +struct commit_runqueue { + int (*cb)(struct nfct_handle *h, int step); +}; + #define STATE_SYNC(x) state.sync->x struct ct_sync_state { @@ -196,6 +214,7 @@ struct ct_sync_state { struct nfct_handle *h; struct evfd *evfd; int current; + struct commit_runqueue rq[2]; struct { int ok; int fail; diff --git a/include/external.h b/include/external.h index eef0e42..70f0c5c 100644 --- a/include/external.h +++ b/include/external.h @@ -18,6 +18,17 @@ struct external_handler { void (*stats)(int fd); void (*stats_ext)(int fd); } ct; + struct { + void (*new)(struct nf_expect *exp); + void (*upd)(struct nf_expect *exp); + void (*del)(struct nf_expect *exp); + + void (*dump)(int fd, int type); + void (*flush)(void); + int (*commit)(struct nfct_handle *h, int fd); + void (*stats)(int fd); + void (*stats_ext)(int fd); + } exp; }; extern struct external_handler external_cache; diff --git a/include/filter.h b/include/filter.h index f19b18b..3c7c8cc 100644 --- a/include/filter.h +++ b/include/filter.h @@ -52,4 +52,11 @@ void ct_filter_set_logic(struct ct_filter *f, enum ct_filter_logic logic); int ct_filter_conntrack(const struct nf_conntrack *ct, int userspace); +struct exp_filter; +struct nf_expect; + +struct exp_filter *exp_filter_create(void); +int exp_filter_add(struct exp_filter *f, const char *helper_name); +int exp_filter_find(struct exp_filter *f, const struct nf_expect *exp); + #endif diff --git a/include/internal.h b/include/internal.h index f50eb79..2ba9714 100644 --- a/include/internal.h +++ b/include/internal.h @@ -34,6 +34,23 @@ struct internal_handler { void (*stats)(int fd); void (*stats_ext)(int fd); } ct; + struct { + void *data; + + void (*new)(struct nf_expect *exp, int origin_type); + void (*upd)(struct nf_expect *exp, int origin_type); + int (*del)(struct nf_expect *exp, int origin_type); + + void (*dump)(int fd, int type); + void (*populate)(struct nf_expect *exp); + void (*purge)(void); + int (*resync)(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data); + void (*flush)(void); + + void (*stats)(int fd); + void (*stats_ext)(int fd); + } exp; }; extern struct internal_handler internal_cache; diff --git a/include/log.h b/include/log.h index f5c5b4f..ae58e79 100644 --- a/include/log.h +++ b/include/log.h @@ -4,10 +4,12 @@ #include struct nf_conntrack; +struct nf_expect; int init_log(void); void dlog(int priority, const char *format, ...); void dlog_ct(FILE *fd, struct nf_conntrack *ct, unsigned int type); +void dlog_exp(FILE *fd, struct nf_expect *exp, unsigned int type); void close_log(void); #endif diff --git a/include/netlink.h b/include/netlink.h index 0df0cbb..3bde30c 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -30,4 +30,11 @@ static inline int ct_is_related(const struct nf_conntrack *ct) nfct_attr_is_set(ct, ATTR_MASTER_PORT_DST)); } +int nl_create_expect(struct nfct_handle *h, const struct nf_expect *orig, int timeout); +int nl_destroy_expect(struct nfct_handle *h, const struct nf_expect *exp); +int nl_get_expect(struct nfct_handle *h, const struct nf_expect *exp); +int nl_dump_expect_table(struct nfct_handle *h); +int nl_flush_expect_table(struct nfct_handle *h); +int nl_send_expect_resync(struct nfct_handle *h); + #endif diff --git a/include/network.h b/include/network.h index d0531b9..ab95499 100644 --- a/include/network.h +++ b/include/network.h @@ -4,9 +4,10 @@ #include #include -#define CONNTRACKD_PROTOCOL_VERSION 0 +#define CONNTRACKD_PROTOCOL_VERSION 1 struct nf_conntrack; +struct nf_expect; struct nethdr { #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -28,7 +29,10 @@ enum nethdr_type { NET_T_STATE_CT_NEW = 0, NET_T_STATE_CT_UPD, NET_T_STATE_CT_DEL, - NET_T_STATE_MAX = NET_T_STATE_CT_DEL, + NET_T_STATE_EXP_NEW = 3, + NET_T_STATE_EXP_UPD, + NET_T_STATE_EXP_DEL, + NET_T_STATE_MAX = NET_T_STATE_EXP_DEL, NET_T_CTL = 10, }; @@ -92,6 +96,17 @@ enum { __hdr; \ }) +#define BUILD_NETMSG_FROM_EXP(exp, query) \ +({ \ + static char __net[4096]; \ + struct nethdr *__hdr = (struct nethdr *) __net; \ + memset(__hdr, 0, NETHDR_SIZ); \ + nethdr_set(__hdr, query); \ + exp2msg(exp, __hdr); \ + HDR_HOST2NETWORK(__hdr); \ + __hdr; \ +}) + struct mcast_sock_multi; enum { @@ -239,4 +254,25 @@ struct nta_attr_natseqadj { void ct2msg(const struct nf_conntrack *ct, struct nethdr *n); int msg2ct(struct nf_conntrack *ct, struct nethdr *n, size_t remain); +enum nta_exp_attr { + NTA_EXP_MASTER_IPV4 = 0, /* struct nfct_attr_grp_ipv4 */ + NTA_EXP_MASTER_IPV6, /* struct nfct_attr_grp_ipv6 */ + NTA_EXP_MASTER_L4PROTO, /* uint8_t */ + NTA_EXP_MASTER_PORT, /* struct nfct_attr_grp_port */ + NTA_EXP_EXPECT_IPV4 = 4, /* struct nfct_attr_grp_ipv4 */ + NTA_EXP_EXPECT_IPV6, /* struct nfct_attr_grp_ipv6 */ + NTA_EXP_EXPECT_L4PROTO, /* uint8_t */ + NTA_EXP_EXPECT_PORT, /* struct nfct_attr_grp_port */ + NTA_EXP_MASK_IPV4 = 8, /* struct nfct_attr_grp_ipv4 */ + NTA_EXP_MASK_IPV6, /* struct nfct_attr_grp_ipv6 */ + NTA_EXP_MASK_L4PROTO, /* uint8_t */ + NTA_EXP_MASK_PORT, /* struct nfct_attr_grp_port */ + NTA_EXP_TIMEOUT, /* uint32_t */ + NTA_EXP_FLAGS, /* uint32_t */ + NTA_EXP_MAX +}; + +void exp2msg(const struct nf_expect *exp, struct nethdr *n); +int msg2exp(struct nf_expect *exp, struct nethdr *n, size_t remain); + #endif diff --git a/src/Makefile.am b/src/Makefile.am index a0abeee..7d7b2ac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c udp.c netlink.c vector.c \ filter.c fds.c event.c process.c origin.c date.c \ - cache.c cache-ct.c \ + cache.c cache-ct.c cache-exp.c \ cache_timer.c \ sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ traffic_stats.c stats-mode.c \ diff --git a/src/build.c b/src/build.c index 9c3687c..3193884 100644 --- a/src/build.c +++ b/src/build.c @@ -224,3 +224,102 @@ void ct2msg(const struct nf_conntrack *ct, struct nethdr *n) if (nfct_attr_is_set_array(ct, nat_type, 6)) ct_build_natseqadj(ct, n); } + +static void +exp_build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n, int a) +{ + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, a, + sizeof(struct nfct_attr_grp_port)); +} + +static void +exp_build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n, int a) +{ + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, a, + sizeof(struct nfct_attr_grp_port)); +} + +static void +exp_build_l4proto_dccp(const struct nf_conntrack *ct, struct nethdr *n, int a) +{ + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, a, + sizeof(struct nfct_attr_grp_port)); +} + +static void +exp_build_l4proto_udp(const struct nf_conntrack *ct, struct nethdr *n, int a) +{ + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, a, + sizeof(struct nfct_attr_grp_port)); +} + +static struct exp_build_l4proto { + void (*build)(const struct nf_conntrack *, struct nethdr *n, int a); +} exp_l4proto_fcn[IPPROTO_MAX] = { + [IPPROTO_TCP] = { .build = exp_build_l4proto_tcp }, + [IPPROTO_SCTP] = { .build = exp_build_l4proto_sctp }, + [IPPROTO_DCCP] = { .build = exp_build_l4proto_dccp }, + [IPPROTO_UDP] = { .build = exp_build_l4proto_udp }, +}; + +static inline void +exp_build_u32(const struct nf_expect *exp, int a, struct nethdr *n, int b) +{ + uint32_t data = nfexp_get_attr_u32(exp, a); + data = htonl(data); + addattr(n, b, &data, sizeof(uint32_t)); +} + +void exp2msg(const struct nf_expect *exp, struct nethdr *n) +{ + const struct nf_conntrack *ct = nfexp_get_attr(exp, ATTR_EXP_MASTER); + uint8_t l4proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); + + /* master conntrack for this expectation. */ + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_EXP_MASTER_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_EXP_MASTER_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + } + ct_build_u8(ct, ATTR_L4PROTO, n, NTA_EXP_MASTER_L4PROTO); + + if (exp_l4proto_fcn[l4proto].build) + exp_l4proto_fcn[l4proto].build(ct, n, NTA_EXP_MASTER_PORT); + + /* the expectation itself. */ + ct = nfexp_get_attr(exp, ATTR_EXP_EXPECTED); + + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_EXP_EXPECT_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_EXP_EXPECT_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + } + ct_build_u8(ct, ATTR_L4PROTO, n, NTA_EXP_EXPECT_L4PROTO); + + if (exp_l4proto_fcn[l4proto].build) + exp_l4proto_fcn[l4proto].build(ct, n, NTA_EXP_EXPECT_PORT); + + /* mask for the expectation. */ + ct = nfexp_get_attr(exp, ATTR_EXP_MASK); + + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_EXP_MASK_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_EXP_MASK_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + } + ct_build_u8(ct, ATTR_L4PROTO, n, NTA_EXP_MASK_L4PROTO); + + if (exp_l4proto_fcn[l4proto].build) + exp_l4proto_fcn[l4proto].build(ct, n, NTA_EXP_MASK_PORT); + + if (!CONFIG(commit_timeout) && nfexp_attr_is_set(exp, ATTR_EXP_TIMEOUT)) + exp_build_u32(exp, ATTR_EXP_TIMEOUT, n, NTA_EXP_TIMEOUT); + + exp_build_u32(exp, ATTR_EXP_FLAGS, n, NTA_EXP_FLAGS); +} diff --git a/src/cache-ct.c b/src/cache-ct.c index 2c6fd4e..0ad8d2a 100644 --- a/src/cache-ct.c +++ b/src/cache-ct.c @@ -251,7 +251,7 @@ static int cache_ct_commit(struct cache *c, struct nfct_handle *h, int clientfd) /* we already have one commit in progress, skip this. The clientfd * descriptor has to be closed by the caller. */ if (clientfd && STATE_SYNC(commit).clientfd != -1) - return 0; + return -1; switch(STATE_SYNC(commit).state) { case COMMIT_STATE_INACTIVE: @@ -308,9 +308,7 @@ static int cache_ct_commit(struct cache *c, struct nfct_handle *h, int clientfd) STATE_SYNC(commit).current = 0; STATE_SYNC(commit).state = COMMIT_STATE_INACTIVE; - /* Close the client socket now that we're done. */ - close(STATE_SYNC(commit).clientfd); - STATE_SYNC(commit).clientfd = -1; + return 0; } return 1; } diff --git a/src/cache-exp.c b/src/cache-exp.c new file mode 100644 index 0000000..e88877a --- /dev/null +++ b/src/cache-exp.c @@ -0,0 +1,308 @@ +/* + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cache.h" +#include "hash.h" +#include "log.h" +#include "conntrackd.h" +#include "netlink.h" +#include "event.h" +#include "jhash.h" +#include "network.h" + +#include +#include +#include +#include + +static uint32_t +cache_hash4_exp(const struct nf_conntrack *ct, const struct hashtable *table) +{ + uint32_t a[4] = { + [0] = nfct_get_attr_u32(ct, ATTR_IPV4_SRC), + [1] = nfct_get_attr_u32(ct, ATTR_IPV4_DST), + [2] = nfct_get_attr_u8(ct, ATTR_L3PROTO) << 16 | + nfct_get_attr_u8(ct, ATTR_L4PROTO), + [3] = nfct_get_attr_u16(ct, ATTR_PORT_SRC) << 16 | + nfct_get_attr_u16(ct, ATTR_PORT_DST), + }; + + /* + * Instead of returning hash % table->hashsize (implying a divide) + * we return the high 32 bits of the (hash * table->hashsize) that will + * give results between [0 and hashsize-1] and same hash distribution, + * but using a multiply, less expensive than a divide. See: + * http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html + */ + return ((uint64_t)jhash2(a, 4, 0) * table->hashsize) >> 32; +} + +static uint32_t +cache_hash6_exp(const struct nf_conntrack *ct, const struct hashtable *table) +{ + uint32_t a[10]; + + memcpy(&a[0], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); + memcpy(&a[4], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); + a[8] = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16 | + nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); + a[9] = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16 | + nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST); + + return ((uint64_t)jhash2(a, 10, 0) * table->hashsize) >> 32; +} + +static uint32_t +cache_exp_hash(const void *data, const struct hashtable *table) +{ + int ret = 0; + const struct nf_expect *exp = data; + const struct nf_conntrack *ct = nfexp_get_attr(exp, ATTR_EXP_MASTER); + + switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { + case AF_INET: + ret = cache_hash4_exp(ct, table); + break; + case AF_INET6: + ret = cache_hash6_exp(ct, table); + break; + default: + dlog(LOG_ERR, "unknown layer 3 proto in hash"); + break; + } + return ret; +} + +static int cache_exp_cmp(const void *data1, const void *data2) +{ + const struct cache_object *obj = data1; + const struct nf_expect *exp = data2; + + return nfexp_cmp(obj->ptr, exp, 0); +} + +static void *cache_exp_alloc(void) +{ + return nfexp_new(); +} + +static void cache_exp_free(void *ptr) +{ + nfexp_destroy(ptr); +} + +static void cache_exp_copy(void *dst, void *src, unsigned int flags) +{ + /* XXX: add nfexp_copy(...) to libnetfilter_conntrack. */ + memcpy(dst, src, nfexp_maxsize()); +} + +static int cache_exp_dump_step(void *data1, void *n) +{ + char buf[1024]; + int size; + struct __dump_container *container = data1; + struct cache_object *obj = n; + char *data = obj->data; + unsigned i; + + /* + * XXX: Do not dump the entries that are scheduled to expire. + * These entries talk about already destroyed connections + * that we keep for some time just in case that we have to + * resent some lost messages. We do not show them to the + * user as he may think that the firewall replicas are not + * in sync. The branch below is a hack as it is quite + * specific and it breaks conntrackd modularity. Probably + * there's a nicer way to do this but until I come up with it... + */ + if (CONFIG(flags) & CTD_SYNC_FTFW && obj->status == C_OBJ_DEAD) + return 0; + + /* do not show cached timeout, this may confuse users */ + if (nfexp_attr_is_set(obj->ptr, ATTR_EXP_TIMEOUT)) + nfexp_attr_unset(obj->ptr, ATTR_EXP_TIMEOUT); + + memset(buf, 0, sizeof(buf)); + size = nfexp_snprintf(buf, sizeof(buf),obj->ptr, + NFCT_T_UNKNOWN, container->type, 0); + + for (i = 0; i < obj->cache->num_features; i++) { + if (obj->cache->features[i]->dump) { + size += obj->cache->features[i]->dump(obj, data, + buf+size, + container->type); + data += obj->cache->features[i]->size; + } + } + if (container->type != NFCT_O_XML) { + long tm = time(NULL); + size += sprintf(buf+size, " [active since %lds]", + tm - obj->lifetime); + } + size += sprintf(buf+size, "\n"); + if (send(container->fd, buf, size, 0) == -1) { + if (errno != EPIPE) + return -1; + } + + return 0; +} + +static int cache_exp_commit_step(void *data, void *n) +{ + struct cache_object *obj = n; + struct __commit_container *tmp = data; + int ret, retry = 1, timeout; + struct nf_expect *exp = obj->ptr; + + if (CONFIG(commit_timeout)) { + timeout = CONFIG(commit_timeout); + } else { + timeout = time(NULL) - obj->lastupdate; + if (timeout < 0) { + /* XXX: Arbitrarily set the timer to one minute, how + * can this happen? For example, an adjustment due to + * daylight-saving. Probably other situations can + * trigger this. */ + timeout = 60; + } + /* calculate an estimation of the current timeout */ + timeout = nfexp_get_attr_u32(exp, ATTR_EXP_TIMEOUT) - timeout; + if (timeout < 0) { + timeout = 60; + } + } + +retry: + if (nl_create_expect(tmp->h, exp, timeout) == -1) { + if (errno == EEXIST && retry == 1) { + ret = nl_destroy_expect(tmp->h, exp); + if (ret == 0 || (ret == -1 && errno == ENOENT)) { + if (retry) { + retry = 0; + goto retry; + } + } + dlog(LOG_ERR, "commit-destroy: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + tmp->c->stats.commit_fail++; + } else { + dlog(LOG_ERR, "commit-create: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + tmp->c->stats.commit_fail++; + } + } else { + tmp->c->stats.commit_ok++; + } + /* keep iterating even if we have found errors */ + return 0; +} + +static int +cache_exp_commit(struct cache *c, struct nfct_handle *h, int clientfd) +{ + unsigned int commit_ok, commit_fail; + struct timeval commit_stop, res; + struct __commit_container tmp = { + .h = h, + .c = c, + }; + + /* we already have one commit in progress, skip this. The clientfd + * descriptor has to be closed by the caller. */ + if (clientfd && STATE_SYNC(commit).clientfd != -1) + return -1; + + switch(STATE_SYNC(commit).state) { + case COMMIT_STATE_INACTIVE: + gettimeofday(&STATE_SYNC(commit).stats.start, NULL); + STATE_SYNC(commit).stats.ok = c->stats.commit_ok; + STATE_SYNC(commit).stats.fail = c->stats.commit_fail; + STATE_SYNC(commit).clientfd = clientfd; + case COMMIT_STATE_MASTER: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, + STATE_SYNC(commit).current, + CONFIG(general).commit_steps, + cache_exp_commit_step); + if (STATE_SYNC(commit).current < CONFIG(hashsize)) { + STATE_SYNC(commit).state = COMMIT_STATE_MASTER; + /* give it another step as soon as possible */ + write_evfd(STATE_SYNC(commit).evfd); + return 1; + } + + /* calculate the time that commit has taken */ + gettimeofday(&commit_stop, NULL); + timersub(&commit_stop, &STATE_SYNC(commit).stats.start, &res); + + /* calculate new entries committed */ + commit_ok = c->stats.commit_ok - STATE_SYNC(commit).stats.ok; + commit_fail = + c->stats.commit_fail - STATE_SYNC(commit).stats.fail; + + /* log results */ + dlog(LOG_NOTICE, "Committed %u new expectations", commit_ok); + + if (commit_fail) + dlog(LOG_NOTICE, "%u expectations can't be " + "committed", commit_fail); + + dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds", + res.tv_sec, res.tv_usec); + + /* prepare the state machine for new commits */ + STATE_SYNC(commit).current = 0; + STATE_SYNC(commit).state = COMMIT_STATE_INACTIVE; + + return 0; + } + return 1; +} + +static struct nethdr * +cache_exp_build_msg(const struct cache_object *obj, int type) +{ + return BUILD_NETMSG_FROM_EXP(obj->ptr, type); +} + +/* template to cache expectations coming from the kernel. */ +struct cache_ops cache_sync_internal_exp_ops = { + .hash = cache_exp_hash, + .cmp = cache_exp_cmp, + .alloc = cache_exp_alloc, + .free = cache_exp_free, + .copy = cache_exp_copy, + .dump_step = cache_exp_dump_step, + .commit = NULL, + .build_msg = cache_exp_build_msg, +}; + +/* template to cache expectations coming from the network. */ +struct cache_ops cache_sync_external_exp_ops = { + .hash = cache_exp_hash, + .cmp = cache_exp_cmp, + .alloc = cache_exp_alloc, + .free = cache_exp_free, + .copy = cache_exp_copy, + .dump_step = cache_exp_dump_step, + .commit = cache_exp_commit, + .build_msg = NULL, +}; diff --git a/src/external_cache.c b/src/external_cache.c index 3f896a0..e290249 100644 --- a/src/external_cache.c +++ b/src/external_cache.c @@ -26,6 +26,7 @@ #include static struct cache *external; +static struct cache *external_exp; static int external_cache_init(void) { @@ -36,12 +37,21 @@ static int external_cache_init(void) dlog(LOG_ERR, "can't allocate memory for the external cache"); return -1; } + external_exp = cache_create("external", CACHE_T_EXP, + STATE_SYNC(sync)->external_cache_flags, + NULL, &cache_sync_external_exp_ops); + if (external_exp == NULL) { + dlog(LOG_ERR, "can't allocate memory for the external cache"); + return -1; + } + return 0; } static void external_cache_close(void) { cache_destroy(external); + cache_destroy(external_exp); } static void external_cache_ct_new(struct nf_conntrack *ct) @@ -109,6 +119,71 @@ static void external_cache_ct_stats_ext(int fd) cache_stats_extended(external, fd); } +static void external_cache_exp_new(struct nf_expect *exp) +{ + struct cache_object *obj; + int id; + + obj = cache_find(external_exp, exp, &id); + if (obj == NULL) { +retry: + obj = cache_object_new(external_exp, exp); + if (obj == NULL) + return; + + if (cache_add(external_exp, obj, id) == -1) { + cache_object_free(obj); + return; + } + } else { + cache_del(external_exp, obj); + cache_object_free(obj); + goto retry; + } +} + +static void external_cache_exp_upd(struct nf_expect *exp) +{ + cache_update_force(external_exp, exp); +} + +static void external_cache_exp_del(struct nf_expect *exp) +{ + struct cache_object *obj; + int id; + + obj = cache_find(external_exp, exp, &id); + if (obj) { + cache_del(external_exp, obj); + cache_object_free(obj); + } +} + +static void external_cache_exp_dump(int fd, int type) +{ + cache_dump(external_exp, fd, type); +} + +static int external_cache_exp_commit(struct nfct_handle *h, int fd) +{ + return cache_commit(external_exp, h, fd); +} + +static void external_cache_exp_flush(void) +{ + cache_flush(external_exp); +} + +static void external_cache_exp_stats(int fd) +{ + cache_stats(external_exp, fd); +} + +static void external_cache_exp_stats_ext(int fd) +{ + cache_stats_extended(external_exp, fd); +} + struct external_handler external_cache = { .init = external_cache_init, .close = external_cache_close, @@ -122,4 +197,14 @@ struct external_handler external_cache = { .stats = external_cache_ct_stats, .stats_ext = external_cache_ct_stats_ext, }, + .exp = { + .new = external_cache_exp_new, + .upd = external_cache_exp_upd, + .del = external_cache_exp_del, + .dump = external_cache_exp_dump, + .commit = external_cache_exp_commit, + .flush = external_cache_exp_flush, + .stats = external_cache_exp_stats, + .stats_ext = external_cache_exp_stats_ext, + }, }; diff --git a/src/external_inject.c b/src/external_inject.c index ba5f3d1..0ad3478 100644 --- a/src/external_inject.c +++ b/src/external_inject.c @@ -42,7 +42,7 @@ struct { static int external_inject_init(void) { /* handler to directly inject conntracks into kernel-space */ - inject = nfct_open(CONNTRACK, 0); + inject = nfct_open(CONFIG(netlink).subsys_id, 0); if (inject == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -175,6 +175,89 @@ static void external_inject_ct_stats(int fd) send(fd, buf, size, 0); } +struct { + uint32_t add_ok; + uint32_t add_fail; + uint32_t upd_ok; + uint32_t upd_fail; + uint32_t del_ok; + uint32_t del_fail; +} exp_external_inject_stat; + +static void external_inject_exp_new(struct nf_expect *exp) +{ + int ret, retry = 1; + +retry: + if (nl_create_expect(inject, exp, 0) == -1) { + /* if the state entry exists, we delete and try again */ + if (errno == EEXIST && retry == 1) { + ret = nl_destroy_expect(inject, exp); + if (ret == 0 || (ret == -1 && errno == ENOENT)) { + if (retry) { + retry = 0; + goto retry; + } + } + exp_external_inject_stat.add_fail++; + dlog(LOG_ERR, "inject-add1: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + return; + } + exp_external_inject_stat.add_fail++; + dlog(LOG_ERR, "inject-add2: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + } else { + exp_external_inject_stat.add_ok++; + } +} + +static void external_inject_exp_del(struct nf_expect *exp) +{ + if (nl_destroy_expect(inject, exp) == -1) { + if (errno != ENOENT) { + exp_external_inject_stat.del_fail++; + dlog(LOG_ERR, "inject-del: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + } + } else { + exp_external_inject_stat.del_ok++; + } +} + +static void external_inject_exp_dump(int fd, int type) +{ +} + +static int external_inject_exp_commit(struct nfct_handle *h, int fd) +{ + /* close the commit socket. */ + return LOCAL_RET_OK; +} + +static void external_inject_exp_flush(void) +{ +} + +static void external_inject_exp_stats(int fd) +{ + char buf[512]; + int size; + + size = sprintf(buf, "external inject:\n" + "connections created:\t\t%12u\tfailed:\t%12u\n" + "connections updated:\t\t%12u\tfailed:\t%12u\n" + "connections destroyed:\t\t%12u\tfailed:\t%12u\n\n", + exp_external_inject_stat.add_ok, + exp_external_inject_stat.add_fail, + exp_external_inject_stat.upd_ok, + exp_external_inject_stat.upd_fail, + exp_external_inject_stat.del_ok, + exp_external_inject_stat.del_fail); + + send(fd, buf, size, 0); +} + struct external_handler external_inject = { .init = external_inject_init, .close = external_inject_close, @@ -188,4 +271,14 @@ struct external_handler external_inject = { .stats = external_inject_ct_stats, .stats_ext = external_inject_ct_stats, }, + .exp = { + .new = external_inject_exp_new, + .upd = external_inject_exp_new, + .del = external_inject_exp_del, + .dump = external_inject_exp_dump, + .commit = external_inject_exp_commit, + .flush = external_inject_exp_flush, + .stats = external_inject_exp_stats, + .stats_ext = external_inject_exp_stats, + }, }; diff --git a/src/filter.c b/src/filter.c index 746a9bb..e8515d6 100644 --- a/src/filter.c +++ b/src/filter.c @@ -405,3 +405,79 @@ int ct_filter_conntrack(const struct nf_conntrack *ct, int userspace) return 0; } + +struct exp_filter { + struct list_head list; +}; + +struct exp_filter *exp_filter_create(void) +{ + struct exp_filter *f; + + f = calloc(1, sizeof(struct exp_filter)); + if (f == NULL) + return NULL; + + INIT_LIST_HEAD(&f->list); + return f; +} + +struct exp_filter_item { + struct list_head head; + char helper_name[NFCT_HELPER_NAME_MAX]; +}; + +/* this is ugly, but it simplifies read_config_yy.y */ +static struct exp_filter *exp_filter_alloc(void) +{ + if (STATE(exp_filter) == NULL) { + STATE(exp_filter) = exp_filter_create(); + if (STATE(exp_filter) == NULL) { + fprintf(stderr, "Can't init expectation filtering!\n"); + return NULL; + } + } + return STATE(exp_filter);; +} + +int exp_filter_add(struct exp_filter *f, const char *helper_name) +{ + struct exp_filter_item *item; + + f = exp_filter_alloc(); + if (f == NULL) + return -1; + + list_for_each_entry(item, &f->list, head) { + if (strncmp(item->helper_name, helper_name, + NFCT_HELPER_NAME_MAX) == 0) { + return -1; + } + } + item = calloc(1, sizeof(struct exp_filter_item)); + if (item == NULL) + return -1; + + strncpy(item->helper_name, helper_name, NFCT_HELPER_NAME_MAX); + list_add(&item->head, &f->list); + return 0; +} + +int exp_filter_find(struct exp_filter *f, const struct nf_expect *exp) +{ + struct exp_filter_item *item; + + if (f == NULL) + return 0; + + list_for_each_entry(item, &f->list, head) { + const char *name = nfexp_get_attr(exp, ATTR_EXP_HELPER_NAME); + + /* we allow partial matching to support things like sip-PORT. */ + if (strncmp(item->helper_name, name, + strlen(item->helper_name)) == 0) { + return 1; + } + } + return 0; +} diff --git a/src/internal_bypass.c b/src/internal_bypass.c index 98717f3..5c83c21 100644 --- a/src/internal_bypass.c +++ b/src/internal_bypass.c @@ -52,7 +52,7 @@ static void internal_bypass_ct_dump(int fd, int type) u_int32_t family = AF_UNSPEC; int ret; - h = nfct_open(CONNTRACK, 0); + h = nfct_open(CONFIG(netlink).subsys_id, 0); if (h == NULL) { dlog(LOG_ERR, "can't allocate memory for the internal cache"); return; @@ -151,6 +151,138 @@ static int internal_bypass_ct_event_del(struct nf_conntrack *ct, int origin) return 1; } +static int +internal_bypass_exp_dump_cb(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + char buf[1024]; + int size, *fd = data; + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + if (!exp_filter_find(STATE(exp_filter), exp)) + return NFCT_CB_CONTINUE; + + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + size = nfexp_snprintf(buf, 1024, exp, + NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0); + if (size < 1024) { + buf[size] = '\n'; + size++; + } + send(*fd, buf, size, 0); + + return NFCT_CB_CONTINUE; +} + +static void internal_bypass_exp_dump(int fd, int type) +{ + struct nfct_handle *h; + u_int32_t family = AF_UNSPEC; + int ret; + + h = nfct_open(CONFIG(netlink).subsys_id, 0); + if (h == NULL) { + dlog(LOG_ERR, "can't allocate memory for the internal cache"); + return; + } + nfexp_callback_register(h, NFCT_T_ALL, + internal_bypass_exp_dump_cb, &fd); + ret = nfexp_query(h, NFCT_Q_DUMP, &family); + if (ret == -1) { + dlog(LOG_ERR, "can't dump kernel table"); + } + nfct_close(h); +} + +static void internal_bypass_exp_flush(void) +{ + nl_flush_expect_table(STATE(flush)); +} + +struct { + uint32_t new; + uint32_t upd; + uint32_t del; +} exp_internal_bypass_stats; + +static void internal_bypass_exp_stats(int fd) +{ + char buf[512]; + int size; + + size = sprintf(buf, "internal bypass:\n" + "connections new:\t\t%12u\n" + "connections updated:\t\t%12u\n" + "connections destroyed:\t\t%12u\n\n", + exp_internal_bypass_stats.new, + exp_internal_bypass_stats.upd, + exp_internal_bypass_stats.del); + + send(fd, buf, size, 0); +} + +/* unused, INTERNAL_F_POPULATE is unset. No cache, nothing to populate. */ +static void internal_bypass_exp_populate(struct nf_expect *exp) +{ +} + +/* unused, INTERNAL_F_RESYNC is unset. */ +static void internal_bypass_exp_purge(void) +{ +} + +/* unused, INTERNAL_F_RESYNC is unset. Nothing to resync, we have no cache. */ +static int +internal_bypass_exp_resync(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + return NFCT_CB_CONTINUE; +} + +static void internal_bypass_exp_event_new(struct nf_expect *exp, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return; + + net = BUILD_NETMSG_FROM_EXP(exp, NET_T_STATE_EXP_NEW); + multichannel_send(STATE_SYNC(channel), net); + exp_internal_bypass_stats.new++; +} + +static void internal_bypass_exp_event_upd(struct nf_expect *exp, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return; + + net = BUILD_NETMSG_FROM_EXP(exp, NET_T_STATE_EXP_UPD); + multichannel_send(STATE_SYNC(channel), net); + exp_internal_bypass_stats.upd++; +} + +static int internal_bypass_exp_event_del(struct nf_expect *exp, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return 1; + + net = BUILD_NETMSG_FROM_EXP(exp, NET_T_STATE_EXP_DEL); + multichannel_send(STATE_SYNC(channel), net); + exp_internal_bypass_stats.del++; + + return 1; +} + struct internal_handler internal_bypass = { .init = internal_bypass_init, .close = internal_bypass_close, @@ -166,4 +298,16 @@ struct internal_handler internal_bypass = { .upd = internal_bypass_ct_event_upd, .del = internal_bypass_ct_event_del, }, + .exp = { + .dump = internal_bypass_exp_dump, + .flush = internal_bypass_exp_flush, + .stats = internal_bypass_exp_stats, + .stats_ext = internal_bypass_exp_stats, + .populate = internal_bypass_exp_populate, + .purge = internal_bypass_exp_purge, + .resync = internal_bypass_exp_resync, + .new = internal_bypass_exp_event_new, + .upd = internal_bypass_exp_event_upd, + .del = internal_bypass_exp_event_del, + }, }; diff --git a/src/internal_cache.c b/src/internal_cache.c index 952327d..ba2d74b 100644 --- a/src/internal_cache.c +++ b/src/internal_cache.c @@ -32,12 +32,25 @@ static int internal_cache_init(void) dlog(LOG_ERR, "can't allocate memory for the internal cache"); return -1; } + + STATE(mode)->internal->exp.data = + cache_create("internal", CACHE_T_EXP, + STATE_SYNC(sync)->internal_cache_flags, + STATE_SYNC(sync)->internal_cache_extra, + &cache_sync_internal_exp_ops); + + if (!STATE(mode)->internal->exp.data) { + dlog(LOG_ERR, "can't allocate memory for the internal cache"); + return -1; + } + return 0; } static void internal_cache_close(void) { cache_destroy(STATE(mode)->internal->ct.data); + cache_destroy(STATE(mode)->internal->exp.data); } static void internal_cache_ct_dump(int fd, int type) @@ -203,6 +216,154 @@ static int internal_cache_ct_event_del(struct nf_conntrack *ct, int origin) return 1; } +static void internal_cache_exp_dump(int fd, int type) +{ + cache_dump(STATE(mode)->internal->exp.data, fd, type); +} + +static void internal_cache_exp_flush(void) +{ + cache_flush(STATE(mode)->internal->exp.data); +} + +static void internal_cache_exp_stats(int fd) +{ + cache_stats(STATE(mode)->internal->exp.data, fd); +} + +static void internal_cache_exp_stats_ext(int fd) +{ + cache_stats_extended(STATE(mode)->internal->exp.data, fd); +} + +static void internal_cache_exp_populate(struct nf_expect *exp) +{ + cache_update_force(STATE(mode)->internal->exp.data, exp); +} + +static int internal_cache_exp_purge_step(void *data1, void *data2) +{ + struct cache_object *obj = data2; + + STATE(get_retval) = 0; + nl_get_expect(STATE(get), obj->ptr); /* modifies STATE(get_reval) */ + if (!STATE(get_retval)) { + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + sync_send(obj, NET_T_STATE_EXP_DEL); + cache_object_put(obj); + } + } + + return 0; +} + +static void internal_cache_exp_purge(void) +{ + cache_iterate(STATE(mode)->internal->exp.data, NULL, + internal_cache_exp_purge_step); +} + +static int +internal_cache_exp_resync(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + struct cache_object *obj; + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + if (!exp_filter_find(STATE(exp_filter), exp)) + return NFCT_CB_CONTINUE; + + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + obj = cache_update_force(STATE(mode)->internal->exp.data, exp); + if (obj == NULL) + return NFCT_CB_CONTINUE; + + switch (obj->status) { + case C_OBJ_NEW: + sync_send(obj, NET_T_STATE_EXP_NEW); + break; + case C_OBJ_ALIVE: + sync_send(obj, NET_T_STATE_EXP_UPD); + break; + } + return NFCT_CB_CONTINUE; +} + +static void internal_cache_exp_event_new(struct nf_expect *exp, int origin) +{ + struct cache_object *obj; + int id; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return; + + obj = cache_find(STATE(mode)->internal->exp.data, exp, &id); + if (obj == NULL) { +retry: + obj = cache_object_new(STATE(mode)->internal->exp.data, exp); + if (obj == NULL) + return; + if (cache_add(STATE(mode)->internal->exp.data, obj, id) == -1) { + cache_object_free(obj); + return; + } + /* only synchronize events that have been triggered by other + * processes or the kernel, but don't propagate events that + * have been triggered by conntrackd itself, eg. commits. */ + if (origin == CTD_ORIGIN_NOT_ME) + sync_send(obj, NET_T_STATE_EXP_NEW); + } else { + cache_del(STATE(mode)->internal->exp.data, obj); + cache_object_free(obj); + goto retry; + } +} + +static void internal_cache_exp_event_upd(struct nf_expect *exp, int origin) +{ + struct cache_object *obj; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return; + + obj = cache_update_force(STATE(mode)->internal->exp.data, exp); + if (obj == NULL) + return; + + if (origin == CTD_ORIGIN_NOT_ME) + sync_send(obj, NET_T_STATE_EXP_UPD); +} + +static int internal_cache_exp_event_del(struct nf_expect *exp, int origin) +{ + struct cache_object *obj; + int id; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return 0; + + /* we don't synchronize events for objects that are not in the cache */ + obj = cache_find(STATE(mode)->internal->exp.data, exp, &id); + if (obj == NULL) + return 0; + + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + if (origin == CTD_ORIGIN_NOT_ME) { + sync_send(obj, NET_T_STATE_EXP_DEL); + } + cache_object_put(obj); + } + return 1; +} + struct internal_handler internal_cache = { .flags = INTERNAL_F_POPULATE | INTERNAL_F_RESYNC, .init = internal_cache_init, @@ -219,4 +380,16 @@ struct internal_handler internal_cache = { .upd = internal_cache_ct_event_upd, .del = internal_cache_ct_event_del, }, + .exp = { + .dump = internal_cache_exp_dump, + .flush = internal_cache_exp_flush, + .stats = internal_cache_exp_stats, + .stats_ext = internal_cache_exp_stats_ext, + .populate = internal_cache_exp_populate, + .purge = internal_cache_exp_purge, + .resync = internal_cache_exp_resync, + .new = internal_cache_exp_event_new, + .upd = internal_cache_exp_event_upd, + .del = internal_cache_exp_event_del, + }, }; diff --git a/src/log.c b/src/log.c index 9fe5119..d4de111 100644 --- a/src/log.c +++ b/src/log.c @@ -145,6 +145,43 @@ void dlog_ct(FILE *fd, struct nf_conntrack *ct, unsigned int type) } } +void dlog_exp(FILE *fd, struct nf_expect *exp, unsigned int type) +{ + time_t t; + char buf[1024]; + char *tmp; + unsigned int flags = 0; + + buf[0]='\0'; + + switch(type) { + case NFCT_O_PLAIN: + t = time(NULL); + ctime_r(&t, buf); + tmp = buf + strlen(buf); + buf[strlen(buf)-1]='\t'; + break; + default: + return; + } + nfexp_snprintf(buf+strlen(buf), 1024-strlen(buf), exp, 0, type, flags); + + if (fd) { + snprintf(buf+strlen(buf), 1024-strlen(buf), "\n"); + fputs(buf, fd); + } + + if (fd == STATE(log)) { + /* error reporting */ + if (CONFIG(syslog_facility) != -1) + syslog(LOG_ERR, "%s", tmp); + } else if (fd == STATE(stats_log)) { + /* connection logging */ + if (CONFIG(stats).syslog_facility != -1) + syslog(LOG_INFO, "%s", tmp); + } +} + void close_log(void) { if (STATE(log) != NULL) diff --git a/src/main.c b/src/main.c index ebfc8b9..342ed45 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,6 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. * * 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 @@ -38,14 +39,15 @@ static const char usage_daemon_commands[] = static const char usage_client_commands[] = "Client mode commands:\n" - " -c, commit external cache to conntrack table\n" + " -c [ct|expect], commit external cache to conntrack table\n" " -f [|internal|external], flush internal and external cache\n" - " -F, flush kernel conntrack table\n" - " -i, display content of the internal cache\n" - " -e, display the content of the external cache\n" + " -F [ct|expect], flush kernel conntrack table\n" + " -i [ct|expect], display content of the internal cache\n" + " -e [ct|expect], display the content of the external cache\n" " -k, kill conntrack daemon\n" - " -s [|network|cache|runtime|link|rsqueue|queue], dump statistics\n" - " -R, resync with kernel conntrack table\n" + " -s [|network|cache|runtime|link|rsqueue|queue|ct|expect], " + "dump statistics\n" + " -R [ct|expect], resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)\n" " -t, reset the kernel timeout (see PurgeTimeout clause)\n" @@ -89,6 +91,25 @@ set_operation_mode(int *current, int want, char *argv[]) } } +static int +set_action_by_table(int i, int argc, char *argv[], + int ct_action, int exp_action, int dfl_action, int *action) +{ + if (i+1 < argc && argv[i+1][0] != '-') { + if (strncmp(argv[i+1], "ct", strlen(argv[i+1])) == 0) { + *action = ct_action; + i++; + } else if (strncmp(argv[i+1], "expect", + strlen(argv[i+1])) == 0) { + *action = exp_action; + i++; + } + } else + *action = dfl_action; + + return i; +} + int main(int argc, char *argv[]) { int ret, i, action = -1; @@ -115,15 +136,23 @@ int main(int argc, char *argv[]) break; case 'c': set_operation_mode(&type, REQUEST, argv); - action = CT_COMMIT; + i = set_action_by_table(i, argc, argv, + CT_COMMIT, EXP_COMMIT, + ALL_COMMIT, &action); break; case 'i': set_operation_mode(&type, REQUEST, argv); - action = CT_DUMP_INTERNAL; + i = set_action_by_table(i, argc, argv, + CT_DUMP_INTERNAL, + EXP_DUMP_INTERNAL, + CT_DUMP_INTERNAL, &action); break; case 'e': set_operation_mode(&type, REQUEST, argv); - action = CT_DUMP_EXTERNAL; + i = set_action_by_table(i, argc, argv, + CT_DUMP_EXTERNAL, + EXP_DUMP_EXTERNAL, + CT_DUMP_EXTERNAL, &action); break; case 'C': if (++i < argc) { @@ -142,7 +171,10 @@ int main(int argc, char *argv[]) break; case 'F': set_operation_mode(&type, REQUEST, argv); - action = CT_FLUSH_MASTER; + i = set_action_by_table(i, argc, argv, + CT_FLUSH_MASTER, + EXP_FLUSH_MASTER, + ALL_FLUSH_MASTER, &action); break; case 'f': set_operation_mode(&type, REQUEST, argv); @@ -164,12 +196,15 @@ int main(int argc, char *argv[]) } } else { /* default to general flushing */ - action = CT_FLUSH_CACHE; + action = ALL_FLUSH_CACHE; } break; case 'R': set_operation_mode(&type, REQUEST, argv); - action = CT_RESYNC_MASTER; + i = set_action_by_table(i, argc, argv, + CT_RESYNC_MASTER, + EXP_RESYNC_MASTER, + ALL_RESYNC_MASTER, &action); break; case 'B': set_operation_mode(&type, REQUEST, argv); @@ -222,6 +257,14 @@ int main(int argc, char *argv[]) strlen(argv[i+1])) == 0) { action = STATS_QUEUE; i++; + } else if (strncmp(argv[i+1], "ct", + strlen(argv[i+1])) == 0) { + action = STATS; + i++; + } else if (strncmp(argv[i+1], "expect", + strlen(argv[i+1])) == 0) { + action = EXP_STATS; + i++; } else { fprintf(stderr, "ERROR: unknown " "parameter `%s' for " diff --git a/src/netlink.c b/src/netlink.c index 60274f3..fe979e3 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -1,5 +1,6 @@ /* - * (C) 2006 by Pablo Neira Ayuso + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. * * 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 @@ -32,7 +33,7 @@ struct nfct_handle *nl_init_event_handler(void) { struct nfct_handle *h; - h = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); + h = nfct_open(CONFIG(netlink).subsys_id, CONFIG(netlink).groups); if (h == NULL) return NULL; @@ -301,3 +302,61 @@ int nl_destroy_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) { return nfct_query(h, NFCT_Q_DESTROY, ct); } + +int nl_create_expect(struct nfct_handle *h, const struct nf_expect *orig, + int timeout) +{ + int ret; + struct nf_expect *exp; + + exp = nfexp_clone(orig); + if (exp == NULL) + return -1; + + if (timeout > 0) + nfexp_set_attr_u32(exp, ATTR_EXP_TIMEOUT, timeout); + + ret = nfexp_query(h, NFCT_Q_CREATE, exp); + nfexp_destroy(exp); + + return ret; +} + +int nl_destroy_expect(struct nfct_handle *h, const struct nf_expect *exp) +{ + return nfexp_query(h, NFCT_Q_DESTROY, exp); +} + +/* if the handle has no callback, check for existence, otherwise, update */ +int nl_get_expect(struct nfct_handle *h, const struct nf_expect *exp) +{ + int ret = 1; + struct nf_expect *tmp; + + /* XXX: we only need the expectation, not the mask and the master. */ + tmp = nfexp_clone(exp); + if (tmp == NULL) + return -1; + + if (nfexp_query(h, NFCT_Q_GET, tmp) == -1) + ret = (errno == ENOENT) ? 0 : -1; + + nfexp_destroy(tmp); + return ret; +} + +int nl_dump_expect_table(struct nfct_handle *h) +{ + return nfexp_query(h, NFCT_Q_DUMP, &CONFIG(family)); +} + +int nl_flush_expect_table(struct nfct_handle *h) +{ + return nfexp_query(h, NFCT_Q_FLUSH, &CONFIG(family)); +} + +int nl_send_expect_resync(struct nfct_handle *h) +{ + int family = CONFIG(family); + return nfexp_send(h, NFCT_Q_DUMP, &family); +} diff --git a/src/network.c b/src/network.c index cadc466..13db37c 100644 --- a/src/network.c +++ b/src/network.c @@ -126,6 +126,11 @@ static int status2type[CACHE_T_MAX][C_OBJ_MAX] = { [C_OBJ_ALIVE] = NET_T_STATE_CT_UPD, [C_OBJ_DEAD] = NET_T_STATE_CT_DEL, }, + [CACHE_T_EXP] = { + [C_OBJ_NEW] = NET_T_STATE_EXP_NEW, + [C_OBJ_ALIVE] = NET_T_STATE_EXP_UPD, + [C_OBJ_DEAD] = NET_T_STATE_EXP_DEL, + }, }; int object_status_to_network_type(struct cache_object *obj) diff --git a/src/parse.c b/src/parse.c index 0718128..81e9c6b 100644 --- a/src/parse.c +++ b/src/parse.c @@ -248,3 +248,195 @@ int msg2ct(struct nf_conntrack *ct, struct nethdr *net, size_t remain) return 0; } + +static void exp_parse_ct_group(void *ct, int attr, void *data); +static void exp_parse_ct_u8(void *ct, int attr, void *data); +static void exp_parse_u32(void *exp, int attr, void *data); + +static struct exp_parser { + void (*parse)(void *obj, int attr, void *data); + int exp_attr; + int ct_attr; + int size; +} exp_h[NTA_EXP_MAX] = { + [NTA_EXP_MASTER_IPV4] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_EXP_MASTER_IPV6] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_EXP_MASTER_L4PROTO] = { + .parse = exp_parse_ct_u8, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_EXP_MASTER_PORT] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_EXP_EXPECT_IPV4] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_EXP_EXPECT_IPV6] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_EXP_EXPECT_L4PROTO] = { + .parse = exp_parse_ct_u8, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_EXP_EXPECT_PORT] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_EXP_MASK_IPV4] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_EXP_MASK_IPV6] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_EXP_MASK_L4PROTO] = { + .parse = exp_parse_ct_u8, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_EXP_MASK_PORT] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_EXP_TIMEOUT] = { + .parse = exp_parse_u32, + .exp_attr = ATTR_EXP_TIMEOUT, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_EXP_FLAGS] = { + .parse = exp_parse_u32, + .exp_attr = ATTR_EXP_FLAGS, + .size = NTA_SIZE(sizeof(uint32_t)), + }, +}; + +static void exp_parse_ct_group(void *ct, int attr, void *data) +{ + nfct_set_attr_grp(ct, exp_h[attr].ct_attr, data); +} + +static void exp_parse_ct_u8(void *ct, int attr, void *data) +{ + uint8_t *value = (uint8_t *) data; + nfct_set_attr_u8(ct, exp_h[attr].ct_attr, *value); +} + +static void exp_parse_u32(void *exp, int attr, void *data) +{ + uint32_t *value = (uint32_t *) data; + nfexp_set_attr_u32(exp, exp_h[attr].exp_attr, ntohl(*value)); +} + +int msg2exp(struct nf_expect *exp, struct nethdr *net, size_t remain) +{ + int len; + struct netattr *attr; + struct nf_conntrack *master, *expected, *mask; + + if (remain < net->len) + return -1; + + len = net->len - NETHDR_SIZ; + attr = NETHDR_DATA(net); + + master = nfct_new(); + if (master == NULL) + goto err_master; + + expected = nfct_new(); + if (expected == NULL) + goto err_expected; + + mask = nfct_new(); + if (mask == NULL) + goto err_mask; + + while (len > ssizeof(struct netattr)) { + ATTR_NETWORK2HOST(attr); + if (attr->nta_len > len) + goto err; + if (attr->nta_attr > NTA_MAX) + goto err; + if (attr->nta_len != exp_h[attr->nta_attr].size) + goto err; + if (exp_h[attr->nta_attr].parse == NULL) { + attr = NTA_NEXT(attr, len); + continue; + } + switch(exp_h[attr->nta_attr].exp_attr) { + case ATTR_EXP_MASTER: + exp_h[attr->nta_attr].parse(master, attr->nta_attr, + NTA_DATA(attr)); + case ATTR_EXP_EXPECTED: + exp_h[attr->nta_attr].parse(expected, attr->nta_attr, + NTA_DATA(attr)); + case ATTR_EXP_MASK: + exp_h[attr->nta_attr].parse(mask, attr->nta_attr, + NTA_DATA(attr)); + break; + case ATTR_EXP_TIMEOUT: + case ATTR_EXP_FLAGS: + exp_h[attr->nta_attr].parse(exp, attr->nta_attr, + NTA_DATA(attr)); + break; + } + attr = NTA_NEXT(attr, len); + } + + nfexp_set_attr(exp, ATTR_EXP_MASTER, master); + nfexp_set_attr(exp, ATTR_EXP_EXPECTED, expected); + nfexp_set_attr(exp, ATTR_EXP_MASK, mask); + + /* We can release the conntrack objects at this point because the + * setter makes a copy of them. This is not efficient, it would be + * better to save that extra copy but this is how the library works. + * I'm sorry, I cannot change it without breaking backward + * compatibility. Probably it is a good idea to think of adding new + * interfaces in the near future to get it better. */ + nfct_destroy(mask); + nfct_destroy(expected); + nfct_destroy(master); + + return 0; +err: + nfct_destroy(mask); +err_mask: + nfct_destroy(expected); +err_expected: + nfct_destroy(master); +err_master: + return -1; +} diff --git a/src/read_config_lex.l b/src/read_config_lex.l index be6bf8b..01fe4fc 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -140,6 +140,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "DisableExternalCache" { return T_DISABLE_EXTERNAL_CACHE; } "Options" { return T_OPTIONS; } "TCPWindowTracking" { return T_TCP_WINDOW_TRACKING; } +"ExpectationSync" { return T_EXPECT_SYNC; } "ErrorQueueLength" { return T_ERROR_QUEUE_LENGTH; } {is_on} { return T_ON; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 68a83f7..b22784c 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -73,7 +73,7 @@ static void __max_dedicated_links_reached(void); %token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR %token T_SCHEDULER T_TYPE T_PRIO T_NETLINK_EVENTS_RELIABLE %token T_DISABLE_INTERNAL_CACHE T_DISABLE_EXTERNAL_CACHE T_ERROR_QUEUE_LENGTH -%token T_OPTIONS T_TCP_WINDOW_TRACKING +%token T_OPTIONS T_TCP_WINDOW_TRACKING T_EXPECT_SYNC %token T_IP T_PATH_VAL %token T_NUMBER @@ -828,6 +828,46 @@ option: T_TCP_WINDOW_TRACKING T_OFF CONFIG(sync).tcp_window_tracking = 0; }; +option: T_EXPECT_SYNC T_ON +{ + CONFIG(flags) |= CTD_EXPECT; + CONFIG(netlink).subsys_id = NFNL_SUBSYS_NONE; + CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY | + NF_NETLINK_CONNTRACK_EXP_NEW | + NF_NETLINK_CONNTRACK_EXP_UPDATE | + NF_NETLINK_CONNTRACK_EXP_DESTROY; +}; + +option: T_EXPECT_SYNC T_OFF +{ + CONFIG(netlink).subsys_id = NFNL_SUBSYS_CTNETLINK; + CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY; +}; + +option: T_EXPECT_SYNC '{' expect_list '}' +{ + CONFIG(flags) |= CTD_EXPECT; + CONFIG(netlink).subsys_id = NFNL_SUBSYS_NONE; + CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY | + NF_NETLINK_CONNTRACK_EXP_NEW | + NF_NETLINK_CONNTRACK_EXP_UPDATE | + NF_NETLINK_CONNTRACK_EXP_DESTROY; +}; + +expect_list: + | expect_list expect_item ; + +expect_item: T_STRING +{ + exp_filter_add(STATE(exp_filter), $1); +} + sync_mode_alarm: T_SYNC_MODE T_ALARM '{' sync_mode_alarm_list '}' { conf.flags |= CTD_SYNC_ALARM; @@ -1598,6 +1638,7 @@ init_config(char *filename) /* Zero may be a valid facility */ CONFIG(syslog_facility) = -1; CONFIG(stats).syslog_facility = -1; + CONFIG(netlink).subsys_id = -1; yyrestart(fp); yyparse(); @@ -1646,5 +1687,12 @@ init_config(char *filename) if (CONFIG(channelc).error_queue_length == 0) CONFIG(channelc).error_queue_length = 128; + if (CONFIG(netlink).subsys_id == -1) { + CONFIG(netlink).subsys_id = NFNL_SUBSYS_CTNETLINK; + CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY; + } + return 0; } diff --git a/src/run.c b/src/run.c index c21db2e..26c1783 100644 --- a/src/run.c +++ b/src/run.c @@ -187,6 +187,62 @@ static void dump_stats_runtime(int fd) send(fd, buf, size, 0); } +static void local_flush_master(void) +{ + STATE(stats).nl_kernel_table_flush++; + dlog(LOG_NOTICE, "flushing kernel conntrack table"); + + /* fork a child process that performs the flush operation, + * meanwhile the parent process handles events. */ + if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL, + NULL, NULL) == 0) { + nl_flush_conntrack_table(STATE(flush)); + exit(EXIT_SUCCESS); + } +} + +static void local_resync_master(void) +{ + if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { + STATE(stats).nl_kernel_table_resync++; + dlog(LOG_NOTICE, "resync with master conntrack table"); + nl_dump_conntrack_table(STATE(dump)); + } else { + dlog(LOG_NOTICE, "resync is unsupported in this mode"); + } +} + +static void local_exp_flush_master(void) +{ + if (!(CONFIG(flags) & CTD_EXPECT)) + return; + + STATE(stats).nl_kernel_table_flush++; + dlog(LOG_NOTICE, "flushing kernel expect table"); + + /* fork a child process that performs the flush operation, + * meanwhile the parent process handles events. */ + if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL, + NULL, NULL) == 0) { + nl_flush_expect_table(STATE(flush)); + exit(EXIT_SUCCESS); + } +} + +static void local_exp_resync_master(void) +{ + if (!(CONFIG(flags) & CTD_EXPECT)) + return; + + if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { + STATE(stats).nl_kernel_table_resync++; + dlog(LOG_NOTICE, "resync with master expect table"); + nl_dump_expect_table(STATE(dump)); + } else { + dlog(LOG_NOTICE, "resync is unsupported in this mode"); + } +} + static int local_handler(int fd, void *data) { int ret = LOCAL_RET_OK; @@ -198,25 +254,24 @@ static int local_handler(int fd, void *data) } switch(type) { case CT_FLUSH_MASTER: - STATE(stats).nl_kernel_table_flush++; - dlog(LOG_NOTICE, "flushing kernel conntrack table"); - - /* fork a child process that performs the flush operation, - * meanwhile the parent process handles events. */ - if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL, - NULL, NULL) == 0) { - nl_flush_conntrack_table(STATE(flush)); - exit(EXIT_SUCCESS); - } + local_flush_master(); break; case CT_RESYNC_MASTER: - if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { - STATE(stats).nl_kernel_table_resync++; - dlog(LOG_NOTICE, "resync with master table"); - nl_dump_conntrack_table(STATE(dump)); - } else { - dlog(LOG_NOTICE, "resync is unsupported in this mode"); - } + local_resync_master(); + break; + case EXP_FLUSH_MASTER: + local_exp_flush_master(); + break; + case EXP_RESYNC_MASTER: + local_exp_resync_master(); + break; + case ALL_FLUSH_MASTER: + local_flush_master(); + local_exp_flush_master(); + break; + case ALL_RESYNC_MASTER: + local_resync_master(); + local_exp_resync_master(); break; case STATS_RUNTIME: dump_stats_runtime(fd); @@ -245,7 +300,11 @@ static void do_polling_alarm(struct alarm_block *a, void *data) if (STATE(mode)->internal->ct.purge) STATE(mode)->internal->ct.purge(); + if (STATE(mode)->internal->exp.purge) + STATE(mode)->internal->exp.purge(); + nl_send_resync(STATE(resync)); + nl_send_expect_resync(STATE(resync)); add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0); } @@ -290,6 +349,49 @@ out: return NFCT_CB_CONTINUE; } +static int exp_event_handler(const struct nlmsghdr *nlh, + enum nf_conntrack_msg_type type, + struct nf_expect *exp, + void *data) +{ + int origin_type; + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + STATE(stats).nl_events_received++; + + if (!exp_filter_find(STATE(exp_filter), exp)) { + STATE(stats).nl_events_filtered++; + goto out; + } + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + origin_type = origin_find(nlh); + + switch(type) { + case NFCT_T_NEW: + STATE(mode)->internal->exp.new(exp, origin_type); + break; + case NFCT_T_UPDATE: + STATE(mode)->internal->exp.upd(exp, origin_type); + break; + case NFCT_T_DESTROY: + STATE(mode)->internal->exp.del(exp, origin_type); + break; + default: + STATE(stats).nl_events_unknown_type++; + break; + } + +out: + /* we reset the iteration limiter in the main select loop. */ + if (STATE(event_iterations_limit)-- <= 0) + return NFCT_CB_STOP; + else + return NFCT_CB_CONTINUE; +} + static int dump_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) @@ -308,6 +410,29 @@ static int dump_handler(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } +static int exp_dump_handler(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + if (!exp_filter_find(STATE(exp_filter), exp)) + return NFCT_CB_CONTINUE; + + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + switch(type) { + case NFCT_T_UPDATE: + STATE(mode)->internal->exp.populate(exp); + break; + default: + STATE(stats).nl_dump_unknown_type++; + break; + } + return NFCT_CB_CONTINUE; +} + static int get_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) @@ -319,6 +444,22 @@ static int get_handler(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } +static int exp_get_handler(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + if (!exp_filter_find(STATE(exp_filter), exp)) + return NFCT_CB_CONTINUE; + + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + STATE(get_retval) = 1; + return NFCT_CB_CONTINUE; +} + int init(void) { @@ -355,7 +496,7 @@ init(void) register_fd(STATE(local).fd, STATE(fds)); /* resynchronize (like 'dump' socket) but it also purges old entries */ - STATE(resync) = nfct_open(CONNTRACK, 0); + STATE(resync) = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE(resync)== NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -370,7 +511,7 @@ init(void) fcntl(nfct_fd(STATE(resync)), F_SETFL, O_NONBLOCK); if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { - STATE(dump) = nfct_open(CONNTRACK, 0); + STATE(dump) = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE(dump) == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -380,13 +521,26 @@ init(void) nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL); + if (CONFIG(flags) & CTD_EXPECT) { + nfexp_callback_register(STATE(dump), NFCT_T_ALL, + exp_dump_handler, NULL); + } + if (nl_dump_conntrack_table(STATE(dump)) == -1) { dlog(LOG_ERR, "can't get kernel conntrack table"); return -1; } + + if (CONFIG(flags) & CTD_EXPECT) { + if (nl_dump_expect_table(STATE(dump)) == -1) { + dlog(LOG_ERR, "can't get kernel " + "expect table"); + return -1; + } + } } - STATE(get) = nfct_open(CONNTRACK, 0); + STATE(get) = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE(get) == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -395,7 +549,12 @@ init(void) } nfct_callback_register(STATE(get), NFCT_T_ALL, get_handler, NULL); - STATE(flush) = nfct_open(CONNTRACK, 0); + if (CONFIG(flags) & CTD_EXPECT) { + nfexp_callback_register(STATE(get), NFCT_T_ALL, + exp_get_handler, NULL); + } + + STATE(flush) = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE(flush) == NULL) { dlog(LOG_ERR, "cannot open flusher handler"); return -1; @@ -426,6 +585,11 @@ init(void) } nfct_callback_register2(STATE(event), NFCT_T_ALL, event_handler, NULL); + + if (CONFIG(flags) & CTD_EXPECT) { + nfexp_callback_register2(STATE(event), NFCT_T_ALL, + exp_event_handler, NULL); + } register_fd(nfct_fd(STATE(event)), STATE(fds)); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index fa76c0c..1bc2d9f 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -231,6 +231,8 @@ static int ftfw_local(int fd, int type, void *data) dlog(LOG_NOTICE, "sending bulk update"); cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->exp.data, + NULL, do_cache_to_tx); break; case STATS_RSQUEUE: ftfw_local_queue(fd); @@ -350,7 +352,10 @@ static int digest_msg(const struct nethdr *net) } else if (IS_RESYNC(net)) { dp("RESYNC ALL\n"); - cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->ct.data, NULL, + do_cache_to_tx); + cache_iterate(STATE(mode)->internal->exp.data, NULL, + do_cache_to_tx); return MSG_CTL; } else if (IS_ALIVE(net)) diff --git a/src/sync-mode.c b/src/sync-mode.c index fa522c7..2505631 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -59,10 +59,29 @@ static struct nf_conntrack *msg2ct_alloc(struct nethdr *net, size_t remain) return ct; } +static struct nf_expect *msg2exp_alloc(struct nethdr *net, size_t remain) +{ + struct nf_expect *exp; + + /* TODO: add stats on ENOMEM errors in the future. */ + exp = nfexp_new(); + if (exp == NULL) + return NULL; + + if (msg2exp(exp, net, remain) == -1) { + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_payload++; + nfexp_destroy(exp); + return NULL; + } + return exp; +} + static void do_channel_handler_step(int i, struct nethdr *net, size_t remain) { - struct nf_conntrack *ct; + struct nf_conntrack *ct = NULL; + struct nf_expect *exp = NULL; if (net->version != CONNTRACKD_PROTOCOL_VERSION) { STATE_SYNC(error).msg_rcv_malformed++; @@ -112,12 +131,33 @@ do_channel_handler_step(int i, struct nethdr *net, size_t remain) return; STATE_SYNC(external)->ct.del(ct); break; + case NET_T_STATE_EXP_NEW: + exp = msg2exp_alloc(net, remain); + if (exp == NULL) + return; + STATE_SYNC(external)->exp.new(exp); + break; + case NET_T_STATE_EXP_UPD: + exp = msg2exp_alloc(net, remain); + if (exp == NULL) + return; + STATE_SYNC(external)->exp.upd(exp); + break; + case NET_T_STATE_EXP_DEL: + exp = msg2exp_alloc(net, remain); + if (exp == NULL) + return; + STATE_SYNC(external)->exp.del(exp); + break; default: STATE_SYNC(error).msg_rcv_malformed++; STATE_SYNC(error).msg_rcv_bad_type++; break; } - nfct_destroy(ct); + if (ct != NULL) + nfct_destroy(ct); + if (exp != NULL) + nfexp_destroy(exp); } static char __net[65536]; /* XXX: maximum MTU for IPv4 */ @@ -351,7 +391,7 @@ static int init_sync(void) STATE(fds)) == -1) return -1; - STATE_SYNC(commit).h = nfct_open(CONNTRACK, 0); + STATE_SYNC(commit).h = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE_SYNC(commit).h == NULL) { dlog(LOG_ERR, "can't create handler to commit"); return -1; @@ -402,8 +442,30 @@ static void run_sync(fd_set *readfds) interface_handler(); if (FD_ISSET(get_read_evfd(STATE_SYNC(commit).evfd), readfds)) { + int ret; + read_evfd(STATE_SYNC(commit).evfd); - STATE_SYNC(external)->ct.commit(STATE_SYNC(commit).h, 0); + + ret = STATE_SYNC(commit).rq[0].cb(STATE_SYNC(commit).h, 0); + if (ret == 0) { + /* we still have things in the callback queue. */ + if (STATE_SYNC(commit).rq[1].cb) { + int fd = STATE_SYNC(commit).clientfd; + + STATE_SYNC(commit).rq[0].cb = + STATE_SYNC(commit).rq[1].cb; + + STATE_SYNC(commit).rq[1].cb = NULL; + + STATE_SYNC(commit).clientfd = -1; + STATE_SYNC(commit).rq[0].cb( + STATE_SYNC(commit).h, fd); + } else { + /* Close the client socket now, we're done. */ + close(STATE_SYNC(commit).clientfd); + STATE_SYNC(commit).clientfd = -1; + } + } } /* flush pending messages */ @@ -480,6 +542,27 @@ static void dump_stats_sync_extended(int fd) send(fd, buf, size, 0); } +static int local_commit(int fd) +{ + int ret; + + /* delete the reset alarm if any before committing */ + del_alarm(&STATE_SYNC(reset_cache_alarm)); + + ret = STATE_SYNC(commit).rq[0].cb(STATE_SYNC(commit).h, fd); + if (ret == -1) { + dlog(LOG_NOTICE, "commit already in progress, skipping"); + ret = LOCAL_RET_OK; + } else if (ret == 0) { + /* we've finished the commit. */ + ret = LOCAL_RET_OK; + } else { + /* Keep open the client, we want synchronous commit. */ + ret = LOCAL_RET_STOLEN; + } + return ret; +} + /* handler for requests coming via UNIX socket */ static int local_handler_sync(int fd, int type, void *data) { @@ -511,19 +594,10 @@ static int local_handler_sync(int fd, int type, void *data) } break; case CT_COMMIT: - /* delete the reset alarm if any before committing */ - del_alarm(&STATE_SYNC(reset_cache_alarm)); - - dlog(LOG_NOTICE, "committing external cache"); - ret = STATE_SYNC(external)->ct.commit(STATE_SYNC(commit).h, fd); - if (ret == 0) { - dlog(LOG_NOTICE, "commit already in progress, " - "skipping"); - ret = LOCAL_RET_OK; - } else { - /* Keep open the client, we want synchronous commit. */ - ret = LOCAL_RET_STOLEN; - } + dlog(LOG_NOTICE, "committing conntrack cache"); + STATE_SYNC(commit).rq[0].cb = STATE_SYNC(external)->ct.commit; + STATE_SYNC(commit).rq[1].cb = NULL; + ret = local_commit(fd); break; case RESET_TIMERS: if (!alarm_pending(&STATE_SYNC(reset_cache_alarm))) { @@ -575,6 +649,63 @@ static int local_handler_sync(int fd, int type, void *data) case STATS_QUEUE: queue_stats_show(fd); break; + case EXP_STATS: + if (!(CONFIG(flags) & CTD_EXPECT)) + break; + + STATE(mode)->internal->exp.stats(fd); + STATE_SYNC(external)->exp.stats(fd); + dump_traffic_stats(fd); + multichannel_stats(STATE_SYNC(channel), fd); + dump_stats_sync(fd); + break; + case EXP_DUMP_INTERNAL: + if (!(CONFIG(flags) & CTD_EXPECT)) + break; + + if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { + STATE(mode)->internal->exp.dump(fd, NFCT_O_PLAIN); + exit(EXIT_SUCCESS); + } + break; + case EXP_DUMP_EXTERNAL: + if (!(CONFIG(flags) & CTD_EXPECT)) + break; + + if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { + STATE_SYNC(external)->exp.dump(fd, NFCT_O_PLAIN); + exit(EXIT_SUCCESS); + } + break; + case EXP_COMMIT: + if (!(CONFIG(flags) & CTD_EXPECT)) + break; + + dlog(LOG_NOTICE, "committing expectation cache"); + STATE_SYNC(commit).rq[0].cb = STATE_SYNC(external)->exp.commit; + STATE_SYNC(commit).rq[1].cb = NULL; + local_commit(fd); + break; + case ALL_FLUSH_CACHE: + dlog(LOG_NOTICE, "flushing caches"); + STATE(mode)->internal->ct.flush(); + STATE_SYNC(external)->ct.flush(); + if (CONFIG(flags) & CTD_EXPECT) { + STATE(mode)->internal->exp.flush(); + STATE_SYNC(external)->exp.flush(); + } + break; + case ALL_COMMIT: + dlog(LOG_NOTICE, "committing all external caches"); + STATE_SYNC(commit).rq[0].cb = STATE_SYNC(external)->ct.commit; + if (CONFIG(flags) & CTD_EXPECT) { + STATE_SYNC(commit).rq[1].cb = + STATE_SYNC(external)->exp.commit; + } else { + STATE_SYNC(commit).rq[1].cb = NULL; + } + local_commit(fd); + break; default: if (STATE_SYNC(sync)->local) ret = STATE_SYNC(sync)->local(fd, type, data); diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 06ad1f0..a7df4e7 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -102,7 +102,7 @@ static void kernel_resync(void) u_int32_t family = AF_UNSPEC; int ret; - h = nfct_open(CONNTRACK, 0); + h = nfct_open(CONFIG(netlink).subsys_id, 0); if (h == NULL) { dlog(LOG_ERR, "can't allocate memory for the internal cache"); return; @@ -131,6 +131,8 @@ static int notrack_local(int fd, int type, void *data) } else { cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->exp.data, + NULL, do_cache_to_tx); } break; default: @@ -152,6 +154,8 @@ static int digest_msg(const struct nethdr *net) } else { cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->exp.data, + NULL, do_cache_to_tx); } return MSG_CTL; } -- cgit v1.2.3