diff options
author | /C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org </C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org> | 2007-11-25 18:08:02 +0000 |
---|---|---|
committer | /C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org </C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org> | 2007-11-25 18:08:02 +0000 |
commit | 3c5e35974c65f4470e6543c2cc772c0f1824dc44 (patch) | |
tree | 11fd67edbffc4c626af730738465108f965eb863 | |
parent | 66cd168df39bfcf581bb36250a080a66331ee5cd (diff) | |
download | conntrack-tools-3c5e35974c65f4470e6543c2cc772c0f1824dc44.tar.gz conntrack-tools-3c5e35974c65f4470e6543c2cc772c0f1824dc44.zip |
Add CacheWriteThrough clause: external cache write through policy. This feature is particularly useful for active-active setup without connection persistency, ie. you cannot know which firewall would filter a packet that belongs to a connection.
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | examples/sync/nack/node1/conntrackd.conf | 8 | ||||
-rw-r--r-- | examples/sync/nack/node2/conntrackd.conf | 8 | ||||
-rw-r--r-- | examples/sync/persistent/node1/conntrackd.conf | 8 | ||||
-rw-r--r-- | examples/sync/persistent/node2/conntrackd.conf | 8 | ||||
-rw-r--r-- | include/cache.h | 4 | ||||
-rw-r--r-- | include/conntrackd.h | 1 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/cache.c | 17 | ||||
-rw-r--r-- | src/cache_iterators.c | 21 | ||||
-rw-r--r-- | src/cache_wt.c | 53 | ||||
-rw-r--r-- | src/netlink.c | 31 | ||||
-rw-r--r-- | src/read_config_lex.l | 1 | ||||
-rw-r--r-- | src/read_config_yy.y | 13 | ||||
-rw-r--r-- | src/sync-mode.c | 22 |
15 files changed, 163 insertions, 35 deletions
@@ -7,6 +7,7 @@ o include kernel options and Fedora comments in the INSTALL file = conntrackd = o Remove window tracking disabling limitation (requires Linux kernel >= 2.6.22) o syslog support (based on patch from Simon Lodal) +o add CacheWriteThrough clause: external cache write through policy version 0.9.5 (2007/07/29) ------------------------------ diff --git a/examples/sync/nack/node1/conntrackd.conf b/examples/sync/nack/node1/conntrackd.conf index ef9eb4a..4fc8f22 100644 --- a/examples/sync/nack/node1/conntrackd.conf +++ b/examples/sync/nack/node1/conntrackd.conf @@ -47,6 +47,14 @@ Sync { # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. # # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On } # diff --git a/examples/sync/nack/node2/conntrackd.conf b/examples/sync/nack/node2/conntrackd.conf index c4d8a21..43ebd77 100644 --- a/examples/sync/nack/node2/conntrackd.conf +++ b/examples/sync/nack/node2/conntrackd.conf @@ -46,6 +46,14 @@ Sync { # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. # # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On } # diff --git a/examples/sync/persistent/node1/conntrackd.conf b/examples/sync/persistent/node1/conntrackd.conf index d240fbb..a55608b 100644 --- a/examples/sync/persistent/node1/conntrackd.conf +++ b/examples/sync/persistent/node1/conntrackd.conf @@ -52,6 +52,14 @@ Sync { # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. # # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On } # diff --git a/examples/sync/persistent/node2/conntrackd.conf b/examples/sync/persistent/node2/conntrackd.conf index d5a276e..32416d0 100644 --- a/examples/sync/persistent/node2/conntrackd.conf +++ b/examples/sync/persistent/node2/conntrackd.conf @@ -52,6 +52,14 @@ Sync { # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. # # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On } # diff --git a/include/cache.h b/include/cache.h index e755dbe..f5e9576 100644 --- a/include/cache.h +++ b/include/cache.h @@ -14,6 +14,9 @@ enum { LIFETIME_FEATURE = 2, LIFETIME = (1 << LIFETIME_FEATURE), + WRITE_THROUGH_FEATURE = 3, + WRITE_THROUGH = (1 << WRITE_THROUGH_FEATURE), + __CACHE_MAX_FEATURE }; #define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE @@ -31,6 +34,7 @@ struct cache_feature { extern struct cache_feature lifetime_feature; extern struct cache_feature timer_feature; +extern struct cache_feature writethrough_feature; #define CACHE_MAX_NAMELEN 32 diff --git a/include/conntrackd.h b/include/conntrackd.h index fc15ebe..2722f00 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -86,6 +86,7 @@ struct ct_conf { int family; /* protocol family */ unsigned int resend_buffer_size;/* NACK protocol */ unsigned int window_size; + int cache_write_through; }; #define STATE(x) st.x diff --git a/src/Makefile.am b/src/Makefile.am index 83511fa..8f5c620 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,7 +14,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ local.c log.c mcast.c netlink.c \ ignore_pool.c \ cache.c cache_iterators.c \ - cache_lifetime.c cache_timer.c \ + cache_lifetime.c cache_timer.c cache_wt.c \ sync-mode.c sync-notrack.c sync-nack.c \ traffic_stats.c stats-mode.c \ network.c \ diff --git a/src/cache.c b/src/cache.c index 1e20d95..80cde01 100644 --- a/src/cache.c +++ b/src/cache.c @@ -110,6 +110,7 @@ static int compare6(const void *data1, const void *data2) struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { [TIMER_FEATURE] = &timer_feature, [LIFETIME_FEATURE] = &lifetime_feature, + [WRITE_THROUGH_FEATURE] = &writethrough_feature, }; struct cache *cache_create(char *name, @@ -263,14 +264,6 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) int i; void *data = u->data; - for (i = 0; i < c->num_features; i++) { - c->features[i]->update(u, data); - data += c->features[i]->size; - } - - if (c->extra && c->extra->update) - c->extra->update(u, ((void *) u) + c->extra_offset); - if (nfct_attr_is_set(ct, ATTR_STATUS)) nfct_set_attr_u32(u->ct, ATTR_STATUS, nfct_get_attr_u32(ct, ATTR_STATUS)); @@ -281,6 +274,14 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) nfct_set_attr_u32(u->ct, ATTR_TIMEOUT, nfct_get_attr_u32(ct, ATTR_TIMEOUT)); + for (i = 0; i < c->num_features; i++) { + c->features[i]->update(u, data); + data += c->features[i]->size; + } + + if (c->extra && c->extra->update) + c->extra->update(u, ((void *) u) + c->extra_offset); + return u; } return NULL; diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 24506e4..c29100c 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -78,36 +78,17 @@ void cache_dump(struct cache *c, int fd, int type) static int do_commit(void *data1, void *data2) { int ret; - u_int8_t flags; struct cache *c = data1; struct us_conntrack *u = data2; 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); - } - - nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); - /* * Set a reduced timeout for candidate-to-be-committed * conntracks that live in the external cache */ nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); - /* - * TCP flags to overpass window tracking for recovered connections - */ - flags = IP_CT_TCP_FLAG_BE_LIBERAL | IP_CT_TCP_FLAG_SACK_PERM; - nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); - nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); - nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); - nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); - - ret = nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); + ret = nl_create_conntrack(ct); if (ret == -1) { switch(errno) { case EEXIST: diff --git a/src/cache_wt.c b/src/cache_wt.c new file mode 100644 index 0000000..2a9d8e7 --- /dev/null +++ b/src/cache_wt.c @@ -0,0 +1,53 @@ +/* + * (C) 2007 by Pablo Neira Ayuso <pablo@netfilter.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 <stdio.h> +#include "conntrackd.h" +#include "us-conntrack.h" +#include "cache.h" + +static void add_update(struct us_conntrack *u) +{ + char __ct[nfct_maxsize()]; + struct nf_conntrack *ct = (struct nf_conntrack *) __ct; + + memcpy(ct, u->ct, nfct_maxsize()); + + nl_create_conntrack(ct); +} + +static void writethrough_add(struct us_conntrack *u, void *data) +{ + add_update(u); +} + +static void writethrough_update(struct us_conntrack *u, void *data) +{ + add_update(u); +} + +static void writethrough_destroy(struct us_conntrack *u, void *data) +{ + nl_destroy_conntrack(u->ct); +} + +struct cache_feature writethrough_feature = { + .add = writethrough_add, + .update = writethrough_update, + .destroy = writethrough_destroy, +}; diff --git a/src/netlink.c b/src/netlink.c index 693646f..d453fe1 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -194,3 +194,34 @@ int nl_dump_conntrack_table(void) { return nfct_query(STATE(dump), NFCT_Q_DUMP, &CONFIG(family)); } + +/* This function modifies the conntrack passed as argument! */ +int nl_create_conntrack(struct nf_conntrack *ct) +{ + u_int8_t flags; + + /* 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); + } + + nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); + + /* + * TCP flags to overpass window tracking for recovered connections + */ + flags = IP_CT_TCP_FLAG_BE_LIBERAL | IP_CT_TCP_FLAG_SACK_PERM; + nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); + nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); + nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); + nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); + + return nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); +} + +int nl_destroy_conntrack(struct nf_conntrack *ct) +{ + return nfct_query(STATE(dump), NFCT_Q_DESTROY, ct); +} diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 48c0409..844cae1 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -90,6 +90,7 @@ nack [N|n][A|a][C|c][K|k] "ACKWindowSize" { return T_WINDOWSIZE; } "Replicate" { return T_REPLICATE; } "for" { return T_FOR; } +"CacheWriteThrough" { return T_WRITE_THROUGH; } "SYN_SENT" { return T_SYN_SENT; } "SYN_RECV" { return T_SYN_RECV; } "ESTABLISHED" { return T_ESTABLISHED; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 8bc83fe..e5ce195 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -49,7 +49,7 @@ struct ct_conf conf; %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 -%token T_SYSLOG +%token T_SYSLOG T_WRITE_THROUGH %token <string> T_IP T_PATH_VAL @@ -366,6 +366,7 @@ sync_line: refreshtime | sync_mode_nack | listen_to | state_replication + | cache_writethrough ; sync_mode_persistent: T_SYNC_MODE T_PERSISTENT '{' sync_mode_persistent_list '}' @@ -500,6 +501,16 @@ tcp_state: T_LISTEN state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LISTEN); }; +cache_writethrough: T_WRITE_THROUGH T_ON +{ + conf.cache_write_through = 1; +}; + +cache_writethrough: T_WRITE_THROUGH T_OFF +{ + conf.cache_write_through = 0; +}; + general: T_GENERAL '{' general_list '}'; general_list: diff --git a/src/sync-mode.c b/src/sync-mode.c index e48b121..8a19ac5 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -147,6 +147,10 @@ static int init_sync(void) return -1; } + /* straight forward commit of conntrack to kernel space */ + if (CONFIG(cache_write_through)) + STATE_SYNC(sync)->external_cache_flags |= WRITE_THROUGH; + STATE_SYNC(external) = cache_create("external", STATE_SYNC(sync)->external_cache_flags, @@ -301,8 +305,10 @@ static int local_handler_sync(int fd, int type, void *data) static void dump_sync(struct nf_conntrack *ct) { + if (!CONFIG(cache_write_through)) + nfct_attr_unset(ct, ATTR_TIMEOUT); + /* This is required by kernels < 2.6.20 */ - nfct_attr_unset(ct, ATTR_TIMEOUT); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); @@ -339,8 +345,10 @@ static int overrun_cb(enum nf_conntrack_msg_type type, if (ignore_conntrack(ct)) return NFCT_CB_CONTINUE; + if (!CONFIG(cache_write_through)) + nfct_attr_unset(ct, ATTR_TIMEOUT); + /* This is required by kernels < 2.6.20 */ - nfct_attr_unset(ct, ATTR_TIMEOUT); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); @@ -420,12 +428,14 @@ static void event_new_sync(struct nf_conntrack *ct) { struct us_conntrack *u; + if (!CONFIG(cache_write_through)) + nfct_attr_unset(ct, ATTR_TIMEOUT); + /* 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); - nfct_attr_unset(ct, ATTR_TIMEOUT); retry: if ((u = cache_add(STATE_SYNC(internal), ct))) { mcast_send_sync(u, ct, NFCT_Q_CREATE); @@ -447,7 +457,8 @@ static void event_update_sync(struct nf_conntrack *ct) { struct us_conntrack *u; - nfct_attr_unset(ct, ATTR_TIMEOUT); + if (!CONFIG(cache_write_through)) + nfct_attr_unset(ct, ATTR_TIMEOUT); if ((u = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { debug_ct(ct, "can't update"); @@ -459,7 +470,8 @@ static void event_update_sync(struct nf_conntrack *ct) static int event_destroy_sync(struct nf_conntrack *ct) { - nfct_attr_unset(ct, ATTR_TIMEOUT); + if (!CONFIG(cache_write_through)) + nfct_attr_unset(ct, ATTR_TIMEOUT); if (cache_del(STATE_SYNC(internal), ct)) { mcast_send_sync(NULL, ct, NFCT_Q_DESTROY); |