From 0a6f6cedb730df9280f99ee1acd007f9e5b971aa 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"
 </C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org>
Date: Tue, 25 Oct 2005 00:04:34 +0000
Subject: See ChangeLog

---
 autogen.sh | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100755 autogen.sh

(limited to 'autogen.sh')

diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..2e2a638
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+run ()
+{
+    echo "running: $*"
+    eval $*
+
+    if test $? != 0 ; then
+	echo "error: while running '$*'"
+	exit 1
+    fi
+}
+
+run aclocal
+run libtoolize -f
+run autoheader
+run automake -a
+run autoconf
-- 
cgit v1.2.3


From 3da97ea51d5f2b6ec6911b6ad370a6d09cfa940c 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"
 </C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org>
Date: Tue, 23 Jan 2007 13:06:05 +0000
Subject: comment `autoheader' invocation from autogen.sh, we don't need any
 config.h file to compile the conntrack tool

---
 autogen.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'autogen.sh')

diff --git a/autogen.sh b/autogen.sh
index 2e2a638..e76d3ef 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -13,6 +13,6 @@ run ()
 
 run aclocal
 run libtoolize -f
-run autoheader
+#run autoheader
 run automake -a
 run autoconf
-- 
cgit v1.2.3


From ad31f852c3454136bdbfeb7f222cb9c175f13c1c Mon Sep 17 00:00:00 2001
From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org"
 </C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org>
Date: Mon, 16 Apr 2007 17:55:00 +0000
Subject: initial import of the conntrack daemon to Netfilter SVN

---
 AUTHORS                                            |    2 -
 ChangeLog                                          |  243 -----
 INSTALL                                            |  229 ----
 Make_global.am                                     |    1 -
 Makefile.am                                        |   21 -
 README                                             |   17 +
 autogen.sh                                         |   18 -
 cli/AUTHORS                                        |    2 +
 cli/ChangeLog                                      |  243 +++++
 cli/INSTALL                                        |  229 ++++
 cli/Make_global.am                                 |    1 +
 cli/Makefile.am                                    |   21 +
 cli/autogen.sh                                     |   18 +
 cli/configure.in                                   |   72 ++
 cli/conntrack.8                                    |  142 +++
 cli/extensions/Makefile.am                         |   16 +
 cli/extensions/libct_proto_icmp.c                  |  108 ++
 cli/extensions/libct_proto_icmp.man                |   10 +
 cli/extensions/libct_proto_sctp.c                  |  164 +++
 cli/extensions/libct_proto_tcp.c                   |  180 ++++
 cli/extensions/libct_proto_tcp.man                 |   16 +
 cli/extensions/libct_proto_udp.c                   |  141 +++
 cli/extensions/libct_proto_udp.man                 |   13 +
 cli/include/Makefile.am                            |    2 +
 cli/include/conntrack.h                            |  160 +++
 cli/include/linux_list.h                           |  725 +++++++++++++
 cli/src/Makefile.am                                |    7 +
 cli/src/conntrack.c                                | 1131 ++++++++++++++++++++
 cli/test.sh                                        |  110 ++
 configure.in                                       |   72 --
 conntrack.8                                        |  142 ---
 daemon/AUTHORS                                     |    1 +
 daemon/CHANGELOG                                   |  184 ++++
 daemon/CONTRIBUTORS                                |    3 +
 daemon/INSTALL                                     |  199 ++++
 daemon/Make_global.am                              |    1 +
 daemon/Makefile.am                                 |   21 +
 daemon/TODO                                        |   18 +
 daemon/autogen.sh                                  |   18 +
 daemon/configure.in                                |  106 ++
 daemon/examples/Makefile.am                        |    1 +
 daemon/examples/debian.conntrackd.init.d           |   48 +
 daemon/examples/stats/Makefile.am                  |    1 +
 daemon/examples/stats/conntrackd.conf              |   69 ++
 daemon/examples/sync/Makefile.am                   |    1 +
 daemon/examples/sync/nack/Makefile.am              |    2 +
 daemon/examples/sync/nack/README                   |    1 +
 daemon/examples/sync/nack/node1/Makefile.am        |    1 +
 daemon/examples/sync/nack/node1/conntrackd.conf    |  125 +++
 daemon/examples/sync/nack/node1/keepalived.conf    |   38 +
 daemon/examples/sync/nack/node2/Makefile.am        |    1 +
 daemon/examples/sync/nack/node2/conntrackd.conf    |  124 +++
 daemon/examples/sync/nack/node2/keepalived.conf    |   38 +
 daemon/examples/sync/nack/script_backup.sh         |    3 +
 daemon/examples/sync/nack/script_master.sh         |    5 +
 daemon/examples/sync/persistent/Makefile.am        |    2 +
 daemon/examples/sync/persistent/README             |    1 +
 daemon/examples/sync/persistent/node1/Makefile.am  |    1 +
 .../examples/sync/persistent/node1/conntrackd.conf |  130 +++
 .../examples/sync/persistent/node1/keepalived.conf |   38 +
 daemon/examples/sync/persistent/node2/Makefile.am  |    1 +
 .../examples/sync/persistent/node2/conntrackd.conf |  130 +++
 .../examples/sync/persistent/node2/keepalived.conf |   38 +
 daemon/examples/sync/persistent/script_backup.sh   |    3 +
 daemon/examples/sync/persistent/script_master.sh   |    4 +
 daemon/include/Makefile.am                         |    5 +
 daemon/include/alarm.h                             |   13 +
 daemon/include/buffer.h                            |   32 +
 daemon/include/cache.h                             |   92 ++
 daemon/include/conntrackd.h                        |  174 +++
 daemon/include/debug.h                             |   53 +
 daemon/include/hash.h                              |   47 +
 daemon/include/ignore.h                            |   12 +
 daemon/include/jhash.h                             |  146 +++
 daemon/include/linux_list.h                        |  725 +++++++++++++
 daemon/include/local.h                             |   29 +
 daemon/include/log.h                               |   10 +
 daemon/include/mcast.h                             |   48 +
 daemon/include/network.h                           |   34 +
 daemon/include/slist.h                             |   41 +
 daemon/include/state_helper.h                      |   20 +
 daemon/include/sync.h                              |   23 +
 daemon/include/us-conntrack.h                      |   13 +
 daemon/src/Makefile.am                             |   22 +
 daemon/src/alarm.c                                 |  141 +++
 daemon/src/buffer.c                                |  136 +++
 daemon/src/cache.c                                 |  446 ++++++++
 daemon/src/cache_iterators.c                       |  229 ++++
 daemon/src/cache_lifetime.c                        |   65 ++
 daemon/src/cache_timer.c                           |   72 ++
 daemon/src/checksum.c                              |   32 +
 daemon/src/hash.c                                  |  199 ++++
 daemon/src/ignore_pool.c                           |  136 +++
 daemon/src/local.c                                 |  159 +++
 daemon/src/lock.c                                  |   32 +
 daemon/src/log.c                                   |   57 +
 daemon/src/main.c                                  |  302 ++++++
 daemon/src/mcast.c                                 |  287 +++++
 daemon/src/netlink.c                               |  326 ++++++
 daemon/src/network.c                               |  282 +++++
 daemon/src/proxy.c                                 |  124 +++
 daemon/src/read_config_lex.l                       |  125 +++
 daemon/src/read_config_yy.y                        |  550 ++++++++++
 daemon/src/run.c                                   |  227 ++++
 daemon/src/state_helper.c                          |   44 +
 daemon/src/state_helper_tcp.c                      |   35 +
 daemon/src/stats-mode.c                            |  151 +++
 daemon/src/sync-mode.c                             |  416 +++++++
 daemon/src/sync-nack.c                             |  309 ++++++
 daemon/src/sync-notrack.c                          |  127 +++
 daemon/src/traffic_stats.c                         |   54 +
 extensions/Makefile.am                             |   16 -
 extensions/libct_proto_icmp.c                      |  108 --
 extensions/libct_proto_icmp.man                    |   10 -
 extensions/libct_proto_sctp.c                      |  164 ---
 extensions/libct_proto_tcp.c                       |  180 ----
 extensions/libct_proto_tcp.man                     |   16 -
 extensions/libct_proto_udp.c                       |  141 ---
 extensions/libct_proto_udp.man                     |   13 -
 include/Makefile.am                                |    2 -
 include/conntrack.h                                |  160 ---
 include/linux_list.h                               |  725 -------------
 src/Makefile.am                                    |    7 -
 src/conntrack.c                                    | 1131 --------------------
 test.sh                                            |  110 --
 125 files changed, 11487 insertions(+), 3511 deletions(-)
 delete mode 100644 AUTHORS
 delete mode 100644 ChangeLog
 delete mode 100644 INSTALL
 delete mode 100644 Make_global.am
 delete mode 100644 Makefile.am
 create mode 100644 README
 delete mode 100755 autogen.sh
 create mode 100644 cli/AUTHORS
 create mode 100644 cli/ChangeLog
 create mode 100644 cli/INSTALL
 create mode 100644 cli/Make_global.am
 create mode 100644 cli/Makefile.am
 create mode 100755 cli/autogen.sh
 create mode 100644 cli/configure.in
 create mode 100644 cli/conntrack.8
 create mode 100644 cli/extensions/Makefile.am
 create mode 100644 cli/extensions/libct_proto_icmp.c
 create mode 100644 cli/extensions/libct_proto_icmp.man
 create mode 100644 cli/extensions/libct_proto_sctp.c
 create mode 100644 cli/extensions/libct_proto_tcp.c
 create mode 100644 cli/extensions/libct_proto_tcp.man
 create mode 100644 cli/extensions/libct_proto_udp.c
 create mode 100644 cli/extensions/libct_proto_udp.man
 create mode 100644 cli/include/Makefile.am
 create mode 100644 cli/include/conntrack.h
 create mode 100644 cli/include/linux_list.h
 create mode 100644 cli/src/Makefile.am
 create mode 100644 cli/src/conntrack.c
 create mode 100644 cli/test.sh
 delete mode 100644 configure.in
 delete mode 100644 conntrack.8
 create mode 100644 daemon/AUTHORS
 create mode 100644 daemon/CHANGELOG
 create mode 100644 daemon/CONTRIBUTORS
 create mode 100644 daemon/INSTALL
 create mode 100644 daemon/Make_global.am
 create mode 100644 daemon/Makefile.am
 create mode 100644 daemon/TODO
 create mode 100755 daemon/autogen.sh
 create mode 100644 daemon/configure.in
 create mode 100644 daemon/examples/Makefile.am
 create mode 100644 daemon/examples/debian.conntrackd.init.d
 create mode 100644 daemon/examples/stats/Makefile.am
 create mode 100644 daemon/examples/stats/conntrackd.conf
 create mode 100644 daemon/examples/sync/Makefile.am
 create mode 100644 daemon/examples/sync/nack/Makefile.am
 create mode 100644 daemon/examples/sync/nack/README
 create mode 100644 daemon/examples/sync/nack/node1/Makefile.am
 create mode 100644 daemon/examples/sync/nack/node1/conntrackd.conf
 create mode 100644 daemon/examples/sync/nack/node1/keepalived.conf
 create mode 100644 daemon/examples/sync/nack/node2/Makefile.am
 create mode 100644 daemon/examples/sync/nack/node2/conntrackd.conf
 create mode 100644 daemon/examples/sync/nack/node2/keepalived.conf
 create mode 100755 daemon/examples/sync/nack/script_backup.sh
 create mode 100755 daemon/examples/sync/nack/script_master.sh
 create mode 100644 daemon/examples/sync/persistent/Makefile.am
 create mode 100644 daemon/examples/sync/persistent/README
 create mode 100644 daemon/examples/sync/persistent/node1/Makefile.am
 create mode 100644 daemon/examples/sync/persistent/node1/conntrackd.conf
 create mode 100644 daemon/examples/sync/persistent/node1/keepalived.conf
 create mode 100644 daemon/examples/sync/persistent/node2/Makefile.am
 create mode 100644 daemon/examples/sync/persistent/node2/conntrackd.conf
 create mode 100644 daemon/examples/sync/persistent/node2/keepalived.conf
 create mode 100755 daemon/examples/sync/persistent/script_backup.sh
 create mode 100755 daemon/examples/sync/persistent/script_master.sh
 create mode 100644 daemon/include/Makefile.am
 create mode 100644 daemon/include/alarm.h
 create mode 100644 daemon/include/buffer.h
 create mode 100644 daemon/include/cache.h
 create mode 100644 daemon/include/conntrackd.h
 create mode 100644 daemon/include/debug.h
 create mode 100644 daemon/include/hash.h
 create mode 100644 daemon/include/ignore.h
 create mode 100644 daemon/include/jhash.h
 create mode 100644 daemon/include/linux_list.h
 create mode 100644 daemon/include/local.h
 create mode 100644 daemon/include/log.h
 create mode 100644 daemon/include/mcast.h
 create mode 100644 daemon/include/network.h
 create mode 100644 daemon/include/slist.h
 create mode 100644 daemon/include/state_helper.h
 create mode 100644 daemon/include/sync.h
 create mode 100644 daemon/include/us-conntrack.h
 create mode 100644 daemon/src/Makefile.am
 create mode 100644 daemon/src/alarm.c
 create mode 100644 daemon/src/buffer.c
 create mode 100644 daemon/src/cache.c
 create mode 100644 daemon/src/cache_iterators.c
 create mode 100644 daemon/src/cache_lifetime.c
 create mode 100644 daemon/src/cache_timer.c
 create mode 100644 daemon/src/checksum.c
 create mode 100644 daemon/src/hash.c
 create mode 100644 daemon/src/ignore_pool.c
 create mode 100644 daemon/src/local.c
 create mode 100644 daemon/src/lock.c
 create mode 100644 daemon/src/log.c
 create mode 100644 daemon/src/main.c
 create mode 100644 daemon/src/mcast.c
 create mode 100644 daemon/src/netlink.c
 create mode 100644 daemon/src/network.c
 create mode 100644 daemon/src/proxy.c
 create mode 100644 daemon/src/read_config_lex.l
 create mode 100644 daemon/src/read_config_yy.y
 create mode 100644 daemon/src/run.c
 create mode 100644 daemon/src/state_helper.c
 create mode 100644 daemon/src/state_helper_tcp.c
 create mode 100644 daemon/src/stats-mode.c
 create mode 100644 daemon/src/sync-mode.c
 create mode 100644 daemon/src/sync-nack.c
 create mode 100644 daemon/src/sync-notrack.c
 create mode 100644 daemon/src/traffic_stats.c
 delete mode 100644 extensions/Makefile.am
 delete mode 100644 extensions/libct_proto_icmp.c
 delete mode 100644 extensions/libct_proto_icmp.man
 delete mode 100644 extensions/libct_proto_sctp.c
 delete mode 100644 extensions/libct_proto_tcp.c
 delete mode 100644 extensions/libct_proto_tcp.man
 delete mode 100644 extensions/libct_proto_udp.c
 delete mode 100644 extensions/libct_proto_udp.man
 delete mode 100644 include/Makefile.am
 delete mode 100644 include/conntrack.h
 delete mode 100644 include/linux_list.h
 delete mode 100644 src/Makefile.am
 delete mode 100644 src/conntrack.c
 delete mode 100644 test.sh

(limited to 'autogen.sh')

diff --git a/AUTHORS b/AUTHORS
deleted file mode 100644
index d1cb6fa..0000000
--- a/AUTHORS
+++ /dev/null
@@ -1,2 +0,0 @@
-Pablo Neira Ayuso <pablo@eurodev.net>
-Harald Welte <laforge@netfilter.org>
diff --git a/ChangeLog b/ChangeLog
deleted file mode 100644
index 1524ef6..0000000
--- a/ChangeLog
+++ /dev/null
@@ -1,243 +0,0 @@
-2006-03-20
-<hidden@sch.bme.hu>
-	o fix ICMP protocol extension parse callback
-
-2006-01-15
-<pablo@netfilter.org>
-	o Added missing parameters to set the ports of an expectation tuple
-	o Add support to filter dumped entries. 
-	  ie: conntrack -L -p tcp --orig-port-dst 993
-	  display all the connections to IMAPS servers
-	      conntrack -L -m 2
-	  display all the connection marked with 2
-	o Bumped version to 1.00beta2
-
-2005-12-26
-<pablo@netfilter.org>
-	o add IPv6 support: main change
-	o removed dead code: iptables_insmod and get_modprobe
-	o compact the commands vs. options table
-	o move working vars from the stack to the BSS section
-	o update manpage
-	o Bumped version to 1.0beta1
-<yasuyuki.kozakai@toshiba.co.jp>
-	o check address family mismatch
-	o fix incomplete copying IPv6 addresses
-
-2005-12-19
-<pablo@netfilter.org>
-	o We only support ipv4 at the moment: set l3protonum to AF_INET
-	o Minor changes to prepare upcoming ipv6 support
-
-2005-12-03
-<pablo@netfilter.org>
-	o Add support to filter events. ie: -p tcp --orig-port-dst 80 in
-	conjuction with -E to get all the requests to HTTP servers
-	o Update manpage
-	o Missing static function declaration in the protocol handlers
-	o Use protocol flags defined in libnetfilter_conntrack
-	o Bumped version to 0.991
-
-2005-11-22
-<marcus@ingate.com>
-	o Fix oversized number of options
-
-2005-11-11
-<laforge@netfilter.org>
-	o don't check for kernel header path in configure, since we don't use
-	  kernel headers
-	o don't check for libnfnetlink, we don't use it directly
-	o move plugins into pkglibdir
-	o remove 'lib' prefix of plugins, they're not really libraries
-	o remove version information from plugin filenames
-	o Bumped version to 0.99
-2005-11-09
-<pablo@netfilter.org>
-	o set status to zero, libnetfilter_conntrack now activate
-	IPS_CONFIRMED since all conntrack in hash must be confirmed.
-	o Bumped version to 0.98
-
-2005-11-08
-<olenf@ans.pl>
-	o Fix warnings generated by gcc -Wall
-	o Fix conntrack exit value at error
-	o Replace obsolete inet_addr by inet_aton
-
-2005-11-05
-<olenf@ans.pl>
-	o Improved conntrack -h output
-	o add htons for icmp id.
-<pablo@eurodev.net>
-	o -t and -u are optional at update.
-	o Fixed versioning :(
-	o Bumped version to 0.97
-
-2005-11-03
-<laforge@netfilter.org>
-	o Use extra 'data' argument of nfct_register_callback() function that
-	  I've introduced in libetfilter_conntrack.
-<olenf@ans.pl>
-	o moves conntrack tool from bin to sbin directory since this
-	application is an administration utility and it requires uid==0 or
-	CAP_NET_ADMIN
-<pablo@eurodev.net>
-	o check if --state missing when -p is passed
-	o command type is passed to final_check: checkings based on the
-	command can be done now.
-	o kill duplicated definition of IPS_* bits: Already present in 
-	libnetfilter_conntrack.
-	o Move action and command enum to conntrack.h
-	o kill NIPQUAD macro
-	o make conntrack handler cth static.
-	o Bumped version to 0.96
-
-2005-11-01
-<pablo@eurodev.net>
-	o Fix error message describing illegal option -E -i
-	o -D -i ID requires tuple information: Display an error message
-	o Use NFCT_ALL_CT_GROUPS flag instead of NFCT_ALL_GROUPS
-	o Event mask doesn't make sense for expectations, kill dead code
-	o Bumped version to 0.95
-<olenf@ans.pl>
-	o Fix wrong formating in conntrack -h
-
-2005-10-30
-<pablo@eurodev.net>
-	Special thanks to Deti Fiegl from the Leibniz Supercomputing Centre in
-	Munich, Germany for providing the "fast" hardware to reproduce
-	spurious bugs ;)
-
-	o Replace misleading message "Not enough memory" by "Can't open handler"
-	o New option -i for expectation dumping: conntrack -L expect [-i]
-	o sed 's/VERSION/CONNTRACK_VERSION/g'
-	o Fix nfct_open flags, now uses NFCT_ALL_GROUPS when needed
-	o Bumped version to 0.94
-
-2005-10-28
-<pablo@eurodev.net>
-	o New option -i for dumping: conntrack -L [-i]
-	o Fixed warning in findproto due to a stupid wrong type definition
-	o sed 's/nfct_set_callback/nfct_register_callback/g'
-	o killed the 'retry' logic, *sigh* it is broken in some cases
-	o killed broken and unneeded protocol handler destructors (fini)
-	o killed unregister_proto
-	o Fixed code indentation in the command selector
-	o Bumped version to 0.93
-
-2005-10-27
-<pablo@eurodev.net>
-	o Use conntrack VERSION instead of the old LIBCT_VERSION
-	o proto_list and lib_dir are now static
-	o kill dead code: function dump_tuple
-	o Bumped version to 0.92
-
-2005-10-25
-<eleblond@inl.fr>
-	o Add missing autogen.sh file
-
-2005-10-24
-<pablo@eurodev.net>
-	o use NFCT_ANY_GROUP flag in nfct_open()
-
-2005-10-21
-<pablo@eurodev.net>
-	o Bumped version to 0.90
-	o Add support for id and marks
-
-2005-10-20
-<pablo@eurodev.net>
-	o Kill some more files that generated by the autocrap
-	o Resync with the lastest libnetfilter_conntrack API changes
-
-2005-10-16
-<pablo@netfilter.org>
-	o Rename libct_proto.h to conntrack.h
-	o Remove config.h.in from svn, it's autogenerated by the autocrap :)
-	o Remove dead functions in the SCTP protocol helper
-
-2005-10-14
-<pablo@netfilter.org>
-	o Kill config.h.in, it's generated by the autocrap
-	o The conntrack tool now uses libnetfilter_conntrack :)
-	o libct.c has been killed, now it's in libnetfilter_conntrack
-	o Check if you're root or CAP_NET_ADMIN
-	o Bumped version number to 0.86
-
-2005-10-07
-<chentschel@iplan.com.ar>
-	o Fixed ICMP options
-<pablo@netfilter.org>
-	o Multiple fixes for the ICMP protocol handler
-	o Fix ICMP output: wrong output. type and code were set to zero.
-
-2005-10-05
-<pablo@netfilter.org>
-	o Fix up counters
-	o Fix up compilation (IPS_* stuff missing), still need a proper fix
-	o Bumped version number to 0.82
-
-2005-09-24
-<laforge@netfilter.org>
-	o Get rid of C++ style comments
-	o Remove remaining bits of "-A --action", group-mask and dump-mask
-	o Clean up #include's
-	o Fix double-free when exiting via signal handler (Ctrl+C)
-	o Add "version" member to plugins
-	o Fix some Endianness issues when printing CTA_STATUS
-
-2005-08-31
-<pablo@netfilter.org>
-	o Fix packet and bytes counters (use __be64_to_cpu)
-	o Fix ip_conntrack_netlink load-on-demand
-
-2005-07-12
-<pablo@eurodev.net>
-	o Use conntrack netlink attributes: Major change
-	o Kill action setting: Mask based dumping
-	o Fix ChangeLog
-
-2005-05-23
-<laforge@netfilter.org>
-	o Fixed syntax error (tab/space issue) in help message
-	o Fixed getopt handling on big endian machines
-	o Fixed possible future read-over-end-of-array in TCP extension
-	o Add manpage
-	o Add missing space at output of libct_proto_icmp.c
-	o Add status bits that were introduced in 2.6.11
-	o Add SCTP extension
-	o Add support for expect creation
-	o Bump version number to 0.63
-
-2005-05-17
-<pablo@eurodev.net>
-	o Added descriptive error messages.
-	o Fix wrong flags check in [tcp|udp] proto helpers.
-
-2005-05-16
-<pablo@eurodev.net>
-	o Implemented ICMP proto helper
-	o Added help() and final_check() functions for proto helpers.
-
-2005-05-01
-<pablo@eurodev.net>
-	o Created changelog file
-	o Deleted libctnetlink.h and libnfnetlink.h from the include/ dir.
-	o Added support for version (-V) and help (-h)
-	o Added event mask based support
-	o Added GPLv2 headers
-	o Use fprintf instead of printf
-	o Defined print_tuple and print_proto output interfaces
-	o ctnl_[get|del]_conntrack handles return value from kernel via msgerr
-	o Added support for conntrack table flushing
-	o Added test case file (test.sh)
-	o Improve dump output
-
-<azez@ufomechanic.net>
-	o Autoconf stuff for conntrack + some pablo's modifications.
-	o Fixed packet counters formatting (use %llu instead of %lu)
-
-2005-04-25
-<pablo@eurodev.net>
-	o Added support for mask based event dumping
-	o Added support for mask based event notification
-	o On-demand autoload of ip_conntrack_netlink
diff --git a/INSTALL b/INSTALL
deleted file mode 100644
index 54caf7c..0000000
--- a/INSTALL
+++ /dev/null
@@ -1,229 +0,0 @@
-Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
-Foundation, Inc.
-
-   This file is free documentation; the Free Software Foundation gives
-unlimited permission to copy, distribute and modify it.
-
-Basic Installation
-==================
-
-   These are generic installation instructions.
-
-   The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation.  It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions.  Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
-   It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring.  (Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.)
-
-   If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release.  If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
-
-   The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'.  You only need
-`configure.ac' if you want to change it or regenerate `configure' using
-a newer version of `autoconf'.
-
-The simplest way to compile this package is:
-
-  1. `cd' to the directory containing the package's source code and type
-     `./configure' to configure the package for your system.  If you're
-     using `csh' on an old version of System V, you might need to type
-     `sh ./configure' instead to prevent `csh' from trying to execute
-     `configure' itself.
-
-     Running `configure' takes awhile.  While running, it prints some
-     messages telling which features it is checking for.
-
-  2. Type `make' to compile the package.
-
-  3. Optionally, type `make check' to run any self-tests that come with
-     the package.
-
-  4. Type `make install' to install the programs and any data files and
-     documentation.
-
-  5. You can remove the program binaries and object files from the
-     source code directory by typing `make clean'.  To also remove the
-     files that `configure' created (so you can compile the package for
-     a different kind of computer), type `make distclean'.  There is
-     also a `make maintainer-clean' target, but that is intended mainly
-     for the package's developers.  If you use it, you may have to get
-     all sorts of other programs in order to regenerate files that came
-     with the distribution.
-
-Compilers and Options
-=====================
-
-   Some systems require unusual options for compilation or linking that
-the `configure' script does not know about.  Run `./configure --help'
-for details on some of the pertinent environment variables.
-
-   You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment.  Here
-is an example:
-
-     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
-
-   *Note Defining Variables::, for more details.
-
-Compiling For Multiple Architectures
-====================================
-
-   You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory.  To do this, you must use a version of `make' that
-supports the `VPATH' variable, such as GNU `make'.  `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script.  `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'.
-
-   If you have to use a `make' that does not support the `VPATH'
-variable, you have to compile the package for one architecture at a
-time in the source code directory.  After you have installed the
-package for one architecture, use `make distclean' before reconfiguring
-for another architecture.
-
-Installation Names
-==================
-
-   By default, `make install' will install the package's files in
-`/usr/local/bin', `/usr/local/man', etc.  You can specify an
-installation prefix other than `/usr/local' by giving `configure' the
-option `--prefix=PATH'.
-
-   You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files.  If you
-give `configure' the option `--exec-prefix=PATH', the package will use
-PATH as the prefix for installing programs and libraries.
-Documentation and other data files will still use the regular prefix.
-
-   In addition, if you use an unusual directory layout you can give
-options like `--bindir=PATH' to specify different values for particular
-kinds of files.  Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them.
-
-   If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
-Optional Features
-=================
-
-   Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System).  The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
-   For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
-Specifying the System Type
-==========================
-
-   There may be some features `configure' cannot figure out
-automatically, but needs to determine by the type of machine the package
-will run on.  Usually, assuming the package is built to be run on the
-_same_ architectures, `configure' can figure that out, but if it prints
-a message saying it cannot guess the machine type, give it the
-`--build=TYPE' option.  TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
-     CPU-COMPANY-SYSTEM
-
-where SYSTEM can have one of these forms:
-
-     OS KERNEL-OS
-
-   See the file `config.sub' for the possible values of each field.  If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
-
-   If you are _building_ compiler tools for cross-compiling, you should
-use the `--target=TYPE' option to select the type of system they will
-produce code for.
-
-   If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
-
-Sharing Defaults
-================
-
-   If you want to set default values for `configure' scripts to share,
-you can create a site shell script called `config.site' that gives
-default values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists.  Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-Defining Variables
-==================
-
-   Variables not defined in a site shell script can be set in the
-environment passed to `configure'.  However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost.  In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'.  For example:
-
-     ./configure CC=/usr/local2/bin/gcc
-
-will cause the specified gcc to be used as the C compiler (unless it is
-overridden in the site shell script).
-
-`configure' Invocation
-======================
-
-   `configure' recognizes the following options to control how it
-operates.
-
-`--help'
-`-h'
-     Print a summary of the options to `configure', and exit.
-
-`--version'
-`-V'
-     Print the version of Autoconf used to generate the `configure'
-     script, and exit.
-
-`--cache-file=FILE'
-     Enable the cache: use and save the results of the tests in FILE,
-     traditionally `config.cache'.  FILE defaults to `/dev/null' to
-     disable caching.
-
-`--config-cache'
-`-C'
-     Alias for `--cache-file=config.cache'.
-
-`--quiet'
-`--silent'
-`-q'
-     Do not print messages saying which checks are being made.  To
-     suppress all normal output, redirect it to `/dev/null' (any error
-     messages will still be shown).
-
-`--srcdir=DIR'
-     Look for the package's source code in directory DIR.  Usually
-     `configure' can determine that directory automatically.
-
-`configure' also accepts some other, not widely useful, options.  Run
-`configure --help' for more details.
-
diff --git a/Make_global.am b/Make_global.am
deleted file mode 100644
index 685add7..0000000
--- a/Make_global.am
+++ /dev/null
@@ -1 +0,0 @@
-INCLUDES=$(all_includes) -I$(top_srcdir)/include
diff --git a/Makefile.am b/Makefile.am
deleted file mode 100644
index d3b4ceb..0000000
--- a/Makefile.am
+++ /dev/null
@@ -1,21 +0,0 @@
-include Make_global.am
-
-# not a GNU package. You can remove this line, if
-# have all needed files, that a GNU package needs
-AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
-
-man_MANS = conntrack.8
-
-EXTRA_DIST = $(man_MANS) Make_global.am debian
-
-SUBDIRS   = src extensions
-DIST_SUBDIRS = include src extensions
-LINKOPTS  = -ldl -lnetfilter_conntrack
-AM_CFLAGS = -g
-
-$(OBJECTS): libtool
-libtool: $(LIBTOOL_DEPS)
-	$(SHELL) ./config.status --recheck
-
-dist-hook:
-	rm -rf `find $(distdir)/debian -name .svn`
diff --git a/README b/README
new file mode 100644
index 0000000..314a2e4
--- /dev/null
+++ b/README
@@ -0,0 +1,17 @@
+This package contains two subdirectories:
+
+cli (command line interface)
+============================
+This subdirectory contains the command line tool `conntrack' that provides an 
+userspace interface to the connection tracking system. This tool let system
+administrators perform different actions against the connection tracking
+table. For more information see the manpage conntrack(8).
+
+daemon
+======
+This subdirectory contains the userspace connection tracking daemon so-called
+'conntrackd`. This daemon maintains a copy of the connection tracking table
+in userspace. It is highly configurable and easily extensible. Currently it
+covers the specific aspects of stateful GNU/Linux firewalls to enable high
+availability solutions and can be used as statistics collector of the firewall
+use.
diff --git a/autogen.sh b/autogen.sh
deleted file mode 100755
index e76d3ef..0000000
--- a/autogen.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/sh
-
-run ()
-{
-    echo "running: $*"
-    eval $*
-
-    if test $? != 0 ; then
-	echo "error: while running '$*'"
-	exit 1
-    fi
-}
-
-run aclocal
-run libtoolize -f
-#run autoheader
-run automake -a
-run autoconf
diff --git a/cli/AUTHORS b/cli/AUTHORS
new file mode 100644
index 0000000..d1cb6fa
--- /dev/null
+++ b/cli/AUTHORS
@@ -0,0 +1,2 @@
+Pablo Neira Ayuso <pablo@eurodev.net>
+Harald Welte <laforge@netfilter.org>
diff --git a/cli/ChangeLog b/cli/ChangeLog
new file mode 100644
index 0000000..1524ef6
--- /dev/null
+++ b/cli/ChangeLog
@@ -0,0 +1,243 @@
+2006-03-20
+<hidden@sch.bme.hu>
+	o fix ICMP protocol extension parse callback
+
+2006-01-15
+<pablo@netfilter.org>
+	o Added missing parameters to set the ports of an expectation tuple
+	o Add support to filter dumped entries. 
+	  ie: conntrack -L -p tcp --orig-port-dst 993
+	  display all the connections to IMAPS servers
+	      conntrack -L -m 2
+	  display all the connection marked with 2
+	o Bumped version to 1.00beta2
+
+2005-12-26
+<pablo@netfilter.org>
+	o add IPv6 support: main change
+	o removed dead code: iptables_insmod and get_modprobe
+	o compact the commands vs. options table
+	o move working vars from the stack to the BSS section
+	o update manpage
+	o Bumped version to 1.0beta1
+<yasuyuki.kozakai@toshiba.co.jp>
+	o check address family mismatch
+	o fix incomplete copying IPv6 addresses
+
+2005-12-19
+<pablo@netfilter.org>
+	o We only support ipv4 at the moment: set l3protonum to AF_INET
+	o Minor changes to prepare upcoming ipv6 support
+
+2005-12-03
+<pablo@netfilter.org>
+	o Add support to filter events. ie: -p tcp --orig-port-dst 80 in
+	conjuction with -E to get all the requests to HTTP servers
+	o Update manpage
+	o Missing static function declaration in the protocol handlers
+	o Use protocol flags defined in libnetfilter_conntrack
+	o Bumped version to 0.991
+
+2005-11-22
+<marcus@ingate.com>
+	o Fix oversized number of options
+
+2005-11-11
+<laforge@netfilter.org>
+	o don't check for kernel header path in configure, since we don't use
+	  kernel headers
+	o don't check for libnfnetlink, we don't use it directly
+	o move plugins into pkglibdir
+	o remove 'lib' prefix of plugins, they're not really libraries
+	o remove version information from plugin filenames
+	o Bumped version to 0.99
+2005-11-09
+<pablo@netfilter.org>
+	o set status to zero, libnetfilter_conntrack now activate
+	IPS_CONFIRMED since all conntrack in hash must be confirmed.
+	o Bumped version to 0.98
+
+2005-11-08
+<olenf@ans.pl>
+	o Fix warnings generated by gcc -Wall
+	o Fix conntrack exit value at error
+	o Replace obsolete inet_addr by inet_aton
+
+2005-11-05
+<olenf@ans.pl>
+	o Improved conntrack -h output
+	o add htons for icmp id.
+<pablo@eurodev.net>
+	o -t and -u are optional at update.
+	o Fixed versioning :(
+	o Bumped version to 0.97
+
+2005-11-03
+<laforge@netfilter.org>
+	o Use extra 'data' argument of nfct_register_callback() function that
+	  I've introduced in libetfilter_conntrack.
+<olenf@ans.pl>
+	o moves conntrack tool from bin to sbin directory since this
+	application is an administration utility and it requires uid==0 or
+	CAP_NET_ADMIN
+<pablo@eurodev.net>
+	o check if --state missing when -p is passed
+	o command type is passed to final_check: checkings based on the
+	command can be done now.
+	o kill duplicated definition of IPS_* bits: Already present in 
+	libnetfilter_conntrack.
+	o Move action and command enum to conntrack.h
+	o kill NIPQUAD macro
+	o make conntrack handler cth static.
+	o Bumped version to 0.96
+
+2005-11-01
+<pablo@eurodev.net>
+	o Fix error message describing illegal option -E -i
+	o -D -i ID requires tuple information: Display an error message
+	o Use NFCT_ALL_CT_GROUPS flag instead of NFCT_ALL_GROUPS
+	o Event mask doesn't make sense for expectations, kill dead code
+	o Bumped version to 0.95
+<olenf@ans.pl>
+	o Fix wrong formating in conntrack -h
+
+2005-10-30
+<pablo@eurodev.net>
+	Special thanks to Deti Fiegl from the Leibniz Supercomputing Centre in
+	Munich, Germany for providing the "fast" hardware to reproduce
+	spurious bugs ;)
+
+	o Replace misleading message "Not enough memory" by "Can't open handler"
+	o New option -i for expectation dumping: conntrack -L expect [-i]
+	o sed 's/VERSION/CONNTRACK_VERSION/g'
+	o Fix nfct_open flags, now uses NFCT_ALL_GROUPS when needed
+	o Bumped version to 0.94
+
+2005-10-28
+<pablo@eurodev.net>
+	o New option -i for dumping: conntrack -L [-i]
+	o Fixed warning in findproto due to a stupid wrong type definition
+	o sed 's/nfct_set_callback/nfct_register_callback/g'
+	o killed the 'retry' logic, *sigh* it is broken in some cases
+	o killed broken and unneeded protocol handler destructors (fini)
+	o killed unregister_proto
+	o Fixed code indentation in the command selector
+	o Bumped version to 0.93
+
+2005-10-27
+<pablo@eurodev.net>
+	o Use conntrack VERSION instead of the old LIBCT_VERSION
+	o proto_list and lib_dir are now static
+	o kill dead code: function dump_tuple
+	o Bumped version to 0.92
+
+2005-10-25
+<eleblond@inl.fr>
+	o Add missing autogen.sh file
+
+2005-10-24
+<pablo@eurodev.net>
+	o use NFCT_ANY_GROUP flag in nfct_open()
+
+2005-10-21
+<pablo@eurodev.net>
+	o Bumped version to 0.90
+	o Add support for id and marks
+
+2005-10-20
+<pablo@eurodev.net>
+	o Kill some more files that generated by the autocrap
+	o Resync with the lastest libnetfilter_conntrack API changes
+
+2005-10-16
+<pablo@netfilter.org>
+	o Rename libct_proto.h to conntrack.h
+	o Remove config.h.in from svn, it's autogenerated by the autocrap :)
+	o Remove dead functions in the SCTP protocol helper
+
+2005-10-14
+<pablo@netfilter.org>
+	o Kill config.h.in, it's generated by the autocrap
+	o The conntrack tool now uses libnetfilter_conntrack :)
+	o libct.c has been killed, now it's in libnetfilter_conntrack
+	o Check if you're root or CAP_NET_ADMIN
+	o Bumped version number to 0.86
+
+2005-10-07
+<chentschel@iplan.com.ar>
+	o Fixed ICMP options
+<pablo@netfilter.org>
+	o Multiple fixes for the ICMP protocol handler
+	o Fix ICMP output: wrong output. type and code were set to zero.
+
+2005-10-05
+<pablo@netfilter.org>
+	o Fix up counters
+	o Fix up compilation (IPS_* stuff missing), still need a proper fix
+	o Bumped version number to 0.82
+
+2005-09-24
+<laforge@netfilter.org>
+	o Get rid of C++ style comments
+	o Remove remaining bits of "-A --action", group-mask and dump-mask
+	o Clean up #include's
+	o Fix double-free when exiting via signal handler (Ctrl+C)
+	o Add "version" member to plugins
+	o Fix some Endianness issues when printing CTA_STATUS
+
+2005-08-31
+<pablo@netfilter.org>
+	o Fix packet and bytes counters (use __be64_to_cpu)
+	o Fix ip_conntrack_netlink load-on-demand
+
+2005-07-12
+<pablo@eurodev.net>
+	o Use conntrack netlink attributes: Major change
+	o Kill action setting: Mask based dumping
+	o Fix ChangeLog
+
+2005-05-23
+<laforge@netfilter.org>
+	o Fixed syntax error (tab/space issue) in help message
+	o Fixed getopt handling on big endian machines
+	o Fixed possible future read-over-end-of-array in TCP extension
+	o Add manpage
+	o Add missing space at output of libct_proto_icmp.c
+	o Add status bits that were introduced in 2.6.11
+	o Add SCTP extension
+	o Add support for expect creation
+	o Bump version number to 0.63
+
+2005-05-17
+<pablo@eurodev.net>
+	o Added descriptive error messages.
+	o Fix wrong flags check in [tcp|udp] proto helpers.
+
+2005-05-16
+<pablo@eurodev.net>
+	o Implemented ICMP proto helper
+	o Added help() and final_check() functions for proto helpers.
+
+2005-05-01
+<pablo@eurodev.net>
+	o Created changelog file
+	o Deleted libctnetlink.h and libnfnetlink.h from the include/ dir.
+	o Added support for version (-V) and help (-h)
+	o Added event mask based support
+	o Added GPLv2 headers
+	o Use fprintf instead of printf
+	o Defined print_tuple and print_proto output interfaces
+	o ctnl_[get|del]_conntrack handles return value from kernel via msgerr
+	o Added support for conntrack table flushing
+	o Added test case file (test.sh)
+	o Improve dump output
+
+<azez@ufomechanic.net>
+	o Autoconf stuff for conntrack + some pablo's modifications.
+	o Fixed packet counters formatting (use %llu instead of %lu)
+
+2005-04-25
+<pablo@eurodev.net>
+	o Added support for mask based event dumping
+	o Added support for mask based event notification
+	o On-demand autoload of ip_conntrack_netlink
diff --git a/cli/INSTALL b/cli/INSTALL
new file mode 100644
index 0000000..54caf7c
--- /dev/null
+++ b/cli/INSTALL
@@ -0,0 +1,229 @@
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
+Foundation, Inc.
+
+   This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+   These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory.  After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/cli/Make_global.am b/cli/Make_global.am
new file mode 100644
index 0000000..685add7
--- /dev/null
+++ b/cli/Make_global.am
@@ -0,0 +1 @@
+INCLUDES=$(all_includes) -I$(top_srcdir)/include
diff --git a/cli/Makefile.am b/cli/Makefile.am
new file mode 100644
index 0000000..d3b4ceb
--- /dev/null
+++ b/cli/Makefile.am
@@ -0,0 +1,21 @@
+include Make_global.am
+
+# not a GNU package. You can remove this line, if
+# have all needed files, that a GNU package needs
+AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
+
+man_MANS = conntrack.8
+
+EXTRA_DIST = $(man_MANS) Make_global.am debian
+
+SUBDIRS   = src extensions
+DIST_SUBDIRS = include src extensions
+LINKOPTS  = -ldl -lnetfilter_conntrack
+AM_CFLAGS = -g
+
+$(OBJECTS): libtool
+libtool: $(LIBTOOL_DEPS)
+	$(SHELL) ./config.status --recheck
+
+dist-hook:
+	rm -rf `find $(distdir)/debian -name .svn`
diff --git a/cli/autogen.sh b/cli/autogen.sh
new file mode 100755
index 0000000..e76d3ef
--- /dev/null
+++ b/cli/autogen.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+run ()
+{
+    echo "running: $*"
+    eval $*
+
+    if test $? != 0 ; then
+	echo "error: while running '$*'"
+	exit 1
+    fi
+}
+
+run aclocal
+run libtoolize -f
+#run autoheader
+run automake -a
+run autoconf
diff --git a/cli/configure.in b/cli/configure.in
new file mode 100644
index 0000000..1b1b391
--- /dev/null
+++ b/cli/configure.in
@@ -0,0 +1,72 @@
+AC_INIT
+
+AC_CANONICAL_SYSTEM
+
+AM_INIT_AUTOMAKE(conntrack, 1.00beta2)
+
+AC_PROG_CC
+AM_PROG_LIBTOOL
+AC_PROG_INSTALL
+AC_PROG_LN_S
+
+case $target in
+*-*-linux*) ;;
+*) AC_MSG_ERROR([Linux only, dude!]);;
+esac
+
+dnl Dependencies
+LIBNFCONNTRACK_REQUIRED=0.0.31
+ 
+AC_CHECK_LIB(dl, dlopen)
+
+PKG_CHECK_MODULES(LIBNFCONNTRACK, libnetfilter_conntrack >= $LIBNFCONNTRACK_REQUIRED,,
+	AC_MSG_ERROR(Cannot find libnetfilter_conntrack >= $LIBNFCONNTRACK_REQUIRED))
+ 
+AC_CHECK_HEADERS(arpa/inet.h)
+dnl check for inet_pton
+AC_CHECK_FUNCS(inet_pton)
+dnl Some systems have it, but not IPv6
+if test "$ac_cv_func_inet_pton" = "yes" ; then
+AC_MSG_CHECKING(if inet_pton supports IPv6)
+AC_TRY_RUN(
+   [
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+int main()
+  {
+     struct in6_addr addr6;
+     if (inet_pton(AF_INET6, "::1", &addr6) < 1)
+        exit(1);
+     else
+        exit(0);
+  }
+  ], [ AC_MSG_RESULT(yes)
+       AC_DEFINE_UNQUOTED(HAVE_INET_PTON_IPV6, 1, [Define to 1 if inet_pton supports IPv6.])
+  ], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+fi
+
+dnl--------------------------------
+
+if test ! -z "$libdir"; then
+   MODULE_DIR="\\\"$libdir/conntrack/\\\""
+   CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR"
+fi
+
+dnl--------------------------------
+
+CFLAGS="$CFLAGS $LIBNFCONNTRACK_CFLAGS"
+CONNTRACK_LIBS="$LIBNFCONNTRACK_LIBS"
+
+AC_SUBST(CONNTRACK_LIBS)
+
+AC_OUTPUT(Makefile src/Makefile extensions/Makefile include/Makefile)
diff --git a/cli/conntrack.8 b/cli/conntrack.8
new file mode 100644
index 0000000..307180b
--- /dev/null
+++ b/cli/conntrack.8
@@ -0,0 +1,142 @@
+.TH CONNTRACK 8 "Jun 23, 2005" "" ""
+
+.\" Man page written by Harald Welte <laforge@netfilter.org (Jun 2005)
+
+.SH NAME
+conntrack \- administration tool for netfilter connection tracking
+.SH SYNOPSIS
+.BR "conntrack -L [table] [-z]"
+.br
+.BR "conntrack -G [table] parameters"
+.br
+.BR "conntrack -D [table] paramaters"
+.br
+.BR "conntrack -I [table] parameters"
+.br
+.BR "conntrack -E [table] parameters"
+.br
+.BR "conntrack -F [table]"
+.SH DESCRIPTION
+.B conntrack
+is used to search, list, inspect and maintain the netfilter connection tracking
+subsystem of the Linux kernel.
+.PP
+Using 
+.B conntrack
+, you can dump a list of all (or a filtered selection of) currently tracked
+connections, delete connections from the state table, and even add new ones.
+.PP
+In addition, you can also monitor connection tracking events, e.g. show an
+event message (one line) per newly established connection.
+.SH TABLES
+The connection tracking subsystem maintains two internal tables:
+.TP
+.BR "conntrack" :
+This is the default table.  It contains a list of all currently tracked
+connections through the system.  If you don't use connection tracking
+exemptions (NOTRACK iptables target), this means all connections that go
+through the system.
+.TP
+.BR "expect" :
+This is the table of expectations.  Connection tracking expectations are the
+mechanism used to "expect" RELATED connections to existing ones.  Expectations
+are generally used by "connection tracking helpers" (sometimes called
+application level gateways [ALGs]) for more complex protocols such as FTP,
+SIP, H.323.
+.SH OPTIONS
+The options recognized by 
+.B conntrack
+can be divided into several different groups.
+.SS COMMANDS
+These options specify the particular operation to perform.  Only one of them
+can be specified at any given time.
+.TP
+.BI "-L --dump "
+List connection tacking or expectation table
+.TP
+.BI "-G, --get "
+Search for and show a particular (matching) entry in the given table.
+.TP
+.BI "-D, --delete "
+Delete an entry from the given table.
+.TP
+.BI "-I, --create "
+Create a new entry from the given table.
+.TP
+.BI "-E, --event "
+Display a real-time event log.
+.TP
+.BI "-F, --flush "
+Flush the whole given table
+.SS PARAMETERS
+.TP
+.BI "-z, --zero "
+Atomically zero counters after reading them.  This option is only valid in
+combination with the "-L, --dump" command options.
+.TP
+.BI "-e, --event-mask " "[ALL|NEW|UPDATES|DESTROY][,...]"
+Set the bitmask of events that are to be generated by the in-kernel ctnetlink
+event code.  Using this parameter, you can reduce the event messages generated
+by the kernel to those types to those that you are actually interested in.
+.
+This option can only be used in conjunction with "-E, --event".
+.SS FILTER PARAMETERS
+.TP
+.BI "-s, --orig-src " IP_ADDRESS
+Match only entries whose source address in the original direction equals the one specified as argument.
+.TP
+.BI "-d, --orig-dst " IP_ADDRESS
+Match only entries whose destination address in the original direction equals the one specified as argument.
+.TP
+.BI "-r, --reply-src " IP_ADDRESS
+Match only entries whose source address in the reply direction equals the one specified as argument.
+.TP
+.BI "-q, --reply-dst " IP_ADDRESS
+Match only entries whose destination address in the reply direction equals the one specified as argument.
+.TP
+.BI "-p, --proto " "PROTO "
+Specify layer four (TCP, UDP, ...) protocol.
+.TP
+.BI "-f, --family " "PROTO"
+Specify layer three (ipv4, ipv6) protocol
+This option is only required in conjunction with "-L, --dump". If this option is not passed, the default layer 3 protocol will be IPv4.
+.TP
+.BI "-t, --timeout " "TIMEOUT"
+Specify the timeout.
+.TP
+.BI "-u, --status " "[ASSURED|SEEN_REPLY|UNSET|SRC_NAT|DST_NAT][,...]"
+Specify the conntrack status.
+.TP
+.BI "-i, --id " "ID"
+Specify the conntrack ID. 
+.
+This option can only be used in conjunction with "-L, --dump" to display the conntrack IDs.
+.TP
+.BI "--tuple-src " IP_ADDRESS
+Specify the tuple source address of an expectation.
+.TP
+.BI "--tuple-dst " IP_ADDRESS
+Specify the tuple destination address of an expectation.
+.TP
+.BI "--mask-src " IP_ADDRESS
+Specify the source address mask of an expectation.
+.TP
+.BI "--mask-dst " IP_ADDRESS
+Specify the destination address mask of an expectation.
+.SH DIAGNOSTICS
+The exit code is 0 for correct function.  Errors which appear to be caused by
+invalid command line parameters cause an exit code of 2.  Any other errors
+cause an exit code of 1.
+.SH BUGS
+Bugs? What's this ;-)
+.SH SEE ALSO
+.BR iptables (8)
+.br
+See
+.BR "http://netfilter.org/" .
+.SH AUTHORS
+Jay Schulist, Patrick McHardy, Harald Welte and Pablo Neira wrote the kernel-level "ctnetlink" interface that is used by the conntrack tool.
+.PP
+Pablo Neira wrote the conntrack tool, Harald Welte added support for conntrack based accounting counters.
+.PP
+Man page written by Harald Welte <laforge@netfilter.org>.
diff --git a/cli/extensions/Makefile.am b/cli/extensions/Makefile.am
new file mode 100644
index 0000000..5366ee3
--- /dev/null
+++ b/cli/extensions/Makefile.am
@@ -0,0 +1,16 @@
+include $(top_srcdir)/Make_global.am
+
+AM_CFLAGS=-fPIC -Wall
+LIBS=
+
+pkglib_LTLIBRARIES = ct_proto_tcp.la ct_proto_udp.la		\
+		     ct_proto_icmp.la ct_proto_sctp.la
+
+ct_proto_tcp_la_SOURCES = libct_proto_tcp.c
+ct_proto_tcp_la_LDFLAGS = -module -avoid-version
+ct_proto_udp_la_SOURCES = libct_proto_udp.c
+ct_proto_udp_la_LDFLAGS = -module -avoid-version
+ct_proto_icmp_la_SOURCES = libct_proto_icmp.c
+ct_proto_icmp_la_LDFLAGS = -module -avoid-version
+ct_proto_sctp_la_SOURCES = libct_proto_sctp.c
+ct_proto_sctp_la_LDFLAGS = -module -avoid-version
diff --git a/cli/extensions/libct_proto_icmp.c b/cli/extensions/libct_proto_icmp.c
new file mode 100644
index 0000000..e7cb04d
--- /dev/null
+++ b/cli/extensions/libct_proto_icmp.c
@@ -0,0 +1,108 @@
+/*
+ * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
+ *	       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 <stdlib.h>
+#include <netinet/in.h> /* For htons */
+#include <netinet/ip_icmp.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_icmp.h>
+#include "conntrack.h"
+
+static struct option opts[] = {
+	{"icmp-type", 1, 0, '1'},
+	{"icmp-code", 1, 0, '2'},
+	{"icmp-id", 1, 0, '3'},
+	{0, 0, 0, 0}
+};
+
+static void help()
+{
+	fprintf(stdout, "--icmp-type            icmp type\n");
+	fprintf(stdout, "--icmp-code            icmp code\n");
+	fprintf(stdout, "--icmp-id              icmp id\n");
+}
+
+/* Add 1; spaces filled with 0. */
+static u_int8_t invmap[]
+	= { [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
+	    [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
+	    [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
+	    [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
+	    [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
+	    [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
+	    [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
+	    [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1};
+
+static int parse(char c, char *argv[], 
+		 struct nfct_tuple *orig,
+		 struct nfct_tuple *reply,
+		 struct nfct_tuple *exptuple,
+		 struct nfct_tuple *mask,
+		 union nfct_protoinfo *proto,
+		 unsigned int *flags)
+{
+	switch(c) {
+		case '1':
+			if (optarg) {
+				orig->l4dst.icmp.type = atoi(optarg);
+				reply->l4dst.icmp.type =
+					invmap[orig->l4dst.icmp.type] - 1;
+				*flags |= ICMP_TYPE;
+			}
+			break;
+		case '2':
+			if (optarg) {
+				orig->l4dst.icmp.code = atoi(optarg);
+				reply->l4dst.icmp.code = 0;
+				*flags |= ICMP_CODE;
+			}
+			break;
+		case '3':
+			if (optarg) {
+				orig->l4src.icmp.id = htons(atoi(optarg));
+				reply->l4dst.icmp.id = 0;
+				*flags |= ICMP_ID;
+			}
+			break;
+	}
+	return 1;
+}
+
+static int final_check(unsigned int flags,
+		       unsigned int command,
+		       struct nfct_tuple *orig,
+		       struct nfct_tuple *reply)
+{
+	if (!(flags & ICMP_TYPE))
+		return 0;
+	else if (!(flags & ICMP_CODE))
+		return 0;
+
+	return 1;
+}
+
+static struct ctproto_handler icmp = {
+	.name 		= "icmp",
+	.protonum	= IPPROTO_ICMP,
+	.parse_opts	= parse,
+	.final_check	= final_check,
+	.help		= help,
+	.opts		= opts,
+	.version	= VERSION,
+};
+
+static void __attribute__ ((constructor)) init(void);
+
+static void init(void)
+{
+	register_proto(&icmp);
+}
diff --git a/cli/extensions/libct_proto_icmp.man b/cli/extensions/libct_proto_icmp.man
new file mode 100644
index 0000000..3b860d0
--- /dev/null
+++ b/cli/extensions/libct_proto_icmp.man
@@ -0,0 +1,10 @@
+This module matches on ICMP-specific fields.
+.TP
+.BI "--icmp-type " "TYPE"
+ICMP Type. Has to be specified numerically.
+.TP
+.BI "--icmp-code " "CODE"
+ICMP Code. Has to be specified numerically.
+.TP
+.BI "--icmp-id " "ID"
+ICMP Id. Has to be specified numerically.
diff --git a/cli/extensions/libct_proto_sctp.c b/cli/extensions/libct_proto_sctp.c
new file mode 100644
index 0000000..1c8f0d1
--- /dev/null
+++ b/cli/extensions/libct_proto_sctp.c
@@ -0,0 +1,164 @@
+/*
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ *     2006 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 "conntrack.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_sctp.h>
+
+static struct option opts[] = {
+	{"orig-port-src", 1, 0, '1'},
+	{"orig-port-dst", 1, 0, '2'},
+	{"reply-port-src", 1, 0, '3'},
+	{"reply-port-dst", 1, 0, '4'},
+	{"state", 1, 0, '5'},
+	{"tuple-port-src", 1, 0, '6'},
+	{"tuple-port-dst", 1, 0, '7'},
+	{0, 0, 0, 0}
+};
+
+static const char *states[] = {
+	"NONE",
+	"CLOSED",
+	"COOKIE_WAIT",
+	"COOKIE_ECHOED",
+	"ESTABLISHED",
+	"SHUTDOWN_SENT",
+	"SHUTDOWN_RECV",
+	"SHUTDOWN_ACK_SENT",
+};
+
+static void help()
+{
+	fprintf(stdout, "--orig-port-src        original source port\n");
+	fprintf(stdout, "--orig-port-dst        original destination port\n");
+	fprintf(stdout, "--reply-port-src       reply source port\n");
+	fprintf(stdout, "--reply-port-dst       reply destination port\n");
+	fprintf(stdout, "--state                SCTP state, fe. ESTABLISHED\n");
+	fprintf(stdout, "--tuple-port-src	expectation tuple src port\n");
+	fprintf(stdout, "--tuple-port-src	expectation tuple dst port\n");
+}
+
+static int parse_options(char c, char *argv[], 
+			 struct nfct_tuple *orig,
+			 struct nfct_tuple *reply,
+			 struct nfct_tuple *exptuple,
+			 struct nfct_tuple *mask,
+			 union nfct_protoinfo *proto,
+			 unsigned int *flags)
+{
+	switch(c) {
+		case '1':
+			if (optarg) {
+				orig->l4src.sctp.port = htons(atoi(optarg));
+				*flags |= SCTP_ORIG_SPORT;
+			}
+			break;
+		case '2':
+			if (optarg) {
+				orig->l4dst.sctp.port = htons(atoi(optarg));
+				*flags |= SCTP_ORIG_DPORT;
+			}
+			break;
+		case '3':
+			if (optarg) {
+				reply->l4src.sctp.port = htons(atoi(optarg));
+				*flags |= SCTP_REPL_SPORT;
+			}
+			break;
+		case '4':
+			if (optarg) {
+				reply->l4dst.sctp.port = htons(atoi(optarg));
+				*flags |= SCTP_REPL_DPORT;
+			}
+			break;
+		case '5':
+			if (optarg) {
+				int i;
+				for (i=0; i<10; i++) {
+					if (strcmp(optarg, states[i]) == 0) {
+						/* FIXME: Add state to
+						 * nfct_protoinfo
+						proto->sctp.state = i; */
+						break;
+					}
+				}
+				if (i == 10) {
+					printf("doh?\n");
+					return 0;
+				}
+				*flags |= SCTP_STATE;
+			}
+			break;
+		case '6':
+			if (optarg) {
+				exptuple->l4src.sctp.port = htons(atoi(optarg));
+				*flags |= SCTP_EXPTUPLE_SPORT;
+			}
+			break;
+		case '7':
+			if (optarg) {
+				exptuple->l4dst.sctp.port = htons(atoi(optarg));
+				*flags |= SCTP_EXPTUPLE_DPORT;
+			}
+
+	}
+	return 1;
+}
+
+static int final_check(unsigned int flags,
+		       unsigned int command,
+		       struct nfct_tuple *orig,
+		       struct nfct_tuple *reply)
+{
+	int ret = 0;
+	
+	if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) 
+	    && !(flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) {
+		reply->l4src.sctp.port = orig->l4dst.sctp.port;
+		reply->l4dst.sctp.port = orig->l4src.sctp.port;
+		ret = 1;
+	} else if (!(flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT))
+	            && (flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) {
+		orig->l4src.sctp.port = reply->l4dst.sctp.port;
+		orig->l4dst.sctp.port = reply->l4src.sctp.port;
+		ret = 1;
+	}
+	if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) 
+	    && ((flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))))
+		ret = 1;
+
+	/* --state is missing and we are trying to create a conntrack */
+	if (ret && (command & CT_CREATE) && (!(flags & SCTP_STATE)))
+		ret = 0;
+
+	return ret;
+}
+
+static struct ctproto_handler sctp = {
+	.name 			= "sctp",
+	.protonum		= IPPROTO_SCTP,
+	.parse_opts		= parse_options,
+	.final_check		= final_check,
+	.help			= help,
+	.opts			= opts,
+	.version		= VERSION,
+};
+
+static void __attribute__ ((constructor)) init(void);
+
+static void init(void)
+{
+	register_proto(&sctp);
+}
diff --git a/cli/extensions/libct_proto_tcp.c b/cli/extensions/libct_proto_tcp.c
new file mode 100644
index 0000000..ee24206
--- /dev/null
+++ b/cli/extensions/libct_proto_tcp.c
@@ -0,0 +1,180 @@
+/*
+ * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
+ *
+ *      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 <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
+
+#include "conntrack.h"
+
+static struct option opts[] = {
+	{"orig-port-src", 1, 0, '1'},
+	{"orig-port-dst", 1, 0, '2'},
+	{"reply-port-src", 1, 0, '3'},
+	{"reply-port-dst", 1, 0, '4'},
+	{"mask-port-src", 1, 0, '5'},
+	{"mask-port-dst", 1, 0, '6'},
+	{"state", 1, 0, '7'},
+	{"tuple-port-src", 1, 0, '8'},
+	{"tuple-port-dst", 1, 0, '9'},
+	{0, 0, 0, 0}
+};
+
+static const char *states[] = {
+	"NONE",
+	"SYN_SENT",
+	"SYN_RECV",
+	"ESTABLISHED",
+	"FIN_WAIT",
+	"CLOSE_WAIT",
+	"LAST_ACK",
+	"TIME_WAIT",
+	"CLOSE",
+	"LISTEN"
+};
+
+static void help()
+{
+	fprintf(stdout, "--orig-port-src        original source port\n");
+	fprintf(stdout, "--orig-port-dst        original destination port\n");
+	fprintf(stdout, "--reply-port-src       reply source port\n");
+	fprintf(stdout, "--reply-port-dst       reply destination port\n");
+	fprintf(stdout, "--mask-port-src	mask source port\n");
+	fprintf(stdout, "--mask-port-dst	mask destination port\n");
+	fprintf(stdout, "--tuple-port-src	expectation tuple src port\n");
+	fprintf(stdout, "--tuple-port-src	expectation tuple dst port\n");
+	fprintf(stdout, "--state                TCP state, fe. ESTABLISHED\n");
+}
+
+static int parse_options(char c, char *argv[], 
+			 struct nfct_tuple *orig,
+			 struct nfct_tuple *reply,
+			 struct nfct_tuple *exptuple,
+			 struct nfct_tuple *mask,
+			 union nfct_protoinfo *proto,
+			 unsigned int *flags)
+{
+	switch(c) {
+		case '1':
+			if (optarg) {
+				orig->l4src.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_ORIG_SPORT;
+			}
+			break;
+		case '2':
+			if (optarg) {
+				orig->l4dst.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_ORIG_DPORT;
+			}
+			break;
+		case '3':
+			if (optarg) {
+				reply->l4src.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_REPL_SPORT;
+			}
+			break;
+		case '4':
+			if (optarg) {
+				reply->l4dst.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_REPL_DPORT;
+			}
+			break;
+		case '5':
+			if (optarg) {
+				mask->l4src.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_MASK_SPORT;
+			}
+			break;
+		case '6':
+			if (optarg) {
+				mask->l4dst.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_MASK_DPORT;
+			}
+			break;
+		case '7':
+			if (optarg) {
+				int i;
+				for (i=0; i<10; i++) {
+					if (strcmp(optarg, states[i]) == 0) {
+						proto->tcp.state = i;
+						break;
+					}
+				}
+				if (i == 10) {
+					printf("doh?\n");
+					return 0;
+				}
+				*flags |= TCP_STATE;
+			}
+			break;
+		case '8':
+			if (optarg) {
+				exptuple->l4src.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_EXPTUPLE_SPORT;
+			}
+			break;
+		case '9':
+			if (optarg) {
+				exptuple->l4dst.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_EXPTUPLE_DPORT;
+			}
+			break;
+	}
+	return 1;
+}
+
+static int final_check(unsigned int flags,
+		       unsigned int command,
+		       struct nfct_tuple *orig,
+		       struct nfct_tuple *reply)
+{
+	int ret = 0;
+	
+	if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) 
+	    && !(flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) {
+		reply->l4src.tcp.port = orig->l4dst.tcp.port;
+		reply->l4dst.tcp.port = orig->l4src.tcp.port;
+		ret = 1;
+	} else if (!(flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT))
+	            && (flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) {
+		orig->l4src.tcp.port = reply->l4dst.tcp.port;
+		orig->l4dst.tcp.port = reply->l4src.tcp.port;
+		ret = 1;
+	}
+	if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) 
+	    && ((flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))))
+		ret = 1;
+
+	/* --state is missing and we are trying to create a conntrack */
+	if (ret && (command & CT_CREATE) && (!(flags & TCP_STATE)))
+		ret = 0;
+
+	return ret;
+}
+
+static struct ctproto_handler tcp = {
+	.name 			= "tcp",
+	.protonum		= IPPROTO_TCP,
+	.parse_opts		= parse_options,
+	.final_check		= final_check,
+	.help			= help,
+	.opts			= opts,
+	.version		= VERSION,
+};
+
+static void __attribute__ ((constructor)) init(void);
+
+static void init(void)
+{
+	register_proto(&tcp);
+}
diff --git a/cli/extensions/libct_proto_tcp.man b/cli/extensions/libct_proto_tcp.man
new file mode 100644
index 0000000..41783f8
--- /dev/null
+++ b/cli/extensions/libct_proto_tcp.man
@@ -0,0 +1,16 @@
+This module matches on TCP-specific fields.
+.TP
+.BI "--orig-port-src " "PORT"
+Source port in original direction
+.TP
+.BI "--orig-port-dst " "PORT"
+Destination port in original direction
+.TP
+.BI "--reply-port-src " "PORT"
+Source port in reply direction
+.TP
+.BI "--reply-port-dst " "PORT"
+Destination port in reply direction
+.TP
+.BI "--state " "[NONE|SYN_SENT|SYN_RECV|ESTABLISHED|FIN_WAIT|CLOSE_WAIT|LAST_ACK|TIME_WAIT|CLOSE|LISTEN]"
+TCP state
diff --git a/cli/extensions/libct_proto_udp.c b/cli/extensions/libct_proto_udp.c
new file mode 100644
index 0000000..48079e0
--- /dev/null
+++ b/cli/extensions/libct_proto_udp.c
@@ -0,0 +1,141 @@
+/*
+ * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
+ *
+ *      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 <netinet/in.h> /* For htons */
+#include "conntrack.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_udp.h>
+
+static struct option opts[] = {
+	{"orig-port-src", 1, 0, '1'},
+	{"orig-port-dst", 1, 0, '2'},
+	{"reply-port-src", 1, 0, '3'},
+	{"reply-port-dst", 1, 0, '4'},
+	{"mask-port-src", 1, 0, '5'},
+	{"mask-port-dst", 1, 0, '6'},
+	{"tuple-port-src", 1, 0, '7'},
+	{"tuple-port-dst", 1, 0, '8'},
+	{0, 0, 0, 0}
+};
+
+static void help()
+{
+	fprintf(stdout, "--orig-port-src        original source port\n");
+	fprintf(stdout, "--orig-port-dst        original destination port\n");
+	fprintf(stdout, "--reply-port-src       reply source port\n");
+	fprintf(stdout, "--reply-port-dst       reply destination port\n");
+	fprintf(stdout, "--mask-port-src	mask source port\n");
+	fprintf(stdout, "--mask-port-dst	mask destination port\n");
+	fprintf(stdout, "--tuple-port-src	expectation tuple src port\n");
+	fprintf(stdout, "--tuple-port-src	expectation tuple dst port\n");
+}
+
+static int parse_options(char c, char *argv[], 
+			 struct nfct_tuple *orig,
+			 struct nfct_tuple *reply,
+			 struct nfct_tuple *exptuple,
+			 struct nfct_tuple *mask,
+			 union nfct_protoinfo *proto,
+			 unsigned int *flags)
+{
+	switch(c) {
+		case '1':
+			if (optarg) {
+				orig->l4src.udp.port = htons(atoi(optarg));
+				*flags |= UDP_ORIG_SPORT;
+			}
+			break;
+		case '2':
+			if (optarg) {
+				orig->l4dst.udp.port = htons(atoi(optarg));
+				*flags |= UDP_ORIG_DPORT;
+			}
+			break;
+		case '3':
+			if (optarg) {
+				reply->l4src.udp.port = htons(atoi(optarg));
+				*flags |= UDP_REPL_SPORT;
+			}
+			break;
+		case '4':
+			if (optarg) {
+				reply->l4dst.udp.port = htons(atoi(optarg));
+				*flags |= UDP_REPL_DPORT;
+			}
+			break;
+		case '5':
+			if (optarg) {
+				mask->l4src.udp.port = htons(atoi(optarg));
+				*flags |= UDP_MASK_SPORT;
+			}
+			break;
+		case '6':
+			if (optarg) {
+				mask->l4dst.udp.port = htons(atoi(optarg));
+				*flags |= UDP_MASK_DPORT;
+			}
+			break;
+		case '7':
+			if (optarg) {
+				exptuple->l4src.udp.port = htons(atoi(optarg));
+				*flags |= UDP_EXPTUPLE_SPORT;
+			}
+			break;
+		case '8':
+			if (optarg) {
+				exptuple->l4dst.udp.port = htons(atoi(optarg));
+				*flags |= UDP_EXPTUPLE_DPORT;
+			}
+
+	}
+	return 1;
+}
+
+static int final_check(unsigned int flags,
+		       unsigned int command,
+		       struct nfct_tuple *orig,
+		       struct nfct_tuple *reply)
+{
+	if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) 
+	    && !(flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) {
+		reply->l4src.udp.port = orig->l4dst.udp.port;
+		reply->l4dst.udp.port = orig->l4src.udp.port;
+		return 1;
+	} else if (!(flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT))
+	            && (flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) {
+		orig->l4src.udp.port = reply->l4dst.udp.port;
+		orig->l4dst.udp.port = reply->l4src.udp.port;
+		return 1;
+	}
+	if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) 
+	    && ((flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))))
+		return 1;
+
+	return 0;
+}
+
+static struct ctproto_handler udp = {
+	.name 			= "udp",
+	.protonum		= IPPROTO_UDP,
+	.parse_opts		= parse_options,
+	.final_check		= final_check,
+	.help			= help,
+	.opts			= opts,
+	.version		= VERSION,
+};
+
+static void __attribute__ ((constructor)) init(void);
+
+static void init(void)
+{
+	register_proto(&udp);
+}
diff --git a/cli/extensions/libct_proto_udp.man b/cli/extensions/libct_proto_udp.man
new file mode 100644
index 0000000..c67fedf
--- /dev/null
+++ b/cli/extensions/libct_proto_udp.man
@@ -0,0 +1,13 @@
+This module matches on UDP-specific fields.
+.TP
+.BI "--orig-port-src " "PORT"
+Source port in original direction
+.TP
+.BI "--orig-port-dst " "PORT"
+Destination port in original direction
+.TP
+.BI "--reply-port-src " "PORT"
+Source port in reply direction
+.TP
+.BI "--reply-port-dst " "PORT"
+Destination port in reply direction
diff --git a/cli/include/Makefile.am b/cli/include/Makefile.am
new file mode 100644
index 0000000..ef7ce45
--- /dev/null
+++ b/cli/include/Makefile.am
@@ -0,0 +1,2 @@
+
+noinst_HEADERS = conntrack.h linux_list.h
diff --git a/cli/include/conntrack.h b/cli/include/conntrack.h
new file mode 100644
index 0000000..fb3b9b6
--- /dev/null
+++ b/cli/include/conntrack.h
@@ -0,0 +1,160 @@
+#ifndef _CONNTRACK_H
+#define _CONNTRACK_H
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#include "linux_list.h"
+#include <getopt.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+#define PROGNAME "conntrack"
+
+#include <netinet/in.h>
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP 132
+#endif
+
+enum action {
+	CT_NONE		= 0,
+	
+	CT_LIST_BIT 	= 0,
+	CT_LIST 	= (1 << CT_LIST_BIT),
+	
+	CT_CREATE_BIT	= 1,
+	CT_CREATE	= (1 << CT_CREATE_BIT),
+
+	CT_UPDATE_BIT	= 2,
+	CT_UPDATE	= (1 << CT_UPDATE_BIT),
+	
+	CT_DELETE_BIT	= 3,
+	CT_DELETE	= (1 << CT_DELETE_BIT),
+	
+	CT_GET_BIT	= 4,
+	CT_GET		= (1 << CT_GET_BIT),
+
+	CT_FLUSH_BIT	= 5,
+	CT_FLUSH	= (1 << CT_FLUSH_BIT),
+
+	CT_EVENT_BIT	= 6,
+	CT_EVENT	= (1 << CT_EVENT_BIT),
+
+	CT_VERSION_BIT	= 7,
+	CT_VERSION	= (1 << CT_VERSION_BIT),
+
+	CT_HELP_BIT	= 8,
+	CT_HELP		= (1 << CT_HELP_BIT),
+
+	EXP_LIST_BIT 	= 9,
+	EXP_LIST 	= (1 << EXP_LIST_BIT),
+	
+	EXP_CREATE_BIT	= 10,
+	EXP_CREATE	= (1 << EXP_CREATE_BIT),
+	
+	EXP_DELETE_BIT	= 11,
+	EXP_DELETE	= (1 << EXP_DELETE_BIT),
+	
+	EXP_GET_BIT	= 12,
+	EXP_GET		= (1 << EXP_GET_BIT),
+
+	EXP_FLUSH_BIT	= 13,
+	EXP_FLUSH	= (1 << EXP_FLUSH_BIT),
+
+	EXP_EVENT_BIT	= 14,
+	EXP_EVENT	= (1 << EXP_EVENT_BIT),
+};
+#define NUMBER_OF_CMD   15
+
+enum options {
+	CT_OPT_ORIG_SRC_BIT	= 0,
+	CT_OPT_ORIG_SRC 	= (1 << CT_OPT_ORIG_SRC_BIT),
+	
+	CT_OPT_ORIG_DST_BIT	= 1,
+	CT_OPT_ORIG_DST		= (1 << CT_OPT_ORIG_DST_BIT),
+
+	CT_OPT_ORIG		= (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST),
+	
+	CT_OPT_REPL_SRC_BIT	= 2,
+	CT_OPT_REPL_SRC		= (1 << CT_OPT_REPL_SRC_BIT),
+	
+	CT_OPT_REPL_DST_BIT	= 3,
+	CT_OPT_REPL_DST		= (1 << CT_OPT_REPL_DST_BIT),
+
+	CT_OPT_REPL		= (CT_OPT_REPL_SRC | CT_OPT_REPL_DST),
+
+	CT_OPT_PROTO_BIT	= 4,
+	CT_OPT_PROTO		= (1 << CT_OPT_PROTO_BIT),
+
+	CT_OPT_TIMEOUT_BIT	= 5,
+	CT_OPT_TIMEOUT		= (1 << CT_OPT_TIMEOUT_BIT),
+
+	CT_OPT_STATUS_BIT	= 6,
+	CT_OPT_STATUS		= (1 << CT_OPT_STATUS_BIT),
+
+	CT_OPT_ZERO_BIT		= 7,
+	CT_OPT_ZERO		= (1 << CT_OPT_ZERO_BIT),
+
+	CT_OPT_EVENT_MASK_BIT	= 8,
+	CT_OPT_EVENT_MASK	= (1 << CT_OPT_EVENT_MASK_BIT),
+
+	CT_OPT_EXP_SRC_BIT	= 9,
+	CT_OPT_EXP_SRC		= (1 << CT_OPT_EXP_SRC_BIT),
+
+	CT_OPT_EXP_DST_BIT	= 10,
+	CT_OPT_EXP_DST		= (1 << CT_OPT_EXP_DST_BIT),
+
+	CT_OPT_MASK_SRC_BIT	= 11,
+	CT_OPT_MASK_SRC		= (1 << CT_OPT_MASK_SRC_BIT),
+
+	CT_OPT_MASK_DST_BIT	= 12,
+	CT_OPT_MASK_DST		= (1 << CT_OPT_MASK_DST_BIT),
+
+	CT_OPT_NATRANGE_BIT	= 13,
+	CT_OPT_NATRANGE		= (1 << CT_OPT_NATRANGE_BIT),
+
+	CT_OPT_MARK_BIT		= 14,
+	CT_OPT_MARK		= (1 << CT_OPT_MARK_BIT),
+
+	CT_OPT_ID_BIT		= 15,
+	CT_OPT_ID		= (1 << CT_OPT_ID_BIT),
+
+	CT_OPT_FAMILY_BIT	= 16,
+	CT_OPT_FAMILY		= (1 << CT_OPT_FAMILY_BIT),
+
+	CT_OPT_MAX_BIT		= CT_OPT_FAMILY_BIT
+};
+#define NUMBER_OF_OPT   CT_OPT_MAX_BIT+1
+
+struct ctproto_handler {
+	struct list_head 	head;
+
+	char 			*name;
+	u_int16_t 		protonum;
+	char			*version;
+
+	enum ctattr_protoinfo	protoinfo_attr;
+	
+	int (*parse_opts)(char c, char *argv[], 
+		     struct nfct_tuple *orig,
+		     struct nfct_tuple *reply,
+		     struct nfct_tuple *exptuple,
+		     struct nfct_tuple *mask,
+		     union nfct_protoinfo *proto,
+		     unsigned int *flags);
+
+	int (*final_check)(unsigned int flags,
+			   unsigned int command,
+			   struct nfct_tuple *orig,
+			   struct nfct_tuple *reply);
+
+	void (*help)();
+
+	struct option 		*opts;
+
+	unsigned int		option_offset;
+};
+
+extern void register_proto(struct ctproto_handler *h);
+
+#endif
diff --git a/cli/include/linux_list.h b/cli/include/linux_list.h
new file mode 100644
index 0000000..57b56d7
--- /dev/null
+++ b/cli/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/cli/src/Makefile.am b/cli/src/Makefile.am
new file mode 100644
index 0000000..83cad99
--- /dev/null
+++ b/cli/src/Makefile.am
@@ -0,0 +1,7 @@
+include $(top_srcdir)/Make_global.am
+LIBS = @CONNTRACK_LIBS@
+
+sbin_PROGRAMS = conntrack
+conntrack_SOURCES = conntrack.c
+conntrack_LDFLAGS = -rdynamic
+ 
diff --git a/cli/src/conntrack.c b/cli/src/conntrack.c
new file mode 100644
index 0000000..30fbf69
--- /dev/null
+++ b/cli/src/conntrack.c
@@ -0,0 +1,1131 @@
+/*
+ * (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.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Note:
+ *	Yes, portions of this code has been stolen from iptables ;)
+ *	Special thanks to the the Netfilter Core Team.
+ *	Thanks to Javier de Miguel Rodriguez <jmiguel at talika.eii.us.es>
+ *	for introducing me to advanced firewalling stuff.
+ *
+ *						--pablo 13/04/2005
+ *
+ * 2005-04-16 Harald Welte <laforge@netfilter.org>: 
+ * 	Add support for conntrack accounting and conntrack mark
+ * 2005-06-23 Harald Welte <laforge@netfilter.org>:
+ * 	Add support for expect creation
+ * 2005-09-24 Harald Welte <laforge@netfilter.org>:
+ * 	Remove remaints of "-A"
+ *
+ */
+#include <stdio.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <string.h>
+#include "linux_list.h"
+#include "conntrack.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_ipv4.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_ipv6.h>
+
+static const char cmdflags[NUMBER_OF_CMD]
+= {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'};
+
+static const char cmd_need_param[NUMBER_OF_CMD]
+= { 2,  0,  0,  0,  0,  2,  2,  2,  2,  2,  0,  0,  0,  2,  2 };
+
+static const char optflags[NUMBER_OF_OPT]
+= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f'};
+
+static struct option original_opts[] = {
+	{"dump", 2, 0, 'L'},
+	{"create", 1, 0, 'I'},
+	{"delete", 1, 0, 'D'},
+	{"update", 1, 0, 'U'},
+	{"get", 1, 0, 'G'},
+	{"flush", 1, 0, 'F'},
+	{"event", 1, 0, 'E'},
+	{"version", 0, 0, 'V'},
+	{"help", 0, 0, 'h'},
+	{"orig-src", 1, 0, 's'},
+	{"orig-dst", 1, 0, 'd'},
+	{"reply-src", 1, 0, 'r'},
+	{"reply-dst", 1, 0, 'q'},
+	{"protonum", 1, 0, 'p'},
+	{"timeout", 1, 0, 't'},
+	{"status", 1, 0, 'u'},
+	{"zero", 0, 0, 'z'},
+	{"event-mask", 1, 0, 'e'},
+	{"tuple-src", 1, 0, '['},
+	{"tuple-dst", 1, 0, ']'},
+	{"mask-src", 1, 0, '{'},
+	{"mask-dst", 1, 0, '}'},
+	{"nat-range", 1, 0, 'a'},
+	{"mark", 1, 0, 'm'},
+	{"id", 2, 0, 'i'},
+	{"family", 1, 0, 'f'},
+	{0, 0, 0, 0}
+};
+
+#define OPTION_OFFSET 256
+
+static struct nfct_handle *cth;
+static struct option *opts = original_opts;
+static unsigned int global_option_offset = 0;
+
+/* Table of legal combinations of commands and options.  If any of the
+ * given commands make an option legal, that option is legal (applies to
+ * CMD_LIST and CMD_ZERO only).
+ * Key:
+ *  0  illegal
+ *  1  compulsory
+ *  2  optional
+ */
+
+static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
+/* Well, it's better than "Re: Linux vs FreeBSD" */
+{
+          /*   s d r q p t u z e x y k l a m i f*/
+/*CT_LIST*/   {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2},
+/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0},
+/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0},
+/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0},
+/*CT_GET*/    {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0},
+/*CT_FLUSH*/  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+/*CT_EVENT*/  {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0},
+/*VERSION*/   {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+/*HELP*/      {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+/*EXP_LIST*/  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2},
+/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0},
+/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0},
+/*EXP_GET*/   {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0},
+/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+};
+
+static char *lib_dir = CONNTRACK_LIB_DIR;
+
+static LIST_HEAD(proto_list);
+
+void register_proto(struct ctproto_handler *h)
+{
+	if (strcmp(h->version, VERSION) != 0) {
+		fprintf(stderr, "plugin `%s': version %s (I'm %s)\n",
+			h->name, h->version, VERSION);
+		exit(1);
+	}
+	list_add(&h->head, &proto_list);
+}
+
+static struct ctproto_handler *findproto(char *name)
+{
+	struct list_head *i;
+	struct ctproto_handler *cur = NULL, *handler = NULL;
+
+	if (!name) 
+		return handler;
+
+	lib_dir = getenv("CONNTRACK_LIB_DIR");
+	if (!lib_dir)
+		lib_dir = CONNTRACK_LIB_DIR;
+
+	list_for_each(i, &proto_list) {
+		cur = (struct ctproto_handler *) i;
+		if (strcmp(cur->name, name) == 0) {
+			handler = cur;
+			break;
+		}
+	}
+
+	if (!handler) {
+		char path[sizeof("ct_proto_.so")
+			 + strlen(name) + strlen(lib_dir)];
+                sprintf(path, "%s/ct_proto_%s.so", lib_dir, name);
+		if (dlopen(path, RTLD_NOW))
+			handler = findproto(name);
+		else
+			fprintf(stderr, "%s\n", dlerror());
+	}
+
+	return handler;
+}
+
+enum exittype {
+        OTHER_PROBLEM = 1,
+        PARAMETER_PROBLEM,
+        VERSION_PROBLEM
+};
+
+void extension_help(struct ctproto_handler *h)
+{
+	fprintf(stdout, "\n");
+	fprintf(stdout, "Proto `%s' help:\n", h->name);
+	h->help();
+}
+
+void
+exit_tryhelp(int status)
+{
+	fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
+			PROGNAME, PROGNAME);
+	exit(status);
+}
+
+static void
+exit_error(enum exittype status, char *msg, ...)
+{
+	va_list args;
+
+	/* On error paths, make sure that we don't leak the memory
+	 * reserved during options merging */
+	if (opts != original_opts) {
+		free(opts);
+		opts = original_opts;
+		global_option_offset = 0;
+	}
+	va_start(args, msg);
+	fprintf(stderr,"%s v%s: ", PROGNAME, VERSION);
+	vfprintf(stderr, msg, args);
+	va_end(args);
+	fprintf(stderr, "\n");
+	if (status == PARAMETER_PROBLEM)
+		exit_tryhelp(status);
+	exit(status);
+}
+
+static void
+generic_cmd_check(int command, int options)
+{
+	int i;
+	
+	for (i = 0; i < NUMBER_OF_CMD; i++) {
+		if (!(command & (1<<i)))
+			continue;
+
+		if (cmd_need_param[i] == 0 && !options)
+			exit_error(PARAMETER_PROBLEM,
+				   "You need to supply parameters to `-%c'\n",
+				   cmdflags[i]);
+	}
+}
+
+static void
+generic_opt_check(int command, int options)
+{
+	int i, j, legal = 0;
+
+	/* Check that commands are valid with options.  Complicated by the
+	 * fact that if an option is legal with *any* command given, it is
+	 * legal overall (ie. -z and -l).
+	 */
+	for (i = 0; i < NUMBER_OF_OPT; i++) {
+		legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
+
+		for (j = 0; j < NUMBER_OF_CMD; j++) {
+			if (!(command & (1<<j)))
+				continue;
+
+			if (!(options & (1<<i))) {
+				if (commands_v_options[j][i] == 1) 
+					exit_error(PARAMETER_PROBLEM, 
+						   "You need to supply the "
+						   "`-%c' option for this "
+						   "command\n", optflags[i]);
+			} else {
+				if (commands_v_options[j][i] != 0)
+					legal = 1;
+				else if (legal == 0)
+					legal = -1;
+			}
+		}
+		if (legal == -1)
+			exit_error(PARAMETER_PROBLEM, "Illegal option `-%c' "
+				   "with this command\n", optflags[i]);
+	}
+}
+
+static struct option *
+merge_options(struct option *oldopts, const struct option *newopts,
+	      unsigned int *option_offset)
+{
+	unsigned int num_old, num_new, i;
+	struct option *merge;
+
+	for (num_old = 0; oldopts[num_old].name; num_old++);
+	for (num_new = 0; newopts[num_new].name; num_new++);
+
+	global_option_offset += OPTION_OFFSET;
+	*option_offset = global_option_offset;
+
+	merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
+	memcpy(merge, oldopts, num_old * sizeof(struct option));
+	for (i = 0; i < num_new; i++) {
+		merge[num_old + i] = newopts[i];
+		merge[num_old + i].val += *option_offset;
+	}
+	memset(merge + num_old + num_new, 0, sizeof(struct option));
+
+	return merge;
+}
+
+/* From linux/errno.h */
+#define ENOTSUPP        524     /* Operation is not supported */
+
+/* Translates errno numbers into more human-readable form than strerror. */
+const char *
+err2str(int err, enum action command)
+{
+	unsigned int i;
+	struct table_struct {
+		enum action act;
+		int err;
+		const char *message;
+	} table [] =
+	  { { CT_LIST, -ENOTSUPP, "function not implemented" },
+	    { 0xFFFF, -EINVAL, "invalid parameters" },
+	    { CT_CREATE, -EEXIST, "Such conntrack exists, try -U to update" },
+	    { CT_CREATE|CT_GET|CT_DELETE, -ENOENT, 
+		    "such conntrack doesn't exist" },
+	    { CT_CREATE|CT_GET, -ENOMEM, "not enough memory" },
+	    { CT_GET, -EAFNOSUPPORT, "protocol not supported" },
+	    { CT_CREATE, -ETIME, "conntrack has expired" },
+	    { EXP_CREATE, -ENOENT, "master conntrack not found" },
+	    { EXP_CREATE, -EINVAL, "invalid parameters" },
+	    { ~0UL, -EPERM, "sorry, you must be root or get "
+		    	    "CAP_NET_ADMIN capability to do this"}
+	  };
+
+	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
+		if ((table[i].act & command) && table[i].err == err)
+			return table[i].message;
+	}
+
+	return strerror(err);
+}
+
+#define PARSE_STATUS 0
+#define PARSE_EVENT 1
+#define PARSE_MAX 2
+
+static struct parse_parameter {
+	char 	*parameter[6];
+	size_t  size;
+	unsigned int value[6];
+} parse_array[PARSE_MAX] = {
+	{ {"ASSURED", "SEEN_REPLY", "UNSET", "SRC_NAT", "DST_NAT","FIXED_TIMEOUT"}, 6,
+	  { IPS_ASSURED, IPS_SEEN_REPLY, 0, 
+	    IPS_SRC_NAT_DONE, IPS_DST_NAT_DONE, IPS_FIXED_TIMEOUT} },
+	{ {"ALL", "NEW", "UPDATES", "DESTROY"}, 4,
+	  {~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE, 
+	   NF_NETLINK_CONNTRACK_DESTROY} },
+};
+
+static int
+do_parse_parameter(const char *str, size_t strlen, unsigned int *value, 
+		   int parse_type)
+{
+	int i, ret = 0;
+	struct parse_parameter *p = &parse_array[parse_type];
+	
+	for (i = 0; i < p->size; i++)
+		if (strncasecmp(str, p->parameter[i], strlen) == 0) {
+			*value |= p->value[i];
+			ret = 1;
+			break;
+		}
+	
+	return ret;
+}
+
+static void
+parse_parameter(const char *arg, unsigned int *status, int parse_type)
+{
+	const char *comma;
+
+	while ((comma = strchr(arg, ',')) != NULL) {
+		if (comma == arg 
+		    || !do_parse_parameter(arg, comma-arg, status, parse_type))
+			exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg);
+		arg = comma+1;
+	}
+
+	if (strlen(arg) == 0
+	    || !do_parse_parameter(arg, strlen(arg), status, parse_type))
+		exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg);
+}
+
+static void
+add_command(unsigned int *cmd, const int newcmd, const int othercmds)
+{
+	if (*cmd & (~othercmds))
+		exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n");
+	*cmd |= newcmd;
+}
+
+unsigned int check_type(int argc, char *argv[])
+{
+	char *table = NULL;
+
+	/* Nasty bug or feature in getopt_long ? 
+	 * It seems that it behaves badly with optional arguments.
+	 * Fortunately, I just stole the fix from iptables ;) */
+	if (optarg)
+		return 0;
+	else if (optind < argc && argv[optind][0] != '-' 
+			&& argv[optind][0] != '!')
+		table = argv[optind++];
+	
+	if (!table)
+		return 0;
+		
+	if (strncmp("expect", table, 6) == 0)
+		return 1;
+	else if (strncmp("conntrack", table, 9) == 0)
+		return 0;
+	else
+		exit_error(PARAMETER_PROBLEM, "unknown type `%s'\n", table);
+
+	return 0;
+}
+
+static void set_family(int *family, int new)
+{
+	if (*family == AF_UNSPEC)
+		*family = new;
+	else if (*family != new)
+		exit_error(PARAMETER_PROBLEM, "mismatched address family\n");
+}
+
+struct addr_parse {
+	struct in_addr addr;
+	struct in6_addr addr6;
+	unsigned int family;
+};
+
+int __parse_inetaddr(const char *cp, struct addr_parse *parse)
+{
+	if (inet_aton(cp, &parse->addr))
+		return AF_INET;
+#ifdef HAVE_INET_PTON_IPV6
+	else if (inet_pton(AF_INET6, cp, &parse->addr6) > 0)
+		return AF_INET6;
+#endif
+
+	exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp);
+}
+
+int parse_inetaddr(const char *cp, union nfct_address *address)
+{
+	struct addr_parse parse;
+	int ret;
+	
+	if ((ret = __parse_inetaddr(cp, &parse)) == AF_INET)
+		address->v4 = parse.addr.s_addr;
+	else if (ret == AF_INET6)
+		memcpy(address->v6, &parse.addr6, sizeof(parse.addr6));
+
+	return ret;
+}
+
+/* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */
+static void
+nat_parse(char *arg, int portok, struct nfct_nat *range)
+{
+	char *colon, *dash, *error;
+	struct addr_parse parse;
+
+	memset(range, 0, sizeof(range));
+	colon = strchr(arg, ':');
+
+	if (colon) {
+		int port;
+
+		if (!portok)
+			exit_error(PARAMETER_PROBLEM,
+				   "Need TCP or UDP with port specification");
+
+		port = atoi(colon+1);
+		if (port == 0 || port > 65535)
+			exit_error(PARAMETER_PROBLEM,
+				   "Port `%s' not valid\n", colon+1);
+
+		error = strchr(colon+1, ':');
+		if (error)
+			exit_error(PARAMETER_PROBLEM,
+				   "Invalid port:port syntax - use dash\n");
+
+		dash = strchr(colon, '-');
+		if (!dash) {
+			range->l4min.tcp.port
+				= range->l4max.tcp.port
+				= htons(port);
+		} else {
+			int maxport;
+
+			maxport = atoi(dash + 1);
+			if (maxport == 0 || maxport > 65535)
+				exit_error(PARAMETER_PROBLEM,
+					   "Port `%s' not valid\n", dash+1);
+			if (maxport < port)
+				/* People are stupid.  */
+				exit_error(PARAMETER_PROBLEM,
+					   "Port range `%s' funky\n", colon+1);
+			range->l4min.tcp.port = htons(port);
+			range->l4max.tcp.port = htons(maxport);
+		}
+		/* Starts with a colon? No IP info... */
+		if (colon == arg)
+			return;
+		*colon = '\0';
+	}
+
+	dash = strchr(arg, '-');
+	if (colon && dash && dash > colon)
+		dash = NULL;
+
+	if (dash)
+		*dash = '\0';
+
+	if (__parse_inetaddr(arg, &parse) != AF_INET)
+		return;
+
+	range->min_ip = parse.addr.s_addr;
+	if (dash) {
+		if (__parse_inetaddr(dash+1, &parse) != AF_INET)
+			return;
+		range->max_ip = parse.addr.s_addr;
+	} else
+		range->max_ip = parse.addr.s_addr;
+}
+
+static void event_sighandler(int s)
+{
+	fprintf(stdout, "Now closing conntrack event dumping...\n");
+	nfct_close(cth);
+	exit(0);
+}
+
+static const char usage_commands[] =
+	"Commands:\n"
+	"  -L [table] [options]\t\tList conntrack or expectation table\n"
+	"  -G [table] parameters\t\tGet conntrack or expectation\n"
+	"  -D [table] parameters\t\tDelete conntrack or expectation\n"
+	"  -I [table] parameters\t\tCreate a conntrack or expectation\n"
+	"  -U [table] parameters\t\tUpdate a conntrack\n"
+	"  -E [table] [options]\t\tShow events\n"
+	"  -F [table]\t\t\tFlush table\n";
+
+static const char usage_tables[] =
+	"Tables: conntrack, expect\n";
+
+static const char usage_conntrack_parameters[] =
+	"Conntrack parameters and options:\n"
+	"  -a, --nat-range min_ip[-max_ip]\tNAT ip range\n"
+	"  -m, --mark mark\t\t\tSet mark\n"
+	"  -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n"
+	"  -z, --zero \t\t\t\tZero counters while listing\n"
+	;
+
+static const char usage_expectation_parameters[] =
+	"Expectation parameters and options:\n"
+	"  --tuple-src ip\tSource address in expect tuple\n"
+	"  --tuple-dst ip\tDestination address in expect tuple\n"
+	"  --mask-src ip\t\tSource mask address\n"
+	"  --mask-dst ip\t\tDestination mask address\n";
+
+static const char usage_parameters[] =
+	"Common parameters and options:\n"
+	"  -s, --orig-src ip\t\tSource address from original direction\n"
+	"  -d, --orig-dst ip\t\tDestination address from original direction\n"
+	"  -r, --reply-src ip\t\tSource addres from reply direction\n"
+	"  -q, --reply-dst ip\t\tDestination address from reply direction\n"
+	"  -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n"
+	"  -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n"
+	"  -t, --timeout timeout\t\tSet timeout\n"
+	"  -u, --status status\t\tSet status, eg. ASSURED\n"
+	"  -i, --id [id]\t\t\tShow or set conntrack ID\n"
+	;
+  
+
+void usage(char *prog) {
+	fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION);
+	fprintf(stdout, "Usage: %s [commands] [options]\n", prog);
+
+	fprintf(stdout, "\n%s", usage_commands);
+	fprintf(stdout, "\n%s", usage_tables);
+	fprintf(stdout, "\n%s", usage_conntrack_parameters);
+	fprintf(stdout, "\n%s", usage_expectation_parameters);
+	fprintf(stdout, "\n%s", usage_parameters);
+}
+
+#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK)
+
+static struct nfct_tuple orig, reply, mask;
+static struct nfct_tuple exptuple;
+static struct ctproto_handler *h;
+static union nfct_protoinfo proto;
+static struct nfct_nat range;
+static struct nfct_conntrack *ct;
+static struct nfct_expect *exp;
+static unsigned long timeout;
+static unsigned int status;
+static unsigned int mark;
+static unsigned int id = NFCT_ANY_ID;
+static struct nfct_conntrack_compare cmp;
+
+int main(int argc, char *argv[])
+{
+	int c;
+	unsigned int command = 0, options = 0;
+	unsigned int type = 0, event_mask = 0;
+	unsigned int l3flags = 0, l4flags = 0, metaflags = 0;
+	int res = 0;
+	int family = AF_UNSPEC;
+	struct nfct_conntrack_compare *pcmp;
+
+	while ((c = getopt_long(argc, argv, 
+		"L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:", 
+		opts, NULL)) != -1) {
+	switch(c) {
+		case 'L':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_LIST, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_LIST, CT_NONE);
+			break;
+		case 'I':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_CREATE, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_CREATE, CT_NONE);
+			break;
+		case 'U':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_UPDATE, CT_NONE);
+			else
+				exit_error(PARAMETER_PROBLEM, "Can't update "
+					   "expectations");
+			break;
+		case 'D':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_DELETE, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_DELETE, CT_NONE);
+			break;
+		case 'G':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_GET, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_GET, CT_NONE);
+			break;
+		case 'F':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_FLUSH, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_FLUSH, CT_NONE);
+			break;
+		case 'E':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_EVENT, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_EVENT, CT_NONE);
+			break;
+		case 'V':
+			add_command(&command, CT_VERSION, CT_NONE);
+			break;
+		case 'h':
+			add_command(&command, CT_HELP, CT_NONE);
+			break;
+		case 's':
+			options |= CT_OPT_ORIG_SRC;
+			if (optarg) {
+				orig.l3protonum =
+					parse_inetaddr(optarg, &orig.src);
+				set_family(&family, orig.l3protonum);
+				if (orig.l3protonum == AF_INET)
+					l3flags |= IPV4_ORIG_SRC;
+				else if (orig.l3protonum == AF_INET6)
+					l3flags |= IPV6_ORIG_SRC;
+			}
+			break;
+		case 'd':
+			options |= CT_OPT_ORIG_DST;
+			if (optarg) {
+				orig.l3protonum = 
+					parse_inetaddr(optarg, &orig.dst);
+				set_family(&family, orig.l3protonum);
+				if (orig.l3protonum == AF_INET)
+					l3flags |= IPV4_ORIG_DST;
+				else if (orig.l3protonum == AF_INET6)
+					l3flags |= IPV6_ORIG_DST;
+			}
+			break;
+		case 'r':
+			options |= CT_OPT_REPL_SRC;
+			if (optarg) {
+				reply.l3protonum = 
+					parse_inetaddr(optarg, &reply.src);
+				set_family(&family, reply.l3protonum);
+				if (orig.l3protonum == AF_INET)
+					l3flags |= IPV4_REPL_SRC;
+				else if (orig.l3protonum == AF_INET6)
+					l3flags |= IPV6_REPL_SRC;
+			}
+			break;
+		case 'q':
+			options |= CT_OPT_REPL_DST;
+			if (optarg) {
+				reply.l3protonum = 
+					parse_inetaddr(optarg, &reply.dst);
+				set_family(&family, reply.l3protonum);
+				if (orig.l3protonum == AF_INET)
+					l3flags |= IPV4_REPL_DST;
+				else if (orig.l3protonum == AF_INET6)
+					l3flags |= IPV6_REPL_DST;
+			}
+			break;
+		case 'p':
+			options |= CT_OPT_PROTO;
+			h = findproto(optarg);
+			if (!h)
+				exit_error(PARAMETER_PROBLEM, "proto needed\n");
+			orig.protonum = h->protonum;
+			reply.protonum = h->protonum;
+			exptuple.protonum = h->protonum;
+			mask.protonum = h->protonum;
+			opts = merge_options(opts, h->opts, 
+					     &h->option_offset);
+			break;
+		case 't':
+			options |= CT_OPT_TIMEOUT;
+			if (optarg)
+				timeout = atol(optarg);
+			break;
+		case 'u': {
+			if (!optarg)
+				continue;
+
+			options |= CT_OPT_STATUS;
+			parse_parameter(optarg, &status, PARSE_STATUS);
+			break;
+		}
+		case 'e':
+			options |= CT_OPT_EVENT_MASK;
+			parse_parameter(optarg, &event_mask, PARSE_EVENT);
+			break;
+		case 'z':
+			options |= CT_OPT_ZERO;
+			break;
+		case '{':
+			options |= CT_OPT_MASK_SRC;
+			if (optarg) {
+				mask.l3protonum = 
+					parse_inetaddr(optarg, &mask.src);
+				set_family(&family, mask.l3protonum);
+			}
+			break;
+		case '}':
+			options |= CT_OPT_MASK_DST;
+			if (optarg) {
+				mask.l3protonum = 
+					parse_inetaddr(optarg, &mask.dst);
+				set_family(&family, mask.l3protonum);
+			}
+			break;
+		case '[':
+			options |= CT_OPT_EXP_SRC;
+			if (optarg) {
+				exptuple.l3protonum = 
+					parse_inetaddr(optarg, &exptuple.src);
+				set_family(&family, exptuple.l3protonum);
+			}
+			break;
+		case ']':
+			options |= CT_OPT_EXP_DST;
+			if (optarg) {
+				exptuple.l3protonum = 
+					parse_inetaddr(optarg, &exptuple.dst);
+				set_family(&family, exptuple.l3protonum);
+			}
+			break;
+		case 'a':
+			options |= CT_OPT_NATRANGE;
+			set_family(&family, AF_INET);
+			nat_parse(optarg, 1, &range);
+			break;
+		case 'm':
+			options |= CT_OPT_MARK;
+			mark = atol(optarg);
+			metaflags |= NFCT_MARK;
+			break;
+		case 'i': {
+			char *s = NULL;
+			options |= CT_OPT_ID;
+			if (optarg)
+				break;
+			else if (optind < argc && argv[optind][0] != '-'
+					&& argv[optind][0] != '!')
+				s = argv[optind++];
+
+			if (s)
+				id = atol(s);
+			break;
+		}
+		case 'f':
+			options |= CT_OPT_FAMILY;
+			if (strncmp(optarg, "ipv4", strlen("ipv4")) == 0)
+				set_family(&family, AF_INET);
+			else if (strncmp(optarg, "ipv6", strlen("ipv6")) == 0)
+				set_family(&family, AF_INET6);
+			else
+				exit_error(PARAMETER_PROBLEM, "Unknown "
+					   "protocol family\n");
+			break;
+		default:
+			if (h && h->parse_opts 
+			    &&!h->parse_opts(c - h->option_offset, argv, &orig, 
+				             &reply, &exptuple, &mask, &proto, 
+					     &l4flags))
+				exit_error(PARAMETER_PROBLEM, "parse error\n");
+
+			/* Unknown argument... */
+			if (!h) {
+				usage(argv[0]);
+				exit_error(PARAMETER_PROBLEM, "Missing "
+					   "arguments...\n");
+			}
+			break;
+		}
+	}
+
+	/* default family */
+	if (family == AF_UNSPEC)
+		family = AF_INET;
+
+	generic_cmd_check(command, options);
+	generic_opt_check(command, options);
+
+	if (!(command & CT_HELP)
+	    && h && h->final_check 
+	    && !h->final_check(l4flags, command, &orig, &reply)) {
+		usage(argv[0]);
+		extension_help(h);
+		exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n");
+	}
+
+	switch(command) {
+
+	case CT_LIST:
+		cth = nfct_open(CONNTRACK, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+
+		if (options & CT_COMPARISON) {
+
+			if (options & CT_OPT_ZERO)
+				exit_error(PARAMETER_PROBLEM, "Can't use -z "
+					   "with filtering parameters");
+
+			ct = nfct_conntrack_alloc(&orig, &reply, timeout,
+						  &proto, status, mark, id,
+						  NULL);
+			if (!ct)
+				exit_error(OTHER_PROBLEM, "Not enough memory");
+			
+			cmp.ct = ct;
+			cmp.flags = metaflags;
+			cmp.l3flags = l3flags;
+			cmp.l4flags = l4flags;
+			pcmp = &cmp;
+		}
+
+		if (options & CT_OPT_ID)
+			nfct_register_callback(cth, 
+					nfct_default_conntrack_display_id,
+					(void *) pcmp);
+		else
+			nfct_register_callback(cth,
+					nfct_default_conntrack_display,
+					(void *) pcmp);
+			
+		if (options & CT_OPT_ZERO)
+			res = 
+			nfct_dump_conntrack_table_reset_counters(cth, family);
+		else
+			res = nfct_dump_conntrack_table(cth, family);
+		nfct_close(cth);
+		break;
+
+	case EXP_LIST:
+		cth = nfct_open(EXPECT, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		if (options & CT_OPT_ID)
+			nfct_register_callback(cth, 
+					nfct_default_expect_display_id,
+					NULL);
+		else
+			nfct_register_callback(cth,
+					nfct_default_expect_display,
+					NULL);
+		res = nfct_dump_expect_list(cth, family);
+		nfct_close(cth);
+		break;
+			
+	case CT_CREATE:
+		if ((options & CT_OPT_ORIG) 
+		    && !(options & CT_OPT_REPL)) {
+			reply.l3protonum = orig.l3protonum;
+			memcpy(&reply.src, &orig.dst, sizeof(reply.src));
+			memcpy(&reply.dst, &orig.src, sizeof(reply.dst));
+		} else if (!(options & CT_OPT_ORIG)
+			   && (options & CT_OPT_REPL)) {
+			orig.l3protonum = reply.l3protonum;
+			memcpy(&orig.src, &reply.dst, sizeof(orig.src));
+			memcpy(&orig.dst, &reply.src, sizeof(orig.dst));
+		}
+		if (options & CT_OPT_NATRANGE)
+			ct = nfct_conntrack_alloc(&orig, &reply, timeout, 
+						  &proto, status, mark, id,
+						  &range);
+		else
+			ct = nfct_conntrack_alloc(&orig, &reply, timeout, 
+						  &proto, status, mark, id,
+						  NULL);
+		if (!ct)
+			exit_error(OTHER_PROBLEM, "Not Enough memory");
+		
+		cth = nfct_open(CONNTRACK, 0);
+		if (!cth) {
+			nfct_conntrack_free(ct);
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		}
+		res = nfct_create_conntrack(cth, ct);
+		nfct_close(cth);
+		nfct_conntrack_free(ct);
+		break;
+
+	case EXP_CREATE:
+		if (options & CT_OPT_ORIG)
+			exp = nfct_expect_alloc(&orig, &exptuple,
+						&mask, timeout, id);
+		else if (options & CT_OPT_REPL)
+			exp = nfct_expect_alloc(&reply, &exptuple,
+						&mask, timeout, id);
+		if (!exp)
+			exit_error(OTHER_PROBLEM, "Not enough memory");
+
+		cth = nfct_open(EXPECT, 0);
+		if (!cth) {
+			nfct_expect_free(exp);
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		}
+		res = nfct_create_expectation(cth, exp);
+		nfct_expect_free(exp);
+		nfct_close(cth);
+		break;
+
+	case CT_UPDATE:
+		if ((options & CT_OPT_ORIG) 
+		    && !(options & CT_OPT_REPL)) {
+			reply.l3protonum = orig.l3protonum;
+			memcpy(&reply.src, &orig.dst, sizeof(reply.src));
+			memcpy(&reply.dst, &orig.src, sizeof(reply.dst));
+		} else if (!(options & CT_OPT_ORIG)
+			   && (options & CT_OPT_REPL)) {
+			orig.l3protonum = reply.l3protonum;
+			memcpy(&orig.src, &reply.dst, sizeof(orig.src));
+			memcpy(&orig.dst, &reply.src, sizeof(orig.dst));
+		}
+		ct = nfct_conntrack_alloc(&orig, &reply, timeout,
+					  &proto, status, mark, id,
+					  NULL);
+		if (!ct)
+			exit_error(OTHER_PROBLEM, "Not enough memory");
+		
+		cth = nfct_open(CONNTRACK, 0);
+		if (!cth) {
+			nfct_conntrack_free(ct);
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		}
+		res = nfct_update_conntrack(cth, ct);
+		nfct_conntrack_free(ct);
+		nfct_close(cth);
+		break;
+		
+	case CT_DELETE:
+		if (!(options & CT_OPT_ORIG) && !(options & CT_OPT_REPL))
+			exit_error(PARAMETER_PROBLEM, "Can't kill conntracks "
+						      "just by its ID");
+		cth = nfct_open(CONNTRACK, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		if (options & CT_OPT_ORIG)
+			res = nfct_delete_conntrack(cth, &orig, 
+						    NFCT_DIR_ORIGINAL,
+						    id);
+		else if (options & CT_OPT_REPL)
+			res = nfct_delete_conntrack(cth, &reply, 
+						    NFCT_DIR_REPLY,
+						    id);
+		nfct_close(cth);
+		break;
+
+	case EXP_DELETE:
+		cth = nfct_open(EXPECT, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		if (options & CT_OPT_ORIG)
+			res = nfct_delete_expectation(cth, &orig, id);
+		else if (options & CT_OPT_REPL)
+			res = nfct_delete_expectation(cth, &reply, id);
+		nfct_close(cth);
+		break;
+
+	case CT_GET:
+		cth = nfct_open(CONNTRACK, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		nfct_register_callback(cth, nfct_default_conntrack_display,
+					NULL);
+		if (options & CT_OPT_ORIG)
+			res = nfct_get_conntrack(cth, &orig,
+						 NFCT_DIR_ORIGINAL, id);
+		else if (options & CT_OPT_REPL)
+			res = nfct_get_conntrack(cth, &reply,
+						 NFCT_DIR_REPLY, id);
+		nfct_close(cth);
+		break;
+
+	case EXP_GET:
+		cth = nfct_open(EXPECT, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		nfct_register_callback(cth, nfct_default_expect_display,
+					NULL);
+		if (options & CT_OPT_ORIG)
+			res = nfct_get_expectation(cth, &orig, id);
+		else if (options & CT_OPT_REPL)
+			res = nfct_get_expectation(cth, &reply, id);
+		nfct_close(cth);
+		break;
+
+	case CT_FLUSH:
+		cth = nfct_open(CONNTRACK, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		res = nfct_flush_conntrack_table(cth, AF_INET);
+		nfct_close(cth);
+		break;
+
+	case EXP_FLUSH:
+		cth = nfct_open(EXPECT, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		res = nfct_flush_expectation_table(cth, AF_INET);
+		nfct_close(cth);
+		break;
+		
+	case CT_EVENT:
+		if (options & CT_OPT_EVENT_MASK)
+			cth = nfct_open(CONNTRACK, event_mask);
+		else
+			cth = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS);
+
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		signal(SIGINT, event_sighandler);
+
+		if (options & CT_COMPARISON) {
+			ct = nfct_conntrack_alloc(&orig, &reply, timeout,
+						  &proto, status, mark, id, 
+						  NULL);
+			if (!ct)
+				exit_error(OTHER_PROBLEM, "Not enough memory");
+
+			cmp.ct = ct;
+			cmp.flags = metaflags;
+			cmp.l3flags = l3flags;
+			cmp.l4flags = l4flags;
+			pcmp = &cmp;
+		}
+
+		nfct_register_callback(cth,
+				       nfct_default_conntrack_event_display, 
+				       (void *) pcmp);
+		res = nfct_event_conntrack(cth);
+		nfct_close(cth);
+		break;
+
+	case EXP_EVENT:
+		cth = nfct_open(EXPECT, NF_NETLINK_CONNTRACK_EXP_NEW);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		signal(SIGINT, event_sighandler);
+		nfct_register_callback(cth, nfct_default_expect_display,
+					NULL);
+		res = nfct_event_expectation(cth);
+		nfct_close(cth);
+		break;
+			
+	case CT_VERSION:
+		fprintf(stdout, "%s v%s\n", PROGNAME, VERSION);
+		break;
+	case CT_HELP:
+		usage(argv[0]);
+		if (options & CT_OPT_PROTO)
+			extension_help(h);
+		break;
+	default:
+		usage(argv[0]);
+		break;
+	}
+
+	if (opts != original_opts) {
+		free(opts);
+		opts = original_opts;
+		global_option_offset = 0;
+	}
+
+	if (res < 0) {
+		fprintf(stderr, "Operation failed: %s\n", err2str(res, command));
+		exit(OTHER_PROBLEM);
+	}
+
+	return 0;
+}
diff --git a/cli/test.sh b/cli/test.sh
new file mode 100644
index 0000000..4694236
--- /dev/null
+++ b/cli/test.sh
@@ -0,0 +1,110 @@
+CONNTRACK=conntrack
+
+SRC=1.1.1.1
+DST=2.2.2.2
+SPORT=2005
+DPORT=21
+
+case $1 in
+	dump)
+		echo "Dumping conntrack table"
+		$CONNTRACK -L
+		;;
+	flush)
+		echo "Flushing conntrack table"
+		$CONNTRACK -F
+		;;
+	new)
+		echo "creating a new conntrack"
+		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
+		 --reply-src $DST --reply-dst $SRC -p tcp \
+		 --orig-port-src $SPORT  --orig-port-dst $DPORT \
+		 --reply-port-src $DPORT --reply-port-dst $SPORT \
+		--state LISTEN -u SEEN_REPLY -t 50
+		;;
+	new-simple)
+		echo "creating a new conntrack (simplified)"
+		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
+		-p tcp --orig-port-src $SPORT  --orig-port-dst $DPORT \
+		--state LISTEN -u SEEN_REPLY -t 50
+		;;
+	new-nat)
+		echo "creating a new conntrack (NAT)"
+		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
+		-p tcp --orig-port-src $SPORT  --orig-port-dst $DPORT \
+		--state LISTEN -u SEEN_REPLY,SRC_NAT -t 50 -a 8.8.8.8
+		;;
+	get)
+		echo "getting a conntrack"
+		$CONNTRACK -G --orig-src $SRC --orig-dst $DST \
+		-p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \
+		--reply-port-src $DPORT --reply-port-dst $SPORT
+		;;
+	change)
+		echo "change a conntrack"
+		$CONNTRACK -U --orig-src $SRC --orig-dst $DST \
+		--reply-src $DST --reply-dst $SRC -p tcp \
+		--orig-port-src $SPORT --orig-port-dst $DPORT \
+		--reply-port-src $DPORT --reply-port-dst $SPORT \
+		--state TIME_WAIT -u ASSURED,SEEN_REPLY -t 500
+		;;
+	delete)
+		$CONNTRACK -D --orig-src $SRC --orig-dst $DST \
+		-p tcp --orig-port-src $SPORT --orig-port-dst $DPORT
+		;;
+	output)
+		proc=$(cat /proc/net/ip_conntrack | wc -l)
+		netl=$($CONNTRACK -L | wc -l)
+		count=$(cat /proc/sys/net/ipv4/netfilter/ip_conntrack_count)
+		if [ $proc -ne $netl ]; then
+			echo "proc is $proc and netl is $netl and count is $count"
+		else
+			if [ $proc -ne $count ]; then
+				echo "proc is $proc and netl is $netl and count is $count"
+			else
+				echo "now $proc"
+			fi
+		fi
+		;;
+	dump-expect)
+		$CONNTRACK -L expect
+		;;
+	flush-expect)
+		$CONNTRACK -F expect
+		;;
+	create-expect)
+		# requires modprobe ip_conntrack_ftp
+		$CONNTRACK -I expect --orig-src $SRC --orig-dst $DST \
+		--tuple-src 4.4.4.4 --tuple-dst 5.5.5.5 \
+		--mask-src 255.255.255.0 --mask-dst 255.255.255.255 \
+		-p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \
+		-t 200 --tuple-port-src 10 --tuple-port-dst 300 \
+		--mask-port-src 10 --mask-port-dst 300
+		;;
+	get-expect)
+		$CONNTRACK -G expect --orig-src 4.4.4.4 --orig-dst 5.5.5.5 \
+		--p tcp --orig-port-src 0 --orig-port-dst 0 \
+		--mask-port-src 10 --mask-port-dst 11
+		;;
+	delete-expect)
+		$CONNTRACK -D expect --orig-src 4.4.4.4 \
+		--orig-dst 5.5.5.5 -p tcp --orig-port-src 0 \
+		--orig-port-dst 0 --mask-port-src 10 --mask-port-dst 11
+		;;
+	*)
+		echo "Usage: $0 [dump"
+		echo "		|new"
+		echo "		|new-simple"
+		echo "		|new-nat"
+		echo "		|get"
+		echo "		|change"
+		echo "		|delete"
+		echo "		|output"
+		echo "		|flush"
+		echo "		|dump-expect"
+		echo "		|flush-expect"
+		echo "		|create-expect"
+		echo "		|get-expect"
+		echo "		|delete-expect]"
+		;;
+esac
diff --git a/configure.in b/configure.in
deleted file mode 100644
index 1b1b391..0000000
--- a/configure.in
+++ /dev/null
@@ -1,72 +0,0 @@
-AC_INIT
-
-AC_CANONICAL_SYSTEM
-
-AM_INIT_AUTOMAKE(conntrack, 1.00beta2)
-
-AC_PROG_CC
-AM_PROG_LIBTOOL
-AC_PROG_INSTALL
-AC_PROG_LN_S
-
-case $target in
-*-*-linux*) ;;
-*) AC_MSG_ERROR([Linux only, dude!]);;
-esac
-
-dnl Dependencies
-LIBNFCONNTRACK_REQUIRED=0.0.31
- 
-AC_CHECK_LIB(dl, dlopen)
-
-PKG_CHECK_MODULES(LIBNFCONNTRACK, libnetfilter_conntrack >= $LIBNFCONNTRACK_REQUIRED,,
-	AC_MSG_ERROR(Cannot find libnetfilter_conntrack >= $LIBNFCONNTRACK_REQUIRED))
- 
-AC_CHECK_HEADERS(arpa/inet.h)
-dnl check for inet_pton
-AC_CHECK_FUNCS(inet_pton)
-dnl Some systems have it, but not IPv6
-if test "$ac_cv_func_inet_pton" = "yes" ; then
-AC_MSG_CHECKING(if inet_pton supports IPv6)
-AC_TRY_RUN(
-   [
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-int main()
-  {
-     struct in6_addr addr6;
-     if (inet_pton(AF_INET6, "::1", &addr6) < 1)
-        exit(1);
-     else
-        exit(0);
-  }
-  ], [ AC_MSG_RESULT(yes)
-       AC_DEFINE_UNQUOTED(HAVE_INET_PTON_IPV6, 1, [Define to 1 if inet_pton supports IPv6.])
-  ], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
-fi
-
-dnl--------------------------------
-
-if test ! -z "$libdir"; then
-   MODULE_DIR="\\\"$libdir/conntrack/\\\""
-   CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR"
-fi
-
-dnl--------------------------------
-
-CFLAGS="$CFLAGS $LIBNFCONNTRACK_CFLAGS"
-CONNTRACK_LIBS="$LIBNFCONNTRACK_LIBS"
-
-AC_SUBST(CONNTRACK_LIBS)
-
-AC_OUTPUT(Makefile src/Makefile extensions/Makefile include/Makefile)
diff --git a/conntrack.8 b/conntrack.8
deleted file mode 100644
index 307180b..0000000
--- a/conntrack.8
+++ /dev/null
@@ -1,142 +0,0 @@
-.TH CONNTRACK 8 "Jun 23, 2005" "" ""
-
-.\" Man page written by Harald Welte <laforge@netfilter.org (Jun 2005)
-
-.SH NAME
-conntrack \- administration tool for netfilter connection tracking
-.SH SYNOPSIS
-.BR "conntrack -L [table] [-z]"
-.br
-.BR "conntrack -G [table] parameters"
-.br
-.BR "conntrack -D [table] paramaters"
-.br
-.BR "conntrack -I [table] parameters"
-.br
-.BR "conntrack -E [table] parameters"
-.br
-.BR "conntrack -F [table]"
-.SH DESCRIPTION
-.B conntrack
-is used to search, list, inspect and maintain the netfilter connection tracking
-subsystem of the Linux kernel.
-.PP
-Using 
-.B conntrack
-, you can dump a list of all (or a filtered selection of) currently tracked
-connections, delete connections from the state table, and even add new ones.
-.PP
-In addition, you can also monitor connection tracking events, e.g. show an
-event message (one line) per newly established connection.
-.SH TABLES
-The connection tracking subsystem maintains two internal tables:
-.TP
-.BR "conntrack" :
-This is the default table.  It contains a list of all currently tracked
-connections through the system.  If you don't use connection tracking
-exemptions (NOTRACK iptables target), this means all connections that go
-through the system.
-.TP
-.BR "expect" :
-This is the table of expectations.  Connection tracking expectations are the
-mechanism used to "expect" RELATED connections to existing ones.  Expectations
-are generally used by "connection tracking helpers" (sometimes called
-application level gateways [ALGs]) for more complex protocols such as FTP,
-SIP, H.323.
-.SH OPTIONS
-The options recognized by 
-.B conntrack
-can be divided into several different groups.
-.SS COMMANDS
-These options specify the particular operation to perform.  Only one of them
-can be specified at any given time.
-.TP
-.BI "-L --dump "
-List connection tacking or expectation table
-.TP
-.BI "-G, --get "
-Search for and show a particular (matching) entry in the given table.
-.TP
-.BI "-D, --delete "
-Delete an entry from the given table.
-.TP
-.BI "-I, --create "
-Create a new entry from the given table.
-.TP
-.BI "-E, --event "
-Display a real-time event log.
-.TP
-.BI "-F, --flush "
-Flush the whole given table
-.SS PARAMETERS
-.TP
-.BI "-z, --zero "
-Atomically zero counters after reading them.  This option is only valid in
-combination with the "-L, --dump" command options.
-.TP
-.BI "-e, --event-mask " "[ALL|NEW|UPDATES|DESTROY][,...]"
-Set the bitmask of events that are to be generated by the in-kernel ctnetlink
-event code.  Using this parameter, you can reduce the event messages generated
-by the kernel to those types to those that you are actually interested in.
-.
-This option can only be used in conjunction with "-E, --event".
-.SS FILTER PARAMETERS
-.TP
-.BI "-s, --orig-src " IP_ADDRESS
-Match only entries whose source address in the original direction equals the one specified as argument.
-.TP
-.BI "-d, --orig-dst " IP_ADDRESS
-Match only entries whose destination address in the original direction equals the one specified as argument.
-.TP
-.BI "-r, --reply-src " IP_ADDRESS
-Match only entries whose source address in the reply direction equals the one specified as argument.
-.TP
-.BI "-q, --reply-dst " IP_ADDRESS
-Match only entries whose destination address in the reply direction equals the one specified as argument.
-.TP
-.BI "-p, --proto " "PROTO "
-Specify layer four (TCP, UDP, ...) protocol.
-.TP
-.BI "-f, --family " "PROTO"
-Specify layer three (ipv4, ipv6) protocol
-This option is only required in conjunction with "-L, --dump". If this option is not passed, the default layer 3 protocol will be IPv4.
-.TP
-.BI "-t, --timeout " "TIMEOUT"
-Specify the timeout.
-.TP
-.BI "-u, --status " "[ASSURED|SEEN_REPLY|UNSET|SRC_NAT|DST_NAT][,...]"
-Specify the conntrack status.
-.TP
-.BI "-i, --id " "ID"
-Specify the conntrack ID. 
-.
-This option can only be used in conjunction with "-L, --dump" to display the conntrack IDs.
-.TP
-.BI "--tuple-src " IP_ADDRESS
-Specify the tuple source address of an expectation.
-.TP
-.BI "--tuple-dst " IP_ADDRESS
-Specify the tuple destination address of an expectation.
-.TP
-.BI "--mask-src " IP_ADDRESS
-Specify the source address mask of an expectation.
-.TP
-.BI "--mask-dst " IP_ADDRESS
-Specify the destination address mask of an expectation.
-.SH DIAGNOSTICS
-The exit code is 0 for correct function.  Errors which appear to be caused by
-invalid command line parameters cause an exit code of 2.  Any other errors
-cause an exit code of 1.
-.SH BUGS
-Bugs? What's this ;-)
-.SH SEE ALSO
-.BR iptables (8)
-.br
-See
-.BR "http://netfilter.org/" .
-.SH AUTHORS
-Jay Schulist, Patrick McHardy, Harald Welte and Pablo Neira wrote the kernel-level "ctnetlink" interface that is used by the conntrack tool.
-.PP
-Pablo Neira wrote the conntrack tool, Harald Welte added support for conntrack based accounting counters.
-.PP
-Man page written by Harald Welte <laforge@netfilter.org>.
diff --git a/daemon/AUTHORS b/daemon/AUTHORS
new file mode 100644
index 0000000..e6c2f6b
--- /dev/null
+++ b/daemon/AUTHORS
@@ -0,0 +1 @@
+Pablo Neira Ayuso <pablo@netfilter.org>
diff --git a/daemon/CHANGELOG b/daemon/CHANGELOG
new file mode 100644
index 0000000..afab61d
--- /dev/null
+++ b/daemon/CHANGELOG
@@ -0,0 +1,184 @@
+version 0.9.3 (yet unreleased)
+------------------------------
+o fix commit of confirmed expectations (reported by Nishit Shah)
+o fix double increment of counters in cache_update_force() (Niko Tyni)
+o nl_dump_handler must return NFCT_CB_CONTINUE (Niko Tyni)
+o initialize buffer in nl_event_handler() and nl_dump_handler() (Niko Tyni) 
+o CacheCommit value can be set via conntrackd.conf for the NACK approach
+o fix leaks in the hashtable/cache flush path (Niko Tyni)
+o fix leak if a connection already exists in the cache (Niko Tyni)
+o introduce a new header that encapsulates netlink messages
+o remove all '_entry' tail from all functions in cache.c
+o split cache.c: move cache iterators to file cache_iterators.c
+o fix inconsistencies in the cache API related to counters
+o cleanup 'usage' message
+o fix typo in examples/sync/nack/node1/conntrackd.conf
+o introduce message checksumming as described in RFC1071 (enabled by default)
+o major cleanups in the synchronization code
+o just warn once that the maximum netlink socket buffer has been reached
+o fix ignore conntrack entries by IP and introduce ignore pool abstraction layer
+o introduce netlink socket buffer overrun handler
+o constification of hash, compare and hashtable_test functions in hash.c
+o introduce ACKnowledgement mechanisms to reduce the size of the resend queue
+o remove OK messages at startup since provide useless data
+o fix compilation warning in mcast.c: recvfrom takes socklen_t not size_t
+o add a lock per buffer: makes buffer code thread safe
+o introduce 'Replicate' clause to explicitely set states to be replicated
+o kill cache feature abuse: introduce nicer cache hooks for sync algorithms
+o fix oversized buffer allocated in the stack in the cache functions
+o add support to dump internal/external cache in XML format '-x'
+
+version 0.9.2 (2006/01/17)
+--------------------------
+o remove spamming packet lost messages
+o generalize network netlink sequence tracking 
+o fix bogus error message on resync `-R'
+o fix endianess issues in the network netlink message
+o introduce generic netlink multicast primitives to send and receive
+o fix bogus replayed multicast message due to sequence numbering wraparound
+o introduce counter for malformed netlink messages received
+o introduce a new syntax for the `Sync' section  in the configuration file
+o several cleanups and remove unused variables
+o add autostuff to include examples in the tarball (reported by Victor Lozano)
+o use the new API available in libnetfilter_conntrack-0.0.50
+o implement a NACK based protocol for replication
+
+version 0.9.1 (2006/11/06)
+--------------------------
+o conntrackd requires kernel >= 2.6.18
+o remove bogus TIMERS_MODE constant
+o implement bulk mode '-B': first works to address the preemption issue
+o fix minor reduction conflicts in the configfile grammar
+o check for CAP_NET_ADMIN instead of requiring root privileges
+o check that linux/capability.h exists
+o fix formatting at dump statistics '-s'
+o move dump traffic stats before multicast traffic stats
+o move event and dump handler to a generic infrastructure: kill events.c file
+o kill unused function inc_ct_stats
+o kill file resync.h
+o cleanup broadcast_sync: renamed to mcast_send_sync
+o sed 's/perror/debug/g' local.c
+o fix bogus increment of update_fail stats at dump stage
+o display descriptive error if we can't connect to conntrackd via UNIX socket
+o remove debugging message from alarm.c
+o move dump_mcast_stats to mcast.c where it really belongs
+o rename stats.c to traffic_stats.c
+o check for replayed/lost multicast message: simple seq tracking w/o recovery
+o reissue nfnl_catch on ENOENT error: a message for other subsystem
+o remove test/ directory in tree
+o improve cache commit stats
+o kill last_commit and last_flush from cache statistics: use the logfile
+o recover cache naming for dump stats `-s'
+o display multicast sequence tracking statistics: packets lost and replayed
+o zero ct_sync_state and ct_stats_state structures after allocation
+o improve keepalived scripts:
+   - resync with conntrack table on transition to master
+   - send bulk on transition to backup
+o implement alarm cascade of ten levels
+o implement timer cache flavour: limited life of entries in the external cache
+o implement a global lock that protects operation with conntrack entries
+o remove debug checking in cache_del_entry
+o set a reduced timeout for committed entries: 180 seconds by default
+o update comments on the sync-mode code
+o introduce delay destroy messages facility
+o increase timer for external states from 60 to 180 seconds
+o remove unused replicate/dont_replicated constants
+o fix cache entry clashing issue (reported by Maik Hentsche)
+o fix bogus increment of error stats in the external cache
+o remove pollution generated by `[REQ] cache dump' message from logfile
+
+version 0.9.0 (2006/09/17)
+--------------------------
+o implement initial for IPv6 (untested)
+o implement generic extensible cache: kill the internal and external caches
+o implement persistence cache feature
+o implement lifetime cache feature
+o modify UNIX facilities identification numbers:
+  separate master conntrack facilities and internal plugin facilities
+o break backward compatibility of configuration file:
+  remove IgnoreLoopback, use IgnoreTrafficFor instead
+  remove IgnoreMulticastTraffic, use IgnoreTrafficFor instead
+o merge event/event_subsys and sync/sync_subsys initialization to run.c
+o improve control of the iteration process in the hashtables
+o fix wrong locking in the alarm thread
+o supersede AcceptNAT by StripNAT clause
+o replace ignore traffic array by a hashtable
+o move lockfile checking before daemonization
+o on initialization error give a descriptive error
+o introduce netlink socket size grown limitator
+o introduce force resync with master conntrack table facility '-R'
+o ignore SIGPIPE signal
+o kill post_step since it is not used anymore
+
+version 0.8.3 (2006/09/03)
+--------------------------
+Author: Maik Hentsche <maik mm-double net>
+
+o Fix typo in conntrackd -h
+o Disable debugging messages by default
+o No signals while signals handlings
+o Add extra checkings at forking
+o Check maximum size for file passed via -C
+
+Author: Pablo Neira Ayuso <pablo netfilter org>
+
+o retry select() if EINTR is returned (Reported by Maik Hentsche)
+o Fix bug in slist_for_each_entry (Reported by Maik Hetsche)
+o Signal handler registration done after intialization
+o Implement alarm thread (based on Maik Hentsche's patch)
+o Fix segfault on conntrackd -k (Reported by Maik Hentsche)
+o Fix bug on alarm removal (Reported by Maik Hentsche)
+o configure stops if bison, flex or yacc are not installed
+
+version 0.8.2 (2006/07/05)
+--------------------------
+o RelaxTransitions clause introduced in Sync mode
+o multicast messages sequence tracking
+o SocketBufferSize clause to set up the netlink socket buffer
+o use new libnfnetlink API to solve limitations of nfnl_listen
+o extra sanity checkings for netlink multicast messages
+o improve statistics
+o tons of cleanups 8)
+
+version 0.8.1 (2006/06/13)
+--------------------------
+o -f now just flushes the internal and external caches
+o -F flushes the master conntrack table
+o fix segfault under heavy load and signal received
+o added -S mode for statistics: still needs more thinking
+
+version 0.8.0 (2006/06/11)
+--------------------------
+o more work to generalize the daemon: now it's ready to implement
+modular support for adaptive timers and conntrack statistics, time
+to implement them ;). This is *still* a work in progress.
+
+version 0.7.2 (2006/06/05)
+--------------------------
+o stupid bug in normal and alarm caches initialization: flush unset
+o fix racy signal handling
+
+version 0.7.1 (2006/06/05)
+--------------------------
+o Bugfix for multicast sockets communication
+
+version 0.7 (2006/06/01)
+------------------------
+o Major code re-structuration: internal and external cache abstraction
+o sequence tracking for event messages
+o expect more changes, I still dislike some stuff in its current status ;)
+
+version 0.6 (2006/05/31)
+------------------------
+o Lock file support
+o use new API nfct_conntrack_event_raw
+o major code clean ups
+
+version 0.5 (2006/05/30)
+-------------------------
+o Fix multicast server binds to wrong interface
+o Include clause `IgnoreProtocol', deprecates IgnoreUDP and IgnoreICMP
+
+version 0.4 (2006/05/29)
+------------------------
+o Initial release
diff --git a/daemon/CONTRIBUTORS b/daemon/CONTRIBUTORS
new file mode 100644
index 0000000..c5e40b4
--- /dev/null
+++ b/daemon/CONTRIBUTORS
@@ -0,0 +1,3 @@
+Maik Hentsche <netfilter@mm-double.de>:
+  - Feedback & Brainstorming
+  - Bug hunting
diff --git a/daemon/INSTALL b/daemon/INSTALL
new file mode 100644
index 0000000..0de8dc0
--- /dev/null
+++ b/daemon/INSTALL
@@ -0,0 +1,199 @@
+Copyright (C) 2006-2007 Pablo Neira Ayuso <pablo netfilter org>
+
+1.Basic Installation
+====================
+
+ To compile and install 'conntrackd' just follow the classical steps:
+
+	$ ./configure
+	$ make
+	# make install
+	# mkdir /etc/conntrackd/
+
+2.1. Synchronization Mode
+=========================
+
+ Conntrackd can replicate the status of the connections that are currently
+ being processed by your stateful firewall based on Linux. This section
+ describes how to setup the daemon in synchronization mode:
+
+2.1.1. Requirements
+
+ You have to install the following software in order to get conntrackd working,
+ make sure that you have installed them correctly before going forward:
+
+ o linux kernel version >= 2.6.18 (http://www.kernel.org) with support for:
+     - connection tracking system (quite obvious ;)
+     - nfnetlink
+     - ctnetlink (ip_conntrack_netlink)
+     - connection tracking event notification API
+
+ o libnfnetlink: the netfilter netlink library
+
+     Since conntrackd version 0.9.2 you can used the official release availble at
+     http://www.netfilter.org/projects/libnfnetlink/files/
+
+     Up to conntrackd version 0.9.1 use the unofficial release available at the
+     download section
+
+ o libnetfilter_conntrack: the netfilter conntrack library
+
+     Since  conntrackd version 0.9.2 you can used the official release availble at
+     http://www.netfilter.org/projects/libnetfilter_conntrack/files/
+
+     Up to conntrackd version 0.9.1 use the unnoficial release available at the
+     download section
+
+ o Keepalived version 1.x (http://www.keepalived.org)
+     check if your distribution comes with a recent version
+
+2.1.2. Configuration
+
+ 1) Setting up keepalived
+
+    There is an example file available inside the conntrackd tarball:
+
+    For node 1: conntrackd-x.x.x/examples/sync/node1/keepalived.conf
+    For node 2: conntrackd-x.x.x/examples/sync/node2/keepalived.conf
+
+    These files can be used to set up a simple VRRP cluster composed of
+    two machines that hold the virtual IPs 192.168.0.100 on eth0 and
+    192.168.1.100 on eth1.
+
+    If you are not familiar with keepalived, please read the official
+    docs available at http://www.keepalived.org
+
+    Please, make sure that keepalived is correctly working before passing
+    to step 2)
+
+ 2) Setting up conntrackd
+
+    To setup 'conntrackd' in synchronization mode, you have to put the
+    configuration file in the directory /etc/conntrackd.
+
+    On node 1:
+	# cp examples/sync/_type_/node1/conntrackd.conf /etc/conntrackd.conf
+
+    On node 2:
+        # cp examples/sync/_type_/node1/conntrackd.conf /etc/conntrackd.conf
+
+    Where _type_ is the synchronization type selected, currently there are
+    two: the persistent mode and the NACK mode. The persistent mode consumes
+    more resources than the NACK mode, however the NACK mode is still
+    experimental
+
+    Do not forget to edit the files in order to adapt them to the
+    setting that you are deploying.
+
+    Note: If you don't want to put the config file under /etc/conntrackd,
+    just tell conntrackd where to find it passing the option -C
+
+ 3) Running conntrackd
+
+    Conntrackd can run in console mode, in that case just type 'conntrackd',
+    otherwise, if you want to run it in daemon mode the type 'conntrackd -d'.
+
+ 4) Checking that conntrackd is working fine
+
+    Conntrackd comes with several facilities to check its status:
+
+    - Dump the cache of connections that are currently being processed by
+      this node (aka. internal cache):
+
+    # conntrackd -i
+
+    - Dump the cache of connections that has been transfered from
+      others active nodes in the network (aka. external cache)
+
+    # conntrackd -e
+
+    - Dump statistics collected by the replication daemon:
+
+    # conntrackd -s
+
+ 5) Setting up interaction with keepalived
+
+    If keepalived detects the failure of the active node, then it designates
+    a candidate node that will replace the failing active. On such event,
+    the external cache, eg. the cache that contains the connections processed
+    by other nodes, must be commited. To commit the external cache, just type:
+
+    # conntrackd -c
+
+    See that keepalived provides a shell script interface to interact with
+    other programs, so we can automate the process of commiting the external
+    cache by introducing the following line in the keepalived file:
+
+    notify_master /etc/conntrackd/script_master.sh
+
+    The script 'script_master.sh' just the following:
+
+    #!/bin/sh
+    /usr/sbin/conntrackd -c
+
+    Therefore, on failure event, the candidate node takes over the virtual
+    IPs and the connections that the failing active was processing. Observe
+    that this file differs for the NACK mode.
+
+ 6) Disable TCP window tracking
+
+ Until the appropiate patches don't go into kernel mainline, you will have
+ to disable TCP window tracking, consider this as a temporary solution:
+
+    # echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal
+
+2.2. Statistics mode
+====================
+
+ Conntrackd can also run as statistics daemon, if you are not interested in
+ this mode, just skip it. It is not required in order to get the
+ synchronization mode working. This section details how to setup the daemon
+ in statistics mode:
+
+2.2.1. Requirements
+
+ You have to install the following software in order to get conntrackd working,
+ make sure that you have them installed correctly before going forward:
+
+ o linux kernel version >= 2.6.18 (http://www.kernel.org) with support for:
+      - connection tracking system
+      - nfnetlink
+      - ctnetlink (ip_conntrack_netlink)
+      - connection tracking event notification API
+
+ o libnfnetlink: the netfilter netlink library
+
+     Since conntrackd version 0.9.2 you can used the official release availble at
+     http://www.netfilter.org/projects/libnfnetlink/files/
+
+     Up to conntrackd version 0.9.1 use the unofficial release available at the
+     download section
+
+ o libnetfilter_conntrack: the netfilter conntrack library
+
+     Since  conntrackd version 0.9.2 you can used the official release availble at
+     http://www.netfilter.org/projects/libnetfilter_conntrack/files/
+
+     Up to conntrackd version 0.9.1 use the unnoficial release available at the
+     download section
+
+2.2.2. Configuration
+
+ Setting up conntrackd in statistics mode is rather easy. Just copy the
+ configuration file
+
+    # cp examples/stats/conntrackd.conf /etc/conntrackd.conf
+
+2.2.3. Running conntrackd in statistics mode
+
+ To run conntrackd in statistics mode:
+
+    # conntrackd -S
+
+ Alternatively, you can run conntrackd in daemon mode:
+
+    # conntrackd -S -d
+
+ In order to dump the statistics, just type:
+
+    # conntrackd -s
diff --git a/daemon/Make_global.am b/daemon/Make_global.am
new file mode 100644
index 0000000..685add7
--- /dev/null
+++ b/daemon/Make_global.am
@@ -0,0 +1 @@
+INCLUDES=$(all_includes) -I$(top_srcdir)/include
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
new file mode 100644
index 0000000..998f4c6
--- /dev/null
+++ b/daemon/Makefile.am
@@ -0,0 +1,21 @@
+include Make_global.am
+
+# not a GNU package. You can remove this line, if
+# have all needed files, that a GNU package needs
+AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
+
+# man_MANS = ""
+# EXTRA_DIST = $(man_MANS) Make_global.am debian
+EXTRA_DIST = Make_global.am CHANGELOG TODO
+
+SUBDIRS   = src
+DIST_SUBDIRS = include src examples
+LINKOPTS  = -lnfnetlink -lnetfilter_conntrack -lpthread
+AM_CFLAGS = -g
+
+$(OBJECTS): libtool
+libtool: $(LIBTOOL_DEPS)
+	$(SHELL) ./config.status --recheck
+
+dist-hook:
+	rm -rf `find $(distdir)/debian -name .svn`
diff --git a/daemon/TODO b/daemon/TODO
new file mode 100644
index 0000000..130b1f8
--- /dev/null
+++ b/daemon/TODO
@@ -0,0 +1,18 @@
+There are several tasks that are pending to be done, I have classified them
+by dificulty levels:
+
+Relatively easy
+===============
+
+- test ipv6 support
+- improve shell scripts
+- test NACK based protocol
+- manpage for conntrackd
+
+Requires some work
+==================
+
+- study better keepalived transitions
+- implement support for TCP window tracking (patches are on the table)
+	- at the moment you have to disable it:
+	echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal
diff --git a/daemon/autogen.sh b/daemon/autogen.sh
new file mode 100755
index 0000000..e76d3ef
--- /dev/null
+++ b/daemon/autogen.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+run ()
+{
+    echo "running: $*"
+    eval $*
+
+    if test $? != 0 ; then
+	echo "error: while running '$*'"
+	exit 1
+    fi
+}
+
+run aclocal
+run libtoolize -f
+#run autoheader
+run automake -a
+run autoconf
diff --git a/daemon/configure.in b/daemon/configure.in
new file mode 100644
index 0000000..92e512a
--- /dev/null
+++ b/daemon/configure.in
@@ -0,0 +1,106 @@
+AC_INIT(conntrackd, 0.9.2, pablo@netfilter.org)
+
+AC_CANONICAL_SYSTEM
+
+AM_INIT_AUTOMAKE
+
+AC_PROG_CC
+AM_PROG_LIBTOOL
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AM_PROG_LEX
+AC_PROG_YACC
+
+case $target in
+*-*-linux*) ;;
+*) AC_MSG_ERROR([Linux only, dude!]);;
+esac
+
+AC_CHECK_PROGS(XYACC,$YACC bison yacc,none)
+if test "$XYACC" = "none"
+then
+	echo "*** Error: No suitable bison/yacc found. ***"
+	echo "    Please install the 'bison' package."
+	exit 1
+fi
+AC_CHECK_PROGS(XLEX,$LEX flex lex,none)
+if test "$XLEX" = "none"
+then
+	echo "*** Error: No suitable bison/yacc found. ***"
+	echo "    Please install the 'bison' package."
+	exit 1
+fi
+
+AC_CHECK_HEADERS([linux/capability.h],, [AC_MSG_ERROR([Cannot find linux/capabibility.h])])
+
+# Checks for libraries.
+# FIXME: Replace `main' with a function in `-lc':
+dnl AC_CHECK_LIB([c], [main])
+# FIXME: Replace `main' with a function in `-ldl':
+
+AC_CHECK_LIB([nfnetlink], [nfnl_talk] ,,,[-lnfnetlink])
+AC_CHECK_LIB([netfilter_conntrack], [nfct_dump_conntrack_table] ,,,[-lnetfilter_conntrack])
+AC_CHECK_LIB([pthread], [pthread_create] ,,,[-lpthread])
+
+AC_CHECK_HEADERS(arpa/inet.h)
+dnl check for inet_pton
+AC_CHECK_FUNCS(inet_pton)
+dnl Some systems have it, but not IPv6
+if test "$ac_cv_func_inet_pton" = "yes" ; then
+AC_MSG_CHECKING(if inet_pton supports IPv6)
+AC_TRY_RUN(
+   [
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+int main()
+  {
+     struct in6_addr addr6;
+     if (inet_pton(AF_INET6, "::1", &addr6) < 1)
+        exit(1);
+     else
+        exit(0);
+  }
+  ], [ AC_MSG_RESULT(yes)
+       AC_DEFINE_UNQUOTED(HAVE_INET_PTON_IPV6, 1, [Define to 1 if inet_pton supports IPv6.])
+  ], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+fi
+
+# Checks for header files.
+dnl AC_HEADER_STDC
+dnl AC_CHECK_HEADERS([netinet/in.h stdlib.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+dnl AC_C_CONST
+dnl AC_C_INLINE
+
+# Checks for library functions.
+dnl AC_FUNC_MALLOC
+dnl AC_FUNC_VPRINTF
+dnl AC_CHECK_FUNCS([memset])
+
+dnl--------------------------------
+
+dnl if test ! -z "$libdir"; then
+dnl    MODULE_DIR="\\\"$libdir/conntrack/\\\""
+dnl    CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR"
+dnl fi
+
+dnl--------------------------------
+
+dnl AC_CONFIG_FILES([Makefile
+dnl                  debug/Makefile
+dnl                  debug/src/Makefile
+dnl                  extensions/Makefile
+dnl                  src/Makefile])
+
+AC_OUTPUT(Makefile src/Makefile include/Makefile examples/Makefile examples/stats/Makefile examples/sync/Makefile examples/sync/persistent/Makefile examples/sync/nack/Makefile examples/sync/persistent/node1/Makefile examples/sync/persistent/node2/Makefile examples/sync/nack/node1/Makefile examples/sync/nack/node2/Makefile)
diff --git a/daemon/examples/Makefile.am b/daemon/examples/Makefile.am
new file mode 100644
index 0000000..be83d42
--- /dev/null
+++ b/daemon/examples/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = stats sync 
diff --git a/daemon/examples/debian.conntrackd.init.d b/daemon/examples/debian.conntrackd.init.d
new file mode 100644
index 0000000..ba847dd
--- /dev/null
+++ b/daemon/examples/debian.conntrackd.init.d
@@ -0,0 +1,48 @@
+#!/bin/sh
+#
+# /etc/init.d/conntrackd
+#
+# Maximilian Wilhelm <max@rfc2324.org>
+#  -- Mon, 06 Nov 2006 18:39:07 +0100
+#
+
+export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+
+NAME="conntrackd"
+DAEMON=`command -v conntrackd`
+CONFIG="/etc/conntrack/conntrackd.conf"
+PIDFILE="/var/run/${NAME}.pid"
+
+
+# Gracefully exit if there is no daemon (debian way of life)
+if [ ! -x "${DAEMON}" ]; then
+	exit 0
+fi
+
+# Check for config file
+if [ ! -f /etc/conntrackd/conntrackd.conf ]; then
+	echo "Error: There is no config file for $NAME" >&2
+	exit 1;
+fi
+
+case "$1" in
+  start)
+        echo -n "Starting $NAME: "
+	start-stop-daemon --start --quiet --make-pidfile --pidfile "/var/run/${NAME}.pid" --background --exec "${DAEMON}"  && echo "done." || echo "FAILED!"
+	;;
+  stop)
+        echo -n "Stopping $NAME:"
+	start-stop-daemon --stop --quiet --oknodo --pidfile "/var/run/${NAME}.pid" && echo "done." || echo "FAILED!"
+	;;
+
+  restart)
+	$0 start
+	$0 stop
+	;;
+
+  *)
+	echo "Usage: /etc/init.d/conntrackd {start|stop|restart}"
+	exit 1
+esac
+
+exit 0
diff --git a/daemon/examples/stats/Makefile.am b/daemon/examples/stats/Makefile.am
new file mode 100644
index 0000000..b43c3b8
--- /dev/null
+++ b/daemon/examples/stats/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = conntrackd.conf 
diff --git a/daemon/examples/stats/conntrackd.conf b/daemon/examples/stats/conntrackd.conf
new file mode 100644
index 0000000..e514ac0
--- /dev/null
+++ b/daemon/examples/stats/conntrackd.conf
@@ -0,0 +1,69 @@
+#
+# General settings
+#
+General {
+	#
+	# Number of buckets in the caches: hash table
+	#
+	HashSize 8192
+
+	#
+	# Maximum number of conntracks: 
+	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
+	#
+	HashLimit 65535
+
+	#
+	# Logfile
+	#
+	LogFile /var/log/conntrackd.log
+
+	#
+	# Lockfile
+	# 
+	LockFile /var/lock/conntrack.lock
+
+	#
+	# Unix socket configuration
+	#
+	UNIX {
+		Path /tmp/sync.sock
+		Backlog 20
+	}
+
+	#
+	# Netlink socket buffer size
+	#
+	SocketBufferSize 262142
+
+	#
+	# Increase the socket buffer up to maximun if required
+	#
+	SocketBufferSizeMaxGrown 655355
+}
+
+#
+# Ignore traffic for a certain set of IP's: Usually
+# all the IP assigned to the firewall since local
+# traffic must be ignored, just forwarded connections
+# are worth to replicate
+#
+IgnoreTrafficFor {
+	IPv4_address 127.0.0.1 # loopback
+}
+
+#
+# Do not replicate certain protocol traffic 
+#
+IgnoreProtocol {
+	UDP
+#	ICMP
+#	IGMP
+#	VRRP
+	# numeric numbers also valid
+}
+
+#
+# Strip NAT traffic
+#
+StripNAT
diff --git a/daemon/examples/sync/Makefile.am b/daemon/examples/sync/Makefile.am
new file mode 100644
index 0000000..28e7643
--- /dev/null
+++ b/daemon/examples/sync/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = persistent nack
diff --git a/daemon/examples/sync/nack/Makefile.am b/daemon/examples/sync/nack/Makefile.am
new file mode 100644
index 0000000..6fd99b1
--- /dev/null
+++ b/daemon/examples/sync/nack/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = script_backup.sh script_master.sh 
+SUBDIRS = node1 node2
diff --git a/daemon/examples/sync/nack/README b/daemon/examples/sync/nack/README
new file mode 100644
index 0000000..66987f7
--- /dev/null
+++ b/daemon/examples/sync/nack/README
@@ -0,0 +1 @@
+This directory contains the files for the NACK based protocol
diff --git a/daemon/examples/sync/nack/node1/Makefile.am b/daemon/examples/sync/nack/node1/Makefile.am
new file mode 100644
index 0000000..edc0ed7
--- /dev/null
+++ b/daemon/examples/sync/nack/node1/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = conntrackd.conf keepalived.conf 
diff --git a/daemon/examples/sync/nack/node1/conntrackd.conf b/daemon/examples/sync/nack/node1/conntrackd.conf
new file mode 100644
index 0000000..f24fa7e
--- /dev/null
+++ b/daemon/examples/sync/nack/node1/conntrackd.conf
@@ -0,0 +1,125 @@
+#
+# Synchronizer settings
+#
+Sync {
+	Mode NACK {
+		#
+		# Size of the buffer that hold destroy messages for 
+		# possible resends (in bytes)
+		#
+		ResendBufferSize 262144
+
+		#
+		# Entries committed to the connection tracking table 
+		# starts with a limited timeout of N seconds until the
+		# takeover process is completed.
+		#
+		CommitTimeout 180
+
+		# Set Acknowledgement window size
+		ACKWindowSize 20
+	}
+
+	#
+	# Multicast IP and interface where messages are
+	# broadcasted (dedicated link). IMPORTANT: Make sure
+	# that iptables accepts traffic for destination
+	# 225.0.0.50, eg:
+	#
+	#	iptables -I INPUT -d 225.0.0.50 -j ACCEPT
+	#	iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT
+	#
+	Multicast {
+		IPv4_address 225.0.0.50
+		IPv4_interface 192.168.100.100 # IP of dedicated link
+		Group 3780
+		Backlog 20
+	}
+
+	# Enable/Disable message checksumming
+	Checksum on
+
+	# Uncomment this if you want to replicate just certain TCP states.
+	# This option introduces a tradeoff in the replication: it reduces
+	# CPU consumption and lost messages rate at the cost of having 
+	# backup replicas that don't contain the current state that the active 
+	# replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED,
+	# FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN.
+	# 
+	# Replicate ESTABLISHED TIME_WAIT for TCP
+}
+
+#
+# General settings
+#
+General {
+	#
+	# Number of buckets in the caches: hash table
+	#
+	HashSize 8192
+
+	#
+	# Maximum number of conntracks: 
+	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
+	#
+	HashLimit 65535
+
+	#
+	# Logfile
+	#
+	LogFile /var/log/conntrackd.log
+
+	#
+	# Lockfile
+	# 
+	LockFile /var/lock/conntrack.lock
+
+	#
+	# Unix socket configuration
+	#
+	UNIX {
+		Path /tmp/sync.sock
+		Backlog 20
+	}
+
+	#
+	# Netlink socket buffer size
+	#
+	SocketBufferSize 262142
+
+	#
+	# Increase the socket buffer up to maximum if required
+	#
+	SocketBufferSizeMaxGrown 655355
+}
+
+#
+# Ignore traffic for a certain set of IP's: Usually
+# all the IP assigned to the firewall since local
+# traffic must be ignored, just forwarded connections
+# are worth to replicate
+#
+IgnoreTrafficFor {
+	IPv4_address 127.0.0.1 # loopback
+	IPv4_address 192.168.0.1
+	IPv4_address 192.168.1.1
+	IPv4_address 192.168.100.100 # dedicated link ip
+	IPv4_address 192.168.0.100 # virtual IP 1
+	IPv4_address 192.168.1.100 # virtual IP 2
+}
+
+#
+# Do not replicate certain protocol traffic 
+#
+IgnoreProtocol {
+	UDP
+	ICMP
+	IGMP
+	VRRP
+	# numeric numbers also valid
+}
+
+#
+# Strip NAT traffic
+#
+StripNAT
diff --git a/daemon/examples/sync/nack/node1/keepalived.conf b/daemon/examples/sync/nack/node1/keepalived.conf
new file mode 100644
index 0000000..41aa35b
--- /dev/null
+++ b/daemon/examples/sync/nack/node1/keepalived.conf
@@ -0,0 +1,38 @@
+vrrp_sync_group G1 {   # must be before vrrp_instance declaration
+  group {
+    VI_1
+    VI_2
+  }
+  notify_master /etc/conntrackd/script_master.sh
+  notify_backup /etc/conntrackd/script_backup.sh
+}
+
+vrrp_instance VI_1 {
+    interface eth1
+    state SLAVE
+    virtual_router_id 61
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.0.100   # default CIDR mask is /32
+    }
+}
+
+vrrp_instance VI_2 {
+    interface eth0
+    state SLAVE
+    virtual_router_id 62
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.1.100
+    }
+}
diff --git a/daemon/examples/sync/nack/node2/Makefile.am b/daemon/examples/sync/nack/node2/Makefile.am
new file mode 100644
index 0000000..edc0ed7
--- /dev/null
+++ b/daemon/examples/sync/nack/node2/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = conntrackd.conf keepalived.conf 
diff --git a/daemon/examples/sync/nack/node2/conntrackd.conf b/daemon/examples/sync/nack/node2/conntrackd.conf
new file mode 100644
index 0000000..4f15773
--- /dev/null
+++ b/daemon/examples/sync/nack/node2/conntrackd.conf
@@ -0,0 +1,124 @@
+#
+# Synchronizer settings
+#
+Sync {
+	Mode NACK {
+                #
+		# Size of the buffer that hold destroy messages for 
+		# possible resends (in bytes)
+		#
+		ResendBufferSize 262144
+
+		# Entries committed to the connection tracking table 
+		# starts with a limited timeout of N seconds until the
+		# takeover process is completed.
+		#
+		CommitTimeout 180
+
+		# Set Acknowledgement window size
+		ACKWindowSize 20
+	}
+
+	#
+	# Multicast IP and interface where messages are
+	# broadcasted (dedicated link). IMPORTANT: Make sure
+	# that iptables accepts traffic for destination
+	# 225.0.0.50, eg:
+	#
+	#	iptables -I INPUT -d 225.0.0.50 -j ACCEPT
+	#	iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT
+	#
+	Multicast {
+		IPv4_address 225.0.0.50
+		IPv4_interface 192.168.100.200 # IP of dedicated link
+		Group 3780
+		Backlog 20
+	}
+
+	# Enable/Disable message checksumming
+	Checksum on
+
+	# Uncomment this if you want to replicate just certain TCP states.
+	# This option introduces a tradeoff in the replication: it reduces
+	# CPU consumption and lost messages rate at the cost of having 
+	# backup replicas that don't contain the current state that the active 
+	# replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED,
+	# FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN.
+	# 
+	# Replicate ESTABLISHED TIME_WAIT for TCP
+}
+
+#
+# General settings
+#
+General {
+	#
+	# Number of buckets in the caches: hash table
+	#
+	HashSize 8192
+
+	#
+	# Maximum number of conntracks: 
+	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
+	#
+	HashLimit 65535
+
+	#
+	# Logfile
+	#
+	LogFile /var/log/conntrackd.log
+
+	#
+	# Lockfile
+	# 
+	LockFile /var/lock/conntrack.lock
+
+	#
+	# Unix socket configuration
+	#
+	UNIX {
+		Path /tmp/sync.sock
+		Backlog 20
+	}
+
+	#
+	# Netlink socket buffer size
+	#
+	SocketBufferSize 262142
+
+	#
+	# Increase the socket buffer up to maximum if required
+	#
+	SocketBufferSizeMaxGrown 655355
+}
+
+#
+# Ignore traffic for a certain set of IP's: Usually
+# all the IP assigned to the firewall since local
+# traffic must be ignored, just forwarded connections
+# are worth to replicate
+#
+IgnoreTrafficFor {
+	IPv4_address 127.0.0.1 # loopback
+	IPv4_address 192.168.0.2
+	IPv4_address 192.168.1.2
+	IPv4_address 192.168.100.200 # dedicated link ip
+	IPv4_address 192.168.0.200 # virtual IP 1
+	IPv4_address 192.168.1.200 # virtual IP 2
+}
+
+#
+# Do not replicate certain protocol traffic 
+#
+IgnoreProtocol {
+	UDP
+	ICMP
+	IGMP
+	VRRP
+	# numeric numbers also valid
+}
+
+#
+# Strip NAT traffic
+#
+StripNAT
diff --git a/daemon/examples/sync/nack/node2/keepalived.conf b/daemon/examples/sync/nack/node2/keepalived.conf
new file mode 100644
index 0000000..41aa35b
--- /dev/null
+++ b/daemon/examples/sync/nack/node2/keepalived.conf
@@ -0,0 +1,38 @@
+vrrp_sync_group G1 {   # must be before vrrp_instance declaration
+  group {
+    VI_1
+    VI_2
+  }
+  notify_master /etc/conntrackd/script_master.sh
+  notify_backup /etc/conntrackd/script_backup.sh
+}
+
+vrrp_instance VI_1 {
+    interface eth1
+    state SLAVE
+    virtual_router_id 61
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.0.100   # default CIDR mask is /32
+    }
+}
+
+vrrp_instance VI_2 {
+    interface eth0
+    state SLAVE
+    virtual_router_id 62
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.1.100
+    }
+}
diff --git a/daemon/examples/sync/nack/script_backup.sh b/daemon/examples/sync/nack/script_backup.sh
new file mode 100755
index 0000000..813e375
--- /dev/null
+++ b/daemon/examples/sync/nack/script_backup.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+/usr/sbin/conntrackd -n # request a resync from other nodes via multicast
diff --git a/daemon/examples/sync/nack/script_master.sh b/daemon/examples/sync/nack/script_master.sh
new file mode 100755
index 0000000..ff1dbc0
--- /dev/null
+++ b/daemon/examples/sync/nack/script_master.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+/usr/sbin/conntrackd -c # commit the cache
+/usr/sbin/conntrackd -f # flush the caches
+/usr/sbin/conntrackd -R # resync with kernel conntrack table
diff --git a/daemon/examples/sync/persistent/Makefile.am b/daemon/examples/sync/persistent/Makefile.am
new file mode 100644
index 0000000..6fd99b1
--- /dev/null
+++ b/daemon/examples/sync/persistent/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = script_backup.sh script_master.sh 
+SUBDIRS = node1 node2
diff --git a/daemon/examples/sync/persistent/README b/daemon/examples/sync/persistent/README
new file mode 100644
index 0000000..36b5989
--- /dev/null
+++ b/daemon/examples/sync/persistent/README
@@ -0,0 +1 @@
+This directory contains the files for the PERSISTENT based protocol
diff --git a/daemon/examples/sync/persistent/node1/Makefile.am b/daemon/examples/sync/persistent/node1/Makefile.am
new file mode 100644
index 0000000..edc0ed7
--- /dev/null
+++ b/daemon/examples/sync/persistent/node1/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = conntrackd.conf keepalived.conf 
diff --git a/daemon/examples/sync/persistent/node1/conntrackd.conf b/daemon/examples/sync/persistent/node1/conntrackd.conf
new file mode 100644
index 0000000..90afeb7
--- /dev/null
+++ b/daemon/examples/sync/persistent/node1/conntrackd.conf
@@ -0,0 +1,130 @@
+#
+# Synchronizer settings
+#
+Sync {
+	Mode PERSISTENT {
+		#
+		# If a conntrack entry is not modified in <= 15 seconds, then
+		# a message is broadcasted. This mechanism is used to
+		# resynchronize nodes that just joined the multicast group
+		#
+		RefreshTime 15
+	
+		#
+		# If we don't receive a notification about the state of 
+		# an entry in the external cache after N seconds, then
+		# remove it.
+		#
+		CacheTimeout 180
+
+		#
+		# Entries committed to the connection tracking table 
+		# starts with a limited timeout of N seconds until the
+		# takeover process is completed.
+		#
+		CommitTimeout 180
+	}
+
+	#
+	# Multicast IP and interface where messages are
+	# broadcasted (dedicated link). IMPORTANT: Make sure
+	# that iptables accepts traffic for destination
+	# 225.0.0.50, eg:
+	#
+	#	iptables -I INPUT -d 225.0.0.50 -j ACCEPT
+	#	iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT
+	#
+	Multicast {
+		IPv4_address 225.0.0.50
+		IPv4_interface 192.168.100.100 # IP of dedicated link
+		Group 3780
+		Backlog 20
+	}
+
+	# Enable/Disable message checksumming
+	Checksum on
+
+	# Uncomment this if you want to replicate just certain TCP states.
+	# This option introduces a tradeoff in the replication: it reduces
+	# CPU consumption and lost messages rate at the cost of having 
+	# backup replicas that don't contain the current state that the active 
+	# replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED,
+	# FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN.
+	# 
+	# Replicate ESTABLISHED TIME_WAIT for TCP
+}
+
+#
+# General settings
+#
+General {
+	#
+	# Number of buckets in the caches: hash table
+	#
+	HashSize 8192
+
+	#
+	# Maximum number of conntracks: 
+	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
+	#
+	HashLimit 65535
+
+	#
+	# Logfile
+	#
+	LogFile /var/log/conntrackd.log
+
+	#
+	# Lockfile
+	# 
+	LockFile /var/lock/conntrack.lock
+
+	#
+	# Unix socket configuration
+	#
+	UNIX {
+		Path /tmp/sync.sock
+		Backlog 20
+	}
+
+	#
+	# Netlink socket buffer size
+	#
+	SocketBufferSize 262142
+
+	#
+	# Increase the socket buffer up to maximum if required
+	#
+	SocketBufferSizeMaxGrown 655355
+}
+
+#
+# Ignore traffic for a certain set of IP's: Usually
+# all the IP assigned to the firewall since local
+# traffic must be ignored, just forwarded connections
+# are worth to replicate
+#
+IgnoreTrafficFor {
+	IPv4_address 127.0.0.1 # loopback
+	IPv4_address 192.168.0.1
+	IPv4_address 192.168.1.1
+	IPv4_address 192.168.100.100 # dedicated link ip
+	IPv4_address 192.168.0.100 # virtual IP 1
+	IPv4_address 192.168.1.100 # virtual IP 2
+}
+
+#
+# Do not replicate certain protocol traffic 
+#
+IgnoreProtocol {
+	UDP
+	ICMP
+	IGMP
+	VRRP
+	# numeric numbers also valid
+}
+
+#
+# Strip NAT traffic
+#
+StripNAT
diff --git a/daemon/examples/sync/persistent/node1/keepalived.conf b/daemon/examples/sync/persistent/node1/keepalived.conf
new file mode 100644
index 0000000..41aa35b
--- /dev/null
+++ b/daemon/examples/sync/persistent/node1/keepalived.conf
@@ -0,0 +1,38 @@
+vrrp_sync_group G1 {   # must be before vrrp_instance declaration
+  group {
+    VI_1
+    VI_2
+  }
+  notify_master /etc/conntrackd/script_master.sh
+  notify_backup /etc/conntrackd/script_backup.sh
+}
+
+vrrp_instance VI_1 {
+    interface eth1
+    state SLAVE
+    virtual_router_id 61
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.0.100   # default CIDR mask is /32
+    }
+}
+
+vrrp_instance VI_2 {
+    interface eth0
+    state SLAVE
+    virtual_router_id 62
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.1.100
+    }
+}
diff --git a/daemon/examples/sync/persistent/node2/Makefile.am b/daemon/examples/sync/persistent/node2/Makefile.am
new file mode 100644
index 0000000..edc0ed7
--- /dev/null
+++ b/daemon/examples/sync/persistent/node2/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = conntrackd.conf keepalived.conf 
diff --git a/daemon/examples/sync/persistent/node2/conntrackd.conf b/daemon/examples/sync/persistent/node2/conntrackd.conf
new file mode 100644
index 0000000..aee4a29
--- /dev/null
+++ b/daemon/examples/sync/persistent/node2/conntrackd.conf
@@ -0,0 +1,130 @@
+#
+# Synchronizer settings
+#
+Sync {
+	Mode PERSISTENT {
+		#
+		# If a conntrack entry is not modified in <= 15 seconds, then
+		# a message is broadcasted. This mechanism is used to
+		# resynchronize nodes that just joined the multicast group
+		#
+		RefreshTime 15
+	
+		#
+		# If we don't receive a notification about the state of 
+		# an entry in the external cache after N seconds, then
+		# remove it.
+		#
+		CacheTimeout 180
+
+		#
+		# Entries committed to the connection tracking table 
+		# starts with a limited timeout of N seconds until the
+		# takeover process is completed.
+		#
+		CommitTimeout 180
+	}
+
+	#
+	# Multicast IP and interface where messages are
+	# broadcasted (dedicated link). IMPORTANT: Make sure
+	# that iptables accepts traffic for destination
+	# 225.0.0.50, eg:
+	#
+	#	iptables -I INPUT -d 225.0.0.50 -j ACCEPT
+	#	iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT
+	#
+	Multicast {
+		IPv4_address 225.0.0.50
+		IPv4_interface 192.168.100.200 # IP of dedicated link
+		Group 3780
+		Backlog 20
+	}
+
+	# Enable/Disable message checksumming
+	Checksum on
+
+	# Uncomment this if you want to replicate just certain TCP states.
+	# This option introduces a tradeoff in the replication: it reduces
+	# CPU consumption and lost messages rate at the cost of having 
+	# backup replicas that don't contain the current state that the active 
+	# replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED,
+	# FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN.
+	# 
+	# Replicate ESTABLISHED TIME_WAIT for TCP
+}
+
+#
+# General settings
+#
+General {
+	#
+	# Number of buckets in the caches: hash table
+	#
+	HashSize 8192
+
+	#
+	# Maximum number of conntracks: 
+	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
+	#
+	HashLimit 65535
+
+	#
+	# Logfile
+	#
+	LogFile /var/log/conntrackd.log
+
+	#
+	# Lockfile
+	# 
+	LockFile /var/lock/conntrack.lock
+
+	#
+	# Unix socket configuration
+	#
+	UNIX {
+		Path /tmp/sync.sock
+		Backlog 20
+	}
+
+	#
+	# Netlink socket buffer size
+	#
+	SocketBufferSize 262142
+
+	#
+	# Increase the socket buffer up to maximum if required
+	#
+	SocketBufferSizeMaxGrown 655355
+}
+
+#
+# Ignore traffic for a certain set of IP's: Usually
+# all the IP assigned to the firewall since local
+# traffic must be ignored, just forwarded connections
+# are worth to replicate
+#
+IgnoreTrafficFor {
+	IPv4_address 127.0.0.1 # loopback
+	IPv4_address 192.168.0.2
+	IPv4_address 192.168.1.2
+	IPv4_address 192.168.100.200 # dedicated link ip
+	IPv4_address 192.168.0.200 # virtual IP 1
+	IPv4_address 192.168.1.200 # virtual IP 2
+}
+
+#
+# Do not replicate certain protocol traffic 
+#
+IgnoreProtocol {
+	UDP
+	ICMP
+	IGMP
+	VRRP
+	# numeric numbers also valid
+}
+
+#
+# Strip NAT traffic
+#
+StripNAT
diff --git a/daemon/examples/sync/persistent/node2/keepalived.conf b/daemon/examples/sync/persistent/node2/keepalived.conf
new file mode 100644
index 0000000..41aa35b
--- /dev/null
+++ b/daemon/examples/sync/persistent/node2/keepalived.conf
@@ -0,0 +1,38 @@
+vrrp_sync_group G1 {   # must be before vrrp_instance declaration
+  group {
+    VI_1
+    VI_2
+  }
+  notify_master /etc/conntrackd/script_master.sh
+  notify_backup /etc/conntrackd/script_backup.sh
+}
+
+vrrp_instance VI_1 {
+    interface eth1
+    state SLAVE
+    virtual_router_id 61
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.0.100   # default CIDR mask is /32
+    }
+}
+
+vrrp_instance VI_2 {
+    interface eth0
+    state SLAVE
+    virtual_router_id 62
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.1.100
+    }
+}
diff --git a/daemon/examples/sync/persistent/script_backup.sh b/daemon/examples/sync/persistent/script_backup.sh
new file mode 100755
index 0000000..8ea2ad8
--- /dev/null
+++ b/daemon/examples/sync/persistent/script_backup.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+/usr/sbin/conntrackd -B
diff --git a/daemon/examples/sync/persistent/script_master.sh b/daemon/examples/sync/persistent/script_master.sh
new file mode 100755
index 0000000..70c26c9
--- /dev/null
+++ b/daemon/examples/sync/persistent/script_master.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+/usr/sbin/conntrackd -c
+/usr/sbin/conntrackd -R
diff --git a/daemon/include/Makefile.am b/daemon/include/Makefile.am
new file mode 100644
index 0000000..e669d73
--- /dev/null
+++ b/daemon/include/Makefile.am
@@ -0,0 +1,5 @@
+
+noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \
+		 sync.h conntrackd.h local.h us-conntrack.h \
+		 debug.h log.h hash.h mcast.h buffer.h
+
diff --git a/daemon/include/alarm.h b/daemon/include/alarm.h
new file mode 100644
index 0000000..93e6482
--- /dev/null
+++ b/daemon/include/alarm.h
@@ -0,0 +1,13 @@
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+#include "linux_list.h"
+
+struct alarm_list {
+	struct list_head	head;
+	unsigned long		expires;
+	void			*data;
+	void			(*function)(struct alarm_list *a, void *data);
+};
+
+#endif
diff --git a/daemon/include/buffer.h b/daemon/include/buffer.h
new file mode 100644
index 0000000..8d72dfb
--- /dev/null
+++ b/daemon/include/buffer.h
@@ -0,0 +1,32 @@
+#ifndef _BUFFER_H_
+#define _BUFFER_H_
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include "linux_list.h"
+
+struct buffer {
+	pthread_mutex_t lock;
+	size_t max_size;
+	size_t cur_size;
+	struct list_head head;
+};
+
+struct buffer_node {
+	struct list_head head;
+	size_t size;
+	char data[0];
+};
+
+struct buffer *buffer_create(size_t max_size);
+void buffer_destroy(struct buffer *b);
+int buffer_add(struct buffer *b, const void *data, size_t size);
+void buffer_del(struct buffer *b, void *data);
+void __buffer_del(struct buffer *b, void *data);
+void buffer_iterate(struct buffer *b, 
+		    void *data, 
+		    int (*iterate)(void *data1, void *data2));
+
+#endif
diff --git a/daemon/include/cache.h b/daemon/include/cache.h
new file mode 100644
index 0000000..7d9559a
--- /dev/null
+++ b/daemon/include/cache.h
@@ -0,0 +1,92 @@
+#ifndef _CACHE_H_
+#define _CACHE_H_
+
+#include <sys/types.h>
+#include <time.h>
+
+/* cache features */
+enum {
+	NO_FEATURES = 0,
+
+	TIMER_FEATURE = 0,
+	TIMER = (1 << TIMER_FEATURE),
+
+	LIFETIME_FEATURE = 2,
+	LIFETIME = (1 << LIFETIME_FEATURE),
+
+	__CACHE_MAX_FEATURE
+};
+#define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE
+
+struct cache;
+struct us_conntrack;
+
+struct cache_feature {
+	size_t size;
+	void (*add)(struct us_conntrack *u, void *data);
+	void (*update)(struct us_conntrack *u, void *data);
+	void (*destroy)(struct us_conntrack *u, void *data);
+	int  (*dump)(struct us_conntrack *u, void *data, char *buf, int type);
+};
+
+extern struct cache_feature lifetime_feature;
+extern struct cache_feature timer_feature;
+
+#define CACHE_MAX_NAMELEN 32
+
+struct cache {
+	char name[CACHE_MAX_NAMELEN];
+	struct hashtable *h;
+
+	unsigned int num_features;
+	struct cache_feature **features;
+	unsigned int feature_type[CACHE_MAX_FEATURE];
+	unsigned int *feature_offset;
+	struct cache_extra *extra;
+	unsigned int extra_offset;
+
+        /* statistics */
+	unsigned int add_ok;
+	unsigned int del_ok;
+	unsigned int upd_ok;
+
+	unsigned int add_fail;
+	unsigned int del_fail;
+	unsigned int upd_fail;
+
+	unsigned int commit_ok;
+	unsigned int commit_exist;
+	unsigned int commit_fail;
+
+	unsigned int flush;
+};
+
+struct cache_extra {
+	unsigned int size;
+
+	void (*add)(struct us_conntrack *u, void *data);
+	void (*update)(struct us_conntrack *u, void *data);
+	void (*destroy)(struct us_conntrack *u, void *data);
+};
+
+struct nf_conntrack;
+
+struct cache *cache_create(char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra);
+void cache_destroy(struct cache *e);
+
+struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct);
+struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct);
+struct us_conntrack *cache_update_force(struct cache *c, struct nf_conntrack *ct);
+int cache_del(struct cache *c, struct nf_conntrack *ct);
+int cache_test(struct cache *c, struct nf_conntrack *ct);
+void cache_stats(struct cache *c, int fd);
+struct us_conntrack *cache_get_conntrack(struct cache *, void *);
+void *cache_get_extra(struct cache *, void *);
+
+/* iterators */
+void cache_dump(struct cache *c, int fd, int type);
+void cache_commit(struct cache *c);
+void cache_flush(struct cache *c);
+void cache_bulk(struct cache *c);
+
+#endif
diff --git a/daemon/include/conntrackd.h b/daemon/include/conntrackd.h
new file mode 100644
index 0000000..a5f7a3a
--- /dev/null
+++ b/daemon/include/conntrackd.h
@@ -0,0 +1,174 @@
+#ifndef _CONNTRACKD_H_
+#define _CONNTRACKD_H_
+
+#include "mcast.h"
+#include "local.h"
+
+#include <stdio.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h> 
+#include "cache.h"
+#include "debug.h"
+#include <signal.h>
+#include "state_helper.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
+
+/* UNIX facilities */
+#define FLUSH_MASTER	0	/* flush kernel conntrack table 	*/
+#define RESYNC_MASTER	1	/* resync with kernel conntrack table 	*/
+#define DUMP_INTERNAL 	16	/* dump internal cache 			*/
+#define DUMP_EXTERNAL 	17	/* dump external cache 			*/
+#define COMMIT		18	/* commit external cache		*/
+#define FLUSH_CACHE	19	/* flush cache				*/
+#define KILL		20	/* kill conntrackd			*/
+#define STATS		21	/* dump statistics			*/
+#define SEND_BULK	22	/* send a bulk				*/
+#define REQUEST_DUMP	23	/* request dump 			*/
+#define DUMP_INT_XML	24	/* dump internal cache in XML		*/
+#define DUMP_EXT_XML	25	/* dump external cache in XML		*/
+
+#define DEFAULT_CONFIGFILE	"/etc/conntrackd/conntrackd.conf"
+#define DEFAULT_LOCKFILE	"/var/lock/conntrackd.lock"
+
+enum {
+	STRIP_NAT_BIT = 0,
+	STRIP_NAT = (1 << STRIP_NAT_BIT),
+
+	DELAY_DESTROY_MSG_BIT = 1,
+	DELAY_DESTROY_MSG = (1 << DELAY_DESTROY_MSG_BIT),
+
+	RELAX_TRANSITIONS_BIT = 2,
+	RELAX_TRANSITIONS = (1 << RELAX_TRANSITIONS_BIT),
+
+	SYNC_MODE_PERSISTENT_BIT = 3,
+	SYNC_MODE_PERSISTENT = (1 << SYNC_MODE_PERSISTENT_BIT),
+
+	SYNC_MODE_NACK_BIT = 4,
+	SYNC_MODE_NACK = (1 << SYNC_MODE_NACK_BIT),
+
+	DONT_CHECKSUM_BIT = 5,
+	DONT_CHECKSUM = (1 << DONT_CHECKSUM_BIT),
+};
+
+/* daemon/request modes */
+#define NOT_SET         0
+#define DAEMON		1
+#define REQUEST		2
+
+/* conntrackd modes */
+#define SYNC_MODE	0
+#define STATS_MODE      1
+
+/* FILENAME_MAX is 4096 on my system, perhaps too much? */
+#ifndef FILENAME_MAXLEN
+#define FILENAME_MAXLEN 256
+#endif
+
+union inet_address {
+	u_int32_t ipv4;
+	u_int32_t ipv6[4];
+	u_int32_t all[4];
+};
+
+#define CONFIG(x) conf.x
+
+struct ct_conf {
+	char logfile[FILENAME_MAXLEN];
+	char lockfile[FILENAME_MAXLEN];
+	int hashsize;			/* hashtable size */
+	struct mcast_conf mcast;	/* multicast settings */
+	struct local_conf local;	/* unix socket facilities */
+	int limit;
+	int refresh;
+	int cache_timeout;		/* cache entries timeout */
+	int commit_timeout;		/* committed entries timeout */
+	unsigned int netlink_buffer_size;
+	unsigned int netlink_buffer_size_max_grown;
+	unsigned char ignore_protocol[IPPROTO_MAX];
+	union inet_address *listen_to;
+	unsigned int listen_to_len;
+	unsigned int flags;
+	int family;			/* protocol family */
+	unsigned int resend_buffer_size;/* NACK protocol */
+	unsigned int window_size;
+};
+
+#define STATE(x) st.x
+
+struct ct_general_state {
+	sigset_t 			block;
+	FILE 				*log;
+	int 				local;
+	struct ct_mode 			*mode;
+	struct ignore_pool		*ignore_pool;
+
+	struct nfnl_handle		*event;         /* event handler */
+	struct nfnl_handle		*sync;          /* sync handler */
+	struct nfnl_handle		*dump;		/* dump handler */
+
+	struct nfnl_subsys_handle	*subsys_event;  /* events */
+	struct nfnl_subsys_handle	*subsys_sync;	/* resync */
+	struct nfnl_subsys_handle	*subsys_dump;   /* dump */
+
+	/* statistics */
+	u_int64_t			malformed;
+	u_int64_t 			bytes[NFCT_DIR_MAX];
+	u_int64_t 			packets[NFCT_DIR_MAX];
+};
+
+#define STATE_SYNC(x) state.sync->x
+
+struct ct_sync_state {
+	struct cache *internal; 	/* internal events cache (netlink) */
+	struct cache *external; 	/* external events cache (mcast) */
+
+	struct mcast_sock *mcast_server;  /* multicast socket: incoming */
+	struct mcast_sock *mcast_client;  /* multicast socket: outgoing  */
+
+	struct sync_mode *mcast_sync;
+	struct buffer *buffer;
+
+	u_int32_t last_seq_sent;	/* last sequence number sent */
+	u_int32_t last_seq_recv;	/* last sequence number recv */
+	u_int64_t packets_replayed;	/* number of replayed packets */
+	u_int64_t packets_lost;         /* lost packets: sequence tracking */
+};
+
+#define STATE_STATS(x) state.stats->x
+
+struct ct_stats_state {
+	struct cache *cache;            /* internal events cache (netlink) */
+};
+
+union ct_state {
+	struct ct_sync_state *sync;
+	struct ct_stats_state *stats;
+};
+
+extern struct ct_conf conf;
+extern union ct_state state;
+extern struct ct_general_state st;
+
+#ifndef IPPROTO_VRRP
+#define IPPROTO_VRRP 112
+#endif
+
+struct ct_mode {
+	int (*init)(void);
+	int (*add_fds_to_set)(fd_set *readfds);
+	void (*step)(fd_set *readfds);
+	int (*local)(int fd, int type, void *data);
+	void (*kill)(void);
+	void (*dump)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
+	void (*overrun)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
+	void (*event_new)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
+	void (*event_upd)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
+	int (*event_dst)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
+};
+
+/* conntrackd modes */
+extern struct ct_mode sync_mode;
+extern struct ct_mode stats_mode;
+
+#define MAX(x, y) x > y ? x : y
+
+#endif
diff --git a/daemon/include/debug.h b/daemon/include/debug.h
new file mode 100644
index 0000000..67f2c71
--- /dev/null
+++ b/daemon/include/debug.h
@@ -0,0 +1,53 @@
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+#if 0
+#define debug printf
+#else
+#define debug
+#endif
+
+#include <string.h>
+#include <netinet/in.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+static inline void debug_ct(struct nf_conntrack *ct, char *msg)
+{
+	struct in_addr addr, addr2, addr3, addr4;
+
+	debug("----%s (%p) ----\n", msg, ct);
+	memcpy(&addr, 
+	       nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), 
+	       sizeof(u_int32_t));
+	memcpy(&addr2, 
+	       nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), 
+	       sizeof(u_int32_t));
+	memcpy(&addr3, 
+	       nfct_get_attr(ct, ATTR_REPL_IPV4_SRC), 
+	       sizeof(u_int32_t));
+	memcpy(&addr4, 
+	       nfct_get_attr(ct, ATTR_REPL_IPV4_DST), 
+	       sizeof(u_int32_t));
+
+	debug("status: %x\n", nfct_get_attr_u32(ct, ATTR_STATUS));
+	debug("l3:%d l4:%d ",
+			nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO),
+			nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO));
+	debug("%s:%hu ->", inet_ntoa(addr),
+			   ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC)));
+	debug("%s:%hu\n",
+			inet_ntoa(addr2),
+			ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)));
+	debug("l3:%d l4:%d ",
+			nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO),
+			nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO));
+	debug("%s:%hu ->",
+			inet_ntoa(addr3),
+			ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)));
+	debug("%s:%hu\n",
+			inet_ntoa(addr4),
+			ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)));
+	debug("-------------------------\n");
+}
+
+#endif
diff --git a/daemon/include/hash.h b/daemon/include/hash.h
new file mode 100644
index 0000000..fd971e7
--- /dev/null
+++ b/daemon/include/hash.h
@@ -0,0 +1,47 @@
+#ifndef _NF_SET_HASH_H_
+#define _NF_SET_HASH_H_
+
+#include <unistd.h>
+#include <sys/types.h>
+#include "slist.h"
+#include "linux_list.h"
+
+struct hashtable;
+struct hashtable_node;
+
+struct hashtable {
+	u_int32_t hashsize;
+	u_int32_t limit;
+	u_int32_t count;
+	u_int32_t initval;
+	u_int32_t datasize;
+	
+	u_int32_t	(*hash)(const void *data, struct hashtable *table);
+	int		(*compare)(const void *data1, const void *data2);
+
+	struct slist_head 	members[0];
+};
+
+struct hashtable_node {
+	struct slist_head head;
+	char data[0];
+};
+
+struct hashtable_node *hashtable_alloc_node(int datasize, void *data);
+void hashtable_destroy_node(struct hashtable_node *h);
+
+struct hashtable *
+hashtable_create(int hashsize, int limit, int datasize,
+		 u_int32_t (*hash)(const void *data, struct hashtable *table),
+		 int (*compare)(const void *data1, const void *data2));
+void hashtable_destroy(struct hashtable *h);
+
+void *hashtable_add(struct hashtable *table, void *data);
+void *hashtable_test(struct hashtable *table, const void *data);
+int hashtable_del(struct hashtable *table, void *data);
+int hashtable_flush(struct hashtable *table);
+int hashtable_iterate(struct hashtable *table, void *data,
+		      int (*iterate)(void *data1, void *data2));
+unsigned int hashtable_counter(struct hashtable *table);
+
+#endif
diff --git a/daemon/include/ignore.h b/daemon/include/ignore.h
new file mode 100644
index 0000000..40cb02d
--- /dev/null
+++ b/daemon/include/ignore.h
@@ -0,0 +1,12 @@
+#ifndef _IGNORE_H_
+#define _IGNORE_H_
+
+struct ignore_pool {
+	struct hashtable *h;
+};
+
+struct ignore_pool *ignore_pool_create(u_int8_t family);
+void ignore_pool_destroy(struct ignore_pool *ip);
+int ignore_pool_add(struct ignore_pool *ip, void *data);
+
+#endif
diff --git a/daemon/include/jhash.h b/daemon/include/jhash.h
new file mode 100644
index 0000000..38b8780
--- /dev/null
+++ b/daemon/include/jhash.h
@@ -0,0 +1,146 @@
+#ifndef _LINUX_JHASH_H
+#define _LINUX_JHASH_H
+
+#define u32 unsigned int
+#define u8  char
+
+/* jhash.h: Jenkins hash support.
+ *
+ * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
+ *
+ * http://burtleburtle.net/bob/hash/
+ *
+ * These are the credits from Bob's sources:
+ *
+ * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
+ * hash(), hash2(), hash3, and mix() are externally useful functions.
+ * Routines to test the hash are included if SELF_TEST is defined.
+ * You can use this free for any purpose.  It has no warranty.
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ *
+ * I've modified Bob's hash to be useful in the Linux kernel, and
+ * any bugs present are surely my fault.  -DaveM
+ */
+
+/* NOTE: Arguments are modified. */
+#define __jhash_mix(a, b, c) \
+{ \
+  a -= b; a -= c; a ^= (c>>13); \
+  b -= c; b -= a; b ^= (a<<8); \
+  c -= a; c -= b; c ^= (b>>13); \
+  a -= b; a -= c; a ^= (c>>12);  \
+  b -= c; b -= a; b ^= (a<<16); \
+  c -= a; c -= b; c ^= (b>>5); \
+  a -= b; a -= c; a ^= (c>>3);  \
+  b -= c; b -= a; b ^= (a<<10); \
+  c -= a; c -= b; c ^= (b>>15); \
+}
+
+/* The golden ration: an arbitrary value */
+#define JHASH_GOLDEN_RATIO	0x9e3779b9
+
+/* The most generic version, hashes an arbitrary sequence
+ * of bytes.  No alignment or length assumptions are made about
+ * the input key.
+ */
+static inline u32 jhash(const void *key, u32 length, u32 initval)
+{
+	u32 a, b, c, len;
+	const u8 *k = key;
+
+	len = length;
+	a = b = JHASH_GOLDEN_RATIO;
+	c = initval;
+
+	while (len >= 12) {
+		a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
+		b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
+		c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
+
+		__jhash_mix(a,b,c);
+
+		k += 12;
+		len -= 12;
+	}
+
+	c += length;
+	switch (len) {
+	case 11: c += ((u32)k[10]<<24);
+	case 10: c += ((u32)k[9]<<16);
+	case 9 : c += ((u32)k[8]<<8);
+	case 8 : b += ((u32)k[7]<<24);
+	case 7 : b += ((u32)k[6]<<16);
+	case 6 : b += ((u32)k[5]<<8);
+	case 5 : b += k[4];
+	case 4 : a += ((u32)k[3]<<24);
+	case 3 : a += ((u32)k[2]<<16);
+	case 2 : a += ((u32)k[1]<<8);
+	case 1 : a += k[0];
+	};
+
+	__jhash_mix(a,b,c);
+
+	return c;
+}
+
+/* A special optimized version that handles 1 or more of u32s.
+ * The length parameter here is the number of u32s in the key.
+ */
+static inline u32 jhash2(u32 *k, u32 length, u32 initval)
+{
+	u32 a, b, c, len;
+
+	a = b = JHASH_GOLDEN_RATIO;
+	c = initval;
+	len = length;
+
+	while (len >= 3) {
+		a += k[0];
+		b += k[1];
+		c += k[2];
+		__jhash_mix(a, b, c);
+		k += 3; len -= 3;
+	}
+
+	c += length * 4;
+
+	switch (len) {
+	case 2 : b += k[1];
+	case 1 : a += k[0];
+	};
+
+	__jhash_mix(a,b,c);
+
+	return c;
+}
+
+
+/* A special ultra-optimized versions that knows they are hashing exactly
+ * 3, 2 or 1 word(s).
+ *
+ * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
+ *       done at the end is not done here.
+ */
+static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
+{
+	a += JHASH_GOLDEN_RATIO;
+	b += JHASH_GOLDEN_RATIO;
+	c += initval;
+
+	__jhash_mix(a, b, c);
+
+	return c;
+}
+
+static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
+{
+	return jhash_3words(a, b, 0, initval);
+}
+
+static inline u32 jhash_1word(u32 a, u32 initval)
+{
+	return jhash_3words(a, 0, 0, initval);
+}
+
+#endif /* _LINUX_JHASH_H */
diff --git a/daemon/include/linux_list.h b/daemon/include/linux_list.h
new file mode 100644
index 0000000..57b56d7
--- /dev/null
+++ b/daemon/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/daemon/include/local.h b/daemon/include/local.h
new file mode 100644
index 0000000..350b8bf
--- /dev/null
+++ b/daemon/include/local.h
@@ -0,0 +1,29 @@
+#ifndef _LOCAL_SOCKET_H_
+#define _LOCAL_SOCKET_H_
+
+#include <sys/un.h>
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX   108
+#endif
+
+struct local_conf {
+	int backlog;
+	int reuseaddr;
+	char path[UNIX_PATH_MAX];
+};
+
+/* local server */
+int local_server_create(struct local_conf *conf);
+void local_server_destroy(int fd);
+int do_local_server_step(int fd, void *data, 
+			 void (*process)(int fd, void *data));
+
+/* local client */
+int local_client_create(struct local_conf *conf);
+void local_client_destroy(int fd);
+int do_local_client_step(int fd, void (*process)(char *buf));
+int do_local_request(int, struct local_conf *,void (*step)(char *buf));
+void local_step(char *buf);
+
+#endif
diff --git a/daemon/include/log.h b/daemon/include/log.h
new file mode 100644
index 0000000..9ecff30
--- /dev/null
+++ b/daemon/include/log.h
@@ -0,0 +1,10 @@
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include <stdio.h>
+
+FILE *init_log(char *filename);
+void dlog(FILE *fd, char *format, ...);
+void close_log(FILE *fd);
+
+#endif
diff --git a/daemon/include/mcast.h b/daemon/include/mcast.h
new file mode 100644
index 0000000..0f3e3cd
--- /dev/null
+++ b/daemon/include/mcast.h
@@ -0,0 +1,48 @@
+#ifndef _MCAST_H_
+#define _MCAST_H_
+
+#include <netinet/in.h>
+
+struct mcast_conf {
+	int ipproto;
+	int backlog;
+	int reuseaddr;
+	unsigned short port;
+	union {
+		struct in_addr inet_addr;
+		struct in6_addr inet_addr6;
+	} in;
+	union {
+		struct in_addr interface_addr;
+		struct in6_addr interface_addr6;
+	} ifa;
+};
+
+struct mcast_stats {
+	u_int64_t bytes;
+	u_int64_t messages;
+	u_int64_t error;
+};
+
+struct mcast_sock {
+	int fd;
+	union {
+		struct sockaddr_in ipv4;
+		struct sockaddr_in6 ipv6;
+	} addr;
+	struct mcast_stats stats;
+};
+
+struct mcast_sock *mcast_server_create(struct mcast_conf *conf);
+void mcast_server_destroy(struct mcast_sock *m);
+
+struct mcast_sock *mcast_client_create(struct mcast_conf *conf);
+void mcast_client_destroy(struct mcast_sock *m);
+
+int mcast_send(struct mcast_sock *m, void *data, int size);
+int mcast_recv(struct mcast_sock *m, void *data, int size);
+
+struct mcast_stats *mcast_get_stats(struct mcast_sock *m);
+void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r);
+
+#endif
diff --git a/daemon/include/network.h b/daemon/include/network.h
new file mode 100644
index 0000000..dab50db
--- /dev/null
+++ b/daemon/include/network.h
@@ -0,0 +1,34 @@
+#ifndef _NETWORK_H_
+#define _NETWORK_H_
+
+#include <sys/types.h>
+
+struct nlnetwork {
+	u_int16_t flags; 
+	u_int16_t checksum;
+	u_int32_t seq;
+};
+
+struct nlnetwork_ack {
+	u_int16_t flags; 
+	u_int16_t checksum;
+	u_int32_t seq;
+	u_int32_t from;
+	u_int32_t to;
+};
+
+enum {
+	NET_HELLO_BIT = 0,
+	NET_HELLO = (1 << NET_HELLO_BIT),
+
+	NET_RESYNC_BIT = 1,
+	NET_RESYNC = (1 << NET_RESYNC_BIT),
+
+	NET_NACK_BIT = 2,
+	NET_NACK = (1 << NET_NACK_BIT),
+
+	NET_ACK_BIT = 3,
+	NET_ACK = (1 << NET_ACK_BIT),
+};
+
+#endif
diff --git a/daemon/include/slist.h b/daemon/include/slist.h
new file mode 100644
index 0000000..ab7fa34
--- /dev/null
+++ b/daemon/include/slist.h
@@ -0,0 +1,41 @@
+#ifndef _SLIST_H_
+#define _SLIST_H_
+
+#include "linux_list.h"
+
+#define INIT_SLIST_HEAD(ptr) ((ptr).next = NULL)
+
+struct slist_head {
+	struct slist_head *next;
+};
+
+static inline int slist_empty(const struct slist_head *h)
+{
+	return !h->next;
+}
+
+static inline void slist_del(struct slist_head *t, struct slist_head *prev)
+{
+	prev->next = t->next;
+	t->next = LIST_POISON1;
+}
+
+static inline void slist_add(struct slist_head *head, struct slist_head *t)
+{
+	struct slist_head *tmp = head->next;
+	head->next = t;
+	t->next = tmp;
+}
+
+#define slist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define slist_for_each(pos, head) \
+	for (pos = (head)->next; pos && ({ prefetch(pos.next); 1; }); \
+	     pos = pos->next)
+
+#define slist_for_each_safe(pos, prev, next, head) \
+	for (pos = (head)->next, prev = (head); \
+	     pos && ({ next = pos->next; 1; }); \
+	     ({ prev = (prev->next != next) ? prev->next : prev; }), pos = next)
+
+#endif
diff --git a/daemon/include/state_helper.h b/daemon/include/state_helper.h
new file mode 100644
index 0000000..1ed0b79
--- /dev/null
+++ b/daemon/include/state_helper.h
@@ -0,0 +1,20 @@
+#ifndef _STATE_HELPER_H_
+#define _STATE_HELPER_H_
+
+enum {
+	ST_H_SKIP,
+	ST_H_REPLICATE
+};
+
+struct state_replication_helper {
+	u_int8_t 		proto;
+	unsigned int		state;
+
+	int (*verdict)(const struct state_replication_helper *h,
+		       const struct nf_conntrack *ct); 
+};
+
+int state_helper_verdict(int type, struct nf_conntrack *ct);
+void state_helper_register(struct state_replication_helper *h, int state);
+
+#endif
diff --git a/daemon/include/sync.h b/daemon/include/sync.h
new file mode 100644
index 0000000..7756c87
--- /dev/null
+++ b/daemon/include/sync.h
@@ -0,0 +1,23 @@
+#ifndef _SYNC_HOOKS_H_
+#define _SYNC_HOOKS_H_
+
+struct nlnetwork;
+struct us_conntrack;
+
+struct sync_mode {
+	int internal_cache_flags;
+	int external_cache_flags;
+	struct cache_extra *internal_cache_extra;
+	struct cache_extra *external_cache_extra;
+
+	int  (*init)(void);
+	void (*kill)(void);
+	int  (*local)(int fd, int type, void *data);
+	int  (*pre_recv)(const struct nlnetwork *net);
+	void (*post_send)(const struct nlnetwork *net, struct us_conntrack *u);
+};
+
+extern struct sync_mode notrack;
+extern struct sync_mode nack;
+
+#endif
diff --git a/daemon/include/us-conntrack.h b/daemon/include/us-conntrack.h
new file mode 100644
index 0000000..3d71e22
--- /dev/null
+++ b/daemon/include/us-conntrack.h
@@ -0,0 +1,13 @@
+#ifndef _US_CONNTRACK_H_
+#define _US_CONNTRACK_H_
+
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+/* be careful, do not modify the layout */
+struct us_conntrack {
+	struct 	nf_conntrack *ct;
+	struct  cache *cache;          /* add new attributes here */
+	char 	data[0];
+};
+
+#endif
diff --git a/daemon/src/Makefile.am b/daemon/src/Makefile.am
new file mode 100644
index 0000000..5d1c6cb
--- /dev/null
+++ b/daemon/src/Makefile.am
@@ -0,0 +1,22 @@
+include $(top_srcdir)/Make_global.am
+
+YACC=@YACC@ -d
+
+CLEANFILES = read_config_yy.c read_config_lex.c
+
+sbin_PROGRAMS = conntrackd
+conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \
+		    local.c log.c mcast.c netlink.c proxy.c lock.c \
+		    ignore_pool.c \
+		    cache.c cache_iterators.c \
+		    cache_lifetime.c cache_timer.c \
+		    sync-mode.c sync-notrack.c sync-nack.c \
+		    traffic_stats.c stats-mode.c \
+		    network.c checksum.c \
+		    state_helper.c state_helper_tcp.c \
+		    read_config_yy.y read_config_lex.l
+
+conntrackd_LDFLAGS = $(all_libraries) -lnfnetlink -lnetfilter_conntrack \
+		     -lpthread
+
+EXTRA_DIST = read_config_yy.h
diff --git a/daemon/src/alarm.c b/daemon/src/alarm.c
new file mode 100644
index 0000000..1a465c2
--- /dev/null
+++ b/daemon/src/alarm.c
@@ -0,0 +1,141 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include "linux_list.h"
+#include "conntrackd.h"
+#include "alarm.h"
+#include "jhash.h"
+#include <pthread.h>
+#include <time.h>
+#include <errno.h>
+
+/* alarm cascade */
+#define ALARM_CASCADE_SIZE     10
+static struct list_head *alarm_cascade;
+
+/* thread stuff */
+static pthread_t alarm_thread;
+
+struct alarm_list *create_alarm()
+{	
+	return (struct alarm_list *) malloc(sizeof(struct alarm_list));
+}
+
+void destroy_alarm(struct alarm_list *t)
+{
+	free(t);
+}
+
+void set_alarm_expiration(struct alarm_list *t, unsigned long expires)
+{
+	t->expires = expires;
+}
+
+void set_alarm_function(struct alarm_list *t,
+			void (*fcn)(struct alarm_list *a, void *data))
+{
+	t->function = fcn;
+}
+
+void set_alarm_data(struct alarm_list *t, void *data)
+{
+	t->data = data;
+}
+
+void init_alarm(struct alarm_list *t)
+{
+	INIT_LIST_HEAD(&t->head);
+
+	t->expires 	= 0;
+	t->data 	= 0;
+	t->function 	= NULL;
+}
+
+void add_alarm(struct alarm_list *alarm)
+{
+	unsigned int pos = jhash(alarm, sizeof(alarm), 0) % ALARM_CASCADE_SIZE;
+
+	list_add(&alarm->head, &alarm_cascade[pos]);
+}
+
+void del_alarm(struct alarm_list *alarm)
+{
+	list_del(&alarm->head);
+}
+
+int mod_alarm(struct alarm_list *alarm, unsigned long expires)
+{
+	alarm->expires = expires;
+	return 0;
+}
+
+void __run_alarms()
+{
+	struct list_head *i, *tmp;
+	struct alarm_list *t;
+	struct timespec req = {0, 1000000000 / ALARM_CASCADE_SIZE};
+	struct timespec rem;
+	static int step = 0;
+
+retry:
+	if (nanosleep(&req, &rem) == -1) {
+		/* interrupted syscall: retry with remaining time */
+		if (errno == EINTR) {
+			memcpy(&req, &rem, sizeof(struct timespec));
+			goto retry;
+		}
+	}
+
+	lock();
+	list_for_each_safe(i, tmp, &alarm_cascade[step]) {
+		t = (struct alarm_list *) i;
+
+		t->expires--;
+		if (t->expires == 0)
+			t->function(t, t->data);
+	}
+	step = (step + 1) < ALARM_CASCADE_SIZE ? step + 1 : 0;
+	unlock();
+}
+
+void *run_alarms(void *foo)
+{
+	while(1)
+		__run_alarms();
+}
+
+int create_alarm_thread()
+{
+	int i;
+
+	alarm_cascade = malloc(sizeof(struct list_head) * ALARM_CASCADE_SIZE);
+	if (alarm_cascade == NULL)
+		return -1;
+
+	for (i=0; i<ALARM_CASCADE_SIZE; i++)
+		INIT_LIST_HEAD(&alarm_cascade[i]);
+
+	return pthread_create(&alarm_thread, NULL, run_alarms, NULL);
+}
+
+int destroy_alarm_thread()
+{
+	return pthread_cancel(alarm_thread);
+}
diff --git a/daemon/src/buffer.c b/daemon/src/buffer.c
new file mode 100644
index 0000000..fa0b859
--- /dev/null
+++ b/daemon/src/buffer.c
@@ -0,0 +1,136 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "buffer.h"
+
+struct buffer *buffer_create(size_t max_size)
+{
+	struct buffer *b;
+
+	b = malloc(sizeof(struct buffer));
+	if (b == NULL)
+		return NULL;
+	memset(b, 0, sizeof(struct buffer));
+
+	b->max_size = max_size;
+	INIT_LIST_HEAD(&b->head);
+	pthread_mutex_init(&b->lock, NULL);
+
+	return b;
+}
+
+void buffer_destroy(struct buffer *b)
+{
+	struct list_head *i, *tmp;
+	struct buffer_node *node;
+
+	pthread_mutex_lock(&b->lock);
+	list_for_each_safe(i, tmp, &b->head) {
+		node = (struct buffer_node *) i;
+		list_del(i);
+		free(node);
+	}
+	pthread_mutex_unlock(&b->lock);
+	pthread_mutex_destroy(&b->lock);
+	free(b);
+}
+
+static struct buffer_node *buffer_node_create(const void *data, size_t size)
+{
+	struct buffer_node *n;
+
+	n = malloc(sizeof(struct buffer_node) + size);
+	if (n == NULL)
+		return NULL;
+
+	INIT_LIST_HEAD(&n->head);
+	n->size = size;
+	memcpy(n->data, data, size);
+
+	return n;
+}
+
+int buffer_add(struct buffer *b, const void *data, size_t size)
+{
+	int ret = 0;
+	struct buffer_node *n;
+
+	pthread_mutex_lock(&b->lock);
+
+	/* does it fit this buffer? */
+	if (size > b->max_size) {
+		errno = ENOSPC;
+		ret = -1;
+		goto err;
+	}
+
+retry:
+	/* buffer is full: kill the oldest entry */
+	if (b->cur_size + size > b->max_size) {
+		n = (struct buffer_node *) b->head.prev;
+		list_del(b->head.prev);
+		b->cur_size -= n->size;
+		free(n);
+		goto retry;
+	}
+
+	n = buffer_node_create(data, size);
+	if (n == NULL) {
+		ret = -1;
+		goto err;
+	}
+
+	list_add(&n->head, &b->head);
+	b->cur_size += size;
+
+err:
+	pthread_mutex_unlock(&b->lock);
+	return ret;
+}
+
+void __buffer_del(struct buffer *b, void *data)
+{
+	struct buffer_node *n = container_of(data, struct buffer_node, data); 
+
+	list_del(&n->head);
+	b->cur_size -= n->size;
+	free(n);
+}
+
+void buffer_del(struct buffer *b, void *data)
+{
+	pthread_mutex_lock(&b->lock);
+	buffer_del(b, data);
+	pthread_mutex_unlock(&b->lock);
+}
+
+void buffer_iterate(struct buffer *b, 
+		    void *data, 
+		    int (*iterate)(void *data1, void *data2))
+{
+	struct list_head *i, *tmp;
+	struct buffer_node *n;
+
+	pthread_mutex_lock(&b->lock);
+	list_for_each_safe(i, tmp, &b->head) {
+		n = (struct buffer_node *) i;
+		if (iterate(n->data, data))
+			break;
+	}
+	pthread_mutex_unlock(&b->lock);
+}
diff --git a/daemon/src/cache.c b/daemon/src/cache.c
new file mode 100644
index 0000000..6f7442b
--- /dev/null
+++ b/daemon/src/cache.c
@@ -0,0 +1,446 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "jhash.h"
+#include "hash.h"
+#include "conntrackd.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include "cache.h"
+#include "debug.h"
+
+static u_int32_t hash(const void *data, struct hashtable *table)
+{
+	unsigned int a, b;
+	const struct us_conntrack *u = data;
+	struct nf_conntrack *ct = u->ct;
+
+	a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), sizeof(u_int32_t),
+		  ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) |
+		   (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO))));
+
+	b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), sizeof(u_int32_t),
+		  ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) |
+		   (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST))));
+
+	return jhash_2words(a, b, 0) % table->hashsize;
+}
+
+static u_int32_t hash6(const void *data, struct hashtable *table)
+{
+	unsigned int a, b;
+	const struct us_conntrack *u = data;
+	struct nf_conntrack *ct = u->ct;
+
+	a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(u_int32_t),
+		  ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) |
+		   (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO))));
+
+	b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_DST), sizeof(u_int32_t),
+		  ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) |
+		   (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST))));
+
+	return jhash_2words(a, b, 0) % table->hashsize;
+}
+
+static int __compare(const struct nf_conntrack *ct1, 
+		     const struct nf_conntrack *ct2)
+{
+	return ((nfct_get_attr_u8(ct1, ATTR_ORIG_L3PROTO) ==
+	  	 nfct_get_attr_u8(ct2, ATTR_ORIG_L3PROTO)) &&
+		(nfct_get_attr_u8(ct1, ATTR_ORIG_L4PROTO) ==
+		 nfct_get_attr_u8(ct2, ATTR_ORIG_L4PROTO)) && 
+		(nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_SRC) ==
+		 nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_SRC)) &&
+		(nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_DST) ==
+	 	 nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_DST)) &&
+		(nfct_get_attr_u16(ct1, ATTR_REPL_PORT_SRC) ==
+	 	 nfct_get_attr_u16(ct2, ATTR_REPL_PORT_SRC)) &&
+		(nfct_get_attr_u16(ct1, ATTR_REPL_PORT_DST) ==
+	 	 nfct_get_attr_u16(ct2, ATTR_REPL_PORT_DST)));
+}
+
+static int compare(const void *data1, const void *data2)
+{
+	const struct us_conntrack *u1 = data1;
+	const struct us_conntrack *u2 = data2;
+
+	return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_SRC) ==
+	         nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_SRC)) &&
+	 	(nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_DST) ==
+		 nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_DST)) &&
+		(nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_SRC) ==
+		 nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_SRC)) &&
+		(nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_DST) ==
+		 nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_DST)) &&
+		 __compare(u1->ct, u2->ct));
+}
+
+static int compare6(const void *data1, const void *data2)
+{
+	const struct us_conntrack *u1 = data1;
+	const struct us_conntrack *u2 = data2;
+
+	return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_SRC) ==
+	         nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_SRC)) &&
+	 	(nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_DST) ==
+		 nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_DST)) &&
+		(nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_SRC) ==
+		 nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_SRC)) &&
+		(nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_DST) ==
+		 nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_DST)) &&
+		 __compare(u1->ct, u2->ct));
+}
+
+struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = {
+	[TIMER_FEATURE]		= &timer_feature,
+	[LIFETIME_FEATURE]	= &lifetime_feature,
+};
+
+struct cache *cache_create(char *name, 
+			   unsigned int features, 
+			   u_int8_t proto,
+			   struct cache_extra *extra)
+{
+	size_t size = sizeof(struct us_conntrack);
+	int i, j = 0;
+	struct cache *c;
+	struct cache_feature *feature_array[CACHE_MAX_FEATURE] = {};
+	unsigned int feature_offset[CACHE_MAX_FEATURE] = {};
+	unsigned int feature_type[CACHE_MAX_FEATURE] = {};
+
+	c = malloc(sizeof(struct cache));
+	if (!c)
+		return NULL;
+	memset(c, 0, sizeof(struct cache));
+
+	strcpy(c->name, name);
+
+	for (i = 0; i < CACHE_MAX_FEATURE; i++) {
+		if ((1 << i) & features) {
+			feature_array[j] = cache_feature[i];
+			feature_offset[j] = size;
+			feature_type[i] = j;
+			size += cache_feature[i]->size;
+			j++;
+		}
+	}
+
+	memcpy(c->feature_type, feature_type, sizeof(feature_type));
+
+	c->features = malloc(sizeof(struct cache_feature) * j);
+	if (!c->features) {
+		free(c);
+		return NULL;
+	}
+	memcpy(c->features, feature_array, sizeof(struct cache_feature) * j);
+	c->num_features = j;
+
+	c->extra_offset = size;
+	c->extra = extra;
+	if (extra)
+		size += extra->size;
+
+	c->feature_offset = malloc(sizeof(unsigned int) * j);
+	if (!c->feature_offset) {
+		free(c->features);
+		free(c);
+		return NULL;
+	}
+	memcpy(c->feature_offset, feature_offset, sizeof(unsigned int) * j);
+
+	switch(proto) {
+	case AF_INET:
+		c->h = hashtable_create(CONFIG(hashsize),
+					CONFIG(limit),
+					size,
+					hash,
+					compare);
+		break;
+	case AF_INET6:
+		c->h = hashtable_create(CONFIG(hashsize),
+					CONFIG(limit),
+					size,
+					hash6,
+					compare6);
+		break;
+	}
+
+	if (!c->h) {
+		free(c->features);
+		free(c->feature_offset);
+		free(c);
+		return NULL;
+	}
+
+	return c;
+}
+
+void cache_destroy(struct cache *c)
+{
+	lock();
+	hashtable_destroy(c->h);
+	unlock();
+	free(c->features);
+	free(c->feature_offset);
+	free(c);
+}
+
+static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct)
+{
+	int i;
+	size_t size = c->h->datasize;
+	char buf[size];
+	struct us_conntrack *u = (struct us_conntrack *) buf;
+	struct nf_conntrack *newct;
+
+	memset(u, 0, size);
+
+	u->cache = c;
+	if ((u->ct = newct = nfct_new()) == NULL) {
+		errno = ENOMEM;
+		return 0;
+	}
+	memcpy(u->ct, ct, nfct_sizeof(ct));
+
+	u = hashtable_add(c->h, u);
+	if (u) {
+		void *data = u->data;
+
+        	for (i = 0; i < c->num_features; i++) {
+			c->features[i]->add(u, data);
+			data += c->features[i]->size;
+		}
+
+		if (c->extra)
+			c->extra->add(u, ((void *) u) + c->extra_offset);
+
+		return u;
+	}
+	free(newct);
+
+	return NULL;
+}
+
+struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct)
+{
+	struct us_conntrack *u;
+
+	u = __add(c, ct);
+	if (u) {
+		c->add_ok++;
+		return u;
+	}
+	c->add_fail++;
+
+	return NULL;
+}
+
+struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct)
+{
+	struct us_conntrack *u;
+
+	lock();
+	u = __cache_add(c, ct);
+	unlock();
+
+	return u;
+}
+
+static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct)
+{
+	size_t size = c->h->datasize;
+	char buf[size];
+	struct us_conntrack *u = (struct us_conntrack *) buf;
+
+	u->ct = ct;
+
+	u = (struct us_conntrack *) hashtable_test(c->h, u);
+	if (u) {
+		int i;
+		void *data = u->data;
+
+		for (i = 0; i < c->num_features; i++) {
+			c->features[i]->update(u, data);
+			data += c->features[i]->size;
+		}
+
+		if (c->extra)
+			c->extra->update(u, ((void *) u) + c->extra_offset);
+
+		if (nfct_attr_is_set(ct, ATTR_STATUS))
+		    	nfct_set_attr_u32(u->ct, ATTR_STATUS,
+					  nfct_get_attr_u32(ct, ATTR_STATUS));
+		if (nfct_attr_is_set(ct, ATTR_TCP_STATE))
+			nfct_set_attr_u8(u->ct, ATTR_TCP_STATE,
+					 nfct_get_attr_u8(ct, ATTR_TCP_STATE));
+		if (nfct_attr_is_set(ct, ATTR_TIMEOUT))
+			nfct_set_attr_u32(u->ct, ATTR_TIMEOUT,
+					  nfct_get_attr_u32(ct, ATTR_TIMEOUT));
+
+		return u;
+	} 
+	return NULL;
+}
+
+struct us_conntrack *__cache_update(struct cache *c, struct nf_conntrack *ct)
+{
+	struct us_conntrack *u;
+
+	u = __update(c, ct);
+	if (u) {
+		c->upd_ok++;
+		return u;
+	}
+	c->upd_fail++;
+	
+	return NULL;
+}
+
+struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct)
+{
+	struct us_conntrack *u;
+
+	lock();
+	u = __cache_update(c, ct);
+	unlock();
+
+	return u;
+}
+
+struct us_conntrack *cache_update_force(struct cache *c,
+					struct nf_conntrack *ct)
+{
+	struct us_conntrack *u;
+
+	lock();
+	if ((u = __update(c, ct)) != NULL) {
+		c->upd_ok++;
+		unlock();
+		return u;
+	}
+	if ((u = __add(c, ct)) != NULL) {
+		c->add_ok++;
+		unlock();
+		return u;
+	}
+	c->add_fail++;
+	unlock();
+	return NULL;
+}
+
+int cache_test(struct cache *c, struct nf_conntrack *ct)
+{
+	size_t size = c->h->datasize;
+	char buf[size];
+	struct us_conntrack *u = (struct us_conntrack *) buf;
+	void *ret;
+
+	u->ct = ct;
+
+	lock();
+	ret = hashtable_test(c->h, u);
+	unlock();
+
+	return ret != NULL;
+}
+
+static int __del(struct cache *c, struct nf_conntrack *ct)
+{
+	size_t size = c->h->datasize;
+	char buf[size];
+	struct us_conntrack *u = (struct us_conntrack *) buf;
+
+	u->ct = ct;
+
+	u = (struct us_conntrack *) hashtable_test(c->h, u);
+	if (u) {
+		int i;
+		void *data = u->data;
+		struct nf_conntrack *p = u->ct;
+
+		for (i = 0; i < c->num_features; i++) {
+			c->features[i]->destroy(u, data);
+			data += c->features[i]->size;
+		}
+
+		if (c->extra)
+			c->extra->destroy(u, ((void *) u) + c->extra_offset);
+
+		hashtable_del(c->h, u);
+		free(p);
+		return 1;
+	}
+	return 0;
+}
+
+int __cache_del(struct cache *c, struct nf_conntrack *ct)
+{
+	if (__del(c, ct)) {
+		c->del_ok++;
+		return 1;
+	}
+	c->del_fail++;
+
+	return 0;
+}
+
+int cache_del(struct cache *c, struct nf_conntrack *ct)
+{
+	int ret;
+
+	lock();
+	ret = __cache_del(c, ct);
+	unlock();
+
+	return ret;
+}
+
+struct us_conntrack *cache_get_conntrack(struct cache *c, void *data)
+{
+	return data - c->extra_offset;
+}
+
+void *cache_get_extra(struct cache *c, void *data)
+{
+	return data + c->extra_offset;
+}
+
+void cache_stats(struct cache *c, int fd)
+{
+	char buf[512];
+	int size;
+
+	lock();
+	size = sprintf(buf, "cache %s:\n"
+			    "current active connections:\t%12u\n"
+			    "connections created:\t\t%12u\tfailed:\t%12u\n"
+			    "connections updated:\t\t%12u\tfailed:\t%12u\n"
+			    "connections destroyed:\t\t%12u\tfailed:\t%12u\n\n",
+			    			 c->name,
+			    			 hashtable_counter(c->h),
+			    			 c->add_ok, 
+			    			 c->add_fail,
+						 c->upd_ok,
+						 c->upd_fail,
+						 c->del_ok,
+						 c->del_fail);
+	unlock();
+	send(fd, buf, size, 0);
+}
diff --git a/daemon/src/cache_iterators.c b/daemon/src/cache_iterators.c
new file mode 100644
index 0000000..5d5d22b
--- /dev/null
+++ b/daemon/src/cache_iterators.c
@@ -0,0 +1,229 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cache.h"
+#include "jhash.h"
+#include "hash.h"
+#include "conntrackd.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include "debug.h"
+
+struct __dump_container {
+	int fd;
+	int type;
+};
+
+static int do_dump(void *data1, void *data2)
+{
+	char buf[1024];
+	int size;
+	struct __dump_container *container = data1;
+	struct us_conntrack *u = data2;
+	void *data = u->data;
+	int i;
+
+	memset(buf, 0, sizeof(buf));
+	size = nfct_snprintf(buf, 
+			     sizeof(buf), 
+			     u->ct, 
+			     NFCT_T_UNKNOWN, 
+			     container->type,
+			     0);
+
+	for (i = 0; i < u->cache->num_features; i++) {
+		if (u->cache->features[i]->dump) {
+			size += u->cache->features[i]->dump(u, 
+							    data, 
+							    buf+size,
+							    container->type);
+			data += u->cache->features[i]->size;
+		}
+	}
+	size += sprintf(buf+size, "\n");
+	if (send(container->fd, buf, size, 0) == -1) {
+		if (errno != EPIPE)
+			return -1;
+	}
+
+	return 0;
+}
+
+void cache_dump(struct cache *c, int fd, int type)
+{
+	struct __dump_container tmp = {
+		.fd	= fd,
+		.type	= type
+	};
+
+	lock();
+	hashtable_iterate(c->h, (void *) &tmp, do_dump);
+	unlock();
+}
+
+static int do_commit(void *data1, void *data2)
+{
+	int ret;
+	struct cache *c = data1;
+	struct us_conntrack *u = data2;
+	struct nf_conntrack *ct;
+	char buf[4096];
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
+
+	ct = nfct_clone(u->ct);
+	if (ct == NULL)
+		return 0;
+
+	if (nfct_attr_is_set(ct, ATTR_STATUS)) {
+		u_int32_t status = nfct_get_attr_u32(ct, ATTR_STATUS);
+		status &= ~IPS_EXPECTED;
+		nfct_set_attr_u32(ct, ATTR_STATUS, status);
+	}
+
+	if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT))
+		nfct_setobjopt(ct, NFCT_SOPT_UNDO_SNAT);
+	if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT))
+		nfct_setobjopt(ct, NFCT_SOPT_UNDO_DNAT);
+	if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT))
+		nfct_setobjopt(ct, NFCT_SOPT_UNDO_SPAT);
+	if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT))
+		nfct_setobjopt(ct, NFCT_SOPT_UNDO_DPAT);
+
+        /* 
+	 * Set a reduced timeout for candidate-to-be-committed
+	 * conntracks that live in the external cache
+	 */
+	nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout));
+
+        ret = nfct_build_query(STATE(subsys_sync),
+			       NFCT_Q_CREATE,
+			       ct,
+			       nlh,
+			       sizeof(buf));
+
+	free(ct);
+
+	if (ret == -1) {
+		/* XXX: Please cleanup this debug crap, default in logfile */
+		debug("--- failed to build: %s --- \n", strerror(errno));
+		return 0;
+	}
+
+	ret = nfnl_query(STATE(sync), nlh);
+	if (ret == -1) {
+		switch(errno) {
+			case EEXIST:
+				c->commit_exist++;
+				break;
+			default:
+				c->commit_fail++;
+				break;
+		}
+		debug("--- failed to commit: %s --- \n", strerror(errno));
+	} else {
+		c->commit_ok++;
+		debug("----- commit -----\n");
+	}
+
+	/* keep iterating even if we have found errors */
+	return 0;
+}
+
+void cache_commit(struct cache *c)
+{
+	unsigned int commit_ok = c->commit_ok;
+	unsigned int commit_exist = c->commit_exist;
+	unsigned int commit_fail = c->commit_fail;
+
+	lock();
+	hashtable_iterate(c->h, c, do_commit);
+	unlock();
+
+	/* calculate new entries committed */
+	commit_ok = c->commit_ok - commit_ok;
+	commit_fail = c->commit_fail - commit_fail;
+	commit_exist = c->commit_exist - commit_exist;
+
+	/* log results */
+	dlog(STATE(log), "Committed %u new entries", commit_ok);
+
+	if (commit_exist)
+		dlog(STATE(log), "%u entries ignored, "
+				 "already exist", commit_exist);
+	if (commit_fail)
+		dlog(STATE(log), "%u entries can't be "
+				 "committed", commit_fail);
+}
+
+static int do_flush(void *data1, void *data2)
+{
+	struct cache *c = data1;
+	struct us_conntrack *u = data2;
+	void *data = u->data;
+	int i;
+
+	for (i = 0; i < c->num_features; i++) {
+		c->features[i]->destroy(u, data);
+		data += c->features[i]->size;
+	}
+	free(u->ct);
+
+	return 0;
+}
+
+void cache_flush(struct cache *c)
+{
+	lock();
+	hashtable_iterate(c->h, c, do_flush);
+	hashtable_flush(c->h);
+	c->flush++;
+	unlock();
+}
+
+#include "sync.h"
+#include "network.h"
+
+static int do_bulk(void *data1, void *data2)
+{
+	int ret;
+	struct us_conntrack *u = data2;
+	char buf[4096];
+	struct nlnetwork *net = (struct nlnetwork *) buf;
+
+	ret = build_network_msg(NFCT_Q_UPDATE,
+				STATE(subsys_sync),
+				u->ct,
+				buf,
+				sizeof(buf));
+	if (ret == -1)
+		debug_ct(u->ct, "failed to build");
+
+	mcast_send_netmsg(STATE_SYNC(mcast_client), net);
+	STATE_SYNC(mcast_sync)->post_send(net, u);
+
+	/* keep iterating even if we have found errors */
+	return 0;
+}
+
+void cache_bulk(struct cache *c)
+{
+	lock();
+	hashtable_iterate(c->h, NULL, do_bulk);
+	unlock();
+}
diff --git a/daemon/src/cache_lifetime.c b/daemon/src/cache_lifetime.c
new file mode 100644
index 0000000..ae54df2
--- /dev/null
+++ b/daemon/src/cache_lifetime.c
@@ -0,0 +1,65 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include "conntrackd.h"
+#include "us-conntrack.h"
+#include "cache.h"
+#include "alarm.h"
+
+static void lifetime_add(struct us_conntrack *u, void *data)
+{
+	long *lifetime = data;
+	struct timeval tv;
+
+	gettimeofday(&tv, NULL);
+
+	*lifetime = tv.tv_sec;
+}
+
+static void lifetime_update(struct us_conntrack *u, void *data)
+{
+}
+
+static void lifetime_destroy(struct us_conntrack *u, void *data)
+{
+}
+
+static int lifetime_dump(struct us_conntrack *u, 
+			 void *data, 
+			 char *buf, 
+			 int type)
+{
+	long *lifetime = data;
+	struct timeval tv;
+
+	if (type == NFCT_O_XML)
+		return 0;
+
+	gettimeofday(&tv, NULL);
+
+	return sprintf(buf, " [active since %lds]", tv.tv_sec - *lifetime);
+}
+
+struct cache_feature lifetime_feature = {
+	.size		= sizeof(long),
+	.add		= lifetime_add,
+	.update		= lifetime_update,
+	.destroy	= lifetime_destroy,
+	.dump		= lifetime_dump
+};
diff --git a/daemon/src/cache_timer.c b/daemon/src/cache_timer.c
new file mode 100644
index 0000000..213b59a
--- /dev/null
+++ b/daemon/src/cache_timer.c
@@ -0,0 +1,72 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include "conntrackd.h"
+#include "us-conntrack.h"
+#include "cache.h"
+#include "alarm.h"
+
+static void timeout(struct alarm_list *a, void *data)
+{
+	struct us_conntrack *u = data;
+
+	debug_ct(u->ct, "expired timeout");
+	__cache_del(u->cache, u->ct);
+}
+
+static void timer_add(struct us_conntrack *u, void *data)
+{
+	struct alarm_list *alarm = data;
+
+	init_alarm(alarm);
+	set_alarm_expiration(alarm, CONFIG(cache_timeout));
+	set_alarm_data(alarm, u);
+	set_alarm_function(alarm, timeout);
+	add_alarm(alarm);
+}
+
+static void timer_update(struct us_conntrack *u, void *data)
+{
+	struct alarm_list *alarm = data;
+	mod_alarm(alarm, CONFIG(cache_timeout));
+}
+
+static void timer_destroy(struct us_conntrack *u, void *data)
+{
+	struct alarm_list *alarm = data;
+	del_alarm(alarm);
+}
+
+static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type)
+{
+ 	struct alarm_list *alarm = data;
+
+	if (type == NFCT_O_XML)
+		return 0;
+
+	return sprintf(buf, " [expires in %ds]", alarm->expires);
+}
+
+struct cache_feature timer_feature = {
+	.size		= sizeof(struct alarm_list),
+	.add		= timer_add,
+	.update		= timer_update,
+	.destroy	= timer_destroy,
+	.dump		= timer_dump
+};
diff --git a/daemon/src/checksum.c b/daemon/src/checksum.c
new file mode 100644
index 0000000..41866ff
--- /dev/null
+++ b/daemon/src/checksum.c
@@ -0,0 +1,32 @@
+/* 
+ * Extracted from RFC 1071 with some minor changes to fix compilation on GCC,
+ * this can probably be improved
+ * 					--pablo 11/feb/07
+ */
+
+#include <conntrackd.h>
+
+unsigned short do_csum(const void *addr, unsigned int count)
+{
+	unsigned int sum = 0;
+
+	/* checksumming disabled, just skip */
+	if (CONFIG(flags) & DONT_CHECKSUM)
+		return 0;
+
+	while(count > 1)  {
+		/*  This is the inner loop */
+		sum += *((unsigned short *) addr++);
+		count -= 2;
+	}
+
+	/*  Add left-over byte, if any */
+	if(count > 0)
+		sum += *((unsigned char *) addr);
+
+	/*  Fold 32-bit sum to 16 bits */
+	while (sum>>16)
+		sum = (sum & 0xffff) + (sum >> 16);
+
+	return ~sum;
+}
diff --git a/daemon/src/hash.c b/daemon/src/hash.c
new file mode 100644
index 0000000..274a140
--- /dev/null
+++ b/daemon/src/hash.c
@@ -0,0 +1,199 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: generic hash table implementation
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include "slist.h"
+#include "hash.h"
+
+
+struct hashtable_node *hashtable_alloc_node(int datasize, void *data)
+{
+	struct hashtable_node *n;
+	int size = sizeof(struct hashtable_node) + datasize;
+
+	n = malloc(size);
+	if (!n)
+		return NULL;
+	memset(n, 0, size);
+	memcpy(n->data, data, datasize);
+
+	return n;
+}
+
+void hashtable_destroy_node(struct hashtable_node *h)
+{
+	free(h);
+}
+
+struct hashtable *
+hashtable_create(int hashsize, int limit, int datasize,
+		 u_int32_t (*hash)(const void *data, struct hashtable *table),
+		 int (*compare)(const void *data1, const void *data2))
+{
+	int i;
+	struct hashtable *h;
+	struct hashtype *t;
+	int size = sizeof(struct hashtable)
+		   + hashsize * sizeof(struct slist_head);
+
+	h = (struct hashtable *) malloc(size);
+	if (!h) {
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	memset(h, 0, size);
+	for (i=0; i<hashsize; i++)
+		INIT_SLIST_HEAD(h->members[i]);
+
+	h->hashsize = hashsize;
+	h->limit = limit;
+	h->datasize = datasize;
+	h->hash = hash;
+	h->compare = compare;
+
+	return h;
+}
+
+void hashtable_destroy(struct hashtable *h)
+{
+	hashtable_flush(h);
+	free(h);
+}
+
+void *hashtable_add(struct hashtable *table, void *data)
+{
+	struct slist_head *e;
+	struct hashtable_node *n;
+	u_int32_t id;
+	int i;
+
+	/* hash table is full */
+	if (table->count >= table->limit) {
+		errno = ENOSPC;
+		return NULL;
+	}
+
+	id = table->hash(data, table);
+
+	slist_for_each(e, &table->members[id]) {
+		n = slist_entry(e, struct hashtable_node, head);
+		if (table->compare(n->data, data)) {
+			errno = EEXIST;
+			return NULL;
+		}
+	}
+
+	n = hashtable_alloc_node(table->datasize, data);
+	if (n == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	slist_add(&table->members[id], &n->head);
+	table->count++;
+
+	return n->data;
+}
+
+void *hashtable_test(struct hashtable *table, const void *data)
+{
+	struct slist_head *e;
+	u_int32_t id;
+	struct hashtable_node *n;
+	int i;
+
+	id = table->hash(data, table);
+
+	slist_for_each(e, &table->members[id]) {
+		n = slist_entry(e, struct hashtable_node, head);
+		if (table->compare(n->data, data))
+			return n->data;
+	}
+
+	errno = ENOENT;
+	return NULL;
+}
+
+int hashtable_del(struct hashtable *table, void *data)
+{
+	struct slist_head *e, *next, *prev;
+	u_int32_t id;
+	struct hashtable_node *n;
+	int i;
+
+	id = table->hash(data, table);
+
+	slist_for_each_safe(e, prev, next, &table->members[id]) {
+		n = slist_entry(e, struct hashtable_node, head);
+		if (table->compare(n->data, data)) {
+			slist_del(e, prev);
+			hashtable_destroy_node(n);
+			table->count--;
+			return 0;
+		}
+	}
+	errno = ENOENT;
+	return -1;
+}
+
+int hashtable_flush(struct hashtable *table)
+{
+	int i;
+	struct slist_head *e, *next, *prev;
+	struct hashtable_node *n;
+
+	for (i=0; i < table->hashsize; i++)
+		slist_for_each_safe(e, prev, next, &table->members[i]) {
+			n = slist_entry(e, struct hashtable_node, head);
+			slist_del(e, prev);
+			hashtable_destroy_node(n);
+		}
+
+	table->count = 0;
+	
+	return 0;
+}
+
+int hashtable_iterate(struct hashtable *table, void *data,
+		      int (*iterate)(void *data1, void *data2))
+{
+	int i;
+	struct slist_head *e, *next, *prev;
+	struct hashtable_node *n;
+
+	for (i=0; i < table->hashsize; i++) {
+		slist_for_each_safe(e, prev, next, &table->members[i]) {
+			n = slist_entry(e, struct hashtable_node, head);
+			if (iterate(data, n->data) == -1)
+				return -1;
+		}
+	}
+	return 0;
+}
+
+unsigned int hashtable_counter(struct hashtable *table)
+{
+	return table->count;
+}
diff --git a/daemon/src/ignore_pool.c b/daemon/src/ignore_pool.c
new file mode 100644
index 0000000..5946617
--- /dev/null
+++ b/daemon/src/ignore_pool.c
@@ -0,0 +1,136 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "jhash.h"
+#include "hash.h"
+#include "conntrackd.h"
+#include "ignore.h"
+#include "debug.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+#define IGNORE_POOL_SIZE 32
+#define IGNORE_POOL_LIMIT 1024
+
+static u_int32_t hash(const void *data, struct hashtable *table)
+{
+	const u_int32_t *ip = data;
+
+	return jhash_1word(*ip, 0) % table->hashsize;
+}
+
+static u_int32_t hash6(const void *data, struct hashtable *table)
+{
+	return jhash(data, sizeof(u_int32_t)*4, 0) % table->hashsize;
+}
+
+static int compare(const void *data1, const void *data2)
+{
+	const u_int32_t *ip1 = data1;
+	const u_int32_t *ip2 = data2;
+
+	return *ip1 == *ip2;
+}
+
+static int compare6(const void *data1, const void *data2)
+{
+	return memcmp(data1, data2, sizeof(u_int32_t)*4) == 0;
+}
+
+struct ignore_pool *ignore_pool_create(u_int8_t proto)
+{
+	int i, j = 0;
+	struct ignore_pool *ip;
+
+	ip = malloc(sizeof(struct ignore_pool));
+	if (!ip)
+		return NULL;
+	memset(ip, 0, sizeof(struct ignore_pool));
+
+	switch(proto) {
+	case AF_INET:
+		ip->h = hashtable_create(IGNORE_POOL_SIZE,
+					 IGNORE_POOL_LIMIT,
+					 sizeof(u_int32_t),
+					 hash,
+					 compare);
+		break;
+	case AF_INET6:
+		ip->h = hashtable_create(IGNORE_POOL_SIZE,
+					 IGNORE_POOL_LIMIT,
+					 sizeof(u_int32_t)*4,
+					 hash6,
+					 compare6);
+		break;
+	}
+
+	if (!ip->h) {
+		free(ip);
+		return NULL;
+	}
+
+	return ip;
+}
+
+void ignore_pool_destroy(struct ignore_pool *ip)
+{
+	hashtable_destroy(ip->h);
+	free(ip);
+}
+
+int ignore_pool_add(struct ignore_pool *ip, void *data)
+{
+	if (!hashtable_add(ip->h, data))
+		return 0;
+
+	return 1;
+}
+
+int __ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct)
+{
+	return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) ||
+		hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST)) ||
+		hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC)) ||
+		hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_DST)));
+}
+
+int __ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct)
+{
+	return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) ||
+	        hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) ||
+	        hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)) ||
+	        hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_DST)));
+}
+
+int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct)
+{
+	int ret;
+
+	switch(nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO)) {
+	case AF_INET:
+		ret = __ignore_pool_test_ipv4(ip, ct);
+		break;
+	case AF_INET6:
+		ret = __ignore_pool_test_ipv6(ip, ct);
+		break;
+	default:
+		dlog(STATE(log), "unknown conntrack layer 3 protocol?");
+		break;
+	}
+
+	return ret;
+}
diff --git a/daemon/src/local.c b/daemon/src/local.c
new file mode 100644
index 0000000..eef70ad
--- /dev/null
+++ b/daemon/src/local.c
@@ -0,0 +1,159 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: UNIX sockets library
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include "debug.h"
+
+#include "local.h"
+
+int local_server_create(struct local_conf *conf)
+{
+	int fd;
+	int len;
+	struct sockaddr_un local;
+
+	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+		debug("local_server_create:socket");
+		return -1;
+	}
+
+	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &conf->reuseaddr, 
+				sizeof(conf->reuseaddr)) == -1) {
+		debug("local_server_create:setsockopt");
+		close(fd);
+		return -1;
+	}
+
+	local.sun_family = AF_UNIX;
+	strcpy(local.sun_path, conf->path);
+	len = strlen(local.sun_path) + sizeof(local.sun_family);
+	unlink(conf->path);
+
+	if (bind(fd, (struct sockaddr *) &local, len) == -1) {
+		debug("local_server_create:bind");
+		close(fd);
+		return -1;
+	}
+
+	if (listen(fd, conf->backlog) == -1) {
+		close(fd);
+		debug("local_server_create:listen");
+		return -1;
+	}
+
+	return fd;
+}
+
+void local_server_destroy(int fd)
+{
+	close(fd);
+}
+
+int do_local_server_step(int fd, void *data, 
+			 void (*process)(int fd, void *data))
+{
+	int rfd;
+	struct sockaddr_un local;
+	size_t sin_size = sizeof(struct sockaddr_un);
+	
+	if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) {
+		debug("do_local_server_step:accept");
+		return -1;
+	}
+
+	process(rfd, data);
+	close(rfd);
+
+	return 0;
+}
+
+int local_client_create(struct local_conf *conf)
+{
+	int len;
+	struct sockaddr_un local;
+	int fd;
+
+	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+		return -1;
+
+	local.sun_family = AF_UNIX;
+	strcpy(local.sun_path, conf->path);
+	len = strlen(local.sun_path) + sizeof(local.sun_family);
+
+	if (connect(fd, (struct sockaddr *) &local, len) == -1) {
+		close(fd);
+		debug("local_client_create: connect: ");
+		return -1;
+	}
+
+	return fd;
+}
+
+void local_client_destroy(int fd)
+{
+	close(fd);
+}
+
+int do_local_client_step(int fd, void (*process)(char *buf))
+{
+	int numbytes;
+	char buf[1024];
+
+	memset(buf, 0, sizeof(buf));
+	while ((numbytes = recv(fd, buf, sizeof(buf)-1, 0)) > 0) {
+		buf[sizeof(buf)-1] = '\0';
+		if (process)
+			process(buf);
+		memset(buf, 0, sizeof(buf));
+	}
+
+	return 0;
+}
+
+void local_step(char *buf)
+{
+	printf(buf);
+}
+
+int do_local_request(int request,
+		     struct local_conf *conf,
+		     void (*step)(char *buf))
+{
+	int fd, ret;
+
+	fd = local_client_create(conf);
+	if (fd == -1)
+		return -1;
+
+	ret = send(fd, &request, sizeof(int), 0);
+	if (ret == -1) {
+		debug("send:");
+		return -1;
+	}
+
+	do_local_client_step(fd, step);
+
+	local_client_destroy(fd);
+	
+	return 0;
+}
diff --git a/daemon/src/lock.c b/daemon/src/lock.c
new file mode 100644
index 0000000..cd68baf
--- /dev/null
+++ b/daemon/src/lock.c
@@ -0,0 +1,32 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+
+static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;
+
+void lock()
+{
+	pthread_mutex_lock(&global_lock);
+}
+
+void unlock()
+{
+	pthread_mutex_unlock(&global_lock);
+}
diff --git a/daemon/src/log.c b/daemon/src/log.c
new file mode 100644
index 0000000..88cadea
--- /dev/null
+++ b/daemon/src/log.c
@@ -0,0 +1,57 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: Logging support for the conntrack daemon
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <stdarg.h>
+#include <string.h>
+
+FILE *init_log(char *filename)
+{
+	FILE *fd;
+
+	fd = fopen(filename, "a+");
+	if (fd == NULL) {
+		fprintf(stderr, "can't open log file `%s'\n", filename);
+		return NULL;
+	}
+
+	return fd;
+}
+
+void dlog(FILE *fd, char *format, ...)
+{
+	time_t t = time(NULL);
+	char *buf = ctime(&t);
+	va_list args;
+
+	buf[strlen(buf)-1]='\0';
+	va_start(args, format);
+	fprintf(fd, "[%s] (pid=%d) ", buf, getpid());
+	vfprintf(fd, format, args);
+	va_end(args);
+	fprintf(fd, "\n");
+	fflush(fd);
+}
+
+void close_log(FILE *fd)
+{
+	fclose(fd);
+}
diff --git a/daemon/src/main.c b/daemon/src/main.c
new file mode 100644
index 0000000..1c75970
--- /dev/null
+++ b/daemon/src/main.c
@@ -0,0 +1,302 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include "conntrackd.h"
+#include "log.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/utsname.h>
+#include <linux/capability.h>
+#include <errno.h>
+#include "hash.h"
+#include "jhash.h"
+
+struct ct_general_state st;
+union ct_state state;
+
+static const char usage_daemon_commands[] =
+	"Daemon mode commands:\n"
+	"  -d [options]\t\tRun in daemon mode\n"
+	"  -S [options]\t\tRun in statistics mode\n";
+
+static const char usage_client_commands[] = 
+	"Client mode commands:\n"
+	"  -c, commit external cache to conntrack table\n"
+	"  -f, flush internal and external cache\n"
+	"  -F, flush kernel conntrack table\n"
+	"  -i, display content of the internal cache\n"
+	"  -e, display the content of the external cache\n"
+	"  -k, kill conntrack daemon\n"
+	"  -s, dump statistics\n"
+	"  -R, resync with kernel conntrack table\n"
+	"  -n, request resync with other node (only NACK mode)\n"
+	"  -x, dump cache in XML format (requires -i or -e)";
+
+static const char usage_options[] =
+	"Options:\n"
+	"  -C [configfile], configuration file path\n";
+
+void show_usage(char *progname)
+{
+	fprintf(stdout, "Connection tracking userspace daemon v%s\n", VERSION);
+	fprintf(stdout, "Usage: %s [commands] [options]\n\n", progname);
+	fprintf(stdout, "%s\n", usage_daemon_commands);
+	fprintf(stdout, "%s\n", usage_client_commands);
+	fprintf(stdout, "%s\n", usage_options);
+}
+
+/* These live in run.c */
+int init(int);
+void run(void);
+
+void set_operation_mode(int *current, int want, char *argv[])
+{
+	if (*current == NOT_SET) {
+		*current = want;
+		return;
+	}
+	if (*current != want) {
+		show_usage(argv[0]);
+		fprintf(stderr, "\nError: Invalid parameters\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static int check_capabilities(void)
+{
+	int ret;
+	cap_user_header_t hcap;
+	cap_user_data_t dcap;
+
+	hcap = malloc(sizeof(cap_user_header_t));
+	if (!hcap)
+		return -1;
+
+	hcap->version = _LINUX_CAPABILITY_VERSION;
+	hcap->pid = getpid();
+
+	dcap = malloc(sizeof(cap_user_data_t));
+	if (!dcap) {
+		free(hcap);
+		return -1;
+	}
+
+	if (capget(hcap, dcap) == -1) {
+		free(hcap);
+		free(dcap);
+		return -1;
+	}
+
+	ret = dcap->permitted & (1 << CAP_NET_ADMIN);
+
+	free(hcap);
+	free(dcap);
+
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret, i, config_set = 0, action;
+	char config_file[PATH_MAX];
+	int type = 0, mode = 0;
+	struct utsname u;
+	int version, major, minor;
+
+	/* Check kernel version: it must be >= 2.6.18 */
+	if (uname(&u) == -1) {
+		fprintf(stderr, "Can't retrieve kernel version via uname()\n");
+		exit(EXIT_FAILURE);
+	}
+	sscanf(u.release, "%d.%d.%d", &version, &major, &minor);
+	if (version < 2 && major < 6) {
+		fprintf(stderr, "Linux kernel version must be >= 2.6.18\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (major == 6 && minor < 18) {
+		fprintf(stderr, "Linux kernel version must be >= 2.6.18\n");
+		exit(EXIT_FAILURE);
+	}
+
+	ret = check_capabilities();
+	switch (ret) {
+		case -1:
+			fprintf(stderr, "Can't get capabilities\n");
+			exit(EXIT_FAILURE);
+			break;
+		case 0:
+			fprintf(stderr, "You require CAP_NET_ADMIN in order "
+					"to run conntrackd\n");
+			exit(EXIT_FAILURE);
+			break;
+		default:
+			break;
+	}
+
+	for (i=1; i<argc; i++) {
+		switch(argv[i][1]) {
+		case 'd':
+			set_operation_mode(&type, DAEMON, argv);
+			break;
+		case 'c':
+			set_operation_mode(&type, REQUEST, argv);
+			action = COMMIT;
+			break;
+		case 'i':
+			set_operation_mode(&type, REQUEST, argv);
+			action = DUMP_INTERNAL;
+			break;
+		case 'e':
+			set_operation_mode(&type, REQUEST, argv);
+			action = DUMP_EXTERNAL;
+			break;
+		case 'C':
+			if (++i < argc) {
+				strncpy(config_file, argv[i], PATH_MAX);
+				if (strlen(argv[i]) >= PATH_MAX){
+					config_file[PATH_MAX-1]='\0';
+					fprintf(stderr, "Path to config file "
+						        "to long. Cutting it "
+							"down to %d characters",
+							PATH_MAX);
+				}
+				config_set = 1;
+				break;
+			}
+			show_usage(argv[0]);
+			fprintf(stderr, "Missing config filename\n");
+			break;
+		case 'F':
+			set_operation_mode(&type, REQUEST, argv);
+			action = FLUSH_MASTER;
+		case 'f':
+			set_operation_mode(&type, REQUEST, argv);
+			action = FLUSH_CACHE;
+			break;
+		case 'R':
+			set_operation_mode(&type, REQUEST, argv);
+			action = RESYNC_MASTER;
+			break;
+		case 'B':
+			set_operation_mode(&type, REQUEST, argv);
+			action = SEND_BULK;
+			break;
+		case 'k':
+			set_operation_mode(&type, REQUEST, argv);
+			action = KILL;
+			break;
+		case 's':
+			set_operation_mode(&type, REQUEST, argv);
+			action = STATS;
+			break;
+		case 'S':
+			set_operation_mode(&mode, STATS_MODE, argv);
+			break;
+		case 'n':
+			set_operation_mode(&type, REQUEST, argv);
+			action = REQUEST_DUMP;
+			break;
+		case 'x':
+			if (action == DUMP_INTERNAL)
+				action = DUMP_INT_XML;
+			else if (action == DUMP_EXTERNAL)
+				action = DUMP_EXT_XML;
+			else {
+				show_usage(argv[0]);
+				fprintf(stderr, "Error: Invalid parameters\n");
+				exit(EXIT_FAILURE);
+
+			}
+			break;
+		default:
+			show_usage(argv[0]);
+			fprintf(stderr, "Unknown option: %s\n", argv[i]);
+			return 0;
+			break;
+		}
+	}
+
+	if (config_set == 0)
+		strcpy(config_file, DEFAULT_CONFIGFILE);
+
+	if ((ret = init_config(config_file)) == -1) {
+		fprintf(stderr, "can't open config file `%s'\n", config_file);
+		exit(EXIT_FAILURE);
+	}
+
+	/*
+	 * Setting up logfile
+	 */
+	STATE(log) = init_log(CONFIG(logfile));
+	if (!STATE(log)) {
+		fprintf(stdout, "can't open logfile `%s\n'", CONFIG(logfile));
+		exit(EXIT_FAILURE);
+	}
+
+	if (type == REQUEST) {
+		if (do_local_request(action, &conf.local, local_step) == -1)
+			fprintf(stderr, "can't connect: is conntrackd "
+					"running? appropiate permissions?\n");
+		exit(EXIT_SUCCESS);
+	}
+
+	/*
+	 * lock file
+	 */
+	if ((ret = open(CONFIG(lockfile), O_CREAT | O_EXCL | O_TRUNC)) == -1) {
+		fprintf(stderr, "lockfile `%s' exists, perhaps conntrackd "
+			        "already running?\n", CONFIG(lockfile));
+		exit(EXIT_FAILURE);
+	}
+	close(ret);
+
+	/* Daemonize conntrackd */
+	if (type == DAEMON) {
+		pid_t pid;
+
+		if ((pid = fork()) == -1) {
+			dlog(STATE(log), "fork() failed: "
+					 "%s", strerror(errno));
+			exit(EXIT_FAILURE);
+		} else if (pid)
+			exit(EXIT_SUCCESS);
+		
+		dlog(STATE(log), "--- starting in daemon mode ---");
+	} else
+		dlog(STATE(log), "--- starting in console mode ---");
+
+	/*
+	 * initialization process
+	 */
+
+	if (init(mode) == -1) {
+		close_log(STATE(log));
+		fprintf(stderr, "ERROR: conntrackd cannot start, please "
+				"check the logfile for more info\n");
+		unlink(CONFIG(lockfile));
+		exit(EXIT_FAILURE);
+	}
+
+	/*
+	 * run main process
+	 */
+	run();
+}
diff --git a/daemon/src/mcast.c b/daemon/src/mcast.c
new file mode 100644
index 0000000..9904544
--- /dev/null
+++ b/daemon/src/mcast.c
@@ -0,0 +1,287 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: multicast socket library
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string.h>
+#include "mcast.h"
+#include "debug.h"
+
+struct mcast_sock *mcast_server_create(struct mcast_conf *conf)
+{
+	int yes = 1;
+	union {
+		struct ip_mreq ipv4;
+		struct ipv6_mreq ipv6;
+	} mreq;
+	struct mcast_sock *m;
+
+	m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock));
+	if (!m)
+		return NULL;
+	memset(m, 0, sizeof(struct mcast_sock));
+
+	switch(conf->ipproto) {
+	case AF_INET:
+		mreq.ipv4.imr_multiaddr.s_addr = conf->in.inet_addr.s_addr;
+		mreq.ipv4.imr_interface.s_addr =conf->ifa.interface_addr.s_addr;
+
+	        m->addr.ipv4.sin_family = AF_INET;
+	        m->addr.ipv4.sin_port = htons(conf->port);
+	        m->addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
+		break;
+
+	case AF_INET6:
+		memcpy(&mreq.ipv6.ipv6mr_multiaddr, &conf->in.inet_addr6,
+		       sizeof(u_int32_t) * 4);
+		memcpy(&mreq.ipv6.ipv6mr_interface, &conf->ifa.interface_addr6,
+		       sizeof(u_int32_t) * 4);
+
+		m->addr.ipv6.sin6_family = AF_INET6;
+		m->addr.ipv6.sin6_port = htons(conf->port);
+		m->addr.ipv6.sin6_addr = in6addr_any;
+		break;
+	}
+
+	if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) {
+		debug("mcast_sock_server_create:socket");
+		free(m);
+		return NULL;
+	}
+
+	if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, 
+				sizeof(int)) == -1) {
+		debug("mcast_sock_server_create:setsockopt1");
+		close(m->fd);
+		free(m);
+		return NULL;
+	}
+
+	if (bind(m->fd, (struct sockaddr *) &m->addr, 
+			 sizeof(struct sockaddr)) == -1) {
+		debug("mcast_sock_server_create:bind");
+		close(m->fd);
+		free(m);
+		return NULL;
+	}
+
+
+	switch(conf->ipproto) {
+	case AF_INET:
+		if (setsockopt(m->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+			       &mreq.ipv4, sizeof(mreq.ipv4)) < 0) {
+			debug("mcast_sock_server_create:setsockopt2");
+			close(m->fd);
+			free(m);
+			return NULL;
+		}
+		break;
+	case AF_INET6:
+		if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+			       &mreq.ipv6, sizeof(mreq.ipv6)) < 0) {
+			debug("mcast_sock_server_create:setsockopt2");
+			close(m->fd);
+			free(m);
+			return NULL;
+		}
+		break;
+	}
+
+	return m;
+}
+
+void mcast_server_destroy(struct mcast_sock *m)
+{
+	close(m->fd);
+	free(m);
+}
+
+static int 
+__mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf)
+{
+	int no = 0;
+
+	m->addr.ipv4.sin_family = AF_INET;
+	m->addr.ipv4.sin_port = htons(conf->port);
+	m->addr.ipv4.sin_addr = conf->in.inet_addr;
+
+	if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &no,
+		       sizeof(int)) < 0) {
+		debug("mcast_sock_client_create:setsockopt2");
+		close(m->fd);
+		return -1;
+	}
+
+	if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_IF,
+		       &conf->ifa.interface_addr,
+		       sizeof(struct in_addr)) == -1) {
+		debug("mcast_sock_client_create:setsockopt3");
+		close(m->fd);
+		free(m);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int 
+__mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf)
+{
+	int no = 0;
+
+	m->addr.ipv6.sin6_family = AF_INET6;
+	m->addr.ipv6.sin6_port = htons(conf->port);
+	memcpy(&m->addr.ipv6.sin6_addr,
+	       &conf->in.inet_addr6,
+	       sizeof(struct in6_addr));
+
+	if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &no,
+		       sizeof(int)) < 0) {
+		debug("mcast_sock_client_create:setsockopt2");
+		close(m->fd);
+		return -1;
+	}
+
+	if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+		       &conf->ifa.interface_addr,
+		       sizeof(struct in_addr)) == -1) {
+		debug("mcast_sock_client_create:setsockopt3");
+		close(m->fd);
+		free(m);
+		return -1;
+	}
+
+	return 0;
+}
+
+struct mcast_sock *mcast_client_create(struct mcast_conf *conf)
+{
+	int ret = 0;
+	struct sockaddr_in addr;
+	struct mcast_sock *m;
+
+	m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock));
+	if (!m)
+		return NULL;
+	memset(m, 0, sizeof(struct mcast_sock));
+
+	if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) {
+		debug("mcast_sock_client_create:socket");
+		return NULL;
+	}
+
+	switch(conf->ipproto) {
+		case AF_INET:
+			ret = __mcast_client_create_ipv4(m, conf);
+			break;
+		case AF_INET6:
+			ret = __mcast_client_create_ipv6(m, conf);
+			break;
+		default:
+			break;
+	}
+
+	if (ret == -1) {
+		free(m);
+		m = NULL;
+	}
+
+	return m;
+}
+
+void mcast_client_destroy(struct mcast_sock *m)
+{
+	close(m->fd);
+	free(m);
+}
+
+int mcast_send(struct mcast_sock *m, void *data, int size)
+{
+	int ret;
+	
+	ret = sendto(m->fd, 
+		     data,
+		     size,
+		     0,
+		     (struct sockaddr *) &m->addr,
+		     sizeof(struct sockaddr));
+	if (ret == -1) {
+		debug("mcast_sock_send");
+		m->stats.error++;
+		return ret;
+	}
+
+	m->stats.bytes += ret;
+	m->stats.messages++;  
+
+	return ret;
+}
+
+int mcast_recv(struct mcast_sock *m, void *data, int size)
+{
+	int ret;
+	socklen_t sin_size = sizeof(struct sockaddr_in);
+
+        ret = recvfrom(m->fd,
+		       data, 
+		       size,
+		       0,
+		       (struct sockaddr *)&m->addr,
+		       &sin_size);
+	if (ret == -1) {
+		debug("mcast_sock_recv");
+		m->stats.error++;
+		return ret;
+	}
+
+	m->stats.bytes += ret;
+	m->stats.messages++;
+
+	return ret;
+}
+
+struct mcast_stats *mcast_get_stats(struct mcast_sock *m)
+{
+	return &m->stats;
+}
+
+void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r)
+{
+	char buf[512];
+	int size;
+
+	size = sprintf(buf, "multicast traffic:\n"
+			    "%20llu Bytes sent "
+			    "%20llu Bytes recv\n"
+			    "%20llu Pckts sent "
+			    "%20llu Pckts recv\n"
+			    "%20llu Error send "
+			    "%20llu Error recv\n\n",
+			    s->stats.bytes, r->stats.bytes,
+			    s->stats.messages, r->stats.messages,
+			    s->stats.error, r->stats.error);
+
+	send(fd, buf, size, 0);
+}
diff --git a/daemon/src/netlink.c b/daemon/src/netlink.c
new file mode 100644
index 0000000..0bde632
--- /dev/null
+++ b/daemon/src/netlink.c
@@ -0,0 +1,326 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "conntrackd.h"
+#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include <signal.h>
+#include <stdlib.h>
+#include "network.h"
+
+static int ignore_conntrack(struct nf_conntrack *ct)
+{
+	/* ignore a certain protocol */
+	if (CONFIG(ignore_protocol)[nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)])
+		return 1;
+
+	/* Accept DNAT'ed traffic: not really coming to the local machine */
+	if ((CONFIG(flags) & STRIP_NAT) && 
+	    nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) {
+		debug_ct(ct, "DNAT");
+		return 0;
+	}
+
+        /* Accept SNAT'ed traffic: not really coming to the local machine */
+	if ((CONFIG(flags) & STRIP_NAT) && 
+	    nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) {
+		debug_ct(ct, "SNAT");
+		return 0;
+	}
+
+	/* Ignore traffic */
+	if (ignore_pool_test(STATE(ignore_pool), ct)) {
+		debug_ct(ct, "ignore traffic");
+		return 1;
+	}
+
+	return 0;
+}
+
+static int nl_event_handler(struct nlmsghdr *nlh,
+			    struct nfattr *nfa[],
+			    void *data)
+{
+	char tmp[1024];
+	struct nf_conntrack *ct = (struct nf_conntrack *) tmp;
+	int type;
+
+	memset(tmp, 0, sizeof(tmp));
+
+	if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR)
+		return NFCT_CB_STOP;
+
+	/* 
+	 * Ignore this conntrack: it talks about a
+	 * connection that is not interesting for us.
+	 */
+	if (ignore_conntrack(ct))
+		return NFCT_CB_STOP;
+
+	switch(type) {
+	case NFCT_T_NEW:
+		STATE(mode)->event_new(ct, nlh);
+		break;
+	case NFCT_T_UPDATE:
+		STATE(mode)->event_upd(ct, nlh);
+		break;
+	case NFCT_T_DESTROY:
+		if (STATE(mode)->event_dst(ct, nlh))
+			update_traffic_stats(ct);
+		break;
+	default:
+		dlog(STATE(log), "received unknown msg from ctnetlink\n");
+		break;
+	}
+
+	return NFCT_CB_STOP;
+}
+
+int nl_init_event_handler(void)
+{
+	struct nfnl_callback cb_events = {
+		.call		= nl_event_handler,
+		.attr_count	= CTA_MAX
+	};
+
+	/* open event netlink socket */
+	STATE(event) = nfnl_open();
+	if (!STATE(event))
+		return -1;
+
+	/* set up socket buffer size */
+	if (CONFIG(netlink_buffer_size))
+		nfnl_rcvbufsiz(STATE(event), CONFIG(netlink_buffer_size));
+	else {
+		socklen_t socklen = sizeof(unsigned int);
+		unsigned int read_size;
+
+		/* get current buffer size */
+		getsockopt(nfnl_fd(STATE(event)), SOL_SOCKET,
+			   SO_RCVBUF, &read_size, &socklen);
+
+		CONFIG(netlink_buffer_size) = read_size;
+	}
+
+	/* ensure that maximum grown size is >= than maximum size */
+	if (CONFIG(netlink_buffer_size_max_grown) < CONFIG(netlink_buffer_size))
+		CONFIG(netlink_buffer_size_max_grown) = 
+					CONFIG(netlink_buffer_size);
+
+	/* open event subsystem */
+	STATE(subsys_event) = nfnl_subsys_open(STATE(event),
+					       NFNL_SUBSYS_CTNETLINK,
+					       IPCTNL_MSG_MAX,
+					       NFCT_ALL_CT_GROUPS);
+	if (STATE(subsys_event) == NULL)
+		return -1;
+
+	/* register callback for new and update events */
+	nfnl_callback_register(STATE(subsys_event),
+			       IPCTNL_MSG_CT_NEW,
+			       &cb_events);
+
+	/* register callback for delete events */
+	nfnl_callback_register(STATE(subsys_event),
+			       IPCTNL_MSG_CT_DELETE,
+			       &cb_events);
+
+	return 0;
+}
+
+static int nl_dump_handler(struct nlmsghdr *nlh,
+			   struct nfattr *nfa[],
+			   void *data)
+{
+	char buf[1024];
+	struct nf_conntrack *ct = (struct nf_conntrack *) buf;
+	int type;
+
+	memset(buf, 0, sizeof(buf));
+
+	if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR)
+		return NFCT_CB_CONTINUE;
+
+	/* 
+	 * Ignore this conntrack: it talks about a
+	 * connection that is not interesting for us.
+	 */
+	if (ignore_conntrack(ct))
+		return NFCT_CB_CONTINUE;
+
+	switch(type) {
+	case NFCT_T_UPDATE:
+		STATE(mode)->dump(ct, nlh);
+		break;
+	default:
+		dlog(STATE(log), "received unknown msg from ctnetlink");
+		break;
+	}
+	return NFCT_CB_CONTINUE;
+}
+
+int nl_init_dump_handler(void)
+{
+	struct nfnl_callback cb_dump = {
+		.call		= nl_dump_handler,
+		.attr_count	= CTA_MAX
+	};
+
+	/* open dump netlink socket */
+	STATE(dump) = nfnl_open();
+	if (!STATE(dump))
+		return -1;
+
+	/* open dump subsystem */
+	STATE(subsys_dump) = nfnl_subsys_open(STATE(dump),
+					      NFNL_SUBSYS_CTNETLINK,
+					      IPCTNL_MSG_MAX,
+					      0);
+	if (STATE(subsys_dump) == NULL)
+		return -1;
+
+	/* register callback for dumped entries */
+	nfnl_callback_register(STATE(subsys_dump),
+			       IPCTNL_MSG_CT_NEW,
+			       &cb_dump);
+
+	if (nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)) == -1)
+		return -1;
+
+	return 0;
+}
+
+static int nl_overrun_handler(struct nlmsghdr *nlh,
+			      struct nfattr *nfa[],
+			      void *data)
+{
+	char buf[1024];
+	struct nf_conntrack *ct = (struct nf_conntrack *) buf;
+	int type;
+
+	memset(buf, 0, sizeof(buf));
+
+	if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR)
+		return NFCT_CB_CONTINUE;
+
+	/* 
+	 * Ignore this conntrack: it talks about a
+	 * connection that is not interesting for us.
+	 */
+	if (ignore_conntrack(ct))
+		return NFCT_CB_CONTINUE;
+
+	switch(type) {
+	case NFCT_T_UPDATE:
+		if (STATE(mode)->overrun)
+			STATE(mode)->overrun(ct, nlh);
+		break;
+	default:
+		dlog(STATE(log), "received unknown msg from ctnetlink");
+		break;
+	}
+	return NFCT_CB_CONTINUE;
+}
+
+int nl_init_overrun_handler(void)
+{
+	struct nfnl_callback cb_sync = {
+		.call		= nl_overrun_handler,
+		.attr_count	= CTA_MAX
+	};
+
+	/* open sync netlink socket */
+	STATE(sync) = nfnl_open();
+	if (!STATE(sync))
+		return -1;
+
+	/* open synchronizer subsystem */
+	STATE(subsys_sync) = nfnl_subsys_open(STATE(sync),
+					      NFNL_SUBSYS_CTNETLINK,
+					      IPCTNL_MSG_MAX,
+					      0);
+	if (STATE(subsys_sync) == NULL)
+		return -1;
+
+	/* register callback for dumped entries */
+	nfnl_callback_register(STATE(subsys_sync),
+			       IPCTNL_MSG_CT_NEW,
+			       &cb_sync);
+
+	return 0;
+}
+
+static int warned = 0;
+
+void nl_resize_socket_buffer(struct nfnl_handle *h)
+{
+	unsigned int s = CONFIG(netlink_buffer_size) * 2;
+
+	/* already warned that we have reached the maximum buffer size */
+	if (warned)
+		return;
+
+	if (s > CONFIG(netlink_buffer_size_max_grown)) {
+		dlog(STATE(log), "maximum netlink socket buffer size reached");
+		s = CONFIG(netlink_buffer_size_max_grown);
+		warned = 1;
+	}
+
+	CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(h, s);
+
+	/* notify the sysadmin */
+	dlog(STATE(log), "netlink socket buffer size has been set to %u bytes", 
+			  CONFIG(netlink_buffer_size));
+}
+
+int nl_dump_conntrack_table(struct nfnl_handle *h, 
+			    struct nfnl_subsys_handle *subsys)
+{
+	struct nfnlhdr req;
+
+	memset(&req, 0, sizeof(req));
+	nfct_build_query(subsys, 
+			 NFCT_Q_DUMP, 
+			 &CONFIG(family), 
+			 &req, 
+			 sizeof(req));
+
+	if (nfnl_query(h, &req.nlh) == -1)
+		return -1;
+
+	return 0;
+}
+
+int nl_flush_master_conntrack_table(void)
+{
+	struct nfnlhdr req;
+
+	memset(&req, 0, sizeof(req));
+	nfct_build_query(STATE(subsys_sync), 
+			 NFCT_Q_FLUSH, 
+			 &CONFIG(family), 
+			 &req, 
+			 sizeof(req));
+
+	if (nfnl_query(STATE(sync), &req.nlh) == -1)
+		return -1;
+
+	return 0;
+}
diff --git a/daemon/src/network.c b/daemon/src/network.c
new file mode 100644
index 0000000..b9be318
--- /dev/null
+++ b/daemon/src/network.c
@@ -0,0 +1,282 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "conntrackd.h"
+#include "network.h"
+
+#if 0 
+#define _TEST_DROP
+#else
+#undef _TEST_DROP
+#endif
+
+static int drop = 0; /* debugging purposes */
+static unsigned int seq_set, cur_seq;
+
+static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len)
+{
+	struct nlnetwork *net = data;
+
+#ifdef _TEST_DROP
+        if (++drop > 10) {
+		drop = 0;
+		printf("dropping resend (seq=%u)\n", ntohl(net->seq));
+		return 0;
+	}
+#endif
+	return mcast_send(m, net, len);
+}
+
+int mcast_send_netmsg(struct mcast_sock *m, void *data)
+{
+	struct nlmsghdr *nlh = data + sizeof(struct nlnetwork);
+	unsigned int len = nlh->nlmsg_len + sizeof(struct nlnetwork);
+	struct nlnetwork *net = data;
+
+	if (!seq_set) {
+		seq_set = 1;
+		cur_seq = time(NULL);
+		net->flags |= NET_HELLO;
+	}
+
+	net->flags = htons(net->flags);
+	net->seq = htonl(cur_seq++);
+
+	if (nlh_host2network(nlh) == -1)
+		return -1;
+
+	net->checksum = 0;
+	net->checksum = ntohs(do_csum(data, len));
+
+	return send_netmsg(m, data, len);
+}
+
+int mcast_resend_netmsg(struct mcast_sock *m, void *data)
+{
+	struct nlnetwork *net = data;
+	struct nlmsghdr *nlh = data + sizeof(struct nlnetwork);
+	unsigned int len = htonl(nlh->nlmsg_len) + sizeof(struct nlnetwork);
+
+	net->flags = ntohs(net->flags);
+
+	if (!seq_set) {
+		seq_set = 1;
+		cur_seq = time(NULL);
+		net->flags |= NET_HELLO;
+	}
+
+	if (net->flags & NET_NACK || net->flags & NET_ACK) {
+		struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net;
+		len = sizeof(struct nlnetwork_ack);
+	}
+
+	net->flags = htons(net->flags);
+	net->seq = htonl(cur_seq++);
+	net->checksum = 0;
+	net->checksum = ntohs(do_csum(data, len));
+
+	return send_netmsg(m, data, len);
+}
+
+int mcast_send_error(struct mcast_sock *m, void *data)
+{
+	struct nlnetwork *net = data;
+	unsigned int len = sizeof(struct nlnetwork);
+
+	if (!seq_set) {
+		seq_set = 1;
+		cur_seq = time(NULL);
+		net->flags |= NET_HELLO;
+	}
+
+	if (net->flags & NET_NACK || net->flags & NET_ACK) {
+		struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net;
+		nack->from = htonl(nack->from);
+		nack->to = htonl(nack->to);
+		len = sizeof(struct nlnetwork_ack);
+	}
+
+	net->flags = htons(net->flags);
+	net->seq = htonl(cur_seq++);
+	net->checksum = 0;
+	net->checksum = ntohs(do_csum(data, len));
+
+	return send_netmsg(m, data, len);
+}
+
+static int valid_checksum(void *data, unsigned int len)
+{
+	struct nlnetwork *net = data;
+	unsigned short checksum, tmp;
+
+	checksum = ntohs(net->checksum);
+
+	/* no checksum, skip */
+	if (!checksum)
+		return 1;
+
+	net->checksum = 0;
+	tmp = do_csum(data, len);
+
+	return tmp == checksum;
+}
+
+int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len)
+{
+	int ret;
+	struct nlnetwork *net = data;
+	struct nlmsghdr *nlh = data + sizeof(struct nlnetwork);
+	struct nfgenmsg *nfhdr;
+
+	ret = mcast_recv(m, net, len);
+	if (ret <= 0)
+		return ret;
+
+	if (ret < sizeof(struct nlnetwork))
+		return -1;
+
+	if (!valid_checksum(data, ret))
+		return -1;
+
+	net->flags = ntohs(net->flags);
+	net->seq = ntohl(net->seq);
+
+	if (net->flags & NET_HELLO)
+		STATE_SYNC(last_seq_recv) = net->seq-1;
+
+	if (net->flags & NET_NACK || net->flags & NET_ACK) {
+		struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net;
+
+		if (ret < sizeof(struct nlnetwork_ack))
+			return -1;
+
+		nack->from = ntohl(nack->from);
+		nack->to = ntohl(nack->to);
+
+		return ret;
+	}
+
+	if (net->flags & NET_RESYNC)
+		return ret;
+
+	/* information received is too small */
+	if (ret < NLMSG_SPACE(sizeof(struct nfgenmsg)))
+		return -1;
+
+	/* information received and message length does not match */
+	if (ret != ntohl(nlh->nlmsg_len) + sizeof(struct nlnetwork))
+		return -1;
+
+	/* this message does not come from ctnetlink */
+	if (NFNL_SUBSYS_ID(ntohs(nlh->nlmsg_type)) != NFNL_SUBSYS_CTNETLINK)
+		return -1;
+
+	nfhdr = NLMSG_DATA(nlh);
+
+	/* only AF_INET and AF_INET6 are supported */
+	if (nfhdr->nfgen_family != AF_INET &&
+	    nfhdr->nfgen_family != AF_INET6)
+		return -1;
+
+	/* only process message coming from nfnetlink v0 */
+	if (nfhdr->version != NFNETLINK_V0)
+		return -1;
+
+	if (nlh_network2host(nlh) == -1)
+		return -1;
+
+	return ret;
+}
+
+int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq)
+{
+	static int seq_set = 0;
+	int ret = 1;
+
+	/* netlink sequence tracking initialization */
+	if (!seq_set) {
+		seq_set = 1;
+		goto out;
+	}
+
+	/* fast path: we received the correct sequence */
+	if (seq == STATE_SYNC(last_seq_recv)+1)
+		goto out;
+
+	/* out of sequence: some messages got lost */
+	if (seq > STATE_SYNC(last_seq_recv)+1) {
+		STATE_SYNC(packets_lost) += seq-STATE_SYNC(last_seq_recv)+1;
+		ret = 0;
+		goto out;
+	}
+
+	/* out of sequence: replayed or sequence wrapped around issues */
+	if (seq < STATE_SYNC(last_seq_recv)+1) {
+		/* 
+		 * Check if the sequence has wrapped around.
+		 * Perhaps it can be a replayed packet.
+		 */
+		if (STATE_SYNC(last_seq_recv)+1-seq > ~0U/2) {
+			/* 
+			 * Indeed, it is a wrapped around
+			 */
+			STATE_SYNC(packets_lost) += 
+				~0U-STATE_SYNC(last_seq_recv)+1+seq;
+		} else {
+			/*
+			 * It is a delayed packet
+			 */
+			dlog(STATE(log), "delayed packet? exp=%u rcv=%u",
+					 STATE_SYNC(last_seq_recv)+1, seq);
+		}
+		ret = 0;
+	}
+
+out:
+	*exp_seq = STATE_SYNC(last_seq_recv)+1;
+	/* update expected sequence */
+	STATE_SYNC(last_seq_recv) = seq;
+
+	return ret;
+}
+
+int build_network_msg(const int msg_type,
+		      struct nfnl_subsys_handle *ssh, 
+		      struct nf_conntrack *ct,
+		      void *buffer,
+		      unsigned int size)
+{
+	memset(buffer, 0, size);
+	buffer += sizeof(struct nlnetwork);
+	return nfct_build_query(ssh, msg_type, ct, buffer, size);
+}
+
+unsigned int parse_network_msg(struct nf_conntrack *ct, 
+			       const struct nlmsghdr *nlh)
+{
+	/* 
+	 * The parsing of netlink messages going through network is 
+	 * similar to the one that is done for messages coming from
+	 * kernel, therefore do not replicate more code and use the
+	 * function provided in the libraries.
+	 *
+	 * Yup, this is a hack 8)
+	 */
+	return nfct_parse_conntrack(NFCT_T_ALL, nlh, ct);
+}
+
diff --git a/daemon/src/proxy.c b/daemon/src/proxy.c
new file mode 100644
index 0000000..b9bb04e
--- /dev/null
+++ b/daemon/src/proxy.c
@@ -0,0 +1,124 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+#if 0
+#define dprintf printf
+#else
+#define dprintf
+#endif
+
+int nlh_payload_host2network(struct nfattr *nfa, int len)
+{
+	struct nfattr *__nfa;
+
+	while (NFA_OK(nfa, len)) {
+
+		dprintf("type=%d nfalen=%d len=%d [%s]\n", 
+			nfa->nfa_type & 0x7fff,
+			nfa->nfa_len, len,
+			nfa->nfa_type & NFNL_NFA_NEST ? "NEST":"");
+
+		if (nfa->nfa_type & NFNL_NFA_NEST) {
+			if (NFA_PAYLOAD(nfa) > len)
+				return -1;
+
+			if (nlh_payload_host2network(NFA_DATA(nfa), 
+						     NFA_PAYLOAD(nfa)) == -1)
+				return -1;
+		}
+
+		__nfa = NFA_NEXT(nfa, len);
+
+		nfa->nfa_type = htons(nfa->nfa_type);
+		nfa->nfa_len  = htons(nfa->nfa_len);
+
+		nfa = __nfa; 
+	}
+	return 0;
+}
+
+int nlh_host2network(struct nlmsghdr *nlh)
+{
+	struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
+	struct nfattr *cda[CTA_MAX];
+	unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
+	unsigned int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
+
+	nlh->nlmsg_len   = htonl(nlh->nlmsg_len);
+	nlh->nlmsg_type  = htons(nlh->nlmsg_type);
+	nlh->nlmsg_flags = htons(nlh->nlmsg_flags);
+	nlh->nlmsg_seq   = htonl(nlh->nlmsg_seq);
+	nlh->nlmsg_pid   = htonl(nlh->nlmsg_pid);
+
+	nfhdr->res_id    = htons(nfhdr->res_id);
+
+	return nlh_payload_host2network(NFM_NFA(NLMSG_DATA(nlh)), len);
+}
+
+int nlh_payload_network2host(struct nfattr *nfa, int len)
+{
+	nfa->nfa_type = ntohs(nfa->nfa_type);
+	nfa->nfa_len  = ntohs(nfa->nfa_len);
+
+	while(NFA_OK(nfa, len)) {
+
+                dprintf("type=%d nfalen=%d len=%d [%s]\n", 
+		        nfa->nfa_type & 0x7fff, 
+		        nfa->nfa_len, len, 
+		        nfa->nfa_type & NFNL_NFA_NEST ? "NEST":"");
+
+		if (nfa->nfa_type & NFNL_NFA_NEST) {
+			if (NFA_PAYLOAD(nfa) > len)
+				return -1;
+
+			if (nlh_payload_network2host(NFA_DATA(nfa),
+						     NFA_PAYLOAD(nfa)) == -1)
+				return -1;
+		}
+
+		nfa = NFA_NEXT(nfa,len);
+
+		if (len < NFA_LENGTH(0))
+			break;
+
+		nfa->nfa_type = ntohs(nfa->nfa_type);
+		nfa->nfa_len  = ntohs(nfa->nfa_len);
+	}
+	return 0;
+}
+
+int nlh_network2host(struct nlmsghdr *nlh)
+{
+	struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
+	struct nfattr *cda[CTA_MAX];
+	unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
+	unsigned int len = ntohl(nlh->nlmsg_len) - NLMSG_ALIGN(min_len);
+
+	nlh->nlmsg_len   = ntohl(nlh->nlmsg_len);
+	nlh->nlmsg_type  = ntohs(nlh->nlmsg_type);
+	nlh->nlmsg_flags = ntohs(nlh->nlmsg_flags);
+	nlh->nlmsg_seq   = ntohl(nlh->nlmsg_seq);
+	nlh->nlmsg_pid   = ntohl(nlh->nlmsg_pid);
+
+	nfhdr->res_id    = ntohs(nfhdr->res_id);
+
+	return nlh_payload_network2host(NFM_NFA(NLMSG_DATA(nlh)), len);
+}
diff --git a/daemon/src/read_config_lex.l b/daemon/src/read_config_lex.l
new file mode 100644
index 0000000..dee90c9
--- /dev/null
+++ b/daemon/src/read_config_lex.l
@@ -0,0 +1,125 @@
+%{
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: configuration file syntax
+ */
+
+#include "read_config_yy.h"
+#include "conntrackd.h"
+%}
+
+%option yylineno
+%option nounput
+
+ws		[ \t]+
+comment         #.*$
+nl		[\n\r]
+
+is_on		[o|O][n|N]
+is_off		[o|O][f|F][f|F]
+integer		[0-9]+
+path		\/[^\"\n ]*
+ip4_end		[0-9]*[0-9]+
+ip4_part	[0-2]*{ip4_end}
+ip4		{ip4_part}\.{ip4_part}\.{ip4_part}\.{ip4_part}
+hex_255		[0-9a-fA-F]{1,4}
+ip6_part	{hex_255}":"?
+ip6_form1	{ip6_part}{0,16}"::"{ip6_part}{0,16}
+ip6_form2	({hex_255}":"){16}{hex_255}
+ip6		{ip6_form1}|{ip6_form2}
+string		[a-zA-Z]*
+persistent	[P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T]
+nack		[N|n][A|a][C|c][K|k]
+
+%%
+"UNIX"				{ return T_UNIX; }
+"IPv4_address"			{ return T_IPV4_ADDR; }
+"IPv6_address"			{ return T_IPV6_ADDR; }
+"IPv4_interface"		{ return T_IPV4_IFACE; }
+"IPv6_interface"		{ return T_IPV6_IFACE; }
+"Port"				{ return T_PORT; }
+"Multicast"			{ return T_MULTICAST; }
+"HashSize"			{ return T_HASHSIZE; }
+"RefreshTime"			{ return T_REFRESH; }
+"CacheTimeout"			{ return T_EXPIRE; }
+"CommitTimeout"			{ return T_TIMEOUT; }
+"DelayDestroyMessages"		{ return T_DELAY; }
+"HashLimit"			{ return T_HASHLIMIT; }
+"Path"				{ return T_PATH; }
+"IgnoreProtocol"		{ return T_IGNORE_PROTOCOL; }
+"UDP"				{ return T_UDP; }
+"ICMP"				{ return T_ICMP; }
+"VRRP"				{ return T_VRRP; }
+"IGMP"				{ return T_IGMP; }
+"TCP"				{ return T_TCP; }
+"IgnoreTrafficFor"		{ return T_IGNORE_TRAFFIC; }
+"StripNAT"			{ return T_STRIP_NAT; }
+"Backlog"			{ return T_BACKLOG; }
+"Group"				{ return T_GROUP; }
+"LogFile"			{ return T_LOG; }
+"LockFile"			{ return T_LOCK; }
+"General"			{ return T_GENERAL; }
+"Sync"				{ return T_SYNC; }
+"Stats"				{ return T_STATS; }
+"RelaxTransitions"		{ return T_RELAX_TRANSITIONS; }
+"SocketBufferSize"		{ return T_BUFFER_SIZE; }
+"SocketBufferSizeMaxGrown"	{ return T_BUFFER_SIZE_MAX_GROWN; }
+"SocketBufferSizeMaxGrowth"	{ return T_BUFFER_SIZE_MAX_GROWN; }
+"Mode"				{ return T_SYNC_MODE; }
+"ListenTo"			{ return T_LISTEN_TO; }
+"Family"			{ return T_FAMILY; }
+"ResendBufferSize"		{ return T_RESEND_BUFFER_SIZE; }
+"Checksum"			{ return T_CHECKSUM; }
+"ACKWindowSize"			{ return T_WINDOWSIZE; }
+"Replicate"			{ return T_REPLICATE; }
+"for"				{ return T_FOR; }
+"SYN_SENT"			{ return T_SYN_SENT; }
+"SYN_RECV"			{ return T_SYN_RECV; }
+"ESTABLISHED"			{ return T_ESTABLISHED; }
+"FIN_WAIT"			{ return T_FIN_WAIT; }
+"CLOSE_WAIT"			{ return T_CLOSE_WAIT; }
+"LAST_ACK"			{ return T_LAST_ACK; }
+"TIME_WAIT"			{ return T_TIME_WAIT; }
+"CLOSE"				{ return T_CLOSE; }
+"LISTEN"			{ return T_LISTEN; }
+
+{is_on}			{ return T_ON; }
+{is_off}		{ return T_OFF; }
+{integer}		{ yylval.val = atoi(yytext); return T_NUMBER; }
+{ip4}			{ yylval.string = strdup(yytext); return T_IP; }
+{ip6}			{ yylval.string = strdup(yytext); return T_IP; }
+{path}			{ yylval.string = strdup(yytext); return T_PATH_VAL; }
+{persistent}		{ return T_PERSISTENT; }
+{nack}			{ return T_NACK; }
+{string}		{ yylval.string = strdup(yytext); return T_STRING; }
+
+{comment}	;
+{ws}		;
+{nl}		;
+
+<<EOF>>		{ yyterminate(); }
+
+.		{ return yytext[0]; }
+
+%%
+
+int
+yywrap()
+{
+	return 1;
+}
diff --git a/daemon/src/read_config_yy.y b/daemon/src/read_config_yy.y
new file mode 100644
index 0000000..1668919
--- /dev/null
+++ b/daemon/src/read_config_yy.y
@@ -0,0 +1,550 @@
+%{
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: configuration file abstract grammar
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "conntrackd.h"
+#include "ignore.h"
+
+extern char *yytext;
+extern int   yylineno;
+
+struct ct_conf conf;
+%}
+
+%union {
+	int		val;
+	char		*string;
+}
+
+%token T_IPV4_ADDR T_IPV4_IFACE T_PORT T_HASHSIZE T_HASHLIMIT T_MULTICAST
+%token T_PATH T_UNIX T_REFRESH T_IPV6_ADDR T_IPV6_IFACE
+%token T_IGNORE_UDP T_IGNORE_ICMP T_IGNORE_TRAFFIC T_BACKLOG T_GROUP
+%token T_LOG T_UDP T_ICMP T_IGMP T_VRRP T_TCP T_IGNORE_PROTOCOL
+%token T_LOCK T_STRIP_NAT T_BUFFER_SIZE_MAX_GROWN T_EXPIRE T_TIMEOUT
+%token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY
+%token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE
+%token T_PERSISTENT T_NACK T_CHECKSUM T_WINDOWSIZE T_ON T_OFF
+%token T_REPLICATE T_FOR 
+%token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT 
+%token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN
+
+
+%token <string> T_IP T_PATH_VAL
+%token <val> T_NUMBER
+%token <string> T_STRING
+
+%%
+
+configfile :
+	   | lines
+	   ;
+
+lines : line
+      | lines line
+      ;
+
+line : ignore_protocol
+     | ignore_traffic
+     | strip_nat
+     | general
+     | sync
+     | stats
+     ;
+
+log : T_LOG T_PATH_VAL
+{
+	strncpy(conf.logfile, $2, FILENAME_MAXLEN);
+};
+
+lock : T_LOCK T_PATH_VAL
+{
+	strncpy(conf.lockfile, $2, FILENAME_MAXLEN);
+};
+
+strip_nat: T_STRIP_NAT
+{
+	conf.flags |= STRIP_NAT;
+};
+
+refreshtime : T_REFRESH T_NUMBER
+{
+	conf.refresh = $2;
+};
+
+expiretime: T_EXPIRE T_NUMBER
+{
+	conf.cache_timeout = $2;
+};
+
+timeout: T_TIMEOUT T_NUMBER
+{
+	conf.commit_timeout = $2;
+};
+
+checksum: T_CHECKSUM T_ON 
+{
+};
+
+checksum: T_CHECKSUM T_OFF
+{
+	conf.flags |= DONT_CHECKSUM;
+};
+
+ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}';
+
+ignore_traffic_options :
+		       | ignore_traffic_options ignore_traffic_option;
+
+ignore_traffic_option : T_IPV4_ADDR T_IP
+{
+	union inet_address ip;
+	int family = 0;
+
+	memset(&ip, 0, sizeof(union inet_address));
+
+	if (inet_aton($2, &ip.ipv4))
+		family = AF_INET;
+#ifdef HAVE_INET_PTON_IPV6
+	else if (inet_pton(AF_INET6, $2, &ip.ipv6) > 0)
+		family = AF_INET6;
+#endif
+
+	if (!family) {
+		fprintf(stdout, "%s is not a valid IP, ignoring", $2);
+		return;
+	}
+
+	if (!STATE(ignore_pool)) {
+		STATE(ignore_pool) = ignore_pool_create(family);
+		if (!STATE(ignore_pool)) {
+			fprintf(stdout, "Can't create ignore pool!\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (!ignore_pool_add(STATE(ignore_pool), &ip)) {
+		if (errno == EEXIST)
+			fprintf(stdout, "IP %s is repeated "
+					"in the ignore pool\n", $2);
+		if (errno == ENOSPC)
+			fprintf(stdout, "Too many IP in the ignore pool!\n");
+	}
+};
+
+multicast_line : T_MULTICAST '{' multicast_options '}';
+
+multicast_options :
+		  | multicast_options multicast_option;
+
+multicast_option : T_IPV4_ADDR T_IP
+{
+	if (!inet_aton($2, &conf.mcast.in)) {
+		fprintf(stderr, "%s is not a valid IPv4 address\n");
+		return;
+	}
+
+        if (conf.mcast.ipproto == AF_INET6) {
+		fprintf(stderr, "Your multicast address is IPv4 but "
+		                "is binded to an IPv6 interface? Surely "
+				"this is not what you want\n");
+		return;
+	}
+
+	conf.mcast.ipproto = AF_INET;
+};
+
+multicast_option : T_IPV6_ADDR T_IP
+{
+#ifdef HAVE_INET_PTON_IPV6
+	if (inet_pton(AF_INET6, $2, &conf.mcast.in) <= 0)
+		fprintf(stderr, "%s is not a valid IPv6 address\n", $2);
+#endif
+
+	if (conf.mcast.ipproto == AF_INET) {
+		fprintf(stderr, "Your multicast address is IPv6 but "
+				"is binded to an IPv4 interface? Surely "
+				"this is not what you want\n");
+		return;
+	}
+
+	conf.mcast.ipproto = AF_INET6;
+};
+
+multicast_option : T_IPV4_IFACE T_IP
+{
+	if (!inet_aton($2, &conf.mcast.ifa)) {
+		fprintf(stderr, "%s is not a valid IPv4 address\n");
+		return;
+	}
+
+        if (conf.mcast.ipproto == AF_INET6) {
+		fprintf(stderr, "Your multicast interface is IPv4 but "
+		                "is binded to an IPv6 interface? Surely "
+				"this is not what you want\n");
+		return;
+	}
+
+	conf.mcast.ipproto = AF_INET;
+};
+
+multicast_option : T_IPV6_IFACE T_IP
+{
+#ifdef HAVE_INET_PTON_IPV6
+	if (inet_pton(AF_INET6, $2, &conf.mcast.ifa) <= 0)
+		fprintf(stderr, "%s is not a valid IPv6 address\n", $2);
+#endif
+
+	if (conf.mcast.ipproto == AF_INET) {
+		fprintf(stderr, "Your multicast interface is IPv6 but "
+				"is binded to an IPv4 interface? Surely "
+				"this is not what you want\n");
+		return;
+	}
+
+	conf.mcast.ipproto = AF_INET6;
+};
+
+multicast_option : T_BACKLOG T_NUMBER
+{
+	conf.mcast.backlog = $2;
+};
+
+multicast_option : T_GROUP T_NUMBER
+{
+	conf.mcast.port = $2;
+};
+
+hashsize : T_HASHSIZE T_NUMBER
+{
+	conf.hashsize = $2;
+};
+
+hashlimit: T_HASHLIMIT T_NUMBER
+{
+	conf.limit = $2;
+};
+
+unix_line: T_UNIX '{' unix_options '}';
+
+unix_options:
+	    | unix_options unix_option
+	    ;
+
+unix_option : T_PATH T_PATH_VAL
+{
+	strcpy(conf.local.path, $2);
+};
+
+unix_option : T_BACKLOG T_NUMBER
+{
+	conf.local.backlog = $2;
+};
+
+ignore_protocol: T_IGNORE_PROTOCOL '{' ignore_proto_list '}';
+
+ignore_proto_list:
+		 | ignore_proto_list ignore_proto
+		 ;
+
+ignore_proto: T_NUMBER
+{
+	if ($1 < IPPROTO_MAX)
+		conf.ignore_protocol[$1] = 1;
+	else
+		fprintf(stdout, "Protocol number `%d' is freak\n", $1);
+};
+
+ignore_proto: T_UDP
+{
+	conf.ignore_protocol[IPPROTO_UDP] = 1;
+};
+
+ignore_proto: T_ICMP
+{
+	conf.ignore_protocol[IPPROTO_ICMP] = 1;
+};
+
+ignore_proto: T_VRRP
+{
+	conf.ignore_protocol[IPPROTO_VRRP] = 1;
+};
+
+ignore_proto: T_IGMP
+{
+	conf.ignore_protocol[IPPROTO_IGMP] = 1;
+};
+
+sync: T_SYNC '{' sync_list '}';
+
+sync_list:
+	 | sync_list sync_line;
+
+sync_line: refreshtime
+	 | expiretime
+	 | timeout
+	 | checksum
+	 | multicast_line
+	 | relax_transitions
+	 | delay_destroy_msgs
+	 | sync_mode_persistent
+	 | sync_mode_nack
+	 | listen_to
+	 | state_replication
+	 ;
+
+sync_mode_persistent: T_SYNC_MODE T_PERSISTENT '{' sync_mode_persistent_list '}'
+{
+	conf.flags |= SYNC_MODE_PERSISTENT;
+};
+
+sync_mode_nack: T_SYNC_MODE T_NACK '{' sync_mode_nack_list '}'
+{
+	conf.flags |= SYNC_MODE_NACK;
+};
+
+sync_mode_persistent_list:
+	      | sync_mode_persistent_list sync_mode_persistent_line;
+
+sync_mode_persistent_line: refreshtime
+              		 | expiretime
+	     		 | timeout
+			 | relax_transitions
+			 | delay_destroy_msgs
+			 ;
+
+sync_mode_nack_list:
+	      | sync_mode_nack_list sync_mode_nack_line;
+
+sync_mode_nack_line: resend_buffer_size
+		   | timeout
+		   | window_size
+		   ;
+
+resend_buffer_size: T_RESEND_BUFFER_SIZE T_NUMBER
+{
+	conf.resend_buffer_size = $2;
+};
+
+window_size: T_WINDOWSIZE T_NUMBER
+{
+	conf.window_size = $2;
+};
+
+relax_transitions: T_RELAX_TRANSITIONS
+{
+	conf.flags |= RELAX_TRANSITIONS;
+};
+
+delay_destroy_msgs: T_DELAY
+{
+	conf.flags |= DELAY_DESTROY_MSG;
+};
+
+listen_to: T_LISTEN_TO T_IP
+{
+	union inet_address addr;
+
+#ifdef HAVE_INET_PTON_IPV6
+	if (inet_pton(AF_INET6, $2, &addr.ipv6) <= 0)
+#endif
+		if (inet_aton($2, &addr.ipv4) <= 0) {
+			fprintf(stderr, "%s is not a valid IP address\n", $2);
+			exit(EXIT_FAILURE);
+		}
+
+	if (CONFIG(listen_to_len) == 0 || CONFIG(listen_to_len) % 16) {
+		CONFIG(listen_to) = realloc(CONFIG(listen_to),
+					    sizeof(union inet_address) *
+					    (CONFIG(listen_to_len) + 16));
+		if (CONFIG(listen_to) == NULL) {
+			fprintf(stderr, "cannot init listen_to array\n");
+			exit(EXIT_FAILURE);
+		}
+
+		memset(CONFIG(listen_to) + 
+		       (CONFIG(listen_to_len) * sizeof(union inet_address)),
+		       0, sizeof(union inet_address) * 16);
+
+	}
+};
+
+state_replication: T_REPLICATE states T_FOR state_proto;
+
+states:
+      | states state;
+
+state_proto: T_TCP;
+state: tcp_state;
+
+tcp_state: T_SYN_SENT
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_SENT);
+};
+tcp_state: T_SYN_RECV
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_RECV);
+};
+tcp_state: T_ESTABLISHED
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_ESTABLISHED);
+};
+tcp_state: T_FIN_WAIT
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_FIN_WAIT);
+};
+tcp_state: T_CLOSE_WAIT
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE_WAIT);
+};
+tcp_state: T_LAST_ACK
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LAST_ACK);
+};
+tcp_state: T_TIME_WAIT
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_TIME_WAIT);
+};
+tcp_state: T_CLOSE
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE);
+};
+tcp_state: T_LISTEN
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LISTEN);
+};
+
+general: T_GENERAL '{' general_list '}';
+
+general_list:
+	    | general_list general_line
+	    ;
+
+general_line: hashsize
+	    | hashlimit
+	    | log
+	    | lock
+	    | unix_line
+	    | netlink_buffer_size
+	    | netlink_buffer_size_max_grown
+	    | family
+	    ;
+
+netlink_buffer_size: T_BUFFER_SIZE T_NUMBER
+{
+	conf.netlink_buffer_size = $2;
+};
+
+netlink_buffer_size_max_grown : T_BUFFER_SIZE_MAX_GROWN T_NUMBER
+{
+	conf.netlink_buffer_size_max_grown = $2;
+};
+
+family : T_FAMILY T_STRING
+{
+	if (strncmp($2, "IPv6", strlen("IPv6")) == 0)
+		conf.family = AF_INET6;
+	else
+		conf.family = AF_INET;
+};
+
+stats: T_SYNC '{' stats_list '}';
+
+stats_list:
+	 | stats_list stat_line
+	 ;
+
+stat_line:
+	 |
+	 ;
+
+%%
+
+int
+yyerror(char *msg)
+{
+	printf("Error parsing config file: ");
+	printf("line (%d), symbol '%s': %s\n", yylineno, yytext, msg);
+	exit(EXIT_FAILURE);
+}
+
+int
+init_config(char *filename)
+{
+	FILE *fp;
+
+	fp = fopen(filename, "r");
+	if (!fp)
+		return -1;
+
+	yyrestart(fp);
+	yyparse();
+	fclose(fp);
+
+	/* default to IPv4 */
+	if (CONFIG(family) == 0)
+		CONFIG(family) = AF_INET;
+
+	/* set to default is not specified */
+	if (strcmp(CONFIG(lockfile), "") == 0)
+		strncpy(CONFIG(lockfile), DEFAULT_LOCKFILE, FILENAME_MAXLEN);
+
+	/* default to 180 seconds of expiration time: cache entries */
+	if (CONFIG(cache_timeout) == 0)
+		CONFIG(cache_timeout) = 180;
+
+	/* default to 180 seconds: committed entries */
+	if (CONFIG(commit_timeout) == 0)
+		CONFIG(commit_timeout) = 180;
+
+	/* default to 60 seconds of refresh time */
+	if (CONFIG(refresh) == 0)
+		CONFIG(refresh) = 60;
+
+	if (CONFIG(resend_buffer_size) == 0)
+		CONFIG(resend_buffer_size) = 262144;
+
+	/* create empty pool */
+	if (!STATE(ignore_pool)) {
+		STATE(ignore_pool) = ignore_pool_create(CONFIG(family));
+		if (!STATE(ignore_pool)) {
+			fprintf(stdout, "Can't create ignore pool!\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	/* default to a window size of 20 packets */
+	if (CONFIG(window_size) == 0)
+		CONFIG(window_size) = 20;
+
+	return 0;
+}
diff --git a/daemon/src/run.c b/daemon/src/run.c
new file mode 100644
index 0000000..67437d8
--- /dev/null
+++ b/daemon/src/run.c
@@ -0,0 +1,227 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: run and init functions
+ */
+
+#include "conntrackd.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include <signal.h>
+#include <stdlib.h>
+
+void killer(int foo)
+{
+	/* no signals while handling signals */
+	sigprocmask(SIG_BLOCK, &STATE(block), NULL);
+
+	nfnl_subsys_close(STATE(subsys_event));
+	nfnl_subsys_close(STATE(subsys_dump));
+	nfnl_subsys_close(STATE(subsys_sync));
+	nfnl_close(STATE(event));
+	nfnl_close(STATE(dump));
+	nfnl_close(STATE(sync));
+
+	ignore_pool_destroy(STATE(ignore_pool));
+	local_server_destroy(STATE(local));
+	STATE(mode)->kill();
+        unlink(CONFIG(lockfile));
+	dlog(STATE(log), "------- shutdown received ----");
+	close_log(STATE(log));
+
+	sigprocmask(SIG_UNBLOCK, &STATE(block), NULL);
+
+	exit(0);			
+}
+
+void local_handler(int fd, void *data)
+{
+	int ret;
+	int type;
+
+	ret = read(fd, &type, sizeof(type));
+	if (ret == -1) {
+		dlog(STATE(log), "can't read from unix socket\n");
+		return;
+	}
+	if (ret == 0) {
+		debug("nothing to process\n");
+		return;
+	}
+
+	switch(type) {
+	case FLUSH_MASTER:
+		dlog(STATE(log), "[REQ] flushing master table");
+		nl_flush_master_conntrack_table();
+		return;
+	case RESYNC_MASTER:
+		dlog(STATE(log), "[REQ] resync with master table");
+		nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump));
+		return;
+	}
+
+	if (!STATE(mode)->local(fd, type, data))
+		dlog(STATE(log), "[FAIL] unknown local request %d", type);
+}
+
+int init(int mode)
+{
+	switch(mode) {
+		case STATS_MODE:
+			STATE(mode) = &stats_mode;
+			break;
+		case SYNC_MODE:
+			STATE(mode) = &sync_mode;
+			break;
+		default:
+			fprintf(stderr, "Unknown running mode! default "
+					"to synchronization mode\n");
+			STATE(mode) = &sync_mode;
+			break;
+	}
+
+	/* Initialization */
+	if (STATE(mode)->init() == -1) {
+		dlog(STATE(log), "[FAIL] initialization failed");
+		return -1;
+	}
+
+	/* local UNIX socket */
+	STATE(local) = local_server_create(&CONFIG(local));
+	if (!STATE(local)) {
+		dlog(STATE(log), "[FAIL] can't open unix socket!");
+		return -1;
+	}
+
+	if (nl_init_event_handler() == -1) {
+		dlog(STATE(log), "[FAIL] can't open netlink handler! "
+				 "no ctnetlink kernel support?");
+		return -1;
+	}
+
+	if (nl_init_dump_handler() == -1) {
+		dlog(STATE(log), "[FAIL] can't open netlink handler! "
+				 "no ctnetlink kernel support?");
+		return -1;
+	}
+
+	if (nl_init_overrun_handler() == -1) {
+		dlog(STATE(log), "[FAIL] can't open netlink handler! "
+				 "no ctnetlink kernel support?");
+		return -1;
+	}
+
+        /* Signals handling */
+	sigemptyset(&STATE(block));
+	sigaddset(&STATE(block), SIGTERM);
+	sigaddset(&STATE(block), SIGINT);
+
+	if (signal(SIGINT, killer) == SIG_ERR)
+		return -1;
+
+	if (signal(SIGTERM, killer) == SIG_ERR)
+		return -1;
+
+	/* ignore connection reset by peer */
+	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+		return -1;
+
+	dlog(STATE(log), "[OK] initialization completed");
+
+	return 0;
+}
+
+#define POLL_NSECS 1
+
+static void __run(void)
+{
+	int max, ret;
+	fd_set readfds;
+	struct timeval tv = {
+		.tv_sec         = POLL_NSECS,
+		.tv_usec        = 0
+	};
+
+	FD_ZERO(&readfds);
+	FD_SET(STATE(local), &readfds);
+	FD_SET(nfnl_fd(STATE(event)), &readfds);
+
+	max = MAX(STATE(local), nfnl_fd(STATE(event)));
+
+	if (STATE(mode)->add_fds_to_set)
+		max = MAX(max, STATE(mode)->add_fds_to_set(&readfds));
+
+	ret = select(max+1, &readfds, NULL, NULL, &tv);
+	if (ret == -1) {
+		/* interrupted syscall, retry */
+		if (errno == EINTR)
+			return;
+
+		dlog(STATE(log), "select() failed: %s", strerror(errno));
+		return;
+	}
+
+	/* signals are racy */
+	sigprocmask(SIG_BLOCK, &STATE(block), NULL);		
+
+	/* order received via UNIX socket */
+	if (FD_ISSET(STATE(local), &readfds))
+		do_local_server_step(STATE(local), NULL, local_handler);
+
+	/* conntrack event has happened */
+	if (FD_ISSET(nfnl_fd(STATE(event)), &readfds)) {
+		ret = nfnl_catch(STATE(event));
+		if (ret == -1) {
+			switch(errno) {
+			case ENOBUFS:
+                		/*
+		 		 * It seems that ctnetlink can't back off,
+				 * it's likely that we're losing events.
+				 * Solution: duplicate the socket buffer
+				 * size and resync with master conntrack table.
+				 */
+				nl_resize_socket_buffer(STATE(event));
+				nl_dump_conntrack_table(STATE(sync),
+							STATE(subsys_sync));
+				break;
+			case ENOENT:
+				/*
+				 * We received a message from another
+				 * netfilter subsystem that we are not
+				 * interested in. Just ignore it.
+				 */
+				break;
+			default:
+				dlog(STATE(log), "event catch says: %s",
+						  strerror(errno));
+				break;
+			}
+		}
+	}
+
+	if (STATE(mode)->step)
+		STATE(mode)->step(&readfds);
+
+	sigprocmask(SIG_UNBLOCK, &STATE(block), NULL);
+}
+
+void run(void)
+{
+	while(1)
+		__run();
+}
diff --git a/daemon/src/state_helper.c b/daemon/src/state_helper.c
new file mode 100644
index 0000000..81b0d09
--- /dev/null
+++ b/daemon/src/state_helper.c
@@ -0,0 +1,44 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "conntrackd.h"
+#include "state_helper.h"
+
+static struct state_replication_helper *helper[IPPROTO_MAX];
+
+int state_helper_verdict(int type, struct nf_conntrack *ct) 
+{
+	u_int8_t l4proto;
+
+        if (type == NFCT_T_DESTROY)
+		return ST_H_REPLICATE;
+
+	l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
+	if (helper[l4proto])
+		return helper[l4proto]->verdict(helper[l4proto], ct);
+
+	return ST_H_REPLICATE;
+}
+
+void state_helper_register(struct state_replication_helper *h, int state)
+{
+	if (helper[h->proto] == NULL)
+		helper[h->proto] = h;
+
+	helper[h->proto]->state |= (1 << state);
+}
diff --git a/daemon/src/state_helper_tcp.c b/daemon/src/state_helper_tcp.c
new file mode 100644
index 0000000..af714dc
--- /dev/null
+++ b/daemon/src/state_helper_tcp.c
@@ -0,0 +1,35 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "conntrackd.h"
+#include "state_helper.h"
+
+static int tcp_verdict(const struct state_replication_helper *h,
+		       const struct nf_conntrack *ct)
+{
+	u_int8_t state = nfct_get_attr_u8(ct, ATTR_TCP_STATE);
+	if (h->state & (1 << state))
+		return ST_H_REPLICATE;
+
+	return ST_H_SKIP;
+}
+
+struct state_replication_helper tcp_state_helper = {
+	.proto 		= IPPROTO_TCP,
+	.verdict 	= tcp_verdict,
+};
diff --git a/daemon/src/stats-mode.c b/daemon/src/stats-mode.c
new file mode 100644
index 0000000..9647bbf
--- /dev/null
+++ b/daemon/src/stats-mode.c
@@ -0,0 +1,151 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include "cache.h"
+#include "conntrackd.h"
+#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include <signal.h>
+#include <sys/select.h>
+
+static int init_stats(void)
+{
+	int ret;
+
+	state.stats = malloc(sizeof(struct ct_stats_state));
+	if (!state.stats) {
+		dlog(STATE(log), "[FAIL] can't allocate memory for stats sync");
+		return -1;
+	}
+	memset(state.stats, 0, sizeof(struct ct_stats_state));
+
+	STATE_STATS(cache) = cache_create("stats",
+					  LIFETIME, 
+					  CONFIG(family),
+					  NULL); 
+	if (!STATE_STATS(cache)) {
+		dlog(STATE(log), "[FAIL] can't allocate memory for the "
+				 "external cache");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void kill_stats()
+{
+	cache_destroy(STATE_STATS(cache));
+}
+
+/* handler for requests coming via UNIX socket */
+static int local_handler_stats(int fd, int type, void *data)
+{
+	int ret = 1;
+
+	switch(type) {
+	case DUMP_INTERNAL:
+		cache_dump(STATE_STATS(cache), fd, NFCT_O_PLAIN);
+		break;
+	case DUMP_INT_XML:
+		cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML);
+		break;
+	case FLUSH_CACHE:
+		dlog(STATE(log), "[REQ] flushing caches");
+		cache_flush(STATE_STATS(cache));
+		break;
+	case KILL:
+		killer();
+		break;
+	case STATS:
+		cache_stats(STATE_STATS(cache), fd);
+		dump_traffic_stats(fd);
+		break;
+	default:
+		ret = 0;
+		break;
+	}
+
+	return ret;
+}
+
+static void dump_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	if (cache_update_force(STATE_STATS(cache), ct))
+		debug_ct(ct, "resync entry");
+}
+
+static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	debug_ct(ct, "debug event");
+	if (cache_add(STATE_STATS(cache), ct)) {
+		debug_ct(ct, "cache new");
+	} else {
+		dlog(STATE(log), "can't add to cache cache: "
+				      "%s\n", strerror(errno));
+		debug_ct(ct, "can't add");
+	}
+}
+
+static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	debug_ct(ct, "update");
+
+	if (!cache_update(STATE_STATS(cache), ct)) {
+		/*
+		 * Perhaps we are losing events. If we are working 
+		 * in relax mode then add a new entry to the cache.
+		 *
+		 * FIXME: relax transitions not implemented yet
+		 */
+		if ((CONFIG(flags) & RELAX_TRANSITIONS)
+		    && cache_add(STATE_STATS(cache), ct)) {
+			debug_ct(ct, "forcing cache update");
+		} else {
+			debug_ct(ct, "can't update");
+			return;
+		}
+	}
+	debug_ct(ct, "update");
+}
+
+static int event_destroy_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	if (cache_del(STATE_STATS(cache), ct)) {
+		debug_ct(ct, "cache destroy");
+		return 1;
+	} else {
+		debug_ct(ct, "can't destroy!");
+		return 0;
+	}
+}
+
+struct ct_mode stats_mode = {
+	.init 			= init_stats,
+	.add_fds_to_set 	= NULL,
+	.step			= NULL,
+	.local			= local_handler_stats,
+	.kill			= kill_stats,
+	.dump			= dump_stats,
+	.overrun		= dump_stats,
+	.event_new		= event_new_stats,
+	.event_upd		= event_update_stats,
+	.event_dst		= event_destroy_stats
+};
diff --git a/daemon/src/sync-mode.c b/daemon/src/sync-mode.c
new file mode 100644
index 0000000..b32bef7
--- /dev/null
+++ b/daemon/src/sync-mode.c
@@ -0,0 +1,416 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include "cache.h"
+#include "conntrackd.h"
+#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include <signal.h>
+#include <sys/select.h>
+#include "sync.h"
+#include "network.h"
+
+/* handler for multicast messages received */
+static void mcast_handler()
+{
+	int ret;
+	char buf[4096], tmp[256];
+	struct mcast_sock *m = STATE_SYNC(mcast_server);
+	unsigned int type;
+	struct nlnetwork *net = (struct nlnetwork *) buf;
+	unsigned int size = sizeof(struct nlnetwork);
+	struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size);
+	struct nf_conntrack *ct = (struct nf_conntrack *) tmp;
+	struct us_conntrack *u = NULL;
+
+	memset(tmp, 0, sizeof(tmp));
+
+	ret = mcast_recv_netmsg(m, buf, sizeof(buf));
+	if (ret <= 0) {
+		STATE(malformed)++;
+		return;
+	}
+
+	if (STATE_SYNC(mcast_sync)->pre_recv(net))
+		return;
+
+	if ((type = parse_network_msg(ct, nlh)) == NFCT_T_ERROR) {
+		STATE(malformed)++;
+		return;
+	}
+
+	nfct_attr_unset(ct, ATTR_TIMEOUT);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS);
+
+	switch(type) {
+	case NFCT_T_NEW:
+retry:		
+		if ((u = cache_add(STATE_SYNC(external), ct))) {
+			debug_ct(u->ct, "external new");
+		} else {
+		        /*
+			 * One certain connection A arrives to the cache but 
+			 * another existing connection B in the cache has 
+			 * the same configuration, therefore B clashes with A.
+			 */
+			if (errno == EEXIST) {
+				cache_del(STATE_SYNC(external), ct);
+				goto retry;
+			}
+			debug_ct(ct, "can't add");
+		}
+		break;
+	case NFCT_T_UPDATE:
+		if ((u = cache_update_force(STATE_SYNC(external), ct))) {
+			debug_ct(u->ct, "external update");
+		} else
+			debug_ct(ct, "can't update");
+		break;
+	case NFCT_T_DESTROY:
+		if (cache_del(STATE_SYNC(external), ct))
+			debug_ct(ct, "external destroy");
+		else
+			debug_ct(ct, "can't destroy");
+		break;
+	default:
+		debug("unknown type %d\n", type);
+		break;
+	}
+}
+
+static int init_sync(void)
+{
+	int ret;
+
+	state.sync = malloc(sizeof(struct ct_sync_state));
+	if (!state.sync) {
+		dlog(STATE(log), "[FAIL] can't allocate memory for state sync");
+		return -1;
+	}
+	memset(state.sync, 0, sizeof(struct ct_sync_state));
+
+	if (CONFIG(flags) & SYNC_MODE_NACK)
+		STATE_SYNC(mcast_sync) = &nack;
+	else
+		/* default to persistent mode */
+		STATE_SYNC(mcast_sync) = &notrack;
+
+	if (STATE_SYNC(mcast_sync)->init)
+		STATE_SYNC(mcast_sync)->init();
+
+	STATE_SYNC(internal) =
+		cache_create("internal", 
+			     STATE_SYNC(mcast_sync)->internal_cache_flags,
+			     CONFIG(family),
+			     STATE_SYNC(mcast_sync)->internal_cache_extra);
+
+	if (!STATE_SYNC(internal)) {
+		dlog(STATE(log), "[FAIL] can't allocate memory for "
+				 "the internal cache");
+		return -1;
+	}
+
+	STATE_SYNC(external) = 
+		cache_create("external",
+			     STATE_SYNC(mcast_sync)->external_cache_flags,
+			     CONFIG(family),
+			     NULL);
+
+	if (!STATE_SYNC(external)) {
+		dlog(STATE(log), "[FAIL] can't allocate memory for the "
+				 "external cache");
+		return -1;
+	}
+
+	/* multicast server to receive events from the wire */
+	STATE_SYNC(mcast_server) = mcast_server_create(&CONFIG(mcast));
+	if (STATE_SYNC(mcast_server) == NULL) {
+		dlog(STATE(log), "[FAIL] can't open multicast server!");
+		return -1;
+	}
+
+	/* multicast client to send events on the wire */
+	STATE_SYNC(mcast_client) = mcast_client_create(&CONFIG(mcast));
+	if (STATE_SYNC(mcast_client) == NULL) {
+		dlog(STATE(log), "[FAIL] can't open client multicast socket!");
+		return -1;
+	}
+
+	/* initialization of multicast sequence generation */
+	STATE_SYNC(last_seq_sent) = time(NULL);
+
+	if (create_alarm_thread() == -1) {
+		dlog(STATE(log), "[FAIL] can't initialize alarm thread");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int add_fds_to_set_sync(fd_set *readfds) 
+{
+	FD_SET(STATE_SYNC(mcast_server->fd), readfds);
+
+	return STATE_SYNC(mcast_server->fd);
+}
+
+static void step_sync(fd_set *readfds)
+{
+	/* multicast packet has been received */
+	if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds))
+		mcast_handler();
+}
+
+static void kill_sync()
+{
+	cache_destroy(STATE_SYNC(internal));
+	cache_destroy(STATE_SYNC(external));
+
+	mcast_server_destroy(STATE_SYNC(mcast_server));
+	mcast_client_destroy(STATE_SYNC(mcast_client));
+
+	destroy_alarm_thread();
+
+	if (STATE_SYNC(mcast_sync)->kill)
+		STATE_SYNC(mcast_sync)->kill();
+}
+
+static dump_stats_sync(int fd)
+{
+	char buf[512];
+	int size;
+
+	size = sprintf(buf, "multicast sequence tracking:\n"
+			    "%20llu Pckts mfrm "
+			    "%20llu Pckts lost\n\n",
+			STATE(malformed),
+			STATE_SYNC(packets_lost));
+
+	send(fd, buf, size, 0);
+}
+
+/* handler for requests coming via UNIX socket */
+static int local_handler_sync(int fd, int type, void *data)
+{
+	int ret = 1;
+
+	switch(type) {
+	case DUMP_INTERNAL:
+		cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN);
+		break;
+	case DUMP_EXTERNAL:
+		cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN);
+		break;
+	case DUMP_INT_XML:
+		cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML);
+		break;
+	case DUMP_EXT_XML:
+		cache_dump(STATE_SYNC(external), fd, NFCT_O_XML);
+		break;
+	case COMMIT:
+		dlog(STATE(log), "[REQ] commit external cache to master table");
+		cache_commit(STATE_SYNC(external));
+		break;
+	case FLUSH_CACHE:
+		dlog(STATE(log), "[REQ] flushing caches");
+		cache_flush(STATE_SYNC(internal));
+		cache_flush(STATE_SYNC(external));
+		break;
+	case KILL:
+		killer();
+		break;
+	case STATS:
+		cache_stats(STATE_SYNC(internal), fd);
+		cache_stats(STATE_SYNC(external), fd);
+		dump_traffic_stats(fd);
+		mcast_dump_stats(fd, STATE_SYNC(mcast_client), 
+				     STATE_SYNC(mcast_server));
+		dump_stats_sync(fd);
+		break;
+	case SEND_BULK:
+		dlog(STATE(log), "[REQ] sending bulk update");
+		cache_bulk(STATE_SYNC(internal));
+		break;
+	default:
+		if (STATE_SYNC(mcast_sync)->local)
+			ret = STATE_SYNC(mcast_sync)->local(fd, type, data);
+		break;
+	}
+
+	return ret;
+}
+
+static void dump_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	/* This is required by kernels < 2.6.20 */
+	nfct_attr_unset(ct, ATTR_TIMEOUT);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_USE);
+
+	if (cache_update_force(STATE_SYNC(internal), ct))
+		debug_ct(ct, "resync");
+}
+
+static void mcast_send_sync(struct nlmsghdr *nlh,
+			    struct us_conntrack *u,
+			    struct nf_conntrack *ct,
+			    int type)
+{
+	char buf[4096];
+	struct nlnetwork *net = (struct nlnetwork *) buf;
+	int mangled = 0;
+
+	memset(buf, 0, sizeof(buf));
+
+	if (!state_helper_verdict(type, ct))
+		return;
+
+	if (!mangled)
+		memcpy(buf + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len);
+
+	mcast_send_netmsg(STATE_SYNC(mcast_client), net); 
+	STATE_SYNC(mcast_sync)->post_send(net, u);
+}
+
+static void overrun_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	struct us_conntrack *u;
+
+	/* This is required by kernels < 2.6.20 */
+	nfct_attr_unset(ct, ATTR_TIMEOUT);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_USE);
+
+	if (!cache_test(STATE_SYNC(internal), ct)) {
+		if ((u = cache_update_force(STATE_SYNC(internal), ct))) {
+			debug_ct(ct, "overrun resync");
+			mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE);
+		}
+	}
+}
+
+static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	struct us_conntrack *u;
+
+	/* required by linux kernel <= 2.6.20 */
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_TIMEOUT);
+retry:
+	if ((u = cache_add(STATE_SYNC(internal), ct))) {
+		mcast_send_sync(nlh, u, ct, NFCT_T_NEW);
+		debug_ct(u->ct, "internal new");
+	} else {
+		if (errno == EEXIST) {
+			char buf[4096];
+			struct nlmsghdr *nlh = (struct nlmsghdr *) buf;
+
+			int ret = build_network_msg(NFCT_Q_DESTROY,
+						    STATE(subsys_event),
+						    ct,
+						    buf,
+						    sizeof(buf));
+			if (ret == -1)
+				return;
+
+			cache_del(STATE_SYNC(internal), ct);
+			mcast_send_sync(nlh, NULL, ct, NFCT_T_NEW);
+			goto retry;
+		}
+		dlog(STATE(log), "can't add to internal cache: "
+				      "%s\n", strerror(errno));
+		debug_ct(ct, "can't add");
+	}
+}
+
+static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	struct us_conntrack *u;
+
+	nfct_attr_unset(ct, ATTR_TIMEOUT);
+
+	if ((u = cache_update(STATE_SYNC(internal), ct)) == NULL) {
+		/*
+		 * Perhaps we are losing events. If we are working 
+		 * in relax mode then add a new entry to the cache.
+		 *
+		 * FIXME: relax transitions not implemented yet
+		 */
+		if ((CONFIG(flags) & RELAX_TRANSITIONS)
+		    && (u = cache_add(STATE_SYNC(internal), ct))) {
+			debug_ct(u->ct, "forcing internal update");
+		} else {
+			debug_ct(ct, "can't update");
+			return;
+		}
+	}
+	debug_ct(u->ct, "internal update");
+	mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE);
+}
+
+static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	nfct_attr_unset(ct, ATTR_TIMEOUT);
+
+	if (CONFIG(flags) & DELAY_DESTROY_MSG) {
+
+		nfct_set_attr_u32(ct, ATTR_STATUS, IPS_DYING);
+
+		if (cache_update(STATE_SYNC(internal), ct)) {
+			debug_ct(ct, "delay internal destroy");
+			return 1;
+		} else {
+			debug_ct(ct, "can't delay destroy!");
+			return 0;
+		}
+	} else {
+		if (cache_del(STATE_SYNC(internal), ct)) {
+			mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY);
+			debug_ct(ct, "internal destroy");
+		} else
+			debug_ct(ct, "can't destroy");
+	}
+}
+
+struct ct_mode sync_mode = {
+	.init 			= init_sync,
+	.add_fds_to_set 	= add_fds_to_set_sync,
+	.step			= step_sync,
+	.local			= local_handler_sync,
+	.kill			= kill_sync,
+	.dump			= dump_sync,
+	.overrun		= overrun_sync,
+	.event_new		= event_new_sync,
+	.event_upd		= event_update_sync,
+	.event_dst		= event_destroy_sync
+};
diff --git a/daemon/src/sync-nack.c b/daemon/src/sync-nack.c
new file mode 100644
index 0000000..288dba4
--- /dev/null
+++ b/daemon/src/sync-nack.c
@@ -0,0 +1,309 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <errno.h>
+#include "conntrackd.h"
+#include "sync.h"
+#include "linux_list.h"
+#include "us-conntrack.h"
+#include "buffer.h"
+#include "debug.h"
+#include "network.h"
+#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+#if 0 
+#define dp printf
+#else
+#define dp
+#endif
+
+static LIST_HEAD(queue);
+
+struct cache_nack {
+	struct list_head 	head;
+	u_int32_t 		seq;
+};
+
+static void cache_nack_add(struct us_conntrack *u, void *data)
+{
+	struct cache_nack *cn = data;
+
+	INIT_LIST_HEAD(&cn->head);
+	list_add(&cn->head, &queue);
+}
+
+static void cache_nack_update(struct us_conntrack *u, void *data)
+{
+	struct cache_nack *cn = data;
+
+	if (cn->head.next != LIST_POISON1 &&
+	    cn->head.prev != LIST_POISON2)
+		list_del(&cn->head);
+
+	INIT_LIST_HEAD(&cn->head);
+	list_add(&cn->head, &queue);
+}
+
+static void cache_nack_destroy(struct us_conntrack *u, void *data)
+{
+	struct cache_nack *cn = data;
+
+	if (cn->head.next != LIST_POISON1 &&
+	    cn->head.prev != LIST_POISON2)
+		list_del(&cn->head);
+}
+
+static struct cache_extra cache_nack_extra = {
+	.size 		= sizeof(struct cache_nack),
+	.add		= cache_nack_add,
+	.update		= cache_nack_update,
+	.destroy	= cache_nack_destroy
+};
+
+static int nack_init()
+{
+	STATE_SYNC(buffer) = buffer_create(CONFIG(resend_buffer_size));
+	if (STATE_SYNC(buffer) == NULL)
+		return -1;
+
+	return 0;
+}
+
+static void nack_kill()
+{
+	buffer_destroy(STATE_SYNC(buffer));
+}
+
+static void mcast_send_nack(u_int32_t expt_seq, u_int32_t recv_seq)
+{
+	struct nlnetwork_ack nack = {
+		.flags = NET_NACK,
+		.from  = expt_seq,
+		.to    = recv_seq,
+	};
+
+	mcast_send_error(STATE_SYNC(mcast_client), &nack);
+	buffer_add(STATE_SYNC(buffer), &nack, sizeof(struct nlnetwork_ack));
+}
+
+static void mcast_send_ack(u_int32_t from, u_int32_t to)
+{
+	struct nlnetwork_ack ack = {
+		.flags = NET_ACK,
+		.from   = from,
+		.to	= to,
+	};
+
+	mcast_send_error(STATE_SYNC(mcast_client), &ack);
+	buffer_add(STATE_SYNC(buffer), &ack, sizeof(struct nlnetwork_ack));
+}
+
+static void mcast_send_resync()
+{
+	struct nlnetwork net = {
+		.flags = NET_RESYNC,
+	};
+
+	mcast_send_error(STATE_SYNC(mcast_client), &net);
+	buffer_add(STATE_SYNC(buffer), &net, sizeof(struct nlnetwork));
+}
+
+int nack_local(int fd, int type, void *data)
+{
+	int ret = 1;
+
+	switch(type) {
+		case REQUEST_DUMP:
+			mcast_send_resync();
+			dlog(STATE(log), "[REQ] request resync");
+			break;
+		default:
+			ret = 0;
+			break;
+	}
+
+	return ret;
+}
+
+static int buffer_compare(void *data1, void *data2)
+{
+	struct nlnetwork *net = data1;
+	struct nlnetwork_ack *nack = data2;
+	struct nlmsghdr *nlh = data1 + sizeof(struct nlnetwork);
+
+	unsigned old_seq = ntohl(net->seq);
+
+	if (ntohl(net->seq) >= nack->from && ntohl(net->seq) <= nack->to) {
+		if (mcast_resend_netmsg(STATE_SYNC(mcast_client), net))
+			dp("resend destroy (old seq=%u) (seq=%u)\n", 
+			   old_seq, ntohl(net->seq));
+	}
+	return 0;
+}
+
+static int buffer_remove(void *data1, void *data2)
+{
+	struct nlnetwork *net = data1;
+	struct nlnetwork_ack *h = data2;
+
+	if (ntohl(net->seq) >= h->from && ntohl(net->seq) <= h->to) {
+		dp("remove from buffer (seq=%u)\n", ntohl(net->seq));
+		__buffer_del(STATE_SYNC(buffer), data1);
+	}
+	return 0;
+}
+
+static void queue_resend(struct cache *c, unsigned int from, unsigned int to)
+{
+	struct list_head *n;
+	struct us_conntrack *u;
+	unsigned int *seq;
+
+	lock();
+	list_for_each(n, &queue) {
+		struct cache_nack *cn = (struct cache_nack *) n;
+		struct us_conntrack *u;
+		
+		u = cache_get_conntrack(STATE_SYNC(internal), cn);
+
+		if (cn->seq >= from && cn->seq <= to) {
+			debug_ct(u->ct, "resend nack");
+			dp("resending nack'ed (oldseq=%u) ", cn->seq);
+
+			char buf[4096];
+			struct nlnetwork *net = (struct nlnetwork *) buf;
+
+			int ret = build_network_msg(NFCT_Q_UPDATE,
+						    STATE(subsys_event),
+						    u->ct,
+						    buf,
+						    sizeof(buf));
+			if (ret == -1) {
+				unlock();
+				break;
+			}
+
+			mcast_send_netmsg(STATE_SYNC(mcast_client), buf); 
+			STATE_SYNC(mcast_sync)->post_send(net, u);
+			dp("(newseq=%u)\n", *seq);
+		} 
+	}
+	unlock();
+}
+
+static void queue_empty(struct cache *c, unsigned int from, unsigned int to)
+{
+	struct list_head *n, *tmp;
+	struct us_conntrack *u;
+	unsigned int *seq;
+
+	lock();
+	dp("ACK from %u to %u\n", from, to);
+	list_for_each_safe(n, tmp, &queue) {
+		struct cache_nack *cn = (struct cache_nack *) n;
+
+		u = cache_get_conntrack(STATE_SYNC(internal), cn);
+		if (cn->seq >= from && cn->seq <= to) {
+			dp("remove %u\n", cn->seq);
+			debug_ct(u->ct, "ack received: empty queue");
+			dp("queue: deleting from queue (seq=%u)\n", cn->seq);
+			list_del(&cn->head);
+		} 
+	}
+	unlock();
+}
+
+static int nack_pre_recv(const struct nlnetwork *net)
+{
+	static unsigned int window = 0;
+	unsigned int exp_seq;
+
+	if (window == 0)
+		window = CONFIG(window_size);
+
+	if (!mcast_track_seq(net->seq, &exp_seq)) {
+		dp("OOS: sending nack (seq=%u)\n", exp_seq);
+		mcast_send_nack(exp_seq, net->seq - 1);
+		window = CONFIG(window_size);
+	} else {
+		/* received a window, send an acknowledgement */
+		if (--window == 0) {
+			dp("sending ack (seq=%u)\n", net->seq);
+			mcast_send_ack(net->seq-CONFIG(window_size), net->seq);
+		}
+	}
+
+	if (net->flags & NET_NACK) {
+		struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net;
+
+		dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to);
+		queue_resend(STATE_SYNC(internal), nack->from, nack->to);
+		buffer_iterate(STATE_SYNC(buffer), nack, buffer_compare);
+		return 1;
+	} else if (net->flags & NET_RESYNC) {
+		dp("RESYNC ALL\n");
+		cache_bulk(STATE_SYNC(internal));
+		return 1;
+	} else if (net->flags & NET_ACK) {
+		struct nlnetwork_ack *h = (struct nlnetwork_ack *) net;
+
+		dp("ACK: from seq=%u to seq=%u\n", h->from, h->to);
+		queue_empty(STATE_SYNC(internal), h->from, h->to);
+		buffer_iterate(STATE_SYNC(buffer), h, buffer_remove);
+		return 1;
+	}
+
+	return 0;
+}
+
+static void nack_post_send(const struct nlnetwork *net, struct us_conntrack *u)
+{
+	unsigned int size = sizeof(struct nlnetwork);
+	struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size);
+
+	if (NFNL_MSG_TYPE(ntohs(nlh->nlmsg_type)) == IPCTNL_MSG_CT_DELETE) {
+		buffer_add(STATE_SYNC(buffer), net, 
+			   ntohl(nlh->nlmsg_len) + size); 
+	} else if (u != NULL) {
+		unsigned int *seq;
+		struct list_head *n;
+		struct cache_nack *cn;
+
+		cn = (struct cache_nack *)
+			cache_get_extra(STATE_SYNC(internal), u);
+		cn->seq = ntohl(net->seq);
+		if (cn->head.next != LIST_POISON1 &&
+		    cn->head.prev != LIST_POISON2)
+		    	list_del(&cn->head);
+
+		INIT_LIST_HEAD(&cn->head);
+		list_add(&cn->head, &queue);
+	}
+}
+
+struct sync_mode nack = {
+	.internal_cache_flags	= LIFETIME,
+	.external_cache_flags	= LIFETIME,
+	.internal_cache_extra	= &cache_nack_extra,
+	.init			= nack_init,
+	.kill			= nack_kill,
+	.local			= nack_local,
+	.pre_recv		= nack_pre_recv,
+	.post_send		= nack_post_send,
+};
diff --git a/daemon/src/sync-notrack.c b/daemon/src/sync-notrack.c
new file mode 100644
index 0000000..2b5ae38
--- /dev/null
+++ b/daemon/src/sync-notrack.c
@@ -0,0 +1,127 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "conntrackd.h"
+#include "sync.h"
+#include "network.h"
+#include "us-conntrack.h"
+#include "alarm.h"
+
+static void refresher(struct alarm_list *a, void *data)
+{
+	struct us_conntrack *u = data;
+	char buf[8192];
+	int size;
+
+	if (nfct_get_attr_u32(u->ct, ATTR_STATUS) & IPS_DYING) {
+		
+		debug_ct(u->ct, "persistence destroy");
+
+		size = build_network_msg(NFCT_Q_DESTROY,
+					 STATE(subsys_event),
+					 u->ct,
+					 buf,
+					 sizeof(buf));
+
+		__cache_del(u->cache, u->ct);
+		mcast_send_netmsg(STATE_SYNC(mcast_client), buf);
+	} else {
+		
+		debug_ct(u->ct, "persistence update");
+
+		a->expires = random() % CONFIG(refresh) + 1;
+		size = build_network_msg(NFCT_Q_UPDATE,
+					 STATE(subsys_event),
+					 u->ct,
+					 buf, 
+					 sizeof(buf));
+		mcast_send_netmsg(STATE_SYNC(mcast_client), buf);
+	}
+}
+
+static void cache_notrack_add(struct us_conntrack *u, void *data)
+{
+	struct alarm_list *alarm = data;
+
+	init_alarm(alarm);
+	set_alarm_expiration(alarm, (random() % conf.refresh) + 1);
+	set_alarm_data(alarm, u);
+	set_alarm_function(alarm, refresher);
+	add_alarm(alarm);
+}
+
+static void cache_notrack_update(struct us_conntrack *u, void *data)
+{
+	struct alarm_list *alarm = data;
+	mod_alarm(alarm, (random() % conf.refresh) + 1);
+}
+
+static void cache_notrack_destroy(struct us_conntrack *u, void *data)
+{
+	struct alarm_list *alarm = data;
+	del_alarm(alarm);
+}
+
+static struct cache_extra cache_notrack_extra = {
+	.size 		= sizeof(struct alarm_list),
+	.add		= cache_notrack_add,
+	.update		= cache_notrack_update,
+	.destroy	= cache_notrack_destroy
+};
+
+static int notrack_pre_recv(const struct nlnetwork *net)
+{
+	unsigned int exp_seq;
+
+	/* 
+	 * Ignore error messages: Although this message type is not ever
+	 * generated in notrack mode, we don't want to crash the daemon 
+	 * if someone nuts mixes nack and notrack.
+	 */
+	if (net->flags & (NET_RESYNC | NET_NACK))
+		return 1;
+
+	/* 
+	 * Multicast sequence tracking: we keep track of multicast messages
+	 * although we don't do any explicit message recovery. So, why do
+	 * we do sequence tracking? Just to let know the sysadmin.
+	 *
+	 * Let t be 1 < t < RefreshTime. To ensure consistency, conntrackd
+	 * retransmit every t seconds a message with the state of a certain
+	 * entry even if such entry did not change. This mechanism also
+	 * provides passive resynchronization, in other words, there is
+	 * no facility to request a full synchronization from new nodes that
+	 * just joined the cluster, instead they just get resynchronized in
+	 * RefreshTime seconds at worst case.
+	 */
+	mcast_track_seq(net->seq, &exp_seq);
+
+	return 0;
+}
+
+static void notrack_post_send(const struct nlnetwork *n, struct us_conntrack *u)
+{
+}
+
+struct sync_mode notrack = {
+	.internal_cache_flags	= LIFETIME,
+	.external_cache_flags	= TIMER | LIFETIME,
+	.internal_cache_extra	= &cache_notrack_extra,
+	.pre_recv 		= notrack_pre_recv,
+	.post_send		= notrack_post_send,
+};
diff --git a/daemon/src/traffic_stats.c b/daemon/src/traffic_stats.c
new file mode 100644
index 0000000..b510b77
--- /dev/null
+++ b/daemon/src/traffic_stats.c
@@ -0,0 +1,54 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cache.h"
+#include "hash.h"
+#include "conntrackd.h"
+#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include <signal.h>
+
+void update_traffic_stats(struct nf_conntrack *ct)
+{
+	STATE(bytes)[NFCT_DIR_ORIGINAL] +=
+		nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_BYTES);
+	STATE(bytes)[NFCT_DIR_REPLY] +=
+		nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_BYTES);
+	STATE(packets)[NFCT_DIR_ORIGINAL] += 
+		nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_PACKETS);
+	STATE(packets)[NFCT_DIR_REPLY] +=
+		nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_PACKETS);
+}
+
+void dump_traffic_stats(int fd)
+{
+	char buf[512];
+	int size;
+	u_int64_t bytes = STATE(bytes)[NFCT_DIR_ORIGINAL] +
+			  STATE(bytes)[NFCT_DIR_REPLY];
+	u_int64_t packets = STATE(packets)[NFCT_DIR_ORIGINAL] +
+			    STATE(packets)[NFCT_DIR_REPLY];
+
+	size = sprintf(buf, "traffic processed:\n");
+	size += sprintf(buf+size, "%20llu Bytes      ", bytes);
+	size += sprintf(buf+size, "%20llu Pckts\n\n", packets);
+
+	send(fd, buf, size, 0);
+}
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
deleted file mode 100644
index 5366ee3..0000000
--- a/extensions/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-include $(top_srcdir)/Make_global.am
-
-AM_CFLAGS=-fPIC -Wall
-LIBS=
-
-pkglib_LTLIBRARIES = ct_proto_tcp.la ct_proto_udp.la		\
-		     ct_proto_icmp.la ct_proto_sctp.la
-
-ct_proto_tcp_la_SOURCES = libct_proto_tcp.c
-ct_proto_tcp_la_LDFLAGS = -module -avoid-version
-ct_proto_udp_la_SOURCES = libct_proto_udp.c
-ct_proto_udp_la_LDFLAGS = -module -avoid-version
-ct_proto_icmp_la_SOURCES = libct_proto_icmp.c
-ct_proto_icmp_la_LDFLAGS = -module -avoid-version
-ct_proto_sctp_la_SOURCES = libct_proto_sctp.c
-ct_proto_sctp_la_LDFLAGS = -module -avoid-version
diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c
deleted file mode 100644
index e7cb04d..0000000
--- a/extensions/libct_proto_icmp.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
- *	       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 <stdlib.h>
-#include <netinet/in.h> /* For htons */
-#include <netinet/ip_icmp.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack_icmp.h>
-#include "conntrack.h"
-
-static struct option opts[] = {
-	{"icmp-type", 1, 0, '1'},
-	{"icmp-code", 1, 0, '2'},
-	{"icmp-id", 1, 0, '3'},
-	{0, 0, 0, 0}
-};
-
-static void help()
-{
-	fprintf(stdout, "--icmp-type            icmp type\n");
-	fprintf(stdout, "--icmp-code            icmp code\n");
-	fprintf(stdout, "--icmp-id              icmp id\n");
-}
-
-/* Add 1; spaces filled with 0. */
-static u_int8_t invmap[]
-	= { [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
-	    [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
-	    [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
-	    [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
-	    [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
-	    [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
-	    [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
-	    [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1};
-
-static int parse(char c, char *argv[], 
-		 struct nfct_tuple *orig,
-		 struct nfct_tuple *reply,
-		 struct nfct_tuple *exptuple,
-		 struct nfct_tuple *mask,
-		 union nfct_protoinfo *proto,
-		 unsigned int *flags)
-{
-	switch(c) {
-		case '1':
-			if (optarg) {
-				orig->l4dst.icmp.type = atoi(optarg);
-				reply->l4dst.icmp.type =
-					invmap[orig->l4dst.icmp.type] - 1;
-				*flags |= ICMP_TYPE;
-			}
-			break;
-		case '2':
-			if (optarg) {
-				orig->l4dst.icmp.code = atoi(optarg);
-				reply->l4dst.icmp.code = 0;
-				*flags |= ICMP_CODE;
-			}
-			break;
-		case '3':
-			if (optarg) {
-				orig->l4src.icmp.id = htons(atoi(optarg));
-				reply->l4dst.icmp.id = 0;
-				*flags |= ICMP_ID;
-			}
-			break;
-	}
-	return 1;
-}
-
-static int final_check(unsigned int flags,
-		       unsigned int command,
-		       struct nfct_tuple *orig,
-		       struct nfct_tuple *reply)
-{
-	if (!(flags & ICMP_TYPE))
-		return 0;
-	else if (!(flags & ICMP_CODE))
-		return 0;
-
-	return 1;
-}
-
-static struct ctproto_handler icmp = {
-	.name 		= "icmp",
-	.protonum	= IPPROTO_ICMP,
-	.parse_opts	= parse,
-	.final_check	= final_check,
-	.help		= help,
-	.opts		= opts,
-	.version	= VERSION,
-};
-
-static void __attribute__ ((constructor)) init(void);
-
-static void init(void)
-{
-	register_proto(&icmp);
-}
diff --git a/extensions/libct_proto_icmp.man b/extensions/libct_proto_icmp.man
deleted file mode 100644
index 3b860d0..0000000
--- a/extensions/libct_proto_icmp.man
+++ /dev/null
@@ -1,10 +0,0 @@
-This module matches on ICMP-specific fields.
-.TP
-.BI "--icmp-type " "TYPE"
-ICMP Type. Has to be specified numerically.
-.TP
-.BI "--icmp-code " "CODE"
-ICMP Code. Has to be specified numerically.
-.TP
-.BI "--icmp-id " "ID"
-ICMP Id. Has to be specified numerically.
diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c
deleted file mode 100644
index 1c8f0d1..0000000
--- a/extensions/libct_proto_sctp.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * (C) 2005 by Harald Welte <laforge@netfilter.org>
- *     2006 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 "conntrack.h"
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack_sctp.h>
-
-static struct option opts[] = {
-	{"orig-port-src", 1, 0, '1'},
-	{"orig-port-dst", 1, 0, '2'},
-	{"reply-port-src", 1, 0, '3'},
-	{"reply-port-dst", 1, 0, '4'},
-	{"state", 1, 0, '5'},
-	{"tuple-port-src", 1, 0, '6'},
-	{"tuple-port-dst", 1, 0, '7'},
-	{0, 0, 0, 0}
-};
-
-static const char *states[] = {
-	"NONE",
-	"CLOSED",
-	"COOKIE_WAIT",
-	"COOKIE_ECHOED",
-	"ESTABLISHED",
-	"SHUTDOWN_SENT",
-	"SHUTDOWN_RECV",
-	"SHUTDOWN_ACK_SENT",
-};
-
-static void help()
-{
-	fprintf(stdout, "--orig-port-src        original source port\n");
-	fprintf(stdout, "--orig-port-dst        original destination port\n");
-	fprintf(stdout, "--reply-port-src       reply source port\n");
-	fprintf(stdout, "--reply-port-dst       reply destination port\n");
-	fprintf(stdout, "--state                SCTP state, fe. ESTABLISHED\n");
-	fprintf(stdout, "--tuple-port-src	expectation tuple src port\n");
-	fprintf(stdout, "--tuple-port-src	expectation tuple dst port\n");
-}
-
-static int parse_options(char c, char *argv[], 
-			 struct nfct_tuple *orig,
-			 struct nfct_tuple *reply,
-			 struct nfct_tuple *exptuple,
-			 struct nfct_tuple *mask,
-			 union nfct_protoinfo *proto,
-			 unsigned int *flags)
-{
-	switch(c) {
-		case '1':
-			if (optarg) {
-				orig->l4src.sctp.port = htons(atoi(optarg));
-				*flags |= SCTP_ORIG_SPORT;
-			}
-			break;
-		case '2':
-			if (optarg) {
-				orig->l4dst.sctp.port = htons(atoi(optarg));
-				*flags |= SCTP_ORIG_DPORT;
-			}
-			break;
-		case '3':
-			if (optarg) {
-				reply->l4src.sctp.port = htons(atoi(optarg));
-				*flags |= SCTP_REPL_SPORT;
-			}
-			break;
-		case '4':
-			if (optarg) {
-				reply->l4dst.sctp.port = htons(atoi(optarg));
-				*flags |= SCTP_REPL_DPORT;
-			}
-			break;
-		case '5':
-			if (optarg) {
-				int i;
-				for (i=0; i<10; i++) {
-					if (strcmp(optarg, states[i]) == 0) {
-						/* FIXME: Add state to
-						 * nfct_protoinfo
-						proto->sctp.state = i; */
-						break;
-					}
-				}
-				if (i == 10) {
-					printf("doh?\n");
-					return 0;
-				}
-				*flags |= SCTP_STATE;
-			}
-			break;
-		case '6':
-			if (optarg) {
-				exptuple->l4src.sctp.port = htons(atoi(optarg));
-				*flags |= SCTP_EXPTUPLE_SPORT;
-			}
-			break;
-		case '7':
-			if (optarg) {
-				exptuple->l4dst.sctp.port = htons(atoi(optarg));
-				*flags |= SCTP_EXPTUPLE_DPORT;
-			}
-
-	}
-	return 1;
-}
-
-static int final_check(unsigned int flags,
-		       unsigned int command,
-		       struct nfct_tuple *orig,
-		       struct nfct_tuple *reply)
-{
-	int ret = 0;
-	
-	if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) 
-	    && !(flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) {
-		reply->l4src.sctp.port = orig->l4dst.sctp.port;
-		reply->l4dst.sctp.port = orig->l4src.sctp.port;
-		ret = 1;
-	} else if (!(flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT))
-	            && (flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) {
-		orig->l4src.sctp.port = reply->l4dst.sctp.port;
-		orig->l4dst.sctp.port = reply->l4src.sctp.port;
-		ret = 1;
-	}
-	if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) 
-	    && ((flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))))
-		ret = 1;
-
-	/* --state is missing and we are trying to create a conntrack */
-	if (ret && (command & CT_CREATE) && (!(flags & SCTP_STATE)))
-		ret = 0;
-
-	return ret;
-}
-
-static struct ctproto_handler sctp = {
-	.name 			= "sctp",
-	.protonum		= IPPROTO_SCTP,
-	.parse_opts		= parse_options,
-	.final_check		= final_check,
-	.help			= help,
-	.opts			= opts,
-	.version		= VERSION,
-};
-
-static void __attribute__ ((constructor)) init(void);
-
-static void init(void)
-{
-	register_proto(&sctp);
-}
diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c
deleted file mode 100644
index ee24206..0000000
--- a/extensions/libct_proto_tcp.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
- *
- *      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 <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
-
-#include "conntrack.h"
-
-static struct option opts[] = {
-	{"orig-port-src", 1, 0, '1'},
-	{"orig-port-dst", 1, 0, '2'},
-	{"reply-port-src", 1, 0, '3'},
-	{"reply-port-dst", 1, 0, '4'},
-	{"mask-port-src", 1, 0, '5'},
-	{"mask-port-dst", 1, 0, '6'},
-	{"state", 1, 0, '7'},
-	{"tuple-port-src", 1, 0, '8'},
-	{"tuple-port-dst", 1, 0, '9'},
-	{0, 0, 0, 0}
-};
-
-static const char *states[] = {
-	"NONE",
-	"SYN_SENT",
-	"SYN_RECV",
-	"ESTABLISHED",
-	"FIN_WAIT",
-	"CLOSE_WAIT",
-	"LAST_ACK",
-	"TIME_WAIT",
-	"CLOSE",
-	"LISTEN"
-};
-
-static void help()
-{
-	fprintf(stdout, "--orig-port-src        original source port\n");
-	fprintf(stdout, "--orig-port-dst        original destination port\n");
-	fprintf(stdout, "--reply-port-src       reply source port\n");
-	fprintf(stdout, "--reply-port-dst       reply destination port\n");
-	fprintf(stdout, "--mask-port-src	mask source port\n");
-	fprintf(stdout, "--mask-port-dst	mask destination port\n");
-	fprintf(stdout, "--tuple-port-src	expectation tuple src port\n");
-	fprintf(stdout, "--tuple-port-src	expectation tuple dst port\n");
-	fprintf(stdout, "--state                TCP state, fe. ESTABLISHED\n");
-}
-
-static int parse_options(char c, char *argv[], 
-			 struct nfct_tuple *orig,
-			 struct nfct_tuple *reply,
-			 struct nfct_tuple *exptuple,
-			 struct nfct_tuple *mask,
-			 union nfct_protoinfo *proto,
-			 unsigned int *flags)
-{
-	switch(c) {
-		case '1':
-			if (optarg) {
-				orig->l4src.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_ORIG_SPORT;
-			}
-			break;
-		case '2':
-			if (optarg) {
-				orig->l4dst.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_ORIG_DPORT;
-			}
-			break;
-		case '3':
-			if (optarg) {
-				reply->l4src.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_REPL_SPORT;
-			}
-			break;
-		case '4':
-			if (optarg) {
-				reply->l4dst.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_REPL_DPORT;
-			}
-			break;
-		case '5':
-			if (optarg) {
-				mask->l4src.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_MASK_SPORT;
-			}
-			break;
-		case '6':
-			if (optarg) {
-				mask->l4dst.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_MASK_DPORT;
-			}
-			break;
-		case '7':
-			if (optarg) {
-				int i;
-				for (i=0; i<10; i++) {
-					if (strcmp(optarg, states[i]) == 0) {
-						proto->tcp.state = i;
-						break;
-					}
-				}
-				if (i == 10) {
-					printf("doh?\n");
-					return 0;
-				}
-				*flags |= TCP_STATE;
-			}
-			break;
-		case '8':
-			if (optarg) {
-				exptuple->l4src.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_EXPTUPLE_SPORT;
-			}
-			break;
-		case '9':
-			if (optarg) {
-				exptuple->l4dst.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_EXPTUPLE_DPORT;
-			}
-			break;
-	}
-	return 1;
-}
-
-static int final_check(unsigned int flags,
-		       unsigned int command,
-		       struct nfct_tuple *orig,
-		       struct nfct_tuple *reply)
-{
-	int ret = 0;
-	
-	if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) 
-	    && !(flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) {
-		reply->l4src.tcp.port = orig->l4dst.tcp.port;
-		reply->l4dst.tcp.port = orig->l4src.tcp.port;
-		ret = 1;
-	} else if (!(flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT))
-	            && (flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) {
-		orig->l4src.tcp.port = reply->l4dst.tcp.port;
-		orig->l4dst.tcp.port = reply->l4src.tcp.port;
-		ret = 1;
-	}
-	if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) 
-	    && ((flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))))
-		ret = 1;
-
-	/* --state is missing and we are trying to create a conntrack */
-	if (ret && (command & CT_CREATE) && (!(flags & TCP_STATE)))
-		ret = 0;
-
-	return ret;
-}
-
-static struct ctproto_handler tcp = {
-	.name 			= "tcp",
-	.protonum		= IPPROTO_TCP,
-	.parse_opts		= parse_options,
-	.final_check		= final_check,
-	.help			= help,
-	.opts			= opts,
-	.version		= VERSION,
-};
-
-static void __attribute__ ((constructor)) init(void);
-
-static void init(void)
-{
-	register_proto(&tcp);
-}
diff --git a/extensions/libct_proto_tcp.man b/extensions/libct_proto_tcp.man
deleted file mode 100644
index 41783f8..0000000
--- a/extensions/libct_proto_tcp.man
+++ /dev/null
@@ -1,16 +0,0 @@
-This module matches on TCP-specific fields.
-.TP
-.BI "--orig-port-src " "PORT"
-Source port in original direction
-.TP
-.BI "--orig-port-dst " "PORT"
-Destination port in original direction
-.TP
-.BI "--reply-port-src " "PORT"
-Source port in reply direction
-.TP
-.BI "--reply-port-dst " "PORT"
-Destination port in reply direction
-.TP
-.BI "--state " "[NONE|SYN_SENT|SYN_RECV|ESTABLISHED|FIN_WAIT|CLOSE_WAIT|LAST_ACK|TIME_WAIT|CLOSE|LISTEN]"
-TCP state
diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c
deleted file mode 100644
index 48079e0..0000000
--- a/extensions/libct_proto_udp.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
- *
- *      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 <netinet/in.h> /* For htons */
-#include "conntrack.h"
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack_udp.h>
-
-static struct option opts[] = {
-	{"orig-port-src", 1, 0, '1'},
-	{"orig-port-dst", 1, 0, '2'},
-	{"reply-port-src", 1, 0, '3'},
-	{"reply-port-dst", 1, 0, '4'},
-	{"mask-port-src", 1, 0, '5'},
-	{"mask-port-dst", 1, 0, '6'},
-	{"tuple-port-src", 1, 0, '7'},
-	{"tuple-port-dst", 1, 0, '8'},
-	{0, 0, 0, 0}
-};
-
-static void help()
-{
-	fprintf(stdout, "--orig-port-src        original source port\n");
-	fprintf(stdout, "--orig-port-dst        original destination port\n");
-	fprintf(stdout, "--reply-port-src       reply source port\n");
-	fprintf(stdout, "--reply-port-dst       reply destination port\n");
-	fprintf(stdout, "--mask-port-src	mask source port\n");
-	fprintf(stdout, "--mask-port-dst	mask destination port\n");
-	fprintf(stdout, "--tuple-port-src	expectation tuple src port\n");
-	fprintf(stdout, "--tuple-port-src	expectation tuple dst port\n");
-}
-
-static int parse_options(char c, char *argv[], 
-			 struct nfct_tuple *orig,
-			 struct nfct_tuple *reply,
-			 struct nfct_tuple *exptuple,
-			 struct nfct_tuple *mask,
-			 union nfct_protoinfo *proto,
-			 unsigned int *flags)
-{
-	switch(c) {
-		case '1':
-			if (optarg) {
-				orig->l4src.udp.port = htons(atoi(optarg));
-				*flags |= UDP_ORIG_SPORT;
-			}
-			break;
-		case '2':
-			if (optarg) {
-				orig->l4dst.udp.port = htons(atoi(optarg));
-				*flags |= UDP_ORIG_DPORT;
-			}
-			break;
-		case '3':
-			if (optarg) {
-				reply->l4src.udp.port = htons(atoi(optarg));
-				*flags |= UDP_REPL_SPORT;
-			}
-			break;
-		case '4':
-			if (optarg) {
-				reply->l4dst.udp.port = htons(atoi(optarg));
-				*flags |= UDP_REPL_DPORT;
-			}
-			break;
-		case '5':
-			if (optarg) {
-				mask->l4src.udp.port = htons(atoi(optarg));
-				*flags |= UDP_MASK_SPORT;
-			}
-			break;
-		case '6':
-			if (optarg) {
-				mask->l4dst.udp.port = htons(atoi(optarg));
-				*flags |= UDP_MASK_DPORT;
-			}
-			break;
-		case '7':
-			if (optarg) {
-				exptuple->l4src.udp.port = htons(atoi(optarg));
-				*flags |= UDP_EXPTUPLE_SPORT;
-			}
-			break;
-		case '8':
-			if (optarg) {
-				exptuple->l4dst.udp.port = htons(atoi(optarg));
-				*flags |= UDP_EXPTUPLE_DPORT;
-			}
-
-	}
-	return 1;
-}
-
-static int final_check(unsigned int flags,
-		       unsigned int command,
-		       struct nfct_tuple *orig,
-		       struct nfct_tuple *reply)
-{
-	if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) 
-	    && !(flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) {
-		reply->l4src.udp.port = orig->l4dst.udp.port;
-		reply->l4dst.udp.port = orig->l4src.udp.port;
-		return 1;
-	} else if (!(flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT))
-	            && (flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) {
-		orig->l4src.udp.port = reply->l4dst.udp.port;
-		orig->l4dst.udp.port = reply->l4src.udp.port;
-		return 1;
-	}
-	if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) 
-	    && ((flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))))
-		return 1;
-
-	return 0;
-}
-
-static struct ctproto_handler udp = {
-	.name 			= "udp",
-	.protonum		= IPPROTO_UDP,
-	.parse_opts		= parse_options,
-	.final_check		= final_check,
-	.help			= help,
-	.opts			= opts,
-	.version		= VERSION,
-};
-
-static void __attribute__ ((constructor)) init(void);
-
-static void init(void)
-{
-	register_proto(&udp);
-}
diff --git a/extensions/libct_proto_udp.man b/extensions/libct_proto_udp.man
deleted file mode 100644
index c67fedf..0000000
--- a/extensions/libct_proto_udp.man
+++ /dev/null
@@ -1,13 +0,0 @@
-This module matches on UDP-specific fields.
-.TP
-.BI "--orig-port-src " "PORT"
-Source port in original direction
-.TP
-.BI "--orig-port-dst " "PORT"
-Destination port in original direction
-.TP
-.BI "--reply-port-src " "PORT"
-Source port in reply direction
-.TP
-.BI "--reply-port-dst " "PORT"
-Destination port in reply direction
diff --git a/include/Makefile.am b/include/Makefile.am
deleted file mode 100644
index ef7ce45..0000000
--- a/include/Makefile.am
+++ /dev/null
@@ -1,2 +0,0 @@
-
-noinst_HEADERS = conntrack.h linux_list.h
diff --git a/include/conntrack.h b/include/conntrack.h
deleted file mode 100644
index fb3b9b6..0000000
--- a/include/conntrack.h
+++ /dev/null
@@ -1,160 +0,0 @@
-#ifndef _CONNTRACK_H
-#define _CONNTRACK_H
-
-#ifdef HAVE_CONFIG_H
-#include "../config.h"
-#endif
-
-#include "linux_list.h"
-#include <getopt.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-
-#define PROGNAME "conntrack"
-
-#include <netinet/in.h>
-#ifndef IPPROTO_SCTP
-#define IPPROTO_SCTP 132
-#endif
-
-enum action {
-	CT_NONE		= 0,
-	
-	CT_LIST_BIT 	= 0,
-	CT_LIST 	= (1 << CT_LIST_BIT),
-	
-	CT_CREATE_BIT	= 1,
-	CT_CREATE	= (1 << CT_CREATE_BIT),
-
-	CT_UPDATE_BIT	= 2,
-	CT_UPDATE	= (1 << CT_UPDATE_BIT),
-	
-	CT_DELETE_BIT	= 3,
-	CT_DELETE	= (1 << CT_DELETE_BIT),
-	
-	CT_GET_BIT	= 4,
-	CT_GET		= (1 << CT_GET_BIT),
-
-	CT_FLUSH_BIT	= 5,
-	CT_FLUSH	= (1 << CT_FLUSH_BIT),
-
-	CT_EVENT_BIT	= 6,
-	CT_EVENT	= (1 << CT_EVENT_BIT),
-
-	CT_VERSION_BIT	= 7,
-	CT_VERSION	= (1 << CT_VERSION_BIT),
-
-	CT_HELP_BIT	= 8,
-	CT_HELP		= (1 << CT_HELP_BIT),
-
-	EXP_LIST_BIT 	= 9,
-	EXP_LIST 	= (1 << EXP_LIST_BIT),
-	
-	EXP_CREATE_BIT	= 10,
-	EXP_CREATE	= (1 << EXP_CREATE_BIT),
-	
-	EXP_DELETE_BIT	= 11,
-	EXP_DELETE	= (1 << EXP_DELETE_BIT),
-	
-	EXP_GET_BIT	= 12,
-	EXP_GET		= (1 << EXP_GET_BIT),
-
-	EXP_FLUSH_BIT	= 13,
-	EXP_FLUSH	= (1 << EXP_FLUSH_BIT),
-
-	EXP_EVENT_BIT	= 14,
-	EXP_EVENT	= (1 << EXP_EVENT_BIT),
-};
-#define NUMBER_OF_CMD   15
-
-enum options {
-	CT_OPT_ORIG_SRC_BIT	= 0,
-	CT_OPT_ORIG_SRC 	= (1 << CT_OPT_ORIG_SRC_BIT),
-	
-	CT_OPT_ORIG_DST_BIT	= 1,
-	CT_OPT_ORIG_DST		= (1 << CT_OPT_ORIG_DST_BIT),
-
-	CT_OPT_ORIG		= (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST),
-	
-	CT_OPT_REPL_SRC_BIT	= 2,
-	CT_OPT_REPL_SRC		= (1 << CT_OPT_REPL_SRC_BIT),
-	
-	CT_OPT_REPL_DST_BIT	= 3,
-	CT_OPT_REPL_DST		= (1 << CT_OPT_REPL_DST_BIT),
-
-	CT_OPT_REPL		= (CT_OPT_REPL_SRC | CT_OPT_REPL_DST),
-
-	CT_OPT_PROTO_BIT	= 4,
-	CT_OPT_PROTO		= (1 << CT_OPT_PROTO_BIT),
-
-	CT_OPT_TIMEOUT_BIT	= 5,
-	CT_OPT_TIMEOUT		= (1 << CT_OPT_TIMEOUT_BIT),
-
-	CT_OPT_STATUS_BIT	= 6,
-	CT_OPT_STATUS		= (1 << CT_OPT_STATUS_BIT),
-
-	CT_OPT_ZERO_BIT		= 7,
-	CT_OPT_ZERO		= (1 << CT_OPT_ZERO_BIT),
-
-	CT_OPT_EVENT_MASK_BIT	= 8,
-	CT_OPT_EVENT_MASK	= (1 << CT_OPT_EVENT_MASK_BIT),
-
-	CT_OPT_EXP_SRC_BIT	= 9,
-	CT_OPT_EXP_SRC		= (1 << CT_OPT_EXP_SRC_BIT),
-
-	CT_OPT_EXP_DST_BIT	= 10,
-	CT_OPT_EXP_DST		= (1 << CT_OPT_EXP_DST_BIT),
-
-	CT_OPT_MASK_SRC_BIT	= 11,
-	CT_OPT_MASK_SRC		= (1 << CT_OPT_MASK_SRC_BIT),
-
-	CT_OPT_MASK_DST_BIT	= 12,
-	CT_OPT_MASK_DST		= (1 << CT_OPT_MASK_DST_BIT),
-
-	CT_OPT_NATRANGE_BIT	= 13,
-	CT_OPT_NATRANGE		= (1 << CT_OPT_NATRANGE_BIT),
-
-	CT_OPT_MARK_BIT		= 14,
-	CT_OPT_MARK		= (1 << CT_OPT_MARK_BIT),
-
-	CT_OPT_ID_BIT		= 15,
-	CT_OPT_ID		= (1 << CT_OPT_ID_BIT),
-
-	CT_OPT_FAMILY_BIT	= 16,
-	CT_OPT_FAMILY		= (1 << CT_OPT_FAMILY_BIT),
-
-	CT_OPT_MAX_BIT		= CT_OPT_FAMILY_BIT
-};
-#define NUMBER_OF_OPT   CT_OPT_MAX_BIT+1
-
-struct ctproto_handler {
-	struct list_head 	head;
-
-	char 			*name;
-	u_int16_t 		protonum;
-	char			*version;
-
-	enum ctattr_protoinfo	protoinfo_attr;
-	
-	int (*parse_opts)(char c, char *argv[], 
-		     struct nfct_tuple *orig,
-		     struct nfct_tuple *reply,
-		     struct nfct_tuple *exptuple,
-		     struct nfct_tuple *mask,
-		     union nfct_protoinfo *proto,
-		     unsigned int *flags);
-
-	int (*final_check)(unsigned int flags,
-			   unsigned int command,
-			   struct nfct_tuple *orig,
-			   struct nfct_tuple *reply);
-
-	void (*help)();
-
-	struct option 		*opts;
-
-	unsigned int		option_offset;
-};
-
-extern void register_proto(struct ctproto_handler *h);
-
-#endif
diff --git a/include/linux_list.h b/include/linux_list.h
deleted file mode 100644
index 57b56d7..0000000
--- a/include/linux_list.h
+++ /dev/null
@@ -1,725 +0,0 @@
-#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
deleted file mode 100644
index 83cad99..0000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,7 +0,0 @@
-include $(top_srcdir)/Make_global.am
-LIBS = @CONNTRACK_LIBS@
-
-sbin_PROGRAMS = conntrack
-conntrack_SOURCES = conntrack.c
-conntrack_LDFLAGS = -rdynamic
- 
diff --git a/src/conntrack.c b/src/conntrack.c
deleted file mode 100644
index 30fbf69..0000000
--- a/src/conntrack.c
+++ /dev/null
@@ -1,1131 +0,0 @@
-/*
- * (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.
- *
- *      This program is distributed in the hope that it will be useful,
- *      but WITHOUT ANY WARRANTY; without even the implied warranty of
- *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *      GNU General Public License for more details.
- *
- *      You should have received a copy of the GNU General Public License
- *      along with this program; if not, write to the Free Software
- *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Note:
- *	Yes, portions of this code has been stolen from iptables ;)
- *	Special thanks to the the Netfilter Core Team.
- *	Thanks to Javier de Miguel Rodriguez <jmiguel at talika.eii.us.es>
- *	for introducing me to advanced firewalling stuff.
- *
- *						--pablo 13/04/2005
- *
- * 2005-04-16 Harald Welte <laforge@netfilter.org>: 
- * 	Add support for conntrack accounting and conntrack mark
- * 2005-06-23 Harald Welte <laforge@netfilter.org>:
- * 	Add support for expect creation
- * 2005-09-24 Harald Welte <laforge@netfilter.org>:
- * 	Remove remaints of "-A"
- *
- */
-#include <stdio.h>
-#include <sys/wait.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#include <fcntl.h>
-#include <dlfcn.h>
-#include <signal.h>
-#include <string.h>
-#include "linux_list.h"
-#include "conntrack.h"
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack_ipv4.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack_ipv6.h>
-
-static const char cmdflags[NUMBER_OF_CMD]
-= {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'};
-
-static const char cmd_need_param[NUMBER_OF_CMD]
-= { 2,  0,  0,  0,  0,  2,  2,  2,  2,  2,  0,  0,  0,  2,  2 };
-
-static const char optflags[NUMBER_OF_OPT]
-= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f'};
-
-static struct option original_opts[] = {
-	{"dump", 2, 0, 'L'},
-	{"create", 1, 0, 'I'},
-	{"delete", 1, 0, 'D'},
-	{"update", 1, 0, 'U'},
-	{"get", 1, 0, 'G'},
-	{"flush", 1, 0, 'F'},
-	{"event", 1, 0, 'E'},
-	{"version", 0, 0, 'V'},
-	{"help", 0, 0, 'h'},
-	{"orig-src", 1, 0, 's'},
-	{"orig-dst", 1, 0, 'd'},
-	{"reply-src", 1, 0, 'r'},
-	{"reply-dst", 1, 0, 'q'},
-	{"protonum", 1, 0, 'p'},
-	{"timeout", 1, 0, 't'},
-	{"status", 1, 0, 'u'},
-	{"zero", 0, 0, 'z'},
-	{"event-mask", 1, 0, 'e'},
-	{"tuple-src", 1, 0, '['},
-	{"tuple-dst", 1, 0, ']'},
-	{"mask-src", 1, 0, '{'},
-	{"mask-dst", 1, 0, '}'},
-	{"nat-range", 1, 0, 'a'},
-	{"mark", 1, 0, 'm'},
-	{"id", 2, 0, 'i'},
-	{"family", 1, 0, 'f'},
-	{0, 0, 0, 0}
-};
-
-#define OPTION_OFFSET 256
-
-static struct nfct_handle *cth;
-static struct option *opts = original_opts;
-static unsigned int global_option_offset = 0;
-
-/* Table of legal combinations of commands and options.  If any of the
- * given commands make an option legal, that option is legal (applies to
- * CMD_LIST and CMD_ZERO only).
- * Key:
- *  0  illegal
- *  1  compulsory
- *  2  optional
- */
-
-static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
-/* Well, it's better than "Re: Linux vs FreeBSD" */
-{
-          /*   s d r q p t u z e x y k l a m i f*/
-/*CT_LIST*/   {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2},
-/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0},
-/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0},
-/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0},
-/*CT_GET*/    {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0},
-/*CT_FLUSH*/  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*CT_EVENT*/  {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0},
-/*VERSION*/   {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*HELP*/      {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_LIST*/  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2},
-/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0},
-/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_GET*/   {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-};
-
-static char *lib_dir = CONNTRACK_LIB_DIR;
-
-static LIST_HEAD(proto_list);
-
-void register_proto(struct ctproto_handler *h)
-{
-	if (strcmp(h->version, VERSION) != 0) {
-		fprintf(stderr, "plugin `%s': version %s (I'm %s)\n",
-			h->name, h->version, VERSION);
-		exit(1);
-	}
-	list_add(&h->head, &proto_list);
-}
-
-static struct ctproto_handler *findproto(char *name)
-{
-	struct list_head *i;
-	struct ctproto_handler *cur = NULL, *handler = NULL;
-
-	if (!name) 
-		return handler;
-
-	lib_dir = getenv("CONNTRACK_LIB_DIR");
-	if (!lib_dir)
-		lib_dir = CONNTRACK_LIB_DIR;
-
-	list_for_each(i, &proto_list) {
-		cur = (struct ctproto_handler *) i;
-		if (strcmp(cur->name, name) == 0) {
-			handler = cur;
-			break;
-		}
-	}
-
-	if (!handler) {
-		char path[sizeof("ct_proto_.so")
-			 + strlen(name) + strlen(lib_dir)];
-                sprintf(path, "%s/ct_proto_%s.so", lib_dir, name);
-		if (dlopen(path, RTLD_NOW))
-			handler = findproto(name);
-		else
-			fprintf(stderr, "%s\n", dlerror());
-	}
-
-	return handler;
-}
-
-enum exittype {
-        OTHER_PROBLEM = 1,
-        PARAMETER_PROBLEM,
-        VERSION_PROBLEM
-};
-
-void extension_help(struct ctproto_handler *h)
-{
-	fprintf(stdout, "\n");
-	fprintf(stdout, "Proto `%s' help:\n", h->name);
-	h->help();
-}
-
-void
-exit_tryhelp(int status)
-{
-	fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
-			PROGNAME, PROGNAME);
-	exit(status);
-}
-
-static void
-exit_error(enum exittype status, char *msg, ...)
-{
-	va_list args;
-
-	/* On error paths, make sure that we don't leak the memory
-	 * reserved during options merging */
-	if (opts != original_opts) {
-		free(opts);
-		opts = original_opts;
-		global_option_offset = 0;
-	}
-	va_start(args, msg);
-	fprintf(stderr,"%s v%s: ", PROGNAME, VERSION);
-	vfprintf(stderr, msg, args);
-	va_end(args);
-	fprintf(stderr, "\n");
-	if (status == PARAMETER_PROBLEM)
-		exit_tryhelp(status);
-	exit(status);
-}
-
-static void
-generic_cmd_check(int command, int options)
-{
-	int i;
-	
-	for (i = 0; i < NUMBER_OF_CMD; i++) {
-		if (!(command & (1<<i)))
-			continue;
-
-		if (cmd_need_param[i] == 0 && !options)
-			exit_error(PARAMETER_PROBLEM,
-				   "You need to supply parameters to `-%c'\n",
-				   cmdflags[i]);
-	}
-}
-
-static void
-generic_opt_check(int command, int options)
-{
-	int i, j, legal = 0;
-
-	/* Check that commands are valid with options.  Complicated by the
-	 * fact that if an option is legal with *any* command given, it is
-	 * legal overall (ie. -z and -l).
-	 */
-	for (i = 0; i < NUMBER_OF_OPT; i++) {
-		legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
-
-		for (j = 0; j < NUMBER_OF_CMD; j++) {
-			if (!(command & (1<<j)))
-				continue;
-
-			if (!(options & (1<<i))) {
-				if (commands_v_options[j][i] == 1) 
-					exit_error(PARAMETER_PROBLEM, 
-						   "You need to supply the "
-						   "`-%c' option for this "
-						   "command\n", optflags[i]);
-			} else {
-				if (commands_v_options[j][i] != 0)
-					legal = 1;
-				else if (legal == 0)
-					legal = -1;
-			}
-		}
-		if (legal == -1)
-			exit_error(PARAMETER_PROBLEM, "Illegal option `-%c' "
-				   "with this command\n", optflags[i]);
-	}
-}
-
-static struct option *
-merge_options(struct option *oldopts, const struct option *newopts,
-	      unsigned int *option_offset)
-{
-	unsigned int num_old, num_new, i;
-	struct option *merge;
-
-	for (num_old = 0; oldopts[num_old].name; num_old++);
-	for (num_new = 0; newopts[num_new].name; num_new++);
-
-	global_option_offset += OPTION_OFFSET;
-	*option_offset = global_option_offset;
-
-	merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
-	memcpy(merge, oldopts, num_old * sizeof(struct option));
-	for (i = 0; i < num_new; i++) {
-		merge[num_old + i] = newopts[i];
-		merge[num_old + i].val += *option_offset;
-	}
-	memset(merge + num_old + num_new, 0, sizeof(struct option));
-
-	return merge;
-}
-
-/* From linux/errno.h */
-#define ENOTSUPP        524     /* Operation is not supported */
-
-/* Translates errno numbers into more human-readable form than strerror. */
-const char *
-err2str(int err, enum action command)
-{
-	unsigned int i;
-	struct table_struct {
-		enum action act;
-		int err;
-		const char *message;
-	} table [] =
-	  { { CT_LIST, -ENOTSUPP, "function not implemented" },
-	    { 0xFFFF, -EINVAL, "invalid parameters" },
-	    { CT_CREATE, -EEXIST, "Such conntrack exists, try -U to update" },
-	    { CT_CREATE|CT_GET|CT_DELETE, -ENOENT, 
-		    "such conntrack doesn't exist" },
-	    { CT_CREATE|CT_GET, -ENOMEM, "not enough memory" },
-	    { CT_GET, -EAFNOSUPPORT, "protocol not supported" },
-	    { CT_CREATE, -ETIME, "conntrack has expired" },
-	    { EXP_CREATE, -ENOENT, "master conntrack not found" },
-	    { EXP_CREATE, -EINVAL, "invalid parameters" },
-	    { ~0UL, -EPERM, "sorry, you must be root or get "
-		    	    "CAP_NET_ADMIN capability to do this"}
-	  };
-
-	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
-		if ((table[i].act & command) && table[i].err == err)
-			return table[i].message;
-	}
-
-	return strerror(err);
-}
-
-#define PARSE_STATUS 0
-#define PARSE_EVENT 1
-#define PARSE_MAX 2
-
-static struct parse_parameter {
-	char 	*parameter[6];
-	size_t  size;
-	unsigned int value[6];
-} parse_array[PARSE_MAX] = {
-	{ {"ASSURED", "SEEN_REPLY", "UNSET", "SRC_NAT", "DST_NAT","FIXED_TIMEOUT"}, 6,
-	  { IPS_ASSURED, IPS_SEEN_REPLY, 0, 
-	    IPS_SRC_NAT_DONE, IPS_DST_NAT_DONE, IPS_FIXED_TIMEOUT} },
-	{ {"ALL", "NEW", "UPDATES", "DESTROY"}, 4,
-	  {~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE, 
-	   NF_NETLINK_CONNTRACK_DESTROY} },
-};
-
-static int
-do_parse_parameter(const char *str, size_t strlen, unsigned int *value, 
-		   int parse_type)
-{
-	int i, ret = 0;
-	struct parse_parameter *p = &parse_array[parse_type];
-	
-	for (i = 0; i < p->size; i++)
-		if (strncasecmp(str, p->parameter[i], strlen) == 0) {
-			*value |= p->value[i];
-			ret = 1;
-			break;
-		}
-	
-	return ret;
-}
-
-static void
-parse_parameter(const char *arg, unsigned int *status, int parse_type)
-{
-	const char *comma;
-
-	while ((comma = strchr(arg, ',')) != NULL) {
-		if (comma == arg 
-		    || !do_parse_parameter(arg, comma-arg, status, parse_type))
-			exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg);
-		arg = comma+1;
-	}
-
-	if (strlen(arg) == 0
-	    || !do_parse_parameter(arg, strlen(arg), status, parse_type))
-		exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg);
-}
-
-static void
-add_command(unsigned int *cmd, const int newcmd, const int othercmds)
-{
-	if (*cmd & (~othercmds))
-		exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n");
-	*cmd |= newcmd;
-}
-
-unsigned int check_type(int argc, char *argv[])
-{
-	char *table = NULL;
-
-	/* Nasty bug or feature in getopt_long ? 
-	 * It seems that it behaves badly with optional arguments.
-	 * Fortunately, I just stole the fix from iptables ;) */
-	if (optarg)
-		return 0;
-	else if (optind < argc && argv[optind][0] != '-' 
-			&& argv[optind][0] != '!')
-		table = argv[optind++];
-	
-	if (!table)
-		return 0;
-		
-	if (strncmp("expect", table, 6) == 0)
-		return 1;
-	else if (strncmp("conntrack", table, 9) == 0)
-		return 0;
-	else
-		exit_error(PARAMETER_PROBLEM, "unknown type `%s'\n", table);
-
-	return 0;
-}
-
-static void set_family(int *family, int new)
-{
-	if (*family == AF_UNSPEC)
-		*family = new;
-	else if (*family != new)
-		exit_error(PARAMETER_PROBLEM, "mismatched address family\n");
-}
-
-struct addr_parse {
-	struct in_addr addr;
-	struct in6_addr addr6;
-	unsigned int family;
-};
-
-int __parse_inetaddr(const char *cp, struct addr_parse *parse)
-{
-	if (inet_aton(cp, &parse->addr))
-		return AF_INET;
-#ifdef HAVE_INET_PTON_IPV6
-	else if (inet_pton(AF_INET6, cp, &parse->addr6) > 0)
-		return AF_INET6;
-#endif
-
-	exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp);
-}
-
-int parse_inetaddr(const char *cp, union nfct_address *address)
-{
-	struct addr_parse parse;
-	int ret;
-	
-	if ((ret = __parse_inetaddr(cp, &parse)) == AF_INET)
-		address->v4 = parse.addr.s_addr;
-	else if (ret == AF_INET6)
-		memcpy(address->v6, &parse.addr6, sizeof(parse.addr6));
-
-	return ret;
-}
-
-/* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */
-static void
-nat_parse(char *arg, int portok, struct nfct_nat *range)
-{
-	char *colon, *dash, *error;
-	struct addr_parse parse;
-
-	memset(range, 0, sizeof(range));
-	colon = strchr(arg, ':');
-
-	if (colon) {
-		int port;
-
-		if (!portok)
-			exit_error(PARAMETER_PROBLEM,
-				   "Need TCP or UDP with port specification");
-
-		port = atoi(colon+1);
-		if (port == 0 || port > 65535)
-			exit_error(PARAMETER_PROBLEM,
-				   "Port `%s' not valid\n", colon+1);
-
-		error = strchr(colon+1, ':');
-		if (error)
-			exit_error(PARAMETER_PROBLEM,
-				   "Invalid port:port syntax - use dash\n");
-
-		dash = strchr(colon, '-');
-		if (!dash) {
-			range->l4min.tcp.port
-				= range->l4max.tcp.port
-				= htons(port);
-		} else {
-			int maxport;
-
-			maxport = atoi(dash + 1);
-			if (maxport == 0 || maxport > 65535)
-				exit_error(PARAMETER_PROBLEM,
-					   "Port `%s' not valid\n", dash+1);
-			if (maxport < port)
-				/* People are stupid.  */
-				exit_error(PARAMETER_PROBLEM,
-					   "Port range `%s' funky\n", colon+1);
-			range->l4min.tcp.port = htons(port);
-			range->l4max.tcp.port = htons(maxport);
-		}
-		/* Starts with a colon? No IP info... */
-		if (colon == arg)
-			return;
-		*colon = '\0';
-	}
-
-	dash = strchr(arg, '-');
-	if (colon && dash && dash > colon)
-		dash = NULL;
-
-	if (dash)
-		*dash = '\0';
-
-	if (__parse_inetaddr(arg, &parse) != AF_INET)
-		return;
-
-	range->min_ip = parse.addr.s_addr;
-	if (dash) {
-		if (__parse_inetaddr(dash+1, &parse) != AF_INET)
-			return;
-		range->max_ip = parse.addr.s_addr;
-	} else
-		range->max_ip = parse.addr.s_addr;
-}
-
-static void event_sighandler(int s)
-{
-	fprintf(stdout, "Now closing conntrack event dumping...\n");
-	nfct_close(cth);
-	exit(0);
-}
-
-static const char usage_commands[] =
-	"Commands:\n"
-	"  -L [table] [options]\t\tList conntrack or expectation table\n"
-	"  -G [table] parameters\t\tGet conntrack or expectation\n"
-	"  -D [table] parameters\t\tDelete conntrack or expectation\n"
-	"  -I [table] parameters\t\tCreate a conntrack or expectation\n"
-	"  -U [table] parameters\t\tUpdate a conntrack\n"
-	"  -E [table] [options]\t\tShow events\n"
-	"  -F [table]\t\t\tFlush table\n";
-
-static const char usage_tables[] =
-	"Tables: conntrack, expect\n";
-
-static const char usage_conntrack_parameters[] =
-	"Conntrack parameters and options:\n"
-	"  -a, --nat-range min_ip[-max_ip]\tNAT ip range\n"
-	"  -m, --mark mark\t\t\tSet mark\n"
-	"  -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n"
-	"  -z, --zero \t\t\t\tZero counters while listing\n"
-	;
-
-static const char usage_expectation_parameters[] =
-	"Expectation parameters and options:\n"
-	"  --tuple-src ip\tSource address in expect tuple\n"
-	"  --tuple-dst ip\tDestination address in expect tuple\n"
-	"  --mask-src ip\t\tSource mask address\n"
-	"  --mask-dst ip\t\tDestination mask address\n";
-
-static const char usage_parameters[] =
-	"Common parameters and options:\n"
-	"  -s, --orig-src ip\t\tSource address from original direction\n"
-	"  -d, --orig-dst ip\t\tDestination address from original direction\n"
-	"  -r, --reply-src ip\t\tSource addres from reply direction\n"
-	"  -q, --reply-dst ip\t\tDestination address from reply direction\n"
-	"  -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n"
-	"  -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n"
-	"  -t, --timeout timeout\t\tSet timeout\n"
-	"  -u, --status status\t\tSet status, eg. ASSURED\n"
-	"  -i, --id [id]\t\t\tShow or set conntrack ID\n"
-	;
-  
-
-void usage(char *prog) {
-	fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION);
-	fprintf(stdout, "Usage: %s [commands] [options]\n", prog);
-
-	fprintf(stdout, "\n%s", usage_commands);
-	fprintf(stdout, "\n%s", usage_tables);
-	fprintf(stdout, "\n%s", usage_conntrack_parameters);
-	fprintf(stdout, "\n%s", usage_expectation_parameters);
-	fprintf(stdout, "\n%s", usage_parameters);
-}
-
-#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK)
-
-static struct nfct_tuple orig, reply, mask;
-static struct nfct_tuple exptuple;
-static struct ctproto_handler *h;
-static union nfct_protoinfo proto;
-static struct nfct_nat range;
-static struct nfct_conntrack *ct;
-static struct nfct_expect *exp;
-static unsigned long timeout;
-static unsigned int status;
-static unsigned int mark;
-static unsigned int id = NFCT_ANY_ID;
-static struct nfct_conntrack_compare cmp;
-
-int main(int argc, char *argv[])
-{
-	int c;
-	unsigned int command = 0, options = 0;
-	unsigned int type = 0, event_mask = 0;
-	unsigned int l3flags = 0, l4flags = 0, metaflags = 0;
-	int res = 0;
-	int family = AF_UNSPEC;
-	struct nfct_conntrack_compare *pcmp;
-
-	while ((c = getopt_long(argc, argv, 
-		"L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:", 
-		opts, NULL)) != -1) {
-	switch(c) {
-		case 'L':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_LIST, CT_NONE);
-			else if (type == 1)
-				add_command(&command, EXP_LIST, CT_NONE);
-			break;
-		case 'I':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_CREATE, CT_NONE);
-			else if (type == 1)
-				add_command(&command, EXP_CREATE, CT_NONE);
-			break;
-		case 'U':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_UPDATE, CT_NONE);
-			else
-				exit_error(PARAMETER_PROBLEM, "Can't update "
-					   "expectations");
-			break;
-		case 'D':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_DELETE, CT_NONE);
-			else if (type == 1)
-				add_command(&command, EXP_DELETE, CT_NONE);
-			break;
-		case 'G':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_GET, CT_NONE);
-			else if (type == 1)
-				add_command(&command, EXP_GET, CT_NONE);
-			break;
-		case 'F':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_FLUSH, CT_NONE);
-			else if (type == 1)
-				add_command(&command, EXP_FLUSH, CT_NONE);
-			break;
-		case 'E':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_EVENT, CT_NONE);
-			else if (type == 1)
-				add_command(&command, EXP_EVENT, CT_NONE);
-			break;
-		case 'V':
-			add_command(&command, CT_VERSION, CT_NONE);
-			break;
-		case 'h':
-			add_command(&command, CT_HELP, CT_NONE);
-			break;
-		case 's':
-			options |= CT_OPT_ORIG_SRC;
-			if (optarg) {
-				orig.l3protonum =
-					parse_inetaddr(optarg, &orig.src);
-				set_family(&family, orig.l3protonum);
-				if (orig.l3protonum == AF_INET)
-					l3flags |= IPV4_ORIG_SRC;
-				else if (orig.l3protonum == AF_INET6)
-					l3flags |= IPV6_ORIG_SRC;
-			}
-			break;
-		case 'd':
-			options |= CT_OPT_ORIG_DST;
-			if (optarg) {
-				orig.l3protonum = 
-					parse_inetaddr(optarg, &orig.dst);
-				set_family(&family, orig.l3protonum);
-				if (orig.l3protonum == AF_INET)
-					l3flags |= IPV4_ORIG_DST;
-				else if (orig.l3protonum == AF_INET6)
-					l3flags |= IPV6_ORIG_DST;
-			}
-			break;
-		case 'r':
-			options |= CT_OPT_REPL_SRC;
-			if (optarg) {
-				reply.l3protonum = 
-					parse_inetaddr(optarg, &reply.src);
-				set_family(&family, reply.l3protonum);
-				if (orig.l3protonum == AF_INET)
-					l3flags |= IPV4_REPL_SRC;
-				else if (orig.l3protonum == AF_INET6)
-					l3flags |= IPV6_REPL_SRC;
-			}
-			break;
-		case 'q':
-			options |= CT_OPT_REPL_DST;
-			if (optarg) {
-				reply.l3protonum = 
-					parse_inetaddr(optarg, &reply.dst);
-				set_family(&family, reply.l3protonum);
-				if (orig.l3protonum == AF_INET)
-					l3flags |= IPV4_REPL_DST;
-				else if (orig.l3protonum == AF_INET6)
-					l3flags |= IPV6_REPL_DST;
-			}
-			break;
-		case 'p':
-			options |= CT_OPT_PROTO;
-			h = findproto(optarg);
-			if (!h)
-				exit_error(PARAMETER_PROBLEM, "proto needed\n");
-			orig.protonum = h->protonum;
-			reply.protonum = h->protonum;
-			exptuple.protonum = h->protonum;
-			mask.protonum = h->protonum;
-			opts = merge_options(opts, h->opts, 
-					     &h->option_offset);
-			break;
-		case 't':
-			options |= CT_OPT_TIMEOUT;
-			if (optarg)
-				timeout = atol(optarg);
-			break;
-		case 'u': {
-			if (!optarg)
-				continue;
-
-			options |= CT_OPT_STATUS;
-			parse_parameter(optarg, &status, PARSE_STATUS);
-			break;
-		}
-		case 'e':
-			options |= CT_OPT_EVENT_MASK;
-			parse_parameter(optarg, &event_mask, PARSE_EVENT);
-			break;
-		case 'z':
-			options |= CT_OPT_ZERO;
-			break;
-		case '{':
-			options |= CT_OPT_MASK_SRC;
-			if (optarg) {
-				mask.l3protonum = 
-					parse_inetaddr(optarg, &mask.src);
-				set_family(&family, mask.l3protonum);
-			}
-			break;
-		case '}':
-			options |= CT_OPT_MASK_DST;
-			if (optarg) {
-				mask.l3protonum = 
-					parse_inetaddr(optarg, &mask.dst);
-				set_family(&family, mask.l3protonum);
-			}
-			break;
-		case '[':
-			options |= CT_OPT_EXP_SRC;
-			if (optarg) {
-				exptuple.l3protonum = 
-					parse_inetaddr(optarg, &exptuple.src);
-				set_family(&family, exptuple.l3protonum);
-			}
-			break;
-		case ']':
-			options |= CT_OPT_EXP_DST;
-			if (optarg) {
-				exptuple.l3protonum = 
-					parse_inetaddr(optarg, &exptuple.dst);
-				set_family(&family, exptuple.l3protonum);
-			}
-			break;
-		case 'a':
-			options |= CT_OPT_NATRANGE;
-			set_family(&family, AF_INET);
-			nat_parse(optarg, 1, &range);
-			break;
-		case 'm':
-			options |= CT_OPT_MARK;
-			mark = atol(optarg);
-			metaflags |= NFCT_MARK;
-			break;
-		case 'i': {
-			char *s = NULL;
-			options |= CT_OPT_ID;
-			if (optarg)
-				break;
-			else if (optind < argc && argv[optind][0] != '-'
-					&& argv[optind][0] != '!')
-				s = argv[optind++];
-
-			if (s)
-				id = atol(s);
-			break;
-		}
-		case 'f':
-			options |= CT_OPT_FAMILY;
-			if (strncmp(optarg, "ipv4", strlen("ipv4")) == 0)
-				set_family(&family, AF_INET);
-			else if (strncmp(optarg, "ipv6", strlen("ipv6")) == 0)
-				set_family(&family, AF_INET6);
-			else
-				exit_error(PARAMETER_PROBLEM, "Unknown "
-					   "protocol family\n");
-			break;
-		default:
-			if (h && h->parse_opts 
-			    &&!h->parse_opts(c - h->option_offset, argv, &orig, 
-				             &reply, &exptuple, &mask, &proto, 
-					     &l4flags))
-				exit_error(PARAMETER_PROBLEM, "parse error\n");
-
-			/* Unknown argument... */
-			if (!h) {
-				usage(argv[0]);
-				exit_error(PARAMETER_PROBLEM, "Missing "
-					   "arguments...\n");
-			}
-			break;
-		}
-	}
-
-	/* default family */
-	if (family == AF_UNSPEC)
-		family = AF_INET;
-
-	generic_cmd_check(command, options);
-	generic_opt_check(command, options);
-
-	if (!(command & CT_HELP)
-	    && h && h->final_check 
-	    && !h->final_check(l4flags, command, &orig, &reply)) {
-		usage(argv[0]);
-		extension_help(h);
-		exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n");
-	}
-
-	switch(command) {
-
-	case CT_LIST:
-		cth = nfct_open(CONNTRACK, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-
-		if (options & CT_COMPARISON) {
-
-			if (options & CT_OPT_ZERO)
-				exit_error(PARAMETER_PROBLEM, "Can't use -z "
-					   "with filtering parameters");
-
-			ct = nfct_conntrack_alloc(&orig, &reply, timeout,
-						  &proto, status, mark, id,
-						  NULL);
-			if (!ct)
-				exit_error(OTHER_PROBLEM, "Not enough memory");
-			
-			cmp.ct = ct;
-			cmp.flags = metaflags;
-			cmp.l3flags = l3flags;
-			cmp.l4flags = l4flags;
-			pcmp = &cmp;
-		}
-
-		if (options & CT_OPT_ID)
-			nfct_register_callback(cth, 
-					nfct_default_conntrack_display_id,
-					(void *) pcmp);
-		else
-			nfct_register_callback(cth,
-					nfct_default_conntrack_display,
-					(void *) pcmp);
-			
-		if (options & CT_OPT_ZERO)
-			res = 
-			nfct_dump_conntrack_table_reset_counters(cth, family);
-		else
-			res = nfct_dump_conntrack_table(cth, family);
-		nfct_close(cth);
-		break;
-
-	case EXP_LIST:
-		cth = nfct_open(EXPECT, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		if (options & CT_OPT_ID)
-			nfct_register_callback(cth, 
-					nfct_default_expect_display_id,
-					NULL);
-		else
-			nfct_register_callback(cth,
-					nfct_default_expect_display,
-					NULL);
-		res = nfct_dump_expect_list(cth, family);
-		nfct_close(cth);
-		break;
-			
-	case CT_CREATE:
-		if ((options & CT_OPT_ORIG) 
-		    && !(options & CT_OPT_REPL)) {
-			reply.l3protonum = orig.l3protonum;
-			memcpy(&reply.src, &orig.dst, sizeof(reply.src));
-			memcpy(&reply.dst, &orig.src, sizeof(reply.dst));
-		} else if (!(options & CT_OPT_ORIG)
-			   && (options & CT_OPT_REPL)) {
-			orig.l3protonum = reply.l3protonum;
-			memcpy(&orig.src, &reply.dst, sizeof(orig.src));
-			memcpy(&orig.dst, &reply.src, sizeof(orig.dst));
-		}
-		if (options & CT_OPT_NATRANGE)
-			ct = nfct_conntrack_alloc(&orig, &reply, timeout, 
-						  &proto, status, mark, id,
-						  &range);
-		else
-			ct = nfct_conntrack_alloc(&orig, &reply, timeout, 
-						  &proto, status, mark, id,
-						  NULL);
-		if (!ct)
-			exit_error(OTHER_PROBLEM, "Not Enough memory");
-		
-		cth = nfct_open(CONNTRACK, 0);
-		if (!cth) {
-			nfct_conntrack_free(ct);
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		}
-		res = nfct_create_conntrack(cth, ct);
-		nfct_close(cth);
-		nfct_conntrack_free(ct);
-		break;
-
-	case EXP_CREATE:
-		if (options & CT_OPT_ORIG)
-			exp = nfct_expect_alloc(&orig, &exptuple,
-						&mask, timeout, id);
-		else if (options & CT_OPT_REPL)
-			exp = nfct_expect_alloc(&reply, &exptuple,
-						&mask, timeout, id);
-		if (!exp)
-			exit_error(OTHER_PROBLEM, "Not enough memory");
-
-		cth = nfct_open(EXPECT, 0);
-		if (!cth) {
-			nfct_expect_free(exp);
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		}
-		res = nfct_create_expectation(cth, exp);
-		nfct_expect_free(exp);
-		nfct_close(cth);
-		break;
-
-	case CT_UPDATE:
-		if ((options & CT_OPT_ORIG) 
-		    && !(options & CT_OPT_REPL)) {
-			reply.l3protonum = orig.l3protonum;
-			memcpy(&reply.src, &orig.dst, sizeof(reply.src));
-			memcpy(&reply.dst, &orig.src, sizeof(reply.dst));
-		} else if (!(options & CT_OPT_ORIG)
-			   && (options & CT_OPT_REPL)) {
-			orig.l3protonum = reply.l3protonum;
-			memcpy(&orig.src, &reply.dst, sizeof(orig.src));
-			memcpy(&orig.dst, &reply.src, sizeof(orig.dst));
-		}
-		ct = nfct_conntrack_alloc(&orig, &reply, timeout,
-					  &proto, status, mark, id,
-					  NULL);
-		if (!ct)
-			exit_error(OTHER_PROBLEM, "Not enough memory");
-		
-		cth = nfct_open(CONNTRACK, 0);
-		if (!cth) {
-			nfct_conntrack_free(ct);
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		}
-		res = nfct_update_conntrack(cth, ct);
-		nfct_conntrack_free(ct);
-		nfct_close(cth);
-		break;
-		
-	case CT_DELETE:
-		if (!(options & CT_OPT_ORIG) && !(options & CT_OPT_REPL))
-			exit_error(PARAMETER_PROBLEM, "Can't kill conntracks "
-						      "just by its ID");
-		cth = nfct_open(CONNTRACK, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		if (options & CT_OPT_ORIG)
-			res = nfct_delete_conntrack(cth, &orig, 
-						    NFCT_DIR_ORIGINAL,
-						    id);
-		else if (options & CT_OPT_REPL)
-			res = nfct_delete_conntrack(cth, &reply, 
-						    NFCT_DIR_REPLY,
-						    id);
-		nfct_close(cth);
-		break;
-
-	case EXP_DELETE:
-		cth = nfct_open(EXPECT, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		if (options & CT_OPT_ORIG)
-			res = nfct_delete_expectation(cth, &orig, id);
-		else if (options & CT_OPT_REPL)
-			res = nfct_delete_expectation(cth, &reply, id);
-		nfct_close(cth);
-		break;
-
-	case CT_GET:
-		cth = nfct_open(CONNTRACK, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		nfct_register_callback(cth, nfct_default_conntrack_display,
-					NULL);
-		if (options & CT_OPT_ORIG)
-			res = nfct_get_conntrack(cth, &orig,
-						 NFCT_DIR_ORIGINAL, id);
-		else if (options & CT_OPT_REPL)
-			res = nfct_get_conntrack(cth, &reply,
-						 NFCT_DIR_REPLY, id);
-		nfct_close(cth);
-		break;
-
-	case EXP_GET:
-		cth = nfct_open(EXPECT, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		nfct_register_callback(cth, nfct_default_expect_display,
-					NULL);
-		if (options & CT_OPT_ORIG)
-			res = nfct_get_expectation(cth, &orig, id);
-		else if (options & CT_OPT_REPL)
-			res = nfct_get_expectation(cth, &reply, id);
-		nfct_close(cth);
-		break;
-
-	case CT_FLUSH:
-		cth = nfct_open(CONNTRACK, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		res = nfct_flush_conntrack_table(cth, AF_INET);
-		nfct_close(cth);
-		break;
-
-	case EXP_FLUSH:
-		cth = nfct_open(EXPECT, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		res = nfct_flush_expectation_table(cth, AF_INET);
-		nfct_close(cth);
-		break;
-		
-	case CT_EVENT:
-		if (options & CT_OPT_EVENT_MASK)
-			cth = nfct_open(CONNTRACK, event_mask);
-		else
-			cth = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS);
-
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		signal(SIGINT, event_sighandler);
-
-		if (options & CT_COMPARISON) {
-			ct = nfct_conntrack_alloc(&orig, &reply, timeout,
-						  &proto, status, mark, id, 
-						  NULL);
-			if (!ct)
-				exit_error(OTHER_PROBLEM, "Not enough memory");
-
-			cmp.ct = ct;
-			cmp.flags = metaflags;
-			cmp.l3flags = l3flags;
-			cmp.l4flags = l4flags;
-			pcmp = &cmp;
-		}
-
-		nfct_register_callback(cth,
-				       nfct_default_conntrack_event_display, 
-				       (void *) pcmp);
-		res = nfct_event_conntrack(cth);
-		nfct_close(cth);
-		break;
-
-	case EXP_EVENT:
-		cth = nfct_open(EXPECT, NF_NETLINK_CONNTRACK_EXP_NEW);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		signal(SIGINT, event_sighandler);
-		nfct_register_callback(cth, nfct_default_expect_display,
-					NULL);
-		res = nfct_event_expectation(cth);
-		nfct_close(cth);
-		break;
-			
-	case CT_VERSION:
-		fprintf(stdout, "%s v%s\n", PROGNAME, VERSION);
-		break;
-	case CT_HELP:
-		usage(argv[0]);
-		if (options & CT_OPT_PROTO)
-			extension_help(h);
-		break;
-	default:
-		usage(argv[0]);
-		break;
-	}
-
-	if (opts != original_opts) {
-		free(opts);
-		opts = original_opts;
-		global_option_offset = 0;
-	}
-
-	if (res < 0) {
-		fprintf(stderr, "Operation failed: %s\n", err2str(res, command));
-		exit(OTHER_PROBLEM);
-	}
-
-	return 0;
-}
diff --git a/test.sh b/test.sh
deleted file mode 100644
index 4694236..0000000
--- a/test.sh
+++ /dev/null
@@ -1,110 +0,0 @@
-CONNTRACK=conntrack
-
-SRC=1.1.1.1
-DST=2.2.2.2
-SPORT=2005
-DPORT=21
-
-case $1 in
-	dump)
-		echo "Dumping conntrack table"
-		$CONNTRACK -L
-		;;
-	flush)
-		echo "Flushing conntrack table"
-		$CONNTRACK -F
-		;;
-	new)
-		echo "creating a new conntrack"
-		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
-		 --reply-src $DST --reply-dst $SRC -p tcp \
-		 --orig-port-src $SPORT  --orig-port-dst $DPORT \
-		 --reply-port-src $DPORT --reply-port-dst $SPORT \
-		--state LISTEN -u SEEN_REPLY -t 50
-		;;
-	new-simple)
-		echo "creating a new conntrack (simplified)"
-		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
-		-p tcp --orig-port-src $SPORT  --orig-port-dst $DPORT \
-		--state LISTEN -u SEEN_REPLY -t 50
-		;;
-	new-nat)
-		echo "creating a new conntrack (NAT)"
-		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
-		-p tcp --orig-port-src $SPORT  --orig-port-dst $DPORT \
-		--state LISTEN -u SEEN_REPLY,SRC_NAT -t 50 -a 8.8.8.8
-		;;
-	get)
-		echo "getting a conntrack"
-		$CONNTRACK -G --orig-src $SRC --orig-dst $DST \
-		-p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \
-		--reply-port-src $DPORT --reply-port-dst $SPORT
-		;;
-	change)
-		echo "change a conntrack"
-		$CONNTRACK -U --orig-src $SRC --orig-dst $DST \
-		--reply-src $DST --reply-dst $SRC -p tcp \
-		--orig-port-src $SPORT --orig-port-dst $DPORT \
-		--reply-port-src $DPORT --reply-port-dst $SPORT \
-		--state TIME_WAIT -u ASSURED,SEEN_REPLY -t 500
-		;;
-	delete)
-		$CONNTRACK -D --orig-src $SRC --orig-dst $DST \
-		-p tcp --orig-port-src $SPORT --orig-port-dst $DPORT
-		;;
-	output)
-		proc=$(cat /proc/net/ip_conntrack | wc -l)
-		netl=$($CONNTRACK -L | wc -l)
-		count=$(cat /proc/sys/net/ipv4/netfilter/ip_conntrack_count)
-		if [ $proc -ne $netl ]; then
-			echo "proc is $proc and netl is $netl and count is $count"
-		else
-			if [ $proc -ne $count ]; then
-				echo "proc is $proc and netl is $netl and count is $count"
-			else
-				echo "now $proc"
-			fi
-		fi
-		;;
-	dump-expect)
-		$CONNTRACK -L expect
-		;;
-	flush-expect)
-		$CONNTRACK -F expect
-		;;
-	create-expect)
-		# requires modprobe ip_conntrack_ftp
-		$CONNTRACK -I expect --orig-src $SRC --orig-dst $DST \
-		--tuple-src 4.4.4.4 --tuple-dst 5.5.5.5 \
-		--mask-src 255.255.255.0 --mask-dst 255.255.255.255 \
-		-p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \
-		-t 200 --tuple-port-src 10 --tuple-port-dst 300 \
-		--mask-port-src 10 --mask-port-dst 300
-		;;
-	get-expect)
-		$CONNTRACK -G expect --orig-src 4.4.4.4 --orig-dst 5.5.5.5 \
-		--p tcp --orig-port-src 0 --orig-port-dst 0 \
-		--mask-port-src 10 --mask-port-dst 11
-		;;
-	delete-expect)
-		$CONNTRACK -D expect --orig-src 4.4.4.4 \
-		--orig-dst 5.5.5.5 -p tcp --orig-port-src 0 \
-		--orig-port-dst 0 --mask-port-src 10 --mask-port-dst 11
-		;;
-	*)
-		echo "Usage: $0 [dump"
-		echo "		|new"
-		echo "		|new-simple"
-		echo "		|new-nat"
-		echo "		|get"
-		echo "		|change"
-		echo "		|delete"
-		echo "		|output"
-		echo "		|flush"
-		echo "		|dump-expect"
-		echo "		|flush-expect"
-		echo "		|create-expect"
-		echo "		|get-expect"
-		echo "		|delete-expect]"
-		;;
-esac
-- 
cgit v1.2.3


From 5eb3bc6d5594fccfff26329a26225f999e971652 Mon Sep 17 00:00:00 2001
From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org"
 </C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org>
Date: Mon, 16 Apr 2007 19:08:42 +0000
Subject: first step forward to merge conntrackd and conntrack into the same
 building chain

---
 AUTHORS                                            |    1 +
 CHANGELOG                                          |  184 ++++
 CONTRIBUTORS                                       |    3 +
 ChangeLog                                          |  243 +++++
 INSTALL                                            |  199 ++++
 Make_global.am                                     |    1 +
 Makefile.am                                        |   21 +
 TODO                                               |   18 +
 autogen.sh                                         |   18 +
 cli/ChangeLog                                      |  243 -----
 cli/conntrack.8                                    |  142 ---
 cli/extensions/Makefile.am                         |   16 -
 cli/extensions/libct_proto_icmp.c                  |  108 --
 cli/extensions/libct_proto_icmp.man                |   10 -
 cli/extensions/libct_proto_sctp.c                  |  164 ---
 cli/extensions/libct_proto_tcp.c                   |  180 ----
 cli/extensions/libct_proto_tcp.man                 |   16 -
 cli/extensions/libct_proto_udp.c                   |  141 ---
 cli/extensions/libct_proto_udp.man                 |   13 -
 cli/include/conntrack.h                            |  160 ---
 cli/src/conntrack.c                                | 1131 --------------------
 cli/test.sh                                        |  110 --
 configure.in                                       |  106 ++
 conntrack.8                                        |  142 +++
 daemon/AUTHORS                                     |    1 -
 daemon/CHANGELOG                                   |  184 ----
 daemon/CONTRIBUTORS                                |    3 -
 daemon/INSTALL                                     |  199 ----
 daemon/Make_global.am                              |    1 -
 daemon/Makefile.am                                 |   21 -
 daemon/TODO                                        |   18 -
 daemon/autogen.sh                                  |   18 -
 daemon/configure.in                                |  106 --
 daemon/examples/Makefile.am                        |    1 -
 daemon/examples/debian.conntrackd.init.d           |   48 -
 daemon/examples/stats/Makefile.am                  |    1 -
 daemon/examples/stats/conntrackd.conf              |   69 --
 daemon/examples/sync/Makefile.am                   |    1 -
 daemon/examples/sync/nack/Makefile.am              |    2 -
 daemon/examples/sync/nack/README                   |    1 -
 daemon/examples/sync/nack/node1/Makefile.am        |    1 -
 daemon/examples/sync/nack/node1/conntrackd.conf    |  125 ---
 daemon/examples/sync/nack/node1/keepalived.conf    |   38 -
 daemon/examples/sync/nack/node2/Makefile.am        |    1 -
 daemon/examples/sync/nack/node2/conntrackd.conf    |  124 ---
 daemon/examples/sync/nack/node2/keepalived.conf    |   38 -
 daemon/examples/sync/nack/script_backup.sh         |    3 -
 daemon/examples/sync/nack/script_master.sh         |    5 -
 daemon/examples/sync/persistent/Makefile.am        |    2 -
 daemon/examples/sync/persistent/README             |    1 -
 daemon/examples/sync/persistent/node1/Makefile.am  |    1 -
 .../examples/sync/persistent/node1/conntrackd.conf |  130 ---
 .../examples/sync/persistent/node1/keepalived.conf |   38 -
 daemon/examples/sync/persistent/node2/Makefile.am  |    1 -
 .../examples/sync/persistent/node2/conntrackd.conf |  130 ---
 .../examples/sync/persistent/node2/keepalived.conf |   38 -
 daemon/examples/sync/persistent/script_backup.sh   |    3 -
 daemon/examples/sync/persistent/script_master.sh   |    4 -
 daemon/include/Makefile.am                         |    5 -
 daemon/include/alarm.h                             |   13 -
 daemon/include/buffer.h                            |   32 -
 daemon/include/cache.h                             |   92 --
 daemon/include/conntrackd.h                        |  174 ---
 daemon/include/debug.h                             |   53 -
 daemon/include/hash.h                              |   47 -
 daemon/include/ignore.h                            |   12 -
 daemon/include/jhash.h                             |  146 ---
 daemon/include/linux_list.h                        |  725 -------------
 daemon/include/local.h                             |   29 -
 daemon/include/log.h                               |   10 -
 daemon/include/mcast.h                             |   48 -
 daemon/include/network.h                           |   34 -
 daemon/include/slist.h                             |   41 -
 daemon/include/state_helper.h                      |   20 -
 daemon/include/sync.h                              |   23 -
 daemon/include/us-conntrack.h                      |   13 -
 daemon/src/Makefile.am                             |   22 -
 daemon/src/alarm.c                                 |  141 ---
 daemon/src/buffer.c                                |  136 ---
 daemon/src/cache.c                                 |  446 --------
 daemon/src/cache_iterators.c                       |  229 ----
 daemon/src/cache_lifetime.c                        |   65 --
 daemon/src/cache_timer.c                           |   72 --
 daemon/src/checksum.c                              |   32 -
 daemon/src/hash.c                                  |  199 ----
 daemon/src/ignore_pool.c                           |  136 ---
 daemon/src/local.c                                 |  159 ---
 daemon/src/lock.c                                  |   32 -
 daemon/src/log.c                                   |   57 -
 daemon/src/main.c                                  |  302 ------
 daemon/src/mcast.c                                 |  287 -----
 daemon/src/netlink.c                               |  326 ------
 daemon/src/network.c                               |  282 -----
 daemon/src/proxy.c                                 |  124 ---
 daemon/src/read_config_lex.l                       |  125 ---
 daemon/src/read_config_yy.y                        |  550 ----------
 daemon/src/run.c                                   |  227 ----
 daemon/src/state_helper.c                          |   44 -
 daemon/src/state_helper_tcp.c                      |   35 -
 daemon/src/stats-mode.c                            |  151 ---
 daemon/src/sync-mode.c                             |  416 -------
 daemon/src/sync-nack.c                             |  309 ------
 daemon/src/sync-notrack.c                          |  127 ---
 daemon/src/traffic_stats.c                         |   54 -
 examples/Makefile.am                               |    1 +
 examples/debian.conntrackd.init.d                  |   48 +
 examples/stats/Makefile.am                         |    1 +
 examples/stats/conntrackd.conf                     |   69 ++
 examples/sync/Makefile.am                          |    1 +
 examples/sync/nack/Makefile.am                     |    2 +
 examples/sync/nack/README                          |    1 +
 examples/sync/nack/node1/Makefile.am               |    1 +
 examples/sync/nack/node1/conntrackd.conf           |  125 +++
 examples/sync/nack/node1/keepalived.conf           |   38 +
 examples/sync/nack/node2/Makefile.am               |    1 +
 examples/sync/nack/node2/conntrackd.conf           |  124 +++
 examples/sync/nack/node2/keepalived.conf           |   38 +
 examples/sync/nack/script_backup.sh                |    3 +
 examples/sync/nack/script_master.sh                |    5 +
 examples/sync/persistent/Makefile.am               |    2 +
 examples/sync/persistent/README                    |    1 +
 examples/sync/persistent/node1/Makefile.am         |    1 +
 examples/sync/persistent/node1/conntrackd.conf     |  130 +++
 examples/sync/persistent/node1/keepalived.conf     |   38 +
 examples/sync/persistent/node2/Makefile.am         |    1 +
 examples/sync/persistent/node2/conntrackd.conf     |  130 +++
 examples/sync/persistent/node2/keepalived.conf     |   38 +
 examples/sync/persistent/script_backup.sh          |    3 +
 examples/sync/persistent/script_master.sh          |    4 +
 extensions/Makefile.am                             |   16 +
 extensions/libct_proto_icmp.c                      |  108 ++
 extensions/libct_proto_icmp.man                    |   10 +
 extensions/libct_proto_sctp.c                      |  164 +++
 extensions/libct_proto_tcp.c                       |  180 ++++
 extensions/libct_proto_tcp.man                     |   16 +
 extensions/libct_proto_udp.c                       |  141 +++
 extensions/libct_proto_udp.man                     |   13 +
 include/Makefile.am                                |    5 +
 include/alarm.h                                    |   13 +
 include/buffer.h                                   |   32 +
 include/cache.h                                    |   92 ++
 include/conntrack.h                                |  160 +++
 include/conntrackd.h                               |  174 +++
 include/debug.h                                    |   53 +
 include/hash.h                                     |   47 +
 include/ignore.h                                   |   12 +
 include/jhash.h                                    |  146 +++
 include/linux_list.h                               |  725 +++++++++++++
 include/local.h                                    |   29 +
 include/log.h                                      |   10 +
 include/mcast.h                                    |   48 +
 include/network.h                                  |   34 +
 include/slist.h                                    |   41 +
 include/state_helper.h                             |   20 +
 include/sync.h                                     |   23 +
 include/us-conntrack.h                             |   13 +
 src/Makefile.am                                    |   26 +
 src/alarm.c                                        |  141 +++
 src/buffer.c                                       |  136 +++
 src/cache.c                                        |  446 ++++++++
 src/cache_iterators.c                              |  229 ++++
 src/cache_lifetime.c                               |   65 ++
 src/cache_timer.c                                  |   72 ++
 src/checksum.c                                     |   32 +
 src/conntrack.c                                    | 1131 ++++++++++++++++++++
 src/hash.c                                         |  199 ++++
 src/ignore_pool.c                                  |  136 +++
 src/local.c                                        |  159 +++
 src/lock.c                                         |   32 +
 src/log.c                                          |   57 +
 src/main.c                                         |  302 ++++++
 src/mcast.c                                        |  287 +++++
 src/netlink.c                                      |  326 ++++++
 src/network.c                                      |  282 +++++
 src/proxy.c                                        |  124 +++
 src/read_config_lex.l                              |  125 +++
 src/read_config_yy.y                               |  550 ++++++++++
 src/run.c                                          |  227 ++++
 src/state_helper.c                                 |   44 +
 src/state_helper_tcp.c                             |   35 +
 src/stats-mode.c                                   |  151 +++
 src/sync-mode.c                                    |  416 +++++++
 src/sync-nack.c                                    |  309 ++++++
 src/sync-notrack.c                                 |  127 +++
 src/traffic_stats.c                                |   54 +
 test.sh                                            |  110 ++
 186 files changed, 10397 insertions(+), 10393 deletions(-)
 create mode 100644 AUTHORS
 create mode 100644 CHANGELOG
 create mode 100644 CONTRIBUTORS
 create mode 100644 ChangeLog
 create mode 100644 INSTALL
 create mode 100644 Make_global.am
 create mode 100644 Makefile.am
 create mode 100644 TODO
 create mode 100755 autogen.sh
 delete mode 100644 cli/ChangeLog
 delete mode 100644 cli/conntrack.8
 delete mode 100644 cli/extensions/Makefile.am
 delete mode 100644 cli/extensions/libct_proto_icmp.c
 delete mode 100644 cli/extensions/libct_proto_icmp.man
 delete mode 100644 cli/extensions/libct_proto_sctp.c
 delete mode 100644 cli/extensions/libct_proto_tcp.c
 delete mode 100644 cli/extensions/libct_proto_tcp.man
 delete mode 100644 cli/extensions/libct_proto_udp.c
 delete mode 100644 cli/extensions/libct_proto_udp.man
 delete mode 100644 cli/include/conntrack.h
 delete mode 100644 cli/src/conntrack.c
 delete mode 100644 cli/test.sh
 create mode 100644 configure.in
 create mode 100644 conntrack.8
 delete mode 100644 daemon/AUTHORS
 delete mode 100644 daemon/CHANGELOG
 delete mode 100644 daemon/CONTRIBUTORS
 delete mode 100644 daemon/INSTALL
 delete mode 100644 daemon/Make_global.am
 delete mode 100644 daemon/Makefile.am
 delete mode 100644 daemon/TODO
 delete mode 100755 daemon/autogen.sh
 delete mode 100644 daemon/configure.in
 delete mode 100644 daemon/examples/Makefile.am
 delete mode 100644 daemon/examples/debian.conntrackd.init.d
 delete mode 100644 daemon/examples/stats/Makefile.am
 delete mode 100644 daemon/examples/stats/conntrackd.conf
 delete mode 100644 daemon/examples/sync/Makefile.am
 delete mode 100644 daemon/examples/sync/nack/Makefile.am
 delete mode 100644 daemon/examples/sync/nack/README
 delete mode 100644 daemon/examples/sync/nack/node1/Makefile.am
 delete mode 100644 daemon/examples/sync/nack/node1/conntrackd.conf
 delete mode 100644 daemon/examples/sync/nack/node1/keepalived.conf
 delete mode 100644 daemon/examples/sync/nack/node2/Makefile.am
 delete mode 100644 daemon/examples/sync/nack/node2/conntrackd.conf
 delete mode 100644 daemon/examples/sync/nack/node2/keepalived.conf
 delete mode 100755 daemon/examples/sync/nack/script_backup.sh
 delete mode 100755 daemon/examples/sync/nack/script_master.sh
 delete mode 100644 daemon/examples/sync/persistent/Makefile.am
 delete mode 100644 daemon/examples/sync/persistent/README
 delete mode 100644 daemon/examples/sync/persistent/node1/Makefile.am
 delete mode 100644 daemon/examples/sync/persistent/node1/conntrackd.conf
 delete mode 100644 daemon/examples/sync/persistent/node1/keepalived.conf
 delete mode 100644 daemon/examples/sync/persistent/node2/Makefile.am
 delete mode 100644 daemon/examples/sync/persistent/node2/conntrackd.conf
 delete mode 100644 daemon/examples/sync/persistent/node2/keepalived.conf
 delete mode 100755 daemon/examples/sync/persistent/script_backup.sh
 delete mode 100755 daemon/examples/sync/persistent/script_master.sh
 delete mode 100644 daemon/include/Makefile.am
 delete mode 100644 daemon/include/alarm.h
 delete mode 100644 daemon/include/buffer.h
 delete mode 100644 daemon/include/cache.h
 delete mode 100644 daemon/include/conntrackd.h
 delete mode 100644 daemon/include/debug.h
 delete mode 100644 daemon/include/hash.h
 delete mode 100644 daemon/include/ignore.h
 delete mode 100644 daemon/include/jhash.h
 delete mode 100644 daemon/include/linux_list.h
 delete mode 100644 daemon/include/local.h
 delete mode 100644 daemon/include/log.h
 delete mode 100644 daemon/include/mcast.h
 delete mode 100644 daemon/include/network.h
 delete mode 100644 daemon/include/slist.h
 delete mode 100644 daemon/include/state_helper.h
 delete mode 100644 daemon/include/sync.h
 delete mode 100644 daemon/include/us-conntrack.h
 delete mode 100644 daemon/src/Makefile.am
 delete mode 100644 daemon/src/alarm.c
 delete mode 100644 daemon/src/buffer.c
 delete mode 100644 daemon/src/cache.c
 delete mode 100644 daemon/src/cache_iterators.c
 delete mode 100644 daemon/src/cache_lifetime.c
 delete mode 100644 daemon/src/cache_timer.c
 delete mode 100644 daemon/src/checksum.c
 delete mode 100644 daemon/src/hash.c
 delete mode 100644 daemon/src/ignore_pool.c
 delete mode 100644 daemon/src/local.c
 delete mode 100644 daemon/src/lock.c
 delete mode 100644 daemon/src/log.c
 delete mode 100644 daemon/src/main.c
 delete mode 100644 daemon/src/mcast.c
 delete mode 100644 daemon/src/netlink.c
 delete mode 100644 daemon/src/network.c
 delete mode 100644 daemon/src/proxy.c
 delete mode 100644 daemon/src/read_config_lex.l
 delete mode 100644 daemon/src/read_config_yy.y
 delete mode 100644 daemon/src/run.c
 delete mode 100644 daemon/src/state_helper.c
 delete mode 100644 daemon/src/state_helper_tcp.c
 delete mode 100644 daemon/src/stats-mode.c
 delete mode 100644 daemon/src/sync-mode.c
 delete mode 100644 daemon/src/sync-nack.c
 delete mode 100644 daemon/src/sync-notrack.c
 delete mode 100644 daemon/src/traffic_stats.c
 create mode 100644 examples/Makefile.am
 create mode 100644 examples/debian.conntrackd.init.d
 create mode 100644 examples/stats/Makefile.am
 create mode 100644 examples/stats/conntrackd.conf
 create mode 100644 examples/sync/Makefile.am
 create mode 100644 examples/sync/nack/Makefile.am
 create mode 100644 examples/sync/nack/README
 create mode 100644 examples/sync/nack/node1/Makefile.am
 create mode 100644 examples/sync/nack/node1/conntrackd.conf
 create mode 100644 examples/sync/nack/node1/keepalived.conf
 create mode 100644 examples/sync/nack/node2/Makefile.am
 create mode 100644 examples/sync/nack/node2/conntrackd.conf
 create mode 100644 examples/sync/nack/node2/keepalived.conf
 create mode 100755 examples/sync/nack/script_backup.sh
 create mode 100755 examples/sync/nack/script_master.sh
 create mode 100644 examples/sync/persistent/Makefile.am
 create mode 100644 examples/sync/persistent/README
 create mode 100644 examples/sync/persistent/node1/Makefile.am
 create mode 100644 examples/sync/persistent/node1/conntrackd.conf
 create mode 100644 examples/sync/persistent/node1/keepalived.conf
 create mode 100644 examples/sync/persistent/node2/Makefile.am
 create mode 100644 examples/sync/persistent/node2/conntrackd.conf
 create mode 100644 examples/sync/persistent/node2/keepalived.conf
 create mode 100755 examples/sync/persistent/script_backup.sh
 create mode 100755 examples/sync/persistent/script_master.sh
 create mode 100644 extensions/Makefile.am
 create mode 100644 extensions/libct_proto_icmp.c
 create mode 100644 extensions/libct_proto_icmp.man
 create mode 100644 extensions/libct_proto_sctp.c
 create mode 100644 extensions/libct_proto_tcp.c
 create mode 100644 extensions/libct_proto_tcp.man
 create mode 100644 extensions/libct_proto_udp.c
 create mode 100644 extensions/libct_proto_udp.man
 create mode 100644 include/Makefile.am
 create mode 100644 include/alarm.h
 create mode 100644 include/buffer.h
 create mode 100644 include/cache.h
 create mode 100644 include/conntrack.h
 create mode 100644 include/conntrackd.h
 create mode 100644 include/debug.h
 create mode 100644 include/hash.h
 create mode 100644 include/ignore.h
 create mode 100644 include/jhash.h
 create mode 100644 include/linux_list.h
 create mode 100644 include/local.h
 create mode 100644 include/log.h
 create mode 100644 include/mcast.h
 create mode 100644 include/network.h
 create mode 100644 include/slist.h
 create mode 100644 include/state_helper.h
 create mode 100644 include/sync.h
 create mode 100644 include/us-conntrack.h
 create mode 100644 src/Makefile.am
 create mode 100644 src/alarm.c
 create mode 100644 src/buffer.c
 create mode 100644 src/cache.c
 create mode 100644 src/cache_iterators.c
 create mode 100644 src/cache_lifetime.c
 create mode 100644 src/cache_timer.c
 create mode 100644 src/checksum.c
 create mode 100644 src/conntrack.c
 create mode 100644 src/hash.c
 create mode 100644 src/ignore_pool.c
 create mode 100644 src/local.c
 create mode 100644 src/lock.c
 create mode 100644 src/log.c
 create mode 100644 src/main.c
 create mode 100644 src/mcast.c
 create mode 100644 src/netlink.c
 create mode 100644 src/network.c
 create mode 100644 src/proxy.c
 create mode 100644 src/read_config_lex.l
 create mode 100644 src/read_config_yy.y
 create mode 100644 src/run.c
 create mode 100644 src/state_helper.c
 create mode 100644 src/state_helper_tcp.c
 create mode 100644 src/stats-mode.c
 create mode 100644 src/sync-mode.c
 create mode 100644 src/sync-nack.c
 create mode 100644 src/sync-notrack.c
 create mode 100644 src/traffic_stats.c
 create mode 100644 test.sh

(limited to 'autogen.sh')

diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e6c2f6b
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Pablo Neira Ayuso <pablo@netfilter.org>
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 0000000..afab61d
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,184 @@
+version 0.9.3 (yet unreleased)
+------------------------------
+o fix commit of confirmed expectations (reported by Nishit Shah)
+o fix double increment of counters in cache_update_force() (Niko Tyni)
+o nl_dump_handler must return NFCT_CB_CONTINUE (Niko Tyni)
+o initialize buffer in nl_event_handler() and nl_dump_handler() (Niko Tyni) 
+o CacheCommit value can be set via conntrackd.conf for the NACK approach
+o fix leaks in the hashtable/cache flush path (Niko Tyni)
+o fix leak if a connection already exists in the cache (Niko Tyni)
+o introduce a new header that encapsulates netlink messages
+o remove all '_entry' tail from all functions in cache.c
+o split cache.c: move cache iterators to file cache_iterators.c
+o fix inconsistencies in the cache API related to counters
+o cleanup 'usage' message
+o fix typo in examples/sync/nack/node1/conntrackd.conf
+o introduce message checksumming as described in RFC1071 (enabled by default)
+o major cleanups in the synchronization code
+o just warn once that the maximum netlink socket buffer has been reached
+o fix ignore conntrack entries by IP and introduce ignore pool abstraction layer
+o introduce netlink socket buffer overrun handler
+o constification of hash, compare and hashtable_test functions in hash.c
+o introduce ACKnowledgement mechanisms to reduce the size of the resend queue
+o remove OK messages at startup since provide useless data
+o fix compilation warning in mcast.c: recvfrom takes socklen_t not size_t
+o add a lock per buffer: makes buffer code thread safe
+o introduce 'Replicate' clause to explicitely set states to be replicated
+o kill cache feature abuse: introduce nicer cache hooks for sync algorithms
+o fix oversized buffer allocated in the stack in the cache functions
+o add support to dump internal/external cache in XML format '-x'
+
+version 0.9.2 (2006/01/17)
+--------------------------
+o remove spamming packet lost messages
+o generalize network netlink sequence tracking 
+o fix bogus error message on resync `-R'
+o fix endianess issues in the network netlink message
+o introduce generic netlink multicast primitives to send and receive
+o fix bogus replayed multicast message due to sequence numbering wraparound
+o introduce counter for malformed netlink messages received
+o introduce a new syntax for the `Sync' section  in the configuration file
+o several cleanups and remove unused variables
+o add autostuff to include examples in the tarball (reported by Victor Lozano)
+o use the new API available in libnetfilter_conntrack-0.0.50
+o implement a NACK based protocol for replication
+
+version 0.9.1 (2006/11/06)
+--------------------------
+o conntrackd requires kernel >= 2.6.18
+o remove bogus TIMERS_MODE constant
+o implement bulk mode '-B': first works to address the preemption issue
+o fix minor reduction conflicts in the configfile grammar
+o check for CAP_NET_ADMIN instead of requiring root privileges
+o check that linux/capability.h exists
+o fix formatting at dump statistics '-s'
+o move dump traffic stats before multicast traffic stats
+o move event and dump handler to a generic infrastructure: kill events.c file
+o kill unused function inc_ct_stats
+o kill file resync.h
+o cleanup broadcast_sync: renamed to mcast_send_sync
+o sed 's/perror/debug/g' local.c
+o fix bogus increment of update_fail stats at dump stage
+o display descriptive error if we can't connect to conntrackd via UNIX socket
+o remove debugging message from alarm.c
+o move dump_mcast_stats to mcast.c where it really belongs
+o rename stats.c to traffic_stats.c
+o check for replayed/lost multicast message: simple seq tracking w/o recovery
+o reissue nfnl_catch on ENOENT error: a message for other subsystem
+o remove test/ directory in tree
+o improve cache commit stats
+o kill last_commit and last_flush from cache statistics: use the logfile
+o recover cache naming for dump stats `-s'
+o display multicast sequence tracking statistics: packets lost and replayed
+o zero ct_sync_state and ct_stats_state structures after allocation
+o improve keepalived scripts:
+   - resync with conntrack table on transition to master
+   - send bulk on transition to backup
+o implement alarm cascade of ten levels
+o implement timer cache flavour: limited life of entries in the external cache
+o implement a global lock that protects operation with conntrack entries
+o remove debug checking in cache_del_entry
+o set a reduced timeout for committed entries: 180 seconds by default
+o update comments on the sync-mode code
+o introduce delay destroy messages facility
+o increase timer for external states from 60 to 180 seconds
+o remove unused replicate/dont_replicated constants
+o fix cache entry clashing issue (reported by Maik Hentsche)
+o fix bogus increment of error stats in the external cache
+o remove pollution generated by `[REQ] cache dump' message from logfile
+
+version 0.9.0 (2006/09/17)
+--------------------------
+o implement initial for IPv6 (untested)
+o implement generic extensible cache: kill the internal and external caches
+o implement persistence cache feature
+o implement lifetime cache feature
+o modify UNIX facilities identification numbers:
+  separate master conntrack facilities and internal plugin facilities
+o break backward compatibility of configuration file:
+  remove IgnoreLoopback, use IgnoreTrafficFor instead
+  remove IgnoreMulticastTraffic, use IgnoreTrafficFor instead
+o merge event/event_subsys and sync/sync_subsys initialization to run.c
+o improve control of the iteration process in the hashtables
+o fix wrong locking in the alarm thread
+o supersede AcceptNAT by StripNAT clause
+o replace ignore traffic array by a hashtable
+o move lockfile checking before daemonization
+o on initialization error give a descriptive error
+o introduce netlink socket size grown limitator
+o introduce force resync with master conntrack table facility '-R'
+o ignore SIGPIPE signal
+o kill post_step since it is not used anymore
+
+version 0.8.3 (2006/09/03)
+--------------------------
+Author: Maik Hentsche <maik mm-double net>
+
+o Fix typo in conntrackd -h
+o Disable debugging messages by default
+o No signals while signals handlings
+o Add extra checkings at forking
+o Check maximum size for file passed via -C
+
+Author: Pablo Neira Ayuso <pablo netfilter org>
+
+o retry select() if EINTR is returned (Reported by Maik Hentsche)
+o Fix bug in slist_for_each_entry (Reported by Maik Hetsche)
+o Signal handler registration done after intialization
+o Implement alarm thread (based on Maik Hentsche's patch)
+o Fix segfault on conntrackd -k (Reported by Maik Hentsche)
+o Fix bug on alarm removal (Reported by Maik Hentsche)
+o configure stops if bison, flex or yacc are not installed
+
+version 0.8.2 (2006/07/05)
+--------------------------
+o RelaxTransitions clause introduced in Sync mode
+o multicast messages sequence tracking
+o SocketBufferSize clause to set up the netlink socket buffer
+o use new libnfnetlink API to solve limitations of nfnl_listen
+o extra sanity checkings for netlink multicast messages
+o improve statistics
+o tons of cleanups 8)
+
+version 0.8.1 (2006/06/13)
+--------------------------
+o -f now just flushes the internal and external caches
+o -F flushes the master conntrack table
+o fix segfault under heavy load and signal received
+o added -S mode for statistics: still needs more thinking
+
+version 0.8.0 (2006/06/11)
+--------------------------
+o more work to generalize the daemon: now it's ready to implement
+modular support for adaptive timers and conntrack statistics, time
+to implement them ;). This is *still* a work in progress.
+
+version 0.7.2 (2006/06/05)
+--------------------------
+o stupid bug in normal and alarm caches initialization: flush unset
+o fix racy signal handling
+
+version 0.7.1 (2006/06/05)
+--------------------------
+o Bugfix for multicast sockets communication
+
+version 0.7 (2006/06/01)
+------------------------
+o Major code re-structuration: internal and external cache abstraction
+o sequence tracking for event messages
+o expect more changes, I still dislike some stuff in its current status ;)
+
+version 0.6 (2006/05/31)
+------------------------
+o Lock file support
+o use new API nfct_conntrack_event_raw
+o major code clean ups
+
+version 0.5 (2006/05/30)
+-------------------------
+o Fix multicast server binds to wrong interface
+o Include clause `IgnoreProtocol', deprecates IgnoreUDP and IgnoreICMP
+
+version 0.4 (2006/05/29)
+------------------------
+o Initial release
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
new file mode 100644
index 0000000..c5e40b4
--- /dev/null
+++ b/CONTRIBUTORS
@@ -0,0 +1,3 @@
+Maik Hentsche <netfilter@mm-double.de>:
+  - Feedback & Brainstorming
+  - Bug hunting
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..1524ef6
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,243 @@
+2006-03-20
+<hidden@sch.bme.hu>
+	o fix ICMP protocol extension parse callback
+
+2006-01-15
+<pablo@netfilter.org>
+	o Added missing parameters to set the ports of an expectation tuple
+	o Add support to filter dumped entries. 
+	  ie: conntrack -L -p tcp --orig-port-dst 993
+	  display all the connections to IMAPS servers
+	      conntrack -L -m 2
+	  display all the connection marked with 2
+	o Bumped version to 1.00beta2
+
+2005-12-26
+<pablo@netfilter.org>
+	o add IPv6 support: main change
+	o removed dead code: iptables_insmod and get_modprobe
+	o compact the commands vs. options table
+	o move working vars from the stack to the BSS section
+	o update manpage
+	o Bumped version to 1.0beta1
+<yasuyuki.kozakai@toshiba.co.jp>
+	o check address family mismatch
+	o fix incomplete copying IPv6 addresses
+
+2005-12-19
+<pablo@netfilter.org>
+	o We only support ipv4 at the moment: set l3protonum to AF_INET
+	o Minor changes to prepare upcoming ipv6 support
+
+2005-12-03
+<pablo@netfilter.org>
+	o Add support to filter events. ie: -p tcp --orig-port-dst 80 in
+	conjuction with -E to get all the requests to HTTP servers
+	o Update manpage
+	o Missing static function declaration in the protocol handlers
+	o Use protocol flags defined in libnetfilter_conntrack
+	o Bumped version to 0.991
+
+2005-11-22
+<marcus@ingate.com>
+	o Fix oversized number of options
+
+2005-11-11
+<laforge@netfilter.org>
+	o don't check for kernel header path in configure, since we don't use
+	  kernel headers
+	o don't check for libnfnetlink, we don't use it directly
+	o move plugins into pkglibdir
+	o remove 'lib' prefix of plugins, they're not really libraries
+	o remove version information from plugin filenames
+	o Bumped version to 0.99
+2005-11-09
+<pablo@netfilter.org>
+	o set status to zero, libnetfilter_conntrack now activate
+	IPS_CONFIRMED since all conntrack in hash must be confirmed.
+	o Bumped version to 0.98
+
+2005-11-08
+<olenf@ans.pl>
+	o Fix warnings generated by gcc -Wall
+	o Fix conntrack exit value at error
+	o Replace obsolete inet_addr by inet_aton
+
+2005-11-05
+<olenf@ans.pl>
+	o Improved conntrack -h output
+	o add htons for icmp id.
+<pablo@eurodev.net>
+	o -t and -u are optional at update.
+	o Fixed versioning :(
+	o Bumped version to 0.97
+
+2005-11-03
+<laforge@netfilter.org>
+	o Use extra 'data' argument of nfct_register_callback() function that
+	  I've introduced in libetfilter_conntrack.
+<olenf@ans.pl>
+	o moves conntrack tool from bin to sbin directory since this
+	application is an administration utility and it requires uid==0 or
+	CAP_NET_ADMIN
+<pablo@eurodev.net>
+	o check if --state missing when -p is passed
+	o command type is passed to final_check: checkings based on the
+	command can be done now.
+	o kill duplicated definition of IPS_* bits: Already present in 
+	libnetfilter_conntrack.
+	o Move action and command enum to conntrack.h
+	o kill NIPQUAD macro
+	o make conntrack handler cth static.
+	o Bumped version to 0.96
+
+2005-11-01
+<pablo@eurodev.net>
+	o Fix error message describing illegal option -E -i
+	o -D -i ID requires tuple information: Display an error message
+	o Use NFCT_ALL_CT_GROUPS flag instead of NFCT_ALL_GROUPS
+	o Event mask doesn't make sense for expectations, kill dead code
+	o Bumped version to 0.95
+<olenf@ans.pl>
+	o Fix wrong formating in conntrack -h
+
+2005-10-30
+<pablo@eurodev.net>
+	Special thanks to Deti Fiegl from the Leibniz Supercomputing Centre in
+	Munich, Germany for providing the "fast" hardware to reproduce
+	spurious bugs ;)
+
+	o Replace misleading message "Not enough memory" by "Can't open handler"
+	o New option -i for expectation dumping: conntrack -L expect [-i]
+	o sed 's/VERSION/CONNTRACK_VERSION/g'
+	o Fix nfct_open flags, now uses NFCT_ALL_GROUPS when needed
+	o Bumped version to 0.94
+
+2005-10-28
+<pablo@eurodev.net>
+	o New option -i for dumping: conntrack -L [-i]
+	o Fixed warning in findproto due to a stupid wrong type definition
+	o sed 's/nfct_set_callback/nfct_register_callback/g'
+	o killed the 'retry' logic, *sigh* it is broken in some cases
+	o killed broken and unneeded protocol handler destructors (fini)
+	o killed unregister_proto
+	o Fixed code indentation in the command selector
+	o Bumped version to 0.93
+
+2005-10-27
+<pablo@eurodev.net>
+	o Use conntrack VERSION instead of the old LIBCT_VERSION
+	o proto_list and lib_dir are now static
+	o kill dead code: function dump_tuple
+	o Bumped version to 0.92
+
+2005-10-25
+<eleblond@inl.fr>
+	o Add missing autogen.sh file
+
+2005-10-24
+<pablo@eurodev.net>
+	o use NFCT_ANY_GROUP flag in nfct_open()
+
+2005-10-21
+<pablo@eurodev.net>
+	o Bumped version to 0.90
+	o Add support for id and marks
+
+2005-10-20
+<pablo@eurodev.net>
+	o Kill some more files that generated by the autocrap
+	o Resync with the lastest libnetfilter_conntrack API changes
+
+2005-10-16
+<pablo@netfilter.org>
+	o Rename libct_proto.h to conntrack.h
+	o Remove config.h.in from svn, it's autogenerated by the autocrap :)
+	o Remove dead functions in the SCTP protocol helper
+
+2005-10-14
+<pablo@netfilter.org>
+	o Kill config.h.in, it's generated by the autocrap
+	o The conntrack tool now uses libnetfilter_conntrack :)
+	o libct.c has been killed, now it's in libnetfilter_conntrack
+	o Check if you're root or CAP_NET_ADMIN
+	o Bumped version number to 0.86
+
+2005-10-07
+<chentschel@iplan.com.ar>
+	o Fixed ICMP options
+<pablo@netfilter.org>
+	o Multiple fixes for the ICMP protocol handler
+	o Fix ICMP output: wrong output. type and code were set to zero.
+
+2005-10-05
+<pablo@netfilter.org>
+	o Fix up counters
+	o Fix up compilation (IPS_* stuff missing), still need a proper fix
+	o Bumped version number to 0.82
+
+2005-09-24
+<laforge@netfilter.org>
+	o Get rid of C++ style comments
+	o Remove remaining bits of "-A --action", group-mask and dump-mask
+	o Clean up #include's
+	o Fix double-free when exiting via signal handler (Ctrl+C)
+	o Add "version" member to plugins
+	o Fix some Endianness issues when printing CTA_STATUS
+
+2005-08-31
+<pablo@netfilter.org>
+	o Fix packet and bytes counters (use __be64_to_cpu)
+	o Fix ip_conntrack_netlink load-on-demand
+
+2005-07-12
+<pablo@eurodev.net>
+	o Use conntrack netlink attributes: Major change
+	o Kill action setting: Mask based dumping
+	o Fix ChangeLog
+
+2005-05-23
+<laforge@netfilter.org>
+	o Fixed syntax error (tab/space issue) in help message
+	o Fixed getopt handling on big endian machines
+	o Fixed possible future read-over-end-of-array in TCP extension
+	o Add manpage
+	o Add missing space at output of libct_proto_icmp.c
+	o Add status bits that were introduced in 2.6.11
+	o Add SCTP extension
+	o Add support for expect creation
+	o Bump version number to 0.63
+
+2005-05-17
+<pablo@eurodev.net>
+	o Added descriptive error messages.
+	o Fix wrong flags check in [tcp|udp] proto helpers.
+
+2005-05-16
+<pablo@eurodev.net>
+	o Implemented ICMP proto helper
+	o Added help() and final_check() functions for proto helpers.
+
+2005-05-01
+<pablo@eurodev.net>
+	o Created changelog file
+	o Deleted libctnetlink.h and libnfnetlink.h from the include/ dir.
+	o Added support for version (-V) and help (-h)
+	o Added event mask based support
+	o Added GPLv2 headers
+	o Use fprintf instead of printf
+	o Defined print_tuple and print_proto output interfaces
+	o ctnl_[get|del]_conntrack handles return value from kernel via msgerr
+	o Added support for conntrack table flushing
+	o Added test case file (test.sh)
+	o Improve dump output
+
+<azez@ufomechanic.net>
+	o Autoconf stuff for conntrack + some pablo's modifications.
+	o Fixed packet counters formatting (use %llu instead of %lu)
+
+2005-04-25
+<pablo@eurodev.net>
+	o Added support for mask based event dumping
+	o Added support for mask based event notification
+	o On-demand autoload of ip_conntrack_netlink
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..0de8dc0
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,199 @@
+Copyright (C) 2006-2007 Pablo Neira Ayuso <pablo netfilter org>
+
+1.Basic Installation
+====================
+
+ To compile and install 'conntrackd' just follow the classical steps:
+
+	$ ./configure
+	$ make
+	# make install
+	# mkdir /etc/conntrackd/
+
+2.1. Synchronization Mode
+=========================
+
+ Conntrackd can replicate the status of the connections that are currently
+ being processed by your stateful firewall based on Linux. This section
+ describes how to setup the daemon in synchronization mode:
+
+2.1.1. Requirements
+
+ You have to install the following software in order to get conntrackd working,
+ make sure that you have installed them correctly before going forward:
+
+ o linux kernel version >= 2.6.18 (http://www.kernel.org) with support for:
+     - connection tracking system (quite obvious ;)
+     - nfnetlink
+     - ctnetlink (ip_conntrack_netlink)
+     - connection tracking event notification API
+
+ o libnfnetlink: the netfilter netlink library
+
+     Since conntrackd version 0.9.2 you can used the official release availble at
+     http://www.netfilter.org/projects/libnfnetlink/files/
+
+     Up to conntrackd version 0.9.1 use the unofficial release available at the
+     download section
+
+ o libnetfilter_conntrack: the netfilter conntrack library
+
+     Since  conntrackd version 0.9.2 you can used the official release availble at
+     http://www.netfilter.org/projects/libnetfilter_conntrack/files/
+
+     Up to conntrackd version 0.9.1 use the unnoficial release available at the
+     download section
+
+ o Keepalived version 1.x (http://www.keepalived.org)
+     check if your distribution comes with a recent version
+
+2.1.2. Configuration
+
+ 1) Setting up keepalived
+
+    There is an example file available inside the conntrackd tarball:
+
+    For node 1: conntrackd-x.x.x/examples/sync/node1/keepalived.conf
+    For node 2: conntrackd-x.x.x/examples/sync/node2/keepalived.conf
+
+    These files can be used to set up a simple VRRP cluster composed of
+    two machines that hold the virtual IPs 192.168.0.100 on eth0 and
+    192.168.1.100 on eth1.
+
+    If you are not familiar with keepalived, please read the official
+    docs available at http://www.keepalived.org
+
+    Please, make sure that keepalived is correctly working before passing
+    to step 2)
+
+ 2) Setting up conntrackd
+
+    To setup 'conntrackd' in synchronization mode, you have to put the
+    configuration file in the directory /etc/conntrackd.
+
+    On node 1:
+	# cp examples/sync/_type_/node1/conntrackd.conf /etc/conntrackd.conf
+
+    On node 2:
+        # cp examples/sync/_type_/node1/conntrackd.conf /etc/conntrackd.conf
+
+    Where _type_ is the synchronization type selected, currently there are
+    two: the persistent mode and the NACK mode. The persistent mode consumes
+    more resources than the NACK mode, however the NACK mode is still
+    experimental
+
+    Do not forget to edit the files in order to adapt them to the
+    setting that you are deploying.
+
+    Note: If you don't want to put the config file under /etc/conntrackd,
+    just tell conntrackd where to find it passing the option -C
+
+ 3) Running conntrackd
+
+    Conntrackd can run in console mode, in that case just type 'conntrackd',
+    otherwise, if you want to run it in daemon mode the type 'conntrackd -d'.
+
+ 4) Checking that conntrackd is working fine
+
+    Conntrackd comes with several facilities to check its status:
+
+    - Dump the cache of connections that are currently being processed by
+      this node (aka. internal cache):
+
+    # conntrackd -i
+
+    - Dump the cache of connections that has been transfered from
+      others active nodes in the network (aka. external cache)
+
+    # conntrackd -e
+
+    - Dump statistics collected by the replication daemon:
+
+    # conntrackd -s
+
+ 5) Setting up interaction with keepalived
+
+    If keepalived detects the failure of the active node, then it designates
+    a candidate node that will replace the failing active. On such event,
+    the external cache, eg. the cache that contains the connections processed
+    by other nodes, must be commited. To commit the external cache, just type:
+
+    # conntrackd -c
+
+    See that keepalived provides a shell script interface to interact with
+    other programs, so we can automate the process of commiting the external
+    cache by introducing the following line in the keepalived file:
+
+    notify_master /etc/conntrackd/script_master.sh
+
+    The script 'script_master.sh' just the following:
+
+    #!/bin/sh
+    /usr/sbin/conntrackd -c
+
+    Therefore, on failure event, the candidate node takes over the virtual
+    IPs and the connections that the failing active was processing. Observe
+    that this file differs for the NACK mode.
+
+ 6) Disable TCP window tracking
+
+ Until the appropiate patches don't go into kernel mainline, you will have
+ to disable TCP window tracking, consider this as a temporary solution:
+
+    # echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal
+
+2.2. Statistics mode
+====================
+
+ Conntrackd can also run as statistics daemon, if you are not interested in
+ this mode, just skip it. It is not required in order to get the
+ synchronization mode working. This section details how to setup the daemon
+ in statistics mode:
+
+2.2.1. Requirements
+
+ You have to install the following software in order to get conntrackd working,
+ make sure that you have them installed correctly before going forward:
+
+ o linux kernel version >= 2.6.18 (http://www.kernel.org) with support for:
+      - connection tracking system
+      - nfnetlink
+      - ctnetlink (ip_conntrack_netlink)
+      - connection tracking event notification API
+
+ o libnfnetlink: the netfilter netlink library
+
+     Since conntrackd version 0.9.2 you can used the official release availble at
+     http://www.netfilter.org/projects/libnfnetlink/files/
+
+     Up to conntrackd version 0.9.1 use the unofficial release available at the
+     download section
+
+ o libnetfilter_conntrack: the netfilter conntrack library
+
+     Since  conntrackd version 0.9.2 you can used the official release availble at
+     http://www.netfilter.org/projects/libnetfilter_conntrack/files/
+
+     Up to conntrackd version 0.9.1 use the unnoficial release available at the
+     download section
+
+2.2.2. Configuration
+
+ Setting up conntrackd in statistics mode is rather easy. Just copy the
+ configuration file
+
+    # cp examples/stats/conntrackd.conf /etc/conntrackd.conf
+
+2.2.3. Running conntrackd in statistics mode
+
+ To run conntrackd in statistics mode:
+
+    # conntrackd -S
+
+ Alternatively, you can run conntrackd in daemon mode:
+
+    # conntrackd -S -d
+
+ In order to dump the statistics, just type:
+
+    # conntrackd -s
diff --git a/Make_global.am b/Make_global.am
new file mode 100644
index 0000000..685add7
--- /dev/null
+++ b/Make_global.am
@@ -0,0 +1 @@
+INCLUDES=$(all_includes) -I$(top_srcdir)/include
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..8a4ce7c
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,21 @@
+include Make_global.am
+
+# not a GNU package. You can remove this line, if
+# have all needed files, that a GNU package needs
+AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
+
+# man_MANS = ""
+# EXTRA_DIST = $(man_MANS) Make_global.am debian
+EXTRA_DIST = Make_global.am CHANGELOG TODO
+
+SUBDIRS   = src extensions
+DIST_SUBDIRS = include src extensions examples
+LINKOPTS  = -lnfnetlink -lnetfilter_conntrack -lpthread
+AM_CFLAGS = -g
+
+$(OBJECTS): libtool
+libtool: $(LIBTOOL_DEPS)
+	$(SHELL) ./config.status --recheck
+
+dist-hook:
+	rm -rf `find $(distdir)/debian -name .svn`
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..130b1f8
--- /dev/null
+++ b/TODO
@@ -0,0 +1,18 @@
+There are several tasks that are pending to be done, I have classified them
+by dificulty levels:
+
+Relatively easy
+===============
+
+- test ipv6 support
+- improve shell scripts
+- test NACK based protocol
+- manpage for conntrackd
+
+Requires some work
+==================
+
+- study better keepalived transitions
+- implement support for TCP window tracking (patches are on the table)
+	- at the moment you have to disable it:
+	echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..e76d3ef
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+run ()
+{
+    echo "running: $*"
+    eval $*
+
+    if test $? != 0 ; then
+	echo "error: while running '$*'"
+	exit 1
+    fi
+}
+
+run aclocal
+run libtoolize -f
+#run autoheader
+run automake -a
+run autoconf
diff --git a/cli/ChangeLog b/cli/ChangeLog
deleted file mode 100644
index 1524ef6..0000000
--- a/cli/ChangeLog
+++ /dev/null
@@ -1,243 +0,0 @@
-2006-03-20
-<hidden@sch.bme.hu>
-	o fix ICMP protocol extension parse callback
-
-2006-01-15
-<pablo@netfilter.org>
-	o Added missing parameters to set the ports of an expectation tuple
-	o Add support to filter dumped entries. 
-	  ie: conntrack -L -p tcp --orig-port-dst 993
-	  display all the connections to IMAPS servers
-	      conntrack -L -m 2
-	  display all the connection marked with 2
-	o Bumped version to 1.00beta2
-
-2005-12-26
-<pablo@netfilter.org>
-	o add IPv6 support: main change
-	o removed dead code: iptables_insmod and get_modprobe
-	o compact the commands vs. options table
-	o move working vars from the stack to the BSS section
-	o update manpage
-	o Bumped version to 1.0beta1
-<yasuyuki.kozakai@toshiba.co.jp>
-	o check address family mismatch
-	o fix incomplete copying IPv6 addresses
-
-2005-12-19
-<pablo@netfilter.org>
-	o We only support ipv4 at the moment: set l3protonum to AF_INET
-	o Minor changes to prepare upcoming ipv6 support
-
-2005-12-03
-<pablo@netfilter.org>
-	o Add support to filter events. ie: -p tcp --orig-port-dst 80 in
-	conjuction with -E to get all the requests to HTTP servers
-	o Update manpage
-	o Missing static function declaration in the protocol handlers
-	o Use protocol flags defined in libnetfilter_conntrack
-	o Bumped version to 0.991
-
-2005-11-22
-<marcus@ingate.com>
-	o Fix oversized number of options
-
-2005-11-11
-<laforge@netfilter.org>
-	o don't check for kernel header path in configure, since we don't use
-	  kernel headers
-	o don't check for libnfnetlink, we don't use it directly
-	o move plugins into pkglibdir
-	o remove 'lib' prefix of plugins, they're not really libraries
-	o remove version information from plugin filenames
-	o Bumped version to 0.99
-2005-11-09
-<pablo@netfilter.org>
-	o set status to zero, libnetfilter_conntrack now activate
-	IPS_CONFIRMED since all conntrack in hash must be confirmed.
-	o Bumped version to 0.98
-
-2005-11-08
-<olenf@ans.pl>
-	o Fix warnings generated by gcc -Wall
-	o Fix conntrack exit value at error
-	o Replace obsolete inet_addr by inet_aton
-
-2005-11-05
-<olenf@ans.pl>
-	o Improved conntrack -h output
-	o add htons for icmp id.
-<pablo@eurodev.net>
-	o -t and -u are optional at update.
-	o Fixed versioning :(
-	o Bumped version to 0.97
-
-2005-11-03
-<laforge@netfilter.org>
-	o Use extra 'data' argument of nfct_register_callback() function that
-	  I've introduced in libetfilter_conntrack.
-<olenf@ans.pl>
-	o moves conntrack tool from bin to sbin directory since this
-	application is an administration utility and it requires uid==0 or
-	CAP_NET_ADMIN
-<pablo@eurodev.net>
-	o check if --state missing when -p is passed
-	o command type is passed to final_check: checkings based on the
-	command can be done now.
-	o kill duplicated definition of IPS_* bits: Already present in 
-	libnetfilter_conntrack.
-	o Move action and command enum to conntrack.h
-	o kill NIPQUAD macro
-	o make conntrack handler cth static.
-	o Bumped version to 0.96
-
-2005-11-01
-<pablo@eurodev.net>
-	o Fix error message describing illegal option -E -i
-	o -D -i ID requires tuple information: Display an error message
-	o Use NFCT_ALL_CT_GROUPS flag instead of NFCT_ALL_GROUPS
-	o Event mask doesn't make sense for expectations, kill dead code
-	o Bumped version to 0.95
-<olenf@ans.pl>
-	o Fix wrong formating in conntrack -h
-
-2005-10-30
-<pablo@eurodev.net>
-	Special thanks to Deti Fiegl from the Leibniz Supercomputing Centre in
-	Munich, Germany for providing the "fast" hardware to reproduce
-	spurious bugs ;)
-
-	o Replace misleading message "Not enough memory" by "Can't open handler"
-	o New option -i for expectation dumping: conntrack -L expect [-i]
-	o sed 's/VERSION/CONNTRACK_VERSION/g'
-	o Fix nfct_open flags, now uses NFCT_ALL_GROUPS when needed
-	o Bumped version to 0.94
-
-2005-10-28
-<pablo@eurodev.net>
-	o New option -i for dumping: conntrack -L [-i]
-	o Fixed warning in findproto due to a stupid wrong type definition
-	o sed 's/nfct_set_callback/nfct_register_callback/g'
-	o killed the 'retry' logic, *sigh* it is broken in some cases
-	o killed broken and unneeded protocol handler destructors (fini)
-	o killed unregister_proto
-	o Fixed code indentation in the command selector
-	o Bumped version to 0.93
-
-2005-10-27
-<pablo@eurodev.net>
-	o Use conntrack VERSION instead of the old LIBCT_VERSION
-	o proto_list and lib_dir are now static
-	o kill dead code: function dump_tuple
-	o Bumped version to 0.92
-
-2005-10-25
-<eleblond@inl.fr>
-	o Add missing autogen.sh file
-
-2005-10-24
-<pablo@eurodev.net>
-	o use NFCT_ANY_GROUP flag in nfct_open()
-
-2005-10-21
-<pablo@eurodev.net>
-	o Bumped version to 0.90
-	o Add support for id and marks
-
-2005-10-20
-<pablo@eurodev.net>
-	o Kill some more files that generated by the autocrap
-	o Resync with the lastest libnetfilter_conntrack API changes
-
-2005-10-16
-<pablo@netfilter.org>
-	o Rename libct_proto.h to conntrack.h
-	o Remove config.h.in from svn, it's autogenerated by the autocrap :)
-	o Remove dead functions in the SCTP protocol helper
-
-2005-10-14
-<pablo@netfilter.org>
-	o Kill config.h.in, it's generated by the autocrap
-	o The conntrack tool now uses libnetfilter_conntrack :)
-	o libct.c has been killed, now it's in libnetfilter_conntrack
-	o Check if you're root or CAP_NET_ADMIN
-	o Bumped version number to 0.86
-
-2005-10-07
-<chentschel@iplan.com.ar>
-	o Fixed ICMP options
-<pablo@netfilter.org>
-	o Multiple fixes for the ICMP protocol handler
-	o Fix ICMP output: wrong output. type and code were set to zero.
-
-2005-10-05
-<pablo@netfilter.org>
-	o Fix up counters
-	o Fix up compilation (IPS_* stuff missing), still need a proper fix
-	o Bumped version number to 0.82
-
-2005-09-24
-<laforge@netfilter.org>
-	o Get rid of C++ style comments
-	o Remove remaining bits of "-A --action", group-mask and dump-mask
-	o Clean up #include's
-	o Fix double-free when exiting via signal handler (Ctrl+C)
-	o Add "version" member to plugins
-	o Fix some Endianness issues when printing CTA_STATUS
-
-2005-08-31
-<pablo@netfilter.org>
-	o Fix packet and bytes counters (use __be64_to_cpu)
-	o Fix ip_conntrack_netlink load-on-demand
-
-2005-07-12
-<pablo@eurodev.net>
-	o Use conntrack netlink attributes: Major change
-	o Kill action setting: Mask based dumping
-	o Fix ChangeLog
-
-2005-05-23
-<laforge@netfilter.org>
-	o Fixed syntax error (tab/space issue) in help message
-	o Fixed getopt handling on big endian machines
-	o Fixed possible future read-over-end-of-array in TCP extension
-	o Add manpage
-	o Add missing space at output of libct_proto_icmp.c
-	o Add status bits that were introduced in 2.6.11
-	o Add SCTP extension
-	o Add support for expect creation
-	o Bump version number to 0.63
-
-2005-05-17
-<pablo@eurodev.net>
-	o Added descriptive error messages.
-	o Fix wrong flags check in [tcp|udp] proto helpers.
-
-2005-05-16
-<pablo@eurodev.net>
-	o Implemented ICMP proto helper
-	o Added help() and final_check() functions for proto helpers.
-
-2005-05-01
-<pablo@eurodev.net>
-	o Created changelog file
-	o Deleted libctnetlink.h and libnfnetlink.h from the include/ dir.
-	o Added support for version (-V) and help (-h)
-	o Added event mask based support
-	o Added GPLv2 headers
-	o Use fprintf instead of printf
-	o Defined print_tuple and print_proto output interfaces
-	o ctnl_[get|del]_conntrack handles return value from kernel via msgerr
-	o Added support for conntrack table flushing
-	o Added test case file (test.sh)
-	o Improve dump output
-
-<azez@ufomechanic.net>
-	o Autoconf stuff for conntrack + some pablo's modifications.
-	o Fixed packet counters formatting (use %llu instead of %lu)
-
-2005-04-25
-<pablo@eurodev.net>
-	o Added support for mask based event dumping
-	o Added support for mask based event notification
-	o On-demand autoload of ip_conntrack_netlink
diff --git a/cli/conntrack.8 b/cli/conntrack.8
deleted file mode 100644
index 307180b..0000000
--- a/cli/conntrack.8
+++ /dev/null
@@ -1,142 +0,0 @@
-.TH CONNTRACK 8 "Jun 23, 2005" "" ""
-
-.\" Man page written by Harald Welte <laforge@netfilter.org (Jun 2005)
-
-.SH NAME
-conntrack \- administration tool for netfilter connection tracking
-.SH SYNOPSIS
-.BR "conntrack -L [table] [-z]"
-.br
-.BR "conntrack -G [table] parameters"
-.br
-.BR "conntrack -D [table] paramaters"
-.br
-.BR "conntrack -I [table] parameters"
-.br
-.BR "conntrack -E [table] parameters"
-.br
-.BR "conntrack -F [table]"
-.SH DESCRIPTION
-.B conntrack
-is used to search, list, inspect and maintain the netfilter connection tracking
-subsystem of the Linux kernel.
-.PP
-Using 
-.B conntrack
-, you can dump a list of all (or a filtered selection of) currently tracked
-connections, delete connections from the state table, and even add new ones.
-.PP
-In addition, you can also monitor connection tracking events, e.g. show an
-event message (one line) per newly established connection.
-.SH TABLES
-The connection tracking subsystem maintains two internal tables:
-.TP
-.BR "conntrack" :
-This is the default table.  It contains a list of all currently tracked
-connections through the system.  If you don't use connection tracking
-exemptions (NOTRACK iptables target), this means all connections that go
-through the system.
-.TP
-.BR "expect" :
-This is the table of expectations.  Connection tracking expectations are the
-mechanism used to "expect" RELATED connections to existing ones.  Expectations
-are generally used by "connection tracking helpers" (sometimes called
-application level gateways [ALGs]) for more complex protocols such as FTP,
-SIP, H.323.
-.SH OPTIONS
-The options recognized by 
-.B conntrack
-can be divided into several different groups.
-.SS COMMANDS
-These options specify the particular operation to perform.  Only one of them
-can be specified at any given time.
-.TP
-.BI "-L --dump "
-List connection tacking or expectation table
-.TP
-.BI "-G, --get "
-Search for and show a particular (matching) entry in the given table.
-.TP
-.BI "-D, --delete "
-Delete an entry from the given table.
-.TP
-.BI "-I, --create "
-Create a new entry from the given table.
-.TP
-.BI "-E, --event "
-Display a real-time event log.
-.TP
-.BI "-F, --flush "
-Flush the whole given table
-.SS PARAMETERS
-.TP
-.BI "-z, --zero "
-Atomically zero counters after reading them.  This option is only valid in
-combination with the "-L, --dump" command options.
-.TP
-.BI "-e, --event-mask " "[ALL|NEW|UPDATES|DESTROY][,...]"
-Set the bitmask of events that are to be generated by the in-kernel ctnetlink
-event code.  Using this parameter, you can reduce the event messages generated
-by the kernel to those types to those that you are actually interested in.
-.
-This option can only be used in conjunction with "-E, --event".
-.SS FILTER PARAMETERS
-.TP
-.BI "-s, --orig-src " IP_ADDRESS
-Match only entries whose source address in the original direction equals the one specified as argument.
-.TP
-.BI "-d, --orig-dst " IP_ADDRESS
-Match only entries whose destination address in the original direction equals the one specified as argument.
-.TP
-.BI "-r, --reply-src " IP_ADDRESS
-Match only entries whose source address in the reply direction equals the one specified as argument.
-.TP
-.BI "-q, --reply-dst " IP_ADDRESS
-Match only entries whose destination address in the reply direction equals the one specified as argument.
-.TP
-.BI "-p, --proto " "PROTO "
-Specify layer four (TCP, UDP, ...) protocol.
-.TP
-.BI "-f, --family " "PROTO"
-Specify layer three (ipv4, ipv6) protocol
-This option is only required in conjunction with "-L, --dump". If this option is not passed, the default layer 3 protocol will be IPv4.
-.TP
-.BI "-t, --timeout " "TIMEOUT"
-Specify the timeout.
-.TP
-.BI "-u, --status " "[ASSURED|SEEN_REPLY|UNSET|SRC_NAT|DST_NAT][,...]"
-Specify the conntrack status.
-.TP
-.BI "-i, --id " "ID"
-Specify the conntrack ID. 
-.
-This option can only be used in conjunction with "-L, --dump" to display the conntrack IDs.
-.TP
-.BI "--tuple-src " IP_ADDRESS
-Specify the tuple source address of an expectation.
-.TP
-.BI "--tuple-dst " IP_ADDRESS
-Specify the tuple destination address of an expectation.
-.TP
-.BI "--mask-src " IP_ADDRESS
-Specify the source address mask of an expectation.
-.TP
-.BI "--mask-dst " IP_ADDRESS
-Specify the destination address mask of an expectation.
-.SH DIAGNOSTICS
-The exit code is 0 for correct function.  Errors which appear to be caused by
-invalid command line parameters cause an exit code of 2.  Any other errors
-cause an exit code of 1.
-.SH BUGS
-Bugs? What's this ;-)
-.SH SEE ALSO
-.BR iptables (8)
-.br
-See
-.BR "http://netfilter.org/" .
-.SH AUTHORS
-Jay Schulist, Patrick McHardy, Harald Welte and Pablo Neira wrote the kernel-level "ctnetlink" interface that is used by the conntrack tool.
-.PP
-Pablo Neira wrote the conntrack tool, Harald Welte added support for conntrack based accounting counters.
-.PP
-Man page written by Harald Welte <laforge@netfilter.org>.
diff --git a/cli/extensions/Makefile.am b/cli/extensions/Makefile.am
deleted file mode 100644
index 5366ee3..0000000
--- a/cli/extensions/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-include $(top_srcdir)/Make_global.am
-
-AM_CFLAGS=-fPIC -Wall
-LIBS=
-
-pkglib_LTLIBRARIES = ct_proto_tcp.la ct_proto_udp.la		\
-		     ct_proto_icmp.la ct_proto_sctp.la
-
-ct_proto_tcp_la_SOURCES = libct_proto_tcp.c
-ct_proto_tcp_la_LDFLAGS = -module -avoid-version
-ct_proto_udp_la_SOURCES = libct_proto_udp.c
-ct_proto_udp_la_LDFLAGS = -module -avoid-version
-ct_proto_icmp_la_SOURCES = libct_proto_icmp.c
-ct_proto_icmp_la_LDFLAGS = -module -avoid-version
-ct_proto_sctp_la_SOURCES = libct_proto_sctp.c
-ct_proto_sctp_la_LDFLAGS = -module -avoid-version
diff --git a/cli/extensions/libct_proto_icmp.c b/cli/extensions/libct_proto_icmp.c
deleted file mode 100644
index e7cb04d..0000000
--- a/cli/extensions/libct_proto_icmp.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
- *	       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 <stdlib.h>
-#include <netinet/in.h> /* For htons */
-#include <netinet/ip_icmp.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack_icmp.h>
-#include "conntrack.h"
-
-static struct option opts[] = {
-	{"icmp-type", 1, 0, '1'},
-	{"icmp-code", 1, 0, '2'},
-	{"icmp-id", 1, 0, '3'},
-	{0, 0, 0, 0}
-};
-
-static void help()
-{
-	fprintf(stdout, "--icmp-type            icmp type\n");
-	fprintf(stdout, "--icmp-code            icmp code\n");
-	fprintf(stdout, "--icmp-id              icmp id\n");
-}
-
-/* Add 1; spaces filled with 0. */
-static u_int8_t invmap[]
-	= { [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
-	    [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
-	    [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
-	    [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
-	    [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
-	    [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
-	    [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
-	    [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1};
-
-static int parse(char c, char *argv[], 
-		 struct nfct_tuple *orig,
-		 struct nfct_tuple *reply,
-		 struct nfct_tuple *exptuple,
-		 struct nfct_tuple *mask,
-		 union nfct_protoinfo *proto,
-		 unsigned int *flags)
-{
-	switch(c) {
-		case '1':
-			if (optarg) {
-				orig->l4dst.icmp.type = atoi(optarg);
-				reply->l4dst.icmp.type =
-					invmap[orig->l4dst.icmp.type] - 1;
-				*flags |= ICMP_TYPE;
-			}
-			break;
-		case '2':
-			if (optarg) {
-				orig->l4dst.icmp.code = atoi(optarg);
-				reply->l4dst.icmp.code = 0;
-				*flags |= ICMP_CODE;
-			}
-			break;
-		case '3':
-			if (optarg) {
-				orig->l4src.icmp.id = htons(atoi(optarg));
-				reply->l4dst.icmp.id = 0;
-				*flags |= ICMP_ID;
-			}
-			break;
-	}
-	return 1;
-}
-
-static int final_check(unsigned int flags,
-		       unsigned int command,
-		       struct nfct_tuple *orig,
-		       struct nfct_tuple *reply)
-{
-	if (!(flags & ICMP_TYPE))
-		return 0;
-	else if (!(flags & ICMP_CODE))
-		return 0;
-
-	return 1;
-}
-
-static struct ctproto_handler icmp = {
-	.name 		= "icmp",
-	.protonum	= IPPROTO_ICMP,
-	.parse_opts	= parse,
-	.final_check	= final_check,
-	.help		= help,
-	.opts		= opts,
-	.version	= VERSION,
-};
-
-static void __attribute__ ((constructor)) init(void);
-
-static void init(void)
-{
-	register_proto(&icmp);
-}
diff --git a/cli/extensions/libct_proto_icmp.man b/cli/extensions/libct_proto_icmp.man
deleted file mode 100644
index 3b860d0..0000000
--- a/cli/extensions/libct_proto_icmp.man
+++ /dev/null
@@ -1,10 +0,0 @@
-This module matches on ICMP-specific fields.
-.TP
-.BI "--icmp-type " "TYPE"
-ICMP Type. Has to be specified numerically.
-.TP
-.BI "--icmp-code " "CODE"
-ICMP Code. Has to be specified numerically.
-.TP
-.BI "--icmp-id " "ID"
-ICMP Id. Has to be specified numerically.
diff --git a/cli/extensions/libct_proto_sctp.c b/cli/extensions/libct_proto_sctp.c
deleted file mode 100644
index 1c8f0d1..0000000
--- a/cli/extensions/libct_proto_sctp.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * (C) 2005 by Harald Welte <laforge@netfilter.org>
- *     2006 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 "conntrack.h"
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack_sctp.h>
-
-static struct option opts[] = {
-	{"orig-port-src", 1, 0, '1'},
-	{"orig-port-dst", 1, 0, '2'},
-	{"reply-port-src", 1, 0, '3'},
-	{"reply-port-dst", 1, 0, '4'},
-	{"state", 1, 0, '5'},
-	{"tuple-port-src", 1, 0, '6'},
-	{"tuple-port-dst", 1, 0, '7'},
-	{0, 0, 0, 0}
-};
-
-static const char *states[] = {
-	"NONE",
-	"CLOSED",
-	"COOKIE_WAIT",
-	"COOKIE_ECHOED",
-	"ESTABLISHED",
-	"SHUTDOWN_SENT",
-	"SHUTDOWN_RECV",
-	"SHUTDOWN_ACK_SENT",
-};
-
-static void help()
-{
-	fprintf(stdout, "--orig-port-src        original source port\n");
-	fprintf(stdout, "--orig-port-dst        original destination port\n");
-	fprintf(stdout, "--reply-port-src       reply source port\n");
-	fprintf(stdout, "--reply-port-dst       reply destination port\n");
-	fprintf(stdout, "--state                SCTP state, fe. ESTABLISHED\n");
-	fprintf(stdout, "--tuple-port-src	expectation tuple src port\n");
-	fprintf(stdout, "--tuple-port-src	expectation tuple dst port\n");
-}
-
-static int parse_options(char c, char *argv[], 
-			 struct nfct_tuple *orig,
-			 struct nfct_tuple *reply,
-			 struct nfct_tuple *exptuple,
-			 struct nfct_tuple *mask,
-			 union nfct_protoinfo *proto,
-			 unsigned int *flags)
-{
-	switch(c) {
-		case '1':
-			if (optarg) {
-				orig->l4src.sctp.port = htons(atoi(optarg));
-				*flags |= SCTP_ORIG_SPORT;
-			}
-			break;
-		case '2':
-			if (optarg) {
-				orig->l4dst.sctp.port = htons(atoi(optarg));
-				*flags |= SCTP_ORIG_DPORT;
-			}
-			break;
-		case '3':
-			if (optarg) {
-				reply->l4src.sctp.port = htons(atoi(optarg));
-				*flags |= SCTP_REPL_SPORT;
-			}
-			break;
-		case '4':
-			if (optarg) {
-				reply->l4dst.sctp.port = htons(atoi(optarg));
-				*flags |= SCTP_REPL_DPORT;
-			}
-			break;
-		case '5':
-			if (optarg) {
-				int i;
-				for (i=0; i<10; i++) {
-					if (strcmp(optarg, states[i]) == 0) {
-						/* FIXME: Add state to
-						 * nfct_protoinfo
-						proto->sctp.state = i; */
-						break;
-					}
-				}
-				if (i == 10) {
-					printf("doh?\n");
-					return 0;
-				}
-				*flags |= SCTP_STATE;
-			}
-			break;
-		case '6':
-			if (optarg) {
-				exptuple->l4src.sctp.port = htons(atoi(optarg));
-				*flags |= SCTP_EXPTUPLE_SPORT;
-			}
-			break;
-		case '7':
-			if (optarg) {
-				exptuple->l4dst.sctp.port = htons(atoi(optarg));
-				*flags |= SCTP_EXPTUPLE_DPORT;
-			}
-
-	}
-	return 1;
-}
-
-static int final_check(unsigned int flags,
-		       unsigned int command,
-		       struct nfct_tuple *orig,
-		       struct nfct_tuple *reply)
-{
-	int ret = 0;
-	
-	if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) 
-	    && !(flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) {
-		reply->l4src.sctp.port = orig->l4dst.sctp.port;
-		reply->l4dst.sctp.port = orig->l4src.sctp.port;
-		ret = 1;
-	} else if (!(flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT))
-	            && (flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) {
-		orig->l4src.sctp.port = reply->l4dst.sctp.port;
-		orig->l4dst.sctp.port = reply->l4src.sctp.port;
-		ret = 1;
-	}
-	if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) 
-	    && ((flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))))
-		ret = 1;
-
-	/* --state is missing and we are trying to create a conntrack */
-	if (ret && (command & CT_CREATE) && (!(flags & SCTP_STATE)))
-		ret = 0;
-
-	return ret;
-}
-
-static struct ctproto_handler sctp = {
-	.name 			= "sctp",
-	.protonum		= IPPROTO_SCTP,
-	.parse_opts		= parse_options,
-	.final_check		= final_check,
-	.help			= help,
-	.opts			= opts,
-	.version		= VERSION,
-};
-
-static void __attribute__ ((constructor)) init(void);
-
-static void init(void)
-{
-	register_proto(&sctp);
-}
diff --git a/cli/extensions/libct_proto_tcp.c b/cli/extensions/libct_proto_tcp.c
deleted file mode 100644
index ee24206..0000000
--- a/cli/extensions/libct_proto_tcp.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
- *
- *      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 <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
-
-#include "conntrack.h"
-
-static struct option opts[] = {
-	{"orig-port-src", 1, 0, '1'},
-	{"orig-port-dst", 1, 0, '2'},
-	{"reply-port-src", 1, 0, '3'},
-	{"reply-port-dst", 1, 0, '4'},
-	{"mask-port-src", 1, 0, '5'},
-	{"mask-port-dst", 1, 0, '6'},
-	{"state", 1, 0, '7'},
-	{"tuple-port-src", 1, 0, '8'},
-	{"tuple-port-dst", 1, 0, '9'},
-	{0, 0, 0, 0}
-};
-
-static const char *states[] = {
-	"NONE",
-	"SYN_SENT",
-	"SYN_RECV",
-	"ESTABLISHED",
-	"FIN_WAIT",
-	"CLOSE_WAIT",
-	"LAST_ACK",
-	"TIME_WAIT",
-	"CLOSE",
-	"LISTEN"
-};
-
-static void help()
-{
-	fprintf(stdout, "--orig-port-src        original source port\n");
-	fprintf(stdout, "--orig-port-dst        original destination port\n");
-	fprintf(stdout, "--reply-port-src       reply source port\n");
-	fprintf(stdout, "--reply-port-dst       reply destination port\n");
-	fprintf(stdout, "--mask-port-src	mask source port\n");
-	fprintf(stdout, "--mask-port-dst	mask destination port\n");
-	fprintf(stdout, "--tuple-port-src	expectation tuple src port\n");
-	fprintf(stdout, "--tuple-port-src	expectation tuple dst port\n");
-	fprintf(stdout, "--state                TCP state, fe. ESTABLISHED\n");
-}
-
-static int parse_options(char c, char *argv[], 
-			 struct nfct_tuple *orig,
-			 struct nfct_tuple *reply,
-			 struct nfct_tuple *exptuple,
-			 struct nfct_tuple *mask,
-			 union nfct_protoinfo *proto,
-			 unsigned int *flags)
-{
-	switch(c) {
-		case '1':
-			if (optarg) {
-				orig->l4src.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_ORIG_SPORT;
-			}
-			break;
-		case '2':
-			if (optarg) {
-				orig->l4dst.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_ORIG_DPORT;
-			}
-			break;
-		case '3':
-			if (optarg) {
-				reply->l4src.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_REPL_SPORT;
-			}
-			break;
-		case '4':
-			if (optarg) {
-				reply->l4dst.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_REPL_DPORT;
-			}
-			break;
-		case '5':
-			if (optarg) {
-				mask->l4src.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_MASK_SPORT;
-			}
-			break;
-		case '6':
-			if (optarg) {
-				mask->l4dst.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_MASK_DPORT;
-			}
-			break;
-		case '7':
-			if (optarg) {
-				int i;
-				for (i=0; i<10; i++) {
-					if (strcmp(optarg, states[i]) == 0) {
-						proto->tcp.state = i;
-						break;
-					}
-				}
-				if (i == 10) {
-					printf("doh?\n");
-					return 0;
-				}
-				*flags |= TCP_STATE;
-			}
-			break;
-		case '8':
-			if (optarg) {
-				exptuple->l4src.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_EXPTUPLE_SPORT;
-			}
-			break;
-		case '9':
-			if (optarg) {
-				exptuple->l4dst.tcp.port = htons(atoi(optarg));
-				*flags |= TCP_EXPTUPLE_DPORT;
-			}
-			break;
-	}
-	return 1;
-}
-
-static int final_check(unsigned int flags,
-		       unsigned int command,
-		       struct nfct_tuple *orig,
-		       struct nfct_tuple *reply)
-{
-	int ret = 0;
-	
-	if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) 
-	    && !(flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) {
-		reply->l4src.tcp.port = orig->l4dst.tcp.port;
-		reply->l4dst.tcp.port = orig->l4src.tcp.port;
-		ret = 1;
-	} else if (!(flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT))
-	            && (flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) {
-		orig->l4src.tcp.port = reply->l4dst.tcp.port;
-		orig->l4dst.tcp.port = reply->l4src.tcp.port;
-		ret = 1;
-	}
-	if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) 
-	    && ((flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))))
-		ret = 1;
-
-	/* --state is missing and we are trying to create a conntrack */
-	if (ret && (command & CT_CREATE) && (!(flags & TCP_STATE)))
-		ret = 0;
-
-	return ret;
-}
-
-static struct ctproto_handler tcp = {
-	.name 			= "tcp",
-	.protonum		= IPPROTO_TCP,
-	.parse_opts		= parse_options,
-	.final_check		= final_check,
-	.help			= help,
-	.opts			= opts,
-	.version		= VERSION,
-};
-
-static void __attribute__ ((constructor)) init(void);
-
-static void init(void)
-{
-	register_proto(&tcp);
-}
diff --git a/cli/extensions/libct_proto_tcp.man b/cli/extensions/libct_proto_tcp.man
deleted file mode 100644
index 41783f8..0000000
--- a/cli/extensions/libct_proto_tcp.man
+++ /dev/null
@@ -1,16 +0,0 @@
-This module matches on TCP-specific fields.
-.TP
-.BI "--orig-port-src " "PORT"
-Source port in original direction
-.TP
-.BI "--orig-port-dst " "PORT"
-Destination port in original direction
-.TP
-.BI "--reply-port-src " "PORT"
-Source port in reply direction
-.TP
-.BI "--reply-port-dst " "PORT"
-Destination port in reply direction
-.TP
-.BI "--state " "[NONE|SYN_SENT|SYN_RECV|ESTABLISHED|FIN_WAIT|CLOSE_WAIT|LAST_ACK|TIME_WAIT|CLOSE|LISTEN]"
-TCP state
diff --git a/cli/extensions/libct_proto_udp.c b/cli/extensions/libct_proto_udp.c
deleted file mode 100644
index 48079e0..0000000
--- a/cli/extensions/libct_proto_udp.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
- *
- *      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 <netinet/in.h> /* For htons */
-#include "conntrack.h"
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack_udp.h>
-
-static struct option opts[] = {
-	{"orig-port-src", 1, 0, '1'},
-	{"orig-port-dst", 1, 0, '2'},
-	{"reply-port-src", 1, 0, '3'},
-	{"reply-port-dst", 1, 0, '4'},
-	{"mask-port-src", 1, 0, '5'},
-	{"mask-port-dst", 1, 0, '6'},
-	{"tuple-port-src", 1, 0, '7'},
-	{"tuple-port-dst", 1, 0, '8'},
-	{0, 0, 0, 0}
-};
-
-static void help()
-{
-	fprintf(stdout, "--orig-port-src        original source port\n");
-	fprintf(stdout, "--orig-port-dst        original destination port\n");
-	fprintf(stdout, "--reply-port-src       reply source port\n");
-	fprintf(stdout, "--reply-port-dst       reply destination port\n");
-	fprintf(stdout, "--mask-port-src	mask source port\n");
-	fprintf(stdout, "--mask-port-dst	mask destination port\n");
-	fprintf(stdout, "--tuple-port-src	expectation tuple src port\n");
-	fprintf(stdout, "--tuple-port-src	expectation tuple dst port\n");
-}
-
-static int parse_options(char c, char *argv[], 
-			 struct nfct_tuple *orig,
-			 struct nfct_tuple *reply,
-			 struct nfct_tuple *exptuple,
-			 struct nfct_tuple *mask,
-			 union nfct_protoinfo *proto,
-			 unsigned int *flags)
-{
-	switch(c) {
-		case '1':
-			if (optarg) {
-				orig->l4src.udp.port = htons(atoi(optarg));
-				*flags |= UDP_ORIG_SPORT;
-			}
-			break;
-		case '2':
-			if (optarg) {
-				orig->l4dst.udp.port = htons(atoi(optarg));
-				*flags |= UDP_ORIG_DPORT;
-			}
-			break;
-		case '3':
-			if (optarg) {
-				reply->l4src.udp.port = htons(atoi(optarg));
-				*flags |= UDP_REPL_SPORT;
-			}
-			break;
-		case '4':
-			if (optarg) {
-				reply->l4dst.udp.port = htons(atoi(optarg));
-				*flags |= UDP_REPL_DPORT;
-			}
-			break;
-		case '5':
-			if (optarg) {
-				mask->l4src.udp.port = htons(atoi(optarg));
-				*flags |= UDP_MASK_SPORT;
-			}
-			break;
-		case '6':
-			if (optarg) {
-				mask->l4dst.udp.port = htons(atoi(optarg));
-				*flags |= UDP_MASK_DPORT;
-			}
-			break;
-		case '7':
-			if (optarg) {
-				exptuple->l4src.udp.port = htons(atoi(optarg));
-				*flags |= UDP_EXPTUPLE_SPORT;
-			}
-			break;
-		case '8':
-			if (optarg) {
-				exptuple->l4dst.udp.port = htons(atoi(optarg));
-				*flags |= UDP_EXPTUPLE_DPORT;
-			}
-
-	}
-	return 1;
-}
-
-static int final_check(unsigned int flags,
-		       unsigned int command,
-		       struct nfct_tuple *orig,
-		       struct nfct_tuple *reply)
-{
-	if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) 
-	    && !(flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) {
-		reply->l4src.udp.port = orig->l4dst.udp.port;
-		reply->l4dst.udp.port = orig->l4src.udp.port;
-		return 1;
-	} else if (!(flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT))
-	            && (flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) {
-		orig->l4src.udp.port = reply->l4dst.udp.port;
-		orig->l4dst.udp.port = reply->l4src.udp.port;
-		return 1;
-	}
-	if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) 
-	    && ((flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))))
-		return 1;
-
-	return 0;
-}
-
-static struct ctproto_handler udp = {
-	.name 			= "udp",
-	.protonum		= IPPROTO_UDP,
-	.parse_opts		= parse_options,
-	.final_check		= final_check,
-	.help			= help,
-	.opts			= opts,
-	.version		= VERSION,
-};
-
-static void __attribute__ ((constructor)) init(void);
-
-static void init(void)
-{
-	register_proto(&udp);
-}
diff --git a/cli/extensions/libct_proto_udp.man b/cli/extensions/libct_proto_udp.man
deleted file mode 100644
index c67fedf..0000000
--- a/cli/extensions/libct_proto_udp.man
+++ /dev/null
@@ -1,13 +0,0 @@
-This module matches on UDP-specific fields.
-.TP
-.BI "--orig-port-src " "PORT"
-Source port in original direction
-.TP
-.BI "--orig-port-dst " "PORT"
-Destination port in original direction
-.TP
-.BI "--reply-port-src " "PORT"
-Source port in reply direction
-.TP
-.BI "--reply-port-dst " "PORT"
-Destination port in reply direction
diff --git a/cli/include/conntrack.h b/cli/include/conntrack.h
deleted file mode 100644
index fb3b9b6..0000000
--- a/cli/include/conntrack.h
+++ /dev/null
@@ -1,160 +0,0 @@
-#ifndef _CONNTRACK_H
-#define _CONNTRACK_H
-
-#ifdef HAVE_CONFIG_H
-#include "../config.h"
-#endif
-
-#include "linux_list.h"
-#include <getopt.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-
-#define PROGNAME "conntrack"
-
-#include <netinet/in.h>
-#ifndef IPPROTO_SCTP
-#define IPPROTO_SCTP 132
-#endif
-
-enum action {
-	CT_NONE		= 0,
-	
-	CT_LIST_BIT 	= 0,
-	CT_LIST 	= (1 << CT_LIST_BIT),
-	
-	CT_CREATE_BIT	= 1,
-	CT_CREATE	= (1 << CT_CREATE_BIT),
-
-	CT_UPDATE_BIT	= 2,
-	CT_UPDATE	= (1 << CT_UPDATE_BIT),
-	
-	CT_DELETE_BIT	= 3,
-	CT_DELETE	= (1 << CT_DELETE_BIT),
-	
-	CT_GET_BIT	= 4,
-	CT_GET		= (1 << CT_GET_BIT),
-
-	CT_FLUSH_BIT	= 5,
-	CT_FLUSH	= (1 << CT_FLUSH_BIT),
-
-	CT_EVENT_BIT	= 6,
-	CT_EVENT	= (1 << CT_EVENT_BIT),
-
-	CT_VERSION_BIT	= 7,
-	CT_VERSION	= (1 << CT_VERSION_BIT),
-
-	CT_HELP_BIT	= 8,
-	CT_HELP		= (1 << CT_HELP_BIT),
-
-	EXP_LIST_BIT 	= 9,
-	EXP_LIST 	= (1 << EXP_LIST_BIT),
-	
-	EXP_CREATE_BIT	= 10,
-	EXP_CREATE	= (1 << EXP_CREATE_BIT),
-	
-	EXP_DELETE_BIT	= 11,
-	EXP_DELETE	= (1 << EXP_DELETE_BIT),
-	
-	EXP_GET_BIT	= 12,
-	EXP_GET		= (1 << EXP_GET_BIT),
-
-	EXP_FLUSH_BIT	= 13,
-	EXP_FLUSH	= (1 << EXP_FLUSH_BIT),
-
-	EXP_EVENT_BIT	= 14,
-	EXP_EVENT	= (1 << EXP_EVENT_BIT),
-};
-#define NUMBER_OF_CMD   15
-
-enum options {
-	CT_OPT_ORIG_SRC_BIT	= 0,
-	CT_OPT_ORIG_SRC 	= (1 << CT_OPT_ORIG_SRC_BIT),
-	
-	CT_OPT_ORIG_DST_BIT	= 1,
-	CT_OPT_ORIG_DST		= (1 << CT_OPT_ORIG_DST_BIT),
-
-	CT_OPT_ORIG		= (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST),
-	
-	CT_OPT_REPL_SRC_BIT	= 2,
-	CT_OPT_REPL_SRC		= (1 << CT_OPT_REPL_SRC_BIT),
-	
-	CT_OPT_REPL_DST_BIT	= 3,
-	CT_OPT_REPL_DST		= (1 << CT_OPT_REPL_DST_BIT),
-
-	CT_OPT_REPL		= (CT_OPT_REPL_SRC | CT_OPT_REPL_DST),
-
-	CT_OPT_PROTO_BIT	= 4,
-	CT_OPT_PROTO		= (1 << CT_OPT_PROTO_BIT),
-
-	CT_OPT_TIMEOUT_BIT	= 5,
-	CT_OPT_TIMEOUT		= (1 << CT_OPT_TIMEOUT_BIT),
-
-	CT_OPT_STATUS_BIT	= 6,
-	CT_OPT_STATUS		= (1 << CT_OPT_STATUS_BIT),
-
-	CT_OPT_ZERO_BIT		= 7,
-	CT_OPT_ZERO		= (1 << CT_OPT_ZERO_BIT),
-
-	CT_OPT_EVENT_MASK_BIT	= 8,
-	CT_OPT_EVENT_MASK	= (1 << CT_OPT_EVENT_MASK_BIT),
-
-	CT_OPT_EXP_SRC_BIT	= 9,
-	CT_OPT_EXP_SRC		= (1 << CT_OPT_EXP_SRC_BIT),
-
-	CT_OPT_EXP_DST_BIT	= 10,
-	CT_OPT_EXP_DST		= (1 << CT_OPT_EXP_DST_BIT),
-
-	CT_OPT_MASK_SRC_BIT	= 11,
-	CT_OPT_MASK_SRC		= (1 << CT_OPT_MASK_SRC_BIT),
-
-	CT_OPT_MASK_DST_BIT	= 12,
-	CT_OPT_MASK_DST		= (1 << CT_OPT_MASK_DST_BIT),
-
-	CT_OPT_NATRANGE_BIT	= 13,
-	CT_OPT_NATRANGE		= (1 << CT_OPT_NATRANGE_BIT),
-
-	CT_OPT_MARK_BIT		= 14,
-	CT_OPT_MARK		= (1 << CT_OPT_MARK_BIT),
-
-	CT_OPT_ID_BIT		= 15,
-	CT_OPT_ID		= (1 << CT_OPT_ID_BIT),
-
-	CT_OPT_FAMILY_BIT	= 16,
-	CT_OPT_FAMILY		= (1 << CT_OPT_FAMILY_BIT),
-
-	CT_OPT_MAX_BIT		= CT_OPT_FAMILY_BIT
-};
-#define NUMBER_OF_OPT   CT_OPT_MAX_BIT+1
-
-struct ctproto_handler {
-	struct list_head 	head;
-
-	char 			*name;
-	u_int16_t 		protonum;
-	char			*version;
-
-	enum ctattr_protoinfo	protoinfo_attr;
-	
-	int (*parse_opts)(char c, char *argv[], 
-		     struct nfct_tuple *orig,
-		     struct nfct_tuple *reply,
-		     struct nfct_tuple *exptuple,
-		     struct nfct_tuple *mask,
-		     union nfct_protoinfo *proto,
-		     unsigned int *flags);
-
-	int (*final_check)(unsigned int flags,
-			   unsigned int command,
-			   struct nfct_tuple *orig,
-			   struct nfct_tuple *reply);
-
-	void (*help)();
-
-	struct option 		*opts;
-
-	unsigned int		option_offset;
-};
-
-extern void register_proto(struct ctproto_handler *h);
-
-#endif
diff --git a/cli/src/conntrack.c b/cli/src/conntrack.c
deleted file mode 100644
index 30fbf69..0000000
--- a/cli/src/conntrack.c
+++ /dev/null
@@ -1,1131 +0,0 @@
-/*
- * (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.
- *
- *      This program is distributed in the hope that it will be useful,
- *      but WITHOUT ANY WARRANTY; without even the implied warranty of
- *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *      GNU General Public License for more details.
- *
- *      You should have received a copy of the GNU General Public License
- *      along with this program; if not, write to the Free Software
- *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Note:
- *	Yes, portions of this code has been stolen from iptables ;)
- *	Special thanks to the the Netfilter Core Team.
- *	Thanks to Javier de Miguel Rodriguez <jmiguel at talika.eii.us.es>
- *	for introducing me to advanced firewalling stuff.
- *
- *						--pablo 13/04/2005
- *
- * 2005-04-16 Harald Welte <laforge@netfilter.org>: 
- * 	Add support for conntrack accounting and conntrack mark
- * 2005-06-23 Harald Welte <laforge@netfilter.org>:
- * 	Add support for expect creation
- * 2005-09-24 Harald Welte <laforge@netfilter.org>:
- * 	Remove remaints of "-A"
- *
- */
-#include <stdio.h>
-#include <sys/wait.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#include <fcntl.h>
-#include <dlfcn.h>
-#include <signal.h>
-#include <string.h>
-#include "linux_list.h"
-#include "conntrack.h"
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack_ipv4.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack_ipv6.h>
-
-static const char cmdflags[NUMBER_OF_CMD]
-= {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'};
-
-static const char cmd_need_param[NUMBER_OF_CMD]
-= { 2,  0,  0,  0,  0,  2,  2,  2,  2,  2,  0,  0,  0,  2,  2 };
-
-static const char optflags[NUMBER_OF_OPT]
-= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f'};
-
-static struct option original_opts[] = {
-	{"dump", 2, 0, 'L'},
-	{"create", 1, 0, 'I'},
-	{"delete", 1, 0, 'D'},
-	{"update", 1, 0, 'U'},
-	{"get", 1, 0, 'G'},
-	{"flush", 1, 0, 'F'},
-	{"event", 1, 0, 'E'},
-	{"version", 0, 0, 'V'},
-	{"help", 0, 0, 'h'},
-	{"orig-src", 1, 0, 's'},
-	{"orig-dst", 1, 0, 'd'},
-	{"reply-src", 1, 0, 'r'},
-	{"reply-dst", 1, 0, 'q'},
-	{"protonum", 1, 0, 'p'},
-	{"timeout", 1, 0, 't'},
-	{"status", 1, 0, 'u'},
-	{"zero", 0, 0, 'z'},
-	{"event-mask", 1, 0, 'e'},
-	{"tuple-src", 1, 0, '['},
-	{"tuple-dst", 1, 0, ']'},
-	{"mask-src", 1, 0, '{'},
-	{"mask-dst", 1, 0, '}'},
-	{"nat-range", 1, 0, 'a'},
-	{"mark", 1, 0, 'm'},
-	{"id", 2, 0, 'i'},
-	{"family", 1, 0, 'f'},
-	{0, 0, 0, 0}
-};
-
-#define OPTION_OFFSET 256
-
-static struct nfct_handle *cth;
-static struct option *opts = original_opts;
-static unsigned int global_option_offset = 0;
-
-/* Table of legal combinations of commands and options.  If any of the
- * given commands make an option legal, that option is legal (applies to
- * CMD_LIST and CMD_ZERO only).
- * Key:
- *  0  illegal
- *  1  compulsory
- *  2  optional
- */
-
-static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
-/* Well, it's better than "Re: Linux vs FreeBSD" */
-{
-          /*   s d r q p t u z e x y k l a m i f*/
-/*CT_LIST*/   {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2},
-/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0},
-/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0},
-/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0},
-/*CT_GET*/    {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0},
-/*CT_FLUSH*/  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*CT_EVENT*/  {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0},
-/*VERSION*/   {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*HELP*/      {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_LIST*/  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2},
-/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0},
-/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_GET*/   {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-};
-
-static char *lib_dir = CONNTRACK_LIB_DIR;
-
-static LIST_HEAD(proto_list);
-
-void register_proto(struct ctproto_handler *h)
-{
-	if (strcmp(h->version, VERSION) != 0) {
-		fprintf(stderr, "plugin `%s': version %s (I'm %s)\n",
-			h->name, h->version, VERSION);
-		exit(1);
-	}
-	list_add(&h->head, &proto_list);
-}
-
-static struct ctproto_handler *findproto(char *name)
-{
-	struct list_head *i;
-	struct ctproto_handler *cur = NULL, *handler = NULL;
-
-	if (!name) 
-		return handler;
-
-	lib_dir = getenv("CONNTRACK_LIB_DIR");
-	if (!lib_dir)
-		lib_dir = CONNTRACK_LIB_DIR;
-
-	list_for_each(i, &proto_list) {
-		cur = (struct ctproto_handler *) i;
-		if (strcmp(cur->name, name) == 0) {
-			handler = cur;
-			break;
-		}
-	}
-
-	if (!handler) {
-		char path[sizeof("ct_proto_.so")
-			 + strlen(name) + strlen(lib_dir)];
-                sprintf(path, "%s/ct_proto_%s.so", lib_dir, name);
-		if (dlopen(path, RTLD_NOW))
-			handler = findproto(name);
-		else
-			fprintf(stderr, "%s\n", dlerror());
-	}
-
-	return handler;
-}
-
-enum exittype {
-        OTHER_PROBLEM = 1,
-        PARAMETER_PROBLEM,
-        VERSION_PROBLEM
-};
-
-void extension_help(struct ctproto_handler *h)
-{
-	fprintf(stdout, "\n");
-	fprintf(stdout, "Proto `%s' help:\n", h->name);
-	h->help();
-}
-
-void
-exit_tryhelp(int status)
-{
-	fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
-			PROGNAME, PROGNAME);
-	exit(status);
-}
-
-static void
-exit_error(enum exittype status, char *msg, ...)
-{
-	va_list args;
-
-	/* On error paths, make sure that we don't leak the memory
-	 * reserved during options merging */
-	if (opts != original_opts) {
-		free(opts);
-		opts = original_opts;
-		global_option_offset = 0;
-	}
-	va_start(args, msg);
-	fprintf(stderr,"%s v%s: ", PROGNAME, VERSION);
-	vfprintf(stderr, msg, args);
-	va_end(args);
-	fprintf(stderr, "\n");
-	if (status == PARAMETER_PROBLEM)
-		exit_tryhelp(status);
-	exit(status);
-}
-
-static void
-generic_cmd_check(int command, int options)
-{
-	int i;
-	
-	for (i = 0; i < NUMBER_OF_CMD; i++) {
-		if (!(command & (1<<i)))
-			continue;
-
-		if (cmd_need_param[i] == 0 && !options)
-			exit_error(PARAMETER_PROBLEM,
-				   "You need to supply parameters to `-%c'\n",
-				   cmdflags[i]);
-	}
-}
-
-static void
-generic_opt_check(int command, int options)
-{
-	int i, j, legal = 0;
-
-	/* Check that commands are valid with options.  Complicated by the
-	 * fact that if an option is legal with *any* command given, it is
-	 * legal overall (ie. -z and -l).
-	 */
-	for (i = 0; i < NUMBER_OF_OPT; i++) {
-		legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
-
-		for (j = 0; j < NUMBER_OF_CMD; j++) {
-			if (!(command & (1<<j)))
-				continue;
-
-			if (!(options & (1<<i))) {
-				if (commands_v_options[j][i] == 1) 
-					exit_error(PARAMETER_PROBLEM, 
-						   "You need to supply the "
-						   "`-%c' option for this "
-						   "command\n", optflags[i]);
-			} else {
-				if (commands_v_options[j][i] != 0)
-					legal = 1;
-				else if (legal == 0)
-					legal = -1;
-			}
-		}
-		if (legal == -1)
-			exit_error(PARAMETER_PROBLEM, "Illegal option `-%c' "
-				   "with this command\n", optflags[i]);
-	}
-}
-
-static struct option *
-merge_options(struct option *oldopts, const struct option *newopts,
-	      unsigned int *option_offset)
-{
-	unsigned int num_old, num_new, i;
-	struct option *merge;
-
-	for (num_old = 0; oldopts[num_old].name; num_old++);
-	for (num_new = 0; newopts[num_new].name; num_new++);
-
-	global_option_offset += OPTION_OFFSET;
-	*option_offset = global_option_offset;
-
-	merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
-	memcpy(merge, oldopts, num_old * sizeof(struct option));
-	for (i = 0; i < num_new; i++) {
-		merge[num_old + i] = newopts[i];
-		merge[num_old + i].val += *option_offset;
-	}
-	memset(merge + num_old + num_new, 0, sizeof(struct option));
-
-	return merge;
-}
-
-/* From linux/errno.h */
-#define ENOTSUPP        524     /* Operation is not supported */
-
-/* Translates errno numbers into more human-readable form than strerror. */
-const char *
-err2str(int err, enum action command)
-{
-	unsigned int i;
-	struct table_struct {
-		enum action act;
-		int err;
-		const char *message;
-	} table [] =
-	  { { CT_LIST, -ENOTSUPP, "function not implemented" },
-	    { 0xFFFF, -EINVAL, "invalid parameters" },
-	    { CT_CREATE, -EEXIST, "Such conntrack exists, try -U to update" },
-	    { CT_CREATE|CT_GET|CT_DELETE, -ENOENT, 
-		    "such conntrack doesn't exist" },
-	    { CT_CREATE|CT_GET, -ENOMEM, "not enough memory" },
-	    { CT_GET, -EAFNOSUPPORT, "protocol not supported" },
-	    { CT_CREATE, -ETIME, "conntrack has expired" },
-	    { EXP_CREATE, -ENOENT, "master conntrack not found" },
-	    { EXP_CREATE, -EINVAL, "invalid parameters" },
-	    { ~0UL, -EPERM, "sorry, you must be root or get "
-		    	    "CAP_NET_ADMIN capability to do this"}
-	  };
-
-	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
-		if ((table[i].act & command) && table[i].err == err)
-			return table[i].message;
-	}
-
-	return strerror(err);
-}
-
-#define PARSE_STATUS 0
-#define PARSE_EVENT 1
-#define PARSE_MAX 2
-
-static struct parse_parameter {
-	char 	*parameter[6];
-	size_t  size;
-	unsigned int value[6];
-} parse_array[PARSE_MAX] = {
-	{ {"ASSURED", "SEEN_REPLY", "UNSET", "SRC_NAT", "DST_NAT","FIXED_TIMEOUT"}, 6,
-	  { IPS_ASSURED, IPS_SEEN_REPLY, 0, 
-	    IPS_SRC_NAT_DONE, IPS_DST_NAT_DONE, IPS_FIXED_TIMEOUT} },
-	{ {"ALL", "NEW", "UPDATES", "DESTROY"}, 4,
-	  {~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE, 
-	   NF_NETLINK_CONNTRACK_DESTROY} },
-};
-
-static int
-do_parse_parameter(const char *str, size_t strlen, unsigned int *value, 
-		   int parse_type)
-{
-	int i, ret = 0;
-	struct parse_parameter *p = &parse_array[parse_type];
-	
-	for (i = 0; i < p->size; i++)
-		if (strncasecmp(str, p->parameter[i], strlen) == 0) {
-			*value |= p->value[i];
-			ret = 1;
-			break;
-		}
-	
-	return ret;
-}
-
-static void
-parse_parameter(const char *arg, unsigned int *status, int parse_type)
-{
-	const char *comma;
-
-	while ((comma = strchr(arg, ',')) != NULL) {
-		if (comma == arg 
-		    || !do_parse_parameter(arg, comma-arg, status, parse_type))
-			exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg);
-		arg = comma+1;
-	}
-
-	if (strlen(arg) == 0
-	    || !do_parse_parameter(arg, strlen(arg), status, parse_type))
-		exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg);
-}
-
-static void
-add_command(unsigned int *cmd, const int newcmd, const int othercmds)
-{
-	if (*cmd & (~othercmds))
-		exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n");
-	*cmd |= newcmd;
-}
-
-unsigned int check_type(int argc, char *argv[])
-{
-	char *table = NULL;
-
-	/* Nasty bug or feature in getopt_long ? 
-	 * It seems that it behaves badly with optional arguments.
-	 * Fortunately, I just stole the fix from iptables ;) */
-	if (optarg)
-		return 0;
-	else if (optind < argc && argv[optind][0] != '-' 
-			&& argv[optind][0] != '!')
-		table = argv[optind++];
-	
-	if (!table)
-		return 0;
-		
-	if (strncmp("expect", table, 6) == 0)
-		return 1;
-	else if (strncmp("conntrack", table, 9) == 0)
-		return 0;
-	else
-		exit_error(PARAMETER_PROBLEM, "unknown type `%s'\n", table);
-
-	return 0;
-}
-
-static void set_family(int *family, int new)
-{
-	if (*family == AF_UNSPEC)
-		*family = new;
-	else if (*family != new)
-		exit_error(PARAMETER_PROBLEM, "mismatched address family\n");
-}
-
-struct addr_parse {
-	struct in_addr addr;
-	struct in6_addr addr6;
-	unsigned int family;
-};
-
-int __parse_inetaddr(const char *cp, struct addr_parse *parse)
-{
-	if (inet_aton(cp, &parse->addr))
-		return AF_INET;
-#ifdef HAVE_INET_PTON_IPV6
-	else if (inet_pton(AF_INET6, cp, &parse->addr6) > 0)
-		return AF_INET6;
-#endif
-
-	exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp);
-}
-
-int parse_inetaddr(const char *cp, union nfct_address *address)
-{
-	struct addr_parse parse;
-	int ret;
-	
-	if ((ret = __parse_inetaddr(cp, &parse)) == AF_INET)
-		address->v4 = parse.addr.s_addr;
-	else if (ret == AF_INET6)
-		memcpy(address->v6, &parse.addr6, sizeof(parse.addr6));
-
-	return ret;
-}
-
-/* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */
-static void
-nat_parse(char *arg, int portok, struct nfct_nat *range)
-{
-	char *colon, *dash, *error;
-	struct addr_parse parse;
-
-	memset(range, 0, sizeof(range));
-	colon = strchr(arg, ':');
-
-	if (colon) {
-		int port;
-
-		if (!portok)
-			exit_error(PARAMETER_PROBLEM,
-				   "Need TCP or UDP with port specification");
-
-		port = atoi(colon+1);
-		if (port == 0 || port > 65535)
-			exit_error(PARAMETER_PROBLEM,
-				   "Port `%s' not valid\n", colon+1);
-
-		error = strchr(colon+1, ':');
-		if (error)
-			exit_error(PARAMETER_PROBLEM,
-				   "Invalid port:port syntax - use dash\n");
-
-		dash = strchr(colon, '-');
-		if (!dash) {
-			range->l4min.tcp.port
-				= range->l4max.tcp.port
-				= htons(port);
-		} else {
-			int maxport;
-
-			maxport = atoi(dash + 1);
-			if (maxport == 0 || maxport > 65535)
-				exit_error(PARAMETER_PROBLEM,
-					   "Port `%s' not valid\n", dash+1);
-			if (maxport < port)
-				/* People are stupid.  */
-				exit_error(PARAMETER_PROBLEM,
-					   "Port range `%s' funky\n", colon+1);
-			range->l4min.tcp.port = htons(port);
-			range->l4max.tcp.port = htons(maxport);
-		}
-		/* Starts with a colon? No IP info... */
-		if (colon == arg)
-			return;
-		*colon = '\0';
-	}
-
-	dash = strchr(arg, '-');
-	if (colon && dash && dash > colon)
-		dash = NULL;
-
-	if (dash)
-		*dash = '\0';
-
-	if (__parse_inetaddr(arg, &parse) != AF_INET)
-		return;
-
-	range->min_ip = parse.addr.s_addr;
-	if (dash) {
-		if (__parse_inetaddr(dash+1, &parse) != AF_INET)
-			return;
-		range->max_ip = parse.addr.s_addr;
-	} else
-		range->max_ip = parse.addr.s_addr;
-}
-
-static void event_sighandler(int s)
-{
-	fprintf(stdout, "Now closing conntrack event dumping...\n");
-	nfct_close(cth);
-	exit(0);
-}
-
-static const char usage_commands[] =
-	"Commands:\n"
-	"  -L [table] [options]\t\tList conntrack or expectation table\n"
-	"  -G [table] parameters\t\tGet conntrack or expectation\n"
-	"  -D [table] parameters\t\tDelete conntrack or expectation\n"
-	"  -I [table] parameters\t\tCreate a conntrack or expectation\n"
-	"  -U [table] parameters\t\tUpdate a conntrack\n"
-	"  -E [table] [options]\t\tShow events\n"
-	"  -F [table]\t\t\tFlush table\n";
-
-static const char usage_tables[] =
-	"Tables: conntrack, expect\n";
-
-static const char usage_conntrack_parameters[] =
-	"Conntrack parameters and options:\n"
-	"  -a, --nat-range min_ip[-max_ip]\tNAT ip range\n"
-	"  -m, --mark mark\t\t\tSet mark\n"
-	"  -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n"
-	"  -z, --zero \t\t\t\tZero counters while listing\n"
-	;
-
-static const char usage_expectation_parameters[] =
-	"Expectation parameters and options:\n"
-	"  --tuple-src ip\tSource address in expect tuple\n"
-	"  --tuple-dst ip\tDestination address in expect tuple\n"
-	"  --mask-src ip\t\tSource mask address\n"
-	"  --mask-dst ip\t\tDestination mask address\n";
-
-static const char usage_parameters[] =
-	"Common parameters and options:\n"
-	"  -s, --orig-src ip\t\tSource address from original direction\n"
-	"  -d, --orig-dst ip\t\tDestination address from original direction\n"
-	"  -r, --reply-src ip\t\tSource addres from reply direction\n"
-	"  -q, --reply-dst ip\t\tDestination address from reply direction\n"
-	"  -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n"
-	"  -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n"
-	"  -t, --timeout timeout\t\tSet timeout\n"
-	"  -u, --status status\t\tSet status, eg. ASSURED\n"
-	"  -i, --id [id]\t\t\tShow or set conntrack ID\n"
-	;
-  
-
-void usage(char *prog) {
-	fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION);
-	fprintf(stdout, "Usage: %s [commands] [options]\n", prog);
-
-	fprintf(stdout, "\n%s", usage_commands);
-	fprintf(stdout, "\n%s", usage_tables);
-	fprintf(stdout, "\n%s", usage_conntrack_parameters);
-	fprintf(stdout, "\n%s", usage_expectation_parameters);
-	fprintf(stdout, "\n%s", usage_parameters);
-}
-
-#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK)
-
-static struct nfct_tuple orig, reply, mask;
-static struct nfct_tuple exptuple;
-static struct ctproto_handler *h;
-static union nfct_protoinfo proto;
-static struct nfct_nat range;
-static struct nfct_conntrack *ct;
-static struct nfct_expect *exp;
-static unsigned long timeout;
-static unsigned int status;
-static unsigned int mark;
-static unsigned int id = NFCT_ANY_ID;
-static struct nfct_conntrack_compare cmp;
-
-int main(int argc, char *argv[])
-{
-	int c;
-	unsigned int command = 0, options = 0;
-	unsigned int type = 0, event_mask = 0;
-	unsigned int l3flags = 0, l4flags = 0, metaflags = 0;
-	int res = 0;
-	int family = AF_UNSPEC;
-	struct nfct_conntrack_compare *pcmp;
-
-	while ((c = getopt_long(argc, argv, 
-		"L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:", 
-		opts, NULL)) != -1) {
-	switch(c) {
-		case 'L':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_LIST, CT_NONE);
-			else if (type == 1)
-				add_command(&command, EXP_LIST, CT_NONE);
-			break;
-		case 'I':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_CREATE, CT_NONE);
-			else if (type == 1)
-				add_command(&command, EXP_CREATE, CT_NONE);
-			break;
-		case 'U':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_UPDATE, CT_NONE);
-			else
-				exit_error(PARAMETER_PROBLEM, "Can't update "
-					   "expectations");
-			break;
-		case 'D':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_DELETE, CT_NONE);
-			else if (type == 1)
-				add_command(&command, EXP_DELETE, CT_NONE);
-			break;
-		case 'G':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_GET, CT_NONE);
-			else if (type == 1)
-				add_command(&command, EXP_GET, CT_NONE);
-			break;
-		case 'F':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_FLUSH, CT_NONE);
-			else if (type == 1)
-				add_command(&command, EXP_FLUSH, CT_NONE);
-			break;
-		case 'E':
-			type = check_type(argc, argv);
-			if (type == 0)
-				add_command(&command, CT_EVENT, CT_NONE);
-			else if (type == 1)
-				add_command(&command, EXP_EVENT, CT_NONE);
-			break;
-		case 'V':
-			add_command(&command, CT_VERSION, CT_NONE);
-			break;
-		case 'h':
-			add_command(&command, CT_HELP, CT_NONE);
-			break;
-		case 's':
-			options |= CT_OPT_ORIG_SRC;
-			if (optarg) {
-				orig.l3protonum =
-					parse_inetaddr(optarg, &orig.src);
-				set_family(&family, orig.l3protonum);
-				if (orig.l3protonum == AF_INET)
-					l3flags |= IPV4_ORIG_SRC;
-				else if (orig.l3protonum == AF_INET6)
-					l3flags |= IPV6_ORIG_SRC;
-			}
-			break;
-		case 'd':
-			options |= CT_OPT_ORIG_DST;
-			if (optarg) {
-				orig.l3protonum = 
-					parse_inetaddr(optarg, &orig.dst);
-				set_family(&family, orig.l3protonum);
-				if (orig.l3protonum == AF_INET)
-					l3flags |= IPV4_ORIG_DST;
-				else if (orig.l3protonum == AF_INET6)
-					l3flags |= IPV6_ORIG_DST;
-			}
-			break;
-		case 'r':
-			options |= CT_OPT_REPL_SRC;
-			if (optarg) {
-				reply.l3protonum = 
-					parse_inetaddr(optarg, &reply.src);
-				set_family(&family, reply.l3protonum);
-				if (orig.l3protonum == AF_INET)
-					l3flags |= IPV4_REPL_SRC;
-				else if (orig.l3protonum == AF_INET6)
-					l3flags |= IPV6_REPL_SRC;
-			}
-			break;
-		case 'q':
-			options |= CT_OPT_REPL_DST;
-			if (optarg) {
-				reply.l3protonum = 
-					parse_inetaddr(optarg, &reply.dst);
-				set_family(&family, reply.l3protonum);
-				if (orig.l3protonum == AF_INET)
-					l3flags |= IPV4_REPL_DST;
-				else if (orig.l3protonum == AF_INET6)
-					l3flags |= IPV6_REPL_DST;
-			}
-			break;
-		case 'p':
-			options |= CT_OPT_PROTO;
-			h = findproto(optarg);
-			if (!h)
-				exit_error(PARAMETER_PROBLEM, "proto needed\n");
-			orig.protonum = h->protonum;
-			reply.protonum = h->protonum;
-			exptuple.protonum = h->protonum;
-			mask.protonum = h->protonum;
-			opts = merge_options(opts, h->opts, 
-					     &h->option_offset);
-			break;
-		case 't':
-			options |= CT_OPT_TIMEOUT;
-			if (optarg)
-				timeout = atol(optarg);
-			break;
-		case 'u': {
-			if (!optarg)
-				continue;
-
-			options |= CT_OPT_STATUS;
-			parse_parameter(optarg, &status, PARSE_STATUS);
-			break;
-		}
-		case 'e':
-			options |= CT_OPT_EVENT_MASK;
-			parse_parameter(optarg, &event_mask, PARSE_EVENT);
-			break;
-		case 'z':
-			options |= CT_OPT_ZERO;
-			break;
-		case '{':
-			options |= CT_OPT_MASK_SRC;
-			if (optarg) {
-				mask.l3protonum = 
-					parse_inetaddr(optarg, &mask.src);
-				set_family(&family, mask.l3protonum);
-			}
-			break;
-		case '}':
-			options |= CT_OPT_MASK_DST;
-			if (optarg) {
-				mask.l3protonum = 
-					parse_inetaddr(optarg, &mask.dst);
-				set_family(&family, mask.l3protonum);
-			}
-			break;
-		case '[':
-			options |= CT_OPT_EXP_SRC;
-			if (optarg) {
-				exptuple.l3protonum = 
-					parse_inetaddr(optarg, &exptuple.src);
-				set_family(&family, exptuple.l3protonum);
-			}
-			break;
-		case ']':
-			options |= CT_OPT_EXP_DST;
-			if (optarg) {
-				exptuple.l3protonum = 
-					parse_inetaddr(optarg, &exptuple.dst);
-				set_family(&family, exptuple.l3protonum);
-			}
-			break;
-		case 'a':
-			options |= CT_OPT_NATRANGE;
-			set_family(&family, AF_INET);
-			nat_parse(optarg, 1, &range);
-			break;
-		case 'm':
-			options |= CT_OPT_MARK;
-			mark = atol(optarg);
-			metaflags |= NFCT_MARK;
-			break;
-		case 'i': {
-			char *s = NULL;
-			options |= CT_OPT_ID;
-			if (optarg)
-				break;
-			else if (optind < argc && argv[optind][0] != '-'
-					&& argv[optind][0] != '!')
-				s = argv[optind++];
-
-			if (s)
-				id = atol(s);
-			break;
-		}
-		case 'f':
-			options |= CT_OPT_FAMILY;
-			if (strncmp(optarg, "ipv4", strlen("ipv4")) == 0)
-				set_family(&family, AF_INET);
-			else if (strncmp(optarg, "ipv6", strlen("ipv6")) == 0)
-				set_family(&family, AF_INET6);
-			else
-				exit_error(PARAMETER_PROBLEM, "Unknown "
-					   "protocol family\n");
-			break;
-		default:
-			if (h && h->parse_opts 
-			    &&!h->parse_opts(c - h->option_offset, argv, &orig, 
-				             &reply, &exptuple, &mask, &proto, 
-					     &l4flags))
-				exit_error(PARAMETER_PROBLEM, "parse error\n");
-
-			/* Unknown argument... */
-			if (!h) {
-				usage(argv[0]);
-				exit_error(PARAMETER_PROBLEM, "Missing "
-					   "arguments...\n");
-			}
-			break;
-		}
-	}
-
-	/* default family */
-	if (family == AF_UNSPEC)
-		family = AF_INET;
-
-	generic_cmd_check(command, options);
-	generic_opt_check(command, options);
-
-	if (!(command & CT_HELP)
-	    && h && h->final_check 
-	    && !h->final_check(l4flags, command, &orig, &reply)) {
-		usage(argv[0]);
-		extension_help(h);
-		exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n");
-	}
-
-	switch(command) {
-
-	case CT_LIST:
-		cth = nfct_open(CONNTRACK, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-
-		if (options & CT_COMPARISON) {
-
-			if (options & CT_OPT_ZERO)
-				exit_error(PARAMETER_PROBLEM, "Can't use -z "
-					   "with filtering parameters");
-
-			ct = nfct_conntrack_alloc(&orig, &reply, timeout,
-						  &proto, status, mark, id,
-						  NULL);
-			if (!ct)
-				exit_error(OTHER_PROBLEM, "Not enough memory");
-			
-			cmp.ct = ct;
-			cmp.flags = metaflags;
-			cmp.l3flags = l3flags;
-			cmp.l4flags = l4flags;
-			pcmp = &cmp;
-		}
-
-		if (options & CT_OPT_ID)
-			nfct_register_callback(cth, 
-					nfct_default_conntrack_display_id,
-					(void *) pcmp);
-		else
-			nfct_register_callback(cth,
-					nfct_default_conntrack_display,
-					(void *) pcmp);
-			
-		if (options & CT_OPT_ZERO)
-			res = 
-			nfct_dump_conntrack_table_reset_counters(cth, family);
-		else
-			res = nfct_dump_conntrack_table(cth, family);
-		nfct_close(cth);
-		break;
-
-	case EXP_LIST:
-		cth = nfct_open(EXPECT, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		if (options & CT_OPT_ID)
-			nfct_register_callback(cth, 
-					nfct_default_expect_display_id,
-					NULL);
-		else
-			nfct_register_callback(cth,
-					nfct_default_expect_display,
-					NULL);
-		res = nfct_dump_expect_list(cth, family);
-		nfct_close(cth);
-		break;
-			
-	case CT_CREATE:
-		if ((options & CT_OPT_ORIG) 
-		    && !(options & CT_OPT_REPL)) {
-			reply.l3protonum = orig.l3protonum;
-			memcpy(&reply.src, &orig.dst, sizeof(reply.src));
-			memcpy(&reply.dst, &orig.src, sizeof(reply.dst));
-		} else if (!(options & CT_OPT_ORIG)
-			   && (options & CT_OPT_REPL)) {
-			orig.l3protonum = reply.l3protonum;
-			memcpy(&orig.src, &reply.dst, sizeof(orig.src));
-			memcpy(&orig.dst, &reply.src, sizeof(orig.dst));
-		}
-		if (options & CT_OPT_NATRANGE)
-			ct = nfct_conntrack_alloc(&orig, &reply, timeout, 
-						  &proto, status, mark, id,
-						  &range);
-		else
-			ct = nfct_conntrack_alloc(&orig, &reply, timeout, 
-						  &proto, status, mark, id,
-						  NULL);
-		if (!ct)
-			exit_error(OTHER_PROBLEM, "Not Enough memory");
-		
-		cth = nfct_open(CONNTRACK, 0);
-		if (!cth) {
-			nfct_conntrack_free(ct);
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		}
-		res = nfct_create_conntrack(cth, ct);
-		nfct_close(cth);
-		nfct_conntrack_free(ct);
-		break;
-
-	case EXP_CREATE:
-		if (options & CT_OPT_ORIG)
-			exp = nfct_expect_alloc(&orig, &exptuple,
-						&mask, timeout, id);
-		else if (options & CT_OPT_REPL)
-			exp = nfct_expect_alloc(&reply, &exptuple,
-						&mask, timeout, id);
-		if (!exp)
-			exit_error(OTHER_PROBLEM, "Not enough memory");
-
-		cth = nfct_open(EXPECT, 0);
-		if (!cth) {
-			nfct_expect_free(exp);
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		}
-		res = nfct_create_expectation(cth, exp);
-		nfct_expect_free(exp);
-		nfct_close(cth);
-		break;
-
-	case CT_UPDATE:
-		if ((options & CT_OPT_ORIG) 
-		    && !(options & CT_OPT_REPL)) {
-			reply.l3protonum = orig.l3protonum;
-			memcpy(&reply.src, &orig.dst, sizeof(reply.src));
-			memcpy(&reply.dst, &orig.src, sizeof(reply.dst));
-		} else if (!(options & CT_OPT_ORIG)
-			   && (options & CT_OPT_REPL)) {
-			orig.l3protonum = reply.l3protonum;
-			memcpy(&orig.src, &reply.dst, sizeof(orig.src));
-			memcpy(&orig.dst, &reply.src, sizeof(orig.dst));
-		}
-		ct = nfct_conntrack_alloc(&orig, &reply, timeout,
-					  &proto, status, mark, id,
-					  NULL);
-		if (!ct)
-			exit_error(OTHER_PROBLEM, "Not enough memory");
-		
-		cth = nfct_open(CONNTRACK, 0);
-		if (!cth) {
-			nfct_conntrack_free(ct);
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		}
-		res = nfct_update_conntrack(cth, ct);
-		nfct_conntrack_free(ct);
-		nfct_close(cth);
-		break;
-		
-	case CT_DELETE:
-		if (!(options & CT_OPT_ORIG) && !(options & CT_OPT_REPL))
-			exit_error(PARAMETER_PROBLEM, "Can't kill conntracks "
-						      "just by its ID");
-		cth = nfct_open(CONNTRACK, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		if (options & CT_OPT_ORIG)
-			res = nfct_delete_conntrack(cth, &orig, 
-						    NFCT_DIR_ORIGINAL,
-						    id);
-		else if (options & CT_OPT_REPL)
-			res = nfct_delete_conntrack(cth, &reply, 
-						    NFCT_DIR_REPLY,
-						    id);
-		nfct_close(cth);
-		break;
-
-	case EXP_DELETE:
-		cth = nfct_open(EXPECT, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		if (options & CT_OPT_ORIG)
-			res = nfct_delete_expectation(cth, &orig, id);
-		else if (options & CT_OPT_REPL)
-			res = nfct_delete_expectation(cth, &reply, id);
-		nfct_close(cth);
-		break;
-
-	case CT_GET:
-		cth = nfct_open(CONNTRACK, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		nfct_register_callback(cth, nfct_default_conntrack_display,
-					NULL);
-		if (options & CT_OPT_ORIG)
-			res = nfct_get_conntrack(cth, &orig,
-						 NFCT_DIR_ORIGINAL, id);
-		else if (options & CT_OPT_REPL)
-			res = nfct_get_conntrack(cth, &reply,
-						 NFCT_DIR_REPLY, id);
-		nfct_close(cth);
-		break;
-
-	case EXP_GET:
-		cth = nfct_open(EXPECT, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		nfct_register_callback(cth, nfct_default_expect_display,
-					NULL);
-		if (options & CT_OPT_ORIG)
-			res = nfct_get_expectation(cth, &orig, id);
-		else if (options & CT_OPT_REPL)
-			res = nfct_get_expectation(cth, &reply, id);
-		nfct_close(cth);
-		break;
-
-	case CT_FLUSH:
-		cth = nfct_open(CONNTRACK, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		res = nfct_flush_conntrack_table(cth, AF_INET);
-		nfct_close(cth);
-		break;
-
-	case EXP_FLUSH:
-		cth = nfct_open(EXPECT, 0);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		res = nfct_flush_expectation_table(cth, AF_INET);
-		nfct_close(cth);
-		break;
-		
-	case CT_EVENT:
-		if (options & CT_OPT_EVENT_MASK)
-			cth = nfct_open(CONNTRACK, event_mask);
-		else
-			cth = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS);
-
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		signal(SIGINT, event_sighandler);
-
-		if (options & CT_COMPARISON) {
-			ct = nfct_conntrack_alloc(&orig, &reply, timeout,
-						  &proto, status, mark, id, 
-						  NULL);
-			if (!ct)
-				exit_error(OTHER_PROBLEM, "Not enough memory");
-
-			cmp.ct = ct;
-			cmp.flags = metaflags;
-			cmp.l3flags = l3flags;
-			cmp.l4flags = l4flags;
-			pcmp = &cmp;
-		}
-
-		nfct_register_callback(cth,
-				       nfct_default_conntrack_event_display, 
-				       (void *) pcmp);
-		res = nfct_event_conntrack(cth);
-		nfct_close(cth);
-		break;
-
-	case EXP_EVENT:
-		cth = nfct_open(EXPECT, NF_NETLINK_CONNTRACK_EXP_NEW);
-		if (!cth)
-			exit_error(OTHER_PROBLEM, "Can't open handler");
-		signal(SIGINT, event_sighandler);
-		nfct_register_callback(cth, nfct_default_expect_display,
-					NULL);
-		res = nfct_event_expectation(cth);
-		nfct_close(cth);
-		break;
-			
-	case CT_VERSION:
-		fprintf(stdout, "%s v%s\n", PROGNAME, VERSION);
-		break;
-	case CT_HELP:
-		usage(argv[0]);
-		if (options & CT_OPT_PROTO)
-			extension_help(h);
-		break;
-	default:
-		usage(argv[0]);
-		break;
-	}
-
-	if (opts != original_opts) {
-		free(opts);
-		opts = original_opts;
-		global_option_offset = 0;
-	}
-
-	if (res < 0) {
-		fprintf(stderr, "Operation failed: %s\n", err2str(res, command));
-		exit(OTHER_PROBLEM);
-	}
-
-	return 0;
-}
diff --git a/cli/test.sh b/cli/test.sh
deleted file mode 100644
index 4694236..0000000
--- a/cli/test.sh
+++ /dev/null
@@ -1,110 +0,0 @@
-CONNTRACK=conntrack
-
-SRC=1.1.1.1
-DST=2.2.2.2
-SPORT=2005
-DPORT=21
-
-case $1 in
-	dump)
-		echo "Dumping conntrack table"
-		$CONNTRACK -L
-		;;
-	flush)
-		echo "Flushing conntrack table"
-		$CONNTRACK -F
-		;;
-	new)
-		echo "creating a new conntrack"
-		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
-		 --reply-src $DST --reply-dst $SRC -p tcp \
-		 --orig-port-src $SPORT  --orig-port-dst $DPORT \
-		 --reply-port-src $DPORT --reply-port-dst $SPORT \
-		--state LISTEN -u SEEN_REPLY -t 50
-		;;
-	new-simple)
-		echo "creating a new conntrack (simplified)"
-		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
-		-p tcp --orig-port-src $SPORT  --orig-port-dst $DPORT \
-		--state LISTEN -u SEEN_REPLY -t 50
-		;;
-	new-nat)
-		echo "creating a new conntrack (NAT)"
-		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
-		-p tcp --orig-port-src $SPORT  --orig-port-dst $DPORT \
-		--state LISTEN -u SEEN_REPLY,SRC_NAT -t 50 -a 8.8.8.8
-		;;
-	get)
-		echo "getting a conntrack"
-		$CONNTRACK -G --orig-src $SRC --orig-dst $DST \
-		-p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \
-		--reply-port-src $DPORT --reply-port-dst $SPORT
-		;;
-	change)
-		echo "change a conntrack"
-		$CONNTRACK -U --orig-src $SRC --orig-dst $DST \
-		--reply-src $DST --reply-dst $SRC -p tcp \
-		--orig-port-src $SPORT --orig-port-dst $DPORT \
-		--reply-port-src $DPORT --reply-port-dst $SPORT \
-		--state TIME_WAIT -u ASSURED,SEEN_REPLY -t 500
-		;;
-	delete)
-		$CONNTRACK -D --orig-src $SRC --orig-dst $DST \
-		-p tcp --orig-port-src $SPORT --orig-port-dst $DPORT
-		;;
-	output)
-		proc=$(cat /proc/net/ip_conntrack | wc -l)
-		netl=$($CONNTRACK -L | wc -l)
-		count=$(cat /proc/sys/net/ipv4/netfilter/ip_conntrack_count)
-		if [ $proc -ne $netl ]; then
-			echo "proc is $proc and netl is $netl and count is $count"
-		else
-			if [ $proc -ne $count ]; then
-				echo "proc is $proc and netl is $netl and count is $count"
-			else
-				echo "now $proc"
-			fi
-		fi
-		;;
-	dump-expect)
-		$CONNTRACK -L expect
-		;;
-	flush-expect)
-		$CONNTRACK -F expect
-		;;
-	create-expect)
-		# requires modprobe ip_conntrack_ftp
-		$CONNTRACK -I expect --orig-src $SRC --orig-dst $DST \
-		--tuple-src 4.4.4.4 --tuple-dst 5.5.5.5 \
-		--mask-src 255.255.255.0 --mask-dst 255.255.255.255 \
-		-p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \
-		-t 200 --tuple-port-src 10 --tuple-port-dst 300 \
-		--mask-port-src 10 --mask-port-dst 300
-		;;
-	get-expect)
-		$CONNTRACK -G expect --orig-src 4.4.4.4 --orig-dst 5.5.5.5 \
-		--p tcp --orig-port-src 0 --orig-port-dst 0 \
-		--mask-port-src 10 --mask-port-dst 11
-		;;
-	delete-expect)
-		$CONNTRACK -D expect --orig-src 4.4.4.4 \
-		--orig-dst 5.5.5.5 -p tcp --orig-port-src 0 \
-		--orig-port-dst 0 --mask-port-src 10 --mask-port-dst 11
-		;;
-	*)
-		echo "Usage: $0 [dump"
-		echo "		|new"
-		echo "		|new-simple"
-		echo "		|new-nat"
-		echo "		|get"
-		echo "		|change"
-		echo "		|delete"
-		echo "		|output"
-		echo "		|flush"
-		echo "		|dump-expect"
-		echo "		|flush-expect"
-		echo "		|create-expect"
-		echo "		|get-expect"
-		echo "		|delete-expect]"
-		;;
-esac
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..5bd9815
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,106 @@
+AC_INIT(conntrackd, 0.9.2, pablo@netfilter.org)
+
+AC_CANONICAL_SYSTEM
+
+AM_INIT_AUTOMAKE
+
+AC_PROG_CC
+AM_PROG_LIBTOOL
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AM_PROG_LEX
+AC_PROG_YACC
+
+case $target in
+*-*-linux*) ;;
+*) AC_MSG_ERROR([Linux only, dude!]);;
+esac
+
+AC_CHECK_PROGS(XYACC,$YACC bison yacc,none)
+if test "$XYACC" = "none"
+then
+	echo "*** Error: No suitable bison/yacc found. ***"
+	echo "    Please install the 'bison' package."
+	exit 1
+fi
+AC_CHECK_PROGS(XLEX,$LEX flex lex,none)
+if test "$XLEX" = "none"
+then
+	echo "*** Error: No suitable bison/yacc found. ***"
+	echo "    Please install the 'bison' package."
+	exit 1
+fi
+
+AC_CHECK_HEADERS([linux/capability.h],, [AC_MSG_ERROR([Cannot find linux/capabibility.h])])
+
+# Checks for libraries.
+# FIXME: Replace `main' with a function in `-lc':
+dnl AC_CHECK_LIB([c], [main])
+# FIXME: Replace `main' with a function in `-ldl':
+
+AC_CHECK_LIB([nfnetlink], [nfnl_talk] ,,,[-lnfnetlink])
+AC_CHECK_LIB([netfilter_conntrack], [nfct_dump_conntrack_table] ,,,[-lnetfilter_conntrack])
+AC_CHECK_LIB([pthread], [pthread_create] ,,,[-lpthread])
+
+AC_CHECK_HEADERS(arpa/inet.h)
+dnl check for inet_pton
+AC_CHECK_FUNCS(inet_pton)
+dnl Some systems have it, but not IPv6
+if test "$ac_cv_func_inet_pton" = "yes" ; then
+AC_MSG_CHECKING(if inet_pton supports IPv6)
+AC_TRY_RUN(
+   [
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+int main()
+  {
+     struct in6_addr addr6;
+     if (inet_pton(AF_INET6, "::1", &addr6) < 1)
+        exit(1);
+     else
+        exit(0);
+  }
+  ], [ AC_MSG_RESULT(yes)
+       AC_DEFINE_UNQUOTED(HAVE_INET_PTON_IPV6, 1, [Define to 1 if inet_pton supports IPv6.])
+  ], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+fi
+
+# Checks for header files.
+dnl AC_HEADER_STDC
+dnl AC_CHECK_HEADERS([netinet/in.h stdlib.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+dnl AC_C_CONST
+dnl AC_C_INLINE
+
+# Checks for library functions.
+dnl AC_FUNC_MALLOC
+dnl AC_FUNC_VPRINTF
+dnl AC_CHECK_FUNCS([memset])
+
+dnl--------------------------------
+
+if test ! -z "$libdir"; then
+   MODULE_DIR="\\\"$libdir/conntrack/\\\""
+   CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR"
+fi
+
+dnl--------------------------------
+
+dnl AC_CONFIG_FILES([Makefile
+dnl                  debug/Makefile
+dnl                  debug/src/Makefile
+dnl                  extensions/Makefile
+dnl                  src/Makefile])
+
+AC_OUTPUT(Makefile src/Makefile include/Makefile extensions/Makefile examples/Makefile examples/stats/Makefile examples/sync/Makefile examples/sync/persistent/Makefile examples/sync/nack/Makefile examples/sync/persistent/node1/Makefile examples/sync/persistent/node2/Makefile examples/sync/nack/node1/Makefile examples/sync/nack/node2/Makefile)
diff --git a/conntrack.8 b/conntrack.8
new file mode 100644
index 0000000..307180b
--- /dev/null
+++ b/conntrack.8
@@ -0,0 +1,142 @@
+.TH CONNTRACK 8 "Jun 23, 2005" "" ""
+
+.\" Man page written by Harald Welte <laforge@netfilter.org (Jun 2005)
+
+.SH NAME
+conntrack \- administration tool for netfilter connection tracking
+.SH SYNOPSIS
+.BR "conntrack -L [table] [-z]"
+.br
+.BR "conntrack -G [table] parameters"
+.br
+.BR "conntrack -D [table] paramaters"
+.br
+.BR "conntrack -I [table] parameters"
+.br
+.BR "conntrack -E [table] parameters"
+.br
+.BR "conntrack -F [table]"
+.SH DESCRIPTION
+.B conntrack
+is used to search, list, inspect and maintain the netfilter connection tracking
+subsystem of the Linux kernel.
+.PP
+Using 
+.B conntrack
+, you can dump a list of all (or a filtered selection of) currently tracked
+connections, delete connections from the state table, and even add new ones.
+.PP
+In addition, you can also monitor connection tracking events, e.g. show an
+event message (one line) per newly established connection.
+.SH TABLES
+The connection tracking subsystem maintains two internal tables:
+.TP
+.BR "conntrack" :
+This is the default table.  It contains a list of all currently tracked
+connections through the system.  If you don't use connection tracking
+exemptions (NOTRACK iptables target), this means all connections that go
+through the system.
+.TP
+.BR "expect" :
+This is the table of expectations.  Connection tracking expectations are the
+mechanism used to "expect" RELATED connections to existing ones.  Expectations
+are generally used by "connection tracking helpers" (sometimes called
+application level gateways [ALGs]) for more complex protocols such as FTP,
+SIP, H.323.
+.SH OPTIONS
+The options recognized by 
+.B conntrack
+can be divided into several different groups.
+.SS COMMANDS
+These options specify the particular operation to perform.  Only one of them
+can be specified at any given time.
+.TP
+.BI "-L --dump "
+List connection tacking or expectation table
+.TP
+.BI "-G, --get "
+Search for and show a particular (matching) entry in the given table.
+.TP
+.BI "-D, --delete "
+Delete an entry from the given table.
+.TP
+.BI "-I, --create "
+Create a new entry from the given table.
+.TP
+.BI "-E, --event "
+Display a real-time event log.
+.TP
+.BI "-F, --flush "
+Flush the whole given table
+.SS PARAMETERS
+.TP
+.BI "-z, --zero "
+Atomically zero counters after reading them.  This option is only valid in
+combination with the "-L, --dump" command options.
+.TP
+.BI "-e, --event-mask " "[ALL|NEW|UPDATES|DESTROY][,...]"
+Set the bitmask of events that are to be generated by the in-kernel ctnetlink
+event code.  Using this parameter, you can reduce the event messages generated
+by the kernel to those types to those that you are actually interested in.
+.
+This option can only be used in conjunction with "-E, --event".
+.SS FILTER PARAMETERS
+.TP
+.BI "-s, --orig-src " IP_ADDRESS
+Match only entries whose source address in the original direction equals the one specified as argument.
+.TP
+.BI "-d, --orig-dst " IP_ADDRESS
+Match only entries whose destination address in the original direction equals the one specified as argument.
+.TP
+.BI "-r, --reply-src " IP_ADDRESS
+Match only entries whose source address in the reply direction equals the one specified as argument.
+.TP
+.BI "-q, --reply-dst " IP_ADDRESS
+Match only entries whose destination address in the reply direction equals the one specified as argument.
+.TP
+.BI "-p, --proto " "PROTO "
+Specify layer four (TCP, UDP, ...) protocol.
+.TP
+.BI "-f, --family " "PROTO"
+Specify layer three (ipv4, ipv6) protocol
+This option is only required in conjunction with "-L, --dump". If this option is not passed, the default layer 3 protocol will be IPv4.
+.TP
+.BI "-t, --timeout " "TIMEOUT"
+Specify the timeout.
+.TP
+.BI "-u, --status " "[ASSURED|SEEN_REPLY|UNSET|SRC_NAT|DST_NAT][,...]"
+Specify the conntrack status.
+.TP
+.BI "-i, --id " "ID"
+Specify the conntrack ID. 
+.
+This option can only be used in conjunction with "-L, --dump" to display the conntrack IDs.
+.TP
+.BI "--tuple-src " IP_ADDRESS
+Specify the tuple source address of an expectation.
+.TP
+.BI "--tuple-dst " IP_ADDRESS
+Specify the tuple destination address of an expectation.
+.TP
+.BI "--mask-src " IP_ADDRESS
+Specify the source address mask of an expectation.
+.TP
+.BI "--mask-dst " IP_ADDRESS
+Specify the destination address mask of an expectation.
+.SH DIAGNOSTICS
+The exit code is 0 for correct function.  Errors which appear to be caused by
+invalid command line parameters cause an exit code of 2.  Any other errors
+cause an exit code of 1.
+.SH BUGS
+Bugs? What's this ;-)
+.SH SEE ALSO
+.BR iptables (8)
+.br
+See
+.BR "http://netfilter.org/" .
+.SH AUTHORS
+Jay Schulist, Patrick McHardy, Harald Welte and Pablo Neira wrote the kernel-level "ctnetlink" interface that is used by the conntrack tool.
+.PP
+Pablo Neira wrote the conntrack tool, Harald Welte added support for conntrack based accounting counters.
+.PP
+Man page written by Harald Welte <laforge@netfilter.org>.
diff --git a/daemon/AUTHORS b/daemon/AUTHORS
deleted file mode 100644
index e6c2f6b..0000000
--- a/daemon/AUTHORS
+++ /dev/null
@@ -1 +0,0 @@
-Pablo Neira Ayuso <pablo@netfilter.org>
diff --git a/daemon/CHANGELOG b/daemon/CHANGELOG
deleted file mode 100644
index afab61d..0000000
--- a/daemon/CHANGELOG
+++ /dev/null
@@ -1,184 +0,0 @@
-version 0.9.3 (yet unreleased)
-------------------------------
-o fix commit of confirmed expectations (reported by Nishit Shah)
-o fix double increment of counters in cache_update_force() (Niko Tyni)
-o nl_dump_handler must return NFCT_CB_CONTINUE (Niko Tyni)
-o initialize buffer in nl_event_handler() and nl_dump_handler() (Niko Tyni) 
-o CacheCommit value can be set via conntrackd.conf for the NACK approach
-o fix leaks in the hashtable/cache flush path (Niko Tyni)
-o fix leak if a connection already exists in the cache (Niko Tyni)
-o introduce a new header that encapsulates netlink messages
-o remove all '_entry' tail from all functions in cache.c
-o split cache.c: move cache iterators to file cache_iterators.c
-o fix inconsistencies in the cache API related to counters
-o cleanup 'usage' message
-o fix typo in examples/sync/nack/node1/conntrackd.conf
-o introduce message checksumming as described in RFC1071 (enabled by default)
-o major cleanups in the synchronization code
-o just warn once that the maximum netlink socket buffer has been reached
-o fix ignore conntrack entries by IP and introduce ignore pool abstraction layer
-o introduce netlink socket buffer overrun handler
-o constification of hash, compare and hashtable_test functions in hash.c
-o introduce ACKnowledgement mechanisms to reduce the size of the resend queue
-o remove OK messages at startup since provide useless data
-o fix compilation warning in mcast.c: recvfrom takes socklen_t not size_t
-o add a lock per buffer: makes buffer code thread safe
-o introduce 'Replicate' clause to explicitely set states to be replicated
-o kill cache feature abuse: introduce nicer cache hooks for sync algorithms
-o fix oversized buffer allocated in the stack in the cache functions
-o add support to dump internal/external cache in XML format '-x'
-
-version 0.9.2 (2006/01/17)
---------------------------
-o remove spamming packet lost messages
-o generalize network netlink sequence tracking 
-o fix bogus error message on resync `-R'
-o fix endianess issues in the network netlink message
-o introduce generic netlink multicast primitives to send and receive
-o fix bogus replayed multicast message due to sequence numbering wraparound
-o introduce counter for malformed netlink messages received
-o introduce a new syntax for the `Sync' section  in the configuration file
-o several cleanups and remove unused variables
-o add autostuff to include examples in the tarball (reported by Victor Lozano)
-o use the new API available in libnetfilter_conntrack-0.0.50
-o implement a NACK based protocol for replication
-
-version 0.9.1 (2006/11/06)
---------------------------
-o conntrackd requires kernel >= 2.6.18
-o remove bogus TIMERS_MODE constant
-o implement bulk mode '-B': first works to address the preemption issue
-o fix minor reduction conflicts in the configfile grammar
-o check for CAP_NET_ADMIN instead of requiring root privileges
-o check that linux/capability.h exists
-o fix formatting at dump statistics '-s'
-o move dump traffic stats before multicast traffic stats
-o move event and dump handler to a generic infrastructure: kill events.c file
-o kill unused function inc_ct_stats
-o kill file resync.h
-o cleanup broadcast_sync: renamed to mcast_send_sync
-o sed 's/perror/debug/g' local.c
-o fix bogus increment of update_fail stats at dump stage
-o display descriptive error if we can't connect to conntrackd via UNIX socket
-o remove debugging message from alarm.c
-o move dump_mcast_stats to mcast.c where it really belongs
-o rename stats.c to traffic_stats.c
-o check for replayed/lost multicast message: simple seq tracking w/o recovery
-o reissue nfnl_catch on ENOENT error: a message for other subsystem
-o remove test/ directory in tree
-o improve cache commit stats
-o kill last_commit and last_flush from cache statistics: use the logfile
-o recover cache naming for dump stats `-s'
-o display multicast sequence tracking statistics: packets lost and replayed
-o zero ct_sync_state and ct_stats_state structures after allocation
-o improve keepalived scripts:
-   - resync with conntrack table on transition to master
-   - send bulk on transition to backup
-o implement alarm cascade of ten levels
-o implement timer cache flavour: limited life of entries in the external cache
-o implement a global lock that protects operation with conntrack entries
-o remove debug checking in cache_del_entry
-o set a reduced timeout for committed entries: 180 seconds by default
-o update comments on the sync-mode code
-o introduce delay destroy messages facility
-o increase timer for external states from 60 to 180 seconds
-o remove unused replicate/dont_replicated constants
-o fix cache entry clashing issue (reported by Maik Hentsche)
-o fix bogus increment of error stats in the external cache
-o remove pollution generated by `[REQ] cache dump' message from logfile
-
-version 0.9.0 (2006/09/17)
---------------------------
-o implement initial for IPv6 (untested)
-o implement generic extensible cache: kill the internal and external caches
-o implement persistence cache feature
-o implement lifetime cache feature
-o modify UNIX facilities identification numbers:
-  separate master conntrack facilities and internal plugin facilities
-o break backward compatibility of configuration file:
-  remove IgnoreLoopback, use IgnoreTrafficFor instead
-  remove IgnoreMulticastTraffic, use IgnoreTrafficFor instead
-o merge event/event_subsys and sync/sync_subsys initialization to run.c
-o improve control of the iteration process in the hashtables
-o fix wrong locking in the alarm thread
-o supersede AcceptNAT by StripNAT clause
-o replace ignore traffic array by a hashtable
-o move lockfile checking before daemonization
-o on initialization error give a descriptive error
-o introduce netlink socket size grown limitator
-o introduce force resync with master conntrack table facility '-R'
-o ignore SIGPIPE signal
-o kill post_step since it is not used anymore
-
-version 0.8.3 (2006/09/03)
---------------------------
-Author: Maik Hentsche <maik mm-double net>
-
-o Fix typo in conntrackd -h
-o Disable debugging messages by default
-o No signals while signals handlings
-o Add extra checkings at forking
-o Check maximum size for file passed via -C
-
-Author: Pablo Neira Ayuso <pablo netfilter org>
-
-o retry select() if EINTR is returned (Reported by Maik Hentsche)
-o Fix bug in slist_for_each_entry (Reported by Maik Hetsche)
-o Signal handler registration done after intialization
-o Implement alarm thread (based on Maik Hentsche's patch)
-o Fix segfault on conntrackd -k (Reported by Maik Hentsche)
-o Fix bug on alarm removal (Reported by Maik Hentsche)
-o configure stops if bison, flex or yacc are not installed
-
-version 0.8.2 (2006/07/05)
---------------------------
-o RelaxTransitions clause introduced in Sync mode
-o multicast messages sequence tracking
-o SocketBufferSize clause to set up the netlink socket buffer
-o use new libnfnetlink API to solve limitations of nfnl_listen
-o extra sanity checkings for netlink multicast messages
-o improve statistics
-o tons of cleanups 8)
-
-version 0.8.1 (2006/06/13)
---------------------------
-o -f now just flushes the internal and external caches
-o -F flushes the master conntrack table
-o fix segfault under heavy load and signal received
-o added -S mode for statistics: still needs more thinking
-
-version 0.8.0 (2006/06/11)
---------------------------
-o more work to generalize the daemon: now it's ready to implement
-modular support for adaptive timers and conntrack statistics, time
-to implement them ;). This is *still* a work in progress.
-
-version 0.7.2 (2006/06/05)
---------------------------
-o stupid bug in normal and alarm caches initialization: flush unset
-o fix racy signal handling
-
-version 0.7.1 (2006/06/05)
---------------------------
-o Bugfix for multicast sockets communication
-
-version 0.7 (2006/06/01)
-------------------------
-o Major code re-structuration: internal and external cache abstraction
-o sequence tracking for event messages
-o expect more changes, I still dislike some stuff in its current status ;)
-
-version 0.6 (2006/05/31)
-------------------------
-o Lock file support
-o use new API nfct_conntrack_event_raw
-o major code clean ups
-
-version 0.5 (2006/05/30)
--------------------------
-o Fix multicast server binds to wrong interface
-o Include clause `IgnoreProtocol', deprecates IgnoreUDP and IgnoreICMP
-
-version 0.4 (2006/05/29)
-------------------------
-o Initial release
diff --git a/daemon/CONTRIBUTORS b/daemon/CONTRIBUTORS
deleted file mode 100644
index c5e40b4..0000000
--- a/daemon/CONTRIBUTORS
+++ /dev/null
@@ -1,3 +0,0 @@
-Maik Hentsche <netfilter@mm-double.de>:
-  - Feedback & Brainstorming
-  - Bug hunting
diff --git a/daemon/INSTALL b/daemon/INSTALL
deleted file mode 100644
index 0de8dc0..0000000
--- a/daemon/INSTALL
+++ /dev/null
@@ -1,199 +0,0 @@
-Copyright (C) 2006-2007 Pablo Neira Ayuso <pablo netfilter org>
-
-1.Basic Installation
-====================
-
- To compile and install 'conntrackd' just follow the classical steps:
-
-	$ ./configure
-	$ make
-	# make install
-	# mkdir /etc/conntrackd/
-
-2.1. Synchronization Mode
-=========================
-
- Conntrackd can replicate the status of the connections that are currently
- being processed by your stateful firewall based on Linux. This section
- describes how to setup the daemon in synchronization mode:
-
-2.1.1. Requirements
-
- You have to install the following software in order to get conntrackd working,
- make sure that you have installed them correctly before going forward:
-
- o linux kernel version >= 2.6.18 (http://www.kernel.org) with support for:
-     - connection tracking system (quite obvious ;)
-     - nfnetlink
-     - ctnetlink (ip_conntrack_netlink)
-     - connection tracking event notification API
-
- o libnfnetlink: the netfilter netlink library
-
-     Since conntrackd version 0.9.2 you can used the official release availble at
-     http://www.netfilter.org/projects/libnfnetlink/files/
-
-     Up to conntrackd version 0.9.1 use the unofficial release available at the
-     download section
-
- o libnetfilter_conntrack: the netfilter conntrack library
-
-     Since  conntrackd version 0.9.2 you can used the official release availble at
-     http://www.netfilter.org/projects/libnetfilter_conntrack/files/
-
-     Up to conntrackd version 0.9.1 use the unnoficial release available at the
-     download section
-
- o Keepalived version 1.x (http://www.keepalived.org)
-     check if your distribution comes with a recent version
-
-2.1.2. Configuration
-
- 1) Setting up keepalived
-
-    There is an example file available inside the conntrackd tarball:
-
-    For node 1: conntrackd-x.x.x/examples/sync/node1/keepalived.conf
-    For node 2: conntrackd-x.x.x/examples/sync/node2/keepalived.conf
-
-    These files can be used to set up a simple VRRP cluster composed of
-    two machines that hold the virtual IPs 192.168.0.100 on eth0 and
-    192.168.1.100 on eth1.
-
-    If you are not familiar with keepalived, please read the official
-    docs available at http://www.keepalived.org
-
-    Please, make sure that keepalived is correctly working before passing
-    to step 2)
-
- 2) Setting up conntrackd
-
-    To setup 'conntrackd' in synchronization mode, you have to put the
-    configuration file in the directory /etc/conntrackd.
-
-    On node 1:
-	# cp examples/sync/_type_/node1/conntrackd.conf /etc/conntrackd.conf
-
-    On node 2:
-        # cp examples/sync/_type_/node1/conntrackd.conf /etc/conntrackd.conf
-
-    Where _type_ is the synchronization type selected, currently there are
-    two: the persistent mode and the NACK mode. The persistent mode consumes
-    more resources than the NACK mode, however the NACK mode is still
-    experimental
-
-    Do not forget to edit the files in order to adapt them to the
-    setting that you are deploying.
-
-    Note: If you don't want to put the config file under /etc/conntrackd,
-    just tell conntrackd where to find it passing the option -C
-
- 3) Running conntrackd
-
-    Conntrackd can run in console mode, in that case just type 'conntrackd',
-    otherwise, if you want to run it in daemon mode the type 'conntrackd -d'.
-
- 4) Checking that conntrackd is working fine
-
-    Conntrackd comes with several facilities to check its status:
-
-    - Dump the cache of connections that are currently being processed by
-      this node (aka. internal cache):
-
-    # conntrackd -i
-
-    - Dump the cache of connections that has been transfered from
-      others active nodes in the network (aka. external cache)
-
-    # conntrackd -e
-
-    - Dump statistics collected by the replication daemon:
-
-    # conntrackd -s
-
- 5) Setting up interaction with keepalived
-
-    If keepalived detects the failure of the active node, then it designates
-    a candidate node that will replace the failing active. On such event,
-    the external cache, eg. the cache that contains the connections processed
-    by other nodes, must be commited. To commit the external cache, just type:
-
-    # conntrackd -c
-
-    See that keepalived provides a shell script interface to interact with
-    other programs, so we can automate the process of commiting the external
-    cache by introducing the following line in the keepalived file:
-
-    notify_master /etc/conntrackd/script_master.sh
-
-    The script 'script_master.sh' just the following:
-
-    #!/bin/sh
-    /usr/sbin/conntrackd -c
-
-    Therefore, on failure event, the candidate node takes over the virtual
-    IPs and the connections that the failing active was processing. Observe
-    that this file differs for the NACK mode.
-
- 6) Disable TCP window tracking
-
- Until the appropiate patches don't go into kernel mainline, you will have
- to disable TCP window tracking, consider this as a temporary solution:
-
-    # echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal
-
-2.2. Statistics mode
-====================
-
- Conntrackd can also run as statistics daemon, if you are not interested in
- this mode, just skip it. It is not required in order to get the
- synchronization mode working. This section details how to setup the daemon
- in statistics mode:
-
-2.2.1. Requirements
-
- You have to install the following software in order to get conntrackd working,
- make sure that you have them installed correctly before going forward:
-
- o linux kernel version >= 2.6.18 (http://www.kernel.org) with support for:
-      - connection tracking system
-      - nfnetlink
-      - ctnetlink (ip_conntrack_netlink)
-      - connection tracking event notification API
-
- o libnfnetlink: the netfilter netlink library
-
-     Since conntrackd version 0.9.2 you can used the official release availble at
-     http://www.netfilter.org/projects/libnfnetlink/files/
-
-     Up to conntrackd version 0.9.1 use the unofficial release available at the
-     download section
-
- o libnetfilter_conntrack: the netfilter conntrack library
-
-     Since  conntrackd version 0.9.2 you can used the official release availble at
-     http://www.netfilter.org/projects/libnetfilter_conntrack/files/
-
-     Up to conntrackd version 0.9.1 use the unnoficial release available at the
-     download section
-
-2.2.2. Configuration
-
- Setting up conntrackd in statistics mode is rather easy. Just copy the
- configuration file
-
-    # cp examples/stats/conntrackd.conf /etc/conntrackd.conf
-
-2.2.3. Running conntrackd in statistics mode
-
- To run conntrackd in statistics mode:
-
-    # conntrackd -S
-
- Alternatively, you can run conntrackd in daemon mode:
-
-    # conntrackd -S -d
-
- In order to dump the statistics, just type:
-
-    # conntrackd -s
diff --git a/daemon/Make_global.am b/daemon/Make_global.am
deleted file mode 100644
index 685add7..0000000
--- a/daemon/Make_global.am
+++ /dev/null
@@ -1 +0,0 @@
-INCLUDES=$(all_includes) -I$(top_srcdir)/include
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
deleted file mode 100644
index 998f4c6..0000000
--- a/daemon/Makefile.am
+++ /dev/null
@@ -1,21 +0,0 @@
-include Make_global.am
-
-# not a GNU package. You can remove this line, if
-# have all needed files, that a GNU package needs
-AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
-
-# man_MANS = ""
-# EXTRA_DIST = $(man_MANS) Make_global.am debian
-EXTRA_DIST = Make_global.am CHANGELOG TODO
-
-SUBDIRS   = src
-DIST_SUBDIRS = include src examples
-LINKOPTS  = -lnfnetlink -lnetfilter_conntrack -lpthread
-AM_CFLAGS = -g
-
-$(OBJECTS): libtool
-libtool: $(LIBTOOL_DEPS)
-	$(SHELL) ./config.status --recheck
-
-dist-hook:
-	rm -rf `find $(distdir)/debian -name .svn`
diff --git a/daemon/TODO b/daemon/TODO
deleted file mode 100644
index 130b1f8..0000000
--- a/daemon/TODO
+++ /dev/null
@@ -1,18 +0,0 @@
-There are several tasks that are pending to be done, I have classified them
-by dificulty levels:
-
-Relatively easy
-===============
-
-- test ipv6 support
-- improve shell scripts
-- test NACK based protocol
-- manpage for conntrackd
-
-Requires some work
-==================
-
-- study better keepalived transitions
-- implement support for TCP window tracking (patches are on the table)
-	- at the moment you have to disable it:
-	echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal
diff --git a/daemon/autogen.sh b/daemon/autogen.sh
deleted file mode 100755
index e76d3ef..0000000
--- a/daemon/autogen.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/sh
-
-run ()
-{
-    echo "running: $*"
-    eval $*
-
-    if test $? != 0 ; then
-	echo "error: while running '$*'"
-	exit 1
-    fi
-}
-
-run aclocal
-run libtoolize -f
-#run autoheader
-run automake -a
-run autoconf
diff --git a/daemon/configure.in b/daemon/configure.in
deleted file mode 100644
index 92e512a..0000000
--- a/daemon/configure.in
+++ /dev/null
@@ -1,106 +0,0 @@
-AC_INIT(conntrackd, 0.9.2, pablo@netfilter.org)
-
-AC_CANONICAL_SYSTEM
-
-AM_INIT_AUTOMAKE
-
-AC_PROG_CC
-AM_PROG_LIBTOOL
-AC_PROG_INSTALL
-AC_PROG_LN_S
-AM_PROG_LEX
-AC_PROG_YACC
-
-case $target in
-*-*-linux*) ;;
-*) AC_MSG_ERROR([Linux only, dude!]);;
-esac
-
-AC_CHECK_PROGS(XYACC,$YACC bison yacc,none)
-if test "$XYACC" = "none"
-then
-	echo "*** Error: No suitable bison/yacc found. ***"
-	echo "    Please install the 'bison' package."
-	exit 1
-fi
-AC_CHECK_PROGS(XLEX,$LEX flex lex,none)
-if test "$XLEX" = "none"
-then
-	echo "*** Error: No suitable bison/yacc found. ***"
-	echo "    Please install the 'bison' package."
-	exit 1
-fi
-
-AC_CHECK_HEADERS([linux/capability.h],, [AC_MSG_ERROR([Cannot find linux/capabibility.h])])
-
-# Checks for libraries.
-# FIXME: Replace `main' with a function in `-lc':
-dnl AC_CHECK_LIB([c], [main])
-# FIXME: Replace `main' with a function in `-ldl':
-
-AC_CHECK_LIB([nfnetlink], [nfnl_talk] ,,,[-lnfnetlink])
-AC_CHECK_LIB([netfilter_conntrack], [nfct_dump_conntrack_table] ,,,[-lnetfilter_conntrack])
-AC_CHECK_LIB([pthread], [pthread_create] ,,,[-lpthread])
-
-AC_CHECK_HEADERS(arpa/inet.h)
-dnl check for inet_pton
-AC_CHECK_FUNCS(inet_pton)
-dnl Some systems have it, but not IPv6
-if test "$ac_cv_func_inet_pton" = "yes" ; then
-AC_MSG_CHECKING(if inet_pton supports IPv6)
-AC_TRY_RUN(
-   [
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-int main()
-  {
-     struct in6_addr addr6;
-     if (inet_pton(AF_INET6, "::1", &addr6) < 1)
-        exit(1);
-     else
-        exit(0);
-  }
-  ], [ AC_MSG_RESULT(yes)
-       AC_DEFINE_UNQUOTED(HAVE_INET_PTON_IPV6, 1, [Define to 1 if inet_pton supports IPv6.])
-  ], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
-fi
-
-# Checks for header files.
-dnl AC_HEADER_STDC
-dnl AC_CHECK_HEADERS([netinet/in.h stdlib.h])
-
-# Checks for typedefs, structures, and compiler characteristics.
-dnl AC_C_CONST
-dnl AC_C_INLINE
-
-# Checks for library functions.
-dnl AC_FUNC_MALLOC
-dnl AC_FUNC_VPRINTF
-dnl AC_CHECK_FUNCS([memset])
-
-dnl--------------------------------
-
-dnl if test ! -z "$libdir"; then
-dnl    MODULE_DIR="\\\"$libdir/conntrack/\\\""
-dnl    CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR"
-dnl fi
-
-dnl--------------------------------
-
-dnl AC_CONFIG_FILES([Makefile
-dnl                  debug/Makefile
-dnl                  debug/src/Makefile
-dnl                  extensions/Makefile
-dnl                  src/Makefile])
-
-AC_OUTPUT(Makefile src/Makefile include/Makefile examples/Makefile examples/stats/Makefile examples/sync/Makefile examples/sync/persistent/Makefile examples/sync/nack/Makefile examples/sync/persistent/node1/Makefile examples/sync/persistent/node2/Makefile examples/sync/nack/node1/Makefile examples/sync/nack/node2/Makefile)
diff --git a/daemon/examples/Makefile.am b/daemon/examples/Makefile.am
deleted file mode 100644
index be83d42..0000000
--- a/daemon/examples/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-SUBDIRS = stats sync 
diff --git a/daemon/examples/debian.conntrackd.init.d b/daemon/examples/debian.conntrackd.init.d
deleted file mode 100644
index ba847dd..0000000
--- a/daemon/examples/debian.conntrackd.init.d
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/sh
-#
-# /etc/init.d/conntrackd
-#
-# Maximilian Wilhelm <max@rfc2324.org>
-#  -- Mon, 06 Nov 2006 18:39:07 +0100
-#
-
-export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
-
-NAME="conntrackd"
-DAEMON=`command -v conntrackd`
-CONFIG="/etc/conntrack/conntrackd.conf"
-PIDFILE="/var/run/${NAME}.pid"
-
-
-# Gracefully exit if there is no daemon (debian way of life)
-if [ ! -x "${DAEMON}" ]; then
-	exit 0
-fi
-
-# Check for config file
-if [ ! -f /etc/conntrackd/conntrackd.conf ]; then
-	echo "Error: There is no config file for $NAME" >&2
-	exit 1;
-fi
-
-case "$1" in
-  start)
-        echo -n "Starting $NAME: "
-	start-stop-daemon --start --quiet --make-pidfile --pidfile "/var/run/${NAME}.pid" --background --exec "${DAEMON}"  && echo "done." || echo "FAILED!"
-	;;
-  stop)
-        echo -n "Stopping $NAME:"
-	start-stop-daemon --stop --quiet --oknodo --pidfile "/var/run/${NAME}.pid" && echo "done." || echo "FAILED!"
-	;;
-
-  restart)
-	$0 start
-	$0 stop
-	;;
-
-  *)
-	echo "Usage: /etc/init.d/conntrackd {start|stop|restart}"
-	exit 1
-esac
-
-exit 0
diff --git a/daemon/examples/stats/Makefile.am b/daemon/examples/stats/Makefile.am
deleted file mode 100644
index b43c3b8..0000000
--- a/daemon/examples/stats/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-EXTRA_DIST = conntrackd.conf 
diff --git a/daemon/examples/stats/conntrackd.conf b/daemon/examples/stats/conntrackd.conf
deleted file mode 100644
index e514ac0..0000000
--- a/daemon/examples/stats/conntrackd.conf
+++ /dev/null
@@ -1,69 +0,0 @@
-#
-# General settings
-#
-General {
-	#
-	# Number of buckets in the caches: hash table
-	#
-	HashSize 8192
-
-	#
-	# Maximum number of conntracks: 
-	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
-	#
-	HashLimit 65535
-
-	#
-	# Logfile
-	#
-	LogFile /var/log/conntrackd.log
-
-	#
-	# Lockfile
-	# 
-	LockFile /var/lock/conntrack.lock
-
-	#
-	# Unix socket configuration
-	#
-	UNIX {
-		Path /tmp/sync.sock
-		Backlog 20
-	}
-
-	#
-	# Netlink socket buffer size
-	#
-	SocketBufferSize 262142
-
-	#
-	# Increase the socket buffer up to maximun if required
-	#
-	SocketBufferSizeMaxGrown 655355
-}
-
-#
-# Ignore traffic for a certain set of IP's: Usually
-# all the IP assigned to the firewall since local
-# traffic must be ignored, just forwarded connections
-# are worth to replicate
-#
-IgnoreTrafficFor {
-	IPv4_address 127.0.0.1 # loopback
-}
-
-#
-# Do not replicate certain protocol traffic 
-#
-IgnoreProtocol {
-	UDP
-#	ICMP
-#	IGMP
-#	VRRP
-	# numeric numbers also valid
-}
-
-#
-# Strip NAT traffic
-#
-StripNAT
diff --git a/daemon/examples/sync/Makefile.am b/daemon/examples/sync/Makefile.am
deleted file mode 100644
index 28e7643..0000000
--- a/daemon/examples/sync/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-SUBDIRS = persistent nack
diff --git a/daemon/examples/sync/nack/Makefile.am b/daemon/examples/sync/nack/Makefile.am
deleted file mode 100644
index 6fd99b1..0000000
--- a/daemon/examples/sync/nack/Makefile.am
+++ /dev/null
@@ -1,2 +0,0 @@
-EXTRA_DIST = script_backup.sh script_master.sh 
-SUBDIRS = node1 node2
diff --git a/daemon/examples/sync/nack/README b/daemon/examples/sync/nack/README
deleted file mode 100644
index 66987f7..0000000
--- a/daemon/examples/sync/nack/README
+++ /dev/null
@@ -1 +0,0 @@
-This directory contains the files for the NACK based protocol
diff --git a/daemon/examples/sync/nack/node1/Makefile.am b/daemon/examples/sync/nack/node1/Makefile.am
deleted file mode 100644
index edc0ed7..0000000
--- a/daemon/examples/sync/nack/node1/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-EXTRA_DIST = conntrackd.conf keepalived.conf 
diff --git a/daemon/examples/sync/nack/node1/conntrackd.conf b/daemon/examples/sync/nack/node1/conntrackd.conf
deleted file mode 100644
index f24fa7e..0000000
--- a/daemon/examples/sync/nack/node1/conntrackd.conf
+++ /dev/null
@@ -1,125 +0,0 @@
-#
-# Synchronizer settings
-#
-Sync {
-	Mode NACK {
-		#
-		# Size of the buffer that hold destroy messages for 
-		# possible resends (in bytes)
-		#
-		ResendBufferSize 262144
-
-		#
-		# Entries committed to the connection tracking table 
-		# starts with a limited timeout of N seconds until the
-		# takeover process is completed.
-		#
-		CommitTimeout 180
-
-		# Set Acknowledgement window size
-		ACKWindowSize 20
-	}
-
-	#
-	# Multicast IP and interface where messages are
-	# broadcasted (dedicated link). IMPORTANT: Make sure
-	# that iptables accepts traffic for destination
-	# 225.0.0.50, eg:
-	#
-	#	iptables -I INPUT -d 225.0.0.50 -j ACCEPT
-	#	iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT
-	#
-	Multicast {
-		IPv4_address 225.0.0.50
-		IPv4_interface 192.168.100.100 # IP of dedicated link
-		Group 3780
-		Backlog 20
-	}
-
-	# Enable/Disable message checksumming
-	Checksum on
-
-	# Uncomment this if you want to replicate just certain TCP states.
-	# This option introduces a tradeoff in the replication: it reduces
-	# CPU consumption and lost messages rate at the cost of having 
-	# backup replicas that don't contain the current state that the active 
-	# replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED,
-	# FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN.
-	# 
-	# Replicate ESTABLISHED TIME_WAIT for TCP
-}
-
-#
-# General settings
-#
-General {
-	#
-	# Number of buckets in the caches: hash table
-	#
-	HashSize 8192
-
-	#
-	# Maximum number of conntracks: 
-	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
-	#
-	HashLimit 65535
-
-	#
-	# Logfile
-	#
-	LogFile /var/log/conntrackd.log
-
-	#
-	# Lockfile
-	# 
-	LockFile /var/lock/conntrack.lock
-
-	#
-	# Unix socket configuration
-	#
-	UNIX {
-		Path /tmp/sync.sock
-		Backlog 20
-	}
-
-	#
-	# Netlink socket buffer size
-	#
-	SocketBufferSize 262142
-
-	#
-	# Increase the socket buffer up to maximum if required
-	#
-	SocketBufferSizeMaxGrown 655355
-}
-
-#
-# Ignore traffic for a certain set of IP's: Usually
-# all the IP assigned to the firewall since local
-# traffic must be ignored, just forwarded connections
-# are worth to replicate
-#
-IgnoreTrafficFor {
-	IPv4_address 127.0.0.1 # loopback
-	IPv4_address 192.168.0.1
-	IPv4_address 192.168.1.1
-	IPv4_address 192.168.100.100 # dedicated link ip
-	IPv4_address 192.168.0.100 # virtual IP 1
-	IPv4_address 192.168.1.100 # virtual IP 2
-}
-
-#
-# Do not replicate certain protocol traffic 
-#
-IgnoreProtocol {
-	UDP
-	ICMP
-	IGMP
-	VRRP
-	# numeric numbers also valid
-}
-
-#
-# Strip NAT traffic
-#
-StripNAT
diff --git a/daemon/examples/sync/nack/node1/keepalived.conf b/daemon/examples/sync/nack/node1/keepalived.conf
deleted file mode 100644
index 41aa35b..0000000
--- a/daemon/examples/sync/nack/node1/keepalived.conf
+++ /dev/null
@@ -1,38 +0,0 @@
-vrrp_sync_group G1 {   # must be before vrrp_instance declaration
-  group {
-    VI_1
-    VI_2
-  }
-  notify_master /etc/conntrackd/script_master.sh
-  notify_backup /etc/conntrackd/script_backup.sh
-}
-
-vrrp_instance VI_1 {
-    interface eth1
-    state SLAVE
-    virtual_router_id 61
-    priority 80
-    advert_int 3
-    authentication {
-      auth_type PASS
-      auth_pass papas_con_tomate
-    }
-    virtual_ipaddress {
-        192.168.0.100   # default CIDR mask is /32
-    }
-}
-
-vrrp_instance VI_2 {
-    interface eth0
-    state SLAVE
-    virtual_router_id 62
-    priority 80
-    advert_int 3
-    authentication {
-      auth_type PASS
-      auth_pass papas_con_tomate
-    }
-    virtual_ipaddress {
-        192.168.1.100
-    }
-}
diff --git a/daemon/examples/sync/nack/node2/Makefile.am b/daemon/examples/sync/nack/node2/Makefile.am
deleted file mode 100644
index edc0ed7..0000000
--- a/daemon/examples/sync/nack/node2/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-EXTRA_DIST = conntrackd.conf keepalived.conf 
diff --git a/daemon/examples/sync/nack/node2/conntrackd.conf b/daemon/examples/sync/nack/node2/conntrackd.conf
deleted file mode 100644
index 4f15773..0000000
--- a/daemon/examples/sync/nack/node2/conntrackd.conf
+++ /dev/null
@@ -1,124 +0,0 @@
-#
-# Synchronizer settings
-#
-Sync {
-	Mode NACK {
-                #
-		# Size of the buffer that hold destroy messages for 
-		# possible resends (in bytes)
-		#
-		ResendBufferSize 262144
-
-		# Entries committed to the connection tracking table 
-		# starts with a limited timeout of N seconds until the
-		# takeover process is completed.
-		#
-		CommitTimeout 180
-
-		# Set Acknowledgement window size
-		ACKWindowSize 20
-	}
-
-	#
-	# Multicast IP and interface where messages are
-	# broadcasted (dedicated link). IMPORTANT: Make sure
-	# that iptables accepts traffic for destination
-	# 225.0.0.50, eg:
-	#
-	#	iptables -I INPUT -d 225.0.0.50 -j ACCEPT
-	#	iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT
-	#
-	Multicast {
-		IPv4_address 225.0.0.50
-		IPv4_interface 192.168.100.200 # IP of dedicated link
-		Group 3780
-		Backlog 20
-	}
-
-	# Enable/Disable message checksumming
-	Checksum on
-
-	# Uncomment this if you want to replicate just certain TCP states.
-	# This option introduces a tradeoff in the replication: it reduces
-	# CPU consumption and lost messages rate at the cost of having 
-	# backup replicas that don't contain the current state that the active 
-	# replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED,
-	# FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN.
-	# 
-	# Replicate ESTABLISHED TIME_WAIT for TCP
-}
-
-#
-# General settings
-#
-General {
-	#
-	# Number of buckets in the caches: hash table
-	#
-	HashSize 8192
-
-	#
-	# Maximum number of conntracks: 
-	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
-	#
-	HashLimit 65535
-
-	#
-	# Logfile
-	#
-	LogFile /var/log/conntrackd.log
-
-	#
-	# Lockfile
-	# 
-	LockFile /var/lock/conntrack.lock
-
-	#
-	# Unix socket configuration
-	#
-	UNIX {
-		Path /tmp/sync.sock
-		Backlog 20
-	}
-
-	#
-	# Netlink socket buffer size
-	#
-	SocketBufferSize 262142
-
-	#
-	# Increase the socket buffer up to maximum if required
-	#
-	SocketBufferSizeMaxGrown 655355
-}
-
-#
-# Ignore traffic for a certain set of IP's: Usually
-# all the IP assigned to the firewall since local
-# traffic must be ignored, just forwarded connections
-# are worth to replicate
-#
-IgnoreTrafficFor {
-	IPv4_address 127.0.0.1 # loopback
-	IPv4_address 192.168.0.2
-	IPv4_address 192.168.1.2
-	IPv4_address 192.168.100.200 # dedicated link ip
-	IPv4_address 192.168.0.200 # virtual IP 1
-	IPv4_address 192.168.1.200 # virtual IP 2
-}
-
-#
-# Do not replicate certain protocol traffic 
-#
-IgnoreProtocol {
-	UDP
-	ICMP
-	IGMP
-	VRRP
-	# numeric numbers also valid
-}
-
-#
-# Strip NAT traffic
-#
-StripNAT
diff --git a/daemon/examples/sync/nack/node2/keepalived.conf b/daemon/examples/sync/nack/node2/keepalived.conf
deleted file mode 100644
index 41aa35b..0000000
--- a/daemon/examples/sync/nack/node2/keepalived.conf
+++ /dev/null
@@ -1,38 +0,0 @@
-vrrp_sync_group G1 {   # must be before vrrp_instance declaration
-  group {
-    VI_1
-    VI_2
-  }
-  notify_master /etc/conntrackd/script_master.sh
-  notify_backup /etc/conntrackd/script_backup.sh
-}
-
-vrrp_instance VI_1 {
-    interface eth1
-    state SLAVE
-    virtual_router_id 61
-    priority 80
-    advert_int 3
-    authentication {
-      auth_type PASS
-      auth_pass papas_con_tomate
-    }
-    virtual_ipaddress {
-        192.168.0.100   # default CIDR mask is /32
-    }
-}
-
-vrrp_instance VI_2 {
-    interface eth0
-    state SLAVE
-    virtual_router_id 62
-    priority 80
-    advert_int 3
-    authentication {
-      auth_type PASS
-      auth_pass papas_con_tomate
-    }
-    virtual_ipaddress {
-        192.168.1.100
-    }
-}
diff --git a/daemon/examples/sync/nack/script_backup.sh b/daemon/examples/sync/nack/script_backup.sh
deleted file mode 100755
index 813e375..0000000
--- a/daemon/examples/sync/nack/script_backup.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-/usr/sbin/conntrackd -n # request a resync from other nodes via multicast
diff --git a/daemon/examples/sync/nack/script_master.sh b/daemon/examples/sync/nack/script_master.sh
deleted file mode 100755
index ff1dbc0..0000000
--- a/daemon/examples/sync/nack/script_master.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-/usr/sbin/conntrackd -c # commit the cache
-/usr/sbin/conntrackd -f # flush the caches
-/usr/sbin/conntrackd -R # resync with kernel conntrack table
diff --git a/daemon/examples/sync/persistent/Makefile.am b/daemon/examples/sync/persistent/Makefile.am
deleted file mode 100644
index 6fd99b1..0000000
--- a/daemon/examples/sync/persistent/Makefile.am
+++ /dev/null
@@ -1,2 +0,0 @@
-EXTRA_DIST = script_backup.sh script_master.sh 
-SUBDIRS = node1 node2
diff --git a/daemon/examples/sync/persistent/README b/daemon/examples/sync/persistent/README
deleted file mode 100644
index 36b5989..0000000
--- a/daemon/examples/sync/persistent/README
+++ /dev/null
@@ -1 +0,0 @@
-This directory contains the files for the PERSISTENT based protocol
diff --git a/daemon/examples/sync/persistent/node1/Makefile.am b/daemon/examples/sync/persistent/node1/Makefile.am
deleted file mode 100644
index edc0ed7..0000000
--- a/daemon/examples/sync/persistent/node1/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-EXTRA_DIST = conntrackd.conf keepalived.conf 
diff --git a/daemon/examples/sync/persistent/node1/conntrackd.conf b/daemon/examples/sync/persistent/node1/conntrackd.conf
deleted file mode 100644
index 90afeb7..0000000
--- a/daemon/examples/sync/persistent/node1/conntrackd.conf
+++ /dev/null
@@ -1,130 +0,0 @@
-#
-# Synchronizer settings
-#
-Sync {
-	Mode PERSISTENT {
-		#
-		# If a conntrack entry is not modified in <= 15 seconds, then
-		# a message is broadcasted. This mechanism is used to
-		# resynchronize nodes that just joined the multicast group
-		#
-		RefreshTime 15
-	
-		#
-		# If we don't receive a notification about the state of 
-		# an entry in the external cache after N seconds, then
-		# remove it.
-		#
-		CacheTimeout 180
-
-		#
-		# Entries committed to the connection tracking table 
-		# starts with a limited timeout of N seconds until the
-		# takeover process is completed.
-		#
-		CommitTimeout 180
-	}
-
-	#
-	# Multicast IP and interface where messages are
-	# broadcasted (dedicated link). IMPORTANT: Make sure
-	# that iptables accepts traffic for destination
-	# 225.0.0.50, eg:
-	#
-	#	iptables -I INPUT -d 225.0.0.50 -j ACCEPT
-	#	iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT
-	#
-	Multicast {
-		IPv4_address 225.0.0.50
-		IPv4_interface 192.168.100.100 # IP of dedicated link
-		Group 3780
-		Backlog 20
-	}
-
-	# Enable/Disable message checksumming
-	Checksum on
-
-	# Uncomment this if you want to replicate just certain TCP states.
-	# This option introduces a tradeoff in the replication: it reduces
-	# CPU consumption and lost messages rate at the cost of having 
-	# backup replicas that don't contain the current state that the active 
-	# replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED,
-	# FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN.
-	# 
-	# Replicate ESTABLISHED TIME_WAIT for TCP
-}
-
-#
-# General settings
-#
-General {
-	#
-	# Number of buckets in the caches: hash table
-	#
-	HashSize 8192
-
-	#
-	# Maximum number of conntracks: 
-	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
-	#
-	HashLimit 65535
-
-	#
-	# Logfile
-	#
-	LogFile /var/log/conntrackd.log
-
-	#
-	# Lockfile
-	# 
-	LockFile /var/lock/conntrack.lock
-
-	#
-	# Unix socket configuration
-	#
-	UNIX {
-		Path /tmp/sync.sock
-		Backlog 20
-	}
-
-	#
-	# Netlink socket buffer size
-	#
-	SocketBufferSize 262142
-
-	#
-	# Increase the socket buffer up to maximum if required
-	#
-	SocketBufferSizeMaxGrown 655355
-}
-
-#
-# Ignore traffic for a certain set of IP's: Usually
-# all the IP assigned to the firewall since local
-# traffic must be ignored, just forwarded connections
-# are worth to replicate
-#
-IgnoreTrafficFor {
-	IPv4_address 127.0.0.1 # loopback
-	IPv4_address 192.168.0.1
-	IPv4_address 192.168.1.1
-	IPv4_address 192.168.100.100 # dedicated link ip
-	IPv4_address 192.168.0.100 # virtual IP 1
-	IPv4_address 192.168.1.100 # virtual IP 2
-}
-
-#
-# Do not replicate certain protocol traffic 
-#
-IgnoreProtocol {
-	UDP
-	ICMP
-	IGMP
-	VRRP
-	# numeric numbers also valid
-}
-
-#
-# Strip NAT traffic
-#
-StripNAT
diff --git a/daemon/examples/sync/persistent/node1/keepalived.conf b/daemon/examples/sync/persistent/node1/keepalived.conf
deleted file mode 100644
index 41aa35b..0000000
--- a/daemon/examples/sync/persistent/node1/keepalived.conf
+++ /dev/null
@@ -1,38 +0,0 @@
-vrrp_sync_group G1 {   # must be before vrrp_instance declaration
-  group {
-    VI_1
-    VI_2
-  }
-  notify_master /etc/conntrackd/script_master.sh
-  notify_backup /etc/conntrackd/script_backup.sh
-}
-
-vrrp_instance VI_1 {
-    interface eth1
-    state SLAVE
-    virtual_router_id 61
-    priority 80
-    advert_int 3
-    authentication {
-      auth_type PASS
-      auth_pass papas_con_tomate
-    }
-    virtual_ipaddress {
-        192.168.0.100   # default CIDR mask is /32
-    }
-}
-
-vrrp_instance VI_2 {
-    interface eth0
-    state SLAVE
-    virtual_router_id 62
-    priority 80
-    advert_int 3
-    authentication {
-      auth_type PASS
-      auth_pass papas_con_tomate
-    }
-    virtual_ipaddress {
-        192.168.1.100
-    }
-}
diff --git a/daemon/examples/sync/persistent/node2/Makefile.am b/daemon/examples/sync/persistent/node2/Makefile.am
deleted file mode 100644
index edc0ed7..0000000
--- a/daemon/examples/sync/persistent/node2/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-EXTRA_DIST = conntrackd.conf keepalived.conf 
diff --git a/daemon/examples/sync/persistent/node2/conntrackd.conf b/daemon/examples/sync/persistent/node2/conntrackd.conf
deleted file mode 100644
index aee4a29..0000000
--- a/daemon/examples/sync/persistent/node2/conntrackd.conf
+++ /dev/null
@@ -1,130 +0,0 @@
-#
-# Synchronizer settings
-#
-Sync {
-	Mode PERSISTENT {
-		#
-		# If a conntrack entry is not modified in <= 15 seconds, then
-		# a message is broadcasted. This mechanism is used to
-		# resynchronize nodes that just joined the multicast group
-		#
-		RefreshTime 15
-	
-		#
-		# If we don't receive a notification about the state of 
-		# an entry in the external cache after N seconds, then
-		# remove it.
-		#
-		CacheTimeout 180
-
-		#
-		# Entries committed to the connection tracking table 
-		# starts with a limited timeout of N seconds until the
-		# takeover process is completed.
-		#
-		CommitTimeout 180
-	}
-
-	#
-	# Multicast IP and interface where messages are
-	# broadcasted (dedicated link). IMPORTANT: Make sure
-	# that iptables accepts traffic for destination
-	# 225.0.0.50, eg:
-	#
-	#	iptables -I INPUT -d 225.0.0.50 -j ACCEPT
-	#	iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT
-	#
-	Multicast {
-		IPv4_address 225.0.0.50
-		IPv4_interface 192.168.100.200 # IP of dedicated link
-		Group 3780
-		Backlog 20
-	}
-
-	# Enable/Disable message checksumming
-	Checksum on
-
-	# Uncomment this if you want to replicate just certain TCP states.
-	# This option introduces a tradeoff in the replication: it reduces
-	# CPU consumption and lost messages rate at the cost of having 
-	# backup replicas that don't contain the current state that the active 
-	# replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED,
-	# FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN.
-	# 
-	# Replicate ESTABLISHED TIME_WAIT for TCP
-}
-
-#
-# General settings
-#
-General {
-	#
-	# Number of buckets in the caches: hash table
-	#
-	HashSize 8192
-
-	#
-	# Maximum number of conntracks: 
-	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
-	#
-	HashLimit 65535
-
-	#
-	# Logfile
-	#
-	LogFile /var/log/conntrackd.log
-
-	#
-	# Lockfile
-	# 
-	LockFile /var/lock/conntrack.lock
-
-	#
-	# Unix socket configuration
-	#
-	UNIX {
-		Path /tmp/sync.sock
-		Backlog 20
-	}
-
-	#
-	# Netlink socket buffer size
-	#
-	SocketBufferSize 262142
-
-	#
-	# Increase the socket buffer up to maximum if required
-	#
-	SocketBufferSizeMaxGrown 655355
-}
-
-#
-# Ignore traffic for a certain set of IP's: Usually
-# all the IP assigned to the firewall since local
-# traffic must be ignored, just forwarded connections
-# are worth to replicate
-#
-IgnoreTrafficFor {
-	IPv4_address 127.0.0.1 # loopback
-	IPv4_address 192.168.0.2
-	IPv4_address 192.168.1.2
-	IPv4_address 192.168.100.200 # dedicated link ip
-	IPv4_address 192.168.0.200 # virtual IP 1
-	IPv4_address 192.168.1.200 # virtual IP 2
-}
-
-#
-# Do not replicate certain protocol traffic 
-#
-IgnoreProtocol {
-	UDP
-	ICMP
-	IGMP
-	VRRP
-	# numeric numbers also valid
-}
-
-#
-# Strip NAT traffic
-#
-StripNAT
diff --git a/daemon/examples/sync/persistent/node2/keepalived.conf b/daemon/examples/sync/persistent/node2/keepalived.conf
deleted file mode 100644
index 41aa35b..0000000
--- a/daemon/examples/sync/persistent/node2/keepalived.conf
+++ /dev/null
@@ -1,38 +0,0 @@
-vrrp_sync_group G1 {   # must be before vrrp_instance declaration
-  group {
-    VI_1
-    VI_2
-  }
-  notify_master /etc/conntrackd/script_master.sh
-  notify_backup /etc/conntrackd/script_backup.sh
-}
-
-vrrp_instance VI_1 {
-    interface eth1
-    state SLAVE
-    virtual_router_id 61
-    priority 80
-    advert_int 3
-    authentication {
-      auth_type PASS
-      auth_pass papas_con_tomate
-    }
-    virtual_ipaddress {
-        192.168.0.100   # default CIDR mask is /32
-    }
-}
-
-vrrp_instance VI_2 {
-    interface eth0
-    state SLAVE
-    virtual_router_id 62
-    priority 80
-    advert_int 3
-    authentication {
-      auth_type PASS
-      auth_pass papas_con_tomate
-    }
-    virtual_ipaddress {
-        192.168.1.100
-    }
-}
diff --git a/daemon/examples/sync/persistent/script_backup.sh b/daemon/examples/sync/persistent/script_backup.sh
deleted file mode 100755
index 8ea2ad8..0000000
--- a/daemon/examples/sync/persistent/script_backup.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-/usr/sbin/conntrackd -B
diff --git a/daemon/examples/sync/persistent/script_master.sh b/daemon/examples/sync/persistent/script_master.sh
deleted file mode 100755
index 70c26c9..0000000
--- a/daemon/examples/sync/persistent/script_master.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-/usr/sbin/conntrackd -c
-/usr/sbin/conntrackd -R
diff --git a/daemon/include/Makefile.am b/daemon/include/Makefile.am
deleted file mode 100644
index e669d73..0000000
--- a/daemon/include/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-
-noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \
-		 sync.h conntrackd.h local.h us-conntrack.h \
-		 debug.h log.h hash.h mcast.h buffer.h
-
diff --git a/daemon/include/alarm.h b/daemon/include/alarm.h
deleted file mode 100644
index 93e6482..0000000
--- a/daemon/include/alarm.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef _TIMER_H_
-#define _TIMER_H_
-
-#include "linux_list.h"
-
-struct alarm_list {
-	struct list_head	head;
-	unsigned long		expires;
-	void			*data;
-	void			(*function)(struct alarm_list *a, void *data);
-};
-
-#endif
diff --git a/daemon/include/buffer.h b/daemon/include/buffer.h
deleted file mode 100644
index 8d72dfb..0000000
--- a/daemon/include/buffer.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef _BUFFER_H_
-#define _BUFFER_H_
-
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <pthread.h>
-#include "linux_list.h"
-
-struct buffer {
-	pthread_mutex_t lock;
-	size_t max_size;
-	size_t cur_size;
-	struct list_head head;
-};
-
-struct buffer_node {
-	struct list_head head;
-	size_t size;
-	char data[0];
-};
-
-struct buffer *buffer_create(size_t max_size);
-void buffer_destroy(struct buffer *b);
-int buffer_add(struct buffer *b, const void *data, size_t size);
-void buffer_del(struct buffer *b, void *data);
-void __buffer_del(struct buffer *b, void *data);
-void buffer_iterate(struct buffer *b, 
-		    void *data, 
-		    int (*iterate)(void *data1, void *data2));
-
-#endif
diff --git a/daemon/include/cache.h b/daemon/include/cache.h
deleted file mode 100644
index 7d9559a..0000000
--- a/daemon/include/cache.h
+++ /dev/null
@@ -1,92 +0,0 @@
-#ifndef _CACHE_H_
-#define _CACHE_H_
-
-#include <sys/types.h>
-#include <time.h>
-
-/* cache features */
-enum {
-	NO_FEATURES = 0,
-
-	TIMER_FEATURE = 0,
-	TIMER = (1 << TIMER_FEATURE),
-
-	LIFETIME_FEATURE = 2,
-	LIFETIME = (1 << LIFETIME_FEATURE),
-
-	__CACHE_MAX_FEATURE
-};
-#define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE
-
-struct cache;
-struct us_conntrack;
-
-struct cache_feature {
-	size_t size;
-	void (*add)(struct us_conntrack *u, void *data);
-	void (*update)(struct us_conntrack *u, void *data);
-	void (*destroy)(struct us_conntrack *u, void *data);
-	int  (*dump)(struct us_conntrack *u, void *data, char *buf, int type);
-};
-
-extern struct cache_feature lifetime_feature;
-extern struct cache_feature timer_feature;
-
-#define CACHE_MAX_NAMELEN 32
-
-struct cache {
-	char name[CACHE_MAX_NAMELEN];
-	struct hashtable *h;
-
-	unsigned int num_features;
-	struct cache_feature **features;
-	unsigned int feature_type[CACHE_MAX_FEATURE];
-	unsigned int *feature_offset;
-	struct cache_extra *extra;
-	unsigned int extra_offset;
-
-        /* statistics */
-	unsigned int add_ok;
-	unsigned int del_ok;
-	unsigned int upd_ok;
-
-	unsigned int add_fail;
-	unsigned int del_fail;
-	unsigned int upd_fail;
-
-	unsigned int commit_ok;
-	unsigned int commit_exist;
-	unsigned int commit_fail;
-
-	unsigned int flush;
-};
-
-struct cache_extra {
-	unsigned int size;
-
-	void (*add)(struct us_conntrack *u, void *data);
-	void (*update)(struct us_conntrack *u, void *data);
-	void (*destroy)(struct us_conntrack *u, void *data);
-};
-
-struct nf_conntrack;
-
-struct cache *cache_create(char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra);
-void cache_destroy(struct cache *e);
-
-struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct);
-struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct);
-struct us_conntrack *cache_update_force(struct cache *c, struct nf_conntrack *ct);
-int cache_del(struct cache *c, struct nf_conntrack *ct);
-int cache_test(struct cache *c, struct nf_conntrack *ct);
-void cache_stats(struct cache *c, int fd);
-struct us_conntrack *cache_get_conntrack(struct cache *, void *);
-void *cache_get_extra(struct cache *, void *);
-
-/* iterators */
-void cache_dump(struct cache *c, int fd, int type);
-void cache_commit(struct cache *c);
-void cache_flush(struct cache *c);
-void cache_bulk(struct cache *c);
-
-#endif
diff --git a/daemon/include/conntrackd.h b/daemon/include/conntrackd.h
deleted file mode 100644
index a5f7a3a..0000000
--- a/daemon/include/conntrackd.h
+++ /dev/null
@@ -1,174 +0,0 @@
-#ifndef _CONNTRACKD_H_
-#define _CONNTRACKD_H_
-
-#include "mcast.h"
-#include "local.h"
-
-#include <stdio.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h> 
-#include "cache.h"
-#include "debug.h"
-#include <signal.h>
-#include "state_helper.h"
-#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
-
-/* UNIX facilities */
-#define FLUSH_MASTER	0	/* flush kernel conntrack table 	*/
-#define RESYNC_MASTER	1	/* resync with kernel conntrack table 	*/
-#define DUMP_INTERNAL 	16	/* dump internal cache 			*/
-#define DUMP_EXTERNAL 	17	/* dump external cache 			*/
-#define COMMIT		18	/* commit external cache		*/
-#define FLUSH_CACHE	19	/* flush cache				*/
-#define KILL		20	/* kill conntrackd			*/
-#define STATS		21	/* dump statistics			*/
-#define SEND_BULK	22	/* send a bulk				*/
-#define REQUEST_DUMP	23	/* request dump 			*/
-#define DUMP_INT_XML	24	/* dump internal cache in XML		*/
-#define DUMP_EXT_XML	25	/* dump external cache in XML		*/
-
-#define DEFAULT_CONFIGFILE	"/etc/conntrackd/conntrackd.conf"
-#define DEFAULT_LOCKFILE	"/var/lock/conntrackd.lock"
-
-enum {
-	STRIP_NAT_BIT = 0,
-	STRIP_NAT = (1 << STRIP_NAT_BIT),
-
-	DELAY_DESTROY_MSG_BIT = 1,
-	DELAY_DESTROY_MSG = (1 << DELAY_DESTROY_MSG_BIT),
-
-	RELAX_TRANSITIONS_BIT = 2,
-	RELAX_TRANSITIONS = (1 << RELAX_TRANSITIONS_BIT),
-
-	SYNC_MODE_PERSISTENT_BIT = 3,
-	SYNC_MODE_PERSISTENT = (1 << SYNC_MODE_PERSISTENT_BIT),
-
-	SYNC_MODE_NACK_BIT = 4,
-	SYNC_MODE_NACK = (1 << SYNC_MODE_NACK_BIT),
-
-	DONT_CHECKSUM_BIT = 5,
-	DONT_CHECKSUM = (1 << DONT_CHECKSUM_BIT),
-};
-
-/* daemon/request modes */
-#define NOT_SET         0
-#define DAEMON		1
-#define REQUEST		2
-
-/* conntrackd modes */
-#define SYNC_MODE	0
-#define STATS_MODE      1
-
-/* FILENAME_MAX is 4096 on my system, perhaps too much? */
-#ifndef FILENAME_MAXLEN
-#define FILENAME_MAXLEN 256
-#endif
-
-union inet_address {
-	u_int32_t ipv4;
-	u_int32_t ipv6[4];
-	u_int32_t all[4];
-};
-
-#define CONFIG(x) conf.x
-
-struct ct_conf {
-	char logfile[FILENAME_MAXLEN];
-	char lockfile[FILENAME_MAXLEN];
-	int hashsize;			/* hashtable size */
-	struct mcast_conf mcast;	/* multicast settings */
-	struct local_conf local;	/* unix socket facilities */
-	int limit;
-	int refresh;
-	int cache_timeout;		/* cache entries timeout */
-	int commit_timeout;		/* committed entries timeout */
-	unsigned int netlink_buffer_size;
-	unsigned int netlink_buffer_size_max_grown;
-	unsigned char ignore_protocol[IPPROTO_MAX];
-	union inet_address *listen_to;
-	unsigned int listen_to_len;
-	unsigned int flags;
-	int family;			/* protocol family */
-	unsigned int resend_buffer_size;/* NACK protocol */
-	unsigned int window_size;
-};
-
-#define STATE(x) st.x
-
-struct ct_general_state {
-	sigset_t 			block;
-	FILE 				*log;
-	int 				local;
-	struct ct_mode 			*mode;
-	struct ignore_pool		*ignore_pool;
-
-	struct nfnl_handle		*event;         /* event handler */
-	struct nfnl_handle		*sync;          /* sync handler */
-	struct nfnl_handle		*dump;		/* dump handler */
-
-	struct nfnl_subsys_handle	*subsys_event;  /* events */
-	struct nfnl_subsys_handle	*subsys_sync;	/* resync */
-	struct nfnl_subsys_handle	*subsys_dump;   /* dump */
-
-	/* statistics */
-	u_int64_t			malformed;
-	u_int64_t 			bytes[NFCT_DIR_MAX];
-	u_int64_t 			packets[NFCT_DIR_MAX];
-};
-
-#define STATE_SYNC(x) state.sync->x
-
-struct ct_sync_state {
-	struct cache *internal; 	/* internal events cache (netlink) */
-	struct cache *external; 	/* external events cache (mcast) */
-
-	struct mcast_sock *mcast_server;  /* multicast socket: incoming */
-	struct mcast_sock *mcast_client;  /* multicast socket: outgoing  */
-
-	struct sync_mode *mcast_sync;
-	struct buffer *buffer;
-
-	u_int32_t last_seq_sent;	/* last sequence number sent */
-	u_int32_t last_seq_recv;	/* last sequence number recv */
-	u_int64_t packets_replayed;	/* number of replayed packets */
-	u_int64_t packets_lost;         /* lost packets: sequence tracking */
-};
-
-#define STATE_STATS(x) state.stats->x
-
-struct ct_stats_state {
-	struct cache *cache;            /* internal events cache (netlink) */
-};
-
-union ct_state {
-	struct ct_sync_state *sync;
-	struct ct_stats_state *stats;
-};
-
-extern struct ct_conf conf;
-extern union ct_state state;
-extern struct ct_general_state st;
-
-#ifndef IPPROTO_VRRP
-#define IPPROTO_VRRP 112
-#endif
-
-struct ct_mode {
-	int (*init)(void);
-	int (*add_fds_to_set)(fd_set *readfds);
-	void (*step)(fd_set *readfds);
-	int (*local)(int fd, int type, void *data);
-	void (*kill)(void);
-	void (*dump)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
-	void (*overrun)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
-	void (*event_new)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
-	void (*event_upd)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
-	int (*event_dst)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
-};
-
-/* conntrackd modes */
-extern struct ct_mode sync_mode;
-extern struct ct_mode stats_mode;
-
-#define MAX(x, y) x > y ? x : y
-
-#endif
diff --git a/daemon/include/debug.h b/daemon/include/debug.h
deleted file mode 100644
index 67f2c71..0000000
--- a/daemon/include/debug.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef _DEBUG_H
-#define _DEBUG_H
-
-#if 0
-#define debug printf
-#else
-#define debug
-#endif
-
-#include <string.h>
-#include <netinet/in.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-
-static inline void debug_ct(struct nf_conntrack *ct, char *msg)
-{
-	struct in_addr addr, addr2, addr3, addr4;
-
-	debug("----%s (%p) ----\n", msg, ct);
-	memcpy(&addr, 
-	       nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), 
-	       sizeof(u_int32_t));
-	memcpy(&addr2, 
-	       nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), 
-	       sizeof(u_int32_t));
-	memcpy(&addr3, 
-	       nfct_get_attr(ct, ATTR_REPL_IPV4_SRC), 
-	       sizeof(u_int32_t));
-	memcpy(&addr4, 
-	       nfct_get_attr(ct, ATTR_REPL_IPV4_DST), 
-	       sizeof(u_int32_t));
-
-	debug("status: %x\n", nfct_get_attr_u32(ct, ATTR_STATUS));
-	debug("l3:%d l4:%d ",
-			nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO),
-			nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO));
-	debug("%s:%hu ->", inet_ntoa(addr),
-			   ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC)));
-	debug("%s:%hu\n",
-			inet_ntoa(addr2),
-			ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)));
-	debug("l3:%d l4:%d ",
-			nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO),
-			nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO));
-	debug("%s:%hu ->",
-			inet_ntoa(addr3),
-			ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)));
-	debug("%s:%hu\n",
-			inet_ntoa(addr4),
-			ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)));
-	debug("-------------------------\n");
-}
-
-#endif
diff --git a/daemon/include/hash.h b/daemon/include/hash.h
deleted file mode 100644
index fd971e7..0000000
--- a/daemon/include/hash.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef _NF_SET_HASH_H_
-#define _NF_SET_HASH_H_
-
-#include <unistd.h>
-#include <sys/types.h>
-#include "slist.h"
-#include "linux_list.h"
-
-struct hashtable;
-struct hashtable_node;
-
-struct hashtable {
-	u_int32_t hashsize;
-	u_int32_t limit;
-	u_int32_t count;
-	u_int32_t initval;
-	u_int32_t datasize;
-	
-	u_int32_t	(*hash)(const void *data, struct hashtable *table);
-	int		(*compare)(const void *data1, const void *data2);
-
-	struct slist_head 	members[0];
-};
-
-struct hashtable_node {
-	struct slist_head head;
-	char data[0];
-};
-
-struct hashtable_node *hashtable_alloc_node(int datasize, void *data);
-void hashtable_destroy_node(struct hashtable_node *h);
-
-struct hashtable *
-hashtable_create(int hashsize, int limit, int datasize,
-		 u_int32_t (*hash)(const void *data, struct hashtable *table),
-		 int (*compare)(const void *data1, const void *data2));
-void hashtable_destroy(struct hashtable *h);
-
-void *hashtable_add(struct hashtable *table, void *data);
-void *hashtable_test(struct hashtable *table, const void *data);
-int hashtable_del(struct hashtable *table, void *data);
-int hashtable_flush(struct hashtable *table);
-int hashtable_iterate(struct hashtable *table, void *data,
-		      int (*iterate)(void *data1, void *data2));
-unsigned int hashtable_counter(struct hashtable *table);
-
-#endif
diff --git a/daemon/include/ignore.h b/daemon/include/ignore.h
deleted file mode 100644
index 40cb02d..0000000
--- a/daemon/include/ignore.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _IGNORE_H_
-#define _IGNORE_H_
-
-struct ignore_pool {
-	struct hashtable *h;
-};
-
-struct ignore_pool *ignore_pool_create(u_int8_t family);
-void ignore_pool_destroy(struct ignore_pool *ip);
-int ignore_pool_add(struct ignore_pool *ip, void *data);
-
-#endif
diff --git a/daemon/include/jhash.h b/daemon/include/jhash.h
deleted file mode 100644
index 38b8780..0000000
--- a/daemon/include/jhash.h
+++ /dev/null
@@ -1,146 +0,0 @@
-#ifndef _LINUX_JHASH_H
-#define _LINUX_JHASH_H
-
-#define u32 unsigned int
-#define u8  char
-
-/* jhash.h: Jenkins hash support.
- *
- * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
- *
- * http://burtleburtle.net/bob/hash/
- *
- * These are the credits from Bob's sources:
- *
- * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
- * hash(), hash2(), hash3, and mix() are externally useful functions.
- * Routines to test the hash are included if SELF_TEST is defined.
- * You can use this free for any purpose.  It has no warranty.
- *
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
- *
- * I've modified Bob's hash to be useful in the Linux kernel, and
- * any bugs present are surely my fault.  -DaveM
- */
-
-/* NOTE: Arguments are modified. */
-#define __jhash_mix(a, b, c) \
-{ \
-  a -= b; a -= c; a ^= (c>>13); \
-  b -= c; b -= a; b ^= (a<<8); \
-  c -= a; c -= b; c ^= (b>>13); \
-  a -= b; a -= c; a ^= (c>>12);  \
-  b -= c; b -= a; b ^= (a<<16); \
-  c -= a; c -= b; c ^= (b>>5); \
-  a -= b; a -= c; a ^= (c>>3);  \
-  b -= c; b -= a; b ^= (a<<10); \
-  c -= a; c -= b; c ^= (b>>15); \
-}
-
-/* The golden ration: an arbitrary value */
-#define JHASH_GOLDEN_RATIO	0x9e3779b9
-
-/* The most generic version, hashes an arbitrary sequence
- * of bytes.  No alignment or length assumptions are made about
- * the input key.
- */
-static inline u32 jhash(const void *key, u32 length, u32 initval)
-{
-	u32 a, b, c, len;
-	const u8 *k = key;
-
-	len = length;
-	a = b = JHASH_GOLDEN_RATIO;
-	c = initval;
-
-	while (len >= 12) {
-		a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
-		b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
-		c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
-
-		__jhash_mix(a,b,c);
-
-		k += 12;
-		len -= 12;
-	}
-
-	c += length;
-	switch (len) {
-	case 11: c += ((u32)k[10]<<24);
-	case 10: c += ((u32)k[9]<<16);
-	case 9 : c += ((u32)k[8]<<8);
-	case 8 : b += ((u32)k[7]<<24);
-	case 7 : b += ((u32)k[6]<<16);
-	case 6 : b += ((u32)k[5]<<8);
-	case 5 : b += k[4];
-	case 4 : a += ((u32)k[3]<<24);
-	case 3 : a += ((u32)k[2]<<16);
-	case 2 : a += ((u32)k[1]<<8);
-	case 1 : a += k[0];
-	};
-
-	__jhash_mix(a,b,c);
-
-	return c;
-}
-
-/* A special optimized version that handles 1 or more of u32s.
- * The length parameter here is the number of u32s in the key.
- */
-static inline u32 jhash2(u32 *k, u32 length, u32 initval)
-{
-	u32 a, b, c, len;
-
-	a = b = JHASH_GOLDEN_RATIO;
-	c = initval;
-	len = length;
-
-	while (len >= 3) {
-		a += k[0];
-		b += k[1];
-		c += k[2];
-		__jhash_mix(a, b, c);
-		k += 3; len -= 3;
-	}
-
-	c += length * 4;
-
-	switch (len) {
-	case 2 : b += k[1];
-	case 1 : a += k[0];
-	};
-
-	__jhash_mix(a,b,c);
-
-	return c;
-}
-
-
-/* A special ultra-optimized versions that knows they are hashing exactly
- * 3, 2 or 1 word(s).
- *
- * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
- *       done at the end is not done here.
- */
-static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
-{
-	a += JHASH_GOLDEN_RATIO;
-	b += JHASH_GOLDEN_RATIO;
-	c += initval;
-
-	__jhash_mix(a, b, c);
-
-	return c;
-}
-
-static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
-{
-	return jhash_3words(a, b, 0, initval);
-}
-
-static inline u32 jhash_1word(u32 a, u32 initval)
-{
-	return jhash_3words(a, 0, 0, initval);
-}
-
-#endif /* _LINUX_JHASH_H */
diff --git a/daemon/include/linux_list.h b/daemon/include/linux_list.h
deleted file mode 100644
index 57b56d7..0000000
--- a/daemon/include/linux_list.h
+++ /dev/null
@@ -1,725 +0,0 @@
-#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/daemon/include/local.h b/daemon/include/local.h
deleted file mode 100644
index 350b8bf..0000000
--- a/daemon/include/local.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _LOCAL_SOCKET_H_
-#define _LOCAL_SOCKET_H_
-
-#include <sys/un.h>
-
-#ifndef UNIX_PATH_MAX
-#define UNIX_PATH_MAX   108
-#endif
-
-struct local_conf {
-	int backlog;
-	int reuseaddr;
-	char path[UNIX_PATH_MAX];
-};
-
-/* local server */
-int local_server_create(struct local_conf *conf);
-void local_server_destroy(int fd);
-int do_local_server_step(int fd, void *data, 
-			 void (*process)(int fd, void *data));
-
-/* local client */
-int local_client_create(struct local_conf *conf);
-void local_client_destroy(int fd);
-int do_local_client_step(int fd, void (*process)(char *buf));
-int do_local_request(int, struct local_conf *,void (*step)(char *buf));
-void local_step(char *buf);
-
-#endif
diff --git a/daemon/include/log.h b/daemon/include/log.h
deleted file mode 100644
index 9ecff30..0000000
--- a/daemon/include/log.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _LOG_H_
-#define _LOG_H_
-
-#include <stdio.h>
-
-FILE *init_log(char *filename);
-void dlog(FILE *fd, char *format, ...);
-void close_log(FILE *fd);
-
-#endif
diff --git a/daemon/include/mcast.h b/daemon/include/mcast.h
deleted file mode 100644
index 0f3e3cd..0000000
--- a/daemon/include/mcast.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef _MCAST_H_
-#define _MCAST_H_
-
-#include <netinet/in.h>
-
-struct mcast_conf {
-	int ipproto;
-	int backlog;
-	int reuseaddr;
-	unsigned short port;
-	union {
-		struct in_addr inet_addr;
-		struct in6_addr inet_addr6;
-	} in;
-	union {
-		struct in_addr interface_addr;
-		struct in6_addr interface_addr6;
-	} ifa;
-};
-
-struct mcast_stats {
-	u_int64_t bytes;
-	u_int64_t messages;
-	u_int64_t error;
-};
-
-struct mcast_sock {
-	int fd;
-	union {
-		struct sockaddr_in ipv4;
-		struct sockaddr_in6 ipv6;
-	} addr;
-	struct mcast_stats stats;
-};
-
-struct mcast_sock *mcast_server_create(struct mcast_conf *conf);
-void mcast_server_destroy(struct mcast_sock *m);
-
-struct mcast_sock *mcast_client_create(struct mcast_conf *conf);
-void mcast_client_destroy(struct mcast_sock *m);
-
-int mcast_send(struct mcast_sock *m, void *data, int size);
-int mcast_recv(struct mcast_sock *m, void *data, int size);
-
-struct mcast_stats *mcast_get_stats(struct mcast_sock *m);
-void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r);
-
-#endif
diff --git a/daemon/include/network.h b/daemon/include/network.h
deleted file mode 100644
index dab50db..0000000
--- a/daemon/include/network.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef _NETWORK_H_
-#define _NETWORK_H_
-
-#include <sys/types.h>
-
-struct nlnetwork {
-	u_int16_t flags; 
-	u_int16_t checksum;
-	u_int32_t seq;
-};
-
-struct nlnetwork_ack {
-	u_int16_t flags; 
-	u_int16_t checksum;
-	u_int32_t seq;
-	u_int32_t from;
-	u_int32_t to;
-};
-
-enum {
-	NET_HELLO_BIT = 0,
-	NET_HELLO = (1 << NET_HELLO_BIT),
-
-	NET_RESYNC_BIT = 1,
-	NET_RESYNC = (1 << NET_RESYNC_BIT),
-
-	NET_NACK_BIT = 2,
-	NET_NACK = (1 << NET_NACK_BIT),
-
-	NET_ACK_BIT = 3,
-	NET_ACK = (1 << NET_ACK_BIT),
-};
-
-#endif
diff --git a/daemon/include/slist.h b/daemon/include/slist.h
deleted file mode 100644
index ab7fa34..0000000
--- a/daemon/include/slist.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef _SLIST_H_
-#define _SLIST_H_
-
-#include "linux_list.h"
-
-#define INIT_SLIST_HEAD(ptr) ((ptr).next = NULL)
-
-struct slist_head {
-	struct slist_head *next;
-};
-
-static inline int slist_empty(const struct slist_head *h)
-{
-	return !h->next;
-}
-
-static inline void slist_del(struct slist_head *t, struct slist_head *prev)
-{
-	prev->next = t->next;
-	t->next = LIST_POISON1;
-}
-
-static inline void slist_add(struct slist_head *head, struct slist_head *t)
-{
-	struct slist_head *tmp = head->next;
-	head->next = t;
-	t->next = tmp;
-}
-
-#define slist_entry(ptr, type, member) container_of(ptr,type,member)
-
-#define slist_for_each(pos, head) \
-	for (pos = (head)->next; pos && ({ prefetch(pos.next); 1; }); \
-	     pos = pos->next)
-
-#define slist_for_each_safe(pos, prev, next, head) \
-	for (pos = (head)->next, prev = (head); \
-	     pos && ({ next = pos->next; 1; }); \
-	     ({ prev = (prev->next != next) ? prev->next : prev; }), pos = next)
-
-#endif
diff --git a/daemon/include/state_helper.h b/daemon/include/state_helper.h
deleted file mode 100644
index 1ed0b79..0000000
--- a/daemon/include/state_helper.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _STATE_HELPER_H_
-#define _STATE_HELPER_H_
-
-enum {
-	ST_H_SKIP,
-	ST_H_REPLICATE
-};
-
-struct state_replication_helper {
-	u_int8_t 		proto;
-	unsigned int		state;
-
-	int (*verdict)(const struct state_replication_helper *h,
-		       const struct nf_conntrack *ct); 
-};
-
-int state_helper_verdict(int type, struct nf_conntrack *ct);
-void state_helper_register(struct state_replication_helper *h, int state);
-
-#endif
diff --git a/daemon/include/sync.h b/daemon/include/sync.h
deleted file mode 100644
index 7756c87..0000000
--- a/daemon/include/sync.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _SYNC_HOOKS_H_
-#define _SYNC_HOOKS_H_
-
-struct nlnetwork;
-struct us_conntrack;
-
-struct sync_mode {
-	int internal_cache_flags;
-	int external_cache_flags;
-	struct cache_extra *internal_cache_extra;
-	struct cache_extra *external_cache_extra;
-
-	int  (*init)(void);
-	void (*kill)(void);
-	int  (*local)(int fd, int type, void *data);
-	int  (*pre_recv)(const struct nlnetwork *net);
-	void (*post_send)(const struct nlnetwork *net, struct us_conntrack *u);
-};
-
-extern struct sync_mode notrack;
-extern struct sync_mode nack;
-
-#endif
diff --git a/daemon/include/us-conntrack.h b/daemon/include/us-conntrack.h
deleted file mode 100644
index 3d71e22..0000000
--- a/daemon/include/us-conntrack.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef _US_CONNTRACK_H_
-#define _US_CONNTRACK_H_
-
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-
-/* be careful, do not modify the layout */
-struct us_conntrack {
-	struct 	nf_conntrack *ct;
-	struct  cache *cache;          /* add new attributes here */
-	char 	data[0];
-};
-
-#endif
diff --git a/daemon/src/Makefile.am b/daemon/src/Makefile.am
deleted file mode 100644
index 5d1c6cb..0000000
--- a/daemon/src/Makefile.am
+++ /dev/null
@@ -1,22 +0,0 @@
-include $(top_srcdir)/Make_global.am
-
-YACC=@YACC@ -d
-
-CLEANFILES = read_config_yy.c read_config_lex.c
-
-sbin_PROGRAMS = conntrackd
-conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \
-		    local.c log.c mcast.c netlink.c proxy.c lock.c \
-		    ignore_pool.c \
-		    cache.c cache_iterators.c \
-		    cache_lifetime.c cache_timer.c \
-		    sync-mode.c sync-notrack.c sync-nack.c \
-		    traffic_stats.c stats-mode.c \
-		    network.c checksum.c \
-		    state_helper.c state_helper_tcp.c \
-		    read_config_yy.y read_config_lex.l
-
-conntrackd_LDFLAGS = $(all_libraries) -lnfnetlink -lnetfilter_conntrack \
-		     -lpthread
-
-EXTRA_DIST = read_config_yy.h
diff --git a/daemon/src/alarm.c b/daemon/src/alarm.c
deleted file mode 100644
index 1a465c2..0000000
--- a/daemon/src/alarm.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include "linux_list.h"
-#include "conntrackd.h"
-#include "alarm.h"
-#include "jhash.h"
-#include <pthread.h>
-#include <time.h>
-#include <errno.h>
-
-/* alarm cascade */
-#define ALARM_CASCADE_SIZE     10
-static struct list_head *alarm_cascade;
-
-/* thread stuff */
-static pthread_t alarm_thread;
-
-struct alarm_list *create_alarm()
-{	
-	return (struct alarm_list *) malloc(sizeof(struct alarm_list));
-}
-
-void destroy_alarm(struct alarm_list *t)
-{
-	free(t);
-}
-
-void set_alarm_expiration(struct alarm_list *t, unsigned long expires)
-{
-	t->expires = expires;
-}
-
-void set_alarm_function(struct alarm_list *t,
-			void (*fcn)(struct alarm_list *a, void *data))
-{
-	t->function = fcn;
-}
-
-void set_alarm_data(struct alarm_list *t, void *data)
-{
-	t->data = data;
-}
-
-void init_alarm(struct alarm_list *t)
-{
-	INIT_LIST_HEAD(&t->head);
-
-	t->expires 	= 0;
-	t->data 	= 0;
-	t->function 	= NULL;
-}
-
-void add_alarm(struct alarm_list *alarm)
-{
-	unsigned int pos = jhash(alarm, sizeof(alarm), 0) % ALARM_CASCADE_SIZE;
-
-	list_add(&alarm->head, &alarm_cascade[pos]);
-}
-
-void del_alarm(struct alarm_list *alarm)
-{
-	list_del(&alarm->head);
-}
-
-int mod_alarm(struct alarm_list *alarm, unsigned long expires)
-{
-	alarm->expires = expires;
-	return 0;
-}
-
-void __run_alarms()
-{
-	struct list_head *i, *tmp;
-	struct alarm_list *t;
-	struct timespec req = {0, 1000000000 / ALARM_CASCADE_SIZE};
-	struct timespec rem;
-	static int step = 0;
-
-retry:
-	if (nanosleep(&req, &rem) == -1) {
-		/* interrupted syscall: retry with remaining time */
-		if (errno == EINTR) {
-			memcpy(&req, &rem, sizeof(struct timespec));
-			goto retry;
-		}
-	}
-
-	lock();
-	list_for_each_safe(i, tmp, &alarm_cascade[step]) {
-		t = (struct alarm_list *) i;
-
-		t->expires--;
-		if (t->expires == 0)
-			t->function(t, t->data);
-	}
-	step = (step + 1) < ALARM_CASCADE_SIZE ? step + 1 : 0;
-	unlock();
-}
-
-void *run_alarms(void *foo)
-{
-	while(1)
-		__run_alarms();
-}
-
-int create_alarm_thread()
-{
-	int i;
-
-	alarm_cascade = malloc(sizeof(struct list_head) * ALARM_CASCADE_SIZE);
-	if (alarm_cascade == NULL)
-		return -1;
-
-	for (i=0; i<ALARM_CASCADE_SIZE; i++)
-		INIT_LIST_HEAD(&alarm_cascade[i]);
-
-	return pthread_create(&alarm_thread, NULL, run_alarms, NULL);
-}
-
-int destroy_alarm_thread()
-{
-	return pthread_cancel(alarm_thread);
-}
diff --git a/daemon/src/buffer.c b/daemon/src/buffer.c
deleted file mode 100644
index fa0b859..0000000
--- a/daemon/src/buffer.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * (C) 2006-2007 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "buffer.h"
-
-struct buffer *buffer_create(size_t max_size)
-{
-	struct buffer *b;
-
-	b = malloc(sizeof(struct buffer));
-	if (b == NULL)
-		return NULL;
-	memset(b, 0, sizeof(struct buffer));
-
-	b->max_size = max_size;
-	INIT_LIST_HEAD(&b->head);
-	pthread_mutex_init(&b->lock, NULL);
-
-	return b;
-}
-
-void buffer_destroy(struct buffer *b)
-{
-	struct list_head *i, *tmp;
-	struct buffer_node *node;
-
-	pthread_mutex_lock(&b->lock);
-	list_for_each_safe(i, tmp, &b->head) {
-		node = (struct buffer_node *) i;
-		list_del(i);
-		free(node);
-	}
-	pthread_mutex_unlock(&b->lock);
-	pthread_mutex_destroy(&b->lock);
-	free(b);
-}
-
-static struct buffer_node *buffer_node_create(const void *data, size_t size)
-{
-	struct buffer_node *n;
-
-	n = malloc(sizeof(struct buffer_node) + size);
-	if (n == NULL)
-		return NULL;
-
-	INIT_LIST_HEAD(&n->head);
-	n->size = size;
-	memcpy(n->data, data, size);
-
-	return n;
-}
-
-int buffer_add(struct buffer *b, const void *data, size_t size)
-{
-	int ret = 0;
-	struct buffer_node *n;
-
-	pthread_mutex_lock(&b->lock);
-
-	/* does it fit this buffer? */
-	if (size > b->max_size) {
-		errno = ENOSPC;
-		ret = -1;
-		goto err;
-	}
-
-retry:
-	/* buffer is full: kill the oldest entry */
-	if (b->cur_size + size > b->max_size) {
-		n = (struct buffer_node *) b->head.prev;
-		list_del(b->head.prev);
-		b->cur_size -= n->size;
-		free(n);
-		goto retry;
-	}
-
-	n = buffer_node_create(data, size);
-	if (n == NULL) {
-		ret = -1;
-		goto err;
-	}
-
-	list_add(&n->head, &b->head);
-	b->cur_size += size;
-
-err:
-	pthread_mutex_unlock(&b->lock);
-	return ret;
-}
-
-void __buffer_del(struct buffer *b, void *data)
-{
-	struct buffer_node *n = container_of(data, struct buffer_node, data); 
-
-	list_del(&n->head);
-	b->cur_size -= n->size;
-	free(n);
-}
-
-void buffer_del(struct buffer *b, void *data)
-{
-	pthread_mutex_lock(&b->lock);
-	buffer_del(b, data);
-	pthread_mutex_unlock(&b->lock);
-}
-
-void buffer_iterate(struct buffer *b, 
-		    void *data, 
-		    int (*iterate)(void *data1, void *data2))
-{
-	struct list_head *i, *tmp;
-	struct buffer_node *n;
-
-	pthread_mutex_lock(&b->lock);
-	list_for_each_safe(i, tmp, &b->head) {
-		n = (struct buffer_node *) i;
-		if (iterate(n->data, data))
-			break;
-	}
-	pthread_mutex_unlock(&b->lock);
-}
diff --git a/daemon/src/cache.c b/daemon/src/cache.c
deleted file mode 100644
index 6f7442b..0000000
--- a/daemon/src/cache.c
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * (C) 2006-2007 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "jhash.h"
-#include "hash.h"
-#include "conntrackd.h"
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <errno.h>
-#include "us-conntrack.h"
-#include "cache.h"
-#include "debug.h"
-
-static u_int32_t hash(const void *data, struct hashtable *table)
-{
-	unsigned int a, b;
-	const struct us_conntrack *u = data;
-	struct nf_conntrack *ct = u->ct;
-
-	a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), sizeof(u_int32_t),
-		  ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) |
-		   (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO))));
-
-	b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), sizeof(u_int32_t),
-		  ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) |
-		   (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST))));
-
-	return jhash_2words(a, b, 0) % table->hashsize;
-}
-
-static u_int32_t hash6(const void *data, struct hashtable *table)
-{
-	unsigned int a, b;
-	const struct us_conntrack *u = data;
-	struct nf_conntrack *ct = u->ct;
-
-	a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(u_int32_t),
-		  ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) |
-		   (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO))));
-
-	b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_DST), sizeof(u_int32_t),
-		  ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) |
-		   (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST))));
-
-	return jhash_2words(a, b, 0) % table->hashsize;
-}
-
-static int __compare(const struct nf_conntrack *ct1, 
-		     const struct nf_conntrack *ct2)
-{
-	return ((nfct_get_attr_u8(ct1, ATTR_ORIG_L3PROTO) ==
-	  	 nfct_get_attr_u8(ct2, ATTR_ORIG_L3PROTO)) &&
-		(nfct_get_attr_u8(ct1, ATTR_ORIG_L4PROTO) ==
-		 nfct_get_attr_u8(ct2, ATTR_ORIG_L4PROTO)) && 
-		(nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_SRC) ==
-		 nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_SRC)) &&
-		(nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_DST) ==
-	 	 nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_DST)) &&
-		(nfct_get_attr_u16(ct1, ATTR_REPL_PORT_SRC) ==
-	 	 nfct_get_attr_u16(ct2, ATTR_REPL_PORT_SRC)) &&
-		(nfct_get_attr_u16(ct1, ATTR_REPL_PORT_DST) ==
-	 	 nfct_get_attr_u16(ct2, ATTR_REPL_PORT_DST)));
-}
-
-static int compare(const void *data1, const void *data2)
-{
-	const struct us_conntrack *u1 = data1;
-	const struct us_conntrack *u2 = data2;
-
-	return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_SRC) ==
-	         nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_SRC)) &&
-	 	(nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_DST) ==
-		 nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_DST)) &&
-		(nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_SRC) ==
-		 nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_SRC)) &&
-		(nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_DST) ==
-		 nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_DST)) &&
-		 __compare(u1->ct, u2->ct));
-}
-
-static int compare6(const void *data1, const void *data2)
-{
-	const struct us_conntrack *u1 = data1;
-	const struct us_conntrack *u2 = data2;
-
-	return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_SRC) ==
-	         nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_SRC)) &&
-	 	(nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_DST) ==
-		 nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_DST)) &&
-		(nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_SRC) ==
-		 nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_SRC)) &&
-		(nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_DST) ==
-		 nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_DST)) &&
-		 __compare(u1->ct, u2->ct));
-}
-
-struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = {
-	[TIMER_FEATURE]		= &timer_feature,
-	[LIFETIME_FEATURE]	= &lifetime_feature,
-};
-
-struct cache *cache_create(char *name, 
-			   unsigned int features, 
-			   u_int8_t proto,
-			   struct cache_extra *extra)
-{
-	size_t size = sizeof(struct us_conntrack);
-	int i, j = 0;
-	struct cache *c;
-	struct cache_feature *feature_array[CACHE_MAX_FEATURE] = {};
-	unsigned int feature_offset[CACHE_MAX_FEATURE] = {};
-	unsigned int feature_type[CACHE_MAX_FEATURE] = {};
-
-	c = malloc(sizeof(struct cache));
-	if (!c)
-		return NULL;
-	memset(c, 0, sizeof(struct cache));
-
-	strcpy(c->name, name);
-
-	for (i = 0; i < CACHE_MAX_FEATURE; i++) {
-		if ((1 << i) & features) {
-			feature_array[j] = cache_feature[i];
-			feature_offset[j] = size;
-			feature_type[i] = j;
-			size += cache_feature[i]->size;
-			j++;
-		}
-	}
-
-	memcpy(c->feature_type, feature_type, sizeof(feature_type));
-
-	c->features = malloc(sizeof(struct cache_feature) * j);
-	if (!c->features) {
-		free(c);
-		return NULL;
-	}
-	memcpy(c->features, feature_array, sizeof(struct cache_feature) * j);
-	c->num_features = j;
-
-	c->extra_offset = size;
-	c->extra = extra;
-	if (extra)
-		size += extra->size;
-
-	c->feature_offset = malloc(sizeof(unsigned int) * j);
-	if (!c->feature_offset) {
-		free(c->features);
-		free(c);
-		return NULL;
-	}
-	memcpy(c->feature_offset, feature_offset, sizeof(unsigned int) * j);
-
-	switch(proto) {
-	case AF_INET:
-		c->h = hashtable_create(CONFIG(hashsize),
-					CONFIG(limit),
-					size,
-					hash,
-					compare);
-		break;
-	case AF_INET6:
-		c->h = hashtable_create(CONFIG(hashsize),
-					CONFIG(limit),
-					size,
-					hash6,
-					compare6);
-		break;
-	}
-
-	if (!c->h) {
-		free(c->features);
-		free(c->feature_offset);
-		free(c);
-		return NULL;
-	}
-
-	return c;
-}
-
-void cache_destroy(struct cache *c)
-{
-	lock();
-	hashtable_destroy(c->h);
-	unlock();
-	free(c->features);
-	free(c->feature_offset);
-	free(c);
-}
-
-static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct)
-{
-	int i;
-	size_t size = c->h->datasize;
-	char buf[size];
-	struct us_conntrack *u = (struct us_conntrack *) buf;
-	struct nf_conntrack *newct;
-
-	memset(u, 0, size);
-
-	u->cache = c;
-	if ((u->ct = newct = nfct_new()) == NULL) {
-		errno = ENOMEM;
-		return 0;
-	}
-	memcpy(u->ct, ct, nfct_sizeof(ct));
-
-	u = hashtable_add(c->h, u);
-	if (u) {
-		void *data = u->data;
-
-        	for (i = 0; i < c->num_features; i++) {
-			c->features[i]->add(u, data);
-			data += c->features[i]->size;
-		}
-
-		if (c->extra)
-			c->extra->add(u, ((void *) u) + c->extra_offset);
-
-		return u;
-	}
-	free(newct);
-
-	return NULL;
-}
-
-struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct)
-{
-	struct us_conntrack *u;
-
-	u = __add(c, ct);
-	if (u) {
-		c->add_ok++;
-		return u;
-	}
-	c->add_fail++;
-
-	return NULL;
-}
-
-struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct)
-{
-	struct us_conntrack *u;
-
-	lock();
-	u = __cache_add(c, ct);
-	unlock();
-
-	return u;
-}
-
-static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct)
-{
-	size_t size = c->h->datasize;
-	char buf[size];
-	struct us_conntrack *u = (struct us_conntrack *) buf;
-
-	u->ct = ct;
-
-	u = (struct us_conntrack *) hashtable_test(c->h, u);
-	if (u) {
-		int i;
-		void *data = u->data;
-
-		for (i = 0; i < c->num_features; i++) {
-			c->features[i]->update(u, data);
-			data += c->features[i]->size;
-		}
-
-		if (c->extra)
-			c->extra->update(u, ((void *) u) + c->extra_offset);
-
-		if (nfct_attr_is_set(ct, ATTR_STATUS))
-		    	nfct_set_attr_u32(u->ct, ATTR_STATUS,
-					  nfct_get_attr_u32(ct, ATTR_STATUS));
-		if (nfct_attr_is_set(ct, ATTR_TCP_STATE))
-			nfct_set_attr_u8(u->ct, ATTR_TCP_STATE,
-					 nfct_get_attr_u8(ct, ATTR_TCP_STATE));
-		if (nfct_attr_is_set(ct, ATTR_TIMEOUT))
-			nfct_set_attr_u32(u->ct, ATTR_TIMEOUT,
-					  nfct_get_attr_u32(ct, ATTR_TIMEOUT));
-
-		return u;
-	} 
-	return NULL;
-}
-
-struct us_conntrack *__cache_update(struct cache *c, struct nf_conntrack *ct)
-{
-	struct us_conntrack *u;
-
-	u = __update(c, ct);
-	if (u) {
-		c->upd_ok++;
-		return u;
-	}
-	c->upd_fail++;
-	
-	return NULL;
-}
-
-struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct)
-{
-	struct us_conntrack *u;
-
-	lock();
-	u = __cache_update(c, ct);
-	unlock();
-
-	return u;
-}
-
-struct us_conntrack *cache_update_force(struct cache *c,
-					struct nf_conntrack *ct)
-{
-	struct us_conntrack *u;
-
-	lock();
-	if ((u = __update(c, ct)) != NULL) {
-		c->upd_ok++;
-		unlock();
-		return u;
-	}
-	if ((u = __add(c, ct)) != NULL) {
-		c->add_ok++;
-		unlock();
-		return u;
-	}
-	c->add_fail++;
-	unlock();
-	return NULL;
-}
-
-int cache_test(struct cache *c, struct nf_conntrack *ct)
-{
-	size_t size = c->h->datasize;
-	char buf[size];
-	struct us_conntrack *u = (struct us_conntrack *) buf;
-	void *ret;
-
-	u->ct = ct;
-
-	lock();
-	ret = hashtable_test(c->h, u);
-	unlock();
-
-	return ret != NULL;
-}
-
-static int __del(struct cache *c, struct nf_conntrack *ct)
-{
-	size_t size = c->h->datasize;
-	char buf[size];
-	struct us_conntrack *u = (struct us_conntrack *) buf;
-
-	u->ct = ct;
-
-	u = (struct us_conntrack *) hashtable_test(c->h, u);
-	if (u) {
-		int i;
-		void *data = u->data;
-		struct nf_conntrack *p = u->ct;
-
-		for (i = 0; i < c->num_features; i++) {
-			c->features[i]->destroy(u, data);
-			data += c->features[i]->size;
-		}
-
-		if (c->extra)
-			c->extra->destroy(u, ((void *) u) + c->extra_offset);
-
-		hashtable_del(c->h, u);
-		free(p);
-		return 1;
-	}
-	return 0;
-}
-
-int __cache_del(struct cache *c, struct nf_conntrack *ct)
-{
-	if (__del(c, ct)) {
-		c->del_ok++;
-		return 1;
-	}
-	c->del_fail++;
-
-	return 0;
-}
-
-int cache_del(struct cache *c, struct nf_conntrack *ct)
-{
-	int ret;
-
-	lock();
-	ret = __cache_del(c, ct);
-	unlock();
-
-	return ret;
-}
-
-struct us_conntrack *cache_get_conntrack(struct cache *c, void *data)
-{
-	return data - c->extra_offset;
-}
-
-void *cache_get_extra(struct cache *c, void *data)
-{
-	return data + c->extra_offset;
-}
-
-void cache_stats(struct cache *c, int fd)
-{
-	char buf[512];
-	int size;
-
-	lock();
-	size = sprintf(buf, "cache %s:\n"
-			    "current active connections:\t%12u\n"
-			    "connections created:\t\t%12u\tfailed:\t%12u\n"
-			    "connections updated:\t\t%12u\tfailed:\t%12u\n"
-			    "connections destroyed:\t\t%12u\tfailed:\t%12u\n\n",
-			    			 c->name,
-			    			 hashtable_counter(c->h),
-			    			 c->add_ok, 
-			    			 c->add_fail,
-						 c->upd_ok,
-						 c->upd_fail,
-						 c->del_ok,
-						 c->del_fail);
-	unlock();
-	send(fd, buf, size, 0);
-}
diff --git a/daemon/src/cache_iterators.c b/daemon/src/cache_iterators.c
deleted file mode 100644
index 5d5d22b..0000000
--- a/daemon/src/cache_iterators.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * (C) 2006-2007 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "cache.h"
-#include "jhash.h"
-#include "hash.h"
-#include "conntrackd.h"
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <errno.h>
-#include "us-conntrack.h"
-#include "debug.h"
-
-struct __dump_container {
-	int fd;
-	int type;
-};
-
-static int do_dump(void *data1, void *data2)
-{
-	char buf[1024];
-	int size;
-	struct __dump_container *container = data1;
-	struct us_conntrack *u = data2;
-	void *data = u->data;
-	int i;
-
-	memset(buf, 0, sizeof(buf));
-	size = nfct_snprintf(buf, 
-			     sizeof(buf), 
-			     u->ct, 
-			     NFCT_T_UNKNOWN, 
-			     container->type,
-			     0);
-
-	for (i = 0; i < u->cache->num_features; i++) {
-		if (u->cache->features[i]->dump) {
-			size += u->cache->features[i]->dump(u, 
-							    data, 
-							    buf+size,
-							    container->type);
-			data += u->cache->features[i]->size;
-		}
-	}
-	size += sprintf(buf+size, "\n");
-	if (send(container->fd, buf, size, 0) == -1) {
-		if (errno != EPIPE)
-			return -1;
-	}
-
-	return 0;
-}
-
-void cache_dump(struct cache *c, int fd, int type)
-{
-	struct __dump_container tmp = {
-		.fd	= fd,
-		.type	= type
-	};
-
-	lock();
-	hashtable_iterate(c->h, (void *) &tmp, do_dump);
-	unlock();
-}
-
-static int do_commit(void *data1, void *data2)
-{
-	int ret;
-	struct cache *c = data1;
-	struct us_conntrack *u = data2;
-	struct nf_conntrack *ct;
-	char buf[4096];
-	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
-
-	ct = nfct_clone(u->ct);
-	if (ct == NULL)
-		return 0;
-
-	if (nfct_attr_is_set(ct, ATTR_STATUS)) {
-		u_int32_t status = nfct_get_attr_u32(ct, ATTR_STATUS);
-		status &= ~IPS_EXPECTED;
-		nfct_set_attr_u32(ct, ATTR_STATUS, status);
-	}
-
-	if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT))
-		nfct_setobjopt(ct, NFCT_SOPT_UNDO_SNAT);
-	if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT))
-		nfct_setobjopt(ct, NFCT_SOPT_UNDO_DNAT);
-	if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT))
-		nfct_setobjopt(ct, NFCT_SOPT_UNDO_SPAT);
-	if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT))
-		nfct_setobjopt(ct, NFCT_SOPT_UNDO_DPAT);
-
-        /* 
-	 * Set a reduced timeout for candidate-to-be-committed
-	 * conntracks that live in the external cache
-	 */
-	nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout));
-
-        ret = nfct_build_query(STATE(subsys_sync),
-			       NFCT_Q_CREATE,
-			       ct,
-			       nlh,
-			       sizeof(buf));
-
-	free(ct);
-
-	if (ret == -1) {
-		/* XXX: Please cleanup this debug crap, default in logfile */
-		debug("--- failed to build: %s --- \n", strerror(errno));
-		return 0;
-	}
-
-	ret = nfnl_query(STATE(sync), nlh);
-	if (ret == -1) {
-		switch(errno) {
-			case EEXIST:
-				c->commit_exist++;
-				break;
-			default:
-				c->commit_fail++;
-				break;
-		}
-		debug("--- failed to commit: %s --- \n", strerror(errno));
-	} else {
-		c->commit_ok++;
-		debug("----- commit -----\n");
-	}
-
-	/* keep iterating even if we have found errors */
-	return 0;
-}
-
-void cache_commit(struct cache *c)
-{
-	unsigned int commit_ok = c->commit_ok;
-	unsigned int commit_exist = c->commit_exist;
-	unsigned int commit_fail = c->commit_fail;
-
-	lock();
-	hashtable_iterate(c->h, c, do_commit);
-	unlock();
-
-	/* calculate new entries committed */
-	commit_ok = c->commit_ok - commit_ok;
-	commit_fail = c->commit_fail - commit_fail;
-	commit_exist = c->commit_exist - commit_exist;
-
-	/* log results */
-	dlog(STATE(log), "Committed %u new entries", commit_ok);
-
-	if (commit_exist)
-		dlog(STATE(log), "%u entries ignored, "
-				 "already exist", commit_exist);
-	if (commit_fail)
-		dlog(STATE(log), "%u entries can't be "
-				 "committed", commit_fail);
-}
-
-static int do_flush(void *data1, void *data2)
-{
-	struct cache *c = data1;
-	struct us_conntrack *u = data2;
-	void *data = u->data;
-	int i;
-
-	for (i = 0; i < c->num_features; i++) {
-		c->features[i]->destroy(u, data);
-		data += c->features[i]->size;
-	}
-	free(u->ct);
-
-	return 0;
-}
-
-void cache_flush(struct cache *c)
-{
-	lock();
-	hashtable_iterate(c->h, c, do_flush);
-	hashtable_flush(c->h);
-	c->flush++;
-	unlock();
-}
-
-#include "sync.h"
-#include "network.h"
-
-static int do_bulk(void *data1, void *data2)
-{
-	int ret;
-	struct us_conntrack *u = data2;
-	char buf[4096];
-	struct nlnetwork *net = (struct nlnetwork *) buf;
-
-	ret = build_network_msg(NFCT_Q_UPDATE,
-				STATE(subsys_sync),
-				u->ct,
-				buf,
-				sizeof(buf));
-	if (ret == -1)
-		debug_ct(u->ct, "failed to build");
-
-	mcast_send_netmsg(STATE_SYNC(mcast_client), net);
-	STATE_SYNC(mcast_sync)->post_send(net, u);
-
-	/* keep iterating even if we have found errors */
-	return 0;
-}
-
-void cache_bulk(struct cache *c)
-{
-	lock();
-	hashtable_iterate(c->h, NULL, do_bulk);
-	unlock();
-}
diff --git a/daemon/src/cache_lifetime.c b/daemon/src/cache_lifetime.c
deleted file mode 100644
index ae54df2..0000000
--- a/daemon/src/cache_lifetime.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <stdio.h>
-#include "conntrackd.h"
-#include "us-conntrack.h"
-#include "cache.h"
-#include "alarm.h"
-
-static void lifetime_add(struct us_conntrack *u, void *data)
-{
-	long *lifetime = data;
-	struct timeval tv;
-
-	gettimeofday(&tv, NULL);
-
-	*lifetime = tv.tv_sec;
-}
-
-static void lifetime_update(struct us_conntrack *u, void *data)
-{
-}
-
-static void lifetime_destroy(struct us_conntrack *u, void *data)
-{
-}
-
-static int lifetime_dump(struct us_conntrack *u, 
-			 void *data, 
-			 char *buf, 
-			 int type)
-{
-	long *lifetime = data;
-	struct timeval tv;
-
-	if (type == NFCT_O_XML)
-		return 0;
-
-	gettimeofday(&tv, NULL);
-
-	return sprintf(buf, " [active since %lds]", tv.tv_sec - *lifetime);
-}
-
-struct cache_feature lifetime_feature = {
-	.size		= sizeof(long),
-	.add		= lifetime_add,
-	.update		= lifetime_update,
-	.destroy	= lifetime_destroy,
-	.dump		= lifetime_dump
-};
diff --git a/daemon/src/cache_timer.c b/daemon/src/cache_timer.c
deleted file mode 100644
index 213b59a..0000000
--- a/daemon/src/cache_timer.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <stdio.h>
-#include "conntrackd.h"
-#include "us-conntrack.h"
-#include "cache.h"
-#include "alarm.h"
-
-static void timeout(struct alarm_list *a, void *data)
-{
-	struct us_conntrack *u = data;
-
-	debug_ct(u->ct, "expired timeout");
-	__cache_del(u->cache, u->ct);
-}
-
-static void timer_add(struct us_conntrack *u, void *data)
-{
-	struct alarm_list *alarm = data;
-
-	init_alarm(alarm);
-	set_alarm_expiration(alarm, CONFIG(cache_timeout));
-	set_alarm_data(alarm, u);
-	set_alarm_function(alarm, timeout);
-	add_alarm(alarm);
-}
-
-static void timer_update(struct us_conntrack *u, void *data)
-{
-	struct alarm_list *alarm = data;
-	mod_alarm(alarm, CONFIG(cache_timeout));
-}
-
-static void timer_destroy(struct us_conntrack *u, void *data)
-{
-	struct alarm_list *alarm = data;
-	del_alarm(alarm);
-}
-
-static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type)
-{
- 	struct alarm_list *alarm = data;
-
-	if (type == NFCT_O_XML)
-		return 0;
-
-	return sprintf(buf, " [expires in %ds]", alarm->expires);
-}
-
-struct cache_feature timer_feature = {
-	.size		= sizeof(struct alarm_list),
-	.add		= timer_add,
-	.update		= timer_update,
-	.destroy	= timer_destroy,
-	.dump		= timer_dump
-};
diff --git a/daemon/src/checksum.c b/daemon/src/checksum.c
deleted file mode 100644
index 41866ff..0000000
--- a/daemon/src/checksum.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 
- * Extracted from RFC 1071 with some minor changes to fix compilation on GCC,
- * this can probably be improved
- * 					--pablo 11/feb/07
- */
-
-#include <conntrackd.h>
-
-unsigned short do_csum(const void *addr, unsigned int count)
-{
-	unsigned int sum = 0;
-
-	/* checksumming disabled, just skip */
-	if (CONFIG(flags) & DONT_CHECKSUM)
-		return 0;
-
-	while(count > 1)  {
-		/*  This is the inner loop */
-		sum += *((unsigned short *) addr++);
-		count -= 2;
-	}
-
-	/*  Add left-over byte, if any */
-	if(count > 0)
-		sum += *((unsigned char *) addr);
-
-	/*  Fold 32-bit sum to 16 bits */
-	while (sum>>16)
-		sum = (sum & 0xffff) + (sum >> 16);
-
-	return ~sum;
-}
diff --git a/daemon/src/hash.c b/daemon/src/hash.c
deleted file mode 100644
index 274a140..0000000
--- a/daemon/src/hash.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * (C) 2006-2007 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Description: generic hash table implementation
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <string.h>
-#include "slist.h"
-#include "hash.h"
-
-
-struct hashtable_node *hashtable_alloc_node(int datasize, void *data)
-{
-	struct hashtable_node *n;
-	int size = sizeof(struct hashtable_node) + datasize;
-
-	n = malloc(size);
-	if (!n)
-		return NULL;
-	memset(n, 0, size);
-	memcpy(n->data, data, datasize);
-
-	return n;
-}
-
-void hashtable_destroy_node(struct hashtable_node *h)
-{
-	free(h);
-}
-
-struct hashtable *
-hashtable_create(int hashsize, int limit, int datasize,
-		 u_int32_t (*hash)(const void *data, struct hashtable *table),
-		 int (*compare)(const void *data1, const void *data2))
-{
-	int i;
-	struct hashtable *h;
-	struct hashtype *t;
-	int size = sizeof(struct hashtable)
-		   + hashsize * sizeof(struct slist_head);
-
-	h = (struct hashtable *) malloc(size);
-	if (!h) {
-		errno = ENOMEM;
-		return NULL;
-	}
-
-	memset(h, 0, size);
-	for (i=0; i<hashsize; i++)
-		INIT_SLIST_HEAD(h->members[i]);
-
-	h->hashsize = hashsize;
-	h->limit = limit;
-	h->datasize = datasize;
-	h->hash = hash;
-	h->compare = compare;
-
-	return h;
-}
-
-void hashtable_destroy(struct hashtable *h)
-{
-	hashtable_flush(h);
-	free(h);
-}
-
-void *hashtable_add(struct hashtable *table, void *data)
-{
-	struct slist_head *e;
-	struct hashtable_node *n;
-	u_int32_t id;
-	int i;
-
-	/* hash table is full */
-	if (table->count >= table->limit) {
-		errno = ENOSPC;
-		return NULL;
-	}
-
-	id = table->hash(data, table);
-
-	slist_for_each(e, &table->members[id]) {
-		n = slist_entry(e, struct hashtable_node, head);
-		if (table->compare(n->data, data)) {
-			errno = EEXIST;
-			return NULL;
-		}
-	}
-
-	n = hashtable_alloc_node(table->datasize, data);
-	if (n == NULL) {
-		errno = ENOMEM;
-		return NULL;
-	}
-
-	slist_add(&table->members[id], &n->head);
-	table->count++;
-
-	return n->data;
-}
-
-void *hashtable_test(struct hashtable *table, const void *data)
-{
-	struct slist_head *e;
-	u_int32_t id;
-	struct hashtable_node *n;
-	int i;
-
-	id = table->hash(data, table);
-
-	slist_for_each(e, &table->members[id]) {
-		n = slist_entry(e, struct hashtable_node, head);
-		if (table->compare(n->data, data))
-			return n->data;
-	}
-
-	errno = ENOENT;
-	return NULL;
-}
-
-int hashtable_del(struct hashtable *table, void *data)
-{
-	struct slist_head *e, *next, *prev;
-	u_int32_t id;
-	struct hashtable_node *n;
-	int i;
-
-	id = table->hash(data, table);
-
-	slist_for_each_safe(e, prev, next, &table->members[id]) {
-		n = slist_entry(e, struct hashtable_node, head);
-		if (table->compare(n->data, data)) {
-			slist_del(e, prev);
-			hashtable_destroy_node(n);
-			table->count--;
-			return 0;
-		}
-	}
-	errno = ENOENT;
-	return -1;
-}
-
-int hashtable_flush(struct hashtable *table)
-{
-	int i;
-	struct slist_head *e, *next, *prev;
-	struct hashtable_node *n;
-
-	for (i=0; i < table->hashsize; i++)
-		slist_for_each_safe(e, prev, next, &table->members[i]) {
-			n = slist_entry(e, struct hashtable_node, head);
-			slist_del(e, prev);
-			hashtable_destroy_node(n);
-		}
-
-	table->count = 0;
-	
-	return 0;
-}
-
-int hashtable_iterate(struct hashtable *table, void *data,
-		      int (*iterate)(void *data1, void *data2))
-{
-	int i;
-	struct slist_head *e, *next, *prev;
-	struct hashtable_node *n;
-
-	for (i=0; i < table->hashsize; i++) {
-		slist_for_each_safe(e, prev, next, &table->members[i]) {
-			n = slist_entry(e, struct hashtable_node, head);
-			if (iterate(data, n->data) == -1)
-				return -1;
-		}
-	}
-	return 0;
-}
-
-unsigned int hashtable_counter(struct hashtable *table)
-{
-	return table->count;
-}
diff --git a/daemon/src/ignore_pool.c b/daemon/src/ignore_pool.c
deleted file mode 100644
index 5946617..0000000
--- a/daemon/src/ignore_pool.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * (C) 2006-2007 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "jhash.h"
-#include "hash.h"
-#include "conntrackd.h"
-#include "ignore.h"
-#include "debug.h"
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-
-#define IGNORE_POOL_SIZE 32
-#define IGNORE_POOL_LIMIT 1024
-
-static u_int32_t hash(const void *data, struct hashtable *table)
-{
-	const u_int32_t *ip = data;
-
-	return jhash_1word(*ip, 0) % table->hashsize;
-}
-
-static u_int32_t hash6(const void *data, struct hashtable *table)
-{
-	return jhash(data, sizeof(u_int32_t)*4, 0) % table->hashsize;
-}
-
-static int compare(const void *data1, const void *data2)
-{
-	const u_int32_t *ip1 = data1;
-	const u_int32_t *ip2 = data2;
-
-	return *ip1 == *ip2;
-}
-
-static int compare6(const void *data1, const void *data2)
-{
-	return memcmp(data1, data2, sizeof(u_int32_t)*4) == 0;
-}
-
-struct ignore_pool *ignore_pool_create(u_int8_t proto)
-{
-	int i, j = 0;
-	struct ignore_pool *ip;
-
-	ip = malloc(sizeof(struct ignore_pool));
-	if (!ip)
-		return NULL;
-	memset(ip, 0, sizeof(struct ignore_pool));
-
-	switch(proto) {
-	case AF_INET:
-		ip->h = hashtable_create(IGNORE_POOL_SIZE,
-					 IGNORE_POOL_LIMIT,
-					 sizeof(u_int32_t),
-					 hash,
-					 compare);
-		break;
-	case AF_INET6:
-		ip->h = hashtable_create(IGNORE_POOL_SIZE,
-					 IGNORE_POOL_LIMIT,
-					 sizeof(u_int32_t)*4,
-					 hash6,
-					 compare6);
-		break;
-	}
-
-	if (!ip->h) {
-		free(ip);
-		return NULL;
-	}
-
-	return ip;
-}
-
-void ignore_pool_destroy(struct ignore_pool *ip)
-{
-	hashtable_destroy(ip->h);
-	free(ip);
-}
-
-int ignore_pool_add(struct ignore_pool *ip, void *data)
-{
-	if (!hashtable_add(ip->h, data))
-		return 0;
-
-	return 1;
-}
-
-int __ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct)
-{
-	return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) ||
-		hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST)) ||
-		hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC)) ||
-		hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_DST)));
-}
-
-int __ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct)
-{
-	return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) ||
-	        hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) ||
-	        hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)) ||
-	        hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_DST)));
-}
-
-int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct)
-{
-	int ret;
-
-	switch(nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO)) {
-	case AF_INET:
-		ret = __ignore_pool_test_ipv4(ip, ct);
-		break;
-	case AF_INET6:
-		ret = __ignore_pool_test_ipv6(ip, ct);
-		break;
-	default:
-		dlog(STATE(log), "unknown conntrack layer 3 protocol?");
-		break;
-	}
-
-	return ret;
-}
diff --git a/daemon/src/local.c b/daemon/src/local.c
deleted file mode 100644
index eef70ad..0000000
--- a/daemon/src/local.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Description: UNIX sockets library
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include "debug.h"
-
-#include "local.h"
-
-int local_server_create(struct local_conf *conf)
-{
-	int fd;
-	int len;
-	struct sockaddr_un local;
-
-	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
-		debug("local_server_create:socket");
-		return -1;
-	}
-
-	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &conf->reuseaddr, 
-				sizeof(conf->reuseaddr)) == -1) {
-		debug("local_server_create:setsockopt");
-		close(fd);
-		return -1;
-	}
-
-	local.sun_family = AF_UNIX;
-	strcpy(local.sun_path, conf->path);
-	len = strlen(local.sun_path) + sizeof(local.sun_family);
-	unlink(conf->path);
-
-	if (bind(fd, (struct sockaddr *) &local, len) == -1) {
-		debug("local_server_create:bind");
-		close(fd);
-		return -1;
-	}
-
-	if (listen(fd, conf->backlog) == -1) {
-		close(fd);
-		debug("local_server_create:listen");
-		return -1;
-	}
-
-	return fd;
-}
-
-void local_server_destroy(int fd)
-{
-	close(fd);
-}
-
-int do_local_server_step(int fd, void *data, 
-			 void (*process)(int fd, void *data))
-{
-	int rfd;
-	struct sockaddr_un local;
-	size_t sin_size = sizeof(struct sockaddr_un);
-	
-	if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) {
-		debug("do_local_server_step:accept");
-		return -1;
-	}
-
-	process(rfd, data);
-	close(rfd);
-
-	return 0;
-}
-
-int local_client_create(struct local_conf *conf)
-{
-	int len;
-	struct sockaddr_un local;
-	int fd;
-
-	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
-		return -1;
-
-	local.sun_family = AF_UNIX;
-	strcpy(local.sun_path, conf->path);
-	len = strlen(local.sun_path) + sizeof(local.sun_family);
-
-	if (connect(fd, (struct sockaddr *) &local, len) == -1) {
-		close(fd);
-		debug("local_client_create: connect: ");
-		return -1;
-	}
-
-	return fd;
-}
-
-void local_client_destroy(int fd)
-{
-	close(fd);
-}
-
-int do_local_client_step(int fd, void (*process)(char *buf))
-{
-	int numbytes;
-	char buf[1024];
-
-	memset(buf, 0, sizeof(buf));
-	while ((numbytes = recv(fd, buf, sizeof(buf)-1, 0)) > 0) {
-		buf[sizeof(buf)-1] = '\0';
-		if (process)
-			process(buf);
-		memset(buf, 0, sizeof(buf));
-	}
-
-	return 0;
-}
-
-void local_step(char *buf)
-{
-	printf(buf);
-}
-
-int do_local_request(int request,
-		     struct local_conf *conf,
-		     void (*step)(char *buf))
-{
-	int fd, ret;
-
-	fd = local_client_create(conf);
-	if (fd == -1)
-		return -1;
-
-	ret = send(fd, &request, sizeof(int), 0);
-	if (ret == -1) {
-		debug("send:");
-		return -1;
-	}
-
-	do_local_client_step(fd, step);
-
-	local_client_destroy(fd);
-	
-	return 0;
-}
diff --git a/daemon/src/lock.c b/daemon/src/lock.c
deleted file mode 100644
index cd68baf..0000000
--- a/daemon/src/lock.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <stdio.h>
-#include <pthread.h>
-
-static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;
-
-void lock()
-{
-	pthread_mutex_lock(&global_lock);
-}
-
-void unlock()
-{
-	pthread_mutex_unlock(&global_lock);
-}
diff --git a/daemon/src/log.c b/daemon/src/log.c
deleted file mode 100644
index 88cadea..0000000
--- a/daemon/src/log.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Description: Logging support for the conntrack daemon
- */
-
-#include <stdio.h>
-#include <time.h>
-#include <stdarg.h>
-#include <string.h>
-
-FILE *init_log(char *filename)
-{
-	FILE *fd;
-
-	fd = fopen(filename, "a+");
-	if (fd == NULL) {
-		fprintf(stderr, "can't open log file `%s'\n", filename);
-		return NULL;
-	}
-
-	return fd;
-}
-
-void dlog(FILE *fd, char *format, ...)
-{
-	time_t t = time(NULL);
-	char *buf = ctime(&t);
-	va_list args;
-
-	buf[strlen(buf)-1]='\0';
-	va_start(args, format);
-	fprintf(fd, "[%s] (pid=%d) ", buf, getpid());
-	vfprintf(fd, format, args);
-	va_end(args);
-	fprintf(fd, "\n");
-	fflush(fd);
-}
-
-void close_log(FILE *fd)
-{
-	fclose(fd);
-}
diff --git a/daemon/src/main.c b/daemon/src/main.c
deleted file mode 100644
index 1c75970..0000000
--- a/daemon/src/main.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * (C) 2006-2007 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <stdlib.h>
-#include "conntrackd.h"
-#include "log.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/utsname.h>
-#include <linux/capability.h>
-#include <errno.h>
-#include "hash.h"
-#include "jhash.h"
-
-struct ct_general_state st;
-union ct_state state;
-
-static const char usage_daemon_commands[] =
-	"Daemon mode commands:\n"
-	"  -d [options]\t\tRun in daemon mode\n"
-	"  -S [options]\t\tRun in statistics mode\n";
-
-static const char usage_client_commands[] = 
-	"Client mode commands:\n"
-	"  -c, commit external cache to conntrack table\n"
-	"  -f, flush internal and external cache\n"
-	"  -F, flush kernel conntrack table\n"
-	"  -i, display content of the internal cache\n"
-	"  -e, display the content of the external cache\n"
-	"  -k, kill conntrack daemon\n"
-	"  -s, dump statistics\n"
-	"  -R, resync with kernel conntrack table\n"
-	"  -n, request resync with other node (only NACK mode)\n"
-	"  -x, dump cache in XML format (requires -i or -e)";
-
-static const char usage_options[] =
-	"Options:\n"
-	"  -C [configfile], configuration file path\n";
-
-void show_usage(char *progname)
-{
-	fprintf(stdout, "Connection tracking userspace daemon v%s\n", VERSION);
-	fprintf(stdout, "Usage: %s [commands] [options]\n\n", progname);
-	fprintf(stdout, "%s\n", usage_daemon_commands);
-	fprintf(stdout, "%s\n", usage_client_commands);
-	fprintf(stdout, "%s\n", usage_options);
-}
-
-/* These live in run.c */
-int init(int);
-void run(void);
-
-void set_operation_mode(int *current, int want, char *argv[])
-{
-	if (*current == NOT_SET) {
-		*current = want;
-		return;
-	}
-	if (*current != want) {
-		show_usage(argv[0]);
-		fprintf(stderr, "\nError: Invalid parameters\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static int check_capabilities(void)
-{
-	int ret;
-	cap_user_header_t hcap;
-	cap_user_data_t dcap;
-
-	hcap = malloc(sizeof(cap_user_header_t));
-	if (!hcap)
-		return -1;
-
-	hcap->version = _LINUX_CAPABILITY_VERSION;
-	hcap->pid = getpid();
-
-	dcap = malloc(sizeof(cap_user_data_t));
-	if (!dcap) {
-		free(hcap);
-		return -1;
-	}
-
-	if (capget(hcap, dcap) == -1) {
-		free(hcap);
-		free(dcap);
-		return -1;
-	}
-
-	ret = dcap->permitted & (1 << CAP_NET_ADMIN);
-
-	free(hcap);
-	free(dcap);
-
-	return ret;
-}
-
-int main(int argc, char *argv[])
-{
-	int ret, i, config_set = 0, action;
-	char config_file[PATH_MAX];
-	int type = 0, mode = 0;
-	struct utsname u;
-	int version, major, minor;
-
-	/* Check kernel version: it must be >= 2.6.18 */
-	if (uname(&u) == -1) {
-		fprintf(stderr, "Can't retrieve kernel version via uname()\n");
-		exit(EXIT_FAILURE);
-	}
-	sscanf(u.release, "%d.%d.%d", &version, &major, &minor);
-	if (version < 2 && major < 6) {
-		fprintf(stderr, "Linux kernel version must be >= 2.6.18\n");
-		exit(EXIT_FAILURE);
-	}
-
-	if (major == 6 && minor < 18) {
-		fprintf(stderr, "Linux kernel version must be >= 2.6.18\n");
-		exit(EXIT_FAILURE);
-	}
-
-	ret = check_capabilities();
-	switch (ret) {
-		case -1:
-			fprintf(stderr, "Can't get capabilities\n");
-			exit(EXIT_FAILURE);
-			break;
-		case 0:
-			fprintf(stderr, "You require CAP_NET_ADMIN in order "
-					"to run conntrackd\n");
-			exit(EXIT_FAILURE);
-			break;
-		default:
-			break;
-	}
-
-	for (i=1; i<argc; i++) {
-		switch(argv[i][1]) {
-		case 'd':
-			set_operation_mode(&type, DAEMON, argv);
-			break;
-		case 'c':
-			set_operation_mode(&type, REQUEST, argv);
-			action = COMMIT;
-			break;
-		case 'i':
-			set_operation_mode(&type, REQUEST, argv);
-			action = DUMP_INTERNAL;
-			break;
-		case 'e':
-			set_operation_mode(&type, REQUEST, argv);
-			action = DUMP_EXTERNAL;
-			break;
-		case 'C':
-			if (++i < argc) {
-				strncpy(config_file, argv[i], PATH_MAX);
-				if (strlen(argv[i]) >= PATH_MAX){
-					config_file[PATH_MAX-1]='\0';
-					fprintf(stderr, "Path to config file "
-						        "to long. Cutting it "
-							"down to %d characters",
-							PATH_MAX);
-				}
-				config_set = 1;
-				break;
-			}
-			show_usage(argv[0]);
-			fprintf(stderr, "Missing config filename\n");
-			break;
-		case 'F':
-			set_operation_mode(&type, REQUEST, argv);
-			action = FLUSH_MASTER;
-		case 'f':
-			set_operation_mode(&type, REQUEST, argv);
-			action = FLUSH_CACHE;
-			break;
-		case 'R':
-			set_operation_mode(&type, REQUEST, argv);
-			action = RESYNC_MASTER;
-			break;
-		case 'B':
-			set_operation_mode(&type, REQUEST, argv);
-			action = SEND_BULK;
-			break;
-		case 'k':
-			set_operation_mode(&type, REQUEST, argv);
-			action = KILL;
-			break;
-		case 's':
-			set_operation_mode(&type, REQUEST, argv);
-			action = STATS;
-			break;
-		case 'S':
-			set_operation_mode(&mode, STATS_MODE, argv);
-			break;
-		case 'n':
-			set_operation_mode(&type, REQUEST, argv);
-			action = REQUEST_DUMP;
-			break;
-		case 'x':
-			if (action == DUMP_INTERNAL)
-				action = DUMP_INT_XML;
-			else if (action == DUMP_EXTERNAL)
-				action = DUMP_EXT_XML;
-			else {
-				show_usage(argv[0]);
-				fprintf(stderr, "Error: Invalid parameters\n");
-				exit(EXIT_FAILURE);
-
-			}
-			break;
-		default:
-			show_usage(argv[0]);
-			fprintf(stderr, "Unknown option: %s\n", argv[i]);
-			return 0;
-			break;
-		}
-	}
-
-	if (config_set == 0)
-		strcpy(config_file, DEFAULT_CONFIGFILE);
-
-	if ((ret = init_config(config_file)) == -1) {
-		fprintf(stderr, "can't open config file `%s'\n", config_file);
-		exit(EXIT_FAILURE);
-	}
-
-	/*
-	 * Setting up logfile
-	 */
-	STATE(log) = init_log(CONFIG(logfile));
-	if (!STATE(log)) {
-		fprintf(stdout, "can't open logfile `%s\n'", CONFIG(logfile));
-		exit(EXIT_FAILURE);
-	}
-
-	if (type == REQUEST) {
-		if (do_local_request(action, &conf.local, local_step) == -1)
-			fprintf(stderr, "can't connect: is conntrackd "
-					"running? appropiate permissions?\n");
-		exit(EXIT_SUCCESS);
-	}
-
-	/*
-	 * lock file
-	 */
-	if ((ret = open(CONFIG(lockfile), O_CREAT | O_EXCL | O_TRUNC)) == -1) {
-		fprintf(stderr, "lockfile `%s' exists, perhaps conntrackd "
-			        "already running?\n", CONFIG(lockfile));
-		exit(EXIT_FAILURE);
-	}
-	close(ret);
-
-	/* Daemonize conntrackd */
-	if (type == DAEMON) {
-		pid_t pid;
-
-		if ((pid = fork()) == -1) {
-			dlog(STATE(log), "fork() failed: "
-					 "%s", strerror(errno));
-			exit(EXIT_FAILURE);
-		} else if (pid)
-			exit(EXIT_SUCCESS);
-		
-		dlog(STATE(log), "--- starting in daemon mode ---");
-	} else
-		dlog(STATE(log), "--- starting in console mode ---");
-
-	/*
-	 * initialization process
-	 */
-
-	if (init(mode) == -1) {
-		close_log(STATE(log));
-		fprintf(stderr, "ERROR: conntrackd cannot start, please "
-				"check the logfile for more info\n");
-		unlink(CONFIG(lockfile));
-		exit(EXIT_FAILURE);
-	}
-
-	/*
-	 * run main process
-	 */
-	run();
-}
diff --git a/daemon/src/mcast.c b/daemon/src/mcast.c
deleted file mode 100644
index 9904544..0000000
--- a/daemon/src/mcast.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Description: multicast socket library
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <string.h>
-#include "mcast.h"
-#include "debug.h"
-
-struct mcast_sock *mcast_server_create(struct mcast_conf *conf)
-{
-	int yes = 1;
-	union {
-		struct ip_mreq ipv4;
-		struct ipv6_mreq ipv6;
-	} mreq;
-	struct mcast_sock *m;
-
-	m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock));
-	if (!m)
-		return NULL;
-	memset(m, 0, sizeof(struct mcast_sock));
-
-	switch(conf->ipproto) {
-	case AF_INET:
-		mreq.ipv4.imr_multiaddr.s_addr = conf->in.inet_addr.s_addr;
-		mreq.ipv4.imr_interface.s_addr =conf->ifa.interface_addr.s_addr;
-
-	        m->addr.ipv4.sin_family = AF_INET;
-	        m->addr.ipv4.sin_port = htons(conf->port);
-	        m->addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
-		break;
-
-	case AF_INET6:
-		memcpy(&mreq.ipv6.ipv6mr_multiaddr, &conf->in.inet_addr6,
-		       sizeof(u_int32_t) * 4);
-		memcpy(&mreq.ipv6.ipv6mr_interface, &conf->ifa.interface_addr6,
-		       sizeof(u_int32_t) * 4);
-
-		m->addr.ipv6.sin6_family = AF_INET6;
-		m->addr.ipv6.sin6_port = htons(conf->port);
-		m->addr.ipv6.sin6_addr = in6addr_any;
-		break;
-	}
-
-	if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) {
-		debug("mcast_sock_server_create:socket");
-		free(m);
-		return NULL;
-	}
-
-	if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, 
-				sizeof(int)) == -1) {
-		debug("mcast_sock_server_create:setsockopt1");
-		close(m->fd);
-		free(m);
-		return NULL;
-	}
-
-	if (bind(m->fd, (struct sockaddr *) &m->addr, 
-			 sizeof(struct sockaddr)) == -1) {
-		debug("mcast_sock_server_create:bind");
-		close(m->fd);
-		free(m);
-		return NULL;
-	}
-
-
-	switch(conf->ipproto) {
-	case AF_INET:
-		if (setsockopt(m->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
-			       &mreq.ipv4, sizeof(mreq.ipv4)) < 0) {
-			debug("mcast_sock_server_create:setsockopt2");
-			close(m->fd);
-			free(m);
-			return NULL;
-		}
-		break;
-	case AF_INET6:
-		if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
-			       &mreq.ipv6, sizeof(mreq.ipv6)) < 0) {
-			debug("mcast_sock_server_create:setsockopt2");
-			close(m->fd);
-			free(m);
-			return NULL;
-		}
-		break;
-	}
-
-	return m;
-}
-
-void mcast_server_destroy(struct mcast_sock *m)
-{
-	close(m->fd);
-	free(m);
-}
-
-static int 
-__mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf)
-{
-	int no = 0;
-
-	m->addr.ipv4.sin_family = AF_INET;
-	m->addr.ipv4.sin_port = htons(conf->port);
-	m->addr.ipv4.sin_addr = conf->in.inet_addr;
-
-	if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &no,
-		       sizeof(int)) < 0) {
-		debug("mcast_sock_client_create:setsockopt2");
-		close(m->fd);
-		return -1;
-	}
-
-	if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_IF,
-		       &conf->ifa.interface_addr,
-		       sizeof(struct in_addr)) == -1) {
-		debug("mcast_sock_client_create:setsockopt3");
-		close(m->fd);
-		free(m);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int 
-__mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf)
-{
-	int no = 0;
-
-	m->addr.ipv6.sin6_family = AF_INET6;
-	m->addr.ipv6.sin6_port = htons(conf->port);
-	memcpy(&m->addr.ipv6.sin6_addr,
-	       &conf->in.inet_addr6,
-	       sizeof(struct in6_addr));
-
-	if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &no,
-		       sizeof(int)) < 0) {
-		debug("mcast_sock_client_create:setsockopt2");
-		close(m->fd);
-		return -1;
-	}
-
-	if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
-		       &conf->ifa.interface_addr,
-		       sizeof(struct in_addr)) == -1) {
-		debug("mcast_sock_client_create:setsockopt3");
-		close(m->fd);
-		free(m);
-		return -1;
-	}
-
-	return 0;
-}
-
-struct mcast_sock *mcast_client_create(struct mcast_conf *conf)
-{
-	int ret = 0;
-	struct sockaddr_in addr;
-	struct mcast_sock *m;
-
-	m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock));
-	if (!m)
-		return NULL;
-	memset(m, 0, sizeof(struct mcast_sock));
-
-	if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) {
-		debug("mcast_sock_client_create:socket");
-		return NULL;
-	}
-
-	switch(conf->ipproto) {
-		case AF_INET:
-			ret = __mcast_client_create_ipv4(m, conf);
-			break;
-		case AF_INET6:
-			ret = __mcast_client_create_ipv6(m, conf);
-			break;
-		default:
-			break;
-	}
-
-	if (ret == -1) {
-		free(m);
-		m = NULL;
-	}
-
-	return m;
-}
-
-void mcast_client_destroy(struct mcast_sock *m)
-{
-	close(m->fd);
-	free(m);
-}
-
-int mcast_send(struct mcast_sock *m, void *data, int size)
-{
-	int ret;
-	
-	ret = sendto(m->fd, 
-		     data,
-		     size,
-		     0,
-		     (struct sockaddr *) &m->addr,
-		     sizeof(struct sockaddr));
-	if (ret == -1) {
-		debug("mcast_sock_send");
-		m->stats.error++;
-		return ret;
-	}
-
-	m->stats.bytes += ret;
-	m->stats.messages++;  
-
-	return ret;
-}
-
-int mcast_recv(struct mcast_sock *m, void *data, int size)
-{
-	int ret;
-	socklen_t sin_size = sizeof(struct sockaddr_in);
-
-        ret = recvfrom(m->fd,
-		       data, 
-		       size,
-		       0,
-		       (struct sockaddr *)&m->addr,
-		       &sin_size);
-	if (ret == -1) {
-		debug("mcast_sock_recv");
-		m->stats.error++;
-		return ret;
-	}
-
-	m->stats.bytes += ret;
-	m->stats.messages++;
-
-	return ret;
-}
-
-struct mcast_stats *mcast_get_stats(struct mcast_sock *m)
-{
-	return &m->stats;
-}
-
-void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r)
-{
-	char buf[512];
-	int size;
-
-	size = sprintf(buf, "multicast traffic:\n"
-			    "%20llu Bytes sent "
-			    "%20llu Bytes recv\n"
-			    "%20llu Pckts sent "
-			    "%20llu Pckts recv\n"
-			    "%20llu Error send "
-			    "%20llu Error recv\n\n",
-			    s->stats.bytes, r->stats.bytes,
-			    s->stats.messages, r->stats.messages,
-			    s->stats.error, r->stats.error);
-
-	send(fd, buf, size, 0);
-}
diff --git a/daemon/src/netlink.c b/daemon/src/netlink.c
deleted file mode 100644
index 0bde632..0000000
--- a/daemon/src/netlink.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "conntrackd.h"
-#include <libnfnetlink/libnfnetlink.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <errno.h>
-#include "us-conntrack.h"
-#include <signal.h>
-#include <stdlib.h>
-#include "network.h"
-
-static int ignore_conntrack(struct nf_conntrack *ct)
-{
-	/* ignore a certain protocol */
-	if (CONFIG(ignore_protocol)[nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)])
-		return 1;
-
-	/* Accept DNAT'ed traffic: not really coming to the local machine */
-	if ((CONFIG(flags) & STRIP_NAT) && 
-	    nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) {
-		debug_ct(ct, "DNAT");
-		return 0;
-	}
-
-        /* Accept SNAT'ed traffic: not really coming to the local machine */
-	if ((CONFIG(flags) & STRIP_NAT) && 
-	    nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) {
-		debug_ct(ct, "SNAT");
-		return 0;
-	}
-
-	/* Ignore traffic */
-	if (ignore_pool_test(STATE(ignore_pool), ct)) {
-		debug_ct(ct, "ignore traffic");
-		return 1;
-	}
-
-	return 0;
-}
-
-static int nl_event_handler(struct nlmsghdr *nlh,
-			    struct nfattr *nfa[],
-			    void *data)
-{
-	char tmp[1024];
-	struct nf_conntrack *ct = (struct nf_conntrack *) tmp;
-	int type;
-
-	memset(tmp, 0, sizeof(tmp));
-
-	if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR)
-		return NFCT_CB_STOP;
-
-	/* 
-	 * Ignore this conntrack: it talks about a
-	 * connection that is not interesting for us.
-	 */
-	if (ignore_conntrack(ct))
-		return NFCT_CB_STOP;
-
-	switch(type) {
-	case NFCT_T_NEW:
-		STATE(mode)->event_new(ct, nlh);
-		break;
-	case NFCT_T_UPDATE:
-		STATE(mode)->event_upd(ct, nlh);
-		break;
-	case NFCT_T_DESTROY:
-		if (STATE(mode)->event_dst(ct, nlh))
-			update_traffic_stats(ct);
-		break;
-	default:
-		dlog(STATE(log), "received unknown msg from ctnetlink\n");
-		break;
-	}
-
-	return NFCT_CB_STOP;
-}
-
-int nl_init_event_handler(void)
-{
-	struct nfnl_callback cb_events = {
-		.call		= nl_event_handler,
-		.attr_count	= CTA_MAX
-	};
-
-	/* open event netlink socket */
-	STATE(event) = nfnl_open();
-	if (!STATE(event))
-		return -1;
-
-	/* set up socket buffer size */
-	if (CONFIG(netlink_buffer_size))
-		nfnl_rcvbufsiz(STATE(event), CONFIG(netlink_buffer_size));
-	else {
-		socklen_t socklen = sizeof(unsigned int);
-		unsigned int read_size;
-
-		/* get current buffer size */
-		getsockopt(nfnl_fd(STATE(event)), SOL_SOCKET,
-			   SO_RCVBUF, &read_size, &socklen);
-
-		CONFIG(netlink_buffer_size) = read_size;
-	}
-
-	/* ensure that maximum grown size is >= than maximum size */
-	if (CONFIG(netlink_buffer_size_max_grown) < CONFIG(netlink_buffer_size))
-		CONFIG(netlink_buffer_size_max_grown) = 
-					CONFIG(netlink_buffer_size);
-
-	/* open event subsystem */
-	STATE(subsys_event) = nfnl_subsys_open(STATE(event),
-					       NFNL_SUBSYS_CTNETLINK,
-					       IPCTNL_MSG_MAX,
-					       NFCT_ALL_CT_GROUPS);
-	if (STATE(subsys_event) == NULL)
-		return -1;
-
-	/* register callback for new and update events */
-	nfnl_callback_register(STATE(subsys_event),
-			       IPCTNL_MSG_CT_NEW,
-			       &cb_events);
-
-	/* register callback for delete events */
-	nfnl_callback_register(STATE(subsys_event),
-			       IPCTNL_MSG_CT_DELETE,
-			       &cb_events);
-
-	return 0;
-}
-
-static int nl_dump_handler(struct nlmsghdr *nlh,
-			   struct nfattr *nfa[],
-			   void *data)
-{
-	char buf[1024];
-	struct nf_conntrack *ct = (struct nf_conntrack *) buf;
-	int type;
-
-	memset(buf, 0, sizeof(buf));
-
-	if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR)
-		return NFCT_CB_CONTINUE;
-
-	/* 
-	 * Ignore this conntrack: it talks about a
-	 * connection that is not interesting for us.
-	 */
-	if (ignore_conntrack(ct))
-		return NFCT_CB_CONTINUE;
-
-	switch(type) {
-	case NFCT_T_UPDATE:
-		STATE(mode)->dump(ct, nlh);
-		break;
-	default:
-		dlog(STATE(log), "received unknown msg from ctnetlink");
-		break;
-	}
-	return NFCT_CB_CONTINUE;
-}
-
-int nl_init_dump_handler(void)
-{
-	struct nfnl_callback cb_dump = {
-		.call		= nl_dump_handler,
-		.attr_count	= CTA_MAX
-	};
-
-	/* open dump netlink socket */
-	STATE(dump) = nfnl_open();
-	if (!STATE(dump))
-		return -1;
-
-	/* open dump subsystem */
-	STATE(subsys_dump) = nfnl_subsys_open(STATE(dump),
-					      NFNL_SUBSYS_CTNETLINK,
-					      IPCTNL_MSG_MAX,
-					      0);
-	if (STATE(subsys_dump) == NULL)
-		return -1;
-
-	/* register callback for dumped entries */
-	nfnl_callback_register(STATE(subsys_dump),
-			       IPCTNL_MSG_CT_NEW,
-			       &cb_dump);
-
-	if (nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)) == -1)
-		return -1;
-
-	return 0;
-}
-
-static int nl_overrun_handler(struct nlmsghdr *nlh,
-			      struct nfattr *nfa[],
-			      void *data)
-{
-	char buf[1024];
-	struct nf_conntrack *ct = (struct nf_conntrack *) buf;
-	int type;
-
-	memset(buf, 0, sizeof(buf));
-
-	if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR)
-		return NFCT_CB_CONTINUE;
-
-	/* 
-	 * Ignore this conntrack: it talks about a
-	 * connection that is not interesting for us.
-	 */
-	if (ignore_conntrack(ct))
-		return NFCT_CB_CONTINUE;
-
-	switch(type) {
-	case NFCT_T_UPDATE:
-		if (STATE(mode)->overrun)
-			STATE(mode)->overrun(ct, nlh);
-		break;
-	default:
-		dlog(STATE(log), "received unknown msg from ctnetlink");
-		break;
-	}
-	return NFCT_CB_CONTINUE;
-}
-
-int nl_init_overrun_handler(void)
-{
-	struct nfnl_callback cb_sync = {
-		.call		= nl_overrun_handler,
-		.attr_count	= CTA_MAX
-	};
-
-	/* open sync netlink socket */
-	STATE(sync) = nfnl_open();
-	if (!STATE(sync))
-		return -1;
-
-	/* open synchronizer subsystem */
-	STATE(subsys_sync) = nfnl_subsys_open(STATE(sync),
-					      NFNL_SUBSYS_CTNETLINK,
-					      IPCTNL_MSG_MAX,
-					      0);
-	if (STATE(subsys_sync) == NULL)
-		return -1;
-
-	/* register callback for dumped entries */
-	nfnl_callback_register(STATE(subsys_sync),
-			       IPCTNL_MSG_CT_NEW,
-			       &cb_sync);
-
-	return 0;
-}
-
-static int warned = 0;
-
-void nl_resize_socket_buffer(struct nfnl_handle *h)
-{
-	unsigned int s = CONFIG(netlink_buffer_size) * 2;
-
-	/* already warned that we have reached the maximum buffer size */
-	if (warned)
-		return;
-
-	if (s > CONFIG(netlink_buffer_size_max_grown)) {
-		dlog(STATE(log), "maximum netlink socket buffer size reached");
-		s = CONFIG(netlink_buffer_size_max_grown);
-		warned = 1;
-	}
-
-	CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(h, s);
-
-	/* notify the sysadmin */
-	dlog(STATE(log), "netlink socket buffer size has been set to %u bytes", 
-			  CONFIG(netlink_buffer_size));
-}
-
-int nl_dump_conntrack_table(struct nfnl_handle *h, 
-			    struct nfnl_subsys_handle *subsys)
-{
-	struct nfnlhdr req;
-
-	memset(&req, 0, sizeof(req));
-	nfct_build_query(subsys, 
-			 NFCT_Q_DUMP, 
-			 &CONFIG(family), 
-			 &req, 
-			 sizeof(req));
-
-	if (nfnl_query(h, &req.nlh) == -1)
-		return -1;
-
-	return 0;
-}
-
-int nl_flush_master_conntrack_table(void)
-{
-	struct nfnlhdr req;
-
-	memset(&req, 0, sizeof(req));
-	nfct_build_query(STATE(subsys_sync), 
-			 NFCT_Q_FLUSH, 
-			 &CONFIG(family), 
-			 &req, 
-			 sizeof(req));
-
-	if (nfnl_query(STATE(sync), &req.nlh) == -1)
-		return -1;
-
-	return 0;
-}
diff --git a/daemon/src/network.c b/daemon/src/network.c
deleted file mode 100644
index b9be318..0000000
--- a/daemon/src/network.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * (C) 2006-2007 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "conntrackd.h"
-#include "network.h"
-
-#if 0 
-#define _TEST_DROP
-#else
-#undef _TEST_DROP
-#endif
-
-static int drop = 0; /* debugging purposes */
-static unsigned int seq_set, cur_seq;
-
-static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len)
-{
-	struct nlnetwork *net = data;
-
-#ifdef _TEST_DROP
-        if (++drop > 10) {
-		drop = 0;
-		printf("dropping resend (seq=%u)\n", ntohl(net->seq));
-		return 0;
-	}
-#endif
-	return mcast_send(m, net, len);
-}
-
-int mcast_send_netmsg(struct mcast_sock *m, void *data)
-{
-	struct nlmsghdr *nlh = data + sizeof(struct nlnetwork);
-	unsigned int len = nlh->nlmsg_len + sizeof(struct nlnetwork);
-	struct nlnetwork *net = data;
-
-	if (!seq_set) {
-		seq_set = 1;
-		cur_seq = time(NULL);
-		net->flags |= NET_HELLO;
-	}
-
-	net->flags = htons(net->flags);
-	net->seq = htonl(cur_seq++);
-
-	if (nlh_host2network(nlh) == -1)
-		return -1;
-
-	net->checksum = 0;
-	net->checksum = ntohs(do_csum(data, len));
-
-	return send_netmsg(m, data, len);
-}
-
-int mcast_resend_netmsg(struct mcast_sock *m, void *data)
-{
-	struct nlnetwork *net = data;
-	struct nlmsghdr *nlh = data + sizeof(struct nlnetwork);
-	unsigned int len = htonl(nlh->nlmsg_len) + sizeof(struct nlnetwork);
-
-	net->flags = ntohs(net->flags);
-
-	if (!seq_set) {
-		seq_set = 1;
-		cur_seq = time(NULL);
-		net->flags |= NET_HELLO;
-	}
-
-	if (net->flags & NET_NACK || net->flags & NET_ACK) {
-		struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net;
-		len = sizeof(struct nlnetwork_ack);
-	}
-
-	net->flags = htons(net->flags);
-	net->seq = htonl(cur_seq++);
-	net->checksum = 0;
-	net->checksum = ntohs(do_csum(data, len));
-
-	return send_netmsg(m, data, len);
-}
-
-int mcast_send_error(struct mcast_sock *m, void *data)
-{
-	struct nlnetwork *net = data;
-	unsigned int len = sizeof(struct nlnetwork);
-
-	if (!seq_set) {
-		seq_set = 1;
-		cur_seq = time(NULL);
-		net->flags |= NET_HELLO;
-	}
-
-	if (net->flags & NET_NACK || net->flags & NET_ACK) {
-		struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net;
-		nack->from = htonl(nack->from);
-		nack->to = htonl(nack->to);
-		len = sizeof(struct nlnetwork_ack);
-	}
-
-	net->flags = htons(net->flags);
-	net->seq = htonl(cur_seq++);
-	net->checksum = 0;
-	net->checksum = ntohs(do_csum(data, len));
-
-	return send_netmsg(m, data, len);
-}
-
-static int valid_checksum(void *data, unsigned int len)
-{
-	struct nlnetwork *net = data;
-	unsigned short checksum, tmp;
-
-	checksum = ntohs(net->checksum);
-
-	/* no checksum, skip */
-	if (!checksum)
-		return 1;
-
-	net->checksum = 0;
-	tmp = do_csum(data, len);
-
-	return tmp == checksum;
-}
-
-int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len)
-{
-	int ret;
-	struct nlnetwork *net = data;
-	struct nlmsghdr *nlh = data + sizeof(struct nlnetwork);
-	struct nfgenmsg *nfhdr;
-
-	ret = mcast_recv(m, net, len);
-	if (ret <= 0)
-		return ret;
-
-	if (ret < sizeof(struct nlnetwork))
-		return -1;
-
-	if (!valid_checksum(data, ret))
-		return -1;
-
-	net->flags = ntohs(net->flags);
-	net->seq = ntohl(net->seq);
-
-	if (net->flags & NET_HELLO)
-		STATE_SYNC(last_seq_recv) = net->seq-1;
-
-	if (net->flags & NET_NACK || net->flags & NET_ACK) {
-		struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net;
-
-		if (ret < sizeof(struct nlnetwork_ack))
-			return -1;
-
-		nack->from = ntohl(nack->from);
-		nack->to = ntohl(nack->to);
-
-		return ret;
-	}
-
-	if (net->flags & NET_RESYNC)
-		return ret;
-
-	/* information received is too small */
-	if (ret < NLMSG_SPACE(sizeof(struct nfgenmsg)))
-		return -1;
-
-	/* information received and message length does not match */
-	if (ret != ntohl(nlh->nlmsg_len) + sizeof(struct nlnetwork))
-		return -1;
-
-	/* this message does not come from ctnetlink */
-	if (NFNL_SUBSYS_ID(ntohs(nlh->nlmsg_type)) != NFNL_SUBSYS_CTNETLINK)
-		return -1;
-
-	nfhdr = NLMSG_DATA(nlh);
-
-	/* only AF_INET and AF_INET6 are supported */
-	if (nfhdr->nfgen_family != AF_INET &&
-	    nfhdr->nfgen_family != AF_INET6)
-		return -1;
-
-	/* only process message coming from nfnetlink v0 */
-	if (nfhdr->version != NFNETLINK_V0)
-		return -1;
-
-	if (nlh_network2host(nlh) == -1)
-		return -1;
-
-	return ret;
-}
-
-int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq)
-{
-	static int seq_set = 0;
-	int ret = 1;
-
-	/* netlink sequence tracking initialization */
-	if (!seq_set) {
-		seq_set = 1;
-		goto out;
-	}
-
-	/* fast path: we received the correct sequence */
-	if (seq == STATE_SYNC(last_seq_recv)+1)
-		goto out;
-
-	/* out of sequence: some messages got lost */
-	if (seq > STATE_SYNC(last_seq_recv)+1) {
-		STATE_SYNC(packets_lost) += seq-STATE_SYNC(last_seq_recv)+1;
-		ret = 0;
-		goto out;
-	}
-
-	/* out of sequence: replayed or sequence wrapped around issues */
-	if (seq < STATE_SYNC(last_seq_recv)+1) {
-		/* 
-		 * Check if the sequence has wrapped around.
-		 * Perhaps it can be a replayed packet.
-		 */
-		if (STATE_SYNC(last_seq_recv)+1-seq > ~0U/2) {
-			/* 
-			 * Indeed, it is a wrapped around
-			 */
-			STATE_SYNC(packets_lost) += 
-				~0U-STATE_SYNC(last_seq_recv)+1+seq;
-		} else {
-			/*
-			 * It is a delayed packet
-			 */
-			dlog(STATE(log), "delayed packet? exp=%u rcv=%u",
-					 STATE_SYNC(last_seq_recv)+1, seq);
-		}
-		ret = 0;
-	}
-
-out:
-	*exp_seq = STATE_SYNC(last_seq_recv)+1;
-	/* update expected sequence */
-	STATE_SYNC(last_seq_recv) = seq;
-
-	return ret;
-}
-
-int build_network_msg(const int msg_type,
-		      struct nfnl_subsys_handle *ssh, 
-		      struct nf_conntrack *ct,
-		      void *buffer,
-		      unsigned int size)
-{
-	memset(buffer, 0, size);
-	buffer += sizeof(struct nlnetwork);
-	return nfct_build_query(ssh, msg_type, ct, buffer, size);
-}
-
-unsigned int parse_network_msg(struct nf_conntrack *ct, 
-			       const struct nlmsghdr *nlh)
-{
-	/* 
-	 * The parsing of netlink messages going through network is 
-	 * similar to the one that is done for messages coming from
-	 * kernel, therefore do not replicate more code and use the
-	 * function provided in the libraries.
-	 *
-	 * Yup, this is a hack 8)
-	 */
-	return nfct_parse_conntrack(NFCT_T_ALL, nlh, ct);
-}
-
diff --git a/daemon/src/proxy.c b/daemon/src/proxy.c
deleted file mode 100644
index b9bb04e..0000000
--- a/daemon/src/proxy.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <libnfnetlink/libnfnetlink.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-
-#if 0
-#define dprintf printf
-#else
-#define dprintf
-#endif
-
-int nlh_payload_host2network(struct nfattr *nfa, int len)
-{
-	struct nfattr *__nfa;
-
-	while (NFA_OK(nfa, len)) {
-
-		dprintf("type=%d nfalen=%d len=%d [%s]\n", 
-			nfa->nfa_type & 0x7fff,
-			nfa->nfa_len, len,
-			nfa->nfa_type & NFNL_NFA_NEST ? "NEST":"");
-
-		if (nfa->nfa_type & NFNL_NFA_NEST) {
-			if (NFA_PAYLOAD(nfa) > len)
-				return -1;
-
-			if (nlh_payload_host2network(NFA_DATA(nfa), 
-						     NFA_PAYLOAD(nfa)) == -1)
-				return -1;
-		}
-
-		__nfa = NFA_NEXT(nfa, len);
-
-		nfa->nfa_type = htons(nfa->nfa_type);
-		nfa->nfa_len  = htons(nfa->nfa_len);
-
-		nfa = __nfa; 
-	}
-	return 0;
-}
-
-int nlh_host2network(struct nlmsghdr *nlh)
-{
-	struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
-	struct nfattr *cda[CTA_MAX];
-	unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
-	unsigned int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
-
-	nlh->nlmsg_len   = htonl(nlh->nlmsg_len);
-	nlh->nlmsg_type  = htons(nlh->nlmsg_type);
-	nlh->nlmsg_flags = htons(nlh->nlmsg_flags);
-	nlh->nlmsg_seq   = htonl(nlh->nlmsg_seq);
-	nlh->nlmsg_pid   = htonl(nlh->nlmsg_pid);
-
-	nfhdr->res_id    = htons(nfhdr->res_id);
-
-	return nlh_payload_host2network(NFM_NFA(NLMSG_DATA(nlh)), len);
-}
-
-int nlh_payload_network2host(struct nfattr *nfa, int len)
-{
-	nfa->nfa_type = ntohs(nfa->nfa_type);
-	nfa->nfa_len  = ntohs(nfa->nfa_len);
-
-	while(NFA_OK(nfa, len)) {
-
-                dprintf("type=%d nfalen=%d len=%d [%s]\n", 
-		        nfa->nfa_type & 0x7fff, 
-		        nfa->nfa_len, len, 
-		        nfa->nfa_type & NFNL_NFA_NEST ? "NEST":"");
-
-		if (nfa->nfa_type & NFNL_NFA_NEST) {
-			if (NFA_PAYLOAD(nfa) > len)
-				return -1;
-
-			if (nlh_payload_network2host(NFA_DATA(nfa),
-						     NFA_PAYLOAD(nfa)) == -1)
-				return -1;
-		}
-
-		nfa = NFA_NEXT(nfa,len);
-
-		if (len < NFA_LENGTH(0))
-			break;
-
-		nfa->nfa_type = ntohs(nfa->nfa_type);
-		nfa->nfa_len  = ntohs(nfa->nfa_len);
-	}
-	return 0;
-}
-
-int nlh_network2host(struct nlmsghdr *nlh)
-{
-	struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
-	struct nfattr *cda[CTA_MAX];
-	unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
-	unsigned int len = ntohl(nlh->nlmsg_len) - NLMSG_ALIGN(min_len);
-
-	nlh->nlmsg_len   = ntohl(nlh->nlmsg_len);
-	nlh->nlmsg_type  = ntohs(nlh->nlmsg_type);
-	nlh->nlmsg_flags = ntohs(nlh->nlmsg_flags);
-	nlh->nlmsg_seq   = ntohl(nlh->nlmsg_seq);
-	nlh->nlmsg_pid   = ntohl(nlh->nlmsg_pid);
-
-	nfhdr->res_id    = ntohs(nfhdr->res_id);
-
-	return nlh_payload_network2host(NFM_NFA(NLMSG_DATA(nlh)), len);
-}
diff --git a/daemon/src/read_config_lex.l b/daemon/src/read_config_lex.l
deleted file mode 100644
index dee90c9..0000000
--- a/daemon/src/read_config_lex.l
+++ /dev/null
@@ -1,125 +0,0 @@
-%{
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Description: configuration file syntax
- */
-
-#include "read_config_yy.h"
-#include "conntrackd.h"
-%}
-
-%option yylineno
-%option nounput
-
-ws		[ \t]+
-comment         #.*$
-nl		[\n\r]
-
-is_on		[o|O][n|N]
-is_off		[o|O][f|F][f|F]
-integer		[0-9]+
-path		\/[^\"\n ]*
-ip4_end		[0-9]*[0-9]+
-ip4_part	[0-2]*{ip4_end}
-ip4		{ip4_part}\.{ip4_part}\.{ip4_part}\.{ip4_part}
-hex_255		[0-9a-fA-F]{1,4}
-ip6_part	{hex_255}":"?
-ip6_form1	{ip6_part}{0,16}"::"{ip6_part}{0,16}
-ip6_form2	({hex_255}":"){16}{hex_255}
-ip6		{ip6_form1}|{ip6_form2}
-string		[a-zA-Z]*
-persistent	[P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T]
-nack		[N|n][A|a][C|c][K|k]
-
-%%
-"UNIX"				{ return T_UNIX; }
-"IPv4_address"			{ return T_IPV4_ADDR; }
-"IPv6_address"			{ return T_IPV6_ADDR; }
-"IPv4_interface"		{ return T_IPV4_IFACE; }
-"IPv6_interface"		{ return T_IPV6_IFACE; }
-"Port"				{ return T_PORT; }
-"Multicast"			{ return T_MULTICAST; }
-"HashSize"			{ return T_HASHSIZE; }
-"RefreshTime"			{ return T_REFRESH; }
-"CacheTimeout"			{ return T_EXPIRE; }
-"CommitTimeout"			{ return T_TIMEOUT; }
-"DelayDestroyMessages"		{ return T_DELAY; }
-"HashLimit"			{ return T_HASHLIMIT; }
-"Path"				{ return T_PATH; }
-"IgnoreProtocol"		{ return T_IGNORE_PROTOCOL; }
-"UDP"				{ return T_UDP; }
-"ICMP"				{ return T_ICMP; }
-"VRRP"				{ return T_VRRP; }
-"IGMP"				{ return T_IGMP; }
-"TCP"				{ return T_TCP; }
-"IgnoreTrafficFor"		{ return T_IGNORE_TRAFFIC; }
-"StripNAT"			{ return T_STRIP_NAT; }
-"Backlog"			{ return T_BACKLOG; }
-"Group"				{ return T_GROUP; }
-"LogFile"			{ return T_LOG; }
-"LockFile"			{ return T_LOCK; }
-"General"			{ return T_GENERAL; }
-"Sync"				{ return T_SYNC; }
-"Stats"				{ return T_STATS; }
-"RelaxTransitions"		{ return T_RELAX_TRANSITIONS; }
-"SocketBufferSize"		{ return T_BUFFER_SIZE; }
-"SocketBufferSizeMaxGrown"	{ return T_BUFFER_SIZE_MAX_GROWN; }
-"SocketBufferSizeMaxGrowth"	{ return T_BUFFER_SIZE_MAX_GROWN; }
-"Mode"				{ return T_SYNC_MODE; }
-"ListenTo"			{ return T_LISTEN_TO; }
-"Family"			{ return T_FAMILY; }
-"ResendBufferSize"		{ return T_RESEND_BUFFER_SIZE; }
-"Checksum"			{ return T_CHECKSUM; }
-"ACKWindowSize"			{ return T_WINDOWSIZE; }
-"Replicate"			{ return T_REPLICATE; }
-"for"				{ return T_FOR; }
-"SYN_SENT"			{ return T_SYN_SENT; }
-"SYN_RECV"			{ return T_SYN_RECV; }
-"ESTABLISHED"			{ return T_ESTABLISHED; }
-"FIN_WAIT"			{ return T_FIN_WAIT; }
-"CLOSE_WAIT"			{ return T_CLOSE_WAIT; }
-"LAST_ACK"			{ return T_LAST_ACK; }
-"TIME_WAIT"			{ return T_TIME_WAIT; }
-"CLOSE"				{ return T_CLOSE; }
-"LISTEN"			{ return T_LISTEN; }
-
-{is_on}			{ return T_ON; }
-{is_off}		{ return T_OFF; }
-{integer}		{ yylval.val = atoi(yytext); return T_NUMBER; }
-{ip4}			{ yylval.string = strdup(yytext); return T_IP; }
-{ip6}			{ yylval.string = strdup(yytext); return T_IP; }
-{path}			{ yylval.string = strdup(yytext); return T_PATH_VAL; }
-{persistent}		{ return T_PERSISTENT; }
-{nack}			{ return T_NACK; }
-{string}		{ yylval.string = strdup(yytext); return T_STRING; }
-
-{comment}	;
-{ws}		;
-{nl}		;
-
-<<EOF>>		{ yyterminate(); }
-
-.		{ return yytext[0]; }
-
-%%
-
-int
-yywrap()
-{
-	return 1;
-}
diff --git a/daemon/src/read_config_yy.y b/daemon/src/read_config_yy.y
deleted file mode 100644
index 1668919..0000000
--- a/daemon/src/read_config_yy.y
+++ /dev/null
@@ -1,550 +0,0 @@
-%{
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Description: configuration file abstract grammar
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include "conntrackd.h"
-#include "ignore.h"
-
-extern char *yytext;
-extern int   yylineno;
-
-struct ct_conf conf;
-%}
-
-%union {
-	int		val;
-	char		*string;
-}
-
-%token T_IPV4_ADDR T_IPV4_IFACE T_PORT T_HASHSIZE T_HASHLIMIT T_MULTICAST
-%token T_PATH T_UNIX T_REFRESH T_IPV6_ADDR T_IPV6_IFACE
-%token T_IGNORE_UDP T_IGNORE_ICMP T_IGNORE_TRAFFIC T_BACKLOG T_GROUP
-%token T_LOG T_UDP T_ICMP T_IGMP T_VRRP T_TCP T_IGNORE_PROTOCOL
-%token T_LOCK T_STRIP_NAT T_BUFFER_SIZE_MAX_GROWN T_EXPIRE T_TIMEOUT
-%token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY
-%token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE
-%token T_PERSISTENT T_NACK T_CHECKSUM T_WINDOWSIZE T_ON T_OFF
-%token T_REPLICATE T_FOR 
-%token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT 
-%token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN
-
-
-%token <string> T_IP T_PATH_VAL
-%token <val> T_NUMBER
-%token <string> T_STRING
-
-%%
-
-configfile :
-	   | lines
-	   ;
-
-lines : line
-      | lines line
-      ;
-
-line : ignore_protocol
-     | ignore_traffic
-     | strip_nat
-     | general
-     | sync
-     | stats
-     ;
-
-log : T_LOG T_PATH_VAL
-{
-	strncpy(conf.logfile, $2, FILENAME_MAXLEN);
-};
-
-lock : T_LOCK T_PATH_VAL
-{
-	strncpy(conf.lockfile, $2, FILENAME_MAXLEN);
-};
-
-strip_nat: T_STRIP_NAT
-{
-	conf.flags |= STRIP_NAT;
-};
-
-refreshtime : T_REFRESH T_NUMBER
-{
-	conf.refresh = $2;
-};
-
-expiretime: T_EXPIRE T_NUMBER
-{
-	conf.cache_timeout = $2;
-};
-
-timeout: T_TIMEOUT T_NUMBER
-{
-	conf.commit_timeout = $2;
-};
-
-checksum: T_CHECKSUM T_ON 
-{
-};
-
-checksum: T_CHECKSUM T_OFF
-{
-	conf.flags |= DONT_CHECKSUM;
-};
-
-ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}';
-
-ignore_traffic_options :
-		       | ignore_traffic_options ignore_traffic_option;
-
-ignore_traffic_option : T_IPV4_ADDR T_IP
-{
-	union inet_address ip;
-	int family = 0;
-
-	memset(&ip, 0, sizeof(union inet_address));
-
-	if (inet_aton($2, &ip.ipv4))
-		family = AF_INET;
-#ifdef HAVE_INET_PTON_IPV6
-	else if (inet_pton(AF_INET6, $2, &ip.ipv6) > 0)
-		family = AF_INET6;
-#endif
-
-	if (!family) {
-		fprintf(stdout, "%s is not a valid IP, ignoring", $2);
-		return;
-	}
-
-	if (!STATE(ignore_pool)) {
-		STATE(ignore_pool) = ignore_pool_create(family);
-		if (!STATE(ignore_pool)) {
-			fprintf(stdout, "Can't create ignore pool!\n");
-			exit(EXIT_FAILURE);
-		}
-	}
-
-	if (!ignore_pool_add(STATE(ignore_pool), &ip)) {
-		if (errno == EEXIST)
-			fprintf(stdout, "IP %s is repeated "
-					"in the ignore pool\n", $2);
-		if (errno == ENOSPC)
-			fprintf(stdout, "Too many IP in the ignore pool!\n");
-	}
-};
-
-multicast_line : T_MULTICAST '{' multicast_options '}';
-
-multicast_options :
-		  | multicast_options multicast_option;
-
-multicast_option : T_IPV4_ADDR T_IP
-{
-	if (!inet_aton($2, &conf.mcast.in)) {
-		fprintf(stderr, "%s is not a valid IPv4 address\n");
-		return;
-	}
-
-        if (conf.mcast.ipproto == AF_INET6) {
-		fprintf(stderr, "Your multicast address is IPv4 but "
-		                "is binded to an IPv6 interface? Surely "
-				"this is not what you want\n");
-		return;
-	}
-
-	conf.mcast.ipproto = AF_INET;
-};
-
-multicast_option : T_IPV6_ADDR T_IP
-{
-#ifdef HAVE_INET_PTON_IPV6
-	if (inet_pton(AF_INET6, $2, &conf.mcast.in) <= 0)
-		fprintf(stderr, "%s is not a valid IPv6 address\n", $2);
-#endif
-
-	if (conf.mcast.ipproto == AF_INET) {
-		fprintf(stderr, "Your multicast address is IPv6 but "
-				"is binded to an IPv4 interface? Surely "
-				"this is not what you want\n");
-		return;
-	}
-
-	conf.mcast.ipproto = AF_INET6;
-};
-
-multicast_option : T_IPV4_IFACE T_IP
-{
-	if (!inet_aton($2, &conf.mcast.ifa)) {
-		fprintf(stderr, "%s is not a valid IPv4 address\n");
-		return;
-	}
-
-        if (conf.mcast.ipproto == AF_INET6) {
-		fprintf(stderr, "Your multicast interface is IPv4 but "
-		                "is binded to an IPv6 interface? Surely "
-				"this is not what you want\n");
-		return;
-	}
-
-	conf.mcast.ipproto = AF_INET;
-};
-
-multicast_option : T_IPV6_IFACE T_IP
-{
-#ifdef HAVE_INET_PTON_IPV6
-	if (inet_pton(AF_INET6, $2, &conf.mcast.ifa) <= 0)
-		fprintf(stderr, "%s is not a valid IPv6 address\n", $2);
-#endif
-
-	if (conf.mcast.ipproto == AF_INET) {
-		fprintf(stderr, "Your multicast interface is IPv6 but "
-				"is binded to an IPv4 interface? Surely "
-				"this is not what you want\n");
-		return;
-	}
-
-	conf.mcast.ipproto = AF_INET6;
-};
-
-multicast_option : T_BACKLOG T_NUMBER
-{
-	conf.mcast.backlog = $2;
-};
-
-multicast_option : T_GROUP T_NUMBER
-{
-	conf.mcast.port = $2;
-};
-
-hashsize : T_HASHSIZE T_NUMBER
-{
-	conf.hashsize = $2;
-};
-
-hashlimit: T_HASHLIMIT T_NUMBER
-{
-	conf.limit = $2;
-};
-
-unix_line: T_UNIX '{' unix_options '}';
-
-unix_options:
-	    | unix_options unix_option
-	    ;
-
-unix_option : T_PATH T_PATH_VAL
-{
-	strcpy(conf.local.path, $2);
-};
-
-unix_option : T_BACKLOG T_NUMBER
-{
-	conf.local.backlog = $2;
-};
-
-ignore_protocol: T_IGNORE_PROTOCOL '{' ignore_proto_list '}';
-
-ignore_proto_list:
-		 | ignore_proto_list ignore_proto
-		 ;
-
-ignore_proto: T_NUMBER
-{
-	if ($1 < IPPROTO_MAX)
-		conf.ignore_protocol[$1] = 1;
-	else
-		fprintf(stdout, "Protocol number `%d' is freak\n", $1);
-};
-
-ignore_proto: T_UDP
-{
-	conf.ignore_protocol[IPPROTO_UDP] = 1;
-};
-
-ignore_proto: T_ICMP
-{
-	conf.ignore_protocol[IPPROTO_ICMP] = 1;
-};
-
-ignore_proto: T_VRRP
-{
-	conf.ignore_protocol[IPPROTO_VRRP] = 1;
-};
-
-ignore_proto: T_IGMP
-{
-	conf.ignore_protocol[IPPROTO_IGMP] = 1;
-};
-
-sync: T_SYNC '{' sync_list '}';
-
-sync_list:
-	 | sync_list sync_line;
-
-sync_line: refreshtime
-	 | expiretime
-	 | timeout
-	 | checksum
-	 | multicast_line
-	 | relax_transitions
-	 | delay_destroy_msgs
-	 | sync_mode_persistent
-	 | sync_mode_nack
-	 | listen_to
-	 | state_replication
-	 ;
-
-sync_mode_persistent: T_SYNC_MODE T_PERSISTENT '{' sync_mode_persistent_list '}'
-{
-	conf.flags |= SYNC_MODE_PERSISTENT;
-};
-
-sync_mode_nack: T_SYNC_MODE T_NACK '{' sync_mode_nack_list '}'
-{
-	conf.flags |= SYNC_MODE_NACK;
-};
-
-sync_mode_persistent_list:
-	      | sync_mode_persistent_list sync_mode_persistent_line;
-
-sync_mode_persistent_line: refreshtime
-              		 | expiretime
-	     		 | timeout
-			 | relax_transitions
-			 | delay_destroy_msgs
-			 ;
-
-sync_mode_nack_list:
-	      | sync_mode_nack_list sync_mode_nack_line;
-
-sync_mode_nack_line: resend_buffer_size
-		   | timeout
-		   | window_size
-		   ;
-
-resend_buffer_size: T_RESEND_BUFFER_SIZE T_NUMBER
-{
-	conf.resend_buffer_size = $2;
-};
-
-window_size: T_WINDOWSIZE T_NUMBER
-{
-	conf.window_size = $2;
-};
-
-relax_transitions: T_RELAX_TRANSITIONS
-{
-	conf.flags |= RELAX_TRANSITIONS;
-};
-
-delay_destroy_msgs: T_DELAY
-{
-	conf.flags |= DELAY_DESTROY_MSG;
-};
-
-listen_to: T_LISTEN_TO T_IP
-{
-	union inet_address addr;
-
-#ifdef HAVE_INET_PTON_IPV6
-	if (inet_pton(AF_INET6, $2, &addr.ipv6) <= 0)
-#endif
-		if (inet_aton($2, &addr.ipv4) <= 0) {
-			fprintf(stderr, "%s is not a valid IP address\n", $2);
-			exit(EXIT_FAILURE);
-		}
-
-	if (CONFIG(listen_to_len) == 0 || CONFIG(listen_to_len) % 16) {
-		CONFIG(listen_to) = realloc(CONFIG(listen_to),
-					    sizeof(union inet_address) *
-					    (CONFIG(listen_to_len) + 16));
-		if (CONFIG(listen_to) == NULL) {
-			fprintf(stderr, "cannot init listen_to array\n");
-			exit(EXIT_FAILURE);
-		}
-
-		memset(CONFIG(listen_to) + 
-		       (CONFIG(listen_to_len) * sizeof(union inet_address)),
-		       0, sizeof(union inet_address) * 16);
-
-	}
-};
-
-state_replication: T_REPLICATE states T_FOR state_proto;
-
-states:
-      | states state;
-
-state_proto: T_TCP;
-state: tcp_state;
-
-tcp_state: T_SYN_SENT
-{
-	extern struct state_replication_helper tcp_state_helper;
-	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_SENT);
-};
-tcp_state: T_SYN_RECV
-{
-	extern struct state_replication_helper tcp_state_helper;
-	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_RECV);
-};
-tcp_state: T_ESTABLISHED
-{
-	extern struct state_replication_helper tcp_state_helper;
-	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_ESTABLISHED);
-};
-tcp_state: T_FIN_WAIT
-{
-	extern struct state_replication_helper tcp_state_helper;
-	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_FIN_WAIT);
-};
-tcp_state: T_CLOSE_WAIT
-{
-	extern struct state_replication_helper tcp_state_helper;
-	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE_WAIT);
-};
-tcp_state: T_LAST_ACK
-{
-	extern struct state_replication_helper tcp_state_helper;
-	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LAST_ACK);
-};
-tcp_state: T_TIME_WAIT
-{
-	extern struct state_replication_helper tcp_state_helper;
-	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_TIME_WAIT);
-};
-tcp_state: T_CLOSE
-{
-	extern struct state_replication_helper tcp_state_helper;
-	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE);
-};
-tcp_state: T_LISTEN
-{
-	extern struct state_replication_helper tcp_state_helper;
-	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LISTEN);
-};
-
-general: T_GENERAL '{' general_list '}';
-
-general_list:
-	    | general_list general_line
-	    ;
-
-general_line: hashsize
-	    | hashlimit
-	    | log
-	    | lock
-	    | unix_line
-	    | netlink_buffer_size
-	    | netlink_buffer_size_max_grown
-	    | family
-	    ;
-
-netlink_buffer_size: T_BUFFER_SIZE T_NUMBER
-{
-	conf.netlink_buffer_size = $2;
-};
-
-netlink_buffer_size_max_grown : T_BUFFER_SIZE_MAX_GROWN T_NUMBER
-{
-	conf.netlink_buffer_size_max_grown = $2;
-};
-
-family : T_FAMILY T_STRING
-{
-	if (strncmp($2, "IPv6", strlen("IPv6")) == 0)
-		conf.family = AF_INET6;
-	else
-		conf.family = AF_INET;
-};
-
-stats: T_SYNC '{' stats_list '}';
-
-stats_list:
-	 | stats_list stat_line
-	 ;
-
-stat_line:
-	 |
-	 ;
-
-%%
-
-int
-yyerror(char *msg)
-{
-	printf("Error parsing config file: ");
-	printf("line (%d), symbol '%s': %s\n", yylineno, yytext, msg);
-	exit(EXIT_FAILURE);
-}
-
-int
-init_config(char *filename)
-{
-	FILE *fp;
-
-	fp = fopen(filename, "r");
-	if (!fp)
-		return -1;
-
-	yyrestart(fp);
-	yyparse();
-	fclose(fp);
-
-	/* default to IPv4 */
-	if (CONFIG(family) == 0)
-		CONFIG(family) = AF_INET;
-
-	/* set to default is not specified */
-	if (strcmp(CONFIG(lockfile), "") == 0)
-		strncpy(CONFIG(lockfile), DEFAULT_LOCKFILE, FILENAME_MAXLEN);
-
-	/* default to 180 seconds of expiration time: cache entries */
-	if (CONFIG(cache_timeout) == 0)
-		CONFIG(cache_timeout) = 180;
-
-	/* default to 180 seconds: committed entries */
-	if (CONFIG(commit_timeout) == 0)
-		CONFIG(commit_timeout) = 180;
-
-	/* default to 60 seconds of refresh time */
-	if (CONFIG(refresh) == 0)
-		CONFIG(refresh) = 60;
-
-	if (CONFIG(resend_buffer_size) == 0)
-		CONFIG(resend_buffer_size) = 262144;
-
-	/* create empty pool */
-	if (!STATE(ignore_pool)) {
-		STATE(ignore_pool) = ignore_pool_create(CONFIG(family));
-		if (!STATE(ignore_pool)) {
-			fprintf(stdout, "Can't create ignore pool!\n");
-			exit(EXIT_FAILURE);
-		}
-	}
-
-	/* default to a window size of 20 packets */
-	if (CONFIG(window_size) == 0)
-		CONFIG(window_size) = 20;
-
-	return 0;
-}
diff --git a/daemon/src/run.c b/daemon/src/run.c
deleted file mode 100644
index 67437d8..0000000
--- a/daemon/src/run.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * (C) 2006-2007 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Description: run and init functions
- */
-
-#include "conntrackd.h"
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <errno.h>
-#include "us-conntrack.h"
-#include <signal.h>
-#include <stdlib.h>
-
-void killer(int foo)
-{
-	/* no signals while handling signals */
-	sigprocmask(SIG_BLOCK, &STATE(block), NULL);
-
-	nfnl_subsys_close(STATE(subsys_event));
-	nfnl_subsys_close(STATE(subsys_dump));
-	nfnl_subsys_close(STATE(subsys_sync));
-	nfnl_close(STATE(event));
-	nfnl_close(STATE(dump));
-	nfnl_close(STATE(sync));
-
-	ignore_pool_destroy(STATE(ignore_pool));
-	local_server_destroy(STATE(local));
-	STATE(mode)->kill();
-        unlink(CONFIG(lockfile));
-	dlog(STATE(log), "------- shutdown received ----");
-	close_log(STATE(log));
-
-	sigprocmask(SIG_UNBLOCK, &STATE(block), NULL);
-
-	exit(0);			
-}
-
-void local_handler(int fd, void *data)
-{
-	int ret;
-	int type;
-
-	ret = read(fd, &type, sizeof(type));
-	if (ret == -1) {
-		dlog(STATE(log), "can't read from unix socket\n");
-		return;
-	}
-	if (ret == 0) {
-		debug("nothing to process\n");
-		return;
-	}
-
-	switch(type) {
-	case FLUSH_MASTER:
-		dlog(STATE(log), "[REQ] flushing master table");
-		nl_flush_master_conntrack_table();
-		return;
-	case RESYNC_MASTER:
-		dlog(STATE(log), "[REQ] resync with master table");
-		nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump));
-		return;
-	}
-
-	if (!STATE(mode)->local(fd, type, data))
-		dlog(STATE(log), "[FAIL] unknown local request %d", type);
-}
-
-int init(int mode)
-{
-	switch(mode) {
-		case STATS_MODE:
-			STATE(mode) = &stats_mode;
-			break;
-		case SYNC_MODE:
-			STATE(mode) = &sync_mode;
-			break;
-		default:
-			fprintf(stderr, "Unknown running mode! default "
-					"to synchronization mode\n");
-			STATE(mode) = &sync_mode;
-			break;
-	}
-
-	/* Initialization */
-	if (STATE(mode)->init() == -1) {
-		dlog(STATE(log), "[FAIL] initialization failed");
-		return -1;
-	}
-
-	/* local UNIX socket */
-	STATE(local) = local_server_create(&CONFIG(local));
-	if (!STATE(local)) {
-		dlog(STATE(log), "[FAIL] can't open unix socket!");
-		return -1;
-	}
-
-	if (nl_init_event_handler() == -1) {
-		dlog(STATE(log), "[FAIL] can't open netlink handler! "
-				 "no ctnetlink kernel support?");
-		return -1;
-	}
-
-	if (nl_init_dump_handler() == -1) {
-		dlog(STATE(log), "[FAIL] can't open netlink handler! "
-				 "no ctnetlink kernel support?");
-		return -1;
-	}
-
-	if (nl_init_overrun_handler() == -1) {
-		dlog(STATE(log), "[FAIL] can't open netlink handler! "
-				 "no ctnetlink kernel support?");
-		return -1;
-	}
-
-        /* Signals handling */
-	sigemptyset(&STATE(block));
-	sigaddset(&STATE(block), SIGTERM);
-	sigaddset(&STATE(block), SIGINT);
-
-	if (signal(SIGINT, killer) == SIG_ERR)
-		return -1;
-
-	if (signal(SIGTERM, killer) == SIG_ERR)
-		return -1;
-
-	/* ignore connection reset by peer */
-	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
-		return -1;
-
-	dlog(STATE(log), "[OK] initialization completed");
-
-	return 0;
-}
-
-#define POLL_NSECS 1
-
-static void __run(void)
-{
-	int max, ret;
-	fd_set readfds;
-	struct timeval tv = {
-		.tv_sec         = POLL_NSECS,
-		.tv_usec        = 0
-	};
-
-	FD_ZERO(&readfds);
-	FD_SET(STATE(local), &readfds);
-	FD_SET(nfnl_fd(STATE(event)), &readfds);
-
-	max = MAX(STATE(local), nfnl_fd(STATE(event)));
-
-	if (STATE(mode)->add_fds_to_set)
-		max = MAX(max, STATE(mode)->add_fds_to_set(&readfds));
-
-	ret = select(max+1, &readfds, NULL, NULL, &tv);
-	if (ret == -1) {
-		/* interrupted syscall, retry */
-		if (errno == EINTR)
-			return;
-
-		dlog(STATE(log), "select() failed: %s", strerror(errno));
-		return;
-	}
-
-	/* signals are racy */
-	sigprocmask(SIG_BLOCK, &STATE(block), NULL);		
-
-	/* order received via UNIX socket */
-	if (FD_ISSET(STATE(local), &readfds))
-		do_local_server_step(STATE(local), NULL, local_handler);
-
-	/* conntrack event has happened */
-	if (FD_ISSET(nfnl_fd(STATE(event)), &readfds)) {
-		ret = nfnl_catch(STATE(event));
-		if (ret == -1) {
-			switch(errno) {
-			case ENOBUFS:
-                		/*
-		 		 * It seems that ctnetlink can't back off,
-				 * it's likely that we're losing events.
-				 * Solution: duplicate the socket buffer
-				 * size and resync with master conntrack table.
-				 */
-				nl_resize_socket_buffer(STATE(event));
-				nl_dump_conntrack_table(STATE(sync),
-							STATE(subsys_sync));
-				break;
-			case ENOENT:
-				/*
-				 * We received a message from another
-				 * netfilter subsystem that we are not
-				 * interested in. Just ignore it.
-				 */
-				break;
-			default:
-				dlog(STATE(log), "event catch says: %s",
-						  strerror(errno));
-				break;
-			}
-		}
-	}
-
-	if (STATE(mode)->step)
-		STATE(mode)->step(&readfds);
-
-	sigprocmask(SIG_UNBLOCK, &STATE(block), NULL);
-}
-
-void run(void)
-{
-	while(1)
-		__run();
-}
diff --git a/daemon/src/state_helper.c b/daemon/src/state_helper.c
deleted file mode 100644
index 81b0d09..0000000
--- a/daemon/src/state_helper.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * (C) 2006-2007 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "conntrackd.h"
-#include "state_helper.h"
-
-static struct state_replication_helper *helper[IPPROTO_MAX];
-
-int state_helper_verdict(int type, struct nf_conntrack *ct) 
-{
-	u_int8_t l4proto;
-
-        if (type == NFCT_T_DESTROY)
-		return ST_H_REPLICATE;
-
-	l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
-	if (helper[l4proto])
-		return helper[l4proto]->verdict(helper[l4proto], ct);
-
-	return ST_H_REPLICATE;
-}
-
-void state_helper_register(struct state_replication_helper *h, int state)
-{
-	if (helper[h->proto] == NULL)
-		helper[h->proto] = h;
-
-	helper[h->proto]->state |= (1 << state);
-}
diff --git a/daemon/src/state_helper_tcp.c b/daemon/src/state_helper_tcp.c
deleted file mode 100644
index af714dc..0000000
--- a/daemon/src/state_helper_tcp.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * (C) 2006-2007 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "conntrackd.h"
-#include "state_helper.h"
-
-static int tcp_verdict(const struct state_replication_helper *h,
-		       const struct nf_conntrack *ct)
-{
-	u_int8_t state = nfct_get_attr_u8(ct, ATTR_TCP_STATE);
-	if (h->state & (1 << state))
-		return ST_H_REPLICATE;
-
-	return ST_H_SKIP;
-}
-
-struct state_replication_helper tcp_state_helper = {
-	.proto 		= IPPROTO_TCP,
-	.verdict 	= tcp_verdict,
-};
diff --git a/daemon/src/stats-mode.c b/daemon/src/stats-mode.c
deleted file mode 100644
index 9647bbf..0000000
--- a/daemon/src/stats-mode.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <stdlib.h>
-#include "cache.h"
-#include "conntrackd.h"
-#include <libnfnetlink/libnfnetlink.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <errno.h>
-#include "us-conntrack.h"
-#include <signal.h>
-#include <sys/select.h>
-
-static int init_stats(void)
-{
-	int ret;
-
-	state.stats = malloc(sizeof(struct ct_stats_state));
-	if (!state.stats) {
-		dlog(STATE(log), "[FAIL] can't allocate memory for stats sync");
-		return -1;
-	}
-	memset(state.stats, 0, sizeof(struct ct_stats_state));
-
-	STATE_STATS(cache) = cache_create("stats",
-					  LIFETIME, 
-					  CONFIG(family),
-					  NULL); 
-	if (!STATE_STATS(cache)) {
-		dlog(STATE(log), "[FAIL] can't allocate memory for the "
-				 "external cache");
-		return -1;
-	}
-
-	return 0;
-}
-
-static void kill_stats()
-{
-	cache_destroy(STATE_STATS(cache));
-}
-
-/* handler for requests coming via UNIX socket */
-static int local_handler_stats(int fd, int type, void *data)
-{
-	int ret = 1;
-
-	switch(type) {
-	case DUMP_INTERNAL:
-		cache_dump(STATE_STATS(cache), fd, NFCT_O_PLAIN);
-		break;
-	case DUMP_INT_XML:
-		cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML);
-		break;
-	case FLUSH_CACHE:
-		dlog(STATE(log), "[REQ] flushing caches");
-		cache_flush(STATE_STATS(cache));
-		break;
-	case KILL:
-		killer();
-		break;
-	case STATS:
-		cache_stats(STATE_STATS(cache), fd);
-		dump_traffic_stats(fd);
-		break;
-	default:
-		ret = 0;
-		break;
-	}
-
-	return ret;
-}
-
-static void dump_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
-{
-	if (cache_update_force(STATE_STATS(cache), ct))
-		debug_ct(ct, "resync entry");
-}
-
-static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
-{
-	debug_ct(ct, "debug event");
-	if (cache_add(STATE_STATS(cache), ct)) {
-		debug_ct(ct, "cache new");
-	} else {
-		dlog(STATE(log), "can't add to cache cache: "
-				      "%s\n", strerror(errno));
-		debug_ct(ct, "can't add");
-	}
-}
-
-static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
-{
-	debug_ct(ct, "update");
-
-	if (!cache_update(STATE_STATS(cache), ct)) {
-		/*
-		 * Perhaps we are losing events. If we are working 
-		 * in relax mode then add a new entry to the cache.
-		 *
-		 * FIXME: relax transitions not implemented yet
-		 */
-		if ((CONFIG(flags) & RELAX_TRANSITIONS)
-		    && cache_add(STATE_STATS(cache), ct)) {
-			debug_ct(ct, "forcing cache update");
-		} else {
-			debug_ct(ct, "can't update");
-			return;
-		}
-	}
-	debug_ct(ct, "update");
-}
-
-static int event_destroy_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
-{
-	if (cache_del(STATE_STATS(cache), ct)) {
-		debug_ct(ct, "cache destroy");
-		return 1;
-	} else {
-		debug_ct(ct, "can't destroy!");
-		return 0;
-	}
-}
-
-struct ct_mode stats_mode = {
-	.init 			= init_stats,
-	.add_fds_to_set 	= NULL,
-	.step			= NULL,
-	.local			= local_handler_stats,
-	.kill			= kill_stats,
-	.dump			= dump_stats,
-	.overrun		= dump_stats,
-	.event_new		= event_new_stats,
-	.event_upd		= event_update_stats,
-	.event_dst		= event_destroy_stats
-};
diff --git a/daemon/src/sync-mode.c b/daemon/src/sync-mode.c
deleted file mode 100644
index b32bef7..0000000
--- a/daemon/src/sync-mode.c
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <stdlib.h>
-#include "cache.h"
-#include "conntrackd.h"
-#include <libnfnetlink/libnfnetlink.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <errno.h>
-#include "us-conntrack.h"
-#include <signal.h>
-#include <sys/select.h>
-#include "sync.h"
-#include "network.h"
-
-/* handler for multicast messages received */
-static void mcast_handler()
-{
-	int ret;
-	char buf[4096], tmp[256];
-	struct mcast_sock *m = STATE_SYNC(mcast_server);
-	unsigned int type;
-	struct nlnetwork *net = (struct nlnetwork *) buf;
-	unsigned int size = sizeof(struct nlnetwork);
-	struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size);
-	struct nf_conntrack *ct = (struct nf_conntrack *) tmp;
-	struct us_conntrack *u = NULL;
-
-	memset(tmp, 0, sizeof(tmp));
-
-	ret = mcast_recv_netmsg(m, buf, sizeof(buf));
-	if (ret <= 0) {
-		STATE(malformed)++;
-		return;
-	}
-
-	if (STATE_SYNC(mcast_sync)->pre_recv(net))
-		return;
-
-	if ((type = parse_network_msg(ct, nlh)) == NFCT_T_ERROR) {
-		STATE(malformed)++;
-		return;
-	}
-
-	nfct_attr_unset(ct, ATTR_TIMEOUT);
-	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES);
-	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS);
-	nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES);
-	nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS);
-
-	switch(type) {
-	case NFCT_T_NEW:
-retry:		
-		if ((u = cache_add(STATE_SYNC(external), ct))) {
-			debug_ct(u->ct, "external new");
-		} else {
-		        /*
-			 * One certain connection A arrives to the cache but 
-			 * another existing connection B in the cache has 
-			 * the same configuration, therefore B clashes with A.
-			 */
-			if (errno == EEXIST) {
-				cache_del(STATE_SYNC(external), ct);
-				goto retry;
-			}
-			debug_ct(ct, "can't add");
-		}
-		break;
-	case NFCT_T_UPDATE:
-		if ((u = cache_update_force(STATE_SYNC(external), ct))) {
-			debug_ct(u->ct, "external update");
-		} else
-			debug_ct(ct, "can't update");
-		break;
-	case NFCT_T_DESTROY:
-		if (cache_del(STATE_SYNC(external), ct))
-			debug_ct(ct, "external destroy");
-		else
-			debug_ct(ct, "can't destroy");
-		break;
-	default:
-		debug("unknown type %d\n", type);
-		break;
-	}
-}
-
-static int init_sync(void)
-{
-	int ret;
-
-	state.sync = malloc(sizeof(struct ct_sync_state));
-	if (!state.sync) {
-		dlog(STATE(log), "[FAIL] can't allocate memory for state sync");
-		return -1;
-	}
-	memset(state.sync, 0, sizeof(struct ct_sync_state));
-
-	if (CONFIG(flags) & SYNC_MODE_NACK)
-		STATE_SYNC(mcast_sync) = &nack;
-	else
-		/* default to persistent mode */
-		STATE_SYNC(mcast_sync) = &notrack;
-
-	if (STATE_SYNC(mcast_sync)->init)
-		STATE_SYNC(mcast_sync)->init();
-
-	STATE_SYNC(internal) =
-		cache_create("internal", 
-			     STATE_SYNC(mcast_sync)->internal_cache_flags,
-			     CONFIG(family),
-			     STATE_SYNC(mcast_sync)->internal_cache_extra);
-
-	if (!STATE_SYNC(internal)) {
-		dlog(STATE(log), "[FAIL] can't allocate memory for "
-				 "the internal cache");
-		return -1;
-	}
-
-	STATE_SYNC(external) = 
-		cache_create("external",
-			     STATE_SYNC(mcast_sync)->external_cache_flags,
-			     CONFIG(family),
-			     NULL);
-
-	if (!STATE_SYNC(external)) {
-		dlog(STATE(log), "[FAIL] can't allocate memory for the "
-				 "external cache");
-		return -1;
-	}
-
-	/* multicast server to receive events from the wire */
-	STATE_SYNC(mcast_server) = mcast_server_create(&CONFIG(mcast));
-	if (STATE_SYNC(mcast_server) == NULL) {
-		dlog(STATE(log), "[FAIL] can't open multicast server!");
-		return -1;
-	}
-
-	/* multicast client to send events on the wire */
-	STATE_SYNC(mcast_client) = mcast_client_create(&CONFIG(mcast));
-	if (STATE_SYNC(mcast_client) == NULL) {
-		dlog(STATE(log), "[FAIL] can't open client multicast socket!");
-		return -1;
-	}
-
-	/* initialization of multicast sequence generation */
-	STATE_SYNC(last_seq_sent) = time(NULL);
-
-	if (create_alarm_thread() == -1) {
-		dlog(STATE(log), "[FAIL] can't initialize alarm thread");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int add_fds_to_set_sync(fd_set *readfds) 
-{
-	FD_SET(STATE_SYNC(mcast_server->fd), readfds);
-
-	return STATE_SYNC(mcast_server->fd);
-}
-
-static void step_sync(fd_set *readfds)
-{
-	/* multicast packet has been received */
-	if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds))
-		mcast_handler();
-}
-
-static void kill_sync()
-{
-	cache_destroy(STATE_SYNC(internal));
-	cache_destroy(STATE_SYNC(external));
-
-	mcast_server_destroy(STATE_SYNC(mcast_server));
-	mcast_client_destroy(STATE_SYNC(mcast_client));
-
-	destroy_alarm_thread();
-
-	if (STATE_SYNC(mcast_sync)->kill)
-		STATE_SYNC(mcast_sync)->kill();
-}
-
-static dump_stats_sync(int fd)
-{
-	char buf[512];
-	int size;
-
-	size = sprintf(buf, "multicast sequence tracking:\n"
-			    "%20llu Pckts mfrm "
-			    "%20llu Pckts lost\n\n",
-			STATE(malformed),
-			STATE_SYNC(packets_lost));
-
-	send(fd, buf, size, 0);
-}
-
-/* handler for requests coming via UNIX socket */
-static int local_handler_sync(int fd, int type, void *data)
-{
-	int ret = 1;
-
-	switch(type) {
-	case DUMP_INTERNAL:
-		cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN);
-		break;
-	case DUMP_EXTERNAL:
-		cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN);
-		break;
-	case DUMP_INT_XML:
-		cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML);
-		break;
-	case DUMP_EXT_XML:
-		cache_dump(STATE_SYNC(external), fd, NFCT_O_XML);
-		break;
-	case COMMIT:
-		dlog(STATE(log), "[REQ] commit external cache to master table");
-		cache_commit(STATE_SYNC(external));
-		break;
-	case FLUSH_CACHE:
-		dlog(STATE(log), "[REQ] flushing caches");
-		cache_flush(STATE_SYNC(internal));
-		cache_flush(STATE_SYNC(external));
-		break;
-	case KILL:
-		killer();
-		break;
-	case STATS:
-		cache_stats(STATE_SYNC(internal), fd);
-		cache_stats(STATE_SYNC(external), fd);
-		dump_traffic_stats(fd);
-		mcast_dump_stats(fd, STATE_SYNC(mcast_client), 
-				     STATE_SYNC(mcast_server));
-		dump_stats_sync(fd);
-		break;
-	case SEND_BULK:
-		dlog(STATE(log), "[REQ] sending bulk update");
-		cache_bulk(STATE_SYNC(internal));
-		break;
-	default:
-		if (STATE_SYNC(mcast_sync)->local)
-			ret = STATE_SYNC(mcast_sync)->local(fd, type, data);
-		break;
-	}
-
-	return ret;
-}
-
-static void dump_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
-{
-	/* This is required by kernels < 2.6.20 */
-	nfct_attr_unset(ct, ATTR_TIMEOUT);
-	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES);
-	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS);
-	nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES);
-	nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS);
-	nfct_attr_unset(ct, ATTR_USE);
-
-	if (cache_update_force(STATE_SYNC(internal), ct))
-		debug_ct(ct, "resync");
-}
-
-static void mcast_send_sync(struct nlmsghdr *nlh,
-			    struct us_conntrack *u,
-			    struct nf_conntrack *ct,
-			    int type)
-{
-	char buf[4096];
-	struct nlnetwork *net = (struct nlnetwork *) buf;
-	int mangled = 0;
-
-	memset(buf, 0, sizeof(buf));
-
-	if (!state_helper_verdict(type, ct))
-		return;
-
-	if (!mangled)
-		memcpy(buf + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len);
-
-	mcast_send_netmsg(STATE_SYNC(mcast_client), net); 
-	STATE_SYNC(mcast_sync)->post_send(net, u);
-}
-
-static void overrun_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
-{
-	struct us_conntrack *u;
-
-	/* This is required by kernels < 2.6.20 */
-	nfct_attr_unset(ct, ATTR_TIMEOUT);
-	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES);
-	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS);
-	nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES);
-	nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS);
-	nfct_attr_unset(ct, ATTR_USE);
-
-	if (!cache_test(STATE_SYNC(internal), ct)) {
-		if ((u = cache_update_force(STATE_SYNC(internal), ct))) {
-			debug_ct(ct, "overrun resync");
-			mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE);
-		}
-	}
-}
-
-static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
-{
-	struct us_conntrack *u;
-
-	/* required by linux kernel <= 2.6.20 */
-	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES);
-	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS);
-	nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES);
-	nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS);
-	nfct_attr_unset(ct, ATTR_TIMEOUT);
-retry:
-	if ((u = cache_add(STATE_SYNC(internal), ct))) {
-		mcast_send_sync(nlh, u, ct, NFCT_T_NEW);
-		debug_ct(u->ct, "internal new");
-	} else {
-		if (errno == EEXIST) {
-			char buf[4096];
-			struct nlmsghdr *nlh = (struct nlmsghdr *) buf;
-
-			int ret = build_network_msg(NFCT_Q_DESTROY,
-						    STATE(subsys_event),
-						    ct,
-						    buf,
-						    sizeof(buf));
-			if (ret == -1)
-				return;
-
-			cache_del(STATE_SYNC(internal), ct);
-			mcast_send_sync(nlh, NULL, ct, NFCT_T_NEW);
-			goto retry;
-		}
-		dlog(STATE(log), "can't add to internal cache: "
-				      "%s\n", strerror(errno));
-		debug_ct(ct, "can't add");
-	}
-}
-
-static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
-{
-	struct us_conntrack *u;
-
-	nfct_attr_unset(ct, ATTR_TIMEOUT);
-
-	if ((u = cache_update(STATE_SYNC(internal), ct)) == NULL) {
-		/*
-		 * Perhaps we are losing events. If we are working 
-		 * in relax mode then add a new entry to the cache.
-		 *
-		 * FIXME: relax transitions not implemented yet
-		 */
-		if ((CONFIG(flags) & RELAX_TRANSITIONS)
-		    && (u = cache_add(STATE_SYNC(internal), ct))) {
-			debug_ct(u->ct, "forcing internal update");
-		} else {
-			debug_ct(ct, "can't update");
-			return;
-		}
-	}
-	debug_ct(u->ct, "internal update");
-	mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE);
-}
-
-static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
-{
-	nfct_attr_unset(ct, ATTR_TIMEOUT);
-
-	if (CONFIG(flags) & DELAY_DESTROY_MSG) {
-
-		nfct_set_attr_u32(ct, ATTR_STATUS, IPS_DYING);
-
-		if (cache_update(STATE_SYNC(internal), ct)) {
-			debug_ct(ct, "delay internal destroy");
-			return 1;
-		} else {
-			debug_ct(ct, "can't delay destroy!");
-			return 0;
-		}
-	} else {
-		if (cache_del(STATE_SYNC(internal), ct)) {
-			mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY);
-			debug_ct(ct, "internal destroy");
-		} else
-			debug_ct(ct, "can't destroy");
-	}
-}
-
-struct ct_mode sync_mode = {
-	.init 			= init_sync,
-	.add_fds_to_set 	= add_fds_to_set_sync,
-	.step			= step_sync,
-	.local			= local_handler_sync,
-	.kill			= kill_sync,
-	.dump			= dump_sync,
-	.overrun		= overrun_sync,
-	.event_new		= event_new_sync,
-	.event_upd		= event_update_sync,
-	.event_dst		= event_destroy_sync
-};
diff --git a/daemon/src/sync-nack.c b/daemon/src/sync-nack.c
deleted file mode 100644
index 288dba4..0000000
--- a/daemon/src/sync-nack.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * (C) 2006-2007 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <errno.h>
-#include "conntrackd.h"
-#include "sync.h"
-#include "linux_list.h"
-#include "us-conntrack.h"
-#include "buffer.h"
-#include "debug.h"
-#include "network.h"
-#include <libnfnetlink/libnfnetlink.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-
-#if 0 
-#define dp printf
-#else
-#define dp
-#endif
-
-static LIST_HEAD(queue);
-
-struct cache_nack {
-	struct list_head 	head;
-	u_int32_t 		seq;
-};
-
-static void cache_nack_add(struct us_conntrack *u, void *data)
-{
-	struct cache_nack *cn = data;
-
-	INIT_LIST_HEAD(&cn->head);
-	list_add(&cn->head, &queue);
-}
-
-static void cache_nack_update(struct us_conntrack *u, void *data)
-{
-	struct cache_nack *cn = data;
-
-	if (cn->head.next != LIST_POISON1 &&
-	    cn->head.prev != LIST_POISON2)
-		list_del(&cn->head);
-
-	INIT_LIST_HEAD(&cn->head);
-	list_add(&cn->head, &queue);
-}
-
-static void cache_nack_destroy(struct us_conntrack *u, void *data)
-{
-	struct cache_nack *cn = data;
-
-	if (cn->head.next != LIST_POISON1 &&
-	    cn->head.prev != LIST_POISON2)
-		list_del(&cn->head);
-}
-
-static struct cache_extra cache_nack_extra = {
-	.size 		= sizeof(struct cache_nack),
-	.add		= cache_nack_add,
-	.update		= cache_nack_update,
-	.destroy	= cache_nack_destroy
-};
-
-static int nack_init()
-{
-	STATE_SYNC(buffer) = buffer_create(CONFIG(resend_buffer_size));
-	if (STATE_SYNC(buffer) == NULL)
-		return -1;
-
-	return 0;
-}
-
-static void nack_kill()
-{
-	buffer_destroy(STATE_SYNC(buffer));
-}
-
-static void mcast_send_nack(u_int32_t expt_seq, u_int32_t recv_seq)
-{
-	struct nlnetwork_ack nack = {
-		.flags = NET_NACK,
-		.from  = expt_seq,
-		.to    = recv_seq,
-	};
-
-	mcast_send_error(STATE_SYNC(mcast_client), &nack);
-	buffer_add(STATE_SYNC(buffer), &nack, sizeof(struct nlnetwork_ack));
-}
-
-static void mcast_send_ack(u_int32_t from, u_int32_t to)
-{
-	struct nlnetwork_ack ack = {
-		.flags = NET_ACK,
-		.from   = from,
-		.to	= to,
-	};
-
-	mcast_send_error(STATE_SYNC(mcast_client), &ack);
-	buffer_add(STATE_SYNC(buffer), &ack, sizeof(struct nlnetwork_ack));
-}
-
-static void mcast_send_resync()
-{
-	struct nlnetwork net = {
-		.flags = NET_RESYNC,
-	};
-
-	mcast_send_error(STATE_SYNC(mcast_client), &net);
-	buffer_add(STATE_SYNC(buffer), &net, sizeof(struct nlnetwork));
-}
-
-int nack_local(int fd, int type, void *data)
-{
-	int ret = 1;
-
-	switch(type) {
-		case REQUEST_DUMP:
-			mcast_send_resync();
-			dlog(STATE(log), "[REQ] request resync");
-			break;
-		default:
-			ret = 0;
-			break;
-	}
-
-	return ret;
-}
-
-static int buffer_compare(void *data1, void *data2)
-{
-	struct nlnetwork *net = data1;
-	struct nlnetwork_ack *nack = data2;
-	struct nlmsghdr *nlh = data1 + sizeof(struct nlnetwork);
-
-	unsigned old_seq = ntohl(net->seq);
-
-	if (ntohl(net->seq) >= nack->from && ntohl(net->seq) <= nack->to) {
-		if (mcast_resend_netmsg(STATE_SYNC(mcast_client), net))
-			dp("resend destroy (old seq=%u) (seq=%u)\n", 
-			   old_seq, ntohl(net->seq));
-	}
-	return 0;
-}
-
-static int buffer_remove(void *data1, void *data2)
-{
-	struct nlnetwork *net = data1;
-	struct nlnetwork_ack *h = data2;
-
-	if (ntohl(net->seq) >= h->from && ntohl(net->seq) <= h->to) {
-		dp("remove from buffer (seq=%u)\n", ntohl(net->seq));
-		__buffer_del(STATE_SYNC(buffer), data1);
-	}
-	return 0;
-}
-
-static void queue_resend(struct cache *c, unsigned int from, unsigned int to)
-{
-	struct list_head *n;
-	struct us_conntrack *u;
-	unsigned int *seq;
-
-	lock();
-	list_for_each(n, &queue) {
-		struct cache_nack *cn = (struct cache_nack *) n;
-		struct us_conntrack *u;
-		
-		u = cache_get_conntrack(STATE_SYNC(internal), cn);
-
-		if (cn->seq >= from && cn->seq <= to) {
-			debug_ct(u->ct, "resend nack");
-			dp("resending nack'ed (oldseq=%u) ", cn->seq);
-
-			char buf[4096];
-			struct nlnetwork *net = (struct nlnetwork *) buf;
-
-			int ret = build_network_msg(NFCT_Q_UPDATE,
-						    STATE(subsys_event),
-						    u->ct,
-						    buf,
-						    sizeof(buf));
-			if (ret == -1) {
-				unlock();
-				break;
-			}
-
-			mcast_send_netmsg(STATE_SYNC(mcast_client), buf); 
-			STATE_SYNC(mcast_sync)->post_send(net, u);
-			dp("(newseq=%u)\n", *seq);
-		} 
-	}
-	unlock();
-}
-
-static void queue_empty(struct cache *c, unsigned int from, unsigned int to)
-{
-	struct list_head *n, *tmp;
-	struct us_conntrack *u;
-	unsigned int *seq;
-
-	lock();
-	dp("ACK from %u to %u\n", from, to);
-	list_for_each_safe(n, tmp, &queue) {
-		struct cache_nack *cn = (struct cache_nack *) n;
-
-		u = cache_get_conntrack(STATE_SYNC(internal), cn);
-		if (cn->seq >= from && cn->seq <= to) {
-			dp("remove %u\n", cn->seq);
-			debug_ct(u->ct, "ack received: empty queue");
-			dp("queue: deleting from queue (seq=%u)\n", cn->seq);
-			list_del(&cn->head);
-		} 
-	}
-	unlock();
-}
-
-static int nack_pre_recv(const struct nlnetwork *net)
-{
-	static unsigned int window = 0;
-	unsigned int exp_seq;
-
-	if (window == 0)
-		window = CONFIG(window_size);
-
-	if (!mcast_track_seq(net->seq, &exp_seq)) {
-		dp("OOS: sending nack (seq=%u)\n", exp_seq);
-		mcast_send_nack(exp_seq, net->seq - 1);
-		window = CONFIG(window_size);
-	} else {
-		/* received a window, send an acknowledgement */
-		if (--window == 0) {
-			dp("sending ack (seq=%u)\n", net->seq);
-			mcast_send_ack(net->seq-CONFIG(window_size), net->seq);
-		}
-	}
-
-	if (net->flags & NET_NACK) {
-		struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net;
-
-		dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to);
-		queue_resend(STATE_SYNC(internal), nack->from, nack->to);
-		buffer_iterate(STATE_SYNC(buffer), nack, buffer_compare);
-		return 1;
-	} else if (net->flags & NET_RESYNC) {
-		dp("RESYNC ALL\n");
-		cache_bulk(STATE_SYNC(internal));
-		return 1;
-	} else if (net->flags & NET_ACK) {
-		struct nlnetwork_ack *h = (struct nlnetwork_ack *) net;
-
-		dp("ACK: from seq=%u to seq=%u\n", h->from, h->to);
-		queue_empty(STATE_SYNC(internal), h->from, h->to);
-		buffer_iterate(STATE_SYNC(buffer), h, buffer_remove);
-		return 1;
-	}
-
-	return 0;
-}
-
-static void nack_post_send(const struct nlnetwork *net, struct us_conntrack *u)
-{
-	unsigned int size = sizeof(struct nlnetwork);
-	struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size);
-
-	if (NFNL_MSG_TYPE(ntohs(nlh->nlmsg_type)) == IPCTNL_MSG_CT_DELETE) {
-		buffer_add(STATE_SYNC(buffer), net, 
-			   ntohl(nlh->nlmsg_len) + size); 
-	} else if (u != NULL) {
-		unsigned int *seq;
-		struct list_head *n;
-		struct cache_nack *cn;
-
-		cn = (struct cache_nack *)
-			cache_get_extra(STATE_SYNC(internal), u);
-		cn->seq = ntohl(net->seq);
-		if (cn->head.next != LIST_POISON1 &&
-		    cn->head.prev != LIST_POISON2)
-		    	list_del(&cn->head);
-
-		INIT_LIST_HEAD(&cn->head);
-		list_add(&cn->head, &queue);
-	}
-}
-
-struct sync_mode nack = {
-	.internal_cache_flags	= LIFETIME,
-	.external_cache_flags	= LIFETIME,
-	.internal_cache_extra	= &cache_nack_extra,
-	.init			= nack_init,
-	.kill			= nack_kill,
-	.local			= nack_local,
-	.pre_recv		= nack_pre_recv,
-	.post_send		= nack_post_send,
-};
diff --git a/daemon/src/sync-notrack.c b/daemon/src/sync-notrack.c
deleted file mode 100644
index 2b5ae38..0000000
--- a/daemon/src/sync-notrack.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * (C) 2006-2007 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "conntrackd.h"
-#include "sync.h"
-#include "network.h"
-#include "us-conntrack.h"
-#include "alarm.h"
-
-static void refresher(struct alarm_list *a, void *data)
-{
-	struct us_conntrack *u = data;
-	char buf[8192];
-	int size;
-
-	if (nfct_get_attr_u32(u->ct, ATTR_STATUS) & IPS_DYING) {
-		
-		debug_ct(u->ct, "persistence destroy");
-
-		size = build_network_msg(NFCT_Q_DESTROY,
-					 STATE(subsys_event),
-					 u->ct,
-					 buf,
-					 sizeof(buf));
-
-		__cache_del(u->cache, u->ct);
-		mcast_send_netmsg(STATE_SYNC(mcast_client), buf);
-	} else {
-		
-		debug_ct(u->ct, "persistence update");
-
-		a->expires = random() % CONFIG(refresh) + 1;
-		size = build_network_msg(NFCT_Q_UPDATE,
-					 STATE(subsys_event),
-					 u->ct,
-					 buf, 
-					 sizeof(buf));
-		mcast_send_netmsg(STATE_SYNC(mcast_client), buf);
-	}
-}
-
-static void cache_notrack_add(struct us_conntrack *u, void *data)
-{
-	struct alarm_list *alarm = data;
-
-	init_alarm(alarm);
-	set_alarm_expiration(alarm, (random() % conf.refresh) + 1);
-	set_alarm_data(alarm, u);
-	set_alarm_function(alarm, refresher);
-	add_alarm(alarm);
-}
-
-static void cache_notrack_update(struct us_conntrack *u, void *data)
-{
-	struct alarm_list *alarm = data;
-	mod_alarm(alarm, (random() % conf.refresh) + 1);
-}
-
-static void cache_notrack_destroy(struct us_conntrack *u, void *data)
-{
-	struct alarm_list *alarm = data;
-	del_alarm(alarm);
-}
-
-static struct cache_extra cache_notrack_extra = {
-	.size 		= sizeof(struct alarm_list),
-	.add		= cache_notrack_add,
-	.update		= cache_notrack_update,
-	.destroy	= cache_notrack_destroy
-};
-
-static int notrack_pre_recv(const struct nlnetwork *net)
-{
-	unsigned int exp_seq;
-
-	/* 
-	 * Ignore error messages: Although this message type is not ever
-	 * generated in notrack mode, we don't want to crash the daemon 
-	 * if someone nuts mixes nack and notrack.
-	 */
-	if (net->flags & (NET_RESYNC | NET_NACK))
-		return 1;
-
-	/* 
-	 * Multicast sequence tracking: we keep track of multicast messages
-	 * although we don't do any explicit message recovery. So, why do
-	 * we do sequence tracking? Just to let know the sysadmin.
-	 *
-	 * Let t be 1 < t < RefreshTime. To ensure consistency, conntrackd
-	 * retransmit every t seconds a message with the state of a certain
-	 * entry even if such entry did not change. This mechanism also
-	 * provides passive resynchronization, in other words, there is
-	 * no facility to request a full synchronization from new nodes that
-	 * just joined the cluster, instead they just get resynchronized in
-	 * RefreshTime seconds at worst case.
-	 */
-	mcast_track_seq(net->seq, &exp_seq);
-
-	return 0;
-}
-
-static void notrack_post_send(const struct nlnetwork *n, struct us_conntrack *u)
-{
-}
-
-struct sync_mode notrack = {
-	.internal_cache_flags	= LIFETIME,
-	.external_cache_flags	= TIMER | LIFETIME,
-	.internal_cache_extra	= &cache_notrack_extra,
-	.pre_recv 		= notrack_pre_recv,
-	.post_send		= notrack_post_send,
-};
diff --git a/daemon/src/traffic_stats.c b/daemon/src/traffic_stats.c
deleted file mode 100644
index b510b77..0000000
--- a/daemon/src/traffic_stats.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * (C) 2006 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "cache.h"
-#include "hash.h"
-#include "conntrackd.h"
-#include <libnfnetlink/libnfnetlink.h>
-#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#include <errno.h>
-#include "us-conntrack.h"
-#include <signal.h>
-
-void update_traffic_stats(struct nf_conntrack *ct)
-{
-	STATE(bytes)[NFCT_DIR_ORIGINAL] +=
-		nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_BYTES);
-	STATE(bytes)[NFCT_DIR_REPLY] +=
-		nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_BYTES);
-	STATE(packets)[NFCT_DIR_ORIGINAL] += 
-		nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_PACKETS);
-	STATE(packets)[NFCT_DIR_REPLY] +=
-		nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_PACKETS);
-}
-
-void dump_traffic_stats(int fd)
-{
-	char buf[512];
-	int size;
-	u_int64_t bytes = STATE(bytes)[NFCT_DIR_ORIGINAL] +
-			  STATE(bytes)[NFCT_DIR_REPLY];
-	u_int64_t packets = STATE(packets)[NFCT_DIR_ORIGINAL] +
-			    STATE(packets)[NFCT_DIR_REPLY];
-
-	size = sprintf(buf, "traffic processed:\n");
-	size += sprintf(buf+size, "%20llu Bytes      ", bytes);
-	size += sprintf(buf+size, "%20llu Pckts\n\n", packets);
-
-	send(fd, buf, size, 0);
-}
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..be83d42
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = stats sync 
diff --git a/examples/debian.conntrackd.init.d b/examples/debian.conntrackd.init.d
new file mode 100644
index 0000000..ba847dd
--- /dev/null
+++ b/examples/debian.conntrackd.init.d
@@ -0,0 +1,48 @@
+#!/bin/sh
+#
+# /etc/init.d/conntrackd
+#
+# Maximilian Wilhelm <max@rfc2324.org>
+#  -- Mon, 06 Nov 2006 18:39:07 +0100
+#
+
+export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+
+NAME="conntrackd"
+DAEMON=`command -v conntrackd`
+CONFIG="/etc/conntrack/conntrackd.conf"
+PIDFILE="/var/run/${NAME}.pid"
+
+
+# Gracefully exit if there is no daemon (debian way of life)
+if [ ! -x "${DAEMON}" ]; then
+	exit 0
+fi
+
+# Check for config file
+if [ ! -f /etc/conntrackd/conntrackd.conf ]; then
+	echo "Error: There is no config file for $NAME" >&2
+	exit 1;
+fi
+
+case "$1" in
+  start)
+        echo -n "Starting $NAME: "
+	start-stop-daemon --start --quiet --make-pidfile --pidfile "/var/run/${NAME}.pid" --background --exec "${DAEMON}"  && echo "done." || echo "FAILED!"
+	;;
+  stop)
+        echo -n "Stopping $NAME:"
+	start-stop-daemon --stop --quiet --oknodo --pidfile "/var/run/${NAME}.pid" && echo "done." || echo "FAILED!"
+	;;
+
+  restart)
+	$0 start
+	$0 stop
+	;;
+
+  *)
+	echo "Usage: /etc/init.d/conntrackd {start|stop|restart}"
+	exit 1
+esac
+
+exit 0
diff --git a/examples/stats/Makefile.am b/examples/stats/Makefile.am
new file mode 100644
index 0000000..b43c3b8
--- /dev/null
+++ b/examples/stats/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = conntrackd.conf 
diff --git a/examples/stats/conntrackd.conf b/examples/stats/conntrackd.conf
new file mode 100644
index 0000000..e514ac0
--- /dev/null
+++ b/examples/stats/conntrackd.conf
@@ -0,0 +1,69 @@
+#
+# General settings
+#
+General {
+	#
+	# Number of buckets in the caches: hash table
+	#
+	HashSize 8192
+
+	#
+	# Maximum number of conntracks: 
+	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
+	#
+	HashLimit 65535
+
+	#
+	# Logfile
+	#
+	LogFile /var/log/conntrackd.log
+
+	#
+	# Lockfile
+	# 
+	LockFile /var/lock/conntrack.lock
+
+	#
+	# Unix socket configuration
+	#
+	UNIX {
+		Path /tmp/sync.sock
+		Backlog 20
+	}
+
+	#
+	# Netlink socket buffer size
+	#
+	SocketBufferSize 262142
+
+	#
+	# Increase the socket buffer up to maximun if required
+	#
+	SocketBufferSizeMaxGrown 655355
+}
+
+#
+# Ignore traffic for a certain set of IP's: Usually
+# all the IP assigned to the firewall since local
+# traffic must be ignored, just forwarded connections
+# are worth to replicate
+#
+IgnoreTrafficFor {
+	IPv4_address 127.0.0.1 # loopback
+}
+
+#
+# Do not replicate certain protocol traffic 
+#
+IgnoreProtocol {
+	UDP
+#	ICMP
+#	IGMP
+#	VRRP
+	# numeric numbers also valid
+}
+
+#
+# Strip NAT traffic
+#
+StripNAT
diff --git a/examples/sync/Makefile.am b/examples/sync/Makefile.am
new file mode 100644
index 0000000..28e7643
--- /dev/null
+++ b/examples/sync/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = persistent nack
diff --git a/examples/sync/nack/Makefile.am b/examples/sync/nack/Makefile.am
new file mode 100644
index 0000000..6fd99b1
--- /dev/null
+++ b/examples/sync/nack/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = script_backup.sh script_master.sh 
+SUBDIRS = node1 node2
diff --git a/examples/sync/nack/README b/examples/sync/nack/README
new file mode 100644
index 0000000..66987f7
--- /dev/null
+++ b/examples/sync/nack/README
@@ -0,0 +1 @@
+This directory contains the files for the NACK based protocol
diff --git a/examples/sync/nack/node1/Makefile.am b/examples/sync/nack/node1/Makefile.am
new file mode 100644
index 0000000..edc0ed7
--- /dev/null
+++ b/examples/sync/nack/node1/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = conntrackd.conf keepalived.conf 
diff --git a/examples/sync/nack/node1/conntrackd.conf b/examples/sync/nack/node1/conntrackd.conf
new file mode 100644
index 0000000..f24fa7e
--- /dev/null
+++ b/examples/sync/nack/node1/conntrackd.conf
@@ -0,0 +1,125 @@
+#
+# Synchronizer settings
+#
+Sync {
+	Mode NACK {
+		#
+		# Size of the buffer that hold destroy messages for 
+		# possible resends (in bytes)
+		#
+		ResendBufferSize 262144
+
+		#
+		# Entries committed to the connection tracking table 
+		# starts with a limited timeout of N seconds until the
+		# takeover process is completed.
+		#
+		CommitTimeout 180
+
+		# Set Acknowledgement window size
+		ACKWindowSize 20
+	}
+
+	#
+	# Multicast IP and interface where messages are
+	# broadcasted (dedicated link). IMPORTANT: Make sure
+	# that iptables accepts traffic for destination
+	# 225.0.0.50, eg:
+	#
+	#	iptables -I INPUT -d 225.0.0.50 -j ACCEPT
+	#	iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT
+	#
+	Multicast {
+		IPv4_address 225.0.0.50
+		IPv4_interface 192.168.100.100 # IP of dedicated link
+		Group 3780
+		Backlog 20
+	}
+
+	# Enable/Disable message checksumming
+	Checksum on
+
+	# Uncomment this if you want to replicate just certain TCP states.
+	# This option introduces a tradeoff in the replication: it reduces
+	# CPU consumption and lost messages rate at the cost of having 
+	# backup replicas that don't contain the current state that the active 
+	# replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED,
+	# FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN.
+	# 
+	# Replicate ESTABLISHED TIME_WAIT for TCP
+}
+
+#
+# General settings
+#
+General {
+	#
+	# Number of buckets in the caches: hash table
+	#
+	HashSize 8192
+
+	#
+	# Maximum number of conntracks: 
+	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
+	#
+	HashLimit 65535
+
+	#
+	# Logfile
+	#
+	LogFile /var/log/conntrackd.log
+
+	#
+	# Lockfile
+	# 
+	LockFile /var/lock/conntrack.lock
+
+	#
+	# Unix socket configuration
+	#
+	UNIX {
+		Path /tmp/sync.sock
+		Backlog 20
+	}
+
+	#
+	# Netlink socket buffer size
+	#
+	SocketBufferSize 262142
+
+	#
+	# Increase the socket buffer up to maximum if required
+	#
+	SocketBufferSizeMaxGrown 655355
+}
+
+#
+# Ignore traffic for a certain set of IP's: Usually
+# all the IP assigned to the firewall since local
+# traffic must be ignored, just forwarded connections
+# are worth to replicate
+#
+IgnoreTrafficFor {
+	IPv4_address 127.0.0.1 # loopback
+	IPv4_address 192.168.0.1
+	IPv4_address 192.168.1.1
+	IPv4_address 192.168.100.100 # dedicated link ip
+	IPv4_address 192.168.0.100 # virtual IP 1
+	IPv4_address 192.168.1.100 # virtual IP 2
+}
+
+#
+# Do not replicate certain protocol traffic 
+#
+IgnoreProtocol {
+	UDP
+	ICMP
+	IGMP
+	VRRP
+	# numeric numbers also valid
+}
+
+#
+# Strip NAT traffic
+#
+StripNAT
diff --git a/examples/sync/nack/node1/keepalived.conf b/examples/sync/nack/node1/keepalived.conf
new file mode 100644
index 0000000..41aa35b
--- /dev/null
+++ b/examples/sync/nack/node1/keepalived.conf
@@ -0,0 +1,38 @@
+vrrp_sync_group G1 {   # must be before vrrp_instance declaration
+  group {
+    VI_1
+    VI_2
+  }
+  notify_master /etc/conntrackd/script_master.sh
+  notify_backup /etc/conntrackd/script_backup.sh
+}
+
+vrrp_instance VI_1 {
+    interface eth1
+    state SLAVE
+    virtual_router_id 61
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.0.100   # default CIDR mask is /32
+    }
+}
+
+vrrp_instance VI_2 {
+    interface eth0
+    state SLAVE
+    virtual_router_id 62
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.1.100
+    }
+}
diff --git a/examples/sync/nack/node2/Makefile.am b/examples/sync/nack/node2/Makefile.am
new file mode 100644
index 0000000..edc0ed7
--- /dev/null
+++ b/examples/sync/nack/node2/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = conntrackd.conf keepalived.conf 
diff --git a/examples/sync/nack/node2/conntrackd.conf b/examples/sync/nack/node2/conntrackd.conf
new file mode 100644
index 0000000..4f15773
--- /dev/null
+++ b/examples/sync/nack/node2/conntrackd.conf
@@ -0,0 +1,124 @@
+#
+# Synchronizer settings
+#
+Sync {
+	Mode NACK {
+                #
+		# Size of the buffer that hold destroy messages for 
+		# possible resends (in bytes)
+		#
+		ResendBufferSize 262144
+
+		# Entries committed to the connection tracking table 
+		# starts with a limited timeout of N seconds until the
+		# takeover process is completed.
+		#
+		CommitTimeout 180
+
+		# Set Acknowledgement window size
+		ACKWindowSize 20
+	}
+
+	#
+	# Multicast IP and interface where messages are
+	# broadcasted (dedicated link). IMPORTANT: Make sure
+	# that iptables accepts traffic for destination
+	# 225.0.0.50, eg:
+	#
+	#	iptables -I INPUT -d 225.0.0.50 -j ACCEPT
+	#	iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT
+	#
+	Multicast {
+		IPv4_address 225.0.0.50
+		IPv4_interface 192.168.100.200 # IP of dedicated link
+		Group 3780
+		Backlog 20
+	}
+
+	# Enable/Disable message checksumming
+	Checksum on
+
+	# Uncomment this if you want to replicate just certain TCP states.
+	# This option introduces a tradeoff in the replication: it reduces
+	# CPU consumption and lost messages rate at the cost of having 
+	# backup replicas that don't contain the current state that the active 
+	# replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED,
+	# FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN.
+	# 
+	# Replicate ESTABLISHED TIME_WAIT for TCP
+}
+
+#
+# General settings
+#
+General {
+	#
+	# Number of buckets in the caches: hash table
+	#
+	HashSize 8192
+
+	#
+	# Maximum number of conntracks: 
+	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
+	#
+	HashLimit 65535
+
+	#
+	# Logfile
+	#
+	LogFile /var/log/conntrackd.log
+
+	#
+	# Lockfile
+	# 
+	LockFile /var/lock/conntrack.lock
+
+	#
+	# Unix socket configuration
+	#
+	UNIX {
+		Path /tmp/sync.sock
+		Backlog 20
+	}
+
+	#
+	# Netlink socket buffer size
+	#
+	SocketBufferSize 262142
+
+	#
+	# Increase the socket buffer up to maximum if required
+	#
+	SocketBufferSizeMaxGrown 655355
+}
+
+#
+# Ignore traffic for a certain set of IP's: Usually
+# all the IP assigned to the firewall since local
+# traffic must be ignored, just forwarded connections
+# are worth to replicate
+#
+IgnoreTrafficFor {
+	IPv4_address 127.0.0.1 # loopback
+	IPv4_address 192.168.0.2
+	IPv4_address 192.168.1.2
+	IPv4_address 192.168.100.200 # dedicated link ip
+	IPv4_address 192.168.0.200 # virtual IP 1
+	IPv4_address 192.168.1.200 # virtual IP 2
+}
+
+#
+# Do not replicate certain protocol traffic 
+#
+IgnoreProtocol {
+	UDP
+	ICMP
+	IGMP
+	VRRP
+	# numeric numbers also valid
+}
+
+#
+# Strip NAT traffic
+#
+StripNAT
diff --git a/examples/sync/nack/node2/keepalived.conf b/examples/sync/nack/node2/keepalived.conf
new file mode 100644
index 0000000..41aa35b
--- /dev/null
+++ b/examples/sync/nack/node2/keepalived.conf
@@ -0,0 +1,38 @@
+vrrp_sync_group G1 {   # must be before vrrp_instance declaration
+  group {
+    VI_1
+    VI_2
+  }
+  notify_master /etc/conntrackd/script_master.sh
+  notify_backup /etc/conntrackd/script_backup.sh
+}
+
+vrrp_instance VI_1 {
+    interface eth1
+    state SLAVE
+    virtual_router_id 61
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.0.100   # default CIDR mask is /32
+    }
+}
+
+vrrp_instance VI_2 {
+    interface eth0
+    state SLAVE
+    virtual_router_id 62
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.1.100
+    }
+}
diff --git a/examples/sync/nack/script_backup.sh b/examples/sync/nack/script_backup.sh
new file mode 100755
index 0000000..813e375
--- /dev/null
+++ b/examples/sync/nack/script_backup.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+/usr/sbin/conntrackd -n # request a resync from other nodes via multicast
diff --git a/examples/sync/nack/script_master.sh b/examples/sync/nack/script_master.sh
new file mode 100755
index 0000000..ff1dbc0
--- /dev/null
+++ b/examples/sync/nack/script_master.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+/usr/sbin/conntrackd -c # commit the cache
+/usr/sbin/conntrackd -f # flush the caches
+/usr/sbin/conntrackd -R # resync with kernel conntrack table
diff --git a/examples/sync/persistent/Makefile.am b/examples/sync/persistent/Makefile.am
new file mode 100644
index 0000000..6fd99b1
--- /dev/null
+++ b/examples/sync/persistent/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = script_backup.sh script_master.sh 
+SUBDIRS = node1 node2
diff --git a/examples/sync/persistent/README b/examples/sync/persistent/README
new file mode 100644
index 0000000..36b5989
--- /dev/null
+++ b/examples/sync/persistent/README
@@ -0,0 +1 @@
+This directory contains the files for the PERSISTENT based protocol
diff --git a/examples/sync/persistent/node1/Makefile.am b/examples/sync/persistent/node1/Makefile.am
new file mode 100644
index 0000000..edc0ed7
--- /dev/null
+++ b/examples/sync/persistent/node1/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = conntrackd.conf keepalived.conf 
diff --git a/examples/sync/persistent/node1/conntrackd.conf b/examples/sync/persistent/node1/conntrackd.conf
new file mode 100644
index 0000000..90afeb7
--- /dev/null
+++ b/examples/sync/persistent/node1/conntrackd.conf
@@ -0,0 +1,130 @@
+#
+# Synchronizer settings
+#
+Sync {
+	Mode PERSISTENT {
+		#
+		# If a conntrack entry is not modified in <= 15 seconds, then
+		# a message is broadcasted. This mechanism is used to
+		# resynchronize nodes that just joined the multicast group
+		#
+		RefreshTime 15
+	
+		#
+		# If we don't receive a notification about the state of 
+		# an entry in the external cache after N seconds, then
+		# remove it.
+		#
+		CacheTimeout 180
+
+		#
+		# Entries committed to the connection tracking table 
+		# starts with a limited timeout of N seconds until the
+		# takeover process is completed.
+		#
+		CommitTimeout 180
+	}
+
+	#
+	# Multicast IP and interface where messages are
+	# broadcasted (dedicated link). IMPORTANT: Make sure
+	# that iptables accepts traffic for destination
+	# 225.0.0.50, eg:
+	#
+	#	iptables -I INPUT -d 225.0.0.50 -j ACCEPT
+	#	iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT
+	#
+	Multicast {
+		IPv4_address 225.0.0.50
+		IPv4_interface 192.168.100.100 # IP of dedicated link
+		Group 3780
+		Backlog 20
+	}
+
+	# Enable/Disable message checksumming
+	Checksum on
+
+	# Uncomment this if you want to replicate just certain TCP states.
+	# This option introduces a tradeoff in the replication: it reduces
+	# CPU consumption and lost messages rate at the cost of having 
+	# backup replicas that don't contain the current state that the active 
+	# replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED,
+	# FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN.
+	# 
+	# Replicate ESTABLISHED TIME_WAIT for TCP
+}
+
+#
+# General settings
+#
+General {
+	#
+	# Number of buckets in the caches: hash table
+	#
+	HashSize 8192
+
+	#
+	# Maximum number of conntracks: 
+	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
+	#
+	HashLimit 65535
+
+	#
+	# Logfile
+	#
+	LogFile /var/log/conntrackd.log
+
+	#
+	# Lockfile
+	# 
+	LockFile /var/lock/conntrack.lock
+
+	#
+	# Unix socket configuration
+	#
+	UNIX {
+		Path /tmp/sync.sock
+		Backlog 20
+	}
+
+	#
+	# Netlink socket buffer size
+	#
+	SocketBufferSize 262142
+
+	#
+	# Increase the socket buffer up to maximum if required
+	#
+	SocketBufferSizeMaxGrown 655355
+}
+
+#
+# Ignore traffic for a certain set of IP's: Usually
+# all the IP assigned to the firewall since local
+# traffic must be ignored, just forwarded connections
+# are worth to replicate
+#
+IgnoreTrafficFor {
+	IPv4_address 127.0.0.1 # loopback
+	IPv4_address 192.168.0.1
+	IPv4_address 192.168.1.1
+	IPv4_address 192.168.100.100 # dedicated link ip
+	IPv4_address 192.168.0.100 # virtual IP 1
+	IPv4_address 192.168.1.100 # virtual IP 2
+}
+
+#
+# Do not replicate certain protocol traffic 
+#
+IgnoreProtocol {
+	UDP
+	ICMP
+	IGMP
+	VRRP
+	# numeric numbers also valid
+}
+
+#
+# Strip NAT traffic
+#
+StripNAT
diff --git a/examples/sync/persistent/node1/keepalived.conf b/examples/sync/persistent/node1/keepalived.conf
new file mode 100644
index 0000000..41aa35b
--- /dev/null
+++ b/examples/sync/persistent/node1/keepalived.conf
@@ -0,0 +1,38 @@
+vrrp_sync_group G1 {   # must be before vrrp_instance declaration
+  group {
+    VI_1
+    VI_2
+  }
+  notify_master /etc/conntrackd/script_master.sh
+  notify_backup /etc/conntrackd/script_backup.sh
+}
+
+vrrp_instance VI_1 {
+    interface eth1
+    state SLAVE
+    virtual_router_id 61
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.0.100   # default CIDR mask is /32
+    }
+}
+
+vrrp_instance VI_2 {
+    interface eth0
+    state SLAVE
+    virtual_router_id 62
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.1.100
+    }
+}
diff --git a/examples/sync/persistent/node2/Makefile.am b/examples/sync/persistent/node2/Makefile.am
new file mode 100644
index 0000000..edc0ed7
--- /dev/null
+++ b/examples/sync/persistent/node2/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = conntrackd.conf keepalived.conf 
diff --git a/examples/sync/persistent/node2/conntrackd.conf b/examples/sync/persistent/node2/conntrackd.conf
new file mode 100644
index 0000000..aee4a29
--- /dev/null
+++ b/examples/sync/persistent/node2/conntrackd.conf
@@ -0,0 +1,130 @@
+#
+# Synchronizer settings
+#
+Sync {
+	Mode PERSISTENT {
+		#
+		# If a conntrack entry is not modified in <= 15 seconds, then
+		# a message is broadcasted. This mechanism is used to
+		# resynchronize nodes that just joined the multicast group
+		#
+		RefreshTime 15
+	
+		#
+		# If we don't receive a notification about the state of 
+		# an entry in the external cache after N seconds, then
+		# remove it.
+		#
+		CacheTimeout 180
+
+		#
+		# Entries committed to the connection tracking table 
+		# starts with a limited timeout of N seconds until the
+		# takeover process is completed.
+		#
+		CommitTimeout 180
+	}
+
+	#
+	# Multicast IP and interface where messages are
+	# broadcasted (dedicated link). IMPORTANT: Make sure
+	# that iptables accepts traffic for destination
+	# 225.0.0.50, eg:
+	#
+	#	iptables -I INPUT -d 225.0.0.50 -j ACCEPT
+	#	iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT
+	#
+	Multicast {
+		IPv4_address 225.0.0.50
+		IPv4_interface 192.168.100.200 # IP of dedicated link
+		Group 3780
+		Backlog 20
+	}
+
+	# Enable/Disable message checksumming
+	Checksum on
+
+	# Uncomment this if you want to replicate just certain TCP states.
+	# This option introduces a tradeoff in the replication: it reduces
+	# CPU consumption and lost messages rate at the cost of having 
+	# backup replicas that don't contain the current state that the active 
+	# replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED,
+	# FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN.
+	# 
+	# Replicate ESTABLISHED TIME_WAIT for TCP
+}
+
+#
+# General settings
+#
+General {
+	#
+	# Number of buckets in the caches: hash table
+	#
+	HashSize 8192
+
+	#
+	# Maximum number of conntracks: 
+	# it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max
+	#
+	HashLimit 65535
+
+	#
+	# Logfile
+	#
+	LogFile /var/log/conntrackd.log
+
+	#
+	# Lockfile
+	# 
+	LockFile /var/lock/conntrack.lock
+
+	#
+	# Unix socket configuration
+	#
+	UNIX {
+		Path /tmp/sync.sock
+		Backlog 20
+	}
+
+	#
+	# Netlink socket buffer size
+	#
+	SocketBufferSize 262142
+
+	#
+	# Increase the socket buffer up to maximum if required
+	#
+	SocketBufferSizeMaxGrown 655355
+}
+
+#
+# Ignore traffic for a certain set of IP's: Usually
+# all the IP assigned to the firewall since local
+# traffic must be ignored, just forwarded connections
+# are worth to replicate
+#
+IgnoreTrafficFor {
+	IPv4_address 127.0.0.1 # loopback
+	IPv4_address 192.168.0.2
+	IPv4_address 192.168.1.2
+	IPv4_address 192.168.100.200 # dedicated link ip
+	IPv4_address 192.168.0.200 # virtual IP 1
+	IPv4_address 192.168.1.200 # virtual IP 2
+}
+
+#
+# Do not replicate certain protocol traffic 
+#
+IgnoreProtocol {
+	UDP
+	ICMP
+	IGMP
+	VRRP
+	# numeric numbers also valid
+}
+
+#
+# Strip NAT traffic
+#
+StripNAT
diff --git a/examples/sync/persistent/node2/keepalived.conf b/examples/sync/persistent/node2/keepalived.conf
new file mode 100644
index 0000000..41aa35b
--- /dev/null
+++ b/examples/sync/persistent/node2/keepalived.conf
@@ -0,0 +1,38 @@
+vrrp_sync_group G1 {   # must be before vrrp_instance declaration
+  group {
+    VI_1
+    VI_2
+  }
+  notify_master /etc/conntrackd/script_master.sh
+  notify_backup /etc/conntrackd/script_backup.sh
+}
+
+vrrp_instance VI_1 {
+    interface eth1
+    state SLAVE
+    virtual_router_id 61
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.0.100   # default CIDR mask is /32
+    }
+}
+
+vrrp_instance VI_2 {
+    interface eth0
+    state SLAVE
+    virtual_router_id 62
+    priority 80
+    advert_int 3
+    authentication {
+      auth_type PASS
+      auth_pass papas_con_tomate
+    }
+    virtual_ipaddress {
+        192.168.1.100
+    }
+}
diff --git a/examples/sync/persistent/script_backup.sh b/examples/sync/persistent/script_backup.sh
new file mode 100755
index 0000000..8ea2ad8
--- /dev/null
+++ b/examples/sync/persistent/script_backup.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+/usr/sbin/conntrackd -B
diff --git a/examples/sync/persistent/script_master.sh b/examples/sync/persistent/script_master.sh
new file mode 100755
index 0000000..70c26c9
--- /dev/null
+++ b/examples/sync/persistent/script_master.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+/usr/sbin/conntrackd -c
+/usr/sbin/conntrackd -R
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
new file mode 100644
index 0000000..5366ee3
--- /dev/null
+++ b/extensions/Makefile.am
@@ -0,0 +1,16 @@
+include $(top_srcdir)/Make_global.am
+
+AM_CFLAGS=-fPIC -Wall
+LIBS=
+
+pkglib_LTLIBRARIES = ct_proto_tcp.la ct_proto_udp.la		\
+		     ct_proto_icmp.la ct_proto_sctp.la
+
+ct_proto_tcp_la_SOURCES = libct_proto_tcp.c
+ct_proto_tcp_la_LDFLAGS = -module -avoid-version
+ct_proto_udp_la_SOURCES = libct_proto_udp.c
+ct_proto_udp_la_LDFLAGS = -module -avoid-version
+ct_proto_icmp_la_SOURCES = libct_proto_icmp.c
+ct_proto_icmp_la_LDFLAGS = -module -avoid-version
+ct_proto_sctp_la_SOURCES = libct_proto_sctp.c
+ct_proto_sctp_la_LDFLAGS = -module -avoid-version
diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c
new file mode 100644
index 0000000..e7cb04d
--- /dev/null
+++ b/extensions/libct_proto_icmp.c
@@ -0,0 +1,108 @@
+/*
+ * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
+ *	       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 <stdlib.h>
+#include <netinet/in.h> /* For htons */
+#include <netinet/ip_icmp.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_icmp.h>
+#include "conntrack.h"
+
+static struct option opts[] = {
+	{"icmp-type", 1, 0, '1'},
+	{"icmp-code", 1, 0, '2'},
+	{"icmp-id", 1, 0, '3'},
+	{0, 0, 0, 0}
+};
+
+static void help()
+{
+	fprintf(stdout, "--icmp-type            icmp type\n");
+	fprintf(stdout, "--icmp-code            icmp code\n");
+	fprintf(stdout, "--icmp-id              icmp id\n");
+}
+
+/* Add 1; spaces filled with 0. */
+static u_int8_t invmap[]
+	= { [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
+	    [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
+	    [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
+	    [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
+	    [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
+	    [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
+	    [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
+	    [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1};
+
+static int parse(char c, char *argv[], 
+		 struct nfct_tuple *orig,
+		 struct nfct_tuple *reply,
+		 struct nfct_tuple *exptuple,
+		 struct nfct_tuple *mask,
+		 union nfct_protoinfo *proto,
+		 unsigned int *flags)
+{
+	switch(c) {
+		case '1':
+			if (optarg) {
+				orig->l4dst.icmp.type = atoi(optarg);
+				reply->l4dst.icmp.type =
+					invmap[orig->l4dst.icmp.type] - 1;
+				*flags |= ICMP_TYPE;
+			}
+			break;
+		case '2':
+			if (optarg) {
+				orig->l4dst.icmp.code = atoi(optarg);
+				reply->l4dst.icmp.code = 0;
+				*flags |= ICMP_CODE;
+			}
+			break;
+		case '3':
+			if (optarg) {
+				orig->l4src.icmp.id = htons(atoi(optarg));
+				reply->l4dst.icmp.id = 0;
+				*flags |= ICMP_ID;
+			}
+			break;
+	}
+	return 1;
+}
+
+static int final_check(unsigned int flags,
+		       unsigned int command,
+		       struct nfct_tuple *orig,
+		       struct nfct_tuple *reply)
+{
+	if (!(flags & ICMP_TYPE))
+		return 0;
+	else if (!(flags & ICMP_CODE))
+		return 0;
+
+	return 1;
+}
+
+static struct ctproto_handler icmp = {
+	.name 		= "icmp",
+	.protonum	= IPPROTO_ICMP,
+	.parse_opts	= parse,
+	.final_check	= final_check,
+	.help		= help,
+	.opts		= opts,
+	.version	= VERSION,
+};
+
+static void __attribute__ ((constructor)) init(void);
+
+static void init(void)
+{
+	register_proto(&icmp);
+}
diff --git a/extensions/libct_proto_icmp.man b/extensions/libct_proto_icmp.man
new file mode 100644
index 0000000..3b860d0
--- /dev/null
+++ b/extensions/libct_proto_icmp.man
@@ -0,0 +1,10 @@
+This module matches on ICMP-specific fields.
+.TP
+.BI "--icmp-type " "TYPE"
+ICMP Type. Has to be specified numerically.
+.TP
+.BI "--icmp-code " "CODE"
+ICMP Code. Has to be specified numerically.
+.TP
+.BI "--icmp-id " "ID"
+ICMP Id. Has to be specified numerically.
diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c
new file mode 100644
index 0000000..1c8f0d1
--- /dev/null
+++ b/extensions/libct_proto_sctp.c
@@ -0,0 +1,164 @@
+/*
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ *     2006 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 "conntrack.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_sctp.h>
+
+static struct option opts[] = {
+	{"orig-port-src", 1, 0, '1'},
+	{"orig-port-dst", 1, 0, '2'},
+	{"reply-port-src", 1, 0, '3'},
+	{"reply-port-dst", 1, 0, '4'},
+	{"state", 1, 0, '5'},
+	{"tuple-port-src", 1, 0, '6'},
+	{"tuple-port-dst", 1, 0, '7'},
+	{0, 0, 0, 0}
+};
+
+static const char *states[] = {
+	"NONE",
+	"CLOSED",
+	"COOKIE_WAIT",
+	"COOKIE_ECHOED",
+	"ESTABLISHED",
+	"SHUTDOWN_SENT",
+	"SHUTDOWN_RECV",
+	"SHUTDOWN_ACK_SENT",
+};
+
+static void help()
+{
+	fprintf(stdout, "--orig-port-src        original source port\n");
+	fprintf(stdout, "--orig-port-dst        original destination port\n");
+	fprintf(stdout, "--reply-port-src       reply source port\n");
+	fprintf(stdout, "--reply-port-dst       reply destination port\n");
+	fprintf(stdout, "--state                SCTP state, fe. ESTABLISHED\n");
+	fprintf(stdout, "--tuple-port-src	expectation tuple src port\n");
+	fprintf(stdout, "--tuple-port-src	expectation tuple dst port\n");
+}
+
+static int parse_options(char c, char *argv[], 
+			 struct nfct_tuple *orig,
+			 struct nfct_tuple *reply,
+			 struct nfct_tuple *exptuple,
+			 struct nfct_tuple *mask,
+			 union nfct_protoinfo *proto,
+			 unsigned int *flags)
+{
+	switch(c) {
+		case '1':
+			if (optarg) {
+				orig->l4src.sctp.port = htons(atoi(optarg));
+				*flags |= SCTP_ORIG_SPORT;
+			}
+			break;
+		case '2':
+			if (optarg) {
+				orig->l4dst.sctp.port = htons(atoi(optarg));
+				*flags |= SCTP_ORIG_DPORT;
+			}
+			break;
+		case '3':
+			if (optarg) {
+				reply->l4src.sctp.port = htons(atoi(optarg));
+				*flags |= SCTP_REPL_SPORT;
+			}
+			break;
+		case '4':
+			if (optarg) {
+				reply->l4dst.sctp.port = htons(atoi(optarg));
+				*flags |= SCTP_REPL_DPORT;
+			}
+			break;
+		case '5':
+			if (optarg) {
+				int i;
+				for (i=0; i<10; i++) {
+					if (strcmp(optarg, states[i]) == 0) {
+						/* FIXME: Add state to
+						 * nfct_protoinfo
+						proto->sctp.state = i; */
+						break;
+					}
+				}
+				if (i == 10) {
+					printf("doh?\n");
+					return 0;
+				}
+				*flags |= SCTP_STATE;
+			}
+			break;
+		case '6':
+			if (optarg) {
+				exptuple->l4src.sctp.port = htons(atoi(optarg));
+				*flags |= SCTP_EXPTUPLE_SPORT;
+			}
+			break;
+		case '7':
+			if (optarg) {
+				exptuple->l4dst.sctp.port = htons(atoi(optarg));
+				*flags |= SCTP_EXPTUPLE_DPORT;
+			}
+
+	}
+	return 1;
+}
+
+static int final_check(unsigned int flags,
+		       unsigned int command,
+		       struct nfct_tuple *orig,
+		       struct nfct_tuple *reply)
+{
+	int ret = 0;
+	
+	if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) 
+	    && !(flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) {
+		reply->l4src.sctp.port = orig->l4dst.sctp.port;
+		reply->l4dst.sctp.port = orig->l4src.sctp.port;
+		ret = 1;
+	} else if (!(flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT))
+	            && (flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) {
+		orig->l4src.sctp.port = reply->l4dst.sctp.port;
+		orig->l4dst.sctp.port = reply->l4src.sctp.port;
+		ret = 1;
+	}
+	if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) 
+	    && ((flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))))
+		ret = 1;
+
+	/* --state is missing and we are trying to create a conntrack */
+	if (ret && (command & CT_CREATE) && (!(flags & SCTP_STATE)))
+		ret = 0;
+
+	return ret;
+}
+
+static struct ctproto_handler sctp = {
+	.name 			= "sctp",
+	.protonum		= IPPROTO_SCTP,
+	.parse_opts		= parse_options,
+	.final_check		= final_check,
+	.help			= help,
+	.opts			= opts,
+	.version		= VERSION,
+};
+
+static void __attribute__ ((constructor)) init(void);
+
+static void init(void)
+{
+	register_proto(&sctp);
+}
diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c
new file mode 100644
index 0000000..ee24206
--- /dev/null
+++ b/extensions/libct_proto_tcp.c
@@ -0,0 +1,180 @@
+/*
+ * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
+ *
+ *      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 <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
+
+#include "conntrack.h"
+
+static struct option opts[] = {
+	{"orig-port-src", 1, 0, '1'},
+	{"orig-port-dst", 1, 0, '2'},
+	{"reply-port-src", 1, 0, '3'},
+	{"reply-port-dst", 1, 0, '4'},
+	{"mask-port-src", 1, 0, '5'},
+	{"mask-port-dst", 1, 0, '6'},
+	{"state", 1, 0, '7'},
+	{"tuple-port-src", 1, 0, '8'},
+	{"tuple-port-dst", 1, 0, '9'},
+	{0, 0, 0, 0}
+};
+
+static const char *states[] = {
+	"NONE",
+	"SYN_SENT",
+	"SYN_RECV",
+	"ESTABLISHED",
+	"FIN_WAIT",
+	"CLOSE_WAIT",
+	"LAST_ACK",
+	"TIME_WAIT",
+	"CLOSE",
+	"LISTEN"
+};
+
+static void help()
+{
+	fprintf(stdout, "--orig-port-src        original source port\n");
+	fprintf(stdout, "--orig-port-dst        original destination port\n");
+	fprintf(stdout, "--reply-port-src       reply source port\n");
+	fprintf(stdout, "--reply-port-dst       reply destination port\n");
+	fprintf(stdout, "--mask-port-src	mask source port\n");
+	fprintf(stdout, "--mask-port-dst	mask destination port\n");
+	fprintf(stdout, "--tuple-port-src	expectation tuple src port\n");
+	fprintf(stdout, "--tuple-port-src	expectation tuple dst port\n");
+	fprintf(stdout, "--state                TCP state, fe. ESTABLISHED\n");
+}
+
+static int parse_options(char c, char *argv[], 
+			 struct nfct_tuple *orig,
+			 struct nfct_tuple *reply,
+			 struct nfct_tuple *exptuple,
+			 struct nfct_tuple *mask,
+			 union nfct_protoinfo *proto,
+			 unsigned int *flags)
+{
+	switch(c) {
+		case '1':
+			if (optarg) {
+				orig->l4src.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_ORIG_SPORT;
+			}
+			break;
+		case '2':
+			if (optarg) {
+				orig->l4dst.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_ORIG_DPORT;
+			}
+			break;
+		case '3':
+			if (optarg) {
+				reply->l4src.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_REPL_SPORT;
+			}
+			break;
+		case '4':
+			if (optarg) {
+				reply->l4dst.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_REPL_DPORT;
+			}
+			break;
+		case '5':
+			if (optarg) {
+				mask->l4src.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_MASK_SPORT;
+			}
+			break;
+		case '6':
+			if (optarg) {
+				mask->l4dst.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_MASK_DPORT;
+			}
+			break;
+		case '7':
+			if (optarg) {
+				int i;
+				for (i=0; i<10; i++) {
+					if (strcmp(optarg, states[i]) == 0) {
+						proto->tcp.state = i;
+						break;
+					}
+				}
+				if (i == 10) {
+					printf("doh?\n");
+					return 0;
+				}
+				*flags |= TCP_STATE;
+			}
+			break;
+		case '8':
+			if (optarg) {
+				exptuple->l4src.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_EXPTUPLE_SPORT;
+			}
+			break;
+		case '9':
+			if (optarg) {
+				exptuple->l4dst.tcp.port = htons(atoi(optarg));
+				*flags |= TCP_EXPTUPLE_DPORT;
+			}
+			break;
+	}
+	return 1;
+}
+
+static int final_check(unsigned int flags,
+		       unsigned int command,
+		       struct nfct_tuple *orig,
+		       struct nfct_tuple *reply)
+{
+	int ret = 0;
+	
+	if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) 
+	    && !(flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) {
+		reply->l4src.tcp.port = orig->l4dst.tcp.port;
+		reply->l4dst.tcp.port = orig->l4src.tcp.port;
+		ret = 1;
+	} else if (!(flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT))
+	            && (flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) {
+		orig->l4src.tcp.port = reply->l4dst.tcp.port;
+		orig->l4dst.tcp.port = reply->l4src.tcp.port;
+		ret = 1;
+	}
+	if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) 
+	    && ((flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))))
+		ret = 1;
+
+	/* --state is missing and we are trying to create a conntrack */
+	if (ret && (command & CT_CREATE) && (!(flags & TCP_STATE)))
+		ret = 0;
+
+	return ret;
+}
+
+static struct ctproto_handler tcp = {
+	.name 			= "tcp",
+	.protonum		= IPPROTO_TCP,
+	.parse_opts		= parse_options,
+	.final_check		= final_check,
+	.help			= help,
+	.opts			= opts,
+	.version		= VERSION,
+};
+
+static void __attribute__ ((constructor)) init(void);
+
+static void init(void)
+{
+	register_proto(&tcp);
+}
diff --git a/extensions/libct_proto_tcp.man b/extensions/libct_proto_tcp.man
new file mode 100644
index 0000000..41783f8
--- /dev/null
+++ b/extensions/libct_proto_tcp.man
@@ -0,0 +1,16 @@
+This module matches on TCP-specific fields.
+.TP
+.BI "--orig-port-src " "PORT"
+Source port in original direction
+.TP
+.BI "--orig-port-dst " "PORT"
+Destination port in original direction
+.TP
+.BI "--reply-port-src " "PORT"
+Source port in reply direction
+.TP
+.BI "--reply-port-dst " "PORT"
+Destination port in reply direction
+.TP
+.BI "--state " "[NONE|SYN_SENT|SYN_RECV|ESTABLISHED|FIN_WAIT|CLOSE_WAIT|LAST_ACK|TIME_WAIT|CLOSE|LISTEN]"
+TCP state
diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c
new file mode 100644
index 0000000..48079e0
--- /dev/null
+++ b/extensions/libct_proto_udp.c
@@ -0,0 +1,141 @@
+/*
+ * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
+ *
+ *      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 <netinet/in.h> /* For htons */
+#include "conntrack.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_udp.h>
+
+static struct option opts[] = {
+	{"orig-port-src", 1, 0, '1'},
+	{"orig-port-dst", 1, 0, '2'},
+	{"reply-port-src", 1, 0, '3'},
+	{"reply-port-dst", 1, 0, '4'},
+	{"mask-port-src", 1, 0, '5'},
+	{"mask-port-dst", 1, 0, '6'},
+	{"tuple-port-src", 1, 0, '7'},
+	{"tuple-port-dst", 1, 0, '8'},
+	{0, 0, 0, 0}
+};
+
+static void help()
+{
+	fprintf(stdout, "--orig-port-src        original source port\n");
+	fprintf(stdout, "--orig-port-dst        original destination port\n");
+	fprintf(stdout, "--reply-port-src       reply source port\n");
+	fprintf(stdout, "--reply-port-dst       reply destination port\n");
+	fprintf(stdout, "--mask-port-src	mask source port\n");
+	fprintf(stdout, "--mask-port-dst	mask destination port\n");
+	fprintf(stdout, "--tuple-port-src	expectation tuple src port\n");
+	fprintf(stdout, "--tuple-port-src	expectation tuple dst port\n");
+}
+
+static int parse_options(char c, char *argv[], 
+			 struct nfct_tuple *orig,
+			 struct nfct_tuple *reply,
+			 struct nfct_tuple *exptuple,
+			 struct nfct_tuple *mask,
+			 union nfct_protoinfo *proto,
+			 unsigned int *flags)
+{
+	switch(c) {
+		case '1':
+			if (optarg) {
+				orig->l4src.udp.port = htons(atoi(optarg));
+				*flags |= UDP_ORIG_SPORT;
+			}
+			break;
+		case '2':
+			if (optarg) {
+				orig->l4dst.udp.port = htons(atoi(optarg));
+				*flags |= UDP_ORIG_DPORT;
+			}
+			break;
+		case '3':
+			if (optarg) {
+				reply->l4src.udp.port = htons(atoi(optarg));
+				*flags |= UDP_REPL_SPORT;
+			}
+			break;
+		case '4':
+			if (optarg) {
+				reply->l4dst.udp.port = htons(atoi(optarg));
+				*flags |= UDP_REPL_DPORT;
+			}
+			break;
+		case '5':
+			if (optarg) {
+				mask->l4src.udp.port = htons(atoi(optarg));
+				*flags |= UDP_MASK_SPORT;
+			}
+			break;
+		case '6':
+			if (optarg) {
+				mask->l4dst.udp.port = htons(atoi(optarg));
+				*flags |= UDP_MASK_DPORT;
+			}
+			break;
+		case '7':
+			if (optarg) {
+				exptuple->l4src.udp.port = htons(atoi(optarg));
+				*flags |= UDP_EXPTUPLE_SPORT;
+			}
+			break;
+		case '8':
+			if (optarg) {
+				exptuple->l4dst.udp.port = htons(atoi(optarg));
+				*flags |= UDP_EXPTUPLE_DPORT;
+			}
+
+	}
+	return 1;
+}
+
+static int final_check(unsigned int flags,
+		       unsigned int command,
+		       struct nfct_tuple *orig,
+		       struct nfct_tuple *reply)
+{
+	if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) 
+	    && !(flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) {
+		reply->l4src.udp.port = orig->l4dst.udp.port;
+		reply->l4dst.udp.port = orig->l4src.udp.port;
+		return 1;
+	} else if (!(flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT))
+	            && (flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) {
+		orig->l4src.udp.port = reply->l4dst.udp.port;
+		orig->l4dst.udp.port = reply->l4src.udp.port;
+		return 1;
+	}
+	if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) 
+	    && ((flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))))
+		return 1;
+
+	return 0;
+}
+
+static struct ctproto_handler udp = {
+	.name 			= "udp",
+	.protonum		= IPPROTO_UDP,
+	.parse_opts		= parse_options,
+	.final_check		= final_check,
+	.help			= help,
+	.opts			= opts,
+	.version		= VERSION,
+};
+
+static void __attribute__ ((constructor)) init(void);
+
+static void init(void)
+{
+	register_proto(&udp);
+}
diff --git a/extensions/libct_proto_udp.man b/extensions/libct_proto_udp.man
new file mode 100644
index 0000000..c67fedf
--- /dev/null
+++ b/extensions/libct_proto_udp.man
@@ -0,0 +1,13 @@
+This module matches on UDP-specific fields.
+.TP
+.BI "--orig-port-src " "PORT"
+Source port in original direction
+.TP
+.BI "--orig-port-dst " "PORT"
+Destination port in original direction
+.TP
+.BI "--reply-port-src " "PORT"
+Source port in reply direction
+.TP
+.BI "--reply-port-dst " "PORT"
+Destination port in reply direction
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..e669d73
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,5 @@
+
+noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \
+		 sync.h conntrackd.h local.h us-conntrack.h \
+		 debug.h log.h hash.h mcast.h buffer.h
+
diff --git a/include/alarm.h b/include/alarm.h
new file mode 100644
index 0000000..93e6482
--- /dev/null
+++ b/include/alarm.h
@@ -0,0 +1,13 @@
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+#include "linux_list.h"
+
+struct alarm_list {
+	struct list_head	head;
+	unsigned long		expires;
+	void			*data;
+	void			(*function)(struct alarm_list *a, void *data);
+};
+
+#endif
diff --git a/include/buffer.h b/include/buffer.h
new file mode 100644
index 0000000..8d72dfb
--- /dev/null
+++ b/include/buffer.h
@@ -0,0 +1,32 @@
+#ifndef _BUFFER_H_
+#define _BUFFER_H_
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include "linux_list.h"
+
+struct buffer {
+	pthread_mutex_t lock;
+	size_t max_size;
+	size_t cur_size;
+	struct list_head head;
+};
+
+struct buffer_node {
+	struct list_head head;
+	size_t size;
+	char data[0];
+};
+
+struct buffer *buffer_create(size_t max_size);
+void buffer_destroy(struct buffer *b);
+int buffer_add(struct buffer *b, const void *data, size_t size);
+void buffer_del(struct buffer *b, void *data);
+void __buffer_del(struct buffer *b, void *data);
+void buffer_iterate(struct buffer *b, 
+		    void *data, 
+		    int (*iterate)(void *data1, void *data2));
+
+#endif
diff --git a/include/cache.h b/include/cache.h
new file mode 100644
index 0000000..7d9559a
--- /dev/null
+++ b/include/cache.h
@@ -0,0 +1,92 @@
+#ifndef _CACHE_H_
+#define _CACHE_H_
+
+#include <sys/types.h>
+#include <time.h>
+
+/* cache features */
+enum {
+	NO_FEATURES = 0,
+
+	TIMER_FEATURE = 0,
+	TIMER = (1 << TIMER_FEATURE),
+
+	LIFETIME_FEATURE = 2,
+	LIFETIME = (1 << LIFETIME_FEATURE),
+
+	__CACHE_MAX_FEATURE
+};
+#define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE
+
+struct cache;
+struct us_conntrack;
+
+struct cache_feature {
+	size_t size;
+	void (*add)(struct us_conntrack *u, void *data);
+	void (*update)(struct us_conntrack *u, void *data);
+	void (*destroy)(struct us_conntrack *u, void *data);
+	int  (*dump)(struct us_conntrack *u, void *data, char *buf, int type);
+};
+
+extern struct cache_feature lifetime_feature;
+extern struct cache_feature timer_feature;
+
+#define CACHE_MAX_NAMELEN 32
+
+struct cache {
+	char name[CACHE_MAX_NAMELEN];
+	struct hashtable *h;
+
+	unsigned int num_features;
+	struct cache_feature **features;
+	unsigned int feature_type[CACHE_MAX_FEATURE];
+	unsigned int *feature_offset;
+	struct cache_extra *extra;
+	unsigned int extra_offset;
+
+        /* statistics */
+	unsigned int add_ok;
+	unsigned int del_ok;
+	unsigned int upd_ok;
+
+	unsigned int add_fail;
+	unsigned int del_fail;
+	unsigned int upd_fail;
+
+	unsigned int commit_ok;
+	unsigned int commit_exist;
+	unsigned int commit_fail;
+
+	unsigned int flush;
+};
+
+struct cache_extra {
+	unsigned int size;
+
+	void (*add)(struct us_conntrack *u, void *data);
+	void (*update)(struct us_conntrack *u, void *data);
+	void (*destroy)(struct us_conntrack *u, void *data);
+};
+
+struct nf_conntrack;
+
+struct cache *cache_create(char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra);
+void cache_destroy(struct cache *e);
+
+struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct);
+struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct);
+struct us_conntrack *cache_update_force(struct cache *c, struct nf_conntrack *ct);
+int cache_del(struct cache *c, struct nf_conntrack *ct);
+int cache_test(struct cache *c, struct nf_conntrack *ct);
+void cache_stats(struct cache *c, int fd);
+struct us_conntrack *cache_get_conntrack(struct cache *, void *);
+void *cache_get_extra(struct cache *, void *);
+
+/* iterators */
+void cache_dump(struct cache *c, int fd, int type);
+void cache_commit(struct cache *c);
+void cache_flush(struct cache *c);
+void cache_bulk(struct cache *c);
+
+#endif
diff --git a/include/conntrack.h b/include/conntrack.h
new file mode 100644
index 0000000..fb3b9b6
--- /dev/null
+++ b/include/conntrack.h
@@ -0,0 +1,160 @@
+#ifndef _CONNTRACK_H
+#define _CONNTRACK_H
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#include "linux_list.h"
+#include <getopt.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+#define PROGNAME "conntrack"
+
+#include <netinet/in.h>
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP 132
+#endif
+
+enum action {
+	CT_NONE		= 0,
+	
+	CT_LIST_BIT 	= 0,
+	CT_LIST 	= (1 << CT_LIST_BIT),
+	
+	CT_CREATE_BIT	= 1,
+	CT_CREATE	= (1 << CT_CREATE_BIT),
+
+	CT_UPDATE_BIT	= 2,
+	CT_UPDATE	= (1 << CT_UPDATE_BIT),
+	
+	CT_DELETE_BIT	= 3,
+	CT_DELETE	= (1 << CT_DELETE_BIT),
+	
+	CT_GET_BIT	= 4,
+	CT_GET		= (1 << CT_GET_BIT),
+
+	CT_FLUSH_BIT	= 5,
+	CT_FLUSH	= (1 << CT_FLUSH_BIT),
+
+	CT_EVENT_BIT	= 6,
+	CT_EVENT	= (1 << CT_EVENT_BIT),
+
+	CT_VERSION_BIT	= 7,
+	CT_VERSION	= (1 << CT_VERSION_BIT),
+
+	CT_HELP_BIT	= 8,
+	CT_HELP		= (1 << CT_HELP_BIT),
+
+	EXP_LIST_BIT 	= 9,
+	EXP_LIST 	= (1 << EXP_LIST_BIT),
+	
+	EXP_CREATE_BIT	= 10,
+	EXP_CREATE	= (1 << EXP_CREATE_BIT),
+	
+	EXP_DELETE_BIT	= 11,
+	EXP_DELETE	= (1 << EXP_DELETE_BIT),
+	
+	EXP_GET_BIT	= 12,
+	EXP_GET		= (1 << EXP_GET_BIT),
+
+	EXP_FLUSH_BIT	= 13,
+	EXP_FLUSH	= (1 << EXP_FLUSH_BIT),
+
+	EXP_EVENT_BIT	= 14,
+	EXP_EVENT	= (1 << EXP_EVENT_BIT),
+};
+#define NUMBER_OF_CMD   15
+
+enum options {
+	CT_OPT_ORIG_SRC_BIT	= 0,
+	CT_OPT_ORIG_SRC 	= (1 << CT_OPT_ORIG_SRC_BIT),
+	
+	CT_OPT_ORIG_DST_BIT	= 1,
+	CT_OPT_ORIG_DST		= (1 << CT_OPT_ORIG_DST_BIT),
+
+	CT_OPT_ORIG		= (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST),
+	
+	CT_OPT_REPL_SRC_BIT	= 2,
+	CT_OPT_REPL_SRC		= (1 << CT_OPT_REPL_SRC_BIT),
+	
+	CT_OPT_REPL_DST_BIT	= 3,
+	CT_OPT_REPL_DST		= (1 << CT_OPT_REPL_DST_BIT),
+
+	CT_OPT_REPL		= (CT_OPT_REPL_SRC | CT_OPT_REPL_DST),
+
+	CT_OPT_PROTO_BIT	= 4,
+	CT_OPT_PROTO		= (1 << CT_OPT_PROTO_BIT),
+
+	CT_OPT_TIMEOUT_BIT	= 5,
+	CT_OPT_TIMEOUT		= (1 << CT_OPT_TIMEOUT_BIT),
+
+	CT_OPT_STATUS_BIT	= 6,
+	CT_OPT_STATUS		= (1 << CT_OPT_STATUS_BIT),
+
+	CT_OPT_ZERO_BIT		= 7,
+	CT_OPT_ZERO		= (1 << CT_OPT_ZERO_BIT),
+
+	CT_OPT_EVENT_MASK_BIT	= 8,
+	CT_OPT_EVENT_MASK	= (1 << CT_OPT_EVENT_MASK_BIT),
+
+	CT_OPT_EXP_SRC_BIT	= 9,
+	CT_OPT_EXP_SRC		= (1 << CT_OPT_EXP_SRC_BIT),
+
+	CT_OPT_EXP_DST_BIT	= 10,
+	CT_OPT_EXP_DST		= (1 << CT_OPT_EXP_DST_BIT),
+
+	CT_OPT_MASK_SRC_BIT	= 11,
+	CT_OPT_MASK_SRC		= (1 << CT_OPT_MASK_SRC_BIT),
+
+	CT_OPT_MASK_DST_BIT	= 12,
+	CT_OPT_MASK_DST		= (1 << CT_OPT_MASK_DST_BIT),
+
+	CT_OPT_NATRANGE_BIT	= 13,
+	CT_OPT_NATRANGE		= (1 << CT_OPT_NATRANGE_BIT),
+
+	CT_OPT_MARK_BIT		= 14,
+	CT_OPT_MARK		= (1 << CT_OPT_MARK_BIT),
+
+	CT_OPT_ID_BIT		= 15,
+	CT_OPT_ID		= (1 << CT_OPT_ID_BIT),
+
+	CT_OPT_FAMILY_BIT	= 16,
+	CT_OPT_FAMILY		= (1 << CT_OPT_FAMILY_BIT),
+
+	CT_OPT_MAX_BIT		= CT_OPT_FAMILY_BIT
+};
+#define NUMBER_OF_OPT   CT_OPT_MAX_BIT+1
+
+struct ctproto_handler {
+	struct list_head 	head;
+
+	char 			*name;
+	u_int16_t 		protonum;
+	char			*version;
+
+	enum ctattr_protoinfo	protoinfo_attr;
+	
+	int (*parse_opts)(char c, char *argv[], 
+		     struct nfct_tuple *orig,
+		     struct nfct_tuple *reply,
+		     struct nfct_tuple *exptuple,
+		     struct nfct_tuple *mask,
+		     union nfct_protoinfo *proto,
+		     unsigned int *flags);
+
+	int (*final_check)(unsigned int flags,
+			   unsigned int command,
+			   struct nfct_tuple *orig,
+			   struct nfct_tuple *reply);
+
+	void (*help)();
+
+	struct option 		*opts;
+
+	unsigned int		option_offset;
+};
+
+extern void register_proto(struct ctproto_handler *h);
+
+#endif
diff --git a/include/conntrackd.h b/include/conntrackd.h
new file mode 100644
index 0000000..a5f7a3a
--- /dev/null
+++ b/include/conntrackd.h
@@ -0,0 +1,174 @@
+#ifndef _CONNTRACKD_H_
+#define _CONNTRACKD_H_
+
+#include "mcast.h"
+#include "local.h"
+
+#include <stdio.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h> 
+#include "cache.h"
+#include "debug.h"
+#include <signal.h>
+#include "state_helper.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
+
+/* UNIX facilities */
+#define FLUSH_MASTER	0	/* flush kernel conntrack table 	*/
+#define RESYNC_MASTER	1	/* resync with kernel conntrack table 	*/
+#define DUMP_INTERNAL 	16	/* dump internal cache 			*/
+#define DUMP_EXTERNAL 	17	/* dump external cache 			*/
+#define COMMIT		18	/* commit external cache		*/
+#define FLUSH_CACHE	19	/* flush cache				*/
+#define KILL		20	/* kill conntrackd			*/
+#define STATS		21	/* dump statistics			*/
+#define SEND_BULK	22	/* send a bulk				*/
+#define REQUEST_DUMP	23	/* request dump 			*/
+#define DUMP_INT_XML	24	/* dump internal cache in XML		*/
+#define DUMP_EXT_XML	25	/* dump external cache in XML		*/
+
+#define DEFAULT_CONFIGFILE	"/etc/conntrackd/conntrackd.conf"
+#define DEFAULT_LOCKFILE	"/var/lock/conntrackd.lock"
+
+enum {
+	STRIP_NAT_BIT = 0,
+	STRIP_NAT = (1 << STRIP_NAT_BIT),
+
+	DELAY_DESTROY_MSG_BIT = 1,
+	DELAY_DESTROY_MSG = (1 << DELAY_DESTROY_MSG_BIT),
+
+	RELAX_TRANSITIONS_BIT = 2,
+	RELAX_TRANSITIONS = (1 << RELAX_TRANSITIONS_BIT),
+
+	SYNC_MODE_PERSISTENT_BIT = 3,
+	SYNC_MODE_PERSISTENT = (1 << SYNC_MODE_PERSISTENT_BIT),
+
+	SYNC_MODE_NACK_BIT = 4,
+	SYNC_MODE_NACK = (1 << SYNC_MODE_NACK_BIT),
+
+	DONT_CHECKSUM_BIT = 5,
+	DONT_CHECKSUM = (1 << DONT_CHECKSUM_BIT),
+};
+
+/* daemon/request modes */
+#define NOT_SET         0
+#define DAEMON		1
+#define REQUEST		2
+
+/* conntrackd modes */
+#define SYNC_MODE	0
+#define STATS_MODE      1
+
+/* FILENAME_MAX is 4096 on my system, perhaps too much? */
+#ifndef FILENAME_MAXLEN
+#define FILENAME_MAXLEN 256
+#endif
+
+union inet_address {
+	u_int32_t ipv4;
+	u_int32_t ipv6[4];
+	u_int32_t all[4];
+};
+
+#define CONFIG(x) conf.x
+
+struct ct_conf {
+	char logfile[FILENAME_MAXLEN];
+	char lockfile[FILENAME_MAXLEN];
+	int hashsize;			/* hashtable size */
+	struct mcast_conf mcast;	/* multicast settings */
+	struct local_conf local;	/* unix socket facilities */
+	int limit;
+	int refresh;
+	int cache_timeout;		/* cache entries timeout */
+	int commit_timeout;		/* committed entries timeout */
+	unsigned int netlink_buffer_size;
+	unsigned int netlink_buffer_size_max_grown;
+	unsigned char ignore_protocol[IPPROTO_MAX];
+	union inet_address *listen_to;
+	unsigned int listen_to_len;
+	unsigned int flags;
+	int family;			/* protocol family */
+	unsigned int resend_buffer_size;/* NACK protocol */
+	unsigned int window_size;
+};
+
+#define STATE(x) st.x
+
+struct ct_general_state {
+	sigset_t 			block;
+	FILE 				*log;
+	int 				local;
+	struct ct_mode 			*mode;
+	struct ignore_pool		*ignore_pool;
+
+	struct nfnl_handle		*event;         /* event handler */
+	struct nfnl_handle		*sync;          /* sync handler */
+	struct nfnl_handle		*dump;		/* dump handler */
+
+	struct nfnl_subsys_handle	*subsys_event;  /* events */
+	struct nfnl_subsys_handle	*subsys_sync;	/* resync */
+	struct nfnl_subsys_handle	*subsys_dump;   /* dump */
+
+	/* statistics */
+	u_int64_t			malformed;
+	u_int64_t 			bytes[NFCT_DIR_MAX];
+	u_int64_t 			packets[NFCT_DIR_MAX];
+};
+
+#define STATE_SYNC(x) state.sync->x
+
+struct ct_sync_state {
+	struct cache *internal; 	/* internal events cache (netlink) */
+	struct cache *external; 	/* external events cache (mcast) */
+
+	struct mcast_sock *mcast_server;  /* multicast socket: incoming */
+	struct mcast_sock *mcast_client;  /* multicast socket: outgoing  */
+
+	struct sync_mode *mcast_sync;
+	struct buffer *buffer;
+
+	u_int32_t last_seq_sent;	/* last sequence number sent */
+	u_int32_t last_seq_recv;	/* last sequence number recv */
+	u_int64_t packets_replayed;	/* number of replayed packets */
+	u_int64_t packets_lost;         /* lost packets: sequence tracking */
+};
+
+#define STATE_STATS(x) state.stats->x
+
+struct ct_stats_state {
+	struct cache *cache;            /* internal events cache (netlink) */
+};
+
+union ct_state {
+	struct ct_sync_state *sync;
+	struct ct_stats_state *stats;
+};
+
+extern struct ct_conf conf;
+extern union ct_state state;
+extern struct ct_general_state st;
+
+#ifndef IPPROTO_VRRP
+#define IPPROTO_VRRP 112
+#endif
+
+struct ct_mode {
+	int (*init)(void);
+	int (*add_fds_to_set)(fd_set *readfds);
+	void (*step)(fd_set *readfds);
+	int (*local)(int fd, int type, void *data);
+	void (*kill)(void);
+	void (*dump)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
+	void (*overrun)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
+	void (*event_new)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
+	void (*event_upd)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
+	int (*event_dst)(struct nf_conntrack *ct, struct nlmsghdr *nlh);
+};
+
+/* conntrackd modes */
+extern struct ct_mode sync_mode;
+extern struct ct_mode stats_mode;
+
+#define MAX(x, y) x > y ? x : y
+
+#endif
diff --git a/include/debug.h b/include/debug.h
new file mode 100644
index 0000000..67f2c71
--- /dev/null
+++ b/include/debug.h
@@ -0,0 +1,53 @@
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+#if 0
+#define debug printf
+#else
+#define debug
+#endif
+
+#include <string.h>
+#include <netinet/in.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+static inline void debug_ct(struct nf_conntrack *ct, char *msg)
+{
+	struct in_addr addr, addr2, addr3, addr4;
+
+	debug("----%s (%p) ----\n", msg, ct);
+	memcpy(&addr, 
+	       nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), 
+	       sizeof(u_int32_t));
+	memcpy(&addr2, 
+	       nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), 
+	       sizeof(u_int32_t));
+	memcpy(&addr3, 
+	       nfct_get_attr(ct, ATTR_REPL_IPV4_SRC), 
+	       sizeof(u_int32_t));
+	memcpy(&addr4, 
+	       nfct_get_attr(ct, ATTR_REPL_IPV4_DST), 
+	       sizeof(u_int32_t));
+
+	debug("status: %x\n", nfct_get_attr_u32(ct, ATTR_STATUS));
+	debug("l3:%d l4:%d ",
+			nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO),
+			nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO));
+	debug("%s:%hu ->", inet_ntoa(addr),
+			   ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC)));
+	debug("%s:%hu\n",
+			inet_ntoa(addr2),
+			ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)));
+	debug("l3:%d l4:%d ",
+			nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO),
+			nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO));
+	debug("%s:%hu ->",
+			inet_ntoa(addr3),
+			ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)));
+	debug("%s:%hu\n",
+			inet_ntoa(addr4),
+			ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)));
+	debug("-------------------------\n");
+}
+
+#endif
diff --git a/include/hash.h b/include/hash.h
new file mode 100644
index 0000000..fd971e7
--- /dev/null
+++ b/include/hash.h
@@ -0,0 +1,47 @@
+#ifndef _NF_SET_HASH_H_
+#define _NF_SET_HASH_H_
+
+#include <unistd.h>
+#include <sys/types.h>
+#include "slist.h"
+#include "linux_list.h"
+
+struct hashtable;
+struct hashtable_node;
+
+struct hashtable {
+	u_int32_t hashsize;
+	u_int32_t limit;
+	u_int32_t count;
+	u_int32_t initval;
+	u_int32_t datasize;
+	
+	u_int32_t	(*hash)(const void *data, struct hashtable *table);
+	int		(*compare)(const void *data1, const void *data2);
+
+	struct slist_head 	members[0];
+};
+
+struct hashtable_node {
+	struct slist_head head;
+	char data[0];
+};
+
+struct hashtable_node *hashtable_alloc_node(int datasize, void *data);
+void hashtable_destroy_node(struct hashtable_node *h);
+
+struct hashtable *
+hashtable_create(int hashsize, int limit, int datasize,
+		 u_int32_t (*hash)(const void *data, struct hashtable *table),
+		 int (*compare)(const void *data1, const void *data2));
+void hashtable_destroy(struct hashtable *h);
+
+void *hashtable_add(struct hashtable *table, void *data);
+void *hashtable_test(struct hashtable *table, const void *data);
+int hashtable_del(struct hashtable *table, void *data);
+int hashtable_flush(struct hashtable *table);
+int hashtable_iterate(struct hashtable *table, void *data,
+		      int (*iterate)(void *data1, void *data2));
+unsigned int hashtable_counter(struct hashtable *table);
+
+#endif
diff --git a/include/ignore.h b/include/ignore.h
new file mode 100644
index 0000000..40cb02d
--- /dev/null
+++ b/include/ignore.h
@@ -0,0 +1,12 @@
+#ifndef _IGNORE_H_
+#define _IGNORE_H_
+
+struct ignore_pool {
+	struct hashtable *h;
+};
+
+struct ignore_pool *ignore_pool_create(u_int8_t family);
+void ignore_pool_destroy(struct ignore_pool *ip);
+int ignore_pool_add(struct ignore_pool *ip, void *data);
+
+#endif
diff --git a/include/jhash.h b/include/jhash.h
new file mode 100644
index 0000000..38b8780
--- /dev/null
+++ b/include/jhash.h
@@ -0,0 +1,146 @@
+#ifndef _LINUX_JHASH_H
+#define _LINUX_JHASH_H
+
+#define u32 unsigned int
+#define u8  char
+
+/* jhash.h: Jenkins hash support.
+ *
+ * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
+ *
+ * http://burtleburtle.net/bob/hash/
+ *
+ * These are the credits from Bob's sources:
+ *
+ * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
+ * hash(), hash2(), hash3, and mix() are externally useful functions.
+ * Routines to test the hash are included if SELF_TEST is defined.
+ * You can use this free for any purpose.  It has no warranty.
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ *
+ * I've modified Bob's hash to be useful in the Linux kernel, and
+ * any bugs present are surely my fault.  -DaveM
+ */
+
+/* NOTE: Arguments are modified. */
+#define __jhash_mix(a, b, c) \
+{ \
+  a -= b; a -= c; a ^= (c>>13); \
+  b -= c; b -= a; b ^= (a<<8); \
+  c -= a; c -= b; c ^= (b>>13); \
+  a -= b; a -= c; a ^= (c>>12);  \
+  b -= c; b -= a; b ^= (a<<16); \
+  c -= a; c -= b; c ^= (b>>5); \
+  a -= b; a -= c; a ^= (c>>3);  \
+  b -= c; b -= a; b ^= (a<<10); \
+  c -= a; c -= b; c ^= (b>>15); \
+}
+
+/* The golden ration: an arbitrary value */
+#define JHASH_GOLDEN_RATIO	0x9e3779b9
+
+/* The most generic version, hashes an arbitrary sequence
+ * of bytes.  No alignment or length assumptions are made about
+ * the input key.
+ */
+static inline u32 jhash(const void *key, u32 length, u32 initval)
+{
+	u32 a, b, c, len;
+	const u8 *k = key;
+
+	len = length;
+	a = b = JHASH_GOLDEN_RATIO;
+	c = initval;
+
+	while (len >= 12) {
+		a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
+		b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
+		c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
+
+		__jhash_mix(a,b,c);
+
+		k += 12;
+		len -= 12;
+	}
+
+	c += length;
+	switch (len) {
+	case 11: c += ((u32)k[10]<<24);
+	case 10: c += ((u32)k[9]<<16);
+	case 9 : c += ((u32)k[8]<<8);
+	case 8 : b += ((u32)k[7]<<24);
+	case 7 : b += ((u32)k[6]<<16);
+	case 6 : b += ((u32)k[5]<<8);
+	case 5 : b += k[4];
+	case 4 : a += ((u32)k[3]<<24);
+	case 3 : a += ((u32)k[2]<<16);
+	case 2 : a += ((u32)k[1]<<8);
+	case 1 : a += k[0];
+	};
+
+	__jhash_mix(a,b,c);
+
+	return c;
+}
+
+/* A special optimized version that handles 1 or more of u32s.
+ * The length parameter here is the number of u32s in the key.
+ */
+static inline u32 jhash2(u32 *k, u32 length, u32 initval)
+{
+	u32 a, b, c, len;
+
+	a = b = JHASH_GOLDEN_RATIO;
+	c = initval;
+	len = length;
+
+	while (len >= 3) {
+		a += k[0];
+		b += k[1];
+		c += k[2];
+		__jhash_mix(a, b, c);
+		k += 3; len -= 3;
+	}
+
+	c += length * 4;
+
+	switch (len) {
+	case 2 : b += k[1];
+	case 1 : a += k[0];
+	};
+
+	__jhash_mix(a,b,c);
+
+	return c;
+}
+
+
+/* A special ultra-optimized versions that knows they are hashing exactly
+ * 3, 2 or 1 word(s).
+ *
+ * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
+ *       done at the end is not done here.
+ */
+static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
+{
+	a += JHASH_GOLDEN_RATIO;
+	b += JHASH_GOLDEN_RATIO;
+	c += initval;
+
+	__jhash_mix(a, b, c);
+
+	return c;
+}
+
+static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
+{
+	return jhash_3words(a, b, 0, initval);
+}
+
+static inline u32 jhash_1word(u32 a, u32 initval)
+{
+	return jhash_3words(a, 0, 0, initval);
+}
+
+#endif /* _LINUX_JHASH_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/include/local.h b/include/local.h
new file mode 100644
index 0000000..350b8bf
--- /dev/null
+++ b/include/local.h
@@ -0,0 +1,29 @@
+#ifndef _LOCAL_SOCKET_H_
+#define _LOCAL_SOCKET_H_
+
+#include <sys/un.h>
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX   108
+#endif
+
+struct local_conf {
+	int backlog;
+	int reuseaddr;
+	char path[UNIX_PATH_MAX];
+};
+
+/* local server */
+int local_server_create(struct local_conf *conf);
+void local_server_destroy(int fd);
+int do_local_server_step(int fd, void *data, 
+			 void (*process)(int fd, void *data));
+
+/* local client */
+int local_client_create(struct local_conf *conf);
+void local_client_destroy(int fd);
+int do_local_client_step(int fd, void (*process)(char *buf));
+int do_local_request(int, struct local_conf *,void (*step)(char *buf));
+void local_step(char *buf);
+
+#endif
diff --git a/include/log.h b/include/log.h
new file mode 100644
index 0000000..9ecff30
--- /dev/null
+++ b/include/log.h
@@ -0,0 +1,10 @@
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include <stdio.h>
+
+FILE *init_log(char *filename);
+void dlog(FILE *fd, char *format, ...);
+void close_log(FILE *fd);
+
+#endif
diff --git a/include/mcast.h b/include/mcast.h
new file mode 100644
index 0000000..0f3e3cd
--- /dev/null
+++ b/include/mcast.h
@@ -0,0 +1,48 @@
+#ifndef _MCAST_H_
+#define _MCAST_H_
+
+#include <netinet/in.h>
+
+struct mcast_conf {
+	int ipproto;
+	int backlog;
+	int reuseaddr;
+	unsigned short port;
+	union {
+		struct in_addr inet_addr;
+		struct in6_addr inet_addr6;
+	} in;
+	union {
+		struct in_addr interface_addr;
+		struct in6_addr interface_addr6;
+	} ifa;
+};
+
+struct mcast_stats {
+	u_int64_t bytes;
+	u_int64_t messages;
+	u_int64_t error;
+};
+
+struct mcast_sock {
+	int fd;
+	union {
+		struct sockaddr_in ipv4;
+		struct sockaddr_in6 ipv6;
+	} addr;
+	struct mcast_stats stats;
+};
+
+struct mcast_sock *mcast_server_create(struct mcast_conf *conf);
+void mcast_server_destroy(struct mcast_sock *m);
+
+struct mcast_sock *mcast_client_create(struct mcast_conf *conf);
+void mcast_client_destroy(struct mcast_sock *m);
+
+int mcast_send(struct mcast_sock *m, void *data, int size);
+int mcast_recv(struct mcast_sock *m, void *data, int size);
+
+struct mcast_stats *mcast_get_stats(struct mcast_sock *m);
+void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r);
+
+#endif
diff --git a/include/network.h b/include/network.h
new file mode 100644
index 0000000..dab50db
--- /dev/null
+++ b/include/network.h
@@ -0,0 +1,34 @@
+#ifndef _NETWORK_H_
+#define _NETWORK_H_
+
+#include <sys/types.h>
+
+struct nlnetwork {
+	u_int16_t flags; 
+	u_int16_t checksum;
+	u_int32_t seq;
+};
+
+struct nlnetwork_ack {
+	u_int16_t flags; 
+	u_int16_t checksum;
+	u_int32_t seq;
+	u_int32_t from;
+	u_int32_t to;
+};
+
+enum {
+	NET_HELLO_BIT = 0,
+	NET_HELLO = (1 << NET_HELLO_BIT),
+
+	NET_RESYNC_BIT = 1,
+	NET_RESYNC = (1 << NET_RESYNC_BIT),
+
+	NET_NACK_BIT = 2,
+	NET_NACK = (1 << NET_NACK_BIT),
+
+	NET_ACK_BIT = 3,
+	NET_ACK = (1 << NET_ACK_BIT),
+};
+
+#endif
diff --git a/include/slist.h b/include/slist.h
new file mode 100644
index 0000000..ab7fa34
--- /dev/null
+++ b/include/slist.h
@@ -0,0 +1,41 @@
+#ifndef _SLIST_H_
+#define _SLIST_H_
+
+#include "linux_list.h"
+
+#define INIT_SLIST_HEAD(ptr) ((ptr).next = NULL)
+
+struct slist_head {
+	struct slist_head *next;
+};
+
+static inline int slist_empty(const struct slist_head *h)
+{
+	return !h->next;
+}
+
+static inline void slist_del(struct slist_head *t, struct slist_head *prev)
+{
+	prev->next = t->next;
+	t->next = LIST_POISON1;
+}
+
+static inline void slist_add(struct slist_head *head, struct slist_head *t)
+{
+	struct slist_head *tmp = head->next;
+	head->next = t;
+	t->next = tmp;
+}
+
+#define slist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define slist_for_each(pos, head) \
+	for (pos = (head)->next; pos && ({ prefetch(pos.next); 1; }); \
+	     pos = pos->next)
+
+#define slist_for_each_safe(pos, prev, next, head) \
+	for (pos = (head)->next, prev = (head); \
+	     pos && ({ next = pos->next; 1; }); \
+	     ({ prev = (prev->next != next) ? prev->next : prev; }), pos = next)
+
+#endif
diff --git a/include/state_helper.h b/include/state_helper.h
new file mode 100644
index 0000000..1ed0b79
--- /dev/null
+++ b/include/state_helper.h
@@ -0,0 +1,20 @@
+#ifndef _STATE_HELPER_H_
+#define _STATE_HELPER_H_
+
+enum {
+	ST_H_SKIP,
+	ST_H_REPLICATE
+};
+
+struct state_replication_helper {
+	u_int8_t 		proto;
+	unsigned int		state;
+
+	int (*verdict)(const struct state_replication_helper *h,
+		       const struct nf_conntrack *ct); 
+};
+
+int state_helper_verdict(int type, struct nf_conntrack *ct);
+void state_helper_register(struct state_replication_helper *h, int state);
+
+#endif
diff --git a/include/sync.h b/include/sync.h
new file mode 100644
index 0000000..7756c87
--- /dev/null
+++ b/include/sync.h
@@ -0,0 +1,23 @@
+#ifndef _SYNC_HOOKS_H_
+#define _SYNC_HOOKS_H_
+
+struct nlnetwork;
+struct us_conntrack;
+
+struct sync_mode {
+	int internal_cache_flags;
+	int external_cache_flags;
+	struct cache_extra *internal_cache_extra;
+	struct cache_extra *external_cache_extra;
+
+	int  (*init)(void);
+	void (*kill)(void);
+	int  (*local)(int fd, int type, void *data);
+	int  (*pre_recv)(const struct nlnetwork *net);
+	void (*post_send)(const struct nlnetwork *net, struct us_conntrack *u);
+};
+
+extern struct sync_mode notrack;
+extern struct sync_mode nack;
+
+#endif
diff --git a/include/us-conntrack.h b/include/us-conntrack.h
new file mode 100644
index 0000000..3d71e22
--- /dev/null
+++ b/include/us-conntrack.h
@@ -0,0 +1,13 @@
+#ifndef _US_CONNTRACK_H_
+#define _US_CONNTRACK_H_
+
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+/* be careful, do not modify the layout */
+struct us_conntrack {
+	struct 	nf_conntrack *ct;
+	struct  cache *cache;          /* add new attributes here */
+	char 	data[0];
+};
+
+#endif
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..381f8ac
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,26 @@
+include $(top_srcdir)/Make_global.am
+
+YACC=@YACC@ -d
+
+CLEANFILES = read_config_yy.c read_config_lex.c
+
+sbin_PROGRAMS = conntrack conntrackd
+
+conntrack_SOURCES = conntrack.c
+conntrack_LDFLAGS = -rdynamic
+
+conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \
+		    local.c log.c mcast.c netlink.c proxy.c lock.c \
+		    ignore_pool.c \
+		    cache.c cache_iterators.c \
+		    cache_lifetime.c cache_timer.c \
+		    sync-mode.c sync-notrack.c sync-nack.c \
+		    traffic_stats.c stats-mode.c \
+		    network.c checksum.c \
+		    state_helper.c state_helper_tcp.c \
+		    read_config_yy.y read_config_lex.l
+
+conntrackd_LDFLAGS = $(all_libraries) -lnfnetlink -lnetfilter_conntrack \
+		     -lpthread
+
+EXTRA_DIST = read_config_yy.h
diff --git a/src/alarm.c b/src/alarm.c
new file mode 100644
index 0000000..1a465c2
--- /dev/null
+++ b/src/alarm.c
@@ -0,0 +1,141 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include "linux_list.h"
+#include "conntrackd.h"
+#include "alarm.h"
+#include "jhash.h"
+#include <pthread.h>
+#include <time.h>
+#include <errno.h>
+
+/* alarm cascade */
+#define ALARM_CASCADE_SIZE     10
+static struct list_head *alarm_cascade;
+
+/* thread stuff */
+static pthread_t alarm_thread;
+
+struct alarm_list *create_alarm()
+{	
+	return (struct alarm_list *) malloc(sizeof(struct alarm_list));
+}
+
+void destroy_alarm(struct alarm_list *t)
+{
+	free(t);
+}
+
+void set_alarm_expiration(struct alarm_list *t, unsigned long expires)
+{
+	t->expires = expires;
+}
+
+void set_alarm_function(struct alarm_list *t,
+			void (*fcn)(struct alarm_list *a, void *data))
+{
+	t->function = fcn;
+}
+
+void set_alarm_data(struct alarm_list *t, void *data)
+{
+	t->data = data;
+}
+
+void init_alarm(struct alarm_list *t)
+{
+	INIT_LIST_HEAD(&t->head);
+
+	t->expires 	= 0;
+	t->data 	= 0;
+	t->function 	= NULL;
+}
+
+void add_alarm(struct alarm_list *alarm)
+{
+	unsigned int pos = jhash(alarm, sizeof(alarm), 0) % ALARM_CASCADE_SIZE;
+
+	list_add(&alarm->head, &alarm_cascade[pos]);
+}
+
+void del_alarm(struct alarm_list *alarm)
+{
+	list_del(&alarm->head);
+}
+
+int mod_alarm(struct alarm_list *alarm, unsigned long expires)
+{
+	alarm->expires = expires;
+	return 0;
+}
+
+void __run_alarms()
+{
+	struct list_head *i, *tmp;
+	struct alarm_list *t;
+	struct timespec req = {0, 1000000000 / ALARM_CASCADE_SIZE};
+	struct timespec rem;
+	static int step = 0;
+
+retry:
+	if (nanosleep(&req, &rem) == -1) {
+		/* interrupted syscall: retry with remaining time */
+		if (errno == EINTR) {
+			memcpy(&req, &rem, sizeof(struct timespec));
+			goto retry;
+		}
+	}
+
+	lock();
+	list_for_each_safe(i, tmp, &alarm_cascade[step]) {
+		t = (struct alarm_list *) i;
+
+		t->expires--;
+		if (t->expires == 0)
+			t->function(t, t->data);
+	}
+	step = (step + 1) < ALARM_CASCADE_SIZE ? step + 1 : 0;
+	unlock();
+}
+
+void *run_alarms(void *foo)
+{
+	while(1)
+		__run_alarms();
+}
+
+int create_alarm_thread()
+{
+	int i;
+
+	alarm_cascade = malloc(sizeof(struct list_head) * ALARM_CASCADE_SIZE);
+	if (alarm_cascade == NULL)
+		return -1;
+
+	for (i=0; i<ALARM_CASCADE_SIZE; i++)
+		INIT_LIST_HEAD(&alarm_cascade[i]);
+
+	return pthread_create(&alarm_thread, NULL, run_alarms, NULL);
+}
+
+int destroy_alarm_thread()
+{
+	return pthread_cancel(alarm_thread);
+}
diff --git a/src/buffer.c b/src/buffer.c
new file mode 100644
index 0000000..fa0b859
--- /dev/null
+++ b/src/buffer.c
@@ -0,0 +1,136 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "buffer.h"
+
+struct buffer *buffer_create(size_t max_size)
+{
+	struct buffer *b;
+
+	b = malloc(sizeof(struct buffer));
+	if (b == NULL)
+		return NULL;
+	memset(b, 0, sizeof(struct buffer));
+
+	b->max_size = max_size;
+	INIT_LIST_HEAD(&b->head);
+	pthread_mutex_init(&b->lock, NULL);
+
+	return b;
+}
+
+void buffer_destroy(struct buffer *b)
+{
+	struct list_head *i, *tmp;
+	struct buffer_node *node;
+
+	pthread_mutex_lock(&b->lock);
+	list_for_each_safe(i, tmp, &b->head) {
+		node = (struct buffer_node *) i;
+		list_del(i);
+		free(node);
+	}
+	pthread_mutex_unlock(&b->lock);
+	pthread_mutex_destroy(&b->lock);
+	free(b);
+}
+
+static struct buffer_node *buffer_node_create(const void *data, size_t size)
+{
+	struct buffer_node *n;
+
+	n = malloc(sizeof(struct buffer_node) + size);
+	if (n == NULL)
+		return NULL;
+
+	INIT_LIST_HEAD(&n->head);
+	n->size = size;
+	memcpy(n->data, data, size);
+
+	return n;
+}
+
+int buffer_add(struct buffer *b, const void *data, size_t size)
+{
+	int ret = 0;
+	struct buffer_node *n;
+
+	pthread_mutex_lock(&b->lock);
+
+	/* does it fit this buffer? */
+	if (size > b->max_size) {
+		errno = ENOSPC;
+		ret = -1;
+		goto err;
+	}
+
+retry:
+	/* buffer is full: kill the oldest entry */
+	if (b->cur_size + size > b->max_size) {
+		n = (struct buffer_node *) b->head.prev;
+		list_del(b->head.prev);
+		b->cur_size -= n->size;
+		free(n);
+		goto retry;
+	}
+
+	n = buffer_node_create(data, size);
+	if (n == NULL) {
+		ret = -1;
+		goto err;
+	}
+
+	list_add(&n->head, &b->head);
+	b->cur_size += size;
+
+err:
+	pthread_mutex_unlock(&b->lock);
+	return ret;
+}
+
+void __buffer_del(struct buffer *b, void *data)
+{
+	struct buffer_node *n = container_of(data, struct buffer_node, data); 
+
+	list_del(&n->head);
+	b->cur_size -= n->size;
+	free(n);
+}
+
+void buffer_del(struct buffer *b, void *data)
+{
+	pthread_mutex_lock(&b->lock);
+	buffer_del(b, data);
+	pthread_mutex_unlock(&b->lock);
+}
+
+void buffer_iterate(struct buffer *b, 
+		    void *data, 
+		    int (*iterate)(void *data1, void *data2))
+{
+	struct list_head *i, *tmp;
+	struct buffer_node *n;
+
+	pthread_mutex_lock(&b->lock);
+	list_for_each_safe(i, tmp, &b->head) {
+		n = (struct buffer_node *) i;
+		if (iterate(n->data, data))
+			break;
+	}
+	pthread_mutex_unlock(&b->lock);
+}
diff --git a/src/cache.c b/src/cache.c
new file mode 100644
index 0000000..6f7442b
--- /dev/null
+++ b/src/cache.c
@@ -0,0 +1,446 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "jhash.h"
+#include "hash.h"
+#include "conntrackd.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include "cache.h"
+#include "debug.h"
+
+static u_int32_t hash(const void *data, struct hashtable *table)
+{
+	unsigned int a, b;
+	const struct us_conntrack *u = data;
+	struct nf_conntrack *ct = u->ct;
+
+	a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), sizeof(u_int32_t),
+		  ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) |
+		   (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO))));
+
+	b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), sizeof(u_int32_t),
+		  ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) |
+		   (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST))));
+
+	return jhash_2words(a, b, 0) % table->hashsize;
+}
+
+static u_int32_t hash6(const void *data, struct hashtable *table)
+{
+	unsigned int a, b;
+	const struct us_conntrack *u = data;
+	struct nf_conntrack *ct = u->ct;
+
+	a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(u_int32_t),
+		  ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) |
+		   (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO))));
+
+	b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_DST), sizeof(u_int32_t),
+		  ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) |
+		   (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST))));
+
+	return jhash_2words(a, b, 0) % table->hashsize;
+}
+
+static int __compare(const struct nf_conntrack *ct1, 
+		     const struct nf_conntrack *ct2)
+{
+	return ((nfct_get_attr_u8(ct1, ATTR_ORIG_L3PROTO) ==
+	  	 nfct_get_attr_u8(ct2, ATTR_ORIG_L3PROTO)) &&
+		(nfct_get_attr_u8(ct1, ATTR_ORIG_L4PROTO) ==
+		 nfct_get_attr_u8(ct2, ATTR_ORIG_L4PROTO)) && 
+		(nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_SRC) ==
+		 nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_SRC)) &&
+		(nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_DST) ==
+	 	 nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_DST)) &&
+		(nfct_get_attr_u16(ct1, ATTR_REPL_PORT_SRC) ==
+	 	 nfct_get_attr_u16(ct2, ATTR_REPL_PORT_SRC)) &&
+		(nfct_get_attr_u16(ct1, ATTR_REPL_PORT_DST) ==
+	 	 nfct_get_attr_u16(ct2, ATTR_REPL_PORT_DST)));
+}
+
+static int compare(const void *data1, const void *data2)
+{
+	const struct us_conntrack *u1 = data1;
+	const struct us_conntrack *u2 = data2;
+
+	return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_SRC) ==
+	         nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_SRC)) &&
+	 	(nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_DST) ==
+		 nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_DST)) &&
+		(nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_SRC) ==
+		 nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_SRC)) &&
+		(nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_DST) ==
+		 nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_DST)) &&
+		 __compare(u1->ct, u2->ct));
+}
+
+static int compare6(const void *data1, const void *data2)
+{
+	const struct us_conntrack *u1 = data1;
+	const struct us_conntrack *u2 = data2;
+
+	return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_SRC) ==
+	         nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_SRC)) &&
+	 	(nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_DST) ==
+		 nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_DST)) &&
+		(nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_SRC) ==
+		 nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_SRC)) &&
+		(nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_DST) ==
+		 nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_DST)) &&
+		 __compare(u1->ct, u2->ct));
+}
+
+struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = {
+	[TIMER_FEATURE]		= &timer_feature,
+	[LIFETIME_FEATURE]	= &lifetime_feature,
+};
+
+struct cache *cache_create(char *name, 
+			   unsigned int features, 
+			   u_int8_t proto,
+			   struct cache_extra *extra)
+{
+	size_t size = sizeof(struct us_conntrack);
+	int i, j = 0;
+	struct cache *c;
+	struct cache_feature *feature_array[CACHE_MAX_FEATURE] = {};
+	unsigned int feature_offset[CACHE_MAX_FEATURE] = {};
+	unsigned int feature_type[CACHE_MAX_FEATURE] = {};
+
+	c = malloc(sizeof(struct cache));
+	if (!c)
+		return NULL;
+	memset(c, 0, sizeof(struct cache));
+
+	strcpy(c->name, name);
+
+	for (i = 0; i < CACHE_MAX_FEATURE; i++) {
+		if ((1 << i) & features) {
+			feature_array[j] = cache_feature[i];
+			feature_offset[j] = size;
+			feature_type[i] = j;
+			size += cache_feature[i]->size;
+			j++;
+		}
+	}
+
+	memcpy(c->feature_type, feature_type, sizeof(feature_type));
+
+	c->features = malloc(sizeof(struct cache_feature) * j);
+	if (!c->features) {
+		free(c);
+		return NULL;
+	}
+	memcpy(c->features, feature_array, sizeof(struct cache_feature) * j);
+	c->num_features = j;
+
+	c->extra_offset = size;
+	c->extra = extra;
+	if (extra)
+		size += extra->size;
+
+	c->feature_offset = malloc(sizeof(unsigned int) * j);
+	if (!c->feature_offset) {
+		free(c->features);
+		free(c);
+		return NULL;
+	}
+	memcpy(c->feature_offset, feature_offset, sizeof(unsigned int) * j);
+
+	switch(proto) {
+	case AF_INET:
+		c->h = hashtable_create(CONFIG(hashsize),
+					CONFIG(limit),
+					size,
+					hash,
+					compare);
+		break;
+	case AF_INET6:
+		c->h = hashtable_create(CONFIG(hashsize),
+					CONFIG(limit),
+					size,
+					hash6,
+					compare6);
+		break;
+	}
+
+	if (!c->h) {
+		free(c->features);
+		free(c->feature_offset);
+		free(c);
+		return NULL;
+	}
+
+	return c;
+}
+
+void cache_destroy(struct cache *c)
+{
+	lock();
+	hashtable_destroy(c->h);
+	unlock();
+	free(c->features);
+	free(c->feature_offset);
+	free(c);
+}
+
+static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct)
+{
+	int i;
+	size_t size = c->h->datasize;
+	char buf[size];
+	struct us_conntrack *u = (struct us_conntrack *) buf;
+	struct nf_conntrack *newct;
+
+	memset(u, 0, size);
+
+	u->cache = c;
+	if ((u->ct = newct = nfct_new()) == NULL) {
+		errno = ENOMEM;
+		return 0;
+	}
+	memcpy(u->ct, ct, nfct_sizeof(ct));
+
+	u = hashtable_add(c->h, u);
+	if (u) {
+		void *data = u->data;
+
+        	for (i = 0; i < c->num_features; i++) {
+			c->features[i]->add(u, data);
+			data += c->features[i]->size;
+		}
+
+		if (c->extra)
+			c->extra->add(u, ((void *) u) + c->extra_offset);
+
+		return u;
+	}
+	free(newct);
+
+	return NULL;
+}
+
+struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct)
+{
+	struct us_conntrack *u;
+
+	u = __add(c, ct);
+	if (u) {
+		c->add_ok++;
+		return u;
+	}
+	c->add_fail++;
+
+	return NULL;
+}
+
+struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct)
+{
+	struct us_conntrack *u;
+
+	lock();
+	u = __cache_add(c, ct);
+	unlock();
+
+	return u;
+}
+
+static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct)
+{
+	size_t size = c->h->datasize;
+	char buf[size];
+	struct us_conntrack *u = (struct us_conntrack *) buf;
+
+	u->ct = ct;
+
+	u = (struct us_conntrack *) hashtable_test(c->h, u);
+	if (u) {
+		int i;
+		void *data = u->data;
+
+		for (i = 0; i < c->num_features; i++) {
+			c->features[i]->update(u, data);
+			data += c->features[i]->size;
+		}
+
+		if (c->extra)
+			c->extra->update(u, ((void *) u) + c->extra_offset);
+
+		if (nfct_attr_is_set(ct, ATTR_STATUS))
+		    	nfct_set_attr_u32(u->ct, ATTR_STATUS,
+					  nfct_get_attr_u32(ct, ATTR_STATUS));
+		if (nfct_attr_is_set(ct, ATTR_TCP_STATE))
+			nfct_set_attr_u8(u->ct, ATTR_TCP_STATE,
+					 nfct_get_attr_u8(ct, ATTR_TCP_STATE));
+		if (nfct_attr_is_set(ct, ATTR_TIMEOUT))
+			nfct_set_attr_u32(u->ct, ATTR_TIMEOUT,
+					  nfct_get_attr_u32(ct, ATTR_TIMEOUT));
+
+		return u;
+	} 
+	return NULL;
+}
+
+struct us_conntrack *__cache_update(struct cache *c, struct nf_conntrack *ct)
+{
+	struct us_conntrack *u;
+
+	u = __update(c, ct);
+	if (u) {
+		c->upd_ok++;
+		return u;
+	}
+	c->upd_fail++;
+	
+	return NULL;
+}
+
+struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct)
+{
+	struct us_conntrack *u;
+
+	lock();
+	u = __cache_update(c, ct);
+	unlock();
+
+	return u;
+}
+
+struct us_conntrack *cache_update_force(struct cache *c,
+					struct nf_conntrack *ct)
+{
+	struct us_conntrack *u;
+
+	lock();
+	if ((u = __update(c, ct)) != NULL) {
+		c->upd_ok++;
+		unlock();
+		return u;
+	}
+	if ((u = __add(c, ct)) != NULL) {
+		c->add_ok++;
+		unlock();
+		return u;
+	}
+	c->add_fail++;
+	unlock();
+	return NULL;
+}
+
+int cache_test(struct cache *c, struct nf_conntrack *ct)
+{
+	size_t size = c->h->datasize;
+	char buf[size];
+	struct us_conntrack *u = (struct us_conntrack *) buf;
+	void *ret;
+
+	u->ct = ct;
+
+	lock();
+	ret = hashtable_test(c->h, u);
+	unlock();
+
+	return ret != NULL;
+}
+
+static int __del(struct cache *c, struct nf_conntrack *ct)
+{
+	size_t size = c->h->datasize;
+	char buf[size];
+	struct us_conntrack *u = (struct us_conntrack *) buf;
+
+	u->ct = ct;
+
+	u = (struct us_conntrack *) hashtable_test(c->h, u);
+	if (u) {
+		int i;
+		void *data = u->data;
+		struct nf_conntrack *p = u->ct;
+
+		for (i = 0; i < c->num_features; i++) {
+			c->features[i]->destroy(u, data);
+			data += c->features[i]->size;
+		}
+
+		if (c->extra)
+			c->extra->destroy(u, ((void *) u) + c->extra_offset);
+
+		hashtable_del(c->h, u);
+		free(p);
+		return 1;
+	}
+	return 0;
+}
+
+int __cache_del(struct cache *c, struct nf_conntrack *ct)
+{
+	if (__del(c, ct)) {
+		c->del_ok++;
+		return 1;
+	}
+	c->del_fail++;
+
+	return 0;
+}
+
+int cache_del(struct cache *c, struct nf_conntrack *ct)
+{
+	int ret;
+
+	lock();
+	ret = __cache_del(c, ct);
+	unlock();
+
+	return ret;
+}
+
+struct us_conntrack *cache_get_conntrack(struct cache *c, void *data)
+{
+	return data - c->extra_offset;
+}
+
+void *cache_get_extra(struct cache *c, void *data)
+{
+	return data + c->extra_offset;
+}
+
+void cache_stats(struct cache *c, int fd)
+{
+	char buf[512];
+	int size;
+
+	lock();
+	size = sprintf(buf, "cache %s:\n"
+			    "current active connections:\t%12u\n"
+			    "connections created:\t\t%12u\tfailed:\t%12u\n"
+			    "connections updated:\t\t%12u\tfailed:\t%12u\n"
+			    "connections destroyed:\t\t%12u\tfailed:\t%12u\n\n",
+			    			 c->name,
+			    			 hashtable_counter(c->h),
+			    			 c->add_ok, 
+			    			 c->add_fail,
+						 c->upd_ok,
+						 c->upd_fail,
+						 c->del_ok,
+						 c->del_fail);
+	unlock();
+	send(fd, buf, size, 0);
+}
diff --git a/src/cache_iterators.c b/src/cache_iterators.c
new file mode 100644
index 0000000..5d5d22b
--- /dev/null
+++ b/src/cache_iterators.c
@@ -0,0 +1,229 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cache.h"
+#include "jhash.h"
+#include "hash.h"
+#include "conntrackd.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include "debug.h"
+
+struct __dump_container {
+	int fd;
+	int type;
+};
+
+static int do_dump(void *data1, void *data2)
+{
+	char buf[1024];
+	int size;
+	struct __dump_container *container = data1;
+	struct us_conntrack *u = data2;
+	void *data = u->data;
+	int i;
+
+	memset(buf, 0, sizeof(buf));
+	size = nfct_snprintf(buf, 
+			     sizeof(buf), 
+			     u->ct, 
+			     NFCT_T_UNKNOWN, 
+			     container->type,
+			     0);
+
+	for (i = 0; i < u->cache->num_features; i++) {
+		if (u->cache->features[i]->dump) {
+			size += u->cache->features[i]->dump(u, 
+							    data, 
+							    buf+size,
+							    container->type);
+			data += u->cache->features[i]->size;
+		}
+	}
+	size += sprintf(buf+size, "\n");
+	if (send(container->fd, buf, size, 0) == -1) {
+		if (errno != EPIPE)
+			return -1;
+	}
+
+	return 0;
+}
+
+void cache_dump(struct cache *c, int fd, int type)
+{
+	struct __dump_container tmp = {
+		.fd	= fd,
+		.type	= type
+	};
+
+	lock();
+	hashtable_iterate(c->h, (void *) &tmp, do_dump);
+	unlock();
+}
+
+static int do_commit(void *data1, void *data2)
+{
+	int ret;
+	struct cache *c = data1;
+	struct us_conntrack *u = data2;
+	struct nf_conntrack *ct;
+	char buf[4096];
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
+
+	ct = nfct_clone(u->ct);
+	if (ct == NULL)
+		return 0;
+
+	if (nfct_attr_is_set(ct, ATTR_STATUS)) {
+		u_int32_t status = nfct_get_attr_u32(ct, ATTR_STATUS);
+		status &= ~IPS_EXPECTED;
+		nfct_set_attr_u32(ct, ATTR_STATUS, status);
+	}
+
+	if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT))
+		nfct_setobjopt(ct, NFCT_SOPT_UNDO_SNAT);
+	if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT))
+		nfct_setobjopt(ct, NFCT_SOPT_UNDO_DNAT);
+	if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT))
+		nfct_setobjopt(ct, NFCT_SOPT_UNDO_SPAT);
+	if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT))
+		nfct_setobjopt(ct, NFCT_SOPT_UNDO_DPAT);
+
+        /* 
+	 * Set a reduced timeout for candidate-to-be-committed
+	 * conntracks that live in the external cache
+	 */
+	nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout));
+
+        ret = nfct_build_query(STATE(subsys_sync),
+			       NFCT_Q_CREATE,
+			       ct,
+			       nlh,
+			       sizeof(buf));
+
+	free(ct);
+
+	if (ret == -1) {
+		/* XXX: Please cleanup this debug crap, default in logfile */
+		debug("--- failed to build: %s --- \n", strerror(errno));
+		return 0;
+	}
+
+	ret = nfnl_query(STATE(sync), nlh);
+	if (ret == -1) {
+		switch(errno) {
+			case EEXIST:
+				c->commit_exist++;
+				break;
+			default:
+				c->commit_fail++;
+				break;
+		}
+		debug("--- failed to commit: %s --- \n", strerror(errno));
+	} else {
+		c->commit_ok++;
+		debug("----- commit -----\n");
+	}
+
+	/* keep iterating even if we have found errors */
+	return 0;
+}
+
+void cache_commit(struct cache *c)
+{
+	unsigned int commit_ok = c->commit_ok;
+	unsigned int commit_exist = c->commit_exist;
+	unsigned int commit_fail = c->commit_fail;
+
+	lock();
+	hashtable_iterate(c->h, c, do_commit);
+	unlock();
+
+	/* calculate new entries committed */
+	commit_ok = c->commit_ok - commit_ok;
+	commit_fail = c->commit_fail - commit_fail;
+	commit_exist = c->commit_exist - commit_exist;
+
+	/* log results */
+	dlog(STATE(log), "Committed %u new entries", commit_ok);
+
+	if (commit_exist)
+		dlog(STATE(log), "%u entries ignored, "
+				 "already exist", commit_exist);
+	if (commit_fail)
+		dlog(STATE(log), "%u entries can't be "
+				 "committed", commit_fail);
+}
+
+static int do_flush(void *data1, void *data2)
+{
+	struct cache *c = data1;
+	struct us_conntrack *u = data2;
+	void *data = u->data;
+	int i;
+
+	for (i = 0; i < c->num_features; i++) {
+		c->features[i]->destroy(u, data);
+		data += c->features[i]->size;
+	}
+	free(u->ct);
+
+	return 0;
+}
+
+void cache_flush(struct cache *c)
+{
+	lock();
+	hashtable_iterate(c->h, c, do_flush);
+	hashtable_flush(c->h);
+	c->flush++;
+	unlock();
+}
+
+#include "sync.h"
+#include "network.h"
+
+static int do_bulk(void *data1, void *data2)
+{
+	int ret;
+	struct us_conntrack *u = data2;
+	char buf[4096];
+	struct nlnetwork *net = (struct nlnetwork *) buf;
+
+	ret = build_network_msg(NFCT_Q_UPDATE,
+				STATE(subsys_sync),
+				u->ct,
+				buf,
+				sizeof(buf));
+	if (ret == -1)
+		debug_ct(u->ct, "failed to build");
+
+	mcast_send_netmsg(STATE_SYNC(mcast_client), net);
+	STATE_SYNC(mcast_sync)->post_send(net, u);
+
+	/* keep iterating even if we have found errors */
+	return 0;
+}
+
+void cache_bulk(struct cache *c)
+{
+	lock();
+	hashtable_iterate(c->h, NULL, do_bulk);
+	unlock();
+}
diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c
new file mode 100644
index 0000000..ae54df2
--- /dev/null
+++ b/src/cache_lifetime.c
@@ -0,0 +1,65 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include "conntrackd.h"
+#include "us-conntrack.h"
+#include "cache.h"
+#include "alarm.h"
+
+static void lifetime_add(struct us_conntrack *u, void *data)
+{
+	long *lifetime = data;
+	struct timeval tv;
+
+	gettimeofday(&tv, NULL);
+
+	*lifetime = tv.tv_sec;
+}
+
+static void lifetime_update(struct us_conntrack *u, void *data)
+{
+}
+
+static void lifetime_destroy(struct us_conntrack *u, void *data)
+{
+}
+
+static int lifetime_dump(struct us_conntrack *u, 
+			 void *data, 
+			 char *buf, 
+			 int type)
+{
+	long *lifetime = data;
+	struct timeval tv;
+
+	if (type == NFCT_O_XML)
+		return 0;
+
+	gettimeofday(&tv, NULL);
+
+	return sprintf(buf, " [active since %lds]", tv.tv_sec - *lifetime);
+}
+
+struct cache_feature lifetime_feature = {
+	.size		= sizeof(long),
+	.add		= lifetime_add,
+	.update		= lifetime_update,
+	.destroy	= lifetime_destroy,
+	.dump		= lifetime_dump
+};
diff --git a/src/cache_timer.c b/src/cache_timer.c
new file mode 100644
index 0000000..213b59a
--- /dev/null
+++ b/src/cache_timer.c
@@ -0,0 +1,72 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include "conntrackd.h"
+#include "us-conntrack.h"
+#include "cache.h"
+#include "alarm.h"
+
+static void timeout(struct alarm_list *a, void *data)
+{
+	struct us_conntrack *u = data;
+
+	debug_ct(u->ct, "expired timeout");
+	__cache_del(u->cache, u->ct);
+}
+
+static void timer_add(struct us_conntrack *u, void *data)
+{
+	struct alarm_list *alarm = data;
+
+	init_alarm(alarm);
+	set_alarm_expiration(alarm, CONFIG(cache_timeout));
+	set_alarm_data(alarm, u);
+	set_alarm_function(alarm, timeout);
+	add_alarm(alarm);
+}
+
+static void timer_update(struct us_conntrack *u, void *data)
+{
+	struct alarm_list *alarm = data;
+	mod_alarm(alarm, CONFIG(cache_timeout));
+}
+
+static void timer_destroy(struct us_conntrack *u, void *data)
+{
+	struct alarm_list *alarm = data;
+	del_alarm(alarm);
+}
+
+static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type)
+{
+ 	struct alarm_list *alarm = data;
+
+	if (type == NFCT_O_XML)
+		return 0;
+
+	return sprintf(buf, " [expires in %ds]", alarm->expires);
+}
+
+struct cache_feature timer_feature = {
+	.size		= sizeof(struct alarm_list),
+	.add		= timer_add,
+	.update		= timer_update,
+	.destroy	= timer_destroy,
+	.dump		= timer_dump
+};
diff --git a/src/checksum.c b/src/checksum.c
new file mode 100644
index 0000000..41866ff
--- /dev/null
+++ b/src/checksum.c
@@ -0,0 +1,32 @@
+/* 
+ * Extracted from RFC 1071 with some minor changes to fix compilation on GCC,
+ * this can probably be improved
+ * 					--pablo 11/feb/07
+ */
+
+#include <conntrackd.h>
+
+unsigned short do_csum(const void *addr, unsigned int count)
+{
+	unsigned int sum = 0;
+
+	/* checksumming disabled, just skip */
+	if (CONFIG(flags) & DONT_CHECKSUM)
+		return 0;
+
+	while(count > 1)  {
+		/*  This is the inner loop */
+		sum += *((unsigned short *) addr++);
+		count -= 2;
+	}
+
+	/*  Add left-over byte, if any */
+	if(count > 0)
+		sum += *((unsigned char *) addr);
+
+	/*  Fold 32-bit sum to 16 bits */
+	while (sum>>16)
+		sum = (sum & 0xffff) + (sum >> 16);
+
+	return ~sum;
+}
diff --git a/src/conntrack.c b/src/conntrack.c
new file mode 100644
index 0000000..30fbf69
--- /dev/null
+++ b/src/conntrack.c
@@ -0,0 +1,1131 @@
+/*
+ * (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.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Note:
+ *	Yes, portions of this code has been stolen from iptables ;)
+ *	Special thanks to the the Netfilter Core Team.
+ *	Thanks to Javier de Miguel Rodriguez <jmiguel at talika.eii.us.es>
+ *	for introducing me to advanced firewalling stuff.
+ *
+ *						--pablo 13/04/2005
+ *
+ * 2005-04-16 Harald Welte <laforge@netfilter.org>: 
+ * 	Add support for conntrack accounting and conntrack mark
+ * 2005-06-23 Harald Welte <laforge@netfilter.org>:
+ * 	Add support for expect creation
+ * 2005-09-24 Harald Welte <laforge@netfilter.org>:
+ * 	Remove remaints of "-A"
+ *
+ */
+#include <stdio.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <string.h>
+#include "linux_list.h"
+#include "conntrack.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_ipv4.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_ipv6.h>
+
+static const char cmdflags[NUMBER_OF_CMD]
+= {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'};
+
+static const char cmd_need_param[NUMBER_OF_CMD]
+= { 2,  0,  0,  0,  0,  2,  2,  2,  2,  2,  0,  0,  0,  2,  2 };
+
+static const char optflags[NUMBER_OF_OPT]
+= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f'};
+
+static struct option original_opts[] = {
+	{"dump", 2, 0, 'L'},
+	{"create", 1, 0, 'I'},
+	{"delete", 1, 0, 'D'},
+	{"update", 1, 0, 'U'},
+	{"get", 1, 0, 'G'},
+	{"flush", 1, 0, 'F'},
+	{"event", 1, 0, 'E'},
+	{"version", 0, 0, 'V'},
+	{"help", 0, 0, 'h'},
+	{"orig-src", 1, 0, 's'},
+	{"orig-dst", 1, 0, 'd'},
+	{"reply-src", 1, 0, 'r'},
+	{"reply-dst", 1, 0, 'q'},
+	{"protonum", 1, 0, 'p'},
+	{"timeout", 1, 0, 't'},
+	{"status", 1, 0, 'u'},
+	{"zero", 0, 0, 'z'},
+	{"event-mask", 1, 0, 'e'},
+	{"tuple-src", 1, 0, '['},
+	{"tuple-dst", 1, 0, ']'},
+	{"mask-src", 1, 0, '{'},
+	{"mask-dst", 1, 0, '}'},
+	{"nat-range", 1, 0, 'a'},
+	{"mark", 1, 0, 'm'},
+	{"id", 2, 0, 'i'},
+	{"family", 1, 0, 'f'},
+	{0, 0, 0, 0}
+};
+
+#define OPTION_OFFSET 256
+
+static struct nfct_handle *cth;
+static struct option *opts = original_opts;
+static unsigned int global_option_offset = 0;
+
+/* Table of legal combinations of commands and options.  If any of the
+ * given commands make an option legal, that option is legal (applies to
+ * CMD_LIST and CMD_ZERO only).
+ * Key:
+ *  0  illegal
+ *  1  compulsory
+ *  2  optional
+ */
+
+static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
+/* Well, it's better than "Re: Linux vs FreeBSD" */
+{
+          /*   s d r q p t u z e x y k l a m i f*/
+/*CT_LIST*/   {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2},
+/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0},
+/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0},
+/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0},
+/*CT_GET*/    {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0},
+/*CT_FLUSH*/  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+/*CT_EVENT*/  {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0},
+/*VERSION*/   {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+/*HELP*/      {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+/*EXP_LIST*/  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2},
+/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0},
+/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0},
+/*EXP_GET*/   {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0},
+/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+};
+
+static char *lib_dir = CONNTRACK_LIB_DIR;
+
+static LIST_HEAD(proto_list);
+
+void register_proto(struct ctproto_handler *h)
+{
+	if (strcmp(h->version, VERSION) != 0) {
+		fprintf(stderr, "plugin `%s': version %s (I'm %s)\n",
+			h->name, h->version, VERSION);
+		exit(1);
+	}
+	list_add(&h->head, &proto_list);
+}
+
+static struct ctproto_handler *findproto(char *name)
+{
+	struct list_head *i;
+	struct ctproto_handler *cur = NULL, *handler = NULL;
+
+	if (!name) 
+		return handler;
+
+	lib_dir = getenv("CONNTRACK_LIB_DIR");
+	if (!lib_dir)
+		lib_dir = CONNTRACK_LIB_DIR;
+
+	list_for_each(i, &proto_list) {
+		cur = (struct ctproto_handler *) i;
+		if (strcmp(cur->name, name) == 0) {
+			handler = cur;
+			break;
+		}
+	}
+
+	if (!handler) {
+		char path[sizeof("ct_proto_.so")
+			 + strlen(name) + strlen(lib_dir)];
+                sprintf(path, "%s/ct_proto_%s.so", lib_dir, name);
+		if (dlopen(path, RTLD_NOW))
+			handler = findproto(name);
+		else
+			fprintf(stderr, "%s\n", dlerror());
+	}
+
+	return handler;
+}
+
+enum exittype {
+        OTHER_PROBLEM = 1,
+        PARAMETER_PROBLEM,
+        VERSION_PROBLEM
+};
+
+void extension_help(struct ctproto_handler *h)
+{
+	fprintf(stdout, "\n");
+	fprintf(stdout, "Proto `%s' help:\n", h->name);
+	h->help();
+}
+
+void
+exit_tryhelp(int status)
+{
+	fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
+			PROGNAME, PROGNAME);
+	exit(status);
+}
+
+static void
+exit_error(enum exittype status, char *msg, ...)
+{
+	va_list args;
+
+	/* On error paths, make sure that we don't leak the memory
+	 * reserved during options merging */
+	if (opts != original_opts) {
+		free(opts);
+		opts = original_opts;
+		global_option_offset = 0;
+	}
+	va_start(args, msg);
+	fprintf(stderr,"%s v%s: ", PROGNAME, VERSION);
+	vfprintf(stderr, msg, args);
+	va_end(args);
+	fprintf(stderr, "\n");
+	if (status == PARAMETER_PROBLEM)
+		exit_tryhelp(status);
+	exit(status);
+}
+
+static void
+generic_cmd_check(int command, int options)
+{
+	int i;
+	
+	for (i = 0; i < NUMBER_OF_CMD; i++) {
+		if (!(command & (1<<i)))
+			continue;
+
+		if (cmd_need_param[i] == 0 && !options)
+			exit_error(PARAMETER_PROBLEM,
+				   "You need to supply parameters to `-%c'\n",
+				   cmdflags[i]);
+	}
+}
+
+static void
+generic_opt_check(int command, int options)
+{
+	int i, j, legal = 0;
+
+	/* Check that commands are valid with options.  Complicated by the
+	 * fact that if an option is legal with *any* command given, it is
+	 * legal overall (ie. -z and -l).
+	 */
+	for (i = 0; i < NUMBER_OF_OPT; i++) {
+		legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
+
+		for (j = 0; j < NUMBER_OF_CMD; j++) {
+			if (!(command & (1<<j)))
+				continue;
+
+			if (!(options & (1<<i))) {
+				if (commands_v_options[j][i] == 1) 
+					exit_error(PARAMETER_PROBLEM, 
+						   "You need to supply the "
+						   "`-%c' option for this "
+						   "command\n", optflags[i]);
+			} else {
+				if (commands_v_options[j][i] != 0)
+					legal = 1;
+				else if (legal == 0)
+					legal = -1;
+			}
+		}
+		if (legal == -1)
+			exit_error(PARAMETER_PROBLEM, "Illegal option `-%c' "
+				   "with this command\n", optflags[i]);
+	}
+}
+
+static struct option *
+merge_options(struct option *oldopts, const struct option *newopts,
+	      unsigned int *option_offset)
+{
+	unsigned int num_old, num_new, i;
+	struct option *merge;
+
+	for (num_old = 0; oldopts[num_old].name; num_old++);
+	for (num_new = 0; newopts[num_new].name; num_new++);
+
+	global_option_offset += OPTION_OFFSET;
+	*option_offset = global_option_offset;
+
+	merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
+	memcpy(merge, oldopts, num_old * sizeof(struct option));
+	for (i = 0; i < num_new; i++) {
+		merge[num_old + i] = newopts[i];
+		merge[num_old + i].val += *option_offset;
+	}
+	memset(merge + num_old + num_new, 0, sizeof(struct option));
+
+	return merge;
+}
+
+/* From linux/errno.h */
+#define ENOTSUPP        524     /* Operation is not supported */
+
+/* Translates errno numbers into more human-readable form than strerror. */
+const char *
+err2str(int err, enum action command)
+{
+	unsigned int i;
+	struct table_struct {
+		enum action act;
+		int err;
+		const char *message;
+	} table [] =
+	  { { CT_LIST, -ENOTSUPP, "function not implemented" },
+	    { 0xFFFF, -EINVAL, "invalid parameters" },
+	    { CT_CREATE, -EEXIST, "Such conntrack exists, try -U to update" },
+	    { CT_CREATE|CT_GET|CT_DELETE, -ENOENT, 
+		    "such conntrack doesn't exist" },
+	    { CT_CREATE|CT_GET, -ENOMEM, "not enough memory" },
+	    { CT_GET, -EAFNOSUPPORT, "protocol not supported" },
+	    { CT_CREATE, -ETIME, "conntrack has expired" },
+	    { EXP_CREATE, -ENOENT, "master conntrack not found" },
+	    { EXP_CREATE, -EINVAL, "invalid parameters" },
+	    { ~0UL, -EPERM, "sorry, you must be root or get "
+		    	    "CAP_NET_ADMIN capability to do this"}
+	  };
+
+	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
+		if ((table[i].act & command) && table[i].err == err)
+			return table[i].message;
+	}
+
+	return strerror(err);
+}
+
+#define PARSE_STATUS 0
+#define PARSE_EVENT 1
+#define PARSE_MAX 2
+
+static struct parse_parameter {
+	char 	*parameter[6];
+	size_t  size;
+	unsigned int value[6];
+} parse_array[PARSE_MAX] = {
+	{ {"ASSURED", "SEEN_REPLY", "UNSET", "SRC_NAT", "DST_NAT","FIXED_TIMEOUT"}, 6,
+	  { IPS_ASSURED, IPS_SEEN_REPLY, 0, 
+	    IPS_SRC_NAT_DONE, IPS_DST_NAT_DONE, IPS_FIXED_TIMEOUT} },
+	{ {"ALL", "NEW", "UPDATES", "DESTROY"}, 4,
+	  {~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE, 
+	   NF_NETLINK_CONNTRACK_DESTROY} },
+};
+
+static int
+do_parse_parameter(const char *str, size_t strlen, unsigned int *value, 
+		   int parse_type)
+{
+	int i, ret = 0;
+	struct parse_parameter *p = &parse_array[parse_type];
+	
+	for (i = 0; i < p->size; i++)
+		if (strncasecmp(str, p->parameter[i], strlen) == 0) {
+			*value |= p->value[i];
+			ret = 1;
+			break;
+		}
+	
+	return ret;
+}
+
+static void
+parse_parameter(const char *arg, unsigned int *status, int parse_type)
+{
+	const char *comma;
+
+	while ((comma = strchr(arg, ',')) != NULL) {
+		if (comma == arg 
+		    || !do_parse_parameter(arg, comma-arg, status, parse_type))
+			exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg);
+		arg = comma+1;
+	}
+
+	if (strlen(arg) == 0
+	    || !do_parse_parameter(arg, strlen(arg), status, parse_type))
+		exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg);
+}
+
+static void
+add_command(unsigned int *cmd, const int newcmd, const int othercmds)
+{
+	if (*cmd & (~othercmds))
+		exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n");
+	*cmd |= newcmd;
+}
+
+unsigned int check_type(int argc, char *argv[])
+{
+	char *table = NULL;
+
+	/* Nasty bug or feature in getopt_long ? 
+	 * It seems that it behaves badly with optional arguments.
+	 * Fortunately, I just stole the fix from iptables ;) */
+	if (optarg)
+		return 0;
+	else if (optind < argc && argv[optind][0] != '-' 
+			&& argv[optind][0] != '!')
+		table = argv[optind++];
+	
+	if (!table)
+		return 0;
+		
+	if (strncmp("expect", table, 6) == 0)
+		return 1;
+	else if (strncmp("conntrack", table, 9) == 0)
+		return 0;
+	else
+		exit_error(PARAMETER_PROBLEM, "unknown type `%s'\n", table);
+
+	return 0;
+}
+
+static void set_family(int *family, int new)
+{
+	if (*family == AF_UNSPEC)
+		*family = new;
+	else if (*family != new)
+		exit_error(PARAMETER_PROBLEM, "mismatched address family\n");
+}
+
+struct addr_parse {
+	struct in_addr addr;
+	struct in6_addr addr6;
+	unsigned int family;
+};
+
+int __parse_inetaddr(const char *cp, struct addr_parse *parse)
+{
+	if (inet_aton(cp, &parse->addr))
+		return AF_INET;
+#ifdef HAVE_INET_PTON_IPV6
+	else if (inet_pton(AF_INET6, cp, &parse->addr6) > 0)
+		return AF_INET6;
+#endif
+
+	exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp);
+}
+
+int parse_inetaddr(const char *cp, union nfct_address *address)
+{
+	struct addr_parse parse;
+	int ret;
+	
+	if ((ret = __parse_inetaddr(cp, &parse)) == AF_INET)
+		address->v4 = parse.addr.s_addr;
+	else if (ret == AF_INET6)
+		memcpy(address->v6, &parse.addr6, sizeof(parse.addr6));
+
+	return ret;
+}
+
+/* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */
+static void
+nat_parse(char *arg, int portok, struct nfct_nat *range)
+{
+	char *colon, *dash, *error;
+	struct addr_parse parse;
+
+	memset(range, 0, sizeof(range));
+	colon = strchr(arg, ':');
+
+	if (colon) {
+		int port;
+
+		if (!portok)
+			exit_error(PARAMETER_PROBLEM,
+				   "Need TCP or UDP with port specification");
+
+		port = atoi(colon+1);
+		if (port == 0 || port > 65535)
+			exit_error(PARAMETER_PROBLEM,
+				   "Port `%s' not valid\n", colon+1);
+
+		error = strchr(colon+1, ':');
+		if (error)
+			exit_error(PARAMETER_PROBLEM,
+				   "Invalid port:port syntax - use dash\n");
+
+		dash = strchr(colon, '-');
+		if (!dash) {
+			range->l4min.tcp.port
+				= range->l4max.tcp.port
+				= htons(port);
+		} else {
+			int maxport;
+
+			maxport = atoi(dash + 1);
+			if (maxport == 0 || maxport > 65535)
+				exit_error(PARAMETER_PROBLEM,
+					   "Port `%s' not valid\n", dash+1);
+			if (maxport < port)
+				/* People are stupid.  */
+				exit_error(PARAMETER_PROBLEM,
+					   "Port range `%s' funky\n", colon+1);
+			range->l4min.tcp.port = htons(port);
+			range->l4max.tcp.port = htons(maxport);
+		}
+		/* Starts with a colon? No IP info... */
+		if (colon == arg)
+			return;
+		*colon = '\0';
+	}
+
+	dash = strchr(arg, '-');
+	if (colon && dash && dash > colon)
+		dash = NULL;
+
+	if (dash)
+		*dash = '\0';
+
+	if (__parse_inetaddr(arg, &parse) != AF_INET)
+		return;
+
+	range->min_ip = parse.addr.s_addr;
+	if (dash) {
+		if (__parse_inetaddr(dash+1, &parse) != AF_INET)
+			return;
+		range->max_ip = parse.addr.s_addr;
+	} else
+		range->max_ip = parse.addr.s_addr;
+}
+
+static void event_sighandler(int s)
+{
+	fprintf(stdout, "Now closing conntrack event dumping...\n");
+	nfct_close(cth);
+	exit(0);
+}
+
+static const char usage_commands[] =
+	"Commands:\n"
+	"  -L [table] [options]\t\tList conntrack or expectation table\n"
+	"  -G [table] parameters\t\tGet conntrack or expectation\n"
+	"  -D [table] parameters\t\tDelete conntrack or expectation\n"
+	"  -I [table] parameters\t\tCreate a conntrack or expectation\n"
+	"  -U [table] parameters\t\tUpdate a conntrack\n"
+	"  -E [table] [options]\t\tShow events\n"
+	"  -F [table]\t\t\tFlush table\n";
+
+static const char usage_tables[] =
+	"Tables: conntrack, expect\n";
+
+static const char usage_conntrack_parameters[] =
+	"Conntrack parameters and options:\n"
+	"  -a, --nat-range min_ip[-max_ip]\tNAT ip range\n"
+	"  -m, --mark mark\t\t\tSet mark\n"
+	"  -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n"
+	"  -z, --zero \t\t\t\tZero counters while listing\n"
+	;
+
+static const char usage_expectation_parameters[] =
+	"Expectation parameters and options:\n"
+	"  --tuple-src ip\tSource address in expect tuple\n"
+	"  --tuple-dst ip\tDestination address in expect tuple\n"
+	"  --mask-src ip\t\tSource mask address\n"
+	"  --mask-dst ip\t\tDestination mask address\n";
+
+static const char usage_parameters[] =
+	"Common parameters and options:\n"
+	"  -s, --orig-src ip\t\tSource address from original direction\n"
+	"  -d, --orig-dst ip\t\tDestination address from original direction\n"
+	"  -r, --reply-src ip\t\tSource addres from reply direction\n"
+	"  -q, --reply-dst ip\t\tDestination address from reply direction\n"
+	"  -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n"
+	"  -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n"
+	"  -t, --timeout timeout\t\tSet timeout\n"
+	"  -u, --status status\t\tSet status, eg. ASSURED\n"
+	"  -i, --id [id]\t\t\tShow or set conntrack ID\n"
+	;
+  
+
+void usage(char *prog) {
+	fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION);
+	fprintf(stdout, "Usage: %s [commands] [options]\n", prog);
+
+	fprintf(stdout, "\n%s", usage_commands);
+	fprintf(stdout, "\n%s", usage_tables);
+	fprintf(stdout, "\n%s", usage_conntrack_parameters);
+	fprintf(stdout, "\n%s", usage_expectation_parameters);
+	fprintf(stdout, "\n%s", usage_parameters);
+}
+
+#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK)
+
+static struct nfct_tuple orig, reply, mask;
+static struct nfct_tuple exptuple;
+static struct ctproto_handler *h;
+static union nfct_protoinfo proto;
+static struct nfct_nat range;
+static struct nfct_conntrack *ct;
+static struct nfct_expect *exp;
+static unsigned long timeout;
+static unsigned int status;
+static unsigned int mark;
+static unsigned int id = NFCT_ANY_ID;
+static struct nfct_conntrack_compare cmp;
+
+int main(int argc, char *argv[])
+{
+	int c;
+	unsigned int command = 0, options = 0;
+	unsigned int type = 0, event_mask = 0;
+	unsigned int l3flags = 0, l4flags = 0, metaflags = 0;
+	int res = 0;
+	int family = AF_UNSPEC;
+	struct nfct_conntrack_compare *pcmp;
+
+	while ((c = getopt_long(argc, argv, 
+		"L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:", 
+		opts, NULL)) != -1) {
+	switch(c) {
+		case 'L':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_LIST, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_LIST, CT_NONE);
+			break;
+		case 'I':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_CREATE, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_CREATE, CT_NONE);
+			break;
+		case 'U':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_UPDATE, CT_NONE);
+			else
+				exit_error(PARAMETER_PROBLEM, "Can't update "
+					   "expectations");
+			break;
+		case 'D':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_DELETE, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_DELETE, CT_NONE);
+			break;
+		case 'G':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_GET, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_GET, CT_NONE);
+			break;
+		case 'F':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_FLUSH, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_FLUSH, CT_NONE);
+			break;
+		case 'E':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_EVENT, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_EVENT, CT_NONE);
+			break;
+		case 'V':
+			add_command(&command, CT_VERSION, CT_NONE);
+			break;
+		case 'h':
+			add_command(&command, CT_HELP, CT_NONE);
+			break;
+		case 's':
+			options |= CT_OPT_ORIG_SRC;
+			if (optarg) {
+				orig.l3protonum =
+					parse_inetaddr(optarg, &orig.src);
+				set_family(&family, orig.l3protonum);
+				if (orig.l3protonum == AF_INET)
+					l3flags |= IPV4_ORIG_SRC;
+				else if (orig.l3protonum == AF_INET6)
+					l3flags |= IPV6_ORIG_SRC;
+			}
+			break;
+		case 'd':
+			options |= CT_OPT_ORIG_DST;
+			if (optarg) {
+				orig.l3protonum = 
+					parse_inetaddr(optarg, &orig.dst);
+				set_family(&family, orig.l3protonum);
+				if (orig.l3protonum == AF_INET)
+					l3flags |= IPV4_ORIG_DST;
+				else if (orig.l3protonum == AF_INET6)
+					l3flags |= IPV6_ORIG_DST;
+			}
+			break;
+		case 'r':
+			options |= CT_OPT_REPL_SRC;
+			if (optarg) {
+				reply.l3protonum = 
+					parse_inetaddr(optarg, &reply.src);
+				set_family(&family, reply.l3protonum);
+				if (orig.l3protonum == AF_INET)
+					l3flags |= IPV4_REPL_SRC;
+				else if (orig.l3protonum == AF_INET6)
+					l3flags |= IPV6_REPL_SRC;
+			}
+			break;
+		case 'q':
+			options |= CT_OPT_REPL_DST;
+			if (optarg) {
+				reply.l3protonum = 
+					parse_inetaddr(optarg, &reply.dst);
+				set_family(&family, reply.l3protonum);
+				if (orig.l3protonum == AF_INET)
+					l3flags |= IPV4_REPL_DST;
+				else if (orig.l3protonum == AF_INET6)
+					l3flags |= IPV6_REPL_DST;
+			}
+			break;
+		case 'p':
+			options |= CT_OPT_PROTO;
+			h = findproto(optarg);
+			if (!h)
+				exit_error(PARAMETER_PROBLEM, "proto needed\n");
+			orig.protonum = h->protonum;
+			reply.protonum = h->protonum;
+			exptuple.protonum = h->protonum;
+			mask.protonum = h->protonum;
+			opts = merge_options(opts, h->opts, 
+					     &h->option_offset);
+			break;
+		case 't':
+			options |= CT_OPT_TIMEOUT;
+			if (optarg)
+				timeout = atol(optarg);
+			break;
+		case 'u': {
+			if (!optarg)
+				continue;
+
+			options |= CT_OPT_STATUS;
+			parse_parameter(optarg, &status, PARSE_STATUS);
+			break;
+		}
+		case 'e':
+			options |= CT_OPT_EVENT_MASK;
+			parse_parameter(optarg, &event_mask, PARSE_EVENT);
+			break;
+		case 'z':
+			options |= CT_OPT_ZERO;
+			break;
+		case '{':
+			options |= CT_OPT_MASK_SRC;
+			if (optarg) {
+				mask.l3protonum = 
+					parse_inetaddr(optarg, &mask.src);
+				set_family(&family, mask.l3protonum);
+			}
+			break;
+		case '}':
+			options |= CT_OPT_MASK_DST;
+			if (optarg) {
+				mask.l3protonum = 
+					parse_inetaddr(optarg, &mask.dst);
+				set_family(&family, mask.l3protonum);
+			}
+			break;
+		case '[':
+			options |= CT_OPT_EXP_SRC;
+			if (optarg) {
+				exptuple.l3protonum = 
+					parse_inetaddr(optarg, &exptuple.src);
+				set_family(&family, exptuple.l3protonum);
+			}
+			break;
+		case ']':
+			options |= CT_OPT_EXP_DST;
+			if (optarg) {
+				exptuple.l3protonum = 
+					parse_inetaddr(optarg, &exptuple.dst);
+				set_family(&family, exptuple.l3protonum);
+			}
+			break;
+		case 'a':
+			options |= CT_OPT_NATRANGE;
+			set_family(&family, AF_INET);
+			nat_parse(optarg, 1, &range);
+			break;
+		case 'm':
+			options |= CT_OPT_MARK;
+			mark = atol(optarg);
+			metaflags |= NFCT_MARK;
+			break;
+		case 'i': {
+			char *s = NULL;
+			options |= CT_OPT_ID;
+			if (optarg)
+				break;
+			else if (optind < argc && argv[optind][0] != '-'
+					&& argv[optind][0] != '!')
+				s = argv[optind++];
+
+			if (s)
+				id = atol(s);
+			break;
+		}
+		case 'f':
+			options |= CT_OPT_FAMILY;
+			if (strncmp(optarg, "ipv4", strlen("ipv4")) == 0)
+				set_family(&family, AF_INET);
+			else if (strncmp(optarg, "ipv6", strlen("ipv6")) == 0)
+				set_family(&family, AF_INET6);
+			else
+				exit_error(PARAMETER_PROBLEM, "Unknown "
+					   "protocol family\n");
+			break;
+		default:
+			if (h && h->parse_opts 
+			    &&!h->parse_opts(c - h->option_offset, argv, &orig, 
+				             &reply, &exptuple, &mask, &proto, 
+					     &l4flags))
+				exit_error(PARAMETER_PROBLEM, "parse error\n");
+
+			/* Unknown argument... */
+			if (!h) {
+				usage(argv[0]);
+				exit_error(PARAMETER_PROBLEM, "Missing "
+					   "arguments...\n");
+			}
+			break;
+		}
+	}
+
+	/* default family */
+	if (family == AF_UNSPEC)
+		family = AF_INET;
+
+	generic_cmd_check(command, options);
+	generic_opt_check(command, options);
+
+	if (!(command & CT_HELP)
+	    && h && h->final_check 
+	    && !h->final_check(l4flags, command, &orig, &reply)) {
+		usage(argv[0]);
+		extension_help(h);
+		exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n");
+	}
+
+	switch(command) {
+
+	case CT_LIST:
+		cth = nfct_open(CONNTRACK, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+
+		if (options & CT_COMPARISON) {
+
+			if (options & CT_OPT_ZERO)
+				exit_error(PARAMETER_PROBLEM, "Can't use -z "
+					   "with filtering parameters");
+
+			ct = nfct_conntrack_alloc(&orig, &reply, timeout,
+						  &proto, status, mark, id,
+						  NULL);
+			if (!ct)
+				exit_error(OTHER_PROBLEM, "Not enough memory");
+			
+			cmp.ct = ct;
+			cmp.flags = metaflags;
+			cmp.l3flags = l3flags;
+			cmp.l4flags = l4flags;
+			pcmp = &cmp;
+		}
+
+		if (options & CT_OPT_ID)
+			nfct_register_callback(cth, 
+					nfct_default_conntrack_display_id,
+					(void *) pcmp);
+		else
+			nfct_register_callback(cth,
+					nfct_default_conntrack_display,
+					(void *) pcmp);
+			
+		if (options & CT_OPT_ZERO)
+			res = 
+			nfct_dump_conntrack_table_reset_counters(cth, family);
+		else
+			res = nfct_dump_conntrack_table(cth, family);
+		nfct_close(cth);
+		break;
+
+	case EXP_LIST:
+		cth = nfct_open(EXPECT, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		if (options & CT_OPT_ID)
+			nfct_register_callback(cth, 
+					nfct_default_expect_display_id,
+					NULL);
+		else
+			nfct_register_callback(cth,
+					nfct_default_expect_display,
+					NULL);
+		res = nfct_dump_expect_list(cth, family);
+		nfct_close(cth);
+		break;
+			
+	case CT_CREATE:
+		if ((options & CT_OPT_ORIG) 
+		    && !(options & CT_OPT_REPL)) {
+			reply.l3protonum = orig.l3protonum;
+			memcpy(&reply.src, &orig.dst, sizeof(reply.src));
+			memcpy(&reply.dst, &orig.src, sizeof(reply.dst));
+		} else if (!(options & CT_OPT_ORIG)
+			   && (options & CT_OPT_REPL)) {
+			orig.l3protonum = reply.l3protonum;
+			memcpy(&orig.src, &reply.dst, sizeof(orig.src));
+			memcpy(&orig.dst, &reply.src, sizeof(orig.dst));
+		}
+		if (options & CT_OPT_NATRANGE)
+			ct = nfct_conntrack_alloc(&orig, &reply, timeout, 
+						  &proto, status, mark, id,
+						  &range);
+		else
+			ct = nfct_conntrack_alloc(&orig, &reply, timeout, 
+						  &proto, status, mark, id,
+						  NULL);
+		if (!ct)
+			exit_error(OTHER_PROBLEM, "Not Enough memory");
+		
+		cth = nfct_open(CONNTRACK, 0);
+		if (!cth) {
+			nfct_conntrack_free(ct);
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		}
+		res = nfct_create_conntrack(cth, ct);
+		nfct_close(cth);
+		nfct_conntrack_free(ct);
+		break;
+
+	case EXP_CREATE:
+		if (options & CT_OPT_ORIG)
+			exp = nfct_expect_alloc(&orig, &exptuple,
+						&mask, timeout, id);
+		else if (options & CT_OPT_REPL)
+			exp = nfct_expect_alloc(&reply, &exptuple,
+						&mask, timeout, id);
+		if (!exp)
+			exit_error(OTHER_PROBLEM, "Not enough memory");
+
+		cth = nfct_open(EXPECT, 0);
+		if (!cth) {
+			nfct_expect_free(exp);
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		}
+		res = nfct_create_expectation(cth, exp);
+		nfct_expect_free(exp);
+		nfct_close(cth);
+		break;
+
+	case CT_UPDATE:
+		if ((options & CT_OPT_ORIG) 
+		    && !(options & CT_OPT_REPL)) {
+			reply.l3protonum = orig.l3protonum;
+			memcpy(&reply.src, &orig.dst, sizeof(reply.src));
+			memcpy(&reply.dst, &orig.src, sizeof(reply.dst));
+		} else if (!(options & CT_OPT_ORIG)
+			   && (options & CT_OPT_REPL)) {
+			orig.l3protonum = reply.l3protonum;
+			memcpy(&orig.src, &reply.dst, sizeof(orig.src));
+			memcpy(&orig.dst, &reply.src, sizeof(orig.dst));
+		}
+		ct = nfct_conntrack_alloc(&orig, &reply, timeout,
+					  &proto, status, mark, id,
+					  NULL);
+		if (!ct)
+			exit_error(OTHER_PROBLEM, "Not enough memory");
+		
+		cth = nfct_open(CONNTRACK, 0);
+		if (!cth) {
+			nfct_conntrack_free(ct);
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		}
+		res = nfct_update_conntrack(cth, ct);
+		nfct_conntrack_free(ct);
+		nfct_close(cth);
+		break;
+		
+	case CT_DELETE:
+		if (!(options & CT_OPT_ORIG) && !(options & CT_OPT_REPL))
+			exit_error(PARAMETER_PROBLEM, "Can't kill conntracks "
+						      "just by its ID");
+		cth = nfct_open(CONNTRACK, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		if (options & CT_OPT_ORIG)
+			res = nfct_delete_conntrack(cth, &orig, 
+						    NFCT_DIR_ORIGINAL,
+						    id);
+		else if (options & CT_OPT_REPL)
+			res = nfct_delete_conntrack(cth, &reply, 
+						    NFCT_DIR_REPLY,
+						    id);
+		nfct_close(cth);
+		break;
+
+	case EXP_DELETE:
+		cth = nfct_open(EXPECT, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		if (options & CT_OPT_ORIG)
+			res = nfct_delete_expectation(cth, &orig, id);
+		else if (options & CT_OPT_REPL)
+			res = nfct_delete_expectation(cth, &reply, id);
+		nfct_close(cth);
+		break;
+
+	case CT_GET:
+		cth = nfct_open(CONNTRACK, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		nfct_register_callback(cth, nfct_default_conntrack_display,
+					NULL);
+		if (options & CT_OPT_ORIG)
+			res = nfct_get_conntrack(cth, &orig,
+						 NFCT_DIR_ORIGINAL, id);
+		else if (options & CT_OPT_REPL)
+			res = nfct_get_conntrack(cth, &reply,
+						 NFCT_DIR_REPLY, id);
+		nfct_close(cth);
+		break;
+
+	case EXP_GET:
+		cth = nfct_open(EXPECT, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		nfct_register_callback(cth, nfct_default_expect_display,
+					NULL);
+		if (options & CT_OPT_ORIG)
+			res = nfct_get_expectation(cth, &orig, id);
+		else if (options & CT_OPT_REPL)
+			res = nfct_get_expectation(cth, &reply, id);
+		nfct_close(cth);
+		break;
+
+	case CT_FLUSH:
+		cth = nfct_open(CONNTRACK, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		res = nfct_flush_conntrack_table(cth, AF_INET);
+		nfct_close(cth);
+		break;
+
+	case EXP_FLUSH:
+		cth = nfct_open(EXPECT, 0);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		res = nfct_flush_expectation_table(cth, AF_INET);
+		nfct_close(cth);
+		break;
+		
+	case CT_EVENT:
+		if (options & CT_OPT_EVENT_MASK)
+			cth = nfct_open(CONNTRACK, event_mask);
+		else
+			cth = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS);
+
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		signal(SIGINT, event_sighandler);
+
+		if (options & CT_COMPARISON) {
+			ct = nfct_conntrack_alloc(&orig, &reply, timeout,
+						  &proto, status, mark, id, 
+						  NULL);
+			if (!ct)
+				exit_error(OTHER_PROBLEM, "Not enough memory");
+
+			cmp.ct = ct;
+			cmp.flags = metaflags;
+			cmp.l3flags = l3flags;
+			cmp.l4flags = l4flags;
+			pcmp = &cmp;
+		}
+
+		nfct_register_callback(cth,
+				       nfct_default_conntrack_event_display, 
+				       (void *) pcmp);
+		res = nfct_event_conntrack(cth);
+		nfct_close(cth);
+		break;
+
+	case EXP_EVENT:
+		cth = nfct_open(EXPECT, NF_NETLINK_CONNTRACK_EXP_NEW);
+		if (!cth)
+			exit_error(OTHER_PROBLEM, "Can't open handler");
+		signal(SIGINT, event_sighandler);
+		nfct_register_callback(cth, nfct_default_expect_display,
+					NULL);
+		res = nfct_event_expectation(cth);
+		nfct_close(cth);
+		break;
+			
+	case CT_VERSION:
+		fprintf(stdout, "%s v%s\n", PROGNAME, VERSION);
+		break;
+	case CT_HELP:
+		usage(argv[0]);
+		if (options & CT_OPT_PROTO)
+			extension_help(h);
+		break;
+	default:
+		usage(argv[0]);
+		break;
+	}
+
+	if (opts != original_opts) {
+		free(opts);
+		opts = original_opts;
+		global_option_offset = 0;
+	}
+
+	if (res < 0) {
+		fprintf(stderr, "Operation failed: %s\n", err2str(res, command));
+		exit(OTHER_PROBLEM);
+	}
+
+	return 0;
+}
diff --git a/src/hash.c b/src/hash.c
new file mode 100644
index 0000000..274a140
--- /dev/null
+++ b/src/hash.c
@@ -0,0 +1,199 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: generic hash table implementation
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include "slist.h"
+#include "hash.h"
+
+
+struct hashtable_node *hashtable_alloc_node(int datasize, void *data)
+{
+	struct hashtable_node *n;
+	int size = sizeof(struct hashtable_node) + datasize;
+
+	n = malloc(size);
+	if (!n)
+		return NULL;
+	memset(n, 0, size);
+	memcpy(n->data, data, datasize);
+
+	return n;
+}
+
+void hashtable_destroy_node(struct hashtable_node *h)
+{
+	free(h);
+}
+
+struct hashtable *
+hashtable_create(int hashsize, int limit, int datasize,
+		 u_int32_t (*hash)(const void *data, struct hashtable *table),
+		 int (*compare)(const void *data1, const void *data2))
+{
+	int i;
+	struct hashtable *h;
+	struct hashtype *t;
+	int size = sizeof(struct hashtable)
+		   + hashsize * sizeof(struct slist_head);
+
+	h = (struct hashtable *) malloc(size);
+	if (!h) {
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	memset(h, 0, size);
+	for (i=0; i<hashsize; i++)
+		INIT_SLIST_HEAD(h->members[i]);
+
+	h->hashsize = hashsize;
+	h->limit = limit;
+	h->datasize = datasize;
+	h->hash = hash;
+	h->compare = compare;
+
+	return h;
+}
+
+void hashtable_destroy(struct hashtable *h)
+{
+	hashtable_flush(h);
+	free(h);
+}
+
+void *hashtable_add(struct hashtable *table, void *data)
+{
+	struct slist_head *e;
+	struct hashtable_node *n;
+	u_int32_t id;
+	int i;
+
+	/* hash table is full */
+	if (table->count >= table->limit) {
+		errno = ENOSPC;
+		return NULL;
+	}
+
+	id = table->hash(data, table);
+
+	slist_for_each(e, &table->members[id]) {
+		n = slist_entry(e, struct hashtable_node, head);
+		if (table->compare(n->data, data)) {
+			errno = EEXIST;
+			return NULL;
+		}
+	}
+
+	n = hashtable_alloc_node(table->datasize, data);
+	if (n == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	slist_add(&table->members[id], &n->head);
+	table->count++;
+
+	return n->data;
+}
+
+void *hashtable_test(struct hashtable *table, const void *data)
+{
+	struct slist_head *e;
+	u_int32_t id;
+	struct hashtable_node *n;
+	int i;
+
+	id = table->hash(data, table);
+
+	slist_for_each(e, &table->members[id]) {
+		n = slist_entry(e, struct hashtable_node, head);
+		if (table->compare(n->data, data))
+			return n->data;
+	}
+
+	errno = ENOENT;
+	return NULL;
+}
+
+int hashtable_del(struct hashtable *table, void *data)
+{
+	struct slist_head *e, *next, *prev;
+	u_int32_t id;
+	struct hashtable_node *n;
+	int i;
+
+	id = table->hash(data, table);
+
+	slist_for_each_safe(e, prev, next, &table->members[id]) {
+		n = slist_entry(e, struct hashtable_node, head);
+		if (table->compare(n->data, data)) {
+			slist_del(e, prev);
+			hashtable_destroy_node(n);
+			table->count--;
+			return 0;
+		}
+	}
+	errno = ENOENT;
+	return -1;
+}
+
+int hashtable_flush(struct hashtable *table)
+{
+	int i;
+	struct slist_head *e, *next, *prev;
+	struct hashtable_node *n;
+
+	for (i=0; i < table->hashsize; i++)
+		slist_for_each_safe(e, prev, next, &table->members[i]) {
+			n = slist_entry(e, struct hashtable_node, head);
+			slist_del(e, prev);
+			hashtable_destroy_node(n);
+		}
+
+	table->count = 0;
+	
+	return 0;
+}
+
+int hashtable_iterate(struct hashtable *table, void *data,
+		      int (*iterate)(void *data1, void *data2))
+{
+	int i;
+	struct slist_head *e, *next, *prev;
+	struct hashtable_node *n;
+
+	for (i=0; i < table->hashsize; i++) {
+		slist_for_each_safe(e, prev, next, &table->members[i]) {
+			n = slist_entry(e, struct hashtable_node, head);
+			if (iterate(data, n->data) == -1)
+				return -1;
+		}
+	}
+	return 0;
+}
+
+unsigned int hashtable_counter(struct hashtable *table)
+{
+	return table->count;
+}
diff --git a/src/ignore_pool.c b/src/ignore_pool.c
new file mode 100644
index 0000000..5946617
--- /dev/null
+++ b/src/ignore_pool.c
@@ -0,0 +1,136 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "jhash.h"
+#include "hash.h"
+#include "conntrackd.h"
+#include "ignore.h"
+#include "debug.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+#define IGNORE_POOL_SIZE 32
+#define IGNORE_POOL_LIMIT 1024
+
+static u_int32_t hash(const void *data, struct hashtable *table)
+{
+	const u_int32_t *ip = data;
+
+	return jhash_1word(*ip, 0) % table->hashsize;
+}
+
+static u_int32_t hash6(const void *data, struct hashtable *table)
+{
+	return jhash(data, sizeof(u_int32_t)*4, 0) % table->hashsize;
+}
+
+static int compare(const void *data1, const void *data2)
+{
+	const u_int32_t *ip1 = data1;
+	const u_int32_t *ip2 = data2;
+
+	return *ip1 == *ip2;
+}
+
+static int compare6(const void *data1, const void *data2)
+{
+	return memcmp(data1, data2, sizeof(u_int32_t)*4) == 0;
+}
+
+struct ignore_pool *ignore_pool_create(u_int8_t proto)
+{
+	int i, j = 0;
+	struct ignore_pool *ip;
+
+	ip = malloc(sizeof(struct ignore_pool));
+	if (!ip)
+		return NULL;
+	memset(ip, 0, sizeof(struct ignore_pool));
+
+	switch(proto) {
+	case AF_INET:
+		ip->h = hashtable_create(IGNORE_POOL_SIZE,
+					 IGNORE_POOL_LIMIT,
+					 sizeof(u_int32_t),
+					 hash,
+					 compare);
+		break;
+	case AF_INET6:
+		ip->h = hashtable_create(IGNORE_POOL_SIZE,
+					 IGNORE_POOL_LIMIT,
+					 sizeof(u_int32_t)*4,
+					 hash6,
+					 compare6);
+		break;
+	}
+
+	if (!ip->h) {
+		free(ip);
+		return NULL;
+	}
+
+	return ip;
+}
+
+void ignore_pool_destroy(struct ignore_pool *ip)
+{
+	hashtable_destroy(ip->h);
+	free(ip);
+}
+
+int ignore_pool_add(struct ignore_pool *ip, void *data)
+{
+	if (!hashtable_add(ip->h, data))
+		return 0;
+
+	return 1;
+}
+
+int __ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct)
+{
+	return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) ||
+		hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST)) ||
+		hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC)) ||
+		hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_DST)));
+}
+
+int __ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct)
+{
+	return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) ||
+	        hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) ||
+	        hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)) ||
+	        hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_DST)));
+}
+
+int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct)
+{
+	int ret;
+
+	switch(nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO)) {
+	case AF_INET:
+		ret = __ignore_pool_test_ipv4(ip, ct);
+		break;
+	case AF_INET6:
+		ret = __ignore_pool_test_ipv6(ip, ct);
+		break;
+	default:
+		dlog(STATE(log), "unknown conntrack layer 3 protocol?");
+		break;
+	}
+
+	return ret;
+}
diff --git a/src/local.c b/src/local.c
new file mode 100644
index 0000000..eef70ad
--- /dev/null
+++ b/src/local.c
@@ -0,0 +1,159 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: UNIX sockets library
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include "debug.h"
+
+#include "local.h"
+
+int local_server_create(struct local_conf *conf)
+{
+	int fd;
+	int len;
+	struct sockaddr_un local;
+
+	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+		debug("local_server_create:socket");
+		return -1;
+	}
+
+	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &conf->reuseaddr, 
+				sizeof(conf->reuseaddr)) == -1) {
+		debug("local_server_create:setsockopt");
+		close(fd);
+		return -1;
+	}
+
+	local.sun_family = AF_UNIX;
+	strcpy(local.sun_path, conf->path);
+	len = strlen(local.sun_path) + sizeof(local.sun_family);
+	unlink(conf->path);
+
+	if (bind(fd, (struct sockaddr *) &local, len) == -1) {
+		debug("local_server_create:bind");
+		close(fd);
+		return -1;
+	}
+
+	if (listen(fd, conf->backlog) == -1) {
+		close(fd);
+		debug("local_server_create:listen");
+		return -1;
+	}
+
+	return fd;
+}
+
+void local_server_destroy(int fd)
+{
+	close(fd);
+}
+
+int do_local_server_step(int fd, void *data, 
+			 void (*process)(int fd, void *data))
+{
+	int rfd;
+	struct sockaddr_un local;
+	size_t sin_size = sizeof(struct sockaddr_un);
+	
+	if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) {
+		debug("do_local_server_step:accept");
+		return -1;
+	}
+
+	process(rfd, data);
+	close(rfd);
+
+	return 0;
+}
+
+int local_client_create(struct local_conf *conf)
+{
+	int len;
+	struct sockaddr_un local;
+	int fd;
+
+	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+		return -1;
+
+	local.sun_family = AF_UNIX;
+	strcpy(local.sun_path, conf->path);
+	len = strlen(local.sun_path) + sizeof(local.sun_family);
+
+	if (connect(fd, (struct sockaddr *) &local, len) == -1) {
+		close(fd);
+		debug("local_client_create: connect: ");
+		return -1;
+	}
+
+	return fd;
+}
+
+void local_client_destroy(int fd)
+{
+	close(fd);
+}
+
+int do_local_client_step(int fd, void (*process)(char *buf))
+{
+	int numbytes;
+	char buf[1024];
+
+	memset(buf, 0, sizeof(buf));
+	while ((numbytes = recv(fd, buf, sizeof(buf)-1, 0)) > 0) {
+		buf[sizeof(buf)-1] = '\0';
+		if (process)
+			process(buf);
+		memset(buf, 0, sizeof(buf));
+	}
+
+	return 0;
+}
+
+void local_step(char *buf)
+{
+	printf(buf);
+}
+
+int do_local_request(int request,
+		     struct local_conf *conf,
+		     void (*step)(char *buf))
+{
+	int fd, ret;
+
+	fd = local_client_create(conf);
+	if (fd == -1)
+		return -1;
+
+	ret = send(fd, &request, sizeof(int), 0);
+	if (ret == -1) {
+		debug("send:");
+		return -1;
+	}
+
+	do_local_client_step(fd, step);
+
+	local_client_destroy(fd);
+	
+	return 0;
+}
diff --git a/src/lock.c b/src/lock.c
new file mode 100644
index 0000000..cd68baf
--- /dev/null
+++ b/src/lock.c
@@ -0,0 +1,32 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+
+static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;
+
+void lock()
+{
+	pthread_mutex_lock(&global_lock);
+}
+
+void unlock()
+{
+	pthread_mutex_unlock(&global_lock);
+}
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..88cadea
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,57 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: Logging support for the conntrack daemon
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <stdarg.h>
+#include <string.h>
+
+FILE *init_log(char *filename)
+{
+	FILE *fd;
+
+	fd = fopen(filename, "a+");
+	if (fd == NULL) {
+		fprintf(stderr, "can't open log file `%s'\n", filename);
+		return NULL;
+	}
+
+	return fd;
+}
+
+void dlog(FILE *fd, char *format, ...)
+{
+	time_t t = time(NULL);
+	char *buf = ctime(&t);
+	va_list args;
+
+	buf[strlen(buf)-1]='\0';
+	va_start(args, format);
+	fprintf(fd, "[%s] (pid=%d) ", buf, getpid());
+	vfprintf(fd, format, args);
+	va_end(args);
+	fprintf(fd, "\n");
+	fflush(fd);
+}
+
+void close_log(FILE *fd)
+{
+	fclose(fd);
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..1c75970
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,302 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include "conntrackd.h"
+#include "log.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/utsname.h>
+#include <linux/capability.h>
+#include <errno.h>
+#include "hash.h"
+#include "jhash.h"
+
+struct ct_general_state st;
+union ct_state state;
+
+static const char usage_daemon_commands[] =
+	"Daemon mode commands:\n"
+	"  -d [options]\t\tRun in daemon mode\n"
+	"  -S [options]\t\tRun in statistics mode\n";
+
+static const char usage_client_commands[] = 
+	"Client mode commands:\n"
+	"  -c, commit external cache to conntrack table\n"
+	"  -f, flush internal and external cache\n"
+	"  -F, flush kernel conntrack table\n"
+	"  -i, display content of the internal cache\n"
+	"  -e, display the content of the external cache\n"
+	"  -k, kill conntrack daemon\n"
+	"  -s, dump statistics\n"
+	"  -R, resync with kernel conntrack table\n"
+	"  -n, request resync with other node (only NACK mode)\n"
+	"  -x, dump cache in XML format (requires -i or -e)";
+
+static const char usage_options[] =
+	"Options:\n"
+	"  -C [configfile], configuration file path\n";
+
+void show_usage(char *progname)
+{
+	fprintf(stdout, "Connection tracking userspace daemon v%s\n", VERSION);
+	fprintf(stdout, "Usage: %s [commands] [options]\n\n", progname);
+	fprintf(stdout, "%s\n", usage_daemon_commands);
+	fprintf(stdout, "%s\n", usage_client_commands);
+	fprintf(stdout, "%s\n", usage_options);
+}
+
+/* These live in run.c */
+int init(int);
+void run(void);
+
+void set_operation_mode(int *current, int want, char *argv[])
+{
+	if (*current == NOT_SET) {
+		*current = want;
+		return;
+	}
+	if (*current != want) {
+		show_usage(argv[0]);
+		fprintf(stderr, "\nError: Invalid parameters\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static int check_capabilities(void)
+{
+	int ret;
+	cap_user_header_t hcap;
+	cap_user_data_t dcap;
+
+	hcap = malloc(sizeof(cap_user_header_t));
+	if (!hcap)
+		return -1;
+
+	hcap->version = _LINUX_CAPABILITY_VERSION;
+	hcap->pid = getpid();
+
+	dcap = malloc(sizeof(cap_user_data_t));
+	if (!dcap) {
+		free(hcap);
+		return -1;
+	}
+
+	if (capget(hcap, dcap) == -1) {
+		free(hcap);
+		free(dcap);
+		return -1;
+	}
+
+	ret = dcap->permitted & (1 << CAP_NET_ADMIN);
+
+	free(hcap);
+	free(dcap);
+
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret, i, config_set = 0, action;
+	char config_file[PATH_MAX];
+	int type = 0, mode = 0;
+	struct utsname u;
+	int version, major, minor;
+
+	/* Check kernel version: it must be >= 2.6.18 */
+	if (uname(&u) == -1) {
+		fprintf(stderr, "Can't retrieve kernel version via uname()\n");
+		exit(EXIT_FAILURE);
+	}
+	sscanf(u.release, "%d.%d.%d", &version, &major, &minor);
+	if (version < 2 && major < 6) {
+		fprintf(stderr, "Linux kernel version must be >= 2.6.18\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (major == 6 && minor < 18) {
+		fprintf(stderr, "Linux kernel version must be >= 2.6.18\n");
+		exit(EXIT_FAILURE);
+	}
+
+	ret = check_capabilities();
+	switch (ret) {
+		case -1:
+			fprintf(stderr, "Can't get capabilities\n");
+			exit(EXIT_FAILURE);
+			break;
+		case 0:
+			fprintf(stderr, "You require CAP_NET_ADMIN in order "
+					"to run conntrackd\n");
+			exit(EXIT_FAILURE);
+			break;
+		default:
+			break;
+	}
+
+	for (i=1; i<argc; i++) {
+		switch(argv[i][1]) {
+		case 'd':
+			set_operation_mode(&type, DAEMON, argv);
+			break;
+		case 'c':
+			set_operation_mode(&type, REQUEST, argv);
+			action = COMMIT;
+			break;
+		case 'i':
+			set_operation_mode(&type, REQUEST, argv);
+			action = DUMP_INTERNAL;
+			break;
+		case 'e':
+			set_operation_mode(&type, REQUEST, argv);
+			action = DUMP_EXTERNAL;
+			break;
+		case 'C':
+			if (++i < argc) {
+				strncpy(config_file, argv[i], PATH_MAX);
+				if (strlen(argv[i]) >= PATH_MAX){
+					config_file[PATH_MAX-1]='\0';
+					fprintf(stderr, "Path to config file "
+						        "to long. Cutting it "
+							"down to %d characters",
+							PATH_MAX);
+				}
+				config_set = 1;
+				break;
+			}
+			show_usage(argv[0]);
+			fprintf(stderr, "Missing config filename\n");
+			break;
+		case 'F':
+			set_operation_mode(&type, REQUEST, argv);
+			action = FLUSH_MASTER;
+		case 'f':
+			set_operation_mode(&type, REQUEST, argv);
+			action = FLUSH_CACHE;
+			break;
+		case 'R':
+			set_operation_mode(&type, REQUEST, argv);
+			action = RESYNC_MASTER;
+			break;
+		case 'B':
+			set_operation_mode(&type, REQUEST, argv);
+			action = SEND_BULK;
+			break;
+		case 'k':
+			set_operation_mode(&type, REQUEST, argv);
+			action = KILL;
+			break;
+		case 's':
+			set_operation_mode(&type, REQUEST, argv);
+			action = STATS;
+			break;
+		case 'S':
+			set_operation_mode(&mode, STATS_MODE, argv);
+			break;
+		case 'n':
+			set_operation_mode(&type, REQUEST, argv);
+			action = REQUEST_DUMP;
+			break;
+		case 'x':
+			if (action == DUMP_INTERNAL)
+				action = DUMP_INT_XML;
+			else if (action == DUMP_EXTERNAL)
+				action = DUMP_EXT_XML;
+			else {
+				show_usage(argv[0]);
+				fprintf(stderr, "Error: Invalid parameters\n");
+				exit(EXIT_FAILURE);
+
+			}
+			break;
+		default:
+			show_usage(argv[0]);
+			fprintf(stderr, "Unknown option: %s\n", argv[i]);
+			return 0;
+			break;
+		}
+	}
+
+	if (config_set == 0)
+		strcpy(config_file, DEFAULT_CONFIGFILE);
+
+	if ((ret = init_config(config_file)) == -1) {
+		fprintf(stderr, "can't open config file `%s'\n", config_file);
+		exit(EXIT_FAILURE);
+	}
+
+	/*
+	 * Setting up logfile
+	 */
+	STATE(log) = init_log(CONFIG(logfile));
+	if (!STATE(log)) {
+		fprintf(stdout, "can't open logfile `%s\n'", CONFIG(logfile));
+		exit(EXIT_FAILURE);
+	}
+
+	if (type == REQUEST) {
+		if (do_local_request(action, &conf.local, local_step) == -1)
+			fprintf(stderr, "can't connect: is conntrackd "
+					"running? appropiate permissions?\n");
+		exit(EXIT_SUCCESS);
+	}
+
+	/*
+	 * lock file
+	 */
+	if ((ret = open(CONFIG(lockfile), O_CREAT | O_EXCL | O_TRUNC)) == -1) {
+		fprintf(stderr, "lockfile `%s' exists, perhaps conntrackd "
+			        "already running?\n", CONFIG(lockfile));
+		exit(EXIT_FAILURE);
+	}
+	close(ret);
+
+	/* Daemonize conntrackd */
+	if (type == DAEMON) {
+		pid_t pid;
+
+		if ((pid = fork()) == -1) {
+			dlog(STATE(log), "fork() failed: "
+					 "%s", strerror(errno));
+			exit(EXIT_FAILURE);
+		} else if (pid)
+			exit(EXIT_SUCCESS);
+		
+		dlog(STATE(log), "--- starting in daemon mode ---");
+	} else
+		dlog(STATE(log), "--- starting in console mode ---");
+
+	/*
+	 * initialization process
+	 */
+
+	if (init(mode) == -1) {
+		close_log(STATE(log));
+		fprintf(stderr, "ERROR: conntrackd cannot start, please "
+				"check the logfile for more info\n");
+		unlink(CONFIG(lockfile));
+		exit(EXIT_FAILURE);
+	}
+
+	/*
+	 * run main process
+	 */
+	run();
+}
diff --git a/src/mcast.c b/src/mcast.c
new file mode 100644
index 0000000..9904544
--- /dev/null
+++ b/src/mcast.c
@@ -0,0 +1,287 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: multicast socket library
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string.h>
+#include "mcast.h"
+#include "debug.h"
+
+struct mcast_sock *mcast_server_create(struct mcast_conf *conf)
+{
+	int yes = 1;
+	union {
+		struct ip_mreq ipv4;
+		struct ipv6_mreq ipv6;
+	} mreq;
+	struct mcast_sock *m;
+
+	m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock));
+	if (!m)
+		return NULL;
+	memset(m, 0, sizeof(struct mcast_sock));
+
+	switch(conf->ipproto) {
+	case AF_INET:
+		mreq.ipv4.imr_multiaddr.s_addr = conf->in.inet_addr.s_addr;
+		mreq.ipv4.imr_interface.s_addr =conf->ifa.interface_addr.s_addr;
+
+	        m->addr.ipv4.sin_family = AF_INET;
+	        m->addr.ipv4.sin_port = htons(conf->port);
+	        m->addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
+		break;
+
+	case AF_INET6:
+		memcpy(&mreq.ipv6.ipv6mr_multiaddr, &conf->in.inet_addr6,
+		       sizeof(u_int32_t) * 4);
+		memcpy(&mreq.ipv6.ipv6mr_interface, &conf->ifa.interface_addr6,
+		       sizeof(u_int32_t) * 4);
+
+		m->addr.ipv6.sin6_family = AF_INET6;
+		m->addr.ipv6.sin6_port = htons(conf->port);
+		m->addr.ipv6.sin6_addr = in6addr_any;
+		break;
+	}
+
+	if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) {
+		debug("mcast_sock_server_create:socket");
+		free(m);
+		return NULL;
+	}
+
+	if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, 
+				sizeof(int)) == -1) {
+		debug("mcast_sock_server_create:setsockopt1");
+		close(m->fd);
+		free(m);
+		return NULL;
+	}
+
+	if (bind(m->fd, (struct sockaddr *) &m->addr, 
+			 sizeof(struct sockaddr)) == -1) {
+		debug("mcast_sock_server_create:bind");
+		close(m->fd);
+		free(m);
+		return NULL;
+	}
+
+
+	switch(conf->ipproto) {
+	case AF_INET:
+		if (setsockopt(m->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+			       &mreq.ipv4, sizeof(mreq.ipv4)) < 0) {
+			debug("mcast_sock_server_create:setsockopt2");
+			close(m->fd);
+			free(m);
+			return NULL;
+		}
+		break;
+	case AF_INET6:
+		if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+			       &mreq.ipv6, sizeof(mreq.ipv6)) < 0) {
+			debug("mcast_sock_server_create:setsockopt2");
+			close(m->fd);
+			free(m);
+			return NULL;
+		}
+		break;
+	}
+
+	return m;
+}
+
+void mcast_server_destroy(struct mcast_sock *m)
+{
+	close(m->fd);
+	free(m);
+}
+
+static int 
+__mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf)
+{
+	int no = 0;
+
+	m->addr.ipv4.sin_family = AF_INET;
+	m->addr.ipv4.sin_port = htons(conf->port);
+	m->addr.ipv4.sin_addr = conf->in.inet_addr;
+
+	if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &no,
+		       sizeof(int)) < 0) {
+		debug("mcast_sock_client_create:setsockopt2");
+		close(m->fd);
+		return -1;
+	}
+
+	if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_IF,
+		       &conf->ifa.interface_addr,
+		       sizeof(struct in_addr)) == -1) {
+		debug("mcast_sock_client_create:setsockopt3");
+		close(m->fd);
+		free(m);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int 
+__mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf)
+{
+	int no = 0;
+
+	m->addr.ipv6.sin6_family = AF_INET6;
+	m->addr.ipv6.sin6_port = htons(conf->port);
+	memcpy(&m->addr.ipv6.sin6_addr,
+	       &conf->in.inet_addr6,
+	       sizeof(struct in6_addr));
+
+	if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &no,
+		       sizeof(int)) < 0) {
+		debug("mcast_sock_client_create:setsockopt2");
+		close(m->fd);
+		return -1;
+	}
+
+	if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+		       &conf->ifa.interface_addr,
+		       sizeof(struct in_addr)) == -1) {
+		debug("mcast_sock_client_create:setsockopt3");
+		close(m->fd);
+		free(m);
+		return -1;
+	}
+
+	return 0;
+}
+
+struct mcast_sock *mcast_client_create(struct mcast_conf *conf)
+{
+	int ret = 0;
+	struct sockaddr_in addr;
+	struct mcast_sock *m;
+
+	m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock));
+	if (!m)
+		return NULL;
+	memset(m, 0, sizeof(struct mcast_sock));
+
+	if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) {
+		debug("mcast_sock_client_create:socket");
+		return NULL;
+	}
+
+	switch(conf->ipproto) {
+		case AF_INET:
+			ret = __mcast_client_create_ipv4(m, conf);
+			break;
+		case AF_INET6:
+			ret = __mcast_client_create_ipv6(m, conf);
+			break;
+		default:
+			break;
+	}
+
+	if (ret == -1) {
+		free(m);
+		m = NULL;
+	}
+
+	return m;
+}
+
+void mcast_client_destroy(struct mcast_sock *m)
+{
+	close(m->fd);
+	free(m);
+}
+
+int mcast_send(struct mcast_sock *m, void *data, int size)
+{
+	int ret;
+	
+	ret = sendto(m->fd, 
+		     data,
+		     size,
+		     0,
+		     (struct sockaddr *) &m->addr,
+		     sizeof(struct sockaddr));
+	if (ret == -1) {
+		debug("mcast_sock_send");
+		m->stats.error++;
+		return ret;
+	}
+
+	m->stats.bytes += ret;
+	m->stats.messages++;  
+
+	return ret;
+}
+
+int mcast_recv(struct mcast_sock *m, void *data, int size)
+{
+	int ret;
+	socklen_t sin_size = sizeof(struct sockaddr_in);
+
+        ret = recvfrom(m->fd,
+		       data, 
+		       size,
+		       0,
+		       (struct sockaddr *)&m->addr,
+		       &sin_size);
+	if (ret == -1) {
+		debug("mcast_sock_recv");
+		m->stats.error++;
+		return ret;
+	}
+
+	m->stats.bytes += ret;
+	m->stats.messages++;
+
+	return ret;
+}
+
+struct mcast_stats *mcast_get_stats(struct mcast_sock *m)
+{
+	return &m->stats;
+}
+
+void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r)
+{
+	char buf[512];
+	int size;
+
+	size = sprintf(buf, "multicast traffic:\n"
+			    "%20llu Bytes sent "
+			    "%20llu Bytes recv\n"
+			    "%20llu Pckts sent "
+			    "%20llu Pckts recv\n"
+			    "%20llu Error send "
+			    "%20llu Error recv\n\n",
+			    s->stats.bytes, r->stats.bytes,
+			    s->stats.messages, r->stats.messages,
+			    s->stats.error, r->stats.error);
+
+	send(fd, buf, size, 0);
+}
diff --git a/src/netlink.c b/src/netlink.c
new file mode 100644
index 0000000..0bde632
--- /dev/null
+++ b/src/netlink.c
@@ -0,0 +1,326 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "conntrackd.h"
+#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include <signal.h>
+#include <stdlib.h>
+#include "network.h"
+
+static int ignore_conntrack(struct nf_conntrack *ct)
+{
+	/* ignore a certain protocol */
+	if (CONFIG(ignore_protocol)[nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)])
+		return 1;
+
+	/* Accept DNAT'ed traffic: not really coming to the local machine */
+	if ((CONFIG(flags) & STRIP_NAT) && 
+	    nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) {
+		debug_ct(ct, "DNAT");
+		return 0;
+	}
+
+        /* Accept SNAT'ed traffic: not really coming to the local machine */
+	if ((CONFIG(flags) & STRIP_NAT) && 
+	    nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) {
+		debug_ct(ct, "SNAT");
+		return 0;
+	}
+
+	/* Ignore traffic */
+	if (ignore_pool_test(STATE(ignore_pool), ct)) {
+		debug_ct(ct, "ignore traffic");
+		return 1;
+	}
+
+	return 0;
+}
+
+static int nl_event_handler(struct nlmsghdr *nlh,
+			    struct nfattr *nfa[],
+			    void *data)
+{
+	char tmp[1024];
+	struct nf_conntrack *ct = (struct nf_conntrack *) tmp;
+	int type;
+
+	memset(tmp, 0, sizeof(tmp));
+
+	if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR)
+		return NFCT_CB_STOP;
+
+	/* 
+	 * Ignore this conntrack: it talks about a
+	 * connection that is not interesting for us.
+	 */
+	if (ignore_conntrack(ct))
+		return NFCT_CB_STOP;
+
+	switch(type) {
+	case NFCT_T_NEW:
+		STATE(mode)->event_new(ct, nlh);
+		break;
+	case NFCT_T_UPDATE:
+		STATE(mode)->event_upd(ct, nlh);
+		break;
+	case NFCT_T_DESTROY:
+		if (STATE(mode)->event_dst(ct, nlh))
+			update_traffic_stats(ct);
+		break;
+	default:
+		dlog(STATE(log), "received unknown msg from ctnetlink\n");
+		break;
+	}
+
+	return NFCT_CB_STOP;
+}
+
+int nl_init_event_handler(void)
+{
+	struct nfnl_callback cb_events = {
+		.call		= nl_event_handler,
+		.attr_count	= CTA_MAX
+	};
+
+	/* open event netlink socket */
+	STATE(event) = nfnl_open();
+	if (!STATE(event))
+		return -1;
+
+	/* set up socket buffer size */
+	if (CONFIG(netlink_buffer_size))
+		nfnl_rcvbufsiz(STATE(event), CONFIG(netlink_buffer_size));
+	else {
+		socklen_t socklen = sizeof(unsigned int);
+		unsigned int read_size;
+
+		/* get current buffer size */
+		getsockopt(nfnl_fd(STATE(event)), SOL_SOCKET,
+			   SO_RCVBUF, &read_size, &socklen);
+
+		CONFIG(netlink_buffer_size) = read_size;
+	}
+
+	/* ensure that maximum grown size is >= than maximum size */
+	if (CONFIG(netlink_buffer_size_max_grown) < CONFIG(netlink_buffer_size))
+		CONFIG(netlink_buffer_size_max_grown) = 
+					CONFIG(netlink_buffer_size);
+
+	/* open event subsystem */
+	STATE(subsys_event) = nfnl_subsys_open(STATE(event),
+					       NFNL_SUBSYS_CTNETLINK,
+					       IPCTNL_MSG_MAX,
+					       NFCT_ALL_CT_GROUPS);
+	if (STATE(subsys_event) == NULL)
+		return -1;
+
+	/* register callback for new and update events */
+	nfnl_callback_register(STATE(subsys_event),
+			       IPCTNL_MSG_CT_NEW,
+			       &cb_events);
+
+	/* register callback for delete events */
+	nfnl_callback_register(STATE(subsys_event),
+			       IPCTNL_MSG_CT_DELETE,
+			       &cb_events);
+
+	return 0;
+}
+
+static int nl_dump_handler(struct nlmsghdr *nlh,
+			   struct nfattr *nfa[],
+			   void *data)
+{
+	char buf[1024];
+	struct nf_conntrack *ct = (struct nf_conntrack *) buf;
+	int type;
+
+	memset(buf, 0, sizeof(buf));
+
+	if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR)
+		return NFCT_CB_CONTINUE;
+
+	/* 
+	 * Ignore this conntrack: it talks about a
+	 * connection that is not interesting for us.
+	 */
+	if (ignore_conntrack(ct))
+		return NFCT_CB_CONTINUE;
+
+	switch(type) {
+	case NFCT_T_UPDATE:
+		STATE(mode)->dump(ct, nlh);
+		break;
+	default:
+		dlog(STATE(log), "received unknown msg from ctnetlink");
+		break;
+	}
+	return NFCT_CB_CONTINUE;
+}
+
+int nl_init_dump_handler(void)
+{
+	struct nfnl_callback cb_dump = {
+		.call		= nl_dump_handler,
+		.attr_count	= CTA_MAX
+	};
+
+	/* open dump netlink socket */
+	STATE(dump) = nfnl_open();
+	if (!STATE(dump))
+		return -1;
+
+	/* open dump subsystem */
+	STATE(subsys_dump) = nfnl_subsys_open(STATE(dump),
+					      NFNL_SUBSYS_CTNETLINK,
+					      IPCTNL_MSG_MAX,
+					      0);
+	if (STATE(subsys_dump) == NULL)
+		return -1;
+
+	/* register callback for dumped entries */
+	nfnl_callback_register(STATE(subsys_dump),
+			       IPCTNL_MSG_CT_NEW,
+			       &cb_dump);
+
+	if (nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)) == -1)
+		return -1;
+
+	return 0;
+}
+
+static int nl_overrun_handler(struct nlmsghdr *nlh,
+			      struct nfattr *nfa[],
+			      void *data)
+{
+	char buf[1024];
+	struct nf_conntrack *ct = (struct nf_conntrack *) buf;
+	int type;
+
+	memset(buf, 0, sizeof(buf));
+
+	if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR)
+		return NFCT_CB_CONTINUE;
+
+	/* 
+	 * Ignore this conntrack: it talks about a
+	 * connection that is not interesting for us.
+	 */
+	if (ignore_conntrack(ct))
+		return NFCT_CB_CONTINUE;
+
+	switch(type) {
+	case NFCT_T_UPDATE:
+		if (STATE(mode)->overrun)
+			STATE(mode)->overrun(ct, nlh);
+		break;
+	default:
+		dlog(STATE(log), "received unknown msg from ctnetlink");
+		break;
+	}
+	return NFCT_CB_CONTINUE;
+}
+
+int nl_init_overrun_handler(void)
+{
+	struct nfnl_callback cb_sync = {
+		.call		= nl_overrun_handler,
+		.attr_count	= CTA_MAX
+	};
+
+	/* open sync netlink socket */
+	STATE(sync) = nfnl_open();
+	if (!STATE(sync))
+		return -1;
+
+	/* open synchronizer subsystem */
+	STATE(subsys_sync) = nfnl_subsys_open(STATE(sync),
+					      NFNL_SUBSYS_CTNETLINK,
+					      IPCTNL_MSG_MAX,
+					      0);
+	if (STATE(subsys_sync) == NULL)
+		return -1;
+
+	/* register callback for dumped entries */
+	nfnl_callback_register(STATE(subsys_sync),
+			       IPCTNL_MSG_CT_NEW,
+			       &cb_sync);
+
+	return 0;
+}
+
+static int warned = 0;
+
+void nl_resize_socket_buffer(struct nfnl_handle *h)
+{
+	unsigned int s = CONFIG(netlink_buffer_size) * 2;
+
+	/* already warned that we have reached the maximum buffer size */
+	if (warned)
+		return;
+
+	if (s > CONFIG(netlink_buffer_size_max_grown)) {
+		dlog(STATE(log), "maximum netlink socket buffer size reached");
+		s = CONFIG(netlink_buffer_size_max_grown);
+		warned = 1;
+	}
+
+	CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(h, s);
+
+	/* notify the sysadmin */
+	dlog(STATE(log), "netlink socket buffer size has been set to %u bytes", 
+			  CONFIG(netlink_buffer_size));
+}
+
+int nl_dump_conntrack_table(struct nfnl_handle *h, 
+			    struct nfnl_subsys_handle *subsys)
+{
+	struct nfnlhdr req;
+
+	memset(&req, 0, sizeof(req));
+	nfct_build_query(subsys, 
+			 NFCT_Q_DUMP, 
+			 &CONFIG(family), 
+			 &req, 
+			 sizeof(req));
+
+	if (nfnl_query(h, &req.nlh) == -1)
+		return -1;
+
+	return 0;
+}
+
+int nl_flush_master_conntrack_table(void)
+{
+	struct nfnlhdr req;
+
+	memset(&req, 0, sizeof(req));
+	nfct_build_query(STATE(subsys_sync), 
+			 NFCT_Q_FLUSH, 
+			 &CONFIG(family), 
+			 &req, 
+			 sizeof(req));
+
+	if (nfnl_query(STATE(sync), &req.nlh) == -1)
+		return -1;
+
+	return 0;
+}
diff --git a/src/network.c b/src/network.c
new file mode 100644
index 0000000..b9be318
--- /dev/null
+++ b/src/network.c
@@ -0,0 +1,282 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "conntrackd.h"
+#include "network.h"
+
+#if 0 
+#define _TEST_DROP
+#else
+#undef _TEST_DROP
+#endif
+
+static int drop = 0; /* debugging purposes */
+static unsigned int seq_set, cur_seq;
+
+static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len)
+{
+	struct nlnetwork *net = data;
+
+#ifdef _TEST_DROP
+        if (++drop > 10) {
+		drop = 0;
+		printf("dropping resend (seq=%u)\n", ntohl(net->seq));
+		return 0;
+	}
+#endif
+	return mcast_send(m, net, len);
+}
+
+int mcast_send_netmsg(struct mcast_sock *m, void *data)
+{
+	struct nlmsghdr *nlh = data + sizeof(struct nlnetwork);
+	unsigned int len = nlh->nlmsg_len + sizeof(struct nlnetwork);
+	struct nlnetwork *net = data;
+
+	if (!seq_set) {
+		seq_set = 1;
+		cur_seq = time(NULL);
+		net->flags |= NET_HELLO;
+	}
+
+	net->flags = htons(net->flags);
+	net->seq = htonl(cur_seq++);
+
+	if (nlh_host2network(nlh) == -1)
+		return -1;
+
+	net->checksum = 0;
+	net->checksum = ntohs(do_csum(data, len));
+
+	return send_netmsg(m, data, len);
+}
+
+int mcast_resend_netmsg(struct mcast_sock *m, void *data)
+{
+	struct nlnetwork *net = data;
+	struct nlmsghdr *nlh = data + sizeof(struct nlnetwork);
+	unsigned int len = htonl(nlh->nlmsg_len) + sizeof(struct nlnetwork);
+
+	net->flags = ntohs(net->flags);
+
+	if (!seq_set) {
+		seq_set = 1;
+		cur_seq = time(NULL);
+		net->flags |= NET_HELLO;
+	}
+
+	if (net->flags & NET_NACK || net->flags & NET_ACK) {
+		struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net;
+		len = sizeof(struct nlnetwork_ack);
+	}
+
+	net->flags = htons(net->flags);
+	net->seq = htonl(cur_seq++);
+	net->checksum = 0;
+	net->checksum = ntohs(do_csum(data, len));
+
+	return send_netmsg(m, data, len);
+}
+
+int mcast_send_error(struct mcast_sock *m, void *data)
+{
+	struct nlnetwork *net = data;
+	unsigned int len = sizeof(struct nlnetwork);
+
+	if (!seq_set) {
+		seq_set = 1;
+		cur_seq = time(NULL);
+		net->flags |= NET_HELLO;
+	}
+
+	if (net->flags & NET_NACK || net->flags & NET_ACK) {
+		struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net;
+		nack->from = htonl(nack->from);
+		nack->to = htonl(nack->to);
+		len = sizeof(struct nlnetwork_ack);
+	}
+
+	net->flags = htons(net->flags);
+	net->seq = htonl(cur_seq++);
+	net->checksum = 0;
+	net->checksum = ntohs(do_csum(data, len));
+
+	return send_netmsg(m, data, len);
+}
+
+static int valid_checksum(void *data, unsigned int len)
+{
+	struct nlnetwork *net = data;
+	unsigned short checksum, tmp;
+
+	checksum = ntohs(net->checksum);
+
+	/* no checksum, skip */
+	if (!checksum)
+		return 1;
+
+	net->checksum = 0;
+	tmp = do_csum(data, len);
+
+	return tmp == checksum;
+}
+
+int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len)
+{
+	int ret;
+	struct nlnetwork *net = data;
+	struct nlmsghdr *nlh = data + sizeof(struct nlnetwork);
+	struct nfgenmsg *nfhdr;
+
+	ret = mcast_recv(m, net, len);
+	if (ret <= 0)
+		return ret;
+
+	if (ret < sizeof(struct nlnetwork))
+		return -1;
+
+	if (!valid_checksum(data, ret))
+		return -1;
+
+	net->flags = ntohs(net->flags);
+	net->seq = ntohl(net->seq);
+
+	if (net->flags & NET_HELLO)
+		STATE_SYNC(last_seq_recv) = net->seq-1;
+
+	if (net->flags & NET_NACK || net->flags & NET_ACK) {
+		struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net;
+
+		if (ret < sizeof(struct nlnetwork_ack))
+			return -1;
+
+		nack->from = ntohl(nack->from);
+		nack->to = ntohl(nack->to);
+
+		return ret;
+	}
+
+	if (net->flags & NET_RESYNC)
+		return ret;
+
+	/* information received is too small */
+	if (ret < NLMSG_SPACE(sizeof(struct nfgenmsg)))
+		return -1;
+
+	/* information received and message length does not match */
+	if (ret != ntohl(nlh->nlmsg_len) + sizeof(struct nlnetwork))
+		return -1;
+
+	/* this message does not come from ctnetlink */
+	if (NFNL_SUBSYS_ID(ntohs(nlh->nlmsg_type)) != NFNL_SUBSYS_CTNETLINK)
+		return -1;
+
+	nfhdr = NLMSG_DATA(nlh);
+
+	/* only AF_INET and AF_INET6 are supported */
+	if (nfhdr->nfgen_family != AF_INET &&
+	    nfhdr->nfgen_family != AF_INET6)
+		return -1;
+
+	/* only process message coming from nfnetlink v0 */
+	if (nfhdr->version != NFNETLINK_V0)
+		return -1;
+
+	if (nlh_network2host(nlh) == -1)
+		return -1;
+
+	return ret;
+}
+
+int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq)
+{
+	static int seq_set = 0;
+	int ret = 1;
+
+	/* netlink sequence tracking initialization */
+	if (!seq_set) {
+		seq_set = 1;
+		goto out;
+	}
+
+	/* fast path: we received the correct sequence */
+	if (seq == STATE_SYNC(last_seq_recv)+1)
+		goto out;
+
+	/* out of sequence: some messages got lost */
+	if (seq > STATE_SYNC(last_seq_recv)+1) {
+		STATE_SYNC(packets_lost) += seq-STATE_SYNC(last_seq_recv)+1;
+		ret = 0;
+		goto out;
+	}
+
+	/* out of sequence: replayed or sequence wrapped around issues */
+	if (seq < STATE_SYNC(last_seq_recv)+1) {
+		/* 
+		 * Check if the sequence has wrapped around.
+		 * Perhaps it can be a replayed packet.
+		 */
+		if (STATE_SYNC(last_seq_recv)+1-seq > ~0U/2) {
+			/* 
+			 * Indeed, it is a wrapped around
+			 */
+			STATE_SYNC(packets_lost) += 
+				~0U-STATE_SYNC(last_seq_recv)+1+seq;
+		} else {
+			/*
+			 * It is a delayed packet
+			 */
+			dlog(STATE(log), "delayed packet? exp=%u rcv=%u",
+					 STATE_SYNC(last_seq_recv)+1, seq);
+		}
+		ret = 0;
+	}
+
+out:
+	*exp_seq = STATE_SYNC(last_seq_recv)+1;
+	/* update expected sequence */
+	STATE_SYNC(last_seq_recv) = seq;
+
+	return ret;
+}
+
+int build_network_msg(const int msg_type,
+		      struct nfnl_subsys_handle *ssh, 
+		      struct nf_conntrack *ct,
+		      void *buffer,
+		      unsigned int size)
+{
+	memset(buffer, 0, size);
+	buffer += sizeof(struct nlnetwork);
+	return nfct_build_query(ssh, msg_type, ct, buffer, size);
+}
+
+unsigned int parse_network_msg(struct nf_conntrack *ct, 
+			       const struct nlmsghdr *nlh)
+{
+	/* 
+	 * The parsing of netlink messages going through network is 
+	 * similar to the one that is done for messages coming from
+	 * kernel, therefore do not replicate more code and use the
+	 * function provided in the libraries.
+	 *
+	 * Yup, this is a hack 8)
+	 */
+	return nfct_parse_conntrack(NFCT_T_ALL, nlh, ct);
+}
+
diff --git a/src/proxy.c b/src/proxy.c
new file mode 100644
index 0000000..b9bb04e
--- /dev/null
+++ b/src/proxy.c
@@ -0,0 +1,124 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+#if 0
+#define dprintf printf
+#else
+#define dprintf
+#endif
+
+int nlh_payload_host2network(struct nfattr *nfa, int len)
+{
+	struct nfattr *__nfa;
+
+	while (NFA_OK(nfa, len)) {
+
+		dprintf("type=%d nfalen=%d len=%d [%s]\n", 
+			nfa->nfa_type & 0x7fff,
+			nfa->nfa_len, len,
+			nfa->nfa_type & NFNL_NFA_NEST ? "NEST":"");
+
+		if (nfa->nfa_type & NFNL_NFA_NEST) {
+			if (NFA_PAYLOAD(nfa) > len)
+				return -1;
+
+			if (nlh_payload_host2network(NFA_DATA(nfa), 
+						     NFA_PAYLOAD(nfa)) == -1)
+				return -1;
+		}
+
+		__nfa = NFA_NEXT(nfa, len);
+
+		nfa->nfa_type = htons(nfa->nfa_type);
+		nfa->nfa_len  = htons(nfa->nfa_len);
+
+		nfa = __nfa; 
+	}
+	return 0;
+}
+
+int nlh_host2network(struct nlmsghdr *nlh)
+{
+	struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
+	struct nfattr *cda[CTA_MAX];
+	unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
+	unsigned int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
+
+	nlh->nlmsg_len   = htonl(nlh->nlmsg_len);
+	nlh->nlmsg_type  = htons(nlh->nlmsg_type);
+	nlh->nlmsg_flags = htons(nlh->nlmsg_flags);
+	nlh->nlmsg_seq   = htonl(nlh->nlmsg_seq);
+	nlh->nlmsg_pid   = htonl(nlh->nlmsg_pid);
+
+	nfhdr->res_id    = htons(nfhdr->res_id);
+
+	return nlh_payload_host2network(NFM_NFA(NLMSG_DATA(nlh)), len);
+}
+
+int nlh_payload_network2host(struct nfattr *nfa, int len)
+{
+	nfa->nfa_type = ntohs(nfa->nfa_type);
+	nfa->nfa_len  = ntohs(nfa->nfa_len);
+
+	while(NFA_OK(nfa, len)) {
+
+                dprintf("type=%d nfalen=%d len=%d [%s]\n", 
+		        nfa->nfa_type & 0x7fff, 
+		        nfa->nfa_len, len, 
+		        nfa->nfa_type & NFNL_NFA_NEST ? "NEST":"");
+
+		if (nfa->nfa_type & NFNL_NFA_NEST) {
+			if (NFA_PAYLOAD(nfa) > len)
+				return -1;
+
+			if (nlh_payload_network2host(NFA_DATA(nfa),
+						     NFA_PAYLOAD(nfa)) == -1)
+				return -1;
+		}
+
+		nfa = NFA_NEXT(nfa,len);
+
+		if (len < NFA_LENGTH(0))
+			break;
+
+		nfa->nfa_type = ntohs(nfa->nfa_type);
+		nfa->nfa_len  = ntohs(nfa->nfa_len);
+	}
+	return 0;
+}
+
+int nlh_network2host(struct nlmsghdr *nlh)
+{
+	struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
+	struct nfattr *cda[CTA_MAX];
+	unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
+	unsigned int len = ntohl(nlh->nlmsg_len) - NLMSG_ALIGN(min_len);
+
+	nlh->nlmsg_len   = ntohl(nlh->nlmsg_len);
+	nlh->nlmsg_type  = ntohs(nlh->nlmsg_type);
+	nlh->nlmsg_flags = ntohs(nlh->nlmsg_flags);
+	nlh->nlmsg_seq   = ntohl(nlh->nlmsg_seq);
+	nlh->nlmsg_pid   = ntohl(nlh->nlmsg_pid);
+
+	nfhdr->res_id    = ntohs(nfhdr->res_id);
+
+	return nlh_payload_network2host(NFM_NFA(NLMSG_DATA(nlh)), len);
+}
diff --git a/src/read_config_lex.l b/src/read_config_lex.l
new file mode 100644
index 0000000..dee90c9
--- /dev/null
+++ b/src/read_config_lex.l
@@ -0,0 +1,125 @@
+%{
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: configuration file syntax
+ */
+
+#include "read_config_yy.h"
+#include "conntrackd.h"
+%}
+
+%option yylineno
+%option nounput
+
+ws		[ \t]+
+comment         #.*$
+nl		[\n\r]
+
+is_on		[o|O][n|N]
+is_off		[o|O][f|F][f|F]
+integer		[0-9]+
+path		\/[^\"\n ]*
+ip4_end		[0-9]*[0-9]+
+ip4_part	[0-2]*{ip4_end}
+ip4		{ip4_part}\.{ip4_part}\.{ip4_part}\.{ip4_part}
+hex_255		[0-9a-fA-F]{1,4}
+ip6_part	{hex_255}":"?
+ip6_form1	{ip6_part}{0,16}"::"{ip6_part}{0,16}
+ip6_form2	({hex_255}":"){16}{hex_255}
+ip6		{ip6_form1}|{ip6_form2}
+string		[a-zA-Z]*
+persistent	[P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T]
+nack		[N|n][A|a][C|c][K|k]
+
+%%
+"UNIX"				{ return T_UNIX; }
+"IPv4_address"			{ return T_IPV4_ADDR; }
+"IPv6_address"			{ return T_IPV6_ADDR; }
+"IPv4_interface"		{ return T_IPV4_IFACE; }
+"IPv6_interface"		{ return T_IPV6_IFACE; }
+"Port"				{ return T_PORT; }
+"Multicast"			{ return T_MULTICAST; }
+"HashSize"			{ return T_HASHSIZE; }
+"RefreshTime"			{ return T_REFRESH; }
+"CacheTimeout"			{ return T_EXPIRE; }
+"CommitTimeout"			{ return T_TIMEOUT; }
+"DelayDestroyMessages"		{ return T_DELAY; }
+"HashLimit"			{ return T_HASHLIMIT; }
+"Path"				{ return T_PATH; }
+"IgnoreProtocol"		{ return T_IGNORE_PROTOCOL; }
+"UDP"				{ return T_UDP; }
+"ICMP"				{ return T_ICMP; }
+"VRRP"				{ return T_VRRP; }
+"IGMP"				{ return T_IGMP; }
+"TCP"				{ return T_TCP; }
+"IgnoreTrafficFor"		{ return T_IGNORE_TRAFFIC; }
+"StripNAT"			{ return T_STRIP_NAT; }
+"Backlog"			{ return T_BACKLOG; }
+"Group"				{ return T_GROUP; }
+"LogFile"			{ return T_LOG; }
+"LockFile"			{ return T_LOCK; }
+"General"			{ return T_GENERAL; }
+"Sync"				{ return T_SYNC; }
+"Stats"				{ return T_STATS; }
+"RelaxTransitions"		{ return T_RELAX_TRANSITIONS; }
+"SocketBufferSize"		{ return T_BUFFER_SIZE; }
+"SocketBufferSizeMaxGrown"	{ return T_BUFFER_SIZE_MAX_GROWN; }
+"SocketBufferSizeMaxGrowth"	{ return T_BUFFER_SIZE_MAX_GROWN; }
+"Mode"				{ return T_SYNC_MODE; }
+"ListenTo"			{ return T_LISTEN_TO; }
+"Family"			{ return T_FAMILY; }
+"ResendBufferSize"		{ return T_RESEND_BUFFER_SIZE; }
+"Checksum"			{ return T_CHECKSUM; }
+"ACKWindowSize"			{ return T_WINDOWSIZE; }
+"Replicate"			{ return T_REPLICATE; }
+"for"				{ return T_FOR; }
+"SYN_SENT"			{ return T_SYN_SENT; }
+"SYN_RECV"			{ return T_SYN_RECV; }
+"ESTABLISHED"			{ return T_ESTABLISHED; }
+"FIN_WAIT"			{ return T_FIN_WAIT; }
+"CLOSE_WAIT"			{ return T_CLOSE_WAIT; }
+"LAST_ACK"			{ return T_LAST_ACK; }
+"TIME_WAIT"			{ return T_TIME_WAIT; }
+"CLOSE"				{ return T_CLOSE; }
+"LISTEN"			{ return T_LISTEN; }
+
+{is_on}			{ return T_ON; }
+{is_off}		{ return T_OFF; }
+{integer}		{ yylval.val = atoi(yytext); return T_NUMBER; }
+{ip4}			{ yylval.string = strdup(yytext); return T_IP; }
+{ip6}			{ yylval.string = strdup(yytext); return T_IP; }
+{path}			{ yylval.string = strdup(yytext); return T_PATH_VAL; }
+{persistent}		{ return T_PERSISTENT; }
+{nack}			{ return T_NACK; }
+{string}		{ yylval.string = strdup(yytext); return T_STRING; }
+
+{comment}	;
+{ws}		;
+{nl}		;
+
+<<EOF>>		{ yyterminate(); }
+
+.		{ return yytext[0]; }
+
+%%
+
+int
+yywrap()
+{
+	return 1;
+}
diff --git a/src/read_config_yy.y b/src/read_config_yy.y
new file mode 100644
index 0000000..1668919
--- /dev/null
+++ b/src/read_config_yy.y
@@ -0,0 +1,550 @@
+%{
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: configuration file abstract grammar
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "conntrackd.h"
+#include "ignore.h"
+
+extern char *yytext;
+extern int   yylineno;
+
+struct ct_conf conf;
+%}
+
+%union {
+	int		val;
+	char		*string;
+}
+
+%token T_IPV4_ADDR T_IPV4_IFACE T_PORT T_HASHSIZE T_HASHLIMIT T_MULTICAST
+%token T_PATH T_UNIX T_REFRESH T_IPV6_ADDR T_IPV6_IFACE
+%token T_IGNORE_UDP T_IGNORE_ICMP T_IGNORE_TRAFFIC T_BACKLOG T_GROUP
+%token T_LOG T_UDP T_ICMP T_IGMP T_VRRP T_TCP T_IGNORE_PROTOCOL
+%token T_LOCK T_STRIP_NAT T_BUFFER_SIZE_MAX_GROWN T_EXPIRE T_TIMEOUT
+%token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY
+%token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE
+%token T_PERSISTENT T_NACK T_CHECKSUM T_WINDOWSIZE T_ON T_OFF
+%token T_REPLICATE T_FOR 
+%token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT 
+%token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN
+
+
+%token <string> T_IP T_PATH_VAL
+%token <val> T_NUMBER
+%token <string> T_STRING
+
+%%
+
+configfile :
+	   | lines
+	   ;
+
+lines : line
+      | lines line
+      ;
+
+line : ignore_protocol
+     | ignore_traffic
+     | strip_nat
+     | general
+     | sync
+     | stats
+     ;
+
+log : T_LOG T_PATH_VAL
+{
+	strncpy(conf.logfile, $2, FILENAME_MAXLEN);
+};
+
+lock : T_LOCK T_PATH_VAL
+{
+	strncpy(conf.lockfile, $2, FILENAME_MAXLEN);
+};
+
+strip_nat: T_STRIP_NAT
+{
+	conf.flags |= STRIP_NAT;
+};
+
+refreshtime : T_REFRESH T_NUMBER
+{
+	conf.refresh = $2;
+};
+
+expiretime: T_EXPIRE T_NUMBER
+{
+	conf.cache_timeout = $2;
+};
+
+timeout: T_TIMEOUT T_NUMBER
+{
+	conf.commit_timeout = $2;
+};
+
+checksum: T_CHECKSUM T_ON 
+{
+};
+
+checksum: T_CHECKSUM T_OFF
+{
+	conf.flags |= DONT_CHECKSUM;
+};
+
+ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}';
+
+ignore_traffic_options :
+		       | ignore_traffic_options ignore_traffic_option;
+
+ignore_traffic_option : T_IPV4_ADDR T_IP
+{
+	union inet_address ip;
+	int family = 0;
+
+	memset(&ip, 0, sizeof(union inet_address));
+
+	if (inet_aton($2, &ip.ipv4))
+		family = AF_INET;
+#ifdef HAVE_INET_PTON_IPV6
+	else if (inet_pton(AF_INET6, $2, &ip.ipv6) > 0)
+		family = AF_INET6;
+#endif
+
+	if (!family) {
+		fprintf(stdout, "%s is not a valid IP, ignoring", $2);
+		return;
+	}
+
+	if (!STATE(ignore_pool)) {
+		STATE(ignore_pool) = ignore_pool_create(family);
+		if (!STATE(ignore_pool)) {
+			fprintf(stdout, "Can't create ignore pool!\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (!ignore_pool_add(STATE(ignore_pool), &ip)) {
+		if (errno == EEXIST)
+			fprintf(stdout, "IP %s is repeated "
+					"in the ignore pool\n", $2);
+		if (errno == ENOSPC)
+			fprintf(stdout, "Too many IP in the ignore pool!\n");
+	}
+};
+
+multicast_line : T_MULTICAST '{' multicast_options '}';
+
+multicast_options :
+		  | multicast_options multicast_option;
+
+multicast_option : T_IPV4_ADDR T_IP
+{
+	if (!inet_aton($2, &conf.mcast.in)) {
+		fprintf(stderr, "%s is not a valid IPv4 address\n");
+		return;
+	}
+
+        if (conf.mcast.ipproto == AF_INET6) {
+		fprintf(stderr, "Your multicast address is IPv4 but "
+		                "is binded to an IPv6 interface? Surely "
+				"this is not what you want\n");
+		return;
+	}
+
+	conf.mcast.ipproto = AF_INET;
+};
+
+multicast_option : T_IPV6_ADDR T_IP
+{
+#ifdef HAVE_INET_PTON_IPV6
+	if (inet_pton(AF_INET6, $2, &conf.mcast.in) <= 0)
+		fprintf(stderr, "%s is not a valid IPv6 address\n", $2);
+#endif
+
+	if (conf.mcast.ipproto == AF_INET) {
+		fprintf(stderr, "Your multicast address is IPv6 but "
+				"is binded to an IPv4 interface? Surely "
+				"this is not what you want\n");
+		return;
+	}
+
+	conf.mcast.ipproto = AF_INET6;
+};
+
+multicast_option : T_IPV4_IFACE T_IP
+{
+	if (!inet_aton($2, &conf.mcast.ifa)) {
+		fprintf(stderr, "%s is not a valid IPv4 address\n");
+		return;
+	}
+
+        if (conf.mcast.ipproto == AF_INET6) {
+		fprintf(stderr, "Your multicast interface is IPv4 but "
+		                "is binded to an IPv6 interface? Surely "
+				"this is not what you want\n");
+		return;
+	}
+
+	conf.mcast.ipproto = AF_INET;
+};
+
+multicast_option : T_IPV6_IFACE T_IP
+{
+#ifdef HAVE_INET_PTON_IPV6
+	if (inet_pton(AF_INET6, $2, &conf.mcast.ifa) <= 0)
+		fprintf(stderr, "%s is not a valid IPv6 address\n", $2);
+#endif
+
+	if (conf.mcast.ipproto == AF_INET) {
+		fprintf(stderr, "Your multicast interface is IPv6 but "
+				"is binded to an IPv4 interface? Surely "
+				"this is not what you want\n");
+		return;
+	}
+
+	conf.mcast.ipproto = AF_INET6;
+};
+
+multicast_option : T_BACKLOG T_NUMBER
+{
+	conf.mcast.backlog = $2;
+};
+
+multicast_option : T_GROUP T_NUMBER
+{
+	conf.mcast.port = $2;
+};
+
+hashsize : T_HASHSIZE T_NUMBER
+{
+	conf.hashsize = $2;
+};
+
+hashlimit: T_HASHLIMIT T_NUMBER
+{
+	conf.limit = $2;
+};
+
+unix_line: T_UNIX '{' unix_options '}';
+
+unix_options:
+	    | unix_options unix_option
+	    ;
+
+unix_option : T_PATH T_PATH_VAL
+{
+	strcpy(conf.local.path, $2);
+};
+
+unix_option : T_BACKLOG T_NUMBER
+{
+	conf.local.backlog = $2;
+};
+
+ignore_protocol: T_IGNORE_PROTOCOL '{' ignore_proto_list '}';
+
+ignore_proto_list:
+		 | ignore_proto_list ignore_proto
+		 ;
+
+ignore_proto: T_NUMBER
+{
+	if ($1 < IPPROTO_MAX)
+		conf.ignore_protocol[$1] = 1;
+	else
+		fprintf(stdout, "Protocol number `%d' is freak\n", $1);
+};
+
+ignore_proto: T_UDP
+{
+	conf.ignore_protocol[IPPROTO_UDP] = 1;
+};
+
+ignore_proto: T_ICMP
+{
+	conf.ignore_protocol[IPPROTO_ICMP] = 1;
+};
+
+ignore_proto: T_VRRP
+{
+	conf.ignore_protocol[IPPROTO_VRRP] = 1;
+};
+
+ignore_proto: T_IGMP
+{
+	conf.ignore_protocol[IPPROTO_IGMP] = 1;
+};
+
+sync: T_SYNC '{' sync_list '}';
+
+sync_list:
+	 | sync_list sync_line;
+
+sync_line: refreshtime
+	 | expiretime
+	 | timeout
+	 | checksum
+	 | multicast_line
+	 | relax_transitions
+	 | delay_destroy_msgs
+	 | sync_mode_persistent
+	 | sync_mode_nack
+	 | listen_to
+	 | state_replication
+	 ;
+
+sync_mode_persistent: T_SYNC_MODE T_PERSISTENT '{' sync_mode_persistent_list '}'
+{
+	conf.flags |= SYNC_MODE_PERSISTENT;
+};
+
+sync_mode_nack: T_SYNC_MODE T_NACK '{' sync_mode_nack_list '}'
+{
+	conf.flags |= SYNC_MODE_NACK;
+};
+
+sync_mode_persistent_list:
+	      | sync_mode_persistent_list sync_mode_persistent_line;
+
+sync_mode_persistent_line: refreshtime
+              		 | expiretime
+	     		 | timeout
+			 | relax_transitions
+			 | delay_destroy_msgs
+			 ;
+
+sync_mode_nack_list:
+	      | sync_mode_nack_list sync_mode_nack_line;
+
+sync_mode_nack_line: resend_buffer_size
+		   | timeout
+		   | window_size
+		   ;
+
+resend_buffer_size: T_RESEND_BUFFER_SIZE T_NUMBER
+{
+	conf.resend_buffer_size = $2;
+};
+
+window_size: T_WINDOWSIZE T_NUMBER
+{
+	conf.window_size = $2;
+};
+
+relax_transitions: T_RELAX_TRANSITIONS
+{
+	conf.flags |= RELAX_TRANSITIONS;
+};
+
+delay_destroy_msgs: T_DELAY
+{
+	conf.flags |= DELAY_DESTROY_MSG;
+};
+
+listen_to: T_LISTEN_TO T_IP
+{
+	union inet_address addr;
+
+#ifdef HAVE_INET_PTON_IPV6
+	if (inet_pton(AF_INET6, $2, &addr.ipv6) <= 0)
+#endif
+		if (inet_aton($2, &addr.ipv4) <= 0) {
+			fprintf(stderr, "%s is not a valid IP address\n", $2);
+			exit(EXIT_FAILURE);
+		}
+
+	if (CONFIG(listen_to_len) == 0 || CONFIG(listen_to_len) % 16) {
+		CONFIG(listen_to) = realloc(CONFIG(listen_to),
+					    sizeof(union inet_address) *
+					    (CONFIG(listen_to_len) + 16));
+		if (CONFIG(listen_to) == NULL) {
+			fprintf(stderr, "cannot init listen_to array\n");
+			exit(EXIT_FAILURE);
+		}
+
+		memset(CONFIG(listen_to) + 
+		       (CONFIG(listen_to_len) * sizeof(union inet_address)),
+		       0, sizeof(union inet_address) * 16);
+
+	}
+};
+
+state_replication: T_REPLICATE states T_FOR state_proto;
+
+states:
+      | states state;
+
+state_proto: T_TCP;
+state: tcp_state;
+
+tcp_state: T_SYN_SENT
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_SENT);
+};
+tcp_state: T_SYN_RECV
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_RECV);
+};
+tcp_state: T_ESTABLISHED
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_ESTABLISHED);
+};
+tcp_state: T_FIN_WAIT
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_FIN_WAIT);
+};
+tcp_state: T_CLOSE_WAIT
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE_WAIT);
+};
+tcp_state: T_LAST_ACK
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LAST_ACK);
+};
+tcp_state: T_TIME_WAIT
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_TIME_WAIT);
+};
+tcp_state: T_CLOSE
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE);
+};
+tcp_state: T_LISTEN
+{
+	extern struct state_replication_helper tcp_state_helper;
+	state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LISTEN);
+};
+
+general: T_GENERAL '{' general_list '}';
+
+general_list:
+	    | general_list general_line
+	    ;
+
+general_line: hashsize
+	    | hashlimit
+	    | log
+	    | lock
+	    | unix_line
+	    | netlink_buffer_size
+	    | netlink_buffer_size_max_grown
+	    | family
+	    ;
+
+netlink_buffer_size: T_BUFFER_SIZE T_NUMBER
+{
+	conf.netlink_buffer_size = $2;
+};
+
+netlink_buffer_size_max_grown : T_BUFFER_SIZE_MAX_GROWN T_NUMBER
+{
+	conf.netlink_buffer_size_max_grown = $2;
+};
+
+family : T_FAMILY T_STRING
+{
+	if (strncmp($2, "IPv6", strlen("IPv6")) == 0)
+		conf.family = AF_INET6;
+	else
+		conf.family = AF_INET;
+};
+
+stats: T_SYNC '{' stats_list '}';
+
+stats_list:
+	 | stats_list stat_line
+	 ;
+
+stat_line:
+	 |
+	 ;
+
+%%
+
+int
+yyerror(char *msg)
+{
+	printf("Error parsing config file: ");
+	printf("line (%d), symbol '%s': %s\n", yylineno, yytext, msg);
+	exit(EXIT_FAILURE);
+}
+
+int
+init_config(char *filename)
+{
+	FILE *fp;
+
+	fp = fopen(filename, "r");
+	if (!fp)
+		return -1;
+
+	yyrestart(fp);
+	yyparse();
+	fclose(fp);
+
+	/* default to IPv4 */
+	if (CONFIG(family) == 0)
+		CONFIG(family) = AF_INET;
+
+	/* set to default is not specified */
+	if (strcmp(CONFIG(lockfile), "") == 0)
+		strncpy(CONFIG(lockfile), DEFAULT_LOCKFILE, FILENAME_MAXLEN);
+
+	/* default to 180 seconds of expiration time: cache entries */
+	if (CONFIG(cache_timeout) == 0)
+		CONFIG(cache_timeout) = 180;
+
+	/* default to 180 seconds: committed entries */
+	if (CONFIG(commit_timeout) == 0)
+		CONFIG(commit_timeout) = 180;
+
+	/* default to 60 seconds of refresh time */
+	if (CONFIG(refresh) == 0)
+		CONFIG(refresh) = 60;
+
+	if (CONFIG(resend_buffer_size) == 0)
+		CONFIG(resend_buffer_size) = 262144;
+
+	/* create empty pool */
+	if (!STATE(ignore_pool)) {
+		STATE(ignore_pool) = ignore_pool_create(CONFIG(family));
+		if (!STATE(ignore_pool)) {
+			fprintf(stdout, "Can't create ignore pool!\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	/* default to a window size of 20 packets */
+	if (CONFIG(window_size) == 0)
+		CONFIG(window_size) = 20;
+
+	return 0;
+}
diff --git a/src/run.c b/src/run.c
new file mode 100644
index 0000000..67437d8
--- /dev/null
+++ b/src/run.c
@@ -0,0 +1,227 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Description: run and init functions
+ */
+
+#include "conntrackd.h"
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include <signal.h>
+#include <stdlib.h>
+
+void killer(int foo)
+{
+	/* no signals while handling signals */
+	sigprocmask(SIG_BLOCK, &STATE(block), NULL);
+
+	nfnl_subsys_close(STATE(subsys_event));
+	nfnl_subsys_close(STATE(subsys_dump));
+	nfnl_subsys_close(STATE(subsys_sync));
+	nfnl_close(STATE(event));
+	nfnl_close(STATE(dump));
+	nfnl_close(STATE(sync));
+
+	ignore_pool_destroy(STATE(ignore_pool));
+	local_server_destroy(STATE(local));
+	STATE(mode)->kill();
+        unlink(CONFIG(lockfile));
+	dlog(STATE(log), "------- shutdown received ----");
+	close_log(STATE(log));
+
+	sigprocmask(SIG_UNBLOCK, &STATE(block), NULL);
+
+	exit(0);			
+}
+
+void local_handler(int fd, void *data)
+{
+	int ret;
+	int type;
+
+	ret = read(fd, &type, sizeof(type));
+	if (ret == -1) {
+		dlog(STATE(log), "can't read from unix socket\n");
+		return;
+	}
+	if (ret == 0) {
+		debug("nothing to process\n");
+		return;
+	}
+
+	switch(type) {
+	case FLUSH_MASTER:
+		dlog(STATE(log), "[REQ] flushing master table");
+		nl_flush_master_conntrack_table();
+		return;
+	case RESYNC_MASTER:
+		dlog(STATE(log), "[REQ] resync with master table");
+		nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump));
+		return;
+	}
+
+	if (!STATE(mode)->local(fd, type, data))
+		dlog(STATE(log), "[FAIL] unknown local request %d", type);
+}
+
+int init(int mode)
+{
+	switch(mode) {
+		case STATS_MODE:
+			STATE(mode) = &stats_mode;
+			break;
+		case SYNC_MODE:
+			STATE(mode) = &sync_mode;
+			break;
+		default:
+			fprintf(stderr, "Unknown running mode! default "
+					"to synchronization mode\n");
+			STATE(mode) = &sync_mode;
+			break;
+	}
+
+	/* Initialization */
+	if (STATE(mode)->init() == -1) {
+		dlog(STATE(log), "[FAIL] initialization failed");
+		return -1;
+	}
+
+	/* local UNIX socket */
+	STATE(local) = local_server_create(&CONFIG(local));
+	if (!STATE(local)) {
+		dlog(STATE(log), "[FAIL] can't open unix socket!");
+		return -1;
+	}
+
+	if (nl_init_event_handler() == -1) {
+		dlog(STATE(log), "[FAIL] can't open netlink handler! "
+				 "no ctnetlink kernel support?");
+		return -1;
+	}
+
+	if (nl_init_dump_handler() == -1) {
+		dlog(STATE(log), "[FAIL] can't open netlink handler! "
+				 "no ctnetlink kernel support?");
+		return -1;
+	}
+
+	if (nl_init_overrun_handler() == -1) {
+		dlog(STATE(log), "[FAIL] can't open netlink handler! "
+				 "no ctnetlink kernel support?");
+		return -1;
+	}
+
+        /* Signals handling */
+	sigemptyset(&STATE(block));
+	sigaddset(&STATE(block), SIGTERM);
+	sigaddset(&STATE(block), SIGINT);
+
+	if (signal(SIGINT, killer) == SIG_ERR)
+		return -1;
+
+	if (signal(SIGTERM, killer) == SIG_ERR)
+		return -1;
+
+	/* ignore connection reset by peer */
+	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
+		return -1;
+
+	dlog(STATE(log), "[OK] initialization completed");
+
+	return 0;
+}
+
+#define POLL_NSECS 1
+
+static void __run(void)
+{
+	int max, ret;
+	fd_set readfds;
+	struct timeval tv = {
+		.tv_sec         = POLL_NSECS,
+		.tv_usec        = 0
+	};
+
+	FD_ZERO(&readfds);
+	FD_SET(STATE(local), &readfds);
+	FD_SET(nfnl_fd(STATE(event)), &readfds);
+
+	max = MAX(STATE(local), nfnl_fd(STATE(event)));
+
+	if (STATE(mode)->add_fds_to_set)
+		max = MAX(max, STATE(mode)->add_fds_to_set(&readfds));
+
+	ret = select(max+1, &readfds, NULL, NULL, &tv);
+	if (ret == -1) {
+		/* interrupted syscall, retry */
+		if (errno == EINTR)
+			return;
+
+		dlog(STATE(log), "select() failed: %s", strerror(errno));
+		return;
+	}
+
+	/* signals are racy */
+	sigprocmask(SIG_BLOCK, &STATE(block), NULL);		
+
+	/* order received via UNIX socket */
+	if (FD_ISSET(STATE(local), &readfds))
+		do_local_server_step(STATE(local), NULL, local_handler);
+
+	/* conntrack event has happened */
+	if (FD_ISSET(nfnl_fd(STATE(event)), &readfds)) {
+		ret = nfnl_catch(STATE(event));
+		if (ret == -1) {
+			switch(errno) {
+			case ENOBUFS:
+                		/*
+		 		 * It seems that ctnetlink can't back off,
+				 * it's likely that we're losing events.
+				 * Solution: duplicate the socket buffer
+				 * size and resync with master conntrack table.
+				 */
+				nl_resize_socket_buffer(STATE(event));
+				nl_dump_conntrack_table(STATE(sync),
+							STATE(subsys_sync));
+				break;
+			case ENOENT:
+				/*
+				 * We received a message from another
+				 * netfilter subsystem that we are not
+				 * interested in. Just ignore it.
+				 */
+				break;
+			default:
+				dlog(STATE(log), "event catch says: %s",
+						  strerror(errno));
+				break;
+			}
+		}
+	}
+
+	if (STATE(mode)->step)
+		STATE(mode)->step(&readfds);
+
+	sigprocmask(SIG_UNBLOCK, &STATE(block), NULL);
+}
+
+void run(void)
+{
+	while(1)
+		__run();
+}
diff --git a/src/state_helper.c b/src/state_helper.c
new file mode 100644
index 0000000..81b0d09
--- /dev/null
+++ b/src/state_helper.c
@@ -0,0 +1,44 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "conntrackd.h"
+#include "state_helper.h"
+
+static struct state_replication_helper *helper[IPPROTO_MAX];
+
+int state_helper_verdict(int type, struct nf_conntrack *ct) 
+{
+	u_int8_t l4proto;
+
+        if (type == NFCT_T_DESTROY)
+		return ST_H_REPLICATE;
+
+	l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
+	if (helper[l4proto])
+		return helper[l4proto]->verdict(helper[l4proto], ct);
+
+	return ST_H_REPLICATE;
+}
+
+void state_helper_register(struct state_replication_helper *h, int state)
+{
+	if (helper[h->proto] == NULL)
+		helper[h->proto] = h;
+
+	helper[h->proto]->state |= (1 << state);
+}
diff --git a/src/state_helper_tcp.c b/src/state_helper_tcp.c
new file mode 100644
index 0000000..af714dc
--- /dev/null
+++ b/src/state_helper_tcp.c
@@ -0,0 +1,35 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "conntrackd.h"
+#include "state_helper.h"
+
+static int tcp_verdict(const struct state_replication_helper *h,
+		       const struct nf_conntrack *ct)
+{
+	u_int8_t state = nfct_get_attr_u8(ct, ATTR_TCP_STATE);
+	if (h->state & (1 << state))
+		return ST_H_REPLICATE;
+
+	return ST_H_SKIP;
+}
+
+struct state_replication_helper tcp_state_helper = {
+	.proto 		= IPPROTO_TCP,
+	.verdict 	= tcp_verdict,
+};
diff --git a/src/stats-mode.c b/src/stats-mode.c
new file mode 100644
index 0000000..9647bbf
--- /dev/null
+++ b/src/stats-mode.c
@@ -0,0 +1,151 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include "cache.h"
+#include "conntrackd.h"
+#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include <signal.h>
+#include <sys/select.h>
+
+static int init_stats(void)
+{
+	int ret;
+
+	state.stats = malloc(sizeof(struct ct_stats_state));
+	if (!state.stats) {
+		dlog(STATE(log), "[FAIL] can't allocate memory for stats sync");
+		return -1;
+	}
+	memset(state.stats, 0, sizeof(struct ct_stats_state));
+
+	STATE_STATS(cache) = cache_create("stats",
+					  LIFETIME, 
+					  CONFIG(family),
+					  NULL); 
+	if (!STATE_STATS(cache)) {
+		dlog(STATE(log), "[FAIL] can't allocate memory for the "
+				 "external cache");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void kill_stats()
+{
+	cache_destroy(STATE_STATS(cache));
+}
+
+/* handler for requests coming via UNIX socket */
+static int local_handler_stats(int fd, int type, void *data)
+{
+	int ret = 1;
+
+	switch(type) {
+	case DUMP_INTERNAL:
+		cache_dump(STATE_STATS(cache), fd, NFCT_O_PLAIN);
+		break;
+	case DUMP_INT_XML:
+		cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML);
+		break;
+	case FLUSH_CACHE:
+		dlog(STATE(log), "[REQ] flushing caches");
+		cache_flush(STATE_STATS(cache));
+		break;
+	case KILL:
+		killer();
+		break;
+	case STATS:
+		cache_stats(STATE_STATS(cache), fd);
+		dump_traffic_stats(fd);
+		break;
+	default:
+		ret = 0;
+		break;
+	}
+
+	return ret;
+}
+
+static void dump_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	if (cache_update_force(STATE_STATS(cache), ct))
+		debug_ct(ct, "resync entry");
+}
+
+static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	debug_ct(ct, "debug event");
+	if (cache_add(STATE_STATS(cache), ct)) {
+		debug_ct(ct, "cache new");
+	} else {
+		dlog(STATE(log), "can't add to cache cache: "
+				      "%s\n", strerror(errno));
+		debug_ct(ct, "can't add");
+	}
+}
+
+static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	debug_ct(ct, "update");
+
+	if (!cache_update(STATE_STATS(cache), ct)) {
+		/*
+		 * Perhaps we are losing events. If we are working 
+		 * in relax mode then add a new entry to the cache.
+		 *
+		 * FIXME: relax transitions not implemented yet
+		 */
+		if ((CONFIG(flags) & RELAX_TRANSITIONS)
+		    && cache_add(STATE_STATS(cache), ct)) {
+			debug_ct(ct, "forcing cache update");
+		} else {
+			debug_ct(ct, "can't update");
+			return;
+		}
+	}
+	debug_ct(ct, "update");
+}
+
+static int event_destroy_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	if (cache_del(STATE_STATS(cache), ct)) {
+		debug_ct(ct, "cache destroy");
+		return 1;
+	} else {
+		debug_ct(ct, "can't destroy!");
+		return 0;
+	}
+}
+
+struct ct_mode stats_mode = {
+	.init 			= init_stats,
+	.add_fds_to_set 	= NULL,
+	.step			= NULL,
+	.local			= local_handler_stats,
+	.kill			= kill_stats,
+	.dump			= dump_stats,
+	.overrun		= dump_stats,
+	.event_new		= event_new_stats,
+	.event_upd		= event_update_stats,
+	.event_dst		= event_destroy_stats
+};
diff --git a/src/sync-mode.c b/src/sync-mode.c
new file mode 100644
index 0000000..b32bef7
--- /dev/null
+++ b/src/sync-mode.c
@@ -0,0 +1,416 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdlib.h>
+#include "cache.h"
+#include "conntrackd.h"
+#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include <signal.h>
+#include <sys/select.h>
+#include "sync.h"
+#include "network.h"
+
+/* handler for multicast messages received */
+static void mcast_handler()
+{
+	int ret;
+	char buf[4096], tmp[256];
+	struct mcast_sock *m = STATE_SYNC(mcast_server);
+	unsigned int type;
+	struct nlnetwork *net = (struct nlnetwork *) buf;
+	unsigned int size = sizeof(struct nlnetwork);
+	struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size);
+	struct nf_conntrack *ct = (struct nf_conntrack *) tmp;
+	struct us_conntrack *u = NULL;
+
+	memset(tmp, 0, sizeof(tmp));
+
+	ret = mcast_recv_netmsg(m, buf, sizeof(buf));
+	if (ret <= 0) {
+		STATE(malformed)++;
+		return;
+	}
+
+	if (STATE_SYNC(mcast_sync)->pre_recv(net))
+		return;
+
+	if ((type = parse_network_msg(ct, nlh)) == NFCT_T_ERROR) {
+		STATE(malformed)++;
+		return;
+	}
+
+	nfct_attr_unset(ct, ATTR_TIMEOUT);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS);
+
+	switch(type) {
+	case NFCT_T_NEW:
+retry:		
+		if ((u = cache_add(STATE_SYNC(external), ct))) {
+			debug_ct(u->ct, "external new");
+		} else {
+		        /*
+			 * One certain connection A arrives to the cache but 
+			 * another existing connection B in the cache has 
+			 * the same configuration, therefore B clashes with A.
+			 */
+			if (errno == EEXIST) {
+				cache_del(STATE_SYNC(external), ct);
+				goto retry;
+			}
+			debug_ct(ct, "can't add");
+		}
+		break;
+	case NFCT_T_UPDATE:
+		if ((u = cache_update_force(STATE_SYNC(external), ct))) {
+			debug_ct(u->ct, "external update");
+		} else
+			debug_ct(ct, "can't update");
+		break;
+	case NFCT_T_DESTROY:
+		if (cache_del(STATE_SYNC(external), ct))
+			debug_ct(ct, "external destroy");
+		else
+			debug_ct(ct, "can't destroy");
+		break;
+	default:
+		debug("unknown type %d\n", type);
+		break;
+	}
+}
+
+static int init_sync(void)
+{
+	int ret;
+
+	state.sync = malloc(sizeof(struct ct_sync_state));
+	if (!state.sync) {
+		dlog(STATE(log), "[FAIL] can't allocate memory for state sync");
+		return -1;
+	}
+	memset(state.sync, 0, sizeof(struct ct_sync_state));
+
+	if (CONFIG(flags) & SYNC_MODE_NACK)
+		STATE_SYNC(mcast_sync) = &nack;
+	else
+		/* default to persistent mode */
+		STATE_SYNC(mcast_sync) = &notrack;
+
+	if (STATE_SYNC(mcast_sync)->init)
+		STATE_SYNC(mcast_sync)->init();
+
+	STATE_SYNC(internal) =
+		cache_create("internal", 
+			     STATE_SYNC(mcast_sync)->internal_cache_flags,
+			     CONFIG(family),
+			     STATE_SYNC(mcast_sync)->internal_cache_extra);
+
+	if (!STATE_SYNC(internal)) {
+		dlog(STATE(log), "[FAIL] can't allocate memory for "
+				 "the internal cache");
+		return -1;
+	}
+
+	STATE_SYNC(external) = 
+		cache_create("external",
+			     STATE_SYNC(mcast_sync)->external_cache_flags,
+			     CONFIG(family),
+			     NULL);
+
+	if (!STATE_SYNC(external)) {
+		dlog(STATE(log), "[FAIL] can't allocate memory for the "
+				 "external cache");
+		return -1;
+	}
+
+	/* multicast server to receive events from the wire */
+	STATE_SYNC(mcast_server) = mcast_server_create(&CONFIG(mcast));
+	if (STATE_SYNC(mcast_server) == NULL) {
+		dlog(STATE(log), "[FAIL] can't open multicast server!");
+		return -1;
+	}
+
+	/* multicast client to send events on the wire */
+	STATE_SYNC(mcast_client) = mcast_client_create(&CONFIG(mcast));
+	if (STATE_SYNC(mcast_client) == NULL) {
+		dlog(STATE(log), "[FAIL] can't open client multicast socket!");
+		return -1;
+	}
+
+	/* initialization of multicast sequence generation */
+	STATE_SYNC(last_seq_sent) = time(NULL);
+
+	if (create_alarm_thread() == -1) {
+		dlog(STATE(log), "[FAIL] can't initialize alarm thread");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int add_fds_to_set_sync(fd_set *readfds) 
+{
+	FD_SET(STATE_SYNC(mcast_server->fd), readfds);
+
+	return STATE_SYNC(mcast_server->fd);
+}
+
+static void step_sync(fd_set *readfds)
+{
+	/* multicast packet has been received */
+	if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds))
+		mcast_handler();
+}
+
+static void kill_sync()
+{
+	cache_destroy(STATE_SYNC(internal));
+	cache_destroy(STATE_SYNC(external));
+
+	mcast_server_destroy(STATE_SYNC(mcast_server));
+	mcast_client_destroy(STATE_SYNC(mcast_client));
+
+	destroy_alarm_thread();
+
+	if (STATE_SYNC(mcast_sync)->kill)
+		STATE_SYNC(mcast_sync)->kill();
+}
+
+static dump_stats_sync(int fd)
+{
+	char buf[512];
+	int size;
+
+	size = sprintf(buf, "multicast sequence tracking:\n"
+			    "%20llu Pckts mfrm "
+			    "%20llu Pckts lost\n\n",
+			STATE(malformed),
+			STATE_SYNC(packets_lost));
+
+	send(fd, buf, size, 0);
+}
+
+/* handler for requests coming via UNIX socket */
+static int local_handler_sync(int fd, int type, void *data)
+{
+	int ret = 1;
+
+	switch(type) {
+	case DUMP_INTERNAL:
+		cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN);
+		break;
+	case DUMP_EXTERNAL:
+		cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN);
+		break;
+	case DUMP_INT_XML:
+		cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML);
+		break;
+	case DUMP_EXT_XML:
+		cache_dump(STATE_SYNC(external), fd, NFCT_O_XML);
+		break;
+	case COMMIT:
+		dlog(STATE(log), "[REQ] commit external cache to master table");
+		cache_commit(STATE_SYNC(external));
+		break;
+	case FLUSH_CACHE:
+		dlog(STATE(log), "[REQ] flushing caches");
+		cache_flush(STATE_SYNC(internal));
+		cache_flush(STATE_SYNC(external));
+		break;
+	case KILL:
+		killer();
+		break;
+	case STATS:
+		cache_stats(STATE_SYNC(internal), fd);
+		cache_stats(STATE_SYNC(external), fd);
+		dump_traffic_stats(fd);
+		mcast_dump_stats(fd, STATE_SYNC(mcast_client), 
+				     STATE_SYNC(mcast_server));
+		dump_stats_sync(fd);
+		break;
+	case SEND_BULK:
+		dlog(STATE(log), "[REQ] sending bulk update");
+		cache_bulk(STATE_SYNC(internal));
+		break;
+	default:
+		if (STATE_SYNC(mcast_sync)->local)
+			ret = STATE_SYNC(mcast_sync)->local(fd, type, data);
+		break;
+	}
+
+	return ret;
+}
+
+static void dump_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	/* This is required by kernels < 2.6.20 */
+	nfct_attr_unset(ct, ATTR_TIMEOUT);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_USE);
+
+	if (cache_update_force(STATE_SYNC(internal), ct))
+		debug_ct(ct, "resync");
+}
+
+static void mcast_send_sync(struct nlmsghdr *nlh,
+			    struct us_conntrack *u,
+			    struct nf_conntrack *ct,
+			    int type)
+{
+	char buf[4096];
+	struct nlnetwork *net = (struct nlnetwork *) buf;
+	int mangled = 0;
+
+	memset(buf, 0, sizeof(buf));
+
+	if (!state_helper_verdict(type, ct))
+		return;
+
+	if (!mangled)
+		memcpy(buf + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len);
+
+	mcast_send_netmsg(STATE_SYNC(mcast_client), net); 
+	STATE_SYNC(mcast_sync)->post_send(net, u);
+}
+
+static void overrun_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	struct us_conntrack *u;
+
+	/* This is required by kernels < 2.6.20 */
+	nfct_attr_unset(ct, ATTR_TIMEOUT);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_USE);
+
+	if (!cache_test(STATE_SYNC(internal), ct)) {
+		if ((u = cache_update_force(STATE_SYNC(internal), ct))) {
+			debug_ct(ct, "overrun resync");
+			mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE);
+		}
+	}
+}
+
+static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	struct us_conntrack *u;
+
+	/* required by linux kernel <= 2.6.20 */
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES);
+	nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS);
+	nfct_attr_unset(ct, ATTR_TIMEOUT);
+retry:
+	if ((u = cache_add(STATE_SYNC(internal), ct))) {
+		mcast_send_sync(nlh, u, ct, NFCT_T_NEW);
+		debug_ct(u->ct, "internal new");
+	} else {
+		if (errno == EEXIST) {
+			char buf[4096];
+			struct nlmsghdr *nlh = (struct nlmsghdr *) buf;
+
+			int ret = build_network_msg(NFCT_Q_DESTROY,
+						    STATE(subsys_event),
+						    ct,
+						    buf,
+						    sizeof(buf));
+			if (ret == -1)
+				return;
+
+			cache_del(STATE_SYNC(internal), ct);
+			mcast_send_sync(nlh, NULL, ct, NFCT_T_NEW);
+			goto retry;
+		}
+		dlog(STATE(log), "can't add to internal cache: "
+				      "%s\n", strerror(errno));
+		debug_ct(ct, "can't add");
+	}
+}
+
+static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	struct us_conntrack *u;
+
+	nfct_attr_unset(ct, ATTR_TIMEOUT);
+
+	if ((u = cache_update(STATE_SYNC(internal), ct)) == NULL) {
+		/*
+		 * Perhaps we are losing events. If we are working 
+		 * in relax mode then add a new entry to the cache.
+		 *
+		 * FIXME: relax transitions not implemented yet
+		 */
+		if ((CONFIG(flags) & RELAX_TRANSITIONS)
+		    && (u = cache_add(STATE_SYNC(internal), ct))) {
+			debug_ct(u->ct, "forcing internal update");
+		} else {
+			debug_ct(ct, "can't update");
+			return;
+		}
+	}
+	debug_ct(u->ct, "internal update");
+	mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE);
+}
+
+static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh)
+{
+	nfct_attr_unset(ct, ATTR_TIMEOUT);
+
+	if (CONFIG(flags) & DELAY_DESTROY_MSG) {
+
+		nfct_set_attr_u32(ct, ATTR_STATUS, IPS_DYING);
+
+		if (cache_update(STATE_SYNC(internal), ct)) {
+			debug_ct(ct, "delay internal destroy");
+			return 1;
+		} else {
+			debug_ct(ct, "can't delay destroy!");
+			return 0;
+		}
+	} else {
+		if (cache_del(STATE_SYNC(internal), ct)) {
+			mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY);
+			debug_ct(ct, "internal destroy");
+		} else
+			debug_ct(ct, "can't destroy");
+	}
+}
+
+struct ct_mode sync_mode = {
+	.init 			= init_sync,
+	.add_fds_to_set 	= add_fds_to_set_sync,
+	.step			= step_sync,
+	.local			= local_handler_sync,
+	.kill			= kill_sync,
+	.dump			= dump_sync,
+	.overrun		= overrun_sync,
+	.event_new		= event_new_sync,
+	.event_upd		= event_update_sync,
+	.event_dst		= event_destroy_sync
+};
diff --git a/src/sync-nack.c b/src/sync-nack.c
new file mode 100644
index 0000000..288dba4
--- /dev/null
+++ b/src/sync-nack.c
@@ -0,0 +1,309 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <errno.h>
+#include "conntrackd.h"
+#include "sync.h"
+#include "linux_list.h"
+#include "us-conntrack.h"
+#include "buffer.h"
+#include "debug.h"
+#include "network.h"
+#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+#if 0 
+#define dp printf
+#else
+#define dp
+#endif
+
+static LIST_HEAD(queue);
+
+struct cache_nack {
+	struct list_head 	head;
+	u_int32_t 		seq;
+};
+
+static void cache_nack_add(struct us_conntrack *u, void *data)
+{
+	struct cache_nack *cn = data;
+
+	INIT_LIST_HEAD(&cn->head);
+	list_add(&cn->head, &queue);
+}
+
+static void cache_nack_update(struct us_conntrack *u, void *data)
+{
+	struct cache_nack *cn = data;
+
+	if (cn->head.next != LIST_POISON1 &&
+	    cn->head.prev != LIST_POISON2)
+		list_del(&cn->head);
+
+	INIT_LIST_HEAD(&cn->head);
+	list_add(&cn->head, &queue);
+}
+
+static void cache_nack_destroy(struct us_conntrack *u, void *data)
+{
+	struct cache_nack *cn = data;
+
+	if (cn->head.next != LIST_POISON1 &&
+	    cn->head.prev != LIST_POISON2)
+		list_del(&cn->head);
+}
+
+static struct cache_extra cache_nack_extra = {
+	.size 		= sizeof(struct cache_nack),
+	.add		= cache_nack_add,
+	.update		= cache_nack_update,
+	.destroy	= cache_nack_destroy
+};
+
+static int nack_init()
+{
+	STATE_SYNC(buffer) = buffer_create(CONFIG(resend_buffer_size));
+	if (STATE_SYNC(buffer) == NULL)
+		return -1;
+
+	return 0;
+}
+
+static void nack_kill()
+{
+	buffer_destroy(STATE_SYNC(buffer));
+}
+
+static void mcast_send_nack(u_int32_t expt_seq, u_int32_t recv_seq)
+{
+	struct nlnetwork_ack nack = {
+		.flags = NET_NACK,
+		.from  = expt_seq,
+		.to    = recv_seq,
+	};
+
+	mcast_send_error(STATE_SYNC(mcast_client), &nack);
+	buffer_add(STATE_SYNC(buffer), &nack, sizeof(struct nlnetwork_ack));
+}
+
+static void mcast_send_ack(u_int32_t from, u_int32_t to)
+{
+	struct nlnetwork_ack ack = {
+		.flags = NET_ACK,
+		.from   = from,
+		.to	= to,
+	};
+
+	mcast_send_error(STATE_SYNC(mcast_client), &ack);
+	buffer_add(STATE_SYNC(buffer), &ack, sizeof(struct nlnetwork_ack));
+}
+
+static void mcast_send_resync()
+{
+	struct nlnetwork net = {
+		.flags = NET_RESYNC,
+	};
+
+	mcast_send_error(STATE_SYNC(mcast_client), &net);
+	buffer_add(STATE_SYNC(buffer), &net, sizeof(struct nlnetwork));
+}
+
+int nack_local(int fd, int type, void *data)
+{
+	int ret = 1;
+
+	switch(type) {
+		case REQUEST_DUMP:
+			mcast_send_resync();
+			dlog(STATE(log), "[REQ] request resync");
+			break;
+		default:
+			ret = 0;
+			break;
+	}
+
+	return ret;
+}
+
+static int buffer_compare(void *data1, void *data2)
+{
+	struct nlnetwork *net = data1;
+	struct nlnetwork_ack *nack = data2;
+	struct nlmsghdr *nlh = data1 + sizeof(struct nlnetwork);
+
+	unsigned old_seq = ntohl(net->seq);
+
+	if (ntohl(net->seq) >= nack->from && ntohl(net->seq) <= nack->to) {
+		if (mcast_resend_netmsg(STATE_SYNC(mcast_client), net))
+			dp("resend destroy (old seq=%u) (seq=%u)\n", 
+			   old_seq, ntohl(net->seq));
+	}
+	return 0;
+}
+
+static int buffer_remove(void *data1, void *data2)
+{
+	struct nlnetwork *net = data1;
+	struct nlnetwork_ack *h = data2;
+
+	if (ntohl(net->seq) >= h->from && ntohl(net->seq) <= h->to) {
+		dp("remove from buffer (seq=%u)\n", ntohl(net->seq));
+		__buffer_del(STATE_SYNC(buffer), data1);
+	}
+	return 0;
+}
+
+static void queue_resend(struct cache *c, unsigned int from, unsigned int to)
+{
+	struct list_head *n;
+	struct us_conntrack *u;
+	unsigned int *seq;
+
+	lock();
+	list_for_each(n, &queue) {
+		struct cache_nack *cn = (struct cache_nack *) n;
+		struct us_conntrack *u;
+		
+		u = cache_get_conntrack(STATE_SYNC(internal), cn);
+
+		if (cn->seq >= from && cn->seq <= to) {
+			debug_ct(u->ct, "resend nack");
+			dp("resending nack'ed (oldseq=%u) ", cn->seq);
+
+			char buf[4096];
+			struct nlnetwork *net = (struct nlnetwork *) buf;
+
+			int ret = build_network_msg(NFCT_Q_UPDATE,
+						    STATE(subsys_event),
+						    u->ct,
+						    buf,
+						    sizeof(buf));
+			if (ret == -1) {
+				unlock();
+				break;
+			}
+
+			mcast_send_netmsg(STATE_SYNC(mcast_client), buf); 
+			STATE_SYNC(mcast_sync)->post_send(net, u);
+			dp("(newseq=%u)\n", *seq);
+		} 
+	}
+	unlock();
+}
+
+static void queue_empty(struct cache *c, unsigned int from, unsigned int to)
+{
+	struct list_head *n, *tmp;
+	struct us_conntrack *u;
+	unsigned int *seq;
+
+	lock();
+	dp("ACK from %u to %u\n", from, to);
+	list_for_each_safe(n, tmp, &queue) {
+		struct cache_nack *cn = (struct cache_nack *) n;
+
+		u = cache_get_conntrack(STATE_SYNC(internal), cn);
+		if (cn->seq >= from && cn->seq <= to) {
+			dp("remove %u\n", cn->seq);
+			debug_ct(u->ct, "ack received: empty queue");
+			dp("queue: deleting from queue (seq=%u)\n", cn->seq);
+			list_del(&cn->head);
+		} 
+	}
+	unlock();
+}
+
+static int nack_pre_recv(const struct nlnetwork *net)
+{
+	static unsigned int window = 0;
+	unsigned int exp_seq;
+
+	if (window == 0)
+		window = CONFIG(window_size);
+
+	if (!mcast_track_seq(net->seq, &exp_seq)) {
+		dp("OOS: sending nack (seq=%u)\n", exp_seq);
+		mcast_send_nack(exp_seq, net->seq - 1);
+		window = CONFIG(window_size);
+	} else {
+		/* received a window, send an acknowledgement */
+		if (--window == 0) {
+			dp("sending ack (seq=%u)\n", net->seq);
+			mcast_send_ack(net->seq-CONFIG(window_size), net->seq);
+		}
+	}
+
+	if (net->flags & NET_NACK) {
+		struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net;
+
+		dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to);
+		queue_resend(STATE_SYNC(internal), nack->from, nack->to);
+		buffer_iterate(STATE_SYNC(buffer), nack, buffer_compare);
+		return 1;
+	} else if (net->flags & NET_RESYNC) {
+		dp("RESYNC ALL\n");
+		cache_bulk(STATE_SYNC(internal));
+		return 1;
+	} else if (net->flags & NET_ACK) {
+		struct nlnetwork_ack *h = (struct nlnetwork_ack *) net;
+
+		dp("ACK: from seq=%u to seq=%u\n", h->from, h->to);
+		queue_empty(STATE_SYNC(internal), h->from, h->to);
+		buffer_iterate(STATE_SYNC(buffer), h, buffer_remove);
+		return 1;
+	}
+
+	return 0;
+}
+
+static void nack_post_send(const struct nlnetwork *net, struct us_conntrack *u)
+{
+	unsigned int size = sizeof(struct nlnetwork);
+	struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size);
+
+	if (NFNL_MSG_TYPE(ntohs(nlh->nlmsg_type)) == IPCTNL_MSG_CT_DELETE) {
+		buffer_add(STATE_SYNC(buffer), net, 
+			   ntohl(nlh->nlmsg_len) + size); 
+	} else if (u != NULL) {
+		unsigned int *seq;
+		struct list_head *n;
+		struct cache_nack *cn;
+
+		cn = (struct cache_nack *)
+			cache_get_extra(STATE_SYNC(internal), u);
+		cn->seq = ntohl(net->seq);
+		if (cn->head.next != LIST_POISON1 &&
+		    cn->head.prev != LIST_POISON2)
+		    	list_del(&cn->head);
+
+		INIT_LIST_HEAD(&cn->head);
+		list_add(&cn->head, &queue);
+	}
+}
+
+struct sync_mode nack = {
+	.internal_cache_flags	= LIFETIME,
+	.external_cache_flags	= LIFETIME,
+	.internal_cache_extra	= &cache_nack_extra,
+	.init			= nack_init,
+	.kill			= nack_kill,
+	.local			= nack_local,
+	.pre_recv		= nack_pre_recv,
+	.post_send		= nack_post_send,
+};
diff --git a/src/sync-notrack.c b/src/sync-notrack.c
new file mode 100644
index 0000000..2b5ae38
--- /dev/null
+++ b/src/sync-notrack.c
@@ -0,0 +1,127 @@
+/*
+ * (C) 2006-2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "conntrackd.h"
+#include "sync.h"
+#include "network.h"
+#include "us-conntrack.h"
+#include "alarm.h"
+
+static void refresher(struct alarm_list *a, void *data)
+{
+	struct us_conntrack *u = data;
+	char buf[8192];
+	int size;
+
+	if (nfct_get_attr_u32(u->ct, ATTR_STATUS) & IPS_DYING) {
+		
+		debug_ct(u->ct, "persistence destroy");
+
+		size = build_network_msg(NFCT_Q_DESTROY,
+					 STATE(subsys_event),
+					 u->ct,
+					 buf,
+					 sizeof(buf));
+
+		__cache_del(u->cache, u->ct);
+		mcast_send_netmsg(STATE_SYNC(mcast_client), buf);
+	} else {
+		
+		debug_ct(u->ct, "persistence update");
+
+		a->expires = random() % CONFIG(refresh) + 1;
+		size = build_network_msg(NFCT_Q_UPDATE,
+					 STATE(subsys_event),
+					 u->ct,
+					 buf, 
+					 sizeof(buf));
+		mcast_send_netmsg(STATE_SYNC(mcast_client), buf);
+	}
+}
+
+static void cache_notrack_add(struct us_conntrack *u, void *data)
+{
+	struct alarm_list *alarm = data;
+
+	init_alarm(alarm);
+	set_alarm_expiration(alarm, (random() % conf.refresh) + 1);
+	set_alarm_data(alarm, u);
+	set_alarm_function(alarm, refresher);
+	add_alarm(alarm);
+}
+
+static void cache_notrack_update(struct us_conntrack *u, void *data)
+{
+	struct alarm_list *alarm = data;
+	mod_alarm(alarm, (random() % conf.refresh) + 1);
+}
+
+static void cache_notrack_destroy(struct us_conntrack *u, void *data)
+{
+	struct alarm_list *alarm = data;
+	del_alarm(alarm);
+}
+
+static struct cache_extra cache_notrack_extra = {
+	.size 		= sizeof(struct alarm_list),
+	.add		= cache_notrack_add,
+	.update		= cache_notrack_update,
+	.destroy	= cache_notrack_destroy
+};
+
+static int notrack_pre_recv(const struct nlnetwork *net)
+{
+	unsigned int exp_seq;
+
+	/* 
+	 * Ignore error messages: Although this message type is not ever
+	 * generated in notrack mode, we don't want to crash the daemon 
+	 * if someone nuts mixes nack and notrack.
+	 */
+	if (net->flags & (NET_RESYNC | NET_NACK))
+		return 1;
+
+	/* 
+	 * Multicast sequence tracking: we keep track of multicast messages
+	 * although we don't do any explicit message recovery. So, why do
+	 * we do sequence tracking? Just to let know the sysadmin.
+	 *
+	 * Let t be 1 < t < RefreshTime. To ensure consistency, conntrackd
+	 * retransmit every t seconds a message with the state of a certain
+	 * entry even if such entry did not change. This mechanism also
+	 * provides passive resynchronization, in other words, there is
+	 * no facility to request a full synchronization from new nodes that
+	 * just joined the cluster, instead they just get resynchronized in
+	 * RefreshTime seconds at worst case.
+	 */
+	mcast_track_seq(net->seq, &exp_seq);
+
+	return 0;
+}
+
+static void notrack_post_send(const struct nlnetwork *n, struct us_conntrack *u)
+{
+}
+
+struct sync_mode notrack = {
+	.internal_cache_flags	= LIFETIME,
+	.external_cache_flags	= TIMER | LIFETIME,
+	.internal_cache_extra	= &cache_notrack_extra,
+	.pre_recv 		= notrack_pre_recv,
+	.post_send		= notrack_post_send,
+};
diff --git a/src/traffic_stats.c b/src/traffic_stats.c
new file mode 100644
index 0000000..b510b77
--- /dev/null
+++ b/src/traffic_stats.c
@@ -0,0 +1,54 @@
+/*
+ * (C) 2006 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cache.h"
+#include "hash.h"
+#include "conntrackd.h"
+#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <errno.h>
+#include "us-conntrack.h"
+#include <signal.h>
+
+void update_traffic_stats(struct nf_conntrack *ct)
+{
+	STATE(bytes)[NFCT_DIR_ORIGINAL] +=
+		nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_BYTES);
+	STATE(bytes)[NFCT_DIR_REPLY] +=
+		nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_BYTES);
+	STATE(packets)[NFCT_DIR_ORIGINAL] += 
+		nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_PACKETS);
+	STATE(packets)[NFCT_DIR_REPLY] +=
+		nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_PACKETS);
+}
+
+void dump_traffic_stats(int fd)
+{
+	char buf[512];
+	int size;
+	u_int64_t bytes = STATE(bytes)[NFCT_DIR_ORIGINAL] +
+			  STATE(bytes)[NFCT_DIR_REPLY];
+	u_int64_t packets = STATE(packets)[NFCT_DIR_ORIGINAL] +
+			    STATE(packets)[NFCT_DIR_REPLY];
+
+	size = sprintf(buf, "traffic processed:\n");
+	size += sprintf(buf+size, "%20llu Bytes      ", bytes);
+	size += sprintf(buf+size, "%20llu Pckts\n\n", packets);
+
+	send(fd, buf, size, 0);
+}
diff --git a/test.sh b/test.sh
new file mode 100644
index 0000000..4694236
--- /dev/null
+++ b/test.sh
@@ -0,0 +1,110 @@
+CONNTRACK=conntrack
+
+SRC=1.1.1.1
+DST=2.2.2.2
+SPORT=2005
+DPORT=21
+
+case $1 in
+	dump)
+		echo "Dumping conntrack table"
+		$CONNTRACK -L
+		;;
+	flush)
+		echo "Flushing conntrack table"
+		$CONNTRACK -F
+		;;
+	new)
+		echo "creating a new conntrack"
+		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
+		 --reply-src $DST --reply-dst $SRC -p tcp \
+		 --orig-port-src $SPORT  --orig-port-dst $DPORT \
+		 --reply-port-src $DPORT --reply-port-dst $SPORT \
+		--state LISTEN -u SEEN_REPLY -t 50
+		;;
+	new-simple)
+		echo "creating a new conntrack (simplified)"
+		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
+		-p tcp --orig-port-src $SPORT  --orig-port-dst $DPORT \
+		--state LISTEN -u SEEN_REPLY -t 50
+		;;
+	new-nat)
+		echo "creating a new conntrack (NAT)"
+		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
+		-p tcp --orig-port-src $SPORT  --orig-port-dst $DPORT \
+		--state LISTEN -u SEEN_REPLY,SRC_NAT -t 50 -a 8.8.8.8
+		;;
+	get)
+		echo "getting a conntrack"
+		$CONNTRACK -G --orig-src $SRC --orig-dst $DST \
+		-p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \
+		--reply-port-src $DPORT --reply-port-dst $SPORT
+		;;
+	change)
+		echo "change a conntrack"
+		$CONNTRACK -U --orig-src $SRC --orig-dst $DST \
+		--reply-src $DST --reply-dst $SRC -p tcp \
+		--orig-port-src $SPORT --orig-port-dst $DPORT \
+		--reply-port-src $DPORT --reply-port-dst $SPORT \
+		--state TIME_WAIT -u ASSURED,SEEN_REPLY -t 500
+		;;
+	delete)
+		$CONNTRACK -D --orig-src $SRC --orig-dst $DST \
+		-p tcp --orig-port-src $SPORT --orig-port-dst $DPORT
+		;;
+	output)
+		proc=$(cat /proc/net/ip_conntrack | wc -l)
+		netl=$($CONNTRACK -L | wc -l)
+		count=$(cat /proc/sys/net/ipv4/netfilter/ip_conntrack_count)
+		if [ $proc -ne $netl ]; then
+			echo "proc is $proc and netl is $netl and count is $count"
+		else
+			if [ $proc -ne $count ]; then
+				echo "proc is $proc and netl is $netl and count is $count"
+			else
+				echo "now $proc"
+			fi
+		fi
+		;;
+	dump-expect)
+		$CONNTRACK -L expect
+		;;
+	flush-expect)
+		$CONNTRACK -F expect
+		;;
+	create-expect)
+		# requires modprobe ip_conntrack_ftp
+		$CONNTRACK -I expect --orig-src $SRC --orig-dst $DST \
+		--tuple-src 4.4.4.4 --tuple-dst 5.5.5.5 \
+		--mask-src 255.255.255.0 --mask-dst 255.255.255.255 \
+		-p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \
+		-t 200 --tuple-port-src 10 --tuple-port-dst 300 \
+		--mask-port-src 10 --mask-port-dst 300
+		;;
+	get-expect)
+		$CONNTRACK -G expect --orig-src 4.4.4.4 --orig-dst 5.5.5.5 \
+		--p tcp --orig-port-src 0 --orig-port-dst 0 \
+		--mask-port-src 10 --mask-port-dst 11
+		;;
+	delete-expect)
+		$CONNTRACK -D expect --orig-src 4.4.4.4 \
+		--orig-dst 5.5.5.5 -p tcp --orig-port-src 0 \
+		--orig-port-dst 0 --mask-port-src 10 --mask-port-dst 11
+		;;
+	*)
+		echo "Usage: $0 [dump"
+		echo "		|new"
+		echo "		|new-simple"
+		echo "		|new-nat"
+		echo "		|get"
+		echo "		|change"
+		echo "		|delete"
+		echo "		|output"
+		echo "		|flush"
+		echo "		|dump-expect"
+		echo "		|flush-expect"
+		echo "		|create-expect"
+		echo "		|get-expect"
+		echo "		|delete-expect]"
+		;;
+esac
-- 
cgit v1.2.3


From 4dd73e4e34b57685d8a85e041f6a0b4a65200e30 Mon Sep 17 00:00:00 2001
From: Jan Engelhardt <jengelh@medozas.de>
Date: Mon, 26 Jan 2009 19:30:33 +0100
Subject: build: upgrade build system

- add .gitignore files
- replace outdated autoconf macros by new constructs, including autogen.sh
- and use AC_CONFIG_MACRO_DIR as suggested by libtool2:

libtoolize: Consider adding `AC_CONFIG_MACRO_DIR([m4])' to configure.in and
libtoolize: rerunning libtoolize, to keep the correct libtool macros in-tree.
libtoolize: Consider adding `-I m4' to ACLOCAL_AMFLAGS in Makefile.am.

Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 Makefile.am  |  1 +
 autogen.sh   | 18 ++----------------
 configure.in |  6 ++++--
 3 files changed, 7 insertions(+), 18 deletions(-)

(limited to 'autogen.sh')

diff --git a/Makefile.am b/Makefile.am
index 7383328..fde65aa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,6 +2,7 @@ include Make_global.am
 
 # not a GNU package. You can remove this line, if
 # have all needed files, that a GNU package needs
+ACLOCAL_AMFLAGS  = -I m4
 AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
 
 man_MANS = conntrack.8 conntrackd.8
diff --git a/autogen.sh b/autogen.sh
index e76d3ef..36b2a2a 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,18 +1,4 @@
 #!/bin/sh
 
-run ()
-{
-    echo "running: $*"
-    eval $*
-
-    if test $? != 0 ; then
-	echo "error: while running '$*'"
-	exit 1
-    fi
-}
-
-run aclocal
-run libtoolize -f
-#run autoheader
-run automake -a
-run autoconf
+autoreconf -fi;
+rm -Rf autom4te.cache;
diff --git a/configure.in b/configure.in
index c430df7..cd2e7d5 100644
--- a/configure.in
+++ b/configure.in
@@ -2,7 +2,8 @@ AC_INIT(conntrack-tools, 0.9.10, pablo@netfilter.org)
 
 AC_CANONICAL_SYSTEM
 
-AM_INIT_AUTOMAKE
+AC_CONFIG_MACRO_DIR([m4])
+AM_INIT_AUTOMAKE([-Wall])
 
 AC_PROG_CC
 AM_PROG_LIBTOOL
@@ -130,4 +131,5 @@ CFLAGS="$CFLAGS $LIBNETFILTER_CONNTRACK_CFLAGS"
 
 AC_SUBST(LIBNETFILTER_CONNTRACK_LIBS)
 
-AC_OUTPUT(Makefile src/Makefile include/Makefile extensions/Makefile)
+AC_CONFIG_FILES([Makefile src/Makefile include/Makefile extensions/Makefile])
+AC_OUTPUT
-- 
cgit v1.2.3