diff options
Diffstat (limited to 'src')
-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 |
6 files changed, 136 insertions, 29 deletions
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; |