diff options
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | include/internal.h | 64 | ||||
-rw-r--r-- | include/libnetfilter_conntrack/libnetfilter_conntrack.h | 35 | ||||
-rw-r--r-- | src/conntrack/Makefile.am | 3 | ||||
-rw-r--r-- | src/conntrack/api.c | 93 | ||||
-rw-r--r-- | src/conntrack/bsf.c | 416 | ||||
-rw-r--r-- | src/conntrack/filter.c | 39 | ||||
-rw-r--r-- | utils/Makefile.am | 6 | ||||
-rw-r--r-- | utils/conntrack_filter.c | 83 |
9 files changed, 738 insertions, 3 deletions
diff --git a/configure.in b/configure.in index fef5508..6568334 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ AC_INIT AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(libnetfilter_conntrack, 0.0.96) +AM_INIT_AUTOMAKE(libnetfilter_conntrack, 0.0.97) AC_PROG_CC AM_PROG_LIBTOOL diff --git a/include/internal.h b/include/internal.h index 6661dbe..33b0dcd 100644 --- a/include/internal.h +++ b/include/internal.h @@ -19,6 +19,7 @@ #include <arpa/inet.h> #include <time.h> #include <errno.h> +#include <netinet/in.h> #include <libnfnetlink/libnfnetlink.h> #include <libnetfilter_conntrack/libnetfilter_conntrack.h> @@ -31,15 +32,22 @@ #define IPPROTO_UDPLITE 136 #endif +#ifndef IPPROTO_DCCP +#define IPPROTO_DCCP 33 +#endif + struct nfct_handle; +struct nfct_filter; typedef void (*set_attr)(struct nf_conntrack *ct, const void *value); typedef const void *(*get_attr)(const struct nf_conntrack *ct); typedef void (*copy_attr)(struct nf_conntrack *d, const struct nf_conntrack *o); +typedef void (*filter_attr)(struct nfct_filter *filter, const void *value); extern set_attr set_attr_array[]; extern get_attr get_attr_array[]; extern copy_attr copy_attr_array[]; +extern filter_attr filter_attr_array[]; typedef int (*nfct_handler)(struct nfct_handle *cth, struct nlmsghdr *nlh, void *arg); @@ -165,6 +173,50 @@ struct nf_conntrack { u_int32_t set[2]; }; +struct nfct_filter { + /* + * As many other objects in this library, the attributes are + * private. This gives us the chance to modify the layout and + * object size. + * + * Another observation, although this object might seem too + * memory consuming, it is only needed to build the filter. Thus, + * once it is attached, you can release this object. + */ + + /* + * This the layer 4 protocol map for filtering. + */ + u_int32_t l4proto_map[IPPROTO_MAX/32]; + + struct { + /* + * No limitations in the protocol filtering. We use a map of + * 16 bits per protocol. As for now, DCCP has 10 states, TCP has + * 10 states, SCTP has 8 state. Therefore, 16 bits is enough. + */ +#define __FILTER_PROTO_MAX 16 + u_int16_t map; + } l4proto_state[IPPROTO_MAX]; + +#define __FILTER_ADDR_SRC 0 +#define __FILTER_ADDR_DST 1 + + /* + * FIXME: For IPv4 filtering, up to 256 IPs or masks by now. + * This limitation is related to the existing autogenerated BSF code + * and the fact that the maximum jump offset if 2^8 = 256. + */ + u_int32_t l3proto_elems[2]; + struct { +#define __FILTER_ADDR_MAX 256 + u_int32_t addr; + u_int32_t mask; + } l3proto[2][__FILTER_ADDR_MAX]; + + u_int32_t set[1]; +}; + struct nf_expect { struct nf_conntrack master; struct nf_conntrack expected; @@ -193,6 +245,16 @@ static inline void unset_bit(int nr, u_int32_t *addr) addr[nr >> 5] &= ~(1UL << (nr & 31)); } +static inline void set_bit_u16(int nr, u_int16_t *addr) +{ + addr[nr >> 4] |= (1UL << (nr & 15)); +} + +static inline void unset_bit_u16(int nr, u_int16_t *addr) +{ + addr[nr >> 4] &= ~(1UL << (nr & 15)); +} + static inline int test_bit(int nr, const u_int32_t *addr) { return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0; @@ -224,6 +286,8 @@ int __setobjopt(struct nf_conntrack *ct, unsigned int option); int __getobjopt(const struct nf_conntrack *ct, unsigned int option); int __compare(const struct nf_conntrack *ct1, const struct nf_conntrack *ct2, unsigned int flags); +int __setup_netlink_socket_filter(int fd, struct nfct_filter *filter); + typedef void (*set_exp_attr)(struct nf_expect *exp, const void *value); typedef const void *(*get_exp_attr)(const struct nf_expect *exp); diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack.h b/include/libnetfilter_conntrack/libnetfilter_conntrack.h index a043f91..328cf8b 100644 --- a/include/libnetfilter_conntrack/libnetfilter_conntrack.h +++ b/include/libnetfilter_conntrack/libnetfilter_conntrack.h @@ -324,6 +324,41 @@ extern void nfct_copy_attr(struct nf_conntrack *ct1, const struct nf_conntrack *ct2, const enum nf_conntrack_attr type); +/* filter */ + +struct nfct_filter; + +extern struct nfct_filter *nfct_filter_create(void); +extern void nfct_filter_destroy(struct nfct_filter *filter); + +struct nfct_filter_proto { + u_int16_t proto; + u_int16_t state; +}; +struct nfct_filter_ipv4 { + u_int32_t addr; + u_int32_t mask; +}; + +enum nfct_filter_attr { + NFCT_FILTER_L4PROTO = 0, /* u_int32_t */ + NFCT_FILTER_L4PROTO_STATE, /* struct nfct_filter_proto */ + NFCT_FILTER_SRC_IPV4, /* struct nfct_filter_ipv4 */ + NFCT_FILTER_DST_IPV4, /* struct nfct_filter_ipv4 */ + NFCT_FILTER_MAX +}; + +extern void nfct_filter_add_attr(struct nfct_filter *filter, + const enum nfct_filter_attr attr, + const void *value); + +extern void nfct_filter_add_attr_u32(struct nfct_filter *filter, + const enum nfct_filter_attr attr, + const u_int32_t value); + +extern int nfct_filter_attach(int fd, struct nfct_filter *filter); +extern int nfct_filter_detach(int fd); + /* low level API: netlink functions */ extern int nfct_build_conntrack(struct nfnl_subsys_handle *ssh, diff --git a/src/conntrack/Makefile.am b/src/conntrack/Makefile.am index 6440dd7..94009ea 100644 --- a/src/conntrack/Makefile.am +++ b/src/conntrack/Makefile.am @@ -12,4 +12,5 @@ libnfconntrack_la_SOURCES = api.c callback.c \ snprintf_default.c snprintf_xml.c \ objopt.c \ compare.c \ - copy.c + copy.c \ + filter.c bsf.c diff --git a/src/conntrack/api.c b/src/conntrack/api.c index 58efd32..3bd96a8 100644 --- a/src/conntrack/api.c +++ b/src/conntrack/api.c @@ -842,3 +842,96 @@ void nfct_copy_attr(struct nf_conntrack *ct1, set_bit(type, ct1->set); } } + +/** + * nfct_filter_create - create a filter + * + * This function returns a valid pointer on success, otherwise NULL is + * returned and errno is appropriately set. + */ +struct nfct_filter *nfct_filter_create(void) +{ + return calloc(sizeof(struct nfct_filter), 1); +} + +/** + * nfct_filter_destroy - destroy a filter + * @filter: filter that we want to destroy + * + * This function releases the memory that is used by the filter object. + * However, please note that this function does *not* detach an already + * attached filter. + */ +void nfct_filter_destroy(struct nfct_filter *filter) +{ + assert(filter != NULL); + free(filter); + filter = NULL; +} + +/** + * nfct_filter_add_attr - add a filter attribute of the filter object + * @filter: filter object that we want to modify + * @type: filter attribute type + * @value: pointer to the value of the filter attribute + * + * Limitations: You can add up to 256 IPv4 addresses and masks for + * NFCT_FILTER_SRC_IPV4 and, similarly, 256 for NFCT_FILTER_DST_IPV4. + */ +void nfct_filter_add_attr(struct nfct_filter *filter, + const enum nfct_filter_attr type, + const void *value) +{ + assert(filter != NULL); + assert(value != NULL); + + if (type >= NFCT_FILTER_MAX) + return; + + if (filter_attr_array[type]) { + filter_attr_array[type](filter, value); + set_bit(type, filter->set); + } +} + +/** + * nfct_filter_add_attr_u32 - add an u32 filter attribute of the filter object + * @filter: filter object that we want to modify + * @type: filter attribute type + * @value: value of the filter attribute using unsigned int (32 bits). + */ +void nfct_filter_add_attr_u32(struct nfct_filter *filter, + const enum nfct_filter_attr type, + u_int32_t value) +{ + nfct_filter_add_attr(filter, type, &value); +} + +/** + * nfct_filter_attach - attach a filter to a socket descriptor + * @fd: socket descriptor + * @filter: filter that we want to attach to the socket + * + * This function returns -1 on error and set errno appropriately. If the + * function returns EINVAL probably you have found a bug in it. Please, + * report this. + */ +int nfct_filter_attach(int fd, struct nfct_filter *filter) +{ + assert(filter != NULL); + + return __setup_netlink_socket_filter(fd, filter); +} + +/** + * nfct_filter_detach - detach an existing filter + * @fd: socket descriptor + * + * This function returns -1 on error and set errno appropriately. + */ +int nfct_filter_detach(int fd) +{ + int val = 0; + + return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, &val, sizeof(val)); +} diff --git a/src/conntrack/bsf.c b/src/conntrack/bsf.c new file mode 100644 index 0000000..2ac5fe1 --- /dev/null +++ b/src/conntrack/bsf.c @@ -0,0 +1,416 @@ +/* + * (C) 2008 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" +#include <linux/filter.h> + +#ifndef SKF_AD_NLATTR +#define SKF_AD_NLATTR 12 +#endif + +#define NFCT_FILTER_REJECT 0U +#define NFCT_FILTER_ACCEPT ~0U + +#if 0 +static void show_filter(struct sock_filter *this, int size) +{ + int i; + + for(i=0; i<size; i++) + printf("(%.4x) code=%.4x jt=%.2x jf=%.2x k=%.8x\n", + i, + this[i].code & 0xFFFF, + this[i].jt & 0xFF, + this[i].jf & 0xFF, + this[i].k & 0xFFFFFFFF); +} +#else +static inline void show_filter(struct sock_filter *this, int size) {} +#endif + +static void set_basic_filter(struct sock_filter *this, + unsigned int first_type, + unsigned int second_type, + unsigned int third_type, + unsigned int label, + unsigned int word_size) +{ + struct sock_filter filter[] = { + [0] = { + /* A = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg) */ + .code = BPF_LD|BPF_IMM, + .k = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg), + }, + [1] = { + /* X = first_type */ + .code = BPF_LDX|BPF_IMM, + .k = first_type, + }, + [2] = { + /* A = netlink attribute offset */ + .code = BPF_LD|BPF_B|BPF_ABS, + .k = SKF_AD_OFF + SKF_AD_NLATTR, + }, + [3] = { + /* Reject if not found (A == 0) */ + .code = BPF_JMP|BPF_JEQ|BPF_K, + .k = 0, + .jt = label - 3 - 1, + }, + [4] = { + /* A += sizeof(struct nfattr) */ + .code = BPF_ALU|BPF_ADD|BPF_K, + .k = sizeof(struct nfattr), + }, + [5] = { + /* X = second_type */ + .code = BPF_LDX|BPF_IMM, + .k = second_type, + }, + [6] = { + /* A = netlink attribute offset */ + .code = BPF_LD|BPF_B|BPF_ABS, + .k = SKF_AD_OFF + SKF_AD_NLATTR, + }, + [7] = { + /* Reject if not found (A == 0) */ + .code = BPF_JMP|BPF_JEQ|BPF_K, + .k = 0, + .jt = label - 7 - 1, + }, + [8] = { + /* A += sizeof(struct nfattr) */ + .code = BPF_ALU|BPF_ADD|BPF_K, + .k = sizeof(struct nfattr), + }, + [9] = { + /* X = third_type */ + .code = BPF_LDX|BPF_IMM, + .k = third_type, + }, + [10] = { + /* A = netlink attribute offset */ + .code = BPF_LD|BPF_B|BPF_ABS, + .k = SKF_AD_OFF + SKF_AD_NLATTR, + }, + [11] = { + /* Reject if not found (A == 0) */ + .code = BPF_JMP|BPF_JEQ|BPF_K, + .k = 0, + .jt = label - 11 - 1, + }, + [12] = { + /* X = A */ + .code = BPF_MISC|BPF_TAX, + }, + [13] = { + /* A = skb->data[X + k:word_size] */ + .code = BPF_LD|word_size|BPF_IND, + .k = sizeof(struct nfattr), + }, + }; + + memcpy(this, filter, sizeof(filter)); +} + +static int +add_state_filter_cta(struct sock_filter *this, + unsigned int cta_protoinfo_proto, + unsigned int cta_protoinfo_state, + u_int16_t state_flags, + size_t remain) +{ + struct sock_filter filter[14 + __FILTER_PROTO_MAX]; + struct sock_filter verdict = { + /* Reject */ + .code = BPF_RET|BPF_K, + .k = NFCT_FILTER_REJECT, + }; + unsigned int i, j; + unsigned int label_continue; + + /* calculate the number of filter lines */ + for (i = 0, j = 0; i < sizeof(state_flags) * 8; i++) { + if (state_flags & (1 << i)) { + j++; + } + } + + /* nothing to filter, skip */ + if (j == 0) + return 0; + + if (j + 14 >= __FILTER_PROTO_MAX + 14 || j + 14 > remain) { + errno = ENOSPC; + return -1; + } + + memset(filter, 0, sizeof(filter)); + + label_continue = j + 1; + + set_basic_filter(filter, + CTA_PROTOINFO, + cta_protoinfo_proto, + cta_protoinfo_state, + 14 + label_continue, + BPF_B); + + for (i = 0, j = 0; i < sizeof(state_flags) * 8; i++) { + struct sock_filter cmp = { + .code = BPF_JMP|BPF_JEQ|BPF_K, + .k = i, + .jt = label_continue - j - 1, + }; + + if (state_flags & (1 << i)) { + memcpy(&filter[j + 14], &cmp, sizeof(cmp)); + j++; + } + } + + memcpy(this, filter, sizeof(struct sock_filter) * (j + 14)); + memcpy(&this[j + 14], &verdict, sizeof(verdict)); + + return j + 14 + 1; +} + +static int +add_state_filter(struct sock_filter *this, + int proto, + u_int16_t flags, + size_t remain) +{ + struct { + unsigned int cta_protoinfo; + unsigned int cta_state; + } cta[IPPROTO_MAX] = { + [IPPROTO_TCP] = { + .cta_protoinfo = CTA_PROTOINFO_TCP, + .cta_state = CTA_PROTOINFO_TCP_STATE, + }, + [IPPROTO_SCTP] = { + .cta_protoinfo = CTA_PROTOINFO_SCTP, + .cta_state = CTA_PROTOINFO_SCTP_STATE, + }, + [IPPROTO_DCCP] = { + .cta_protoinfo = CTA_PROTOINFO_DCCP, + .cta_state = CTA_PROTOINFO_DCCP_STATE, + }, + }; + + if (cta[proto].cta_protoinfo == 0 && cta[proto].cta_state == 0) { + errno = ENOTSUP; + return -1; + } + + return add_state_filter_cta(this, + cta[proto].cta_protoinfo, + cta[proto].cta_state, + flags, + remain); +} + +static int +bsf_add_state_filter(const struct nfct_filter *filter, + struct sock_filter *this, + size_t remain) +{ + unsigned int i, j; + + for (i = 0, j = 0; i < IPPROTO_MAX; i++) { + if (test_bit(i, filter->l4proto_map) && + filter->l4proto_state[i].map) { + j += add_state_filter(this, + i, + filter->l4proto_state[i].map, + remain); + } + } + + return j; +} + +static int +bsf_add_proto_filter(const struct nfct_filter *f, + struct sock_filter *this, + size_t remain) +{ + struct sock_filter filter[14 + IPPROTO_MAX]; + struct sock_filter verdict = { + /* Reject */ + .code = BPF_RET|BPF_K, + .k = NFCT_FILTER_REJECT, + }; + unsigned int i, j; + unsigned int label_continue; + + for (i = 0, j = 0; i < IPPROTO_MAX; i++) { + if (test_bit(i, f->l4proto_map)) { + j++; + } + } + + /* nothing to filter, skip */ + if (j == 0) + return 0; + + if (j + 14 >= IPPROTO_MAX + 14 || j + 14 > remain) { + errno = ENOSPC; + return -1; + } + + label_continue = j + 1; + + memset(filter, 0, sizeof(filter)); + + set_basic_filter(filter, + CTA_TUPLE_ORIG, + CTA_TUPLE_PROTO, + CTA_PROTO_NUM, + 14 + label_continue, + BPF_B); + + for (i = 0, j = 0; i < IPPROTO_MAX; i++) { + struct sock_filter cmp = { + .code = BPF_JMP|BPF_JEQ|BPF_K, + .k = i, + .jt = label_continue - j - 1, + }; + + if (test_bit(i, f->l4proto_map)) { + memcpy(&filter[j + 14], &cmp, sizeof(cmp)); + j++; + } + } + + memcpy(this, filter, sizeof(struct sock_filter) * (j + 14)); + memcpy(&this[j + 14], &verdict, sizeof(verdict)); + + return j + 14 + 1; +} + +static int +bsf_add_addr_ipv4_filter(const struct nfct_filter *f, + struct sock_filter *this, + unsigned int type, + size_t remain) +{ + struct sock_filter filter[14 + __FILTER_ADDR_MAX]; + struct sock_filter verdict = { + /* Reject */ + .code = BPF_RET|BPF_K, + .k = NFCT_FILTER_REJECT, + }; + unsigned int i, j, dir; + unsigned int label_continue; + + switch(type) { + case CTA_IP_V4_SRC: + dir = __FILTER_ADDR_SRC; + break; + case CTA_IP_V4_DST: + dir = __FILTER_ADDR_DST; + break; + default: + return 0; + } + + /* nothing to filter, skip */ + if (f->l3proto_elems[dir] == 0) + return 0; + + if (f->l3proto_elems[dir] + 14 >= __FILTER_ADDR_MAX + 14 || + f->l3proto_elems[dir] + 14 > remain) { + errno = ENOSPC; + return -1; + } + + label_continue = (f->l3proto_elems[dir] * 2) + 1; + + memset(filter, 0, sizeof(filter)); + + set_basic_filter(filter, + CTA_TUPLE_ORIG, + CTA_TUPLE_IP, + type, + 14 + label_continue, + BPF_W); + + for (i = 0, j = 0; i < f->l3proto_elems[dir]; i++) { + struct sock_filter cmp[] = { + [0] = { + .code = BPF_ALU|BPF_AND|BPF_K, + .k = f->l3proto[dir][i].mask, + }, + [1] = { + .code = BPF_JMP|BPF_JEQ|BPF_K, + .k = f->l3proto[dir][i].addr & + f->l3proto[dir][i].mask, + .jt = label_continue - j - 2, + }, + }; + memcpy(&filter[j + 14], cmp, sizeof(cmp)); + j+=2; + } + + memcpy(this, filter, sizeof(struct sock_filter) * (j + 14)); + memcpy(&this[j + 14], &verdict, sizeof(verdict)); + + return j + 14 + 1; +} + +static int +bsf_add_saddr_ipv4_filter(const struct nfct_filter *f, + struct sock_filter *this, + size_t remain) +{ + return bsf_add_addr_ipv4_filter(f, this, CTA_IP_V4_SRC, remain); +} + +static int +bsf_add_daddr_ipv4_filter(const struct nfct_filter *f, + struct sock_filter *this, + size_t remain) +{ + return bsf_add_addr_ipv4_filter(f, this, CTA_IP_V4_DST, remain); +} + +/* this buffer must be big enough to store all the autogenerated lines */ +#define BSF_BUFFER_SIZE 1024 + +int __setup_netlink_socket_filter(int fd, struct nfct_filter *f) +{ + struct sock_filter bsf[BSF_BUFFER_SIZE]; + struct sock_filter bsf_accept = { + /* Accept */ + .code = BPF_RET|BPF_K, + .k = NFCT_FILTER_ACCEPT, + }; + struct sock_fprog sf; + unsigned int j = 0; + + memset(bsf, 0, sizeof(bsf)); + + j += bsf_add_proto_filter(f, &bsf[j], BSF_BUFFER_SIZE-j); + j += bsf_add_saddr_ipv4_filter(f, &bsf[j], BSF_BUFFER_SIZE-j); + j += bsf_add_daddr_ipv4_filter(f, &bsf[j], BSF_BUFFER_SIZE-j); + j += bsf_add_state_filter(f, &bsf[j], BSF_BUFFER_SIZE-j); + + /* nothing to filter, skip */ + if (j == 0) + return 0; + + memcpy(&bsf[j], &bsf_accept, sizeof(struct sock_filter)); + + show_filter(bsf, j+1); + + sf.len = (sizeof(struct sock_filter) * (j + 1)) / sizeof(bsf[0]); + sf.filter = bsf; + + return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &sf, sizeof(sf)); +} diff --git a/src/conntrack/filter.c b/src/conntrack/filter.c new file mode 100644 index 0000000..5ea7d5e --- /dev/null +++ b/src/conntrack/filter.c @@ -0,0 +1,39 @@ +#include "internal.h" + +static void filter_attr_l4proto(struct nfct_filter *filter, const void *value) +{ + set_bit(*((int *) value), filter->l4proto_map); +} + +static void +filter_attr_l4proto_state(struct nfct_filter *filter, const void *value) +{ + const struct nfct_filter_proto *this = value; + + set_bit_u16(this->state, &filter->l4proto_state[this->proto].map); +} + +static void filter_attr_src_ipv4(struct nfct_filter *filter, const void *value) +{ + const struct nfct_filter_ipv4 *this = value; + + filter->l3proto[0][filter->l3proto_elems[0]].addr = this->addr; + filter->l3proto[0][filter->l3proto_elems[0]].mask = this->mask; + filter->l3proto_elems[0]++; +} + +static void filter_attr_dst_ipv4(struct nfct_filter *filter, const void *value) +{ + const struct nfct_filter_ipv4 *this = value; + + filter->l3proto[1][filter->l3proto_elems[1]].addr = this->addr; + filter->l3proto[1][filter->l3proto_elems[1]].mask = this->mask; + filter->l3proto_elems[1]++; +} + +filter_attr filter_attr_array[] = { + [NFCT_FILTER_L4PROTO] = filter_attr_l4proto, + [NFCT_FILTER_L4PROTO_STATE] = filter_attr_l4proto_state, + [NFCT_FILTER_SRC_IPV4] = filter_attr_src_ipv4, + [NFCT_FILTER_DST_IPV4] = filter_attr_dst_ipv4, +}; diff --git a/utils/Makefile.am b/utils/Makefile.am index bdf3833..b0797ae 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -5,7 +5,7 @@ check_PROGRAMS = expect_dump expect_create expect_get expect_delete \ conntrack_create conntrack_dump conntrack_update \ conntrack_delete conntrack_flush conntrack_create_nat \ conntrack_get conntrack_events \ - conntrack_master + conntrack_master conntrack_filter conntrack_create_SOURCES = conntrack_create.c conntrack_create_LDADD = ../src/libnetfilter_conntrack.la @@ -39,6 +39,10 @@ conntrack_events_SOURCES = conntrack_events.c conntrack_events_LDADD = ../src/libnetfilter_conntrack.la conntrack_events_LDFLAGS = -dynamic -ldl +conntrack_filter_SOURCES = conntrack_filter.c +conntrack_filter_LDADD = ../src/libnetfilter_conntrack.la +conntrack_filter_LDFLAGS = -dynamic -ldl + conntrack_master_SOURCES = conntrack_master.c conntrack_master_LDADD = ../src/libnetfilter_conntrack.la conntrack_master_LDFLAGS = -dynamic -ldl diff --git a/utils/conntrack_filter.c b/utils/conntrack_filter.c new file mode 100644 index 0000000..7d22950 --- /dev/null +++ b/utils/conntrack_filter.c @@ -0,0 +1,83 @@ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include <libnetfilter_conntrack/libnetfilter_conntrack.h> +#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h> + +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_PLAIN, NFCT_OF_TIME); + 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 nfct_filter *filter; + struct nf_conntrack *ct; + char buf[1024]; + + h = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE); + if (!h) { + perror("nfct_open"); + return 0; + } + + filter = nfct_filter_create(); + if (!filter) { + perror("nfct_create_filter"); + return 0; + } + + nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP); + nfct_filter_add_attr_u32(filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP); + + struct nfct_filter_proto filter_proto = { + .proto = IPPROTO_TCP, + .state = TCP_CONNTRACK_ESTABLISHED + }; + + nfct_filter_add_attr(filter, NFCT_FILTER_L4PROTO_STATE, &filter_proto); + + struct nfct_filter_ipv4 filter_ipv4 = { + .addr = htonl(inet_addr("127.0.0.1")), + .mask = 0xffffffff, + }; + + nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4); + + if (nfct_filter_attach(nfct_fd(h), filter) == -1) { + perror("nfct_filter_attach"); + return 0; + } + + /* release the filter object, this does not detach the filter */ + nfct_filter_destroy(filter); + + nfct_callback_register(h, NFCT_T_ALL, event_cb, NULL); + + printf("TEST: waiting for 10 events...\n"); + + ret = nfct_catch(h); + + printf("TEST: OK (%d)(%s)\n", ret, strerror(errno)); + + if (ret == -1) + exit(EXIT_FAILURE); + + nfct_close(h); +} |