summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am5
-rw-r--r--src/conntrack/parse.c17
-rw-r--r--src/conntrack/snprintf_default.c6
-rw-r--r--src/expect/Makefile.am16
-rw-r--r--src/expect/api.c545
-rw-r--r--src/expect/build.c58
-rw-r--r--src/expect/callback.c53
-rw-r--r--src/expect/getter.c35
-rw-r--r--src/expect/parse.c57
-rw-r--r--src/expect/setter.c35
-rw-r--r--src/expect/snprintf.c33
-rw-r--r--src/expect/snprintf_default.c62
12 files changed, 904 insertions, 18 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 87911ce..544311a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,14 +4,15 @@ include $(top_srcdir)/Make_global.am
#EXTRA_DIST = $(man_MANS) acinclude.m4
-SUBDIRS=conntrack
+SUBDIRS=conntrack expect
AM_CFLAGS = -fPIC -Wall
LIBS = @LIBNFCONNTRACK_LIBS@
lib_LTLIBRARIES = libnetfilter_conntrack.la
-libnetfilter_conntrack_la_LIBADD = conntrack/libnetfilter_conntrack_new_api.la
+libnetfilter_conntrack_la_LIBADD = conntrack/libnetfilter_conntrack_new_api.la \
+ expect/libnetfilter_conntrack_expect.la
libnetfilter_conntrack_la_LDFLAGS = -Wc,-nostartfiles -lnfnetlink -ldl \
-version-info $(LIBVERSION)
libnetfilter_conntrack_la_SOURCES = libnetfilter_conntrack.c
diff --git a/src/conntrack/parse.c b/src/conntrack/parse.c
index 5cbd302..b9bc095 100644
--- a/src/conntrack/parse.c
+++ b/src/conntrack/parse.c
@@ -133,10 +133,10 @@ static void __parse_proto(const struct nfattr *attr,
}
}
-static void __parse_tuple(const struct nfattr *attr,
- struct __nfct_tuple *tuple,
- int dir,
- u_int32_t *set)
+void __parse_tuple(const struct nfattr *attr,
+ struct __nfct_tuple *tuple,
+ int dir,
+ u_int32_t *set)
{
struct nfattr *tb[CTA_TUPLE_MAX];
@@ -148,15 +148,6 @@ static void __parse_tuple(const struct nfattr *attr,
__parse_proto(tb[CTA_TUPLE_PROTO-1], tuple, dir, set);
}
-static void __parse_mask(const struct nfattr *attr,
- struct __nfct_tuple *tuple,
- const u_int8_t l3protonum,
- const u_int16_t protonum,
- u_int32_t *set)
-{
- __parse_tuple(attr, tuple, __DIR_ORIG, set);
-}
-
static void __parse_protoinfo_tcp(const struct nfattr *attr,
struct nf_conntrack *ct)
{
diff --git a/src/conntrack/snprintf_default.c b/src/conntrack/snprintf_default.c
index e826511..7f63d4c 100644
--- a/src/conntrack/snprintf_default.c
+++ b/src/conntrack/snprintf_default.c
@@ -42,9 +42,9 @@ static int __snprintf_l3protocol(char *buf,
ct->tuple[__DIR_ORIG].l3protonum));
}
-static int __snprintf_protocol(char *buf,
- unsigned int len,
- const struct nf_conntrack *ct)
+int __snprintf_protocol(char *buf,
+ unsigned int len,
+ const struct nf_conntrack *ct)
{
return (snprintf(buf, len, "%-8s %u ",
proto2str[ct->tuple[__DIR_ORIG].protonum] == NULL ?
diff --git a/src/expect/Makefile.am b/src/expect/Makefile.am
new file mode 100644
index 0000000..80bef3c
--- /dev/null
+++ b/src/expect/Makefile.am
@@ -0,0 +1,16 @@
+include $(top_srcdir)/Make_global.am
+
+#AUTOMAKE_OPTIONS = no-dependencies foreign
+
+#EXTRA_DIST = $(man_MANS) acinclude.m4
+
+AM_CFLAGS = -fPIC -Wall
+LIBS = @LIBNFCONNTRACK_LIBS@
+
+noinst_LTLIBRARIES = libnetfilter_conntrack_expect.la
+
+libnetfilter_conntrack_expect_la_SOURCES = api.c callback.c \
+ getter.c setter.c \
+ parse.c build.c \
+ snprintf.c \
+ snprintf_default.c
diff --git a/src/expect/api.c b/src/expect/api.c
new file mode 100644
index 0000000..127846a
--- /dev/null
+++ b/src/expect/api.c
@@ -0,0 +1,545 @@
+/*
+ * (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 <stdlib.h>
+#include <string.h> /* for memset */
+#include <errno.h>
+#include <assert.h>
+
+#include "internal.h"
+
+/**
+ * nfexp_new - allocate a new expectation
+ *
+ * In case of success, this function returns a valid pointer to a memory blob,
+ * otherwise NULL is returned and errno is set appropiately.
+ */
+struct nf_expect *nfexp_new()
+{
+ struct nf_expect *exp;
+
+ exp = malloc(sizeof(struct nf_expect));
+ if (!exp)
+ return NULL;
+
+ memset(exp, 0, sizeof(struct nf_expect));
+
+ return exp;
+}
+
+/**
+ * nfexp_destroy - release an expectation object
+ * @exp: pointer to the expectation object
+ */
+void nfexp_destroy(struct nf_expect *exp)
+{
+ assert(exp != NULL);
+ free(exp);
+ exp = NULL; /* bugtrap */
+}
+
+/**
+ * nfexp_clone - clone a expectation object
+ * @exp: pointer to a valid expectation object
+ *
+ * On error, NULL is returned and errno is appropiately set. Otherwise,
+ * a valid pointer to the clone expect is returned.
+ */
+struct nf_expect *nfexp_clone(const struct nf_expect *exp)
+{
+ struct nf_expect *clone;
+
+ assert(exp != NULL);
+
+ if ((clone = nfexp_new()) == NULL)
+ return NULL;
+ memcpy(clone, exp, sizeof(*exp));
+
+ return clone;
+}
+
+/**
+ * nfexp_callback_register - register a callback
+ * @h: library handler
+ * @cb: callback used to process expect received
+ * @data: data used by the callback, if any.
+ *
+ * This function register a callback to handle the expect received,
+ * in case of error -1 is returned and errno is set appropiately, otherwise
+ * 0 is returned.
+ *
+ * Note that the data parameter is optional, if you do not want to pass any
+ * data to your callback, then use NULL.
+ */
+int nfexp_callback_register(struct nfct_handle *h,
+ enum nf_conntrack_msg_type type,
+ int (*cb)(enum nf_conntrack_msg_type type,
+ struct nf_expect *exp,
+ void *data),
+ void *data)
+{
+ struct __data_container *container;
+
+ assert(h != NULL);
+
+ container = malloc(sizeof(struct __data_container));
+ if (!container)
+ return -1;
+ memset(container, 0, sizeof(struct __data_container));
+
+ h->expect_cb = cb;
+ container->h = 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;
+
+ nfnl_callback_register(h->nfnlssh_exp,
+ IPCTNL_MSG_EXP_NEW,
+ &h->nfnl_cb);
+
+ nfnl_callback_register(h->nfnlssh_exp,
+ IPCTNL_MSG_EXP_DELETE,
+ &h->nfnl_cb);
+
+ return 0;
+}
+
+/**
+ * nfexp_callback_unregister - unregister a callback
+ * @h: library handler
+ */
+void nfexp_callback_unregister(struct nfct_handle *h)
+{
+ assert(h != NULL);
+
+ nfnl_callback_unregister(h->nfnlssh_exp, IPCTNL_MSG_EXP_NEW);
+ nfnl_callback_unregister(h->nfnlssh_exp, IPCTNL_MSG_EXP_DELETE);
+
+ h->expect_cb = NULL;
+ free(h->nfnl_cb.data);
+
+ h->nfnl_cb.call = NULL;
+ h->nfnl_cb.data = NULL;
+ h->nfnl_cb.attr_count = 0;
+}
+
+/**
+ * nfexp_set_attr - set the value of a certain expect attribute
+ * @exp: pointer to a valid expect
+ * @type: attribute type
+ * @value: pointer to the attribute value
+ *
+ * Note that certain attributes are unsettable:
+ * - ATTR_EXP_USE
+ * - ATTR_EXP_ID
+ * - ATTR_EXP_*_COUNTER_*
+ * The call of this function for such attributes do nothing.
+ */
+void nfexp_set_attr(struct nf_expect *exp,
+ const enum nf_expect_attr type,
+ const void *value)
+{
+ assert(exp != NULL);
+ assert(value != NULL);
+
+ if (type >= ATTR_EXP_MAX)
+ return;
+
+ if (set_exp_attr_array[type]) {
+ set_exp_attr_array[type](exp, value);
+ set_bit(type, exp->set);
+ }
+}
+
+/**
+ * nfexp_set_attr_u8 - set the value of a certain expect attribute
+ * @exp: pointer to a valid expect
+ * @type: attribute type
+ * @value: unsigned 8 bits attribute value
+ */
+void nfexp_set_attr_u8(struct nf_expect *exp,
+ const enum nf_expect_attr type,
+ u_int8_t value)
+{
+ nfexp_set_attr(exp, type, &value);
+}
+
+/**
+ * nfexp_set_attr_u16 - set the value of a certain expect attribute
+ * @exp: pointer to a valid expect
+ * @type: attribute type
+ * @value: unsigned 16 bits attribute value
+ */
+void nfexp_set_attr_u16(struct nf_expect *exp,
+ const enum nf_expect_attr type,
+ u_int16_t value)
+{
+ nfexp_set_attr(exp, type, &value);
+}
+
+/**
+ * nfexp_set_attr_u32 - set the value of a certain expect attribute
+ * @exp: pointer to a valid expect
+ * @type: attribute type
+ * @value: unsigned 32 bits attribute value
+ */
+void nfexp_set_attr_u32(struct nf_expect *exp,
+ const enum nf_expect_attr type,
+ u_int32_t value)
+{
+ nfexp_set_attr(exp, type, &value);
+}
+
+/**
+ * nfexp_get_attr - get an expect attribute
+ * exp: pointer to a valid expect
+ * @type: attribute type
+ *
+ * In case of success a valid pointer to the attribute requested is returned,
+ * on error NULL is returned and errno is set appropiately.
+ */
+const void *nfexp_get_attr(const struct nf_expect *exp,
+ const enum nf_expect_attr type)
+{
+ assert(exp != NULL);
+
+ if (type >= ATTR_EXP_MAX) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (!test_bit(type, exp->set)) {
+ errno = ENODATA;
+ return NULL;
+ }
+
+ return get_exp_attr_array[type](exp);
+}
+
+/**
+ * nfexp_get_attr_u8 - get attribute of unsigned 8-bits long
+ * @exp: pointer to a valid expectation
+ * @type: attribute type
+ *
+ * Returns the value of the requested attribute, if the attribute is not
+ * set, 0 is returned. In order to check if the attribute is set or not,
+ * use nfexp_attr_is_set.
+ */
+u_int8_t nfexp_get_attr_u8(const struct nf_expect *exp,
+ const enum nf_expect_attr type)
+{
+ const int *ret = nfexp_get_attr(exp, type);
+ return ret == NULL ? 0 : *ret;
+}
+
+/**
+ * nfexp_get_attr_u16 - get attribute of unsigned 16-bits long
+ * @exp: pointer to a valid expectation
+ * @type: attribute type
+ *
+ * Returns the value of the requested attribute, if the attribute is not
+ * set, 0 is returned. In order to check if the attribute is set or not,
+ * use nfexp_attr_is_set.
+ */
+u_int16_t nfexp_get_attr_u16(const struct nf_expect *exp,
+ const enum nf_expect_attr type)
+{
+ const int *ret = nfexp_get_attr(exp, type);
+ return ret == NULL ? 0 : *ret;
+}
+
+/**
+ * nfexp_get_attr_u32 - get attribute of unsigned 32-bits long
+ * @exp: pointer to a valid expectation
+ * @type: attribute type
+ *
+ * Returns the value of the requested attribute, if the attribute is not
+ * set, 0 is returned. In order to check if the attribute is set or not,
+ * use nfexp_attr_is_set.
+ */
+u_int32_t nfexp_get_attr_u32(const struct nf_expect *exp,
+ const enum nf_expect_attr type)
+{
+ const int *ret = nfexp_get_attr(exp, type);
+ return ret == NULL ? 0 : *ret;
+}
+
+/**
+ * nfexp_attr_is_set - check if a certain attribute is set
+ * @exp: pointer to a valid expectation object
+ * @type: attribute type
+ *
+ * On error, -1 is returned and errno is set appropiately, otherwise
+ * the value of the attribute is returned.
+ */
+int nfexp_attr_is_set(const struct nf_expect *exp,
+ const enum nf_expect_attr type)
+{
+ assert(exp != NULL);
+
+ if (type >= ATTR_EXP_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+ return test_bit(type, exp->set);
+}
+
+/**
+ * nfexp_attr_unset - unset a certain attribute
+ * @type: attribute type
+ * @exp: pointer to a valid expectation object
+ *
+ * On error, -1 is returned and errno is set appropiately, otherwise
+ * 0 is returned.
+ */
+int nfexp_attr_unset(struct nf_expect *exp,
+ const enum nf_expect_attr type)
+{
+ assert(exp != NULL);
+
+ if (type >= ATTR_EXP_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+ unset_bit(type, exp->set);
+
+ return 0;
+}
+
+/**
+ * nfexp_build_expect - build a netlink message from a conntrack object
+ * @ssh: nfnetlink subsystem handler
+ * @req: buffer used to build the netlink message
+ * @size: size of the buffer passed
+ * @type: netlink message type
+ * @flags: netlink flags
+ * @exp: pointer to a conntrack object
+ *
+ * This is a low level function for those that require to be close to
+ * netlink details via libnfnetlink. If you do want to obviate the netlink
+ * details then we suggest you to use nfexp_query.
+ *
+ * On error, -1 is returned and errno is appropiately set.
+ * On success, 0 is returned.
+ */
+int nfexp_build_expect(struct nfnl_subsys_handle *ssh,
+ void *req,
+ size_t size,
+ u_int16_t type,
+ u_int16_t flags,
+ const struct nf_expect *exp)
+{
+ assert(ssh != NULL);
+ assert(req != NULL);
+ assert(exp != NULL);
+
+ return __build_expect(ssh, req, size, type, flags, exp);
+}
+
+/**
+ * nfexp_build_query - build a query in netlink message format for ctnetlink
+ * @ssh: nfnetlink subsystem handler
+ * @qt: query type
+ * @data: data required to build the query
+ * @req: buffer to build the netlink message
+ * @size: size of the buffer passed
+ *
+ * This is a low level function, use it if you want to require to work
+ * with netlink details via libnfnetlink, otherwise we suggest you to
+ * use nfexp_query.
+ *
+ * The pointer to data can be a conntrack object or the protocol family
+ * depending on the request.
+ *
+ * For query types:
+ * NFEXP_Q_CREATE
+ * NFEXP_Q_DESTROY
+ *
+ * Pass a valid pointer to an expectation object.
+ *
+ * For query types:
+ * NFEXP_Q_FLUSH
+ * NFEXP_Q_DUMP
+ *
+ * Pass a valid pointer to the protocol family (u_int8_t)
+ *
+ * On success, 0 is returned. On error, -1 is returned and errno is set
+ * appropiately.
+ */
+int nfexp_build_query(struct nfnl_subsys_handle *ssh,
+ const enum nf_conntrack_query qt,
+ const void *data,
+ void *buffer,
+ unsigned int size)
+{
+ struct nfnlhdr *req = buffer;
+ const u_int8_t *family = data;
+
+ assert(ssh != NULL);
+ assert(data != NULL);
+ assert(req != NULL);
+
+ memset(req, 0, size);
+
+ switch(qt) {
+ case NFCT_Q_CREATE:
+ nfexp_build_expect(ssh, req, size, IPCTNL_MSG_EXP_NEW, NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK|NLM_F_EXCL, data);
+ break;
+ case NFCT_Q_GET:
+ nfexp_build_expect(ssh, req, size, IPCTNL_MSG_EXP_GET, NLM_F_REQUEST|NLM_F_ACK, data);
+ break;
+ case NFCT_Q_DESTROY:
+ nfexp_build_expect(ssh, req, size, IPCTNL_MSG_EXP_DELETE, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK, data);
+ break;
+ case NFCT_Q_FLUSH:
+ nfnl_fill_hdr(ssh, &req->nlh, 0, *family, 0, IPCTNL_MSG_EXP_DELETE, NLM_F_REQUEST|NLM_F_ACK);
+ break;
+ case NFCT_Q_DUMP:
+ nfnl_fill_hdr(ssh, &req->nlh, 0, *family, 0, IPCTNL_MSG_EXP_GET, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_DUMP);
+ break;
+ default:
+ errno = ENOTSUP;
+ return -1;
+ }
+ return 1;
+}
+
+/**
+ * nfexp_parse_expect - translate a netlink message to a conntrack object
+ * @type: do the translation iif the message type is of a certain type
+ * @nlh: pointer to the netlink message
+ * @exp: pointer to the conntrack object
+ *
+ * This is a low level function, use it in case that you require to work
+ * with netlink details via libnfnetlink. Otherwise, we suggest you to
+ * use the high level API.
+ *
+ * The message types are:
+ *
+ * NFEXP_T_NEW: parse messages with new conntracks
+ * NFEXP_T_UPDATE: parse messages with conntrack updates
+ * NFEXP_T_DESTROY: parse messages with conntrack destroy
+ * NFEXP_T_ALL: all message types
+ *
+ * The message type is a flag, therefore the can be combined, ie.
+ * NFEXP_T_NEW | NFEXP_T_DESTROY to parse only new and destroy messages
+ *
+ * On error, NFEXP_T_ERROR is returned and errno is set appropiately. If
+ * the message received is not of the requested type then 0 is returned,
+ * otherwise this function returns the message type parsed.
+ */
+int nfexp_parse_expect(enum nf_conntrack_msg_type type,
+ const struct nlmsghdr *nlh,
+ struct nf_expect *exp)
+{
+ unsigned int flags;
+ int len = nlh->nlmsg_len;
+ struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
+ struct nfattr *cda[CTA_EXPECT_MAX];
+
+ assert(nlh != NULL);
+ assert(exp != NULL);
+
+ len -= NLMSG_LENGTH(sizeof(struct nfgenmsg));
+ if (len < 0) {
+ errno = EINVAL;
+ return NFCT_T_ERROR;
+ }
+
+ flags = __parse_expect_message_type(nlh);
+ if (!(flags & type))
+ return 0;
+
+ nfnl_parse_attr(cda, CTA_EXPECT_MAX, NFA_DATA(nfhdr), len);
+
+ __parse_expect(nlh, cda, exp);
+
+ return flags;
+}
+
+/**
+ * nfexp_query - send a query to ctnetlink
+ * @h: library handler
+ * @qt: query type
+ * @data: data required to send the query
+ *
+ * On error, -1 is returned and errno is explicitely set. On success, 0
+ * is returned.
+ */
+int nfexp_query(struct nfct_handle *h,
+ const enum nf_conntrack_query qt,
+ const void *data)
+{
+ size_t size = 4096; /* enough for now */
+ char buffer[4096];
+ struct nfnlhdr *req = (struct nfnlhdr *) buffer;
+
+ assert(h != NULL);
+ assert(data != NULL);
+
+ if (nfexp_build_query(h->nfnlssh_exp, qt, data, req, size) == -1)
+ return -1;
+
+ return nfnl_query(h->nfnlh, &req->nlh);
+}
+
+/**
+ * nfexp_catch - catch events
+ * @h: library handler
+ *
+ * On error, -1 is returned and errno is set appropiately. On success,
+ * a value greater or equal to 0 is returned indicating the callback
+ * verdiexp: NFEXP_CB_STOP, NFEXP_CB_CONTINUE or NFEXP_CB_STOLEN
+ */
+int nfexp_catch(struct nfct_handle *h)
+{
+ assert(h != NULL);
+
+ return nfnl_catch(h->nfnlh);
+}
+
+/**
+ * nfexp_snprintf - print a conntrack object to a buffer
+ * @buf: buffer used to build the printable conntrack
+ * @size: size of the buffer
+ * @exp: pointer to a valid expectation object
+ * @message_type: print message type (NFEXP_T_UNKNOWN, NFEXP_T_NEW,...)
+ * @output_type: print type (NFEXP_O_DEFAULT, NFEXP_O_XML, ...)
+ * @flags: extra flags for the output type (NFEXP_OF_LAYER3)
+ *
+ * If you are listening to events, probably you want to display the message
+ * type as well. In that case, set the message type parameter to any of the
+ * known existing types, ie. NFEXP_T_NEW, NFEXP_T_UPDATE, NFEXP_T_DESTROY.
+ * If you pass NFEXP_T_UNKNOWN, the message type will not be output.
+ *
+ * Currently, the output available are:
+ * - NFEXP_O_DEFAULT: default /proc-like output
+ * - NFEXP_O_XML: XML output
+ *
+ * The output flags are:
+ * - NFEXP_O_LAYER: include layer 3 information in the output, this is
+ * *only* required by NFEXP_O_DEFAULT.
+ *
+ * On error, -1 is returned and errno is set appropiately. Otherwise,
+ * 0 is returned.
+ */
+int nfexp_snprintf(char *buf,
+ unsigned int size,
+ const struct nf_expect *exp,
+ unsigned int msg_type,
+ unsigned int out_type,
+ unsigned int flags)
+{
+ assert(buf != NULL);
+ assert(size > 0);
+ assert(exp != NULL);
+
+ return __snprintf_expect(buf, size, exp, msg_type, out_type, flags);
+}
diff --git a/src/expect/build.c b/src/expect/build.c
new file mode 100644
index 0000000..501263a
--- /dev/null
+++ b/src/expect/build.c
@@ -0,0 +1,58 @@
+/*
+ * (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.h"
+
+static void __build_timeout(struct nfnlhdr *req,
+ size_t size,
+ const struct nf_expect *exp)
+{
+ nfnl_addattr32(&req->nlh, size, CTA_EXPECT_TIMEOUT,htonl(exp->timeout));
+}
+
+int __build_expect(struct nfnl_subsys_handle *ssh,
+ struct nfnlhdr *req,
+ size_t size,
+ u_int16_t type,
+ u_int16_t flags,
+ const struct nf_expect *exp)
+{
+ u_int8_t l3num = exp->master.tuple[NFCT_DIR_ORIGINAL].l3protonum;
+
+ if (!test_bit(ATTR_ORIG_L3PROTO, exp->master.set)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(req, 0, size);
+
+ nfnl_fill_hdr(ssh, &req->nlh, 0, l3num, 0, type, flags);
+
+ __build_tuple(req,
+ size,
+ &exp->expected.tuple[__DIR_ORIG],
+ CTA_EXPECT_TUPLE);
+
+ /* get and delete only require the expectation tuple */
+ if (type == IPCTNL_MSG_EXP_GET || type == IPCTNL_MSG_EXP_DELETE)
+ return 0;
+
+ __build_tuple(req,
+ size,
+ &exp->master.tuple[__DIR_ORIG],
+ CTA_EXPECT_MASTER);
+
+ __build_tuple(req,
+ size,
+ &exp->mask.tuple[__DIR_ORIG],
+ CTA_EXPECT_MASK);
+
+ if (test_bit(ATTR_EXP_TIMEOUT, exp->set))
+ __build_timeout(req, size, exp);
+
+ return 0;
+}
diff --git a/src/expect/callback.c b/src/expect/callback.c
new file mode 100644
index 0000000..df4ffe7
--- /dev/null
+++ b/src/expect/callback.c
@@ -0,0 +1,53 @@
+/*
+ * (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.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);
+
+ 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/expect/getter.c b/src/expect/getter.c
new file mode 100644
index 0000000..2cbebe6
--- /dev/null
+++ b/src/expect/getter.c
@@ -0,0 +1,35 @@
+/*
+ * (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.h"
+
+static const void *get_exp_attr_master(const struct nf_expect *exp)
+{
+ return &exp->master;
+}
+
+static const void *get_exp_attr_expected(const struct nf_expect *exp)
+{
+ return &exp->expected;
+}
+
+static const void *get_exp_attr_mask(const struct nf_expect *exp)
+{
+ return &exp->mask;
+}
+
+static const void *get_exp_attr_timeout(const struct nf_expect *exp)
+{
+ return &exp->timeout;
+}
+
+get_exp_attr get_exp_attr_array[] = {
+ [ATTR_EXP_MASTER] = get_exp_attr_master,
+ [ATTR_EXP_EXPECTED] = get_exp_attr_expected,
+ [ATTR_EXP_MASK] = get_exp_attr_mask,
+ [ATTR_EXP_TIMEOUT] = get_exp_attr_timeout,
+};
diff --git a/src/expect/parse.c b/src/expect/parse.c
new file mode 100644
index 0000000..5fe0bce
--- /dev/null
+++ b/src/expect/parse.c
@@ -0,0 +1,57 @@
+/*
+ * (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.h"
+
+int __parse_expect_message_type(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;
+
+ if (type == IPCTNL_MSG_EXP_NEW) {
+ if (flags & (NLM_F_CREATE|NLM_F_EXCL))
+ ret = NFCT_T_NEW;
+ else
+ ret = NFCT_T_UPDATE;
+ } else if (type == IPCTNL_MSG_EXP_DELETE)
+ ret = NFCT_T_DESTROY;
+
+ return ret;
+}
+
+void __parse_expect(const struct nlmsghdr *nlh,
+ const struct nfattr *cda[],
+ struct nf_expect *exp)
+{
+ struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
+
+ /* XXX: this is ugly, clean it up, please */
+ exp->expected.tuple[__DIR_ORIG].l3protonum = nfhdr->nfgen_family;
+ set_bit(ATTR_ORIG_L3PROTO, exp->expected.set);
+
+ exp->mask.tuple[__DIR_REPL].l3protonum = nfhdr->nfgen_family;
+ set_bit(ATTR_ORIG_L3PROTO, exp->mask.set);
+
+ if (cda[CTA_EXPECT_TUPLE-1])
+ __parse_tuple(cda[CTA_EXPECT_TUPLE-1],
+ &exp->expected.tuple[__DIR_ORIG],
+ __DIR_ORIG,
+ exp->set);
+
+ if (cda[CTA_EXPECT_MASK-1])
+ __parse_tuple(cda[CTA_EXPECT_MASK-1],
+ &exp->mask.tuple[__DIR_ORIG],
+ __DIR_ORIG,
+ exp->set);
+
+ if (cda[CTA_EXPECT_TIMEOUT-1]) {
+ exp->timeout =
+ ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_TIMEOUT-1]));
+ set_bit(ATTR_EXP_TIMEOUT, exp->set);
+ }
+}
diff --git a/src/expect/setter.c b/src/expect/setter.c
new file mode 100644
index 0000000..ae80ca8
--- /dev/null
+++ b/src/expect/setter.c
@@ -0,0 +1,35 @@
+/*
+ * (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.h"
+
+static void set_exp_attr_master(struct nf_expect *exp, const void *value)
+{
+ exp->master = *((struct nf_conntrack *) value);
+}
+
+static void set_exp_attr_expected(struct nf_expect *exp, const void *value)
+{
+ exp->expected = *((struct nf_conntrack *) value);
+}
+
+static void set_exp_attr_mask(struct nf_expect *exp, const void *value)
+{
+ exp->mask = *((struct nf_conntrack *) value);
+}
+
+static void set_exp_attr_timeout(struct nf_expect *exp, const void *value)
+{
+ exp->timeout = *((u_int32_t *) value);
+}
+
+set_exp_attr set_exp_attr_array[] = {
+ [ATTR_EXP_MASTER] = set_exp_attr_master,
+ [ATTR_EXP_EXPECTED] = set_exp_attr_expected,
+ [ATTR_EXP_MASK] = set_exp_attr_mask,
+ [ATTR_EXP_TIMEOUT] = set_exp_attr_timeout,
+};
diff --git a/src/expect/snprintf.c b/src/expect/snprintf.c
new file mode 100644
index 0000000..b981625
--- /dev/null
+++ b/src/expect/snprintf.c
@@ -0,0 +1,33 @@
+/*
+ * (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.h"
+
+int __snprintf_expect(char *buf,
+ unsigned int len,
+ const struct nf_expect *exp,
+ unsigned int type,
+ unsigned int msg_output,
+ unsigned int flags)
+{
+ int size;
+
+ switch(msg_output) {
+ case NFCT_O_DEFAULT:
+ size = __snprintf_expect_default(buf, len, exp, type, flags);
+ break;
+ default:
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* NULL terminated string */
+ if (snprintf(buf+size, len-size, "\0") == -1)
+ return -1;
+
+ return size;
+}
diff --git a/src/expect/snprintf_default.c b/src/expect/snprintf_default.c
new file mode 100644
index 0000000..1b64eb2
--- /dev/null
+++ b/src/expect/snprintf_default.c
@@ -0,0 +1,62 @@
+/*
+ * (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.h"
+
+static int __snprintf_expect_proto(char *buf,
+ unsigned int len,
+ const struct nf_expect *exp)
+{
+ return(snprintf(buf, len, "%u proto=%d ",
+ exp->timeout,
+ exp->expected.tuple[__DIR_ORIG].protonum));
+}
+
+int __snprintf_expect_default(char *buf,
+ unsigned int remain,
+ const struct nf_expect *exp,
+ unsigned int msg_type,
+ unsigned int flags)
+{
+ int ret = 0, size = 0;
+
+ switch(msg_type) {
+ case NFCT_T_NEW:
+ ret = snprintf(buf, remain, "%9s ", "[NEW]");
+ break;
+ default:
+ break;
+ }
+
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+
+ ret = __snprintf_expect_proto(buf+size, remain, exp);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+
+ ret = __snprintf_address(buf+size, remain, &exp->expected.tuple[__DIR_ORIG]);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+
+ ret = __snprintf_proto(buf+size, remain, &exp->expected.tuple[__DIR_ORIG]);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+
+ /* Delete the last blank space */
+ size--;
+
+ return size;
+}