aboutsummaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2017-03-24 06:32:41 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-03-24 06:32:41 +0000
commite20d6bf62b07e455e15b3d8982fb83dc99b9e564 (patch)
tree4400fe0ba9baae676633293796954b4061726d5d /extensions
parenta1ffd5ecfa5d72c6dc4cfaf11653d61e3e9083bc (diff)
parentff45753ae3c3108c6c93ec132f7cf62190f9c628 (diff)
downloadplatform_external_iptables-e20d6bf62b07e455e15b3d8982fb83dc99b9e564.tar.gz
platform_external_iptables-e20d6bf62b07e455e15b3d8982fb83dc99b9e564.tar.bz2
platform_external_iptables-e20d6bf62b07e455e15b3d8982fb83dc99b9e564.zip
Merge changes from topic 'iptables-1.6.1' am: c784fc47e6
am: ff45753ae3 Change-Id: Ic463667ae6ac346f8eae4b6ca18888dcd24b9d6d
Diffstat (limited to 'extensions')
-rw-r--r--extensions/Android.mk5
-rw-r--r--extensions/GNUmakefile.in85
-rw-r--r--extensions/libarpt_mangle.c204
-rw-r--r--extensions/libebt_802_3.c133
-rw-r--r--extensions/libebt_ip.c312
-rw-r--r--extensions/libebt_limit.c179
-rw-r--r--extensions/libebt_log.c197
-rw-r--r--extensions/libebt_mark.c191
-rw-r--r--extensions/libebt_mark_m.c118
-rw-r--r--extensions/libebt_nflog.c144
-rw-r--r--extensions/libip6t_DNAT.c51
-rw-r--r--extensions/libip6t_DNAT.t8
-rw-r--r--extensions/libip6t_DNPT.c8
-rw-r--r--extensions/libip6t_DNPT.t7
-rw-r--r--extensions/libip6t_HL.t10
-rw-r--r--extensions/libip6t_LOG.c64
-rw-r--r--extensions/libip6t_LOG.t12
-rw-r--r--extensions/libip6t_MASQUERADE.c21
-rw-r--r--extensions/libip6t_MASQUERADE.t8
-rw-r--r--extensions/libip6t_NETMAP.c13
-rw-r--r--extensions/libip6t_NETMAP.t4
-rw-r--r--extensions/libip6t_REDIRECT.c19
-rw-r--r--extensions/libip6t_REDIRECT.t6
-rw-r--r--extensions/libip6t_REJECT.c44
-rw-r--r--extensions/libip6t_REJECT.man7
-rw-r--r--extensions/libip6t_REJECT.t11
-rw-r--r--extensions/libip6t_SNAT.c75
-rw-r--r--extensions/libip6t_SNAT.t8
-rw-r--r--extensions/libip6t_SNPT.c8
-rw-r--r--extensions/libip6t_SNPT.t7
-rw-r--r--extensions/libip6t_ah.c45
-rw-r--r--extensions/libip6t_ah.t15
-rw-r--r--extensions/libip6t_dst.c2
-rw-r--r--extensions/libip6t_dst.t5
-rw-r--r--extensions/libip6t_eui64.t8
-rw-r--r--extensions/libip6t_frag.c40
-rw-r--r--extensions/libip6t_frag.t11
-rw-r--r--extensions/libip6t_hbh.c18
-rw-r--r--extensions/libip6t_hbh.t5
-rw-r--r--extensions/libip6t_hl.c19
-rw-r--r--extensions/libip6t_hl.t8
-rw-r--r--extensions/libip6t_icmp6.c69
-rw-r--r--extensions/libip6t_icmp6.t6
-rw-r--r--extensions/libip6t_ipv6header.c2
-rw-r--r--extensions/libip6t_ipv6header.man4
-rw-r--r--extensions/libip6t_ipv6header.t4
-rw-r--r--extensions/libip6t_mh.c21
-rw-r--r--extensions/libip6t_mh.t6
-rw-r--r--extensions/libip6t_rt.c46
-rw-r--r--extensions/libip6t_rt.t5
-rw-r--r--extensions/libipt_DNAT.c46
-rw-r--r--extensions/libipt_DNAT.t8
-rw-r--r--extensions/libipt_ECN.t5
-rw-r--r--extensions/libipt_LOG.c64
-rw-r--r--extensions/libipt_LOG.t12
-rw-r--r--extensions/libipt_MASQUERADE.c23
-rw-r--r--extensions/libipt_MASQUERADE.t8
-rw-r--r--extensions/libipt_MIRROR.c15
-rw-r--r--extensions/libipt_MIRROR.man12
-rw-r--r--extensions/libipt_NETMAP.c13
-rw-r--r--extensions/libipt_NETMAP.t4
-rw-r--r--extensions/libipt_REDIRECT.c19
-rw-r--r--extensions/libipt_REDIRECT.t6
-rw-r--r--extensions/libipt_REJECT.c49
-rw-r--r--extensions/libipt_REJECT.man8
-rw-r--r--extensions/libipt_REJECT.t9
-rw-r--r--extensions/libipt_SAME.c186
-rw-r--r--extensions/libipt_SAME.man17
-rw-r--r--extensions/libipt_SNAT.c71
-rw-r--r--extensions/libipt_SNAT.t8
-rw-r--r--extensions/libipt_TTL.t10
-rw-r--r--extensions/libipt_ULOG.t19
-rw-r--r--extensions/libipt_ah.c39
-rw-r--r--extensions/libipt_ah.t13
-rw-r--r--extensions/libipt_icmp.c36
-rw-r--r--extensions/libipt_icmp.t15
-rw-r--r--extensions/libipt_realm.c42
-rw-r--r--extensions/libipt_realm.t4
-rw-r--r--extensions/libipt_ttl.c30
-rw-r--r--extensions/libipt_ttl.t15
-rw-r--r--extensions/libipt_unclean.c15
-rw-r--r--extensions/libipt_unclean.man2
-rw-r--r--extensions/libxt_AUDIT.t6
-rw-r--r--extensions/libxt_CHECKSUM.t4
-rw-r--r--extensions/libxt_CLASSIFY.c71
-rw-r--r--extensions/libxt_CLASSIFY.t9
-rw-r--r--extensions/libxt_CONNMARK.c47
-rw-r--r--extensions/libxt_CONNMARK.t7
-rw-r--r--extensions/libxt_CONNSECMARK.t5
-rw-r--r--extensions/libxt_CT.c87
-rw-r--r--extensions/libxt_CT.man16
-rw-r--r--extensions/libxt_CT.t20
-rw-r--r--extensions/libxt_DSCP.c64
-rw-r--r--extensions/libxt_DSCP.t11
-rw-r--r--extensions/libxt_HMARK.t8
-rw-r--r--extensions/libxt_IDLETIMER.t4
-rw-r--r--extensions/libxt_LED.t4
-rw-r--r--extensions/libxt_LOG.man6
-rw-r--r--extensions/libxt_MARK.c51
-rw-r--r--extensions/libxt_MARK.t7
-rw-r--r--extensions/libxt_NFLOG.c59
-rw-r--r--extensions/libxt_NFLOG.man3
-rw-r--r--extensions/libxt_NFLOG.t24
-rw-r--r--extensions/libxt_NFQUEUE.c158
-rw-r--r--extensions/libxt_NFQUEUE.man13
-rw-r--r--extensions/libxt_NFQUEUE.t16
-rw-r--r--extensions/libxt_NOTRACK.t4
-rw-r--r--extensions/libxt_RATEEST.t2
-rw-r--r--extensions/libxt_SET.c193
-rw-r--r--extensions/libxt_SET.man21
-rw-r--r--extensions/libxt_SET.t3
-rw-r--r--extensions/libxt_SNAT.man7
-rw-r--r--extensions/libxt_SYNPROXY.c127
-rw-r--r--extensions/libxt_SYNPROXY.man64
-rw-r--r--extensions/libxt_SYNPROXY.t3
-rw-r--r--extensions/libxt_TCPMSS.t6
-rw-r--r--extensions/libxt_TCPOPTSTRIP.c15
-rw-r--r--extensions/libxt_TCPOPTSTRIP.t8
-rw-r--r--extensions/libxt_TEE.c36
-rw-r--r--extensions/libxt_TEE.t4
-rw-r--r--extensions/libxt_TOS.t16
-rw-r--r--extensions/libxt_TPROXY.t5
-rw-r--r--extensions/libxt_TRACE.c8
-rw-r--r--extensions/libxt_TRACE.t3
-rw-r--r--extensions/libxt_addrtype.t17
-rw-r--r--extensions/libxt_bpf.c220
-rw-r--r--extensions/libxt_bpf.man32
-rw-r--r--extensions/libxt_bpf.t2
-rw-r--r--extensions/libxt_cgroup.c184
-rw-r--r--extensions/libxt_cgroup.man30
-rw-r--r--extensions/libxt_cgroup.t8
-rw-r--r--extensions/libxt_cluster.man5
-rw-r--r--extensions/libxt_cluster.t10
-rw-r--r--extensions/libxt_comment.c21
-rw-r--r--extensions/libxt_comment.t12
-rw-r--r--extensions/libxt_connbytes.t21
-rw-r--r--extensions/libxt_connlabel.c59
-rw-r--r--extensions/libxt_connlabel.t18
-rw-r--r--extensions/libxt_connlimit.t16
-rw-r--r--extensions/libxt_connmark.c50
-rw-r--r--extensions/libxt_connmark.t9
-rw-r--r--extensions/libxt_conntrack.c243
-rw-r--r--extensions/libxt_conntrack.man4
-rw-r--r--extensions/libxt_conntrack.t27
-rw-r--r--extensions/libxt_cpu.c13
-rw-r--r--extensions/libxt_cpu.t6
-rw-r--r--extensions/libxt_dccp.c92
-rw-r--r--extensions/libxt_dccp.t30
-rw-r--r--extensions/libxt_devgroup.c62
-rw-r--r--extensions/libxt_dscp.c71
-rw-r--r--extensions/libxt_dscp.t10
-rw-r--r--extensions/libxt_ecn.c31
-rw-r--r--extensions/libxt_ecn.t5
-rw-r--r--extensions/libxt_esp.c31
-rw-r--r--extensions/libxt_esp.t8
-rw-r--r--extensions/libxt_hashlimit.c487
-rw-r--r--extensions/libxt_hashlimit.man2
-rw-r--r--extensions/libxt_hashlimit.t28
-rw-r--r--extensions/libxt_helper.c16
-rw-r--r--extensions/libxt_helper.t6
-rw-r--r--extensions/libxt_ipcomp.c134
-rw-r--r--extensions/libxt_ipcomp.c.man7
-rw-r--r--extensions/libxt_iprange.c113
-rw-r--r--extensions/libxt_iprange.t11
-rw-r--r--extensions/libxt_length.c16
-rw-r--r--extensions/libxt_length.t10
-rw-r--r--extensions/libxt_limit.c39
-rw-r--r--extensions/libxt_limit.t6
-rw-r--r--extensions/libxt_mac.c27
-rw-r--r--extensions/libxt_mac.t5
-rw-r--r--extensions/libxt_mangle.c396
-rw-r--r--extensions/libxt_mark.c48
-rw-r--r--extensions/libxt_mark.t7
-rw-r--r--extensions/libxt_multiport.c110
-rw-r--r--extensions/libxt_multiport.t23
-rw-r--r--extensions/libxt_nfacct.t10
-rw-r--r--extensions/libxt_osf.c2
-rw-r--r--extensions/libxt_osf.t4
-rw-r--r--extensions/libxt_owner.c51
-rw-r--r--extensions/libxt_owner.t12
-rw-r--r--extensions/libxt_physdev.man14
-rw-r--r--extensions/libxt_physdev.t14
-rw-r--r--extensions/libxt_pkttype.c37
-rw-r--r--extensions/libxt_pkttype.t6
-rw-r--r--extensions/libxt_policy.t5
-rw-r--r--extensions/libxt_quota.c14
-rw-r--r--extensions/libxt_quota.t7
-rw-r--r--extensions/libxt_rateest.t16
-rw-r--r--extensions/libxt_recent.c2
-rw-r--r--extensions/libxt_recent.man3
-rw-r--r--extensions/libxt_recent.t11
-rw-r--r--extensions/libxt_rpfilter.man2
-rw-r--r--extensions/libxt_rpfilter.t4
-rw-r--r--extensions/libxt_sctp.c39
-rw-r--r--extensions/libxt_sctp.t32
-rw-r--r--extensions/libxt_set.c200
-rw-r--r--extensions/libxt_set.h52
-rw-r--r--extensions/libxt_set.man2
-rw-r--r--extensions/libxt_set.t4
-rw-r--r--extensions/libxt_socket.man35
-rw-r--r--extensions/libxt_socket.t8
-rw-r--r--extensions/libxt_standard.t4
-rw-r--r--extensions/libxt_state.t6
-rw-r--r--extensions/libxt_statistic.c21
-rw-r--r--extensions/libxt_statistic.t8
-rw-r--r--extensions/libxt_string.man13
-rw-r--r--extensions/libxt_string.t18
-rw-r--r--extensions/libxt_tcp.c84
-rw-r--r--extensions/libxt_tcp.man1
-rw-r--r--extensions/libxt_tcp.t26
-rw-r--r--extensions/libxt_tcpmss.t5
-rw-r--r--extensions/libxt_time.t4
-rw-r--r--extensions/libxt_tos.t13
-rw-r--r--extensions/libxt_u32.t2
-rw-r--r--extensions/libxt_udp.c39
-rw-r--r--extensions/libxt_udp.t22
216 files changed, 7422 insertions, 614 deletions
diff --git a/extensions/Android.mk b/extensions/Android.mk
index 2f949016..b41cf380 100644
--- a/extensions/Android.mk
+++ b/extensions/Android.mk
@@ -4,7 +4,7 @@ LOCAL_PATH:= $(call my-dir)
MY_srcdir:=$(LOCAL_PATH)
# Exclude some modules that are problematic to compile (types/header).
-MY_excluded_modules:=TCPOPTSTRIP connlabel
+MY_excluded_modules:=TCPOPTSTRIP connlabel cgroup
MY_pfx_build_mod := $(patsubst ${MY_srcdir}/libxt_%.c,%,$(sort $(wildcard ${MY_srcdir}/libxt_*.c)))
MY_pf4_build_mod := $(patsubst ${MY_srcdir}/libipt_%.c,%,$(sort $(wildcard ${MY_srcdir}/libipt_*.c)))
@@ -19,7 +19,8 @@ MY_pf6_objs := $(patsubst %,libip6t_%.o,${MY_pf6_build_mod})
MY_warnings := \
-Wno-unused-parameter -Wno-missing-field-initializers \
-Wno-sign-compare -Wno-pointer-arith \
- -Wno-pointer-bool-conversion
+ -Wno-pointer-bool-conversion \
+ -Wno-tautological-pointer-compare
libext_suffix :=
libext_prefix := xt
diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in
index 780e7150..b7a8a836 100644
--- a/extensions/GNUmakefile.in
+++ b/extensions/GNUmakefile.in
@@ -11,6 +11,7 @@ libdir = @libdir@
libexecdir = @libexecdir@
xtlibdir = @xtlibdir@
+AR = @AR@
CC = @CC@
CCLD = ${CC}
CFLAGS = @CFLAGS@
@@ -21,7 +22,7 @@ regular_CPPFLAGS = @regular_CPPFLAGS@
kinclude_CPPFLAGS = @kinclude_CPPFLAGS@
AM_CFLAGS = ${regular_CFLAGS}
-AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_builddir} -I${top_srcdir}/include ${kinclude_CPPFLAGS} @libnetfilter_conntrack_CFLAGS@
+AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_builddir} -I${top_srcdir}/include -I${top_srcdir} ${kinclude_CPPFLAGS} ${CPPFLAGS} @libnetfilter_conntrack_CFLAGS@ @libnftnl_CFLAGS@
AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@
AM_LDFLAGS = @noundef_LDFLAGS@
@@ -39,16 +40,24 @@ endif
# Wildcard module list
#
pfx_build_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(sort $(wildcard ${srcdir}/libxt_*.c)))
+pfb_build_mod := $(patsubst ${srcdir}/libebt_%.c,%,$(sort $(wildcard ${srcdir}/libebt_*.c)))
+pfa_build_mod := $(patsubst ${srcdir}/libarpt_%.c,%,$(sort $(wildcard ${srcdir}/libarpt_*.c)))
pfx_symlinks := NOTRACK state
@ENABLE_IPV4_TRUE@ pf4_build_mod := $(patsubst ${srcdir}/libipt_%.c,%,$(sort $(wildcard ${srcdir}/libipt_*.c)))
@ENABLE_IPV6_TRUE@ pf6_build_mod := $(patsubst ${srcdir}/libip6t_%.c,%,$(sort $(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})
+pfx_build_mod := $(filter-out @blacklist_modules@ @blacklist_x_modules@,${pfx_build_mod})
+pfb_build_mod := $(filter-out @blacklist_modules@ @blacklist_b_modules@,${pfb_build_mod})
+pfa_build_mod := $(filter-out @blacklist_modules@ @blacklist_a_modules@,${pfa_build_mod})
+pf4_build_mod := $(filter-out @blacklist_modules@ @blacklist_4_modules@,${pf4_build_mod})
+pf6_build_mod := $(filter-out @blacklist_modules@ @blacklist_6_modules@,${pf6_build_mod})
pfx_objs := $(patsubst %,libxt_%.o,${pfx_build_mod})
+pfb_objs := $(patsubst %,libebt_%.o,${pfb_build_mod})
+pfa_objs := $(patsubst %,libarpt_%.o,${pfa_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} ${pfx_symlinks})
+pfb_solibs := $(patsubst %,libebt_%.so,${pfb_build_mod})
+pfa_solibs := $(patsubst %,libarpt_%.so,${pfa_build_mod})
pf4_solibs := $(patsubst %,libipt_%.so,${pf4_build_mod})
pf6_solibs := $(patsubst %,libip6t_%.so,${pf6_build_mod})
@@ -56,13 +65,15 @@ pf6_solibs := $(patsubst %,libip6t_%.so,${pf6_build_mod})
#
# Building blocks
#
-targets := libext.a libext4.a libext6.a matches.man targets.man
+targets := libext.a libext4.a libext6.a libext_ebt.a libext_arpt.a matches.man targets.man
targets_install :=
@ENABLE_STATIC_TRUE@ libext_objs := ${pfx_objs}
+@ENABLE_STATIC_TRUE@ libext_ebt_objs := ${pfb_objs}
+@ENABLE_STATIC_TRUE@ libext_arpt_objs := ${pfa_objs}
@ENABLE_STATIC_TRUE@ libext4_objs := ${pf4_objs}
@ENABLE_STATIC_TRUE@ libext6_objs := ${pf6_objs}
-@ENABLE_STATIC_FALSE@ targets += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs}
-@ENABLE_STATIC_FALSE@ targets_install += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs}
+@ENABLE_STATIC_FALSE@ targets += ${pfx_solibs} ${pfb_solibs} ${pf4_solibs} ${pf6_solibs} ${pfa_solibs}
+@ENABLE_STATIC_FALSE@ targets_install += ${pfx_solibs} ${pfb_solibs} ${pf4_solibs} ${pf6_solibs} ${pfa_solibs}
.SECONDARY:
@@ -75,7 +86,7 @@ install: ${targets_install}
if test -n "${targets_install}"; then install -pm0755 $^ "${DESTDIR}${xtlibdir}/"; fi;
clean:
- rm -f *.o *.oo *.so *.a {matches,targets}.man initext.c initext4.c initext6.c;
+ rm -f *.o *.oo *.so *.a {matches,targets}.man initext.c initext4.c initext6.c initextb.c initexta.c;
rm -f .*.d .*.dd;
distclean: clean
@@ -118,6 +129,12 @@ lib%.o: ${srcdir}/lib%.c
libext.a: initext.o ${libext_objs}
${AM_VERBOSE_AR} ${AR} crs $@ $^;
+libext_ebt.a: initextb.o ${libext_ebt_objs}
+ ${AM_VERBOSE_AR} ${AR} crs $@ $^;
+
+libext_arpt.a: initexta.o ${libext_arpt_objs}
+ ${AM_VERBOSE_AR} ${AR} crs $@ $^;
+
libext4.a: initext4.o ${libext4_objs}
${AM_VERBOSE_AR} ${AR} crs $@ $^;
@@ -125,6 +142,8 @@ libext6.a: initext6.o ${libext6_objs}
${AM_VERBOSE_AR} ${AR} crs $@ $^;
initext_func := $(addprefix xt_,${pfx_build_mod})
+initextb_func := $(addprefix ebt_,${pfb_build_mod})
+initexta_func := $(addprefix arpt_,${pfa_build_mod})
initext4_func := $(addprefix ipt_,${pf4_build_mod})
initext6_func := $(addprefix ip6t_,${pf6_build_mod})
@@ -133,6 +152,16 @@ initext6_func := $(addprefix ip6t_,${pf6_build_mod})
cmp -s $@ $@.tmp || mv $@.tmp $@; \
rm -f $@.tmp;
+.initextb.dd: FORCE
+ @echo "${initextb_func}" >$@.tmp; \
+ cmp -s $@ $@.tmp || mv $@.tmp $@; \
+ rm -f $@.tmp;
+
+.initexta.dd: FORCE
+ @echo "${initexta_func}" >$@.tmp; \
+ cmp -s $@ $@.tmp || mv $@.tmp $@; \
+ rm -f $@.tmp;
+
.initext4.dd: FORCE
@echo "${initext4_func}" >$@.tmp; \
cmp -s $@ $@.tmp || mv $@.tmp $@; \
@@ -159,6 +188,38 @@ initext.c: .initext.dd
echo "}" >>$@; \
);
+initextb.c: .initextb.dd
+ ${AM_VERBOSE_GEN}
+ @( \
+ echo "" >$@; \
+ for i in ${initextb_func}; do \
+ echo "extern void lib$${i}_init(void);" >>$@; \
+ done; \
+ echo "void init_extensionsb(void);" >>$@; \
+ echo "void init_extensionsb(void)" >>$@; \
+ echo "{" >>$@; \
+ for i in ${initextb_func}; do \
+ echo " ""lib$${i}_init();" >>$@; \
+ done; \
+ echo "}" >>$@; \
+ );
+
+initexta.c: .initexta.dd
+ ${AM_VERBOSE_GEN}
+ @( \
+ echo "" >$@; \
+ for i in ${initexta_func}; do \
+ echo "extern void lib$${i}_init(void);" >>$@; \
+ done; \
+ echo "void init_extensionsa(void);" >>$@; \
+ echo "void init_extensionsa(void)" >>$@; \
+ echo "{" >>$@; \
+ for i in ${initexta_func}; do \
+ echo " ""lib$${i}_init();" >>$@; \
+ done; \
+ echo "}" >>$@; \
+ );
+
initext4.c: .initext4.dd
${AM_VERBOSE_GEN}
@( \
@@ -219,8 +280,8 @@ man_run = \
fi; \
done >$@;
-matches.man: .initext.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man)
- $(call man_run,$(call ex_matches,${pfx_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks}))
+matches.man: .initext.dd .initextb.dd .initexta.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man)
+ $(call man_run,$(call ex_matches,${pfx_build_mod} ${pfb_build_mod} ${pfa_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks}))
-targets.man: .initext.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man)
- $(call man_run,$(call ex_targets,${pfx_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks}))
+targets.man: .initext.dd .initextb.dd .initexta.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man)
+ $(call man_run,$(call ex_targets,${pfx_build_mod} ${pfb_build_mod} ${pfa_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks}))
diff --git a/extensions/libarpt_mangle.c b/extensions/libarpt_mangle.c
new file mode 100644
index 00000000..ec9b5436
--- /dev/null
+++ b/extensions/libarpt_mangle.c
@@ -0,0 +1,204 @@
+/*
+ * Arturo Borrero Gonzalez <arturo@debian.org> adapted
+ * this code to libxtables for arptables-compat in 2015
+ */
+
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <getopt.h>
+#include <netinet/ether.h>
+#include <xtables.h>
+#include <linux/netfilter_arp/arpt_mangle.h>
+#include "iptables/nft.h"
+#include "iptables/nft-arp.h"
+
+static void arpmangle_print_help(void)
+{
+ printf(
+ "mangle target options:\n"
+ "--mangle-ip-s IP address\n"
+ "--mangle-ip-d IP address\n"
+ "--mangle-mac-s MAC address\n"
+ "--mangle-mac-d MAC address\n"
+ "--mangle-target target (DROP, CONTINUE or ACCEPT -- default is ACCEPT)\n");
+}
+
+#define MANGLE_IPS '1'
+#define MANGLE_IPT '2'
+#define MANGLE_DEVS '3'
+#define MANGLE_DEVT '4'
+#define MANGLE_TARGET '5'
+
+static struct option arpmangle_opts[] = {
+ { .name = "mangle-ip-s", .has_arg = true, .val = MANGLE_IPS },
+ { .name = "mangle-ip-d", .has_arg = true, .val = MANGLE_IPT },
+ { .name = "mangle-mac-s", .has_arg = true, .val = MANGLE_DEVS },
+ { .name = "mangle-mac-d", .has_arg = true, .val = MANGLE_DEVT },
+ { .name = "mangle-target", .has_arg = true, .val = MANGLE_TARGET },
+ XT_GETOPT_TABLEEND,
+};
+
+static void arpmangle_init(struct xt_entry_target *target)
+{
+ struct arpt_mangle *mangle = (struct arpt_mangle *)target->data;
+
+ mangle->target = NF_ACCEPT;
+}
+
+static int
+arpmangle_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_target **target)
+{
+ struct arpt_mangle *mangle = (struct arpt_mangle *)(*target)->data;
+ struct in_addr *ipaddr, mask;
+ struct ether_addr *macaddr;
+ const struct arpt_entry *e = (const struct arpt_entry *)entry;
+ unsigned int nr;
+ int ret = 1;
+
+ memset(&mask, 0, sizeof(mask));
+
+ switch (c) {
+ case MANGLE_IPS:
+ xtables_ipparse_any(optarg, &ipaddr, &mask, &nr);
+ mangle->u_s.src_ip.s_addr = ipaddr->s_addr;
+ free(ipaddr);
+ mangle->flags |= ARPT_MANGLE_SIP;
+ break;
+ case MANGLE_IPT:
+ xtables_ipparse_any(optarg, &ipaddr, &mask, &nr);
+ mangle->u_t.tgt_ip.s_addr = ipaddr->s_addr;
+ free(ipaddr);
+ mangle->flags |= ARPT_MANGLE_TIP;
+ break;
+ case MANGLE_DEVS:
+ if (e->arp.arhln_mask == 0)
+ xtables_error(PARAMETER_PROBLEM,
+ "no --h-length defined");
+ if (e->arp.invflags & ARPT_INV_ARPHLN)
+ xtables_error(PARAMETER_PROBLEM,
+ "! --h-length not allowed for "
+ "--mangle-mac-s");
+ if (e->arp.arhln != 6)
+ xtables_error(PARAMETER_PROBLEM,
+ "only --h-length 6 supported");
+ macaddr = ether_aton(optarg);
+ if (macaddr == NULL)
+ xtables_error(PARAMETER_PROBLEM,
+ "invalid source MAC");
+ memcpy(mangle->src_devaddr, macaddr, e->arp.arhln);
+ mangle->flags |= ARPT_MANGLE_SDEV;
+ break;
+ case MANGLE_DEVT:
+ if (e->arp.arhln_mask == 0)
+ xtables_error(PARAMETER_PROBLEM,
+ "no --h-length defined");
+ if (e->arp.invflags & ARPT_INV_ARPHLN)
+ xtables_error(PARAMETER_PROBLEM,
+ "! hln not allowed for --mangle-mac-d");
+ if (e->arp.arhln != 6)
+ xtables_error(PARAMETER_PROBLEM,
+ "only --h-length 6 supported");
+ macaddr = ether_aton(optarg);
+ if (macaddr == NULL)
+ xtables_error(PARAMETER_PROBLEM, "invalid target MAC");
+ memcpy(mangle->tgt_devaddr, macaddr, e->arp.arhln);
+ mangle->flags |= ARPT_MANGLE_TDEV;
+ break;
+ case MANGLE_TARGET:
+ if (!strcmp(optarg, "DROP"))
+ mangle->target = NF_DROP;
+ else if (!strcmp(optarg, "ACCEPT"))
+ mangle->target = NF_ACCEPT;
+ else if (!strcmp(optarg, "CONTINUE"))
+ mangle->target = XT_CONTINUE;
+ else
+ xtables_error(PARAMETER_PROBLEM,
+ "bad target for --mangle-target");
+ break;
+ default:
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static void arpmangle_final_check(unsigned int flags)
+{
+}
+
+static void print_mac(const unsigned char *mac, int l)
+{
+ int j;
+
+ for (j = 0; j < l; j++)
+ printf("%02x%s", mac[j],
+ (j==l-1) ? "" : ":");
+}
+
+static void
+arpmangle_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ struct arpt_mangle *m = (struct arpt_mangle *)(target->data);
+ char buf[100];
+
+ if (m->flags & ARPT_MANGLE_SIP) {
+ if (numeric)
+ sprintf(buf, "%s",
+ xtables_ipaddr_to_numeric(&(m->u_s.src_ip)));
+ else
+ sprintf(buf, "%s",
+ xtables_ipaddr_to_anyname(&(m->u_s.src_ip)));
+ printf("--mangle-ip-s %s ", buf);
+ }
+ if (m->flags & ARPT_MANGLE_SDEV) {
+ printf("--mangle-mac-s ");
+ print_mac((unsigned char *)m->src_devaddr, 6);
+ printf(" ");
+ }
+ if (m->flags & ARPT_MANGLE_TIP) {
+ if (numeric)
+ sprintf(buf, "%s",
+ xtables_ipaddr_to_numeric(&(m->u_t.tgt_ip)));
+ else
+ sprintf(buf, "%s",
+ xtables_ipaddr_to_anyname(&(m->u_t.tgt_ip)));
+ printf("--mangle-ip-d %s ", buf);
+ }
+ if (m->flags & ARPT_MANGLE_TDEV) {
+ printf("--mangle-mac-d ");
+ print_mac((unsigned char *)m->tgt_devaddr, 6);
+ printf(" ");
+ }
+ if (m->target != NF_ACCEPT) {
+ printf("--mangle-target ");
+ if (m->target == NF_DROP)
+ printf("DROP ");
+ else
+ printf("CONTINUE ");
+ }
+}
+
+static struct xtables_target arpmangle_target = {
+ .name = "mangle",
+ .revision = 0,
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_ARP,
+ .size = XT_ALIGN(sizeof(struct arpt_mangle)),
+ .userspacesize = XT_ALIGN(sizeof(struct arpt_mangle)),
+ .help = arpmangle_print_help,
+ .init = arpmangle_init,
+ .parse = arpmangle_parse,
+ .final_check = arpmangle_final_check,
+ .print = arpmangle_print,
+ .extra_opts = arpmangle_opts,
+};
+
+void _init(void)
+{
+ xtables_register_target(&arpmangle_target);
+}
diff --git a/extensions/libebt_802_3.c b/extensions/libebt_802_3.c
new file mode 100644
index 00000000..f05d02ea
--- /dev/null
+++ b/extensions/libebt_802_3.c
@@ -0,0 +1,133 @@
+/* 802_3
+ *
+ * Author:
+ * Chris Vitale <csv@bluetail.com>
+ *
+ * May 2003
+ *
+ * Adapted by Arturo Borrero Gonzalez <arturo@debian.org>
+ * to use libxtables for ebtables-compat
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter_bridge/ebt_802_3.h>
+
+#define _802_3_SAP '1'
+#define _802_3_TYPE '2'
+
+static const struct option br802_3_opts[] = {
+ { .name = "802_3-sap", .has_arg = true, .val = _802_3_SAP },
+ { .name = "802_3-type", .has_arg = true, .val = _802_3_TYPE },
+ XT_GETOPT_TABLEEND,
+};
+
+static void br802_3_print_help(void)
+{
+ printf(
+"802_3 options:\n"
+"--802_3-sap [!] protocol : 802.3 DSAP/SSAP- 1 byte value (hex)\n"
+" DSAP and SSAP are always the same. One SAP applies to both fields\n"
+"--802_3-type [!] protocol : 802.3 SNAP Type- 2 byte value (hex)\n"
+" Type implies SAP value 0xaa\n");
+}
+
+static void br802_3_init(struct xt_entry_match *match)
+{
+ struct ebt_802_3_info *info = (struct ebt_802_3_info *)match->data;
+
+ info->invflags = 0;
+ info->bitmask = 0;
+}
+
+static int
+br802_3_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_match **match)
+{
+ struct ebt_802_3_info *info = (struct ebt_802_3_info *) (*match)->data;
+ unsigned int i;
+ char *end;
+
+ switch (c) {
+ case _802_3_SAP:
+ if (invert)
+ info->invflags |= EBT_802_3_SAP;
+ i = strtoul(optarg, &end, 16);
+ if (i > 255 || *end != '\0')
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified "
+ "sap hex value, %x",i);
+ info->sap = i; /* one byte, so no byte order worries */
+ info->bitmask |= EBT_802_3_SAP;
+ break;
+ case _802_3_TYPE:
+ if (invert)
+ info->invflags |= EBT_802_3_TYPE;
+ i = strtoul(optarg, &end, 16);
+ if (i > 65535 || *end != '\0') {
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with the specified "
+ "type hex value, %x",i);
+ }
+ info->type = htons(i);
+ info->bitmask |= EBT_802_3_TYPE;
+ break;
+ default:
+ return 0;
+ }
+
+ *flags |= info->bitmask;
+ return 1;
+}
+
+static void
+br802_3_final_check(unsigned int flags)
+{
+ if (!flags)
+ xtables_error(PARAMETER_PROBLEM,
+ "You must specify proper arguments");
+}
+
+static void br802_3_print(const void *ip, const struct xt_entry_match *match,
+ int numeric)
+{
+ struct ebt_802_3_info *info = (struct ebt_802_3_info *)match->data;
+
+ if (info->bitmask & EBT_802_3_SAP) {
+ printf("--802_3-sap ");
+ if (info->invflags & EBT_802_3_SAP)
+ printf("! ");
+ printf("0x%.2x ", info->sap);
+ }
+ if (info->bitmask & EBT_802_3_TYPE) {
+ printf("--802_3-type ");
+ if (info->invflags & EBT_802_3_TYPE)
+ printf("! ");
+ printf("0x%.4x ", ntohs(info->type));
+ }
+}
+
+static struct xtables_match br802_3_match =
+{
+ .name = "802_3",
+ .revision = 0,
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_BRIDGE,
+ .size = XT_ALIGN(sizeof(struct ebt_802_3_info)),
+ .userspacesize = XT_ALIGN(sizeof(struct ebt_802_3_info)),
+ .init = br802_3_init,
+ .help = br802_3_print_help,
+ .parse = br802_3_parse,
+ .final_check = br802_3_final_check,
+ .print = br802_3_print,
+ .extra_opts = br802_3_opts,
+};
+
+void _init(void)
+{
+ xtables_register_match(&br802_3_match);
+}
diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c
new file mode 100644
index 00000000..4ca63e93
--- /dev/null
+++ b/extensions/libebt_ip.c
@@ -0,0 +1,312 @@
+/* ebt_ip
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * Changes:
+ * added ip-sport and ip-dport; parsing of port arguments is
+ * based on code from iptables-1.2.7a
+ * Innominate Security Technologies AG <mhopf@innominate.com>
+ * September, 2002
+ *
+ * Adapted by Arturo Borrero Gonzalez <arturo@debian.org>
+ * to use libxtables for ebtables-compat in 2015.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <xtables.h>
+#include <linux/netfilter_bridge/ebt_ip.h>
+
+#define IP_SOURCE '1'
+#define IP_DEST '2'
+#define IP_EBT_TOS '3' /* include/bits/in.h seems to already define IP_TOS */
+#define IP_PROTO '4'
+#define IP_SPORT '5'
+#define IP_DPORT '6'
+
+static const struct option brip_opts[] = {
+ { .name = "ip-source", .has_arg = true, .val = IP_SOURCE },
+ { .name = "ip-src", .has_arg = true, .val = IP_SOURCE },
+ { .name = "ip-destination", .has_arg = true, .val = IP_DEST },
+ { .name = "ip-dst", .has_arg = true, .val = IP_DEST },
+ { .name = "ip-tos", .has_arg = true, .val = IP_EBT_TOS },
+ { .name = "ip-protocol", .has_arg = true, .val = IP_PROTO },
+ { .name = "ip-proto", .has_arg = true, .val = IP_PROTO },
+ { .name = "ip-source-port", .has_arg = true, .val = IP_SPORT },
+ { .name = "ip-sport", .has_arg = true, .val = IP_SPORT },
+ { .name = "ip-destination-port",.has_arg = true, .val = IP_DPORT },
+ { .name = "ip-dport", .has_arg = true, .val = IP_DPORT },
+ XT_GETOPT_TABLEEND,
+};
+
+static void brip_print_help(void)
+{
+ printf(
+"ip options:\n"
+"--ip-src [!] address[/mask]: ip source specification\n"
+"--ip-dst [!] address[/mask]: ip destination specification\n"
+"--ip-tos [!] tos : ip tos specification\n"
+"--ip-proto [!] protocol : ip protocol specification\n"
+"--ip-sport [!] port[:port] : tcp/udp source port or port range\n"
+"--ip-dport [!] port[:port] : tcp/udp destination port or port range\n");
+}
+
+static void brip_init(struct xt_entry_match *match)
+{
+ struct ebt_ip_info *info = (struct ebt_ip_info *)match->data;
+
+ info->invflags = 0;
+ info->bitmask = 0;
+}
+
+static void
+parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
+{
+ char *buffer;
+ char *cp;
+
+ buffer = strdup(portstring);
+ if ((cp = strchr(buffer, ':')) == NULL)
+ ports[0] = ports[1] = xtables_parse_port(buffer, NULL);
+ else {
+ *cp = '\0';
+ cp++;
+
+ ports[0] = buffer[0] ? xtables_parse_port(buffer, NULL) : 0;
+ ports[1] = cp[0] ? xtables_parse_port(cp, NULL) : 0xFFFF;
+
+ if (ports[0] > ports[1])
+ xtables_error(PARAMETER_PROBLEM,
+ "invalid portrange (min > max)");
+ }
+ free(buffer);
+}
+
+/* original code from ebtables: useful_functions.c */
+static int undot_ip(char *ip, unsigned char *ip2)
+{
+ char *p, *q, *end;
+ long int onebyte;
+ int i;
+ char buf[20];
+
+ strncpy(buf, ip, sizeof(buf) - 1);
+
+ p = buf;
+ for (i = 0; i < 3; i++) {
+ if ((q = strchr(p, '.')) == NULL)
+ return -1;
+ *q = '\0';
+ onebyte = strtol(p, &end, 10);
+ if (*end != '\0' || onebyte > 255 || onebyte < 0)
+ return -1;
+ ip2[i] = (unsigned char)onebyte;
+ p = q + 1;
+ }
+
+ onebyte = strtol(p, &end, 10);
+ if (*end != '\0' || onebyte > 255 || onebyte < 0)
+ return -1;
+ ip2[3] = (unsigned char)onebyte;
+
+ return 0;
+}
+
+static int ip_mask(char *mask, unsigned char *mask2)
+{
+ char *end;
+ long int bits;
+ uint32_t mask22;
+
+ if (undot_ip(mask, mask2)) {
+ /* not the /a.b.c.e format, maybe the /x format */
+ bits = strtol(mask, &end, 10);
+ if (*end != '\0' || bits > 32 || bits < 0)
+ return -1;
+ if (bits != 0) {
+ mask22 = htonl(0xFFFFFFFF << (32 - bits));
+ memcpy(mask2, &mask22, 4);
+ } else {
+ mask22 = 0xFFFFFFFF;
+ memcpy(mask2, &mask22, 4);
+ }
+ }
+ return 0;
+}
+
+static void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk)
+{
+ char *p;
+
+ /* first the mask */
+ if ((p = strrchr(address, '/')) != NULL) {
+ *p = '\0';
+ if (ip_mask(p + 1, (unsigned char *)msk)) {
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with the IP mask '%s'", p + 1);
+ return;
+ }
+ } else
+ *msk = 0xFFFFFFFF;
+
+ if (undot_ip(address, (unsigned char *)addr)) {
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with the IP address '%s'", address);
+ return;
+ }
+ *addr = *addr & *msk;
+}
+
+static int
+brip_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_match **match)
+{
+ struct ebt_ip_info *info = (struct ebt_ip_info *)(*match)->data;
+
+ switch (c) {
+ case IP_SOURCE:
+ if (invert)
+ info->invflags |= EBT_IP_SOURCE;
+ ebt_parse_ip_address(optarg, &info->saddr, &info->smsk);
+ info->bitmask |= EBT_IP_SOURCE;
+ break;
+ case IP_DEST:
+ if (invert)
+ info->invflags |= EBT_IP_DEST;
+ ebt_parse_ip_address(optarg, &info->daddr, &info->dmsk);
+ info->bitmask |= EBT_IP_DEST;
+ break;
+ case IP_SPORT:
+ if (invert)
+ info->invflags |= EBT_IP_SPORT;
+ parse_port_range(NULL, optarg, info->sport);
+ info->bitmask |= EBT_IP_SPORT;
+ break;
+ case IP_DPORT:
+ if (invert)
+ info->invflags |= EBT_IP_DPORT;
+ parse_port_range(NULL, optarg, info->dport);
+ info->bitmask |= EBT_IP_DPORT;
+ break;
+ case IP_EBT_TOS:
+ if (invert)
+ info->invflags |= EBT_IP_TOS;
+ if (!xtables_strtoul(optarg, NULL, (uintmax_t *)&info->tos,
+ 0, 255))
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with specified IP tos");
+ info->bitmask |= EBT_IP_TOS;
+ break;
+ case IP_PROTO:
+ if (invert)
+ info->invflags |= EBT_IP_PROTO;
+ info->protocol = xtables_parse_protocol(optarg);
+ if (info->protocol == -1)
+ xtables_error(PARAMETER_PROBLEM,
+ "Unknown specified IP protocol - %s",
+ optarg);
+ info->bitmask |= EBT_IP_PROTO;
+ break;
+ default:
+ return 0;
+ }
+
+ *flags |= info->bitmask;
+ return 1;
+}
+
+static void brip_final_check(unsigned int flags)
+{
+ if (!flags)
+ xtables_error(PARAMETER_PROBLEM,
+ "You must specify proper arguments");
+}
+
+static void print_port_range(uint16_t *ports)
+{
+ if (ports[0] == ports[1])
+ printf("%d ", ports[0]);
+ else
+ printf("%d:%d ", ports[0], ports[1]);
+}
+
+static void brip_print(const void *ip, const struct xt_entry_match *match,
+ int numeric)
+{
+ struct ebt_ip_info *info = (struct ebt_ip_info *)match->data;
+ struct in_addr *addrp, *maskp;
+
+ if (info->bitmask & EBT_IP_SOURCE) {
+ printf("--ip-src ");
+ if (info->invflags & EBT_IP_SOURCE)
+ printf("! ");
+ addrp = (struct in_addr *)&info->saddr;
+ maskp = (struct in_addr *)&info->smsk;
+ printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
+ xtables_ipmask_to_numeric(maskp));
+ }
+ if (info->bitmask & EBT_IP_DEST) {
+ printf("--ip-dst ");
+ if (info->invflags & EBT_IP_DEST)
+ printf("! ");
+ addrp = (struct in_addr *)&info->daddr;
+ maskp = (struct in_addr *)&info->dmsk;
+ printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
+ xtables_ipmask_to_numeric(maskp));
+ }
+ if (info->bitmask & EBT_IP_TOS) {
+ printf("--ip-tos ");
+ if (info->invflags & EBT_IP_TOS)
+ printf("! ");
+ printf("0x%02X ", info->tos);
+ }
+ if (info->bitmask & EBT_IP_PROTO) {
+ struct protoent *pe;
+
+ printf("--ip-proto ");
+ if (info->invflags & EBT_IP_PROTO)
+ printf("! ");
+ pe = getprotobynumber(info->protocol);
+ if (pe == NULL) {
+ printf("%d ", info->protocol);
+ } else {
+ printf("%s ", pe->p_name);
+ }
+ }
+ if (info->bitmask & EBT_IP_SPORT) {
+ printf("--ip-sport ");
+ if (info->invflags & EBT_IP_SPORT)
+ printf("! ");
+ print_port_range(info->sport);
+ }
+ if (info->bitmask & EBT_IP_DPORT) {
+ printf("--ip-dport ");
+ if (info->invflags & EBT_IP_DPORT)
+ printf("! ");
+ print_port_range(info->dport);
+ }
+}
+
+static struct xtables_match brip_match = {
+ .name = "ip",
+ .revision = 0,
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_BRIDGE,
+ .size = XT_ALIGN(sizeof(struct ebt_ip_info)),
+ .userspacesize = XT_ALIGN(sizeof(struct ebt_ip_info)),
+ .init = brip_init,
+ .help = brip_print_help,
+ .parse = brip_parse,
+ .final_check = brip_final_check,
+ .print = brip_print,
+ .extra_opts = brip_opts,
+};
+
+void _init(void)
+{
+ xtables_register_match(&brip_match);
+}
diff --git a/extensions/libebt_limit.c b/extensions/libebt_limit.c
new file mode 100644
index 00000000..6b9bb16f
--- /dev/null
+++ b/extensions/libebt_limit.c
@@ -0,0 +1,179 @@
+/* ebt_limit
+ *
+ * Authors:
+ * Tom Marshall <tommy@home.tig-grr.com>
+ *
+ * Mostly copied from iptables' limit match.
+ *
+ * September, 2003
+ *
+ * Translated to use libxtables for ebtables-compat in 2015 by
+ * Arturo Borrero Gonzalez <arturo@debian.org>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <xtables.h>
+#include <linux/netfilter_bridge/ebt_limit.h>
+#include "iptables/nft.h"
+#include "iptables/nft-bridge.h"
+
+#define EBT_LIMIT_AVG "3/hour"
+#define EBT_LIMIT_BURST 5
+
+#define FLAG_LIMIT 0x01
+#define FLAG_LIMIT_BURST 0x02
+#define ARG_LIMIT '1'
+#define ARG_LIMIT_BURST '2'
+
+static struct option brlimit_opts[] =
+{
+ { .name = "limit", .has_arg = true, .val = ARG_LIMIT },
+ { .name = "limit-burst",.has_arg = true, .val = ARG_LIMIT_BURST },
+ XT_GETOPT_TABLEEND,
+};
+
+static void brlimit_print_help(void)
+{
+ printf(
+"limit options:\n"
+"--limit avg : max average match rate: default "EBT_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, -1 < number < 10001,\n"
+" default %u\n", EBT_LIMIT_BURST);
+}
+
+static int parse_rate(const char *rate, uint32_t *val)
+{
+ const char *delim;
+ uint32_t r;
+ uint32_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 > EBT_LIMIT_SCALE)
+ return 0;
+
+ *val = EBT_LIMIT_SCALE * mult / r;
+ return 1;
+}
+
+static void brlimit_init(struct xt_entry_match *match)
+{
+ struct ebt_limit_info *r = (struct ebt_limit_info *)match->data;
+
+ parse_rate(EBT_LIMIT_AVG, &r->avg);
+ r->burst = EBT_LIMIT_BURST;
+}
+
+static int brlimit_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_match **match)
+{
+ struct ebt_limit_info *r = (struct ebt_limit_info *)(*match)->data;
+ uintmax_t num;
+
+ switch (c) {
+ case ARG_LIMIT:
+ EBT_CHECK_OPTION(flags, FLAG_LIMIT);
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --limit");
+ if (!parse_rate(optarg, &r->avg))
+ xtables_error(PARAMETER_PROBLEM,
+ "bad rate `%s'", optarg);
+ break;
+ case ARG_LIMIT_BURST:
+ EBT_CHECK_OPTION(flags, FLAG_LIMIT_BURST);
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --limit-burst");
+ if (!xtables_strtoul(optarg, NULL, &num, 0, 10000))
+ xtables_error(PARAMETER_PROBLEM,
+ "bad --limit-burst `%s'", optarg);
+ r->burst = num;
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+struct rates
+{
+ const char *name;
+ uint32_t mult;
+};
+
+static struct rates g_rates[] =
+{
+ { "day", EBT_LIMIT_SCALE*24*60*60 },
+ { "hour", EBT_LIMIT_SCALE*60*60 },
+ { "min", EBT_LIMIT_SCALE*60 },
+ { "sec", EBT_LIMIT_SCALE }
+};
+
+static void print_rate(uint32_t period)
+{
+ unsigned int i;
+
+ for (i = 1; i < sizeof(g_rates)/sizeof(struct rates); i++)
+ if (period > g_rates[i].mult ||
+ g_rates[i].mult/period < g_rates[i].mult%period)
+ break;
+
+ printf("%u/%s ", g_rates[i-1].mult / period, g_rates[i-1].name);
+}
+
+static void brlimit_print(const void *ip, const struct xt_entry_match *match,
+ int numeric)
+{
+ struct ebt_limit_info *r = (struct ebt_limit_info *)match->data;
+
+ printf("--limit ");
+ print_rate(r->avg);
+ printf("--limit-burst %u ", r->burst);
+}
+
+static struct xtables_match brlimit_match = {
+ .name = "limit",
+ .revision = 0,
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_BRIDGE,
+ .size = XT_ALIGN(sizeof(struct ebt_limit_info)),
+ .userspacesize = offsetof(struct ebt_limit_info, prev),
+ .init = brlimit_init,
+ .help = brlimit_print_help,
+ .parse = brlimit_parse,
+ .print = brlimit_print,
+ .extra_opts = brlimit_opts,
+};
+
+void _init(void)
+{
+ xtables_register_match(&brlimit_match);
+}
diff --git a/extensions/libebt_log.c b/extensions/libebt_log.c
new file mode 100644
index 00000000..0799185d
--- /dev/null
+++ b/extensions/libebt_log.c
@@ -0,0 +1,197 @@
+/*
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * 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.
+ *
+ * Giuseppe Longo <giuseppelng@gmail.com> adapted the original code to the
+ * xtables-compat environment in 2015.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter_bridge/ebt_log.h>
+
+#define LOG_DEFAULT_LEVEL LOG_INFO
+
+#define LOG_PREFIX '1'
+#define LOG_LEVEL '2'
+#define LOG_ARP '3'
+#define LOG_IP '4'
+#define LOG_LOG '5'
+#define LOG_IP6 '6'
+
+typedef struct _code {
+ char *c_name;
+ int c_val;
+} CODE;
+
+static CODE eight_priority[] = {
+ { "emerg", LOG_EMERG },
+ { "alert", LOG_ALERT },
+ { "crit", LOG_CRIT },
+ { "error", LOG_ERR },
+ { "warning", LOG_WARNING },
+ { "notice", LOG_NOTICE },
+ { "info", LOG_INFO },
+ { "debug", LOG_DEBUG }
+};
+
+static int name_to_loglevel(const char *arg)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ if (!strcmp(arg, eight_priority[i].c_name))
+ return eight_priority[i].c_val;
+
+ /* return bad loglevel */
+ return 9;
+}
+
+static const struct option brlog_opts[] = {
+ { .name = "log-prefix", .has_arg = true, .val = LOG_PREFIX },
+ { .name = "log-level", .has_arg = true, .val = LOG_LEVEL },
+ { .name = "log-arp", .has_arg = false, .val = LOG_ARP },
+ { .name = "log-ip", .has_arg = false, .val = LOG_IP },
+ { .name = "log", .has_arg = false, .val = LOG_LOG },
+ { .name = "log-ip6", .has_arg = false, .val = LOG_IP6 },
+ XT_GETOPT_TABLEEND,
+};
+
+static void brlog_help(void)
+{
+ int i;
+
+ printf(
+"log options:\n"
+"--log : use this if you're not specifying anything\n"
+"--log-level level : level = [1-8] or a string\n"
+"--log-prefix prefix : max. %d chars.\n"
+"--log-ip : put ip info. in the log for ip packets\n"
+"--log-arp : put (r)arp info. in the log for (r)arp packets\n"
+"--log-ip6 : put ip6 info. in the log for ip6 packets\n"
+ , EBT_LOG_PREFIX_SIZE - 1);
+ for (i = 0; i < 8; i++)
+ printf("%d = %s\n", eight_priority[i].c_val,
+ eight_priority[i].c_name);
+}
+
+static void brlog_init(struct xt_entry_target *t)
+{
+ struct ebt_log_info *loginfo = (struct ebt_log_info *)t->data;
+
+ loginfo->bitmask = 0;
+ loginfo->prefix[0] = '\0';
+ loginfo->loglevel = LOG_NOTICE;
+}
+
+static int brlog_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_target **target)
+{
+ struct ebt_log_info *loginfo = (struct ebt_log_info *)(*target)->data;
+ long int i;
+ char *end;
+
+ switch (c) {
+ case LOG_PREFIX:
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "Unexpected `!` after --log-prefix");
+ if (strlen(optarg) > sizeof(loginfo->prefix) - 1)
+ xtables_error(PARAMETER_PROBLEM,
+ "Prefix too long");
+ if (strchr(optarg, '\"'))
+ xtables_error(PARAMETER_PROBLEM,
+ "Use of \\\" is not allowed"
+ " in the prefix");
+ strcpy((char *)loginfo->prefix, (char *)optarg);
+ break;
+ case LOG_LEVEL:
+ i = strtol(optarg, &end, 16);
+ if (*end != '\0' || i < 0 || i > 7)
+ loginfo->loglevel = name_to_loglevel(optarg);
+ else
+ loginfo->loglevel = i;
+
+ if (loginfo->loglevel == 9)
+ xtables_error(PARAMETER_PROBLEM,
+ "Problem with the log-level");
+ break;
+ case LOG_IP:
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --log-ip");
+ loginfo->bitmask |= EBT_LOG_IP;
+ break;
+ case LOG_ARP:
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --log-arp");
+ loginfo->bitmask |= EBT_LOG_ARP;
+ case LOG_LOG:
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --log");
+ break;
+ case LOG_IP6:
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --log-ip6");
+ loginfo->bitmask |= EBT_LOG_IP6;
+ break;
+ default:
+ return 0;
+ }
+
+ *flags |= loginfo->bitmask;
+ return 1;
+}
+
+static void brlog_final_check(unsigned int flags)
+{
+}
+
+static void brlog_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ struct ebt_log_info *loginfo = (struct ebt_log_info *)target->data;
+
+ printf("--log-level %s --log-prefix \"%s\"",
+ eight_priority[loginfo->loglevel].c_name,
+ loginfo->prefix);
+
+ if (loginfo->bitmask & EBT_LOG_IP)
+ printf(" --log-ip");
+ if (loginfo->bitmask & EBT_LOG_ARP)
+ printf(" --log-arp");
+ if (loginfo->bitmask & EBT_LOG_IP6)
+ printf(" --log-ip6");
+ printf(" ");
+}
+
+static struct xtables_target brlog_target = {
+ .name = "log",
+ .revision = 0,
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_BRIDGE,
+ .size = XT_ALIGN(sizeof(struct ebt_log_info)),
+ .userspacesize = XT_ALIGN(sizeof(struct ebt_log_info)),
+ .init = brlog_init,
+ .help = brlog_help,
+ .parse = brlog_parse,
+ .final_check = brlog_final_check,
+ .print = brlog_print,
+ .extra_opts = brlog_opts,
+};
+
+void _init(void)
+{
+ xtables_register_target(&brlog_target);
+}
diff --git a/extensions/libebt_mark.c b/extensions/libebt_mark.c
new file mode 100644
index 00000000..a1a208c3
--- /dev/null
+++ b/extensions/libebt_mark.c
@@ -0,0 +1,191 @@
+/* ebt_mark
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * July, 2002, September 2006
+ *
+ * Adapted by Arturo Borrero Gonzalez <arturo@debian.org>
+ * to use libxtables for ebtables-compat in 2015.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter_bridge/ebt_mark_t.h>
+#include "iptables/nft.h"
+#include "iptables/nft-bridge.h"
+
+static int mark_supplied;
+
+#define MARK_TARGET '1'
+#define MARK_SETMARK '2'
+#define MARK_ORMARK '3'
+#define MARK_ANDMARK '4'
+#define MARK_XORMARK '5'
+static struct option brmark_opts[] = {
+ { .name = "mark-target",.has_arg = true, .val = MARK_TARGET },
+ /* an oldtime messup, we should have always used the scheme
+ * <extension-name>-<option> */
+ { .name = "set-mark", .has_arg = true, .val = MARK_SETMARK },
+ { .name = "mark-set", .has_arg = true, .val = MARK_SETMARK },
+ { .name = "mark-or", .has_arg = true, .val = MARK_ORMARK },
+ { .name = "mark-and", .has_arg = true, .val = MARK_ANDMARK },
+ { .name = "mark-xor", .has_arg = true, .val = MARK_XORMARK },
+ XT_GETOPT_TABLEEND,
+};
+
+static void brmark_print_help(void)
+{
+ printf(
+ "mark target options:\n"
+ " --mark-set value : Set nfmark value\n"
+ " --mark-or value : Or nfmark with value (nfmark |= value)\n"
+ " --mark-and value : And nfmark with value (nfmark &= value)\n"
+ " --mark-xor value : Xor nfmark with value (nfmark ^= value)\n"
+ " --mark-target target : ACCEPT, DROP, RETURN or CONTINUE\n");
+}
+
+static void brmark_init(struct xt_entry_target *target)
+{
+ struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)target->data;
+
+ info->target = EBT_ACCEPT;
+ info->mark = 0;
+ mark_supplied = 0;
+}
+
+#define OPT_MARK_TARGET 0x01
+#define OPT_MARK_SETMARK 0x02
+#define OPT_MARK_ORMARK 0x04
+#define OPT_MARK_ANDMARK 0x08
+#define OPT_MARK_XORMARK 0x10
+
+static int
+brmark_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_target **target)
+{
+ struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)
+ (*target)->data;
+ char *end;
+ uint32_t mask;
+
+ switch (c) {
+ case MARK_TARGET:
+ { unsigned int tmp;
+ EBT_CHECK_OPTION(flags, OPT_MARK_TARGET);
+ if (ebt_fill_target(optarg, &tmp))
+ xtables_error(PARAMETER_PROBLEM,
+ "Illegal --mark-target target");
+ /* the 4 lsb are left to designate the target */
+ info->target = (info->target & ~EBT_VERDICT_BITS) |
+ (tmp & EBT_VERDICT_BITS);
+ }
+ return 1;
+ case MARK_SETMARK:
+ EBT_CHECK_OPTION(flags, OPT_MARK_SETMARK);
+ mask = (OPT_MARK_ORMARK|OPT_MARK_ANDMARK|OPT_MARK_XORMARK);
+ if (*flags & mask)
+ xtables_error(PARAMETER_PROBLEM,
+ "--mark-set cannot be used together with"
+ " specific --mark option");
+ info->target = (info->target & EBT_VERDICT_BITS) |
+ MARK_SET_VALUE;
+ break;
+ case MARK_ORMARK:
+ EBT_CHECK_OPTION(flags, OPT_MARK_ORMARK);
+ mask = (OPT_MARK_SETMARK|OPT_MARK_ANDMARK|OPT_MARK_XORMARK);
+ if (*flags & mask)
+ xtables_error(PARAMETER_PROBLEM,
+ "--mark-or cannot be used together with"
+ " specific --mark option");
+ info->target = (info->target & EBT_VERDICT_BITS) |
+ MARK_OR_VALUE;
+ break;
+ case MARK_ANDMARK:
+ EBT_CHECK_OPTION(flags, OPT_MARK_ANDMARK);
+ mask = (OPT_MARK_SETMARK|OPT_MARK_ORMARK|OPT_MARK_XORMARK);
+ if (*flags & mask)
+ xtables_error(PARAMETER_PROBLEM,
+ "--mark-and cannot be used together with"
+ " specific --mark option");
+ info->target = (info->target & EBT_VERDICT_BITS) |
+ MARK_AND_VALUE;
+ break;
+ case MARK_XORMARK:
+ EBT_CHECK_OPTION(flags, OPT_MARK_XORMARK);
+ mask = (OPT_MARK_SETMARK|OPT_MARK_ANDMARK|OPT_MARK_ORMARK);
+ if (*flags & mask)
+ xtables_error(PARAMETER_PROBLEM,
+ "--mark-xor cannot be used together with"
+ " specific --mark option");
+ info->target = (info->target & EBT_VERDICT_BITS) |
+ MARK_XOR_VALUE;
+ break;
+ default:
+ return 0;
+ }
+ /* mutual code */
+ info->mark = strtoul(optarg, &end, 0);
+ if (*end != '\0' || end == optarg)
+ xtables_error(PARAMETER_PROBLEM, "Bad MARK value '%s'",
+ optarg);
+
+ mark_supplied = 1;
+ return 1;
+}
+
+static void brmark_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)target->data;
+ int tmp;
+
+ tmp = info->target & ~EBT_VERDICT_BITS;
+ if (tmp == MARK_SET_VALUE)
+ printf("--mark-set");
+ else if (tmp == MARK_OR_VALUE)
+ printf("--mark-or");
+ else if (tmp == MARK_XOR_VALUE)
+ printf("--mark-xor");
+ else if (tmp == MARK_AND_VALUE)
+ printf("--mark-and");
+ else
+ xtables_error(PARAMETER_PROBLEM, "Unknown mark action");
+
+ printf(" 0x%lx", info->mark);
+ tmp = info->target | ~EBT_VERDICT_BITS;
+ printf(" --mark-target %s", ebt_target_name(tmp));
+}
+
+static void brmark_final_check(unsigned int flags)
+{
+ if (mark_supplied == 0)
+ xtables_error(PARAMETER_PROBLEM, "No mark value supplied");
+
+ if (!flags)
+ xtables_error(PARAMETER_PROBLEM,
+ "You must specify some option");
+}
+
+static struct xtables_target brmark_target = {
+ .name = "mark",
+ .revision = 0,
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_BRIDGE,
+ .size = XT_ALIGN(sizeof(struct ebt_mark_t_info)),
+ .userspacesize = XT_ALIGN(sizeof(struct ebt_mark_t_info)),
+ .help = brmark_print_help,
+ .init = brmark_init,
+ .parse = brmark_parse,
+ .final_check = brmark_final_check,
+ .print = brmark_print,
+ .extra_opts = brmark_opts,
+};
+
+void _init(void)
+{
+ xtables_register_target(&brmark_target);
+}
diff --git a/extensions/libebt_mark_m.c b/extensions/libebt_mark_m.c
new file mode 100644
index 00000000..ab9d2344
--- /dev/null
+++ b/extensions/libebt_mark_m.c
@@ -0,0 +1,118 @@
+/* ebt_mark_m
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * July, 2002
+ *
+ * Adapted by Arturo Borrero Gonzalez <arturo@debian.org>
+ * to use libxtables for ebtables-compat in 2015.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter_bridge/ebt_mark_m.h>
+
+#define MARK '1'
+
+static struct option brmark_m_opts[] = {
+ { .name = "mark", .has_arg = true, .val = MARK },
+ XT_GETOPT_TABLEEND,
+};
+
+static void brmark_m_print_help(void)
+{
+ printf(
+"mark option:\n"
+"--mark [!] [value][/mask]: Match nfmask value (see man page)\n");
+}
+
+static void brmark_m_init(struct xt_entry_match *match)
+{
+ struct ebt_mark_m_info *info = (struct ebt_mark_m_info *)match->data;
+
+ info->mark = 0;
+ info->mask = 0;
+ info->invert = 0;
+ info->bitmask = 0;
+}
+
+#define OPT_MARK 0x01
+static int
+brmark_m_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_match **match)
+{
+ struct ebt_mark_m_info *info = (struct ebt_mark_m_info *)
+ (*match)->data;
+ char *end;
+
+ switch (c) {
+ case MARK:
+ if (invert)
+ info->invert = 1;
+ info->mark = strtoul(optarg, &end, 0);
+ info->bitmask = EBT_MARK_AND;
+ if (*end == '/') {
+ if (end == optarg)
+ info->bitmask = EBT_MARK_OR;
+ info->mask = strtoul(end+1, &end, 0);
+ } else {
+ info->mask = 0xffffffff;
+ }
+ if (*end != '\0' || end == optarg)
+ xtables_error(PARAMETER_PROBLEM, "Bad mark value '%s'",
+ optarg);
+ break;
+ default:
+ return 0;
+ }
+
+ *flags |= info->bitmask;
+ return 1;
+}
+
+static void brmark_m_final_check(unsigned int flags)
+{
+ if (!flags)
+ xtables_error(PARAMETER_PROBLEM,
+ "You must specify proper arguments");
+}
+
+static void brmark_m_print(const void *ip, const struct xt_entry_match *match,
+ int numeric)
+{
+ struct ebt_mark_m_info *info = (struct ebt_mark_m_info *)match->data;
+
+ printf("--mark ");
+ if (info->invert)
+ printf("! ");
+ if (info->bitmask == EBT_MARK_OR)
+ printf("/0x%lx ", info->mask);
+ else if (info->mask != 0xffffffff)
+ printf("0x%lx/0x%lx ", info->mark, info->mask);
+ else
+ printf("0x%lx ", info->mark);
+}
+
+static struct xtables_match brmark_m_match = {
+ .name = "mark_m",
+ .revision = 0,
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_BRIDGE,
+ .size = XT_ALIGN(sizeof(struct ebt_mark_m_info)),
+ .userspacesize = XT_ALIGN(sizeof(struct ebt_mark_m_info)),
+ .init = brmark_m_init,
+ .help = brmark_m_print_help,
+ .parse = brmark_m_parse,
+ .final_check = brmark_m_final_check,
+ .print = brmark_m_print,
+ .extra_opts = brmark_m_opts,
+};
+
+void _init(void)
+{
+ xtables_register_match(&brmark_m_match);
+}
diff --git a/extensions/libebt_nflog.c b/extensions/libebt_nflog.c
new file mode 100644
index 00000000..fef71960
--- /dev/null
+++ b/extensions/libebt_nflog.c
@@ -0,0 +1,144 @@
+/* ebt_nflog
+ *
+ * Authors:
+ * Peter Warasin <peter@endian.com>
+ *
+ * February, 2008
+ *
+ * Based on:
+ * ebt_ulog.c, (C) 2004, Bart De Schuymer <bdschuym@pandora.be>
+ * libxt_NFLOG.c
+ *
+ * Adapted to libxtables for ebtables-compat in 2015 by
+ * Arturo Borrero Gonzalez <arturo@debian.org>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <xtables.h>
+#include "iptables/nft.h"
+#include "iptables/nft-bridge.h"
+#include <linux/netfilter_bridge/ebt_nflog.h>
+
+enum {
+ NFLOG_GROUP = 0x1,
+ NFLOG_PREFIX = 0x2,
+ NFLOG_RANGE = 0x4,
+ NFLOG_THRESHOLD = 0x8,
+ NFLOG_NFLOG = 0x16,
+};
+
+static struct option brnflog_opts[] = {
+ { .name = "nflog-group", .has_arg = true, .val = NFLOG_GROUP},
+ { .name = "nflog-prefix", .has_arg = true, .val = NFLOG_PREFIX},
+ { .name = "nflog-range", .has_arg = true, .val = NFLOG_RANGE},
+ { .name = "nflog-threshold", .has_arg = true, .val = NFLOG_THRESHOLD},
+ { .name = "nflog", .has_arg = false, .val = NFLOG_NFLOG},
+ XT_GETOPT_TABLEEND,
+};
+
+static void brnflog_help(void)
+{
+ printf("nflog options:\n"
+ "--nflog : use the default nflog parameters\n"
+ "--nflog-prefix prefix : Prefix string for log message\n"
+ "--nflog-group group : NETLINK group used for logging\n"
+ "--nflog-range range : Number of byte to copy\n"
+ "--nflog-threshold : Message threshold of"
+ "in-kernel queue\n");
+}
+
+static void brnflog_init(struct xt_entry_target *t)
+{
+ struct ebt_nflog_info *info = (struct ebt_nflog_info *)t->data;
+
+ info->prefix[0] = '\0';
+ info->group = EBT_NFLOG_DEFAULT_GROUP;
+ info->threshold = EBT_NFLOG_DEFAULT_THRESHOLD;
+}
+
+static int brnflog_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_target **target)
+{
+ struct ebt_nflog_info *info = (struct ebt_nflog_info *)(*target)->data;
+ unsigned int i;
+
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "The use of '!' makes no sense for the"
+ " nflog watcher");
+
+ switch (c) {
+ case NFLOG_PREFIX:
+ EBT_CHECK_OPTION(flags, NFLOG_PREFIX);
+ if (strlen(optarg) > EBT_NFLOG_PREFIX_SIZE - 1)
+ xtables_error(PARAMETER_PROBLEM,
+ "Prefix too long for nflog-prefix");
+ strncpy(info->prefix, optarg, EBT_NFLOG_PREFIX_SIZE);
+ break;
+ case NFLOG_GROUP:
+ EBT_CHECK_OPTION(flags, NFLOG_GROUP);
+ if (!xtables_strtoui(optarg, NULL, &i, 1, UINT32_MAX))
+ xtables_error(PARAMETER_PROBLEM,
+ "--nflog-group must be a number!");
+ info->group = i;
+ break;
+ case NFLOG_RANGE:
+ EBT_CHECK_OPTION(flags, NFLOG_RANGE);
+ if (!xtables_strtoui(optarg, NULL, &i, 1, UINT32_MAX))
+ xtables_error(PARAMETER_PROBLEM,
+ "--nflog-range must be a number!");
+ info->len = i;
+ break;
+ case NFLOG_THRESHOLD:
+ EBT_CHECK_OPTION(flags, NFLOG_THRESHOLD);
+ if (!xtables_strtoui(optarg, NULL, &i, 1, UINT32_MAX))
+ xtables_error(PARAMETER_PROBLEM,
+ "--nflog-threshold must be a number!");
+ info->threshold = i;
+ break;
+ case NFLOG_NFLOG:
+ EBT_CHECK_OPTION(flags, NFLOG_NFLOG);
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static void
+brnflog_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ struct ebt_nflog_info *info = (struct ebt_nflog_info *)target->data;
+
+ if (info->prefix[0] != '\0')
+ printf("--nflog-prefix \"%s\" ", info->prefix);
+ if (info->group)
+ printf("--nflog-group %d ", info->group);
+ if (info->len)
+ printf("--nflog-range %d ", info->len);
+ if (info->threshold != EBT_NFLOG_DEFAULT_THRESHOLD)
+ printf("--nflog-threshold %d ", info->threshold);
+}
+
+static struct xtables_target brnflog_watcher = {
+ .name = "nflog",
+ .revision = 0,
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_BRIDGE,
+ .size = XT_ALIGN(sizeof(struct ebt_nflog_info)),
+ .userspacesize = XT_ALIGN(sizeof(struct ebt_nflog_info)),
+ .init = brnflog_init,
+ .help = brnflog_help,
+ .parse = brnflog_parse,
+ .print = brnflog_print,
+ .extra_opts = brnflog_opts,
+};
+
+void _init(void)
+{
+ xtables_register_target(&brnflog_watcher);
+}
diff --git a/extensions/libip6t_DNAT.c b/extensions/libip6t_DNAT.c
index eaa6bf1e..08d920db 100644
--- a/extensions/libip6t_DNAT.c
+++ b/extensions/libip6t_DNAT.c
@@ -231,6 +231,56 @@ static void DNAT_save(const void *ip, const struct xt_entry_target *target)
printf(" --persistent");
}
+static void print_range_xlate(const struct nf_nat_range *range,
+ struct xt_xlate *xl)
+{
+ bool proto_specified = range->flags & NF_NAT_RANGE_PROTO_SPECIFIED;
+
+ if (range->flags & NF_NAT_RANGE_MAP_IPS) {
+ xt_xlate_add(xl, "%s%s%s",
+ proto_specified ? "[" : "",
+ xtables_ip6addr_to_numeric(&range->min_addr.in6),
+ proto_specified ? "]" : "");
+
+ if (memcmp(&range->min_addr, &range->max_addr,
+ sizeof(range->min_addr))) {
+ xt_xlate_add(xl, "-%s%s%s",
+ proto_specified ? "[" : "",
+ xtables_ip6addr_to_numeric(&range->max_addr.in6),
+ proto_specified ? "]" : "");
+ }
+ }
+ if (proto_specified) {
+ xt_xlate_add(xl, ":%hu", ntohs(range->min_proto.tcp.port));
+
+ if (range->max_proto.tcp.port != range->min_proto.tcp.port)
+ xt_xlate_add(xl, "-%hu",
+ ntohs(range->max_proto.tcp.port));
+ }
+}
+
+static int DNAT_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct nf_nat_range *range = (const void *)params->target->data;
+ bool sep_need = false;
+ const char *sep = " ";
+
+ xt_xlate_add(xl, "dnat to ");
+ print_range_xlate(range, xl);
+ if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) {
+ xt_xlate_add(xl, " random");
+ sep_need = true;
+ }
+ if (range->flags & NF_NAT_RANGE_PERSISTENT) {
+ if (sep_need)
+ sep = ",";
+ xt_xlate_add(xl, "%spersistent", sep);
+ }
+
+ return 1;
+}
+
static struct xtables_target snat_tg_reg = {
.name = "DNAT",
.version = XTABLES_VERSION,
@@ -244,6 +294,7 @@ static struct xtables_target snat_tg_reg = {
.print = DNAT_print,
.save = DNAT_save,
.x6_options = DNAT_opts,
+ .xlate = DNAT_xlate,
};
void _init(void)
diff --git a/extensions/libip6t_DNAT.t b/extensions/libip6t_DNAT.t
new file mode 100644
index 00000000..3141c299
--- /dev/null
+++ b/extensions/libip6t_DNAT.t
@@ -0,0 +1,8 @@
+:PREROUTING
+*nat
+-j DNAT --to-destination dead::beef;=;OK
+-j DNAT --to-destination dead::beef-dead::fee7;=;OK
+-p tcp -j DNAT --to-destination [dead::beef]:1025-65535;=;OK
+-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1025-65535;=;OK
+-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1025-65536;;FAIL
+-j DNAT;;FAIL
diff --git a/extensions/libip6t_DNPT.c b/extensions/libip6t_DNPT.c
index a442de6d..d045e44c 100644
--- a/extensions/libip6t_DNPT.c
+++ b/extensions/libip6t_DNPT.c
@@ -52,9 +52,9 @@ static void DNPT_print(const void *ip, const struct xt_entry_target *target,
{
const struct ip6t_npt_tginfo *npt = (const void *)target->data;
- printf("src-pfx %s/%u ", xtables_ip6addr_to_numeric(&npt->src_pfx.in6),
+ printf(" DNPT src-pfx %s/%u", xtables_ip6addr_to_numeric(&npt->src_pfx.in6),
npt->src_pfx_len);
- printf("dst-pfx %s/%u ", xtables_ip6addr_to_numeric(&npt->dst_pfx.in6),
+ printf(" dst-pfx %s/%u", xtables_ip6addr_to_numeric(&npt->dst_pfx.in6),
npt->dst_pfx_len);
}
@@ -65,12 +65,12 @@ static void DNPT_save(const void *ip, const struct xt_entry_target *target)
if (memcmp(&info->src_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 ||
info->src_pfx_len != 0)
- printf("--src-pfx %s/%u ",
+ printf(" --src-pfx %s/%u",
xtables_ip6addr_to_numeric(&info->src_pfx.in6),
info->src_pfx_len);
if (memcmp(&info->dst_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 ||
info->dst_pfx_len != 0)
- printf("--dst-pfx %s/%u ",
+ printf(" --dst-pfx %s/%u",
xtables_ip6addr_to_numeric(&info->dst_pfx.in6),
info->dst_pfx_len);
}
diff --git a/extensions/libip6t_DNPT.t b/extensions/libip6t_DNPT.t
new file mode 100644
index 00000000..0406dc90
--- /dev/null
+++ b/extensions/libip6t_DNPT.t
@@ -0,0 +1,7 @@
+:PREROUTING
+*mangle
+-j DNPT --src-pfx dead::/64 --dst-pfx 1c3::/64;=;OK
+-j DNPT --src-pfx dead::beef --dst-pfx 1c3::/64;;FAIL
+-j DNPT --src-pfx dead::/64;;FAIL
+-j DNPT --dst-pfx dead::/64;;FAIL
+-j DNPT;;FAIL
diff --git a/extensions/libip6t_HL.t b/extensions/libip6t_HL.t
new file mode 100644
index 00000000..4e529f88
--- /dev/null
+++ b/extensions/libip6t_HL.t
@@ -0,0 +1,10 @@
+:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j HL --hl-set 42;=;OK
+-j HL --hl-inc 1;=;OK
+-j HL --hl-dec 1;=;OK
+-j HL --hl-set 256;;FAIL
+-j HL --hl-inc 0;;FAIL
+-j HL --hl-dec 0;;FAIL
+-j HL --hl-dec 1 --hl-inc 1;;FAIL
+-j HL --hl-set --hl-inc 1;;FAIL
diff --git a/extensions/libip6t_LOG.c b/extensions/libip6t_LOG.c
index 4639268d..40adc69d 100644
--- a/extensions/libip6t_LOG.c
+++ b/extensions/libip6t_LOG.c
@@ -63,6 +63,11 @@ struct ip6t_log_names {
unsigned int level;
};
+struct ip6t_log_xlate {
+ 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 },
@@ -166,6 +171,64 @@ static void LOG_save(const void *ip, const struct xt_entry_target *target)
printf(" --log-macdecode");
}
+static const struct ip6t_log_xlate ip6t_log_xlate_names[] = {
+ {"alert", LOG_ALERT },
+ {"crit", LOG_CRIT },
+ {"debug", LOG_DEBUG },
+ {"emerg", LOG_EMERG },
+ {"err", LOG_ERR },
+ {"info", LOG_INFO },
+ {"notice", LOG_NOTICE },
+ {"warn", LOG_WARNING }
+};
+
+static int LOG_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct ip6t_log_info *loginfo =
+ (const struct ip6t_log_info *)params->target->data;
+ unsigned int i = 0;
+
+ xt_xlate_add(xl, "log");
+ if (strcmp(loginfo->prefix, "") != 0) {
+ if (params->escape_quotes)
+ xt_xlate_add(xl, " prefix \\\"%s\\\"", loginfo->prefix);
+ else
+ xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ip6t_log_xlate_names); ++i)
+ if (loginfo->level == ip6t_log_xlate_names[i].level &&
+ loginfo->level != LOG_DEFAULT_LEVEL) {
+ xt_xlate_add(xl, " level %s",
+ ip6t_log_xlate_names[i].name);
+ break;
+ }
+
+ if ((loginfo->logflags & IP6T_LOG_MASK) == IP6T_LOG_MASK) {
+ xt_xlate_add(xl, " flags all");
+ } else {
+ if (loginfo->logflags & (IP6T_LOG_TCPSEQ | IP6T_LOG_TCPOPT)) {
+ const char *delim = " ";
+
+ xt_xlate_add(xl, " flags tcp");
+ if (loginfo->logflags & IP6T_LOG_TCPSEQ) {
+ xt_xlate_add(xl, " sequence");
+ delim = ",";
+ }
+ if (loginfo->logflags & IP6T_LOG_TCPOPT)
+ xt_xlate_add(xl, "%soptions", delim);
+ }
+ if (loginfo->logflags & IP6T_LOG_IPOPT)
+ xt_xlate_add(xl, " flags ip options");
+ if (loginfo->logflags & IP6T_LOG_UID)
+ xt_xlate_add(xl, " flags skuid");
+ if (loginfo->logflags & IP6T_LOG_MACDECODE)
+ xt_xlate_add(xl, " flags ether");
+ }
+
+ return 1;
+}
static struct xtables_target log_tg6_reg = {
.name = "LOG",
.version = XTABLES_VERSION,
@@ -178,6 +241,7 @@ static struct xtables_target log_tg6_reg = {
.save = LOG_save,
.x6_parse = LOG_parse,
.x6_options = LOG_opts,
+ .xlate = LOG_xlate,
};
void _init(void)
diff --git a/extensions/libip6t_LOG.t b/extensions/libip6t_LOG.t
new file mode 100644
index 00000000..fbf5118b
--- /dev/null
+++ b/extensions/libip6t_LOG.t
@@ -0,0 +1,12 @@
+:INPUT,FORWARD,OUTPUT
+-j LOG;-j LOG;OK
+-j LOG --log-prefix "test: ";=;OK
+-j LOG --log-prefix "test: " --log-level 1;=;OK
+# iptables displays the log-level output using the number; not the string
+-j LOG --log-prefix "test: " --log-level alert;-j LOG --log-prefix "test: " --log-level 1;OK
+-j LOG --log-prefix "test: " --log-tcp-sequence;=;OK
+-j LOG --log-prefix "test: " --log-tcp-options;=;OK
+-j LOG --log-prefix "test: " --log-ip-options;=;OK
+-j LOG --log-prefix "test: " --log-uid;=;OK
+-j LOG --log-prefix "test: " --log-level bad;;FAIL
+-j LOG --log-prefix;;FAIL
diff --git a/extensions/libip6t_MASQUERADE.c b/extensions/libip6t_MASQUERADE.c
index eb9213ef..3b59e43e 100644
--- a/extensions/libip6t_MASQUERADE.c
+++ b/extensions/libip6t_MASQUERADE.c
@@ -131,6 +131,26 @@ MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
printf(" --random");
}
+static int MASQUERADE_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct nf_nat_range *r = (const void *)params->target->data;
+
+ xt_xlate_add(xl, "masquerade");
+
+ if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
+ xt_xlate_add(xl, " to :%hu", ntohs(r->min_proto.tcp.port));
+ if (r->max_proto.tcp.port != r->min_proto.tcp.port)
+ xt_xlate_add(xl, "-%hu", ntohs(r->max_proto.tcp.port));
+ }
+
+ xt_xlate_add(xl, " ");
+ if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
+ xt_xlate_add(xl, "random ");
+
+ return 1;
+}
+
static struct xtables_target masquerade_tg_reg = {
.name = "MASQUERADE",
.version = XTABLES_VERSION,
@@ -142,6 +162,7 @@ static struct xtables_target masquerade_tg_reg = {
.print = MASQUERADE_print,
.save = MASQUERADE_save,
.x6_options = MASQUERADE_opts,
+ .xlate = MASQUERADE_xlate,
};
void _init(void)
diff --git a/extensions/libip6t_MASQUERADE.t b/extensions/libip6t_MASQUERADE.t
new file mode 100644
index 00000000..46502040
--- /dev/null
+++ b/extensions/libip6t_MASQUERADE.t
@@ -0,0 +1,8 @@
+:POSTROUTING
+*nat
+-j MASQUERADE;=;OK
+-j MASQUERADE --random;=;OK
+-p tcp -j MASQUERADE --to-ports 1024;=;OK
+-p udp -j MASQUERADE --to-ports 1024-65535;=;OK
+-p udp -j MASQUERADE --to-ports 1024-65536;;FAIL
+-p udp -j MASQUERADE --to-ports -1;;FAIL
diff --git a/extensions/libip6t_NETMAP.c b/extensions/libip6t_NETMAP.c
index a4df70ee..579ed04e 100644
--- a/extensions/libip6t_NETMAP.c
+++ b/extensions/libip6t_NETMAP.c
@@ -49,8 +49,8 @@ static void NETMAP_parse(struct xt_option_call *cb)
}
}
-static void NETMAP_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
+static void __NETMAP_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
{
const struct nf_nat_range *r = (const void *)target->data;
struct in6_addr a;
@@ -68,10 +68,17 @@ static void NETMAP_print(const void *ip, const struct xt_entry_target *target,
printf("/%d", bits);
}
+static void NETMAP_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ printf(" to:");
+ __NETMAP_print(ip, target, numeric);
+}
+
static void NETMAP_save(const void *ip, const struct xt_entry_target *target)
{
printf(" --%s ", NETMAP_opts[0].name);
- NETMAP_print(ip, target, 0);
+ __NETMAP_print(ip, target, 0);
}
static struct xtables_target netmap_tg_reg = {
diff --git a/extensions/libip6t_NETMAP.t b/extensions/libip6t_NETMAP.t
new file mode 100644
index 00000000..043562d2
--- /dev/null
+++ b/extensions/libip6t_NETMAP.t
@@ -0,0 +1,4 @@
+:PREROUTING,INPUT,OUTPUT,POSTROUTING
+*nat
+-j NETMAP --to dead::/64;=;OK
+-j NETMAP --to dead::beef;=;OK
diff --git a/extensions/libip6t_REDIRECT.c b/extensions/libip6t_REDIRECT.c
index 1724aa67..8e04d2cd 100644
--- a/extensions/libip6t_REDIRECT.c
+++ b/extensions/libip6t_REDIRECT.c
@@ -132,6 +132,24 @@ static void REDIRECT_save(const void *ip, const struct xt_entry_target *target)
}
}
+static int REDIRECT_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct nf_nat_range *range = (const void *)params->target->data;
+
+ if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
+ xt_xlate_add(xl, "redirect to :%hu",
+ ntohs(range->min_proto.tcp.port));
+ if (range->max_proto.tcp.port != range->min_proto.tcp.port)
+ xt_xlate_add(xl, "-%hu ",
+ ntohs(range->max_proto.tcp.port));
+ if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
+ xt_xlate_add(xl, " random ");
+ }
+
+ return 1;
+}
+
static struct xtables_target redirect_tg_reg = {
.name = "REDIRECT",
.version = XTABLES_VERSION,
@@ -143,6 +161,7 @@ static struct xtables_target redirect_tg_reg = {
.print = REDIRECT_print,
.save = REDIRECT_save,
.x6_options = REDIRECT_opts,
+ .xlate = REDIRECT_xlate,
};
void _init(void)
diff --git a/extensions/libip6t_REDIRECT.t b/extensions/libip6t_REDIRECT.t
new file mode 100644
index 00000000..a0fb0ed1
--- /dev/null
+++ b/extensions/libip6t_REDIRECT.t
@@ -0,0 +1,6 @@
+:PREROUTING,OUTPUT
+*nat
+-p tcp -j REDIRECT --to-ports 42;=;OK
+-p udp -j REDIRECT --to-ports 42-1234;=;OK
+-p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK
+-j REDIRECT --to-ports 42;;FAIL
diff --git a/extensions/libip6t_REJECT.c b/extensions/libip6t_REJECT.c
index 8085321a..c5b980d0 100644
--- a/extensions/libip6t_REJECT.c
+++ b/extensions/libip6t_REJECT.c
@@ -17,6 +17,11 @@ struct reject_names {
const char *desc;
};
+struct reject_names_xlate {
+ const char *name;
+ enum ip6t_reject_with with;
+};
+
enum {
O_REJECT_WITH = 0,
};
@@ -35,7 +40,11 @@ static const struct reject_names reject_table[] = {
{"icmp6-port-unreachable", "port-unreach",
IP6T_ICMP6_PORT_UNREACH, "ICMPv6 port unreachable"},
{"tcp-reset", "tcp-reset",
- IP6T_TCP_RESET, "TCP RST packet"}
+ IP6T_TCP_RESET, "TCP RST packet"},
+ {"icmp6-policy-fail", "policy-fail",
+ IP6T_ICMP6_POLICY_FAIL, "ICMPv6 policy fail"},
+ {"icmp6-reject-route", "reject-route",
+ IP6T_ICMP6_REJECT_ROUTE, "ICMPv6 reject route"}
};
static void
@@ -120,6 +129,38 @@ static void REJECT_save(const void *ip, const struct xt_entry_target *target)
printf(" --reject-with %s", reject_table[i].name);
}
+static const struct reject_names_xlate reject_table_xlate[] = {
+ {"no-route", IP6T_ICMP6_NO_ROUTE},
+ {"admin-prohibited", IP6T_ICMP6_ADM_PROHIBITED},
+ {"addr-unreachable", IP6T_ICMP6_ADDR_UNREACH},
+ {"port-unreachable", IP6T_ICMP6_PORT_UNREACH},
+ {"tcp reset", IP6T_TCP_RESET},
+ {"policy-fail", IP6T_ICMP6_POLICY_FAIL},
+ {"reject-route", IP6T_ICMP6_REJECT_ROUTE}
+};
+
+static int REJECT_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct ip6t_reject_info *reject =
+ (const struct ip6t_reject_info *)params->target->data;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(reject_table_xlate); ++i)
+ if (reject_table_xlate[i].with == reject->with)
+ break;
+
+ if (reject->with == IP6T_ICMP6_PORT_UNREACH)
+ xt_xlate_add(xl, "reject");
+ else if (reject->with == IP6T_TCP_RESET)
+ xt_xlate_add(xl, "reject with %s", reject_table_xlate[i].name);
+ else
+ xt_xlate_add(xl, "reject with icmpv6 type %s",
+ reject_table_xlate[i].name);
+
+ return 1;
+}
+
static struct xtables_target reject_tg6_reg = {
.name = "REJECT",
.version = XTABLES_VERSION,
@@ -132,6 +173,7 @@ static struct xtables_target reject_tg6_reg = {
.save = REJECT_save,
.x6_parse = REJECT_parse,
.x6_options = REJECT_opts,
+ .xlate = REJECT_xlate,
};
void _init(void)
diff --git a/extensions/libip6t_REJECT.man b/extensions/libip6t_REJECT.man
index 2d09e050..0030a51f 100644
--- a/extensions/libip6t_REJECT.man
+++ b/extensions/libip6t_REJECT.man
@@ -18,10 +18,9 @@ The type given can be
\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
+\fBaddr\-unreach\fP, or
+\fBicmp6\-port\-unreachable\fP,
+which return the appropriate ICMPv6 error message (\fBicmp6\-port\-unreachable\fP is
the default). Finally, the option
\fBtcp\-reset\fP
can be used on rules which only match the TCP protocol: this causes a
diff --git a/extensions/libip6t_REJECT.t b/extensions/libip6t_REJECT.t
new file mode 100644
index 00000000..d2b337d7
--- /dev/null
+++ b/extensions/libip6t_REJECT.t
@@ -0,0 +1,11 @@
+:INPUT,FORWARD,OUTPUT
+-j REJECT;=;OK
+# manpage for IPv6 variant of REJECT does not show up for some reason?
+-j REJECT --reject-with icmp6-no-route;=;OK
+-j REJECT --reject-with icmp6-adm-prohibited;=;OK
+-j REJECT --reject-with icmp6-addr-unreachable;=;OK
+-j REJECT --reject-with icmp6-port-unreachable;=;OK
+-j REJECT --reject-with icmp6-policy-fail;=;OK
+-j REJECT --reject-with icmp6-reject-route;=;OK
+-p tcp -j REJECT --reject-with tcp-reset;=;OK
+-j REJECT --reject-with tcp-reset;;FAIL
diff --git a/extensions/libip6t_SNAT.c b/extensions/libip6t_SNAT.c
index 7382ad06..671ac61a 100644
--- a/extensions/libip6t_SNAT.c
+++ b/extensions/libip6t_SNAT.c
@@ -18,11 +18,13 @@
enum {
O_TO_SRC = 0,
O_RANDOM,
+ O_RANDOM_FULLY,
O_PERSISTENT,
O_X_TO_SRC,
- F_TO_SRC = 1 << O_TO_SRC,
- F_RANDOM = 1 << O_RANDOM,
- F_X_TO_SRC = 1 << O_X_TO_SRC,
+ F_TO_SRC = 1 << O_TO_SRC,
+ F_RANDOM = 1 << O_RANDOM,
+ F_RANDOM_FULLY = 1 << O_RANDOM_FULLY,
+ F_X_TO_SRC = 1 << O_X_TO_SRC,
};
static void SNAT_help(void)
@@ -31,13 +33,14 @@ static void SNAT_help(void)
"SNAT target options:\n"
" --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
" Address to map source to.\n"
-"[--random] [--persistent]\n");
+"[--random] [--random-fully] [--persistent]\n");
}
static const struct xt_option_entry SNAT_opts[] = {
{.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_MULTI},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
+ {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE},
{.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
@@ -180,10 +183,13 @@ static void SNAT_parse(struct xt_option_call *cb)
static void SNAT_fcheck(struct xt_fcheck_call *cb)
{
static const unsigned int f = F_TO_SRC | F_RANDOM;
+ static const unsigned int r = F_TO_SRC | F_RANDOM_FULLY;
struct nf_nat_range *range = cb->data;
if ((cb->xflags & f) == f)
range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
+ if ((cb->xflags & r) == r)
+ range->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY;
}
static void print_range(const struct nf_nat_range *range)
@@ -215,6 +221,8 @@ static void SNAT_print(const void *ip, const struct xt_entry_target *target,
print_range(range);
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" random");
+ if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+ printf(" random-fully");
if (range->flags & NF_NAT_RANGE_PERSISTENT)
printf(" persistent");
}
@@ -227,10 +235,68 @@ static void SNAT_save(const void *ip, const struct xt_entry_target *target)
print_range(range);
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
+ if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+ printf(" --random-fully");
if (range->flags & NF_NAT_RANGE_PERSISTENT)
printf(" --persistent");
}
+static void print_range_xlate(const struct nf_nat_range *range,
+ struct xt_xlate *xl)
+{
+ bool proto_specified = range->flags & NF_NAT_RANGE_PROTO_SPECIFIED;
+
+ if (range->flags & NF_NAT_RANGE_MAP_IPS) {
+ xt_xlate_add(xl, "%s%s%s",
+ proto_specified ? "[" : "",
+ xtables_ip6addr_to_numeric(&range->min_addr.in6),
+ proto_specified ? "]" : "");
+
+ if (memcmp(&range->min_addr, &range->max_addr,
+ sizeof(range->min_addr))) {
+ xt_xlate_add(xl, "-%s%s%s",
+ proto_specified ? "[" : "",
+ xtables_ip6addr_to_numeric(&range->max_addr.in6),
+ proto_specified ? "]" : "");
+ }
+ }
+ if (proto_specified) {
+ xt_xlate_add(xl, ":%hu", ntohs(range->min_proto.tcp.port));
+
+ if (range->max_proto.tcp.port != range->min_proto.tcp.port)
+ xt_xlate_add(xl, "-%hu",
+ ntohs(range->max_proto.tcp.port));
+ }
+}
+
+static int SNAT_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct nf_nat_range *range = (const void *)params->target->data;
+ bool sep_need = false;
+ const char *sep = " ";
+
+ xt_xlate_add(xl, "snat to ");
+ print_range_xlate(range, xl);
+ if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) {
+ xt_xlate_add(xl, " random");
+ sep_need = true;
+ }
+ if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
+ if (sep_need)
+ sep = ",";
+ xt_xlate_add(xl, "%sfully-random", sep);
+ sep_need = true;
+ }
+ if (range->flags & NF_NAT_RANGE_PERSISTENT) {
+ if (sep_need)
+ sep = ",";
+ xt_xlate_add(xl, "%spersistent", sep);
+ }
+
+ return 1;
+}
+
static struct xtables_target snat_tg_reg = {
.name = "SNAT",
.version = XTABLES_VERSION,
@@ -244,6 +310,7 @@ static struct xtables_target snat_tg_reg = {
.print = SNAT_print,
.save = SNAT_save,
.x6_options = SNAT_opts,
+ .xlate = SNAT_xlate,
};
void _init(void)
diff --git a/extensions/libip6t_SNAT.t b/extensions/libip6t_SNAT.t
new file mode 100644
index 00000000..bb080497
--- /dev/null
+++ b/extensions/libip6t_SNAT.t
@@ -0,0 +1,8 @@
+:POSTROUTING
+*nat
+-j SNAT --to-source dead::beef;=;OK
+-j SNAT --to-source dead::beef-dead::fee7;=;OK
+-p tcp -j SNAT --to-source [dead::beef]:1025-65535;=;OK
+-p tcp -j SNAT --to-source [dead::beef-dead::fee7]:1025-65535;=;OK
+-p tcp -j SNAT --to-source [dead::beef-dead::fee7]:1025-65536;;FAIL
+-j SNAT;;FAIL
diff --git a/extensions/libip6t_SNPT.c b/extensions/libip6t_SNPT.c
index 4f10de03..65f787d9 100644
--- a/extensions/libip6t_SNPT.c
+++ b/extensions/libip6t_SNPT.c
@@ -52,9 +52,9 @@ static void SNPT_print(const void *ip, const struct xt_entry_target *target,
{
const struct ip6t_npt_tginfo *npt = (const void *)target->data;
- printf("src-pfx %s/%u ", xtables_ip6addr_to_numeric(&npt->src_pfx.in6),
+ printf(" SNPT src-pfx %s/%u", xtables_ip6addr_to_numeric(&npt->src_pfx.in6),
npt->src_pfx_len);
- printf("dst-pfx %s/%u ", xtables_ip6addr_to_numeric(&npt->dst_pfx.in6),
+ printf(" dst-pfx %s/%u", xtables_ip6addr_to_numeric(&npt->dst_pfx.in6),
npt->dst_pfx_len);
}
@@ -65,12 +65,12 @@ static void SNPT_save(const void *ip, const struct xt_entry_target *target)
if (memcmp(&info->src_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 ||
info->src_pfx_len != 0)
- printf("--src-pfx %s/%u ",
+ printf(" --src-pfx %s/%u",
xtables_ip6addr_to_numeric(&info->src_pfx.in6),
info->src_pfx_len);
if (memcmp(&info->dst_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 ||
info->dst_pfx_len != 0)
- printf("--dst-pfx %s/%u ",
+ printf(" --dst-pfx %s/%u",
xtables_ip6addr_to_numeric(&info->dst_pfx.in6),
info->dst_pfx_len);
}
diff --git a/extensions/libip6t_SNPT.t b/extensions/libip6t_SNPT.t
new file mode 100644
index 00000000..7ed6d0c9
--- /dev/null
+++ b/extensions/libip6t_SNPT.t
@@ -0,0 +1,7 @@
+:INPUT,POSTROUTING
+*mangle
+-j SNPT --src-pfx dead::/64 --dst-pfx 1c3::/64;=;OK
+-j SNPT --src-pfx dead::beef --dst-pfx 1c3::/64;;FAIL
+-j SNPT --src-pfx dead::/64;;FAIL
+-j SNPT --dst-pfx dead::/64;;FAIL
+-j SNPT;;FAIL
diff --git a/extensions/libip6t_ah.c b/extensions/libip6t_ah.c
index 26f81408..f35982f3 100644
--- a/extensions/libip6t_ah.c
+++ b/extensions/libip6t_ah.c
@@ -28,6 +28,14 @@ static const struct xt_option_entry ah_opts[] = {
};
#undef s
+static void ah_init(struct xt_entry_match *m)
+{
+ struct ip6t_ah *ahinfo = (void *)m->data;
+
+ /* Defaults for when no --ahspi is used at all */
+ ahinfo->spis[1] = ~0U;
+}
+
static void ah_parse(struct xt_option_call *cb)
{
struct ip6t_ah *ahinfo = cb->data;
@@ -120,6 +128,41 @@ static void ah_save(const void *ip, const struct xt_entry_match *match)
printf(" --ahres");
}
+static int ah_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct ip6t_ah *ahinfo = (struct ip6t_ah *)params->match->data;
+ char *space = "";
+
+ if (!(ahinfo->spis[0] == 0 && ahinfo->spis[1] == 0xFFFFFFFF)) {
+ xt_xlate_add(xl, "ah spi%s ",
+ (ahinfo->invflags & IP6T_AH_INV_SPI) ? " !=" : "");
+ if (ahinfo->spis[0] != ahinfo->spis[1])
+ xt_xlate_add(xl, "%u-%u", ahinfo->spis[0],
+ ahinfo->spis[1]);
+ else
+ xt_xlate_add(xl, "%u", ahinfo->spis[0]);
+ space = " ";
+ }
+
+ if (ahinfo->hdrlen != 0 || (ahinfo->invflags & IP6T_AH_INV_LEN)) {
+ xt_xlate_add(xl, "%sah hdrlength%s %u", space,
+ (ahinfo->invflags & IP6T_AH_INV_LEN) ? " !=" : "",
+ ahinfo->hdrlen);
+ space = " ";
+ }
+
+ if (ahinfo->hdrres != 0) {
+ xt_xlate_add(xl, "%sah reserved %u", space, ahinfo->hdrres);
+ space = " ";
+ }
+
+ if (!space[0]) /* plain '-m ah' */
+ xt_xlate_add(xl, "meta l4proto ah");
+
+ return 1;
+}
+
static struct xtables_match ah_mt6_reg = {
.name = "ah",
.version = XTABLES_VERSION,
@@ -127,10 +170,12 @@ static struct xtables_match ah_mt6_reg = {
.size = XT_ALIGN(sizeof(struct ip6t_ah)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_ah)),
.help = ah_help,
+ .init = ah_init,
.print = ah_print,
.save = ah_save,
.x6_parse = ah_parse,
.x6_options = ah_opts,
+ .xlate = ah_xlate,
};
void
diff --git a/extensions/libip6t_ah.t b/extensions/libip6t_ah.t
new file mode 100644
index 00000000..c1898d44
--- /dev/null
+++ b/extensions/libip6t_ah.t
@@ -0,0 +1,15 @@
+:INPUT,FORWARD,OUTPUT
+-m ah --ahspi 0;=;OK
+-m ah --ahspi 4294967295;=;OK
+-m ah --ahspi 0:4294967295;-m ah;OK
+-m ah ! --ahspi 0;=;OK
+# ERROR: should fail: iptables -A FORWARD -t mangle -j CLASSIFY --set-class 1:-1
+# -m ah --ahres;=;OK
+# ERROR: line 7 (cannot find: ip6tables -I INPUT -m ah --ahlen 32
+# -m ah --ahlen 32;=;OK
+-m ah --ahspi -1;;FAIL
+-m ah --ahspi 4294967296;;FAIL
+-m ah --ahspi invalid;;FAIL
+-m ah --ahspi 0:invalid;;FAIL
+-m ah --ahspi;;FAIL
+-m ah;=;OK
diff --git a/extensions/libip6t_dst.c b/extensions/libip6t_dst.c
index 3fd4c019..fe7e3403 100644
--- a/extensions/libip6t_dst.c
+++ b/extensions/libip6t_dst.c
@@ -112,6 +112,8 @@ static void dst_parse(struct xt_option_call *cb)
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_DSTLEN:
+ if (cb->invert)
+ optinfo->invflags |= IP6T_OPTS_INV_LEN;
optinfo->flags |= IP6T_OPTS_LEN;
break;
case O_DSTOPTS:
diff --git a/extensions/libip6t_dst.t b/extensions/libip6t_dst.t
new file mode 100644
index 00000000..0b0013b5
--- /dev/null
+++ b/extensions/libip6t_dst.t
@@ -0,0 +1,5 @@
+:INPUT,FORWARD,OUTPUT
+-m dst --dst-len 0;=;OK
+-m dst --dst-opts 149:92,12:12,123:12;=;OK
+-m dst ! --dst-len 42;=;OK
+-m dst --dst-len 42 --dst-opts 149:92,12:12,123:12;=;OK
diff --git a/extensions/libip6t_eui64.t b/extensions/libip6t_eui64.t
new file mode 100644
index 00000000..e5aaaace
--- /dev/null
+++ b/extensions/libip6t_eui64.t
@@ -0,0 +1,8 @@
+:PREROUTING
+*raw
+-m eui64;=;OK
+:INPUT,FORWARD
+*filter
+-m eui64;=;OK
+:OUTPUT
+-m eui64;;FAIL
diff --git a/extensions/libip6t_frag.c b/extensions/libip6t_frag.c
index 023df627..3842496e 100644
--- a/extensions/libip6t_frag.c
+++ b/extensions/libip6t_frag.c
@@ -173,6 +173,45 @@ static void frag_save(const void *ip, const struct xt_entry_match *match)
printf(" --fraglast");
}
+static int frag_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct ip6t_frag *fraginfo =
+ (struct ip6t_frag *)params->match->data;
+ char *space= "";
+
+ if (!(fraginfo->ids[0] == 0 && fraginfo->ids[1] == 0xFFFFFFFF)) {
+ xt_xlate_add(xl, "frag id %s",
+ (fraginfo->invflags & IP6T_FRAG_INV_IDS) ?
+ "!= " : "");
+ if (fraginfo->ids[0] != fraginfo->ids[1])
+ xt_xlate_add(xl, "%u-%u", fraginfo->ids[0],
+ fraginfo->ids[1]);
+ else
+ xt_xlate_add(xl, "%u", fraginfo->ids[0]);
+
+ space = " ";
+ }
+
+ if (fraginfo->flags & IP6T_FRAG_RES) {
+ xt_xlate_add(xl, "%sfrag reserved 1", space);
+ space = " ";
+ }
+ if (fraginfo->flags & IP6T_FRAG_FST) {
+ xt_xlate_add(xl, "%sfrag frag-off 0", space);
+ space = " ";
+ }
+ if (fraginfo->flags & IP6T_FRAG_MF) {
+ xt_xlate_add(xl, "%sfrag more-fragments 1", space);
+ space = " ";
+ }
+ if (fraginfo->flags & IP6T_FRAG_NMF) {
+ xt_xlate_add(xl, "%sfrag more-fragments 0", space);
+ }
+
+ return 1;
+}
+
static struct xtables_match frag_mt6_reg = {
.name = "frag",
.version = XTABLES_VERSION,
@@ -185,6 +224,7 @@ static struct xtables_match frag_mt6_reg = {
.save = frag_save,
.x6_parse = frag_parse,
.x6_options = frag_opts,
+ .xlate = frag_xlate,
};
void
diff --git a/extensions/libip6t_frag.t b/extensions/libip6t_frag.t
new file mode 100644
index 00000000..dab49894
--- /dev/null
+++ b/extensions/libip6t_frag.t
@@ -0,0 +1,11 @@
+:INPUT,FORWARD,OUTPUT
+-m frag --fragid 1:42;=;OK
+-m frag --fraglen 42;=;OK
+-m frag --fragres;=;OK
+-m frag --fragfirst;=;OK
+-m frag --fragmore;=;OK
+-m frag --fraglast;=;OK
+-m frag ! --fragid 1 ! --fraglen 42 --fragres --fragfirst;=;OK
+-m frag --fragfirst --fragmore;=;OK
+-m frag --fragfirst --fraglast;=;OK
+-m frag --fraglast --fragmore;;FAIL
diff --git a/extensions/libip6t_hbh.c b/extensions/libip6t_hbh.c
index c0389ed8..76b4ff00 100644
--- a/extensions/libip6t_hbh.c
+++ b/extensions/libip6t_hbh.c
@@ -164,6 +164,23 @@ static void hbh_save(const void *ip, const struct xt_entry_match *match)
print_options(optinfo->optsnr, (uint16_t *)optinfo->opts);
}
+static int hbh_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct ip6t_opts *optinfo =
+ (struct ip6t_opts *)params->match->data;
+
+ if (!(optinfo->flags & IP6T_OPTS_LEN) ||
+ (optinfo->flags & IP6T_OPTS_OPTS))
+ return 0;
+
+ xt_xlate_add(xl, "hbh hdrlength %s%u",
+ (optinfo->invflags & IP6T_OPTS_INV_LEN) ? "!= " : "",
+ optinfo->hdrlen);
+
+ return 1;
+}
+
static struct xtables_match hbh_mt6_reg = {
.name = "hbh",
.version = XTABLES_VERSION,
@@ -175,6 +192,7 @@ static struct xtables_match hbh_mt6_reg = {
.save = hbh_save,
.x6_parse = hbh_parse,
.x6_options = hbh_opts,
+ .xlate = hbh_xlate,
};
void
diff --git a/extensions/libip6t_hbh.t b/extensions/libip6t_hbh.t
new file mode 100644
index 00000000..4b58f25a
--- /dev/null
+++ b/extensions/libip6t_hbh.t
@@ -0,0 +1,5 @@
+:INPUT,FORWARD,OUTPUT
+-m hbh;=;OK
+-m hbh --hbh-len 42;=;OK
+-m hbh ! --hbh-len 42;=;OK
+-m hbh --hbh-len 42 --hbh-opts 1:2,23:42,4:6,8:10,42,23,4:5;=;OK
diff --git a/extensions/libip6t_hl.c b/extensions/libip6t_hl.c
index 3559db46..37922f6f 100644
--- a/extensions/libip6t_hl.c
+++ b/extensions/libip6t_hl.c
@@ -83,6 +83,24 @@ static void hl_save(const void *ip, const struct xt_entry_match *match)
printf(" %s %u", op[info->mode], info->hop_limit);
}
+static const char *const op[] = {
+ [IP6T_HL_EQ] = "",
+ [IP6T_HL_NE] = "!= ",
+ [IP6T_HL_LT] = "lt ",
+ [IP6T_HL_GT] = "gt "
+};
+
+static int hl_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct ip6t_hl_info *info =
+ (struct ip6t_hl_info *) params->match->data;
+
+ xt_xlate_add(xl, "ip6 hoplimit %s%u", op[info->mode], info->hop_limit);
+
+ return 1;
+}
+
#define s struct ip6t_hl_info
static const struct xt_option_entry hl_opts[] = {
{.name = "hl-lt", .id = O_HL_LT, .excl = F_ANY, .type = XTTYPE_UINT8,
@@ -109,6 +127,7 @@ static struct xtables_match hl_mt6_reg = {
.x6_parse = hl_parse,
.x6_fcheck = hl_check,
.x6_options = hl_opts,
+ .xlate = hl_xlate,
};
diff --git a/extensions/libip6t_hl.t b/extensions/libip6t_hl.t
new file mode 100644
index 00000000..b02816af
--- /dev/null
+++ b/extensions/libip6t_hl.t
@@ -0,0 +1,8 @@
+:INPUT,FORWARD,OUTPUT
+-m hl;;FAIL
+-m hl --hl-eq 42;=;OK
+-m hl ! --hl-eq 42;=;OK
+-m hl --hl-lt 42;=;OK
+-m hl --hl-gt 42;=;OK
+-m hl --hl-gt 42 --hl-eq 42;;FAIL
+-m hl --hl-gt;;FAIL
diff --git a/extensions/libip6t_icmp6.c b/extensions/libip6t_icmp6.c
index 68b940bd..b49a241d 100644
--- a/extensions/libip6t_icmp6.c
+++ b/extensions/libip6t_icmp6.c
@@ -4,6 +4,7 @@
#include <xtables.h>
#include <limits.h> /* INT_MAX in ip6_tables.h */
#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <netinet/icmp6.h>
enum {
O_ICMPV6_TYPE = 0,
@@ -19,8 +20,11 @@ static const struct icmpv6_names icmpv6_codes[] = {
{ "destination-unreachable", 1, 0, 0xFF },
{ "no-route", 1, 0, 0 },
{ "communication-prohibited", 1, 1, 1 },
+ { "beyond-scope", 1, 2, 2 },
{ "address-unreachable", 1, 3, 3 },
{ "port-unreachable", 1, 4, 4 },
+ { "failed-policy", 1, 5, 5 },
+ { "reject-route", 1, 6, 6 },
{ "packet-too-big", 2, 0, 0xFF },
@@ -219,6 +223,70 @@ static void icmp6_save(const void *ip, const struct xt_entry_match *match)
printf("/%u", icmpv6->code[0]);
}
+#define XT_ICMPV6_TYPE(type) (type - ND_ROUTER_SOLICIT)
+
+static const char *icmp6_type_xlate_array[] = {
+ [XT_ICMPV6_TYPE(ND_ROUTER_SOLICIT)] = "nd-router-solicit",
+ [XT_ICMPV6_TYPE(ND_ROUTER_ADVERT)] = "nd-router-advert",
+ [XT_ICMPV6_TYPE(ND_NEIGHBOR_SOLICIT)] = "nd-neighbor-solicit",
+ [XT_ICMPV6_TYPE(ND_NEIGHBOR_ADVERT)] = "nd-neighbor-advert",
+ [XT_ICMPV6_TYPE(ND_REDIRECT)] = "nd-redirect",
+};
+
+static const char *icmp6_type_xlate(unsigned int type)
+{
+ if (type < ND_ROUTER_SOLICIT || type > ND_REDIRECT)
+ return NULL;
+
+ return icmp6_type_xlate_array[XT_ICMPV6_TYPE(type)];
+}
+
+static unsigned int type_xlate_print(struct xt_xlate *xl, unsigned int icmptype,
+ unsigned int code_min,
+ unsigned int code_max)
+{
+ unsigned int i;
+ const char *type_name;
+
+ if (code_min == code_max)
+ return 0;
+
+ type_name = icmp6_type_xlate(icmptype);
+
+ if (type_name) {
+ xt_xlate_add(xl, type_name);
+ } else {
+ for (i = 0; i < ARRAY_SIZE(icmpv6_codes); ++i)
+ if (icmpv6_codes[i].type == icmptype &&
+ icmpv6_codes[i].code_min == code_min &&
+ icmpv6_codes[i].code_max == code_max)
+ break;
+
+ if (i != ARRAY_SIZE(icmpv6_codes))
+ xt_xlate_add(xl, icmpv6_codes[i].name);
+ else
+ return 0;
+ }
+
+ return 1;
+}
+
+static int icmp6_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct ip6t_icmp *info = (struct ip6t_icmp *)params->match->data;
+
+ xt_xlate_add(xl, "icmpv6 type%s ",
+ (info->invflags & IP6T_ICMP_INV) ? " !=" : "");
+
+ if (!type_xlate_print(xl, info->type, info->code[0], info->code[1]))
+ return 0;
+
+ xt_xlate_add(xl, " ");
+
+ return 1;
+}
+
static struct xtables_match icmp6_mt6_reg = {
.name = "icmp6",
.version = XTABLES_VERSION,
@@ -231,6 +299,7 @@ static struct xtables_match icmp6_mt6_reg = {
.save = icmp6_save,
.x6_parse = icmp6_parse,
.x6_options = icmp6_opts,
+ .xlate = icmp6_xlate,
};
void _init(void)
diff --git a/extensions/libip6t_icmp6.t b/extensions/libip6t_icmp6.t
new file mode 100644
index 00000000..028cfc16
--- /dev/null
+++ b/extensions/libip6t_icmp6.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-m icmpv6;;FAIL
+-p ipv6-icmp -m icmp6 --icmpv6-type 1/0;=;OK
+-p ipv6-icmp -m icmp6 --icmpv6-type 2;=;OK
+# cannot use option twice:
+-p ipv6-icmp -m icmp6 --icmpv6-type no-route --icmpv6-type packet-too-big;;FAIL
diff --git a/extensions/libip6t_ipv6header.c b/extensions/libip6t_ipv6header.c
index 00d5d5b4..6f03087b 100644
--- a/extensions/libip6t_ipv6header.c
+++ b/extensions/libip6t_ipv6header.c
@@ -127,7 +127,7 @@ 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"
+" names: hop,dst,route,frag,auth,esp,none,prot\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"
diff --git a/extensions/libip6t_ipv6header.man b/extensions/libip6t_ipv6header.man
index a9988614..807d9abc 100644
--- a/extensions/libip6t_ipv6header.man
+++ b/extensions/libip6t_ipv6header.man
@@ -31,7 +31,7 @@ Encapsulating Security Payload header
No Next header which matches 59 in the 'Next Header field' of IPv6 header or
any IPv6 extension headers
.TP
-\fBproto\fP
+\fBprot\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.
+\fBprot\fP.
diff --git a/extensions/libip6t_ipv6header.t b/extensions/libip6t_ipv6header.t
new file mode 100644
index 00000000..67fa4799
--- /dev/null
+++ b/extensions/libip6t_ipv6header.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+-m ipv6header --header hop-by-hop;=;OK
+-m ipv6header --header hop-by-hop --soft;=;OK
+-m ipv6header --header ipv6-nonxt;=;OK
diff --git a/extensions/libip6t_mh.c b/extensions/libip6t_mh.c
index 686a2932..f4c0fd9f 100644
--- a/extensions/libip6t_mh.c
+++ b/extensions/libip6t_mh.c
@@ -202,6 +202,26 @@ static void mh_save(const void *ip, const struct xt_entry_match *match)
printf(" --mh-type %u", mhinfo->types[0]);
}
+static int mh_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct ip6t_mh *mhinfo = (struct ip6t_mh *)params->match->data;
+
+ if (mhinfo->types[0] == 0 && mhinfo->types[1] == 0xff)
+ return 1;
+
+ if (mhinfo->types[0] != mhinfo->types[1])
+ xt_xlate_add(xl, "mh type %s%u-%u",
+ mhinfo->invflags & IP6T_MH_INV_TYPE ? "!= " : "",
+ mhinfo->types[0], mhinfo->types[1]);
+ else
+ xt_xlate_add(xl, "mh type %s%u",
+ mhinfo->invflags & IP6T_MH_INV_TYPE ? "!= " : "",
+ mhinfo->types[0]);
+
+ return 1;
+}
+
static const struct xt_option_entry mh_opts[] = {
{.name = "mh-type", .id = O_MH_TYPE, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
@@ -220,6 +240,7 @@ static struct xtables_match mh_mt6_reg = {
.print = mh_print,
.save = mh_save,
.x6_options = mh_opts,
+ .xlate = mh_xlate,
};
void _init(void)
diff --git a/extensions/libip6t_mh.t b/extensions/libip6t_mh.t
new file mode 100644
index 00000000..6b76d13d
--- /dev/null
+++ b/extensions/libip6t_mh.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-m mh;;FAIL
+-p mobility-header -m mh;=;OK
+-p mobility-header -m mh --mh-type 1;=;OK
+-p mobility-header -m mh ! --mh-type 4;=;OK
+-p mobility-header -m mh --mh-type 4:123;=;OK
diff --git a/extensions/libip6t_rt.c b/extensions/libip6t_rt.c
index d470488d..3cb3b249 100644
--- a/extensions/libip6t_rt.c
+++ b/extensions/libip6t_rt.c
@@ -99,6 +99,13 @@ parse_addresses(const char *addrstr, struct in6_addr *addrp)
return i;
}
+static void rt_init(struct xt_entry_match *m)
+{
+ struct ip6t_rt *rtinfo = (void *)m->data;
+
+ rtinfo->segsleft[1] = ~0U;
+}
+
static void rt_parse(struct xt_option_call *cb)
{
struct ip6t_rt *rtinfo = cb->data;
@@ -238,6 +245,43 @@ static void rt_save(const void *ip, const struct xt_entry_match *match)
}
+static int rt_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct ip6t_rt *rtinfo = (struct ip6t_rt *)params->match->data;
+ char *space = "";
+
+ if (rtinfo->flags & IP6T_RT_TYP) {
+ xt_xlate_add(xl, "rt type%s %u",
+ (rtinfo->invflags & IP6T_RT_INV_TYP) ? " !=" : "",
+ rtinfo->rt_type);
+ space = " ";
+ }
+
+ if (!(rtinfo->segsleft[0] == 0 && rtinfo->segsleft[1] == 0xFFFFFFFF)) {
+ xt_xlate_add(xl, "%srt seg-left%s ", space,
+ (rtinfo->invflags & IP6T_RT_INV_SGS) ? " !=" : "");
+
+ if (rtinfo->segsleft[0] != rtinfo->segsleft[1])
+ xt_xlate_add(xl, "%u-%u", rtinfo->segsleft[0],
+ rtinfo->segsleft[1]);
+ else
+ xt_xlate_add(xl, "%u", rtinfo->segsleft[0]);
+ space = " ";
+ }
+
+ if (rtinfo->flags & IP6T_RT_LEN) {
+ xt_xlate_add(xl, "%srt hdrlength%s %u", space,
+ (rtinfo->invflags & IP6T_RT_INV_LEN) ? " !=" : "",
+ rtinfo->hdrlen);
+ }
+
+ if (rtinfo->flags & (IP6T_RT_RES | IP6T_RT_FST | IP6T_RT_FST_NSTRICT))
+ return 0;
+
+ return 1;
+}
+
static struct xtables_match rt_mt6_reg = {
.name = "rt",
.version = XTABLES_VERSION,
@@ -245,10 +289,12 @@ static struct xtables_match rt_mt6_reg = {
.size = XT_ALIGN(sizeof(struct ip6t_rt)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_rt)),
.help = rt_help,
+ .init = rt_init,
.x6_parse = rt_parse,
.print = rt_print,
.save = rt_save,
.x6_options = rt_opts,
+ .xlate = rt_xlate,
};
void
diff --git a/extensions/libip6t_rt.t b/extensions/libip6t_rt.t
new file mode 100644
index 00000000..3c7b2d98
--- /dev/null
+++ b/extensions/libip6t_rt.t
@@ -0,0 +1,5 @@
+:INPUT,FORWARD,OUTPUT
+-m rt --rt-type 0 --rt-segsleft 1:23 --rt-len 42 --rt-0-res;=;OK
+-m rt --rt-type 0 ! --rt-segsleft 1:23 ! --rt-len 42 --rt-0-res;=;OK
+-m rt ! --rt-type 1 ! --rt-segsleft 12:23 ! --rt-len 42;=;OK
+-m rt;=;OK
diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c
index ff187999..a14d16f7 100644
--- a/extensions/libipt_DNAT.c
+++ b/extensions/libipt_DNAT.c
@@ -242,6 +242,51 @@ static void DNAT_save(const void *ip, const struct xt_entry_target *target)
}
}
+static void print_range_xlate(const struct nf_nat_ipv4_range *r,
+ struct xt_xlate *xl)
+{
+ if (r->flags & NF_NAT_RANGE_MAP_IPS) {
+ struct in_addr a;
+
+ a.s_addr = r->min_ip;
+ xt_xlate_add(xl, "%s", xtables_ipaddr_to_numeric(&a));
+ if (r->max_ip != r->min_ip) {
+ a.s_addr = r->max_ip;
+ xt_xlate_add(xl, "-%s", xtables_ipaddr_to_numeric(&a));
+ }
+ }
+ if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
+ xt_xlate_add(xl, ":%hu", ntohs(r->min.tcp.port));
+ if (r->max.tcp.port != r->min.tcp.port)
+ xt_xlate_add(xl, "-%hu", ntohs(r->max.tcp.port));
+ }
+}
+
+static int DNAT_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct ipt_natinfo *info = (const void *)params->target;
+ unsigned int i = 0;
+ bool sep_need = false;
+ const char *sep = " ";
+
+ for (i = 0; i < info->mr.rangesize; i++) {
+ xt_xlate_add(xl, "dnat to ");
+ print_range_xlate(&info->mr.range[i], xl);
+ if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) {
+ xt_xlate_add(xl, " random");
+ sep_need = true;
+ }
+ if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) {
+ if (sep_need)
+ sep = ",";
+ xt_xlate_add(xl, "%spersistent", sep);
+ }
+ }
+
+ return 1;
+}
+
static struct xtables_target dnat_tg_reg = {
.name = "DNAT",
.version = XTABLES_VERSION,
@@ -254,6 +299,7 @@ static struct xtables_target dnat_tg_reg = {
.print = DNAT_print,
.save = DNAT_save,
.x6_options = DNAT_opts,
+ .xlate = DNAT_xlate,
};
void _init(void)
diff --git a/extensions/libipt_DNAT.t b/extensions/libipt_DNAT.t
new file mode 100644
index 00000000..e3fd5632
--- /dev/null
+++ b/extensions/libipt_DNAT.t
@@ -0,0 +1,8 @@
+:PREROUTING
+*nat
+-j DNAT --to-destination 1.1.1.1;=;OK
+-j DNAT --to-destination 1.1.1.1-1.1.1.10;=;OK
+-p tcp -j DNAT --to-destination 1.1.1.1:1025-65535;=;OK
+-p tcp -j DNAT --to-destination 1.1.1.1-1.1.1.10:1025-65535;=;OK
+-p tcp -j DNAT --to-destination 1.1.1.1-1.1.1.10:1025-65536;;FAIL
+-j DNAT;;FAIL
diff --git a/extensions/libipt_ECN.t b/extensions/libipt_ECN.t
new file mode 100644
index 00000000..2e092052
--- /dev/null
+++ b/extensions/libipt_ECN.t
@@ -0,0 +1,5 @@
+:PREROUTING,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j ECN;;FAIL
+-p tcp -j ECN;;FAIL
+-p tcp -j ECN --ecn-tcp-remove;=;OK
diff --git a/extensions/libipt_LOG.c b/extensions/libipt_LOG.c
index 77f16d19..36e2e73b 100644
--- a/extensions/libipt_LOG.c
+++ b/extensions/libipt_LOG.c
@@ -63,6 +63,11 @@ struct ipt_log_names {
unsigned int level;
};
+struct ipt_log_xlate {
+ 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 },
@@ -166,6 +171,64 @@ static void LOG_save(const void *ip, const struct xt_entry_target *target)
printf(" --log-macdecode");
}
+static const struct ipt_log_xlate ipt_log_xlate_names[] = {
+ {"alert", LOG_ALERT },
+ {"crit", LOG_CRIT },
+ {"debug", LOG_DEBUG },
+ {"emerg", LOG_EMERG },
+ {"err", LOG_ERR },
+ {"info", LOG_INFO },
+ {"notice", LOG_NOTICE },
+ {"warn", LOG_WARNING }
+};
+
+static int LOG_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct ipt_log_info *loginfo =
+ (const struct ipt_log_info *)params->target->data;
+ unsigned int i = 0;
+
+ xt_xlate_add(xl, "log");
+ if (strcmp(loginfo->prefix, "") != 0) {
+ if (params->escape_quotes)
+ xt_xlate_add(xl, " prefix \\\"%s\\\"", loginfo->prefix);
+ else
+ xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ipt_log_xlate_names); ++i)
+ if (loginfo->level != LOG_DEFAULT_LEVEL &&
+ loginfo->level == ipt_log_xlate_names[i].level) {
+ xt_xlate_add(xl, " level %s",
+ ipt_log_xlate_names[i].name);
+ break;
+ }
+
+ if ((loginfo->logflags & IPT_LOG_MASK) == IPT_LOG_MASK) {
+ xt_xlate_add(xl, " flags all");
+ } else {
+ if (loginfo->logflags & (IPT_LOG_TCPSEQ | IPT_LOG_TCPOPT)) {
+ const char *delim = " ";
+
+ xt_xlate_add(xl, " flags tcp");
+ if (loginfo->logflags & IPT_LOG_TCPSEQ) {
+ xt_xlate_add(xl, " sequence");
+ delim = ",";
+ }
+ if (loginfo->logflags & IPT_LOG_TCPOPT)
+ xt_xlate_add(xl, "%soptions", delim);
+ }
+ if (loginfo->logflags & IPT_LOG_IPOPT)
+ xt_xlate_add(xl, " flags ip options");
+ if (loginfo->logflags & IPT_LOG_UID)
+ xt_xlate_add(xl, " flags skuid");
+ if (loginfo->logflags & IPT_LOG_MACDECODE)
+ xt_xlate_add(xl, " flags ether");
+ }
+
+ return 1;
+}
static struct xtables_target log_tg_reg = {
.name = "LOG",
.version = XTABLES_VERSION,
@@ -178,6 +241,7 @@ static struct xtables_target log_tg_reg = {
.save = LOG_save,
.x6_parse = LOG_parse,
.x6_options = LOG_opts,
+ .xlate = LOG_xlate,
};
void _init(void)
diff --git a/extensions/libipt_LOG.t b/extensions/libipt_LOG.t
new file mode 100644
index 00000000..fbf5118b
--- /dev/null
+++ b/extensions/libipt_LOG.t
@@ -0,0 +1,12 @@
+:INPUT,FORWARD,OUTPUT
+-j LOG;-j LOG;OK
+-j LOG --log-prefix "test: ";=;OK
+-j LOG --log-prefix "test: " --log-level 1;=;OK
+# iptables displays the log-level output using the number; not the string
+-j LOG --log-prefix "test: " --log-level alert;-j LOG --log-prefix "test: " --log-level 1;OK
+-j LOG --log-prefix "test: " --log-tcp-sequence;=;OK
+-j LOG --log-prefix "test: " --log-tcp-options;=;OK
+-j LOG --log-prefix "test: " --log-ip-options;=;OK
+-j LOG --log-prefix "test: " --log-uid;=;OK
+-j LOG --log-prefix "test: " --log-level bad;;FAIL
+-j LOG --log-prefix;;FAIL
diff --git a/extensions/libipt_MASQUERADE.c b/extensions/libipt_MASQUERADE.c
index ea074454..b7b5fc74 100644
--- a/extensions/libipt_MASQUERADE.c
+++ b/extensions/libipt_MASQUERADE.c
@@ -134,6 +134,28 @@ MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
printf(" --random");
}
+static int MASQUERADE_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct nf_nat_ipv4_multi_range_compat *mr =
+ (const void *)params->target->data;
+ const struct nf_nat_ipv4_range *r = &mr->range[0];
+
+ xt_xlate_add(xl, "masquerade");
+
+ if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
+ xt_xlate_add(xl, " to :%hu", ntohs(r->min.tcp.port));
+ if (r->max.tcp.port != r->min.tcp.port)
+ xt_xlate_add(xl, "-%hu", ntohs(r->max.tcp.port));
+ }
+
+ xt_xlate_add(xl, " ");
+ if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
+ xt_xlate_add(xl, "random ");
+
+ return 1;
+}
+
static struct xtables_target masquerade_tg_reg = {
.name = "MASQUERADE",
.version = XTABLES_VERSION,
@@ -146,6 +168,7 @@ static struct xtables_target masquerade_tg_reg = {
.print = MASQUERADE_print,
.save = MASQUERADE_save,
.x6_options = MASQUERADE_opts,
+ .xlate = MASQUERADE_xlate,
};
void _init(void)
diff --git a/extensions/libipt_MASQUERADE.t b/extensions/libipt_MASQUERADE.t
new file mode 100644
index 00000000..46502040
--- /dev/null
+++ b/extensions/libipt_MASQUERADE.t
@@ -0,0 +1,8 @@
+:POSTROUTING
+*nat
+-j MASQUERADE;=;OK
+-j MASQUERADE --random;=;OK
+-p tcp -j MASQUERADE --to-ports 1024;=;OK
+-p udp -j MASQUERADE --to-ports 1024-65535;=;OK
+-p udp -j MASQUERADE --to-ports 1024-65536;;FAIL
+-p udp -j MASQUERADE --to-ports -1;;FAIL
diff --git a/extensions/libipt_MIRROR.c b/extensions/libipt_MIRROR.c
deleted file mode 100644
index fb78751d..00000000
--- a/extensions/libipt_MIRROR.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/* Shared library add-on to iptables to add MIRROR target support. */
-#include <xtables.h>
-
-static struct xtables_target mirror_tg_reg = {
- .name = "MIRROR",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV4,
- .size = XT_ALIGN(0),
- .userspacesize = XT_ALIGN(0),
-};
-
-void _init(void)
-{
- xtables_register_target(&mirror_tg_reg);
-}
diff --git a/extensions/libipt_MIRROR.man b/extensions/libipt_MIRROR.man
deleted file mode 100644
index 7b720bcb..00000000
--- a/extensions/libipt_MIRROR.man
+++ /dev/null
@@ -1,12 +0,0 @@
-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/extensions/libipt_NETMAP.c b/extensions/libipt_NETMAP.c
index dee7b01b..f30615a3 100644
--- a/extensions/libipt_NETMAP.c
+++ b/extensions/libipt_NETMAP.c
@@ -62,8 +62,8 @@ static void NETMAP_parse(struct xt_option_call *cb)
range->max_ip = range->min_ip | ~cb->val.hmask.ip;
}
-static void NETMAP_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
+static void __NETMAP_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
{
const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data;
const struct nf_nat_ipv4_range *r = &mr->range[0];
@@ -80,10 +80,17 @@ static void NETMAP_print(const void *ip, const struct xt_entry_target *target,
printf("/%d", bits);
}
+static void NETMAP_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ printf(" to:");
+ __NETMAP_print(ip, target, numeric);
+}
+
static void NETMAP_save(const void *ip, const struct xt_entry_target *target)
{
printf(" --%s ", NETMAP_opts[0].name);
- NETMAP_print(ip, target, 0);
+ __NETMAP_print(ip, target, 0);
}
static struct xtables_target netmap_tg_reg = {
diff --git a/extensions/libipt_NETMAP.t b/extensions/libipt_NETMAP.t
new file mode 100644
index 00000000..31924b98
--- /dev/null
+++ b/extensions/libipt_NETMAP.t
@@ -0,0 +1,4 @@
+:PREROUTING,INPUT,OUTPUT,POSTROUTING
+*nat
+-j NETMAP --to 1.2.3.0/24;=;OK
+-j NETMAP --to 1.2.3.4;=;OK
diff --git a/extensions/libipt_REDIRECT.c b/extensions/libipt_REDIRECT.c
index 610a9499..7850306f 100644
--- a/extensions/libipt_REDIRECT.c
+++ b/extensions/libipt_REDIRECT.c
@@ -135,6 +135,24 @@ static void REDIRECT_save(const void *ip, const struct xt_entry_target *target)
}
}
+static int REDIRECT_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct nf_nat_ipv4_multi_range_compat *mr =
+ (const void *)params->target->data;
+ const struct nf_nat_ipv4_range *r = &mr->range[0];
+
+ if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
+ xt_xlate_add(xl, "redirect to :%hu", ntohs(r->min.tcp.port));
+ if (r->max.tcp.port != r->min.tcp.port)
+ xt_xlate_add(xl, "-%hu ", ntohs(r->max.tcp.port));
+ if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM)
+ xt_xlate_add(xl, " random ");
+ }
+
+ return 1;
+}
+
static struct xtables_target redirect_tg_reg = {
.name = "REDIRECT",
.version = XTABLES_VERSION,
@@ -147,6 +165,7 @@ static struct xtables_target redirect_tg_reg = {
.print = REDIRECT_print,
.save = REDIRECT_save,
.x6_options = REDIRECT_opts,
+ .xlate = REDIRECT_xlate,
};
void _init(void)
diff --git a/extensions/libipt_REDIRECT.t b/extensions/libipt_REDIRECT.t
new file mode 100644
index 00000000..a0fb0ed1
--- /dev/null
+++ b/extensions/libipt_REDIRECT.t
@@ -0,0 +1,6 @@
+:PREROUTING,OUTPUT
+*nat
+-p tcp -j REDIRECT --to-ports 42;=;OK
+-p udp -j REDIRECT --to-ports 42-1234;=;OK
+-p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK
+-j REDIRECT --to-ports 42;;FAIL
diff --git a/extensions/libipt_REJECT.c b/extensions/libipt_REJECT.c
index 362c65ed..ba815bae 100644
--- a/extensions/libipt_REJECT.c
+++ b/extensions/libipt_REJECT.c
@@ -24,6 +24,11 @@ struct reject_names {
const char *desc;
};
+struct reject_names_xlate {
+ const char *name;
+ enum ipt_reject_with with;
+};
+
enum {
O_REJECT_WITH = 0,
};
@@ -129,8 +134,8 @@ static void REJECT_print(const void *ip, const struct xt_entry_target *target,
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;
+ const struct ipt_reject_info *reject =
+ (const struct ipt_reject_info *)target->data;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(reject_table); ++i)
@@ -140,6 +145,45 @@ static void REJECT_save(const void *ip, const struct xt_entry_target *target)
printf(" --reject-with %s", reject_table[i].name);
}
+static const struct reject_names_xlate reject_table_xlate[] = {
+ {"net-unreachable", IPT_ICMP_NET_UNREACHABLE},
+ {"host-unreachable", IPT_ICMP_HOST_UNREACHABLE},
+ {"prot-unreachable", IPT_ICMP_PROT_UNREACHABLE},
+ {"port-unreachable", IPT_ICMP_PORT_UNREACHABLE},
+#if 0
+ {"echo-reply", IPT_ICMP_ECHOREPLY},
+#endif
+ {"net-prohibited", IPT_ICMP_NET_PROHIBITED},
+ {"host-prohibited", IPT_ICMP_HOST_PROHIBITED},
+ {"tcp reset", IPT_TCP_RESET},
+ {"admin-prohibited", IPT_ICMP_ADMIN_PROHIBITED}
+};
+
+static int REJECT_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct ipt_reject_info *reject =
+ (const struct ipt_reject_info *)params->target->data;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(reject_table_xlate); ++i) {
+ if (reject_table_xlate[i].with == reject->with)
+ break;
+ }
+
+ if (reject->with == IPT_ICMP_PORT_UNREACHABLE)
+ xt_xlate_add(xl, "reject");
+ else if (reject->with == IPT_TCP_RESET)
+ xt_xlate_add(xl, "reject with %s",
+ reject_table_xlate[i].name);
+ else
+ xt_xlate_add(xl, "reject with icmp type %s",
+ reject_table_xlate[i].name);
+
+ return 1;
+}
+
+
static struct xtables_target reject_tg_reg = {
.name = "REJECT",
.version = XTABLES_VERSION,
@@ -152,6 +196,7 @@ static struct xtables_target reject_tg_reg = {
.save = REJECT_save,
.x6_parse = REJECT_parse,
.x6_options = REJECT_opts,
+ .xlate = REJECT_xlate,
};
void _init(void)
diff --git a/extensions/libipt_REJECT.man b/extensions/libipt_REJECT.man
index c419a85e..8a360ce7 100644
--- a/extensions/libipt_REJECT.man
+++ b/extensions/libipt_REJECT.man
@@ -18,9 +18,9 @@ The type given can be
\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
+\fBicmp\-host\-prohibited\fP, or
+\fBicmp\-admin\-prohibited\fP (*),
+which return the appropriate ICMP error message (\fBicmp\-port\-unreachable\fP is
the default). The option
\fBtcp\-reset\fP
can be used on rules which only match the TCP protocol: this causes a
@@ -28,5 +28,5 @@ 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
+.IP
(*) Using icmp\-admin\-prohibited with kernels that do not support it will result in a plain DROP instead of REJECT
diff --git a/extensions/libipt_REJECT.t b/extensions/libipt_REJECT.t
new file mode 100644
index 00000000..5b26b107
--- /dev/null
+++ b/extensions/libipt_REJECT.t
@@ -0,0 +1,9 @@
+:INPUT,FORWARD,OUTPUT
+-j REJECT;=;OK
+-j REJECT --reject-with icmp-net-unreachable;=;OK
+-j REJECT --reject-with icmp-host-unreachable;=;OK
+-j REJECT --reject-with icmp-port-unreachable;=;OK
+-j REJECT --reject-with icmp-proto-unreachable;=;OK
+-j REJECT --reject-with icmp-net-prohibited;=;OK
+-j REJECT --reject-with icmp-host-prohibited;=;OK
+-j REJECT --reject-with icmp-admin-prohibited;=;OK
diff --git a/extensions/libipt_SAME.c b/extensions/libipt_SAME.c
deleted file mode 100644
index 5d5bf630..00000000
--- a/extensions/libipt_SAME.c
+++ /dev/null
@@ -1,186 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <xtables.h>
-#include <linux/netfilter/nf_nat.h>
-#include <linux/netfilter_ipv4/ipt_SAME.h>
-
-enum {
- O_TO_ADDR = 0,
- O_NODST,
- O_RANDOM,
- F_TO_ADDR = 1 << O_TO_ADDR,
- F_RANDOM = 1 << O_RANDOM,
-};
-
-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 xt_option_entry SAME_opts[] = {
- {.name = "to", .id = O_TO_ADDR, .type = XTTYPE_STRING,
- .flags = XTOPT_MAND},
- {.name = "nodst", .id = O_NODST, .type = XTTYPE_NONE},
- {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
- XTOPT_TABLEEND,
-};
-
-/* Parses range of IPs */
-static void parse_to(const char *orig_arg, struct nf_nat_ipv4_range *range)
-{
- char *dash, *arg;
- const struct in_addr *ip;
-
- arg = strdup(orig_arg);
- if (arg == NULL)
- xtables_error(RESOURCE_PROBLEM, "strdup");
- range->flags |= NF_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);
- free(arg);
-}
-
-static void SAME_parse(struct xt_option_call *cb)
-{
- struct ipt_same_info *mr = cb->data;
- unsigned int count;
-
- xtables_option_parse(cb);
- switch (cb->entry->id) {
- case O_TO_ADDR:
- if (mr->rangesize == IPT_SAME_MAX_RANGE)
- xtables_error(PARAMETER_PROBLEM,
- "Too many ranges specified, maximum "
- "is %i ranges.\n",
- IPT_SAME_MAX_RANGE);
- parse_to(cb->arg, &mr->range[mr->rangesize]);
- mr->rangesize++;
- break;
- case O_NODST:
- mr->info |= IPT_SAME_NODST;
- break;
- case O_RANDOM:
- for (count=0; count < mr->rangesize; count++)
- mr->range[count].flags |= NF_NAT_RANGE_PROTO_RANDOM;
- break;
- }
-}
-
-static void SAME_fcheck(struct xt_fcheck_call *cb)
-{
- static const unsigned int f = F_TO_ADDR | F_RANDOM;
- struct ipt_same_info *mr = cb->data;
- unsigned int count;
-
- if ((cb->xflags & f) == f)
- for (count = 0; count < mr->rangesize; ++count)
- mr->range[count].flags |= NF_NAT_RANGE_PROTO_RANDOM;
-}
-
-static void SAME_print(const void *ip, const struct xt_entry_target *target,
- int numeric)
-{
- unsigned int count;
- const struct ipt_same_info *mr = (const void *)target->data;
- int random_selection = 0;
-
- printf(" same:");
-
- for (count = 0; count < mr->rangesize; count++) {
- const struct nf_nat_ipv4_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("-%s", xtables_ipaddr_to_numeric(&a));
- if (r->flags & NF_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;
- const struct ipt_same_info *mr = (const void *)target->data;
- int random_selection = 0;
-
- for (count = 0; count < mr->rangesize; count++) {
- const struct nf_nat_ipv4_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("-%s", xtables_ipaddr_to_numeric(&a));
- if (r->flags & NF_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,
- .x6_parse = SAME_parse,
- .x6_fcheck = SAME_fcheck,
- .print = SAME_print,
- .save = SAME_save,
- .x6_options = SAME_opts,
-};
-
-void _init(void)
-{
- xtables_register_target(&same_tg_reg);
-}
diff --git a/extensions/libipt_SAME.man b/extensions/libipt_SAME.man
deleted file mode 100644
index a99dc73f..00000000
--- a/extensions/libipt_SAME.man
+++ /dev/null
@@ -1,17 +0,0 @@
-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.
-.PP
-N.B.: The DNAT target's \fB\-\-persistent\fP option replaced the SAME target.
-.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/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c
index 1a24f3d8..e92d811c 100644
--- a/extensions/libipt_SNAT.c
+++ b/extensions/libipt_SNAT.c
@@ -11,11 +11,13 @@
enum {
O_TO_SRC = 0,
O_RANDOM,
+ O_RANDOM_FULLY,
O_PERSISTENT,
O_X_TO_SRC,
- F_TO_SRC = 1 << O_TO_SRC,
- F_RANDOM = 1 << O_RANDOM,
- F_X_TO_SRC = 1 << O_X_TO_SRC,
+ F_TO_SRC = 1 << O_TO_SRC,
+ F_RANDOM = 1 << O_RANDOM,
+ F_RANDOM_FULLY = 1 << O_RANDOM_FULLY,
+ F_X_TO_SRC = 1 << O_X_TO_SRC,
};
/* Source NAT data consists of a multi-range, indicating where to map
@@ -32,13 +34,14 @@ static void SNAT_help(void)
"SNAT target options:\n"
" --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
" Address to map source to.\n"
-"[--random] [--persistent]\n");
+"[--random] [--random-fully] [--persistent]\n");
}
static const struct xt_option_entry SNAT_opts[] = {
{.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_MULTI},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
+ {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE},
{.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
@@ -185,10 +188,13 @@ static void SNAT_parse(struct xt_option_call *cb)
static void SNAT_fcheck(struct xt_fcheck_call *cb)
{
static const unsigned int f = F_TO_SRC | F_RANDOM;
+ static const unsigned int r = F_TO_SRC | F_RANDOM_FULLY;
struct nf_nat_ipv4_multi_range_compat *mr = cb->data;
if ((cb->xflags & f) == f)
mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM;
+ if ((cb->xflags & r) == r)
+ mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY;
}
static void print_range(const struct nf_nat_ipv4_range *r)
@@ -222,6 +228,8 @@ static void SNAT_print(const void *ip, const struct xt_entry_target *target,
print_range(&info->mr.range[i]);
if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" random");
+ if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+ printf(" random-fully");
if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
printf(" persistent");
}
@@ -237,11 +245,65 @@ static void SNAT_save(const void *ip, const struct xt_entry_target *target)
print_range(&info->mr.range[i]);
if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
+ if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+ printf(" --random-fully");
if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT)
printf(" --persistent");
}
}
+static void print_range_xlate(const struct nf_nat_ipv4_range *r,
+ struct xt_xlate *xl)
+{
+ if (r->flags & NF_NAT_RANGE_MAP_IPS) {
+ struct in_addr a;
+
+ a.s_addr = r->min_ip;
+ xt_xlate_add(xl, "%s", xtables_ipaddr_to_numeric(&a));
+ if (r->max_ip != r->min_ip) {
+ a.s_addr = r->max_ip;
+ xt_xlate_add(xl, "-%s", xtables_ipaddr_to_numeric(&a));
+ }
+ }
+ if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
+ xt_xlate_add(xl, ":");
+ xt_xlate_add(xl, "%hu", ntohs(r->min.tcp.port));
+ if (r->max.tcp.port != r->min.tcp.port)
+ xt_xlate_add(xl, "-%hu", ntohs(r->max.tcp.port));
+ }
+}
+
+static int SNAT_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct ipt_natinfo *info = (const void *)params->target;
+ unsigned int i = 0;
+ bool sep_need = false;
+ const char *sep = " ";
+
+ for (i = 0; i < info->mr.rangesize; i++) {
+ xt_xlate_add(xl, "snat to ");
+ print_range_xlate(&info->mr.range[i], xl);
+ if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) {
+ xt_xlate_add(xl, " random");
+ sep_need = true;
+ }
+ if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
+ if (sep_need)
+ sep = ",";
+ xt_xlate_add(xl, "%sfully-random", sep);
+ sep_need = true;
+ }
+ if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) {
+ if (sep_need)
+ sep = ",";
+ xt_xlate_add(xl, "%spersistent", sep);
+ }
+ }
+
+ return 1;
+}
+
static struct xtables_target snat_tg_reg = {
.name = "SNAT",
.version = XTABLES_VERSION,
@@ -254,6 +316,7 @@ static struct xtables_target snat_tg_reg = {
.print = SNAT_print,
.save = SNAT_save,
.x6_options = SNAT_opts,
+ .xlate = SNAT_xlate,
};
void _init(void)
diff --git a/extensions/libipt_SNAT.t b/extensions/libipt_SNAT.t
new file mode 100644
index 00000000..73071bb0
--- /dev/null
+++ b/extensions/libipt_SNAT.t
@@ -0,0 +1,8 @@
+:POSTROUTING
+*nat
+-j SNAT --to-source 1.1.1.1;=;OK
+-j SNAT --to-source 1.1.1.1-1.1.1.10;=;OK
+-p tcp -j SNAT --to-source 1.1.1.1:1025-65535;=;OK
+-p tcp -j SNAT --to-source 1.1.1.1-1.1.1.10:1025-65535;=;OK
+-p tcp -j SNAT --to-source 1.1.1.1-1.1.1.10:1025-65536;;FAIL
+-j SNAT;;FAIL
diff --git a/extensions/libipt_TTL.t b/extensions/libipt_TTL.t
new file mode 100644
index 00000000..36809792
--- /dev/null
+++ b/extensions/libipt_TTL.t
@@ -0,0 +1,10 @@
+:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j TTL --ttl-set 42;=;OK
+-j TTL --ttl-inc 1;=;OK
+-j TTL --ttl-dec 1;=;OK
+-j TTL --ttl-set 256;;FAIL
+-j TTL --ttl-inc 0;;FAIL
+-j TTL --ttl-dec 0;;FAIL
+-j TTL --ttl-dec 1 --ttl-inc 1;;FAIL
+-j TTL --ttl-set --ttl-inc 1;;FAIL
diff --git a/extensions/libipt_ULOG.t b/extensions/libipt_ULOG.t
new file mode 100644
index 00000000..97500b00
--- /dev/null
+++ b/extensions/libipt_ULOG.t
@@ -0,0 +1,19 @@
+:INPUT,FORWARD,OUTPUT
+-j ULOG --ulog-nlgroup 1;-j ULOG;OK
+-j ULOG --ulog-nlgroup 32;=;OK
+-j ULOG --ulog-nlgroup 33;;FAIL
+-j ULOG --ulog-nlgroup 0;;FAIL
+-j ULOG --ulog-cprange 1;=;OK
+-j ULOG --ulog-cprange 4294967295;=;OK
+# This below outputs 0 in iptables-save
+# ERROR: should fail: iptables -A INPUT -j ULOG --ulog-cprange 4294967296
+#-j ULOG --ulog-cprange 4294967296;;FAIL
+# supports up to 31 characters
+-j ULOG --ulog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
+# ERROR: should fail: iptables -A INPUT -j ULOG --ulog-prefix xxxxxx [...]
+#-j ULOG --ulog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;;FAIL
+-j ULOG --ulog-qthreshold 1;-j ULOG;OK
+-j ULOG --ulog-qthreshold 0;;FAIL
+-j ULOG --ulog-qthreshold 50;=;OK
+-j ULOG --ulog-qthreshold 51;;FAIL
+-j ULOG;=;OK
diff --git a/extensions/libipt_ah.c b/extensions/libipt_ah.c
index 8cf167c4..fec5705c 100644
--- a/extensions/libipt_ah.c
+++ b/extensions/libipt_ah.c
@@ -21,6 +21,13 @@ static const struct xt_option_entry ah_opts[] = {
XTOPT_TABLEEND,
};
+static void ah_init(struct xt_entry_match *m)
+{
+ struct ipt_ah *ahinfo = (void *)m->data;
+
+ ahinfo->spis[1] = ~0U;
+}
+
static void ah_parse(struct xt_option_call *cb)
{
struct ipt_ah *ahinfo = cb->data;
@@ -85,17 +92,37 @@ static void ah_save(const void *ip, const struct xt_entry_match *match)
}
+static int ah_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct ipt_ah *ahinfo = (struct ipt_ah *)params->match->data;
+
+ if (!(ahinfo->spis[0] == 0 && ahinfo->spis[1] == 0xFFFFFFFF)) {
+ xt_xlate_add(xl, "ah spi%s ",
+ (ahinfo->invflags & IPT_AH_INV_SPI) ? " !=" : "");
+ if (ahinfo->spis[0] != ahinfo->spis[1])
+ xt_xlate_add(xl, "%u-%u", ahinfo->spis[0],
+ ahinfo->spis[1]);
+ else
+ xt_xlate_add(xl, "%u", ahinfo->spis[0]);
+ }
+
+ return 1;
+}
+
static struct xtables_match ah_mt_reg = {
- .name = "ah",
- .version = XTABLES_VERSION,
+ .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,
- .print = ah_print,
- .save = ah_save,
+ .userspacesize = XT_ALIGN(sizeof(struct ipt_ah)),
+ .help = ah_help,
+ .init = ah_init,
+ .print = ah_print,
+ .save = ah_save,
.x6_parse = ah_parse,
.x6_options = ah_opts,
+ .xlate = ah_xlate,
};
void
diff --git a/extensions/libipt_ah.t b/extensions/libipt_ah.t
new file mode 100644
index 00000000..cd853865
--- /dev/null
+++ b/extensions/libipt_ah.t
@@ -0,0 +1,13 @@
+:INPUT,FORWARD,OUTPUT
+-p ah -m ah --ahspi 0;=;OK
+-p ah -m ah --ahspi 4294967295;=;OK
+-p ah -m ah --ahspi 0:4294967295;-p ah -m ah;OK
+-p ah -m ah ! --ahspi 0;=;OK
+-p ah -m ah --ahspi -1;;FAIL
+-p ah -m ah --ahspi 4294967296;;FAIL
+-p ah -m ah --ahspi invalid;;FAIL
+-p ah -m ah --ahspi 0:invalid;;FAIL
+-m ah --ahspi 0;;FAIL
+-m ah --ahspi;;FAIL
+-m ah;;FAIL
+-p ah -m ah;=;OK
diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c
index 666e7daf..680a5b0c 100644
--- a/extensions/libipt_icmp.c
+++ b/extensions/libipt_icmp.c
@@ -249,6 +249,41 @@ static void icmp_save(const void *ip, const struct xt_entry_match *match)
}
}
+static unsigned int type_xlate_print(struct xt_xlate *xl, unsigned int icmptype,
+ unsigned int code_min,
+ unsigned int code_max)
+{
+ unsigned int i;
+
+ if (code_min != code_max) {
+ for (i = 0; i < ARRAY_SIZE(icmp_codes); ++i)
+ if (icmp_codes[i].type == icmptype &&
+ icmp_codes[i].code_min == code_min &&
+ icmp_codes[i].code_max == code_max) {
+ xt_xlate_add(xl, icmp_codes[i].name);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int icmp_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct ipt_icmp *info = (struct ipt_icmp *)params->match->data;
+
+ if (info->type != 0xFF) {
+ xt_xlate_add(xl, "icmp type%s ",
+ (info->invflags & IPT_ICMP_INV) ? " !=" : "");
+
+ if (!type_xlate_print(xl, info->type, info->code[0],
+ info->code[1]))
+ return 0;
+ }
+ return 1;
+}
+
static struct xtables_match icmp_mt_reg = {
.name = "icmp",
.version = XTABLES_VERSION,
@@ -261,6 +296,7 @@ static struct xtables_match icmp_mt_reg = {
.save = icmp_save,
.x6_parse = icmp_parse,
.x6_options = icmp_opts,
+ .xlate = icmp_xlate,
};
void _init(void)
diff --git a/extensions/libipt_icmp.t b/extensions/libipt_icmp.t
new file mode 100644
index 00000000..f4ba65c2
--- /dev/null
+++ b/extensions/libipt_icmp.t
@@ -0,0 +1,15 @@
+:INPUT,FORWARD,OUTPUT
+-p icmp -m icmp --icmp-type any;=;OK
+# output uses the number, better use the name?
+# ERROR: cannot find: iptables -I INPUT -p icmp -m icmp --icmp-type echo-reply
+# -p icmp -m icmp --icmp-type echo-reply;=;OK
+# output uses the number, better use the name?
+# ERROR: annot find: iptables -I INPUT -p icmp -m icmp --icmp-type destination-unreachable
+# -p icmp -m icmp --icmp-type destination-unreachable;=;OK
+# it does not acccept name/name, should we accept this?
+# ERROR: cannot load: iptables -A INPUT -p icmp -m icmp --icmp-type destination-unreachable/network-unreachable
+# -p icmp -m icmp --icmp-type destination-unreachable/network-unreachable;=;OK
+-m icmp;;FAIL
+# we accept "iptables -I INPUT -p tcp -m tcp", why not this below?
+# ERROR: cannot load: iptables -A INPUT -p icmp -m icmp
+# -p icmp -m icmp;=;OK
diff --git a/extensions/libipt_realm.c b/extensions/libipt_realm.c
index a8d9dda0..8eea7874 100644
--- a/extensions/libipt_realm.c
+++ b/extensions/libipt_realm.c
@@ -34,6 +34,7 @@ static struct xtables_lmap *realms;
static void realm_init(struct xt_entry_match *m)
{
const char file[] = "/etc/iproute2/rt_realms";
+
realms = xtables_lmap_init(file);
if (realms == NULL && errno != ENOENT)
fprintf(stderr, "Warning: %s: %s\n", file, strerror(errno));
@@ -70,7 +71,7 @@ static void realm_parse(struct xt_option_call *cb)
static void
print_realm(unsigned long id, unsigned long mask, int numeric)
{
- const char* name = NULL;
+ const char *name = NULL;
if (mask != 0xffffffff)
printf(" 0x%lx/0x%lx", id, mask);
@@ -85,7 +86,7 @@ print_realm(unsigned long id, unsigned long mask, int numeric)
}
static void realm_print(const void *ip, const struct xt_entry_match *match,
- int numeric)
+ int numeric)
{
const struct xt_realm_info *ri = (const void *)match->data;
@@ -107,6 +108,42 @@ static void realm_save(const void *ip, const struct xt_entry_match *match)
print_realm(ri->id, ri->mask, 0);
}
+static void
+print_realm_xlate(unsigned long id, unsigned long mask,
+ int numeric, struct xt_xlate *xl, uint32_t op)
+{
+ const char *name = NULL;
+
+ if (mask != 0xffffffff)
+ xt_xlate_add(xl, " and 0x%lx %s 0x%lx", mask,
+ op == XT_OP_EQ ? "==" : "!=", id);
+ else {
+ if (numeric == 0)
+ name = xtables_lmap_id2name(realms, id);
+ if (name)
+ xt_xlate_add(xl, " %s%s",
+ op == XT_OP_EQ ? "" : "!= ", name);
+ else
+ xt_xlate_add(xl, " %s0x%lx",
+ op == XT_OP_EQ ? "" : "!= ", id);
+ }
+}
+
+static int realm_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_realm_info *ri = (const void *)params->match->data;
+ enum xt_op op = XT_OP_EQ;
+
+ if (ri->invert)
+ op = XT_OP_NEQ;
+
+ xt_xlate_add(xl, "rtclassid");
+ print_realm_xlate(ri->id, ri->mask, 0, xl, op);
+
+ return 1;
+}
+
static struct xtables_match realm_mt_reg = {
.name = "realm",
.version = XTABLES_VERSION,
@@ -119,6 +156,7 @@ static struct xtables_match realm_mt_reg = {
.save = realm_save,
.x6_parse = realm_parse,
.x6_options = realm_opts,
+ .xlate = realm_xlate,
};
void _init(void)
diff --git a/extensions/libipt_realm.t b/extensions/libipt_realm.t
new file mode 100644
index 00000000..ca666407
--- /dev/null
+++ b/extensions/libipt_realm.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+-m realm --realm 0x1/0x2a;=;OK
+-m realm --realm 0x2a;=;OK
+-m realm;;FAIL
diff --git a/extensions/libipt_ttl.c b/extensions/libipt_ttl.c
index 5fe08ccd..6bdd2196 100644
--- a/extensions/libipt_ttl.c
+++ b/extensions/libipt_ttl.c
@@ -100,6 +100,35 @@ static void ttl_save(const void *ip, const struct xt_entry_match *match)
printf(" %u", info->ttl);
}
+static int ttl_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct ipt_ttl_info *info =
+ (struct ipt_ttl_info *) params->match->data;
+
+ switch (info->mode) {
+ case IPT_TTL_EQ:
+ xt_xlate_add(xl, "ip ttl");
+ break;
+ case IPT_TTL_NE:
+ xt_xlate_add(xl, "ip ttl !=");
+ break;
+ case IPT_TTL_LT:
+ xt_xlate_add(xl, "ip ttl lt");
+ break;
+ case IPT_TTL_GT:
+ xt_xlate_add(xl, "ip ttl gt");
+ break;
+ default:
+ /* Should not happen. */
+ break;
+ }
+
+ xt_xlate_add(xl, " %u", info->ttl);
+
+ return 1;
+}
+
#define s struct ipt_ttl_info
static const struct xt_option_entry ttl_opts[] = {
{.name = "ttl-lt", .id = O_TTL_LT, .excl = F_ANY, .type = XTTYPE_UINT8,
@@ -126,6 +155,7 @@ static struct xtables_match ttl_mt_reg = {
.x6_parse = ttl_parse,
.x6_fcheck = ttl_check,
.x6_options = ttl_opts,
+ .xlate = ttl_xlate,
};
diff --git a/extensions/libipt_ttl.t b/extensions/libipt_ttl.t
new file mode 100644
index 00000000..ebe5b3a2
--- /dev/null
+++ b/extensions/libipt_ttl.t
@@ -0,0 +1,15 @@
+:INPUT,FORWARD,OUTPUT
+-m ttl --ttl-eq 0;=;OK
+-m ttl --ttl-eq 255;=;OK
+-m ttl ! --ttl-eq 0;=;OK
+-m ttl ! --ttl-eq 255;=;OK
+-m ttl --ttl-gt 0;=;OK
+# not possible have anything greater than 255, TTL is 8-bit long
+# ERROR: should fail: iptables -A INPUT -m ttl --ttl-gt 255
+## -m ttl --ttl-gt 255;;FAIL
+# not possible have anything below 0
+# ERROR: should fail: iptables -A INPUT -m ttl --ttl-lt 0
+## -m ttl --ttl-lt 0;;FAIL
+-m ttl --ttl-eq 256;;FAIL
+-m ttl --ttl-eq -1;;FAIL
+-m ttl;;FAIL
diff --git a/extensions/libipt_unclean.c b/extensions/libipt_unclean.c
deleted file mode 100644
index bc4a4a08..00000000
--- a/extensions/libipt_unclean.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/* Shared library add-on to iptables for unclean. */
-#include <xtables.h>
-
-static struct xtables_match unclean_mt_reg = {
- .name = "unclean",
- .version = XTABLES_VERSION,
- .family = NFPROTO_IPV4,
- .size = XT_ALIGN(0),
- .userspacesize = XT_ALIGN(0),
-};
-
-void _init(void)
-{
- xtables_register_match(&unclean_mt_reg);
-}
diff --git a/extensions/libipt_unclean.man b/extensions/libipt_unclean.man
deleted file mode 100644
index 3fecd554..00000000
--- a/extensions/libipt_unclean.man
+++ /dev/null
@@ -1,2 +0,0 @@
-This module takes no options, but attempts to match packets which seem
-malformed or unusual. This is regarded as experimental.
diff --git a/extensions/libxt_AUDIT.t b/extensions/libxt_AUDIT.t
new file mode 100644
index 00000000..97575b0e
--- /dev/null
+++ b/extensions/libxt_AUDIT.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-j AUDIT --type accept;=;OK
+-j AUDIT --type drop;=;OK
+-j AUDIT --type reject;=;OK
+-j AUDIT;;FAIL
+-j AUDIT --type wrong;;FAIL
diff --git a/extensions/libxt_CHECKSUM.t b/extensions/libxt_CHECKSUM.t
new file mode 100644
index 00000000..9451ad86
--- /dev/null
+++ b/extensions/libxt_CHECKSUM.t
@@ -0,0 +1,4 @@
+:PREROUTING,FORWARD,POSTROUTING
+*mangle
+-j CHECKSUM --checksum-fill;=;OK
+-j CHECKSUM;;FAIL
diff --git a/extensions/libxt_CLASSIFY.c b/extensions/libxt_CLASSIFY.c
index e04657ae..ba88f758 100644
--- a/extensions/libxt_CLASSIFY.c
+++ b/extensions/libxt_CLASSIFY.c
@@ -73,20 +73,67 @@ CLASSIFY_save(const void *ip, const struct xt_entry_target *target)
TC_H_MAJ(clinfo->priority)>>16, TC_H_MIN(clinfo->priority));
}
-static struct xtables_target classify_target = {
- .family = NFPROTO_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,
- .print = CLASSIFY_print,
- .save = CLASSIFY_save,
- .x6_parse = CLASSIFY_parse,
- .x6_options = CLASSIFY_opts,
+static void
+arpCLASSIFY_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ CLASSIFY_save(ip, target);
+}
+
+static int CLASSIFY_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_classify_target_info *clinfo =
+ (const struct xt_classify_target_info *)params->target->data;
+ __u32 handle = clinfo->priority;
+
+ xt_xlate_add(xl, "meta priority set ");
+
+ switch (handle) {
+ case TC_H_ROOT:
+ xt_xlate_add(xl, "root");
+ break;
+ case TC_H_UNSPEC:
+ xt_xlate_add(xl, "none");
+ break;
+ default:
+ xt_xlate_add(xl, "%0x:%0x", TC_H_MAJ(handle) >> 16,
+ TC_H_MIN(handle));
+ break;
+ }
+
+ return 1;
+}
+
+static struct xtables_target classify_target[] = {
+ {
+ .family = NFPROTO_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,
+ .print = CLASSIFY_print,
+ .save = CLASSIFY_save,
+ .x6_parse = CLASSIFY_parse,
+ .x6_options = CLASSIFY_opts,
+ .xlate = CLASSIFY_xlate,
+ },
+ {
+ .family = NFPROTO_ARP,
+ .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,
+ .print = arpCLASSIFY_print,
+ .x6_parse = CLASSIFY_parse,
+ .x6_options = CLASSIFY_opts,
+ .xlate = CLASSIFY_xlate,
+ },
};
void _init(void)
{
- xtables_register_target(&classify_target);
+ xtables_register_targets(classify_target, ARRAY_SIZE(classify_target));
}
diff --git a/extensions/libxt_CLASSIFY.t b/extensions/libxt_CLASSIFY.t
new file mode 100644
index 00000000..7b3ddbf7
--- /dev/null
+++ b/extensions/libxt_CLASSIFY.t
@@ -0,0 +1,9 @@
+:FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j CLASSIFY --set-class 0000:ffff;=;OK
+# maximum handle accepted by tc is 0xffff
+# ERROR : should fail: iptables -A FORWARD -t mangle -j CLASSIFY --set-class 0000:ffffffff
+# -j CLASSIFY --set-class 0000:ffffffff;;FAIL
+# ERROR: should fail: iptables -A FORWARD -t mangle -j CLASSIFY --set-class 1:-1
+# -j CLASSIFY --set-class 1:-1;;FAIL
+-j CLASSIFY;;FAIL
diff --git a/extensions/libxt_CONNMARK.c b/extensions/libxt_CONNMARK.c
index 5d5351e3..f60be583 100644
--- a/extensions/libxt_CONNMARK.c
+++ b/extensions/libxt_CONNMARK.c
@@ -17,7 +17,7 @@
*
* 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdbool.h>
#include <stdint.h>
@@ -347,6 +347,50 @@ connmark_tg_save(const void *ip, const struct xt_entry_target *target)
}
}
+static int connmark_tg_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_connmark_tginfo1 *info =
+ (const void *)params->target->data;
+
+ switch (info->mode) {
+ case XT_CONNMARK_SET:
+ xt_xlate_add(xl, "ct mark set ");
+ if (info->ctmark == 0)
+ xt_xlate_add(xl, "ct mark and 0x%x", ~info->ctmask);
+ else if (info->ctmark == info->ctmask)
+ xt_xlate_add(xl, "ct mark or 0x%x",
+ info->ctmark);
+ else if (info->ctmask == 0)
+ xt_xlate_add(xl, "ct mark xor 0x%x",
+ info->ctmark);
+ else if (info->ctmask == 0xFFFFFFFFU)
+ xt_xlate_add(xl, "0x%x ", info->ctmark);
+ else
+ xt_xlate_add(xl, "ct mark xor 0x%x and 0x%x",
+ info->ctmark, ~info->ctmask);
+ break;
+ case XT_CONNMARK_SAVE:
+ xt_xlate_add(xl, "ct mark set mark");
+ if (!(info->nfmask == UINT32_MAX &&
+ info->ctmask == UINT32_MAX)) {
+ if (info->nfmask == info->ctmask)
+ xt_xlate_add(xl, " and 0x%x", info->nfmask);
+ }
+ break;
+ case XT_CONNMARK_RESTORE:
+ xt_xlate_add(xl, "meta mark set ct mark");
+ if (!(info->nfmask == UINT32_MAX &&
+ info->ctmask == UINT32_MAX)) {
+ if (info->nfmask == info->ctmask)
+ xt_xlate_add(xl, " and 0x%x", info->nfmask);
+ }
+ break;
+ }
+
+ return 1;
+}
+
static struct xtables_target connmark_tg_reg[] = {
{
.family = NFPROTO_UNSPEC,
@@ -377,6 +421,7 @@ static struct xtables_target connmark_tg_reg[] = {
.x6_parse = connmark_tg_parse,
.x6_fcheck = connmark_tg_check,
.x6_options = connmark_tg_opts,
+ .xlate = connmark_tg_xlate,
},
};
diff --git a/extensions/libxt_CONNMARK.t b/extensions/libxt_CONNMARK.t
new file mode 100644
index 00000000..79a838fe
--- /dev/null
+++ b/extensions/libxt_CONNMARK.t
@@ -0,0 +1,7 @@
+:PREROUTING,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j CONNMARK --restore-mark;=;OK
+-j CONNMARK --save-mark;=;OK
+-j CONNMARK --save-mark --nfmask 0xfffffff --ctmask 0xffffffff;-j CONNMARK --save-mark;OK
+-j CONNMARK --restore-mark --nfmask 0xfffffff --ctmask 0xffffffff;-j CONNMARK --restore-mark;OK
+-j CONNMARK;;FAIL
diff --git a/extensions/libxt_CONNSECMARK.t b/extensions/libxt_CONNSECMARK.t
new file mode 100644
index 00000000..2751b255
--- /dev/null
+++ b/extensions/libxt_CONNSECMARK.t
@@ -0,0 +1,5 @@
+:PREROUTING,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j CONNSECMARK --restore;=;OK
+-j CONNSECMARK --save;=;OK
+-j CONNSECMARK;;FAIL
diff --git a/extensions/libxt_CT.c b/extensions/libxt_CT.c
index 6b28fe1b..371b2176 100644
--- a/extensions/libxt_CT.c
+++ b/extensions/libxt_CT.c
@@ -16,7 +16,9 @@ static void ct_help(void)
" --helper name Use conntrack helper 'name' for connection\n"
" --ctevents event[,event...] Generate specified conntrack events for connection\n"
" --expevents event[,event...] Generate specified expectation events for connection\n"
-" --zone ID Assign/Lookup connection in zone ID\n"
+" --zone {ID|mark} Assign/Lookup connection in zone ID/packet nfmark\n"
+" --zone-orig {ID|mark} Same as 'zone' option, but only applies to ORIGINAL direction\n"
+" --zone-reply {ID|mark} Same as 'zone' option, but only applies to REPLY direction\n"
);
}
@@ -29,7 +31,9 @@ static void ct_help_v1(void)
" --timeout name Use timeout policy 'name' for connection\n"
" --ctevents event[,event...] Generate specified conntrack events for connection\n"
" --expevents event[,event...] Generate specified expectation events for connection\n"
-" --zone ID Assign/Lookup connection in zone ID\n"
+" --zone {ID|mark} Assign/Lookup connection in zone ID/packet nfmark\n"
+" --zone-orig {ID|mark} Same as 'zone' option, but only applies to ORIGINAL direction\n"
+" --zone-reply {ID|mark} Same as 'zone' option, but only applies to REPLY direction\n"
);
}
@@ -40,6 +44,8 @@ enum {
O_CTEVENTS,
O_EXPEVENTS,
O_ZONE,
+ O_ZONE_ORIG,
+ O_ZONE_REPLY,
};
#define s struct xt_ct_target_info
@@ -49,8 +55,9 @@ static const struct xt_option_entry ct_opts[] = {
.flags = XTOPT_PUT, XTOPT_POINTER(s, helper)},
{.name = "ctevents", .id = O_CTEVENTS, .type = XTTYPE_STRING},
{.name = "expevents", .id = O_EXPEVENTS, .type = XTTYPE_STRING},
- {.name = "zone", .id = O_ZONE, .type = XTTYPE_UINT16,
- .flags = XTOPT_PUT, XTOPT_POINTER(s, zone)},
+ {.name = "zone-orig", .id = O_ZONE_ORIG, .type = XTTYPE_STRING},
+ {.name = "zone-reply", .id = O_ZONE_REPLY, .type = XTTYPE_STRING},
+ {.name = "zone", .id = O_ZONE, .type = XTTYPE_STRING},
XTOPT_TABLEEND,
};
#undef s
@@ -64,8 +71,9 @@ static const struct xt_option_entry ct_opts_v1[] = {
.flags = XTOPT_PUT, XTOPT_POINTER(s, timeout)},
{.name = "ctevents", .id = O_CTEVENTS, .type = XTTYPE_STRING},
{.name = "expevents", .id = O_EXPEVENTS, .type = XTTYPE_STRING},
- {.name = "zone", .id = O_ZONE, .type = XTTYPE_UINT16,
- .flags = XTOPT_PUT, XTOPT_POINTER(s, zone)},
+ {.name = "zone-orig", .id = O_ZONE_ORIG, .type = XTTYPE_STRING},
+ {.name = "zone-reply", .id = O_ZONE_REPLY, .type = XTTYPE_STRING},
+ {.name = "zone", .id = O_ZONE, .type = XTTYPE_STRING},
XTOPT_TABLEEND,
};
#undef s
@@ -92,6 +100,45 @@ static const struct event_tbl exp_event_tbl[] = {
{ "new", IPEXP_NEW },
};
+static void ct_parse_zone_id(const char *opt, unsigned int opt_id,
+ uint16_t *zone_id, uint16_t *flags)
+{
+ if (opt_id == O_ZONE_ORIG)
+ *flags |= XT_CT_ZONE_DIR_ORIG;
+ if (opt_id == O_ZONE_REPLY)
+ *flags |= XT_CT_ZONE_DIR_REPL;
+
+ *zone_id = 0;
+
+ if (strcasecmp(opt, "mark") == 0) {
+ *flags |= XT_CT_ZONE_MARK;
+ } else {
+ uintmax_t val;
+
+ if (!xtables_strtoul(opt, NULL, &val, 0, UINT16_MAX))
+ xtables_error(PARAMETER_PROBLEM,
+ "Cannot parse %s as a zone ID\n", opt);
+
+ *zone_id = (uint16_t)val;
+ }
+}
+
+static void ct_print_zone_id(const char *pfx, uint16_t zone_id, uint16_t flags)
+{
+ printf(" %s", pfx);
+
+ if ((flags & (XT_CT_ZONE_DIR_ORIG |
+ XT_CT_ZONE_DIR_REPL)) == XT_CT_ZONE_DIR_ORIG)
+ printf("-orig");
+ if ((flags & (XT_CT_ZONE_DIR_ORIG |
+ XT_CT_ZONE_DIR_REPL)) == XT_CT_ZONE_DIR_REPL)
+ printf("-reply");
+ if (flags & XT_CT_ZONE_MARK)
+ printf(" mark");
+ else
+ printf(" %u", zone_id);
+}
+
static uint32_t ct_parse_events(const struct event_tbl *tbl, unsigned int size,
const char *events)
{
@@ -138,6 +185,12 @@ static void ct_parse(struct xt_option_call *cb)
case O_NOTRACK:
info->flags |= XT_CT_NOTRACK;
break;
+ case O_ZONE_ORIG:
+ case O_ZONE_REPLY:
+ case O_ZONE:
+ ct_parse_zone_id(cb->arg, cb->entry->id, &info->zone,
+ &info->flags);
+ break;
case O_CTEVENTS:
info->ct_events = ct_parse_events(ct_event_tbl, ARRAY_SIZE(ct_event_tbl), cb->arg);
break;
@@ -156,6 +209,12 @@ static void ct_parse_v1(struct xt_option_call *cb)
case O_NOTRACK:
info->flags |= XT_CT_NOTRACK;
break;
+ case O_ZONE_ORIG:
+ case O_ZONE_REPLY:
+ case O_ZONE:
+ ct_parse_zone_id(cb->arg, cb->entry->id, &info->zone,
+ &info->flags);
+ break;
case O_CTEVENTS:
info->ct_events = ct_parse_events(ct_event_tbl,
ARRAY_SIZE(ct_event_tbl),
@@ -185,8 +244,8 @@ static void ct_print(const void *ip, const struct xt_entry_target *target, int n
if (info->exp_events)
ct_print_events("expevents", exp_event_tbl,
ARRAY_SIZE(exp_event_tbl), info->exp_events);
- if (info->zone)
- printf("zone %u ", info->zone);
+ if (info->flags & XT_CT_ZONE_MARK || info->zone)
+ ct_print_zone_id("zone", info->zone, info->flags);
}
static void
@@ -212,8 +271,8 @@ ct_print_v1(const void *ip, const struct xt_entry_target *target, int numeric)
if (info->exp_events)
ct_print_events("expevents", exp_event_tbl,
ARRAY_SIZE(exp_event_tbl), info->exp_events);
- if (info->zone)
- printf("zone %u ", info->zone);
+ if (info->flags & XT_CT_ZONE_MARK || info->zone)
+ ct_print_zone_id("zone", info->zone, info->flags);
}
static void ct_save(const void *ip, const struct xt_entry_target *target)
@@ -233,8 +292,8 @@ static void ct_save(const void *ip, const struct xt_entry_target *target)
if (info->exp_events)
ct_print_events("--expevents", exp_event_tbl,
ARRAY_SIZE(exp_event_tbl), info->exp_events);
- if (info->zone)
- printf(" --zone %u", info->zone);
+ if (info->flags & XT_CT_ZONE_MARK || info->zone)
+ ct_print_zone_id("--zone", info->zone, info->flags);
}
static void ct_save_v1(const void *ip, const struct xt_entry_target *target)
@@ -256,8 +315,8 @@ static void ct_save_v1(const void *ip, const struct xt_entry_target *target)
if (info->exp_events)
ct_print_events("--expevents", exp_event_tbl,
ARRAY_SIZE(exp_event_tbl), info->exp_events);
- if (info->zone)
- printf(" --zone %u", info->zone);
+ if (info->flags & XT_CT_ZONE_MARK || info->zone)
+ ct_print_zone_id("--zone", info->zone, info->flags);
}
static const char *
diff --git a/extensions/libxt_CT.man b/extensions/libxt_CT.man
index a93eb149..e992120a 100644
--- a/extensions/libxt_CT.man
+++ b/extensions/libxt_CT.man
@@ -20,9 +20,21 @@ the ctmark, not nfmark), \fBnatseqinfo\fP, \fBsecmark\fP (ctsecmark).
Only generate the specified expectation events for this connection.
Possible event types are: \fBnew\fP.
.TP
-\fB\-\-zone\fP \fIid\fP
+\fB\-\-zone-orig\fP {\fIid\fP|\fBmark\fP}
+For traffic coming from ORIGINAL direction, assign this packet to zone
+\fIid\fP and only have lookups done in that zone. If \fBmark\fP is used
+instead of \fIid\fP, the zone is derived from the packet nfmark.
+.TP
+\fB\-\-zone-reply\fP {\fIid\fP|\fBmark\fP}
+For traffic coming from REPLY direction, assign this packet to zone
+\fIid\fP and only have lookups done in that zone. If \fBmark\fP is used
+instead of \fIid\fP, the zone is derived from the packet nfmark.
+.TP
+\fB\-\-zone\fP {\fIid\fP|\fBmark\fP}
Assign this packet to zone \fIid\fP and only have lookups done in that zone.
-By default, packets have zone 0.
+If \fBmark\fP is used instead of \fIid\fP, the zone is derived from the
+packet nfmark. By default, packets have zone 0. This option applies to both
+directions.
.TP
\fB\-\-timeout\fP \fIname\fP
Use the timeout policy identified by \fIname\fP for the connection. This is
diff --git a/extensions/libxt_CT.t b/extensions/libxt_CT.t
new file mode 100644
index 00000000..3c28534e
--- /dev/null
+++ b/extensions/libxt_CT.t
@@ -0,0 +1,20 @@
+:PREROUTING,OUTPUT
+*raw
+-j CT --notrack;=;OK
+-j CT --ctevents new,related,destroy,reply,assured,protoinfo,helper,mark;=;OK
+-j CT --expevents new;=;OK
+# ERROR: cannot find: iptables -I PREROUTING -t raw -j CT --zone 0
+# -j CT --zone 0;=;OK
+-j CT --zone 65535;=;OK
+-j CT --zone 65536;;FAIL
+-j CT --zone -1;;FAIL
+# ERROR: should fail: iptables -A PREROUTING -t raw -j CT
+# -j CT;;FAIL
+@nfct timeout add test inet tcp ESTABLISHED 100
+# cannot load: iptables -A PREROUTING -t raw -j CT --timeout test
+# -j CT --timeout test;=;OK
+@nfct timeout del test
+@nfct helper add rpc inet tcp
+# cannot load: iptables -A PREROUTING -t raw -j CT --helper rpc
+# -j CT --helper rpc;=;OK
+@nfct helper del rpc
diff --git a/extensions/libxt_DSCP.c b/extensions/libxt_DSCP.c
index e16e93c4..cae0d830 100644
--- a/extensions/libxt_DSCP.c
+++ b/extensions/libxt_DSCP.c
@@ -92,21 +92,59 @@ static void DSCP_save(const void *ip, const struct xt_entry_target *target)
printf(" --set-dscp 0x%02x", dinfo->dscp);
}
-static struct xtables_target dscp_target = {
- .family = NFPROTO_UNSPEC,
- .name = "DSCP",
- .version = XTABLES_VERSION,
- .size = XT_ALIGN(sizeof(struct xt_DSCP_info)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_DSCP_info)),
- .help = DSCP_help,
- .print = DSCP_print,
- .save = DSCP_save,
- .x6_parse = DSCP_parse,
- .x6_fcheck = DSCP_check,
- .x6_options = DSCP_opts,
+
+static int DSCP_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_DSCP_info *dinfo =
+ (struct xt_DSCP_info *)params->target->data;
+
+ xt_xlate_add(xl, "ip dscp set 0x%02x", dinfo->dscp);
+ return 1;
+}
+
+static int DSCP_xlate6(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_DSCP_info *dinfo =
+ (struct xt_DSCP_info *)params->target->data;
+
+ xt_xlate_add(xl, "ip6 dscp set 0x%02x", dinfo->dscp);
+ return 1;
+}
+
+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,
+ .print = DSCP_print,
+ .save = DSCP_save,
+ .x6_parse = DSCP_parse,
+ .x6_fcheck = DSCP_check,
+ .x6_options = DSCP_opts,
+ .xlate = DSCP_xlate,
+ },
+ {
+ .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,
+ .print = DSCP_print,
+ .save = DSCP_save,
+ .x6_parse = DSCP_parse,
+ .x6_fcheck = DSCP_check,
+ .x6_options = DSCP_opts,
+ .xlate = DSCP_xlate6,
+ },
};
void _init(void)
{
- xtables_register_target(&dscp_target);
+ xtables_register_targets(dscp_target, ARRAY_SIZE(dscp_target));
}
diff --git a/extensions/libxt_DSCP.t b/extensions/libxt_DSCP.t
new file mode 100644
index 00000000..fcc55986
--- /dev/null
+++ b/extensions/libxt_DSCP.t
@@ -0,0 +1,11 @@
+:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j DSCP --set-dscp 0;=;OK
+-j DSCP --set-dscp 0x3f;=;OK
+-j DSCP --set-dscp -1;;FAIL
+-j DSCP --set-dscp 0x40;;FAIL
+-j DSCP --set-dscp 0x3f --set-dscp-class CS0;;FAIL
+-j DSCP --set-dscp-class CS0;-j DSCP --set-dscp 0x00;OK
+-j DSCP --set-dscp-class BE;-j DSCP --set-dscp 0x00;OK
+-j DSCP --set-dscp-class EF;-j DSCP --set-dscp 0x2e;OK
+-j DSCP;;FAIL
diff --git a/extensions/libxt_HMARK.t b/extensions/libxt_HMARK.t
new file mode 100644
index 00000000..3bcf1dad
--- /dev/null
+++ b/extensions/libxt_HMARK.t
@@ -0,0 +1,8 @@
+:INPUT,FORWARD,OUTPUT
+-j HMARK;;FAIL
+-j HMARK --hmark-src-prefix 32 --hmark-rnd 0x00000004 --hmark-mod 42;=;OK
+-j HMARK --hmark-src-prefix 32 --hmark-dst-prefix 32 --hmark-sport-mask 0xffff --hmark-dport-mask 0xffff --hmark-proto-mask 0xffff --hmark-rnd 0x00000004 --hmark-mod 42 --hmark-offset 1 --hmark-tuple ct;=;OK
+-j HMARK --hmark-src-prefix 32 --hmark-dst-prefix 32 --hmark-spi-mask 0x00000004 --hmark-proto-mask 0xffff --hmark-rnd 0x00000004 --hmark-mod 42 --hmark-offset 1 --hmark-tuple ct;=;OK
+-j HMARK --hmark-src-prefix 1 --hmark-dst-prefix 2 --hmark-sport-mask 0x0003 --hmark-dport-mask 0x0004 --hmark-proto-mask 0x05 --hmark-rnd 0x00000004 --hmark-mod 42 --hmark-offset 1 --hmark-tuple ct;=;OK
+# cannot mix in spi mask:
+-j HMARK --hmark-src-prefix 32 --hmark-dst-prefix 32 --hmark-sport-mask 0xffff --hmark-dport-mask 0xffff --hmark-proto-mask 0xffff --hmark-rnd 0x00000004 --hmark-mod 42 --hmark-offset 1 --hmark-tuple ct --hmark-spi-mask 4;;FAIL
diff --git a/extensions/libxt_IDLETIMER.t b/extensions/libxt_IDLETIMER.t
new file mode 100644
index 00000000..6afd92c1
--- /dev/null
+++ b/extensions/libxt_IDLETIMER.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+-j IDLETIMER --timeout;;FAIL
+-j IDLETIMER --timeout 42;;FAIL
+-j IDLETIMER --timeout 42 --label foo;=;OK
diff --git a/extensions/libxt_LED.t b/extensions/libxt_LED.t
new file mode 100644
index 00000000..1f6705f4
--- /dev/null
+++ b/extensions/libxt_LED.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+-j LED;;FAIL
+-j LED --led-trigger-id "foo";=;OK
+-j LED --led-trigger-id "foo" --led-delay 42 --led-always-blink;=;OK
diff --git a/extensions/libxt_LOG.man b/extensions/libxt_LOG.man
index 6d3a83a4..354edf4c 100644
--- a/extensions/libxt_LOG.man
+++ b/extensions/libxt_LOG.man
@@ -1,10 +1,8 @@
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/IPv6 header fields) via the kernel log
-(where it can be read with
-.I dmesg
-or
-.IR syslogd (8)).
+(where it can be read with \fIdmesg(1)\fP or read in the syslog).
+.PP
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
diff --git a/extensions/libxt_MARK.c b/extensions/libxt_MARK.c
index 556dbde5..c2f15e3b 100644
--- a/extensions/libxt_MARK.c
+++ b/extensions/libxt_MARK.c
@@ -195,7 +195,7 @@ static void MARK_print_v1(const void *ip, const struct xt_entry_target *target,
case XT_MARK_AND:
printf(" MARK and");
break;
- case XT_MARK_OR:
+ case XT_MARK_OR:
printf(" MARK or");
break;
}
@@ -231,7 +231,7 @@ static void MARK_save_v1(const void *ip, const struct xt_entry_target *target)
case XT_MARK_AND:
printf(" --and-mark");
break;
- case XT_MARK_OR:
+ case XT_MARK_OR:
printf(" --or-mark");
break;
}
@@ -245,6 +245,51 @@ static void mark_tg_save(const void *ip, const struct xt_entry_target *target)
printf(" --set-xmark 0x%x/0x%x", info->mark, info->mask);
}
+static int mark_tg_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_mark_tginfo2 *info = (const void *)params->target->data;
+
+ xt_xlate_add(xl, "meta mark set ");
+
+ if (info->mark == 0)
+ xt_xlate_add(xl, "mark and 0x%x ", ~info->mask);
+ else if (info->mark == info->mask)
+ xt_xlate_add(xl, "mark or 0x%x ", info->mark);
+ else if (info->mask == 0)
+ xt_xlate_add(xl, "mark xor 0x%x ", info->mark);
+ else if (info->mask == 0xffffffffU)
+ xt_xlate_add(xl, "0x%x ", info->mark);
+ else
+ xt_xlate_add(xl, "mark and 0x%x xor 0x%x ", ~info->mask,
+ info->mark);
+
+ return 1;
+}
+
+static int MARK_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_mark_target_info_v1 *markinfo =
+ (const struct xt_mark_target_info_v1 *)params->target->data;
+
+ xt_xlate_add(xl, "meta mark set ");
+
+ switch(markinfo->mode) {
+ case XT_MARK_SET:
+ xt_xlate_add(xl, "0x%x ", markinfo->mark);
+ break;
+ case XT_MARK_AND:
+ xt_xlate_add(xl, "mark and 0x%x ", markinfo->mark);
+ break;
+ case XT_MARK_OR:
+ xt_xlate_add(xl, "mark or 0x%x ", markinfo->mark);
+ break;
+ }
+
+ return 1;
+}
+
static struct xtables_target mark_tg_reg[] = {
{
.family = NFPROTO_UNSPEC,
@@ -273,6 +318,7 @@ static struct xtables_target mark_tg_reg[] = {
.x6_parse = MARK_parse_v1,
.x6_fcheck = MARK_check,
.x6_options = MARK_opts,
+ .xlate = MARK_xlate,
},
{
.version = XTABLES_VERSION,
@@ -287,6 +333,7 @@ static struct xtables_target mark_tg_reg[] = {
.x6_parse = mark_tg_parse,
.x6_fcheck = mark_tg_check,
.x6_options = mark_tg_opts,
+ .xlate = mark_tg_xlate,
},
};
diff --git a/extensions/libxt_MARK.t b/extensions/libxt_MARK.t
new file mode 100644
index 00000000..9d1aa7d7
--- /dev/null
+++ b/extensions/libxt_MARK.t
@@ -0,0 +1,7 @@
+:INPUT,FORWARD,OUTPUT
+-j MARK --set-xmark 0xfeedcafe/0xfeedcafe;=;OK
+-j MARK --set-xmark 0;=;OK
+-j MARK --set-xmark 4294967295;-j MARK --set-xmark 0xffffffff;OK
+-j MARK --set-xmark 4294967296;;FAIL
+-j MARK --set-xmark -1;;FAIL
+-j MARK;;FAIL
diff --git a/extensions/libxt_NFLOG.c b/extensions/libxt_NFLOG.c
index 448576af..02a1b4aa 100644
--- a/extensions/libxt_NFLOG.c
+++ b/extensions/libxt_NFLOG.c
@@ -12,7 +12,10 @@ enum {
O_GROUP = 0,
O_PREFIX,
O_RANGE,
+ O_SIZE,
O_THRESHOLD,
+ F_RANGE = 1 << O_RANGE,
+ F_SIZE = 1 << O_SIZE,
};
#define s struct xt_nflog_info
@@ -22,7 +25,9 @@ static const struct xt_option_entry NFLOG_opts[] = {
{.name = "nflog-prefix", .id = O_PREFIX, .type = XTTYPE_STRING,
.min = 1, .flags = XTOPT_PUT, XTOPT_POINTER(s, prefix)},
{.name = "nflog-range", .id = O_RANGE, .type = XTTYPE_UINT32,
- .flags = XTOPT_PUT, XTOPT_POINTER(s, len)},
+ .excl = F_SIZE, .flags = XTOPT_PUT, XTOPT_POINTER(s, len)},
+ {.name = "nflog-size", .id = O_SIZE, .type = XTTYPE_UINT32,
+ .excl = F_RANGE, .flags = XTOPT_PUT, XTOPT_POINTER(s, len)},
{.name = "nflog-threshold", .id = O_THRESHOLD, .type = XTTYPE_UINT16,
.flags = XTOPT_PUT, XTOPT_POINTER(s, threshold)},
XTOPT_TABLEEND,
@@ -33,7 +38,8 @@ 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-range NUM This option has no effect, use --nflog-size\n"
+ " --nflog-size NUM Number of bytes to copy\n"
" --nflog-threshold NUM Message threshold of in-kernel queue\n"
" --nflog-prefix STRING Prefix string for log messages\n");
}
@@ -57,6 +63,18 @@ static void NFLOG_parse(struct xt_option_call *cb)
}
}
+static void NFLOG_check(struct xt_fcheck_call *cb)
+{
+ struct xt_nflog_info *info = cb->data;
+
+ if (cb->xflags & F_RANGE)
+ fprintf(stderr, "warn: --nflog-range has never worked and is no"
+ " longer supported, please use --nflog-size insted\n");
+
+ if (cb->xflags & F_SIZE)
+ info->flags |= XT_NFLOG_F_COPY_LEN;
+}
+
static void nflog_print(const struct xt_nflog_info *info, char *prefix)
{
if (info->prefix[0] != '\0') {
@@ -65,14 +83,16 @@ static void nflog_print(const struct xt_nflog_info *info, char *prefix)
}
if (info->group)
printf(" %snflog-group %u", prefix, info->group);
- if (info->len)
+ if (info->flags & XT_NFLOG_F_COPY_LEN)
+ printf(" %snflog-size %u", prefix, info->len);
+ else 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)
+ int numeric)
{
const struct xt_nflog_info *info = (struct xt_nflog_info *)target->data;
@@ -86,6 +106,35 @@ static void NFLOG_save(const void *ip, const struct xt_entry_target *target)
nflog_print(info, "--");
}
+static void nflog_print_xlate(const struct xt_nflog_info *info,
+ struct xt_xlate *xl, bool escape_quotes)
+{
+ xt_xlate_add(xl, "log ");
+ if (info->prefix[0] != '\0') {
+ if (escape_quotes)
+ xt_xlate_add(xl, "prefix \\\"%s\\\" ", info->prefix);
+ else
+ xt_xlate_add(xl, "prefix \"%s\" ", info->prefix);
+
+ }
+ if (info->flags & XT_NFLOG_F_COPY_LEN)
+ xt_xlate_add(xl, "snaplen %u ", info->len);
+ if (info->threshold != XT_NFLOG_DEFAULT_THRESHOLD)
+ xt_xlate_add(xl, "queue-threshold %u ", info->threshold);
+ xt_xlate_add(xl, "group %u ", info->group);
+}
+
+static int NFLOG_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_nflog_info *info =
+ (struct xt_nflog_info *)params->target->data;
+
+ nflog_print_xlate(info, xl, params->escape_quotes);
+
+ return 1;
+}
+
static struct xtables_target nflog_target = {
.family = NFPROTO_UNSPEC,
.name = "NFLOG",
@@ -94,10 +143,12 @@ static struct xtables_target nflog_target = {
.userspacesize = XT_ALIGN(sizeof(struct xt_nflog_info)),
.help = NFLOG_help,
.init = NFLOG_init,
+ .x6_fcheck = NFLOG_check,
.x6_parse = NFLOG_parse,
.print = NFLOG_print,
.save = NFLOG_save,
.x6_options = NFLOG_opts,
+ .xlate = NFLOG_xlate,
};
void _init(void)
diff --git a/extensions/libxt_NFLOG.man b/extensions/libxt_NFLOG.man
index 1b6dbf16..318e6305 100644
--- a/extensions/libxt_NFLOG.man
+++ b/extensions/libxt_NFLOG.man
@@ -17,6 +17,9 @@ 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
+This option has never worked, use --nflog-size instead
+.TP
+\fB\-\-nflog\-size\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.
diff --git a/extensions/libxt_NFLOG.t b/extensions/libxt_NFLOG.t
new file mode 100644
index 00000000..933fa221
--- /dev/null
+++ b/extensions/libxt_NFLOG.t
@@ -0,0 +1,24 @@
+:INPUT,FORWARD,OUTPUT
+-j NFLOG --nflog-group 1;=;OK
+-j NFLOG --nflog-group 65535;=;OK
+-j NFLOG --nflog-group 65536;;FAIL
+-j NFLOG --nflog-group 0;-j NFLOG;OK
+-j NFLOG --nflog-range 1;=;OK
+-j NFLOG --nflog-range 4294967295;=;OK
+-j NFLOG --nflog-range 4294967296;;FAIL
+-j NFLOG --nflog-range -1;;FAIL
+-j NFLOG --nflog-size 0;=;OK
+-j NFLOG --nflog-size 1;=;OK
+-j NFLOG --nflog-size 4294967295;=;OK
+-j NFLOG --nflog-size 4294967296;;FAIL
+-j NFLOG --nflog-size -1;;FAIL
+# ERROR: cannot find: iptables -I INPUT -j NFLOG --nflog-prefix xxxxxx [...]
+# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
+# ERROR: should fail: iptables -A INPUT -j NFLOG --nflog-prefix xxxxxxx [...]
+# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;;FAIL
+-j NFLOG --nflog-threshold 1;=;OK
+# ERROR: line 13 (should fail: iptables -A INPUT -j NFLOG --nflog-threshold 0
+# -j NFLOG --nflog-threshold 0;;FAIL
+-j NFLOG --nflog-threshold 65535;=;OK
+-j NFLOG --nflog-threshold 65536;;FAIL
+-j NFLOG;=;OK
diff --git a/extensions/libxt_NFQUEUE.c b/extensions/libxt_NFQUEUE.c
index 0c869187..fe519078 100644
--- a/extensions/libxt_NFQUEUE.c
+++ b/extensions/libxt_NFQUEUE.c
@@ -30,23 +30,32 @@ static void NFQUEUE_help(void)
static void NFQUEUE_help_v1(void)
{
- NFQUEUE_help();
printf(
+"NFQUEUE target options\n"
+" --queue-num value Send packet to QUEUE number <value>.\n"
+" Valid queue numbers are 0-65535\n"
" --queue-balance first:last Balance flows between queues <value> to <value>.\n");
}
static void NFQUEUE_help_v2(void)
{
- NFQUEUE_help_v1();
printf(
+"NFQUEUE target options\n"
+" --queue-num value Send packet to QUEUE number <value>.\n"
+" Valid queue numbers are 0-65535\n"
+" --queue-balance first:last Balance flows between queues <value> to <value>.\n"
" --queue-bypass Bypass Queueing if no queue instance exists.\n"
" --queue-cpu-fanout Use current CPU (no hashing)\n");
}
static void NFQUEUE_help_v3(void)
{
- NFQUEUE_help_v2();
printf(
+"NFQUEUE target options\n"
+" --queue-num value Send packet to QUEUE number <value>.\n"
+" Valid queue numbers are 0-65535\n"
+" --queue-balance first:last Balance flows between queues <value> to <value>.\n"
+" --queue-bypass Bypass Queueing if no queue instance exists.\n"
" --queue-cpu-fanout Use current CPU (no hashing)\n");
}
@@ -95,11 +104,23 @@ static void NFQUEUE_parse_v1(struct xt_option_call *cb)
static void NFQUEUE_parse_v2(struct xt_option_call *cb)
{
struct xt_NFQ_info_v2 *info = cb->data;
+ const uint16_t *r = cb->val.u16_range;
- NFQUEUE_parse_v1(cb);
+ xtables_option_parse(cb);
switch (cb->entry->id) {
+ case O_QUEUE_BALANCE:
+ if (cb->nvals != 2)
+ xtables_error(PARAMETER_PROBLEM,
+ "Bad range \"%s\"", cb->arg);
+ if (r[0] >= r[1])
+ xtables_error(PARAMETER_PROBLEM,
+ "%u should be less than %u",
+ r[0], r[1]);
+ info->queuenum = r[0];
+ info->queues_total = r[1] - r[0] + 1;
+ break;
case O_QUEUE_BYPASS:
- info->bypass = 1;
+ info->bypass |= NFQ_FLAG_BYPASS;
break;
}
}
@@ -107,9 +128,24 @@ static void NFQUEUE_parse_v2(struct xt_option_call *cb)
static void NFQUEUE_parse_v3(struct xt_option_call *cb)
{
struct xt_NFQ_info_v3 *info = cb->data;
+ const uint16_t *r = cb->val.u16_range;
- NFQUEUE_parse_v2(cb);
+ xtables_option_parse(cb);
switch (cb->entry->id) {
+ case O_QUEUE_BALANCE:
+ if (cb->nvals != 2)
+ xtables_error(PARAMETER_PROBLEM,
+ "Bad range \"%s\"", cb->arg);
+ if (r[0] >= r[1])
+ xtables_error(PARAMETER_PROBLEM,
+ "%u should be less than %u",
+ r[0], r[1]);
+ info->queuenum = r[0];
+ info->queues_total = r[1] - r[0] + 1;
+ break;
+ case O_QUEUE_BYPASS:
+ info->flags |= NFQ_FLAG_BYPASS;
+ break;
case O_QUEUE_CPU_FANOUT:
info->flags |= NFQ_FLAG_CPU_FANOUT;
break;
@@ -142,8 +178,14 @@ static void NFQUEUE_print_v2(const void *ip,
const struct xt_entry_target *target, int numeric)
{
const struct xt_NFQ_info_v2 *info = (void *) target->data;
+ unsigned int last = info->queues_total;
+
+ if (last > 1) {
+ last += info->queuenum - 1;
+ printf(" NFQUEUE balance %u:%u", info->queuenum, last);
+ } else
+ printf(" NFQUEUE num %u", info->queuenum);
- NFQUEUE_print_v1(ip, target, numeric);
if (info->bypass & NFQ_FLAG_BYPASS)
printf(" bypass");
}
@@ -152,8 +194,17 @@ static void NFQUEUE_print_v3(const void *ip,
const struct xt_entry_target *target, int numeric)
{
const struct xt_NFQ_info_v3 *info = (void *)target->data;
+ unsigned int last = info->queues_total;
+
+ if (last > 1) {
+ last += info->queuenum - 1;
+ printf(" NFQUEUE balance %u:%u", info->queuenum, last);
+ } else
+ printf(" NFQUEUE num %u", info->queuenum);
+
+ if (info->flags & NFQ_FLAG_BYPASS)
+ printf(" bypass");
- NFQUEUE_print_v2(ip, target, numeric);
if (info->flags & NFQ_FLAG_CPU_FANOUT)
printf(" cpu-fanout");
}
@@ -182,8 +233,13 @@ static void NFQUEUE_save_v1(const void *ip, const struct xt_entry_target *target
static void NFQUEUE_save_v2(const void *ip, const struct xt_entry_target *target)
{
const struct xt_NFQ_info_v2 *info = (void *) target->data;
+ unsigned int last = info->queues_total;
- NFQUEUE_save_v1(ip, target);
+ if (last > 1) {
+ last += info->queuenum - 1;
+ printf(" --queue-balance %u:%u", info->queuenum, last);
+ } else
+ printf(" --queue-num %u", info->queuenum);
if (info->bypass & NFQ_FLAG_BYPASS)
printf(" --queue-bypass");
@@ -193,8 +249,17 @@ static void NFQUEUE_save_v3(const void *ip,
const struct xt_entry_target *target)
{
const struct xt_NFQ_info_v3 *info = (void *)target->data;
+ unsigned int last = info->queues_total;
+
+ if (last > 1) {
+ last += info->queuenum - 1;
+ printf(" --queue-balance %u:%u", info->queuenum, last);
+ } else
+ printf(" --queue-num %u", info->queuenum);
+
+ if (info->flags & NFQ_FLAG_BYPASS)
+ printf(" --queue-bypass");
- NFQUEUE_save_v2(ip, target);
if (info->flags & NFQ_FLAG_CPU_FANOUT)
printf(" --queue-cpu-fanout");
}
@@ -205,6 +270,73 @@ static void NFQUEUE_init_v1(struct xt_entry_target *t)
tinfo->queues_total = 1;
}
+static int NFQUEUE_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_NFQ_info *tinfo =
+ (const struct xt_NFQ_info *)params->target->data;
+
+ xt_xlate_add(xl, "queue num %u ", tinfo->queuenum);
+
+ return 1;
+}
+
+static int NFQUEUE_xlate_v1(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_NFQ_info_v1 *tinfo = (const void *)params->target->data;
+ unsigned int last = tinfo->queues_total;
+
+ if (last > 1) {
+ last += tinfo->queuenum - 1;
+ xt_xlate_add(xl, "queue num %u-%u ", tinfo->queuenum, last);
+ } else {
+ xt_xlate_add(xl, "queue num %u ", tinfo->queuenum);
+ }
+
+ return 1;
+}
+
+static int NFQUEUE_xlate_v2(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_NFQ_info_v2 *info = (void *)params->target->data;
+ unsigned int last = info->queues_total;
+
+ if (last > 1) {
+ last += info->queuenum - 1;
+ xt_xlate_add(xl, "queue num %u-%u ", info->queuenum, last);
+ } else
+ xt_xlate_add(xl, "queue num %u ", info->queuenum);
+
+ if (info->bypass & NFQ_FLAG_BYPASS)
+ xt_xlate_add(xl, "bypass");
+
+ return 1;
+}
+
+static int NFQUEUE_xlate_v3(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_NFQ_info_v3 *info = (void *)params->target->data;
+ unsigned int last = info->queues_total;
+
+ if (last > 1) {
+ last += info->queuenum - 1;
+ xt_xlate_add(xl, "queue num %u-%u ", info->queuenum, last);
+ } else
+ xt_xlate_add(xl, "queue num %u ", info->queuenum);
+
+ if (info->flags & NFQ_FLAG_BYPASS)
+ xt_xlate_add(xl, "bypass");
+
+ if (info->flags & NFQ_FLAG_CPU_FANOUT)
+ xt_xlate_add(xl, "%sfanout ",
+ info->flags & NFQ_FLAG_BYPASS ? "," : "");
+
+ return 1;
+}
+
static struct xtables_target nfqueue_targets[] = {
{
.family = NFPROTO_UNSPEC,
@@ -216,7 +348,8 @@ static struct xtables_target nfqueue_targets[] = {
.print = NFQUEUE_print,
.save = NFQUEUE_save,
.x6_parse = NFQUEUE_parse,
- .x6_options = NFQUEUE_opts
+ .x6_options = NFQUEUE_opts,
+ .xlate = NFQUEUE_xlate,
},{
.family = NFPROTO_UNSPEC,
.revision = 1,
@@ -230,6 +363,7 @@ static struct xtables_target nfqueue_targets[] = {
.save = NFQUEUE_save_v1,
.x6_parse = NFQUEUE_parse_v1,
.x6_options = NFQUEUE_opts,
+ .xlate = NFQUEUE_xlate_v1,
},{
.family = NFPROTO_UNSPEC,
.revision = 2,
@@ -243,6 +377,7 @@ static struct xtables_target nfqueue_targets[] = {
.save = NFQUEUE_save_v2,
.x6_parse = NFQUEUE_parse_v2,
.x6_options = NFQUEUE_opts,
+ .xlate = NFQUEUE_xlate_v2,
},{
.family = NFPROTO_UNSPEC,
.revision = 3,
@@ -256,6 +391,7 @@ static struct xtables_target nfqueue_targets[] = {
.save = NFQUEUE_save_v3,
.x6_parse = NFQUEUE_parse_v3,
.x6_options = NFQUEUE_opts,
+ .xlate = NFQUEUE_xlate_v3,
}
};
diff --git a/extensions/libxt_NFQUEUE.man b/extensions/libxt_NFQUEUE.man
index 7a991291..1bfb7b84 100644
--- a/extensions/libxt_NFQUEUE.man
+++ b/extensions/libxt_NFQUEUE.man
@@ -1,11 +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.
-It can only be used with Kernel versions 2.6.14 or later, since it requires
-the
+This target passes the packet to userspace using the
+\fBnfnetlink_queue\fP handler. The packet is put into the queue
+identified by its 16-bit queue number. Userspace can inspect
+and modify the packet if desired. Userspace must then drop or
+reinject the packet into the kernel. Please see libnetfilter_queue
+for details.
.B
nfnetlink_queue
-kernel support. The \fBqueue-balance\fP option was added in Linux 2.6.31,
+was added in Linux 2.6.14. The \fBqueue-balance\fP option was added in Linux 2.6.31,
\fBqueue-bypass\fP in 2.6.39.
.TP
\fB\-\-queue\-num\fP \fIvalue\fP
diff --git a/extensions/libxt_NFQUEUE.t b/extensions/libxt_NFQUEUE.t
new file mode 100644
index 00000000..b51b19fd
--- /dev/null
+++ b/extensions/libxt_NFQUEUE.t
@@ -0,0 +1,16 @@
+:INPUT,FORWARD,OUTPUT
+-j NFQUEUE;=;OK
+-j NFQUEUE --queue-num 0;=;OK
+-j NFQUEUE --queue-num 65535;=;OK
+-j NFQUEUE --queue-num 65536;;FAIL
+-j NFQUEUE --queue-num -1;;FAIL
+# it says "NFQUEUE: number of total queues is 0", overflow in NFQUEUE_parse_v1?
+# ERROR: cannot load: iptables -A INPUT -j NFQUEUE --queue-balance 0:65535
+# -j NFQUEUE --queue-balance 0:65535;=;OK
+-j NFQUEUE --queue-balance 0:65536;;FAIL
+-j NFQUEUE --queue-balance -1:65535;;FAIL
+-j NFQUEUE --queue-num 10 --queue-bypass;=;OK
+-j NFQUEUE --queue-balance 0:6 --queue-cpu-fanout --queue-bypass;-j NFQUEUE --queue-balance 0:6 --queue-bypass --queue-cpu-fanout;OK
+-j NFQUEUE --queue-bypass --queue-balance 0:6 --queue-cpu-fanout;-j NFQUEUE --queue-balance 0:6 --queue-bypass --queue-cpu-fanout;OK
+-j NFQUEUE --queue-balance 0:6 --queue-bypass;=;OK
+-j NFQUEUE --queue-bypass;-j NFQUEUE --queue-num 0 --queue-bypass;OK
diff --git a/extensions/libxt_NOTRACK.t b/extensions/libxt_NOTRACK.t
new file mode 100644
index 00000000..585be82d
--- /dev/null
+++ b/extensions/libxt_NOTRACK.t
@@ -0,0 +1,4 @@
+:PREROUTING,OUTPUT
+*raw
+# ERROR: cannot find: iptables -I PREROUTING -t raw -j NOTRACK
+#-j NOTRACK;=;OK
diff --git a/extensions/libxt_RATEEST.t b/extensions/libxt_RATEEST.t
new file mode 100644
index 00000000..c2b6bb34
--- /dev/null
+++ b/extensions/libxt_RATEEST.t
@@ -0,0 +1,2 @@
+:INPUT,FORWARD,OUTPUT
+-j RATEEST --rateest-name RE1 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms;=;OK
diff --git a/extensions/libxt_SET.c b/extensions/libxt_SET.c
index a11db395..2a7640a0 100644
--- a/extensions/libxt_SET.c
+++ b/extensions/libxt_SET.c
@@ -5,7 +5,7 @@
*
* 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.
+ * published by the Free Software Foundation.
*/
/* Shared library add-on to iptables to add IP set mangling target. */
@@ -80,7 +80,7 @@ parse_target_v0(char **argv, int invert, unsigned int *flags,
get_set_byname(optarg, (struct xt_set_info *)info);
parse_dirs_v0(argv[optind], info);
optind++;
-
+
*flags = 1;
}
@@ -116,7 +116,7 @@ print_target_v0(const char *prefix, const struct xt_set_info_v0 *info)
printf(" %s %s", prefix, setname);
for (i = 0; i < IPSET_DIM_MAX; i++) {
if (!info->u.flags[i])
- break;
+ break;
printf("%s%s",
i == 0 ? " " : ",",
info->u.flags[i] & IPSET_SRC ? "src" : "dst");
@@ -125,7 +125,7 @@ print_target_v0(const char *prefix, const struct xt_set_info_v0 *info)
static void
set_target_print_v0(const void *ip, const struct xt_entry_target *target,
- int numeric)
+ int numeric)
{
const struct xt_set_info_target_v0 *info = (const void *)target->data;
@@ -158,6 +158,10 @@ set_target_init_v1(struct xt_entry_target *target)
#define SET_TARGET_DEL 0x2
#define SET_TARGET_EXIST 0x4
#define SET_TARGET_TIMEOUT 0x8
+#define SET_TARGET_MAP 0x10
+#define SET_TARGET_MAP_MARK 0x20
+#define SET_TARGET_MAP_PRIO 0x40
+#define SET_TARGET_MAP_QUEUE 0x80
static void
parse_target(char **argv, int invert, struct xt_set_info *info,
@@ -314,7 +318,7 @@ set_target_parse_v2(int c, char **argv, int invert, unsigned int *flags,
"or out of range 0-%u", UINT32_MAX - 1);
myinfo->timeout = timeout;
*flags |= SET_TARGET_TIMEOUT;
- break;
+ break;
}
return 1;
}
@@ -346,6 +350,170 @@ set_target_save_v2(const void *ip, const struct xt_entry_target *target)
print_target("--del-set", &info->del_set);
}
+
+/* Revision 3 */
+
+static void
+set_target_help_v3(void)
+{
+ printf("SET target options:\n"
+ " --add-set name flags [--exist] [--timeout n]\n"
+ " --del-set name flags\n"
+ " --map-set name flags"
+ " [--map-mark] [--map-prio] [--map-queue]\n"
+ " add/del src/dst IP/port from/to named sets,\n"
+ " where flags are the comma separated list of\n"
+ " 'src' and 'dst' specifications.\n");
+}
+
+static const struct option set_target_opts_v3[] = {
+ {.name = "add-set", .has_arg = true, .val = '1'},
+ {.name = "del-set", .has_arg = true, .val = '2'},
+ {.name = "exist", .has_arg = false, .val = '3'},
+ {.name = "timeout", .has_arg = true, .val = '4'},
+ {.name = "map-set", .has_arg = true, .val = '5'},
+ {.name = "map-mark", .has_arg = false, .val = '6'},
+ {.name = "map-prio", .has_arg = false, .val = '7'},
+ {.name = "map-queue", .has_arg = false, .val = '8'},
+ XT_GETOPT_TABLEEND,
+};
+
+static void
+set_target_check_v3(unsigned int flags)
+{
+ if (!(flags & (SET_TARGET_ADD|SET_TARGET_DEL|SET_TARGET_MAP)))
+ xtables_error(PARAMETER_PROBLEM,
+ "You must specify either `--add-set' or "
+ "`--del-set' or `--map-set'");
+ if (!(flags & SET_TARGET_ADD)) {
+ if (flags & SET_TARGET_EXIST)
+ xtables_error(PARAMETER_PROBLEM,
+ "Flag `--exist' can be used with `--add-set' only");
+ if (flags & SET_TARGET_TIMEOUT)
+ xtables_error(PARAMETER_PROBLEM,
+ "Option `--timeout' can be used with `--add-set' only");
+ }
+ if (!(flags & SET_TARGET_MAP)) {
+ if (flags & SET_TARGET_MAP_MARK)
+ xtables_error(PARAMETER_PROBLEM,
+ "Flag `--map-mark' can be used with `--map-set' only");
+ if (flags & SET_TARGET_MAP_PRIO)
+ xtables_error(PARAMETER_PROBLEM,
+ "Flag `--map-prio' can be used with `--map-set' only");
+ if (flags & SET_TARGET_MAP_QUEUE)
+ xtables_error(PARAMETER_PROBLEM,
+ "Flag `--map-queue' can be used with `--map-set' only");
+ }
+ if ((flags & SET_TARGET_MAP) && !(flags & (SET_TARGET_MAP_MARK |
+ SET_TARGET_MAP_PRIO |
+ SET_TARGET_MAP_QUEUE)))
+ xtables_error(PARAMETER_PROBLEM,
+ "You must specify flags `--map-mark' or "
+ "'--map-prio` or `--map-queue'");
+}
+
+static void
+set_target_init_v3(struct xt_entry_target *target)
+{
+ struct xt_set_info_target_v3 *info =
+ (struct xt_set_info_target_v3 *) target->data;
+
+ info->add_set.index =
+ info->del_set.index =
+ info->map_set.index = IPSET_INVALID_ID;
+ info->timeout = UINT32_MAX;
+}
+
+static int
+set_target_parse_v3(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_target **target)
+{
+ struct xt_set_info_target_v3 *myinfo =
+ (struct xt_set_info_target_v3 *) (*target)->data;
+ unsigned int timeout;
+
+ switch (c) {
+ case '1': /* --add-set <set> <flags> */
+ parse_target(argv, invert, &myinfo->add_set, "add-set");
+ *flags |= SET_TARGET_ADD;
+ break;
+ case '2': /* --del-set <set>[:<flags>] <flags> */
+ parse_target(argv, invert, &myinfo->del_set, "del-set");
+ *flags |= SET_TARGET_DEL;
+ break;
+ case '3':
+ myinfo->flags |= IPSET_FLAG_EXIST;
+ *flags |= SET_TARGET_EXIST;
+ break;
+ case '4':
+ if (!xtables_strtoui(optarg, NULL, &timeout, 0, UINT32_MAX - 1))
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid value for option --timeout "
+ "or out of range 0-%u", UINT32_MAX - 1);
+ myinfo->timeout = timeout;
+ *flags |= SET_TARGET_TIMEOUT;
+ break;
+ case '5': /* --map-set <set> <flags> */
+ parse_target(argv, invert, &myinfo->map_set, "map-set");
+ *flags |= SET_TARGET_MAP;
+ break;
+ case '6':
+ myinfo->flags |= IPSET_FLAG_MAP_SKBMARK;
+ *flags |= SET_TARGET_MAP_MARK;
+ break;
+ case '7':
+ myinfo->flags |= IPSET_FLAG_MAP_SKBPRIO;
+ *flags |= SET_TARGET_MAP_PRIO;
+ break;
+ case '8':
+ myinfo->flags |= IPSET_FLAG_MAP_SKBQUEUE;
+ *flags |= SET_TARGET_MAP_QUEUE;
+ break;
+ }
+ return 1;
+}
+
+static void
+set_target_print_v3(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ const struct xt_set_info_target_v3 *info = (const void *)target->data;
+
+ print_target("add-set", &info->add_set);
+ if (info->flags & IPSET_FLAG_EXIST)
+ printf(" exist");
+ if (info->timeout != UINT32_MAX)
+ printf(" timeout %u", info->timeout);
+ print_target("del-set", &info->del_set);
+ print_target("map-set", &info->map_set);
+ if (info->flags & IPSET_FLAG_MAP_SKBMARK)
+ printf(" map-mark");
+ if (info->flags & IPSET_FLAG_MAP_SKBPRIO)
+ printf(" map-prio");
+ if (info->flags & IPSET_FLAG_MAP_SKBQUEUE)
+ printf(" map-queue");
+}
+
+static void
+set_target_save_v3(const void *ip, const struct xt_entry_target *target)
+{
+ const struct xt_set_info_target_v3 *info = (const void *)target->data;
+
+ print_target("--add-set", &info->add_set);
+ if (info->flags & IPSET_FLAG_EXIST)
+ printf(" --exist");
+ if (info->timeout != UINT32_MAX)
+ printf(" --timeout %u", info->timeout);
+ print_target("--del-set", &info->del_set);
+ print_target("--map-set", &info->map_set);
+ if (info->flags & IPSET_FLAG_MAP_SKBMARK)
+ printf(" --map-mark");
+ if (info->flags & IPSET_FLAG_MAP_SKBPRIO)
+ printf(" --map-prio");
+ if (info->flags & IPSET_FLAG_MAP_SKBQUEUE)
+ printf(" --map-queue");
+}
+
static struct xtables_target set_tg_reg[] = {
{
.name = "SET",
@@ -392,6 +560,21 @@ static struct xtables_target set_tg_reg[] = {
.save = set_target_save_v2,
.extra_opts = set_target_opts_v2,
},
+ {
+ .name = "SET",
+ .revision = 3,
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_UNSPEC,
+ .size = XT_ALIGN(sizeof(struct xt_set_info_target_v3)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v3)),
+ .help = set_target_help_v3,
+ .init = set_target_init_v3,
+ .parse = set_target_parse_v3,
+ .final_check = set_target_check_v3,
+ .print = set_target_print_v3,
+ .save = set_target_save_v3,
+ .extra_opts = set_target_opts_v3,
+ },
};
void _init(void)
diff --git a/extensions/libxt_SET.man b/extensions/libxt_SET.man
index c35ba93d..78a9ae0f 100644
--- a/extensions/libxt_SET.man
+++ b/extensions/libxt_SET.man
@@ -6,6 +6,10 @@ add the address(es)/port(s) of the packet to the set
.TP
\fB\-\-del\-set\fP \fIsetname\fP \fIflag\fP[\fB,\fP\fIflag\fP...]
delete the address(es)/port(s) of the packet from the set
+.TP
+\fB\-\-map\-set\fP \fIsetname\fP \fIflag\fP[\fB,\fP\fIflag\fP...]
+[\-\-map\-mark] [\-\-map\-prio] [\-\-map\-queue]
+map packet properties (firewall mark, tc priority, hardware queue)
.IP
where \fIflag\fP(s) are
.BR "src"
@@ -20,6 +24,23 @@ one from the set definition
\fB\-\-exist\fP
when adding an entry if it already exists, reset the timeout value
to the specified one or to the default from the set definition
+.TP
+\fB\-\-map\-set\fP \fIset\-name\fP
+the set-name should be created with --skbinfo option
+\fB\-\-map\-mark\fP
+map firewall mark to packet by lookup of value in the set
+\fB\-\-map\-prio\fP
+map traffic control priority to packet by lookup of value in the set
+\fB\-\-map\-queue\fP
+map hardware NIC queue to packet by lookup of value in the set
+.IP
+The
+\fB\-\-map\-set\fP
+option can be used from the mangle table only. The
+\fB\-\-map\-prio\fP
+and
+\fB\-\-map\-queue\fP
+flags can be used in the OUTPUT, FORWARD and POSTROUTING chains.
.PP
Use of -j SET requires that ipset kernel support is provided, which, for
standard kernels, is the case since Linux 2.6.39.
diff --git a/extensions/libxt_SET.t b/extensions/libxt_SET.t
new file mode 100644
index 00000000..30c27ca3
--- /dev/null
+++ b/extensions/libxt_SET.t
@@ -0,0 +1,3 @@
+:INPUT,FORWARD,OUTPUT
+# fails: foo does not exist
+-j SET --add-set foo src,dst;;FAIL
diff --git a/extensions/libxt_SNAT.man b/extensions/libxt_SNAT.man
index f0620a21..8cd0b80e 100644
--- a/extensions/libxt_SNAT.man
+++ b/extensions/libxt_SNAT.man
@@ -29,7 +29,12 @@ anymore.
\fB\-\-random\fP
If option
\fB\-\-random\fP
-is used then port mapping will be randomized (kernel >= 2.6.21).
+is used then port mapping will be randomized through a hash-based algorithm (kernel >= 2.6.21).
+.TP
+\fB\-\-random-fully\fP
+If option
+\fB\-\-random-fully\fP
+is used then port mapping will be fully randomized through a PRNG (kernel >= 3.14).
.TP
\fB\-\-persistent\fP
Gives a client the same source-/destination-address for each connection.
diff --git a/extensions/libxt_SYNPROXY.c b/extensions/libxt_SYNPROXY.c
new file mode 100644
index 00000000..475590ea
--- /dev/null
+++ b/extensions/libxt_SYNPROXY.c
@@ -0,0 +1,127 @@
+
+/*
+ * Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
+ *
+ * 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.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <xtables.h>
+#include <linux/netfilter/xt_SYNPROXY.h>
+
+enum {
+ O_SACK_PERM = 0,
+ O_TIMESTAMP,
+ O_WSCALE,
+ O_MSS,
+ O_ECN,
+};
+
+static void SYNPROXY_help(void)
+{
+ printf(
+"SYNPROXY target options:\n"
+" --sack-perm Set SACK_PERM\n"
+" --timestamp Set TIMESTAMP\n"
+" --wscale value Set window scaling factor\n"
+" --mss value Set MSS value\n"
+" --ecn Set ECN\n");
+}
+
+static const struct xt_option_entry SYNPROXY_opts[] = {
+ {.name = "sack-perm", .id = O_SACK_PERM, .type = XTTYPE_NONE, },
+ {.name = "timestamp", .id = O_TIMESTAMP, .type = XTTYPE_NONE, },
+ {.name = "wscale", .id = O_WSCALE, .type = XTTYPE_UINT32, },
+ {.name = "mss", .id = O_MSS, .type = XTTYPE_UINT32, },
+ {.name = "ecn", .id = O_ECN, .type = XTTYPE_NONE, },
+ XTOPT_TABLEEND,
+};
+
+static void SYNPROXY_parse(struct xt_option_call *cb)
+{
+ struct xt_synproxy_info *info = cb->data;
+
+ xtables_option_parse(cb);
+ switch (cb->entry->id) {
+ case O_SACK_PERM:
+ info->options |= XT_SYNPROXY_OPT_SACK_PERM;
+ break;
+ case O_TIMESTAMP:
+ info->options |= XT_SYNPROXY_OPT_TIMESTAMP;
+ break;
+ case O_WSCALE:
+ info->options |= XT_SYNPROXY_OPT_WSCALE;
+ info->wscale = cb->val.u32;
+ break;
+ case O_MSS:
+ info->options |= XT_SYNPROXY_OPT_MSS;
+ info->mss = cb->val.u32;
+ break;
+ case O_ECN:
+ info->options |= XT_SYNPROXY_OPT_ECN;
+ break;
+ }
+}
+
+static void SYNPROXY_check(struct xt_fcheck_call *cb)
+{
+}
+
+static void SYNPROXY_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ const struct xt_synproxy_info *info =
+ (const struct xt_synproxy_info *)target->data;
+
+ printf(" SYNPROXY ");
+ if (info->options & XT_SYNPROXY_OPT_SACK_PERM)
+ printf("sack-perm ");
+ if (info->options & XT_SYNPROXY_OPT_TIMESTAMP)
+ printf("timestamp ");
+ if (info->options & XT_SYNPROXY_OPT_WSCALE)
+ printf("wscale %u ", info->wscale);
+ if (info->options & XT_SYNPROXY_OPT_MSS)
+ printf("mss %u ", info->mss);
+ if (info->options & XT_SYNPROXY_OPT_ECN)
+ printf("ecn ");
+}
+
+static void SYNPROXY_save(const void *ip, const struct xt_entry_target *target)
+{
+ const struct xt_synproxy_info *info =
+ (const struct xt_synproxy_info *)target->data;
+
+ if (info->options & XT_SYNPROXY_OPT_SACK_PERM)
+ printf(" --sack-perm");
+ if (info->options & XT_SYNPROXY_OPT_TIMESTAMP)
+ printf(" --timestamp");
+ if (info->options & XT_SYNPROXY_OPT_WSCALE)
+ printf(" --wscale %u", info->wscale);
+ if (info->options & XT_SYNPROXY_OPT_MSS)
+ printf(" --mss %u", info->mss);
+ if (info->options & XT_SYNPROXY_OPT_ECN)
+ printf(" --ecn");
+}
+
+static struct xtables_target synproxy_tg_reg = {
+ .family = NFPROTO_UNSPEC,
+ .name = "SYNPROXY",
+ .version = XTABLES_VERSION,
+ .revision = 0,
+ .size = XT_ALIGN(sizeof(struct xt_synproxy_info)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_synproxy_info)),
+ .help = SYNPROXY_help,
+ .print = SYNPROXY_print,
+ .save = SYNPROXY_save,
+ .x6_parse = SYNPROXY_parse,
+ .x6_fcheck = SYNPROXY_check,
+ .x6_options = SYNPROXY_opts,
+};
+
+void _init(void)
+{
+ xtables_register_target(&synproxy_tg_reg);
+}
diff --git a/extensions/libxt_SYNPROXY.man b/extensions/libxt_SYNPROXY.man
new file mode 100644
index 00000000..25325fc2
--- /dev/null
+++ b/extensions/libxt_SYNPROXY.man
@@ -0,0 +1,64 @@
+This target will process TCP three-way-handshake parallel in netfilter
+context to protect either local or backend system. This target requires
+connection tracking because sequence numbers need to be translated.
+.TP
+\fB\-\-mss\fP \fImaximum segment size\fP
+Maximum segment size announced to clients. This must match the backend.
+.TP
+\fB\-\-wscale\fP \fIwindow scale\fP
+Window scale announced to clients. This must match the backend.
+.TP
+\fB\-\-sack\-perm\fP
+Pass client selective acknowledgement option to backend (will be disabled
+if not present).
+.TP
+\fB\-\-timestamps\fP
+Pass client timestamp option to backend (will be disabled if not present,
+also needed for selective acknowledgement and window scaling).
+.PP
+Example:
+.PP
+Determine tcp options used by backend, from an external system
+.IP
+tcpdump -pni eth0 -c 1 'tcp[tcpflags] == (tcp-syn|tcp-ack)'
+.br
+ port 80 &
+.br
+telnet 192.0.2.42 80
+.br
+18:57:24.693307 IP 192.0.2.42.80 > 192.0.2.43.48757:
+.br
+ Flags [S.], seq 360414582, ack 788841994, win 14480,
+.br
+ options [mss 1460,sackOK,
+.br
+ TS val 1409056151 ecr 9690221,
+.br
+ nop,wscale 9],
+.br
+ length 0
+.PP
+Switch tcp_loose mode off, so conntrack will mark out\-of\-flow
+packets as state INVALID.
+.IP
+echo 0 > /proc/sys/net/netfilter/nf_conntrack_tcp_loose
+.PP
+Make SYN packets untracked
+.IP
+iptables \-t raw \-A PREROUTING \-i eth0 \-p tcp \-\-dport 80
+ \-\-syn \-j CT \-\-notrack
+.PP
+Catch UNTRACKED (SYN packets) and INVALID (3WHS ACK packets) states
+and send them to SYNPROXY. This rule will respond to SYN packets with
+SYN+ACK syncookies, create ESTABLISHED for valid client response (3WHS ACK
+packets) and drop incorrect cookies. Flags combinations not expected
+during 3WHS will not match and continue (e.g. SYN+FIN, SYN+ACK).
+.IP
+iptables \-A INPUT \-i eth0 \-p tcp \-\-dport 80
+ \-m state \-\-state UNTRACKED,INVALID \-j SYNPROXY
+ \-\-sack\-perm \-\-timestamp \-\-mss 1460 \-\-wscale 9
+.PP
+Drop invalid packets, this will be out\-of\-flow packets that were not
+matched by SYNPROXY.
+.IP
+iptables \-A INPUT \-i eth0 \-p tcp \-\-dport 80 \-m state \-\-state INVALID \-j DROP
diff --git a/extensions/libxt_SYNPROXY.t b/extensions/libxt_SYNPROXY.t
new file mode 100644
index 00000000..dd8b0e76
--- /dev/null
+++ b/extensions/libxt_SYNPROXY.t
@@ -0,0 +1,3 @@
+:INPUT,FORWARD
+-j SYNPROXY --sack-perm --timestamp --mss 1460 --wscale 9;;FAIL
+-p tcp -m tcp --dport 42 -m conntrack --ctstate INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 9 --mss 1460;=;OK
diff --git a/extensions/libxt_TCPMSS.t b/extensions/libxt_TCPMSS.t
new file mode 100644
index 00000000..553a3452
--- /dev/null
+++ b/extensions/libxt_TCPMSS.t
@@ -0,0 +1,6 @@
+:FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j TCPMSS;;FAIL
+-p tcp -j TCPMSS --set-mss 42;;FAIL
+-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j TCPMSS --set-mss 42;=;OK
+-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j TCPMSS --clamp-mss-to-pmtu;=;OK
diff --git a/extensions/libxt_TCPOPTSTRIP.c b/extensions/libxt_TCPOPTSTRIP.c
index 68978573..6ea34892 100644
--- a/extensions/libxt_TCPOPTSTRIP.c
+++ b/extensions/libxt_TCPOPTSTRIP.c
@@ -12,6 +12,21 @@
#ifndef TCPOPT_MD5SIG
# define TCPOPT_MD5SIG 19
#endif
+#ifndef TCPOPT_MAXSEG
+# define TCPOPT_MAXSEG 2
+#endif
+#ifndef TCPOPT_WINDOW
+# define TCPOPT_WINDOW 3
+#endif
+#ifndef TCPOPT_SACK_PERMITTED
+# define TCPOPT_SACK_PERMITTED 4
+#endif
+#ifndef TCPOPT_SACK
+# define TCPOPT_SACK 5
+#endif
+#ifndef TCPOPT_TIMESTAMP
+# define TCPOPT_TIMESTAMP 8
+#endif
enum {
O_STRIP_OPTION = 0,
diff --git a/extensions/libxt_TCPOPTSTRIP.t b/extensions/libxt_TCPOPTSTRIP.t
new file mode 100644
index 00000000..b5c7a109
--- /dev/null
+++ b/extensions/libxt_TCPOPTSTRIP.t
@@ -0,0 +1,8 @@
+:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j TCPOPTSTRIP;;FAIL
+-p tcp -j TCPOPTSTRIP;=;OK
+-p tcp -j TCPOPTSTRIP --strip-options 2,3,4,5,6,7;=;OK
+-p tcp -j TCPOPTSTRIP --strip-options 0;;FAIL
+-p tcp -j TCPOPTSTRIP --strip-options 1;;FAIL
+-p tcp -j TCPOPTSTRIP --strip-options 1,2;;FAIL
diff --git a/extensions/libxt_TEE.c b/extensions/libxt_TEE.c
index 66c060d3..4676e33b 100644
--- a/extensions/libxt_TEE.c
+++ b/extensions/libxt_TEE.c
@@ -92,6 +92,40 @@ static void tee_tg6_save(const void *ip, const struct xt_entry_target *target)
printf(" --oif %s", info->oif);
}
+static int tee_tg_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_tee_tginfo *info = (const void *)params->target->data;
+
+ if (params->numeric)
+ xt_xlate_add(xl, "dup to %s",
+ xtables_ipaddr_to_numeric(&info->gw.in));
+ else
+ xt_xlate_add(xl, "dup to %s",
+ xtables_ipaddr_to_anyname(&info->gw.in));
+ if (*info->oif != '\0')
+ xt_xlate_add(xl, " device %s", info->oif);
+
+ return 1;
+}
+
+static int tee_tg6_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ const struct xt_tee_tginfo *info = (const void *)params->target->data;
+
+ if (params->numeric)
+ xt_xlate_add(xl, "dup to %s",
+ xtables_ip6addr_to_numeric(&info->gw.in6));
+ else
+ xt_xlate_add(xl, "dup to %s",
+ xtables_ip6addr_to_anyname(&info->gw.in6));
+ if (*info->oif != '\0')
+ xt_xlate_add(xl, " device %s", info->oif);
+
+ return 1;
+}
+
static struct xtables_target tee_tg_reg[] = {
{
.name = "TEE",
@@ -105,6 +139,7 @@ static struct xtables_target tee_tg_reg[] = {
.save = tee_tg_save,
.x6_parse = xtables_option_parse,
.x6_options = tee_tg_opts,
+ .xlate = tee_tg_xlate,
},
{
.name = "TEE",
@@ -118,6 +153,7 @@ static struct xtables_target tee_tg_reg[] = {
.save = tee_tg6_save,
.x6_parse = xtables_option_parse,
.x6_options = tee_tg_opts,
+ .xlate = tee_tg6_xlate,
},
};
diff --git a/extensions/libxt_TEE.t b/extensions/libxt_TEE.t
new file mode 100644
index 00000000..ce8b103e
--- /dev/null
+++ b/extensions/libxt_TEE.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+-j TEE --gateway 1.1.1.1;=;OK
+-j TEE ! --gateway 1.1.1.1;;FAIL
+-j TEE;;FAIL
diff --git a/extensions/libxt_TOS.t b/extensions/libxt_TOS.t
new file mode 100644
index 00000000..ae8531cc
--- /dev/null
+++ b/extensions/libxt_TOS.t
@@ -0,0 +1,16 @@
+:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-j TOS --set-tos 0x1f;=;OK
+-j TOS --set-tos 0x1f/0x1f;=;OK
+# maximum TOS is 0x1f (5 bits)
+# ERROR: should fail: iptables -A PREROUTING -t mangle -j TOS --set-tos 0xff
+# -j TOS --set-tos 0xff;;FAIL
+-j TOS --set-tos Minimize-Delay;-j TOS --set-tos 0x10;OK
+-j TOS --set-tos Maximize-Throughput;-j TOS --set-tos 0x08;OK
+-j TOS --set-tos Maximize-Reliability;-j TOS --set-tos 0x04;OK
+-j TOS --set-tos Minimize-Cost;-j TOS --set-tos 0x02;OK
+-j TOS --set-tos Normal-Service;-j TOS --set-tos 0x00;OK
+-j TOS --and-tos 0x12;-j TOS --set-tos 0x00/0xed;OK
+-j TOS --or-tos 0x12;-j TOS --set-tos 0x12/0x12;OK
+-j TOS --xor-tos 0x12;-j TOS --set-tos 0x12/0x00;OK
+-j TOS;;FAIL
diff --git a/extensions/libxt_TPROXY.t b/extensions/libxt_TPROXY.t
new file mode 100644
index 00000000..12f82b1f
--- /dev/null
+++ b/extensions/libxt_TPROXY.t
@@ -0,0 +1,5 @@
+:PREROUTING
+*mangle
+-j TPROXY --on-port 12345 --on-ip 10.0.0.1 --tproxy-mark 0x23/0xff;;FAIL
+-p udp -j TPROXY --on-port 12345 --on-ip 10.0.0.1 --tproxy-mark 0x23/0xff;=;OK
+-p tcp -m tcp --dport 2342 -j TPROXY --on-port 12345 --on-ip 10.0.0.1 --tproxy-mark 0x23/0xff;=;OK
diff --git a/extensions/libxt_TRACE.c b/extensions/libxt_TRACE.c
index 0282e6ff..ac4f6fab 100644
--- a/extensions/libxt_TRACE.c
+++ b/extensions/libxt_TRACE.c
@@ -7,12 +7,20 @@
#include <xtables.h>
#include <linux/netfilter/x_tables.h>
+static int trace_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_tg_params *params)
+{
+ xt_xlate_add(xl, "nftrace set 1");
+ return 1;
+}
+
static struct xtables_target trace_target = {
.family = NFPROTO_UNSPEC,
.name = "TRACE",
.version = XTABLES_VERSION,
.size = XT_ALIGN(0),
.userspacesize = XT_ALIGN(0),
+ .xlate = trace_xlate,
};
void _init(void)
diff --git a/extensions/libxt_TRACE.t b/extensions/libxt_TRACE.t
new file mode 100644
index 00000000..cadb7330
--- /dev/null
+++ b/extensions/libxt_TRACE.t
@@ -0,0 +1,3 @@
+:PREROUTING,OUTPUT
+*raw
+-j TRACE;=;OK
diff --git a/extensions/libxt_addrtype.t b/extensions/libxt_addrtype.t
new file mode 100644
index 00000000..390a63f0
--- /dev/null
+++ b/extensions/libxt_addrtype.t
@@ -0,0 +1,17 @@
+:INPUT,FORWARD,OUTPUT
+-m addrtype;;FAIL
+-m addrtype --src-type wrong;;FAIL
+-m addrtype --src-type UNSPEC;=;OK
+-m addrtype --dst-type UNSPEC;=;OK
+-m addrtype --src-type LOCAL --dst-type LOCAL;=;OK
+-m addrtype --dst-type UNSPEC;=;OK
+-m addrtype --limit-iface-in;;FAIL
+-m addrtype --limit-iface-out;;FAIL
+-m addrtype --limit-iface-in --limit-iface-out;;FAIL
+-m addrtype --src-type LOCAL --limit-iface-in --limit-iface-out;;FAIL
+:INPUT
+-m addrtype --src-type LOCAL --limit-iface-in;=;OK
+-m addrtype --dst-type LOCAL --limit-iface-in;=;OK
+:OUTPUT
+-m addrtype --src-type LOCAL --limit-iface-out;=;OK
+-m addrtype --dst-type LOCAL --limit-iface-out;=;OK
diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c
index dca97d70..92c445e8 100644
--- a/extensions/libxt_bpf.c
+++ b/extensions/libxt_bpf.c
@@ -16,11 +16,17 @@
#include <sys/types.h>
#include <unistd.h>
#include <xtables.h>
+#include "config.h"
+
+#ifdef HAVE_LINUX_BPF_H
+#include <linux/bpf.h>
+#endif
#define BCODE_FILE_MAX_LEN_B 1024
enum {
O_BCODE_STDIN = 0,
+ O_OBJ_PINNED = 1,
};
static void bpf_help(void)
@@ -28,7 +34,16 @@ static void bpf_help(void)
printf(
"bpf match options:\n"
"--bytecode <program> : a bpf program as generated by\n"
-" `nfbpf_compiler RAW <filter>`\n");
+" $(nfbpf_compile RAW '<filter>')\n");
+}
+
+static void bpf_help_v1(void)
+{
+ printf(
+"bpf match options:\n"
+"--bytecode <program> : a bpf program as generated by\n"
+" $(nfbpf_compile RAW '<filter>')\n"
+"--object-pinned <bpf object> : a path to a pinned BPF object in bpf fs\n");
}
static const struct xt_option_entry bpf_opts[] = {
@@ -36,23 +51,47 @@ static const struct xt_option_entry bpf_opts[] = {
XTOPT_TABLEEND,
};
-static void bpf_parse_string(struct xt_option_call *cb, const char *bpf_program,
- const char separator)
+static const struct xt_option_entry bpf_opts_v1[] = {
+ {.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING},
+ {.name = "object-pinned" , .id = O_OBJ_PINNED, .type = XTTYPE_STRING,
+ .flags = XTOPT_PUT, XTOPT_POINTER(struct xt_bpf_info_v1, path)},
+ XTOPT_TABLEEND,
+};
+
+static int bpf_obj_get(const char *filepath)
{
- struct xt_bpf_info *bi = (void *) cb->data;
+#if defined HAVE_LINUX_BPF_H && defined __NR_bpf
+ union bpf_attr attr;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.pathname = (__u64) filepath;
+
+ return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
+#else
+ xtables_error(OTHER_PROBLEM,
+ "No bpf header, kernel headers too old?\n");
+ return -EINVAL;
+#endif
+}
+
+static void bpf_parse_string(struct sock_filter *pc, __u16 *lenp, __u16 len_max,
+ const char *bpf_program)
+{
+ const char separator = ',';
const char *token;
char sp;
int i;
+ __u16 len;
/* parse head: length. */
- if (sscanf(bpf_program, "%hu%c", &bi->bpf_program_num_elem, &sp) != 2 ||
+ if (sscanf(bpf_program, "%hu%c", &len, &sp) != 2 ||
sp != separator)
xtables_error(PARAMETER_PROBLEM,
"bpf: error parsing program length");
- if (!bi->bpf_program_num_elem)
+ if (!len)
xtables_error(PARAMETER_PROBLEM,
"bpf: illegal zero length program");
- if (bi->bpf_program_num_elem > XT_BPF_MAX_NUM_INSTR)
+ if (len > len_max)
xtables_error(PARAMETER_PROBLEM,
"bpf: number of instructions exceeds maximum");
@@ -60,62 +99,108 @@ static void bpf_parse_string(struct xt_option_call *cb, const char *bpf_program,
i = 0;
token = bpf_program;
while ((token = strchr(token, separator)) && (++token)[0]) {
- if (i >= bi->bpf_program_num_elem)
+ if (i >= len)
xtables_error(PARAMETER_PROBLEM,
"bpf: real program length exceeds"
" the encoded length parameter");
if (sscanf(token, "%hu %hhu %hhu %u,",
- &bi->bpf_program[i].code,
- &bi->bpf_program[i].jt,
- &bi->bpf_program[i].jf,
- &bi->bpf_program[i].k) != 4)
+ &pc->code, &pc->jt, &pc->jf, &pc->k) != 4)
xtables_error(PARAMETER_PROBLEM,
"bpf: error at instr %d", i);
i++;
+ pc++;
}
- if (i != bi->bpf_program_num_elem)
+ if (i != len)
xtables_error(PARAMETER_PROBLEM,
"bpf: parsed program length is less than the"
" encoded length parameter");
+
+ *lenp = len;
+}
+
+static void bpf_parse_obj_pinned(struct xt_bpf_info_v1 *bi,
+ const char *filepath)
+{
+ bi->fd = bpf_obj_get(filepath);
+ if (bi->fd < 0)
+ xtables_error(PARAMETER_PROBLEM,
+ "bpf: failed to get bpf object");
+
+ /* Cannot close bi->fd explicitly. Rely on exit */
+ if (fcntl(bi->fd, F_SETFD, FD_CLOEXEC) == -1) {
+ xtables_error(OTHER_PROBLEM,
+ "Could not set close on exec: %s\n",
+ strerror(errno));
+ }
}
static void bpf_parse(struct xt_option_call *cb)
{
+ struct xt_bpf_info *bi = (void *) cb->data;
+
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_BCODE_STDIN:
- bpf_parse_string(cb, cb->arg, ',');
+ bpf_parse_string(bi->bpf_program, &bi->bpf_program_num_elem,
+ ARRAY_SIZE(bi->bpf_program), cb->arg);
break;
default:
xtables_error(PARAMETER_PROBLEM, "bpf: unknown option");
}
}
-static void bpf_print_code(const void *ip, const struct xt_entry_match *match)
+static void bpf_parse_v1(struct xt_option_call *cb)
{
- const struct xt_bpf_info *info = (void *) match->data;
- int i;
+ struct xt_bpf_info_v1 *bi = (void *) cb->data;
+
+ xtables_option_parse(cb);
+ switch (cb->entry->id) {
+ case O_BCODE_STDIN:
+ bpf_parse_string(bi->bpf_program, &bi->bpf_program_num_elem,
+ ARRAY_SIZE(bi->bpf_program), cb->arg);
+ bi->mode = XT_BPF_MODE_BYTECODE;
+ break;
+ case O_OBJ_PINNED:
+ bpf_parse_obj_pinned(bi, cb->arg);
+ bi->mode = XT_BPF_MODE_FD_PINNED;
+ break;
+ default:
+ xtables_error(PARAMETER_PROBLEM, "bpf: unknown option");
+ }
+}
- for (i = 0; i < info->bpf_program_num_elem-1; i++)
- printf("%hu %hhu %hhu %u,", info->bpf_program[i].code,
- info->bpf_program[i].jt,
- info->bpf_program[i].jf,
- info->bpf_program[i].k);
+static void bpf_print_code(const struct sock_filter *pc, __u16 len, char tail)
+{
+ for (; len; len--, pc++)
+ printf("%hu %hhu %hhu %u%c",
+ pc->code, pc->jt, pc->jf, pc->k,
+ len > 1 ? ',' : tail);
+}
- printf("%hu %hhu %hhu %u", info->bpf_program[i].code,
- info->bpf_program[i].jt,
- info->bpf_program[i].jf,
- info->bpf_program[i].k);
+static void bpf_save_code(const struct sock_filter *pc, __u16 len)
+{
+ printf(" --bytecode \"%hu,", len);
+ bpf_print_code(pc, len, '\"');
}
static void bpf_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_bpf_info *info = (void *) match->data;
- printf(" --bytecode \"%hu,", info->bpf_program_num_elem);
- bpf_print_code(ip, match);
- printf("\"");
+ bpf_save_code(info->bpf_program, info->bpf_program_num_elem);
+}
+
+static void bpf_save_v1(const void *ip, const struct xt_entry_match *match)
+{
+ const struct xt_bpf_info_v1 *info = (void *) match->data;
+
+ if (info->mode == XT_BPF_MODE_BYTECODE)
+ bpf_save_code(info->bpf_program, info->bpf_program_num_elem);
+ else if (info->mode == XT_BPF_MODE_FD_PINNED)
+ printf(" --object-pinned %s", info->path);
+ else
+ xtables_error(OTHER_PROBLEM, "unknown bpf mode");
}
static void bpf_fcheck(struct xt_fcheck_call *cb)
@@ -125,28 +210,73 @@ static void bpf_fcheck(struct xt_fcheck_call *cb)
"bpf: missing --bytecode parameter");
}
+static void bpf_fcheck_v1(struct xt_fcheck_call *cb)
+{
+ const unsigned int bit_bcode = 1 << O_BCODE_STDIN;
+ const unsigned int bit_pinned = 1 << O_OBJ_PINNED;
+ unsigned int flags;
+
+ flags = cb->xflags & (bit_bcode | bit_pinned);
+ if (flags != bit_bcode && flags != bit_pinned)
+ xtables_error(PARAMETER_PROBLEM,
+ "bpf: one of --bytecode or --pinned is required");
+}
+
static void bpf_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
+ const struct xt_bpf_info *info = (void *) match->data;
+
+ printf("match bpf ");
+ bpf_print_code(info->bpf_program, info->bpf_program_num_elem, '\0');
+}
+
+static void bpf_print_v1(const void *ip, const struct xt_entry_match *match,
+ int numeric)
+{
+ const struct xt_bpf_info_v1 *info = (void *) match->data;
+
printf("match bpf ");
- return bpf_print_code(ip, match);
-}
-
-static struct xtables_match bpf_match = {
- .family = NFPROTO_UNSPEC,
- .name = "bpf",
- .version = XTABLES_VERSION,
- .size = XT_ALIGN(sizeof(struct xt_bpf_info)),
- .userspacesize = XT_ALIGN(offsetof(struct xt_bpf_info, filter)),
- .help = bpf_help,
- .print = bpf_print,
- .save = bpf_save,
- .x6_parse = bpf_parse,
- .x6_fcheck = bpf_fcheck,
- .x6_options = bpf_opts,
+ if (info->mode == XT_BPF_MODE_BYTECODE)
+ bpf_print_code(info->bpf_program, info->bpf_program_num_elem, '\0');
+ else if (info->mode == XT_BPF_MODE_FD_PINNED)
+ printf("pinned %s", info->path);
+ else
+ printf("unknown");
+}
+
+static struct xtables_match bpf_matches[] = {
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "bpf",
+ .version = XTABLES_VERSION,
+ .revision = 0,
+ .size = XT_ALIGN(sizeof(struct xt_bpf_info)),
+ .userspacesize = XT_ALIGN(offsetof(struct xt_bpf_info, filter)),
+ .help = bpf_help,
+ .print = bpf_print,
+ .save = bpf_save,
+ .x6_parse = bpf_parse,
+ .x6_fcheck = bpf_fcheck,
+ .x6_options = bpf_opts,
+ },
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "bpf",
+ .version = XTABLES_VERSION,
+ .revision = 1,
+ .size = XT_ALIGN(sizeof(struct xt_bpf_info_v1)),
+ .userspacesize = XT_ALIGN(offsetof(struct xt_bpf_info_v1, filter)),
+ .help = bpf_help_v1,
+ .print = bpf_print_v1,
+ .save = bpf_save_v1,
+ .x6_parse = bpf_parse_v1,
+ .x6_fcheck = bpf_fcheck_v1,
+ .x6_options = bpf_opts_v1,
+ },
};
void _init(void)
{
- xtables_register_match(&bpf_match);
+ xtables_register_matches(bpf_matches, ARRAY_SIZE(bpf_matches));
}
diff --git a/extensions/libxt_bpf.man b/extensions/libxt_bpf.man
index 5b1d0424..1d2aa9e6 100644
--- a/extensions/libxt_bpf.man
+++ b/extensions/libxt_bpf.man
@@ -1,8 +1,21 @@
-Match using Linux Socket Filter. Expects a BPF program in decimal format. This
-is the format generated by the \fBnfbpf_compile\fP utility.
+Match using Linux Socket Filter. Expects a path to an eBPF object or a cBPF
+program in decimal format.
+.TP
+\fB\-\-object\-pinned\fP \fIpath\fP
+Pass a path to a pinned eBPF object.
+.PP
+Applications load eBPF programs into the kernel with the bpf() system call and
+BPF_PROG_LOAD command and can pin them in a virtual filesystem with BPF_OBJ_PIN.
+To use a pinned object in iptables, mount the bpf filesystem using
+.IP
+mount \-t bpf bpf ${BPF_MOUNT}
+.PP
+then insert the filter in iptables by path:
+.IP
+iptables \-A OUTPUT \-m bpf \-\-object\-pinned ${BPF_MOUNT}/{PINNED_PATH} \-j ACCEPT
.TP
\fB\-\-bytecode\fP \fIcode\fP
-Pass the BPF byte code format (described in the example below).
+Pass the BPF byte code format as generated by the \fBnfbpf_compile\fP utility.
.PP
The code format is similar to the output of the tcpdump -ddd command: one line
that stores the number of instructions, followed by one line for each
@@ -31,4 +44,17 @@ Or instead, you can invoke the nfbpf_compile utility.
.IP
iptables \-A OUTPUT \-m bpf \-\-bytecode "`nfbpf_compile RAW 'ip proto 6'`" \-j ACCEPT
.PP
+Or use tcpdump -ddd. In that case, generate BPF targeting a device with the
+same data link type as the xtables match. Iptables passes packets from the
+network layer up, without mac layer. Select a device with data link type RAW,
+such as a tun device:
+.IP
+ip tuntap add tun0 mode tun
+.br
+ip link set tun0 up
+.br
+tcpdump -ddd -i tun0 ip proto 6
+.PP
+See tcpdump -L -i $dev for a list of known data link types for a given device.
+.PP
You may want to learn more about BPF from FreeBSD's bpf(4) manpage.
diff --git a/extensions/libxt_bpf.t b/extensions/libxt_bpf.t
new file mode 100644
index 00000000..80361ad5
--- /dev/null
+++ b/extensions/libxt_bpf.t
@@ -0,0 +1,2 @@
+:INPUT,FORWARD,OUTPUT
+-m bpf --bytecode "4,48 0 0 9,21 0 1 6,6 0 0 1,6 0 0 0";=;OK
diff --git a/extensions/libxt_cgroup.c b/extensions/libxt_cgroup.c
new file mode 100644
index 00000000..480d64c9
--- /dev/null
+++ b/extensions/libxt_cgroup.c
@@ -0,0 +1,184 @@
+#include <stdio.h>
+#include <xtables.h>
+#include <linux/netfilter/xt_cgroup.h>
+
+enum {
+ O_CLASSID = 0,
+ O_PATH = 1,
+};
+
+static void cgroup_help_v0(void)
+{
+ printf(
+"cgroup match options:\n"
+"[!] --cgroup classid Match cgroup classid\n");
+}
+
+static void cgroup_help_v1(void)
+{
+ printf(
+"cgroup match options:\n"
+"[!] --path path Recursively match path relative to cgroup2 root\n"
+"[!] --cgroup classid Match cgroup classid, can't be used with --path\n");
+}
+
+static const struct xt_option_entry cgroup_opts_v0[] = {
+ {
+ .name = "cgroup",
+ .id = O_CLASSID,
+ .type = XTTYPE_UINT32,
+ .flags = XTOPT_INVERT | XTOPT_MAND | XTOPT_PUT,
+ XTOPT_POINTER(struct xt_cgroup_info_v0, id)
+ },
+ XTOPT_TABLEEND,
+};
+
+static const struct xt_option_entry cgroup_opts_v1[] = {
+ {
+ .name = "path",
+ .id = O_PATH,
+ .type = XTTYPE_STRING,
+ .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct xt_cgroup_info_v1, path)
+ },
+ {
+ .name = "cgroup",
+ .id = O_CLASSID,
+ .type = XTTYPE_UINT32,
+ .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct xt_cgroup_info_v1, classid)
+ },
+ XTOPT_TABLEEND,
+};
+
+static void cgroup_parse_v0(struct xt_option_call *cb)
+{
+ struct xt_cgroup_info_v0 *cgroupinfo = cb->data;
+
+ xtables_option_parse(cb);
+ if (cb->invert)
+ cgroupinfo->invert = true;
+}
+
+static void cgroup_parse_v1(struct xt_option_call *cb)
+{
+ struct xt_cgroup_info_v1 *info = cb->data;
+
+ xtables_option_parse(cb);
+
+ switch (cb->entry->id) {
+ case O_PATH:
+ info->has_path = true;
+ if (cb->invert)
+ info->invert_path = true;
+ break;
+ case O_CLASSID:
+ info->has_classid = true;
+ if (cb->invert)
+ info->invert_classid = true;
+ break;
+ }
+}
+
+static void
+cgroup_print_v0(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+ const struct xt_cgroup_info_v0 *info = (void *) match->data;
+
+ printf(" cgroup %s%u", info->invert ? "! ":"", info->id);
+}
+
+static void cgroup_save_v0(const void *ip, const struct xt_entry_match *match)
+{
+ const struct xt_cgroup_info_v0 *info = (void *) match->data;
+
+ printf("%s --cgroup %u", info->invert ? " !" : "", info->id);
+}
+
+static void
+cgroup_print_v1(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+ const struct xt_cgroup_info_v1 *info = (void *)match->data;
+
+ printf(" cgroup");
+ if (info->has_path)
+ printf(" %s%s", info->invert_path ? "! ":"", info->path);
+ if (info->has_classid)
+ printf(" %s%u", info->invert_classid ? "! ":"", info->classid);
+}
+
+static void cgroup_save_v1(const void *ip, const struct xt_entry_match *match)
+{
+ const struct xt_cgroup_info_v1 *info = (void *)match->data;
+
+ if (info->has_path) {
+ printf("%s --path", info->invert_path ? " !" : "");
+ xtables_save_string(info->path);
+ }
+
+ if (info->has_classid)
+ printf("%s --cgroup %u", info->invert_classid ? " !" : "",
+ info->classid);
+}
+
+static int cgroup_xlate_v0(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_cgroup_info_v0 *info = (void *)params->match->data;
+
+ xt_xlate_add(xl, "meta cgroup %s%u", info->invert ? "!= " : "",
+ info->id);
+ return 1;
+}
+
+static int cgroup_xlate_v1(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_cgroup_info_v1 *info = (void *)params->match->data;
+
+ if (info->has_path)
+ return 0;
+
+ if (info->has_classid)
+ xt_xlate_add(xl, "meta cgroup %s%u",
+ info->invert_classid ? "!= " : "",
+ info->classid);
+
+ return 1;
+}
+
+static struct xtables_match cgroup_match[] = {
+ {
+ .family = NFPROTO_UNSPEC,
+ .revision = 0,
+ .name = "cgroup",
+ .version = XTABLES_VERSION,
+ .size = XT_ALIGN(sizeof(struct xt_cgroup_info_v0)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_cgroup_info_v0)),
+ .help = cgroup_help_v0,
+ .print = cgroup_print_v0,
+ .save = cgroup_save_v0,
+ .x6_parse = cgroup_parse_v0,
+ .x6_options = cgroup_opts_v0,
+ .xlate = cgroup_xlate_v0,
+ },
+ {
+ .family = NFPROTO_UNSPEC,
+ .revision = 1,
+ .name = "cgroup",
+ .version = XTABLES_VERSION,
+ .size = XT_ALIGN(sizeof(struct xt_cgroup_info_v1)),
+ .userspacesize = offsetof(struct xt_cgroup_info_v1, priv),
+ .help = cgroup_help_v1,
+ .print = cgroup_print_v1,
+ .save = cgroup_save_v1,
+ .x6_parse = cgroup_parse_v1,
+ .x6_options = cgroup_opts_v1,
+ .xlate = cgroup_xlate_v1,
+ },
+};
+
+void _init(void)
+{
+ xtables_register_matches(cgroup_match, ARRAY_SIZE(cgroup_match));
+}
diff --git a/extensions/libxt_cgroup.man b/extensions/libxt_cgroup.man
new file mode 100644
index 00000000..4d5d1d86
--- /dev/null
+++ b/extensions/libxt_cgroup.man
@@ -0,0 +1,30 @@
+.TP
+[\fB!\fP] \fB\-\-path\fP \fIpath\fP
+Match cgroup2 membership.
+
+Each socket is associated with the v2 cgroup of the creating process.
+This matches packets coming from or going to all sockets in the
+sub-hierarchy of the specified path. The path should be relative to
+the root of the cgroup2 hierarchy.
+.TP
+[\fB!\fP] \fB\-\-cgroup\fP \fIclassid\fP
+Match cgroup net_cls classid.
+
+classid is the marker set through the cgroup net_cls controller. This
+option and \-\-path can't be used together.
+.PP
+Example:
+.IP
+iptables \-A OUTPUT \-p tcp \-\-sport 80 \-m cgroup ! \-\-path service/http-server \-j DROP
+.IP
+iptables \-A OUTPUT \-p tcp \-\-sport 80 \-m cgroup ! \-\-cgroup 1
+\-j DROP
+.PP
+\fBIMPORTANT\fP: when being used in the INPUT chain, the cgroup
+matcher is currently only of limited functionality, meaning it
+will only match on packets that are processed for local sockets
+through early socket demuxing. Therefore, general usage on the
+INPUT chain is not advised unless the implications are well
+understood.
+.PP
+Available since Linux 3.14.
diff --git a/extensions/libxt_cgroup.t b/extensions/libxt_cgroup.t
new file mode 100644
index 00000000..72c8e377
--- /dev/null
+++ b/extensions/libxt_cgroup.t
@@ -0,0 +1,8 @@
+:INPUT,OUTPUT,POSTROUTING
+*mangle
+-m cgroup --cgroup 1;=;OK
+-m cgroup ! --cgroup 1;=;OK
+-m cgroup --path "/";=;OK
+-m cgroup ! --path "/";=;OK
+-m cgroup --cgroup 1 --path "/";;FAIL
+-m cgroup ;;FAIL
diff --git a/extensions/libxt_cluster.man b/extensions/libxt_cluster.man
index 62ad71cc..94b4b205 100644
--- a/extensions/libxt_cluster.man
+++ b/extensions/libxt_cluster.man
@@ -55,6 +55,11 @@ arptables \-A INPUT \-i eth2 \-\-h\-length 6
\-\-destination\-mac 01:00:5e:00:01:02
\-j mangle \-\-mangle\-mac\-d 00:zz:yy:xx:5a:27
.PP
+\fBNOTE\fP: the arptables commands above use mainstream syntax. If you
+are using arptables-jf included in some RedHat, CentOS and Fedora
+versions, you will hit syntax errors. Therefore, you'll have to adapt
+these to the arptables-jf syntax to get them working.
+.PP
In the case of TCP connections, pickup facility has to be disabled
to avoid marking TCP ACK packets coming in the reply direction as
valid.
diff --git a/extensions/libxt_cluster.t b/extensions/libxt_cluster.t
new file mode 100644
index 00000000..ac608244
--- /dev/null
+++ b/extensions/libxt_cluster.t
@@ -0,0 +1,10 @@
+:PREROUTING,FORWARD,POSTROUTING
+*mangle
+-m cluster;;FAIL
+-m cluster --cluster-total-nodes 3;;FAIL
+-m cluster --cluster-total-nodes 2 --cluster-local-node 2;;FAIL
+-m cluster --cluster-total-nodes 2 --cluster-local-node 3 --cluster-hash-seed;;FAIL
+#
+# outputs --cluster-local-nodemask instead of --cluster-local-node
+#
+-m cluster --cluster-total-nodes 2 --cluster-local-node 2 --cluster-hash-seed 0xfeedcafe;-m cluster --cluster-local-nodemask 0x00000002 --cluster-total-nodes 2 --cluster-hash-seed 0xfeedcafe;OK
diff --git a/extensions/libxt_comment.c b/extensions/libxt_comment.c
index 6ed2ff9b..b635d16c 100644
--- a/extensions/libxt_comment.c
+++ b/extensions/libxt_comment.c
@@ -48,6 +48,26 @@ comment_save(const void *ip, const struct xt_entry_match *match)
xtables_save_string(commentinfo->comment);
}
+static int comment_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ struct xt_comment_info *commentinfo = (void *)params->match->data;
+ char comment[XT_MAX_COMMENT_LEN];
+
+ commentinfo->comment[XT_MAX_COMMENT_LEN - 1] = '\0';
+ if (params->escape_quotes)
+ snprintf(comment, XT_MAX_COMMENT_LEN, "\\\"%s\\\"",
+ commentinfo->comment);
+ else
+ snprintf(comment, XT_MAX_COMMENT_LEN, "\"%s\"",
+ commentinfo->comment);
+
+ comment[XT_MAX_COMMENT_LEN - 1] = '\0';
+ xt_xlate_add_comment(xl, comment);
+
+ return 1;
+}
+
static struct xtables_match comment_match = {
.family = NFPROTO_UNSPEC,
.name = "comment",
@@ -59,6 +79,7 @@ static struct xtables_match comment_match = {
.save = comment_save,
.x6_parse = xtables_option_parse,
.x6_options = comment_opts,
+ .xlate = comment_xlate,
};
void _init(void)
diff --git a/extensions/libxt_comment.t b/extensions/libxt_comment.t
new file mode 100644
index 00000000..f12cd668
--- /dev/null
+++ b/extensions/libxt_comment.t
@@ -0,0 +1,12 @@
+:INPUT,FORWARD,OUTPUT
+-m comment;;FAIL
+-m comment --comment;;FAIL
+#
+# it fails with 256 characters
+#
+# should fail: iptables -A INPUT -m comment --comment xxxxxxxxxxxxxxxxx [....]
+# -m comment --comment xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;;FAIL
+#
+# success with 255 characters
+#
+-m comment --comment xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
diff --git a/extensions/libxt_connbytes.t b/extensions/libxt_connbytes.t
new file mode 100644
index 00000000..6b24e266
--- /dev/null
+++ b/extensions/libxt_connbytes.t
@@ -0,0 +1,21 @@
+:INPUT,FORWARD,OUTPUT
+-m connbytes --connbytes 0:1000 --connbytes-mode packets --connbytes-dir original;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode packets --connbytes-dir reply;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode packets --connbytes-dir both;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode bytes --connbytes-dir original;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode bytes --connbytes-dir reply;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode bytes --connbytes-dir both;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode avgpkt --connbytes-dir original;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode avgpkt --connbytes-dir reply;=;OK
+-m connbytes --connbytes 0:1000 --connbytes-mode avgpkt --connbytes-dir both;=;OK
+-m connbytes --connbytes -1:0 --connbytes-mode packets --connbytes-dir original;;FAIL
+-m connbytes --connbytes 0:-1 --connbytes-mode packets --connbytes-dir original;;FAIL
+# ERROR: cannot find: iptables -I INPUT -m connbytes --connbytes 0:18446744073709551615 --connbytes-mode avgpkt --connbytes-dir both
+# -m connbytes --connbytes 0:18446744073709551615 --connbytes-mode avgpkt --connbytes-dir both;=;OK
+-m connbytes --connbytes 0:18446744073709551616 --connbytes-mode avgpkt --connbytes-dir both;;FAIL
+-m connbytes --connbytes 0:1000 --connbytes-mode wrong --connbytes-dir both;;FAIL
+-m connbytes --connbytes 0:1000 --connbytes-dir original;;FAIL
+-m connbytes --connbytes 0:1000 --connbytes-mode packets;;FAIL
+-m connbytes --connbytes-dir original;;FAIL
+-m connbytes --connbytes 0:1000;;FAIL
+-m connbytes;;FAIL
diff --git a/extensions/libxt_connlabel.c b/extensions/libxt_connlabel.c
index c84a1671..d06bb27a 100644
--- a/extensions/libxt_connlabel.c
+++ b/extensions/libxt_connlabel.c
@@ -29,11 +29,36 @@ static const struct xt_option_entry connlabel_mt_opts[] = {
XTOPT_TABLEEND,
};
+/* cannot do this via _init, else static builds might spew error message
+ * for every iptables invocation.
+ */
+static void connlabel_open(void)
+{
+ const char *fname;
+
+ if (map)
+ return;
+
+ map = nfct_labelmap_new(NULL);
+ if (map != NULL)
+ return;
+
+ fname = nfct_labels_get_path();
+ if (errno) {
+ xtables_error(RESOURCE_PROBLEM,
+ "cannot open %s: %s", fname, strerror(errno));
+ } else {
+ xtables_error(RESOURCE_PROBLEM,
+ "cannot parse %s: no labels found", fname);
+ }
+}
+
static void connlabel_mt_parse(struct xt_option_call *cb)
{
struct xt_connlabel_mtinfo *info = cb->data;
int tmp;
+ connlabel_open();
xtables_option_parse(cb);
switch (cb->entry->id) {
@@ -54,7 +79,11 @@ static void connlabel_mt_parse(struct xt_option_call *cb)
static const char *connlabel_get_name(int b)
{
- const char *name = nfct_labelmap_get_name(map, b);
+ const char *name;
+
+ connlabel_open();
+
+ name = nfct_labelmap_get_name(map, b);
if (name && strcmp(name, ""))
return name;
return NULL;
@@ -99,6 +128,27 @@ connlabel_mt_save(const void *ip, const struct xt_entry_match *match)
connlabel_mt_print_op(info, "--");
}
+static int connlabel_mt_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_connlabel_mtinfo *info =
+ (const void *)params->match->data;
+ const char *name = connlabel_get_name(info->bit);
+
+ if (name == NULL)
+ return 0;
+
+ if (info->options & XT_CONNLABEL_OP_SET)
+ xt_xlate_add(xl, "ct label set %s ", name);
+
+ xt_xlate_add(xl, "ct label ");
+ if (info->options & XT_CONNLABEL_OP_INVERT)
+ xt_xlate_add(xl, "and %s != ", name);
+ xt_xlate_add(xl, "%s", name);
+
+ return 1;
+}
+
static struct xtables_match connlabel_mt_reg = {
.family = NFPROTO_UNSPEC,
.name = "connlabel",
@@ -110,15 +160,10 @@ static struct xtables_match connlabel_mt_reg = {
.save = connlabel_mt_save,
.x6_parse = connlabel_mt_parse,
.x6_options = connlabel_mt_opts,
+ .xlate = connlabel_mt_xlate,
};
void _init(void)
{
- map = nfct_labelmap_new(NULL);
- if (!map) {
- fprintf(stderr, "cannot open connlabel.conf, not registering '%s' match: %s\n",
- connlabel_mt_reg.name, strerror(errno));
- return;
- }
xtables_register_match(&connlabel_mt_reg);
}
diff --git a/extensions/libxt_connlabel.t b/extensions/libxt_connlabel.t
new file mode 100644
index 00000000..aad1032b
--- /dev/null
+++ b/extensions/libxt_connlabel.t
@@ -0,0 +1,18 @@
+:INPUT,FORWARD,OUTPUT
+# Backup the connlabel.conf, then add some label maps for test
+@[ -f /etc/xtables/connlabel.conf ] && mv /etc/xtables/connlabel.conf /tmp/connlabel.conf.bak
+@mkdir -p /etc/xtables
+@echo "40 bit40" > /etc/xtables/connlabel.conf
+@echo "41 bit41" >> /etc/xtables/connlabel.conf
+@echo "128 bit128" >> /etc/xtables/connlabel.conf
+-m connlabel --label "bit40";=;OK
+-m connlabel ! --label "bit40";=;OK
+-m connlabel --label "bit41" --set;=;OK
+-m connlabel ! --label "bit41" --set;=;OK
+-m connlabel --label "bit128";;FAIL
+@echo > /etc/xtables/connlabel.conf
+-m connlabel --label "abc";;FAIL
+@rm -f /etc/xtables/connlabel.conf
+-m connlabel --label "abc";;FAIL
+# Restore the original connlabel.conf
+@[ -f /tmp/connlabel.conf.bak ] && mv /tmp/connlabel.conf.bak /etc/xtables/connlabel.conf
diff --git a/extensions/libxt_connlimit.t b/extensions/libxt_connlimit.t
new file mode 100644
index 00000000..c7ea61e9
--- /dev/null
+++ b/extensions/libxt_connlimit.t
@@ -0,0 +1,16 @@
+:INPUT,FORWARD,OUTPUT
+-m connlimit --connlimit-upto 0;=;OK
+-m connlimit --connlimit-upto 4294967295;=;OK
+-m connlimit --connlimit-upto 4294967296;;FAIL
+-m connlimit --connlimit-upto -1;;FAIL
+-m connlimit --connlimit-above 0;=;OK
+-m connlimit --connlimit-above 4294967295;=;OK
+-m connlimit --connlimit-above 4294967296;;FAIL
+-m connlimit --connlimit-above -1;;FAIL
+-m connlimit --connlimit-upto 1 --conlimit-above 1;;FAIL
+-m connlimit --connlimit-above 10 --connlimit-saddr;-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-saddr;OK
+-m connlimit --connlimit-above 10 --connlimit-daddr;-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-daddr;OK
+-m connlimit --connlimit-above 10 --connlimit-saddr --connlimit-daddr;;FAIL
+-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-saddr;=;OK
+-m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-daddr;=;OK
+-m connlimit;;FAIL
diff --git a/extensions/libxt_connmark.c b/extensions/libxt_connmark.c
index 6f1d5323..be3499b6 100644
--- a/extensions/libxt_connmark.c
+++ b/extensions/libxt_connmark.c
@@ -17,7 +17,7 @@
*
* 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdbool.h>
#include <stdint.h>
@@ -89,7 +89,8 @@ connmark_print(const void *ip, const struct xt_entry_match *match, int numeric)
}
static void
-connmark_mt_print(const void *ip, const struct xt_entry_match *match, int numeric)
+connmark_mt_print(const void *ip, const struct xt_entry_match *match,
+ int numeric)
{
const struct xt_connmark_mtinfo1 *info = (const void *)match->data;
@@ -122,6 +123,49 @@ connmark_mt_save(const void *ip, const struct xt_entry_match *match)
print_mark(info->mark, info->mask);
}
+static void print_mark_xlate(unsigned int mark, unsigned int mask,
+ struct xt_xlate *xl, uint32_t op)
+{
+ if (mask != 0xffffffffU)
+ xt_xlate_add(xl, " and 0x%x %s 0x%x", mask,
+ op == XT_OP_EQ ? "==" : "!=", mark);
+ else
+ xt_xlate_add(xl, " %s0x%x",
+ op == XT_OP_EQ ? "" : "!= ", mark);
+}
+
+static int connmark_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_connmark_info *info = (const void *)params->match->data;
+ enum xt_op op = XT_OP_EQ;
+
+ if (info->invert)
+ op = XT_OP_NEQ;
+
+ xt_xlate_add(xl, "ct mark");
+ print_mark_xlate(info->mark, info->mask, xl, op);
+
+ return 1;
+}
+
+static int
+connmark_mt_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_connmark_mtinfo1 *info =
+ (const void *)params->match->data;
+ enum xt_op op = XT_OP_EQ;
+
+ if (info->invert)
+ op = XT_OP_NEQ;
+
+ xt_xlate_add(xl, "ct mark");
+ print_mark_xlate(info->mark, info->mask, xl, op);
+
+ return 1;
+}
+
static struct xtables_match connmark_mt_reg[] = {
{
.family = NFPROTO_UNSPEC,
@@ -135,6 +179,7 @@ static struct xtables_match connmark_mt_reg[] = {
.save = connmark_save,
.x6_parse = connmark_parse,
.x6_options = connmark_mt_opts,
+ .xlate = connmark_xlate,
},
{
.version = XTABLES_VERSION,
@@ -148,6 +193,7 @@ static struct xtables_match connmark_mt_reg[] = {
.save = connmark_mt_save,
.x6_parse = connmark_mt_parse,
.x6_options = connmark_mt_opts,
+ .xlate = connmark_mt_xlate,
},
};
diff --git a/extensions/libxt_connmark.t b/extensions/libxt_connmark.t
new file mode 100644
index 00000000..4dd7d9af
--- /dev/null
+++ b/extensions/libxt_connmark.t
@@ -0,0 +1,9 @@
+:PREROUTING,FORWARD,OUTPUT,POSTROUTING
+*mangle
+-m connmark --mark 0xffffffff;=;OK
+-m connmark --mark 0xffffffff/0xffffffff;-m connmark --mark 0xffffffff;OK
+-m connmark --mark 0xffffffff/0;=;OK
+-m connmark --mark 0/0xffffffff;-m connmark --mark 0;OK
+-m connmark --mark -1;;FAIL
+-m connmark --mark 0xfffffffff;;FAIL
+-m connmark;;FAIL
diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c
index 128bbd20..72c52200 100644
--- a/extensions/libxt_conntrack.c
+++ b/extensions/libxt_conntrack.c
@@ -1156,6 +1156,246 @@ static void state_save(const void *ip, const struct xt_entry_match *match)
state_print_state(sinfo->statemask);
}
+static void state_xlate_print(struct xt_xlate *xl, unsigned int statemask)
+{
+ const char *sep = "";
+
+ if (statemask & XT_CONNTRACK_STATE_INVALID) {
+ xt_xlate_add(xl, "%s%s", sep, "invalid");
+ sep = ",";
+ }
+ if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) {
+ xt_xlate_add(xl, "%s%s", sep, "new");
+ sep = ",";
+ }
+ if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) {
+ xt_xlate_add(xl, "%s%s", sep, "related");
+ sep = ",";
+ }
+ if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) {
+ xt_xlate_add(xl, "%s%s", sep, "established");
+ sep = ",";
+ }
+ if (statemask & XT_CONNTRACK_STATE_UNTRACKED) {
+ xt_xlate_add(xl, "%s%s", sep, "untracked");
+ sep = ",";
+ }
+}
+
+static int state_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_conntrack_mtinfo3 *sinfo =
+ (const void *)params->match->data;
+
+ xt_xlate_add(xl, "ct state %s", sinfo->invert_flags & XT_CONNTRACK_STATE ?
+ "!= " : "");
+ state_xlate_print(xl, sinfo->state_mask);
+ xt_xlate_add(xl, " ");
+ return 1;
+}
+
+static void status_xlate_print(struct xt_xlate *xl, unsigned int statusmask)
+{
+ const char *sep = "";
+
+ if (statusmask & IPS_EXPECTED) {
+ xt_xlate_add(xl, "%s%s", sep, "expected");
+ sep = ",";
+ }
+ if (statusmask & IPS_SEEN_REPLY) {
+ xt_xlate_add(xl, "%s%s", sep, "seen-reply");
+ sep = ",";
+ }
+ if (statusmask & IPS_ASSURED) {
+ xt_xlate_add(xl, "%s%s", sep, "assured");
+ sep = ",";
+ }
+ if (statusmask & IPS_CONFIRMED) {
+ xt_xlate_add(xl, "%s%s", sep, "confirmed");
+ sep = ",";
+ }
+}
+
+static void addr_xlate_print(struct xt_xlate *xl,
+ const union nf_inet_addr *addr,
+ const union nf_inet_addr *mask,
+ unsigned int family)
+{
+ if (family == NFPROTO_IPV4) {
+ xt_xlate_add(xl, "%s%s", xtables_ipaddr_to_numeric(&addr->in),
+ xtables_ipmask_to_numeric(&mask->in));
+ } else if (family == NFPROTO_IPV6) {
+ xt_xlate_add(xl, "%s%s", xtables_ip6addr_to_numeric(&addr->in6),
+ xtables_ip6mask_to_numeric(&mask->in6));
+ }
+}
+
+static int _conntrack3_mt_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params,
+ int family)
+{
+ const struct xt_conntrack_mtinfo3 *sinfo =
+ (const void *)params->match->data;
+ char *space = "";
+
+ if (sinfo->match_flags & XT_CONNTRACK_DIRECTION) {
+ xt_xlate_add(xl, "ct direction %s",
+ sinfo->invert_flags & XT_CONNTRACK_DIRECTION ?
+ "reply" : "original");
+ space = " ";
+ }
+
+ if (sinfo->match_flags & XT_CONNTRACK_PROTO) {
+ xt_xlate_add(xl, "%sct %s protocol %s%u", space,
+ sinfo->invert_flags & XT_CONNTRACK_DIRECTION ?
+ "reply" : "original",
+ sinfo->invert_flags & XT_CONNTRACK_PROTO ?
+ "!= " : "",
+ sinfo->l4proto);
+ space = " ";
+ }
+
+ if (sinfo->match_flags & XT_CONNTRACK_STATE) {
+ xt_xlate_add(xl, "%sct state %s", space,
+ sinfo->invert_flags & XT_CONNTRACK_STATE ?
+ "!= " : "");
+ state_xlate_print(xl, sinfo->state_mask);
+ space = " ";
+ }
+
+ if (sinfo->match_flags & XT_CONNTRACK_STATUS) {
+ if (sinfo->status_mask == 1)
+ return 0;
+ xt_xlate_add(xl, "%sct status %s", space,
+ sinfo->invert_flags & XT_CONNTRACK_STATUS ?
+ "!= " : "");
+ status_xlate_print(xl, sinfo->status_mask);
+ space = " ";
+ }
+
+ if (sinfo->match_flags & XT_CONNTRACK_EXPIRES) {
+ xt_xlate_add(xl, "%sct expiration %s", space,
+ sinfo->invert_flags & XT_CONNTRACK_EXPIRES ?
+ "!= " : "");
+ if (sinfo->expires_max == sinfo->expires_min)
+ xt_xlate_add(xl, "%lu", sinfo->expires_min);
+ else
+ xt_xlate_add(xl, "%lu-%lu", sinfo->expires_min,
+ sinfo->expires_max);
+ space = " ";
+ }
+
+ if (sinfo->match_flags & XT_CONNTRACK_ORIGSRC) {
+ if (&sinfo->origsrc_addr == 0L)
+ return 0;
+
+ xt_xlate_add(xl, "%sct original saddr %s", space,
+ sinfo->invert_flags & XT_CONNTRACK_ORIGSRC ?
+ "!= " : "");
+ addr_xlate_print(xl, &sinfo->origsrc_addr,
+ &sinfo->origsrc_mask, family);
+ space = " ";
+ }
+
+ if (sinfo->match_flags & XT_CONNTRACK_ORIGDST) {
+ if (&sinfo->origdst_addr == 0L)
+ return 0;
+
+ xt_xlate_add(xl, "%sct original daddr %s", space,
+ sinfo->invert_flags & XT_CONNTRACK_ORIGDST ?
+ "!= " : "");
+ addr_xlate_print(xl, &sinfo->origdst_addr,
+ &sinfo->origdst_mask, family);
+ space = " ";
+ }
+
+ if (sinfo->match_flags & XT_CONNTRACK_REPLSRC) {
+ if (&sinfo->replsrc_addr == 0L)
+ return 0;
+
+ xt_xlate_add(xl, "%sct reply saddr %s", space,
+ sinfo->invert_flags & XT_CONNTRACK_REPLSRC ?
+ "!= " : "");
+ addr_xlate_print(xl, &sinfo->replsrc_addr,
+ &sinfo->replsrc_mask, family);
+ space = " ";
+ }
+
+ if (sinfo->match_flags & XT_CONNTRACK_REPLDST) {
+ if (&sinfo->repldst_addr == 0L)
+ return 0;
+
+ xt_xlate_add(xl, "%sct reply daddr %s", space,
+ sinfo->invert_flags & XT_CONNTRACK_REPLDST ?
+ "!= " : "");
+ addr_xlate_print(xl, &sinfo->repldst_addr,
+ &sinfo->repldst_mask, family);
+ space = " ";
+ }
+
+ if (sinfo->match_flags & XT_CONNTRACK_ORIGSRC_PORT) {
+ xt_xlate_add(xl, "%sct original proto-src %s", space,
+ sinfo->invert_flags & XT_CONNTRACK_ORIGSRC_PORT ?
+ "!= " : "");
+ if (sinfo->origsrc_port == sinfo->origsrc_port_high)
+ xt_xlate_add(xl, "%u", sinfo->origsrc_port);
+ else
+ xt_xlate_add(xl, "%u-%u", sinfo->origsrc_port,
+ sinfo->origsrc_port_high);
+ space = " ";
+ }
+
+ if (sinfo->match_flags & XT_CONNTRACK_ORIGDST_PORT) {
+ xt_xlate_add(xl, "%sct original proto-dst %s", space,
+ sinfo->invert_flags & XT_CONNTRACK_ORIGDST_PORT ?
+ "!= " : "");
+ if (sinfo->origdst_port == sinfo->origdst_port_high)
+ xt_xlate_add(xl, "%u", sinfo->origdst_port);
+ else
+ xt_xlate_add(xl, "%u-%u", sinfo->origdst_port,
+ sinfo->origdst_port_high);
+ space = " ";
+ }
+
+ if (sinfo->match_flags & XT_CONNTRACK_REPLSRC_PORT) {
+ xt_xlate_add(xl, "%sct reply proto-src %s", space,
+ sinfo->invert_flags & XT_CONNTRACK_REPLSRC_PORT ?
+ "!= " : "");
+ if (sinfo->replsrc_port == sinfo->replsrc_port_high)
+ xt_xlate_add(xl, "%u", sinfo->replsrc_port);
+ else
+ xt_xlate_add(xl, "%u-%u", sinfo->replsrc_port,
+ sinfo->replsrc_port_high);
+ space = " ";
+ }
+
+ if (sinfo->match_flags & XT_CONNTRACK_REPLDST_PORT) {
+ xt_xlate_add(xl, "%sct reply proto-dst %s", space,
+ sinfo->invert_flags & XT_CONNTRACK_REPLDST_PORT ?
+ "!= " : "", sinfo->repldst_port);
+ if (sinfo->repldst_port == sinfo->repldst_port_high)
+ xt_xlate_add(xl, "%u", sinfo->repldst_port);
+ else
+ xt_xlate_add(xl, "%u-%u", sinfo->repldst_port,
+ sinfo->repldst_port_high);
+ }
+
+ return 1;
+}
+
+static int conntrack3_mt4_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ return _conntrack3_mt_xlate(xl, params, NFPROTO_IPV4);
+}
+
+static int conntrack3_mt6_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ return _conntrack3_mt_xlate(xl, params, NFPROTO_IPV6);
+}
+
static struct xtables_match conntrack_mt_reg[] = {
{
.version = XTABLES_VERSION,
@@ -1246,6 +1486,7 @@ static struct xtables_match conntrack_mt_reg[] = {
.save = conntrack3_mt_save,
.alias = conntrack_print_name_alias,
.x6_options = conntrack3_mt_opts,
+ .xlate = conntrack3_mt4_xlate,
},
{
.version = XTABLES_VERSION,
@@ -1261,6 +1502,7 @@ static struct xtables_match conntrack_mt_reg[] = {
.save = conntrack3_mt6_save,
.alias = conntrack_print_name_alias,
.x6_options = conntrack3_mt_opts,
+ .xlate = conntrack3_mt6_xlate,
},
{
.family = NFPROTO_UNSPEC,
@@ -1306,6 +1548,7 @@ static struct xtables_match conntrack_mt_reg[] = {
.save = state_save,
.x6_parse = state_ct23_parse,
.x6_options = state_opts,
+ .xlate = state_xlate,
},
{
.family = NFPROTO_UNSPEC,
diff --git a/extensions/libxt_conntrack.man b/extensions/libxt_conntrack.man
index 15fd1ddf..4b13f0f6 100644
--- a/extensions/libxt_conntrack.man
+++ b/extensions/libxt_conntrack.man
@@ -45,7 +45,7 @@ States for \fB\-\-ctstate\fP:
The packet is associated with no known connection.
.TP
\fBNEW\fP
-The packet has started a new connection, or otherwise associated
+The packet has started a new connection or otherwise associated
with a connection which has not seen packets in both directions.
.TP
\fBESTABLISHED\fP
@@ -54,7 +54,7 @@ in both directions.
.TP
\fBRELATED\fP
The packet is starting a new connection, but is associated with an
-existing connection, such as an FTP data transfer, or an ICMP error.
+existing connection, such as an FTP data transfer or an ICMP error.
.TP
\fBUNTRACKED\fP
The packet is not tracked at all, which happens if you explicitly untrack it
diff --git a/extensions/libxt_conntrack.t b/extensions/libxt_conntrack.t
new file mode 100644
index 00000000..db531475
--- /dev/null
+++ b/extensions/libxt_conntrack.t
@@ -0,0 +1,27 @@
+:INPUT,FORWARD,OUTPUT
+-m conntrack --ctstate NEW;=;OK
+-m conntrack --ctstate NEW,ESTABLISHED;=;OK
+-m conntrack --ctstate NEW,RELATED,ESTABLISHED;=;OK
+-m conntrack --ctstate INVALID;=;OK
+-m conntrack --ctstate UNTRACKED;=;OK
+-m conntrack --ctstate SNAT,DNAT;=;OK
+-m conntrack --ctstate wrong;;FAIL
+# should we convert this to output "tcp" instead of 6?
+-m conntrack --ctproto tcp;-m conntrack --ctproto 6;OK
+-m conntrack --ctorigsrc 1.1.1.1;=;OK
+-m conntrack --ctorigdst 1.1.1.1;=;OK
+-m conntrack --ctreplsrc 1.1.1.1;=;OK
+-m conntrack --ctrepldst 1.1.1.1;=;OK
+-m conntrack --ctexpire 0;=;OK
+-m conntrack --ctexpire 4294967295;=;OK
+-m conntrack --ctexpire 0:4294967295;=;OK
+-m conntrack --ctexpire 42949672956;;FAIL
+-m conntrack --ctexpire -1;;FAIL
+-m conntrack --ctdir ORIGINAL;=;OK
+-m conntrack --ctdir REPLY;=;OK
+-m conntrack --ctstatus NONE;=;OK
+-m conntrack --ctstatus CONFIRMED;=;OK
+-m conntrack --ctstatus ASSURED;=;OK
+-m conntrack --ctstatus EXPECTED;=;OK
+-m conntrack --ctstatus SEEN_REPLY;=;OK
+-m conntrack;;FAIL
diff --git a/extensions/libxt_cpu.c b/extensions/libxt_cpu.c
index 404a6a66..41c13c3c 100644
--- a/extensions/libxt_cpu.c
+++ b/extensions/libxt_cpu.c
@@ -44,9 +44,19 @@ static void cpu_save(const void *ip, const struct xt_entry_match *match)
printf("%s --cpu %u", info->invert ? " !" : "", info->cpu);
}
+static int cpu_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_cpu_info *info = (void *)params->match->data;
+
+ xt_xlate_add(xl, "cpu%s %u", info->invert ? " !=" : "", info->cpu);
+
+ return 1;
+}
+
static struct xtables_match cpu_match = {
.family = NFPROTO_UNSPEC,
- .name = "cpu",
+ .name = "cpu",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_cpu_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_cpu_info)),
@@ -55,6 +65,7 @@ static struct xtables_match cpu_match = {
.save = cpu_save,
.x6_parse = cpu_parse,
.x6_options = cpu_opts,
+ .xlate = cpu_xlate,
};
void _init(void)
diff --git a/extensions/libxt_cpu.t b/extensions/libxt_cpu.t
new file mode 100644
index 00000000..f5adb45d
--- /dev/null
+++ b/extensions/libxt_cpu.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-m cpu --cpu 0;=;OK
+-m cpu ! --cpu 0;=;OK
+-m cpu --cpu 4294967295;=;OK
+-m cpu --cpu 4294967296;;FAIL
+-m cpu;;FAIL
diff --git a/extensions/libxt_dccp.c b/extensions/libxt_dccp.c
index a35cabbd..5e67c264 100644
--- a/extensions/libxt_dccp.c
+++ b/extensions/libxt_dccp.c
@@ -277,6 +277,97 @@ static void dccp_save(const void *ip, const struct xt_entry_match *match)
}
}
+static const char *const dccp_pkt_types_xlate[] = {
+ [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",
+};
+
+static int dccp_type_xlate(const struct xt_dccp_info *einfo,
+ struct xt_xlate *xl)
+{
+ bool have_type = false, set_need = false;
+ uint16_t types = einfo->typemask;
+
+ if (types & (1 << DCCP_PKT_INVALID))
+ return 0;
+
+ xt_xlate_add(xl, " dccp type%s ", einfo->invflags ? " !=" : "");
+
+ if ((types != 0) && !(types == (types & -types))) {
+ xt_xlate_add(xl, "{");
+ set_need = true;
+ }
+
+ while (types) {
+ unsigned int i;
+
+ for (i = 0; !(types & (1 << i)); i++);
+
+ if (have_type)
+ xt_xlate_add(xl, ", ");
+ else
+ have_type = true;
+
+ xt_xlate_add(xl, "%s", dccp_pkt_types_xlate[i]);
+
+ types &= ~(1 << i);
+ }
+
+ if (set_need)
+ xt_xlate_add(xl, "}");
+
+ return 1;
+}
+
+static int dccp_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_dccp_info *einfo =
+ (const struct xt_dccp_info *)params->match->data;
+ char *space = "";
+ int ret = 1;
+
+ xt_xlate_add(xl, "dccp ");
+
+ if (einfo->flags & XT_DCCP_SRC_PORTS) {
+ if (einfo->spts[0] != einfo->spts[1])
+ xt_xlate_add(xl, "sport%s %u-%u",
+ einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "",
+ einfo->spts[0], einfo->spts[1]);
+ else
+ xt_xlate_add(xl, "sport%s %u",
+ einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "",
+ einfo->spts[0]);
+ space = " ";
+ }
+
+ if (einfo->flags & XT_DCCP_DEST_PORTS) {
+ if (einfo->dpts[0] != einfo->dpts[1])
+ xt_xlate_add(xl, "%sdport%s %u-%u", space,
+ einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "",
+ einfo->dpts[0], einfo->dpts[1]);
+ else
+ xt_xlate_add(xl, "%sdport%s %u", space,
+ einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "",
+ einfo->dpts[0]);
+ }
+
+ if (einfo->flags & XT_DCCP_TYPE)
+ ret = dccp_type_xlate(einfo, xl);
+
+ if (einfo->flags & XT_DCCP_OPTION)
+ ret = 0;
+
+ return ret;
+}
static struct xtables_match dccp_match = {
.name = "dccp",
.family = NFPROTO_UNSPEC,
@@ -288,6 +379,7 @@ static struct xtables_match dccp_match = {
.save = dccp_save,
.x6_parse = dccp_parse,
.x6_options = dccp_opts,
+ .xlate = dccp_xlate,
};
void _init(void)
diff --git a/extensions/libxt_dccp.t b/extensions/libxt_dccp.t
new file mode 100644
index 00000000..f60b480f
--- /dev/null
+++ b/extensions/libxt_dccp.t
@@ -0,0 +1,30 @@
+:INPUT,FORWARD,OUTPUT
+-p dccp -m dccp --sport 1;=;OK
+-p dccp -m dccp --sport 65535;=;OK
+-p dccp -m dccp --dport 1;=;OK
+-p dccp -m dccp --dport 65535;=;OK
+-p dccp -m dccp --sport 1:1023;=;OK
+-p dccp -m dccp --sport 1024:65535;=;OK
+-p dccp -m dccp --sport 1024:;-p dccp -m dccp --sport 1024:65535;OK
+-p dccp -m dccp ! --sport 1;=;OK
+-p dccp -m dccp ! --sport 65535;=;OK
+-p dccp -m dccp ! --dport 1;=;OK
+-p dccp -m dccp ! --dport 65535;=;OK
+-p dccp -m dccp --sport 1 --dport 65535;=;OK
+-p dccp -m dccp --sport 65535 --dport 1;=;OK
+-p dccp -m dccp ! --sport 1 --dport 65535;=;OK
+-p dccp -m dccp ! --sport 65535 --dport 1;=;OK
+# ERROR: should fail: iptables -A INPUT -p dccp -m dccp --sport 65536
+# -p dccp -m dccp --sport 65536;;FAIL
+-p dccp -m dccp --sport -1;;FAIL
+-p dccp -m dccp --dport -1;;FAIL
+-p dccp -m dccp --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,RESET,SYNC,SYNCACK,INVALID;=;OK
+-p dccp -m dccp ! --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,RESET,SYNC,SYNCACK,INVALID;=;OK
+# DCCP option 0 is valid, see http://tools.ietf.org/html/rfc4340#page-29
+# ERROR: cannot load: iptables -A INPUT -p dccp -m dccp --dccp-option 0
+#-p dccp -m dccp --dccp-option 0;=;OK
+-p dccp -m dccp --dccp-option 255;=;OK
+-p dccp -m dccp --dccp-option 256;;FAIL
+-p dccp -m dccp --dccp-option -1;;FAIL
+# should we accept this below?
+-p dccp -m dccp;=;OK
diff --git a/extensions/libxt_devgroup.c b/extensions/libxt_devgroup.c
index 4a69c822..2ec3905c 100644
--- a/extensions/libxt_devgroup.c
+++ b/extensions/libxt_devgroup.c
@@ -31,12 +31,12 @@ static const struct xt_option_entry devgroup_opts[] = {
XTOPT_TABLEEND,
};
-/* array of devgroups from /etc/iproute2/group_map */
+/* array of devgroups from /etc/iproute2/group */
static struct xtables_lmap *devgroups;
static void devgroup_init(struct xt_entry_match *match)
{
- const char file[] = "/etc/iproute2/group_map";
+ const char file[] = "/etc/iproute2/group";
devgroups = xtables_lmap_init(file);
if (devgroups == NULL && errno != ENOENT)
fprintf(stderr, "Warning: %s: %s\n", file, strerror(errno));
@@ -124,7 +124,7 @@ static void devgroup_show(const char *pfx, const struct xt_devgroup_info *info,
if (info->flags & XT_DEVGROUP_INVERT_DST)
printf(" !");
printf(" %sdst-group ", pfx);
- print_devgroup(info->src_group, info->src_mask, numeric);
+ print_devgroup(info->dst_group, info->dst_mask, numeric);
}
}
@@ -151,6 +151,61 @@ static void devgroup_check(struct xt_fcheck_call *cb)
"'--src-group' or '--dst-group'");
}
+static void
+print_devgroup_xlate(unsigned int id, uint32_t op, unsigned int mask,
+ struct xt_xlate *xl, int numeric)
+{
+ const char *name = NULL;
+
+ if (mask != 0xffffffff)
+ xt_xlate_add(xl, "and 0x%x %s 0x%x", mask,
+ op == XT_OP_EQ ? "==" : "!=", id);
+ else {
+ if (numeric == 0)
+ name = xtables_lmap_id2name(devgroups, id);
+
+ xt_xlate_add(xl, "%s", op == XT_OP_EQ ? "" : "!= ");
+ if (name)
+ xt_xlate_add(xl, "%s", name);
+ else
+ xt_xlate_add(xl, "0x%x", id);
+ }
+}
+
+static void devgroup_show_xlate(const struct xt_devgroup_info *info,
+ struct xt_xlate *xl, int numeric)
+{
+ enum xt_op op = XT_OP_EQ;
+ char *space = "";
+
+ if (info->flags & XT_DEVGROUP_MATCH_SRC) {
+ if (info->flags & XT_DEVGROUP_INVERT_SRC)
+ op = XT_OP_NEQ;
+ xt_xlate_add(xl, "iifgroup ");
+ print_devgroup_xlate(info->src_group, op,
+ info->src_mask, xl, numeric);
+ space = " ";
+ }
+
+ if (info->flags & XT_DEVGROUP_MATCH_DST) {
+ if (info->flags & XT_DEVGROUP_INVERT_DST)
+ op = XT_OP_NEQ;
+ xt_xlate_add(xl, "%soifgroup ", space);
+ print_devgroup_xlate(info->dst_group, op,
+ info->dst_mask, xl, numeric);
+ }
+}
+
+static int devgroup_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_devgroup_info *info = (const void *)params->match->data;
+
+ devgroup_show_xlate(info, xl, 0);
+
+ return 1;
+}
+
static struct xtables_match devgroup_mt_reg = {
.name = "devgroup",
.version = XTABLES_VERSION,
@@ -164,6 +219,7 @@ static struct xtables_match devgroup_mt_reg = {
.x6_parse = devgroup_parse,
.x6_fcheck = devgroup_check,
.x6_options = devgroup_opts,
+ .xlate = devgroup_xlate,
};
void _init(void)
diff --git a/extensions/libxt_dscp.c b/extensions/libxt_dscp.c
index 02b22a4e..d5c73236 100644
--- a/extensions/libxt_dscp.c
+++ b/extensions/libxt_dscp.c
@@ -91,21 +91,66 @@ static void dscp_save(const void *ip, const struct xt_entry_match *match)
printf("%s --dscp 0x%02x", dinfo->invert ? " !" : "", dinfo->dscp);
}
-static struct xtables_match dscp_match = {
- .family = NFPROTO_UNSPEC,
- .name = "dscp",
- .version = XTABLES_VERSION,
- .size = XT_ALIGN(sizeof(struct xt_dscp_info)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_dscp_info)),
- .help = dscp_help,
- .print = dscp_print,
- .save = dscp_save,
- .x6_parse = dscp_parse,
- .x6_fcheck = dscp_check,
- .x6_options = dscp_opts,
+static int __dscp_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_dscp_info *dinfo =
+ (const struct xt_dscp_info *)params->match->data;
+
+ xt_xlate_add(xl, "dscp %s0x%02x", dinfo->invert ? "!= " : "",
+ dinfo->dscp);
+
+ return 1;
+}
+
+static int dscp_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ xt_xlate_add(xl, "ip ");
+
+ return __dscp_xlate(xl, params);
+}
+
+static int dscp_xlate6(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ xt_xlate_add(xl, "ip6 ");
+
+ return __dscp_xlate(xl, params);
+}
+
+static struct xtables_match dscp_mt_reg[] = {
+ {
+ .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,
+ .print = dscp_print,
+ .save = dscp_save,
+ .x6_parse = dscp_parse,
+ .x6_fcheck = dscp_check,
+ .x6_options = dscp_opts,
+ .xlate = dscp_xlate,
+ },
+ {
+ .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,
+ .print = dscp_print,
+ .save = dscp_save,
+ .x6_parse = dscp_parse,
+ .x6_fcheck = dscp_check,
+ .x6_options = dscp_opts,
+ .xlate = dscp_xlate6,
+ },
};
void _init(void)
{
- xtables_register_match(&dscp_match);
+ xtables_register_matches(dscp_mt_reg, ARRAY_SIZE(dscp_mt_reg));
}
diff --git a/extensions/libxt_dscp.t b/extensions/libxt_dscp.t
new file mode 100644
index 00000000..38d7f04e
--- /dev/null
+++ b/extensions/libxt_dscp.t
@@ -0,0 +1,10 @@
+:INPUT,FORWARD,OUTPUT
+-m dscp --dscp 0;=;OK
+-m dscp --dscp 0x3f;=;OK
+-m dscp --dscp -1;;FAIL
+-m dscp --dscp 0x40;;FAIL
+-m dscp --dscp 0x3f --dscp-class CS0;;FAIL
+-m dscp --dscp-class CS0;-m dscp --dscp 0x00;OK
+-m dscp --dscp-class BE;-m dscp --dscp 0x00;OK
+-m dscp --dscp-class EF;-m dscp --dscp 0x2e;OK
+-m dscp;;FAIL
diff --git a/extensions/libxt_ecn.c b/extensions/libxt_ecn.c
index 286782a3..aeba01b3 100644
--- a/extensions/libxt_ecn.c
+++ b/extensions/libxt_ecn.c
@@ -118,6 +118,36 @@ static void ecn_save(const void *ip, const struct xt_entry_match *match)
}
}
+static int ecn_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_ecn_info *einfo =
+ (const struct xt_ecn_info *)params->match->data;
+
+ if (!(einfo->operation & XT_ECN_OP_MATCH_IP))
+ return 0;
+
+ xt_xlate_add(xl, "ip ecn ");
+ if (einfo->invert)
+ xt_xlate_add(xl,"!= ");
+
+ switch (einfo->ip_ect) {
+ case 0:
+ xt_xlate_add(xl, "not-ect");
+ break;
+ case 1:
+ xt_xlate_add(xl, "ect1");
+ break;
+ case 2:
+ xt_xlate_add(xl, "ect0");
+ break;
+ case 3:
+ xt_xlate_add(xl, "ce");
+ break;
+ }
+ return 1;
+}
+
static struct xtables_match ecn_mt_reg = {
.name = "ecn",
.version = XTABLES_VERSION,
@@ -130,6 +160,7 @@ static struct xtables_match ecn_mt_reg = {
.x6_parse = ecn_parse,
.x6_fcheck = ecn_check,
.x6_options = ecn_opts,
+ .xlate = ecn_xlate,
};
void _init(void)
diff --git a/extensions/libxt_ecn.t b/extensions/libxt_ecn.t
new file mode 100644
index 00000000..b32aea30
--- /dev/null
+++ b/extensions/libxt_ecn.t
@@ -0,0 +1,5 @@
+:INPUT,FORWARD,OUTPUT
+-m ecn --ecn-tcp-cwr;;FAIL
+-p tcp -m ecn --ecn-tcp-cwr;=;OK
+-p tcp -m ecn --ecn-tcp-ece --ecn-tcp-cwr --ecn-ip-ect 2;=;OK
+-p tcp -m ecn ! --ecn-tcp-ece ! --ecn-tcp-cwr ! --ecn-ip-ect 2;=;OK
diff --git a/extensions/libxt_esp.c b/extensions/libxt_esp.c
index 294338b4..2c7ff942 100644
--- a/extensions/libxt_esp.c
+++ b/extensions/libxt_esp.c
@@ -21,6 +21,13 @@ static const struct xt_option_entry esp_opts[] = {
XTOPT_TABLEEND,
};
+static void esp_init(struct xt_entry_match *m)
+{
+ struct xt_esp *espinfo = (void *)m->data;
+
+ espinfo->spis[1] = ~0U;
+}
+
static void esp_parse(struct xt_option_call *cb)
{
struct xt_esp *espinfo = cb->data;
@@ -79,17 +86,37 @@ static void esp_save(const void *ip, const struct xt_entry_match *match)
}
+static int esp_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_esp *espinfo = (struct xt_esp *)params->match->data;
+
+ if (!(espinfo->spis[0] == 0 && espinfo->spis[1] == 0xFFFFFFFF)) {
+ xt_xlate_add(xl, "esp spi%s",
+ (espinfo->invflags & XT_ESP_INV_SPI) ? " !=" : "");
+ if (espinfo->spis[0] != espinfo->spis[1])
+ xt_xlate_add(xl, " %u-%u", espinfo->spis[0],
+ espinfo->spis[1]);
+ else
+ xt_xlate_add(xl, " %u", espinfo->spis[0]);
+ }
+
+ return 1;
+}
+
static struct xtables_match esp_match = {
.family = NFPROTO_UNSPEC,
- .name = "esp",
- .version = XTABLES_VERSION,
+ .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,
.print = esp_print,
.save = esp_save,
.x6_parse = esp_parse,
.x6_options = esp_opts,
+ .xlate = esp_xlate,
};
void
diff --git a/extensions/libxt_esp.t b/extensions/libxt_esp.t
new file mode 100644
index 00000000..92c5779f
--- /dev/null
+++ b/extensions/libxt_esp.t
@@ -0,0 +1,8 @@
+:INPUT,FORWARD,OUTPUT
+-p esp -m esp --espspi 0;=;OK
+-p esp -m esp --espspi :32;-p esp -m esp --espspi 0:32;OK
+-p esp -m esp --espspi 0:4294967295;-p esp -m esp;OK
+-p esp -m esp ! --espspi 0:4294967294;=;OK
+-p esp -m esp --espspi -1;;FAIL
+-p esp -m esp;=;OK
+-m esp;;FAIL
diff --git a/extensions/libxt_hashlimit.c b/extensions/libxt_hashlimit.c
index c5b8d779..7a1b37a9 100644
--- a/extensions/libxt_hashlimit.c
+++ b/extensions/libxt_hashlimit.c
@@ -18,12 +18,14 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <errno.h>
#include <xtables.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_hashlimit.h>
#define XT_HASHLIMIT_BURST 5
-#define XT_HASHLIMIT_BURST_MAX 10000
+#define XT_HASHLIMIT_BURST_MAX_v1 10000
+#define XT_HASHLIMIT_BURST_MAX 1000000
#define XT_HASHLIMIT_BYTE_EXPIRE 15
#define XT_HASHLIMIT_BYTE_EXPIRE_BURST 60
@@ -98,7 +100,7 @@ static const struct xt_option_entry hashlimit_opts[] = {
{.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
.type = XTTYPE_STRING},
{.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_UINT32,
- .min = 1, .max = XT_HASHLIMIT_BURST_MAX, .flags = XTOPT_PUT,
+ .min = 1, .max = XT_HASHLIMIT_BURST_MAX_v1, .flags = XTOPT_PUT,
XTOPT_POINTER(s, cfg.burst)},
{.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
.type = XTTYPE_UINT32, .flags = XTOPT_PUT,
@@ -121,6 +123,36 @@ static const struct xt_option_entry hashlimit_opts[] = {
#undef s
#define s struct xt_hashlimit_mtinfo1
+static const struct xt_option_entry hashlimit_mt_opts_v1[] = {
+ {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
+ .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
+ {.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO,
+ .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
+ {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
+ .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */
+ {.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN},
+ {.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN},
+ {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING},
+ {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
+ .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
+ XTOPT_POINTER(s, cfg.size)},
+ {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
+ .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
+ XTOPT_POINTER(s, cfg.max)},
+ {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
+ .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
+ XTOPT_POINTER(s, cfg.gc_interval)},
+ {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
+ .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
+ XTOPT_POINTER(s, cfg.expire)},
+ {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING},
+ {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
+ .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
+ XTOPT_TABLEEND,
+};
+#undef s
+
+#define s struct xt_hashlimit_mtinfo2
static const struct xt_option_entry hashlimit_mt_opts[] = {
{.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
.type = XTTYPE_STRING, .flags = XTOPT_INVERT},
@@ -150,16 +182,40 @@ static const struct xt_option_entry hashlimit_mt_opts[] = {
};
#undef s
-static uint32_t cost_to_bytes(uint32_t cost)
+static int
+cfg_copy(struct hashlimit_cfg2 *to, const void *from, int revision)
+{
+ if (revision == 1) {
+ struct hashlimit_cfg1 *cfg = (struct hashlimit_cfg1 *)from;
+
+ to->mode = cfg->mode;
+ to->avg = cfg->avg;
+ to->burst = cfg->burst;
+ to->size = cfg->size;
+ to->max = cfg->max;
+ to->gc_interval = cfg->gc_interval;
+ to->expire = cfg->expire;
+ to->srcmask = cfg->srcmask;
+ to->dstmask = cfg->dstmask;
+ } else if (revision == 2) {
+ memcpy(to, from, sizeof(struct hashlimit_cfg2));
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static uint64_t cost_to_bytes(uint64_t cost)
{
- uint32_t r;
+ uint64_t r;
r = cost ? UINT32_MAX / cost : UINT32_MAX;
r = (r - 1) << XT_HASHLIMIT_BYTE_SHIFT;
return r;
}
-static uint64_t bytes_to_cost(uint32_t bytes)
+static uint64_t bytes_to_cost(uint64_t bytes)
{
uint32_t r = bytes >> XT_HASHLIMIT_BYTE_SHIFT;
return UINT32_MAX / (r+1);
@@ -174,63 +230,84 @@ static uint32_t get_factor(int chr)
return 1;
}
+static void burst_error_v1(void)
+{
+ xtables_error(PARAMETER_PROBLEM, "bad value for option "
+ "\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX_v1);
+}
+
static void burst_error(void)
{
xtables_error(PARAMETER_PROBLEM, "bad value for option "
"\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX);
}
-static uint32_t parse_burst(const char *burst, struct xt_hashlimit_mtinfo1 *info)
+static uint64_t parse_burst(const char *burst, int revision)
{
uintmax_t v;
char *end;
-
- if (!xtables_strtoul(burst, &end, &v, 1, UINT32_MAX) ||
- (*end == 0 && v > XT_HASHLIMIT_BURST_MAX))
- burst_error();
+ uint64_t max = (revision == 1) ? UINT32_MAX : UINT64_MAX;
+ uint64_t burst_max = (revision == 1) ?
+ XT_HASHLIMIT_BURST_MAX_v1 : XT_HASHLIMIT_BURST_MAX;
+
+ if (!xtables_strtoul(burst, &end, &v, 1, max) ||
+ (*end == 0 && v > burst_max)) {
+ if (revision == 1)
+ burst_error_v1();
+ else
+ burst_error();
+ }
v *= get_factor(*end);
- if (v > UINT32_MAX)
+ if (v > max)
xtables_error(PARAMETER_PROBLEM, "bad value for option "
"\"--hashlimit-burst\", value \"%s\" too large "
- "(max %umb).", burst, UINT32_MAX/1024/1024);
+ "(max %lumb).", burst, max/1024/1024);
return v;
}
-static bool parse_bytes(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud)
+static bool parse_bytes(const char *rate, void *val, struct hashlimit_mt_udata *ud, int revision)
{
unsigned int factor = 1;
- uint64_t tmp;
- int r;
+ uint64_t tmp, r;
const char *mode = strstr(rate, "b/s");
+ uint64_t max = (revision == 1) ? UINT32_MAX : UINT64_MAX;
+
if (!mode || mode == rate)
return false;
mode--;
- r = atoi(rate);
+ r = atoll(rate);
if (r == 0)
return false;
factor = get_factor(*mode);
tmp = (uint64_t) r * factor;
- if (tmp > UINT32_MAX)
+ if (tmp > max)
xtables_error(PARAMETER_PROBLEM,
- "Rate value too large \"%llu\" (max %u)\n",
- (unsigned long long)tmp, UINT32_MAX);
+ "Rate value too large \"%llu\" (max %lu)\n",
+ (unsigned long long)tmp, max);
- *val = bytes_to_cost(tmp);
- if (*val == 0)
+ tmp = bytes_to_cost(tmp);
+ if (tmp == 0)
xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"\n", rate);
ud->mult = XT_HASHLIMIT_BYTE_EXPIRE;
+
+ if(revision == 1)
+ *((uint32_t*)val) = tmp;
+ else
+ *((uint64_t*)val) = tmp;
+
return true;
}
static
-int parse_rate(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud)
+int parse_rate(const char *rate, void *val, struct hashlimit_mt_udata *ud, int revision)
{
const char *delim;
- uint32_t r;
+ uint64_t tmp, r;
+ uint64_t scale = (revision == 1) ? XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2;
ud->mult = 1; /* Seconds by default. */
delim = strchr(rate, '/');
@@ -249,17 +326,23 @@ int parse_rate(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud)
else
return 0;
}
- r = atoi(rate);
+ r = atoll(rate);
if (!r)
return 0;
- *val = XT_HASHLIMIT_SCALE * ud->mult / r;
- if (*val == 0)
+ tmp = scale * ud->mult / r;
+ if (tmp == 0)
/*
* The rate maps to infinity. (1/day is the minimum they can
* specify, so we are ok at that end).
*/
xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
+
+ if(revision == 1)
+ *((uint32_t*)val) = tmp;
+ else
+ *((uint64_t*)val) = tmp;
+
return 1;
}
@@ -272,7 +355,7 @@ static void hashlimit_init(struct xt_entry_match *m)
}
-static void hashlimit_mt4_init(struct xt_entry_match *match)
+static void hashlimit_mt4_init_v1(struct xt_entry_match *match)
{
struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
@@ -283,7 +366,7 @@ static void hashlimit_mt4_init(struct xt_entry_match *match)
info->cfg.dstmask = 32;
}
-static void hashlimit_mt6_init(struct xt_entry_match *match)
+static void hashlimit_mt6_init_v1(struct xt_entry_match *match)
{
struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
@@ -294,6 +377,28 @@ static void hashlimit_mt6_init(struct xt_entry_match *match)
info->cfg.dstmask = 128;
}
+static void hashlimit_mt4_init(struct xt_entry_match *match)
+{
+ struct xt_hashlimit_mtinfo2 *info = (void *)match->data;
+
+ info->cfg.mode = 0;
+ info->cfg.burst = XT_HASHLIMIT_BURST;
+ info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
+ info->cfg.srcmask = 32;
+ info->cfg.dstmask = 32;
+}
+
+static void hashlimit_mt6_init(struct xt_entry_match *match)
+{
+ struct xt_hashlimit_mtinfo2 *info = (void *)match->data;
+
+ info->cfg.mode = 0;
+ info->cfg.burst = XT_HASHLIMIT_BURST;
+ info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
+ info->cfg.srcmask = 128;
+ info->cfg.dstmask = 128;
+}
+
/* Parse a 'mode' parameter into the required bitmask */
static int parse_mode(uint32_t *mode, const char *option_arg)
{
@@ -330,7 +435,7 @@ static void hashlimit_parse(struct xt_option_call *cb)
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_UPTO:
- if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
+ if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
xtables_param_act(XTF_BAD_VALUE, "hashlimit",
"--hashlimit-upto", cb->arg);
break;
@@ -342,30 +447,71 @@ static void hashlimit_parse(struct xt_option_call *cb)
}
}
-static void hashlimit_mt_parse(struct xt_option_call *cb)
+static void hashlimit_mt_parse_v1(struct xt_option_call *cb)
{
struct xt_hashlimit_mtinfo1 *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_BURST:
- info->cfg.burst = parse_burst(cb->arg, info);
+ info->cfg.burst = parse_burst(cb->arg, 1);
break;
case O_UPTO:
if (cb->invert)
info->cfg.mode |= XT_HASHLIMIT_INVERT;
- if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata))
+ if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 1))
info->cfg.mode |= XT_HASHLIMIT_BYTES;
- else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
+ else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
xtables_param_act(XTF_BAD_VALUE, "hashlimit",
"--hashlimit-upto", cb->arg);
break;
case O_ABOVE:
if (!cb->invert)
info->cfg.mode |= XT_HASHLIMIT_INVERT;
- if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata))
+ if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 1))
info->cfg.mode |= XT_HASHLIMIT_BYTES;
- else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
+ else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
+ xtables_param_act(XTF_BAD_VALUE, "hashlimit",
+ "--hashlimit-above", cb->arg);
+ break;
+ case O_MODE:
+ if (parse_mode(&info->cfg.mode, cb->arg) < 0)
+ xtables_param_act(XTF_BAD_VALUE, "hashlimit",
+ "--hashlimit-mode", cb->arg);
+ break;
+ case O_SRCMASK:
+ info->cfg.srcmask = cb->val.hlen;
+ break;
+ case O_DSTMASK:
+ info->cfg.dstmask = cb->val.hlen;
+ break;
+ }
+}
+
+static void hashlimit_mt_parse(struct xt_option_call *cb)
+{
+ struct xt_hashlimit_mtinfo2 *info = cb->data;
+
+ xtables_option_parse(cb);
+ switch (cb->entry->id) {
+ case O_BURST:
+ info->cfg.burst = parse_burst(cb->arg, 2);
+ break;
+ case O_UPTO:
+ if (cb->invert)
+ info->cfg.mode |= XT_HASHLIMIT_INVERT;
+ if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
+ info->cfg.mode |= XT_HASHLIMIT_BYTES;
+ else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
+ xtables_param_act(XTF_BAD_VALUE, "hashlimit",
+ "--hashlimit-upto", cb->arg);
+ break;
+ case O_ABOVE:
+ if (!cb->invert)
+ info->cfg.mode |= XT_HASHLIMIT_INVERT;
+ if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
+ info->cfg.mode |= XT_HASHLIMIT_BYTES;
+ else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
xtables_param_act(XTF_BAD_VALUE, "hashlimit",
"--hashlimit-above", cb->arg);
break;
@@ -395,7 +541,7 @@ static void hashlimit_check(struct xt_fcheck_call *cb)
info->cfg.expire = udata->mult * 1000; /* from s to msec */
}
-static void hashlimit_mt_check(struct xt_fcheck_call *cb)
+static void hashlimit_mt_check_v1(struct xt_fcheck_call *cb)
{
const struct hashlimit_mt_udata *udata = cb->udata;
struct xt_hashlimit_mtinfo1 *info = cb->data;
@@ -411,7 +557,37 @@ static void hashlimit_mt_check(struct xt_fcheck_call *cb)
if (cb->xflags & F_BURST) {
if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
xtables_error(PARAMETER_PROBLEM,
- "burst cannot be smaller than %ub", cost_to_bytes(info->cfg.avg));
+ "burst cannot be smaller than %lub", cost_to_bytes(info->cfg.avg));
+
+ burst = info->cfg.burst;
+ burst /= cost_to_bytes(info->cfg.avg);
+ if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
+ burst++;
+ if (!(cb->xflags & F_HTABLE_EXPIRE))
+ info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
+ }
+ info->cfg.burst = burst;
+ } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX_v1)
+ burst_error_v1();
+}
+
+static void hashlimit_mt_check(struct xt_fcheck_call *cb)
+{
+ const struct hashlimit_mt_udata *udata = cb->udata;
+ struct xt_hashlimit_mtinfo2 *info = cb->data;
+
+ if (!(cb->xflags & (F_UPTO | F_ABOVE)))
+ xtables_error(PARAMETER_PROBLEM,
+ "You have to specify --hashlimit");
+ if (!(cb->xflags & F_HTABLE_EXPIRE))
+ info->cfg.expire = udata->mult * 1000; /* from s to msec */
+
+ if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
+ uint32_t burst = 0;
+ if (cb->xflags & F_BURST) {
+ if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
+ xtables_error(PARAMETER_PROBLEM,
+ "burst cannot be smaller than %lub", cost_to_bytes(info->cfg.avg));
burst = info->cfg.burst;
burst /= cost_to_bytes(info->cfg.avg);
@@ -425,18 +601,25 @@ static void hashlimit_mt_check(struct xt_fcheck_call *cb)
burst_error();
}
-static const struct rates
-{
+struct rates {
const char *name;
- uint32_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 uint32_t print_rate(uint32_t period)
+ uint64_t mult;
+} rates_v1[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 },
+ { "hour", XT_HASHLIMIT_SCALE*60*60 },
+ { "min", XT_HASHLIMIT_SCALE*60 },
+ { "sec", XT_HASHLIMIT_SCALE } };
+
+static const struct rates rates[] = {
+ { "day", XT_HASHLIMIT_SCALE_v2*24*60*60 },
+ { "hour", XT_HASHLIMIT_SCALE_v2*60*60 },
+ { "min", XT_HASHLIMIT_SCALE_v2*60 },
+ { "sec", XT_HASHLIMIT_SCALE_v2 } };
+
+static uint32_t print_rate(uint32_t period, int revision)
{
unsigned int i;
+ const struct rates *_rates = (revision == 1) ? rates_v1 : rates;
+ uint64_t scale = (revision == 1) ? XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2;
if (period == 0) {
printf(" %f", INFINITY);
@@ -444,13 +627,13 @@ static uint32_t print_rate(uint32_t period)
}
for (i = 1; i < ARRAY_SIZE(rates); ++i)
- if (period > rates[i].mult
- || rates[i].mult/period < rates[i].mult%period)
+ 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);
+ printf(" %lu/%s", _rates[i-1].mult / period, _rates[i-1].name);
/* return in msec */
- return rates[i-1].mult / XT_HASHLIMIT_SCALE * 1000;
+ return _rates[i-1].mult / scale * 1000;
}
static const struct {
@@ -462,7 +645,7 @@ static const struct {
{ "", 1 },
};
-static uint32_t print_bytes(uint32_t avg, uint32_t burst, const char *prefix)
+static uint32_t print_bytes(uint64_t avg, uint64_t burst, const char *prefix)
{
unsigned int i;
unsigned long long r;
@@ -523,7 +706,7 @@ static void hashlimit_print(const void *ip,
uint32_t quantum;
fputs(" limit: avg", stdout);
- quantum = print_rate(r->cfg.avg);
+ quantum = print_rate(r->cfg.avg, 1);
printf(" burst %u", r->cfg.burst);
fputs(" mode", stdout);
print_mode(r->cfg.mode, '-');
@@ -538,57 +721,89 @@ static void hashlimit_print(const void *ip,
}
static void
-hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
+hashlimit_mt_print(const struct hashlimit_cfg2 *cfg, unsigned int dmask, int revision)
{
uint32_t quantum;
- if (info->cfg.mode & XT_HASHLIMIT_INVERT)
+ if (cfg->mode & XT_HASHLIMIT_INVERT)
fputs(" limit: above", stdout);
else
fputs(" limit: up to", stdout);
- if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
- quantum = print_bytes(info->cfg.avg, info->cfg.burst, "");
+ if (cfg->mode & XT_HASHLIMIT_BYTES) {
+ quantum = print_bytes(cfg->avg, cfg->burst, "");
} else {
- quantum = print_rate(info->cfg.avg);
- printf(" burst %u", info->cfg.burst);
+ quantum = print_rate(cfg->avg, revision);
+ printf(" burst %llu", cfg->burst);
}
- if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
+ if (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, '-');
+ print_mode(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 != quantum)
- printf(" htable-expire %u", info->cfg.expire);
+ if (cfg->size != 0)
+ printf(" htable-size %u", cfg->size);
+ if (cfg->max != 0)
+ printf(" htable-max %u", cfg->max);
+ if (cfg->gc_interval != XT_HASHLIMIT_GCINTERVAL)
+ printf(" htable-gcinterval %u", cfg->gc_interval);
+ if (cfg->expire != quantum)
+ printf(" htable-expire %u", cfg->expire);
+
+ if (cfg->srcmask != dmask)
+ printf(" srcmask %u", cfg->srcmask);
+ if (cfg->dstmask != dmask)
+ printf(" dstmask %u", cfg->dstmask);
+}
+
+static void
+hashlimit_mt4_print_v1(const void *ip, const struct xt_entry_match *match,
+ int numeric)
+{
+ const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
+ struct hashlimit_cfg2 cfg;
+ int ret;
+
+ ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
+
+ if (ret)
+ xtables_error(OTHER_PROBLEM, "unknown revision");
- if (info->cfg.srcmask != dmask)
- printf(" srcmask %u", info->cfg.srcmask);
- if (info->cfg.dstmask != dmask)
- printf(" dstmask %u", info->cfg.dstmask);
+ hashlimit_mt_print(&cfg, 32, 1);
}
static void
-hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match,
+hashlimit_mt6_print_v1(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
+ struct hashlimit_cfg2 cfg;
+ int ret;
+
+ ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
+
+ if (ret)
+ xtables_error(OTHER_PROBLEM, "unknown revision");
+
+ hashlimit_mt_print(&cfg, 128, 1);
+}
+
+static void
+hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match,
+ int numeric)
+{
+ const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
- hashlimit_mt_print(info, 32);
+ hashlimit_mt_print(&info->cfg, 32, 2);
}
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;
+ const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
- hashlimit_mt_print(info, 128);
+ hashlimit_mt_print(&info->cfg, 128, 2);
}
static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
@@ -597,7 +812,7 @@ static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
uint32_t quantum;
fputs(" --hashlimit", stdout);
- quantum = print_rate(r->cfg.avg);
+ quantum = print_rate(r->cfg.avg, 1);
printf(" --hashlimit-burst %u", r->cfg.burst);
fputs(" --hashlimit-mode", stdout);
@@ -616,59 +831,89 @@ static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
}
static void
-hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
+hashlimit_mt_save(const struct hashlimit_cfg2 *cfg, const char* name, unsigned int dmask, int revision)
{
uint32_t quantum;
- if (info->cfg.mode & XT_HASHLIMIT_INVERT)
+ if (cfg->mode & XT_HASHLIMIT_INVERT)
fputs(" --hashlimit-above", stdout);
else
fputs(" --hashlimit-upto", stdout);
- if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
- quantum = print_bytes(info->cfg.avg, info->cfg.burst, "--hashlimit-");
+ if (cfg->mode & XT_HASHLIMIT_BYTES) {
+ quantum = print_bytes(cfg->avg, cfg->burst, "--hashlimit-");
} else {
- quantum = print_rate(info->cfg.avg);
- printf(" --hashlimit-burst %u", info->cfg.burst);
+ quantum = print_rate(cfg->avg, revision);
+ printf(" --hashlimit-burst %llu", cfg->burst);
}
- if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
+ if (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, ',');
+ print_mode(cfg->mode, ',');
}
- printf(" --hashlimit-name %s", info->name);
+ printf(" --hashlimit-name %s", name);
+
+ if (cfg->size != 0)
+ printf(" --hashlimit-htable-size %u", cfg->size);
+ if (cfg->max != 0)
+ printf(" --hashlimit-htable-max %u", cfg->max);
+ if (cfg->gc_interval != XT_HASHLIMIT_GCINTERVAL)
+ printf(" --hashlimit-htable-gcinterval %u", cfg->gc_interval);
+ if (cfg->expire != quantum)
+ printf(" --hashlimit-htable-expire %u", cfg->expire);
+
+ if (cfg->srcmask != dmask)
+ printf(" --hashlimit-srcmask %u", cfg->srcmask);
+ if (cfg->dstmask != dmask)
+ printf(" --hashlimit-dstmask %u", cfg->dstmask);
+}
+
+static void
+hashlimit_mt4_save_v1(const void *ip, const struct xt_entry_match *match)
+{
+ const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
+ struct hashlimit_cfg2 cfg;
+ int ret;
+
+ ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
- 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 != quantum)
- printf(" --hashlimit-htable-expire %u", info->cfg.expire);
+ if (ret)
+ xtables_error(OTHER_PROBLEM, "unknown revision");
- if (info->cfg.srcmask != dmask)
- printf(" --hashlimit-srcmask %u", info->cfg.srcmask);
- if (info->cfg.dstmask != dmask)
- printf(" --hashlimit-dstmask %u", info->cfg.dstmask);
+ hashlimit_mt_save(&cfg, info->name, 32, 1);
}
static void
-hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
+hashlimit_mt6_save_v1(const void *ip, const struct xt_entry_match *match)
{
const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
+ struct hashlimit_cfg2 cfg;
+ int ret;
+
+ ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
+
+ if (ret)
+ xtables_error(OTHER_PROBLEM, "unknown revision");
+
+ hashlimit_mt_save(&cfg, info->name, 128, 1);
+}
+
+static void
+hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
+{
+ const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
- hashlimit_mt_save(info, 32);
+ hashlimit_mt_save(&info->cfg, info->name, 32, 2);
}
static void
hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match)
{
- const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
+ const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
- hashlimit_mt_save(info, 128);
+ hashlimit_mt_save(&info->cfg, info->name, 128, 2);
}
static struct xtables_match hashlimit_mt_reg[] = {
@@ -696,6 +941,38 @@ static struct xtables_match hashlimit_mt_reg[] = {
.size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
.userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
.help = hashlimit_mt_help,
+ .init = hashlimit_mt4_init_v1,
+ .x6_parse = hashlimit_mt_parse_v1,
+ .x6_fcheck = hashlimit_mt_check_v1,
+ .print = hashlimit_mt4_print_v1,
+ .save = hashlimit_mt4_save_v1,
+ .x6_options = hashlimit_mt_opts_v1,
+ .udata_size = sizeof(struct hashlimit_mt_udata),
+ },
+ {
+ .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_v1,
+ .x6_parse = hashlimit_mt_parse_v1,
+ .x6_fcheck = hashlimit_mt_check_v1,
+ .print = hashlimit_mt6_print_v1,
+ .save = hashlimit_mt6_save_v1,
+ .x6_options = hashlimit_mt_opts_v1,
+ .udata_size = sizeof(struct hashlimit_mt_udata),
+ },
+ {
+ .version = XTABLES_VERSION,
+ .name = "hashlimit",
+ .revision = 2,
+ .family = NFPROTO_IPV4,
+ .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)),
+ .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo),
+ .help = hashlimit_mt_help,
.init = hashlimit_mt4_init,
.x6_parse = hashlimit_mt_parse,
.x6_fcheck = hashlimit_mt_check,
@@ -707,10 +984,10 @@ static struct xtables_match hashlimit_mt_reg[] = {
{
.version = XTABLES_VERSION,
.name = "hashlimit",
- .revision = 1,
+ .revision = 2,
.family = NFPROTO_IPV6,
- .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
- .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
+ .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)),
+ .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo),
.help = hashlimit_mt_help,
.init = hashlimit_mt6_init,
.x6_parse = hashlimit_mt_parse,
diff --git a/extensions/libxt_hashlimit.man b/extensions/libxt_hashlimit.man
index 17cb2b00..6aac3f28 100644
--- a/extensions/libxt_hashlimit.man
+++ b/extensions/libxt_hashlimit.man
@@ -65,7 +65,7 @@ matching on source port
matching on subnet
"10000 packets per minute for every /28 subnet (groups of 8 addresses)
in 10.0.0.0/8" =>
-\-s 10.0.0.8 \-\-hashlimit\-mask 28 \-\-hashlimit\-upto 10000/min
+\-s 10.0.0.0/8 \-\-hashlimit\-mask 28 \-\-hashlimit\-upto 10000/min
.TP
matching bytes per second
"flows exceeding 512kbyte/s" =>
diff --git a/extensions/libxt_hashlimit.t b/extensions/libxt_hashlimit.t
new file mode 100644
index 00000000..d27c8616
--- /dev/null
+++ b/extensions/libxt_hashlimit.t
@@ -0,0 +1,28 @@
+:INPUT,FORWARD,OUTPUT
+-m hashlimit --hashlimit-above 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-above 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-above 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-above 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+# kernel says "xt_hashlimit: overflow, try lower: 864000000/5"
+-m hashlimit --hashlimit-above 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-upto 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-upto 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-upto 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+# kernel says "xt_hashlimit: overflow, try lower: 864000000/5"
+-m hashlimit --hashlimit-upto 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode srcip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-max 2000 --hashlimit-htable-expire 2000;=;OK
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-max 2000 --hashlimit-htable-gcinterval 60000 --hashlimit-htable-expire 2000;=;OK
+-m hashlimit --hashlimit-upto 1/sec --hashlimit-name mini1;-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 5 --hashlimit-name mini1;OK
+-m hashlimit --hashlimit-upto 4kb/s --hashlimit-burst 400kb --hashlimit-name mini5;=;OK
+-m hashlimit --hashlimit-upto 10mb/s --hashlimit-name mini6;=;OK
+-m hashlimit --hashlimit-upto 123456b/s --hashlimit-burst 1mb --hashlimit-name mini7;=;OK
+# should work, it says "iptables v1.4.15: burst cannot be smaller than 96b"
+# ERROR: cannot load: iptables -A INPUT -m hashlimit --hashlimit-upto 96b/s --hashlimit-burst 5 --hashlimit-name mini1
+# -m hashlimit --hashlimit-upto 96b/s --hashlimit-burst 5 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-name mini1;;FAIL
+-m hashlimit --hashlimit-upto 1/sec;;FAIL
+-m hashlimit;;FAIL
diff --git a/extensions/libxt_helper.c b/extensions/libxt_helper.c
index c9f9435e..2afbf996 100644
--- a/extensions/libxt_helper.c
+++ b/extensions/libxt_helper.c
@@ -45,6 +45,21 @@ static void helper_save(const void *ip, const struct xt_entry_match *match)
xtables_save_string(info->name);
}
+static int helper_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_helper_info *info = (const void *)params->match->data;
+
+ if (params->escape_quotes)
+ xt_xlate_add(xl, "ct helper%s \\\"%s\\\"",
+ info->invert ? " !=" : "", info->name);
+ else
+ xt_xlate_add(xl, "ct helper%s \"%s\"",
+ info->invert ? " !=" : "", info->name);
+
+ return 1;
+}
+
static struct xtables_match helper_match = {
.family = NFPROTO_UNSPEC,
.name = "helper",
@@ -55,6 +70,7 @@ static struct xtables_match helper_match = {
.save = helper_save,
.x6_parse = helper_parse,
.x6_options = helper_opts,
+ .xlate = helper_xlate,
};
void _init(void)
diff --git a/extensions/libxt_helper.t b/extensions/libxt_helper.t
new file mode 100644
index 00000000..8c8420ac
--- /dev/null
+++ b/extensions/libxt_helper.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-m helper --helper ftp;=;OK
+# should be OK?
+# ERROR: should fail: iptables -A INPUT -m helper --helper wrong
+# -m helper --helper wrong;;FAIL
+-m helper;;FAIL
diff --git a/extensions/libxt_ipcomp.c b/extensions/libxt_ipcomp.c
new file mode 100644
index 00000000..b5c43128
--- /dev/null
+++ b/extensions/libxt_ipcomp.c
@@ -0,0 +1,134 @@
+#include <stdio.h>
+#include <xtables.h>
+#include <linux/netfilter/xt_ipcomp.h>
+
+enum {
+ O_compSPI = 0,
+ O_compRES,
+};
+
+static void comp_help(void)
+{
+ printf(
+"comp match options:\n"
+"[!] --ipcompspi spi[:spi]\n"
+" match spi (range)\n");
+}
+
+static const struct xt_option_entry comp_opts[] = {
+ {.name = "ipcompspi", .id = O_compSPI, .type = XTTYPE_UINT32RC,
+ .flags = XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct xt_ipcomp, spis)},
+ {.name = "compres", .id = O_compRES, .type = XTTYPE_NONE},
+ XTOPT_TABLEEND,
+};
+#undef s
+
+static void comp_parse(struct xt_option_call *cb)
+{
+ struct xt_ipcomp *compinfo = cb->data;
+
+ xtables_option_parse(cb);
+ switch (cb->entry->id) {
+ case O_compSPI:
+ if (cb->nvals == 1)
+ compinfo->spis[1] = compinfo->spis[0];
+ if (cb->invert)
+ compinfo->invflags |= XT_IPCOMP_INV_SPI;
+ break;
+ case O_compRES:
+ compinfo->hdrres = 1;
+ break;
+ }
+}
+
+static void
+print_spis(const char *name, uint32_t min, uint32_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 comp_print(const void *ip, const struct xt_entry_match *match,
+ int numeric)
+{
+ const struct xt_ipcomp *comp = (struct xt_ipcomp *)match->data;
+
+ printf(" comp ");
+ print_spis("spi", comp->spis[0], comp->spis[1],
+ comp->invflags & XT_IPCOMP_INV_SPI);
+
+ if (comp->hdrres)
+ printf(" reserved");
+
+ if (comp->invflags & ~XT_IPCOMP_INV_MASK)
+ printf(" Unknown invflags: 0x%X",
+ comp->invflags & ~XT_IPCOMP_INV_MASK);
+}
+
+static void comp_save(const void *ip, const struct xt_entry_match *match)
+{
+ const struct xt_ipcomp *compinfo = (struct xt_ipcomp *)match->data;
+
+ if (!(compinfo->spis[0] == 0
+ && compinfo->spis[1] == 0xFFFFFFFF)) {
+ printf("%s --ipcompspi ",
+ (compinfo->invflags & XT_IPCOMP_INV_SPI) ? " !" : "");
+ if (compinfo->spis[0]
+ != compinfo->spis[1])
+ printf("%u:%u",
+ compinfo->spis[0],
+ compinfo->spis[1]);
+ else
+ printf("%u",
+ compinfo->spis[0]);
+ }
+
+ if (compinfo->hdrres != 0 )
+ printf(" --compres");
+}
+
+static int comp_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_ipcomp *compinfo =
+ (struct xt_ipcomp *)params->match->data;
+
+ xt_xlate_add(xl, "comp cpi %s",
+ compinfo->invflags & XT_IPCOMP_INV_SPI ? "!= " : "");
+ if (compinfo->spis[0] != compinfo->spis[1])
+ xt_xlate_add(xl, "%u-%u", compinfo->spis[0],
+ compinfo->spis[1]);
+ else
+ xt_xlate_add(xl, "%u", compinfo->spis[0]);
+
+ return 1;
+}
+
+static struct xtables_match comp_mt_reg = {
+ .name = "ipcomp",
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_UNSPEC,
+ .size = XT_ALIGN(sizeof(struct xt_ipcomp)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_ipcomp)),
+ .help = comp_help,
+ .print = comp_print,
+ .save = comp_save,
+ .x6_parse = comp_parse,
+ .x6_options = comp_opts,
+ .xlate = comp_xlate,
+};
+
+void
+_init(void)
+{
+ xtables_register_match(&comp_mt_reg);
+};
+
diff --git a/extensions/libxt_ipcomp.c.man b/extensions/libxt_ipcomp.c.man
new file mode 100644
index 00000000..f3b17d21
--- /dev/null
+++ b/extensions/libxt_ipcomp.c.man
@@ -0,0 +1,7 @@
+This module matches the parameters in IPcomp header of IPsec packets.
+.TP
+[\fB!\fP] \fB\-\-ipcompspi\fP \fIspi\fP[\fB:\fP\fIspi\fP]
+Matches IPcomp header CPI value.
+.TP
+\fB\-\-compres\fP
+Matches if the reserved field is filled with zero.
diff --git a/extensions/libxt_iprange.c b/extensions/libxt_iprange.c
index 2c9ea992..8be24814 100644
--- a/extensions/libxt_iprange.c
+++ b/extensions/libxt_iprange.c
@@ -104,7 +104,8 @@ static void iprange_parse(struct xt_option_call *cb)
info->flags |= IPRANGE_SRC;
if (cb->invert)
info->flags |= IPRANGE_SRC_INV;
- iprange_parse_range(cb->arg, range, NFPROTO_IPV4, "--src-range");
+ iprange_parse_range(cb->arg, range,
+ NFPROTO_IPV4, "--src-range");
info->src.min_ip = range[0].ip;
info->src.max_ip = range[1].ip;
break;
@@ -112,7 +113,8 @@ static void iprange_parse(struct xt_option_call *cb)
info->flags |= IPRANGE_DST;
if (cb->invert)
info->flags |= IPRANGE_DST_INV;
- iprange_parse_range(cb->arg, range, NFPROTO_IPV4, "--dst-range");
+ iprange_parse_range(cb->arg, range,
+ NFPROTO_IPV4, "--dst-range");
info->dst.min_ip = range[0].ip;
info->dst.max_ip = range[1].ip;
break;
@@ -172,7 +174,7 @@ print_iprange(const struct ipt_iprange *range)
}
static void iprange_print(const void *ip, const struct xt_entry_match *match,
- int numeric)
+ int numeric)
{
const struct ipt_iprange_info *info = (const void *)match->data;
@@ -192,7 +194,7 @@ static void iprange_print(const void *ip, const struct xt_entry_match *match,
static void
iprange_mt4_print(const void *ip, const struct xt_entry_match *match,
- int numeric)
+ int numeric)
{
const struct xt_iprange_mtinfo *info = (const void *)match->data;
@@ -218,7 +220,7 @@ iprange_mt4_print(const void *ip, const struct xt_entry_match *match,
static void
iprange_mt6_print(const void *ip, const struct xt_entry_match *match,
- int numeric)
+ int numeric)
{
const struct xt_iprange_mtinfo *info = (const void *)match->data;
@@ -267,13 +269,15 @@ static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match)
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(" --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(" --dst-range %s",
+ xtables_ipaddr_to_numeric(&info->dst_min.in));
printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in));
}
}
@@ -285,17 +289,105 @@ static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match)
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(" --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(" --dst-range %s",
+ xtables_ip6addr_to_numeric(&info->dst_min.in6));
printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6));
}
}
+static void
+print_iprange_xlate(const struct ipt_iprange *range,
+ struct xt_xlate *xl)
+{
+ const unsigned char *byte_min, *byte_max;
+
+ byte_min = (const unsigned char *)&range->min_ip;
+ byte_max = (const unsigned char *)&range->max_ip;
+ xt_xlate_add(xl, " %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 int iprange_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct ipt_iprange_info *info = (const void *)params->match->data;
+ char *space = "";
+
+ if (info->flags & IPRANGE_SRC) {
+ xt_xlate_add(xl, "ip saddr%s",
+ info->flags & IPRANGE_SRC_INV ? " !=" : "");
+ print_iprange_xlate(&info->src, xl);
+ space = " ";
+ }
+ if (info->flags & IPRANGE_DST) {
+ xt_xlate_add(xl, "%sip daddr%s", space,
+ info->flags & IPRANGE_DST_INV ? " !=" : "");
+ print_iprange_xlate(&info->dst, xl);
+ }
+
+ return 1;
+}
+
+static int iprange_mt4_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_iprange_mtinfo *info =
+ (const void *)params->match->data;
+ char *space = "";
+
+ if (info->flags & IPRANGE_SRC) {
+ xt_xlate_add(xl, "ip saddr%s %s",
+ info->flags & IPRANGE_SRC_INV ? " !=" : "",
+ xtables_ipaddr_to_numeric(&info->src_min.in));
+ xt_xlate_add(xl, "-%s",
+ xtables_ipaddr_to_numeric(&info->src_max.in));
+ space = " ";
+ }
+ if (info->flags & IPRANGE_DST) {
+ xt_xlate_add(xl, "%sip daddr%s %s", space,
+ info->flags & IPRANGE_DST_INV ? " !=" : "",
+ xtables_ipaddr_to_numeric(&info->dst_min.in));
+ xt_xlate_add(xl, "-%s",
+ xtables_ipaddr_to_numeric(&info->dst_max.in));
+ }
+
+ return 1;
+}
+
+static int iprange_mt6_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_iprange_mtinfo *info =
+ (const void *)params->match->data;
+ char *space = "";
+
+ if (info->flags & IPRANGE_SRC) {
+ xt_xlate_add(xl, "ip6 saddr%s %s",
+ info->flags & IPRANGE_SRC_INV ? " !=" : "",
+ xtables_ip6addr_to_numeric(&info->src_min.in6));
+ xt_xlate_add(xl, "-%s",
+ xtables_ip6addr_to_numeric(&info->src_max.in6));
+ space = " ";
+ }
+ if (info->flags & IPRANGE_DST) {
+ xt_xlate_add(xl, "%sip6 daddr%s %s", space,
+ info->flags & IPRANGE_DST_INV ? " !=" : "",
+ xtables_ip6addr_to_numeric(&info->dst_min.in6));
+ xt_xlate_add(xl, "-%s",
+ xtables_ip6addr_to_numeric(&info->dst_max.in6));
+ }
+
+ return 1;
+}
+
static struct xtables_match iprange_mt_reg[] = {
{
.version = XTABLES_VERSION,
@@ -310,6 +402,7 @@ static struct xtables_match iprange_mt_reg[] = {
.print = iprange_print,
.save = iprange_save,
.x6_options = iprange_mt_opts,
+ .xlate = iprange_xlate,
},
{
.version = XTABLES_VERSION,
@@ -324,6 +417,7 @@ static struct xtables_match iprange_mt_reg[] = {
.print = iprange_mt4_print,
.save = iprange_mt4_save,
.x6_options = iprange_mt_opts,
+ .xlate = iprange_mt4_xlate,
},
{
.version = XTABLES_VERSION,
@@ -338,6 +432,7 @@ static struct xtables_match iprange_mt_reg[] = {
.print = iprange_mt6_print,
.save = iprange_mt6_save,
.x6_options = iprange_mt_opts,
+ .xlate = iprange_mt6_xlate,
},
};
diff --git a/extensions/libxt_iprange.t b/extensions/libxt_iprange.t
new file mode 100644
index 00000000..6fd98be6
--- /dev/null
+++ b/extensions/libxt_iprange.t
@@ -0,0 +1,11 @@
+:INPUT,FORWARD,OUTPUT
+-m iprange --src-range 1.1.1.1-1.1.1.10;=;OK
+-m iprange ! --src-range 1.1.1.1-1.1.1.10;=;OK
+-m iprange --dst-range 1.1.1.1-1.1.1.10;=;OK
+-m iprange ! --dst-range 1.1.1.1-1.1.1.10;=;OK
+# it shows -A INPUT -m iprange --src-range 1.1.1.1-1.1.1.1, should we support this?
+# ERROR: should fail: iptables -A INPUT -m iprange --src-range 1.1.1.1
+# -m iprange --src-range 1.1.1.1;;FAIL
+# ERROR: should fail: iptables -A INPUT -m iprange --dst-range 1.1.1.1
+#-m iprange --dst-range 1.1.1.1;;FAIL
+-m iprange;;FAIL
diff --git a/extensions/libxt_length.c b/extensions/libxt_length.c
index 6ea76465..04eac4a5 100644
--- a/extensions/libxt_length.c
+++ b/extensions/libxt_length.c
@@ -56,6 +56,21 @@ static void length_save(const void *ip, const struct xt_entry_match *match)
printf("%u:%u", info->min, info->max);
}
+static int length_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_length_info *info = (void *)params->match->data;
+
+ xt_xlate_add(xl, "meta length %s", info->invert ? "!= " : "");
+ if (info->min == info->max)
+ xt_xlate_add(xl, "%u", info->min);
+ else
+ xt_xlate_add(xl, "%u-%u", info->min, info->max);
+
+ return 1;
+}
+
+
static struct xtables_match length_match = {
.family = NFPROTO_UNSPEC,
.name = "length",
@@ -67,6 +82,7 @@ static struct xtables_match length_match = {
.save = length_save,
.x6_parse = length_parse,
.x6_options = length_opts,
+ .xlate = length_xlate,
};
void _init(void)
diff --git a/extensions/libxt_length.t b/extensions/libxt_length.t
new file mode 100644
index 00000000..0b6624ee
--- /dev/null
+++ b/extensions/libxt_length.t
@@ -0,0 +1,10 @@
+:INPUT,FORWARD,OUTPUT
+-m length --length 1;=;OK
+-m length --length :2;-m length --length 0:2;OK
+-m length --length 0:3;=;OK
+-m length --length 4:;=;OK
+-m length --length 0:65535;=;OK
+-m length ! --length 0:65535;=;OK
+-m length --length 0:65536;;FAIL
+-m length --length -1:65535;;FAIL
+-m length;;FAIL
diff --git a/extensions/libxt_limit.c b/extensions/libxt_limit.c
index f75ef2f8..5cc95c2e 100644
--- a/extensions/libxt_limit.c
+++ b/extensions/libxt_limit.c
@@ -152,6 +152,44 @@ static void limit_save(const void *ip, const struct xt_entry_match *match)
printf(" --limit-burst %u", r->burst);
}
+static const struct rates rates_xlate[] = {
+ { "day", XT_LIMIT_SCALE * 24 * 60 * 60 },
+ { "hour", XT_LIMIT_SCALE * 60 * 60 },
+ { "minute", XT_LIMIT_SCALE * 60 },
+ { "second", XT_LIMIT_SCALE }
+};
+
+static void print_rate_xlate(uint32_t period, struct xt_xlate *xl)
+{
+ unsigned int i;
+
+ if (period == 0) {
+ xt_xlate_add(xl, " %f", INFINITY);
+ return;
+ }
+
+ for (i = 1; i < ARRAY_SIZE(rates); ++i)
+ if (period > rates_xlate[i].mult ||
+ rates_xlate[i].mult / period < rates_xlate[i].mult % period)
+ break;
+
+ xt_xlate_add(xl, " %u/%s", rates_xlate[i - 1].mult / period,
+ rates_xlate[i - 1].name);
+}
+
+static int limit_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_rateinfo *r = (const void *)params->match->data;
+
+ xt_xlate_add(xl, "limit rate");
+ print_rate_xlate(r->avg, xl);
+ if (r->burst != 0)
+ xt_xlate_add(xl, " burst %u packets", r->burst);
+
+ return 1;
+}
+
static struct xtables_match limit_match = {
.family = NFPROTO_UNSPEC,
.name = "limit",
@@ -164,6 +202,7 @@ static struct xtables_match limit_match = {
.print = limit_print,
.save = limit_save,
.x6_options = limit_opts,
+ .xlate = limit_xlate,
};
void _init(void)
diff --git a/extensions/libxt_limit.t b/extensions/libxt_limit.t
new file mode 100644
index 00000000..b0af6538
--- /dev/null
+++ b/extensions/libxt_limit.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-m limit --limit 1/sec;=;OK
+-m limit --limit 1/min;=;OK
+-m limit --limit 1000/hour;=;OK
+-m limit --limit 1000/day;=;OK
+-m limit --limit 1/sec --limit-burst 1;=;OK
diff --git a/extensions/libxt_mac.c b/extensions/libxt_mac.c
index f171d153..b6d717bc 100644
--- a/extensions/libxt_mac.c
+++ b/extensions/libxt_mac.c
@@ -50,11 +50,12 @@ 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);
}
@@ -69,9 +70,30 @@ static void mac_save(const void *ip, const struct xt_entry_match *match)
print_mac(info->srcaddr);
}
+static void print_mac_xlate(const unsigned char *macaddress,
+ struct xt_xlate *xl)
+{
+ unsigned int i;
+
+ xt_xlate_add(xl, "%02x", macaddress[0]);
+ for (i = 1; i < ETH_ALEN; ++i)
+ xt_xlate_add(xl, ":%02x", macaddress[i]);
+}
+
+static int mac_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_mac_info *info = (void *)params->match->data;
+
+ xt_xlate_add(xl, "ether saddr%s ", info->invert ? " !=" : "");
+ print_mac_xlate(info->srcaddr, xl);
+
+ return 1;
+}
+
static struct xtables_match mac_match = {
.family = NFPROTO_UNSPEC,
- .name = "mac",
+ .name = "mac",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_mac_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_mac_info)),
@@ -80,6 +102,7 @@ static struct xtables_match mac_match = {
.print = mac_print,
.save = mac_save,
.x6_options = mac_opts,
+ .xlate = mac_xlate,
};
void _init(void)
diff --git a/extensions/libxt_mac.t b/extensions/libxt_mac.t
new file mode 100644
index 00000000..a5ec81d8
--- /dev/null
+++ b/extensions/libxt_mac.t
@@ -0,0 +1,5 @@
+:INPUT,FORWARD
+-m mac --mac-source 42:01:02:03:04:05;=;OK
+-m mac --mac-source 42:01:02:03:04;=;FAIL
+-m mac --mac-source 42:01:02:03:04:05:06;=;FAIL
+-m mac;;FAIL
diff --git a/extensions/libxt_mangle.c b/extensions/libxt_mangle.c
new file mode 100644
index 00000000..360742b6
--- /dev/null
+++ b/extensions/libxt_mangle.c
@@ -0,0 +1,396 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Libarptc code from: Bart De Schuymer <bdschuym@pandora.be>
+ * Port to libxtables: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
+ */
+
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <getopt.h>
+#include <errno.h>
+#include <netinet/ether.h>
+
+#include <xtables.h>
+#include <linux/netfilter_arp/arpt_mangle.h>
+
+static void mangle_help(void)
+{
+ printf(
+"mangle target options:\n"
+"--mangle-ip-s IP address\n"
+"--mangle-ip-d IP address\n"
+"--mangle-mac-s MAC address\n"
+"--mangle-mac-d MAC address\n"
+"--mangle-target target (DROP, CONTINUE or ACCEPT -- default is ACCEPT)\n"
+ );
+}
+
+enum {
+ MANGLE_IPS = 0,
+ MANGLE_IPT = 1,
+ MANGLE_DEVS = 2,
+ MANGLE_DEVT = 3,
+ MANGLE_TARGET = 4,
+};
+
+static const struct xt_option_entry mangle_opts[] = {
+ { .name = "mangle-ip-s", .id = MANGLE_IPS, .type = XTTYPE_STRING },
+ { .name = "mangle-ip-d", .id = MANGLE_IPT, .type = XTTYPE_STRING },
+ { .name = "mangle-mac-s", .id = MANGLE_DEVS, .type = XTTYPE_STRING },
+ { .name = "mangle-mac-d", .id = MANGLE_DEVT, .type = XTTYPE_STRING },
+ { .name = "mangle-target", .id = MANGLE_TARGET,
+ .type = XTTYPE_STRING },
+ XTOPT_TABLEEND,
+};
+
+
+static struct in_addr *network_to_addr(const char *name)
+{
+ struct netent *net;
+ static struct in_addr addr;
+
+ if ((net = getnetbyname(name)) != NULL) {
+ if (net->n_addrtype != AF_INET)
+ return (struct in_addr *) NULL;
+ addr.s_addr = htonl((unsigned long) net->n_net);
+ return &addr;
+ }
+
+ return (struct in_addr *) NULL;
+}
+
+static void inaddrcpy(struct in_addr *dst, struct in_addr *src)
+{
+ dst->s_addr = src->s_addr;
+}
+
+static struct in_addr *host_to_addr(const char *name, unsigned int *naddr)
+{
+ struct in_addr *addr;
+ struct addrinfo hints;
+ struct addrinfo *res, *p;
+ int err;
+ unsigned int i;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_RAW;
+
+ *naddr = 0;
+ err = getaddrinfo(name, NULL, &hints, &res);
+ if (err != 0)
+ return NULL;
+ else {
+ for (p = res; p != NULL; p = p->ai_next)
+ (*naddr)++;
+ addr = xtables_calloc(*naddr, sizeof(struct in_addr));
+ for (i = 0, p = res; p != NULL; p = p->ai_next)
+ memcpy(&addr[i++],
+ &((const struct sockaddr_in *)p->ai_addr)->sin_addr,
+ sizeof(struct in_addr));
+ freeaddrinfo(res);
+ return addr;
+ }
+
+ return (struct in_addr *) NULL;
+}
+
+static int string_to_number(const char *s, unsigned int min,
+ unsigned int max, unsigned int *ret)
+{
+ long number;
+ char *end;
+
+ /* Handle hex, octal, etc. */
+ errno = 0;
+ number = strtol(s, &end, 0);
+ if (*end == '\0' && end != s) {
+ /* we parsed a number, let's see if we want this */
+ if (errno != ERANGE && min <= number && number <= max) {
+ *ret = number;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static struct in_addr *dotted_to_addr(const char *dotted)
+{
+ static struct in_addr addr;
+ unsigned char *addrp;
+ char *p, *q;
+ unsigned int onebyte;
+ int i;
+ char buf[20];
+
+ /* copy dotted string, because we need to modify it */
+ strncpy(buf, dotted, sizeof(buf) - 1);
+ addrp = (unsigned char *) &(addr.s_addr);
+
+ p = buf;
+ for (i = 0; i < 3; i++) {
+ if ((q = strchr(p, '.')) == NULL)
+ return (struct in_addr *) NULL;
+
+ *q = '\0';
+ if (string_to_number(p, 0, 255, &onebyte) == -1)
+ return (struct in_addr *) NULL;
+
+ addrp[i] = (unsigned char) onebyte;
+ p = q + 1;
+ }
+
+ /* we've checked 3 bytes, now we check the last one */
+ if (string_to_number(p, 0, 255, &onebyte) == -1)
+ return (struct in_addr *) NULL;
+
+ addrp[3] = (unsigned char) onebyte;
+
+ return &addr;
+}
+
+static struct in_addr *parse_hostnetwork(const char *name,
+ unsigned int *naddrs)
+{
+ struct in_addr *addrp, *addrptmp;
+
+ if ((addrptmp = dotted_to_addr(name)) != NULL ||
+ (addrptmp = network_to_addr(name)) != NULL) {
+ addrp = xtables_malloc(sizeof(struct in_addr));
+ inaddrcpy(addrp, addrptmp);
+ *naddrs = 1;
+ return addrp;
+ }
+ if ((addrp = host_to_addr(name, naddrs)) != NULL)
+ return addrp;
+
+ xtables_error(PARAMETER_PROBLEM, "host/network `%s' not found", name);
+}
+
+static void mangle_parse(struct xt_option_call *cb)
+{
+ const struct arpt_entry *e = cb->xt_entry;
+ struct arpt_mangle *mangle = cb->data;
+ struct in_addr *ipaddr;
+ struct ether_addr *macaddr;
+
+ /* mangle target is by default "ACCEPT". Setting it here,
+ * since original arpt_mangle.c init() no longer exists*/
+ mangle->target = NF_ACCEPT;
+
+ xtables_option_parse(cb);
+ switch (cb->entry->id) {
+ case MANGLE_IPS:
+/*
+ if (e->arp.arpln_mask == 0)
+ xtables_error(PARAMETER_PROBLEM, "no pln defined");
+
+ if (e->arp.invflags & ARPT_INV_ARPPLN)
+ xtables_error(PARAMETER_PROBLEM,
+ "! pln not allowed for --mangle-ip-s");
+*/
+/*
+ if (e->arp.arpln != 4)
+ xtables_error(PARAMETER_PROBLEM, "only pln=4 supported");
+*/
+ {
+ unsigned int nr;
+ ipaddr = parse_hostnetwork(cb->arg, &nr);
+ }
+ mangle->u_s.src_ip.s_addr = ipaddr->s_addr;
+ free(ipaddr);
+ mangle->flags |= ARPT_MANGLE_SIP;
+ break;
+ case MANGLE_IPT:
+/*
+ if (e->arp.arpln_mask == 0)
+ xtables_error(PARAMETER_PROBLEM, "no pln defined");
+
+ if (e->arp.invflags & ARPT_INV_ARPPLN)
+ xtables_error(PARAMETER_PROBLEM,
+ "! pln not allowed for --mangle-ip-d");
+*/
+/*
+ if (e->arp.arpln != 4)
+ xtables_error(PARAMETER_PROBLEM, "only pln=4 supported");
+*/
+ {
+ unsigned int nr;
+ ipaddr = parse_hostnetwork(cb->arg, &nr);
+ }
+ mangle->u_t.tgt_ip.s_addr = ipaddr->s_addr;
+ free(ipaddr);
+ mangle->flags |= ARPT_MANGLE_TIP;
+ break;
+ case MANGLE_DEVS:
+ if (e->arp.arhln_mask == 0)
+ xtables_error(PARAMETER_PROBLEM,
+ "no --h-length defined");
+ if (e->arp.invflags & ARPT_INV_ARPHLN)
+ xtables_error(PARAMETER_PROBLEM,
+ "! --h-length not allowed for "
+ "--mangle-mac-s");
+ if (e->arp.arhln != 6)
+ xtables_error(PARAMETER_PROBLEM,
+ "only --h-length 6 supported");
+ macaddr = ether_aton(cb->arg);
+ if (macaddr == NULL)
+ xtables_error(PARAMETER_PROBLEM, "invalid source MAC");
+ memcpy(mangle->src_devaddr, macaddr, e->arp.arhln);
+ mangle->flags |= ARPT_MANGLE_SDEV;
+ break;
+ case MANGLE_DEVT:
+ if (e->arp.arhln_mask == 0)
+ xtables_error(PARAMETER_PROBLEM,
+ "no --h-length defined");
+ if (e->arp.invflags & ARPT_INV_ARPHLN)
+ xtables_error(PARAMETER_PROBLEM,
+ "! hln not allowed for --mangle-mac-d");
+ if (e->arp.arhln != 6)
+ xtables_error(PARAMETER_PROBLEM,
+ "only --h-length 6 supported");
+ macaddr = ether_aton(cb->arg);
+ if (macaddr == NULL)
+ xtables_error(PARAMETER_PROBLEM, "invalid target MAC");
+ memcpy(mangle->tgt_devaddr, macaddr, e->arp.arhln);
+ mangle->flags |= ARPT_MANGLE_TDEV;
+ break;
+ case MANGLE_TARGET:
+ if (!strcmp(cb->arg, "DROP"))
+ mangle->target = NF_DROP;
+ else if (!strcmp(cb->arg, "ACCEPT"))
+ mangle->target = NF_ACCEPT;
+ else if (!strcmp(cb->arg, "CONTINUE"))
+ mangle->target = ARPT_CONTINUE;
+ else
+ xtables_error(PARAMETER_PROBLEM,
+ "bad target for --mangle-target");
+ break;
+ }
+}
+
+static void mangle_fcheck(struct xt_fcheck_call *cb)
+{
+}
+
+static char *addr_to_dotted(const struct in_addr *addrp)
+{
+ static char buf[20];
+ const unsigned char *bytep;
+
+ bytep = (const unsigned char *) &(addrp->s_addr);
+ sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
+ return buf;
+}
+
+static char *addr_to_host(const struct in_addr *addr)
+{
+ struct hostent *host;
+
+ if ((host = gethostbyaddr((char *) addr,
+ sizeof(struct in_addr), AF_INET)) != NULL)
+ return (char *) host->h_name;
+
+ return (char *) NULL;
+}
+
+static char *addr_to_network(const struct in_addr *addr)
+{
+ struct netent *net;
+
+ if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL)
+ return (char *) net->n_name;
+
+ return (char *) NULL;
+}
+
+static char *addr_to_anyname(const struct in_addr *addr)
+{
+ char *name;
+
+ if ((name = addr_to_host(addr)) != NULL ||
+ (name = addr_to_network(addr)) != NULL)
+ return name;
+
+ return addr_to_dotted(addr);
+}
+
+static void print_mac(const unsigned char *mac, int l)
+{
+ int j;
+
+ for (j = 0; j < l; j++)
+ printf("%02x%s", mac[j],
+ (j==l-1) ? "" : ":");
+}
+
+static void mangle_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ const struct arpt_mangle *m = (const void *)target;
+ char buf[100];
+
+ if (m->flags & ARPT_MANGLE_SIP) {
+ if (numeric)
+ sprintf(buf, "%s", addr_to_dotted(&(m->u_s.src_ip)));
+ else
+ sprintf(buf, "%s", addr_to_anyname(&(m->u_s.src_ip)));
+ printf("--mangle-ip-s %s ", buf);
+ }
+ if (m->flags & ARPT_MANGLE_SDEV) {
+ printf("--mangle-mac-s ");
+ print_mac((unsigned char *)m->src_devaddr, 6);
+ printf(" ");
+ }
+ if (m->flags & ARPT_MANGLE_TIP) {
+ if (numeric)
+ sprintf(buf, "%s", addr_to_dotted(&(m->u_t.tgt_ip)));
+ else
+ sprintf(buf, "%s", addr_to_anyname(&(m->u_t.tgt_ip)));
+ printf("--mangle-ip-d %s ", buf);
+ }
+ if (m->flags & ARPT_MANGLE_TDEV) {
+ printf("--mangle-mac-d ");
+ print_mac((unsigned char *)m->tgt_devaddr, 6);
+ printf(" ");
+ }
+ if (m->target != NF_ACCEPT) {
+ printf("--mangle-target ");
+ if (m->target == NF_DROP)
+ printf("DROP ");
+ else
+ printf("CONTINUE ");
+ }
+}
+
+static void mangle_save(const void *ip, const struct xt_entry_target *target)
+{
+}
+
+static struct xtables_target mangle_tg_reg = {
+ .family = NFPROTO_ARP,
+ .name = "mangle",
+ .version = XTABLES_VERSION,
+ .size = XT_ALIGN(sizeof(struct arpt_mangle)),
+ .userspacesize = XT_ALIGN(sizeof(struct arpt_mangle)),
+ .help = mangle_help,
+ .x6_parse = mangle_parse,
+ .x6_fcheck = mangle_fcheck,
+ .print = mangle_print,
+ .save = mangle_save,
+ .x6_options = mangle_opts,
+};
+
+void _init(void)
+{
+ xtables_register_target(&mangle_tg_reg);
+}
diff --git a/extensions/libxt_mark.c b/extensions/libxt_mark.c
index 7f8c995c..e1d00de9 100644
--- a/extensions/libxt_mark.c
+++ b/extensions/libxt_mark.c
@@ -75,7 +75,7 @@ mark_print(const void *ip, const struct xt_entry_match *match, int numeric)
if (info->invert)
printf(" !");
-
+
print_mark(info->mark, info->mask);
}
@@ -97,11 +97,53 @@ mark_save(const void *ip, const struct xt_entry_match *match)
if (info->invert)
printf(" !");
-
+
printf(" --mark");
print_mark(info->mark, info->mask);
}
+static void
+print_mark_xlate(struct xt_xlate *xl, unsigned int mark,
+ unsigned int mask, uint32_t op)
+{
+ if (mask != 0xffffffffU)
+ xt_xlate_add(xl, " and 0x%x %s 0x%x", mask,
+ op == XT_OP_EQ ? "==" : "!=", mark);
+ else
+ xt_xlate_add(xl, " %s0x%x",
+ op == XT_OP_EQ ? "" : "!= ", mark);
+}
+
+static int mark_mt_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_mark_mtinfo1 *info = (const void *)params->match->data;
+ enum xt_op op = XT_OP_EQ;
+
+ if (info->invert)
+ op = XT_OP_NEQ;
+
+ xt_xlate_add(xl, "mark");
+ print_mark_xlate(xl, info->mark, info->mask, op);
+
+ return 1;
+}
+
+static int mark_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_mark_info *info = (const void *)params->match->data;
+ enum xt_op op = XT_OP_EQ;
+
+ if (info->invert)
+ op = XT_OP_NEQ;
+
+ xt_xlate_add(xl, "mark");
+ print_mark_xlate(xl, info->mark, info->mask, op);
+
+ return 1;
+}
+
static struct xtables_match mark_mt_reg[] = {
{
.family = NFPROTO_UNSPEC,
@@ -115,6 +157,7 @@ static struct xtables_match mark_mt_reg[] = {
.save = mark_save,
.x6_parse = mark_parse,
.x6_options = mark_mt_opts,
+ .xlate = mark_xlate,
},
{
.version = XTABLES_VERSION,
@@ -128,6 +171,7 @@ static struct xtables_match mark_mt_reg[] = {
.save = mark_mt_save,
.x6_parse = mark_mt_parse,
.x6_options = mark_mt_opts,
+ .xlate = mark_mt_xlate,
},
};
diff --git a/extensions/libxt_mark.t b/extensions/libxt_mark.t
new file mode 100644
index 00000000..7c005379
--- /dev/null
+++ b/extensions/libxt_mark.t
@@ -0,0 +1,7 @@
+:INPUT,FORWARD,OUTPUT
+-m mark --mark 0xfeedcafe/0xfeedcafe;=;OK
+-m mark --mark 0;=;OK
+-m mark --mark 4294967295;-m mark --mark 0xffffffff;OK
+-m mark --mark 4294967296;;FAIL
+-m mark --mark -1;;FAIL
+-m mark;;FAIL
diff --git a/extensions/libxt_multiport.c b/extensions/libxt_multiport.c
index 03af5a96..07ad4cfd 100644
--- a/extensions/libxt_multiport.c
+++ b/extensions/libxt_multiport.c
@@ -108,7 +108,6 @@ parse_multi_ports_v1(const char *portstring,
{
char *buffer, *cp, *next, *range;
unsigned int i;
- uint16_t m;
buffer = strdup(portstring);
if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
@@ -133,7 +132,6 @@ parse_multi_ports_v1(const char *portstring,
if (multiinfo->ports[i-1] >= multiinfo->ports[i])
xtables_error(PARAMETER_PROBLEM,
"invalid portrange specified");
- m <<= 1;
}
}
multiinfo->count = i;
@@ -468,6 +466,110 @@ static void multiport_save6_v1(const void *ip_void,
__multiport_save_v1(match, ip->proto);
}
+static int __multiport_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_multiport *multiinfo
+ = (const struct xt_multiport *)params->match->data;
+ unsigned int i;
+
+ switch (multiinfo->flags) {
+ case XT_MULTIPORT_SOURCE:
+ xt_xlate_add(xl, " sport ");
+ break;
+ case XT_MULTIPORT_DESTINATION:
+ xt_xlate_add(xl, " dport ");
+ break;
+ case XT_MULTIPORT_EITHER:
+ return 0;
+ }
+
+ if (multiinfo->count > 1)
+ xt_xlate_add(xl, "{ ");
+
+ for (i = 0; i < multiinfo->count; i++)
+ xt_xlate_add(xl, "%s%u", i ? "," : "", multiinfo->ports[i]);
+
+ if (multiinfo->count > 1)
+ xt_xlate_add(xl, "}");
+
+ return 1;
+}
+
+static int multiport_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ uint8_t proto = ((const struct ipt_ip *)params->ip)->proto;
+
+ xt_xlate_add(xl, "%s", proto_to_name(proto));
+ return __multiport_xlate(xl, params);
+}
+
+static int multiport_xlate6(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ uint8_t proto = ((const struct ip6t_ip6 *)params->ip)->proto;
+
+ xt_xlate_add(xl, "%s", proto_to_name(proto));
+ return __multiport_xlate(xl, params);
+}
+
+static int __multiport_xlate_v1(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_multiport_v1 *multiinfo =
+ (const struct xt_multiport_v1 *)params->match->data;
+ unsigned int i;
+
+ switch (multiinfo->flags) {
+ case XT_MULTIPORT_SOURCE:
+ xt_xlate_add(xl, " sport ");
+ break;
+ case XT_MULTIPORT_DESTINATION:
+ xt_xlate_add(xl, " dport ");
+ break;
+ case XT_MULTIPORT_EITHER:
+ return 0;
+ }
+
+ if (multiinfo->invert)
+ xt_xlate_add(xl, "!= ");
+
+ if (multiinfo->count > 2 ||
+ (multiinfo->count > 1 && !multiinfo->pflags[0]))
+ xt_xlate_add(xl, "{ ");
+
+ for (i = 0; i < multiinfo->count; i++) {
+ xt_xlate_add(xl, "%s%u", i ? "," : "", multiinfo->ports[i]);
+ if (multiinfo->pflags[i])
+ xt_xlate_add(xl, "-%u", multiinfo->ports[++i]);
+ }
+
+ if (multiinfo->count > 2 ||
+ (multiinfo->count > 1 && !multiinfo->pflags[0]))
+ xt_xlate_add(xl, "}");
+
+ return 1;
+}
+
+static int multiport_xlate_v1(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ uint8_t proto = ((const struct ipt_ip *)params->ip)->proto;
+
+ xt_xlate_add(xl, "%s", proto_to_name(proto));
+ return __multiport_xlate_v1(xl, params);
+}
+
+static int multiport_xlate6_v1(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ uint8_t proto = ((const struct ip6t_ip6 *)params->ip)->proto;
+
+ xt_xlate_add(xl, "%s", proto_to_name(proto));
+ return __multiport_xlate_v1(xl, params);
+}
+
static struct xtables_match multiport_mt_reg[] = {
{
.family = NFPROTO_IPV4,
@@ -482,6 +584,7 @@ static struct xtables_match multiport_mt_reg[] = {
.print = multiport_print,
.save = multiport_save,
.x6_options = multiport_opts,
+ .xlate = multiport_xlate,
},
{
.family = NFPROTO_IPV6,
@@ -496,6 +599,7 @@ static struct xtables_match multiport_mt_reg[] = {
.print = multiport_print6,
.save = multiport_save6,
.x6_options = multiport_opts,
+ .xlate = multiport_xlate6,
},
{
.family = NFPROTO_IPV4,
@@ -510,6 +614,7 @@ static struct xtables_match multiport_mt_reg[] = {
.print = multiport_print_v1,
.save = multiport_save_v1,
.x6_options = multiport_opts,
+ .xlate = multiport_xlate_v1,
},
{
.family = NFPROTO_IPV6,
@@ -524,6 +629,7 @@ static struct xtables_match multiport_mt_reg[] = {
.print = multiport_print6_v1,
.save = multiport_save6_v1,
.x6_options = multiport_opts,
+ .xlate = multiport_xlate6_v1,
},
};
diff --git a/extensions/libxt_multiport.t b/extensions/libxt_multiport.t
new file mode 100644
index 00000000..e9b80a4e
--- /dev/null
+++ b/extensions/libxt_multiport.t
@@ -0,0 +1,23 @@
+:INPUT,FORWARD,OUTPUT
+-p tcp -m multiport --sports 53,1024:65535;=;OK
+-p tcp -m multiport --dports 53,1024:65535;=;OK
+-p udp -m multiport --sports 53,1024:65535;=;OK
+-p udp -m multiport --dports 53,1024:65535;=;OK
+-p udp -m multiport --ports 53,1024:65535;=;OK
+-p udp -m multiport --ports 53,1024:65535;=;OK
+-p sctp -m multiport --sports 53,1024:65535;=;OK
+-p sctp -m multiport --dports 53,1024:65535;=;OK
+-p dccp -m multiport --sports 53,1024:65535;=;OK
+-p dccp -m multiport --dports 53,1024:65535;=;OK
+-p udplite -m multiport --sports 53,1024:65535;=;OK
+-p udplite -m multiport --dports 53,1024:65535;=;OK
+-p tcp -m multiport --sports 1024:65536;;FAIL
+-p udp -m multiport --sports 1024:65536;;FAIL
+-p tcp -m multiport --ports 1024:65536;;FAIL
+-p udp -m multiport --ports 1024:65536;;FAIL
+-p tcp -m multiport --ports 1,2,3,4,6,7,8,9,10,11,12,13,14,15;=;OK
+# fix manpage, it says "up to 15 ports supported"
+# ERROR: should fail: iptables -A INPUT -p tcp -m multiport --ports 1,2,3,4,6,7,8,9,10,11,12,13,14,15,16
+# -p tcp -m multiport --ports 1,2,3,4,6,7,8,9,10,11,12,13,14,15,16;;FAIL
+-p tcp --multiport;;FAIL
+-m multiport;;FAIL
diff --git a/extensions/libxt_nfacct.t b/extensions/libxt_nfacct.t
new file mode 100644
index 00000000..3419b4ce
--- /dev/null
+++ b/extensions/libxt_nfacct.t
@@ -0,0 +1,10 @@
+:INPUT,FORWARD,OUTPUT
+@nfacct add test
+#
+# extra space in iptables-save output, fix it
+#
+# ERROR: cannot load: iptables -A INPUT -m nfacct --nfacct-name test
+#-m nfacct --nfacct-name test;=;OK
+-m nfacct --nfacct-name wrong;;FAIL
+-m nfacct;;FAIL
+@nfacct del test
diff --git a/extensions/libxt_osf.c b/extensions/libxt_osf.c
index 52dba474..496b4805 100644
--- a/extensions/libxt_osf.c
+++ b/extensions/libxt_osf.c
@@ -14,7 +14,7 @@
*
* 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
diff --git a/extensions/libxt_osf.t b/extensions/libxt_osf.t
new file mode 100644
index 00000000..ede6d32c
--- /dev/null
+++ b/extensions/libxt_osf.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD
+-m osf --genre linux --ttl 0 --log 0;;FAIL
+-p tcp -m osf --genre linux --ttl 0 --log 0;=;OK
+-p tcp -m osf --genre linux --ttl 3 --log 0;;FAIL
diff --git a/extensions/libxt_owner.c b/extensions/libxt_owner.c
index d9adc12e..87e4df31 100644
--- a/extensions/libxt_owner.c
+++ b/extensions/libxt_owner.c
@@ -492,6 +492,56 @@ static void owner_mt_save(const void *ip, const struct xt_entry_match *match)
owner_mt_print_item(info, "--gid-owner", XT_OWNER_GID, true);
}
+static int
+owner_mt_print_uid_xlate(const struct xt_owner_match_info *info,
+ struct xt_xlate *xl)
+{
+ xt_xlate_add(xl, "skuid%s ", info->invert ? " !=" : "");
+
+ if (info->uid_min != info->uid_max)
+ xt_xlate_add(xl, "%u-%u", (unsigned int)info->uid_min,
+ (unsigned int)info->uid_max);
+ else
+ xt_xlate_add(xl, "%u", (unsigned int)info->uid_min);
+
+ return 1;
+}
+
+static int
+owner_mt_print_gid_xlate(const struct xt_owner_match_info *info,
+ struct xt_xlate *xl)
+{
+ xt_xlate_add(xl, "skgid%s ", info->invert ? " !=" : "");
+
+ if (info->gid_min != info->gid_max)
+ xt_xlate_add(xl, "%u-%u", (unsigned int)info->gid_min,
+ (unsigned int)info->gid_max);
+ else
+ xt_xlate_add(xl, "%u", (unsigned int)info->gid_min);
+
+ return 1;
+}
+
+static int owner_mt_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_owner_match_info *info = (void *)params->match->data;
+ int ret;
+
+ switch (info->match) {
+ case XT_OWNER_UID:
+ ret = owner_mt_print_uid_xlate(info, xl);
+ break;
+ case XT_OWNER_GID:
+ ret = owner_mt_print_gid_xlate(info, xl);
+ break;
+ default:
+ ret = 0;
+ }
+
+ return ret;
+}
+
static struct xtables_match owner_mt_reg[] = {
{
.version = XTABLES_VERSION,
@@ -534,6 +584,7 @@ static struct xtables_match owner_mt_reg[] = {
.print = owner_mt_print,
.save = owner_mt_save,
.x6_options = owner_mt_opts,
+ .xlate = owner_mt_xlate,
},
};
diff --git a/extensions/libxt_owner.t b/extensions/libxt_owner.t
new file mode 100644
index 00000000..aec30b65
--- /dev/null
+++ b/extensions/libxt_owner.t
@@ -0,0 +1,12 @@
+:OUTPUT,POSTROUTING
+*mangle
+-m owner --uid-owner root;-m owner --uid-owner 0;OK
+-m owner --uid-owner 0-10;=;OK
+-m owner --gid-owner root;-m owner --gid-owner 0;OK
+-m owner --gid-owner 0-10;=;OK
+-m owner --uid-owner root --gid-owner root;-m owner --uid-owner 0 --gid-owner 0;OK
+-m owner --uid-owner 0-10 --gid-owner 0-10;=;OK
+-m owner ! --uid-owner root;-m owner ! --uid-owner 0;OK
+-m owner --socket-exists;=;OK
+:INPUT
+-m owner --uid-owner root;;FAIL
diff --git a/extensions/libxt_physdev.man b/extensions/libxt_physdev.man
index 53beb2e5..06b778af 100644
--- a/extensions/libxt_physdev.man
+++ b/extensions/libxt_physdev.man
@@ -15,21 +15,13 @@ 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
+Name of a bridge port via which a packet is going to be sent (for bridged packets
entering the
-.BR FORWARD ,
-.B OUTPUT
+.BR FORWARD
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.
+interface which begins with this name will match.
.TP
[\fB!\fP] \fB\-\-physdev\-is\-in\fP
Matches if the packet has entered through a bridge interface.
diff --git a/extensions/libxt_physdev.t b/extensions/libxt_physdev.t
new file mode 100644
index 00000000..1fab7e19
--- /dev/null
+++ b/extensions/libxt_physdev.t
@@ -0,0 +1,14 @@
+:INPUT,FORWARD
+-m physdev --physdev-in lo;=;OK
+-m physdev --physdev-is-in --physdev-in lo;=;OK
+:OUTPUT,FORWARD
+# xt_physdev: using --physdev-out in the OUTPUT, FORWARD and POSTROUTING chains for non-bridged traffic is not supported anymore.
+# ERROR: should fail: iptables -A FORWARD -m physdev --physdev-out lo
+#-m physdev --physdev-out lo;;FAIL
+# ERROR: cannot load: iptables -A OUTPUT -m physdev --physdev-is-out --physdev-out lo
+#-m physdev --physdev-is-out --physdev-out lo;=;OK
+:FORWARD
+-m physdev --physdev-in lo --physdev-is-bridged;=;OK
+:POSTROUTING
+*mangle
+-m physdev --physdev-out lo --physdev-is-bridged;=;OK
diff --git a/extensions/libxt_pkttype.c b/extensions/libxt_pkttype.c
index 1ed3b445..bf6f5b96 100644
--- a/extensions/libxt_pkttype.c
+++ b/extensions/libxt_pkttype.c
@@ -21,6 +21,11 @@ struct pkttypes {
const char *help;
};
+struct pkttypes_xlate {
+ const char *name;
+ unsigned char pkttype;
+};
+
static const struct pkttypes supported_types[] = {
{"unicast", PACKET_HOST, 1, "to us"},
{"broadcast", PACKET_BROADCAST, 1, "to all"},
@@ -115,6 +120,37 @@ static void pkttype_save(const void *ip, const struct xt_entry_match *match)
print_pkttype(info);
}
+static const struct pkttypes_xlate supported_types_xlate[] = {
+ {"unicast", PACKET_HOST},
+ {"broadcast", PACKET_BROADCAST},
+ {"multicast", PACKET_MULTICAST},
+};
+
+static void print_pkttype_xlate(const struct xt_pkttype_info *info,
+ struct xt_xlate *xl)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(supported_types_xlate); ++i) {
+ if (supported_types_xlate[i].pkttype == info->pkttype) {
+ xt_xlate_add(xl, "%s", supported_types_xlate[i].name);
+ return;
+ }
+ }
+ xt_xlate_add(xl, "%d", info->pkttype);
+}
+
+static int pkttype_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_pkttype_info *info = (const void *)params->match->data;
+
+ xt_xlate_add(xl, "pkttype%s ", info->invert ? " !=" : "");
+ print_pkttype_xlate(info, xl);
+
+ return 1;
+}
+
static struct xtables_match pkttype_match = {
.family = NFPROTO_UNSPEC,
.name = "pkttype",
@@ -126,6 +162,7 @@ static struct xtables_match pkttype_match = {
.save = pkttype_save,
.x6_parse = pkttype_parse,
.x6_options = pkttype_opts,
+ .xlate = pkttype_xlate,
};
void _init(void)
diff --git a/extensions/libxt_pkttype.t b/extensions/libxt_pkttype.t
new file mode 100644
index 00000000..d93baeaf
--- /dev/null
+++ b/extensions/libxt_pkttype.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-m pkttype --pkt-type unicast;=;OK
+-m pkttype --pkt-type broadcast;=;OK
+-m pkttype --pkt-type multicast;=;OK
+-m pkttype --pkt-type wrong;;FAIL
+-m pkttype;;FAIL
diff --git a/extensions/libxt_policy.t b/extensions/libxt_policy.t
new file mode 100644
index 00000000..24a3e2f4
--- /dev/null
+++ b/extensions/libxt_policy.t
@@ -0,0 +1,5 @@
+:INPUT,FORWARD
+-m policy --dir in --pol ipsec;=;OK
+-m policy --dir in --pol ipsec --strict;;FAIL
+-m policy --dir in --pol ipsec --strict --reqid 1 --spi 0x1 --proto esp --mode tunnel --tunnel-dst 10.0.0.0/8 --tunnel-src 10.0.0.0/8 --next --reqid 2;=;OK
+-m policy --dir in --pol ipsec --strict --reqid 1 --spi 0x1 --proto esp --tunnel-dst 10.0.0.0/8;;FAIL
diff --git a/extensions/libxt_quota.c b/extensions/libxt_quota.c
index 26fba0bb..192cc717 100644
--- a/extensions/libxt_quota.c
+++ b/extensions/libxt_quota.c
@@ -37,7 +37,7 @@ quota_save(const void *ip, const struct xt_entry_match *match)
const struct xt_quota_info *q = (const void *)match->data;
if (q->flags & XT_QUOTA_INVERT)
- printf("! ");
+ printf(" !");
printf(" --quota %llu", (unsigned long long) q->quota);
}
@@ -51,6 +51,17 @@ static void quota_parse(struct xt_option_call *cb)
info->quota = cb->val.u64;
}
+static int quota_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_quota_info *q = (void *)params->match->data;
+
+ xt_xlate_add(xl, "quota %s%llu bytes",
+ q->flags & XT_QUOTA_INVERT ? "over " : "",
+ (unsigned long long) q->quota);
+ return 1;
+}
+
static struct xtables_match quota_match = {
.family = NFPROTO_UNSPEC,
.name = "quota",
@@ -62,6 +73,7 @@ static struct xtables_match quota_match = {
.save = quota_save,
.x6_parse = quota_parse,
.x6_options = quota_opts,
+ .xlate = quota_xlate,
};
void
diff --git a/extensions/libxt_quota.t b/extensions/libxt_quota.t
new file mode 100644
index 00000000..c5684279
--- /dev/null
+++ b/extensions/libxt_quota.t
@@ -0,0 +1,7 @@
+:INPUT,FORWARD,OUTPUT
+-m quota --quota 0;=;OK
+-m quota ! --quota 0;=;OK
+-m quota --quota 18446744073709551615;=;OK
+-m quota ! --quota 18446744073709551615;=;OK
+-m quota --quota 18446744073709551616;;FAIL
+-m quota;;FAIL
diff --git a/extensions/libxt_rateest.t b/extensions/libxt_rateest.t
new file mode 100644
index 00000000..c53b4b62
--- /dev/null
+++ b/extensions/libxt_rateest.t
@@ -0,0 +1,16 @@
+:INPUT,FORWARD,OUTPUT
+@iptables -I INPUT -j RATEEST --rateest-name RE1 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms
+-m rateest --rateest RE1 --rateest-lt --rateest-bps 8bit;=;OK
+-m rateest --rateest RE1 --rateest-eq --rateest-pps 5;=;OK
+-m rateest --rateest RE1 --rateest-gt --rateest-bps 5kbit;-m rateest --rateest RE1 --rateest-gt --rateest-bps 5000bit;OK
+-m rateest --rateest-delta --rateest RE1 --rateest-bps1 8bit --rateest-lt --rateest-bps2 16bit;=;OK
+@iptables -I INPUT -j RATEEST --rateest-name RE2 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms
+-m rateest --rateest1 RE1 --rateest-lt --rateest-bps --rateest2 RE2;=;OK
+-m rateest --rateest-delta --rateest1 RE1 --rateest-pps1 0 --rateest-lt --rateest-pps2 42 --rateest2 RE2;=;OK
+-m rateest --rateest-delta --rateest RE1 --rateest-bps1 8bit --rateest-eq --rateest-bps2 16bit;=;OK
+-m rateest --rateest-delta --rateest RE1 --rateest-bps1 8bit --rateest-gt --rateest-bps2 16bit;=;OK
+-m rateest --rateest-delta --rateest RE1 --rateest-pps1 8 --rateest-lt --rateest-pps2 9;=;OK
+-m rateest --rateest-delta --rateest RE1 --rateest-pps1 8 --rateest-eq --rateest-pps2 9;=;OK
+-m rateest --rateest-delta --rateest RE1 --rateest-pps1 8 --rateest-gt --rateest-pps2 9;=;OK
+@iptables -D INPUT -j RATEEST --rateest-name RE1 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms
+@iptables -D INPUT -j RATEEST --rateest-name RE2 --rateest-interval 250.0ms --rateest-ewmalog 500.0ms
diff --git a/extensions/libxt_recent.c b/extensions/libxt_recent.c
index b3510d99..e1801f1c 100644
--- a/extensions/libxt_recent.c
+++ b/extensions/libxt_recent.c
@@ -104,7 +104,7 @@ static void recent_help(void)
" --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"
" --mask netmask Netmask that will be applied to this recent list.\n"
-"xt_recent by: Stephen Frost <sfrost@snowman.net>. http://snowman.net/projects/ipt_recent/\n");
+"xt_recent by: Stephen Frost <sfrost@snowman.net>.\n");
}
enum {
diff --git a/extensions/libxt_recent.man b/extensions/libxt_recent.man
index d9bd5d2a..419be257 100644
--- a/extensions/libxt_recent.man
+++ b/extensions/libxt_recent.man
@@ -73,9 +73,6 @@ iptables \-A FORWARD \-m recent \-\-name badguy \-\-rcheck \-\-seconds 60 \-j DR
.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/*\fP are the current lists of addresses and information
about each entry of each list.
.PP
diff --git a/extensions/libxt_recent.t b/extensions/libxt_recent.t
new file mode 100644
index 00000000..9a83918e
--- /dev/null
+++ b/extensions/libxt_recent.t
@@ -0,0 +1,11 @@
+:INPUT,FORWARD,OUTPUT
+-m recent --set;=;OK
+-m recent --rcheck --hitcount 8 --name foo --mask 255.255.255.255 --rsource;=;OK
+-m recent --rcheck --hitcount 12 --name foo --mask 255.255.255.255 --rsource;=;OK
+-m recent --update --rttl;=;OK
+-m recent --set --rttl;;FAIL
+-m recent --rcheck --hitcount 999 --name foo --mask 255.255.255.255 --rsource;;FAIL
+# nonsensical, but all should load successfully:
+-m recent --rcheck --hitcount 3 --name foo --mask 255.255.255.255 --rsource -m recent --rcheck --hitcount 4 --name foo --mask 255.255.255.255 --rsource;=;OK
+-m recent --rcheck --hitcount 4 --name foo --mask 255.255.255.255 --rsource -m recent --rcheck --hitcount 4 --name foo --mask 255.255.255.255 --rsource;=;OK
+-m recent --rcheck --hitcount 8 --name foo --mask 255.255.255.255 --rsource -m recent --rcheck --hitcount 12 --name foo --mask 255.255.255.255 --rsource;=;OK
diff --git a/extensions/libxt_rpfilter.man b/extensions/libxt_rpfilter.man
index f7f56d23..a3c0fcdc 100644
--- a/extensions/libxt_rpfilter.man
+++ b/extensions/libxt_rpfilter.man
@@ -8,7 +8,7 @@ Also, packets arriving via the loopback interface are always permitted.
This match can only be used in the PREROUTING chain of the raw or mangle table.
.TP
\fB\-\-loose\fP
-Used to specifiy that the reverse path filter test should match
+Used to specify that the reverse path filter test should match
even if the selected output device is not the expected one.
.TP
\fB\-\-validmark\fP
diff --git a/extensions/libxt_rpfilter.t b/extensions/libxt_rpfilter.t
new file mode 100644
index 00000000..390268f3
--- /dev/null
+++ b/extensions/libxt_rpfilter.t
@@ -0,0 +1,4 @@
+:PREROUTING
+*mangle
+-m rpfilter;=;OK
+-m rpfilter --loose --validmark --accept-local --invert;=;OK
diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c
index 56a4cdf2..df1936be 100644
--- a/extensions/libxt_sctp.c
+++ b/extensions/libxt_sctp.c
@@ -485,6 +485,44 @@ static void sctp_save(const void *ip, const struct xt_entry_match *match)
}
}
+static int sctp_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_sctp_info *einfo =
+ (const struct xt_sctp_info *)params->match->data;
+ char *space = "";
+
+ if (!einfo->flags)
+ return 0;
+
+ xt_xlate_add(xl, "sctp ");
+
+ if (einfo->flags & XT_SCTP_SRC_PORTS) {
+ if (einfo->spts[0] != einfo->spts[1])
+ xt_xlate_add(xl, "sport%s %u-%u",
+ einfo->invflags & XT_SCTP_SRC_PORTS ? " !=" : "",
+ einfo->spts[0], einfo->spts[1]);
+ else
+ xt_xlate_add(xl, "sport%s %u",
+ einfo->invflags & XT_SCTP_SRC_PORTS ? " !=" : "",
+ einfo->spts[0]);
+ space = " ";
+ }
+
+ if (einfo->flags & XT_SCTP_DEST_PORTS) {
+ if (einfo->dpts[0] != einfo->dpts[1])
+ xt_xlate_add(xl, "%sdport%s %u-%u", space,
+ einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "",
+ einfo->dpts[0], einfo->dpts[1]);
+ else
+ xt_xlate_add(xl, "%sdport%s %u", space,
+ einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "",
+ einfo->dpts[0]);
+ }
+
+ return 1;
+}
+
static struct xtables_match sctp_match = {
.name = "sctp",
.family = NFPROTO_UNSPEC,
@@ -497,6 +535,7 @@ static struct xtables_match sctp_match = {
.print = sctp_print,
.save = sctp_save,
.extra_opts = sctp_opts,
+ .xlate = sctp_xlate,
};
void _init(void)
diff --git a/extensions/libxt_sctp.t b/extensions/libxt_sctp.t
new file mode 100644
index 00000000..2f75e2a6
--- /dev/null
+++ b/extensions/libxt_sctp.t
@@ -0,0 +1,32 @@
+:INPUT,FORWARD,OUTPUT
+-p sctp -m sctp --sport 1;=;OK
+-p sctp -m sctp --sport 65535;=;OK
+-p sctp -m sctp --sport 1:65535;=;OK
+-p sctp -m sctp --sport -1;;FAIL
+-p sctp -m sctp --sport 65536;;FAIL
+-p sctp -m sctp --dport 1;=;OK
+-p sctp -m sctp --dport 1:65535;=;OK
+-p sctp -m sctp --dport 65535;=;OK
+-p sctp -m sctp --dport -1;;FAIL
+-p sctp -m sctp --dport 65536;;FAIL
+-p sctp -m sctp --chunk-types all DATA;=;OK
+-p sctp -m sctp --chunk-types all INIT;=;OK
+-p sctp -m sctp --chunk-types all INIT_ACK;=;OK
+-p sctp -m sctp --chunk-types all SACK;=;OK
+-p sctp -m sctp --chunk-types all HEARTBEAT;=;OK
+-p sctp -m sctp --chunk-types all HEARTBEAT_ACK;=;OK
+-p sctp -m sctp --chunk-types all ABORT;=;OK
+-p sctp -m sctp --chunk-types all SHUTDOWN;=;OK
+-p sctp -m sctp --chunk-types all SHUTDOWN_ACK;=;OK
+-p sctp -m sctp --chunk-types all ERROR;=;OK
+-p sctp -m sctp --chunk-types all COOKIE_ECHO;=;OK
+-p sctp -m sctp --chunk-types all COOKIE_ACK;=;OK
+-p sctp -m sctp --chunk-types all ECN_ECNE;=;OK
+-p sctp -m sctp --chunk-types all ECN_CWR;=;OK
+# ERROR: iptables-save segfaults: iptables -A INPUT -p sctp -m sctp --chunk-types all ASCONF
+# -p sctp -m sctp --chunk-types all ASCONF;=;OK
+# ERROR: iptables-save segfaults: iptables -A INPUT -p sctp -m sctp --chunk-types all ASCONF_ACK
+# -p sctp -m sctp --chunk-types all ASCONF_ACK;=;OK
+# ERROR: iptables-save segfaults: iptables -A INPUT -p sctp -m sctp --chunk-types all FORWARD_TSN
+# -p sctp -m sctp --chunk-types all FORWARD_TSN;=;OK
+-p sctp -m sctp --chunk-types all SHUTDOWN_COMPLETE;=;OK
diff --git a/extensions/libxt_set.c b/extensions/libxt_set.c
index 2cb9e78a..679c04c7 100644
--- a/extensions/libxt_set.c
+++ b/extensions/libxt_set.c
@@ -52,7 +52,7 @@ static int
set_parse_v0(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
- struct xt_set_info_match_v0 *myinfo =
+ struct xt_set_info_match_v0 *myinfo =
(struct xt_set_info_match_v0 *) (*match)->data;
struct xt_set_info_v0 *info = &myinfo->match_set;
@@ -82,7 +82,7 @@ set_parse_v0(int c, char **argv, int invert, unsigned int *flags,
parse_dirs_v0(argv[optind], info);
DEBUGP("parse: set index %u\n", info->index);
optind++;
-
+
*flags = 1;
break;
}
@@ -132,7 +132,7 @@ static int
set_parse_v1(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
- struct xt_set_info_match_v1 *myinfo =
+ struct xt_set_info_match_v1 *myinfo =
(struct xt_set_info_match_v1 *) (*match)->data;
struct xt_set_info *info = &myinfo->match_set;
@@ -162,7 +162,7 @@ set_parse_v1(int c, char **argv, int invert, unsigned int *flags,
parse_dirs(argv[optind], info);
DEBUGP("parse: set index %u\n", info->index);
optind++;
-
+
*flags = 1;
break;
}
@@ -227,7 +227,7 @@ static int
set_parse_v2(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
- struct xt_set_info_match_v1 *myinfo =
+ struct xt_set_info_match_v1 *myinfo =
(struct xt_set_info_match_v1 *) (*match)->data;
struct xt_set_info *info = &myinfo->match_set;
@@ -260,7 +260,7 @@ set_parse_v2(int c, char **argv, int invert, unsigned int *flags,
parse_dirs(argv[optind], info);
DEBUGP("parse: set index %u\n", info->index);
optind++;
-
+
*flags = 1;
break;
}
@@ -334,7 +334,7 @@ static int
set_parse_v3(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
- struct xt_set_info_match_v3 *info =
+ struct xt_set_info_match_v3 *info =
(struct xt_set_info_match_v3 *) (*match)->data;
switch (c) {
@@ -437,7 +437,7 @@ set_parse_v3(int c, char **argv, int invert, unsigned int *flags,
parse_dirs(argv[optind], &info->match_set);
DEBUGP("parse: set index %u\n", info->match_set.index);
optind++;
-
+
*flags = 1;
break;
}
@@ -446,7 +446,7 @@ set_parse_v3(int c, char **argv, int invert, unsigned int *flags,
}
static void
-set_printv3_counter(const struct ip_set_counter_match *c, const char *name,
+set_printv3_counter(const struct ip_set_counter_match0 *c, const char *name,
const char *sep)
{
switch (c->op) {
@@ -497,6 +497,174 @@ set_save_v3(const void *ip, const struct xt_entry_match *match)
set_print_v3_matchinfo(info, "--match-set", "--");
}
+/* Revision 4 */
+static int
+set_parse_v4(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_match **match)
+{
+ struct xt_set_info_match_v4 *info =
+ (struct xt_set_info_match_v4 *) (*match)->data;
+
+ switch (c) {
+ case 'a':
+ if (invert)
+ info->flags |= IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE;
+ break;
+ case '0':
+ if (info->bytes.op != IPSET_COUNTER_NONE)
+ xtables_error(PARAMETER_PROBLEM,
+ "only one of the --bytes-[eq|lt|gt]"
+ " is allowed\n");
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "--bytes-gt option cannot be inverted\n");
+ info->bytes.op = IPSET_COUNTER_GT;
+ info->bytes.value = parse_counter(optarg);
+ break;
+ case '9':
+ if (info->bytes.op != IPSET_COUNTER_NONE)
+ xtables_error(PARAMETER_PROBLEM,
+ "only one of the --bytes-[eq|lt|gt]"
+ " is allowed\n");
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "--bytes-lt option cannot be inverted\n");
+ info->bytes.op = IPSET_COUNTER_LT;
+ info->bytes.value = parse_counter(optarg);
+ break;
+ case '8':
+ if (info->bytes.op != IPSET_COUNTER_NONE)
+ xtables_error(PARAMETER_PROBLEM,
+ "only one of the --bytes-[eq|lt|gt]"
+ " is allowed\n");
+ info->bytes.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ;
+ info->bytes.value = parse_counter(optarg);
+ break;
+ case '7':
+ if (info->packets.op != IPSET_COUNTER_NONE)
+ xtables_error(PARAMETER_PROBLEM,
+ "only one of the --packets-[eq|lt|gt]"
+ " is allowed\n");
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "--packets-gt option cannot be inverted\n");
+ info->packets.op = IPSET_COUNTER_GT;
+ info->packets.value = parse_counter(optarg);
+ break;
+ case '6':
+ if (info->packets.op != IPSET_COUNTER_NONE)
+ xtables_error(PARAMETER_PROBLEM,
+ "only one of the --packets-[eq|lt|gt]"
+ " is allowed\n");
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "--packets-lt option cannot be inverted\n");
+ info->packets.op = IPSET_COUNTER_LT;
+ info->packets.value = parse_counter(optarg);
+ break;
+ case '5':
+ if (info->packets.op != IPSET_COUNTER_NONE)
+ xtables_error(PARAMETER_PROBLEM,
+ "only one of the --packets-[eq|lt|gt]"
+ " is allowed\n");
+ info->packets.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ;
+ info->packets.value = parse_counter(optarg);
+ break;
+ case '4':
+ if (invert)
+ info->flags |= IPSET_FLAG_SKIP_COUNTER_UPDATE;
+ break;
+ case '3':
+ if (invert)
+ xtables_error(PARAMETER_PROBLEM,
+ "--return-nomatch flag cannot be inverted\n");
+ info->flags |= IPSET_FLAG_RETURN_NOMATCH;
+ break;
+ case '2':
+ fprintf(stderr,
+ "--set option deprecated, please use --match-set\n");
+ case '1': /* --match-set <set> <flag>[,<flag> */
+ if (info->match_set.dim)
+ xtables_error(PARAMETER_PROBLEM,
+ "--match-set can be specified only once");
+ if (invert)
+ info->match_set.flags |= IPSET_INV_MATCH;
+
+ if (!argv[optind]
+ || argv[optind][0] == '-'
+ || argv[optind][0] == '!')
+ xtables_error(PARAMETER_PROBLEM,
+ "--match-set requires two args.");
+
+ if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
+ xtables_error(PARAMETER_PROBLEM,
+ "setname `%s' too long, max %d characters.",
+ optarg, IPSET_MAXNAMELEN - 1);
+
+ get_set_byname(optarg, &info->match_set);
+ parse_dirs(argv[optind], &info->match_set);
+ DEBUGP("parse: set index %u\n", info->match_set.index);
+ optind++;
+
+ *flags = 1;
+ break;
+ }
+
+ return 1;
+}
+
+static void
+set_printv4_counter(const struct ip_set_counter_match *c, const char *name,
+ const char *sep)
+{
+ switch (c->op) {
+ case IPSET_COUNTER_EQ:
+ printf(" %s%s-eq %llu", sep, name, c->value);
+ break;
+ case IPSET_COUNTER_NE:
+ printf(" ! %s%s-eq %llu", sep, name, c->value);
+ break;
+ case IPSET_COUNTER_LT:
+ printf(" %s%s-lt %llu", sep, name, c->value);
+ break;
+ case IPSET_COUNTER_GT:
+ printf(" %s%s-gt %llu", sep, name, c->value);
+ break;
+ }
+}
+
+static void
+set_print_v4_matchinfo(const struct xt_set_info_match_v4 *info,
+ const char *opt, const char *sep)
+{
+ print_match(opt, &info->match_set);
+ if (info->flags & IPSET_FLAG_RETURN_NOMATCH)
+ printf(" %sreturn-nomatch", sep);
+ if ((info->flags & IPSET_FLAG_SKIP_COUNTER_UPDATE))
+ printf(" ! %supdate-counters", sep);
+ if ((info->flags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE))
+ printf(" ! %supdate-subcounters", sep);
+ set_printv4_counter(&info->packets, "packets", sep);
+ set_printv4_counter(&info->bytes, "bytes", sep);
+}
+
+/* Prints out the matchinfo. */
+static void
+set_print_v4(const void *ip, const struct xt_entry_match *match, int numeric)
+{
+ const struct xt_set_info_match_v4 *info = (const void *)match->data;
+
+ set_print_v4_matchinfo(info, "match-set", "");
+}
+
+static void
+set_save_v4(const void *ip, const struct xt_entry_match *match)
+{
+ const struct xt_set_info_match_v4 *info = (const void *)match->data;
+
+ set_print_v4_matchinfo(info, "--match-set", "--");
+}
+
static struct xtables_match set_mt_reg[] = {
{
.name = "set",
@@ -554,6 +722,20 @@ static struct xtables_match set_mt_reg[] = {
.save = set_save_v3,
.extra_opts = set_opts_v3,
},
+ {
+ .name = "set",
+ .revision = 4,
+ .version = XTABLES_VERSION,
+ .family = NFPROTO_UNSPEC,
+ .size = XT_ALIGN(sizeof(struct xt_set_info_match_v4)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_match_v4)),
+ .help = set_help_v3,
+ .parse = set_parse_v4,
+ .final_check = set_check_v0,
+ .print = set_print_v4,
+ .save = set_save_v4,
+ .extra_opts = set_opts_v3,
+ },
};
void _init(void)
diff --git a/extensions/libxt_set.h b/extensions/libxt_set.h
index 47c3f5b6..5a1bdcf7 100644
--- a/extensions/libxt_set.h
+++ b/extensions/libxt_set.h
@@ -6,6 +6,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
+#include "../iptables/xshared.h"
#ifdef DEBUG
#define DEBUGP(x, args...) fprintf(stderr, x , ## args)
@@ -71,13 +72,13 @@ get_set_byid(char *setname, ip_set_id_t idx)
}
static void
-get_set_byname(const char *setname, struct xt_set_info *info)
+get_set_byname_only(const char *setname, struct xt_set_info *info,
+ int sockfd, unsigned int version)
{
- struct ip_set_req_get_set req;
+ struct ip_set_req_get_set req = { .version = version };
socklen_t size = sizeof(struct ip_set_req_get_set);
- int res, sockfd;
+ int res;
- sockfd = get_version(&req.version);
req.op = IP_SET_OP_GET_BYNAME;
strncpy(req.set.name, setname, IPSET_MAXNAMELEN);
req.set.name[IPSET_MAXNAMELEN - 1] = '\0';
@@ -101,6 +102,49 @@ get_set_byname(const char *setname, struct xt_set_info *info)
}
static void
+get_set_byname(const char *setname, struct xt_set_info *info)
+{
+ struct ip_set_req_get_set_family req;
+ socklen_t size = sizeof(struct ip_set_req_get_set_family);
+ int res, sockfd, version;
+
+ sockfd = get_version(&req.version);
+ version = req.version;
+ req.op = IP_SET_OP_GET_FNAME;
+ strncpy(req.set.name, setname, IPSET_MAXNAMELEN);
+ req.set.name[IPSET_MAXNAMELEN - 1] = '\0';
+ res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req, &size);
+
+ if (res != 0 && errno == EBADMSG)
+ /* Backward compatibility */
+ return get_set_byname_only(setname, info, sockfd, version);
+
+ close(sockfd);
+ if (res != 0)
+ xtables_error(OTHER_PROBLEM,
+ "Problem when communicating with ipset, errno=%d.\n",
+ errno);
+ if (size != sizeof(struct ip_set_req_get_set_family))
+ xtables_error(OTHER_PROBLEM,
+ "Incorrect return size from kernel during ipset lookup, "
+ "(want %zu, got %zu)\n",
+ sizeof(struct ip_set_req_get_set_family),
+ (size_t)size);
+ if (req.set.index == IPSET_INVALID_ID)
+ xtables_error(PARAMETER_PROBLEM,
+ "Set %s doesn't exist.\n", setname);
+ if (!(req.family == afinfo->family ||
+ req.family == NFPROTO_UNSPEC))
+ xtables_error(PARAMETER_PROBLEM,
+ "The protocol family of set %s is %s, "
+ "which is not applicable.\n",
+ setname,
+ req.family == NFPROTO_IPV4 ? "IPv4" : "IPv6");
+
+ info->index = req.set.index;
+}
+
+static void
parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info)
{
char *saved = strdup(opt_arg);
diff --git a/extensions/libxt_set.man b/extensions/libxt_set.man
index 7012ef2e..dbc1586b 100644
--- a/extensions/libxt_set.man
+++ b/extensions/libxt_set.man
@@ -43,7 +43,7 @@ packet counter of the element is less than the given value as well.
If the packet is matched an element in the set, match only if the
packet counter of the element is greater than the given value as well.
.TP
-[\fB!\fP] \fB\-bytes\-eq\fP \fIvalue\fP
+[\fB!\fP] \fB\-\-bytes\-eq\fP \fIvalue\fP
If the packet is matched an element in the set, match only if the
byte counter of the element matches the given value too.
.TP
diff --git a/extensions/libxt_set.t b/extensions/libxt_set.t
new file mode 100644
index 00000000..dd9e9f17
--- /dev/null
+++ b/extensions/libxt_set.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+-m set --match-set foo;;FAIL
+# fails: foo does not exist
+-m set --match-set foo src,dst;;FAIL
diff --git a/extensions/libxt_socket.man b/extensions/libxt_socket.man
index 41e8d674..f809df69 100644
--- a/extensions/libxt_socket.man
+++ b/extensions/libxt_socket.man
@@ -1,5 +1,36 @@
-This matches if an open socket can be found by doing a socket lookup on the
-packet.
+This matches if an open TCP/UDP socket can be found by doing a socket lookup on the
+packet. It matches if there is an established or non\-zero bound listening
+socket (possibly with a non\-local address). The lookup is performed using
+the \fBpacket\fP tuple of TCP/UDP packets, or the original TCP/UDP header
+\fBembedded\fP in an ICMP/ICPMv6 error packet.
.TP
\fB\-\-transparent\fP
Ignore non-transparent sockets.
+.TP
+\fB\-\-nowildcard\fP
+Do not ignore sockets bound to 'any' address.
+The socket match won't accept zero\-bound listeners by default, since
+then local services could intercept traffic that would otherwise be forwarded.
+This option therefore has security implications when used to match traffic being
+forwarded to redirect such packets to local machine with policy routing.
+When using the socket match to implement fully transparent
+proxies bound to non\-local addresses it is recommended to use the \-\-transparent
+option instead.
+.PP
+Example (assuming packets with mark 1 are delivered locally):
+.IP
+\-t mangle \-A PREROUTING \-m socket \-\-transparent \-j MARK \-\-set\-mark 1
+.TP
+\fB\-\-restore\-skmark\fP
+Set the packet mark to the matching socket's mark. Can be combined with the
+\fB\-\-transparent\fP and \fB\-\-nowildcard\fP options to restrict the sockets
+to be matched when restoring the packet mark.
+.PP
+Example: An application opens 2 transparent (\fBIP_TRANSPARENT\fP) sockets and
+sets a mark on them with \fBSO_MARK\fP socket option. We can filter matching packets:
+.IP
+\-t mangle \-I PREROUTING \-m socket \-\-transparent \-\-restore-skmark \-j action
+.IP
+\-t mangle \-A action \-m mark \-\-mark 10 \-j action2
+.IP
+\-t mangle \-A action \-m mark \-\-mark 11 \-j action3
diff --git a/extensions/libxt_socket.t b/extensions/libxt_socket.t
new file mode 100644
index 00000000..fe4eb3e4
--- /dev/null
+++ b/extensions/libxt_socket.t
@@ -0,0 +1,8 @@
+:PREROUTING,INPUT
+*mangle
+-m socket;=;OK
+-m socket --transparent --nowildcard;=;OK
+-m socket --transparent --nowildcard --restore-skmark;=;OK
+-m socket --transparent --restore-skmark;=;OK
+-m socket --nowildcard --restore-skmark;=;OK
+-m socket --restore-skmark;=;OK
diff --git a/extensions/libxt_standard.t b/extensions/libxt_standard.t
new file mode 100644
index 00000000..923569c3
--- /dev/null
+++ b/extensions/libxt_standard.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+-j DROP;=;OK
+-j ACCEPT;=;OK
+-j RETURN;=;OK
diff --git a/extensions/libxt_state.t b/extensions/libxt_state.t
new file mode 100644
index 00000000..8e4bce3f
--- /dev/null
+++ b/extensions/libxt_state.t
@@ -0,0 +1,6 @@
+:INPUT,FORWARD,OUTPUT
+-m state --state INVALID;=;OK
+-m state --state NEW,RELATED;=;OK
+-m state --state UNTRACKED;=;OK
+-m state wrong;;FAIL
+-m state;;FAIL
diff --git a/extensions/libxt_statistic.c b/extensions/libxt_statistic.c
index b6ae5f5c..4f3341a3 100644
--- a/extensions/libxt_statistic.c
+++ b/extensions/libxt_statistic.c
@@ -133,6 +133,26 @@ static void statistic_save(const void *ip, const struct xt_entry_match *match)
print_match(info, "--");
}
+static int statistic_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_statistic_info *info =
+ (struct xt_statistic_info *)params->match->data;
+
+ switch (info->mode) {
+ case XT_STATISTIC_MODE_RANDOM:
+ return 0;
+ case XT_STATISTIC_MODE_NTH:
+ xt_xlate_add(xl, "numgen inc mod %u %s%u",
+ info->u.nth.every + 1,
+ info->flags & XT_STATISTIC_INVERT ? "!= " : "",
+ info->u.nth.packet);
+ break;
+ }
+
+ return 1;
+}
+
static struct xtables_match statistic_match = {
.family = NFPROTO_UNSPEC,
.name = "statistic",
@@ -145,6 +165,7 @@ static struct xtables_match statistic_match = {
.print = statistic_print,
.save = statistic_save,
.x6_options = statistic_opts,
+ .xlate = statistic_xlate,
};
void _init(void)
diff --git a/extensions/libxt_statistic.t b/extensions/libxt_statistic.t
new file mode 100644
index 00000000..bb6673da
--- /dev/null
+++ b/extensions/libxt_statistic.t
@@ -0,0 +1,8 @@
+:INPUT,FORWARD,OUTPUT
+-m statistic;;FAIL
+-m statistic --mode random ! --probability 0.50000000000;=;OK
+-m statistic --mode random ! --probability 1.1;;FAIL
+-m statistic --probability 1;;FAIL
+-m statistic --mode nth ! --every 5 --packet 2;=;OK
+-m statistic --mode nth ! --every 5;;FAIL
+-m statistic --mode nth ! --every 5 --packet 5;;FAIL
diff --git a/extensions/libxt_string.man b/extensions/libxt_string.man
index b6b271d1..54c03a3a 100644
--- a/extensions/libxt_string.man
+++ b/extensions/libxt_string.man
@@ -16,3 +16,16 @@ Matches the given pattern.
.TP
[\fB!\fP] \fB\-\-hex\-string\fP \fIpattern\fP
Matches the given pattern in hex notation.
+.TP
+\fB\-\-icase\fP
+Ignore case when searching.
+.TP
+Examples:
+.IP
+# The string pattern can be used for simple text characters.
+.br
+iptables \-A INPUT \-p tcp \-\-dport 80 \-m string \-\-algo bm \-\-string 'GET /index.html' \-j LOG
+.IP
+# The hex string pattern can be used for non-printable characters, like |0D 0A| or |0D0A|.
+.br
+iptables \-p udp \-\-dport 53 \-m string \-\-algo bm \-\-from 40 \-\-to 57 \-\-hex\-string '|03|www|09|netfilter|03|org|00|'
diff --git a/extensions/libxt_string.t b/extensions/libxt_string.t
new file mode 100644
index 00000000..d68f099d
--- /dev/null
+++ b/extensions/libxt_string.t
@@ -0,0 +1,18 @@
+:INPUT,FORWARD,OUTPUT
+# ERROR: cannot find: iptables -I INPUT -m string --algo bm --string "test"
+# -m string --algo bm --string "test";=;OK
+# ERROR: cannot find: iptables -I INPUT -m string --algo kmp --string "test")
+# -m string --algo kmp --string "test";=;OK
+# ERROR: cannot find: iptables -I INPUT -m string --algo kmp ! --string "test"
+# -m string --algo kmp ! --string "test";=;OK
+# cannot find: iptables -I INPUT -m string --algo bm --string "xxxxxxxxxxx" ....]
+# -m string --algo bm --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";=;OK
+# ERROR: cannot load: iptables -A INPUT -m string --algo bm --string "xxxx"
+# -m string --algo bm --string "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";=;OK
+# ERROR: cannot load: iptables -A INPUT -m string --algo bm --hexstring "|0a0a0a0a|"
+# -m string --algo bm --hexstring "|0a0a0a0a|";=;OK
+# ERROR: cannot find: iptables -I INPUT -m string --algo bm --from 0 --to 65535 --string "test"
+# -m string --algo bm --from 0 --to 65535 --string "test";=;OK
+-m string --algo wrong;;FAIL
+-m string --algo bm;;FAIL
+-m string;;FAIL
diff --git a/extensions/libxt_tcp.c b/extensions/libxt_tcp.c
index bbdec454..58f3c0a0 100644
--- a/extensions/libxt_tcp.c
+++ b/extensions/libxt_tcp.c
@@ -362,6 +362,89 @@ static void tcp_save(const void *ip, const struct xt_entry_match *match)
}
}
+static const struct tcp_flag_names tcp_flag_names_xlate[] = {
+ { "fin", 0x01 },
+ { "syn", 0x02 },
+ { "rst", 0x04 },
+ { "psh", 0x08 },
+ { "ack", 0x10 },
+ { "urg", 0x20 },
+};
+
+static void print_tcp_xlate(struct xt_xlate *xl, uint8_t flags)
+{
+ int have_flag = 0;
+
+ while (flags) {
+ unsigned int i;
+
+ for (i = 0; (flags & tcp_flag_names_xlate[i].flag) == 0; i++);
+
+ if (have_flag)
+ xt_xlate_add(xl, "|");
+
+ xt_xlate_add(xl, "%s", tcp_flag_names_xlate[i].name);
+ have_flag = 1;
+
+ flags &= ~tcp_flag_names_xlate[i].flag;
+ }
+
+ if (!have_flag)
+ xt_xlate_add(xl, "0x0");
+}
+
+static int tcp_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_tcp *tcpinfo =
+ (const struct xt_tcp *)params->match->data;
+ char *space= "";
+
+ if (tcpinfo->spts[0] != 0 || tcpinfo->spts[1] != 0xffff) {
+ if (tcpinfo->spts[0] != tcpinfo->spts[1]) {
+ xt_xlate_add(xl, "tcp sport %s%u-%u",
+ tcpinfo->invflags & XT_TCP_INV_SRCPT ?
+ "!= " : "",
+ tcpinfo->spts[0], tcpinfo->spts[1]);
+ } else {
+ xt_xlate_add(xl, "tcp sport %s%u",
+ tcpinfo->invflags & XT_TCP_INV_SRCPT ?
+ "!= " : "",
+ tcpinfo->spts[0]);
+ }
+ space = " ";
+ }
+
+ if (tcpinfo->dpts[0] != 0 || tcpinfo->dpts[1] != 0xffff) {
+ if (tcpinfo->dpts[0] != tcpinfo->dpts[1]) {
+ xt_xlate_add(xl, "%stcp dport %s%u-%u", space,
+ tcpinfo->invflags & XT_TCP_INV_DSTPT ?
+ "!= " : "",
+ tcpinfo->dpts[0], tcpinfo->dpts[1]);
+ } else {
+ xt_xlate_add(xl, "%stcp dport %s%u", space,
+ tcpinfo->invflags & XT_TCP_INV_DSTPT ?
+ "!= " : "",
+ tcpinfo->dpts[0]);
+ }
+ space = " ";
+ }
+
+ /* XXX not yet implemented */
+ if (tcpinfo->option || (tcpinfo->invflags & XT_TCP_INV_OPTION))
+ return 0;
+
+ if (tcpinfo->flg_mask || (tcpinfo->invflags & XT_TCP_INV_FLAGS)) {
+ xt_xlate_add(xl, "%stcp flags & (", space);
+ print_tcp_xlate(xl, tcpinfo->flg_mask);
+ xt_xlate_add(xl, ") %s ",
+ tcpinfo->invflags & XT_TCP_INV_FLAGS ? "!=": "==");
+ print_tcp_xlate(xl, tcpinfo->flg_cmp);
+ }
+
+ return 1;
+}
+
static struct xtables_match tcp_match = {
.family = NFPROTO_UNSPEC,
.name = "tcp",
@@ -374,6 +457,7 @@ static struct xtables_match tcp_match = {
.print = tcp_print,
.save = tcp_save,
.extra_opts = tcp_opts,
+ .xlate = tcp_xlate,
};
void
diff --git a/extensions/libxt_tcp.man b/extensions/libxt_tcp.man
index 7a16118b..80194617 100644
--- a/extensions/libxt_tcp.man
+++ b/extensions/libxt_tcp.man
@@ -7,7 +7,6 @@ name or a port number. An inclusive range can also be specified,
using the format \fIfirst\fP\fB:\fP\fIlast\fP.
If the first port is omitted, "0" is assumed; if the last is omitted,
"65535" is assumed.
-If the first port is greater than the second one they will be swapped.
The flag
\fB\-\-sport\fP
is a convenient alias for this option.
diff --git a/extensions/libxt_tcp.t b/extensions/libxt_tcp.t
new file mode 100644
index 00000000..b0e8006e
--- /dev/null
+++ b/extensions/libxt_tcp.t
@@ -0,0 +1,26 @@
+:INPUT,FORWARD,OUTPUT
+-p tcp -m tcp --sport 1;=;OK
+-p tcp -m tcp --sport 65535;=;OK
+-p tcp -m tcp --dport 1;=;OK
+-p tcp -m tcp --dport 65535;=;OK
+-p tcp -m tcp --sport 1:1023;=;OK
+-p tcp -m tcp --sport 1024:65535;=;OK
+-p tcp -m tcp --sport 1024:;-p tcp -m tcp --sport 1024:65535;OK
+-p tcp -m tcp ! --sport 1;=;OK
+-p tcp -m tcp ! --sport 65535;=;OK
+-p tcp -m tcp ! --dport 1;=;OK
+-p tcp -m tcp ! --dport 65535;=;OK
+-p tcp -m tcp --sport 1 --dport 65535;=;OK
+-p tcp -m tcp --sport 65535 --dport 1;=;OK
+-p tcp -m tcp ! --sport 1 --dport 65535;=;OK
+-p tcp -m tcp ! --sport 65535 --dport 1;=;OK
+-p tcp -m tcp --sport 65536;;FAIL
+-p tcp -m tcp --sport -1;;FAIL
+-p tcp -m tcp --dport -1;;FAIL
+-p tcp -m tcp --syn;-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN;OK
+-p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN;=;OK
+-p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG SYN;=;OK
+-p tcp -m tcp ! --tcp-flags FIN,SYN,RST,PSH,ACK,URG SYN;=;OK
+-p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG RST;=;OK
+# should we accept this below?
+-p tcp -m tcp;=;OK
diff --git a/extensions/libxt_tcpmss.t b/extensions/libxt_tcpmss.t
new file mode 100644
index 00000000..3181e49d
--- /dev/null
+++ b/extensions/libxt_tcpmss.t
@@ -0,0 +1,5 @@
+:INPUT,FORWARD,OUTPUT
+-m tcpmss --mss 42;;FAIL
+-p tcp -m tcpmss --mss 42;=;OK
+-p tcp -m tcpmss --mss 42:12345;=;OK
+-p tcp -m tcpmss --mss 42:65536;;FAIL
diff --git a/extensions/libxt_time.t b/extensions/libxt_time.t
new file mode 100644
index 00000000..673af09b
--- /dev/null
+++ b/extensions/libxt_time.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+-m time --timestart 01:02:03 --timestop 04:05:06 --monthdays 1,2,3,4,5 --weekdays Mon,Fri,Sun --datestart 2001-02-03T04:05:06 --datestop 2012-09-08T09:06:05 --kerneltz;=;OK
+-m time --timestart 01:02:03 --timestop 04:05:06 --monthdays 1,2,3,4,5 --weekdays Mon,Fri,Sun --datestart 2001-02-03T04:05:06 --datestop 2012-09-08T09:06:05;=;OK
+-m time --timestart 02:00:00 --timestop 03:00:00 --datestart 1970-01-01T02:00:00 --datestop 1970-01-01T03:00:00;=;OK
diff --git a/extensions/libxt_tos.t b/extensions/libxt_tos.t
new file mode 100644
index 00000000..ccbe8009
--- /dev/null
+++ b/extensions/libxt_tos.t
@@ -0,0 +1,13 @@
+:INPUT,FORWARD,OUTPUT
+-m tos --tos Minimize-Delay;-m tos --tos 0x10/0x3f;OK
+-m tos --tos Maximize-Throughput;-m tos --tos 0x08/0x3f;OK
+-m tos --tos Maximize-Reliability;-m tos --tos 0x04/0x3f;OK
+-m tos --tos Minimize-Cost;-m tos --tos 0x02/0x3f;OK
+-m tos --tos Normal-Service;-m tos --tos 0x00/0x3f;OK
+-m tos --tos 0xff;=;OK
+-m tos ! --tos 0xff;=;OK
+-m tos --tos 0x00;=;OK
+-m tos --tos 0x0f;=;OK
+-m tos --tos 0x0f/0x0f;=;OK
+-m tos --tos wrong;;FAIL
+-m tos;;FAIL
diff --git a/extensions/libxt_u32.t b/extensions/libxt_u32.t
new file mode 100644
index 00000000..0d9be47a
--- /dev/null
+++ b/extensions/libxt_u32.t
@@ -0,0 +1,2 @@
+:INPUT,FORWARD,OUTPUT
+-m u32 --u32 "0x0=0x0&&0x0=0x1";=;OK
diff --git a/extensions/libxt_udp.c b/extensions/libxt_udp.c
index b9f39ee4..0c7a4bc2 100644
--- a/extensions/libxt_udp.c
+++ b/extensions/libxt_udp.c
@@ -152,6 +152,44 @@ static void udp_save(const void *ip, const struct xt_entry_match *match)
}
}
+static int udp_xlate(struct xt_xlate *xl,
+ const struct xt_xlate_mt_params *params)
+{
+ const struct xt_udp *udpinfo = (struct xt_udp *)params->match->data;
+ char *space= "";
+
+ if (udpinfo->spts[0] != 0 || udpinfo->spts[1] != 0xFFFF) {
+ if (udpinfo->spts[0] != udpinfo->spts[1]) {
+ xt_xlate_add(xl,"udp sport %s%u-%u",
+ udpinfo->invflags & XT_UDP_INV_SRCPT ?
+ "!= ": "",
+ udpinfo->spts[0], udpinfo->spts[1]);
+ } else {
+ xt_xlate_add(xl, "udp sport %s%u",
+ udpinfo->invflags & XT_UDP_INV_SRCPT ?
+ "!= ": "",
+ udpinfo->spts[0]);
+ }
+ space = " ";
+ }
+
+ if (udpinfo->dpts[0] != 0 || udpinfo->dpts[1] != 0xFFFF) {
+ if (udpinfo->dpts[0] != udpinfo->dpts[1]) {
+ xt_xlate_add(xl,"%sudp dport %s%u-%u", space,
+ udpinfo->invflags & XT_UDP_INV_SRCPT ?
+ "!= ": "",
+ udpinfo->dpts[0], udpinfo->dpts[1]);
+ } else {
+ xt_xlate_add(xl,"%sudp dport %s%u", space,
+ udpinfo->invflags & XT_UDP_INV_SRCPT ?
+ "!= ": "",
+ udpinfo->dpts[0]);
+ }
+ }
+
+ return 1;
+}
+
static struct xtables_match udp_match = {
.family = NFPROTO_UNSPEC,
.name = "udp",
@@ -164,6 +202,7 @@ static struct xtables_match udp_match = {
.save = udp_save,
.x6_parse = udp_parse,
.x6_options = udp_opts,
+ .xlate = udp_xlate,
};
void
diff --git a/extensions/libxt_udp.t b/extensions/libxt_udp.t
new file mode 100644
index 00000000..1b4d3dd6
--- /dev/null
+++ b/extensions/libxt_udp.t
@@ -0,0 +1,22 @@
+:INPUT,OUTPUT,FORWARD
+-p udp -m udp --sport 1;=;OK
+-p udp -m udp --sport 65535;=;OK
+-p udp -m udp --dport 1;=;OK
+-p udp -m udp --dport 65535;=;OK
+-p udp -m udp --sport 1:1023;=;OK
+-p udp -m udp --sport 1024:65535;=;OK
+-p udp -m udp --sport 1024:;-p udp -m udp --sport 1024:65535;OK
+-p udp -m udp ! --sport 1;=;OK
+-p udp -m udp ! --sport 65535;=;OK
+-p udp -m udp ! --dport 1;=;OK
+-p udp -m udp ! --dport 65535;=;OK
+-p udp -m udp --sport 1 --dport 65535;=;OK
+-p udp -m udp --sport 65535 --dport 1;=;OK
+-p udp -m udp ! --sport 1 --dport 65535;=;OK
+-p udp -m udp ! --sport 65535 --dport 1;=;OK
+# ERRROR: should fail: iptables -A INPUT -p udp -m udp --sport 65536
+# -p udp -m udp --sport 65536;;FAIL
+-p udp -m udp --sport -1;;FAIL
+-p udp -m udp --dport -1;;FAIL
+# should we accept this below?
+-p udp -m udp;=;OK