summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
author/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org </C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org>2006-12-19 17:41:53 +0000
committer/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org </C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org>2006-12-19 17:41:53 +0000
commitb4c3a23c884c24f4e5d941fb928cf49561a9cdf9 (patch)
tree1b171cb10c87258f590650761f020cbcb77ebc97 /src
parent9cd6994c1d784e55fb009d6ab0ddc5832158a77d (diff)
Introduce the new libnetfilter_conntrack API, features:
- object oriented infrastructure - extensible and configurable output (XML) - low level functions to interact with netlink details - fairly documented Still backward compatible.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/conntrack/Makefile.am17
-rw-r--r--src/conntrack/api.c596
-rw-r--r--src/conntrack/build.c284
-rw-r--r--src/conntrack/callback.c53
-rw-r--r--src/conntrack/getter.c197
-rw-r--r--src/conntrack/objopt.c71
-rw-r--r--src/conntrack/parse.c295
-rw-r--r--src/conntrack/setter.c173
-rw-r--r--src/conntrack/snprintf.c36
-rw-r--r--src/conntrack/snprintf_default.c344
-rw-r--r--src/conntrack/snprintf_xml.c413
-rw-r--r--src/libnetfilter_conntrack.c23
13 files changed, 2492 insertions, 13 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 8a1278b..87911ce 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,11 +4,14 @@ include $(top_srcdir)/Make_global.am
#EXTRA_DIST = $(man_MANS) acinclude.m4
+SUBDIRS=conntrack
+
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_LDFLAGS = -Wc,-nostartfiles -lnfnetlink -ldl \
-version-info $(LIBVERSION)
libnetfilter_conntrack_la_SOURCES = libnetfilter_conntrack.c
diff --git a/src/conntrack/Makefile.am b/src/conntrack/Makefile.am
new file mode 100644
index 0000000..c58c09d
--- /dev/null
+++ b/src/conntrack/Makefile.am
@@ -0,0 +1,17 @@
+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_new_api.la
+
+libnetfilter_conntrack_new_api_la_SOURCES = api.c callback.c \
+ getter.c setter.c \
+ parse.c build.c \
+ snprintf.c \
+ snprintf_default.c snprintf_xml.c \
+ objopt.c
diff --git a/src/conntrack/api.c b/src/conntrack/api.c
new file mode 100644
index 0000000..1646839
--- /dev/null
+++ b/src/conntrack/api.c
@@ -0,0 +1,596 @@
+/*
+ * (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 <stdlib.h>
+#include <string.h> /* for memset */
+#include <errno.h>
+#include <assert.h>
+
+#include "internal.h"
+
+/**
+ * nfct_conntrack_new - allocate a new conntrack
+ *
+ * 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_conntrack *nfct_new()
+{
+ struct nf_conntrack *ct;
+
+ ct = malloc(sizeof(struct nf_conntrack));
+ if (!ct)
+ return NULL;
+
+ memset(ct, 0, sizeof(struct nf_conntrack));
+
+ /* always work with confirmed conntracks */
+// ct->status |= IPS_CONFIRMED;
+
+ return ct;
+}
+
+/**
+ * nf_conntrack_destroy - release a conntrack object
+ * @ct: pointer to the conntrack object
+ */
+void nfct_destroy(struct nf_conntrack *ct)
+{
+ assert(ct != NULL);
+ free(ct);
+ ct = NULL; /* bugtrap */
+}
+
+/**
+ * nf_sizeof - return the size of a certain conntrack object
+ * @ct: pointer to the conntrack object
+ */
+size_t nfct_sizeof(const struct nf_conntrack *ct)
+{
+ assert(ct != NULL);
+ return sizeof(*ct);
+}
+
+/**
+ * nfct_clone - clone a conntrack object
+ * @ct: pointer to a valid conntrack object
+ *
+ * On error, NULL is returned and errno is appropiately set. Otherwise,
+ * a valid pointer to the clone conntrack is returned.
+ */
+struct nf_conntrack *nfct_clone(const struct nf_conntrack *ct)
+{
+ struct nf_conntrack *clone;
+
+ assert(ct != NULL);
+
+ if ((clone = nfct_new()) == NULL)
+ return NULL;
+ memcpy(clone, ct, sizeof(*ct));
+
+ return clone;
+}
+
+/**
+ * nfct_setobjopt - set a certain option for a conntrack object
+ * @ct: conntrack object
+ * @option: option parameter
+ *
+ * In case of error, -1 is returned and errno is appropiately set. On success,
+ * 0 is returned.
+ */
+int nfct_setobjopt(struct nf_conntrack *ct, unsigned int option)
+{
+ assert(ct != NULL);
+
+ if (option > NFCT_SOPT_MAX) {
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+
+ return __setobjopt(ct, option);
+}
+
+/**
+ * nfct_getobjopt - get a certain option for a conntrack object
+ * @ct: conntrack object
+ * @option: option parameter
+ *
+ * In case of error, -1 is returned and errno is appropiately set. On success,
+ * 0 is returned.
+ */
+int nfct_getobjopt(const struct nf_conntrack *ct, unsigned int option)
+{
+ assert(ct != NULL);
+
+ if (option > NFCT_GOPT_MAX) {
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+
+ return __getobjopt(ct, option);
+}
+
+/**
+ * nf_callback_register - register a callback
+ * @h: library handler
+ * @cb: callback used to process conntrack received
+ * @data: data used by the callback, if any.
+ *
+ * This function register a callback to handle the conntrack 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 nfct_callback_register(struct nfct_handle *h,
+ enum nf_conntrack_msg_type type,
+ int (*cb)(enum nf_conntrack_msg_type type,
+ struct nf_conntrack *ct,
+ 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->cb = cb;
+ container->h = h;
+ container->type = type;
+ container->data = data;
+
+ h->nfnl_cb.call = __callback;
+ h->nfnl_cb.data = container;
+ h->nfnl_cb.attr_count = CTA_MAX;
+
+ nfnl_callback_register(h->nfnlssh_ct,
+ IPCTNL_MSG_CT_NEW,
+ &h->nfnl_cb);
+
+ nfnl_callback_register(h->nfnlssh_ct,
+ IPCTNL_MSG_CT_DELETE,
+ &h->nfnl_cb);
+
+ return 0;
+}
+
+/**
+ * nfct_callback_unregister - unregister a callback
+ * @h: library handler
+ */
+void nfct_callback_unregister(struct nfct_handle *h)
+{
+ assert(h != NULL);
+
+ nfnl_callback_unregister(h->nfnlssh_ct, IPCTNL_MSG_CT_NEW);
+ nfnl_callback_unregister(h->nfnlssh_ct, IPCTNL_MSG_CT_DELETE);
+
+ h->cb = NULL;
+ free(h->nfnl_cb.data);
+
+ h->nfnl_cb.call = NULL;
+ h->nfnl_cb.data = NULL;
+ h->nfnl_cb.attr_count = 0;
+}
+
+/**
+ * nfct_set_attr - set the value of a certain conntrack attribute
+ * @ct: pointer to a valid conntrack
+ * @type: attribute type
+ * @value: pointer to the attribute value
+ */
+void nfct_set_attr(struct nf_conntrack *ct,
+ const enum nf_conntrack_attr type,
+ void *value)
+{
+ assert(ct != NULL);
+ assert(value != NULL);
+
+ if (type >= ATTR_MAX)
+ return;
+
+ set_attr_array[type](ct, value);
+ set_bit(type, ct->set);
+}
+
+/**
+ * nfct_set_attr_u8 - set the value of a certain conntrack attribute
+ * @ct: pointer to a valid conntrack
+ * @type: attribute type
+ * @value: unsigned 8 bits attribute value
+ */
+void nfct_set_attr_u8(struct nf_conntrack *ct,
+ const enum nf_conntrack_attr type,
+ u_int8_t value)
+{
+ nfct_set_attr(ct, type, &value);
+}
+
+/**
+ * nfct_set_attr_u16 - set the value of a certain conntrack attribute
+ * @ct: pointer to a valid conntrack
+ * @type: attribute type
+ * @value: unsigned 16 bits attribute value
+ */
+void nfct_set_attr_u16(struct nf_conntrack *ct,
+ const enum nf_conntrack_attr type,
+ u_int16_t value)
+{
+ nfct_set_attr(ct, type, &value);
+}
+
+/**
+ * nfct_set_attr_u32 - set the value of a certain conntrack attribute
+ * @ct: pointer to a valid conntrack
+ * @type: attribute type
+ * @value: unsigned 32 bits attribute value
+ */
+void nfct_set_attr_u32(struct nf_conntrack *ct,
+ const enum nf_conntrack_attr type,
+ u_int32_t value)
+{
+ nfct_set_attr(ct, type, &value);
+}
+
+/**
+ * nfct_get_attr - get a conntrack attribute
+ * ct: pointer to a valid conntrack
+ * @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 *nfct_get_attr(const struct nf_conntrack *ct,
+ const enum nf_conntrack_attr type)
+{
+ assert(ct != NULL);
+
+ if (type >= ATTR_MAX) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (!test_bit(type, ct->set)) {
+ errno = ENODATA;
+ return NULL;
+ }
+
+ return get_attr_array[type](ct);
+}
+
+/**
+ * nfct_get_attr_u8 - get attribute of unsigned 8-bits long
+ * @ct: pointer to a valid conntrack
+ * @type: attribute type
+ *
+ * On error, -1 is returned and errno is set appropiately, otherwise
+ * the value of the attribute is returned.
+ */
+u_int8_t nfct_get_attr_u8(const struct nf_conntrack *ct,
+ const enum nf_conntrack_attr type)
+{
+ const int *ret = nfct_get_attr(ct, type);
+ return ret == NULL ? 0 : *ret;
+}
+
+/**
+ * nfct_get_attr_u16 - get attribute of unsigned 16-bits long
+ * @ct: pointer to a valid conntrack
+ * @type: attribute type
+ *
+ * On error, -1 is returned and errno is set appropiately, otherwise
+ * the value of the attribute is returned.
+ */
+u_int16_t nfct_get_attr_u16(const struct nf_conntrack *ct,
+ const enum nf_conntrack_attr type)
+{
+ const int *ret = nfct_get_attr(ct, type);
+ return ret == NULL ? 0 : *ret;
+}
+
+/**
+ * nfct_get_attr_u32 - get attribute of unsigned 32-bits long
+ * @ct: pointer to a valid conntrack
+ * @type: attribute type
+ *
+ * On error, -1 is returned and errno is set appropiately, otherwise
+ * the value of the attribute is returned.
+ */
+u_int32_t nfct_get_attr_u32(const struct nf_conntrack *ct,
+ const enum nf_conntrack_attr type)
+{
+ const int *ret = nfct_get_attr(ct, type);
+ return ret == NULL ? 0 : *ret;
+}
+
+/**
+ * nfct_attr_is_set - check if a certain attribute is set
+ * @ct: pointer to a valid conntrack object
+ * @type: attribute type
+ *
+ * On error, -1 is returned and errno is set appropiately, otherwise
+ * the value of the attribute is returned.
+ */
+int nfct_attr_is_set(const struct nf_conntrack *ct,
+ const enum nf_conntrack_attr type)
+{
+ assert(ct != NULL);
+
+ if (type >= ATTR_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+ return test_bit(type, ct->set);
+}
+
+/**
+ * nfct_attr_unset - unset a certain attribute
+ * @type: attribute type
+ * @ct: pointer to a valid conntrack object
+ *
+ * On error, -1 is returned and errno is set appropiately, otherwise
+ * 0 is returned.
+ */
+int nfct_attr_unset(struct nf_conntrack *ct,
+ const enum nf_conntrack_attr type)
+{
+ assert(ct != NULL);
+
+ if (type >= ATTR_MAX) {
+ errno = EINVAL;
+ return -1;
+ }
+ unset_bit(type, ct->set);
+
+ return 0;
+}
+
+/**
+ * nfct_build_conntrack - 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
+ * @ct: 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 nfct_query.
+ *
+ * On error, -1 is returned and errno is appropiately set.
+ * On success, 0 is returned.
+ */
+int nfct_build_conntrack(struct nfnl_subsys_handle *ssh,
+ void *req,
+ size_t size,
+ u_int16_t type,
+ u_int16_t flags,
+ const struct nf_conntrack *ct)
+{
+ assert(ssh != NULL);
+ assert(req != NULL);
+ assert(ct != NULL);
+
+ return __build_conntrack(ssh, req, size, type, flags, ct);
+}
+
+/**
+ * nfct_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 nfct_query.
+ *
+ * The pointer to data can be a conntrack object or the protocol family
+ * depending on the request.
+ *
+ * For query types:
+ * NFCT_Q_CREATE
+ * NFCT_Q_UPDATE
+ * NFCT_Q_DESTROY
+ * NFCT_Q_GET
+ *
+ * Pass a valid pointer to a conntrack object.
+ *
+ * For query types:
+ * NFCT_Q_FLUSH
+ * NFCT_Q_DUMP
+ * NFCT_Q_DUMP_RESET
+ *
+ * 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 nfct_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:
+ nfct_build_conntrack(ssh, req, size, IPCTNL_MSG_CT_NEW, NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK|NLM_F_EXCL, data);
+ break;
+ case NFCT_Q_UPDATE:
+ nfct_build_conntrack(ssh, req, size, IPCTNL_MSG_CT_NEW, NLM_F_REQUEST|NLM_F_ACK, data);
+ break;
+ case NFCT_Q_DESTROY:
+ nfct_build_conntrack(ssh, req, size, IPCTNL_MSG_CT_DELETE, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK, data);
+ break;
+ case NFCT_Q_GET:
+ nfct_build_conntrack(ssh, req, size, IPCTNL_MSG_CT_GET, NLM_F_REQUEST|NLM_F_ACK, data);
+ break;
+ case NFCT_Q_FLUSH:
+ nfnl_fill_hdr(ssh, &req->nlh, 0, *family, 0, IPCTNL_MSG_CT_DELETE, NLM_F_REQUEST|NLM_F_ACK);
+ break;
+ case NFCT_Q_DUMP:
+ nfnl_fill_hdr(ssh, &req->nlh, 0, *family, 0, IPCTNL_MSG_CT_GET, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_DUMP);
+ break;
+ case NFCT_Q_DUMP_RESET:
+ nfnl_fill_hdr(ssh, &req->nlh, 0, *family, 0, IPCTNL_MSG_CT_GET_CTRZERO, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_DUMP);
+ break;
+ default:
+ errno = ENOTSUP;
+ return -1;
+ }
+ return 1;
+}
+
+/**
+ * nfct_parse_conntrack - 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
+ * @ct: 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:
+ *
+ * NFCT_T_NEW: parse messages with new conntracks
+ * NFCT_T_UPDATE: parse messages with conntrack updates
+ * NFCT_T_DESTROY: parse messages with conntrack destroy
+ * NFCT_T_ALL: all message types
+ *
+ * The message type is a flag, therefore the can be combined, ie.
+ * NFCT_T_NEW | NFCT_T_DESTROY to parse only new and destroy messages
+ *
+ * On error, NFCT_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 nfct_parse_conntrack(enum nf_conntrack_msg_type type,
+ const struct nlmsghdr *nlh,
+ struct nf_conntrack *ct)
+{
+ unsigned int flags;
+ int len = nlh->nlmsg_len;
+ struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
+ struct nfattr *cda[CTA_MAX];
+
+ assert(nlh != NULL);
+ assert(ct != NULL);
+
+ len -= NLMSG_LENGTH(sizeof(struct nfgenmsg));
+ if (len < 0) {
+ errno = EINVAL;
+ return NFCT_T_ERROR;
+ }
+
+ flags = __parse_message_type(nlh);
+ if (!(flags & type))
+ return 0;
+
+ nfnl_parse_attr(cda, CTA_MAX, NFA_DATA(nfhdr), len);
+
+ __parse_conntrack(nlh, cda, ct);
+
+ return flags;
+}
+
+/**
+ * nfct_query - send a query to ctnetlin
+ * @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 nfct_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 (nfct_build_query(h->nfnlssh_ct, qt, data, req, size) == -1)
+ return -1;
+
+ return nfnl_query(h->nfnlh, &req->nlh);
+}
+
+/**
+ * nfct_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
+ * verdict: NFCT_CB_STOP, NFCT_CB_CONTINUE or NFCT_CB_STOLEN
+ */
+int nfct_catch(struct nfct_handle *h)
+{
+ assert(h != NULL);
+
+ return nfnl_catch(h->nfnlh);
+}
+
+/**
+ * nfct_snprintf - print a conntrack object to a buffer
+ * @buf: buffer used to build the printable conntrack
+ * @size: size of the buffer
+ * @ct: pointer to a valid conntrack object
+ * @message_type: print message type (NFCT_T_UNKNOWN, NFCT_T_NEW,...)
+ * @output_type: print type (NFCT_O_DEFAULT, NFCT_O_XML, ...)
+ * @flags: extra flags for the output type (NFCT_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. NFCT_T_NEW, NFCT_T_UPDATE, NFCT_T_DESTROY.
+ * If you pass NFCT_T_UNKNOWN, the message type will not be output.
+ *
+ * Currently, the output available are:
+ * - NFCT_O_DEFAULT: default /proc-like output
+ * - NFCT_O_XML: XML output
+ *
+ * The output flags are:
+ * - NFCT_O_LAYER: include layer 3 information in the output, this is
+ * *only* required by NFCT_O_DEFAULT.
+ *
+ * On error, -1 is returned and errno is set appropiately. Otherwise,
+ * 0 is returned.
+ */
+int nfct_snprintf(char *buf,
+ unsigned int size,
+ const struct nf_conntrack *ct,
+ unsigned int msg_type,
+ unsigned int out_type,
+ unsigned int flags)
+{
+ assert(buf != NULL);
+ assert(size > 0);
+ assert(ct != NULL);
+
+ return __snprintf_conntrack(buf, size, ct, msg_type, out_type, flags);
+}
diff --git a/src/conntrack/build.c b/src/conntrack/build.c
new file mode 100644
index 0000000..e8d5276
--- /dev/null
+++ b/src/conntrack/build.c
@@ -0,0 +1,284 @@
+/*
+ * (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.h"
+
+void __build_tuple_ip(struct nfnlhdr *req,
+ size_t size,
+ const struct __nfct_tuple *t)
+{
+ struct nfattr *nest;
+
+ nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_IP);
+
+ switch(t->l3protonum) {
+ case AF_INET:
+ nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_SRC, &t->src.v4,
+ sizeof(u_int32_t));
+ nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_DST, &t->dst.v4,
+ sizeof(u_int32_t));
+ break;
+ case AF_INET6:
+ nfnl_addattr_l(&req->nlh, size, CTA_IP_V6_SRC, &t->src.v6,
+ sizeof(struct in6_addr));
+ nfnl_addattr_l(&req->nlh, size, CTA_IP_V6_DST, &t->dst.v6,
+ sizeof(struct in6_addr));
+ break;
+ default:
+ break;
+ }
+
+ nfnl_nest_end(&req->nlh, nest);
+}
+
+void __build_tuple_proto(struct nfnlhdr *req,
+ size_t size,
+ const struct __nfct_tuple *t)
+{
+ struct nfattr *nest;
+
+ nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_PROTO);
+
+ nfnl_addattr_l(&req->nlh, size, CTA_PROTO_NUM, &t->protonum,
+ sizeof(u_int8_t));
+
+ switch(t->protonum) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPPROTO_SCTP:
+ nfnl_addattr_l(&req->nlh, size, CTA_PROTO_SRC_PORT,
+ &t->l4src.tcp.port, sizeof(u_int16_t));
+ nfnl_addattr_l(&req->nlh, size, CTA_PROTO_DST_PORT,
+ &t->l4dst.tcp.port, sizeof(u_int16_t));
+ break;
+ case IPPROTO_ICMP:
+ nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_CODE,
+ &t->l4dst.icmp.code, sizeof(u_int8_t));
+ nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_TYPE,
+ &t->l4dst.icmp.type, sizeof(u_int8_t));
+ nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_ID,
+ &t->l4src.icmp.id, sizeof(u_int16_t));
+ break;
+ default:
+ break;
+ }
+
+ nfnl_nest_end(&req->nlh, nest);
+}
+
+void __build_tuple(struct nfnlhdr *req,
+ size_t size,
+ const struct __nfct_tuple *t,
+ const int type)
+{
+ struct nfattr *nest;
+
+ nest = nfnl_nest(&req->nlh, size, type);
+
+ __build_tuple_ip(req, size, t);
+ __build_tuple_proto(req, size, t);
+
+ nfnl_nest_end(&req->nlh, nest);
+}
+
+void __build_protoinfo(struct nfnlhdr *req,
+ size_t size,
+ const struct nf_conntrack *ct)
+{
+ struct nfattr *nest, *nest_proto;
+
+ switch(ct->tuple[__DIR_ORIG].protonum) {
+ case IPPROTO_TCP:
+ nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO);
+ nest_proto = nfnl_nest(&req->nlh, size, CTA_PROTOINFO_TCP);
+ nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_TCP_STATE,
+ &ct->protoinfo.tcp.state, sizeof(u_int8_t));
+ nfnl_nest_end(&req->nlh, nest_proto);
+ nfnl_nest_end(&req->nlh, nest);
+ break;
+ default:
+ break;
+ }
+}
+
+void __build_protonat(struct nfnlhdr *req,
+ size_t size,
+ const struct nf_conntrack *ct,
+ const struct __nfct_nat *nat)
+{
+ struct nfattr *nest;
+
+ nest = nfnl_nest(&req->nlh, size, CTA_NAT_PROTO);
+
+ switch (ct->tuple[NFCT_DIR_ORIGINAL].protonum) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_PORT_MIN,
+ &nat->l4min.tcp.port, sizeof(u_int16_t));
+ nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_PORT_MAX,
+ &nat->l4max.tcp.port, sizeof(u_int16_t));
+ break;
+ }
+ nfnl_nest_end(&req->nlh, nest);
+}
+
+void __build_nat(struct nfnlhdr *req,
+ size_t size,
+ const struct __nfct_nat *nat)
+{
+ nfnl_addattr_l(&req->nlh, size, CTA_NAT_MINIP,
+ &nat->min_ip, sizeof(u_int32_t));
+}
+
+void __build_snat(struct nfnlhdr *req,
+ size_t size,
+ const struct nf_conntrack *ct)
+{
+ struct nfattr *nest;
+
+ nest = nfnl_nest(&req->nlh, size, CTA_NAT_SRC);
+ __build_nat(req, size, &ct->snat);
+ __build_protonat(req, size, ct, &ct->snat);
+ nfnl_nest_end(&req->nlh, nest);
+}
+
+void __build_snat_ipv4(struct nfnlhdr *req,
+ size_t size,
+ const struct nf_conntrack *ct)
+{
+ struct nfattr *nest;
+
+ nest = nfnl_nest(&req->nlh, size, CTA_NAT_SRC);
+ __build_nat(req, size, &ct->snat);
+ nfnl_nest_end(&req->nlh, nest);
+}
+
+void __build_snat_port(struct nfnlhdr *req,
+ size_t size,
+ const struct nf_conntrack *ct)
+{
+ struct nfattr *nest;
+
+ nest = nfnl_nest(&req->nlh, size, CTA_NAT_SRC);
+ __build_protonat(req, size, ct, &ct->snat);
+ nfnl_nest_end(&req->nlh, nest);
+}
+
+void __build_dnat(struct nfnlhdr *req,
+ size_t size,
+ const struct nf_conntrack *ct)
+{
+ struct nfattr *nest;
+
+ nest = nfnl_nest(&req->nlh, size, CTA_NAT_DST);
+ __build_nat(req, size, &ct->dnat);
+ __build_protonat(req, size, ct, &ct->dnat);
+ nfnl_nest_end(&req->nlh, nest);
+}
+
+void __build_dnat_ipv4(struct nfnlhdr *req,
+ size_t size,
+ const struct nf_conntrack *ct)
+{
+ struct nfattr *nest;
+
+ nest = nfnl_nest(&req->nlh, size, CTA_NAT_DST);
+ __build_nat(req, size, &ct->dnat);
+ nfnl_nest_end(&req->nlh, nest);
+}
+
+void __build_dnat_port(struct nfnlhdr *req,
+ size_t size,
+ const struct nf_conntrack *ct)
+{
+ struct nfattr *nest;
+
+ nest = nfnl_nest(&req->nlh, size, CTA_NAT_DST);
+ __build_protonat(req, size, ct, &ct->dnat);
+ nfnl_nest_end(&req->nlh, nest);
+}
+
+void __build_status(struct nfnlhdr *req,
+ size_t size,
+ const struct nf_conntrack *ct)
+{
+ nfnl_addattr32(&req->nlh, size, CTA_STATUS,
+ htonl(ct->status | IPS_CONFIRMED));
+}
+
+void __build_timeout(struct nfnlhdr *req,
+ size_t size,
+ const struct nf_conntrack *ct)
+{
+ nfnl_addattr32(&req->nlh, size, CTA_TIMEOUT, htonl(ct->timeout));
+}
+
+void __build_mark(struct nfnlhdr *req,
+ size_t size,
+ const struct nf_conntrack *ct)
+{
+ nfnl_addattr32(&req->nlh, size, CTA_MARK, htonl(ct->mark));
+}
+
+void __build_id(struct nfnlhdr *req,
+ size_t size,
+ const const struct nf_conntrack *ct)
+{
+ nfnl_addattr32(&req->nlh, size, CTA_ID, htonl(ct->id));
+}
+
+int __build_conntrack(struct nfnl_subsys_handle *ssh,
+ struct nfnlhdr *req,
+ size_t size,
+ u_int16_t type,
+ u_int16_t flags,
+ const struct nf_conntrack *ct)
+{
+ u_int8_t l3num = ct->tuple[NFCT_DIR_ORIGINAL].l3protonum;
+
+ if (!test_bit(ATTR_ORIG_L3PROTO, ct->set)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(req, 0, size);
+
+ nfnl_fill_hdr(ssh, &req->nlh, 0, l3num, 0, type, flags);
+
+ __build_tuple(req, size, &ct->tuple[__DIR_ORIG], CTA_TUPLE_ORIG);
+ __build_tuple(req, size, &ct->tuple[__DIR_REPL], CTA_TUPLE_REPLY);
+
+ /* always build IPS_CONFIRMED */
+ __build_status(req, size, ct);
+
+ if (test_bit(ATTR_TIMEOUT, ct->set))
+ __build_timeout(req, size, ct);
+
+ if (test_bit(ATTR_MARK, ct->set))
+ __build_mark(req, size, ct);
+
+ if (test_bit(ATTR_TCP_STATE, ct->set))
+ __build_protoinfo(req, size, ct);
+
+ if (test_bit(ATTR_SNAT_IPV4, ct->set) &&
+ test_bit(ATTR_SNAT_PORT, ct->set))
+ __build_snat(req, size, ct);
+ else if (test_bit(ATTR_SNAT_IPV4, ct->set))
+ __build_snat_ipv4(req, size, ct);
+ else if (test_bit(ATTR_SNAT_PORT, ct->set))
+ __build_snat_port(req, size, ct);
+
+ if (test_bit(ATTR_DNAT_IPV4, ct->set) &&
+ test_bit(ATTR_DNAT_PORT, ct->set))
+ __build_dnat(req, size, ct);
+ else if (test_bit(ATTR_DNAT_IPV4, ct->set))
+ __build_dnat_ipv4(req, size, ct);
+ else if (test_bit(ATTR_DNAT_PORT, ct->set))
+ __build_dnat_port(req, size, ct);
+
+ return 0;
+}
diff --git a/src/conntrack/callback.c b/src/conntrack/callback.c
new file mode 100644
index 0000000..582dfc4
--- /dev/null
+++ b/src/conntrack/callback.c
@@ -0,0 +1,53 @@
+/*
+ * (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.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);
+
+ 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/conntrack/getter.c b/src/conntrack/getter.c
new file mode 100644
index 0000000..7e19978
--- /dev/null
+++ b/src/conntrack/getter.c
@@ -0,0 +1,197 @@
+/*
+ * (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.h"
+
+static const void *get_attr_orig_ipv4_src(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_ORIG].src.v4;
+}
+
+static const void *get_attr_orig_ipv4_dst(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_ORIG].dst.v4;
+}
+
+static const void *get_attr_repl_ipv4_src(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_REPL].src.v4;
+}
+
+static const void *get_attr_repl_ipv4_dst(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_REPL].dst.v4;
+}
+
+static const void *get_attr_orig_ipv6_src(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_ORIG].src.v6;
+}
+
+static const void *get_attr_orig_ipv6_dst(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_ORIG].dst.v6;
+}
+
+static const void *get_attr_repl_ipv6_src(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_REPL].src.v6;
+}
+
+static const void *get_attr_repl_ipv6_dst(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_REPL].dst.v6;
+}
+
+static const void *get_attr_orig_port_src(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_ORIG].l4src.all;
+}
+
+static const void *get_attr_orig_port_dst(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_ORIG].l4dst.all;
+}
+
+static const void *get_attr_repl_port_src(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_REPL].l4src.all;
+}
+
+static const void *get_attr_repl_port_dst(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_REPL].l4dst.all;
+}
+
+static const void *get_attr_icmp_type(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_ORIG].l4dst.icmp.type;
+}
+
+static const void *get_attr_icmp_code(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_ORIG].l4dst.icmp.code;
+}
+
+static const void *get_attr_icmp_id(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_ORIG].l4src.icmp.id;
+}
+
+static const void *get_attr_orig_l3proto(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_ORIG].l3protonum;
+}
+
+static const void *get_attr_repl_l3proto(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_REPL].l3protonum;
+}
+
+static const void *get_attr_orig_l4proto(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_ORIG].protonum;
+}
+
+static const void *get_attr_repl_l4proto(const struct nf_conntrack *ct)
+{
+ return &ct->tuple[__DIR_REPL].protonum;
+}
+
+static const void *get_attr_tcp_state(const struct nf_conntrack *ct)
+{
+ return &ct->protoinfo.tcp.state;
+}
+
+static const void *get_attr_snat_ipv4(const struct nf_conntrack *ct)
+{
+ return &ct->snat.min_ip;
+}
+
+static const void *get_attr_dnat_ipv4(const struct nf_conntrack *ct)
+{
+ return &ct->dnat.min_ip;
+}
+
+static const void *get_attr_snat_port(const struct nf_conntrack *ct)
+{
+ return &ct->snat.l4min.all;
+}
+
+static const void *get_attr_dnat_port(const struct nf_conntrack *ct)
+{
+ return &ct->dnat.l4min.all;
+}
+
+static const void *get_attr_timeout(const struct nf_conntrack *ct)
+{
+ return &ct->timeout;
+}
+
+static const void *get_attr_mark(const struct nf_conntrack *ct)
+{
+ return &ct->mark;
+}
+
+static const void *get_attr_orig_counter_packets(const struct nf_conntrack *ct)
+{
+ return &ct->counters[__DIR_ORIG].packets;
+}
+
+static const void *get_attr_orig_counter_bytes(const struct nf_conntrack *ct)
+{
+ return &ct->counters[__DIR_ORIG].bytes;
+}
+
+static const void *get_attr_repl_counter_packets(const struct nf_conntrack *ct)
+{
+ return &ct->counters[__DIR_REPL].packets;
+}
+
+static const void *get_attr_repl_counter_bytes(const struct nf_conntrack *ct)
+{
+ return &ct->counters[__DIR_REPL].bytes;
+}
+
+static const void *get_attr_status(const struct nf_conntrack *ct)
+{
+ return &ct->status;
+}
+
+get_attr get_attr_array[] = {
+ [ATTR_ORIG_IPV4_SRC] = get_attr_orig_ipv4_src,
+ [ATTR_ORIG_IPV4_DST] = get_attr_orig_ipv4_dst,
+ [ATTR_REPL_IPV4_SRC] = get_attr_repl_ipv4_src,
+ [ATTR_REPL_IPV4_DST] = get_attr_repl_ipv4_dst,
+ [ATTR_ORIG_IPV6_SRC] = get_attr_orig_ipv6_src,
+ [ATTR_ORIG_IPV6_DST] = get_attr_orig_ipv6_dst,
+ [ATTR_REPL_IPV6_SRC] = get_attr_repl_ipv6_src,
+ [ATTR_REPL_IPV6_DST] = get_attr_repl_ipv6_dst,
+ [ATTR_ORIG_PORT_SRC] = get_attr_orig_port_src,
+ [ATTR_ORIG_PORT_DST] = get_attr_orig_port_dst,
+ [ATTR_REPL_PORT_SRC] = get_attr_repl_port_src,
+ [ATTR_REPL_PORT_DST] = get_attr_repl_port_dst,
+ [ATTR_ICMP_TYPE] = get_attr_icmp_type,
+ [ATTR_ICMP_CODE] = get_attr_icmp_code,
+ [ATTR_ICMP_ID] = get_attr_icmp_id,
+ [ATTR_ORIG_L3PROTO] = get_attr_orig_l3proto,
+ [ATTR_REPL_L3PROTO] = get_attr_repl_l3proto,
+ [ATTR_ORIG_L4PROTO] = get_attr_orig_l4proto,
+ [ATTR_REPL_L4PROTO] = get_attr_repl_l4proto,
+ [ATTR_TCP_STATE] = get_attr_tcp_state,
+ [ATTR_SNAT_IPV4] = get_attr_snat_ipv4,
+ [ATTR_DNAT_IPV4] = get_attr_dnat_ipv4,
+ [ATTR_SNAT_PORT] = get_attr_snat_port,
+ [ATTR_DNAT_PORT] = get_attr_dnat_port,
+ [ATTR_TIMEOUT] = get_attr_timeout,
+ [ATTR_MARK] = get_attr_mark,
+ [ATTR_ORIG_COUNTER_PACKETS] = get_attr_orig_counter_packets,
+ [ATTR_ORIG_COUNTER_BYTES] = get_attr_orig_counter_bytes,
+ [ATTR_REPL_COUNTER_PACKETS] = get_attr_repl_counter_packets,
+ [ATTR_REPL_COUNTER_BYTES] = get_attr_repl_counter_bytes,
+ [ATTR_STATUS] = get_attr_status,
+};
diff --git a/src/conntrack/objopt.c b/src/conntrack/objopt.c
new file mode 100644
index 0000000..b495f55
--- /dev/null
+++ b/src/conntrack/objopt.c
@@ -0,0 +1,71 @@
+/*
+ * (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.h"
+
+int __setobjopt(struct nf_conntrack *ct, unsigned int option)
+{
+ switch(option) {
+ case NFCT_SOPT_UNDO_SNAT:
+ ct->snat.min_ip = ct->tuple[__DIR_REPL].dst.v4;
+ ct->snat.max_ip = ct->snat.min_ip;
+ ct->tuple[__DIR_REPL].dst.v4 = ct->tuple[__DIR_ORIG].src.v4;
+ set_bit(ATTR_SNAT_IPV4, ct->set);
+ break;
+ case NFCT_SOPT_UNDO_DNAT:
+ ct->dnat.min_ip = ct->tuple[__DIR_REPL].src.v4;
+ ct->dnat.max_ip = ct->dnat.min_ip;
+ ct->tuple[__DIR_REPL].src.v4 = ct->tuple[__DIR_ORIG].dst.v4;
+ set_bit(ATTR_DNAT_IPV4, ct->set);
+ break;
+ case NFCT_SOPT_UNDO_SPAT:
+ ct->snat.l4min.all = ct->tuple[__DIR_REPL].l4dst.tcp.port;
+ ct->snat.l4max.all = ct->snat.l4max.all;
+ ct->tuple[__DIR_REPL].l4dst.tcp.port =
+ ct->tuple[__DIR_ORIG].l4src.tcp.port;
+ set_bit(ATTR_SNAT_PORT, ct->set);
+ break;
+ case NFCT_SOPT_UNDO_DPAT:
+ ct->dnat.l4min.all = ct->tuple[__DIR_REPL].l4src.tcp.port;
+ ct->dnat.l4max.all = ct->dnat.l4min.all;
+ ct->tuple[__DIR_REPL].l4src.tcp.port =
+ ct->tuple[__DIR_ORIG].l4dst.tcp.port;
+ set_bit(ATTR_DNAT_PORT, ct->set);
+ break;
+ }
+ return 0;
+}
+
+int __getobjopt(const struct nf_conntrack *ct, unsigned int option)
+{
+ int ret = -1;
+
+ switch(option) {
+ case NFCT_GOPT_IS_SNAT:
+ ret = (ct->status & IPS_SRC_NAT_DONE &&
+ ct->tuple[__DIR_REPL].dst.v4 !=
+ ct->tuple[__DIR_ORIG].src.v4);
+ break;
+ case NFCT_GOPT_IS_DNAT:
+ ret = (ct->status & IPS_DST_NAT_DONE &&
+ ct->tuple[__DIR_REPL].src.v4 !=
+ ct->tuple[__DIR_ORIG].dst.v4);
+ break;
+ case NFCT_GOPT_IS_SPAT:
+ ret = (ct->status & IPS_SRC_NAT_DONE &&
+ ct->tuple[__DIR_REPL].l4dst.tcp.port !=
+ ct->tuple[__DIR_ORIG].l4src.tcp.port);
+ break;
+ case NFCT_GOPT_IS_DPAT:
+ ret = (ct->status & IPS_DST_NAT_DONE &&
+ ct->tuple[__DIR_REPL].l4src.tcp.port !=
+ ct->tuple[__DIR_ORIG].l4dst.tcp.port);
+ break;
+ }
+
+ return ret;
+}
diff --git a/src/conntrack/parse.c b/src/conntrack/parse.c
new file mode 100644
index 0000000..bfa6ae0
--- /dev/null
+++ b/src/conntrack/parse.c
@@ -0,0 +1,295 @@
+/*
+ * (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.h"
+
+static void __parse_ip(const struct nfattr *attr,
+ struct __nfct_tuple *tuple,
+ const int dir,
+ u_int32_t *set)
+{
+ struct nfattr *tb[CTA_IP_MAX];
+
+ nfnl_parse_nested(tb, CTA_IP_MAX, attr);
+
+ if (tb[CTA_IP_V4_SRC-1]) {
+ tuple->src.v4 = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
+ switch(dir) {
+ case __DIR_ORIG:
+ set_bit(ATTR_ORIG_IPV4_SRC, set);
+ break;
+ case __DIR_REPL:
+ set_bit(ATTR_REPL_IPV4_SRC, set);
+ break;
+ }
+ }
+
+ if (tb[CTA_IP_V4_DST-1]) {
+ tuple->dst.v4 = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
+ switch(dir) {
+ case __DIR_ORIG:
+ set_bit(ATTR_ORIG_IPV4_DST, set);
+ break;
+ case __DIR_REPL:
+ set_bit(ATTR_REPL_IPV4_DST, set);
+ break;
+ }
+ }
+
+ if (tb[CTA_IP_V6_SRC-1]) {
+ memcpy(&tuple->src.v6, NFA_DATA(tb[CTA_IP_V6_SRC-1]),
+ sizeof(struct in6_addr));
+ switch(dir) {
+ case __DIR_ORIG:
+ set_bit(ATTR_ORIG_IPV6_SRC, set);
+ break;
+ case __DIR_REPL:
+ set_bit(ATTR_REPL_IPV6_SRC, set);
+ break;
+ }
+ }
+
+ if (tb[CTA_IP_V6_DST-1]) {
+ memcpy(&tuple->dst.v6, NFA_DATA(tb[CTA_IP_V6_DST-1]),
+ sizeof(struct in6_addr));
+ switch(dir) {
+ case __DIR_ORIG:
+ set_bit(ATTR_ORIG_IPV6_DST, set);
+ break;
+ case __DIR_REPL:
+ set_bit(ATTR_REPL_IPV6_DST, set);
+ break;
+ }
+ }
+}
+
+static void __parse_proto(const struct nfattr *attr,
+ struct __nfct_tuple *tuple,
+ const int dir,
+ u_int32_t *set)
+{
+ struct nfattr *tb[CTA_PROTO_MAX];
+
+ nfnl_parse_nested(tb, CTA_PROTO_MAX, attr);
+
+ if (tb[CTA_PROTO_NUM-1]) {
+ tuple->protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]);
+ switch(dir) {
+ case __DIR_ORIG:
+ set_bit(ATTR_ORIG_L4PROTO, set);
+ break;
+ case __DIR_REPL:
+ set_bit(ATTR_REPL_L4PROTO, set);
+ break;
+ }
+ }
+
+ if (tb[CTA_PROTO_SRC_PORT-1]) {
+ tuple->l4src.tcp.port =
+ *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]);
+ switch(dir) {
+ case __DIR_ORIG:
+ set_bit(ATTR_ORIG_PORT_SRC, set);
+ break;
+ case __DIR_REPL:
+ set_bit(ATTR_REPL_PORT_SRC, set);
+ break;
+ }
+ }
+
+ if (tb[CTA_PROTO_DST_PORT-1]) {
+ tuple->l4dst.tcp.port =
+ *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]);
+ switch(dir) {
+ case __DIR_ORIG:
+ set_bit(ATTR_ORIG_PORT_DST, set);
+ break;
+ case __DIR_REPL:
+ set_bit(ATTR_REPL_PORT_DST, set);
+ break;
+ }
+ }
+
+ if (tb[CTA_PROTO_ICMP_TYPE-1]) {
+ tuple->l4dst.icmp.type =
+ *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]);
+ set_bit(ATTR_ICMP_TYPE, set);
+ }
+
+ if (tb[CTA_PROTO_ICMP_CODE-1]) {
+ tuple->l4dst.icmp.code =
+ *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]);
+ set_bit(ATTR_ICMP_CODE, set);
+ }
+
+ if (tb[CTA_PROTO_ICMP_ID-1]) {
+ tuple->l4src.icmp.id =
+ *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
+ set_bit(ATTR_ICMP_ID, set);
+ }
+}
+
+static void __parse_tuple(const struct nfattr *attr,
+ struct __nfct_tuple *tuple,
+ int dir,
+ u_int32_t *set)
+{
+ struct nfattr *tb[CTA_TUPLE_MAX];
+
+ nfnl_parse_nested(tb, CTA_TUPLE_MAX, attr);
+
+ if (tb[CTA_TUPLE_IP-1])
+ __parse_ip(tb[CTA_TUPLE_IP-1], tuple, dir, set);
+ if (tb[CTA_TUPLE_PROTO-1])
+ __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)
+{
+ struct nfattr *tb[CTA_PROTOINFO_TCP_MAX];
+
+ nfnl_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr);
+
+ if (tb[CTA_PROTOINFO_TCP_STATE-1]) {
+ ct->protoinfo.tcp.state =
+ *(u_int8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]);
+ set_bit(ATTR_TCP_STATE, ct->set);
+ }
+}
+
+static void __parse_protoinfo(const struct nfattr *attr,
+ struct nf_conntrack *ct)
+{
+ struct nfattr *tb[CTA_PROTOINFO_MAX];
+
+ nfnl_parse_nested(tb, CTA_PROTOINFO_MAX, attr);
+
+ if (!tb[CTA_PROTOINFO_TCP-1])
+ return;
+
+ __parse_protoinfo_tcp(tb[CTA_PROTOINFO_TCP-1], ct);
+}
+
+static void __parse_counters(const struct nfattr *attr,
+ struct nf_conntrack *ct,
+ int dir)
+{
+ struct nfattr *tb[CTA_COUNTERS_MAX];
+
+ nfnl_parse_nested(tb, CTA_COUNTERS_MAX, attr);
+ if (tb[CTA_COUNTERS32_PACKETS-1]) {
+ ct->counters[dir].packets
+ = htonl(*(u_int32_t *)
+ NFA_DATA(tb[CTA_COUNTERS32_PACKETS-1]));
+ switch(dir) {
+ case __DIR_ORIG:
+ set_bit(ATTR_ORIG_COUNTER_PACKETS, ct->set);
+ break;
+ case __DIR_REPL:
+ set_bit(ATTR_REPL_COUNTER_PACKETS, ct->set);
+ break;
+ }
+ }
+ if (tb[CTA_COUNTERS32_BYTES-1]) {
+ ct->counters[dir].bytes
+ = htonl(*(u_int32_t *)
+ NFA_DATA(tb[CTA_COUNTERS32_BYTES-1]));
+ switch(dir) {
+ case __DIR_ORIG:
+ set_bit(ATTR_ORIG_COUNTER_BYTES, ct->set);
+ break;
+ case __DIR_REPL:
+ set_bit(ATTR_REPL_COUNTER_BYTES, ct->set);
+ break;
+ }
+ }
+}
+
+int __parse_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_CT_NEW) {
+ if (flags & (NLM_F_CREATE|NLM_F_EXCL))
+ ret = NFCT_T_NEW;
+ else
+ ret = NFCT_T_UPDATE;
+ } else if (type == IPCTNL_MSG_CT_DELETE)
+ ret = NFCT_T_DESTROY;
+
+ return ret;
+}
+
+void __parse_conntrack(const struct nlmsghdr *nlh,
+ const struct nfattr *cda[],
+ struct nf_conntrack *ct)
+{
+ struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
+
+ ct->tuple[__DIR_ORIG].l3protonum = nfhdr->nfgen_family;
+ set_bit(ATTR_ORIG_L3PROTO, ct->set);
+
+ ct->tuple[__DIR_REPL].l3protonum = nfhdr->nfgen_family;
+ set_bit(ATTR_REPL_L3PROTO, ct->set);
+
+ if (cda[CTA_TUPLE_ORIG-1])
+ __parse_tuple(cda[CTA_TUPLE_ORIG-1],
+ &ct->tuple[__DIR_ORIG], __DIR_ORIG, ct->set);
+
+ if (cda[CTA_TUPLE_REPLY-1])
+ __parse_tuple(cda[CTA_TUPLE_REPLY-1],
+ &ct->tuple[__DIR_REPL], __DIR_REPL, ct->set);
+
+ if (cda[CTA_STATUS-1]) {
+ ct->status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]));
+ if (ct->status & IPS_ASSURED)
+ set_bit(ATTR_STATUS, ct->set);
+ if (ct->status & IPS_SEEN_REPLY)
+ set_bit(ATTR_STATUS, ct->set);
+ }
+
+ if (cda[CTA_PROTOINFO-1])
+ __parse_protoinfo(cda[CTA_PROTOINFO-1], ct);
+
+ if (cda[CTA_TIMEOUT-1]) {
+ ct->timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
+ set_bit(ATTR_TIMEOUT, ct->set);
+ }
+
+ if (cda[CTA_MARK-1]) {
+ ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
+ set_bit(ATTR_MARK, ct->set);
+ }
+
+ if (cda[CTA_COUNTERS_ORIG-1])
+ __parse_counters(cda[CTA_COUNTERS_ORIG-1], ct, __DIR_ORIG);
+
+ if (cda[CTA_COUNTERS_REPLY-1])
+ __parse_counters(cda[CTA_COUNTERS_REPLY-1], ct, __DIR_REPL);
+
+ if (cda[CTA_USE-1]) {
+ ct->use = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_USE-1]));
+ set_bit(ATTR_USE, ct->set);
+ }
+
+ if (cda[CTA_ID-1]) {
+ ct->id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1]));
+ set_bit(ATTR_ID, ct->set);
+ }
+}
diff --git a/src/conntrack/setter.c b/src/conntrack/setter.c
new file mode 100644
index 0000000..7bc77b5
--- /dev/null
+++ b/src/conntrack/setter.c
@@ -0,0 +1,173 @@
+/*
+ * (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.h"
+
+static void set_attr_orig_ipv4_src(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_ORIG].src.v4 = *((u_int32_t *) value);
+}
+
+static void set_attr_orig_ipv4_dst(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_ORIG].dst.v4 = *((u_int32_t *) value);
+}
+
+static void set_attr_repl_ipv4_src(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_REPL].src.v4 = *((u_int32_t *) value);
+}
+
+static void set_attr_repl_ipv4_dst(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_REPL].dst.v4 = *((u_int32_t *) value);
+}
+
+static void set_attr_orig_ipv6_src(struct nf_conntrack *ct, const void *value)
+{
+ memcpy(&ct->tuple[__DIR_ORIG].src.v6, value, sizeof(u_int32_t)*4);
+}
+
+static void set_attr_orig_ipv6_dst(struct nf_conntrack *ct, const void *value)
+{
+ memcpy(&ct->tuple[__DIR_ORIG].dst.v6, value, sizeof(u_int32_t)*4);
+}
+
+static void set_attr_repl_ipv6_src(struct nf_conntrack *ct, const void *value)
+{
+ memcpy(&ct->tuple[__DIR_REPL].src.v6, value, sizeof(u_int32_t)*4);
+}
+
+static void set_attr_repl_ipv6_dst(struct nf_conntrack *ct, const void *value)
+{
+ memcpy(&ct->tuple[__DIR_REPL].dst.v6, value, sizeof(u_int32_t)*4);
+}
+
+static void set_attr_orig_port_src(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_ORIG].l4src.all = *((u_int16_t *) value);
+}
+
+static void set_attr_orig_port_dst(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_ORIG].l4dst.all = *((u_int16_t *) value);
+}
+
+static void set_attr_repl_port_src(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_REPL].l4src.all = *((u_int16_t *) value);
+}
+
+static void set_attr_repl_port_dst(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_REPL].l4dst.all = *((u_int16_t *) value);
+}
+
+static void set_attr_icmp_type(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_ORIG].l4dst.icmp.type = *((u_int8_t *) value);
+}
+
+static void set_attr_icmp_code(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_ORIG].l4dst.icmp.code = *((u_int8_t *) value);
+}
+
+static void set_attr_icmp_id(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_ORIG].l4src.icmp.id = *((u_int8_t *) value);
+}
+
+static void set_attr_orig_l3proto(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_ORIG].l3protonum = *((u_int8_t *) value);
+}
+
+static void set_attr_repl_l3proto(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_REPL].l3protonum = *((u_int8_t *) value);
+}
+
+static void set_attr_orig_l4proto(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_ORIG].protonum = *((u_int8_t *) value);
+}
+
+static void set_attr_repl_l4proto(struct nf_conntrack *ct, const void *value)
+{
+ ct->tuple[__DIR_REPL].protonum = *((u_int8_t *) value);
+}
+
+static void set_attr_tcp_state(struct nf_conntrack *ct, const void *value)
+{
+ ct->protoinfo.tcp.state = *((u_int8_t *) value);
+}
+
+static void set_attr_snat_ipv4(struct nf_conntrack *ct, const void *value)
+{
+ ct->snat.min_ip = ct->snat.max_ip = *((u_int32_t *) value);
+}
+
+static void set_attr_dnat_ipv4(struct nf_conntrack *ct, const void *value)
+{
+ ct->dnat.min_ip = ct->snat.max_ip = *((u_int32_t *) value);
+}
+
+static void set_attr_snat_port(struct nf_conntrack *ct, const void *value)
+{
+ ct->snat.l4min.all = ct->snat.l4max.all = *((u_int16_t *) value);
+}
+
+static void set_attr_dnat_port(struct nf_conntrack *ct, const void *value)
+{
+ ct->dnat.l4min.all = ct->dnat.l4max.all = *((u_int16_t *) value);
+}
+
+static void set_attr_timeout(struct nf_conntrack *ct, const void *value)
+{
+ ct->timeout = *((u_int32_t *) value);
+}
+
+static void set_attr_mark(struct nf_conntrack *ct, const void *value)
+{
+ ct->mark = *((u_int32_t *) value);
+}
+
+static void set_attr_status(struct nf_conntrack *ct, const void *value)
+{
+ ct->status |= *((u_int32_t *) value);
+}
+
+set_attr set_attr_array[] = {
+ [ATTR_ORIG_IPV4_SRC] = set_attr_orig_ipv4_src,
+ [ATTR_ORIG_IPV4_DST] = set_attr_orig_ipv4_dst,
+ [ATTR_REPL_IPV4_SRC] = set_attr_repl_ipv4_src,
+ [ATTR_REPL_IPV4_DST] = set_attr_repl_ipv4_dst,
+ [ATTR_ORIG_IPV6_SRC] = set_attr_orig_ipv6_src,
+ [ATTR_ORIG_IPV6_DST] = set_attr_orig_ipv6_dst,
+ [ATTR_REPL_IPV6_SRC] = set_attr_repl_ipv6_src,
+ [ATTR_REPL_IPV6_DST] = set_attr_repl_ipv6_dst,
+ [ATTR_ORIG_PORT_SRC] = set_attr_orig_port_src,
+ [ATTR_ORIG_PORT_DST] = set_attr_orig_port_dst,
+ [ATTR_REPL_PORT_SRC] = set_attr_repl_port_src,
+ [ATTR_REPL_PORT_DST] = set_attr_repl_port_dst,
+ [ATTR_ICMP_TYPE] = set_attr_icmp_type,
+ [ATTR_ICMP_CODE] = set_attr_icmp_code,
+ [ATTR_ICMP_ID] = set_attr_icmp_id,
+ [ATTR_ORIG_L3PROTO] = set_attr_orig_l3proto,
+ [ATTR_REPL_L3PROTO] = set_attr_repl_l3proto,
+ [ATTR_ORIG_L4PROTO] = set_attr_orig_l4proto,
+ [ATTR_REPL_L4PROTO] = set_attr_repl_l4proto,
+ [ATTR_TCP_STATE] = set_attr_tcp_state,
+ [ATTR_SNAT_IPV4] = set_attr_snat_ipv4,
+ [ATTR_DNAT_IPV4] = set_attr_dnat_ipv4,
+ [ATTR_SNAT_PORT] = set_attr_snat_port,
+ [ATTR_DNAT_PORT] = set_attr_dnat_port,
+ [ATTR_TIMEOUT] = set_attr_timeout,
+ [ATTR_MARK] = set_attr_mark,
+ [ATTR_STATUS] = set_attr_status,
+};
diff --git a/src/conntrack/snprintf.c b/src/conntrack/snprintf.c
new file mode 100644
index 0000000..0c500b7
--- /dev/null
+++ b/src/conntrack/snprintf.c
@@ -0,0 +1,36 @@
+/*
+ * (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.h"
+
+int __snprintf_conntrack(char *buf,
+ unsigned int len,
+ const struct nf_conntrack *ct,
+ unsigned int type,
+ unsigned int msg_output,
+ unsigned int flags)
+{
+ int size;
+
+ switch(msg_output) {
+ case NFCT_O_DEFAULT:
+ size = __snprintf_conntrack_default(buf, len, ct, type, flags);
+ break;
+ case NFCT_O_XML:
+ size = __snprintf_conntrack_xml(buf, len, ct, 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/conntrack/snprintf_default.c b/src/conntrack/snprintf_default.c
new file mode 100644
index 0000000..e826511
--- /dev/null
+++ b/src/conntrack/snprintf_default.c
@@ -0,0 +1,344 @@
+/*
+ * (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.h"
+
+static char *proto2str[IPPROTO_MAX] = {
+ [IPPROTO_TCP] = "tcp",
+ [IPPROTO_UDP] = "udp",
+ [IPPROTO_ICMP] = "icmp",
+ [IPPROTO_SCTP] = "sctp"
+};
+
+static char *l3proto2str[AF_MAX] = {
+ [AF_INET] = "ipv4",
+ [AF_INET6] = "ipv6"
+};
+
+static const char *states[] = {
+ "NONE",
+ "SYN_SENT",
+ "SYN_RECV",
+ "ESTABLISHED",
+ "FIN_WAIT",
+ "CLOSE_WAIT",
+ "LAST_ACK",
+ "TIME_WAIT",
+ "CLOSE",
+ "LISTEN"
+};
+
+static int __snprintf_l3protocol(char *buf,
+ unsigned int len,
+ const struct nf_conntrack *ct)
+{
+ return (snprintf(buf, len, "%-8s %u ",
+ l3proto2str[ct->tuple[__DIR_ORIG].l3protonum] == NULL ?
+ "unknown" : l3proto2str[ct->tuple[__DIR_ORIG].l3protonum],
+ ct->tuple[__DIR_ORIG].l3protonum));
+}
+
+static 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 ?
+ "unknown" : proto2str[ct->tuple[__DIR_ORIG].protonum],
+ ct->tuple[__DIR_ORIG].protonum));
+}
+
+int __snprintf_timeout(char *buf,
+ unsigned int len,
+ const struct nf_conntrack *ct)
+{
+ return snprintf(buf, len, "%u ", ct->timeout);
+}
+
+int __snprintf_protoinfo(char *buf,
+ unsigned int len,
+ const struct nf_conntrack *ct)
+{
+ return snprintf(buf, len, "%s ", states[ct->protoinfo.tcp.state]);
+}
+
+int __snprintf_address_ipv4(char *buf,
+ unsigned int len,
+ const struct __nfct_tuple *tuple)
+{
+ int ret, size;
+ struct in_addr src = { .s_addr = tuple->src.v4 };
+ struct in_addr dst = { .s_addr = tuple->dst.v4 };
+
+ ret = snprintf(buf, len, "src=%s ", inet_ntoa(src));
+ if (ret == -1)
+ return -1;
+ size = ret;
+
+ ret = snprintf(buf+size, len-size, "dst=%s ", inet_ntoa(dst));
+ if (ret == -1)
+ return -1;
+ size += ret;
+
+ return size;
+}
+
+int __snprintf_address_ipv6(char *buf,
+ unsigned int len,
+ const struct __nfct_tuple *tuple)
+{
+ int size;
+ struct in6_addr src;
+ struct in6_addr dst;
+ char tmp[INET6_ADDRSTRLEN];
+
+ memcpy(&src.in6_u, &tuple->src.v6, sizeof(struct in6_addr));
+ memcpy(&dst.in6_u, &tuple->dst.v6, sizeof(struct in6_addr));
+
+ if (!inet_ntop(AF_INET6, &src, tmp, sizeof(tmp)))
+ return -1;
+
+ size = snprintf(buf, len, "src=%s ", tmp);
+
+ if (!inet_ntop(AF_INET6, &dst, tmp, sizeof(tmp)))
+ return -1;
+
+ size += snprintf(buf+size, len-size, "dst=%s ", tmp);
+
+ return size;
+}
+
+int __snprintf_address(char *buf,
+ unsigned int len,
+ const struct __nfct_tuple *tuple)
+{
+ int size = 0;
+
+ switch (tuple->l3protonum) {
+ case AF_INET:
+ size = __snprintf_address_ipv4(buf, len, tuple);
+ break;
+ case AF_INET6:
+ size = __snprintf_address_ipv4(buf, len, tuple);
+ break;
+ }
+
+ return size;
+}
+
+int __snprintf_proto(char *buf,
+ unsigned int len,
+ const struct __nfct_tuple *tuple)
+{
+ int size = 0;
+
+ switch(tuple->protonum) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ case IPPROTO_SCTP:
+ return snprintf(buf, len, "sport=%u dport=%u ",
+ htons(tuple->l4src.tcp.port),
+ htons(tuple->l4dst.tcp.port));
+ break;
+ case IPPROTO_ICMP:
+ /* The ID only makes sense some ICMP messages but we want to
+ * display the same output that /proc/net/ip_conntrack does */
+ return (snprintf(buf, len, "type=%d code=%d id=%d ",
+ tuple->l4dst.icmp.type,
+ tuple->l4dst.icmp.code,
+ ntohs(tuple->l4src.icmp.id)));
+ break;
+ }
+
+ return size;
+}
+
+int __snprintf_status_assured(char *buf,
+ unsigned int len,
+ const struct nf_conntrack *ct)
+{
+ int size = 0;
+
+ if (ct->status & IPS_ASSURED)
+ size = snprintf(buf, len, "[ASSURED] ");
+
+ return size;
+}
+
+int __snprintf_status_not_seen_reply(char *buf,
+ unsigned int len,
+ const struct nf_conntrack *ct)
+{
+ int size = 0;
+
+ if (!(ct->status & IPS_SEEN_REPLY))
+ size = snprintf(buf, len, "[UNREPLIED] ");
+
+ return size;
+}
+
+int __snprintf_counters(char *buf,
+ unsigned int len,
+ const struct nf_conntrack *ct,
+ int dir)
+{
+ return (snprintf(buf, len, "packets=%llu bytes=%llu ",
+ (unsigned long long) ct->counters[dir].packets,
+ (unsigned long long) ct->counters[dir].bytes));
+}
+
+int __snprintf_mark(char *buf, unsigned int len, const struct nf_conntrack *ct)
+{
+ return (snprintf(buf, len, "mark=%u ", ct->mark));
+}
+
+int __snprintf_use(char *buf, unsigned int len, const struct nf_conntrack *ct)
+{
+ return (snprintf(buf, len, "use=%u ", ct->use));
+}
+
+int __snprintf_id(char *buf, unsigned int len, u_int32_t id)
+{
+ return (snprintf(buf, len, "id=%u ", id));
+}
+
+int __snprintf_conntrack_default(char *buf,
+ unsigned int remain,
+ const struct nf_conntrack *ct,
+ 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;
+ case NFCT_T_UPDATE:
+ ret = snprintf(buf, remain, "%9s ", "[UPDATE]");
+ break;
+ case NFCT_T_DESTROY:
+ ret = snprintf(buf, remain, "%9s ", "[DESTROY]");
+ break;
+ default:
+ break;
+ }
+
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+
+ if (flags & NFCT_OF_SHOW_LAYER3) {
+ ret = __snprintf_l3protocol(buf+size, remain, ct);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+ }
+
+ ret = __snprintf_protocol(buf+size, remain, ct);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+
+ if (test_bit(ATTR_TIMEOUT, ct->set)) {
+ ret = __snprintf_timeout(buf+size, remain, ct);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+ }
+
+ if (test_bit(ATTR_TCP_STATE, ct->set)) {
+ ret = __snprintf_protoinfo(buf+size, remain, ct);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+ }
+
+ ret = __snprintf_address(buf+size, remain, &ct->tuple[__DIR_ORIG]);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+
+ ret = __snprintf_proto(buf+size, remain, &ct->tuple[__DIR_ORIG]);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+
+ if (test_bit(ATTR_ORIG_COUNTER_PACKETS, ct->set) &&
+ test_bit(ATTR_ORIG_COUNTER_BYTES, ct->set)) {
+ ret = __snprintf_counters(buf+size, remain, ct, __DIR_ORIG);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+ }
+
+ if (test_bit(ATTR_STATUS, ct->set)) {
+ ret = __snprintf_status_not_seen_reply(buf+size, remain, ct);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+ }
+
+ ret = __snprintf_address(buf+size, remain, &ct->tuple[__DIR_REPL]);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+
+ ret = __snprintf_proto(buf+size, remain, &ct->tuple[__DIR_REPL]);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+
+ if (test_bit(ATTR_REPL_COUNTER_PACKETS, ct->set) &&
+ test_bit(ATTR_REPL_COUNTER_BYTES, ct->set)) {
+ ret = __snprintf_counters(buf+size, remain, ct, __DIR_REPL);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+ }
+
+ if (test_bit(ATTR_STATUS, ct->set)) {
+ ret = __snprintf_status_assured(buf+size, remain, ct);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+ }
+
+ if (test_bit(ATTR_MARK, ct->set)) {
+ ret = __snprintf_mark(buf+size, remain, ct);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+ }
+
+ if (test_bit(ATTR_USE, ct->set)) {
+ ret = __snprintf_use(buf+size, remain, ct);
+ if (ret == -1)
+ return -1;
+ size += ret;
+ remain -= ret;
+ }
+
+ /* Delete the last blank space */
+ size--;
+
+ return size;
+}
diff --git a/src/conntrack/snprintf_xml.c b/src/conntrack/snprintf_xml.c
new file mode 100644
index 0000000..1cc62d8
--- /dev/null
+++ b/src/conntrack/snprintf_xml.c
@@ -0,0 +1,413 @@
+/*
+ * (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.h"
+
+/*
+ * XML output sample:
+ *
+ * <flow>
+ * <meta direction="original">
+ * <layer3 protonum="2" protoname="IPv4">
+ * <src>192.168.0.1</src>
+ * <dst>192.168.0.2</dst>
+ * </layer3>
+ * <layer4 protonum="16" protoname"udp">
+ * <sport>80</sport>
+ * <dport>56665</dport>
+ * </layer4>
+ * <counters>
+ * <bytes>10</bytes>
+ * <packets>1</packets>
+ * </counters>
+ * </meta>
+ * <meta direction="reply">
+ * <layer3 protonum="2" protoname="IPv4">
+ * <src>192.168.0.2</src>
+ * <dst>192.168.0.1</dst>
+ * </layer3>
+ * <layer4 protonum="16" protoname="udp">
+ * <sport>80</sport>
+ * <dport>56665</dport>
+ * </layer4>
+ * <counters>
+ * <bytes>5029</bytes>
+ * <packets>12</packets>
+ * </counters>
+ * </meta>
+ * <meta direction="independent">
+ * <layer4>
+ * <state>ESTABLISHED</state>
+ * </layer4>
+ * <timeout>100</timeout>
+ * <mark>1</mark>
+ * <use>1</use>
+ * <assured/>
+ * </meta>
+ * </flow>
+ */
+
+static char *proto2str[IPPROTO_MAX] = {
+ [IPPROTO_TCP] = "tcp",
+ [IPPROTO_UDP] = "udp",
+ [IPPROTO_ICMP] = "icmp",
+ [IPPROTO_SCTP] = "sctp"
+};
+static char *l3proto2str[AF_MAX] = {
+ [AF_INET] = "ipv4",
+ [AF_INET6] = "ipv6"
+};
+
+enum {
+ __ADDR_SRC = 0,
+ __ADDR_DST,
+};
+
+static void buffer_size(int ret, unsigned int *size, unsigned int *len)
+{
+ *size += ret;
+ *len -= ret;
+}
+
+static char *__proto2str(u_int8_t protonum)
+{
+ return proto2str[protonum] ? proto2str[protonum] : "unknown";
+}
+
+static char *__l3proto2str(u_int8_t protonum)
+{
+ return l3proto2str[protonum] ? l3proto2str[protonum] : "unknown";
+}
+
+static int __snprintf_ipv4_xml(char *buf,
+ unsigned int len,
+ const struct __nfct_tuple *tuple,
+ unsigned int type)
+{
+ struct in_addr addr = {
+ .s_addr = (type == __ADDR_SRC) ? tuple->src.v4 : tuple->dst.v4,
+ };
+
+ return snprintf(buf, len, "%s", inet_ntoa(addr));
+}
+
+static int __snprintf_ipv6_xml(char *buf,
+ unsigned int len,
+ const struct __nfct_tuple *tuple,
+ unsigned int type)
+{
+ struct in6_addr addr;
+ static char tmp[INET6_ADDRSTRLEN];
+ const void *p = (type == __ADDR_SRC) ? &tuple->src.v6 : &tuple->dst.v6;
+
+ memcpy(&addr.in6_u, p, sizeof(struct in6_addr));
+
+ if (!inet_ntop(AF_INET6, &addr, tmp, sizeof(tmp)))
+ return -1;
+
+ return snprintf(buf, len, "%s", tmp);
+}
+
+static int __snprintf_addr_xml(char *buf,
+ unsigned int len,
+ const struct __nfct_tuple *tuple,
+ unsigned int type)
+{
+ int ret;
+ unsigned int size = 0;
+
+ switch(type) {
+ case __ADDR_SRC:
+ ret = snprintf(buf, len, "<src>");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ break;
+ case __ADDR_DST:
+ ret = snprintf(buf+size, len, "<dst>");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ break;
+ }
+
+ switch (tuple->l3protonum) {
+ case AF_INET:
+ ret = __snprintf_ipv4_xml(buf+size, len, tuple, type);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ break;
+ case AF_INET6:
+ ret = __snprintf_ipv6_xml(buf+size, len, tuple, type);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ break;
+ }
+
+ switch(type) {
+ case __ADDR_SRC:
+ ret = snprintf(buf+size, len, "</src>");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ break;
+ case __ADDR_DST:
+ ret = snprintf(buf+size, len, "</dst>");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ break;
+ }
+
+ return size;
+}
+
+static int __snprintf_proto_xml(char *buf,
+ unsigned int len,
+ const struct __nfct_tuple *tuple,
+ unsigned int type)
+{
+ int ret = 0;
+ unsigned int size = 0;
+
+ switch(tuple->protonum) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ case IPPROTO_SCTP:
+ if (type == __ADDR_SRC) {
+ ret = snprintf(buf, len, "<sport>%u</sport>",
+ tuple->l4src.tcp.port);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ } else {
+ ret = snprintf(buf, len, "<dport>%u</dport>",
+ tuple->l4dst.tcp.port);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ }
+ break;
+ }
+
+ return ret;
+}
+
+static int __snprintf_counters_xml(char *buf,
+ unsigned int len,
+ const struct nf_conntrack *ct,
+ unsigned int type)
+{
+ int ret;
+ unsigned int size = 0;
+
+ ret = snprintf(buf, len, "<packets>%llu</packets>",
+ ct->counters[type].packets);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ ret = snprintf(buf+size, len, "<bytes>%llu</bytes>",
+ ct->counters[type].bytes);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ return size;
+}
+
+static int __snprintf_tuple_xml(char *buf,
+ unsigned int len,
+ const struct nf_conntrack *ct,
+ unsigned int dir)
+{
+ int ret;
+ unsigned int size = 0;
+ const struct __nfct_tuple *tuple = &ct->tuple[dir];
+
+ ret = snprintf(buf, len, "<meta direction=\"%s\">",
+ dir == __DIR_ORIG ? "original" : "reply");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ ret = snprintf(buf+size, len,
+ "<layer3 protonum=\"%d\" protoname=\"%s\">",
+ tuple->l3protonum, __l3proto2str(tuple->l3protonum));
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ ret = __snprintf_addr_xml(buf+size, len, tuple, __DIR_ORIG);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ ret = __snprintf_addr_xml(buf+size, len, tuple, __DIR_REPL);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ ret = snprintf(buf+size, len, "</layer3>");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ ret = snprintf(buf+size, len,
+ "<layer4 protonum=\"%d\" protoname=\"%s\">",
+ tuple->protonum, __proto2str(tuple->protonum));
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ ret = __snprintf_proto_xml(buf+size, len, tuple, __DIR_ORIG);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ ret = __snprintf_proto_xml(buf+size, len, tuple, __DIR_REPL);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ ret = snprintf(buf+size, len, "</layer4>");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ if (test_bit(ATTR_ORIG_COUNTER_PACKETS, ct->set) &&
+ test_bit(ATTR_ORIG_COUNTER_BYTES, ct->set)) {
+ ret = snprintf(buf+size, len, "<counters>");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ ret = __snprintf_counters_xml(buf+size, len, ct, dir);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ ret = snprintf(buf+size, len, "</counters>");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ }
+
+ ret = snprintf(buf+size, len, "</meta>");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ return size;
+}
+
+int __snprintf_conntrack_xml(char *buf,
+ unsigned int len,
+ const struct nf_conntrack *ct,
+ const unsigned int msg_type,
+ const unsigned int flags)
+{
+ int ret = 0;
+ unsigned int size = 0;
+
+ switch(msg_type) {
+ case NFCT_T_NEW:
+ ret = snprintf(buf, len, "<flow type=\"new\">");
+ break;
+ case NFCT_T_UPDATE:
+ ret = snprintf(buf, len, "<flow type=\"update\"");
+ break;
+ case NFCT_T_DESTROY:
+ ret = snprintf(buf, len, "<flow type=\"destroy\"");
+ break;
+ default:
+ ret = snprintf(buf, len, "<flow>");
+ break;
+ }
+
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ ret = __snprintf_tuple_xml(buf+size, len, ct, __DIR_ORIG);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ ret = __snprintf_tuple_xml(buf+size, len, ct, __DIR_REPL);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ if (test_bit(ATTR_TIMEOUT, ct->set) ||
+ test_bit(ATTR_MARK, ct->set) ||
+ test_bit(ATTR_USE, ct->set) ||
+ test_bit(ATTR_STATUS, ct->set)) {
+ ret = snprintf(buf+size, len,
+ "<meta direction=\"independent\">");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ }
+
+ if (test_bit(ATTR_TIMEOUT, ct->set)) {
+ ret = snprintf(buf+size, len,
+ "<timeout>%u</timeout>", ct->timeout);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ }
+
+ if (test_bit(ATTR_MARK, ct->set)) {
+ ret = snprintf(buf+size, len, "<mark>%u</mark>", ct->mark);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ }
+
+ if (test_bit(ATTR_USE, ct->set)) {
+ ret = snprintf(buf+size, len, "<use>%u</use>", ct->use);
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ }
+
+ if (test_bit(ATTR_STATUS, ct->set)
+ && ct->status & IPS_ASSURED) {
+ ret = snprintf(buf+size, len, "<assured/>");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ }
+
+ if (test_bit(ATTR_STATUS, ct->set)
+ && !(ct->status & IPS_SEEN_REPLY)) {
+ ret = snprintf(buf+size, len, "<unreplied/>");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ }
+
+ if (test_bit(ATTR_TIMEOUT, ct->set) ||
+ test_bit(ATTR_MARK, ct->set) ||
+ test_bit(ATTR_USE, ct->set) ||
+ test_bit(ATTR_STATUS, ct->set)) {
+ ret = snprintf(buf+size, len, "</meta>");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+ }
+
+ ret = snprintf(buf+size, len, "</flow>");
+ if (ret == -1)
+ return -1;
+ buffer_size(ret, &size, &len);
+
+ return size;
+}
diff --git a/src/libnetfilter_conntrack.c b/src/libnetfilter_conntrack.c
index 3b6f2cf..dc8d619 100644
--- a/src/libnetfilter_conntrack.c
+++ b/src/libnetfilter_conntrack.c
@@ -22,20 +22,9 @@
#include <libnetfilter_conntrack/libnetfilter_conntrack_l3extensions.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack_extensions.h>
-#define NFCT_BUFSIZE 4096
+#include "internal.h"
-typedef int (*nfct_handler)(struct nfct_handle *cth, struct nlmsghdr *nlh,
- void *arg);
-
-/* Harald says: "better for encapsulation" ;) */
-struct nfct_handle {
- struct nfnl_handle *nfnlh;
- struct nfnl_subsys_handle *nfnlssh_ct;
- struct nfnl_subsys_handle *nfnlssh_exp;
- nfct_callback callback; /* user callback */
- void *callback_data; /* user data for callback */
- nfct_handler handler; /* netlink handler */
-};
+#define NFCT_BUFSIZE 4096
static char *lib_dir = LIBNETFILTER_CONNTRACK_DIR;
static LIST_HEAD(proto_list);
@@ -151,6 +140,14 @@ int nfct_close(struct nfct_handle *cth)
cth->nfnlssh_ct = NULL;
}
+ /* required by the new API */
+ cth->cb = NULL;
+ free(cth->nfnl_cb.data);
+
+ cth->nfnl_cb.call = NULL;
+ cth->nfnl_cb.data = NULL;
+ cth->nfnl_cb.attr_count = 0;
+
err = nfnl_close(cth->nfnlh);
free(cth);