From f9dc4d2ed9f724057ed107839aa8ca6122f7b46c Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org" Date: Sun, 16 Oct 2005 19:44:46 +0000 Subject: Major changes, this library isn't libnfnetlink_conntrack anymore. We provide an high level interface that abstracts from the netlink sockets. Now users don't need to know anything about them. --- Makefile.am | 2 +- configure.in | 9 +- extensions/Makefile.am | 16 + extensions/libnetfilter_conntrack_icmp.c | 65 ++ extensions/libnetfilter_conntrack_sctp.c | 69 ++ extensions/libnetfilter_conntrack_tcp.c | 84 ++ extensions/libnetfilter_conntrack_udp.c | 53 ++ include/Makefile.am | 2 +- include/libnetfilter_conntrack/Makefile.am | 2 + .../libnfnetlink_conntrack.h | 131 +++ include/libnfnetlink_conntrack/Makefile.am | 6 - .../libnfnetlink_conntrack.h | 131 --- include/linux_list.h | 725 +++++++++++++++ src/Makefile.am | 6 +- src/libnetfilter_conntrack.c | 994 +++++++++++++++++++++ src/libnfnetlink_conntrack.c | 579 ------------ 16 files changed, 2151 insertions(+), 723 deletions(-) create mode 100644 extensions/Makefile.am create mode 100644 extensions/libnetfilter_conntrack_icmp.c create mode 100644 extensions/libnetfilter_conntrack_sctp.c create mode 100644 extensions/libnetfilter_conntrack_tcp.c create mode 100644 extensions/libnetfilter_conntrack_udp.c create mode 100644 include/libnetfilter_conntrack/Makefile.am create mode 100644 include/libnetfilter_conntrack/libnfnetlink_conntrack.h delete mode 100644 include/libnfnetlink_conntrack/Makefile.am delete mode 100644 include/libnfnetlink_conntrack/libnfnetlink_conntrack.h create mode 100644 include/linux_list.h create mode 100644 src/libnetfilter_conntrack.c delete mode 100644 src/libnfnetlink_conntrack.c diff --git a/Makefile.am b/Makefile.am index 026dc26..4cecdaf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 INCLUDES =$(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} -SUBDIRS = include src +SUBDIRS = include src extensions LINKOPTS = -lnfnetlink man_MANS = #nfnetlink_conntrack.3 nfnetlink_conntrack.7 diff --git a/configure.in b/configure.in index a6b05ab..a2b8468 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ AC_INIT AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(libnfnetlink_conntrack, 0.0.10) +AM_INIT_AUTOMAKE(libnetfilter_conntrack, 0.0.20) AC_PROG_CC AM_PROG_LIBTOOL @@ -59,9 +59,14 @@ AC_ARG_WITH(kernel, [ Show location of kernel source. Default is to use uname -r and look in /lib/modules/KERNEL/build/include. ]), NF_KERNEL_SOURCE($with_kernel),NF_KERNEL_SOURCE()) +if test ! -z "$libdir"; then + MODULE_DIR="\\\"$libdir/\\\"" + CFLAGS="$CFLAGS -DLIBNETFILTER_CONNTRACK_DIR=$MODULE_DIR" +fi + dnl-------------------------------- dnl Output the makefile -AC_OUTPUT(Makefile src/Makefile include/Makefile utils/Makefile) +AC_OUTPUT(Makefile src/Makefile include/Makefile utils/Makefile include/libnetfilter_conntrack/Makefile extensions/Makefile) diff --git a/extensions/Makefile.am b/extensions/Makefile.am new file mode 100644 index 0000000..c06e9f6 --- /dev/null +++ b/extensions/Makefile.am @@ -0,0 +1,16 @@ +AUTOMAKE_OPTIONS = no-dependencies foreign + +EXTRA_DIST = $(man_MANS) acinclude.m4 + +man_MANS = + +INCLUDES=-I../include -I${KERNELDIR} +CFLAGS=-fPIC -Wall +LIBS= + +lib_LTLIBRARIES = libnetfilter_conntrack_tcp.la libnetfilter_conntrack_udp.la libnetfilter_conntrack_icmp.la libnetfilter_conntrack_sctp.la + +libnetfilter_conntrack_tcp_la_SOURCES = libnetfilter_conntrack_tcp.c +libnetfilter_conntrack_udp_la_SOURCES = libnetfilter_conntrack_udp.c +libnetfilter_conntrack_icmp_la_SOURCES = libnetfilter_conntrack_icmp.c +libnetfilter_conntrack_sctp_la_SOURCES = libnetfilter_conntrack_sctp.c diff --git a/extensions/libnetfilter_conntrack_icmp.c b/extensions/libnetfilter_conntrack_icmp.c new file mode 100644 index 0000000..38ad41a --- /dev/null +++ b/extensions/libnetfilter_conntrack_icmp.c @@ -0,0 +1,65 @@ +/* + * (C) 2005 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include +#include +#include /* For htons */ +#include +#include + +void parse_proto(struct nfattr *cda[], struct nfct_tuple *tuple) +{ + if (cda[CTA_PROTO_ICMP_TYPE-1]) + tuple->l4dst.icmp.type = + *(u_int8_t *)NFA_DATA(cda[CTA_PROTO_ICMP_TYPE-1]); + + if (cda[CTA_PROTO_ICMP_CODE-1]) + tuple->l4dst.icmp.code = + *(u_int8_t *)NFA_DATA(cda[CTA_PROTO_ICMP_CODE-1]); + + if (cda[CTA_PROTO_ICMP_ID-1]) + tuple->l4src.icmp.id = + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_ICMP_ID-1]); +} + +int print_proto(char *buf, struct nfct_tuple *t) +{ + int size = 0; + + size += sprintf(buf, "type=%d code=%d ", t->l4dst.icmp.type, + t->l4dst.icmp.code); + /* ID only makes sense with ECHO */ + if (t->l4dst.icmp.type == 8) + size += sprintf(buf, "id=%d ", t->l4src.icmp.id); + + return size; +} + +static struct nfct_proto icmp = { + .name = "icmp", + .protonum = IPPROTO_ICMP, + .parse_proto = parse_proto, + .print_proto = print_proto, + .version = LIBNETFILTER_CONNTRACK_VERSION +}; + +void __attribute__ ((constructor)) init(void); +void __attribute__ ((destructor)) fini(void); + +void init(void) +{ + nfct_register_proto(&icmp); +} + +void fini(void) +{ + nfct_unregister_proto(&icmp); +} diff --git a/extensions/libnetfilter_conntrack_sctp.c b/extensions/libnetfilter_conntrack_sctp.c new file mode 100644 index 0000000..a42a6c8 --- /dev/null +++ b/extensions/libnetfilter_conntrack_sctp.c @@ -0,0 +1,69 @@ +/* + * (C) 2005 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include +#include +#include /* For htons */ +#include +#include + +void parse_proto(struct nfattr *cda[], struct nfct_tuple *tuple) +{ + if (cda[CTA_PROTO_SRC_PORT-1]) + tuple->l4src.sctp.port = + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SRC_PORT-1]); + if (cda[CTA_PROTO_DST_PORT-1]) + tuple->l4dst.sctp.port = + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_DST_PORT-1]); +} + +void parse_protoinfo(struct nfattr *cda[], struct nfct_conntrack *ct) +{ +/* if (cda[CTA_PROTOINFO_SCTP_STATE-1]) + ct->protoinfo.sctp.state = + *(u_int8_t *)NFA_DATA(cda[CTA_PROTOINFO_SCTP_STATE-1]); +*/ +} + +int print_protoinfo(char *buf, union nfct_protoinfo *protoinfo) +{ +/* fprintf(stdout, "%s ", states[protoinfo->sctp.state]); */ + return 0; +} + +int print_proto(char *buf, struct nfct_tuple *tuple) +{ + return(sprintf(buf, "sport=%u dport=%u ", htons(tuple->l4src.sctp.port), + htons(tuple->l4dst.sctp.port))); +} + +static struct nfct_proto sctp = { + .name = "sctp", + .protonum = IPPROTO_SCTP, + .parse_proto = parse_proto, + .parse_protoinfo = parse_protoinfo, + .print_proto = print_proto, + .print_protoinfo = print_protoinfo, + .version = LIBNETFILTER_CONNTRACK_VERSION +}; + +void __attribute__ ((constructor)) init(void); +void __attribute__ ((destructor)) fini(void); + +void init(void) +{ + nfct_register_proto(&sctp); +} + +void fini(void) +{ + nfct_unregister_proto(&sctp); +} diff --git a/extensions/libnetfilter_conntrack_tcp.c b/extensions/libnetfilter_conntrack_tcp.c new file mode 100644 index 0000000..5b53fd1 --- /dev/null +++ b/extensions/libnetfilter_conntrack_tcp.c @@ -0,0 +1,84 @@ +/* + * (C) 2005 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include +#include +#include /* For htons */ +#include +#include + +static const char *states[] = { + "NONE", + "SYN_SENT", + "SYN_RECV", + "ESTABLISHED", + "FIN_WAIT", + "CLOSE_WAIT", + "LAST_ACK", + "TIME_WAIT", + "CLOSE", + "LISTEN" +}; + +void parse_proto(struct nfattr *cda[], struct nfct_tuple *tuple) +{ + if (cda[CTA_PROTO_SRC_PORT-1]) + tuple->l4src.tcp.port = + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SRC_PORT-1]); + if (cda[CTA_PROTO_DST_PORT-1]) + tuple->l4dst.tcp.port = + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_DST_PORT-1]); +} + +void parse_protoinfo(struct nfattr *cda[], struct nfct_conntrack *ct) +{ + struct nfattr *tb[CTA_PROTOINFO_TCP_MAX]; + + nfnl_parse_nested(tb,CTA_PROTOINFO_TCP_MAX, cda[CTA_PROTOINFO_TCP-1]); + + if (tb[CTA_PROTOINFO_TCP_STATE-1]) + ct->protoinfo.tcp.state = + *(u_int8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]); +} + +int print_protoinfo(char *buf, union nfct_protoinfo *protoinfo) +{ + return(sprintf(buf, "%s ", states[protoinfo->tcp.state])); +} + +int print_proto(char *buf, struct nfct_tuple *tuple) +{ + return(sprintf(buf, "sport=%u dport=%u ", htons(tuple->l4src.tcp.port), + htons(tuple->l4dst.tcp.port))); +} + +static struct nfct_proto tcp = { + .name = "tcp", + .protonum = IPPROTO_TCP, + .parse_protoinfo = parse_protoinfo, + .parse_proto = parse_proto, + .print_protoinfo = print_protoinfo, + .print_proto = print_proto, + .version = LIBNETFILTER_CONNTRACK_VERSION +}; + +void __attribute__ ((constructor)) init(void); +void __attribute__ ((destructor)) fini(void); + +void init(void) +{ + nfct_register_proto(&tcp); +} + +void fini(void) +{ + nfct_unregister_proto(&tcp); +} diff --git a/extensions/libnetfilter_conntrack_udp.c b/extensions/libnetfilter_conntrack_udp.c new file mode 100644 index 0000000..de7c9f7 --- /dev/null +++ b/extensions/libnetfilter_conntrack_udp.c @@ -0,0 +1,53 @@ +/* + * (C) 2005 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include +#include +#include /* For htons */ +#include +#include + +void parse_proto(struct nfattr *cda[], struct nfct_tuple *tuple) +{ + if (cda[CTA_PROTO_SRC_PORT-1]) + tuple->l4src.udp.port = + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SRC_PORT-1]); + if (cda[CTA_PROTO_DST_PORT-1]) + tuple->l4dst.udp.port = + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_DST_PORT-1]); +} + +int print_proto(char *buf, struct nfct_tuple *tuple) +{ + return (sprintf(buf, "sport=%u dport=%u ", htons(tuple->l4src.udp.port), + htons(tuple->l4dst.udp.port))); +} + +static struct nfct_proto udp = { + .name = "udp", + .protonum = IPPROTO_UDP, + .parse_proto = parse_proto, + .print_proto = print_proto, + .version = LIBNETFILTER_CONNTRACK_VERSION, +}; + +void __attribute__ ((constructor)) init(void); +void __attribute__ ((destructor)) fini(void); + +void init(void) +{ + nfct_register_proto(&udp); +} + +void fini(void) +{ + nfct_unregister_proto(&udp); +} diff --git a/include/Makefile.am b/include/Makefile.am index 9a3e71b..93416b9 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS = libnfnetlink_conntrack +SUBDIRS = libnetfilter_conntrack diff --git a/include/libnetfilter_conntrack/Makefile.am b/include/libnetfilter_conntrack/Makefile.am new file mode 100644 index 0000000..a6f4617 --- /dev/null +++ b/include/libnetfilter_conntrack/Makefile.am @@ -0,0 +1,2 @@ + +pkginclude_HEADERS = libnetfilter_conntrack.h diff --git a/include/libnetfilter_conntrack/libnfnetlink_conntrack.h b/include/libnetfilter_conntrack/libnfnetlink_conntrack.h new file mode 100644 index 0000000..954b3e2 --- /dev/null +++ b/include/libnetfilter_conntrack/libnfnetlink_conntrack.h @@ -0,0 +1,131 @@ +/* libctnetlink.h: Header file for the Connection Tracking library. + * + * Jay Schulist , Copyright (c) 2001. + * (C) 2002 by Harald Welte + * (C) 2005 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. + */ + +#ifndef __LIBCTNETLINK_H +#define __LIBCTNETLINK_H + +#include +#include +#include +#include +#include + +/* we need this for "enum ip_conntrack_status" */ +#include + +#include + +#define CTNL_BUFFSIZE 4096 + +union ctnl_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; +}; + +struct ctnl_tuple { + union { + u_int32_t v4; + u_int64_t v6; + } src; + + union { + u_int32_t v4; + u_int64_t v6; + } dst; + + u_int8_t protonum; + union ctnl_l4 l4src; + union ctnl_l4 l4dst; +}; + +union ctnl_protoinfo { + struct { + u_int8_t state; + } tcp; +}; + +struct ctnl_counters { + u_int64_t packets; + u_int64_t bytes; +}; + +struct ctnl_nat { + u_int32_t min_ip, max_ip; + union ctnl_l4 l4min, l4max; +}; + +#define CTNL_DIR_ORIGINAL 0 +#define CTNL_DIR_REPLY 1 +#define CTNL_DIR_MAX CTNL_DIR_REPLY+1 + +struct ctnl_conntrack { + struct ctnl_tuple tuple[CTNL_DIR_MAX]; + + unsigned long timeout; + unsigned long mark; + unsigned int status; + unsigned int use; + unsigned int id; + + union ctnl_protoinfo protoinfo; + struct ctnl_counters counters[CTNL_DIR_MAX]; + struct ctnl_nat nat; +}; + +struct ctnl_msg_handler { + int type; + int (*handler)(struct sockaddr_nl *, struct nlmsghdr *, void *arg); +}; + +struct ctnl_handle { + struct nfnl_handle nfnlh; + struct ctnl_msg_handler *handler[IPCTNL_MSG_MAX]; +}; + +extern int ctnl_open(struct ctnl_handle *, u_int8_t, unsigned); +extern int ctnl_close(struct ctnl_handle *); +extern int ctnl_unregister_handler(struct ctnl_handle *, int); +extern int ctnl_register_handler(struct ctnl_handle *, + struct ctnl_msg_handler *); +extern int ctnl_new_conntrack(struct ctnl_handle *, struct ctnl_conntrack *); +extern int ctnl_upd_conntrack(struct ctnl_handle *, struct ctnl_conntrack *); +extern int ctnl_get_conntrack(struct ctnl_handle *, struct ctnl_tuple *, int); +extern int ctnl_del_conntrack(struct ctnl_handle *, struct ctnl_tuple *, int); +extern int ctnl_list_conntrack(struct ctnl_handle *, int); +extern int ctnl_list_conntrack_zero_counters(struct ctnl_handle *, int); +extern int ctnl_event_conntrack(struct ctnl_handle *, int); +extern int ctnl_flush_conntrack(struct ctnl_handle *); + +extern int ctnl_new_expect(struct ctnl_handle *, struct ctnl_tuple *, + struct ctnl_tuple *, struct ctnl_tuple *, + unsigned long); +extern int ctnl_del_expect(struct ctnl_handle *,struct ctnl_tuple *); +extern int ctnl_get_expect(struct ctnl_handle *, struct ctnl_tuple *); +extern int ctnl_list_expect(struct ctnl_handle *, int); +extern int ctnl_event_expect(struct ctnl_handle *, int); +extern int ctnl_flush_expect(struct ctnl_handle *); + +extern int ctnl_send(struct ctnl_handle *, struct nlmsghdr *); +extern int ctnl_wilddump_request(struct ctnl_handle *, int , int); + +#endif /* __LIBCTNETLINK_H */ diff --git a/include/libnfnetlink_conntrack/Makefile.am b/include/libnfnetlink_conntrack/Makefile.am deleted file mode 100644 index 370255a..0000000 --- a/include/libnfnetlink_conntrack/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ - -pkginclude_HEADERS = libnfnetlink_conntrack.h - - -pkginclude_HEADERS = libnfnetlink_conntrack.h - diff --git a/include/libnfnetlink_conntrack/libnfnetlink_conntrack.h b/include/libnfnetlink_conntrack/libnfnetlink_conntrack.h deleted file mode 100644 index 954b3e2..0000000 --- a/include/libnfnetlink_conntrack/libnfnetlink_conntrack.h +++ /dev/null @@ -1,131 +0,0 @@ -/* libctnetlink.h: Header file for the Connection Tracking library. - * - * Jay Schulist , Copyright (c) 2001. - * (C) 2002 by Harald Welte - * (C) 2005 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. - */ - -#ifndef __LIBCTNETLINK_H -#define __LIBCTNETLINK_H - -#include -#include -#include -#include -#include - -/* we need this for "enum ip_conntrack_status" */ -#include - -#include - -#define CTNL_BUFFSIZE 4096 - -union ctnl_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; -}; - -struct ctnl_tuple { - union { - u_int32_t v4; - u_int64_t v6; - } src; - - union { - u_int32_t v4; - u_int64_t v6; - } dst; - - u_int8_t protonum; - union ctnl_l4 l4src; - union ctnl_l4 l4dst; -}; - -union ctnl_protoinfo { - struct { - u_int8_t state; - } tcp; -}; - -struct ctnl_counters { - u_int64_t packets; - u_int64_t bytes; -}; - -struct ctnl_nat { - u_int32_t min_ip, max_ip; - union ctnl_l4 l4min, l4max; -}; - -#define CTNL_DIR_ORIGINAL 0 -#define CTNL_DIR_REPLY 1 -#define CTNL_DIR_MAX CTNL_DIR_REPLY+1 - -struct ctnl_conntrack { - struct ctnl_tuple tuple[CTNL_DIR_MAX]; - - unsigned long timeout; - unsigned long mark; - unsigned int status; - unsigned int use; - unsigned int id; - - union ctnl_protoinfo protoinfo; - struct ctnl_counters counters[CTNL_DIR_MAX]; - struct ctnl_nat nat; -}; - -struct ctnl_msg_handler { - int type; - int (*handler)(struct sockaddr_nl *, struct nlmsghdr *, void *arg); -}; - -struct ctnl_handle { - struct nfnl_handle nfnlh; - struct ctnl_msg_handler *handler[IPCTNL_MSG_MAX]; -}; - -extern int ctnl_open(struct ctnl_handle *, u_int8_t, unsigned); -extern int ctnl_close(struct ctnl_handle *); -extern int ctnl_unregister_handler(struct ctnl_handle *, int); -extern int ctnl_register_handler(struct ctnl_handle *, - struct ctnl_msg_handler *); -extern int ctnl_new_conntrack(struct ctnl_handle *, struct ctnl_conntrack *); -extern int ctnl_upd_conntrack(struct ctnl_handle *, struct ctnl_conntrack *); -extern int ctnl_get_conntrack(struct ctnl_handle *, struct ctnl_tuple *, int); -extern int ctnl_del_conntrack(struct ctnl_handle *, struct ctnl_tuple *, int); -extern int ctnl_list_conntrack(struct ctnl_handle *, int); -extern int ctnl_list_conntrack_zero_counters(struct ctnl_handle *, int); -extern int ctnl_event_conntrack(struct ctnl_handle *, int); -extern int ctnl_flush_conntrack(struct ctnl_handle *); - -extern int ctnl_new_expect(struct ctnl_handle *, struct ctnl_tuple *, - struct ctnl_tuple *, struct ctnl_tuple *, - unsigned long); -extern int ctnl_del_expect(struct ctnl_handle *,struct ctnl_tuple *); -extern int ctnl_get_expect(struct ctnl_handle *, struct ctnl_tuple *); -extern int ctnl_list_expect(struct ctnl_handle *, int); -extern int ctnl_event_expect(struct ctnl_handle *, int); -extern int ctnl_flush_expect(struct ctnl_handle *); - -extern int ctnl_send(struct ctnl_handle *, struct nlmsghdr *); -extern int ctnl_wilddump_request(struct ctnl_handle *, int , int); - -#endif /* __LIBCTNETLINK_H */ diff --git a/include/linux_list.h b/include/linux_list.h new file mode 100644 index 0000000..57b56d7 --- /dev/null +++ b/include/linux_list.h @@ -0,0 +1,725 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* + * Check at compile time that something is of a particular type. + * Always evaluates to 1 so you may use it easily in comparisons. + */ +#define typecheck(type,x) \ +({ type __dummy; \ + typeof(x) __dummy2; \ + (void)(&__dummy == &__dummy2); \ + 1; \ +}) + +#define prefetch(x) 1 + +/* empty define to make this work in userspace -HW */ +#ifndef smp_wmb +#define smp_wmb() +#endif + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add_rcu(struct list_head * new, + struct list_head * prev, struct list_head * next) +{ + new->next = next; + new->prev = prev; + smp_wmb(); + next->prev = new; + prev->next = new; +} + +/** + * list_add_rcu - add a new entry to rcu-protected list + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_add_rcu() + * or list_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + */ +static inline void list_add_rcu(struct list_head *new, struct list_head *head) +{ + __list_add_rcu(new, head, head->next); +} + +/** + * list_add_tail_rcu - add a new entry to rcu-protected list + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_add_tail_rcu() + * or list_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + */ +static inline void list_add_tail_rcu(struct list_head *new, + struct list_head *head) +{ + __list_add_rcu(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_rcu - deletes entry from list without re-initialization + * @entry: the element to delete from the list. + * + * Note: list_empty on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_del_rcu() + * or list_add_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + * + * Note that the caller is not permitted to immediately free + * the newly deleted entry. Instead, either synchronize_kernel() + * or call_rcu() must be used to defer freeing until an RCU + * grace period has elapsed. + */ +static inline void list_del_rcu(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->prev = LIST_POISON2; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is + * empty _and_ checks that no other CPU might be + * in the process of still modifying either member + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + * + * @head: the list to test. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, prefetch(pos->next)) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ + pos = pos->prev, prefetch(pos->prev)) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + prefetch(pos->member.prev); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member), \ + prefetch(pos->member.prev)) + +/** + * list_prepare_entry - prepare a pos entry for use as a start point in + * list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - iterate over list of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_rcu - iterate over an rcu-protected list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_rcu(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next)) + +#define __list_for_each_rcu(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;})) + +/** + * list_for_each_safe_rcu - iterate over an rcu-protected list safe + * against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_safe_rcu(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next) + +/** + * list_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_entry_rcu(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + ({ smp_read_barrier_depends(); 0;}), \ + prefetch(pos->member.next)) + + +/** + * list_for_each_continue_rcu - iterate over an rcu-protected list + * continuing after existing point. + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_continue_rcu(pos, head) \ + for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \ + (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +/** + * hlist_del_rcu - deletes entry from hash list without re-initialization + * @n: the element to delete from the hash list. + * + * Note: list_unhashed() on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the hash list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry(). + */ +static inline void hlist_del_rcu(struct hlist_node *n) +{ + __hlist_del(n); + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (n->pprev) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +#define hlist_del_rcu_init hlist_del_init + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + + +/** + * hlist_add_head_rcu - adds the specified element to the specified hlist, + * while permitting racing traversals. + * @n: the element to add to the hash list. + * @h: the list to add to. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry(), but only if smp_read_barrier_depends() + * is used to prevent memory-consistency problems on Alpha CPUs. + * Regardless of the type of CPU, the list-traversal primitive + * must be guarded by rcu_read_lock(). + * + * OK, so why don't we have an hlist_for_each_entry_rcu()??? + */ +static inline void hlist_add_head_rcu(struct hlist_node *n, + struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + n->pprev = &h->first; + smp_wmb(); + if (first) + first->pprev = &n->next; + h->first = n; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +/** + * hlist_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as hlist_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define hlist_for_each_entry_rcu(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0; }) ) + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 599e4ba..64b7763 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,7 +6,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} AM_CFLAGS=-fPIC -Wall LIBS= -lib_LTLIBRARIES = libnfnetlink_conntrack.la +lib_LTLIBRARIES = libnetfilter_conntrack.la -libnfnetlink_conntrack_la_LDFLAGS = -Wc,-nostartfiles -libnfnetlink_conntrack_la_SOURCES = libnfnetlink_conntrack.c +libnetfilter_conntrack_la_LDFLAGS = -Wc,-nostartfiles +libnetfilter_conntrack_la_SOURCES = libnetfilter_conntrack.c diff --git a/src/libnetfilter_conntrack.c b/src/libnetfilter_conntrack.c new file mode 100644 index 0000000..3b130da --- /dev/null +++ b/src/libnetfilter_conntrack.c @@ -0,0 +1,994 @@ +/* + * (C) 2005 by Pablo Neira Ayuso + * Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include "linux_list.h" +#include +#include + +#define NFCT_BUFSIZE 4096 + +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] + +char *lib_dir = LIBNETFILTER_CONNTRACK_DIR; +struct list_head proto_list; +char *proto2str[IPPROTO_MAX] = { + [IPPROTO_TCP] = "tcp", + [IPPROTO_UDP] = "udp", + [IPPROTO_ICMP] = "icmp", + [IPPROTO_SCTP] = "sctp" +}; + +/* handler used for nfnl_listen */ +static int callback_handler(struct sockaddr_nl *nladdr, + struct nlmsghdr *n, void *arg) +{ + struct nfct_handle *cth = (struct nfct_handle *) arg; + int type = NFNL_MSG_TYPE(n->nlmsg_type); + struct nfct_msg_handler *hdlr = cth->handler[type]; + int ret; + + if (NFNL_SUBSYS_ID(n->nlmsg_type) != NFNL_SUBSYS_CTNETLINK && + NFNL_SUBSYS_ID(n->nlmsg_type) != NFNL_SUBSYS_CTNETLINK_EXP) { + nfnl_dump_packet(n, n->nlmsg_len, "callback_handler"); + return 0; + } + + if (!hdlr) + return 0; + + if (!hdlr->handler) + return 0; + + ret = hdlr->handler(nladdr, n, arg); + + return ret; +} + +struct nfct_handle *nfct_open(u_int8_t subsys_id, unsigned subscriptions) +{ + int err; + u_int8_t cb_count; + struct nfct_handle *cth; + + switch(subsys_id) { + case NFNL_SUBSYS_CTNETLINK: + cb_count = IPCTNL_MSG_MAX; + break; + case NFNL_SUBSYS_CTNETLINK_EXP: + cb_count = IPCTNL_MSG_EXP_MAX; + break; + default: + return NULL; + break; + } + cth = (struct nfct_handle *) + malloc(sizeof(struct nfct_handle)); + if (!cth) + return NULL; + + memset(cth, 0, sizeof(*cth)); + + err = nfnl_open(&cth->nfnlh, subsys_id, cb_count, subscriptions); + if (err < 0) + return NULL; + + return cth; +} + +int nfct_close(struct nfct_handle *cth) +{ + int err; + + err = nfnl_close(&cth->nfnlh); + free(cth); + + return err; +} + +void nfct_set_callback(struct nfct_handle *cth, + nfct_callback callback) +{ + cth->callback = callback; +} + +static int nfct_register_handler(struct nfct_handle *cth, + struct nfct_msg_handler *hndlr) +{ + if (hndlr->type >= IPCTNL_MSG_MAX) + return -EINVAL; + + cth->handler[hndlr->type] = hndlr; + + return 0; +} + +static void nfct_build_tuple_ip(struct nfnlhdr *req, int size, + struct nfct_tuple *t) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_IP); + + 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)); + + nfnl_nest_end(&req->nlh, nest); +} + +static void nfct_build_tuple_proto(struct nfnlhdr *req, int size, + 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_int16_t)); + + switch(t->protonum) { + case IPPROTO_TCP: + case IPPROTO_UDP: + 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)); + /* This is an ICMP echo */ + if (t->l4dst.icmp.type == 8) + nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_ID, + &t->l4src.icmp.id, sizeof(u_int16_t)); + break; + } + nfnl_nest_end(&req->nlh, nest); +} + +static void nfct_build_tuple(struct nfnlhdr *req, int size, + struct nfct_tuple *t, int type) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, type); + + nfct_build_tuple_ip(req, size, t); + nfct_build_tuple_proto(req, size, t); + + nfnl_nest_end(&req->nlh, nest); +} + +static void nfct_build_protoinfo(struct nfnlhdr *req, int size, + struct nfct_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO); + + switch (ct->tuple[NFCT_DIR_ORIGINAL].protonum) { + case IPPROTO_TCP: { + struct nfattr *nest_proto; + 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); + break; + } + default: + break; + } + + nfnl_nest_end(&req->nlh, nest); +} + +static void nfct_build_protonat(struct nfnlhdr *req, int size, + struct nfct_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT_PROTO); + + switch (ct->tuple[NFCT_DIR_ORIGINAL].protonum) { +#if 0 + case IPPROTO_TCP: + nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_TCP_MIN, + &ct->nat.l4min.tcp.port, sizeof(u_int16_t)); + nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_TCP_MAX, + &ct->nat.l4max.tcp.port, sizeof(u_int16_t)); + break; + case IPPROTO_UDP: + nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_UDP_MIN, + &ct->nat.l4min.udp.port, sizeof(u_int16_t)); + nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_UDP_MAX, + &ct->nat.l4max.udp.port, sizeof(u_int16_t)); + break; +#endif + } + nfnl_nest_end(&req->nlh, nest); +} + +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); + + nfnl_addattr_l(&req->nlh, size, CTA_NAT_MINIP, + &ct->nat.min_ip, sizeof(u_int32_t)); + + if (ct->nat.min_ip != ct->nat.max_ip) + nfnl_addattr_l(&req->nlh, size, CTA_NAT_MAXIP, + &ct->nat.max_ip, sizeof(u_int32_t)); + + if (ct->nat.l4min.all != ct->nat.l4max.all) + nfct_build_protonat(req, size, ct); + + nfnl_nest_end(&req->nlh, nest); +} + +static void nfct_build_conntrack(struct nfnlhdr *req, int size, + struct nfct_conntrack *ct) +{ + nfct_build_tuple(req, size, &ct->tuple[NFCT_DIR_ORIGINAL], + CTA_TUPLE_ORIG); + nfct_build_tuple(req, size, &ct->tuple[NFCT_DIR_REPLY], + CTA_TUPLE_REPLY); + + nfnl_addattr_l(&req->nlh, size, CTA_STATUS, &ct->status, + sizeof(unsigned int)); + nfnl_addattr_l(&req->nlh, size, CTA_TIMEOUT, &ct->timeout, + sizeof(unsigned long)); + + nfct_build_protoinfo(req, size, ct); + if (ct->nat.min_ip != 0) + nfct_build_nat(req, size, ct); +} + +void nfct_dump_tuple(struct nfct_tuple *tp) +{ + fprintf(stdout, "tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", + tp, tp->protonum, + NIPQUAD(tp->src.v4), ntohs(tp->l4src.all), + NIPQUAD(tp->dst.v4), ntohs(tp->l4dst.all)); +} + +static struct nfct_proto *findproto(char *name) +{ + struct list_head *i; + struct nfct_proto *cur = NULL, *handler = NULL; + + if (!name) + return handler; + + lib_dir = getenv("LIBNETFILTER_CONNTRACK_DIR"); + if (!lib_dir) + lib_dir = LIBNETFILTER_CONNTRACK_DIR; + + list_for_each(i, &proto_list) { + cur = (struct nfct_proto *) i; + if (strcmp(cur->name, name) == 0) { + handler = cur; + break; + } + } + + if (!handler) { + char path[sizeof("libnetfilter_conntrack_.so") + + strlen(name) + strlen(lib_dir)]; + sprintf(path, "%s/libnetfilter_conntrack_%s.so", lib_dir, name); + if (dlopen(path, RTLD_NOW)) + handler = findproto(name); + else + fprintf(stderr, "%s\n", dlerror()); + } + + return handler; +} + +static int print_status(char *buf, unsigned int status) +{ + int size = 0; + + if (status & IPS_ASSURED) + size = sprintf(buf, "[ASSURED] "); + if (!(status & IPS_SEEN_REPLY)) + size = sprintf(buf, "[UNREPLIED] "); + + return size; +} + +static void parse_ip(struct nfattr *attr, struct nfct_tuple *tuple) +{ + 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]); + + if (tb[CTA_IP_V4_DST-1]) + tuple->dst.v4 = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]); +} + +static void parse_proto(struct nfattr *attr, struct nfct_tuple *tuple) +{ + struct nfattr *tb[CTA_PROTO_MAX]; + struct nfct_proto *h; + + 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]); + + h = findproto(proto2str[tuple->protonum]); + if (h && h->parse_proto) + h->parse_proto(tb, tuple); +} + +static void parse_tuple(struct nfattr *attr, struct nfct_tuple *tuple) +{ + 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); + if (tb[CTA_TUPLE_PROTO-1]) + parse_proto(tb[CTA_TUPLE_PROTO-1], tuple); +} + +static void parse_protoinfo(struct nfattr *attr, struct nfct_conntrack *ct) +{ + struct nfattr *tb[CTA_PROTOINFO_MAX]; + struct nfct_proto *h; + + nfnl_parse_nested(tb,CTA_PROTOINFO_MAX, attr); + + h = findproto(proto2str[ct->tuple[NFCT_DIR_ORIGINAL].protonum]); + if (h && h->parse_protoinfo) + h->parse_protoinfo(tb, ct); +} + +static void nfct_parse_counters(struct nfattr *attr, + struct nfct_conntrack *ct, + enum ctattr_type parent) +{ + struct nfattr *tb[CTA_COUNTERS_MAX]; + int dir = (parent == CTA_COUNTERS_ORIG ? NFCT_DIR_REPLY + : NFCT_DIR_ORIGINAL); + + nfnl_parse_nested(tb, CTA_COUNTERS_MAX, attr); + if (tb[CTA_COUNTERS_PACKETS-1]) + ct->counters[dir].packets + = __be64_to_cpu(*(u_int64_t *) + NFA_DATA(tb[CTA_COUNTERS_PACKETS-1])); + if (tb[CTA_COUNTERS_BYTES-1]) + ct->counters[dir].bytes + = __be64_to_cpu(*(u_int64_t *) + NFA_DATA(tb[CTA_COUNTERS_BYTES-1])); + if (tb[CTA_COUNTERS32_PACKETS-1]) + ct->counters[dir].packets + = htonl(*(u_int32_t *) + NFA_DATA(tb[CTA_COUNTERS32_PACKETS-1])); + if (tb[CTA_COUNTERS32_BYTES-1]) + ct->counters[dir].bytes + = htonl(*(u_int32_t *) + NFA_DATA(tb[CTA_COUNTERS32_BYTES-1])); +} + +static int nfct_conntrack_netlink_handler(struct sockaddr_nl *sock, + struct nlmsghdr *nlh, void *arg) +{ + struct nfgenmsg *nfmsg; + int min_len = sizeof(struct nfgenmsg);; + struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + struct nfct_conntrack ct; + unsigned int flags = 0; + struct nfct_handle *cth = arg; + + memset(&ct, 0, sizeof(struct nfct_conntrack)); + + nfmsg = NLMSG_DATA(nlh); + + if (nlh->nlmsg_len < min_len) + return -EINVAL; + + while (NFA_OK(attr, attrlen)) { + switch(NFA_TYPE(attr)) { + case CTA_TUPLE_ORIG: + parse_tuple(attr, &ct.tuple[NFCT_DIR_ORIGINAL]); + break; + case CTA_TUPLE_REPLY: + parse_tuple(attr, &ct.tuple[NFCT_DIR_REPLY]); + break; + case CTA_STATUS: + ct.status = ntohl(*(u_int32_t *)NFA_DATA(attr)); + flags |= NFCT_STATUS; + break; + case CTA_PROTOINFO: + parse_protoinfo(attr, &ct); + flags |= NFCT_PROTOINFO; + break; + case CTA_TIMEOUT: + ct.timeout = ntohl(*(u_int32_t *)NFA_DATA(attr)); + flags |= NFCT_TIMEOUT; + break; + case CTA_MARK: + ct.mark = ntohl(*(u_int32_t *)NFA_DATA(attr)); + flags |= NFCT_MARK; + break; + case CTA_COUNTERS_ORIG: + case CTA_COUNTERS_REPLY: + nfct_parse_counters(attr, &ct, + NFA_TYPE(attr)-1); + flags |= NFCT_COUNTERS; + break; + case CTA_USE: + ct.use = ntohl(*(u_int32_t *)NFA_DATA(attr)); + flags |= NFCT_USE; + break; + case CTA_ID: + ct.id = ntohl(*(u_int32_t *)NFA_DATA(attr)); + flags |= NFCT_ID; + break; + default: + fprintf(stderr, "Unknown Attribute\n"); + break; + } + attr = NFA_NEXT(attr, attrlen); + } + if (cth->callback) + cth->callback((void *) &ct, flags); + + return 0; +} + +void nfct_default_conntrack_display(void *arg, unsigned int flags) +{ + struct nfct_conntrack *ct = arg; + struct nfct_proto *h = NULL; + char buf[512]; + int size = 0; + + size += sprintf(buf, "%-8s %u ", + proto2str[ct->tuple[NFCT_DIR_ORIGINAL].protonum] == NULL ? + "unknown" : proto2str[ct->tuple[NFCT_DIR_ORIGINAL].protonum], + ct->tuple[NFCT_DIR_ORIGINAL].protonum); + + if (flags & NFCT_TIMEOUT) + size += sprintf(buf+size, "%lu ", ct->timeout); + + h = findproto(proto2str[ct->tuple[NFCT_DIR_ORIGINAL].protonum]); + if ((flags & NFCT_PROTOINFO) && h && h->print_protoinfo) + size += h->print_protoinfo(buf+size, &ct->protoinfo); + + size += sprintf(buf+size, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(ct->tuple[NFCT_DIR_ORIGINAL].src.v4), + NIPQUAD(ct->tuple[NFCT_DIR_ORIGINAL].dst.v4)); + + if (h && h->print_proto) + size += h->print_proto(buf+size, &ct->tuple[NFCT_DIR_ORIGINAL]); + + if (flags & NFCT_COUNTERS) + size += printf(buf+size, "packets=%llu bytes=%llu ", + ct->counters[NFCT_DIR_ORIGINAL].packets, + ct->counters[NFCT_DIR_ORIGINAL].bytes); + + size += sprintf(buf+size, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(ct->tuple[NFCT_DIR_REPLY].src.v4), + NIPQUAD(ct->tuple[NFCT_DIR_REPLY].dst.v4)); + + h = findproto(proto2str[ct->tuple[NFCT_DIR_ORIGINAL].protonum]); + if (h && h->print_proto) + size += h->print_proto(buf+size, &ct->tuple[NFCT_DIR_REPLY]); + + if (flags & NFCT_COUNTERS) + size += sprintf(buf+size, "packets=%llu bytes=%llu ", + ct->counters[NFCT_DIR_REPLY].packets, + ct->counters[NFCT_DIR_REPLY].bytes); + + if (flags & NFCT_STATUS) + size += print_status(buf+size, ct->status); + + if (flags & NFCT_MARK) + size += sprintf(buf+size, "mark=%lu ", ct->mark); + if (flags & NFCT_USE) + size += sprintf(buf+size, "use=%u ", ct->use); + if (flags & NFCT_ID) + size += sprintf(buf+size, "id=%u ", ct->id); + + sprintf(buf+size, "\n"); + fprintf(stdout, buf); +} + +void nfct_default_expect_display(void *arg, unsigned int flags) +{ + struct nfct_expect *exp = arg; + char buf[256]; + int size = 0; + + size += sprintf(buf, "%ld proto=%d ", exp->timeout, exp->tuple.protonum); + size += sprintf(buf+size, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(exp->tuple.src.v4), + NIPQUAD(exp->tuple.dst.v4)); + size += sprintf(buf+size, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(exp->mask.src.v4), + NIPQUAD(exp->mask.dst.v4)); + size += sprintf(buf+size, "id=%u ", exp->id); + size += sprintf(buf, "\n"); + fprintf(stdout, buf); +} + +static char *typemsg2str(type, flags) +{ + char *ret = "[UNKNOWN]"; + + if (type == IPCTNL_MSG_CT_NEW) { + if (flags & NLM_F_CREATE) + ret = "[NEW]"; + else + ret = "[UPDATE]"; + } else if (type == IPCTNL_MSG_CT_DELETE) + ret = "[DESTROY]"; + + return ret; +} + +static int nfct_event_handler(struct sockaddr_nl *sock, + struct nlmsghdr *nlh, + void *arg) +{ + int type = NFNL_MSG_TYPE(nlh->nlmsg_type); + fprintf(stdout, "%9s ", typemsg2str(type, nlh->nlmsg_flags)); + return nfct_conntrack_netlink_handler(sock, nlh, arg); +} + +static int nfct_expect_netlink_handler(struct sockaddr_nl *sock, + struct nlmsghdr *nlh, void *arg) +{ + struct nfgenmsg *nfmsg; + struct nfct_handle *cth = arg; + int min_len = sizeof(struct nfgenmsg); + struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + struct nfct_expect exp; + + memset(&exp, 0, sizeof(struct nfct_expect)); + + nfmsg = NLMSG_DATA(nlh); + + if (nlh->nlmsg_len < min_len) + return -EINVAL; + + while (NFA_OK(attr, attrlen)) { + switch(NFA_TYPE(attr)) { + + case CTA_EXPECT_TUPLE: + parse_tuple(attr, &exp.tuple); + break; + case CTA_EXPECT_MASK: + parse_tuple(attr, &exp.mask); + break; + case CTA_EXPECT_TIMEOUT: + exp.timeout = htonl(*(unsigned long *) + NFA_DATA(attr)); + break; + case CTA_EXPECT_ID: + exp.id = htonl(*(u_int32_t *)NFA_DATA(attr)); + break; + } + attr = NFA_NEXT(attr, attrlen); + } + if (cth->callback) + cth->callback((void *)&exp, 0); + + return 0; +} + +static +int __nfct_create_conntrack(struct nfct_handle *cth, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + unsigned long timeout, + union nfct_protoinfo *proto, + unsigned int status, + struct nfct_nat *range) +{ + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + struct nfct_conntrack ct; + int ret; + + req = (void *) buf; + + memset(buf, 0, sizeof(buf)); + memset(&ct, 0, sizeof(struct nfct_conntrack)); + + ct.tuple[NFCT_DIR_ORIGINAL] = *orig; + ct.tuple[NFCT_DIR_REPLY] = *reply; + ct.timeout = htonl(timeout); + ct.status = htonl(status); + ct.protoinfo = *proto; + if (range) + ct.nat = *range; + + nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, 0, IPCTNL_MSG_CT_NEW, + NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK|NLM_F_EXCL); + + nfct_build_conntrack(req, sizeof(buf), &ct); + + if (nfnl_send(&cth->nfnlh, &req->nlh) < 0 ) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_create_conntrack(struct nfct_handle *cth, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + unsigned long timeout, + union nfct_protoinfo *proto, + unsigned int status) +{ + return(__nfct_create_conntrack(cth, orig, reply, timeout, + proto, status, NULL)); +} + +int nfct_create_conntrack_nat(struct nfct_handle *cth, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + unsigned long timeout, + union nfct_protoinfo *proto, + unsigned int status, + struct nfct_nat *nat) +{ + return(__nfct_create_conntrack(cth, orig, reply, timeout, + proto, status, nat)); +} + +int nfct_update_conntrack(struct nfct_handle *cth, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + unsigned long timeout, + union nfct_protoinfo *proto, + unsigned int status) +{ + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + struct nfct_conntrack ct; + int ret; + + req = (void *) &buf; + memset(&buf, 0, sizeof(buf)); + memset(&ct, 0, sizeof(struct nfct_conntrack)); + + ct.tuple[NFCT_DIR_ORIGINAL] = *orig; + ct.tuple[NFCT_DIR_REPLY] = *reply; + ct.timeout = htonl(timeout); + ct.status = htonl(status); + ct.protoinfo = *proto; + + nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, 0, IPCTNL_MSG_CT_NEW, + NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK); + + nfct_build_conntrack(req, sizeof(buf), &ct); + + if (nfnl_send(&cth->nfnlh, &req->nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_delete_conntrack(struct nfct_handle *cth,struct nfct_tuple *tuple, int dir) +{ + int ret; + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + int type = dir ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, + AF_INET, 0, IPCTNL_MSG_CT_DELETE, + NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK); + + nfct_build_tuple(req, sizeof(buf), tuple, type); + + if (nfnl_send(&cth->nfnlh, &req->nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +/* get_conntrack_handler */ +int nfct_get_conntrack(struct nfct_handle *cth,struct nfct_tuple *tuple, int dir) +{ + int ret; + struct nfnlhdr *req; + struct nfct_msg_handler h = { + .type = 0, + .handler = nfct_conntrack_netlink_handler + }; + char buf[NFCT_BUFSIZE]; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfct_build_tuple(req, sizeof(buf), tuple, dir); + + nfct_register_handler(cth, &h); + nfct_build_tuple(req, sizeof(buf), tuple, dir); + + if (nfnl_send(&cth->nfnlh, &req->nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +static int __nfct_dump_conntrack_table(struct nfct_handle *cth,int zero) +{ + int ret, msg; + struct nfct_msg_handler h = { + .type = IPCTNL_MSG_CT_NEW, /* Hm... really? */ + .handler = nfct_conntrack_netlink_handler + }; + struct nfnlhdr req; + + nfct_register_handler(cth, &h); + + if (zero) + msg = IPCTNL_MSG_CT_GET_CTRZERO; + else + msg = IPCTNL_MSG_CT_GET; + + nfnl_fill_hdr(&cth->nfnlh, &req.nlh, 0, AF_INET, 0, + msg, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST); + + if (nfnl_send(&cth->nfnlh, &req.nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_dump_conntrack_table(struct nfct_handle *cth) +{ + return(__nfct_dump_conntrack_table(cth, 0)); +} + +int nfct_dump_conntrack_table_zero(struct nfct_handle *cth) +{ + return(__nfct_dump_conntrack_table(cth, 1)); +} + +int nfct_event_conntrack(struct nfct_handle *cth) +{ + struct nfct_msg_handler hnew = { + .type = IPCTNL_MSG_CT_NEW, + .handler = nfct_event_handler + }; + struct nfct_msg_handler hdestroy = { + .type = IPCTNL_MSG_CT_DELETE, + .handler = nfct_event_handler + }; + int ret; + + nfct_register_handler(cth, &hnew); + nfct_register_handler(cth, &hdestroy); + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return 0; +} + +void nfct_register_proto(struct nfct_proto *h) +{ + if (strcmp(h->version, LIBNETFILTER_CONNTRACK_VERSION) != 0) { + fprintf(stderr, "plugin `%s': version %s (I'm %s)\n", + h->name, h->version, LIBNETFILTER_CONNTRACK_VERSION); + exit(1); + } + list_add(&h->head, &proto_list); +} + +void nfct_unregister_proto(struct nfct_proto *h) +{ + list_del(&h->head); +} + +int nfct_dump_expect_list(struct nfct_handle *cth) +{ + struct nfct_msg_handler h = { + .type = IPCTNL_MSG_EXP_NEW, + .handler = nfct_expect_netlink_handler + }; + int ret; + struct nfnlhdr req; + + nfct_register_handler(cth, &h); + + nfnl_fill_hdr(&cth->nfnlh, &req.nlh, 0, AF_INET, 0, + IPCTNL_MSG_EXP_GET, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST); + + if (nfnl_send(&cth->nfnlh, &req.nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_flush_conntrack_table(struct nfct_handle *cth) +{ + int ret; + struct nfnlhdr *req; + char buf[sizeof(*req)]; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf, + 0, AF_INET, 0, IPCTNL_MSG_CT_DELETE, + NLM_F_REQUEST|NLM_F_ACK); + + if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_get_expectation(struct nfct_handle *cth,struct nfct_tuple *tuple) +{ + struct nfct_msg_handler h = { + .type = IPCTNL_MSG_EXP_NEW, + .handler = nfct_expect_netlink_handler + }; + int ret; + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, 0, IPCTNL_MSG_EXP_GET, + NLM_F_REQUEST|NLM_F_ACK); + + nfct_register_handler(cth, &h); + nfct_build_tuple(req, sizeof(buf), tuple, CTA_EXPECT_MASTER); + + if (nfnl_send(&cth->nfnlh, &req->nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_create_expectation(struct nfct_handle *cth,struct nfct_tuple *master, + struct nfct_tuple *tuple, + struct nfct_tuple *mask, + unsigned long timeout) +{ + int ret; + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + req = (void *) &buf; + + memset(&buf, 0, sizeof(buf)); + + nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, 0, IPCTNL_MSG_EXP_NEW, + NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK); + + nfct_build_tuple(req, sizeof(buf), master, CTA_EXPECT_MASTER); + nfct_build_tuple(req, sizeof(buf), tuple, CTA_EXPECT_TUPLE); + nfct_build_tuple(req, sizeof(buf), mask, CTA_EXPECT_MASK); + + if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_EXPECT_TIMEOUT, &timeout, + sizeof(timeout)) < 0) + return -1; + + if (nfnl_send(&cth->nfnlh, &req->nlh) < 0 ) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_delete_expectation(struct nfct_handle *cth,struct nfct_tuple *tuple) +{ + int ret; + struct nfnlhdr *req; + char buf[NFCT_BUFSIZE]; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, + 0, IPCTNL_MSG_EXP_DELETE, + NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK); + + nfct_build_tuple(req, sizeof(buf), tuple, CTA_EXPECT_MASTER); + + if (nfnl_send(&cth->nfnlh, &req->nlh) < 0) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_event_expectation(struct nfct_handle *cth) +{ + struct nfct_msg_handler hnew = { + .type = IPCTNL_MSG_EXP_NEW, + .handler = nfct_expect_netlink_handler + }; + struct nfct_msg_handler hdestroy = { + .type = IPCTNL_MSG_EXP_DELETE, + .handler = nfct_expect_netlink_handler + }; + int ret; + + nfct_register_handler(cth, &hnew); + nfct_register_handler(cth, &hdestroy); + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} + +int nfct_flush_expectation_table(struct nfct_handle *cth) +{ + int ret; + struct nfnlhdr *req; + char buf[sizeof(*req)]; + + memset(&buf, 0, sizeof(buf)); + req = (void *) &buf; + + nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf, + 0, AF_INET, 0, IPCTNL_MSG_EXP_DELETE, + NLM_F_REQUEST|NLM_F_ACK); + + if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) + return -1; + + ret = nfnl_listen(&cth->nfnlh, &callback_handler, cth); + + return ret; +} diff --git a/src/libnfnetlink_conntrack.c b/src/libnfnetlink_conntrack.c deleted file mode 100644 index 098505f..0000000 --- a/src/libnfnetlink_conntrack.c +++ /dev/null @@ -1,579 +0,0 @@ -/* libctnetlink.c: generic library for access to connection tracking. - * - * (C) 2001 by Jay Schulist - * (C) 2002-2005 by Harald Welte - * (C) 2005 by Pablo Neira Ayuso - * - * Development of this code funded by Astaro AG (http://www.astaro.com) - * - * this software may be used and distributed according to the terms - * of the gnu general public license, incorporated herein by reference. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define ctnl_error(format, args...) fprintf(stderr, format, ## args) - -struct nfnlhdr { - struct nlmsghdr nlh; - struct nfgenmsg nfmsg; -}; - -/*********************************************************************** - * low level stuff - ***********************************************************************/ -int ctnl_send(struct ctnl_handle *cth, struct nlmsghdr *n) -{ - return nfnl_send(&cth->nfnlh, n); -} - -int ctnl_wilddump_request(struct ctnl_handle *cth, int family, int type) -{ - struct nfnlhdr req; - - nfnl_fill_hdr(&cth->nfnlh, &req.nlh, 0, AF_INET, 0, - type, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST); - - return nfnl_send(&cth->nfnlh, &req.nlh); -} - -/* handler used for nfnl_listen */ -static int callback_handler(struct sockaddr_nl *nladdr, - struct nlmsghdr *n, void *arg) -{ - struct ctnl_handle *cth = (struct ctnl_handle *) arg; - int type = NFNL_MSG_TYPE(n->nlmsg_type); - struct ctnl_msg_handler *hdlr = cth->handler[type]; - int ret; - - if (NFNL_SUBSYS_ID(n->nlmsg_type) != NFNL_SUBSYS_CTNETLINK && - NFNL_SUBSYS_ID(n->nlmsg_type) != NFNL_SUBSYS_CTNETLINK_EXP) { - ctnl_error("received message for wrong subsys, skipping\n"); - nfnl_dump_packet(n, n->nlmsg_len, "callback_handler"); - return 0; - } - - if (!hdlr) { - ctnl_error("no handler for type %d\n", type); - return 0; - } - - if (!hdlr->handler) { - ctnl_error("no handler function for type %d\n", type); - return 0; - } - - ret = hdlr->handler(nladdr, n, arg); - - return ret; -} - -/*********************************************************************** - * high level stuff - ***********************************************************************/ - -/** - * ctnl_open - open a libctnetlink handle - * - * cth: pointer to already allocated library handle - * subsys_id: ID of the subsystem - * subscriptions: netlink groups we are interested in - */ -int ctnl_open(struct ctnl_handle *cth, u_int8_t subsys_id, - unsigned subscriptions) -{ - int err; - u_int8_t cb_count; - - switch(subsys_id) { - case NFNL_SUBSYS_CTNETLINK: - cb_count = IPCTNL_MSG_MAX; - break; - case NFNL_SUBSYS_CTNETLINK_EXP: - cb_count = IPCTNL_MSG_EXP_MAX; - break; - default: - return -ENOENT; - break; - } - memset(cth, 0, sizeof(*cth)); - - err = nfnl_open(&cth->nfnlh, subsys_id, cb_count, subscriptions); - if (err < 0) { - return err; - } - - return 0; -} - -/** - * ctnl_close - close a libctnetlink handle - * - * cth: libctnetlink handle - */ -int ctnl_close(struct ctnl_handle *cth) -{ - int err; - - err = nfnl_close(&cth->nfnlh); - - return err; -} - -/* ctnl_register_handler - register handler for ctnetlink mesage type - * - * cth: libctnetlink handle - * hndlr: handler structure - */ -int ctnl_register_handler(struct ctnl_handle *cth, - struct ctnl_msg_handler *hndlr) -{ - if (hndlr->type >= IPCTNL_MSG_MAX) - return -EINVAL; - - cth->handler[hndlr->type] = hndlr; - - return 0; -} - -/** - * ctnl_unregister_handler - unregister handler for ctnetlink msgtype - * - * cth: libctnetlink handle - * type: message type - */ -int ctnl_unregister_handler(struct ctnl_handle *cth, int type) -{ - if (type >= IPCTNL_MSG_MAX) - return -EINVAL; - - cth->handler[type] = NULL; - return 0; -} - -int ctnl_flush_conntrack(struct ctnl_handle *cth) -{ - struct nfnlhdr *req; - char buf[sizeof(*req)]; - - memset(&buf, 0, sizeof(buf)); - req = (void *) &buf; - - nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf, - 0, AF_INET, 0, IPCTNL_MSG_CT_DELETE, - NLM_F_REQUEST|NLM_F_ACK); - - if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) - return -1; - - return nfnl_listen(&cth->nfnlh, &callback_handler, cth); -} - -/** - * ctnl_list_conntrack - list connection tracking table - * cth: libctnetlink handle - * family: AF_INET, ... - */ -int ctnl_list_conntrack(struct ctnl_handle *cth, int family) -{ - if (ctnl_wilddump_request(cth, family, IPCTNL_MSG_CT_GET) < 0) - return -1; - - return nfnl_listen(&cth->nfnlh, &callback_handler, cth); -} - -int ctnl_list_conntrack_zero_counters(struct ctnl_handle *cth, int family) -{ - if (ctnl_wilddump_request(cth, family, IPCTNL_MSG_CT_GET_CTRZERO) < 0) - return -1; - - return nfnl_listen(&cth->nfnlh, &callback_handler, cth); -} - -int ctnl_event_conntrack(struct ctnl_handle *cth, int family) -{ - return nfnl_listen(&cth->nfnlh, &callback_handler, cth); -} - -static void ctnl_build_tuple_ip(struct nfnlhdr *req, int size, - struct ctnl_tuple *t) -{ - struct nfattr *nest; - - nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_IP); - - 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)); - - nfnl_nest_end(&req->nlh, nest); -} - -static void ctnl_build_tuple_proto(struct nfnlhdr *req, int size, - struct ctnl_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_int16_t)); - - switch(t->protonum) { - case IPPROTO_TCP: - case IPPROTO_UDP: - 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)); - /* This is an ICMP echo */ - if (t->l4dst.icmp.type == 8) - nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_ID, - &t->l4src.icmp.id, sizeof(u_int16_t)); - break; - } - nfnl_nest_end(&req->nlh, nest); -} - -static void ctnl_build_tuple(struct nfnlhdr *req, int size, - struct ctnl_tuple *t, int type) -{ - struct nfattr *nest; - - nest = nfnl_nest(&req->nlh, size, type); - - ctnl_build_tuple_ip(req, size, t); - ctnl_build_tuple_proto(req, size, t); - - nfnl_nest_end(&req->nlh, nest); -} - -static void ctnl_build_protoinfo(struct nfnlhdr *req, int size, - struct ctnl_conntrack *ct) -{ - struct nfattr *nest; - - nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO); - - switch (ct->tuple[CTNL_DIR_ORIGINAL].protonum) { - case IPPROTO_TCP: { - struct nfattr *nest_proto; - 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); - break; - } - default: - break; - } - - nfnl_nest_end(&req->nlh, nest); -} - -static void ctnl_build_protonat(struct nfnlhdr *req, int size, - struct ctnl_conntrack *ct) -{ - struct nfattr *nest; - - nest = nfnl_nest(&req->nlh, size, CTA_NAT_PROTO); - - switch (ct->tuple[CTNL_DIR_ORIGINAL].protonum) { -#if 0 - case IPPROTO_TCP: - nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_TCP_MIN, - &ct->nat.l4min.tcp.port, sizeof(u_int16_t)); - nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_TCP_MAX, - &ct->nat.l4max.tcp.port, sizeof(u_int16_t)); - break; - case IPPROTO_UDP: - nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_UDP_MIN, - &ct->nat.l4min.udp.port, sizeof(u_int16_t)); - nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_UDP_MAX, - &ct->nat.l4max.udp.port, sizeof(u_int16_t)); - break; -#endif - } - nfnl_nest_end(&req->nlh, nest); -} - -static void ctnl_build_nat(struct nfnlhdr *req, int size, - struct ctnl_conntrack *ct) -{ - struct nfattr *nest; - - 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)); - - if (ct->nat.min_ip != ct->nat.max_ip) - nfnl_addattr_l(&req->nlh, size, CTA_NAT_MAXIP, - &ct->nat.max_ip, sizeof(u_int32_t)); - - if (ct->nat.l4min.all != ct->nat.l4max.all) - ctnl_build_protonat(req, size, ct); - - nfnl_nest_end(&req->nlh, nest); -} - -static void ctnl_build_conntrack(struct nfnlhdr *req, int size, - struct ctnl_conntrack *ct) -{ - ctnl_build_tuple(req, size, &ct->tuple[CTNL_DIR_ORIGINAL], - CTA_TUPLE_ORIG); - ctnl_build_tuple(req, size, &ct->tuple[CTNL_DIR_REPLY], - CTA_TUPLE_REPLY); - - nfnl_addattr_l(&req->nlh, size, CTA_STATUS, &ct->status, - sizeof(unsigned int)); - nfnl_addattr_l(&req->nlh, size, CTA_TIMEOUT, &ct->timeout, - sizeof(unsigned long)); - - ctnl_build_protoinfo(req, size, ct); - if (ct->nat.min_ip != 0) - ctnl_build_nat(req, size, ct); -} - -/** - * ctnl_get_conntrack - get a connection from conntrack hashtable - * cth: libctnetlink handle - * t: tuple of connection to get - * cb: a struct nfattr to put the connection in - */ -int ctnl_get_conntrack(struct ctnl_handle *cth, - struct ctnl_tuple *tuple, - int dir) -{ - struct nfnlhdr *req; - char buf[CTNL_BUFFSIZE]; - - memset(&buf, 0, sizeof(buf)); - req = (void *) &buf; - - nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf, - 0, AF_INET, 0, IPCTNL_MSG_CT_GET, - NLM_F_REQUEST|NLM_F_ACK); - - ctnl_build_tuple(req, sizeof(buf), tuple, dir); - - if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0) - return -1; - - return nfnl_listen(&cth->nfnlh, &callback_handler, cth); -} - -/** - * ctnl_del_conntrack - delete a connection from conntrack hashtable - * cth: libctnetlink handle - * t: tuple of to-be-deleted connection - */ -int ctnl_del_conntrack(struct ctnl_handle *cth, - struct ctnl_tuple *tuple, - int dir) -{ - struct nfnlhdr *req; - char buf[CTNL_BUFFSIZE]; - int type = dir ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG; - - memset(&buf, 0, sizeof(buf)); - req = (void *) &buf; - - nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf, - 0, AF_INET, 0, IPCTNL_MSG_CT_DELETE, - NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK); - - ctnl_build_tuple(req, sizeof(buf), tuple, type); - - if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0) - return -1; - - return nfnl_listen(&cth->nfnlh, &callback_handler, cth); -} -static int new_update_conntrack(struct ctnl_handle *cth, - struct ctnl_conntrack *ct, - u_int16_t msg_flags) -{ - struct nfnlhdr *req; - char buf[CTNL_BUFFSIZE]; - - memset(&buf, 0, sizeof(buf)); - req = (void *) &buf; - - nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf, - 0, AF_INET, 0, IPCTNL_MSG_CT_NEW, - NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK|msg_flags); - - ctnl_build_conntrack(req, sizeof(buf), ct); - - if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) - return -1; - - return nfnl_listen(&cth->nfnlh, &callback_handler, cth); -} - -/** - * ctnl_new_conntrack - create a connection in the conntrack hashtable - * cth: libctnetlink handle - * t: tuple of to-be-created connection - */ -int ctnl_new_conntrack(struct ctnl_handle *cth, struct ctnl_conntrack *ct) -{ - return new_update_conntrack(cth, ct, NLM_F_EXCL); -} - -int ctnl_upd_conntrack(struct ctnl_handle *cth, struct ctnl_conntrack *ct) -{ - return new_update_conntrack(cth, ct, 0); -} - -/** - * ctnl_list_expect - retrieve a list of expectations from conntrack subsys - * cth: libctnetlink handle - * family: AF_INET, ... - */ -int ctnl_list_expect(struct ctnl_handle *cth, int family) -{ - if (ctnl_wilddump_request(cth, family, IPCTNL_MSG_EXP_GET) < 0) - return -1; - - return nfnl_listen(&cth->nfnlh, &callback_handler, cth); - -} - -int ctnl_event_expect(struct ctnl_handle *cth, int family) -{ - return nfnl_listen(&cth->nfnlh, &callback_handler, cth); -} - -int ctnl_flush_expect(struct ctnl_handle *cth) -{ - struct nfnlhdr *req; - char buf[sizeof(*req)]; - - memset(&buf, 0, sizeof(buf)); - req = (void *) &buf; - - nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf, - 0, AF_INET, 0, IPCTNL_MSG_EXP_DELETE, - NLM_F_REQUEST|NLM_F_ACK); - - if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) - return -1; - - return nfnl_listen(&cth->nfnlh, &callback_handler, cth); -} - -/** - * ctnl_new_expect - create a new expectation - * - * cth: libctnetlink handle - * master_tuple: tuple of the master original direction - * t: direction, original or reply. - * exp_tuple: tuple of to-be-created expectation - * mask: mask of to-be-created expectation - * timeout: timeout of new expectation - */ -int ctnl_new_expect(struct ctnl_handle *cth, - struct ctnl_tuple *master, - struct ctnl_tuple *tuple, - struct ctnl_tuple *mask, - unsigned long timeout) -{ - struct nfnlhdr *req; - char buf[CTNL_BUFFSIZE]; - - memset(&buf, 0, sizeof(buf)); - req = (void *) &buf; - - nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf, - 0, AF_INET, 0, IPCTNL_MSG_EXP_NEW, - NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK); - - ctnl_build_tuple(req, sizeof(buf), master, CTA_EXPECT_MASTER); - ctnl_build_tuple(req, sizeof(buf), tuple, CTA_EXPECT_TUPLE); - ctnl_build_tuple(req, sizeof(buf), mask, CTA_EXPECT_MASK); - - if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_EXPECT_TIMEOUT, &timeout, - sizeof(timeout)) < 0) - return -1; - - if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) - return -1; - - return nfnl_listen(&cth->nfnlh, &callback_handler, cth); -} - -/** - * ctnl_del_expect - delete an expectation from conntrack subsystem - * - * cth: libctnetlink handle - * t: tuple of to-be-deleted expectation - */ -int ctnl_del_expect(struct ctnl_handle *cth, - struct ctnl_tuple *tuple) -{ - struct nfnlhdr *req; - char buf[CTNL_BUFFSIZE]; - - memset(&buf, 0, sizeof(buf)); - req = (void *) &buf; - - nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf, - 0, AF_INET, 0, IPCTNL_MSG_EXP_DELETE, - NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK); - - ctnl_build_tuple(req, sizeof(buf), tuple, CTA_EXPECT_MASTER); - - if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0) - return -1; - - return nfnl_listen(&cth->nfnlh, &callback_handler, cth); -} - -int ctnl_get_expect(struct ctnl_handle *cth, - struct ctnl_tuple *tuple) -{ - struct nfnlhdr *req; - char buf[CTNL_BUFFSIZE]; - - memset(&buf, 0, sizeof(buf)); - req = (void *) &buf; - - nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf, - 0, AF_INET, 0, IPCTNL_MSG_EXP_GET, - NLM_F_REQUEST|NLM_F_ACK); - - ctnl_build_tuple(req, sizeof(buf), tuple, CTA_EXPECT_MASTER); - - if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) - return -1; - - return nfnl_listen(&cth->nfnlh, &callback_handler, cth); -} - -- cgit v1.2.3