summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--configure.in9
-rw-r--r--extensions/Makefile.am16
-rw-r--r--extensions/libnetfilter_conntrack_icmp.c65
-rw-r--r--extensions/libnetfilter_conntrack_sctp.c69
-rw-r--r--extensions/libnetfilter_conntrack_tcp.c84
-rw-r--r--extensions/libnetfilter_conntrack_udp.c53
-rw-r--r--include/Makefile.am2
-rw-r--r--include/libnetfilter_conntrack/Makefile.am2
-rw-r--r--include/libnetfilter_conntrack/libnfnetlink_conntrack.h (renamed from include/libnfnetlink_conntrack/libnfnetlink_conntrack.h)0
-rw-r--r--include/libnfnetlink_conntrack/Makefile.am6
-rw-r--r--include/linux_list.h725
-rw-r--r--src/Makefile.am6
-rw-r--r--src/libnetfilter_conntrack.c994
-rw-r--r--src/libnfnetlink_conntrack.c579
15 files changed, 2020 insertions, 592 deletions
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 <pablo@netfilter.org>
+ *
+ * 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 <stdio.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h> /* For htons */
+#include <linux/netfilter/nfnetlink_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+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 <pablo@netfilter.org>
+ *
+ * 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 <stdio.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h> /* For htons */
+#include <linux/netfilter/nfnetlink_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+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 <pablo@netfilter.org>
+ *
+ * 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 <stdio.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h> /* For htons */
+#include <linux/netfilter/nfnetlink_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+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 <pablo@netfilter.org>
+ *
+ * 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 <stdio.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h> /* For htons */
+#include <linux/netfilter/nfnetlink_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+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/libnfnetlink_conntrack/libnfnetlink_conntrack.h b/include/libnetfilter_conntrack/libnfnetlink_conntrack.h
index 954b3e2..954b3e2 100644
--- a/include/libnfnetlink_conntrack/libnfnetlink_conntrack.h
+++ b/include/libnetfilter_conntrack/libnfnetlink_conntrack.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/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 <pablo@netfilter.org>
+ * Harald Welte <laforge@netfilter.org>
+ *
+ * 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 <stdio.h>
+#include <getopt.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include "linux_list.h"
+#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+#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 <jschlst@samba.org>
- * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
- * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-#include <errno.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <asm/types.h>
-#include <linux/if.h>
-#include <linux/netlink.h>
-#include <linux/netfilter/nfnetlink_conntrack.h>
-
-#include <libnfnetlink/libnfnetlink.h>
-#include <libnfnetlink_conntrack/libnfnetlink_conntrack.h>
-
-#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);
-}
-