diff options
| -rw-r--r-- | include/Makefile.am | 2 | ||||
| -rw-r--r-- | include/cache.h | 4 | ||||
| -rw-r--r-- | include/conntrackd.h | 6 | ||||
| -rw-r--r-- | include/origin.h | 14 | ||||
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/cache_iterators.c | 15 | ||||
| -rw-r--r-- | src/origin.c | 70 | ||||
| -rw-r--r-- | src/run.c | 18 | ||||
| -rw-r--r-- | src/stats-mode.c | 9 | ||||
| -rw-r--r-- | src/sync-mode.c | 51 | 
10 files changed, 157 insertions, 34 deletions
| diff --git a/include/Makefile.am b/include/Makefile.am index 0ea056c..b72fb36 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -4,5 +4,5 @@ noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.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 channel.h \ -		 process.h +		 process.h origin.h diff --git a/include/cache.h b/include/cache.h index 371170d..b6facdc 100644 --- a/include/cache.h +++ b/include/cache.h @@ -121,8 +121,10 @@ void *cache_get_extra(struct cache *, void *);  void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2));  /* iterators */ +struct nfct_handle; +  void cache_dump(struct cache *c, int fd, int type); -void cache_commit(struct cache *c); +void cache_commit(struct cache *c, struct nfct_handle *h);  void cache_flush(struct cache *c);  void cache_bulk(struct cache *c); diff --git a/include/conntrackd.h b/include/conntrackd.h index 013ec4f..81cfd51 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -218,9 +218,9 @@ struct ct_mode {  		      struct nf_conntrack *ct,  		      void *data);  	int (*purge)(void); -	void (*event_new)(struct nf_conntrack *ct); -	void (*event_upd)(struct nf_conntrack *ct); -	int (*event_dst)(struct nf_conntrack *ct); +	void (*event_new)(struct nf_conntrack *ct, int origin); +	void (*event_upd)(struct nf_conntrack *ct, int origin); +	int (*event_dst)(struct nf_conntrack *ct, int origin);  };  /* conntrackd modes */ diff --git a/include/origin.h b/include/origin.h new file mode 100644 index 0000000..b2d1823 --- /dev/null +++ b/include/origin.h @@ -0,0 +1,14 @@ +#ifndef _ORIGIN_H_ +#define _ORIGIN_H_ + +enum { +	CTD_ORIGIN_NOT_ME = 0,		/* this event comes from the kernel or +					   any process, but not conntrackd */ +	CTD_ORIGIN_COMMIT,		/* event comes from committer */ +}; + +int origin_register(struct nfct_handle *h, int origin_type); +int origin_find(const struct nlmsghdr *nlh); +int origin_unregister(struct nfct_handle *h); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index decc545..c338fee 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@  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 \ +		    filter.c fds.c event.c process.c origin.c \  		    cache.c cache_iterators.c \  		    cache_timer.c cache_wt.c \  		    sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ diff --git a/src/cache_iterators.c b/src/cache_iterators.c index dfccc68..542ab91 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -175,20 +175,16 @@ static int do_commit_master(void *data, struct hashtable_node *n)  }  /* no need to clone, called from child process */ -void cache_commit(struct cache *c) +void cache_commit(struct cache *c, struct nfct_handle *h)  {  	unsigned int commit_ok = c->stats.commit_ok;  	unsigned int commit_fail = c->stats.commit_fail; -	struct __commit_container tmp; +	struct __commit_container tmp = { +		.h = h, +		.c = c, +	};  	struct timeval commit_start, commit_stop, res; -	tmp.h = nfct_open(CONNTRACK, 0); -	if (tmp.h == NULL) { -		dlog(LOG_ERR, "can't create handler to commit entries"); -		return; -	} -	tmp.c = c; -  	gettimeofday(&commit_start, NULL);  	/* commit master conntrack first, then related ones */  	hashtable_iterate(c->h, &tmp, do_commit_master); @@ -206,7 +202,6 @@ void cache_commit(struct cache *c)  	if (commit_fail)  		dlog(LOG_NOTICE, "%u entries can't be "  				 "committed", commit_fail); -	nfct_close(tmp.h);  	dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds",   			res.tv_sec, res.tv_usec); diff --git a/src/origin.c b/src/origin.c new file mode 100644 index 0000000..3c65f3d --- /dev/null +++ b/src/origin.c @@ -0,0 +1,70 @@ +/* + * (C) 2009 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 "conntrackd.h" +#include "origin.h" + +static LIST_HEAD(origin_list); + +struct origin { +	struct list_head	head; +	unsigned int		nl_portid; +	int			type; +}; + +/* register a Netlink socket as origin of possible events */ +int origin_register(struct nfct_handle *h, int origin_type) +{ +	struct origin *nlp; + +	nlp = calloc(sizeof(struct origin), 1); +	if (nlp == NULL) +		return -1; + +	nlp->nl_portid = nfnl_portid(nfct_nfnlh(h)); +	nlp->type = origin_type; + +	list_add(&nlp->head, &origin_list); +	return 0; +} + +/* look up for the origin of this Netlink event */ +int origin_find(const struct nlmsghdr *nlh) +{ +	struct origin *this; + +	list_for_each_entry(this, &origin_list, head) { +		if (this->nl_portid == nlh->nlmsg_pid) { +			return this->type; +		} +	} +	return CTD_ORIGIN_NOT_ME; +} + +int origin_unregister(struct nfct_handle *h) +{ +	struct origin *this, *tmp; + +	list_for_each_entry_safe(this, tmp, &origin_list, head) { +		if (this->nl_portid == nfnl_portid(nfct_nfnlh(h))) { +			list_del(&this->head); +			free(this); +			return 1; +		} +	} +	return 0; +} @@ -26,6 +26,7 @@  #include "fds.h"  #include "traffic_stats.h"  #include "process.h" +#include "origin.h"  #include <errno.h>  #include <signal.h> @@ -228,10 +229,13 @@ static void do_polling_alarm(struct alarm_block *a, void *data)  	add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0);  } -static int event_handler(enum nf_conntrack_msg_type type, +static int event_handler(const struct nlmsghdr *nlh, +			 enum nf_conntrack_msg_type type,  			 struct nf_conntrack *ct,  			 void *data)  { +	int origin_type; +  	STATE(stats).nl_events_received++;  	/* skip user-space filtering if already do it in the kernel */ @@ -240,15 +244,17 @@ static int event_handler(enum nf_conntrack_msg_type type,  		goto out;  	} +	origin_type = origin_find(nlh); +  	switch(type) {  	case NFCT_T_NEW: -		STATE(mode)->event_new(ct); +		STATE(mode)->event_new(ct, origin_type);  		break;  	case NFCT_T_UPDATE: -		STATE(mode)->event_upd(ct); +		STATE(mode)->event_upd(ct, origin_type);  		break;  	case NFCT_T_DESTROY: -		if (STATE(mode)->event_dst(ct)) +		if (STATE(mode)->event_dst(ct, origin_type))  			update_traffic_stats(ct);  		break;  	default: @@ -334,8 +340,8 @@ init(void)  			dlog(LOG_ERR, "no ctnetlink kernel support?");  			return -1;  		} -		nfct_callback_register(STATE(event), NFCT_T_ALL, -				       event_handler, NULL); +		nfct_callback_register2(STATE(event), NFCT_T_ALL, +				        event_handler, NULL);  		register_fd(nfct_fd(STATE(event)), STATE(fds));  	} diff --git a/src/stats-mode.c b/src/stats-mode.c index af1c136..b84c7a1 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -141,7 +141,8 @@ static int purge_stats(void)  	return 0;  } -static void event_new_stats(struct nf_conntrack *ct) +static void +event_new_stats(struct nf_conntrack *ct, int origin)  {  	int id;  	struct cache_object *obj; @@ -162,13 +163,15 @@ static void event_new_stats(struct nf_conntrack *ct)  	return;  } -static void event_update_stats(struct nf_conntrack *ct) +static void +event_update_stats(struct nf_conntrack *ct, int origin)  {  	nfct_attr_unset(ct, ATTR_TIMEOUT);  	cache_update_force(STATE_STATS(cache), ct);  } -static int event_destroy_stats(struct nf_conntrack *ct) +static int +event_destroy_stats(struct nf_conntrack *ct, int origin)  {  	int id;  	struct cache_object *obj; diff --git a/src/sync-mode.c b/src/sync-mode.c index 0d35923..91e028e 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -27,6 +27,7 @@  #include "event.h"  #include "queue.h"  #include "process.h" +#include "origin.h"  #include <errno.h>  #include <unistd.h> @@ -385,6 +386,14 @@ static void dump_stats_sync_extended(int fd)  	send(fd, buf, size, 0);  } +/* this is called once the committer process has finished */ +static void commit_done_cb(void *data) +{ +	struct nfct_handle *h = data; +	origin_unregister(h); +	nfct_close(h); +} +  /* handler for requests coming via UNIX socket */  static int local_handler_sync(int fd, int type, void *data)  { @@ -419,16 +428,29 @@ static int local_handler_sync(int fd, int type, void *data)  			exit(EXIT_SUCCESS);  		}  		break; -	case COMMIT: +	case COMMIT: { +		struct nfct_handle *h; +  		/* delete the reset alarm if any before committing */  		del_alarm(&STATE_SYNC(reset_cache_alarm)); -		ret = fork_process_new(NULL, NULL); + +		/* disposable handler for commit operations */ +		h = nfct_open(CONNTRACK, 0); +		if (h == NULL) { +			dlog(LOG_ERR, "can't create handler to commit"); +			break; +		} +		origin_register(h, CTD_ORIGIN_COMMIT); + +		/* fork new process and insert it the process list */ +		ret = fork_process_new(commit_done_cb, h);  		if (ret == 0) {  			dlog(LOG_NOTICE, "committing external cache"); -			cache_commit(STATE_SYNC(external)); +			cache_commit(STATE_SYNC(external), h);  			exit(EXIT_SUCCESS);  		}  		break; +	}  	case RESET_TIMERS:  		if (!alarm_pending(&STATE_SYNC(reset_cache_alarm))) {  			dlog(LOG_NOTICE, "flushing conntrack table in %d secs", @@ -557,7 +579,8 @@ static int resync_sync(enum nf_conntrack_msg_type type,  	return NFCT_CB_CONTINUE;  } -static void event_new_sync(struct nf_conntrack *ct) +static void +event_new_sync(struct nf_conntrack *ct, int origin)  {  	struct cache_object *obj;  	int id; @@ -578,7 +601,11 @@ retry:  			cache_object_free(obj);  			return;  		} -		sync_send(obj, NET_T_STATE_NEW); +		/* 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_NEW);  	} else {  		cache_del(STATE_SYNC(internal), obj);  		cache_object_free(obj); @@ -586,7 +613,8 @@ retry:  	}  } -static void event_update_sync(struct nf_conntrack *ct) +static void +event_update_sync(struct nf_conntrack *ct, int origin)  {  	struct cache_object *obj; @@ -594,21 +622,26 @@ static void event_update_sync(struct nf_conntrack *ct)  	if (obj == NULL)  		return; -	sync_send(obj, NET_T_STATE_UPD); +	if (origin == CTD_ORIGIN_NOT_ME) +		sync_send(obj, NET_T_STATE_UPD);  } -static int event_destroy_sync(struct nf_conntrack *ct) +static int +event_destroy_sync(struct nf_conntrack *ct, int origin)  {  	struct cache_object *obj;  	int id; +	/* we don't synchronize events for objects that are not in the cache */  	obj = cache_find(STATE_SYNC(internal), ct, &id);  	if (obj == NULL)  		return 0;  	if (obj->status != C_OBJ_DEAD) {  		cache_object_set_status(obj, C_OBJ_DEAD); -		sync_send(obj, NET_T_STATE_DEL); +		if (origin == CTD_ORIGIN_NOT_ME) { +			sync_send(obj, NET_T_STATE_DEL); +		}  		cache_object_put(obj);  	}  	return 1; | 
