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> | 2008-04-29 14:18:17 +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> | 2008-04-29 14:18:17 +0000 | 
| commit | ace1f6a61b6842e2b49ec7a08f368a2d9f433be0 (patch) | |
| tree | 92c62e1bf75ff98d949b8f71a0f79c948d1e544a /src | |
| parent | 96213d5f0821aee2fe52459ab2cd54569e50cf85 (diff) | |
| download | conntrack-tools-ace1f6a61b6842e2b49ec7a08f368a2d9f433be0.tar.gz conntrack-tools-ace1f6a61b6842e2b49ec7a08f368a2d9f433be0.zip | |
Fix reorder possible reordering of destroy messages under message omission. This patch introduces the TimeoutDestroy clause to determine how long a conntrack remains in the internal cache once it has been destroy from the kernel table.
Diffstat (limited to 'src')
| -rw-r--r-- | src/alarm.c | 5 | ||||
| -rw-r--r-- | src/cache.c | 81 | ||||
| -rw-r--r-- | src/cache_lifetime.c | 8 | ||||
| -rw-r--r-- | src/read_config_lex.l | 1 | ||||
| -rw-r--r-- | src/read_config_yy.y | 12 | ||||
| -rw-r--r-- | src/sync-ftfw.c | 13 | ||||
| -rw-r--r-- | src/sync-mode.c | 27 | 
7 files changed, 100 insertions, 47 deletions
| diff --git a/src/alarm.c b/src/alarm.c index 91ee2ca..fe938a0 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -123,7 +123,7 @@ do_alarm_run(struct timeval *next_run)  {  	struct list_head alarm_run_queue;  	struct rb_node *node; -	struct alarm_block *this; +	struct alarm_block *this, *tmp;  	struct timeval tv;  	gettimeofday(&tv, NULL); @@ -138,7 +138,8 @@ do_alarm_run(struct timeval *next_run)  		list_add(&this->list, &alarm_run_queue);  	} -	list_for_each_entry(this, &alarm_run_queue, list) { +	/* must be safe as entries can vanish from the callback */ +	list_for_each_entry_safe(this, tmp, &alarm_run_queue, list) {  		rb_erase(&this->node, &alarm_root);  		RB_CLEAR_NODE(&this->node);  		this->function(this, this->data); diff --git a/src/cache.c b/src/cache.c index 73d539a..eac9a78 100644 --- a/src/cache.c +++ b/src/cache.c @@ -237,6 +237,8 @@ void cache_destroy(struct cache *c)  	free(c);  } +static void __del_timeout(struct alarm_block *a, void *data); +  static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct)  {  	unsigned i; @@ -258,6 +260,8 @@ static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct)  	if (u) {  		char *data = u->data; +		init_alarm(&u->alarm, u, __del_timeout); +          	for (i = 0; i < c->num_features; i++) {  			c->features[i]->add(u, data);  			data += c->features[i]->size; @@ -324,8 +328,7 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct)  	return NULL;  } -static struct us_conntrack * -__cache_update(struct cache *c, struct nf_conntrack *ct) +struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct)  {  	struct us_conntrack *u; @@ -339,15 +342,6 @@ __cache_update(struct cache *c, struct nf_conntrack *ct)  	return NULL;  } -struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) -{ -	struct us_conntrack *u; - -	u = __cache_update(c, ct); - -	return u; -} -  struct us_conntrack *cache_update_force(struct cache *c,  					struct nf_conntrack *ct)  { @@ -379,6 +373,24 @@ int cache_test(struct cache *c, struct nf_conntrack *ct)  	return ret != NULL;  } +static void __del2(struct cache *c, struct us_conntrack *u) +{ +	unsigned i; +	char *data = u->data; +	struct nf_conntrack *p = u->ct; + +	for (i = 0; i < c->num_features; i++) { +		c->features[i]->destroy(u, data); +		data += c->features[i]->size; +	} + +	if (c->extra && c->extra->destroy) +		c->extra->destroy(u, ((char *) u) + c->extra_offset); + +	hashtable_del(c->h, u); +	free(p); +} +  static int __del(struct cache *c, struct nf_conntrack *ct)  {  	size_t size = c->h->datasize; @@ -389,20 +401,8 @@ static int __del(struct cache *c, struct nf_conntrack *ct)  	u = (struct us_conntrack *) hashtable_test(c->h, u);  	if (u) { -		unsigned i; -		char *data = u->data; -		struct nf_conntrack *p = u->ct; - -		for (i = 0; i < c->num_features; i++) { -			c->features[i]->destroy(u, data); -			data += c->features[i]->size; -		} - -		if (c->extra && c->extra->destroy) -			c->extra->destroy(u, ((char *) u) + c->extra_offset); - -		hashtable_del(c->h, u); -		free(p); +		del_alarm(&u->alarm); +		__del2(c, u);  		return 1;  	}  	return 0; @@ -419,6 +419,37 @@ int cache_del(struct cache *c, struct nf_conntrack *ct)  	return 0;  } +static void __del_timeout(struct alarm_block *a, void *data) +{ +	struct us_conntrack *u = (struct us_conntrack *) data; +	struct cache *c = u->cache; + +	__del2(u->cache, u); +	c->del_ok++; +} + +struct us_conntrack * +cache_del_timeout(struct cache *c, struct nf_conntrack *ct, int timeout) +{ +	size_t size = c->h->datasize; +	char buf[size]; +	struct us_conntrack *u = (struct us_conntrack *) buf; + +	if (timeout <= 0) +		cache_del(c, ct); + +	u->ct = ct; + +	u = (struct us_conntrack *) hashtable_test(c->h, u); +	if (u) { +		if (!alarm_pending(&u->alarm)) { +			add_alarm(&u->alarm, timeout, 0); +			return u; +		} +	} +	return NULL; +} +  struct us_conntrack *cache_get_conntrack(struct cache *c, void *data)  {  	return (struct us_conntrack *)((char*)data - c->extra_offset); diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c index ad3416a..cf84d20 100644 --- a/src/cache_lifetime.c +++ b/src/cache_lifetime.c @@ -53,7 +53,13 @@ static int lifetime_dump(struct us_conntrack *u,  	gettimeofday(&tv, NULL); -	return sprintf(buf, " [active since %lds]", tv.tv_sec - *lifetime); +	if (alarm_pending(&u->alarm)) +		return sprintf(buf, " [active since %lds] [expires in %lds]", +			       tv.tv_sec - *lifetime,  +			       u->alarm.tv.tv_sec - tv.tv_sec); +	else +		return sprintf(buf, " [active since %lds]",  +			       tv.tv_sec - *lifetime);  }  struct cache_feature lifetime_feature = { diff --git a/src/read_config_lex.l b/src/read_config_lex.l index fe2090b..1350afc 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -103,6 +103,7 @@ ftfw		[F|f][T|t][F|f][W|w]  "CLOSE"				{ return T_CLOSE; }  "LISTEN"			{ return T_LISTEN; }  "LogFileBufferSize"		{ return T_STAT_BUFFER_SIZE; } +"DestroyTimeout"		{ return T_DESTROY_TIMEOUT; }  {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 86fee9b..0bc5e3c 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -52,7 +52,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 T_WRITE_THROUGH T_STAT_BUFFER_SIZE +%token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT  %token <string> T_IP T_PATH_VAL @@ -429,6 +429,7 @@ sync_line: refreshtime  	 | listen_to  	 | state_replication  	 | cache_writethrough +	 | destroy_timeout  	 ;  sync_mode_alarm: T_SYNC_MODE T_ALARM '{' sync_mode_alarm_list '}' @@ -469,6 +470,11 @@ window_size: T_WINDOWSIZE T_NUMBER  	conf.window_size = $2;  }; +destroy_timeout: T_DESTROY_TIMEOUT T_NUMBER +{ +	conf.del_timeout = $2; +}; +  relax_transitions: T_RELAX_TRANSITIONS  {  	fprintf(stderr, "Notice: RelaxTransitions clause is obsolete. " @@ -746,5 +752,9 @@ init_config(char *filename)  	if (CONFIG(window_size) == 0)  		CONFIG(window_size) = 20; +	/* double of 120 seconds which is common timeout of a final state */ +	if (conf.flags & CTD_SYNC_FTFW && CONFIG(del_timeout) == 0) +		CONFIG(del_timeout) = 240; +  	return 0;  } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 0b98513..77f8fd4 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -390,6 +390,7 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u)  	switch(ntohs(pld->query)) {  	case NFCT_Q_CREATE:  	case NFCT_Q_UPDATE: +	case NFCT_Q_DESTROY:  		cn = (struct cache_ftfw *)   			cache_get_extra(STATE_SYNC(internal), u); @@ -402,9 +403,6 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u)  		list_add_tail(&cn->rs_list, &rs_list);  		rs_list_len++;  		break; -	case NFCT_Q_DESTROY: -		queue_add(rs_queue, net, net->len); -		break;  	}  } @@ -429,10 +427,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) +static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type)  {  	int ret; -	struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); +	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", @@ -460,7 +458,10 @@ static void ftfw_run(void)  		struct us_conntrack *u;  		u = cache_get_conntrack(STATE_SYNC(internal), cn); -		tx_list_xmit(&cn->tx_list, u); +		if (alarm_pending(&u->alarm)) +			tx_list_xmit(&cn->tx_list, u, NFCT_Q_DESTROY); +		else +			tx_list_xmit(&cn->tx_list, u, NFCT_Q_UPDATE);  	}  	/* reset alive alarm */ diff --git a/src/sync-mode.c b/src/sync-mode.c index cbb4769..a952a5b 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -344,17 +344,15 @@ static void dump_sync(struct nf_conntrack *ct)  		debug_ct(ct, "resync");  } -static void mcast_send_sync(struct us_conntrack *u, -			    struct nf_conntrack *ct, -			    int query) +static void mcast_send_sync(struct us_conntrack *u, int query)  {  	size_t len;  	struct nethdr *net; -	if (!state_helper_verdict(query, ct)) +	if (!state_helper_verdict(query, u->ct))  		return; -	net = BUILD_NETMSG(ct, 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) @@ -370,8 +368,10 @@ 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, u->ct, NFCT_Q_DESTROY); -		cache_del(STATE_SYNC(internal), u->ct); +		if (cache_del_timeout(STATE_SYNC(internal), +				      u->ct,  +				      CONFIG(del_timeout))) +			mcast_send_sync(u, NFCT_Q_DESTROY);  	}  	return 0; @@ -406,7 +406,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, u->ct, NFCT_Q_UPDATE); +			mcast_send_sync(u, NFCT_Q_UPDATE);  		}  	} @@ -427,7 +427,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, ct, NFCT_Q_CREATE); +		mcast_send_sync(u, NFCT_Q_CREATE);  		debug_ct(u->ct, "internal new");  	} else {  		if (errno == EEXIST) { @@ -453,16 +453,19 @@ static void event_update_sync(struct nf_conntrack *ct)  		return;  	}  	debug_ct(u->ct, "internal update"); -	mcast_send_sync(u, ct, NFCT_Q_UPDATE); +	mcast_send_sync(u, NFCT_Q_UPDATE);  }  static int event_destroy_sync(struct nf_conntrack *ct)  { +	struct us_conntrack *u; +  	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); +	u = cache_del_timeout(STATE_SYNC(internal), ct, CONFIG(del_timeout)); +	if (u != NULL) { +		mcast_send_sync(u, NFCT_Q_DESTROY);  		debug_ct(ct, "internal destroy");  		return 1;  	} else { | 
