Index: libnetfilter_conntrack/include/libnetfilter_conntrack/libnetfilter_conntrack.h =================================================================== --- libnetfilter_conntrack.orig/include/libnetfilter_conntrack/libnetfilter_conntrack.h 2006-12-12 22:36:26.000000000 +0100 +++ libnetfilter_conntrack/include/libnetfilter_conntrack/libnetfilter_conntrack.h 2006-12-18 02:14:51.000000000 +0100 @@ -332,6 +332,220 @@ extern int nfct_sprintf_expect_id(char * extern void nfct_build_tuple(struct nfnlhdr *req, int size, struct nfct_tuple *t, int type); +/* + * NEW libnetfilter_conntrack API + */ +/* high level API */ + +#include + +/* conntrack object */ +struct nf_conntrack; + +/* conntrack attributes */ +enum nf_conntrack_attr { + ATTR_ORIG_IPV4_SRC = 0, /* u32 bits */ + ATTR_ORIG_IPV4_DST, /* u32 bits */ + ATTR_REPL_IPV4_SRC, /* u32 bits */ + ATTR_REPL_IPV4_DST, /* u32 bits */ + ATTR_ORIG_IPV6_SRC = 4, /* u128 bits */ + ATTR_ORIG_IPV6_DST, /* u128 bits */ + ATTR_REPL_IPV6_SRC, /* u128 bits */ + ATTR_REPL_IPV6_DST, /* u128 bits */ + ATTR_ORIG_PORT_SRC = 8, /* u16 bits */ + ATTR_ORIG_PORT_DST, /* u16 bits */ + ATTR_REPL_PORT_SRC, /* u16 bits */ + ATTR_REPL_PORT_DST, /* u16 bits */ + ATTR_ICMP_TYPE = 12, /* u8 bits */ + ATTR_ICMP_CODE, /* u8 bits */ + ATTR_ICMP_ID, /* u8 bits */ + ATTR_ORIG_L3PROTO, /* u8 bits */ + ATTR_REPL_L3PROTO = 16, /* u8 bits */ + ATTR_ORIG_L4PROTO, /* u8 bits */ + ATTR_REPL_L4PROTO, /* u8 bits */ + ATTR_TCP_STATE, /* u8 bits */ + ATTR_SNAT_IPV4 = 20, /* u32 bits */ + ATTR_DNAT_IPV4, /* u32 bits */ + ATTR_SNAT_PORT, /* u16 bits */ + ATTR_DNAT_PORT, /* u16 bits */ + ATTR_TIMEOUT = 24, /* u32 bits */ + ATTR_MARK, /* u32 bits */ + ATTR_ORIG_COUNTER_PACKETS, /* u32 bits */ + ATTR_REPL_COUNTER_PACKETS, /* u32 bits */ + ATTR_ORIG_COUNTER_BYTES = 28, /* u32 bits */ + ATTR_REPL_COUNTER_BYTES, /* u32 bits */ + ATTR_USE, /* u32 bits */ + ATTR_ID, /* u32 bits */ + ATTR_STATUS = 32, /* u32 bits */ + ATTR_MAX +}; + +/* message type */ +enum nf_conntrack_msg_type { + NFCT_T_UNKNOWN = 0, + + NFCT_T_NEW_BIT = 0, + NFCT_T_NEW = (1 << NFCT_T_NEW_BIT), + + NFCT_T_UPDATE_BIT = 1, + NFCT_T_UPDATE = (1 << NFCT_T_UPDATE_BIT), + + NFCT_T_DESTROY_BIT = 2, + NFCT_T_DESTROY = (1 << NFCT_T_DESTROY_BIT), + + NFCT_T_ALL = NFCT_T_NEW | NFCT_T_UPDATE | NFCT_T_DESTROY, + + NFCT_T_ERROR_BIT = 31, + NFCT_T_ERROR = (1 << NFCT_T_ERROR_BIT), +}; + +/* constructor / destructor */ +extern struct nf_conntrack *nfct_new(void); +extern void nfct_destroy(struct nf_conntrack *ct); + +/* clone */ +struct nf_conntrack *nfct_clone(const struct nf_conntrack *ct); + +/* object size */ +extern size_t nfct_sizeof(const struct nf_conntrack *ct); + +/* set option */ +enum { + NFCT_SOPT_UNDO_SNAT, + NFCT_SOPT_UNDO_DNAT, + NFCT_SOPT_UNDO_SPAT, + NFCT_SOPT_UNDO_DPAT, + __NFCT_SOPT_MAX, +}; +#define NFCT_SOPT_MAX (__NFCT_SOPT_MAX - 1) + +/* get option */ +enum { + NFCT_GOPT_IS_SNAT, + NFCT_GOPT_IS_DNAT, + NFCT_GOPT_IS_SPAT, + NFCT_GOPT_IS_DPAT, + __NFCT_GOPT_MAX, +}; +#define NFCT_GOPT_MAX (__NFCT_GOPT_MAX - 1) + +extern int nfct_setobjopt(struct nf_conntrack *ct, unsigned int option); +extern int nfct_getobjopt(const struct nf_conntrack *ct, unsigned int option); + +/* register / unregister callback */ + +extern 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); + +extern void nfct_callback_unregister(struct nfct_handle *h); + +/* callback verdict */ +enum { + NFCT_CB_FAILURE = -1, /* failure */ + NFCT_CB_STOP = 0, /* stop the query */ + NFCT_CB_CONTINUE = 1, /* keep iterating through data */ + NFCT_CB_STOLEN = 2, /* like continue, but ct is not freed */ +}; + +/* setter */ +extern void nfct_set_attr(struct nf_conntrack *ct, + const enum nf_conntrack_attr type, + void *value); + +extern void nfct_set_attr_u8(struct nf_conntrack *ct, + const enum nf_conntrack_attr type, + u_int8_t value); + +extern void nfct_set_attr_u16(struct nf_conntrack *ct, + const enum nf_conntrack_attr type, + u_int16_t value); + +extern void nfct_set_attr_u32(struct nf_conntrack *ct, + const enum nf_conntrack_attr type, + u_int32_t value); + +/* getter */ +extern const void *nfct_get_attr(const struct nf_conntrack *ct, + const enum nf_conntrack_attr type); + +extern u_int8_t nfct_get_attr_u8(const struct nf_conntrack *ct, + const enum nf_conntrack_attr type); + +extern u_int16_t nfct_get_attr_u16(const struct nf_conntrack *ct, + const enum nf_conntrack_attr type); + +extern u_int32_t nfct_get_attr_u32(const struct nf_conntrack *ct, + const enum nf_conntrack_attr type); + +/* checker */ +extern int nfct_attr_is_set(const struct nf_conntrack *ct, + const enum nf_conntrack_attr type); + +/* unsetter */ +extern int nfct_attr_unset(struct nf_conntrack *ct, + const enum nf_conntrack_attr type); + +/* print */ + +/* output type */ +enum { + NFCT_O_DEFAULT, + NFCT_O_XML, + NFCT_O_MAX +}; + +/* output flags */ +enum { + NFCT_OF_SHOW_LAYER3_BIT = 0, + NFCT_OF_SHOW_LAYER3 = (1 << NFCT_OF_SHOW_LAYER3_BIT), +}; + +extern int nfct_snprintf(char *buf, + unsigned int size, + const struct nf_conntrack *ct, + const unsigned int msg_type, + const unsigned int out_type, + const unsigned int out_flags); + +/* query */ +enum nf_conntrack_query { + NFCT_Q_CREATE, + NFCT_Q_UPDATE, + NFCT_Q_DESTROY, + NFCT_Q_GET, + NFCT_Q_FLUSH, + NFCT_Q_DUMP, + NFCT_Q_DUMP_RESET, +}; + +extern int nfct_query(struct nfct_handle *h, + const enum nf_conntrack_query query, + const void *data); + +extern int nfct_catch(struct nfct_handle *h); + +/* low level API: netlink functions */ + +extern 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); + +extern int nfct_parse_conntrack(enum nf_conntrack_msg_type msg, + const struct nlmsghdr *nlh, + struct nf_conntrack *ct); + +extern int nfct_build_query(struct nfnl_subsys_handle *ssh, + const enum nf_conntrack_query query, + const void *data, + void *req, + unsigned int size); #endif /* _LIBNETFILTER_CONNTRACK_H_ */ Index: libnetfilter_conntrack/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h =================================================================== --- libnetfilter_conntrack.orig/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h 2006-12-12 22:36:26.000000000 +0100 +++ libnetfilter_conntrack/include/libnetfilter_conntrack/linux_nfnetlink_conntrack.h 2006-12-17 02:36:24.000000000 +0100 @@ -27,13 +27,15 @@ enum ctattr_type { CTA_STATUS, CTA_PROTOINFO, CTA_HELP, - CTA_NAT, + CTA_NAT_SRC, +#define CTA_NAT CTA_NAT_SRC /* backwards compatibility */ CTA_TIMEOUT, CTA_MARK, CTA_COUNTERS_ORIG, CTA_COUNTERS_REPLY, CTA_USE, CTA_ID, + CTA_NAT_DST, __CTA_MAX }; #define CTA_MAX (__CTA_MAX - 1) Index: libnetfilter_conntrack/utils/Makefile.am =================================================================== --- libnetfilter_conntrack.orig/utils/Makefile.am 2006-12-04 16:15:53.000000000 +0100 +++ libnetfilter_conntrack/utils/Makefile.am 2006-12-12 22:36:29.000000000 +0100 @@ -1,6 +1,10 @@ include $(top_srcdir)/Make_global.am -bin_PROGRAMS = ctnl_test +bin_PROGRAMS = ctnl_test new_api_test + +new_api_test_SOURCES = new_api_test.c +new_api_test_LDADD = ../src/libnetfilter_conntrack.la +new_api_test_LDFLAGS = -dynamic -ldl ctnl_test_SOURCES = ctnl_test.c ctnl_test_LDADD = ../src/libnetfilter_conntrack.la Index: libnetfilter_conntrack/utils/new_api_test.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libnetfilter_conntrack/utils/new_api_test.c 2006-12-17 16:52:28.000000000 +0100 @@ -0,0 +1,124 @@ +#include +#include + +#include +#include + +static int cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + char buf[1024]; + + nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, NFCT_OF_SHOW_LAYER3); + printf("%s\n", buf); + + return NFCT_CB_CONTINUE; +} + +static int event_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + static int n = 0; + char buf[1024]; + + nfct_snprintf(buf, 1024, ct, type, NFCT_O_XML, 0); + printf("%s\n", buf); + + if (++n == 10) + return NFCT_CB_STOP; + + return NFCT_CB_CONTINUE; +} + +int main() +{ + int ret; + u_int8_t family = AF_INET; + struct nfct_handle *h; + struct nf_conntrack *ct; + char buf[1024]; + + printf("Test for NEW libnetfilter_conntrack API\n"); + printf("=======================================\n"); + + ct = nfct_new(); + if (!ct) { + perror("nfct_new"); + return 0; + } + + nfct_set_attr_u8(ct, ATTR_ORIG_L3PROTO, AF_INET); + nfct_set_attr_u32(ct, ATTR_ORIG_IPV4_SRC, inet_addr("1.1.1.1")); + nfct_set_attr_u32(ct, ATTR_ORIG_IPV4_DST, inet_addr("2.2.2.2")); + + nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, IPPROTO_TCP); + nfct_set_attr_u16(ct, ATTR_ORIG_PORT_SRC, ntohs(20)); + nfct_set_attr_u16(ct, ATTR_ORIG_PORT_DST, ntohs(10)); + + nfct_set_attr_u8(ct, ATTR_REPL_L3PROTO, AF_INET); + nfct_set_attr_u32(ct, ATTR_REPL_IPV4_SRC, inet_addr("2.2.2.2")); + nfct_set_attr_u32(ct, ATTR_REPL_IPV4_DST, inet_addr("1.1.1.1")); + + nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, IPPROTO_TCP); + nfct_set_attr_u16(ct, ATTR_REPL_PORT_SRC, ntohs(10)); + nfct_set_attr_u16(ct, ATTR_REPL_PORT_DST, ntohs(20)); + + nfct_set_attr_u8(ct, ATTR_TCP_STATE, NFCT_TCP_ST_LISTEN); + nfct_set_attr_u32(ct, ATTR_TIMEOUT, 100); + + h = nfct_open(CONNTRACK, 0); + if (!h) { + perror("nfct_open"); + return -1; + } + + ret = nfct_query(h, NFCT_Q_CREATE, ct); + + printf("TEST 1: create conntrack (%d)(%s)\n", ret, strerror(errno)); + + ret = nfct_query(h, NFCT_Q_UPDATE, ct); + + printf("TEST 2: update conntrack (%d)(%s)\n", ret, strerror(errno)); + + nfct_callback_register(h, NFCT_T_ALL, cb, NULL); + ret = nfct_query(h, NFCT_Q_GET, ct); + + printf("TEST 3: get conntrack (%d)(%s)\n", ret, strerror(errno)); + + ret = nfct_query(h, NFCT_Q_DESTROY, ct); + + printf("TEST 4: destroy conntrack (%d)(%s)\n", ret, strerror(errno)); + + nfct_set_attr_u32(ct, ATTR_SNAT_IPV4, inet_addr("8.8.8.8")); + ret = nfct_query(h, NFCT_Q_CREATE, ct); + + printf("TEST 5: create NAT conntrack (%d)(%s)\n", ret, strerror(errno)); + + ret = nfct_query(h, NFCT_Q_GET, ct); + + printf("TEST 6: get NAT conntrack (%d)(%s)\n", ret, strerror(errno)); + + ret = nfct_query(h, NFCT_Q_DESTROY, ct); + + printf("TEST 7: destroy NAT conntrack (%d)(%s)\n",ret,strerror(errno)); + + nfct_close(h); + + h = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); + if (!h) { + perror("nfct_open"); + return -1; + } + + nfct_callback_register(h, NFCT_T_ALL, event_cb, NULL); + + printf("TEST 8: waiting for 10 events...\n"); + + ret = nfct_catch(h); + + printf("TEST 8: OK (%d)(%s)\n", ret, strerror(errno)); + + nfct_close(h); +} Index: libnetfilter_conntrack/src/conntrack/api.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libnetfilter_conntrack/src/conntrack/api.c 2006-12-18 02:14:39.000000000 +0100 @@ -0,0 +1,596 @@ +/* + * (C) 2006 by Pablo Neira Ayuso + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + */ + +#include +#include /* for memset */ +#include +#include + +#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); +} Index: libnetfilter_conntrack/src/conntrack/build.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libnetfilter_conntrack/src/conntrack/build.c 2006-12-18 01:31:15.000000000 +0100 @@ -0,0 +1,284 @@ +/* + * (C) 2006 by Pablo Neira Ayuso + * + * 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; +} Index: libnetfilter_conntrack/src/conntrack/getter.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libnetfilter_conntrack/src/conntrack/getter.c 2006-12-17 03:25:43.000000000 +0100 @@ -0,0 +1,197 @@ +/* + * (C) 2006 by Pablo Neira Ayuso + * + * 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, +}; Index: libnetfilter_conntrack/src/conntrack/parse.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libnetfilter_conntrack/src/conntrack/parse.c 2006-12-17 02:27:43.000000000 +0100 @@ -0,0 +1,295 @@ +/* + * (C) 2006 by Pablo Neira Ayuso + * + * 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); + } +} Index: libnetfilter_conntrack/src/conntrack/setter.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libnetfilter_conntrack/src/conntrack/setter.c 2006-12-17 03:35:35.000000000 +0100 @@ -0,0 +1,173 @@ +/* + * (C) 2006 by Pablo Neira Ayuso + * + * 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, +}; Index: libnetfilter_conntrack/src/conntrack/Makefile.am =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libnetfilter_conntrack/src/conntrack/Makefile.am 2006-12-16 17:43:41.000000000 +0100 @@ -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 Index: libnetfilter_conntrack/src/libnetfilter_conntrack.c =================================================================== --- libnetfilter_conntrack.orig/src/libnetfilter_conntrack.c 2006-12-12 22:36:26.000000000 +0100 +++ libnetfilter_conntrack/src/libnetfilter_conntrack.c 2006-12-18 00:35:22.000000000 +0100 @@ -22,20 +22,9 @@ #include #include -#define NFCT_BUFSIZE 4096 - -typedef int (*nfct_handler)(struct nfct_handle *cth, struct nlmsghdr *nlh, - void *arg); +#include "internal.h" -/* 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); @@ -265,9 +262,7 @@ static void nfct_build_protonat(struct n static void nfct_build_nat(struct nfnlhdr *req, int size, struct nfct_conntrack *ct) { - struct nfattr *nest; - - nest = nfnl_nest(&req->nlh, size, CTA_NAT); + struct nfattr *nest = nfnl_nest(&req->nlh, size, CTA_NAT); nfnl_addattr_l(&req->nlh, size, CTA_NAT_MINIP, &ct->nat.min_ip, sizeof(u_int32_t)); Index: libnetfilter_conntrack/src/conntrack/callback.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libnetfilter_conntrack/src/conntrack/callback.c 2006-12-12 23:29:39.000000000 +0100 @@ -0,0 +1,53 @@ +/* + * (C) 2006 by Pablo Neira Ayuso + * + * 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; +} Index: libnetfilter_conntrack/src/Makefile.am =================================================================== --- libnetfilter_conntrack.orig/src/Makefile.am 2006-12-04 16:15:53.000000000 +0100 +++ libnetfilter_conntrack/src/Makefile.am 2006-12-12 22:36:30.000000000 +0100 @@ -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 Index: libnetfilter_conntrack/include/libnetfilter_conntrack/libnetfilter_conntrack_tcp.h =================================================================== --- libnetfilter_conntrack.orig/include/libnetfilter_conntrack/libnetfilter_conntrack_tcp.h 2006-12-04 16:15:53.000000000 +0100 +++ libnetfilter_conntrack/include/libnetfilter_conntrack/libnetfilter_conntrack_tcp.h 2006-12-12 22:36:30.000000000 +0100 @@ -8,6 +8,19 @@ #ifndef _LIBNETFILTER_CONNTRACK_TCP_H_ #define _LIBNETFILTER_CONNTRACK_TCP_H_ +enum tcp_state { + NFCT_TCP_ST_NONE, + NFCT_TCP_ST_SYN_SENT, + NFCT_TCP_ST_SYN_RECV, + NFCT_TCP_ST_ESTABLISHED, + NFCT_TCP_ST_FIN_WAIT, + NFCT_TCP_ST_CLOSE_WAIT, + NFCT_TCP_ST_LAST_ACK, + NFCT_TCP_ST_TIME_WAIT, + NFCT_TCP_ST_CLOSE, + NFCT_TCP_ST_LISTEN +}; + enum tcp_flags { TCP_ORIG_SPORT_BIT = 0, TCP_ORIG_SPORT = (1 << TCP_ORIG_SPORT_BIT), Index: libnetfilter_conntrack/include/internal.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libnetfilter_conntrack/include/internal.h 2006-12-17 23:22:44.000000000 +0100 @@ -0,0 +1,154 @@ +/* + * (C) 2006 by Pablo Neira Ayuso + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * WARNING: Do *NOT* ever include this file, only for internal use! + * Use the set/get API in order to set/get the conntrack attributes + */ + +#ifndef __LIBNETFILTER_CONNTRACK_INTERNAL__ +#define __LIBNETFILTER_CONNTRACK_INTERNAL__ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct nfct_handle; + +typedef void (*set_attr)(struct nf_conntrack *ct, const void *value); +typedef const void *(*get_attr)(const struct nf_conntrack *ct); + +extern set_attr set_attr_array[]; +extern get_attr get_attr_array[]; + +typedef int (*nfct_handler)(struct nfct_handle *cth, struct nlmsghdr *nlh, + void *arg); + +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 */ + + /* callback handler for the new API */ + struct nfnl_callback nfnl_cb; + int(*cb)(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data); +}; + +union __nfct_l4 { + /* Add other protocols here. */ + u_int16_t all; + struct { + u_int16_t port; + } tcp; + struct { + u_int16_t port; + } udp; + struct { + u_int8_t type, code; + u_int16_t id; + } icmp; + struct { + u_int16_t port; + } sctp; +}; + +union __nfct_address { + u_int32_t v4; + struct in6_addr v6; +}; + +struct __nfct_tuple { + union __nfct_address src; + union __nfct_address dst; + + u_int8_t l3protonum; + u_int8_t protonum; + union __nfct_l4 l4src; + union __nfct_l4 l4dst; +}; + +union __nfct_protoinfo { + struct { + u_int8_t state; + } tcp; +}; + +struct __nfct_counters { + u_int64_t packets; + u_int64_t bytes; +}; + +struct __nfct_nat { + u_int32_t min_ip, max_ip; + union __nfct_l4 l4min, l4max; +}; + +#define __DIR_ORIG 0 +#define __DIR_REPL 1 +#define __DIR_MAX __DIR_REPL+1 + +struct nf_conntrack { + struct __nfct_tuple tuple[__DIR_MAX]; + + u_int32_t timeout; + u_int32_t mark; + u_int32_t status; + u_int32_t use; + u_int32_t id; + + union __nfct_protoinfo protoinfo; + struct __nfct_counters counters[__DIR_MAX]; + struct __nfct_nat snat; + struct __nfct_nat dnat; + + u_int32_t set[2]; +}; + +/* container used to pass data to nfnl callbacks */ +struct __data_container { + struct nfct_handle *h; + enum nf_conntrack_msg_type type; + void *data; +}; + +static inline void set_bit(int nr, u_int32_t *addr) +{ + addr[nr >> 5] |= (1UL << (nr & 31)); +} + +static inline void unset_bit(int nr, u_int32_t *addr) +{ + addr[nr >> 5] &= ~(1UL << (nr & 31)); +} + +static inline int test_bit(int nr, const u_int32_t *addr) +{ + return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0; +} + +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); +int __parse_message_type(const struct nlmsghdr *nlh); +void __parse_conntrack(const struct nlmsghdr *nlh, const struct nfattr *cda[], struct nf_conntrack *ct); +int __snprintf_conntrack(char *buf, unsigned int len, const struct nf_conntrack *ct, unsigned int type, unsigned int msg_output, unsigned int flags); + + +int __callback(struct nlmsghdr *nlh, struct nfattr *nfa[], void *data); + +int __setobjopt(struct nf_conntrack *ct, unsigned int option); +int __getobjopt(const struct nf_conntrack *ct, unsigned int option); + +#endif Index: libnetfilter_conntrack/include/Makefile.am =================================================================== --- libnetfilter_conntrack.orig/include/Makefile.am 2006-12-04 16:15:53.000000000 +0100 +++ libnetfilter_conntrack/include/Makefile.am 2006-12-12 22:36:30.000000000 +0100 @@ -1,4 +1,4 @@ SUBDIRS = libnetfilter_conntrack -noinst_HEADERS = linux_list.h +noinst_HEADERS = linux_list.h internal.h Index: libnetfilter_conntrack/src/conntrack/snprintf.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libnetfilter_conntrack/src/conntrack/snprintf.c 2006-12-18 02:10:57.000000000 +0100 @@ -0,0 +1,36 @@ +/* + * (C) 2006 by Pablo Neira Ayuso + * + * 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; +} Index: libnetfilter_conntrack/src/conntrack/snprintf_default.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libnetfilter_conntrack/src/conntrack/snprintf_default.c 2006-12-18 02:11:07.000000000 +0100 @@ -0,0 +1,344 @@ +/* + * (C) 2006 by Pablo Neira Ayuso + * + * 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; +} Index: libnetfilter_conntrack/src/conntrack/snprintf_xml.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libnetfilter_conntrack/src/conntrack/snprintf_xml.c 2006-12-17 02:29:56.000000000 +0100 @@ -0,0 +1,413 @@ +/* + * (C) 2006 by Pablo Neira Ayuso + * + * 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: + * + * + * + * + * 192.168.0.1 + * 192.168.0.2 + * + * + * 80 + * 56665 + * + * + * 10 + * 1 + * + * + * + * + * 192.168.0.2 + * 192.168.0.1 + * + * + * 80 + * 56665 + * + * + * 5029 + * 12 + * + * + * + * + * ESTABLISHED + * + * 100 + * 1 + * 1 + * + * + * + */ + +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, ""); + if (ret == -1) + return -1; + buffer_size(ret, &size, &len); + break; + case __ADDR_DST: + ret = snprintf(buf+size, len, ""); + 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, ""); + if (ret == -1) + return -1; + buffer_size(ret, &size, &len); + break; + case __ADDR_DST: + ret = snprintf(buf+size, len, ""); + 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, "%u", + tuple->l4src.tcp.port); + if (ret == -1) + return -1; + buffer_size(ret, &size, &len); + } else { + ret = snprintf(buf, len, "%u", + 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, "%llu", + ct->counters[type].packets); + if (ret == -1) + return -1; + buffer_size(ret, &size, &len); + + ret = snprintf(buf+size, len, "%llu", + 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, "", + dir == __DIR_ORIG ? "original" : "reply"); + if (ret == -1) + return -1; + buffer_size(ret, &size, &len); + + ret = snprintf(buf+size, len, + "", + 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, ""); + if (ret == -1) + return -1; + buffer_size(ret, &size, &len); + + ret = snprintf(buf+size, len, + "", + 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, ""); + 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, ""); + 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, ""); + if (ret == -1) + return -1; + buffer_size(ret, &size, &len); + } + + ret = snprintf(buf+size, len, ""); + 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, ""); + break; + case NFCT_T_UPDATE: + ret = snprintf(buf, len, ""); + 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, + ""); + if (ret == -1) + return -1; + buffer_size(ret, &size, &len); + } + + if (test_bit(ATTR_TIMEOUT, ct->set)) { + ret = snprintf(buf+size, len, + "%u", ct->timeout); + if (ret == -1) + return -1; + buffer_size(ret, &size, &len); + } + + if (test_bit(ATTR_MARK, ct->set)) { + ret = snprintf(buf+size, len, "%u", ct->mark); + if (ret == -1) + return -1; + buffer_size(ret, &size, &len); + } + + if (test_bit(ATTR_USE, ct->set)) { + ret = snprintf(buf+size, len, "%u", 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, ""); + 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, ""); + 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, ""); + if (ret == -1) + return -1; + buffer_size(ret, &size, &len); + } + + ret = snprintf(buf+size, len, ""); + if (ret == -1) + return -1; + buffer_size(ret, &size, &len); + + return size; +} Index: libnetfilter_conntrack/src/conntrack/objopt.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ libnetfilter_conntrack/src/conntrack/objopt.c 2006-12-17 20:34:38.000000000 +0100 @@ -0,0 +1,71 @@ +/* + * (C) 2006 by Pablo Neira Ayuso + * + * 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; +}