summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2009-05-23 12:54:51 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2009-05-23 12:54:51 +0200
commitef047d03613bf9fa105db009773136817e2ec4c6 (patch)
tree7bdeaa64da5ebe1aeb79bdfaa8c24fa8de2cfad7 /src
parent0374398fd14bf587d80d9d31e361e266e69387c8 (diff)
downloadconntrack-tools-ef047d03613bf9fa105db009773136817e2ec4c6.tar.gz
conntrack-tools-ef047d03613bf9fa105db009773136817e2ec4c6.zip
conntrackd: detect where the events comes from
Since Linux kernel 2.6.29, ctnetlink reports the changes that have been done using ctnetlink. With this patch, conntrackd can recognize who is the origin of the event messages. For example, this is interesting to avoid a messy implicit bulk send during the commit of entries. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/cache_iterators.c15
-rw-r--r--src/origin.c70
-rw-r--r--src/run.c18
-rw-r--r--src/stats-mode.c9
-rw-r--r--src/sync-mode.c51
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;
+}
diff --git a/src/run.c b/src/run.c
index 09e2ae9..e54764c 100644
--- a/src/run.c
+++ b/src/run.c
@@ -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;