summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README4
-rw-r--r--include/internal/object.h3
-rw-r--r--src/Makefile.am2
-rw-r--r--src/callback.c111
-rw-r--r--src/conntrack/Makefile.am2
-rw-r--r--src/conntrack/api.c36
-rw-r--r--src/conntrack/bsf.c30
-rw-r--r--src/conntrack/callback.c55
-rw-r--r--src/expect/Makefile.am2
-rw-r--r--src/expect/api.c36
-rw-r--r--src/expect/callback.c55
-rw-r--r--src/main.c24
-rw-r--r--utils/.gitignore1
-rw-r--r--utils/Makefile.am7
-rw-r--r--utils/ctexp_events.c70
15 files changed, 282 insertions, 156 deletions
diff --git a/README b/README
index f0eed70..4a03627 100644
--- a/README
+++ b/README
@@ -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;
-}
diff --git a/src/main.c b/src/main.c
index 6da4198..7a4f8d0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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);
+}