summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/Makefile.am8
-rw-r--r--include/Makefile.in427
-rw-r--r--include/alarm.h33
-rw-r--r--include/bitops.h36
-rw-r--r--include/cache.h128
-rw-r--r--include/channel.h124
-rw-r--r--include/cidr.h9
-rw-r--r--include/conntrack.h206
-rw-r--r--include/conntrackd.h265
-rw-r--r--include/date.h10
-rw-r--r--include/debug.h21
-rw-r--r--include/event.h14
-rw-r--r--include/external.h24
-rw-r--r--include/fds.h22
-rw-r--r--include/filter.h55
-rw-r--r--include/hash.h44
-rw-r--r--include/internal.h39
-rw-r--r--include/jhash.h146
-rw-r--r--include/linux_list.h727
-rw-r--r--include/linux_rbtree.h160
-rw-r--r--include/local.h37
-rw-r--r--include/log.h13
-rw-r--r--include/mcast.h60
-rw-r--r--include/netlink.h33
-rw-r--r--include/network.h239
-rw-r--r--include/origin.h16
-rw-r--r--include/process.h25
-rw-r--r--include/queue.h62
-rw-r--r--include/sync.h28
-rw-r--r--include/tcp.h76
-rw-r--r--include/traffic_stats.h10
-rw-r--r--include/udp.h64
-rw-r--r--include/vector.h13
33 files changed, 3174 insertions, 0 deletions
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..cbbca6b
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,8 @@
+
+noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \
+ sync.h conntrackd.h local.h udp.h tcp.h \
+ debug.h log.h hash.h mcast.h conntrack.h \
+ network.h filter.h queue.h vector.h cidr.h \
+ traffic_stats.h netlink.h fds.h event.h bitops.h channel.h \
+ process.h origin.h internal.h external.h date.h
+
diff --git a/include/Makefile.in b/include/Makefile.in
new file mode 100644
index 0000000..5a38ca1
--- /dev/null
+++ b/include/Makefile.in
@@ -0,0 +1,427 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = include
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+SOURCES =
+DIST_SOURCES =
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_PKG_CONFIG = @HAVE_PKG_CONFIG@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBNETFILTER_CONNTRACK_CFLAGS = @LIBNETFILTER_CONNTRACK_CFLAGS@
+LIBNETFILTER_CONNTRACK_LIBS = @LIBNETFILTER_CONNTRACK_LIBS@
+LIBNFNETLINK_CFLAGS = @LIBNFNETLINK_CFLAGS@
+LIBNFNETLINK_LIBS = @LIBNFNETLINK_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XLEX = @XLEX@
+XYACC = @XYACC@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \
+ sync.h conntrackd.h local.h udp.h tcp.h \
+ debug.h log.h hash.h mcast.h conntrack.h \
+ network.h filter.h queue.h vector.h cidr.h \
+ traffic_stats.h netlink.h fds.h event.h bitops.h channel.h \
+ process.h origin.h internal.h external.h date.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu include/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool ctags distclean distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/include/alarm.h b/include/alarm.h
new file mode 100644
index 0000000..38aaa01
--- /dev/null
+++ b/include/alarm.h
@@ -0,0 +1,33 @@
+#ifndef _ALARM_H_
+#define _ALARM_H_
+
+#include "linux_rbtree.h"
+#include "linux_list.h"
+
+#include <sys/time.h>
+
+struct alarm_block {
+ struct rb_node node;
+ struct list_head list;
+ struct timeval tv;
+ void *data;
+ void (*function)(struct alarm_block *a, void *data);
+};
+
+void init_alarm(struct alarm_block *t,
+ void *data,
+ void (*fcn)(struct alarm_block *a, void *data));
+
+void add_alarm(struct alarm_block *alarm, unsigned long sc, unsigned long usc);
+
+void del_alarm(struct alarm_block *alarm);
+
+int alarm_pending(struct alarm_block *alarm);
+
+struct timeval *
+get_next_alarm_run(struct timeval *next_alarm);
+
+struct timeval *
+do_alarm_run(struct timeval *next_alarm);
+
+#endif
diff --git a/include/bitops.h b/include/bitops.h
new file mode 100644
index 0000000..51f4289
--- /dev/null
+++ b/include/bitops.h
@@ -0,0 +1,36 @@
+#ifndef _BITOPS_H_
+#define _BITOPS_H_
+
+#include <stdlib.h>
+
+static inline void set_bit_u32(int nr, u_int32_t *addr)
+{
+ addr[nr >> 5] |= (1UL << (nr & 31));
+}
+
+static inline void unset_bit_u32(int nr, u_int32_t *addr)
+{
+ addr[nr >> 5] &= ~(1UL << (nr & 31));
+}
+
+static inline int test_bit_u32(int nr, const u_int32_t *addr)
+{
+ return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0;
+}
+
+static inline void set_bit_u16(int nr, u_int16_t *addr)
+{
+ addr[nr >> 4] |= (1UL << (nr & 15));
+}
+
+static inline void unset_bit_u16(int nr, u_int16_t *addr)
+{
+ addr[nr >> 4] &= ~(1UL << (nr & 15));
+}
+
+static inline int test_bit_u16(int nr, const u_int16_t *addr)
+{
+ return ((1UL << (nr & 15)) & (addr[nr >> 4])) != 0;
+}
+
+#endif
diff --git a/include/cache.h b/include/cache.h
new file mode 100644
index 0000000..28917f2
--- /dev/null
+++ b/include/cache.h
@@ -0,0 +1,128 @@
+#ifndef _CACHE_H_
+#define _CACHE_H_
+
+#include <stdint.h>
+#include <stddef.h>
+#include "hash.h"
+#include "date.h"
+
+/* cache features */
+enum {
+ NO_FEATURES = 0,
+
+ TIMER_FEATURE = 0,
+ TIMER = (1 << TIMER_FEATURE),
+
+ __CACHE_MAX_FEATURE
+};
+#define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE
+
+enum {
+ C_OBJ_NONE = 0, /* not in the cache */
+ C_OBJ_NEW, /* just added to the cache */
+ C_OBJ_ALIVE, /* in the cache, alive */
+ C_OBJ_DEAD /* still in the cache, but dead */
+};
+
+struct cache;
+struct cache_object {
+ struct hashtable_node hashnode;
+ struct nf_conntrack *ct;
+ struct cache *cache;
+ int status;
+ int refcnt;
+ long lifetime;
+ long lastupdate;
+ char data[0];
+};
+
+struct cache_feature {
+ size_t size;
+ void (*add)(struct cache_object *obj, void *data);
+ void (*update)(struct cache_object *obj, void *data);
+ void (*destroy)(struct cache_object *obj, void *data);
+ int (*dump)(struct cache_object *obj, void *data, char *buf, int type);
+};
+
+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;
+ size_t object_size;
+
+ /* statistics */
+ struct {
+ uint32_t active;
+
+ uint32_t add_ok;
+ uint32_t del_ok;
+ uint32_t upd_ok;
+
+ uint32_t add_fail;
+ uint32_t del_fail;
+ uint32_t upd_fail;
+
+ uint32_t add_fail_enomem;
+ uint32_t add_fail_enospc;
+ uint32_t del_fail_enoent;
+ uint32_t upd_fail_enoent;
+
+ uint32_t commit_ok;
+ uint32_t commit_fail;
+
+ uint32_t flush;
+
+ uint32_t objects;
+ } stats;
+};
+
+struct cache_extra {
+ unsigned int size;
+
+ void (*add)(struct cache_object *obj, void *data);
+ void (*update)(struct cache_object *obj, void *data);
+ void (*destroy)(struct cache_object *obj, void *data);
+};
+
+struct nf_conntrack;
+
+struct cache *cache_create(const char *name, unsigned int features, struct cache_extra *extra);
+void cache_destroy(struct cache *e);
+
+struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct);
+void cache_object_free(struct cache_object *obj);
+void cache_object_get(struct cache_object *obj);
+int cache_object_put(struct cache_object *obj);
+void cache_object_set_status(struct cache_object *obj, int status);
+
+int cache_add(struct cache *c, struct cache_object *obj, int id);
+void cache_update(struct cache *c, struct cache_object *obj, int id, struct nf_conntrack *ct);
+struct cache_object *cache_update_force(struct cache *c, struct nf_conntrack *ct);
+void cache_del(struct cache *c, struct cache_object *obj);
+struct cache_object *cache_find(struct cache *c, struct nf_conntrack *ct, int *pos);
+void cache_stats(const struct cache *c, int fd);
+void cache_stats_extended(const struct cache *c, int fd);
+struct cache_object *cache_data_get_object(struct cache *c, void *data);
+void *cache_get_extra(struct cache *, void *);
+void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2));
+void cache_iterate_limit(struct cache *c, void *data, uint32_t from, uint32_t steps, int (*iterate)(void *data1, void *data2));
+
+/* iterators */
+struct nfct_handle;
+
+void cache_dump(struct cache *c, int fd, int type);
+void cache_commit(struct cache *c, struct nfct_handle *h, int clientfd);
+void cache_flush(struct cache *c);
+void cache_bulk(struct cache *c);
+
+#endif
diff --git a/include/channel.h b/include/channel.h
new file mode 100644
index 0000000..9b5fad8
--- /dev/null
+++ b/include/channel.h
@@ -0,0 +1,124 @@
+#ifndef _CHANNEL_H_
+#define _CHANNEL_H_
+
+#include "mcast.h"
+#include "udp.h"
+#include "tcp.h"
+
+struct channel;
+struct nethdr;
+
+enum {
+ CHANNEL_NONE,
+ CHANNEL_MCAST,
+ CHANNEL_UDP,
+ CHANNEL_TCP,
+ CHANNEL_MAX,
+};
+
+struct mcast_channel {
+ struct mcast_sock *client;
+ struct mcast_sock *server;
+};
+
+struct udp_channel {
+ struct udp_sock *client;
+ struct udp_sock *server;
+};
+
+struct tcp_channel {
+ struct tcp_sock *client;
+ struct tcp_sock *server;
+};
+
+#define CHANNEL_F_DEFAULT (1 << 0)
+#define CHANNEL_F_BUFFERED (1 << 1)
+#define CHANNEL_F_STREAM (1 << 2)
+#define CHANNEL_F_ERRORS (1 << 3)
+#define CHANNEL_F_MAX (1 << 4)
+
+union channel_type_conf {
+ struct mcast_conf mcast;
+ struct udp_conf udp;
+ struct tcp_conf tcp;
+};
+
+struct channel_conf {
+ int channel_type;
+ char channel_ifname[IFNAMSIZ];
+ unsigned int channel_flags;
+ union channel_type_conf u;
+};
+
+struct nlif_handle;
+
+struct channel_ops {
+ int headersiz;
+ void * (*open)(void *conf);
+ void (*close)(void *channel);
+ int (*send)(void *channel, const void *data, int len);
+ int (*recv)(void *channel, char *buf, int len);
+ int (*accept)(struct channel *c);
+ int (*get_fd)(void *channel);
+ int (*isset)(struct channel *c, fd_set *readfds);
+ int (*accept_isset)(struct channel *c, fd_set *readfds);
+ void (*stats)(struct channel *c, int fd);
+ void (*stats_extended)(struct channel *c, int active,
+ struct nlif_handle *h, int fd);
+};
+
+struct channel_buffer;
+
+struct channel {
+ int channel_type;
+ int channel_ifindex;
+ int channel_ifmtu;
+ unsigned int channel_flags;
+ struct channel_buffer *buffer;
+ struct channel_ops *ops;
+ void *data;
+};
+
+int channel_init(void);
+void channel_end(void);
+struct channel *channel_open(struct channel_conf *conf);
+void channel_close(struct channel *c);
+
+int channel_send(struct channel *c, const struct nethdr *net);
+int channel_send_flush(struct channel *c);
+int channel_recv(struct channel *c, char *buf, int size);
+int channel_accept(struct channel *c);
+
+int channel_get_fd(struct channel *c);
+int channel_accept_isset(struct channel *c, fd_set *readfds);
+int channel_isset(struct channel *c, fd_set *readfds);
+
+void channel_stats(struct channel *c, int fd);
+void channel_stats_extended(struct channel *c, int active,
+ struct nlif_handle *h, int fd);
+
+#define MULTICHANNEL_MAX 4
+
+struct multichannel {
+ int channel_num;
+ struct channel *channel[MULTICHANNEL_MAX];
+ struct channel *current;
+};
+
+struct multichannel *multichannel_open(struct channel_conf *conf, int len);
+void multichannel_close(struct multichannel *m);
+
+int multichannel_send(struct multichannel *c, const struct nethdr *net);
+int multichannel_send_flush(struct multichannel *c);
+int multichannel_recv(struct multichannel *c, char *buf, int size);
+
+void multichannel_stats(struct multichannel *m, int fd);
+void multichannel_stats_extended(struct multichannel *m,
+ struct nlif_handle *h, int fd);
+
+int multichannel_get_ifindex(struct multichannel *m, int i);
+int multichannel_get_current_ifindex(struct multichannel *m);
+void multichannel_set_current_channel(struct multichannel *m, int i);
+void multichannel_change_current_channel(struct multichannel *m, int i);
+
+#endif /* _CHANNEL_H_ */
diff --git a/include/cidr.h b/include/cidr.h
new file mode 100644
index 0000000..413c321
--- /dev/null
+++ b/include/cidr.h
@@ -0,0 +1,9 @@
+#ifndef _CIDR_H_
+
+uint32_t ipv4_cidr2mask_host(uint8_t cidr);
+uint32_t ipv4_cidr2mask_net(uint8_t cidr);
+void ipv6_cidr2mask_host(uint8_t cidr, uint32_t *res);
+void ipv6_cidr2mask_net(uint8_t cidr, uint32_t *res);
+void ipv6_addr2addr_host(uint32_t *addr, uint32_t *res);
+
+#endif
diff --git a/include/conntrack.h b/include/conntrack.h
new file mode 100644
index 0000000..61e7581
--- /dev/null
+++ b/include/conntrack.h
@@ -0,0 +1,206 @@
+#ifndef _CONNTRACK_H
+#define _CONNTRACK_H
+
+#include "linux_list.h"
+#include <stdint.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+#define PROGNAME "conntrack"
+
+#include <netinet/in.h>
+
+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),
+
+ CT_COUNT_BIT = 15,
+ CT_COUNT = (1 << CT_COUNT_BIT),
+
+ EXP_COUNT_BIT = 16,
+ EXP_COUNT = (1 << EXP_COUNT_BIT),
+
+ X_STATS_BIT = 17,
+ X_STATS = (1 << X_STATS_BIT),
+};
+#define NUMBER_OF_CMD 18
+
+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_TUPLE_ORIG = (CT_OPT_ORIG | CT_OPT_PROTO),
+ CT_OPT_TUPLE_REPL = (CT_OPT_REPL | CT_OPT_PROTO),
+
+ 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_SRC_NAT_BIT = 17,
+ CT_OPT_SRC_NAT = (1 << CT_OPT_SRC_NAT_BIT),
+
+ CT_OPT_DST_NAT_BIT = 18,
+ CT_OPT_DST_NAT = (1 << CT_OPT_DST_NAT_BIT),
+
+ CT_OPT_OUTPUT_BIT = 19,
+ CT_OPT_OUTPUT = (1 << CT_OPT_OUTPUT_BIT),
+
+ CT_OPT_SECMARK_BIT = 20,
+ CT_OPT_SECMARK = (1 << CT_OPT_SECMARK_BIT),
+
+ CT_OPT_BUFFERSIZE_BIT = 21,
+ CT_OPT_BUFFERSIZE = (1 << CT_OPT_BUFFERSIZE_BIT),
+
+ CT_OPT_MAX = CT_OPT_BUFFERSIZE_BIT
+};
+#define NUMBER_OF_OPT CT_OPT_MAX+1
+
+enum {
+ _O_XML = (1 << 0),
+ _O_EXT = (1 << 1),
+ _O_TMS = (1 << 2),
+ _O_ID = (1 << 3),
+};
+
+struct ctproto_handler {
+ struct list_head head;
+
+ const char *name;
+ uint16_t protonum;
+ const char *version;
+
+ enum ctattr_protoinfo protoinfo_attr;
+
+ int (*parse_opts)(char c,
+ struct nf_conntrack *ct,
+ struct nf_conntrack *exptuple,
+ struct nf_conntrack *mask,
+ unsigned int *flags);
+
+ void (*final_check)(unsigned int flags,
+ unsigned int command,
+ struct nf_conntrack *ct);
+
+ void (*help)(void);
+
+ struct option *opts;
+
+ unsigned int option_offset;
+};
+
+enum exittype {
+ OTHER_PROBLEM = 1,
+ PARAMETER_PROBLEM,
+ VERSION_PROBLEM
+};
+
+int generic_opt_check(int options, int nops,
+ char *optset, const char *optflg[],
+ unsigned int *coupled_flags, int coupled_flags_size,
+ int *partial);
+void exit_error(enum exittype status, const char *msg, ...);
+
+extern void register_proto(struct ctproto_handler *h);
+
+extern void register_tcp(void);
+extern void register_udp(void);
+extern void register_udplite(void);
+extern void register_sctp(void);
+extern void register_dccp(void);
+extern void register_icmp(void);
+extern void register_icmpv6(void);
+extern void register_gre(void);
+extern void register_unknown(void);
+
+#endif
diff --git a/include/conntrackd.h b/include/conntrackd.h
new file mode 100644
index 0000000..c7f33f0
--- /dev/null
+++ b/include/conntrackd.h
@@ -0,0 +1,265 @@
+#ifndef _CONNTRACKD_H_
+#define _CONNTRACKD_H_
+
+#include "mcast.h"
+#include "local.h"
+#include "alarm.h"
+#include "filter.h"
+#include "channel.h"
+#include "internal.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <syslog.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 RESET_TIMERS 26 /* reset kernel timers */
+#define DEBUG_INFO 27 /* unused */
+#define STATS_NETWORK 28 /* extended network stats */
+#define STATS_CACHE 29 /* extended cache stats */
+#define STATS_RUNTIME 30 /* extended runtime stats */
+#define STATS_LINK 31 /* dedicated link stats */
+#define STATS_RSQUEUE 32 /* resend queue stats */
+#define FLUSH_INT_CACHE 33 /* flush internal cache */
+#define FLUSH_EXT_CACHE 34 /* flush external cache */
+#define STATS_PROCESS 35 /* child process stats */
+#define STATS_QUEUE 36 /* queue stats */
+
+#define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf"
+#define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock"
+#define DEFAULT_LOGFILE "/var/log/conntrackd.log"
+#define DEFAULT_STATS_LOGFILE "/var/log/conntrackd-stats.log"
+#define DEFAULT_SYSLOG_FACILITY LOG_DAEMON
+
+/* daemon/request modes */
+#define NOT_SET 0
+#define DAEMON 1
+#define REQUEST 2
+
+/* conntrackd modes */
+#define CTD_SYNC_MODE (1UL << 0)
+#define CTD_STATS_MODE (1UL << 1)
+#define CTD_SYNC_FTFW (1UL << 2)
+#define CTD_SYNC_ALARM (1UL << 3)
+#define CTD_SYNC_NOTRACK (1UL << 4)
+#define CTD_POLL (1UL << 5)
+
+/* FILENAME_MAX is 4096 on my system, perhaps too much? */
+#ifndef FILENAME_MAXLEN
+#define FILENAME_MAXLEN 256
+#endif
+
+union inet_address {
+ uint32_t ipv4;
+ uint32_t ipv6[4];
+ uint32_t all[4];
+};
+
+#define CONFIG(x) conf.x
+
+struct ct_conf {
+ char logfile[FILENAME_MAXLEN];
+ int syslog_facility;
+ char lockfile[FILENAME_MAXLEN];
+ int hashsize; /* hashtable size */
+ int channel_num;
+ int channel_default;
+ int channel_type_global;
+ struct channel_conf channel[MULTICHANNEL_MAX];
+ struct local_conf local; /* unix socket facilities */
+ int nice;
+ int limit;
+ int refresh;
+ int cache_timeout; /* cache entries timeout */
+ int commit_timeout; /* committed entries timeout */
+ unsigned int purge_timeout; /* purge kernel entries timeout */
+ unsigned int netlink_buffer_size;
+ unsigned int netlink_buffer_size_max_grown;
+ int nl_overrun_resync;
+ unsigned int flags;
+ int family; /* protocol family */
+ unsigned int resend_queue_size; /* FTFW protocol */
+ unsigned int window_size;
+ int poll_kernel_secs;
+ int filter_from_kernelspace;
+ int event_iterations_limit;
+ struct {
+ int error_queue_length;
+ } channelc;
+ struct {
+ int internal_cache_disable;
+ int external_cache_disable;
+ } sync;
+ struct {
+ int events_reliable;
+ } netlink;
+ struct {
+ int commit_steps;
+ } general;
+ struct {
+ int type;
+ int prio;
+ } sched;
+ struct {
+ char logfile[FILENAME_MAXLEN];
+ int syslog_facility;
+ size_t buffer_size;
+ } stats;
+};
+
+#define STATE(x) st.x
+
+struct ct_general_state {
+ sigset_t block;
+ FILE *log;
+ FILE *stats_log;
+ struct local_server local;
+ struct ct_mode *mode;
+ struct ct_filter *us_filter;
+
+ struct nfct_handle *event; /* event handler */
+ struct nfct_filter *filter; /* event filter */
+ int event_iterations_limit;
+
+ struct nfct_handle *dump; /* dump handler */
+ struct nfct_handle *resync; /* resync handler */
+ struct nfct_handle *get; /* get handler */
+ int get_retval; /* hackish */
+ struct nfct_handle *flush; /* flusher */
+
+ struct alarm_block resync_alarm;
+ struct alarm_block polling_alarm;
+
+ struct fds *fds;
+
+ /* statistics */
+ struct {
+ uint64_t bytes_orig;
+ uint64_t bytes_repl;
+ uint64_t packets_orig;
+ uint64_t packets_repl;
+
+ time_t daemon_start_time;
+
+ uint64_t nl_events_received;
+ uint64_t nl_events_filtered;
+ uint32_t nl_events_unknown_type;
+ uint32_t nl_catch_event_failed;
+ uint32_t nl_overrun;
+ uint32_t nl_dump_unknown_type;
+ uint32_t nl_kernel_table_flush;
+ uint32_t nl_kernel_table_resync;
+
+ uint32_t child_process_failed;
+ uint32_t child_process_error_segfault;
+ uint32_t child_process_error_term;
+
+ uint32_t select_failed;
+ uint32_t wait_failed;
+
+ uint32_t local_read_failed;
+ uint32_t local_unknown_request;
+
+ } stats;
+};
+
+#define STATE_SYNC(x) state.sync->x
+
+struct ct_sync_state {
+ struct external_handler *external;
+
+ struct multichannel *channel;
+ struct nlif_handle *interface;
+ struct queue *tx_queue;
+
+#define COMMIT_STATE_INACTIVE 0
+#define COMMIT_STATE_MASTER 1
+#define COMMIT_STATE_RELATED 2
+
+ struct {
+ int state;
+ int clientfd;
+ struct nfct_handle *h;
+ struct evfd *evfd;
+ int current;
+ struct {
+ int ok;
+ int fail;
+ struct timeval start;
+ } stats;
+ } commit;
+
+ struct alarm_block reset_cache_alarm;
+
+ struct sync_mode *sync; /* sync mode */
+
+ /* statistics */
+ struct {
+ uint64_t msg_rcv_malformed;
+ uint32_t msg_rcv_bad_version;
+ uint32_t msg_rcv_bad_payload;
+ uint32_t msg_rcv_bad_header;
+ uint32_t msg_rcv_bad_type;
+ uint32_t msg_rcv_truncated;
+ uint32_t msg_rcv_bad_size;
+ uint32_t msg_snd_malformed;
+ uint64_t msg_rcv_lost;
+ uint64_t msg_rcv_before;
+ } error;
+
+ uint32_t last_seq_sent; /* last sequence number sent */
+ uint32_t last_seq_recv; /* last sequence number recv */
+};
+
+#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;
+
+struct ct_mode {
+ struct internal_handler *internal;
+ int (*init)(void);
+ void (*run)(fd_set *readfds);
+ int (*local)(int fd, int type, void *data);
+ void (*kill)(void);
+};
+
+/* conntrackd modes */
+extern struct ct_mode sync_mode;
+extern struct ct_mode stats_mode;
+
+#define MAX(x, y) x > y ? x : y
+
+/* These live in run.c */
+void killer(int foo);
+int init(void);
+void run(void);
+
+/* from read_config_yy.c */
+int
+init_config(char *filename);
+
+#endif
diff --git a/include/date.h b/include/date.h
new file mode 100644
index 0000000..296b996
--- /dev/null
+++ b/include/date.h
@@ -0,0 +1,10 @@
+#ifndef _DATE_H_
+#define _DATE_H_
+
+#include <sys/time.h>
+
+int do_gettimeofday(void);
+void gettimeofday_cached(struct timeval *tv);
+int time_cached(void);
+
+#endif
diff --git a/include/debug.h b/include/debug.h
new file mode 100644
index 0000000..f205983
--- /dev/null
+++ b/include/debug.h
@@ -0,0 +1,21 @@
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+#undef DEBUG_CT
+
+#ifdef DEBUG_CT
+#define debug_ct(ct, msg) \
+({ \
+ char buf[1024]; \
+ nfct_snprintf(buf, 1024, ct, NFCT_T_ALL, 0, 0); \
+ printf("[%s]: %s\n", msg, buf); \
+})
+#define debug printf
+#else
+#define debug_ct(ct, msg) do {} while (0)
+#define debug(...) do {} while (0)
+#endif
+
+#endif
diff --git a/include/event.h b/include/event.h
new file mode 100644
index 0000000..b6bff5a
--- /dev/null
+++ b/include/event.h
@@ -0,0 +1,14 @@
+#ifndef _EVENT_H_
+#define _EVENT_H_
+
+struct evfd *create_evfd(void);
+
+void destroy_evfd(struct evfd *e);
+
+int get_read_evfd(struct evfd *evfd);
+
+int write_evfd(struct evfd *evfd);
+
+int read_evfd(struct evfd *evfd);
+
+#endif
diff --git a/include/external.h b/include/external.h
new file mode 100644
index 0000000..938941a
--- /dev/null
+++ b/include/external.h
@@ -0,0 +1,24 @@
+#ifndef _EXTERNAL_H_
+#define _EXTERNAL_H_
+
+struct nf_conntrack;
+
+struct external_handler {
+ int (*init)(void);
+ void (*close)(void);
+
+ void (*new)(struct nf_conntrack *ct);
+ void (*update)(struct nf_conntrack *ct);
+ void (*destroy)(struct nf_conntrack *ct);
+
+ void (*dump)(int fd, int type);
+ void (*flush)(void);
+ void (*commit)(struct nfct_handle *h, int fd);
+ void (*stats)(int fd);
+ void (*stats_ext)(int fd);
+};
+
+extern struct external_handler external_cache;
+extern struct external_handler external_inject;
+
+#endif
diff --git a/include/fds.h b/include/fds.h
new file mode 100644
index 0000000..f3728d7
--- /dev/null
+++ b/include/fds.h
@@ -0,0 +1,22 @@
+#ifndef _FDS_H_
+#define _FDS_H_
+
+#include "linux_list.h"
+
+struct fds {
+ int maxfd;
+ fd_set readfds;
+ struct list_head list;
+};
+
+struct fds_item {
+ struct list_head head;
+ int fd;
+};
+
+struct fds *create_fds(void);
+void destroy_fds(struct fds *);
+int register_fd(int fd, struct fds *fds);
+int unregister_fd(int fd, struct fds *fds);
+
+#endif
diff --git a/include/filter.h b/include/filter.h
new file mode 100644
index 0000000..72c2aa4
--- /dev/null
+++ b/include/filter.h
@@ -0,0 +1,55 @@
+#ifndef _FILTER_H_
+#define _FILTER_H_
+
+#include <stdint.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <hash.h>
+
+enum ct_filter_type {
+ CT_FILTER_L4PROTO,
+ CT_FILTER_STATE,
+ CT_FILTER_ADDRESS, /* also for netmask */
+ CT_FILTER_MAX
+};
+
+enum ct_filter_logic {
+ CT_FILTER_NEGATIVE = 0,
+ CT_FILTER_POSITIVE = 1,
+};
+
+struct ct_filter_ipv4_hnode {
+ struct hashtable_node node;
+ uint32_t ip;
+};
+
+struct ct_filter_ipv6_hnode {
+ struct hashtable_node node;
+ uint32_t ipv6[4];
+};
+
+struct ct_filter_netmask_ipv4 {
+ uint32_t ip;
+ uint32_t mask;
+};
+
+struct ct_filter_netmask_ipv6 {
+ uint32_t ip[4];
+ uint32_t mask[4];
+};
+
+struct nf_conntrack;
+struct ct_filter;
+
+struct ct_filter *ct_filter_create(void);
+void ct_filter_destroy(struct ct_filter *filter);
+int ct_filter_add_ip(struct ct_filter *filter, void *data, uint8_t family);
+int ct_filter_add_netmask(struct ct_filter *filter, void *data, uint8_t family);
+void ct_filter_add_proto(struct ct_filter *filter, int protonum);
+void ct_filter_add_state(struct ct_filter *f, int protonum, int state);
+void ct_filter_set_logic(struct ct_filter *f,
+ enum ct_filter_type type,
+ enum ct_filter_logic logic);
+int ct_filter_conntrack(struct nf_conntrack *ct, int userspace);
+
+#endif
diff --git a/include/hash.h b/include/hash.h
new file mode 100644
index 0000000..eaa9e96
--- /dev/null
+++ b/include/hash.h
@@ -0,0 +1,44 @@
+#ifndef _NF_SET_HASH_H_
+#define _NF_SET_HASH_H_
+
+#include <unistd.h>
+#include "linux_list.h"
+
+#include <stdint.h>
+
+struct hashtable;
+struct hashtable_node;
+
+struct hashtable {
+ uint32_t hashsize;
+ uint32_t limit;
+ uint32_t count;
+ uint32_t initval;
+
+ uint32_t (*hash)(const void *data, const struct hashtable *table);
+ int (*compare)(const void *data1, const void *data2);
+
+ struct list_head members[0];
+};
+
+struct hashtable_node {
+ struct list_head head;
+};
+
+struct hashtable *
+hashtable_create(int hashsize, int limit,
+ uint32_t (*hash)(const void *data,
+ const struct hashtable *table),
+ int (*compare)(const void *data1, const void *data2));
+void hashtable_destroy(struct hashtable *h);
+int hashtable_hash(const struct hashtable *table, const void *data);
+struct hashtable_node *hashtable_find(const struct hashtable *table, const void *data, int id);
+int hashtable_add(struct hashtable *table, struct hashtable_node *n, int id);
+void hashtable_del(struct hashtable *table, struct hashtable_node *node);
+int hashtable_flush(struct hashtable *table);
+int hashtable_iterate(struct hashtable *table, void *data,
+ int (*iterate)(void *data, void *n));
+int hashtable_iterate_limit(struct hashtable *table, void *data, uint32_t from, uint32_t steps, int (*iterate)(void *data1, void *n));
+unsigned int hashtable_counter(const struct hashtable *table);
+
+#endif
diff --git a/include/internal.h b/include/internal.h
new file mode 100644
index 0000000..1f11340
--- /dev/null
+++ b/include/internal.h
@@ -0,0 +1,39 @@
+#ifndef _INTERNAL_H_
+#define _INTERNAL_H_
+
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+struct nf_conntrack;
+
+enum {
+ INTERNAL_F_POPULATE = (1 << 0),
+ INTERNAL_F_RESYNC = (1 << 1),
+ INTERNAL_F_MAX = (1 << 2)
+};
+
+struct internal_handler {
+ void *data;
+ unsigned int flags;
+
+ int (*init)(void);
+ void (*close)(void);
+
+ void (*new)(struct nf_conntrack *ct, int origin_type);
+ void (*update)(struct nf_conntrack *ct, int origin_type);
+ int (*destroy)(struct nf_conntrack *ct, int origin_type);
+
+ void (*dump)(int fd, int type);
+ void (*populate)(struct nf_conntrack *ct);
+ void (*purge)(void);
+ int (*resync)(enum nf_conntrack_msg_type type,
+ struct nf_conntrack *ct, void *data);
+ void (*flush)(void);
+
+ void (*stats)(int fd);
+ void (*stats_ext)(int fd);
+};
+
+extern struct internal_handler internal_cache;
+extern struct internal_handler internal_bypass;
+
+#endif
diff --git a/include/jhash.h b/include/jhash.h
new file mode 100644
index 0000000..d164e38
--- /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(const 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..de182a4
--- /dev/null
+++ b/include/linux_list.h
@@ -0,0 +1,727 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include <stddef.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) ({ \
+ 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/linux_rbtree.h b/include/linux_rbtree.h
new file mode 100644
index 0000000..ee98891
--- /dev/null
+++ b/include/linux_rbtree.h
@@ -0,0 +1,160 @@
+/*
+ Red Black Trees
+ (C) 1999 Andrea Arcangeli <andrea@suse.de>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ linux/include/linux/rbtree.h
+
+ To use rbtrees you'll have to implement your own insert and search cores.
+ This will avoid us to use callbacks and to drop drammatically performances.
+ I know it's not the cleaner way, but in C (not in C++) to get
+ performances and genericity...
+
+ Some example of insert and search follows here. The search is a plain
+ normal search over an ordered tree. The insert instead must be implemented
+ int two steps: as first thing the code must insert the element in
+ order as a red leaf in the tree, then the support library function
+ rb_insert_color() must be called. Such function will do the
+ not trivial work to rebalance the rbtree if necessary.
+
+-----------------------------------------------------------------------
+static inline struct page * rb_search_page_cache(struct inode * inode,
+ unsigned long offset)
+{
+ struct rb_node * n = inode->i_rb_page_cache.rb_node;
+ struct page * page;
+
+ while (n)
+ {
+ page = rb_entry(n, struct page, rb_page_cache);
+
+ if (offset < page->offset)
+ n = n->rb_left;
+ else if (offset > page->offset)
+ n = n->rb_right;
+ else
+ return page;
+ }
+ return NULL;
+}
+
+static inline struct page * __rb_insert_page_cache(struct inode * inode,
+ unsigned long offset,
+ struct rb_node * node)
+{
+ struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
+ struct rb_node * parent = NULL;
+ struct page * page;
+
+ while (*p)
+ {
+ parent = *p;
+ page = rb_entry(parent, struct page, rb_page_cache);
+
+ if (offset < page->offset)
+ p = &(*p)->rb_left;
+ else if (offset > page->offset)
+ p = &(*p)->rb_right;
+ else
+ return page;
+ }
+
+ rb_link_node(node, parent, p);
+
+ return NULL;
+}
+
+static inline struct page * rb_insert_page_cache(struct inode * inode,
+ unsigned long offset,
+ struct rb_node * node)
+{
+ struct page * ret;
+ if ((ret = __rb_insert_page_cache(inode, offset, node)))
+ goto out;
+ rb_insert_color(node, &inode->i_rb_page_cache);
+ out:
+ return ret;
+}
+-----------------------------------------------------------------------
+*/
+
+#ifndef _LINUX_RBTREE_H
+#define _LINUX_RBTREE_H
+
+#include <stdlib.h>
+
+struct rb_node
+{
+ unsigned long rb_parent_color;
+#define RB_RED 0
+#define RB_BLACK 1
+ struct rb_node *rb_right;
+ struct rb_node *rb_left;
+} __attribute__((aligned(sizeof(long))));
+ /* The alignment might seem pointless, but allegedly CRIS needs it */
+
+struct rb_root
+{
+ struct rb_node *rb_node;
+};
+
+
+#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
+#define rb_color(r) ((r)->rb_parent_color & 1)
+#define rb_is_red(r) (!rb_color(r))
+#define rb_is_black(r) rb_color(r)
+#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
+#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
+
+static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
+{
+ rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
+}
+static inline void rb_set_color(struct rb_node *rb, int color)
+{
+ rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
+}
+
+#define RB_ROOT { NULL, }
+#define rb_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
+#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
+#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
+
+extern void rb_insert_color(struct rb_node *, struct rb_root *);
+extern void rb_erase(struct rb_node *, struct rb_root *);
+
+/* Find logical next and previous nodes in a tree */
+extern struct rb_node *rb_next(struct rb_node *);
+extern struct rb_node *rb_prev(struct rb_node *);
+extern struct rb_node *rb_first(struct rb_root *);
+extern struct rb_node *rb_last(struct rb_root *);
+
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+ struct rb_root *root);
+
+static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
+ struct rb_node ** rb_link)
+{
+ node->rb_parent_color = (unsigned long )parent;
+ node->rb_left = node->rb_right = NULL;
+
+ *rb_link = node;
+}
+
+#endif /* _LINUX_RBTREE_H */
diff --git a/include/local.h b/include/local.h
new file mode 100644
index 0000000..f9121b1
--- /dev/null
+++ b/include/local.h
@@ -0,0 +1,37 @@
+#ifndef _LOCAL_SOCKET_H_
+#define _LOCAL_SOCKET_H_
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX 108
+#endif
+
+struct local_conf {
+ int backlog;
+ int reuseaddr;
+ char path[UNIX_PATH_MAX];
+};
+
+struct local_server {
+ int fd;
+ char path[UNIX_PATH_MAX];
+};
+
+/* callback return values */
+#define LOCAL_RET_ERROR -1
+#define LOCAL_RET_OK 0
+#define LOCAL_RET_STOLEN 1
+
+/* local server */
+int local_server_create(struct local_server *server, struct local_conf *conf);
+void local_server_destroy(struct local_server *server);
+int do_local_server_step(struct local_server *server, void *data,
+ int (*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..f5c5b4f
--- /dev/null
+++ b/include/log.h
@@ -0,0 +1,13 @@
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include <stdio.h>
+
+struct nf_conntrack;
+
+int init_log(void);
+void dlog(int priority, const char *format, ...);
+void dlog_ct(FILE *fd, struct nf_conntrack *ct, unsigned int type);
+void close_log(void);
+
+#endif
diff --git a/include/mcast.h b/include/mcast.h
new file mode 100644
index 0000000..402a033
--- /dev/null
+++ b/include/mcast.h
@@ -0,0 +1,60 @@
+#ifndef _MCAST_H_
+#define _MCAST_H_
+
+#include <stdint.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+struct mcast_conf {
+ int ipproto;
+ int reuseaddr;
+ int checksum;
+ unsigned short port;
+ union {
+ struct in_addr inet_addr;
+ struct in6_addr inet_addr6;
+ } in;
+ union {
+ struct in_addr interface_addr;
+ unsigned int interface_index6;
+ } ifa;
+ int sndbuf;
+ int rcvbuf;
+};
+
+struct mcast_stats {
+ uint64_t bytes;
+ uint64_t messages;
+ uint64_t error;
+};
+
+struct mcast_sock {
+ int fd;
+ union {
+ struct sockaddr_in ipv4;
+ struct sockaddr_in6 ipv6;
+ } addr;
+ socklen_t sockaddr_len;
+ 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);
+
+ssize_t mcast_send(struct mcast_sock *m, const void *data, int size);
+ssize_t mcast_recv(struct mcast_sock *m, void *data, int size);
+
+int mcast_get_fd(struct mcast_sock *m);
+int mcast_isset(struct mcast_sock *m, fd_set *readfds);
+
+int mcast_snprintf_stats(char *buf, size_t buflen, char *ifname,
+ struct mcast_stats *s, struct mcast_stats *r);
+
+int mcast_snprintf_stats2(char *buf, size_t buflen, const char *ifname,
+ const char *status, int active,
+ struct mcast_stats *s, struct mcast_stats *r);
+
+#endif
diff --git a/include/netlink.h b/include/netlink.h
new file mode 100644
index 0000000..0df0cbb
--- /dev/null
+++ b/include/netlink.h
@@ -0,0 +1,33 @@
+#ifndef _NETLINK_H_
+#define _NETLINK_H_
+
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+struct nf_conntrack;
+struct nfct_handle;
+
+struct nfct_handle *nl_init_event_handler(void);
+struct nlif_handle *nl_init_interface_handler(void);
+
+int nl_send_resync(struct nfct_handle *h);
+void nl_resize_socket_buffer(struct nfct_handle *h);
+int nl_dump_conntrack_table(struct nfct_handle *h);
+int nl_flush_conntrack_table(struct nfct_handle *h);
+int nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct);
+int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct, int timeout);
+int nl_update_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct, int timeout);
+int nl_destroy_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct);
+
+static inline int ct_is_related(const struct nf_conntrack *ct)
+{
+ return (nfct_attr_is_set(ct, ATTR_MASTER_L3PROTO) &&
+ nfct_attr_is_set(ct, ATTR_MASTER_L4PROTO) &&
+ ((nfct_attr_is_set(ct, ATTR_MASTER_IPV4_SRC) &&
+ nfct_attr_is_set(ct, ATTR_MASTER_IPV4_DST)) ||
+ (nfct_attr_is_set(ct, ATTR_MASTER_IPV6_SRC) &&
+ nfct_attr_is_set(ct, ATTR_MASTER_IPV6_DST))) &&
+ nfct_attr_is_set(ct, ATTR_MASTER_PORT_SRC) &&
+ nfct_attr_is_set(ct, ATTR_MASTER_PORT_DST));
+}
+
+#endif
diff --git a/include/network.h b/include/network.h
new file mode 100644
index 0000000..70812b1
--- /dev/null
+++ b/include/network.h
@@ -0,0 +1,239 @@
+#ifndef _NETWORK_H_
+#define _NETWORK_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#define CONNTRACKD_PROTOCOL_VERSION 0
+
+struct nf_conntrack;
+
+struct nethdr {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ uint8_t type:4,
+ version:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ uint8_t version:4,
+ type:4;
+#else
+#error "Unknown system endianess!"
+#endif
+ uint8_t flags;
+ uint16_t len;
+ uint32_t seq;
+};
+#define NETHDR_SIZ nethdr_align(sizeof(struct nethdr))
+
+enum nethdr_type {
+ NET_T_STATE_NEW = 0,
+ NET_T_STATE_UPD,
+ NET_T_STATE_DEL,
+ NET_T_STATE_MAX = NET_T_STATE_DEL,
+ NET_T_CTL = 10,
+};
+
+int nethdr_align(int len);
+int nethdr_size(int len);
+void nethdr_set(struct nethdr *net, int type);
+void nethdr_set_ack(struct nethdr *net);
+void nethdr_set_ctl(struct nethdr *net);
+int object_status_to_network_type(int status);
+
+#define NETHDR_DATA(x) \
+ (struct netattr *)(((char *)x) + NETHDR_SIZ)
+#define NETHDR_TAIL(x) \
+ (struct netattr *)(((char *)x) + x->len)
+
+struct nethdr_ack {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ uint8_t type:4,
+ version:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ uint8_t version:4,
+ type:4;
+#else
+#error "Unknown system endianess!"
+#endif
+ uint8_t flags;
+ uint16_t len;
+ uint32_t seq;
+ uint32_t from;
+ uint32_t to;
+};
+#define NETHDR_ACK_SIZ nethdr_align(sizeof(struct nethdr_ack))
+
+enum {
+ NET_F_UNUSED = (1 << 0),
+ NET_F_RESYNC = (1 << 1),
+ NET_F_NACK = (1 << 2),
+ NET_F_ACK = (1 << 3),
+ NET_F_ALIVE = (1 << 4),
+ NET_F_HELLO = (1 << 5),
+ NET_F_HELLO_BACK= (1 << 6),
+};
+
+enum {
+ MSG_DATA,
+ MSG_CTL,
+ MSG_DROP,
+ MSG_BAD,
+};
+
+#define BUILD_NETMSG(ct, query) \
+({ \
+ static char __net[4096]; \
+ struct nethdr *__hdr = (struct nethdr *) __net; \
+ memset(__hdr, 0, NETHDR_SIZ); \
+ nethdr_set(__hdr, query); \
+ build_payload(ct, __hdr); \
+ HDR_HOST2NETWORK(__hdr); \
+ __hdr; \
+})
+
+struct mcast_sock_multi;
+
+enum {
+ SEQ_UNKNOWN,
+ SEQ_UNSET,
+ SEQ_IN_SYNC,
+ SEQ_AFTER,
+ SEQ_BEFORE,
+};
+
+int nethdr_track_seq(uint32_t seq, uint32_t *exp_seq);
+void nethdr_track_update_seq(uint32_t seq);
+int nethdr_track_is_seq_set(void);
+
+struct mcast_conf;
+
+#define IS_DATA(x) (x->type <= NET_T_STATE_MAX && \
+ (x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0)
+#define IS_ACK(x) (x->type == NET_T_CTL && x->flags & NET_F_ACK)
+#define IS_NACK(x) (x->type == NET_T_CTL && x->flags & NET_F_NACK)
+#define IS_RESYNC(x) (x->type == NET_T_CTL && x->flags & NET_F_RESYNC)
+#define IS_ALIVE(x) (x->type == NET_T_CTL && x->flags & NET_F_ALIVE)
+#define IS_HELLO(x) (x->flags & NET_F_HELLO)
+#define IS_HELLO_BACK(x)(x->flags & NET_F_HELLO_BACK)
+
+#define HDR_NETWORK2HOST(x) \
+({ \
+ x->len = ntohs(x->len); \
+ x->seq = ntohl(x->seq); \
+ if (IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x)) { \
+ struct nethdr_ack *__ack = (struct nethdr_ack *) x; \
+ __ack->from = ntohl(__ack->from); \
+ __ack->to = ntohl(__ack->to); \
+ } \
+})
+
+#define HDR_HOST2NETWORK(x) \
+({ \
+ if (IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x)) { \
+ struct nethdr_ack *__ack = (struct nethdr_ack *) x; \
+ __ack->from = htonl(__ack->from); \
+ __ack->to = htonl(__ack->to); \
+ } \
+ x->len = htons(x->len); \
+ x->seq = htonl(x->seq); \
+})
+
+/* extracted from net/tcp.h */
+
+/*
+ * The next routines deal with comparing 32 bit unsigned ints
+ * and worry about wraparound (automatic with unsigned arithmetic).
+ */
+
+static inline int before(uint32_t seq1, uint32_t seq2)
+{
+ return (int32_t)(seq1-seq2) < 0;
+}
+#define after(seq2, seq1) before(seq1, seq2)
+
+/* is s2<=s1<=s3 ? */
+static inline int between(uint32_t seq1, uint32_t seq2, uint32_t seq3)
+{
+ return seq3 - seq2 >= seq1 - seq2;
+}
+
+#define PLD_NETWORK2HOST(x) \
+({ \
+ x->len = ntohs(x->len); \
+ x->query = ntohs(x->query); \
+})
+
+#define PLD_HOST2NETWORK(x) \
+({ \
+ x->len = htons(x->len); \
+ x->query = htons(x->query); \
+})
+
+struct netattr {
+ uint16_t nta_len;
+ uint16_t nta_attr;
+};
+
+#define ATTR_NETWORK2HOST(x) \
+({ \
+ x->nta_len = ntohs(x->nta_len); \
+ x->nta_attr = ntohs(x->nta_attr); \
+})
+
+#define NTA_SIZE(len) NTA_ALIGN(sizeof(struct netattr)) + len
+
+#define NTA_DATA(x) \
+ (void *)(((char *)x) + NTA_ALIGN(sizeof(struct netattr)))
+
+#define NTA_NEXT(x, len) \
+( \
+ len -= NTA_ALIGN(x->nta_len), \
+ (struct netattr *)(((char *)x) + NTA_ALIGN(x->nta_len)) \
+)
+
+#define NTA_ALIGNTO 4
+#define NTA_ALIGN(len) (((len) + NTA_ALIGNTO - 1) & ~(NTA_ALIGNTO - 1))
+#define NTA_LENGTH(len) (NTA_ALIGN(sizeof(struct netattr)) + (len))
+
+enum nta_attr {
+ NTA_IPV4 = 0, /* struct nfct_attr_grp_ipv4 */
+ NTA_IPV6, /* struct nfct_attr_grp_ipv6 */
+ NTA_L4PROTO, /* uint8_t */
+ NTA_PORT, /* struct nfct_attr_grp_port */
+ NTA_TCP_STATE = 4, /* uint8_t */
+ NTA_STATUS, /* uint32_t */
+ NTA_TIMEOUT, /* uint32_t */
+ NTA_MARK, /* uint32_t */
+ NTA_MASTER_IPV4 = 8, /* struct nfct_attr_grp_ipv4 */
+ NTA_MASTER_IPV6, /* struct nfct_attr_grp_ipv6 */
+ NTA_MASTER_L4PROTO, /* uint8_t */
+ NTA_MASTER_PORT, /* struct nfct_attr_grp_port */
+ NTA_SNAT_IPV4 = 12, /* uint32_t */
+ NTA_DNAT_IPV4, /* uint32_t */
+ NTA_SPAT_PORT, /* uint16_t */
+ NTA_DPAT_PORT, /* uint16_t */
+ NTA_NAT_SEQ_ADJ = 16, /* struct nta_attr_natseqadj */
+ NTA_SCTP_STATE, /* uint8_t */
+ NTA_SCTP_VTAG_ORIG, /* uint32_t */
+ NTA_SCTP_VTAG_REPL, /* uint32_t */
+ NTA_DCCP_STATE = 20, /* uint8_t */
+ NTA_DCCP_ROLE, /* uint8_t */
+ NTA_ICMP_TYPE, /* uint8_t */
+ NTA_ICMP_CODE, /* uint8_t */
+ NTA_ICMP_ID, /* uint16_t */
+ NTA_MAX
+};
+
+struct nta_attr_natseqadj {
+ uint32_t orig_seq_correction_pos;
+ uint32_t orig_seq_offset_before;
+ uint32_t orig_seq_offset_after;
+ uint32_t repl_seq_correction_pos;
+ uint32_t repl_seq_offset_before;
+ uint32_t repl_seq_offset_after;
+};
+
+void build_payload(const struct nf_conntrack *ct, struct nethdr *n);
+
+int parse_payload(struct nf_conntrack *ct, struct nethdr *n, size_t remain);
+
+#endif
diff --git a/include/origin.h b/include/origin.h
new file mode 100644
index 0000000..1b974e9
--- /dev/null
+++ b/include/origin.h
@@ -0,0 +1,16 @@
+#ifndef _ORIGIN_H_
+#define _ORIGIN_H_
+
+enum {
+ CTD_ORIGIN_NOT_ME = 0, /* this event comes from the kernel or
+ any process, but not conntrackd */
+ CTD_ORIGIN_COMMIT, /* event comes from committer */
+ CTD_ORIGIN_FLUSH, /* event comes from flush */
+ CTD_ORIGIN_INJECT, /* event comes from direct inject */
+};
+
+int origin_register(struct nfct_handle *h, int origin_type);
+int origin_find(const struct nlmsghdr *nlh);
+int origin_unregister(struct nfct_handle *h);
+
+#endif
diff --git a/include/process.h b/include/process.h
new file mode 100644
index 0000000..41c7c10
--- /dev/null
+++ b/include/process.h
@@ -0,0 +1,25 @@
+#ifndef _PROCESS_H_
+#define _PROCESS_H_
+
+enum process_type {
+ CTD_PROC_ANY, /* any type */
+ CTD_PROC_FLUSH, /* flush process */
+ CTD_PROC_COMMIT, /* commit process */
+ CTD_PROC_MAX
+};
+
+#define CTD_PROC_F_EXCL (1 << 0) /* only one process at a time */
+
+struct child_process {
+ struct list_head head;
+ int pid;
+ int type;
+ void (*cb)(void *data);
+ void *data;
+};
+
+int fork_process_new(int type, int flags, void (*cb)(void *data), void *data);
+int fork_process_delete(int pid);
+void fork_process_dump(int fd);
+
+#endif
diff --git a/include/queue.h b/include/queue.h
new file mode 100644
index 0000000..188e106
--- /dev/null
+++ b/include/queue.h
@@ -0,0 +1,62 @@
+#ifndef _QUEUE_H_
+#define _QUEUE_H_
+
+#include <stdint.h>
+#include "linux_list.h"
+
+struct queue_node {
+ struct list_head head;
+ uint32_t type;
+ struct queue *owner;
+ size_t size;
+};
+
+enum {
+ Q_ELEM_OBJ = 0,
+ Q_ELEM_CTL = 1,
+ Q_ELEM_ERR = 2,
+};
+
+void queue_node_init(struct queue_node *n, int type);
+void *queue_node_data(struct queue_node *n);
+
+struct queue_object {
+ struct queue_node qnode;
+ char data[0];
+};
+
+struct queue_object *queue_object_new(int type, size_t size);
+void queue_object_free(struct queue_object *obj);
+
+struct evfd;
+
+#define QUEUE_NAMELEN 16
+
+struct queue {
+ struct list_head list;
+ unsigned int max_elems;
+ unsigned int num_elems;
+ uint32_t enospc_err;
+ uint32_t flags;
+ struct list_head head;
+ struct evfd *evfd;
+ char name[QUEUE_NAMELEN];
+};
+
+#define QUEUE_F_EVFD (1U << 0)
+
+struct queue *queue_create(const char *name,
+ int max_objects, unsigned int flags);
+void queue_destroy(struct queue *b);
+void queue_stats_show(int fd);
+unsigned int queue_len(const struct queue *b);
+int queue_add(struct queue *b, struct queue_node *n);
+int queue_del(struct queue_node *n);
+struct queue_node *queue_del_head(struct queue *b);
+int queue_in(struct queue *b, struct queue_node *n);
+void queue_iterate(struct queue *b,
+ const void *data,
+ int (*iterate)(struct queue_node *n, const void *data2));
+int queue_get_eventfd(struct queue *b);
+
+#endif
diff --git a/include/sync.h b/include/sync.h
new file mode 100644
index 0000000..51f8f5b
--- /dev/null
+++ b/include/sync.h
@@ -0,0 +1,28 @@
+#ifndef _SYNC_HOOKS_H_
+#define _SYNC_HOOKS_H_
+
+#include <sys/select.h>
+
+struct nethdr;
+struct cache_object;
+struct fds;
+
+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 (*recv)(const struct nethdr *net);
+ void (*enqueue)(struct cache_object *obj, int type);
+ void (*xmit)(void);
+};
+
+extern struct sync_mode sync_alarm;
+extern struct sync_mode sync_ftfw;
+extern struct sync_mode sync_notrack;
+
+#endif
diff --git a/include/tcp.h b/include/tcp.h
new file mode 100644
index 0000000..2f0fd0a
--- /dev/null
+++ b/include/tcp.h
@@ -0,0 +1,76 @@
+#ifndef _TCP_H_
+#define _TCP_H_
+
+#include <stdint.h>
+#include <netinet/in.h>
+
+struct tcp_conf {
+ int ipproto;
+ int reuseaddr;
+ int checksum;
+ unsigned short port;
+ union {
+ struct {
+ struct in_addr inet_addr;
+ } ipv4;
+ struct {
+ struct in6_addr inet_addr6;
+ int scope_id;
+ } ipv6;
+ } server;
+ union {
+ struct in_addr inet_addr;
+ struct in6_addr inet_addr6;
+ } client;
+ int sndbuf;
+ int rcvbuf;
+};
+
+struct tcp_stats {
+ uint64_t bytes;
+ uint64_t messages;
+ uint64_t error;
+};
+
+enum tcp_sock_state {
+ TCP_SERVER_ACCEPTING,
+ TCP_SERVER_CONNECTED,
+ TCP_CLIENT_DISCONNECTED,
+ TCP_CLIENT_CONNECTED
+};
+
+struct tcp_sock {
+ int state; /* enum tcp_sock_state */
+ int fd;
+ int client_fd; /* only for the server side */
+ union {
+ struct sockaddr_in ipv4;
+ struct sockaddr_in6 ipv6;
+ } addr;
+ socklen_t sockaddr_len;
+ struct tcp_stats stats;
+ struct tcp_conf *conf;
+};
+
+struct tcp_sock *tcp_server_create(struct tcp_conf *conf);
+void tcp_server_destroy(struct tcp_sock *m);
+
+struct tcp_sock *tcp_client_create(struct tcp_conf *conf);
+void tcp_client_destroy(struct tcp_sock *m);
+
+ssize_t tcp_send(struct tcp_sock *m, const void *data, int size);
+ssize_t tcp_recv(struct tcp_sock *m, void *data, int size);
+int tcp_accept(struct tcp_sock *m);
+
+int tcp_get_fd(struct tcp_sock *m);
+int tcp_isset(struct tcp_sock *m, fd_set *readfds);
+int tcp_accept_isset(struct tcp_sock *m, fd_set *readfds);
+
+int tcp_snprintf_stats(char *buf, size_t buflen, char *ifname,
+ struct tcp_sock *s, struct tcp_sock *r);
+
+int tcp_snprintf_stats2(char *buf, size_t buflen, const char *ifname,
+ const char *status, int active,
+ struct tcp_stats *s, struct tcp_stats *r);
+
+#endif
diff --git a/include/traffic_stats.h b/include/traffic_stats.h
new file mode 100644
index 0000000..71fd268
--- /dev/null
+++ b/include/traffic_stats.h
@@ -0,0 +1,10 @@
+#ifndef _TRAFFIC_STATS_H_
+#define _TRAFFIC_STATS_H_
+
+struct nf_conntrack;
+
+void update_traffic_stats(struct nf_conntrack *ct);
+
+void dump_traffic_stats(int fd);
+
+#endif
diff --git a/include/udp.h b/include/udp.h
new file mode 100644
index 0000000..9f9c17a
--- /dev/null
+++ b/include/udp.h
@@ -0,0 +1,64 @@
+#ifndef _UDP_H_
+#define _UDP_H_
+
+#include <stdint.h>
+#include <netinet/in.h>
+
+struct udp_conf {
+ int ipproto;
+ int reuseaddr;
+ int checksum;
+ unsigned short port;
+ union {
+ struct {
+ struct in_addr inet_addr;
+ } ipv4;
+ struct {
+ struct in6_addr inet_addr6;
+ int scope_id;
+ } ipv6;
+ } server;
+ union {
+ struct in_addr inet_addr;
+ struct in6_addr inet_addr6;
+ } client;
+ int sndbuf;
+ int rcvbuf;
+};
+
+struct udp_stats {
+ uint64_t bytes;
+ uint64_t messages;
+ uint64_t error;
+};
+
+struct udp_sock {
+ int fd;
+ union {
+ struct sockaddr_in ipv4;
+ struct sockaddr_in6 ipv6;
+ } addr;
+ socklen_t sockaddr_len;
+ struct udp_stats stats;
+};
+
+struct udp_sock *udp_server_create(struct udp_conf *conf);
+void udp_server_destroy(struct udp_sock *m);
+
+struct udp_sock *udp_client_create(struct udp_conf *conf);
+void udp_client_destroy(struct udp_sock *m);
+
+ssize_t udp_send(struct udp_sock *m, const void *data, int size);
+ssize_t udp_recv(struct udp_sock *m, void *data, int size);
+
+int udp_get_fd(struct udp_sock *m);
+int udp_isset(struct udp_sock *m, fd_set *readfds);
+
+int udp_snprintf_stats(char *buf, size_t buflen, char *ifname,
+ struct udp_stats *s, struct udp_stats *r);
+
+int udp_snprintf_stats2(char *buf, size_t buflen, const char *ifname,
+ const char *status, int active,
+ struct udp_stats *s, struct udp_stats *r);
+
+#endif
diff --git a/include/vector.h b/include/vector.h
new file mode 100644
index 0000000..5b05cba
--- /dev/null
+++ b/include/vector.h
@@ -0,0 +1,13 @@
+#ifndef _VECTOR_H_
+#define _VECTOR_H_
+
+#include <stdlib.h>
+
+struct vector;
+
+struct vector *vector_create(size_t size);
+void vector_destroy(struct vector *v);
+int vector_add(struct vector *v, void *data);
+int vector_iterate(struct vector *v, const void *data, int (*fcn)(const void *a, const void *b));
+
+#endif