From 3c5e35974c65f4470e6543c2cc772c0f1824dc44 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sun, 25 Nov 2007 18:08:02 +0000 Subject: 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. --- src/Makefile.am | 2 +- src/cache.c | 17 +++++++++-------- src/cache_iterators.c | 21 +------------------- src/cache_wt.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/netlink.c | 31 ++++++++++++++++++++++++++++++ src/read_config_lex.l | 1 + src/read_config_yy.y | 13 ++++++++++++- src/sync-mode.c | 22 ++++++++++++++++----- 8 files changed, 125 insertions(+), 35 deletions(-) create mode 100644 src/cache_wt.c (limited to 'src') 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 + * + * 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 "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 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); -- cgit v1.2.3