[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit

Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/app/iptables/extensions/GNUmakefile.in b/ap/app/iptables/extensions/GNUmakefile.in
new file mode 100755
index 0000000..add4021
--- /dev/null
+++ b/ap/app/iptables/extensions/GNUmakefile.in
@@ -0,0 +1,246 @@
+# -*- Makefile -*-
+
+top_builddir := @top_builddir@
+builddir     := @builddir@
+top_srcdir  := @top_srcdir@
+srcdir      := @srcdir@
+ksourcedir  := @ksourcedir@
+prefix      := @prefix@
+exec_prefix := @exec_prefix@
+libdir      := @libdir@
+libexecdir  := @libexecdir@
+xtlibdir    := @xtlibdir@
+
+CC             := @CC@
+CCLD           := ${CC}
+CFLAGS         := @CFLAGS@
+LDFLAGS        := @LDFLAGS@
+regular_CFLAGS := @regular_CFLAGS@
+kinclude_CFLAGS := @kinclude_CFLAGS@
+
+AM_CFLAGS      := ${regular_CFLAGS} -I${top_builddir}/include -I${top_srcdir}/include ${kinclude_CFLAGS}
+AM_DEPFLAGS     = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@
+
+ifeq (${V},)
+AM_LIBTOOL_SILENT = --silent
+AM_VERBOSE_CC     = @echo "  CC      " $@;
+AM_VERBOSE_CCLD   = @echo "  CCLD    " $@;
+AM_VERBOSE_CXX    = @echo "  CXX     " $@;
+AM_VERBOSE_CXXLD  = @echo "  CXXLD   " $@;
+AM_VERBOSE_AR     = @echo "  AR      " $@;
+AM_VERBOSE_GEN    = @echo "  GEN     " $@;
+endif
+
+#
+#	Wildcard module list
+#
+pfx_build_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(wildcard ${srcdir}/libxt_*.c))
+@ENABLE_IPV4_TRUE@ pf4_build_mod := $(patsubst ${srcdir}/libipt_%.c,%,$(wildcard ${srcdir}/libipt_*.c))
+@ENABLE_IPV6_TRUE@ pf6_build_mod := $(patsubst ${srcdir}/libip6t_%.c,%,$(wildcard ${srcdir}/libip6t_*.c))
+pfx_build_mod := $(filter-out @blacklist_modules@,${pfx_build_mod})
+pf4_build_mod := $(filter-out @blacklist_modules@,${pf4_build_mod})
+pf6_build_mod := $(filter-out @blacklist_modules@,${pf6_build_mod})
+
+# Only build matches/targets for the current kernel config
+-include $(LINUX_DIR)/.config
+lower=$(shell echo $(1) | tr [:upper:] [:lower:])
+upper=$(shell echo $(1) | tr [:lower:] [:upper:])
+keeplower=$(filter-out $(call upper,$(1)),$(1))
+keepupper=$(filter-out $(call lower,$(1)),$(1))
+TEST_CONFIG_VAL=$(patsubst $(3)_%,%,$(filter $(3)_%,$(foreach i,$(1),$(CONFIG_$(2)_$(i))_$(i))))
+TEST_CONFIG_TYPE=$(call TEST_CONFIG_VAL,$(1),$(2),y) $(call TEST_CONFIG_VAL,$(1),$(2),m)
+TEST_CONFIG=$(call TEST_CONFIG_TYPE,$(1),$(2)_$(3)) $(call TEST_CONFIG_TYPE,$(1),NETFILTER_XT_$(3))
+
+PF_EXT_SLIB_BASE:=icmp
+PF_EXT_SLIB_OPT:=$(filter-out $(PF_EXT_SLIB_BASE),$(pf4_build_mod))
+PF_EXT_SLIB_MATCH:=$(sort $(call upper,$(call keeplower,$(PF_EXT_SLIB_OPT))))
+PF_EXT_SLIB_TARGET:=$(sort $(call keepupper,$(PF_EXT_SLIB_OPT)))
+pf4_build_mod:=$(PF_EXT_SLIB_BASE)
+pf4_build_mod+=$(call lower,$(call TEST_CONFIG,$(PF_EXT_SLIB_MATCH),IP_NF,MATCH))
+pf4_build_mod+=$(call TEST_CONFIG,$(PF_EXT_SLIB_TARGET),IP_NF,TARGET)
+
+PF6_EXT_SLIB_BASE:=icmp6
+PF6_EXT_SLIB_OPT:=$(filter-out $(PF6_EXT_SLIB_BASE),$(pf6_build_mod))
+PF6_EXT_SLIB_MATCH:=$(sort $(call upper,$(call keeplower,$(PF6_EXT_SLIB_OPT))))
+PF6_EXT_SLIB_TARGET:=$(sort $(call keepupper,$(PF6_EXT_SLIB_OPT)))
+pf6_build_mod:=$(PF6_EXT_SLIB_BASE)
+pf6_build_mod+=$(call lower,$(call TEST_CONFIG,$(PF6_EXT_SLIB_MATCH),IP6_NF,MATCH))
+pf6_build_mod+=$(call TEST_CONFIG,$(PF6_EXT_SLIB_TARGET),IP6_NF,TARGET)
+
+PFX_EXT_SLIB_BASE:=tcp udp standard
+PFX_EXT_SLIB_OPT:=$(filter-out $(PFX_EXT_SLIB_BASE),$(pfx_build_mod))
+PFX_EXT_SLIB_MATCH:=$(sort $(call upper,$(call keeplower,$(PFX_EXT_SLIB_OPT))))
+PFX_EXT_SLIB_TARGET:=$(sort $(call keepupper,$(PFX_EXT_SLIB_OPT)))
+pfx_build_mod:=$(PFX_EXT_SLIB_BASE)
+pfx_build_mod+=$(call lower,$(call TEST_CONFIG,$(PFX_EXT_SLIB_MATCH),IP_NF,MATCH))
+pfx_build_mod+=$(call TEST_CONFIG,$(PFX_EXT_SLIB_TARGET),IP_NF,TARGET)
+ifeq ($(DO_IPV6), 1)
+pfx_build_mod+=$(call lower,$(call TEST_CONFIG,$(PFX_EXT_SLIB_MATCH),IP6_NF,MATCH))
+pfx_build_mod+=$(call TEST_CONFIG,$(PFX_EXT_SLIB_TARGET),IP6_NF,TARGET)
+endif
+pfx_build_mod:=$(sort $(pfx_build_mod))
+
+ifneq ($(CONFIG_NETFILTER_XT_TARGET_DSCP),)
+pfx_build_mod+=TOS
+endif
+ifneq ($(CONFIG_IP_NF_NAT)$(CONFIG_NF_NAT),)
+pf4_build_mod+=SNAT DNAT
+endif
+ifneq ($(CONFIG_IP_NF_MATCH_AH_ESP),)
+pf4_build_mod+=ah
+pfx_build_mod+=esp
+endif
+pfx_build_mod+=webstr
+
+pfx_objs      := $(patsubst %,libxt_%.o,${pfx_build_mod})
+pf4_objs      := $(patsubst %,libipt_%.o,${pf4_build_mod})
+pf6_objs      := $(patsubst %,libip6t_%.o,${pf6_build_mod})
+pfx_solibs    := $(patsubst %,libxt_%.so,${pfx_build_mod})
+pf4_solibs    := $(patsubst %,libipt_%.so,${pf4_build_mod})
+pf6_solibs    := $(patsubst %,libip6t_%.so,${pf6_build_mod})
+
+
+#
+# Building blocks
+#
+targets := libext4.a libext6.a matches4.man matches6.man \
+           targets4.man targets6.man
+targets_install :=
+@ENABLE_STATIC_TRUE@ libext4_objs := ${pfx_objs} ${pf4_objs}
+@ENABLE_STATIC_TRUE@ libext6_objs := ${pfx_objs} ${pf6_objs}
+@ENABLE_SHARED_TRUE@ targets += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs}
+@ENABLE_SHARED_TRUE@ targets_install += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs}
+
+.SECONDARY:
+
+.PHONY: all install clean distclean FORCE
+
+all: ${targets}
+
+install: ${targets_install}
+	@mkdir -p "${DESTDIR}${xtlibdir}";
+	if test -n "${targets_install}"; then install -pm0755 $^ "${DESTDIR}${xtlibdir}/"; fi;
+
+clean:
+	rm -f *.o *.oo *.so *.a {matches,targets}[46].man initext4.c initext6.c;
+	rm -f libipt_LED_def.c
+
+distclean: clean
+	rm -f .*.d .*.dd;
+
+init%.o: init%.c
+	${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=$*_init ${CFLAGS} -o $@ -c $<;
+
+-include .*.d
+
+
+#
+#	Shared libraries
+#
+lib%.so: lib%.oo
+	${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $<;
+
+lib%.oo: ${srcdir}/lib%.c
+	${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
+
+
+#
+#	Static bits
+#
+#	If static building is disabled, libext*.a will still be generated,
+#	but will be empty. This is good since we can do with less case
+#	handling code in the Makefiles.
+#
+lib%.o: ${srcdir}/lib%.c
+	${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -DNO_SHARED_LIBS=1 -D_INIT=lib$*_init ${CFLAGS} -o $@ -c $<;
+
+libext4.a: initext4.o ${libext4_objs}
+	${AM_VERBOSE_AR} ${AR} crs $@ $^;
+
+libext6.a: initext6.o ${libext6_objs}
+	${AM_VERBOSE_AR} ${AR} crs $@ $^;
+
+initext_func  := $(sort $(addprefix xt_,${pfx_build_mod})) $(sort $(addprefix ipt_,${pf4_build_mod}))
+initext6_func := $(sort $(addprefix xt_,${pfx_build_mod})) $(sort $(addprefix ip6t_,${pf6_build_mod}))
+
+.initext4.dd: FORCE
+	@echo "${initext_func}" >$@.tmp; \
+	cmp -s $@ $@.tmp || mv $@.tmp $@; \
+	rm -f $@.tmp;
+
+.initext6.dd: FORCE
+	@echo "${initext6_func}" >$@.tmp; \
+	cmp -s $@ $@.tmp || mv $@.tmp $@; \
+	rm -f $@.tmp;
+
+initext4.c: .initext4.dd
+	${AM_VERBOSE_GEN}
+	@( \
+	echo "" >$@; \
+	for i in ${initext_func}; do \
+		echo "extern void lib$${i}_init(void);" >>$@; \
+	done; \
+	echo "void init_extensions(void);" >>$@; \
+	echo "void init_extensions(void)" >>$@; \
+	echo "{" >>$@; \
+	for i in ${initext_func}; do \
+		echo  " ""lib$${i}_init();" >>$@; \
+	done; \
+	echo "}" >>$@; \
+	);
+
+initext6.c: .initext6.dd
+	${AM_VERBOSE_GEN}
+	@( \
+	echo "" >$@; \
+	for i in ${initext6_func}; do \
+		echo "extern void lib$${i}_init(void);" >>$@; \
+	done; \
+	echo "void init_extensions(void);" >>$@; \
+	echo "void init_extensions(void)" >>$@; \
+	echo "{" >>$@; \
+	for i in ${initext6_func}; do \
+		echo " ""lib$${i}_init();" >>$@; \
+	done; \
+	echo "}" >>$@; \
+	);
+
+libipt_LED.o: libipt_LED_def.c
+
+LEDMAN = $(LINUX_DIR)/include/linux/ledman.h
+libipt_LED_def.c: libipt_LED_def.pl $(LEDMAN)
+	perl $< <$(LEDMAN) >$@
+
+#
+#	Manual pages
+#
+ex_matches = $(sort $(shell echo $(1) | grep -Eo '\b[a-z0-9]+\b'))
+ex_targets = $(sort $(shell echo $(1) | grep -Eo '\b[A-Z0-9]+\b'))
+man_run    = \
+	${AM_VERBOSE_GEN} \
+	for ext in $(1); do \
+		f="${srcdir}/libxt_$$ext.man"; \
+		if [ -f "$$f" ]; then \
+			echo ".SS $$ext"; \
+			cat "$$f"; \
+			continue; \
+		fi; \
+		f="${srcdir}/lib$(2)t_$$ext.man"; \
+		if [ -f "$$f" ]; then \
+			echo ".SS $$ext"; \
+			cat "$$f"; \
+			continue; \
+		fi; \
+	done >$@;
+
+matches4.man: .initext4.dd $(wildcard ${srcdir}/lib*.man)
+	$(call man_run,$(call ex_matches,${pfx_build_mod} ${pf4_build_mod}),ip)
+
+matches6.man: .initext6.dd $(wildcard ${srcdir}/lib*.man)
+	$(call man_run,$(call ex_matches,${pfx_build_mod} ${pf6_build_mod}),ip6)
+
+targets4.man: .initext4.dd $(wildcard ${srcdir}/lib*.man)
+	$(call man_run,$(call ex_targets,${pfx_build_mod} ${pf4_build_mod}),ip)
+
+targets6.man: .initext6.dd $(wildcard ${srcdir}/lib*.man)
+	$(call man_run,$(call ex_targets,${pfx_build_mod} ${pf6_build_mod}),ip6)
diff --git a/ap/app/iptables/extensions/dscp_helper.c b/ap/app/iptables/extensions/dscp_helper.c
new file mode 100755
index 0000000..8fa0f4a
--- /dev/null
+++ b/ap/app/iptables/extensions/dscp_helper.c
@@ -0,0 +1,81 @@
+/*
+ * DiffServ classname <-> DiffServ codepoint mapping functions.
+ *
+ * The latest list of the mappings can be found at:
+ * <http://www.iana.org/assignments/dscp-registry>
+ *
+ * This code is released under the GNU GPL v2, 1991
+ *
+ * Author: Iain Barnes
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <xtables.h>
+
+
+static const struct ds_class
+{
+	const char *name;
+	unsigned int dscp;
+} ds_classes[] =
+{
+	{ "CS0", 0x00 },
+	{ "CS1", 0x08 },
+	{ "CS2", 0x10 },
+	{ "CS3", 0x18 },
+	{ "CS4", 0x20 },
+	{ "CS5", 0x28 },
+	{ "CS6", 0x30 },
+	{ "CS7", 0x38 },
+	{ "BE", 0x00 },
+	{ "AF11", 0x0a },
+	{ "AF12", 0x0c },
+	{ "AF13", 0x0e },
+	{ "AF21", 0x12 },
+	{ "AF22", 0x14 },
+	{ "AF23", 0x16 },
+	{ "AF31", 0x1a },
+	{ "AF32", 0x1c },
+	{ "AF33", 0x1e },
+	{ "AF41", 0x22 },
+	{ "AF42", 0x24 },
+	{ "AF43", 0x26 },
+	{ "EF", 0x2e }
+};
+
+
+
+static unsigned int
+class_to_dscp(const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; i < sizeof(ds_classes) / sizeof(struct ds_class); i++) {
+		if (!strncasecmp(name, ds_classes[i].name,
+					strlen(ds_classes[i].name)))
+			return ds_classes[i].dscp;
+	}
+
+	xtables_error(PARAMETER_PROBLEM,
+			"Invalid DSCP value `%s'\n", name);
+}
+
+
+#if 0
+static const char *
+dscp_to_name(unsigned int dscp)
+{
+	int i;
+
+	for (i = 0; i < sizeof(ds_classes) / sizeof(struct ds_class); i++) {
+		if (dscp == ds_classes[i].dscp)
+			return ds_classes[i].name;
+	}
+
+
+	xtables_error(PARAMETER_PROBLEM,
+			"Invalid DSCP value `%d'\n", dscp);
+}
+#endif
+
diff --git a/ap/app/iptables/extensions/libip6t_HL.c b/ap/app/iptables/extensions/libip6t_HL.c
new file mode 100755
index 0000000..12d8e72
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_HL.c
@@ -0,0 +1,157 @@
+/*
+ * IPv6 Hop Limit Target module
+ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
+ * Based on HW's ttl target
+ * This program is distributed under the terms of GNU GPL
+ */
+
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <xtables.h>
+
+#include <linux/netfilter_ipv6/ip6t_HL.h>
+
+#define IP6T_HL_USED	1
+
+static void HL_help(void)
+{
+	printf(
+"HL target options\n"
+"  --hl-set value		Set HL to <value 0-255>\n"
+"  --hl-dec value		Decrement HL by <value 1-255>\n"
+"  --hl-inc value		Increment HL by <value 1-255>\n");
+}
+
+static int HL_parse(int c, char **argv, int invert, unsigned int *flags,
+                    const void *entry, struct xt_entry_target **target)
+{
+	struct ip6t_HL_info *info = (struct ip6t_HL_info *) (*target)->data;
+	unsigned int value;
+
+	if (*flags & IP6T_HL_USED) {
+		xtables_error(PARAMETER_PROBLEM,
+				"Can't specify HL option twice");
+	}
+
+	if (!optarg) 
+		xtables_error(PARAMETER_PROBLEM,
+				"HL: You must specify a value");
+
+	if (xtables_check_inverse(optarg, &invert, NULL, 0))
+		xtables_error(PARAMETER_PROBLEM,
+				"HL: unexpected `!'");
+	
+	if (!xtables_strtoui(optarg, NULL, &value, 0, UINT8_MAX))
+		xtables_error(PARAMETER_PROBLEM,
+		           "HL: Expected value between 0 and 255");
+
+	switch (c) {
+
+		case '1':
+			info->mode = IP6T_HL_SET;
+			break;
+
+		case '2':
+			if (value == 0) {
+				xtables_error(PARAMETER_PROBLEM,
+					"HL: decreasing by 0?");
+			}
+
+			info->mode = IP6T_HL_DEC;
+			break;
+
+		case '3':
+			if (value == 0) {
+				xtables_error(PARAMETER_PROBLEM,
+					"HL: increasing by 0?");
+			}
+
+			info->mode = IP6T_HL_INC;
+			break;
+
+		default:
+			return 0;
+
+	}
+	
+	info->hop_limit = value;
+	*flags |= IP6T_HL_USED;
+
+	return 1;
+}
+
+static void HL_check(unsigned int flags)
+{
+	if (!(flags & IP6T_HL_USED))
+		xtables_error(PARAMETER_PROBLEM,
+				"HL: You must specify an action");
+}
+
+static void HL_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct ip6t_HL_info *info = 
+		(struct ip6t_HL_info *) target->data;
+
+	switch (info->mode) {
+		case IP6T_HL_SET:
+			printf("--hl-set ");
+			break;
+		case IP6T_HL_DEC:
+			printf("--hl-dec ");
+			break;
+
+		case IP6T_HL_INC:
+			printf("--hl-inc ");
+			break;
+	}
+	printf("%u ", info->hop_limit);
+}
+
+static void HL_print(const void *ip, const struct xt_entry_target *target,
+                     int numeric)
+{
+	const struct ip6t_HL_info *info =
+		(struct ip6t_HL_info *) target->data;
+
+	printf("HL ");
+	switch (info->mode) {
+		case IP6T_HL_SET:
+			printf("set to ");
+			break;
+		case IP6T_HL_DEC:
+			printf("decrement by ");
+			break;
+		case IP6T_HL_INC:
+			printf("increment by ");
+			break;
+	}
+	printf("%u ", info->hop_limit);
+}
+
+static const struct option HL_opts[] = {
+	{ "hl-set", 1, NULL, '1' },
+	{ "hl-dec", 1, NULL, '2' },
+	{ "hl-inc", 1, NULL, '3' },
+	{ .name = NULL }
+};
+
+static struct xtables_target hl_tg6_reg = {
+	.name 		= "HL",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV6,
+	.size		= XT_ALIGN(sizeof(struct ip6t_HL_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_HL_info)),
+	.help		= HL_help,
+	.parse		= HL_parse,
+	.final_check	= HL_check,
+	.print		= HL_print,
+	.save		= HL_save,
+	.extra_opts	= HL_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&hl_tg6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_HL.man b/ap/app/iptables/extensions/libip6t_HL.man
new file mode 100755
index 0000000..0f3afb1
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_HL.man
@@ -0,0 +1,17 @@
+This is used to modify the Hop Limit field in IPv6 header. The Hop Limit field
+is similar to what is known as TTL value in IPv4.  Setting or incrementing the
+Hop Limit field can potentially be very dangerous, so it should be avoided at
+any cost. This target is only valid in
+.B mangle
+table.
+.PP
+.B Don't ever set or increment the value on packets that leave your local network!
+.TP
+\fB\-\-hl\-set\fP \fIvalue\fP
+Set the Hop Limit to `value'.
+.TP
+\fB\-\-hl\-dec\fP \fIvalue\fP
+Decrement the Hop Limit `value' times.
+.TP
+\fB\-\-hl\-inc\fP \fIvalue\fP
+Increment the Hop Limit `value' times.
diff --git a/ap/app/iptables/extensions/libip6t_IMQ.c b/ap/app/iptables/extensions/libip6t_IMQ.c
new file mode 100755
index 0000000..ec47aaf
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_IMQ.c
@@ -0,0 +1,102 @@
+/* Shared library add-on to iptables to add IMQ target support. */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <ip6tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_IMQ.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+	printf(
+"IMQ target v%s options:\n"
+"  --todev <N>		enqueue to imq<N>, defaults to 0\n", 
+IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+	{ "todev", 1, 0, '1' },
+	{ 0 }
+};
+
+/* Initialize the target. */
+static void
+init(struct ip6t_entry_target *t, unsigned int *nfcache)
+{
+	struct ip6t_imq_info *mr = (struct ip6t_imq_info*)t->data;
+
+	mr->todev = 0;
+	*nfcache |= NFC_UNKNOWN;
+}
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const struct ip6t_entry *entry,
+      struct ip6t_entry_target **target)
+{
+	struct ip6t_imq_info *mr = (struct ip6t_imq_info*)(*target)->data;
+	
+	switch(c) {
+	case '1':
+		if (check_inverse(optarg, &invert, NULL, 0))
+			exit_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --todev");
+		mr->todev=atoi(optarg);
+		break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static void
+final_check(unsigned int flags)
+{
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ip6t_ip6 *ip,
+      const struct ip6t_entry_target *target,
+      int numeric)
+{
+	struct ip6t_imq_info *mr = (struct ip6t_imq_info*)target->data;
+
+	printf("IMQ: todev %u ", mr->todev);
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ip6t_ip6 *ip, const struct ip6t_entry_target *target)
+{
+	struct ip6t_imq_info *mr = (struct ip6t_imq_info*)target->data;
+
+	printf("--todev %u", mr->todev);
+}
+
+static
+struct ip6tables_target imq
+= { NULL,
+    "IMQ",
+    IPTABLES_VERSION,
+    IP6T_ALIGN(sizeof(struct ip6t_imq_info)),
+    IP6T_ALIGN(sizeof(struct ip6t_imq_info)),
+    &help,
+    &init,
+    &parse,
+    &final_check,
+    &print,
+    &save,
+    opts
+};
+
+void _init(void)
+{
+	register_target6(&imq);
+}
diff --git a/ap/app/iptables/extensions/libip6t_LOG.c b/ap/app/iptables/extensions/libip6t_LOG.c
new file mode 100755
index 0000000..390cb97
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_LOG.c
@@ -0,0 +1,268 @@
+/* Shared library add-on to ip6tables to add LOG support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter_ipv6/ip6t_LOG.h>
+
+#ifndef IP6T_LOG_UID	/* Old kernel */
+#define IP6T_LOG_UID	0x08
+#undef  IP6T_LOG_MASK
+#define IP6T_LOG_MASK	0x0f
+#endif
+
+#define LOG_DEFAULT_LEVEL LOG_WARNING
+
+static void LOG_help(void)
+{
+	printf(
+"LOG target options:\n"
+" --log-level level		Level of logging (numeric or see syslog.conf)\n"
+" --log-prefix prefix		Prefix log messages with this prefix.\n"
+" --log-tcp-sequence		Log TCP sequence numbers.\n"
+" --log-tcp-options		Log TCP options.\n"
+" --log-ip-options		Log IP options.\n"
+" --log-uid			Log UID owning the local socket.\n");
+}
+
+static const struct option LOG_opts[] = {
+	{ .name = "log-level",        .has_arg = 1, .val = '!' },
+	{ .name = "log-prefix",       .has_arg = 1, .val = '#' },
+	{ .name = "log-tcp-sequence", .has_arg = 0, .val = '1' },
+	{ .name = "log-tcp-options",  .has_arg = 0, .val = '2' },
+	{ .name = "log-ip-options",   .has_arg = 0, .val = '3' },
+	{ .name = "log-uid",          .has_arg = 0, .val = '4' },
+	{ .name = NULL }
+};
+
+static void LOG_init(struct xt_entry_target *t)
+{
+	struct ip6t_log_info *loginfo = (struct ip6t_log_info *)t->data;
+
+	loginfo->level = LOG_DEFAULT_LEVEL;
+
+}
+
+struct ip6t_log_names {
+	const char *name;
+	unsigned int level;
+};
+
+static const struct ip6t_log_names ip6t_log_names[]
+= { { .name = "alert",   .level = LOG_ALERT },
+    { .name = "crit",    .level = LOG_CRIT },
+    { .name = "debug",   .level = LOG_DEBUG },
+    { .name = "emerg",   .level = LOG_EMERG },
+    { .name = "error",   .level = LOG_ERR },		/* DEPRECATED */
+    { .name = "info",    .level = LOG_INFO },
+    { .name = "notice",  .level = LOG_NOTICE },
+    { .name = "panic",   .level = LOG_EMERG },		/* DEPRECATED */
+    { .name = "warning", .level = LOG_WARNING }
+};
+
+static u_int8_t
+parse_level(const char *level)
+{
+	unsigned int lev = -1;
+	unsigned int set = 0;
+
+	if (!xtables_strtoui(level, NULL, &lev, 0, 7)) {
+		unsigned int i = 0;
+
+		for (i = 0;
+		     i < sizeof(ip6t_log_names) / sizeof(struct ip6t_log_names);
+		     i++) {
+			if (strncasecmp(level, ip6t_log_names[i].name,
+					strlen(level)) == 0) {
+				if (set++)
+					xtables_error(PARAMETER_PROBLEM,
+						   "log-level `%s' ambiguous",
+						   level);
+				lev = ip6t_log_names[i].level;
+			}
+		}
+
+		if (!set)
+			xtables_error(PARAMETER_PROBLEM,
+				   "log-level `%s' unknown", level);
+	}
+
+	return lev;
+}
+
+#define IP6T_LOG_OPT_LEVEL 0x01
+#define IP6T_LOG_OPT_PREFIX 0x02
+#define IP6T_LOG_OPT_TCPSEQ 0x04
+#define IP6T_LOG_OPT_TCPOPT 0x08
+#define IP6T_LOG_OPT_IPOPT 0x10
+#define IP6T_LOG_OPT_UID 0x20
+
+static int LOG_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_target **target)
+{
+	struct ip6t_log_info *loginfo = (struct ip6t_log_info *)(*target)->data;
+
+	switch (c) {
+	case '!':
+		if (*flags & IP6T_LOG_OPT_LEVEL)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --log-level twice");
+
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --log-level");
+
+		loginfo->level = parse_level(optarg);
+		*flags |= IP6T_LOG_OPT_LEVEL;
+		break;
+
+	case '#':
+		if (*flags & IP6T_LOG_OPT_PREFIX)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --log-prefix twice");
+
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --log-prefix");
+
+		if (strlen(optarg) > sizeof(loginfo->prefix) - 1)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Maximum prefix length %u for --log-prefix",
+				   (unsigned int)sizeof(loginfo->prefix) - 1);
+
+		if (strlen(optarg) == 0)
+			xtables_error(PARAMETER_PROBLEM,
+				   "No prefix specified for --log-prefix");
+
+		if (strlen(optarg) != strlen(strtok(optarg, "\n")))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Newlines not allowed in --log-prefix");
+
+		strcpy(loginfo->prefix, optarg);
+		*flags |= IP6T_LOG_OPT_PREFIX;
+		break;
+
+	case '1':
+		if (*flags & IP6T_LOG_OPT_TCPSEQ)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --log-tcp-sequence "
+				   "twice");
+
+		loginfo->logflags |= IP6T_LOG_TCPSEQ;
+		*flags |= IP6T_LOG_OPT_TCPSEQ;
+		break;
+
+	case '2':
+		if (*flags & IP6T_LOG_OPT_TCPOPT)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --log-tcp-options twice");
+
+		loginfo->logflags |= IP6T_LOG_TCPOPT;
+		*flags |= IP6T_LOG_OPT_TCPOPT;
+		break;
+
+	case '3':
+		if (*flags & IP6T_LOG_OPT_IPOPT)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --log-ip-options twice");
+
+		loginfo->logflags |= IP6T_LOG_IPOPT;
+		*flags |= IP6T_LOG_OPT_IPOPT;
+		break;
+
+	case '4':
+		if (*flags & IP6T_LOG_OPT_UID)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --log-uid twice");
+
+		loginfo->logflags |= IP6T_LOG_UID;
+		*flags |= IP6T_LOG_OPT_UID;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void LOG_print(const void *ip, const struct xt_entry_target *target,
+                      int numeric)
+{
+	const struct ip6t_log_info *loginfo
+		= (const struct ip6t_log_info *)target->data;
+	unsigned int i = 0;
+
+	printf("LOG ");
+	if (numeric)
+		printf("flags %u level %u ",
+		       loginfo->logflags, loginfo->level);
+	else {
+		for (i = 0;
+		     i < sizeof(ip6t_log_names) / sizeof(struct ip6t_log_names);
+		     i++) {
+			if (loginfo->level == ip6t_log_names[i].level) {
+				printf("level %s ", ip6t_log_names[i].name);
+				break;
+			}
+		}
+		if (i == sizeof(ip6t_log_names) / sizeof(struct ip6t_log_names))
+			printf("UNKNOWN level %u ", loginfo->level);
+		if (loginfo->logflags & IP6T_LOG_TCPSEQ)
+			printf("tcp-sequence ");
+		if (loginfo->logflags & IP6T_LOG_TCPOPT)
+			printf("tcp-options ");
+		if (loginfo->logflags & IP6T_LOG_IPOPT)
+			printf("ip-options ");
+		if (loginfo->logflags & IP6T_LOG_UID)
+			printf("uid ");
+		if (loginfo->logflags & ~(IP6T_LOG_MASK))
+			printf("unknown-flags ");
+	}
+
+	if (strcmp(loginfo->prefix, "") != 0)
+		printf("prefix `%s' ", loginfo->prefix);
+}
+
+static void LOG_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct ip6t_log_info *loginfo
+		= (const struct ip6t_log_info *)target->data;
+
+	if (strcmp(loginfo->prefix, "") != 0)
+		printf("--log-prefix \"%s\" ", loginfo->prefix);
+
+	if (loginfo->level != LOG_DEFAULT_LEVEL)
+		printf("--log-level %d ", loginfo->level);
+
+	if (loginfo->logflags & IP6T_LOG_TCPSEQ)
+		printf("--log-tcp-sequence ");
+	if (loginfo->logflags & IP6T_LOG_TCPOPT)
+		printf("--log-tcp-options ");
+	if (loginfo->logflags & IP6T_LOG_IPOPT)
+		printf("--log-ip-options ");
+	if (loginfo->logflags & IP6T_LOG_UID)
+		printf("--log-uid ");
+}
+
+static struct xtables_target log_tg6_reg = {
+    .name          = "LOG",
+    .version       = XTABLES_VERSION,
+    .family        = NFPROTO_IPV6,
+    .size          = XT_ALIGN(sizeof(struct ip6t_log_info)),
+    .userspacesize = XT_ALIGN(sizeof(struct ip6t_log_info)),
+    .help          = LOG_help,
+    .init          = LOG_init,
+    .parse         = LOG_parse,
+    .print         = LOG_print,
+    .save          = LOG_save,
+    .extra_opts    = LOG_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&log_tg6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_LOG.man b/ap/app/iptables/extensions/libip6t_LOG.man
new file mode 100755
index 0000000..b7803fe
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_LOG.man
@@ -0,0 +1,31 @@
+Turn on kernel logging of matching packets.  When this option is set
+for a rule, the Linux kernel will print some information on all
+matching packets (like most IPv6 IPv6-header fields) via the kernel log
+(where it can be read with
+.I dmesg
+or 
+.IR syslogd (8)).
+This is a "non-terminating target", i.e. rule traversal continues at
+the next rule.  So if you want to LOG the packets you refuse, use two
+separate rules with the same matching criteria, first using target LOG
+then DROP (or REJECT).
+.TP
+\fB\-\-log\-level\fP \fIlevel\fP
+Level of logging (numeric or see \fIsyslog.conf\fP(5)).
+.TP
+\fB\-\-log\-prefix\fP \fIprefix\fP
+Prefix log messages with the specified prefix; up to 29 letters long,
+and useful for distinguishing messages in the logs.
+.TP
+\fB\-\-log\-tcp\-sequence\fP
+Log TCP sequence numbers. This is a security risk if the log is
+readable by users.
+.TP
+\fB\-\-log\-tcp\-options\fP
+Log options from the TCP packet header.
+.TP
+\fB\-\-log\-ip\-options\fP
+Log options from the IPv6 packet header.
+.TP
+\fB\-\-log\-uid\fP
+Log the userid of the process which generated the packet.
diff --git a/ap/app/iptables/extensions/libip6t_REJECT.c b/ap/app/iptables/extensions/libip6t_REJECT.c
new file mode 100755
index 0000000..527f595
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_REJECT.c
@@ -0,0 +1,149 @@
+/* Shared library add-on to ip6tables to add customized REJECT support.
+ *
+ * (C) 2000 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * 
+ * ported to IPv6 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter_ipv6/ip6t_REJECT.h>
+
+struct reject_names {
+	const char *name;
+	const char *alias;
+	enum ip6t_reject_with with;
+	const char *desc;
+};
+
+static const struct reject_names reject_table[] = {
+	{"icmp6-no-route", "no-route",
+		IP6T_ICMP6_NO_ROUTE, "ICMPv6 no route"},
+	{"icmp6-adm-prohibited", "adm-prohibited",
+		IP6T_ICMP6_ADM_PROHIBITED, "ICMPv6 administratively prohibited"},
+#if 0
+	{"icmp6-not-neighbor", "not-neighbor"},
+		IP6T_ICMP6_NOT_NEIGHBOR, "ICMPv6 not a neighbor"},
+#endif
+	{"icmp6-addr-unreachable", "addr-unreach",
+		IP6T_ICMP6_ADDR_UNREACH, "ICMPv6 address unreachable"},
+	{"icmp6-port-unreachable", "port-unreach",
+		IP6T_ICMP6_PORT_UNREACH, "ICMPv6 port unreachable"},
+	{"tcp-reset", "tcp-reset",
+		IP6T_TCP_RESET, "TCP RST packet"}
+};
+
+static void
+print_reject_types(void)
+{
+	unsigned int i;
+
+	printf("Valid reject types:\n");
+
+	for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) {
+		printf("    %-25s\t%s\n", reject_table[i].name, reject_table[i].desc);
+		printf("    %-25s\talias\n", reject_table[i].alias);
+	}
+	printf("\n");
+}
+
+static void REJECT_help(void)
+{
+	printf(
+"REJECT target options:\n"
+"--reject-with type              drop input packet and send back\n"
+"                                a reply packet according to type:\n");
+
+	print_reject_types();
+}
+
+static const struct option REJECT_opts[] = {
+	{ "reject-with", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static void REJECT_init(struct xt_entry_target *t)
+{
+	struct ip6t_reject_info *reject = (struct ip6t_reject_info *)t->data;
+
+	/* default */
+	reject->with = IP6T_ICMP6_PORT_UNREACH;
+
+}
+
+static int REJECT_parse(int c, char **argv, int invert, unsigned int *flags,
+                        const void *entry, struct xt_entry_target **target)
+{
+	struct ip6t_reject_info *reject = 
+		(struct ip6t_reject_info *)(*target)->data;
+	unsigned int limit = sizeof(reject_table)/sizeof(struct reject_names);
+	unsigned int i;
+
+	switch(c) {
+	case '1':
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --reject-with");
+		for (i = 0; i < limit; i++) {
+			if ((strncasecmp(reject_table[i].name, optarg, strlen(optarg)) == 0)
+			    || (strncasecmp(reject_table[i].alias, optarg, strlen(optarg)) == 0)) {
+				reject->with = reject_table[i].with;
+				return 1;
+			}
+		}
+		xtables_error(PARAMETER_PROBLEM, "unknown reject type \"%s\"", optarg);
+	default:
+		/* Fall through */
+		break;
+	}
+	return 0;
+}
+
+static void REJECT_print(const void *ip, const struct xt_entry_target *target,
+                         int numeric)
+{
+	const struct ip6t_reject_info *reject
+		= (const struct ip6t_reject_info *)target->data;
+	unsigned int i;
+
+	for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) {
+		if (reject_table[i].with == reject->with)
+			break;
+	}
+	printf("reject-with %s ", reject_table[i].name);
+}
+
+static void REJECT_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct ip6t_reject_info *reject
+		= (const struct ip6t_reject_info *)target->data;
+	unsigned int i;
+
+	for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++)
+		if (reject_table[i].with == reject->with)
+			break;
+
+	printf("--reject-with %s ", reject_table[i].name);
+}
+
+static struct xtables_target reject_tg6_reg = {
+	.name = "REJECT",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV6,
+	.size 		= XT_ALIGN(sizeof(struct ip6t_reject_info)),
+	.userspacesize 	= XT_ALIGN(sizeof(struct ip6t_reject_info)),
+	.help		= REJECT_help,
+	.init		= REJECT_init,
+	.parse		= REJECT_parse,
+	.print		= REJECT_print,
+	.save		= REJECT_save,
+	.extra_opts	= REJECT_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&reject_tg6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_REJECT.man b/ap/app/iptables/extensions/libip6t_REJECT.man
new file mode 100755
index 0000000..2d09e05
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_REJECT.man
@@ -0,0 +1,33 @@
+This is used to send back an error packet in response to the matched
+packet: otherwise it is equivalent to 
+.B DROP
+so it is a terminating TARGET, ending rule traversal.
+This target is only valid in the
+.BR INPUT ,
+.B FORWARD
+and
+.B OUTPUT
+chains, and user-defined chains which are only called from those
+chains.  The following option controls the nature of the error packet
+returned:
+.TP
+\fB\-\-reject\-with\fP \fItype\fP
+The type given can be
+\fBicmp6\-no\-route\fP,
+\fBno\-route\fP,
+\fBicmp6\-adm\-prohibited\fP,
+\fBadm\-prohibited\fP,
+\fBicmp6\-addr\-unreachable\fP,
+\fBaddr\-unreach\fP,
+\fBicmp6\-port\-unreachable\fP or
+\fBport\-unreach\fP
+which return the appropriate ICMPv6 error message (\fBport\-unreach\fP is
+the default). Finally, the option
+\fBtcp\-reset\fP
+can be used on rules which only match the TCP protocol: this causes a
+TCP RST packet to be sent back.  This is mainly useful for blocking 
+.I ident
+(113/tcp) probes which frequently occur when sending mail to broken mail
+hosts (which won't accept your mail otherwise).
+\fBtcp\-reset\fP
+can only be used with kernel versions 2.6.14 or later.
diff --git a/ap/app/iptables/extensions/libip6t_ah.c b/ap/app/iptables/extensions/libip6t_ah.c
new file mode 100755
index 0000000..19b7ad4
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_ah.c
@@ -0,0 +1,207 @@
+/* Shared library add-on to ip6tables to add AH support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <xtables.h>
+#include <linux/netfilter_ipv6/ip6t_ah.h>
+
+static void ah_help(void)
+{
+	printf(
+"ah match options:\n"
+"[!] --ahspi spi[:spi]          match spi (range)\n"
+"[!] --ahlen length             total length of this header\n"
+" --ahres                       check the reserved filed, too\n");
+}
+
+static const struct option ah_opts[] = {
+	{ .name = "ahspi", .has_arg = 1, .val = '1' },
+	{ .name = "ahlen", .has_arg = 1, .val = '2' },
+	{ .name = "ahres", .has_arg = 0, .val = '3' },
+	{ .name = NULL }
+};
+
+static u_int32_t
+parse_ah_spi(const char *spistr, const char *typestr)
+{
+	unsigned long int spi;
+	char* ep;
+
+	spi = strtoul(spistr, &ep, 0);
+
+	if ( spistr == ep )
+		xtables_error(PARAMETER_PROBLEM,
+			   "AH no valid digits in %s `%s'", typestr, spistr);
+
+	if ( spi == ULONG_MAX  && errno == ERANGE )
+		xtables_error(PARAMETER_PROBLEM,
+			   "%s `%s' specified too big: would overflow",
+			   typestr, spistr);
+
+	if ( *spistr != '\0'  && *ep != '\0' )
+		xtables_error(PARAMETER_PROBLEM,
+			   "AH error parsing %s `%s'", typestr, spistr);
+
+	return spi;
+}
+
+static void
+parse_ah_spis(const char *spistring, u_int32_t *spis)
+{
+	char *buffer;
+	char *cp;
+
+	buffer = strdup(spistring);
+	if ((cp = strchr(buffer, ':')) == NULL)
+		spis[0] = spis[1] = parse_ah_spi(buffer, "spi");
+	else {
+		*cp = '\0';
+		cp++;
+
+		spis[0] = buffer[0] ? parse_ah_spi(buffer, "spi") : 0;
+		spis[1] = cp[0] ? parse_ah_spi(cp, "spi") : 0xFFFFFFFF;
+	}
+	free(buffer);
+}
+
+static void ah_init(struct xt_entry_match *m)
+{
+	struct ip6t_ah *ahinfo = (struct ip6t_ah *)m->data;
+
+	ahinfo->spis[1] = 0xFFFFFFFF;
+	ahinfo->hdrlen = 0;
+	ahinfo->hdrres = 0;
+}
+
+static int ah_parse(int c, char **argv, int invert, unsigned int *flags,
+                    const void *entry, struct xt_entry_match **match)
+{
+	struct ip6t_ah *ahinfo = (struct ip6t_ah *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & IP6T_AH_SPI)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--ahspi' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_ah_spis(argv[optind-1], ahinfo->spis);
+		if (invert)
+			ahinfo->invflags |= IP6T_AH_INV_SPI;
+		*flags |= IP6T_AH_SPI;
+		break;
+	case '2':
+		if (*flags & IP6T_AH_LEN)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--ahlen' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		ahinfo->hdrlen = parse_ah_spi(argv[optind-1], "length");
+		if (invert)
+			ahinfo->invflags |= IP6T_AH_INV_LEN;
+		*flags |= IP6T_AH_LEN;
+		break;
+	case '3':
+		if (*flags & IP6T_AH_RES)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--ahres' allowed");
+		ahinfo->hdrres = 1;
+		*flags |= IP6T_AH_RES;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+print_spis(const char *name, u_int32_t min, u_int32_t max,
+	    int invert)
+{
+	const char *inv = invert ? "!" : "";
+
+	if (min != 0 || max != 0xFFFFFFFF || invert) {
+		if (min == max)
+			printf("%s:%s%u ", name, inv, min);
+		else
+			printf("%ss:%s%u:%u ", name, inv, min, max);
+	}
+}
+
+static void
+print_len(const char *name, u_int32_t len, int invert)
+{
+	const char *inv = invert ? "!" : "";
+
+	if (len != 0 || invert)
+		printf("%s:%s%u ", name, inv, len);
+}
+
+static void ah_print(const void *ip, const struct xt_entry_match *match,
+                     int numeric)
+{
+	const struct ip6t_ah *ah = (struct ip6t_ah *)match->data;
+
+	printf("ah ");
+	print_spis("spi", ah->spis[0], ah->spis[1],
+		    ah->invflags & IP6T_AH_INV_SPI);
+	print_len("length", ah->hdrlen, 
+		    ah->invflags & IP6T_AH_INV_LEN);
+
+	if (ah->hdrres)
+		printf("reserved ");
+
+	if (ah->invflags & ~IP6T_AH_INV_MASK)
+		printf("Unknown invflags: 0x%X ",
+		       ah->invflags & ~IP6T_AH_INV_MASK);
+}
+
+static void ah_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ip6t_ah *ahinfo = (struct ip6t_ah *)match->data;
+
+	if (!(ahinfo->spis[0] == 0
+	    && ahinfo->spis[1] == 0xFFFFFFFF)) {
+		printf("%s--ahspi ",
+			(ahinfo->invflags & IP6T_AH_INV_SPI) ? "! " : "");
+		if (ahinfo->spis[0]
+		    != ahinfo->spis[1])
+			printf("%u:%u ",
+			       ahinfo->spis[0],
+			       ahinfo->spis[1]);
+		else
+			printf("%u ",
+			       ahinfo->spis[0]);
+	}
+
+	if (ahinfo->hdrlen != 0 || (ahinfo->invflags & IP6T_AH_INV_LEN) ) {
+		printf("%s--ahlen %u ", 
+			(ahinfo->invflags & IP6T_AH_INV_LEN) ? "! " : "", 
+			ahinfo->hdrlen);
+	}
+
+	if (ahinfo->hdrres != 0 )
+		printf("--ahres ");
+}
+
+static struct xtables_match ah_mt6_reg = {
+	.name          = "ah",
+	.version       = XTABLES_VERSION,
+	.family        = NFPROTO_IPV6,
+	.size          = XT_ALIGN(sizeof(struct ip6t_ah)),
+	.userspacesize = XT_ALIGN(sizeof(struct ip6t_ah)),
+	.help          = ah_help,
+	.init          = ah_init,
+	.parse         = ah_parse,
+	.print         = ah_print,
+	.save          = ah_save,
+	.extra_opts    = ah_opts,
+};
+
+void
+_init(void)
+{
+	xtables_register_match(&ah_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_ah.man b/ap/app/iptables/extensions/libip6t_ah.man
new file mode 100755
index 0000000..9c24dcf
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_ah.man
@@ -0,0 +1,10 @@
+This module matches the parameters in Authentication header of IPsec packets.
+.TP
+[\fB!\fP] \fB\-\-ahspi\fP \fIspi\fP[\fB:\fP\fIspi\fP]
+Matches SPI.
+.TP
+[\fB!\fP] \fB\-\-ahlen\fP \fIlength\fP
+Total length of this header in octets.
+.TP
+\fB\-\-ahres\fP
+Matches if the reserved field is filled with zero.
diff --git a/ap/app/iptables/extensions/libip6t_dst.c b/ap/app/iptables/extensions/libip6t_dst.c
new file mode 100755
index 0000000..a47e3a3
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_dst.c
@@ -0,0 +1,241 @@
+/* Shared library add-on to ip6tables to add Dst header support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <xtables.h>
+#include <linux/netfilter_ipv6/ip6t_opts.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+static void dst_help(void)
+{
+	printf(
+"dst match options:\n"
+"[!] --dst-len length            total length of this header\n"
+"  --dst-opts TYPE[:LEN][,TYPE[:LEN]...]\n"
+"                                Options and its length (list, max: %d)\n",
+IP6T_OPTS_OPTSNR);
+}
+
+static const struct option dst_opts[] = {
+	{ .name = "dst-len",        .has_arg = 1, .val = '1' },
+	{ .name = "dst-opts",       .has_arg = 1, .val = '2' },
+	{ .name = "dst-not-strict", .has_arg = 1, .val = '3' },
+	{ .name = NULL }
+};
+
+static u_int32_t
+parse_opts_num(const char *idstr, const char *typestr)
+{
+	unsigned long int id;
+	char* ep;
+
+	id = strtoul(idstr, &ep, 0);
+
+	if ( idstr == ep ) {
+		xtables_error(PARAMETER_PROBLEM,
+		           "dst: no valid digits in %s `%s'", typestr, idstr);
+	}
+	if ( id == ULONG_MAX  && errno == ERANGE ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "%s `%s' specified too big: would overflow",
+			   typestr, idstr);
+	}
+	if ( *idstr != '\0'  && *ep != '\0' ) {
+		xtables_error(PARAMETER_PROBLEM,
+		           "dst: error parsing %s `%s'", typestr, idstr);
+	}
+	return id;
+}
+
+static int
+parse_options(const char *optsstr, u_int16_t *opts)
+{
+        char *buffer, *cp, *next, *range;
+        unsigned int i;
+	
+	buffer = strdup(optsstr);
+        if (!buffer)
+		xtables_error(OTHER_PROBLEM, "strdup failed");
+			
+        for (cp = buffer, i = 0; cp && i < IP6T_OPTS_OPTSNR; cp = next, i++)
+        {
+                next = strchr(cp, ',');
+
+                if (next)
+			*next++='\0';
+
+                range = strchr(cp, ':');
+
+                if (range) {
+                        if (i == IP6T_OPTS_OPTSNR-1)
+				xtables_error(PARAMETER_PROBLEM,
+                                           "too many ports specified");
+                        *range++ = '\0';
+                }
+
+		opts[i] = (parse_opts_num(cp, "opt") & 0xFF) << 8;
+                if (range) {
+			if (opts[i] == 0)
+				xtables_error(PARAMETER_PROBLEM,
+					"PAD0 hasn't got length");
+			opts[i] |= parse_opts_num(range, "length") & 0xFF;
+                } else
+                        opts[i] |= (0x00FF);
+
+#ifdef DEBUG
+		printf("opts str: %s %s\n", cp, range);
+		printf("opts opt: %04X\n", opts[i]);
+#endif
+	}
+
+        if (cp)
+		xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
+
+	free(buffer);
+
+#ifdef DEBUG
+	printf("addr nr: %d\n", i);
+#endif
+
+	return i;
+}
+
+static void dst_init(struct xt_entry_match *m)
+{
+	struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data;
+
+	optinfo->hdrlen = 0;
+	optinfo->flags = 0;
+	optinfo->invflags = 0;
+	optinfo->optsnr = 0;
+}
+
+static int dst_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_match **match)
+{
+	struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & IP6T_OPTS_LEN)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--dst-len' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		optinfo->hdrlen = parse_opts_num(argv[optind-1], "length");
+		if (invert)
+			optinfo->invflags |= IP6T_OPTS_INV_LEN;
+		optinfo->flags |= IP6T_OPTS_LEN;
+		*flags |= IP6T_OPTS_LEN;
+		break;
+	case '2':
+		if (*flags & IP6T_OPTS_OPTS)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--dst-opts' allowed");
+                xtables_check_inverse(optarg, &invert, &optind, 0);
+                if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+				" '!' not allowed with `--dst-opts'");
+		optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts);
+		optinfo->flags |= IP6T_OPTS_OPTS;
+		*flags |= IP6T_OPTS_OPTS;
+		break;
+	case '3':
+		if (*flags & IP6T_OPTS_NSTRICT)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--dst-not-strict' allowed");
+		if ( !(*flags & IP6T_OPTS_OPTS) )
+			xtables_error(PARAMETER_PROBLEM,
+				   "`--dst-opts ...' required before "
+				   "`--dst-not-strict'");
+		optinfo->flags |= IP6T_OPTS_NSTRICT;
+		*flags |= IP6T_OPTS_NSTRICT;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+print_options(unsigned int optsnr, u_int16_t *optsp)
+{
+	unsigned int i;
+
+	for(i = 0; i < optsnr; i++) {
+		printf("%d", (optsp[i] & 0xFF00) >> 8);
+
+		if ((optsp[i] & 0x00FF) != 0x00FF)
+			printf(":%d", (optsp[i] & 0x00FF));
+
+		printf("%c", (i != optsnr - 1) ? ',' : ' ');
+	}
+}
+
+static void dst_print(const void *ip, const struct xt_entry_match *match,
+                      int numeric)
+{
+	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
+
+	printf("dst ");
+	if (optinfo->flags & IP6T_OPTS_LEN)
+		printf("length:%s%u ",
+			optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "",
+			optinfo->hdrlen);
+
+	if (optinfo->flags & IP6T_OPTS_OPTS)
+		printf("opts ");
+
+	print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
+
+	if (optinfo->flags & IP6T_OPTS_NSTRICT)
+		printf("not-strict ");
+
+	if (optinfo->invflags & ~IP6T_OPTS_INV_MASK)
+		printf("Unknown invflags: 0x%X ",
+		       optinfo->invflags & ~IP6T_OPTS_INV_MASK);
+}
+
+static void dst_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
+
+	if (optinfo->flags & IP6T_OPTS_LEN) {
+		printf("%s--dst-len %u ",
+			(optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "", 
+			optinfo->hdrlen);
+	}
+
+	if (optinfo->flags & IP6T_OPTS_OPTS)
+		printf("--dst-opts ");
+
+	print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
+
+	if (optinfo->flags & IP6T_OPTS_NSTRICT)
+		printf("--dst-not-strict ");
+}
+
+static struct xtables_match dst_mt6_reg = {
+	.name          = "dst",
+	.version       = XTABLES_VERSION,
+	.family        = NFPROTO_IPV6,
+	.size          = XT_ALIGN(sizeof(struct ip6t_opts)),
+	.userspacesize = XT_ALIGN(sizeof(struct ip6t_opts)),
+	.help          = dst_help,
+	.init          = dst_init,
+	.parse         = dst_parse,
+	.print         = dst_print,
+	.save          = dst_save,
+	.extra_opts    = dst_opts,
+};
+
+void
+_init(void)
+{
+	xtables_register_match(&dst_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_dst.man b/ap/app/iptables/extensions/libip6t_dst.man
new file mode 100755
index 0000000..bfbb501
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_dst.man
@@ -0,0 +1,7 @@
+This module matches the parameters in Destination Options header
+.TP
+[\fB!\fP] \fB\-\-dst\-len\fP \fIlength\fP
+Total length of this header in octets.
+.TP
+\fB\-\-dst\-opts\fP \fItype\fP[\fB:\fP\fIlength\fP][\fB,\fP\fItype\fP[\fB:\fP\fIlength\fP]...]
+numeric type of option and the length of the option data in octets.
diff --git a/ap/app/iptables/extensions/libip6t_eui64.c b/ap/app/iptables/extensions/libip6t_eui64.c
new file mode 100755
index 0000000..c92c868
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_eui64.c
@@ -0,0 +1,41 @@
+/* Shared library add-on to ip6tables to add EUI64 address checking support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#if defined(__GLIBC__) && __GLIBC__ == 2
+#include <net/ethernet.h>
+#else
+#include <linux/if_ether.h>
+#endif
+#include <xtables.h>
+
+static void eui64_help(void)
+{
+	printf(
+"eui64 match options:\n"
+" This module hasn't got any option\n"
+" This module checks for EUI64 IPv6 addresses\n");
+}
+
+static int eui64_parse(int c, char **argv, int invert, unsigned int *flags,
+                       const void *entry, struct xt_entry_match **match)
+{
+	return 0;
+}
+
+static struct xtables_match eui64_mt6_reg = {
+	.name 		= "eui64",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV6,
+	.size		= XT_ALIGN(sizeof(int)),
+	.userspacesize	= XT_ALIGN(sizeof(int)),
+	.help		= eui64_help,
+	.parse		= eui64_parse,
+};
+
+void _init(void)
+{
+	xtables_register_match(&eui64_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_eui64.man b/ap/app/iptables/extensions/libip6t_eui64.man
new file mode 100755
index 0000000..cd80b98
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_eui64.man
@@ -0,0 +1,10 @@
+This module matches the EUI-64 part of a stateless autoconfigured IPv6 address.
+It compares the EUI-64 derived from the source MAC address in Ethernet frame
+with the lower 64 bits of the IPv6 source address. But "Universal/Local"
+bit is not compared. This module doesn't match other link layer frame, and
+is only valid in the
+.BR PREROUTING ,
+.BR INPUT
+and
+.BR FORWARD
+chains.
diff --git a/ap/app/iptables/extensions/libip6t_frag.c b/ap/app/iptables/extensions/libip6t_frag.c
new file mode 100755
index 0000000..905b494
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_frag.c
@@ -0,0 +1,252 @@
+/* Shared library add-on to ip6tables to add Fragmentation header support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <xtables.h>
+#include <linux/netfilter_ipv6/ip6t_frag.h>
+
+static void frag_help(void)
+{
+	printf(
+"frag match options:\n"
+"[!] --fragid id[:id]           match the id (range)\n"
+"[!] --fraglen length           total length of this header\n"
+" --fragres                     check the reserved filed, too\n"
+" --fragfirst                   matches on the first fragment\n"
+" [--fragmore|--fraglast]       there are more fragments or this\n"
+"                               is the last one\n");
+}
+
+static const struct option frag_opts[] = {
+	{ .name = "fragid",    .has_arg = 1, .val = '1' },
+	{ .name = "fraglen",   .has_arg = 1, .val = '2' },
+	{ .name = "fragres",   .has_arg = 0, .val = '3' },
+	{ .name = "fragfirst", .has_arg = 0, .val = '4' },
+	{ .name = "fragmore",  .has_arg = 0, .val = '5' },
+	{ .name = "fraglast",  .has_arg = 0, .val = '6' },
+	{ .name = NULL }
+};
+
+static u_int32_t
+parse_frag_id(const char *idstr, const char *typestr)
+{
+	unsigned long int id;
+	char* ep;
+
+	id = strtoul(idstr, &ep, 0);
+
+	if ( idstr == ep ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "FRAG no valid digits in %s `%s'", typestr, idstr);
+	}
+	if ( id == ULONG_MAX  && errno == ERANGE ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "%s `%s' specified too big: would overflow",
+			   typestr, idstr);
+	}	
+	if ( *idstr != '\0'  && *ep != '\0' ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "FRAG error parsing %s `%s'", typestr, idstr);
+	}
+	return id;
+}
+
+static void
+parse_frag_ids(const char *idstring, u_int32_t *ids)
+{
+	char *buffer;
+	char *cp;
+
+	buffer = strdup(idstring);
+	if ((cp = strchr(buffer, ':')) == NULL)
+		ids[0] = ids[1] = parse_frag_id(buffer,"id");
+	else {
+		*cp = '\0';
+		cp++;
+
+		ids[0] = buffer[0] ? parse_frag_id(buffer,"id") : 0;
+		ids[1] = cp[0] ? parse_frag_id(cp,"id") : 0xFFFFFFFF;
+	}
+	free(buffer);
+}
+
+static void frag_init(struct xt_entry_match *m)
+{
+	struct ip6t_frag *fraginfo = (struct ip6t_frag *)m->data;
+
+	fraginfo->ids[0] = 0x0L;
+	fraginfo->ids[1] = 0xFFFFFFFF;
+	fraginfo->hdrlen = 0;
+	fraginfo->flags = 0;
+	fraginfo->invflags = 0;
+}
+
+static int frag_parse(int c, char **argv, int invert, unsigned int *flags,
+                      const void *entry, struct xt_entry_match **match)
+{
+	struct ip6t_frag *fraginfo = (struct ip6t_frag *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & IP6T_FRAG_IDS)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--fragid' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_frag_ids(argv[optind-1], fraginfo->ids);
+		if (invert)
+			fraginfo->invflags |= IP6T_FRAG_INV_IDS;
+		fraginfo->flags |= IP6T_FRAG_IDS;
+		*flags |= IP6T_FRAG_IDS;
+		break;
+	case '2':
+		if (*flags & IP6T_FRAG_LEN)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--fraglen' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		fraginfo->hdrlen = parse_frag_id(argv[optind-1], "length");
+		if (invert)
+			fraginfo->invflags |= IP6T_FRAG_INV_LEN;
+		fraginfo->flags |= IP6T_FRAG_LEN;
+		*flags |= IP6T_FRAG_LEN;
+		break;
+	case '3':
+		if (*flags & IP6T_FRAG_RES)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--fragres' allowed");
+		fraginfo->flags |= IP6T_FRAG_RES;
+		*flags |= IP6T_FRAG_RES;
+		break;
+	case '4':
+		if (*flags & IP6T_FRAG_FST)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--fragfirst' allowed");
+		fraginfo->flags |= IP6T_FRAG_FST;
+		*flags |= IP6T_FRAG_FST;
+		break;
+	case '5':
+		if (*flags & (IP6T_FRAG_MF|IP6T_FRAG_NMF)) 
+			xtables_error(PARAMETER_PROBLEM,
+			   "Only one `--fragmore' or `--fraglast' allowed");
+		fraginfo->flags |= IP6T_FRAG_MF;
+		*flags |= IP6T_FRAG_MF;
+		break;
+	case '6':
+		if (*flags & (IP6T_FRAG_MF|IP6T_FRAG_NMF)) 
+			xtables_error(PARAMETER_PROBLEM,
+			   "Only one `--fragmore' or `--fraglast' allowed");
+		fraginfo->flags |= IP6T_FRAG_NMF;
+		*flags |= IP6T_FRAG_NMF;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+print_ids(const char *name, u_int32_t min, u_int32_t max,
+	    int invert)
+{
+	const char *inv = invert ? "!" : "";
+
+	if (min != 0 || max != 0xFFFFFFFF || invert) {
+		printf("%s", name);
+		if (min == max)
+			printf(":%s%u ", inv, min);
+		else
+			printf("s:%s%u:%u ", inv, min, max);
+	}
+}
+
+static void frag_print(const void *ip, const struct xt_entry_match *match,
+                       int numeric)
+{
+	const struct ip6t_frag *frag = (struct ip6t_frag *)match->data;
+
+	printf("frag ");
+	print_ids("id", frag->ids[0], frag->ids[1],
+		    frag->invflags & IP6T_FRAG_INV_IDS);
+
+	if (frag->flags & IP6T_FRAG_LEN) {
+		printf("length:%s%u ",
+			frag->invflags & IP6T_FRAG_INV_LEN ? "!" : "",
+			frag->hdrlen);
+	}
+
+	if (frag->flags & IP6T_FRAG_RES)
+		printf("reserved ");
+
+	if (frag->flags & IP6T_FRAG_FST)
+		printf("first ");
+
+	if (frag->flags & IP6T_FRAG_MF)
+		printf("more ");
+
+	if (frag->flags & IP6T_FRAG_NMF)
+		printf("last ");
+
+	if (frag->invflags & ~IP6T_FRAG_INV_MASK)
+		printf("Unknown invflags: 0x%X ",
+		       frag->invflags & ~IP6T_FRAG_INV_MASK);
+}
+
+static void frag_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ip6t_frag *fraginfo = (struct ip6t_frag *)match->data;
+
+	if (!(fraginfo->ids[0] == 0
+	    && fraginfo->ids[1] == 0xFFFFFFFF)) {
+		printf("%s--fragid ", 
+			(fraginfo->invflags & IP6T_FRAG_INV_IDS) ? "! " : "");
+		if (fraginfo->ids[0]
+		    != fraginfo->ids[1])
+			printf("%u:%u ",
+			       fraginfo->ids[0],
+			       fraginfo->ids[1]);
+		else
+			printf("%u ",
+			       fraginfo->ids[0]);
+	}
+
+	if (fraginfo->flags & IP6T_FRAG_LEN) {
+		printf("%s--fraglen %u ", 
+			(fraginfo->invflags & IP6T_FRAG_INV_LEN) ? "! " : "", 
+			fraginfo->hdrlen);
+	}
+
+	if (fraginfo->flags & IP6T_FRAG_RES)
+		printf("--fragres ");
+
+	if (fraginfo->flags & IP6T_FRAG_FST)
+		printf("--fragfirst ");
+
+	if (fraginfo->flags & IP6T_FRAG_MF)
+		printf("--fragmore ");
+
+	if (fraginfo->flags & IP6T_FRAG_NMF)
+		printf("--fraglast ");
+}
+
+static struct xtables_match frag_mt6_reg = {
+	.name          = "frag",
+	.version       = XTABLES_VERSION,
+	.family        = NFPROTO_IPV6,
+	.size          = XT_ALIGN(sizeof(struct ip6t_frag)),
+	.userspacesize = XT_ALIGN(sizeof(struct ip6t_frag)),
+	.help          = frag_help,
+	.init          = frag_init,
+	.parse         = frag_parse,
+	.print         = frag_print,
+	.save          = frag_save,
+	.extra_opts    = frag_opts,
+};
+
+void
+_init(void)
+{
+	xtables_register_match(&frag_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_frag.man b/ap/app/iptables/extensions/libip6t_frag.man
new file mode 100755
index 0000000..7bfa227
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_frag.man
@@ -0,0 +1,20 @@
+This module matches the parameters in Fragment header.
+.TP
+[\fB!\fP] \fB\-\-fragid\fP \fIid\fP[\fB:\fP\fIid\fP]
+Matches the given Identification or range of it.
+.TP
+[\fB!\fP] \fB\-\-fraglen\fP \fIlength\fP
+This option cannot be used with kernel version 2.6.10 or later. The length of
+Fragment header is static and this option doesn't make sense.
+.TP
+\fB\-\-fragres\fP
+Matches if the reserved fields are filled with zero.
+.TP
+\fB\-\-fragfirst\fP
+Matches on the first fragment.
+.TP
+\fB\-\-fragmore\fP
+Matches if there are more fragments.
+.TP
+\fB\-\-fraglast\fP
+Matches if this is the last fragment.
diff --git a/ap/app/iptables/extensions/libip6t_hbh.c b/ap/app/iptables/extensions/libip6t_hbh.c
new file mode 100755
index 0000000..e08d84a
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_hbh.c
@@ -0,0 +1,228 @@
+/* Shared library add-on to ip6tables to add Hop-by-Hop header support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <xtables.h>
+/*#include <linux/in6.h>*/
+#include <linux/netfilter_ipv6/ip6t_opts.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#define DEBUG		0
+
+static void hbh_help(void)
+{
+	printf(
+"hbh match options:\n"
+"[!] --hbh-len length            total length of this header\n"
+"  --hbh-opts TYPE[:LEN][,TYPE[:LEN]...] \n"
+"                                Options and its length (list, max: %d)\n",
+IP6T_OPTS_OPTSNR);
+}
+
+static const struct option hbh_opts[] = {
+	{ "hbh-len", 1, NULL, '1' },
+	{ "hbh-opts", 1, NULL, '2' },
+	{ "hbh-not-strict", 1, NULL, '3' },
+	{ .name = NULL }
+};
+
+static u_int32_t
+parse_opts_num(const char *idstr, const char *typestr)
+{
+	unsigned long int id;
+	char* ep;
+
+	id =  strtoul(idstr,&ep,0) ;
+
+	if ( idstr == ep ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "hbh: no valid digits in %s `%s'", typestr, idstr);
+	}
+	if ( id == ULONG_MAX  && errno == ERANGE ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "%s `%s' specified too big: would overflow",
+			   typestr, idstr);
+	}	
+	if ( *idstr != '\0'  && *ep != '\0' ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "hbh: error parsing %s `%s'", typestr, idstr);
+	}
+	return id;
+}
+
+static int
+parse_options(const char *optsstr, u_int16_t *opts)
+{
+        char *buffer, *cp, *next, *range;
+        unsigned int i;
+	
+	buffer = strdup(optsstr);
+	if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
+			
+        for (cp=buffer, i=0; cp && i<IP6T_OPTS_OPTSNR; cp=next,i++)
+        {
+                next=strchr(cp, ',');
+                if (next) *next++='\0';
+                range = strchr(cp, ':');
+                if (range) {
+                        if (i == IP6T_OPTS_OPTSNR-1)
+				xtables_error(PARAMETER_PROBLEM,
+                                           "too many ports specified");
+                        *range++ = '\0';
+                }
+		opts[i] = (parse_opts_num(cp, "opt") & 0xFF) << 8;
+                if (range) {
+			if (opts[i] == 0)
+				xtables_error(PARAMETER_PROBLEM, "PAD0 has not got length");
+			opts[i] |= parse_opts_num(range, "length") & 0xFF;
+                } else {
+                        opts[i] |= (0x00FF);
+		}
+
+#if DEBUG
+		printf("opts str: %s %s\n", cp, range);
+		printf("opts opt: %04X\n", opts[i]);
+#endif
+	}
+	if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
+
+	free(buffer);
+
+#if DEBUG
+	printf("addr nr: %d\n", i);
+#endif
+
+	return i;
+}
+
+static void hbh_init(struct xt_entry_match *m)
+{
+	struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data;
+
+	optinfo->hdrlen = 0;
+	optinfo->flags = 0;
+	optinfo->invflags = 0;
+	optinfo->optsnr = 0;
+}
+
+static int hbh_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_match **match)
+{
+	struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & IP6T_OPTS_LEN)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--hbh-len' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		optinfo->hdrlen = parse_opts_num(argv[optind-1], "length");
+		if (invert)
+			optinfo->invflags |= IP6T_OPTS_INV_LEN;
+		optinfo->flags |= IP6T_OPTS_LEN;
+		*flags |= IP6T_OPTS_LEN;
+		break;
+	case '2':
+		if (*flags & IP6T_OPTS_OPTS)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--hbh-opts' allowed");
+                xtables_check_inverse(optarg, &invert, &optind, 0);
+                if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+				" '!' not allowed with `--hbh-opts'");
+		optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts);
+		optinfo->flags |= IP6T_OPTS_OPTS;
+		*flags |= IP6T_OPTS_OPTS;
+		break;
+	case '3':
+		if (*flags & IP6T_OPTS_NSTRICT)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--hbh-not-strict' allowed");
+		if ( !(*flags & IP6T_OPTS_OPTS) )
+			xtables_error(PARAMETER_PROBLEM,
+				   "`--hbh-opts ...' required before `--hbh-not-strict'");
+		optinfo->flags |= IP6T_OPTS_NSTRICT;
+		*flags |= IP6T_OPTS_NSTRICT;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+print_options(unsigned int optsnr, u_int16_t *optsp)
+{
+	unsigned int i;
+
+	for(i=0; i<optsnr; i++){
+		printf("%d", (optsp[i] & 0xFF00)>>8);
+		if ((optsp[i] & 0x00FF) != 0x00FF){
+			printf(":%d", (optsp[i] & 0x00FF));
+		} 
+		printf("%c", (i!=optsnr-1)?',':' ');
+	}
+}
+
+static void hbh_print(const void *ip, const struct xt_entry_match *match,
+                      int numeric)
+{
+	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
+
+	printf("hbh ");
+	if (optinfo->flags & IP6T_OPTS_LEN) {
+		printf("length");
+		printf(":%s", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "");
+		printf("%u", optinfo->hdrlen);
+		printf(" ");
+	}
+	if (optinfo->flags & IP6T_OPTS_OPTS) printf("opts ");
+	print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
+	if (optinfo->flags & IP6T_OPTS_NSTRICT) printf("not-strict ");
+	if (optinfo->invflags & ~IP6T_OPTS_INV_MASK)
+		printf("Unknown invflags: 0x%X ",
+		       optinfo->invflags & ~IP6T_OPTS_INV_MASK);
+}
+
+static void hbh_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
+
+	if (optinfo->flags & IP6T_OPTS_LEN) {
+		printf("%s--hbh-len %u ",
+			(optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "", 
+			optinfo->hdrlen);
+	}
+
+	if (optinfo->flags & IP6T_OPTS_OPTS)
+		printf("--hbh-opts ");
+	print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
+	if (optinfo->flags & IP6T_OPTS_NSTRICT)
+		printf("--hbh-not-strict ");
+}
+
+static struct xtables_match hbh_mt6_reg = {
+	.name 		= "hbh",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV6,
+	.size		= XT_ALIGN(sizeof(struct ip6t_opts)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_opts)),
+	.help		= hbh_help,
+	.init		= hbh_init,
+	.parse		= hbh_parse,
+	.print		= hbh_print,
+	.save		= hbh_save,
+	.extra_opts	= hbh_opts,
+};
+
+void
+_init(void)
+{
+	xtables_register_match(&hbh_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_hbh.man b/ap/app/iptables/extensions/libip6t_hbh.man
new file mode 100755
index 0000000..2d92e04
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_hbh.man
@@ -0,0 +1,7 @@
+This module matches the parameters in Hop-by-Hop Options header
+.TP
+[\fB!\fP] \fB\-\-hbh\-len\fP \fIlength\fP
+Total length of this header in octets.
+.TP
+\fB\-\-hbh\-opts\fP \fItype\fP[\fB:\fP\fIlength\fP][\fB,\fP\fItype\fP[\fB:\fP\fIlength\fP]...]
+numeric type of option and the length of the option data in octets.
diff --git a/ap/app/iptables/extensions/libip6t_hl.c b/ap/app/iptables/extensions/libip6t_hl.c
new file mode 100755
index 0000000..9252c3d
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_hl.c
@@ -0,0 +1,144 @@
+/*
+ * IPv6 Hop Limit matching module
+ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
+ * Based on HW's ttl match
+ * This program is released under the terms of GNU GPL
+ * Cleanups by Stephane Ouellette <ouellettes@videotron.ca>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <xtables.h>
+
+#include <linux/netfilter_ipv6/ip6t_hl.h>
+
+static void hl_help(void)
+{
+	printf(
+"hl match options:\n"
+"[!] --hl-eq value	Match hop limit value\n"
+"  --hl-lt value	Match HL < value\n"
+"  --hl-gt value	Match HL > value\n");
+}
+
+static int hl_parse(int c, char **argv, int invert, unsigned int *flags,
+                    const void *entry, struct xt_entry_match **match)
+{
+	struct ip6t_hl_info *info = (struct ip6t_hl_info *) (*match)->data;
+	u_int8_t value;
+
+	xtables_check_inverse(optarg, &invert, &optind, 0);
+	value = atoi(argv[optind-1]);
+
+	if (*flags) 
+		xtables_error(PARAMETER_PROBLEM,
+				"Can't specify HL option twice");
+
+	if (!optarg)
+		xtables_error(PARAMETER_PROBLEM,
+				"hl: You must specify a value");
+	switch (c) {
+		case '2':
+			if (invert)
+				info->mode = IP6T_HL_NE;
+			else
+				info->mode = IP6T_HL_EQ;
+
+			/* is 0 allowed? */
+			info->hop_limit = value;
+			*flags = 1;
+
+			break;
+		case '3':
+			if (invert) 
+				xtables_error(PARAMETER_PROBLEM,
+						"hl: unexpected `!'");
+
+			info->mode = IP6T_HL_LT;
+			info->hop_limit = value;
+			*flags = 1;
+
+			break;
+		case '4':
+			if (invert)
+				xtables_error(PARAMETER_PROBLEM,
+						"hl: unexpected `!'");
+
+			info->mode = IP6T_HL_GT;
+			info->hop_limit = value;
+			*flags = 1;
+
+			break;
+		default:
+			return 0;
+	}
+
+	return 1;
+}
+
+static void hl_check(unsigned int flags)
+{
+	if (!flags) 
+		xtables_error(PARAMETER_PROBLEM,
+			"HL match: You must specify one of "
+			"`--hl-eq', `--hl-lt', `--hl-gt'");
+}
+
+static void hl_print(const void *ip, const struct xt_entry_match *match,
+                     int numeric)
+{
+	static const char *op[] = {
+		[IP6T_HL_EQ] = "==",
+		[IP6T_HL_NE] = "!=",
+		[IP6T_HL_LT] = "<",
+		[IP6T_HL_GT] = ">" };
+
+	const struct ip6t_hl_info *info = 
+		(struct ip6t_hl_info *) match->data;
+
+	printf("HL match HL %s %u ", op[info->mode], info->hop_limit);
+}
+
+static void hl_save(const void *ip, const struct xt_entry_match *match)
+{
+	static const char *const op[] = {
+		[IP6T_HL_EQ] = "--hl-eq",
+		[IP6T_HL_NE] = "! --hl-eq",
+		[IP6T_HL_LT] = "--hl-lt",
+		[IP6T_HL_GT] = "--hl-gt" };
+
+	const struct ip6t_hl_info *info =
+		(struct ip6t_hl_info *) match->data;
+
+	printf("%s %u ", op[info->mode], info->hop_limit);
+}
+
+static const struct option hl_opts[] = {
+	{ .name = "hl",    .has_arg = 1, .val = '2' },
+	{ .name = "hl-eq", .has_arg = 1, .val = '2' },
+	{ .name = "hl-lt", .has_arg = 1, .val = '3' },
+	{ .name = "hl-gt", .has_arg = 1, .val = '4' },
+	{ .name = NULL }
+};
+
+static struct xtables_match hl_mt6_reg = {
+	.name          = "hl",
+	.version       = XTABLES_VERSION,
+	.family        = NFPROTO_IPV6,
+	.size          = XT_ALIGN(sizeof(struct ip6t_hl_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct ip6t_hl_info)),
+	.help          = hl_help,
+	.parse         = hl_parse,
+	.final_check   = hl_check,
+	.print         = hl_print,
+	.save          = hl_save,
+	.extra_opts    = hl_opts,
+};
+
+
+void _init(void) 
+{
+	xtables_register_match(&hl_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_hl.man b/ap/app/iptables/extensions/libip6t_hl.man
new file mode 100755
index 0000000..dfbfaf8
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_hl.man
@@ -0,0 +1,10 @@
+This module matches the Hop Limit field in the IPv6 header.
+.TP
+[\fB!\fP] \fB\-\-hl\-eq\fP \fIvalue\fP
+Matches if Hop Limit equals \fIvalue\fP.
+.TP
+\fB\-\-hl\-lt\fP \fIvalue\fP
+Matches if Hop Limit is less than \fIvalue\fP.
+.TP
+\fB\-\-hl\-gt\fP \fIvalue\fP
+Matches if Hop Limit is greater than \fIvalue\fP.
diff --git a/ap/app/iptables/extensions/libip6t_icmp6.c b/ap/app/iptables/extensions/libip6t_icmp6.c
new file mode 100755
index 0000000..0678aac
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_icmp6.c
@@ -0,0 +1,266 @@
+/* Shared library add-on to ip6tables to add ICMP support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <limits.h> /* INT_MAX in ip6_tables.h */
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+struct icmpv6_names {
+	const char *name;
+	u_int8_t type;
+	u_int8_t code_min, code_max;
+};
+
+static const struct icmpv6_names icmpv6_codes[] = {
+	{ "destination-unreachable", 1, 0, 0xFF },
+	{   "no-route", 1, 0, 0 },
+	{   "communication-prohibited", 1, 1, 1 },
+	{   "address-unreachable", 1, 3, 3 },
+	{   "port-unreachable", 1, 4, 4 },
+
+	{ "packet-too-big", 2, 0, 0xFF },
+
+	{ "time-exceeded", 3, 0, 0xFF },
+	/* Alias */ { "ttl-exceeded", 3, 0, 0xFF },
+	{   "ttl-zero-during-transit", 3, 0, 0 },
+	{   "ttl-zero-during-reassembly", 3, 1, 1 },
+
+	{ "parameter-problem", 4, 0, 0xFF },
+	{   "bad-header", 4, 0, 0 },
+	{   "unknown-header-type", 4, 1, 1 },
+	{   "unknown-option", 4, 2, 2 },
+
+	{ "echo-request", 128, 0, 0xFF },
+	/* Alias */ { "ping", 128, 0, 0xFF },
+
+	{ "echo-reply", 129, 0, 0xFF },
+	/* Alias */ { "pong", 129, 0, 0xFF },
+
+	{ "router-solicitation", 133, 0, 0xFF },
+
+	{ "router-advertisement", 134, 0, 0xFF },
+
+	{ "neighbour-solicitation", 135, 0, 0xFF },
+	/* Alias */ { "neighbor-solicitation", 135, 0, 0xFF },
+
+	{ "neighbour-advertisement", 136, 0, 0xFF },
+	/* Alias */ { "neighbor-advertisement", 136, 0, 0xFF },
+
+	{ "redirect", 137, 0, 0xFF },
+
+};
+
+static void
+print_icmpv6types(void)
+{
+	unsigned int i;
+	printf("Valid ICMPv6 Types:");
+
+	for (i = 0; i < sizeof(icmpv6_codes)/sizeof(struct icmpv6_names); i++) {
+		if (i && icmpv6_codes[i].type == icmpv6_codes[i-1].type) {
+			if (icmpv6_codes[i].code_min == icmpv6_codes[i-1].code_min
+			    && (icmpv6_codes[i].code_max
+				== icmpv6_codes[i-1].code_max))
+				printf(" (%s)", icmpv6_codes[i].name);
+			else
+				printf("\n   %s", icmpv6_codes[i].name);
+		}
+		else
+			printf("\n%s", icmpv6_codes[i].name);
+	}
+	printf("\n");
+}
+
+static void icmp6_help(void)
+{
+	printf(
+"icmpv6 match options:\n"
+"[!] --icmpv6-type typename	match icmpv6 type\n"
+"				(or numeric type or type/code)\n");
+	print_icmpv6types();
+}
+
+static const struct option icmp6_opts[] = {
+	{ "icmpv6-type", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static void
+parse_icmpv6(const char *icmpv6type, u_int8_t *type, u_int8_t code[])
+{
+	unsigned int limit = sizeof(icmpv6_codes)/sizeof(struct icmpv6_names);
+	unsigned int match = limit;
+	unsigned int i;
+
+	for (i = 0; i < limit; i++) {
+		if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type))
+		    == 0) {
+			if (match != limit)
+				xtables_error(PARAMETER_PROBLEM,
+					   "Ambiguous ICMPv6 type `%s':"
+					   " `%s' or `%s'?",
+					   icmpv6type,
+					   icmpv6_codes[match].name,
+					   icmpv6_codes[i].name);
+			match = i;
+		}
+	}
+
+	if (match != limit) {
+		*type = icmpv6_codes[match].type;
+		code[0] = icmpv6_codes[match].code_min;
+		code[1] = icmpv6_codes[match].code_max;
+	} else {
+		char *slash;
+		char buffer[strlen(icmpv6type) + 1];
+		unsigned int number;
+
+		strcpy(buffer, icmpv6type);
+		slash = strchr(buffer, '/');
+
+		if (slash)
+			*slash = '\0';
+
+		if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Invalid ICMPv6 type `%s'\n", buffer);
+		*type = number;
+		if (slash) {
+			if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX))
+				xtables_error(PARAMETER_PROBLEM,
+					   "Invalid ICMPv6 code `%s'\n",
+					   slash+1);
+			code[0] = code[1] = number;
+		} else {
+			code[0] = 0;
+			code[1] = 0xFF;
+		}
+	}
+}
+
+static void icmp6_init(struct xt_entry_match *m)
+{
+	struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)m->data;
+
+	icmpv6info->code[1] = 0xFF;
+}
+
+static int icmp6_parse(int c, char **argv, int invert, unsigned int *flags,
+                       const void *entry, struct xt_entry_match **match)
+{
+	struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags == 1)
+			xtables_error(PARAMETER_PROBLEM,
+				   "icmpv6 match: only use --icmpv6-type once!");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_icmpv6(argv[optind-1], &icmpv6info->type, 
+			     icmpv6info->code);
+		if (invert)
+			icmpv6info->invflags |= IP6T_ICMP_INV;
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void print_icmpv6type(u_int8_t type,
+			   u_int8_t code_min, u_int8_t code_max,
+			   int invert,
+			   int numeric)
+{
+	if (!numeric) {
+		unsigned int i;
+
+		for (i = 0;
+		     i < sizeof(icmpv6_codes)/sizeof(struct icmpv6_names);
+		     i++) {
+			if (icmpv6_codes[i].type == type
+			    && icmpv6_codes[i].code_min == code_min
+			    && icmpv6_codes[i].code_max == code_max)
+				break;
+		}
+
+		if (i != sizeof(icmpv6_codes)/sizeof(struct icmpv6_names)) {
+			printf("%s%s ",
+			       invert ? "!" : "",
+			       icmpv6_codes[i].name);
+			return;
+		}
+	}
+
+	if (invert)
+		printf("!");
+
+	printf("type %u", type);
+	if (code_min == 0 && code_max == 0xFF)
+		printf(" ");
+	else if (code_min == code_max)
+		printf(" code %u ", code_min);
+	else
+		printf(" codes %u-%u ", code_min, code_max);
+}
+
+static void icmp6_print(const void *ip, const struct xt_entry_match *match,
+                        int numeric)
+{
+	const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data;
+
+	printf("ipv6-icmp ");
+	print_icmpv6type(icmpv6->type, icmpv6->code[0], icmpv6->code[1],
+		       icmpv6->invflags & IP6T_ICMP_INV,
+		       numeric);
+
+	if (icmpv6->invflags & ~IP6T_ICMP_INV)
+		printf("Unknown invflags: 0x%X ",
+		       icmpv6->invflags & ~IP6T_ICMP_INV);
+}
+
+static void icmp6_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data;
+
+	if (icmpv6->invflags & IP6T_ICMP_INV)
+		printf("! ");
+
+	printf("--icmpv6-type %u", icmpv6->type);
+	if (icmpv6->code[0] != 0 || icmpv6->code[1] != 0xFF)
+		printf("/%u", icmpv6->code[0]);
+	printf(" ");
+}
+
+static void icmp6_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "icmpv6 match: You must specify `--icmpv6-type'");
+}
+
+static struct xtables_match icmp6_mt6_reg = {
+	.name 		= "icmp6",
+	.version 	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV6,
+	.size		= XT_ALIGN(sizeof(struct ip6t_icmp)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_icmp)),
+	.help		= icmp6_help,
+	.init		= icmp6_init,
+	.parse		= icmp6_parse,
+	.final_check	= icmp6_check,
+	.print		= icmp6_print,
+	.save		= icmp6_save,
+	.extra_opts	= icmp6_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&icmp6_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_icmp6.man b/ap/app/iptables/extensions/libip6t_icmp6.man
new file mode 100755
index 0000000..817e21c
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_icmp6.man
@@ -0,0 +1,14 @@
+This extension can be used if `\-\-protocol ipv6\-icmp' or `\-\-protocol icmpv6' is
+specified. It provides the following option:
+.TP
+[\fB!\fP] \fB\-\-icmpv6\-type\fP \fItype\fP[\fB/\fP\fIcode\fP]|\fItypename\fP
+This allows specification of the ICMPv6 type, which can be a numeric
+ICMPv6
+.IR type ,
+.IR type
+and
+.IR code ,
+or one of the ICMPv6 type names shown by the command
+.nf
+ ip6tables \-p ipv6\-icmp \-h
+.fi
diff --git a/ap/app/iptables/extensions/libip6t_ipv6header.c b/ap/app/iptables/extensions/libip6t_ipv6header.c
new file mode 100755
index 0000000..479b313
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_ipv6header.c
@@ -0,0 +1,296 @@
+/* ipv6header match - matches IPv6 packets based
+on whether they contain certain headers */
+
+/* Original idea: Brad Chapman 
+ * Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */
+
+#include <getopt.h>
+#include <xtables.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/types.h>
+
+#include <linux/netfilter_ipv6/ip6t_ipv6header.h>
+
+/* This maybe required 
+#include <linux/in.h>
+#include <linux/in6.h>
+*/
+
+
+/* A few hardcoded protocols for 'all' and in case the user has no
+ *    /etc/protocols */
+struct pprot {
+	char *name;
+	u_int8_t num;
+};
+
+struct numflag {
+	u_int8_t proto;
+	u_int8_t flag;
+};
+
+static const struct pprot chain_protos[] = {
+	{ "hop-by-hop", IPPROTO_HOPOPTS },
+	{ "protocol", IPPROTO_RAW },
+	{ "hop", IPPROTO_HOPOPTS },
+	{ "dst", IPPROTO_DSTOPTS },
+	{ "route", IPPROTO_ROUTING },
+	{ "frag", IPPROTO_FRAGMENT },
+	{ "auth", IPPROTO_AH },
+	{ "esp", IPPROTO_ESP },
+	{ "none", IPPROTO_NONE },
+	{ "prot", IPPROTO_RAW },
+	{ "0", IPPROTO_HOPOPTS },
+	{ "60", IPPROTO_DSTOPTS },
+	{ "43", IPPROTO_ROUTING },
+	{ "44", IPPROTO_FRAGMENT },
+	{ "51", IPPROTO_AH },
+	{ "50", IPPROTO_ESP },
+	{ "59", IPPROTO_NONE },
+	{ "255", IPPROTO_RAW },
+	/* { "all", 0 }, */
+};
+
+static const struct numflag chain_flags[] = {
+	{ IPPROTO_HOPOPTS, MASK_HOPOPTS },
+	{ IPPROTO_DSTOPTS, MASK_DSTOPTS },
+	{ IPPROTO_ROUTING, MASK_ROUTING },
+	{ IPPROTO_FRAGMENT, MASK_FRAGMENT },
+	{ IPPROTO_AH, MASK_AH },
+	{ IPPROTO_ESP, MASK_ESP },
+	{ IPPROTO_NONE, MASK_NONE },
+	{ IPPROTO_RAW, MASK_PROTO },
+};
+
+static char *
+proto_to_name(u_int8_t proto, int nolookup)
+{
+        unsigned int i;
+
+        if (proto && !nolookup) {
+                struct protoent *pent = getprotobynumber(proto);
+                if (pent)
+                        return pent->p_name;
+        }
+
+        for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
+                if (chain_protos[i].num == proto)
+                        return chain_protos[i].name;
+
+        return NULL;
+}
+
+static u_int16_t
+name_to_proto(const char *s)
+{
+        unsigned int proto=0;
+        struct protoent *pent;
+
+        if ((pent = getprotobyname(s)))
+        	proto = pent->p_proto;
+        else {
+        	unsigned int i;
+        	for (i = 0;
+        		i < sizeof(chain_protos)/sizeof(struct pprot);
+        		i++) {
+        		if (strcmp(s, chain_protos[i].name) == 0) {
+        			proto = chain_protos[i].num;
+        			break;
+        		}
+        	}
+
+        	if (i == sizeof(chain_protos)/sizeof(struct pprot))
+			xtables_error(PARAMETER_PROBLEM,
+        			"unknown header `%s' specified",
+        			s);
+        }
+
+        return proto;
+}
+
+static unsigned int 
+add_proto_to_mask(int proto){
+	unsigned int i=0, flag=0;
+
+	for (i = 0;
+		i < sizeof(chain_flags)/sizeof(struct numflag);
+		i++) {
+			if (proto == chain_flags[i].proto){
+				flag = chain_flags[i].flag;
+				break;
+			}
+	}
+
+	if (i == sizeof(chain_flags)/sizeof(struct numflag))
+		xtables_error(PARAMETER_PROBLEM,
+		"unknown header `%d' specified",
+		proto);
+	
+	return flag;
+}	
+
+static void ipv6header_help(void)
+{
+	printf(
+"ipv6header match options:\n"
+"[!] --header headers     Type of header to match, by name\n"
+"                         names: hop,dst,route,frag,auth,esp,none,proto\n"
+"                    long names: hop-by-hop,ipv6-opts,ipv6-route,\n"
+"                                ipv6-frag,ah,esp,ipv6-nonxt,protocol\n"
+"                       numbers: 0,60,43,44,51,50,59\n"
+"--soft                    The header CONTAINS the specified extensions\n");
+}
+
+static const struct option ipv6header_opts[] = {
+	{ "header", 1, NULL, '1' },
+	{ "soft", 0, NULL, '2' },
+	{ .name = NULL }
+};
+
+static void ipv6header_init(struct xt_entry_match *m)
+{
+	struct ip6t_ipv6header_info *info = (struct ip6t_ipv6header_info *)m->data;
+
+	info->matchflags = 0x00;
+	info->invflags = 0x00;
+	info->modeflag = 0x00;
+}
+
+static unsigned int
+parse_header(const char *flags) {
+        unsigned int ret = 0;
+        char *ptr;
+        char *buffer;
+
+        buffer = strdup(flags);
+
+        for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) 
+		ret |= add_proto_to_mask(name_to_proto(ptr));
+                
+        free(buffer);
+        return ret;
+}
+
+#define IPV6_HDR_HEADER	0x01
+#define IPV6_HDR_SOFT	0x02
+
+static int
+ipv6header_parse(int c, char **argv, int invert, unsigned int *flags,
+                 const void *entry, struct xt_entry_match **match)
+{
+	struct ip6t_ipv6header_info *info = (struct ip6t_ipv6header_info *)(*match)->data;
+
+	switch (c) {
+		case '1' : 
+			/* Parse the provided header names */
+			if (*flags & IPV6_HDR_HEADER)
+				xtables_error(PARAMETER_PROBLEM,
+					"Only one `--header' allowed");
+
+			xtables_check_inverse(optarg, &invert, &optind, 0);
+
+			if (! (info->matchflags = parse_header(argv[optind-1])) )
+				xtables_error(PARAMETER_PROBLEM, "ip6t_ipv6header: cannot parse header names");
+
+			if (invert) 
+				info->invflags |= 0xFF;
+			*flags |= IPV6_HDR_HEADER;
+			break;
+		case '2' : 
+			/* Soft-mode requested? */
+			if (*flags & IPV6_HDR_SOFT)
+				xtables_error(PARAMETER_PROBLEM,
+					"Only one `--soft' allowed");
+
+			info->modeflag |= 0xFF;
+			*flags |= IPV6_HDR_SOFT;
+			break;
+		default:
+			return 0;
+	}
+
+	return 1;
+}
+
+static void ipv6header_check(unsigned int flags)
+{
+	if (!flags) xtables_error(PARAMETER_PROBLEM, "ip6t_ipv6header: no options specified");
+}
+
+static void
+print_header(u_int8_t flags){
+        int have_flag = 0;
+
+        while (flags) {
+                unsigned int i;
+
+                for (i = 0; (flags & chain_flags[i].flag) == 0; i++);
+
+                if (have_flag)
+                        printf(",");
+
+                printf("%s", proto_to_name(chain_flags[i].proto,0));
+                have_flag = 1;
+
+                flags &= ~chain_flags[i].flag;
+        }
+
+        if (!have_flag)
+                printf("NONE");
+}
+
+static void ipv6header_print(const void *ip,
+                             const struct xt_entry_match *match, int numeric)
+{
+	const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
+	printf("ipv6header ");
+
+        if (info->matchflags || info->invflags) {
+                printf("flags:%s", info->invflags ? "!" : "");
+                if (numeric)
+                        printf("0x%02X ", info->matchflags);
+                else {
+                        print_header(info->matchflags);
+                        printf(" ");
+                }
+        }
+
+	if (info->modeflag)
+		printf("soft ");
+}
+
+static void ipv6header_save(const void *ip, const struct xt_entry_match *match)
+{
+
+	const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
+
+	printf("%s--header ", info->invflags ? "! " : "");
+	print_header(info->matchflags);
+	printf(" ");
+	if (info->modeflag)
+		printf("--soft ");
+}
+
+static struct xtables_match ipv6header_mt6_reg = {
+	.name		= "ipv6header",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV6,
+	.size		= XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
+	.help		= ipv6header_help,
+	.init		= ipv6header_init,
+	.parse		= ipv6header_parse,
+	.final_check	= ipv6header_check,
+	.print		= ipv6header_print,
+	.save		= ipv6header_save,
+	.extra_opts	= ipv6header_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&ipv6header_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_ipv6header.man b/ap/app/iptables/extensions/libip6t_ipv6header.man
new file mode 100755
index 0000000..a998861
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_ipv6header.man
@@ -0,0 +1,37 @@
+This module matches IPv6 extension headers and/or upper layer header.
+.TP
+\fB\-\-soft\fP
+Matches if the packet includes \fBany\fP of the headers specified with
+\fB\-\-header\fP.
+.TP
+[\fB!\fP] \fB\-\-header\fP \fIheader\fP[\fB,\fP\fIheader\fP...]
+Matches the packet which EXACTLY includes all specified headers. The headers
+encapsulated with ESP header are out of scope.
+Possible \fIheader\fP types can be:
+.TP
+\fBhop\fP|\fBhop\-by\-hop\fP
+Hop-by-Hop Options header
+.TP
+\fBdst\fP
+Destination Options header
+.TP
+\fBroute\fP
+Routing header
+.TP
+\fBfrag\fP
+Fragment header
+.TP
+\fBauth\fP
+Authentication header
+.TP
+\fBesp\fP
+Encapsulating Security Payload header
+.TP
+\fBnone\fP
+No Next header which matches 59 in the 'Next Header field' of IPv6 header or
+any IPv6 extension headers
+.TP
+\fBproto\fP
+which matches any upper layer protocol header. A protocol name from
+/etc/protocols and numeric value also allowed. The number 255 is equivalent to
+\fBproto\fP.
diff --git a/ap/app/iptables/extensions/libip6t_mh.c b/ap/app/iptables/extensions/libip6t_mh.c
new file mode 100755
index 0000000..9711f76
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_mh.c
@@ -0,0 +1,241 @@
+/* Shared library add-on to ip6tables to add mobility header support. */
+/*
+ * Copyright (C)2006 USAGI/WIDE Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Author:
+ *	Masahide NAKAMURA @USAGI <masahide.nakamura.cz@hitachi.com>
+ *
+ * Based on libip6t_{icmpv6,udp}.c
+ */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter_ipv6/ip6t_mh.h>
+
+struct mh_name {
+	const char *name;
+	u_int8_t type;
+};
+
+static const struct mh_name mh_names[] = {
+	{ "binding-refresh-request", 0, },
+	/* Alias */ { "brr", 0, },
+	{ "home-test-init", 1, },
+	/* Alias */ { "hoti", 1, },
+	{ "careof-test-init", 2, },
+	/* Alias */ { "coti", 2, },
+	{ "home-test", 3, },
+	/* Alias */ { "hot", 3, },
+	{ "careof-test", 4, },
+	/* Alias */ { "cot", 4, },
+	{ "binding-update", 5, },
+	/* Alias */ { "bu", 5, },
+	{ "binding-acknowledgement", 6, },
+	/* Alias */ { "ba", 6, },
+	{ "binding-error", 7, },
+	/* Alias */ { "be", 7, },
+};
+
+static void print_types_all(void)
+{
+	unsigned int i;
+	printf("Valid MH types:");
+
+	for (i = 0; i < sizeof(mh_names)/sizeof(struct mh_name); i++) {
+		if (i && mh_names[i].type == mh_names[i-1].type)
+			printf(" (%s)", mh_names[i].name);
+		else
+			printf("\n%s", mh_names[i].name);
+	}
+	printf("\n");
+}
+
+static void mh_help(void)
+{
+	printf(
+"mh match options:\n"
+"[!] --mh-type type[:type]	match mh type\n");
+	print_types_all();
+}
+
+static void mh_init(struct xt_entry_match *m)
+{
+	struct ip6t_mh *mhinfo = (struct ip6t_mh *)m->data;
+
+	mhinfo->types[1] = 0xFF;
+}
+
+static unsigned int name_to_type(const char *name)
+{
+	int namelen = strlen(name);
+	unsigned int limit = sizeof(mh_names)/sizeof(struct mh_name);
+	unsigned int match = limit;
+	unsigned int i;
+
+	for (i = 0; i < limit; i++) {
+		if (strncasecmp(mh_names[i].name, name, namelen) == 0) {
+			int len = strlen(mh_names[i].name);
+			if (match == limit || len == namelen)
+				match = i;
+		}
+	}
+
+	if (match != limit) {
+		return mh_names[match].type;
+	} else {
+		unsigned int number;
+
+		if (!xtables_strtoui(name, NULL, &number, 0, UINT8_MAX))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Invalid MH type `%s'\n", name);
+		return number;
+	}
+}
+
+static void parse_mh_types(const char *mhtype, u_int8_t *types)
+{
+	char *buffer;
+	char *cp;
+
+	buffer = strdup(mhtype);
+	if ((cp = strchr(buffer, ':')) == NULL)
+		types[0] = types[1] = name_to_type(buffer);
+	else {
+		*cp = '\0';
+		cp++;
+
+		types[0] = buffer[0] ? name_to_type(buffer) : 0;
+		types[1] = cp[0] ? name_to_type(cp) : 0xFF;
+
+		if (types[0] > types[1])
+			xtables_error(PARAMETER_PROBLEM,
+				   "Invalid MH type range (min > max)");
+	}
+	free(buffer);
+}
+
+#define MH_TYPES 0x01
+
+static int mh_parse(int c, char **argv, int invert, unsigned int *flags,
+                    const void *entry, struct xt_entry_match **match)
+{
+	struct ip6t_mh *mhinfo = (struct ip6t_mh *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & MH_TYPES)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--mh-type' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_mh_types(argv[optind-1], mhinfo->types);
+		if (invert)
+			mhinfo->invflags |= IP6T_MH_INV_TYPE;
+		*flags |= MH_TYPES;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static const char *type_to_name(u_int8_t type)
+{
+	unsigned int i;
+
+	for (i = 0; i < sizeof(mh_names)/sizeof(struct mh_name); i++) {
+		if (mh_names[i].type == type)
+			return mh_names[i].name;
+	}
+
+	return NULL;
+}
+
+static void print_type(u_int8_t type, int numeric)
+{
+	const char *name;
+	if (numeric || !(name = type_to_name(type)))
+		printf("%u", type);
+	else
+		printf("%s", name);
+}
+
+static void print_types(u_int8_t min, u_int8_t max, int invert, int numeric)
+{
+	const char *inv = invert ? "!" : "";
+
+	if (min != 0 || max != 0xFF || invert) {
+		if (min == max) {
+			printf("%s", inv);
+			print_type(min, numeric);
+		} else {
+			printf("%s", inv);
+			print_type(min, numeric);
+			printf(":");
+			print_type(max, numeric);
+		}
+		printf(" ");
+	}
+}
+
+static void mh_print(const void *ip, const struct xt_entry_match *match,
+                     int numeric)
+{
+	const struct ip6t_mh *mhinfo = (struct ip6t_mh *)match->data;
+
+	printf("mh ");
+	print_types(mhinfo->types[0], mhinfo->types[1],
+		    mhinfo->invflags & IP6T_MH_INV_TYPE,
+		    numeric);
+	if (mhinfo->invflags & ~IP6T_MH_INV_MASK)
+		printf("Unknown invflags: 0x%X ",
+		       mhinfo->invflags & ~IP6T_MH_INV_MASK);
+}
+
+static void mh_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ip6t_mh *mhinfo = (struct ip6t_mh *)match->data;
+
+	if (mhinfo->types[0] == 0 && mhinfo->types[1] == 0xFF)
+		return;
+
+	if (mhinfo->invflags & IP6T_MH_INV_TYPE)
+		printf("! ");
+
+	if (mhinfo->types[0] != mhinfo->types[1])
+		printf("--mh-type %u:%u ", mhinfo->types[0], mhinfo->types[1]);
+	else
+		printf("--mh-type %u ", mhinfo->types[0]);
+}
+
+static const struct option mh_opts[] = {
+	{ "mh-type", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static struct xtables_match mh_mt6_reg = {
+	.name		= "mh",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV6,
+	.size		= XT_ALIGN(sizeof(struct ip6t_mh)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_mh)),
+	.help		= mh_help,
+	.init		= mh_init,
+	.parse		= mh_parse,
+	.print		= mh_print,
+	.save		= mh_save,
+	.extra_opts	= mh_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&mh_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_mh.man b/ap/app/iptables/extensions/libip6t_mh.man
new file mode 100755
index 0000000..4559e78
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_mh.man
@@ -0,0 +1,12 @@
+This extension is loaded if `\-\-protocol ipv6\-mh' or `\-\-protocol mh' is
+specified. It provides the following option:
+.TP
+[\fB!\fP] \fB\-\-mh\-type\fP \fItype\fP[\fB:\fP\fItype\fP]
+This allows specification of the Mobility Header(MH) type, which can be
+a numeric MH
+.IR type ,
+.IR type
+or one of the MH type names shown by the command
+.nf
+ ip6tables \-p ipv6\-mh \-h
+.fi
diff --git a/ap/app/iptables/extensions/libip6t_policy.c b/ap/app/iptables/extensions/libip6t_policy.c
new file mode 100755
index 0000000..5106c28
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_policy.c
@@ -0,0 +1,464 @@
+/* Shared library add-on to ip6tables to add policy support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <xtables.h>
+#include <libiptc/libip6tc.h>
+#include <linux/netfilter_ipv6/ip6t_policy.h>
+
+/*
+ * HACK: global pointer to current matchinfo for making
+ * final checks and adjustments in final_check.
+ */
+static struct ip6t_policy_info *policy_info;
+
+static void policy_help(void)
+{
+	printf(
+"policy match options:\n"
+"  --dir in|out			match policy applied during decapsulation/\n"
+"				policy to be applied during encapsulation\n"
+"  --pol none|ipsec		match policy\n"
+"  --strict 			match entire policy instead of single element\n"
+"				at any position\n"
+"[!] --reqid reqid		match reqid\n"
+"[!] --spi spi			match SPI\n"
+"[!] --proto proto		match protocol (ah/esp/ipcomp)\n"
+"[!] --mode mode 		match mode (transport/tunnel)\n"
+"[!] --tunnel-src addr/masklen	match tunnel source\n"
+"[!] --tunnel-dst addr/masklen	match tunnel destination\n"
+"  --next 			begin next element in policy\n");
+}
+
+static const struct option policy_opts[] =
+{
+	{
+		.name		= "dir",
+		.has_arg	= 1,
+		.val		= '1',
+	},
+	{
+		.name		= "pol",
+		.has_arg	= 1,
+		.val		= '2',
+	},
+	{
+		.name		= "strict",
+		.val		= '3'
+	},
+	{
+		.name		= "reqid",
+		.has_arg	= 1,
+		.val		= '4',
+	},
+	{
+		.name		= "spi",
+		.has_arg	= 1,
+		.val		= '5'
+	},
+	{
+		.name		= "tunnel-src",
+		.has_arg	= 1,
+		.val		= '6'
+	},
+	{
+		.name		= "tunnel-dst",
+		.has_arg	= 1,
+		.val		= '7'
+	},
+	{
+		.name		= "proto",
+		.has_arg	= 1,
+		.val		= '8'
+	},
+	{
+		.name		= "mode",
+		.has_arg	= 1,
+		.val		= '9'
+	},
+	{
+		.name		= "next",
+		.val		= 'a'
+	},
+	{ .name = NULL }
+};
+
+/* FIXME - Duplicated code from ip6tables.c */
+/* Duplicated to stop too many changes in other files .... */
+static void
+in6addrcpy(struct in6_addr *dst, struct in6_addr *src)
+{
+        memcpy(dst, src, sizeof(struct in6_addr));
+        /* dst->s6_addr = src->s6_addr; */
+}
+
+static char *
+addr_to_numeric(const struct in6_addr *addrp)
+{
+        /* 0000:0000:0000:0000:0000:000.000.000.000
+	 * 0000:0000:0000:0000:0000:0000:0000:0000 */
+        static char buf[50+1];
+        return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
+}
+
+static char *
+mask_to_numeric(const struct in6_addr *addrp)
+{
+        static char buf[50+2];
+        int l = ipv6_prefix_length(addrp);
+        if (l == -1) {
+		strcpy(buf, "/");
+		strcat(buf, addr_to_numeric(addrp));
+		return buf;
+	}
+	sprintf(buf, "/%d", l);
+	return buf;
+}
+
+static int parse_direction(char *s)
+{
+	if (strcmp(s, "in") == 0)
+		return IP6T_POLICY_MATCH_IN;
+	if (strcmp(s, "out") == 0)
+		return IP6T_POLICY_MATCH_OUT;
+	xtables_error(PARAMETER_PROBLEM, "policy_match: invalid dir \"%s\"", s);
+}
+
+static int parse_policy(char *s)
+{
+	if (strcmp(s, "none") == 0)
+		return IP6T_POLICY_MATCH_NONE;
+	if (strcmp(s, "ipsec") == 0)
+		return 0;
+	xtables_error(PARAMETER_PROBLEM, "policy match: invalid policy \"%s\"", s);
+}
+
+static int parse_mode(char *s)
+{
+	if (strcmp(s, "transport") == 0)
+		return IP6T_POLICY_MODE_TRANSPORT;
+	if (strcmp(s, "tunnel") == 0)
+		return IP6T_POLICY_MODE_TUNNEL;
+	xtables_error(PARAMETER_PROBLEM, "policy match: invalid mode \"%s\"", s);
+}
+
+static int policy_parse(int c, char **argv, int invert, unsigned int *flags,
+                        const void *entry, struct xt_entry_match **match)
+{
+	struct ip6t_policy_info *info = (void *)(*match)->data;
+	struct ip6t_policy_elem *e = &info->pol[info->len];
+	struct in6_addr *addr = NULL, mask;
+	unsigned int naddr = 0, num;
+	int mode;
+
+	xtables_check_inverse(optarg, &invert, &optind, 0);
+
+	switch (c) {
+	case '1':
+		if (info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --dir option");
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: can't invert --dir option");
+
+		info->flags |= parse_direction(argv[optind-1]);
+		break;
+	case '2':
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: can't invert --policy option");
+
+		info->flags |= parse_policy(argv[optind-1]);
+		break;
+	case '3':
+		if (info->flags & IP6T_POLICY_MATCH_STRICT)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --strict option");
+
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: can't invert --strict option");
+
+		info->flags |= IP6T_POLICY_MATCH_STRICT;
+		break;
+	case '4':
+		if (e->match.reqid)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --reqid option");
+
+		e->match.reqid = 1;
+		e->invert.reqid = invert;
+		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "policy", "--reqid", optarg);
+		e->reqid = num;
+		break;
+	case '5':
+		if (e->match.spi)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --spi option");
+
+		e->match.spi = 1;
+		e->invert.spi = invert;
+		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "policy", "--spi", optarg);
+		e->spi = num;
+		break;
+	case '6':
+		if (e->match.saddr)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --tunnel-src option");
+
+		xtables_ip6parse_any(argv[optind-1], &addr, &mask, &naddr);
+		if (naddr > 1)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: name resolves to multiple IPs");
+
+		e->match.saddr = 1;
+		e->invert.saddr = invert;
+		in6addrcpy(&e->saddr.a6, addr);
+		in6addrcpy(&e->smask.a6, &mask);
+                break;
+	case '7':
+		if (e->match.daddr)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --tunnel-dst option");
+
+		xtables_ip6parse_any(argv[optind-1], &addr, &mask, &naddr);
+		if (naddr > 1)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: name resolves to multiple IPs");
+
+		e->match.daddr = 1;
+		e->invert.daddr = invert;
+		in6addrcpy(&e->daddr.a6, addr);
+		in6addrcpy(&e->dmask.a6, &mask);
+		break;
+	case '8':
+		if (e->match.proto)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --proto option");
+
+		e->proto = xtables_parse_protocol(argv[optind-1]);
+		if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP &&
+		    e->proto != IPPROTO_COMP)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: protocol must ah/esp/ipcomp");
+		e->match.proto = 1;
+		e->invert.proto = invert;
+		break;
+	case '9':
+		if (e->match.mode)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --mode option");
+
+		mode = parse_mode(argv[optind-1]);
+		e->match.mode = 1;
+		e->invert.mode = invert;
+		e->mode = mode;
+		break;
+	case 'a':
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: can't invert --next option");
+
+		if (++info->len == IP6T_POLICY_MAX_ELEM)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: maximum policy depth reached");
+		break;
+	default:
+		return 0;
+	}
+
+	policy_info = info;
+	return 1;
+}
+
+static void policy_check(unsigned int flags)
+{
+	struct ip6t_policy_info *info = policy_info;
+	struct ip6t_policy_elem *e;
+	int i;
+
+	if (info == NULL)
+		xtables_error(PARAMETER_PROBLEM,
+		           "policy match: no parameters given");
+
+	if (!(info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT)))
+		xtables_error(PARAMETER_PROBLEM,
+		           "policy match: neither --in nor --out specified");
+
+	if (info->flags & IP6T_POLICY_MATCH_NONE) {
+		if (info->flags & IP6T_POLICY_MATCH_STRICT)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: policy none but --strict given");
+
+		if (info->len != 0)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: policy none but policy given");
+	} else
+		info->len++;	/* increase len by 1, no --next after last element */
+
+	if (!(info->flags & IP6T_POLICY_MATCH_STRICT) && info->len > 1)
+		xtables_error(PARAMETER_PROBLEM,
+		           "policy match: multiple elements but no --strict");
+
+	for (i = 0; i < info->len; i++) {
+		e = &info->pol[i];
+
+                if (info->flags & IP6T_POLICY_MATCH_STRICT &&
+		    !(e->match.reqid || e->match.spi || e->match.saddr ||
+                      e->match.daddr || e->match.proto || e->match.mode))
+			xtables_error(PARAMETER_PROBLEM,
+                                   "policy match: empty policy element");
+
+		if ((e->match.saddr || e->match.daddr)
+		    && ((e->mode == IP6T_POLICY_MODE_TUNNEL && e->invert.mode) ||
+		        (e->mode == IP6T_POLICY_MODE_TRANSPORT && !e->invert.mode)))
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: --tunnel-src/--tunnel-dst "
+			           "is only valid in tunnel mode");
+	}
+}
+
+static void print_mode(char *prefix, u_int8_t mode, int numeric)
+{
+	printf("%smode ", prefix);
+
+	switch (mode) {
+	case IP6T_POLICY_MODE_TRANSPORT:
+		printf("transport ");
+		break;
+	case IP6T_POLICY_MODE_TUNNEL:
+		printf("tunnel ");
+		break;
+	default:
+		printf("??? ");
+		break;
+	}
+}
+
+static void print_proto(char *prefix, u_int8_t proto, int numeric)
+{
+	struct protoent *p = NULL;
+
+	printf("%sproto ", prefix);
+	if (!numeric)
+		p = getprotobynumber(proto);
+	if (p != NULL)
+		printf("%s ", p->p_name);
+	else
+		printf("%u ", proto);
+}
+
+#define PRINT_INVERT(x)		\
+do {				\
+	if (x)			\
+		printf("! ");	\
+} while(0)
+
+static void print_entry(char *prefix, const struct ip6t_policy_elem *e,
+                        int numeric)
+{
+	if (e->match.reqid) {
+		PRINT_INVERT(e->invert.reqid);
+		printf("%sreqid %u ", prefix, e->reqid);
+	}
+	if (e->match.spi) {
+		PRINT_INVERT(e->invert.spi);
+		printf("%sspi 0x%x ", prefix, e->spi);
+	}
+	if (e->match.proto) {
+		PRINT_INVERT(e->invert.proto);
+		print_proto(prefix, e->proto, numeric);
+	}
+	if (e->match.mode) {
+		PRINT_INVERT(e->invert.mode);
+		print_mode(prefix, e->mode, numeric);
+	}
+	if (e->match.daddr) {
+		PRINT_INVERT(e->invert.daddr);
+		printf("%stunnel-dst %s%s ", prefix,
+		       addr_to_numeric((struct in6_addr *)&e->daddr),
+		       mask_to_numeric((struct in6_addr *)&e->dmask));
+	}
+	if (e->match.saddr) {
+		PRINT_INVERT(e->invert.saddr);
+		printf("%stunnel-src %s%s ", prefix,
+		       addr_to_numeric((struct in6_addr *)&e->saddr),
+		       mask_to_numeric((struct in6_addr *)&e->smask));
+	}
+}
+
+static void print_flags(char *prefix, const struct ip6t_policy_info *info)
+{
+	if (info->flags & IP6T_POLICY_MATCH_IN)
+		printf("%sdir in ", prefix);
+	else
+		printf("%sdir out ", prefix);
+
+	if (info->flags & IP6T_POLICY_MATCH_NONE)
+		printf("%spol none ", prefix);
+	else
+		printf("%spol ipsec ", prefix);
+
+	if (info->flags & IP6T_POLICY_MATCH_STRICT)
+		printf("%sstrict ", prefix);
+}
+
+static void policy_print(const void *ip, const struct xt_entry_match *match,
+                         int numeric)
+{
+	const struct ip6t_policy_info *info = (void *)match->data;
+	unsigned int i;
+
+	printf("policy match ");
+	print_flags("", info);
+	for (i = 0; i < info->len; i++) {
+		if (info->len > 1)
+			printf("[%u] ", i);
+		print_entry("", &info->pol[i], numeric);
+	}
+
+	printf("\n");
+}
+
+static void policy_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ip6t_policy_info *info = (void *)match->data;
+	unsigned int i;
+
+	print_flags("--", info);
+	for (i = 0; i < info->len; i++) {
+		print_entry("--", &info->pol[i], 0);
+		if (i + 1 < info->len)
+			printf("--next ");
+	}
+}
+
+static struct xtables_match policy_mt6_reg = {
+	.name		= "policy",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV6,
+	.size		= XT_ALIGN(sizeof(struct ip6t_policy_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_policy_info)),
+	.help		= policy_help,
+	.parse		= policy_parse,
+	.final_check	= policy_check,
+	.print		= policy_print,
+	.save		= policy_save,
+	.extra_opts	= policy_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&policy_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_rt.c b/ap/app/iptables/extensions/libip6t_rt.c
new file mode 100755
index 0000000..c9bf994
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_rt.c
@@ -0,0 +1,344 @@
+/* Shared library add-on to ip6tables to add Routing header support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <xtables.h>
+/*#include <linux/in6.h>*/
+#include <linux/netfilter_ipv6/ip6t_rt.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+/*#define DEBUG	1*/
+
+static void rt_help(void)
+{
+	printf(
+"rt match options:\n"
+"[!] --rt-type type             match the type\n"
+"[!] --rt-segsleft num[:num]    match the Segments Left field (range)\n"
+"[!] --rt-len length            total length of this header\n"
+" --rt-0-res                    check the reserved filed, too (type 0)\n"
+" --rt-0-addrs ADDR[,ADDR...]   Type=0 addresses (list, max: %d)\n"
+" --rt-0-not-strict             List of Type=0 addresses not a strict list\n",
+IP6T_RT_HOPS);
+}
+
+static const struct option rt_opts[] = {
+	{ "rt-type", 1, NULL, '1' },
+	{ "rt-segsleft", 1, NULL, '2' },
+	{ "rt-len", 1, NULL, '3' },
+	{ "rt-0-res", 0, NULL, '4' },
+	{ "rt-0-addrs", 1, NULL, '5' },
+	{ "rt-0-not-strict", 0, NULL, '6' },
+	{ .name = NULL }
+};
+
+static u_int32_t
+parse_rt_num(const char *idstr, const char *typestr)
+{
+	unsigned long int id;
+	char* ep;
+
+	id =  strtoul(idstr,&ep,0) ;
+
+	if ( idstr == ep ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "RT no valid digits in %s `%s'", typestr, idstr);
+	}
+	if ( id == ULONG_MAX  && errno == ERANGE ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "%s `%s' specified too big: would overflow",
+			   typestr, idstr);
+	}	
+	if ( *idstr != '\0'  && *ep != '\0' ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "RT error parsing %s `%s'", typestr, idstr);
+	}
+	return id;
+}
+
+static void
+parse_rt_segsleft(const char *idstring, u_int32_t *ids)
+{
+	char *buffer;
+	char *cp;
+
+	buffer = strdup(idstring);
+	if ((cp = strchr(buffer, ':')) == NULL)
+		ids[0] = ids[1] = parse_rt_num(buffer,"segsleft");
+	else {
+		*cp = '\0';
+		cp++;
+
+		ids[0] = buffer[0] ? parse_rt_num(buffer,"segsleft") : 0;
+		ids[1] = cp[0] ? parse_rt_num(cp,"segsleft") : 0xFFFFFFFF;
+	}
+	free(buffer);
+}
+
+static char *
+addr_to_numeric(const struct in6_addr *addrp)
+{
+	static char buf[50+1];
+	return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
+}
+
+static struct in6_addr *
+numeric_to_addr(const char *num)
+{
+	static struct in6_addr ap;
+	int err;
+
+	if ((err=inet_pton(AF_INET6, num, &ap)) == 1)
+		return &ap;
+#ifdef DEBUG
+	fprintf(stderr, "\nnumeric2addr: %d\n", err);
+#endif
+	xtables_error(PARAMETER_PROBLEM, "bad address: %s", num);
+
+	return (struct in6_addr *)NULL;
+}
+
+
+static int
+parse_addresses(const char *addrstr, struct in6_addr *addrp)
+{
+        char *buffer, *cp, *next;
+        unsigned int i;
+	
+	buffer = strdup(addrstr);
+	if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
+			
+        for (cp=buffer, i=0; cp && i<IP6T_RT_HOPS; cp=next,i++)
+        {
+                next=strchr(cp, ',');
+                if (next) *next++='\0';
+		memcpy(&(addrp[i]), numeric_to_addr(cp), sizeof(struct in6_addr));
+#if DEBUG
+		printf("addr str: %s\n", cp);
+		printf("addr ip6: %s\n", addr_to_numeric((numeric_to_addr(cp))));
+		printf("addr [%d]: %s\n", i, addr_to_numeric(&(addrp[i])));
+#endif
+	}
+	if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
+
+	free(buffer);
+
+#if DEBUG
+	printf("addr nr: %d\n", i);
+#endif
+
+	return i;
+}
+
+static void rt_init(struct xt_entry_match *m)
+{
+	struct ip6t_rt *rtinfo = (struct ip6t_rt *)m->data;
+
+	rtinfo->rt_type = 0x0L;
+	rtinfo->segsleft[0] = 0x0L;
+	rtinfo->segsleft[1] = 0xFFFFFFFF;
+	rtinfo->hdrlen = 0;
+	rtinfo->flags = 0;
+	rtinfo->invflags = 0;
+	rtinfo->addrnr = 0;
+}
+
+static int rt_parse(int c, char **argv, int invert, unsigned int *flags,
+                    const void *entry, struct xt_entry_match **match)
+{
+	struct ip6t_rt *rtinfo = (struct ip6t_rt *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & IP6T_RT_TYP)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--rt-type' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		rtinfo->rt_type = parse_rt_num(argv[optind-1], "type");
+		if (invert)
+			rtinfo->invflags |= IP6T_RT_INV_TYP;
+		rtinfo->flags |= IP6T_RT_TYP;
+		*flags |= IP6T_RT_TYP;
+		break;
+	case '2':
+		if (*flags & IP6T_RT_SGS)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--rt-segsleft' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_rt_segsleft(argv[optind-1], rtinfo->segsleft);
+		if (invert)
+			rtinfo->invflags |= IP6T_RT_INV_SGS;
+		rtinfo->flags |= IP6T_RT_SGS;
+		*flags |= IP6T_RT_SGS;
+		break;
+	case '3':
+		if (*flags & IP6T_RT_LEN)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--rt-len' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		rtinfo->hdrlen = parse_rt_num(argv[optind-1], "length");
+		if (invert)
+			rtinfo->invflags |= IP6T_RT_INV_LEN;
+		rtinfo->flags |= IP6T_RT_LEN;
+		*flags |= IP6T_RT_LEN;
+		break;
+	case '4':
+		if (*flags & IP6T_RT_RES)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--rt-0-res' allowed");
+		if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) )
+			xtables_error(PARAMETER_PROBLEM,
+				   "`--rt-type 0' required before `--rt-0-res'");
+		rtinfo->flags |= IP6T_RT_RES;
+		*flags |= IP6T_RT_RES;
+		break;
+	case '5':
+		if (*flags & IP6T_RT_FST)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--rt-0-addrs' allowed");
+		if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) )
+			xtables_error(PARAMETER_PROBLEM,
+				   "`--rt-type 0' required before `--rt-0-addrs'");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+				   " '!' not allowed with `--rt-0-addrs'");
+		rtinfo->addrnr = parse_addresses(argv[optind-1], rtinfo->addrs);
+		rtinfo->flags |= IP6T_RT_FST;
+		*flags |= IP6T_RT_FST;
+		break;
+	case '6':
+		if (*flags & IP6T_RT_FST_NSTRICT)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--rt-0-not-strict' allowed");
+		if ( !(*flags & IP6T_RT_FST) )
+			xtables_error(PARAMETER_PROBLEM,
+				   "`--rt-0-addr ...' required before `--rt-0-not-strict'");
+		rtinfo->flags |= IP6T_RT_FST_NSTRICT;
+		*flags |= IP6T_RT_FST_NSTRICT;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+print_nums(const char *name, u_int32_t min, u_int32_t max,
+	    int invert)
+{
+	const char *inv = invert ? "!" : "";
+
+	if (min != 0 || max != 0xFFFFFFFF || invert) {
+		printf("%s", name);
+		if (min == max) {
+			printf(":%s", inv);
+			printf("%u", min);
+		} else {
+			printf("s:%s", inv);
+			printf("%u",min);
+			printf(":");
+			printf("%u",max);
+		}
+		printf(" ");
+	}
+}
+
+static void
+print_addresses(unsigned int addrnr, struct in6_addr *addrp)
+{
+	unsigned int i;
+
+	for(i=0; i<addrnr; i++){
+		printf("%s%c", addr_to_numeric(&(addrp[i])), (i!=addrnr-1)?',':' ');
+	}
+}
+
+static void rt_print(const void *ip, const struct xt_entry_match *match,
+                     int numeric)
+{
+	const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
+
+	printf("rt ");
+	if (rtinfo->flags & IP6T_RT_TYP)
+	    printf("type:%s%d ", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "",
+		    rtinfo->rt_type);
+	print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1],
+		    rtinfo->invflags & IP6T_RT_INV_SGS);
+	if (rtinfo->flags & IP6T_RT_LEN) {
+		printf("length");
+		printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : "");
+		printf("%u", rtinfo->hdrlen);
+		printf(" ");
+	}
+	if (rtinfo->flags & IP6T_RT_RES) printf("reserved ");
+	if (rtinfo->flags & IP6T_RT_FST) printf("0-addrs ");
+	print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
+	if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("0-not-strict ");
+	if (rtinfo->invflags & ~IP6T_RT_INV_MASK)
+		printf("Unknown invflags: 0x%X ",
+		       rtinfo->invflags & ~IP6T_RT_INV_MASK);
+}
+
+static void rt_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
+
+	if (rtinfo->flags & IP6T_RT_TYP) {
+		printf("%s--rt-type %u ", 
+			(rtinfo->invflags & IP6T_RT_INV_TYP) ? "! " : "", 
+			rtinfo->rt_type);
+	}
+
+	if (!(rtinfo->segsleft[0] == 0
+	    && rtinfo->segsleft[1] == 0xFFFFFFFF)) {
+		printf("%s--rt-segsleft ",
+			(rtinfo->invflags & IP6T_RT_INV_SGS) ? "! " : "");
+		if (rtinfo->segsleft[0]
+		    != rtinfo->segsleft[1])
+			printf("%u:%u ",
+			       rtinfo->segsleft[0],
+			       rtinfo->segsleft[1]);
+		else
+			printf("%u ",
+			       rtinfo->segsleft[0]);
+	}
+
+	if (rtinfo->flags & IP6T_RT_LEN) {
+		printf("%s--rt-len %u ",
+			(rtinfo->invflags & IP6T_RT_INV_LEN) ? "! " : "", 
+			rtinfo->hdrlen);
+	}
+
+	if (rtinfo->flags & IP6T_RT_RES) printf("--rt-0-res ");
+	if (rtinfo->flags & IP6T_RT_FST) printf("--rt-0-addrs ");
+	print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
+	if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("--rt-0-not-strict ");
+
+}
+
+static struct xtables_match rt_mt6_reg = {
+	.name		= "rt",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV6,
+	.size		= XT_ALIGN(sizeof(struct ip6t_rt)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ip6t_rt)),
+	.help		= rt_help,
+	.init		= rt_init,
+	.parse		= rt_parse,
+	.print		= rt_print,
+	.save		= rt_save,
+	.extra_opts	= rt_opts,
+};
+
+void
+_init(void)
+{
+	xtables_register_match(&rt_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libip6t_rt.man b/ap/app/iptables/extensions/libip6t_rt.man
new file mode 100755
index 0000000..0443e0a
--- /dev/null
+++ b/ap/app/iptables/extensions/libip6t_rt.man
@@ -0,0 +1,19 @@
+Match on IPv6 routing header
+.TP
+[\fB!\fP] \fB\-\-rt\-type\fP \fItype\fP
+Match the type (numeric).
+.TP
+[\fB!\fP] \fB\-\-rt\-segsleft\fP \fInum\fP[\fB:\fP\fInum\fP]
+Match the `segments left' field (range).
+.TP
+[\fB!\fP] \fB\-\-rt\-len\fP \fIlength\fP
+Match the length of this header.
+.TP
+\fB\-\-rt\-0\-res\fP
+Match the reserved field, too (type=0)
+.TP
+\fB\-\-rt\-0\-addrs\fP \fIaddr\fP[\fB,\fP\fIaddr\fP...]
+Match type=0 addresses (list).
+.TP
+\fB\-\-rt\-0\-not\-strict\fP
+List of type=0 addresses is not a strict list.
diff --git a/ap/app/iptables/extensions/libipt_CLUSTERIP.c b/ap/app/iptables/extensions/libipt_CLUSTERIP.c
new file mode 100755
index 0000000..279aacf
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_CLUSTERIP.c
@@ -0,0 +1,249 @@
+/* Shared library add-on to iptables to add CLUSTERIP target support. 
+ * (C) 2003 by Harald Welte <laforge@gnumonks.org>
+ *
+ * Development of this code was funded by SuSE AG, http://www.suse.com/
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <stddef.h>
+
+#if defined(__GLIBC__) && __GLIBC__ == 2
+#include <net/ethernet.h>
+#else
+#include <linux/if_ether.h>
+#endif
+
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
+
+static void CLUSTERIP_help(void)
+{
+	printf(
+"CLUSTERIP target options:\n"
+"  --new			 Create a new ClusterIP\n"
+"  --hashmode <mode>		 Specify hashing mode\n"
+"					sourceip\n"
+"					sourceip-sourceport\n"
+"					sourceip-sourceport-destport\n"
+"  --clustermac <mac>		 Set clusterIP MAC address\n"
+"  --total-nodes <num>		 Set number of total nodes in cluster\n"
+"  --local-node <num>		 Set the local node number\n"
+"  --hash-init <num>		 Set init value of the Jenkins hash\n");
+}
+
+#define	PARAM_NEW	0x0001
+#define PARAM_HMODE	0x0002
+#define PARAM_MAC	0x0004
+#define PARAM_TOTALNODE	0x0008
+#define PARAM_LOCALNODE	0x0010
+#define PARAM_HASHINIT	0x0020
+
+static const struct option CLUSTERIP_opts[] = {
+	{ "new", 0, NULL, '1' },
+	{ "hashmode", 1, NULL, '2' },
+	{ "clustermac", 1, NULL, '3' },
+	{ "total-nodes", 1, NULL, '4' },
+	{ "local-node", 1, NULL, '5' },
+	{ "hash-init", 1, NULL, '6' },
+	{ .name = NULL }
+};
+
+static void
+parse_mac(const char *mac, char *macbuf)
+{
+	unsigned int i = 0;
+
+	if (strlen(mac) != ETH_ALEN*3-1)
+		xtables_error(PARAMETER_PROBLEM, "Bad mac address \"%s\"", mac);
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		long number;
+		char *end;
+
+		number = strtol(mac + i*3, &end, 16);
+
+		if (end == mac + i*3 + 2
+		    && number >= 0
+		    && number <= 255)
+			macbuf[i] = number;
+		else
+			xtables_error(PARAMETER_PROBLEM,
+				   "Bad mac address `%s'", mac);
+	}
+}
+
+static int CLUSTERIP_parse(int c, char **argv, int invert, unsigned int *flags,
+                           const void *entry, struct xt_entry_target **target)
+{
+	struct ipt_clusterip_tgt_info *cipinfo
+		= (struct ipt_clusterip_tgt_info *)(*target)->data;
+
+	switch (c) {
+		unsigned int num;
+	case '1':
+		cipinfo->flags |= CLUSTERIP_FLAG_NEW;
+		if (*flags & PARAM_NEW)
+			xtables_error(PARAMETER_PROBLEM, "Can only specify \"--new\" once\n");
+		*flags |= PARAM_NEW;
+		break;
+	case '2':
+		if (!(*flags & PARAM_NEW))
+			xtables_error(PARAMETER_PROBLEM, "Can only specify hashmode combined with \"--new\"\n");
+		if (*flags & PARAM_HMODE)
+			xtables_error(PARAMETER_PROBLEM, "Can only specify hashmode once\n");
+		if (!strcmp(optarg, "sourceip"))
+			cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP;
+		else if (!strcmp(optarg, "sourceip-sourceport"))
+			cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT;
+		else if (!strcmp(optarg, "sourceip-sourceport-destport"))
+			cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT_DPT;
+		else
+			xtables_error(PARAMETER_PROBLEM, "Unknown hashmode \"%s\"\n",
+				   optarg);
+		*flags |= PARAM_HMODE;
+		break;
+	case '3':
+		if (!(*flags & PARAM_NEW))
+			xtables_error(PARAMETER_PROBLEM, "Can only specify MAC combined with \"--new\"\n");
+		if (*flags & PARAM_MAC)
+			xtables_error(PARAMETER_PROBLEM, "Can only specify MAC once\n");
+		parse_mac(optarg, (char *)cipinfo->clustermac);
+		if (!(cipinfo->clustermac[0] & 0x01))
+			xtables_error(PARAMETER_PROBLEM, "MAC has to be a multicast ethernet address\n");
+		*flags |= PARAM_MAC;
+		break;
+	case '4':
+		if (!(*flags & PARAM_NEW))
+			xtables_error(PARAMETER_PROBLEM, "Can only specify node number combined with \"--new\"\n");
+		if (*flags & PARAM_TOTALNODE)
+			xtables_error(PARAMETER_PROBLEM, "Can only specify total node number once\n");
+		if (!xtables_strtoui(optarg, NULL, &num, 1, CLUSTERIP_MAX_NODES))
+			xtables_error(PARAMETER_PROBLEM, "Unable to parse \"%s\"\n", optarg);
+		cipinfo->num_total_nodes = num;
+		*flags |= PARAM_TOTALNODE;
+		break;
+	case '5':
+		if (!(*flags & PARAM_NEW))
+			xtables_error(PARAMETER_PROBLEM, "Can only specify node number combined with \"--new\"\n");
+		if (*flags & PARAM_LOCALNODE)
+			xtables_error(PARAMETER_PROBLEM, "Can only specify local node number once\n");
+		if (!xtables_strtoui(optarg, NULL, &num, 1, CLUSTERIP_MAX_NODES))
+			xtables_error(PARAMETER_PROBLEM, "Unable to parse \"%s\"\n", optarg);
+		cipinfo->num_local_nodes = 1;
+		cipinfo->local_nodes[0] = num;
+		*flags |= PARAM_LOCALNODE;
+		break;
+	case '6':
+		if (!(*flags & PARAM_NEW))
+			xtables_error(PARAMETER_PROBLEM, "Can only specify hash init value combined with \"--new\"\n");
+		if (*flags & PARAM_HASHINIT)
+			xtables_error(PARAMETER_PROBLEM, "Can specify hash init value only once\n");
+		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT_MAX))
+			xtables_error(PARAMETER_PROBLEM, "Unable to parse \"%s\"\n", optarg);
+		cipinfo->hash_initval = num;
+		*flags |= PARAM_HASHINIT;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void CLUSTERIP_check(unsigned int flags)
+{
+	if (flags == 0)
+		return;
+
+	if ((flags & (PARAM_NEW|PARAM_HMODE|PARAM_MAC|PARAM_TOTALNODE|PARAM_LOCALNODE))
+		== (PARAM_NEW|PARAM_HMODE|PARAM_MAC|PARAM_TOTALNODE|PARAM_LOCALNODE))
+		return;
+
+	xtables_error(PARAMETER_PROBLEM, "CLUSTERIP target: Invalid parameter combination\n");
+}
+
+static char *hashmode2str(enum clusterip_hashmode mode)
+{
+	char *retstr;
+	switch (mode) {
+		case CLUSTERIP_HASHMODE_SIP:
+			retstr = "sourceip";
+			break;
+		case CLUSTERIP_HASHMODE_SIP_SPT:
+			retstr = "sourceip-sourceport";
+			break;
+		case CLUSTERIP_HASHMODE_SIP_SPT_DPT:
+			retstr = "sourceip-sourceport-destport";
+			break;
+		default:
+			retstr = "unknown-error";
+			break;
+	}
+	return retstr;
+}
+
+static char *mac2str(const u_int8_t mac[ETH_ALEN])
+{
+	static char buf[ETH_ALEN*3];
+	sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
+		mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+	return buf;
+}
+
+static void CLUSTERIP_print(const void *ip,
+                            const struct xt_entry_target *target, int numeric)
+{
+	const struct ipt_clusterip_tgt_info *cipinfo =
+		(const struct ipt_clusterip_tgt_info *)target->data;
+	
+	if (!cipinfo->flags & CLUSTERIP_FLAG_NEW) {
+		printf("CLUSTERIP");
+		return;
+	}
+
+	printf("CLUSTERIP hashmode=%s clustermac=%s total_nodes=%u local_node=%u hash_init=%u", 
+		hashmode2str(cipinfo->hash_mode),
+		mac2str(cipinfo->clustermac),
+		cipinfo->num_total_nodes,
+		cipinfo->local_nodes[0],
+		cipinfo->hash_initval);
+}
+
+static void CLUSTERIP_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct ipt_clusterip_tgt_info *cipinfo =
+		(const struct ipt_clusterip_tgt_info *)target->data;
+
+	/* if this is not a new entry, we don't need to save target
+	 * parameters */
+	if (!cipinfo->flags & CLUSTERIP_FLAG_NEW)
+		return;
+
+	printf("--new --hashmode %s --clustermac %s --total-nodes %d --local-node %d --hash-init %u",
+	       hashmode2str(cipinfo->hash_mode),
+	       mac2str(cipinfo->clustermac),
+	       cipinfo->num_total_nodes,
+	       cipinfo->local_nodes[0],
+	       cipinfo->hash_initval);
+}
+
+static struct xtables_target clusterip_tg_reg = {
+	.name		= "CLUSTERIP",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct ipt_clusterip_tgt_info)),
+	.userspacesize	= offsetof(struct ipt_clusterip_tgt_info, config),
+ 	.help		= CLUSTERIP_help,
+	.parse		= CLUSTERIP_parse,
+	.final_check	= CLUSTERIP_check,
+	.print		= CLUSTERIP_print,
+	.save		= CLUSTERIP_save,
+	.extra_opts	= CLUSTERIP_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&clusterip_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_CLUSTERIP.man b/ap/app/iptables/extensions/libipt_CLUSTERIP.man
new file mode 100755
index 0000000..8ec6d6b
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_CLUSTERIP.man
@@ -0,0 +1,24 @@
+This module allows you to configure a simple cluster of nodes that share
+a certain IP and MAC address without an explicit load balancer in front of
+them.  Connections are statically distributed between the nodes in this
+cluster.
+.TP
+\fB\-\-new\fP
+Create a new ClusterIP.  You always have to set this on the first rule
+for a given ClusterIP.
+.TP
+\fB\-\-hashmode\fP \fImode\fP
+Specify the hashing mode.  Has to be one of
+\fBsourceip\fP, \fBsourceip\-sourceport\fP, \fBsourceip\-sourceport\-destport\fP.
+.TP
+\fB\-\-clustermac\fP \fImac\fP
+Specify the ClusterIP MAC address. Has to be a link\-layer multicast address
+.TP
+\fB\-\-total\-nodes\fP \fInum\fP
+Number of total nodes within this cluster.
+.TP
+\fB\-\-local\-node\fP \fInum\fP
+Local node number within this cluster.
+.TP
+\fB\-\-hash\-init\fP \fIrnd\fP
+Specify the random seed used for hash initialization.
diff --git a/ap/app/iptables/extensions/libipt_CONNLOG.c b/ap/app/iptables/extensions/libipt_CONNLOG.c
new file mode 100755
index 0000000..0b4e5ff
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_CONNLOG.c
@@ -0,0 +1,100 @@
+/* Shared library add-on to iptables to add CONNLOG target support. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ipt_CONNLOG.h>
+
+static void
+help(void)
+{
+	printf(
+"CONNLOG target options:\n"
+"  --confirm       Log confirm events\n"
+"  --destroy       Log destroy events\n");
+}
+
+static struct option opts[] = {
+	{ "confirm", 0, 0, '1' },
+	{ "destroy", 0, 0, '2' },
+	{ .name = NULL }
+};
+
+static void
+init(struct xt_entry_target *t)
+{
+}
+
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const void *entry,
+      struct xt_entry_target **target)
+{
+	struct ipt_connlog_target_info *loginfo
+		= (struct ipt_connlog_target_info *)(*target)->data;
+
+	switch (c) {
+	case '1':
+		loginfo->events |= IPT_CONNLOG_CONFIRM;
+		break;
+	case '2':
+		loginfo->events |= IPT_CONNLOG_DESTROY;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+final_check(unsigned int flags)
+{
+}
+
+static void
+print(const void *ip,
+      const struct xt_entry_target *target,
+      int numeric)
+{
+	const struct ipt_connlog_target_info *loginfo =
+		(const struct ipt_connlog_target_info *)target->data;
+
+	printf("CONNLOG");
+	if (loginfo->events & IPT_CONNLOG_CONFIRM)
+		printf(" confirm");
+	if (loginfo->events & IPT_CONNLOG_DESTROY)
+		printf(" destroy");
+}
+
+static void
+save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct ipt_connlog_target_info *loginfo =
+		(const struct ipt_connlog_target_info *)target->data;
+
+	if (loginfo->events & IPT_CONNLOG_CONFIRM)
+		printf("--confirm ");
+	if (loginfo->events & IPT_CONNLOG_DESTROY)
+		printf("--destroy ");
+}
+
+static struct xtables_target connlog_target = {
+    .name          = "CONNLOG",
+    .version       = XTABLES_VERSION,
+    .family        = NFPROTO_IPV4,
+    .size          = XT_ALIGN(sizeof(struct ipt_connlog_target_info)),
+    .userspacesize = XT_ALIGN(sizeof(struct ipt_connlog_target_info)),
+    .help          = &help,
+    .init          = &init,
+    .parse         = &parse,
+    .final_check   = &final_check,
+    .print         = &print,
+    .save          = &save,
+    .extra_opts    = opts
+};
+
+void _init(void)
+{
+	xtables_register_target(&connlog_target);
+}
diff --git a/ap/app/iptables/extensions/libipt_DNAT.c b/ap/app/iptables/extensions/libipt_DNAT.c
new file mode 100755
index 0000000..b5f8028
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_DNAT.c
@@ -0,0 +1,259 @@
+/* Shared library add-on to iptables to add destination-NAT support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <iptables.h> /* get_kernel_version */
+#include <limits.h> /* INT_MAX in ip_tables.h */
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <net/netfilter/nf_nat.h>
+
+#define IPT_DNAT_OPT_DEST 0x1
+#define IPT_DNAT_OPT_RANDOM 0x2
+
+/* Dest NAT data consists of a multi-range, indicating where to map
+   to. */
+struct ipt_natinfo
+{
+	struct xt_entry_target t;
+	struct nf_nat_multi_range mr;
+};
+
+static void DNAT_help(void)
+{
+	printf(
+"DNAT target options:\n"
+" --to-destination <ipaddr>[-<ipaddr>][:port-port]\n"
+"				Address to map destination to.\n"
+"[--random]\n");
+}
+
+static const struct option DNAT_opts[] = {
+	{ "to-destination", 1, NULL, '1' },
+	{ "random", 0, NULL, '2' },
+	{ .name = NULL }
+};
+
+static struct ipt_natinfo *
+append_range(struct ipt_natinfo *info, const struct nf_nat_range *range)
+{
+	unsigned int size;
+
+	/* One rangesize already in struct ipt_natinfo */
+	size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
+
+	info = realloc(info, size);
+	if (!info)
+		xtables_error(OTHER_PROBLEM, "Out of memory\n");
+
+	info->t.u.target_size = size;
+	info->mr.range[info->mr.rangesize] = *range;
+	info->mr.rangesize++;
+
+	return info;
+}
+
+/* Ranges expected in network order. */
+static struct xt_entry_target *
+parse_to(char *arg, int portok, struct ipt_natinfo *info)
+{
+	struct nf_nat_range range;
+	char *colon, *dash, *error;
+	const struct in_addr *ip;
+
+	memset(&range, 0, sizeof(range));
+	colon = strchr(arg, ':');
+
+	if (colon) {
+		int port;
+
+		if (!portok)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Need TCP, UDP, SCTP or DCCP with port specification");
+
+		range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+		port = atoi(colon+1);
+		if (port <= 0 || port > 65535)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Port `%s' not valid\n", colon+1);
+
+		error = strchr(colon+1, ':');
+		if (error)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Invalid port:port syntax - use dash\n");
+
+		dash = strchr(colon, '-');
+		if (!dash) {
+			range.min.tcp.port
+				= range.max.tcp.port
+				= htons(port);
+		} else {
+			int maxport;
+
+			maxport = atoi(dash + 1);
+			if (maxport <= 0 || maxport > 65535)
+				xtables_error(PARAMETER_PROBLEM,
+					   "Port `%s' not valid\n", dash+1);
+			if (maxport < port)
+				/* People are stupid. */
+				xtables_error(PARAMETER_PROBLEM,
+					   "Port range `%s' funky\n", colon+1);
+			range.min.tcp.port = htons(port);
+			range.max.tcp.port = htons(maxport);
+		}
+		/* Starts with a colon? No IP info...*/
+		if (colon == arg)
+			return &(append_range(info, &range)->t);
+		*colon = '\0';
+	}
+
+	range.flags |= IP_NAT_RANGE_MAP_IPS;
+	dash = strchr(arg, '-');
+	if (colon && dash && dash > colon)
+		dash = NULL;
+
+	if (dash)
+		*dash = '\0';
+
+	ip = xtables_numeric_to_ipaddr(arg);
+	if (!ip)
+		xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
+			   arg);
+	range.min_ip = ip->s_addr;
+	if (dash) {
+		ip = xtables_numeric_to_ipaddr(dash+1);
+		if (!ip)
+			xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
+				   dash+1);
+		range.max_ip = ip->s_addr;
+	} else
+		range.max_ip = range.min_ip;
+
+	return &(append_range(info, &range)->t);
+}
+
+static int DNAT_parse(int c, char **argv, int invert, unsigned int *flags,
+                      const void *e, struct xt_entry_target **target)
+{
+	const struct ipt_entry *entry = e;
+	struct ipt_natinfo *info = (void *)*target;
+	int portok;
+
+	if (entry->ip.proto == IPPROTO_TCP
+	    || entry->ip.proto == IPPROTO_UDP
+	    || entry->ip.proto == IPPROTO_SCTP
+	    || entry->ip.proto == IPPROTO_DCCP
+	    || entry->ip.proto == IPPROTO_ICMP)
+		portok = 1;
+	else
+		portok = 0;
+
+	switch (c) {
+	case '1':
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --to-destination");
+
+		if (*flags) {
+			if (!kernel_version)
+				get_kernel_version();
+			if (kernel_version > LINUX_VERSION(2, 6, 10))
+				xtables_error(PARAMETER_PROBLEM,
+					   "Multiple --to-destination not supported");
+		}
+		*target = parse_to(optarg, portok, info);
+		/* WTF do we need this for?? */
+		if (*flags & IPT_DNAT_OPT_RANDOM)
+			info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
+		*flags |= IPT_DNAT_OPT_DEST;
+		return 1;
+
+	case '2':
+		if (*flags & IPT_DNAT_OPT_DEST) {
+			info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
+			*flags |= IPT_DNAT_OPT_RANDOM;
+		} else
+			*flags |= IPT_DNAT_OPT_RANDOM;
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static void DNAT_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "You must specify --to-destination");
+}
+
+static void print_range(const struct nf_nat_range *r)
+{
+	if (r->flags & IP_NAT_RANGE_MAP_IPS) {
+		struct in_addr a;
+
+		a.s_addr = r->min_ip;
+		printf("%s", xtables_ipaddr_to_numeric(&a));
+		if (r->max_ip != r->min_ip) {
+			a.s_addr = r->max_ip;
+			printf("-%s", xtables_ipaddr_to_numeric(&a));
+		}
+	}
+	if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+		printf(":");
+		printf("%hu", ntohs(r->min.tcp.port));
+		if (r->max.tcp.port != r->min.tcp.port)
+			printf("-%hu", ntohs(r->max.tcp.port));
+	}
+}
+
+static void DNAT_print(const void *ip, const struct xt_entry_target *target,
+                       int numeric)
+{
+	struct ipt_natinfo *info = (void *)target;
+	unsigned int i = 0;
+
+	printf("to:");
+	for (i = 0; i < info->mr.rangesize; i++) {
+		print_range(&info->mr.range[i]);
+		printf(" ");
+		if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM)
+			printf("random ");
+	}
+}
+
+static void DNAT_save(const void *ip, const struct xt_entry_target *target)
+{
+	struct ipt_natinfo *info = (void *)target;
+	unsigned int i = 0;
+
+	for (i = 0; i < info->mr.rangesize; i++) {
+		printf("--to-destination ");
+		print_range(&info->mr.range[i]);
+		printf(" ");
+		if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM)
+			printf("--random ");
+	}
+}
+
+static struct xtables_target dnat_tg_reg = {
+	.name		= "DNAT",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct nf_nat_multi_range)),
+	.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_multi_range)),
+	.help		= DNAT_help,
+	.parse		= DNAT_parse,
+	.final_check	= DNAT_check,
+	.print		= DNAT_print,
+	.save		= DNAT_save,
+	.extra_opts	= DNAT_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&dnat_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_DNAT.man b/ap/app/iptables/extensions/libipt_DNAT.man
new file mode 100755
index 0000000..22e84c6
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_DNAT.man
@@ -0,0 +1,36 @@
+This target is only valid in the
+.B nat
+table, in the
+.B PREROUTING
+and
+.B OUTPUT
+chains, and user-defined chains which are only called from those
+chains.  It specifies that the destination address of the packet
+should be modified (and all future packets in this connection will
+also be mangled), and rules should cease being examined.  It takes one
+type of option:
+.TP
+\fB\-\-to\-destination\fP [\fIipaddr\fP][\fB\-\fP\fIipaddr\fP][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP]]
+which can specify a single new destination IP address, an inclusive
+range of IP addresses, and optionally, a port range (which is only
+valid if the rule also specifies
+\fB\-p tcp\fP
+or
+\fB\-p udp\fP).
+If no port range is specified, then the destination port will never be
+modified. If no IP address is specified then only the destination port
+will be modified.
+
+In Kernels up to 2.6.10 you can add several \-\-to\-destination options. For
+those kernels, if you specify more than one destination address, either via an
+address range or multiple \-\-to\-destination options, a simple round-robin (one
+after another in cycle) load balancing takes place between these addresses.
+Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges
+anymore.
+.TP
+\fB\-\-random\fP
+If option
+\fB\-\-random\fP
+is used then port mapping will be randomized (kernel >= 2.6.22).
+.RS
+.PP
diff --git a/ap/app/iptables/extensions/libipt_ECN.c b/ap/app/iptables/extensions/libipt_ECN.c
new file mode 100755
index 0000000..bf1f8a5
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_ECN.c
@@ -0,0 +1,169 @@
+/* Shared library add-on to iptables for ECN, $Version$
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This program is distributed under the terms of GNU GPL v2, 1991
+ *
+ * libipt_ECN.c borrowed heavily from libipt_DSCP.c
+ *
+ * $Id$
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ipt_ECN.h>
+
+static void ECN_help(void)
+{
+	printf(
+"ECN target options\n"
+"  --ecn-tcp-remove		Remove all ECN bits from TCP header\n");
+}
+
+#if 0
+"ECN target v%s EXPERIMENTAL options (use with extreme care!)\n"
+"  --ecn-ip-ect			Set the IPv4 ECT codepoint (0 to 3)\n"
+"  --ecn-tcp-cwr		Set the IPv4 CWR bit (0 or 1)\n"
+"  --ecn-tcp-ece		Set the IPv4 ECE bit (0 or 1)\n",
+#endif
+
+
+static const struct option ECN_opts[] = {
+	{ "ecn-tcp-remove", 0, NULL, 'F' },
+	{ "ecn-tcp-cwr", 1, NULL, 'G' },
+	{ "ecn-tcp-ece", 1, NULL, 'H' },
+	{ "ecn-ip-ect", 1, NULL, '9' },
+	{ .name = NULL }
+};
+
+static int ECN_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_target **target)
+{
+	unsigned int result;
+	struct ipt_ECN_info *einfo
+		= (struct ipt_ECN_info *)(*target)->data;
+
+	switch (c) {
+	case 'F':
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+			        "ECN target: Only use --ecn-tcp-remove ONCE!");
+		einfo->operation = IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR;
+		einfo->proto.tcp.ece = 0;
+		einfo->proto.tcp.cwr = 0;
+		*flags = 1;
+		break;
+	case 'G':
+		if (*flags & IPT_ECN_OP_SET_CWR)
+			xtables_error(PARAMETER_PROBLEM,
+				"ECN target: Only use --ecn-tcp-cwr ONCE!");
+		if (!xtables_strtoui(optarg, NULL, &result, 0, 1))
+			xtables_error(PARAMETER_PROBLEM,
+				   "ECN target: Value out of range");
+		einfo->operation |= IPT_ECN_OP_SET_CWR;
+		einfo->proto.tcp.cwr = result;
+		*flags |= IPT_ECN_OP_SET_CWR;
+		break;
+	case 'H':
+		if (*flags & IPT_ECN_OP_SET_ECE)
+			xtables_error(PARAMETER_PROBLEM,
+				"ECN target: Only use --ecn-tcp-ece ONCE!");
+		if (!xtables_strtoui(optarg, NULL, &result, 0, 1))
+			xtables_error(PARAMETER_PROBLEM,
+				   "ECN target: Value out of range");
+		einfo->operation |= IPT_ECN_OP_SET_ECE;
+		einfo->proto.tcp.ece = result;
+		*flags |= IPT_ECN_OP_SET_ECE;
+		break;
+	case '9':
+		if (*flags & IPT_ECN_OP_SET_IP)
+			xtables_error(PARAMETER_PROBLEM,
+				"ECN target: Only use --ecn-ip-ect ONCE!");
+		if (!xtables_strtoui(optarg, NULL, &result, 0, 3))
+			xtables_error(PARAMETER_PROBLEM,
+				   "ECN target: Value out of range");
+		einfo->operation |= IPT_ECN_OP_SET_IP;
+		einfo->ip_ect = result;
+		*flags |= IPT_ECN_OP_SET_IP;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void ECN_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+		           "ECN target: Parameter --ecn-tcp-remove is required");
+}
+
+static void ECN_print(const void *ip, const struct xt_entry_target *target,
+                      int numeric)
+{
+	const struct ipt_ECN_info *einfo =
+		(const struct ipt_ECN_info *)target->data;
+
+	printf("ECN ");
+
+	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
+	    && einfo->proto.tcp.ece == 0
+	    && einfo->proto.tcp.cwr == 0)
+		printf("TCP remove ");
+	else {
+		if (einfo->operation & IPT_ECN_OP_SET_ECE)
+			printf("ECE=%u ", einfo->proto.tcp.ece);
+
+		if (einfo->operation & IPT_ECN_OP_SET_CWR)
+			printf("CWR=%u ", einfo->proto.tcp.cwr);
+
+		if (einfo->operation & IPT_ECN_OP_SET_IP)
+			printf("ECT codepoint=%u ", einfo->ip_ect);
+	}
+}
+
+static void ECN_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct ipt_ECN_info *einfo =
+		(const struct ipt_ECN_info *)target->data;
+
+	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
+	    && einfo->proto.tcp.ece == 0
+	    && einfo->proto.tcp.cwr == 0)
+		printf("--ecn-tcp-remove ");
+	else {
+
+		if (einfo->operation & IPT_ECN_OP_SET_ECE)
+			printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece);
+
+		if (einfo->operation & IPT_ECN_OP_SET_CWR)
+			printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr);
+
+		if (einfo->operation & IPT_ECN_OP_SET_IP)
+			printf("--ecn-ip-ect %d ", einfo->ip_ect);
+	}
+}
+
+static struct xtables_target ecn_tg_reg = {
+	.name		= "ECN",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct ipt_ECN_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ipt_ECN_info)),
+	.help		= ECN_help,
+	.parse		= ECN_parse,
+	.final_check	= ECN_check,
+	.print		= ECN_print,
+	.save		= ECN_save,
+	.extra_opts	= ECN_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&ecn_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_ECN.man b/ap/app/iptables/extensions/libipt_ECN.man
new file mode 100755
index 0000000..a9cbe10
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_ECN.man
@@ -0,0 +1,7 @@
+This target allows to selectively work around known ECN blackholes.
+It can only be used in the mangle table.
+.TP
+\fB\-\-ecn\-tcp\-remove\fP
+Remove all ECN bits from the TCP header.  Of course, it can only be used
+in conjunction with
+\fB\-p tcp\fP.
diff --git a/ap/app/iptables/extensions/libipt_IMQ.c b/ap/app/iptables/extensions/libipt_IMQ.c
new file mode 100755
index 0000000..43e2d04
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_IMQ.c
@@ -0,0 +1,94 @@
+/* Shared library add-on to iptables to add IMQ target support. */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ipt_IMQ.h>
+
+static void
+help(void)
+{
+	printf(
+"IMQ target options:\n"
+"  --todev <N>		enqueue to imq<N>, defaults to 0\n");
+}
+
+static struct option opts[] = {
+	{ "todev", 1, 0, '1' },
+	{ .name = NULL }
+};
+
+static void
+init(struct xt_entry_target *t)
+{
+	struct ipt_imq_info *mr = (struct ipt_imq_info*)t->data;
+
+	mr->todev = 0;
+}
+
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const void *entry,
+      struct xt_entry_target **target)
+{
+	struct ipt_imq_info *mr = (struct ipt_imq_info*)(*target)->data;
+	
+	switch(c) {
+	case '1':
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --todev");
+		mr->todev=atoi(optarg);
+		break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static void
+final_check(unsigned int flags)
+{
+}
+
+static void
+print(const void *ip,
+      const struct xt_entry_target *target,
+      int numeric)
+{
+	struct ipt_imq_info *mr = (struct ipt_imq_info*)target->data;
+
+	printf("IMQ: todev %u ", mr->todev);
+}
+
+static void
+save(const void *ip, const struct xt_entry_target *target)
+{
+	struct ipt_imq_info *mr = (struct ipt_imq_info*)target->data;
+
+	printf("--todev %u", mr->todev);
+}
+
+static
+struct xtables_target imq
+= {
+    .name = "IMQ",
+    .version = XTABLES_VERSION,
+    .family = NFPROTO_IPV4,
+    .size = XT_ALIGN(sizeof(struct ipt_imq_info)),
+    .userspacesize = XT_ALIGN(sizeof(struct ipt_imq_info)),
+    .help = &help,
+    .init = &init,
+    .parse = &parse,
+    .final_check = &final_check,
+    .print = &print,
+    .save = &save,
+    .extra_opts = opts
+};
+
+void _init(void)
+{
+	xtables_register_target(&imq);
+}
diff --git a/ap/app/iptables/extensions/libipt_LED.c b/ap/app/iptables/extensions/libipt_LED.c
new file mode 100755
index 0000000..ead6de7
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_LED.c
@@ -0,0 +1,228 @@
+/* Shared library add-on to iptables to add LED support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ipt_LED.h>
+#include <linux/ledman.h>
+
+static struct option opts[] = {
+	{ .name = "led",              .has_arg = 1, .flag = 0, .val = '1' },
+	{ .name = "save",             .has_arg = 0, .flag = 0, .val = '2' },
+	{ .name = "restore",          .has_arg = 0, .flag = 0, .val = '3' },
+	{ .name = NULL }
+};
+
+static void
+init(struct xt_entry_target *t)
+{
+	struct ipt_led_info *ledinfo = (struct ipt_led_info *)t->data;
+
+	ledinfo->led = LEDMAN_ALL;
+	ledinfo->mode = IPT_LED_SET;
+}
+
+struct ipt_led_names {
+	const char *name;
+	u_int32_t led;
+};
+
+static struct ipt_led_names ipt_led_names[] = {
+#include "libipt_LED_def.c"
+    { }
+};
+
+static u_int32_t
+parse_led(const char *name)
+{
+	unsigned int led = -1;
+	unsigned int set = 0;
+
+	if (!xtables_strtoui(name, NULL, &led, 0, 7)) {
+		unsigned int i = 0;
+
+		for (i = 0; ipt_led_names[i].name; i++) {
+			if (strcasecmp(name, ipt_led_names[i].name) == 0) {
+				set++;
+				led = ipt_led_names[i].led;
+				break;
+			}
+			if (strncasecmp(name, ipt_led_names[i].name,
+					strlen(name)) == 0) {
+				if (set++)
+					xtables_error(PARAMETER_PROBLEM,
+						   "led `%s' ambiguous", name);
+				led = ipt_led_names[i].led;
+			}
+		}
+
+		if (!set)
+			xtables_error(PARAMETER_PROBLEM,
+				   "led `%s' unknown", name);
+	}
+
+	return led;
+}
+
+#define IPT_LED_OPT_LED    0x01
+#define IPT_LED_OPT_MODE   0x02
+#define IPT_LED_OPT_NO_LED 0x04
+
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const void *entry,
+      struct xt_entry_target **target)
+{
+	struct ipt_led_info *ledinfo = (struct ipt_led_info *)(*target)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & IPT_LED_OPT_LED)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --led twice");
+
+		ledinfo->led = parse_led(optarg);
+		*flags |= IPT_LED_OPT_LED;
+		break;
+
+	case '2':
+		if (*flags & IPT_LED_OPT_MODE)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --save twice");
+
+		ledinfo->mode = IPT_LED_SAVE;
+		*flags |= IPT_LED_OPT_MODE;
+		break;
+
+	case '3':
+		if (*flags & IPT_LED_OPT_MODE)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --restore twice");
+
+		ledinfo->mode = IPT_LED_RESTORE;
+		*flags |= IPT_LED_OPT_MODE | IPT_LED_OPT_NO_LED;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+final_check(unsigned int flags)
+{
+	if ((flags & IPT_LED_OPT_NO_LED) && (flags & IPT_LED_OPT_LED))
+		xtables_error(PARAMETER_PROBLEM,
+	           	   "LED target: Can't specify --led with --restore");
+
+	if (!(flags & IPT_LED_OPT_NO_LED) && !(flags & IPT_LED_OPT_LED))
+		xtables_error(PARAMETER_PROBLEM,
+		           "LED target: No --led specified");
+}
+
+static void
+print(const void *ip,
+      const struct xt_entry_target *target,
+      int numeric)
+{
+	const struct ipt_led_info *ledinfo
+		= (const struct ipt_led_info *)target->data;
+	unsigned int i;
+
+	printf("LED ");
+	switch (ledinfo->mode) {
+	case IPT_LED_SAVE:
+		printf("save ");
+		/* fallthrough */
+	case IPT_LED_SET:
+		for (i = 0; ipt_led_names[i].name; i++) {
+			if (ledinfo->led == ipt_led_names[i].led) {
+				printf("led %s ", ipt_led_names[i].name);
+				break;
+			}
+		}
+		if (!ipt_led_names[i].name)
+			printf("UNKNOWN led %u ", ledinfo->led);
+		break;
+	case IPT_LED_RESTORE:
+		printf("restore ");
+		break;
+	default:
+		printf("ERROR: UNKNOWN LED MODE ");
+		break;
+	}
+}
+
+static void
+save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct ipt_led_info *ledinfo
+		= (const struct ipt_led_info *)target->data;
+	unsigned int i;
+
+	switch (ledinfo->mode) {
+	case IPT_LED_SAVE:
+		printf("--save ");
+		/* fallthrough */
+	case IPT_LED_SET:
+		printf("--led ");
+		for (i = 0; ipt_led_names[i].name; i++) {
+			if (ledinfo->led == ipt_led_names[i].led) {
+				printf("led %s ", ipt_led_names[i].name);
+				break;
+			}
+		}
+		if (!ipt_led_names[i].name)
+			printf("%u ", ledinfo->led);
+		break;
+	case IPT_LED_RESTORE:
+		printf("--restore ");
+		break;
+	default:
+		printf("ERROR: UNKNOWN LED MODE ");
+		break;
+	}
+}
+
+static void
+help(void)
+{
+	unsigned int i;
+
+	printf(
+"LED target options:\n"
+"  --led LED                     LED to set\n"
+"  --save                        Save the LED value in the connection\n"
+"  --restore                     Use the saved LED value\n");
+
+	printf("LED names:\n");
+	for (i = 0; ipt_led_names[i].name; i++)
+		printf(" %s\n", ipt_led_names[i].name);
+}
+
+static
+struct xtables_target led
+= {
+    .name          = "LED",
+    .version       = XTABLES_VERSION,
+    .family        = NFPROTO_IPV4,
+    .size          = XT_ALIGN(sizeof(struct ipt_led_info)),
+    .userspacesize = XT_ALIGN(sizeof(struct ipt_led_info)),
+    .help          = &help,
+    .init          = &init,
+    .parse         = &parse,
+    .final_check   = &final_check,
+    .print         = &print,
+    .save          = &save,
+    .extra_opts    = opts
+};
+
+void _init(void)
+{
+	xtables_register_target(&led);
+}
diff --git a/ap/app/iptables/extensions/libipt_LED_def.pl b/ap/app/iptables/extensions/libipt_LED_def.pl
new file mode 100755
index 0000000..965f481
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_LED_def.pl
@@ -0,0 +1,17 @@
+# Generate keyword tables from ledman.h.
+
+my @cmds;
+my @leds;
+
+while (<>) {
+    if (/^#define\s+LEDMAN_CMD_([A-Z0-9_]+)/) {
+	push @cmds, $1;
+    } elsif (@cmds || /LEDMAN_MAX/) {
+	next;
+    } elsif (/^#define\s+LEDMAN_([A-Z0-9_]+)/) {
+	push @leds, $1;
+    }
+}
+
+print "  { \"$_\", LEDMAN_$_ },\n"
+    foreach (@leds);
diff --git a/ap/app/iptables/extensions/libipt_LOG.c b/ap/app/iptables/extensions/libipt_LOG.c
new file mode 100755
index 0000000..ebcb574
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_LOG.c
@@ -0,0 +1,270 @@
+/* Shared library add-on to iptables to add LOG support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ipt_LOG.h>
+
+#define LOG_DEFAULT_LEVEL LOG_WARNING
+
+#ifndef IPT_LOG_UID /* Old kernel */
+#define IPT_LOG_UID	0x08	/* Log UID owning local socket */
+#undef  IPT_LOG_MASK
+#define IPT_LOG_MASK	0x0f
+#endif
+
+static void LOG_help(void)
+{
+	printf(
+"LOG target options:\n"
+" --log-level level		Level of logging (numeric or see syslog.conf)\n"
+" --log-prefix prefix		Prefix log messages with this prefix.\n\n"
+" --log-tcp-sequence		Log TCP sequence numbers.\n\n"
+" --log-tcp-options		Log TCP options.\n\n"
+" --log-ip-options		Log IP options.\n\n"
+" --log-uid			Log UID owning the local socket.\n\n");
+}
+
+static const struct option LOG_opts[] = {
+	{ .name = "log-level",        .has_arg = 1, .val = '!' },
+	{ .name = "log-prefix",       .has_arg = 1, .val = '#' },
+	{ .name = "log-tcp-sequence", .has_arg = 0, .val = '1' },
+	{ .name = "log-tcp-options",  .has_arg = 0, .val = '2' },
+	{ .name = "log-ip-options",   .has_arg = 0, .val = '3' },
+	{ .name = "log-uid",          .has_arg = 0, .val = '4' },
+	{ .name = NULL }
+};
+
+static void LOG_init(struct xt_entry_target *t)
+{
+	struct ipt_log_info *loginfo = (struct ipt_log_info *)t->data;
+
+	loginfo->level = LOG_DEFAULT_LEVEL;
+
+}
+
+struct ipt_log_names {
+	const char *name;
+	unsigned int level;
+};
+
+static const struct ipt_log_names ipt_log_names[]
+= { { .name = "alert",   .level = LOG_ALERT },
+    { .name = "crit",    .level = LOG_CRIT },
+    { .name = "debug",   .level = LOG_DEBUG },
+    { .name = "emerg",   .level = LOG_EMERG },
+    { .name = "error",   .level = LOG_ERR },		/* DEPRECATED */
+    { .name = "info",    .level = LOG_INFO },
+    { .name = "notice",  .level = LOG_NOTICE },
+    { .name = "panic",   .level = LOG_EMERG },		/* DEPRECATED */
+    { .name = "warning", .level = LOG_WARNING }
+};
+
+static u_int8_t
+parse_level(const char *level)
+{
+	unsigned int lev = -1;
+	unsigned int set = 0;
+
+	if (!xtables_strtoui(level, NULL, &lev, 0, 7)) {
+		unsigned int i = 0;
+
+		for (i = 0;
+		     i < sizeof(ipt_log_names) / sizeof(struct ipt_log_names);
+		     i++) {
+			if (strncasecmp(level, ipt_log_names[i].name,
+					strlen(level)) == 0) {
+				if (set++)
+					xtables_error(PARAMETER_PROBLEM,
+						   "log-level `%s' ambiguous",
+						   level);
+				lev = ipt_log_names[i].level;
+			}
+		}
+
+		if (!set)
+			xtables_error(PARAMETER_PROBLEM,
+				   "log-level `%s' unknown", level);
+	}
+
+	return lev;
+}
+
+#define IPT_LOG_OPT_LEVEL 0x01
+#define IPT_LOG_OPT_PREFIX 0x02
+#define IPT_LOG_OPT_TCPSEQ 0x04
+#define IPT_LOG_OPT_TCPOPT 0x08
+#define IPT_LOG_OPT_IPOPT 0x10
+#define IPT_LOG_OPT_UID 0x20
+
+static int LOG_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_target **target)
+{
+	struct ipt_log_info *loginfo = (struct ipt_log_info *)(*target)->data;
+
+	switch (c) {
+	case '!':
+		if (*flags & IPT_LOG_OPT_LEVEL)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --log-level twice");
+
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --log-level");
+
+		loginfo->level = parse_level(optarg);
+		*flags |= IPT_LOG_OPT_LEVEL;
+		break;
+
+	case '#':
+		if (*flags & IPT_LOG_OPT_PREFIX)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --log-prefix twice");
+
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --log-prefix");
+
+		if (strlen(optarg) > sizeof(loginfo->prefix) - 1)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Maximum prefix length %u for --log-prefix",
+				   (unsigned int)sizeof(loginfo->prefix) - 1);
+
+		if (strlen(optarg) == 0)
+			xtables_error(PARAMETER_PROBLEM,
+				   "No prefix specified for --log-prefix");
+
+		if (strlen(optarg) != strlen(strtok(optarg, "\n")))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Newlines not allowed in --log-prefix");
+
+		strcpy(loginfo->prefix, optarg);
+		*flags |= IPT_LOG_OPT_PREFIX;
+		break;
+
+	case '1':
+		if (*flags & IPT_LOG_OPT_TCPSEQ)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --log-tcp-sequence "
+				   "twice");
+
+		loginfo->logflags |= IPT_LOG_TCPSEQ;
+		*flags |= IPT_LOG_OPT_TCPSEQ;
+		break;
+
+	case '2':
+		if (*flags & IPT_LOG_OPT_TCPOPT)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --log-tcp-options twice");
+
+		loginfo->logflags |= IPT_LOG_TCPOPT;
+		*flags |= IPT_LOG_OPT_TCPOPT;
+		break;
+
+	case '3':
+		if (*flags & IPT_LOG_OPT_IPOPT)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --log-ip-options twice");
+
+		loginfo->logflags |= IPT_LOG_IPOPT;
+		*flags |= IPT_LOG_OPT_IPOPT;
+		break;
+
+	case '4':
+		if (*flags & IPT_LOG_OPT_UID)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --log-uid twice");
+
+		loginfo->logflags |= IPT_LOG_UID;
+		*flags |= IPT_LOG_OPT_UID;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void LOG_print(const void *ip, const struct xt_entry_target *target,
+                      int numeric)
+{
+	const struct ipt_log_info *loginfo
+		= (const struct ipt_log_info *)target->data;
+	unsigned int i = 0;
+
+	printf("LOG ");
+	if (numeric)
+		printf("flags %u level %u ",
+		       loginfo->logflags, loginfo->level);
+	else {
+		for (i = 0;
+		     i < sizeof(ipt_log_names) / sizeof(struct ipt_log_names);
+		     i++) {
+			if (loginfo->level == ipt_log_names[i].level) {
+				printf("level %s ", ipt_log_names[i].name);
+				break;
+			}
+		}
+		if (i == sizeof(ipt_log_names) / sizeof(struct ipt_log_names))
+			printf("UNKNOWN level %u ", loginfo->level);
+		if (loginfo->logflags & IPT_LOG_TCPSEQ)
+			printf("tcp-sequence ");
+		if (loginfo->logflags & IPT_LOG_TCPOPT)
+			printf("tcp-options ");
+		if (loginfo->logflags & IPT_LOG_IPOPT)
+			printf("ip-options ");
+		if (loginfo->logflags & IPT_LOG_UID)
+			printf("uid ");
+		if (loginfo->logflags & ~(IPT_LOG_MASK))
+			printf("unknown-flags ");
+	}
+
+	if (strcmp(loginfo->prefix, "") != 0)
+		printf("prefix `%s' ", loginfo->prefix);
+}
+
+static void LOG_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct ipt_log_info *loginfo
+		= (const struct ipt_log_info *)target->data;
+
+	if (strcmp(loginfo->prefix, "") != 0) {
+		printf("--log-prefix ");
+		xtables_save_string(loginfo->prefix);
+	}
+
+	if (loginfo->level != LOG_DEFAULT_LEVEL)
+		printf("--log-level %d ", loginfo->level);
+
+	if (loginfo->logflags & IPT_LOG_TCPSEQ)
+		printf("--log-tcp-sequence ");
+	if (loginfo->logflags & IPT_LOG_TCPOPT)
+		printf("--log-tcp-options ");
+	if (loginfo->logflags & IPT_LOG_IPOPT)
+		printf("--log-ip-options ");
+	if (loginfo->logflags & IPT_LOG_UID)
+		printf("--log-uid ");
+}
+
+static struct xtables_target log_tg_reg = {
+    .name          = "LOG",
+    .version       = XTABLES_VERSION,
+    .family        = NFPROTO_IPV4,
+    .size          = XT_ALIGN(sizeof(struct ipt_log_info)),
+    .userspacesize = XT_ALIGN(sizeof(struct ipt_log_info)),
+    .help          = LOG_help,
+    .init          = LOG_init,
+    .parse         = LOG_parse,
+    .print         = LOG_print,
+    .save          = LOG_save,
+    .extra_opts    = LOG_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&log_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_LOG.man b/ap/app/iptables/extensions/libipt_LOG.man
new file mode 100755
index 0000000..47c35e0
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_LOG.man
@@ -0,0 +1,31 @@
+Turn on kernel logging of matching packets.  When this option is set
+for a rule, the Linux kernel will print some information on all
+matching packets (like most IP header fields) via the kernel log
+(where it can be read with
+.I dmesg
+or 
+.IR syslogd (8)).
+This is a "non-terminating target", i.e. rule traversal continues at
+the next rule.  So if you want to LOG the packets you refuse, use two
+separate rules with the same matching criteria, first using target LOG
+then DROP (or REJECT).
+.TP
+\fB\-\-log\-level\fP \fIlevel\fP
+Level of logging (numeric or see \fIsyslog.conf\fP(5)).
+.TP
+\fB\-\-log\-prefix\fP \fIprefix\fP
+Prefix log messages with the specified prefix; up to 29 letters long,
+and useful for distinguishing messages in the logs.
+.TP
+\fB\-\-log\-tcp\-sequence\fP
+Log TCP sequence numbers. This is a security risk if the log is
+readable by users.
+.TP
+\fB\-\-log\-tcp\-options\fP
+Log options from the TCP packet header.
+.TP
+\fB\-\-log\-ip\-options\fP
+Log options from the IP packet header.
+.TP
+\fB\-\-log\-uid\fP
+Log the userid of the process which generated the packet.
diff --git a/ap/app/iptables/extensions/libipt_MASQUERADE.c b/ap/app/iptables/extensions/libipt_MASQUERADE.c
new file mode 100755
index 0000000..82c2230
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_MASQUERADE.c
@@ -0,0 +1,165 @@
+/* Shared library add-on to iptables to add masquerade support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <limits.h> /* INT_MAX in ip_tables.h */
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <net/netfilter/nf_nat.h>
+
+static void MASQUERADE_help(void)
+{
+	printf(
+"MASQUERADE target options:\n"
+" --to-ports <port>[-<port>]\n"
+"				Port (range) to map to.\n"
+" --random\n"
+"				Randomize source port.\n");
+}
+
+static const struct option MASQUERADE_opts[] = {
+	{ "to-ports", 1, NULL, '1' },
+	{ "random", 0, NULL, '2' },
+	{ .name = NULL }
+};
+
+static void MASQUERADE_init(struct xt_entry_target *t)
+{
+	struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data;
+
+	/* Actually, it's 0, but it's ignored at the moment. */
+	mr->rangesize = 1;
+
+}
+
+/* Parses ports */
+static void
+parse_ports(const char *arg, struct nf_nat_multi_range *mr)
+{
+	const char *dash;
+	int port;
+
+	mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+	port = atoi(arg);
+	if (port <= 0 || port > 65535)
+		xtables_error(PARAMETER_PROBLEM, "Port \"%s\" not valid\n", arg);
+
+	dash = strchr(arg, '-');
+	if (!dash) {
+		mr->range[0].min.tcp.port
+			= mr->range[0].max.tcp.port
+			= htons(port);
+	} else {
+		int maxport;
+
+		maxport = atoi(dash + 1);
+		if (maxport == 0 || maxport > 65535)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Port `%s' not valid\n", dash+1);
+		if (maxport < port)
+			/* People are stupid.  Present reader excepted. */
+			xtables_error(PARAMETER_PROBLEM,
+				   "Port range `%s' funky\n", arg);
+		mr->range[0].min.tcp.port = htons(port);
+		mr->range[0].max.tcp.port = htons(maxport);
+	}
+}
+
+static int MASQUERADE_parse(int c, char **argv, int invert, unsigned int *flags,
+                            const void *e, struct xt_entry_target **target)
+{
+	const struct ipt_entry *entry = e;
+	int portok;
+	struct nf_nat_multi_range *mr
+		= (struct nf_nat_multi_range *)(*target)->data;
+
+	if (entry->ip.proto == IPPROTO_TCP
+	    || entry->ip.proto == IPPROTO_UDP
+	    || entry->ip.proto == IPPROTO_SCTP
+	    || entry->ip.proto == IPPROTO_DCCP
+	    || entry->ip.proto == IPPROTO_ICMP)
+		portok = 1;
+	else
+		portok = 0;
+
+	switch (c) {
+	case '1':
+		if (!portok)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Need TCP, UDP, SCTP or DCCP with port specification");
+
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --to-ports");
+
+		parse_ports(optarg, mr);
+		return 1;
+
+	case '2':
+		mr->range[0].flags |=  IP_NAT_RANGE_PROTO_RANDOM;
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+static void
+MASQUERADE_print(const void *ip, const struct xt_entry_target *target,
+                 int numeric)
+{
+	struct nf_nat_multi_range *mr
+		= (struct nf_nat_multi_range *)target->data;
+	struct nf_nat_range *r = &mr->range[0];
+
+	if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+		printf("masq ports: ");
+		printf("%hu", ntohs(r->min.tcp.port));
+		if (r->max.tcp.port != r->min.tcp.port)
+			printf("-%hu", ntohs(r->max.tcp.port));
+		printf(" ");
+	}
+
+	if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
+		printf("random ");
+}
+
+static void
+MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
+{
+	struct nf_nat_multi_range *mr
+		= (struct nf_nat_multi_range *)target->data;
+	struct nf_nat_range *r = &mr->range[0];
+
+	if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+		printf("--to-ports %hu", ntohs(r->min.tcp.port));
+		if (r->max.tcp.port != r->min.tcp.port)
+			printf("-%hu", ntohs(r->max.tcp.port));
+		printf(" ");
+	}
+
+	if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
+		printf("--random ");
+}
+
+static struct xtables_target masquerade_tg_reg = {
+	.name		= "MASQUERADE",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct nf_nat_multi_range)),
+	.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_multi_range)),
+	.help		= MASQUERADE_help,
+	.init		= MASQUERADE_init,
+	.parse		= MASQUERADE_parse,
+	.print		= MASQUERADE_print,
+	.save		= MASQUERADE_save,
+	.extra_opts	= MASQUERADE_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&masquerade_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_MASQUERADE.man b/ap/app/iptables/extensions/libipt_MASQUERADE.man
new file mode 100755
index 0000000..8f42993
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_MASQUERADE.man
@@ -0,0 +1,30 @@
+This target is only valid in the
+.B nat
+table, in the
+.B POSTROUTING
+chain.  It should only be used with dynamically assigned IP (dialup)
+connections: if you have a static IP address, you should use the SNAT
+target.  Masquerading is equivalent to specifying a mapping to the IP
+address of the interface the packet is going out, but also has the
+effect that connections are
+.I forgotten
+when the interface goes down.  This is the correct behavior when the
+next dialup is unlikely to have the same interface address (and hence
+any established connections are lost anyway).  It takes one option:
+.TP
+\fB\-\-to\-ports\fP \fIport\fP[\fB\-\fP\fIport\fP]
+This specifies a range of source ports to use, overriding the default
+.B SNAT
+source port-selection heuristics (see above).  This is only valid
+if the rule also specifies
+\fB\-p tcp\fP
+or
+\fB\-p udp\fP.
+.TP
+\fB\-\-random\fP
+Randomize source port mapping
+If option
+\fB\-\-random\fP
+is used then port mapping will be randomized (kernel >= 2.6.21).
+.RS
+.PP
diff --git a/ap/app/iptables/extensions/libipt_MIRROR.c b/ap/app/iptables/extensions/libipt_MIRROR.c
new file mode 100755
index 0000000..81964dd
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_MIRROR.c
@@ -0,0 +1,35 @@
+/* Shared library add-on to iptables to add MIRROR target support. */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+
+static void MIRROR_help(void)
+{
+	printf("MIRROR target takes no options\n");
+}
+
+static int MIRROR_parse(int c, char **argv, int invert, unsigned int *flags,
+                        const void *entry, struct xt_entry_target **target)
+{
+	return 0;
+}
+
+static struct xtables_target mirror_tg_reg = {
+	.name		= "MIRROR",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(0),
+	.userspacesize	= XT_ALIGN(0),
+ 	.help		= MIRROR_help,
+ 	.parse		= MIRROR_parse,
+	.print		= NULL,
+	.save		= NULL,
+};
+
+void _init(void)
+{
+	xtables_register_target(&mirror_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_MIRROR.man b/ap/app/iptables/extensions/libipt_MIRROR.man
new file mode 100755
index 0000000..7b720bc
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_MIRROR.man
@@ -0,0 +1,12 @@
+This is an experimental demonstration target which inverts the source
+and destination fields in the IP header and retransmits the packet.
+It is only valid in the
+.BR INPUT ,
+.B FORWARD
+and
+.B PREROUTING
+chains, and user-defined chains which are only called from those
+chains.  Note that the outgoing packets are
+.B NOT
+seen by any packet filtering chains, connection tracking or NAT, to
+avoid loops and other problems.
diff --git a/ap/app/iptables/extensions/libipt_NETMAP.c b/ap/app/iptables/extensions/libipt_NETMAP.c
new file mode 100755
index 0000000..9820230
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_NETMAP.c
@@ -0,0 +1,183 @@
+/* Shared library add-on to iptables to add static NAT support.
+   Author: Svenning Soerensen <svenning@post5.tele.dk>
+*/
+
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <net/netfilter/nf_nat.h>
+
+#define MODULENAME "NETMAP"
+
+static const struct option NETMAP_opts[] = {
+	{ "to", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static void NETMAP_help(void)
+{
+	printf(MODULENAME" target options:\n"
+	       "  --%s address[/mask]\n"
+	       "				Network address to map to.\n\n",
+	       NETMAP_opts[0].name);
+}
+
+static u_int32_t
+bits2netmask(int bits)
+{
+	u_int32_t netmask, bm;
+
+	if (bits >= 32 || bits < 0)
+		return(~0);
+	for (netmask = 0, bm = 0x80000000; bits; bits--, bm >>= 1)
+		netmask |= bm;
+	return htonl(netmask);
+}
+
+static int
+netmask2bits(u_int32_t netmask)
+{
+	u_int32_t bm;
+	int bits;
+
+	netmask = ntohl(netmask);
+	for (bits = 0, bm = 0x80000000; netmask & bm; netmask <<= 1)
+		bits++;
+	if (netmask)
+		return -1; /* holes in netmask */
+	return bits;
+}
+
+static void NETMAP_init(struct xt_entry_target *t)
+{
+	struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data;
+
+	/* Actually, it's 0, but it's ignored at the moment. */
+	mr->rangesize = 1;
+
+}
+
+/* Parses network address */
+static void
+parse_to(char *arg, struct nf_nat_range *range)
+{
+	char *slash;
+	const struct in_addr *ip;
+	u_int32_t netmask;
+	unsigned int bits;
+
+	range->flags |= IP_NAT_RANGE_MAP_IPS;
+	slash = strchr(arg, '/');
+	if (slash)
+		*slash = '\0';
+
+	ip = xtables_numeric_to_ipaddr(arg);
+	if (!ip)
+		xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
+			   arg);
+	range->min_ip = ip->s_addr;
+	if (slash) {
+		if (strchr(slash+1, '.')) {
+			ip = xtables_numeric_to_ipmask(slash+1);
+			if (!ip)
+				xtables_error(PARAMETER_PROBLEM, "Bad netmask \"%s\"\n",
+					   slash+1);
+			netmask = ip->s_addr;
+		}
+		else {
+			if (!xtables_strtoui(slash+1, NULL, &bits, 0, 32))
+				xtables_error(PARAMETER_PROBLEM, "Bad netmask \"%s\"\n",
+					   slash+1);
+			netmask = bits2netmask(bits);
+		}
+		/* Don't allow /0 (/1 is probably insane, too) */
+		if (netmask == 0)
+			xtables_error(PARAMETER_PROBLEM, "Netmask needed\n");
+	}
+	else
+		netmask = ~0;
+
+	if (range->min_ip & ~netmask) {
+		if (slash)
+			*slash = '/';
+		xtables_error(PARAMETER_PROBLEM, "Bad network address \"%s\"\n",
+			   arg);
+	}
+	range->max_ip = range->min_ip | ~netmask;
+}
+
+static int NETMAP_parse(int c, char **argv, int invert, unsigned int *flags,
+                        const void *entry, struct xt_entry_target **target)
+{
+	struct nf_nat_multi_range *mr
+		= (struct nf_nat_multi_range *)(*target)->data;
+
+	switch (c) {
+	case '1':
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --%s", NETMAP_opts[0].name);
+
+		parse_to(optarg, &mr->range[0]);
+		*flags = 1;
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+static void NETMAP_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   MODULENAME" needs --%s", NETMAP_opts[0].name);
+}
+
+static void NETMAP_print(const void *ip, const struct xt_entry_target *target,
+                         int numeric)
+{
+	struct nf_nat_multi_range *mr
+		= (struct nf_nat_multi_range *)target->data;
+	struct nf_nat_range *r = &mr->range[0];
+	struct in_addr a;
+	int bits;
+
+	a.s_addr = r->min_ip;
+	printf("%s", xtables_ipaddr_to_numeric(&a));
+	a.s_addr = ~(r->min_ip ^ r->max_ip);
+	bits = netmask2bits(a.s_addr);
+	if (bits < 0)
+		printf("/%s", xtables_ipaddr_to_numeric(&a));
+	else
+		printf("/%d", bits);
+}
+
+static void NETMAP_save(const void *ip, const struct xt_entry_target *target)
+{
+	printf("--%s ", NETMAP_opts[0].name);
+	NETMAP_print(ip, target, 0);
+}
+
+static struct xtables_target netmap_tg_reg = {
+	.name		= MODULENAME,
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct nf_nat_multi_range)),
+	.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_multi_range)),
+	.help		= NETMAP_help,
+	.init		= NETMAP_init,
+	.parse		= NETMAP_parse,
+	.final_check	= NETMAP_check,
+	.print		= NETMAP_print,
+	.save		= NETMAP_save,
+	.extra_opts	= NETMAP_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&netmap_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_NETMAP.man b/ap/app/iptables/extensions/libipt_NETMAP.man
new file mode 100755
index 0000000..a7e90b8
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_NETMAP.man
@@ -0,0 +1,9 @@
+This target allows you to statically map a whole network of addresses onto
+another network of addresses.  It can only be used from rules in the
+.B nat
+table.
+.TP
+\fB\-\-to\fP \fIaddress\fP[\fB/\fP\fImask\fP]
+Network address to map to.  The resulting address will be constructed in the
+following way: All 'one' bits in the mask are filled in from the new `address'.
+All bits that are zero in the mask are filled in from the original address.
diff --git a/ap/app/iptables/extensions/libipt_REDIRECT.c b/ap/app/iptables/extensions/libipt_REDIRECT.c
new file mode 100755
index 0000000..658f933
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_REDIRECT.c
@@ -0,0 +1,176 @@
+/* Shared library add-on to iptables to add redirect support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <limits.h> /* INT_MAX in ip_tables.h */
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <net/netfilter/nf_nat.h>
+
+#define IPT_REDIRECT_OPT_DEST	0x01
+#define IPT_REDIRECT_OPT_RANDOM	0x02
+
+static void REDIRECT_help(void)
+{
+	printf(
+"REDIRECT target options:\n"
+" --to-ports <port>[-<port>]\n"
+"				Port (range) to map to.\n");
+}
+
+static const struct option REDIRECT_opts[] = {
+	{ "to-ports", 1, NULL, '1' },
+	{ "random", 0, NULL, '2' },
+	{ .name = NULL }
+};
+
+static void REDIRECT_init(struct xt_entry_target *t)
+{
+	struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data;
+
+	/* Actually, it's 0, but it's ignored at the moment. */
+	mr->rangesize = 1;
+
+}
+
+/* Parses ports */
+static void
+parse_ports(const char *arg, struct nf_nat_multi_range *mr)
+{
+	const char *dash;
+	int port;
+
+	mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+	if (strchr(arg, '.'))
+		xtables_error(PARAMETER_PROBLEM, "IP address not permitted\n");
+
+	port = atoi(arg);
+	if (port == 0)
+		port = xtables_service_to_port(arg, NULL);
+
+	if (port == 0 || port > 65535)
+		xtables_error(PARAMETER_PROBLEM, "Port \"%s\" not valid\n", arg);
+
+	dash = strchr(arg, '-');
+	if (!dash) {
+		mr->range[0].min.tcp.port
+			= mr->range[0].max.tcp.port
+			= htons(port);
+	} else {
+		int maxport;
+
+		maxport = atoi(dash + 1);
+		if (maxport == 0 || maxport > 65535)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Port `%s' not valid\n", dash+1);
+		if (maxport < port)
+			/* People are stupid. */
+			xtables_error(PARAMETER_PROBLEM,
+				   "Port range `%s' funky\n", arg);
+		mr->range[0].min.tcp.port = htons(port);
+		mr->range[0].max.tcp.port = htons(maxport);
+	}
+}
+
+static int REDIRECT_parse(int c, char **argv, int invert, unsigned int *flags,
+                          const void *e, struct xt_entry_target **target)
+{
+	const struct ipt_entry *entry = e;
+	struct nf_nat_multi_range *mr
+		= (struct nf_nat_multi_range *)(*target)->data;
+	int portok;
+
+	if (entry->ip.proto == IPPROTO_TCP
+	    || entry->ip.proto == IPPROTO_UDP
+	    || entry->ip.proto == IPPROTO_SCTP
+	    || entry->ip.proto == IPPROTO_DCCP
+	    || entry->ip.proto == IPPROTO_ICMP)
+		portok = 1;
+	else
+		portok = 0;
+
+	switch (c) {
+	case '1':
+		if (!portok)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Need TCP, UDP, SCTP or DCCP with port specification");
+
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --to-ports");
+
+		parse_ports(optarg, mr);
+		if (*flags & IPT_REDIRECT_OPT_RANDOM)
+			mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
+		*flags |= IPT_REDIRECT_OPT_DEST;
+		return 1;
+
+	case '2':
+		if (*flags & IPT_REDIRECT_OPT_DEST) {
+			mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
+			*flags |= IPT_REDIRECT_OPT_RANDOM;
+		} else
+			*flags |= IPT_REDIRECT_OPT_RANDOM;
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+static void REDIRECT_print(const void *ip, const struct xt_entry_target *target,
+                           int numeric)
+{
+	struct nf_nat_multi_range *mr
+		= (struct nf_nat_multi_range *)target->data;
+	struct nf_nat_range *r = &mr->range[0];
+
+	if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+		printf("redir ports ");
+		printf("%hu", ntohs(r->min.tcp.port));
+		if (r->max.tcp.port != r->min.tcp.port)
+			printf("-%hu", ntohs(r->max.tcp.port));
+		printf(" ");
+		if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM)
+			printf("random ");
+	}
+}
+
+static void REDIRECT_save(const void *ip, const struct xt_entry_target *target)
+{
+	struct nf_nat_multi_range *mr
+		= (struct nf_nat_multi_range *)target->data;
+	struct nf_nat_range *r = &mr->range[0];
+
+	if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+		printf("--to-ports ");
+		printf("%hu", ntohs(r->min.tcp.port));
+		if (r->max.tcp.port != r->min.tcp.port)
+			printf("-%hu", ntohs(r->max.tcp.port));
+		printf(" ");
+		if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM)
+			printf("--random ");
+	}
+}
+
+static struct xtables_target redirect_tg_reg = {
+	.name		= "REDIRECT",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct nf_nat_multi_range)),
+	.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_multi_range)),
+	.help		= REDIRECT_help,
+	.init		= REDIRECT_init,
+ 	.parse		= REDIRECT_parse,
+	.print		= REDIRECT_print,
+	.save		= REDIRECT_save,
+	.extra_opts	= REDIRECT_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&redirect_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_REDIRECT.man b/ap/app/iptables/extensions/libipt_REDIRECT.man
new file mode 100755
index 0000000..90ab19d
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_REDIRECT.man
@@ -0,0 +1,25 @@
+This target is only valid in the
+.B nat
+table, in the
+.B PREROUTING
+and
+.B OUTPUT
+chains, and user-defined chains which are only called from those
+chains.  It redirects the packet to the machine itself by changing the
+destination IP to the primary address of the incoming interface
+(locally-generated packets are mapped to the 127.0.0.1 address).
+.TP
+\fB\-\-to\-ports\fP \fIport\fP[\fB\-\fP\fIport\fP]
+This specifies a destination port or range of ports to use: without
+this, the destination port is never altered.  This is only valid
+if the rule also specifies
+\fB\-p tcp\fP
+or
+\fB\-p udp\fP.
+.TP
+\fB\-\-random\fP
+If option
+\fB\-\-random\fP
+is used then port mapping will be randomized (kernel >= 2.6.22).
+.RS
+.PP
diff --git a/ap/app/iptables/extensions/libipt_REJECT.c b/ap/app/iptables/extensions/libipt_REJECT.c
new file mode 100755
index 0000000..5b23f54
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_REJECT.c
@@ -0,0 +1,168 @@
+/* Shared library add-on to iptables to add customized REJECT support.
+ *
+ * (C) 2000 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ipt_REJECT.h>
+#include <linux/version.h>
+
+/* If we are compiling against a kernel that does not support
+ * IPT_ICMP_ADMIN_PROHIBITED, we are emulating it.
+ * The result will be a plain DROP of the packet instead of
+ * reject. -- Maciej Soltysiak <solt@dns.toxicfilms.tv>
+ */
+#ifndef IPT_ICMP_ADMIN_PROHIBITED
+#define IPT_ICMP_ADMIN_PROHIBITED	IPT_TCP_RESET + 1
+#endif
+
+struct reject_names {
+	const char *name;
+	const char *alias;
+	enum ipt_reject_with with;
+	const char *desc;
+};
+
+static const struct reject_names reject_table[] = {
+	{"icmp-net-unreachable", "net-unreach",
+		IPT_ICMP_NET_UNREACHABLE, "ICMP network unreachable"},
+	{"icmp-host-unreachable", "host-unreach",
+		IPT_ICMP_HOST_UNREACHABLE, "ICMP host unreachable"},
+	{"icmp-proto-unreachable", "proto-unreach",
+		IPT_ICMP_PROT_UNREACHABLE, "ICMP protocol unreachable"},
+	{"icmp-port-unreachable", "port-unreach",
+		IPT_ICMP_PORT_UNREACHABLE, "ICMP port unreachable (default)"},
+#if 0
+	{"echo-reply", "echoreply",
+	 IPT_ICMP_ECHOREPLY, "for ICMP echo only: faked ICMP echo reply"},
+#endif
+	{"icmp-net-prohibited", "net-prohib",
+	 IPT_ICMP_NET_PROHIBITED, "ICMP network prohibited"},
+	{"icmp-host-prohibited", "host-prohib",
+	 IPT_ICMP_HOST_PROHIBITED, "ICMP host prohibited"},
+	{"tcp-reset", "tcp-rst",
+	 IPT_TCP_RESET, "TCP RST packet"},
+	{"icmp-admin-prohibited", "admin-prohib",
+	 IPT_ICMP_ADMIN_PROHIBITED, "ICMP administratively prohibited (*)"}
+};
+
+static void
+print_reject_types(void)
+{
+	unsigned int i;
+
+	printf("Valid reject types:\n");
+
+	for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) {
+		printf("    %-25s\t%s\n", reject_table[i].name, reject_table[i].desc);
+		printf("    %-25s\talias\n", reject_table[i].alias);
+	}
+	printf("\n");
+}
+
+static void REJECT_help(void)
+{
+	printf(
+"REJECT target options:\n"
+"--reject-with type              drop input packet and send back\n"
+"                                a reply packet according to type:\n");
+
+	print_reject_types();
+
+	printf("(*) See man page or read the INCOMPATIBILITES file for compatibility issues.\n");
+}
+
+static const struct option REJECT_opts[] = {
+	{ "reject-with", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static void REJECT_init(struct xt_entry_target *t)
+{
+	struct ipt_reject_info *reject = (struct ipt_reject_info *)t->data;
+
+	/* default */
+	reject->with = IPT_ICMP_PORT_UNREACHABLE;
+
+}
+
+static int REJECT_parse(int c, char **argv, int invert, unsigned int *flags,
+                        const void *entry, struct xt_entry_target **target)
+{
+	struct ipt_reject_info *reject = (struct ipt_reject_info *)(*target)->data;
+	unsigned int limit = sizeof(reject_table)/sizeof(struct reject_names);
+	unsigned int i;
+
+	switch(c) {
+	case '1':
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --reject-with");
+		for (i = 0; i < limit; i++) {
+			if ((strncasecmp(reject_table[i].name, optarg, strlen(optarg)) == 0)
+			    || (strncasecmp(reject_table[i].alias, optarg, strlen(optarg)) == 0)) {
+				reject->with = reject_table[i].with;
+				return 1;
+			}
+		}
+		/* This due to be dropped late in 2.4 pre-release cycle --RR */
+		if (strncasecmp("echo-reply", optarg, strlen(optarg)) == 0
+		    || strncasecmp("echoreply", optarg, strlen(optarg)) == 0)
+			fprintf(stderr, "--reject-with echo-reply no longer"
+				" supported\n");
+		xtables_error(PARAMETER_PROBLEM, "unknown reject type \"%s\"", optarg);
+	default:
+		/* Fall through */
+		break;
+	}
+	return 0;
+}
+
+static void REJECT_print(const void *ip, const struct xt_entry_target *target,
+                         int numeric)
+{
+	const struct ipt_reject_info *reject
+		= (const struct ipt_reject_info *)target->data;
+	unsigned int i;
+
+	for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) {
+		if (reject_table[i].with == reject->with)
+			break;
+	}
+	printf("reject-with %s ", reject_table[i].name);
+}
+
+static void REJECT_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct ipt_reject_info *reject
+		= (const struct ipt_reject_info *)target->data;
+	unsigned int i;
+
+	for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++)
+		if (reject_table[i].with == reject->with)
+			break;
+
+	printf("--reject-with %s ", reject_table[i].name);
+}
+
+static struct xtables_target reject_tg_reg = {
+	.name		= "REJECT",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct ipt_reject_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ipt_reject_info)),
+	.help		= REJECT_help,
+	.init		= REJECT_init,
+	.parse		= REJECT_parse,
+	.print		= REJECT_print,
+	.save		= REJECT_save,
+	.extra_opts	= REJECT_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&reject_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_REJECT.man b/ap/app/iptables/extensions/libipt_REJECT.man
new file mode 100755
index 0000000..c419a85
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_REJECT.man
@@ -0,0 +1,32 @@
+This is used to send back an error packet in response to the matched
+packet: otherwise it is equivalent to
+.B DROP
+so it is a terminating TARGET, ending rule traversal.
+This target is only valid in the
+.BR INPUT ,
+.B FORWARD
+and
+.B OUTPUT
+chains, and user-defined chains which are only called from those
+chains.  The following option controls the nature of the error packet
+returned:
+.TP
+\fB\-\-reject\-with\fP \fItype\fP
+The type given can be
+\fBicmp\-net\-unreachable\fP,
+\fBicmp\-host\-unreachable\fP,
+\fBicmp\-port\-unreachable\fP,
+\fBicmp\-proto\-unreachable\fP,
+\fBicmp\-net\-prohibited\fP,
+\fBicmp\-host\-prohibited\fP or
+\fBicmp\-admin\-prohibited\fP (*)
+which return the appropriate ICMP error message (\fBport\-unreachable\fP is
+the default).  The option
+\fBtcp\-reset\fP
+can be used on rules which only match the TCP protocol: this causes a
+TCP RST packet to be sent back.  This is mainly useful for blocking 
+.I ident
+(113/tcp) probes which frequently occur when sending mail to broken mail
+hosts (which won't accept your mail otherwise).
+.PP
+(*) Using icmp\-admin\-prohibited with kernels that do not support it will result in a plain DROP instead of REJECT
diff --git a/ap/app/iptables/extensions/libipt_SAME.c b/ap/app/iptables/extensions/libipt_SAME.c
new file mode 100755
index 0000000..a07d9f4
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_SAME.c
@@ -0,0 +1,219 @@
+/* Shared library add-on to iptables to add simple non load-balancing SNAT support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <net/netfilter/nf_nat.h>
+/* For 64bit kernel / 32bit userspace */
+#include <linux/netfilter_ipv4/ipt_SAME.h>
+
+static void SAME_help(void)
+{
+	printf(
+"SAME target options:\n"
+" --to <ipaddr>-<ipaddr>\n"
+"				Addresses to map source to.\n"
+"				 May be specified more than\n"
+"				  once for multiple ranges.\n"
+" --nodst\n"
+"				Don't use destination-ip in\n"
+"				           source selection\n"
+" --random\n"
+"				Randomize source port\n");
+}
+
+static const struct option SAME_opts[] = {
+	{ "to", 1, NULL, '1' },
+	{ "nodst", 0, NULL, '2'},
+	{ "random", 0, NULL, '3' },
+	{ .name = NULL }
+};
+
+static void SAME_init(struct xt_entry_target *t)
+{
+	struct ipt_same_info *mr = (struct ipt_same_info *)t->data;
+
+	/* Set default to 0 */
+	mr->rangesize = 0;
+	mr->info = 0;
+	mr->ipnum = 0;
+	
+}
+
+/* Parses range of IPs */
+static void
+parse_to(char *arg, struct nf_nat_range *range)
+{
+	char *dash;
+	const struct in_addr *ip;
+
+	range->flags |= IP_NAT_RANGE_MAP_IPS;
+	dash = strchr(arg, '-');
+
+	if (dash)
+		*dash = '\0';
+
+	ip = xtables_numeric_to_ipaddr(arg);
+	if (!ip)
+		xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
+			   arg);
+	range->min_ip = ip->s_addr;
+
+	if (dash) {
+		ip = xtables_numeric_to_ipaddr(dash+1);
+		if (!ip)
+			xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
+				   dash+1);
+	}
+	range->max_ip = ip->s_addr;
+	if (dash)
+		if (range->min_ip > range->max_ip)
+			xtables_error(PARAMETER_PROBLEM, "Bad IP range \"%s-%s\"\n",
+				   arg, dash+1);
+}
+
+#define IPT_SAME_OPT_TO			0x01
+#define IPT_SAME_OPT_NODST		0x02
+#define IPT_SAME_OPT_RANDOM		0x04
+
+static int SAME_parse(int c, char **argv, int invert, unsigned int *flags,
+                      const void *entry, struct xt_entry_target **target)
+{
+	struct ipt_same_info *mr
+		= (struct ipt_same_info *)(*target)->data;
+	unsigned int count;
+
+	switch (c) {
+	case '1':
+		if (mr->rangesize == IPT_SAME_MAX_RANGE)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Too many ranges specified, maximum "
+				   "is %i ranges.\n",
+				   IPT_SAME_MAX_RANGE);
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --to");
+
+		parse_to(optarg, &mr->range[mr->rangesize]);
+		/* WTF do we need this for? */
+		if (*flags & IPT_SAME_OPT_RANDOM)
+			mr->range[mr->rangesize].flags 
+				|= IP_NAT_RANGE_PROTO_RANDOM;
+		mr->rangesize++;
+		*flags |= IPT_SAME_OPT_TO;
+		break;
+		
+	case '2':
+		if (*flags & IPT_SAME_OPT_NODST)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --nodst twice");
+		
+		mr->info |= IPT_SAME_NODST;
+		*flags |= IPT_SAME_OPT_NODST;
+		break;
+
+	case '3':	
+		*flags |= IPT_SAME_OPT_RANDOM;
+		for (count=0; count < mr->rangesize; count++)
+			mr->range[count].flags |= IP_NAT_RANGE_PROTO_RANDOM;
+		break;
+
+	default:
+		return 0;
+	}
+	
+	return 1;
+}
+
+static void SAME_check(unsigned int flags)
+{
+	if (!(flags & IPT_SAME_OPT_TO))
+		xtables_error(PARAMETER_PROBLEM,
+			   "SAME needs --to");
+}
+
+static void SAME_print(const void *ip, const struct xt_entry_target *target,
+                       int numeric)
+{
+	unsigned int count;
+	struct ipt_same_info *mr
+		= (struct ipt_same_info *)target->data;
+	int random_selection = 0;
+	
+	printf("same:");
+	
+	for (count = 0; count < mr->rangesize; count++) {
+		struct nf_nat_range *r = &mr->range[count];
+		struct in_addr a;
+
+		a.s_addr = r->min_ip;
+
+		printf("%s", xtables_ipaddr_to_numeric(&a));
+		a.s_addr = r->max_ip;
+		
+		if (r->min_ip == r->max_ip)
+			printf(" ");
+		else
+			printf("-%s ", xtables_ipaddr_to_numeric(&a));
+		if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) 
+			random_selection = 1;
+	}
+	
+	if (mr->info & IPT_SAME_NODST)
+		printf("nodst ");
+
+	if (random_selection)
+		printf("random ");
+}
+
+static void SAME_save(const void *ip, const struct xt_entry_target *target)
+{
+	unsigned int count;
+	struct ipt_same_info *mr
+		= (struct ipt_same_info *)target->data;
+	int random_selection = 0;
+
+	for (count = 0; count < mr->rangesize; count++) {
+		struct nf_nat_range *r = &mr->range[count];
+		struct in_addr a;
+
+		a.s_addr = r->min_ip;
+		printf("--to %s", xtables_ipaddr_to_numeric(&a));
+		a.s_addr = r->max_ip;
+
+		if (r->min_ip == r->max_ip)
+			printf(" ");
+		else
+			printf("-%s ", xtables_ipaddr_to_numeric(&a));
+		if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) 
+			random_selection = 1;
+	}
+	
+	if (mr->info & IPT_SAME_NODST)
+		printf("--nodst ");
+
+	if (random_selection)
+		printf("--random ");
+}
+
+static struct xtables_target same_tg_reg = {
+	.name		= "SAME",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct ipt_same_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ipt_same_info)),
+	.help		= SAME_help,
+	.init		= SAME_init,
+	.parse		= SAME_parse,
+	.final_check	= SAME_check,
+	.print		= SAME_print,
+	.save		= SAME_save,
+	.extra_opts	= SAME_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&same_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_SAME.man b/ap/app/iptables/extensions/libipt_SAME.man
new file mode 100755
index 0000000..b862aa4
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_SAME.man
@@ -0,0 +1,15 @@
+Similar to SNAT/DNAT depending on chain: it takes a range of addresses
+(`\-\-to 1.2.3.4\-1.2.3.7') and gives a client the same
+source-/destination-address for each connection.
+.TP
+\fB\-\-to\fP \fIipaddr\fP[\fB\-\fP\fIipaddr\fP]
+Addresses to map source to. May be specified more than once for
+multiple ranges.
+.TP
+\fB\-\-nodst\fP
+Don't use the destination-ip in the calculations when selecting the
+new source-ip
+.TP
+\fB\-\-random\fP
+Port mapping will be forcibly randomized to avoid attacks based on 
+port prediction (kernel >= 2.6.21).
diff --git a/ap/app/iptables/extensions/libipt_SET.c b/ap/app/iptables/extensions/libipt_SET.c
new file mode 100755
index 0000000..390a7d9
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_SET.c
@@ -0,0 +1,162 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ *                         Patrick Schaaf <bof@bof.de>
+ *                         Martin Josefsson <gandalf@wlug.westbo.se>
+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.  
+ */
+
+/* Shared library add-on to iptables to add IP set mangling target. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <ctype.h>
+
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ipt_set.h>
+#include "libipt_set.h"
+
+static void SET_help(void)
+{
+	printf("SET target options:\n"
+	       " --add-set name flags\n"
+	       " --del-set name flags\n"
+	       "		add/del src/dst IP/port from/to named sets,\n"
+	       "		where flags are the comma separated list of\n"
+	       "		'src' and 'dst'.\n");
+}
+
+static const struct option SET_opts[] = {
+	{"add-set",   1, NULL, '1'},
+	{"del-set",   1, NULL, '2'},
+	{ }
+};
+
+static void SET_init(struct xt_entry_target *target)
+{
+	struct ipt_set_info_target *info =
+	    (struct ipt_set_info_target *) target->data;
+
+	memset(info, 0, sizeof(struct ipt_set_info_target));
+	info->add_set.index =
+	info->del_set.index = IP_SET_INVALID_ID;
+
+}
+
+static void
+parse_target(char **argv, int invert, unsigned int *flags,
+             struct ipt_set_info *info, const char *what)
+{
+	if (info->flags[0])
+		xtables_error(PARAMETER_PROBLEM,
+			   "--%s can be specified only once", what);
+
+	if (xtables_check_inverse(optarg, &invert, NULL, 0))
+		xtables_error(PARAMETER_PROBLEM,
+			   "Unexpected `!' after --%s", what);
+
+	if (!argv[optind]
+	    || argv[optind][0] == '-' || argv[optind][0] == '!')
+		xtables_error(PARAMETER_PROBLEM,
+			   "--%s requires two args.", what);
+
+	if (strlen(argv[optind-1]) > IP_SET_MAXNAMELEN - 1)
+		xtables_error(PARAMETER_PROBLEM,
+			   "setname `%s' too long, max %d characters.",
+			   argv[optind-1], IP_SET_MAXNAMELEN - 1);
+
+	strcpy(info->setname, argv[optind - 1]);
+	parse_bindings(argv[optind], info);
+	optind++;
+	
+	*flags = 1;
+}
+
+static int SET_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_target **target)
+{
+	struct ipt_set_info_target *myinfo =
+	    (struct ipt_set_info_target *) (*target)->data;
+
+	switch (c) {
+	case '1':		/* --add-set <set> <flags> */
+		parse_target(argv, invert, flags,
+			     &myinfo->add_set, "add-set");
+		break;
+	case '2':		/* --del-set <set>[:<flags>] <flags> */
+		parse_target(argv, invert, flags,
+			     &myinfo->del_set, "del-set");
+		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static void SET_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "You must specify either `--add-set' or `--del-set'");
+}
+
+static void
+print_target(const char *prefix, const struct ipt_set_info *info)
+{
+	int i;
+
+	printf("%s %s", prefix, info->setname);
+	for (i = 0; i < IP_SET_MAX_BINDINGS; i++) {
+		if (!info->flags[i])
+			break;		
+		printf("%s%s",
+		       i == 0 ? " " : ",",
+		       info->flags[i] & IPSET_SRC ? "src" : "dst");
+	}
+	printf(" ");
+}
+
+static void SET_print(const void *ip, const struct xt_entry_target *target,
+                      int numeric)
+{
+	struct ipt_set_info_target *info =
+	    (struct ipt_set_info_target *) target->data;
+
+	print_target("add-set", &info->add_set);
+	print_target("del-set", &info->del_set);
+}
+
+static void SET_save(const void *ip, const struct xt_entry_target *target)
+{
+	struct ipt_set_info_target *info =
+	    (struct ipt_set_info_target *) target->data;
+
+	print_target("--add-set", &info->add_set);
+	print_target("--del-set", &info->del_set);
+}
+
+static struct xtables_target set_tg_reg = {
+	.name		= "SET",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct ipt_set_info_target)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ipt_set_info_target)),
+	.help		= SET_help,
+	.init		= SET_init,
+	.parse		= SET_parse,
+	.final_check	= SET_check,
+	.print		= SET_print,
+	.save		= SET_save,
+	.extra_opts	= SET_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&set_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_SET.man b/ap/app/iptables/extensions/libipt_SET.man
new file mode 100755
index 0000000..a3e17e2
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_SET.man
@@ -0,0 +1,16 @@
+This modules adds and/or deletes entries from IP sets which can be defined 
+by ipset(8).
+.TP
+\fB\-\-add\-set\fP \fIsetname\fP \fIflag\fP[\fB,\fP\fIflag\fP...]
+add the address(es)/port(s) of the packet to the sets
+.TP
+\fB\-\-del\-set\fP \fIsetname\fP \fIflag\fP[\fB,\fP\fIflag\fP...]
+delete the address(es)/port(s) of the packet from the sets,
+where flags are
+.BR "src"
+and/or
+.BR "dst"
+and there can be no more than six of them.
+.PP
+The bindings to follow must previously be defined in order to use 
+multilevel adding/deleting by the SET target.
diff --git a/ap/app/iptables/extensions/libipt_SNAT.c b/ap/app/iptables/extensions/libipt_SNAT.c
new file mode 100755
index 0000000..944fe67
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_SNAT.c
@@ -0,0 +1,260 @@
+/* Shared library add-on to iptables to add source-NAT support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <iptables.h>
+#include <limits.h> /* INT_MAX in ip_tables.h */
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <net/netfilter/nf_nat.h>
+
+#define IPT_SNAT_OPT_SOURCE 0x01
+#define IPT_SNAT_OPT_RANDOM 0x02
+
+/* Source NAT data consists of a multi-range, indicating where to map
+   to. */
+struct ipt_natinfo
+{
+	struct xt_entry_target t;
+	struct nf_nat_multi_range mr;
+};
+
+static void SNAT_help(void)
+{
+	printf(
+"SNAT target options:\n"
+" --to-source <ipaddr>[-<ipaddr>][:port-port]\n"
+"				Address to map source to.\n"
+"[--random]\n");
+}
+
+static const struct option SNAT_opts[] = {
+	{ "to-source", 1, NULL, '1' },
+	{ "random", 0, NULL, '2' },
+	{ .name = NULL }
+};
+
+static struct ipt_natinfo *
+append_range(struct ipt_natinfo *info, const struct nf_nat_range *range)
+{
+	unsigned int size;
+
+	/* One rangesize already in struct ipt_natinfo */
+	size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
+
+	info = realloc(info, size);
+	if (!info)
+		xtables_error(OTHER_PROBLEM, "Out of memory\n");
+
+	info->t.u.target_size = size;
+	info->mr.range[info->mr.rangesize] = *range;
+	info->mr.rangesize++;
+
+	return info;
+}
+
+/* Ranges expected in network order. */
+static struct xt_entry_target *
+parse_to(char *arg, int portok, struct ipt_natinfo *info)
+{
+	struct nf_nat_range range;
+	char *colon, *dash, *error;
+	const struct in_addr *ip;
+
+	memset(&range, 0, sizeof(range));
+	colon = strchr(arg, ':');
+
+	if (colon) {
+		int port;
+
+		if (!portok)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Need TCP, UDP, SCTP or DCCP with port specification");
+
+		range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+		port = atoi(colon+1);
+		if (port <= 0 || port > 65535)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Port `%s' not valid\n", colon+1);
+
+		error = strchr(colon+1, ':');
+		if (error)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Invalid port:port syntax - use dash\n");
+
+		dash = strchr(colon, '-');
+		if (!dash) {
+			range.min.tcp.port
+				= range.max.tcp.port
+				= htons(port);
+		} else {
+			int maxport;
+
+			maxport = atoi(dash + 1);
+			if (maxport <= 0 || maxport > 65535)
+				xtables_error(PARAMETER_PROBLEM,
+					   "Port `%s' not valid\n", dash+1);
+			if (maxport < port)
+				/* People are stupid. */
+				xtables_error(PARAMETER_PROBLEM,
+					   "Port range `%s' funky\n", colon+1);
+			range.min.tcp.port = htons(port);
+			range.max.tcp.port = htons(maxport);
+		}
+		/* Starts with a colon? No IP info...*/
+		if (colon == arg)
+			return &(append_range(info, &range)->t);
+		*colon = '\0';
+	}
+
+	range.flags |= IP_NAT_RANGE_MAP_IPS;
+	dash = strchr(arg, '-');
+	if (colon && dash && dash > colon)
+		dash = NULL;
+
+	if (dash)
+		*dash = '\0';
+
+	ip = xtables_numeric_to_ipaddr(arg);
+	if (!ip)
+		xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
+			   arg);
+	range.min_ip = ip->s_addr;
+	if (dash) {
+		ip = xtables_numeric_to_ipaddr(dash+1);
+		if (!ip)
+			xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
+				   dash+1);
+		range.max_ip = ip->s_addr;
+	} else
+		range.max_ip = range.min_ip;
+
+	return &(append_range(info, &range)->t);
+}
+
+static int SNAT_parse(int c, char **argv, int invert, unsigned int *flags,
+                      const void *e, struct xt_entry_target **target)
+{
+	const struct ipt_entry *entry = e;
+	struct ipt_natinfo *info = (void *)*target;
+	int portok;
+
+	if (entry->ip.proto == IPPROTO_TCP
+	    || entry->ip.proto == IPPROTO_UDP
+	    || entry->ip.proto == IPPROTO_SCTP
+	    || entry->ip.proto == IPPROTO_DCCP
+	    || entry->ip.proto == IPPROTO_ICMP)
+		portok = 1;
+	else
+		portok = 0;
+
+	switch (c) {
+	case '1':
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --to-source");
+
+		if (*flags & IPT_SNAT_OPT_SOURCE) {
+			if (!kernel_version)
+				get_kernel_version();
+			if (kernel_version > LINUX_VERSION(2, 6, 10))
+				xtables_error(PARAMETER_PROBLEM,
+					   "Multiple --to-source not supported");
+		}
+		*target = parse_to(optarg, portok, info);
+		/* WTF do we need this for?? */
+		if (*flags & IPT_SNAT_OPT_RANDOM)
+			info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
+		*flags |= IPT_SNAT_OPT_SOURCE;
+		return 1;
+
+	case '2':
+		if (*flags & IPT_SNAT_OPT_SOURCE) {
+			info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
+			*flags |= IPT_SNAT_OPT_RANDOM;
+		} else
+			*flags |= IPT_SNAT_OPT_RANDOM;
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+static void SNAT_check(unsigned int flags)
+{
+	if (!(flags & IPT_SNAT_OPT_SOURCE))
+		xtables_error(PARAMETER_PROBLEM,
+			   "You must specify --to-source");
+}
+
+static void print_range(const struct nf_nat_range *r)
+{
+	if (r->flags & IP_NAT_RANGE_MAP_IPS) {
+		struct in_addr a;
+
+		a.s_addr = r->min_ip;
+		printf("%s", xtables_ipaddr_to_numeric(&a));
+		if (r->max_ip != r->min_ip) {
+			a.s_addr = r->max_ip;
+			printf("-%s", xtables_ipaddr_to_numeric(&a));
+		}
+	}
+	if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+		printf(":");
+		printf("%hu", ntohs(r->min.tcp.port));
+		if (r->max.tcp.port != r->min.tcp.port)
+			printf("-%hu", ntohs(r->max.tcp.port));
+	}
+}
+
+static void SNAT_print(const void *ip, const struct xt_entry_target *target,
+                       int numeric)
+{
+	struct ipt_natinfo *info = (void *)target;
+	unsigned int i = 0;
+
+	printf("to:");
+	for (i = 0; i < info->mr.rangesize; i++) {
+		print_range(&info->mr.range[i]);
+		printf(" ");
+		if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM)
+			printf("random ");
+	}
+}
+
+static void SNAT_save(const void *ip, const struct xt_entry_target *target)
+{
+	struct ipt_natinfo *info = (void *)target;
+	unsigned int i = 0;
+
+	for (i = 0; i < info->mr.rangesize; i++) {
+		printf("--to-source ");
+		print_range(&info->mr.range[i]);
+		printf(" ");
+		if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM)
+			printf("--random ");
+	}
+}
+
+static struct xtables_target snat_tg_reg = {
+	.name		= "SNAT",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct nf_nat_multi_range)),
+	.userspacesize	= XT_ALIGN(sizeof(struct nf_nat_multi_range)),
+	.help		= SNAT_help,
+	.parse		= SNAT_parse,
+	.final_check	= SNAT_check,
+	.print		= SNAT_print,
+	.save		= SNAT_save,
+	.extra_opts	= SNAT_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&snat_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_SNAT.man b/ap/app/iptables/extensions/libipt_SNAT.man
new file mode 100755
index 0000000..040571b
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_SNAT.man
@@ -0,0 +1,34 @@
+This target is only valid in the
+.B nat
+table, in the
+.B POSTROUTING
+chain.  It specifies that the source address of the packet should be
+modified (and all future packets in this connection will also be
+mangled), and rules should cease being examined.  It takes one type
+of option:
+.TP
+\fB\-\-to\-source\fP \fIipaddr\fP[\fB\-\fP\fIipaddr\fP][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP]]
+which can specify a single new source IP address, an inclusive range
+of IP addresses, and optionally, a port range (which is only valid if
+the rule also specifies
+\fB\-p tcp\fP
+or
+\fB\-p udp\fP).
+If no port range is specified, then source ports below 512 will be
+mapped to other ports below 512: those between 512 and 1023 inclusive
+will be mapped to ports below 1024, and other ports will be mapped to
+1024 or above. Where possible, no port alteration will
+
+In Kernels up to 2.6.10, you can add several \-\-to\-source options. For those
+kernels, if you specify more than one source address, either via an address
+range or multiple \-\-to\-source options, a simple round-robin (one after another
+in cycle) takes place between these addresses.
+Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges
+anymore.
+.TP
+\fB\-\-random\fP
+If option
+\fB\-\-random\fP
+is used then port mapping will be randomized (kernel >= 2.6.21).
+.RS
+.PP
diff --git a/ap/app/iptables/extensions/libipt_TTL.c b/ap/app/iptables/extensions/libipt_TTL.c
new file mode 100755
index 0000000..0e2be0b
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_TTL.c
@@ -0,0 +1,157 @@
+/* Shared library add-on to iptables for the TTL target
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ *
+ * $Id$
+ *
+ * This program is distributed under the terms of GNU GPL
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+
+#include <linux/netfilter_ipv4/ipt_TTL.h>
+
+#define IPT_TTL_USED	1
+
+static void TTL_help(void)
+{
+	printf(
+"TTL target options\n"
+"  --ttl-set value		Set TTL to <value 0-255>\n"
+"  --ttl-dec value		Decrement TTL by <value 1-255>\n"
+"  --ttl-inc value		Increment TTL by <value 1-255>\n");
+}
+
+static int TTL_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_target **target)
+{
+	struct ipt_TTL_info *info = (struct ipt_TTL_info *) (*target)->data;
+	unsigned int value;
+
+	if (*flags & IPT_TTL_USED) {
+		xtables_error(PARAMETER_PROBLEM,
+				"Can't specify TTL option twice");
+	}
+
+	if (!optarg) 
+		xtables_error(PARAMETER_PROBLEM,
+				"TTL: You must specify a value");
+
+	if (xtables_check_inverse(optarg, &invert, NULL, 0))
+		xtables_error(PARAMETER_PROBLEM,
+				"TTL: unexpected `!'");
+	
+	if (!xtables_strtoui(optarg, NULL, &value, 0, UINT8_MAX))
+		xtables_error(PARAMETER_PROBLEM,
+		           "TTL: Expected value between 0 and 255");
+
+	switch (c) {
+
+		case '1':
+			info->mode = IPT_TTL_SET;
+			break;
+
+		case '2':
+			if (value == 0) {
+				xtables_error(PARAMETER_PROBLEM,
+					"TTL: decreasing by 0?");
+			}
+
+			info->mode = IPT_TTL_DEC;
+			break;
+
+		case '3':
+			if (value == 0) {
+				xtables_error(PARAMETER_PROBLEM,
+					"TTL: increasing by 0?");
+			}
+
+			info->mode = IPT_TTL_INC;
+			break;
+
+		default:
+			return 0;
+
+	}
+	
+	info->ttl = value;
+	*flags |= IPT_TTL_USED;
+
+	return 1;
+}
+
+static void TTL_check(unsigned int flags)
+{
+	if (!(flags & IPT_TTL_USED))
+		xtables_error(PARAMETER_PROBLEM,
+				"TTL: You must specify an action");
+}
+
+static void TTL_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct ipt_TTL_info *info = 
+		(struct ipt_TTL_info *) target->data;
+
+	switch (info->mode) {
+		case IPT_TTL_SET:
+			printf("--ttl-set ");
+			break;
+		case IPT_TTL_DEC:
+			printf("--ttl-dec ");
+			break;
+
+		case IPT_TTL_INC:
+			printf("--ttl-inc ");
+			break;
+	}
+	printf("%u ", info->ttl);
+}
+
+static void TTL_print(const void *ip, const struct xt_entry_target *target,
+                      int numeric)
+{
+	const struct ipt_TTL_info *info =
+		(struct ipt_TTL_info *) target->data;
+
+	printf("TTL ");
+	switch (info->mode) {
+		case IPT_TTL_SET:
+			printf("set to ");
+			break;
+		case IPT_TTL_DEC:
+			printf("decrement by ");
+			break;
+		case IPT_TTL_INC:
+			printf("increment by ");
+			break;
+	}
+	printf("%u ", info->ttl);
+}
+
+static const struct option TTL_opts[] = {
+	{ "ttl-set", 1, NULL, '1' },
+	{ "ttl-dec", 1, NULL, '2' },
+	{ "ttl-inc", 1, NULL, '3' },
+	{ .name = NULL }
+};
+
+static struct xtables_target ttl_tg_reg = {
+	.name		= "TTL",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct ipt_TTL_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ipt_TTL_info)),
+	.help		= TTL_help,
+	.parse		= TTL_parse,
+	.final_check	= TTL_check,
+	.print		= TTL_print,
+	.save		= TTL_save,
+	.extra_opts	= TTL_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&ttl_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_TTL.man b/ap/app/iptables/extensions/libipt_TTL.man
new file mode 100755
index 0000000..89fc18f
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_TTL.man
@@ -0,0 +1,19 @@
+This is used to modify the IPv4 TTL header field.  The TTL field determines
+how many hops (routers) a packet can traverse until it's time to live is
+exceeded.
+.PP
+Setting or incrementing the TTL field can potentially be very dangerous,
+so it should be avoided at any cost.  
+.PP
+.B Don't ever set or increment the value on packets that leave your local network!
+.B mangle
+table.
+.TP
+\fB\-\-ttl\-set\fP \fIvalue\fP
+Set the TTL value to `value'.
+.TP
+\fB\-\-ttl\-dec\fP \fIvalue\fP
+Decrement the TTL value `value' times.
+.TP
+\fB\-\-ttl\-inc\fP \fIvalue\fP
+Increment the TTL value `value' times.
diff --git a/ap/app/iptables/extensions/libipt_ULOG.c b/ap/app/iptables/extensions/libipt_ULOG.c
new file mode 100755
index 0000000..3fa91f2
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_ULOG.c
@@ -0,0 +1,198 @@
+/* Shared library add-on to iptables to add ULOG support.
+ * 
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ *
+ * multipart netlink support based on ideas by Sebastian Zander 
+ * 						<zander@fokus.gmd.de>
+ *
+ * This software is released under the terms of GNU GPL
+ * 
+ * libipt_ULOG.c,v 1.7 2001/01/30 11:55:02 laforge Exp
+ */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <xtables.h>
+/* For 64bit kernel / 32bit userspace */
+#include <linux/netfilter_ipv4/ipt_ULOG.h>
+
+
+static void print_groups(unsigned int gmask)
+{
+	int b;
+	unsigned int test;
+
+	for (b = 31; b >= 0; b--) {
+		test = (1 << b);
+		if (gmask & test)
+			printf("%d ", b + 1);
+	}
+}
+
+static void ULOG_help(void)
+{
+	printf("ULOG target options:\n"
+	       " --ulog-nlgroup nlgroup		NETLINK group used for logging\n"
+	       " --ulog-cprange size		Bytes of each packet to be passed\n"
+	       " --ulog-qthreshold		Threshold of in-kernel queue\n"
+	       " --ulog-prefix prefix		Prefix log messages with this prefix.\n");
+}
+
+static const struct option ULOG_opts[] = {
+	{"ulog-nlgroup", 1, NULL, '!'},
+	{"ulog-prefix", 1, NULL, '#'},
+	{"ulog-cprange", 1, NULL, 'A'},
+	{"ulog-qthreshold", 1, NULL, 'B'},
+	{ .name = NULL }
+};
+
+static void ULOG_init(struct xt_entry_target *t)
+{
+	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) t->data;
+
+	loginfo->nl_group = ULOG_DEFAULT_NLGROUP;
+	loginfo->qthreshold = ULOG_DEFAULT_QTHRESHOLD;
+
+}
+
+#define IPT_LOG_OPT_NLGROUP 0x01
+#define IPT_LOG_OPT_PREFIX 0x02
+#define IPT_LOG_OPT_CPRANGE 0x04
+#define IPT_LOG_OPT_QTHRESHOLD 0x08
+
+static int ULOG_parse(int c, char **argv, int invert, unsigned int *flags,
+                      const void *entry, struct xt_entry_target **target)
+{
+	struct ipt_ulog_info *loginfo =
+	    (struct ipt_ulog_info *) (*target)->data;
+	int group_d;
+
+	switch (c) {
+	case '!':
+		if (*flags & IPT_LOG_OPT_NLGROUP)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --ulog-nlgroup twice");
+
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --ulog-nlgroup");
+		group_d = atoi(optarg);
+		if (group_d > 32 || group_d < 1)
+			xtables_error(PARAMETER_PROBLEM,
+				   "--ulog-nlgroup has to be between 1 and 32");
+
+		loginfo->nl_group = (1 << (group_d - 1));
+
+		*flags |= IPT_LOG_OPT_NLGROUP;
+		break;
+
+	case '#':
+		if (*flags & IPT_LOG_OPT_PREFIX)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --ulog-prefix twice");
+
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --ulog-prefix");
+
+		if (strlen(optarg) > sizeof(loginfo->prefix) - 1)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Maximum prefix length %u for --ulog-prefix",
+				   (unsigned int)sizeof(loginfo->prefix) - 1);
+
+		if (strlen(optarg) == 0)
+			xtables_error(PARAMETER_PROBLEM,
+				   "No prefix specified for --ulog-prefix");
+
+		if (strlen(optarg) != strlen(strtok(optarg, "\n")))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Newlines not allowed in --ulog-prefix");
+
+		strcpy(loginfo->prefix, optarg);
+		*flags |= IPT_LOG_OPT_PREFIX;
+		break;
+	case 'A':
+		if (*flags & IPT_LOG_OPT_CPRANGE)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --ulog-cprange twice");
+		if (atoi(optarg) < 0)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Negative copy range?");
+		loginfo->copy_range = atoi(optarg);
+		*flags |= IPT_LOG_OPT_CPRANGE;
+		break;
+	case 'B':
+		if (*flags & IPT_LOG_OPT_QTHRESHOLD)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --ulog-qthreshold twice");
+		if (atoi(optarg) < 1)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Negative or zero queue threshold ?");
+		if (atoi(optarg) > ULOG_MAX_QLEN)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Maximum queue length exceeded");
+		loginfo->qthreshold = atoi(optarg);
+		*flags |= IPT_LOG_OPT_QTHRESHOLD;
+		break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static void ULOG_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct ipt_ulog_info *loginfo
+	    = (const struct ipt_ulog_info *) target->data;
+
+	if (strcmp(loginfo->prefix, "") != 0) {
+		fputs("--ulog-prefix ", stdout);
+		xtables_save_string(loginfo->prefix);
+	}
+
+	if (loginfo->nl_group != ULOG_DEFAULT_NLGROUP) {
+		printf("--ulog-nlgroup ");
+		print_groups(loginfo->nl_group);
+	}
+	if (loginfo->copy_range)
+		printf("--ulog-cprange %u ", (unsigned int)loginfo->copy_range);
+
+	if (loginfo->qthreshold != ULOG_DEFAULT_QTHRESHOLD)
+		printf("--ulog-qthreshold %u ", (unsigned int)loginfo->qthreshold);
+}
+
+static void ULOG_print(const void *ip, const struct xt_entry_target *target,
+                       int numeric)
+{
+	const struct ipt_ulog_info *loginfo
+	    = (const struct ipt_ulog_info *) target->data;
+
+	printf("ULOG ");
+	printf("copy_range %u nlgroup ", (unsigned int)loginfo->copy_range);
+	print_groups(loginfo->nl_group);
+	if (strcmp(loginfo->prefix, "") != 0)
+		printf("prefix `%s' ", loginfo->prefix);
+	printf("queue_threshold %u ", (unsigned int)loginfo->qthreshold);
+}
+
+static struct xtables_target ulog_tg_reg = {
+	.name		= "ULOG",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct ipt_ulog_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ipt_ulog_info)),
+	.help		= ULOG_help,
+	.init		= ULOG_init,
+	.parse		= ULOG_parse,
+	.print		= ULOG_print,
+	.save		= ULOG_save,
+	.extra_opts	= ULOG_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&ulog_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_ULOG.man b/ap/app/iptables/extensions/libipt_ULOG.man
new file mode 100755
index 0000000..649b6e3
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_ULOG.man
@@ -0,0 +1,27 @@
+This target provides userspace logging of matching packets.  When this
+target is set for a rule, the Linux kernel will multicast this packet
+through a
+.IR netlink 
+socket. One or more userspace processes may then subscribe to various 
+multicast groups and receive the packets.
+Like LOG, this is a "non-terminating target", i.e. rule traversal
+continues at the next rule.
+.TP
+\fB\-\-ulog\-nlgroup\fP \fInlgroup\fP
+This specifies the netlink group (1-32) to which the packet is sent.
+Default value is 1.
+.TP
+\fB\-\-ulog\-prefix\fP \fIprefix\fP
+Prefix log messages with the specified prefix; up to 32 characters
+long, and useful for distinguishing messages in the logs.
+.TP
+\fB\-\-ulog\-cprange\fP \fIsize\fP
+Number of bytes to be copied to userspace.  A value of 0 always copies
+the entire packet, regardless of its size.  Default is 0.
+.TP
+\fB\-\-ulog\-qthreshold\fP \fIsize\fP
+Number of packet to queue inside kernel.  Setting this value to, e.g. 10
+accumulates ten packets inside the kernel and transmits them as one
+netlink multipart message to userspace.  Default is 1 (for backwards
+compatibility).
+.br
diff --git a/ap/app/iptables/extensions/libipt_addrtype.c b/ap/app/iptables/extensions/libipt_addrtype.c
new file mode 100755
index 0000000..ecd51b5
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_addrtype.c
@@ -0,0 +1,360 @@
+/* Shared library add-on to iptables to add addrtype matching support 
+ * 
+ * This program is released under the terms of GNU GPL */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <xtables.h>
+
+#include <linux/netfilter_ipv4/ipt_addrtype.h>
+
+/* from linux/rtnetlink.h, must match order of enumeration */
+static const char *const rtn_names[] = {
+	"UNSPEC",
+	"UNICAST",
+	"LOCAL",
+	"BROADCAST",
+	"ANYCAST",
+	"MULTICAST",
+	"BLACKHOLE",
+	"UNREACHABLE",
+	"PROHIBIT",
+	"THROW",
+	"NAT",
+	"XRESOLVE",
+	NULL
+};
+
+static void addrtype_help_types(void)
+{
+	int i;
+
+	for (i = 0; rtn_names[i]; i++)
+		printf("                                %s\n", rtn_names[i]);
+}
+
+static void addrtype_help_v0(void)
+{
+	printf(
+"Address type match options:\n"
+" [!] --src-type type[,...]      Match source address type\n"
+" [!] --dst-type type[,...]      Match destination address type\n"
+"\n"
+"Valid types:           \n");
+	addrtype_help_types();
+}
+
+static void addrtype_help_v1(void)
+{
+	printf(
+"Address type match options:\n"
+" [!] --src-type type[,...]      Match source address type\n"
+" [!] --dst-type type[,...]      Match destination address type\n"
+"     --limit-iface-in           Match only on the packet's incoming device\n"
+"     --limit-iface-out          Match only on the packet's incoming device\n"
+"\n"
+"Valid types:           \n");
+	addrtype_help_types();
+}
+
+static int
+parse_type(const char *name, size_t len, u_int16_t *mask)
+{
+	int i;
+
+	for (i = 0; rtn_names[i]; i++)
+		if (strncasecmp(name, rtn_names[i], len) == 0) {
+			/* build up bitmask for kernel module */
+			*mask |= (1 << i);
+			return 1;
+		}
+
+	return 0;
+}
+
+static void parse_types(const char *arg, u_int16_t *mask)
+{
+	const char *comma;
+
+	while ((comma = strchr(arg, ',')) != NULL) {
+		if (comma == arg || !parse_type(arg, comma-arg, mask))
+			xtables_error(PARAMETER_PROBLEM,
+			           "addrtype: bad type `%s'", arg);
+		arg = comma + 1;
+	}
+
+	if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask))
+		xtables_error(PARAMETER_PROBLEM, "addrtype: bad type \"%s\"", arg);
+}
+	
+#define IPT_ADDRTYPE_OPT_SRCTYPE	0x1
+#define IPT_ADDRTYPE_OPT_DSTTYPE	0x2
+#define IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN		0x4
+#define IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT	0x8
+
+static int
+addrtype_parse_v0(int c, char **argv, int invert, unsigned int *flags,
+                  const void *entry, struct xt_entry_match **match)
+{
+	struct ipt_addrtype_info *info =
+		(struct ipt_addrtype_info *) (*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags&IPT_ADDRTYPE_OPT_SRCTYPE)
+			xtables_error(PARAMETER_PROBLEM,
+			           "addrtype: can't specify src-type twice");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_types(argv[optind-1], &info->source);
+		if (invert)
+			info->invert_source = 1;
+		*flags |= IPT_ADDRTYPE_OPT_SRCTYPE;
+		break;
+	case '2':
+		if (*flags&IPT_ADDRTYPE_OPT_DSTTYPE)
+			xtables_error(PARAMETER_PROBLEM,
+			           "addrtype: can't specify dst-type twice");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_types(argv[optind-1], &info->dest);
+		if (invert)
+			info->invert_dest = 1;
+		*flags |= IPT_ADDRTYPE_OPT_DSTTYPE;
+		break;
+	default:
+		return 0;
+	}
+	
+	return 1;
+}
+
+static int
+addrtype_parse_v1(int c, char **argv, int invert, unsigned int *flags,
+                  const void *entry, struct xt_entry_match **match)
+{
+	struct ipt_addrtype_info_v1 *info =
+		(struct ipt_addrtype_info_v1 *) (*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & IPT_ADDRTYPE_OPT_SRCTYPE)
+			xtables_error(PARAMETER_PROBLEM,
+			           "addrtype: can't specify src-type twice");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_types(argv[optind-1], &info->source);
+		if (invert)
+			info->flags |= IPT_ADDRTYPE_INVERT_SOURCE;
+		*flags |= IPT_ADDRTYPE_OPT_SRCTYPE;
+		break;
+	case '2':
+		if (*flags & IPT_ADDRTYPE_OPT_DSTTYPE)
+			xtables_error(PARAMETER_PROBLEM,
+			           "addrtype: can't specify dst-type twice");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_types(argv[optind-1], &info->dest);
+		if (invert)
+			info->flags |= IPT_ADDRTYPE_INVERT_DEST;
+		*flags |= IPT_ADDRTYPE_OPT_DSTTYPE;
+		break;
+	case '3':
+		if (*flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN)
+			xtables_error(PARAMETER_PROBLEM,
+			           "addrtype: can't specify limit-iface-in twice");
+		info->flags |= IPT_ADDRTYPE_LIMIT_IFACE_IN;
+		*flags |= IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN;
+		break;
+	case '4':
+		if (*flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT)
+			xtables_error(PARAMETER_PROBLEM,
+			           "addrtype: can't specify limit-iface-out twice");
+		info->flags |= IPT_ADDRTYPE_LIMIT_IFACE_OUT;
+		*flags |= IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT;
+		break;
+	default:
+		return 0;
+	}
+	
+	return 1;
+}
+
+static void addrtype_check_v0(unsigned int flags)
+{
+	if (!(flags & (IPT_ADDRTYPE_OPT_SRCTYPE|IPT_ADDRTYPE_OPT_DSTTYPE)))
+		xtables_error(PARAMETER_PROBLEM,
+			   "addrtype: you must specify --src-type or --dst-type");
+}
+
+static void addrtype_check_v1(unsigned int flags)
+{
+	if (!(flags & (IPT_ADDRTYPE_OPT_SRCTYPE|IPT_ADDRTYPE_OPT_DSTTYPE)))
+		xtables_error(PARAMETER_PROBLEM,
+			   "addrtype: you must specify --src-type or --dst-type");
+	if (flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN &&
+	    flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT)
+		xtables_error(PARAMETER_PROBLEM,
+			   "addrtype: you can't specify both --limit-iface-in "
+			   "and --limit-iface-out");
+}
+
+static void print_types(u_int16_t mask)
+{
+	const char *sep = "";
+	int i;
+
+	for (i = 0; rtn_names[i]; i++)
+		if (mask & (1 << i)) {
+			printf("%s%s", sep, rtn_names[i]);
+			sep = ",";
+		}
+
+	printf(" ");
+}
+
+static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match,
+                              int numeric)
+{
+	const struct ipt_addrtype_info *info = 
+		(struct ipt_addrtype_info *) match->data;
+
+	printf("ADDRTYPE match ");
+	if (info->source) {
+		printf("src-type ");
+		if (info->invert_source)
+			printf("!");
+		print_types(info->source);
+	}
+	if (info->dest) {
+		printf("dst-type ");
+		if (info->invert_dest)
+			printf("!");
+		print_types(info->dest);
+	}
+}
+
+static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match,
+                              int numeric)
+{
+	const struct ipt_addrtype_info_v1 *info = 
+		(struct ipt_addrtype_info_v1 *) match->data;
+
+	printf("ADDRTYPE match ");
+	if (info->source) {
+		printf("src-type ");
+		if (info->flags & IPT_ADDRTYPE_INVERT_SOURCE)
+			printf("!");
+		print_types(info->source);
+	}
+	if (info->dest) {
+		printf("dst-type ");
+		if (info->flags & IPT_ADDRTYPE_INVERT_DEST)
+			printf("!");
+		print_types(info->dest);
+	}
+	if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN) {
+		printf("limit-in ");
+	}
+	if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) {
+		printf("limit-out ");
+	}
+}
+
+static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ipt_addrtype_info *info =
+		(struct ipt_addrtype_info *) match->data;
+
+	if (info->source) {
+		if (info->invert_source)
+			printf("! ");
+		printf("--src-type ");
+		print_types(info->source);
+	}
+	if (info->dest) {
+		if (info->invert_dest)
+			printf("! ");
+		printf("--dst-type ");
+		print_types(info->dest);
+	}
+}
+
+static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ipt_addrtype_info_v1 *info =
+		(struct ipt_addrtype_info_v1 *) match->data;
+
+	if (info->source) {
+		if (info->flags & IPT_ADDRTYPE_INVERT_SOURCE)
+			printf("! ");
+		printf("--src-type ");
+		print_types(info->source);
+	}
+	if (info->dest) {
+		if (info->flags & IPT_ADDRTYPE_INVERT_DEST)
+			printf("! ");
+		printf("--dst-type ");
+		print_types(info->dest);
+	}
+	if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN) {
+		printf("--limit-iface-in ");
+	}
+	if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) {
+		printf("--limit-iface-out ");
+	}
+}
+
+static const struct option addrtype_opts[] = {
+	{ "src-type", 1, NULL, '1' },
+	{ "dst-type", 1, NULL, '2' },
+	{ .name = NULL }
+};
+
+static const struct option addrtype_opts_v0[] = {
+	{ "src-type", 1, NULL, '1' },
+	{ "dst-type", 1, NULL, '2' },
+	{ .name = NULL }
+};
+
+static const struct option addrtype_opts_v1[] = {
+	{ "src-type", 1, NULL, '1' },
+	{ "dst-type", 1, NULL, '2' },
+	{ "limit-iface-in", 0, NULL, '3' },
+	{ "limit-iface-out", 0, NULL, '4' },
+	{ .name = NULL }
+};
+
+static struct xtables_match addrtype_mt_reg_v0 = {
+	.name 		= "addrtype",
+	.version 	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size 		= XT_ALIGN(sizeof(struct ipt_addrtype_info)),
+	.userspacesize 	= XT_ALIGN(sizeof(struct ipt_addrtype_info)),
+	.help 		= addrtype_help_v0,
+	.parse 		= addrtype_parse_v0,
+	.final_check 	= addrtype_check_v0,
+	.print 		= addrtype_print_v0,
+	.save 		= addrtype_save_v0,
+	.extra_opts 	= addrtype_opts_v0,
+};
+
+static struct xtables_match addrtype_mt_reg_v1 = {
+	.name 		= "addrtype",
+	.version 	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size 		= XT_ALIGN(sizeof(struct ipt_addrtype_info_v1)),
+	.userspacesize 	= XT_ALIGN(sizeof(struct ipt_addrtype_info_v1)),
+	.help 		= addrtype_help_v1,
+	.parse 		= addrtype_parse_v1,
+	.final_check 	= addrtype_check_v1,
+	.print 		= addrtype_print_v1,
+	.save 		= addrtype_save_v1,
+	.extra_opts 	= addrtype_opts_v1,
+	.revision	= 1,
+};
+
+
+void _init(void) 
+{
+	xtables_register_match(&addrtype_mt_reg_v0);
+	xtables_register_match(&addrtype_mt_reg_v1);
+}
diff --git a/ap/app/iptables/extensions/libipt_addrtype.man b/ap/app/iptables/extensions/libipt_addrtype.man
new file mode 100755
index 0000000..731f9b1
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_addrtype.man
@@ -0,0 +1,69 @@
+This module matches packets based on their 
+.B address type.
+Address types are used within the kernel networking stack and categorize
+addresses into various groups.  The exact definition of that group depends on the specific layer three protocol.
+.PP
+The following address types are possible:
+.TP
+.BI "UNSPEC"
+an unspecified address (i.e. 0.0.0.0)
+.TP
+.BI "UNICAST"
+an unicast address
+.TP
+.BI "LOCAL"
+a local address
+.TP
+.BI "BROADCAST"
+a broadcast address
+.TP
+.BI "ANYCAST"
+an anycast packet
+.TP
+.BI "MULTICAST"
+a multicast address
+.TP
+.BI "BLACKHOLE"
+a blackhole address
+.TP
+.BI "UNREACHABLE"
+an unreachable address
+.TP
+.BI "PROHIBIT"
+a prohibited address
+.TP
+.BI "THROW"
+FIXME
+.TP
+.BI "NAT"
+FIXME
+.TP
+.BI "XRESOLVE"
+.TP
+[\fB!\fP] \fB\-\-src\-type\fP \fItype\fP
+Matches if the source address is of given type
+.TP
+[\fB!\fP] \fB\-\-dst\-type\fP \fItype\fP
+Matches if the destination address is of given type
+.TP
+.BI "\-\-limit\-iface\-in"
+The address type checking can be limited to the interface the packet is coming
+in. This option is only valid in the
+.BR PREROUTING ,
+.B INPUT
+and
+.B FORWARD
+chains. It cannot be specified with the
+\fB\-\-limit\-iface\-out\fP
+option.
+.TP
+\fB\-\-limit\-iface\-out\fP
+The address type checiking can be limited to the interface the packet is going
+out. This option is only valid in the
+.BR POSTROUTING ,
+.B OUTPUT
+and
+.B FORWARD
+chains. It cannot be specified with the
+\fB\-\-limit\-iface\-in\fP
+option.
diff --git a/ap/app/iptables/extensions/libipt_ah.c b/ap/app/iptables/extensions/libipt_ah.c
new file mode 100755
index 0000000..d049b42
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_ah.c
@@ -0,0 +1,170 @@
+/* Shared library add-on to iptables to add AH support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ipt_ah.h>
+
+static void ah_help(void)
+{
+	printf(
+"ah match options:\n"
+"[!] --ahspi spi[:spi]\n"
+"				match spi (range)\n");
+}
+
+static const struct option ah_opts[] = {
+	{ "ahspi", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static u_int32_t
+parse_ah_spi(const char *spistr)
+{
+	unsigned long int spi;
+	char* ep;
+
+	spi =  strtoul(spistr,&ep,0) ;
+
+	if ( spistr == ep ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "AH no valid digits in spi `%s'", spistr);
+	}
+	if ( spi == ULONG_MAX  && errno == ERANGE ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "spi `%s' specified too big: would overflow", spistr);
+	}	
+	if ( *spistr != '\0'  && *ep != '\0' ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "AH error parsing spi `%s'", spistr);
+	}
+	return spi;
+}
+
+static void
+parse_ah_spis(const char *spistring, u_int32_t *spis)
+{
+	char *buffer;
+	char *cp;
+
+	buffer = strdup(spistring);
+	if ((cp = strchr(buffer, ':')) == NULL)
+		spis[0] = spis[1] = parse_ah_spi(buffer);
+	else {
+		*cp = '\0';
+		cp++;
+
+		spis[0] = buffer[0] ? parse_ah_spi(buffer) : 0;
+		spis[1] = cp[0] ? parse_ah_spi(cp) : 0xFFFFFFFF;
+	}
+	free(buffer);
+}
+
+static void ah_init(struct xt_entry_match *m)
+{
+	struct ipt_ah *ahinfo = (struct ipt_ah *)m->data;
+
+	ahinfo->spis[1] = 0xFFFFFFFF;
+}
+
+#define AH_SPI 0x01
+
+static int ah_parse(int c, char **argv, int invert, unsigned int *flags,
+                    const void *entry, struct xt_entry_match **match)
+{
+	struct ipt_ah *ahinfo = (struct ipt_ah *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & AH_SPI)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--ahspi' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_ah_spis(argv[optind-1], ahinfo->spis);
+		if (invert)
+			ahinfo->invflags |= IPT_AH_INV_SPI;
+		*flags |= AH_SPI;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+print_spis(const char *name, u_int32_t min, u_int32_t max,
+	    int invert)
+{
+	const char *inv = invert ? "!" : "";
+
+	if (min != 0 || max != 0xFFFFFFFF || invert) {
+		printf("%s", name);
+		if (min == max) {
+			printf(":%s", inv);
+			printf("%u", min);
+		} else {
+			printf("s:%s", inv);
+			printf("%u",min);
+			printf(":");
+			printf("%u",max);
+		}
+		printf(" ");
+	}
+}
+
+static void ah_print(const void *ip, const struct xt_entry_match *match,
+                     int numeric)
+{
+	const struct ipt_ah *ah = (struct ipt_ah *)match->data;
+
+	printf("ah ");
+	print_spis("spi", ah->spis[0], ah->spis[1],
+		    ah->invflags & IPT_AH_INV_SPI);
+	if (ah->invflags & ~IPT_AH_INV_MASK)
+		printf("Unknown invflags: 0x%X ",
+		       ah->invflags & ~IPT_AH_INV_MASK);
+}
+
+static void ah_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ipt_ah *ahinfo = (struct ipt_ah *)match->data;
+
+	if (!(ahinfo->spis[0] == 0
+	    && ahinfo->spis[1] == 0xFFFFFFFF)) {
+		printf("%s--ahspi ",
+			(ahinfo->invflags & IPT_AH_INV_SPI) ? "! " : "");
+		if (ahinfo->spis[0]
+		    != ahinfo->spis[1])
+			printf("%u:%u ",
+			       ahinfo->spis[0],
+			       ahinfo->spis[1]);
+		else
+			printf("%u ",
+			       ahinfo->spis[0]);
+	}
+
+}
+
+static struct xtables_match ah_mt_reg = {
+	.name 		= "ah",
+	.version 	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct ipt_ah)),
+	.userspacesize 	= XT_ALIGN(sizeof(struct ipt_ah)),
+	.help 		= ah_help,
+	.init 		= ah_init,
+	.parse 		= ah_parse,
+	.print 		= ah_print,
+	.save 		= ah_save,
+	.extra_opts 	= ah_opts,
+};
+
+void
+_init(void)
+{
+	xtables_register_match(&ah_mt_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_ah.man b/ap/app/iptables/extensions/libipt_ah.man
new file mode 100755
index 0000000..d26455e
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_ah.man
@@ -0,0 +1,3 @@
+This module matches the SPIs in Authentication header of IPsec packets.
+.TP
+[\fB!\fP] \fB\-\-ahspi\fP \fIspi\fP[\fB:\fP\fIspi\fP]
diff --git a/ap/app/iptables/extensions/libipt_ecn.c b/ap/app/iptables/extensions/libipt_ecn.c
new file mode 100755
index 0000000..3ee190e
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_ecn.c
@@ -0,0 +1,160 @@
+/* Shared library add-on to iptables for ECN matching
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This program is distributed under the terms of GNU GPL v2, 1991
+ *
+ * libipt_ecn.c borrowed heavily from libipt_dscp.c
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ipt_ecn.h>
+
+static void ecn_help(void)
+{
+	printf(
+"ECN match options\n"
+"[!] --ecn-tcp-cwr 		Match CWR bit of TCP header\n"
+"[!] --ecn-tcp-ece		Match ECE bit of TCP header\n"
+"[!] --ecn-ip-ect [0..3]	Match ECN codepoint in IPv4 header\n");
+}
+
+static const struct option ecn_opts[] = {
+	{ .name = "ecn-tcp-cwr", .has_arg = 0, .val = 'F' },
+	{ .name = "ecn-tcp-ece", .has_arg = 0, .val = 'G' },
+	{ .name = "ecn-ip-ect",  .has_arg = 1, .val = 'H' },
+	{ .name = NULL }
+};
+
+static int ecn_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_match **match)
+{
+	unsigned int result;
+	struct ipt_ecn_info *einfo
+		= (struct ipt_ecn_info *)(*match)->data;
+
+	switch (c) {
+	case 'F':
+		if (*flags & IPT_ECN_OP_MATCH_CWR)
+			xtables_error(PARAMETER_PROBLEM,
+			           "ECN match: can only use parameter ONCE!");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		einfo->operation |= IPT_ECN_OP_MATCH_CWR;
+		if (invert)
+			einfo->invert |= IPT_ECN_OP_MATCH_CWR;
+		*flags |= IPT_ECN_OP_MATCH_CWR;
+		break;
+
+	case 'G':
+		if (*flags & IPT_ECN_OP_MATCH_ECE)
+			xtables_error(PARAMETER_PROBLEM,
+				   "ECN match: can only use parameter ONCE!");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		einfo->operation |= IPT_ECN_OP_MATCH_ECE;
+		if (invert)
+			einfo->invert |= IPT_ECN_OP_MATCH_ECE;
+		*flags |= IPT_ECN_OP_MATCH_ECE;
+		break;
+
+	case 'H':
+		if (*flags & IPT_ECN_OP_MATCH_IP)
+			xtables_error(PARAMETER_PROBLEM,
+				   "ECN match: can only use parameter ONCE!");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		if (invert)
+			einfo->invert |= IPT_ECN_OP_MATCH_IP;
+		*flags |= IPT_ECN_OP_MATCH_IP;
+		einfo->operation |= IPT_ECN_OP_MATCH_IP;
+		if (!xtables_strtoui(optarg, NULL, &result, 0, 3))
+			xtables_error(PARAMETER_PROBLEM,
+				   "ECN match: Value out of range");
+		einfo->ip_ect = result;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void ecn_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+		           "ECN match: some option required");
+}
+
+static void ecn_print(const void *ip, const struct xt_entry_match *match,
+                      int numeric)
+{
+	const struct ipt_ecn_info *einfo =
+		(const struct ipt_ecn_info *)match->data;
+
+	printf("ECN match ");
+
+	if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
+		if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
+			fputc('!', stdout);
+		printf("ECE ");
+	}
+
+	if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
+		if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
+			fputc('!', stdout);
+		printf("CWR ");
+	}
+
+	if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
+		if (einfo->invert & IPT_ECN_OP_MATCH_IP)
+			fputc('!', stdout);
+		printf("ECT=%d ", einfo->ip_ect);
+	}
+}
+
+static void ecn_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ipt_ecn_info *einfo =
+		(const struct ipt_ecn_info *)match->data;
+	
+	if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
+		if (einfo->invert & IPT_ECN_OP_MATCH_ECE)
+			printf("! ");
+		printf("--ecn-tcp-ece ");
+	}
+
+	if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
+		if (einfo->invert & IPT_ECN_OP_MATCH_CWR)
+			printf("! ");
+		printf("--ecn-tcp-cwr ");
+	}
+
+	if (einfo->operation & IPT_ECN_OP_MATCH_IP) {
+		if (einfo->invert & IPT_ECN_OP_MATCH_IP)
+			printf("! ");
+		printf("--ecn-ip-ect %d", einfo->ip_ect);
+	}
+}
+
+static struct xtables_match ecn_mt_reg = {
+    .name          = "ecn",
+    .version       = XTABLES_VERSION,
+    .family        = NFPROTO_IPV4,
+    .size          = XT_ALIGN(sizeof(struct ipt_ecn_info)),
+    .userspacesize = XT_ALIGN(sizeof(struct ipt_ecn_info)),
+    .help          = ecn_help,
+    .parse         = ecn_parse,
+    .final_check   = ecn_check,
+    .print         = ecn_print,
+    .save          = ecn_save,
+    .extra_opts    = ecn_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&ecn_mt_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_ecn.man b/ap/app/iptables/extensions/libipt_ecn.man
new file mode 100755
index 0000000..7f80647
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_ecn.man
@@ -0,0 +1,11 @@
+This allows you to match the ECN bits of the IPv4 and TCP header.  ECN is the Explicit Congestion Notification mechanism as specified in RFC3168
+.TP
+[\fB!\fP] \fB\-\-ecn\-tcp\-cwr\fP
+This matches if the TCP ECN CWR (Congestion Window Received) bit is set.
+.TP
+[\fB!\fP] \fB\-\-ecn\-tcp\-ece\fP
+This matches if the TCP ECN ECE (ECN Echo) bit is set.
+.TP
+[\fB!\fP] \fB\-\-ecn\-ip\-ect\fP \fInum\fP
+This matches a particular IPv4 ECT (ECN-Capable Transport). You have to specify
+a number between `0' and `3'.
diff --git a/ap/app/iptables/extensions/libipt_icmp.c b/ap/app/iptables/extensions/libipt_icmp.c
new file mode 100755
index 0000000..15c1787
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_icmp.c
@@ -0,0 +1,288 @@
+/* Shared library add-on to iptables to add ICMP support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <limits.h> /* INT_MAX in ip_tables.h */
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+/* special hack for icmp-type 'any': 
+ * Up to kernel <=2.4.20 the problem was:
+ * '-p icmp ' matches all icmp packets
+ * '-p icmp -m icmp' matches _only_ ICMP type 0 :(
+ * This is now fixed by initializing the field * to icmp type 0xFF
+ * See: https://bugzilla.netfilter.org/cgi-bin/bugzilla/show_bug.cgi?id=37
+ */
+
+struct icmp_names {
+	const char *name;
+	u_int8_t type;
+	u_int8_t code_min, code_max;
+};
+
+static const struct icmp_names icmp_codes[] = {
+	{ "any", 0xFF, 0, 0xFF },
+	{ "echo-reply", 0, 0, 0xFF },
+	/* Alias */ { "pong", 0, 0, 0xFF },
+
+	{ "destination-unreachable", 3, 0, 0xFF },
+	{   "network-unreachable", 3, 0, 0 },
+	{   "host-unreachable", 3, 1, 1 },
+	{   "protocol-unreachable", 3, 2, 2 },
+	{   "port-unreachable", 3, 3, 3 },
+	{   "fragmentation-needed", 3, 4, 4 },
+	{   "source-route-failed", 3, 5, 5 },
+	{   "network-unknown", 3, 6, 6 },
+	{   "host-unknown", 3, 7, 7 },
+	{   "network-prohibited", 3, 9, 9 },
+	{   "host-prohibited", 3, 10, 10 },
+	{   "TOS-network-unreachable", 3, 11, 11 },
+	{   "TOS-host-unreachable", 3, 12, 12 },
+	{   "communication-prohibited", 3, 13, 13 },
+	{   "host-precedence-violation", 3, 14, 14 },
+	{   "precedence-cutoff", 3, 15, 15 },
+
+	{ "source-quench", 4, 0, 0xFF },
+
+	{ "redirect", 5, 0, 0xFF },
+	{   "network-redirect", 5, 0, 0 },
+	{   "host-redirect", 5, 1, 1 },
+	{   "TOS-network-redirect", 5, 2, 2 },
+	{   "TOS-host-redirect", 5, 3, 3 },
+
+	{ "echo-request", 8, 0, 0xFF },
+	/* Alias */ { "ping", 8, 0, 0xFF },
+
+	{ "router-advertisement", 9, 0, 0xFF },
+
+	{ "router-solicitation", 10, 0, 0xFF },
+
+	{ "time-exceeded", 11, 0, 0xFF },
+	/* Alias */ { "ttl-exceeded", 11, 0, 0xFF },
+	{   "ttl-zero-during-transit", 11, 0, 0 },
+	{   "ttl-zero-during-reassembly", 11, 1, 1 },
+
+	{ "parameter-problem", 12, 0, 0xFF },
+	{   "ip-header-bad", 12, 0, 0 },
+	{   "required-option-missing", 12, 1, 1 },
+
+	{ "timestamp-request", 13, 0, 0xFF },
+
+	{ "timestamp-reply", 14, 0, 0xFF },
+
+	{ "address-mask-request", 17, 0, 0xFF },
+
+	{ "address-mask-reply", 18, 0, 0xFF }
+};
+
+static void
+print_icmptypes(void)
+{
+	unsigned int i;
+	printf("Valid ICMP Types:");
+
+	for (i = 0; i < sizeof(icmp_codes)/sizeof(struct icmp_names); i++) {
+		if (i && icmp_codes[i].type == icmp_codes[i-1].type) {
+			if (icmp_codes[i].code_min == icmp_codes[i-1].code_min
+			    && (icmp_codes[i].code_max
+				== icmp_codes[i-1].code_max))
+				printf(" (%s)", icmp_codes[i].name);
+			else
+				printf("\n   %s", icmp_codes[i].name);
+		}
+		else
+			printf("\n%s", icmp_codes[i].name);
+	}
+	printf("\n");
+}
+
+static void icmp_help(void)
+{
+	printf(
+"icmp match options:\n"
+"[!] --icmp-type typename	match icmp type\n"
+"[!] --icmp-type type[/code]	(or numeric type or type/code)\n");
+	print_icmptypes();
+}
+
+static const struct option icmp_opts[] = {
+	{ "icmp-type", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static void 
+parse_icmp(const char *icmptype, u_int8_t *type, u_int8_t code[])
+{
+	unsigned int limit = sizeof(icmp_codes)/sizeof(struct icmp_names);
+	unsigned int match = limit;
+	unsigned int i;
+
+	for (i = 0; i < limit; i++) {
+		if (strncasecmp(icmp_codes[i].name, icmptype, strlen(icmptype))
+		    == 0) {
+			if (match != limit)
+				xtables_error(PARAMETER_PROBLEM,
+					   "Ambiguous ICMP type `%s':"
+					   " `%s' or `%s'?",
+					   icmptype,
+					   icmp_codes[match].name,
+					   icmp_codes[i].name);
+			match = i;
+		}
+	}
+
+	if (match != limit) {
+		*type = icmp_codes[match].type;
+		code[0] = icmp_codes[match].code_min;
+		code[1] = icmp_codes[match].code_max;
+	} else {
+		char *slash;
+		char buffer[strlen(icmptype) + 1];
+		unsigned int number;
+
+		strcpy(buffer, icmptype);
+		slash = strchr(buffer, '/');
+
+		if (slash)
+			*slash = '\0';
+
+		if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Invalid ICMP type `%s'\n", buffer);
+		*type = number;
+		if (slash) {
+			if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX))
+				xtables_error(PARAMETER_PROBLEM,
+					   "Invalid ICMP code `%s'\n",
+					   slash+1);
+			code[0] = code[1] = number;
+		} else {
+			code[0] = 0;
+			code[1] = 0xFF;
+		}
+	}
+}
+
+static void icmp_init(struct xt_entry_match *m)
+{
+	struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data;
+
+	icmpinfo->type = 0xFF;
+	icmpinfo->code[1] = 0xFF;
+}
+
+static int icmp_parse(int c, char **argv, int invert, unsigned int *flags,
+                      const void *entry, struct xt_entry_match **match)
+{
+	struct ipt_icmp *icmpinfo = (struct ipt_icmp *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags == 1)
+			xtables_error(PARAMETER_PROBLEM,
+				   "icmp match: only use --icmp-type once!");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_icmp(argv[optind-1], &icmpinfo->type, 
+			   icmpinfo->code);
+		if (invert)
+			icmpinfo->invflags |= IPT_ICMP_INV;
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void print_icmptype(u_int8_t type,
+			   u_int8_t code_min, u_int8_t code_max,
+			   int invert,
+			   int numeric)
+{
+	if (!numeric) {
+		unsigned int i;
+
+		for (i = 0;
+		     i < sizeof(icmp_codes)/sizeof(struct icmp_names);
+		     i++) {
+			if (icmp_codes[i].type == type
+			    && icmp_codes[i].code_min == code_min
+			    && icmp_codes[i].code_max == code_max)
+				break;
+		}
+
+		if (i != sizeof(icmp_codes)/sizeof(struct icmp_names)) {
+			printf("%s%s ",
+			       invert ? "!" : "",
+			       icmp_codes[i].name);
+			return;
+		}
+	}
+
+	if (invert)
+		printf("!");
+
+	printf("type %u", type);
+	if (code_min == 0 && code_max == 0xFF)
+		printf(" ");
+	else if (code_min == code_max)
+		printf(" code %u ", code_min);
+	else
+		printf(" codes %u-%u ", code_min, code_max);
+}
+
+static void icmp_print(const void *ip, const struct xt_entry_match *match,
+                       int numeric)
+{
+	const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data;
+
+	printf("icmp ");
+	print_icmptype(icmp->type, icmp->code[0], icmp->code[1],
+		       icmp->invflags & IPT_ICMP_INV,
+		       numeric);
+
+	if (icmp->invflags & ~IPT_ICMP_INV)
+		printf("Unknown invflags: 0x%X ",
+		       icmp->invflags & ~IPT_ICMP_INV);
+}
+
+static void icmp_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data;
+
+	if (icmp->invflags & IPT_ICMP_INV)
+		printf("! ");
+
+	/* special hack for 'any' case */
+	if (icmp->type == 0xFF) {
+		printf("--icmp-type any ");
+	} else {
+		printf("--icmp-type %u", icmp->type);
+		if (icmp->code[0] != 0 || icmp->code[1] != 0xFF)
+			printf("/%u", icmp->code[0]);
+		printf(" ");
+	}
+}
+
+static struct xtables_match icmp_mt_reg = {
+	.name		= "icmp",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct ipt_icmp)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ipt_icmp)),
+	.help		= icmp_help,
+	.init		= icmp_init,
+	.parse		= icmp_parse,
+	.print		= icmp_print,
+	.save		= icmp_save,
+	.extra_opts	= icmp_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&icmp_mt_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_icmp.man b/ap/app/iptables/extensions/libipt_icmp.man
new file mode 100755
index 0000000..1039704
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_icmp.man
@@ -0,0 +1,9 @@
+This extension can be used if `\-\-protocol icmp' is specified. It
+provides the following option:
+.TP
+[\fB!\fP] \fB\-\-icmp\-type\fP {\fItype\fP[\fB/\fP\fIcode\fP]|\fItypename\fP}
+This allows specification of the ICMP type, which can be a numeric
+ICMP type, type/code pair, or one of the ICMP type names shown by the command
+.nf
+ iptables \-p icmp \-h
+.fi
diff --git a/ap/app/iptables/extensions/libipt_layer7.c b/ap/app/iptables/extensions/libipt_layer7.c
new file mode 100755
index 0000000..a8d6fcc
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_layer7.c
@@ -0,0 +1,408 @@
+/* 
+   Shared library add-on to iptables to add layer 7 matching support. 
+  
+   By Matthew Strait <quadong@users.sf.net>, Oct 2003.
+
+   http://l7-filter.sf.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.
+   http://www.gnu.org/licenses/gpl.txt
+
+   Based on libipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be>
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <dirent.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_layer7.h>
+
+#define MAX_FN_LEN 256
+
+static char l7dir[MAX_FN_LEN] = "\0";
+
+/* Function which prints out usage message. */
+static void help(void)
+{
+	printf(
+	"LAYER7 match options:\n"
+	"--l7dir <directory>  : Look for patterns here instead of /etc/l7-protocols/\n"
+	"                       (--l7dir must be specified before --l7proto if used!)\n"
+	"--l7proto [!] <name> : Match the protocol defined in /etc/l7-protocols/name.pat\n");
+	fputc('\n', stdout);
+}
+
+static struct option opts[] = {
+	{ .name = "l7proto", .has_arg = 1, .flag = 0, .val = '1' },
+	{ .name = "l7dir",   .has_arg = 1, .flag = 0, .val = '2' },
+	{ .name = NULL }
+};
+
+/* reads filename, puts protocol info into layer7_protocol_info, number of protocols to numprotos */
+static int parse_protocol_file(char * filename, const char * protoname, struct xt_layer7_info *info)
+{
+	FILE * f;
+	char * line = NULL;
+	size_t len = 0;
+
+	enum { protocol, pattern, done } datatype = protocol;
+
+	f = fopen(filename, "r");
+
+	if(!f)
+		return 0;
+
+	while(getline(&line, &len, f) != -1)
+	{
+		if(strlen(line) < 2 || line[0] == '#')
+			continue;
+
+		/* strip the pesky newline... */
+		if(line[strlen(line) - 1] == '\n')
+			line[strlen(line) - 1] = '\0';
+
+		if(datatype == protocol)
+		{
+			/* Ignore everything on the line beginning with the 
+			first space or tab . For instance, this allows the 
+			protocol line in http.pat to be "http " (or 
+			"http I am so cool") instead of just "http". */
+			if(strchr(line, ' ')){
+				char * space = strchr(line, ' ');
+				space[0] = '\0';
+			}
+			if(strchr(line, '\t')){
+				char * space = strchr(line, '\t');
+				space[0] = '\0';
+			}
+
+			/* sanity check.  First non-comment non-blank 
+			line must be the same as the file name. */
+			if(strcmp(line, protoname))
+				xtables_error(OTHER_PROBLEM, 
+					"Protocol name (%s) doesn't match file name (%s).  Bailing out\n",
+					line, filename);
+
+			if(strlen(line) >= MAX_PROTOCOL_LEN)
+				 xtables_error(PARAMETER_PROBLEM, 
+					"Protocol name in %s too long!", filename);
+			strncpy(info->protocol, line, MAX_PROTOCOL_LEN);
+
+			datatype = pattern; 
+		}
+		else if(datatype == pattern)
+		{
+			if(strlen(line) >= MAX_PATTERN_LEN)
+				 xtables_error(PARAMETER_PROBLEM, "Pattern in %s too long!", filename);
+			strncpy(info->pattern, line, MAX_PATTERN_LEN);
+			
+			datatype = done;			
+			break;
+		}
+		else
+			xtables_error(OTHER_PROBLEM, "Internal error");
+	}
+
+	if(datatype != done)
+		xtables_error(OTHER_PROBLEM, "Failed to get all needed data from %s", filename);
+
+	if(line) free(line);
+	fclose(f);
+
+	return 1;
+
+/*
+	fprintf(stderr, "protocol: %s\npattern: %s\n\n", 
+			info->protocol,
+			info->pattern);
+*/
+}
+
+static int hex2dec(char c)
+{
+        switch (c)
+        {
+                case '0' ... '9':
+                        return c - '0';
+                case 'a' ... 'f':
+                        return c - 'a' + 10;
+                case 'A' ... 'F':
+                        return c - 'A' + 10;
+                default:
+                        xtables_error(OTHER_PROBLEM, "hex2dec: bad value!\n");
+                        return 0;
+        }
+}
+
+/* takes a string with \xHH escapes and returns one with the characters 
+they stand for */
+static char * pre_process(char * s)
+{
+	char * result = malloc(strlen(s) + 1);
+	int sindex = 0, rindex = 0;
+        while( sindex < strlen(s) )
+        {
+            if( sindex + 3 < strlen(s) &&
+                s[sindex] == '\\' && s[sindex+1] == 'x' && 
+                isxdigit(s[sindex + 2]) && isxdigit(s[sindex + 3]) ) 
+                {
+                        /* carefully remember to call tolower here... */
+                        result[rindex] = tolower( hex2dec(s[sindex + 2])*16 +
+                                                  hex2dec(s[sindex + 3] ) );
+
+			switch ( result[rindex] )
+			{
+			case 0x24:
+			case 0x28:
+			case 0x29:
+			case 0x2a:
+			case 0x2b:
+			case 0x2e:
+			case 0x3f:
+			case 0x5b:
+			case 0x5c:
+			case 0x5e:
+			case 0x7c:
+				fprintf(stderr, 
+					"Warning: layer7 regexp contains a control character, %c, in hex (\\x%c%c).\n"
+					"I recommend that you write this as %c or \\%c, depending on what you meant.\n",
+					result[rindex], s[sindex + 2], s[sindex + 3], result[rindex], result[rindex]);
+				break;
+			case 0x00:
+				fprintf(stderr, 
+					"Warning: null (\\x00) in layer7 regexp.  A null terminates the regexp string!\n");
+				break;
+			default:
+				break;
+			}
+
+
+                        sindex += 3; /* 4 total */
+                }
+                else
+                        result[rindex] = tolower(s[sindex]);
+
+		sindex++; 
+		rindex++;
+        }
+	result[rindex] = '\0';
+
+	return result;
+}
+
+#define MAX_SUBDIRS 128
+static char ** readl7dir(char * dirname)
+{
+        DIR             * scratchdir;
+        struct dirent   ** namelist;
+	char ** subdirs = malloc(MAX_SUBDIRS * sizeof(char *));
+
+        int n, d = 1;
+	subdirs[0] = "";
+
+        n = scandir(dirname, &namelist, 0, alphasort);
+
+	if (n < 0)
+	{
+            perror("scandir");
+	    xtables_error(OTHER_PROBLEM, "Couldn't open %s\n", dirname);
+	}
+        else 
+	{
+            	while(n--) 
+		{
+			char fulldirname[MAX_FN_LEN];
+
+			snprintf(fulldirname, MAX_FN_LEN, "%s/%s", dirname, namelist[n]->d_name);
+
+                	if((scratchdir = opendir(fulldirname)) != NULL)
+			{
+				closedir(scratchdir);
+
+				if(!strcmp(namelist[n]->d_name, ".") || 
+				   !strcmp(namelist[n]->d_name, ".."))
+					/* do nothing */ ;
+				else
+				{
+					subdirs[d] = malloc(strlen(namelist[n]->d_name) + 1);
+					strcpy(subdirs[d], namelist[n]->d_name);
+					d++;
+					if(d >= MAX_SUBDIRS - 1)
+					{
+						fprintf(stderr, 
+						  "Too many subdirectories, skipping the rest!\n");
+						break;
+					}
+				}
+			}
+                	free(namelist[n]);
+            	}
+            	free(namelist);
+        }
+	
+	subdirs[d] = NULL;
+
+	return subdirs;
+}
+
+static void
+parse_layer7_protocol(const char *s, struct xt_layer7_info *info)
+{
+	char filename[MAX_FN_LEN];
+	char * dir = NULL;
+	char ** subdirs;
+	int n = 0, done = 0;
+
+	if(strlen(l7dir) > 0)
+		dir = l7dir;
+	else
+		dir = "/etc/l7-protocols";
+
+	subdirs = readl7dir(dir);
+
+	while(subdirs[n] != NULL)
+	{
+		int c = snprintf(filename, MAX_FN_LEN, "%s/%s/%s.pat", dir, subdirs[n], s);
+
+		//fprintf(stderr, "Trying to find pattern in %s ... ", filename);
+
+		if(c > MAX_FN_LEN)
+		{
+			xtables_error(OTHER_PROBLEM, 
+				"Filename beginning with %s is too long!\n", filename);
+		}
+
+		/* read in the pattern from the file */
+		if(parse_protocol_file(filename, s, info))
+		{
+			//fprintf(stderr, "found\n");
+			done = 1;
+			break;
+		}
+		
+		//fprintf(stderr, "not found\n");
+
+		n++;
+	}
+
+	if(!done)
+		xtables_error(OTHER_PROBLEM, 
+			"Couldn't find a pattern definition file for %s.\n", s);
+
+	/* process \xHH escapes and tolower everything. (our regex lib has no
+	case insensitivity option.) */
+	strncpy(info->pattern, pre_process(info->pattern), MAX_PATTERN_LEN);
+}
+
+/* Function which parses command options; returns true if it ate an option */
+static int parse(int c, char **argv, int invert, unsigned int *flags,
+      const void *entry,
+      struct xt_entry_match **match)
+{
+	struct xt_layer7_info *layer7info = 
+		(struct xt_layer7_info *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_layer7_protocol(argv[optind-1], layer7info);
+		if (invert)
+			layer7info->invert = 1;
+		*flags = 1;
+		break;
+
+	case '2':
+		/* not going to use this, but maybe we need to strip a ! anyway (?) */
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+
+		if(strlen(argv[optind-1]) >= MAX_FN_LEN)
+			xtables_error(PARAMETER_PROBLEM, "directory name too long\n");
+
+		strncpy(l7dir, argv[optind-1], MAX_FN_LEN);
+
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+/* Final check; must have specified --l7proto */
+static void final_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "LAYER7 match: You must specify `--l7proto'");
+}
+
+static void print_protocol(char s[], int invert, int numeric)
+{
+	fputs("l7proto ", stdout);
+	if (invert) fputc('!', stdout);
+	printf("%s ", s);
+}
+
+/* Prints out the matchinfo. */
+static void print(const void *ip,
+      const struct xt_entry_match *match,
+      int numeric)
+{
+	printf("LAYER7 ");
+
+	print_protocol(((struct xt_layer7_info *)match->data)->protocol,
+		  ((struct xt_layer7_info *)match->data)->invert, numeric);
+}
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void save(const void *ip, const struct xt_entry_match *match)
+{
+        const struct xt_layer7_info *info =
+            (const struct xt_layer7_info*) match->data;
+
+        printf("--l7proto %s%s ", (info->invert)   ? "! ": "", info->protocol);
+}
+
+static struct xtables_match layer7_match = {
+    .family        = NFPROTO_IPV4,
+    .name          = "layer7",
+    .version       = XTABLES_VERSION,
+    .size          = XT_ALIGN(sizeof(struct xt_layer7_info)),
+    .userspacesize = XT_ALIGN(sizeof(struct xt_layer7_info)),
+    .help          = &help,
+    .parse         = &parse,
+    .final_check   = &final_check,
+    .print         = &print,
+    .save          = &save,
+    .extra_opts    = opts
+};
+
+static struct xtables_match layer7_match6 = {
+    .family        = NFPROTO_IPV6,
+    .name          = "layer7",
+    .version       = XTABLES_VERSION,
+    .size          = XT_ALIGN(sizeof(struct xt_layer7_info)),
+    .userspacesize = XT_ALIGN(sizeof(struct xt_layer7_info)),
+    .help          = &help,
+    .parse         = &parse,
+    .final_check   = &final_check,
+    .print         = &print,
+    .save          = &save,
+    .extra_opts    = opts
+};
+
+void _init(void)
+{
+	xtables_register_match(&layer7_match);
+	xtables_register_match(&layer7_match6);
+}
diff --git a/ap/app/iptables/extensions/libipt_layer7.man b/ap/app/iptables/extensions/libipt_layer7.man
new file mode 100755
index 0000000..83a8c53
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_layer7.man
@@ -0,0 +1,14 @@
+This module matches packets based on the application layer data of 
+their connections.  It uses regular expression matching to compare 
+the application layer data to regular expressions found it the layer7 
+configuration files.  This is an experimental module which can be found at 
+http://l7-filter.sf.net.  It takes two options.
+.TP
+.BI "--l7proto " "\fIprotocol\fP"
+Match the specified protocol.  The protocol name must match a file 
+name in /etc/l7-protocols/ or one of its first-level child directories.
+.TP
+.BI "--l7dir " "\fIdirectory\fP"
+Use \fIdirectory\fP instead of /etc/l7-protocols/.  This option must be 
+specified before --l7proto.
+
diff --git a/ap/app/iptables/extensions/libipt_policy.c b/ap/app/iptables/extensions/libipt_policy.c
new file mode 100755
index 0000000..ae7282a
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_policy.c
@@ -0,0 +1,430 @@
+/* Shared library add-on to iptables to add policy support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <xtables.h>
+
+#include <linux/netfilter_ipv4/ipt_policy.h>
+
+/*
+ * HACK: global pointer to current matchinfo for making
+ * final checks and adjustments in final_check.
+ */
+static struct ipt_policy_info *policy_info;
+
+static void policy_help(void)
+{
+	printf(
+"policy match options:\n"
+"  --dir in|out			match policy applied during decapsulation/\n"
+"				policy to be applied during encapsulation\n"
+"  --pol none|ipsec		match policy\n"
+"  --strict 			match entire policy instead of single element\n"
+"				at any position\n"
+"[!] --reqid reqid		match reqid\n"
+"[!] --spi spi			match SPI\n"
+"[!] --proto proto		match protocol (ah/esp/ipcomp)\n"
+"[!] --mode mode 		match mode (transport/tunnel)\n"
+"[!] --tunnel-src addr/mask	match tunnel source\n"
+"[!] --tunnel-dst addr/mask	match tunnel destination\n"
+"  --next 			begin next element in policy\n");
+}
+
+static const struct option policy_opts[] =
+{
+	{
+		.name		= "dir",
+		.has_arg	= 1,
+		.val		= '1',
+	},
+	{
+		.name		= "pol",
+		.has_arg	= 1,
+		.val		= '2',
+	},
+	{
+		.name		= "strict",
+		.val		= '3'
+	},
+	{
+		.name		= "reqid",
+		.has_arg	= 1,
+		.val		= '4',
+	},
+	{
+		.name		= "spi",
+		.has_arg	= 1,
+		.val		= '5'
+	},
+	{
+		.name		= "tunnel-src",
+		.has_arg	= 1,
+		.val		= '6'
+	},
+	{
+		.name		= "tunnel-dst",
+		.has_arg	= 1,
+		.val		= '7'
+	},
+	{
+		.name		= "proto",
+		.has_arg	= 1,
+		.val		= '8'
+	},
+	{
+		.name		= "mode",
+		.has_arg	= 1,
+		.val		= '9'
+	},
+	{
+		.name		= "next",
+		.val		= 'a'
+	},
+	{ .name = NULL }
+};
+
+static int parse_direction(char *s)
+{
+	if (strcmp(s, "in") == 0)
+		return IPT_POLICY_MATCH_IN;
+	if (strcmp(s, "out") == 0)
+		return IPT_POLICY_MATCH_OUT;
+	xtables_error(PARAMETER_PROBLEM, "policy_match: invalid dir \"%s\"", s);
+}
+
+static int parse_policy(char *s)
+{
+	if (strcmp(s, "none") == 0)
+		return IPT_POLICY_MATCH_NONE;
+	if (strcmp(s, "ipsec") == 0)
+		return 0;
+	xtables_error(PARAMETER_PROBLEM, "policy match: invalid policy \"%s\"", s);
+}
+
+static int parse_mode(char *s)
+{
+	if (strcmp(s, "transport") == 0)
+		return IPT_POLICY_MODE_TRANSPORT;
+	if (strcmp(s, "tunnel") == 0)
+		return IPT_POLICY_MODE_TUNNEL;
+	xtables_error(PARAMETER_PROBLEM, "policy match: invalid mode \"%s\"", s);
+}
+
+static int policy_parse(int c, char **argv, int invert, unsigned int *flags,
+                        const void *entry, struct xt_entry_match **match)
+{
+	struct ipt_policy_info *info = (void *)(*match)->data;
+	struct ipt_policy_elem *e = &info->pol[info->len];
+	struct in_addr *addr = NULL, mask;
+	unsigned int naddr = 0, num;
+	int mode;
+
+	xtables_check_inverse(optarg, &invert, &optind, 0);
+
+	switch (c) {
+	case '1':
+		if (info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT))
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --dir option");
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: can't invert --dir option");
+
+		info->flags |= parse_direction(argv[optind-1]);
+		break;
+	case '2':
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: can't invert --policy option");
+
+		info->flags |= parse_policy(argv[optind-1]);
+		break;
+	case '3':
+		if (info->flags & IPT_POLICY_MATCH_STRICT)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --strict option");
+
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: can't invert --strict option");
+
+		info->flags |= IPT_POLICY_MATCH_STRICT;
+		break;
+	case '4':
+		if (e->match.reqid)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --reqid option");
+
+		e->match.reqid = 1;
+		e->invert.reqid = invert;
+		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "policy", "--spi", optarg);
+		e->reqid = num;
+		break;
+	case '5':
+		if (e->match.spi)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --spi option");
+
+		e->match.spi = 1;
+		e->invert.spi = invert;
+		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "policy", "--spi", optarg);
+		e->spi = num;
+		break;
+	case '6':
+		if (e->match.saddr)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --tunnel-src option");
+
+		xtables_ipparse_any(argv[optind-1], &addr, &mask, &naddr);
+		if (naddr > 1)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: name resolves to multiple IPs");
+
+		e->match.saddr = 1;
+		e->invert.saddr = invert;
+		e->saddr.a4 = addr[0];
+		e->smask.a4 = mask;
+                break;
+	case '7':
+		if (e->match.daddr)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --tunnel-dst option");
+
+		xtables_ipparse_any(argv[optind-1], &addr, &mask, &naddr);
+		if (naddr > 1)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: name resolves to multiple IPs");
+
+		e->match.daddr = 1;
+		e->invert.daddr = invert;
+		e->daddr.a4 = addr[0];
+		e->dmask.a4 = mask;
+		break;
+	case '8':
+		if (e->match.proto)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --proto option");
+
+		e->proto = xtables_parse_protocol(argv[optind-1]);
+		if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP &&
+		    e->proto != IPPROTO_COMP)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: protocol must ah/esp/ipcomp");
+		e->match.proto = 1;
+		e->invert.proto = invert;
+		break;
+	case '9':
+		if (e->match.mode)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: double --mode option");
+
+		mode = parse_mode(argv[optind-1]);
+		e->match.mode = 1;
+		e->invert.mode = invert;
+		e->mode = mode;
+		break;
+	case 'a':
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: can't invert --next option");
+
+		if (++info->len == IPT_POLICY_MAX_ELEM)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: maximum policy depth reached");
+		break;
+	default:
+		return 0;
+	}
+
+	policy_info = info;
+	return 1;
+}
+
+static void policy_check(unsigned int flags)
+{
+	struct ipt_policy_info *info = policy_info;
+	struct ipt_policy_elem *e;
+	int i;
+
+	if (info == NULL)
+		xtables_error(PARAMETER_PROBLEM,
+		           "policy match: no parameters given");
+
+	if (!(info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT)))
+		xtables_error(PARAMETER_PROBLEM,
+		           "policy match: neither --in nor --out specified");
+
+	if (info->flags & IPT_POLICY_MATCH_NONE) {
+		if (info->flags & IPT_POLICY_MATCH_STRICT)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: policy none but --strict given");
+
+		if (info->len != 0)
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: policy none but policy given");
+	} else
+		info->len++;	/* increase len by 1, no --next after last element */
+
+	if (!(info->flags & IPT_POLICY_MATCH_STRICT) && info->len > 1)
+		xtables_error(PARAMETER_PROBLEM,
+		           "policy match: multiple elements but no --strict");
+
+	for (i = 0; i < info->len; i++) {
+		e = &info->pol[i];
+
+		if (info->flags & IPT_POLICY_MATCH_STRICT &&
+		    !(e->match.reqid || e->match.spi || e->match.saddr ||
+		      e->match.daddr || e->match.proto || e->match.mode))
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: empty policy element");
+
+		if ((e->match.saddr || e->match.daddr)
+		    && ((e->mode == IPT_POLICY_MODE_TUNNEL && e->invert.mode) ||
+		        (e->mode == IPT_POLICY_MODE_TRANSPORT && !e->invert.mode)))
+			xtables_error(PARAMETER_PROBLEM,
+			           "policy match: --tunnel-src/--tunnel-dst "
+			           "is only valid in tunnel mode");
+	}
+}
+
+static void print_mode(char *prefix, u_int8_t mode, int numeric)
+{
+	printf("%smode ", prefix);
+
+	switch (mode) {
+	case IPT_POLICY_MODE_TRANSPORT:
+		printf("transport ");
+		break;
+	case IPT_POLICY_MODE_TUNNEL:
+		printf("tunnel ");
+		break;
+	default:
+		printf("??? ");
+		break;
+	}
+}
+
+static void print_proto(char *prefix, u_int8_t proto, int numeric)
+{
+	struct protoent *p = NULL;
+
+	printf("%sproto ", prefix);
+	if (!numeric)
+		p = getprotobynumber(proto);
+	if (p != NULL)
+		printf("%s ", p->p_name);
+	else
+		printf("%u ", proto);
+}
+
+#define PRINT_INVERT(x)		\
+do {				\
+	if (x)			\
+		printf("! ");	\
+} while(0)
+
+static void print_entry(char *prefix, const struct ipt_policy_elem *e,
+                        int numeric)
+{
+	if (e->match.reqid) {
+		PRINT_INVERT(e->invert.reqid);
+		printf("%sreqid %u ", prefix, e->reqid);
+	}
+	if (e->match.spi) {
+		PRINT_INVERT(e->invert.spi);
+		printf("%sspi 0x%x ", prefix, e->spi);
+	}
+	if (e->match.proto) {
+		PRINT_INVERT(e->invert.proto);
+		print_proto(prefix, e->proto, numeric);
+	}
+	if (e->match.mode) {
+		PRINT_INVERT(e->invert.mode);
+		print_mode(prefix, e->mode, numeric);
+	}
+	if (e->match.daddr) {
+		PRINT_INVERT(e->invert.daddr);
+		printf("%stunnel-dst %s%s ", prefix,
+		       xtables_ipaddr_to_numeric((const void *)&e->daddr),
+		       xtables_ipmask_to_numeric((const void *)&e->dmask));
+	}
+	if (e->match.saddr) {
+		PRINT_INVERT(e->invert.saddr);
+		printf("%stunnel-src %s%s ", prefix,
+		       xtables_ipaddr_to_numeric((const void *)&e->saddr),
+		       xtables_ipmask_to_numeric((const void *)&e->smask));
+	}
+}
+
+static void print_flags(char *prefix, const struct ipt_policy_info *info)
+{
+	if (info->flags & IPT_POLICY_MATCH_IN)
+		printf("%sdir in ", prefix);
+	else
+		printf("%sdir out ", prefix);
+
+	if (info->flags & IPT_POLICY_MATCH_NONE)
+		printf("%spol none ", prefix);
+	else
+		printf("%spol ipsec ", prefix);
+
+	if (info->flags & IPT_POLICY_MATCH_STRICT)
+		printf("%sstrict ", prefix);
+}
+
+static void policy_print(const void *ip, const struct xt_entry_match *match,
+                         int numeric)
+{
+	const struct ipt_policy_info *info = (void *)match->data;
+	unsigned int i;
+
+	printf("policy match ");
+	print_flags("", info);
+	for (i = 0; i < info->len; i++) {
+		if (info->len > 1)
+			printf("[%u] ", i);
+		print_entry("", &info->pol[i], numeric);
+	}
+}
+
+static void policy_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ipt_policy_info *info = (void *)match->data;
+	unsigned int i;
+
+	print_flags("--", info);
+	for (i = 0; i < info->len; i++) {
+		print_entry("--", &info->pol[i], 0);
+		if (i + 1 < info->len)
+			printf("--next ");
+	}
+}
+
+static struct xtables_match policy_mt_reg = {
+	.name		= "policy",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct ipt_policy_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ipt_policy_info)),
+	.help		= policy_help,
+	.parse		= policy_parse,
+	.final_check	= policy_check,
+	.print		= policy_print,
+	.save		= policy_save,
+	.extra_opts	= policy_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&policy_mt_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_realm.c b/ap/app/iptables/extensions/libipt_realm.c
new file mode 100755
index 0000000..3dd63d3
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_realm.c
@@ -0,0 +1,254 @@
+/* Shared library add-on to iptables to add realm matching support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <getopt.h>
+#if defined(__GLIBC__) && __GLIBC__ == 2
+#include <net/ethernet.h>
+#else
+#include <linux/if_ether.h>
+#endif
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ipt_realm.h>
+
+static void realm_help(void)
+{
+	printf(
+"realm match options:\n"
+"[!] --realm value[/mask]\n"
+"				Match realm\n");
+}
+
+static const struct option realm_opts[] = {
+	{ "realm", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+struct realmname { 
+	int	id;
+	char*	name;
+	int	len;
+	struct realmname* next;
+};
+
+/* array of realms from /etc/iproute2/rt_realms */
+static struct realmname *realms = NULL;
+/* 1 if loading failed */
+static int rdberr = 0;
+
+
+static void load_realms(void)
+{
+	const char* rfnm = "/etc/iproute2/rt_realms";
+	char buf[512];
+	FILE *fil;
+	char *cur, *nxt;
+	int id;
+	struct realmname *oldnm = NULL, *newnm = NULL;
+
+	fil = fopen(rfnm, "r");
+	if (!fil) {
+		rdberr = 1;
+		return;
+	}
+
+	while (fgets(buf, sizeof(buf), fil)) {
+		cur = buf;
+		while ((*cur == ' ') || (*cur == '\t'))
+			cur++;
+		if ((*cur == '#') || (*cur == '\n') || (*cur == 0))
+			continue;
+
+		/* iproute2 allows hex and dec format */
+		errno = 0;
+		id = strtoul(cur, &nxt, strncmp(cur, "0x", 2) ? 10 : 16);
+		if ((nxt == cur) || errno)
+			continue;
+
+		/* same boundaries as in iproute2 */
+		if (id < 0 || id > 255)
+			continue;
+		cur = nxt;
+
+		if (!isspace(*cur))
+			continue;
+		while ((*cur == ' ') || (*cur == '\t'))
+			cur++;
+		if ((*cur == '#') || (*cur == '\n') || (*cur == 0))
+			continue;
+		nxt = cur;
+		while ((*nxt != 0) && !isspace(*nxt))
+			nxt++;
+		if (nxt == cur)
+			continue;
+
+		/* found valid data */
+		newnm = (struct realmname*)malloc(sizeof(struct realmname));
+		if (newnm == NULL) {
+			perror("libipt_realm: malloc failed");
+			exit(1);
+		}
+		newnm->id = id;
+		newnm->len = nxt - cur;
+		newnm->name = (char*)malloc(newnm->len + 1);
+		if (newnm->name == NULL) {
+			perror("libipt_realm: malloc failed");
+			exit(1);
+		}
+		strncpy(newnm->name, cur, newnm->len);
+		newnm->name[newnm->len] = 0;
+		newnm->next = NULL;
+
+		if (oldnm)
+			oldnm->next = newnm;
+		else
+			realms = newnm;
+		oldnm = newnm;
+	}
+
+	fclose(fil);
+}
+
+/* get realm id for name, -1 if error/not found */
+static int realm_name2id(const char* name)
+{
+	struct realmname* cur;
+
+	if ((realms == NULL) && (rdberr == 0))
+		load_realms();
+	cur = realms;
+	if (cur == NULL)
+		return -1;
+	while (cur) {
+		if (!strncmp(name, cur->name, cur->len + 1))
+			return cur->id;
+		cur = cur->next;
+	}
+	return -1;
+}
+
+/* get realm name for id, NULL if error/not found */
+static const char *realm_id2name(int id)
+{
+	struct realmname* cur;
+
+	if ((realms == NULL) && (rdberr == 0))
+		load_realms();
+	cur = realms;
+	if (cur == NULL)
+		return NULL;
+	while (cur) {
+		if (id == cur->id)
+			return cur->name;
+		cur = cur->next;
+	}
+	return NULL;
+}
+
+static int realm_parse(int c, char **argv, int invert, unsigned int *flags,
+                       const void *entry, struct xt_entry_match **match)
+{
+	struct ipt_realm_info *realminfo = (struct ipt_realm_info *)(*match)->data;
+	int id;
+
+	switch (c) {
+		char *end;
+	case '1':
+		xtables_check_inverse(argv[optind-1], &invert, &optind, 0);
+		end = optarg = argv[optind-1];
+		realminfo->id = strtoul(optarg, &end, 0);
+		if (end != optarg && (*end == '/' || *end == '\0')) {
+			if (*end == '/')
+				realminfo->mask = strtoul(end+1, &end, 0);
+			else
+				realminfo->mask = 0xffffffff;
+			if (*end != '\0' || end == optarg)
+				xtables_error(PARAMETER_PROBLEM,
+					   "Bad realm value `%s'", optarg);
+		} else {
+			id = realm_name2id(optarg);
+			if (id == -1)
+				xtables_error(PARAMETER_PROBLEM,
+					   "Realm `%s' not found", optarg);
+			realminfo->id = id;
+			realminfo->mask = 0xffffffff;
+		}
+		if (invert)
+			realminfo->invert = 1;
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static void
+print_realm(unsigned long id, unsigned long mask, int numeric)
+{
+	const char* name = NULL;
+
+	if (mask != 0xffffffff)
+		printf("0x%lx/0x%lx ", id, mask);
+	else {
+		if (numeric == 0)
+			name = realm_id2name(id);
+		if (name)
+			printf("%s ", name);
+		else
+			printf("0x%lx ", id);
+	}
+}
+
+static void realm_print(const void *ip, const struct xt_entry_match *match,
+                        int numeric)
+{
+	struct ipt_realm_info *ri = (struct ipt_realm_info *) match->data;
+
+	if (ri->invert)
+		printf("! ");
+
+	printf("realm ");
+	print_realm(ri->id, ri->mask, numeric);
+}
+
+static void realm_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct ipt_realm_info *ri = (struct ipt_realm_info *) match->data;
+
+	if (ri->invert)
+		printf("! ");
+
+	printf("--realm ");
+	print_realm(ri->id, ri->mask, 0);
+}
+
+static void realm_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "realm match: You must specify `--realm'");
+}
+
+static struct xtables_match realm_mt_reg = {
+	.name		= "realm",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct ipt_realm_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ipt_realm_info)),
+	.help		= realm_help,
+	.parse		= realm_parse,
+	.final_check	= realm_check,
+	.print		= realm_print,
+	.save		= realm_save,
+	.extra_opts	= realm_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&realm_mt_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_realm.man b/ap/app/iptables/extensions/libipt_realm.man
new file mode 100755
index 0000000..a40b1ad
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_realm.man
@@ -0,0 +1,7 @@
+This matches the routing realm.  Routing realms are used in complex routing
+setups involving dynamic routing protocols like BGP.
+.TP
+[\fB!\fP] \fB\-\-realm\fP \fIvalue\fP[\fB/\fP\fImask\fP]
+Matches a given realm number (and optionally mask). If not a number, value
+can be a named realm from /etc/iproute2/rt_realms (mask can not be used in
+that case).
diff --git a/ap/app/iptables/extensions/libipt_set.c b/ap/app/iptables/extensions/libipt_set.c
new file mode 100755
index 0000000..902c0df
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_set.c
@@ -0,0 +1,154 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ *                         Patrick Schaaf <bof@bof.de>
+ *                         Martin Josefsson <gandalf@wlug.westbo.se>
+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.  
+ */
+
+/* Shared library add-on to iptables to add IP set matching. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ipt_set.h>
+#include "libipt_set.h"
+
+static void set_help(void)
+{
+	printf("set match options:\n"
+	       " [!] --set     name flags\n"
+	       "		'name' is the set name from to match,\n" 
+	       "		'flags' are the comma separated list of\n"
+	       "		'src' and 'dst'.\n");
+}
+
+static const struct option set_opts[] = {
+	{"set", 1, NULL, '1'},
+	{ }
+};
+
+static void set_init(struct xt_entry_match *match)
+{
+	struct ipt_set_info_match *info = 
+		(struct ipt_set_info_match *) match->data;
+	
+
+	memset(info, 0, sizeof(struct ipt_set_info_match));
+
+}
+
+static int set_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_match **match)
+{
+	struct ipt_set_info_match *myinfo = 
+		(struct ipt_set_info_match *) (*match)->data;
+	struct ipt_set_info *info = &myinfo->match_set;
+
+	switch (c) {
+	case '1':		/* --set <set> <flag>[,<flag> */
+		if (info->flags[0])
+			xtables_error(PARAMETER_PROBLEM,
+				   "--set can be specified only once");
+
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		if (invert)
+			info->flags[0] |= IPSET_MATCH_INV;
+
+		if (!argv[optind]
+		    || argv[optind][0] == '-'
+		    || argv[optind][0] == '!')
+			xtables_error(PARAMETER_PROBLEM,
+				   "--set requires two args.");
+
+		if (strlen(argv[optind-1]) > IP_SET_MAXNAMELEN - 1)
+			xtables_error(PARAMETER_PROBLEM,
+				   "setname `%s' too long, max %d characters.",
+				   argv[optind-1], IP_SET_MAXNAMELEN - 1);
+
+		strcpy(info->setname, argv[optind - 1]);
+		parse_bindings(argv[optind], info);
+		DEBUGP("parse: set index %u\n", info->index);
+		optind++;
+		
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void set_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "You must specify `--set' with proper arguments");
+	DEBUGP("final check OK\n");
+}
+
+static void
+print_match(const char *prefix, const struct ipt_set_info *info)
+{
+	int i;
+
+	printf("%s%s %s", 
+	       (info->flags[0] & IPSET_MATCH_INV) ? "! " : "",
+	       prefix,
+	       info->setname);
+	for (i = 0; i < IP_SET_MAX_BINDINGS; i++) {
+		if (!info->flags[i])
+			break;		
+		printf("%s%s",
+		       i == 0 ? " " : ",",
+		       info->flags[i] & IPSET_SRC ? "src" : "dst");
+	}
+	printf(" ");
+}
+
+/* Prints out the matchinfo. */
+static void set_print(const void *ip, const struct xt_entry_match *match,
+                      int numeric)
+{
+	struct ipt_set_info_match *info = 
+		(struct ipt_set_info_match *) match->data;
+
+	print_match("set", &info->match_set);
+}
+
+static void set_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct ipt_set_info_match *info = 
+		(struct ipt_set_info_match *) match->data;
+
+	print_match("--set", &info->match_set);
+}
+
+static struct xtables_match set_mt_reg = {
+	.name		= "set",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct ipt_set_info_match)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ipt_set_info_match)),
+	.help		= set_help,
+	.init		= set_init,
+	.parse		= set_parse,
+	.final_check	= set_check,
+	.print		= set_print,
+	.save		= set_save,
+	.extra_opts	= set_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&set_mt_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_set.h b/ap/app/iptables/extensions/libipt_set.h
new file mode 100755
index 0000000..3553178
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_set.h
@@ -0,0 +1,40 @@
+#ifndef _LIBIPT_SET_H
+#define _LIBIPT_SET_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#ifdef DEBUG
+#define DEBUGP(x, args...) fprintf(stderr, x, ## args)
+#else
+#define DEBUGP(x, args...) 
+#endif
+
+static void
+parse_bindings(const char *opt_arg, struct ipt_set_info *info)
+{
+	char *saved = strdup(opt_arg);
+	char *ptr, *tmp = saved;
+	int i = 0;
+	
+	while (i < (IP_SET_MAX_BINDINGS - 1) && tmp != NULL) {
+		ptr = strsep(&tmp, ",");
+		if (strncmp(ptr, "src", 3) == 0)
+			info->flags[i++] |= IPSET_SRC;
+		else if (strncmp(ptr, "dst", 3) == 0)
+			info->flags[i++] |= IPSET_DST;
+		else
+			xtables_error(PARAMETER_PROBLEM,
+				   "You must spefify (the comma separated list of) 'src' or 'dst'.");
+	}
+
+	if (tmp)
+		xtables_error(PARAMETER_PROBLEM,
+			   "Can't follow bindings deeper than %i.", 
+			   IP_SET_MAX_BINDINGS - 1);
+
+	free(saved);
+}
+
+#endif /*_LIBIPT_SET_H*/
diff --git a/ap/app/iptables/extensions/libipt_set.man b/ap/app/iptables/extensions/libipt_set.man
new file mode 100755
index 0000000..0df73c1
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_set.man
@@ -0,0 +1,17 @@
+This modules macthes IP sets which can be defined by ipset(8).
+.TP
+[\fB!\fP] \fB\-\-set\fP \fIsetname\fP \fIflag\fP[\fB,\fP\fIflag\fP]...
+where flags are
+.BR "src"
+and/or
+.BR "dst" 
+and there can be no more than six of them. Hence the command
+.nf
+ iptables \-A FORWARD \-m set \-\-set test src,dst
+.fi
+will match packets, for which (depending on the type of the set) the source
+address or port number of the packet can be found in the specified set. If 
+there is a binding belonging to the mached set element or there is a default 
+binding for the given set, then the rule will match the packet only if 
+additionally (depending on the type of the set) the destination address or 
+port number of the packet can be found in the set according to the binding.
diff --git a/ap/app/iptables/extensions/libipt_string_old.c b/ap/app/iptables/extensions/libipt_string_old.c
new file mode 100755
index 0000000..c17cd23
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_string_old.c
@@ -0,0 +1,289 @@
+/* Shared library add-on to iptables to add string matching support. 
+ * 
+ * Copyright (C) 2000 Emmanuel Roger  <winfield@freegates.be>
+ *
+ * ChangeLog
+ *     29.12.2003: Michael Rash <mbr@cipherdyne.org>
+ *             Fixed iptables save/restore for ascii strings
+ *             that contain space chars, and hex strings that
+ *             contain embedded NULL chars.  Updated to print
+ *             strings in hex mode if any non-printable char
+ *             is contained within the string.
+ *
+ *     27.01.2001: Gianni Tedesco <gianni@ecsc.co.uk>
+ *             Changed --tos to --string in save(). Also
+ *             updated to work with slightly modified
+ *             ipt_string_info.
+ */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <ctype.h>
+
+#include <xtables.h>
+#include <linux/netfilter_ipv4/ipt_string.h>
+
+
+static void
+help(void)
+{
+	printf(
+"STRING match options:\n"
+"--string [!] string          Match a string in a packet\n"
+"--hex-string [!] string      Match a hex string in a packet\n");
+}
+
+
+static struct option opts[] = {
+	{ .name = "string",     .has_arg = 1, .flag = 0, .val = '1' },
+	{ .name = "hex-string", .has_arg = 1, .flag = 0, .val = '2' },
+	{ .name = NULL }
+};
+
+
+static void
+init(struct xt_entry_match *m)
+{
+}
+
+
+static void
+parse_string(const char *s, struct ipt_string_info *info)
+{	
+	if (strlen(s) <= BM_MAX_NLEN) strcpy(info->string, s);
+	else xtables_error(PARAMETER_PROBLEM, "STRING too long `%s'", s);
+}
+
+
+static void
+parse_hex_string(const char *s, struct ipt_string_info *info)
+{
+	int i=0, slen, sindex=0, schar;
+	short hex_f = 0, literal_f = 0;
+	char hextmp[3];
+
+	slen = strlen(s);
+
+	if (slen == 0) {
+		xtables_error(PARAMETER_PROBLEM,
+			"STRING must contain at least one char");
+	}
+
+	while (i < slen) {
+		if (s[i] == '\\' && !hex_f) {
+			literal_f = 1;
+		} else if (s[i] == '\\') {
+			xtables_error(PARAMETER_PROBLEM,
+				"Cannot include literals in hex data");
+		} else if (s[i] == '|') {
+			if (hex_f)
+				hex_f = 0;
+			else {
+				hex_f = 1;
+				/* get past any initial whitespace just after the '|' */
+				while (s[i+1] == ' ')
+					i++;
+			}
+			if (i+1 >= slen)
+				break;
+			else
+				i++;  /* advance to the next character */
+		}
+
+		if (literal_f) {
+			if (i+1 >= slen) {
+				xtables_error(PARAMETER_PROBLEM,
+					"Bad literal placement at end of string");
+			}
+			info->string[sindex] = s[i+1];
+			i += 2;  /* skip over literal char */
+			literal_f = 0;
+		} else if (hex_f) {
+			if (i+1 >= slen) {
+				xtables_error(PARAMETER_PROBLEM,
+					"Odd number of hex digits");
+			}
+			if (i+2 >= slen) {
+				/* must end with a "|" */
+				xtables_error(PARAMETER_PROBLEM, "Invalid hex block");
+			}
+			if (! isxdigit(s[i])) /* check for valid hex char */
+				xtables_error(PARAMETER_PROBLEM, "Invalid hex char `%c'", s[i]);
+			if (! isxdigit(s[i+1])) /* check for valid hex char */
+				xtables_error(PARAMETER_PROBLEM, "Invalid hex char `%c'", s[i+1]);
+			hextmp[0] = s[i];
+			hextmp[1] = s[i+1];
+			hextmp[2] = '\0';
+			if (! sscanf(hextmp, "%x", &schar))
+				xtables_error(PARAMETER_PROBLEM,
+					"Invalid hex char `%c'", s[i]);
+			info->string[sindex] = (char) schar;
+			if (s[i+2] == ' ')
+				i += 3;  /* spaces included in the hex block */
+			else
+				i += 2;
+		} else {  /* the char is not part of hex data, so just copy */
+			info->string[sindex] = s[i];
+			i++;
+		}
+		if (sindex > BM_MAX_NLEN)
+			xtables_error(PARAMETER_PROBLEM, "STRING too long `%s'", s);
+		sindex++;
+	}
+	info->len = sindex;
+}
+
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const void *entry, struct xt_entry_match **match)
+{
+	struct ipt_string_info *stringinfo = (struct ipt_string_info *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify multiple strings");
+
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_string(argv[optind-1], stringinfo);
+		if (invert)
+			stringinfo->invert = 1;
+		stringinfo->len=strlen((char *)&stringinfo->string);
+		*flags = 1;
+		break;
+
+	case '2':
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify multiple strings");
+
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_hex_string(argv[optind-1], stringinfo);  /* sets length */
+		if (invert)
+			stringinfo->invert = 1;
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+
+/* Final check; must have specified --string. */
+static void
+final_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "STRING match: You must specify `--string' or `--hex-string'");
+}
+
+/* Test to see if the string contains non-printable chars or quotes */
+static unsigned short int
+is_hex_string(const char *str, const unsigned short int len)
+{
+	unsigned int i;
+	for (i=0; i < len; i++)
+		if (! isprint(str[i]))
+			return 1;  /* string contains at least one non-printable char */
+	/* use hex output if the last char is a "\" */
+	if ((unsigned char) str[len-1] == 0x5c)
+		return 1;
+	return 0;
+}
+
+/* Print string with "|" chars included as one would pass to --hex-string */
+static void
+print_hex_string(const char *str, const unsigned short int len)
+{
+	unsigned int i;
+	/* start hex block */
+	printf("\"|");
+	for (i=0; i < len; i++) {
+		/* see if we need to prepend a zero */
+		if ((unsigned char) str[i] <= 0x0F)
+			printf("0%x", (unsigned char) str[i]);
+		else
+			printf("%x", (unsigned char) str[i]);
+	}
+	/* close hex block */
+	printf("|\" ");
+}
+
+static void
+print_string(const char *str, const unsigned short int len)
+{
+	unsigned int i;
+	printf("\"");
+	for (i=0; i < len; i++) {
+		if ((unsigned char) str[i] == 0x22)  /* escape any embedded quotes */
+			printf("%c", 0x5c);
+		printf("%c", (unsigned char) str[i]);
+	}
+	printf("\" ");  /* closing space and quote */
+}
+
+/* Prints out the matchinfo. */
+static void
+print(const void *ip,
+      const struct xt_entry_match *match,
+      int numeric)
+{
+	const struct ipt_string_info *info =
+	    (const struct ipt_string_info*) match->data;
+
+	if (is_hex_string(info->string, info->len)) {
+		printf("STRING match %s", (info->invert) ? "!" : "");
+		print_hex_string(info->string, info->len);
+	} else {
+		printf("STRING match %s", (info->invert) ? "!" : "");
+		print_string(info->string, info->len);
+	}
+}
+
+
+/* Saves the union ipt_matchinfo in parseable form to stdout. */
+static void
+save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ipt_string_info *info =
+	    (const struct ipt_string_info*) match->data;
+
+	if (is_hex_string(info->string, info->len)) {
+		printf("--hex-string %s", (info->invert) ? "! ": "");
+		print_hex_string(info->string, info->len);
+	} else {
+		printf("--string %s", (info->invert) ? "! ": "");
+		print_string(info->string, info->len);
+	}
+}
+
+
+static struct xtables_match string = {
+    .name          = "string",
+    .version       = XTABLES_VERSION,
+    .family        = NFPROTO_IPV4,
+    .size          = XT_ALIGN(sizeof(struct ipt_string_info)),
+    .userspacesize = XT_ALIGN(sizeof(struct ipt_string_info)),
+    .help          = &help,
+    .init          = &init,
+    .parse         = &parse,
+    .final_check   = &final_check,
+    .print         = &print,
+    .save          = &save,
+    .extra_opts    = opts
+};
+
+
+void _init(void)
+{
+	xtables_register_match(&string);
+}
diff --git a/ap/app/iptables/extensions/libipt_ttl.c b/ap/app/iptables/extensions/libipt_ttl.c
new file mode 100755
index 0000000..019a556
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_ttl.c
@@ -0,0 +1,167 @@
+/* Shared library add-on to iptables to add TTL matching support 
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ *
+ * $Id$
+ *
+ * This program is released under the terms of GNU GPL */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <xtables.h>
+
+#include <linux/netfilter_ipv4/ipt_ttl.h>
+
+static void ttl_help(void)
+{
+	printf(
+"ttl match options:\n"
+"  --ttl-eq value	Match time to live value\n"
+"  --ttl-lt value	Match TTL < value\n"
+"  --ttl-gt value	Match TTL > value\n");
+}
+
+static int ttl_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_match **match)
+{
+	struct ipt_ttl_info *info = (struct ipt_ttl_info *) (*match)->data;
+	unsigned int value;
+
+	xtables_check_inverse(optarg, &invert, &optind, 0);
+
+	switch (c) {
+		case '2':
+			if (!xtables_strtoui(optarg, NULL, &value, 0, UINT8_MAX))
+				xtables_error(PARAMETER_PROBLEM,
+				           "ttl: Expected value between 0 and 255");
+
+			if (invert)
+				info->mode = IPT_TTL_NE;
+			else
+				info->mode = IPT_TTL_EQ;
+
+			/* is 0 allowed? */
+			info->ttl = value;
+			break;
+		case '3':
+			if (!xtables_strtoui(optarg, NULL, &value, 0, UINT8_MAX))
+				xtables_error(PARAMETER_PROBLEM,
+				           "ttl: Expected value between 0 and 255");
+
+			if (invert) 
+				xtables_error(PARAMETER_PROBLEM,
+						"ttl: unexpected `!'");
+
+			info->mode = IPT_TTL_LT;
+			info->ttl = value;
+			break;
+		case '4':
+			if (!xtables_strtoui(optarg, NULL, &value, 0, UINT8_MAX))
+				xtables_error(PARAMETER_PROBLEM,
+				           "ttl: Expected value between 0 and 255");
+
+			if (invert)
+				xtables_error(PARAMETER_PROBLEM,
+						"ttl: unexpected `!'");
+
+			info->mode = IPT_TTL_GT;
+			info->ttl = value;
+			break;
+		default:
+			return 0;
+
+	}
+
+	if (*flags) 
+		xtables_error(PARAMETER_PROBLEM,
+				"Can't specify TTL option twice");
+	*flags = 1;
+
+	return 1;
+}
+
+static void ttl_check(unsigned int flags)
+{
+	if (!flags) 
+		xtables_error(PARAMETER_PROBLEM,
+			"TTL match: You must specify one of "
+			"`--ttl-eq', `--ttl-lt', `--ttl-gt");
+}
+
+static void ttl_print(const void *ip, const struct xt_entry_match *match,
+                      int numeric)
+{
+	const struct ipt_ttl_info *info = 
+		(struct ipt_ttl_info *) match->data;
+
+	printf("TTL match ");
+	switch (info->mode) {
+		case IPT_TTL_EQ:
+			printf("TTL == ");
+			break;
+		case IPT_TTL_NE:
+			printf("TTL != ");
+			break;
+		case IPT_TTL_LT:
+			printf("TTL < ");
+			break;
+		case IPT_TTL_GT:
+			printf("TTL > ");
+			break;
+	}
+	printf("%u ", info->ttl);
+}
+
+static void ttl_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ipt_ttl_info *info =
+		(struct ipt_ttl_info *) match->data;
+
+	switch (info->mode) {
+		case IPT_TTL_EQ:
+			printf("--ttl-eq ");
+			break;
+		case IPT_TTL_NE:
+			printf("! --ttl-eq ");
+			break;
+		case IPT_TTL_LT:
+			printf("--ttl-lt ");
+			break;
+		case IPT_TTL_GT:
+			printf("--ttl-gt ");
+			break;
+		default:
+			/* error */
+			break;
+	}
+	printf("%u ", info->ttl);
+}
+
+static const struct option ttl_opts[] = {
+	{ "ttl", 1, NULL, '2' },
+	{ "ttl-eq", 1, NULL, '2'},
+	{ "ttl-lt", 1, NULL, '3'},
+	{ "ttl-gt", 1, NULL, '4'},
+	{ .name = NULL }
+};
+
+static struct xtables_match ttl_mt_reg = {
+	.name		= "ttl",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(sizeof(struct ipt_ttl_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct ipt_ttl_info)),
+	.help		= ttl_help,
+	.parse		= ttl_parse,
+	.final_check	= ttl_check,
+	.print		= ttl_print,
+	.save		= ttl_save,
+	.extra_opts	= ttl_opts,
+};
+
+
+void _init(void) 
+{
+	xtables_register_match(&ttl_mt_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_ttl.man b/ap/app/iptables/extensions/libipt_ttl.man
new file mode 100755
index 0000000..849f704
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_ttl.man
@@ -0,0 +1,10 @@
+This module matches the time to live field in the IP header.
+.TP
+\fB\-\-ttl\-eq\fP \fIttl\fP
+Matches the given TTL value.
+.TP
+\fB\-\-ttl\-gt\fP \fIttl\fP
+Matches if TTL is greater than the given TTL value.
+.TP
+\fB\-\-ttl\-lt\fP \fIttl\fP
+Matches if TTL is less than the given TTL value.
diff --git a/ap/app/iptables/extensions/libipt_unclean.c b/ap/app/iptables/extensions/libipt_unclean.c
new file mode 100755
index 0000000..93d9013
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_unclean.c
@@ -0,0 +1,31 @@
+/* Shared library add-on to iptables for unclean. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+
+static void unclean_help(void)
+{
+	printf("unclean match takes no options\n");
+}
+
+static int unclean_parse(int c, char **argv, int invert, unsigned int *flags,
+                         const void *entry, struct xt_entry_match **match)
+{
+	return 0;
+}
+
+static struct xtables_match unclean_mt_reg = {
+	.name		= "unclean",
+	.version	= XTABLES_VERSION,
+	.family		= NFPROTO_IPV4,
+	.size		= XT_ALIGN(0),
+	.userspacesize	= XT_ALIGN(0),
+	.help		= unclean_help,
+	.parse		= unclean_parse,
+};
+
+void _init(void)
+{
+	xtables_register_match(&unclean_mt_reg);
+}
diff --git a/ap/app/iptables/extensions/libipt_unclean.man b/ap/app/iptables/extensions/libipt_unclean.man
new file mode 100755
index 0000000..3fecd55
--- /dev/null
+++ b/ap/app/iptables/extensions/libipt_unclean.man
@@ -0,0 +1,2 @@
+This module takes no options, but attempts to match packets which seem
+malformed or unusual.  This is regarded as experimental.
diff --git a/ap/app/iptables/extensions/libxt_CLASSIFY.c b/ap/app/iptables/extensions/libxt_CLASSIFY.c
new file mode 100755
index 0000000..7db2e4c
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_CLASSIFY.c
@@ -0,0 +1,115 @@
+/* Shared library add-on to iptables to add CLASSIFY target support. */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_CLASSIFY.h>
+#include <linux/types.h>
+#include <linux/pkt_sched.h>
+
+static void
+CLASSIFY_help(void)
+{
+	printf(
+"CLASSIFY target options:\n"
+"--set-class MAJOR:MINOR    Set skb->priority value (always hexadecimal!)\n");
+}
+
+static const struct option CLASSIFY_opts[] = {
+	{ "set-class", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static int CLASSIFY_string_to_priority(const char *s, unsigned int *p)
+{
+	unsigned int i, j;
+
+	if (sscanf(s, "%x:%x", &i, &j) != 2)
+		return 1;
+	
+	*p = TC_H_MAKE(i<<16, j);
+	return 0;
+}
+
+static int
+CLASSIFY_parse(int c, char **argv, int invert, unsigned int *flags,
+      const void *entry,
+      struct xt_entry_target **target)
+{
+	struct xt_classify_target_info *clinfo
+		= (struct xt_classify_target_info *)(*target)->data;
+
+	switch (c) {
+	case '1':
+		if (CLASSIFY_string_to_priority(optarg, &clinfo->priority))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Bad class value `%s'", optarg);
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+			           "CLASSIFY: Can't specify --set-class twice");
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+CLASSIFY_final_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+		           "CLASSIFY: Parameter --set-class is required");
+}
+
+static void
+CLASSIFY_print_class(unsigned int priority, int numeric)
+{
+	printf("%x:%x ", TC_H_MAJ(priority)>>16, TC_H_MIN(priority));
+}
+
+static void
+CLASSIFY_print(const void *ip,
+      const struct xt_entry_target *target,
+      int numeric)
+{
+	const struct xt_classify_target_info *clinfo =
+		(const struct xt_classify_target_info *)target->data;
+	printf("CLASSIFY set ");
+	CLASSIFY_print_class(clinfo->priority, numeric);
+}
+
+static void
+CLASSIFY_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct xt_classify_target_info *clinfo =
+		(const struct xt_classify_target_info *)target->data;
+
+	printf("--set-class %.4x:%.4x ",
+	       TC_H_MAJ(clinfo->priority)>>16, TC_H_MIN(clinfo->priority));
+}
+
+static struct xtables_target classify_target = { 
+	.family		= AF_UNSPEC,
+	.name		= "CLASSIFY",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_classify_target_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_classify_target_info)),
+	.help		= CLASSIFY_help,
+	.parse		= CLASSIFY_parse,
+	.final_check	= CLASSIFY_final_check,
+	.print		= CLASSIFY_print,
+	.save		= CLASSIFY_save,
+	.extra_opts	= CLASSIFY_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&classify_target);
+}
diff --git a/ap/app/iptables/extensions/libxt_CLASSIFY.man b/ap/app/iptables/extensions/libxt_CLASSIFY.man
new file mode 100755
index 0000000..0270fd1
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_CLASSIFY.man
@@ -0,0 +1,5 @@
+This module allows you to set the skb\->priority value (and thus classify the packet into a specific CBQ class).
+.TP
+\fB\-\-set\-class\fP \fImajor\fP\fB:\fP\fIminor\fP
+Set the major and minor class value. The values are always interpreted as
+hexadecimal even if no 0x prefix is given.
diff --git a/ap/app/iptables/extensions/libxt_CONNMARK.c b/ap/app/iptables/extensions/libxt_CONNMARK.c
new file mode 100755
index 0000000..6e42898
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_CONNMARK.c
@@ -0,0 +1,471 @@
+/* Shared library add-on to iptables to add CONNMARK target support.
+ *
+ * (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.com>
+ *
+ * Version 1.1
+ *
+ * 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
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_CONNMARK.h>
+
+enum {
+	F_MARK    = 1 << 0,
+	F_SR_MARK = 1 << 1,
+};
+
+static void CONNMARK_help(void)
+{
+	printf(
+"CONNMARK target options:\n"
+"  --set-mark value[/mask]       Set conntrack mark value\n"
+"  --save-mark [--mask mask]     Save the packet nfmark in the connection\n"
+"  --restore-mark [--mask mask]  Restore saved nfmark value\n");
+}
+
+static const struct option CONNMARK_opts[] = {
+	{ "set-mark", 1, NULL, '1' },
+	{ "save-mark", 0, NULL, '2' },
+	{ "restore-mark", 0, NULL, '3' },
+	{ "mask", 1, NULL, '4' },
+	{ .name = NULL }
+};
+
+static const struct option connmark_tg_opts[] = {
+	{.name = "set-xmark",     .has_arg = true,  .val = '='},
+	{.name = "set-mark",      .has_arg = true,  .val = '-'},
+	{.name = "and-mark",      .has_arg = true,  .val = '&'},
+	{.name = "or-mark",       .has_arg = true,  .val = '|'},
+	{.name = "xor-mark",      .has_arg = true,  .val = '^'},
+	{.name = "save-mark",     .has_arg = false, .val = 'S'},
+	{.name = "restore-mark",  .has_arg = false, .val = 'R'},
+	{.name = "ctmask",        .has_arg = true,  .val = 'c'},
+	{.name = "nfmask",        .has_arg = true,  .val = 'n'},
+	{.name = "mask",          .has_arg = true,  .val = 'm'},
+	{.name = NULL},
+};
+
+static void connmark_tg_help(void)
+{
+	printf(
+"CONNMARK target options:\n"
+"  --set-xmark value[/ctmask]    Zero mask bits and XOR ctmark with value\n"
+"  --save-mark [--ctmask mask] [--nfmask mask]\n"
+"                                Copy ctmark to nfmark using masks\n"
+"  --restore-mark [--ctmask mask] [--nfmask mask]\n"
+"                                Copy nfmark to ctmark using masks\n"
+"  --set-mark value[/mask]       Set conntrack mark value\n"
+"  --save-mark [--mask mask]     Save the packet nfmark in the connection\n"
+"  --restore-mark [--mask mask]  Restore saved nfmark value\n"
+"  --and-mark value              Binary AND the ctmark with bits\n"
+"  --or-mark value               Binary OR  the ctmark with bits\n"
+"  --xor-mark value              Binary XOR the ctmark with bits\n"
+);
+}
+
+static void connmark_tg_init(struct xt_entry_target *target)
+{
+	struct xt_connmark_tginfo1 *info = (void *)target->data;
+
+	/*
+	 * Need these defaults for --save-mark/--restore-mark if no
+	 * --ctmark or --nfmask is given.
+	 */
+	info->ctmask = UINT32_MAX;
+	info->nfmask = UINT32_MAX;
+}
+
+static int
+CONNMARK_parse(int c, char **argv, int invert, unsigned int *flags,
+               const void *entry, struct xt_entry_target **target)
+{
+	struct xt_connmark_target_info *markinfo
+		= (struct xt_connmark_target_info *)(*target)->data;
+
+	switch (c) {
+		char *end;
+	case '1':
+		markinfo->mode = XT_CONNMARK_SET;
+
+		markinfo->mark = strtoul(optarg, &end, 0);
+		if (*end == '/' && end[1] != '\0')
+		    markinfo->mask = strtoul(end+1, &end, 0);
+
+		if (*end != '\0' || end == optarg)
+			xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg);
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+			           "CONNMARK target: Can't specify --set-mark twice");
+		*flags = 1;
+		break;
+	case '2':
+		markinfo->mode = XT_CONNMARK_SAVE;
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+			           "CONNMARK target: Can't specify --save-mark twice");
+		*flags = 1;
+		break;
+	case '3':
+		markinfo->mode = XT_CONNMARK_RESTORE;
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+			           "CONNMARK target: Can't specify --restore-mark twice");
+		*flags = 1;
+		break;
+	case '4':
+		if (!*flags)
+			xtables_error(PARAMETER_PROBLEM,
+			           "CONNMARK target: Can't specify --mask without a operation");
+		markinfo->mask = strtoul(optarg, &end, 0);
+
+		if (*end != '\0' || end == optarg)
+			xtables_error(PARAMETER_PROBLEM, "Bad MASK value \"%s\"", optarg);
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static int connmark_tg_parse(int c, char **argv, int invert,
+                             unsigned int *flags, const void *entry,
+                             struct xt_entry_target **target)
+{
+	struct xt_connmark_tginfo1 *info = (void *)(*target)->data;
+	unsigned int value, mask = UINT32_MAX;
+	char *end;
+
+	switch (c) {
+	case '=': /* --set-xmark */
+	case '-': /* --set-mark */
+		xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
+		if (!xtables_strtoui(optarg, &end, &value, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
+		if (*end == '/')
+			if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX))
+				xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
+		if (*end != '\0')
+			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
+		info->mode   = XT_CONNMARK_SET;
+		info->ctmark = value;
+		info->ctmask = mask;
+		if (c == '-')
+			info->ctmask |= value;
+		*flags |= F_MARK;
+		return true;
+
+	case '&': /* --and-mark */
+		xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
+		if (!xtables_strtoui(optarg, NULL, &mask, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--and-mark", optarg);
+		info->mode   = XT_CONNMARK_SET;
+		info->ctmark = 0;
+		info->ctmask = ~mask;
+		*flags      |= F_MARK;
+		return true;
+
+	case '|': /* --or-mark */
+		xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
+		if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--or-mark", optarg);
+		info->mode   = XT_CONNMARK_SET;
+		info->ctmark = value;
+		info->ctmask = value;
+		*flags      |= F_MARK;
+		return true;
+
+	case '^': /* --xor-mark */
+		xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
+		if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--xor-mark", optarg);
+		info->mode   = XT_CONNMARK_SET;
+		info->ctmark = value;
+		info->ctmask = 0;
+		*flags      |= F_MARK;
+		return true;
+
+	case 'S': /* --save-mark */
+		xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
+		info->mode = XT_CONNMARK_SAVE;
+		*flags |= F_MARK | F_SR_MARK;
+		return true;
+
+	case 'R': /* --restore-mark */
+		xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
+		info->mode = XT_CONNMARK_RESTORE;
+		*flags |= F_MARK | F_SR_MARK;
+		return true;
+
+	case 'n': /* --nfmask */
+		if (!(*flags & F_SR_MARK))
+			xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
+			           "or --restore-mark is required for "
+			           "--nfmask");
+		if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--nfmask", optarg);
+		info->nfmask = value;
+		return true;
+
+	case 'c': /* --ctmask */
+		if (!(*flags & F_SR_MARK))
+			xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
+			           "or --restore-mark is required for "
+			           "--ctmask");
+		if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--ctmask", optarg);
+		info->ctmask = value;
+		return true;
+
+	case 'm': /* --mask */
+		if (!(*flags & F_SR_MARK))
+			xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
+			           "or --restore-mark is required for "
+			           "--mask");
+		if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--mask", optarg);
+		info->nfmask = info->ctmask = value;
+		return true;
+	}
+
+	return false;
+}
+
+static void connmark_tg_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+		           "CONNMARK target: No operation specified");
+}
+
+static void
+print_mark(unsigned long mark)
+{
+	printf("0x%lx", mark);
+}
+
+static void
+print_mask(const char *text, unsigned long mask)
+{
+	if (mask != 0xffffffffUL)
+		printf("%s0x%lx", text, mask);
+}
+
+static void CONNMARK_print(const void *ip,
+                           const struct xt_entry_target *target, int numeric)
+{
+	const struct xt_connmark_target_info *markinfo =
+		(const struct xt_connmark_target_info *)target->data;
+	switch (markinfo->mode) {
+	case XT_CONNMARK_SET:
+	    printf("CONNMARK set ");
+	    print_mark(markinfo->mark);
+	    print_mask("/", markinfo->mask);
+	    printf(" ");
+	    break;
+	case XT_CONNMARK_SAVE:
+	    printf("CONNMARK save ");
+	    print_mask("mask ", markinfo->mask);
+	    printf(" ");
+	    break;
+	case XT_CONNMARK_RESTORE:
+	    printf("CONNMARK restore ");
+	    print_mask("mask ", markinfo->mask);
+	    break;
+	default:
+	    printf("ERROR: UNKNOWN CONNMARK MODE ");
+	    break;
+	}
+}
+
+static void
+connmark_tg_print(const void *ip, const struct xt_entry_target *target,
+                  int numeric)
+{
+	const struct xt_connmark_tginfo1 *info = (const void *)target->data;
+
+	switch (info->mode) {
+	case XT_CONNMARK_SET:
+		if (info->ctmark == 0)
+			printf("CONNMARK and 0x%x ",
+			       (unsigned int)(u_int32_t)~info->ctmask);
+		else if (info->ctmark == info->ctmask)
+			printf("CONNMARK or 0x%x ", info->ctmark);
+		else if (info->ctmask == 0)
+			printf("CONNMARK xor 0x%x ", info->ctmark);
+		else
+			printf("CONNMARK xset 0x%x/0x%x ",
+			       info->ctmark, info->ctmask);
+		break;
+	case XT_CONNMARK_SAVE:
+		if (info->nfmask == UINT32_MAX && info->ctmask == UINT32_MAX)
+			printf("CONNMARK save ");
+		else if (info->nfmask == info->ctmask)
+			printf("CONNMARK save mask 0x%x ", info->nfmask);
+		else
+			printf("CONNMARK save nfmask 0x%x ctmask ~0x%x ",
+			       info->nfmask, info->ctmask);
+		break;
+	case XT_CONNMARK_RESTORE:
+		if (info->ctmask == UINT32_MAX && info->nfmask == UINT32_MAX)
+			printf("CONNMARK restore ");
+		else if (info->ctmask == info->nfmask)
+			printf("CONNMARK restore mask 0x%x ", info->ctmask);
+		else
+			printf("CONNMARK restore ctmask 0x%x nfmask ~0x%x ",
+			       info->ctmask, info->nfmask);
+		break;
+
+	default:
+		printf("ERROR: UNKNOWN CONNMARK MODE");
+		break;
+	}
+}
+
+static void CONNMARK_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct xt_connmark_target_info *markinfo =
+		(const struct xt_connmark_target_info *)target->data;
+
+	switch (markinfo->mode) {
+	case XT_CONNMARK_SET:
+	    printf("--set-mark ");
+	    print_mark(markinfo->mark);
+	    print_mask("/", markinfo->mask);
+	    printf(" ");
+	    break;
+	case XT_CONNMARK_SAVE:
+	    printf("--save-mark ");
+	    print_mask("--mask ", markinfo->mask);
+	    break;
+	case XT_CONNMARK_RESTORE:
+	    printf("--restore-mark ");
+	    print_mask("--mask ", markinfo->mask);
+	    break;
+	default:
+	    printf("ERROR: UNKNOWN CONNMARK MODE ");
+	    break;
+	}
+}
+
+static void CONNMARK_init(struct xt_entry_target *t)
+{
+	struct xt_connmark_target_info *markinfo
+		= (struct xt_connmark_target_info *)t->data;
+
+	markinfo->mask = 0xffffffffUL;
+}
+
+static void
+connmark_tg_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct xt_connmark_tginfo1 *info = (const void *)target->data;
+
+	switch (info->mode) {
+	case XT_CONNMARK_SET:
+		printf("--set-xmark 0x%x/0x%x ", info->ctmark, info->ctmask);
+		break;
+	case XT_CONNMARK_SAVE:
+		printf("--save-mark --nfmask 0x%x --ctmask 0x%x ",
+		       info->nfmask, info->ctmask);
+		break;
+	case XT_CONNMARK_RESTORE:
+		printf("--restore-mark --nfmask 0x%x --ctmask 0x%x ",
+		       info->nfmask, info->ctmask);
+		break;
+	default:
+		printf("ERROR: UNKNOWN CONNMARK MODE");
+		break;
+	}
+}
+
+static struct xtables_target connmark_target = {
+	.family		= NFPROTO_IPV4,
+	.name		= "CONNMARK",
+	.revision	= 0,
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_connmark_target_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_connmark_target_info)),
+	.help		= CONNMARK_help,
+	.init           = CONNMARK_init,
+	.parse		= CONNMARK_parse,
+	.final_check	= connmark_tg_check,
+	.print		= CONNMARK_print,
+	.save		= CONNMARK_save,
+	.extra_opts	= CONNMARK_opts,
+};
+
+static struct xtables_target connmark_target6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "CONNMARK",
+	.revision	= 0,
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_connmark_target_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_connmark_target_info)),
+	.help		= CONNMARK_help,
+	.init           = CONNMARK_init,
+	.parse		= CONNMARK_parse,
+	.final_check	= connmark_tg_check,
+	.print		= CONNMARK_print,
+	.save		= CONNMARK_save,
+	.extra_opts	= CONNMARK_opts,
+};
+
+static struct xtables_target connmark_tg_reg = {
+	.version        = XTABLES_VERSION,
+	.name           = "CONNMARK",
+	.revision       = 1,
+	.family         = NFPROTO_IPV4,
+	.size           = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
+	.userspacesize  = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
+	.help           = connmark_tg_help,
+	.init           = connmark_tg_init,
+	.parse          = connmark_tg_parse,
+	.final_check    = connmark_tg_check,
+	.print          = connmark_tg_print,
+	.save           = connmark_tg_save,
+	.extra_opts     = connmark_tg_opts,
+};
+
+static struct xtables_target connmark_tg6_reg = {
+	.version        = XTABLES_VERSION,
+	.name           = "CONNMARK",
+	.revision       = 1,
+	.family         = NFPROTO_IPV6,
+	.size           = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
+	.userspacesize  = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
+	.help           = connmark_tg_help,
+	.init           = connmark_tg_init,
+	.parse          = connmark_tg_parse,
+	.final_check    = connmark_tg_check,
+	.print          = connmark_tg_print,
+	.save           = connmark_tg_save,
+	.extra_opts     = connmark_tg_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&connmark_target);
+	xtables_register_target(&connmark_target6);
+	xtables_register_target(&connmark_tg_reg);
+	xtables_register_target(&connmark_tg6_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_CONNMARK.man b/ap/app/iptables/extensions/libxt_CONNMARK.man
new file mode 100755
index 0000000..571ce37
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_CONNMARK.man
@@ -0,0 +1,52 @@
+This module sets the netfilter mark value associated with a connection.
+.TP
+\fB\-\-set\-xmark\fP \fIvalue\fP[\fB/\fP\fImask\fP]
+Zero out the bits given by \fImask\fR and XOR \fIvalue\fR into the ctmark.
+.TP
+\fB\-\-save\-mark\fP [\fB\-\-nfmask\fP \fInfmask\fP] [\fB\-\-ctmask\fP \fIctmask\fP]
+Copy the packet mark (nfmark) to the connection mark (ctmark) using the given
+masks. The new nfmark value is determined as follows:
+.IP
+ctmark = (ctmark & ~ctmask) ^ (nfmark & nfmask)
+.IP
+i.e. \fIctmask\fR defines what bits to clear and \fInfmask\fR what bits of the
+nfmark to XOR into the ctmark. \fIctmask\fR and \fInfmask\fR default to
+0xFFFFFFFF.
+.TP
+\fB\-\-restore\-mark\fP [\fB\-\-nfmask\fP \fInfmask\fP] [\fB\-\-ctmask\fP \fIctmask\fP]
+Copy the connection mark (ctmark) to the packet mark (nfmark) using the given
+masks. The new ctmark value is determined as follows:
+.IP
+nfmark = (nfmark & ~\fInfmask\fR) ^ (ctmark & \fIctmask\fR);
+.IP
+i.e. \fInfmask\fR defines what bits to clear and \fIctmask\fR what bits of the
+ctmark to XOR into the nfmark. \fIctmask\fR and \fInfmask\fR default to
+0xFFFFFFFF.
+.IP
+\fB\-\-restore\-mark\fP is only valid in the \fBmangle\fP table.
+.PP
+The following mnemonics are available for \fB\-\-set\-xmark\fP:
+.TP
+\fB\-\-and\-mark\fP \fIbits\fP
+Binary AND the ctmark with \fIbits\fR. (Mnemonic for \fB\-\-set\-xmark
+0/\fR\fIinvbits\fR, where \fIinvbits\fR is the binary negation of \fIbits\fR.)
+.TP
+\fB\-\-or\-mark\fP \fIbits\fP
+Binary OR the ctmark with \fIbits\fR. (Mnemonic for \fB\-\-set\-xmark\fP
+\fIbits\fR\fB/\fR\fIbits\fR.)
+.TP
+\fB\-\-xor\-mark\fP \fIbits\fP
+Binary XOR the ctmark with \fIbits\fR. (Mnemonic for \fB\-\-set\-xmark\fP
+\fIbits\fR\fB/0\fR.)
+.TP
+\fB\-\-set\-mark\fP \fIvalue\fP[\fB/\fP\fImask\fP]
+Set the connection mark. If a mask is specified then only those bits set in the
+mask are modified.
+.TP
+\fB\-\-save\-mark\fP [\fB\-\-mask\fP \fImask\fP]
+Copy the nfmark to the ctmark. If a mask is specified, only those bits are
+copied.
+.TP
+\fB\-\-restore\-mark\fP [\fB\-\-mask\fP \fImask\fP]
+Copy the ctmark to the nfmark. If a mask is specified, only those bits are
+copied. This is only valid in the \fBmangle\fR table.
diff --git a/ap/app/iptables/extensions/libxt_CONNSECMARK.c b/ap/app/iptables/extensions/libxt_CONNSECMARK.c
new file mode 100755
index 0000000..1515f6f
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_CONNSECMARK.c
@@ -0,0 +1,143 @@
+/*
+ * Shared library add-on to iptables to add CONNSECMARK target support.
+ *
+ * Based on the MARK and CONNMARK targets.
+ *
+ * Copyright (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter/xt_CONNSECMARK.h>
+
+#define PFX "CONNSECMARK target: "
+
+static void CONNSECMARK_help(void)
+{
+	printf(
+"CONNSECMARK target options:\n"
+"  --save                   Copy security mark from packet to conntrack\n"
+"  --restore                Copy security mark from connection to packet\n");
+}
+
+static const struct option CONNSECMARK_opts[] = {
+	{ "save", 0, NULL, '1' },
+	{ "restore", 0, NULL, '2' },
+	{ .name = NULL }
+};
+
+static int
+CONNSECMARK_parse(int c, char **argv, int invert, unsigned int *flags,
+                  const void *entry, struct xt_entry_target **target)
+{
+	struct xt_connsecmark_target_info *info =
+		(struct xt_connsecmark_target_info*)(*target)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & CONNSECMARK_SAVE)
+			xtables_error(PARAMETER_PROBLEM, PFX
+				   "Can't specify --save twice");
+		info->mode = CONNSECMARK_SAVE;
+		*flags |= CONNSECMARK_SAVE;
+		break;
+
+	case '2':
+		if (*flags & CONNSECMARK_RESTORE)
+			xtables_error(PARAMETER_PROBLEM, PFX
+				   "Can't specify --restore twice");
+		info->mode = CONNSECMARK_RESTORE;
+		*flags |= CONNSECMARK_RESTORE;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void CONNSECMARK_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM, PFX "parameter required");
+
+	if (flags == (CONNSECMARK_SAVE|CONNSECMARK_RESTORE))
+		xtables_error(PARAMETER_PROBLEM, PFX "only one flag of --save "
+		           "or --restore is allowed");
+}
+
+static void print_connsecmark(struct xt_connsecmark_target_info *info)
+{
+	switch (info->mode) {
+	case CONNSECMARK_SAVE:
+		printf("save ");
+		break;
+		
+	case CONNSECMARK_RESTORE:
+		printf("restore ");
+		break;
+		
+	default:
+		xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", info->mode);
+	}
+}
+
+static void
+CONNSECMARK_print(const void *ip, const struct xt_entry_target *target,
+                  int numeric)
+{
+	struct xt_connsecmark_target_info *info =
+		(struct xt_connsecmark_target_info*)(target)->data;
+
+	printf("CONNSECMARK ");
+	print_connsecmark(info);
+}
+
+static void
+CONNSECMARK_save(const void *ip, const struct xt_entry_target *target)
+{
+	struct xt_connsecmark_target_info *info =
+		(struct xt_connsecmark_target_info*)target->data;
+
+	printf("--");
+	print_connsecmark(info);
+}
+
+static struct xtables_target connsecmark_target = {
+	.family		= NFPROTO_IPV4,
+	.name		= "CONNSECMARK",
+	.version	= XTABLES_VERSION,
+	.revision	= 0,
+	.size		= XT_ALIGN(sizeof(struct xt_connsecmark_target_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_connsecmark_target_info)),
+	.parse		= CONNSECMARK_parse,
+	.help		= CONNSECMARK_help,
+	.final_check	= CONNSECMARK_check,
+	.print		= CONNSECMARK_print,
+	.save		= CONNSECMARK_save,
+	.extra_opts	= CONNSECMARK_opts,
+};
+
+static struct xtables_target connsecmark_target6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "CONNSECMARK",
+	.version	= XTABLES_VERSION,
+	.revision	= 0,
+	.size		= XT_ALIGN(sizeof(struct xt_connsecmark_target_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_connsecmark_target_info)),
+	.parse		= CONNSECMARK_parse,
+	.help		= CONNSECMARK_help,
+	.final_check	= CONNSECMARK_check,
+	.print		= CONNSECMARK_print,
+	.save		= CONNSECMARK_save,
+	.extra_opts	= CONNSECMARK_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&connsecmark_target);
+	xtables_register_target(&connsecmark_target6);
+}
diff --git a/ap/app/iptables/extensions/libxt_CONNSECMARK.man b/ap/app/iptables/extensions/libxt_CONNSECMARK.man
new file mode 100755
index 0000000..a72e710
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_CONNSECMARK.man
@@ -0,0 +1,15 @@
+This module copies security markings from packets to connections
+(if unlabeled), and from connections back to packets (also only
+if unlabeled).  Typically used in conjunction with SECMARK, it is
+only valid in the
+.B mangle
+table.
+.TP
+\fB\-\-save\fP
+If the packet has a security marking, copy it to the connection
+if the connection is not marked.
+.TP
+\fB\-\-restore\fP
+If the packet does not have a security marking, and the connection
+does, copy the security marking from the connection to the packet.
+
diff --git a/ap/app/iptables/extensions/libxt_DSCP.c b/ap/app/iptables/extensions/libxt_DSCP.c
new file mode 100755
index 0000000..ddb9c99
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_DSCP.c
@@ -0,0 +1,164 @@
+/* Shared library add-on to iptables for DSCP
+ *
+ * (C) 2000- 2002 by Matthew G. Marsh <mgm@paktronix.com>,
+ * 		     Harald Welte <laforge@gnumonks.org>
+ *
+ * This program is distributed under the terms of GNU GPL v2, 1991
+ *
+ * libipt_DSCP.c borrowed heavily from libipt_TOS.c
+ *
+ * --set-class added by Iain Barnes
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_DSCP.h>
+
+/* This is evil, but it's my code - HW*/
+#include "dscp_helper.c"
+
+static void DSCP_help(void)
+{
+	printf(
+"DSCP target options\n"
+"  --set-dscp value		Set DSCP field in packet header to value\n"
+"  		                This value can be in decimal (ex: 32)\n"
+"               		or in hex (ex: 0x20)\n"
+"  --set-dscp-class class	Set the DSCP field in packet header to the\n"
+"				value represented by the DiffServ class value.\n"
+"				This class may be EF,BE or any of the CSxx\n"
+"				or AFxx classes.\n"
+"\n"
+"				These two options are mutually exclusive !\n"
+);
+}
+
+static const struct option DSCP_opts[] = {
+	{ "set-dscp", 1, NULL, 'F' },
+	{ "set-dscp-class", 1, NULL, 'G' },
+	{ .name = NULL }
+};
+
+static void
+parse_dscp(const char *s, struct xt_DSCP_info *dinfo)
+{
+	unsigned int dscp;
+       
+	if (!xtables_strtoui(s, NULL, &dscp, 0, UINT8_MAX))
+		xtables_error(PARAMETER_PROBLEM,
+			   "Invalid dscp `%s'\n", s);
+
+	if (dscp > XT_DSCP_MAX)
+		xtables_error(PARAMETER_PROBLEM,
+			   "DSCP `%d` out of range\n", dscp);
+
+	dinfo->dscp = dscp;
+}
+
+
+static void
+parse_class(const char *s, struct xt_DSCP_info *dinfo)
+{
+	unsigned int dscp = class_to_dscp(s);
+
+	/* Assign the value */
+	dinfo->dscp = dscp;
+}
+
+
+static int DSCP_parse(int c, char **argv, int invert, unsigned int *flags,
+                      const void *entry, struct xt_entry_target **target)
+{
+	struct xt_DSCP_info *dinfo
+		= (struct xt_DSCP_info *)(*target)->data;
+
+	switch (c) {
+	case 'F':
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+			           "DSCP target: Only use --set-dscp ONCE!");
+		parse_dscp(optarg, dinfo);
+		*flags = 1;
+		break;
+	case 'G':
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+				   "DSCP target: Only use --set-dscp-class ONCE!");
+		parse_class(optarg, dinfo);
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void DSCP_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+		           "DSCP target: Parameter --set-dscp is required");
+}
+
+static void
+print_dscp(u_int8_t dscp, int numeric)
+{
+ 	printf("0x%02x ", dscp);
+}
+
+static void DSCP_print(const void *ip, const struct xt_entry_target *target,
+                       int numeric)
+{
+	const struct xt_DSCP_info *dinfo =
+		(const struct xt_DSCP_info *)target->data;
+	printf("DSCP set ");
+	print_dscp(dinfo->dscp, numeric);
+}
+
+static void DSCP_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct xt_DSCP_info *dinfo =
+		(const struct xt_DSCP_info *)target->data;
+
+	printf("--set-dscp 0x%02x ", dinfo->dscp);
+}
+
+static struct xtables_target dscp_target = {
+	.family		= NFPROTO_IPV4,
+	.name		= "DSCP",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_DSCP_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_DSCP_info)),
+	.help		= DSCP_help,
+	.parse		= DSCP_parse,
+	.final_check	= DSCP_check,
+	.print		= DSCP_print,
+	.save		= DSCP_save,
+	.extra_opts	= DSCP_opts,
+};
+
+static struct xtables_target dscp_target6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "DSCP",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_DSCP_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_DSCP_info)),
+	.help		= DSCP_help,
+	.parse		= DSCP_parse,
+	.final_check	= DSCP_check,
+	.print		= DSCP_print,
+	.save		= DSCP_save,
+	.extra_opts	= DSCP_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&dscp_target);
+	xtables_register_target(&dscp_target6);
+}
diff --git a/ap/app/iptables/extensions/libxt_DSCP.man b/ap/app/iptables/extensions/libxt_DSCP.man
new file mode 100755
index 0000000..551ba2e
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_DSCP.man
@@ -0,0 +1,9 @@
+This target allows to alter the value of the DSCP bits within the TOS
+header of the IPv4 packet.  As this manipulates a packet, it can only
+be used in the mangle table.
+.TP
+\fB\-\-set\-dscp\fP \fIvalue\fP
+Set the DSCP field to a numerical value (can be decimal or hex)
+.TP
+\fB\-\-set\-dscp\-class\fP \fIclass\fP
+Set the DSCP field to a DiffServ class.
diff --git a/ap/app/iptables/extensions/libxt_MARK.c b/ap/app/iptables/extensions/libxt_MARK.c
new file mode 100755
index 0000000..ec2fe96
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_MARK.c
@@ -0,0 +1,346 @@
+/* Shared library add-on to iptables to add MARK target support. */
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_MARK.h>
+
+enum {
+	F_MARK = 1 << 0,
+};
+
+static void MARK_help(void)
+{
+	printf(
+"MARK target options:\n"
+"  --set-mark value                   Set nfmark value\n"
+"  --and-mark value                   Binary AND the nfmark with value\n"
+"  --or-mark  value                   Binary OR  the nfmark with value\n");
+}
+
+static const struct option MARK_opts[] = {
+	{ "set-mark", 1, NULL, '1' },
+	{ "and-mark", 1, NULL, '2' },
+	{ "or-mark", 1, NULL, '3' },
+	{ .name = NULL }
+};
+
+static const struct option mark_tg_opts[] = {
+	{.name = "set-xmark", .has_arg = true, .val = 'X'},
+	{.name = "set-mark",  .has_arg = true, .val = '='},
+	{.name = "and-mark",  .has_arg = true, .val = '&'},
+	{.name = "or-mark",   .has_arg = true, .val = '|'},
+	{.name = "xor-mark",  .has_arg = true, .val = '^'},
+	{ .name = NULL }
+};
+
+static void mark_tg_help(void)
+{
+	printf(
+"MARK target options:\n"
+"  --set-xmark value[/mask]  Clear bits in mask and XOR value into nfmark\n"
+"  --set-mark value[/mask]   Clear bits in mask and OR value into nfmark\n"
+"  --and-mark bits           Binary AND the nfmark with bits\n"
+"  --or-mark bits            Binary OR the nfmark with bits\n"
+"  --xor-mask bits           Binary XOR the nfmark with bits\n"
+"\n");
+}
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int
+MARK_parse_v0(int c, char **argv, int invert, unsigned int *flags,
+              const void *entry, struct xt_entry_target **target)
+{
+	struct xt_mark_target_info *markinfo
+		= (struct xt_mark_target_info *)(*target)->data;
+	unsigned int mark = 0;
+
+	switch (c) {
+	case '1':
+		if (!xtables_strtoui(optarg, NULL, &mark, 0, UINT32_MAX))
+			xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg);
+		markinfo->mark = mark;
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+			           "MARK target: Can't specify --set-mark twice");
+		*flags = 1;
+		break;
+	case '2':
+		xtables_error(PARAMETER_PROBLEM,
+			   "MARK target: kernel too old for --and-mark");
+	case '3':
+		xtables_error(PARAMETER_PROBLEM,
+			   "MARK target: kernel too old for --or-mark");
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void MARK_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+		           "MARK target: Parameter --set/and/or-mark"
+			   " is required");
+}
+
+static int
+MARK_parse_v1(int c, char **argv, int invert, unsigned int *flags,
+              const void *entry, struct xt_entry_target **target)
+{
+	struct xt_mark_target_info_v1 *markinfo
+		= (struct xt_mark_target_info_v1 *)(*target)->data;
+	unsigned int mark = 0;
+
+	switch (c) {
+	case '1':
+	        markinfo->mode = XT_MARK_SET;
+		break;
+	case '2':
+	        markinfo->mode = XT_MARK_AND;
+		break;
+	case '3':
+	        markinfo->mode = XT_MARK_OR;
+		break;
+	default:
+		return 0;
+	}
+
+	if (!xtables_strtoui(optarg, NULL, &mark, 0, UINT32_MAX))
+		xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg);
+	markinfo->mark = mark;
+	if (*flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "MARK target: Can't specify --set-mark twice");
+
+	*flags = 1;
+	return 1;
+}
+
+static int mark_tg_parse(int c, char **argv, int invert, unsigned int *flags,
+                         const void *entry, struct xt_entry_target **target)
+{
+	struct xt_mark_tginfo2 *info = (void *)(*target)->data;
+	unsigned int value, mask = UINT32_MAX;
+	char *end;
+
+	switch (c) {
+	case 'X': /* --set-xmark */
+	case '=': /* --set-mark */
+		xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK);
+		xtables_param_act(XTF_NO_INVERT, "MARK", "--set-xmark/--set-mark", invert);
+		if (!xtables_strtoui(optarg, &end, &value, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg);
+		if (*end == '/')
+			if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX))
+				xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg);
+		if (*end != '\0')
+			xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg);
+		info->mark = value;
+		info->mask = mask;
+
+		if (c == '=')
+			info->mask = value | mask;
+		break;
+
+	case '&': /* --and-mark */
+		xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK);
+		xtables_param_act(XTF_NO_INVERT, "MARK", "--and-mark", invert);
+		if (!xtables_strtoui(optarg, NULL, &mask, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "MARK", "--and-mark", optarg);
+		info->mark = 0;
+		info->mask = ~mask;
+		break;
+
+	case '|': /* --or-mark */
+		xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK);
+		xtables_param_act(XTF_NO_INVERT, "MARK", "--or-mark", invert);
+		if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "MARK", "--or-mark", optarg);
+		info->mark = value;
+		info->mask = value;
+		break;
+
+	case '^': /* --xor-mark */
+		xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK);
+		xtables_param_act(XTF_NO_INVERT, "MARK", "--xor-mark", invert);
+		if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "MARK", "--xor-mark", optarg);
+		info->mark = value;
+		info->mask = 0;
+		break;
+
+	default:
+		return false;
+	}
+
+	*flags |= F_MARK;
+	return true;
+}
+
+static void mark_tg_check(unsigned int flags)
+{
+	if (flags == 0)
+		xtables_error(PARAMETER_PROBLEM, "MARK: One of the --set-xmark, "
+		           "--{and,or,xor,set}-mark options is required");
+}
+
+static void
+print_mark(unsigned long mark)
+{
+	printf("0x%lx ", mark);
+}
+
+static void MARK_print_v0(const void *ip,
+                          const struct xt_entry_target *target, int numeric)
+{
+	const struct xt_mark_target_info *markinfo =
+		(const struct xt_mark_target_info *)target->data;
+	printf("MARK set ");
+	print_mark(markinfo->mark);
+}
+
+static void MARK_save_v0(const void *ip, const struct xt_entry_target *target)
+{
+	const struct xt_mark_target_info *markinfo =
+		(const struct xt_mark_target_info *)target->data;
+
+	printf("--set-mark ");
+	print_mark(markinfo->mark);
+}
+
+static void MARK_print_v1(const void *ip, const struct xt_entry_target *target,
+                          int numeric)
+{
+	const struct xt_mark_target_info_v1 *markinfo =
+		(const struct xt_mark_target_info_v1 *)target->data;
+
+	switch (markinfo->mode) {
+	case XT_MARK_SET:
+		printf("MARK set ");
+		break;
+	case XT_MARK_AND:
+		printf("MARK and ");
+		break;
+	case XT_MARK_OR: 
+		printf("MARK or ");
+		break;
+	}
+	print_mark(markinfo->mark);
+}
+
+static void mark_tg_print(const void *ip, const struct xt_entry_target *target,
+                          int numeric)
+{
+	const struct xt_mark_tginfo2 *info = (const void *)target->data;
+
+	if (info->mark == 0)
+		printf("MARK and 0x%x ", (unsigned int)(u_int32_t)~info->mask);
+	else if (info->mark == info->mask)
+		printf("MARK or 0x%x ", info->mark);
+	else if (info->mask == 0)
+		printf("MARK xor 0x%x ", info->mark);
+	else
+		printf("MARK xset 0x%x/0x%x ", info->mark, info->mask);
+}
+
+static void MARK_save_v1(const void *ip, const struct xt_entry_target *target)
+{
+	const struct xt_mark_target_info_v1 *markinfo =
+		(const struct xt_mark_target_info_v1 *)target->data;
+
+	switch (markinfo->mode) {
+	case XT_MARK_SET:
+		printf("--set-mark ");
+		break;
+	case XT_MARK_AND:
+		printf("--and-mark ");
+		break;
+	case XT_MARK_OR: 
+		printf("--or-mark ");
+		break;
+	}
+	print_mark(markinfo->mark);
+}
+
+static void mark_tg_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct xt_mark_tginfo2 *info = (const void *)target->data;
+
+	printf("--set-xmark 0x%x/0x%x ", info->mark, info->mask);
+}
+
+static struct xtables_target mark_target_v0 = {
+	.family		= NFPROTO_IPV4,
+	.name		= "MARK",
+	.version	= XTABLES_VERSION,
+	.revision	= 0,
+	.size		= XT_ALIGN(sizeof(struct xt_mark_target_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_mark_target_info)),
+	.help		= MARK_help,
+	.parse		= MARK_parse_v0,
+	.final_check	= MARK_check,
+	.print		= MARK_print_v0,
+	.save		= MARK_save_v0,
+	.extra_opts	= MARK_opts,
+};
+
+static struct xtables_target mark_target_v1 = {
+	.family		= NFPROTO_IPV4,
+	.name		= "MARK",
+	.version	= XTABLES_VERSION,
+	.revision	= 1,
+	.size		= XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
+	.help		= MARK_help,
+	.parse		= MARK_parse_v1,
+	.final_check	= MARK_check,
+	.print		= MARK_print_v1,
+	.save		= MARK_save_v1,
+	.extra_opts	= MARK_opts,
+};
+
+static struct xtables_target mark_target6_v0 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "MARK",
+	.version	= XTABLES_VERSION,
+	.revision	= 0,
+	.size		= XT_ALIGN(sizeof(struct xt_mark_target_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_mark_target_info)),
+	.help		= MARK_help,
+	.parse		= MARK_parse_v0,
+	.final_check	= MARK_check,
+	.print		= MARK_print_v0,
+	.save		= MARK_save_v0,
+	.extra_opts	= MARK_opts,
+};
+
+static struct xtables_target mark_tg_reg_v2 = {
+	.version       = XTABLES_VERSION,
+	.name          = "MARK",
+	.revision      = 2,
+	.family        = AF_UNSPEC,
+	.size          = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
+	.help          = mark_tg_help,
+	.parse         = mark_tg_parse,
+	.final_check   = mark_tg_check,
+	.print         = mark_tg_print,
+	.save          = mark_tg_save,
+	.extra_opts    = mark_tg_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&mark_target_v0);
+	xtables_register_target(&mark_target_v1);
+	xtables_register_target(&mark_target6_v0);
+	xtables_register_target(&mark_tg_reg_v2);
+}
diff --git a/ap/app/iptables/extensions/libxt_MARK.man b/ap/app/iptables/extensions/libxt_MARK.man
new file mode 100755
index 0000000..7bb05be
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_MARK.man
@@ -0,0 +1,25 @@
+This target is used to set the Netfilter mark value associated with the packet.
+The target can only be used in the \fBmangle\fR table. It can, for example, be
+used in conjunction with routing based on fwmark (needs iproute2).
+.TP
+\fB\-\-set\-xmark\fP \fIvalue\fP[\fB/\fP\fImask\fP]
+Zeroes out the bits given by \fImask\fR and XORs \fIvalue\fR into the packet
+mark ("nfmark"). If \fImask\fR is omitted, 0xFFFFFFFF is assumed.
+.TP
+\fB\-\-set\-mark\fP \fIvalue\fP[\fB/\fP\fImask\fP]
+Zeroes out the bits given by \fImask\fR and ORs \fIvalue\fR into the packet
+mark. If \fImask\fR is omitted, 0xFFFFFFFF is assumed.
+.PP
+The following mnemonics are available:
+.TP
+\fB\-\-and\-mark\fP \fIbits\fP
+Binary AND the nfmark with \fIbits\fR. (Mnemonic for \fB\-\-set\-xmark
+0/\fR\fIinvbits\fR, where \fIinvbits\fR is the binary negation of \fIbits\fR.)
+.TP
+\fB\-\-or\-mark\fP \fIbits\fP
+Binary OR the nfmark with \fIbits\fR. (Mnemonic for \fB\-\-set\-xmark\fP
+\fIbits\fR\fB/\fR\fIbits\fR.)
+.TP
+\fB\-\-xor\-mark\fP \fIbits\fP
+Binary XOR the nfmark with \fIbits\fR. (Mnemonic for \fB\-\-set\-xmark\fP
+\fIbits\fR\fB/0\fR.)
diff --git a/ap/app/iptables/extensions/libxt_NFLOG.c b/ap/app/iptables/extensions/libxt_NFLOG.c
new file mode 100755
index 0000000..007c7b4
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_NFLOG.c
@@ -0,0 +1,173 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <xtables.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_NFLOG.h>
+
+enum {
+	NFLOG_GROUP	= 0x1,
+	NFLOG_PREFIX	= 0x2,
+	NFLOG_RANGE	= 0x4,
+	NFLOG_THRESHOLD	= 0x8,
+};
+
+static const struct option NFLOG_opts[] = {
+	{ "nflog-group",     1, NULL, NFLOG_GROUP },
+	{ "nflog-prefix",    1, NULL, NFLOG_PREFIX },
+	{ "nflog-range",     1, NULL, NFLOG_RANGE },
+	{ "nflog-threshold", 1, NULL, NFLOG_THRESHOLD },
+	{ .name = NULL }
+};
+
+static void NFLOG_help(void)
+{
+	printf("NFLOG target options:\n"
+	       " --nflog-group NUM		NETLINK group used for logging\n"
+	       " --nflog-range NUM		Number of byte to copy\n"
+	       " --nflog-threshold NUM		Message threshold of in-kernel queue\n"
+	       " --nflog-prefix STRING		Prefix string for log messages\n");
+}
+
+static void NFLOG_init(struct xt_entry_target *t)
+{
+	struct xt_nflog_info *info = (struct xt_nflog_info *)t->data;
+
+	info->group	= 0;
+	info->threshold	= XT_NFLOG_DEFAULT_THRESHOLD;
+}
+
+static int NFLOG_parse(int c, char **argv, int invert, unsigned int *flags,
+                       const void *entry, struct xt_entry_target **target)
+{
+	struct xt_nflog_info *info = (struct xt_nflog_info *)(*target)->data;
+	int n;
+	size_t length;
+
+	switch (c) {
+	case NFLOG_GROUP:
+		if (*flags & NFLOG_GROUP)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --nflog-group twice");
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --nflog-group");
+
+		n = atoi(optarg);
+		if (n < 0)
+			xtables_error(PARAMETER_PROBLEM,
+				   "--nflog-group can not be negative");
+		info->group = n;
+		break;
+	case NFLOG_PREFIX:
+		if (*flags & NFLOG_PREFIX)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --nflog-prefix twice");
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --nflog-prefix");
+
+		length = strlen(optarg);
+		if (length == 0)
+			xtables_error(PARAMETER_PROBLEM,
+				   "No prefix specified for --nflog-prefix");
+		if (length >= sizeof(info->prefix))
+			xtables_error(PARAMETER_PROBLEM,
+				   "--nflog-prefix too long, max %Zu characters",
+				   sizeof(info->prefix) - 1);
+		if (length != strlen(strtok(optarg, "\n")))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Newlines are not allowed in --nflog-prefix");
+		strcpy(info->prefix, optarg);
+		break;
+	case NFLOG_RANGE:
+		if (*flags & NFLOG_RANGE)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --nflog-range twice");
+		n = atoi(optarg);
+		if (n < 0)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Invalid --nflog-range, must be >= 0");
+		info->len = n;
+		break;
+	case NFLOG_THRESHOLD:
+		if (*flags & NFLOG_THRESHOLD)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify --nflog-threshold twice");
+		n = atoi(optarg);
+		if (n < 1)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Invalid --nflog-threshold, must be >= 1");
+		info->threshold = n;
+		break;
+	default:
+		return 0;
+	}
+	*flags |= c;
+	return 1;
+}
+
+static void nflog_print(const struct xt_nflog_info *info, char *prefix)
+{
+	if (info->prefix[0] != '\0') {
+		printf("%snflog-prefix ", prefix);
+		xtables_save_string(info->prefix);
+	}
+	if (info->group)
+		printf("%snflog-group %u ", prefix, info->group);
+	if (info->len)
+		printf("%snflog-range %u ", prefix, info->len);
+	if (info->threshold != XT_NFLOG_DEFAULT_THRESHOLD)
+		printf("%snflog-threshold %u ", prefix, info->threshold);
+}
+
+static void NFLOG_print(const void *ip, const struct xt_entry_target *target,
+                        int numeric)
+{
+	const struct xt_nflog_info *info = (struct xt_nflog_info *)target->data;
+
+	nflog_print(info, "");
+}
+
+static void NFLOG_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct xt_nflog_info *info = (struct xt_nflog_info *)target->data;
+
+	nflog_print(info, "--");
+}
+
+static struct xtables_target nflog_target = {
+	.family		= NFPROTO_IPV4,
+	.name		= "NFLOG",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_nflog_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_nflog_info)),
+	.help		= NFLOG_help,
+	.init		= NFLOG_init,
+	.parse		= NFLOG_parse,
+	.print		= NFLOG_print,
+	.save		= NFLOG_save,
+	.extra_opts	= NFLOG_opts,
+};
+
+static struct xtables_target nflog_target6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "NFLOG",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_nflog_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_nflog_info)),
+	.help		= NFLOG_help,
+	.init		= NFLOG_init,
+	.parse		= NFLOG_parse,
+	.print		= NFLOG_print,
+	.save		= NFLOG_save,
+	.extra_opts	= NFLOG_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&nflog_target);
+	xtables_register_target(&nflog_target6);
+}
diff --git a/ap/app/iptables/extensions/libxt_NFLOG.man b/ap/app/iptables/extensions/libxt_NFLOG.man
new file mode 100755
index 0000000..861501b
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_NFLOG.man
@@ -0,0 +1,29 @@
+This target provides logging of matching packets. When this target is
+set for a rule, the Linux kernel will pass the packet to the loaded
+logging backend to log the packet. This is usually used in combination
+with nfnetlink_log as logging backend, which will multicast the packet
+through a
+.IR netlink
+socket to the specified multicast group. One or more userspace processes
+may subscribe to the group to receive the packets. Like LOG, this is a
+non-terminating target, i.e. rule traversal continues at the next rule.
+.TP
+\fB\-\-nflog\-group\fP \fInlgroup\fP
+The netlink group (1 - 2^32\-1) to which packets are (only applicable for
+nfnetlink_log). The default value is 0.
+.TP
+\fB\-\-nflog\-prefix\fP \fIprefix\fP
+A prefix string to include in the log message, up to 64 characters
+long, useful for distinguishing messages in the logs.
+.TP
+\fB\-\-nflog\-range\fP \fIsize\fP
+The number of bytes to be copied to userspace (only applicable for
+nfnetlink_log). nfnetlink_log instances may specify their own
+range, this option overrides it.
+.TP
+\fB\-\-nflog\-threshold\fP \fIsize\fP
+Number of packets to queue inside the kernel before sending them
+to userspace (only applicable for nfnetlink_log). Higher values
+result in less overhead per packet, but increase delay until the
+packets reach userspace. The default value is 1.
+.BR
diff --git a/ap/app/iptables/extensions/libxt_NFQUEUE.c b/ap/app/iptables/extensions/libxt_NFQUEUE.c
new file mode 100755
index 0000000..3ca2239
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_NFQUEUE.c
@@ -0,0 +1,110 @@
+/* Shared library add-on to iptables for NFQ
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ *
+ * This program is distributed under the terms of GNU GPL v2, 1991
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_NFQUEUE.h>
+
+static void NFQUEUE_help(void)
+{
+	printf(
+"NFQUEUE target options\n"
+"  --queue-num value		Send packet to QUEUE number <value>.\n"
+"  		                Valid queue numbers are 0-65535\n"
+);
+}
+
+static const struct option NFQUEUE_opts[] = {
+	{ "queue-num", 1, NULL, 'F' },
+	{ .name = NULL }
+};
+
+static void
+parse_num(const char *s, struct xt_NFQ_info *tinfo)
+{
+	unsigned int num;
+       
+	if (!xtables_strtoui(s, NULL, &num, 0, UINT16_MAX))
+		xtables_error(PARAMETER_PROBLEM,
+			   "Invalid queue number `%s'\n", s);
+
+    	tinfo->queuenum = num & 0xffff;
+}
+
+static int
+NFQUEUE_parse(int c, char **argv, int invert, unsigned int *flags,
+              const void *entry, struct xt_entry_target **target)
+{
+	struct xt_NFQ_info *tinfo
+		= (struct xt_NFQ_info *)(*target)->data;
+
+	switch (c) {
+	case 'F':
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM, "NFQUEUE target: "
+				   "Only use --queue-num ONCE!");
+		parse_num(optarg, tinfo);
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void NFQUEUE_print(const void *ip,
+                          const struct xt_entry_target *target, int numeric)
+{
+	const struct xt_NFQ_info *tinfo =
+		(const struct xt_NFQ_info *)target->data;
+	printf("NFQUEUE num %u", tinfo->queuenum);
+}
+
+static void NFQUEUE_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct xt_NFQ_info *tinfo =
+		(const struct xt_NFQ_info *)target->data;
+
+	printf("--queue-num %u ", tinfo->queuenum);
+}
+
+static struct xtables_target nfqueue_target = {
+	.family		= NFPROTO_IPV4,
+	.name		= "NFQUEUE",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_NFQ_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_NFQ_info)),
+	.help		= NFQUEUE_help,
+	.parse		= NFQUEUE_parse,
+	.print		= NFQUEUE_print,
+	.save		= NFQUEUE_save,
+	.extra_opts	= NFQUEUE_opts
+};
+
+static struct xtables_target nfqueue_target6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "NFQUEUE",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_NFQ_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_NFQ_info)),
+	.help		= NFQUEUE_help,
+	.parse		= NFQUEUE_parse,
+	.print		= NFQUEUE_print,
+	.save		= NFQUEUE_save,
+	.extra_opts	= NFQUEUE_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&nfqueue_target);
+	xtables_register_target(&nfqueue_target6);
+}
diff --git a/ap/app/iptables/extensions/libxt_NFQUEUE.man b/ap/app/iptables/extensions/libxt_NFQUEUE.man
new file mode 100755
index 0000000..b2c90bb
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_NFQUEUE.man
@@ -0,0 +1,12 @@
+This target is an extension of the QUEUE target. As opposed to QUEUE, it allows
+you to put a packet into any specific queue, identified by its 16-bit queue
+number.  
+.TP
+\fB\-\-queue\-num\fP \fIvalue\fP
+This specifies the QUEUE number to use. Valid queue numbers are 0 to 65535. The default value is 0.
+.PP
+It can only be used with Kernel versions 2.6.14 or later, since it requires
+the
+.B
+nfnetlink_queue
+kernel support.
diff --git a/ap/app/iptables/extensions/libxt_NOTRACK.c b/ap/app/iptables/extensions/libxt_NOTRACK.c
new file mode 100755
index 0000000..ef26654
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_NOTRACK.c
@@ -0,0 +1,46 @@
+/* Shared library add-on to iptables to add NOTRACK target support. */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+
+static void NOTRACK_help(void)
+{
+	printf("NOTRACK target takes no options\n");
+}
+
+static int
+NOTRACK_parse(int c, char **argv, int invert, unsigned int *flags,
+              const void *entry, struct xt_entry_target **target)
+{
+	return 0;
+}
+
+static struct xtables_target notrack_target = {
+	.family		= NFPROTO_IPV4,
+	.name		= "NOTRACK",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(0),
+	.userspacesize	= XT_ALIGN(0),
+	.help		= NOTRACK_help,
+	.parse		= NOTRACK_parse,
+};
+
+static struct xtables_target notrack_target6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "NOTRACK",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(0),
+	.userspacesize	= XT_ALIGN(0),
+	.help		= NOTRACK_help,
+	.parse		= NOTRACK_parse,
+};
+
+void _init(void)
+{
+	xtables_register_target(&notrack_target);
+	xtables_register_target(&notrack_target6);
+}
diff --git a/ap/app/iptables/extensions/libxt_NOTRACK.man b/ap/app/iptables/extensions/libxt_NOTRACK.man
new file mode 100755
index 0000000..c2cdf5a
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_NOTRACK.man
@@ -0,0 +1,5 @@
+This target disables connection tracking for all packets matching that rule.
+.PP
+It can only be used in the
+.B raw
+table.
diff --git a/ap/app/iptables/extensions/libxt_RATEEST.c b/ap/app/iptables/extensions/libxt_RATEEST.c
new file mode 100755
index 0000000..d4fd6dd
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_RATEEST.c
@@ -0,0 +1,222 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <getopt.h>
+#include <math.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_RATEEST.h>
+
+/* hack to pass raw values to final_check */
+static struct xt_rateest_target_info *RATEEST_info;
+static unsigned int interval;
+static unsigned int ewma_log;
+
+static void
+RATEEST_help(void)
+{
+	printf(
+"RATEEST target options:\n"
+"  --rateest-name name		Rate estimator name\n"
+"  --rateest-interval sec	Rate measurement interval in seconds\n"
+"  --rateest-ewmalog value	Rate measurement averaging time constant\n");
+}
+
+enum RATEEST_options {
+	RATEEST_OPT_NAME,
+	RATEEST_OPT_INTERVAL,
+	RATEEST_OPT_EWMALOG,
+};
+
+static const struct option RATEEST_opts[] = {
+	{ "rateest-name",	1, NULL, RATEEST_OPT_NAME },
+	{ "rateest-interval",	1, NULL, RATEEST_OPT_INTERVAL },
+	{ "rateest-ewmalog",	1, NULL, RATEEST_OPT_EWMALOG },
+	{ .name = NULL },
+};
+
+/* Copied from iproute */
+#define TIME_UNITS_PER_SEC	1000000
+
+static int
+RATEEST_get_time(unsigned int *time, const char *str)
+{
+	double t;
+	char *p;
+
+	t = strtod(str, &p);
+	if (p == str)
+		return -1;
+
+	if (*p) {
+		if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 ||
+		    strcasecmp(p, "secs")==0)
+			t *= TIME_UNITS_PER_SEC;
+		else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 ||
+			 strcasecmp(p, "msecs") == 0)
+			t *= TIME_UNITS_PER_SEC/1000;
+		else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 ||
+			 strcasecmp(p, "usecs") == 0)
+			t *= TIME_UNITS_PER_SEC/1000000;
+		else
+			return -1;
+	}
+
+	*time = t;
+	return 0;
+}
+
+static void
+RATEEST_print_time(unsigned int time)
+{
+	double tmp = time;
+
+	if (tmp >= TIME_UNITS_PER_SEC)
+		printf("%.1fs ", tmp/TIME_UNITS_PER_SEC);
+	else if (tmp >= TIME_UNITS_PER_SEC/1000)
+		printf("%.1fms ", tmp/(TIME_UNITS_PER_SEC/1000));
+	else
+		printf("%uus ", time);
+}
+
+static void
+RATEEST_init(struct xt_entry_target *target)
+{
+	interval = 0;
+	ewma_log = 0;
+}
+
+static int
+RATEEST_parse(int c, char **argv, int invert, unsigned int *flags,
+	      const void *entry, struct xt_entry_target **target)
+{
+	struct xt_rateest_target_info *info = (void *)(*target)->data;
+
+	RATEEST_info = info;
+
+	switch (c) {
+	case RATEEST_OPT_NAME:
+		if (*flags & (1 << c))
+			xtables_error(PARAMETER_PROBLEM,
+				   "RATEEST: can't specify --rateest-name twice");
+		*flags |= 1 << c;
+
+		strncpy(info->name, optarg, sizeof(info->name) - 1);
+		break;
+
+	case RATEEST_OPT_INTERVAL:
+		if (*flags & (1 << c))
+			xtables_error(PARAMETER_PROBLEM,
+				   "RATEEST: can't specify --rateest-interval twice");
+		*flags |= 1 << c;
+
+		if (RATEEST_get_time(&interval, optarg) < 0)
+			xtables_error(PARAMETER_PROBLEM,
+				   "RATEEST: bad interval value `%s'", optarg);
+
+		break;
+
+	case RATEEST_OPT_EWMALOG:
+		if (*flags & (1 << c))
+			xtables_error(PARAMETER_PROBLEM,
+				   "RATEEST: can't specify --rateest-ewmalog twice");
+		*flags |= 1 << c;
+
+		if (RATEEST_get_time(&ewma_log, optarg) < 0)
+			xtables_error(PARAMETER_PROBLEM,
+				   "RATEEST: bad ewmalog value `%s'", optarg);
+
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+RATEEST_final_check(unsigned int flags)
+{
+	struct xt_rateest_target_info *info = RATEEST_info;
+
+	if (!(flags & (1 << RATEEST_OPT_NAME)))
+		xtables_error(PARAMETER_PROBLEM, "RATEEST: no name specified");
+	if (!(flags & (1 << RATEEST_OPT_INTERVAL)))
+		xtables_error(PARAMETER_PROBLEM, "RATEEST: no interval specified");
+	if (!(flags & (1 << RATEEST_OPT_EWMALOG)))
+		xtables_error(PARAMETER_PROBLEM, "RATEEST: no ewmalog specified");
+
+	for (info->interval = 0; info->interval <= 5; info->interval++) {
+		if (interval <= (1 << info->interval) * (TIME_UNITS_PER_SEC / 4))
+			break;
+	}
+
+	if (info->interval > 5)
+		xtables_error(PARAMETER_PROBLEM,
+			   "RATEEST: interval value is too large");
+	info->interval -= 2;
+
+	for (info->ewma_log = 1; info->ewma_log < 32; info->ewma_log++) {
+		double w = 1.0 - 1.0 / (1 << info->ewma_log);
+		if (interval / (-log(w)) > ewma_log)
+			break;
+	}
+	info->ewma_log--;
+
+	if (info->ewma_log == 0 || info->ewma_log >= 31)
+		xtables_error(PARAMETER_PROBLEM,
+			   "RATEEST: ewmalog value is out of range");
+}
+
+static void
+__RATEEST_print(const struct xt_entry_target *target, const char *prefix)
+{
+	struct xt_rateest_target_info *info = (void *)target->data;
+	unsigned int local_interval;
+	unsigned int local_ewma_log;
+
+	local_interval = (TIME_UNITS_PER_SEC << (info->interval + 2)) / 4;
+	local_ewma_log = local_interval * (1 << (info->ewma_log));
+
+	printf("%sname %s ", prefix, info->name);
+	printf("%sinterval ", prefix);
+	RATEEST_print_time(local_interval);
+	printf("%sewmalog ", prefix);
+	RATEEST_print_time(local_ewma_log);
+}
+
+static void
+RATEEST_print(const void *ip, const struct xt_entry_target *target,
+	      int numeric)
+{
+	__RATEEST_print(target, "");
+}
+
+static void
+RATEEST_save(const void *ip, const struct xt_entry_target *target)
+{
+	__RATEEST_print(target, "--rateest-");
+}
+
+static struct xtables_target rateest_tg_reg = {
+	.family		= AF_UNSPEC,
+	.name		= "RATEEST",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_rateest_target_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_rateest_target_info)),
+	.help		= RATEEST_help,
+	.init		= RATEEST_init,
+	.parse		= RATEEST_parse,
+	.final_check	= RATEEST_final_check,
+	.print		= RATEEST_print,
+	.save		= RATEEST_save,
+	.extra_opts	= RATEEST_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&rateest_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_RATEEST.man b/ap/app/iptables/extensions/libxt_RATEEST.man
new file mode 100755
index 0000000..37de759
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_RATEEST.man
@@ -0,0 +1,12 @@
+The RATEEST target collects statistics, performs rate estimation calculation
+and saves the results for later evaluation using the \fBrateest\fP match.
+.TP
+\fB\-\-rateest\-name\fP \fIname\fP
+Count matched packets into the pool referred to by \fIname\fP, which is freely
+choosable.
+.TP
+\fB\-\-rateest\-interval\fP \fIamount\fP{\fBs\fP|\fBms\fP|\fBus\fP}
+Rate measurement interval, in seconds, milliseconds or microseconds.
+.TP
+\fB\-\-rateest\-ewmalog\fP \fIvalue\fP
+Rate measurement averaging time constant.
diff --git a/ap/app/iptables/extensions/libxt_SECMARK.c b/ap/app/iptables/extensions/libxt_SECMARK.c
new file mode 100755
index 0000000..9db2327
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_SECMARK.c
@@ -0,0 +1,113 @@
+/*
+ * Shared library add-on to iptables to add SECMARK target support.
+ *
+ * Based on the MARK target.
+ *
+ * Copyright (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter/xt_SECMARK.h>
+
+#define PFX "SECMARK target: "
+
+static void SECMARK_help(void)
+{
+	printf(
+"SECMARK target options:\n"
+"  --selctx value                     Set the SELinux security context\n");
+}
+
+static const struct option SECMARK_opts[] = {
+	{ "selctx", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static int SECMARK_parse(int c, char **argv, int invert, unsigned int *flags,
+                         const void *entry, struct xt_entry_target **target)
+{
+	struct xt_secmark_target_info *info =
+		(struct xt_secmark_target_info*)(*target)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & SECMARK_MODE_SEL)
+			xtables_error(PARAMETER_PROBLEM, PFX
+				   "Can't specify --selctx twice");
+		info->mode = SECMARK_MODE_SEL;
+
+		if (strlen(optarg) > SECMARK_SELCTX_MAX-1)
+			xtables_error(PARAMETER_PROBLEM, PFX
+				   "Maximum length %u exceeded by --selctx"
+				   " parameter (%zu)",
+				   SECMARK_SELCTX_MAX-1, strlen(optarg));
+
+		strcpy(info->u.sel.selctx, optarg);
+		*flags |= SECMARK_MODE_SEL;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void SECMARK_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM, PFX "parameter required");
+}
+
+static void print_secmark(struct xt_secmark_target_info *info)
+{
+	switch (info->mode) {
+	case SECMARK_MODE_SEL:
+		printf("selctx %s ", info->u.sel.selctx);\
+		break;
+	
+	default:
+		xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", info->mode);
+	}
+}
+
+static void SECMARK_print(const void *ip, const struct xt_entry_target *target,
+                          int numeric)
+{
+	struct xt_secmark_target_info *info =
+		(struct xt_secmark_target_info*)(target)->data;
+
+	printf("SECMARK ");
+	print_secmark(info);
+}
+
+static void SECMARK_save(const void *ip, const struct xt_entry_target *target)
+{
+	struct xt_secmark_target_info *info =
+		(struct xt_secmark_target_info*)target->data;
+
+	printf("--");
+	print_secmark(info);
+}
+
+static struct xtables_target secmark_target = {
+	.family		= AF_UNSPEC,
+	.name		= "SECMARK",
+	.version	= XTABLES_VERSION,
+	.revision	= 0,
+	.size		= XT_ALIGN(sizeof(struct xt_secmark_target_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_secmark_target_info)),
+	.help		= SECMARK_help,
+	.parse		= SECMARK_parse,
+	.final_check	= SECMARK_check,
+	.print		= SECMARK_print,
+	.save		= SECMARK_save,
+	.extra_opts	= SECMARK_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&secmark_target);
+}
diff --git a/ap/app/iptables/extensions/libxt_SECMARK.man b/ap/app/iptables/extensions/libxt_SECMARK.man
new file mode 100755
index 0000000..f58bb43
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_SECMARK.man
@@ -0,0 +1,7 @@
+This is used to set the security mark value associated with the
+packet for use by security subsystems such as SELinux.  It is only
+valid in the
+.B mangle
+table.
+.TP
+\fB\-\-selctx\fP \fIsecurity_context\fP
diff --git a/ap/app/iptables/extensions/libxt_TCPMSS.c b/ap/app/iptables/extensions/libxt_TCPMSS.c
new file mode 100755
index 0000000..ac9e2d0
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_TCPMSS.c
@@ -0,0 +1,154 @@
+/* Shared library add-on to iptables to add TCPMSS target support.
+ *
+ * Copyright (c) 2000 Marc Boucher
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_TCPMSS.h>
+
+struct mssinfo {
+	struct xt_entry_target t;
+	struct xt_tcpmss_info mss;
+};
+
+static void __TCPMSS_help(int hdrsize)
+{
+	printf(
+"TCPMSS target mutually-exclusive options:\n"
+"  --set-mss value               explicitly set MSS option to specified value\n"
+"  --clamp-mss-to-pmtu           automatically clamp MSS value to (path_MTU - %d)\n",
+hdrsize);
+}
+
+static void TCPMSS_help(void)
+{
+	__TCPMSS_help(40);
+}
+
+static void TCPMSS_help6(void)
+{
+	__TCPMSS_help(60);
+}
+
+static const struct option TCPMSS_opts[] = {
+	{ "set-mss", 1, NULL, '1' },
+	{ "clamp-mss-to-pmtu", 0, NULL, '2' },
+	{ .name = NULL }
+};
+
+static int __TCPMSS_parse(int c, char **argv, int invert, unsigned int *flags,
+                          const void *entry, struct xt_entry_target **target,
+                          int hdrsize)
+{
+	struct xt_tcpmss_info *mssinfo
+		= (struct xt_tcpmss_info *)(*target)->data;
+
+	switch (c) {
+		unsigned int mssval;
+
+	case '1':
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+			           "TCPMSS target: Only one option may be specified");
+		if (!xtables_strtoui(optarg, NULL, &mssval,
+		    0, UINT16_MAX - hdrsize))
+			xtables_error(PARAMETER_PROBLEM, "Bad TCPMSS value \"%s\"", optarg);
+		
+		mssinfo->mss = mssval;
+		*flags = 1;
+		break;
+
+	case '2':
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+			           "TCPMSS target: Only one option may be specified");
+		mssinfo->mss = XT_TCPMSS_CLAMP_PMTU;
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static int TCPMSS_parse(int c, char **argv, int invert, unsigned int *flags,
+                        const void *entry, struct xt_entry_target **target)
+{
+	return __TCPMSS_parse(c, argv, invert, flags, entry, target, 40);
+}
+
+static int TCPMSS_parse6(int c, char **argv, int invert, unsigned int *flags,
+                         const void *entry, struct xt_entry_target **target)
+{
+	return __TCPMSS_parse(c, argv, invert, flags, entry, target, 60);
+}
+
+static void TCPMSS_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+		           "TCPMSS target: At least one parameter is required");
+}
+
+static void TCPMSS_print(const void *ip, const struct xt_entry_target *target,
+                         int numeric)
+{
+	const struct xt_tcpmss_info *mssinfo =
+		(const struct xt_tcpmss_info *)target->data;
+	if(mssinfo->mss == XT_TCPMSS_CLAMP_PMTU)
+		printf("TCPMSS clamp to PMTU ");
+	else
+		printf("TCPMSS set %u ", mssinfo->mss);
+}
+
+static void TCPMSS_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct xt_tcpmss_info *mssinfo =
+		(const struct xt_tcpmss_info *)target->data;
+
+	if(mssinfo->mss == XT_TCPMSS_CLAMP_PMTU)
+		printf("--clamp-mss-to-pmtu ");
+	else
+		printf("--set-mss %u ", mssinfo->mss);
+}
+
+static struct xtables_target tcpmss_target = {
+	.family		= NFPROTO_IPV4,
+	.name		= "TCPMSS",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_tcpmss_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_tcpmss_info)),
+	.help		= TCPMSS_help,
+	.parse		= TCPMSS_parse,
+	.final_check	= TCPMSS_check,
+	.print		= TCPMSS_print,
+	.save		= TCPMSS_save,
+	.extra_opts	= TCPMSS_opts,
+};
+
+static struct xtables_target tcpmss_target6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "TCPMSS",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_tcpmss_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_tcpmss_info)),
+	.help		= TCPMSS_help6,
+	.parse		= TCPMSS_parse6,
+	.final_check	= TCPMSS_check,
+	.print		= TCPMSS_print,
+	.save		= TCPMSS_save,
+	.extra_opts	= TCPMSS_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&tcpmss_target);
+	xtables_register_target(&tcpmss_target6);
+}
diff --git a/ap/app/iptables/extensions/libxt_TCPMSS.man b/ap/app/iptables/extensions/libxt_TCPMSS.man
new file mode 100755
index 0000000..675fc5e
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_TCPMSS.man
@@ -0,0 +1,43 @@
+This target allows to alter the MSS value of TCP SYN packets, to control
+the maximum size for that connection (usually limiting it to your
+outgoing interface's MTU minus 40 for IPv4 or 60 for IPv6, respectively).
+Of course, it can only be used
+in conjunction with
+\fB\-p tcp\fP.
+It is only valid in the
+.BR mangle
+table.
+.br
+This target is used to overcome criminally braindead ISPs or servers
+which block "ICMP Fragmentation Needed" or "ICMPv6 Packet Too Big"
+packets.  The symptoms of this
+problem are that everything works fine from your Linux
+firewall/router, but machines behind it can never exchange large
+packets:
+.PD 0
+.RS 0.1i
+.TP 0.3i
+1)
+Web browsers connect, then hang with no data received.
+.TP
+2)
+Small mail works fine, but large emails hang.
+.TP
+3)
+ssh works fine, but scp hangs after initial handshaking.
+.RE
+.PD
+Workaround: activate this option and add a rule to your firewall
+configuration like:
+.nf
+ iptables \-t mangle \-A FORWARD \-p tcp \-\-tcp\-flags SYN,RST SYN \\
+             \-j TCPMSS \-\-clamp\-mss\-to\-pmtu
+.fi
+.TP
+\fB\-\-set\-mss\fP \fIvalue\fP
+Explicitly set MSS option to specified value.
+.TP
+\fB\-\-clamp\-mss\-to\-pmtu\fP
+Automatically clamp MSS value to (path_MTU \- 40 for IPv4; \-60 for IPv6).
+.PP
+These options are mutually exclusive.
diff --git a/ap/app/iptables/extensions/libxt_TCPOPTSTRIP.c b/ap/app/iptables/extensions/libxt_TCPOPTSTRIP.c
new file mode 100755
index 0000000..cf946fc
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_TCPOPTSTRIP.c
@@ -0,0 +1,214 @@
+/*
+ * Shared library add-on to iptables to add TCPOPTSTRIP target support.
+ * Copyright (c) 2007 Sven Schnelle <svens@bitebene.org>
+ * Copyright © CC Computer Consultants GmbH, 2007
+ * Jan Engelhardt <jengelh@computergmbh.de>
+ */
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <xtables.h>
+#include <netinet/tcp.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_TCPOPTSTRIP.h>
+#ifndef TCPOPT_MD5SIG
+#	define TCPOPT_MD5SIG 19
+#endif
+
+enum {
+	FLAG_STRIP = 1 << 0,
+};
+
+struct tcp_optionmap {
+	const char *name, *desc;
+	const unsigned int option;
+};
+
+static const struct option tcpoptstrip_tg_opts[] = {
+	{.name = "strip-options", .has_arg = true, .val = 's'},
+	{ .name = NULL }
+};
+
+static const struct tcp_optionmap tcp_optionmap[] = {
+	{"wscale",         "Window scale",         TCPOPT_WINDOW},
+	{"mss",            "Maximum Segment Size", TCPOPT_MAXSEG},
+	{"sack-permitted", "SACK permitted",       TCPOPT_SACK_PERMITTED},
+	{"sack",           "Selective ACK",        TCPOPT_SACK},
+	{"timestamp",      "Timestamp",            TCPOPT_TIMESTAMP},
+	{"md5",            "MD5 signature",        TCPOPT_MD5SIG},
+	{ .name = NULL }
+};
+
+static void tcpoptstrip_tg_help(void)
+{
+	const struct tcp_optionmap *w;
+
+	printf(
+"TCPOPTSTRIP target options:\n"
+"  --strip-options value     strip specified TCP options denoted by value\n"
+"                            (separated by comma) from TCP header\n"
+"  Instead of the numeric value, you can also use the following names:\n"
+	);
+
+	for (w = tcp_optionmap; w->name != NULL; ++w)
+		printf("    %-14s    strip \"%s\" option\n", w->name, w->desc);
+}
+
+static void tcpoptstrip_tg_init(struct xt_entry_target *t)
+{
+	struct xt_tcpoptstrip_target_info *info = (void *)t->data;
+
+	/* strictly necessary? play safe for now. */
+	memset(info->strip_bmap, 0, sizeof(info->strip_bmap));
+}
+
+static void parse_list(struct xt_tcpoptstrip_target_info *info, char *arg)
+{
+	unsigned int option;
+	char *p;
+	int i;
+
+	while (true) {
+		p = strchr(arg, ',');
+		if (p != NULL)
+			*p = '\0';
+
+		option = 0;
+		for (i = 0; tcp_optionmap[i].name != NULL; ++i)
+			if (strcmp(tcp_optionmap[i].name, arg) == 0) {
+				option = tcp_optionmap[i].option;
+				break;
+			}
+
+		if (option == 0 &&
+		    !xtables_strtoui(arg, NULL, &option, 0, UINT8_MAX))
+			xtables_error(PARAMETER_PROBLEM,
+			           "Bad TCP option value \"%s\"", arg);
+
+		if (option < 2)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Option value may not be 0 or 1");
+
+		if (tcpoptstrip_test_bit(info->strip_bmap, option))
+			xtables_error(PARAMETER_PROBLEM,
+			           "Option \"%s\" already specified", arg);
+
+		tcpoptstrip_set_bit(info->strip_bmap, option);
+		if (p == NULL)
+			break;
+		arg = p + 1;
+	}
+}
+
+static int tcpoptstrip_tg_parse(int c, char **argv, int invert,
+                                unsigned int *flags, const void *entry,
+                                struct xt_entry_target **target)
+{
+	struct xt_tcpoptstrip_target_info *info = (void *)(*target)->data;
+
+	switch (c) {
+	case 's':
+		if (*flags & FLAG_STRIP)
+			xtables_error(PARAMETER_PROBLEM,
+			           "You can specify --strip-options only once");
+		parse_list(info, optarg);
+		*flags |= FLAG_STRIP;
+		return true;
+	}
+
+	return false;
+}
+
+static void tcpoptstrip_tg_check(unsigned int flags)
+{
+	if (flags == 0)
+		xtables_error(PARAMETER_PROBLEM,
+		           "TCPOPTSTRIP: --strip-options parameter required");
+}
+
+static void
+tcpoptstrip_print_list(const struct xt_tcpoptstrip_target_info *info,
+                       bool numeric)
+{
+	unsigned int i, j;
+	const char *name;
+	bool first = true;
+
+	for (i = 0; i < 256; ++i) {
+		if (!tcpoptstrip_test_bit(info->strip_bmap, i))
+			continue;
+		if (!first)
+			printf(",");
+
+		first = false;
+		name  = NULL;
+		if (!numeric)
+			for (j = 0; tcp_optionmap[j].name != NULL; ++j)
+				if (tcp_optionmap[j].option == i)
+					name = tcp_optionmap[j].name;
+
+		if (name != NULL)
+			printf("%s", name);
+		else
+			printf("%u", i);
+	}
+}
+
+static void
+tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target,
+                     int numeric)
+{
+	const struct xt_tcpoptstrip_target_info *info =
+		(const void *)target->data;
+
+	printf("TCPOPTSTRIP options ");
+	tcpoptstrip_print_list(info, numeric);
+}
+
+static void
+tcpoptstrip_tg_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct xt_tcpoptstrip_target_info *info =
+		(const void *)target->data;
+
+	printf("--strip-options ");
+	tcpoptstrip_print_list(info, true);
+}
+
+static struct xtables_target tcpoptstrip_tg_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "TCPOPTSTRIP",
+	.family        = NFPROTO_IPV4,
+	.size          = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
+	.help          = tcpoptstrip_tg_help,
+	.init          = tcpoptstrip_tg_init,
+	.parse         = tcpoptstrip_tg_parse,
+	.final_check   = tcpoptstrip_tg_check,
+	.print         = tcpoptstrip_tg_print,
+	.save          = tcpoptstrip_tg_save,
+	.extra_opts    = tcpoptstrip_tg_opts,
+};
+
+static struct xtables_target tcpoptstrip_tg6_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "TCPOPTSTRIP",
+	.family        = NFPROTO_IPV6,
+	.size          = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
+	.help          = tcpoptstrip_tg_help,
+	.init          = tcpoptstrip_tg_init,
+	.parse         = tcpoptstrip_tg_parse,
+	.final_check   = tcpoptstrip_tg_check,
+	.print         = tcpoptstrip_tg_print,
+	.save          = tcpoptstrip_tg_save,
+	.extra_opts    = tcpoptstrip_tg_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&tcpoptstrip_tg_reg);
+	xtables_register_target(&tcpoptstrip_tg6_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_TCPOPTSTRIP.man b/ap/app/iptables/extensions/libxt_TCPOPTSTRIP.man
new file mode 100755
index 0000000..2a07709
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_TCPOPTSTRIP.man
@@ -0,0 +1,7 @@
+This target will strip TCP options off a TCP packet. (It will actually replace
+them by NO-OPs.) As such, you will need to add the \fB\-p tcp\fP parameters.
+.TP
+\fB\-\-strip\-options\fP \fIoption\fP[\fB,\fP\fIoption\fP...]
+Strip the given option(s). The options may be specified by TCP option number or
+by symbolic name. The list of recognized options can be obtained by calling
+iptables with \fB\-j TCPOPTSTRIP \-h\fP.
diff --git a/ap/app/iptables/extensions/libxt_TOS.c b/ap/app/iptables/extensions/libxt_TOS.c
new file mode 100755
index 0000000..c08f53b
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_TOS.c
@@ -0,0 +1,258 @@
+/*
+ * Shared library add-on to iptables to add TOS target support
+ *
+ * Copyright © CC Computer Consultants GmbH, 2007
+ * Contact: Jan Engelhardt <jengelh@computergmbh.de>
+ */
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_DSCP.h>
+#include <linux/netfilter_ipv4/ipt_TOS.h>
+#include "tos_values.c"
+
+enum {
+	FLAG_TOS = 1 << 0,
+};
+
+static const struct option tos_tg_opts_v0[] = {
+	{.name = "set-tos", .has_arg = true, .val = '='},
+	{ .name = NULL }
+};
+
+static const struct option tos_tg_opts[] = {
+	{.name = "set-tos", .has_arg = true, .val = '='},
+	{.name = "and-tos", .has_arg = true, .val = '&'},
+	{.name = "or-tos",  .has_arg = true, .val = '|'},
+	{.name = "xor-tos", .has_arg = true, .val = '^'},
+	{ .name = NULL }
+};
+
+static void tos_tg_help_v0(void)
+{
+	const struct tos_symbol_info *symbol;
+
+	printf(
+"TOS target options:\n"
+"  --set-tos value     Set Type of Service/Priority field to value\n"
+"  --set-tos symbol    Set TOS field (IPv4 only) by symbol\n"
+"                      Accepted symbolic names for value are:\n");
+
+	for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
+		printf("                        (0x%02x) %2u %s\n",
+		       symbol->value, symbol->value, symbol->name);
+
+	printf("\n");
+}
+
+static void tos_tg_help(void)
+{
+	const struct tos_symbol_info *symbol;
+
+	printf(
+"TOS target v%s options:\n"
+"  --set-tos value[/mask]  Set Type of Service/Priority field to value\n"
+"                          (Zero out bits in mask and XOR value into TOS)\n"
+"  --set-tos symbol        Set TOS field (IPv4 only) by symbol\n"
+"                          (this zeroes the 4-bit Precedence part!)\n"
+"                          Accepted symbolic names for value are:\n",
+XTABLES_VERSION);
+
+	for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
+		printf("                            (0x%02x) %2u %s\n",
+		       symbol->value, symbol->value, symbol->name);
+
+	printf(
+"\n"
+"  --and-tos bits          Binary AND the TOS value with bits\n"
+"  --or-tos  bits          Binary OR the TOS value with bits\n"
+"  --xor-tos bits          Binary XOR the TOS value with bits\n"
+);
+}
+
+static int tos_tg_parse_v0(int c, char **argv, int invert, unsigned int *flags,
+                           const void *entry, struct xt_entry_target **target)
+{
+	struct ipt_tos_target_info *info = (void *)(*target)->data;
+	struct tos_value_mask tvm;
+
+	switch (c) {
+	case '=':
+		xtables_param_act(XTF_ONLY_ONCE, "TOS", "--set-tos", *flags & FLAG_TOS);
+		xtables_param_act(XTF_NO_INVERT, "TOS", "--set-tos", invert);
+		if (!tos_parse_symbolic(optarg, &tvm, 0xFF))
+			xtables_param_act(XTF_BAD_VALUE, "TOS", "--set-tos", optarg);
+		if (tvm.mask != 0xFF)
+			xtables_error(PARAMETER_PROBLEM, "tos match: Your kernel "
+			           "is too old to support anything besides "
+				   "/0xFF as a mask.");
+		info->tos = tvm.value;
+		*flags |= FLAG_TOS;
+		return true;
+	}
+
+	return false;
+}
+
+static int tos_tg_parse(int c, char **argv, int invert, unsigned int *flags,
+                         const void *entry, struct xt_entry_target **target)
+{
+	struct xt_tos_target_info *info = (void *)(*target)->data;
+	struct tos_value_mask tvm;
+	unsigned int bits;
+
+	switch (c) {
+	case '=': /* --set-tos */
+		xtables_param_act(XTF_ONLY_ONCE, "TOS", "--set-tos", *flags & FLAG_TOS);
+		xtables_param_act(XTF_NO_INVERT, "TOS", "--set-tos", invert);
+		if (!tos_parse_symbolic(optarg, &tvm, 0x3F))
+			xtables_param_act(XTF_BAD_VALUE, "TOS", "--set-tos", optarg);
+		info->tos_value = tvm.value;
+		info->tos_mask  = tvm.mask;
+		break;
+
+	case '&': /* --and-tos */
+		xtables_param_act(XTF_ONLY_ONCE, "TOS", "--and-tos", *flags & FLAG_TOS);
+		xtables_param_act(XTF_NO_INVERT, "TOS", "--and-tos", invert);
+		if (!xtables_strtoui(optarg, NULL, &bits, 0, UINT8_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "TOS", "--and-tos", optarg);
+		info->tos_value = 0;
+		info->tos_mask  = ~bits;
+		break;
+
+	case '|': /* --or-tos */
+		xtables_param_act(XTF_ONLY_ONCE, "TOS", "--or-tos", *flags & FLAG_TOS);
+		xtables_param_act(XTF_NO_INVERT, "TOS", "--or-tos", invert);
+		if (!xtables_strtoui(optarg, NULL, &bits, 0, UINT8_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "TOS", "--or-tos", optarg);
+		info->tos_value = bits;
+		info->tos_mask  = bits;
+		break;
+
+	case '^': /* --xor-tos */
+		xtables_param_act(XTF_ONLY_ONCE, "TOS", "--xor-tos", *flags & FLAG_TOS);
+		xtables_param_act(XTF_NO_INVERT, "TOS", "--xor-tos", invert);
+		if (!xtables_strtoui(optarg, NULL, &bits, 0, UINT8_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "TOS", "--xor-tos", optarg);
+		info->tos_value = bits;
+		info->tos_mask  = 0;
+		break;
+
+	default:
+		return false;
+	}
+
+	*flags |= FLAG_TOS;
+	return true;
+}
+
+static void tos_tg_check(unsigned int flags)
+{
+	if (flags == 0)
+		xtables_error(PARAMETER_PROBLEM,
+		           "TOS: The --set-tos parameter is required");
+}
+
+static void tos_tg_print_v0(const void *ip,
+                            const struct xt_entry_target *target, int numeric)
+{
+	const struct ipt_tos_target_info *info = (const void *)target->data;
+
+	printf("TOS set ");
+	if (numeric || !tos_try_print_symbolic("", info->tos, 0xFF))
+		printf("0x%02x ", info->tos);
+}
+
+static void tos_tg_print(const void *ip, const struct xt_entry_target *target,
+                         int numeric)
+{
+	const struct xt_tos_target_info *info = (const void *)target->data;
+
+	if (numeric)
+		printf("TOS set 0x%02x/0x%02x ",
+		       info->tos_value, info->tos_mask);
+	else if (tos_try_print_symbolic("TOS set ",
+	    info->tos_value, info->tos_mask))
+		/* already printed by call */
+		return;
+	else if (info->tos_value == 0)
+		printf("TOS and 0x%02x ",
+		       (unsigned int)(u_int8_t)~info->tos_mask);
+	else if (info->tos_value == info->tos_mask)
+		printf("TOS or 0x%02x ", info->tos_value);
+	else if (info->tos_mask == 0)
+		printf("TOS xor 0x%02x ", info->tos_value);
+	else
+		printf("TOS set 0x%02x/0x%02x ",
+		       info->tos_value, info->tos_mask);
+}
+
+static void tos_tg_save_v0(const void *ip, const struct xt_entry_target *target)
+{
+	const struct ipt_tos_target_info *info = (const void *)target->data;
+
+	printf("--set-tos 0x%02x ", info->tos);
+}
+
+static void tos_tg_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct xt_tos_target_info *info = (const void *)target->data;
+
+	printf("--set-tos 0x%02x/0x%02x ", info->tos_value, info->tos_mask);
+}
+
+static struct xtables_target tos_tg_reg_v0 = {
+	.version       = XTABLES_VERSION,
+	.name          = "TOS",
+	.revision      = 0,
+	.family        = NFPROTO_IPV4,
+	.size          = XT_ALIGN(sizeof(struct xt_tos_target_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_tos_target_info)),
+	.help          = tos_tg_help_v0,
+	.parse         = tos_tg_parse_v0,
+	.final_check   = tos_tg_check,
+	.print         = tos_tg_print_v0,
+	.save          = tos_tg_save_v0,
+	.extra_opts    = tos_tg_opts_v0,
+};
+
+static struct xtables_target tos_tg_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "TOS",
+	.revision      = 1,
+	.family        = NFPROTO_IPV4,
+	.size          = XT_ALIGN(sizeof(struct xt_tos_target_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_tos_target_info)),
+	.help          = tos_tg_help,
+	.parse         = tos_tg_parse,
+	.final_check   = tos_tg_check,
+	.print         = tos_tg_print,
+	.save          = tos_tg_save,
+	.extra_opts    = tos_tg_opts,
+};
+
+static struct xtables_target tos_tg6_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "TOS",
+	.family        = NFPROTO_IPV6,
+	.revision      = 1,
+	.size          = XT_ALIGN(sizeof(struct xt_tos_target_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_tos_target_info)),
+	.help          = tos_tg_help,
+	.parse         = tos_tg_parse,
+	.final_check   = tos_tg_check,
+	.print         = tos_tg_print,
+	.save          = tos_tg_save,
+	.extra_opts    = tos_tg_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&tos_tg_reg_v0);
+	xtables_register_target(&tos_tg_reg);
+	xtables_register_target(&tos_tg6_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_TOS.man b/ap/app/iptables/extensions/libxt_TOS.man
new file mode 100755
index 0000000..a42a73d
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_TOS.man
@@ -0,0 +1,27 @@
+This module sets the Type of Service field in the IPv4 header (including the
+'precedence' bits) or the Priority field in the IPv6 header. Note that TOS
+shares the same bits as DSCP and ECN. The TOS target is only valid in the
+\fBmangle\fR table.
+.TP
+\fB\-\-set\-tos\fP \fIvalue\fP[\fB/\fP\fImask\fP]
+Zeroes out the bits given by \fImask\fR and XORs \fIvalue\fR into the
+TOS/Priority field. If \fImask\fR is omitted, 0xFF is assumed.
+.TP
+\fB\-\-set\-tos\fP \fIsymbol\fP
+You can specify a symbolic name when using the TOS target for IPv4. It implies
+a mask of 0xFF. The list of recognized TOS names can be obtained by calling
+iptables with \fB\-j TOS \-h\fP.
+.PP
+The following mnemonics are available:
+.TP
+\fB\-\-and\-tos\fP \fIbits\fP
+Binary AND the TOS value with \fIbits\fR. (Mnemonic for \fB\-\-set\-tos
+0/\fR\fIinvbits\fR, where \fIinvbits\fR is the binary negation of \fIbits\fR.)
+.TP
+\fB\-\-or\-tos\fP \fIbits\fP
+Binary OR the TOS value with \fIbits\fR. (Mnemonic for \fB\-\-set\-tos\fP
+\fIbits\fR\fB/\fR\fIbits\fR.)
+.TP
+\fB\-\-xor\-tos\fP \fIbits\fP
+Binary XOR the TOS value with \fIbits\fR. (Mnemonic for \fB\-\-set\-tos\fP
+\fIbits\fR\fB/0\fR.)
diff --git a/ap/app/iptables/extensions/libxt_TPROXY.c b/ap/app/iptables/extensions/libxt_TPROXY.c
new file mode 100755
index 0000000..d410c52
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_TPROXY.c
@@ -0,0 +1,150 @@
+/*
+ * Shared library add-on to iptables to add TPROXY target support.
+ *
+ * Copyright (C) 2002-2008 BalaBit IT Ltd.
+ */
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_TPROXY.h>
+
+static const struct option tproxy_tg_opts[] = {
+	{ .name = "on-port", .has_arg = 1, .val = '1'},
+	{ .name = "on-ip", .has_arg = 1, .val = '2'},
+	{ .name = "tproxy-mark", .has_arg = 1, .val = '3'},
+	{NULL},
+};
+
+enum {
+	PARAM_ONPORT = 1 << 0,
+	PARAM_ONIP = 1 << 1,
+	PARAM_MARK = 1 << 2,
+};
+
+static void tproxy_tg_help(void)
+{
+	printf(
+"TPROXY target options:\n"
+"  --on-port port		    Redirect connection to port, or the original port if 0\n"
+"  --on-ip ip			    Optionally redirect to the given IP\n"
+"  --tproxy-mark value[/mask]	    Mark packets with the given value/mask\n\n");
+}
+
+static void parse_tproxy_lport(const char *s, struct xt_tproxy_target_info *info)
+{
+	unsigned int lport;
+
+	if (xtables_strtoui(s, NULL, &lport, 0, UINT16_MAX))
+		info->lport = htons(lport);
+	else
+		xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--on-port", s);
+}
+
+static void parse_tproxy_laddr(const char *s, struct xt_tproxy_target_info *info)
+{
+	struct in_addr *laddr;
+
+	if ((laddr = xtables_numeric_to_ipaddr(s)) == NULL)
+		xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--on-ip", s);
+
+	info->laddr = laddr->s_addr;
+}
+
+static void parse_tproxy_mark(char *s, struct xt_tproxy_target_info *info)
+{
+	unsigned int value, mask = UINT32_MAX;
+	char *end;
+
+	if (!xtables_strtoui(s, &end, &value, 0, UINT32_MAX))
+		xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s);
+	if (*end == '/')
+		if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s);
+	if (*end != '\0')
+		xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s);
+
+	info->mark_mask = mask;
+	info->mark_value = value;
+}
+
+static int tproxy_tg_parse(int c, char **argv, int invert, unsigned int *flags,
+			const void *entry, struct xt_entry_target **target)
+{
+	struct xt_tproxy_target_info *tproxyinfo = (void *)(*target)->data;
+
+	switch (c) {
+	case '1':
+		xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-port", *flags & PARAM_ONPORT);
+		xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-port", invert);
+		parse_tproxy_lport(optarg, tproxyinfo);
+		*flags |= PARAM_ONPORT;
+		return 1;
+	case '2':
+		xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-ip", *flags & PARAM_ONIP);
+		xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-ip", invert);
+		parse_tproxy_laddr(optarg, tproxyinfo);
+		*flags |= PARAM_ONIP;
+		return 1;
+	case '3':
+		xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--tproxy-mark", *flags & PARAM_MARK);
+		xtables_param_act(XTF_NO_INVERT, "TPROXY", "--tproxy-mark", invert);
+		parse_tproxy_mark(optarg, tproxyinfo);
+		*flags |= PARAM_MARK;
+		return 1;
+	}
+
+	return 0;
+}
+
+static void tproxy_tg_check(unsigned int flags)
+{
+	if (!(flags & PARAM_ONPORT))
+		xtables_error(PARAMETER_PROBLEM,
+			   "TPROXY target: Parameter --on-port is required");
+}
+
+static void tproxy_tg_print(const void *ip, const struct xt_entry_target *target,
+			 int numeric)
+{
+	const struct xt_tproxy_target_info *info = (const void *)target->data;
+	printf("TPROXY redirect %s:%u mark 0x%x/0x%x",
+	       xtables_ipaddr_to_numeric((const struct in_addr *)&info->laddr),
+	       ntohs(info->lport), (unsigned int)info->mark_value,
+	       (unsigned int)info->mark_mask);
+}
+
+static void tproxy_tg_save(const void *ip, const struct xt_entry_target *target)
+{
+	const struct xt_tproxy_target_info *info = (const void *)target->data;
+
+	printf("--on-port %u ", ntohs(info->lport));
+	printf("--on-ip %s ",
+	       xtables_ipaddr_to_numeric((const struct in_addr *)&info->laddr));
+	printf("--tproxy-mark 0x%x/0x%x ",
+	       (unsigned int)info->mark_value, (unsigned int)info->mark_mask);
+}
+
+static struct xtables_target tproxy_tg_reg = {
+	.name	       = "TPROXY",
+	.family	       = NFPROTO_IPV4,
+	.version       = XTABLES_VERSION,
+	.size	       = XT_ALIGN(sizeof(struct xt_tproxy_target_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info)),
+	.help	       = tproxy_tg_help,
+	.parse	       = tproxy_tg_parse,
+	.final_check   = tproxy_tg_check,
+	.print	       = tproxy_tg_print,
+	.save	       = tproxy_tg_save,
+	.extra_opts    = tproxy_tg_opts,
+};
+
+void _init(void)
+{
+	xtables_register_target(&tproxy_tg_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_TPROXY.man b/ap/app/iptables/extensions/libxt_TPROXY.man
new file mode 100755
index 0000000..c087ebf
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_TPROXY.man
@@ -0,0 +1,21 @@
+This target is only valid in the \fBmangle\fR table, in the \fBPREROUTING\fR
+chain and user-defined chains which are only called from this chain. It
+redirects the packet to a local socket without changing the packet header in
+any way. It can also change the mark value which can then be used in advanced
+routing rules.
+It takes three options:
+.TP
+\fB\-\-on\-port\fP \fIport\fP
+This specifies a destination port to use. It is a required option, 0 means the
+new destination port is the same as the original. This is only valid if the
+rule also specifies \fB\-p tcp\fP or \fB\-p udp\fP.
+.TP
+\fB\-\-on\-ip\fP \fIaddress\fP
+This specifies a destination address to use. By default the address is the IP
+address of the incoming interface. This is only valid if the rule also
+specifies \fB\-p tcp\fP or \fP\-p udp\fP.
+.TP
+\fB\-\-tproxy\-mark\fP \fIvalue\fP[\fB/\fP\fImask\fP]
+Marks packets with the given value/mask. The fwmark value set here can be used
+by advanced routing. (Required for transparent proxying to work: otherwise
+these packets will get forwarded, which is probably not what you want.)
diff --git a/ap/app/iptables/extensions/libxt_TRACE.c b/ap/app/iptables/extensions/libxt_TRACE.c
new file mode 100755
index 0000000..b8eb969
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_TRACE.c
@@ -0,0 +1,34 @@
+/* Shared library add-on to iptables to add TRACE target support. */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+
+static void TRACE_help(void)
+{
+	printf("TRACE target takes no options\n");
+}
+
+static int TRACE_parse(int c, char **argv, int invert, unsigned int *flags,
+                       const void *entry, struct xt_entry_target **target)
+{
+	return 0;
+}
+
+static struct xtables_target trace_target = {
+	.family		= AF_UNSPEC,
+	.name		= "TRACE",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(0),
+	.userspacesize	= XT_ALIGN(0),
+	.help		= TRACE_help,
+	.parse		= TRACE_parse,
+};
+
+void _init(void)
+{
+	xtables_register_target(&trace_target);
+}
diff --git a/ap/app/iptables/extensions/libxt_TRACE.man b/ap/app/iptables/extensions/libxt_TRACE.man
new file mode 100755
index 0000000..d28c3a0
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_TRACE.man
@@ -0,0 +1,11 @@
+This target marks packes so that the kernel will log every rule which match 
+the packets as those traverse the tables, chains, rules. (The ipt_LOG or
+ip6t_LOG module 
+is required for the logging.) The packets are logged with the string prefix: 
+"TRACE: tablename:chainname:type:rulenum " where type can be "rule" for 
+plain rule, "return" for implicit rule at the end of a user defined chain 
+and "policy" for the policy of the built in chains. 
+.br
+It can only be used in the
+.BR raw
+table.
diff --git a/ap/app/iptables/extensions/libxt_comment.c b/ap/app/iptables/extensions/libxt_comment.c
new file mode 100755
index 0000000..67d7f99
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_comment.c
@@ -0,0 +1,123 @@
+/* Shared library add-on to iptables to add comment match support.
+ *
+ * ChangeLog
+ *     2003-05-13: Brad Fisher <brad@info-link.net>
+ *         Initial comment match
+ *     2004-05-12: Brad Fisher <brad@info-link.net>
+ *         Port to patch-o-matic-ng
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_comment.h>
+
+static void comment_help(void)
+{
+	printf(
+		"comment match options:\n"
+		"--comment COMMENT             Attach a comment to a rule\n");
+}
+
+static const struct option comment_opts[] = {
+	{ "comment", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static void
+parse_comment(const char *s, struct xt_comment_info *info)
+{	
+	int slen = strlen(s);
+
+	if (slen >= XT_MAX_COMMENT_LEN) {
+		xtables_error(PARAMETER_PROBLEM,
+			"COMMENT must be shorter than %i characters", XT_MAX_COMMENT_LEN);
+	}
+	strcpy((char *)info->comment, s);
+}
+
+static int
+comment_parse(int c, char **argv, int invert, unsigned int *flags,
+              const void *entry, struct xt_entry_match **match)
+{
+	struct xt_comment_info *commentinfo = (struct xt_comment_info *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		xtables_check_inverse(argv[optind-1], &invert, &optind, 0);
+		if (invert) {
+			xtables_error(PARAMETER_PROBLEM,
+					"Sorry, you can't have an inverted comment");
+		}
+		parse_comment(argv[optind-1], commentinfo);
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static void comment_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "COMMENT match: You must specify `--comment'");
+}
+
+static void
+comment_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	struct xt_comment_info *commentinfo = (struct xt_comment_info *)match->data;
+
+	commentinfo->comment[XT_MAX_COMMENT_LEN-1] = '\0';
+	printf("/* %s */ ", commentinfo->comment);
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void
+comment_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct xt_comment_info *commentinfo = (struct xt_comment_info *)match->data;
+
+	commentinfo->comment[XT_MAX_COMMENT_LEN-1] = '\0';
+	printf("--comment ");
+	xtables_save_string((const char *)commentinfo->comment);
+}
+
+static struct xtables_match comment_match = {
+	.family		= NFPROTO_IPV4,
+	.name		= "comment",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_comment_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_comment_info)),
+	.help		= comment_help,
+	.parse		= comment_parse,
+	.final_check	= comment_check,
+	.print 		= comment_print,
+	.save 		= comment_save,
+	.extra_opts	= comment_opts,
+};
+
+static struct xtables_match comment_match6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "comment",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_comment_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_comment_info)),
+	.help		= comment_help,
+	.parse		= comment_parse,
+	.final_check	= comment_check,
+	.print 		= comment_print,
+	.save 		= comment_save,
+	.extra_opts	= comment_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&comment_match);
+	xtables_register_match(&comment_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_comment.man b/ap/app/iptables/extensions/libxt_comment.man
new file mode 100755
index 0000000..94f871e
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_comment.man
@@ -0,0 +1,6 @@
+Allows you to add comments (up to 256 characters) to any rule.
+.TP
+\fB\-\-comment\fP \fIcomment\fP
+.TP
+Example:
+iptables \-A INPUT \-s 192.168.0.0/16 \-m comment \-\-comment "A privatized IP block"
diff --git a/ap/app/iptables/extensions/libxt_connbytes.c b/ap/app/iptables/extensions/libxt_connbytes.c
new file mode 100755
index 0000000..9f6af1c
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_connbytes.c
@@ -0,0 +1,214 @@
+/* Shared library add-on to iptables to add byte tracking support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/netfilter/xt_connbytes.h>
+
+static void connbytes_help(void)
+{
+	printf(
+"connbytes match options:\n"
+" [!] --connbytes from:[to]\n"
+"     --connbytes-dir [original, reply, both]\n"
+"     --connbytes-mode [packets, bytes, avgpkt]\n");
+}
+
+static const struct option connbytes_opts[] = {
+	{ "connbytes", 1, NULL, '1' },
+	{ "connbytes-dir", 1, NULL, '2' },
+	{ "connbytes-mode", 1, NULL, '3' },
+	{ .name = NULL }
+};
+
+static void
+parse_range(const char *arg, struct xt_connbytes_info *si)
+{
+	char *colon,*p;
+
+	si->count.from = strtoul(arg,&colon,10);
+	if (*colon != ':') 
+		xtables_error(PARAMETER_PROBLEM, "Bad range \"%s\"", arg);
+	si->count.to = strtoul(colon+1,&p,10);
+	if (p == colon+1) {
+		/* second number omited */
+		si->count.to = 0xffffffff;
+	}
+	if (si->count.from > si->count.to)
+		xtables_error(PARAMETER_PROBLEM, "%llu should be less than %llu",
+			   (unsigned long long)si->count.from,
+			   (unsigned long long)si->count.to);
+}
+
+static int
+connbytes_parse(int c, char **argv, int invert, unsigned int *flags,
+                const void *entry, struct xt_entry_match **match)
+{
+	struct xt_connbytes_info *sinfo = (struct xt_connbytes_info *)(*match)->data;
+	unsigned long i;
+
+	switch (c) {
+	case '1':
+		if (xtables_check_inverse(optarg, &invert, &optind, 0))
+			optind++;
+
+		parse_range(argv[optind-1], sinfo);
+		if (invert) {
+			i = sinfo->count.from;
+			sinfo->count.from = sinfo->count.to;
+			sinfo->count.to = i;
+		}
+		*flags |= 1;
+		break;
+	case '2':
+		if (!strcmp(optarg, "original"))
+			sinfo->direction = XT_CONNBYTES_DIR_ORIGINAL;
+		else if (!strcmp(optarg, "reply"))
+			sinfo->direction = XT_CONNBYTES_DIR_REPLY;
+		else if (!strcmp(optarg, "both"))
+			sinfo->direction = XT_CONNBYTES_DIR_BOTH;
+		else
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unknown --connbytes-dir `%s'", optarg);
+
+		*flags |= 2;
+		break;
+	case '3':
+		if (!strcmp(optarg, "packets"))
+			sinfo->what = XT_CONNBYTES_PKTS;
+		else if (!strcmp(optarg, "bytes"))
+			sinfo->what = XT_CONNBYTES_BYTES;
+		else if (!strcmp(optarg, "avgpkt"))
+			sinfo->what = XT_CONNBYTES_AVGPKT;
+		else
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unknown --connbytes-mode `%s'", optarg);
+		*flags |= 4;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void connbytes_check(unsigned int flags)
+{
+	if (flags != 7)
+		xtables_error(PARAMETER_PROBLEM, "You must specify `--connbytes'"
+			   "`--connbytes-dir' and `--connbytes-mode'");
+}
+
+static void print_mode(struct xt_connbytes_info *sinfo)
+{
+	switch (sinfo->what) {
+		case XT_CONNBYTES_PKTS:
+			fputs("packets ", stdout);
+			break;
+		case XT_CONNBYTES_BYTES:
+			fputs("bytes ", stdout);
+			break;
+		case XT_CONNBYTES_AVGPKT:
+			fputs("avgpkt ", stdout);
+			break;
+		default:
+			fputs("unknown ", stdout);
+			break;
+	}
+}
+
+static void print_direction(struct xt_connbytes_info *sinfo)
+{
+	switch (sinfo->direction) {
+		case XT_CONNBYTES_DIR_ORIGINAL:
+			fputs("original ", stdout);
+			break;
+		case XT_CONNBYTES_DIR_REPLY:
+			fputs("reply ", stdout);
+			break;
+		case XT_CONNBYTES_DIR_BOTH:
+			fputs("both ", stdout);
+			break;
+		default:
+			fputs("unknown ", stdout);
+			break;
+	}
+}
+
+static void
+connbytes_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	struct xt_connbytes_info *sinfo = (struct xt_connbytes_info *)match->data;
+
+	if (sinfo->count.from > sinfo->count.to) 
+		printf("connbytes ! %llu:%llu ",
+			(unsigned long long)sinfo->count.to,
+			(unsigned long long)sinfo->count.from);
+	else
+		printf("connbytes %llu:%llu ",
+			(unsigned long long)sinfo->count.from,
+			(unsigned long long)sinfo->count.to);
+
+	fputs("connbytes mode ", stdout);
+	print_mode(sinfo);
+
+	fputs("connbytes direction ", stdout);
+	print_direction(sinfo);
+}
+
+static void connbytes_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct xt_connbytes_info *sinfo = (struct xt_connbytes_info *)match->data;
+
+	if (sinfo->count.from > sinfo->count.to) 
+		printf("! --connbytes %llu:%llu ",
+			(unsigned long long)sinfo->count.to,
+			(unsigned long long)sinfo->count.from);
+	else
+		printf("--connbytes %llu:%llu ",
+			(unsigned long long)sinfo->count.from,
+			(unsigned long long)sinfo->count.to);
+
+	fputs("--connbytes-mode ", stdout);
+	print_mode(sinfo);
+
+	fputs("--connbytes-dir ", stdout);
+	print_direction(sinfo);
+}
+
+static struct xtables_match connbytes_match = {
+	.family		= NFPROTO_IPV4,
+	.name 		= "connbytes",
+	.version 	= XTABLES_VERSION,
+	.size 		= XT_ALIGN(sizeof(struct xt_connbytes_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_connbytes_info)),
+	.help		= connbytes_help,
+	.parse		= connbytes_parse,
+	.final_check	= connbytes_check,
+	.print		= connbytes_print,
+	.save 		= connbytes_save,
+	.extra_opts	= connbytes_opts,
+};
+
+static struct xtables_match connbytes_match6 = {
+	.family		= NFPROTO_IPV6,
+	.name 		= "connbytes",
+	.version 	= XTABLES_VERSION,
+	.size 		= XT_ALIGN(sizeof(struct xt_connbytes_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_connbytes_info)),
+	.help		= connbytes_help,
+	.parse		= connbytes_parse,
+	.final_check	= connbytes_check,
+	.print		= connbytes_print,
+	.save 		= connbytes_save,
+	.extra_opts	= connbytes_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&connbytes_match);
+	xtables_register_match(&connbytes_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_connbytes.man b/ap/app/iptables/extensions/libxt_connbytes.man
new file mode 100755
index 0000000..e475cae
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_connbytes.man
@@ -0,0 +1,36 @@
+Match by how many bytes or packets a connection (or one of the two
+flows constituting the connection) has transferred so far, or by
+average bytes per packet.
+.PP
+The counters are 64-bit and are thus not expected to overflow ;)
+.PP
+The primary use is to detect long-lived downloads and mark them to be
+scheduled using a lower priority band in traffic control.
+.PP
+The transferred bytes per connection can also be viewed through
+`conntrack -L` and accessed via ctnetlink.
+.PP
+NOTE that for connections which have no accounting information, the match will
+always return false. The "net.netfilter.nf_conntrack_acct" sysctl flag controls
+whether \fBnew\fP connections will be byte/packet counted. Existing connection
+flows will not be gaining/losing a/the accounting structure when be sysctl flag
+is flipped.
+.TP
+[\fB!\fP] \fB\-\-connbytes\fP \fIfrom\fP[\fB:\fP\fIto\fP]
+match packets from a connection whose packets/bytes/average packet
+size is more than FROM and less than TO bytes/packets. if TO is
+omitted only FROM check is done. "!" is used to match packets not
+falling in the range.
+.TP
+\fB\-\-connbytes\-dir\fP {\fBoriginal\fP|\fBreply\fP|\fBboth\fP}
+which packets to consider
+.TP
+\fB\-\-connbytes\-mode\fP {\fBpackets\fP|\fBbytes\fP|\fBavgpkt\fP}
+whether to check the amount of packets, number of bytes transferred or
+the average size (in bytes) of all packets received so far. Note that
+when "both" is used together with "avgpkt", and data is going (mainly)
+only in one direction (for example HTTP), the average packet size will
+be about half of the actual data packets.
+.TP
+Example:
+iptables .. \-m connbytes \-\-connbytes 10000:100000 \-\-connbytes\-dir both \-\-connbytes\-mode bytes ...
diff --git a/ap/app/iptables/extensions/libxt_connlimit.c b/ap/app/iptables/extensions/libxt_connlimit.c
new file mode 100755
index 0000000..f001a2e
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_connlimit.c
@@ -0,0 +1,214 @@
+/* Shared library add-on to iptables to add connection limit support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter/xt_connlimit.h>
+
+static void connlimit_help(void)
+{
+	printf(
+"connlimit match options:\n"
+"[!] --connlimit-above n        match if the number of existing "
+"                               connections is (not) above n\n"
+"    --connlimit-mask n         group hosts using mask\n");
+}
+
+static const struct option connlimit_opts[] = {
+	{"connlimit-above", 1, NULL, 'A'},
+	{"connlimit-mask",  1, NULL, 'M'},
+	{ .name = NULL }
+};
+
+static void connlimit_init(struct xt_entry_match *match)
+{
+	struct xt_connlimit_info *info = (void *)match->data;
+	info->v4_mask = 0xFFFFFFFFUL;
+}
+
+static void prefix_to_netmask(u_int32_t *mask, unsigned int prefix_len)
+{
+	if (prefix_len == 0) {
+		mask[0] = mask[1] = mask[2] = mask[3] = 0;
+	} else if (prefix_len <= 32) {
+		mask[0] <<= 32 - prefix_len;
+		mask[1] = mask[2] = mask[3] = 0;
+	} else if (prefix_len <= 64) {
+		mask[1] <<= 32 - (prefix_len - 32);
+		mask[2] = mask[3] = 0;
+	} else if (prefix_len <= 96) {
+		mask[2] <<= 32 - (prefix_len - 64);
+		mask[3] = 0;
+	} else if (prefix_len <= 128) {
+		mask[3] <<= 32 - (prefix_len - 96);
+	}
+	mask[0] = htonl(mask[0]);
+	mask[1] = htonl(mask[1]);
+	mask[2] = htonl(mask[2]);
+	mask[3] = htonl(mask[3]);
+}
+
+static int connlimit_parse(int c, char **argv, int invert, unsigned int *flags,
+                           struct xt_connlimit_info *info, unsigned int family)
+{
+	char *err;
+	int i;
+
+	switch (c) {
+	case 'A':
+		if (*flags & 0x1)
+			xtables_error(PARAMETER_PROBLEM,
+				"--connlimit-above may be given only once");
+		*flags |= 0x1;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		info->limit   = strtoul(argv[optind-1], NULL, 0);
+		info->inverse = invert;
+		break;
+	case 'M':
+		if (*flags & 0x2)
+			xtables_error(PARAMETER_PROBLEM,
+				"--connlimit-mask may be given only once");
+
+		*flags |= 0x2;
+		i = strtoul(argv[optind-1], &err, 0);
+		if (family == NFPROTO_IPV6) {
+			if (i > 128 || *err != '\0')
+				xtables_error(PARAMETER_PROBLEM,
+					"--connlimit-mask must be between "
+					"0 and 128");
+			prefix_to_netmask(info->v6_mask, i);
+		} else {
+			if (i > 32 || *err != '\0')
+				xtables_error(PARAMETER_PROBLEM,
+					"--connlimit-mask must be between "
+					"0 and 32");
+			if (i == 0)
+				info->v4_mask = 0;
+			else
+				info->v4_mask = htonl(0xFFFFFFFF << (32 - i));
+		}
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static int connlimit_parse4(int c, char **argv, int invert,
+                            unsigned int *flags, const void *entry,
+                            struct xt_entry_match **match)
+{
+	return connlimit_parse(c, argv, invert, flags,
+	       (void *)(*match)->data, NFPROTO_IPV4);
+}
+
+static int connlimit_parse6(int c, char **argv, int invert,
+                            unsigned int *flags, const void *entry,
+                            struct xt_entry_match **match)
+{
+	return connlimit_parse(c, argv, invert, flags,
+	       (void *)(*match)->data, NFPROTO_IPV6);
+}
+
+static void connlimit_check(unsigned int flags)
+{
+	if (!(flags & 0x1))
+		xtables_error(PARAMETER_PROBLEM,
+			"You must specify \"--connlimit-above\"");
+}
+
+static unsigned int count_bits4(u_int32_t mask)
+{
+	unsigned int bits = 0;
+
+	for (mask = ~ntohl(mask); mask != 0; mask >>= 1)
+		++bits;
+
+	return 32 - bits;
+}
+
+static unsigned int count_bits6(const u_int32_t *mask)
+{
+	unsigned int bits = 0, i;
+	u_int32_t tmp[4];
+
+	for (i = 0; i < 4; ++i)
+		for (tmp[i] = ~ntohl(mask[i]); tmp[i] != 0; tmp[i] >>= 1)
+			++bits;
+	return 128 - bits;
+}
+
+static void connlimit_print4(const void *ip,
+                             const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_connlimit_info *info = (const void *)match->data;
+
+	printf("#conn/%u %s %u ", count_bits4(info->v4_mask),
+	       info->inverse ? "<=" : ">", info->limit);
+}
+
+static void connlimit_print6(const void *ip,
+                             const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_connlimit_info *info = (const void *)match->data;
+	printf("#conn/%u %s %u ", count_bits6(info->v6_mask),
+	       info->inverse ? "<=" : ">", info->limit);
+}
+
+static void connlimit_save4(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_connlimit_info *info = (const void *)match->data;
+
+	printf("%s--connlimit-above %u --connlimit-mask %u ",
+	       info->inverse ? "! " : "", info->limit,
+	       count_bits4(info->v4_mask));
+}
+
+static void connlimit_save6(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_connlimit_info *info = (const void *)match->data;
+
+	printf("%s--connlimit-above %u --connlimit-mask %u ",
+	       info->inverse ? "! " : "", info->limit,
+	       count_bits6(info->v6_mask));
+}
+
+static struct xtables_match connlimit_match = {
+	.name          = "connlimit",
+	.family        = NFPROTO_IPV4,
+	.version       = XTABLES_VERSION,
+	.size          = XT_ALIGN(sizeof(struct xt_connlimit_info)),
+	.userspacesize = offsetof(struct xt_connlimit_info, data),
+	.help          = connlimit_help,
+	.init          = connlimit_init,
+	.parse         = connlimit_parse4,
+	.final_check   = connlimit_check,
+	.print         = connlimit_print4,
+	.save          = connlimit_save4,
+	.extra_opts    = connlimit_opts,
+};
+
+static struct xtables_match connlimit_match6 = {
+	.name          = "connlimit",
+	.family        = NFPROTO_IPV6,
+	.version       = XTABLES_VERSION,
+	.size          = XT_ALIGN(sizeof(struct xt_connlimit_info)),
+	.userspacesize = offsetof(struct xt_connlimit_info, data),
+	.help          = connlimit_help,
+	.init          = connlimit_init,
+	.parse         = connlimit_parse6,
+	.final_check   = connlimit_check,
+	.print         = connlimit_print6,
+	.save          = connlimit_save6,
+	.extra_opts    = connlimit_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&connlimit_match);
+	xtables_register_match(&connlimit_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_connlimit.man b/ap/app/iptables/extensions/libxt_connlimit.man
new file mode 100755
index 0000000..eb0832a
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_connlimit.man
@@ -0,0 +1,27 @@
+Allows you to restrict the number of parallel connections to a server per
+client IP address (or client address block).
+.TP
+[\fB!\fP] \fB\-\-connlimit\-above\fP \fIn\fP
+Match if the number of existing connections is (not) above \fIn\fR.
+.TP
+\fB\-\-connlimit\-mask\fP \fIprefix_length\fP
+Group hosts using the prefix length. For IPv4, this must be a number between
+(including) 0 and 32. For IPv6, between 0 and 128.
+.P
+Examples:
+.TP
+# allow 2 telnet connections per client host
+iptables \-A INPUT \-p tcp \-\-syn \-\-dport 23 \-m connlimit \-\-connlimit\-above 2 \-j REJECT
+.TP
+# you can also match the other way around:
+iptables \-A INPUT \-p tcp \-\-syn \-\-dport 23 \-m connlimit ! \-\-connlimit\-above 2 \-j ACCEPT
+.TP
+# limit the number of parallel HTTP requests to 16 per class C sized \
+network (24 bit netmask)
+iptables \-p tcp \-\-syn \-\-dport 80 \-m connlimit \-\-connlimit\-above 16
+\-\-connlimit\-mask 24 \-j REJECT
+.TP
+# limit the number of parallel HTTP requests to 16 for the link local network \
+(ipv6)
+ip6tables \-p tcp \-\-syn \-\-dport 80 \-s fe80::/64 \-m connlimit \-\-connlimit\-above
+16 \-\-connlimit\-mask 64 \-j REJECT
diff --git a/ap/app/iptables/extensions/libxt_connmark.c b/ap/app/iptables/extensions/libxt_connmark.c
new file mode 100755
index 0000000..2dca5a5
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_connmark.c
@@ -0,0 +1,232 @@
+/* Shared library add-on to iptables to add connmark matching support.
+ *
+ * (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.com>
+ *
+ * Version 1.1
+ *
+ * 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
+ */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_connmark.h>
+
+enum {
+	F_MARK = 1 << 0,
+};
+
+static void connmark_mt_help(void)
+{
+	printf(
+"connmark match options:\n"
+"[!] --mark value[/mask]    Match ctmark value with optional mask\n");
+}
+
+static const struct option connmark_mt_opts[] = {
+	{.name = "mark", .has_arg = true, .val = '1'},
+	{ .name = NULL }
+};
+
+static int
+connmark_mt_parse(int c, char **argv, int invert, unsigned int *flags,
+                  const void *entry, struct xt_entry_match **match)
+{
+	struct xt_connmark_mtinfo1 *info = (void *)(*match)->data;
+	unsigned int mark, mask = UINT32_MAX;
+	char *end;
+
+	switch (c) {
+	case '1': /* --mark */
+		xtables_param_act(XTF_ONLY_ONCE, "connmark", "--mark", *flags & F_MARK);
+		if (!xtables_strtoui(optarg, &end, &mark, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "connmark", "--mark", optarg);
+		if (*end == '/')
+			if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX))
+				xtables_param_act(XTF_BAD_VALUE, "connmark", "--mark", optarg);
+		if (*end != '\0')
+			xtables_param_act(XTF_BAD_VALUE, "connmark", "--mark", optarg);
+
+		if (invert)
+			info->invert = true;
+		info->mark = mark;
+		info->mask = mask;
+		*flags    |= F_MARK;
+		return true;
+	}
+	return false;
+}
+
+static int
+connmark_parse(int c, char **argv, int invert, unsigned int *flags,
+               const void *entry, struct xt_entry_match **match)
+{
+	struct xt_connmark_info *markinfo = (struct xt_connmark_info *)(*match)->data;
+
+	switch (c) {
+		char *end;
+	case '1':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+
+		markinfo->mark = strtoul(optarg, &end, 0);
+		markinfo->mask = 0xffffffffUL;
+		
+		if (*end == '/')
+			markinfo->mask = strtoul(end+1, &end, 0);
+
+		if (*end != '\0' || end == optarg)
+			xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg);
+		if (invert)
+			markinfo->invert = 1;
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static void print_mark(unsigned int mark, unsigned int mask)
+{
+	if (mask != 0xffffffffU)
+		printf("0x%x/0x%x ", mark, mask);
+	else
+		printf("0x%x ", mark);
+}
+
+static void connmark_mt_check(unsigned int flags)
+{
+	if (flags == 0)
+		xtables_error(PARAMETER_PROBLEM,
+		           "connmark: The --mark option is required");
+}
+
+static void
+connmark_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	struct xt_connmark_info *info = (struct xt_connmark_info *)match->data;
+
+	printf("CONNMARK match ");
+	if (info->invert)
+		printf("!");
+	print_mark(info->mark, info->mask);
+}
+
+static void
+connmark_mt_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_connmark_mtinfo1 *info = (const void *)match->data;
+
+	printf("connmark match ");
+	if (info->invert)
+		printf("!");
+	print_mark(info->mark, info->mask);
+}
+
+static void connmark_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct xt_connmark_info *info = (struct xt_connmark_info *)match->data;
+
+	if (info->invert)
+		printf("! ");
+
+	printf("--mark ");
+	print_mark(info->mark, info->mask);
+}
+
+static void
+connmark_mt_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_connmark_mtinfo1 *info = (const void *)match->data;
+
+	if (info->invert)
+		printf("! ");
+
+	printf("--mark ");
+	print_mark(info->mark, info->mask);
+}
+
+static struct xtables_match connmark_mt_reg_v0 = {
+	.family		= NFPROTO_IPV4,
+	.name		= "connmark",
+	.revision	= 0,
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_connmark_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_connmark_info)),
+	.help		= connmark_mt_help,
+	.parse		= connmark_parse,
+	.final_check	= connmark_mt_check,
+	.print		= connmark_print,
+	.save		= connmark_save,
+	.extra_opts	= connmark_mt_opts,
+};
+
+static struct xtables_match connmark_mt6_reg_v0 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "connmark",
+	.revision	= 0,
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_connmark_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_connmark_info)),
+	.help		= connmark_mt_help,
+	.parse		= connmark_parse,
+	.final_check	= connmark_mt_check,
+	.print		= connmark_print,
+	.save		= connmark_save,
+	.extra_opts	= connmark_mt_opts,
+};
+
+static struct xtables_match connmark_mt_reg = {
+	.version        = XTABLES_VERSION,
+	.name           = "connmark",
+	.revision       = 1,
+	.family         = NFPROTO_IPV4,
+	.size           = XT_ALIGN(sizeof(struct xt_connmark_mtinfo1)),
+	.userspacesize  = XT_ALIGN(sizeof(struct xt_connmark_mtinfo1)),
+	.help           = connmark_mt_help,
+	.parse          = connmark_mt_parse,
+	.final_check    = connmark_mt_check,
+	.print          = connmark_mt_print,
+	.save           = connmark_mt_save,
+	.extra_opts     = connmark_mt_opts,
+};
+
+static struct xtables_match connmark_mt6_reg = {
+	.version        = XTABLES_VERSION,
+	.name           = "connmark",
+	.revision       = 1,
+	.family         = NFPROTO_IPV6,
+	.size           = XT_ALIGN(sizeof(struct xt_connmark_mtinfo1)),
+	.userspacesize  = XT_ALIGN(sizeof(struct xt_connmark_mtinfo1)),
+	.help           = connmark_mt_help,
+	.parse          = connmark_mt_parse,
+	.final_check    = connmark_mt_check,
+	.print          = connmark_mt_print,
+	.save           = connmark_mt_save,
+	.extra_opts     = connmark_mt_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&connmark_mt_reg_v0);
+	xtables_register_match(&connmark_mt6_reg_v0);
+	xtables_register_match(&connmark_mt_reg);
+	xtables_register_match(&connmark_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_connmark.man b/ap/app/iptables/extensions/libxt_connmark.man
new file mode 100755
index 0000000..ee87d9e
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_connmark.man
@@ -0,0 +1,6 @@
+This module matches the netfilter mark field associated with a connection
+(which can be set using the \fBCONNMARK\fR target below).
+.TP
+[\fB!\fP] \fB\-\-mark\fP \fIvalue\fP[\fB/\fP\fImask\fP]
+Matches packets in connections with the given mark value (if a mask is
+specified, this is logically ANDed with the mark before the comparison).
diff --git a/ap/app/iptables/extensions/libxt_conntrack.c b/ap/app/iptables/extensions/libxt_conntrack.c
new file mode 100755
index 0000000..d1164c5
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_conntrack.c
@@ -0,0 +1,1207 @@
+/*
+ *	libxt_conntrack
+ *	Shared library add-on to iptables for conntrack matching support.
+ *
+ *	GPL (C) 2001  Marc Boucher (marc@mbsi.ca).
+ *	Copyright © CC Computer Consultants GmbH, 2007 - 2008
+ *	Jan Engelhardt <jengelh@computergmbh.de>
+ */
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <xtables.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/xt_conntrack.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <arpa/inet.h>
+
+static void conntrack_mt_help(void)
+{
+	printf(
+"conntrack match options:\n"
+"[!] --ctstate {INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED|SNAT|DNAT}[,...]\n"
+"                               State(s) to match\n"
+"[!] --ctproto proto            Protocol to match; by number or name, e.g. \"tcp\"\n"
+"[!] --ctorigsrc address[/mask]\n"
+"[!] --ctorigdst address[/mask]\n"
+"[!] --ctreplsrc address[/mask]\n"
+"[!] --ctrepldst address[/mask]\n"
+"                               Original/Reply source/destination address\n"
+"[!] --ctorigsrcport port\n"
+"[!] --ctorigdstport port\n"
+"[!] --ctreplsrcport port\n"
+"[!] --ctrepldstport port\n"
+"                               TCP/UDP/SCTP orig./reply source/destination port\n"
+"[!] --ctstatus {NONE|EXPECTED|SEEN_REPLY|ASSURED|CONFIRMED}[,...]\n"
+"                               Status(es) to match\n"
+"[!] --ctexpire time[:time]     Match remaining lifetime in seconds against\n"
+"                               value or range of values (inclusive)\n"
+"    --ctdir {ORIGINAL|REPLY}   Flow direction of packet\n");
+}
+
+static const struct option conntrack_mt_opts_v0[] = {
+	{.name = "ctstate",   .has_arg = true, .val = '1'},
+	{.name = "ctproto",   .has_arg = true, .val = '2'},
+	{.name = "ctorigsrc", .has_arg = true, .val = '3'},
+	{.name = "ctorigdst", .has_arg = true, .val = '4'},
+	{.name = "ctreplsrc", .has_arg = true, .val = '5'},
+	{.name = "ctrepldst", .has_arg = true, .val = '6'},
+	{.name = "ctstatus",  .has_arg = true, .val = '7'},
+	{.name = "ctexpire",  .has_arg = true, .val = '8'},
+	{ .name = NULL }
+};
+
+static const struct option conntrack_mt_opts[] = {
+	{.name = "ctstate",       .has_arg = true, .val = '1'},
+	{.name = "ctproto",       .has_arg = true, .val = '2'},
+	{.name = "ctorigsrc",     .has_arg = true, .val = '3'},
+	{.name = "ctorigdst",     .has_arg = true, .val = '4'},
+	{.name = "ctreplsrc",     .has_arg = true, .val = '5'},
+	{.name = "ctrepldst",     .has_arg = true, .val = '6'},
+	{.name = "ctstatus",      .has_arg = true, .val = '7'},
+	{.name = "ctexpire",      .has_arg = true, .val = '8'},
+	{.name = "ctorigsrcport", .has_arg = true, .val = 'a'},
+	{.name = "ctorigdstport", .has_arg = true, .val = 'b'},
+	{.name = "ctreplsrcport", .has_arg = true, .val = 'c'},
+	{.name = "ctrepldstport", .has_arg = true, .val = 'd'},
+	{.name = "ctdir",         .has_arg = true, .val = 'e'},
+	{.name = NULL},
+};
+
+static int
+parse_state(const char *state, size_t len, struct xt_conntrack_info *sinfo)
+{
+	if (strncasecmp(state, "INVALID", len) == 0)
+		sinfo->statemask |= XT_CONNTRACK_STATE_INVALID;
+	else if (strncasecmp(state, "NEW", len) == 0)
+		sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
+	else if (strncasecmp(state, "ESTABLISHED", len) == 0)
+		sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
+	else if (strncasecmp(state, "RELATED", len) == 0)
+		sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
+	else if (strncasecmp(state, "UNTRACKED", len) == 0)
+		sinfo->statemask |= XT_CONNTRACK_STATE_UNTRACKED;
+	else if (strncasecmp(state, "SNAT", len) == 0)
+		sinfo->statemask |= XT_CONNTRACK_STATE_SNAT;
+	else if (strncasecmp(state, "DNAT", len) == 0)
+		sinfo->statemask |= XT_CONNTRACK_STATE_DNAT;
+	else
+		return 0;
+	return 1;
+}
+
+static void
+parse_states(const char *arg, struct xt_conntrack_info *sinfo)
+{
+	const char *comma;
+
+	while ((comma = strchr(arg, ',')) != NULL) {
+		if (comma == arg || !parse_state(arg, comma-arg, sinfo))
+			xtables_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg);
+		arg = comma+1;
+	}
+	if (!*arg)
+		xtables_error(PARAMETER_PROBLEM, "\"--ctstate\" requires a list of "
+					      "states with no spaces, e.g. "
+					      "ESTABLISHED,RELATED");
+	if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo))
+		xtables_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg);
+}
+
+static bool
+conntrack_ps_state(struct xt_conntrack_mtinfo2 *info, const char *state,
+                   size_t z)
+{
+	if (strncasecmp(state, "INVALID", z) == 0)
+		info->state_mask |= XT_CONNTRACK_STATE_INVALID;
+	else if (strncasecmp(state, "NEW", z) == 0)
+		info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
+	else if (strncasecmp(state, "ESTABLISHED", z) == 0)
+		info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
+	else if (strncasecmp(state, "RELATED", z) == 0)
+		info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
+	else if (strncasecmp(state, "UNTRACKED", z) == 0)
+		info->state_mask |= XT_CONNTRACK_STATE_UNTRACKED;
+	else if (strncasecmp(state, "SNAT", z) == 0)
+		info->state_mask |= XT_CONNTRACK_STATE_SNAT;
+	else if (strncasecmp(state, "DNAT", z) == 0)
+		info->state_mask |= XT_CONNTRACK_STATE_DNAT;
+	else
+		return false;
+	return true;
+}
+
+static void
+conntrack_ps_states(struct xt_conntrack_mtinfo2 *info, const char *arg)
+{
+	const char *comma;
+
+	while ((comma = strchr(arg, ',')) != NULL) {
+		if (comma == arg || !conntrack_ps_state(info, arg, comma - arg))
+			xtables_error(PARAMETER_PROBLEM,
+			           "Bad ctstate \"%s\"", arg);
+		arg = comma + 1;
+	}
+
+	if (strlen(arg) == 0 || !conntrack_ps_state(info, arg, strlen(arg)))
+		xtables_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg);
+}
+
+static int
+parse_status(const char *status, size_t len, struct xt_conntrack_info *sinfo)
+{
+	if (strncasecmp(status, "NONE", len) == 0)
+		sinfo->statusmask |= 0;
+	else if (strncasecmp(status, "EXPECTED", len) == 0)
+		sinfo->statusmask |= IPS_EXPECTED;
+	else if (strncasecmp(status, "SEEN_REPLY", len) == 0)
+		sinfo->statusmask |= IPS_SEEN_REPLY;
+	else if (strncasecmp(status, "ASSURED", len) == 0)
+		sinfo->statusmask |= IPS_ASSURED;
+#ifdef IPS_CONFIRMED
+	else if (strncasecmp(status, "CONFIRMED", len) == 0)
+		sinfo->statusmask |= IPS_CONFIRMED;
+#endif
+	else
+		return 0;
+	return 1;
+}
+
+static void
+parse_statuses(const char *arg, struct xt_conntrack_info *sinfo)
+{
+	const char *comma;
+
+	while ((comma = strchr(arg, ',')) != NULL) {
+		if (comma == arg || !parse_status(arg, comma-arg, sinfo))
+			xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
+		arg = comma+1;
+	}
+
+	if (strlen(arg) == 0 || !parse_status(arg, strlen(arg), sinfo))
+		xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
+}
+
+static bool
+conntrack_ps_status(struct xt_conntrack_mtinfo2 *info, const char *status,
+                    size_t z)
+{
+	if (strncasecmp(status, "NONE", z) == 0)
+		info->status_mask |= 0;
+	else if (strncasecmp(status, "EXPECTED", z) == 0)
+		info->status_mask |= IPS_EXPECTED;
+	else if (strncasecmp(status, "SEEN_REPLY", z) == 0)
+		info->status_mask |= IPS_SEEN_REPLY;
+	else if (strncasecmp(status, "ASSURED", z) == 0)
+		info->status_mask |= IPS_ASSURED;
+	else if (strncasecmp(status, "CONFIRMED", z) == 0)
+		info->status_mask |= IPS_CONFIRMED;
+	else
+		return false;
+	return true;
+}
+
+static void
+conntrack_ps_statuses(struct xt_conntrack_mtinfo2 *info, const char *arg)
+{
+	const char *comma;
+
+	while ((comma = strchr(arg, ',')) != NULL) {
+		if (comma == arg || !conntrack_ps_status(info, arg, comma - arg))
+			xtables_error(PARAMETER_PROBLEM,
+			           "Bad ctstatus \"%s\"", arg);
+		arg = comma + 1;
+	}
+
+	if (strlen(arg) == 0 || !conntrack_ps_status(info, arg, strlen(arg)))
+		xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
+}
+
+static unsigned long
+parse_expire(const char *s)
+{
+	unsigned int len;
+
+	if (!xtables_strtoui(s, NULL, &len, 0, UINT32_MAX))
+		xtables_error(PARAMETER_PROBLEM, "expire value invalid: \"%s\"\n", s);
+	else
+		return len;
+}
+
+/* If a single value is provided, min and max are both set to the value */
+static void
+parse_expires(const char *s, struct xt_conntrack_info *sinfo)
+{
+	char *buffer;
+	char *cp;
+
+	buffer = strdup(s);
+	if ((cp = strchr(buffer, ':')) == NULL)
+		sinfo->expires_min = sinfo->expires_max =
+			parse_expire(buffer);
+	else {
+		*cp = '\0';
+		cp++;
+
+		sinfo->expires_min = buffer[0] ? parse_expire(buffer) : 0;
+		sinfo->expires_max = cp[0]
+			? parse_expire(cp)
+			: (unsigned long)-1;
+	}
+	free(buffer);
+
+	if (sinfo->expires_min > sinfo->expires_max)
+		xtables_error(PARAMETER_PROBLEM,
+		           "expire min. range value `%lu' greater than max. "
+		           "range value `%lu'", sinfo->expires_min, sinfo->expires_max);
+}
+
+static void
+conntrack_ps_expires(struct xt_conntrack_mtinfo2 *info, const char *s)
+{
+	unsigned int min, max;
+	char *end;
+
+	if (!xtables_strtoui(s, &end, &min, 0, UINT32_MAX))
+		xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s);
+	max = min;
+	if (*end == ':')
+		if (!xtables_strtoui(s, &end, &max, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s);
+	if (*end != '\0')
+		xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s);
+
+	if (min > max)
+		xtables_error(PARAMETER_PROBLEM,
+		           "expire min. range value \"%u\" greater than max. "
+		           "range value \"%u\"", min, max);
+
+	info->expires_min = min;
+	info->expires_max = max;
+}
+
+static int conntrack_parse(int c, char **argv, int invert, unsigned int *flags,
+                           const void *entry, struct xt_entry_match **match)
+{
+	struct xt_conntrack_info *sinfo = (void *)(*match)->data;
+	char *protocol = NULL;
+	unsigned int naddrs = 0;
+	struct in_addr *addrs = NULL;
+
+
+	switch (c) {
+	case '1':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+
+		parse_states(argv[optind-1], sinfo);
+		if (invert) {
+			sinfo->invflags |= XT_CONNTRACK_STATE;
+		}
+		sinfo->flags |= XT_CONNTRACK_STATE;
+		break;
+
+	case '2':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+
+		if(invert)
+			sinfo->invflags |= XT_CONNTRACK_PROTO;
+
+		/* Canonicalize into lower case */
+		for (protocol = argv[optind-1]; *protocol; protocol++)
+			*protocol = tolower(*protocol);
+
+		protocol = argv[optind-1];
+		sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum =
+			xtables_parse_protocol(protocol);
+
+		if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0
+		    && (sinfo->invflags & XT_INV_PROTO))
+			xtables_error(PARAMETER_PROBLEM,
+				   "rule would never match protocol");
+
+		sinfo->flags |= XT_CONNTRACK_PROTO;
+		break;
+
+	case '3':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+
+		if (invert)
+			sinfo->invflags |= XT_CONNTRACK_ORIGSRC;
+
+		xtables_ipparse_any(argv[optind-1], &addrs,
+					&sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
+					&naddrs);
+		if(naddrs > 1)
+			xtables_error(PARAMETER_PROBLEM,
+				"multiple IP addresses not allowed");
+
+		if(naddrs == 1) {
+			sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = addrs[0].s_addr;
+		}
+
+		sinfo->flags |= XT_CONNTRACK_ORIGSRC;
+		break;
+
+	case '4':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+
+		if (invert)
+			sinfo->invflags |= XT_CONNTRACK_ORIGDST;
+
+		xtables_ipparse_any(argv[optind-1], &addrs,
+					&sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
+					&naddrs);
+		if(naddrs > 1)
+			xtables_error(PARAMETER_PROBLEM,
+				"multiple IP addresses not allowed");
+
+		if(naddrs == 1) {
+			sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = addrs[0].s_addr;
+		}
+
+		sinfo->flags |= XT_CONNTRACK_ORIGDST;
+		break;
+
+	case '5':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+
+		if (invert)
+			sinfo->invflags |= XT_CONNTRACK_REPLSRC;
+
+		xtables_ipparse_any(argv[optind-1], &addrs,
+					&sinfo->sipmsk[IP_CT_DIR_REPLY],
+					&naddrs);
+		if(naddrs > 1)
+			xtables_error(PARAMETER_PROBLEM,
+				"multiple IP addresses not allowed");
+
+		if(naddrs == 1) {
+			sinfo->tuple[IP_CT_DIR_REPLY].src.ip = addrs[0].s_addr;
+		}
+
+		sinfo->flags |= XT_CONNTRACK_REPLSRC;
+		break;
+
+	case '6':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+
+		if (invert)
+			sinfo->invflags |= XT_CONNTRACK_REPLDST;
+
+		xtables_ipparse_any(argv[optind-1], &addrs,
+					&sinfo->dipmsk[IP_CT_DIR_REPLY],
+					&naddrs);
+		if(naddrs > 1)
+			xtables_error(PARAMETER_PROBLEM,
+				"multiple IP addresses not allowed");
+
+		if(naddrs == 1) {
+			sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = addrs[0].s_addr;
+		}
+
+		sinfo->flags |= XT_CONNTRACK_REPLDST;
+		break;
+
+	case '7':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+
+		parse_statuses(argv[optind-1], sinfo);
+		if (invert) {
+			sinfo->invflags |= XT_CONNTRACK_STATUS;
+		}
+		sinfo->flags |= XT_CONNTRACK_STATUS;
+		break;
+
+	case '8':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+
+		parse_expires(argv[optind-1], sinfo);
+		if (invert) {
+			sinfo->invflags |= XT_CONNTRACK_EXPIRES;
+		}
+		sinfo->flags |= XT_CONNTRACK_EXPIRES;
+		break;
+
+	default:
+		return 0;
+	}
+
+	*flags = sinfo->flags;
+	return 1;
+}
+
+static int
+conntrack_mt_parse(int c, bool invert, unsigned int *flags,
+                   struct xt_conntrack_mtinfo2 *info)
+{
+	unsigned int port;
+	char *p;
+
+	switch (c) {
+	case '1': /* --ctstate */
+		conntrack_ps_states(info, optarg);
+		info->match_flags |= XT_CONNTRACK_STATE;
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_STATE;
+		break;
+
+	case '2': /* --ctproto */
+		/* Canonicalize into lower case */
+		for (p = optarg; *p != '\0'; ++p)
+			*p = tolower(*p);
+		info->l4proto = xtables_parse_protocol(optarg);
+
+		if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO))
+			xtables_error(PARAMETER_PROBLEM, "conntrack: rule would "
+			           "never match protocol");
+
+		info->match_flags |= XT_CONNTRACK_PROTO;
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_PROTO;
+		break;
+
+	case '7': /* --ctstatus */
+		conntrack_ps_statuses(info, optarg);
+		info->match_flags |= XT_CONNTRACK_STATUS;
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_STATUS;
+		break;
+
+	case '8': /* --ctexpire */
+		conntrack_ps_expires(info, optarg);
+		info->match_flags |= XT_CONNTRACK_EXPIRES;
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_EXPIRES;
+		break;
+
+	case 'a': /* --ctorigsrcport */
+		if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "conntrack",
+			          "--ctorigsrcport", optarg);
+		info->match_flags |= XT_CONNTRACK_ORIGSRC_PORT;
+		info->origsrc_port = htons(port);
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_ORIGSRC_PORT;
+		break;
+
+	case 'b': /* --ctorigdstport */
+		if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "conntrack",
+			          "--ctorigdstport", optarg);
+		info->match_flags |= XT_CONNTRACK_ORIGDST_PORT;
+		info->origdst_port = htons(port);
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_ORIGDST_PORT;
+		break;
+
+	case 'c': /* --ctreplsrcport */
+		if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "conntrack",
+			          "--ctreplsrcport", optarg);
+		info->match_flags |= XT_CONNTRACK_REPLSRC_PORT;
+		info->replsrc_port = htons(port);
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_REPLSRC_PORT;
+		break;
+
+	case 'd': /* --ctrepldstport */
+		if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "conntrack",
+			          "--ctrepldstport", optarg);
+		info->match_flags |= XT_CONNTRACK_REPLDST_PORT;
+		info->repldst_port = htons(port);
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_REPLDST_PORT;
+		break;
+
+	case 'e': /* --ctdir */
+		xtables_param_act(XTF_NO_INVERT, "conntrack", "--ctdir", invert);
+		if (strcasecmp(optarg, "ORIGINAL") == 0) {
+			info->match_flags  |= XT_CONNTRACK_DIRECTION;
+			info->invert_flags &= ~XT_CONNTRACK_DIRECTION;
+		} else if (strcasecmp(optarg, "REPLY") == 0) {
+			info->match_flags  |= XT_CONNTRACK_DIRECTION;
+			info->invert_flags |= XT_CONNTRACK_DIRECTION;
+		} else {
+			xtables_param_act(XTF_BAD_VALUE, "conntrack", "--ctdir", optarg);
+		}
+		break;
+
+	default:
+		return false;
+	}
+
+	*flags = info->match_flags;
+	return true;
+}
+
+static int
+conntrack_mt4_parse(int c, bool invert, unsigned int *flags,
+                    struct xt_conntrack_mtinfo2 *info)
+{
+	struct in_addr *addr = NULL;
+	unsigned int naddrs = 0;
+
+	switch (c) {
+	case '3': /* --ctorigsrc */
+		xtables_ipparse_any(optarg, &addr, &info->origsrc_mask.in,
+		                        &naddrs);
+		if (naddrs > 1)
+			xtables_error(PARAMETER_PROBLEM,
+			           "multiple IP addresses not allowed");
+		if (naddrs == 1)
+			memcpy(&info->origsrc_addr.in, addr, sizeof(*addr));
+		info->match_flags |= XT_CONNTRACK_ORIGSRC;
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_ORIGSRC;
+		break;
+
+	case '4': /* --ctorigdst */
+		xtables_ipparse_any(optarg, &addr, &info->origdst_mask.in,
+		                        &naddrs);
+		if (naddrs > 1)
+			xtables_error(PARAMETER_PROBLEM,
+			           "multiple IP addresses not allowed");
+		if (naddrs == 1)
+			memcpy(&info->origdst_addr.in, addr, sizeof(*addr));
+		info->match_flags |= XT_CONNTRACK_ORIGDST;
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_ORIGDST;
+		break;
+
+	case '5': /* --ctreplsrc */
+		xtables_ipparse_any(optarg, &addr, &info->replsrc_mask.in,
+		                        &naddrs);
+		if (naddrs > 1)
+			xtables_error(PARAMETER_PROBLEM,
+			           "multiple IP addresses not allowed");
+		if (naddrs == 1)
+			memcpy(&info->replsrc_addr.in, addr, sizeof(*addr));
+		info->match_flags |= XT_CONNTRACK_REPLSRC;
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_REPLSRC;
+		break;
+
+	case '6': /* --ctrepldst */
+		xtables_ipparse_any(optarg, &addr, &info->repldst_mask.in,
+		                        &naddrs);
+		if (naddrs > 1)
+			xtables_error(PARAMETER_PROBLEM,
+			           "multiple IP addresses not allowed");
+		if (naddrs == 1)
+			memcpy(&info->repldst_addr.in, addr, sizeof(*addr));
+		info->match_flags |= XT_CONNTRACK_REPLDST;
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_REPLDST;
+		break;
+
+
+	default:
+		return conntrack_mt_parse(c, invert, flags, info);
+	}
+
+	*flags = info->match_flags;
+	return true;
+}
+
+static int
+conntrack_mt6_parse(int c, bool invert, unsigned int *flags,
+                    struct xt_conntrack_mtinfo2 *info)
+{
+	struct in6_addr *addr = NULL;
+	unsigned int naddrs = 0;
+
+	switch (c) {
+	case '3': /* --ctorigsrc */
+		xtables_ip6parse_any(optarg, &addr,
+		                         &info->origsrc_mask.in6, &naddrs);
+		if (naddrs > 1)
+			xtables_error(PARAMETER_PROBLEM,
+			           "multiple IP addresses not allowed");
+		if (naddrs == 1)
+			memcpy(&info->origsrc_addr.in6, addr, sizeof(*addr));
+		info->match_flags |= XT_CONNTRACK_ORIGSRC;
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_ORIGSRC;
+		break;
+
+	case '4': /* --ctorigdst */
+		xtables_ip6parse_any(optarg, &addr,
+		                         &info->origdst_mask.in6, &naddrs);
+		if (naddrs > 1)
+			xtables_error(PARAMETER_PROBLEM,
+			           "multiple IP addresses not allowed");
+		if (naddrs == 1)
+			memcpy(&info->origdst_addr.in, addr, sizeof(*addr));
+		info->match_flags |= XT_CONNTRACK_ORIGDST;
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_ORIGDST;
+		break;
+
+	case '5': /* --ctreplsrc */
+		xtables_ip6parse_any(optarg, &addr,
+		                         &info->replsrc_mask.in6, &naddrs);
+		if (naddrs > 1)
+			xtables_error(PARAMETER_PROBLEM,
+			           "multiple IP addresses not allowed");
+		if (naddrs == 1)
+			memcpy(&info->replsrc_addr.in, addr, sizeof(*addr));
+		info->match_flags |= XT_CONNTRACK_REPLSRC;
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_REPLSRC;
+		break;
+
+	case '6': /* --ctrepldst */
+		xtables_ip6parse_any(optarg, &addr,
+		                         &info->repldst_mask.in6, &naddrs);
+		if (naddrs > 1)
+			xtables_error(PARAMETER_PROBLEM,
+			           "multiple IP addresses not allowed");
+		if (naddrs == 1)
+			memcpy(&info->repldst_addr.in, addr, sizeof(*addr));
+		info->match_flags |= XT_CONNTRACK_REPLDST;
+		if (invert)
+			info->invert_flags |= XT_CONNTRACK_REPLDST;
+		break;
+
+
+	default:
+		return conntrack_mt_parse(c, invert, flags, info);
+	}
+
+	*flags = info->match_flags;
+	return true;
+}
+
+#define cinfo_transform(r, l) \
+	do { \
+		memcpy((r), (l), offsetof(typeof(*(l)), state_mask)); \
+		(r)->state_mask  = (l)->state_mask; \
+		(r)->status_mask = (l)->status_mask; \
+	} while (false);
+
+static int
+conntrack1_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_match **match)
+{
+	struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
+	struct xt_conntrack_mtinfo2 up;
+
+	cinfo_transform(&up, info);
+	if (!conntrack_mt4_parse(c, invert, flags, &up))
+		return false;
+	cinfo_transform(info, &up);
+	return true;
+}
+
+static int
+conntrack1_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_match **match)
+{
+	struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
+	struct xt_conntrack_mtinfo2 up;
+
+	cinfo_transform(&up, info);
+	if (!conntrack_mt6_parse(c, invert, flags, &up))
+		return false;
+	cinfo_transform(info, &up);
+	return true;
+}
+
+static int
+conntrack2_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_match **match)
+{
+	return conntrack_mt4_parse(c, invert, flags, (void *)(*match)->data);
+}
+
+static int
+conntrack2_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
+                     const void *entry, struct xt_entry_match **match)
+{
+	return conntrack_mt6_parse(c, invert, flags, (void *)(*match)->data);
+}
+
+static void conntrack_mt_check(unsigned int flags)
+{
+	if (flags == 0)
+		xtables_error(PARAMETER_PROBLEM, "conntrack: At least one option "
+		           "is required");
+}
+
+static void
+print_state(unsigned int statemask)
+{
+	const char *sep = "";
+
+	if (statemask & XT_CONNTRACK_STATE_INVALID) {
+		printf("%sINVALID", sep);
+		sep = ",";
+	}
+	if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) {
+		printf("%sNEW", sep);
+		sep = ",";
+	}
+	if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) {
+		printf("%sRELATED", sep);
+		sep = ",";
+	}
+	if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) {
+		printf("%sESTABLISHED", sep);
+		sep = ",";
+	}
+	if (statemask & XT_CONNTRACK_STATE_UNTRACKED) {
+		printf("%sUNTRACKED", sep);
+		sep = ",";
+	}
+	if (statemask & XT_CONNTRACK_STATE_SNAT) {
+		printf("%sSNAT", sep);
+		sep = ",";
+	}
+	if (statemask & XT_CONNTRACK_STATE_DNAT) {
+		printf("%sDNAT", sep);
+		sep = ",";
+	}
+	printf(" ");
+}
+
+static void
+print_status(unsigned int statusmask)
+{
+	const char *sep = "";
+
+	if (statusmask & IPS_EXPECTED) {
+		printf("%sEXPECTED", sep);
+		sep = ",";
+	}
+	if (statusmask & IPS_SEEN_REPLY) {
+		printf("%sSEEN_REPLY", sep);
+		sep = ",";
+	}
+	if (statusmask & IPS_ASSURED) {
+		printf("%sASSURED", sep);
+		sep = ",";
+	}
+	if (statusmask & IPS_CONFIRMED) {
+		printf("%sCONFIRMED", sep);
+		sep = ",";
+	}
+	if (statusmask == 0)
+		printf("%sNONE", sep);
+	printf(" ");
+}
+
+static void
+conntrack_dump_addr(const union nf_inet_addr *addr,
+                    const union nf_inet_addr *mask,
+                    unsigned int family, bool numeric)
+{
+	if (family == NFPROTO_IPV4) {
+		if (!numeric && addr->ip == 0) {
+			printf("anywhere ");
+			return;
+		}
+		if (numeric)
+			printf("%s ", xtables_ipaddr_to_numeric(&addr->in));
+		else
+			printf("%s ", xtables_ipaddr_to_anyname(&addr->in));
+	} else if (family == NFPROTO_IPV6) {
+		if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 &&
+		    addr->ip6[2] == 0 && addr->ip6[3] == 0) {
+			printf("anywhere ");
+			return;
+		}
+		if (numeric)
+			printf("%s ", xtables_ip6addr_to_numeric(&addr->in6));
+		else
+			printf("%s ", xtables_ip6addr_to_anyname(&addr->in6));
+	}
+}
+
+static void
+print_addr(struct in_addr *addr, struct in_addr *mask, int inv, int numeric)
+{
+	char buf[BUFSIZ];
+
+	if (inv)
+	       	printf("! ");
+
+	if (mask->s_addr == 0L && !numeric)
+		printf("%s ", "anywhere");
+	else {
+		if (numeric)
+			strcpy(buf, xtables_ipaddr_to_numeric(addr));
+		else
+			strcpy(buf, xtables_ipaddr_to_anyname(addr));
+		strcat(buf, xtables_ipmask_to_numeric(mask));
+		printf("%s ", buf);
+	}
+}
+
+static void
+matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, const char *optpfx)
+{
+	struct xt_conntrack_info *sinfo = (void *)match->data;
+
+	if(sinfo->flags & XT_CONNTRACK_STATE) {
+        	if (sinfo->invflags & XT_CONNTRACK_STATE)
+                	printf("! ");
+		printf("%sctstate ", optpfx);
+		print_state(sinfo->statemask);
+	}
+
+	if(sinfo->flags & XT_CONNTRACK_PROTO) {
+        	if (sinfo->invflags & XT_CONNTRACK_PROTO)
+                	printf("! ");
+		printf("%sctproto ", optpfx);
+		printf("%u ", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum);
+	}
+
+	if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
+		if (sinfo->invflags & XT_CONNTRACK_ORIGSRC)
+			printf("! ");
+		printf("%sctorigsrc ", optpfx);
+
+		print_addr(
+		    (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
+		    &sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
+		    false,
+		    numeric);
+	}
+
+	if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
+		if (sinfo->invflags & XT_CONNTRACK_ORIGDST)
+			printf("! ");
+		printf("%sctorigdst ", optpfx);
+
+		print_addr(
+		    (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
+		    &sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
+		    false,
+		    numeric);
+	}
+
+	if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
+		if (sinfo->invflags & XT_CONNTRACK_REPLSRC)
+			printf("! ");
+		printf("%sctreplsrc ", optpfx);
+
+		print_addr(
+		    (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
+		    &sinfo->sipmsk[IP_CT_DIR_REPLY],
+		    false,
+		    numeric);
+	}
+
+	if(sinfo->flags & XT_CONNTRACK_REPLDST) {
+		if (sinfo->invflags & XT_CONNTRACK_REPLDST)
+			printf("! ");
+		printf("%sctrepldst ", optpfx);
+
+		print_addr(
+		    (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
+		    &sinfo->dipmsk[IP_CT_DIR_REPLY],
+		    false,
+		    numeric);
+	}
+
+	if(sinfo->flags & XT_CONNTRACK_STATUS) {
+        	if (sinfo->invflags & XT_CONNTRACK_STATUS)
+                	printf("! ");
+		printf("%sctstatus ", optpfx);
+		print_status(sinfo->statusmask);
+	}
+
+	if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
+        	if (sinfo->invflags & XT_CONNTRACK_EXPIRES)
+                	printf("! ");
+		printf("%sctexpire ", optpfx);
+
+        	if (sinfo->expires_max == sinfo->expires_min)
+                	printf("%lu ", sinfo->expires_min);
+        	else
+                	printf("%lu:%lu ", sinfo->expires_min, sinfo->expires_max);
+	}
+
+	if (sinfo->flags & XT_CONNTRACK_DIRECTION) {
+		if (sinfo->invflags & XT_CONNTRACK_DIRECTION)
+			printf("%sctdir REPLY", optpfx);
+		else
+			printf("%sctdir ORIGINAL", optpfx);
+	}
+
+}
+
+static void
+conntrack_dump(const struct xt_conntrack_mtinfo2 *info, const char *prefix,
+               unsigned int family, bool numeric)
+{
+	if (info->match_flags & XT_CONNTRACK_STATE) {
+		if (info->invert_flags & XT_CONNTRACK_STATE)
+			printf("! ");
+		printf("%sctstate ", prefix);
+		print_state(info->state_mask);
+	}
+
+	if (info->match_flags & XT_CONNTRACK_PROTO) {
+		if (info->invert_flags & XT_CONNTRACK_PROTO)
+			printf("! ");
+		printf("%sctproto %u ", prefix, info->l4proto);
+	}
+
+	if (info->match_flags & XT_CONNTRACK_ORIGSRC) {
+		if (info->invert_flags & XT_CONNTRACK_ORIGSRC)
+			printf("! ");
+		printf("%sctorigsrc ", prefix);
+		conntrack_dump_addr(&info->origsrc_addr, &info->origsrc_mask,
+		                    family, numeric);
+	}
+
+	if (info->match_flags & XT_CONNTRACK_ORIGDST) {
+		if (info->invert_flags & XT_CONNTRACK_ORIGDST)
+			printf("! ");
+		printf("%sctorigdst ", prefix);
+		conntrack_dump_addr(&info->origdst_addr, &info->origdst_mask,
+		                    family, numeric);
+	}
+
+	if (info->match_flags & XT_CONNTRACK_REPLSRC) {
+		if (info->invert_flags & XT_CONNTRACK_REPLSRC)
+			printf("! ");
+		printf("%sctreplsrc ", prefix);
+		conntrack_dump_addr(&info->replsrc_addr, &info->replsrc_mask,
+		                    family, numeric);
+	}
+
+	if (info->match_flags & XT_CONNTRACK_REPLDST) {
+		if (info->invert_flags & XT_CONNTRACK_REPLDST)
+			printf("! ");
+		printf("%sctrepldst ", prefix);
+		conntrack_dump_addr(&info->repldst_addr, &info->repldst_mask,
+		                    family, numeric);
+	}
+
+	if (info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) {
+		if (info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT)
+			printf("! ");
+		printf("%sctorigsrcport %u ", prefix,
+		       ntohs(info->origsrc_port));
+	}
+
+	if (info->match_flags & XT_CONNTRACK_ORIGDST_PORT) {
+		if (info->invert_flags & XT_CONNTRACK_ORIGDST_PORT)
+			printf("! ");
+		printf("%sctorigdstport %u ", prefix,
+		       ntohs(info->origdst_port));
+	}
+
+	if (info->match_flags & XT_CONNTRACK_REPLSRC_PORT) {
+		if (info->invert_flags & XT_CONNTRACK_REPLSRC_PORT)
+			printf("! ");
+		printf("%sctreplsrcport %u ", prefix,
+		       ntohs(info->replsrc_port));
+	}
+
+	if (info->match_flags & XT_CONNTRACK_REPLDST_PORT) {
+		if (info->invert_flags & XT_CONNTRACK_REPLDST_PORT)
+			printf("! ");
+		printf("%sctrepldstport %u ", prefix,
+		       ntohs(info->repldst_port));
+	}
+
+	if (info->match_flags & XT_CONNTRACK_STATUS) {
+		if (info->invert_flags & XT_CONNTRACK_STATUS)
+			printf("! ");
+		printf("%sctstatus ", prefix);
+		print_status(info->status_mask);
+	}
+
+	if (info->match_flags & XT_CONNTRACK_EXPIRES) {
+		if (info->invert_flags & XT_CONNTRACK_EXPIRES)
+			printf("! ");
+		printf("%sctexpire ", prefix);
+
+		if (info->expires_max == info->expires_min)
+			printf("%u ", (unsigned int)info->expires_min);
+		else
+			printf("%u:%u ", (unsigned int)info->expires_min,
+			       (unsigned int)info->expires_max);
+	}
+
+	if (info->match_flags & XT_CONNTRACK_DIRECTION) {
+		if (info->invert_flags & XT_CONNTRACK_DIRECTION)
+			printf("%sctdir REPLY", prefix);
+		else
+			printf("%sctdir ORIGINAL", prefix);
+	}
+}
+
+static void conntrack_print(const void *ip, const struct xt_entry_match *match,
+                            int numeric)
+{
+	matchinfo_print(ip, match, numeric, "");
+}
+
+static void
+conntrack1_mt4_print(const void *ip, const struct xt_entry_match *match,
+                     int numeric)
+{
+	const struct xt_conntrack_mtinfo1 *info = (void *)match->data;
+	struct xt_conntrack_mtinfo2 up;
+
+	cinfo_transform(&up, info);
+	conntrack_dump(&up, "", NFPROTO_IPV4, numeric);
+}
+
+static void
+conntrack1_mt6_print(const void *ip, const struct xt_entry_match *match,
+                     int numeric)
+{
+	const struct xt_conntrack_mtinfo1 *info = (void *)match->data;
+	struct xt_conntrack_mtinfo2 up;
+
+	cinfo_transform(&up, info);
+	conntrack_dump(&up, "", NFPROTO_IPV6, numeric);
+}
+
+static void
+conntrack_mt_print(const void *ip, const struct xt_entry_match *match,
+                   int numeric)
+{
+	conntrack_dump((const void *)match->data, "", NFPROTO_IPV4, numeric);
+}
+
+static void
+conntrack_mt6_print(const void *ip, const struct xt_entry_match *match,
+                    int numeric)
+{
+	conntrack_dump((const void *)match->data, "", NFPROTO_IPV6, numeric);
+}
+
+static void conntrack_save(const void *ip, const struct xt_entry_match *match)
+{
+	matchinfo_print(ip, match, 1, "--");
+}
+
+static void conntrack_mt_save(const void *ip,
+                              const struct xt_entry_match *match)
+{
+	conntrack_dump((const void *)match->data, "--", NFPROTO_IPV4, true);
+}
+
+static void conntrack_mt6_save(const void *ip,
+                               const struct xt_entry_match *match)
+{
+	conntrack_dump((const void *)match->data, "--", NFPROTO_IPV6, true);
+}
+
+static void
+conntrack1_mt4_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_conntrack_mtinfo1 *info = (void *)match->data;
+	struct xt_conntrack_mtinfo2 up;
+
+	cinfo_transform(&up, info);
+	conntrack_dump(&up, "--", NFPROTO_IPV4, true);
+}
+
+static void
+conntrack1_mt6_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_conntrack_mtinfo1 *info = (void *)match->data;
+	struct xt_conntrack_mtinfo2 up;
+
+	cinfo_transform(&up, info);
+	conntrack_dump(&up, "--", NFPROTO_IPV6, true);
+}
+
+static struct xtables_match conntrack_mt_v0_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "conntrack",
+	.revision      = 0,
+	.family        = NFPROTO_IPV4,
+	.size          = XT_ALIGN(sizeof(struct xt_conntrack_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_info)),
+	.help          = conntrack_mt_help,
+	.parse         = conntrack_parse,
+	.final_check   = conntrack_mt_check,
+	.print         = conntrack_print,
+	.save          = conntrack_save,
+	.extra_opts    = conntrack_mt_opts_v0,
+};
+
+static struct xtables_match conntrack_mt_v1_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "conntrack",
+	.revision      = 1,
+	.family        = NFPROTO_IPV4,
+	.size          = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
+	.help          = conntrack_mt_help,
+	.parse         = conntrack1_mt4_parse,
+	.final_check   = conntrack_mt_check,
+	.print         = conntrack1_mt4_print,
+	.save          = conntrack1_mt4_save,
+	.extra_opts    = conntrack_mt_opts,
+};
+
+static struct xtables_match conntrack_mt6_v1_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "conntrack",
+	.revision      = 1,
+	.family        = NFPROTO_IPV6,
+	.size          = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
+	.help          = conntrack_mt_help,
+	.parse         = conntrack1_mt6_parse,
+	.final_check   = conntrack_mt_check,
+	.print         = conntrack1_mt6_print,
+	.save          = conntrack1_mt6_save,
+	.extra_opts    = conntrack_mt_opts,
+};
+
+static struct xtables_match conntrack_mt_v2_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "conntrack",
+	.revision      = 2,
+	.family        = NFPROTO_IPV4,
+	.size          = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)),
+	.help          = conntrack_mt_help,
+	.parse         = conntrack2_mt4_parse,
+	.final_check   = conntrack_mt_check,
+	.print         = conntrack_mt_print,
+	.save          = conntrack_mt_save,
+	.extra_opts    = conntrack_mt_opts,
+};
+
+static struct xtables_match conntrack_mt6_v2_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "conntrack",
+	.revision      = 2,
+	.family        = NFPROTO_IPV6,
+	.size          = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)),
+	.help          = conntrack_mt_help,
+	.parse         = conntrack2_mt6_parse,
+	.final_check   = conntrack_mt_check,
+	.print         = conntrack_mt6_print,
+	.save          = conntrack_mt6_save,
+	.extra_opts    = conntrack_mt_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&conntrack_mt_v0_reg);
+	xtables_register_match(&conntrack_mt_v1_reg);
+	xtables_register_match(&conntrack_mt6_v1_reg);
+	xtables_register_match(&conntrack_mt_v2_reg);
+	xtables_register_match(&conntrack_mt6_v2_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_conntrack.man b/ap/app/iptables/extensions/libxt_conntrack.man
new file mode 100755
index 0000000..b3d9e73
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_conntrack.man
@@ -0,0 +1,81 @@
+This module, when combined with connection tracking, allows access to the
+connection tracking state for this packet/connection.
+.TP
+[\fB!\fR] \fB\-\-ctstate\fP \fIstatelist\fP
+\fIstatelist\fR is a comma separated list of the connection states to match.
+Possible states are listed below.
+.TP
+[\fB!\fR] \fB\-\-ctproto\fP \fIl4proto\fP
+Layer-4 protocol to match (by number or name)
+.TP
+[\fB!\fR] \fB\-\-ctorigsrc\fP \fIaddress\fP[\fB/\fP\fImask\fP]
+.TP
+[\fB!\fR] \fB\-\-ctorigdst\fP \fIaddress\fP[\fB/\fP\fImask\fP]
+.TP
+[\fB!\fR] \fB\-\-ctreplsrc\fP \fIaddress\fP[\fB/\fP\fImask\fP]
+.TP
+[\fB!\fR] \fB\-\-ctrepldst\fP \fIaddress\fP[\fB/\fP\fImask\fP]
+Match against original/reply source/destination address
+.TP
+[\fB!\fR] \fB\-\-ctorigsrcport\fP \fIport\fP
+.TP
+[\fB!\fR] \fB\-\-ctorigdstport\fP \fIport\fP
+.TP
+[\fB!\fR] \fB\-\-ctreplsrcport\fP \fIport\fP
+.TP
+[\fB!\fR] \fB\-\-ctrepldstport\fP \fIport\fP
+Match against original/reply source/destination port (TCP/UDP/etc.) or GRE key.
+.TP
+[\fB!\fR] \fB\-\-ctstatus\fP \fIstatelist\fP
+\fIstatuslist\fR is a comma separated list of the connection statuses to match.
+Possible statuses are listed below.
+.TP
+[\fB!\fR] \fB\-\-ctexpire\fP \fItime\fP[\fB:\fP\fItime\fP]
+Match remaining lifetime in seconds against given value or range of values
+(inclusive)
+.TP
+\fB\-\-ctdir\fP {\fBORIGINAL\fP|\fBREPLY\fP}
+Match packets that are flowing in the specified direction. If this flag is not
+specified at all, matches packets in both directions.
+.PP
+States for \fB\-\-ctstate\fP:
+.TP
+\fBINVALID\fR
+meaning that the packet is associated with no known connection
+.TP
+\fBNEW\fR
+meaning that the packet has started a new connection, or otherwise associated
+with a connection which has not seen packets in both directions, and
+.TP
+\fBESTABLISHED\fR
+meaning that the packet is associated with a connection which has seen packets
+in both directions,
+.TP
+\fBRELATED\fR
+meaning that the packet is starting a new connection, but is associated with an
+existing connection, such as an FTP data transfer, or an ICMP error.
+.TP
+\fBSNAT\fR
+A virtual state, matching if the original source address differs from the reply
+destination.
+.TP
+\fBDNAT\fR
+A virtual state, matching if the original destination differs from the reply
+source.
+.PP
+Statuses for \fB\-\-ctstatus\fP:
+.TP
+\fBNONE\fR
+None of the below.
+.TP
+\fBEXPECTED\fR
+This is an expected connection (i.e. a conntrack helper set it up)
+.TP
+\fBSEEN_REPLY\fR
+Conntrack has seen packets in both directions.
+.TP
+\fBASSURED\fR
+Conntrack entry should never be early-expired.
+.TP
+\fBCONFIRMED\fR
+Connection is confirmed: originating packet has left box.
diff --git a/ap/app/iptables/extensions/libxt_dccp.c b/ap/app/iptables/extensions/libxt_dccp.c
new file mode 100755
index 0000000..413624e
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_dccp.c
@@ -0,0 +1,370 @@
+/* Shared library add-on to iptables for DCCP matching
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ *
+ * This program is distributed under the terms of GNU GPL v2, 1991
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <ctype.h>
+
+#include <netinet/in.h>
+#include <xtables.h>
+#include <linux/dccp.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_dccp.h>
+
+#if 0
+#define DEBUGP(format, first...) printf(format, ##first)
+#define static
+#else
+#define DEBUGP(format, fist...) 
+#endif
+
+static void dccp_init(struct xt_entry_match *m)
+{
+	struct xt_dccp_info *einfo = (struct xt_dccp_info *)m->data;
+
+	memset(einfo, 0, sizeof(struct xt_dccp_info));
+}
+
+static void dccp_help(void)
+{
+	printf(
+"dccp match options\n"
+"[!] --source-port port[:port]                          match source port(s)\n"
+" --sport ...\n"
+"[!] --destination-port port[:port]                     match destination port(s)\n"
+" --dport ...\n");
+}
+
+static const struct option dccp_opts[] = {
+	{ .name = "source-port", .has_arg = 1, .val = '1' },
+	{ .name = "sport", .has_arg = 1, .val = '1' },
+	{ .name = "destination-port", .has_arg = 1, .val = '2' },
+	{ .name = "dport", .has_arg = 1, .val = '2' },
+	{ .name = "dccp-types", .has_arg = 1, .val = '3' },
+	{ .name = "dccp-option", .has_arg = 1, .val = '4' },
+	{ .name = NULL }
+};
+
+static void
+parse_dccp_ports(const char *portstring, 
+		 u_int16_t *ports)
+{
+	char *buffer;
+	char *cp;
+
+	buffer = strdup(portstring);
+	DEBUGP("%s\n", portstring);
+	if ((cp = strchr(buffer, ':')) == NULL) {
+		ports[0] = ports[1] = xtables_parse_port(buffer, "dccp");
+	}
+	else {
+		*cp = '\0';
+		cp++;
+
+		ports[0] = buffer[0] ? xtables_parse_port(buffer, "dccp") : 0;
+		ports[1] = cp[0] ? xtables_parse_port(cp, "dccp") : 0xFFFF;
+
+		if (ports[0] > ports[1])
+			xtables_error(PARAMETER_PROBLEM,
+				   "invalid portrange (min > max)");
+	}
+	free(buffer);
+}
+
+static const char *const dccp_pkt_types[] = {
+	[DCCP_PKT_REQUEST] 	= "REQUEST",
+	[DCCP_PKT_RESPONSE]	= "RESPONSE",
+	[DCCP_PKT_DATA]		= "DATA",
+	[DCCP_PKT_ACK]		= "ACK",
+	[DCCP_PKT_DATAACK]	= "DATAACK",
+	[DCCP_PKT_CLOSEREQ]	= "CLOSEREQ",
+	[DCCP_PKT_CLOSE]	= "CLOSE",
+	[DCCP_PKT_RESET]	= "RESET",
+	[DCCP_PKT_SYNC]		= "SYNC",
+	[DCCP_PKT_SYNCACK]	= "SYNCACK",
+	[DCCP_PKT_INVALID]	= "INVALID",
+};
+
+static u_int16_t
+parse_dccp_types(const char *typestring)
+{
+	u_int16_t typemask = 0;
+	char *ptr, *buffer;
+
+	buffer = strdup(typestring);
+
+	for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
+		unsigned int i;
+		for (i = 0; i < sizeof(dccp_pkt_types)/sizeof(char *); i++) {
+			if (!strcasecmp(dccp_pkt_types[i], ptr)) {
+				typemask |= (1 << i);
+				break;
+			}
+		}
+		if (i == sizeof(dccp_pkt_types)/sizeof(char *))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unknown DCCP type `%s'", ptr);
+	}
+
+	free(buffer);
+	return typemask;
+}
+
+static u_int8_t parse_dccp_option(char *optstring)
+{
+	unsigned int ret;
+
+	if (!xtables_strtoui(optstring, NULL, &ret, 1, UINT8_MAX))
+		xtables_error(PARAMETER_PROBLEM, "Bad DCCP option \"%s\"",
+			   optstring);
+
+	return ret;
+}
+
+static int
+dccp_parse(int c, char **argv, int invert, unsigned int *flags,
+           const void *entry, struct xt_entry_match **match)
+{
+	struct xt_dccp_info *einfo
+		= (struct xt_dccp_info *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & XT_DCCP_SRC_PORTS)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Only one `--source-port' allowed");
+		einfo->flags |= XT_DCCP_SRC_PORTS;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_dccp_ports(argv[optind-1], einfo->spts);
+		if (invert)
+			einfo->invflags |= XT_DCCP_SRC_PORTS;
+		*flags |= XT_DCCP_SRC_PORTS;
+		break;
+
+	case '2':
+		if (*flags & XT_DCCP_DEST_PORTS)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--destination-port' allowed");
+		einfo->flags |= XT_DCCP_DEST_PORTS;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_dccp_ports(argv[optind-1], einfo->dpts);
+		if (invert)
+			einfo->invflags |= XT_DCCP_DEST_PORTS;
+		*flags |= XT_DCCP_DEST_PORTS;
+		break;
+
+	case '3':
+		if (*flags & XT_DCCP_TYPE)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--dccp-types' allowed");
+		einfo->flags |= XT_DCCP_TYPE;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		einfo->typemask = parse_dccp_types(argv[optind-1]);
+		if (invert)
+			einfo->invflags |= XT_DCCP_TYPE;
+		*flags |= XT_DCCP_TYPE;
+		break;
+
+	case '4':
+		if (*flags & XT_DCCP_OPTION)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--dccp-option' allowed");
+		einfo->flags |= XT_DCCP_OPTION;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		einfo->option = parse_dccp_option(argv[optind-1]);
+		if (invert)
+			einfo->invflags |= XT_DCCP_OPTION;
+		*flags |= XT_DCCP_OPTION;
+		break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static char *
+port_to_service(int port)
+{
+	struct servent *service;
+
+	if ((service = getservbyport(htons(port), "dccp")))
+		return service->s_name;
+
+	return NULL;
+}
+
+static void
+print_port(u_int16_t port, int numeric)
+{
+	char *service;
+
+	if (numeric || (service = port_to_service(port)) == NULL)
+		printf("%u", port);
+	else
+		printf("%s", service);
+}
+
+static void
+print_ports(const char *name, u_int16_t min, u_int16_t max,
+	    int invert, int numeric)
+{
+	const char *inv = invert ? "!" : "";
+
+	if (min != 0 || max != 0xFFFF || invert) {
+		printf("%s", name);
+		if (min == max) {
+			printf(":%s", inv);
+			print_port(min, numeric);
+		} else {
+			printf("s:%s", inv);
+			print_port(min, numeric);
+			printf(":");
+			print_port(max, numeric);
+		}
+		printf(" ");
+	}
+}
+
+static void
+print_types(u_int16_t types, int inverted, int numeric)
+{
+	int have_type = 0;
+
+	if (inverted)
+		printf("! ");
+
+	while (types) {
+		unsigned int i;
+
+		for (i = 0; !(types & (1 << i)); i++);
+
+		if (have_type)
+			printf(",");
+		else
+			have_type = 1;
+
+		if (numeric)
+			printf("%u", i);
+		else
+			printf("%s", dccp_pkt_types[i]);
+
+		types &= ~(1 << i);
+	}
+}
+
+static void
+print_option(u_int8_t option, int invert, int numeric)
+{
+	if (option || invert)
+		printf("option=%s%u ", invert ? "!" : "", option);
+}
+
+static void
+dccp_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_dccp_info *einfo =
+		(const struct xt_dccp_info *)match->data;
+
+	printf("dccp ");
+
+	if (einfo->flags & XT_DCCP_SRC_PORTS) {
+		print_ports("spt", einfo->spts[0], einfo->spts[1],
+			einfo->invflags & XT_DCCP_SRC_PORTS,
+			numeric);
+	}
+
+	if (einfo->flags & XT_DCCP_DEST_PORTS) {
+		print_ports("dpt", einfo->dpts[0], einfo->dpts[1],
+			einfo->invflags & XT_DCCP_DEST_PORTS,
+			numeric);
+	}
+
+	if (einfo->flags & XT_DCCP_TYPE) {
+		print_types(einfo->typemask,
+			   einfo->invflags & XT_DCCP_TYPE,
+			   numeric);
+	}
+
+	if (einfo->flags & XT_DCCP_OPTION) {
+		print_option(einfo->option,
+			     einfo->invflags & XT_DCCP_OPTION, numeric);
+	}
+}
+
+static void dccp_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_dccp_info *einfo =
+		(const struct xt_dccp_info *)match->data;
+
+	if (einfo->flags & XT_DCCP_SRC_PORTS) {
+		if (einfo->invflags & XT_DCCP_SRC_PORTS)
+			printf("! ");
+		if (einfo->spts[0] != einfo->spts[1])
+			printf("--sport %u:%u ", 
+			       einfo->spts[0], einfo->spts[1]);
+		else
+			printf("--sport %u ", einfo->spts[0]);
+	}
+
+	if (einfo->flags & XT_DCCP_DEST_PORTS) {
+		if (einfo->invflags & XT_DCCP_DEST_PORTS)
+			printf("! ");
+		if (einfo->dpts[0] != einfo->dpts[1])
+			printf("--dport %u:%u ",
+			       einfo->dpts[0], einfo->dpts[1]);
+		else
+			printf("--dport %u ", einfo->dpts[0]);
+	}
+
+	if (einfo->flags & XT_DCCP_TYPE) {
+		printf("--dccp-type ");
+		print_types(einfo->typemask, einfo->invflags & XT_DCCP_TYPE,0);
+	}
+
+	if (einfo->flags & XT_DCCP_OPTION) {
+		printf("--dccp-option %s%u ", 
+			einfo->typemask & XT_DCCP_OPTION ? "! " : "",
+			einfo->option);
+	}
+}
+
+static struct xtables_match dccp_match = {
+	.name		= "dccp",
+	.family		= NFPROTO_IPV4,
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_dccp_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_dccp_info)),
+	.help		= dccp_help,
+	.init		= dccp_init,
+	.parse		= dccp_parse,
+	.print		= dccp_print,
+	.save		= dccp_save,
+	.extra_opts	= dccp_opts,
+};
+
+static struct xtables_match dccp_match6 = {
+	.name		= "dccp",
+	.family		= NFPROTO_IPV6,
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_dccp_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_dccp_info)),
+	.help		= dccp_help,
+	.init		= dccp_init,
+	.parse		= dccp_parse,
+	.print		= dccp_print,
+	.save		= dccp_save,
+	.extra_opts	= dccp_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&dccp_match);
+	xtables_register_match(&dccp_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_dccp.man b/ap/app/iptables/extensions/libxt_dccp.man
new file mode 100755
index 0000000..82c3f70
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_dccp.man
@@ -0,0 +1,12 @@
+.TP
+[\fB!\fP] \fB\-\-source\-port\fP,\fB\-\-sport\fP \fIport\fP[\fB:\fP\fIport\fP]
+.TP
+[\fB!\fP] \fB\-\-destination\-port\fP,\fB\-\-dport\fP \fIport\fP[\fB:\fP\fIport\fP]
+.TP
+[\fB!\fP] \fB\-\-dccp\-types\fP \fImask\fP
+Match when the DCCP packet type is one of 'mask'. 'mask' is a comma-separated
+list of packet types.  Packet types are: 
+.BR "REQUEST RESPONSE DATA ACK DATAACK CLOSEREQ CLOSE RESET SYNC SYNCACK INVALID" .
+.TP
+[\fB!\fP] \fB\-\-dccp\-option\fP \fInumber\fP
+Match if DCP option set.
diff --git a/ap/app/iptables/extensions/libxt_dscp.c b/ap/app/iptables/extensions/libxt_dscp.c
new file mode 100755
index 0000000..62fa6af
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_dscp.c
@@ -0,0 +1,165 @@
+/* Shared library add-on to iptables for DSCP
+ *
+ * (C) 2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This program is distributed under the terms of GNU GPL v2, 1991
+ *
+ * libipt_dscp.c borrowed heavily from libipt_tos.c
+ *
+ * --class support added by Iain Barnes
+ * 
+ * For a list of DSCP codepoints see 
+ * http://www.iana.org/assignments/dscp-registry
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_dscp.h>
+
+/* This is evil, but it's my code - HW*/
+#include "dscp_helper.c"
+
+static void dscp_help(void)
+{
+	printf(
+"dscp match options\n"
+"[!] --dscp value		Match DSCP codepoint with numerical value\n"
+"  		                This value can be in decimal (ex: 32)\n"
+"               		or in hex (ex: 0x20)\n"
+"[!] --dscp-class name		Match the DiffServ class. This value may\n"
+"				be any of the BE,EF, AFxx or CSx classes\n"
+"\n"
+"				These two options are mutually exclusive !\n");
+}
+
+static const struct option dscp_opts[] = {
+	{ "dscp", 1, NULL, 'F' },
+	{ "dscp-class", 1, NULL, 'G' },
+	{ .name = NULL }
+};
+
+static void
+parse_dscp(const char *s, struct xt_dscp_info *dinfo)
+{
+	unsigned int dscp;
+       
+	if (!xtables_strtoui(s, NULL, &dscp, 0, UINT8_MAX))
+		xtables_error(PARAMETER_PROBLEM,
+			   "Invalid dscp `%s'\n", s);
+
+	if (dscp > XT_DSCP_MAX)
+		xtables_error(PARAMETER_PROBLEM,
+			   "DSCP `%d` out of range\n", dscp);
+
+	dinfo->dscp = dscp;
+}
+
+
+static void
+parse_class(const char *s, struct xt_dscp_info *dinfo)
+{
+	unsigned int dscp = class_to_dscp(s);
+
+	/* Assign the value */
+	dinfo->dscp = dscp;
+}
+
+
+static int
+dscp_parse(int c, char **argv, int invert, unsigned int *flags,
+           const void *entry, struct xt_entry_match **match)
+{
+	struct xt_dscp_info *dinfo
+		= (struct xt_dscp_info *)(*match)->data;
+
+	switch (c) {
+	case 'F':
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+			           "DSCP match: Only use --dscp ONCE!");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_dscp(argv[optind-1], dinfo);
+		if (invert)
+			dinfo->invert = 1;
+		*flags = 1;
+		break;
+
+	case 'G':
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+					"DSCP match: Only use --dscp-class ONCE!");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_class(argv[optind - 1], dinfo);
+		if (invert)
+			dinfo->invert = 1;
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void dscp_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+		           "DSCP match: Parameter --dscp is required");
+}
+
+static void
+dscp_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_dscp_info *dinfo =
+		(const struct xt_dscp_info *)match->data;
+	printf("DSCP match %s0x%02x", dinfo->invert ? "!" : "", dinfo->dscp);
+}
+
+static void dscp_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_dscp_info *dinfo =
+		(const struct xt_dscp_info *)match->data;
+
+	printf("%s--dscp 0x%02x ", dinfo->invert ? "! " : "", dinfo->dscp);
+}
+
+static struct xtables_match dscp_match = {
+	.family		= NFPROTO_IPV4,
+	.name 		= "dscp",
+	.version 	= XTABLES_VERSION,
+	.size 		= XT_ALIGN(sizeof(struct xt_dscp_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_dscp_info)),
+	.help		= dscp_help,
+	.parse		= dscp_parse,
+	.final_check	= dscp_check,
+	.print		= dscp_print,
+	.save		= dscp_save,
+	.extra_opts	= dscp_opts,
+};
+
+static struct xtables_match dscp_match6 = {
+	.family		= NFPROTO_IPV6,
+	.name 		= "dscp",
+	.version 	= XTABLES_VERSION,
+	.size 		= XT_ALIGN(sizeof(struct xt_dscp_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_dscp_info)),
+	.help		= dscp_help,
+	.parse		= dscp_parse,
+	.final_check	= dscp_check,
+	.print		= dscp_print,
+	.save		= dscp_save,
+	.extra_opts	= dscp_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&dscp_match);
+	xtables_register_match(&dscp_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_dscp.man b/ap/app/iptables/extensions/libxt_dscp.man
new file mode 100755
index 0000000..63a17da
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_dscp.man
@@ -0,0 +1,10 @@
+This module matches the 6 bit DSCP field within the TOS field in the
+IP header.  DSCP has superseded TOS within the IETF.
+.TP
+[\fB!\fP] \fB\-\-dscp\fP \fIvalue\fP
+Match against a numeric (decimal or hex) value [0-63].
+.TP
+[\fB!\fP] \fB\-\-dscp\-class\fP \fIclass\fP
+Match the DiffServ class. This value may be any of the
+BE, EF, AFxx or CSx classes.  It will then be converted
+into its according numeric value.
diff --git a/ap/app/iptables/extensions/libxt_esp.c b/ap/app/iptables/extensions/libxt_esp.c
new file mode 100755
index 0000000..5769edb
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_esp.c
@@ -0,0 +1,184 @@
+/* Shared library add-on to iptables to add ESP support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_esp.h>
+
+static void esp_help(void)
+{
+	printf(
+"esp match options:\n"
+"[!] --espspi spi[:spi]\n"
+"				match spi (range)\n");
+}
+
+static const struct option esp_opts[] = {
+	{ "espspi", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static u_int32_t
+parse_esp_spi(const char *spistr)
+{
+	unsigned long int spi;
+	char* ep;
+
+	spi =  strtoul(spistr,&ep,0) ;
+
+	if ( spistr == ep ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "ESP no valid digits in spi `%s'", spistr);
+	}
+	if ( spi == ULONG_MAX  && errno == ERANGE ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "spi `%s' specified too big: would overflow", spistr);
+	}	
+	if ( *spistr != '\0'  && *ep != '\0' ) {
+		xtables_error(PARAMETER_PROBLEM,
+			   "ESP error parsing spi `%s'", spistr);
+	}
+	return spi;
+}
+
+static void
+parse_esp_spis(const char *spistring, u_int32_t *spis)
+{
+	char *buffer;
+	char *cp;
+
+	buffer = strdup(spistring);
+	if ((cp = strchr(buffer, ':')) == NULL)
+		spis[0] = spis[1] = parse_esp_spi(buffer);
+	else {
+		*cp = '\0';
+		cp++;
+
+		spis[0] = buffer[0] ? parse_esp_spi(buffer) : 0;
+		spis[1] = cp[0] ? parse_esp_spi(cp) : 0xFFFFFFFF;
+		if (spis[0] > spis[1])
+			xtables_error(PARAMETER_PROBLEM,
+				   "Invalid ESP spi range: %s", spistring);
+	}
+	free(buffer);
+}
+
+static void esp_init(struct xt_entry_match *m)
+{
+	struct xt_esp *espinfo = (struct xt_esp *)m->data;
+
+	espinfo->spis[1] = 0xFFFFFFFF;
+}
+
+#define ESP_SPI 0x01
+
+static int
+esp_parse(int c, char **argv, int invert, unsigned int *flags,
+          const void *entry, struct xt_entry_match **match)
+{
+	struct xt_esp *espinfo = (struct xt_esp *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & ESP_SPI)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--espspi' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_esp_spis(argv[optind-1], espinfo->spis);
+		if (invert)
+			espinfo->invflags |= XT_ESP_INV_SPI;
+		*flags |= ESP_SPI;
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+print_spis(const char *name, u_int32_t min, u_int32_t max,
+	    int invert)
+{
+	const char *inv = invert ? "!" : "";
+
+	if (min != 0 || max != 0xFFFFFFFF || invert) {
+		if (min == max)
+			printf("%s:%s%u ", name, inv, min);
+		else
+			printf("%ss:%s%u:%u ", name, inv, min, max);
+	}
+}
+
+static void
+esp_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_esp *esp = (struct xt_esp *)match->data;
+
+	printf("esp ");
+	print_spis("spi", esp->spis[0], esp->spis[1],
+		    esp->invflags & XT_ESP_INV_SPI);
+	if (esp->invflags & ~XT_ESP_INV_MASK)
+		printf("Unknown invflags: 0x%X ",
+		       esp->invflags & ~XT_ESP_INV_MASK);
+}
+
+static void esp_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_esp *espinfo = (struct xt_esp *)match->data;
+
+	if (!(espinfo->spis[0] == 0
+	    && espinfo->spis[1] == 0xFFFFFFFF)) {
+		printf("%s--espspi ",
+			(espinfo->invflags & XT_ESP_INV_SPI) ? "! " : "");
+		if (espinfo->spis[0]
+		    != espinfo->spis[1])
+			printf("%u:%u ",
+			       espinfo->spis[0],
+			       espinfo->spis[1]);
+		else
+			printf("%u ",
+			       espinfo->spis[0]);
+	}
+
+}
+
+static struct xtables_match esp_match = {
+	.family		= NFPROTO_IPV4,
+	.name 		= "esp",
+	.version 	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_esp)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_esp)),
+	.help		= esp_help,
+	.init		= esp_init,
+	.parse		= esp_parse,
+	.print		= esp_print,
+	.save		= esp_save,
+	.extra_opts	= esp_opts,
+};
+
+static struct xtables_match esp_match6 = {
+	.family		= NFPROTO_IPV6,
+	.name 		= "esp",
+	.version 	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_esp)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_esp)),
+	.help		= esp_help,
+	.init		= esp_init,
+	.parse		= esp_parse,
+	.print		= esp_print,
+	.save		= esp_save,
+	.extra_opts	= esp_opts,
+};
+
+void
+_init(void)
+{
+	xtables_register_match(&esp_match);
+	xtables_register_match(&esp_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_esp.man b/ap/app/iptables/extensions/libxt_esp.man
new file mode 100755
index 0000000..699a41c
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_esp.man
@@ -0,0 +1,3 @@
+This module matches the SPIs in ESP header of IPsec packets.
+.TP
+[\fB!\fP] \fB\-\-espspi\fP \fIspi\fP[\fB:\fP\fIspi\fP]
diff --git a/ap/app/iptables/extensions/libxt_hashlimit.c b/ap/app/iptables/extensions/libxt_hashlimit.c
new file mode 100755
index 0000000..9a7e5de
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_hashlimit.c
@@ -0,0 +1,735 @@
+/* ip6tables match extension for limiting packets per destination
+ *
+ * (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
+ *
+ * Development of this code was funded by Astaro AG, http://www.astaro.com/
+ *
+ * Based on ipt_limit.c by
+ * Jérôme de Vivie   <devivie@info.enserb.u-bordeaux.fr>
+ * Hervé Eychenne    <rv@wallfire.org>
+ * 
+ * Error corections by nmalykh@bilim.com (22.01.2005)
+ */
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <stddef.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_hashlimit.h>
+
+#define XT_HASHLIMIT_BURST	5
+
+/* miliseconds */
+#define XT_HASHLIMIT_GCINTERVAL	1000
+#define XT_HASHLIMIT_EXPIRE	10000
+
+static void hashlimit_help(void)
+{
+	printf(
+"hashlimit match options:\n"
+"--hashlimit <avg>		max average match rate\n"
+"                                [Packets per second unless followed by \n"
+"                                /sec /minute /hour /day postfixes]\n"
+"--hashlimit-mode <mode>		mode is a comma-separated list of\n"
+"					dstip,srcip,dstport,srcport\n"
+"--hashlimit-name <name>		name for /proc/net/ipt_hashlimit/\n"
+"[--hashlimit-burst <num>]	number to match in a burst, default %u\n"
+"[--hashlimit-htable-size <num>]	number of hashtable buckets\n"
+"[--hashlimit-htable-max <num>]	number of hashtable entries\n"
+"[--hashlimit-htable-gcinterval]	interval between garbage collection runs\n"
+"[--hashlimit-htable-expire]	after which time are idle entries expired?\n",
+XT_HASHLIMIT_BURST);
+}
+
+static void hashlimit_mt_help(void)
+{
+	printf(
+"hashlimit match options:\n"
+"  --hashlimit-upto <avg>           max average match rate\n"
+"                                   [Packets per second unless followed by \n"
+"                                   /sec /minute /hour /day postfixes]\n"
+"  --hashlimit-above <avg>          min average match rate\n"
+"  --hashlimit-mode <mode>          mode is a comma-separated list of\n"
+"                                   dstip,srcip,dstport,srcport (or none)\n"
+"  --hashlimit-srcmask <length>     source address grouping prefix length\n"
+"  --hashlimit-dstmask <length>     destination address grouping prefix length\n"
+"  --hashlimit-name <name>          name for /proc/net/ipt_hashlimit\n"
+"  --hashlimit-burst <num>	    number to match in a burst, default %u\n"
+"  --hashlimit-htable-size <num>    number of hashtable buckets\n"
+"  --hashlimit-htable-max <num>     number of hashtable entries\n"
+"  --hashlimit-htable-gcinterval    interval between garbage collection runs\n"
+"  --hashlimit-htable-expire        after which time are idle entries expired?\n"
+"\n", XT_HASHLIMIT_BURST);
+}
+
+static const struct option hashlimit_opts[] = {
+	{ "hashlimit", 1, NULL, '%' },
+	{ "hashlimit-burst", 1, NULL, '$' },
+	{ "hashlimit-htable-size", 1, NULL, '&' },
+	{ "hashlimit-htable-max", 1, NULL, '*' },
+	{ "hashlimit-htable-gcinterval", 1, NULL, '(' },
+	{ "hashlimit-htable-expire", 1, NULL, ')' },
+	{ "hashlimit-mode", 1, NULL, '_' },
+	{ "hashlimit-name", 1, NULL, '"' },
+	{ .name = NULL }
+};
+
+static const struct option hashlimit_mt_opts[] = {
+	{.name = "hashlimit-upto",              .has_arg = true, .val = '%'},
+	{.name = "hashlimit-above",             .has_arg = true, .val = '^'},
+	{.name = "hashlimit",                   .has_arg = true, .val = '%'},
+	{.name = "hashlimit-srcmask",           .has_arg = true, .val = '<'},
+	{.name = "hashlimit-dstmask",           .has_arg = true, .val = '>'},
+	{.name = "hashlimit-burst",             .has_arg = true, .val = '$'},
+	{.name = "hashlimit-htable-size",       .has_arg = true, .val = '&'},
+	{.name = "hashlimit-htable-max",        .has_arg = true, .val = '*'},
+	{.name = "hashlimit-htable-gcinterval", .has_arg = true, .val = '('},
+	{.name = "hashlimit-htable-expire",     .has_arg = true, .val = ')'},
+	{.name = "hashlimit-mode",              .has_arg = true, .val = '_'},
+	{.name = "hashlimit-name",              .has_arg = true, .val = '"'},
+	{},
+};
+
+static
+int parse_rate(const char *rate, u_int32_t *val)
+{
+	const char *delim;
+	u_int32_t r;
+	u_int32_t mult = 1;  /* Seconds by default. */
+
+	delim = strchr(rate, '/');
+	if (delim) {
+		if (strlen(delim+1) == 0)
+			return 0;
+
+		if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
+			mult = 1;
+		else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
+			mult = 60;
+		else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
+			mult = 60*60;
+		else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
+			mult = 24*60*60;
+		else
+			return 0;
+	}
+	r = atoi(rate);
+	if (!r)
+		return 0;
+
+	/* This would get mapped to infinite (1/day is minimum they
+           can specify, so we're ok at that end). */
+	if (r / mult > XT_HASHLIMIT_SCALE)
+		xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
+
+	*val = XT_HASHLIMIT_SCALE * mult / r;
+	return 1;
+}
+
+static void hashlimit_init(struct xt_entry_match *m)
+{
+	struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data;
+
+	r->cfg.mode = 0;
+	r->cfg.burst = XT_HASHLIMIT_BURST;
+	r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
+	r->cfg.expire = XT_HASHLIMIT_EXPIRE;
+
+}
+
+static void hashlimit_mt4_init(struct xt_entry_match *match)
+{
+	struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
+
+	info->cfg.mode        = 0;
+	info->cfg.burst       = XT_HASHLIMIT_BURST;
+	info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
+	info->cfg.expire      = XT_HASHLIMIT_EXPIRE;
+	info->cfg.srcmask     = 32;
+	info->cfg.dstmask     = 32;
+}
+
+static void hashlimit_mt6_init(struct xt_entry_match *match)
+{
+	struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
+
+	info->cfg.mode        = 0;
+	info->cfg.burst       = XT_HASHLIMIT_BURST;
+	info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
+	info->cfg.expire      = XT_HASHLIMIT_EXPIRE;
+	info->cfg.srcmask     = 128;
+	info->cfg.dstmask     = 128;
+}
+
+/* Parse a 'mode' parameter into the required bitmask */
+static int parse_mode(uint32_t *mode, char *option_arg)
+{
+	char *tok;
+	char *arg = strdup(option_arg);
+
+	if (!arg)
+		return -1;
+
+	for (tok = strtok(arg, ",|");
+	     tok;
+	     tok = strtok(NULL, ",|")) {
+		if (!strcmp(tok, "dstip"))
+			*mode |= XT_HASHLIMIT_HASH_DIP;
+		else if (!strcmp(tok, "srcip"))
+			*mode |= XT_HASHLIMIT_HASH_SIP;
+		else if (!strcmp(tok, "srcport"))
+			*mode |= XT_HASHLIMIT_HASH_SPT;
+		else if (!strcmp(tok, "dstport"))
+			*mode |= XT_HASHLIMIT_HASH_DPT;
+		else {
+			free(arg);
+			return -1;
+		}
+	}
+	free(arg);
+	return 0;
+}
+
+enum {
+	PARAM_LIMIT      = 1 << 0,
+	PARAM_BURST      = 1 << 1,
+	PARAM_MODE       = 1 << 2,
+	PARAM_NAME       = 1 << 3,
+	PARAM_SIZE       = 1 << 4,
+	PARAM_MAX        = 1 << 5,
+	PARAM_GCINTERVAL = 1 << 6,
+	PARAM_EXPIRE     = 1 << 7,
+	PARAM_SRCMASK    = 1 << 8,
+	PARAM_DSTMASK    = 1 << 9,
+};
+
+static int
+hashlimit_parse(int c, char **argv, int invert, unsigned int *flags,
+                const void *entry, struct xt_entry_match **match)
+{
+	struct xt_hashlimit_info *r = 
+			(struct xt_hashlimit_info *)(*match)->data;
+	unsigned int num;
+
+	switch(c) {
+	case '%':
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit",
+		          *flags & PARAM_LIMIT);
+		if (xtables_check_inverse(argv[optind-1], &invert, &optind, 0)) break;
+		if (!parse_rate(optarg, &r->cfg.avg))
+			xtables_error(PARAMETER_PROBLEM,
+				   "bad rate `%s'", optarg);
+		*flags |= PARAM_LIMIT;
+		break;
+
+	case '$':
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-burst",
+		          *flags & PARAM_BURST);
+		if (xtables_check_inverse(argv[optind-1], &invert, &optind, 0)) break;
+		if (!xtables_strtoui(optarg, NULL, &num, 0, 10000))
+			xtables_error(PARAMETER_PROBLEM,
+				   "bad --hashlimit-burst `%s'", optarg);
+		r->cfg.burst = num;
+		*flags |= PARAM_BURST;
+		break;
+	case '&':
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-size",
+		          *flags & PARAM_SIZE);
+		if (xtables_check_inverse(argv[optind-1], &invert, &optind, 0)) break;
+		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
+			xtables_error(PARAMETER_PROBLEM,
+				"bad --hashlimit-htable-size: `%s'", optarg);
+		r->cfg.size = num;
+		*flags |= PARAM_SIZE;
+		break;
+	case '*':
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-max",
+		          *flags & PARAM_MAX);
+		if (xtables_check_inverse(argv[optind-1], &invert, &optind, 0)) break;
+		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
+			xtables_error(PARAMETER_PROBLEM,
+				"bad --hashlimit-htable-max: `%s'", optarg);
+		r->cfg.max = num;
+		*flags |= PARAM_MAX;
+		break;
+	case '(':
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit",
+		          "--hashlimit-htable-gcinterval",
+		          *flags & PARAM_GCINTERVAL);
+		if (xtables_check_inverse(argv[optind-1], &invert, &optind, 0)) break;
+		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
+			xtables_error(PARAMETER_PROBLEM,
+				"bad --hashlimit-htable-gcinterval: `%s'", 
+				optarg);
+		/* FIXME: not HZ dependent!! */
+		r->cfg.gc_interval = num;
+		*flags |= PARAM_GCINTERVAL;
+		break;
+	case ')':
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit",
+		          "--hashlimit-htable-expire", *flags & PARAM_EXPIRE);
+		if (xtables_check_inverse(argv[optind-1], &invert, &optind, 0)) break;
+		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
+			xtables_error(PARAMETER_PROBLEM,
+				"bad --hashlimit-htable-expire: `%s'", optarg);
+		/* FIXME: not HZ dependent */
+		r->cfg.expire = num;
+		*flags |= PARAM_EXPIRE;
+		break;
+	case '_':
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-mode",
+		          *flags & PARAM_MODE);
+		if (xtables_check_inverse(argv[optind-1], &invert, &optind, 0)) break;
+		if (parse_mode(&r->cfg.mode, optarg) < 0)
+			xtables_error(PARAMETER_PROBLEM,
+				   "bad --hashlimit-mode: `%s'\n", optarg);
+		*flags |= PARAM_MODE;
+		break;
+	case '"':
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-name",
+		          *flags & PARAM_NAME);
+		if (xtables_check_inverse(argv[optind-1], &invert, &optind, 0)) break;
+		if (strlen(optarg) == 0)
+			xtables_error(PARAMETER_PROBLEM, "Zero-length name?");
+		strncpy(r->name, optarg, sizeof(r->name));
+		*flags |= PARAM_NAME;
+		break;
+	default:
+		return 0;
+	}
+
+	if (invert)
+		xtables_error(PARAMETER_PROBLEM,
+			   "hashlimit does not support invert");
+
+	return 1;
+}
+
+static int
+hashlimit_mt_parse(struct xt_hashlimit_mtinfo1 *info, unsigned int *flags,
+                   int c, int invert, unsigned int maxmask)
+{
+	unsigned int num;
+
+	switch(c) {
+	case '%': /* --hashlimit / --hashlimit-below */
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-upto",
+		          *flags & PARAM_LIMIT);
+		if (invert)
+			info->cfg.mode |= XT_HASHLIMIT_INVERT;
+		if (!parse_rate(optarg, &info->cfg.avg))
+			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
+			          "--hashlimit-upto", optarg);
+		*flags |= PARAM_LIMIT;
+		return true;
+
+	case '^': /* --hashlimit-above == !--hashlimit-below */
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-above",
+		          *flags & PARAM_LIMIT);
+		if (!invert)
+			info->cfg.mode |= XT_HASHLIMIT_INVERT;
+		if (!parse_rate(optarg, &info->cfg.avg))
+			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
+			          "--hashlimit-above", optarg);
+		*flags |= PARAM_LIMIT;
+		return true;
+
+	case '$': /* --hashlimit-burst */
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-burst",
+		          *flags & PARAM_BURST);
+		if (!xtables_strtoui(optarg, NULL, &num, 0, 10000))
+			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
+			          "--hashlimit-burst", optarg);
+		info->cfg.burst = num;
+		*flags |= PARAM_BURST;
+		return true;
+
+	case '&': /* --hashlimit-htable-size */
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-size",
+		          *flags & PARAM_SIZE);
+		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
+			          "--hashlimit-htable-size", optarg);
+		info->cfg.size = num;
+		*flags |= PARAM_SIZE;
+		return true;
+
+	case '*': /* --hashlimit-htable-max */
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-max",
+		          *flags & PARAM_MAX);
+		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
+			          "--hashlimit-htable-max", optarg);
+		info->cfg.max = num;
+		*flags |= PARAM_MAX;
+		return true;
+
+	case '(': /* --hashlimit-htable-gcinterval */
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit",
+		          "--hashlimit-htable-gcinterval",
+		          *flags & PARAM_GCINTERVAL);
+		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
+			          "--hashlimit-htable-gcinterval", optarg);
+		/* FIXME: not HZ dependent!! */
+		info->cfg.gc_interval = num;
+		*flags |= PARAM_GCINTERVAL;
+		return true;
+
+	case ')': /* --hashlimit-htable-expire */
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit",
+		          "--hashlimit-htable-expire", *flags & PARAM_EXPIRE);
+		if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
+			          "--hashlimit-htable-expire", optarg);
+		/* FIXME: not HZ dependent */
+		info->cfg.expire = num;
+		*flags |= PARAM_EXPIRE;
+		return true;
+
+	case '_':
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-mode",
+		          *flags & PARAM_MODE);
+		if (parse_mode(&info->cfg.mode, optarg) < 0)
+			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
+			          "--hashlimit-mode", optarg);
+		*flags |= PARAM_MODE;
+		return true;
+
+	case '"': /* --hashlimit-name */
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-name",
+		          *flags & PARAM_NAME);
+		if (strlen(optarg) == 0)
+			xtables_error(PARAMETER_PROBLEM, "Zero-length name?");
+		strncpy(info->name, optarg, sizeof(info->name));
+		info->name[sizeof(info->name)-1] = '\0';
+		*flags |= PARAM_NAME;
+		return true;
+
+	case '<': /* --hashlimit-srcmask */
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-srcmask",
+		          *flags & PARAM_SRCMASK);
+		if (!xtables_strtoui(optarg, NULL, &num, 0, maxmask))
+			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
+			          "--hashlimit-srcmask", optarg);
+		info->cfg.srcmask = num;
+		*flags |= PARAM_SRCMASK;
+		return true;
+
+	case '>': /* --hashlimit-dstmask */
+		xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-dstmask",
+		          *flags & PARAM_DSTMASK);
+		if (!xtables_strtoui(optarg, NULL, &num, 0, maxmask))
+			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
+			          "--hashlimit-dstmask", optarg);
+		info->cfg.dstmask = num;
+		*flags |= PARAM_DSTMASK;
+		return true;
+	}
+	return false;
+}
+
+static int
+hashlimit_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
+                    const void *entry, struct xt_entry_match **match)
+{
+	return hashlimit_mt_parse((void *)(*match)->data,
+	       flags, c, invert, 32);
+}
+
+static int
+hashlimit_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
+                    const void *entry, struct xt_entry_match **match)
+{
+	return hashlimit_mt_parse((void *)(*match)->data,
+	       flags, c, invert, 128);
+}
+
+static void hashlimit_check(unsigned int flags)
+{
+	if (!(flags & PARAM_LIMIT))
+		xtables_error(PARAMETER_PROBLEM,
+				"You have to specify --hashlimit");
+	if (!(flags & PARAM_MODE))
+		xtables_error(PARAMETER_PROBLEM,
+				"You have to specify --hashlimit-mode");
+	if (!(flags & PARAM_NAME))
+		xtables_error(PARAMETER_PROBLEM,
+				"You have to specify --hashlimit-name");
+}
+
+static void hashlimit_mt_check(unsigned int flags)
+{
+	if (!(flags & PARAM_LIMIT))
+		xtables_error(PARAMETER_PROBLEM, "You have to specify "
+		           "--hashlimit-upto or --hashlimit-above");
+	if (!(flags & PARAM_NAME))
+		xtables_error(PARAMETER_PROBLEM,
+		           "You have to specify --hashlimit-name");
+}
+
+static const struct rates
+{
+	const char *name;
+	u_int32_t mult;
+} rates[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 },
+	      { "hour", XT_HASHLIMIT_SCALE*60*60 },
+	      { "min", XT_HASHLIMIT_SCALE*60 },
+	      { "sec", XT_HASHLIMIT_SCALE } };
+
+static void print_rate(u_int32_t period)
+{
+	unsigned int i;
+
+	for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) {
+		if (period > rates[i].mult
+            || rates[i].mult/period < rates[i].mult%period)
+			break;
+	}
+
+	printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name);
+}
+
+static void print_mode(unsigned int mode, char separator)
+{
+	bool prevmode = false;
+
+	if (mode & XT_HASHLIMIT_HASH_SIP) {
+		fputs("srcip", stdout);
+		prevmode = 1;
+	}
+	if (mode & XT_HASHLIMIT_HASH_SPT) {
+		if (prevmode)
+			putchar(separator);
+		fputs("srcport", stdout);
+		prevmode = 1;
+	}
+	if (mode & XT_HASHLIMIT_HASH_DIP) {
+		if (prevmode)
+			putchar(separator);
+		fputs("dstip", stdout);
+		prevmode = 1;
+	}
+	if (mode & XT_HASHLIMIT_HASH_DPT) {
+		if (prevmode)
+			putchar(separator);
+		fputs("dstport", stdout);
+	}
+	putchar(' ');
+}
+
+static void hashlimit_print(const void *ip,
+                            const struct xt_entry_match *match, int numeric)
+{
+	struct xt_hashlimit_info *r = 
+		(struct xt_hashlimit_info *)match->data;
+	fputs("limit: avg ", stdout); print_rate(r->cfg.avg);
+	printf("burst %u ", r->cfg.burst);
+	fputs("mode ", stdout);
+	print_mode(r->cfg.mode, '-');
+	if (r->cfg.size)
+		printf("htable-size %u ", r->cfg.size);
+	if (r->cfg.max)
+		printf("htable-max %u ", r->cfg.max);
+	if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
+		printf("htable-gcinterval %u ", r->cfg.gc_interval);
+	if (r->cfg.expire != XT_HASHLIMIT_EXPIRE)
+		printf("htable-expire %u ", r->cfg.expire);
+}
+
+static void
+hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
+{
+	if (info->cfg.mode & XT_HASHLIMIT_INVERT)
+		fputs("limit: above ", stdout);
+	else
+		fputs("limit: up to ", stdout);
+	print_rate(info->cfg.avg);
+	printf("burst %u ", info->cfg.burst);
+	if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
+	    XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
+		fputs("mode ", stdout);
+		print_mode(info->cfg.mode, '-');
+	}
+	if (info->cfg.size != 0)
+		printf("htable-size %u ", info->cfg.size);
+	if (info->cfg.max != 0)
+		printf("htable-max %u ", info->cfg.max);
+	if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
+		printf("htable-gcinterval %u ", info->cfg.gc_interval);
+	if (info->cfg.expire != XT_HASHLIMIT_EXPIRE)
+		printf("htable-expire %u ", info->cfg.expire);
+
+	if (info->cfg.srcmask != dmask)
+		printf("srcmask %u ", info->cfg.srcmask);
+	if (info->cfg.dstmask != dmask)
+		printf("dstmask %u ", info->cfg.dstmask);
+}
+
+static void
+hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match,
+                   int numeric)
+{
+	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
+
+	hashlimit_mt_print(info, 32);
+}
+
+static void
+hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match,
+                   int numeric)
+{
+	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
+
+	hashlimit_mt_print(info, 128);
+}
+
+static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct xt_hashlimit_info *r = 
+		(struct xt_hashlimit_info *)match->data;
+
+	fputs("--hashlimit ", stdout); print_rate(r->cfg.avg);
+	if (r->cfg.burst != XT_HASHLIMIT_BURST)
+		printf("--hashlimit-burst %u ", r->cfg.burst);
+
+	fputs("--hashlimit-mode ", stdout);
+	print_mode(r->cfg.mode, ',');
+	
+	printf("--hashlimit-name %s ", r->name);
+
+	if (r->cfg.size)
+		printf("--hashlimit-htable-size %u ", r->cfg.size);
+	if (r->cfg.max)
+		printf("--hashlimit-htable-max %u ", r->cfg.max);
+	if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
+		printf("--hashlimit-htable-gcinterval %u ", r->cfg.gc_interval);
+	if (r->cfg.expire != XT_HASHLIMIT_EXPIRE)
+		printf("--hashlimit-htable-expire %u ", r->cfg.expire);
+}
+
+static void
+hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
+{
+	if (info->cfg.mode & XT_HASHLIMIT_INVERT)
+		fputs("--hashlimit-above ", stdout);
+	else
+		fputs("--hashlimit-upto ", stdout);
+	print_rate(info->cfg.avg);
+	if (info->cfg.burst != XT_HASHLIMIT_BURST)
+		printf("--hashlimit-burst %u ", info->cfg.burst);
+
+	if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
+	    XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
+		fputs("--hashlimit-mode ", stdout);
+		print_mode(info->cfg.mode, ',');
+	}
+
+	printf("--hashlimit-name %s ", info->name);
+
+	if (info->cfg.size != 0)
+		printf("--hashlimit-htable-size %u ", info->cfg.size);
+	if (info->cfg.max != 0)
+		printf("--hashlimit-htable-max %u ", info->cfg.max);
+	if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
+		printf("--hashlimit-htable-gcinterval %u ", info->cfg.gc_interval);
+	if (info->cfg.expire != XT_HASHLIMIT_EXPIRE)
+		printf("--hashlimit-htable-expire %u ", info->cfg.expire);
+
+	if (info->cfg.srcmask != dmask)
+		printf("--hashlimit-srcmask %u ", info->cfg.srcmask);
+	if (info->cfg.dstmask != dmask)
+		printf("--hashlimit-dstmask %u ", info->cfg.dstmask);
+}
+
+static void
+hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
+
+	hashlimit_mt_save(info, 32);
+}
+
+static void
+hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
+
+	hashlimit_mt_save(info, 128);
+}
+
+static struct xtables_match hashlimit_match = {
+	.family		= NFPROTO_IPV4,
+	.name		= "hashlimit",
+	.version	= XTABLES_VERSION,
+	.revision	= 0,
+	.size		= XT_ALIGN(sizeof(struct xt_hashlimit_info)),
+	.userspacesize	= offsetof(struct xt_hashlimit_info, hinfo),
+	.help		= hashlimit_help,
+	.init		= hashlimit_init,
+	.parse		= hashlimit_parse,
+	.final_check	= hashlimit_check,
+	.print		= hashlimit_print,
+	.save		= hashlimit_save,
+	.extra_opts	= hashlimit_opts,
+};
+
+static struct xtables_match hashlimit_match6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "hashlimit",
+	.version	= XTABLES_VERSION,
+	.revision	= 0,
+	.size		= XT_ALIGN(sizeof(struct xt_hashlimit_info)),
+	.userspacesize	= offsetof(struct xt_hashlimit_info, hinfo),
+	.help		= hashlimit_help,
+	.init		= hashlimit_init,
+	.parse		= hashlimit_parse,
+	.final_check	= hashlimit_check,
+	.print		= hashlimit_print,
+	.save		= hashlimit_save,
+	.extra_opts	= hashlimit_opts,
+};
+
+static struct xtables_match hashlimit_mt_reg = {
+	.version        = XTABLES_VERSION,
+	.name           = "hashlimit",
+	.revision       = 1,
+	.family         = NFPROTO_IPV4,
+	.size           = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
+	.userspacesize  = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
+	.help           = hashlimit_mt_help,
+	.init           = hashlimit_mt4_init,
+	.parse          = hashlimit_mt4_parse,
+	.final_check	= hashlimit_mt_check,
+	.print          = hashlimit_mt4_print,
+	.save           = hashlimit_mt4_save,
+	.extra_opts     = hashlimit_mt_opts,
+};
+
+static struct xtables_match hashlimit_mt6_reg = {
+	.version        = XTABLES_VERSION,
+	.name           = "hashlimit",
+	.revision       = 1,
+	.family         = NFPROTO_IPV6,
+	.size           = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
+	.userspacesize  = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
+	.help           = hashlimit_mt_help,
+	.init           = hashlimit_mt6_init,
+	.parse          = hashlimit_mt6_parse,
+	.final_check	= hashlimit_mt_check,
+	.print          = hashlimit_mt6_print,
+	.save           = hashlimit_mt6_save,
+	.extra_opts     = hashlimit_mt_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&hashlimit_match);
+	xtables_register_match(&hashlimit_match6);
+	xtables_register_match(&hashlimit_mt_reg);
+	xtables_register_match(&hashlimit_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_hashlimit.man b/ap/app/iptables/extensions/libxt_hashlimit.man
new file mode 100755
index 0000000..9820a92
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_hashlimit.man
@@ -0,0 +1,59 @@
+\fBhashlimit\fR uses hash buckets to express a rate limiting match (like the
+\fBlimit\fR match) for a group of connections using a \fBsingle\fR iptables
+rule. Grouping can be done per-hostgroup (source and/or destination address)
+and/or per-port. It gives you the ability to express "\fIN\fR packets per time
+quantum per group":
+.TP
+matching on source host
+"1000 packets per second for every host in 192.168.0.0/16"
+.TP
+matching on source prot
+"100 packets per second for every service of 192.168.1.1"
+.TP
+matching on subnet
+"10000 packets per minute for every /28 subnet in 10.0.0.0/8"
+.PP
+A hash limit option (\fB\-\-hashlimit\-upto\fP, \fB\-\-hashlimit\-above\fP) and
+\fB\-\-hashlimit\-name\fP are required.
+.TP
+\fB\-\-hashlimit\-upto\fP \fIamount\fP[\fB/second\fP|\fB/minute\fP|\fB/hour\fP|\fB/day\fP]
+Match if the rate is below or equal to \fIamount\fR/quantum. It is specified as
+a number, with an optional time quantum suffix; the default is 3/hour.
+.TP
+\fB\-\-hashlimit\-above\fP \fIamount\fP[\fB/second\fP|\fB/minute\fP|\fB/hour\fP|\fB/day\fP]
+Match if the rate is above \fIamount\fR/quantum.
+.TP
+\fB\-\-hashlimit\-burst\fP \fIamount\fP
+Maximum initial number of packets to match: this number gets recharged by one
+every time the limit specified above is not reached, up to this number; the
+default is 5.
+.TP
+\fB\-\-hashlimit\-mode\fP {\fBsrcip\fP|\fBsrcport\fP|\fBdstip\fP|\fBdstport\fP}\fB,\fP...
+A comma-separated list of objects to take into consideration. If no
+\-\-hashlimit\-mode option is given, hashlimit acts like limit, but at the
+expensive of doing the hash housekeeping.
+.TP
+\fB\-\-hashlimit\-srcmask\fP \fIprefix\fP
+When \-\-hashlimit\-mode srcip is used, all source addresses encountered will be
+grouped according to the given prefix length and the so-created subnet will be
+subject to hashlimit. \fIprefix\fR must be between (inclusive) 0 and 32. Note
+that \-\-hashlimit\-srcmask 0 is basically doing the same thing as not specifying
+srcip for \-\-hashlimit\-mode, but is technically more expensive.
+.TP
+\fB\-\-hashlimit\-dstmask\fP \fIprefix\fP
+Like \-\-hashlimit\-srcmask, but for destination addresses.
+.TP
+\fB\-\-hashlimit\-name\fP \fIfoo\fP
+The name for the /proc/net/ipt_hashlimit/foo entry.
+.TP
+\fB\-\-hashlimit\-htable\-size\fP \fIbuckets\fP
+The number of buckets of the hash table
+.TP
+\fB\-\-hashlimit\-htable\-max\fP \fIentries\fP
+Maximum entries in the hash.
+.TP
+\fB\-\-hashlimit\-htable\-expire\fP \fImsec\fP
+After how many milliseconds do hash entries expire.
+.TP
+\fB\-\-hashlimit\-htable\-gcinterval\fP \fImsec\fP
+How many milliseconds between garbage collection intervals.
diff --git a/ap/app/iptables/extensions/libxt_helper.c b/ap/app/iptables/extensions/libxt_helper.c
new file mode 100755
index 0000000..8378be7
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_helper.c
@@ -0,0 +1,101 @@
+/* Shared library add-on to iptables to add related packet matching support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_helper.h>
+
+static void helper_help(void)
+{
+	printf(
+"helper match options:\n"
+"[!] --helper string        Match helper identified by string\n");
+}
+
+static const struct option helper_opts[] = {
+	{ "helper", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static int
+helper_parse(int c, char **argv, int invert, unsigned int *flags,
+             const void *entry, struct xt_entry_match **match)
+{
+	struct xt_helper_info *info = (struct xt_helper_info *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+					"helper match: Only use --helper ONCE!");
+		xtables_check_inverse(optarg, &invert, &invert, 0);
+		strncpy(info->name, optarg, 29);
+		info->name[29] = '\0';
+		if (invert)
+			info->invert = 1;
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static void helper_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "helper match: You must specify `--helper'");
+}
+
+static void
+helper_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	struct xt_helper_info *info = (struct xt_helper_info *)match->data;
+
+	printf("helper match %s\"%s\" ", info->invert ? "! " : "", info->name);
+}
+
+static void helper_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct xt_helper_info *info = (struct xt_helper_info *)match->data;
+
+	printf("%s--helper ",info->invert ? "! " : "");
+	xtables_save_string(info->name);
+}
+
+static struct xtables_match helper_match = {
+	.family		= NFPROTO_IPV4,
+	.name		= "helper",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_helper_info)),
+	.help		= helper_help,
+	.parse		= helper_parse,
+	.final_check	= helper_check,
+	.print		= helper_print,
+	.save		= helper_save,
+	.extra_opts	= helper_opts,
+};
+
+static struct xtables_match helper_match6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "helper",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_helper_info)),
+	.help		= helper_help,
+	.parse		= helper_parse,
+	.final_check	= helper_check,
+	.print		= helper_print,
+	.save		= helper_save,
+	.extra_opts	= helper_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&helper_match);
+	xtables_register_match(&helper_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_helper.man b/ap/app/iptables/extensions/libxt_helper.man
new file mode 100755
index 0000000..772b135
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_helper.man
@@ -0,0 +1,11 @@
+This module matches packets related to a specific conntrack-helper.
+.TP
+[\fB!\fP] \fB\-\-helper\fP \fIstring\fP
+Matches packets related to the specified conntrack-helper.
+.RS
+.PP
+string can be "ftp" for packets related to a ftp-session on default port.
+For other ports append \-portnr to the value, ie. "ftp\-2121".
+.PP
+Same rules apply for other conntrack-helpers.
+.RE
diff --git a/ap/app/iptables/extensions/libxt_iprange.c b/ap/app/iptables/extensions/libxt_iprange.c
new file mode 100755
index 0000000..bc5b2ae
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_iprange.c
@@ -0,0 +1,397 @@
+/* Shared library add-on to iptables to add IP range matching support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <netinet/in.h>
+#include <xtables.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/xt_iprange.h>
+#include <linux/netfilter_ipv4/ipt_iprange.h>
+
+enum {
+	F_SRCIP = 1 << 0,
+	F_DSTIP = 1 << 1,
+};
+
+static void iprange_mt_help(void)
+{
+	printf(
+"iprange match options:\n"
+"[!] --src-range ip-ip        Match source IP in the specified range\n"
+"[!] --dst-range ip-ip        Match destination IP in the specified range\n");
+}
+
+static const struct option iprange_mt_opts[] = {
+	{.name = "src-range", .has_arg = true, .val = '1'},
+	{.name = "dst-range", .has_arg = true, .val = '2'},
+	{ .name = NULL }
+};
+
+static void
+parse_iprange(char *arg, struct ipt_iprange *range)
+{
+	char *dash;
+	const struct in_addr *ip;
+
+	dash = strchr(arg, '-');
+	if (dash != NULL)
+		*dash = '\0';
+
+	ip = xtables_numeric_to_ipaddr(arg);
+	if (!ip)
+		xtables_error(PARAMETER_PROBLEM, "iprange match: Bad IP address \"%s\"\n",
+			   arg);
+	range->min_ip = ip->s_addr;
+
+	if (dash != NULL) {
+		ip = xtables_numeric_to_ipaddr(dash+1);
+		if (!ip)
+			xtables_error(PARAMETER_PROBLEM, "iprange match: Bad IP address \"%s\"\n",
+				   dash+1);
+		range->max_ip = ip->s_addr;
+	} else {
+		range->max_ip = range->min_ip;
+	}
+}
+
+static int iprange_parse(int c, char **argv, int invert, unsigned int *flags,
+                         const void *entry, struct xt_entry_match **match)
+{
+	struct ipt_iprange_info *info = (struct ipt_iprange_info *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & IPRANGE_SRC)
+			xtables_error(PARAMETER_PROBLEM,
+				   "iprange match: Only use --src-range ONCE!");
+		*flags |= IPRANGE_SRC;
+
+		info->flags |= IPRANGE_SRC;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		if (invert)
+			info->flags |= IPRANGE_SRC_INV;
+		parse_iprange(optarg, &info->src);
+
+		break;
+
+	case '2':
+		if (*flags & IPRANGE_DST)
+			xtables_error(PARAMETER_PROBLEM,
+				   "iprange match: Only use --dst-range ONCE!");
+		*flags |= IPRANGE_DST;
+
+		info->flags |= IPRANGE_DST;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		if (invert)
+			info->flags |= IPRANGE_DST_INV;
+
+		parse_iprange(optarg, &info->dst);
+
+		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static int
+iprange_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
+                  const void *entry, struct xt_entry_match **match)
+{
+	struct xt_iprange_mtinfo *info = (void *)(*match)->data;
+	const struct in_addr *ia;
+	char *end;
+
+	switch (c) {
+	case '1': /* --src-range */
+		end = strchr(optarg, '-');
+		if (end == NULL)
+			xtables_param_act(XTF_BAD_VALUE, "iprange", "--src-range", optarg);
+		*end = '\0';
+		ia = xtables_numeric_to_ipaddr(optarg);
+		if (ia == NULL)
+			xtables_param_act(XTF_BAD_VALUE, "iprange", "--src-range", optarg);
+		memcpy(&info->src_min.in, ia, sizeof(*ia));
+		ia = xtables_numeric_to_ipaddr(end+1);
+		if (ia == NULL)
+			xtables_param_act(XTF_BAD_VALUE, "iprange", "--src-range", end + 1);
+		memcpy(&info->src_max.in, ia, sizeof(*ia));
+		info->flags |= IPRANGE_SRC;
+		if (invert)
+			info->flags |= IPRANGE_SRC_INV;
+		*flags |= F_SRCIP;
+		return true;
+
+	case '2': /* --dst-range */
+		end = strchr(optarg, '-');
+		if (end == NULL)
+			xtables_param_act(XTF_BAD_VALUE, "iprange", "--dst-range", optarg);
+		*end = '\0';
+		ia = xtables_numeric_to_ipaddr(optarg);
+		if (ia == NULL)
+			xtables_param_act(XTF_BAD_VALUE, "iprange", "--dst-range", optarg);
+		memcpy(&info->dst_min.in, ia, sizeof(*ia));
+		ia = xtables_numeric_to_ipaddr(end + 1);
+		if (ia == NULL)
+			xtables_param_act(XTF_BAD_VALUE, "iprange", "--dst-range", end + 1);
+		memcpy(&info->dst_max.in, ia, sizeof(*ia));
+		info->flags |= IPRANGE_DST;
+		if (invert)
+			info->flags |= IPRANGE_DST_INV;
+		*flags |= F_DSTIP;
+		return true;
+	}
+	return false;
+}
+
+static int
+iprange_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
+                  const void *entry, struct xt_entry_match **match)
+{
+	struct xt_iprange_mtinfo *info = (void *)(*match)->data;
+	const struct in6_addr *ia;
+	char *end;
+
+	switch (c) {
+	case '1': /* --src-range */
+		end = strchr(optarg, '-');
+		if (end == NULL)
+			xtables_param_act(XTF_BAD_VALUE, "iprange", "--src-range", optarg);
+		*end = '\0';
+		ia = xtables_numeric_to_ip6addr(optarg);
+		if (ia == NULL)
+			xtables_param_act(XTF_BAD_VALUE, "iprange", "--src-range", optarg);
+		memcpy(&info->src_min.in, ia, sizeof(*ia));
+		ia = xtables_numeric_to_ip6addr(end+1);
+		if (ia == NULL)
+			xtables_param_act(XTF_BAD_VALUE, "iprange", "--src-range", end + 1);
+		memcpy(&info->src_max.in, ia, sizeof(*ia));
+		info->flags |= IPRANGE_SRC;
+		if (invert)
+			info->flags |= IPRANGE_SRC_INV;
+		*flags |= F_SRCIP;
+		return true;
+
+	case '2': /* --dst-range */
+		end = strchr(optarg, '-');
+		if (end == NULL)
+			xtables_param_act(XTF_BAD_VALUE, "iprange", "--dst-range", optarg);
+		*end = '\0';
+		ia = xtables_numeric_to_ip6addr(optarg);
+		if (ia == NULL)
+			xtables_param_act(XTF_BAD_VALUE, "iprange", "--dst-range", optarg);
+		memcpy(&info->dst_min.in, ia, sizeof(*ia));
+		ia = xtables_numeric_to_ip6addr(end + 1);
+		if (ia == NULL)
+			xtables_param_act(XTF_BAD_VALUE, "iprange", "--dst-range", end + 1);
+		memcpy(&info->dst_max.in, ia, sizeof(*ia));
+		info->flags |= IPRANGE_DST;
+		if (invert)
+			info->flags |= IPRANGE_DST_INV;
+		*flags |= F_DSTIP;
+		return true;
+	}
+	return false;
+}
+
+static void iprange_mt_check(unsigned int flags)
+{
+	if (flags == 0)
+		xtables_error(PARAMETER_PROBLEM,
+			   "iprange match: You must specify `--src-range' or `--dst-range'");
+}
+
+static void
+print_iprange(const struct ipt_iprange *range)
+{
+	const unsigned char *byte_min, *byte_max;
+
+	byte_min = (const unsigned char *)&range->min_ip;
+	byte_max = (const unsigned char *)&range->max_ip;
+	printf("%u.%u.%u.%u-%u.%u.%u.%u ",
+		byte_min[0], byte_min[1], byte_min[2], byte_min[3],
+		byte_max[0], byte_max[1], byte_max[2], byte_max[3]);
+}
+
+static void iprange_print(const void *ip, const struct xt_entry_match *match,
+                          int numeric)
+{
+	const struct ipt_iprange_info *info = (const void *)match->data;
+
+	if (info->flags & IPRANGE_SRC) {
+		printf("source IP range ");
+		if (info->flags & IPRANGE_SRC_INV)
+			printf("! ");
+		print_iprange(&info->src);
+	}
+	if (info->flags & IPRANGE_DST) {
+		printf("destination IP range ");
+		if (info->flags & IPRANGE_DST_INV)
+			printf("! ");
+		print_iprange(&info->dst);
+	}
+}
+
+static void
+iprange_mt4_print(const void *ip, const struct xt_entry_match *match,
+                  int numeric)
+{
+	const struct xt_iprange_mtinfo *info = (const void *)match->data;
+
+	if (info->flags & IPRANGE_SRC) {
+		printf("source IP range ");
+		if (info->flags & IPRANGE_SRC_INV)
+			printf("! ");
+		/*
+		 * ipaddr_to_numeric() uses a static buffer, so cannot
+		 * combine the printf() calls.
+		 */
+		printf("%s", xtables_ipaddr_to_numeric(&info->src_min.in));
+		printf("-%s ", xtables_ipaddr_to_numeric(&info->src_max.in));
+	}
+	if (info->flags & IPRANGE_DST) {
+		printf("destination IP range ");
+		if (info->flags & IPRANGE_DST_INV)
+			printf("! ");
+		printf("%s", xtables_ipaddr_to_numeric(&info->dst_min.in));
+		printf("-%s ", xtables_ipaddr_to_numeric(&info->dst_max.in));
+	}
+}
+
+static void
+iprange_mt6_print(const void *ip, const struct xt_entry_match *match,
+                  int numeric)
+{
+	const struct xt_iprange_mtinfo *info = (const void *)match->data;
+
+	if (info->flags & IPRANGE_SRC) {
+		printf("source IP range ");
+		if (info->flags & IPRANGE_SRC_INV)
+			printf("! ");
+		/*
+		 * ipaddr_to_numeric() uses a static buffer, so cannot
+		 * combine the printf() calls.
+		 */
+		printf("%s", xtables_ip6addr_to_numeric(&info->src_min.in6));
+		printf("-%s ", xtables_ip6addr_to_numeric(&info->src_max.in6));
+	}
+	if (info->flags & IPRANGE_DST) {
+		printf("destination IP range ");
+		if (info->flags & IPRANGE_DST_INV)
+			printf("! ");
+		printf("%s", xtables_ip6addr_to_numeric(&info->dst_min.in6));
+		printf("-%s ", xtables_ip6addr_to_numeric(&info->dst_max.in6));
+	}
+}
+
+static void iprange_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ipt_iprange_info *info = (const void *)match->data;
+
+	if (info->flags & IPRANGE_SRC) {
+		if (info->flags & IPRANGE_SRC_INV)
+			printf("! ");
+		printf("--src-range ");
+		print_iprange(&info->src);
+		if (info->flags & IPRANGE_DST)
+			fputc(' ', stdout);
+	}
+	if (info->flags & IPRANGE_DST) {
+		if (info->flags & IPRANGE_DST_INV)
+			printf("! ");
+		printf("--dst-range ");
+		print_iprange(&info->dst);
+	}
+}
+
+static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_iprange_mtinfo *info = (const void *)match->data;
+
+	if (info->flags & IPRANGE_SRC) {
+		if (info->flags & IPRANGE_SRC_INV)
+			printf("! ");
+		printf("--src-range %s", xtables_ipaddr_to_numeric(&info->src_min.in));
+		printf("-%s ", xtables_ipaddr_to_numeric(&info->src_max.in));
+	}
+	if (info->flags & IPRANGE_DST) {
+		if (info->flags & IPRANGE_DST_INV)
+			printf("! ");
+		printf("--dst-range %s", xtables_ipaddr_to_numeric(&info->dst_min.in));
+		printf("-%s ", xtables_ipaddr_to_numeric(&info->dst_max.in));
+	}
+}
+
+static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_iprange_mtinfo *info = (const void *)match->data;
+
+	if (info->flags & IPRANGE_SRC) {
+		if (info->flags & IPRANGE_SRC_INV)
+			printf("! ");
+		printf("--src-range %s", xtables_ip6addr_to_numeric(&info->src_min.in6));
+		printf("-%s ", xtables_ip6addr_to_numeric(&info->src_max.in6));
+	}
+	if (info->flags & IPRANGE_DST) {
+		if (info->flags & IPRANGE_DST_INV)
+			printf("! ");
+		printf("--dst-range %s", xtables_ip6addr_to_numeric(&info->dst_min.in6));
+		printf("-%s ", xtables_ip6addr_to_numeric(&info->dst_max.in6));
+	}
+}
+
+static struct xtables_match iprange_match = {
+	.version       = XTABLES_VERSION,
+	.name          = "iprange",
+	.revision      = 0,
+	.family        = NFPROTO_IPV4,
+	.size          = XT_ALIGN(sizeof(struct ipt_iprange_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)),
+	.help          = iprange_mt_help,
+	.parse         = iprange_parse,
+	.final_check   = iprange_mt_check,
+	.print         = iprange_print,
+	.save          = iprange_save,
+	.extra_opts    = iprange_mt_opts,
+};
+
+static struct xtables_match iprange_mt_reg = {
+	.version        = XTABLES_VERSION,
+	.name           = "iprange",
+	.revision       = 1,
+	.family         = NFPROTO_IPV4,
+	.size           = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
+	.userspacesize  = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
+	.help           = iprange_mt_help,
+	.parse          = iprange_mt4_parse,
+	.final_check    = iprange_mt_check,
+	.print          = iprange_mt4_print,
+	.save           = iprange_mt4_save,
+	.extra_opts     = iprange_mt_opts,
+};
+
+static struct xtables_match iprange_mt6_reg = {
+	.version        = XTABLES_VERSION,
+	.name           = "iprange",
+	.revision       = 1,
+	.family         = NFPROTO_IPV6,
+	.size           = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
+	.userspacesize  = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
+	.help           = iprange_mt_help,
+	.parse          = iprange_mt6_parse,
+	.final_check    = iprange_mt_check,
+	.print          = iprange_mt6_print,
+	.save           = iprange_mt6_save,
+	.extra_opts     = iprange_mt_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&iprange_match);
+	xtables_register_match(&iprange_mt_reg);
+	xtables_register_match(&iprange_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_iprange.man b/ap/app/iptables/extensions/libxt_iprange.man
new file mode 100755
index 0000000..9f65de4
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_iprange.man
@@ -0,0 +1,7 @@
+This matches on a given arbitrary range of IP addresses.
+.TP
+[\fB!\fR] \fB\-\-src\-range\fP \fIfrom\fP[\fB\-\fP\fIto\fP]
+Match source IP in the specified range.
+.TP
+[\fB!\fR] \fB\-\-dst\-range\fP \fIfrom\fP[\fB\-\fP\fIto\fP]
+Match destination IP in the specified range.
diff --git a/ap/app/iptables/extensions/libxt_length.c b/ap/app/iptables/extensions/libxt_length.c
new file mode 100755
index 0000000..7bb31a8
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_length.c
@@ -0,0 +1,133 @@
+/* Shared library add-on to iptables to add packet length matching support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_length.h>
+
+static void length_help(void)
+{
+	printf(
+"length match options:\n"
+"[!] --length length[:length]    Match packet length against value or range\n"
+"                                of values (inclusive)\n");
+}
+  
+static const struct option length_opts[] = {
+	{ "length", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static u_int16_t
+parse_length(const char *s)
+{
+	unsigned int len;
+	
+	if (!xtables_strtoui(s, NULL, &len, 0, UINT32_MAX))
+		xtables_error(PARAMETER_PROBLEM, "length invalid: \"%s\"\n", s);
+	else
+		return len;
+}
+
+/* If a single value is provided, min and max are both set to the value */
+static void
+parse_lengths(const char *s, struct xt_length_info *info)
+{
+	char *buffer;
+	char *cp;
+
+	buffer = strdup(s);
+	if ((cp = strchr(buffer, ':')) == NULL)
+		info->min = info->max = parse_length(buffer);
+	else {
+		*cp = '\0';
+		cp++;
+
+		info->min = buffer[0] ? parse_length(buffer) : 0;
+		info->max = cp[0] ? parse_length(cp) : 0xFFFF;
+	}
+	free(buffer);
+	
+	if (info->min > info->max)
+		xtables_error(PARAMETER_PROBLEM,
+		           "length min. range value `%u' greater than max. "
+		           "range value `%u'", info->min, info->max);
+	
+}
+
+static int
+length_parse(int c, char **argv, int invert, unsigned int *flags,
+             const void *entry, struct xt_entry_match **match)
+{
+	struct xt_length_info *info = (struct xt_length_info *)(*match)->data;
+
+	switch (c) {
+		case '1':
+			if (*flags)
+				xtables_error(PARAMETER_PROBLEM,
+				           "length: `--length' may only be "
+				           "specified once");
+			xtables_check_inverse(optarg, &invert, &optind, 0);
+			parse_lengths(argv[optind-1], info);
+			if (invert)
+				info->invert = 1;
+			*flags = 1;
+			break;
+			
+		default:
+			return 0;
+	}
+	return 1;
+}
+
+static void length_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "length: You must specify `--length'");
+}
+
+static void
+length_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_length_info *info = (void *)match->data;
+
+	printf("length %s", info->invert ? "!" : "");
+	if (info->min == info->max)
+		printf("%u ", info->min);
+	else
+		printf("%u:%u ", info->min, info->max);
+}
+
+static void length_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_length_info *info = (void *)match->data;
+
+	printf("%s--length ", info->invert ? "! " : "");
+	if (info->min == info->max)
+		printf("%u ", info->min);
+	else
+		printf("%u:%u ", info->min, info->max);
+}
+
+static struct xtables_match length_match = {
+	.family		= AF_UNSPEC,
+	.name		= "length",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_length_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_length_info)),
+	.help		= length_help,
+	.parse		= length_parse,
+	.final_check	= length_check,
+	.print		= length_print,
+	.save		= length_save,
+	.extra_opts	= length_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&length_match);
+}
diff --git a/ap/app/iptables/extensions/libxt_length.man b/ap/app/iptables/extensions/libxt_length.man
new file mode 100755
index 0000000..e324e03
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_length.man
@@ -0,0 +1,5 @@
+This module matches the length of the layer-3 payload (e.g. layer-4 packet)
+f a packet against a specific value
+or range of values.
+.TP
+[\fB!\fP] \fB\-\-length\fP \fIlength\fP[\fB:\fP\fIlength\fP]
diff --git a/ap/app/iptables/extensions/libxt_limit.c b/ap/app/iptables/extensions/libxt_limit.c
new file mode 100755
index 0000000..f785d2d
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_limit.c
@@ -0,0 +1,178 @@
+/* Shared library add-on to iptables to add limit support.
+ *
+ * Jérôme de Vivie   <devivie@info.enserb.u-bordeaux.fr>
+ * Hervé Eychenne    <rv@wallfire.org>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <stddef.h>
+#include <linux/netfilter/x_tables.h>
+/* For 64bit kernel / 32bit userspace */
+#include <linux/netfilter/xt_limit.h>
+
+#define XT_LIMIT_AVG	"3/hour"
+#define XT_LIMIT_BURST	5
+
+static void limit_help(void)
+{
+	printf(
+"limit match options:\n"
+"--limit avg			max average match rate: default "XT_LIMIT_AVG"\n"
+"                                [Packets per second unless followed by \n"
+"                                /sec /minute /hour /day postfixes]\n"
+"--limit-burst number		number to match in a burst, default %u\n",
+XT_LIMIT_BURST);
+}
+
+static const struct option limit_opts[] = {
+	{ "limit", 1, NULL, '%' },
+	{ "limit-burst", 1, NULL, '$' },
+	{ .name = NULL }
+};
+
+static
+int parse_rate(const char *rate, u_int32_t *val)
+{
+	const char *delim;
+	u_int32_t r;
+	u_int32_t mult = 1;  /* Seconds by default. */
+
+	delim = strchr(rate, '/');
+	if (delim) {
+		if (strlen(delim+1) == 0)
+			return 0;
+
+		if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
+			mult = 1;
+		else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
+			mult = 60;
+		else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
+			mult = 60*60;
+		else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
+			mult = 24*60*60;
+		else
+			return 0;
+	}
+	r = atoi(rate);
+	if (!r)
+		return 0;
+
+	/* This would get mapped to infinite (1/day is minimum they
+           can specify, so we're ok at that end). */
+	if (r / mult > XT_LIMIT_SCALE)
+		xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
+
+	*val = XT_LIMIT_SCALE * mult / r;
+	return 1;
+}
+
+static void limit_init(struct xt_entry_match *m)
+{
+	struct xt_rateinfo *r = (struct xt_rateinfo *)m->data;
+
+	parse_rate(XT_LIMIT_AVG, &r->avg);
+	r->burst = XT_LIMIT_BURST;
+
+}
+
+/* FIXME: handle overflow:
+	if (r->avg*r->burst/r->burst != r->avg)
+		xtables_error(PARAMETER_PROBLEM,
+			   "Sorry: burst too large for that avg rate.\n");
+*/
+
+static int
+limit_parse(int c, char **argv, int invert, unsigned int *flags,
+            const void *entry, struct xt_entry_match **match)
+{
+	struct xt_rateinfo *r = (struct xt_rateinfo *)(*match)->data;
+	unsigned int num;
+
+	switch(c) {
+	case '%':
+		if (xtables_check_inverse(argv[optind-1], &invert, &optind, 0)) break;
+		if (!parse_rate(optarg, &r->avg))
+			xtables_error(PARAMETER_PROBLEM,
+				   "bad rate `%s'", optarg);
+		break;
+
+	case '$':
+		if (xtables_check_inverse(argv[optind-1], &invert, &optind, 0)) break;
+		if (!xtables_strtoui(optarg, NULL, &num, 0, 10000))
+			xtables_error(PARAMETER_PROBLEM,
+				   "bad --limit-burst `%s'", optarg);
+		r->burst = num;
+		break;
+
+	default:
+		return 0;
+	}
+
+	if (invert)
+		xtables_error(PARAMETER_PROBLEM,
+			   "limit does not support invert");
+
+	return 1;
+}
+
+static const struct rates
+{
+	const char *name;
+	u_int32_t mult;
+} rates[] = { { "day", XT_LIMIT_SCALE*24*60*60 },
+	      { "hour", XT_LIMIT_SCALE*60*60 },
+	      { "min", XT_LIMIT_SCALE*60 },
+	      { "sec", XT_LIMIT_SCALE } };
+
+static void print_rate(u_int32_t period)
+{
+	unsigned int i;
+
+	for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) {
+		if (period > rates[i].mult
+            || rates[i].mult/period < rates[i].mult%period)
+			break;
+	}
+
+	printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name);
+}
+
+static void
+limit_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	struct xt_rateinfo *r = (struct xt_rateinfo *)match->data;
+	printf("limit: avg "); print_rate(r->avg);
+	printf("burst %u ", r->burst);
+}
+
+static void limit_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct xt_rateinfo *r = (struct xt_rateinfo *)match->data;
+
+	printf("--limit "); print_rate(r->avg);
+	if (r->burst != XT_LIMIT_BURST)
+		printf("--limit-burst %u ", r->burst);
+}
+
+static struct xtables_match limit_match = {
+	.family		= AF_UNSPEC,
+	.name		= "limit",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_rateinfo)),
+	.userspacesize	= offsetof(struct xt_rateinfo, prev),
+	.help		= limit_help,
+	.init		= limit_init,
+	.parse		= limit_parse,
+	.print		= limit_print,
+	.save		= limit_save,
+	.extra_opts	= limit_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&limit_match);
+}
diff --git a/ap/app/iptables/extensions/libxt_limit.man b/ap/app/iptables/extensions/libxt_limit.man
new file mode 100755
index 0000000..c00e1d9
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_limit.man
@@ -0,0 +1,15 @@
+This module matches at a limited rate using a token bucket filter.
+A rule using this extension will match until this limit is reached
+(unless the `!' flag is used).  It can be used in combination with the
+.B LOG
+target to give limited logging, for example.
+.TP
+[\fB!\fP] \fB\-\-limit\fP \fIrate\fP[\fB/second\fP|\fB/minute\fP|\fB/hour\fP|\fB/day\fP]
+Maximum average matching rate: specified as a number, with an optional
+`/second', `/minute', `/hour', or `/day' suffix; the default is
+3/hour.
+.TP
+\fB\-\-limit\-burst\fP \fInumber\fP
+Maximum initial number of packets to match: this number gets
+recharged by one every time the limit specified above is not reached,
+up to this number; the default is 5.
diff --git a/ap/app/iptables/extensions/libxt_mac.c b/ap/app/iptables/extensions/libxt_mac.c
new file mode 100755
index 0000000..a57e341
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_mac.c
@@ -0,0 +1,146 @@
+/* Shared library add-on to iptables to add MAC address support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#if defined(__GLIBC__) && __GLIBC__ == 2
+#include <net/ethernet.h>
+#else
+#include <linux/if_ether.h>
+#endif
+#include <xtables.h>
+#include <linux/netfilter/xt_mac.h>
+
+static void mac_help(void)
+{
+	printf(
+"mac match options:\n"
+"[!] --mac-source XX:XX:XX:XX:XX:XX\n"
+"				Match source MAC address\n");
+}
+
+static const struct option mac_opts[] = {
+	{ "mac-source", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static void
+parse_mac(const char *mac, struct xt_mac_info *info)
+{
+	unsigned int i = 0;
+
+	if (strlen(mac) != ETH_ALEN*3-1)
+		xtables_error(PARAMETER_PROBLEM, "Bad mac address \"%s\"", mac);
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		long number;
+		char *end;
+
+		number = strtol(mac + i*3, &end, 16);
+
+		if (end == mac + i*3 + 2
+		    && number >= 0
+		    && number <= 255)
+			info->srcaddr[i] = number;
+		else
+			xtables_error(PARAMETER_PROBLEM,
+				   "Bad mac address `%s'", mac);
+	}
+}
+
+static int
+mac_parse(int c, char **argv, int invert, unsigned int *flags,
+          const void *entry, struct xt_entry_match **match)
+{
+	struct xt_mac_info *macinfo = (struct xt_mac_info *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_mac(argv[optind-1], macinfo);
+		if (invert)
+			macinfo->invert = 1;
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void print_mac(const unsigned char macaddress[ETH_ALEN])
+{
+	unsigned int i;
+
+	printf("%02X", macaddress[0]);
+	for (i = 1; i < ETH_ALEN; i++)
+		printf(":%02X", macaddress[i]);
+	printf(" ");
+}
+
+static void mac_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "You must specify `--mac-source'");
+}
+
+static void
+mac_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_mac_info *info = (void *)match->data;
+	printf("MAC ");
+
+	if (info->invert)
+		printf("! ");
+	
+	print_mac(info->srcaddr);
+}
+
+static void mac_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_mac_info *info = (void *)match->data;
+
+	if (info->invert)
+		printf("! ");
+
+	printf("--mac-source ");
+	print_mac(info->srcaddr);
+}
+
+static struct xtables_match mac_match = {
+	.family		= NFPROTO_IPV4,
+ 	.name		= "mac",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_mac_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_mac_info)),
+	.help		= mac_help,
+	.parse		= mac_parse,
+	.final_check	= mac_check,
+	.print		= mac_print,
+	.save		= mac_save,
+	.extra_opts	= mac_opts,
+};
+
+static struct xtables_match mac_match6 = {
+	.family		= NFPROTO_IPV6,
+ 	.name		= "mac",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_mac_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_mac_info)),
+	.help		= mac_help,
+	.parse		= mac_parse,
+	.final_check	= mac_check,
+	.print		= mac_print,
+	.save		= mac_save,
+	.extra_opts	= mac_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&mac_match);
+	xtables_register_match(&mac_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_mac.man b/ap/app/iptables/extensions/libxt_mac.man
new file mode 100755
index 0000000..66072a2
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_mac.man
@@ -0,0 +1,10 @@
+.TP
+[\fB!\fP] \fB\-\-mac\-source\fP \fIaddress\fP
+Match source MAC address.  It must be of the form XX:XX:XX:XX:XX:XX.
+Note that this only makes sense for packets coming from an Ethernet device
+and entering the
+.BR PREROUTING ,
+.B FORWARD
+or
+.B INPUT
+chains.
diff --git a/ap/app/iptables/extensions/libxt_mark.c b/ap/app/iptables/extensions/libxt_mark.c
new file mode 100755
index 0000000..ceca995
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_mark.c
@@ -0,0 +1,180 @@
+/* Shared library add-on to iptables to add NFMARK matching support. */
+#include <stdbool.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_mark.h>
+
+enum {
+	F_MARK = 1 << 0,
+};
+
+static void mark_mt_help(void)
+{
+	printf(
+"mark match options:\n"
+"[!] --mark value[/mask]    Match nfmark value with optional mask\n");
+}
+
+static const struct option mark_mt_opts[] = {
+	{.name = "mark", .has_arg = true, .val = '1'},
+	{ .name = NULL }
+};
+
+static int mark_mt_parse(int c, char **argv, int invert, unsigned int *flags,
+                         const void *entry, struct xt_entry_match **match)
+{
+	struct xt_mark_mtinfo1 *info = (void *)(*match)->data;
+	unsigned int mark, mask = UINT32_MAX;
+	char *end;
+
+	switch (c) {
+	case '1': /* --mark */
+		xtables_param_act(XTF_ONLY_ONCE, "mark", "--mark", *flags & F_MARK);
+		if (!xtables_strtoui(optarg, &end, &mark, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "mark", "--mark", optarg);
+		if (*end == '/')
+			if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX))
+				xtables_param_act(XTF_BAD_VALUE, "mark", "--mark", optarg);
+		if (*end != '\0')
+			xtables_param_act(XTF_BAD_VALUE, "mark", "--mark", optarg);
+
+		if (invert)
+			info->invert = true;
+		info->mark = mark;
+		info->mask = mask;
+		*flags    |= F_MARK;
+		return true;
+	}
+	return false;
+}
+
+static int
+mark_parse(int c, char **argv, int invert, unsigned int *flags,
+           const void *entry, struct xt_entry_match **match)
+{
+	struct xt_mark_info *markinfo = (struct xt_mark_info *)(*match)->data;
+
+	switch (c) {
+		char *end;
+	case '1':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		markinfo->mark = strtoul(optarg, &end, 0);
+		if (*end == '/') {
+			markinfo->mask = strtoul(end+1, &end, 0);
+		} else
+			markinfo->mask = 0xffffffff;
+		if (*end != '\0' || end == optarg)
+			xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg);
+		if (invert)
+			markinfo->invert = 1;
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static void print_mark(unsigned int mark, unsigned int mask)
+{
+	if (mask != 0xffffffffU)
+		printf("0x%x/0x%x ", mark, mask);
+	else
+		printf("0x%x ", mark);
+}
+
+static void mark_mt_check(unsigned int flags)
+{
+	if (flags == 0)
+		xtables_error(PARAMETER_PROBLEM,
+			   "mark match: The --mark option is required");
+}
+
+static void
+mark_mt_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_mark_mtinfo1 *info = (const void *)match->data;
+
+	printf("mark match ");
+	if (info->invert)
+		printf("!");
+	print_mark(info->mark, info->mask);
+}
+
+static void
+mark_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	struct xt_mark_info *info = (struct xt_mark_info *)match->data;
+
+	printf("MARK match ");
+
+	if (info->invert)
+		printf("!");
+	
+	print_mark(info->mark, info->mask);
+}
+
+static void mark_mt_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_mark_mtinfo1 *info = (const void *)match->data;
+
+	if (info->invert)
+		printf("! ");
+
+	printf("--mark ");
+	print_mark(info->mark, info->mask);
+}
+
+static void
+mark_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct xt_mark_info *info = (struct xt_mark_info *)match->data;
+
+	if (info->invert)
+		printf("! ");
+	
+	printf("--mark ");
+	print_mark(info->mark, info->mask);
+}
+
+static struct xtables_match mark_match = {
+	.family		= AF_UNSPEC,
+	.name		= "mark",
+	.revision	= 0,
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_mark_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_mark_info)),
+	.help		= mark_mt_help,
+	.parse		= mark_parse,
+	.final_check	= mark_mt_check,
+	.print		= mark_print,
+	.save		= mark_save,
+	.extra_opts	= mark_mt_opts,
+};
+
+static struct xtables_match mark_mt_reg = {
+	.version        = XTABLES_VERSION,
+	.name           = "mark",
+	.revision       = 1,
+	.family         = AF_UNSPEC,
+	.size           = XT_ALIGN(sizeof(struct xt_mark_mtinfo1)),
+	.userspacesize  = XT_ALIGN(sizeof(struct xt_mark_mtinfo1)),
+	.help           = mark_mt_help,
+	.parse          = mark_mt_parse,
+	.final_check    = mark_mt_check,
+	.print          = mark_mt_print,
+	.save           = mark_mt_save,
+	.extra_opts     = mark_mt_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&mark_match);
+	xtables_register_match(&mark_mt_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_mark.man b/ap/app/iptables/extensions/libxt_mark.man
new file mode 100755
index 0000000..264b17d
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_mark.man
@@ -0,0 +1,9 @@
+This module matches the netfilter mark field associated with a packet
+(which can be set using the
+.B MARK
+target below).
+.TP
+[\fB!\fP] \fB\-\-mark\fP \fIvalue\fP[\fB/\fP\fImask\fP]
+Matches packets with the given unsigned mark value (if a \fImask\fP is
+specified, this is logically ANDed with the \fImask\fP before the
+comparison).
diff --git a/ap/app/iptables/extensions/libxt_multiport.c b/ap/app/iptables/extensions/libxt_multiport.c
new file mode 100755
index 0000000..c3c8bb9
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_multiport.c
@@ -0,0 +1,579 @@
+/* Shared library add-on to iptables to add multiple TCP port support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <libiptc/libiptc.h>
+#include <libiptc/libip6tc.h>
+#include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/xt_multiport.h>
+
+/* Function which prints out usage message. */
+static void multiport_help(void)
+{
+	printf(
+"multiport match options:\n"
+" --source-ports port[,port,port...]\n"
+" --sports ...\n"
+"				match source port(s)\n"
+" --destination-ports port[,port,port...]\n"
+" --dports ...\n"
+"				match destination port(s)\n"
+" --ports port[,port,port]\n"
+"				match both source and destination port(s)\n"
+" NOTE: this kernel does not support port ranges in multiport.\n");
+}
+
+static void multiport_help_v1(void)
+{
+	printf(
+"multiport match options:\n"
+"[!] --source-ports port[,port:port,port...]\n"
+" --sports ...\n"
+"				match source port(s)\n"
+"[!] --destination-ports port[,port:port,port...]\n"
+" --dports ...\n"
+"				match destination port(s)\n"
+"[!] --ports port[,port:port,port]\n"
+"				match both source and destination port(s)\n");
+}
+
+static const struct option multiport_opts[] = {
+	{ "source-ports", 1, NULL, '1' },
+	{ "sports", 1, NULL, '1' }, /* synonym */
+	{ "destination-ports", 1, NULL, '2' },
+	{ "dports", 1, NULL, '2' }, /* synonym */
+	{ "ports", 1, NULL, '3' },
+	{ .name = NULL }
+};
+
+static char *
+proto_to_name(u_int8_t proto)
+{
+	switch (proto) {
+	case IPPROTO_TCP:
+		return "tcp";
+	case IPPROTO_UDP:
+		return "udp";
+	case IPPROTO_UDPLITE:
+		return "udplite";
+	case IPPROTO_SCTP:
+		return "sctp";
+	case IPPROTO_DCCP:
+		return "dccp";
+	default:
+		return NULL;
+	}
+}
+
+static unsigned int
+parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto)
+{
+	char *buffer, *cp, *next;
+	unsigned int i;
+
+	buffer = strdup(portstring);
+	if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
+
+	for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next,i++)
+	{
+		next=strchr(cp, ',');
+		if (next) *next++='\0';
+		ports[i] = xtables_parse_port(cp, proto);
+	}
+	if (cp) xtables_error(PARAMETER_PROBLEM, "too many ports specified");
+	free(buffer);
+	return i;
+}
+
+static void
+parse_multi_ports_v1(const char *portstring, 
+		     struct xt_multiport_v1 *multiinfo,
+		     const char *proto)
+{
+	char *buffer, *cp, *next, *range;
+	unsigned int i;
+	u_int16_t m;
+
+	buffer = strdup(portstring);
+	if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
+
+	for (i=0; i<XT_MULTI_PORTS; i++)
+		multiinfo->pflags[i] = 0;
+ 
+	for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next, i++) {
+		next=strchr(cp, ',');
+ 		if (next) *next++='\0';
+		range = strchr(cp, ':');
+		if (range) {
+			if (i == XT_MULTI_PORTS-1)
+				xtables_error(PARAMETER_PROBLEM,
+					   "too many ports specified");
+			*range++ = '\0';
+		}
+		multiinfo->ports[i] = xtables_parse_port(cp, proto);
+		if (range) {
+			multiinfo->pflags[i] = 1;
+			multiinfo->ports[++i] = xtables_parse_port(range, proto);
+			if (multiinfo->ports[i-1] >= multiinfo->ports[i])
+				xtables_error(PARAMETER_PROBLEM,
+					   "invalid portrange specified");
+			m <<= 1;
+		}
+ 	}
+	multiinfo->count = i;
+	if (cp) xtables_error(PARAMETER_PROBLEM, "too many ports specified");
+ 	free(buffer);
+}
+
+static const char *
+check_proto(u_int16_t pnum, u_int8_t invflags)
+{
+	char *proto;
+
+	if (invflags & XT_INV_PROTO)
+		xtables_error(PARAMETER_PROBLEM,
+			   "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
+
+	if ((proto = proto_to_name(pnum)) != NULL)
+		return proto;
+	else if (!pnum)
+		xtables_error(PARAMETER_PROBLEM,
+			   "multiport needs `-p tcp', `-p udp', `-p udplite', "
+			   "`-p sctp' or `-p dccp'");
+	else
+		xtables_error(PARAMETER_PROBLEM,
+			   "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
+}
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int
+__multiport_parse(int c, char **argv, int invert, unsigned int *flags,
+                  struct xt_entry_match **match, u_int16_t pnum,
+                  u_int8_t invflags)
+{
+	const char *proto;
+	struct xt_multiport *multiinfo
+		= (struct xt_multiport *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		xtables_check_inverse(argv[optind-1], &invert, &optind, 0);
+		proto = check_proto(pnum, invflags);
+		multiinfo->count = parse_multi_ports(argv[optind-1],
+						     multiinfo->ports, proto);
+		multiinfo->flags = XT_MULTIPORT_SOURCE;
+		break;
+
+	case '2':
+		xtables_check_inverse(argv[optind-1], &invert, &optind, 0);
+		proto = check_proto(pnum, invflags);
+		multiinfo->count = parse_multi_ports(argv[optind-1],
+						     multiinfo->ports, proto);
+		multiinfo->flags = XT_MULTIPORT_DESTINATION;
+		break;
+
+	case '3':
+		xtables_check_inverse(argv[optind-1], &invert, &optind, 0);
+		proto = check_proto(pnum, invflags);
+		multiinfo->count = parse_multi_ports(argv[optind-1],
+						     multiinfo->ports, proto);
+		multiinfo->flags = XT_MULTIPORT_EITHER;
+		break;
+
+	default:
+		return 0;
+	}
+
+	if (invert)
+		xtables_error(PARAMETER_PROBLEM,
+			   "multiport does not support invert");
+
+	if (*flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "multiport can only have one option");
+	*flags = 1;
+	return 1;
+}
+
+static int
+multiport_parse(int c, char **argv, int invert, unsigned int *flags,
+                const void *e, struct xt_entry_match **match)
+{
+	const struct ipt_entry *entry = e;
+	return __multiport_parse(c, argv, invert, flags, match,
+	       entry->ip.proto, entry->ip.invflags);
+}
+
+static int
+multiport_parse6(int c, char **argv, int invert, unsigned int *flags,
+                 const void *e, struct xt_entry_match **match)
+{
+	const struct ip6t_entry *entry = (const struct ip6t_entry *)e;
+	return __multiport_parse(c, argv, invert, flags, match,
+	       entry->ipv6.proto, entry->ipv6.invflags);
+}
+
+static int
+__multiport_parse_v1(int c, char **argv, int invert, unsigned int *flags,
+                     struct xt_entry_match **match, u_int16_t pnum,
+                     u_int8_t invflags)
+{
+	const char *proto;
+	struct xt_multiport_v1 *multiinfo
+		= (struct xt_multiport_v1 *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		xtables_check_inverse(argv[optind-1], &invert, &optind, 0);
+		proto = check_proto(pnum, invflags);
+		parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
+		multiinfo->flags = XT_MULTIPORT_SOURCE;
+		break;
+
+	case '2':
+		xtables_check_inverse(argv[optind-1], &invert, &optind, 0);
+		proto = check_proto(pnum, invflags);
+		parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
+		multiinfo->flags = XT_MULTIPORT_DESTINATION;
+		break;
+
+	case '3':
+		xtables_check_inverse(argv[optind-1], &invert, &optind, 0);
+		proto = check_proto(pnum, invflags);
+		parse_multi_ports_v1(argv[optind-1], multiinfo, proto);
+		multiinfo->flags = XT_MULTIPORT_EITHER;
+		break;
+
+	default:
+		return 0;
+	}
+
+	if (invert)
+		multiinfo->invert = 1;
+
+	if (*flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "multiport can only have one option");
+	*flags = 1;
+	return 1;
+}
+
+static int
+multiport_parse_v1(int c, char **argv, int invert, unsigned int *flags,
+                   const void *e, struct xt_entry_match **match)
+{
+	const struct ipt_entry *entry = e;
+	return __multiport_parse_v1(c, argv, invert, flags, match,
+	       entry->ip.proto, entry->ip.invflags);
+}
+
+static int
+multiport_parse6_v1(int c, char **argv, int invert, unsigned int *flags,
+                    const void *e, struct xt_entry_match **match)
+{
+	const struct ip6t_entry *entry = (const struct ip6t_entry *)e;
+	return __multiport_parse_v1(c, argv, invert, flags, match,
+	       entry->ipv6.proto, entry->ipv6.invflags);
+}
+
+/* Final check; must specify something. */
+static void multiport_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM, "multiport expection an option");
+}
+
+static char *
+port_to_service(int port, u_int8_t proto)
+{
+	struct servent *service;
+
+	if ((service = getservbyport(htons(port), proto_to_name(proto))))
+		return service->s_name;
+
+	return NULL;
+}
+
+static void
+print_port(u_int16_t port, u_int8_t protocol, int numeric)
+{
+	char *service;
+
+	if (numeric || (service = port_to_service(port, protocol)) == NULL)
+		printf("%u", port);
+	else
+		printf("%s", service);
+}
+
+/* Prints out the matchinfo. */
+static void
+__multiport_print(const struct xt_entry_match *match, int numeric,
+                  u_int16_t proto)
+{
+	const struct xt_multiport *multiinfo
+		= (const struct xt_multiport *)match->data;
+	unsigned int i;
+
+	printf("multiport ");
+
+	switch (multiinfo->flags) {
+	case XT_MULTIPORT_SOURCE:
+		printf("sports ");
+		break;
+
+	case XT_MULTIPORT_DESTINATION:
+		printf("dports ");
+		break;
+
+	case XT_MULTIPORT_EITHER:
+		printf("ports ");
+		break;
+
+	default:
+		printf("ERROR ");
+		break;
+	}
+
+	for (i=0; i < multiinfo->count; i++) {
+		printf("%s", i ? "," : "");
+		print_port(multiinfo->ports[i], proto, numeric);
+	}
+	printf(" ");
+}
+
+static void multiport_print(const void *ip_void,
+                            const struct xt_entry_match *match, int numeric)
+{
+	const struct ipt_ip *ip = ip_void;
+	__multiport_print(match, numeric, ip->proto);
+}
+
+static void multiport_print6(const void *ip_void,
+                             const struct xt_entry_match *match, int numeric)
+{
+	const struct ip6t_ip6 *ip = (const struct ip6t_ip6 *)ip_void;
+	__multiport_print(match, numeric, ip->proto);
+}
+
+static void __multiport_print_v1(const struct xt_entry_match *match,
+                                 int numeric, u_int16_t proto)
+{
+	const struct xt_multiport_v1 *multiinfo
+		= (const struct xt_multiport_v1 *)match->data;
+	unsigned int i;
+
+	printf("multiport ");
+
+	switch (multiinfo->flags) {
+	case XT_MULTIPORT_SOURCE:
+		printf("sports ");
+		break;
+
+	case XT_MULTIPORT_DESTINATION:
+		printf("dports ");
+		break;
+
+	case XT_MULTIPORT_EITHER:
+		printf("ports ");
+		break;
+
+	default:
+		printf("ERROR ");
+		break;
+	}
+
+	if (multiinfo->invert)
+		printf("! ");
+
+	for (i=0; i < multiinfo->count; i++) {
+		printf("%s", i ? "," : "");
+		print_port(multiinfo->ports[i], proto, numeric);
+		if (multiinfo->pflags[i]) {
+			printf(":");
+			print_port(multiinfo->ports[++i], proto, numeric);
+		}
+	}
+	printf(" ");
+}
+
+static void multiport_print_v1(const void *ip_void,
+                               const struct xt_entry_match *match, int numeric)
+{
+	const struct ipt_ip *ip = ip_void;
+	__multiport_print_v1(match, numeric, ip->proto);
+}
+
+static void multiport_print6_v1(const void *ip_void,
+                                const struct xt_entry_match *match, int numeric)
+{
+	const struct ip6t_ip6 *ip = (const struct ip6t_ip6 *)ip_void;
+	__multiport_print_v1(match, numeric, ip->proto);
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void __multiport_save(const struct xt_entry_match *match,
+                             u_int16_t proto)
+{
+	const struct xt_multiport *multiinfo
+		= (const struct xt_multiport *)match->data;
+	unsigned int i;
+
+	switch (multiinfo->flags) {
+	case XT_MULTIPORT_SOURCE:
+		printf("--sports ");
+		break;
+
+	case XT_MULTIPORT_DESTINATION:
+		printf("--dports ");
+		break;
+
+	case XT_MULTIPORT_EITHER:
+		printf("--ports ");
+		break;
+	}
+
+	for (i=0; i < multiinfo->count; i++) {
+		printf("%s", i ? "," : "");
+		print_port(multiinfo->ports[i], proto, 1);
+	}
+	printf(" ");
+}
+
+static void multiport_save(const void *ip_void,
+                           const struct xt_entry_match *match)
+{
+	const struct ipt_ip *ip = ip_void;
+	__multiport_save(match, ip->proto);
+}
+
+static void multiport_save6(const void *ip_void,
+                            const struct xt_entry_match *match)
+{
+	const struct ip6t_ip6 *ip = (const struct ip6t_ip6 *)ip_void;
+	__multiport_save(match, ip->proto);
+}
+
+static void __multiport_save_v1(const struct xt_entry_match *match,
+                                u_int16_t proto)
+{
+	const struct xt_multiport_v1 *multiinfo
+		= (const struct xt_multiport_v1 *)match->data;
+	unsigned int i;
+
+	if (multiinfo->invert)
+		printf("! ");
+
+	switch (multiinfo->flags) {
+	case XT_MULTIPORT_SOURCE:
+		printf("--sports ");
+		break;
+
+	case XT_MULTIPORT_DESTINATION:
+		printf("--dports ");
+		break;
+
+	case XT_MULTIPORT_EITHER:
+		printf("--ports ");
+		break;
+	}
+
+	for (i=0; i < multiinfo->count; i++) {
+		printf("%s", i ? "," : "");
+		print_port(multiinfo->ports[i], proto, 1);
+		if (multiinfo->pflags[i]) {
+			printf(":");
+			print_port(multiinfo->ports[++i], proto, 1);
+		}
+	}
+	printf(" ");
+}
+
+static void multiport_save_v1(const void *ip_void,
+                              const struct xt_entry_match *match)
+{
+	const struct ipt_ip *ip = ip_void;
+	__multiport_save_v1(match, ip->proto);
+}
+
+static void multiport_save6_v1(const void *ip_void,
+                               const struct xt_entry_match *match)
+{
+	const struct ip6t_ip6 *ip = (const struct ip6t_ip6 *)ip_void;
+	__multiport_save_v1(match, ip->proto);
+}
+
+static struct xtables_match multiport_match = {
+	.family		= NFPROTO_IPV4,
+	.name		= "multiport",
+	.revision	= 0,
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_multiport)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_multiport)),
+	.help		= multiport_help,
+	.parse		= multiport_parse,
+	.final_check	= multiport_check,
+	.print		= multiport_print,
+	.save		= multiport_save,
+	.extra_opts	= multiport_opts,
+};
+
+static struct xtables_match multiport_match6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "multiport",
+	.revision	= 0,
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_multiport)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_multiport)),
+	.help		= multiport_help,
+	.parse		= multiport_parse6,
+	.final_check	= multiport_check,
+	.print		= multiport_print6,
+	.save		= multiport_save6,
+	.extra_opts	= multiport_opts,
+};
+
+static struct xtables_match multiport_match_v1 = {
+	.family		= NFPROTO_IPV4,
+	.name		= "multiport",
+	.version	= XTABLES_VERSION,
+	.revision	= 1,
+	.size		= XT_ALIGN(sizeof(struct xt_multiport_v1)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_multiport_v1)),
+	.help		= multiport_help_v1,
+	.parse		= multiport_parse_v1,
+	.final_check	= multiport_check,
+	.print		= multiport_print_v1,
+	.save		= multiport_save_v1,
+	.extra_opts	= multiport_opts,
+};
+
+static struct xtables_match multiport_match6_v1 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "multiport",
+	.version	= XTABLES_VERSION,
+	.revision	= 1,
+	.size		= XT_ALIGN(sizeof(struct xt_multiport_v1)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_multiport_v1)),
+	.help		= multiport_help_v1,
+	.parse		= multiport_parse6_v1,
+	.final_check	= multiport_check,
+	.print		= multiport_print6_v1,
+	.save		= multiport_save6_v1,
+	.extra_opts	= multiport_opts,
+};
+
+void
+_init(void)
+{
+	xtables_register_match(&multiport_match);
+	xtables_register_match(&multiport_match6);
+	xtables_register_match(&multiport_match_v1);
+	xtables_register_match(&multiport_match6_v1);
+}
diff --git a/ap/app/iptables/extensions/libxt_multiport.man b/ap/app/iptables/extensions/libxt_multiport.man
new file mode 100755
index 0000000..caf5c56
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_multiport.man
@@ -0,0 +1,23 @@
+This module matches a set of source or destination ports.  Up to 15
+ports can be specified.  A port range (port:port) counts as two
+ports.  It can only be used in conjunction with
+\fB\-p tcp\fP
+or
+\fB\-p udp\fP.
+.TP
+[\fB!\fP] \fB\-\-source\-ports\fP,\fB\-\-sports\fP \fIport\fP[\fB,\fP\fIport\fP|\fB,\fP\fIport\fP\fB:\fP\fIport\fP]...
+Match if the source port is one of the given ports.  The flag
+\fB\-\-sports\fP
+is a convenient alias for this option. Multiple ports or port ranges are
+separated using a comma, and a port range is specified using a colon.
+\fB53,1024:65535\fP would therefore match ports 53 and all from 1024 through
+65535.
+.TP
+[\fB!\fP] \fB\-\-destination\-ports\fP,\fB\-\-dports\fP \fIport\fP[\fB,\fP\fIport\fP|\fB,\fP\fIport\fP\fB:\fP\fIport\fP]...
+Match if the destination port is one of the given ports.  The flag
+\fB\-\-dports\fP
+is a convenient alias for this option.
+.TP
+[\fB!\fP] \fB\-\-ports\fP \fIport\fP[\fB,\fP\fIport\fP|\fB,\fP\fIport\fP\fB:\fP\fIport\fP]...
+Match if either the source or destination ports are equal to one of
+the given ports.
diff --git a/ap/app/iptables/extensions/libxt_owner.c b/ap/app/iptables/extensions/libxt_owner.c
new file mode 100755
index 0000000..d27b3ae
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_owner.c
@@ -0,0 +1,602 @@
+/*
+ *	libxt_owner - iptables addon for xt_owner
+ *
+ *	Copyright © CC Computer Consultants GmbH, 2007 - 2008
+ *	Jan Engelhardt <jengelh@computergmbh.de>
+ */
+#include <getopt.h>
+#include <grp.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_owner.h>
+#include <linux/netfilter_ipv4/ipt_owner.h>
+#include <linux/netfilter_ipv6/ip6t_owner.h>
+
+/*
+ *	Note: "UINT32_MAX - 1" is used in the code because -1 is a reserved
+ *	UID/GID value anyway.
+ */
+
+enum {
+	FLAG_UID_OWNER     = 1 << 0,
+	FLAG_GID_OWNER     = 1 << 1,
+	FLAG_SOCKET_EXISTS = 1 << 2,
+	FLAG_PID_OWNER     = 1 << 3,
+	FLAG_SID_OWNER     = 1 << 4,
+	FLAG_COMM          = 1 << 5,
+};
+
+static void owner_mt_help_v0(void)
+{
+#ifdef IPT_OWNER_COMM
+	printf(
+"owner match options:\n"
+"[!] --uid-owner userid       Match local UID\n"
+"[!] --gid-owner groupid      Match local GID\n"
+"[!] --pid-owner processid    Match local PID\n"
+"[!] --sid-owner sessionid    Match local SID\n"
+"[!] --cmd-owner name         Match local command name\n"
+"NOTE: PID, SID and command matching are broken on SMP\n");
+#else
+	printf(
+"owner match options:\n"
+"[!] --uid-owner userid       Match local UID\n"
+"[!] --gid-owner groupid      Match local GID\n"
+"[!] --pid-owner processid    Match local PID\n"
+"[!] --sid-owner sessionid    Match local SID\n"
+"NOTE: PID and SID matching are broken on SMP\n");
+#endif /* IPT_OWNER_COMM */
+}
+
+static void owner_mt6_help_v0(void)
+{
+	printf(
+"owner match options:\n"
+"[!] --uid-owner userid       Match local UID\n"
+"[!] --gid-owner groupid      Match local GID\n"
+"[!] --pid-owner processid    Match local PID\n"
+"[!] --sid-owner sessionid    Match local SID\n"
+"NOTE: PID and SID matching are broken on SMP\n");
+}
+
+static void owner_mt_help(void)
+{
+	printf(
+"owner match options:\n"
+"[!] --uid-owner userid[-userid]      Match local UID\n"
+"[!] --gid-owner groupid[-groupid]    Match local GID\n"
+"[!] --socket-exists                  Match if socket exists\n");
+}
+
+static const struct option owner_mt_opts_v0[] = {
+	{.name = "uid-owner", .has_arg = true, .val = 'u'},
+	{.name = "gid-owner", .has_arg = true, .val = 'g'},
+	{.name = "pid-owner", .has_arg = true, .val = 'p'},
+	{.name = "sid-owner", .has_arg = true, .val = 's'},
+#ifdef IPT_OWNER_COMM
+	{.name = "cmd-owner", .has_arg = true, .val = 'c'},
+#endif
+	{ .name = NULL }
+};
+
+static const struct option owner_mt6_opts_v0[] = {
+	{.name = "uid-owner", .has_arg = true, .val = 'u'},
+	{.name = "gid-owner", .has_arg = true, .val = 'g'},
+	{.name = "pid-owner", .has_arg = true, .val = 'p'},
+	{.name = "sid-owner", .has_arg = true, .val = 's'},
+	{ .name = NULL }
+};
+
+static const struct option owner_mt_opts[] = {
+	{.name = "uid-owner",     .has_arg = true,  .val = 'u'},
+	{.name = "gid-owner",     .has_arg = true,  .val = 'g'},
+	{.name = "socket-exists", .has_arg = false, .val = 'k'},
+	{ .name = NULL }
+};
+
+static int
+owner_mt_parse_v0(int c, char **argv, int invert, unsigned int *flags,
+                  const void *entry, struct xt_entry_match **match)
+{
+	struct ipt_owner_info *info = (void *)(*match)->data;
+	struct passwd *pwd;
+	struct group *grp;
+	unsigned int id;
+
+	switch (c) {
+	case 'u':
+		xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner", *flags & FLAG_UID_OWNER);
+		if ((pwd = getpwnam(optarg)) != NULL)
+			id = pwd->pw_uid;
+		else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1))
+			xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", optarg);
+		if (invert)
+			info->invert |= IPT_OWNER_UID;
+		info->match |= IPT_OWNER_UID;
+		info->uid    = id;
+		*flags      |= FLAG_UID_OWNER;
+		return true;
+
+	case 'g':
+		xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner", *flags & FLAG_GID_OWNER);
+		if ((grp = getgrnam(optarg)) != NULL)
+			id = grp->gr_gid;
+		else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1))
+			xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", optarg);
+		if (invert)
+			info->invert |= IPT_OWNER_GID;
+		info->match |= IPT_OWNER_GID;
+		info->gid    = id;
+		*flags      |= FLAG_GID_OWNER;
+		return true;
+
+	case 'p':
+		xtables_param_act(XTF_ONLY_ONCE, "owner", "--pid-owner", *flags & FLAG_PID_OWNER);
+		if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "owner", "--pid-owner", optarg);
+		if (invert)
+			info->invert |= IPT_OWNER_PID;
+		info->match |= IPT_OWNER_PID;
+		info->pid    = id;
+		*flags      |= FLAG_PID_OWNER;
+		return true;
+
+	case 's':
+		xtables_param_act(XTF_ONLY_ONCE, "owner", "--sid-owner", *flags & FLAG_SID_OWNER);
+		if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "owner", "--sid-value", optarg);
+		if (invert)
+			info->invert |= IPT_OWNER_SID;
+		info->match |= IPT_OWNER_SID;
+		info->sid    = id;
+		*flags      |= FLAG_SID_OWNER;
+		return true;
+
+#ifdef IPT_OWNER_COMM
+	case 'c':
+		xtables_param_act(XTF_ONLY_ONCE, "owner", "--cmd-owner", *flags & FLAG_COMM);
+		if (strlen(optarg) > sizeof(info->comm))
+			xtables_error(PARAMETER_PROBLEM, "owner match: command "
+			           "\"%s\" too long, max. %zu characters",
+			           optarg, sizeof(info->comm));
+
+		info->comm[sizeof(info->comm)-1] = '\0';
+		strncpy(info->comm, optarg, sizeof(info->comm));
+
+		if (invert)
+			info->invert |= IPT_OWNER_COMM;
+		info->match |= IPT_OWNER_COMM;
+		*flags      |= FLAG_COMM;
+		return true;
+#endif
+	}
+	return false;
+}
+
+static int
+owner_mt6_parse_v0(int c, char **argv, int invert, unsigned int *flags,
+                   const void *entry, struct xt_entry_match **match)
+{
+	struct ip6t_owner_info *info = (void *)(*match)->data;
+	struct passwd *pwd;
+	struct group *grp;
+	unsigned int id;
+
+	switch (c) {
+	case 'u':
+		xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner",
+		          *flags & FLAG_UID_OWNER);
+		if ((pwd = getpwnam(optarg)) != NULL)
+			id = pwd->pw_uid;
+		else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1))
+			xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", optarg);
+		if (invert)
+			info->invert |= IP6T_OWNER_UID;
+		info->match |= IP6T_OWNER_UID;
+		info->uid    = id;
+		*flags      |= FLAG_UID_OWNER;
+		return true;
+
+	case 'g':
+		xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner",
+		          *flags & FLAG_GID_OWNER);
+		if ((grp = getgrnam(optarg)) != NULL)
+			id = grp->gr_gid;
+		else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1))
+			xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", optarg);
+		if (invert)
+			info->invert |= IP6T_OWNER_GID;
+		info->match |= IP6T_OWNER_GID;
+		info->gid    = id;
+		*flags      |= FLAG_GID_OWNER;
+		return true;
+
+	case 'p':
+		xtables_param_act(XTF_ONLY_ONCE, "owner", "--pid-owner",
+		          *flags & FLAG_PID_OWNER);
+		if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "owner", "--pid-owner", optarg);
+		if (invert)
+			info->invert |= IP6T_OWNER_PID;
+		info->match |= IP6T_OWNER_PID;
+		info->pid    = id;
+		*flags      |= FLAG_PID_OWNER;
+		return true;
+
+	case 's':
+		xtables_param_act(XTF_ONLY_ONCE, "owner", "--sid-owner",
+		          *flags & FLAG_SID_OWNER);
+		if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "owner", "--sid-owner", optarg);
+		if (invert)
+			info->invert |= IP6T_OWNER_SID;
+		info->match |= IP6T_OWNER_SID;
+		info->sid    = id;
+		*flags      |= FLAG_SID_OWNER;
+		return true;
+	}
+	return false;
+}
+
+static void owner_parse_range(const char *s, unsigned int *from,
+                              unsigned int *to, const char *opt)
+{
+	char *end;
+
+	/* -1 is reversed, so the max is one less than that. */
+	if (!xtables_strtoui(s, &end, from, 0, UINT32_MAX - 1))
+		xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
+	*to = *from;
+	if (*end == '-' || *end == ':')
+		if (!xtables_strtoui(end + 1, &end, to, 0, UINT32_MAX - 1))
+			xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
+	if (*end != '\0')
+		xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
+}
+
+static int owner_mt_parse(int c, char **argv, int invert, unsigned int *flags,
+                          const void *entry, struct xt_entry_match **match)
+{
+	struct xt_owner_match_info *info = (void *)(*match)->data;
+	struct passwd *pwd;
+	struct group *grp;
+	unsigned int from, to;
+
+	switch (c) {
+	case 'u':
+		xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner",
+		          *flags & FLAG_UID_OWNER);
+		if ((pwd = getpwnam(optarg)) != NULL)
+			from = to = pwd->pw_uid;
+		else
+			owner_parse_range(optarg, &from, &to, "--uid-owner");
+		if (invert)
+			info->invert |= XT_OWNER_UID;
+		info->match  |= XT_OWNER_UID;
+		info->uid_min = from;
+		info->uid_max = to;
+		*flags       |= FLAG_UID_OWNER;
+		return true;
+
+	case 'g':
+		xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner",
+		          *flags & FLAG_GID_OWNER);
+		if ((grp = getgrnam(optarg)) != NULL)
+			from = to = grp->gr_gid;
+		else
+			owner_parse_range(optarg, &from, &to, "--gid-owner");
+		if (invert)
+			info->invert |= XT_OWNER_GID;
+		info->match  |= XT_OWNER_GID;
+		info->gid_min = from;
+		info->gid_max = to;
+		*flags      |= FLAG_GID_OWNER;
+		return true;
+
+	case 'k':
+		xtables_param_act(XTF_ONLY_ONCE, "owner", "--socket-exists",
+		          *flags & FLAG_SOCKET_EXISTS);
+		if (invert)
+			info->invert |= XT_OWNER_SOCKET;
+		info->match |= XT_OWNER_SOCKET;
+		*flags |= FLAG_SOCKET_EXISTS;
+		return true;
+
+	}
+	return false;
+}
+
+static void owner_mt_check(unsigned int flags)
+{
+	if (flags == 0)
+		xtables_error(PARAMETER_PROBLEM, "owner: At least one of "
+		           "--uid-owner, --gid-owner or --socket-exists "
+		           "is required");
+}
+
+static void
+owner_mt_print_item_v0(const struct ipt_owner_info *info, const char *label,
+                       u_int8_t flag, bool numeric)
+{
+	if (!(info->match & flag))
+		return;
+	if (info->invert & flag)
+		printf("! ");
+	printf("%s ", label);
+
+	switch (info->match & flag) {
+	case IPT_OWNER_UID:
+		if (!numeric) {
+			struct passwd *pwd = getpwuid(info->uid);
+
+			if (pwd != NULL && pwd->pw_name != NULL) {
+				printf("%s ", pwd->pw_name);
+				break;
+			}
+		}
+		printf("%u ", (unsigned int)info->uid);
+		break;
+
+	case IPT_OWNER_GID:
+		if (!numeric) {
+			struct group *grp = getgrgid(info->gid);
+
+			if (grp != NULL && grp->gr_name != NULL) {
+				printf("%s ", grp->gr_name);
+				break;
+			}
+		}
+		printf("%u ", (unsigned int)info->gid);
+		break;
+
+	case IPT_OWNER_PID:
+		printf("%u ", (unsigned int)info->pid);
+		break;
+
+	case IPT_OWNER_SID:
+		printf("%u ", (unsigned int)info->sid);
+		break;
+
+#ifdef IPT_OWNER_COMM
+	case IPT_OWNER_COMM:
+		printf("%.*s ", (int)sizeof(info->comm), info->comm);
+		break;
+#endif
+	}
+}
+
+static void
+owner_mt6_print_item_v0(const struct ip6t_owner_info *info, const char *label,
+                        u_int8_t flag, bool numeric)
+{
+	if (!(info->match & flag))
+		return;
+	if (info->invert & flag)
+		printf("! ");
+	printf("%s ", label);
+
+	switch (info->match & flag) {
+	case IP6T_OWNER_UID:
+		if (!numeric) {
+			struct passwd *pwd = getpwuid(info->uid);
+
+			if (pwd != NULL && pwd->pw_name != NULL) {
+				printf("%s ", pwd->pw_name);
+				break;
+			}
+		}
+		printf("%u ", (unsigned int)info->uid);
+		break;
+
+	case IP6T_OWNER_GID:
+		if (!numeric) {
+			struct group *grp = getgrgid(info->gid);
+
+			if (grp != NULL && grp->gr_name != NULL) {
+				printf("%s ", grp->gr_name);
+				break;
+			}
+		}
+		printf("%u ", (unsigned int)info->gid);
+		break;
+
+	case IP6T_OWNER_PID:
+		printf("%u ", (unsigned int)info->pid);
+		break;
+
+	case IP6T_OWNER_SID:
+		printf("%u ", (unsigned int)info->sid);
+		break;
+	}
+}
+
+static void
+owner_mt_print_item(const struct xt_owner_match_info *info, const char *label,
+                    u_int8_t flag, bool numeric)
+{
+	if (!(info->match & flag))
+		return;
+	if (info->invert & flag)
+		printf("! ");
+	printf("%s ", label);
+
+	switch (info->match & flag) {
+	case XT_OWNER_UID:
+		if (info->uid_min != info->uid_max) {
+			printf("%u-%u ", (unsigned int)info->uid_min,
+			       (unsigned int)info->uid_max);
+			break;
+		} else if (!numeric) {
+			const struct passwd *pwd = getpwuid(info->uid_min);
+
+			if (pwd != NULL && pwd->pw_name != NULL) {
+				printf("%s ", pwd->pw_name);
+				break;
+			}
+		}
+		printf("%u ", (unsigned int)info->uid_min);
+		break;
+
+	case XT_OWNER_GID:
+		if (info->gid_min != info->gid_max) {
+			printf("%u-%u ", (unsigned int)info->gid_min,
+			       (unsigned int)info->gid_max);
+			break;
+		} else if (!numeric) {
+			const struct group *grp = getgrgid(info->gid_min);
+
+			if (grp != NULL && grp->gr_name != NULL) {
+				printf("%s ", grp->gr_name);
+				break;
+			}
+		}
+		printf("%u ", (unsigned int)info->gid_min);
+		break;
+	}
+}
+
+static void
+owner_mt_print_v0(const void *ip, const struct xt_entry_match *match,
+                  int numeric)
+{
+	const struct ipt_owner_info *info = (void *)match->data;
+
+	owner_mt_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric);
+	owner_mt_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric);
+	owner_mt_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric);
+	owner_mt_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric);
+#ifdef IPT_OWNER_COMM
+	owner_mt_print_item_v0(info, "owner CMD match", IPT_OWNER_COMM, numeric);
+#endif
+}
+
+static void
+owner_mt6_print_v0(const void *ip, const struct xt_entry_match *match,
+                   int numeric)
+{
+	const struct ip6t_owner_info *info = (void *)match->data;
+
+	owner_mt6_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric);
+	owner_mt6_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric);
+	owner_mt6_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric);
+	owner_mt6_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric);
+}
+
+static void owner_mt_print(const void *ip, const struct xt_entry_match *match,
+                           int numeric)
+{
+	const struct xt_owner_match_info *info = (void *)match->data;
+
+	owner_mt_print_item(info, "owner socket exists", XT_OWNER_SOCKET, numeric);
+	owner_mt_print_item(info, "owner UID match",     XT_OWNER_UID,    numeric);
+	owner_mt_print_item(info, "owner GID match",     XT_OWNER_GID,    numeric);
+}
+
+static void
+owner_mt_save_v0(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ipt_owner_info *info = (void *)match->data;
+
+	owner_mt_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true);
+	owner_mt_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true);
+	owner_mt_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true);
+	owner_mt_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true);
+#ifdef IPT_OWNER_COMM
+	owner_mt_print_item_v0(info, "--cmd-owner", IPT_OWNER_COMM, true);
+#endif
+}
+
+static void
+owner_mt6_save_v0(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ip6t_owner_info *info = (void *)match->data;
+
+	owner_mt6_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true);
+	owner_mt6_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true);
+	owner_mt6_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true);
+	owner_mt6_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true);
+}
+
+static void owner_mt_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_owner_match_info *info = (void *)match->data;
+
+	owner_mt_print_item(info, "--socket-exists",  XT_OWNER_SOCKET, false);
+	owner_mt_print_item(info, "--uid-owner",      XT_OWNER_UID,    false);
+	owner_mt_print_item(info, "--gid-owner",      XT_OWNER_GID,    false);
+}
+
+static struct xtables_match owner_mt_reg_v0 = {
+	.version       = XTABLES_VERSION,
+	.name          = "owner",
+	.revision      = 0,
+	.family        = NFPROTO_IPV4,
+	.size          = XT_ALIGN(sizeof(struct ipt_owner_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct ipt_owner_info)),
+	.help          = owner_mt_help_v0,
+	.parse         = owner_mt_parse_v0,
+	.final_check   = owner_mt_check,
+	.print         = owner_mt_print_v0,
+	.save          = owner_mt_save_v0,
+	.extra_opts    = owner_mt_opts_v0,
+};
+
+static struct xtables_match owner_mt6_reg_v0 = {
+	.version       = XTABLES_VERSION,
+	.name          = "owner",
+	.revision      = 0,
+	.family        = NFPROTO_IPV6,
+	.size          = XT_ALIGN(sizeof(struct ip6t_owner_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct ip6t_owner_info)),
+	.help          = owner_mt6_help_v0,
+	.parse         = owner_mt6_parse_v0,
+	.final_check   = owner_mt_check,
+	.print         = owner_mt6_print_v0,
+	.save          = owner_mt6_save_v0,
+	.extra_opts    = owner_mt6_opts_v0,
+};
+
+static struct xtables_match owner_mt_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "owner",
+	.revision      = 1,
+	.family        = NFPROTO_IPV4,
+	.size          = XT_ALIGN(sizeof(struct xt_owner_match_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_owner_match_info)),
+	.help          = owner_mt_help,
+	.parse         = owner_mt_parse,
+	.final_check   = owner_mt_check,
+	.print         = owner_mt_print,
+	.save          = owner_mt_save,
+	.extra_opts    = owner_mt_opts,
+};
+
+static struct xtables_match owner_mt6_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "owner",
+	.revision      = 1,
+	.family        = NFPROTO_IPV6,
+	.size          = XT_ALIGN(sizeof(struct xt_owner_match_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_owner_match_info)),
+	.help          = owner_mt_help,
+	.parse         = owner_mt_parse,
+	.final_check   = owner_mt_check,
+	.print         = owner_mt_print,
+	.save          = owner_mt_save,
+	.extra_opts    = owner_mt_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&owner_mt_reg_v0);
+	xtables_register_match(&owner_mt6_reg_v0);
+	xtables_register_match(&owner_mt_reg);
+	xtables_register_match(&owner_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_owner.man b/ap/app/iptables/extensions/libxt_owner.man
new file mode 100755
index 0000000..49b58ce
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_owner.man
@@ -0,0 +1,19 @@
+This module attempts to match various characteristics of the packet creator,
+for locally generated packets. This match is only valid in the OUTPUT and
+POSTROUTING chains. Forwarded packets do not have any socket associated with
+them. Packets from kernel threads do have a socket, but usually no owner.
+.TP
+[\fB!\fP] \fB\-\-uid\-owner\fP \fIusername\fP
+.TP
+[\fB!\fP] \fB\-\-uid\-owner\fP \fIuserid\fP[\fB\-\fP\fIuserid\fP]
+Matches if the packet socket's file structure (if it has one) is owned by the
+given user. You may also specify a numerical UID, or an UID range.
+.TP
+[\fB!\fP] \fB\-\-gid\-owner\fP \fIgroupname\fP
+.TP
+[\fB!\fP] \fB\-\-gid\-owner\fP \fIgroupid\fP[\fB\-\fP\fIgroupid\fP]
+Matches if the packet socket's file structure is owned by the given group.
+You may also specify a numerical GID, or a GID range.
+.TP
+[\fB!\fP] \fB\-\-socket\-exists\fP
+Matches if the packet is associated with a socket.
diff --git a/ap/app/iptables/extensions/libxt_physdev.c b/ap/app/iptables/extensions/libxt_physdev.c
new file mode 100755
index 0000000..c87779b
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_physdev.c
@@ -0,0 +1,197 @@
+/* Shared library add-on to iptables to add bridge port matching support. */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <xtables.h>
+#include <linux/netfilter/xt_physdev.h>
+#if defined(__GLIBC__) && __GLIBC__ == 2
+#include <net/ethernet.h>
+#else
+#include <linux/if_ether.h>
+#endif
+
+static void physdev_help(void)
+{
+	printf(
+"physdev match options:\n"
+" [!] --physdev-in inputname[+]		bridge port name ([+] for wildcard)\n"
+" [!] --physdev-out outputname[+]	bridge port name ([+] for wildcard)\n"
+" [!] --physdev-is-in			arrived on a bridge device\n"
+" [!] --physdev-is-out			will leave on a bridge device\n"
+" [!] --physdev-is-bridged		it's a bridged packet\n");
+}
+
+static const struct option physdev_opts[] = {
+	{ "physdev-in", 1, NULL, '1' },
+	{ "physdev-out", 1, NULL, '2' },
+	{ "physdev-is-in", 0, NULL, '3' },
+	{ "physdev-is-out", 0, NULL, '4' },
+	{ "physdev-is-bridged", 0, NULL, '5' },
+	{ .name = NULL }
+};
+
+static int
+physdev_parse(int c, char **argv, int invert, unsigned int *flags,
+              const void *entry, struct xt_entry_match **match)
+{
+	struct xt_physdev_info *info =
+		(struct xt_physdev_info*)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & XT_PHYSDEV_OP_IN)
+			goto multiple_use;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		xtables_parse_interface(argv[optind-1], info->physindev,
+				(unsigned char *)info->in_mask);
+		if (invert)
+			info->invert |= XT_PHYSDEV_OP_IN;
+		info->bitmask |= XT_PHYSDEV_OP_IN;
+		*flags |= XT_PHYSDEV_OP_IN;
+		break;
+
+	case '2':
+		if (*flags & XT_PHYSDEV_OP_OUT)
+			goto multiple_use;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		xtables_parse_interface(argv[optind-1], info->physoutdev,
+				(unsigned char *)info->out_mask);
+		if (invert)
+			info->invert |= XT_PHYSDEV_OP_OUT;
+		info->bitmask |= XT_PHYSDEV_OP_OUT;
+		*flags |= XT_PHYSDEV_OP_OUT;
+		break;
+
+	case '3':
+		if (*flags & XT_PHYSDEV_OP_ISIN)
+			goto multiple_use;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		info->bitmask |= XT_PHYSDEV_OP_ISIN;
+		if (invert)
+			info->invert |= XT_PHYSDEV_OP_ISIN;
+		*flags |= XT_PHYSDEV_OP_ISIN;
+		break;
+
+	case '4':
+		if (*flags & XT_PHYSDEV_OP_ISOUT)
+			goto multiple_use;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		info->bitmask |= XT_PHYSDEV_OP_ISOUT;
+		if (invert)
+			info->invert |= XT_PHYSDEV_OP_ISOUT;
+		*flags |= XT_PHYSDEV_OP_ISOUT;
+		break;
+
+	case '5':
+		if (*flags & XT_PHYSDEV_OP_BRIDGED)
+			goto multiple_use;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		if (invert)
+			info->invert |= XT_PHYSDEV_OP_BRIDGED;
+		*flags |= XT_PHYSDEV_OP_BRIDGED;
+		info->bitmask |= XT_PHYSDEV_OP_BRIDGED;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+multiple_use:
+	xtables_error(PARAMETER_PROBLEM,
+	   "multiple use of the same physdev option is not allowed");
+
+}
+
+static void physdev_check(unsigned int flags)
+{
+	if (flags == 0)
+		xtables_error(PARAMETER_PROBLEM, "PHYSDEV: no physdev option specified");
+}
+
+static void
+physdev_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	struct xt_physdev_info *info =
+		(struct xt_physdev_info*)match->data;
+
+	printf("PHYSDEV match");
+	if (info->bitmask & XT_PHYSDEV_OP_ISIN)
+		printf("%s --physdev-is-in",
+		       info->invert & XT_PHYSDEV_OP_ISIN ? " !":"");
+	if (info->bitmask & XT_PHYSDEV_OP_IN)
+		printf("%s --physdev-in %s",
+		(info->invert & XT_PHYSDEV_OP_IN) ? " !":"", info->physindev);
+
+	if (info->bitmask & XT_PHYSDEV_OP_ISOUT)
+		printf("%s --physdev-is-out",
+		       info->invert & XT_PHYSDEV_OP_ISOUT ? " !":"");
+	if (info->bitmask & XT_PHYSDEV_OP_OUT)
+		printf("%s --physdev-out %s",
+		(info->invert & XT_PHYSDEV_OP_OUT) ? " !":"", info->physoutdev);
+	if (info->bitmask & XT_PHYSDEV_OP_BRIDGED)
+		printf("%s --physdev-is-bridged",
+		       info->invert & XT_PHYSDEV_OP_BRIDGED ? " !":"");
+	printf(" ");
+}
+
+static void physdev_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct xt_physdev_info *info =
+		(struct xt_physdev_info*)match->data;
+
+	if (info->bitmask & XT_PHYSDEV_OP_ISIN)
+		printf("%s--physdev-is-in ",
+		       (info->invert & XT_PHYSDEV_OP_ISIN) ? "! " : "");
+	if (info->bitmask & XT_PHYSDEV_OP_IN)
+		printf("%s--physdev-in %s ",
+		       (info->invert & XT_PHYSDEV_OP_IN) ? "! " : "",
+		       info->physindev);
+
+	if (info->bitmask & XT_PHYSDEV_OP_ISOUT)
+		printf("%s--physdev-is-out ",
+		       (info->invert & XT_PHYSDEV_OP_ISOUT) ? "! " : "");
+	if (info->bitmask & XT_PHYSDEV_OP_OUT)
+		printf("%s--physdev-out %s ",
+		       (info->invert & XT_PHYSDEV_OP_OUT) ? "! " : "",
+		       info->physoutdev);
+	if (info->bitmask & XT_PHYSDEV_OP_BRIDGED)
+		printf("%s--physdev-is-bridged ",
+		       (info->invert & XT_PHYSDEV_OP_BRIDGED) ? "! " : "");
+}
+
+static struct xtables_match physdev_match = {
+	.family		= NFPROTO_IPV4,
+	.name		= "physdev",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_physdev_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_physdev_info)),
+	.help		= physdev_help,
+	.parse		= physdev_parse,
+	.final_check	= physdev_check,
+	.print		= physdev_print,
+	.save		= physdev_save,
+	.extra_opts	= physdev_opts,
+};
+
+static struct xtables_match physdev_match6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "physdev",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_physdev_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_physdev_info)),
+	.help		= physdev_help,
+	.parse		= physdev_parse,
+	.final_check	= physdev_check,
+	.print		= physdev_print,
+	.save		= physdev_save,
+	.extra_opts	= physdev_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&physdev_match);
+	xtables_register_match(&physdev_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_physdev.man b/ap/app/iptables/extensions/libxt_physdev.man
new file mode 100755
index 0000000..53beb2e
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_physdev.man
@@ -0,0 +1,42 @@
+This module matches on the bridge port input and output devices enslaved
+to a bridge device. This module is a part of the infrastructure that enables
+a transparent bridging IP firewall and is only useful for kernel versions
+above version 2.5.44.
+.TP
+[\fB!\fP] \fB\-\-physdev\-in\fP \fIname\fP
+Name of a bridge port via which a packet is received (only for
+packets entering the
+.BR INPUT ,
+.B FORWARD
+and
+.B PREROUTING
+chains). If the interface name ends in a "+", then any
+interface which begins with this name will match. If the packet didn't arrive
+through a bridge device, this packet won't match this option, unless '!' is used.
+.TP
+[\fB!\fP] \fB\-\-physdev\-out\fP \fIname\fP
+Name of a bridge port via which a packet is going to be sent (for packets
+entering the
+.BR FORWARD ,
+.B OUTPUT
+and
+.B POSTROUTING
+chains).  If the interface name ends in a "+", then any
+interface which begins with this name will match. Note that in the
+.BR nat " and " mangle
+.B OUTPUT
+chains one cannot match on the bridge output port, however one can in the
+.B "filter OUTPUT"
+chain. If the packet won't leave by a bridge device or if it is yet unknown what
+the output device will be, then the packet won't match this option,
+unless '!' is used.
+.TP
+[\fB!\fP] \fB\-\-physdev\-is\-in\fP
+Matches if the packet has entered through a bridge interface.
+.TP
+[\fB!\fP] \fB\-\-physdev\-is\-out\fP
+Matches if the packet will leave through a bridge interface.
+.TP
+[\fB!\fP] \fB\-\-physdev\-is\-bridged\fP
+Matches if the packet is being bridged and therefore is not being routed.
+This is only useful in the FORWARD and POSTROUTING chains.
diff --git a/ap/app/iptables/extensions/libxt_pkttype.c b/ap/app/iptables/extensions/libxt_pkttype.c
new file mode 100755
index 0000000..0fa933f
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_pkttype.c
@@ -0,0 +1,164 @@
+/* 
+ * Shared library add-on to iptables to match 
+ * packets by their type (BROADCAST, UNICAST, MULTICAST). 
+ *
+ * Michal Ludvig <michal@logix.cz>
+ */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#if defined(__GLIBC__) && __GLIBC__ == 2
+#include <net/ethernet.h>
+#else
+#include <linux/if_ether.h>
+#endif
+#include <xtables.h>
+#include <linux/if_packet.h>
+#include <linux/netfilter/xt_pkttype.h>
+
+#define	PKTTYPE_VERSION	"0.1"
+
+struct pkttypes {
+	const char *name;
+	unsigned char pkttype;
+	unsigned char printhelp;
+	const char *help;
+};
+
+static const struct pkttypes supported_types[] = {
+	{"unicast", PACKET_HOST, 1, "to us"},
+	{"broadcast", PACKET_BROADCAST, 1, "to all"},
+	{"multicast", PACKET_MULTICAST, 1, "to group"},
+/*
+	{"otherhost", PACKET_OTHERHOST, 1, "to someone else"},
+	{"outgoing", PACKET_OUTGOING, 1, "outgoing of any type"},
+*/
+	/* aliases */
+	{"bcast", PACKET_BROADCAST, 0, NULL},
+	{"mcast", PACKET_MULTICAST, 0, NULL},
+	{"host", PACKET_HOST, 0, NULL}
+};
+
+static void print_types(void)
+{
+	unsigned int	i;
+	
+	printf("Valid packet types:\n");
+	for (i = 0; i < sizeof(supported_types)/sizeof(struct pkttypes); i++)
+	{
+		if(supported_types[i].printhelp == 1)
+			printf("\t%-14s\t\t%s\n", supported_types[i].name, supported_types[i].help);
+	}
+	printf("\n");
+}
+
+static void pkttype_help(void)
+{
+	printf(
+"pkttype match options:\n"
+"[!] --pkt-type packettype    match packet type\n");
+	print_types();
+}
+
+static const struct option pkttype_opts[] = {
+	{"pkt-type", 1, NULL, '1'},
+	{ .name = NULL }
+};
+
+static void parse_pkttype(const char *pkttype, struct xt_pkttype_info *info)
+{
+	unsigned int	i;
+	
+	for (i = 0; i < sizeof(supported_types)/sizeof(struct pkttypes); i++)
+	{
+		if(strcasecmp(pkttype, supported_types[i].name)==0)
+		{
+			info->pkttype=supported_types[i].pkttype;
+			return;
+		}
+	}
+	
+	xtables_error(PARAMETER_PROBLEM, "Bad packet type '%s'", pkttype);
+}
+
+static int pkttype_parse(int c, char **argv, int invert, unsigned int *flags,
+                         const void *entry, struct xt_entry_match **match)
+{
+	struct xt_pkttype_info *info = (struct xt_pkttype_info *)(*match)->data;
+	
+	switch(c)
+	{
+		case '1':
+			xtables_check_inverse(optarg, &invert, &optind, 0);
+			parse_pkttype(argv[optind-1], info);
+			if(invert)
+				info->invert=1;
+			*flags=1;
+			break;
+
+		default: 
+			return 0;
+	}
+
+	return 1;
+}
+
+static void pkttype_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM, "You must specify \"--pkt-type\"");
+}
+
+static void print_pkttype(struct xt_pkttype_info *info)
+{
+	unsigned int	i;
+	
+	for (i = 0; i < sizeof(supported_types)/sizeof(struct pkttypes); i++)
+	{
+		if(supported_types[i].pkttype==info->pkttype)
+		{
+			printf("%s ", supported_types[i].name);
+			return;
+		}
+	}
+
+	printf("%d ", info->pkttype);	/* in case we didn't find an entry in named-packtes */
+}
+
+static void pkttype_print(const void *ip, const struct xt_entry_match *match,
+                          int numeric)
+{
+	struct xt_pkttype_info *info = (struct xt_pkttype_info *)match->data;
+	
+	printf("PKTTYPE %s= ", info->invert?"!":"");
+	print_pkttype(info);
+}
+
+static void pkttype_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct xt_pkttype_info *info = (struct xt_pkttype_info *)match->data;
+	
+	printf("%s--pkt-type ", info->invert ? "! " : "");
+	print_pkttype(info);
+}
+
+static struct xtables_match pkttype_match = {
+	.family		= AF_UNSPEC,
+	.name		= "pkttype",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_pkttype_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_pkttype_info)),
+	.help		= pkttype_help,
+	.parse		= pkttype_parse,
+	.final_check	= pkttype_check,
+	.print		= pkttype_print,
+	.save		= pkttype_save,
+	.extra_opts	= pkttype_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&pkttype_match);
+}
diff --git a/ap/app/iptables/extensions/libxt_pkttype.man b/ap/app/iptables/extensions/libxt_pkttype.man
new file mode 100755
index 0000000..4560c76
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_pkttype.man
@@ -0,0 +1,3 @@
+This module matches the link-layer packet type.
+.TP
+[\fB!\fP] \fB\-\-pkt\-type\fP {\fBunicast\fP|\fBbroadcast\fP|\fBmulticast\fP}
diff --git a/ap/app/iptables/extensions/libxt_policy.man b/ap/app/iptables/extensions/libxt_policy.man
new file mode 100755
index 0000000..3500025
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_policy.man
@@ -0,0 +1,48 @@
+This modules matches the policy used by IPsec for handling a packet.
+.TP
+\fB\-\-dir\fP {\fBin\fP|\fBout\fP}
+Used to select whether to match the policy used for decapsulation or the
+policy that will be used for encapsulation.
+.B in
+is valid in the
+.B PREROUTING, INPUT and FORWARD
+chains,
+.B out
+is valid in the
+.B POSTROUTING, OUTPUT and FORWARD
+chains.
+.TP
+\fB\-\-pol\fP {\fBnone\fP|\fBipsec\fP}
+Matches if the packet is subject to IPsec processing.
+.TP
+\fB\-\-strict\fP
+Selects whether to match the exact policy or match if any rule of
+the policy matches the given policy.
+.TP
+[\fB!\fP] \fB\-\-reqid\fP \fIid\fP
+Matches the reqid of the policy rule. The reqid can be specified with
+.B setkey(8)
+using
+.B unique:id
+as level.
+.TP
+[\fB!\fP] \fB\-\-spi\fP \fIspi\fP
+Matches the SPI of the SA.
+.TP
+[\fB!\fP] \fB\-\-proto\fP {\fBah\fP|\fBesp\fP|\fBipcomp\fP}
+Matches the encapsulation protocol.
+.TP
+[\fB!\fP] \fB\-\-mode\fP {\fBtunnel\fP|\fBtransport\fP}
+Matches the encapsulation mode.
+.TP
+[\fB!\fP] \fB\-\-tunnel\-src\fP \fIaddr\fP[\fB/\fP\fImask\fP]
+Matches the source end-point address of a tunnel mode SA.
+Only valid with \fB\-\-mode tunnel\fP.
+.TP
+[\fB!\fP] \fB\-\-tunnel\-dst\fP \fIaddr\fP[\fB/\fP\fImask\fP]
+Matches the destination end-point address of a tunnel mode SA.
+Only valid with \fB\-\-mode tunnel\fP.
+.TP
+\fB\-\-next\fP
+Start the next element in the policy specification. Can only be used with
+\fB\-\-strict\fP.
diff --git a/ap/app/iptables/extensions/libxt_quota.c b/ap/app/iptables/extensions/libxt_quota.c
new file mode 100755
index 0000000..2657b2a
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_quota.c
@@ -0,0 +1,93 @@
+/*
+ * Shared library add-on to iptables to add quota support
+ *
+ * Sam Johnston <samj@samj.net>
+ */
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+
+#include <linux/netfilter/xt_quota.h>
+
+static const struct option quota_opts[] = {
+	{"quota", 1, NULL, '1'},
+	{ .name = NULL }
+};
+
+static void quota_help(void)
+{
+	printf("quota match options:\n"
+	       " --quota quota			quota (bytes)\n");
+}
+
+static void
+quota_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	struct xt_quota_info *q = (struct xt_quota_info *) match->data;
+	printf("quota: %llu bytes", (unsigned long long) q->quota);
+}
+
+static void
+quota_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct xt_quota_info *q = (struct xt_quota_info *) match->data;
+	printf("--quota %llu ", (unsigned long long) q->quota);
+}
+
+/* parse quota option */
+static int
+parse_quota(const char *s, u_int64_t * quota)
+{
+	*quota = strtoull(s, NULL, 10);
+
+#ifdef DEBUG_XT_QUOTA
+	printf("Quota: %llu\n", *quota);
+#endif
+
+	if (*quota == UINT64_MAX)
+		xtables_error(PARAMETER_PROBLEM, "quota invalid: '%s'\n", s);
+	else
+		return 1;
+}
+
+static int
+quota_parse(int c, char **argv, int invert, unsigned int *flags,
+	    const void *entry, struct xt_entry_match **match)
+{
+	struct xt_quota_info *info = (struct xt_quota_info *) (*match)->data;
+
+	switch (c) {
+	case '1':
+		if (xtables_check_inverse(optarg, &invert, NULL, 0))
+			xtables_error(PARAMETER_PROBLEM, "quota: unexpected '!'");
+		if (!parse_quota(optarg, &info->quota))
+			xtables_error(PARAMETER_PROBLEM,
+				   "bad quota: '%s'", optarg);
+		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static struct xtables_match quota_match = {
+	.family		= AF_UNSPEC,
+	.name		= "quota",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof (struct xt_quota_info)),
+	.userspacesize	= offsetof(struct xt_quota_info, quota),
+	.help		= quota_help,
+	.parse		= quota_parse,
+	.print		= quota_print,
+	.save		= quota_save,
+	.extra_opts	= quota_opts,
+};
+
+void
+_init(void)
+{
+	xtables_register_match(&quota_match);
+}
diff --git a/ap/app/iptables/extensions/libxt_quota.man b/ap/app/iptables/extensions/libxt_quota.man
new file mode 100755
index 0000000..f8bf77b
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_quota.man
@@ -0,0 +1,6 @@
+Implements network quotas by decrementing a byte counter with each
+packet.
+.TP
+\fB\-\-quota\fP \fIbytes\fP
+The quota in bytes.
+.P
diff --git a/ap/app/iptables/extensions/libxt_rateest.c b/ap/app/iptables/extensions/libxt_rateest.c
new file mode 100755
index 0000000..3cff07d
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_rateest.c
@@ -0,0 +1,450 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_rateest.h>
+
+/* Ugly hack to pass info to final_check function. We should fix the API */
+static struct xt_rateest_match_info *rateest_info;
+
+static void rateest_help(void)
+{
+	printf(
+"rateest match options:\n"
+" --rateest1 name		Rate estimator name\n"
+" --rateest2 name		Rate estimator name\n"
+" --rateest-delta		Compare difference(s) to given rate(s)\n"
+" --rateest-bps1 [bps]		Compare bps\n"
+" --rateest-pps1 [pps]		Compare pps\n"
+" --rateest-bps2 [bps]		Compare bps\n"
+" --rateest-pps2 [pps]		Compare pps\n"
+" [!] --rateest-lt		Match if rate is less than given rate/estimator\n"
+" [!] --rateest-gt		Match if rate is greater than given rate/estimator\n"
+" [!] --rateest-eq		Match if rate is equal to given rate/estimator\n");
+}
+
+enum rateest_options {
+	OPT_RATEEST1,
+	OPT_RATEEST2,
+	OPT_RATEEST_BPS1,
+	OPT_RATEEST_PPS1,
+	OPT_RATEEST_BPS2,
+	OPT_RATEEST_PPS2,
+	OPT_RATEEST_DELTA,
+	OPT_RATEEST_LT,
+	OPT_RATEEST_GT,
+	OPT_RATEEST_EQ,
+};
+
+static const struct option rateest_opts[] = {
+	{ "rateest1",		1, NULL, OPT_RATEEST1 },
+	{ "rateest",		1, NULL, OPT_RATEEST1 }, /* alias for absolute mode */
+	{ "rateest2",		1, NULL, OPT_RATEEST2 },
+	{ "rateest-bps1",	0, NULL, OPT_RATEEST_BPS1 },
+	{ "rateest-pps1",	0, NULL, OPT_RATEEST_PPS1 },
+	{ "rateest-bps2",	0, NULL, OPT_RATEEST_BPS2 },
+	{ "rateest-pps2",	0, NULL, OPT_RATEEST_PPS2 },
+	{ "rateest-bps",	0, NULL, OPT_RATEEST_BPS2 }, /* alias for absolute mode */
+	{ "rateest-pps",	0, NULL, OPT_RATEEST_PPS2 }, /* alias for absolute mode */
+	{ "rateest-delta",	0, NULL, OPT_RATEEST_DELTA },
+	{ "rateest-lt",		0, NULL, OPT_RATEEST_LT },
+	{ "rateest-gt",		0, NULL, OPT_RATEEST_GT },
+	{ "rateest-eq",		0, NULL, OPT_RATEEST_EQ },
+	{ .name = NULL }
+};
+
+/* Copied from iproute. See http://physics.nist.gov/cuu/Units/binary.html */
+static const struct rate_suffix {
+	const char *name;
+	double scale;
+} suffixes[] = {
+	{ "bit",	1. },
+	{ "Kibit",	1024. },
+	{ "kbit",	1000. },
+	{ "mibit",	1024.*1024. },
+	{ "mbit",	1000000. },
+	{ "gibit",	1024.*1024.*1024. },
+	{ "gbit",	1000000000. },
+	{ "tibit",	1024.*1024.*1024.*1024. },
+	{ "tbit",	1000000000000. },
+	{ "Bps",	8. },
+	{ "KiBps",	8.*1024. },
+	{ "KBps",	8000. },
+	{ "MiBps",	8.*1024*1024. },
+	{ "MBps",	8000000. },
+	{ "GiBps",	8.*1024.*1024.*1024. },
+	{ "GBps",	8000000000. },
+	{ "TiBps",	8.*1024.*1024.*1024.*1024. },
+	{ "TBps",	8000000000000. },
+	{ .name = NULL }
+};
+
+static int
+rateest_get_rate(u_int32_t *rate, const char *str)
+{
+	char *p;
+	double bps = strtod(str, &p);
+	const struct rate_suffix *s;
+
+	if (p == str)
+		return -1;
+
+	if (*p == '\0') {
+		*rate = bps / 8.;	/* assume bytes/sec */
+		return 0;
+	}
+
+	for (s = suffixes; s->name; ++s) {
+		if (strcasecmp(s->name, p) == 0) {
+			*rate = (bps * s->scale) / 8.;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static int
+rateest_parse(int c, char **argv, int invert, unsigned int *flags,
+	      const void *entry, struct xt_entry_match **match)
+{
+	struct xt_rateest_match_info *info = (void *)(*match)->data;
+	unsigned int val;
+
+	rateest_info = info;
+
+	switch (c) {
+	case OPT_RATEEST1:
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: rateest can't be inverted");
+
+		if (*flags & (1 << c))
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: can't specify --rateest1 twice");
+		*flags |= 1 << c;
+
+		strncpy(info->name1, optarg, sizeof(info->name1) - 1);
+		break;
+
+	case OPT_RATEEST2:
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: rateest can't be inverted");
+
+		if (*flags & (1 << c))
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: can't specify --rateest2 twice");
+		*flags |= 1 << c;
+
+		strncpy(info->name2, optarg, sizeof(info->name2) - 1);
+		info->flags |= XT_RATEEST_MATCH_REL;
+		break;
+
+	case OPT_RATEEST_BPS1:
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: rateest-bps can't be inverted");
+
+		if (*flags & (1 << c))
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: can't specify --rateest-bps1 twice");
+		*flags |= 1 << c;
+
+		info->flags |= XT_RATEEST_MATCH_BPS;
+
+		/* The rate is optional and only required in absolute mode */
+		if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!')
+			break;
+
+		if (rateest_get_rate(&info->bps1, argv[optind]) < 0)
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: could not parse rate `%s'",
+				   argv[optind]);
+		optind++;
+		break;
+
+	case OPT_RATEEST_PPS1:
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: rateest-pps can't be inverted");
+
+		if (*flags & (1 << c))
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: can't specify --rateest-pps1 twice");
+		*flags |= 1 << c;
+
+		info->flags |= XT_RATEEST_MATCH_PPS;
+
+		/* The rate is optional and only required in absolute mode */
+		if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!')
+			break;
+
+		if (!xtables_strtoui(argv[optind], NULL, &val, 0, UINT32_MAX))
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: could not parse pps `%s'",
+				   argv[optind]);
+		info->pps1 = val;
+		optind++;
+		break;
+
+	case OPT_RATEEST_BPS2:
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: rateest-bps can't be inverted");
+
+		if (*flags & (1 << c))
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: can't specify --rateest-bps2 twice");
+		*flags |= 1 << c;
+
+		info->flags |= XT_RATEEST_MATCH_BPS;
+
+		/* The rate is optional and only required in absolute mode */
+		if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!')
+			break;
+
+		if (rateest_get_rate(&info->bps2, argv[optind]) < 0)
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: could not parse rate `%s'",
+				   argv[optind]);
+		optind++;
+		break;
+
+	case OPT_RATEEST_PPS2:
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: rateest-pps can't be inverted");
+
+		if (*flags & (1 << c))
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: can't specify --rateest-pps2 twice");
+		*flags |= 1 << c;
+
+		info->flags |= XT_RATEEST_MATCH_PPS;
+
+		/* The rate is optional and only required in absolute mode */
+		if (!argv[optind] || *argv[optind] == '-' || *argv[optind] == '!')
+			break;
+
+		if (!xtables_strtoui(argv[optind], NULL, &val, 0, UINT32_MAX))
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: could not parse pps `%s'",
+				   argv[optind]);
+		info->pps2 = val;
+		optind++;
+		break;
+
+	case OPT_RATEEST_DELTA:
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: rateest-delta can't be inverted");
+
+		if (*flags & (1 << c))
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: can't specify --rateest-delta twice");
+		*flags |= 1 << c;
+
+		info->flags |= XT_RATEEST_MATCH_DELTA;
+		break;
+
+	case OPT_RATEEST_EQ:
+		xtables_check_inverse(argv[optind-1], &invert, &optind, 0);
+
+		if (*flags & (1 << c))
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: can't specify lt/gt/eq twice");
+		*flags |= 1 << c;
+
+		info->mode = XT_RATEEST_MATCH_EQ;
+		if (invert)
+			info->flags |= XT_RATEEST_MATCH_INVERT;
+		break;
+
+	case OPT_RATEEST_LT:
+		xtables_check_inverse(argv[optind-1], &invert, &optind, 0);
+
+		if (*flags & (1 << c))
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: can't specify lt/gt/eq twice");
+		*flags |= 1 << c;
+
+		info->mode = XT_RATEEST_MATCH_LT;
+		if (invert)
+			info->flags |= XT_RATEEST_MATCH_INVERT;
+		break;
+
+	case OPT_RATEEST_GT:
+		xtables_check_inverse(argv[optind-1], &invert, &optind, 0);
+
+		if (*flags & (1 << c))
+			xtables_error(PARAMETER_PROBLEM,
+				   "rateest: can't specify lt/gt/eq twice");
+		*flags |= 1 << c;
+
+		info->mode = XT_RATEEST_MATCH_GT;
+		if (invert)
+			info->flags |= XT_RATEEST_MATCH_INVERT;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+rateest_final_check(unsigned int flags)
+{
+	struct xt_rateest_match_info *info = rateest_info;
+
+	if (info == NULL)
+		xtables_error(PARAMETER_PROBLEM, "rateest match: "
+		           "you need to specify some flags");
+	if (!(info->flags & XT_RATEEST_MATCH_REL))
+		info->flags |= XT_RATEEST_MATCH_ABS;
+}
+
+static void
+rateest_print_rate(u_int32_t rate, int numeric)
+{
+	double tmp = (double)rate*8;
+
+	if (numeric)
+		printf("%u ", rate);
+	else if (tmp >= 1000.0*1000000.0)
+		printf("%.0fMbit ", tmp/1000000.0);
+	else if (tmp >= 1000.0 * 1000.0)
+		printf("%.0fKbit ", tmp/1000.0);
+	else
+		printf("%.0fbit ", tmp);
+}
+
+static void
+rateest_print_mode(struct xt_rateest_match_info *info, const char *prefix)
+{
+	if (info->flags & XT_RATEEST_MATCH_INVERT)
+		printf("! ");
+
+	switch (info->mode) {
+	case XT_RATEEST_MATCH_EQ:
+		printf("%seq ", prefix);
+		break;
+	case XT_RATEEST_MATCH_LT:
+		printf("%slt ", prefix);
+		break;
+	case XT_RATEEST_MATCH_GT:
+		printf("%sgt ", prefix);
+		break;
+	default:
+		exit(1);
+	}
+}
+
+static void
+rateest_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	struct xt_rateest_match_info *info = (void *)match->data;
+
+	printf("rateest match ");
+
+	printf("%s ", info->name1);
+	if (info->flags & XT_RATEEST_MATCH_DELTA)
+		printf("delta ");
+
+	if (info->flags & XT_RATEEST_MATCH_BPS) {
+		printf("bps ");
+		if (info->flags & XT_RATEEST_MATCH_DELTA)
+			rateest_print_rate(info->bps1, numeric);
+		if (info->flags & XT_RATEEST_MATCH_ABS) {
+			rateest_print_mode(info, "");
+			rateest_print_rate(info->bps2, numeric);
+		}
+	}
+	if (info->flags & XT_RATEEST_MATCH_PPS) {
+		printf("pps ");
+		if (info->flags & XT_RATEEST_MATCH_DELTA)
+			printf("%u ", info->pps1);
+		if (info->flags & XT_RATEEST_MATCH_ABS) {
+			rateest_print_mode(info, "");
+			printf("%u ", info->pps2);
+		}
+	}
+
+	if (info->flags & XT_RATEEST_MATCH_REL) {
+		rateest_print_mode(info, "");
+
+		printf("%s ", info->name2);
+		if (info->flags & XT_RATEEST_MATCH_DELTA)
+			printf("delta ");
+
+		if (info->flags & XT_RATEEST_MATCH_BPS) {
+			printf("bps ");
+			if (info->flags & XT_RATEEST_MATCH_DELTA)
+				rateest_print_rate(info->bps2, numeric);
+		}
+		if (info->flags & XT_RATEEST_MATCH_PPS) {
+			printf("pps ");
+			if (info->flags & XT_RATEEST_MATCH_DELTA)
+				printf("%u ", info->pps2);
+		}
+	}
+}
+
+static void
+rateest_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct xt_rateest_match_info *info = (void *)match->data;
+
+	if (info->flags & XT_RATEEST_MATCH_REL) {
+		printf("--rateest1 %s ", info->name1);
+		if (info->flags & XT_RATEEST_MATCH_BPS)
+			printf("--rateest-bps ");
+		if (info->flags & XT_RATEEST_MATCH_PPS)
+			printf("--rateest-pps ");
+		rateest_print_mode(info, "--rateest-");
+		printf("--rateest2 %s ", info->name2);
+	} else {
+		printf("--rateest %s ", info->name1);
+		if (info->flags & XT_RATEEST_MATCH_BPS) {
+			printf("--rateest-bps ");
+			rateest_print_mode(info, "--rateest-");
+			rateest_print_rate(info->bps2, 0);
+		}
+		if (info->flags & XT_RATEEST_MATCH_PPS) {
+			printf("--rateest-pps ");
+			rateest_print_mode(info, "--rateest-");
+			printf("%u ", info->pps2);
+		}
+	}
+}
+
+static struct xtables_match rateest_mt_reg = {
+	.family		= AF_UNSPEC,
+	.name		= "rateest",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_rateest_match_info)),
+	.userspacesize	= XT_ALIGN(offsetof(struct xt_rateest_match_info, est1)),
+	.help		= rateest_help,
+	.parse		= rateest_parse,
+	.final_check	= rateest_final_check,
+	.print		= rateest_print,
+	.save		= rateest_save,
+	.extra_opts	= rateest_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&rateest_mt_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_rateest.man b/ap/app/iptables/extensions/libxt_rateest.man
new file mode 100755
index 0000000..24c0673
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_rateest.man
@@ -0,0 +1,55 @@
+The rate estimator can match on estimated rates as collected by the RATEEST
+target. It supports matching on absolute bps/pps values, comparing two rate
+estimators and matching on the difference between two rate estimators.
+.TP
+\fB\-\-rateest1\fP \fIname\fP
+Name of the first rate estimator.
+.TP
+\fB\-\-rateest2\fP \fIname\fP
+Name of the second rate estimator (if difference is to be calculated).
+.TP
+\fB\-\-rateest\-delta\fP
+Compare difference(s) to given rate(s)
+.TP
+\fB\-\-rateest1\-bps\fP \fIvalue\fP
+.TP
+\fB\-\-rateest2\-bps\fP \fIvalue\fP
+Compare bytes per second.
+.TP
+\fB\-\-rateest1\-pps\fP \fIvalue\fP
+.TP
+\fB\-\-rateest2\-pps\fP \fIvalue\fP
+Compare packets per second.
+.TP
+[\fB!\fP] \fB\-\-rateest\-lt\fP
+Match if rate is less than given rate/estimator.
+.TP
+[\fB!\fP] \fB\-\-rateest\-gt\fP
+Match if rate is greater than given rate/estimator.
+.TP
+[\fB!\fP] \fB\-\-rateest\-eq\fP
+Match if rate is equal to given rate/estimator.
+.PP
+Example: This is what can be used to route outgoing data connections from an
+FTP server over two lines based on the available bandwidth at the time the data
+connection was started:
+.PP
+# Estimate outgoing rates
+.PP
+iptables \-t mangle \-A POSTROUTING \-o eth0 \-j RATEEST \-\-rateest\-name eth0
+\-\-rateest\-interval 250ms \-\-rateest\-ewma 0.5s
+.PP
+iptables \-t mangle \-A POSTROUTING \-o ppp0 \-j RATEEST \-\-rateest\-name ppp0
+\-\-rateest\-interval 250ms \-\-rateest\-ewma 0.5s
+.PP
+# Mark based on available bandwidth
+.PP
+iptables \-t mangle \-A balance \-m conntrack \-\-ctstate NEW \-m helper \-\-helper ftp
+\-m rateest \-\-rateest\-delta \-\-rateest1 eth0 \-\-rateest\-bps1 2.5mbit \-\-rateest\-gt
+\-\-rateest2 ppp0 \-\-rateest\-bps2 2mbit \-j CONNMARK \-\-set\-mark 1
+.PP
+iptables \-t mangle \-A balance \-m conntrack \-\-ctstate NEW \-m helper \-\-helper ftp
+\-m rateest \-\-rateest\-delta \-\-rateest1 ppp0 \-\-rateest\-bps1 2mbit \-\-rateest\-gt
+\-\-rateest2 eth0 \-\-rateest\-bps2 2.5mbit \-j CONNMARK \-\-set\-mark 2
+.PP
+iptables \-t mangle \-A balance \-j CONNMARK \-\-restore\-mark
diff --git a/ap/app/iptables/extensions/libxt_recent.c b/ap/app/iptables/extensions/libxt_recent.c
new file mode 100755
index 0000000..47c35ff
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_recent.c
@@ -0,0 +1,250 @@
+/* Shared library add-on to iptables to add recent matching support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_recent.h>
+
+static const struct option recent_opts[] = {
+	{ .name = "set",      .has_arg = 0, .val = 201 },
+	{ .name = "rcheck",   .has_arg = 0, .val = 202 },
+	{ .name = "update",   .has_arg = 0, .val = 203 },
+	{ .name = "seconds",  .has_arg = 1, .val = 204 },
+	{ .name = "hitcount", .has_arg = 1, .val = 205 },
+	{ .name = "remove",   .has_arg = 0, .val = 206 },
+	{ .name = "rttl",     .has_arg = 0, .val = 207 },
+	{ .name = "name",     .has_arg = 1, .val = 208 },
+	{ .name = "rsource",  .has_arg = 0, .val = 209 },
+	{ .name = "rdest",    .has_arg = 0, .val = 210 },
+	{ .name = NULL }
+};
+
+static void recent_help(void)
+{
+	printf(
+"recent match options:\n"
+"[!] --set                       Add source address to list, always matches.\n"
+"[!] --rcheck                    Match if source address in list.\n"
+"[!] --update                    Match if source address in list, also update last-seen time.\n"
+"[!] --remove                    Match if source address in list, also removes that address from list.\n"
+"    --seconds seconds           For check and update commands above.\n"
+"                                Specifies that the match will only occur if source address last seen within\n"
+"                                the last 'seconds' seconds.\n"
+"    --hitcount hits             For check and update commands above.\n"
+"                                Specifies that the match will only occur if source address seen hits times.\n"
+"                                May be used in conjunction with the seconds option.\n"
+"    --rttl                      For check and update commands above.\n"
+"                                Specifies that the match will only occur if the source address and the TTL\n"
+"                                match between this packet and the one which was set.\n"
+"                                Useful if you have problems with people spoofing their source address in order\n"
+"                                to DoS you via this module.\n"
+"    --name name                 Name of the recent list to be used.  DEFAULT used if none given.\n"
+"    --rsource                   Match/Save the source address of each packet in the recent list table (default).\n"
+"    --rdest                     Match/Save the destination address of each packet in the recent list table.\n"
+"xt_recent by: Stephen Frost <sfrost@snowman.net>.  http://snowman.net/projects/ipt_recent/\n");
+}
+
+static void recent_init(struct xt_entry_match *match)
+{
+	struct xt_recent_mtinfo *info = (void *)(match)->data;
+
+	strncpy(info->name,"DEFAULT", XT_RECENT_NAME_LEN);
+	/* even though XT_RECENT_NAME_LEN is currently defined as 200,
+	 * better be safe, than sorry */
+	info->name[XT_RECENT_NAME_LEN-1] = '\0';
+	info->side = XT_RECENT_SOURCE;
+}
+
+#define RECENT_CMDS \
+	(XT_RECENT_SET | XT_RECENT_CHECK | \
+	XT_RECENT_UPDATE | XT_RECENT_REMOVE)
+
+static int recent_parse(int c, char **argv, int invert, unsigned int *flags,
+                        const void *entry, struct xt_entry_match **match)
+{
+	struct xt_recent_mtinfo *info = (void *)(*match)->data;
+
+	switch (c) {
+		case 201:
+			if (*flags & RECENT_CMDS)
+				xtables_error(PARAMETER_PROBLEM,
+					"recent: only one of `--set', `--rcheck' "
+					"`--update' or `--remove' may be set");
+			xtables_check_inverse(optarg, &invert, &optind, 0);
+			info->check_set |= XT_RECENT_SET;
+			if (invert) info->invert = 1;
+			*flags |= XT_RECENT_SET;
+			break;
+
+		case 202:
+			if (*flags & RECENT_CMDS)
+				xtables_error(PARAMETER_PROBLEM,
+					"recent: only one of `--set', `--rcheck' "
+					"`--update' or `--remove' may be set");
+			xtables_check_inverse(optarg, &invert, &optind, 0);
+			info->check_set |= XT_RECENT_CHECK;
+			if(invert) info->invert = 1;
+			*flags |= XT_RECENT_CHECK;
+			break;
+
+		case 203:
+			if (*flags & RECENT_CMDS)
+				xtables_error(PARAMETER_PROBLEM,
+					"recent: only one of `--set', `--rcheck' "
+					"`--update' or `--remove' may be set");
+			xtables_check_inverse(optarg, &invert, &optind, 0);
+			info->check_set |= XT_RECENT_UPDATE;
+			if (invert) info->invert = 1;
+			*flags |= XT_RECENT_UPDATE;
+			break;
+
+		case 206:
+			if (*flags & RECENT_CMDS)
+				xtables_error(PARAMETER_PROBLEM,
+					"recent: only one of `--set', `--rcheck' "
+					"`--update' or `--remove' may be set");
+			xtables_check_inverse(optarg, &invert, &optind, 0);
+			info->check_set |= XT_RECENT_REMOVE;
+			if (invert) info->invert = 1;
+			*flags |= XT_RECENT_REMOVE;
+			break;
+
+		case 204:
+			info->seconds = atoi(optarg);
+			break;
+
+		case 205:
+			info->hit_count = atoi(optarg);
+			break;
+
+		case 207:
+			info->check_set |= XT_RECENT_TTL;
+			*flags |= XT_RECENT_TTL;
+			break;
+
+		case 208:
+			strncpy(info->name,optarg, XT_RECENT_NAME_LEN);
+			info->name[XT_RECENT_NAME_LEN-1] = '\0';
+			break;
+
+		case 209:
+			info->side = XT_RECENT_SOURCE;
+			break;
+
+		case 210:
+			info->side = XT_RECENT_DEST;
+			break;
+
+		default:
+			return 0;
+	}
+
+	return 1;
+}
+
+static void recent_check(unsigned int flags)
+{
+	if (!(flags & RECENT_CMDS))
+		xtables_error(PARAMETER_PROBLEM,
+			"recent: you must specify one of `--set', `--rcheck' "
+			"`--update' or `--remove'");
+	if ((flags & XT_RECENT_TTL) &&
+	    (flags & (XT_RECENT_SET | XT_RECENT_REMOVE)))
+		xtables_error(PARAMETER_PROBLEM,
+		           "recent: --rttl may only be used with --rcheck or "
+		           "--update");
+}
+
+static void recent_print(const void *ip, const struct xt_entry_match *match,
+                         int numeric)
+{
+	const struct xt_recent_mtinfo *info = (const void *)match->data;
+
+	if (info->invert)
+		fputc('!', stdout);
+
+	printf("recent: ");
+	if (info->check_set & XT_RECENT_SET)
+		printf("SET ");
+	if (info->check_set & XT_RECENT_CHECK)
+		printf("CHECK ");
+	if (info->check_set & XT_RECENT_UPDATE)
+		printf("UPDATE ");
+	if (info->check_set & XT_RECENT_REMOVE)
+		printf("REMOVE ");
+	if(info->seconds) printf("seconds: %d ",info->seconds);
+	if(info->hit_count) printf("hit_count: %d ",info->hit_count);
+	if (info->check_set & XT_RECENT_TTL)
+		printf("TTL-Match ");
+	if(info->name) printf("name: %s ",info->name);
+	if (info->side == XT_RECENT_SOURCE)
+		printf("side: source ");
+	if (info->side == XT_RECENT_DEST)
+		printf("side: dest");
+}
+
+static void recent_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_recent_mtinfo *info = (const void *)match->data;
+
+	if (info->invert)
+		printf("! ");
+
+	if (info->check_set & XT_RECENT_SET)
+		printf("--set ");
+	if (info->check_set & XT_RECENT_CHECK)
+		printf("--rcheck ");
+	if (info->check_set & XT_RECENT_UPDATE)
+		printf("--update ");
+	if (info->check_set & XT_RECENT_REMOVE)
+		printf("--remove ");
+	if(info->seconds) printf("--seconds %d ",info->seconds);
+	if(info->hit_count) printf("--hitcount %d ",info->hit_count);
+	if (info->check_set & XT_RECENT_TTL)
+		printf("--rttl ");
+	if(info->name) printf("--name %s ",info->name);
+	if (info->side == XT_RECENT_SOURCE)
+		printf("--rsource ");
+	if (info->side == XT_RECENT_DEST)
+		printf("--rdest ");
+}
+
+static struct xtables_match recent_mt_reg = {
+    .name          = "recent",
+    .version       = XTABLES_VERSION,
+    .family        = NFPROTO_IPV4,
+    .size          = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
+    .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
+    .help          = recent_help,
+    .init          = recent_init,
+    .parse         = recent_parse,
+    .final_check   = recent_check,
+    .print         = recent_print,
+    .save          = recent_save,
+    .extra_opts    = recent_opts,
+};
+
+static struct xtables_match recent_mt6_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "recent",
+	.revision      = 0,
+	.family        = NFPROTO_IPV6,
+	.size          = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)),
+	.help          = recent_help,
+	.init          = recent_init,
+	.parse         = recent_parse,
+	.final_check   = recent_check,
+	.print         = recent_print,
+	.save          = recent_save,
+	.extra_opts    = recent_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&recent_mt_reg);
+	xtables_register_match(&recent_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_recent.man b/ap/app/iptables/extensions/libxt_recent.man
new file mode 100755
index 0000000..e03d8ec
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_recent.man
@@ -0,0 +1,99 @@
+Allows you to dynamically create a list of IP addresses and then match against
+that list in a few different ways.
+.PP
+For example, you can create a "badguy" list out of people attempting to connect
+to port 139 on your firewall and then DROP all future packets from them without
+considering them.
+.TP
+\fB\-\-name\fP \fIname\fP
+Specify the list to use for the commands. If no name is given then
+\fBDEFAULT\fR will be used.
+.TP
+[\fB!\fR] \fB\-\-set\fP
+This will add the source address of the packet to the list. If the source
+address is already in the list, this will update the existing entry. This will
+always return success (or failure if \fB!\fR is passed in).
+.TP
+\fB\-\-rsource\fP
+Match/save the source address of each packet in the recent list table. This
+is the default.
+.TP
+\fB\-\-rdest\fP
+Match/save the destination address of each packet in the recent list table.
+.TP
+[\fB!\fR] \fB\-\-rcheck\fP
+Check if the source address of the packet is currently in the list.
+.TP
+[\fB!\fR] \fB\-\-update\fP
+Like \fB\-\-rcheck\fP, except it will update the "last seen" timestamp if it
+matches.
+.TP
+[\fB!\fR] \fB\-\-remove\fP
+Check if the source address of the packet is currently in the list and if so
+that address will be removed from the list and the rule will return true. If
+the address is not found, false is returned.
+.TP
+[\fB!\fR] \fB\-\-seconds \fIseconds\fP
+This option must be used in conjunction with one of \fB\-\-rcheck\fP or
+\fB\-\-update\fP. When used, this will narrow the match to only happen when the
+address is in the list and was seen within the last given number of seconds.
+.TP
+[\fB!\fR] \fB\-\-hitcount \fIhits\fP
+This option must be used in conjunction with one of \fB\-\-rcheck\fP or
+\fB\-\-update\fP. When used, this will narrow the match to only happen when the
+address is in the list and packets had been received greater than or equal to
+the given value. This option may be used along with \fB\-\-seconds\fP to create
+an even narrower match requiring a certain number of hits within a specific
+time frame.
+.TP
+\fB\-\-rttl\fP
+This option may only be used in conjunction with one of \fB\-\-rcheck\fP or
+\fB\-\-update\fP. When used, this will narrow the match to only happen when the
+address is in the list and the TTL of the current packet matches that of the
+packet which hit the \fB\-\-set\fP rule. This may be useful if you have problems
+with people faking their source address in order to DoS you via this module by
+disallowing others access to your site by sending bogus packets to you.
+.PP
+Examples:
+.IP
+iptables \-A FORWARD \-m recent \-\-name badguy \-\-rcheck \-\-seconds 60 \-j DROP
+.IP
+iptables \-A FORWARD \-p tcp \-i eth0 \-\-dport 139 \-m recent \-\-name badguy \-\-set \-j DROP
+.PP
+Steve's ipt_recent website (http://snowman.net/projects/ipt_recent/) also has
+some examples of usage.
+.PP
+\fB/proc/net/xt_recent/*\fR are the current lists of addresses and information
+about each entry of each list.
+.PP
+Each file in \fB/proc/net/xt_recent/\fR can be read from to see the current
+list or written two using the following commands to modify the list:
+.TP
+\fBecho +\fR\fIaddr\fR\fB >/proc/net/xt_recent/DEFAULT\fR
+to add \fIaddr\fR to the DEFAULT list
+.TP
+\fBecho \-\fP\fIaddr\fP\fB >/proc/net/xt_recent/DEFAULT\fP
+to remove \fIaddr\fR from the DEFAULT list
+.TP
+\fBecho / >/proc/net/xt_recent/DEFAULT\fR
+to flush the DEFAULT list (remove all entries).
+.PP
+The module itself accepts parameters, defaults shown:
+.TP
+\fBip_list_tot\fR=\fI100\fR
+Number of addresses remembered per table.
+.TP
+\fBip_pkt_list_tot\fR=\fI20\fR
+Number of packets per address remembered.
+.TP
+\fBip_list_hash_size\fR=\fI0\fR
+Hash table size. 0 means to calculate it based on ip_list_tot, default: 512.
+.TP
+\fBip_list_perms\fR=\fI0644\fR
+Permissions for /proc/net/xt_recent/* files.
+.TP
+\fBip_list_uid\fR=\fI0\fR
+Numerical UID for ownership of /proc/net/xt_recent/* files.
+.TP
+\fBip_list_gid\fR=\fI0\fR
+Numerical GID for ownership of /proc/net/xt_recent/* files.
diff --git a/ap/app/iptables/extensions/libxt_sctp.c b/ap/app/iptables/extensions/libxt_sctp.c
new file mode 100755
index 0000000..b889406
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_sctp.c
@@ -0,0 +1,543 @@
+/* Shared library add-on to iptables for SCTP matching
+ *
+ * (C) 2003 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This program is distributed under the terms of GNU GPL v2, 1991
+ *
+ * libipt_ecn.c borrowed heavily from libipt_dscp.c
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <ctype.h>
+
+#include <netinet/in.h>
+#include <xtables.h>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#include <linux/netfilter/xt_sctp.h>
+
+/* Some ZS!#@:$%*#$! has replaced the ELEMCOUNT macro in ipt_sctp.h with
+ * ARRAY_SIZE without noticing that this file is used from userspace,
+ * and userspace doesn't have ARRAY_SIZE */
+
+#ifndef ELEMCOUNT
+#define ELEMCOUNT ARRAY_SIZE
+#endif
+
+#if 0
+#define DEBUGP(format, first...) printf(format, ##first)
+#define static
+#else
+#define DEBUGP(format, fist...) 
+#endif
+
+static void
+print_chunk(u_int32_t chunknum, int numeric);
+
+static void sctp_init(struct xt_entry_match *m)
+{
+	int i;
+	struct xt_sctp_info *einfo = (struct xt_sctp_info *)m->data;
+
+	memset(einfo, 0, sizeof(struct xt_sctp_info));
+
+	for (i = 0; i < XT_NUM_SCTP_FLAGS; i++) {
+		einfo->flag_info[i].chunktype = -1;
+	}
+}
+
+static void sctp_help(void)
+{
+	printf(
+"sctp match options\n"
+"[!] --source-port port[:port]                          match source port(s)\n"
+" --sport ...\n"
+"[!] --destination-port port[:port]                     match destination port(s)\n"
+" --dport ...\n" 
+"[!] --chunk-types (all|any|none) (chunktype[:flags])+	match if all, any or none of\n"
+"						        chunktypes are present\n"
+"chunktypes - DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE ASCONF ASCONF_ACK ALL NONE\n");
+}
+
+static const struct option sctp_opts[] = {
+	{ .name = "source-port", .has_arg = 1, .val = '1' },
+	{ .name = "sport", .has_arg = 1, .val = '1' },
+	{ .name = "destination-port", .has_arg = 1, .val = '2' },
+	{ .name = "dport", .has_arg = 1, .val = '2' },
+	{ .name = "chunk-types", .has_arg = 1, .val = '3' },
+	{ .name = NULL }
+};
+
+static void
+parse_sctp_ports(const char *portstring, 
+		 u_int16_t *ports)
+{
+	char *buffer;
+	char *cp;
+
+	buffer = strdup(portstring);
+	DEBUGP("%s\n", portstring);
+	if ((cp = strchr(buffer, ':')) == NULL) {
+		ports[0] = ports[1] = xtables_parse_port(buffer, "sctp");
+	}
+	else {
+		*cp = '\0';
+		cp++;
+
+		ports[0] = buffer[0] ? xtables_parse_port(buffer, "sctp") : 0;
+		ports[1] = cp[0] ? xtables_parse_port(cp, "sctp") : 0xFFFF;
+
+		if (ports[0] > ports[1])
+			xtables_error(PARAMETER_PROBLEM,
+				   "invalid portrange (min > max)");
+	}
+	free(buffer);
+}
+
+struct sctp_chunk_names {
+	const char *name;
+	unsigned int chunk_type;
+	const char *valid_flags;
+};
+
+/*'ALL' and 'NONE' will be treated specially. */
+static const struct sctp_chunk_names sctp_chunk_names[]
+= { { .name = "DATA", 		.chunk_type = 0,   .valid_flags = "-----UBE"},
+    { .name = "INIT", 		.chunk_type = 1,   .valid_flags = "--------"},
+    { .name = "INIT_ACK", 	.chunk_type = 2,   .valid_flags = "--------"},
+    { .name = "SACK",		.chunk_type = 3,   .valid_flags = "--------"},
+    { .name = "HEARTBEAT",	.chunk_type = 4,   .valid_flags = "--------"},
+    { .name = "HEARTBEAT_ACK",	.chunk_type = 5,   .valid_flags = "--------"},
+    { .name = "ABORT",		.chunk_type = 6,   .valid_flags = "-------T"},
+    { .name = "SHUTDOWN",	.chunk_type = 7,   .valid_flags = "--------"},
+    { .name = "SHUTDOWN_ACK",	.chunk_type = 8,   .valid_flags = "--------"},
+    { .name = "ERROR",		.chunk_type = 9,   .valid_flags = "--------"},
+    { .name = "COOKIE_ECHO",	.chunk_type = 10,  .valid_flags = "--------"},
+    { .name = "COOKIE_ACK",	.chunk_type = 11,  .valid_flags = "--------"},
+    { .name = "ECN_ECNE",	.chunk_type = 12,  .valid_flags = "--------"},
+    { .name = "ECN_CWR",	.chunk_type = 13,  .valid_flags = "--------"},
+    { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14,  .valid_flags = "-------T"},
+    { .name = "ASCONF",		.chunk_type = 193,  .valid_flags = "--------"},
+    { .name = "ASCONF_ACK",	.chunk_type = 128,  .valid_flags = "--------"},
+};
+
+static void
+save_chunk_flag_info(struct xt_sctp_flag_info *flag_info,
+		     int *flag_count,
+		     int chunktype, 
+		     int bit, 
+		     int set)
+{
+	int i;
+
+	for (i = 0; i < *flag_count; i++) {
+		if (flag_info[i].chunktype == chunktype) {
+			DEBUGP("Previous match found\n");
+			flag_info[i].chunktype = chunktype;
+			flag_info[i].flag_mask |= (1 << bit);
+			if (set) {
+				flag_info[i].flag |= (1 << bit);
+			}
+
+			return;
+		}
+	}
+	
+	if (*flag_count == XT_NUM_SCTP_FLAGS) {
+		xtables_error (PARAMETER_PROBLEM,
+			"Number of chunk types with flags exceeds currently allowed limit."
+			"Increasing this limit involves changing IPT_NUM_SCTP_FLAGS and"
+			"recompiling both the kernel space and user space modules\n");
+	}
+
+	flag_info[*flag_count].chunktype = chunktype;
+	flag_info[*flag_count].flag_mask |= (1 << bit);
+	if (set) {
+		flag_info[*flag_count].flag |= (1 << bit);
+	}
+	(*flag_count)++;
+}
+
+static void
+parse_sctp_chunk(struct xt_sctp_info *einfo, 
+		 const char *chunks)
+{
+	char *ptr;
+	char *buffer;
+	unsigned int i, j;
+	int found = 0;
+	char *chunk_flags;
+
+	buffer = strdup(chunks);
+	DEBUGP("Buffer: %s\n", buffer);
+
+	SCTP_CHUNKMAP_RESET(einfo->chunkmap);
+
+	if (!strcasecmp(buffer, "ALL")) {
+		SCTP_CHUNKMAP_SET_ALL(einfo->chunkmap);
+		goto out;
+	}
+	
+	if (!strcasecmp(buffer, "NONE")) {
+		SCTP_CHUNKMAP_RESET(einfo->chunkmap);
+		goto out;
+	}
+
+	for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
+		found = 0;
+		DEBUGP("Next Chunk type %s\n", ptr);
+		
+		if ((chunk_flags = strchr(ptr, ':')) != NULL) {
+			*chunk_flags++ = 0;
+		}
+		
+		for (i = 0; i < ELEMCOUNT(sctp_chunk_names); i++) {
+			if (strcasecmp(sctp_chunk_names[i].name, ptr) == 0) {
+				DEBUGP("Chunk num %d\n", sctp_chunk_names[i].chunk_type);
+				SCTP_CHUNKMAP_SET(einfo->chunkmap, 
+					sctp_chunk_names[i].chunk_type);
+				found = 1;
+				break;
+			}
+		}
+		if (!found)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unknown sctp chunk `%s'", ptr);
+
+		if (chunk_flags) {
+			DEBUGP("Chunk flags %s\n", chunk_flags);
+			for (j = 0; j < strlen(chunk_flags); j++) {
+				char *p;
+				int bit;
+
+				if ((p = strchr(sctp_chunk_names[i].valid_flags, 
+						toupper(chunk_flags[j]))) != NULL) {
+					bit = p - sctp_chunk_names[i].valid_flags;
+					bit = 7 - bit;
+
+					save_chunk_flag_info(einfo->flag_info, 
+						&(einfo->flag_count), i, bit, 
+						isupper(chunk_flags[j]));
+				} else {
+					xtables_error(PARAMETER_PROBLEM,
+						"Invalid flags for chunk type %d\n", i);
+				}
+			}
+		}
+	}
+out:
+	free(buffer);
+}
+
+static void
+parse_sctp_chunks(struct xt_sctp_info *einfo,
+		  const char *match_type,
+		  const char *chunks)
+{
+	DEBUGP("Match type: %s Chunks: %s\n", match_type, chunks);
+	if (!strcasecmp(match_type, "ANY")) {
+		einfo->chunk_match_type = SCTP_CHUNK_MATCH_ANY;
+	} else 	if (!strcasecmp(match_type, "ALL")) {
+		einfo->chunk_match_type = SCTP_CHUNK_MATCH_ALL;
+	} else 	if (!strcasecmp(match_type, "ONLY")) {
+		einfo->chunk_match_type = SCTP_CHUNK_MATCH_ONLY;
+	} else {
+		xtables_error (PARAMETER_PROBLEM,
+			"Match type has to be one of \"ALL\", \"ANY\" or \"ONLY\"");
+	}
+
+	SCTP_CHUNKMAP_RESET(einfo->chunkmap);
+	parse_sctp_chunk(einfo, chunks);
+}
+
+static int
+sctp_parse(int c, char **argv, int invert, unsigned int *flags,
+           const void *entry, struct xt_entry_match **match)
+{
+	struct xt_sctp_info *einfo
+		= (struct xt_sctp_info *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & XT_SCTP_SRC_PORTS)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Only one `--source-port' allowed");
+		einfo->flags |= XT_SCTP_SRC_PORTS;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_sctp_ports(argv[optind-1], einfo->spts);
+		if (invert)
+			einfo->invflags |= XT_SCTP_SRC_PORTS;
+		*flags |= XT_SCTP_SRC_PORTS;
+		break;
+
+	case '2':
+		if (*flags & XT_SCTP_DEST_PORTS)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--destination-port' allowed");
+		einfo->flags |= XT_SCTP_DEST_PORTS;
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_sctp_ports(argv[optind-1], einfo->dpts);
+		if (invert)
+			einfo->invflags |= XT_SCTP_DEST_PORTS;
+		*flags |= XT_SCTP_DEST_PORTS;
+		break;
+
+	case '3':
+		if (*flags & XT_SCTP_CHUNK_TYPES)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--chunk-types' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+
+		if (!argv[optind] 
+		    || argv[optind][0] == '-' || argv[optind][0] == '!')
+			xtables_error(PARAMETER_PROBLEM,
+				   "--chunk-types requires two args");
+
+		einfo->flags |= XT_SCTP_CHUNK_TYPES;
+		parse_sctp_chunks(einfo, argv[optind-1], argv[optind]);
+		if (invert)
+			einfo->invflags |= XT_SCTP_CHUNK_TYPES;
+		optind++;
+		*flags |= XT_SCTP_CHUNK_TYPES;
+		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static char *
+port_to_service(int port)
+{
+	struct servent *service;
+
+	if ((service = getservbyport(htons(port), "sctp")))
+		return service->s_name;
+
+	return NULL;
+}
+
+static void
+print_port(u_int16_t port, int numeric)
+{
+	char *service;
+
+	if (numeric || (service = port_to_service(port)) == NULL)
+		printf("%u", port);
+	else
+		printf("%s", service);
+}
+
+static void
+print_ports(const char *name, u_int16_t min, u_int16_t max,
+	    int invert, int numeric)
+{
+	const char *inv = invert ? "!" : "";
+
+	if (min != 0 || max != 0xFFFF || invert) {
+		printf("%s", name);
+		if (min == max) {
+			printf(":%s", inv);
+			print_port(min, numeric);
+		} else {
+			printf("s:%s", inv);
+			print_port(min, numeric);
+			printf(":");
+			print_port(max, numeric);
+		}
+		printf(" ");
+	}
+}
+
+static void
+print_chunk_flags(u_int32_t chunknum, u_int8_t chunk_flags, u_int8_t chunk_flags_mask)
+{
+	int i;
+
+	DEBUGP("type: %d\tflags: %x\tflag mask: %x\n", chunknum, chunk_flags, 
+			chunk_flags_mask);
+
+	if (chunk_flags_mask) {
+		printf(":");
+	}
+
+	for (i = 7; i >= 0; i--) {
+		if (chunk_flags_mask & (1 << i)) {
+			if (chunk_flags & (1 << i)) {
+				printf("%c", sctp_chunk_names[chunknum].valid_flags[7-i]);
+			} else {
+				printf("%c", tolower(sctp_chunk_names[chunknum].valid_flags[7-i]));
+			}
+		}
+	}
+}
+
+static void
+print_chunk(u_int32_t chunknum, int numeric)
+{
+	if (numeric) {
+		printf("0x%04X", chunknum);
+	}
+	else {
+		int i;
+
+		for (i = 0; i < ELEMCOUNT(sctp_chunk_names); i++) {
+			if (sctp_chunk_names[i].chunk_type == chunknum)
+				printf("%s", sctp_chunk_names[chunknum].name);
+		}
+	}
+}
+
+static void
+print_chunks(const struct xt_sctp_info *einfo, int numeric)
+{
+	u_int32_t chunk_match_type = einfo->chunk_match_type;
+	const struct xt_sctp_flag_info *flag_info = einfo->flag_info;
+	int flag_count = einfo->flag_count;
+	int i, j;
+	int flag;
+
+	switch (chunk_match_type) {
+		case SCTP_CHUNK_MATCH_ANY:	printf("any "); break;
+		case SCTP_CHUNK_MATCH_ALL:	printf("all "); break;
+		case SCTP_CHUNK_MATCH_ONLY:	printf("only "); break;
+		default:	printf("Never reach herer\n"); break;
+	}
+
+	if (SCTP_CHUNKMAP_IS_CLEAR(einfo->chunkmap)) {
+		printf("NONE ");
+		goto out;
+	}
+	
+	if (SCTP_CHUNKMAP_IS_ALL_SET(einfo->chunkmap)) {
+		printf("ALL ");
+		goto out;
+	}
+	
+	flag = 0;
+	for (i = 0; i < 256; i++) {
+		if (SCTP_CHUNKMAP_IS_SET(einfo->chunkmap, i)) {
+			if (flag)
+				printf(",");
+			flag = 1;
+			print_chunk(i, numeric);
+			for (j = 0; j < flag_count; j++) {
+				if (flag_info[j].chunktype == i) {
+					print_chunk_flags(i, flag_info[j].flag,
+						flag_info[j].flag_mask);
+				}
+			}
+		}
+	}
+
+	if (flag)
+		printf(" ");
+out:
+	return;
+}
+
+static void
+sctp_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_sctp_info *einfo =
+		(const struct xt_sctp_info *)match->data;
+
+	printf("sctp ");
+
+	if (einfo->flags & XT_SCTP_SRC_PORTS) {
+		print_ports("spt", einfo->spts[0], einfo->spts[1],
+			einfo->invflags & XT_SCTP_SRC_PORTS,
+			numeric);
+	}
+
+	if (einfo->flags & XT_SCTP_DEST_PORTS) {
+		print_ports("dpt", einfo->dpts[0], einfo->dpts[1],
+			einfo->invflags & XT_SCTP_DEST_PORTS,
+			numeric);
+	}
+
+	if (einfo->flags & XT_SCTP_CHUNK_TYPES) {
+		/* FIXME: print_chunks() is used in save() where the printing of '!'
+		s taken care of, so we need to do that here as well */
+		if (einfo->invflags & XT_SCTP_CHUNK_TYPES) {
+			printf("! ");
+		}
+		print_chunks(einfo, numeric);
+	}
+}
+
+static void sctp_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_sctp_info *einfo =
+		(const struct xt_sctp_info *)match->data;
+
+	if (einfo->flags & XT_SCTP_SRC_PORTS) {
+		if (einfo->invflags & XT_SCTP_SRC_PORTS)
+			printf("! ");
+		if (einfo->spts[0] != einfo->spts[1])
+			printf("--sport %u:%u ", 
+			       einfo->spts[0], einfo->spts[1]);
+		else
+			printf("--sport %u ", einfo->spts[0]);
+	}
+
+	if (einfo->flags & XT_SCTP_DEST_PORTS) {
+		if (einfo->invflags & XT_SCTP_DEST_PORTS)
+			printf("! ");
+		if (einfo->dpts[0] != einfo->dpts[1])
+			printf("--dport %u:%u ",
+			       einfo->dpts[0], einfo->dpts[1]);
+		else
+			printf("--dport %u ", einfo->dpts[0]);
+	}
+
+	if (einfo->flags & XT_SCTP_CHUNK_TYPES) {
+		if (einfo->invflags & XT_SCTP_CHUNK_TYPES)
+			printf("! ");
+		printf("--chunk-types ");
+
+		print_chunks(einfo, 0);
+	}
+}
+
+static struct xtables_match sctp_match = {
+	.name		= "sctp",
+	.family		= NFPROTO_IPV4,
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_sctp_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_sctp_info)),
+	.help		= sctp_help,
+	.init		= sctp_init,
+	.parse		= sctp_parse,
+	.print		= sctp_print,
+	.save		= sctp_save,
+	.extra_opts	= sctp_opts,
+};
+
+static struct xtables_match sctp_match6 = {
+	.name		= "sctp",
+	.family		= NFPROTO_IPV6,
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_sctp_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_sctp_info)),
+	.help		= sctp_help,
+	.init		= sctp_init,
+	.parse		= sctp_parse,
+	.print		= sctp_print,
+	.save		= sctp_save,
+	.extra_opts	= sctp_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&sctp_match);
+	xtables_register_match(&sctp_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_sctp.man b/ap/app/iptables/extensions/libxt_sctp.man
new file mode 100755
index 0000000..1ecf05c
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_sctp.man
@@ -0,0 +1,28 @@
+.TP
+[\fB!\fP] \fB\-\-source\-port\fP,\fB\-\-sport\fP \fIport\fP[\fB:\fP\fIport\fP]
+.TP
+[\fB!\fP] \fB\-\-destination\-port\fP,\fB\-\-dport\fP \fIport\fP[\fB:\fP\fIport\fP]
+.TP
+[\fB!\fP] \fB\-\-chunk\-types\fP {\fBall\fP|\fBany\fP|\fBonly\fP} \fIchunktype\fP[\fB:\fP\fIflags\fP] [...]
+The flag letter in upper case indicates that the flag is to match if set,
+in the lower case indicates to match if unset.
+
+Chunk types: DATA INIT INIT_ACK SACK HEARTBEAT HEARTBEAT_ACK ABORT SHUTDOWN SHUTDOWN_ACK ERROR COOKIE_ECHO COOKIE_ACK ECN_ECNE ECN_CWR SHUTDOWN_COMPLETE ASCONF ASCONF_ACK
+
+chunk type            available flags      
+.br
+DATA                  U B E u b e         
+.br
+ABORT                 T t                 
+.br
+SHUTDOWN_COMPLETE     T t                 
+
+(lowercase means flag should be "off", uppercase means "on")
+.P
+Examples:
+
+iptables \-A INPUT \-p sctp \-\-dport 80 \-j DROP
+
+iptables \-A INPUT \-p sctp \-\-chunk\-types any DATA,INIT \-j DROP
+
+iptables \-A INPUT \-p sctp \-\-chunk\-types any DATA:Be \-j ACCEPT
diff --git a/ap/app/iptables/extensions/libxt_socket.c b/ap/app/iptables/extensions/libxt_socket.c
new file mode 100755
index 0000000..eebc7c5
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_socket.c
@@ -0,0 +1,39 @@
+/*
+ * Shared library add-on to iptables to add early socket matching support.
+ *
+ * Copyright (C) 2007 BalaBit IT Ltd.
+ */
+#include <stdio.h>
+#include <getopt.h>
+#include <xtables.h>
+
+static void socket_mt_help(void)
+{
+	printf("socket v%s has no options\n\n", XTABLES_VERSION);
+}
+
+static int socket_mt_parse(int c, char **argv, int invert, unsigned int *flags,
+			const void *entry, struct xt_entry_match **match)
+{
+	return 0;
+}
+
+static void socket_mt_check(unsigned int flags)
+{
+}
+
+static struct xtables_match socket_mt_reg = {
+	.name	       = "socket",
+	.version       = XTABLES_VERSION,
+	.family	       = NFPROTO_IPV4,
+	.size	       = XT_ALIGN(0),
+	.userspacesize = XT_ALIGN(0),
+	.parse	       = socket_mt_parse,
+	.final_check   = socket_mt_check,
+	.help	       = socket_mt_help,
+};
+
+void _init(void)
+{
+	xtables_register_match(&socket_mt_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_socket.man b/ap/app/iptables/extensions/libxt_socket.man
new file mode 100755
index 0000000..50c8854
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_socket.man
@@ -0,0 +1,2 @@
+This matches if an open socket can be found by doing a socket lookup on the
+packet.
diff --git a/ap/app/iptables/extensions/libxt_sockopt.c b/ap/app/iptables/extensions/libxt_sockopt.c
new file mode 100755
index 0000000..a87cc51
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_sockopt.c
@@ -0,0 +1,223 @@
+/*
+ *	libxt_sockopt
+ *	Shared library add-on to iptables for socket field matching support.
+ */
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+#include <xtables.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/xt_sockopt.h>
+
+static void sockopt_mt_help(void)
+{
+	printf(
+"sockopt match options:\n"
+"[!] --soorigdev devname\n"
+"[!] --soorigsrc address[/mask]\n"
+"[!] --soorigsrc address-address\n"
+"[!] --soorigdst address[/mask]\n"
+"[!] --soorigdst address-address\n"
+);
+}
+
+static const struct option sockopt_mt_opts[] = {
+	{.name = "soorigdev",         .has_arg = true, .val = '1'},
+	{.name = "soorigsrc",         .has_arg = true, .val = '2'},
+	{.name = "soorigdst",         .has_arg = true, .val = '3'},
+	{.name = NULL},
+};
+
+static int parse_addr(struct in_addr *addr, struct in_addr *mask, char *arg)
+{
+	struct in_addr *ip;
+	char *dash;
+
+	dash = strrchr(arg, '-');
+	if (dash != NULL) {
+		*dash = '\0';
+		ip = xtables_numeric_to_ipaddr(arg);
+		if (!ip)
+			xtables_error(PARAMETER_PROBLEM,
+				"sockopt match: Bad IP address \"%s\"\n", arg);
+		*addr = *ip;
+
+		ip = xtables_numeric_to_ipaddr(dash + 1);
+		if (!ip)
+			xtables_error(PARAMETER_PROBLEM,
+				"sockopt match: Bad IP address \"%s\"\n",
+				dash + 1);
+		*mask = *ip;
+
+		return 1;
+	} else {
+		struct in_addr *addrs = NULL;
+		unsigned int naddrs = 0;
+
+		xtables_ipparse_any(arg, &addrs, mask, &naddrs);
+		if (naddrs > 1)
+			xtables_error(PARAMETER_PROBLEM,
+				"multiple IP addresses not allowed");
+		if (naddrs == 1)
+			memcpy(addr, addrs, sizeof(*addrs));
+
+		return 0;
+	}
+}
+
+static int sockopt_mt_parse(int c, char **argv, int invert, unsigned int *flags,
+                            const void *entry, struct xt_entry_match **match)
+{
+	struct xt_sockopt_mtinfo *info = (void *)(*match)->data;
+	unsigned int dev;
+	char *end;
+
+	switch (c) {
+	case '1':
+		xtables_param_act(XTF_ONLY_ONCE, "sockopt", "--soorigdev", *flags & XT_SOCKOPT_ORIGDEV);
+		if (!xtables_strtoui(optarg, &end, &dev, 0, UINT32_MAX))
+			xtables_param_act(XTF_BAD_VALUE, "sockopt", "--soorigdev", optarg);
+		if (*end != '\0')
+			xtables_param_act(XTF_BAD_VALUE, "sockopt", "--soorigdev", optarg);
+		info->origdev = dev;
+		if (invert)
+			info->invert |= XT_SOCKOPT_ORIGDEV;
+		info->match |= XT_SOCKOPT_ORIGDEV;
+		*flags |= XT_SOCKOPT_ORIGDEV;
+		return true;
+
+	case '2':
+		xtables_param_act(XTF_ONLY_ONCE, "sockopt", "--soorigsrc", *flags & XT_SOCKOPT_ORIGSRC);
+		if (parse_addr(&info->origsrc_addr.in, &info->origsrc_mask.in,
+					argv[optind-1]))
+			info->match |= XT_SOCKOPT_SRCRANGE;
+		if (invert)
+			info->invert |= XT_SOCKOPT_ORIGSRC;
+		info->match |= XT_SOCKOPT_ORIGSRC;
+		*flags |= XT_SOCKOPT_ORIGSRC;
+		return true;
+
+	case '3':
+		xtables_param_act(XTF_ONLY_ONCE, "sockopt", "--soorigdst", *flags & XT_SOCKOPT_ORIGDST);
+		if (parse_addr(&info->origdst_addr.in, &info->origdst_mask.in,
+					argv[optind-1]))
+			info->match |= XT_SOCKOPT_DSTRANGE;
+		if (invert)
+			info->invert |= XT_SOCKOPT_ORIGDST;
+		info->match |= XT_SOCKOPT_ORIGDST;
+		*flags |= XT_SOCKOPT_ORIGDST;
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+static void sockopt_mt_check(unsigned int flags)
+{
+	if (flags == 0)
+		xtables_error(PARAMETER_PROBLEM, "sockopt: At least one option "
+		           "is required");
+}
+
+static void
+sockopt_dump_addr(const union nf_inet_addr *addr,
+                    const union nf_inet_addr *mask, int range,
+                    unsigned int family, bool numeric)
+{
+	if (family == NFPROTO_IPV4) {
+		if (!numeric && addr->ip == 0) {
+			printf("anywhere ");
+		} else if (range) {
+			printf("%s-%s ", xtables_ipaddr_to_numeric(&addr->in),
+					xtables_ipaddr_to_numeric(&mask->in));
+		} else if (numeric) {
+			printf("%s%s ", xtables_ipaddr_to_numeric(&addr->in),
+					xtables_ipmask_to_numeric(&mask->in));
+		} else {
+			printf("%s%s ", xtables_ipaddr_to_anyname(&addr->in),
+					xtables_ipmask_to_numeric(&mask->in));
+		}
+	} else if (family == NFPROTO_IPV6) {
+		if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 &&
+		    addr->ip6[2] == 0 && addr->ip6[3] == 0) {
+			printf("anywhere ");
+		} else if (range) {
+			printf("%s-%s ", xtables_ip6addr_to_numeric(&addr->in6),
+					xtables_ip6addr_to_numeric(&mask->in6));
+		} else if (numeric) {
+			printf("%s%s ", xtables_ip6addr_to_numeric(&addr->in6),
+					xtables_ip6mask_to_numeric(&mask->in6));
+		} else {
+			printf("%s%s ", xtables_ip6addr_to_anyname(&addr->in6),
+					xtables_ip6mask_to_numeric(&mask->in6));
+		}
+	}
+}
+
+static void
+sockopt_dump(const struct xt_sockopt_mtinfo *info, const char *prefix,
+               unsigned int family, bool numeric)
+{
+	if (info->match & XT_SOCKOPT_ORIGDEV) {
+		if (info->invert & XT_SOCKOPT_ORIGDEV)
+			printf("! ");
+		printf("%ssoorigdev ", prefix);
+		printf("%u ", info->origdev);
+	}
+
+	if (info->match & XT_SOCKOPT_ORIGSRC) {
+		if (info->invert & XT_SOCKOPT_ORIGSRC)
+			printf("! ");
+		printf("%ssoorigsrc ", prefix);
+		sockopt_dump_addr(
+			&info->origsrc_addr,
+			&info->origsrc_mask,
+			info->match & XT_SOCKOPT_SRCRANGE,
+			family, numeric);
+	}
+
+	if (info->match & XT_SOCKOPT_ORIGDST) {
+		if (info->invert & XT_SOCKOPT_ORIGDST)
+			printf("! ");
+		printf("%ssoorigsrc ", prefix);
+		sockopt_dump_addr(
+			&info->origdst_addr,
+			&info->origdst_mask,
+			info->match & XT_SOCKOPT_DSTRANGE,
+			family, numeric);
+	}
+}
+
+static void
+sockopt_mt_print(const void *ip, const struct xt_entry_match *match,
+                   int numeric)
+{
+	sockopt_dump((const void *)match->data, "", NFPROTO_IPV4, numeric);
+}
+
+static void sockopt_mt_save(const void *ip,
+                              const struct xt_entry_match *match)
+{
+	sockopt_dump((const void *)match->data, "--", NFPROTO_IPV4, true);
+}
+
+static struct xtables_match sockopt_mt_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "sockopt",
+	.revision      = 0,
+	.family        = NFPROTO_IPV4,
+	.size          = XT_ALIGN(sizeof(struct xt_sockopt_mtinfo)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_sockopt_mtinfo)),
+	.help          = sockopt_mt_help,
+	.parse         = sockopt_mt_parse,
+	.final_check   = sockopt_mt_check,
+	.print         = sockopt_mt_print,
+	.save          = sockopt_mt_save,
+	.extra_opts    = sockopt_mt_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&sockopt_mt_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_standard.c b/ap/app/iptables/extensions/libxt_standard.c
new file mode 100755
index 0000000..54e1348
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_standard.c
@@ -0,0 +1,36 @@
+/* Shared library add-on to iptables for standard target support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <getopt.h>
+#include <xtables.h>
+
+static void standard_help(void)
+{
+	printf(
+"standard match options:\n"
+"(If target is DROP, ACCEPT, RETURN or nothing)\n");
+}
+
+static int standard_parse(int c, char **argv, int invert, unsigned int *flags,
+                          const void *entry, struct xt_entry_target **target)
+{
+	return 0;
+}
+
+static struct xtables_target standard_target = {
+	.family		= AF_UNSPEC,
+	.name		= "standard",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(int)),
+	.userspacesize	= XT_ALIGN(sizeof(int)),
+	.help		= standard_help,
+	.parse		= standard_parse,
+};
+
+void _init(void)
+{
+	xtables_register_target(&standard_target);
+}
diff --git a/ap/app/iptables/extensions/libxt_state.c b/ap/app/iptables/extensions/libxt_state.c
new file mode 100755
index 0000000..0f26443
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_state.c
@@ -0,0 +1,173 @@
+/* Shared library add-on to iptables to add state tracking support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/netfilter/xt_state.h>
+
+#ifndef XT_STATE_UNTRACKED
+#define XT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
+#endif
+
+static void
+state_help(void)
+{
+	printf(
+"state match options:\n"
+" [!] --state [INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED][,...]\n"
+"				State(s) to match\n");
+}
+
+static const struct option state_opts[] = {
+	{ "state", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static int
+state_parse_state(const char *state, size_t len, struct xt_state_info *sinfo)
+{
+	if (strncasecmp(state, "INVALID", len) == 0)
+		sinfo->statemask |= XT_STATE_INVALID;
+	else if (strncasecmp(state, "NEW", len) == 0)
+		sinfo->statemask |= XT_STATE_BIT(IP_CT_NEW);
+	else if (strncasecmp(state, "ESTABLISHED", len) == 0)
+		sinfo->statemask |= XT_STATE_BIT(IP_CT_ESTABLISHED);
+	else if (strncasecmp(state, "RELATED", len) == 0)
+		sinfo->statemask |= XT_STATE_BIT(IP_CT_RELATED);
+	else if (strncasecmp(state, "UNTRACKED", len) == 0)
+		sinfo->statemask |= XT_STATE_UNTRACKED;
+	else
+		return 0;
+	return 1;
+}
+
+static void
+state_parse_states(const char *arg, struct xt_state_info *sinfo)
+{
+	const char *comma;
+
+	while ((comma = strchr(arg, ',')) != NULL) {
+		if (comma == arg || !state_parse_state(arg, comma-arg, sinfo))
+			xtables_error(PARAMETER_PROBLEM, "Bad state \"%s\"", arg);
+		arg = comma+1;
+	}
+	if (!*arg)
+		xtables_error(PARAMETER_PROBLEM, "\"--state\" requires a list of "
+					      "states with no spaces, e.g. "
+					      "ESTABLISHED,RELATED");
+	if (strlen(arg) == 0 || !state_parse_state(arg, strlen(arg), sinfo))
+		xtables_error(PARAMETER_PROBLEM, "Bad state \"%s\"", arg);
+}
+
+static int
+state_parse(int c, char **argv, int invert, unsigned int *flags,
+      const void *entry,
+      struct xt_entry_match **match)
+{
+	struct xt_state_info *sinfo = (struct xt_state_info *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+
+		state_parse_states(argv[optind-1], sinfo);
+		if (invert)
+			sinfo->statemask = ~sinfo->statemask;
+		*flags = 1;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static void state_final_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM, "You must specify \"--state\"");
+}
+
+static void state_print_state(unsigned int statemask)
+{
+	const char *sep = "";
+
+	if (statemask & XT_STATE_INVALID) {
+		printf("%sINVALID", sep);
+		sep = ",";
+	}
+	if (statemask & XT_STATE_BIT(IP_CT_NEW)) {
+		printf("%sNEW", sep);
+		sep = ",";
+	}
+	if (statemask & XT_STATE_BIT(IP_CT_RELATED)) {
+		printf("%sRELATED", sep);
+		sep = ",";
+	}
+	if (statemask & XT_STATE_BIT(IP_CT_ESTABLISHED)) {
+		printf("%sESTABLISHED", sep);
+		sep = ",";
+	}
+	if (statemask & XT_STATE_UNTRACKED) {
+		printf("%sUNTRACKED", sep);
+		sep = ",";
+	}
+	printf(" ");
+}
+
+static void
+state_print(const void *ip,
+      const struct xt_entry_match *match,
+      int numeric)
+{
+	struct xt_state_info *sinfo = (struct xt_state_info *)match->data;
+
+	printf("state ");
+	state_print_state(sinfo->statemask);
+}
+
+static void state_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct xt_state_info *sinfo = (struct xt_state_info *)match->data;
+
+	printf("--state ");
+	state_print_state(sinfo->statemask);
+}
+
+static struct xtables_match state_match = { 
+	.family		= NFPROTO_IPV4,
+	.name		= "state",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_state_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_state_info)),
+	.help		= state_help,
+	.parse		= state_parse,
+	.final_check	= state_final_check,
+	.print		= state_print,
+	.save		= state_save,
+	.extra_opts	= state_opts,
+};
+
+static struct xtables_match state_match6 = { 
+	.family		= NFPROTO_IPV6,
+	.name		= "state",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_state_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_state_info)),
+	.help		= state_help,
+	.parse		= state_parse,
+	.final_check	= state_final_check,
+	.print		= state_print,
+	.save		= state_save,
+	.extra_opts	= state_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&state_match);
+	xtables_register_match(&state_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_state.man b/ap/app/iptables/extensions/libxt_state.man
new file mode 100755
index 0000000..b5e719a
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_state.man
@@ -0,0 +1,21 @@
+This module, when combined with connection tracking, allows access to
+the connection tracking state for this packet.
+.TP
+[\fB!\fP] \fB\-\-state\fP \fIstate\fP
+Where state is a comma separated list of the connection states to
+match.  Possible states are
+.B INVALID
+meaning that the packet could not be identified for some reason which
+includes running out of memory and ICMP errors which don't correspond to any
+known connection,
+.B ESTABLISHED
+meaning that the packet is associated with a connection which has seen
+packets in both directions,
+.B NEW
+meaning that the packet has started a new connection, or otherwise
+associated with a connection which has not seen packets in both
+directions, and
+.B RELATED
+meaning that the packet is starting a new connection, but is
+associated with an existing connection, such as an FTP data transfer,
+or an ICMP error.
diff --git a/ap/app/iptables/extensions/libxt_statistic.c b/ap/app/iptables/extensions/libxt_statistic.c
new file mode 100755
index 0000000..fa044ad
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_statistic.c
@@ -0,0 +1,180 @@
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_statistic.h>
+
+static void statistic_help(void)
+{
+	printf(
+"statistic match options:\n"
+" --mode mode                    Match mode (random, nth)\n"
+" random mode:\n"
+" --probability p		 Probability\n"
+" nth mode:\n"
+" --every n			 Match every nth packet\n"
+" --packet p			 Initial counter value (0 <= p <= n-1, default 0)\n");
+}
+
+static const struct option statistic_opts[] = {
+	{ "mode", 1, NULL, '1' },
+	{ "probability", 1, NULL, '2' },
+	{ "every", 1, NULL, '3' },
+	{ "packet", 1, NULL, '4' },
+	{ .name = NULL }
+};
+
+static struct xt_statistic_info *global_info;
+
+static void statistic_mt_init(struct xt_entry_match *match)
+{
+	global_info = (void *)match->data;
+}
+
+static int
+statistic_parse(int c, char **argv, int invert, unsigned int *flags,
+                const void *entry, struct xt_entry_match **match)
+{
+	struct xt_statistic_info *info = (void *)(*match)->data;
+	unsigned int val;
+	double prob;
+
+	if (invert)
+		info->flags |= XT_STATISTIC_INVERT;
+
+	switch (c) {
+	case '1':
+		if (*flags & 0x1)
+			xtables_error(PARAMETER_PROBLEM, "double --mode");
+		if (!strcmp(optarg, "random"))
+			info->mode = XT_STATISTIC_MODE_RANDOM;
+		else if (!strcmp(optarg, "nth"))
+			info->mode = XT_STATISTIC_MODE_NTH;
+		else
+			xtables_error(PARAMETER_PROBLEM, "Bad mode \"%s\"", optarg);
+		*flags |= 0x1;
+		break;
+	case '2':
+		if (*flags & 0x2)
+			xtables_error(PARAMETER_PROBLEM, "double --probability");
+		prob = atof(optarg);
+		if (prob < 0 || prob > 1)
+			xtables_error(PARAMETER_PROBLEM,
+				   "--probability must be between 0 and 1");
+		info->u.random.probability = 0x80000000 * prob;
+		*flags |= 0x2;
+		break;
+	case '3':
+		if (*flags & 0x4)
+			xtables_error(PARAMETER_PROBLEM, "double --every");
+		if (!xtables_strtoui(optarg, NULL, &val, 0, UINT32_MAX))
+			xtables_error(PARAMETER_PROBLEM,
+				   "cannot parse --every `%s'", optarg);
+		info->u.nth.every = val;
+		if (info->u.nth.every == 0)
+			xtables_error(PARAMETER_PROBLEM, "--every cannot be 0");
+		info->u.nth.every--;
+		*flags |= 0x4;
+		break;
+	case '4':
+		if (*flags & 0x8)
+			xtables_error(PARAMETER_PROBLEM, "double --packet");
+		if (!xtables_strtoui(optarg, NULL, &val, 0, UINT32_MAX))
+			xtables_error(PARAMETER_PROBLEM,
+				   "cannot parse --packet `%s'", optarg);
+		info->u.nth.packet = val;
+		*flags |= 0x8;
+		break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static void statistic_check(unsigned int flags)
+{
+	if (!(flags & 0x1))
+		xtables_error(PARAMETER_PROBLEM, "no mode specified");
+	if ((flags & 0x2) && (flags & (0x4 | 0x8)))
+		xtables_error(PARAMETER_PROBLEM,
+			   "both nth and random parameters given");
+	if (flags & 0x2 && global_info->mode != XT_STATISTIC_MODE_RANDOM)
+		xtables_error(PARAMETER_PROBLEM,
+			   "--probability can only be used in random mode");
+	if (flags & 0x4 && global_info->mode != XT_STATISTIC_MODE_NTH)
+		xtables_error(PARAMETER_PROBLEM,
+			   "--every can only be used in nth mode");
+	if (flags & 0x8 && global_info->mode != XT_STATISTIC_MODE_NTH)
+		xtables_error(PARAMETER_PROBLEM,
+			   "--packet can only be used in nth mode");
+	if ((flags & 0x8) && !(flags & 0x4))
+		xtables_error(PARAMETER_PROBLEM,
+			   "--packet can only be used with --every");
+	/* at this point, info->u.nth.every have been decreased. */
+	if (global_info->u.nth.packet > global_info->u.nth.every)
+		xtables_error(PARAMETER_PROBLEM,
+			  "the --packet p must be 0 <= p <= n-1");
+
+
+	global_info->u.nth.count = global_info->u.nth.every -
+	                           global_info->u.nth.packet;
+}
+
+static void print_match(const struct xt_statistic_info *info, char *prefix)
+{
+	if (info->flags & XT_STATISTIC_INVERT)
+		printf("! ");
+
+	switch (info->mode) {
+	case XT_STATISTIC_MODE_RANDOM:
+		printf("%smode random %sprobability %f ", prefix, prefix,
+		       1.0 * info->u.random.probability / 0x80000000);
+		break;
+	case XT_STATISTIC_MODE_NTH:
+		printf("%smode nth %severy %u ", prefix, prefix,
+		       info->u.nth.every + 1);
+		if (info->u.nth.packet)
+			printf("%spacket %u ", prefix, info->u.nth.packet);
+		break;
+	}
+}
+
+static void
+statistic_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	struct xt_statistic_info *info = (struct xt_statistic_info *)match->data;
+
+	printf("statistic ");
+	print_match(info, "");
+}
+
+static void statistic_save(const void *ip, const struct xt_entry_match *match)
+{
+	struct xt_statistic_info *info = (struct xt_statistic_info *)match->data;
+
+	print_match(info, "--");
+}
+
+static struct xtables_match statistic_match = {
+	.family		= AF_UNSPEC,
+	.name		= "statistic",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_statistic_info)),
+	.userspacesize	= offsetof(struct xt_statistic_info, u.nth.count),
+	.init		= statistic_mt_init,
+	.help		= statistic_help,
+	.parse		= statistic_parse,
+	.final_check	= statistic_check,
+	.print		= statistic_print,
+	.save		= statistic_save,
+	.extra_opts	= statistic_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&statistic_match);
+}
diff --git a/ap/app/iptables/extensions/libxt_statistic.man b/ap/app/iptables/extensions/libxt_statistic.man
new file mode 100755
index 0000000..8fc3b29
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_statistic.man
@@ -0,0 +1,30 @@
+This module matches packets based on some statistic condition.
+It supports two distinct modes settable with the 
+\fB\-\-mode\fP
+option.
+.PP
+Supported options:
+.TP
+\fB\-\-mode\fP \fImode\fP
+Set the matching mode of the matching rule, supported modes are
+.B random
+and
+.B nth. 
+.TP
+\fB\-\-probability\fP \fIp\fP
+Set the probability from 0 to 1 for a packet to be randomly
+matched. It works only with the
+.B random
+mode.
+.TP
+\fB\-\-every\fP \fIn\fP
+Match one packet every nth packet. It works only with the
+.B nth
+mode (see also the 
+\fB\-\-packet\fP
+option).
+.TP
+\fB\-\-packet\fP \fIp\fP
+Set the initial counter value (0 <= p <= n\-1, default 0) for the
+.B nth 
+mode.
diff --git a/ap/app/iptables/extensions/libxt_string.c b/ap/app/iptables/extensions/libxt_string.c
new file mode 100755
index 0000000..ba4b720
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_string.c
@@ -0,0 +1,389 @@
+/* Shared library add-on to iptables to add string matching support. 
+ * 
+ * Copyright (C) 2000 Emmanuel Roger  <winfield@freegates.be>
+ *
+ * 2005-08-05 Pablo Neira Ayuso <pablo@eurodev.net>
+ * 	- reimplemented to use new string matching iptables match
+ * 	- add functionality to match packets by using window offsets
+ * 	- add functionality to select the string matching algorithm
+ *
+ * ChangeLog
+ *     29.12.2003: Michael Rash <mbr@cipherdyne.org>
+ *             Fixed iptables save/restore for ascii strings
+ *             that contain space chars, and hex strings that
+ *             contain embedded NULL chars.  Updated to print
+ *             strings in hex mode if any non-printable char
+ *             is contained within the string.
+ *
+ *     27.01.2001: Gianni Tedesco <gianni@ecsc.co.uk>
+ *             Changed --tos to --string in save(). Also
+ *             updated to work with slightly modified
+ *             ipt_string_info.
+ */
+#define _GNU_SOURCE 1
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <xtables.h>
+#include <stddef.h>
+#include <linux/netfilter/xt_string.h>
+
+static void string_help(void)
+{
+	printf(
+"string match options:\n"
+"--from                       Offset to start searching from\n"
+"--to                         Offset to stop searching\n"
+"--algo                       Algorithm\n"
+"--icase                      Ignore case (default: 0)\n"
+"[!] --string string          Match a string in a packet\n"
+"[!] --hex-string string      Match a hex string in a packet\n");
+}
+
+static const struct option string_opts[] = {
+	{ "from", 1, NULL, '1' },
+	{ "to", 1, NULL, '2' },
+	{ "algo", 1, NULL, '3' },
+	{ "string", 1, NULL, '4' },
+	{ "hex-string", 1, NULL, '5' },
+	{ "icase", 0, NULL, '6' },
+	{ .name = NULL }
+};
+
+static void string_init(struct xt_entry_match *m)
+{
+	struct xt_string_info *i = (struct xt_string_info *) m->data;
+
+	if (i->to_offset == 0)
+		i->to_offset = UINT16_MAX;
+}
+
+static void
+parse_string(const char *s, struct xt_string_info *info)
+{	
+	/* xt_string does not need \0 at the end of the pattern */
+	if (strlen(s) <= XT_STRING_MAX_PATTERN_SIZE) {
+		strncpy(info->pattern, s, XT_STRING_MAX_PATTERN_SIZE);
+		info->patlen = strnlen(s, XT_STRING_MAX_PATTERN_SIZE);
+		return;
+	}
+	xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s);
+}
+
+static void
+parse_algo(const char *s, struct xt_string_info *info)
+{
+	/* xt_string needs \0 for algo name */
+	if (strlen(s) < XT_STRING_MAX_ALGO_NAME_SIZE) {
+		strncpy(info->algo, s, XT_STRING_MAX_ALGO_NAME_SIZE);
+		return;
+	}
+	xtables_error(PARAMETER_PROBLEM, "ALGO too long \"%s\"", s);
+}
+
+static void
+parse_hex_string(const char *s, struct xt_string_info *info)
+{
+	int i=0, slen, sindex=0, schar;
+	short hex_f = 0, literal_f = 0;
+	char hextmp[3];
+
+	slen = strlen(s);
+
+	if (slen == 0) {
+		xtables_error(PARAMETER_PROBLEM,
+			"STRING must contain at least one char");
+	}
+
+	while (i < slen) {
+		if (s[i] == '\\' && !hex_f) {
+			literal_f = 1;
+		} else if (s[i] == '\\') {
+			xtables_error(PARAMETER_PROBLEM,
+				"Cannot include literals in hex data");
+		} else if (s[i] == '|') {
+			if (hex_f)
+				hex_f = 0;
+			else {
+				hex_f = 1;
+				/* get past any initial whitespace just after the '|' */
+				while (s[i+1] == ' ')
+					i++;
+			}
+			if (i+1 >= slen)
+				break;
+			else
+				i++;  /* advance to the next character */
+		}
+
+		if (literal_f) {
+			if (i+1 >= slen) {
+				xtables_error(PARAMETER_PROBLEM,
+					"Bad literal placement at end of string");
+			}
+			info->pattern[sindex] = s[i+1];
+			i += 2;  /* skip over literal char */
+			literal_f = 0;
+		} else if (hex_f) {
+			if (i+1 >= slen) {
+				xtables_error(PARAMETER_PROBLEM,
+					"Odd number of hex digits");
+			}
+			if (i+2 >= slen) {
+				/* must end with a "|" */
+				xtables_error(PARAMETER_PROBLEM, "Invalid hex block");
+			}
+			if (! isxdigit(s[i])) /* check for valid hex char */
+				xtables_error(PARAMETER_PROBLEM, "Invalid hex char '%c'", s[i]);
+			if (! isxdigit(s[i+1])) /* check for valid hex char */
+				xtables_error(PARAMETER_PROBLEM, "Invalid hex char '%c'", s[i+1]);
+			hextmp[0] = s[i];
+			hextmp[1] = s[i+1];
+			hextmp[2] = '\0';
+			if (! sscanf(hextmp, "%x", &schar))
+				xtables_error(PARAMETER_PROBLEM,
+					"Invalid hex char `%c'", s[i]);
+			info->pattern[sindex] = (char) schar;
+			if (s[i+2] == ' ')
+				i += 3;  /* spaces included in the hex block */
+			else
+				i += 2;
+		} else {  /* the char is not part of hex data, so just copy */
+			info->pattern[sindex] = s[i];
+			i++;
+		}
+		if (sindex > XT_STRING_MAX_PATTERN_SIZE)
+			xtables_error(PARAMETER_PROBLEM, "STRING too long \"%s\"", s);
+		sindex++;
+	}
+	info->patlen = sindex;
+}
+
+#define STRING 0x1
+#define ALGO   0x2
+#define FROM   0x4
+#define TO     0x8
+#define ICASE  0x10
+
+static int
+string_parse(int c, char **argv, int invert, unsigned int *flags,
+             const void *entry, struct xt_entry_match **match)
+{
+	struct xt_string_info *stringinfo =
+	    (struct xt_string_info *)(*match)->data;
+	const int revision = (*match)->u.user.revision;
+
+	switch (c) {
+	case '1':
+		if (*flags & FROM)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify multiple --from");
+		stringinfo->from_offset = atoi(optarg);
+		*flags |= FROM;
+		break;
+	case '2':
+		if (*flags & TO)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify multiple --to");
+		stringinfo->to_offset = atoi(optarg);
+		*flags |= TO;
+		break;
+	case '3':
+		if (*flags & ALGO)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify multiple --algo");
+		parse_algo(optarg, stringinfo);
+		*flags |= ALGO;
+		break;
+	case '4':
+		if (*flags & STRING)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify multiple --string");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_string(argv[optind-1], stringinfo);
+		if (invert) {
+			if (revision == 0)
+				stringinfo->u.v0.invert = 1;
+			else
+				stringinfo->u.v1.flags |= XT_STRING_FLAG_INVERT;
+		}
+		*flags |= STRING;
+		break;
+
+	case '5':
+		if (*flags & STRING)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Can't specify multiple --hex-string");
+
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_hex_string(argv[optind-1], stringinfo);  /* sets length */
+		if (invert) {
+			if (revision == 0)
+				stringinfo->u.v0.invert = 1;
+			else
+				stringinfo->u.v1.flags |= XT_STRING_FLAG_INVERT;
+		}
+		*flags |= STRING;
+		break;
+
+	case '6':
+		if (revision == 0)
+			xtables_error(VERSION_PROBLEM,
+				   "Kernel doesn't support --icase");
+
+		stringinfo->u.v1.flags |= XT_STRING_FLAG_IGNORECASE;
+		*flags |= ICASE;
+		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static void string_check(unsigned int flags)
+{
+	if (!(flags & STRING))
+		xtables_error(PARAMETER_PROBLEM,
+			   "STRING match: You must specify `--string' or "
+			   "`--hex-string'");
+	if (!(flags & ALGO))
+		xtables_error(PARAMETER_PROBLEM,
+			   "STRING match: You must specify `--algo'");
+}
+
+/* Test to see if the string contains non-printable chars or quotes */
+static unsigned short int
+is_hex_string(const char *str, const unsigned short int len)
+{
+	unsigned int i;
+	for (i=0; i < len; i++)
+		if (! isprint(str[i]))
+			return 1;  /* string contains at least one non-printable char */
+	/* use hex output if the last char is a "\" */
+	if ((unsigned char) str[len-1] == 0x5c)
+		return 1;
+	return 0;
+}
+
+/* Print string with "|" chars included as one would pass to --hex-string */
+static void
+print_hex_string(const char *str, const unsigned short int len)
+{
+	unsigned int i;
+	/* start hex block */
+	printf("\"|");
+	for (i=0; i < len; i++) {
+		/* see if we need to prepend a zero */
+		if ((unsigned char) str[i] <= 0x0F)
+			printf("0%x", (unsigned char) str[i]);
+		else
+			printf("%x", (unsigned char) str[i]);
+	}
+	/* close hex block */
+	printf("|\" ");
+}
+
+static void
+print_string(const char *str, const unsigned short int len)
+{
+	unsigned int i;
+	printf("\"");
+	for (i=0; i < len; i++) {
+		if ((unsigned char) str[i] == 0x22)  /* escape any embedded quotes */
+			printf("%c", 0x5c);
+		printf("%c", (unsigned char) str[i]);
+	}
+	printf("\" ");  /* closing space and quote */
+}
+
+static void
+string_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_string_info *info =
+	    (const struct xt_string_info*) match->data;
+	const int revision = match->u.user.revision;
+	int invert = (revision == 0 ? info->u.v0.invert :
+				    info->u.v1.flags & XT_STRING_FLAG_INVERT);
+
+	if (is_hex_string(info->pattern, info->patlen)) {
+		printf("STRING match %s", invert ? "!" : "");
+		print_hex_string(info->pattern, info->patlen);
+	} else {
+		printf("STRING match %s", invert ? "!" : "");
+		print_string(info->pattern, info->patlen);
+	}
+	printf("ALGO name %s ", info->algo);
+	if (info->from_offset != 0)
+		printf("FROM %u ", info->from_offset);
+	if (info->to_offset != 0)
+		printf("TO %u ", info->to_offset);
+	if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
+		printf("ICASE ");
+}
+
+static void string_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_string_info *info =
+	    (const struct xt_string_info*) match->data;
+	const int revision = match->u.user.revision;
+	int invert = (revision == 0 ? info->u.v0.invert :
+				    info->u.v1.flags & XT_STRING_FLAG_INVERT);
+
+	if (is_hex_string(info->pattern, info->patlen)) {
+		printf("%s--hex-string ", (invert) ? "! ": "");
+		print_hex_string(info->pattern, info->patlen);
+	} else {
+		printf("%s--string ", (invert) ? "! ": "");
+		print_string(info->pattern, info->patlen);
+	}
+	printf("--algo %s ", info->algo);
+	if (info->from_offset != 0)
+		printf("--from %u ", info->from_offset);
+	if (info->to_offset != 0)
+		printf("--to %u ", info->to_offset);
+	if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
+		printf("--icase ");
+}
+
+
+static struct xtables_match string_match = {
+    .name		= "string",
+    .revision		= 0,
+    .family		= AF_UNSPEC,
+    .version		= XTABLES_VERSION,
+    .size		= XT_ALIGN(sizeof(struct xt_string_info)),
+    .userspacesize	= offsetof(struct xt_string_info, config),
+    .help		= string_help,
+    .init		= string_init,
+    .parse		= string_parse,
+    .final_check	= string_check,
+    .print		= string_print,
+    .save		= string_save,
+    .extra_opts		= string_opts,
+};
+
+static struct xtables_match string_match_v1 = {
+    .name		= "string",
+    .revision		= 1,
+    .family		= AF_UNSPEC,
+    .version		= XTABLES_VERSION,
+    .size		= XT_ALIGN(sizeof(struct xt_string_info)),
+    .userspacesize	= offsetof(struct xt_string_info, config),
+    .help		= string_help,
+    .init		= string_init,
+    .parse		= string_parse,
+    .final_check	= string_check,
+    .print		= string_print,
+    .save		= string_save,
+    .extra_opts		= string_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&string_match);
+	xtables_register_match(&string_match_v1);
+}
diff --git a/ap/app/iptables/extensions/libxt_string.man b/ap/app/iptables/extensions/libxt_string.man
new file mode 100755
index 0000000..725f3ff
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_string.man
@@ -0,0 +1,16 @@
+This modules matches a given string by using some pattern matching strategy. It requires a linux kernel >= 2.6.14.
+.TP
+\fB\-\-algo\fP {\fBbm\fP|\fBkmp\fP}
+Select the pattern matching strategy. (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris)
+.TP
+\fB\-\-from\fP \fIoffset\fP
+Set the offset from which it starts looking for any matching. If not passed, default is 0.
+.TP
+\fB\-\-to\fP \fIoffset\fP
+Set the offset from which it starts looking for any matching. If not passed, default is the packet size.
+.TP
+[\fB!\fP] \fB\-\-string\fP \fIpattern\fP
+Matches the given pattern.
+.TP
+[\fB!\fP] \fB\-\-hex\-string\fP \fIpattern\fP
+Matches the given pattern in hex notation.
diff --git a/ap/app/iptables/extensions/libxt_tcp.c b/ap/app/iptables/extensions/libxt_tcp.c
new file mode 100755
index 0000000..09e1193
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_tcp.c
@@ -0,0 +1,413 @@
+/* Shared library add-on to iptables to add TCP support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <netinet/in.h>
+#include <xtables.h>
+#include <linux/netfilter/xt_tcpudp.h>
+
+static void tcp_help(void)
+{
+	printf(
+"tcp match options:\n"
+"[!] --tcp-flags mask comp	match when TCP flags & mask == comp\n"
+"				(Flags: SYN ACK FIN RST URG PSH ALL NONE)\n"
+"[!] --syn			match when only SYN flag set\n"
+"				(equivalent to --tcp-flags SYN,RST,ACK,FIN SYN)\n"
+"[!] --source-port port[:port]\n"
+" --sport ...\n"
+"				match source port(s)\n"
+"[!] --destination-port port[:port]\n"
+" --dport ...\n"
+"				match destination port(s)\n"
+"[!] --tcp-option number        match if TCP option set\n");
+}
+
+static const struct option tcp_opts[] = {
+	{ "source-port", 1, NULL, '1' },
+	{ "sport", 1, NULL, '1' }, /* synonym */
+	{ "destination-port", 1, NULL, '2' },
+	{ "dport", 1, NULL, '2' }, /* synonym */
+	{ "syn", 0, NULL, '3' },
+	{ "tcp-flags", 1, NULL, '4' },
+	{ "tcp-option", 1, NULL, '5' },
+	{ .name = NULL }
+};
+
+static void
+parse_tcp_ports(const char *portstring, u_int16_t *ports)
+{
+	char *buffer;
+	char *cp;
+
+	buffer = strdup(portstring);
+	if ((cp = strchr(buffer, ':')) == NULL)
+		ports[0] = ports[1] = xtables_parse_port(buffer, "tcp");
+	else {
+		*cp = '\0';
+		cp++;
+
+		ports[0] = buffer[0] ? xtables_parse_port(buffer, "tcp") : 0;
+		ports[1] = cp[0] ? xtables_parse_port(cp, "tcp") : 0xFFFF;
+
+		if (ports[0] > ports[1])
+			xtables_error(PARAMETER_PROBLEM,
+				   "invalid portrange (min > max)");
+	}
+	free(buffer);
+}
+
+struct tcp_flag_names {
+	const char *name;
+	unsigned int flag;
+};
+
+static const struct tcp_flag_names tcp_flag_names[]
+= { { "FIN", 0x01 },
+    { "SYN", 0x02 },
+    { "RST", 0x04 },
+    { "PSH", 0x08 },
+    { "ACK", 0x10 },
+    { "URG", 0x20 },
+    { "ALL", 0x3F },
+    { "NONE", 0 },
+};
+
+static unsigned int
+parse_tcp_flag(const char *flags)
+{
+	unsigned int ret = 0;
+	char *ptr;
+	char *buffer;
+
+	buffer = strdup(flags);
+
+	for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
+		unsigned int i;
+		for (i = 0;
+		     i < sizeof(tcp_flag_names)/sizeof(struct tcp_flag_names);
+		     i++) {
+			if (strcasecmp(tcp_flag_names[i].name, ptr) == 0) {
+				ret |= tcp_flag_names[i].flag;
+				break;
+			}
+		}
+		if (i == sizeof(tcp_flag_names)/sizeof(struct tcp_flag_names))
+			xtables_error(PARAMETER_PROBLEM,
+				   "Unknown TCP flag `%s'", ptr);
+		}
+
+	free(buffer);
+	return ret;
+}
+
+static void
+parse_tcp_flags(struct xt_tcp *tcpinfo,
+		const char *mask,
+		const char *cmp,
+		int invert)
+{
+	tcpinfo->flg_mask = parse_tcp_flag(mask);
+	tcpinfo->flg_cmp = parse_tcp_flag(cmp);
+
+	if (invert)
+		tcpinfo->invflags |= XT_TCP_INV_FLAGS;
+}
+
+static void
+parse_tcp_option(const char *option, u_int8_t *result)
+{
+	unsigned int ret;
+
+	if (!xtables_strtoui(option, NULL, &ret, 1, UINT8_MAX))
+		xtables_error(PARAMETER_PROBLEM, "Bad TCP option \"%s\"", option);
+
+	*result = ret;
+}
+
+static void tcp_init(struct xt_entry_match *m)
+{
+	struct xt_tcp *tcpinfo = (struct xt_tcp *)m->data;
+
+	tcpinfo->spts[1] = tcpinfo->dpts[1] = 0xFFFF;
+}
+
+#define TCP_SRC_PORTS 0x01
+#define TCP_DST_PORTS 0x02
+#define TCP_FLAGS 0x04
+#define TCP_OPTION	0x08
+
+static int
+tcp_parse(int c, char **argv, int invert, unsigned int *flags,
+          const void *entry, struct xt_entry_match **match)
+{
+	struct xt_tcp *tcpinfo = (struct xt_tcp *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & TCP_SRC_PORTS)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--source-port' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_tcp_ports(argv[optind-1], tcpinfo->spts);
+		if (invert)
+			tcpinfo->invflags |= XT_TCP_INV_SRCPT;
+		*flags |= TCP_SRC_PORTS;
+		break;
+
+	case '2':
+		if (*flags & TCP_DST_PORTS)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--destination-port' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_tcp_ports(argv[optind-1], tcpinfo->dpts);
+		if (invert)
+			tcpinfo->invflags |= XT_TCP_INV_DSTPT;
+		*flags |= TCP_DST_PORTS;
+		break;
+
+	case '3':
+		if (*flags & TCP_FLAGS)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one of `--syn' or `--tcp-flags' "
+				   " allowed");
+		parse_tcp_flags(tcpinfo, "SYN,RST,ACK", "SYN", invert);//hubÖÎÀí£ºCNNVD-201205-545
+		*flags |= TCP_FLAGS;
+		break;
+
+	case '4':
+		if (*flags & TCP_FLAGS)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one of `--syn' or `--tcp-flags' "
+				   " allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+
+		if (!argv[optind]
+		    || argv[optind][0] == '-' || argv[optind][0] == '!')
+			xtables_error(PARAMETER_PROBLEM,
+				   "--tcp-flags requires two args.");
+
+		parse_tcp_flags(tcpinfo, argv[optind-1], argv[optind],
+				invert);
+		optind++;
+		*flags |= TCP_FLAGS;
+		break;
+
+	case '5':
+		if (*flags & TCP_OPTION)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--tcp-option' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_tcp_option(argv[optind-1], &tcpinfo->option);
+		if (invert)
+			tcpinfo->invflags |= XT_TCP_INV_OPTION;
+		*flags |= TCP_OPTION;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static char *
+port_to_service(int port)
+{
+	struct servent *service;
+
+	if ((service = getservbyport(htons(port), "tcp")))
+		return service->s_name;
+
+	return NULL;
+}
+
+static void
+print_port(u_int16_t port, int numeric)
+{
+	char *service;
+
+	if (numeric || (service = port_to_service(port)) == NULL)
+		printf("%u", port);
+	else
+		printf("%s", service);
+}
+
+static void
+print_ports(const char *name, u_int16_t min, u_int16_t max,
+	    int invert, int numeric)
+{
+	const char *inv = invert ? "!" : "";
+
+	if (min != 0 || max != 0xFFFF || invert) {
+		printf("%s", name);
+		if (min == max) {
+			printf(":%s", inv);
+			print_port(min, numeric);
+		} else {
+			printf("s:%s", inv);
+			print_port(min, numeric);
+			printf(":");
+			print_port(max, numeric);
+		}
+		printf(" ");
+	}
+}
+
+static void
+print_option(u_int8_t option, int invert, int numeric)
+{
+	if (option || invert)
+		printf("option=%s%u ", invert ? "!" : "", option);
+}
+
+static void
+print_tcpf(u_int8_t flags)
+{
+	int have_flag = 0;
+
+	while (flags) {
+		unsigned int i;
+
+		for (i = 0; (flags & tcp_flag_names[i].flag) == 0; i++);
+
+		if (have_flag)
+			printf(",");
+		printf("%s", tcp_flag_names[i].name);
+		have_flag = 1;
+
+		flags &= ~tcp_flag_names[i].flag;
+	}
+
+	if (!have_flag)
+		printf("NONE");
+}
+
+static void
+print_flags(u_int8_t mask, u_int8_t cmp, int invert, int numeric)
+{
+	if (mask || invert) {
+		printf("flags:%s", invert ? "!" : "");
+		if (numeric)
+			printf("0x%02X/0x%02X ", mask, cmp);
+		else {
+			print_tcpf(mask);
+			printf("/");
+			print_tcpf(cmp);
+			printf(" ");
+		}
+	}
+}
+
+static void
+tcp_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_tcp *tcp = (struct xt_tcp *)match->data;
+
+	printf("tcp ");
+	print_ports("spt", tcp->spts[0], tcp->spts[1],
+		    tcp->invflags & XT_TCP_INV_SRCPT,
+		    numeric);
+	print_ports("dpt", tcp->dpts[0], tcp->dpts[1],
+		    tcp->invflags & XT_TCP_INV_DSTPT,
+		    numeric);
+	print_option(tcp->option,
+		     tcp->invflags & XT_TCP_INV_OPTION,
+		     numeric);
+	print_flags(tcp->flg_mask, tcp->flg_cmp,
+		    tcp->invflags & XT_TCP_INV_FLAGS,
+		    numeric);
+	if (tcp->invflags & ~XT_TCP_INV_MASK)
+		printf("Unknown invflags: 0x%X ",
+		       tcp->invflags & ~XT_TCP_INV_MASK);
+}
+
+static void tcp_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_tcp *tcpinfo = (struct xt_tcp *)match->data;
+
+	if (tcpinfo->spts[0] != 0
+	    || tcpinfo->spts[1] != 0xFFFF) {
+		if (tcpinfo->invflags & XT_TCP_INV_SRCPT)
+			printf("! ");
+		if (tcpinfo->spts[0]
+		    != tcpinfo->spts[1])
+			printf("--sport %u:%u ",
+			       tcpinfo->spts[0],
+			       tcpinfo->spts[1]);
+		else
+			printf("--sport %u ",
+			       tcpinfo->spts[0]);
+	}
+
+	if (tcpinfo->dpts[0] != 0
+	    || tcpinfo->dpts[1] != 0xFFFF) {
+		if (tcpinfo->invflags & XT_TCP_INV_DSTPT)
+			printf("! ");
+		if (tcpinfo->dpts[0]
+		    != tcpinfo->dpts[1])
+			printf("--dport %u:%u ",
+			       tcpinfo->dpts[0],
+			       tcpinfo->dpts[1]);
+		else
+			printf("--dport %u ",
+			       tcpinfo->dpts[0]);
+	}
+
+	if (tcpinfo->option
+	    || (tcpinfo->invflags & XT_TCP_INV_OPTION)) {
+		if (tcpinfo->invflags & XT_TCP_INV_OPTION)
+			printf("! ");
+		printf("--tcp-option %u ", tcpinfo->option);
+	}
+
+	if (tcpinfo->flg_mask
+	    || (tcpinfo->invflags & XT_TCP_INV_FLAGS)) {
+		if (tcpinfo->invflags & XT_TCP_INV_FLAGS)
+			printf("! ");
+		printf("--tcp-flags ");
+		if (tcpinfo->flg_mask != 0xFF) {
+			print_tcpf(tcpinfo->flg_mask);
+		}
+		printf(" ");
+		print_tcpf(tcpinfo->flg_cmp);
+		printf(" ");
+	}
+}
+
+static struct xtables_match tcp_match = {
+	.family		= NFPROTO_IPV4,
+	.name		= "tcp",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_tcp)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_tcp)),
+	.help		= tcp_help,
+	.init		= tcp_init,
+	.parse		= tcp_parse,
+	.print		= tcp_print,
+	.save		= tcp_save,
+	.extra_opts	= tcp_opts,
+};
+
+static struct xtables_match tcp_match6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "tcp",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_tcp)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_tcp)),
+	.help		= tcp_help,
+	.init		= tcp_init,
+	.parse		= tcp_parse,
+	.print		= tcp_print,
+	.save		= tcp_save,
+	.extra_opts	= tcp_opts,
+};
+
+void
+_init(void)
+{
+	xtables_register_match(&tcp_match);
+	xtables_register_match(&tcp_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_tcp.man b/ap/app/iptables/extensions/libxt_tcp.man
new file mode 100755
index 0000000..edf6503
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_tcp.man
@@ -0,0 +1,44 @@
+These extensions can be used if `\-\-protocol tcp' is specified. It
+provides the following options:
+.TP
+[\fB!\fP] \fB\-\-source\-port\fP,\fB\-\-sport\fP \fIport\fP[\fB:\fP\fIport\fP]
+Source port or port range specification. This can either be a service
+name or a port number. An inclusive range can also be specified,
+using the format \fIport\fP\fB:\fP\fIport\fP.
+If the first port is omitted, "0" is assumed; if the last is omitted,
+"65535" is assumed.
+If the second port is greater than the first they will be swapped.
+The flag
+\fB\-\-sport\fP
+is a convenient alias for this option.
+.TP
+[\fB!\fP] \fB\-\-destination\-port\fP,\fB\-\-dport\fP \fIport\fP[\fB,\fP\fIport\fP]
+Destination port or port range specification.  The flag
+\fB\-\-dport\fP
+is a convenient alias for this option.
+.TP
+[\fB!\fP] \fB\-\-tcp\-flags\fP \fImask\fP \fIcomp\fP
+Match when the TCP flags are as specified.  The first argument \fImask\fP is the
+flags which we should examine, written as a comma-separated list, and
+the second argument \fIcomp\fP is a comma-separated list of flags which must be
+set.  Flags are:
+.BR "SYN ACK FIN RST URG PSH ALL NONE" .
+Hence the command
+.nf
+ iptables \-A FORWARD \-p tcp \-\-tcp\-flags SYN,ACK,FIN,RST SYN
+.fi
+will only match packets with the SYN flag set, and the ACK, FIN and
+RST flags unset.
+.TP
+[\fB!\fP] \fB\-\-syn\fP
+Only match TCP packets with the SYN bit set and the ACK and RST  bits
+cleared.  Such packets are used to request TCP connection initiation;
+for example, blocking such packets coming in an interface will prevent
+incoming TCP connections, but outgoing TCP connections will be
+unaffected.
+It is equivalent to \fB\-\-tcp\-flags SYN,RST,ACK SYN\fP.
+If the "!" flag precedes the "\-\-syn", the sense of the
+option is inverted.
+.TP
+[\fB!\fP] \fB\-\-tcp\-option\fP \fInumber\fP
+Match if TCP option set.
diff --git a/ap/app/iptables/extensions/libxt_tcpmss.c b/ap/app/iptables/extensions/libxt_tcpmss.c
new file mode 100755
index 0000000..46529f9
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_tcpmss.c
@@ -0,0 +1,143 @@
+/* Shared library add-on to iptables to add tcp MSS matching support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_tcpmss.h>
+
+static void tcpmss_help(void)
+{
+	printf(
+"tcpmss match options:\n"
+"[!] --mss value[:value]	Match TCP MSS range.\n"
+"				(only valid for TCP SYN or SYN/ACK packets)\n");
+}
+
+static const struct option tcpmss_opts[] = {
+	{ "mss", 1, NULL, '1' },
+	{ .name = NULL }
+};
+
+static u_int16_t
+parse_tcp_mssvalue(const char *mssvalue)
+{
+	unsigned int mssvaluenum;
+
+	if (xtables_strtoui(mssvalue, NULL, &mssvaluenum, 0, UINT16_MAX))
+		return mssvaluenum;
+
+	xtables_error(PARAMETER_PROBLEM,
+		   "Invalid mss `%s' specified", mssvalue);
+}
+
+static void
+parse_tcp_mssvalues(const char *mssvaluestring,
+		    u_int16_t *mss_min, u_int16_t *mss_max)
+{
+	char *buffer;
+	char *cp;
+
+	buffer = strdup(mssvaluestring);
+	if ((cp = strchr(buffer, ':')) == NULL)
+		*mss_min = *mss_max = parse_tcp_mssvalue(buffer);
+	else {
+		*cp = '\0';
+		cp++;
+
+		*mss_min = buffer[0] ? parse_tcp_mssvalue(buffer) : 0;
+		*mss_max = cp[0] ? parse_tcp_mssvalue(cp) : 0xFFFF;
+	}
+	free(buffer);
+}
+
+static int
+tcpmss_parse(int c, char **argv, int invert, unsigned int *flags,
+             const void *entry, struct xt_entry_match **match)
+{
+	struct xt_tcpmss_match_info *mssinfo =
+		(struct xt_tcpmss_match_info *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--mss' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_tcp_mssvalues(argv[optind-1],
+				    &mssinfo->mss_min, &mssinfo->mss_max);
+		if (invert)
+			mssinfo->invert = 1;
+		*flags = 1;
+		break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+static void tcpmss_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "tcpmss match: You must specify `--mss'");
+}
+
+static void
+tcpmss_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_tcpmss_match_info *info = (void *)match->data;
+
+	printf("tcpmss match %s", info->invert ? "!" : "");
+	if (info->mss_min == info->mss_max)
+		printf("%u ", info->mss_min);
+	else
+		printf("%u:%u ", info->mss_min, info->mss_max);
+}
+
+static void tcpmss_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_tcpmss_match_info *info = (void *)match->data;
+
+	printf("%s--mss ", info->invert ? "! " : "");
+	if (info->mss_min == info->mss_max)
+		printf("%u ", info->mss_min);
+	else
+		printf("%u:%u ", info->mss_min, info->mss_max);
+}
+
+static struct xtables_match tcpmss_match = {
+	.family		= NFPROTO_IPV4,
+	.name		= "tcpmss",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_tcpmss_match_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_tcpmss_match_info)),
+	.help		= tcpmss_help,
+	.parse		= tcpmss_parse,
+	.final_check	= tcpmss_check,
+	.print		= tcpmss_print,
+	.save		= tcpmss_save,
+	.extra_opts	= tcpmss_opts,
+};
+
+static struct xtables_match tcpmss_match6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "tcpmss",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_tcpmss_match_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_tcpmss_match_info)),
+	.help		= tcpmss_help,
+	.parse		= tcpmss_parse,
+	.final_check	= tcpmss_check,
+	.print		= tcpmss_print,
+	.save		= tcpmss_save,
+	.extra_opts	= tcpmss_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&tcpmss_match);
+	xtables_register_match(&tcpmss_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_tcpmss.man b/ap/app/iptables/extensions/libxt_tcpmss.man
new file mode 100755
index 0000000..8ee715c
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_tcpmss.man
@@ -0,0 +1,4 @@
+This matches the TCP MSS (maximum segment size) field of the TCP header.  You can only use this on TCP SYN or SYN/ACK packets, since the MSS is only negotiated during the TCP handshake at connection startup time.
+.TP
+[\fB!\fP] \fB\-\-mss\fP \fIvalue\fP[\fB:\fP\fIvalue\fP]
+Match a given TCP MSS value or range.
diff --git a/ap/app/iptables/extensions/libxt_time.c b/ap/app/iptables/extensions/libxt_time.c
new file mode 100755
index 0000000..cceb998
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_time.c
@@ -0,0 +1,776 @@
+/*
+ *	libxt_time - iptables part for xt_time
+ *	Copyright © CC Computer Consultants GmbH, 2007
+ *	Contact: <jengelh@computergmbh.de>
+ *
+ *	libxt_time.c 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 or 3 of the License.
+ *
+ *	Based on libipt_time.c.
+ */
+#include <sys/types.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <time.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include <linux/netfilter/xt_time.h>
+#include <xtables.h>
+
+enum { /* getopt "seen" bits */
+	F_DATE_START = 1 << 0,
+	F_DATE_STOP  = 1 << 1,
+	F_TIME_START = 1 << 2,
+	F_TIME_STOP  = 1 << 3,
+	F_MONTHDAYS  = 1 << 4,
+	F_WEEKDAYS   = 1 << 5,
+	F_TIMEZONE   = 1 << 6,
+};
+
+static const char *const week_days[] = {
+	NULL, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun",
+};
+
+static const struct option time_opts_v0[] = {
+	{"datestart", true,  NULL, 'D'},
+	{"datestop",  true,  NULL, 'E'},
+	{"timestart", true,  NULL, 'X'},
+	{"timestop",  true,  NULL, 'Y'},
+	{"weekdays",  true,  NULL, 'w'},
+	{"monthdays", true,  NULL, 'm'},
+	{"localtz",   false, NULL, 'l'},
+	{"utc",       false, NULL, 'u'},
+	{ .name = NULL }
+};
+
+static const struct option time_opts[] = {
+	{"datestart", true,  NULL, 'D'},
+	{"datestop",  true,  NULL, 'E'},
+	{"timestart", true,  NULL, 'X'},
+	{"timestop",  true,  NULL, 'Y'},
+	{"weekdays",  true,  NULL, 'w'},
+	{"monthdays", true,  NULL, 'm'},
+	{"localtz",   false, NULL, 'l'},
+	{"utc",       false, NULL, 'u'},
+	{"tz",        true,  NULL, 'z'},
+	{ .name = NULL }
+};
+
+static void time_help(void)
+{
+	printf(
+"time match options:\n"
+"    --datestart time     Start and stop time, to be given in ISO 8601\n"
+"    --datestop time      (YYYY[-MM[-DD[Thh[:mm[:ss]]]]])\n"
+"    --timestart time     Start and stop daytime (hh:mm[:ss])\n"
+"    --timestop time      (between 00:00:00 and 23:59:59)\n"
+"[!] --monthdays value    List of days on which to match, separated by comma\n"
+"                         (Possible days: 1 to 31; defaults to all)\n"
+"[!] --weekdays value     List of weekdays on which to match, sep. by comma\n"
+"                         (Possible days: Mon,Tue,Wed,Thu,Fri,Sat,Sun or 1 to 7\n"
+"                         Defaults to all weekdays.)\n"
+"    --localtz/--utc      Time is interpreted as UTC/local time\n"
+"    --tz tzspec          Time is interpreted using timezone spec\n");
+}
+
+static void time_init(struct xt_entry_match *m)
+{
+	struct xt_time_info1 *info = (void *)m->data;
+
+	/* By default, we match on every day, every daytime */
+	info->monthdays_match = XT_TIME_ALL_MONTHDAYS;
+	info->weekdays_match  = XT_TIME_ALL_WEEKDAYS;
+	info->daytime_start   = XT_TIME_MIN_DAYTIME;
+	info->daytime_stop    = XT_TIME_MAX_DAYTIME;
+
+	/* ...and have no date-begin or date-end boundary */
+	info->date_start = 0;
+	info->date_stop  = INT_MAX;
+
+	/* local time is default */
+	info->flags |= XT_TIME_LOCAL_TZ;
+}
+
+static time_t time_parse_date(const char *s, bool end)
+{
+	unsigned int month = 1, day = 1, hour = 0, minute = 0, second = 0;
+	unsigned int year  = end ? 2038 : 1970;
+	const char *os = s;
+	struct tm tm;
+	time_t ret;
+	char *e;
+
+	year = strtoul(s, &e, 10);
+	if ((*e != '-' && *e != '\0') || year < 1970 || year > 2038)
+		goto out;
+	if (*e == '\0')
+		goto eval;
+
+	s = e + 1;
+	month = strtoul(s, &e, 10);
+	if ((*e != '-' && *e != '\0') || month > 12)
+		goto out;
+	if (*e == '\0')
+		goto eval;
+
+	s = e + 1;
+	day = strtoul(s, &e, 10);
+	if ((*e != 'T' && *e != '\0') || day > 31)
+		goto out;
+	if (*e == '\0')
+		goto eval;
+
+	s = e + 1;
+	hour = strtoul(s, &e, 10);
+	if ((*e != ':' && *e != '\0') || hour > 23)
+		goto out;
+	if (*e == '\0')
+		goto eval;
+
+	s = e + 1;
+	minute = strtoul(s, &e, 10);
+	if ((*e != ':' && *e != '\0') || minute > 59)
+		goto out;
+	if (*e == '\0')
+		goto eval;
+
+	s = e + 1;
+	second = strtoul(s, &e, 10);
+	if (*e != '\0' || second > 59)
+		goto out;
+
+ eval:
+	tm.tm_year = year - 1900;
+	tm.tm_mon  = month - 1;
+	tm.tm_mday = day;
+	tm.tm_hour = hour;
+	tm.tm_min  = minute;
+	tm.tm_sec  = second;
+	ret = mktime(&tm);
+	if (ret >= 0)
+		return ret;
+	perror("mktime");
+	xtables_error(OTHER_PROBLEM, "mktime returned an error");
+
+ out:
+	xtables_error(PARAMETER_PROBLEM, "Invalid date \"%s\" specified. Should "
+	           "be YYYY[-MM[-DD[Thh[:mm[:ss]]]]]", os);
+	return -1;
+}
+
+static unsigned int time_parse_minutes(const char *s)
+{
+	unsigned int hour, minute, second = 0;
+	char *e;
+
+	hour = strtoul(s, &e, 10);
+	if (*e != ':' || hour > 23)
+		goto out;
+
+	s = e + 1;
+	minute = strtoul(s, &e, 10);
+	if ((*e != ':' && *e != '\0') || minute > 59)
+		goto out;
+	if (*e == '\0')
+		goto eval;
+
+	s = e + 1;
+	second = strtoul(s, &e, 10);
+	if (*e != '\0' || second > 59)
+		goto out;
+
+ eval:
+	return 60 * 60 * hour + 60 * minute + second;
+
+ out:
+	xtables_error(PARAMETER_PROBLEM, "invalid time \"%s\" specified, "
+	           "should be hh:mm[:ss] format and within the boundaries", s);
+	return -1;
+}
+
+static const char *my_strseg(char *buf, unsigned int buflen,
+    const char **arg, char delim)
+{
+	const char *sep;
+
+	if (*arg == NULL || **arg == '\0')
+		return NULL;
+	sep = strchr(*arg, delim);
+	if (sep == NULL) {
+		snprintf(buf, buflen, "%s", *arg);
+		*arg = NULL;
+		return buf;
+	}
+	snprintf(buf, buflen, "%.*s", (unsigned int)(sep - *arg), *arg);
+	*arg = sep + 1;
+	return buf;
+}
+
+static uint32_t time_parse_monthdays(const char *arg)
+{
+	char day[3], *err = NULL;
+	uint32_t ret = 0;
+	unsigned int i;
+
+	while (my_strseg(day, sizeof(day), &arg, ',') != NULL) {
+		i = strtoul(day, &err, 0);
+		if ((*err != ',' && *err != '\0') || i > 31)
+			xtables_error(PARAMETER_PROBLEM,
+			           "%s is not a valid day for --monthdays", day);
+		ret |= 1 << i;
+	}
+
+	return ret;
+}
+
+static unsigned int time_parse_weekdays(const char *arg)
+{
+	char day[4], *err = NULL;
+	unsigned int i, ret = 0;
+	bool valid;
+
+	while (my_strseg(day, sizeof(day), &arg, ',') != NULL) {
+		i = strtoul(day, &err, 0);
+		if (*err == '\0') {
+			if (i == 0)
+				xtables_error(PARAMETER_PROBLEM,
+				           "No, the week does NOT begin with Sunday.");
+			ret |= 1 << i;
+			continue;
+		}
+
+		valid = false;
+		for (i = 1; i < ARRAY_SIZE(week_days); ++i)
+			if (strncmp(day, week_days[i], 2) == 0) {
+				ret |= 1 << i;
+				valid = true;
+			}
+
+		if (!valid)
+			xtables_error(PARAMETER_PROBLEM,
+			           "%s is not a valid day specifier", day);
+	}
+
+	return ret;
+}
+
+static const char *time_parse_tz_time(const char *s, u_int32_t *t)
+{
+	unsigned int hour, minute = 0, second = 0;
+	const char *os = s;
+	char *e;
+
+	if (!isdigit(*s))
+		goto out;
+	hour = strtoul(s, &e, 10);
+	if (hour > 24)
+		goto out;
+	if (*e != ':')
+		goto eval;
+
+	s = e + 1;
+	if (!isdigit(*s))
+		goto out;
+	minute = strtoul(s, &e, 10);
+	if (minute > 59)
+		goto out;
+	if (*e != ':')
+		goto eval;
+
+	s = e + 1;
+	if (!isdigit(*s))
+		goto out;
+	second = strtoul(s, &e, 10);
+	if (second > 59)
+		goto out;
+
+ eval:
+	*t = 60 * 60 * hour + 60 * minute + second;
+	return e;
+
+ out:
+	xtables_error(PARAMETER_PROBLEM, "invalid time \"%s\" specified, "
+	           "should be hh[:mm[:ss]] format and within the boundaries",
+		   os);
+	return NULL;
+}
+
+static const char *time_parse_tz_offset(const char *s, int32_t *offset)
+{
+	int neg = 0;
+	u_int32_t t;
+
+	if (*s == '+')
+		s++;
+	else if (*s =='-') {
+		neg = 1;
+		s++;
+	}
+
+	s = time_parse_tz_time(s, &t);
+	*offset = neg ? -t : t;
+	return s;
+}
+
+static const char *time_parse_tz_rule(const char *s,
+		struct xt_time_info1 *info, int rule)
+{
+	unsigned long l;
+	const char *os = s;
+	char *e;
+
+	if (isdigit(*s)) {
+		info->tz[rule].type = XT_TIME_TZ_TYPE_J0;
+		l = strtoul(s, &e, 10);
+		if (l > 365)
+			goto out;
+		info->tz[rule].day = l;
+		s = e;
+	} else if (*s == 'J') {
+		info->tz[rule].type = XT_TIME_TZ_TYPE_J1;
+		s++;
+
+		if (!isdigit(*s))
+			goto out;
+		l = strtoul(s, &e, 10);
+		if (l < 1 || l > 365)
+			goto out;
+		info->tz[rule].day = l;
+		s = e;
+	} else if (*s == 'M') {
+		info->tz[rule].type = XT_TIME_TZ_TYPE_M;
+		s++;
+
+		l = strtoul(s, &e, 10);
+		if (l < 1 || l > 12)
+			goto out;
+		info->tz[rule].month = l;
+		if (*e != '.')
+			goto out;
+		s = e + 1;
+
+		l = strtoul(s, &e, 10);
+		if (l < 1 || l > 5)
+			goto out;
+		info->tz[rule].week = l;
+		if (*e != '.')
+			goto out;
+		s = e + 1;
+
+		l = strtoul(s, &e, 10);
+		if (l > 6)
+			goto out;
+		info->tz[rule].day = l;
+		s = e;
+	} else
+		goto out;
+
+	if (*s == '/')
+		s = time_parse_tz_time(s + 1, &info->tz[rule].secs);
+	else
+		info->tz[rule].secs = 2 * 60 * 60; /* 2:00:00 */
+
+	return s;
+
+out:
+	xtables_error(PARAMETER_PROBLEM,
+		      "invalid tz rule \"%s\" specified", os);
+	return NULL;
+}
+
+static void time_parse_tz(struct xt_time_info1 *info, const char *arg)
+{
+	const char *p;
+	size_t l;
+
+	/* Parse STD name and offset */
+	p = arg;
+	l = strcspn(p, "+-0123456789,");
+	if (l < 0 || l > 6)
+		xtables_error(PARAMETER_PROBLEM,
+			      "invalid or missing std name in %s", arg);
+	memcpy(info->tz[0].name, p, l);
+	p += l;
+
+	if (!*p || *p == ',')
+		xtables_error(PARAMETER_PROBLEM,
+			      "missing std offset in %s", arg);
+
+	p = time_parse_tz_offset(p, &info->tz[0].offset);
+
+	if (!*p) {
+		/* No DST */
+		info->tz[1].offset = info->tz[0].offset;
+		return;
+	}
+
+	/* Parse DST name and optional offset */
+	l = strcspn(p, "+-0123456789,");
+	if (l < 0 || l > 6)
+		xtables_error(PARAMETER_PROBLEM,
+			      "invalid or missing dst name in %s", arg);
+	memcpy(info->tz[1].name, p, l);
+	p += l;
+
+	if (!*p)
+		xtables_error(PARAMETER_PROBLEM,
+			      "missing dst offset or rule in %s", arg);
+
+	if (*p == ',') {
+		info->tz[1].offset = info->tz[0].offset + (60 * 60);
+	} else {
+		p = time_parse_tz_offset(p, &info->tz[1].offset);
+	}
+
+	/* Parse start rule */
+	if (*p == ',')
+		p++;
+	if (!*p)
+		xtables_error(PARAMETER_PROBLEM,
+			      "missing dst start rule in %s", arg);
+	p = time_parse_tz_rule(p, info, 0);
+
+	/* Parse end rule */
+	if (*p == ',')
+		p++;
+	if (!*p)
+		xtables_error(PARAMETER_PROBLEM,
+			      "missing dst end rule in %s", arg);
+	p = time_parse_tz_rule(p, info, 1);
+
+	if (*p)
+		xtables_error(PARAMETER_PROBLEM,
+			      "invalid tz %s", arg);
+}
+
+static int time_parse(int c, char **argv, int invert, unsigned int *flags,
+                      const void *entry, struct xt_entry_match **match)
+{
+	struct xt_time_info1 *info = (void *)(*match)->data;
+
+	switch (c) {
+	case 'D': /* --datestart */
+		if (*flags & F_DATE_START)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Cannot specify --datestart twice");
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Unexpected \"!\" with --datestart");
+		info->date_start = time_parse_date(optarg, false);
+		*flags |= F_DATE_START;
+		return 1;
+	case 'E': /* --datestop */
+		if (*flags & F_DATE_STOP)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Cannot specify --datestop more than once");
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+			           "unexpected \"!\" with --datestop");
+		info->date_stop = time_parse_date(optarg, true);
+		*flags |= F_DATE_STOP;
+		return 1;
+	case 'X': /* --timestart */
+		if (*flags & F_TIME_START)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Cannot specify --timestart more than once");
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Unexpected \"!\" with --timestart");
+		info->daytime_start = time_parse_minutes(optarg);
+		*flags |= F_TIME_START;
+		return 1;
+	case 'Y': /* --timestop */
+		if (*flags & F_TIME_STOP)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Cannot specify --timestop more than once");
+		if (invert)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Unexpected \"!\" with --timestop");
+		info->daytime_stop = time_parse_minutes(optarg);
+		*flags |= F_TIME_STOP;
+		return 1;
+	case 'l': /* --localtz */
+		if (*flags & F_TIMEZONE)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Can only specify exactly one of --tz, --localtz or --utc");
+		info->flags |= XT_TIME_LOCAL_TZ;
+		*flags |= F_TIMEZONE;
+		return 1;
+	case 'm': /* --monthdays */
+		if (*flags & F_MONTHDAYS)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Cannot specify --monthdays more than once");
+		info->monthdays_match = time_parse_monthdays(optarg);
+		if (invert)
+			info->monthdays_match ^= XT_TIME_ALL_MONTHDAYS;
+		*flags |= F_MONTHDAYS;
+		return 1;
+	case 'w': /* --weekdays */
+		if (*flags & F_WEEKDAYS)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Cannot specify --weekdays more than once");
+		info->weekdays_match = time_parse_weekdays(optarg);
+		if (invert)
+			info->weekdays_match ^= XT_TIME_ALL_WEEKDAYS;
+		*flags |= F_WEEKDAYS;
+		return 1;
+	case 'u': /* --utc */
+		if (*flags & F_TIMEZONE)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Can only specify exactly one of --tz, --localtz or --utc");
+		info->flags &= ~XT_TIME_LOCAL_TZ;
+		*flags |= F_TIMEZONE;
+		return 1;
+	case 'z': /* --tz */
+		if (*flags & F_TIMEZONE)
+			xtables_error(PARAMETER_PROBLEM,
+			           "Can only specify exactly one of --tz, --localtz or --utc");
+		info->flags &= ~XT_TIME_LOCAL_TZ;
+		info->flags |= XT_TIME_TZ;
+		time_parse_tz(info, optarg);
+		*flags |= F_TIMEZONE;
+		return 1;
+	}
+	return 0;
+}
+
+static void time_print_date(time_t date, const char *command)
+{
+	struct tm *t;
+
+	/* If it is the default value, do not print it. */
+	if (date == 0 || date == LONG_MAX)
+		return;
+
+	t = localtime(&date);
+	if (command != NULL)
+		/*
+		 * Need a contiguous string (no whitespaces), hence using
+		 * the ISO 8601 "T" variant.
+		 */
+		printf("%s %04u-%02u-%02uT%02u:%02u:%02u ",
+		       command, t->tm_year + 1900, t->tm_mon + 1,
+		       t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
+	else
+		printf("%04u-%02u-%02u %02u:%02u:%02u ",
+		       t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
+		       t->tm_hour, t->tm_min, t->tm_sec);
+}
+
+static void time_print_monthdays(uint32_t mask, bool human_readable)
+{
+	unsigned int i, nbdays = 0;
+
+	for (i = 1; i <= 31; ++i)
+		if (mask & (1 << i)) {
+			if (nbdays++ > 0)
+				printf(",");
+			printf("%u", i);
+			if (human_readable)
+				switch (i % 10) {
+					case 1:
+						printf("st");
+						break;
+					case 2:
+						printf("nd");
+						break;
+					case 3:
+						printf("rd");
+						break;
+					default:
+						printf("th");
+						break;
+				}
+		}
+	printf(" ");
+}
+
+static void time_print_weekdays(unsigned int mask)
+{
+	unsigned int i, nbdays = 0;
+
+	for (i = 1; i <= 7; ++i)
+		if (mask & (1 << i)) {
+			if (nbdays > 0)
+				printf(",%s", week_days[i]);
+			else
+				printf("%s", week_days[i]);
+			++nbdays;
+		}
+	printf(" ");
+}
+
+static inline void divide_time(unsigned int fulltime, unsigned int *hours,
+    unsigned int *minutes, unsigned int *seconds)
+{
+	*seconds  = fulltime % 60;
+	fulltime /= 60;
+	*minutes  = fulltime % 60;
+	*hours    = fulltime / 60;
+}
+
+static void time_print_tz_offset(const struct xt_time_info1 *info, int rule)
+{
+	unsigned int h, m, s;
+
+	printf("%s", info->tz[rule].name);
+	if (info->tz[rule].offset < 0) {
+		printf("-");
+		divide_time(-info->tz[rule].offset, &h, &m, &s);
+	} else
+		divide_time(info->tz[rule].offset, &h, &m, &s);
+	if (s)
+		printf("%u:%02u:%02u", h, m, s);
+	else if (m)
+		printf("%u:%02u", h, m);
+	else
+		printf("%u", h);
+
+}
+
+static void time_print_tz_rule(const struct xt_time_info1 *info, int rule)
+{
+	unsigned int h, m, s;
+
+	printf(",");
+	switch (info->tz[rule].type) {
+	case XT_TIME_TZ_TYPE_J0:
+		printf("%u", info->tz[rule].day);
+		break;
+	case XT_TIME_TZ_TYPE_J1:
+		printf("J%u", info->tz[rule].day);
+		break;
+	case XT_TIME_TZ_TYPE_M:
+		printf("M%u.%u.%u", info->tz[rule].month,
+		       info->tz[rule].week, info->tz[rule].day);
+	}
+	printf("/");
+	divide_time(info->tz[rule].secs, &h, &m, &s);
+	if (s)
+		printf("%u:%02u:%02u", h, m, s);
+	else if (m)
+		printf("%u:%02u", h, m);
+	else
+		printf("%u", h);
+}
+
+static void time_print_tz(const struct xt_time_info1 *info)
+{
+	time_print_tz_offset(info, 0);
+	if (info->tz[0].offset == info->tz[1].offset)
+		return;
+	time_print_tz_offset(info, 1);
+	time_print_tz_rule(info, 0);
+	time_print_tz_rule(info, 1);
+}
+
+static void time_print(const void *ip, const struct xt_entry_match *match,
+                       int numeric)
+{
+	struct xt_time_info1 *info = (void *)match->data;
+	unsigned int h, m, s;
+
+	printf("TIME ");
+
+	if (info->daytime_start != XT_TIME_MIN_DAYTIME ||
+	    info->daytime_stop != XT_TIME_MAX_DAYTIME) {
+		divide_time(info->daytime_start, &h, &m, &s);
+		printf("from %02u:%02u:%02u ", h, m, s);
+		divide_time(info->daytime_stop, &h, &m, &s);
+		printf("to %02u:%02u:%02u ", h, m, s);
+	}
+	if (info->weekdays_match != XT_TIME_ALL_WEEKDAYS) {
+		printf("on ");
+		time_print_weekdays(info->weekdays_match);
+	}
+	if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) {
+		printf("on ");
+		time_print_monthdays(info->monthdays_match, true);
+	}
+	if (info->date_start != 0) {
+		printf("starting from ");
+		time_print_date(info->date_start, NULL);
+	}
+	if (info->date_stop != INT_MAX) {
+		printf("until date ");
+		time_print_date(info->date_stop, NULL);
+	}
+	if (info->flags & XT_TIME_TZ)
+		time_print_tz(info);
+	else if (!(info->flags & XT_TIME_LOCAL_TZ))
+		printf("UTC ");
+}
+
+static void time_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_time_info1 *info = (const void *)match->data;
+	unsigned int h, m, s;
+
+	if (info->daytime_start != XT_TIME_MIN_DAYTIME ||
+	    info->daytime_stop != XT_TIME_MAX_DAYTIME) {
+		divide_time(info->daytime_start, &h, &m, &s);
+		printf("--timestart %02u:%02u:%02u ", h, m, s);
+		divide_time(info->daytime_stop, &h, &m, &s);
+		printf("--timestop %02u:%02u:%02u ", h, m, s);
+	}
+	if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) {
+		printf("--monthdays ");
+		time_print_monthdays(info->monthdays_match, false);
+	}
+	if (info->weekdays_match != XT_TIME_ALL_WEEKDAYS) {
+		printf("--weekdays ");
+		time_print_weekdays(info->weekdays_match);
+		printf(" ");
+	}
+	time_print_date(info->date_start, "--datestart");
+	time_print_date(info->date_stop, "--datestop");
+	if (info->flags & XT_TIME_TZ) {
+		printf("--tz ");
+		time_print_tz(info);
+		printf(" ");
+	} else if (!(info->flags & XT_TIME_LOCAL_TZ))
+		printf("--utc ");
+}
+
+static struct xtables_match time_match_v0 = {
+	.name          = "time",
+	.revision      = 0,
+	.family        = AF_UNSPEC,
+	.version       = XTABLES_VERSION,
+	.size          = XT_ALIGN(sizeof(struct xt_time_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_time_info)),
+	.help          = time_help,
+	.init          = time_init,
+	.parse         = time_parse,
+	.print         = time_print,
+	.save          = time_save,
+	.extra_opts    = time_opts_v0,
+};
+
+static struct xtables_match time_match = {
+	.name          = "time",
+	.revision      = 1,
+	.family        = AF_UNSPEC,
+	.version       = XTABLES_VERSION,
+	.size          = XT_ALIGN(sizeof(struct xt_time_info1)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_time_info1)),
+	.help          = time_help,
+	.init          = time_init,
+	.parse         = time_parse,
+	.print         = time_print,
+	.save          = time_save,
+	.extra_opts    = time_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&time_match_v0);
+	xtables_register_match(&time_match);
+}
diff --git a/ap/app/iptables/extensions/libxt_time.man b/ap/app/iptables/extensions/libxt_time.man
new file mode 100755
index 0000000..83625a2
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_time.man
@@ -0,0 +1,69 @@
+This matches if the packet arrival time/date is within a given range. All
+options are optional, but are ANDed when specified.
+.TP
+\fB\-\-datestart\fP \fIYYYY\fP[\fB\-\fP\fIMM\fP[\fB\-\fP\fIDD\fP[\fBT\fP\fIhh\fP[\fB:\fP\fImm\fP[\fB:\fP\fIss\fP]]]]]
+.TP
+\fB\-\-datestop\fP \fIYYYY\fP[\fB\-\fP\fIMM\fP[\fB\-\fP\fIDD\fP[\fBT\fP\fIhh\fP[\fB:\fP\fImm\fP[\fB:\fP\fIss\fP]]]]]
+.IP
+Only match during the given time, which must be in ISO 8601 "T" notation.
+The possible time range is 1970-01-01T00:00:00 to 2038-01-19T04:17:07.
+.IP
+If \-\-datestart or \-\-datestop are not specified, it will default to 1970-01-01
+and 2038-01-19, respectively.
+.TP
+\fB\-\-timestart\fP \fIhh\fP\fB:\fP\fImm\fP[\fB:\fP\fIss\fP]
+.TP
+\fB\-\-timestop\fP \fIhh\fP\fB:\fP\fImm\fP[\fB:\fP\fIss\fP]
+.IP
+Only match during the given daytime. The possible time range is 00:00:00 to
+23:59:59. Leading zeroes are allowed (e.g. "06:03") and correctly interpreted
+as base-10.
+.TP
+[\fB!\fR] \fB\-\-monthdays\fP \fIday\fP[\fB,\fP\fIday\fP...]
+.IP
+Only match on the given days of the month. Possible values are \fB1\fR
+to \fB31\fR. Note that specifying \fB31\fR will of course not match
+on months which do not have a 31st day; the same goes for 28- or 29-day
+February.
+.TP
+[\fB!\fR] \fB\-\-weekdays\fP \fIday\fP[\fB,\fP\fIday\fP...]
+.IP
+Only match on the given weekdays. Possible values are \fBMon\fR, \fBTue\fR,
+\fBWed\fR, \fBThu\fR, \fBFri\fR, \fBSat\fR, \fBSun\fR, or values from \fB1\fR
+to \fB7\fR, respectively. You may also use two-character variants (\fBMo\fP,
+\fBTu\fR, etc.).
+.TP
+\fB\-\-utc\fP
+.IP
+Interpret the times given for \fB\-\-datestart\fP, \fB\-\-datestop\fP,
+\fB\-\-timestart\fP and \fB\-\-timestop\fP to be UTC.
+.TP
+\fB\-\-localtz\fP
+.IP
+Interpret the times given for \fB\-\-datestart\fP, \fB\-\-datestop\fP,
+\fB\-\-timestart\fP and \fB\-\-timestop\fP to be local kernel time. (Default)
+.PP
+EXAMPLES. To match on weekends, use:
+.IP
+\-m time \-\-weekdays Sa,Su
+.PP
+Or, to match (once) on a national holiday block:
+.IP
+\-m time \-\-datestart 2007\-12\-24 \-\-datestop 2007\-12\-27
+.PP
+Since the stop time is actually inclusive, you would need the following stop
+time to not match the first second of the new day:
+.IP
+\-m time \-\-datestart 2007\-01\-01T17:00 \-\-datestop 2007\-01\-01T23:59:59
+.PP
+During lunch hour:
+.IP
+\-m time \-\-timestart 12:30 \-\-timestop 13:30
+.PP
+The fourth Friday in the month:
+.IP
+\-m time \-\-weekdays Fr \-\-monthdays 22,23,24,25,26,27,28
+.PP
+(Note that this exploits a certain mathematical property. It is not possible to
+say "fourth Thursday OR fourth Friday" in one rule. It is possible with
+multiple rules, though.)
diff --git a/ap/app/iptables/extensions/libxt_tos.c b/ap/app/iptables/extensions/libxt_tos.c
new file mode 100755
index 0000000..b810ea6
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_tos.c
@@ -0,0 +1,190 @@
+/*
+ * Shared library add-on to iptables to add tos match support
+ *
+ * Copyright © CC Computer Consultants GmbH, 2007
+ * Contact: Jan Engelhardt <jengelh@computergmbh.de>
+ */
+#include <getopt.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_dscp.h>
+#include <linux/netfilter_ipv4/ipt_tos.h>
+#include "tos_values.c"
+
+enum {
+	FLAG_TOS = 1 << 0,
+};
+
+static const struct option tos_mt_opts[] = {
+	{.name = "tos", .has_arg = true, .val = 't'},
+	{ .name = NULL }
+};
+
+static void tos_mt_help(void)
+{
+	const struct tos_symbol_info *symbol;
+
+	printf(
+"tos match options:\n"
+"[!] --tos value[/mask]    Match Type of Service/Priority field value\n"
+"[!] --tos symbol          Match TOS field (IPv4 only) by symbol\n"
+"                          Accepted symbolic names for value are:\n");
+
+	for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
+		printf("                          (0x%02x) %2u %s\n",
+		       symbol->value, symbol->value, symbol->name);
+
+	printf("\n");
+}
+
+static int tos_mt_parse_v0(int c, char **argv, int invert, unsigned int *flags,
+                           const void *entry, struct xt_entry_match **match)
+{
+	struct ipt_tos_info *info = (void *)(*match)->data;
+	struct tos_value_mask tvm;
+
+	switch (c) {
+	case 't':
+		xtables_param_act(XTF_ONLY_ONCE, "tos", "--tos", *flags & FLAG_TOS);
+		if (!tos_parse_symbolic(optarg, &tvm, 0xFF))
+			xtables_param_act(XTF_BAD_VALUE, "tos", "--tos", optarg);
+		if (tvm.mask != 0xFF)
+			xtables_error(PARAMETER_PROBLEM, "tos: Your kernel is "
+			           "too old to support anything besides /0xFF "
+				   "as a mask.");
+		info->tos = tvm.value;
+		if (invert)
+			info->invert = true;
+		*flags |= FLAG_TOS;
+		return true;
+	}
+	return false;
+}
+
+static int tos_mt_parse(int c, char **argv, int invert, unsigned int *flags,
+                        const void *entry, struct xt_entry_match **match)
+{
+	struct xt_tos_match_info *info = (void *)(*match)->data;
+	struct tos_value_mask tvm = {.mask = 0xFF};
+
+	switch (c) {
+	case 't':
+		xtables_param_act(XTF_ONLY_ONCE, "tos", "--tos", *flags & FLAG_TOS);
+		if (!tos_parse_symbolic(optarg, &tvm, 0x3F))
+			xtables_param_act(XTF_BAD_VALUE, "tos", "--tos", optarg);
+		info->tos_value = tvm.value;
+		info->tos_mask  = tvm.mask;
+		if (invert)
+			info->invert = true;
+		*flags |= FLAG_TOS;
+		return true;
+	}
+	return false;
+}
+
+static void tos_mt_check(unsigned int flags)
+{
+	if (flags == 0)
+		xtables_error(PARAMETER_PROBLEM,
+		           "tos: --tos parameter required");
+}
+
+static void tos_mt_print_v0(const void *ip, const struct xt_entry_match *match,
+                            int numeric)
+{
+	const struct ipt_tos_info *info = (const void *)match->data;
+
+	printf("tos match ");
+	if (info->invert)
+		printf("!");
+	if (numeric || !tos_try_print_symbolic("", info->tos, 0x3F))
+		printf("0x%02x ", info->tos);
+}
+
+static void tos_mt_print(const void *ip, const struct xt_entry_match *match,
+                         int numeric)
+{
+	const struct xt_tos_match_info *info = (const void *)match->data;
+
+	printf("tos match ");
+	if (info->invert)
+		printf("!");
+	if (numeric ||
+	    !tos_try_print_symbolic("", info->tos_value, info->tos_mask))
+		printf("0x%02x/0x%02x ", info->tos_value, info->tos_mask);
+}
+
+static void tos_mt_save_v0(const void *ip, const struct xt_entry_match *match)
+{
+	const struct ipt_tos_info *info = (const void *)match->data;
+
+	if (info->invert)
+		printf("! ");
+	printf("--tos 0x%02x ", info->tos);
+}
+
+static void tos_mt_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_tos_match_info *info = (const void *)match->data;
+
+	if (info->invert)
+		printf("! ");
+	printf("--tos 0x%02x/0x%02x ", info->tos_value, info->tos_mask);
+}
+
+static struct xtables_match tos_mt_reg_v0 = {
+	.version       = XTABLES_VERSION,
+	.name          = "tos",
+	.family        = NFPROTO_IPV4,
+	.revision      = 0,
+	.size          = XT_ALIGN(sizeof(struct ipt_tos_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct ipt_tos_info)),
+	.help          = tos_mt_help,
+	.parse         = tos_mt_parse_v0,
+	.final_check   = tos_mt_check,
+	.print         = tos_mt_print_v0,
+	.save          = tos_mt_save_v0,
+	.extra_opts    = tos_mt_opts,
+};
+
+static struct xtables_match tos_mt_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "tos",
+	.family        = NFPROTO_IPV4,
+	.revision      = 1,
+	.size          = XT_ALIGN(sizeof(struct xt_tos_match_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_tos_match_info)),
+	.help          = tos_mt_help,
+	.parse         = tos_mt_parse,
+	.final_check   = tos_mt_check,
+	.print         = tos_mt_print,
+	.save          = tos_mt_save,
+	.extra_opts    = tos_mt_opts,
+};
+
+static struct xtables_match tos_mt6_reg = {
+	.version       = XTABLES_VERSION,
+	.name          = "tos",
+	.family        = NFPROTO_IPV6,
+	.revision      = 1,
+	.size          = XT_ALIGN(sizeof(struct xt_tos_match_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_tos_match_info)),
+	.help          = tos_mt_help,
+	.parse         = tos_mt_parse,
+	.final_check   = tos_mt_check,
+	.print         = tos_mt_print,
+	.save          = tos_mt_save,
+	.extra_opts    = tos_mt_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&tos_mt_reg_v0);
+	xtables_register_match(&tos_mt_reg);
+	xtables_register_match(&tos_mt6_reg);
+}
diff --git a/ap/app/iptables/extensions/libxt_tos.man b/ap/app/iptables/extensions/libxt_tos.man
new file mode 100755
index 0000000..ae73e63
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_tos.man
@@ -0,0 +1,12 @@
+This module matches the 8-bit Type of Service field in the IPv4 header (i.e.
+including the "Precedence" bits) or the (also 8-bit) Priority field in the IPv6
+header.
+.TP
+[\fB!\fP] \fB\-\-tos\fP \fIvalue\fP[\fB/\fP\fImask\fP]
+Matches packets with the given TOS mark value. If a mask is specified, it is
+logically ANDed with the TOS mark before the comparison.
+.TP
+[\fB!\fP] \fB\-\-tos\fP \fIsymbol\fP
+You can specify a symbolic name when using the tos match for IPv4. The list of
+recognized TOS names can be obtained by calling iptables with \fB\-m tos \-h\fP.
+Note that this implies a mask of 0x3F, i.e. all but the ECN bits.
diff --git a/ap/app/iptables/extensions/libxt_tsreputation.c b/ap/app/iptables/extensions/libxt_tsreputation.c
new file mode 100755
index 0000000..27db8cd
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_tsreputation.c
@@ -0,0 +1,101 @@
+/*
+ *	libxt_tsreputation - iptables part for xt_tsreputation
+ *	Copyright © Paul Dale 2009
+ *	Contact: <Paul_Dale@McAfee.com>
+ *
+ *	libxt_tsreputation.c 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 or 3 of the License.
+ */
+#include <sys/types.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <limits.h>
+
+#include <linux/netfilter/xt_tsreputation.h>
+#include <xtables.h>
+
+#define XT_TSREP_DEFINED	1
+
+
+static const struct option tsreputation_opts[] = {
+	{ "reputation", true,  NULL, 'R'},
+	{ .name = NULL }
+};
+
+
+static void tsreputation_help(void)
+{
+	printf(
+"tsreputation match options:\n"
+"    --reputation rep     Reputation threshold (signed integer)\n");
+}
+
+static void tsreputation_init(struct xt_entry_match *m)
+{
+	struct xt_tsreputation_info *info = (void *)m->data;
+
+	info->reputation = 0;
+}
+
+
+static int tsreputation_parse(int c, char **argv, int invert, unsigned int *flags,
+                      const void *entry, struct xt_entry_match **match)
+{
+	struct xt_tsreputation_info *info = (void *)(*match)->data;
+	char *end;
+
+	switch (c) {
+	case 'R': /* --reputation */
+		if (*flags & XT_TSREP_DEFINED)
+			xtables_error(PARAMETER_PROBLEM, "xt_tsreputation: "
+				"Only use \"--reputation\" once!");
+		*flags |= XT_TSREP_DEFINED;
+		info->reputation = strtol(optarg, &end, 10);
+		if (end == optarg || *end != '\0')
+			xtables_error(PARAMETER_PROBLEM,
+			           "No integer argument specified");
+		info->invert = invert?1:0;
+		return 1;
+	}
+	return 0;
+}
+
+static void tsreputation_print(const void *ip, const struct xt_entry_match *match,
+                       int numeric)
+{
+	struct xt_tsreputation_info *info = (void *)match->data;
+
+	printf("TSREPUTATION %d ", info->reputation);
+}
+
+static void tsreputation_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_tsreputation_info *info = (const void *)match->data;
+
+	printf("--reputation %d ", info->reputation);
+}
+
+static struct xtables_match tsreputation_match = {
+	.name          = "tsreputation",
+	.family        = AF_UNSPEC,
+	.version       = XTABLES_VERSION,
+	.size          = XT_ALIGN(sizeof(struct xt_tsreputation_info)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_tsreputation_info)),
+	.help          = tsreputation_help,
+	.init          = tsreputation_init,
+	.parse         = tsreputation_parse,
+	.print         = tsreputation_print,
+	.save          = tsreputation_save,
+	.extra_opts    = tsreputation_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&tsreputation_match);
+}
diff --git a/ap/app/iptables/extensions/libxt_tsreputation.man b/ap/app/iptables/extensions/libxt_tsreputation.man
new file mode 100755
index 0000000..710f989
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_tsreputation.man
@@ -0,0 +1,7 @@
+This matches if the packet reputation is equal to or less than the specified
+threshold.
+.TP
+\fB\-\-reputation\fP \fIn\fP
+.IP
+Specify the reputation threshold to match again.  Packets with a reputation of
+this value or lower are matched..
diff --git a/ap/app/iptables/extensions/libxt_u32.c b/ap/app/iptables/extensions/libxt_u32.c
new file mode 100755
index 0000000..c2aeb27
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_u32.c
@@ -0,0 +1,284 @@
+/* Shared library add-on to iptables to add u32 matching,
+ * generalized matching on values found at packet offsets
+ *
+ * Detailed doc is in the kernel module source
+ * net/netfilter/xt_u32.c
+ *
+ * (C) 2002 by Don Cohen <don-netf@isis.cs3-inc.com>
+ * Released under the terms of GNU GPL v2
+ *
+ * Copyright © CC Computer Consultants GmbH, 2007
+ * Contact: <jengelh@computergmbh.de>
+ */
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <xtables.h>
+#include <linux/netfilter/xt_u32.h>
+
+static const struct option u32_opts[] = {
+	{"u32", 1, NULL, 'u'},
+	{ .name = NULL }
+};
+
+static void u32_help(void)
+{
+	printf(
+		"u32 match options:\n"
+		"[!] --u32 tests\n"
+		"\t\t""tests := location \"=\" value | tests \"&&\" location \"=\" value\n"
+		"\t\t""value := range | value \",\" range\n"
+		"\t\t""range := number | number \":\" number\n"
+		"\t\t""location := number | location operator number\n"
+		"\t\t""operator := \"&\" | \"<<\" | \">>\" | \"@\"\n");
+}
+
+static void u32_dump(const struct xt_u32 *data)
+{
+	const struct xt_u32_test *ct;
+	unsigned int testind, i;
+
+	for (testind = 0; testind < data->ntests; ++testind) {
+		ct = &data->tests[testind];
+
+		if (testind > 0)
+			printf("&&");
+
+		printf("0x%x", ct->location[0].number);
+		for (i = 1; i < ct->nnums; ++i) {
+			switch (ct->location[i].nextop) {
+			case XT_U32_AND:
+				printf("&");
+				break;
+			case XT_U32_LEFTSH:
+				printf("<<");
+				break;
+			case XT_U32_RIGHTSH:
+				printf(">>");
+				break;
+			case XT_U32_AT:
+				printf("@");
+				break;
+			}
+			printf("0x%x", ct->location[i].number);
+		}
+
+		printf("=");
+		for (i = 0; i < ct->nvalues; ++i) {
+			if (i > 0)
+				printf(",");
+			if (ct->value[i].min == ct->value[i].max)
+				printf("0x%x", ct->value[i].min);
+			else
+				printf("0x%x:0x%x", ct->value[i].min,
+				       ct->value[i].max);
+		}
+	}
+	printf(" ");
+}
+
+/* string_to_number() is not quite what we need here ... */
+static u_int32_t parse_number(char **s, int pos)
+{
+	u_int32_t number;
+	char *end;
+
+	errno  = 0;
+	number = strtoul(*s, &end, 0);
+	if (end == *s)
+		xtables_error(PARAMETER_PROBLEM,
+			   "u32: at char %d: expected number", pos);
+	if (errno != 0)
+		xtables_error(PARAMETER_PROBLEM,
+			   "u32: at char %d: error reading number", pos);
+	*s = end;
+	return number;
+}
+
+static int u32_parse(int c, char **argv, int invert, unsigned int *flags,
+		     const void *entry, struct xt_entry_match **match)
+{
+	struct xt_u32 *data = (void *)(*match)->data;
+	unsigned int testind = 0, locind = 0, valind = 0;
+	struct xt_u32_test *ct = &data->tests[testind]; /* current test */
+	char *arg = argv[optind-1]; /* the argument string */
+	char *start = arg;
+	int state = 0;
+
+	if (c != 'u')
+		return 0;
+
+	data->invert = invert;
+
+	/*
+	 * states:
+	 * 0 = looking for numbers and operations,
+	 * 1 = looking for ranges
+	 */
+	while (1) {
+		/* read next operand/number or range */
+		while (isspace(*arg))
+			++arg;
+
+		if (*arg == '\0') {
+			/* end of argument found */
+			if (state == 0)
+				xtables_error(PARAMETER_PROBLEM,
+					   "u32: abrupt end of input after location specifier");
+			if (valind == 0)
+				xtables_error(PARAMETER_PROBLEM,
+					   "u32: test ended with no value specified");
+
+			ct->nnums    = locind;
+			ct->nvalues  = valind;
+			data->ntests = ++testind;
+
+			if (testind > XT_U32_MAXSIZE)
+				xtables_error(PARAMETER_PROBLEM,
+				           "u32: at char %u: too many \"&&\"s",
+				           (unsigned int)(arg - start));
+			return 1;
+		}
+
+		if (state == 0) {
+			/*
+			 * reading location: read a number if nothing read yet,
+			 * otherwise either op number or = to end location spec
+			 */
+			if (*arg == '=') {
+				if (locind == 0) {
+					xtables_error(PARAMETER_PROBLEM,
+					           "u32: at char %u: "
+					           "location spec missing",
+					           (unsigned int)(arg - start));
+				} else {
+					++arg;
+					state = 1;
+				}
+			} else {
+				if (locind != 0) {
+					/* need op before number */
+					if (*arg == '&') {
+						ct->location[locind].nextop = XT_U32_AND;
+					} else if (*arg == '<') {
+						if (*++arg != '<')
+							xtables_error(PARAMETER_PROBLEM,
+								   "u32: at char %u: a second '<' was expected", (unsigned int)(arg - start));
+						ct->location[locind].nextop = XT_U32_LEFTSH;
+					} else if (*arg == '>') {
+						if (*++arg != '>')
+							xtables_error(PARAMETER_PROBLEM,
+								   "u32: at char %u: a second '>' was expected", (unsigned int)(arg - start));
+						ct->location[locind].nextop = XT_U32_RIGHTSH;
+					} else if (*arg == '@') {
+						ct->location[locind].nextop = XT_U32_AT;
+					} else {
+						xtables_error(PARAMETER_PROBLEM,
+							"u32: at char %u: operator expected", (unsigned int)(arg - start));
+					}
+					++arg;
+				}
+				/* now a number; string_to_number skips white space? */
+				ct->location[locind].number =
+					parse_number(&arg, arg - start);
+				if (++locind > XT_U32_MAXSIZE)
+					xtables_error(PARAMETER_PROBLEM,
+						   "u32: at char %u: too many operators", (unsigned int)(arg - start));
+			}
+		} else {
+			/*
+			 * state 1 - reading values: read a range if nothing
+			 * read yet, otherwise either ,range or && to end
+			 * test spec
+			 */
+			if (*arg == '&') {
+				if (*++arg != '&')
+					xtables_error(PARAMETER_PROBLEM,
+						   "u32: at char %u: a second '&' was expected", (unsigned int)(arg - start));
+				if (valind == 0) {
+					xtables_error(PARAMETER_PROBLEM,
+						   "u32: at char %u: value spec missing", (unsigned int)(arg - start));
+				} else {
+					ct->nnums   = locind;
+					ct->nvalues = valind;
+					ct = &data->tests[++testind];
+					if (testind > XT_U32_MAXSIZE)
+						xtables_error(PARAMETER_PROBLEM,
+							   "u32: at char %u: too many \"&&\"s", (unsigned int)(arg - start));
+					++arg;
+					state  = 0;
+					locind = 0;
+					valind = 0;
+				}
+			} else { /* read value range */
+				if (valind > 0) { /* need , before number */
+					if (*arg != ',')
+						xtables_error(PARAMETER_PROBLEM,
+							   "u32: at char %u: expected \",\" or \"&&\"", (unsigned int)(arg - start));
+					++arg;
+				}
+				ct->value[valind].min =
+					parse_number(&arg, arg - start);
+
+				while (isspace(*arg))
+					++arg;
+
+				if (*arg == ':') {
+					++arg;
+					ct->value[valind].max =
+						parse_number(&arg, arg-start);
+				} else {
+					ct->value[valind].max =
+						ct->value[valind].min;
+				}
+
+				if (++valind > XT_U32_MAXSIZE)
+					xtables_error(PARAMETER_PROBLEM,
+						   "u32: at char %u: too many \",\"s", (unsigned int)(arg - start));
+			}
+		}
+	}
+}
+
+static void u32_print(const void *ip, const struct xt_entry_match *match,
+                      int numeric)
+{
+	const struct xt_u32 *data = (const void *)match->data;
+	printf("u32 ");
+	if (data->invert)
+		printf("! ");
+	u32_dump(data);
+}
+
+static void u32_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_u32 *data = (const void *)match->data;
+	if (data->invert)
+		printf("! ");
+	printf("--u32 ");
+	u32_dump(data);
+}
+
+static struct xtables_match u32_match = {
+	.name          = "u32",
+	.family        = AF_UNSPEC,
+	.version       = XTABLES_VERSION,
+	.size          = XT_ALIGN(sizeof(struct xt_u32)),
+	.userspacesize = XT_ALIGN(sizeof(struct xt_u32)),
+	.help          = u32_help,
+	.parse         = u32_parse,
+	.print         = u32_print,
+	.save          = u32_save,
+	.extra_opts    = u32_opts,
+};
+
+void _init(void)
+{
+	xtables_register_match(&u32_match);
+}
diff --git a/ap/app/iptables/extensions/libxt_u32.man b/ap/app/iptables/extensions/libxt_u32.man
new file mode 100755
index 0000000..2ffab30
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_u32.man
@@ -0,0 +1,129 @@
+U32 tests whether quantities of up to 4 bytes extracted from a packet have
+specified values. The specification of what to extract is general enough to
+find data at given offsets from tcp headers or payloads.
+.TP
+[\fB!\fP] \fB\-\-u32\fP \fItests\fP
+The argument amounts to a program in a small language described below.
+.IP
+tests := location "=" value | tests "&&" location "=" value
+.IP
+value := range | value "," range
+.IP
+range := number | number ":" number
+.PP
+a single number, \fIn\fR, is interpreted the same as \fIn:n\fR. \fIn:m\fR is
+interpreted as the range of numbers \fB>=n\fR and \fB<=m\fR.
+.IP "" 4
+location := number | location operator number
+.IP "" 4
+operator := "&" | "<<" | ">>" | "@"
+.PP
+The operators \fB&\fR, \fB<<\fR, \fB>>\fR and \fB&&\fR mean the same as in C.
+The \fB=\fR is really a set membership operator and the value syntax describes
+a set. The \fB@\fR operator is what allows moving to the next header and is
+described further below.
+.PP
+There are currently some artificial implementation limits on the size of the
+tests:
+.IP "    *"
+no more than 10 of "\fB=\fR" (and 9 "\fB&&\fR"s) in the u32 argument
+.IP "    *"
+no more than 10 ranges (and 9 commas) per value
+.IP "    *"
+no more than 10 numbers (and 9 operators) per location
+.PP
+To describe the meaning of location, imagine the following machine that
+interprets it. There are three registers:
+.IP
+A is of type \fBchar *\fR, initially the address of the IP header
+.IP
+B and C are unsigned 32 bit integers, initially zero
+.PP
+The instructions are:
+.IP
+number B = number;
+.IP
+C = (*(A+B)<<24) + (*(A+B+1)<<16) + (*(A+B+2)<<8) + *(A+B+3)
+.IP
+&number C = C & number
+.IP
+<< number C = C << number
+.IP
+>> number C = C >> number
+.IP
+@number A = A + C; then do the instruction number
+.PP
+Any access of memory outside [skb\->data,skb\->end] causes the match to fail.
+Otherwise the result of the computation is the final value of C.
+.PP
+Whitespace is allowed but not required in the tests. However, the characters
+that do occur there are likely to require shell quoting, so it is a good idea
+to enclose the arguments in quotes.
+.PP
+Example:
+.IP
+match IP packets with total length >= 256
+.IP
+The IP header contains a total length field in bytes 2-3.
+.IP
+\-\-u32 "\fB0 & 0xFFFF = 0x100:0xFFFF\fP"
+.IP
+read bytes 0-3
+.IP
+AND that with 0xFFFF (giving bytes 2-3), and test whether that is in the range
+[0x100:0xFFFF]
+.PP
+Example: (more realistic, hence more complicated)
+.IP
+match ICMP packets with icmp type 0
+.IP
+First test that it is an ICMP packet, true iff byte 9 (protocol) = 1
+.IP
+\-\-u32 "\fB6 & 0xFF = 1 &&\fP ...
+.IP
+read bytes 6-9, use \fB&\fR to throw away bytes 6-8 and compare the result to
+1. Next test that it is not a fragment. (If so, it might be part of such a
+packet but we cannot always tell.) N.B.: This test is generally needed if you
+want to match anything beyond the IP header. The last 6 bits of byte 6 and all
+of byte 7 are 0 iff this is a complete packet (not a fragment). Alternatively,
+you can allow first fragments by only testing the last 5 bits of byte 6.
+.IP
+ ... \fB4 & 0x3FFF = 0 &&\fR ...
+.IP
+Last test: the first byte past the IP header (the type) is 0. This is where we
+have to use the @syntax. The length of the IP header (IHL) in 32 bit words is
+stored in the right half of byte 0 of the IP header itself.
+.IP
+ ... \fB0 >> 22 & 0x3C @ 0 >> 24 = 0\fR"
+.IP
+The first 0 means read bytes 0-3, \fB>>22\fR means shift that 22 bits to the
+right. Shifting 24 bits would give the first byte, so only 22 bits is four
+times that plus a few more bits. \fB&3C\fR then eliminates the two extra bits
+on the right and the first four bits of the first byte. For instance, if IHL=5,
+then the IP header is 20 (4 x 5) bytes long. In this case, bytes 0-1 are (in
+binary) xxxx0101 yyzzzzzz, \fB>>22\fR gives the 10 bit value xxxx0101yy and
+\fB&3C\fR gives 010100. \fB@\fR means to use this number as a new offset into
+the packet, and read four bytes starting from there. This is the first 4 bytes
+of the ICMP payload, of which byte 0 is the ICMP type. Therefore, we simply
+shift the value 24 to the right to throw out all but the first byte and compare
+the result with 0.
+.PP
+Example:
+.IP
+TCP payload bytes 8-12 is any of 1, 2, 5 or 8
+.IP
+First we test that the packet is a tcp packet (similar to ICMP).
+.IP
+\-\-u32 "\fB6 & 0xFF = 6 &&\fP ...
+.IP
+Next, test that it is not a fragment (same as above).
+.IP
+ ... \fB0 >> 22 & 0x3C @ 12 >> 26 & 0x3C @ 8 = 1,2,5,8\fR"
+.IP
+\fB0>>22&3C\fR as above computes the number of bytes in the IP header. \fB@\fR
+makes this the new offset into the packet, which is the start of the TCP
+header. The length of the TCP header (again in 32 bit words) is the left half
+of byte 12 of the TCP header. The \fB12>>26&3C\fR computes this length in bytes
+(similar to the IP header before). "@" makes this the new offset, which is the
+start of the TCP payload. Finally, 8 reads bytes 8-12 of the payload and
+\fB=\fR checks whether the result is any of 1, 2, 5 or 8.
diff --git a/ap/app/iptables/extensions/libxt_udp.c b/ap/app/iptables/extensions/libxt_udp.c
new file mode 100755
index 0000000..4b4e84f
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_udp.c
@@ -0,0 +1,226 @@
+/* Shared library add-on to iptables to add UDP support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <netinet/in.h>
+#include <xtables.h>
+#include <linux/netfilter/xt_tcpudp.h>
+
+static void udp_help(void)
+{
+	printf(
+"udp match options:\n"
+"[!] --source-port port[:port]\n"
+" --sport ...\n"
+"				match source port(s)\n"
+"[!] --destination-port port[:port]\n"
+" --dport ...\n"
+"				match destination port(s)\n");
+}
+
+static const struct option udp_opts[] = {
+	{ "source-port", 1, NULL, '1' },
+	{ "sport", 1, NULL, '1' }, /* synonym */
+	{ "destination-port", 1, NULL, '2' },
+	{ "dport", 1, NULL, '2' }, /* synonym */
+	{ .name = NULL }
+};
+
+static void
+parse_udp_ports(const char *portstring, u_int16_t *ports)
+{
+	char *buffer;
+	char *cp;
+
+	buffer = strdup(portstring);
+	if ((cp = strchr(buffer, ':')) == NULL)
+		ports[0] = ports[1] = xtables_parse_port(buffer, "udp");
+	else {
+		*cp = '\0';
+		cp++;
+
+		ports[0] = buffer[0] ? xtables_parse_port(buffer, "udp") : 0;
+		ports[1] = cp[0] ? xtables_parse_port(cp, "udp") : 0xFFFF;
+
+		if (ports[0] > ports[1])
+			xtables_error(PARAMETER_PROBLEM,
+				   "invalid portrange (min > max)");
+	}
+	free(buffer);
+}
+
+static void udp_init(struct xt_entry_match *m)
+{
+	struct xt_udp *udpinfo = (struct xt_udp *)m->data;
+
+	udpinfo->spts[1] = udpinfo->dpts[1] = 0xFFFF;
+}
+
+#define UDP_SRC_PORTS 0x01
+#define UDP_DST_PORTS 0x02
+
+static int
+udp_parse(int c, char **argv, int invert, unsigned int *flags,
+          const void *entry, struct xt_entry_match **match)
+{
+	struct xt_udp *udpinfo = (struct xt_udp *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		if (*flags & UDP_SRC_PORTS)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--source-port' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_udp_ports(argv[optind-1], udpinfo->spts);
+		if (invert)
+			udpinfo->invflags |= XT_UDP_INV_SRCPT;
+		*flags |= UDP_SRC_PORTS;
+		break;
+
+	case '2':
+		if (*flags & UDP_DST_PORTS)
+			xtables_error(PARAMETER_PROBLEM,
+				   "Only one `--destination-port' allowed");
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_udp_ports(argv[optind-1], udpinfo->dpts);
+		if (invert)
+			udpinfo->invflags |= XT_UDP_INV_DSTPT;
+		*flags |= UDP_DST_PORTS;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static char *
+port_to_service(int port)
+{
+	struct servent *service;
+
+	if ((service = getservbyport(htons(port), "udp")))
+		return service->s_name;
+
+	return NULL;
+}
+
+static void
+print_port(u_int16_t port, int numeric)
+{
+	char *service;
+
+	if (numeric || (service = port_to_service(port)) == NULL)
+		printf("%u", port);
+	else
+		printf("%s", service);
+}
+
+static void
+print_ports(const char *name, u_int16_t min, u_int16_t max,
+	    int invert, int numeric)
+{
+	const char *inv = invert ? "!" : "";
+
+	if (min != 0 || max != 0xFFFF || invert) {
+		printf("%s", name);
+		if (min == max) {
+			printf(":%s", inv);
+			print_port(min, numeric);
+		} else {
+			printf("s:%s", inv);
+			print_port(min, numeric);
+			printf(":");
+			print_port(max, numeric);
+		}
+		printf(" ");
+	}
+}
+
+static void
+udp_print(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+	const struct xt_udp *udp = (struct xt_udp *)match->data;
+
+	printf("udp ");
+	print_ports("spt", udp->spts[0], udp->spts[1],
+		    udp->invflags & XT_UDP_INV_SRCPT,
+		    numeric);
+	print_ports("dpt", udp->dpts[0], udp->dpts[1],
+		    udp->invflags & XT_UDP_INV_DSTPT,
+		    numeric);
+	if (udp->invflags & ~XT_UDP_INV_MASK)
+		printf("Unknown invflags: 0x%X ",
+		       udp->invflags & ~XT_UDP_INV_MASK);
+}
+
+static void udp_save(const void *ip, const struct xt_entry_match *match)
+{
+	const struct xt_udp *udpinfo = (struct xt_udp *)match->data;
+
+	if (udpinfo->spts[0] != 0
+	    || udpinfo->spts[1] != 0xFFFF) {
+		if (udpinfo->invflags & XT_UDP_INV_SRCPT)
+			printf("! ");
+		if (udpinfo->spts[0]
+		    != udpinfo->spts[1])
+			printf("--sport %u:%u ",
+			       udpinfo->spts[0],
+			       udpinfo->spts[1]);
+		else
+			printf("--sport %u ",
+			       udpinfo->spts[0]);
+	}
+
+	if (udpinfo->dpts[0] != 0
+	    || udpinfo->dpts[1] != 0xFFFF) {
+		if (udpinfo->invflags & XT_UDP_INV_DSTPT)
+			printf("! ");
+		if (udpinfo->dpts[0]
+		    != udpinfo->dpts[1])
+			printf("--dport %u:%u ",
+			       udpinfo->dpts[0],
+			       udpinfo->dpts[1]);
+		else
+			printf("--dport %u ",
+			       udpinfo->dpts[0]);
+	}
+}
+
+static struct xtables_match udp_match = {
+	.family		= NFPROTO_IPV4,
+	.name		= "udp",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_udp)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_udp)),
+	.help		= udp_help,
+	.init		= udp_init,
+	.parse		= udp_parse,
+	.print		= udp_print,
+	.save		= udp_save,
+	.extra_opts	= udp_opts,
+};
+
+static struct xtables_match udp_match6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "udp",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_udp)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_udp)),
+	.help		= udp_help,
+	.init		= udp_init,
+	.parse		= udp_parse,
+	.print		= udp_print,
+	.save		= udp_save,
+	.extra_opts	= udp_opts,
+};
+
+void
+_init(void)
+{
+	xtables_register_match(&udp_match);
+	xtables_register_match(&udp_match6);
+}
diff --git a/ap/app/iptables/extensions/libxt_udp.man b/ap/app/iptables/extensions/libxt_udp.man
new file mode 100755
index 0000000..5339c8e
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_udp.man
@@ -0,0 +1,14 @@
+These extensions can be used if `\-\-protocol udp' is specified. It
+provides the following options:
+.TP
+[\fB!\fP] \fB\-\-source\-port\fP,\fB\-\-sport\fP \fIport\fP[\fB:\fP\fIport\fP]
+Source port or port range specification.
+See the description of the
+\fB\-\-source\-port\fP
+option of the TCP extension for details.
+.TP
+[\fB!\fP] \fB\-\-destination\-port\fP,\fB\-\-dport\fP \fIport\fP[\fB:\fP\fIport\fP]
+Destination port or port range specification.
+See the description of the
+\fB\-\-destination\-port\fP
+option of the TCP extension for details.
diff --git a/ap/app/iptables/extensions/libxt_webstr.c b/ap/app/iptables/extensions/libxt_webstr.c
new file mode 100755
index 0000000..0ffa365
--- /dev/null
+++ b/ap/app/iptables/extensions/libxt_webstr.c
@@ -0,0 +1,196 @@
+/* Shared library add-on to iptables to add string matching support. 
+ *
+ * (C) 2010 Atheros Communications. Inc.
+ *      3/26/2010: <yingming.yu@atheros.com> 
+ *          Port to netfilter core interface of 2.6.31 kernel (ipt->xt) 
+ * 
+ * Copyright (C) 2000 Emmanuel Roger  <winfield@freegates.be>
+ *
+ * ChangeLog
+ *     27.01.2001: Gianni Tedesco <gianni@ecsc.co.uk>
+ *             Changed --tos to --string in save(). Also
+ *             updated to work with slightly modified
+ *             ipt_string_info.
+ */
+
+/* Shared library add-on to iptables to add webstr matching support. 
+ *
+ * Copyright (C) 2003, CyberTAN Corporation
+ * All Rights Reserved.
+ *
+ * Description:
+ *   This is shared library, added to iptables, for web content inspection. 
+ *   It was derived from 'string' matching support, declared as above.
+ *
+ */
+
+
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_webstr.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+	printf(
+"WEBSTR match v%s options:\n"
+"--webstr [!] host            Match a http string in a packet\n"
+"--webstr [!] url             Match a http string in a packet\n"
+"--webstr [!] content         Match a http string in a packet\n",
+XTABLES_VERSION);
+
+	fputc('\n', stdout);
+}
+
+static struct option opts[] = {
+	{ "host", 1, 0, '1' },
+	{ "url", 1, 0, '2' },
+	{ "content", 1, 0, '3' },
+	{0}
+};
+
+/* Initialize the match. */
+static void
+init(struct xt_entry_match *m, unsigned int *nfcache)
+{
+	*nfcache |= NFC_UNKNOWN;
+}
+
+static void
+parse_string(const char *s, struct xt_webstr_info *info)
+{	
+        if (strlen(s) <= BM_MAX_NLEN) strcpy(info->string, s);
+	else xtables_error(PARAMETER_PROBLEM, "WEBSTR too long `%s'", s);
+}
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const void *entry,
+      struct xt_entry_match **match)
+{
+	struct xt_webstr_info *stringinfo = (struct xt_webstr_info *)(*match)->data;
+
+	switch (c) {
+	case '1':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_string(argv[optind-1], stringinfo);
+		if (invert)
+			stringinfo->invert = 1;
+                stringinfo->len=strlen((char *)&stringinfo->string);
+                stringinfo->type = IPT_WEBSTR_HOST;
+		break;
+
+	case '2':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_string(argv[optind-1], stringinfo);
+		if (invert)
+			stringinfo->invert = 1;
+                stringinfo->len=strlen((char *)&stringinfo->string);
+                stringinfo->type = IPT_WEBSTR_URL;
+		break;
+
+	case '3':
+		xtables_check_inverse(optarg, &invert, &optind, 0);
+		parse_string(argv[optind-1], stringinfo);
+		if (invert)
+			stringinfo->invert = 1;
+                stringinfo->len=strlen((char *)&stringinfo->string);
+                stringinfo->type = IPT_WEBSTR_CONTENT;
+		break;
+
+	default:
+		return 0;
+	}
+
+	*flags = 1;
+	return 1;
+}
+
+static void
+print_string(char string[], int invert, int numeric)
+{
+
+	if (invert)
+		fputc('!', stdout);
+	printf("%s ",string);
+}
+
+/* Final check; must have specified --string. */
+static void
+final_check(unsigned int flags)
+{
+	if (!flags)
+		xtables_error(PARAMETER_PROBLEM,
+			   "WEBSTR match: You must specify `--webstr'");
+}
+
+/* Prints out the matchinfo. */
+static void
+print(const void *ip,
+      const struct xt_entry_match *match,
+      int numeric)
+{
+	struct xt_webstr_info *stringinfo = (struct xt_webstr_info *)match->data;
+
+	printf("WEBSTR match ");
+
+	
+	switch (stringinfo->type) {
+	case IPT_WEBSTR_HOST:
+		printf("host ");
+		break;
+
+	case IPT_WEBSTR_URL:
+		printf("url ");
+		break;
+
+	case IPT_WEBSTR_CONTENT:
+		printf("content ");
+		break;
+
+	default:
+		printf("ERROR ");
+		break;
+	}
+
+	print_string(((struct xt_webstr_info *)match->data)->string,
+		  ((struct xt_webstr_info *)match->data)->invert, numeric);
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void
+save(const void *ip, const struct xt_entry_match *match)
+{
+	printf("--webstr ");
+	print_string(((struct xt_webstr_info *)match->data)->string,
+		  ((struct xt_webstr_info *)match->data)->invert, 0);
+}
+
+static struct xtables_match webstr = { 
+	.next		= NULL,
+	.name		= "webstr",
+	.version	= XTABLES_VERSION,
+	.size		= XT_ALIGN(sizeof(struct xt_webstr_info)),
+	.userspacesize	= XT_ALIGN(sizeof(struct xt_webstr_info)),
+	.help		= &help,
+	//.init		= init,
+	.parse		= parse,
+	.final_check	= final_check,
+	.print		= print,
+	.save		= save,
+	.extra_opts	= opts
+};
+
+void _init(void)
+{
+	xtables_register_match(&webstr);
+}
diff --git a/ap/app/iptables/extensions/tos_values.c b/ap/app/iptables/extensions/tos_values.c
new file mode 100755
index 0000000..2676d81
--- /dev/null
+++ b/ap/app/iptables/extensions/tos_values.c
@@ -0,0 +1,92 @@
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <linux/ip.h>
+
+struct tos_value_mask {
+	uint8_t value, mask;
+};
+
+static const struct tos_symbol_info {
+	unsigned char value;
+	const char *name;
+} tos_symbol_names[] = {
+	{IPTOS_LOWDELAY,    "Minimize-Delay"},
+	{IPTOS_THROUGHPUT,  "Maximize-Throughput"},
+	{IPTOS_RELIABILITY, "Maximize-Reliability"},
+	{IPTOS_MINCOST,     "Minimize-Cost"},
+	{IPTOS_NORMALSVC,   "Normal-Service"},
+	{ .name = NULL }
+};
+
+/*
+ * tos_parse_numeric - parse sth. like "15/255"
+ *
+ * @s:		input string
+ * @info:	accompanying structure
+ * @bits:	number of bits that are allowed
+ *		(8 for IPv4 TOS field, 4 for IPv6 Priority Field)
+ */
+static bool tos_parse_numeric(const char *str, struct tos_value_mask *tvm,
+                              unsigned int bits)
+{
+	const unsigned int max = (1 << bits) - 1;
+	unsigned int value;
+	char *end;
+
+	xtables_strtoui(str, &end, &value, 0, max);
+	tvm->value = value;
+	tvm->mask  = max;
+
+	if (*end == '/') {
+		const char *p = end + 1;
+
+		if (!xtables_strtoui(p, &end, &value, 0, max))
+			xtables_error(PARAMETER_PROBLEM, "Illegal value: \"%s\"",
+			           str);
+		tvm->mask = value;
+	}
+
+	if (*end != '\0')
+		xtables_error(PARAMETER_PROBLEM, "Illegal value: \"%s\"", str);
+	return true;
+}
+
+static bool tos_parse_symbolic(const char *str, struct tos_value_mask *tvm,
+    unsigned int def_mask)
+{
+	const unsigned int max = UINT8_MAX;
+	const struct tos_symbol_info *symbol;
+	char *tmp;
+
+	if (xtables_strtoui(str, &tmp, NULL, 0, max))
+		return tos_parse_numeric(str, tvm, max);
+
+	/* Do not consider ECN bits */
+	tvm->mask = def_mask;
+	for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
+		if (strcasecmp(str, symbol->name) == 0) {
+			tvm->value = symbol->value;
+			return true;
+		}
+
+	xtables_error(PARAMETER_PROBLEM, "Symbolic name \"%s\" is unknown", str);
+	return false;
+}
+
+static bool tos_try_print_symbolic(const char *prefix,
+    u_int8_t value, u_int8_t mask)
+{
+	const struct tos_symbol_info *symbol;
+
+	if (mask != 0x3F)
+		return false;
+
+	for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
+		if (value == symbol->value) {
+			printf("%s%s ", prefix, symbol->name);
+			return true;
+		}
+
+	return false;
+}