diff options
-rw-r--r-- | README | 4 | ||||
-rw-r--r-- | include/internal/object.h | 3 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/callback.c | 111 | ||||
-rw-r--r-- | src/conntrack/Makefile.am | 2 | ||||
-rw-r--r-- | src/conntrack/api.c | 36 | ||||
-rw-r--r-- | src/conntrack/bsf.c | 30 | ||||
-rw-r--r-- | src/conntrack/callback.c | 55 | ||||
-rw-r--r-- | src/expect/Makefile.am | 2 | ||||
-rw-r--r-- | src/expect/api.c | 36 | ||||
-rw-r--r-- | src/expect/callback.c | 55 | ||||
-rw-r--r-- | src/main.c | 24 | ||||
-rw-r--r-- | utils/.gitignore | 1 | ||||
-rw-r--r-- | utils/Makefile.am | 7 | ||||
-rw-r--r-- | utils/ctexp_events.c | 70 |
15 files changed, 282 insertions, 156 deletions
@@ -62,6 +62,10 @@ library only provides the new API that solves former deficiencies. Thus, make sure you use recent versions of libnetfilter_conntrack and, in case that you are using the old API, consider porting your application to the new one. +Since libnetfilter_conntrack >= 0.9.1, you can use the same handler obtained +via nfct_open() to register conntrack and expectation callbacks (before this +version, this was not possible). + = References = [1] Pablo Neira Ayuso. Netfilter's Connection Tracking System: diff --git a/include/internal/object.h b/include/internal/object.h index 4263ef0..8d95aa1 100644 --- a/include/internal/object.h +++ b/include/internal/object.h @@ -16,7 +16,8 @@ struct nfct_handle { struct nfnl_subsys_handle *nfnlssh_exp; /* callback handler for the new API */ - struct nfnl_callback nfnl_cb; + struct nfnl_callback nfnl_cb_ct; + struct nfnl_callback nfnl_cb_exp; int (*cb)(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, diff --git a/src/Makefile.am b/src/Makefile.am index 2e9ccd0..82030c4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,4 +15,4 @@ libnetfilter_conntrack_la_LIBADD = conntrack/libnfconntrack.la \ ${LIBNFNETLINK_LIBS} libnetfilter_conntrack_la_LDFLAGS = -Wc,-nostartfiles -lnfnetlink -ldl \ -version-info $(LIBVERSION) -libnetfilter_conntrack_la_SOURCES = main.c +libnetfilter_conntrack_la_SOURCES = main.c callback.c diff --git a/src/callback.c b/src/callback.c new file mode 100644 index 0000000..fd8b788 --- /dev/null +++ b/src/callback.c @@ -0,0 +1,111 @@ +/* + * (C) 2006-2010 by Pablo Neira Ayuso <pablo@netfilter.org> + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + */ + +#include "internal/internal.h" + +static int __parse_message(const struct nlmsghdr *nlh) +{ + u_int16_t type = NFNL_MSG_TYPE(nlh->nlmsg_type); + u_int16_t flags = nlh->nlmsg_flags; + int ret = NFCT_T_UNKNOWN; + + switch(type) { + case IPCTNL_MSG_CT_NEW: /* same value for IPCTNL_MSG_EXP_NEW. */ + if (flags & (NLM_F_CREATE|NLM_F_EXCL)) + ret = NFCT_T_NEW; + else + ret = NFCT_T_UPDATE; + break; + case IPCTNL_MSG_CT_DELETE: /* same value for IPCTNL_MSG_EXP_DELETE. */ + ret = NFCT_T_DESTROY; + break; + } + return ret; +} + +int __callback(struct nlmsghdr *nlh, struct nfattr *nfa[], void *data) +{ + int ret = NFNL_CB_STOP; + unsigned int type; + struct nf_conntrack *ct = NULL; + struct nf_expect *exp = NULL; + struct __data_container *container = data; + u_int8_t subsys = NFNL_SUBSYS_ID(nlh->nlmsg_type); + + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nfgenmsg))) { + errno = EINVAL; + return NFNL_CB_FAILURE; + } + type = __parse_message(nlh); + if (!(type & container->type)) + return NFNL_CB_CONTINUE; + + switch(subsys) { + case NFNL_SUBSYS_CTNETLINK: + ct = nfct_new(); + if (ct == NULL) + return NFNL_CB_FAILURE; + + __parse_conntrack(nlh, nfa, ct); + + if (container->h->cb) { + ret = container->h->cb(type, ct, container->data); + } else if (container->h->cb2) { + ret = container->h->cb2(nlh, type, ct, + container->data); + } + break; + case NFNL_SUBSYS_CTNETLINK_EXP: + exp = nfexp_new(); + if (exp == NULL) + return NFNL_CB_FAILURE; + + __parse_expect(nlh, nfa, exp); + + if (container->h->expect_cb) { + ret = container->h->expect_cb(type, exp, + container->data); + } else if (container->h->expect_cb2) { + ret = container->h->expect_cb2(nlh, type, exp, + container->data); + } + break; + default: + errno = ENOTSUP; + ret = NFNL_CB_FAILURE; + break; + } + + switch(ret) { + case NFCT_CB_FAILURE: + if (ct) + free(ct); + if (exp) + free(exp); + ret = NFNL_CB_FAILURE; + break; + case NFCT_CB_STOP: + if (ct) + free(ct); + if (exp) + free(exp); + ret = NFNL_CB_STOP; + break; + case NFCT_CB_CONTINUE: + if (ct) + free(ct); + if (exp) + free(exp); + ret = NFNL_CB_CONTINUE; + break; + case NFCT_CB_STOLEN: + ret = NFNL_CB_CONTINUE; + break; + } +out: + return ret; +} diff --git a/src/conntrack/Makefile.am b/src/conntrack/Makefile.am index 68c2d72..34afefb 100644 --- a/src/conntrack/Makefile.am +++ b/src/conntrack/Makefile.am @@ -4,7 +4,7 @@ AM_CFLAGS = -Wall ${LIBNFNETLINK_CFLAGS} noinst_LTLIBRARIES = libnfconntrack.la -libnfconntrack_la_SOURCES = api.c callback.c \ +libnfconntrack_la_SOURCES = api.c \ getter.c setter.c \ parse.c build.c \ snprintf.c \ diff --git a/src/conntrack/api.c b/src/conntrack/api.c index d7f16fe..825afba 100644 --- a/src/conntrack/api.c +++ b/src/conntrack/api.c @@ -226,17 +226,17 @@ int nfct_callback_register(struct nfct_handle *h, container->type = type; container->data = data; - h->nfnl_cb.call = __callback; - h->nfnl_cb.data = container; - h->nfnl_cb.attr_count = CTA_MAX; + h->nfnl_cb_ct.call = __callback; + h->nfnl_cb_ct.data = container; + h->nfnl_cb_ct.attr_count = CTA_MAX; nfnl_callback_register(h->nfnlssh_ct, IPCTNL_MSG_CT_NEW, - &h->nfnl_cb); + &h->nfnl_cb_ct); nfnl_callback_register(h->nfnlssh_ct, IPCTNL_MSG_CT_DELETE, - &h->nfnl_cb); + &h->nfnl_cb_ct); return 0; } @@ -253,11 +253,11 @@ void nfct_callback_unregister(struct nfct_handle *h) nfnl_callback_unregister(h->nfnlssh_ct, IPCTNL_MSG_CT_DELETE); h->cb = NULL; - free(h->nfnl_cb.data); + free(h->nfnl_cb_ct.data); - h->nfnl_cb.call = NULL; - h->nfnl_cb.data = NULL; - h->nfnl_cb.attr_count = 0; + h->nfnl_cb_ct.call = NULL; + h->nfnl_cb_ct.data = NULL; + h->nfnl_cb_ct.attr_count = 0; } /** @@ -300,17 +300,17 @@ int nfct_callback_register2(struct nfct_handle *h, container->type = type; container->data = data; - h->nfnl_cb.call = __callback; - h->nfnl_cb.data = container; - h->nfnl_cb.attr_count = CTA_MAX; + h->nfnl_cb_ct.call = __callback; + h->nfnl_cb_ct.data = container; + h->nfnl_cb_ct.attr_count = CTA_MAX; nfnl_callback_register(h->nfnlssh_ct, IPCTNL_MSG_CT_NEW, - &h->nfnl_cb); + &h->nfnl_cb_ct); nfnl_callback_register(h->nfnlssh_ct, IPCTNL_MSG_CT_DELETE, - &h->nfnl_cb); + &h->nfnl_cb_ct); return 0; } @@ -327,11 +327,11 @@ void nfct_callback_unregister2(struct nfct_handle *h) nfnl_callback_unregister(h->nfnlssh_ct, IPCTNL_MSG_CT_DELETE); h->cb2 = NULL; - free(h->nfnl_cb.data); + free(h->nfnl_cb_ct.data); - h->nfnl_cb.call = NULL; - h->nfnl_cb.data = NULL; - h->nfnl_cb.attr_count = 0; + h->nfnl_cb_ct.call = NULL; + h->nfnl_cb_ct.data = NULL; + h->nfnl_cb_ct.attr_count = 0; } /** diff --git a/src/conntrack/bsf.c b/src/conntrack/bsf.c index 69a7f14..ae7fa4a 100644 --- a/src/conntrack/bsf.c +++ b/src/conntrack/bsf.c @@ -8,6 +8,7 @@ #include "internal/internal.h" #include "internal/stack.h" #include <linux/filter.h> +#include <stddef.h> /* offsetof */ #ifndef SKF_AD_NLATTR #define SKF_AD_NLATTR 12 @@ -214,6 +215,33 @@ nfct_bsf_jump_to(struct sock_filter *this, int line, int pos) return NEW_POS(__code); }; +/* this helps to skip messages coming from the ctnetlink expectation subsys. */ +static int +bsf_cmp_subsys(struct sock_filter *this, int pos, u_int8_t subsys) +{ + struct sock_filter __code[] = { + [0] = { + /* X = offset to nlh->nlmsg_type */ + .code = BPF_LDX|BPF_IMM, + .k = offsetof(struct nlmsghdr, nlmsg_type), + }, + [1] = { + /* A = skb->data[X+k:B] (subsys_id) */ + .code = BPF_LD|BPF_B|BPF_IND, + .k = sizeof(u_int8_t), + }, + [2] = { + /* A == subsys ? jump +1 : accept */ + .code = BPF_JMP|BPF_JEQ|BPF_K, + .k = subsys, + .jt = 1, + .jf = 0, + }, + }; + memcpy(&this[pos], &__code, sizeof(__code)); + return NEW_POS(__code); +} + static int add_state_filter_cta(struct sock_filter *this, unsigned int cta_protoinfo_proto, @@ -584,6 +612,8 @@ int __setup_netlink_socket_filter(int fd, struct nfct_filter *f) memset(bsf, 0, sizeof(bsf)); + j += bsf_cmp_subsys(&bsf[j], j, NFNL_SUBSYS_CTNETLINK); + j += nfct_bsf_ret_verdict(bsf, NFCT_FILTER_ACCEPT, j); j += bsf_add_proto_filter(f, &bsf[j]); j += bsf_add_saddr_ipv4_filter(f, &bsf[j]); j += bsf_add_daddr_ipv4_filter(f, &bsf[j]); diff --git a/src/conntrack/callback.c b/src/conntrack/callback.c deleted file mode 100644 index c83a564..0000000 --- a/src/conntrack/callback.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * (C) 2006 by Pablo Neira Ayuso <pablo@netfilter.org> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#include "internal/internal.h" - -int __callback(struct nlmsghdr *nlh, struct nfattr *nfa[], void *data) -{ - int ret = NFNL_CB_STOP; - unsigned int type; - struct nf_conntrack *ct; - int len = nlh->nlmsg_len; - struct __data_container *container = data; - - len -= NLMSG_LENGTH(sizeof(struct nfgenmsg)); - if (len < 0) - return NFNL_CB_CONTINUE; - - type = __parse_message_type(nlh); - if (!(type & container->type)) - return NFNL_CB_CONTINUE; - - ct = nfct_new(); - if (!ct) - return NFNL_CB_CONTINUE; - - __parse_conntrack(nlh, nfa, ct); - - if (container->h->cb) - ret = container->h->cb(type, ct, container->data); - else if (container->h->cb2) - ret = container->h->cb2(nlh, type, ct, container->data); - - switch(ret) { - case NFCT_CB_FAILURE: - free(ct); - ret = NFNL_CB_FAILURE; - break; - case NFCT_CB_STOP: - free(ct); - ret = NFNL_CB_STOP; - break; - case NFCT_CB_CONTINUE: - free(ct); - ret = NFNL_CB_CONTINUE; - break; - case NFCT_CB_STOLEN: - ret = NFNL_CB_CONTINUE; - break; - } - return ret; -} diff --git a/src/expect/Makefile.am b/src/expect/Makefile.am index b0404ba..380befa 100644 --- a/src/expect/Makefile.am +++ b/src/expect/Makefile.am @@ -4,7 +4,7 @@ AM_CFLAGS = -Wall ${LIBNFNETLINK_CFLAGS} noinst_LTLIBRARIES = libnfexpect.la -libnfexpect_la_SOURCES = api.c callback.c \ +libnfexpect_la_SOURCES = api.c \ getter.c setter.c \ parse.c build.c \ snprintf.c \ diff --git a/src/expect/api.c b/src/expect/api.c index d560178..35c8672 100644 --- a/src/expect/api.c +++ b/src/expect/api.c @@ -139,17 +139,17 @@ int nfexp_callback_register(struct nfct_handle *h, container->type = type; container->data = data; - h->nfnl_cb.call = __expect_callback; - h->nfnl_cb.data = container; - h->nfnl_cb.attr_count = CTA_EXPECT_MAX; + h->nfnl_cb_exp.call = __callback; + h->nfnl_cb_exp.data = container; + h->nfnl_cb_exp.attr_count = CTA_EXPECT_MAX; nfnl_callback_register(h->nfnlssh_exp, IPCTNL_MSG_EXP_NEW, - &h->nfnl_cb); + &h->nfnl_cb_exp); nfnl_callback_register(h->nfnlssh_exp, IPCTNL_MSG_EXP_DELETE, - &h->nfnl_cb); + &h->nfnl_cb_exp); return 0; } @@ -166,11 +166,11 @@ void nfexp_callback_unregister(struct nfct_handle *h) nfnl_callback_unregister(h->nfnlssh_exp, IPCTNL_MSG_EXP_DELETE); h->expect_cb = NULL; - free(h->nfnl_cb.data); + free(h->nfnl_cb_exp.data); - h->nfnl_cb.call = NULL; - h->nfnl_cb.data = NULL; - h->nfnl_cb.attr_count = 0; + h->nfnl_cb_exp.call = NULL; + h->nfnl_cb_exp.data = NULL; + h->nfnl_cb_exp.attr_count = 0; } /** @@ -214,17 +214,17 @@ int nfexp_callback_register2(struct nfct_handle *h, container->type = type; container->data = data; - h->nfnl_cb.call = __expect_callback; - h->nfnl_cb.data = container; - h->nfnl_cb.attr_count = CTA_EXPECT_MAX; + h->nfnl_cb_exp.call = __callback; + h->nfnl_cb_exp.data = container; + h->nfnl_cb_exp.attr_count = CTA_EXPECT_MAX; nfnl_callback_register(h->nfnlssh_exp, IPCTNL_MSG_EXP_NEW, - &h->nfnl_cb); + &h->nfnl_cb_exp); nfnl_callback_register(h->nfnlssh_exp, IPCTNL_MSG_EXP_DELETE, - &h->nfnl_cb); + &h->nfnl_cb_exp); return 0; } @@ -241,11 +241,11 @@ void nfexp_callback_unregister2(struct nfct_handle *h) nfnl_callback_unregister(h->nfnlssh_exp, IPCTNL_MSG_EXP_DELETE); h->expect_cb2 = NULL; - free(h->nfnl_cb.data); + free(h->nfnl_cb_exp.data); - h->nfnl_cb.call = NULL; - h->nfnl_cb.data = NULL; - h->nfnl_cb.attr_count = 0; + h->nfnl_cb_exp.call = NULL; + h->nfnl_cb_exp.data = NULL; + h->nfnl_cb_exp.attr_count = 0; } /** diff --git a/src/expect/callback.c b/src/expect/callback.c deleted file mode 100644 index d2cc26e..0000000 --- a/src/expect/callback.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * (C) 2006-2007 by Pablo Neira Ayuso <pablo@netfilter.org> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#include "internal/internal.h" - -int __expect_callback(struct nlmsghdr *nlh, struct nfattr *nfa[], void *data) -{ - int ret = NFNL_CB_STOP; - unsigned int type; - struct nf_expect *exp; - int len = nlh->nlmsg_len; - struct __data_container *container = data; - - len -= NLMSG_LENGTH(sizeof(struct nfgenmsg)); - if (len < 0) - return NFNL_CB_CONTINUE; - - type = __parse_message_type(nlh); - if (!(type & container->type)) - return NFNL_CB_CONTINUE; - - exp = nfexp_new(); - if (!exp) - return NFNL_CB_CONTINUE; - - __parse_expect(nlh, nfa, exp); - - if (container->h->expect_cb) - ret = container->h->expect_cb(type, exp, container->data); - else if (container->h->expect_cb2) - ret = container->h->expect_cb2(nlh, type, exp, container->data); - - switch(ret) { - case NFCT_CB_FAILURE: - free(exp); - ret = NFNL_CB_FAILURE; - break; - case NFCT_CB_STOP: - free(exp); - ret = NFNL_CB_STOP; - break; - case NFCT_CB_CONTINUE: - free(exp); - ret = NFNL_CB_CONTINUE; - break; - case NFCT_CB_STOLEN: - ret = NFNL_CB_CONTINUE; - break; - } - return ret; -} @@ -70,7 +70,16 @@ out_free: * \param subscriptions ctnetlink groups to subscribe to events * * This function returns a handler to send commands to and receive replies from - * kernel-space. On error, NULL is returned and errno is explicitly set. + * kernel-space. You can pass the following subsystem IDs: + * + * - NFNL_SUBSYS_CTNETLINK: if you are only interested in conntrack operations + * (excluding expectations). + * - NFNL_SUBSYS_CTNETLINK_EXP: if you are only interested in expectation + * operations (exclude conntracks). + * - NFNL_SUBSYS_NONE: if you are interested in both conntrack and expectation + * operations. + * + * On error, NULL is returned and errno is explicitly set. */ struct nfct_handle *nfct_open(u_int8_t subsys_id, unsigned subscriptions) { @@ -111,11 +120,16 @@ int nfct_close(struct nfct_handle *cth) cth->cb2 = NULL; cth->expect_cb = NULL; cth->expect_cb2 = NULL; - free(cth->nfnl_cb.data); + free(cth->nfnl_cb_ct.data); + free(cth->nfnl_cb_exp.data); + + cth->nfnl_cb_ct.call = NULL; + cth->nfnl_cb_ct.data = NULL; + cth->nfnl_cb_ct.attr_count = 0; - cth->nfnl_cb.call = NULL; - cth->nfnl_cb.data = NULL; - cth->nfnl_cb.attr_count = 0; + cth->nfnl_cb_exp.call = NULL; + cth->nfnl_cb_exp.data = NULL; + cth->nfnl_cb_exp.attr_count = 0; err = nfnl_close(cth->nfnlh); free(cth); diff --git a/utils/.gitignore b/utils/.gitignore index 7dd7bb8..04897ba 100644 --- a/utils/.gitignore +++ b/utils/.gitignore @@ -16,3 +16,4 @@ /expect_events /expect_flush /expect_get +/ctexp_events diff --git a/utils/Makefile.am b/utils/Makefile.am index ec4bb85..dcb3fec 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -6,7 +6,8 @@ check_PROGRAMS = expect_dump expect_create expect_get expect_delete \ conntrack_delete conntrack_flush conntrack_create_nat \ conntrack_get conntrack_events \ conntrack_master conntrack_filter \ - conntrack_grp_create + conntrack_grp_create \ + ctexp_events conntrack_grp_create_SOURCES = conntrack_grp_create.c conntrack_grp_create_LDADD = ../src/libnetfilter_conntrack.la @@ -79,3 +80,7 @@ expect_flush_LDFLAGS = -dynamic -ldl expect_events_SOURCES = expect_events.c expect_events_LDADD = ../src/libnetfilter_conntrack.la expect_events_LDFLAGS = -dynamic -ldl + +ctexp_events_SOURCES = ctexp_events.c +ctexp_events_LDADD = ../src/libnetfilter_conntrack.la +ctexp_events_LDFLAGS = -dynamic -ldl diff --git a/utils/ctexp_events.c b/utils/ctexp_events.c new file mode 100644 index 0000000..1df5729 --- /dev/null +++ b/utils/ctexp_events.c @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include <libnetfilter_conntrack/libnetfilter_conntrack.h> + +static int n = 0; + +static int +ct_event_cb(enum nf_conntrack_msg_type type,struct nf_conntrack *ct, void *data) +{ + char buf[1024]; + + nfct_snprintf(buf, 1024, ct, type, NFCT_O_PLAIN, NFCT_OF_TIME); + printf("[CT] %s\n", buf); + + if (++n == 20) + return NFCT_CB_STOP; + + return NFCT_CB_CONTINUE; +} + +static int +exp_event_cb(enum nf_conntrack_msg_type type,struct nf_expect *exp, void *data) +{ + char buf[1024]; + + nfexp_snprintf(buf, 1024, exp, type, NFCT_O_DEFAULT, 0); + printf("[EXP] %s\n", buf); + + if (++n == 20) + return NFCT_CB_STOP; + + return NFCT_CB_CONTINUE; +} + +int main(void) +{ + int ret = 0; + struct nfct_handle *h; + + h = nfct_open(NFNL_SUBSYS_NONE, NF_NETLINK_CONNTRACK_EXP_NEW | + NF_NETLINK_CONNTRACK_EXP_UPDATE | + NF_NETLINK_CONNTRACK_EXP_DESTROY | + NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY); + if (h == NULL) { + perror("nfct_open"); + return -1; + } + + nfexp_callback_register(h, NFCT_T_ALL, exp_event_cb, NULL); + nfct_callback_register(h, NFCT_T_ALL, ct_event_cb, NULL); + + printf("TEST: waiting for 20 expectation events...\n"); + + /* we may use nfexp_catch() instead, it would also work. */ + ret = nfct_catch(h); + + printf("TEST: expectation events "); + if (ret == -1) + printf("(%d)(%s)\n", ret, strerror(errno)); + else + printf("(OK)\n"); + + nfct_close(h); + + ret == -1 ? exit(EXIT_FAILURE) : exit(EXIT_SUCCESS); +} |